minecodex 2.0.11 → 2.0.13

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 (60) hide show
  1. package/README.md +12 -0
  2. package/apps/dashboard/app.js +37 -4
  3. package/apps/dashboard/assets/data-transfer.js +129 -0
  4. package/apps/dashboard/assets/download.svg +15 -0
  5. package/apps/dashboard/assets/upload.svg +15 -0
  6. package/apps/dashboard/index.html +10 -0
  7. package/apps/dashboard/styles.css +52 -1
  8. package/features/file-navigation/assets/book-open.svg +16 -0
  9. package/features/file-navigation/codex-feature.json +27 -0
  10. package/features/file-navigation/src/adapters/codex/modules.mjs +67 -0
  11. package/features/file-navigation/src/adapters/codex/navigation.mjs +84 -0
  12. package/features/file-navigation/src/domain/navigation.mjs +12 -0
  13. package/features/file-navigation/src/entry.mjs +34 -0
  14. package/features/file-navigation/src/frontend/navigation.mjs +140 -0
  15. package/features/file-navigation/src/injection-source.mjs +9 -0
  16. package/features/file-navigation/src/navigation.css +16 -0
  17. package/features/file-navigation/vendor/lucide-LICENSE +43 -0
  18. package/features/markdown-reading/assets/book-open.svg +16 -0
  19. package/features/markdown-reading/codex-feature.json +27 -0
  20. package/features/markdown-reading/src/adapters/codex/links.mjs +280 -0
  21. package/features/markdown-reading/src/adapters/codex/lists.mjs +168 -0
  22. package/features/markdown-reading/src/adapters/codex/markdown-native.mjs +28 -0
  23. package/features/markdown-reading/src/adapters/codex/preview.mjs +38 -0
  24. package/features/markdown-reading/src/adapters/codex/providers.mjs +18 -0
  25. package/features/markdown-reading/src/adapters/codex/reading-runtime.mjs +152 -0
  26. package/features/markdown-reading/src/adapters/codex/rich-text.mjs +561 -0
  27. package/features/markdown-reading/src/adapters/codex/table-actions.mjs +270 -0
  28. package/features/markdown-reading/src/adapters/codex/tables.mjs +493 -0
  29. package/features/markdown-reading/src/adapters/codex/toc-native.mjs +131 -0
  30. package/features/markdown-reading/src/adapters/codex/toc.mjs +334 -0
  31. package/features/markdown-reading/src/domain/footnotes.mjs +56 -0
  32. package/features/markdown-reading/src/injection-source.mjs +43 -0
  33. package/features/markdown-reading/src/markdown-reading.mjs +82 -0
  34. package/features/markdown-reading/src/reading.css +346 -0
  35. package/features/markdown-reading/vendor/lucide-LICENSE +43 -0
  36. package/features/model-slider/codex-feature.json +1 -0
  37. package/features/model-slider/src/adapters/codex/controller.mjs +7 -5
  38. package/features/model-slider/src/backend/favorites.mjs +54 -0
  39. package/features/model-slider/src/domain/model-rules.mjs +6 -1
  40. package/features/model-slider/src/frontend/install.mjs +41 -18
  41. package/features/notes/assets/prompt-previews.json +26 -0
  42. package/features/notes/codex-feature.json +2 -1
  43. package/features/notes/src/backend/transfer.mjs +97 -0
  44. package/features/notes/src/frontend/entry.mjs +380 -10
  45. package/features/notes/src/frontend/icons.json +4 -1
  46. package/features/notes/src/frontend/styles.css +63 -0
  47. package/features/session-status/src/domain/session-stats.mjs +22 -8
  48. package/features/session-status/src/session-status.mjs +2 -2
  49. package/features/sites/src/backend/sites-service.mjs +20 -5
  50. package/features/sites/src/backend/transfer.mjs +43 -0
  51. package/package.json +11 -3
  52. package/packages/cli/src/config.mjs +4 -2
  53. package/packages/cli/src/control-server.mjs +23 -4
  54. package/packages/cli/src/data-transfer/service.mjs +42 -0
  55. package/packages/cli/src/runtime-manager.mjs +3 -0
  56. package/packages/runtime-host/src/codex-injection.mjs +1 -0
  57. package/packages/runtime-host/src/codex-runtime.mjs +11 -0
  58. package/packages/runtime-host/src/feature-registry.mjs +1 -0
  59. package/packages/ui/src/native/theme.mjs +22 -1
  60. package/packages/ui/src/native/tokens.mjs +4 -0
