botmux 2.25.1 → 2.27.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 +48 -46
- package/README.md +47 -46
- package/dist/adapters/backend/session-backend-selector.d.ts +11 -0
- package/dist/adapters/backend/session-backend-selector.d.ts.map +1 -0
- package/dist/adapters/backend/session-backend-selector.js +26 -0
- package/dist/adapters/backend/session-backend-selector.js.map +1 -0
- package/dist/adapters/backend/tmux-pipe-backend.d.ts +55 -15
- package/dist/adapters/backend/tmux-pipe-backend.d.ts.map +1 -1
- package/dist/adapters/backend/tmux-pipe-backend.js +163 -21
- package/dist/adapters/backend/tmux-pipe-backend.js.map +1 -1
- package/dist/adapters/cli/claude-code.d.ts.map +1 -1
- package/dist/adapters/cli/claude-code.js +90 -14
- package/dist/adapters/cli/claude-code.js.map +1 -1
- package/dist/cli.js +259 -40
- package/dist/cli.js.map +1 -1
- package/dist/setup/bots-store.d.ts +3 -0
- package/dist/setup/bots-store.d.ts.map +1 -0
- package/dist/setup/bots-store.js +24 -0
- package/dist/setup/bots-store.js.map +1 -0
- package/dist/setup/lark-scopes.json +301 -0
- package/dist/setup/register-app.d.ts +46 -0
- package/dist/setup/register-app.d.ts.map +1 -0
- package/dist/setup/register-app.js +87 -0
- package/dist/setup/register-app.js.map +1 -0
- package/dist/setup/verify-permissions.d.ts +115 -0
- package/dist/setup/verify-permissions.d.ts.map +1 -0
- package/dist/setup/verify-permissions.js +207 -0
- package/dist/setup/verify-permissions.js.map +1 -0
- package/dist/utils/screenshot-renderer.d.ts.map +1 -1
- package/dist/utils/screenshot-renderer.js +63 -26
- package/dist/utils/screenshot-renderer.js.map +1 -1
- package/dist/utils/terminal-renderer.d.ts +16 -0
- package/dist/utils/terminal-renderer.d.ts.map +1 -1
- package/dist/utils/terminal-renderer.js +35 -21
- package/dist/utils/terminal-renderer.js.map +1 -1
- package/dist/utils/transient-snapshot.d.ts +28 -0
- package/dist/utils/transient-snapshot.d.ts.map +1 -0
- package/dist/utils/transient-snapshot.js +96 -0
- package/dist/utils/transient-snapshot.js.map +1 -0
- package/dist/worker.js +94 -31
- package/dist/worker.js.map +1 -1
- package/package.json +5 -3
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 凭证 + 权限自检. 不阻塞 setup / daemon 启动, 任意失败都降级到"打印剩余步骤".
|
|
3
|
+
*
|
|
4
|
+
* 主路径只用:
|
|
5
|
+
* - {@link validateCredentials} —— 取一次 `tenant_access_token`, 通过才认为
|
|
6
|
+
* AppID/Secret 有效. 没拿到才会让 setup 失败 (拒绝写 bots.json).
|
|
7
|
+
*
|
|
8
|
+
* 仅作为可选 helper, **未启用于 setup / start 主链路**:
|
|
9
|
+
* - {@link checkRequiredScopes} —— 调 `application.v6.scope.list` 比对 botmux
|
|
10
|
+
* 需要的 scope. 待 spike 用真实/可复现 mock 证明 grant_status 闭环后再启用.
|
|
11
|
+
* - {@link applyScopesUnverified} —— 调 `application.v6.scope.apply` 触发管理
|
|
12
|
+
* 员审批. Lark 文档表明它只能提交"已声明但未授权"的 scope, 不能给 manifest
|
|
13
|
+
* 加新 scope, 所以无法绕开"用户去开放平台勾"这步; 同样待 spike 后启用.
|
|
14
|
+
*
|
|
15
|
+
* 安全约束:
|
|
16
|
+
* - Secret 永远不进 console / 日志 / 错误链
|
|
17
|
+
* - 网络/接口错误一律返回结构化结果, 不抛
|
|
18
|
+
*/
|
|
19
|
+
import * as Lark from '@larksuiteoapi/node-sdk';
|
|
20
|
+
/**
|
|
21
|
+
* botmux 运行所需的 scope. 这里**只用于检测/提示**, 不用于自动申请——飞书
|
|
22
|
+
* `scope.apply` 只能提交"已声明但未授权"的, 没法给应用 manifest 加新声明.
|
|
23
|
+
* scope 选择必须用户去开放平台勾.
|
|
24
|
+
*/
|
|
25
|
+
export const BOTMUX_REQUIRED_SCOPES = [
|
|
26
|
+
{ name: 'im:message', desc: '收发消息', critical: true },
|
|
27
|
+
{ name: 'im:message.group_at_msg', desc: '群消息接收', critical: true },
|
|
28
|
+
{ name: 'im:resource', desc: '消息附件下载', critical: true },
|
|
29
|
+
{ name: 'im:chat', desc: '群信息读取', critical: true },
|
|
30
|
+
{ name: 'contact:user.base:readonly', desc: '用户基本信息', critical: true },
|
|
31
|
+
{ name: 'im:message.group_at_msg.include_bot:readonly', desc: '跨 bot @ 事件', critical: false },
|
|
32
|
+
{ name: 'application:application:self_manage', desc: '应用自查 (免审批)', critical: false },
|
|
33
|
+
];
|
|
34
|
+
export function buildScopeDeepLink(appId, scopeName, brand = 'feishu') {
|
|
35
|
+
const host = brand === 'lark' ? 'open.larksuite.com' : 'open.feishu.cn';
|
|
36
|
+
return `https://${host}/app/${appId}/auth?q=${encodeURIComponent(scopeName)}&op_from=openapi&token_type=tenant`;
|
|
37
|
+
}
|
|
38
|
+
export function buildEventSubDeepLink(appId, brand = 'feishu') {
|
|
39
|
+
const host = brand === 'lark' ? 'open.larksuite.com' : 'open.feishu.cn';
|
|
40
|
+
return `https://${host}/app/${appId}/dev-config/event-sub`;
|
|
41
|
+
}
|
|
42
|
+
export function buildAppHomeDeepLink(appId, brand = 'feishu') {
|
|
43
|
+
const host = brand === 'lark' ? 'open.larksuite.com' : 'open.feishu.cn';
|
|
44
|
+
return `https://${host}/app/${appId}`;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* 用 AppID/Secret 取一次 tenant_access_token, 验证凭证可用.
|
|
48
|
+
*
|
|
49
|
+
* Secret 不进 error.message: 错误信息只来自飞书返回的 msg 字段或 axios 错误类型.
|
|
50
|
+
*
|
|
51
|
+
* Codex review #3: 加 AbortController + 总超时. 网络半挂时 `botmux setup` /
|
|
52
|
+
* `botmux start` 不能无限卡住; 超时归类为 network, 这样 setup 走"凭证校验失败
|
|
53
|
+
* 不写盘" 路径, start 走"network 只 WARN 继续"路径.
|
|
54
|
+
*/
|
|
55
|
+
export async function validateCredentials(appId, appSecret, brand = 'feishu', opts = {}) {
|
|
56
|
+
const budgetMs = opts.budgetMs ?? 10_000;
|
|
57
|
+
const host = brand === 'lark' ? 'open.larksuite.com' : 'open.feishu.cn';
|
|
58
|
+
const url = `https://${host}/open-apis/auth/v3/tenant_access_token/internal`;
|
|
59
|
+
// 自家 AbortController 控制总超时; 同时把上层传进来的 signal 也接上.
|
|
60
|
+
const ac = new AbortController();
|
|
61
|
+
const timer = setTimeout(() => ac.abort(), budgetMs);
|
|
62
|
+
if (opts.signal) {
|
|
63
|
+
if (opts.signal.aborted)
|
|
64
|
+
ac.abort();
|
|
65
|
+
else
|
|
66
|
+
opts.signal.addEventListener('abort', () => ac.abort(), { once: true });
|
|
67
|
+
}
|
|
68
|
+
// Codex review v2 follow-up: timer 必须覆盖 res.json() 阶段, 否则飞书极端半挂
|
|
69
|
+
// (body 半 chunk 后服务端不再发) 仍会卡住. clearTimeout 推迟到 JSON 解析之后.
|
|
70
|
+
let res;
|
|
71
|
+
let body;
|
|
72
|
+
try {
|
|
73
|
+
res = await fetch(url, {
|
|
74
|
+
method: 'POST',
|
|
75
|
+
headers: { 'Content-Type': 'application/json' },
|
|
76
|
+
// 注意: 这是飞书唯一接受 appSecret 的端点; 其它端点全部用 token. 不要把
|
|
77
|
+
// secret 拼到 query string 或日志里.
|
|
78
|
+
body: JSON.stringify({ app_id: appId, app_secret: appSecret }),
|
|
79
|
+
signal: ac.signal,
|
|
80
|
+
});
|
|
81
|
+
body = await res.json();
|
|
82
|
+
}
|
|
83
|
+
catch (err) {
|
|
84
|
+
clearTimeout(timer);
|
|
85
|
+
// AbortError (fetch / json() 内部 / 我们自己 timeout) 全部归到 network
|
|
86
|
+
const isAbort = err?.name === 'AbortError' || ac.signal.aborted;
|
|
87
|
+
// JSON 解析错 (非 abort) 归 unknown, 保留旧行为
|
|
88
|
+
if (!isAbort && err instanceof SyntaxError) {
|
|
89
|
+
return { ok: false, error: 'unknown', message: `HTTP ${res?.status ?? '?'} 响应非 JSON` };
|
|
90
|
+
}
|
|
91
|
+
return {
|
|
92
|
+
ok: false,
|
|
93
|
+
error: 'network',
|
|
94
|
+
message: isAbort
|
|
95
|
+
? `请求超时 (> ${budgetMs}ms)`
|
|
96
|
+
: `网络错误: ${err?.code ?? err?.message ?? 'unknown'}`,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
clearTimeout(timer);
|
|
100
|
+
if (body?.code === 0 && typeof body.tenant_access_token === 'string') {
|
|
101
|
+
return { ok: true, tenantAccessToken: body.tenant_access_token, tokenExpiresIn: body.expire ?? 7200 };
|
|
102
|
+
}
|
|
103
|
+
// 飞书常见错误码:
|
|
104
|
+
// 10003 / 10012: app_id or app_secret invalid
|
|
105
|
+
// 10014: 应用未发布
|
|
106
|
+
// 99991663: app_secret invalid
|
|
107
|
+
if (body?.code === 10003 || body?.code === 10012 || body?.code === 99991663) {
|
|
108
|
+
return { ok: false, error: 'invalid_credentials', message: `凭证无效 (code=${body.code}): ${body.msg ?? ''}` };
|
|
109
|
+
}
|
|
110
|
+
return { ok: false, error: 'unknown', message: `code=${body?.code ?? '?'} msg=${body?.msg ?? ''}` };
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* 列出应用的 scope grant 状态, 比对 BOTMUX_REQUIRED_SCOPES.
|
|
114
|
+
*
|
|
115
|
+
* **不在主路径使用** — 待 spike 用真实/可复现 mock 证明 grant_status 含义和
|
|
116
|
+
* 状态闭环后再启用. 当前主路径只输出"剩余步骤 + 深链", 不做 grant_status 判定.
|
|
117
|
+
*
|
|
118
|
+
* scope.list 返回 shape (SDK type):
|
|
119
|
+
* `{ data: { scopes: [{ scope_name, grant_status, scope_type }] } }`
|
|
120
|
+
* grant_status 含义未在官方文档明确, 但社区 SDK / 实测一般约定:
|
|
121
|
+
* 1 = 已申请未生效, 2 = 已生效. 启用前 spike 务必确认这个映射.
|
|
122
|
+
*/
|
|
123
|
+
export async function checkRequiredScopes(appId, appSecret, brand = 'feishu') {
|
|
124
|
+
const domain = brand === 'lark' ? Lark.Domain.Lark : Lark.Domain.Feishu;
|
|
125
|
+
const client = new Lark.Client({ appId, appSecret, domain, loggerLevel: Lark.LoggerLevel.error });
|
|
126
|
+
let resp;
|
|
127
|
+
try {
|
|
128
|
+
resp = await client.application.scope.list();
|
|
129
|
+
}
|
|
130
|
+
catch (err) {
|
|
131
|
+
return { ok: false, error: 'network', message: `scope.list 调用失败: ${err?.code ?? err?.message ?? 'unknown'}` };
|
|
132
|
+
}
|
|
133
|
+
// SDK 失败时不抛, 返回 { code, msg }
|
|
134
|
+
if (resp?.code === 99991672) {
|
|
135
|
+
return {
|
|
136
|
+
ok: false,
|
|
137
|
+
error: 'need_self_manage',
|
|
138
|
+
message: '应用缺少 application:application:self_manage 权限, 无法自查 scope 列表',
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
if (resp?.code !== 0) {
|
|
142
|
+
return { ok: false, error: 'unknown', message: `code=${resp?.code ?? '?'} msg=${resp?.msg ?? ''}` };
|
|
143
|
+
}
|
|
144
|
+
const scopes = resp?.data?.scopes ?? [];
|
|
145
|
+
// grant_status === 2 → granted (待 spike 确认这是正确映射)
|
|
146
|
+
const grantedNames = scopes
|
|
147
|
+
.filter((s) => s?.grant_status === 2 && typeof s?.scope_name === 'string')
|
|
148
|
+
.map((s) => s.scope_name);
|
|
149
|
+
const missingCritical = BOTMUX_REQUIRED_SCOPES.filter(s => s.critical && !grantedNames.includes(s.name));
|
|
150
|
+
const missingOptional = BOTMUX_REQUIRED_SCOPES.filter(s => !s.critical && !grantedNames.includes(s.name));
|
|
151
|
+
return { ok: true, granted: grantedNames, missingCritical, missingOptional };
|
|
152
|
+
}
|
|
153
|
+
export async function applyScopesUnverified(appId, appSecret, opts = {}) {
|
|
154
|
+
const brand = opts.brand ?? 'feishu';
|
|
155
|
+
const budgetMs = opts.budgetMs ?? 15_000;
|
|
156
|
+
const domain = brand === 'lark' ? Lark.Domain.Lark : Lark.Domain.Feishu;
|
|
157
|
+
const client = new Lark.Client({ appId, appSecret, domain, loggerLevel: Lark.LoggerLevel.error });
|
|
158
|
+
const timeout = new Promise((resolve) => {
|
|
159
|
+
const timer = setTimeout(() => resolve({ status: 'timeout', msg: `> ${budgetMs}ms` }), budgetMs);
|
|
160
|
+
opts.signal?.addEventListener('abort', () => {
|
|
161
|
+
clearTimeout(timer);
|
|
162
|
+
resolve({ status: 'timeout', msg: 'aborted' });
|
|
163
|
+
}, { once: true });
|
|
164
|
+
});
|
|
165
|
+
const call = (async () => {
|
|
166
|
+
try {
|
|
167
|
+
const resp = await client.application.scope.apply();
|
|
168
|
+
const code = resp?.code;
|
|
169
|
+
const msg = resp?.msg;
|
|
170
|
+
if (code === 0)
|
|
171
|
+
return { status: 'submitted', code, msg };
|
|
172
|
+
if (code === 212001)
|
|
173
|
+
return { status: 'super_scope_only', code, msg };
|
|
174
|
+
if (code === 212002)
|
|
175
|
+
return { status: 'nothing_to_apply', code, msg };
|
|
176
|
+
if (code === 212003)
|
|
177
|
+
return { status: 'over_limit', code, msg };
|
|
178
|
+
if (code === 212004)
|
|
179
|
+
return { status: 'already_applied', code, msg };
|
|
180
|
+
return { status: 'error', code, msg };
|
|
181
|
+
}
|
|
182
|
+
catch (err) {
|
|
183
|
+
return { status: 'error', msg: err?.code ?? err?.message ?? 'unknown' };
|
|
184
|
+
}
|
|
185
|
+
})();
|
|
186
|
+
return Promise.race([call, timeout]);
|
|
187
|
+
}
|
|
188
|
+
// ─── Remaining-steps printer ──────────────────────────────────────────────
|
|
189
|
+
/**
|
|
190
|
+
* setup 后 "还要手动点的步骤" 结构化数据. 跟 cli.ts 的 printRemainingSteps + README
|
|
191
|
+
* "5 分钟快速接入" 一致: 主线就两步 (权限申请 + 按需重定向 URL); PersonalAgent
|
|
192
|
+
* 应用默认订阅事件 + bot 能力, 不在主线提示, 收不到消息时见 README 的 fallback
|
|
193
|
+
* 自查清单.
|
|
194
|
+
*/
|
|
195
|
+
export function buildRemainingSteps(appId, brand = 'feishu') {
|
|
196
|
+
return [
|
|
197
|
+
{
|
|
198
|
+
title: '申请权限 (一次性导入完整 JSON 提交审批) — 进入「权限管理」→「批量导入/导出权限」, 粘贴 ~/.botmux/lark-scopes.json',
|
|
199
|
+
url: `${buildAppHomeDeepLink(appId, brand)}/auth`,
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
title: '添加重定向 URL http://127.0.0.1:9768/callback (按需, 用于 botmux 内 /login 跨用户调 API)',
|
|
203
|
+
url: `${buildAppHomeDeepLink(appId, brand)}/safe`,
|
|
204
|
+
},
|
|
205
|
+
];
|
|
206
|
+
}
|
|
207
|
+
//# sourceMappingURL=verify-permissions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify-permissions.js","sourceRoot":"","sources":["../../src/setup/verify-permissions.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"screenshot-renderer.d.ts","sourceRoot":"","sources":["../../src/utils/screenshot-renderer.ts"],"names":[],"mappings":"AAUA,OAAO,aAAa,MAAM,iBAAiB,CAAC;AAC5C,KAAK,QAAQ,GAAG,YAAY,CAAC,OAAO,aAAa,CAAC,QAAQ,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"screenshot-renderer.d.ts","sourceRoot":"","sources":["../../src/utils/screenshot-renderer.ts"],"names":[],"mappings":"AAUA,OAAO,aAAa,MAAM,iBAAiB,CAAC;AAC5C,KAAK,QAAQ,GAAG,YAAY,CAAC,OAAO,aAAa,CAAC,QAAQ,CAAC,CAAC;AAoM5D,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"}
|
|
@@ -39,20 +39,57 @@ function ensureFontRegistered() {
|
|
|
39
39
|
break;
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
|
-
//
|
|
43
|
-
//
|
|
44
|
-
//
|
|
42
|
+
// ── fontFamilyChain 顺序很关键 ──
|
|
43
|
+
// skia 按 chain 顺序逐字符找含该 glyph 的字体。Latin **必须放在 CJK 前面**,
|
|
44
|
+
// 否则 CJK 字体(Hiragino / Noto Sans CJK)自带的 ASCII glyph 会先抢走拉丁
|
|
45
|
+
// 字符的渲染权,宽度跟 cell grid 不匹配 → 截图里英文字符间距时疏时密。
|
|
46
|
+
// 顺序:BotmuxMono → Latin mono → CJK mono → Color emoji。
|
|
45
47
|
const userFontDir = join(homedir(), '.botmux', 'fonts');
|
|
48
|
+
// 2. Latin monospace — DejaVu/Liberation/JetBrains Mono cover dingbats (❯,
|
|
49
|
+
// ✓, etc.) and most box-drawing/geometric symbols not in CJK font.
|
|
50
|
+
// macOS:用 Menlo / .SF NS Mono / Monaco(实测三者都能被 @napi-rs/canvas
|
|
51
|
+
// 注册)。注意 SFNSMono 注册后内部 family 名是 ".SF NS Mono"(带点前缀),
|
|
52
|
+
// 用 alias 显式指定别名以保证 fontFamilyChain 里 family name 与 ctx.font
|
|
53
|
+
// 解析路径一致。
|
|
54
|
+
const latinCandidates = [
|
|
55
|
+
{ path: join(userFontDir, 'JetBrainsMono-Regular.ttf'), family: 'JetBrains Mono' },
|
|
56
|
+
{ path: '/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf', family: 'DejaVu Sans Mono' },
|
|
57
|
+
{ path: '/usr/share/fonts/dejavu/DejaVuSansMono.ttf', family: 'DejaVu Sans Mono' },
|
|
58
|
+
{ path: '/usr/share/fonts/truetype/liberation/LiberationMono-Regular.ttf', family: 'Liberation Mono' },
|
|
59
|
+
{ path: '/usr/share/fonts/liberation/LiberationMono-Regular.ttf', family: 'Liberation Mono' },
|
|
60
|
+
{ path: '/usr/share/fonts/truetype/jetbrains-mono/JetBrainsMono-Regular.ttf', family: 'JetBrains Mono' },
|
|
61
|
+
// macOS 系统等宽。Menlo 优先(覆盖最全 + 兼容 box-drawing),SFNSMono / Monaco
|
|
62
|
+
// 兜底。这些路径在 macOS 12+ 都稳定存在。
|
|
63
|
+
{ path: '/System/Library/Fonts/Menlo.ttc', family: 'Menlo' },
|
|
64
|
+
{ path: '/System/Library/Fonts/SFNSMono.ttf', family: 'SF Mono', alias: 'SF Mono' },
|
|
65
|
+
{ path: '/System/Library/Fonts/Monaco.ttf', family: 'Monaco' },
|
|
66
|
+
];
|
|
67
|
+
for (const c of latinCandidates) {
|
|
68
|
+
if (tryRegister(c.path, c.alias)) {
|
|
69
|
+
// Best-effort bold companion. Same dir, replace -Regular with -Bold.
|
|
70
|
+
tryRegister(c.path.replace(/-Regular\.ttf$/, '-Bold.ttf'));
|
|
71
|
+
tryRegister(c.path.replace(/SansMono\.ttf$/, 'SansMono-Bold.ttf'));
|
|
72
|
+
fontFamilyChain.push(c.family);
|
|
73
|
+
break;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
// 3. CJK monospace — Han + Hiragana/Katakana + Hangul.
|
|
77
|
+
// Linux: Noto Sans CJK(需要 fonts-noto-cjk 包,或 botmux setup 自动下载到 ~/.botmux/fonts/);
|
|
78
|
+
// macOS: PingFang 在 macOS 26 上从 /System/Library/Fonts 移除了,回退 Hiragino Sans GB
|
|
79
|
+
// (实测注册成功且 family name 与文件名一致);STHeiti 作为更老系统的兜底。
|
|
46
80
|
const cjkCandidates = [
|
|
47
81
|
{ regular: join(userFontDir, 'NotoSansMonoCJKsc-Regular.otf'), bold: join(userFontDir, 'NotoSansMonoCJKsc-Bold.otf'), family: 'Noto Sans Mono CJK SC' },
|
|
48
82
|
{ regular: '/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc', bold: '/usr/share/fonts/opentype/noto/NotoSansCJK-Bold.ttc', family: 'Noto Sans Mono CJK SC' },
|
|
49
83
|
{ regular: '/usr/share/fonts/noto-cjk/NotoSansCJK-Regular.ttc', bold: '/usr/share/fonts/noto-cjk/NotoSansCJK-Bold.ttc', family: 'Noto Sans Mono CJK SC' },
|
|
50
84
|
{ regular: '/usr/share/fonts/google-noto-cjk/NotoSansCJK-Regular.ttc', bold: '/usr/share/fonts/google-noto-cjk/NotoSansCJK-Bold.ttc', family: 'Noto Sans Mono CJK SC' },
|
|
51
85
|
{ regular: '/usr/share/fonts/opentype/noto/NotoSansMonoCJK-Regular.ttc', bold: '/usr/share/fonts/opentype/noto/NotoSansMonoCJK-Bold.ttc', family: 'Noto Sans Mono CJK SC' },
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
{ regular: '/Library/Fonts/Hiragino Sans GB.ttc', family: 'Hiragino Sans GB' },
|
|
86
|
+
// macOS:Hiragino 含中文常用字 + 日文,PingFang 在 macOS 26 上已被移除,
|
|
87
|
+
// 不放到首选位(路径不在就 fall-through)。
|
|
55
88
|
{ regular: '/System/Library/Fonts/Hiragino Sans GB.ttc', family: 'Hiragino Sans GB' },
|
|
89
|
+
{ regular: '/Library/Fonts/Hiragino Sans GB.ttc', family: 'Hiragino Sans GB' },
|
|
90
|
+
{ regular: '/System/Library/Fonts/STHeiti Medium.ttc', family: 'Heiti TC' },
|
|
91
|
+
{ regular: '/System/Library/Fonts/STHeiti Light.ttc', family: 'Heiti TC' },
|
|
92
|
+
{ regular: '/System/Library/Fonts/PingFang.ttc', family: 'PingFang SC' }, // 旧 macOS 兜底
|
|
56
93
|
];
|
|
57
94
|
for (const c of cjkCandidates) {
|
|
58
95
|
if (tryRegister(c.regular)) {
|
|
@@ -62,25 +99,6 @@ function ensureFontRegistered() {
|
|
|
62
99
|
break;
|
|
63
100
|
}
|
|
64
101
|
}
|
|
65
|
-
// 3. Latin monospace — DejaVu/Liberation/JetBrains Mono cover dingbats (❯,
|
|
66
|
-
// ✓, etc.) and most box-drawing/geometric symbols not in CJK font.
|
|
67
|
-
const latinCandidates = [
|
|
68
|
-
[join(userFontDir, 'JetBrainsMono-Regular.ttf'), 'JetBrains Mono'],
|
|
69
|
-
['/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf', 'DejaVu Sans Mono'],
|
|
70
|
-
['/usr/share/fonts/dejavu/DejaVuSansMono.ttf', 'DejaVu Sans Mono'],
|
|
71
|
-
['/usr/share/fonts/truetype/liberation/LiberationMono-Regular.ttf', 'Liberation Mono'],
|
|
72
|
-
['/usr/share/fonts/liberation/LiberationMono-Regular.ttf', 'Liberation Mono'],
|
|
73
|
-
['/usr/share/fonts/truetype/jetbrains-mono/JetBrainsMono-Regular.ttf', 'JetBrains Mono'],
|
|
74
|
-
];
|
|
75
|
-
for (const [p, name] of latinCandidates) {
|
|
76
|
-
if (tryRegister(p)) {
|
|
77
|
-
// Best-effort bold companion. Same dir, replace -Regular with -Bold.
|
|
78
|
-
tryRegister(p.replace(/-Regular\.ttf$/, '-Bold.ttf'));
|
|
79
|
-
tryRegister(p.replace(/SansMono\.ttf$/, 'SansMono-Bold.ttf'));
|
|
80
|
-
fontFamilyChain.push(name);
|
|
81
|
-
break;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
102
|
// 4. Color emoji — Noto Color Emoji on Linux, Apple Color Emoji on macOS.
|
|
85
103
|
// skia handles CBDT/CBLC + COLR/CPAL color formats.
|
|
86
104
|
const emojiCandidates = [
|
|
@@ -104,6 +122,25 @@ function fontSpec(bold) {
|
|
|
104
122
|
const families = fontFamilyChain.map(f => `"${f}"`).join(', ');
|
|
105
123
|
return `${bold ? 'bold ' : ''}${FONT_SIZE}px ${families}, monospace`;
|
|
106
124
|
}
|
|
125
|
+
/** Map "Misc Technical" / "Supplemental Arrows-C" 三角符号到等价的
|
|
126
|
+
* "Geometric Shapes" 块字符。前者(U+23F4-F7、U+2BC7/8)几乎没有等宽字体
|
|
127
|
+
* 收录—— macOS 系统字体全员缺失,Linux 上 DejaVu/JetBrains 也没有,所以
|
|
128
|
+
* 渲染必出现空方框。后者(U+25B6 ▶ / U+25C0 ◀ / U+25B2 ▲ / U+25BC ▼)
|
|
129
|
+
* 是 Unicode 1.1 老字符,Menlo / Noto / DejaVu 全都有 glyph。
|
|
130
|
+
*
|
|
131
|
+
* 仅替换语义视觉等价的几个字符;U+23F8 ⏸ / U+23F9 ⏹ / U+23FA ⏺ 不动 ——
|
|
132
|
+
* 它们在 Apple Color Emoji 有彩色变体,且没有真正等价的老字符。 */
|
|
133
|
+
const NARROW_SYMBOL_FALLBACK = {
|
|
134
|
+
'⏴': '◀', // ⏴ → ◀
|
|
135
|
+
'⏵': '▶', // ⏵ → ▶
|
|
136
|
+
'⏶': '▲', // ⏶ → ▲
|
|
137
|
+
'⏷': '▼', // ⏷ → ▼
|
|
138
|
+
'⯇': '◀', // ⯇ → ◀
|
|
139
|
+
'⯈': '▶', // ⯈ → ▶
|
|
140
|
+
};
|
|
141
|
+
function fallbackSymbol(ch) {
|
|
142
|
+
return NARROW_SYMBOL_FALLBACK[ch] ?? ch;
|
|
143
|
+
}
|
|
107
144
|
/** Detect whether the leading codepoint is an emoji/symbol pictograph that
|
|
108
145
|
* uses bitmap glyph metrics — these need vertical centering, not top-align. */
|
|
109
146
|
function isPictograph(ch) {
|
|
@@ -190,7 +227,7 @@ export function captureToPng(terminal, opts) {
|
|
|
190
227
|
col++;
|
|
191
228
|
continue;
|
|
192
229
|
}
|
|
193
|
-
const ch = cell.getChars();
|
|
230
|
+
const ch = fallbackSymbol(cell.getChars());
|
|
194
231
|
const x = PADDING + col * CELL_W;
|
|
195
232
|
const y = PADDING + row * CELL_H;
|
|
196
233
|
let fg = colorOf(cell, false) ?? FG;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"screenshot-renderer.js","sourceRoot":"","sources":["../../src/utils/screenshot-renderer.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC5D,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAIzC,+EAA+E;AAC/E,wEAAwE;AACxE,4EAA4E;AAC5E,6EAA6E;AAC7E,4DAA4D;AAE5D,MAAM,eAAe,GAAa,EAAE,CAAC;AACrC,IAAI,eAAe,GAAG,KAAK,CAAC;AAE5B,SAAS,WAAW,CAAC,IAAY,EAAE,KAAc;IAC/C,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC;IACpC,IAAI,CAAC;QAAC,WAAW,CAAC,gBAAgB,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QAAC,OAAO,IAAI,CAAC;IAAC,CAAC;IAC/D,MAAM,CAAC;QAAC,OAAO,KAAK,CAAC;IAAC,CAAC;AACzB,CAAC;AAED,SAAS,oBAAoB;IAC3B,IAAI,eAAe;QAAE,OAAO;IAC5B,eAAe,GAAG,IAAI,CAAC;IAEvB,yFAAyF;IACzF,MAAM,cAAc,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;IACpG,KAAK,MAAM,KAAK,IAAI,CAAC,wBAAwB,EAAE,gBAAgB,EAAE,wBAAwB,CAAC,EAAE,CAAC;QAC3F,IAAI,WAAW,CAAC,IAAI,CAAC,cAAc,EAAE,KAAK,CAAC,EAAE,YAAY,CAAC,EAAE,CAAC;YAC3D,WAAW,CAAC,IAAI,CAAC,cAAc,EAAE,qBAAqB,CAAC,EAAE,YAAY,CAAC,CAAC;YACvE,eAAe,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;YACnC,MAAM;QACR,CAAC;IACH,CAAC;IAED,
|
|
1
|
+
{"version":3,"file":"screenshot-renderer.js","sourceRoot":"","sources":["../../src/utils/screenshot-renderer.ts"],"names":[],"mappings":"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"}
|
|
@@ -9,6 +9,22 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import xtermHeadless from '@xterm/headless';
|
|
11
11
|
declare const Terminal: typeof xtermHeadless.Terminal;
|
|
12
|
+
/**
|
|
13
|
+
* Read the current viewport of an xterm-headless Terminal as plain text.
|
|
14
|
+
*
|
|
15
|
+
* Extracted as a free function so transient renderers (capture-pane seeded)
|
|
16
|
+
* can reuse the same line-filtering + trimming logic without instantiating
|
|
17
|
+
* a full TerminalRenderer (which is built for long-lived buffer accumulation).
|
|
18
|
+
*
|
|
19
|
+
* `filter=true` drops the bare-prompt line and the input-echo line — the
|
|
20
|
+
* card text should show CLI output, not the live cursor reflection.
|
|
21
|
+
*/
|
|
22
|
+
export declare function readViewportText(terminal: InstanceType<typeof Terminal>, opts: {
|
|
23
|
+
filter: boolean;
|
|
24
|
+
readCols?: number;
|
|
25
|
+
startY?: number;
|
|
26
|
+
rows?: number;
|
|
27
|
+
}): string;
|
|
12
28
|
export declare class TerminalRenderer {
|
|
13
29
|
private terminal;
|
|
14
30
|
private lastHash;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"terminal-renderer.d.ts","sourceRoot":"","sources":["../../src/utils/terminal-renderer.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,aAAa,MAAM,iBAAiB,CAAC;AAC5C,QAAA,MAAQ,QAAQ,+BAAkB,CAAC;AAwBnC,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAgC;IAChD,OAAO,CAAC,QAAQ,CAAM;gBAEV,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM;IAItC,mDAAmD;IACnD,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAIzB,iFAAiF;IACjF,WAAW,IAAI,IAAI;IAInB,6EAA6E;IAC7E,QAAQ,IAAI;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAE;IAQjD;;;OAGG;IACH,WAAW,IAAI,MAAM;IAIrB,OAAO,CAAC,YAAY;
|
|
1
|
+
{"version":3,"file":"terminal-renderer.d.ts","sourceRoot":"","sources":["../../src/utils/terminal-renderer.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,aAAa,MAAM,iBAAiB,CAAC;AAC5C,QAAA,MAAQ,QAAQ,+BAAkB,CAAC;AAwBnC;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,YAAY,CAAC,OAAO,QAAQ,CAAC,EACvC,IAAI,EAAE;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GAC3E,MAAM,CAsBR;AAED,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAgC;IAChD,OAAO,CAAC,QAAQ,CAAM;gBAEV,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM;IAItC,mDAAmD;IACnD,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAIzB,iFAAiF;IACjF,WAAW,IAAI,IAAI;IAInB,6EAA6E;IAC7E,QAAQ,IAAI;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAE;IAQjD;;;OAGG;IACH,WAAW,IAAI,MAAM;IAIrB,OAAO,CAAC,YAAY;IAIpB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAIxC,8EAA8E;IAC9E,IAAI,KAAK,IAAI,YAAY,CAAC,OAAO,QAAQ,CAAC,CAA0B;IAEpE,OAAO,IAAI,IAAI;CAGhB"}
|
|
@@ -28,6 +28,40 @@ const BLANK_RE = /^\s*$/;
|
|
|
28
28
|
* cols (PTY_COLS=160 for spawned sessions, source pane width for adopt
|
|
29
29
|
* mode 200-270). Bumping past 320 risks a >5MB canvas per screenshot. */
|
|
30
30
|
const SNAPSHOT_COLS = 320;
|
|
31
|
+
/**
|
|
32
|
+
* Read the current viewport of an xterm-headless Terminal as plain text.
|
|
33
|
+
*
|
|
34
|
+
* Extracted as a free function so transient renderers (capture-pane seeded)
|
|
35
|
+
* can reuse the same line-filtering + trimming logic without instantiating
|
|
36
|
+
* a full TerminalRenderer (which is built for long-lived buffer accumulation).
|
|
37
|
+
*
|
|
38
|
+
* `filter=true` drops the bare-prompt line and the input-echo line — the
|
|
39
|
+
* card text should show CLI output, not the live cursor reflection.
|
|
40
|
+
*/
|
|
41
|
+
export function readViewportText(terminal, opts) {
|
|
42
|
+
const buffer = terminal.buffer.active;
|
|
43
|
+
const readCols = Math.min(opts.readCols ?? SNAPSHOT_COLS, terminal.cols);
|
|
44
|
+
const baseY = opts.startY ?? buffer.baseY;
|
|
45
|
+
const rows = opts.rows ?? terminal.rows;
|
|
46
|
+
const endY = baseY + rows;
|
|
47
|
+
const lines = [];
|
|
48
|
+
for (let y = baseY; y < endY; y++) {
|
|
49
|
+
const line = buffer.getLine(y);
|
|
50
|
+
if (!line)
|
|
51
|
+
continue;
|
|
52
|
+
const s = cleanBoxDrawing(line.translateToString(true, 0, readCols));
|
|
53
|
+
if (opts.filter && (BARE_PROMPT_RE.test(s) || INPUT_ECHO_RE.test(s)))
|
|
54
|
+
continue;
|
|
55
|
+
lines.push(s);
|
|
56
|
+
}
|
|
57
|
+
if (opts.filter) {
|
|
58
|
+
while (lines.length > 0 && BLANK_RE.test(lines[0]))
|
|
59
|
+
lines.shift();
|
|
60
|
+
}
|
|
61
|
+
while (lines.length > 0 && BLANK_RE.test(lines[lines.length - 1]))
|
|
62
|
+
lines.pop();
|
|
63
|
+
return lines.join('\n');
|
|
64
|
+
}
|
|
31
65
|
export class TerminalRenderer {
|
|
32
66
|
terminal;
|
|
33
67
|
lastHash = '';
|
|
@@ -58,27 +92,7 @@ export class TerminalRenderer {
|
|
|
58
92
|
return this.readViewport(false);
|
|
59
93
|
}
|
|
60
94
|
readViewport(filter) {
|
|
61
|
-
|
|
62
|
-
const readCols = Math.min(SNAPSHOT_COLS, this.terminal.cols);
|
|
63
|
-
const baseY = buffer.baseY;
|
|
64
|
-
const endY = baseY + this.terminal.rows;
|
|
65
|
-
const lines = [];
|
|
66
|
-
for (let y = baseY; y < endY; y++) {
|
|
67
|
-
const line = buffer.getLine(y);
|
|
68
|
-
if (!line)
|
|
69
|
-
continue;
|
|
70
|
-
const s = cleanBoxDrawing(line.translateToString(true, 0, readCols));
|
|
71
|
-
if (filter && (BARE_PROMPT_RE.test(s) || INPUT_ECHO_RE.test(s)))
|
|
72
|
-
continue;
|
|
73
|
-
lines.push(s);
|
|
74
|
-
}
|
|
75
|
-
if (filter) {
|
|
76
|
-
while (lines.length > 0 && BLANK_RE.test(lines[0]))
|
|
77
|
-
lines.shift();
|
|
78
|
-
}
|
|
79
|
-
while (lines.length > 0 && BLANK_RE.test(lines[lines.length - 1]))
|
|
80
|
-
lines.pop();
|
|
81
|
-
return lines.join('\n');
|
|
95
|
+
return readViewportText(this.terminal, { filter });
|
|
82
96
|
}
|
|
83
97
|
resize(cols, rows) {
|
|
84
98
|
this.terminal.resize(cols, rows);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"terminal-renderer.js","sourceRoot":"","sources":["../../src/utils/terminal-renderer.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,aAAa,MAAM,iBAAiB,CAAC;AAC5C,MAAM,EAAE,QAAQ,EAAE,GAAG,aAAa,CAAC;AACnC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,gEAAgE;AAChE,SAAS,eAAe,CAAC,IAAY;IACnC,OAAO,IAAI;SACR,OAAO,CAAC,qBAAqB,EAAE,GAAG,CAAC;SACnC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC;SACpB,OAAO,EAAE,CAAC;AACf,CAAC;AAED,kFAAkF;AAClF,MAAM,cAAc,GAAG,WAAW,CAAC;AACnC,+CAA+C;AAC/C,MAAM,aAAa,GAAG,YAAY,CAAC;AACnC,+BAA+B;AAC/B,MAAM,QAAQ,GAAG,OAAO,CAAC;AAEzB;;;0EAG0E;AAC1E,MAAM,aAAa,GAAG,GAAG,CAAC;AAE1B,MAAM,
|
|
1
|
+
{"version":3,"file":"terminal-renderer.js","sourceRoot":"","sources":["../../src/utils/terminal-renderer.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,aAAa,MAAM,iBAAiB,CAAC;AAC5C,MAAM,EAAE,QAAQ,EAAE,GAAG,aAAa,CAAC;AACnC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,gEAAgE;AAChE,SAAS,eAAe,CAAC,IAAY;IACnC,OAAO,IAAI;SACR,OAAO,CAAC,qBAAqB,EAAE,GAAG,CAAC;SACnC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC;SACpB,OAAO,EAAE,CAAC;AACf,CAAC;AAED,kFAAkF;AAClF,MAAM,cAAc,GAAG,WAAW,CAAC;AACnC,+CAA+C;AAC/C,MAAM,aAAa,GAAG,YAAY,CAAC;AACnC,+BAA+B;AAC/B,MAAM,QAAQ,GAAG,OAAO,CAAC;AAEzB;;;0EAG0E;AAC1E,MAAM,aAAa,GAAG,GAAG,CAAC;AAE1B;;;;;;;;;GASG;AACH,MAAM,UAAU,gBAAgB,CAC9B,QAAuC,EACvC,IAA4E;IAE5E,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC;IACtC,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,IAAI,aAAa,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC;IACzE,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,KAAK,CAAC;IAC1C,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,QAAQ,CAAC,IAAI,CAAC;IACxC,MAAM,IAAI,GAAG,KAAK,GAAG,IAAI,CAAC;IAE1B,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,IAAI,CAAC,GAAG,KAAK,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC;QAClC,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QAC/B,IAAI,CAAC,IAAI;YAAE,SAAS;QACpB,MAAM,CAAC,GAAG,eAAe,CAAC,IAAI,CAAC,iBAAiB,CAAC,IAAI,EAAE,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC;QACrE,IAAI,IAAI,CAAC,MAAM,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAAE,SAAS;QAC/E,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAChB,CAAC;IAED,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;QAChB,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YAAE,KAAK,CAAC,KAAK,EAAE,CAAC;IACpE,CAAC;IACD,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAAE,KAAK,CAAC,GAAG,EAAE,CAAC;IAE/E,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,MAAM,OAAO,gBAAgB;IACnB,QAAQ,CAAgC;IACxC,QAAQ,GAAG,EAAE,CAAC;IAEtB,YAAY,IAAY,EAAE,IAAY;QACpC,IAAI,CAAC,QAAQ,GAAG,IAAI,QAAQ,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,gBAAgB,EAAE,IAAI,EAAE,CAAC,CAAC;IACvE,CAAC;IAED,mDAAmD;IACnD,KAAK,CAAC,IAAY;QAChB,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC;IAED,iFAAiF;IACjF,WAAW;QACT,IAAI,CAAC,QAAQ,GAAG,EAAE,CAAC;IACrB,CAAC;IAED,6EAA6E;IAC7E,QAAQ;QACN,MAAM,OAAO,GAAG,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;QACxC,MAAM,IAAI,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAC7D,MAAM,OAAO,GAAG,IAAI,KAAK,IAAI,CAAC,QAAQ,CAAC;QACvC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QACrB,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;IAC9B,CAAC;IAED;;;OAGG;IACH,WAAW;QACT,OAAO,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;IAClC,CAAC;IAEO,YAAY,CAAC,MAAe;QAClC,OAAO,gBAAgB,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;IACrD,CAAC;IAED,MAAM,CAAC,IAAY,EAAE,IAAY;QAC/B,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACnC,CAAC;IAED,8EAA8E;IAC9E,IAAI,KAAK,KAAoC,OAAO,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;IAEpE,OAAO;QACL,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC;IAC1B,CAAC;CACF"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export interface TransientSnapshot {
|
|
2
|
+
cols: number;
|
|
3
|
+
rows: number;
|
|
4
|
+
/** Raw ANSI captured from tmux capture-pane. Useful for hashing/dedup. */
|
|
5
|
+
ansi: string;
|
|
6
|
+
}
|
|
7
|
+
/** Attempt to capture a fresh ANSI snapshot from a TmuxPipeBackend. Returns
|
|
8
|
+
* null if the backend isn't a pipe backend, the pane has gone away, or
|
|
9
|
+
* tmux refuses to answer. Callers should fall back to the legacy renderer
|
|
10
|
+
* path on null. */
|
|
11
|
+
export declare function tryCapturePipeSnapshot(backend: unknown, fallbackCols: number, fallbackRows: number): TransientSnapshot | null;
|
|
12
|
+
/** Render a tmux pipe-pane snapshot to a PNG buffer. Returns null when the
|
|
13
|
+
* backend can't provide a snapshot — caller falls back to the legacy
|
|
14
|
+
* long-lived-renderer path. */
|
|
15
|
+
export declare function snapshotToPng(backend: unknown, fallbackCols: number, fallbackRows: number): Promise<{
|
|
16
|
+
png: Buffer;
|
|
17
|
+
ansi: string;
|
|
18
|
+
} | null>;
|
|
19
|
+
/** Render a tmux pipe-pane snapshot to filtered text (drops the bare prompt
|
|
20
|
+
* + input echo lines, same rules as TerminalRenderer.snapshot()). Returns
|
|
21
|
+
* null when the backend can't provide a snapshot. */
|
|
22
|
+
export declare function snapshotToText(backend: unknown, fallbackCols: number, fallbackRows: number, opts: {
|
|
23
|
+
filter: boolean;
|
|
24
|
+
}): Promise<{
|
|
25
|
+
content: string;
|
|
26
|
+
ansi: string;
|
|
27
|
+
} | null>;
|
|
28
|
+
//# sourceMappingURL=transient-snapshot.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transient-snapshot.d.ts","sourceRoot":"","sources":["../../src/utils/transient-snapshot.ts"],"names":[],"mappings":"AA6BA,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,0EAA0E;IAC1E,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;oBAGoB;AACpB,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,OAAO,EAChB,YAAY,EAAE,MAAM,EACpB,YAAY,EAAE,MAAM,GACnB,iBAAiB,GAAG,IAAI,CAU1B;AAcD;;gCAEgC;AAChC,wBAAsB,aAAa,CACjC,OAAO,EAAE,OAAO,EAChB,YAAY,EAAE,MAAM,EACpB,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CAe/C;AAED;;sDAEsD;AACtD,wBAAsB,cAAc,CAClC,OAAO,EAAE,OAAO,EAChB,YAAY,EAAE,MAAM,EACpB,YAAY,EAAE,MAAM,EACpB,IAAI,EAAE;IAAE,MAAM,EAAE,OAAO,CAAA;CAAE,GACxB,OAAO,CAAC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CAYnD"}
|