agkan 3.5.0 → 3.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/dist/board/BulkRunService.d.ts +35 -0
  2. package/dist/board/BulkRunService.d.ts.map +1 -0
  3. package/dist/board/BulkRunService.js +152 -0
  4. package/dist/board/BulkRunService.js.map +1 -0
  5. package/dist/board/boardRenderer.d.ts.map +1 -1
  6. package/dist/board/boardRenderer.js +14 -23
  7. package/dist/board/boardRenderer.js.map +1 -1
  8. package/dist/board/boardRoutes.d.ts +15 -2
  9. package/dist/board/boardRoutes.d.ts.map +1 -1
  10. package/dist/board/boardRoutes.js +220 -63
  11. package/dist/board/boardRoutes.js.map +1 -1
  12. package/dist/board/boardStyles.d.ts +1 -1
  13. package/dist/board/boardStyles.d.ts.map +1 -1
  14. package/dist/board/boardStyles.js +36 -5
  15. package/dist/board/boardStyles.js.map +1 -1
  16. package/dist/board/client/main.css +252 -0
  17. package/dist/board/client/main.js +12216 -0
  18. package/dist/board/server.d.ts +2 -2
  19. package/dist/board/server.d.ts.map +1 -1
  20. package/dist/board/server.js +44 -8
  21. package/dist/board/server.js.map +1 -1
  22. package/dist/cli/commands/init.d.ts.map +1 -1
  23. package/dist/cli/commands/init.js +7 -2
  24. package/dist/cli/commands/init.js.map +1 -1
  25. package/dist/hooks/claudeHookSettings.d.ts +2 -0
  26. package/dist/hooks/claudeHookSettings.d.ts.map +1 -0
  27. package/dist/hooks/claudeHookSettings.js +54 -0
  28. package/dist/hooks/claudeHookSettings.js.map +1 -0
  29. package/dist/hooks/hook-attention.mjs +54 -0
  30. package/dist/hooks/hook-session-start.mjs +23 -0
  31. package/dist/hooks/hook-stop.mjs +115 -0
  32. package/dist/services/AttentionStateService.d.ts +16 -0
  33. package/dist/services/AttentionStateService.d.ts.map +1 -0
  34. package/dist/services/AttentionStateService.js +42 -0
  35. package/dist/services/AttentionStateService.js.map +1 -0
  36. package/dist/services/ClaudeProcessService.d.ts +7 -0
  37. package/dist/services/ClaudeProcessService.d.ts.map +1 -1
  38. package/dist/services/ClaudeProcessService.js +19 -6
  39. package/dist/services/ClaudeProcessService.js.map +1 -1
  40. package/dist/terminal/PtySessionService.d.ts +51 -0
  41. package/dist/terminal/PtySessionService.d.ts.map +1 -0
  42. package/dist/terminal/PtySessionService.js +341 -0
  43. package/dist/terminal/PtySessionService.js.map +1 -0
  44. package/dist/terminal/wsTerminalServer.d.ts +7 -0
  45. package/dist/terminal/wsTerminalServer.d.ts.map +1 -0
  46. package/dist/terminal/wsTerminalServer.js +81 -0
  47. package/dist/terminal/wsTerminalServer.js.map +1 -0
  48. package/dist/utils/hookToken.d.ts +3 -0
  49. package/dist/utils/hookToken.d.ts.map +1 -0
  50. package/dist/utils/hookToken.js +24 -0
  51. package/dist/utils/hookToken.js.map +1 -0
  52. package/package.json +11 -5