@@ -0,0 +1,270 @@
1
+ import { loadNativeMarkdownRenderer } from './markdown-native.mjs';
2
+ import { captureMarkdownProviders } from './providers.mjs';
3
+
4
+ // 从 Chat Markdown 的公开组件发现悬浮操作栏和控件,不绑定构建 hash。
5
+ export async function loadNativeMarkdownTableActions(native) {
6
+ const url = [...document.querySelectorAll('link[rel="modulepreload"],script[src]')]
7
+ .map((n) => n.href || n.src)
8
+ .find((url) => /\/app-initial-[^/]+\.js/.test(url));
9
+ const response = await fetch(url);
10
+ if (!response.ok) throw new Error('native-table-actions-source-unavailable');
11
+ const source = await response.text();
12
+ const section = (marker) => {
13
+ const at = source.indexOf(marker),
14
+ start = source.lastIndexOf('function ', at),
15
+ end = source.indexOf('function ', at);
16
+ if (at < 0 || start < 0 || end < 0) throw new Error('native-table-actions-contract-changed');
17
+ return source.slice(start, end);
18
+ };
19
+ const actions = section('"data-block-actions":!0'),
20
+ table = section('id:`markdown.expandTable`');
21
+ const exported = source.slice(source.lastIndexOf('export{'));
22
+ const module = await import(url);
23
+ const publicBinding = (name) => {
24
+ const alias = exported.match(new RegExp(`\\b${name} as ([\\w$]+)`))?.[1];
25
+ if (!alias || !module[alias]) throw new Error('native-table-actions-export-unavailable');
26
+ return module[alias];
27
+ };
28
+ // 初始化原生 lazy module,再使用其公开 React 组件。
29
+ const initializer = source
30
+ .slice(source.indexOf(table) + table.length)
31
+ .match(/^function ([\w$]+)\(\)\{return\(\1=/)?.[1];
32
+ if (!initializer) throw new Error('native-table-actions-initializer-unavailable');
33
+ publicBinding(initializer)();
34
+ const imports = new Map();
35
+ for (const match of source.matchAll(/import\{([^}]+)\}from["']([^"']+)["']/g))
36
+ for (const entry of match[1].split(',')) {
37
+ const parts = entry.trim().split(/\s+as\s+/);
38
+ imports.set(parts.at(-1), { name: parts[0], url: new URL(match[2], url).href });
39
+ }
40
+ const binding = async (name) => {
41
+ const item = imports.get(name);
42
+ if (!item) throw new Error('native-table-actions-dependency-unavailable');
43
+ return (await import(item.url))[item.name];
44
+ };
45
+ const sharedUrl = [...imports.values()].find((item) => /\/app-shared-[^/]+\.js/.test(item.url))?.url;
46
+ if (!sharedUrl) throw new Error('native-code-wrap-module-unavailable');
47
+ const sharedSource = await (await fetch(sharedUrl)).text(),
48
+ shared = await import(sharedUrl);
49
+ const wrapAt = sharedSource.indexOf('id:`codeSnippet.wrap.disable`');
50
+ const wrapSection = sharedSource.slice(
51
+ sharedSource.lastIndexOf('function ', wrapAt),
52
+ sharedSource.indexOf('function ', wrapAt),
53
+ );
54
+ const wrapPair = wrapSection.match(
55
+ /children:[\w$]+\?\(0,[\w$]+\.jsx\)\(([\w$]+),\{\}\):\(0,[\w$]+\.jsx\)\(([\w$]+),\{\}\)/,
56
+ );
57
+ if (wrapAt < 0 || !wrapPair) throw new Error('native-code-wrap-icons-unavailable');
58
+ const sharedExports = sharedSource.slice(sharedSource.lastIndexOf('export{'));
59
+ const sharedBinding = (name) => shared[sharedExports.match(new RegExp(`\\b${name} as ([\\w$]+)`))?.[1]];
60
+ const assignment = sharedSource.indexOf(`${wrapPair[1]}=`);
61
+ const initialize = sharedSource
62
+ .slice(sharedSource.lastIndexOf('function ', assignment))
63
+ .match(/^function ([\w$]+)\(\)/)?.[1];
64
+ if (initialize && typeof sharedBinding(initialize) === 'function') sharedBinding(initialize)();
65
+ const wrapIcons = { disable: sharedBinding(wrapPair[1]), enable: sharedBinding(wrapPair[2]) };
66
+ if (!wrapIcons.disable || !wrapIcons.enable) throw new Error('native-code-wrap-icon-exports-unavailable');
67
+ const button = table.match(/jsx\)\(([\w$]+),\{"aria-label":[\w$]+,"aria-expanded"/)?.[1];
68
+ const copy = table.match(/jsx\)\(([\w$]+),\{ariaLabel:[\w$]+,buttonText:/)?.[1];
69
+ const tooltip = table.match(/jsx\)\(([\w$]+),\{tooltipContent:[\w$]+,delayOpen:!0/)?.[1];
70
+ if (!button || !copy || !tooltip) throw new Error('native-table-actions-controls-unavailable');
71
+ const [Button, CopyButton, Tooltip] = await Promise.all([binding(button), binding(copy), binding(tooltip)]);
72
+ const previewName = table.match(/jsx\)\(([\w$]+),\{src:``,alt:/)?.[1];
73
+ const tableName = table.match(/jsx\)\(([\w$]+),\{className:[\w$]+,children:[\w$]+\}/)?.[1];
74
+ const classesName = table.match(/([\w$]+)\.MarkdownTablePreview/)?.[1];
75
+ const icon = table.match(/children:\(0,[\w$]+\.jsx\)\(([\w$]+),\{icon:\{16:([\w$]+),20:([\w$]+)\}\}\)/);
76
+ if (!previewName || !tableName || !classesName || !icon)
77
+ throw new Error('native-table-preview-contract-unavailable');
78
+ const [Icon, small, medium, renderer] = await Promise.all([
79
+ binding(icon[1]),
80
+ binding(icon[2]),
81
+ binding(icon[3]),
82
+ loadNativeMarkdownRenderer(source, url, module),
83
+ ]);
84
+ return {
85
+ ...native,
86
+ ...renderer,
87
+ TablePreview: publicBinding(previewName),
88
+ Table: publicBinding(tableName),
89
+ tableClasses: publicBinding(classesName),
90
+ ExpandIcon: () => native.React.createElement(Icon, { icon: { 16: small, 20: medium } }),
91
+ Actions: publicBinding(actions.match(/^function ([\w$]+)/)[1]),
92
+ Button,
93
+ wrapIcons,
94
+ CopyButton,
95
+ Tooltip,
96
+ };
97
+ }
98
+
99
+ export function installMarkdownTableActions(view, native, codex, controller) {
100
+ const {
101
+ React,
102
+ ReactDOM,
103
+ Actions,
104
+ Button,
105
+ wrapIcons,
106
+ CopyButton,
107
+ Tooltip,
108
+ TablePreview,
109
+ Table,
110
+ tableClasses,
111
+ ExpandIcon,
112
+ Markdown,
113
+ lexer,
114
+ } = native;
115
+ const h = React.createElement;
116
+ const mount = document.createElement('div');
117
+ mount.dataset.mcxReadingTableActions = '';
118
+ view.scrollDOM.append(mount);
119
+ const withProviders = captureMarkdownProviders(view.dom, codex);
120
+ const root = ReactDOM.createRoot(mount);
121
+ const chinese = document.documentElement.lang.startsWith('zh');
122
+ function TableActions({ item }) {
123
+ const [open, setOpen] = React.useState(false);
124
+ const trigger = React.useRef(null);
125
+ const tokens = React.useMemo(() => (open ? lexer(item.source, undefined) : []), [open, item.source]);
126
+ const wrap = chinese
127
+ ? item.fit
128
+ ? '恢复自然列宽'
129
+ : '适配宽度并换行'
130
+ : item.fit
131
+ ? 'Use natural table width'
132
+ : 'Fit table width and wrap';
133
+ const copy = chinese ? '复制表格' : 'Copy table';
134
+ const expand = chinese ? '展开表格' : 'Expand table';
135
+ const preview = chinese ? '表格预览' : 'Table preview';
136
+ const scroll = chinese ? '可横向滚动的表格' : 'Scrollable table';
137
+ return h(
138
+ React.Fragment,
139
+ null,
140
+ h(
141
+ 'div',
142
+ {
143
+ 'data-mcx-reading-table-action-id': item.id,
144
+ style: {
145
+ position: 'absolute',
146
+ left: item.left,
147
+ top: item.top,
148
+ width: item.width,
149
+ height: 48,
150
+ pointerEvents: 'none',
151
+ },
152
+ },
153
+ h('div', {
154
+ 'aria-hidden': true,
155
+ style: {
156
+ position: 'absolute',
157
+ right: 0,
158
+ top: 0,
159
+ width: '100%',
160
+ height: 48,
161
+ pointerEvents: item.visible ? 'auto' : 'none',
162
+ },
163
+ }),
164
+ h(
165
+ Actions,
166
+ { 'data-visible': item.visible, 'data-markdown-copy': 'exclude' },
167
+ item.fit || item.overflow
168
+ ? h(
169
+ Tooltip,
170
+ { tooltipContent: wrap, delayOpen: true },
171
+ h(
172
+ Button,
173
+ {
174
+ 'aria-label': wrap,
175
+ color: 'blockAction',
176
+ radius: 'full',
177
+ size: 'inputIcon',
178
+ onClick: () => controller.toggle(item.id),
179
+ },
180
+ h(item.fit ? wrapIcons.disable : wrapIcons.enable),
181
+ ),
182
+ )
183
+ : null,
184
+ h(CopyButton, {
185
+ ariaLabel: copy,
186
+ buttonText: copy,
187
+ iconOnly: true,
188
+ variant: 'blockAction',
189
+ onCopy: () => navigator.clipboard.writeText(item.source).then(() => true),
190
+ }),
191
+ h(
192
+ Tooltip,
193
+ { tooltipContent: expand, delayOpen: true },
194
+ h(
195
+ Button,
196
+ {
197
+ ref: trigger,
198
+ 'aria-label': expand,
199
+ 'aria-expanded': open,
200
+ 'aria-haspopup': 'dialog',
201
+ color: 'blockAction',
202
+ radius: 'full',
203
+ size: 'inputIcon',
204
+ onClick: () => setOpen(true),
205
+ },
206
+ h(ExpandIcon),
207
+ ),
208
+ ),
209
+ ),
210
+ ),
211
+ open
212
+ ? h(TablePreview, {
213
+ src: '',
214
+ alt: preview,
215
+ open: true,
216
+ dialogAriaLabel: preview,
217
+ closeAriaLabel: chinese ? '关闭表格预览' : 'Close table preview',
218
+ showDownload: false,
219
+ showZoomControls: false,
220
+ onOpenChange: setOpen,
221
+ onCloseAutoFocus: (event) => {
222
+ event.preventDefault();
223
+ trigger.current?.focus();
224
+ },
225
+ // 与原生消息流共用全屏外壳、表格组件和滚动材质,正文编辑器不参与重建。
226
+ previewContent: h(
227
+ 'div',
228
+ { className: `${tableClasses.MarkdownRoot} ${tableClasses.MarkdownTablePreview}` },
229
+ h(
230
+ 'div',
231
+ {
232
+ className: `${tableClasses.TableScroller} flex min-h-0 min-w-0 flex-1 overflow-auto bg-inherit`,
233
+ 'aria-label': scroll,
234
+ role: 'region',
235
+ tabIndex: 0,
236
+ },
237
+ h(
238
+ 'div',
239
+ { className: 'flex w-fit flex-col bg-inherit' },
240
+ h(Markdown, { tokens, components: { table: Table } }),
241
+ h('div', {
242
+ 'aria-hidden': true,
243
+ className: 'pointer-events-none sticky bottom-0 h-2 w-full shrink-0 bg-inherit',
244
+ }),
245
+ ),
246
+ h('div', {
247
+ 'aria-hidden': true,
248
+ className: 'pointer-events-none sticky end-0 top-0 h-full w-2 shrink-0 bg-inherit',
249
+ }),
250
+ ),
251
+ ),
252
+ })
253
+ : null,
254
+ );
255
+ }
256
+ controller.renderActions = (items) => {
257
+ root.render(
258
+ withProviders(
259
+ React,
260
+ h(React.Fragment, null, ...items.map((item) => h(TableActions, { key: item.id, item }))),
261
+ ),
262
+ );
263
+ };
264
+ controller.schedule();
265
+ return () => {
266
+ controller.renderActions = null;
267
+ root.unmount();
268
+ mount.remove();
269
+ };
270
+ }