@coopcli/specsketch 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (178) hide show
  1. package/README.md +141 -0
  2. package/dist/cli/index.js +415 -0
  3. package/dist/client/assets/Assistant-Bold-gm-uSS1B.woff2 +0 -0
  4. package/dist/client/assets/Assistant-Medium-DrcxCXg3.woff2 +0 -0
  5. package/dist/client/assets/Assistant-Regular-DVxZuzxb.woff2 +0 -0
  6. package/dist/client/assets/Assistant-SemiBold-SCI4bEL9.woff2 +0 -0
  7. package/dist/client/assets/abnfDiagram-VRR7QNED-16f2_bGI.js +1 -0
  8. package/dist/client/assets/ar-SA-G6X2FPQ2-BliMWHsq.js +10 -0
  9. package/dist/client/assets/arc-CS-8wk7Q.js +1 -0
  10. package/dist/client/assets/architecture-TIHT7OUA-BKt6Bp_c.js +1 -0
  11. package/dist/client/assets/architectureDiagram-ZJ3FMSHR-6GbpEUM7.js +36 -0
  12. package/dist/client/assets/array-BifhSqXX.js +1 -0
  13. package/dist/client/assets/az-AZ-76LH7QW2-CcmHdpe_.js +1 -0
  14. package/dist/client/assets/bg-BG-XCXSNQG7-9y6uaOsa.js +5 -0
  15. package/dist/client/assets/blockDiagram-677ZJIJ3-BcMBzAms.js +132 -0
  16. package/dist/client/assets/bn-BD-2XOGV67Q-DMquxXr0.js +5 -0
  17. package/dist/client/assets/c4Diagram-LMCZKHZV-DKpo9yq8.js +10 -0
  18. package/dist/client/assets/ca-ES-6MX7JW3Y-DDkONtTz.js +8 -0
  19. package/dist/client/assets/channel-5C_-bpkt.js +1 -0
  20. package/dist/client/assets/chunk-2Q5K7J3B-C1jixKkw.js +1 -0
  21. package/dist/client/assets/chunk-32BRIVSS-DEyl_Nxr.js +1 -0
  22. package/dist/client/assets/chunk-52WLFC77-BRiX6aHf.js +10 -0
  23. package/dist/client/assets/chunk-5VM5RSS4-ZNzvKenW.js +15 -0
  24. package/dist/client/assets/chunk-7BUUIJ7U-Bb538aSH.js +1 -0
  25. package/dist/client/assets/chunk-C7G6YPKG-VAfRRT73.js +1 -0
  26. package/dist/client/assets/chunk-EIO257PC-PJvXSxFd.js +22 -0
  27. package/dist/client/assets/chunk-EX3LRPZG-B12uDakm.js +231 -0
  28. package/dist/client/assets/chunk-FWX5IMBZ-DJqByAOU.js +2 -0
  29. package/dist/client/assets/chunk-HOUHSVGY-uqo-OtAa.js +1 -0
  30. package/dist/client/assets/chunk-ICXQ74PX-CAeU_wWJ.js +2 -0
  31. package/dist/client/assets/chunk-JWPE2WC7-DVXcaiue.js +1 -0
  32. package/dist/client/assets/chunk-KEIR6QF5-BfrZ3jm6.js +161 -0
  33. package/dist/client/assets/chunk-MOJQB5TN-D8mFPGTn.js +88 -0
  34. package/dist/client/assets/chunk-OGEWGWER-rSblczmM.js +1 -0
  35. package/dist/client/assets/chunk-PUDLZKDR-N4MYeMg7.js +156 -0
  36. package/dist/client/assets/chunk-Q4XR5HBZ-DIiKBTGe.js +70 -0
  37. package/dist/client/assets/chunk-RYQCIY6F-CmGX33Ed.js +1 -0
  38. package/dist/client/assets/chunk-V7JOEXUC-D5EtXGKT.js +206 -0
  39. package/dist/client/assets/chunk-VAUOI2AC-DCK8rog6.js +1 -0
  40. package/dist/client/assets/chunk-VR4S4FIN-CM912FqX.js +1 -0
  41. package/dist/client/assets/chunk-WYO6CB5R-2iEnPkYI.js +127 -0
  42. package/dist/client/assets/chunk-XXDRQBXY-B_lJn00H.js +1 -0
  43. package/dist/client/assets/chunk-Y2CYZVJY-DsF7k-Jl.js +1 -0
  44. package/dist/client/assets/chunk-ZGVPDNZ5-CUa-NP8T.js +62 -0
  45. package/dist/client/assets/chunk-ZIRB5QZD-C6fEPe3t.js +32 -0
  46. package/dist/client/assets/classDiagram-OUVF2IWQ-CCWQPaLx.js +1 -0
  47. package/dist/client/assets/classDiagram-v2-EOCWNBFH-CCWQPaLx.js +1 -0
  48. package/dist/client/assets/cose-bilkent-JH36ORCC-pqulBXGU.js +1 -0
  49. package/dist/client/assets/cs-CZ-2BRQDIVT-zXFHXuyN.js +11 -0
  50. package/dist/client/assets/cynefin-VYW2F7L2-Qe97INb_.js +1 -0
  51. package/dist/client/assets/cynefinDiagram-TSTJHNR4-D3j6Tzbk.js +62 -0
  52. package/dist/client/assets/cytoscape.esm-B3I8pqwA.js +321 -0
  53. package/dist/client/assets/da-DK-5WZEPLOC-RsMDMFPN.js +5 -0
  54. package/dist/client/assets/dagre-CXRCoUWR.js +1 -0
  55. package/dist/client/assets/dagre-VKFMJZFB-C8Ytm7T9.js +4 -0
  56. package/dist/client/assets/de-DE-XR44H4JA-rbMWNgc4.js +8 -0
  57. package/dist/client/assets/defaultLocale-C8Fc0cco.js +1 -0
  58. package/dist/client/assets/diagram-FQU43EPY-4gygVoas.js +3 -0
  59. package/dist/client/assets/diagram-G47NLZAW-waBcZ0zD.js +24 -0
  60. package/dist/client/assets/diagram-NH7WQ7WH-CYaesizm.js +24 -0
  61. package/dist/client/assets/diagram-OA4YK3LP-D83Nh9sN.js +30 -0
  62. package/dist/client/assets/diagram-WEI45ONY-CGfmm2WY.js +41 -0
  63. package/dist/client/assets/directory-open-01563666-D4xXyWb_.js +1 -0
  64. package/dist/client/assets/directory-open-4ed118d0-1i309Asm.js +1 -0
  65. package/dist/client/assets/dist-C8c_sMtm.js +1 -0
  66. package/dist/client/assets/dist-f8OLlO52.js +29 -0
  67. package/dist/client/assets/ebnfDiagram-CCIWWBDH-BlZiBb4S.js +1 -0
  68. package/dist/client/assets/el-GR-BZB4AONW-DZqM9E36.js +10 -0
  69. package/dist/client/assets/en-B4ZKOASM-Caam9N-X.js +1 -0
  70. package/dist/client/assets/erDiagram-Q63AITRT-zNSJaDnM.js +85 -0
  71. package/dist/client/assets/es-ES-U4NZUMDT-qzXKymTT.js +9 -0
  72. package/dist/client/assets/eu-ES-A7QVB2H4-CtY7Xg2M.js +11 -0
  73. package/dist/client/assets/eventmodeling-45OFAUF4-CQvE-Zz6.js +1 -0
  74. package/dist/client/assets/fa-IR-HGAKTJCU-DEgH3Hqn.js +8 -0
  75. package/dist/client/assets/fi-FI-Z5N7JZ37-BsnE5kmt.js +6 -0
  76. package/dist/client/assets/file-open-002ab408-BHUWm0Sh.js +1 -0
  77. package/dist/client/assets/file-open-7c801643-DZtJT5zp.js +1 -0
  78. package/dist/client/assets/file-save-3189631c-CO9S4HFW.js +1 -0
  79. package/dist/client/assets/file-save-745eba88-Bwdfz6OZ.js +1 -0
  80. package/dist/client/assets/flowDiagram-23GEKE2U-BZlpWoyS.js +1 -0
  81. package/dist/client/assets/fr-FR-RHASNOE6-D5jzcSio.js +9 -0
  82. package/dist/client/assets/ganttDiagram-NO4QXBWP-CcO5dZaj.js +292 -0
  83. package/dist/client/assets/gitGraph-TEB2WS4Q-BYZp8XwK.js +1 -0
  84. package/dist/client/assets/gitGraphDiagram-IHSO6WYX-C2sgRW8z.js +106 -0
  85. package/dist/client/assets/gl-ES-HMX3MZ6V-CYCG2w9g.js +10 -0
  86. package/dist/client/assets/graphlib-B8gBHxth.js +1 -0
  87. package/dist/client/assets/he-IL-6SHJWFNN--yDEZbty.js +10 -0
  88. package/dist/client/assets/hi-IN-IWLTKZ5I-DRwKRLQJ.js +4 -0
  89. package/dist/client/assets/hu-HU-A5ZG7DT2-IcuCiqhE.js +7 -0
  90. package/dist/client/assets/id-ID-SAP4L64H-DTH2ARbd.js +10 -0
  91. package/dist/client/assets/image-GAAHSSAO-BgFjo4xZ.js +1 -0
  92. package/dist/client/assets/image-blob-reduce.esm-DLFdRAwc.js +2 -0
  93. package/dist/client/assets/index-J0gDT2pS.js +270 -0
  94. package/dist/client/assets/index-Ws5zYxgd.css +1 -0
  95. package/dist/client/assets/info-DKCQHKI2-CRI7fa22.js +1 -0
  96. package/dist/client/assets/infoDiagram-FWYZ7A6U-Bnc2s3td.js +2 -0
  97. package/dist/client/assets/init-D6jRqBbL.js +1 -0
  98. package/dist/client/assets/ishikawaDiagram-FXEZZL3T-DSTRhHYZ.js +70 -0
  99. package/dist/client/assets/it-IT-JPQ66NNP-CYPBIFaT.js +11 -0
  100. package/dist/client/assets/ja-JP-DBVTYXUO-Q3XQ-5r8.js +8 -0
  101. package/dist/client/assets/journeyDiagram-5HDEW3XC-DJrtsHPH.js +139 -0
  102. package/dist/client/assets/kaa-6HZHGXH3-9BnW5XLF.js +1 -0
  103. package/dist/client/assets/kab-KAB-ZGHBKWFO-aoc5dPpL.js +8 -0
  104. package/dist/client/assets/kanban-definition-HUTT4EX6--pNIAYZI.js +89 -0
  105. package/dist/client/assets/katex-CddkPoXu.js +257 -0
  106. package/dist/client/assets/kk-KZ-P5N5QNE5-C9fO5cSG.js +1 -0
  107. package/dist/client/assets/km-KH-HSX4SM5Z-BNuQyN_P.js +11 -0
  108. package/dist/client/assets/ko-KR-MTYHY66A-Dds6B1O1.js +9 -0
  109. package/dist/client/assets/ku-TR-6OUDTVRD-BrWFBN_R.js +9 -0
  110. package/dist/client/assets/line-DWcTvCm-.js +1 -0
  111. package/dist/client/assets/linear-Dcedcc10.js +1 -0
  112. package/dist/client/assets/lt-LT-XHIRWOB4--cJLduJu.js +3 -0
  113. package/dist/client/assets/lv-LV-5QDEKY6T-DDV1U75_.js +7 -0
  114. package/dist/client/assets/map-DsCK-0Cs.js +1 -0
  115. package/dist/client/assets/mermaid-parser.core-BqfnOrIO.js +7 -0
  116. package/dist/client/assets/mindmap-definition-LN4V7U3C-BSrRrH_A.js +96 -0
  117. package/dist/client/assets/mr-IN-CRQNXWMA-BZFiW11y.js +13 -0
  118. package/dist/client/assets/my-MM-5M5IBNSE-B5vq5uIU.js +1 -0
  119. package/dist/client/assets/nb-NO-T6EIAALU-DssJfvx1.js +10 -0
  120. package/dist/client/assets/nl-NL-IS3SIHDZ-DofDpxLe.js +8 -0
  121. package/dist/client/assets/nn-NO-6E72VCQL-COWIwAdQ.js +8 -0
  122. package/dist/client/assets/oc-FR-POXYY2M6-bMMGZDFH.js +8 -0
  123. package/dist/client/assets/ordinal-hYBb2elL.js +1 -0
  124. package/dist/client/assets/pa-IN-N4M65BXN-CN09z_Xv.js +4 -0
  125. package/dist/client/assets/packet-7NZHBO7P-CuYIlMin.js +1 -0
  126. package/dist/client/assets/path-BWPyau1x.js +1 -0
  127. package/dist/client/assets/pegDiagram-2B236MQR-C0BbVZwA.js +1 -0
  128. package/dist/client/assets/percentages-BXMCSKIN-BonUZTZd.js +1 -0
  129. package/dist/client/assets/pica-LQ2hHv1b.js +2 -0
  130. package/dist/client/assets/pie-RZYD4A2V-B7Aa9X74.js +1 -0
  131. package/dist/client/assets/pieDiagram-ENE6RG2P-C0wH5T9e.js +39 -0
  132. package/dist/client/assets/pl-PL-T2D74RX3-Hzfv9oIJ.js +9 -0
  133. package/dist/client/assets/pt-BR-5N22H2LF-CrT9HM0t.js +9 -0
  134. package/dist/client/assets/pt-PT-UZXXM6DQ-oUYp_awL.js +9 -0
  135. package/dist/client/assets/quadrantDiagram-ABIIQ3AL-CL6G6yBt.js +7 -0
  136. package/dist/client/assets/radar-I7S5WNFK-L34bXC8_.js +1 -0
  137. package/dist/client/assets/railroad-3IZDKUUU-q-0aBpk4.js +1 -0
  138. package/dist/client/assets/railroad-abnf-AHOZXSZD-DyhYVkRo.js +1 -0
  139. package/dist/client/assets/railroad-ebnf-EBAXGLYW-CyqxDZEz.js +1 -0
  140. package/dist/client/assets/railroad-peg-LSFZ7HO6-DDlWiY_v.js +1 -0
  141. package/dist/client/assets/railroadDiagram-RFXS5EU6-Dhq_UFr5.js +1 -0
  142. package/dist/client/assets/requirementDiagram-TGXJPOKE-BzIV3auq.js +84 -0
  143. package/dist/client/assets/ro-RO-JPDTUUEW-DBJstEDv.js +11 -0
  144. package/dist/client/assets/rolldown-runtime-BHe-jwch.js +1 -0
  145. package/dist/client/assets/rough.esm-CSKSodPl.js +1 -0
  146. package/dist/client/assets/roundRect-D01gJrlt.js +1 -0
  147. package/dist/client/assets/ru-RU-B4JR7IUQ-DX7bFYoq.js +9 -0
  148. package/dist/client/assets/sankeyDiagram-HTMAVEWB-CPjEKlV1.js +40 -0
  149. package/dist/client/assets/sequenceDiagram-DBY2YBRQ-Cp0Cdfw0.js +162 -0
  150. package/dist/client/assets/si-LK-N5RQ5JYF-Bv0pdm0z.js +1 -0
  151. package/dist/client/assets/sizeCapture-X5ZJPWSS-B0uUizjq.js +1 -0
  152. package/dist/client/assets/sk-SK-C5VTKIMK-D1iTSf5f.js +6 -0
  153. package/dist/client/assets/sl-SI-NN7IZMDC-BqH5ecAz.js +6 -0
  154. package/dist/client/assets/src-DpN7Pt3R.js +1 -0
  155. package/dist/client/assets/stateDiagram-2N3HPSRC-FNhi3doi.js +1 -0
  156. package/dist/client/assets/stateDiagram-v2-6OUMAXLB-CQz3pB3W.js +1 -0
  157. package/dist/client/assets/subset-shared.chunk-AWyPT4lx.js +1 -0
  158. package/dist/client/assets/subset-worker.chunk-Dirfxwpm.js +1 -0
  159. package/dist/client/assets/sv-SE-XGPEYMSR-hfi5sOoT.js +10 -0
  160. package/dist/client/assets/swimlanes-5IMT3BWC-Bc45sTzh.js +2 -0
  161. package/dist/client/assets/swimlanesDiagram-G3AALYLV-aBAqktof.js +8 -0
  162. package/dist/client/assets/ta-IN-2NMHFXQM-B3RmLnFO.js +9 -0
  163. package/dist/client/assets/th-TH-HPSO5L25-z7coHf9c.js +2 -0
  164. package/dist/client/assets/timeline-definition-FHXFAJF6-CUCLhtwj.js +120 -0
  165. package/dist/client/assets/tr-TR-DEFEU3FU-oKbLZIQc.js +7 -0
  166. package/dist/client/assets/treeView-QDETBFTQ-gEqM1aZw.js +1 -0
  167. package/dist/client/assets/treemap-6X3UGDF4-Cpkr6IjV.js +1 -0
  168. package/dist/client/assets/uk-UA-QMV73CPH-BpDJuMHs.js +6 -0
  169. package/dist/client/assets/vennDiagram-L72KCM5P-BSP_kJAN.js +34 -0
  170. package/dist/client/assets/vi-VN-M7AON7JQ-DBfMeBJv.js +5 -0
  171. package/dist/client/assets/wardley-OPB4EBWU-BO-I7Hgc.js +1 -0
  172. package/dist/client/assets/wardleyDiagram-EHGQE667-BBhTfl1P.js +78 -0
  173. package/dist/client/assets/xychartDiagram-FW5EYKEG-CKj06EtN.js +7 -0
  174. package/dist/client/assets/zh-CN-LNUGB5OW-CnPPsSDv.js +10 -0
  175. package/dist/client/assets/zh-HK-E62DVLB3-CV2WuKCN.js +1 -0
  176. package/dist/client/assets/zh-TW-RAJ6MFWO-BFCIDL_e.js +9 -0
  177. package/dist/client/index.html +14 -0
  178. package/package.json +71 -0