@@ -0,0 +1,51 @@
1
+ import type { StorageBackend } from '../db/types/repository';
2
+ import type { RunLog, CompletionConfirmCallback } from '../services/ClaudeProcessService';
3
+ import { AttentionStateService } from '../services/AttentionStateService';
4
+ export declare function stripAnsi(text: string): string;
5
+ type OutputEvent = {
6
+ kind: 'done';
7
+ exitCode: number;
8
+ } | {
9
+ kind: 'error';
10
+ message: string;
11
+ };
12
+ type SubscribeCallback = (event: OutputEvent) => void;
13
+ export interface PtySessionServiceOptions {
14
+ boardApiUrl: string | null;
15
+ attentionStateService: AttentionStateService;
16
+ hookSettingsDataDir: string;
17
+ }
18
+ export declare class PtySessionService {
19
+ private sessions;
20
+ private completedSnapshots;
21
+ private db;
22
+ private runningTasksChangeSubscribers;
23
+ private userStoppedTasks;
24
+ private completionConfirmSubscribers;
25
+ private boardApiUrl;
26
+ private attentionStateService;
27
+ private hookSettingsDataDir;
28
+ private hookSettingsPath;
29
+ constructor(db?: StorageBackend | null, options?: PtySessionServiceOptions);
30
+ setBoardApiUrl(url: string): void;
31
+ subscribeRunningTasksChange(callback: () => void): () => void;
32
+ subscribeCompletionConfirm(callback: CompletionConfirmCallback): () => void;
33
+ notifyCompletionConfirm(taskId: number, targetStatus: string): void;
34
+ isUserStopped(taskId: number): boolean;
35
+ private notifyRunningTasksChange;
36
+ startProcess(taskId: number, prompt: string, command?: string, model?: string, effort?: string): Promise<void>;
37
+ stopProcess(taskId: number): boolean;
38
+ listRunningTasks(): {
39
+ taskId: number;
40
+ command: string;
41
+ }[];
42
+ getSnapshot(taskId: number): string;
43
+ subscribeOutput(taskId: number, callback: SubscribeCallback): () => void;
44
+ subscribeOutputUpdate(taskId: number, callback: () => void): () => void;
45
+ subscribeRawOutput(taskId: number, callback: (data: string) => void): () => void;
46
+ resize(taskId: number, cols: number, rows: number): void;
47
+ writeInput(taskId: number, data: string): void;
48
+ getRunLogs(taskId: number): RunLog[];
49
+ }
50
+ export {};
51
+ //# sourceMappingURL=PtySessionService.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PtySessionService.d.ts","sourceRoot":"","sources":["../../src/terminal/PtySessionService.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAa,MAAM,wBAAwB,CAAC;AACxE,OAAO,KAAK,EACV,MAAM,EAEN,yBAAyB,EAC1B,MAAM,kCAAkC,CAAC;AAI1C,OAAO,EAAE,qBAAqB,EAAE,MAAM,mCAAmC,CAAC;AAE1E,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAY9C;AAgBD,KAAK,WAAW,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAC3F,KAAK,iBAAiB,GAAG,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAC;AA0BtD,MAAM,WAAW,wBAAwB;IACvC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,qBAAqB,EAAE,qBAAqB,CAAC;IAC7C,mBAAmB,EAAE,MAAM,CAAC;CAC7B;AAED,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,QAAQ,CAAuC;IACvD,OAAO,CAAC,kBAAkB,CAAkC;IAC5D,OAAO,CAAC,EAAE,CAAwB;IAClC,OAAO,CAAC,6BAA6B,CAA8B;IACnE,OAAO,CAAC,gBAAgB,CAA0B;IAClD,OAAO,CAAC,4BAA4B,CAA6C;IACjF,OAAO,CAAC,WAAW,CAAgB;IACnC,OAAO,CAAC,qBAAqB,CAA+B;IAC5D,OAAO,CAAC,mBAAmB,CAAgB;IAC3C,OAAO,CAAC,gBAAgB,CAAuB;gBAEnC,EAAE,CAAC,EAAE,cAAc,GAAG,IAAI,EAAE,OAAO,CAAC,EAAE,wBAAwB;IAO1E,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAIjC,2BAA2B,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI;IAO7D,0BAA0B,CAAC,QAAQ,EAAE,yBAAyB,GAAG,MAAM,IAAI;IAO3E,uBAAuB,CAAC,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,IAAI;IAInE,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO;IAItC,OAAO,CAAC,wBAAwB;IAI1B,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,SAAQ,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAiKnH,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO;IAiBpC,gBAAgB,IAAI;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,EAAE;IAIzD,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;IAInC,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,iBAAiB,GAAG,MAAM,IAAI;IAkBxE,qBAAqB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI;IAkBvE,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAAG,MAAM,IAAI;IAShF,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAIxD,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAI9C,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE;CAarC"}
@@ -0,0 +1,341 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.PtySessionService = void 0;
37
+ exports.stripAnsi = stripAnsi;
38
+ const pty = __importStar(require("node-pty"));
39
+ const child_process_1 = require("child_process");
40
+ const errors_1 = require("../errors");
41
+ const claudeHookSettings_1 = require("../hooks/claudeHookSettings");
42
+ const hookToken_1 = require("../utils/hookToken");
43
+ function stripAnsi(text) {
44
+ return (text
45
+ // CSI sequences: ESC [ <param bytes> <intermediate bytes> <final byte>
46
+ .replace(/\x1b\[[\x30-\x3F]*[\x20-\x2F]*[\x40-\x7E]/g, '')
47
+ // OSC sequences: ESC ] ... BEL or ESC \ (also handles unterminated)
48
+ .replace(/\x1b\][^\x07\x1b]*(?:\x07|\x1b\\|$)/g, '')
49
+ // Single ESC sequences (e.g. ESC = ESC >)
50
+ .replace(/\x1b[=>]/g, '')
51
+ // Carriage return overwrite: collapse lines with CR to last segment
52
+ .replace(/[^\n]*\r([^\n])/g, '$1'));
53
+ }
54
+ function resolveClaudePath() {
55
+ try {
56
+ return (0, child_process_1.execSync)('which claude', { env: process.env }).toString().trim() || 'claude';
57
+ }
58
+ catch {
59
+ return 'claude';
60
+ }
61
+ }
62
+ const CLAUDE_BIN = resolveClaudePath();
63
+ const PROMPT_FALLBACK_DELAY_MS = 10000;
64
+ const PROMPT_ENTER_DELAY_MS = 100;
65
+ const MAX_SNAPSHOT_BYTES = 500_000;
66
+ const MAX_COMPLETED_SNAPSHOTS = 10;
67
+ function hasWorkspaceTrustPrompt(text) {
68
+ return /trust.*folder|Do you trust/i.test(text) && /y\/n|yes.*trust/i.test(text);
69
+ }
70
+ function hasClaudeReadySignal(text) {
71
+ return text.includes('bypass permissions');
72
+ }
73
+ class PtySessionService {
74
+ sessions = new Map();
75
+ completedSnapshots = new Map();
76
+ db;
77
+ runningTasksChangeSubscribers = new Set();
78
+ userStoppedTasks = new Set();
79
+ completionConfirmSubscribers = new Set();
80
+ boardApiUrl;
81
+ attentionStateService;
82
+ hookSettingsDataDir;
83
+ hookSettingsPath = null;
84
+ constructor(db, options) {
85
+ this.db = db ?? null;
86
+ this.boardApiUrl = options?.boardApiUrl ?? null;
87
+ this.attentionStateService = options?.attentionStateService ?? null;
88
+ this.hookSettingsDataDir = options?.hookSettingsDataDir ?? null;
89
+ }
90
+ setBoardApiUrl(url) {
91
+ this.boardApiUrl = url;
92
+ }
93
+ subscribeRunningTasksChange(callback) {
94
+ this.runningTasksChangeSubscribers.add(callback);
95
+ return () => {
96
+ this.runningTasksChangeSubscribers.delete(callback);
97
+ };
98
+ }
99
+ subscribeCompletionConfirm(callback) {
100
+ this.completionConfirmSubscribers.add(callback);
101
+ return () => {
102
+ this.completionConfirmSubscribers.delete(callback);
103
+ };
104
+ }
105
+ notifyCompletionConfirm(taskId, targetStatus) {
106
+ this.completionConfirmSubscribers.forEach((cb) => cb(taskId, targetStatus));
107
+ }
108
+ isUserStopped(taskId) {
109
+ return this.userStoppedTasks.has(taskId);
110
+ }
111
+ notifyRunningTasksChange() {
112
+ this.runningTasksChangeSubscribers.forEach((cb) => cb());
113
+ }
114
+ async startProcess(taskId, prompt, command = 'run', model, effort) {
115
+ if (this.sessions.has(taskId)) {
116
+ throw new errors_1.ConflictError(`Process for taskId ${taskId} is already running`);
117
+ }
118
+ // Ensure hook settings file exists if hook integration is configured
119
+ if (this.hookSettingsDataDir !== null && this.hookSettingsPath === null) {
120
+ this.hookSettingsPath = await (0, claudeHookSettings_1.ensureBoardHookSettings)(this.hookSettingsDataDir);
121
+ }
122
+ const modelArgs = model ? ['--model', model] : [];
123
+ const effortArgs = effort ? ['--effort', effort] : [];
124
+ const settingsArgs = this.hookSettingsPath ? ['--settings', this.hookSettingsPath] : [];
125
+ const args = [...settingsArgs, ...modelArgs, ...effortArgs, '--dangerously-skip-permissions'];
126
+ const hookEnv = {};
127
+ if (this.boardApiUrl !== null && this.boardApiUrl !== '') {
128
+ hookEnv.BOARD_TASK_ID = String(taskId);
129
+ hookEnv.BOARD_API_URL = this.boardApiUrl;
130
+ hookEnv.BOARD_HOOK_TOKEN = (0, hookToken_1.getHookToken)();
131
+ }
132
+ const ptyProcess = pty.spawn(CLAUDE_BIN, args, {
133
+ name: 'xterm-256color',
134
+ cols: 220,
135
+ rows: 50,
136
+ cwd: process.cwd(),
137
+ env: {
138
+ ...process.env,
139
+ COLORTERM: 'truecolor',
140
+ TERM: 'xterm-256color',
141
+ ...hookEnv,
142
+ },
143
+ });
144
+ const info = {
145
+ taskId,
146
+ command,
147
+ ptyProcess,
148
+ startedAt: new Date(),
149
+ outputBuffer: '',
150
+ exitSubscribers: new Set(),
151
+ rawOutputSubscribers: new Set(),
152
+ outputUpdateSubscribers: new Set(),
153
+ runLogId: null,
154
+ pendingPrompt: prompt,
155
+ promptTimer: null,
156
+ workspaceTrustHandled: false,
157
+ lastEventsUpdate: 0,
158
+ };
159
+ this.sessions.set(taskId, info);
160
+ this.notifyRunningTasksChange();
161
+ if (this.db) {
162
+ info.runLogId = this.db.runLogs.create(taskId, info.startedAt.toISOString());
163
+ }
164
+ // Fallback: send prompt if ready signal never detected within timeout
165
+ info.promptTimer = setTimeout(() => {
166
+ info.promptTimer = null;
167
+ if (info.pendingPrompt !== null && this.sessions.has(taskId)) {
168
+ const fallbackPrompt = info.pendingPrompt;
169
+ info.pendingPrompt = null;
170
+ ptyProcess.write(fallbackPrompt);
171
+ setTimeout(() => {
172
+ if (this.sessions.has(taskId)) {
173
+ ptyProcess.write('\r');
174
+ }
175
+ }, PROMPT_ENTER_DELAY_MS);
176
+ }
177
+ }, PROMPT_FALLBACK_DELAY_MS);
178
+ ptyProcess.onData((data) => {
179
+ info.outputBuffer += data;
180
+ if (info.outputBuffer.length > MAX_SNAPSHOT_BYTES) {
181
+ info.outputBuffer = info.outputBuffer.slice(-MAX_SNAPSHOT_BYTES);
182
+ }
183
+ // Auto-confirm workspace trust
184
+ if (!info.workspaceTrustHandled && hasWorkspaceTrustPrompt(info.outputBuffer)) {
185
+ info.workspaceTrustHandled = true;
186
+ ptyProcess.write('y\r');
187
+ }
188
+ // Send pending prompt as soon as Claude's input prompt is ready.
189
+ // Delay slightly to ensure the interactive input line is fully initialized
190
+ // before writing — the ready signal fires before the prompt cursor appears.
191
+ if (info.pendingPrompt !== null && hasClaudeReadySignal(info.outputBuffer)) {
192
+ if (info.promptTimer !== null) {
193
+ clearTimeout(info.promptTimer);
194
+ info.promptTimer = null;
195
+ }
196
+ const prompt = info.pendingPrompt;
197
+ info.pendingPrompt = null;
198
+ setTimeout(() => {
199
+ if (this.sessions.has(taskId)) {
200
+ ptyProcess.write(prompt);
201
+ setTimeout(() => {
202
+ if (this.sessions.has(taskId)) {
203
+ ptyProcess.write('\r');
204
+ }
205
+ }, PROMPT_ENTER_DELAY_MS);
206
+ }
207
+ }, 500);
208
+ }
209
+ info.rawOutputSubscribers.forEach((cb) => cb(data));
210
+ // Throttle: persist current output snapshot as events every 2 seconds
211
+ const now = Date.now();
212
+ if (this.db && info.runLogId && now - info.lastEventsUpdate > 2000) {
213
+ info.lastEventsUpdate = now;
214
+ const cleanText = stripAnsi(info.outputBuffer);
215
+ this.db.runLogs.updateEvents(info.runLogId, JSON.stringify([{ kind: 'text', text: cleanText }]));
216
+ info.outputUpdateSubscribers.forEach((cb) => cb());
217
+ }
218
+ });
219
+ ptyProcess.onExit(({ exitCode }) => {
220
+ const code = exitCode ?? 0;
221
+ if (info.promptTimer !== null) {
222
+ clearTimeout(info.promptTimer);
223
+ info.promptTimer = null;
224
+ }
225
+ info.pendingPrompt = null;
226
+ if (this.db && info.runLogId) {
227
+ const finishedAt = new Date().toISOString();
228
+ const cleanText = stripAnsi(info.outputBuffer);
229
+ const events = JSON.stringify([{ kind: 'text', text: cleanText }]);
230
+ this.db.runLogs.updateFinished(info.runLogId, finishedAt, code, events);
231
+ const ids = this.db.runLogs.findIdsByTaskId(taskId);
232
+ if (ids.length > 5) {
233
+ this.db.runLogs.deleteMany(ids.slice(5));
234
+ }
235
+ }
236
+ this.completedSnapshots.set(taskId, info.outputBuffer);
237
+ if (this.completedSnapshots.size > MAX_COMPLETED_SNAPSHOTS) {
238
+ const firstKey = this.completedSnapshots.keys().next().value;
239
+ this.completedSnapshots.delete(firstKey);
240
+ }
241
+ info.outputUpdateSubscribers.forEach((cb) => cb());
242
+ info.outputUpdateSubscribers.clear();
243
+ const doneEvent = { kind: 'done', exitCode: code };
244
+ info.exitSubscribers.forEach((cb) => cb(doneEvent));
245
+ this.attentionStateService?.clearTask(taskId);
246
+ if (this.sessions.get(taskId) === info) {
247
+ this.sessions.delete(taskId);
248
+ this.notifyRunningTasksChange();
249
+ }
250
+ this.userStoppedTasks.delete(taskId);
251
+ });
252
+ }
253
+ stopProcess(taskId) {
254
+ const info = this.sessions.get(taskId);
255
+ if (!info)
256
+ return false;
257
+ if (info.promptTimer !== null) {
258
+ clearTimeout(info.promptTimer);
259
+ info.promptTimer = null;
260
+ }
261
+ info.pendingPrompt = null;
262
+ info.exitSubscribers.clear();
263
+ this.userStoppedTasks.add(taskId);
264
+ info.ptyProcess.kill();
265
+ this.sessions.delete(taskId);
266
+ this.attentionStateService?.clearTask(taskId);
267
+ this.notifyRunningTasksChange();
268
+ return true;
269
+ }
270
+ listRunningTasks() {
271
+ return Array.from(this.sessions.values()).map((s) => ({ taskId: s.taskId, command: s.command }));
272
+ }
273
+ getSnapshot(taskId) {
274
+ return this.sessions.get(taskId)?.outputBuffer ?? this.completedSnapshots.get(taskId) ?? '';
275
+ }
276
+ subscribeOutput(taskId, callback) {
277
+ const info = this.sessions.get(taskId);
278
+ if (!info) {
279
+ if (this.db) {
280
+ const row = this.db.runLogs.findLatestByTaskId(taskId);
281
+ if (row) {
282
+ callback({ kind: 'done', exitCode: row.exit_code ?? 0 });
283
+ return () => { };
284
+ }
285
+ }
286
+ return () => { };
287
+ }
288
+ info.exitSubscribers.add(callback);
289
+ return () => {
290
+ info.exitSubscribers.delete(callback);
291
+ };
292
+ }
293
+ subscribeOutputUpdate(taskId, callback) {
294
+ const info = this.sessions.get(taskId);
295
+ if (!info) {
296
+ if (this.db) {
297
+ const row = this.db.runLogs.findLatestByTaskId(taskId);
298
+ if (row?.finished_at) {
299
+ callback();
300
+ return () => { };
301
+ }
302
+ }
303
+ return () => { };
304
+ }
305
+ info.outputUpdateSubscribers.add(callback);
306
+ return () => {
307
+ info.outputUpdateSubscribers.delete(callback);
308
+ };
309
+ }
310
+ subscribeRawOutput(taskId, callback) {
311
+ const info = this.sessions.get(taskId);
312
+ if (!info)
313
+ return () => { };
314
+ info.rawOutputSubscribers.add(callback);
315
+ return () => {
316
+ info.rawOutputSubscribers.delete(callback);
317
+ };
318
+ }
319
+ resize(taskId, cols, rows) {
320
+ this.sessions.get(taskId)?.ptyProcess.resize(cols, rows);
321
+ }
322
+ writeInput(taskId, data) {
323
+ this.sessions.get(taskId)?.ptyProcess.write(data);
324
+ }
325
+ getRunLogs(taskId) {
326
+ if (!this.db)
327
+ return [];
328
+ const rows = this.db.runLogs.findByTaskId(taskId, 5);
329
+ return rows.map((r) => ({
330
+ id: r.id,
331
+ task_id: r.task_id,
332
+ started_at: r.started_at,
333
+ finished_at: r.finished_at,
334
+ exit_code: r.exit_code,
335
+ session_id: r.session_id,
336
+ events: JSON.parse(r.events),
337
+ }));
338
+ }
339
+ }
340
+ exports.PtySessionService = PtySessionService;
341
+ //# sourceMappingURL=PtySessionService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PtySessionService.js","sourceRoot":"","sources":["../../src/terminal/PtySessionService.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import type { IncomingMessage } from 'http';
2
+ import type { Duplex } from 'stream';
3
+ import type { PtySessionService } from './PtySessionService';
4
+ export declare function createTerminalWsServer(ptyService: PtySessionService): {
5
+ handleUpgrade: (req: IncomingMessage, socket: Duplex, head: Buffer) => void;
6
+ };
7
+ //# sourceMappingURL=wsTerminalServer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wsTerminalServer.d.ts","sourceRoot":"","sources":["../../src/terminal/wsTerminalServer.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,MAAM,CAAC;AAC5C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AACrC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAU7D,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,iBAAiB,GAAG;IACrE,aAAa,EAAE,CAAC,GAAG,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAC7E,CAuEA"}
@@ -0,0 +1,81 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createTerminalWsServer = createTerminalWsServer;
4
+ const ws_1 = require("ws");
5
+ function parseTaskId(url, suffix) {
6
+ if (!url)
7
+ return null;
8
+ const m = url.match(/\/api\/terminal\/(\d+)\/(io|control)/);
9
+ if (!m || m[2] !== suffix)
10
+ return null;
11
+ const id = Number(m[1]);
12
+ return isNaN(id) ? null : id;
13
+ }
14
+ function createTerminalWsServer(ptyService) {
15
+ const ioServer = new ws_1.WebSocketServer({ noServer: true });
16
+ const controlServer = new ws_1.WebSocketServer({ noServer: true });
17
+ ioServer.on('connection', (ws, req) => {
18
+ const taskId = parseTaskId(req.url, 'io');
19
+ if (taskId === null) {
20
+ ws.close(1008, 'Invalid taskId');
21
+ return;
22
+ }
23
+ const snapshot = ptyService.getSnapshot(taskId);
24
+ if (snapshot && ws.readyState === ws_1.WebSocket.OPEN) {
25
+ ws.send(Buffer.from(snapshot));
26
+ }
27
+ const unsub = ptyService.subscribeRawOutput(taskId, (data) => {
28
+ if (ws.readyState === ws_1.WebSocket.OPEN) {
29
+ ws.send(Buffer.from(data));
30
+ }
31
+ });
32
+ ws.on('message', (msg) => {
33
+ const text = typeof msg === 'string' ? msg : msg.toString('utf8');
34
+ ptyService.writeInput(taskId, text);
35
+ });
36
+ ws.on('close', () => {
37
+ unsub();
38
+ });
39
+ ws.on('error', () => {
40
+ unsub();
41
+ });
42
+ });
43
+ controlServer.on('connection', (ws, req) => {
44
+ const taskId = parseTaskId(req.url, 'control');
45
+ if (taskId === null) {
46
+ ws.close(1008, 'Invalid taskId');
47
+ return;
48
+ }
49
+ ws.on('message', (msg) => {
50
+ try {
51
+ const text = typeof msg === 'string' ? msg : msg.toString('utf8');
52
+ const data = JSON.parse(text);
53
+ if (data.type === 'resize' && typeof data.cols === 'number' && typeof data.rows === 'number') {
54
+ ptyService.resize(taskId, data.cols, data.rows);
55
+ }
56
+ }
57
+ catch {
58
+ // Ignore malformed messages
59
+ }
60
+ });
61
+ });
62
+ return {
63
+ handleUpgrade(req, socket, head) {
64
+ const url = req.url ?? '';
65
+ if (url.includes('/io')) {
66
+ ioServer.handleUpgrade(req, socket, head, (ws) => {
67
+ ioServer.emit('connection', ws, req);
68
+ });
69
+ }
70
+ else if (url.includes('/control')) {
71
+ controlServer.handleUpgrade(req, socket, head, (ws) => {
72
+ controlServer.emit('connection', ws, req);
73
+ });
74
+ }
75
+ else {
76
+ socket.destroy();
77
+ }
78
+ },
79
+ };
80
+ }
81
+ //# sourceMappingURL=wsTerminalServer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wsTerminalServer.js","sourceRoot":"","sources":["../../src/terminal/wsTerminalServer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export declare function getHookToken(): string;
2
+ export declare function verifyHookToken(token: string | undefined | null): boolean;
3
+ //# sourceMappingURL=hookToken.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hookToken.d.ts","sourceRoot":"","sources":["../../src/utils/hookToken.ts"],"names":[],"mappings":"AAIA,wBAAgB,YAAY,IAAI,MAAM,CAKrC;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,OAAO,CAKzE"}
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.getHookToken = getHookToken;
7
+ exports.verifyHookToken = verifyHookToken;
8
+ const crypto_1 = __importDefault(require("crypto"));
9
+ let cachedToken = null;
10
+ function getHookToken() {
11
+ if (cachedToken === null) {
12
+ cachedToken = crypto_1.default.randomBytes(32).toString('hex');
13
+ }
14
+ return cachedToken;
15
+ }
16
+ function verifyHookToken(token) {
17
+ if (typeof token !== 'string' || token.length === 0)
18
+ return false;
19
+ const current = getHookToken();
20
+ if (token.length !== current.length)
21
+ return false;
22
+ return crypto_1.default.timingSafeEqual(Buffer.from(token), Buffer.from(current));
23
+ }
24
+ //# sourceMappingURL=hookToken.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hookToken.js","sourceRoot":"","sources":["../../src/utils/hookToken.ts"],"names":[],"mappings":";;;;;AAIA,oCAKC;AAED,0CAKC;AAhBD,oDAA4B;AAE5B,IAAI,WAAW,GAAkB,IAAI,CAAC;AAEtC,SAAgB,YAAY;IAC1B,IAAI,WAAW,KAAK,IAAI,EAAE,CAAC;QACzB,WAAW,GAAG,gBAAM,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IACvD,CAAC;IACD,OAAO,WAAW,CAAC;AACrB,CAAC;AAED,SAAgB,eAAe,CAAC,KAAgC;IAC9D,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAClE,MAAM,OAAO,GAAG,YAAY,EAAE,CAAC;IAC/B,IAAI,KAAK,CAAC,MAAM,KAAK,OAAO,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IAClD,OAAO,gBAAM,CAAC,eAAe,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;AAC1E,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agkan",
3
- "version": "3.5.0",
3
+ "version": "3.8.0",
4
4
  "description": "TypeScript-based CLI task management tool with SQLite storage",
