@portel/photon 1.14.0 → 1.16.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.
Files changed (125) hide show
  1. package/dist/auto-ui/beam/photon-management.d.ts +1 -1
  2. package/dist/auto-ui/beam/photon-management.d.ts.map +1 -1
  3. package/dist/auto-ui/beam/photon-management.js +5 -1
  4. package/dist/auto-ui/beam/photon-management.js.map +1 -1
  5. package/dist/auto-ui/beam/routes/api-config.d.ts.map +1 -1
  6. package/dist/auto-ui/beam/routes/api-config.js +31 -9
  7. package/dist/auto-ui/beam/routes/api-config.js.map +1 -1
  8. package/dist/auto-ui/beam/routes/api-marketplace.d.ts.map +1 -1
  9. package/dist/auto-ui/beam/routes/api-marketplace.js +3 -0
  10. package/dist/auto-ui/beam/routes/api-marketplace.js.map +1 -1
  11. package/dist/auto-ui/beam.d.ts.map +1 -1
  12. package/dist/auto-ui/beam.js +205 -56
  13. package/dist/auto-ui/beam.js.map +1 -1
  14. package/dist/auto-ui/bridge/index.d.ts.map +1 -1
  15. package/dist/auto-ui/bridge/index.js +578 -0
  16. package/dist/auto-ui/bridge/index.js.map +1 -1
  17. package/dist/auto-ui/bridge/renderers.d.ts.map +1 -1
  18. package/dist/auto-ui/bridge/renderers.js +7 -3
  19. package/dist/auto-ui/bridge/renderers.js.map +1 -1
  20. package/dist/auto-ui/bridge/types.d.ts +6 -0
  21. package/dist/auto-ui/bridge/types.d.ts.map +1 -1
  22. package/dist/auto-ui/frontend/pure-view.html +289 -0
  23. package/dist/auto-ui/photon-bridge.d.ts +11 -0
  24. package/dist/auto-ui/photon-bridge.d.ts.map +1 -1
  25. package/dist/auto-ui/photon-bridge.js +75 -1
  26. package/dist/auto-ui/photon-bridge.js.map +1 -1
  27. package/dist/auto-ui/streamable-http-transport.d.ts.map +1 -1
  28. package/dist/auto-ui/streamable-http-transport.js +29 -3
  29. package/dist/auto-ui/streamable-http-transport.js.map +1 -1
  30. package/dist/beam-form.bundle.js +5707 -0
  31. package/dist/beam-form.bundle.js.map +7 -0
  32. package/dist/beam.bundle.js +2863 -895
  33. package/dist/beam.bundle.js.map +4 -4
  34. package/dist/claude-code-plugin.js +11 -3
  35. package/dist/claude-code-plugin.js.map +1 -1
  36. package/dist/cli/commands/build.js +1 -1
  37. package/dist/cli/commands/build.js.map +1 -1
  38. package/dist/cli/commands/doctor.d.ts.map +1 -1
  39. package/dist/cli/commands/doctor.js +7 -5
  40. package/dist/cli/commands/doctor.js.map +1 -1
  41. package/dist/cli/commands/info.d.ts.map +1 -1
  42. package/dist/cli/commands/info.js +18 -4
  43. package/dist/cli/commands/info.js.map +1 -1
  44. package/dist/cli/commands/mcp.js +2 -2
  45. package/dist/cli/commands/mcp.js.map +1 -1
  46. package/dist/cli/commands/update.d.ts.map +1 -1
  47. package/dist/cli/commands/update.js +6 -2
  48. package/dist/cli/commands/update.js.map +1 -1
  49. package/dist/cli-alias.d.ts.map +1 -1
  50. package/dist/cli-alias.js +3 -2
  51. package/dist/cli-alias.js.map +1 -1
  52. package/dist/daemon/client.d.ts +5 -0
  53. package/dist/daemon/client.d.ts.map +1 -1
  54. package/dist/daemon/client.js +50 -0
  55. package/dist/daemon/client.js.map +1 -1
  56. package/dist/daemon/manager.d.ts +15 -0
  57. package/dist/daemon/manager.d.ts.map +1 -1
  58. package/dist/daemon/manager.js +142 -11
  59. package/dist/daemon/manager.js.map +1 -1
  60. package/dist/daemon/worker-manager.js +1 -1
  61. package/dist/daemon/worker-manager.js.map +1 -1
  62. package/dist/deploy/cloudflare.d.ts.map +1 -1
  63. package/dist/deploy/cloudflare.js +12 -10
  64. package/dist/deploy/cloudflare.js.map +1 -1
  65. package/dist/loader.d.ts.map +1 -1
  66. package/dist/loader.js +37 -2
  67. package/dist/loader.js.map +1 -1
  68. package/dist/marketplace-manager.d.ts +9 -0
  69. package/dist/marketplace-manager.d.ts.map +1 -1
  70. package/dist/marketplace-manager.js +115 -42
  71. package/dist/marketplace-manager.js.map +1 -1
  72. package/dist/meta.d.ts +51 -0
  73. package/dist/meta.d.ts.map +1 -0
  74. package/dist/meta.js +320 -0
  75. package/dist/meta.js.map +1 -0
  76. package/dist/photon-cli-runner.d.ts.map +1 -1
  77. package/dist/photon-cli-runner.js +30 -5
  78. package/dist/photon-cli-runner.js.map +1 -1
  79. package/dist/photon-doc-extractor.d.ts +1 -0
  80. package/dist/photon-doc-extractor.d.ts.map +1 -1
  81. package/dist/photon-doc-extractor.js +33 -21
  82. package/dist/photon-doc-extractor.js.map +1 -1
  83. package/dist/photons/builder-compass.photon.d.ts +167 -0
  84. package/dist/photons/builder-compass.photon.d.ts.map +1 -0
  85. package/dist/photons/builder-compass.photon.js +816 -0
  86. package/dist/photons/builder-compass.photon.js.map +1 -0
  87. package/dist/photons/builder-compass.photon.ts +1129 -0
  88. package/dist/photons/docs/ui/docs.html +441 -0
  89. package/dist/photons/docs.photon.d.ts +237 -0
  90. package/dist/photons/docs.photon.d.ts.map +1 -0
  91. package/dist/photons/docs.photon.js +483 -0
  92. package/dist/photons/docs.photon.js.map +1 -0
  93. package/dist/photons/docs.photon.ts +536 -0
  94. package/dist/photons/maker.photon.d.ts.map +1 -1
  95. package/dist/photons/maker.photon.js +19 -2
  96. package/dist/photons/maker.photon.js.map +1 -1
  97. package/dist/photons/maker.photon.ts +18 -2
  98. package/dist/photons/slides.photon.d.ts +212 -0
  99. package/dist/photons/slides.photon.d.ts.map +1 -0
  100. package/dist/photons/slides.photon.js +355 -0
  101. package/dist/photons/slides.photon.js.map +1 -0
  102. package/dist/photons/slides.photon.ts +370 -0
  103. package/dist/photons/spreadsheet/ui/spreadsheet.html +779 -0
  104. package/dist/photons/spreadsheet.photon.d.ts +554 -0
  105. package/dist/photons/spreadsheet.photon.d.ts.map +1 -0
  106. package/dist/photons/spreadsheet.photon.js +1050 -0
  107. package/dist/photons/spreadsheet.photon.js.map +1 -0
  108. package/dist/photons/spreadsheet.photon.ts +1239 -0
  109. package/dist/photons/ui/builder-compass.html +1199 -0
  110. package/dist/photons/ui/builder-compass.photon.html +380 -0
  111. package/dist/server.d.ts.map +1 -1
  112. package/dist/server.js +33 -59
  113. package/dist/server.js.map +1 -1
  114. package/dist/shared/error-handler.d.ts +8 -0
  115. package/dist/shared/error-handler.d.ts.map +1 -1
  116. package/dist/shared/error-handler.js +50 -0
  117. package/dist/shared/error-handler.js.map +1 -1
  118. package/dist/shared-utils.d.ts +16 -2
  119. package/dist/shared-utils.d.ts.map +1 -1
  120. package/dist/shared-utils.js +37 -3
  121. package/dist/shared-utils.js.map +1 -1
  122. package/dist/template-manager.d.ts.map +1 -1
  123. package/dist/template-manager.js +2 -1
  124. package/dist/template-manager.js.map +1 -1
  125. package/package.json +8 -3
