berry-agent 0.1.0-alpha.1
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/LICENSE +21 -0
- package/README.md +96 -0
- package/dist/.api-emit.stamp +1 -0
- package/dist/.build-meta.json +6 -0
- package/dist/agent/events.js +1 -0
- package/dist/agent/index.js +2 -0
- package/dist/agent/loop.js +139 -0
- package/dist/agent/queue.js +119 -0
- package/dist/agent/stream.js +62 -0
- package/dist/agent/tools-batch.js +221 -0
- package/dist/agent/types.js +8 -0
- package/dist/api/berry-agent-llm.d.ts +18 -0
- package/dist/api/berry-agent.d.ts +9 -0
- package/dist/api/surface.json +1632 -0
- package/dist/api/tsconfig.paths.json +12 -0
- package/dist/api/typebox-compile.d.ts +2 -0
- package/dist/api/typebox-value.d.ts +2 -0
- package/dist/api/typebox.d.ts +2 -0
- package/dist/browser/cdp.js +256 -0
- package/dist/browser/codes.js +31 -0
- package/dist/browser/discover.js +107 -0
- package/dist/browser/engine.js +169 -0
- package/dist/browser/index.js +17 -0
- package/dist/browser/install.js +342 -0
- package/dist/browser/page.js +321 -0
- package/dist/browser/service.js +158 -0
- package/dist/browser/tools.js +198 -0
- package/dist/browser/types.js +81 -0
- package/dist/channels/ask-queue.js +82 -0
- package/dist/channels/commands.js +129 -0
- package/dist/channels/engine/cell.js +143 -0
- package/dist/channels/engine/diff.js +143 -0
- package/dist/channels/engine/engine.js +416 -0
- package/dist/channels/engine/index.js +8 -0
- package/dist/channels/engine/input-keys.js +86 -0
- package/dist/channels/engine/input.js +596 -0
- package/dist/channels/engine/memory-io.js +71 -0
- package/dist/channels/engine/process-io.js +38 -0
- package/dist/channels/engine/types.js +17 -0
- package/dist/channels/engine/width.js +122 -0
- package/dist/channels/index.js +15 -0
- package/dist/channels/registry.js +56 -0
- package/dist/channels/sdk/admit.js +29 -0
- package/dist/channels/sdk/backend.js +102 -0
- package/dist/channels/sdk/cursor.js +56 -0
- package/dist/channels/sdk/index.js +20 -0
- package/dist/channels/sdk/jsonl.js +208 -0
- package/dist/channels/sdk/protocol.js +24 -0
- package/dist/channels/sdk/schema.js +91 -0
- package/dist/channels/sdk/wire-core.js +446 -0
- package/dist/channels/service.js +169 -0
- package/dist/channels/tui/autocomplete/autocomplete.js +42 -0
- package/dist/channels/tui/autocomplete/file-mentions.js +106 -0
- package/dist/channels/tui/autocomplete/popup.js +148 -0
- package/dist/channels/tui/autocomplete/provider.js +7 -0
- package/dist/channels/tui/autocomplete/token.js +68 -0
- package/dist/channels/tui/backend/ansi-rows.js +211 -0
- package/dist/channels/tui/backend/main-screen.js +207 -0
- package/dist/channels/tui/backend/osc.js +91 -0
- package/dist/channels/tui/backend/transcript.js +230 -0
- package/dist/channels/tui/backend/tui-backend.js +915 -0
- package/dist/channels/tui/editor/editor-model.js +543 -0
- package/dist/channels/tui/editor/editor-view.js +140 -0
- package/dist/channels/tui/editor/editor.js +275 -0
- package/dist/channels/tui/editor/undo-stack.js +35 -0
- package/dist/channels/tui/editor/visual-lines.js +126 -0
- package/dist/channels/tui/editor/word-nav.js +106 -0
- package/dist/channels/tui/history/history-viewer.js +403 -0
- package/dist/channels/tui/index.js +3 -0
- package/dist/channels/tui/layout.js +167 -0
- package/dist/channels/tui/markdown/blocks.js +111 -0
- package/dist/channels/tui/markdown/inline.js +75 -0
- package/dist/channels/tui/markdown/markdown.js +182 -0
- package/dist/channels/tui/memory/memory-viewer.js +540 -0
- package/dist/channels/tui/overlay/alt-screen.js +105 -0
- package/dist/channels/tui/overlay/overlay.js +57 -0
- package/dist/channels/tui/overlay/select-confirm.js +156 -0
- package/dist/channels/tui/panels/todo-panel.js +54 -0
- package/dist/channels/tui/panels/tool-progress-panel.js +93 -0
- package/dist/channels/tui/scroll/scroll-view.js +254 -0
- package/dist/channels/tui/status/status-line.js +76 -0
- package/dist/channels/tui/text.js +38 -0
- package/dist/channels/tui/theme.js +41 -0
- package/dist/channels/types.js +11 -0
- package/dist/channels/ui-core.js +209 -0
- package/dist/checkpoint/capture.js +45 -0
- package/dist/checkpoint/codes.js +33 -0
- package/dist/checkpoint/command.js +82 -0
- package/dist/checkpoint/gate.js +48 -0
- package/dist/checkpoint/index.js +20 -0
- package/dist/checkpoint/restore.js +172 -0
- package/dist/checkpoint/store.js +247 -0
- package/dist/checkpoint/types.js +4 -0
- package/dist/checkpoint/walk.js +146 -0
- package/dist/compaction/ccr-tools.js +112 -0
- package/dist/compaction/ccr.js +84 -0
- package/dist/compaction/codes.js +21 -0
- package/dist/compaction/index.js +18 -0
- package/dist/compaction/policy.js +200 -0
- package/dist/compaction/service.js +422 -0
- package/dist/compaction/slots.js +121 -0
- package/dist/compaction/types.js +10 -0
- package/dist/context/codes.js +40 -0
- package/dist/context/events.js +160 -0
- package/dist/context/index.js +13 -0
- package/dist/context/logger.js +136 -0
- package/dist/context/scope.js +182 -0
- package/dist/context/workspace.js +104 -0
- package/dist/contracts/agent-events.d.ts +73 -0
- package/dist/contracts/agent-events.js +16 -0
- package/dist/contracts/api.d.ts +249 -0
- package/dist/contracts/api.js +299 -0
- package/dist/contracts/approval.d.ts +37 -0
- package/dist/contracts/approval.js +9 -0
- package/dist/contracts/env-ref.d.ts +41 -0
- package/dist/contracts/env-ref.js +32 -0
- package/dist/contracts/errors.d.ts +56 -0
- package/dist/contracts/errors.js +266 -0
- package/dist/contracts/events.d.ts +70 -0
- package/dist/contracts/events.js +329 -0
- package/dist/contracts/index.d.ts +32 -0
- package/dist/contracts/index.js +26 -0
- package/dist/contracts/llm.d.ts +275 -0
- package/dist/contracts/llm.js +12 -0
- package/dist/contracts/messages.d.ts +63 -0
- package/dist/contracts/messages.js +65 -0
- package/dist/contracts/redact.d.ts +46 -0
- package/dist/contracts/redact.js +223 -0
- package/dist/contracts/tools.d.ts +197 -0
- package/dist/contracts/tools.js +33 -0
- package/dist/contracts/types.d.ts +302 -0
- package/dist/contracts/types.js +50 -0
- package/dist/contracts/ui.d.ts +122 -0
- package/dist/contracts/ui.js +15 -0
- package/dist/conversation/agent-service.js +61 -0
- package/dist/conversation/approval-wiring.js +82 -0
- package/dist/conversation/backoff.js +38 -0
- package/dist/conversation/codes.js +47 -0
- package/dist/conversation/control-tools.js +102 -0
- package/dist/conversation/control.js +210 -0
- package/dist/conversation/driver.js +922 -0
- package/dist/conversation/index.js +12 -0
- package/dist/conversation/model-visible.js +169 -0
- package/dist/conversation/open-tools.js +126 -0
- package/dist/conversation/reseed.js +132 -0
- package/dist/conversation/sessions.js +215 -0
- package/dist/conversation/todo.js +203 -0
- package/dist/conversation/types.js +35 -0
- package/dist/conversation/wiring.js +204 -0
- package/dist/credentials/codes.js +59 -0
- package/dist/credentials/commands.js +186 -0
- package/dist/credentials/env-ref.js +34 -0
- package/dist/credentials/index.js +28 -0
- package/dist/credentials/migration.js +18 -0
- package/dist/credentials/oauth.js +266 -0
- package/dist/credentials/refresh.js +152 -0
- package/dist/credentials/secrets.js +118 -0
- package/dist/credentials/types.js +30 -0
- package/dist/exec/bash.js +279 -0
- package/dist/exec/codes.js +37 -0
- package/dist/exec/env.js +99 -0
- package/dist/exec/environment.js +39 -0
- package/dist/exec/git-guard.js +623 -0
- package/dist/exec/index.js +24 -0
- package/dist/exec/registry.js +120 -0
- package/dist/exec/spawn.js +281 -0
- package/dist/exec/tail.js +77 -0
- package/dist/exec/types.js +5 -0
- package/dist/goal/codes.js +33 -0
- package/dist/goal/command.js +175 -0
- package/dist/goal/fold.js +121 -0
- package/dist/goal/gates.js +122 -0
- package/dist/goal/index.js +22 -0
- package/dist/goal/migration.js +48 -0
- package/dist/goal/service.js +501 -0
- package/dist/goal/todo-tool.js +174 -0
- package/dist/goal/types.js +1 -0
- package/dist/goal/update-tool.js +46 -0
- package/dist/host/approval-cmd.js +276 -0
- package/dist/host/assembly.js +1146 -0
- package/dist/host/boot-failures.js +104 -0
- package/dist/host/budget-advisory.js +74 -0
- package/dist/host/budget-broadcast.js +50 -0
- package/dist/host/builtins.js +54 -0
- package/dist/host/cli.js +544 -0
- package/dist/host/codes.js +120 -0
- package/dist/host/config-schema.js +195 -0
- package/dist/host/conversation-stack.js +654 -0
- package/dist/host/core-plugins.js +1685 -0
- package/dist/host/credentials-cmd.js +42 -0
- package/dist/host/disclosure.js +30 -0
- package/dist/host/dispatch.js +105 -0
- package/dist/host/doors-cmd.js +154 -0
- package/dist/host/dump-config.js +44 -0
- package/dist/host/hook-dispatch-guard.js +27 -0
- package/dist/host/import-gate.js +153 -0
- package/dist/host/index.js +54 -0
- package/dist/host/issue-session.js +241 -0
- package/dist/host/loader.js +372 -0
- package/dist/host/main.js +161 -0
- package/dist/host/manifest.js +381 -0
- package/dist/host/mcp-entry.js +53 -0
- package/dist/host/plugin-boot.js +952 -0
- package/dist/host/plugin-context.js +672 -0
- package/dist/host/plugin-install.js +480 -0
- package/dist/host/plugin-reload.js +124 -0
- package/dist/host/plugin-store.js +462 -0
- package/dist/host/plugin-tools.js +359 -0
- package/dist/host/plugin-uninstall.js +257 -0
- package/dist/host/plugins-cmd.js +302 -0
- package/dist/host/plugins-command.js +130 -0
- package/dist/host/plugins-config.js +195 -0
- package/dist/host/prompt-sections.js +133 -0
- package/dist/host/run-entry.js +544 -0
- package/dist/host/runtime.js +209 -0
- package/dist/host/scheduler-tick.js +294 -0
- package/dist/host/serve-daemon.js +501 -0
- package/dist/host/serve-entry.js +279 -0
- package/dist/host/session-anchor.js +41 -0
- package/dist/host/sessions-cmd.js +219 -0
- package/dist/host/sessions-face.js +47 -0
- package/dist/host/settings-store.js +112 -0
- package/dist/host/signals.js +69 -0
- package/dist/host/single-instance.js +105 -0
- package/dist/host/subagent-factory.js +291 -0
- package/dist/host/testkit/harness.js +283 -0
- package/dist/host/testkit/index.js +14 -0
- package/dist/host/testkit/matrix.js +302 -0
- package/dist/host/tool-policy-store.js +177 -0
- package/dist/host/triggers.js +212 -0
- package/dist/host/tui-entry.js +216 -0
- package/dist/host/webui-bridge.js +165 -0
- package/dist/issue/codes.js +38 -0
- package/dist/issue/filter.js +146 -0
- package/dist/issue/github.js +116 -0
- package/dist/issue/index.js +17 -0
- package/dist/issue/mount.js +70 -0
- package/dist/issue/poll.js +58 -0
- package/dist/issue/service.js +341 -0
- package/dist/issue/tools.js +70 -0
- package/dist/issue/types.js +34 -0
- package/dist/issue/webhook.js +126 -0
- package/dist/llm/codes.js +77 -0
- package/dist/llm/complete.js +196 -0
- package/dist/llm/events.js +15 -0
- package/dist/llm/index.js +24 -0
- package/dist/llm/inflight.js +65 -0
- package/dist/llm/model-id.js +58 -0
- package/dist/llm/provider-face.d.ts +32 -0
- package/dist/llm/provider-face.js +34 -0
- package/dist/llm/recovery.js +146 -0
- package/dist/llm/runtime.js +46 -0
- package/dist/llm/stream-fn.js +147 -0
- package/dist/lsp/codes.js +31 -0
- package/dist/lsp/connection.js +147 -0
- package/dist/lsp/frame.js +110 -0
- package/dist/lsp/index.js +16 -0
- package/dist/lsp/inject.js +58 -0
- package/dist/lsp/instance.js +264 -0
- package/dist/lsp/service.js +522 -0
- package/dist/lsp/tools.js +53 -0
- package/dist/lsp/types.js +201 -0
- package/dist/mcp/bridge.js +222 -0
- package/dist/mcp/codes.js +21 -0
- package/dist/mcp/index.js +19 -0
- package/dist/mcp/jsonrpc.js +230 -0
- package/dist/mcp/service.js +125 -0
- package/dist/mcp/tools.js +145 -0
- package/dist/mcp/types.js +108 -0
- package/dist/memory/cite.js +131 -0
- package/dist/memory/codes.js +50 -0
- package/dist/memory/command.js +71 -0
- package/dist/memory/consolidate.js +219 -0
- package/dist/memory/cycle.js +109 -0
- package/dist/memory/dao.js +878 -0
- package/dist/memory/diff.js +238 -0
- package/dist/memory/extract.js +181 -0
- package/dist/memory/fts.js +58 -0
- package/dist/memory/index.js +42 -0
- package/dist/memory/inject.js +354 -0
- package/dist/memory/merge.js +178 -0
- package/dist/memory/migration.js +132 -0
- package/dist/memory/pollution.js +59 -0
- package/dist/memory/port.js +385 -0
- package/dist/memory/review.js +201 -0
- package/dist/memory/scan.js +89 -0
- package/dist/memory/tools.js +508 -0
- package/dist/memory/types.js +140 -0
- package/dist/obs/codes.js +38 -0
- package/dist/obs/db.js +115 -0
- package/dist/obs/index.js +20 -0
- package/dist/obs/rollup.js +61 -0
- package/dist/obs/service.js +363 -0
- package/dist/obs/session-tools.js +282 -0
- package/dist/obs/session-view.js +225 -0
- package/dist/obs/tool.js +97 -0
- package/dist/obs/types.js +1 -0
- package/dist/persist/audit.js +63 -0
- package/dist/persist/aux.js +39 -0
- package/dist/persist/codes.js +35 -0
- package/dist/persist/index.js +30 -0
- package/dist/persist/load-history.js +50 -0
- package/dist/persist/migrations.js +37 -0
- package/dist/persist/paths.js +108 -0
- package/dist/persist/persistence.js +229 -0
- package/dist/persist/schema.js +99 -0
- package/dist/persist/secret-box.js +95 -0
- package/dist/persist/store.js +706 -0
- package/dist/persist/write-behind.js +238 -0
- package/dist/safety/approval.js +171 -0
- package/dist/safety/bwrap.js +123 -0
- package/dist/safety/codes.js +57 -0
- package/dist/safety/danger.js +505 -0
- package/dist/safety/gate.js +226 -0
- package/dist/safety/index.js +24 -0
- package/dist/safety/presets.js +73 -0
- package/dist/safety/roots.js +139 -0
- package/dist/safety/sandbox.js +214 -0
- package/dist/safety/seatbelt.js +88 -0
- package/dist/safety/sensitive.js +34 -0
- package/dist/safety/tool-policy.js +203 -0
- package/dist/safety/types.js +13 -0
- package/dist/scheduler/codes.js +54 -0
- package/dist/scheduler/cron-backend.js +135 -0
- package/dist/scheduler/engine.js +280 -0
- package/dist/scheduler/gates.js +60 -0
- package/dist/scheduler/index.js +25 -0
- package/dist/scheduler/migration.js +22 -0
- package/dist/scheduler/runner.js +171 -0
- package/dist/scheduler/schedule.js +193 -0
- package/dist/scheduler/service.js +283 -0
- package/dist/scheduler/tick.js +139 -0
- package/dist/scheduler/types.js +1 -0
- package/dist/sdk/http.js +865 -0
- package/dist/sdk/index.js +22 -0
- package/dist/sdk/mcp.js +289 -0
- package/dist/sdk/plugin-route-registry.js +126 -0
- package/dist/sdk/plugin-routes.js +149 -0
- package/dist/sdk/security.js +116 -0
- package/dist/sdk/types.js +32 -0
- package/dist/session/budget.js +159 -0
- package/dist/session/codes.js +40 -0
- package/dist/session/derive.js +180 -0
- package/dist/session/event-data.js +1 -0
- package/dist/session/fork.js +72 -0
- package/dist/session/import-gates.js +148 -0
- package/dist/session/index.js +18 -0
- package/dist/session/recover.js +103 -0
- package/dist/session/session.js +279 -0
- package/dist/session/snapshot.js +107 -0
- package/dist/skills/agents.js +242 -0
- package/dist/skills/codes.js +51 -0
- package/dist/skills/discovery.js +266 -0
- package/dist/skills/frontmatter.js +215 -0
- package/dist/skills/index.js +28 -0
- package/dist/skills/load.js +118 -0
- package/dist/skills/manage.js +201 -0
- package/dist/skills/registry.js +138 -0
- package/dist/skills/render.js +124 -0
- package/dist/skills/sections.js +171 -0
- package/dist/skills/types.js +21 -0
- package/dist/subagent/codes.js +50 -0
- package/dist/subagent/declarative.js +55 -0
- package/dist/subagent/index.js +19 -0
- package/dist/subagent/notify.js +51 -0
- package/dist/subagent/provide.js +7 -0
- package/dist/subagent/registry.js +149 -0
- package/dist/subagent/service.js +338 -0
- package/dist/subagent/surface.js +44 -0
- package/dist/subagent/tool.js +153 -0
- package/dist/subagent/types.js +25 -0
- package/dist/tools/apply-patch.js +164 -0
- package/dist/tools/codes.js +109 -0
- package/dist/tools/fs.js +501 -0
- package/dist/tools/index.js +17 -0
- package/dist/tools/observed.js +99 -0
- package/dist/tools/pipeline.js +176 -0
- package/dist/tools/protected-read.js +54 -0
- package/dist/tools/registry.js +250 -0
- package/dist/tools/search.js +451 -0
- package/dist/tools/worktree.js +327 -0
- package/dist/web/codes.js +37 -0
- package/dist/web/gate.js +43 -0
- package/dist/web/hygiene.js +195 -0
- package/dist/web/index.js +16 -0
- package/dist/web/service.js +207 -0
- package/dist/web/ssrf-guard.js +44 -0
- package/dist/web/tool.js +76 -0
- package/dist/web/types.js +10 -0
- package/dist/webui/assets/index-B-t2O8gh.js +22 -0
- package/dist/webui/assets/index-DOlgSZ9Q.css +2 -0
- package/dist/webui/index.html +14 -0
- package/dist/webui/index.js +14 -0
- package/dist/webui/server.js +549 -0
- package/dist/webui/types.js +38 -0
- package/examples/README.md +26 -0
- package/examples/minimal-code-plugin/entry.js +43 -0
- package/examples/minimal-code-plugin/package.json +12 -0
- package/examples/pure-skill-pack/package.json +14 -0
- package/examples/pure-skill-pack/skills/markdown-table/SKILL.md +32 -0
- package/package.json +86 -0
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { graphemeWidth, splitGraphemes } from './width.js';
|
|
2
|
+
/** 全缺省样式常量(格的缺省样式——比较归一用,冻结防漂) */
|
|
3
|
+
export const EMPTY_STYLE = Object.freeze({});
|
|
4
|
+
/** 默认格(未写格的语义投影:缺省空格——cellEquals 归一基准) */
|
|
5
|
+
const DEFAULT_CELL = Object.freeze({
|
|
6
|
+
grapheme: ' ',
|
|
7
|
+
style: EMPTY_STYLE,
|
|
8
|
+
width: 1,
|
|
9
|
+
});
|
|
10
|
+
/** 样式相等(缺省位归一比较——undefined 与 false 同为缺省) */
|
|
11
|
+
export function styleEquals(a, b) {
|
|
12
|
+
return ((a.fg ?? null) === (b.fg ?? null) &&
|
|
13
|
+
(a.bg ?? null) === (b.bg ?? null) &&
|
|
14
|
+
!!a.bold === !!b.bold &&
|
|
15
|
+
!!a.italic === !!b.italic &&
|
|
16
|
+
!!a.underline === !!b.underline &&
|
|
17
|
+
!!a.dim === !!b.dim &&
|
|
18
|
+
!!a.inverse === !!b.inverse);
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* 单格相等(差分按格直比原语):null 归一到默认空格格后三元比对——
|
|
22
|
+
* 「写入的缺省空格」与「未写格」判等(不产生假变更帧);
|
|
23
|
+
* 续格(width 0)与空格格判不等(续格是宽字素一部分,占位语义不可丢)。
|
|
24
|
+
*/
|
|
25
|
+
export function cellEquals(a, b) {
|
|
26
|
+
const na = a ?? DEFAULT_CELL;
|
|
27
|
+
const nb = b ?? DEFAULT_CELL;
|
|
28
|
+
return na.grapheme === nb.grapheme && na.width === nb.width && styleEquals(na.style, nb.style);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* CellGrid——CellBuffer 协议实装(一维数组行主序网格;行 / 列界外静默吸收)。
|
|
32
|
+
*
|
|
33
|
+
* 摘痕算法(setCell 内执法):覆写区 [col, col+w) 内既有格若属某宽字素
|
|
34
|
+
* (首格或续格),先整字摘除(首格 + 全部续格)再写新字素——防「旧宽字素
|
|
35
|
+
* 右半残留在新字素续格下」的新旧混叠。
|
|
36
|
+
*/
|
|
37
|
+
export class CellGrid {
|
|
38
|
+
columns;
|
|
39
|
+
rows;
|
|
40
|
+
/** 网格(行主序一维;null = 未写格——语义投影为缺省空格) */
|
|
41
|
+
grid;
|
|
42
|
+
/** 本帧光标声明终值(末次声明为准;clearCursor 置 null) */
|
|
43
|
+
cursorState = null;
|
|
44
|
+
constructor(columns = 80, rows = 24) {
|
|
45
|
+
this.columns = columns;
|
|
46
|
+
this.rows = rows;
|
|
47
|
+
this.grid = new Array(columns * rows).fill(null);
|
|
48
|
+
}
|
|
49
|
+
/** 摘格清屏(网格结构复用零分配——帧间清屏 / 全量重绘入口) */
|
|
50
|
+
clear() {
|
|
51
|
+
this.grid.fill(null);
|
|
52
|
+
this.cursorState = null;
|
|
53
|
+
}
|
|
54
|
+
getCell(row, col) {
|
|
55
|
+
if (row < 0 || row >= this.rows || col < 0 || col >= this.columns)
|
|
56
|
+
return null;
|
|
57
|
+
return this.grid[row * this.columns + col] ?? null; // noUncheckedIndexedAccess 归一
|
|
58
|
+
}
|
|
59
|
+
setCell(row, col, grapheme, style = EMPTY_STYLE) {
|
|
60
|
+
// 越界写静默吸收(渲染契约「越界写由缓冲吸收」——组件可信任缓冲兜底)
|
|
61
|
+
if (row < 0 || row >= this.rows || col < 0 || col >= this.columns)
|
|
62
|
+
return;
|
|
63
|
+
const width = graphemeWidth(grapheme);
|
|
64
|
+
if (width === 0)
|
|
65
|
+
return; // 零宽字素不占格(splitGraphemes 已合流,防御位)
|
|
66
|
+
// 摘痕:覆写区内既有宽字素整字摘除(见类注——防新旧混叠)
|
|
67
|
+
this.eraseWideGraphemes(row, col, width);
|
|
68
|
+
// 写首格 + 续格(宽字素右界越界时续格截断丢弃——缓冲兜底;渲染层
|
|
69
|
+
// truncateToWidth 已保证整字不跨界,此为双保险)
|
|
70
|
+
const base = row * this.columns;
|
|
71
|
+
this.grid[base + col] = { grapheme, style, width: width };
|
|
72
|
+
if (width === 2 && col + 1 < this.columns) {
|
|
73
|
+
this.grid[base + col + 1] = { grapheme: '', style, width: 0 };
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
writeText(row, col, text, style) {
|
|
77
|
+
let cursor = col;
|
|
78
|
+
for (const g of splitGraphemes(text)) {
|
|
79
|
+
this.setCell(row, cursor, g, style);
|
|
80
|
+
cursor += graphemeWidth(g);
|
|
81
|
+
}
|
|
82
|
+
return cursor;
|
|
83
|
+
}
|
|
84
|
+
setCursor(row, col) {
|
|
85
|
+
this.cursorState = { row, col, visible: true };
|
|
86
|
+
}
|
|
87
|
+
clearCursor() {
|
|
88
|
+
this.cursorState = null;
|
|
89
|
+
}
|
|
90
|
+
get cursor() {
|
|
91
|
+
return this.cursorState;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* 几何变更(唯一重分配点):网格整体弃置重分配、内容不搬运——
|
|
95
|
+
* 「resize 弃旧换新(不做原地搬运——宽字符 reflow 后必失真)」的缓冲侧
|
|
96
|
+
* 承接,清屏 + 全量重绘兜底归引擎编排件(批 10c)。
|
|
97
|
+
*/
|
|
98
|
+
resize(columns, rows) {
|
|
99
|
+
this.columns = columns;
|
|
100
|
+
this.rows = rows;
|
|
101
|
+
this.grid = new Array(columns * rows).fill(null);
|
|
102
|
+
this.cursorState = null;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* 摘痕原语:把 [col, col+span) 区间(含右邻溢出格——被覆字素可能右探一格)
|
|
106
|
+
* 内牵连的既有宽字素整字摘除。逐格查:续格回溯首格、首格顺摘续格。
|
|
107
|
+
*/
|
|
108
|
+
eraseWideGraphemes(row, col, span) {
|
|
109
|
+
const base = row * this.columns;
|
|
110
|
+
for (let i = col; i <= Math.min(col + span, this.columns - 1); i++) {
|
|
111
|
+
const cell = this.grid[base + i];
|
|
112
|
+
if (!cell)
|
|
113
|
+
continue;
|
|
114
|
+
if (cell.width === 0) {
|
|
115
|
+
// 续格:回溯其首格并整字摘除
|
|
116
|
+
let head = i - 1;
|
|
117
|
+
while (head >= 0) {
|
|
118
|
+
const probe = this.grid[base + head];
|
|
119
|
+
if (probe && probe.width !== 0)
|
|
120
|
+
break;
|
|
121
|
+
head--;
|
|
122
|
+
}
|
|
123
|
+
if (head >= 0 && this.grid[base + head]?.width === 2) {
|
|
124
|
+
this.grid[base + head] = null;
|
|
125
|
+
// 顺摘首格右侧全部续格(可能多格?——续格恰一格,但防御性扫到非续格止)
|
|
126
|
+
let tail = head + 1;
|
|
127
|
+
while (tail < this.columns && this.grid[base + tail]?.width === 0) {
|
|
128
|
+
this.grid[base + tail] = null;
|
|
129
|
+
tail++;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
this.grid[base + i] = null;
|
|
133
|
+
}
|
|
134
|
+
else if (cell.width === 2) {
|
|
135
|
+
// 首格:摘自己 + 右侧续格
|
|
136
|
+
this.grid[base + i] = null;
|
|
137
|
+
if (i + 1 < this.columns && this.grid[base + i + 1]?.width === 0) {
|
|
138
|
+
this.grid[base + i + 1] = null;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 行级差分件(07 篇 §4.1 自研引擎节件 3——批 10b 引擎核心)。
|
|
3
|
+
*
|
|
4
|
+
* 帧差分增量写出纪律:
|
|
5
|
+
* - 无变更帧零写出、未变行零写出(行粒度比较——cellEquals 逐格直比);
|
|
6
|
+
* - 行尾变空白一律 EL 清行**禁空格填充**(空格填充闪烁史反课——擦除只走
|
|
7
|
+
* EL,永不写空格游程);
|
|
8
|
+
* - EL 前置样式复位(BCE 语义——EL 以当前背景色擦除,带背景样式发 EL 会
|
|
9
|
+
* 把擦除区染上底色污染行尾,故先 SGR 复位再 EL);
|
|
10
|
+
* - 帧尾光标统一落位(定位 + 显 / 隐),显隐态跨帧去重——同态零冗余序列;
|
|
11
|
+
* **双零(内容与光标均零变更)才整帧零写出**。
|
|
12
|
+
*
|
|
13
|
+
* 纯函数:from / to 两帧只读比对产 ANSI 字节串;帧管线(请求合并 / 帧率帽)
|
|
14
|
+
* 归引擎编排件(批 10c)。前置条件:两帧同几何——resize 路径编排侧清屏全量
|
|
15
|
+
* 重绘不走本函数,几何不同即编程错、fail-loud。
|
|
16
|
+
*/
|
|
17
|
+
import { cellEquals, EMPTY_STYLE, styleEquals } from './cell.js';
|
|
18
|
+
const ESC = '\x1b';
|
|
19
|
+
/** 光标定位(1 基转义序列——row/col 为 0 基入参) */
|
|
20
|
+
const cup = (row, col) => `${ESC}[${row + 1};${col + 1}H`;
|
|
21
|
+
const EL_TO_EOL = `${ESC}[K`; // EL 0:自光标至行尾
|
|
22
|
+
const SGR_RESET = `${ESC}[0m`;
|
|
23
|
+
const HIDE_CURSOR = `${ESC}[?25l`;
|
|
24
|
+
const SHOW_CURSOR = `${ESC}[?25h`;
|
|
25
|
+
/** 样式 → SGR 序列(全量形——属性位 + 16 色前景背景;空样式返回空串由调用方复位) */
|
|
26
|
+
function buildSgr(style) {
|
|
27
|
+
const params = [];
|
|
28
|
+
if (style.bold)
|
|
29
|
+
params.push('1');
|
|
30
|
+
if (style.dim)
|
|
31
|
+
params.push('2');
|
|
32
|
+
if (style.italic)
|
|
33
|
+
params.push('3');
|
|
34
|
+
if (style.underline)
|
|
35
|
+
params.push('4');
|
|
36
|
+
if (style.inverse)
|
|
37
|
+
params.push('7');
|
|
38
|
+
if (style.fg !== undefined) {
|
|
39
|
+
// 前景 16 色:0-7 标准位 30+n / 8-15 亮位 90+(n-8)
|
|
40
|
+
params.push(String(style.fg < 8 ? 30 + style.fg : 82 + style.fg));
|
|
41
|
+
}
|
|
42
|
+
if (style.bg !== undefined) {
|
|
43
|
+
// 背景 16 色:0-7 标准位 40+n / 8-15 亮位 100+(n-8)
|
|
44
|
+
params.push(String(style.bg < 8 ? 40 + style.bg : 92 + style.bg));
|
|
45
|
+
}
|
|
46
|
+
return params.length > 0 ? `${ESC}[${params.join(';')}m` : '';
|
|
47
|
+
}
|
|
48
|
+
/** 单帧行级差分:返回本帧应写出的 ANSI 字节串(零变更返回空串) */
|
|
49
|
+
export function renderFrameDiff(from, to) {
|
|
50
|
+
if (from.columns !== to.columns || from.rows !== to.rows) {
|
|
51
|
+
// 几何不同是编程错(resize 路径编排侧清屏全量重绘)——fail-loud 不产半帧
|
|
52
|
+
throw new Error(`renderFrameDiff: 两帧几何不同(${from.columns}x${from.rows} vs ${to.columns}x${to.rows})——resize 路径不走帧差分`);
|
|
53
|
+
}
|
|
54
|
+
let out = '';
|
|
55
|
+
/** 帧首光标抑制是否已发(有写出才发——防写内容过程光标跳;幂等只发一次) */
|
|
56
|
+
let cursorSuppressed = false;
|
|
57
|
+
const suppress = () => {
|
|
58
|
+
if (!cursorSuppressed) {
|
|
59
|
+
out += HIDE_CURSOR;
|
|
60
|
+
cursorSuppressed = true;
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
for (let row = 0; row < to.rows; row++) {
|
|
64
|
+
if (rowEquals(from, to, row))
|
|
65
|
+
continue; // 未变行零写出
|
|
66
|
+
suppress();
|
|
67
|
+
out += renderRowDiff(from, to, row);
|
|
68
|
+
}
|
|
69
|
+
// 帧尾光标统一落位(显隐跨帧去重——同态零冗余序列)
|
|
70
|
+
out += renderCursorDiff(from, to, cursorSuppressed);
|
|
71
|
+
return out;
|
|
72
|
+
}
|
|
73
|
+
/** 行相等判定(逐格 cellEquals 直比——null 归一语义在 cellEquals 内) */
|
|
74
|
+
function rowEquals(from, to, row) {
|
|
75
|
+
for (let col = 0; col < to.columns; col++) {
|
|
76
|
+
if (!cellEquals(from.getCell(row, col), to.getCell(row, col)))
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
return true;
|
|
80
|
+
}
|
|
81
|
+
/** 单变行差分:定位 + 写内容 + 行尾残留 EL(禁空格填充——擦除只走 EL) */
|
|
82
|
+
function renderRowDiff(from, to, row) {
|
|
83
|
+
let out = '';
|
|
84
|
+
// 内容末列 = 最右语义非空格格(无样式空格与未写格语义等价、不算内容);
|
|
85
|
+
// 续格(width 0)属首格字素占位、算内容延伸
|
|
86
|
+
let lastContentCol = -1;
|
|
87
|
+
for (let col = to.columns - 1; col >= 0; col--) {
|
|
88
|
+
if (!cellEquals(to.getCell(row, col), null)) {
|
|
89
|
+
lastContentCol = col;
|
|
90
|
+
break;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
if (lastContentCol < 0) {
|
|
94
|
+
// 新帧整行空:定位行首 + 样式复位 + EL 清行(旧帧有残留才到得了本分支)
|
|
95
|
+
return cup(row, 0) + SGR_RESET + EL_TO_EOL;
|
|
96
|
+
}
|
|
97
|
+
// 定位行首并复位样式(跨行样式残留归零——确定态起写)
|
|
98
|
+
out += cup(row, 0) + SGR_RESET;
|
|
99
|
+
let currentStyle = EMPTY_STYLE;
|
|
100
|
+
for (let col = 0; col <= lastContentCol; col++) {
|
|
101
|
+
const cell = to.getCell(row, col);
|
|
102
|
+
if (cell !== null && cell.width === 0)
|
|
103
|
+
continue; // 续格跳过——首格字素已携双宽
|
|
104
|
+
const style = cell?.style ?? EMPTY_STYLE;
|
|
105
|
+
if (!styleEquals(currentStyle, style)) {
|
|
106
|
+
// 样式变更点:先复位再全量设(差量 SGR 优化不预造——闪烁面留给组件批实证)
|
|
107
|
+
out += SGR_RESET + buildSgr(style);
|
|
108
|
+
currentStyle = style;
|
|
109
|
+
}
|
|
110
|
+
out += cell === null ? ' ' : cell.grapheme; // 语义空格(行中内容洞)写字面空格
|
|
111
|
+
}
|
|
112
|
+
// 行尾残留:旧帧在内容末之后还有语义非空格格 → 复位 + EL(BCE:复位后擦除
|
|
113
|
+
// 才不染背景色)。内容写满至行尾列则无擦除空间、天然无残留可清。
|
|
114
|
+
for (let col = lastContentCol + 1; col < to.columns; col++) {
|
|
115
|
+
if (!cellEquals(from.getCell(row, col), null)) {
|
|
116
|
+
out += SGR_RESET + EL_TO_EOL;
|
|
117
|
+
break;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return out;
|
|
121
|
+
}
|
|
122
|
+
/** 帧尾光标落位(跨帧同态去重——值全等即零序列) */
|
|
123
|
+
function renderCursorDiff(from, to, cursorSuppressed) {
|
|
124
|
+
const fromCursor = from.cursor;
|
|
125
|
+
const toCursor = to.cursor;
|
|
126
|
+
// 同态(含双 null / 值全等)零冗余序列——「显隐态跨帧去重」执法位
|
|
127
|
+
if (fromCursor === null && toCursor === null)
|
|
128
|
+
return '';
|
|
129
|
+
if (fromCursor !== null && toCursor !== null && cursorSame(fromCursor, toCursor)) {
|
|
130
|
+
// 内容有写出且帧首已抑制光标、声明仍显 → 恢复显示在原位(抑制的反向配对)
|
|
131
|
+
if (cursorSuppressed)
|
|
132
|
+
return SHOW_CURSOR + cup(toCursor.row, toCursor.col);
|
|
133
|
+
return '';
|
|
134
|
+
}
|
|
135
|
+
if (toCursor === null)
|
|
136
|
+
return HIDE_CURSOR; // 显 → 隐
|
|
137
|
+
// 隐 → 显 / 位置迁移:显 + 定位(SHOW 幂等——重复发无害;帧首抑制已发则仍显式定位)
|
|
138
|
+
return SHOW_CURSOR + cup(toCursor.row, toCursor.col);
|
|
139
|
+
}
|
|
140
|
+
/** 光标声明值相等(row / col / visible 三元) */
|
|
141
|
+
function cursorSame(a, b) {
|
|
142
|
+
return a.row === b.row && a.col === b.col && a.visible === b.visible;
|
|
143
|
+
}
|