botmux 2.2.6 → 2.3.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.
- package/README.en.md +63 -13
- package/README.md +52 -14
- package/dist/adapters/cli/aiden.d.ts.map +1 -1
- package/dist/adapters/cli/aiden.js +0 -40
- package/dist/adapters/cli/aiden.js.map +1 -1
- package/dist/adapters/cli/claude-code.d.ts.map +1 -1
- package/dist/adapters/cli/claude-code.js +27 -63
- package/dist/adapters/cli/claude-code.js.map +1 -1
- package/dist/adapters/cli/coco.d.ts.map +1 -1
- package/dist/adapters/cli/coco.js +0 -33
- package/dist/adapters/cli/coco.js.map +1 -1
- package/dist/adapters/cli/codex.d.ts.map +1 -1
- package/dist/adapters/cli/codex.js +0 -27
- package/dist/adapters/cli/codex.js.map +1 -1
- package/dist/adapters/cli/gemini.d.ts.map +1 -1
- package/dist/adapters/cli/gemini.js +1 -29
- package/dist/adapters/cli/gemini.js.map +1 -1
- package/dist/adapters/cli/opencode.d.ts.map +1 -1
- package/dist/adapters/cli/opencode.js +1 -44
- package/dist/adapters/cli/opencode.js.map +1 -1
- package/dist/adapters/cli/types.d.ts +15 -8
- package/dist/adapters/cli/types.d.ts.map +1 -1
- package/dist/cli.js +737 -16
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +16 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +30 -0
- package/dist/config.js.map +1 -1
- package/dist/core/command-handler.d.ts.map +1 -1
- package/dist/core/command-handler.js +8 -4
- package/dist/core/command-handler.js.map +1 -1
- package/dist/core/scheduler.d.ts +38 -16
- package/dist/core/scheduler.d.ts.map +1 -1
- package/dist/core/scheduler.js +335 -149
- package/dist/core/scheduler.js.map +1 -1
- package/dist/core/session-manager.d.ts +13 -2
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +128 -25
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/types.d.ts +26 -4
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js +6 -0
- package/dist/core/types.js.map +1 -1
- package/dist/core/worker-pool.d.ts +15 -3
- package/dist/core/worker-pool.d.ts.map +1 -1
- package/dist/core/worker-pool.js +233 -31
- package/dist/core/worker-pool.js.map +1 -1
- package/dist/daemon.d.ts.map +1 -1
- package/dist/daemon.js +71 -18
- package/dist/daemon.js.map +1 -1
- package/dist/im/lark/card-builder.d.ts +29 -1
- package/dist/im/lark/card-builder.d.ts.map +1 -1
- package/dist/im/lark/card-builder.js +266 -56
- package/dist/im/lark/card-builder.js.map +1 -1
- package/dist/im/lark/card-handler.d.ts +1 -0
- package/dist/im/lark/card-handler.d.ts.map +1 -1
- package/dist/im/lark/card-handler.js +200 -40
- package/dist/im/lark/card-handler.js.map +1 -1
- package/dist/im/lark/client.d.ts.map +1 -1
- package/dist/im/lark/client.js +4 -3
- package/dist/im/lark/client.js.map +1 -1
- package/dist/im/lark/message-parser.d.ts.map +1 -1
- package/dist/im/lark/message-parser.js +44 -6
- package/dist/im/lark/message-parser.js.map +1 -1
- package/dist/services/schedule-store.d.ts +20 -3
- package/dist/services/schedule-store.d.ts.map +1 -1
- package/dist/services/schedule-store.js +140 -16
- package/dist/services/schedule-store.js.map +1 -1
- package/dist/skills/definitions.d.ts +17 -0
- package/dist/skills/definitions.d.ts.map +1 -0
- package/dist/skills/definitions.js +254 -0
- package/dist/skills/definitions.js.map +1 -0
- package/dist/skills/installer.d.ts +9 -0
- package/dist/skills/installer.d.ts.map +1 -0
- package/dist/skills/installer.js +42 -0
- package/dist/skills/installer.js.map +1 -0
- package/dist/types.d.ts +80 -7
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +1 -5
- package/dist/types.js.map +1 -1
- package/dist/utils/lark-upload.d.ts +2 -0
- package/dist/utils/lark-upload.d.ts.map +1 -0
- package/dist/utils/lark-upload.js +27 -0
- package/dist/utils/lark-upload.js.map +1 -0
- package/dist/utils/screen-analyzer.d.ts +67 -0
- package/dist/utils/screen-analyzer.d.ts.map +1 -0
- package/dist/utils/screen-analyzer.js +256 -0
- package/dist/utils/screen-analyzer.js.map +1 -0
- package/dist/utils/screenshot-renderer.d.ts +11 -0
- package/dist/utils/screenshot-renderer.d.ts.map +1 -0
- package/dist/utils/screenshot-renderer.js +225 -0
- package/dist/utils/screenshot-renderer.js.map +1 -0
- package/dist/utils/terminal-renderer.d.ts +33 -0
- package/dist/utils/terminal-renderer.d.ts.map +1 -1
- package/dist/utils/terminal-renderer.js +34 -1
- package/dist/utils/terminal-renderer.js.map +1 -1
- package/dist/utils/user-token.d.ts.map +1 -1
- package/dist/utils/user-token.js +7 -11
- package/dist/utils/user-token.js.map +1 -1
- package/dist/worker.js +286 -15
- package/dist/worker.js.map +1 -1
- package/package.json +2 -5
- package/dist/index.d.ts +0 -3
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -16
- package/dist/index.js.map +0 -1
- package/dist/server.d.ts +0 -3
- package/dist/server.d.ts.map +0 -1
- package/dist/server.js +0 -115
- package/dist/server.js.map +0 -1
- package/dist/tools/get-thread-messages.d.ts +0 -26
- package/dist/tools/get-thread-messages.d.ts.map +0 -1
- package/dist/tools/get-thread-messages.js +0 -35
- package/dist/tools/get-thread-messages.js.map +0 -1
- package/dist/tools/index.d.ts +0 -9
- package/dist/tools/index.d.ts.map +0 -1
- package/dist/tools/index.js +0 -10
- package/dist/tools/index.js.map +0 -1
- package/dist/tools/list-bots.d.ts +0 -40
- package/dist/tools/list-bots.d.ts.map +0 -1
- package/dist/tools/list-bots.js +0 -74
- package/dist/tools/list-bots.js.map +0 -1
- package/dist/tools/send-to-thread.d.ts +0 -46
- package/dist/tools/send-to-thread.d.ts.map +0 -1
- package/dist/tools/send-to-thread.js +0 -242
- package/dist/tools/send-to-thread.js.map +0 -1
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { writeFileSync, mkdirSync, existsSync, readFileSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { homedir } from 'node:os';
|
|
4
|
+
import { logger } from '../utils/logger.js';
|
|
5
|
+
import { BUILTIN_SKILLS } from './definitions.js';
|
|
6
|
+
function expandHome(p) {
|
|
7
|
+
return p.startsWith('~') ? join(homedir(), p.slice(1)) : p;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Install (or refresh) the built-in skill library into the given CLI's skills
|
|
11
|
+
* directory. Idempotent — only writes when content differs.
|
|
12
|
+
*
|
|
13
|
+
* Each skill becomes {skillsDir}/<name>/SKILL.md. Sub-directory layout
|
|
14
|
+
* matches Claude Code / Gemini / OpenCode convention.
|
|
15
|
+
*/
|
|
16
|
+
export function ensureSkills(cliId, skillsDir) {
|
|
17
|
+
if (!skillsDir)
|
|
18
|
+
return;
|
|
19
|
+
const dir = expandHome(skillsDir);
|
|
20
|
+
try {
|
|
21
|
+
mkdirSync(dir, { recursive: true });
|
|
22
|
+
}
|
|
23
|
+
catch { /* ignore */ }
|
|
24
|
+
for (const skill of BUILTIN_SKILLS) {
|
|
25
|
+
const skillDir = join(dir, skill.name);
|
|
26
|
+
const skillFile = join(skillDir, 'SKILL.md');
|
|
27
|
+
try {
|
|
28
|
+
if (existsSync(skillFile)) {
|
|
29
|
+
const current = readFileSync(skillFile, 'utf-8');
|
|
30
|
+
if (current === skill.content)
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
mkdirSync(skillDir, { recursive: true });
|
|
34
|
+
writeFileSync(skillFile, skill.content, 'utf-8');
|
|
35
|
+
logger.info(`[skills] Installed ${skill.name} for ${cliId} → ${skillFile}`);
|
|
36
|
+
}
|
|
37
|
+
catch (err) {
|
|
38
|
+
logger.warn(`[skills] Failed to install ${skill.name} for ${cliId}: ${err.message}`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=installer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"installer.js","sourceRoot":"","sources":["../../src/skills/installer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC7E,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAC5C,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAElD,SAAS,UAAU,CAAC,CAAS;IAC3B,OAAO,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC7D,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,YAAY,CAAC,KAAa,EAAE,SAA6B;IACvE,IAAI,CAAC,SAAS;QAAE,OAAO;IACvB,MAAM,GAAG,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC;IAClC,IAAI,CAAC;QAAC,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAAC,CAAC;IAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC;IAEnE,KAAK,MAAM,KAAK,IAAI,cAAc,EAAE,CAAC;QACnC,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QACvC,MAAM,SAAS,GAAG,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;QAC7C,IAAI,CAAC;YACH,IAAI,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;gBAC1B,MAAM,OAAO,GAAG,YAAY,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;gBACjD,IAAI,OAAO,KAAK,KAAK,CAAC,OAAO;oBAAE,SAAS;YAC1C,CAAC;YACD,SAAS,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YACzC,aAAa,CAAC,SAAS,EAAE,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YACjD,MAAM,CAAC,IAAI,CAAC,sBAAsB,KAAK,CAAC,IAAI,QAAQ,KAAK,MAAM,SAAS,EAAE,CAAC,CAAC;QAC9E,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAClB,MAAM,CAAC,IAAI,CAAC,8BAA8B,KAAK,CAAC,IAAI,QAAQ,KAAK,KAAK,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;QACvF,CAAC;IACH,CAAC;AACH,CAAC"}
|
package/dist/types.d.ts
CHANGED
|
@@ -12,6 +12,17 @@ export interface Session {
|
|
|
12
12
|
webPort?: number;
|
|
13
13
|
larkAppId?: string;
|
|
14
14
|
ownerOpenId?: string;
|
|
15
|
+
/** Persisted streaming-card state — allows the existing card to be PATCHed
|
|
16
|
+
* (rather than a fresh POST) after daemon restart. */
|
|
17
|
+
streamCardId?: string;
|
|
18
|
+
streamCardNonce?: string;
|
|
19
|
+
/** Legacy field kept for migrating sessions persisted before displayMode was added. */
|
|
20
|
+
streamExpanded?: boolean;
|
|
21
|
+
/** Card body display mode — 'hidden' | 'text' | 'screenshot'. */
|
|
22
|
+
displayMode?: DisplayMode;
|
|
23
|
+
/** Latest uploaded screenshot image_key, persisted so card can re-render after restart. */
|
|
24
|
+
currentImageKey?: string;
|
|
25
|
+
currentTurnTitle?: string;
|
|
15
26
|
/** Persisted adopt metadata — allows adopt sessions to survive daemon restarts. */
|
|
16
27
|
adoptedFrom?: {
|
|
17
28
|
tmuxTarget: string;
|
|
@@ -44,18 +55,57 @@ export interface LarkMessage {
|
|
|
44
55
|
attachments?: LarkAttachment[];
|
|
45
56
|
mentions?: LarkMention[];
|
|
46
57
|
}
|
|
58
|
+
/**
|
|
59
|
+
* Structured schedule form, computed once at creation time from the raw
|
|
60
|
+
* schedule string. Parsed form is authoritative for runtime computation;
|
|
61
|
+
* the raw string is kept only for display/reconfigure.
|
|
62
|
+
*/
|
|
63
|
+
export interface ParsedSchedule {
|
|
64
|
+
kind: 'once' | 'interval' | 'cron';
|
|
65
|
+
/** For 'once': ISO timestamp of run time */
|
|
66
|
+
runAt?: string;
|
|
67
|
+
/** For 'interval': recurrence minutes */
|
|
68
|
+
minutes?: number;
|
|
69
|
+
/** For 'cron': cron expression (5 fields, minute/hour/dom/month/dow) */
|
|
70
|
+
expr?: string;
|
|
71
|
+
/** Human-friendly display text */
|
|
72
|
+
display: string;
|
|
73
|
+
}
|
|
47
74
|
export interface ScheduledTask {
|
|
48
75
|
id: string;
|
|
49
76
|
name: string;
|
|
50
|
-
|
|
77
|
+
/** Raw user input (e.g. "每日17:50" or "30m" or "0 9 * * *") */
|
|
51
78
|
schedule: string;
|
|
79
|
+
/** Structured form — authoritative for runtime */
|
|
80
|
+
parsed: ParsedSchedule;
|
|
52
81
|
prompt: string;
|
|
53
82
|
workingDir: string;
|
|
54
83
|
chatId: string;
|
|
84
|
+
/** Root message id of the topic where the task was created. When set,
|
|
85
|
+
* execution replies into this thread instead of creating a new one. */
|
|
86
|
+
rootMessageId?: string;
|
|
87
|
+
chatType?: 'group' | 'p2p' | 'topic_group';
|
|
88
|
+
larkAppId?: string;
|
|
55
89
|
enabled: boolean;
|
|
56
90
|
createdAt: string;
|
|
57
91
|
lastRunAt?: string;
|
|
92
|
+
nextRunAt?: string;
|
|
93
|
+
lastStatus?: 'ok' | 'error';
|
|
94
|
+
lastError?: string;
|
|
95
|
+
lastDeliveryError?: string;
|
|
96
|
+
/** Repeat counter — times=null means forever; times>0 auto-removes after N runs */
|
|
97
|
+
repeat?: {
|
|
98
|
+
times: number | null;
|
|
99
|
+
completed: number;
|
|
100
|
+
};
|
|
101
|
+
/** Delivery target: 'origin' (original thread, default), 'local' (log only, no delivery) */
|
|
102
|
+
deliver?: 'origin' | 'local';
|
|
103
|
+
type?: 'cron' | 'interval' | 'once';
|
|
58
104
|
}
|
|
105
|
+
/** Display modes for the streaming card output. */
|
|
106
|
+
export type DisplayMode = 'hidden' | 'text' | 'screenshot';
|
|
107
|
+
/** Quick-action keys sent from card buttons to the worker's PTY/tmux backend. */
|
|
108
|
+
export type TermActionKey = 'esc' | 'ctrlc' | 'tab' | 'enter' | 'space' | 'up' | 'down' | 'left' | 'right' | 'half_page_up' | 'half_page_down';
|
|
59
109
|
/** Messages sent from Daemon to Worker */
|
|
60
110
|
export type DaemonToWorker = {
|
|
61
111
|
type: 'init';
|
|
@@ -83,6 +133,16 @@ export type DaemonToWorker = {
|
|
|
83
133
|
type: 'close';
|
|
84
134
|
} | {
|
|
85
135
|
type: 'restart';
|
|
136
|
+
} | {
|
|
137
|
+
type: 'tui_keys';
|
|
138
|
+
keys: string[];
|
|
139
|
+
isFinal: boolean;
|
|
140
|
+
} | {
|
|
141
|
+
type: 'set_display_mode';
|
|
142
|
+
mode: DisplayMode;
|
|
143
|
+
} | {
|
|
144
|
+
type: 'term_action';
|
|
145
|
+
key: TermActionKey;
|
|
86
146
|
};
|
|
87
147
|
/** Messages sent from Worker to Daemon */
|
|
88
148
|
export type WorkerToDaemon = {
|
|
@@ -98,14 +158,27 @@ export type WorkerToDaemon = {
|
|
|
98
158
|
} | {
|
|
99
159
|
type: 'screen_update';
|
|
100
160
|
content: string;
|
|
101
|
-
status: 'working' | 'idle';
|
|
161
|
+
status: 'working' | 'idle' | 'analyzing';
|
|
102
162
|
} | {
|
|
103
163
|
type: 'error';
|
|
104
164
|
message: string;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
165
|
+
} | {
|
|
166
|
+
type: 'tui_prompt';
|
|
167
|
+
description: string;
|
|
168
|
+
options: Array<{
|
|
169
|
+
label?: string;
|
|
170
|
+
text: string;
|
|
171
|
+
selected: boolean;
|
|
172
|
+
type?: string;
|
|
173
|
+
keys?: string[];
|
|
174
|
+
}>;
|
|
175
|
+
multiSelect?: boolean;
|
|
176
|
+
} | {
|
|
177
|
+
type: 'tui_prompt_resolved';
|
|
178
|
+
selectedText?: string;
|
|
179
|
+
} | {
|
|
180
|
+
type: 'screenshot_uploaded';
|
|
181
|
+
imageKey: string;
|
|
182
|
+
status: 'working' | 'idle' | 'analyzing';
|
|
110
183
|
};
|
|
111
184
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,OAAO;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,GAAG,KAAK,CAAC;IAC3B,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,QAAQ,GAAG,QAAQ,CAAC;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mFAAmF;IACnF,WAAW,CAAC,EAAE;QACZ,UAAU,EAAE,MAAM,CAAC;QACnB,cAAc,EAAE,MAAM,CAAC;QACvB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,GAAG,EAAE,MAAM,CAAC;QACZ,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,CAAC;CACH;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,OAAO,GAAG,MAAM,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,cAAc,EAAE,CAAC;IAC/B,QAAQ,CAAC,EAAE,WAAW,EAAE,CAAC;CAC1B;AAED,MAAM,WAAW,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
CHANGED
package/dist/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lark-upload.d.ts","sourceRoot":"","sources":["../../src/utils/lark-upload.ts"],"names":[],"mappings":"AAkBA,wBAAsB,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAQnG"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal Lark image uploader callable from worker process.
|
|
3
|
+
* Worker doesn't load bot-registry — it has LARK_APP_ID/LARK_APP_SECRET in env
|
|
4
|
+
* (see worker-pool.ts forkWorker).
|
|
5
|
+
*/
|
|
6
|
+
import { Client, LoggerLevel } from '@larksuiteoapi/node-sdk';
|
|
7
|
+
let cached = null;
|
|
8
|
+
function getClient(appId, secret) {
|
|
9
|
+
if (cached && cached.appId === appId)
|
|
10
|
+
return cached.client;
|
|
11
|
+
cached = {
|
|
12
|
+
appId,
|
|
13
|
+
client: new Client({ appId, appSecret: secret, loggerLevel: LoggerLevel.error }),
|
|
14
|
+
};
|
|
15
|
+
return cached.client;
|
|
16
|
+
}
|
|
17
|
+
export async function uploadImageBuffer(appId, secret, buf) {
|
|
18
|
+
const c = getClient(appId, secret);
|
|
19
|
+
const res = await c.im.v1.image.create({
|
|
20
|
+
data: { image_type: 'message', image: buf },
|
|
21
|
+
});
|
|
22
|
+
const key = res?.image_key;
|
|
23
|
+
if (!key)
|
|
24
|
+
throw new Error(`upload failed: ${JSON.stringify(res)}`);
|
|
25
|
+
return key;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=lark-upload.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lark-upload.js","sourceRoot":"","sources":["../../src/utils/lark-upload.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAE9D,IAAI,MAAM,GAA0C,IAAI,CAAC;AAEzD,SAAS,SAAS,CAAC,KAAa,EAAE,MAAc;IAC9C,IAAI,MAAM,IAAI,MAAM,CAAC,KAAK,KAAK,KAAK;QAAE,OAAO,MAAM,CAAC,MAAM,CAAC;IAC3D,MAAM,GAAG;QACP,KAAK;QACL,MAAM,EAAE,IAAI,MAAM,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,WAAW,CAAC,KAAK,EAAE,CAAC;KACjF,CAAC;IACF,OAAO,MAAM,CAAC,MAAM,CAAC;AACvB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,KAAa,EAAE,MAAc,EAAE,GAAW;IAChF,MAAM,CAAC,GAAG,SAAS,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IACnC,MAAM,GAAG,GAAG,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC;QACrC,IAAI,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,EAAE;KAC5C,CAAC,CAAC;IACH,MAAM,GAAG,GAAG,GAAG,EAAE,SAAS,CAAC;IAC3B,IAAI,CAAC,GAAG;QAAE,MAAM,IAAI,KAAK,CAAC,kBAAkB,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACnE,OAAO,GAAG,CAAC;AACb,CAAC"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI-powered screen analyzer — detects interactive TUI prompts in terminal output
|
|
3
|
+
* by sending snapshots to a lightweight LLM and parsing structured responses.
|
|
4
|
+
*
|
|
5
|
+
* Token-saving protocol:
|
|
6
|
+
* 1. Text diff — skip if snapshot unchanged
|
|
7
|
+
* 2. Cumulative stability — require N consecutive unchanged snapshots
|
|
8
|
+
* 3. AI-driven cooldown — AI returns checkAgainWhen to control re-call timing
|
|
9
|
+
* 4. Prompt-active guard — stop calling AI once a prompt is reported, until resolved
|
|
10
|
+
*/
|
|
11
|
+
export interface ScreenAnalyzerConfig {
|
|
12
|
+
baseUrl: string;
|
|
13
|
+
apiKey: string;
|
|
14
|
+
model: string;
|
|
15
|
+
intervalMs: number;
|
|
16
|
+
stableCount: number;
|
|
17
|
+
snapshotMaxChars: number;
|
|
18
|
+
extraHeaders?: Record<string, string>;
|
|
19
|
+
extraBody?: Record<string, unknown>;
|
|
20
|
+
}
|
|
21
|
+
export interface TuiPromptOption {
|
|
22
|
+
label: string;
|
|
23
|
+
text: string;
|
|
24
|
+
selected: boolean;
|
|
25
|
+
type: 'select' | 'toggle' | 'confirm' | 'input';
|
|
26
|
+
index: number;
|
|
27
|
+
}
|
|
28
|
+
export interface ScreenAnalysis {
|
|
29
|
+
needsInteraction: boolean;
|
|
30
|
+
description?: string;
|
|
31
|
+
options?: TuiPromptOption[];
|
|
32
|
+
multiSelect?: boolean;
|
|
33
|
+
toggleKey?: string;
|
|
34
|
+
confirmKey?: string;
|
|
35
|
+
checkAgainWhen: 'content_changed' | 'after_5s' | 'after_10s' | 'not_needed';
|
|
36
|
+
}
|
|
37
|
+
export interface ScreenAnalyzerCallbacks {
|
|
38
|
+
getSnapshot: () => string;
|
|
39
|
+
onAnalyzing: () => void;
|
|
40
|
+
onTuiPrompt: (description: string, options: TuiPromptOption[], multiSelect: boolean) => void;
|
|
41
|
+
onTuiPromptResolved: (selectedText?: string) => void;
|
|
42
|
+
log: (msg: string) => void;
|
|
43
|
+
}
|
|
44
|
+
export declare class ScreenAnalyzer {
|
|
45
|
+
private config;
|
|
46
|
+
private callbacks;
|
|
47
|
+
private timer;
|
|
48
|
+
private lastSnapshot;
|
|
49
|
+
private stableCount;
|
|
50
|
+
private lastAnalyzedSnapshot;
|
|
51
|
+
private waitingForContentChange;
|
|
52
|
+
private timerCooldownUntil;
|
|
53
|
+
private promptActive;
|
|
54
|
+
private _analyzing;
|
|
55
|
+
private disposed;
|
|
56
|
+
constructor(config: ScreenAnalyzerConfig, callbacks: ScreenAnalyzerCallbacks);
|
|
57
|
+
/** Whether an AI call is currently in flight */
|
|
58
|
+
get isAnalyzing(): boolean;
|
|
59
|
+
start(): void;
|
|
60
|
+
dispose(): void;
|
|
61
|
+
/** Called externally when user has made a selection via card click */
|
|
62
|
+
notifySelection(selectedText: string): void;
|
|
63
|
+
private tick;
|
|
64
|
+
private analyze;
|
|
65
|
+
private callAI;
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=screen-analyzer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"screen-analyzer.d.ts","sourceRoot":"","sources":["../../src/utils/screen-analyzer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,gBAAgB,EAAE,MAAM,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACrC;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,OAAO,CAAC;IAClB,IAAI,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,OAAO,CAAC;IAChD,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,cAAc;IAC7B,gBAAgB,EAAE,OAAO,CAAC;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,eAAe,EAAE,CAAC;IAC5B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,iBAAiB,GAAG,UAAU,GAAG,WAAW,GAAG,YAAY,CAAC;CAC7E;AAED,MAAM,WAAW,uBAAuB;IACtC,WAAW,EAAE,MAAM,MAAM,CAAC;IAC1B,WAAW,EAAE,MAAM,IAAI,CAAC;IACxB,WAAW,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,EAAE,EAAE,WAAW,EAAE,OAAO,KAAK,IAAI,CAAC;IAC7F,mBAAmB,EAAE,CAAC,YAAY,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IACrD,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CAC5B;AA8CD,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,SAAS,CAA0B;IAC3C,OAAO,CAAC,KAAK,CAA+C;IAG5D,OAAO,CAAC,YAAY,CAAM;IAC1B,OAAO,CAAC,WAAW,CAAK;IAGxB,OAAO,CAAC,oBAAoB,CAAM;IAClC,OAAO,CAAC,uBAAuB,CAAS;IACxC,OAAO,CAAC,kBAAkB,CAAK;IAG/B,OAAO,CAAC,YAAY,CAAS;IAG7B,OAAO,CAAC,UAAU,CAAS;IAG3B,OAAO,CAAC,QAAQ,CAAS;gBAEb,MAAM,EAAE,oBAAoB,EAAE,SAAS,EAAE,uBAAuB;IAK5E,gDAAgD;IAChD,IAAI,WAAW,IAAI,OAAO,CAA4B;IAEtD,KAAK,IAAI,IAAI;IAMb,OAAO,IAAI,IAAI;IAQf,sEAAsE;IACtE,eAAe,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI;YAU7B,IAAI;YA0CJ,OAAO;YAqDP,MAAM;CA6DrB"}
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI-powered screen analyzer — detects interactive TUI prompts in terminal output
|
|
3
|
+
* by sending snapshots to a lightweight LLM and parsing structured responses.
|
|
4
|
+
*
|
|
5
|
+
* Token-saving protocol:
|
|
6
|
+
* 1. Text diff — skip if snapshot unchanged
|
|
7
|
+
* 2. Cumulative stability — require N consecutive unchanged snapshots
|
|
8
|
+
* 3. AI-driven cooldown — AI returns checkAgainWhen to control re-call timing
|
|
9
|
+
* 4. Prompt-active guard — stop calling AI once a prompt is reported, until resolved
|
|
10
|
+
*/
|
|
11
|
+
const SYSTEM_PROMPT = `You are a terminal screen analyzer. Analyze the terminal screenshot and determine if the CLI is showing a **blocking interactive prompt** that requires the user to make a selection before the CLI can proceed.
|
|
12
|
+
|
|
13
|
+
A BLOCKING interactive prompt looks like:
|
|
14
|
+
- A modal dialog with numbered options and a cursor (❯ or >) pointing to the selected option
|
|
15
|
+
- Examples: "Resume from summary / Resume full session / Don't ask me again", "Yes / No / Cancel"
|
|
16
|
+
- The CLI cannot proceed until the user selects an option
|
|
17
|
+
|
|
18
|
+
The following are NOT interactive prompts (return needsInteraction=false):
|
|
19
|
+
- Status bar text like "bypass permissions (shift+tab to cycle)" — this is a persistent status indicator, not a blocking prompt
|
|
20
|
+
- CLI idle state showing an input cursor (❯) waiting for the user to type a message — this is normal operation
|
|
21
|
+
- Progress indicators, spinners, or loading animations
|
|
22
|
+
- Error messages or informational output
|
|
23
|
+
- Any text that is part of the CLI's normal UI chrome (toolbars, status bars, mode indicators)
|
|
24
|
+
|
|
25
|
+
Return ONLY valid JSON (no markdown, no extra text):
|
|
26
|
+
{
|
|
27
|
+
"needsInteraction": boolean,
|
|
28
|
+
"description": "what is being asked",
|
|
29
|
+
"options": [{"label": "1", "text": "option text", "type": "select", "index": 0}],
|
|
30
|
+
"multiSelect": false,
|
|
31
|
+
"toggleKey": "Space",
|
|
32
|
+
"confirmKey": "Enter",
|
|
33
|
+
"checkAgainWhen": "content_changed" | "after_5s" | "after_10s" | "not_needed"
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
For each option:
|
|
37
|
+
- label: exact label shown in TUI. If none, use sequential numbers.
|
|
38
|
+
- text: full option text
|
|
39
|
+
- type: "select" (single pick), "toggle" (multi-select checkbox), "confirm" (submit/next/done), "input" (free text like "Type something")
|
|
40
|
+
- index: the 0-based position of this option in the list (0 = first navigable item, 1 = second, etc.). Count ALL navigable items from top to bottom in order, including submit/next buttons. DO NOT count non-interactive lines like descriptions or separators.
|
|
41
|
+
|
|
42
|
+
toggleKey: the key used to toggle a checkbox item. Read the hint line at the bottom (e.g. "Space to toggle", "Enter to select"). Default "Space".
|
|
43
|
+
confirmKey: the key used to confirm/submit. Usually "Enter".
|
|
44
|
+
multiSelect: true if checkboxes ([ ]/[✓]/[✗], "可多选"), false for single-select (❯ cursor).
|
|
45
|
+
|
|
46
|
+
Important: "index" is the COUNT of ↓ presses needed to reach this option from the FIRST option (index 0). The first option is always index 0.
|
|
47
|
+
|
|
48
|
+
Rules for checkAgainWhen:
|
|
49
|
+
- "content_changed": call again when content changes
|
|
50
|
+
- "after_5s" or "after_10s": check back after a delay
|
|
51
|
+
- "not_needed": CLI is working normally or idle — don't call until content changes substantially
|
|
52
|
+
|
|
53
|
+
If needsInteraction is false, omit description and options fields.`;
|
|
54
|
+
export class ScreenAnalyzer {
|
|
55
|
+
config;
|
|
56
|
+
callbacks;
|
|
57
|
+
timer = null;
|
|
58
|
+
// Stability tracking
|
|
59
|
+
lastSnapshot = '';
|
|
60
|
+
stableCount = 0;
|
|
61
|
+
// AI-driven cooldown
|
|
62
|
+
lastAnalyzedSnapshot = '';
|
|
63
|
+
waitingForContentChange = false;
|
|
64
|
+
timerCooldownUntil = 0;
|
|
65
|
+
// Prompt state
|
|
66
|
+
promptActive = false;
|
|
67
|
+
// Concurrency guard — prevent overlapping AI calls
|
|
68
|
+
_analyzing = false;
|
|
69
|
+
// Disposed flag
|
|
70
|
+
disposed = false;
|
|
71
|
+
constructor(config, callbacks) {
|
|
72
|
+
this.config = config;
|
|
73
|
+
this.callbacks = callbacks;
|
|
74
|
+
}
|
|
75
|
+
/** Whether an AI call is currently in flight */
|
|
76
|
+
get isAnalyzing() { return this._analyzing; }
|
|
77
|
+
start() {
|
|
78
|
+
if (this.timer)
|
|
79
|
+
return;
|
|
80
|
+
this.timer = setInterval(() => this.tick(), this.config.intervalMs);
|
|
81
|
+
this.callbacks.log('ScreenAnalyzer started');
|
|
82
|
+
}
|
|
83
|
+
dispose() {
|
|
84
|
+
this.disposed = true;
|
|
85
|
+
if (this.timer) {
|
|
86
|
+
clearInterval(this.timer);
|
|
87
|
+
this.timer = null;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
/** Called externally when user has made a selection via card click */
|
|
91
|
+
notifySelection(selectedText) {
|
|
92
|
+
this.promptActive = false;
|
|
93
|
+
// Reset all cooldowns so we check again soon to confirm prompt is gone
|
|
94
|
+
this.waitingForContentChange = false;
|
|
95
|
+
this.timerCooldownUntil = 0;
|
|
96
|
+
this.stableCount = 0;
|
|
97
|
+
this.lastSnapshot = '';
|
|
98
|
+
this.callbacks.log(`ScreenAnalyzer: selection made — "${selectedText}"`);
|
|
99
|
+
}
|
|
100
|
+
async tick() {
|
|
101
|
+
if (this.disposed)
|
|
102
|
+
return;
|
|
103
|
+
// Don't call AI while a prompt is active — we already notified Daemon.
|
|
104
|
+
if (this.promptActive)
|
|
105
|
+
return;
|
|
106
|
+
// Don't overlap AI calls
|
|
107
|
+
if (this._analyzing)
|
|
108
|
+
return;
|
|
109
|
+
// Layer 1: Text diff — get current snapshot
|
|
110
|
+
const snapshot = this.callbacks.getSnapshot();
|
|
111
|
+
if (!snapshot)
|
|
112
|
+
return;
|
|
113
|
+
const truncated = snapshot.length > this.config.snapshotMaxChars
|
|
114
|
+
? snapshot.slice(-this.config.snapshotMaxChars)
|
|
115
|
+
: snapshot;
|
|
116
|
+
if (truncated === this.lastSnapshot) {
|
|
117
|
+
this.stableCount++;
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
this.stableCount = 1;
|
|
121
|
+
this.lastSnapshot = truncated;
|
|
122
|
+
if (this.waitingForContentChange) {
|
|
123
|
+
this.waitingForContentChange = false;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
// Layer 2: Cumulative stability — require N consecutive unchanged snapshots
|
|
127
|
+
if (this.stableCount < this.config.stableCount)
|
|
128
|
+
return;
|
|
129
|
+
// Layer 3: AI-driven cooldown
|
|
130
|
+
if (this.waitingForContentChange && truncated === this.lastAnalyzedSnapshot)
|
|
131
|
+
return;
|
|
132
|
+
if (this.timerCooldownUntil > Date.now())
|
|
133
|
+
return;
|
|
134
|
+
// All layers passed — call AI
|
|
135
|
+
this._analyzing = true;
|
|
136
|
+
this.callbacks.onAnalyzing();
|
|
137
|
+
try {
|
|
138
|
+
await this.analyze(truncated);
|
|
139
|
+
}
|
|
140
|
+
finally {
|
|
141
|
+
this._analyzing = false;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
async analyze(snapshot) {
|
|
145
|
+
this.lastAnalyzedSnapshot = snapshot;
|
|
146
|
+
let analysis;
|
|
147
|
+
try {
|
|
148
|
+
analysis = await this.callAI(snapshot);
|
|
149
|
+
}
|
|
150
|
+
catch (err) {
|
|
151
|
+
this.callbacks.log(`ScreenAnalyzer AI call failed: ${err.message}`);
|
|
152
|
+
this.waitingForContentChange = true;
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
// Apply checkAgainWhen
|
|
156
|
+
switch (analysis.checkAgainWhen) {
|
|
157
|
+
case 'content_changed':
|
|
158
|
+
case 'not_needed':
|
|
159
|
+
this.waitingForContentChange = true;
|
|
160
|
+
break;
|
|
161
|
+
case 'after_5s':
|
|
162
|
+
this.timerCooldownUntil = Date.now() + 5_000;
|
|
163
|
+
this.waitingForContentChange = false;
|
|
164
|
+
break;
|
|
165
|
+
case 'after_10s':
|
|
166
|
+
this.timerCooldownUntil = Date.now() + 10_000;
|
|
167
|
+
this.waitingForContentChange = false;
|
|
168
|
+
break;
|
|
169
|
+
}
|
|
170
|
+
if (analysis.needsInteraction && analysis.options && analysis.options.length > 0) {
|
|
171
|
+
// Generate keys deterministically in code, using AI-provided index + toggleKey/confirmKey
|
|
172
|
+
const toggleKey = analysis.toggleKey || 'Space';
|
|
173
|
+
const confirmKey = analysis.confirmKey || 'Enter';
|
|
174
|
+
for (const opt of analysis.options) {
|
|
175
|
+
const keys = [];
|
|
176
|
+
for (let i = 0; i < opt.index; i++)
|
|
177
|
+
keys.push('Down');
|
|
178
|
+
if (opt.type === 'toggle') {
|
|
179
|
+
keys.push(toggleKey);
|
|
180
|
+
// Return to top for next toggle
|
|
181
|
+
for (let i = 0; i < opt.index; i++)
|
|
182
|
+
keys.push('Up');
|
|
183
|
+
}
|
|
184
|
+
else if (opt.type === 'select' || opt.type === 'confirm') {
|
|
185
|
+
keys.push(confirmKey);
|
|
186
|
+
}
|
|
187
|
+
else if (opt.type === 'input') {
|
|
188
|
+
keys.push(confirmKey); // select the input option
|
|
189
|
+
}
|
|
190
|
+
opt.keys = keys;
|
|
191
|
+
}
|
|
192
|
+
this.promptActive = true;
|
|
193
|
+
this.callbacks.onTuiPrompt(analysis.description ?? 'CLI needs your selection', analysis.options, !!analysis.multiSelect);
|
|
194
|
+
this.callbacks.log(`ScreenAnalyzer: TUI prompt detected — ${analysis.description}${analysis.multiSelect ? ' (multi-select)' : ''} [toggleKey=${toggleKey}, confirmKey=${confirmKey}]`);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
async callAI(snapshot) {
|
|
198
|
+
const url = `${this.config.baseUrl.replace(/\/+$/, '')}/chat/completions`;
|
|
199
|
+
const body = {
|
|
200
|
+
model: this.config.model,
|
|
201
|
+
messages: [
|
|
202
|
+
{ role: 'system', content: SYSTEM_PROMPT },
|
|
203
|
+
{ role: 'user', content: snapshot },
|
|
204
|
+
],
|
|
205
|
+
temperature: 0,
|
|
206
|
+
max_tokens: 2048,
|
|
207
|
+
// Extra body params from config (e.g. { thinking: { type: "disabled" } } for Ark)
|
|
208
|
+
...(this.config.extraBody ?? {}),
|
|
209
|
+
};
|
|
210
|
+
const resp = await fetch(url, {
|
|
211
|
+
method: 'POST',
|
|
212
|
+
headers: {
|
|
213
|
+
'Content-Type': 'application/json',
|
|
214
|
+
'Authorization': `Bearer ${this.config.apiKey}`,
|
|
215
|
+
...(this.config.extraHeaders ?? {}),
|
|
216
|
+
},
|
|
217
|
+
body: JSON.stringify(body),
|
|
218
|
+
signal: AbortSignal.timeout(15_000),
|
|
219
|
+
});
|
|
220
|
+
if (!resp.ok) {
|
|
221
|
+
const text = await resp.text().catch(() => '');
|
|
222
|
+
throw new Error(`AI API ${resp.status}: ${text.slice(0, 200)}`);
|
|
223
|
+
}
|
|
224
|
+
const data = await resp.json();
|
|
225
|
+
const content = data?.choices?.[0]?.message?.content ?? '';
|
|
226
|
+
// Parse JSON from response — handle potential markdown wrapping
|
|
227
|
+
const jsonStr = content.replace(/^```json?\s*/, '').replace(/\s*```$/, '').trim();
|
|
228
|
+
try {
|
|
229
|
+
const parsed = JSON.parse(jsonStr);
|
|
230
|
+
return {
|
|
231
|
+
needsInteraction: !!parsed.needsInteraction,
|
|
232
|
+
description: parsed.description,
|
|
233
|
+
multiSelect: !!parsed.multiSelect,
|
|
234
|
+
toggleKey: parsed.toggleKey || 'Space',
|
|
235
|
+
confirmKey: parsed.confirmKey || 'Enter',
|
|
236
|
+
options: Array.isArray(parsed.options)
|
|
237
|
+
? parsed.options.map((o, i) => ({
|
|
238
|
+
label: o.label || String(i + 1),
|
|
239
|
+
// Clean text: collapse newlines/multi-line descriptions into single line
|
|
240
|
+
text: (o.text || '').replace(/\n+/g, ' ').trim(),
|
|
241
|
+
selected: !!o.selected,
|
|
242
|
+
type: (['select', 'toggle', 'confirm', 'input'].includes(o.type) ? o.type : 'select'),
|
|
243
|
+
index: typeof o.index === 'number' ? o.index : i,
|
|
244
|
+
}))
|
|
245
|
+
: undefined,
|
|
246
|
+
checkAgainWhen: ['content_changed', 'after_5s', 'after_10s', 'not_needed'].includes(parsed.checkAgainWhen)
|
|
247
|
+
? parsed.checkAgainWhen
|
|
248
|
+
: 'content_changed',
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
catch {
|
|
252
|
+
throw new Error(`Failed to parse AI response as JSON: ${jsonStr.slice(0, 200)}`);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
//# sourceMappingURL=screen-analyzer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"screen-analyzer.js","sourceRoot":"","sources":["../../src/utils/screen-analyzer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import xtermHeadless from '@xterm/headless';
|
|
2
|
+
type Terminal = InstanceType<typeof xtermHeadless.Terminal>;
|
|
3
|
+
export interface CaptureOpts {
|
|
4
|
+
cols: number;
|
|
5
|
+
rows: number;
|
|
6
|
+
startY: number;
|
|
7
|
+
}
|
|
8
|
+
/** Capture a section of the terminal buffer to a PNG buffer. */
|
|
9
|
+
export declare function captureToPng(terminal: Terminal, opts: CaptureOpts): Buffer;
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=screenshot-renderer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"screenshot-renderer.d.ts","sourceRoot":"","sources":["../../src/utils/screenshot-renderer.ts"],"names":[],"mappings":"AASA,OAAO,aAAa,MAAM,iBAAiB,CAAC;AAC5C,KAAK,QAAQ,GAAG,YAAY,CAAC,OAAO,aAAa,CAAC,QAAQ,CAAC,CAAC;AAuJ5D,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,gEAAgE;AAChE,wBAAgB,YAAY,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,GAAG,MAAM,CAqE1E"}
|