package/README.md ADDED
@@ -0,0 +1,141 @@
1
+ # SpecSketch
2
+
3
+ Diagram a system with your team in real time, talk it through, and turn the result into an
4
+ **OpenSpec** change proposal. Boxes and arrows + conversation in → a reviewable, spec-shaped
5
+ proposal out.
6
+
7
+ This repo is **spec-first**: `openspec/` is the source of truth for what SpecSketch does. The
8
+ code in `src/` is the Phase 1 reference implementation of those specs.
9
+
10
+ ## Product shape (phased)
11
+
12
+ - **Phase 1 — diagram → spec (built).** A single browser session: draw an architecture on an
13
+ Excalidraw canvas, press **Generate Spec**, and an agentic workflow (Flue) returns an OpenSpec
14
+ change proposal (proposal / design / tasks / capability specs).
15
+ - **Phase 2 — real-time collaboration.** Multiple engineers on one server-authoritative canvas
16
+ (Durable Object over WebSocket), with presence and shareable session links.
17
+ - **Phase 3 — voice & specs-from-conversation.** Live audio/video over Cloudflare Realtime
18
+ (WebRTC), transcription, and feeding the transcript into spec generation.
19
+
20
+ ## Architecture (Phase 1)
21
+
22
+ ```
23
+ Browser (Workers Assets) Cloudflare Worker
24
+ ┌───────────────────────────┐ ┌──────────────────────────────┐
25
+ │ React + @excalidraw │ POST │ src/app.ts (Hono @ /api) │
26
+ │ architecture canvas │ ───────► │ /api/workflows/spec-builder│
27
+ │ [Generate Spec] │ graph │ │ │
28
+ │ │ (JSON) │ ▼ │
29
+ │ ◄── OpenSpec artifacts ────┼──────────┤ Flue workflow (Durable │
30
+ └───────────────────────────┘ bundle │ Object) → Anthropic Claude │
31
+ │ │ structured output │
32
+ │ ▼ (SpecBundle) │
33
+ └──────────────────────────────┘
34
+ ```
35
+
36
+ The client distills the raw Excalidraw scene into a compact `{nodes, edges, notes}` graph
37
+ (`src/ui/scene.ts`); the `spec-builder` workflow (`src/workflows/spec-builder.ts`) turns it into
38
+ a validated `SpecBundle` (`src/lib/schema.ts`), rendered as browsable artifacts.
39
+
40
+ ## Stack
41
+
42
+ - **Cloudflare Workers + Workers Assets** — one Worker serves the SPA and the API.
43
+ - **Flue** (`@flue/runtime`, `@flue/cli`) — AI agent orchestration; each workflow is a Durable
44
+ Object. Provider: Anthropic (Claude); the Workers `AI` binding is also available.
45
+ - **Excalidraw** (`@excalidraw/excalidraw`) — the drawing surface.
46
+ - **valibot** — shared request/response schemas (UI + workflow).
47
+ - **Cloudflare Realtime** (Phase 3) — WebRTC SFU for audio/video.
48
+
49
+ ## coopcli specsketch (npm CLI)
50
+
51
+ The distributable, local-only CLI. The OpenSpec change directory you pass is the workspace:
52
+ the Excalidraw session autosaves to `diagram.excalidraw` inside it, and **Generate Spec**
53
+ writes `proposal.md`, `design.md`, `tasks.md`, and `specs/<capability>/spec.md` there — so an
54
+ implementing agent can reference both the specs and the diagram that produced them. Existing
55
+ artifacts are taken as the baseline; regeneration makes the smallest change that fulfills the
56
+ drawing.
57
+
58
+ ```bash
59
+ npx @coopcli/specsketch ./openspec/changes/new-feature-change
60
+ # or: npm install -g @coopcli/specsketch && specsketch ./openspec/changes/new-feature-change
61
+ ```
62
+
63
+ Binds to 127.0.0.1 only (no `--host`); `--port` defaults to 8787. Stop and rerun with the
64
+ same directory to resume where you left off. Local dev of the CLI itself:
65
+ `npm run build:cli` then `node dist/cli/index.js <change-dir>`.
66
+
67
+ ## Getting started (local MVP)
68
+
69
+ ```bash
70
+ npm install
71
+ npm run dev # web (Vite, http://localhost:5173) + api (Hono/Node, :8787)
72
+ ```
73
+
74
+ Open <http://localhost:5173> — a unique canvas URL is minted automatically. Draw labeled boxes
75
+ and arrows, click **Generate Spec**, then use the top-bar **Canvas | Spec** toggle to read the
76
+ generated OpenSpec proposal.
77
+
78
+ **Auth:** the backend calls Anthropic via `new Anthropic()` with no key configured — the SDK
79
+ resolves the local authed session (`ANTHROPIC_API_KEY` → `ANTHROPIC_AUTH_TOKEN` → the active
80
+ `ant auth login` / Claude Code profile). As a dev convenience the local server also reads
81
+ `ANTHROPIC_API_KEY` from `.dev.vars` (the same file the Cloudflare dev flow uses) when the
82
+ environment has no credentials. If a generate call 401s, run `ant auth status`; never paste a
83
+ key into the code.
84
+
85
+ Other scripts:
86
+
87
+ ```bash
88
+ npm run check # tsc --noEmit
89
+ npm test # vitest — unit + integration tests, no credentials needed
90
+ npm run server # api only (tsx watch server/index.ts)
91
+ npm run web # web only (vite)
92
+ npm run smoke # live end-to-end check against a running server (needs auth)
93
+ ```
94
+
95
+ See [TESTING.md](TESTING.md) for the manual QA checklist mapped to the OpenSpec scenarios.
96
+
97
+ ### Cloudflare/Flue production path
98
+
99
+ The Cloudflare deployment (single Worker + Flue Durable Objects) is kept intact under the
100
+ `*:cf` scripts and is not used by the local MVP:
101
+
102
+ ```bash
103
+ cp .dev.vars.example .dev.vars # add your ANTHROPIC_API_KEY
104
+ npm run dev:cf # build the UI, then flue dev --target cloudflare (http://localhost:3583)
105
+ npm run build:cf # vite build → flue build --target cloudflare → patch asset binding
106
+ npx wrangler secret put ANTHROPIC_API_KEY
107
+ npm run deploy:cf # build, then wrangler deploy the generated config
108
+ ```
109
+
110
+ ## OpenSpec roadmap
111
+
112
+ All outcomes are defined as validated OpenSpec change proposals under `openspec/changes/`.
113
+ Each change is a thin, independently implementable/testable slice; its spec scenarios are the QA
114
+ acceptance criteria. Run `npx openspec list` / `npx openspec validate --all`.
115
+
116
+ | Phase | Change | Capability(ies) | Status |
117
+ |-------|--------|-----------------|--------|
118
+ | 1 | `phase-1-diagram-to-spec` | architecture-canvas, diagram-interpretation, spec-generation, openspec-artifacts, worker-platform | scaffold built |
119
+ | 2 | `canvas-room-durable-object` | canvas-room | proposed |
120
+ | 2 | `realtime-canvas-sync` | realtime-canvas-sync | proposed |
121
+ | 2 | `collaboration-presence` | collaboration-presence | proposed |
122
+ | 2 | `shareable-session-links` | shareable-session-links | proposed |
123
+ | 3 | `realtime-voice-signaling` | realtime-voice-session | proposed |
124
+ | 3 | `voice-audio` | voice-audio | proposed |
125
+ | 3 | `participant-video` | participant-video | proposed |
126
+ | 3 | `conversation-transcription` | conversation-transcription | proposed |
127
+ | 3 | `transcript-informed-specs` | transcript-informed-specs | proposed |
128
+ | — | `spec-persistence-and-export` | spec-persistence-and-export | proposed |
129
+ | — | `coopcli-specsketch-distribution` | npm-distribution, local-persistence, product-microsite | proposed |
130
+
131
+ Suggested implementation order follows the table (each Phase 2/3 change builds on the one above
132
+ it). The `spec-builder` workflow already dogfoods this format — its output is exactly these
133
+ artifacts.
134
+
135
+ ## Notes
136
+
137
+ - **Model**: pinned to a verified Flue specifier in one constant in `src/workflows/spec-builder.ts`;
138
+ bump it there as newer Claude specifiers are confirmed in Flue's provider mapping.
139
+ - **Flue beta asset binding**: `flue build` (beta) regenerates the Cloudflare config and currently
140
+ drops the user `assets` block, so `scripts/patch-assets.mjs` re-injects it after the build. Once
141
+ Flue propagates user asset config, delete that script and its `build` step.
@@ -0,0 +1,415 @@
1
+ #!/usr/bin/env node
2
+
3
+ // server/cli.ts
4
+ import { existsSync as existsSync2, readFileSync as readFileSync2 } from "node:fs";
5
+ import { dirname as dirname2, extname, join as join2, normalize, resolve as resolve2 } from "node:path";
6
+ import { fileURLToPath } from "node:url";
7
+ import { parseArgs } from "node:util";
8
+ import { serve } from "@hono/node-server";
9
+ import Anthropic from "@anthropic-ai/sdk";
10
+
11
+ // server/app.ts
12
+ import { zodOutputFormat } from "@anthropic-ai/sdk/helpers/zod";
13
+ import { Hono } from "hono";
14
+
15
+ // src/lib/schema.ts
16
+ import { z } from "zod";
17
+ var DiagramNode = z.object({
18
+ /** Stable short id assigned by the client (n1, n2, ...). */
19
+ id: z.string(),
20
+ /** Human label (bound text), or a shape placeholder when unlabeled. */
21
+ label: z.string(),
22
+ /** Excalidraw shape kind: rectangle | ellipse | diamond | frame | image. */
23
+ shape: z.string()
24
+ });
25
+ var DiagramEdge = z.object({
26
+ from: z.string(),
27
+ to: z.string(),
28
+ label: z.string().optional()
29
+ });
30
+ var DiagramGraph = z.object({
31
+ nodes: z.array(DiagramNode),
32
+ edges: z.array(DiagramEdge),
33
+ /** Free-floating text on the canvas (design notes, constraints, questions). */
34
+ notes: z.array(z.string())
35
+ });
36
+ var SpecRequest = z.object({
37
+ title: z.string().optional(),
38
+ graph: DiagramGraph
39
+ });
40
+ var CapabilitySpec = z.object({
41
+ capability: z.string(),
42
+ spec: z.string()
43
+ });
44
+ var SpecBundle = z.object({
45
+ /** kebab-case change id, e.g. "add-realtime-canvas". */
46
+ changeName: z.string(),
47
+ /** One-paragraph plain-language summary of the architecture. */
48
+ summary: z.string(),
49
+ /** proposal.md — why + what is changing. */
50
+ proposal: z.string(),
51
+ /** design.md — technical approach, components, data flow, decisions. */
52
+ design: z.string(),
53
+ /** tasks.md — implementation checklist. */
54
+ tasks: z.string(),
55
+ /** One entry per capability the architecture introduces. */
56
+ specs: z.array(CapabilitySpec)
57
+ });
58
+ var ExcalidrawScene = z.object({
59
+ elements: z.array(z.unknown()),
60
+ appState: z.record(z.string(), z.unknown()).optional(),
61
+ files: z.record(z.string(), z.unknown()).optional()
62
+ });
63
+ var SessionSave = z.object({
64
+ scene: ExcalidrawScene,
65
+ title: z.string().optional()
66
+ });
67
+ var SessionSnapshot = z.object({
68
+ changeName: z.string(),
69
+ title: z.string().optional(),
70
+ scene: ExcalidrawScene.nullable(),
71
+ bundle: SpecBundle.nullable()
72
+ });
73
+
74
+ // server/app.ts
75
+ var MODEL = "claude-opus-4-8";
76
+ var SYSTEM = `You are a principal software architect and specification writer.
77
+ Given an architecture diagram as a graph (nodes = components/services/datastores/actors,
78
+ directed edges = data/control flow, notes = constraints/decisions), infer the intended system
79
+ and produce an OpenSpec change proposal.
80
+
81
+ Follow OpenSpec conventions:
82
+ - proposal: motivation (why) + what's changing.
83
+ - design: components & responsibilities, data flow, key decisions/trade-offs, open questions.
84
+ - tasks: an ordered "- [ ] " implementation checklist grouped by area.
85
+ - Each capability the architecture introduces gets its own spec: a Purpose paragraph,
86
+ "The system SHALL ..." requirements, and a "WHEN / THEN" scenario per requirement.
87
+ - changeName and capability ids are kebab-case.
88
+ Ground every requirement in what the diagram shows; record ambiguity as an assumption in design
89
+ rather than inventing unrelated features. Prefer 2-5 focused capabilities.`;
90
+ function renderBaseline(ws) {
91
+ const a = ws.readArtifacts();
92
+ const sections = [];
93
+ if (a.proposal) sections.push(`--- proposal.md ---
94
+ ${a.proposal}`);
95
+ if (a.design) sections.push(`--- design.md ---
96
+ ${a.design}`);
97
+ if (a.tasks) sections.push(`--- tasks.md ---
98
+ ${a.tasks}`);
99
+ for (const s of a.specs) sections.push(`--- specs/${s.capability}/spec.md ---
100
+ ${s.spec}`);
101
+ if (sections.length === 0) return "";
102
+ return `
103
+
104
+ The change directory already contains these OpenSpec artifacts. Treat them as the baseline: make the SMALLEST revision that brings the OpenSpec in line with the diagram. Keep content the diagram does not contradict verbatim (do not paraphrase or restructure it); add or modify only what the diagram implicates. Return the complete artifact set with those minimal edits applied.
105
+
106
+ ${sections.join("\n\n")}`;
107
+ }
108
+ function renderGraph(g) {
109
+ const nodes = g.nodes.length ? g.nodes.map((n) => ` - ${n.id} [${n.shape}]: ${n.label}`).join("\n") : " (none)";
110
+ const edges = g.edges.length ? g.edges.map((e) => ` - ${e.from} -> ${e.to}${e.label ? ` : ${e.label}` : ""}`).join("\n") : " (none)";
111
+ const notes = g.notes.length ? g.notes.map((t) => ` - ${t}`).join("\n") : " (none)";
112
+ return `Nodes:
113
+ ${nodes}
114
+
115
+ Edges (from -> to):
116
+ ${edges}
117
+
118
+ Notes:
119
+ ${notes}`;
120
+ }
121
+ function createApp(anthropic, workspace) {
122
+ const app = new Hono();
123
+ app.get("/api/health", (c) => c.json({ ok: true }));
124
+ app.get("/api/config", (c) => c.json({ workspace: Boolean(workspace) }));
125
+ if (workspace) {
126
+ app.get(
127
+ "/api/session",
128
+ (c) => c.json({
129
+ changeName: workspace.changeName,
130
+ title: workspace.readSidecar().title,
131
+ scene: workspace.loadScene(),
132
+ bundle: workspace.toBundle()
133
+ })
134
+ );
135
+ app.put("/api/session", async (c) => {
136
+ const parsed = SessionSave.safeParse(await c.req.json().catch(() => null));
137
+ if (!parsed.success) {
138
+ return c.json({ error: "invalid session", detail: parsed.error.issues }, 400);
139
+ }
140
+ workspace.saveScene(parsed.data.scene, parsed.data.title);
141
+ return c.json({ ok: true });
142
+ });
143
+ }
144
+ app.post("/api/spec", async (c) => {
145
+ const parsed = SpecRequest.safeParse(await c.req.json().catch(() => null));
146
+ if (!parsed.success) {
147
+ return c.json({ error: "invalid request", detail: parsed.error.issues }, 400);
148
+ }
149
+ const { title, graph } = parsed.data;
150
+ if (graph.nodes.length === 0) return c.json({ error: "diagram has no nodes" }, 400);
151
+ const changeNameHint = workspace ? `
152
+
153
+ Use exactly "${workspace.changeName}" as the changeName.` : "";
154
+ const prompt = `Architecture diagram: "${title ?? "Untitled architecture"}"
155
+
156
+ ${renderGraph(graph)}
157
+
158
+ Produce the OpenSpec change proposal for this architecture as structured output.` + changeNameHint + (workspace ? renderBaseline(workspace) : "");
159
+ const msg = await anthropic.messages.parse({
160
+ model: MODEL,
161
+ max_tokens: 16e3,
162
+ // non-streaming stays under the SDK HTTP timeout
163
+ system: SYSTEM,
164
+ messages: [{ role: "user", content: prompt }],
165
+ output_config: { format: zodOutputFormat(SpecBundle) }
166
+ // No temperature/top_p or thinking config — both 400 on modern models.
167
+ });
168
+ if (msg.stop_reason === "refusal") {
169
+ return c.json({ error: "refusal", detail: msg.stop_details }, 422);
170
+ }
171
+ if (!msg.parsed_output) return c.json({ error: "model returned no structured output" }, 502);
172
+ if (workspace) {
173
+ const bundle = { ...msg.parsed_output, changeName: workspace.changeName };
174
+ workspace.writeBundle(bundle);
175
+ return c.json(bundle);
176
+ }
177
+ return c.json(msg.parsed_output);
178
+ });
179
+ return app;
180
+ }
181
+
182
+ // server/workspace.ts
183
+ import { createHash } from "node:crypto";
184
+ import {
185
+ existsSync,
186
+ mkdirSync,
187
+ readFileSync,
188
+ readdirSync,
189
+ renameSync,
190
+ writeFileSync
191
+ } from "node:fs";
192
+ import { basename, dirname, join, resolve } from "node:path";
193
+ var DIAGRAM_FILE = "diagram.excalidraw";
194
+ var SIDECAR_FILE = "specsketch.json";
195
+ var sha256 = (s) => createHash("sha256").update(s).digest("hex");
196
+ var ChangeWorkspace = class {
197
+ dir;
198
+ changeName;
199
+ constructor(dir) {
200
+ this.dir = resolve(dir);
201
+ this.changeName = basename(this.dir);
202
+ mkdirSync(this.dir, { recursive: true });
203
+ }
204
+ writeAtomic(relPath, content) {
205
+ const target = join(this.dir, relPath);
206
+ mkdirSync(dirname(target), { recursive: true });
207
+ const tmp = `${target}.tmp`;
208
+ writeFileSync(tmp, content, "utf8");
209
+ renameSync(tmp, target);
210
+ }
211
+ readIfExists(relPath) {
212
+ const target = join(this.dir, relPath);
213
+ return existsSync(target) ? readFileSync(target, "utf8") : void 0;
214
+ }
215
+ // ── Scene ────────────────────────────────────────────────────────────────
216
+ loadScene() {
217
+ const raw = this.readIfExists(DIAGRAM_FILE);
218
+ if (!raw) return null;
219
+ try {
220
+ const parsed = JSON.parse(raw);
221
+ return {
222
+ elements: Array.isArray(parsed.elements) ? parsed.elements : [],
223
+ appState: parsed.appState ?? void 0,
224
+ files: parsed.files ?? void 0
225
+ };
226
+ } catch {
227
+ return null;
228
+ }
229
+ }
230
+ saveScene(scene, title) {
231
+ this.writeAtomic(
232
+ DIAGRAM_FILE,
233
+ JSON.stringify(
234
+ {
235
+ type: "excalidraw",
236
+ version: 2,
237
+ source: "coopcli-specsketch",
238
+ elements: scene.elements,
239
+ appState: scene.appState ?? {},
240
+ files: scene.files ?? {}
241
+ },
242
+ null,
243
+ 2
244
+ )
245
+ );
246
+ this.updateSidecar((s) => ({ ...s, ...title !== void 0 ? { title } : {} }));
247
+ }
248
+ // ── Sidecar ──────────────────────────────────────────────────────────────
249
+ readSidecar() {
250
+ const raw = this.readIfExists(SIDECAR_FILE);
251
+ if (!raw) return {};
252
+ try {
253
+ return JSON.parse(raw);
254
+ } catch {
255
+ return {};
256
+ }
257
+ }
258
+ updateSidecar(update) {
259
+ const now = (/* @__PURE__ */ new Date()).toISOString();
260
+ const current = this.readSidecar();
261
+ const next = update(current);
262
+ next.createdAt ??= now;
263
+ next.updatedAt = now;
264
+ this.writeAtomic(SIDECAR_FILE, JSON.stringify(next, null, 2));
265
+ }
266
+ // ── Artifacts ────────────────────────────────────────────────────────────
267
+ /** Current artifact files, however they were authored. */
268
+ readArtifacts() {
269
+ const specs = [];
270
+ const specsDir = join(this.dir, "specs");
271
+ if (existsSync(specsDir)) {
272
+ for (const entry of readdirSync(specsDir, { withFileTypes: true })) {
273
+ if (!entry.isDirectory()) continue;
274
+ const spec = this.readIfExists(join("specs", entry.name, "spec.md"));
275
+ if (spec !== void 0) specs.push({ capability: entry.name, spec });
276
+ }
277
+ }
278
+ return {
279
+ proposal: this.readIfExists("proposal.md"),
280
+ design: this.readIfExists("design.md"),
281
+ tasks: this.readIfExists("tasks.md"),
282
+ specs
283
+ };
284
+ }
285
+ /** Reconstruct a SpecBundle view from the files on disk, or null if none. */
286
+ toBundle() {
287
+ const a = this.readArtifacts();
288
+ if (!a.proposal && !a.design && !a.tasks && a.specs.length === 0) return null;
289
+ return {
290
+ changeName: this.changeName,
291
+ summary: this.readSidecar().summary ?? "",
292
+ proposal: a.proposal ?? "",
293
+ design: a.design ?? "",
294
+ tasks: a.tasks ?? "",
295
+ specs: a.specs
296
+ };
297
+ }
298
+ /**
299
+ * Materialize a generated bundle in OpenSpec layout, writing only files
300
+ * whose content actually changed. Returns the relative paths written.
301
+ */
302
+ writeBundle(bundle) {
303
+ const files = {
304
+ "proposal.md": bundle.proposal,
305
+ "design.md": bundle.design,
306
+ "tasks.md": bundle.tasks
307
+ };
308
+ for (const s of bundle.specs) files[join("specs", s.capability, "spec.md")] = s.spec;
309
+ const written = [];
310
+ const manifest = {};
311
+ for (const [relPath, content] of Object.entries(files)) {
312
+ manifest[relPath] = sha256(content);
313
+ if (this.readIfExists(relPath) === content) continue;
314
+ this.writeAtomic(relPath, content);
315
+ written.push(relPath);
316
+ }
317
+ this.updateSidecar((s) => ({ ...s, summary: bundle.summary, generated: manifest }));
318
+ return written;
319
+ }
320
+ };
321
+
322
+ // server/cli.ts
323
+ var USAGE = `Usage: specsketch <path-to-openspec-change-dir> [--port <n>]
324
+
325
+ specsketch ./openspec/changes/new-feature-change
326
+
327
+ The directory is created if it doesn't exist. Diagrams autosave to
328
+ diagram.excalidraw inside it; Generate Spec writes proposal.md, design.md,
329
+ tasks.md and specs/<capability>/spec.md alongside.`;
330
+ var UsageError = class extends Error {
331
+ };
332
+ function parseCliArgs(argv) {
333
+ let parsed;
334
+ try {
335
+ parsed = parseArgs({
336
+ args: argv,
337
+ options: { port: { type: "string" } },
338
+ allowPositionals: true
339
+ });
340
+ } catch (err) {
341
+ throw new UsageError(err instanceof Error ? err.message : String(err));
342
+ }
343
+ const [dir, ...rest] = parsed.positionals;
344
+ if (!dir || rest.length > 0) throw new UsageError("expected exactly one change directory");
345
+ const port = parsed.values.port === void 0 ? 8787 : Number(parsed.values.port);
346
+ if (!Number.isInteger(port) || port < 1 || port > 65535) {
347
+ throw new UsageError(`invalid --port: ${String(parsed.values.port)}`);
348
+ }
349
+ return { dir, port };
350
+ }
351
+ var MIME = {
352
+ ".html": "text/html; charset=utf-8",
353
+ ".js": "text/javascript; charset=utf-8",
354
+ ".css": "text/css; charset=utf-8",
355
+ ".svg": "image/svg+xml",
356
+ ".png": "image/png",
357
+ ".ico": "image/x-icon",
358
+ ".json": "application/json",
359
+ ".map": "application/json",
360
+ ".woff2": "font/woff2",
361
+ ".woff": "font/woff"
362
+ };
363
+ function resolveClientDir(moduleUrl) {
364
+ const here = dirname2(fileURLToPath(moduleUrl));
365
+ const candidates = [
366
+ join2(here, "..", "client"),
367
+ // packed: dist/cli -> dist/client
368
+ join2(here, "..", "dist", "client")
369
+ // repo: server/ -> dist/client
370
+ ];
371
+ for (const dir of candidates) {
372
+ if (existsSync2(join2(dir, "index.html"))) return dir;
373
+ }
374
+ return null;
375
+ }
376
+ function staticResponse(clientDir, pathname) {
377
+ const rel = normalize(decodeURIComponent(pathname)).replace(/^\/+/, "");
378
+ const target = resolve2(clientDir, rel === "" ? "index.html" : rel);
379
+ if (!target.startsWith(resolve2(clientDir))) return null;
380
+ const file = existsSync2(target) && extname(target) ? target : join2(clientDir, "index.html");
381
+ if (!existsSync2(file)) return null;
382
+ return new Response(readFileSync2(file), {
383
+ headers: { "Content-Type": MIME[extname(file)] ?? "application/octet-stream" }
384
+ });
385
+ }
386
+ function main(argv) {
387
+ let args;
388
+ try {
389
+ args = parseCliArgs(argv);
390
+ } catch (err) {
391
+ console.error(err instanceof UsageError ? `specsketch: ${err.message}
392
+
393
+ ${USAGE}` : err);
394
+ process.exit(1);
395
+ }
396
+ const clientDir = resolveClientDir(import.meta.url);
397
+ if (!clientDir) {
398
+ console.error("specsketch: built UI assets not found (dist/client missing).");
399
+ process.exit(1);
400
+ }
401
+ const workspace = new ChangeWorkspace(args.dir);
402
+ const app = createApp(new Anthropic(), workspace);
403
+ app.get("*", (c) => {
404
+ const res = staticResponse(clientDir, new URL(c.req.url).pathname);
405
+ return res ?? c.notFound();
406
+ });
407
+ serve({ fetch: app.fetch, port: args.port, hostname: "127.0.0.1" }, () => {
408
+ console.log(`coopcli specsketch`);
409
+ console.log(` workspace: ${workspace.dir}`);
410
+ console.log(` open: http://127.0.0.1:${args.port}`);
411
+ });
412
+ }
413
+
414
+ // server/cli-entry.ts
415
+ main(process.argv.slice(2));
@@ -0,0 +1 @@
1
+ import{n as e}from"./chunk-Y2CYZVJY-DsF7k-Jl.js";import{m as t}from"./src-DpN7Pt3R.js";import"./chunk-WYO6CB5R-2iEnPkYI.js";import"./chunk-VAUOI2AC-DCK8rog6.js";import{n,r,t as i}from"./chunk-MOJQB5TN-D8mFPGTn.js";import{t as a}from"./chunk-JWPE2WC7-DVXcaiue.js";import{E as o,t as s}from"./mermaid-parser.core-BqfnOrIO.js";var c=o().RailroadAbnf.parser.LangiumParser,l=e(e=>{let t=e.alternatives.map(u);return t.length===1?t[0]:{type:`choice`,alternatives:t}},`transformAlternation`),u=e(e=>{let t=e.elements.map(f);return t.length===1?t[0]:{type:`sequence`,elements:t}},`transformConcatenation`),d=e(e=>{if(e.includes(`*`)){let[t,n]=e.split(`*`);return{min:t?parseInt(t,10):0,max:n?parseInt(n,10):1/0}}let t=parseInt(e,10);return{min:t,max:t}},`parseRepeat`),f=e(e=>{let t=p(e.primary);if(!e.repeat)return t;let{min:n,max:r}=d(e.repeat);return n===0&&r===1?{type:`optional`,element:t}:{type:`repetition`,element:t,min:n,max:r}},`transformElement`),p=e(e=>{switch(e.$type){case`AbnfStringLiteral`:return{type:`terminal`,value:e.value};case`AbnfNumVal`:return{type:`terminal`,value:e.value};case`AbnfRuleName`:return{type:`nonterminal`,name:e.name};case`AbnfGroup`:return l(e.element);case`AbnfOptionalGroup`:return{type:`optional`,element:l(e.element)};default:throw Error(`Unsupported ABNF primary node: ${e.$type}`)}},`transformPrimary`),m=e(e=>({name:e.name,definition:l(e.definition)}),`transformRule`),h=e(e=>{a(e,i),e.title&&i.setTitle(e.title),e.rules.map(e=>i.addRule(m(e)))},`populateDb`),g={parser:{parse:e(e=>{i.clear(),t.debug(`[ABNF Parser] Starting Langium parse`);let n=c.parse(e);if(n.lexerErrors.length>0||n.parserErrors.length>0)throw new s(n);let r=n.value;t.debug(`[ABNF Parser] Parsed rules:`,r.rules.length),h(r),t.debug(`[ABNF Parser] Parse complete`)},`parse`),parser:{yy:i}},db:i,renderer:r,styles:n};export{g as diagram};
@@ -0,0 +1,10 @@
1
+ import"./index-J0gDT2pS.js";var e={paste:`لصق`,pasteAsPlaintext:`اللصق كنص عادي`,pasteCharts:`لصق الرسوم البيانية`,selectAll:`تحديد الكل`,multiSelect:`إضافة عنصر للتحديد`,moveCanvas:`نقل لوح الرسم`,cut:`قص`,copy:`نسخ`,copyAsPng:`نسخ إلى الحافظة بصيغة PNG`,copyAsSvg:`نسخ إلى الحافظة بصيغة SVG`,copyText:`نسخ إلى الحافظة كنص`,copySource:``,convertToCode:``,bringForward:`جلب للأمام`,sendToBack:`أرسل للخلف`,bringToFront:`أحضر للأمام`,sendBackward:`أرسل للخلف`,delete:`حذف`,copyStyles:`نسخ الأنماط`,pasteStyles:`لصق الأنماط`,stroke:`الخط`,background:`الخلفية`,fill:`التعبئة`,strokeWidth:`سُمك الخط`,strokeStyle:`نمط الخط`,strokeStyle_solid:`متصل`,strokeStyle_dashed:`متقطع`,strokeStyle_dotted:`منقط`,sloppiness:`الإمالة`,opacity:`الشفافية`,textAlign:`محاذاة النص`,edges:`الحواف`,sharp:`حادة`,round:`دائرية`,arrowheads:`رؤوس الأسهم`,arrowhead_none:`لا شيء`,arrowhead_arrow:`سهم`,arrowhead_bar:`شريط`,arrowhead_circle:``,arrowhead_circle_outline:``,arrowhead_triangle:`مثلث`,arrowhead_triangle_outline:``,arrowhead_diamond:``,arrowhead_diamond_outline:``,fontSize:`حجم الخط`,fontFamily:`نوع الخط`,addWatermark:`إضافة "مصنوعة بواسطة Excalidraw"`,handDrawn:`رسم باليد`,normal:`عادي`,code:`رمز`,small:`صغير`,medium:`متوسط`,large:`كبير`,veryLarge:`كبير جدا`,solid:`كامل`,hachure:`خطوط`,zigzag:`متعرج`,crossHatch:`خطوط متقطعة`,thin:`نحيف`,bold:`داكن`,left:`الـيسار`,center:`وسط`,right:`يمين`,extraBold:`عريض`,architect:`معماري`,artist:`رسام`,cartoonist:`كرتوني`,fileTitle:`إسم الملف`,colorPicker:`منتقي اللون`,canvasColors:`تستخدم على القماش`,canvasBackground:`خلفية اللوحة`,drawingCanvas:`لوحة الرسم`,layers:`الطبقات`,actions:`الإجراءات`,language:`اللغة`,liveCollaboration:`التعاون المباشر...`,duplicateSelection:`تكرار`,untitled:`غير معنون`,name:`الاسم`,yourName:`اسمك`,madeWithExcalidraw:`مصنوعة بواسطة Excalidraw`,group:`تحديد مجموعة`,ungroup:`إلغاء تحديد مجموعة`,collaborators:`المتعاونون`,showGrid:`إظهار الشبكة`,addToLibrary:`أضف إلى المكتبة`,removeFromLibrary:`حذف من المكتبة`,libraryLoadingMessage:`جارٍ تحميل المكتبة…`,libraries:`تصفح المكتبات`,loadingScene:`جاري تحميل المشهد…`,align:`محاذاة`,alignTop:`محاذاة إلى اﻷعلى`,alignBottom:`محاذاة إلى اﻷسفل`,alignLeft:`محاذاة إلى اليسار`,alignRight:`محاذاة إلى اليمين`,centerVertically:`توسيط عمودي`,centerHorizontally:`توسيط أفقي`,distributeHorizontally:`التوزيع الأفقي`,distributeVertically:`التوزيع عمودياً`,flipHorizontal:`قلب عامودي`,flipVertical:`قلب أفقي`,viewMode:`نمط العرض`,share:`مشاركة`,showStroke:`إظهار منتقي لون الخط`,showBackground:`إظهار منتقي لون الخلفية`,toggleTheme:`غير النمط`,personalLib:`المكتبة الشخصية`,excalidrawLib:`مكتبتنا`,decreaseFontSize:`تصغير حجم الخط`,increaseFontSize:`تكبير حجم الخط`,unbindText:`فك ربط النص`,bindText:`ربط النص بالحاوية`,createContainerFromText:`نص مغلف في حاوية`,link:{edit:`تعديل الرابط`,editEmbed:`تحرير الرابط وإدراجه`,create:`إنشاء رابط`,createEmbed:`إنشاء رابط و إدراجه`,label:`رابط`,labelEmbed:`رابط و إدراج`,empty:`لم يتم تعيين رابط`},lineEditor:{edit:`تحرير السطر`,exit:`الخروج من المُحرر`},elementLock:{lock:`قفل`,unlock:`فتح`,lockAll:`قفل الكل`,unlockAll:`فتح الكل`},statusPublished:`نُشر`,sidebarLock:`إبقاء الشريط الجانبي مفتوح`,selectAllElementsInFrame:`تحديد جميع العناصر في الإطار`,removeAllElementsFromFrame:`إزالة جميع العناصر من الإطار`,eyeDropper:`اختيار اللون من القماش`,textToDiagram:``,prompt:``},t={noItems:`لا توجد عناصر أضيفت بعد...`,hint_emptyLibrary:`حدد عنصر على القماش لإضافته هنا، أو تثبيت مكتبة من المستودع العام أدناه.`,hint_emptyPrivateLibrary:`حدد عنصر على القماش لإضافته هنا.`},n={clearReset:`إعادة تعيين اللوحة`,exportJSON:`صدر الملف`,exportImage:`تصدير الصورة...`,export:`حفظ إلى...`,copyToClipboard:`نسخ إلى الحافظة`,save:`احفظ للملف الحالي`,saveAs:`حفظ كـ`,load:`فتح`,getShareableLink:`احصل على رابط المشاركة`,close:`غلق`,selectLanguage:`اختر اللغة`,scrollBackToContent:`الرجوع إلى المحتوى`,zoomIn:`تكبير`,zoomOut:`تصغير`,resetZoom:`إعادة تعيين الشاشة`,menu:`القائمة`,done:`تم`,edit:`تعديل`,undo:`تراجع`,redo:`إعادة تنفيذ`,resetLibrary:`إعادة ضبط المكتبة`,createNewRoom:`إنشاء غرفة جديدة`,fullScreen:`شاشة كاملة`,darkMode:`الوضع المظلم`,lightMode:`الوضع المضيء`,zenMode:`وضع التأمل`,objectsSnapMode:`التقط إلى العناصر`,exitZenMode:`إلغاء الوضع الليلى`,cancel:`إلغاء`,clear:`مسح`,remove:`إزالة`,embed:`تبديل الإدراج`,publishLibrary:`انشر`,submit:`أرسل`,confirm:`تأكيد`,embeddableInteractionButton:`اضغط للتفاعل`},r={clearReset:`هذا سيُزيل كامل اللوحة. هل أنت متأكد؟`,couldNotCreateShareableLink:`تعذر إنشاء رابطة المشاركة.`,couldNotCreateShareableLinkTooBig:`تعذر إنشاء رابط قابل للمشاركة: المشهد كبير جدًا`,couldNotLoadInvalidFile:`تعذر التحميل، الملف غير صالح`,importBackendFailed:`فشل الاستيراد من الخادوم.`,cannotExportEmptyCanvas:`لا يمكن تصدير لوحة فارغة.`,couldNotCopyToClipboard:`تعذر النسخ إلى الحافظة.`,decryptFailed:`تعذر فك تشفير البيانات.`,uploadedSecurly:`تم تأمين التحميل بتشفير النهاية إلى النهاية، مما يعني أن خادوم Excalidraw والأطراف الثالثة لا يمكنها قراءة المحتوى.`,loadSceneOverridePrompt:`تحميل الرسم الخارجي سيحل محل المحتوى الموجود لديك. هل ترغب في المتابعة؟`,collabStopOverridePrompt:`إيقاف الجلسة سيؤدي إلى الكتابة فوق رسومك السابقة المخزنة داخليا. هل أنت متأكد؟
2
+
3
+ (إذا كنت ترغب في الاحتفاظ برسمك المخزن داخليا، ببساطة أغلق علامة تبويب المتصفح بدلاً من ذلك.)`,errorAddingToLibrary:`تعذر إضافة العنصر للمكتبة`,errorRemovingFromLibrary:`تعذر إزالة العنصر من المكتبة`,confirmAddLibrary:`هذا سيضيف {{numShapes}} شكل إلى مكتبتك. هل أنت متأكد؟`,imageDoesNotContainScene:`يبدو أن هذه الصورة لا تحتوي على أي بيانات مشهد. هل قمت بتمكين تضمين المشهد أثناء التصدير؟`,cannotRestoreFromImage:`تعذر استعادة المشهد من ملف الصورة`,invalidSceneUrl:`تعذر استيراد المشهد من عنوان URL المتوفر. إما أنها مشوهة، أو لا تحتوي على بيانات Excalidraw JSON صالحة.`,resetLibrary:`هذا سوف يمسح مكتبتك. هل أنت متأكد؟`,removeItemsFromsLibrary:`حذف {{count}} عنصر (عناصر) من المكتبة؟`,invalidEncryptionKey:`مفتاح التشفير يجب أن يكون من 22 حرفاً. التعاون المباشر معطل.`,collabOfflineWarning:`لا يوجد اتصال بالانترنت.
4
+ لن يتم حفظ التغييرات التي قمت بها!`},i={unsupportedFileType:`نوع الملف غير مدعوم.`,imageInsertError:`تعذر إدراج الصورة. حاول مرة أخرى لاحقاً...`,fileTooBig:`الملف كبير جداً. الحد الأقصى المسموح به للحجم هو {{maxSize}}.`,svgImageInsertError:`تعذر إدراج صورة SVG. يبدو أن ترميز SVG غير صحيح.`,failedToFetchImage:``,invalidSVGString:`SVG غير صالح.`,cannotResolveCollabServer:`تعذر الاتصال بخادم التعاون. الرجاء إعادة تحميل الصفحة والمحاولة مرة أخرى.`,importLibraryError:`تعذر تحميل المكتبة`,collabSaveFailed:`تعذر الحفظ في قاعدة البيانات. إذا استمرت المشاكل، يفضل أن تحفظ ملفك محليا كي لا تفقد عملك.`,collabSaveFailed_sizeExceeded:`تعذر الحفظ في قاعدة البيانات، يبدو أن القماش كبير للغاية، يفضّل حفظ الملف محليا كي لا تفقد عملك.`,imageToolNotSupported:``,brave_measure_text_error:{line1:`يبدو أنك تستخدم متصفح Brave مع إعداد <bold>حظر صارم لتتبع البصمة</bold>.`,line2:`قد يؤدي هذا إلى كسر <bold>عناصر النص</bold> في الرسومات الخاصة بك.`,line3:`من المستحسن إلغاء تفعيل هذا الإعداد. يمكنك اتباع <link>هذه الخطوات</link> لفعل ذلك.`,line4:`إذا لم يصلح تعطيل هذا الإعداد طريقة عرض النصوص، الرجاء كتابة <issueLink>بلاغ</issueLink> على حسابنا في GitHub، أو راسلنا على <discordLink>Discord</discordLink>`},libraryElementTypeError:{embeddable:`لا يمكن إضافة العناصر القابلة للتضمين في المكتبة.`,iframe:``,image:`سوف يتم دعم إضافة صور إلى المكتبة قريباً!`},asyncPasteFailedOnRead:``,asyncPasteFailedOnParse:``,copyToSystemClipboardFailed:``},a={selection:`تحديد`,image:`إدراج صورة`,rectangle:`مستطيل`,diamond:`مضلع`,ellipse:`دائرة`,arrow:`سهم`,line:`خط`,freedraw:`رسم`,text:`نص`,library:`مكتبة`,lock:`الحفاظ على أداة التحديد نشطة بعد الرسم`,penMode:`وضع القلم - امنع اللمس`,link:`إضافة/تحديث الرابط للشكل المحدد`,eraser:`ممحاة`,frame:`أداة الإطار`,magicframe:``,embeddable:`تضمين ويب`,laser:`مؤشر ليزر`,hand:`يد (أداة الإزاحة)`,extraTools:`المزيد من أﻷدوات`,mermaidToExcalidraw:``,magicSettings:``},o={canvasActions:`إجراءات اللوحة`,selectedShapeActions:`إجراءات الشكل المحدد`,shapes:`الأشكال`},s={canvasPanning:`لتحريك القماش، اضغط على عجلة الفأرة أو مفتاح المسافة أثناء السحب، أو استخدم أداة اليد`,linearElement:`انقر لبدء نقاط متعددة، اسحب لخط واحد`,freeDraw:`انقر واسحب، افرج عند الانتهاء`,text:`نصيحة: يمكنك أيضًا إضافة نص بالنقر المزدوج في أي مكان بأداة الاختيار`,embeddable:`اضغط مع السحب لإنشاء موقع ويب مضمّن`,text_selected:`انقر نقراً مزدوجاً أو اضغط ادخال لتعديل النص`,text_editing:`اضغط على Esc أو (Ctrl أو Cmd) + Enter لإنهاء التعديل`,linearElementMulti:`انقر فوق النقطة الأخيرة أو اضغط على Esc أو Enter للإنهاء`,lockAngle:`يمكنك تقييد الزاوية بالضغط على SHIFT`,resize:`يمكنك تقييد النسب بالضغط على SHIFT أثناء تغيير الحجم،
5
+ اضغط على ALT لتغيير الحجم من المركز`,resizeImage:`يمكنك تغيير الحجم بحرية بالضغط بأستمرار على SHIFT،
6
+ اضغط بأستمرار على ALT أيضا لتغيير الحجم من المركز`,rotate:`يمكنك تقييد الزوايا من خلال الضغط على SHIFT أثناء الدوران`,lineEditor_info:`اضغط على مفتاح (Ctrl أو Cmd) و انقر بشكل مزدوج، أو اضغط على مفتاحي (Ctrl أو Cmd) و (Enter) لتعديل النقاط`,lineEditor_pointSelected:`اضغط على حذف لإزالة النقطة (النِّقَاط)، Ctrl/Cmd+D للتكرار، أو اسحب للانتقال`,lineEditor_nothingSelected:`اختر نقطة لتعديلها (اضغط على SHIFT لتحديد عدة نِقَاط),
7
+ أو اضغط على ALT و انقر بالفأرة لإضافة نِقَاط جديدة`,placeImage:`انقر لوضع الصورة، أو انقر واسحب لتعيين حجمها يدوياً`,publishLibrary:`نشر مكتبتك`,bindTextToElement:`اضغط على إدخال لإضافة نص`,deepBoxSelect:`اضغط على Ctrl\\Cmd للاختيار العميق، ولمنع السحب`,eraserRevert:`اضغط على Alt لاستعادة العناصر المعلَّمة للحذف`,firefox_clipboard_write:`يمكن على الأرجح تمكين هذه الميزة عن طريق تعيين علم "dom.events.asyncClipboard.clipboardItem" إلى "true". لتغيير أعلام المتصفح في Firefox، قم بزيارة صفحة "about:config".`,disableSnapping:`اضغط على Ctrl أو Cmd لتعطيل الالتقاط`},c={cannotShowPreview:`تعذر عرض المعاينة`,canvasTooBig:`قد تكون اللوحة كبيرة جداً.`,canvasTooBigTip:`نصيحة: حاول تحريك العناصر البعيدة بشكل أقرب قليلاً.`},l={headingMain:`حدث خطأ. حاول <button>تحديث الصفحة</button>.`,clearCanvasMessage:`إذا لم تعمل إعادة التحميل، حاول مرة أخرى `,clearCanvasCaveat:` هذا سيؤدي إلى فقدان العمل `,trackedToSentry:`تم تتبع الخطأ في المعرف {{eventId}} على نظامنا.`,openIssueMessage:`حرصنا على عدم إضافة معلومات المشهد في بلاغ الخطأ. في حال كون مشهدك لا يحمل أي معلومات خاصة نرجو المتابعة على <button>نظام تتبع الأخطاء</button>. نرجو إضافة المعلومات أدناه بنسخها ولصقها في محتوى البلاغ على GitHub.`,sceneContent:`محتوى المشهد:`},u={desc_intro:`يمكنك دعوة الآخرين لمشاركتك نفس الجلسة التي تعمل عليها.`,desc_privacy:`لا تقلق، الجلسة تستخدم التشفير من النهاية إلى النهاية، لذلك فإن أي شيء ترسمه سيبقى خاصاً. لن يتمكن حتى الخادوم الخاص بنا من رؤية ما توصلت إليه.`,button_startSession:`بدء الجلسة`,button_stopSession:`إيقاف الجلسة`,desc_inProgressIntro:`تجري الآن المشاركة الحية.`,desc_shareLink:`شارك هذا الرابط مع أي شخص تريده أن يشاركك الجلسة:`,desc_exitSession:`إيقاف الجلسة سيؤدي إلى قطع الاتصال الخاص بك من الغرفة، ولكن ستتمكن من مواصلة العمل مع المشهد، محليا. لاحظ أن هذا لن يؤثر على الأشخاص الآخرين، و سيظلون قادرين على التعاون في إصدارهم.`,shareTitle:`الانضمام إلى جلسة تعاون حية على Excalidraw`},d={title:`خطأ`},f={disk_title:`حفظ الملف للجهاز`,disk_details:`تصدير بيانات المشهد إلى ملف يمكنك الاستيراد منه لاحقاً.`,disk_button:`إحفظ لملف`,link_title:`رابط قابل للمشاركة`,link_details:`صدر الملف للمشاهدة فقط.`,link_button:`التصدير كرابط`,excalidrawplus_description:`حفظ المشهد إلى مساحة العمل +Excalidraw الخاصة بك.`,excalidrawplus_button:`تصدير`,excalidrawplus_exportError:`تعذر التصدير إلى +Excalidraw في الوقت الحالي...`},p={blog:`اقرأ مدونتنا`,click:`انقر`,deepSelect:`تحديد عميق`,deepBoxSelect:`تحديد عميق داخل المربع، ومنع السحب`,curvedArrow:`سهم مائل`,curvedLine:`خط مائل`,documentation:`دليل الاستخدام`,doubleClick:`انقر مرتين`,drag:`اسحب`,editor:`المحرر`,editLineArrowPoints:`تحرير سطر/نقاط سهم`,editText:`تعديل النص / إضافة تسمية`,github:`عثرت على مشكلة؟ إرسال`,howto:`اتبع التعليمات`,or:`أو`,preventBinding:`منع ارتبط السهم`,tools:`الأدوات`,shortcuts:`اختصارات لوحة المفاتيح`,textFinish:`إنهاء التعديل (محرر النص)`,textNewLine:`أضف سطر جديد (محرر نص)`,title:`المساعدة`,view:`عرض`,zoomToFit:`تكبير للملائمة`,zoomToSelection:`تكبير للعنصر المحدد`,toggleElementLock:`إغلاق/فتح المحدد`,movePageUpDown:`نقل الصفحة أعلى/أسفل`,movePageLeftRight:`نقل الصفحة يسار/يمين`},m={title:`مسح اللوحة`},h={title:`نشر المكتبة`,itemName:`إسم العنصر`,authorName:`إسم المؤلف`,githubUsername:`اسم المستخدم في جيت هب`,twitterUsername:`اسم المستخدم في تويتر`,libraryName:`اسم المكتبة`,libraryDesc:`وصف المكتبة`,website:`الموقع`,placeholder:{authorName:`اسمك أو اسم المستخدم`,libraryName:`اسم مكتبتك`,libraryDesc:`وصف مكتبتك لمساعدة الناس على فهم استخدامها`,githubHandle:`معالج GitHub (اختياري)، حتى تتمكن من تحرير المكتبة عند إرسالها للمراجعة`,twitterHandle:`اسم مستخدم تويتر (اختياري)، حتى نعرف من الذي سيتم الإشارة إليه عند الترويج عبر تويتر`,website:`رابط إلى موقعك الشخصي أو في مكان آخر (اختياري)`},errors:{required:`مطلوب`,website:`أدخل عنوان URL صالح`},noteDescription:`تقديم مكتبتك لتضمينها في مستودع المكتبة العامة <link></link> لأشخاص آخرين لاستخدامها في رسومهم.`,noteGuidelines:`تحتاج المكتبة إلى الموافقة أولا. يرجى قراءة <link>المعايير</link> قبل تقديمها. سوف تحتاج إلى حساب GitHub للتواصل وإجراء التغييرات عند الطلب، ولكن ليس مطلوبا بشكل صارم.`,noteLicense:`تقديمك يعني موافقتك على نشر المكتبة المقدمة تحت <link>MIT ترخيص</link>، ما يعني أن لأي أحد الحق في استخدامها دون قيود.`,noteItems:`يجب أن يكون لكل عنصر مكتبة اسمه الخاص حتى يكون قابلاً للتصفية. سيتم تضمين عناصر المكتبة التالية:`,atleastOneLibItem:`يرجى تحديد عنصر مكتبة واحد على الأقل للبدء`,republishWarning:`ملاحظة: بعض العناصر المحددة معينة على أنه نشرها أو تقديمها من قبل. يجب عليك فقط إعادة إرسال العناصر عند تحديث مكتبة موجودة أو إرسالها.`},g={title:`تم إرسال المكتبة`,content:`شكرا لك {{authorName}}. لقد تم إرسال مكتبتك للمراجعة. يمكنك تتبع الحالة`},_={resetLibrary:`إعادة ضبط المكتبة`,removeItemsFromLib:`إزالة العناصر المحددة من المكتبة`},v={header:`تصدير الصورة`,label:{withBackground:`الخلفية`,onlySelected:`المحدد فقط`,darkMode:`الوضع الداكن`,embedScene:`تضمين المشهد`,scale:`الحجم`,padding:`الهوامش`},tooltip:{embedScene:`سيتم حفظ بيانات المشهد في ملف PNG/SVG المصدّر بحيث يمكن استعادة المشهد منه.
8
+ سيزيد حجم الملف المصدر.`},title:{exportToPng:`تصدير بصيغة PNG`,exportToSvg:`تصدير بصيغة SVG`,copyPngToClipboard:`نسخ الـ PNG إلى الحافظة`},button:{exportToPng:`PNG`,exportToSvg:`SVG`,copyPngToClipboard:`نسخ إلى الحافظة`}},y={tooltip:`رسوماتك مشفرة من النهاية إلى النهاية حتى أن خوادم Excalidraw لن تراها أبدا.`,link:`مشاركة المدونة في التشفير من النهاية إلى النهاية في Excalidraw`},b={angle:`الزاوية`,element:`عنصر`,elements:`العناصر`,height:`الارتفاع`,scene:`المشهد`,selected:`المحدد`,storage:`التخزين`,title:`إحصائيات للمهووسين`,total:`المجموع`,version:`الإصدار`,versionCopy:`انقر للنسخ`,versionNotAvailable:`الإصدار غير متوفر`,width:`العرض`},x={addedToLibrary:`تمت الاضافة الى المكتبة!`,copyStyles:`نسخت الانماط.`,copyToClipboard:`نسخ إلى الحافظة.`,copyToClipboardAsPng:`تم نسخ {{exportSelection}} إلى الحافظة بصيغة PNG
9
+ ({{exportColorScheme}})`,fileSaved:`تم حفظ الملف.`,fileSavedToFilename:`حفظ باسم {filename}`,canvas:`لوحة الرسم`,selection:`العنصر المحدد`,pasteAsSingleElement:`استخدم {{shortcut}} للصق كعنصر واحد،
10
+ أو لصق في محرر نص موجود`,unableToEmbed:`تضمين هذا الرابط غير مسموح حاليًا. افتح بلاغاً على GitHub لطلب عنوان Url القائمة البيضاء`,unrecognizedLinkFormat:`الرابط الذي ضمنته لا يتطابق مع التنسيق المتوقع. الرجاء محاولة لصق النص 'المضمن' المُزوَد من موقع المصدر`},S={transparent:`شفاف`,black:`أسود`,white:`أبيض`,red:`أحمر`,pink:`وردي`,grape:`عنبي`,violet:`بنفسجي`,gray:`رمادي`,blue:`أزرق`,cyan:`سماوي`,teal:`أزرق مخضر`,green:`أخضر`,yellow:`أصفر`,orange:`برتقالي`,bronze:`برونزي`},C={app:{center_heading:`جميع بياناتك محفوظة محليا في المتصفح الخاص بك.`,center_heading_plus:`هل تريد الذهاب إلى Excalidraw+ بدلاً من ذلك؟`,menuHint:`التصدير والتفضيلات واللغات ...`},defaults:{menuHint:`التصدير والتفضيلات وغيرها...`,center_heading:`الرسم البياني التصويري. بشكل مبسط.`,toolbarHint:`اختر أداة و ابدأ الرسم!`,helpHint:`الاختصارات و المساعدة`}},w={mostUsedCustomColors:`الألوان المخصصة الأكثر استخداما`,colors:`الألوان`,shades:`الدرجات`,hexCode:`رمز Hex`,noShades:`لا تتوفر درجات لهذا اللون`},T={action:{exportToImage:{title:`تصدير كصورة`,button:`تصدير كصورة`,description:`تصدير بيانات المشهد إلى ملف يمكنك الاستيراد منه لاحقاً.`},saveToDisk:{title:`حفظ الملف للجهاز`,button:`حفظ الملف للجهاز`,description:`تصدير بيانات المشهد إلى ملف يمكنك الاستيراد منه لاحقاً.`},excalidrawPlus:{title:`Excalidraw+`,button:`تصدير إلى Excalidraw+`,description:`حفظ المشهد إلى مساحة العمل +Excalidraw الخاصة بك.`}},modal:{loadFromFile:{title:`تحميل من ملف`,button:`تحميل من ملف`,description:`سيتم التحميل من الملف <bold>استبدال المحتوى الموجود</bold>.<br></br>يمكنك النسخ الاحتياطي لرسمك أولاً باستخدام أحد الخيارات أدناه.`},shareableLink:{title:`تحميل من رابط`,button:`استبدال محتواي`,description:`سيتسبب تحميل رسمة خارجية <bold>باستبدال محتواك الموجود حالياً</bold>.<br></br>بإمكانك إجراء النسخ الاحتياطي لرسمتك الحالية باستخدام أحد الخيارات أدناه.`}}},E={title:``,button:``,description:``,syntax:``,preview:``},D={labels:e,library:t,buttons:n,alerts:r,errors:i,toolBar:a,headings:o,hints:s,canvasError:c,errorSplash:l,roomDialog:u,errorDialog:d,exportDialog:f,helpDialog:p,clearCanvasDialog:m,publishDialog:h,publishSuccessDialog:g,confirmDialog:_,imageExportDialog:v,encrypted:y,stats:b,toast:x,colors:S,welcomeScreen:C,colorPicker:w,overwriteConfirm:T,mermaid:E};export{r as alerts,n as buttons,c as canvasError,m as clearCanvasDialog,w as colorPicker,S as colors,_ as confirmDialog,D as default,y as encrypted,d as errorDialog,l as errorSplash,i as errors,f as exportDialog,o as headings,p as helpDialog,s as hints,v as imageExportDialog,e as labels,t as library,E as mermaid,T as overwriteConfirm,h as publishDialog,g as publishSuccessDialog,u as roomDialog,b as stats,x as toast,a as toolBar,C as welcomeScreen};
@@ -0,0 +1 @@
1
+ import{n as e,t}from"./path-BWPyau1x.js";import{a as n,c as r,d as i,f as a,i as o,l as s,m as c,n as l,o as u,p as d,r as f,u as p}from"./dist-C8c_sMtm.js";function m(e){return e.innerRadius}function h(e){return e.outerRadius}function g(e){return e.startAngle}function _(e){return e.endAngle}function v(e){return e&&e.padAngle}function y(e,t,n,r,i,a,o,s){var c=n-e,l=r-t,u=o-i,d=s-a,f=d*c-u*l;if(!(f*f<1e-12))return f=(u*(t-a)-d*(e-i))/f,[e+f*c,t+f*l]}function b(e,t,n,r,i,a,o){var c=e-n,l=t-r,u=(o?a:-a)/d(c*c+l*l),f=u*l,p=-u*c,m=e+f,h=t+p,g=n+f,_=r+p,v=(m+g)/2,y=(h+_)/2,b=g-m,x=_-h,S=b*b+x*x,C=i-a,w=m*_-g*h,T=(x<0?-1:1)*d(s(0,C*C*S-w*w)),E=(w*x-b*T)/S,D=(-w*b-x*T)/S,O=(w*x+b*T)/S,k=(-w*b+x*T)/S,A=E-v,j=D-y,M=O-v,N=k-y;return A*A+j*j>M*M+N*N&&(E=O,D=k),{cx:E,cy:D,x01:-f,y01:-p,x11:E*(i/C-1),y11:D*(i/C-1)}}function x(){var s=m,x=h,S=e(0),C=null,w=g,T=_,E=v,D=null,O=t(k);function k(){var e,t,m=+s.apply(this,arguments),h=+x.apply(this,arguments),g=w.apply(this,arguments)-r,_=T.apply(this,arguments)-r,v=l(_-g),k=_>g;if(D||=e=O(),h<m&&(t=h,h=m,m=t),!(h>1e-12))D.moveTo(0,0);else if(v>c-1e-12)D.moveTo(h*u(g),h*a(g)),D.arc(0,0,h,g,_,!k),m>1e-12&&(D.moveTo(m*u(_),m*a(_)),D.arc(0,0,m,_,g,k));else{var A=g,j=_,M=g,N=_,P=v,F=v,I=E.apply(this,arguments)/2,L=I>1e-12&&(C?+C.apply(this,arguments):d(m*m+h*h)),R=p(l(h-m)/2,+S.apply(this,arguments)),z=R,B=R,V,H;if(L>1e-12){var U=o(L/m*a(I)),W=o(L/h*a(I));(P-=U*2)>1e-12?(U*=k?1:-1,M+=U,N-=U):(P=0,M=N=(g+_)/2),(F-=W*2)>1e-12?(W*=k?1:-1,A+=W,j-=W):(F=0,A=j=(g+_)/2)}var G=h*u(A),K=h*a(A),q=m*u(N),J=m*a(N);if(R>1e-12){var Y=h*u(j),X=h*a(j),Z=m*u(M),Q=m*a(M),$;if(v<i)if($=y(G,K,Z,Q,Y,X,q,J)){var ee=G-$[0],te=K-$[1],ne=Y-$[0],re=X-$[1],ie=1/a(f((ee*ne+te*re)/(d(ee*ee+te*te)*d(ne*ne+re*re)))/2),ae=d($[0]*$[0]+$[1]*$[1]);z=p(R,(m-ae)/(ie-1)),B=p(R,(h-ae)/(ie+1))}else z=B=0}F>1e-12?B>1e-12?(V=b(Z,Q,G,K,h,B,k),H=b(Y,X,q,J,h,B,k),D.moveTo(V.cx+V.x01,V.cy+V.y01),B<R?D.arc(V.cx,V.cy,B,n(V.y01,V.x01),n(H.y01,H.x01),!k):(D.arc(V.cx,V.cy,B,n(V.y01,V.x01),n(V.y11,V.x11),!k),D.arc(0,0,h,n(V.cy+V.y11,V.cx+V.x11),n(H.cy+H.y11,H.cx+H.x11),!k),D.arc(H.cx,H.cy,B,n(H.y11,H.x11),n(H.y01,H.x01),!k))):(D.moveTo(G,K),D.arc(0,0,h,A,j,!k)):D.moveTo(G,K),!(m>1e-12)||!(P>1e-12)?D.lineTo(q,J):z>1e-12?(V=b(q,J,Y,X,m,-z,k),H=b(G,K,Z,Q,m,-z,k),D.lineTo(V.cx+V.x01,V.cy+V.y01),z<R?D.arc(V.cx,V.cy,z,n(V.y01,V.x01),n(H.y01,H.x01),!k):(D.arc(V.cx,V.cy,z,n(V.y01,V.x01),n(V.y11,V.x11),!k),D.arc(0,0,m,n(V.cy+V.y11,V.cx+V.x11),n(H.cy+H.y11,H.cx+H.x11),k),D.arc(H.cx,H.cy,z,n(H.y11,H.x11),n(H.y01,H.x01),!k))):D.arc(0,0,m,N,M,k)}if(D.closePath(),e)return D=null,e+``||null}return k.centroid=function(){var e=(+s.apply(this,arguments)+ +x.apply(this,arguments))/2,t=(+w.apply(this,arguments)+ +T.apply(this,arguments))/2-i/2;return[u(t)*e,a(t)*e]},k.innerRadius=function(t){return arguments.length?(s=typeof t==`function`?t:e(+t),k):s},k.outerRadius=function(t){return arguments.length?(x=typeof t==`function`?t:e(+t),k):x},k.cornerRadius=function(t){return arguments.length?(S=typeof t==`function`?t:e(+t),k):S},k.padRadius=function(t){return arguments.length?(C=t==null?null:typeof t==`function`?t:e(+t),k):C},k.startAngle=function(t){return arguments.length?(w=typeof t==`function`?t:e(+t),k):w},k.endAngle=function(t){return arguments.length?(T=typeof t==`function`?t:e(+t),k):T},k.padAngle=function(t){return arguments.length?(E=typeof t==`function`?t:e(+t),k):E},k.context=function(e){return arguments.length?(D=e??null,k):D},k}export{x as t};
@@ -0,0 +1 @@
1
+ import"./chunk-KEIR6QF5-BfrZ3jm6.js";import{o as e}from"./mermaid-parser.core-BqfnOrIO.js";export{e as createArchitectureServices};