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.
Files changed (126) hide show
  1. package/README.en.md +63 -13
  2. package/README.md +52 -14
  3. package/dist/adapters/cli/aiden.d.ts.map +1 -1
  4. package/dist/adapters/cli/aiden.js +0 -40
  5. package/dist/adapters/cli/aiden.js.map +1 -1
  6. package/dist/adapters/cli/claude-code.d.ts.map +1 -1
  7. package/dist/adapters/cli/claude-code.js +27 -63
  8. package/dist/adapters/cli/claude-code.js.map +1 -1
  9. package/dist/adapters/cli/coco.d.ts.map +1 -1
  10. package/dist/adapters/cli/coco.js +0 -33
  11. package/dist/adapters/cli/coco.js.map +1 -1
  12. package/dist/adapters/cli/codex.d.ts.map +1 -1
  13. package/dist/adapters/cli/codex.js +0 -27
  14. package/dist/adapters/cli/codex.js.map +1 -1
  15. package/dist/adapters/cli/gemini.d.ts.map +1 -1
  16. package/dist/adapters/cli/gemini.js +1 -29
  17. package/dist/adapters/cli/gemini.js.map +1 -1
  18. package/dist/adapters/cli/opencode.d.ts.map +1 -1
  19. package/dist/adapters/cli/opencode.js +1 -44
  20. package/dist/adapters/cli/opencode.js.map +1 -1
  21. package/dist/adapters/cli/types.d.ts +15 -8
  22. package/dist/adapters/cli/types.d.ts.map +1 -1
  23. package/dist/cli.js +737 -16
  24. package/dist/cli.js.map +1 -1
  25. package/dist/config.d.ts +16 -0
  26. package/dist/config.d.ts.map +1 -1
  27. package/dist/config.js +30 -0
  28. package/dist/config.js.map +1 -1
  29. package/dist/core/command-handler.d.ts.map +1 -1
  30. package/dist/core/command-handler.js +8 -4
  31. package/dist/core/command-handler.js.map +1 -1
  32. package/dist/core/scheduler.d.ts +38 -16
  33. package/dist/core/scheduler.d.ts.map +1 -1
  34. package/dist/core/scheduler.js +335 -149
  35. package/dist/core/scheduler.js.map +1 -1
  36. package/dist/core/session-manager.d.ts +13 -2
  37. package/dist/core/session-manager.d.ts.map +1 -1
  38. package/dist/core/session-manager.js +128 -25
  39. package/dist/core/session-manager.js.map +1 -1
  40. package/dist/core/types.d.ts +26 -4
  41. package/dist/core/types.d.ts.map +1 -1
  42. package/dist/core/types.js +6 -0
  43. package/dist/core/types.js.map +1 -1
  44. package/dist/core/worker-pool.d.ts +15 -3
  45. package/dist/core/worker-pool.d.ts.map +1 -1
  46. package/dist/core/worker-pool.js +233 -31
  47. package/dist/core/worker-pool.js.map +1 -1
  48. package/dist/daemon.d.ts.map +1 -1
  49. package/dist/daemon.js +71 -18
  50. package/dist/daemon.js.map +1 -1
  51. package/dist/im/lark/card-builder.d.ts +29 -1
  52. package/dist/im/lark/card-builder.d.ts.map +1 -1
  53. package/dist/im/lark/card-builder.js +266 -56
  54. package/dist/im/lark/card-builder.js.map +1 -1
  55. package/dist/im/lark/card-handler.d.ts +1 -0
  56. package/dist/im/lark/card-handler.d.ts.map +1 -1
  57. package/dist/im/lark/card-handler.js +200 -40
  58. package/dist/im/lark/card-handler.js.map +1 -1
  59. package/dist/im/lark/client.d.ts.map +1 -1
  60. package/dist/im/lark/client.js +4 -3
  61. package/dist/im/lark/client.js.map +1 -1
  62. package/dist/im/lark/message-parser.d.ts.map +1 -1
  63. package/dist/im/lark/message-parser.js +44 -6
  64. package/dist/im/lark/message-parser.js.map +1 -1
  65. package/dist/services/schedule-store.d.ts +20 -3
  66. package/dist/services/schedule-store.d.ts.map +1 -1
  67. package/dist/services/schedule-store.js +140 -16
  68. package/dist/services/schedule-store.js.map +1 -1
  69. package/dist/skills/definitions.d.ts +17 -0
  70. package/dist/skills/definitions.d.ts.map +1 -0
  71. package/dist/skills/definitions.js +254 -0
  72. package/dist/skills/definitions.js.map +1 -0
  73. package/dist/skills/installer.d.ts +9 -0
  74. package/dist/skills/installer.d.ts.map +1 -0
  75. package/dist/skills/installer.js +42 -0
  76. package/dist/skills/installer.js.map +1 -0
  77. package/dist/types.d.ts +80 -7
  78. package/dist/types.d.ts.map +1 -1
  79. package/dist/types.js +1 -5
  80. package/dist/types.js.map +1 -1
  81. package/dist/utils/lark-upload.d.ts +2 -0
  82. package/dist/utils/lark-upload.d.ts.map +1 -0
  83. package/dist/utils/lark-upload.js +27 -0
  84. package/dist/utils/lark-upload.js.map +1 -0
  85. package/dist/utils/screen-analyzer.d.ts +67 -0
  86. package/dist/utils/screen-analyzer.d.ts.map +1 -0
  87. package/dist/utils/screen-analyzer.js +256 -0
  88. package/dist/utils/screen-analyzer.js.map +1 -0
  89. package/dist/utils/screenshot-renderer.d.ts +11 -0
  90. package/dist/utils/screenshot-renderer.d.ts.map +1 -0
  91. package/dist/utils/screenshot-renderer.js +225 -0
  92. package/dist/utils/screenshot-renderer.js.map +1 -0
  93. package/dist/utils/terminal-renderer.d.ts +33 -0
  94. package/dist/utils/terminal-renderer.d.ts.map +1 -1
  95. package/dist/utils/terminal-renderer.js +34 -1
  96. package/dist/utils/terminal-renderer.js.map +1 -1
  97. package/dist/utils/user-token.d.ts.map +1 -1
  98. package/dist/utils/user-token.js +7 -11
  99. package/dist/utils/user-token.js.map +1 -1
  100. package/dist/worker.js +286 -15
  101. package/dist/worker.js.map +1 -1
  102. package/package.json +2 -5
  103. package/dist/index.d.ts +0 -3
  104. package/dist/index.d.ts.map +0 -1
  105. package/dist/index.js +0 -16
  106. package/dist/index.js.map +0 -1
  107. package/dist/server.d.ts +0 -3
  108. package/dist/server.d.ts.map +0 -1
  109. package/dist/server.js +0 -115
  110. package/dist/server.js.map +0 -1
  111. package/dist/tools/get-thread-messages.d.ts +0 -26
  112. package/dist/tools/get-thread-messages.d.ts.map +0 -1
  113. package/dist/tools/get-thread-messages.js +0 -35
  114. package/dist/tools/get-thread-messages.js.map +0 -1
  115. package/dist/tools/index.d.ts +0 -9
  116. package/dist/tools/index.d.ts.map +0 -1
  117. package/dist/tools/index.js +0 -10
  118. package/dist/tools/index.js.map +0 -1
  119. package/dist/tools/list-bots.d.ts +0 -40
  120. package/dist/tools/list-bots.d.ts.map +0 -1
  121. package/dist/tools/list-bots.js +0 -74
  122. package/dist/tools/list-bots.js.map +0 -1
  123. package/dist/tools/send-to-thread.d.ts +0 -46
  124. package/dist/tools/send-to-thread.d.ts.map +0 -1
  125. package/dist/tools/send-to-thread.js +0 -242
  126. 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
- type: 'cron' | 'interval' | 'once';
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
- export declare const TOOL_NAMES: {
107
- readonly SEND_TO_THREAD: "send_to_thread";
108
- readonly GET_THREAD_MESSAGES: "get_thread_messages";
109
- readonly LIST_BOTS: "list_bots";
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
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js CHANGED
@@ -1,6 +1,2 @@
1
- export const TOOL_NAMES = {
2
- SEND_TO_THREAD: 'send_to_thread',
3
- GET_THREAD_MESSAGES: 'get_thread_messages',
4
- LIST_BOTS: 'list_bots',
5
- };
1
+ export {};
6
2
  //# sourceMappingURL=types.js.map
package/dist/types.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAgFA,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,cAAc,EAAE,gBAAgB;IAChC,mBAAmB,EAAE,qBAAqB;IAE1C,SAAS,EAAE,WAAW;CACd,CAAC"}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ export declare function uploadImageBuffer(appId: string, secret: string, buf: Buffer): Promise<string>;
2
+ //# sourceMappingURL=lark-upload.d.ts.map
@@ -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"}