@k1e1n04/mav 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +212 -0
  3. package/bin/mav.ts +31 -0
  4. package/dist/bin/mav.d.ts +2 -0
  5. package/dist/bin/mav.js +24 -0
  6. package/dist/bin/mav.js.map +1 -0
  7. package/dist/src/agent-launch.d.ts +15 -0
  8. package/dist/src/agent-launch.js +36 -0
  9. package/dist/src/agent-launch.js.map +1 -0
  10. package/dist/src/agent.d.ts +42 -0
  11. package/dist/src/agent.js +209 -0
  12. package/dist/src/agent.js.map +1 -0
  13. package/dist/src/config.d.ts +11 -0
  14. package/dist/src/config.js +32 -0
  15. package/dist/src/config.js.map +1 -0
  16. package/dist/src/current-session.d.ts +15 -0
  17. package/dist/src/current-session.js +17 -0
  18. package/dist/src/current-session.js.map +1 -0
  19. package/dist/src/index.d.ts +6 -0
  20. package/dist/src/index.js +90 -0
  21. package/dist/src/index.js.map +1 -0
  22. package/dist/src/process-cwd.d.ts +1 -0
  23. package/dist/src/process-cwd.js +24 -0
  24. package/dist/src/process-cwd.js.map +1 -0
  25. package/dist/src/session-manager.d.ts +16 -0
  26. package/dist/src/session-manager.js +102 -0
  27. package/dist/src/session-manager.js.map +1 -0
  28. package/dist/src/state.d.ts +19 -0
  29. package/dist/src/state.js +30 -0
  30. package/dist/src/state.js.map +1 -0
  31. package/dist/src/ui/app.d.ts +15 -0
  32. package/dist/src/ui/app.js +109 -0
  33. package/dist/src/ui/app.js.map +1 -0
  34. package/dist/src/ui/detail.d.ts +28 -0
  35. package/dist/src/ui/detail.js +137 -0
  36. package/dist/src/ui/detail.js.map +1 -0
  37. package/dist/src/ui/overview.d.ts +24 -0
  38. package/dist/src/ui/overview.js +267 -0
  39. package/dist/src/ui/overview.js.map +1 -0
  40. package/lua/mav/follow.lua +37 -0
  41. package/lua/mav/init.lua +92 -0
  42. package/lua/mav/state.lua +22 -0
  43. package/package.json +54 -0
  44. package/plugin/mav.lua +24 -0
  45. package/src/agent-launch.ts +43 -0
  46. package/src/agent.ts +243 -0
  47. package/src/config.ts +51 -0
  48. package/src/current-session.ts +34 -0
  49. package/src/index.ts +121 -0
  50. package/src/process-cwd.ts +31 -0
  51. package/src/session-manager.ts +122 -0
  52. package/src/state.ts +49 -0
  53. package/src/types/neo-blessed.d.ts +5 -0
  54. package/src/ui/app.ts +121 -0
  55. package/src/ui/detail.ts +164 -0
  56. package/src/ui/overview.ts +306 -0
