pneuma-skills 1.6.2 → 1.7.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.md +15 -9
- package/bin/pneuma.ts +16 -9
- package/core/__tests__/viewer-contract.test.ts +209 -0
- package/core/types/index.ts +7 -0
- package/core/types/mode-manifest.ts +21 -0
- package/core/types/viewer-contract.ts +94 -3
- package/dist/assets/{EditorPanel-MdL_JiTY.js → EditorPanel-D-Xzb0UT.js} +1 -1
- package/dist/assets/{TerminalPanel-CbFaJVv1.js → TerminalPanel--jJmEknZ.js} +1 -1
- package/dist/assets/{ar-SA-G6X2FPQ2-DI1IvzZy.js → ar-SA-G6X2FPQ2-DEYeWkoJ.js} +1 -1
- package/dist/assets/{arc-D165-OAx.js → arc-B1aGAj1G.js} +1 -1
- package/dist/assets/{az-AZ-76LH7QW2-DYGh7wld.js → az-AZ-76LH7QW2-36P-oGNr.js} +1 -1
- package/dist/assets/{bg-BG-XCXSNQG7-BPdSa6MK.js → bg-BG-XCXSNQG7-o-5anNLs.js} +1 -1
- package/dist/assets/{blockDiagram-38ab4fdb-CEu2OzeC.js → blockDiagram-38ab4fdb-C-B2x2vq.js} +1 -1
- package/dist/assets/{bn-BD-2XOGV67Q-DkIs-slB.js → bn-BD-2XOGV67Q-7BTOK1Pm.js} +1 -1
- package/dist/assets/{c4Diagram-3d4e48cf-DoIsm8EF.js → c4Diagram-3d4e48cf-BYHhg73S.js} +1 -1
- package/dist/assets/{ca-ES-6MX7JW3Y-L170HCw7.js → ca-ES-6MX7JW3Y-BI9kKsDN.js} +1 -1
- package/dist/assets/channel-0wL-Mb1i.js +1 -0
- package/dist/assets/{classDiagram-70f12bd4-QQ76MqW5.js → classDiagram-70f12bd4-A9Ur8RF0.js} +1 -1
- package/dist/assets/{classDiagram-v2-f2320105-BmabMbok.js → classDiagram-v2-f2320105-BZ97-FiS.js} +1 -1
- package/dist/assets/clone-B7lVwD5_.js +1 -0
- package/dist/assets/{createText-2e5e7dd3-tL3VdL-p.js → createText-2e5e7dd3-jR7PHzqx.js} +1 -1
- package/dist/assets/{cs-CZ-2BRQDIVT-d9QyNfe3.js → cs-CZ-2BRQDIVT-DWAcAJ5n.js} +1 -1
- package/dist/assets/{da-DK-5WZEPLOC-C9h-0UH1.js → da-DK-5WZEPLOC-CeYJVcTQ.js} +1 -1
- package/dist/assets/{de-DE-XR44H4JA-0_J2pE7J.js → de-DE-XR44H4JA-GafhllsH.js} +1 -1
- package/dist/assets/{edges-e0da2a9e-9Gd7e5_q.js → edges-e0da2a9e-U8scTAnp.js} +1 -1
- package/dist/assets/{el-GR-BZB4AONW-CPGoB07j.js → el-GR-BZB4AONW-BSQjwQkC.js} +1 -1
- package/dist/assets/{erDiagram-9861fffd--6rJdAlm.js → erDiagram-9861fffd-CmKWBN-l.js} +1 -1
- package/dist/assets/{es-ES-U4NZUMDT-0MvEQWSD.js → es-ES-U4NZUMDT-CQAm4Mwh.js} +1 -1
- package/dist/assets/{eu-ES-A7QVB2H4-BRU3FvSm.js → eu-ES-A7QVB2H4-CrylMmNc.js} +1 -1
- package/dist/assets/{fa-IR-HGAKTJCU-CnBKZHHO.js → fa-IR-HGAKTJCU-DDZCEyKj.js} +1 -1
- package/dist/assets/{fi-FI-Z5N7JZ37-BgG37SFV.js → fi-FI-Z5N7JZ37-C4x4hPQ6.js} +1 -1
- package/dist/assets/{flowDb-956e92f1-DLjSZLGX.js → flowDb-956e92f1-BbWhF1ea.js} +1 -1
- package/dist/assets/{flowDiagram-66a62f08-B3qKWVtA.js → flowDiagram-66a62f08-BIQUcN_l.js} +1 -1
- package/dist/assets/flowDiagram-v2-96b9c2cf-B07s6wKi.js +1 -0
- package/dist/assets/{flowchart-elk-definition-4a651766-tTc1ftqg.js → flowchart-elk-definition-4a651766-Bo9CL9Zs.js} +1 -1
- package/dist/assets/{fr-FR-RHASNOE6-Jl6lji35.js → fr-FR-RHASNOE6-BqLaUIpN.js} +1 -1
- package/dist/assets/{ganttDiagram-c361ad54-lSzFV-3P.js → ganttDiagram-c361ad54-Cf9ILd98.js} +1 -1
- package/dist/assets/{gitGraphDiagram-72cf32ee-7SNlQmFU.js → gitGraphDiagram-72cf32ee-9sSX38SV.js} +1 -1
- package/dist/assets/{gl-ES-HMX3MZ6V-BFbSruD0.js → gl-ES-HMX3MZ6V-C3uE1q3b.js} +1 -1
- package/dist/assets/{graph-BcpGRXRu.js → graph-C7wy9lNH.js} +1 -1
- package/dist/assets/{he-IL-6SHJWFNN-BNLVLLSm.js → he-IL-6SHJWFNN-MF5MaGy0.js} +1 -1
- package/dist/assets/{hi-IN-IWLTKZ5I-Dsj3ZWPl.js → hi-IN-IWLTKZ5I-BbkFDRsT.js} +1 -1
- package/dist/assets/{hu-HU-A5ZG7DT2-DCbDqW_4.js → hu-HU-A5ZG7DT2-hxjfSPrj.js} +1 -1
- package/dist/assets/{id-ID-SAP4L64H-BmeTOocX.js → id-ID-SAP4L64H-6-VwOKBX.js} +1 -1
- package/dist/assets/{index-3862675e-DIhdBfTo.js → index-3862675e-DdLf9jEE.js} +1 -1
- package/dist/assets/{index-qUAZT-v0.js → index-B2NgcflK.js} +4 -4
- package/dist/assets/index-BKxNwozV.css +1 -0
- package/dist/assets/index-DmVx_FQq.js +95 -0
- package/dist/assets/index-joEipVLK.js +1 -0
- package/dist/assets/{infoDiagram-f8f76790-GkJF5VfW.js → infoDiagram-f8f76790-C_fsKuE6.js} +1 -1
- package/dist/assets/{it-IT-JPQ66NNP-B7_H3wxP.js → it-IT-JPQ66NNP-C1QWJk7F.js} +1 -1
- package/dist/assets/{ja-JP-DBVTYXUO-Kiyckl1D.js → ja-JP-DBVTYXUO-DDVc_l2z.js} +1 -1
- package/dist/assets/{journeyDiagram-49397b02-BgjYuH61.js → journeyDiagram-49397b02-BvaCNJN7.js} +1 -1
- package/dist/assets/{kaa-6HZHGXH3-C9JGzPVZ.js → kaa-6HZHGXH3-bcuv6E1h.js} +1 -1
- package/dist/assets/{kab-KAB-ZGHBKWFO-Byx6HzwL.js → kab-KAB-ZGHBKWFO-DOKeeXCt.js} +1 -1
- package/dist/assets/{kk-KZ-P5N5QNE5-Cgk7qzOf.js → kk-KZ-P5N5QNE5-CekykWvn.js} +1 -1
- package/dist/assets/{km-KH-HSX4SM5Z-Elll5unm.js → km-KH-HSX4SM5Z-C5sRJcDc.js} +1 -1
- package/dist/assets/{ko-KR-MTYHY66A-CsOtBxCZ.js → ko-KR-MTYHY66A-BwUv0GPN.js} +1 -1
- package/dist/assets/{ku-TR-6OUDTVRD-CuTEXM4p.js → ku-TR-6OUDTVRD-D5cGeMly.js} +1 -1
- package/dist/assets/{layout-CUWfUNS2.js → layout-D_1xp_6m.js} +1 -1
- package/dist/assets/{line-CVwrY-Vb.js → line-DNXF85tN.js} +1 -1
- package/dist/assets/{linear-BrME-eAl.js → linear-BztL3UDL.js} +1 -1
- package/dist/assets/{lt-LT-XHIRWOB4-C8c0WkUW.js → lt-LT-XHIRWOB4-DeBXYkHY.js} +1 -1
- package/dist/assets/{lv-LV-5QDEKY6T-CEKRGmw8.js → lv-LV-5QDEKY6T-N4Yh5M6g.js} +1 -1
- package/dist/assets/{manifest-BHamNdmX.js → manifest-Ckc6r0Wm.js} +1 -1
- package/dist/assets/{manifest-BQEiVmuZ.js → manifest-D2MnWyhO.js} +1 -1
- package/dist/assets/{manifest-CjjXAwgC.js → manifest-w9cFk2IG.js} +1 -1
- package/dist/assets/{mindmap-definition-fc14e90a-U0UAQ-Fw.js → mindmap-definition-fc14e90a-gVuhVhfo.js} +1 -1
- package/dist/assets/{mr-IN-CRQNXWMA-CTxbfZqj.js → mr-IN-CRQNXWMA-BFKQIG7E.js} +1 -1
- package/dist/assets/{my-MM-5M5IBNSE-DcDY6QTm.js → my-MM-5M5IBNSE-B9jQ7smi.js} +1 -1
- package/dist/assets/{nb-NO-T6EIAALU-C6KHf4vB.js → nb-NO-T6EIAALU-BbBpbOcx.js} +1 -1
- package/dist/assets/{nl-NL-IS3SIHDZ-BGmeQ17q.js → nl-NL-IS3SIHDZ-BdLpCHya.js} +1 -1
- package/dist/assets/{nn-NO-6E72VCQL-C-tmVDb4.js → nn-NO-6E72VCQL-CVtfj1vA.js} +1 -1
- package/dist/assets/{oc-FR-POXYY2M6-C5fnow4b.js → oc-FR-POXYY2M6-D9qTCxvP.js} +1 -1
- package/dist/assets/{pa-IN-N4M65BXN-D6t69GoD.js → pa-IN-N4M65BXN-BLHhJlQA.js} +1 -1
- package/dist/assets/{percentages-BXMCSKIN-CuqegRFs.js → percentages-BXMCSKIN-Bl-rrwAb.js} +7 -7
- package/dist/assets/{pica-DICzK7iG.js → pica-jesPWBk1.js} +1 -1
- package/dist/assets/{pieDiagram-8a3498a8-CbbXLjm7.js → pieDiagram-8a3498a8-BP0ZHwKh.js} +1 -1
- package/dist/assets/{pl-PL-T2D74RX3-DER2H0wo.js → pl-PL-T2D74RX3-d1GpkH6m.js} +1 -1
- package/dist/assets/pneuma-mode-BVYQ3Qh_.js +5 -0
- package/dist/assets/pneuma-mode-CPx9PyGm.js +315 -0
- package/dist/assets/pneuma-mode-DcNMw9rn.js +8 -0
- package/dist/assets/{pt-BR-5N22H2LF-CJHfbbIQ.js → pt-BR-5N22H2LF-CTHPkVAQ.js} +1 -1
- package/dist/assets/{pt-PT-UZXXM6DQ-CkCsXMDT.js → pt-PT-UZXXM6DQ-BWrBYL_s.js} +1 -1
- package/dist/assets/{quadrantDiagram-120e2f19-D_mc357R.js → quadrantDiagram-120e2f19-2YaTIm7H.js} +1 -1
- package/dist/assets/{requirementDiagram-deff3bca-zCTbZYaF.js → requirementDiagram-deff3bca-DNMAR50V.js} +1 -1
- package/dist/assets/{ro-RO-JPDTUUEW-BSHMxikS.js → ro-RO-JPDTUUEW-DEK2V9fV.js} +1 -1
- package/dist/assets/{ru-RU-B4JR7IUQ-DhnnXCsj.js → ru-RU-B4JR7IUQ-CRqCBv4b.js} +1 -1
- package/dist/assets/{sankeyDiagram-04a897e0-BvDjTJE5.js → sankeyDiagram-04a897e0-CZhnknln.js} +1 -1
- package/dist/assets/{sequenceDiagram-704730f1-DyDtB4bR.js → sequenceDiagram-704730f1-Clrxz8db.js} +1 -1
- package/dist/assets/{si-LK-N5RQ5JYF-CBpcfcVd.js → si-LK-N5RQ5JYF-hvn9mLvJ.js} +1 -1
- package/dist/assets/{sk-SK-C5VTKIMK-AQrsUpWY.js → sk-SK-C5VTKIMK-C0DRkLja.js} +1 -1
- package/dist/assets/{sl-SI-NN7IZMDC-CT83Tcto.js → sl-SI-NN7IZMDC-CJ-NioP1.js} +1 -1
- package/dist/assets/{stateDiagram-587899a1-BLA3XkRF.js → stateDiagram-587899a1-BsRIwfy-.js} +1 -1
- package/dist/assets/{stateDiagram-v2-d93cdb3a-DR7IYUqf.js → stateDiagram-v2-d93cdb3a-D9gpT5Rk.js} +1 -1
- package/dist/assets/{styles-6aaf32cf-D2GttATi.js → styles-6aaf32cf-BRsej5x8.js} +1 -1
- package/dist/assets/{styles-9a916d00-BpiIjJGB.js → styles-9a916d00-C6hbEXw6.js} +1 -1
- package/dist/assets/{styles-c10674c1-DvdNSnC7.js → styles-c10674c1-C4arR4zp.js} +1 -1
- package/dist/assets/{subset-shared.chunk-B4kMbE2H.js → subset-shared.chunk-B7JfMLQB.js} +1 -1
- package/dist/assets/{subset-worker.chunk-CPiIs6nq.js → subset-worker.chunk-DT-Mu9P4.js} +1 -1
- package/dist/assets/{sv-SE-XGPEYMSR-BoK_Plbz.js → sv-SE-XGPEYMSR-BcCbiRPD.js} +1 -1
- package/dist/assets/{svgDrawCommon-08f97a94-3WJM28cv.js → svgDrawCommon-08f97a94-CXviZVcP.js} +1 -1
- package/dist/assets/{ta-IN-2NMHFXQM-d4L55p0Z.js → ta-IN-2NMHFXQM-B43FI7HH.js} +1 -1
- package/dist/assets/{th-TH-HPSO5L25-BM_rrii7.js → th-TH-HPSO5L25-CQJRbYxw.js} +1 -1
- package/dist/assets/{timeline-definition-85554ec2-CyUtcC-f.js → timeline-definition-85554ec2-C4ais6Qj.js} +1 -1
- package/dist/assets/{tr-TR-DEFEU3FU-HX-ieOrB.js → tr-TR-DEFEU3FU-COffkYHh.js} +1 -1
- package/dist/assets/{uk-UA-QMV73CPH-BLoCnHH_.js → uk-UA-QMV73CPH-DGHz6r89.js} +1 -1
- package/dist/assets/{vi-VN-M7AON7JQ-25ijC9l1.js → vi-VN-M7AON7JQ-bEWKpDTV.js} +1 -1
- package/dist/assets/{xychartDiagram-e933f94c-BnuVVpgF.js → xychartDiagram-e933f94c-DDLoS3KJ.js} +1 -1
- package/dist/assets/{zh-CN-LNUGB5OW-C40B56rX.js → zh-CN-LNUGB5OW-BdLk07IA.js} +1 -1
- package/dist/assets/{zh-HK-E62DVLB3-NkoZbsR_.js → zh-HK-E62DVLB3-C9_sKRCo.js} +1 -1
- package/dist/assets/{zh-TW-RAJ6MFWO-DVkT3BzC.js → zh-TW-RAJ6MFWO-D1lVeDjl.js} +1 -1
- package/dist/index.html +2 -2
- package/modes/doc/manifest.ts +4 -0
- package/modes/doc/pneuma-mode.ts +17 -9
- package/modes/doc/viewer/DocPreview.tsx +111 -2
- package/modes/draw/manifest.ts +4 -0
- package/modes/draw/pneuma-mode.ts +25 -13
- package/modes/draw/viewer/DrawPreview.tsx +135 -17
- package/modes/slide/manifest.ts +20 -0
- package/modes/slide/pneuma-mode.ts +60 -30
- package/modes/slide/viewer/SlidePreview.tsx +29 -0
- package/package.json +1 -1
- package/server/__tests__/skill-installer.test.ts +107 -2
- package/server/__tests__/ws-bridge-browser.test.ts +1 -0
- package/server/__tests__/ws-bridge-controls.test.ts +1 -0
- package/server/__tests__/ws-bridge-replay.test.ts +1 -0
- package/server/index.ts +15 -0
- package/server/session-types.ts +4 -2
- package/server/skill-installer.ts +92 -1
- package/server/ws-bridge-types.ts +2 -0
- package/server/ws-bridge-viewer.ts +62 -0
- package/server/ws-bridge.ts +28 -0
- package/dist/assets/channel-D5iBNjbH.js +0 -1
- package/dist/assets/clone-BEE8hBIa.js +0 -1
- package/dist/assets/flowDiagram-v2-96b9c2cf-DSrHZQLe.js +0 -1
- package/dist/assets/index-DB9RcBPw.css +0 -1
- package/dist/assets/index-DE39xQEr.js +0 -95
- package/dist/assets/index-DcCNGeQt.js +0 -1
- package/dist/assets/pneuma-mode-D2DgSpg6.js +0 -313
- package/dist/assets/pneuma-mode-DlMa-HY8.js +0 -3
- package/dist/assets/pneuma-mode-Ogulzc3b.js +0 -6
package/README.md
CHANGED
|
@@ -80,6 +80,7 @@ Options:
|
|
|
80
80
|
--workspace <path> Target workspace directory (default: current directory)
|
|
81
81
|
--port <number> Server port (default: 17996)
|
|
82
82
|
--no-open Don't auto-open the browser
|
|
83
|
+
--debug Enable debug mode (inspect enriched CLI payloads)
|
|
83
84
|
```
|
|
84
85
|
|
|
85
86
|
### Remote / External Modes
|
|
@@ -116,7 +117,7 @@ Pneuma is organized in four layers, each with a clear contract boundary:
|
|
|
116
117
|
│ modes/doc/pneuma-mode.ts │
|
|
117
118
|
├─────────────────────────────────────────────────────────┤
|
|
118
119
|
│ Layer 3: Content Viewer │
|
|
119
|
-
│ ViewerContract — "how to render, select,
|
|
120
|
+
│ ViewerContract — "how to render, select, align" │
|
|
120
121
|
│ modes/doc/viewer/DocPreview.tsx │
|
|
121
122
|
├─────────────────────────────────────────────────────────┤
|
|
122
123
|
│ Layer 2: Agent Bridge │
|
|
@@ -140,10 +141,10 @@ When Claude Code edits files, chokidar detects the changes and pushes updated co
|
|
|
140
141
|
| Contract | Responsibility | Extend to... |
|
|
141
142
|
|----------|---------------|-------------|
|
|
142
143
|
| **ModeManifest** | Declares skill, viewer config, agent preferences, init seeds | Add new modes (mindmap, canvas, etc.) |
|
|
143
|
-
| **ViewerContract** | Preview component, context extraction,
|
|
144
|
+
| **ViewerContract** | Preview component, context extraction, file workspace model, agent-callable actions | Custom renderers, viewport tracking, action protocols |
|
|
144
145
|
| **AgentBackend** | Launch, resume, kill, capability declaration | Other agents (Codex, Aider) |
|
|
145
146
|
|
|
146
|
-
Contracts are defined in `core/types/` with
|
|
147
|
+
Contracts are defined in `core/types/` with 208 tests across `core/__tests__/` and `server/__tests__/`.
|
|
147
148
|
|
|
148
149
|
## Project Structure
|
|
149
150
|
|
|
@@ -152,14 +153,14 @@ pneuma-skills/
|
|
|
152
153
|
├── bin/pneuma.ts # CLI entry — orchestrates mode + agent + server
|
|
153
154
|
├── core/
|
|
154
155
|
│ ├── types/ # Contract definitions
|
|
155
|
-
│ │ ├── mode-manifest.ts # ModeManifest, SkillConfig, ViewerConfig
|
|
156
|
-
│ │ ├── viewer-contract.ts # ViewerContract,
|
|
156
|
+
│ │ ├── mode-manifest.ts # ModeManifest, SkillConfig, ViewerConfig, ViewerApi
|
|
157
|
+
│ │ ├── viewer-contract.ts # ViewerContract, FileWorkspaceModel, ViewerAction*
|
|
157
158
|
│ │ ├── agent-backend.ts # AgentBackend, AgentCapabilities
|
|
158
159
|
│ │ ├── mode-definition.ts # ModeDefinition (manifest + viewer)
|
|
159
160
|
│ │ └── index.ts # Re-exports
|
|
160
161
|
│ ├── mode-loader.ts # Dynamic mode discovery and loading (builtin + external)
|
|
161
162
|
│ ├── mode-resolver.ts # Mode source resolution (builtin/local/github)
|
|
162
|
-
│ └── __tests__/ #
|
|
163
|
+
│ └── __tests__/ # Contract tests
|
|
163
164
|
├── modes/
|
|
164
165
|
│ ├── doc/
|
|
165
166
|
│ │ ├── pneuma-mode.ts # Doc Mode definition (manifest + viewer)
|
|
@@ -181,11 +182,12 @@ pneuma-skills/
|
|
|
181
182
|
│ ├── index.ts # ClaudeCodeBackend implements AgentBackend
|
|
182
183
|
│ └── cli-launcher.ts # Process spawner (Bun.spawn + --sdk-url)
|
|
183
184
|
├── server/
|
|
184
|
-
│ ├── index.ts # Hono HTTP server + content
|
|
185
|
-
│ ├── ws-bridge.ts # Dual WebSocket bridge (browser ↔ CLI)
|
|
185
|
+
│ ├── index.ts # Hono HTTP server + WS routing + content/viewer APIs
|
|
186
|
+
│ ├── ws-bridge.ts # Dual WebSocket bridge (browser JSON ↔ CLI NDJSON)
|
|
187
|
+
│ ├── ws-bridge-viewer.ts # Viewer action request/response routing
|
|
186
188
|
│ ├── ws-bridge-*.ts # Controls, replay, browser handlers, types
|
|
187
189
|
│ ├── file-watcher.ts # chokidar watcher (manifest-driven patterns)
|
|
188
|
-
│ ├── skill-installer.ts # Copies skill prompts
|
|
190
|
+
│ ├── skill-installer.ts # Copies skill prompts + template engine
|
|
189
191
|
│ └── terminal-manager.ts # PTY terminal sessions
|
|
190
192
|
├── src/
|
|
191
193
|
│ ├── App.tsx # Root layout (dynamic viewer from store)
|
|
@@ -238,6 +240,9 @@ pneuma-skills/
|
|
|
238
240
|
- **Background processes** — Monitor long-running background commands
|
|
239
241
|
- **Context visualization** — Rich `/context` card with category breakdown and stacked bar
|
|
240
242
|
- **Image upload** — Drag & drop or paste images into chat
|
|
243
|
+
- **Viewer context enrichment** — `<viewer-context>` XML blocks align agent perception with user viewport
|
|
244
|
+
- **Viewer action protocol** — Agent can invoke viewer capabilities (navigate, toggle UI, capture)
|
|
245
|
+
- **Debug mode** — `--debug` flag shows enriched CLI payloads for each message
|
|
241
246
|
|
|
242
247
|
## Roadmap
|
|
243
248
|
|
|
@@ -248,6 +253,7 @@ pneuma-skills/
|
|
|
248
253
|
- [x] Session persistence & resume
|
|
249
254
|
- [x] Terminal, tasks, context panel
|
|
250
255
|
- [x] v1.0 contract architecture (ModeManifest, ViewerContract, AgentBackend)
|
|
256
|
+
- [x] ViewerContract v2 — Agent-Human alignment protocol (workspace model, action protocol, context enrichment)
|
|
251
257
|
- [x] Remote mode loading — `pneuma github:user/repo` or local path (v1.x)
|
|
252
258
|
- [ ] Additional agent backends — Codex CLI, custom agents (v1.x)
|
|
253
259
|
|
package/bin/pneuma.ts
CHANGED
|
@@ -79,6 +79,7 @@ function parseArgs(argv: string[]) {
|
|
|
79
79
|
let workspace = process.cwd();
|
|
80
80
|
let port = 0; // 0 = auto-detect based on mode
|
|
81
81
|
let noOpen = false;
|
|
82
|
+
let debug = false;
|
|
82
83
|
|
|
83
84
|
for (let i = 0; i < args.length; i++) {
|
|
84
85
|
const arg = args[i];
|
|
@@ -88,12 +89,14 @@ function parseArgs(argv: string[]) {
|
|
|
88
89
|
port = Number(args[++i]);
|
|
89
90
|
} else if (arg === "--no-open") {
|
|
90
91
|
noOpen = true;
|
|
92
|
+
} else if (arg === "--debug") {
|
|
93
|
+
debug = true;
|
|
91
94
|
} else if (!arg.startsWith("--")) {
|
|
92
95
|
mode = arg;
|
|
93
96
|
}
|
|
94
97
|
}
|
|
95
98
|
|
|
96
|
-
return { mode, workspace: resolve(workspace), port, noOpen };
|
|
99
|
+
return { mode, workspace: resolve(workspace), port, noOpen, debug };
|
|
97
100
|
}
|
|
98
101
|
|
|
99
102
|
function ask(question: string): Promise<string> {
|
|
@@ -179,7 +182,7 @@ async function main() {
|
|
|
179
182
|
return;
|
|
180
183
|
}
|
|
181
184
|
|
|
182
|
-
const { mode, workspace, port, noOpen } = parseArgs(process.argv);
|
|
185
|
+
const { mode, workspace, port, noOpen, debug } = parseArgs(process.argv);
|
|
183
186
|
|
|
184
187
|
// Validate mode — support builtin names, local paths, and github: specifiers
|
|
185
188
|
if (!mode) {
|
|
@@ -255,6 +258,12 @@ async function main() {
|
|
|
255
258
|
const skillTarget = join(workspace, ".claude", "skills", manifest.skill.installName);
|
|
256
259
|
let skipSkillInstall = false;
|
|
257
260
|
|
|
261
|
+
// Compute the effective API port (same logic as server startup in step 3)
|
|
262
|
+
// Dev mode: backend on 17007, Prod mode: backend on 17996
|
|
263
|
+
const distDir = resolve(PROJECT_ROOT, "dist");
|
|
264
|
+
const isDev = !existsSync(join(distDir, "index.html"));
|
|
265
|
+
const effectiveApiPort = port || (isDev ? 17007 : 17996);
|
|
266
|
+
|
|
258
267
|
if (existsSync(skillTarget)) {
|
|
259
268
|
const answer = await ask(
|
|
260
269
|
`[pneuma] Existing skills found at ${skillTarget}\n` +
|
|
@@ -268,7 +277,7 @@ async function main() {
|
|
|
268
277
|
|
|
269
278
|
if (!skipSkillInstall) {
|
|
270
279
|
console.log("[pneuma] Installing skill and preparing environment...");
|
|
271
|
-
installSkill(workspace, manifest.skill, modeSourceDir, resolvedParams);
|
|
280
|
+
installSkill(workspace, manifest.skill, modeSourceDir, resolvedParams, manifest.viewerApi, effectiveApiPort);
|
|
272
281
|
}
|
|
273
282
|
|
|
274
283
|
// 1.5 Seed default content if workspace has no meaningful files
|
|
@@ -308,10 +317,7 @@ async function main() {
|
|
|
308
317
|
}
|
|
309
318
|
}
|
|
310
319
|
|
|
311
|
-
// 2. Detect dev vs production mode
|
|
312
|
-
const distDir = resolve(PROJECT_ROOT, "dist");
|
|
313
|
-
const isDev = !existsSync(join(distDir, "index.html"));
|
|
314
|
-
|
|
320
|
+
// 2. Detect dev vs production mode (distDir, isDev computed earlier for port)
|
|
315
321
|
if (isDev) {
|
|
316
322
|
console.log("[pneuma] Development mode (serving via Vite)");
|
|
317
323
|
} else {
|
|
@@ -321,7 +327,7 @@ async function main() {
|
|
|
321
327
|
// 3. Start server
|
|
322
328
|
// Dev mode: backend on 17007, Vite on 17996 (user-facing)
|
|
323
329
|
// Prod mode: backend on 17996 (serves everything)
|
|
324
|
-
const serverPort =
|
|
330
|
+
const serverPort = effectiveApiPort;
|
|
325
331
|
const { server, wsBridge, port: actualPort } = startServer({
|
|
326
332
|
port: serverPort,
|
|
327
333
|
workspace,
|
|
@@ -484,7 +490,8 @@ async function main() {
|
|
|
484
490
|
|
|
485
491
|
// 7. Open browser (include mode in URL for frontend)
|
|
486
492
|
if (!noOpen) {
|
|
487
|
-
const
|
|
493
|
+
const debugParam = debug ? "&debug=1" : "";
|
|
494
|
+
const url = `http://localhost:${browserPort}?session=${session.sessionId}&mode=${modeName}${debugParam}`;
|
|
488
495
|
console.log(`[pneuma] Opening browser: ${url}`);
|
|
489
496
|
try {
|
|
490
497
|
const opener = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
|
|
@@ -5,6 +5,9 @@
|
|
|
5
5
|
* - PreviewComponent 是有效的 React 组件类型
|
|
6
6
|
* - extractContext 返回格式正确的上下文字符串
|
|
7
7
|
* - updateStrategy 是合法枚举值
|
|
8
|
+
* - workspace model 约束
|
|
9
|
+
* - action descriptors 结构
|
|
10
|
+
* - 向后兼容
|
|
8
11
|
*/
|
|
9
12
|
|
|
10
13
|
import { describe, test, expect } from "bun:test";
|
|
@@ -13,6 +16,9 @@ import type {
|
|
|
13
16
|
ViewerPreviewProps,
|
|
14
17
|
ViewerSelectionContext,
|
|
15
18
|
ViewerFileContent,
|
|
19
|
+
FileWorkspaceModel,
|
|
20
|
+
WorkspaceItem,
|
|
21
|
+
ViewerActionDescriptor,
|
|
16
22
|
} from "../types/index.js";
|
|
17
23
|
|
|
18
24
|
// ── 辅助:创建 mock viewer ─────────────────────────────────────────────────
|
|
@@ -153,3 +159,206 @@ describe("extractContext edge cases", () => {
|
|
|
153
159
|
expect(viewer.extractContext(null, [])).toBe("");
|
|
154
160
|
});
|
|
155
161
|
});
|
|
162
|
+
|
|
163
|
+
// ── FileWorkspaceModel ─────────────────────────────────────────────────────
|
|
164
|
+
|
|
165
|
+
describe("FileWorkspaceModel", () => {
|
|
166
|
+
test("type 'all' — multi-file, unordered", () => {
|
|
167
|
+
const ws: FileWorkspaceModel = {
|
|
168
|
+
type: "all",
|
|
169
|
+
multiFile: true,
|
|
170
|
+
ordered: false,
|
|
171
|
+
hasActiveFile: false,
|
|
172
|
+
};
|
|
173
|
+
expect(ws.type).toBe("all");
|
|
174
|
+
expect(ws.multiFile).toBe(true);
|
|
175
|
+
expect(ws.ordered).toBe(false);
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
test("type 'manifest' — ordered, with manifest file", () => {
|
|
179
|
+
const ws: FileWorkspaceModel = {
|
|
180
|
+
type: "manifest",
|
|
181
|
+
multiFile: true,
|
|
182
|
+
ordered: true,
|
|
183
|
+
hasActiveFile: true,
|
|
184
|
+
manifestFile: "manifest.json",
|
|
185
|
+
};
|
|
186
|
+
expect(ws.type).toBe("manifest");
|
|
187
|
+
expect(ws.manifestFile).toBe("manifest.json");
|
|
188
|
+
expect(ws.hasActiveFile).toBe(true);
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
test("type 'single' — single file", () => {
|
|
192
|
+
const ws: FileWorkspaceModel = {
|
|
193
|
+
type: "single",
|
|
194
|
+
multiFile: false,
|
|
195
|
+
ordered: false,
|
|
196
|
+
hasActiveFile: false,
|
|
197
|
+
};
|
|
198
|
+
expect(ws.type).toBe("single");
|
|
199
|
+
expect(ws.multiFile).toBe(false);
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
test("resolveItems parses manifest-based workspace", () => {
|
|
203
|
+
const ws: FileWorkspaceModel = {
|
|
204
|
+
type: "manifest",
|
|
205
|
+
multiFile: true,
|
|
206
|
+
ordered: true,
|
|
207
|
+
hasActiveFile: true,
|
|
208
|
+
manifestFile: "manifest.json",
|
|
209
|
+
resolveItems: (files) => {
|
|
210
|
+
const mf = files.find((f) => f.path === "manifest.json");
|
|
211
|
+
if (!mf) return [];
|
|
212
|
+
const parsed = JSON.parse(mf.content);
|
|
213
|
+
return parsed.slides.map(
|
|
214
|
+
(s: { file: string; title: string }, i: number) => ({
|
|
215
|
+
path: s.file,
|
|
216
|
+
label: s.title,
|
|
217
|
+
index: i,
|
|
218
|
+
}),
|
|
219
|
+
);
|
|
220
|
+
},
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
const files: ViewerFileContent[] = [
|
|
224
|
+
{
|
|
225
|
+
path: "manifest.json",
|
|
226
|
+
content: JSON.stringify({
|
|
227
|
+
slides: [
|
|
228
|
+
{ file: "slides/s1.html", title: "Intro" },
|
|
229
|
+
{ file: "slides/s2.html", title: "Content" },
|
|
230
|
+
],
|
|
231
|
+
}),
|
|
232
|
+
},
|
|
233
|
+
];
|
|
234
|
+
|
|
235
|
+
const items = ws.resolveItems!(files);
|
|
236
|
+
expect(items).toHaveLength(2);
|
|
237
|
+
expect(items[0]).toEqual({ path: "slides/s1.html", label: "Intro", index: 0 });
|
|
238
|
+
expect(items[1]).toEqual({ path: "slides/s2.html", label: "Content", index: 1 });
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
test("resolveItems returns empty for missing manifest", () => {
|
|
242
|
+
const ws: FileWorkspaceModel = {
|
|
243
|
+
type: "manifest",
|
|
244
|
+
multiFile: true,
|
|
245
|
+
ordered: true,
|
|
246
|
+
hasActiveFile: true,
|
|
247
|
+
resolveItems: (files) => {
|
|
248
|
+
const mf = files.find((f) => f.path === "manifest.json");
|
|
249
|
+
if (!mf) return [];
|
|
250
|
+
return [];
|
|
251
|
+
},
|
|
252
|
+
};
|
|
253
|
+
expect(ws.resolveItems!([])).toEqual([]);
|
|
254
|
+
});
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
// ── ViewerActionDescriptor ────────────────────────────────────────────────
|
|
258
|
+
|
|
259
|
+
describe("ViewerActionDescriptor", () => {
|
|
260
|
+
test("shape validation", () => {
|
|
261
|
+
const action: ViewerActionDescriptor = {
|
|
262
|
+
id: "navigate-to",
|
|
263
|
+
label: "Go to Slide",
|
|
264
|
+
category: "navigate",
|
|
265
|
+
agentInvocable: true,
|
|
266
|
+
params: {
|
|
267
|
+
file: { type: "string", description: "Slide file path", required: true },
|
|
268
|
+
},
|
|
269
|
+
description: "Navigate to a specific slide",
|
|
270
|
+
};
|
|
271
|
+
|
|
272
|
+
expect(action.id).toBe("navigate-to");
|
|
273
|
+
expect(action.category).toBe("navigate");
|
|
274
|
+
expect(action.agentInvocable).toBe(true);
|
|
275
|
+
expect(action.params?.file.type).toBe("string");
|
|
276
|
+
expect(action.params?.file.required).toBe(true);
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
test("action with no params", () => {
|
|
280
|
+
const action: ViewerActionDescriptor = {
|
|
281
|
+
id: "ui:toggle-outline",
|
|
282
|
+
label: "Toggle Outline",
|
|
283
|
+
category: "ui",
|
|
284
|
+
agentInvocable: true,
|
|
285
|
+
};
|
|
286
|
+
expect(action.params).toBeUndefined();
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
test("non-agent-invocable action", () => {
|
|
290
|
+
const action: ViewerActionDescriptor = {
|
|
291
|
+
id: "internal:refresh",
|
|
292
|
+
label: "Refresh",
|
|
293
|
+
category: "custom",
|
|
294
|
+
agentInvocable: false,
|
|
295
|
+
};
|
|
296
|
+
expect(action.agentInvocable).toBe(false);
|
|
297
|
+
});
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
// ── Backward compatibility ────────────────────────────────────────────────
|
|
301
|
+
|
|
302
|
+
describe("Backward compatibility", () => {
|
|
303
|
+
test("ViewerContract without workspace/actions is valid", () => {
|
|
304
|
+
const viewer = createMockViewer();
|
|
305
|
+
expect(viewer.workspace).toBeUndefined();
|
|
306
|
+
expect(viewer.actions).toBeUndefined();
|
|
307
|
+
// Should still work
|
|
308
|
+
expect(viewer.extractContext(null, [])).toBe("");
|
|
309
|
+
expect(typeof viewer.PreviewComponent).toBe("function");
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
test("ViewerContract with workspace and actions", () => {
|
|
313
|
+
const viewer = createMockViewer({
|
|
314
|
+
workspace: {
|
|
315
|
+
type: "all",
|
|
316
|
+
multiFile: true,
|
|
317
|
+
ordered: false,
|
|
318
|
+
hasActiveFile: false,
|
|
319
|
+
},
|
|
320
|
+
actions: [
|
|
321
|
+
{ id: "test", label: "Test", category: "custom", agentInvocable: true },
|
|
322
|
+
],
|
|
323
|
+
});
|
|
324
|
+
expect(viewer.workspace?.type).toBe("all");
|
|
325
|
+
expect(viewer.actions).toHaveLength(1);
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
test("ViewerPreviewProps with new optional fields", () => {
|
|
329
|
+
const props: ViewerPreviewProps = {
|
|
330
|
+
files: [],
|
|
331
|
+
selection: null,
|
|
332
|
+
onSelect: () => {},
|
|
333
|
+
mode: "view",
|
|
334
|
+
imageVersion: 0,
|
|
335
|
+
// New optional fields
|
|
336
|
+
workspaceItems: [{ path: "test.md", label: "Test" }],
|
|
337
|
+
actionRequest: { requestId: "r1", actionId: "test" },
|
|
338
|
+
onActionResult: () => {},
|
|
339
|
+
onViewportChange: () => {},
|
|
340
|
+
};
|
|
341
|
+
expect(props.workspaceItems).toHaveLength(1);
|
|
342
|
+
expect(props.actionRequest?.actionId).toBe("test");
|
|
343
|
+
expect(typeof props.onViewportChange).toBe("function");
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
test("ViewerSelectionContext with viewport", () => {
|
|
347
|
+
const sel: ViewerSelectionContext = {
|
|
348
|
+
type: "heading",
|
|
349
|
+
content: "Introduction",
|
|
350
|
+
file: "README.md",
|
|
351
|
+
viewport: { startLine: 10, endLine: 40, heading: "## Introduction" },
|
|
352
|
+
};
|
|
353
|
+
expect(sel.viewport?.startLine).toBe(10);
|
|
354
|
+
expect(sel.viewport?.endLine).toBe(40);
|
|
355
|
+
expect(sel.viewport?.heading).toBe("## Introduction");
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
test("ViewerContract with captureViewport", () => {
|
|
359
|
+
const viewer = createMockViewer({
|
|
360
|
+
captureViewport: async () => ({ data: "base64data", media_type: "image/png" }),
|
|
361
|
+
});
|
|
362
|
+
expect(typeof viewer.captureViewport).toBe("function");
|
|
363
|
+
});
|
|
364
|
+
});
|
package/core/types/index.ts
CHANGED
|
@@ -13,6 +13,7 @@ export type {
|
|
|
13
13
|
ViewerConfig,
|
|
14
14
|
AgentPreferences,
|
|
15
15
|
InitConfig,
|
|
16
|
+
ViewerApiConfig,
|
|
16
17
|
} from "./mode-manifest.js";
|
|
17
18
|
|
|
18
19
|
export type {
|
|
@@ -20,6 +21,12 @@ export type {
|
|
|
20
21
|
ViewerPreviewProps,
|
|
21
22
|
ViewerFileContent,
|
|
22
23
|
ViewerSelectionContext,
|
|
24
|
+
WorkspaceItem,
|
|
25
|
+
FileWorkspaceModel,
|
|
26
|
+
ViewerActionParam,
|
|
27
|
+
ViewerActionDescriptor,
|
|
28
|
+
ViewerActionRequest,
|
|
29
|
+
ViewerActionResult,
|
|
23
30
|
} from "./viewer-contract.js";
|
|
24
31
|
|
|
25
32
|
export type { ModeDefinition } from "./mode-definition.js";
|
|
@@ -94,6 +94,25 @@ export interface InitConfig {
|
|
|
94
94
|
deriveParams?: (params: Record<string, number | string>) => Record<string, number | string>;
|
|
95
95
|
}
|
|
96
96
|
|
|
97
|
+
/** Viewer 自描述 API — 纯数据声明,后端 (pneuma.ts / skill-installer) 可读 */
|
|
98
|
+
export interface ViewerApiConfig {
|
|
99
|
+
workspace?: {
|
|
100
|
+
type: "all" | "manifest" | "single";
|
|
101
|
+
multiFile: boolean;
|
|
102
|
+
ordered: boolean;
|
|
103
|
+
hasActiveFile: boolean;
|
|
104
|
+
manifestFile?: string;
|
|
105
|
+
};
|
|
106
|
+
actions?: Array<{
|
|
107
|
+
id: string;
|
|
108
|
+
label: string;
|
|
109
|
+
category: "file" | "navigate" | "ui" | "custom";
|
|
110
|
+
agentInvocable: boolean;
|
|
111
|
+
params?: Record<string, { type: "string" | "number" | "boolean"; description: string; required?: boolean }>;
|
|
112
|
+
description?: string;
|
|
113
|
+
}>;
|
|
114
|
+
}
|
|
115
|
+
|
|
97
116
|
/** Mode 的完整声明式描述 */
|
|
98
117
|
export interface ModeManifest {
|
|
99
118
|
/** Mode 唯一标识 (e.g. "doc", "slide") */
|
|
@@ -113,4 +132,6 @@ export interface ModeManifest {
|
|
|
113
132
|
agent?: AgentPreferences;
|
|
114
133
|
/** 工作区初始化配置 (可选) */
|
|
115
134
|
init?: InitConfig;
|
|
135
|
+
/** Viewer 自描述 API — 纯数据声明,后端可读,自动注入 CLAUDE.md */
|
|
136
|
+
viewerApi?: ViewerApiConfig;
|
|
116
137
|
}
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* ViewerContract —
|
|
2
|
+
* ViewerContract — Agent-Human Alignment Protocol
|
|
3
|
+
*
|
|
4
|
+
* ViewerContract 的核心职责是 Agent-Human 对齐:
|
|
5
|
+
* 1. 感知对齐 — Agent 能看到 User 看到的东西 (extractContext, workspace)
|
|
6
|
+
* 2. 能力对齐 — Agent 能做到 User 能做到的事情 (actions)
|
|
3
7
|
*
|
|
4
|
-
* 定义内容查看器的 UI 能力:查看、编辑、交互捕捉、热更新。
|
|
5
8
|
* 每个 Mode 提供一个实现此接口的对象。
|
|
6
|
-
* Runtime Shell
|
|
9
|
+
* Runtime Shell 通过此接口渲染预览、处理用户交互、桥接 Agent 操作。
|
|
7
10
|
*/
|
|
8
11
|
|
|
9
12
|
import type { ComponentType } from "react";
|
|
@@ -28,8 +31,79 @@ export interface ViewerSelectionContext {
|
|
|
28
31
|
selector?: string;
|
|
29
32
|
/** SVG data URL thumbnail of the selected element (null if capture failed or element too large) */
|
|
30
33
|
thumbnail?: string;
|
|
34
|
+
/** 可见视窗行范围(仅 Doc 等文本 mode 使用) */
|
|
35
|
+
viewport?: { startLine: number; endLine: number; heading?: string };
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// ── File Workspace Model ───────────────────────────────────────────────────
|
|
39
|
+
|
|
40
|
+
/** 工作区项 — 文件导航模型中的一个逻辑单元 */
|
|
41
|
+
export interface WorkspaceItem {
|
|
42
|
+
path: string;
|
|
43
|
+
label: string;
|
|
44
|
+
index?: number;
|
|
45
|
+
metadata?: Record<string, unknown>;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* 文件工作区模型 — 描述 Viewer 如何组织文件。
|
|
50
|
+
*
|
|
51
|
+
* - "all": 所有匹配文件平等展示 (Doc: 每个 .md 独立)
|
|
52
|
+
* - "manifest": 由索引文件定义结构和顺序 (Slide: manifest.json)
|
|
53
|
+
* - "single": 只操作一个主文件 (Draw: 单个 .excalidraw)
|
|
54
|
+
*/
|
|
55
|
+
export interface FileWorkspaceModel {
|
|
56
|
+
type: "all" | "manifest" | "single";
|
|
57
|
+
multiFile: boolean;
|
|
58
|
+
ordered: boolean;
|
|
59
|
+
hasActiveFile: boolean;
|
|
60
|
+
/** type="manifest" 时的索引文件 */
|
|
61
|
+
manifestFile?: string;
|
|
62
|
+
/** 从文件列表解析工作区项(前端运行时使用) */
|
|
63
|
+
resolveItems?: (files: ViewerFileContent[]) => WorkspaceItem[];
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// ── Viewer Action (能力对齐) ───────────────────────────────────────────────
|
|
67
|
+
|
|
68
|
+
/** Viewer 操作参数描述 */
|
|
69
|
+
export interface ViewerActionParam {
|
|
70
|
+
type: "string" | "number" | "boolean";
|
|
71
|
+
description: string;
|
|
72
|
+
required?: boolean;
|
|
31
73
|
}
|
|
32
74
|
|
|
75
|
+
/**
|
|
76
|
+
* Viewer 操作描述 — 能力对齐的基本单元。
|
|
77
|
+
*
|
|
78
|
+
* Viewer 声明自己支持的操作,Agent 通过执行通道调用。
|
|
79
|
+
* 无论是 "导航到第 3 页"、"收起 outline"、还是 "截图当前视图",
|
|
80
|
+
* 对框架来说都是 action。
|
|
81
|
+
*/
|
|
82
|
+
export interface ViewerActionDescriptor {
|
|
83
|
+
id: string;
|
|
84
|
+
label: string;
|
|
85
|
+
category: "file" | "navigate" | "ui" | "custom";
|
|
86
|
+
agentInvocable: boolean;
|
|
87
|
+
params?: Record<string, ViewerActionParam>;
|
|
88
|
+
description?: string;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** 执行通道中的请求 */
|
|
92
|
+
export interface ViewerActionRequest {
|
|
93
|
+
requestId: string;
|
|
94
|
+
actionId: string;
|
|
95
|
+
params?: Record<string, unknown>;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/** 执行结果 */
|
|
99
|
+
export interface ViewerActionResult {
|
|
100
|
+
success: boolean;
|
|
101
|
+
message?: string;
|
|
102
|
+
data?: Record<string, unknown>;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// ── Preview Props & Contract ───────────────────────────────────────────────
|
|
106
|
+
|
|
33
107
|
/** 预览组件的 Props */
|
|
34
108
|
export interface ViewerPreviewProps {
|
|
35
109
|
/** 工作区文件列表 */
|
|
@@ -48,6 +122,14 @@ export interface ViewerPreviewProps {
|
|
|
48
122
|
initParams?: Record<string, number | string>;
|
|
49
123
|
/** 当前查看的文件变更时的回调(用于追踪活跃文件上下文) */
|
|
50
124
|
onActiveFileChange?: (file: string | null) => void;
|
|
125
|
+
/** 由 runtime 通过 workspace.resolveItems 计算后传入 */
|
|
126
|
+
workspaceItems?: WorkspaceItem[];
|
|
127
|
+
/** Runtime 下发的 action 请求,Viewer 执行后调用 onActionResult 返回结果 */
|
|
128
|
+
actionRequest?: ViewerActionRequest | null;
|
|
129
|
+
/** Viewer 执行 action 后返回结果的回调 */
|
|
130
|
+
onActionResult?: (requestId: string, result: ViewerActionResult) => void;
|
|
131
|
+
/** 视窗变更回调 — Viewer 上报当前可见范围 */
|
|
132
|
+
onViewportChange?: (viewport: { file: string; startLine: number; endLine: number; heading?: string }) => void;
|
|
51
133
|
}
|
|
52
134
|
|
|
53
135
|
/** 内容查看器的 UI 契约 */
|
|
@@ -71,4 +153,13 @@ export interface ViewerContract {
|
|
|
71
153
|
|
|
72
154
|
/** 文件变更时的更新策略 */
|
|
73
155
|
updateStrategy: "full-reload" | "incremental";
|
|
156
|
+
|
|
157
|
+
/** 文件工作区模型 — 描述 Viewer 如何组织文件 */
|
|
158
|
+
workspace?: FileWorkspaceModel;
|
|
159
|
+
|
|
160
|
+
/** Viewer 支持的操作 — Agent 可通过执行通道调用 */
|
|
161
|
+
actions?: ViewerActionDescriptor[];
|
|
162
|
+
|
|
163
|
+
/** 捕获当前视窗截图(可选,由 PreviewComponent 在 mount 后动态注入实现) */
|
|
164
|
+
captureViewport?: () => Promise<{ data: string; media_type: string } | null>;
|
|
74
165
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{a as H,j as L,u as Np}from"./index-
|
|
1
|
+
import{a as H,j as L,u as Np}from"./index-DmVx_FQq.js";import{_ as Fp}from"./extends-CF3RwP-h.js";function Hp(n,e){if(n==null)return{};var t={};for(var i in n)if({}.hasOwnProperty.call(n,i)){if(e.indexOf(i)!==-1)continue;t[i]=n[i]}return t}let $o=[],vO=[];(()=>{let n="lc,34,7n,7,7b,19,,,,2,,2,,,20,b,1c,l,g,,2t,7,2,6,2,2,,4,z,,u,r,2j,b,1m,9,9,,o,4,,9,,3,,5,17,3,3b,f,,w,1j,,,,4,8,4,,3,7,a,2,t,,1m,,,,2,4,8,,9,,a,2,q,,2,2,1l,,4,2,4,2,2,3,3,,u,2,3,,b,2,1l,,4,5,,2,4,,k,2,m,6,,,1m,,,2,,4,8,,7,3,a,2,u,,1n,,,,c,,9,,14,,3,,1l,3,5,3,,4,7,2,b,2,t,,1m,,2,,2,,3,,5,2,7,2,b,2,s,2,1l,2,,,2,4,8,,9,,a,2,t,,20,,4,,2,3,,,8,,29,,2,7,c,8,2q,,2,9,b,6,22,2,r,,,,,,1j,e,,5,,2,5,b,,10,9,,2u,4,,6,,2,2,2,p,2,4,3,g,4,d,,2,2,6,,f,,jj,3,qa,3,t,3,t,2,u,2,1s,2,,7,8,,2,b,9,,19,3,3b,2,y,,3a,3,4,2,9,,6,3,63,2,2,,1m,,,7,,,,,2,8,6,a,2,,1c,h,1r,4,1c,7,,,5,,14,9,c,2,w,4,2,2,,3,1k,,,2,3,,,3,1m,8,2,2,48,3,,d,,7,4,,6,,3,2,5i,1m,,5,ek,,5f,x,2da,3,3x,,2o,w,fe,6,2x,2,n9w,4,,a,w,2,28,2,7k,,3,,4,,p,2,5,,47,2,q,i,d,,12,8,p,b,1a,3,1c,,2,4,2,2,13,,1v,6,2,2,2,2,c,,8,,1b,,1f,,,3,2,2,5,2,,,16,2,8,,6m,,2,,4,,fn4,,kh,g,g,g,a6,2,gt,,6a,,45,5,1ae,3,,2,5,4,14,3,4,,4l,2,fx,4,ar,2,49,b,4w,,1i,f,1k,3,1d,4,2,2,1x,3,10,5,,8,1q,,c,2,1g,9,a,4,2,,2n,3,2,,,2,6,,4g,,3,8,l,2,1l,2,,,,,m,,e,7,3,5,5f,8,2,3,,,n,,29,,2,6,,,2,,,2,,2,6j,,2,4,6,2,,2,r,2,2d,8,2,,,2,2y,,,,2,6,,,2t,3,2,4,,5,77,9,,2,6t,,a,2,,,4,,40,4,2,2,4,,w,a,14,6,2,4,8,,9,6,2,3,1a,d,,2,ba,7,,6,,,2a,m,2,7,,2,,2,3e,6,3,,,2,,7,,,20,2,3,,,,9n,2,f0b,5,1n,7,t4,,1r,4,29,,f5k,2,43q,,,3,4,5,8,8,2,7,u,4,44,3,1iz,1j,4,1e,8,,e,,m,5,,f,11s,7,,h,2,7,,2,,5,79,7,c5,4,15s,7,31,7,240,5,gx7k,2o,3k,6o".split(",").map(e=>e?parseInt(e,36):1);for(let e=0,t=0;e<n.length;e++)(e%2?vO:$o).push(t=t+n[e])})();function Kp(n){if(n<768)return!1;for(let e=0,t=$o.length;;){let i=e+t>>1;if(n<$o[i])t=i;else if(n>=vO[i])e=i+1;else return!0;if(e==t)return!1}}function Ea(n){return n>=127462&&n<=127487}const _a=8205;function Jp(n,e,t=!0,i=!0){return(t?TO:em)(n,e,i)}function TO(n,e,t){if(e==n.length)return e;e&&CO(n.charCodeAt(e))&&XO(n.charCodeAt(e-1))&&e--;let i=Cs(n,e);for(e+=Wa(i);e<n.length;){let r=Cs(n,e);if(i==_a||r==_a||t&&Kp(r))e+=Wa(r),i=r;else if(Ea(r)){let s=0,o=e-2;for(;o>=0&&Ea(Cs(n,o));)s++,o-=2;if(s%2==0)break;e+=2}else break}return e}function em(n,e,t){for(;e>0;){let i=TO(n,e-2,t);if(i<e)return i;e--}return 0}function Cs(n,e){let t=n.charCodeAt(e);if(!XO(t)||e+1==n.length)return t;let i=n.charCodeAt(e+1);return CO(i)?(t-55296<<10)+(i-56320)+65536:t}function CO(n){return n>=56320&&n<57344}function XO(n){return n>=55296&&n<56320}function Wa(n){return n<65536?1:2}class I{lineAt(e){if(e<0||e>this.length)throw new RangeError(`Invalid position ${e} in document of length ${this.length}`);return this.lineInner(e,!1,1,0)}line(e){if(e<1||e>this.lines)throw new RangeError(`Invalid line number ${e} in ${this.lines}-line document`);return this.lineInner(e,!0,1,0)}replace(e,t,i){[e,t]=Ci(this,e,t);let r=[];return this.decompose(0,e,r,2),i.length&&i.decompose(0,i.length,r,3),this.decompose(t,this.length,r,1),at.from(r,this.length-(t-e)+i.length)}append(e){return this.replace(this.length,this.length,e)}slice(e,t=this.length){[e,t]=Ci(this,e,t);let i=[];return this.decompose(e,t,i,0),at.from(i,t-e)}eq(e){if(e==this)return!0;if(e.length!=this.length||e.lines!=this.lines)return!1;let t=this.scanIdentical(e,1),i=this.length-this.scanIdentical(e,-1),r=new nn(this),s=new nn(e);for(let o=t,l=t;;){if(r.next(o),s.next(o),o=0,r.lineBreak!=s.lineBreak||r.done!=s.done||r.value!=s.value)return!1;if(l+=r.value.length,r.done||l>=i)return!0}}iter(e=1){return new nn(this,e)}iterRange(e,t=this.length){return new ZO(this,e,t)}iterLines(e,t){let i;if(e==null)i=this.iter();else{t==null&&(t=this.lines+1);let r=this.line(e).from;i=this.iterRange(r,Math.max(r,t==this.lines+1?this.length:t<=1?0:this.line(t-1).to))}return new RO(i)}toString(){return this.sliceString(0)}toJSON(){let e=[];return this.flatten(e),e}constructor(){}static of(e){if(e.length==0)throw new RangeError("A document must have at least one line");return e.length==1&&!e[0]?I.empty:e.length<=32?new oe(e):at.from(oe.split(e,[]))}}class oe extends I{constructor(e,t=tm(e)){super(),this.text=e,this.length=t}get lines(){return this.text.length}get children(){return null}lineInner(e,t,i,r){for(let s=0;;s++){let o=this.text[s],l=r+o.length;if((t?i:l)>=e)return new im(r,l,i,o);r=l+1,i++}}decompose(e,t,i,r){let s=e<=0&&t>=this.length?this:new oe(Va(this.text,e,t),Math.min(t,this.length)-Math.max(0,e));if(r&1){let o=i.pop(),l=Sr(s.text,o.text.slice(),0,s.length);if(l.length<=32)i.push(new oe(l,o.length+s.length));else{let a=l.length>>1;i.push(new oe(l.slice(0,a)),new oe(l.slice(a)))}}else i.push(s)}replace(e,t,i){if(!(i instanceof oe))return super.replace(e,t,i);[e,t]=Ci(this,e,t);let r=Sr(this.text,Sr(i.text,Va(this.text,0,e)),t),s=this.length+i.length-(t-e);return r.length<=32?new oe(r,s):at.from(oe.split(r,[]),s)}sliceString(e,t=this.length,i=`
|
|
2
2
|
`){[e,t]=Ci(this,e,t);let r="";for(let s=0,o=0;s<=t&&o<this.text.length;o++){let l=this.text[o],a=s+l.length;s>e&&o&&(r+=i),e<a&&t>s&&(r+=l.slice(Math.max(0,e-s),t-s)),s=a+1}return r}flatten(e){for(let t of this.text)e.push(t)}scanIdentical(){return 0}static split(e,t){let i=[],r=-1;for(let s of e)i.push(s),r+=s.length+1,i.length==32&&(t.push(new oe(i,r)),i=[],r=-1);return r>-1&&t.push(new oe(i,r)),t}}class at extends I{constructor(e,t){super(),this.children=e,this.length=t,this.lines=0;for(let i of e)this.lines+=i.lines}lineInner(e,t,i,r){for(let s=0;;s++){let o=this.children[s],l=r+o.length,a=i+o.lines-1;if((t?a:l)>=e)return o.lineInner(e,t,i,r);r=l+1,i=a+1}}decompose(e,t,i,r){for(let s=0,o=0;o<=t&&s<this.children.length;s++){let l=this.children[s],a=o+l.length;if(e<=a&&t>=o){let h=r&((o<=e?1:0)|(a>=t?2:0));o>=e&&a<=t&&!h?i.push(l):l.decompose(e-o,t-o,i,h)}o=a+1}}replace(e,t,i){if([e,t]=Ci(this,e,t),i.lines<this.lines)for(let r=0,s=0;r<this.children.length;r++){let o=this.children[r],l=s+o.length;if(e>=s&&t<=l){let a=o.replace(e-s,t-s,i),h=this.lines-o.lines+a.lines;if(a.lines<h>>4&&a.lines>h>>6){let c=this.children.slice();return c[r]=a,new at(c,this.length-(t-e)+i.length)}return super.replace(s,l,a)}s=l+1}return super.replace(e,t,i)}sliceString(e,t=this.length,i=`
|
|
3
3
|
`){[e,t]=Ci(this,e,t);let r="";for(let s=0,o=0;s<this.children.length&&o<=t;s++){let l=this.children[s],a=o+l.length;o>e&&s&&(r+=i),e<a&&t>o&&(r+=l.sliceString(e-o,t-o,i)),o=a+1}return r}flatten(e){for(let t of this.children)t.flatten(e)}scanIdentical(e,t){if(!(e instanceof at))return 0;let i=0,[r,s,o,l]=t>0?[0,0,this.children.length,e.children.length]:[this.children.length-1,e.children.length-1,-1,-1];for(;;r+=t,s+=t){if(r==o||s==l)return i;let a=this.children[r],h=e.children[s];if(a!=h)return i+a.scanIdentical(h,t);i+=a.length+1}}static from(e,t=e.reduce((i,r)=>i+r.length+1,-1)){let i=0;for(let u of e)i+=u.lines;if(i<32){let u=[];for(let d of e)d.flatten(u);return new oe(u,t)}let r=Math.max(32,i>>5),s=r<<1,o=r>>1,l=[],a=0,h=-1,c=[];function O(u){let d;if(u.lines>s&&u instanceof at)for(let m of u.children)O(m);else u.lines>o&&(a>o||!a)?(f(),l.push(u)):u instanceof oe&&a&&(d=c[c.length-1])instanceof oe&&u.lines+d.lines<=32?(a+=u.lines,h+=u.length+1,c[c.length-1]=new oe(d.text.concat(u.text),d.length+1+u.length)):(a+u.lines>r&&f(),a+=u.lines,h+=u.length+1,c.push(u))}function f(){a!=0&&(l.push(c.length==1?c[0]:at.from(c,h)),h=-1,a=c.length=0)}for(let u of e)O(u);return f(),l.length==1?l[0]:new at(l,t)}}I.empty=new oe([""],0);function tm(n){let e=-1;for(let t of n)e+=t.length+1;return e}function Sr(n,e,t=0,i=1e9){for(let r=0,s=0,o=!0;s<n.length&&r<=i;s++){let l=n[s],a=r+l.length;a>=t&&(a>i&&(l=l.slice(0,i-r)),r<t&&(l=l.slice(t-r)),o?(e[e.length-1]+=l,o=!1):e.push(l)),r=a+1}return e}function Va(n,e,t){return Sr(n,[""],e,t)}class nn{constructor(e,t=1){this.dir=t,this.done=!1,this.lineBreak=!1,this.value="",this.nodes=[e],this.offsets=[t>0?1:(e instanceof oe?e.text.length:e.children.length)<<1]}nextInner(e,t){for(this.done=this.lineBreak=!1;;){let i=this.nodes.length-1,r=this.nodes[i],s=this.offsets[i],o=s>>1,l=r instanceof oe?r.text.length:r.children.length;if(o==(t>0?l:0)){if(i==0)return this.done=!0,this.value="",this;t>0&&this.offsets[i-1]++,this.nodes.pop(),this.offsets.pop()}else if((s&1)==(t>0?0:1)){if(this.offsets[i]+=t,e==0)return this.lineBreak=!0,this.value=`
|
|
4
4
|
`,this;e--}else if(r instanceof oe){let a=r.text[o+(t<0?-1:0)];if(this.offsets[i]+=t,a.length>Math.max(0,e))return this.value=e==0?a:t>0?a.slice(e):a.slice(0,a.length-e),this;e-=a.length}else{let a=r.children[o+(t<0?-1:0)];e>a.length?(e-=a.length,this.offsets[i]+=t):(t<0&&this.offsets[i]--,this.nodes.push(a),this.offsets.push(t>0?1:(a instanceof oe?a.text.length:a.children.length)<<1))}}}next(e=0){return e<0&&(this.nextInner(-e,-this.dir),e=this.value.length),this.nextInner(e,this.dir)}}class ZO{constructor(e,t,i){this.value="",this.done=!1,this.cursor=new nn(e,t>i?-1:1),this.pos=t>i?e.length:0,this.from=Math.min(t,i),this.to=Math.max(t,i)}nextInner(e,t){if(t<0?this.pos<=this.from:this.pos>=this.to)return this.value="",this.done=!0,this;e+=Math.max(0,t<0?this.pos-this.to:this.from-this.pos);let i=t<0?this.pos-this.from:this.to-this.pos;e>i&&(e=i),i-=e;let{value:r}=this.cursor.next(e);return this.pos+=(r.length+e)*t,this.value=r.length<=i?r:t<0?r.slice(r.length-i):r.slice(0,i),this.done=!this.value,this}next(e=0){return e<0?e=Math.max(e,this.from-this.pos):e>0&&(e=Math.min(e,this.to-this.pos)),this.nextInner(e,this.cursor.dir)}get lineBreak(){return this.cursor.lineBreak&&this.value!=""}}class RO{constructor(e){this.inner=e,this.afterBreak=!0,this.value="",this.done=!1}next(e=0){let{done:t,lineBreak:i,value:r}=this.inner.next(e);return t&&this.afterBreak?(this.value="",this.afterBreak=!1):t?(this.done=!0,this.value=""):i?this.afterBreak?this.value="":(this.afterBreak=!0,this.next()):(this.value=r,this.afterBreak=!1),this}get lineBreak(){return!1}}typeof Symbol<"u"&&(I.prototype[Symbol.iterator]=function(){return this.iter()},nn.prototype[Symbol.iterator]=ZO.prototype[Symbol.iterator]=RO.prototype[Symbol.iterator]=function(){return this});let im=class{constructor(e,t,i,r){this.from=e,this.to=t,this.number=i,this.text=r}get length(){return this.to-this.from}};function Ci(n,e,t){return e=Math.max(0,Math.min(n.length,e)),[e,Math.max(e,Math.min(n.length,t))]}function pe(n,e,t=!0,i=!0){return Jp(n,e,t,i)}function nm(n){return n>=56320&&n<57344}function rm(n){return n>=55296&&n<56320}function Xe(n,e){let t=n.charCodeAt(e);if(!rm(t)||e+1==n.length)return t;let i=n.charCodeAt(e+1);return nm(i)?(t-55296<<10)+(i-56320)+65536:t}function Zl(n){return n<=65535?String.fromCharCode(n):(n-=65536,String.fromCharCode((n>>10)+55296,(n&1023)+56320))}function ht(n){return n<65536?1:2}const vo=/\r\n?|\n/;var Se=(function(n){return n[n.Simple=0]="Simple",n[n.TrackDel=1]="TrackDel",n[n.TrackBefore=2]="TrackBefore",n[n.TrackAfter=3]="TrackAfter",n})(Se||(Se={}));class pt{constructor(e){this.sections=e}get length(){let e=0;for(let t=0;t<this.sections.length;t+=2)e+=this.sections[t];return e}get newLength(){let e=0;for(let t=0;t<this.sections.length;t+=2){let i=this.sections[t+1];e+=i<0?this.sections[t]:i}return e}get empty(){return this.sections.length==0||this.sections.length==2&&this.sections[1]<0}iterGaps(e){for(let t=0,i=0,r=0;t<this.sections.length;){let s=this.sections[t++],o=this.sections[t++];o<0?(e(i,r,s),r+=s):r+=o,i+=s}}iterChangedRanges(e,t=!1){To(this,e,t)}get invertedDesc(){let e=[];for(let t=0;t<this.sections.length;){let i=this.sections[t++],r=this.sections[t++];r<0?e.push(i,r):e.push(r,i)}return new pt(e)}composeDesc(e){return this.empty?e:e.empty?this:AO(this,e)}mapDesc(e,t=!1){return e.empty?this:Co(this,e,t)}mapPos(e,t=-1,i=Se.Simple){let r=0,s=0;for(let o=0;o<this.sections.length;){let l=this.sections[o++],a=this.sections[o++],h=r+l;if(a<0){if(h>e)return s+(e-r);s+=l}else{if(i!=Se.Simple&&h>=e&&(i==Se.TrackDel&&r<e&&h>e||i==Se.TrackBefore&&r<e||i==Se.TrackAfter&&h>e))return null;if(h>e||h==e&&t<0&&!l)return e==r||t<0?s:s+a;s+=a}r=h}if(e>r)throw new RangeError(`Position ${e} is out of range for changeset of length ${r}`);return s}touchesRange(e,t=e){for(let i=0,r=0;i<this.sections.length&&r<=t;){let s=this.sections[i++],o=this.sections[i++],l=r+s;if(o>=0&&r<=t&&l>=e)return r<e&&l>t?"cover":!0;r=l}return!1}toString(){let e="";for(let t=0;t<this.sections.length;){let i=this.sections[t++],r=this.sections[t++];e+=(e?" ":"")+i+(r>=0?":"+r:"")}return e}toJSON(){return this.sections}static fromJSON(e){if(!Array.isArray(e)||e.length%2||e.some(t=>typeof t!="number"))throw new RangeError("Invalid JSON representation of ChangeDesc");return new pt(e)}static create(e){return new pt(e)}}class Oe extends pt{constructor(e,t){super(e),this.inserted=t}apply(e){if(this.length!=e.length)throw new RangeError("Applying change set to a document with the wrong length");return To(this,(t,i,r,s,o)=>e=e.replace(r,r+(i-t),o),!1),e}mapDesc(e,t=!1){return Co(this,e,t,!0)}invert(e){let t=this.sections.slice(),i=[];for(let r=0,s=0;r<t.length;r+=2){let o=t[r],l=t[r+1];if(l>=0){t[r]=l,t[r+1]=o;let a=r>>1;for(;i.length<a;)i.push(I.empty);i.push(o?e.slice(s,s+o):I.empty)}s+=o}return new Oe(t,i)}compose(e){return this.empty?e:e.empty?this:AO(this,e,!0)}map(e,t=!1){return e.empty?this:Co(this,e,t,!0)}iterChanges(e,t=!1){To(this,e,t)}get desc(){return pt.create(this.sections)}filter(e){let t=[],i=[],r=[],s=new fn(this);e:for(let o=0,l=0;;){let a=o==e.length?1e9:e[o++];for(;l<a||l==a&&s.len==0;){if(s.done)break e;let c=Math.min(s.len,a-l);Pe(r,c,-1);let O=s.ins==-1?-1:s.off==0?s.ins:0;Pe(t,c,O),O>0&&Mt(i,t,s.text),s.forward(c),l+=c}let h=e[o++];for(;l<h;){if(s.done)break e;let c=Math.min(s.len,h-l);Pe(t,c,-1),Pe(r,c,s.ins==-1?-1:s.off==0?s.ins:0),s.forward(c),l+=c}}return{changes:new Oe(t,i),filtered:pt.create(r)}}toJSON(){let e=[];for(let t=0;t<this.sections.length;t+=2){let i=this.sections[t],r=this.sections[t+1];r<0?e.push(i):r==0?e.push([i]):e.push([i].concat(this.inserted[t>>1].toJSON()))}return e}static of(e,t,i){let r=[],s=[],o=0,l=null;function a(c=!1){if(!c&&!r.length)return;o<t&&Pe(r,t-o,-1);let O=new Oe(r,s);l=l?l.compose(O.map(l)):O,r=[],s=[],o=0}function h(c){if(Array.isArray(c))for(let O of c)h(O);else if(c instanceof Oe){if(c.length!=t)throw new RangeError(`Mismatched change set length (got ${c.length}, expected ${t})`);a(),l=l?l.compose(c.map(l)):c}else{let{from:O,to:f=O,insert:u}=c;if(O>f||O<0||f>t)throw new RangeError(`Invalid change range ${O} to ${f} (in doc of length ${t})`);let d=u?typeof u=="string"?I.of(u.split(i||vo)):u:I.empty,m=d.length;if(O==f&&m==0)return;O<o&&a(),O>o&&Pe(r,O-o,-1),Pe(r,f-O,m),Mt(s,r,d),o=f}}return h(e),a(!l),l}static empty(e){return new Oe(e?[e,-1]:[],[])}static fromJSON(e){if(!Array.isArray(e))throw new RangeError("Invalid JSON representation of ChangeSet");let t=[],i=[];for(let r=0;r<e.length;r++){let s=e[r];if(typeof s=="number")t.push(s,-1);else{if(!Array.isArray(s)||typeof s[0]!="number"||s.some((o,l)=>l&&typeof o!="string"))throw new RangeError("Invalid JSON representation of ChangeSet");if(s.length==1)t.push(s[0],0);else{for(;i.length<r;)i.push(I.empty);i[r]=I.of(s.slice(1)),t.push(s[0],i[r].length)}}}return new Oe(t,i)}static createSet(e,t){return new Oe(e,t)}}function Pe(n,e,t,i=!1){if(e==0&&t<=0)return;let r=n.length-2;r>=0&&t<=0&&t==n[r+1]?n[r]+=e:r>=0&&e==0&&n[r]==0?n[r+1]+=t:i?(n[r]+=e,n[r+1]+=t):n.push(e,t)}function Mt(n,e,t){if(t.length==0)return;let i=e.length-2>>1;if(i<n.length)n[n.length-1]=n[n.length-1].append(t);else{for(;n.length<i;)n.push(I.empty);n.push(t)}}function To(n,e,t){let i=n.inserted;for(let r=0,s=0,o=0;o<n.sections.length;){let l=n.sections[o++],a=n.sections[o++];if(a<0)r+=l,s+=l;else{let h=r,c=s,O=I.empty;for(;h+=l,c+=a,a&&i&&(O=O.append(i[o-2>>1])),!(t||o==n.sections.length||n.sections[o+1]<0);)l=n.sections[o++],a=n.sections[o++];e(r,h,s,c,O),r=h,s=c}}}function Co(n,e,t,i=!1){let r=[],s=i?[]:null,o=new fn(n),l=new fn(e);for(let a=-1;;){if(o.done&&l.len||l.done&&o.len)throw new Error("Mismatched change set lengths");if(o.ins==-1&&l.ins==-1){let h=Math.min(o.len,l.len);Pe(r,h,-1),o.forward(h),l.forward(h)}else if(l.ins>=0&&(o.ins<0||a==o.i||o.off==0&&(l.len<o.len||l.len==o.len&&!t))){let h=l.len;for(Pe(r,l.ins,-1);h;){let c=Math.min(o.len,h);o.ins>=0&&a<o.i&&o.len<=c&&(Pe(r,0,o.ins),s&&Mt(s,r,o.text),a=o.i),o.forward(c),h-=c}l.next()}else if(o.ins>=0){let h=0,c=o.len;for(;c;)if(l.ins==-1){let O=Math.min(c,l.len);h+=O,c-=O,l.forward(O)}else if(l.ins==0&&l.len<c)c-=l.len,l.next();else break;Pe(r,h,a<o.i?o.ins:0),s&&a<o.i&&Mt(s,r,o.text),a=o.i,o.forward(o.len-c)}else{if(o.done&&l.done)return s?Oe.createSet(r,s):pt.create(r);throw new Error("Mismatched change set lengths")}}}function AO(n,e,t=!1){let i=[],r=t?[]:null,s=new fn(n),o=new fn(e);for(let l=!1;;){if(s.done&&o.done)return r?Oe.createSet(i,r):pt.create(i);if(s.ins==0)Pe(i,s.len,0,l),s.next();else if(o.len==0&&!o.done)Pe(i,0,o.ins,l),r&&Mt(r,i,o.text),o.next();else{if(s.done||o.done)throw new Error("Mismatched change set lengths");{let a=Math.min(s.len2,o.len),h=i.length;if(s.ins==-1){let c=o.ins==-1?-1:o.off?0:o.ins;Pe(i,a,c,l),r&&c&&Mt(r,i,o.text)}else o.ins==-1?(Pe(i,s.off?0:s.len,a,l),r&&Mt(r,i,s.textBit(a))):(Pe(i,s.off?0:s.len,o.off?0:o.ins,l),r&&!o.off&&Mt(r,i,o.text));l=(s.ins>a||o.ins>=0&&o.len>a)&&(l||i.length>h),s.forward2(a),o.forward(a)}}}}class fn{constructor(e){this.set=e,this.i=0,this.next()}next(){let{sections:e}=this.set;this.i<e.length?(this.len=e[this.i++],this.ins=e[this.i++]):(this.len=0,this.ins=-2),this.off=0}get done(){return this.ins==-2}get len2(){return this.ins<0?this.len:this.ins}get text(){let{inserted:e}=this.set,t=this.i-2>>1;return t>=e.length?I.empty:e[t]}textBit(e){let{inserted:t}=this.set,i=this.i-2>>1;return i>=t.length&&!e?I.empty:t[i].slice(this.off,e==null?void 0:this.off+e)}forward(e){e==this.len?this.next():(this.len-=e,this.off+=e)}forward2(e){this.ins==-1?this.forward(e):e==this.ins?this.next():(this.ins-=e,this.off+=e)}}class ii{constructor(e,t,i){this.from=e,this.to=t,this.flags=i}get anchor(){return this.flags&32?this.to:this.from}get head(){return this.flags&32?this.from:this.to}get empty(){return this.from==this.to}get assoc(){return this.flags&8?-1:this.flags&16?1:0}get bidiLevel(){let e=this.flags&7;return e==7?null:e}get goalColumn(){let e=this.flags>>6;return e==16777215?void 0:e}map(e,t=-1){let i,r;return this.empty?i=r=e.mapPos(this.from,t):(i=e.mapPos(this.from,1),r=e.mapPos(this.to,-1)),i==this.from&&r==this.to?this:new ii(i,r,this.flags)}extend(e,t=e){if(e<=this.anchor&&t>=this.anchor)return y.range(e,t);let i=Math.abs(e-this.anchor)>Math.abs(t-this.anchor)?e:t;return y.range(this.anchor,i)}eq(e,t=!1){return this.anchor==e.anchor&&this.head==e.head&&this.goalColumn==e.goalColumn&&(!t||!this.empty||this.assoc==e.assoc)}toJSON(){return{anchor:this.anchor,head:this.head}}static fromJSON(e){if(!e||typeof e.anchor!="number"||typeof e.head!="number")throw new RangeError("Invalid JSON representation for SelectionRange");return y.range(e.anchor,e.head)}static create(e,t,i){return new ii(e,t,i)}}class y{constructor(e,t){this.ranges=e,this.mainIndex=t}map(e,t=-1){return e.empty?this:y.create(this.ranges.map(i=>i.map(e,t)),this.mainIndex)}eq(e,t=!1){if(this.ranges.length!=e.ranges.length||this.mainIndex!=e.mainIndex)return!1;for(let i=0;i<this.ranges.length;i++)if(!this.ranges[i].eq(e.ranges[i],t))return!1;return!0}get main(){return this.ranges[this.mainIndex]}asSingle(){return this.ranges.length==1?this:new y([this.main],0)}addRange(e,t=!0){return y.create([e].concat(this.ranges),t?0:this.mainIndex+1)}replaceRange(e,t=this.mainIndex){let i=this.ranges.slice();return i[t]=e,y.create(i,this.mainIndex)}toJSON(){return{ranges:this.ranges.map(e=>e.toJSON()),main:this.mainIndex}}static fromJSON(e){if(!e||!Array.isArray(e.ranges)||typeof e.main!="number"||e.main>=e.ranges.length)throw new RangeError("Invalid JSON representation for EditorSelection");return new y(e.ranges.map(t=>ii.fromJSON(t)),e.main)}static single(e,t=e){return new y([y.range(e,t)],0)}static create(e,t=0){if(e.length==0)throw new RangeError("A selection needs at least one range");for(let i=0,r=0;r<e.length;r++){let s=e[r];if(s.empty?s.from<=i:s.from<i)return y.normalized(e.slice(),t);i=s.to}return new y(e,t)}static cursor(e,t=0,i,r){return ii.create(e,e,(t==0?0:t<0?8:16)|(i==null?7:Math.min(6,i))|(r??16777215)<<6)}static range(e,t,i,r){let s=(i??16777215)<<6|(r==null?7:Math.min(6,r));return t<e?ii.create(t,e,48|s):ii.create(e,t,(t>e?8:0)|s)}static normalized(e,t=0){let i=e[t];e.sort((r,s)=>r.from-s.from),t=e.indexOf(i);for(let r=1;r<e.length;r++){let s=e[r],o=e[r-1];if(s.empty?s.from<=o.to:s.from<o.to){let l=o.from,a=Math.max(s.to,o.to);r<=t&&t--,e.splice(--r,2,s.anchor>s.head?y.range(a,l):y.range(l,a))}}return new y(e,t)}}function qO(n,e){for(let t of n.ranges)if(t.to>e)throw new RangeError("Selection points outside of document")}let Rl=0;class C{constructor(e,t,i,r,s){this.combine=e,this.compareInput=t,this.compare=i,this.isStatic=r,this.id=Rl++,this.default=e([]),this.extensions=typeof s=="function"?s(this):s}get reader(){return this}static define(e={}){return new C(e.combine||(t=>t),e.compareInput||((t,i)=>t===i),e.compare||(e.combine?(t,i)=>t===i:Al),!!e.static,e.enables)}of(e){return new br([],this,0,e)}compute(e,t){if(this.isStatic)throw new Error("Can't compute a static facet");return new br(e,this,1,t)}computeN(e,t){if(this.isStatic)throw new Error("Can't compute a static facet");return new br(e,this,2,t)}from(e,t){return t||(t=i=>i),this.compute([e],i=>t(i.field(e)))}}function Al(n,e){return n==e||n.length==e.length&&n.every((t,i)=>t===e[i])}class br{constructor(e,t,i,r){this.dependencies=e,this.facet=t,this.type=i,this.value=r,this.id=Rl++}dynamicSlot(e){var t;let i=this.value,r=this.facet.compareInput,s=this.id,o=e[s]>>1,l=this.type==2,a=!1,h=!1,c=[];for(let O of this.dependencies)O=="doc"?a=!0:O=="selection"?h=!0:(((t=e[O.id])!==null&&t!==void 0?t:1)&1)==0&&c.push(e[O.id]);return{create(O){return O.values[o]=i(O),1},update(O,f){if(a&&f.docChanged||h&&(f.docChanged||f.selection)||Xo(O,c)){let u=i(O);if(l?!La(u,O.values[o],r):!r(u,O.values[o]))return O.values[o]=u,1}return 0},reconfigure:(O,f)=>{let u,d=f.config.address[s];if(d!=null){let m=qr(f,d);if(this.dependencies.every(g=>g instanceof C?f.facet(g)===O.facet(g):g instanceof ye?f.field(g,!1)==O.field(g,!1):!0)||(l?La(u=i(O),m,r):r(u=i(O),m)))return O.values[o]=m,0}else u=i(O);return O.values[o]=u,1}}}}function La(n,e,t){if(n.length!=e.length)return!1;for(let i=0;i<n.length;i++)if(!t(n[i],e[i]))return!1;return!0}function Xo(n,e){let t=!1;for(let i of e)rn(n,i)&1&&(t=!0);return t}function sm(n,e,t){let i=t.map(a=>n[a.id]),r=t.map(a=>a.type),s=i.filter(a=>!(a&1)),o=n[e.id]>>1;function l(a){let h=[];for(let c=0;c<i.length;c++){let O=qr(a,i[c]);if(r[c]==2)for(let f of O)h.push(f);else h.push(O)}return e.combine(h)}return{create(a){for(let h of i)rn(a,h);return a.values[o]=l(a),1},update(a,h){if(!Xo(a,s))return 0;let c=l(a);return e.compare(c,a.values[o])?0:(a.values[o]=c,1)},reconfigure(a,h){let c=Xo(a,i),O=h.config.facets[e.id],f=h.facet(e);if(O&&!c&&Al(t,O))return a.values[o]=f,0;let u=l(a);return e.compare(u,f)?(a.values[o]=f,0):(a.values[o]=u,1)}}}const Gn=C.define({static:!0});class ye{constructor(e,t,i,r,s){this.id=e,this.createF=t,this.updateF=i,this.compareF=r,this.spec=s,this.provides=void 0}static define(e){let t=new ye(Rl++,e.create,e.update,e.compare||((i,r)=>i===r),e);return e.provide&&(t.provides=e.provide(t)),t}create(e){let t=e.facet(Gn).find(i=>i.field==this);return((t==null?void 0:t.create)||this.createF)(e)}slot(e){let t=e[this.id]>>1;return{create:i=>(i.values[t]=this.create(i),1),update:(i,r)=>{let s=i.values[t],o=this.updateF(s,r);return this.compareF(s,o)?0:(i.values[t]=o,1)},reconfigure:(i,r)=>{let s=i.facet(Gn),o=r.facet(Gn),l;return(l=s.find(a=>a.field==this))&&l!=o.find(a=>a.field==this)?(i.values[t]=l.create(i),1):r.config.address[this.id]!=null?(i.values[t]=r.field(this),0):(i.values[t]=this.create(i),1)}}}init(e){return[this,Gn.of({field:this,create:e})]}get extension(){return this}}const Jt={lowest:4,low:3,default:2,high:1,highest:0};function ji(n){return e=>new zO(e,n)}const Zt={highest:ji(Jt.highest),high:ji(Jt.high),default:ji(Jt.default),low:ji(Jt.low),lowest:ji(Jt.lowest)};class zO{constructor(e,t){this.inner=e,this.prec=t}}class fs{of(e){return new Zo(this,e)}reconfigure(e){return fs.reconfigure.of({compartment:this,extension:e})}get(e){return e.config.compartments.get(this)}}class Zo{constructor(e,t){this.compartment=e,this.inner=t}}class Ar{constructor(e,t,i,r,s,o){for(this.base=e,this.compartments=t,this.dynamicSlots=i,this.address=r,this.staticValues=s,this.facets=o,this.statusTemplate=[];this.statusTemplate.length<i.length;)this.statusTemplate.push(0)}staticFacet(e){let t=this.address[e.id];return t==null?e.default:this.staticValues[t>>1]}static resolve(e,t,i){let r=[],s=Object.create(null),o=new Map;for(let f of om(e,t,o))f instanceof ye?r.push(f):(s[f.facet.id]||(s[f.facet.id]=[])).push(f);let l=Object.create(null),a=[],h=[];for(let f of r)l[f.id]=h.length<<1,h.push(u=>f.slot(u));let c=i==null?void 0:i.config.facets;for(let f in s){let u=s[f],d=u[0].facet,m=c&&c[f]||[];if(u.every(g=>g.type==0))if(l[d.id]=a.length<<1|1,Al(m,u))a.push(i.facet(d));else{let g=d.combine(u.map(Q=>Q.value));a.push(i&&d.compare(g,i.facet(d))?i.facet(d):g)}else{for(let g of u)g.type==0?(l[g.id]=a.length<<1|1,a.push(g.value)):(l[g.id]=h.length<<1,h.push(Q=>g.dynamicSlot(Q)));l[d.id]=h.length<<1,h.push(g=>sm(g,d,u))}}let O=h.map(f=>f(l));return new Ar(e,o,O,l,a,s)}}function om(n,e,t){let i=[[],[],[],[],[]],r=new Map;function s(o,l){let a=r.get(o);if(a!=null){if(a<=l)return;let h=i[a].indexOf(o);h>-1&&i[a].splice(h,1),o instanceof Zo&&t.delete(o.compartment)}if(r.set(o,l),Array.isArray(o))for(let h of o)s(h,l);else if(o instanceof Zo){if(t.has(o.compartment))throw new RangeError("Duplicate use of compartment in extensions");let h=e.get(o.compartment)||o.inner;t.set(o.compartment,h),s(h,l)}else if(o instanceof zO)s(o.inner,o.prec);else if(o instanceof ye)i[l].push(o),o.provides&&s(o.provides,l);else if(o instanceof br)i[l].push(o),o.facet.extensions&&s(o.facet.extensions,Jt.default);else{let h=o.extension;if(!h)throw new Error(`Unrecognized extension value in extension set (${o}). This sometimes happens because multiple instances of @codemirror/state are loaded, breaking instanceof checks.`);s(h,l)}}return s(n,Jt.default),i.reduce((o,l)=>o.concat(l))}function rn(n,e){if(e&1)return 2;let t=e>>1,i=n.status[t];if(i==4)throw new Error("Cyclic dependency between fields and/or facets");if(i&2)return i;n.status[t]=4;let r=n.computeSlot(n,n.config.dynamicSlots[t]);return n.status[t]=2|r}function qr(n,e){return e&1?n.config.staticValues[e>>1]:n.values[e>>1]}const MO=C.define(),Ro=C.define({combine:n=>n.some(e=>e),static:!0}),EO=C.define({combine:n=>n.length?n[0]:void 0,static:!0}),_O=C.define(),WO=C.define(),VO=C.define(),LO=C.define({combine:n=>n.length?n[0]:!1});class gt{constructor(e,t){this.type=e,this.value=t}static define(){return new lm}}class lm{of(e){return new gt(this,e)}}class am{constructor(e){this.map=e}of(e){return new z(this,e)}}class z{constructor(e,t){this.type=e,this.value=t}map(e){let t=this.type.map(this.value,e);return t===void 0?void 0:t==this.value?this:new z(this.type,t)}is(e){return this.type==e}static define(e={}){return new am(e.map||(t=>t))}static mapEffects(e,t){if(!e.length)return e;let i=[];for(let r of e){let s=r.map(t);s&&i.push(s)}return i}}z.reconfigure=z.define();z.appendConfig=z.define();class ae{constructor(e,t,i,r,s,o){this.startState=e,this.changes=t,this.selection=i,this.effects=r,this.annotations=s,this.scrollIntoView=o,this._doc=null,this._state=null,i&&qO(i,t.newLength),s.some(l=>l.type==ae.time)||(this.annotations=s.concat(ae.time.of(Date.now())))}static create(e,t,i,r,s,o){return new ae(e,t,i,r,s,o)}get newDoc(){return this._doc||(this._doc=this.changes.apply(this.startState.doc))}get newSelection(){return this.selection||this.startState.selection.map(this.changes)}get state(){return this._state||this.startState.applyTransaction(this),this._state}annotation(e){for(let t of this.annotations)if(t.type==e)return t.value}get docChanged(){return!this.changes.empty}get reconfigured(){return this.startState.config!=this.state.config}isUserEvent(e){let t=this.annotation(ae.userEvent);return!!(t&&(t==e||t.length>e.length&&t.slice(0,e.length)==e&&t[e.length]=="."))}}ae.time=gt.define();ae.userEvent=gt.define();ae.addToHistory=gt.define();ae.remote=gt.define();function hm(n,e){let t=[];for(let i=0,r=0;;){let s,o;if(i<n.length&&(r==e.length||e[r]>=n[i]))s=n[i++],o=n[i++];else if(r<e.length)s=e[r++],o=e[r++];else return t;!t.length||t[t.length-1]<s?t.push(s,o):t[t.length-1]<o&&(t[t.length-1]=o)}}function YO(n,e,t){var i;let r,s,o;return t?(r=e.changes,s=Oe.empty(e.changes.length),o=n.changes.compose(e.changes)):(r=e.changes.map(n.changes),s=n.changes.mapDesc(e.changes,!0),o=n.changes.compose(r)),{changes:o,selection:e.selection?e.selection.map(s):(i=n.selection)===null||i===void 0?void 0:i.map(r),effects:z.mapEffects(n.effects,r).concat(z.mapEffects(e.effects,s)),annotations:n.annotations.length?n.annotations.concat(e.annotations):e.annotations,scrollIntoView:n.scrollIntoView||e.scrollIntoView}}function Ao(n,e,t){let i=e.selection,r=bi(e.annotations);return e.userEvent&&(r=r.concat(ae.userEvent.of(e.userEvent))),{changes:e.changes instanceof Oe?e.changes:Oe.of(e.changes||[],t,n.facet(EO)),selection:i&&(i instanceof y?i:y.single(i.anchor,i.head)),effects:bi(e.effects),annotations:r,scrollIntoView:!!e.scrollIntoView}}function jO(n,e,t){let i=Ao(n,e.length?e[0]:{},n.doc.length);e.length&&e[0].filter===!1&&(t=!1);for(let s=1;s<e.length;s++){e[s].filter===!1&&(t=!1);let o=!!e[s].sequential;i=YO(i,Ao(n,e[s],o?i.changes.newLength:n.doc.length),o)}let r=ae.create(n,i.changes,i.selection,i.effects,i.annotations,i.scrollIntoView);return Om(t?cm(r):r)}function cm(n){let e=n.startState,t=!0;for(let r of e.facet(_O)){let s=r(n);if(s===!1){t=!1;break}Array.isArray(s)&&(t=t===!0?s:hm(t,s))}if(t!==!0){let r,s;if(t===!1)s=n.changes.invertedDesc,r=Oe.empty(e.doc.length);else{let o=n.changes.filter(t);r=o.changes,s=o.filtered.mapDesc(o.changes).invertedDesc}n=ae.create(e,r,n.selection&&n.selection.map(s),z.mapEffects(n.effects,s),n.annotations,n.scrollIntoView)}let i=e.facet(WO);for(let r=i.length-1;r>=0;r--){let s=i[r](n);s instanceof ae?n=s:Array.isArray(s)&&s.length==1&&s[0]instanceof ae?n=s[0]:n=jO(e,bi(s),!1)}return n}function Om(n){let e=n.startState,t=e.facet(VO),i=n;for(let r=t.length-1;r>=0;r--){let s=t[r](n);s&&Object.keys(s).length&&(i=YO(i,Ao(e,s,n.changes.newLength),!0))}return i==n?n:ae.create(e,n.changes,n.selection,i.effects,i.annotations,i.scrollIntoView)}const fm=[];function bi(n){return n==null?fm:Array.isArray(n)?n:[n]}var ne=(function(n){return n[n.Word=0]="Word",n[n.Space=1]="Space",n[n.Other=2]="Other",n})(ne||(ne={}));const um=/[\u00df\u0587\u0590-\u05f4\u0600-\u06ff\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/;let qo;try{qo=new RegExp("[\\p{Alphabetic}\\p{Number}_]","u")}catch{}function dm(n){if(qo)return qo.test(n);for(let e=0;e<n.length;e++){let t=n[e];if(/\w/.test(t)||t>""&&(t.toUpperCase()!=t.toLowerCase()||um.test(t)))return!0}return!1}function pm(n){return e=>{if(!/\S/.test(e))return ne.Space;if(dm(e))return ne.Word;for(let t=0;t<n.length;t++)if(e.indexOf(n[t])>-1)return ne.Word;return ne.Other}}class D{constructor(e,t,i,r,s,o){this.config=e,this.doc=t,this.selection=i,this.values=r,this.status=e.statusTemplate.slice(),this.computeSlot=s,o&&(o._state=this);for(let l=0;l<this.config.dynamicSlots.length;l++)rn(this,l<<1);this.computeSlot=null}field(e,t=!0){let i=this.config.address[e.id];if(i==null){if(t)throw new RangeError("Field is not present in this state");return}return rn(this,i),qr(this,i)}update(...e){return jO(this,e,!0)}applyTransaction(e){let t=this.config,{base:i,compartments:r}=t;for(let l of e.effects)l.is(fs.reconfigure)?(t&&(r=new Map,t.compartments.forEach((a,h)=>r.set(h,a)),t=null),r.set(l.value.compartment,l.value.extension)):l.is(z.reconfigure)?(t=null,i=l.value):l.is(z.appendConfig)&&(t=null,i=bi(i).concat(l.value));let s;t?s=e.startState.values.slice():(t=Ar.resolve(i,r,this),s=new D(t,this.doc,this.selection,t.dynamicSlots.map(()=>null),(a,h)=>h.reconfigure(a,this),null).values);let o=e.startState.facet(Ro)?e.newSelection:e.newSelection.asSingle();new D(t,e.newDoc,o,s,(l,a)=>a.update(l,e),e)}replaceSelection(e){return typeof e=="string"&&(e=this.toText(e)),this.changeByRange(t=>({changes:{from:t.from,to:t.to,insert:e},range:y.cursor(t.from+e.length)}))}changeByRange(e){let t=this.selection,i=e(t.ranges[0]),r=this.changes(i.changes),s=[i.range],o=bi(i.effects);for(let l=1;l<t.ranges.length;l++){let a=e(t.ranges[l]),h=this.changes(a.changes),c=h.map(r);for(let f=0;f<l;f++)s[f]=s[f].map(c);let O=r.mapDesc(h,!0);s.push(a.range.map(O)),r=r.compose(c),o=z.mapEffects(o,c).concat(z.mapEffects(bi(a.effects),O))}return{changes:r,selection:y.create(s,t.mainIndex),effects:o}}changes(e=[]){return e instanceof Oe?e:Oe.of(e,this.doc.length,this.facet(D.lineSeparator))}toText(e){return I.of(e.split(this.facet(D.lineSeparator)||vo))}sliceDoc(e=0,t=this.doc.length){return this.doc.sliceString(e,t,this.lineBreak)}facet(e){let t=this.config.address[e.id];return t==null?e.default:(rn(this,t),qr(this,t))}toJSON(e){let t={doc:this.sliceDoc(),selection:this.selection.toJSON()};if(e)for(let i in e){let r=e[i];r instanceof ye&&this.config.address[r.id]!=null&&(t[i]=r.spec.toJSON(this.field(e[i]),this))}return t}static fromJSON(e,t={},i){if(!e||typeof e.doc!="string")throw new RangeError("Invalid JSON representation for EditorState");let r=[];if(i){for(let s in i)if(Object.prototype.hasOwnProperty.call(e,s)){let o=i[s],l=e[s];r.push(o.init(a=>o.spec.fromJSON(l,a)))}}return D.create({doc:e.doc,selection:y.fromJSON(e.selection),extensions:t.extensions?r.concat([t.extensions]):r})}static create(e={}){let t=Ar.resolve(e.extensions||[],new Map),i=e.doc instanceof I?e.doc:I.of((e.doc||"").split(t.staticFacet(D.lineSeparator)||vo)),r=e.selection?e.selection instanceof y?e.selection:y.single(e.selection.anchor,e.selection.head):y.single(0);return qO(r,i.length),t.staticFacet(Ro)||(r=r.asSingle()),new D(t,i,r,t.dynamicSlots.map(()=>null),(s,o)=>o.create(s),null)}get tabSize(){return this.facet(D.tabSize)}get lineBreak(){return this.facet(D.lineSeparator)||`
|