@@ -0,0 +1,441 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Docs</title>
7
+ <style>
8
+ :root {
9
+ --bg: #0a0e1a;
10
+ --surface: rgba(15, 20, 35, 0.95);
11
+ --line: rgba(255,255,255,0.08);
12
+ --text: #e5e5e5;
13
+ --muted: rgba(255,255,255,0.4);
14
+ --accent: #67c7ff;
15
+ --page-bg: #ffffff;
16
+ --page-text: #1a1a2e;
17
+ --page-shadow: 0 2px 20px rgba(0,0,0,0.4);
18
+ --spring: cubic-bezier(0.16, 1, 0.3, 1);
19
+ }
20
+
21
+ * { box-sizing: border-box; margin: 0; }
22
+
23
+ body {
24
+ background: var(--bg);
25
+ color: var(--text);
26
+ font-family: system-ui, -apple-system, sans-serif;
27
+ height: 100vh;
28
+ display: grid;
29
+ grid-template-columns: 240px 1fr;
30
+ grid-template-rows: auto 1fr;
31
+ overflow: hidden;
32
+ }
33
+
34
+ /* ── Top Bar ── */
35
+
36
+ .topbar {
37
+ grid-column: 1 / -1;
38
+ display: flex;
39
+ align-items: center;
40
+ gap: 12px;
41
+ padding: 10px 20px;
42
+ border-bottom: 1px solid var(--line);
43
+ background: var(--surface);
44
+ font-size: 13px;
45
+ }
46
+
47
+ .topbar .title {
48
+ font-weight: 600;
49
+ flex: 1;
50
+ white-space: nowrap;
51
+ overflow: hidden;
52
+ text-overflow: ellipsis;
53
+ }
54
+
55
+ .topbar .stats {
56
+ color: var(--muted);
57
+ font-size: 12px;
58
+ white-space: nowrap;
59
+ }
60
+
61
+ .topbar button {
62
+ background: rgba(255,255,255,0.06);
63
+ border: 1px solid var(--line);
64
+ color: var(--text);
65
+ padding: 6px 14px;
66
+ border-radius: 6px;
67
+ cursor: pointer;
68
+ font-size: 12px;
69
+ transition: background 0.15s;
70
+ }
71
+
72
+ .topbar button:hover { background: rgba(255,255,255,0.12); }
73
+ .topbar button.primary { background: rgba(103,199,255,0.15); border-color: rgba(103,199,255,0.3); }
74
+
75
+ /* ── Sidebar (Outline) ── */
76
+
77
+ .sidebar {
78
+ background: var(--surface);
79
+ border-right: 1px solid var(--line);
80
+ padding: 16px;
81
+ overflow-y: auto;
82
+ display: flex;
83
+ flex-direction: column;
84
+ gap: 8px;
85
+ }
86
+
87
+ .sidebar-label {
88
+ font-size: 10px;
89
+ text-transform: uppercase;
90
+ letter-spacing: 0.12em;
91
+ color: var(--muted);
92
+ margin-bottom: 4px;
93
+ }
94
+
95
+ .outline-item {
96
+ display: block;
97
+ width: 100%;
98
+ text-align: left;
99
+ background: none;
100
+ border: none;
101
+ color: var(--text);
102
+ padding: 6px 8px;
103
+ border-radius: 6px;
104
+ cursor: pointer;
105
+ font-size: 13px;
106
+ transition: background 0.15s;
107
+ white-space: nowrap;
108
+ overflow: hidden;
109
+ text-overflow: ellipsis;
110
+ }
111
+
112
+ .outline-item:hover { background: rgba(255,255,255,0.06); }
113
+ .outline-item.h2 { padding-left: 20px; font-size: 12px; }
114
+ .outline-item.h3 { padding-left: 36px; font-size: 11px; color: var(--muted); }
115
+
116
+ .doc-list {
117
+ margin-top: 12px;
118
+ display: flex;
119
+ flex-direction: column;
120
+ gap: 4px;
121
+ }
122
+
123
+ .doc-item {
124
+ display: block;
125
+ width: 100%;
126
+ text-align: left;
127
+ background: none;
128
+ border: none;
129
+ color: var(--muted);
130
+ padding: 6px 8px;
131
+ border-radius: 6px;
132
+ cursor: pointer;
133
+ font-size: 12px;
134
+ transition: background 0.15s;
135
+ }
136
+
137
+ .doc-item:hover { background: rgba(255,255,255,0.06); color: var(--text); }
138
+ .doc-item.active { background: rgba(103,199,255,0.1); color: var(--accent); }
139
+
140
+ /* ── Main Editor Area ── */
141
+
142
+ .editor-area {
143
+ display: grid;
144
+ grid-template-columns: 1fr 1fr;
145
+ gap: 0;
146
+ overflow: hidden;
147
+ }
148
+
149
+ .editor-pane {
150
+ display: flex;
151
+ flex-direction: column;
152
+ border-right: 1px solid var(--line);
153
+ overflow: hidden;
154
+ }
155
+
156
+ .pane-header {
157
+ padding: 8px 16px;
158
+ font-size: 11px;
159
+ text-transform: uppercase;
160
+ letter-spacing: 0.1em;
161
+ color: var(--muted);
162
+ border-bottom: 1px solid var(--line);
163
+ background: rgba(255,255,255,0.02);
164
+ flex-shrink: 0;
165
+ }
166
+
167
+ textarea {
168
+ flex: 1;
169
+ width: 100%;
170
+ border: none;
171
+ outline: none;
172
+ resize: none;
173
+ background: rgba(6, 10, 20, 0.9);
174
+ color: var(--text);
175
+ padding: 20px 24px;
176
+ font-family: 'JetBrains Mono', ui-monospace, monospace;
177
+ font-size: 13px;
178
+ line-height: 1.7;
179
+ tab-size: 2;
180
+ }
181
+
182
+ /* ── Preview Pane ── */
183
+
184
+ .preview-pane {
185
+ overflow-y: auto;
186
+ background: #1a1e2e;
187
+ padding: 32px;
188
+ display: flex;
189
+ flex-direction: column;
190
+ align-items: center;
191
+ gap: 24px;
192
+ }
193
+
194
+ .page {
195
+ width: 210mm;
196
+ max-width: 100%;
197
+ min-height: 297mm;
198
+ background: var(--page-bg);
199
+ color: var(--page-text);
200
+ box-shadow: var(--page-shadow);
201
+ border-radius: 4px;
202
+ padding: 60px 50px;
203
+ font-family: 'Inter', 'Georgia', serif;
204
+ font-size: 11pt;
205
+ line-height: 1.7;
206
+ animation: page-fade-in 0.3s ease-out both;
207
+ }
208
+
209
+ @keyframes page-fade-in {
210
+ from { opacity: 0; transform: translateY(8px); }
211
+ to { opacity: 1; transform: translateY(0); }
212
+ }
213
+
214
+ .page h1 { font-size: 2em; margin: 0 0 0.5em; color: #111; font-weight: 700; }
215
+ .page h2 { font-size: 1.5em; margin: 1.2em 0 0.4em; color: #222; font-weight: 600; border-bottom: 1px solid #e5e5e5; padding-bottom: 0.3em; }
216
+ .page h3 { font-size: 1.2em; margin: 1em 0 0.3em; color: #333; }
217
+ .page p { margin: 0.6em 0; }
218
+ .page ul, .page ol { margin: 0.6em 0; padding-left: 1.8em; }
219
+ .page li { margin: 0.3em 0; }
220
+ .page code { background: #f0f0f0; padding: 2px 6px; border-radius: 3px; font-size: 0.9em; font-family: 'JetBrains Mono', monospace; }
221
+ .page pre { background: #f5f5f5; padding: 16px; border-radius: 6px; overflow-x: auto; margin: 0.8em 0; }
222
+ .page pre code { background: none; padding: 0; }
223
+ .page blockquote { border-left: 3px solid #ccc; padding-left: 16px; margin: 0.8em 0; color: #555; }
224
+ .page img { max-width: 100%; border-radius: 4px; }
225
+ .page table { border-collapse: collapse; width: 100%; margin: 0.8em 0; }
226
+ .page th, .page td { border: 1px solid #ddd; padding: 8px 12px; text-align: left; }
227
+ .page th { background: #f8f8f8; font-weight: 600; }
228
+ .page hr { border: none; border-top: 1px solid #e5e5e5; margin: 2em 0; }
229
+
230
+ /* Callout containers */
231
+ .page .callout { padding: 16px 20px; border-radius: 6px; margin: 1em 0; border-left: 4px solid; }
232
+ .page .callout-note { background: #eff6ff; border-color: #3b82f6; }
233
+ .page .callout-warning { background: #fffbeb; border-color: #f59e0b; }
234
+ .page .callout-tip { background: #f0fdf4; border-color: #22c55e; }
235
+ .page .callout-title { font-weight: 600; margin-bottom: 4px; }
236
+
237
+ /* Footnotes */
238
+ .page .footnote { font-size: 0.85em; color: #666; border-top: 1px solid #e5e5e5; padding-top: 8px; margin-top: 2em; }
239
+
240
+ /* Page break indicator */
241
+ .page-break-indicator {
242
+ width: 100%;
243
+ text-align: center;
244
+ color: var(--muted);
245
+ font-size: 11px;
246
+ padding: 4px 0;
247
+ }
248
+
249
+ @media (max-width: 1200px) {
250
+ body { grid-template-columns: 1fr; }
251
+ .sidebar { display: none; }
252
+ .editor-area { grid-template-columns: 1fr; }
253
+ .preview-pane { display: none; }
254
+ }
255
+ </style>
256
+ </head>
257
+ <body>
258
+ <div class="topbar">
259
+ <span class="title" id="doc-title">Untitled Document</span>
260
+ <span class="stats" id="doc-stats"></span>
261
+ <button class="primary" id="save-btn">Save</button>
262
+ </div>
263
+
264
+ <aside class="sidebar">
265
+ <div class="sidebar-label">Outline</div>
266
+ <div id="outline"></div>
267
+ <div class="sidebar-label" style="margin-top:16px;">Documents</div>
268
+ <div class="doc-list" id="doc-list"></div>
269
+ </aside>
270
+
271
+ <div class="editor-area">
272
+ <div class="editor-pane">
273
+ <div class="pane-header">Markdown</div>
274
+ <textarea id="editor" spellcheck="false"></textarea>
275
+ </div>
276
+ <div class="preview-pane" id="preview"></div>
277
+ </div>
278
+
279
+ <script>
280
+ const docsApp = window["docs"];
281
+ let state = { markdown: '', frontmatter: {}, outline: [], stats: {} };
282
+
283
+ function parseMCP(raw) {
284
+ if (raw && raw.content && Array.isArray(raw.content)) {
285
+ const item = raw.content.find(c => c.type === "text" && c.text);
286
+ if (item) { try { return JSON.parse(item.text); } catch { return item.text; } }
287
+ }
288
+ return raw;
289
+ }
290
+
291
+ function renderPreview(markdown) {
292
+ const preview = document.getElementById("preview");
293
+ // Split on page breaks
294
+ const { body } = splitFrontmatter(markdown);
295
+ const pages = body.split(/---pagebreak---/);
296
+
297
+ preview.innerHTML = pages.map((pageContent, i) => {
298
+ const html = renderMarkdown(pageContent.trim());
299
+ return `<div class="page">${html}</div>` +
300
+ (i < pages.length - 1 ? '<div class="page-break-indicator">--- page break ---</div>' : '');
301
+ }).join('');
302
+ }
303
+
304
+ function splitFrontmatter(md) {
305
+ const match = md.match(/^---\n[\s\S]*?\n---\n?/);
306
+ return { frontmatter: match ? match[0] : '', body: match ? md.slice(match[0].length) : md };
307
+ }
308
+
309
+ function renderMarkdown(text) {
310
+ // Simple markdown renderer — handles common elements
311
+ let html = text
312
+ // Code blocks
313
+ .replace(/```(\w*)\n([\s\S]*?)```/g, '<pre><code>$2</code></pre>')
314
+ // Callout containers
315
+ .replace(/::: (note|warning|tip)\n([\s\S]*?):::/g, (_, type, content) =>
316
+ `<div class="callout callout-${type}"><div class="callout-title">${type.charAt(0).toUpperCase() + type.slice(1)}</div>${renderInline(content.trim())}</div>`)
317
+ // Headings
318
+ .replace(/^### (.+)$/gm, '<h3>$1</h3>')
319
+ .replace(/^## (.+)$/gm, '<h2>$1</h2>')
320
+ .replace(/^# (.+)$/gm, '<h1>$1</h1>')
321
+ // Horizontal rules
322
+ .replace(/^---$/gm, '<hr>')
323
+ // Blockquotes
324
+ .replace(/^> (.+)$/gm, '<blockquote>$1</blockquote>')
325
+ // Unordered lists
326
+ .replace(/^- (.+)$/gm, '<li>$1</li>')
327
+ // Ordered lists
328
+ .replace(/^\d+\. (.+)$/gm, '<li>$1</li>')
329
+ // Footnotes
330
+ .replace(/\[\^(\d+)\]:\s*(.+)$/gm, '<div class="footnote"><sup>$1</sup> $2</div>')
331
+ .replace(/\[\^(\d+)\]/g, '<sup>$1</sup>')
332
+ // Paragraphs
333
+ .replace(/\n\n+/g, '</p><p>')
334
+ // Wrap lists
335
+ .replace(/(<li>[\s\S]*?<\/li>)/g, '<ul>$1</ul>')
336
+ // Clean up double-wrapped lists
337
+ .replace(/<\/ul>\s*<ul>/g, '');
338
+
339
+ html = renderInline(html);
340
+ return `<p>${html}</p>`.replace(/<p><\/p>/g, '').replace(/<p>(<h[1-6])/g, '$1').replace(/(<\/h[1-6]>)<\/p>/g, '$1');
341
+ }
342
+
343
+ function renderInline(text) {
344
+ return text
345
+ .replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>')
346
+ .replace(/\*(.+?)\*/g, '<em>$1</em>')
347
+ .replace(/`(.+?)`/g, '<code>$1</code>')
348
+ .replace(/\[(.+?)\]\((.+?)\)/g, '<a href="$2">$1</a>');
349
+ }
350
+
351
+ function renderOutline(outline) {
352
+ const el = document.getElementById("outline");
353
+ if (!outline || !outline.length) { el.innerHTML = '<span style="color:var(--muted);font-size:12px;">No headings</span>'; return; }
354
+ el.innerHTML = outline.map(h =>
355
+ `<button class="outline-item h${h.level}" data-line="${h.line}">${h.text}</button>`
356
+ ).join('');
357
+ el.querySelectorAll("[data-line]").forEach(btn => {
358
+ btn.addEventListener("click", () => {
359
+ const editor = document.getElementById("editor");
360
+ const lines = editor.value.split('\n');
361
+ let charPos = 0;
362
+ for (let i = 0; i < parseInt(btn.dataset.line) - 1 && i < lines.length; i++) {
363
+ charPos += lines[i].length + 1;
364
+ }
365
+ editor.focus();
366
+ editor.setSelectionRange(charPos, charPos);
367
+ });
368
+ });
369
+ }
370
+
371
+ function updateUI(data) {
372
+ if (!data || data.error) return;
373
+ state = data;
374
+ const fm = data.frontmatter || {};
375
+ document.getElementById("doc-title").textContent = fm.title || data.file || 'Untitled';
376
+ document.getElementById("editor").value = data.markdown || '';
377
+ const s = data.stats || {};
378
+ document.getElementById("doc-stats").textContent =
379
+ `${s.words || 0} words · ${s.readingTime || 1} min read · ${s.headings || 0} sections`;
380
+ renderOutline(data.outline);
381
+ renderPreview(data.markdown || '');
382
+ }
383
+
384
+ // ── Event Handlers ──
385
+
386
+ document.getElementById("save-btn").addEventListener("click", async () => {
387
+ const markdown = document.getElementById("editor").value;
388
+ if (docsApp) {
389
+ const result = parseMCP(await docsApp.save({ markdown }));
390
+ updateUI(result);
391
+ }
392
+ });
393
+
394
+ // Live preview on typing (debounced)
395
+ let previewTimeout;
396
+ document.getElementById("editor").addEventListener("input", () => {
397
+ clearTimeout(previewTimeout);
398
+ previewTimeout = setTimeout(() => {
399
+ renderPreview(document.getElementById("editor").value);
400
+ }, 300);
401
+ });
402
+
403
+ // Keyboard shortcut: Cmd/Ctrl+S to save
404
+ document.addEventListener("keydown", (e) => {
405
+ if ((e.metaKey || e.ctrlKey) && e.key === "s") {
406
+ e.preventDefault();
407
+ document.getElementById("save-btn").click();
408
+ }
409
+ });
410
+
411
+ // ── Bridge ──
412
+
413
+ if (docsApp) {
414
+ window.photon?.onResult?.((result) => {
415
+ const data = parseMCP(result);
416
+ if (data && data.markdown) updateUI(data);
417
+ });
418
+
419
+ window.photon?.onEmit?.((event) => {
420
+ if (event?.event === "docChanged") {
421
+ docsApp.main().then(r => updateUI(parseMCP(r)));
422
+ }
423
+ });
424
+
425
+ // Load doc list
426
+ docsApp.list().then(r => {
427
+ const data = parseMCP(r);
428
+ if (data && data.docs) {
429
+ const list = document.getElementById("doc-list");
430
+ list.innerHTML = data.docs.map(d =>
431
+ `<button class="doc-item" data-file="${d.file}">${d.title || d.file}</button>`
432
+ ).join('');
433
+ }
434
+ });
435
+
436
+ // Initial load
437
+ docsApp.main().then(r => updateUI(parseMCP(r)));
438
+ }
439
+ </script>
440
+ </body>
441
+ </html>
@@ -0,0 +1,237 @@
1
+ export default class Docs {
2
+ protected settings: {
3
+ /** @property Directory where document files are stored */
4
+ folder: string;
5
+ };
6
+ memory: {
7
+ get<T>(key: string): Promise<T | null>;
8
+ set(key: string, value: unknown): Promise<void>;
9
+ };
10
+ emit: (payload: {
11
+ event: string;
12
+ data: unknown;
13
+ }) => void;
14
+ instanceName: string;
15
+ private get defaultFolder();
16
+ private get docPath();
17
+ onInitialize(): Promise<void>;
18
+ /**
19
+ * Open the document editor UI
20
+ * @ui editor
21
+ * @autorun
22
+ */
23
+ main(): Promise<{
24
+ file: string;
25
+ markdown: string;
26
+ frontmatter: Record<string, any>;
27
+ outline: HeadingEntry[];
28
+ stats: {
29
+ words: number;
30
+ chars: number;
31
+ paragraphs: number;
32
+ headings: number;
33
+ readingTime: number;
34
+ sections: {
35
+ heading: string;
36
+ level: number;
37
+ words: number;
38
+ }[];
39
+ };
40
+ }>;
41
+ /**
42
+ * Read the document markdown
43
+ * @readOnly
44
+ */
45
+ read(): Promise<{
46
+ file: string;
47
+ markdown: string;
48
+ }>;
49
+ /**
50
+ * Save the full document markdown
51
+ * @param markdown Full markdown content with YAML frontmatter
52
+ * @ui editor
53
+ */
54
+ save({ markdown }: {
55
+ markdown: string;
56
+ }): Promise<{
57
+ file: string;
58
+ markdown: string;
59
+ frontmatter: Record<string, any>;
60
+ outline: HeadingEntry[];
61
+ stats: {
62
+ words: number;
63
+ chars: number;
64
+ paragraphs: number;
65
+ headings: number;
66
+ readingTime: number;
67
+ sections: {
68
+ heading: string;
69
+ level: number;
70
+ words: number;
71
+ }[];
72
+ };
73
+ }>;
74
+ /**
75
+ * Get the document's heading structure for navigation
76
+ * @readOnly
77
+ */
78
+ outline(): Promise<{
79
+ outline: HeadingEntry[];
80
+ }>;
81
+ /**
82
+ * Edit a specific section by heading path
83
+ * @param section Heading text or path like "Chapter 3/Introduction"
84
+ * @param markdown New content for that section (everything under the heading until next same-level heading)
85
+ * @ui editor
86
+ */
87
+ edit({ section, markdown: newContent }: {
88
+ section: string;
89
+ markdown: string;
90
+ }): Promise<{
91
+ file: string;
92
+ markdown: string;
93
+ frontmatter: Record<string, any>;
94
+ outline: HeadingEntry[];
95
+ stats: {
96
+ words: number;
97
+ chars: number;
98
+ paragraphs: number;
99
+ headings: number;
100
+ readingTime: number;
101
+ sections: {
102
+ heading: string;
103
+ level: number;
104
+ words: number;
105
+ }[];
106
+ };
107
+ } | {
108
+ error: string;
109
+ }>;
110
+ /**
111
+ * Append content at the end of the document or after a specific section
112
+ * @param markdown Content to append
113
+ * @param after Optional heading text — inserts after that section instead of end
114
+ * @ui editor
115
+ */
116
+ append({ markdown: content, after }: {
117
+ markdown: string;
118
+ after?: string;
119
+ }): Promise<{
120
+ file: string;
121
+ markdown: string;
122
+ frontmatter: Record<string, any>;
123
+ outline: HeadingEntry[];
124
+ stats: {
125
+ words: number;
126
+ chars: number;
127
+ paragraphs: number;
128
+ headings: number;
129
+ readingTime: number;
130
+ sections: {
131
+ heading: string;
132
+ level: number;
133
+ words: number;
134
+ }[];
135
+ };
136
+ }>;
137
+ /**
138
+ * Find text in the document with optional fuzzy matching
139
+ * @param query Search text
140
+ * @param fuzzy Enable fuzzy matching {@default false}
141
+ * @param scope Limit search to a section heading
142
+ * @readOnly
143
+ */
144
+ find({ query, fuzzy, scope }: {
145
+ query: string;
146
+ fuzzy?: boolean;
147
+ scope?: string;
148
+ }): Promise<{
149
+ query: string;
150
+ fuzzy: boolean;
151
+ scope: string | null;
152
+ matches: {
153
+ line: number;
154
+ text: string;
155
+ context: string;
156
+ }[];
157
+ total: number;
158
+ }>;
159
+ /**
160
+ * Find and replace text in the document
161
+ * @param pattern Text to find (string or regex pattern)
162
+ * @param replacement Replacement text
163
+ * @param scope Limit to a section heading
164
+ * @param all Replace all occurrences {@default true}
165
+ * @ui editor
166
+ */
167
+ replace({ pattern, replacement, scope, all, }: {
168
+ pattern: string;
169
+ replacement: string;
170
+ scope?: string;
171
+ all?: boolean;
172
+ }): Promise<{
173
+ file: string;
174
+ markdown: string;
175
+ frontmatter: Record<string, any>;
176
+ outline: HeadingEntry[];
177
+ stats: {
178
+ words: number;
179
+ chars: number;
180
+ paragraphs: number;
181
+ headings: number;
182
+ readingTime: number;
183
+ sections: {
184
+ heading: string;
185
+ level: number;
186
+ words: number;
187
+ }[];
188
+ };
189
+ replacements: number;
190
+ }>;
191
+ /**
192
+ * List saved documents in the docs folder
193
+ * @readOnly
194
+ */
195
+ list(): Promise<{
196
+ folder: string;
197
+ docs: {
198
+ file: string;
199
+ title: any;
200
+ author: any;
201
+ updatedAt: string;
202
+ wordCount: number;
203
+ }[];
204
+ }>;
205
+ /**
206
+ * Generate table of contents from the document structure
207
+ * @readOnly
208
+ */
209
+ toc(): Promise<{
210
+ outline: HeadingEntry[];
211
+ markdown: string;
212
+ }>;
213
+ /**
214
+ * Document statistics: word count, reading time, section breakdown
215
+ * @readOnly
216
+ */
217
+ stats(): Promise<{
218
+ words: number;
219
+ chars: number;
220
+ paragraphs: number;
221
+ headings: number;
222
+ readingTime: number;
223
+ sections: {
224
+ heading: string;
225
+ level: number;
226
+ words: number;
227
+ }[];
228
+ }>;
229
+ private readDoc;
230
+ }
231
+ interface HeadingEntry {
232
+ level: number;
233
+ text: string;
234
+ line: number;
235
+ }
236
+ export {};
237
+ //# sourceMappingURL=docs.photon.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"docs.photon.d.ts","sourceRoot":"","sources":["../../src/photons/docs.photon.ts"],"names":[],"mappings":"AA4DA,MAAM,CAAC,OAAO,OAAO,IAAI;IACvB,SAAS,CAAC,QAAQ;QAChB,0DAA0D;;MAE1D;IAEM,MAAM,EAAE;QACd,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;QACvC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;KACjD,CAAC;IACM,IAAI,EAAE,CAAC,OAAO,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,OAAO,CAAA;KAAE,KAAK,IAAI,CAAC;IAC1D,YAAY,EAAE,MAAM,CAAC;IAI7B,OAAO,KAAK,aAAa,GAExB;IAED,OAAO,KAAK,OAAO,GAUlB;IAEK,YAAY;IAUlB;;;;OAIG;IACG,IAAI;;;;;;;;;;;;;;;;;;IAaV;;;OAGG;IACG,IAAI;;;;IAIV;;;;OAIG;IACG,IAAI,CAAC,EAAE,QAAQ,EAAE,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAA;KAAE;;;;;;;;;;;;;;;;;;IAgB7C;;;OAGG;IACG,OAAO;;;IAKb;;;;;OAKG;IACG,IAAI,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE;;;;;;;;;;;;;;;;;;;;IAmBnF;;;;;OAKG;IACG,MAAM,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE;;;;;;;;;;;;;;;;;;IAyB/E;;;;;;OAMG;IACG,IAAI,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE;;;;;kBAM7D,MAAM;kBAAQ,MAAM;qBAAW,MAAM;;;;IAe9D;;;;;;;OAOG;IACG,OAAO,CAAC,EACZ,OAAO,EACP,WAAW,EACX,KAAK,EACL,GAAG,GACJ,EAAE;QACD,OAAO,EAAE,MAAM,CAAC;QAChB,WAAW,EAAE,MAAM,CAAC;QACpB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,GAAG,CAAC,EAAE,OAAO,CAAC;KACf;;;;;;;;;;;;;;;;;;;IAqCD;;;OAGG;IACG,IAAI;;;;;;;;;;IAwBV;;;OAGG;IACG,GAAG;;;;IAOT;;;OAGG;IACG,KAAK;;;;;;;;;;;;YAOG,OAAO;CAOtB;AA8CD,UAAU,YAAY;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd"}