@@ -0,0 +1,15 @@
1
+ export interface CurrentSessionSnapshot {
2
+ id: string;
3
+ type: string;
4
+ displayName: string;
5
+ cwd: string;
6
+ }
7
+ export interface CurrentSessionState {
8
+ sessionId: string;
9
+ agentType: string;
10
+ displayName: string;
11
+ cwd: string;
12
+ updatedAt: string;
13
+ }
14
+ export declare function saveCurrentSessionState(path: string, session: CurrentSessionSnapshot): void;
15
+ export declare function clearCurrentSessionState(path: string): void;
@@ -0,0 +1,17 @@
1
+ import { mkdirSync, rmSync, writeFileSync } from 'node:fs';
2
+ import { dirname } from 'node:path';
3
+ export function saveCurrentSessionState(path, session) {
4
+ const state = {
5
+ sessionId: session.id,
6
+ agentType: session.type,
7
+ displayName: session.displayName,
8
+ cwd: session.cwd,
9
+ updatedAt: new Date().toISOString(),
10
+ };
11
+ mkdirSync(dirname(path), { recursive: true });
12
+ writeFileSync(path, JSON.stringify(state), 'utf-8');
13
+ }
14
+ export function clearCurrentSessionState(path) {
15
+ rmSync(path, { force: true });
16
+ }
17
+ //# sourceMappingURL=current-session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"current-session.js","sourceRoot":"","sources":["../../src/current-session.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAC1D,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAiBnC,MAAM,UAAU,uBAAuB,CAAC,IAAY,EAAE,OAA+B;IACnF,MAAM,KAAK,GAAwB;QACjC,SAAS,EAAE,OAAO,CAAC,EAAE;QACrB,SAAS,EAAE,OAAO,CAAC,IAAI;QACvB,WAAW,EAAE,OAAO,CAAC,WAAW;QAChC,GAAG,EAAE,OAAO,CAAC,GAAG;QAChB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACpC,CAAA;IAED,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IAC7C,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC,CAAA;AACrD,CAAC;AAED,MAAM,UAAU,wBAAwB,CAAC,IAAY;IACnD,MAAM,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;AAC/B,CAAC"}
@@ -0,0 +1,6 @@
1
+ import { SessionManager } from './session-manager.js';
2
+ export interface StartOptions {
3
+ configPath?: string;
4
+ agentType?: string;
5
+ }
6
+ export declare function start(options?: StartOptions): SessionManager;
@@ -0,0 +1,90 @@
1
+ import { homedir } from 'node:os';
2
+ import { join, dirname } from 'node:path';
3
+ import { loadConfig } from './config.js';
4
+ import { clearCurrentSessionState, saveCurrentSessionState } from './current-session.js';
5
+ import { loadState, saveState } from './state.js';
6
+ import { SessionManager } from './session-manager.js';
7
+ import { App } from './ui/app.js';
8
+ import { resolveSessionArgs } from './agent-launch.js';
9
+ export function start(options = {}) {
10
+ const configPath = options.configPath ?? join(homedir(), '.config', 'mav', 'config.yaml');
11
+ const statePath = join(dirname(configPath), 'state.json');
12
+ const currentSessionPath = join(homedir(), '.local', 'state', 'mav', 'current-session.json');
13
+ const config = loadConfig(configPath);
14
+ const agentsToStart = options.agentType
15
+ ? config.agents.filter((a) => a.type === options.agentType)
16
+ : config.agents;
17
+ if (agentsToStart.length === 0 && options.agentType) {
18
+ console.error(`No agents found for type: ${options.agentType}`);
19
+ process.exit(1);
20
+ }
21
+ const savedState = loadState(statePath);
22
+ const manager = new SessionManager();
23
+ const app = new App(manager, statePath);
24
+ const publishSelectedSession = () => {
25
+ const session = manager.selectedSession;
26
+ if (!session) {
27
+ clearCurrentSessionState(currentSessionPath);
28
+ return;
29
+ }
30
+ saveCurrentSessionState(currentSessionPath, {
31
+ id: session.id,
32
+ type: session.type,
33
+ displayName: session.displayName,
34
+ cwd: session.cwd,
35
+ });
36
+ };
37
+ const typeCounters = {};
38
+ const configSessionIds = new Set();
39
+ for (const agentConfig of agentsToStart) {
40
+ typeCounters[agentConfig.type] = (typeCounters[agentConfig.type] ?? 0) + 1;
41
+ const predictedId = `${agentConfig.type}#${typeCounters[agentConfig.type]}`;
42
+ const savedSession = savedState?.sessions[predictedId];
43
+ const { args, newSessionId } = resolveSessionArgs(agentConfig.type, agentConfig.args, savedSession?.sessionId, savedSession != null);
44
+ const session = manager.addSession({ ...agentConfig, args });
45
+ session.baseArgs = agentConfig.args;
46
+ configSessionIds.add(session.id);
47
+ if (newSessionId != null) {
48
+ session.sessionId = newSessionId;
49
+ }
50
+ }
51
+ // configに定義されていないが保存済みセッション(動的追加分)を再作成する
52
+ if (savedState) {
53
+ for (const [stateId, savedSession] of Object.entries(savedState.sessions)) {
54
+ if (configSessionIds.has(stateId) || !savedSession.agentBase)
55
+ continue;
56
+ const rc = savedSession.agentBase;
57
+ const { args, newSessionId } = resolveSessionArgs(rc.type, rc.args, savedSession.sessionId, true);
58
+ const session = manager.addSession({ type: rc.type, cmd: rc.cmd, args });
59
+ session.baseArgs = rc.args;
60
+ if (newSessionId != null) {
61
+ session.sessionId = newSessionId;
62
+ }
63
+ }
64
+ }
65
+ if (savedState) {
66
+ manager.restoreLogBuffers(savedState);
67
+ }
68
+ manager.on('selection', () => {
69
+ publishSelectedSession();
70
+ });
71
+ manager.on('cwd', (sessionId) => {
72
+ if (manager.selectedSession?.id !== sessionId) {
73
+ return;
74
+ }
75
+ publishSelectedSession();
76
+ });
77
+ publishSelectedSession();
78
+ // q/Ctrl+C 以外の終了(ウィンドウ閉じ等)でも state を保存する
79
+ const saveOnExit = () => {
80
+ try {
81
+ saveState(statePath, manager);
82
+ }
83
+ catch { /* ignore */ }
84
+ };
85
+ process.once('SIGTERM', () => { saveOnExit(); process.exit(0); });
86
+ process.once('SIGHUP', () => { saveOnExit(); process.exit(0); });
87
+ app.start();
88
+ return manager;
89
+ }
90
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export declare function getProcessCwd(pid: number, platform?: NodeJS.Platform): string | null;
@@ -0,0 +1,24 @@
1
+ import { execFileSync } from 'node:child_process';
2
+ import { readlinkSync } from 'node:fs';
3
+ export function getProcessCwd(pid, platform = process.platform) {
4
+ if (!Number.isInteger(pid) || pid <= 0) {
5
+ return null;
6
+ }
7
+ try {
8
+ if (platform === 'linux') {
9
+ return readlinkSync(`/proc/${pid}/cwd`);
10
+ }
11
+ if (platform === 'darwin') {
12
+ const output = execFileSync('lsof', ['-a', '-d', 'cwd', '-p', String(pid), '-Fn'], { encoding: 'utf8' });
13
+ const cwdLine = output
14
+ .split('\n')
15
+ .find((line) => line.startsWith('n/') || line === 'n/');
16
+ return cwdLine ? cwdLine.slice(1) : null;
17
+ }
18
+ }
19
+ catch {
20
+ return null;
21
+ }
22
+ return null;
23
+ }
24
+ //# sourceMappingURL=process-cwd.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"process-cwd.js","sourceRoot":"","sources":["../../src/process-cwd.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAEtC,MAAM,UAAU,aAAa,CAAC,GAAW,EAAE,WAA4B,OAAO,CAAC,QAAQ;IACrF,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC;QACvC,OAAO,IAAI,CAAA;IACb,CAAC;IAED,IAAI,CAAC;QACH,IAAI,QAAQ,KAAK,OAAO,EAAE,CAAC;YACzB,OAAO,YAAY,CAAC,SAAS,GAAG,MAAM,CAAC,CAAA;QACzC,CAAC;QAED,IAAI,QAAQ,KAAK,QAAQ,EAAE,CAAC;YAC1B,MAAM,MAAM,GAAG,YAAY,CACzB,MAAM,EACN,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,EAC7C,EAAE,QAAQ,EAAE,MAAM,EAAE,CACrB,CAAA;YACD,MAAM,OAAO,GAAG,MAAM;iBACnB,KAAK,CAAC,IAAI,CAAC;iBACX,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,IAAI,KAAK,IAAI,CAAC,CAAA;YAEzD,OAAO,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;QAC1C,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAA;IACb,CAAC;IAED,OAAO,IAAI,CAAA;AACb,CAAC"}
@@ -0,0 +1,16 @@
1
+ import { EventEmitter } from 'node:events';
2
+ import { AgentSession } from './agent.js';
3
+ import type { AgentConfig } from './config.js';
4
+ import type { MavState } from './state.js';
5
+ export declare class SessionManager extends EventEmitter {
6
+ sessions: AgentSession[];
7
+ selectedIndex: number;
8
+ private sessionListeners;
9
+ private emitSelection;
10
+ addSession(config: AgentConfig, cols?: number, rows?: number): AgentSession;
11
+ removeSession(id: string): void;
12
+ selectSession(index: number): void;
13
+ get selectedSession(): AgentSession | null;
14
+ restoreLogBuffers(state: MavState): void;
15
+ killAll(): void;
16
+ }
@@ -0,0 +1,102 @@
1
+ import { EventEmitter } from 'node:events';
2
+ import { AgentSession } from './agent.js';
3
+ export class SessionManager extends EventEmitter {
4
+ sessions = [];
5
+ selectedIndex = -1;
6
+ sessionListeners = new Map();
7
+ emitSelection() {
8
+ this.emit('selection', this.selectedSession);
9
+ }
10
+ addSession(config, cols = 80, rows = 24) {
11
+ const session = new AgentSession(config, cols, rows);
12
+ const onData = (chunk) => { this.emit('data', session.id, chunk); };
13
+ const onExit = (code) => { this.emit('exit', session.id, code); };
14
+ const onStatus = (status) => { this.emit('status', session.id, status); };
15
+ const onName = (name) => { this.emit('name', session.id, name); };
16
+ const onCwd = (cwd) => { this.emit('cwd', session.id, cwd); };
17
+ session.on('data', onData);
18
+ session.on('exit', onExit);
19
+ session.on('status', onStatus);
20
+ session.on('name', onName);
21
+ session.on('cwd', onCwd);
22
+ this.sessionListeners.set(session.id, { onData, onExit, onStatus, onName, onCwd });
23
+ this.sessions.push(session);
24
+ if (this.selectedIndex === -1) {
25
+ this.selectedIndex = 0;
26
+ this.emitSelection();
27
+ }
28
+ return session;
29
+ }
30
+ removeSession(id) {
31
+ const idx = this.sessions.findIndex((s) => s.id === id);
32
+ if (idx === -1)
33
+ return;
34
+ const session = this.sessions[idx];
35
+ const ls = this.sessionListeners.get(id);
36
+ if (ls) {
37
+ session.off('data', ls.onData);
38
+ session.off('exit', ls.onExit);
39
+ session.off('status', ls.onStatus);
40
+ session.off('name', ls.onName);
41
+ session.off('cwd', ls.onCwd);
42
+ this.sessionListeners.delete(id);
43
+ }
44
+ session.kill();
45
+ this.sessions.splice(idx, 1);
46
+ if (this.sessions.length === 0) {
47
+ this.selectedIndex = -1;
48
+ }
49
+ else if (idx < this.selectedIndex) {
50
+ this.selectedIndex -= 1;
51
+ }
52
+ else if (this.selectedIndex >= this.sessions.length) {
53
+ this.selectedIndex = this.sessions.length - 1;
54
+ }
55
+ this.emitSelection();
56
+ }
57
+ selectSession(index) {
58
+ if (index < 0 || index >= this.sessions.length)
59
+ return;
60
+ this.selectedIndex = index;
61
+ this.emitSelection();
62
+ }
63
+ get selectedSession() {
64
+ if (this.selectedIndex === -1)
65
+ return null;
66
+ return this.sessions[this.selectedIndex] ?? null;
67
+ }
68
+ restoreLogBuffers(state) {
69
+ for (const session of this.sessions) {
70
+ const saved = state.sessions[session.id];
71
+ if (saved) {
72
+ session.logBuffer = Array.isArray(saved.logBuffer)
73
+ ? saved.logBuffer.filter((chunk) => typeof chunk === 'string')
74
+ : [];
75
+ if (saved.sessionId != null) {
76
+ session.sessionId = saved.sessionId;
77
+ }
78
+ if (saved.displayName) {
79
+ session.restoreDisplayName(saved.displayName);
80
+ }
81
+ }
82
+ }
83
+ }
84
+ killAll() {
85
+ for (const session of this.sessions) {
86
+ const ls = this.sessionListeners.get(session.id);
87
+ if (ls) {
88
+ session.off('data', ls.onData);
89
+ session.off('exit', ls.onExit);
90
+ session.off('status', ls.onStatus);
91
+ session.off('name', ls.onName);
92
+ session.off('cwd', ls.onCwd);
93
+ }
94
+ session.kill();
95
+ }
96
+ this.sessions = [];
97
+ this.sessionListeners.clear();
98
+ this.selectedIndex = -1;
99
+ this.emitSelection();
100
+ }
101
+ }
102
+ //# sourceMappingURL=session-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-manager.js","sourceRoot":"","sources":["../../src/session-manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ import type { SessionManager } from './session-manager.js';
2
+ import type { SessionStatus } from './agent.js';
3
+ export interface SessionState {
4
+ logBuffer: string[];
5
+ status: SessionStatus;
6
+ sessionId?: string;
7
+ displayName?: string;
8
+ /** configに定義されていない動的セッションを再起動時に復元するための情報 */
9
+ agentBase?: {
10
+ type: string;
11
+ cmd: string;
12
+ args: string[];
13
+ };
14
+ }
15
+ export interface MavState {
16
+ sessions: Record<string, SessionState>;
17
+ }
18
+ export declare function saveState(path: string, manager: SessionManager): void;
19
+ export declare function loadState(path: string): MavState | null;
@@ -0,0 +1,30 @@
1
+ import { readFileSync, writeFileSync, mkdirSync } from 'node:fs';
2
+ import { dirname } from 'node:path';
3
+ export function saveState(path, manager) {
4
+ const state = { sessions: {} };
5
+ for (const session of manager.sessions) {
6
+ state.sessions[session.id] = {
7
+ logBuffer: [...session.logBuffer],
8
+ status: session.status,
9
+ ...(session.sessionId != null && { sessionId: session.sessionId }),
10
+ displayName: session.displayName,
11
+ agentBase: {
12
+ type: session.type,
13
+ cmd: session.cmd,
14
+ args: [...session.baseArgs],
15
+ },
16
+ };
17
+ }
18
+ mkdirSync(dirname(path), { recursive: true });
19
+ writeFileSync(path, JSON.stringify(state), 'utf-8');
20
+ }
21
+ export function loadState(path) {
22
+ try {
23
+ const raw = readFileSync(path, 'utf-8');
24
+ return JSON.parse(raw);
25
+ }
26
+ catch {
27
+ return null;
28
+ }
29
+ }
30
+ //# sourceMappingURL=state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.js","sourceRoot":"","sources":["../../src/state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AAChE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAqBnC,MAAM,UAAU,SAAS,CAAC,IAAY,EAAE,OAAuB;IAC7D,MAAM,KAAK,GAAa,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAA;IACxC,KAAK,MAAM,OAAO,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;QACvC,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG;YAC3B,SAAS,EAAE,CAAC,GAAG,OAAO,CAAC,SAAS,CAAC;YACjC,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,GAAG,CAAC,OAAO,CAAC,SAAS,IAAI,IAAI,IAAI,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,CAAC;YAClE,WAAW,EAAE,OAAO,CAAC,WAAW;YAChC,SAAS,EAAE;gBACT,IAAI,EAAE,OAAO,CAAC,IAAI;gBAClB,GAAG,EAAE,OAAO,CAAC,GAAG;gBAChB,IAAI,EAAE,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC;aAC5B;SACF,CAAA;IACH,CAAC;IACD,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IAC7C,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC,CAAA;AACrD,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,IAAY;IACpC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAA;QACvC,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAa,CAAA;IACpC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAA;IACb,CAAC;AACH,CAAC"}
@@ -0,0 +1,15 @@
1
+ import type { SessionManager } from '../session-manager.js';
2
+ export declare class App {
3
+ private screen;
4
+ private manager;
5
+ private statePath;
6
+ private overviewUI;
7
+ private detailUI;
8
+ private mode;
9
+ constructor(manager: SessionManager, statePath: string);
10
+ private bindGlobalKeys;
11
+ private switchToDetail;
12
+ private switchToOverview;
13
+ private shutdown;
14
+ start(): void;
15
+ }
@@ -0,0 +1,109 @@
1
+ import blessed from 'neo-blessed';
2
+ import { saveState } from '../state.js';
3
+ import { OverviewUI } from './overview.js';
4
+ import { DetailUI } from './detail.js';
5
+ export class App {
6
+ screen;
7
+ manager;
8
+ statePath;
9
+ overviewUI;
10
+ detailUI;
11
+ mode = 'overview';
12
+ constructor(manager, statePath) {
13
+ this.manager = manager;
14
+ this.statePath = statePath;
15
+ this.screen = blessed.screen({
16
+ smartCSR: true,
17
+ title: 'mav',
18
+ fullUnicode: true,
19
+ });
20
+ this.overviewUI = new OverviewUI(this.screen, manager, (session) => {
21
+ if (session) {
22
+ this.switchToDetail(session);
23
+ }
24
+ });
25
+ this.detailUI = new DetailUI(this.screen, () => {
26
+ if (this.mode === 'detail') {
27
+ this.switchToOverview();
28
+ }
29
+ });
30
+ const proto = Object.getPrototypeOf(this.screen);
31
+ const baseRender = proto.render ?? this.screen.render;
32
+ const protoRender = baseRender.bind(this.screen);
33
+ this.screen.render = () => {
34
+ if (this.mode === 'detail')
35
+ return;
36
+ protoRender();
37
+ };
38
+ this.bindGlobalKeys();
39
+ this.screen.on('resize', () => {
40
+ const cols = this.screen.width;
41
+ const rows = this.screen.height;
42
+ if (this.mode === 'detail') {
43
+ this.detailUI.resize(cols, rows);
44
+ return;
45
+ }
46
+ this.overviewUI.resizeSelectedSession();
47
+ });
48
+ }
49
+ bindGlobalKeys() {
50
+ this.screen.key('q', () => {
51
+ if (this.mode === 'detail')
52
+ return;
53
+ this.shutdown();
54
+ });
55
+ this.screen.key('C-c', () => {
56
+ if (this.mode === 'overview') {
57
+ this.shutdown();
58
+ }
59
+ });
60
+ this.screen.key(['right', 'enter'], () => {
61
+ if (this.mode !== 'overview')
62
+ return;
63
+ if (this.overviewUI.isPromptOpen())
64
+ return;
65
+ const session = this.manager.selectedSession;
66
+ if (!session)
67
+ return;
68
+ this.switchToDetail();
69
+ });
70
+ }
71
+ switchToDetail(session = this.manager.selectedSession) {
72
+ if (!session)
73
+ return;
74
+ this.mode = 'detail';
75
+ this.overviewUI.hide();
76
+ this.screen.program.normalBuffer();
77
+ this.screen.program.disableMouse();
78
+ this.screen.realloc();
79
+ this.detailUI.attach(session);
80
+ this.detailUI.resize(this.screen.width, this.screen.height);
81
+ this.detailUI.show();
82
+ }
83
+ switchToOverview() {
84
+ this.mode = 'overview';
85
+ this.detailUI.detach();
86
+ this.detailUI.hide();
87
+ this.screen.program.alternateBuffer();
88
+ this.screen.program.enableMouse();
89
+ this.screen.realloc();
90
+ this.overviewUI.show();
91
+ }
92
+ shutdown() {
93
+ try {
94
+ saveState(this.statePath, this.manager);
95
+ }
96
+ catch {
97
+ // 終了シーケンスは継続する
98
+ }
99
+ this.manager.killAll();
100
+ this.screen.destroy();
101
+ process.exit(0);
102
+ }
103
+ start() {
104
+ this.overviewUI.show();
105
+ this.overviewUI.resizeSelectedSession();
106
+ this.screen.render();
107
+ }
108
+ }
109
+ //# sourceMappingURL=app.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app.js","sourceRoot":"","sources":["../../../src/ui/app.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ import type { Widgets } from 'neo-blessed';
2
+ import type { AgentSession } from '../agent.js';
3
+ export declare class DetailUI {
4
+ private static readonly KEYBOARD_FLAGS_RESPONSE_PATTERN;
5
+ private static readonly PENDING_INPUT_FLUSH_DELAY_MS;
6
+ private static readonly EXIT_SEQUENCES;
7
+ private static readonly EXIT_SEQUENCE_PATTERNS;
8
+ private screen;
9
+ private onExitDetail;
10
+ private currentSession;
11
+ private dataListener;
12
+ private rawInputListener;
13
+ private pendingInput;
14
+ private pendingInputTimer;
15
+ private keyboardEnhancementFlags;
16
+ constructor(screen: Widgets.Screen, onExitDetail: () => void);
17
+ private isExitShortcut;
18
+ private isExitShortcutPrefix;
19
+ private debugLogInput;
20
+ private rememberKeyboardEnhancementFlags;
21
+ private clearPendingInputTimer;
22
+ private flushPendingInput;
23
+ attach(session: AgentSession): void;
24
+ detach(): void;
25
+ show(): void;
26
+ hide(): void;
27
+ resize(cols: number, rows: number): void;
28
+ }