ai-cli-online 3.0.19 → 3.0.20
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.
- package/package.json +1 -1
- package/server/dist/db.d.ts +29 -0
- package/server/dist/db.js +73 -0
- package/server/dist/index.js +9 -0
- package/server/dist/routes/sessions.js +15 -1
- package/server/dist/routes/taskAuto.d.ts +4 -0
- package/server/dist/routes/taskAuto.js +302 -0
- package/server/package.json +1 -1
- package/shared/package.json +1 -1
- package/web/dist/assets/{index-BI7oV4SU.css → index-D7cmVR0X.css} +1 -1
- package/web/dist/assets/index-DG0BJZ53.js +34 -0
- package/web/dist/index.html +2 -2
- package/web/package.json +1 -1
- package/web/dist/assets/index-Kzdpgxcz.js +0 -33
package/package.json
CHANGED
package/server/dist/db.d.ts
CHANGED
|
@@ -10,4 +10,33 @@ export declare function getAnnotation(sessionName: string, filePath: string): {
|
|
|
10
10
|
} | null;
|
|
11
11
|
export declare function saveAnnotation(sessionName: string, filePath: string, content: string, updatedAt: number): void;
|
|
12
12
|
export declare function cleanupOldAnnotations(maxAgeDays?: number): number;
|
|
13
|
+
export interface AutoSession {
|
|
14
|
+
session_name: string;
|
|
15
|
+
task_dir: string;
|
|
16
|
+
status: string;
|
|
17
|
+
max_iterations: number;
|
|
18
|
+
timeout_minutes: number;
|
|
19
|
+
started_at: string;
|
|
20
|
+
}
|
|
21
|
+
export interface AutoStep {
|
|
22
|
+
id: number;
|
|
23
|
+
session_name: string;
|
|
24
|
+
step: string;
|
|
25
|
+
result: string;
|
|
26
|
+
next: string;
|
|
27
|
+
checkpoint: string;
|
|
28
|
+
iteration: number;
|
|
29
|
+
started_at: string;
|
|
30
|
+
ended_at: string | null;
|
|
31
|
+
}
|
|
32
|
+
export declare function createAutoSession(sessionName: string, taskDir: string, maxIterations: number, timeoutMinutes: number): void;
|
|
33
|
+
export declare function getAutoSession(sessionName: string): AutoSession | null;
|
|
34
|
+
export declare function getAllRunningAutoSessions(): AutoSession[];
|
|
35
|
+
export declare function updateAutoStatus(sessionName: string, status: string): void;
|
|
36
|
+
export declare function deleteAutoSession(sessionName: string): void;
|
|
37
|
+
export declare function insertAutoStep(sessionName: string, step: string, result: string, next: string, checkpoint: string, iteration: number): number;
|
|
38
|
+
export declare function endAutoStep(stepId: number): void;
|
|
39
|
+
export declare function getAutoSteps(sessionName: string): AutoStep[];
|
|
40
|
+
export declare function getLastAutoStep(sessionName: string): AutoStep | null;
|
|
41
|
+
export declare function deleteAutoSteps(sessionName: string): void;
|
|
13
42
|
export declare function closeDb(): void;
|
package/server/dist/db.js
CHANGED
|
@@ -106,6 +106,79 @@ export function cleanupOldAnnotations(maxAgeDays = 7) {
|
|
|
106
106
|
const result = stmtAnnCleanup.run(cutoff);
|
|
107
107
|
return result.changes;
|
|
108
108
|
}
|
|
109
|
+
// --- Auto mode tables ---
|
|
110
|
+
db.exec(`
|
|
111
|
+
CREATE TABLE IF NOT EXISTS task_auto (
|
|
112
|
+
session_name TEXT PRIMARY KEY,
|
|
113
|
+
task_dir TEXT NOT NULL UNIQUE,
|
|
114
|
+
status TEXT DEFAULT 'running',
|
|
115
|
+
max_iterations INTEGER DEFAULT 20,
|
|
116
|
+
timeout_minutes INTEGER DEFAULT 30,
|
|
117
|
+
started_at TEXT NOT NULL
|
|
118
|
+
)
|
|
119
|
+
`);
|
|
120
|
+
db.exec(`
|
|
121
|
+
CREATE TABLE IF NOT EXISTS task_auto_steps (
|
|
122
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
123
|
+
session_name TEXT NOT NULL,
|
|
124
|
+
step TEXT NOT NULL,
|
|
125
|
+
result TEXT DEFAULT '',
|
|
126
|
+
next TEXT DEFAULT '',
|
|
127
|
+
checkpoint TEXT DEFAULT '',
|
|
128
|
+
iteration INTEGER DEFAULT 0,
|
|
129
|
+
started_at TEXT NOT NULL,
|
|
130
|
+
ended_at TEXT
|
|
131
|
+
)
|
|
132
|
+
`);
|
|
133
|
+
db.exec('CREATE INDEX IF NOT EXISTS idx_auto_steps_session ON task_auto_steps(session_name)');
|
|
134
|
+
// --- Auto mode statements ---
|
|
135
|
+
const stmtAutoInsert = db.prepare(`
|
|
136
|
+
INSERT INTO task_auto (session_name, task_dir, status, max_iterations, timeout_minutes, started_at)
|
|
137
|
+
VALUES (?, ?, 'running', ?, ?, ?)
|
|
138
|
+
`);
|
|
139
|
+
const stmtAutoGet = db.prepare('SELECT * FROM task_auto WHERE session_name = ?');
|
|
140
|
+
const stmtAutoGetAll = db.prepare("SELECT * FROM task_auto WHERE status = 'running'");
|
|
141
|
+
const stmtAutoUpdateStatus = db.prepare('UPDATE task_auto SET status = ? WHERE session_name = ?');
|
|
142
|
+
const stmtAutoDelete = db.prepare('DELETE FROM task_auto WHERE session_name = ?');
|
|
143
|
+
const stmtAutoStepInsert = db.prepare(`
|
|
144
|
+
INSERT INTO task_auto_steps (session_name, step, result, next, checkpoint, iteration, started_at)
|
|
145
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
146
|
+
`);
|
|
147
|
+
const stmtAutoStepEnd = db.prepare('UPDATE task_auto_steps SET ended_at = ? WHERE id = ?');
|
|
148
|
+
const stmtAutoStepGetAll = db.prepare('SELECT * FROM task_auto_steps WHERE session_name = ? ORDER BY id ASC');
|
|
149
|
+
const stmtAutoStepGetLast = db.prepare('SELECT * FROM task_auto_steps WHERE session_name = ? ORDER BY id DESC LIMIT 1');
|
|
150
|
+
const stmtAutoStepsDelete = db.prepare('DELETE FROM task_auto_steps WHERE session_name = ?');
|
|
151
|
+
export function createAutoSession(sessionName, taskDir, maxIterations, timeoutMinutes) {
|
|
152
|
+
stmtAutoInsert.run(sessionName, taskDir, maxIterations, timeoutMinutes, new Date().toISOString());
|
|
153
|
+
}
|
|
154
|
+
export function getAutoSession(sessionName) {
|
|
155
|
+
return stmtAutoGet.get(sessionName) ?? null;
|
|
156
|
+
}
|
|
157
|
+
export function getAllRunningAutoSessions() {
|
|
158
|
+
return stmtAutoGetAll.all();
|
|
159
|
+
}
|
|
160
|
+
export function updateAutoStatus(sessionName, status) {
|
|
161
|
+
stmtAutoUpdateStatus.run(status, sessionName);
|
|
162
|
+
}
|
|
163
|
+
export function deleteAutoSession(sessionName) {
|
|
164
|
+
stmtAutoDelete.run(sessionName);
|
|
165
|
+
}
|
|
166
|
+
export function insertAutoStep(sessionName, step, result, next, checkpoint, iteration) {
|
|
167
|
+
const info = stmtAutoStepInsert.run(sessionName, step, result, next, checkpoint, iteration, new Date().toISOString());
|
|
168
|
+
return Number(info.lastInsertRowid);
|
|
169
|
+
}
|
|
170
|
+
export function endAutoStep(stepId) {
|
|
171
|
+
stmtAutoStepEnd.run(new Date().toISOString(), stepId);
|
|
172
|
+
}
|
|
173
|
+
export function getAutoSteps(sessionName) {
|
|
174
|
+
return stmtAutoStepGetAll.all(sessionName);
|
|
175
|
+
}
|
|
176
|
+
export function getLastAutoStep(sessionName) {
|
|
177
|
+
return stmtAutoStepGetLast.get(sessionName) ?? null;
|
|
178
|
+
}
|
|
179
|
+
export function deleteAutoSteps(sessionName) {
|
|
180
|
+
stmtAutoStepsDelete.run(sessionName);
|
|
181
|
+
}
|
|
109
182
|
export function closeDb() {
|
|
110
183
|
db.close();
|
|
111
184
|
}
|
package/server/dist/index.js
CHANGED
|
@@ -19,6 +19,7 @@ import filesRouter from './routes/files.js';
|
|
|
19
19
|
import editorRouter from './routes/editor.js';
|
|
20
20
|
import settingsRouter from './routes/settings.js';
|
|
21
21
|
import gitRouter from './routes/git.js';
|
|
22
|
+
import taskAutoRouter, { recoverAutoSessions, stopAllWatchers } from './routes/taskAuto.js';
|
|
22
23
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
23
24
|
config();
|
|
24
25
|
const PORT = process.env.PORT || 3001;
|
|
@@ -101,6 +102,7 @@ async function main() {
|
|
|
101
102
|
app.use(editorRouter);
|
|
102
103
|
app.use(settingsRouter);
|
|
103
104
|
app.use(gitRouter);
|
|
105
|
+
app.use(taskAutoRouter);
|
|
104
106
|
// --- Static files ---
|
|
105
107
|
const webDistPath = join(__dirname, '../../web/dist');
|
|
106
108
|
if (existsSync(webDistPath)) {
|
|
@@ -175,6 +177,12 @@ async function main() {
|
|
|
175
177
|
catch (e) {
|
|
176
178
|
console.error('[startup:drafts]', e);
|
|
177
179
|
}
|
|
180
|
+
try {
|
|
181
|
+
recoverAutoSessions();
|
|
182
|
+
}
|
|
183
|
+
catch (e) {
|
|
184
|
+
console.error('[startup:auto-recover]', e);
|
|
185
|
+
}
|
|
178
186
|
const CLEANUP_INTERVAL = 60 * 60 * 1000;
|
|
179
187
|
const cleanupTimer = setInterval(async () => {
|
|
180
188
|
try {
|
|
@@ -201,6 +209,7 @@ async function main() {
|
|
|
201
209
|
const shutdown = () => {
|
|
202
210
|
console.log('\n[shutdown] Closing server...');
|
|
203
211
|
clearWsIntervals();
|
|
212
|
+
stopAllWatchers();
|
|
204
213
|
if (cleanupTimer)
|
|
205
214
|
clearInterval(cleanupTimer);
|
|
206
215
|
wss.clients.forEach((client) => {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Router } from 'express';
|
|
2
2
|
import { extractToken, checkAuth, resolveSession } from '../middleware/auth.js';
|
|
3
|
-
import { listSessions, killSession, buildSessionName, getCwd, getPaneCommand } from '../tmux.js';
|
|
3
|
+
import { listSessions, killSession, buildSessionName, getCwd, getPaneCommand, captureScrollback } from '../tmux.js';
|
|
4
4
|
import { getActiveSessionNames } from '../websocket.js';
|
|
5
5
|
import { deleteDraft } from '../db.js';
|
|
6
6
|
const router = Router();
|
|
@@ -61,4 +61,18 @@ router.get('/api/sessions/:sessionId/pane-command', async (req, res) => {
|
|
|
61
61
|
res.json({ command: '' });
|
|
62
62
|
}
|
|
63
63
|
});
|
|
64
|
+
// Capture pane scrollback content (for live terminal popup)
|
|
65
|
+
router.get('/api/sessions/:sessionId/capture-pane', async (req, res) => {
|
|
66
|
+
const sessionName = resolveSession(req, res);
|
|
67
|
+
if (!sessionName)
|
|
68
|
+
return;
|
|
69
|
+
try {
|
|
70
|
+
const content = await captureScrollback(sessionName);
|
|
71
|
+
res.json({ content });
|
|
72
|
+
}
|
|
73
|
+
catch (err) {
|
|
74
|
+
console.error(`[api:capture-pane] ${sessionName}:`, err);
|
|
75
|
+
res.status(500).json({ error: 'Failed to capture pane content' });
|
|
76
|
+
}
|
|
77
|
+
});
|
|
64
78
|
export default router;
|
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
import { Router } from 'express';
|
|
2
|
+
import { resolveSession } from '../middleware/auth.js';
|
|
3
|
+
import { createAutoSession, getAutoSession, getAllRunningAutoSessions, updateAutoStatus, deleteAutoSession, insertAutoStep, endAutoStep, getAutoSteps, getLastAutoStep, deleteAutoSteps, } from '../db.js';
|
|
4
|
+
import { watch, readFileSync, writeFileSync, existsSync } from 'fs';
|
|
5
|
+
import { join } from 'path';
|
|
6
|
+
const router = Router();
|
|
7
|
+
// In-memory watcher map: sessionName → FSWatcher
|
|
8
|
+
const watchers = new Map();
|
|
9
|
+
function parseSignalFile(taskDir) {
|
|
10
|
+
const signalPath = join(taskDir, '.auto-signal');
|
|
11
|
+
try {
|
|
12
|
+
if (!existsSync(signalPath))
|
|
13
|
+
return null;
|
|
14
|
+
const raw = readFileSync(signalPath, 'utf-8').trim();
|
|
15
|
+
if (!raw)
|
|
16
|
+
return null;
|
|
17
|
+
return JSON.parse(raw);
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
function formatDuration(startedAt, endedAt) {
|
|
24
|
+
const start = new Date(startedAt).getTime();
|
|
25
|
+
const end = endedAt ? new Date(endedAt).getTime() : Date.now();
|
|
26
|
+
const sec = Math.round((end - start) / 1000);
|
|
27
|
+
if (sec < 60)
|
|
28
|
+
return `${sec}s`;
|
|
29
|
+
const min = Math.floor(sec / 60);
|
|
30
|
+
const rem = sec % 60;
|
|
31
|
+
if (min < 60)
|
|
32
|
+
return rem > 0 ? `${min}m ${rem}s` : `${min}m`;
|
|
33
|
+
const hr = Math.floor(min / 60);
|
|
34
|
+
const mrem = min % 60;
|
|
35
|
+
return mrem > 0 ? `${hr}h ${mrem}m` : `${hr}h`;
|
|
36
|
+
}
|
|
37
|
+
function formatTime(iso) {
|
|
38
|
+
return iso.replace('T', ' ').replace(/\.\d+Z$/, '').replace('Z', '');
|
|
39
|
+
}
|
|
40
|
+
/** Write .auto-timeline.md to the task directory with the full step history */
|
|
41
|
+
function writeTimelineFile(sessionName, taskDir) {
|
|
42
|
+
const session = getAutoSession(sessionName);
|
|
43
|
+
if (!session)
|
|
44
|
+
return;
|
|
45
|
+
const steps = getAutoSteps(sessionName);
|
|
46
|
+
if (steps.length === 0)
|
|
47
|
+
return;
|
|
48
|
+
const totalDuration = formatDuration(session.started_at, steps[steps.length - 1].ended_at ?? new Date().toISOString());
|
|
49
|
+
const endTime = steps[steps.length - 1].ended_at ?? new Date().toISOString();
|
|
50
|
+
const lines = [];
|
|
51
|
+
lines.push(`## Execution Timeline`);
|
|
52
|
+
lines.push(``);
|
|
53
|
+
lines.push(`- **Status**: ${session.status}`);
|
|
54
|
+
lines.push(`- **Total Duration**: ${totalDuration} (${formatTime(session.started_at)} → ${formatTime(endTime)})`);
|
|
55
|
+
const maxIter = Math.max(...steps.map(s => s.iteration));
|
|
56
|
+
if (maxIter > 0)
|
|
57
|
+
lines.push(`- **Iterations**: ${maxIter}`);
|
|
58
|
+
lines.push(``);
|
|
59
|
+
// Table
|
|
60
|
+
lines.push(`| # | Phase | Result | Checkpoint | Duration | Started | Ended |`);
|
|
61
|
+
lines.push(`|---|-------|--------|------------|----------|---------|-------|`);
|
|
62
|
+
for (let i = 0; i < steps.length; i++) {
|
|
63
|
+
const s = steps[i];
|
|
64
|
+
const dur = s.ended_at ? formatDuration(s.started_at, s.ended_at) : 'running';
|
|
65
|
+
const cp = s.checkpoint || '';
|
|
66
|
+
const started = formatTime(s.started_at).split(' ')[1] || '';
|
|
67
|
+
const ended = s.ended_at ? (formatTime(s.ended_at).split(' ')[1] || '') : '—';
|
|
68
|
+
lines.push(`| ${i + 1} | ${s.step} | ${s.result} | ${cp} | ${dur} | ${started} | ${ended} |`);
|
|
69
|
+
}
|
|
70
|
+
lines.push(``);
|
|
71
|
+
// Visual flow — show result only for decision steps (check, merge)
|
|
72
|
+
const flow = steps.map(s => {
|
|
73
|
+
const dur = s.ended_at ? formatDuration(s.started_at, s.ended_at) : '...';
|
|
74
|
+
const showResult = s.step === 'check' || s.step === 'merge';
|
|
75
|
+
const label = showResult ? `${s.step}:${s.result}` : s.step;
|
|
76
|
+
return `${label}(${dur})`;
|
|
77
|
+
}).join(' → ');
|
|
78
|
+
lines.push(`**Flow**: ${flow}`);
|
|
79
|
+
lines.push(``);
|
|
80
|
+
try {
|
|
81
|
+
writeFileSync(join(taskDir, '.auto-timeline.md'), lines.join('\n'));
|
|
82
|
+
}
|
|
83
|
+
catch (err) {
|
|
84
|
+
console.error(`[taskAuto] Failed to write .auto-timeline.md:`, err);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
function processSignal(sessionName, signal) {
|
|
88
|
+
const lastStep = getLastAutoStep(sessionName);
|
|
89
|
+
// If same step+result+checkpoint as last, skip (no transition)
|
|
90
|
+
if (lastStep &&
|
|
91
|
+
lastStep.step === signal.step &&
|
|
92
|
+
lastStep.result === (signal.result || '') &&
|
|
93
|
+
lastStep.checkpoint === (signal.checkpoint || '')) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
// End previous step if it has no ended_at
|
|
97
|
+
if (lastStep && !lastStep.ended_at) {
|
|
98
|
+
endAutoStep(lastStep.id);
|
|
99
|
+
}
|
|
100
|
+
// Insert new step
|
|
101
|
+
insertAutoStep(sessionName, signal.step, signal.result || '', signal.next || '', signal.checkpoint || '', signal.iteration ?? 0);
|
|
102
|
+
// If next is "(stop)" or "(done)", mark auto session as completed
|
|
103
|
+
if (signal.next === '(stop)' || signal.next === '(done)') {
|
|
104
|
+
// End the just-inserted step
|
|
105
|
+
const newLast = getLastAutoStep(sessionName);
|
|
106
|
+
if (newLast && !newLast.ended_at) {
|
|
107
|
+
endAutoStep(newLast.id);
|
|
108
|
+
}
|
|
109
|
+
updateAutoStatus(sessionName, 'completed');
|
|
110
|
+
// Write timeline file before stopping
|
|
111
|
+
const session = getAutoSession(sessionName);
|
|
112
|
+
if (session)
|
|
113
|
+
writeTimelineFile(sessionName, session.task_dir);
|
|
114
|
+
stopWatcher(sessionName);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
function startWatcher(sessionName, taskDir) {
|
|
118
|
+
stopWatcher(sessionName);
|
|
119
|
+
try {
|
|
120
|
+
const watcher = watch(taskDir, (_eventType, filename) => {
|
|
121
|
+
if (filename === '.auto-signal') {
|
|
122
|
+
const signal = parseSignalFile(taskDir);
|
|
123
|
+
if (signal) {
|
|
124
|
+
try {
|
|
125
|
+
processSignal(sessionName, signal);
|
|
126
|
+
}
|
|
127
|
+
catch (err) {
|
|
128
|
+
console.error(`[taskAuto:watcher] Error processing signal for ${sessionName}:`, err);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
// Detect .auto-stop written by the auto skill itself
|
|
133
|
+
if (filename === '.auto-stop') {
|
|
134
|
+
const session = getAutoSession(sessionName);
|
|
135
|
+
if (session && session.status === 'running') {
|
|
136
|
+
const lastStep = getLastAutoStep(sessionName);
|
|
137
|
+
if (lastStep && !lastStep.ended_at) {
|
|
138
|
+
endAutoStep(lastStep.id);
|
|
139
|
+
}
|
|
140
|
+
updateAutoStatus(sessionName, 'stopped');
|
|
141
|
+
writeTimelineFile(sessionName, session.task_dir);
|
|
142
|
+
stopWatcher(sessionName);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
watchers.set(sessionName, watcher);
|
|
147
|
+
}
|
|
148
|
+
catch (err) {
|
|
149
|
+
console.error(`[taskAuto] Failed to watch ${taskDir}:`, err);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
function stopWatcher(sessionName) {
|
|
153
|
+
const watcher = watchers.get(sessionName);
|
|
154
|
+
if (watcher) {
|
|
155
|
+
try {
|
|
156
|
+
watcher.close();
|
|
157
|
+
}
|
|
158
|
+
catch { /* ignore */ }
|
|
159
|
+
watchers.delete(sessionName);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
// --- REST endpoints ---
|
|
163
|
+
// POST: Start auto tracking
|
|
164
|
+
router.post('/api/sessions/:sessionId/task-auto', (req, res) => {
|
|
165
|
+
const sessionName = resolveSession(req, res);
|
|
166
|
+
if (!sessionName)
|
|
167
|
+
return;
|
|
168
|
+
const { taskDir, maxIterations = 20, timeoutMinutes = 1440 } = req.body || {};
|
|
169
|
+
if (!taskDir || typeof taskDir !== 'string') {
|
|
170
|
+
res.status(400).json({ error: 'taskDir is required' });
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
// Check if already tracking
|
|
174
|
+
const existing = getAutoSession(sessionName);
|
|
175
|
+
if (existing && existing.status === 'running') {
|
|
176
|
+
res.status(409).json({ error: 'Auto already running for this session' });
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
// Clean up any old data
|
|
180
|
+
if (existing) {
|
|
181
|
+
deleteAutoSteps(sessionName);
|
|
182
|
+
deleteAutoSession(sessionName);
|
|
183
|
+
}
|
|
184
|
+
try {
|
|
185
|
+
createAutoSession(sessionName, taskDir, maxIterations, timeoutMinutes);
|
|
186
|
+
// Read initial signal if exists
|
|
187
|
+
const signal = parseSignalFile(taskDir);
|
|
188
|
+
if (signal) {
|
|
189
|
+
processSignal(sessionName, signal);
|
|
190
|
+
}
|
|
191
|
+
startWatcher(sessionName, taskDir);
|
|
192
|
+
res.json({ ok: true });
|
|
193
|
+
}
|
|
194
|
+
catch (err) {
|
|
195
|
+
console.error('[taskAuto:start]', err);
|
|
196
|
+
res.status(500).json({ error: 'Failed to start auto tracking' });
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
// GET: Get auto status + step history
|
|
200
|
+
router.get('/api/sessions/:sessionId/task-auto', (req, res) => {
|
|
201
|
+
const sessionName = resolveSession(req, res);
|
|
202
|
+
if (!sessionName)
|
|
203
|
+
return;
|
|
204
|
+
const session = getAutoSession(sessionName);
|
|
205
|
+
if (!session) {
|
|
206
|
+
res.json(null);
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
const steps = getAutoSteps(sessionName);
|
|
210
|
+
const startedAt = new Date(session.started_at);
|
|
211
|
+
const elapsedMinutes = (Date.now() - startedAt.getTime()) / 60000;
|
|
212
|
+
res.json({
|
|
213
|
+
status: session.status,
|
|
214
|
+
taskDir: session.task_dir,
|
|
215
|
+
maxIterations: session.max_iterations,
|
|
216
|
+
timeoutMinutes: session.timeout_minutes,
|
|
217
|
+
startedAt: session.started_at,
|
|
218
|
+
elapsedMinutes: Math.round(elapsedMinutes * 10) / 10,
|
|
219
|
+
steps: steps.map((s) => ({
|
|
220
|
+
id: s.id,
|
|
221
|
+
step: s.step,
|
|
222
|
+
result: s.result,
|
|
223
|
+
next: s.next,
|
|
224
|
+
checkpoint: s.checkpoint,
|
|
225
|
+
iteration: s.iteration,
|
|
226
|
+
startedAt: s.started_at,
|
|
227
|
+
endedAt: s.ended_at,
|
|
228
|
+
})),
|
|
229
|
+
});
|
|
230
|
+
});
|
|
231
|
+
// DELETE: Stop auto tracking
|
|
232
|
+
router.delete('/api/sessions/:sessionId/task-auto', (req, res) => {
|
|
233
|
+
const sessionName = resolveSession(req, res);
|
|
234
|
+
if (!sessionName)
|
|
235
|
+
return;
|
|
236
|
+
const session = getAutoSession(sessionName);
|
|
237
|
+
if (!session) {
|
|
238
|
+
res.status(404).json({ error: 'No auto session found' });
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
// If already finished (completed/cancelled/stopped), just clean up records
|
|
242
|
+
if (session.status !== 'running') {
|
|
243
|
+
deleteAutoSteps(sessionName);
|
|
244
|
+
deleteAutoSession(sessionName);
|
|
245
|
+
res.json({ ok: true });
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
// Write .auto-stop to signal the auto subprocess to halt
|
|
249
|
+
try {
|
|
250
|
+
const stopPath = join(session.task_dir, '.auto-stop');
|
|
251
|
+
writeFileSync(stopPath, JSON.stringify({ reason: 'user_stop', timestamp: new Date().toISOString() }));
|
|
252
|
+
}
|
|
253
|
+
catch (err) {
|
|
254
|
+
console.error('[taskAuto:stop] Failed to write .auto-stop:', err);
|
|
255
|
+
}
|
|
256
|
+
// End last step
|
|
257
|
+
const lastStep = getLastAutoStep(sessionName);
|
|
258
|
+
if (lastStep && !lastStep.ended_at) {
|
|
259
|
+
endAutoStep(lastStep.id);
|
|
260
|
+
}
|
|
261
|
+
updateAutoStatus(sessionName, 'cancelled');
|
|
262
|
+
writeTimelineFile(sessionName, session.task_dir);
|
|
263
|
+
stopWatcher(sessionName);
|
|
264
|
+
res.json({ ok: true });
|
|
265
|
+
});
|
|
266
|
+
// --- Server restart recovery ---
|
|
267
|
+
export function recoverAutoSessions() {
|
|
268
|
+
const sessions = getAllRunningAutoSessions();
|
|
269
|
+
for (const session of sessions) {
|
|
270
|
+
if (existsSync(session.task_dir)) {
|
|
271
|
+
console.log(`[taskAuto:recover] Resuming watcher for ${session.session_name}`);
|
|
272
|
+
// Process any signals that arrived while server was down
|
|
273
|
+
const signal = parseSignalFile(session.task_dir);
|
|
274
|
+
if (signal) {
|
|
275
|
+
try {
|
|
276
|
+
processSignal(session.session_name, signal);
|
|
277
|
+
}
|
|
278
|
+
catch { /* ignore */ }
|
|
279
|
+
}
|
|
280
|
+
// Check if still running after processing
|
|
281
|
+
const updated = getAutoSession(session.session_name);
|
|
282
|
+
if (updated && updated.status === 'running') {
|
|
283
|
+
startWatcher(session.session_name, session.task_dir);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
else {
|
|
287
|
+
console.log(`[taskAuto:recover] Task dir gone for ${session.session_name}, cleaning up`);
|
|
288
|
+
deleteAutoSteps(session.session_name);
|
|
289
|
+
deleteAutoSession(session.session_name);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
export function stopAllWatchers() {
|
|
294
|
+
for (const [, watcher] of watchers) {
|
|
295
|
+
try {
|
|
296
|
+
watcher.close();
|
|
297
|
+
}
|
|
298
|
+
catch { /* ignore */ }
|
|
299
|
+
}
|
|
300
|
+
watchers.clear();
|
|
301
|
+
}
|
|
302
|
+
export default router;
|
package/server/package.json
CHANGED
package/shared/package.json
CHANGED
|
@@ -29,4 +29,4 @@
|
|
|
29
29
|
* The original design remains. The terminal itself
|
|
30
30
|
* has been extended to include xterm CSI codes, among
|
|
31
31
|
* other features.
|
|
32
|
-
*/.xterm{cursor:text;position:relative;user-select:none;-ms-user-select:none;-webkit-user-select:none}.xterm.focus,.xterm:focus{outline:none}.xterm .xterm-helpers{position:absolute;top:0;z-index:5}.xterm .xterm-helper-textarea{padding:0;border:0;margin:0;position:absolute;opacity:0;left:-9999em;top:0;width:0;height:0;z-index:-5;white-space:nowrap;overflow:hidden;resize:none}.xterm .composition-view{background:#000;color:#fff;display:none;position:absolute;white-space:nowrap;z-index:1}.xterm .composition-view.active{display:block}.xterm .xterm-viewport{background-color:#000;overflow-y:scroll;cursor:default;position:absolute;right:0;left:0;top:0;bottom:0}.xterm .xterm-screen{position:relative}.xterm .xterm-screen canvas{position:absolute;left:0;top:0}.xterm-char-measure-element{display:inline-block;visibility:hidden;position:absolute;top:0;left:-9999em;line-height:normal}.xterm.enable-mouse-events{cursor:default}.xterm.xterm-cursor-pointer,.xterm .xterm-cursor-pointer{cursor:pointer}.xterm.column-select.focus{cursor:crosshair}.xterm .xterm-accessibility:not(.debug),.xterm .xterm-message{position:absolute;left:0;top:0;bottom:0;right:0;z-index:10;color:transparent;pointer-events:none}.xterm .xterm-accessibility-tree:not(.debug) *::selection{color:transparent}.xterm .xterm-accessibility-tree{font-family:monospace;-webkit-user-select:text;user-select:text;white-space:pre}.xterm .xterm-accessibility-tree>div{transform-origin:left;width:fit-content}.xterm .live-region{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}.xterm-dim{opacity:1!important}.xterm-underline-1{text-decoration:underline}.xterm-underline-2{text-decoration:double underline}.xterm-underline-3{text-decoration:wavy underline}.xterm-underline-4{text-decoration:dotted underline}.xterm-underline-5{text-decoration:dashed underline}.xterm-overline{text-decoration:overline}.xterm-overline.xterm-underline-1{text-decoration:overline underline}.xterm-overline.xterm-underline-2{text-decoration:overline double underline}.xterm-overline.xterm-underline-3{text-decoration:overline wavy underline}.xterm-overline.xterm-underline-4{text-decoration:overline dotted underline}.xterm-overline.xterm-underline-5{text-decoration:overline dashed underline}.xterm-strikethrough{text-decoration:line-through}.xterm-screen .xterm-decoration-container .xterm-decoration{z-index:6;position:absolute}.xterm-screen .xterm-decoration-container .xterm-decoration.xterm-decoration-top-layer{z-index:7}.xterm-decoration-overview-ruler{z-index:8;position:absolute;top:0;right:0;pointer-events:none}.xterm-decoration-top{z-index:2;position:relative}.xterm .xterm-scrollable-element>.scrollbar{cursor:default}.xterm .xterm-scrollable-element>.scrollbar>.scra{cursor:pointer;font-size:11px!important}.xterm .xterm-scrollable-element>.visible{opacity:1;background:#0000;transition:opacity .1s linear;z-index:11}.xterm .xterm-scrollable-element>.invisible{opacity:0;pointer-events:none}.xterm .xterm-scrollable-element>.invisible.fade{transition:opacity .8s linear}.xterm .xterm-scrollable-element>.shadow{position:absolute;display:none}.xterm .xterm-scrollable-element>.shadow.top{display:block;top:0;left:3px;height:3px;width:100%;box-shadow:var(--vscode-scrollbar-shadow, #000) 0 6px 6px -6px inset}.xterm .xterm-scrollable-element>.shadow.left{display:block;top:3px;left:0;height:100%;width:3px;box-shadow:var(--vscode-scrollbar-shadow, #000) 6px 0 6px -6px inset}.xterm .xterm-scrollable-element>.shadow.top-left-corner{display:block;top:0;left:0;height:3px;width:3px}.xterm .xterm-scrollable-element>.shadow.top.left{box-shadow:var(--vscode-scrollbar-shadow, #000) 6px 0 6px -6px inset}@font-face{font-family:JetBrains Mono;src:url(/fonts/JetBrainsMono-Regular.woff2) format("woff2");font-weight:400;font-style:normal;font-display:swap}@font-face{font-family:JetBrains Mono;src:url(/fonts/JetBrainsMono-Bold.woff2) format("woff2");font-weight:700;font-style:normal;font-display:swap}:root,[data-theme=dark]{--bg-primary: #000000;--bg-secondary: #0c0c0c;--bg-tertiary: #171717;--bg-hover: #1c1c1c;--border: #2d2d2d;--text-primary: #cccccc;--text-secondary: #858585;--text-bright: #e8e8e8;--accent-blue: #569cd6;--accent-purple: #c586c0;--accent-cyan: #4ec9b0;--accent-green: #89d185;--accent-yellow: #cca700;--accent-red: #f44747;--accent-orange: #ce9178;--scrollbar-thumb: rgba(121, 121, 121, .4);--scrollbar-thumb-hover: rgba(121, 121, 121, .7);--selection-bg: rgba(38, 79, 120, .5)}[data-theme=light]{--bg-primary: #ffffff;--bg-secondary: #f6f8fa;--bg-tertiary: #ffffff;--bg-hover: #eff2f5;--border: #d1d9e0;--text-primary: #1f2328;--text-secondary: #59636e;--text-bright: #1f2328;--accent-blue: #0969da;--accent-purple: #8250df;--accent-cyan: #1b7c83;--accent-green: #1a7f37;--accent-yellow: #9a6700;--accent-red: #d1242f;--accent-orange: #bc4c00;--scrollbar-thumb: rgba(31, 35, 40, .15);--scrollbar-thumb-hover: rgba(31, 35, 40, .3);--selection-bg: rgba(9, 105, 218, .2)}*{margin:0;padding:0;box-sizing:border-box}html,body,#root{width:100%;height:100%;overflow:hidden;background-color:var(--bg-primary);font-family:JetBrains Mono,LXGW WenKai Mono,Menlo,Monaco,Courier New,monospace;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;text-rendering:optimizeLegibility}body.resizing-panes,body.resizing-panes *{cursor:col-resize!important;-webkit-user-select:none!important;user-select:none!important}.session-sidebar{transition:width .2s ease;overflow:hidden;flex-shrink:0;z-index:10;position:relative}body.resizing-panes-v,body.resizing-panes-v *{cursor:row-resize!important;-webkit-user-select:none!important;user-select:none!important}button{transition:all .15s ease;font-family:inherit}button:hover{filter:brightness(1.2)}button:active{transform:scale(.97)}::-webkit-scrollbar{width:6px;height:6px}::-webkit-scrollbar-track{background:transparent}::-webkit-scrollbar-thumb{background:var(--scrollbar-thumb);border-radius:3px}::-webkit-scrollbar-thumb:hover{background:var(--scrollbar-thumb-hover)}::selection{background:var(--selection-bg);color:var(--text-bright)}input:focus-visible,button:focus-visible{outline:1px solid var(--accent-blue);outline-offset:1px}.header-btn{background:none;border:1px solid var(--border);color:var(--accent-blue);padding:3px 10px;border-radius:5px;cursor:pointer;font-size:13px;line-height:1.4;transition:all .15s ease}.header-btn:hover{background:#7aa2f71f;border-color:var(--accent-blue);box-shadow:0 0 8px #7aa2f726}.header-btn--muted{color:var(--text-secondary);font-size:12px}.header-btn--muted:hover{color:var(--text-primary);border-color:var(--text-secondary);background:#565f891a}.pane-btn{background:none;border:none;color:var(--text-secondary);cursor:pointer;font-size:12px;line-height:1;padding:2px 5px;border-radius:4px;transition:all .15s ease}.pane-btn:hover{color:var(--accent-blue);background:#7aa2f71f}.pane-btn--danger:hover{color:var(--accent-red);background:#f7768e1f}.login-input{transition:border-color .2s ease,box-shadow .2s ease}.login-input:focus{border-color:var(--accent-blue)!important;box-shadow:0 0 0 3px #7aa2f726}.login-card{box-shadow:0 8px 32px #0006,0 0 0 1px #7aa2f714;transition:box-shadow .3s ease}.login-submit{transition:all .2s ease}.login-submit:not(:disabled):hover{filter:brightness(1.1);box-shadow:0 4px 12px #7aa2f74d}.md-editor-textarea{flex:1;min-width:0;resize:none;border:none;outline:none;padding:8px 12px;font-family:JetBrains Mono,LXGW WenKai Mono,Menlo,Monaco,Courier New,monospace;font-size:13px;line-height:1.5;color:var(--text-primary);background-color:var(--bg-primary);-moz-tab-size:2;tab-size:2}.md-editor-textarea::placeholder{color:var(--scrollbar-thumb-hover);font-style:italic}.md-editor-divider{height:3px;background:var(--border);cursor:row-resize;flex-shrink:0;transition:background .15s ease,box-shadow .15s ease}.md-editor-divider:hover{background:var(--accent-blue);box-shadow:0 0 6px #7aa2f766}.pane-btn--active{color:var(--accent-blue)}.plan-panel-body{display:flex;flex-direction:row;flex:1;min-height:0;overflow:hidden}.plan-renderer{position:relative;overflow:hidden;padding:0;min-width:0;-webkit-user-select:text;user-select:text}.plan-divider-h{width:2px;background:var(--border);cursor:col-resize;flex-shrink:0;transition:background .15s ease,box-shadow .15s ease}.plan-divider-h:hover{background:var(--accent-blue);box-shadow:0 0 6px #7aa2f766}.plan-editor-wrap{flex:1;display:flex;flex-direction:column;min-width:0;overflow:hidden}.plan-filename-input{background:var(--bg-primary);border:1px solid var(--border);color:var(--text-primary);padding:2px 6px;border-radius:3px;font-family:inherit;font-size:11px;width:120px;outline:none;transition:border-color .15s ease}.plan-filename-input:focus{border-color:var(--accent-blue)}body.resizing-panes-h,body.resizing-panes-h *{cursor:col-resize!important;-webkit-user-select:none!important;user-select:none!important}.md-preview{color:var(--text-primary);font-size:13px;line-height:1.6;word-wrap:break-word}.md-preview h1{color:var(--accent-blue);font-size:1.4em;margin:.6em 0 .3em;padding-bottom:.2em;border-bottom:1px solid var(--border)}.md-preview h2{color:var(--accent-purple);font-size:1.2em;margin:.5em 0 .3em}.md-preview h3{color:var(--accent-cyan);font-size:1.05em;margin:.4em 0 .2em}.md-preview p{margin:.4em 0}.md-preview code{background:var(--bg-tertiary);color:var(--text-bright);padding:1px 4px;border-radius:3px;font-size:.9em;font-family:JetBrains Mono,LXGW WenKai Mono,monospace}.md-preview pre{background:var(--bg-tertiary);border:1px solid var(--border);border-radius:4px;padding:10px 12px;overflow-x:auto;margin:.5em 0}.md-preview pre code{background:none;padding:0;border-radius:0}.md-preview blockquote{border-left:3px solid var(--accent-blue);padding:2px 12px;margin:.4em 0;color:var(--text-secondary)}.md-preview ul,.md-preview ol{padding-left:1.5em;margin:.3em 0}.md-preview li{margin:.15em 0}.md-preview table{border-collapse:collapse;width:100%;margin:.5em 0;font-size:12px}.md-preview th,.md-preview td{border:1px solid var(--border);padding:4px 8px;text-align:left}.md-preview th{background:var(--bg-tertiary);color:var(--accent-blue);font-weight:600}.md-preview a{color:var(--accent-blue);text-decoration:none}.md-preview a:hover{text-decoration:underline}.md-preview hr{border:none;border-top:1px solid var(--border);margin:.6em 0}.slash-dropdown{flex-shrink:0;max-height:200px;overflow-y:auto;background:var(--bg-secondary);border-bottom:1px solid var(--border);z-index:10;font-size:13px}.slash-item{display:flex;align-items:center;gap:10px;padding:6px 12px;cursor:pointer;transition:background .12s ease}.slash-item:hover,.slash-item--active{background:var(--bg-hover)}.slash-cmd{color:var(--accent-blue);font-weight:600;min-width:180px;font-family:JetBrains Mono,LXGW WenKai Mono,monospace}.slash-desc{color:var(--accent-purple);font-size:11px}.file-dropdown{flex-shrink:0;max-height:180px;overflow-y:auto;background:var(--bg-secondary);border-bottom:1px solid var(--border);z-index:10;font-size:12px}.file-item{display:flex;align-items:center;gap:8px;padding:5px 10px;cursor:pointer;transition:background .1s ease}.file-item:hover,.file-item--active{background:var(--bg-hover)}.file-loading{color:var(--text-secondary);cursor:default}.file-icon{flex-shrink:0;width:16px;text-align:center;font-size:13px}.file-name{color:var(--text-bright);font-family:JetBrains Mono,LXGW WenKai Mono,monospace;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.history-dropdown{flex-shrink:0;max-height:260px;overflow-y:auto;background:var(--bg-secondary);border-bottom:1px solid var(--border);z-index:10;font-size:12px}.history-item{display:flex;align-items:flex-start;gap:8px;padding:6px 10px;cursor:pointer;transition:background .1s ease;position:relative}.history-item:hover,.history-item--active{background:var(--bg-hover)}.history-empty{color:var(--text-secondary);cursor:default;justify-content:center;padding:12px}.history-text{flex:1;color:var(--text-bright);font-family:JetBrains Mono,LXGW WenKai Mono,monospace;white-space:pre-wrap;overflow-wrap:break-word;line-height:1.4}.history-time{flex-shrink:0;color:var(--text-secondary);font-size:10px;white-space:nowrap;margin-top:2px}.history-delete{flex-shrink:0;background:none;border:none;color:var(--text-secondary);cursor:pointer;font-size:14px;padding:0 2px;line-height:1;opacity:0;transition:opacity .1s ease,color .1s ease}.history-item:hover .history-delete,.history-item--active .history-delete{opacity:1}.history-delete:hover{color:var(--accent-red)}.tab-bar{display:flex;align-items:center;padding:0 10px;height:32px;background:var(--bg-secondary);border-top:1px solid var(--border);flex-shrink:0;overflow-x:auto;gap:3px}.tab-bar::-webkit-scrollbar{height:0}.tab-item{display:flex;align-items:center;gap:6px;padding:4px 12px;font-size:13px;color:var(--text-secondary);cursor:pointer;border-bottom:2px solid transparent;white-space:nowrap;transition:color .15s ease,border-color .15s ease,background .15s ease,box-shadow .15s ease;border-radius:5px 5px 0 0;-webkit-user-select:none;user-select:none;flex-shrink:0}.tab-item:hover{color:var(--text-primary);background:#7aa2f70f}.tab-item--active{color:var(--text-bright);border-bottom-color:var(--accent-blue);background:#7aa2f71a;box-shadow:inset 0 -1px 0 var(--accent-blue)}.tab-item__name{max-width:150px;overflow:hidden;text-overflow:ellipsis}.tab-item__count{font-size:10px;color:var(--scrollbar-thumb-hover)}.tab-item__close{font-size:14px;line-height:1;color:inherit;opacity:0;background:none;border:none;cursor:pointer;padding:0 2px;border-radius:3px;transition:opacity .1s ease}.tab-item:hover .tab-item__close{opacity:.5}.tab-item__close:hover{opacity:1!important;color:var(--accent-red);background:#f7768e1a}.tab-item__rename-input{background:transparent;border:1px solid var(--accent-blue);color:var(--text-bright);font-size:13px;font-family:inherit;padding:0 6px;border-radius:3px;outline:none;width:100px}.tab-bar-add{background:none;border:1px solid transparent;color:var(--text-secondary);font-size:18px;line-height:1;padding:2px 8px;border-radius:5px;cursor:pointer;margin-left:4px;flex-shrink:0}.tab-bar-add:hover{color:var(--accent-blue);border-color:var(--border);background:#7aa2f71a}.md-editor-actions{display:flex;align-items:center;gap:8px;padding:4px 8px;flex-shrink:0;background:var(--bg-secondary);border-top:1px solid var(--border)}.plan-anno-toolbar{display:flex;align-items:center;gap:6px;padding:3px 10px;height:28px;flex-shrink:0;background:var(--bg-secondary);border-bottom:1px solid var(--border)}.plan-anno-content{-webkit-user-select:text;user-select:text}.plan-insert-zone{position:relative;min-height:12px}.plan-insert-btn{display:none;position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);width:20px;height:20px;border-radius:50%;border:1px solid var(--scrollbar-thumb-hover);background:var(--bg-secondary);color:var(--accent-blue);font-size:15px;line-height:1;cursor:pointer;padding:0 0 1px;z-index:2;transition:background .12s ease,border-color .12s ease,transform .12s ease;align-items:center;justify-content:center}.plan-insert-zone:hover .plan-insert-btn{display:flex}.plan-anno-content--editing .plan-insert-zone:hover .plan-insert-btn{display:none}.plan-empty-placeholder{display:flex;align-items:center;justify-content:center;min-height:120px;color:var(--text-secondary);font-size:13px;font-style:italic;cursor:pointer;-webkit-user-select:none;user-select:none;text-align:center;padding:16px}.plan-empty-placeholder:hover{color:var(--accent-blue)}.plan-insert-btn:hover{background:var(--bg-hover);border-color:var(--accent-blue);transform:translate(-50%,-50%) scale(1.15)}.plan-annotation-card{display:flex;align-items:flex-start;gap:6px;padding:6px 10px;margin:4px 0;background:#e0af681f;border-left:3px solid var(--accent-yellow);border-radius:0 4px 4px 0}.plan-annotation-card--editing{border-left-color:var(--accent-blue);background:#7aa2f70f}.plan-annotation-textarea{flex:1;min-height:36px;max-height:30em;field-sizing:content;resize:vertical;border:1px solid var(--border);border-radius:3px;background:var(--bg-primary);color:var(--text-primary);font-family:JetBrains Mono,LXGW WenKai Mono,monospace;font-size:12px;padding:4px 6px;outline:none;transition:border-color .15s ease}.plan-annotation-textarea:focus{border-color:var(--accent-blue)}.plan-annotation-textarea::placeholder{color:var(--scrollbar-thumb-hover);font-style:italic}.plan-deletion-card{display:flex;align-items:center;gap:6px;padding:2px 8px;margin:2px 0;background:#f7768e0f;border-left:3px solid var(--accent-red);border-radius:0 4px 4px 0;font-size:11px}.plan-selection-float{position:absolute;z-index:1000;display:flex;flex-direction:row;gap:2px;background:var(--bg-secondary);border:1px solid var(--border);border-radius:6px;padding:2px;box-shadow:0 2px 8px #0000004d}.plan-selection-float button{width:24px;height:24px;border-radius:4px;border:none;cursor:pointer;font-size:14px;display:flex;align-items:center;justify-content:center;background:transparent;transition:background .15s,transform .1s}.plan-selection-float button:hover{transform:scale(1.1)}.plan-selection-float__delete{color:var(--accent-red)}.plan-selection-float__delete:hover{background:#f7768e33}.plan-selection-float__replace{color:var(--accent-blue)}.plan-selection-float__replace:hover{background:#7aa2f733}.plan-selection-float__comment{color:var(--accent-green)}.plan-selection-float__comment:hover{background:#9ece6a33}.plan-replace-card{display:flex;align-items:flex-start;gap:6px;padding:2px 8px;margin:2px 0;border-left:3px solid rgba(122,162,247,.6);background:#7aa2f70a;border-radius:0 4px 4px 0;font-size:11px}.plan-comment-card{display:flex;align-items:flex-start;gap:6px;padding:2px 8px;margin:2px 0;border-left:3px solid rgba(158,206,106,.6);background:#9ece6a0a;border-radius:0 4px 4px 0;font-size:11px}.plan-block--deleted{border-left:3px solid rgba(247,118,142,.5);padding-left:8px;border-radius:2px;position:relative}.plan-block--replaced{border-left:3px solid rgba(122,162,247,.5);padding-left:8px;border-radius:2px;position:relative}.plan-block--commented{border-left:3px solid rgba(158,206,106,.5);padding-left:8px;border-radius:2px;position:relative}.mermaid-diagram{margin:8px 0;padding:12px;background:var(--bg-secondary);border:1px solid var(--border);border-radius:6px;overflow-x:auto}.mermaid-diagram svg{display:block;margin:0 auto;max-width:100%;height:auto}.mermaid-error{border-left:3px solid var(--accent-red);padding-left:8px}.mermaid-error__msg{color:var(--accent-red);font-size:11px;margin-top:4px}.pane-btn--sm{font-size:11px;flex-shrink:0}.plan-file-browser{display:flex;flex-direction:column;height:100%;width:100%;background:var(--bg-secondary);overflow:hidden}.plan-file-browser__header{display:flex;align-items:center;justify-content:space-between;padding:4px 8px;height:28px;flex-shrink:0;border-bottom:1px solid var(--border)}.plan-file-browser__title{font-size:11px;color:var(--accent-blue);font-weight:600;letter-spacing:.3px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;direction:rtl;text-align:left}.plan-file-browser__list{flex:1;overflow-y:auto;overflow-x:hidden;padding:2px 0}.plan-file-browser__status{padding:8px 10px;font-size:11px;color:var(--text-secondary);font-style:italic}.plan-file-browser__item{display:flex;align-items:center;padding:3px 8px;font-size:12px;cursor:pointer;gap:5px;transition:background .1s ease;border-left:2px solid transparent}.plan-file-browser__item:hover{background:var(--bg-tertiary)}.plan-file-browser__item--active{background:#7aa2f71a;border-left-color:var(--accent-blue)}.plan-file-browser__item--active .plan-file-browser__name{color:var(--text-bright)}.plan-file-browser__icon{flex-shrink:0;width:14px;font-size:10px;color:var(--text-secondary);text-align:center}.plan-file-browser__name{flex:1;color:var(--text-primary);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}.plan-file-browser__size{flex-shrink:1;font-size:9px;color:var(--scrollbar-thumb-hover);white-space:nowrap;overflow:hidden;min-width:0}.plan-file-browser__create{display:flex;align-items:center;gap:4px;padding:4px 6px;border-top:1px solid var(--border);flex-shrink:0}.plan-file-browser__input{flex:1;min-width:0;background:var(--bg-primary);border:1px solid var(--border);color:var(--text-primary);padding:2px 6px;border-radius:3px;font-family:inherit;font-size:11px;outline:none;transition:border-color .15s ease}.plan-file-browser__input:focus{border-color:var(--accent-blue)}.plan-file-browser__input::placeholder{color:var(--scrollbar-thumb-hover);font-style:italic}.plan-overlay-body{display:flex;flex:1;min-height:0;overflow:hidden}.plan-overlay-center{flex:1;min-width:0;overflow:hidden}.plan-anno-counts{display:inline-flex;align-items:center;gap:4px;font-size:10px;margin-left:4px}.plan-anno-counts__unsent{color:var(--accent-yellow)}.plan-anno-counts__sent{color:var(--accent-green)}.plan-anno-dropdown-trigger{display:flex;align-items:center;gap:4px;padding:2px 6px;border:1px solid var(--border);border-radius:3px;cursor:pointer;background:var(--bg-primary);transition:border-color .15s ease,background .15s ease;min-width:0}.plan-anno-dropdown-trigger:hover,.plan-anno-dropdown-trigger--active{border-color:var(--accent-blue);background:var(--bg-hover)}.plan-anno-dropdown-trigger__text{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:11px;color:var(--text-secondary)}.plan-anno-dropdown-trigger__arrow{flex-shrink:0;font-size:9px;color:var(--text-secondary);transition:transform .15s ease}.plan-anno-dropdown-trigger--active .plan-anno-dropdown-trigger__arrow{transform:rotate(180deg)}.plan-anno-dropdown{position:absolute;top:100%;right:0;z-index:100;width:320px;max-height:300px;display:flex;flex-direction:column;background:var(--bg-secondary);border:1px solid var(--border);border-radius:4px;box-shadow:0 4px 12px #0000004d;overflow:hidden}.plan-anno-dropdown__header{display:flex;align-items:center;justify-content:center;padding:4px 6px;border-bottom:1px solid var(--border);flex-shrink:0}.plan-anno-dropdown__list{flex:1;overflow-y:auto;padding:2px 0}.plan-anno-dropdown__item{display:flex;align-items:center;gap:4px;padding:3px 6px;font-size:11px;border-bottom:1px solid var(--border-subtle, rgba(128,128,128,.1))}.plan-anno-dropdown__item:last-child{border-bottom:none}.plan-anno-dropdown__item--add{border-left:2px solid var(--accent-yellow)}.plan-anno-dropdown__item--del{border-left:2px solid var(--accent-red)}.plan-anno-dropdown__item--rep{border-left:2px solid var(--accent-blue)}.plan-anno-dropdown__item--com{border-left:2px solid var(--accent-green)}.plan-anno-dropdown__type{flex-shrink:0;width:14px;font-weight:700;text-align:center}.plan-anno-dropdown__text{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--text-primary)}.plan-anno-dropdown__badge{flex-shrink:0;font-size:9px;padding:0 4px;border-radius:3px;background:var(--accent-green);color:var(--bg-primary)}.plan-anno-dropdown__empty{padding:8px;text-align:center;font-size:11px;color:var(--text-secondary);font-style:italic}.plan-edit-textarea{width:100%;flex:1;resize:none;border:none;outline:none;padding:8px 12px;font-family:JetBrains Mono,LXGW WenKai Mono,Menlo,Monaco,Courier New,monospace;line-height:1.6;background:var(--bg-primary);color:var(--text-primary);-moz-tab-size:2;tab-size:2}.plan-edit-textarea::placeholder{color:var(--scrollbar-thumb-hover);font-style:italic}
|
|
32
|
+
*/.xterm{cursor:text;position:relative;user-select:none;-ms-user-select:none;-webkit-user-select:none}.xterm.focus,.xterm:focus{outline:none}.xterm .xterm-helpers{position:absolute;top:0;z-index:5}.xterm .xterm-helper-textarea{padding:0;border:0;margin:0;position:absolute;opacity:0;left:-9999em;top:0;width:0;height:0;z-index:-5;white-space:nowrap;overflow:hidden;resize:none}.xterm .composition-view{background:#000;color:#fff;display:none;position:absolute;white-space:nowrap;z-index:1}.xterm .composition-view.active{display:block}.xterm .xterm-viewport{background-color:#000;overflow-y:scroll;cursor:default;position:absolute;right:0;left:0;top:0;bottom:0}.xterm .xterm-screen{position:relative}.xterm .xterm-screen canvas{position:absolute;left:0;top:0}.xterm-char-measure-element{display:inline-block;visibility:hidden;position:absolute;top:0;left:-9999em;line-height:normal}.xterm.enable-mouse-events{cursor:default}.xterm.xterm-cursor-pointer,.xterm .xterm-cursor-pointer{cursor:pointer}.xterm.column-select.focus{cursor:crosshair}.xterm .xterm-accessibility:not(.debug),.xterm .xterm-message{position:absolute;left:0;top:0;bottom:0;right:0;z-index:10;color:transparent;pointer-events:none}.xterm .xterm-accessibility-tree:not(.debug) *::selection{color:transparent}.xterm .xterm-accessibility-tree{font-family:monospace;-webkit-user-select:text;user-select:text;white-space:pre}.xterm .xterm-accessibility-tree>div{transform-origin:left;width:fit-content}.xterm .live-region{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}.xterm-dim{opacity:1!important}.xterm-underline-1{text-decoration:underline}.xterm-underline-2{text-decoration:double underline}.xterm-underline-3{text-decoration:wavy underline}.xterm-underline-4{text-decoration:dotted underline}.xterm-underline-5{text-decoration:dashed underline}.xterm-overline{text-decoration:overline}.xterm-overline.xterm-underline-1{text-decoration:overline underline}.xterm-overline.xterm-underline-2{text-decoration:overline double underline}.xterm-overline.xterm-underline-3{text-decoration:overline wavy underline}.xterm-overline.xterm-underline-4{text-decoration:overline dotted underline}.xterm-overline.xterm-underline-5{text-decoration:overline dashed underline}.xterm-strikethrough{text-decoration:line-through}.xterm-screen .xterm-decoration-container .xterm-decoration{z-index:6;position:absolute}.xterm-screen .xterm-decoration-container .xterm-decoration.xterm-decoration-top-layer{z-index:7}.xterm-decoration-overview-ruler{z-index:8;position:absolute;top:0;right:0;pointer-events:none}.xterm-decoration-top{z-index:2;position:relative}.xterm .xterm-scrollable-element>.scrollbar{cursor:default}.xterm .xterm-scrollable-element>.scrollbar>.scra{cursor:pointer;font-size:11px!important}.xterm .xterm-scrollable-element>.visible{opacity:1;background:#0000;transition:opacity .1s linear;z-index:11}.xterm .xterm-scrollable-element>.invisible{opacity:0;pointer-events:none}.xterm .xterm-scrollable-element>.invisible.fade{transition:opacity .8s linear}.xterm .xterm-scrollable-element>.shadow{position:absolute;display:none}.xterm .xterm-scrollable-element>.shadow.top{display:block;top:0;left:3px;height:3px;width:100%;box-shadow:var(--vscode-scrollbar-shadow, #000) 0 6px 6px -6px inset}.xterm .xterm-scrollable-element>.shadow.left{display:block;top:3px;left:0;height:100%;width:3px;box-shadow:var(--vscode-scrollbar-shadow, #000) 6px 0 6px -6px inset}.xterm .xterm-scrollable-element>.shadow.top-left-corner{display:block;top:0;left:0;height:3px;width:3px}.xterm .xterm-scrollable-element>.shadow.top.left{box-shadow:var(--vscode-scrollbar-shadow, #000) 6px 0 6px -6px inset}@font-face{font-family:JetBrains Mono;src:url(/fonts/JetBrainsMono-Regular.woff2) format("woff2");font-weight:400;font-style:normal;font-display:swap}@font-face{font-family:JetBrains Mono;src:url(/fonts/JetBrainsMono-Bold.woff2) format("woff2");font-weight:700;font-style:normal;font-display:swap}:root,[data-theme=dark]{--bg-primary: #000000;--bg-secondary: #0c0c0c;--bg-tertiary: #171717;--bg-hover: #1c1c1c;--border: #2d2d2d;--text-primary: #cccccc;--text-secondary: #858585;--text-bright: #e8e8e8;--accent-blue: #569cd6;--accent-purple: #c586c0;--accent-cyan: #4ec9b0;--accent-green: #89d185;--accent-yellow: #cca700;--accent-red: #f44747;--accent-orange: #ce9178;--scrollbar-thumb: rgba(121, 121, 121, .4);--scrollbar-thumb-hover: rgba(121, 121, 121, .7);--selection-bg: rgba(38, 79, 120, .5)}[data-theme=light]{--bg-primary: #ffffff;--bg-secondary: #f6f8fa;--bg-tertiary: #ffffff;--bg-hover: #eff2f5;--border: #d1d9e0;--text-primary: #1f2328;--text-secondary: #59636e;--text-bright: #1f2328;--accent-blue: #0969da;--accent-purple: #8250df;--accent-cyan: #1b7c83;--accent-green: #1a7f37;--accent-yellow: #9a6700;--accent-red: #d1242f;--accent-orange: #bc4c00;--scrollbar-thumb: rgba(31, 35, 40, .15);--scrollbar-thumb-hover: rgba(31, 35, 40, .3);--selection-bg: rgba(9, 105, 218, .2)}*{margin:0;padding:0;box-sizing:border-box}html,body,#root{width:100%;height:100%;overflow:hidden;background-color:var(--bg-primary);font-family:JetBrains Mono,LXGW WenKai Mono,Menlo,Monaco,Courier New,monospace;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;text-rendering:optimizeLegibility}body.resizing-panes,body.resizing-panes *{cursor:col-resize!important;-webkit-user-select:none!important;user-select:none!important}.session-sidebar{transition:width .2s ease;overflow:hidden;flex-shrink:0;z-index:10;position:relative}body.resizing-panes-v,body.resizing-panes-v *{cursor:row-resize!important;-webkit-user-select:none!important;user-select:none!important}button{transition:all .15s ease;font-family:inherit}button:hover{filter:brightness(1.2)}button:active{transform:scale(.97)}::-webkit-scrollbar{width:6px;height:6px}::-webkit-scrollbar-track{background:transparent}::-webkit-scrollbar-thumb{background:var(--scrollbar-thumb);border-radius:3px}::-webkit-scrollbar-thumb:hover{background:var(--scrollbar-thumb-hover)}::selection{background:var(--selection-bg);color:var(--text-bright)}input:focus-visible,button:focus-visible{outline:1px solid var(--accent-blue);outline-offset:1px}.header-btn{background:none;border:1px solid var(--border);color:var(--accent-blue);padding:3px 10px;border-radius:5px;cursor:pointer;font-size:13px;line-height:1.4;transition:all .15s ease}.header-btn:hover{background:#7aa2f71f;border-color:var(--accent-blue);box-shadow:0 0 8px #7aa2f726}.header-btn--muted{color:var(--text-secondary);font-size:12px}.header-btn--muted:hover{color:var(--text-primary);border-color:var(--text-secondary);background:#565f891a}.pane-btn{background:none;border:none;color:var(--text-secondary);cursor:pointer;font-size:12px;line-height:1;padding:2px 5px;border-radius:4px;transition:all .15s ease}.pane-btn:hover{color:var(--accent-blue);background:#7aa2f71f}.pane-btn--danger:hover{color:var(--accent-red);background:#f7768e1f}.login-input{transition:border-color .2s ease,box-shadow .2s ease}.login-input:focus{border-color:var(--accent-blue)!important;box-shadow:0 0 0 3px #7aa2f726}.login-card{box-shadow:0 8px 32px #0006,0 0 0 1px #7aa2f714;transition:box-shadow .3s ease}.login-submit{transition:all .2s ease}.login-submit:not(:disabled):hover{filter:brightness(1.1);box-shadow:0 4px 12px #7aa2f74d}.md-editor-textarea{flex:1;min-width:0;resize:none;border:none;outline:none;padding:8px 12px;font-family:JetBrains Mono,LXGW WenKai Mono,Menlo,Monaco,Courier New,monospace;font-size:13px;line-height:1.5;color:var(--text-primary);background-color:var(--bg-primary);-moz-tab-size:2;tab-size:2}.md-editor-textarea::placeholder{color:var(--scrollbar-thumb-hover);font-style:italic}.md-editor-divider{height:3px;background:var(--border);cursor:row-resize;flex-shrink:0;transition:background .15s ease,box-shadow .15s ease}.md-editor-divider:hover{background:var(--accent-blue);box-shadow:0 0 6px #7aa2f766}.pane-btn--active{color:var(--accent-blue)}.plan-panel-body{display:flex;flex-direction:row;flex:1;min-height:0;overflow:hidden}.plan-renderer{position:relative;overflow:hidden;padding:0;min-width:0;-webkit-user-select:text;user-select:text}.plan-divider-h{width:2px;background:var(--border);cursor:col-resize;flex-shrink:0;transition:background .15s ease,box-shadow .15s ease}.plan-divider-h:hover{background:var(--accent-blue);box-shadow:0 0 6px #7aa2f766}.plan-editor-wrap{flex:1;display:flex;flex-direction:column;min-width:0;overflow:hidden}.plan-filename-input{background:var(--bg-primary);border:1px solid var(--border);color:var(--text-primary);padding:2px 6px;border-radius:3px;font-family:inherit;font-size:11px;width:120px;outline:none;transition:border-color .15s ease}.plan-filename-input:focus{border-color:var(--accent-blue)}body.resizing-panes-h,body.resizing-panes-h *{cursor:col-resize!important;-webkit-user-select:none!important;user-select:none!important}.md-preview{color:var(--text-primary);font-size:13px;line-height:1.6;word-wrap:break-word}.md-preview h1{color:var(--accent-blue);font-size:1.4em;margin:.6em 0 .3em;padding-bottom:.2em;border-bottom:1px solid var(--border)}.md-preview h2{color:var(--accent-purple);font-size:1.2em;margin:.5em 0 .3em}.md-preview h3{color:var(--accent-cyan);font-size:1.05em;margin:.4em 0 .2em}.md-preview p{margin:.4em 0}.md-preview code{background:var(--bg-tertiary);color:var(--text-bright);padding:1px 4px;border-radius:3px;font-size:.9em;font-family:JetBrains Mono,LXGW WenKai Mono,monospace}.md-preview pre{background:var(--bg-tertiary);border:1px solid var(--border);border-radius:4px;padding:10px 12px;overflow-x:auto;margin:.5em 0}.md-preview pre code{background:none;padding:0;border-radius:0}.md-preview blockquote{border-left:3px solid var(--accent-blue);padding:2px 12px;margin:.4em 0;color:var(--text-secondary)}.md-preview ul,.md-preview ol{padding-left:1.5em;margin:.3em 0}.md-preview li{margin:.15em 0}.md-preview table{border-collapse:collapse;width:100%;margin:.5em 0;font-size:12px}.md-preview th,.md-preview td{border:1px solid var(--border);padding:4px 8px;text-align:left}.md-preview th{background:var(--bg-tertiary);color:var(--accent-blue);font-weight:600}.md-preview a{color:var(--accent-blue);text-decoration:none}.md-preview a:hover{text-decoration:underline}.md-preview hr{border:none;border-top:1px solid var(--border);margin:.6em 0}.slash-dropdown{flex-shrink:0;max-height:200px;overflow-y:auto;background:var(--bg-secondary);border-bottom:1px solid var(--border);z-index:10;font-size:13px}.slash-item{display:flex;align-items:center;gap:10px;padding:6px 12px;cursor:pointer;transition:background .12s ease}.slash-item:hover,.slash-item--active{background:var(--bg-hover)}.slash-cmd{color:var(--accent-blue);font-weight:600;min-width:180px;font-family:JetBrains Mono,LXGW WenKai Mono,monospace}.slash-desc{color:var(--accent-purple);font-size:11px}.file-dropdown{flex-shrink:0;max-height:180px;overflow-y:auto;background:var(--bg-secondary);border-bottom:1px solid var(--border);z-index:10;font-size:12px}.file-item{display:flex;align-items:center;gap:8px;padding:5px 10px;cursor:pointer;transition:background .1s ease}.file-item:hover,.file-item--active{background:var(--bg-hover)}.file-loading{color:var(--text-secondary);cursor:default}.file-icon{flex-shrink:0;width:16px;text-align:center;font-size:13px}.file-name{color:var(--text-bright);font-family:JetBrains Mono,LXGW WenKai Mono,monospace;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.history-dropdown{flex-shrink:0;max-height:260px;overflow-y:auto;background:var(--bg-secondary);border-bottom:1px solid var(--border);z-index:10;font-size:12px}.history-item{display:flex;align-items:flex-start;gap:8px;padding:6px 10px;cursor:pointer;transition:background .1s ease;position:relative}.history-item:hover,.history-item--active{background:var(--bg-hover)}.history-empty{color:var(--text-secondary);cursor:default;justify-content:center;padding:12px}.history-text{flex:1;color:var(--text-bright);font-family:JetBrains Mono,LXGW WenKai Mono,monospace;white-space:pre-wrap;overflow-wrap:break-word;line-height:1.4}.history-time{flex-shrink:0;color:var(--text-secondary);font-size:10px;white-space:nowrap;margin-top:2px}.history-delete{flex-shrink:0;background:none;border:none;color:var(--text-secondary);cursor:pointer;font-size:14px;padding:0 2px;line-height:1;opacity:0;transition:opacity .1s ease,color .1s ease}.history-item:hover .history-delete,.history-item--active .history-delete{opacity:1}.history-delete:hover{color:var(--accent-red)}.tab-bar{display:flex;align-items:center;padding:0 10px;height:32px;background:var(--bg-secondary);border-top:1px solid var(--border);flex-shrink:0;overflow-x:auto;gap:3px}.tab-bar::-webkit-scrollbar{height:0}.tab-item{display:flex;align-items:center;gap:6px;padding:4px 12px;font-size:13px;color:var(--text-secondary);cursor:pointer;border-bottom:2px solid transparent;white-space:nowrap;transition:color .15s ease,border-color .15s ease,background .15s ease,box-shadow .15s ease;border-radius:5px 5px 0 0;-webkit-user-select:none;user-select:none;flex-shrink:0}.tab-item:hover{color:var(--text-primary);background:#7aa2f70f}.tab-item--active{color:var(--text-bright);border-bottom-color:var(--accent-blue);background:#7aa2f71a;box-shadow:inset 0 -1px 0 var(--accent-blue)}.tab-item__name{max-width:150px;overflow:hidden;text-overflow:ellipsis}.tab-item__count{font-size:10px;color:var(--scrollbar-thumb-hover)}.tab-item__close{font-size:14px;line-height:1;color:inherit;opacity:0;background:none;border:none;cursor:pointer;padding:0 2px;border-radius:3px;transition:opacity .1s ease}.tab-item:hover .tab-item__close{opacity:.5}.tab-item__close:hover{opacity:1!important;color:var(--accent-red);background:#f7768e1a}.tab-item__rename-input{background:transparent;border:1px solid var(--accent-blue);color:var(--text-bright);font-size:13px;font-family:inherit;padding:0 6px;border-radius:3px;outline:none;width:100px}.tab-bar-add{background:none;border:1px solid transparent;color:var(--text-secondary);font-size:18px;line-height:1;padding:2px 8px;border-radius:5px;cursor:pointer;margin-left:4px;flex-shrink:0}.tab-bar-add:hover{color:var(--accent-blue);border-color:var(--border);background:#7aa2f71a}.md-editor-actions{display:flex;align-items:center;gap:8px;padding:4px 8px;flex-shrink:0;background:var(--bg-secondary);border-top:1px solid var(--border)}.plan-anno-toolbar{display:flex;align-items:center;gap:6px;padding:3px 10px;height:28px;flex-shrink:0;background:var(--bg-secondary);border-bottom:1px solid var(--border)}.plan-anno-content{-webkit-user-select:text;user-select:text}.plan-insert-zone{position:relative;min-height:12px}.plan-insert-btn{display:none;position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);width:20px;height:20px;border-radius:50%;border:1px solid var(--scrollbar-thumb-hover);background:var(--bg-secondary);color:var(--accent-blue);font-size:15px;line-height:1;cursor:pointer;padding:0 0 1px;z-index:2;transition:background .12s ease,border-color .12s ease,transform .12s ease;align-items:center;justify-content:center}.plan-insert-zone:hover .plan-insert-btn{display:flex}.plan-anno-content--editing .plan-insert-zone:hover .plan-insert-btn{display:none}.plan-empty-placeholder{display:flex;align-items:center;justify-content:center;min-height:120px;color:var(--text-secondary);font-size:13px;font-style:italic;cursor:pointer;-webkit-user-select:none;user-select:none;text-align:center;padding:16px}.plan-empty-placeholder:hover{color:var(--accent-blue)}.plan-insert-btn:hover{background:var(--bg-hover);border-color:var(--accent-blue);transform:translate(-50%,-50%) scale(1.15)}.plan-annotation-card{display:flex;align-items:flex-start;gap:6px;padding:6px 10px;margin:4px 0;background:#e0af681f;border-left:3px solid var(--accent-yellow);border-radius:0 4px 4px 0}.plan-annotation-card--editing{border-left-color:var(--accent-blue);background:#7aa2f70f}.plan-annotation-textarea{flex:1;min-height:36px;max-height:30em;field-sizing:content;resize:vertical;border:1px solid var(--border);border-radius:3px;background:var(--bg-primary);color:var(--text-primary);font-family:JetBrains Mono,LXGW WenKai Mono,monospace;font-size:12px;padding:4px 6px;outline:none;transition:border-color .15s ease}.plan-annotation-textarea:focus{border-color:var(--accent-blue)}.plan-annotation-textarea::placeholder{color:var(--scrollbar-thumb-hover);font-style:italic}.plan-deletion-card{display:flex;align-items:center;gap:6px;padding:2px 8px;margin:2px 0;background:#f7768e0f;border-left:3px solid var(--accent-red);border-radius:0 4px 4px 0;font-size:11px}.plan-selection-float{position:absolute;z-index:1000;display:flex;flex-direction:row;gap:2px;background:var(--bg-secondary);border:1px solid var(--border);border-radius:6px;padding:2px;box-shadow:0 2px 8px #0000004d}.plan-selection-float button{width:24px;height:24px;border-radius:4px;border:none;cursor:pointer;font-size:14px;display:flex;align-items:center;justify-content:center;background:transparent;transition:background .15s,transform .1s}.plan-selection-float button:hover{transform:scale(1.1)}.plan-selection-float__delete{color:var(--accent-red)}.plan-selection-float__delete:hover{background:#f7768e33}.plan-selection-float__replace{color:var(--accent-blue)}.plan-selection-float__replace:hover{background:#7aa2f733}.plan-selection-float__comment{color:var(--accent-green)}.plan-selection-float__comment:hover{background:#9ece6a33}.plan-replace-card{display:flex;align-items:flex-start;gap:6px;padding:2px 8px;margin:2px 0;border-left:3px solid rgba(122,162,247,.6);background:#7aa2f70a;border-radius:0 4px 4px 0;font-size:11px}.plan-comment-card{display:flex;align-items:flex-start;gap:6px;padding:2px 8px;margin:2px 0;border-left:3px solid rgba(158,206,106,.6);background:#9ece6a0a;border-radius:0 4px 4px 0;font-size:11px}.plan-block--deleted{border-left:3px solid rgba(247,118,142,.5);padding-left:8px;border-radius:2px;position:relative}.plan-block--replaced{border-left:3px solid rgba(122,162,247,.5);padding-left:8px;border-radius:2px;position:relative}.plan-block--commented{border-left:3px solid rgba(158,206,106,.5);padding-left:8px;border-radius:2px;position:relative}.mermaid-diagram{margin:8px 0;padding:12px;background:var(--bg-secondary);border:1px solid var(--border);border-radius:6px;overflow-x:auto}.mermaid-diagram svg{display:block;margin:0 auto;max-width:100%;height:auto}.mermaid-error{border-left:3px solid var(--accent-red);padding-left:8px}.mermaid-error__msg{color:var(--accent-red);font-size:11px;margin-top:4px}.pane-btn--sm{font-size:11px;flex-shrink:0}.plan-file-browser{display:flex;flex-direction:column;height:100%;width:100%;background:var(--bg-secondary);overflow:hidden}.plan-file-browser__header{display:flex;align-items:center;justify-content:space-between;padding:4px 8px;height:28px;flex-shrink:0;border-bottom:1px solid var(--border)}.plan-file-browser__title{font-size:11px;color:var(--accent-blue);font-weight:600;letter-spacing:.3px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;direction:rtl;text-align:left}.plan-file-browser__list{flex:1;overflow-y:auto;overflow-x:hidden;padding:2px 0}.plan-file-browser__status{padding:8px 10px;font-size:11px;color:var(--text-secondary);font-style:italic}.plan-file-browser__item{display:flex;align-items:center;padding:3px 8px;font-size:12px;cursor:pointer;gap:5px;transition:background .1s ease;border-left:2px solid transparent}.plan-file-browser__item:hover{background:var(--bg-tertiary)}.plan-file-browser__item--active{background:#7aa2f71a;border-left-color:var(--accent-blue)}.plan-file-browser__item--active .plan-file-browser__name{color:var(--text-bright)}.plan-file-browser__icon{flex-shrink:0;width:14px;font-size:10px;color:var(--text-secondary);text-align:center}.plan-file-browser__name{flex:1;color:var(--text-primary);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}.plan-file-browser__size{flex-shrink:1;font-size:9px;color:var(--scrollbar-thumb-hover);white-space:nowrap;overflow:hidden;min-width:0}.plan-file-browser__create{display:flex;align-items:center;gap:4px;padding:4px 6px;border-top:1px solid var(--border);flex-shrink:0}.plan-file-browser__input{flex:1;min-width:0;background:var(--bg-primary);border:1px solid var(--border);color:var(--text-primary);padding:2px 6px;border-radius:3px;font-family:inherit;font-size:11px;outline:none;transition:border-color .15s ease}.plan-file-browser__input:focus{border-color:var(--accent-blue)}.plan-file-browser__input::placeholder{color:var(--scrollbar-thumb-hover);font-style:italic}.plan-overlay-body{display:flex;flex:1;min-height:0;overflow:hidden}.plan-overlay-center{flex:1;min-width:0;overflow:hidden}.plan-anno-counts{display:inline-flex;align-items:center;gap:4px;font-size:10px;margin-left:4px}.plan-anno-counts__unsent{color:var(--accent-yellow)}.plan-anno-counts__sent{color:var(--accent-green)}.plan-anno-dropdown-trigger{display:flex;align-items:center;gap:4px;padding:2px 6px;border:1px solid var(--border);border-radius:3px;cursor:pointer;background:var(--bg-primary);transition:border-color .15s ease,background .15s ease;min-width:0}.plan-anno-dropdown-trigger:hover,.plan-anno-dropdown-trigger--active{border-color:var(--accent-blue);background:var(--bg-hover)}.plan-anno-dropdown-trigger__text{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:11px;color:var(--text-secondary)}.plan-anno-dropdown-trigger__arrow{flex-shrink:0;font-size:9px;color:var(--text-secondary);transition:transform .15s ease}.plan-anno-dropdown-trigger--active .plan-anno-dropdown-trigger__arrow{transform:rotate(180deg)}.plan-anno-dropdown{position:absolute;top:100%;right:0;z-index:100;width:320px;max-height:300px;display:flex;flex-direction:column;background:var(--bg-secondary);border:1px solid var(--border);border-radius:4px;box-shadow:0 4px 12px #0000004d;overflow:hidden}.plan-anno-dropdown__header{display:flex;align-items:center;justify-content:center;padding:4px 6px;border-bottom:1px solid var(--border);flex-shrink:0}.plan-anno-dropdown__list{flex:1;overflow-y:auto;padding:2px 0}.plan-anno-dropdown__item{display:flex;align-items:center;gap:4px;padding:3px 6px;font-size:11px;border-bottom:1px solid var(--border-subtle, rgba(128,128,128,.1))}.plan-anno-dropdown__item:last-child{border-bottom:none}.plan-anno-dropdown__item--add{border-left:2px solid var(--accent-yellow)}.plan-anno-dropdown__item--del{border-left:2px solid var(--accent-red)}.plan-anno-dropdown__item--rep{border-left:2px solid var(--accent-blue)}.plan-anno-dropdown__item--com{border-left:2px solid var(--accent-green)}.plan-anno-dropdown__type{flex-shrink:0;width:14px;font-weight:700;text-align:center}.plan-anno-dropdown__text{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--text-primary)}.plan-anno-dropdown__badge{flex-shrink:0;font-size:9px;padding:0 4px;border-radius:3px;background:var(--accent-green);color:var(--bg-primary)}.plan-anno-dropdown__empty{padding:8px;text-align:center;font-size:11px;color:var(--text-secondary);font-style:italic}.plan-edit-textarea{width:100%;flex:1;resize:none;border:none;outline:none;padding:8px 12px;font-family:JetBrains Mono,LXGW WenKai Mono,Menlo,Monaco,Courier New,monospace;line-height:1.6;background:var(--bg-primary);color:var(--text-primary);-moz-tab-size:2;tab-size:2}.plan-edit-textarea::placeholder{color:var(--scrollbar-thumb-hover);font-style:italic}.auto-timeline{display:flex;align-items:center;gap:5px;padding:3px 8px;min-height:26px;overflow:hidden}.auto-divider{color:var(--border);font-size:11px;-webkit-user-select:none;user-select:none;flex-shrink:0}.auto-spin-input{display:inline-flex;align-items:center;height:18px;background:var(--bg-tertiary);border:1px solid var(--border);border-radius:3px;overflow:hidden;flex-shrink:0}.auto-spin-input input{width:100%;height:100%;padding:0 2px;font-size:10px;background:transparent;color:var(--text-primary);border:none;outline:none;text-align:left;-moz-appearance:textfield}.auto-spin-input input::-webkit-inner-spin-button,.auto-spin-input input::-webkit-outer-spin-button{-webkit-appearance:none;margin:0}.auto-spin-btns{display:flex;flex-direction:column;flex-shrink:0;border-left:1px solid var(--border)}.auto-spin-btns button{display:flex;align-items:center;justify-content:center;width:14px;height:9px;font-size:5px;line-height:1;padding:0;background:var(--bg-secondary);color:var(--text-secondary);border:none;cursor:pointer}.auto-spin-btns button:hover{background:var(--bg-tertiary);color:var(--text-primary)}.auto-spin-btns button:first-child{border-bottom:1px solid var(--border)}.auto-step-node{display:flex;flex-direction:column;align-items:center;gap:1px;background:none;border:none;padding:2px 4px;cursor:pointer;min-width:40px;flex-shrink:0}.auto-step-node:disabled{cursor:default;opacity:.5}.auto-step-node:not(:disabled):hover .auto-step-circle{transform:scale(1.3)}.auto-step-circle{width:8px;height:8px;border-radius:50%;transition:transform .15s,background-color .2s;flex-shrink:0}.auto-step-node.completed .auto-step-circle{background-color:var(--accent-green)}.auto-step-node.active .auto-step-circle{background-color:var(--accent-blue);animation:auto-pulse 1.5s ease-in-out infinite}.auto-step-node.pending .auto-step-circle{background-color:var(--text-secondary);opacity:.4}@keyframes auto-pulse{0%,to{transform:scale(1);opacity:1}50%{transform:scale(1.4);opacity:.7}}.auto-step-label{font-size:9px;color:var(--text-primary);white-space:nowrap;max-width:50px;overflow:hidden;text-overflow:ellipsis}.auto-step-duration{font-size:8px;color:var(--text-secondary);white-space:nowrap}.auto-connector{width:12px;height:2px;background-color:var(--border);flex-shrink:0;transition:background-color .2s}.auto-connector.completed{background-color:var(--accent-green)}.auto-step-popup{position:absolute;left:0;right:0;bottom:0;top:0;z-index:10;background-color:var(--bg-primary);display:flex;flex-direction:column;border-top:2px solid var(--accent-blue)}
|