ai-cli-online
Advanced tools
| declare const router: import("express-serve-static-core").Router; | ||
| export declare function recoverAutoSessions(): void; | ||
| export declare function stopAllWatchers(): void; | ||
| export default router; |
| import { Router } from 'express'; | ||
| import { resolveSession } from '../middleware/auth.js'; | ||
| import { createAutoSession, getAutoSession, getAllRunningAutoSessions, updateAutoStatus, deleteAutoSession, insertAutoStep, endAutoStep, getAutoSteps, getLastAutoStep, deleteAutoSteps, } from '../db.js'; | ||
| import { watch, readFileSync, writeFileSync, existsSync } from 'fs'; | ||
| import { join } from 'path'; | ||
| const router = Router(); | ||
| // In-memory watcher map: sessionName → FSWatcher | ||
| const watchers = new Map(); | ||
| function parseSignalFile(taskDir) { | ||
| const signalPath = join(taskDir, '.auto-signal'); | ||
| try { | ||
| if (!existsSync(signalPath)) | ||
| return null; | ||
| const raw = readFileSync(signalPath, 'utf-8').trim(); | ||
| if (!raw) | ||
| return null; | ||
| return JSON.parse(raw); | ||
| } | ||
| catch { | ||
| return null; | ||
| } | ||
| } | ||
| function formatDuration(startedAt, endedAt) { | ||
| const start = new Date(startedAt).getTime(); | ||
| const end = endedAt ? new Date(endedAt).getTime() : Date.now(); | ||
| const sec = Math.round((end - start) / 1000); | ||
| if (sec < 60) | ||
| return `${sec}s`; | ||
| const min = Math.floor(sec / 60); | ||
| const rem = sec % 60; | ||
| if (min < 60) | ||
| return rem > 0 ? `${min}m ${rem}s` : `${min}m`; | ||
| const hr = Math.floor(min / 60); | ||
| const mrem = min % 60; | ||
| return mrem > 0 ? `${hr}h ${mrem}m` : `${hr}h`; | ||
| } | ||
| function formatTime(iso) { | ||
| return iso.replace('T', ' ').replace(/\.\d+Z$/, '').replace('Z', ''); | ||
| } | ||
| /** Write .auto-timeline.md to the task directory with the full step history */ | ||
| function writeTimelineFile(sessionName, taskDir) { | ||
| const session = getAutoSession(sessionName); | ||
| if (!session) | ||
| return; | ||
| const steps = getAutoSteps(sessionName); | ||
| if (steps.length === 0) | ||
| return; | ||
| const totalDuration = formatDuration(session.started_at, steps[steps.length - 1].ended_at ?? new Date().toISOString()); | ||
| const endTime = steps[steps.length - 1].ended_at ?? new Date().toISOString(); | ||
| const lines = []; | ||
| lines.push(`## Execution Timeline`); | ||
| lines.push(``); | ||
| lines.push(`- **Status**: ${session.status}`); | ||
| lines.push(`- **Total Duration**: ${totalDuration} (${formatTime(session.started_at)} → ${formatTime(endTime)})`); | ||
| const maxIter = Math.max(...steps.map(s => s.iteration)); | ||
| if (maxIter > 0) | ||
| lines.push(`- **Iterations**: ${maxIter}`); | ||
| lines.push(``); | ||
| // Table | ||
| lines.push(`| # | Phase | Result | Checkpoint | Duration | Started | Ended |`); | ||
| lines.push(`|---|-------|--------|------------|----------|---------|-------|`); | ||
| for (let i = 0; i < steps.length; i++) { | ||
| const s = steps[i]; | ||
| const dur = s.ended_at ? formatDuration(s.started_at, s.ended_at) : 'running'; | ||
| const cp = s.checkpoint || ''; | ||
| const started = formatTime(s.started_at).split(' ')[1] || ''; | ||
| const ended = s.ended_at ? (formatTime(s.ended_at).split(' ')[1] || '') : '—'; | ||
| lines.push(`| ${i + 1} | ${s.step} | ${s.result} | ${cp} | ${dur} | ${started} | ${ended} |`); | ||
| } | ||
| lines.push(``); | ||
| // Visual flow — show result only for decision steps (check, merge) | ||
| const flow = steps.map(s => { | ||
| const dur = s.ended_at ? formatDuration(s.started_at, s.ended_at) : '...'; | ||
| const showResult = s.step === 'check' || s.step === 'merge'; | ||
| const label = showResult ? `${s.step}:${s.result}` : s.step; | ||
| return `${label}(${dur})`; | ||
| }).join(' → '); | ||
| lines.push(`**Flow**: ${flow}`); | ||
| lines.push(``); | ||
| try { | ||
| writeFileSync(join(taskDir, '.auto-timeline.md'), lines.join('\n')); | ||
| } | ||
| catch (err) { | ||
| console.error(`[taskAuto] Failed to write .auto-timeline.md:`, err); | ||
| } | ||
| } | ||
| function processSignal(sessionName, signal) { | ||
| const lastStep = getLastAutoStep(sessionName); | ||
| // If same step+result+checkpoint as last, skip (no transition) | ||
| if (lastStep && | ||
| lastStep.step === signal.step && | ||
| lastStep.result === (signal.result || '') && | ||
| lastStep.checkpoint === (signal.checkpoint || '')) { | ||
| return; | ||
| } | ||
| // End previous step if it has no ended_at | ||
| if (lastStep && !lastStep.ended_at) { | ||
| endAutoStep(lastStep.id); | ||
| } | ||
| // Insert new step | ||
| insertAutoStep(sessionName, signal.step, signal.result || '', signal.next || '', signal.checkpoint || '', signal.iteration ?? 0); | ||
| // If next is "(stop)" or "(done)", mark auto session as completed | ||
| if (signal.next === '(stop)' || signal.next === '(done)') { | ||
| // End the just-inserted step | ||
| const newLast = getLastAutoStep(sessionName); | ||
| if (newLast && !newLast.ended_at) { | ||
| endAutoStep(newLast.id); | ||
| } | ||
| updateAutoStatus(sessionName, 'completed'); | ||
| // Write timeline file before stopping | ||
| const session = getAutoSession(sessionName); | ||
| if (session) | ||
| writeTimelineFile(sessionName, session.task_dir); | ||
| stopWatcher(sessionName); | ||
| } | ||
| } | ||
| function startWatcher(sessionName, taskDir) { | ||
| stopWatcher(sessionName); | ||
| try { | ||
| const watcher = watch(taskDir, (_eventType, filename) => { | ||
| if (filename === '.auto-signal') { | ||
| const signal = parseSignalFile(taskDir); | ||
| if (signal) { | ||
| try { | ||
| processSignal(sessionName, signal); | ||
| } | ||
| catch (err) { | ||
| console.error(`[taskAuto:watcher] Error processing signal for ${sessionName}:`, err); | ||
| } | ||
| } | ||
| } | ||
| // Detect .auto-stop written by the auto skill itself | ||
| if (filename === '.auto-stop') { | ||
| const session = getAutoSession(sessionName); | ||
| if (session && session.status === 'running') { | ||
| const lastStep = getLastAutoStep(sessionName); | ||
| if (lastStep && !lastStep.ended_at) { | ||
| endAutoStep(lastStep.id); | ||
| } | ||
| updateAutoStatus(sessionName, 'stopped'); | ||
| writeTimelineFile(sessionName, session.task_dir); | ||
| stopWatcher(sessionName); | ||
| } | ||
| } | ||
| }); | ||
| watchers.set(sessionName, watcher); | ||
| } | ||
| catch (err) { | ||
| console.error(`[taskAuto] Failed to watch ${taskDir}:`, err); | ||
| } | ||
| } | ||
| function stopWatcher(sessionName) { | ||
| const watcher = watchers.get(sessionName); | ||
| if (watcher) { | ||
| try { | ||
| watcher.close(); | ||
| } | ||
| catch { /* ignore */ } | ||
| watchers.delete(sessionName); | ||
| } | ||
| } | ||
| // --- REST endpoints --- | ||
| // POST: Start auto tracking | ||
| router.post('/api/sessions/:sessionId/task-auto', (req, res) => { | ||
| const sessionName = resolveSession(req, res); | ||
| if (!sessionName) | ||
| return; | ||
| const { taskDir, maxIterations = 20, timeoutMinutes = 1440 } = req.body || {}; | ||
| if (!taskDir || typeof taskDir !== 'string') { | ||
| res.status(400).json({ error: 'taskDir is required' }); | ||
| return; | ||
| } | ||
| // Check if already tracking | ||
| const existing = getAutoSession(sessionName); | ||
| if (existing && existing.status === 'running') { | ||
| res.status(409).json({ error: 'Auto already running for this session' }); | ||
| return; | ||
| } | ||
| // Clean up any old data | ||
| if (existing) { | ||
| deleteAutoSteps(sessionName); | ||
| deleteAutoSession(sessionName); | ||
| } | ||
| try { | ||
| createAutoSession(sessionName, taskDir, maxIterations, timeoutMinutes); | ||
| // Read initial signal if exists | ||
| const signal = parseSignalFile(taskDir); | ||
| if (signal) { | ||
| processSignal(sessionName, signal); | ||
| } | ||
| startWatcher(sessionName, taskDir); | ||
| res.json({ ok: true }); | ||
| } | ||
| catch (err) { | ||
| console.error('[taskAuto:start]', err); | ||
| res.status(500).json({ error: 'Failed to start auto tracking' }); | ||
| } | ||
| }); | ||
| // GET: Get auto status + step history | ||
| router.get('/api/sessions/:sessionId/task-auto', (req, res) => { | ||
| const sessionName = resolveSession(req, res); | ||
| if (!sessionName) | ||
| return; | ||
| const session = getAutoSession(sessionName); | ||
| if (!session) { | ||
| res.json(null); | ||
| return; | ||
| } | ||
| const steps = getAutoSteps(sessionName); | ||
| const startedAt = new Date(session.started_at); | ||
| const elapsedMinutes = (Date.now() - startedAt.getTime()) / 60000; | ||
| res.json({ | ||
| status: session.status, | ||
| taskDir: session.task_dir, | ||
| maxIterations: session.max_iterations, | ||
| timeoutMinutes: session.timeout_minutes, | ||
| startedAt: session.started_at, | ||
| elapsedMinutes: Math.round(elapsedMinutes * 10) / 10, | ||
| steps: steps.map((s) => ({ | ||
| id: s.id, | ||
| step: s.step, | ||
| result: s.result, | ||
| next: s.next, | ||
| checkpoint: s.checkpoint, | ||
| iteration: s.iteration, | ||
| startedAt: s.started_at, | ||
| endedAt: s.ended_at, | ||
| })), | ||
| }); | ||
| }); | ||
| // DELETE: Stop auto tracking | ||
| router.delete('/api/sessions/:sessionId/task-auto', (req, res) => { | ||
| const sessionName = resolveSession(req, res); | ||
| if (!sessionName) | ||
| return; | ||
| const session = getAutoSession(sessionName); | ||
| if (!session) { | ||
| res.status(404).json({ error: 'No auto session found' }); | ||
| return; | ||
| } | ||
| // If already finished (completed/cancelled/stopped), just clean up records | ||
| if (session.status !== 'running') { | ||
| deleteAutoSteps(sessionName); | ||
| deleteAutoSession(sessionName); | ||
| res.json({ ok: true }); | ||
| return; | ||
| } | ||
| // Write .auto-stop to signal the auto subprocess to halt | ||
| try { | ||
| const stopPath = join(session.task_dir, '.auto-stop'); | ||
| writeFileSync(stopPath, JSON.stringify({ reason: 'user_stop', timestamp: new Date().toISOString() })); | ||
| } | ||
| catch (err) { | ||
| console.error('[taskAuto:stop] Failed to write .auto-stop:', err); | ||
| } | ||
| // End last step | ||
| const lastStep = getLastAutoStep(sessionName); | ||
| if (lastStep && !lastStep.ended_at) { | ||
| endAutoStep(lastStep.id); | ||
| } | ||
| updateAutoStatus(sessionName, 'cancelled'); | ||
| writeTimelineFile(sessionName, session.task_dir); | ||
| stopWatcher(sessionName); | ||
| res.json({ ok: true }); | ||
| }); | ||
| // --- Server restart recovery --- | ||
| export function recoverAutoSessions() { | ||
| const sessions = getAllRunningAutoSessions(); | ||
| for (const session of sessions) { | ||
| if (existsSync(session.task_dir)) { | ||
| console.log(`[taskAuto:recover] Resuming watcher for ${session.session_name}`); | ||
| // Process any signals that arrived while server was down | ||
| const signal = parseSignalFile(session.task_dir); | ||
| if (signal) { | ||
| try { | ||
| processSignal(session.session_name, signal); | ||
| } | ||
| catch { /* ignore */ } | ||
| } | ||
| // Check if still running after processing | ||
| const updated = getAutoSession(session.session_name); | ||
| if (updated && updated.status === 'running') { | ||
| startWatcher(session.session_name, session.task_dir); | ||
| } | ||
| } | ||
| else { | ||
| console.log(`[taskAuto:recover] Task dir gone for ${session.session_name}, cleaning up`); | ||
| deleteAutoSteps(session.session_name); | ||
| deleteAutoSession(session.session_name); | ||
| } | ||
| } | ||
| } | ||
| export function stopAllWatchers() { | ||
| for (const [, watcher] of watchers) { | ||
| try { | ||
| watcher.close(); | ||
| } | ||
| catch { /* ignore */ } | ||
| } | ||
| watchers.clear(); | ||
| } | ||
| export default router; |
| /** | ||
| * Copyright (c) 2014 The xterm.js authors. All rights reserved. | ||
| * Copyright (c) 2012-2013, Christopher Jeffrey (MIT License) | ||
| * https://github.com/chjj/term.js | ||
| * @license MIT | ||
| * | ||
| * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| * of this software and associated documentation files (the "Software"), to deal | ||
| * in the Software without restriction, including without limitation the rights | ||
| * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| * copies of the Software, and to permit persons to whom the Software is | ||
| * furnished to do so, subject to the following conditions: | ||
| * | ||
| * The above copyright notice and this permission notice shall be included in | ||
| * all copies or substantial portions of the Software. | ||
| * | ||
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
| * THE SOFTWARE. | ||
| * | ||
| * Originally forked from (with the author's permission): | ||
| * Fabrice Bellard's javascript vt100 for jslinux: | ||
| * http://bellard.org/jslinux/ | ||
| * Copyright (c) 2011 Fabrice Bellard | ||
| * The original design remains. The terminal itself | ||
| * has been extended to include xterm CSI codes, among | ||
| * other features. | ||
| */.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)} |
Sorry, the diff of this file is too big to display
+1
-1
| { | ||
| "name": "ai-cli-online", | ||
| "version": "3.0.19", | ||
| "version": "3.0.20", | ||
| "description": "AI-Cli Online - Web Terminal for Claude Code via xterm.js + tmux", | ||
@@ -5,0 +5,0 @@ "license": "MIT", |
+29
-0
@@ -13,2 +13,31 @@ export declare function getSetting(tokenHash: string, key: string): string | null; | ||
| export declare function cleanupOldAnnotations(maxAgeDays?: number): number; | ||
| export interface AutoSession { | ||
| session_name: string; | ||
| task_dir: string; | ||
| status: string; | ||
| max_iterations: number; | ||
| timeout_minutes: number; | ||
| started_at: string; | ||
| } | ||
| export interface AutoStep { | ||
| id: number; | ||
| session_name: string; | ||
| step: string; | ||
| result: string; | ||
| next: string; | ||
| checkpoint: string; | ||
| iteration: number; | ||
| started_at: string; | ||
| ended_at: string | null; | ||
| } | ||
| export declare function createAutoSession(sessionName: string, taskDir: string, maxIterations: number, timeoutMinutes: number): void; | ||
| export declare function getAutoSession(sessionName: string): AutoSession | null; | ||
| export declare function getAllRunningAutoSessions(): AutoSession[]; | ||
| export declare function updateAutoStatus(sessionName: string, status: string): void; | ||
| export declare function deleteAutoSession(sessionName: string): void; | ||
| export declare function insertAutoStep(sessionName: string, step: string, result: string, next: string, checkpoint: string, iteration: number): number; | ||
| export declare function endAutoStep(stepId: number): void; | ||
| export declare function getAutoSteps(sessionName: string): AutoStep[]; | ||
| export declare function getLastAutoStep(sessionName: string): AutoStep | null; | ||
| export declare function deleteAutoSteps(sessionName: string): void; | ||
| export declare function closeDb(): void; |
+73
-0
@@ -109,4 +109,77 @@ import Database from 'better-sqlite3'; | ||
| } | ||
| // --- Auto mode tables --- | ||
| db.exec(` | ||
| CREATE TABLE IF NOT EXISTS task_auto ( | ||
| session_name TEXT PRIMARY KEY, | ||
| task_dir TEXT NOT NULL UNIQUE, | ||
| status TEXT DEFAULT 'running', | ||
| max_iterations INTEGER DEFAULT 20, | ||
| timeout_minutes INTEGER DEFAULT 30, | ||
| started_at TEXT NOT NULL | ||
| ) | ||
| `); | ||
| db.exec(` | ||
| CREATE TABLE IF NOT EXISTS task_auto_steps ( | ||
| id INTEGER PRIMARY KEY AUTOINCREMENT, | ||
| session_name TEXT NOT NULL, | ||
| step TEXT NOT NULL, | ||
| result TEXT DEFAULT '', | ||
| next TEXT DEFAULT '', | ||
| checkpoint TEXT DEFAULT '', | ||
| iteration INTEGER DEFAULT 0, | ||
| started_at TEXT NOT NULL, | ||
| ended_at TEXT | ||
| ) | ||
| `); | ||
| db.exec('CREATE INDEX IF NOT EXISTS idx_auto_steps_session ON task_auto_steps(session_name)'); | ||
| // --- Auto mode statements --- | ||
| const stmtAutoInsert = db.prepare(` | ||
| INSERT INTO task_auto (session_name, task_dir, status, max_iterations, timeout_minutes, started_at) | ||
| VALUES (?, ?, 'running', ?, ?, ?) | ||
| `); | ||
| const stmtAutoGet = db.prepare('SELECT * FROM task_auto WHERE session_name = ?'); | ||
| const stmtAutoGetAll = db.prepare("SELECT * FROM task_auto WHERE status = 'running'"); | ||
| const stmtAutoUpdateStatus = db.prepare('UPDATE task_auto SET status = ? WHERE session_name = ?'); | ||
| const stmtAutoDelete = db.prepare('DELETE FROM task_auto WHERE session_name = ?'); | ||
| const stmtAutoStepInsert = db.prepare(` | ||
| INSERT INTO task_auto_steps (session_name, step, result, next, checkpoint, iteration, started_at) | ||
| VALUES (?, ?, ?, ?, ?, ?, ?) | ||
| `); | ||
| const stmtAutoStepEnd = db.prepare('UPDATE task_auto_steps SET ended_at = ? WHERE id = ?'); | ||
| const stmtAutoStepGetAll = db.prepare('SELECT * FROM task_auto_steps WHERE session_name = ? ORDER BY id ASC'); | ||
| const stmtAutoStepGetLast = db.prepare('SELECT * FROM task_auto_steps WHERE session_name = ? ORDER BY id DESC LIMIT 1'); | ||
| const stmtAutoStepsDelete = db.prepare('DELETE FROM task_auto_steps WHERE session_name = ?'); | ||
| export function createAutoSession(sessionName, taskDir, maxIterations, timeoutMinutes) { | ||
| stmtAutoInsert.run(sessionName, taskDir, maxIterations, timeoutMinutes, new Date().toISOString()); | ||
| } | ||
| export function getAutoSession(sessionName) { | ||
| return stmtAutoGet.get(sessionName) ?? null; | ||
| } | ||
| export function getAllRunningAutoSessions() { | ||
| return stmtAutoGetAll.all(); | ||
| } | ||
| export function updateAutoStatus(sessionName, status) { | ||
| stmtAutoUpdateStatus.run(status, sessionName); | ||
| } | ||
| export function deleteAutoSession(sessionName) { | ||
| stmtAutoDelete.run(sessionName); | ||
| } | ||
| export function insertAutoStep(sessionName, step, result, next, checkpoint, iteration) { | ||
| const info = stmtAutoStepInsert.run(sessionName, step, result, next, checkpoint, iteration, new Date().toISOString()); | ||
| return Number(info.lastInsertRowid); | ||
| } | ||
| export function endAutoStep(stepId) { | ||
| stmtAutoStepEnd.run(new Date().toISOString(), stepId); | ||
| } | ||
| export function getAutoSteps(sessionName) { | ||
| return stmtAutoStepGetAll.all(sessionName); | ||
| } | ||
| export function getLastAutoStep(sessionName) { | ||
| return stmtAutoStepGetLast.get(sessionName) ?? null; | ||
| } | ||
| export function deleteAutoSteps(sessionName) { | ||
| stmtAutoStepsDelete.run(sessionName); | ||
| } | ||
| export function closeDb() { | ||
| db.close(); | ||
| } |
@@ -22,2 +22,3 @@ import express from 'express'; | ||
| import gitRouter from './routes/git.js'; | ||
| import taskAutoRouter, { recoverAutoSessions, stopAllWatchers } from './routes/taskAuto.js'; | ||
| const __dirname = dirname(fileURLToPath(import.meta.url)); | ||
@@ -105,2 +106,3 @@ config(); | ||
| app.use(gitRouter); | ||
| app.use(taskAutoRouter); | ||
| // --- Static files --- | ||
@@ -180,2 +182,8 @@ const webDistPath = join(__dirname, '../../web/dist'); | ||
| } | ||
| try { | ||
| recoverAutoSessions(); | ||
| } | ||
| catch (e) { | ||
| console.error('[startup:auto-recover]', e); | ||
| } | ||
| const CLEANUP_INTERVAL = 60 * 60 * 1000; | ||
@@ -207,2 +215,3 @@ const cleanupTimer = setInterval(async () => { | ||
| clearWsIntervals(); | ||
| stopAllWatchers(); | ||
| if (cleanupTimer) | ||
@@ -209,0 +218,0 @@ clearInterval(cleanupTimer); |
| import { Router } from 'express'; | ||
| import { extractToken, checkAuth, resolveSession } from '../middleware/auth.js'; | ||
| import { listSessions, killSession, buildSessionName, getCwd, getPaneCommand } from '../tmux.js'; | ||
| import { listSessions, killSession, buildSessionName, getCwd, getPaneCommand, captureScrollback } from '../tmux.js'; | ||
| import { getActiveSessionNames } from '../websocket.js'; | ||
@@ -64,2 +64,16 @@ import { deleteDraft } from '../db.js'; | ||
| }); | ||
| // Capture pane scrollback content (for live terminal popup) | ||
| router.get('/api/sessions/:sessionId/capture-pane', async (req, res) => { | ||
| const sessionName = resolveSession(req, res); | ||
| if (!sessionName) | ||
| return; | ||
| try { | ||
| const content = await captureScrollback(sessionName); | ||
| res.json({ content }); | ||
| } | ||
| catch (err) { | ||
| console.error(`[api:capture-pane] ${sessionName}:`, err); | ||
| res.status(500).json({ error: 'Failed to capture pane content' }); | ||
| } | ||
| }); | ||
| export default router; |
| { | ||
| "name": "ai-cli-online-server", | ||
| "version": "3.0.19", | ||
| "version": "3.0.20", | ||
| "description": "CLI-Online Backend Server", | ||
@@ -5,0 +5,0 @@ "main": "dist/index.js", |
| { | ||
| "name": "ai-cli-online-shared", | ||
| "version": "3.0.19", | ||
| "version": "3.0.20", | ||
| "description": "Shared types for CLI-Online", | ||
@@ -5,0 +5,0 @@ "type": "module", |
@@ -13,7 +13,7 @@ <!DOCTYPE html> | ||
| <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/lxgw-wenkai-webfont@1.7.0/lxgwwenkaimono-bold.css" /> | ||
| <script type="module" crossorigin src="/assets/index-Kzdpgxcz.js"></script> | ||
| <script type="module" crossorigin src="/assets/index-DG0BJZ53.js"></script> | ||
| <link rel="modulepreload" crossorigin href="/assets/react-vendor-BCIvbQoU.js"> | ||
| <link rel="modulepreload" crossorigin href="/assets/terminal-DnNpv9tw.js"> | ||
| <link rel="modulepreload" crossorigin href="/assets/markdown-CU76q5qk.js"> | ||
| <link rel="stylesheet" crossorigin href="/assets/index-BI7oV4SU.css"> | ||
| <link rel="stylesheet" crossorigin href="/assets/index-D7cmVR0X.css"> | ||
| </head> | ||
@@ -20,0 +20,0 @@ <body> |
+1
-1
| { | ||
| "name": "ai-cli-online-web", | ||
| "version": "3.0.19", | ||
| "version": "3.0.20", | ||
| "description": "CLI-Online Web Frontend", | ||
@@ -5,0 +5,0 @@ "type": "module", |
| /** | ||
| * Copyright (c) 2014 The xterm.js authors. All rights reserved. | ||
| * Copyright (c) 2012-2013, Christopher Jeffrey (MIT License) | ||
| * https://github.com/chjj/term.js | ||
| * @license MIT | ||
| * | ||
| * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| * of this software and associated documentation files (the "Software"), to deal | ||
| * in the Software without restriction, including without limitation the rights | ||
| * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| * copies of the Software, and to permit persons to whom the Software is | ||
| * furnished to do so, subject to the following conditions: | ||
| * | ||
| * The above copyright notice and this permission notice shall be included in | ||
| * all copies or substantial portions of the Software. | ||
| * | ||
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
| * THE SOFTWARE. | ||
| * | ||
| * Originally forked from (with the author's permission): | ||
| * Fabrice Bellard's javascript vt100 for jslinux: | ||
| * http://bellard.org/jslinux/ | ||
| * Copyright (c) 2011 Fabrice Bellard | ||
| * The original design remains. The terminal itself | ||
| * has been extended to include xterm CSI codes, among | ||
| * other features. | ||
| */.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} |
Sorry, the diff of this file is too big to display
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
1200219
2.28%62
3.33%7032
7.15%40
2.56%24
20%