5
5
  "main": "dist/cli/index.js",
6
6
  "bin": {
@@ -11,7 +11,7 @@
11
11
  "bin"
12
12
  ],
13
13
  "scripts": {
14
- "build": "tsc && node scripts/build-client.mjs",
14
+ "build": "tsc && node scripts/build-client.mjs && node scripts/build-hooks.mjs",
15
15
  "build:server": "tsc",
16
16
  "build:client": "node scripts/build-client.mjs",
17
17
  "dev": "tsc --watch",
@@ -28,7 +28,7 @@
28
28
  "type-check": "tsc --noEmit && tsc --noEmit -p src/board/client/tsconfig.json",
29
29
  "check": "pnpm run type-check && pnpm run lint && pnpm run format:check",
30
30
  "prepublishOnly": "pnpm run check && pnpm run build && vitest run",
31
- "prepare": "husky || true && chmod +x node_modules/.bin/* node_modules/prettier/bin/*.cjs 2>/dev/null || true"
31
+ "prepare": "husky || true && chmod +x node_modules/.bin/* node_modules/prettier/bin/*.cjs node_modules/node-pty/prebuilds/*/spawn-helper 2>/dev/null || true"
32
32
  },
33
33
  "repository": {
34
34
  "type": "git",
@@ -57,21 +57,27 @@
57
57
  "chalk": "^4.1.2",
58
58
  "commander": "^14.0.3",
59
59
  "hono": "^4.12.5",
60
- "js-yaml": "^4.1.1"
60
+ "js-yaml": "^4.1.1",
61
+ "node-pty": "1.1.0",
62
+ "ws": "8.18.3"
61
63
  },
62
64
  "pnpm": {
63
65
  "onlyBuiltDependencies": [
64
66
  "better-sqlite3",
65
- "esbuild"
67
+ "esbuild",
68
+ "node-pty"
66
69
  ]
67
70
  },
68
71
  "devDependencies": {
69
72
  "@types/better-sqlite3": "^7.6.12",
70
73
  "@types/js-yaml": "^4.0.9",
71
74
  "@types/node": "^22.10.5",
75
+ "@types/ws": "^8.18.1",
72
76
  "@typescript-eslint/eslint-plugin": "^8.56.0",
73
77
  "@typescript-eslint/parser": "^8.56.0",
74
78
  "@vitest/coverage-v8": "^4.0.18",
79
+ "@xterm/addon-fit": "^0.11.0",
80
+ "@xterm/xterm": "^6.0.0",
75
81
  "esbuild": "^0.27.4",
76
82
  "eslint": "^10.0.1",
77
83
  "eslint-config-prettier": "^10.1.8",