@agent-canvas/cli 0.1.2 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/start.d.ts +0 -2
- package/dist/commands/start.js +15 -112
- package/dist/index.js +162 -27
- package/dist/lib/protocol.d.ts +12 -0
- package/dist/lib/ws-client.d.ts +0 -1
- package/dist/lib/ws-client.js +0 -18
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.js +37 -0
- package/dist/static/assets/{ar-SA-G6X2FPQ2-DyNcQEG6.js → ar-SA-G6X2FPQ2-DH2n1f9Q.js} +1 -1
- package/dist/static/assets/{arc-BbhT3kpR.js → arc-DSwghfDE.js} +1 -1
- package/dist/static/assets/{az-AZ-76LH7QW2-6FRN2HRu.js → az-AZ-76LH7QW2-Cxm-bt5B.js} +1 -1
- package/dist/static/assets/{bg-BG-XCXSNQG7-BAatOQKg.js → bg-BG-XCXSNQG7-Cj0Sip-L.js} +1 -1
- package/dist/static/assets/{blockDiagram-38ab4fdb-CWMvXzur.js → blockDiagram-38ab4fdb-CvagfZR2.js} +1 -1
- package/dist/static/assets/{bn-BD-2XOGV67Q-CS2Tej4d.js → bn-BD-2XOGV67Q-BNoWI4Vi.js} +1 -1
- package/dist/static/assets/{c4Diagram-3d4e48cf-C7AOUEVw.js → c4Diagram-3d4e48cf-CF5c7HOc.js} +1 -1
- package/dist/static/assets/{ca-ES-6MX7JW3Y-CrRON-ta.js → ca-ES-6MX7JW3Y-Buz-sA9F.js} +1 -1
- package/dist/static/assets/channel-Bh1oWGVH.js +1 -0
- package/dist/static/assets/{classDiagram-70f12bd4-Dy_Zdc-c.js → classDiagram-70f12bd4-DEy5qx_x.js} +1 -1
- package/dist/static/assets/{classDiagram-v2-f2320105-CjSxB_UF.js → classDiagram-v2-f2320105-BWJFthkP.js} +1 -1
- package/dist/static/assets/clone-BeiLdjSo.js +1 -0
- package/dist/static/assets/{createText-2e5e7dd3-CREXrDg4.js → createText-2e5e7dd3-DT0MMTMt.js} +1 -1
- package/dist/static/assets/{cs-CZ-2BRQDIVT-BLn2zwD5.js → cs-CZ-2BRQDIVT-DkiVtR_5.js} +1 -1
- package/dist/static/assets/{da-DK-5WZEPLOC-DTfqWS1m.js → da-DK-5WZEPLOC-DoVTEeYq.js} +1 -1
- package/dist/static/assets/{de-DE-XR44H4JA-CBm33ToK.js → de-DE-XR44H4JA-D02LO9rN.js} +1 -1
- package/dist/static/assets/{edges-e0da2a9e-XV6mdrlk.js → edges-e0da2a9e-DSJ5Cn_i.js} +1 -1
- package/dist/static/assets/{el-GR-BZB4AONW-CovIUFtq.js → el-GR-BZB4AONW-BAtInWEI.js} +1 -1
- package/dist/static/assets/{erDiagram-9861fffd-BHiuXMbj.js → erDiagram-9861fffd-9K08ZFDe.js} +1 -1
- package/dist/static/assets/{es-ES-U4NZUMDT-xhwf3Gvs.js → es-ES-U4NZUMDT-cPh2cdP7.js} +1 -1
- package/dist/static/assets/{eu-ES-A7QVB2H4-CY-s9u74.js → eu-ES-A7QVB2H4-g1PzZ-pb.js} +1 -1
- package/dist/static/assets/{fa-IR-HGAKTJCU-CqiYv3_M.js → fa-IR-HGAKTJCU-Dotngoci.js} +1 -1
- package/dist/static/assets/{fi-FI-Z5N7JZ37-ByFmziTt.js → fi-FI-Z5N7JZ37-CMkSfDt1.js} +1 -1
- package/dist/static/assets/{flowDb-956e92f1--YaaQ1az.js → flowDb-956e92f1-BF28mVE5.js} +1 -1
- package/dist/static/assets/{flowDiagram-66a62f08-CiStLJ_j.js → flowDiagram-66a62f08-CBq8pz-r.js} +1 -1
- package/dist/static/assets/flowDiagram-v2-96b9c2cf-Dja0Izfz.js +1 -0
- package/dist/static/assets/{flowchart-elk-definition-4a651766-iZZsNsFB.js → flowchart-elk-definition-4a651766-Cz5NLAVQ.js} +1 -1
- package/dist/static/assets/{fr-FR-RHASNOE6-BDM0Orh-.js → fr-FR-RHASNOE6--ee0QaBP.js} +1 -1
- package/dist/static/assets/{ganttDiagram-c361ad54--D8Gb02S.js → ganttDiagram-c361ad54-B41GjRL_.js} +1 -1
- package/dist/static/assets/{gitGraphDiagram-72cf32ee-BP9V2H_i.js → gitGraphDiagram-72cf32ee-Dt6aWBpu.js} +1 -1
- package/dist/static/assets/{gl-ES-HMX3MZ6V-YzWSA_U5.js → gl-ES-HMX3MZ6V-BANNW5oV.js} +1 -1
- package/dist/static/assets/{graph-CDY5v4hg.js → graph-BViLJDpH.js} +1 -1
- package/dist/static/assets/{he-IL-6SHJWFNN-DGhuVKeh.js → he-IL-6SHJWFNN-BIQP0u6P.js} +1 -1
- package/dist/static/assets/{hi-IN-IWLTKZ5I-Bf2OxFpo.js → hi-IN-IWLTKZ5I-BMNE591o.js} +1 -1
- package/dist/static/assets/{hu-HU-A5ZG7DT2-Bgm6MfVV.js → hu-HU-A5ZG7DT2-B59Uuq-D.js} +1 -1
- package/dist/static/assets/{id-ID-SAP4L64H-Be4CWRpp.js → id-ID-SAP4L64H-DWKrSOEI.js} +1 -1
- package/dist/static/assets/{index-3862675e-DO7_p44e.js → index-3862675e-rxi3xVjP.js} +1 -1
- package/dist/static/assets/{index-M3ercR-c.js → index-ChPLID-A.js} +4 -4
- package/dist/static/assets/{index-D9K5p6xj.js → index-Dq9tezYn.js} +50 -50
- package/dist/static/assets/{infoDiagram-f8f76790-R_fZ7_IN.js → infoDiagram-f8f76790-gXSChgmZ.js} +1 -1
- package/dist/static/assets/{it-IT-JPQ66NNP-BNcyVwD2.js → it-IT-JPQ66NNP-5YgGFtR8.js} +1 -1
- package/dist/static/assets/{ja-JP-DBVTYXUO-CLiGkSXX.js → ja-JP-DBVTYXUO-CQe8gSy1.js} +1 -1
- package/dist/static/assets/{journeyDiagram-49397b02-DXa6Hio7.js → journeyDiagram-49397b02-D7dTRcMS.js} +1 -1
- package/dist/static/assets/{kaa-6HZHGXH3-CtCiUe72.js → kaa-6HZHGXH3-qgzLbYWr.js} +1 -1
- package/dist/static/assets/{kab-KAB-ZGHBKWFO-jaWR3c0c.js → kab-KAB-ZGHBKWFO-he6LsMVd.js} +1 -1
- package/dist/static/assets/{kk-KZ-P5N5QNE5-Dz3mQQBP.js → kk-KZ-P5N5QNE5-BAGrvKw-.js} +1 -1
- package/dist/static/assets/{km-KH-HSX4SM5Z-CQlDP0cg.js → km-KH-HSX4SM5Z-YQK2wUqV.js} +1 -1
- package/dist/static/assets/{ko-KR-MTYHY66A-SADoSfWj.js → ko-KR-MTYHY66A-DgUXWHhI.js} +1 -1
- package/dist/static/assets/{ku-TR-6OUDTVRD-B27fDZ8n.js → ku-TR-6OUDTVRD-CllKA2Q8.js} +1 -1
- package/dist/static/assets/{layout-DFkOIywR.js → layout-PtECFbDA.js} +1 -1
- package/dist/static/assets/{line-BkGGz1Gi.js → line--4PuTgFs.js} +1 -1
- package/dist/static/assets/{linear-bj4xbXj8.js → linear-mpRFIrCY.js} +1 -1
- package/dist/static/assets/{lt-LT-XHIRWOB4-CoJ8AQlv.js → lt-LT-XHIRWOB4-Lc06xM_t.js} +1 -1
- package/dist/static/assets/{lv-LV-5QDEKY6T-BNu6FZuj.js → lv-LV-5QDEKY6T-DjPQsp57.js} +1 -1
- package/dist/static/assets/{mindmap-definition-fc14e90a-DmZ8jzp5.js → mindmap-definition-fc14e90a-DVb-paYk.js} +1 -1
- package/dist/static/assets/{mr-IN-CRQNXWMA-BvurhLbm.js → mr-IN-CRQNXWMA-C_oyBWpj.js} +1 -1
- package/dist/static/assets/{my-MM-5M5IBNSE-mRTevT97.js → my-MM-5M5IBNSE-5e9rxU8V.js} +1 -1
- package/dist/static/assets/{nb-NO-T6EIAALU-BcOTaqeP.js → nb-NO-T6EIAALU-DiatY1a3.js} +1 -1
- package/dist/static/assets/{nl-NL-IS3SIHDZ-Bd8Xm5YF.js → nl-NL-IS3SIHDZ-DYho2XpO.js} +1 -1
- package/dist/static/assets/{nn-NO-6E72VCQL-DEvQB3Jv.js → nn-NO-6E72VCQL--exG3tqa.js} +1 -1
- package/dist/static/assets/{oc-FR-POXYY2M6--hbNWw9E.js → oc-FR-POXYY2M6-D5YMexgJ.js} +1 -1
- package/dist/static/assets/{pa-IN-N4M65BXN-pIQoan9P.js → pa-IN-N4M65BXN-B-QpbuPU.js} +1 -1
- package/dist/static/assets/{pica-C10VOhpQ.js → pica-CYGCxyFx.js} +1 -1
- package/dist/static/assets/{pieDiagram-8a3498a8-CiEHu0OP.js → pieDiagram-8a3498a8-BIb0XBmP.js} +1 -1
- package/dist/static/assets/{pl-PL-T2D74RX3-DFiZqgo0.js → pl-PL-T2D74RX3-CyQ9ScCZ.js} +1 -1
- package/dist/static/assets/{pt-BR-5N22H2LF-Cc0xlz4q.js → pt-BR-5N22H2LF-C2fBatBI.js} +1 -1
- package/dist/static/assets/{pt-PT-UZXXM6DQ-B3zd49KM.js → pt-PT-UZXXM6DQ-lSWbA8ta.js} +1 -1
- package/dist/static/assets/{quadrantDiagram-120e2f19-DKTSsmZy.js → quadrantDiagram-120e2f19-B0IUKZHd.js} +1 -1
- package/dist/static/assets/{requirementDiagram-deff3bca-DQOiJiwY.js → requirementDiagram-deff3bca-DQtENapr.js} +1 -1
- package/dist/static/assets/{ro-RO-JPDTUUEW-C9N7IthB.js → ro-RO-JPDTUUEW-CA8EbRFB.js} +1 -1
- package/dist/static/assets/{ru-RU-B4JR7IUQ-CIZdU2_B.js → ru-RU-B4JR7IUQ-DLFEoBBN.js} +1 -1
- package/dist/static/assets/{sankeyDiagram-04a897e0-TilwwYL-.js → sankeyDiagram-04a897e0-CqarZxqc.js} +1 -1
- package/dist/static/assets/{sequenceDiagram-704730f1-BiVJk4lg.js → sequenceDiagram-704730f1-D_k2eCYQ.js} +1 -1
- package/dist/static/assets/{si-LK-N5RQ5JYF-CxFkliCr.js → si-LK-N5RQ5JYF-BNFow9lY.js} +1 -1
- package/dist/static/assets/{sk-SK-C5VTKIMK-JZtsQcSw.js → sk-SK-C5VTKIMK-DGB0M6nr.js} +1 -1
- package/dist/static/assets/{sl-SI-NN7IZMDC-BUYqyq49.js → sl-SI-NN7IZMDC-CJDYDrpB.js} +1 -1
- package/dist/static/assets/{stateDiagram-587899a1-B1sCio7H.js → stateDiagram-587899a1-CmJUP4x5.js} +1 -1
- package/dist/static/assets/{stateDiagram-v2-d93cdb3a-CoGzFssB.js → stateDiagram-v2-d93cdb3a-shPgA-Re.js} +1 -1
- package/dist/static/assets/{styles-6aaf32cf-C1s7Ul3J.js → styles-6aaf32cf-D6ni1cH-.js} +1 -1
- package/dist/static/assets/{styles-9a916d00-Bp5-VH98.js → styles-9a916d00-DF1cbr_V.js} +1 -1
- package/dist/static/assets/{styles-c10674c1-DfO5CrB5.js → styles-c10674c1-pZpeeixm.js} +1 -1
- package/dist/static/assets/{subset-shared.chunk-QCqXuXCH.js → subset-shared.chunk-B7Bsj1CE.js} +1 -1
- package/dist/static/assets/{subset-worker.chunk-BjKI4tmi.js → subset-worker.chunk-DvVFmVNJ.js} +1 -1
- package/dist/static/assets/{sv-SE-XGPEYMSR-Cz1rfwXY.js → sv-SE-XGPEYMSR-Ct3zlqNH.js} +1 -1
- package/dist/static/assets/{svgDrawCommon-08f97a94-mI-dkcv_.js → svgDrawCommon-08f97a94-ihzL1PNw.js} +1 -1
- package/dist/static/assets/{ta-IN-2NMHFXQM-CtHc6ooj.js → ta-IN-2NMHFXQM-Ss8wmPcU.js} +1 -1
- package/dist/static/assets/{th-TH-HPSO5L25-xIQ7sAKy.js → th-TH-HPSO5L25-RgqhD66T.js} +1 -1
- package/dist/static/assets/{timeline-definition-85554ec2-BylSkqlD.js → timeline-definition-85554ec2-Ck3wPUBk.js} +1 -1
- package/dist/static/assets/{tr-TR-DEFEU3FU-CrIfozru.js → tr-TR-DEFEU3FU-CYb8OLTu.js} +1 -1
- package/dist/static/assets/{uk-UA-QMV73CPH-Dr07MVsF.js → uk-UA-QMV73CPH-BirNsE4V.js} +1 -1
- package/dist/static/assets/{vi-VN-M7AON7JQ-ChRYxYRs.js → vi-VN-M7AON7JQ-BxI4Rmvs.js} +1 -1
- package/dist/static/assets/{xychartDiagram-e933f94c-ByBCDYvY.js → xychartDiagram-e933f94c-D2woJW1O.js} +1 -1
- package/dist/static/assets/{zh-CN-LNUGB5OW-B9Dg6rSU.js → zh-CN-LNUGB5OW-DCBQmThi.js} +1 -1
- package/dist/static/assets/{zh-HK-E62DVLB3-17W7WnGJ.js → zh-HK-E62DVLB3-C1h46zXW.js} +1 -1
- package/dist/static/assets/{zh-TW-RAJ6MFWO-B1yJY7cJ.js → zh-TW-RAJ6MFWO-3TGZr7NK.js} +1 -1
- package/dist/static/index.html +1 -1
- package/package.json +1 -1
- package/dist/static/assets/channel-DfDbkfoc.js +0 -1
- package/dist/static/assets/clone-C-cGF6mM.js +0 -1
- package/dist/static/assets/flowDiagram-v2-96b9c2cf-D8VcptSb.js +0 -1
package/dist/commands/start.d.ts
CHANGED
package/dist/commands/start.js
CHANGED
|
@@ -1,76 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { resolve
|
|
3
|
-
import { fileURLToPath } from 'url';
|
|
1
|
+
import { exec } from 'child_process';
|
|
2
|
+
import { resolve } from 'path';
|
|
4
3
|
import { readFileSync, existsSync } from 'fs';
|
|
5
4
|
import { promisify } from 'util';
|
|
6
|
-
import { connectToCanvas,
|
|
7
|
-
import { startServer, isBrowserServerRunning } from '../server/index.js';
|
|
5
|
+
import { connectToCanvas, generateId } from '../lib/ws-client.js';
|
|
6
|
+
import { startServer, isBrowserServerRunning, isBrowserConnected } from '../server/index.js';
|
|
8
7
|
const execAsync = promisify(exec);
|
|
9
|
-
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
10
|
-
function getDevElectronAppPath() {
|
|
11
|
-
// Check if running in monorepo dev mode
|
|
12
|
-
const devPath = resolve(__dirname, '../../../electron-app');
|
|
13
|
-
if (existsSync(resolve(devPath, 'package.json'))) {
|
|
14
|
-
return devPath;
|
|
15
|
-
}
|
|
16
|
-
return null;
|
|
17
|
-
}
|
|
18
|
-
async function findElectronAppCommand() {
|
|
19
|
-
// Check if agent-canvas-app command is available
|
|
20
|
-
try {
|
|
21
|
-
const cmd = process.platform === 'win32' ? 'where' : 'which';
|
|
22
|
-
await execAsync(`${cmd} agent-canvas-app`);
|
|
23
|
-
return 'agent-canvas-app';
|
|
24
|
-
}
|
|
25
|
-
catch {
|
|
26
|
-
return null;
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
async function launchElectronApp() {
|
|
30
|
-
// First, try to find installed electron-app command
|
|
31
|
-
const appCommand = await findElectronAppCommand();
|
|
32
|
-
if (appCommand) {
|
|
33
|
-
// Use installed electron-app
|
|
34
|
-
const child = spawn(appCommand, [], {
|
|
35
|
-
detached: true,
|
|
36
|
-
stdio: 'ignore',
|
|
37
|
-
});
|
|
38
|
-
child.unref();
|
|
39
|
-
}
|
|
40
|
-
else {
|
|
41
|
-
// Check if running in dev mode (monorepo)
|
|
42
|
-
const devPath = getDevElectronAppPath();
|
|
43
|
-
if (devPath) {
|
|
44
|
-
const child = spawn('bun', ['run', 'dev'], {
|
|
45
|
-
cwd: devPath,
|
|
46
|
-
detached: true,
|
|
47
|
-
stdio: 'ignore',
|
|
48
|
-
});
|
|
49
|
-
child.unref();
|
|
50
|
-
}
|
|
51
|
-
else {
|
|
52
|
-
// electron-app not found
|
|
53
|
-
console.error('Electron app not found.');
|
|
54
|
-
console.error('');
|
|
55
|
-
console.error('To use --app mode, install the electron app:');
|
|
56
|
-
console.error(' npm install -g @agent-canvas/electron-app');
|
|
57
|
-
console.error('');
|
|
58
|
-
console.error('Or use browser mode (default):');
|
|
59
|
-
console.error(' agent-canvas start');
|
|
60
|
-
process.exit(1);
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
// Wait for app to start
|
|
64
|
-
const maxRetries = 30;
|
|
65
|
-
const retryInterval = 500;
|
|
66
|
-
for (let i = 0; i < maxRetries; i++) {
|
|
67
|
-
await new Promise((r) => setTimeout(r, retryInterval));
|
|
68
|
-
if (await isCanvasRunning()) {
|
|
69
|
-
return;
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
throw new Error('Failed to start electron app');
|
|
73
|
-
}
|
|
74
8
|
async function openBrowser(url) {
|
|
75
9
|
const platform = process.platform;
|
|
76
10
|
try {
|
|
@@ -118,8 +52,7 @@ async function loadFile(filePath) {
|
|
|
118
52
|
process.exit(1);
|
|
119
53
|
}
|
|
120
54
|
}
|
|
121
|
-
|
|
122
|
-
export async function startBrowser(filePath) {
|
|
55
|
+
export async function start(filePath) {
|
|
123
56
|
if (filePath) {
|
|
124
57
|
const absolutePath = resolve(filePath);
|
|
125
58
|
if (!existsSync(absolutePath)) {
|
|
@@ -128,16 +61,19 @@ export async function startBrowser(filePath) {
|
|
|
128
61
|
}
|
|
129
62
|
}
|
|
130
63
|
const running = await isBrowserServerRunning();
|
|
131
|
-
if (running) {
|
|
132
|
-
console.log('
|
|
133
|
-
|
|
134
|
-
|
|
64
|
+
if (!running) {
|
|
65
|
+
console.log('Starting canvas server...');
|
|
66
|
+
await startServer();
|
|
67
|
+
}
|
|
68
|
+
// Give existing browser tabs a moment to reconnect (browser reconnects every 1s)
|
|
69
|
+
await new Promise((r) => setTimeout(r, 1500));
|
|
70
|
+
const browserConnected = await isBrowserConnected();
|
|
71
|
+
if (browserConnected) {
|
|
72
|
+
console.log('Canvas already running at http://localhost:7891');
|
|
135
73
|
}
|
|
136
74
|
else {
|
|
137
|
-
console.log('Starting canvas server...');
|
|
138
|
-
const { httpUrl } = await startServer();
|
|
139
75
|
console.log('Opening browser...');
|
|
140
|
-
await openBrowser(
|
|
76
|
+
await openBrowser('http://localhost:7891');
|
|
141
77
|
}
|
|
142
78
|
// Wait for browser to connect, then load file if specified
|
|
143
79
|
if (filePath) {
|
|
@@ -162,36 +98,3 @@ export async function startBrowser(filePath) {
|
|
|
162
98
|
console.log('\nCanvas is ready. Press Ctrl+C to stop.');
|
|
163
99
|
await new Promise(() => { }); // Block forever
|
|
164
100
|
}
|
|
165
|
-
// Electron app mode (--app)
|
|
166
|
-
export async function startApp(filePath) {
|
|
167
|
-
if (filePath) {
|
|
168
|
-
const absolutePath = resolve(filePath);
|
|
169
|
-
if (!existsSync(absolutePath)) {
|
|
170
|
-
console.error(`File not found: ${absolutePath}`);
|
|
171
|
-
process.exit(1);
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
console.log('Checking if canvas app is running...');
|
|
175
|
-
const running = await isCanvasRunning();
|
|
176
|
-
if (!running) {
|
|
177
|
-
console.log('Starting canvas app...');
|
|
178
|
-
await launchElectronApp();
|
|
179
|
-
}
|
|
180
|
-
console.log('Connecting to canvas app...');
|
|
181
|
-
try {
|
|
182
|
-
const client = await connectToCanvas();
|
|
183
|
-
console.log('Connected to canvas app');
|
|
184
|
-
if (filePath) {
|
|
185
|
-
await loadFile(filePath);
|
|
186
|
-
}
|
|
187
|
-
client.close();
|
|
188
|
-
}
|
|
189
|
-
catch (err) {
|
|
190
|
-
console.error('Failed to connect:', err instanceof Error ? err.message : err);
|
|
191
|
-
process.exit(1);
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
// Legacy export for backward compatibility
|
|
195
|
-
export async function start(filePath) {
|
|
196
|
-
return startBrowser(filePath);
|
|
197
|
-
}
|
package/dist/index.js
CHANGED
|
@@ -1,25 +1,19 @@
|
|
|
1
1
|
import { Command } from 'commander';
|
|
2
2
|
import { writeFileSync } from 'node:fs';
|
|
3
3
|
import { encode as toToon } from '@toon-format/toon';
|
|
4
|
-
import {
|
|
4
|
+
import { start } from './commands/start.js';
|
|
5
5
|
import { connectToCanvas, generateId } from './lib/ws-client.js';
|
|
6
6
|
const program = new Command();
|
|
7
7
|
program
|
|
8
8
|
.name('agent-canvas')
|
|
9
9
|
.description('CLI for Agent Canvas - Excalidraw interface for AI agents')
|
|
10
|
-
.version('0.1
|
|
10
|
+
.version('0.2.1');
|
|
11
11
|
program
|
|
12
12
|
.command('start')
|
|
13
|
-
.description('Start the canvas
|
|
13
|
+
.description('Start the canvas server and open in browser')
|
|
14
14
|
.option('-f, --file <path>', 'Load an .excalidraw file on start')
|
|
15
|
-
.option('--app', 'Use Electron app instead of browser')
|
|
16
15
|
.action(async (options) => {
|
|
17
|
-
|
|
18
|
-
await startApp(options.file);
|
|
19
|
-
}
|
|
20
|
-
else {
|
|
21
|
-
await startBrowser(options.file);
|
|
22
|
-
}
|
|
16
|
+
await start(options.file);
|
|
23
17
|
});
|
|
24
18
|
// ============================================================================
|
|
25
19
|
// Add Shape
|
|
@@ -39,6 +33,7 @@ program
|
|
|
39
33
|
.option('--fill-style <style>', 'Fill style: hachure, cross-hatch, solid, or zigzag')
|
|
40
34
|
.option('-l, --label <text>', 'Text label inside the shape')
|
|
41
35
|
.option('--label-font-size <number>', 'Label font size', parseFloat)
|
|
36
|
+
.option('-n, --note <text>', 'Note for this element (stored in customData)')
|
|
42
37
|
.action(async (options) => {
|
|
43
38
|
const client = await connectToCanvas();
|
|
44
39
|
const params = {
|
|
@@ -52,6 +47,7 @@ program
|
|
|
52
47
|
strokeWidth: options.strokeWidth,
|
|
53
48
|
strokeStyle: options.strokeStyle,
|
|
54
49
|
fillStyle: options.fillStyle,
|
|
50
|
+
customData: options.note ? { note: options.note } : undefined,
|
|
55
51
|
};
|
|
56
52
|
if (options.label) {
|
|
57
53
|
params.label = { text: options.label, fontSize: options.labelFontSize };
|
|
@@ -78,6 +74,7 @@ program
|
|
|
78
74
|
.option('--font-size <number>', 'Font size', parseFloat)
|
|
79
75
|
.option('--text-align <align>', 'Text alignment: left, center, or right')
|
|
80
76
|
.option('--stroke-color <color>', 'Text color (hex)')
|
|
77
|
+
.option('-n, --note <text>', 'Note for this element (stored in customData)')
|
|
81
78
|
.action(async (options) => {
|
|
82
79
|
const client = await connectToCanvas();
|
|
83
80
|
const result = await client.send({
|
|
@@ -90,6 +87,7 @@ program
|
|
|
90
87
|
fontSize: options.fontSize,
|
|
91
88
|
textAlign: options.textAlign,
|
|
92
89
|
strokeColor: options.strokeColor,
|
|
90
|
+
customData: options.note ? { note: options.note } : undefined,
|
|
93
91
|
},
|
|
94
92
|
});
|
|
95
93
|
if (result.success) {
|
|
@@ -114,6 +112,7 @@ program
|
|
|
114
112
|
.option('--stroke-color <color>', 'Line color (hex)')
|
|
115
113
|
.option('--stroke-width <number>', 'Line width in pixels', parseFloat)
|
|
116
114
|
.option('--stroke-style <style>', 'Line style: solid, dashed, or dotted')
|
|
115
|
+
.option('-n, --note <text>', 'Note for this element (stored in customData)')
|
|
117
116
|
.action(async (options) => {
|
|
118
117
|
const client = await connectToCanvas();
|
|
119
118
|
const result = await client.send({
|
|
@@ -127,6 +126,7 @@ program
|
|
|
127
126
|
strokeColor: options.strokeColor,
|
|
128
127
|
strokeWidth: options.strokeWidth,
|
|
129
128
|
strokeStyle: options.strokeStyle,
|
|
129
|
+
customData: options.note ? { note: options.note } : undefined,
|
|
130
130
|
},
|
|
131
131
|
});
|
|
132
132
|
if (result.success) {
|
|
@@ -153,6 +153,7 @@ program
|
|
|
153
153
|
.option('--stroke-style <style>', 'Arrow style: solid, dashed, or dotted')
|
|
154
154
|
.option('--start-arrowhead <type>', 'Start arrowhead: arrow, bar, dot, triangle, diamond, none')
|
|
155
155
|
.option('--end-arrowhead <type>', 'End arrowhead: arrow, bar, dot, triangle, diamond, none')
|
|
156
|
+
.option('-n, --note <text>', 'Note for this element (stored in customData)')
|
|
156
157
|
.action(async (options) => {
|
|
157
158
|
const client = await connectToCanvas();
|
|
158
159
|
const result = await client.send({
|
|
@@ -168,6 +169,7 @@ program
|
|
|
168
169
|
strokeStyle: options.strokeStyle,
|
|
169
170
|
startArrowhead: options.startArrowhead,
|
|
170
171
|
endArrowhead: options.endArrowhead,
|
|
172
|
+
customData: options.note ? { note: options.note } : undefined,
|
|
171
173
|
},
|
|
172
174
|
});
|
|
173
175
|
if (result.success) {
|
|
@@ -191,6 +193,7 @@ program
|
|
|
191
193
|
.option('--stroke-width <number>', 'Stroke width in pixels', parseFloat)
|
|
192
194
|
.option('--stroke-style <style>', 'Stroke style: solid, dashed, or dotted')
|
|
193
195
|
.option('--fill-style <style>', 'Fill style: hachure, cross-hatch, solid, or zigzag')
|
|
196
|
+
.option('-n, --note <text>', 'Note for this element (stored in customData)')
|
|
194
197
|
.action(async (options) => {
|
|
195
198
|
let points;
|
|
196
199
|
try {
|
|
@@ -211,6 +214,7 @@ program
|
|
|
211
214
|
strokeWidth: options.strokeWidth,
|
|
212
215
|
strokeStyle: options.strokeStyle,
|
|
213
216
|
fillStyle: options.fillStyle,
|
|
217
|
+
customData: options.note ? { note: options.note } : undefined,
|
|
214
218
|
},
|
|
215
219
|
});
|
|
216
220
|
if (result.success) {
|
|
@@ -350,31 +354,162 @@ program
|
|
|
350
354
|
program
|
|
351
355
|
.command('read')
|
|
352
356
|
.description('Read all elements from the canvas (TOON format by default)')
|
|
353
|
-
.option('--json', 'Output
|
|
357
|
+
.option('--json', 'Output raw Excalidraw scene JSON')
|
|
358
|
+
.option('--with-style', 'Include style info (stroke, bg) in TOON output')
|
|
354
359
|
.action(async (options) => {
|
|
355
360
|
const client = await connectToCanvas();
|
|
361
|
+
if (options.json) {
|
|
362
|
+
// Return raw Excalidraw scene data
|
|
363
|
+
const result = await client.send({
|
|
364
|
+
type: 'saveScene',
|
|
365
|
+
id: generateId(),
|
|
366
|
+
});
|
|
367
|
+
if (result.success && result.data) {
|
|
368
|
+
console.log(JSON.stringify(result.data, null, 2));
|
|
369
|
+
}
|
|
370
|
+
else {
|
|
371
|
+
console.error(`Failed: ${result.error}`);
|
|
372
|
+
process.exit(1);
|
|
373
|
+
}
|
|
374
|
+
client.close();
|
|
375
|
+
return;
|
|
376
|
+
}
|
|
356
377
|
const result = await client.send({
|
|
357
378
|
type: 'readScene',
|
|
358
379
|
id: generateId(),
|
|
359
380
|
});
|
|
360
381
|
if (result.success && result.elements) {
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
382
|
+
const withStyle = options.withStyle;
|
|
383
|
+
// Separate elements into shapes, lines, labels (bound text), texts (standalone text), and groups
|
|
384
|
+
const shapes = [];
|
|
385
|
+
const lines = [];
|
|
386
|
+
const labels = [];
|
|
387
|
+
const texts = [];
|
|
388
|
+
const groupsMap = new Map(); // groupId -> elementIds
|
|
389
|
+
for (const el of result.elements) {
|
|
390
|
+
const angle = el.angle ? Math.round(el.angle * 180 / Math.PI) : 0; // Convert radians to degrees
|
|
391
|
+
// Collect group memberships
|
|
392
|
+
if (el.groupIds?.length) {
|
|
393
|
+
for (const groupId of el.groupIds) {
|
|
394
|
+
if (!groupsMap.has(groupId)) {
|
|
395
|
+
groupsMap.set(groupId, []);
|
|
396
|
+
}
|
|
397
|
+
groupsMap.get(groupId).push(el.id);
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
if (el.type === 'text') {
|
|
401
|
+
if (el.containerId) {
|
|
402
|
+
// Bound text (label)
|
|
403
|
+
labels.push({
|
|
404
|
+
id: el.id,
|
|
405
|
+
containerId: el.containerId,
|
|
406
|
+
content: el.text ?? '',
|
|
407
|
+
x: Math.round(el.x),
|
|
408
|
+
y: Math.round(el.y),
|
|
409
|
+
w: el.width !== undefined ? Math.round(el.width) : null,
|
|
410
|
+
h: el.height !== undefined ? Math.round(el.height) : null,
|
|
411
|
+
});
|
|
412
|
+
}
|
|
413
|
+
else {
|
|
414
|
+
// Standalone text
|
|
415
|
+
const text = {
|
|
416
|
+
id: el.id,
|
|
417
|
+
content: el.text ?? '',
|
|
418
|
+
x: Math.round(el.x),
|
|
419
|
+
y: Math.round(el.y),
|
|
420
|
+
w: el.width !== undefined ? Math.round(el.width) : null,
|
|
421
|
+
h: el.height !== undefined ? Math.round(el.height) : null,
|
|
422
|
+
angle,
|
|
423
|
+
note: el.customData?.note ?? null,
|
|
424
|
+
};
|
|
425
|
+
if (withStyle) {
|
|
426
|
+
text.stroke = el.strokeColor ?? null;
|
|
427
|
+
}
|
|
428
|
+
texts.push(text);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
else if (el.type === 'line' || el.type === 'arrow') {
|
|
432
|
+
const pts = el.points ?? [];
|
|
433
|
+
// Check if it's a closed polygon (first and last point within 8px threshold)
|
|
434
|
+
const isPolygon = el.type === 'line' && pts.length >= 3 && (() => {
|
|
435
|
+
const first = pts[0];
|
|
436
|
+
const last = pts[pts.length - 1];
|
|
437
|
+
const distance = Math.sqrt((last[0] - first[0]) ** 2 + (last[1] - first[1]) ** 2);
|
|
438
|
+
return distance <= 8;
|
|
439
|
+
})();
|
|
440
|
+
if (isPolygon) {
|
|
441
|
+
// Polygon - treat as shape
|
|
442
|
+
// Calculate bounding box from points
|
|
443
|
+
const xs = pts.map(p => p[0]);
|
|
444
|
+
const ys = pts.map(p => p[1]);
|
|
445
|
+
const minX = Math.min(...xs);
|
|
446
|
+
const maxX = Math.max(...xs);
|
|
447
|
+
const minY = Math.min(...ys);
|
|
448
|
+
const maxY = Math.max(...ys);
|
|
449
|
+
const shape = {
|
|
450
|
+
id: el.id,
|
|
451
|
+
type: 'polygon',
|
|
452
|
+
x: Math.round(el.x + minX),
|
|
453
|
+
y: Math.round(el.y + minY),
|
|
454
|
+
w: Math.round(maxX - minX),
|
|
455
|
+
h: Math.round(maxY - minY),
|
|
456
|
+
angle,
|
|
457
|
+
labelId: null,
|
|
458
|
+
note: el.customData?.note ?? null,
|
|
459
|
+
};
|
|
460
|
+
if (withStyle) {
|
|
461
|
+
shape.stroke = el.strokeColor ?? null;
|
|
462
|
+
shape.bg = el.backgroundColor ?? null;
|
|
463
|
+
}
|
|
464
|
+
shapes.push(shape);
|
|
465
|
+
}
|
|
466
|
+
else {
|
|
467
|
+
// Line/Arrow element
|
|
468
|
+
const lastPt = pts.length > 0 ? pts[pts.length - 1] : [0, 0];
|
|
469
|
+
const line = {
|
|
470
|
+
id: el.id,
|
|
471
|
+
type: el.type,
|
|
472
|
+
x: Math.round(el.x),
|
|
473
|
+
y: Math.round(el.y),
|
|
474
|
+
endX: Math.round(el.x + lastPt[0]),
|
|
475
|
+
endY: Math.round(el.y + lastPt[1]),
|
|
476
|
+
points: pts.length,
|
|
477
|
+
angle,
|
|
478
|
+
note: el.customData?.note ?? null,
|
|
479
|
+
};
|
|
480
|
+
if (withStyle) {
|
|
481
|
+
line.stroke = el.strokeColor ?? null;
|
|
482
|
+
}
|
|
483
|
+
lines.push(line);
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
else {
|
|
487
|
+
// Shape element (rectangle, ellipse, diamond, etc.)
|
|
488
|
+
const boundText = el.boundElements?.find(b => b.type === 'text');
|
|
489
|
+
const shape = {
|
|
490
|
+
id: el.id,
|
|
491
|
+
type: el.type,
|
|
492
|
+
x: Math.round(el.x),
|
|
493
|
+
y: Math.round(el.y),
|
|
494
|
+
w: el.width !== undefined ? Math.round(el.width) : null,
|
|
495
|
+
h: el.height !== undefined ? Math.round(el.height) : null,
|
|
496
|
+
angle,
|
|
497
|
+
labelId: boundText?.id ?? null,
|
|
498
|
+
note: el.customData?.note ?? null,
|
|
499
|
+
};
|
|
500
|
+
if (withStyle) {
|
|
501
|
+
shape.stroke = el.strokeColor ?? null;
|
|
502
|
+
shape.bg = el.backgroundColor ?? null;
|
|
503
|
+
}
|
|
504
|
+
shapes.push(shape);
|
|
505
|
+
}
|
|
377
506
|
}
|
|
507
|
+
// Build groups array
|
|
508
|
+
const groups = Array.from(groupsMap.entries()).map(([id, elementIds]) => ({
|
|
509
|
+
id,
|
|
510
|
+
elementIds: elementIds.join(','),
|
|
511
|
+
}));
|
|
512
|
+
console.log(toToon({ shapes, lines, labels, texts, groups }));
|
|
378
513
|
}
|
|
379
514
|
else {
|
|
380
515
|
console.error(`Failed: ${result.error}`);
|
package/dist/lib/protocol.d.ts
CHANGED
|
@@ -17,6 +17,7 @@ export interface AddShapeParams {
|
|
|
17
17
|
verticalAlign?: 'top' | 'middle' | 'bottom';
|
|
18
18
|
strokeColor?: string;
|
|
19
19
|
};
|
|
20
|
+
customData?: Record<string, unknown>;
|
|
20
21
|
}
|
|
21
22
|
export interface AddShapeResponse {
|
|
22
23
|
type: 'addShapeResult';
|
|
@@ -32,6 +33,7 @@ export interface AddTextParams {
|
|
|
32
33
|
fontSize?: number;
|
|
33
34
|
textAlign?: 'left' | 'center' | 'right';
|
|
34
35
|
strokeColor?: string;
|
|
36
|
+
customData?: Record<string, unknown>;
|
|
35
37
|
}
|
|
36
38
|
export interface AddTextResponse {
|
|
37
39
|
type: 'addTextResult';
|
|
@@ -48,6 +50,7 @@ export interface AddLineParams {
|
|
|
48
50
|
strokeColor?: string;
|
|
49
51
|
strokeWidth?: number;
|
|
50
52
|
strokeStyle?: 'solid' | 'dashed' | 'dotted';
|
|
53
|
+
customData?: Record<string, unknown>;
|
|
51
54
|
}
|
|
52
55
|
export interface AddLineResponse {
|
|
53
56
|
type: 'addLineResult';
|
|
@@ -66,6 +69,7 @@ export interface AddArrowParams {
|
|
|
66
69
|
strokeStyle?: 'solid' | 'dashed' | 'dotted';
|
|
67
70
|
startArrowhead?: 'arrow' | 'bar' | 'dot' | 'triangle' | 'diamond' | 'none';
|
|
68
71
|
endArrowhead?: 'arrow' | 'bar' | 'dot' | 'triangle' | 'diamond' | 'none';
|
|
72
|
+
customData?: Record<string, unknown>;
|
|
69
73
|
}
|
|
70
74
|
export interface AddArrowResponse {
|
|
71
75
|
type: 'addArrowResult';
|
|
@@ -84,6 +88,7 @@ export interface AddPolygonParams {
|
|
|
84
88
|
strokeWidth?: number;
|
|
85
89
|
strokeStyle?: 'solid' | 'dashed' | 'dotted';
|
|
86
90
|
fillStyle?: 'hachure' | 'cross-hatch' | 'solid' | 'zigzag';
|
|
91
|
+
customData?: Record<string, unknown>;
|
|
87
92
|
}
|
|
88
93
|
export interface AddPolygonResponse {
|
|
89
94
|
type: 'addPolygonResult';
|
|
@@ -144,6 +149,10 @@ export interface MoveElementsResponse {
|
|
|
144
149
|
movedCount?: number;
|
|
145
150
|
error?: string;
|
|
146
151
|
}
|
|
152
|
+
export interface BoundElement {
|
|
153
|
+
id: string;
|
|
154
|
+
type: 'arrow' | 'text';
|
|
155
|
+
}
|
|
147
156
|
export interface SceneElement {
|
|
148
157
|
id: string;
|
|
149
158
|
type: string;
|
|
@@ -157,9 +166,12 @@ export interface SceneElement {
|
|
|
157
166
|
groupIds?: string[];
|
|
158
167
|
text?: string;
|
|
159
168
|
fontSize?: number;
|
|
169
|
+
containerId?: string | null;
|
|
170
|
+
boundElements?: BoundElement[] | null;
|
|
160
171
|
points?: number[][];
|
|
161
172
|
startArrowhead?: string | null;
|
|
162
173
|
endArrowhead?: string | null;
|
|
174
|
+
customData?: Record<string, unknown>;
|
|
163
175
|
}
|
|
164
176
|
export interface ReadSceneResponse {
|
|
165
177
|
type: 'readSceneResult';
|
package/dist/lib/ws-client.d.ts
CHANGED
package/dist/lib/ws-client.js
CHANGED
|
@@ -65,24 +65,6 @@ export function connectToCanvas(timeout = 5000) {
|
|
|
65
65
|
});
|
|
66
66
|
});
|
|
67
67
|
}
|
|
68
|
-
export function isCanvasRunning() {
|
|
69
|
-
return new Promise((resolve) => {
|
|
70
|
-
const ws = new WebSocket(WS_URL);
|
|
71
|
-
const timer = setTimeout(() => {
|
|
72
|
-
ws.close();
|
|
73
|
-
resolve(false);
|
|
74
|
-
}, 1000);
|
|
75
|
-
ws.on('open', () => {
|
|
76
|
-
clearTimeout(timer);
|
|
77
|
-
ws.close();
|
|
78
|
-
resolve(true);
|
|
79
|
-
});
|
|
80
|
-
ws.on('error', () => {
|
|
81
|
-
clearTimeout(timer);
|
|
82
|
-
resolve(false);
|
|
83
|
-
});
|
|
84
|
-
});
|
|
85
|
-
}
|
|
86
68
|
export function generateId() {
|
|
87
69
|
return Math.random().toString(36).substring(2, 15);
|
|
88
70
|
}
|
package/dist/server/index.d.ts
CHANGED
package/dist/server/index.js
CHANGED
|
@@ -92,6 +92,14 @@ export function startServer() {
|
|
|
92
92
|
ws.send(JSON.stringify({ type: 'pong' }));
|
|
93
93
|
return;
|
|
94
94
|
}
|
|
95
|
+
// Check if browser is connected
|
|
96
|
+
if (message.type === 'isBrowserConnected') {
|
|
97
|
+
ws.send(JSON.stringify({
|
|
98
|
+
type: 'browserStatus',
|
|
99
|
+
connected: browserClient !== null && browserClient.readyState === WebSocket.OPEN,
|
|
100
|
+
}));
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
95
103
|
// If this is from browser (response), forward to CLI client
|
|
96
104
|
if (message.id && pendingRequests.has(message.id)) {
|
|
97
105
|
const cliClient = pendingRequests.get(message.id);
|
|
@@ -160,3 +168,32 @@ export function isBrowserServerRunning() {
|
|
|
160
168
|
});
|
|
161
169
|
});
|
|
162
170
|
}
|
|
171
|
+
export function isBrowserConnected() {
|
|
172
|
+
return new Promise((resolve) => {
|
|
173
|
+
const ws = new WebSocket(`ws://localhost:${WS_PORT}`);
|
|
174
|
+
const timer = setTimeout(() => {
|
|
175
|
+
ws.close();
|
|
176
|
+
resolve(false);
|
|
177
|
+
}, 1000);
|
|
178
|
+
ws.on('open', () => {
|
|
179
|
+
ws.send(JSON.stringify({ type: 'isBrowserConnected' }));
|
|
180
|
+
});
|
|
181
|
+
ws.on('message', (data) => {
|
|
182
|
+
try {
|
|
183
|
+
const msg = JSON.parse(data.toString());
|
|
184
|
+
if (msg.type === 'browserStatus') {
|
|
185
|
+
clearTimeout(timer);
|
|
186
|
+
ws.close();
|
|
187
|
+
resolve(msg.connected);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
catch {
|
|
191
|
+
// ignore
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
ws.on('error', () => {
|
|
195
|
+
clearTimeout(timer);
|
|
196
|
+
resolve(false);
|
|
197
|
+
});
|
|
198
|
+
});
|
|
199
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import"./index-
|
|
1
|
+
import"./index-Dq9tezYn.js";var u={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:""},A={noItems:"لا توجد عناصر أضيفت بعد...",hint_emptyLibrary:"حدد عنصر على القماش لإضافته هنا، أو تثبيت مكتبة من المستودع العام أدناه.",hint_emptyPrivateLibrary:"حدد عنصر على القماش لإضافته هنا."},e={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:"اضغط للتفاعل"},a={clearReset:"هذا سيُزيل كامل اللوحة. هل أنت متأكد؟",couldNotCreateShareableLink:"تعذر إنشاء رابطة المشاركة.",couldNotCreateShareableLinkTooBig:"تعذر إنشاء رابط قابل للمشاركة: المشهد كبير جدًا",couldNotLoadInvalidFile:"تعذر التحميل، الملف غير صالح",importBackendFailed:"فشل الاستيراد من الخادوم.",cannotExportEmptyCanvas:"لا يمكن تصدير لوحة فارغة.",couldNotCopyToClipboard:"تعذر النسخ إلى الحافظة.",decryptFailed:"تعذر فك تشفير البيانات.",uploadedSecurly:"تم تأمين التحميل بتشفير النهاية إلى النهاية، مما يعني أن خادوم Excalidraw والأطراف الثالثة لا يمكنها قراءة المحتوى.",loadSceneOverridePrompt:"تحميل الرسم الخارجي سيحل محل المحتوى الموجود لديك. هل ترغب في المتابعة؟",collabStopOverridePrompt:`إيقاف الجلسة سيؤدي إلى الكتابة فوق رسومك السابقة المخزنة داخليا. هل أنت متأكد؟
|
|
2
2
|
|
|
3
3
|
(إذا كنت ترغب في الاحتفاظ برسمك المخزن داخليا، ببساطة أغلق علامة تبويب المتصفح بدلاً من ذلك.)`,errorAddingToLibrary:"تعذر إضافة العنصر للمكتبة",errorRemovingFromLibrary:"تعذر إزالة العنصر من المكتبة",confirmAddLibrary:"هذا سيضيف {{numShapes}} شكل إلى مكتبتك. هل أنت متأكد؟",imageDoesNotContainScene:"يبدو أن هذه الصورة لا تحتوي على أي بيانات مشهد. هل قمت بتمكين تضمين المشهد أثناء التصدير؟",cannotRestoreFromImage:"تعذر استعادة المشهد من ملف الصورة",invalidSceneUrl:"تعذر استيراد المشهد من عنوان URL المتوفر. إما أنها مشوهة، أو لا تحتوي على بيانات Excalidraw JSON صالحة.",resetLibrary:"هذا سوف يمسح مكتبتك. هل أنت متأكد؟",removeItemsFromsLibrary:"حذف {{count}} عنصر (عناصر) من المكتبة؟",invalidEncryptionKey:"مفتاح التشفير يجب أن يكون من 22 حرفاً. التعاون المباشر معطل.",collabOfflineWarning:`لا يوجد اتصال بالانترنت.
|
|
4
4
|
لن يتم حفظ التغييرات التي قمت بها!`},r={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:""},o={selection:"تحديد",image:"إدراج صورة",rectangle:"مستطيل",diamond:"مضلع",ellipse:"دائرة",arrow:"سهم",line:"خط",freedraw:"رسم",text:"نص",library:"مكتبة",lock:"الحفاظ على أداة التحديد نشطة بعد الرسم",penMode:"وضع القلم - امنع اللمس",link:"إضافة/تحديث الرابط للشكل المحدد",eraser:"ممحاة",frame:"أداة الإطار",magicframe:"",embeddable:"تضمين ويب",laser:"مؤشر ليزر",hand:"يد (أداة الإزاحة)",extraTools:"المزيد من أﻷدوات",mermaidToExcalidraw:"",magicSettings:""},t={canvasActions:"إجراءات اللوحة",selectedShapeActions:"إجراءات الشكل المحدد",shapes:"الأشكال"},i={canvasPanning:"لتحريك القماش، اضغط على عجلة الفأرة أو مفتاح المسافة أثناء السحب، أو استخدم أداة اليد",linearElement:"انقر لبدء نقاط متعددة، اسحب لخط واحد",freeDraw:"انقر واسحب، افرج عند الانتهاء",text:"نصيحة: يمكنك أيضًا إضافة نص بالنقر المزدوج في أي مكان بأداة الاختيار",embeddable:"اضغط مع السحب لإنشاء موقع ويب مضمّن",text_selected:"انقر نقراً مزدوجاً أو اضغط ادخال لتعديل النص",text_editing:"اضغط على Esc أو (Ctrl أو Cmd) + Enter لإنهاء التعديل",linearElementMulti:"انقر فوق النقطة الأخيرة أو اضغط على Esc أو Enter للإنهاء",lockAngle:"يمكنك تقييد الزاوية بالضغط على SHIFT",resize:`يمكنك تقييد النسب بالضغط على SHIFT أثناء تغيير الحجم،
|