@monkey-mini-app/dsh-mini-app 0.1.0 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +59 -0
- package/assets/apps-list.png +0 -0
- package/assets/complex-demo-app.png +0 -0
- package/assets/demo-app.png +0 -0
- package/assets/home.png +0 -0
- package/assets/sidebar-mode.png +0 -0
- package/lib/client.js +2024 -783
- package/lib/index.d.ts +5 -2
- package/lib/index.js +29 -16
- package/package.json +12 -10
- package/skills/monkey-mini-app/SKILL.md +182 -106
- package/skills/monkey-mini-app/references/catalog.md +236 -99
- package/skills/monkey-mini-app/references/contracts/accordion.md +30 -0
- package/skills/monkey-mini-app/references/contracts/activity-feed.md +12 -2
- package/skills/monkey-mini-app/references/contracts/alert-dialog.md +38 -0
- package/skills/monkey-mini-app/references/contracts/alert.md +38 -0
- package/skills/monkey-mini-app/references/contracts/app-shell.md +2 -2
- package/skills/monkey-mini-app/references/contracts/aspect-ratio.md +25 -0
- package/skills/monkey-mini-app/references/contracts/attachment-gallery.md +12 -2
- package/skills/monkey-mini-app/references/contracts/attachment.md +35 -0
- package/skills/monkey-mini-app/references/contracts/autocomplete.md +12 -2
- package/skills/monkey-mini-app/references/contracts/avatar.md +24 -0
- package/skills/monkey-mini-app/references/contracts/badge.md +26 -0
- package/skills/monkey-mini-app/references/contracts/breadcrumb.md +33 -0
- package/skills/monkey-mini-app/references/contracts/bubble.md +30 -0
- package/skills/monkey-mini-app/references/contracts/button-group.md +36 -0
- package/skills/monkey-mini-app/references/contracts/button.md +26 -0
- package/skills/monkey-mini-app/references/contracts/calendar.md +20 -0
- package/skills/monkey-mini-app/references/contracts/card.md +41 -0
- package/skills/monkey-mini-app/references/contracts/cascader.md +12 -2
- package/skills/monkey-mini-app/references/contracts/chart.md +32 -0
- package/skills/monkey-mini-app/references/contracts/checkbox.md +19 -0
- package/skills/monkey-mini-app/references/contracts/code-block.md +20 -2
- package/skills/monkey-mini-app/references/contracts/code-editor.md +30 -4
- package/skills/monkey-mini-app/references/contracts/collapsible.md +21 -0
- package/skills/monkey-mini-app/references/contracts/color-picker.md +12 -2
- package/skills/monkey-mini-app/references/contracts/combobox.md +34 -0
- package/skills/monkey-mini-app/references/contracts/command.md +41 -0
- package/skills/monkey-mini-app/references/contracts/comment-thread.md +12 -2
- package/skills/monkey-mini-app/references/contracts/commit-graph.md +50 -0
- package/skills/monkey-mini-app/references/contracts/confirm-dialog.md +20 -2
- package/skills/monkey-mini-app/references/contracts/context-menu.md +41 -0
- package/skills/monkey-mini-app/references/contracts/copyable.md +12 -2
- package/skills/monkey-mini-app/references/contracts/currency-input.md +12 -2
- package/skills/monkey-mini-app/references/contracts/dashboard-shell.md +41 -0
- package/skills/monkey-mini-app/references/contracts/data-grid.md +13 -6
- package/skills/monkey-mini-app/references/contracts/date-picker.md +20 -2
- package/skills/monkey-mini-app/references/contracts/date-range-picker.md +10 -2
- package/skills/monkey-mini-app/references/contracts/date-time-picker.md +20 -2
- package/skills/monkey-mini-app/references/contracts/date-time-range-picker.md +20 -2
- package/skills/monkey-mini-app/references/contracts/description-list.md +12 -2
- package/skills/monkey-mini-app/references/contracts/detail-panel.md +10 -2
- package/skills/monkey-mini-app/references/contracts/dialog.md +44 -0
- package/skills/monkey-mini-app/references/contracts/diff-viewer.md +21 -2
- package/skills/monkey-mini-app/references/contracts/donut-chart.md +14 -2
- package/skills/monkey-mini-app/references/contracts/drawer.md +29 -0
- package/skills/monkey-mini-app/references/contracts/dropdown-menu.md +49 -0
- package/skills/monkey-mini-app/references/contracts/duration-input.md +20 -2
- package/skills/monkey-mini-app/references/contracts/empty.md +40 -0
- package/skills/monkey-mini-app/references/contracts/env-badge.md +12 -2
- package/skills/monkey-mini-app/references/contracts/env-table.md +46 -0
- package/skills/monkey-mini-app/references/contracts/event-calendar.md +28 -20
- package/skills/monkey-mini-app/references/contracts/field.md +34 -0
- package/skills/monkey-mini-app/references/contracts/file-dropzone.md +20 -2
- package/skills/monkey-mini-app/references/contracts/file-tree.md +12 -2
- package/skills/monkey-mini-app/references/contracts/filter-bar.md +2 -2
- package/skills/monkey-mini-app/references/contracts/form-sheet.md +51 -0
- package/skills/monkey-mini-app/references/contracts/gantt.md +20 -2
- package/skills/monkey-mini-app/references/contracts/gauge.md +14 -2
- package/skills/monkey-mini-app/references/contracts/hover-card.md +21 -0
- package/skills/monkey-mini-app/references/contracts/input-group.md +24 -0
- package/skills/monkey-mini-app/references/contracts/input.md +33 -0
- package/skills/monkey-mini-app/references/contracts/item.md +36 -0
- package/skills/monkey-mini-app/references/contracts/jira-wiki.md +3 -4
- package/skills/monkey-mini-app/references/contracts/jql-input.md +15 -8
- package/skills/monkey-mini-app/references/contracts/json-viewer.md +20 -2
- package/skills/monkey-mini-app/references/contracts/kanban-issue-panel.md +12 -2
- package/skills/monkey-mini-app/references/contracts/kanban.md +10 -2
- package/skills/monkey-mini-app/references/contracts/kbd.md +20 -0
- package/skills/monkey-mini-app/references/contracts/label.md +33 -0
- package/skills/monkey-mini-app/references/contracts/list-detail.md +46 -0
- package/skills/monkey-mini-app/references/contracts/log-viewer.md +45 -4
- package/skills/monkey-mini-app/references/contracts/markdown-editor.md +20 -2
- package/skills/monkey-mini-app/references/contracts/markdown.md +12 -2
- package/skills/monkey-mini-app/references/contracts/marker.md +30 -0
- package/skills/monkey-mini-app/references/contracts/menubar.md +34 -0
- package/skills/monkey-mini-app/references/contracts/message-scroller.md +24 -0
- package/skills/monkey-mini-app/references/contracts/message.md +24 -0
- package/skills/monkey-mini-app/references/contracts/mini-calendar.md +20 -2
- package/skills/monkey-mini-app/references/contracts/native-select.md +21 -0
- package/skills/monkey-mini-app/references/contracts/navigation-menu.md +27 -0
- package/skills/monkey-mini-app/references/contracts/notification-center.md +12 -2
- package/skills/monkey-mini-app/references/contracts/number-field.md +20 -2
- package/skills/monkey-mini-app/references/contracts/page-header.md +2 -2
- package/skills/monkey-mini-app/references/contracts/pagination.md +33 -0
- package/skills/monkey-mini-app/references/contracts/password-field.md +12 -2
- package/skills/monkey-mini-app/references/contracts/phone-input.md +12 -2
- package/skills/monkey-mini-app/references/contracts/popover.md +32 -0
- package/skills/monkey-mini-app/references/contracts/progress-ring.md +14 -2
- package/skills/monkey-mini-app/references/contracts/progress.md +39 -0
- package/skills/monkey-mini-app/references/contracts/questionnaire.md +33 -0
- package/skills/monkey-mini-app/references/contracts/radar-chart.md +14 -2
- package/skills/monkey-mini-app/references/contracts/radio-group.md +20 -0
- package/skills/monkey-mini-app/references/contracts/rating.md +12 -2
- package/skills/monkey-mini-app/references/contracts/relative-date-picker.md +20 -2
- package/skills/monkey-mini-app/references/contracts/request-inspector.md +12 -2
- package/skills/monkey-mini-app/references/contracts/resizable.md +29 -0
- package/skills/monkey-mini-app/references/contracts/reveal.md +31 -0
- package/skills/monkey-mini-app/references/contracts/rich-text-editor.md +14 -2
- package/skills/monkey-mini-app/references/contracts/run-timeline.md +20 -2
- package/skills/monkey-mini-app/references/contracts/scroll-area.md +20 -0
- package/skills/monkey-mini-app/references/contracts/scrollspy.md +20 -2
- package/skills/monkey-mini-app/references/contracts/search-input.md +12 -2
- package/skills/monkey-mini-app/references/contracts/select.md +36 -0
- package/skills/monkey-mini-app/references/contracts/separator.md +27 -0
- package/skills/monkey-mini-app/references/contracts/settings-split.md +53 -0
- package/skills/monkey-mini-app/references/contracts/severity-chip.md +12 -2
- package/skills/monkey-mini-app/references/contracts/sheet.md +34 -0
- package/skills/monkey-mini-app/references/contracts/sidebar.md +42 -0
- package/skills/monkey-mini-app/references/contracts/skeleton.md +33 -0
- package/skills/monkey-mini-app/references/contracts/slider-range.md +12 -2
- package/skills/monkey-mini-app/references/contracts/slider.md +25 -0
- package/skills/monkey-mini-app/references/contracts/sortable-list.md +20 -2
- package/skills/monkey-mini-app/references/contracts/sparkline.md +13 -2
- package/skills/monkey-mini-app/references/contracts/spinner.md +31 -0
- package/skills/monkey-mini-app/references/contracts/stacked-bar-chart.md +17 -2
- package/skills/monkey-mini-app/references/contracts/stat-card.md +2 -2
- package/skills/monkey-mini-app/references/contracts/status-badge.md +2 -2
- package/skills/monkey-mini-app/references/contracts/stepper-item.md +39 -0
- package/skills/monkey-mini-app/references/contracts/stepper.md +38 -11
- package/skills/monkey-mini-app/references/contracts/switch.md +25 -0
- package/skills/monkey-mini-app/references/contracts/table-page.md +41 -0
- package/skills/monkey-mini-app/references/contracts/table.md +42 -0
- package/skills/monkey-mini-app/references/contracts/tabs.md +31 -0
- package/skills/monkey-mini-app/references/contracts/tag-input.md +12 -2
- package/skills/monkey-mini-app/references/contracts/terminal.md +13 -2
- package/skills/monkey-mini-app/references/contracts/test-step-list.md +12 -2
- package/skills/monkey-mini-app/references/contracts/textarea.md +25 -0
- package/skills/monkey-mini-app/references/contracts/time-picker.md +18 -2
- package/skills/monkey-mini-app/references/contracts/time-range-picker.md +20 -2
- package/skills/monkey-mini-app/references/contracts/time-wheel.md +6 -2
- package/skills/monkey-mini-app/references/contracts/timeline.md +20 -2
- package/skills/monkey-mini-app/references/contracts/timezone-select.md +20 -2
- package/skills/monkey-mini-app/references/contracts/toast.md +39 -0
- package/skills/monkey-mini-app/references/contracts/toggle-group.md +28 -0
- package/skills/monkey-mini-app/references/contracts/toggle.md +26 -0
- package/skills/monkey-mini-app/references/contracts/tooltip.md +30 -0
- package/skills/monkey-mini-app/references/contracts/transfer.md +12 -2
- package/skills/monkey-mini-app/references/contracts/tree-view.md +20 -2
- package/skills/monkey-mini-app/references/contracts/trend-card.md +12 -2
- package/skills/monkey-mini-app/references/contracts/user-picker.md +12 -2
- package/skills/monkey-mini-app/references/contracts/wizard-shell.md +56 -0
- package/skills/monkey-mini-app/references/ctx.md +123 -53
- package/skills/monkey-mini-app/references/eval.md +115 -0
- package/skills/monkey-mini-app/references/examples/alert/alert-01.tsx +17 -0
- package/skills/monkey-mini-app/references/examples/aspect-ratio/aspect-ratio-01.tsx +16 -0
- package/skills/monkey-mini-app/references/examples/attachment/attachment-01.tsx +19 -0
- package/skills/monkey-mini-app/references/examples/breadcrumb/breadcrumb-01.tsx +31 -0
- package/skills/monkey-mini-app/references/examples/bubble/bubble-01.tsx +16 -0
- package/skills/monkey-mini-app/references/examples/button-group/button-group-01.tsx +23 -0
- package/skills/monkey-mini-app/references/examples/card/card-01.tsx +19 -0
- package/skills/monkey-mini-app/references/examples/charts-blocks.md +15 -0
- package/skills/monkey-mini-app/references/examples/code-block/code-block-01.tsx +14 -0
- package/skills/monkey-mini-app/references/examples/code-editor/code-editor-01.tsx +15 -0
- package/skills/monkey-mini-app/references/examples/command/command-01.tsx +30 -0
- package/skills/monkey-mini-app/references/examples/confirm-dialog/confirm-dialog-01.tsx +33 -0
- package/skills/monkey-mini-app/references/examples/context-menu/context-menu-01.tsx +29 -0
- package/skills/monkey-mini-app/references/examples/dashboard-shell/dashboard-shell-01.tsx +78 -0
- package/skills/monkey-mini-app/references/examples/data-grid/data-grid-01.tsx +34 -0
- package/skills/monkey-mini-app/references/examples/data-grid/data-grid-02.tsx +88 -0
- package/skills/monkey-mini-app/references/examples/date-picker/date-picker-01.tsx +14 -0
- package/skills/monkey-mini-app/references/examples/date-range-picker/date-range-picker-01.tsx +14 -0
- package/skills/monkey-mini-app/references/examples/date-time-picker/date-time-picker-01.tsx +16 -0
- package/skills/monkey-mini-app/references/examples/date-time-range-picker/date-time-range-picker-01.tsx +15 -0
- package/skills/monkey-mini-app/references/examples/detail-panel/detail-panel-01.tsx +21 -0
- package/skills/monkey-mini-app/references/examples/dialog/dialog-01.tsx +30 -0
- package/skills/monkey-mini-app/references/examples/diff-viewer/diff-viewer-01.tsx +10 -0
- package/skills/monkey-mini-app/references/examples/dropdown-menu/dropdown-menu-01.tsx +31 -0
- package/skills/monkey-mini-app/references/examples/duration-input/duration-input-01.tsx +20 -0
- package/skills/monkey-mini-app/references/examples/editors.md +11 -0
- package/skills/monkey-mini-app/references/examples/empty/empty-01.tsx +19 -0
- package/skills/monkey-mini-app/references/examples/event-calendar/event-calendar-01.tsx +53 -0
- package/skills/monkey-mini-app/references/examples/file-dropzone/file-dropzone-01.tsx +14 -0
- package/skills/monkey-mini-app/references/examples/form-sheet/form-sheet-01.tsx +85 -0
- package/skills/monkey-mini-app/references/examples/forms.md +16 -0
- package/skills/monkey-mini-app/references/examples/gantt/gantt-01.tsx +29 -0
- package/skills/monkey-mini-app/references/examples/input/input-01.tsx +10 -0
- package/skills/monkey-mini-app/references/examples/item/item-01.tsx +19 -0
- package/skills/monkey-mini-app/references/examples/jql-input/jql-input-01.tsx +33 -0
- package/skills/monkey-mini-app/references/examples/json-viewer/json-viewer-01.tsx +10 -0
- package/skills/monkey-mini-app/references/examples/kanban/kanban-01.tsx +60 -0
- package/skills/monkey-mini-app/references/examples/label/label-01.tsx +10 -0
- package/skills/monkey-mini-app/references/examples/list-detail/list-detail-01.tsx +117 -0
- package/skills/monkey-mini-app/references/examples/log-viewer/log-viewer-01.tsx +20 -0
- package/skills/monkey-mini-app/references/examples/markdown-editor/markdown-editor-01.tsx +18 -0
- package/skills/monkey-mini-app/references/examples/marker/marker-01.tsx +16 -0
- package/skills/monkey-mini-app/references/examples/mini-calendar/mini-calendar-01.tsx +14 -0
- package/skills/monkey-mini-app/references/examples/misc-charts-blocks/misc-charts-blocks-01.tsx +20 -0
- package/skills/monkey-mini-app/references/examples/misc-charts-blocks/misc-charts-blocks-02.tsx +32 -0
- package/skills/monkey-mini-app/references/examples/misc-charts-blocks/misc-charts-blocks-03.tsx +47 -0
- package/skills/monkey-mini-app/references/examples/misc-charts-blocks/misc-charts-blocks-04.tsx +20 -0
- package/skills/monkey-mini-app/references/examples/misc-charts-blocks/misc-charts-blocks-05.tsx +24 -0
- package/skills/monkey-mini-app/references/examples/misc-charts-blocks/misc-charts-blocks-06.tsx +89 -0
- package/skills/monkey-mini-app/references/examples/misc-editors/misc-editors-01.tsx +114 -0
- package/skills/monkey-mini-app/references/examples/misc-editors/misc-editors-02.tsx +33 -0
- package/skills/monkey-mini-app/references/examples/misc-forms/misc-forms-01.tsx +22 -0
- package/skills/monkey-mini-app/references/examples/misc-forms/misc-forms-02.tsx +37 -0
- package/skills/monkey-mini-app/references/examples/misc-forms/misc-forms-03.tsx +42 -0
- package/skills/monkey-mini-app/references/examples/misc-forms/misc-forms-04.tsx +25 -0
- package/skills/monkey-mini-app/references/examples/misc-forms/misc-forms-05.tsx +27 -0
- package/skills/monkey-mini-app/references/examples/misc-forms/misc-forms-06.tsx +33 -0
- package/skills/monkey-mini-app/references/examples/misc-forms/misc-forms-07.tsx +44 -0
- package/skills/monkey-mini-app/references/examples/misc-overlays/misc-overlays-01.tsx +43 -0
- package/skills/monkey-mini-app/references/examples/misc-overlays/misc-overlays-02.tsx +38 -0
- package/skills/monkey-mini-app/references/examples/misc-primitives/misc-primitives-01.tsx +21 -0
- package/skills/monkey-mini-app/references/examples/misc-primitives/misc-primitives-02.tsx +52 -0
- package/skills/monkey-mini-app/references/examples/misc-primitives/misc-primitives-03.tsx +44 -0
- package/skills/monkey-mini-app/references/examples/number-field/number-field-01.tsx +22 -0
- package/skills/monkey-mini-app/references/examples/overlays.md +11 -0
- package/skills/monkey-mini-app/references/examples/pagination/pagination-01.tsx +51 -0
- package/skills/monkey-mini-app/references/examples/primitives.md +12 -0
- package/skills/monkey-mini-app/references/examples/progress/progress-01.tsx +10 -0
- package/skills/monkey-mini-app/references/examples/relative-date-picker/relative-date-picker-01.tsx +19 -0
- package/skills/monkey-mini-app/references/examples/rich-text-editor/rich-text-editor-01.tsx +15 -0
- package/skills/monkey-mini-app/references/examples/run-timeline/run-timeline-01.tsx +17 -0
- package/skills/monkey-mini-app/references/examples/scrollspy/scrollspy-01.tsx +29 -0
- package/skills/monkey-mini-app/references/examples/separator/separator-01.tsx +10 -0
- package/skills/monkey-mini-app/references/examples/settings-split/settings-split-01.tsx +84 -0
- package/skills/monkey-mini-app/references/examples/shared/jira-wiki-sample.ts +38 -0
- package/skills/monkey-mini-app/references/examples/skeleton/skeleton-01.tsx +10 -0
- package/skills/monkey-mini-app/references/examples/slider/slider-01.tsx +22 -0
- package/skills/monkey-mini-app/references/examples/sortable-list/sortable-list-01.tsx +18 -0
- package/skills/monkey-mini-app/references/examples/spinner/spinner-01.tsx +10 -0
- package/skills/monkey-mini-app/references/examples/stepper/stepper-01.tsx +41 -0
- package/skills/monkey-mini-app/references/examples/table/table-01.tsx +25 -0
- package/skills/monkey-mini-app/references/examples/table-page/table-page-01.tsx +103 -0
- package/skills/monkey-mini-app/references/examples/time-picker/time-picker-01.tsx +19 -0
- package/skills/monkey-mini-app/references/examples/time-range-picker/time-range-picker-01.tsx +14 -0
- package/skills/monkey-mini-app/references/examples/timeline/timeline-01.tsx +18 -0
- package/skills/monkey-mini-app/references/examples/timezone-select/timezone-select-01.tsx +15 -0
- package/skills/monkey-mini-app/references/examples/toggle/toggle-01.tsx +20 -0
- package/skills/monkey-mini-app/references/examples/toggle-group/toggle-group-01.tsx +22 -0
- package/skills/monkey-mini-app/references/examples/tree-view/tree-view-01.tsx +25 -0
- package/skills/monkey-mini-app/references/examples/wizard-shell/wizard-shell-01.tsx +58 -0
- package/skills/monkey-mini-app/references/history.md +23 -7
- package/skills/monkey-mini-app/references/icons.md +99 -69
- package/skills/monkey-mini-app/references/llm-json.md +39 -26
- package/skills/monkey-mini-app/references/loader.md +47 -20
- package/skills/monkey-mini-app/references/looks/aurora-bento.md +88 -0
- package/skills/monkey-mini-app/references/looks/desk-split.md +89 -0
- package/skills/monkey-mini-app/references/looks/editorial.md +78 -0
- package/skills/monkey-mini-app/references/looks/glass-island.md +90 -0
- package/skills/monkey-mini-app/references/looks/index.md +18 -0
- package/skills/monkey-mini-app/references/looks/signage.md +74 -0
- package/skills/monkey-mini-app/references/looks/tape.md +22 -0
- package/skills/monkey-mini-app/references/looks/terminal.md +88 -0
- package/skills/monkey-mini-app/references/looks/void.md +22 -0
- package/skills/monkey-mini-app/references/styling.md +189 -0
- package/skills/monkey-mini-app/references/test.md +12 -12
- package/skills/monkey-mini-app/references/theme.md +197 -0
- package/skills/monkey-mini-app/references/tools.md +12 -12
- package/skills/monkey-mini-app/references/troubleshoot.md +165 -12
- package/skills/monkey-mini-app/templates/README.md +33 -21
- package/skills/monkey-mini-app/templates/{jira → board}/main.api.ts +11 -11
- package/skills/monkey-mini-app/templates/board/manifest.json +8 -0
- package/skills/monkey-mini-app/templates/board/theme.css +46 -0
- package/skills/monkey-mini-app/templates/board/ui.tsx +546 -0
- package/skills/monkey-mini-app/templates/chores/main.api.ts +35 -0
- package/skills/monkey-mini-app/templates/chores/manifest.json +8 -0
- package/skills/monkey-mini-app/templates/chores/theme.css +46 -0
- package/skills/monkey-mini-app/templates/chores/ui.tsx +117 -0
- package/skills/monkey-mini-app/templates/minimal/main.api.ts +5 -5
- package/skills/monkey-mini-app/templates/minimal/manifest.json +1 -2
- package/skills/monkey-mini-app/templates/minimal/ui.tsx +17 -8
- package/skills/monkey-mini-app/templates/radar/api/scan.ts +79 -0
- package/skills/monkey-mini-app/templates/radar/main.api.ts +29 -0
- package/skills/monkey-mini-app/templates/radar/manifest.json +8 -0
- package/skills/monkey-mini-app/templates/radar/shared/events.ts +25 -0
- package/skills/monkey-mini-app/templates/{insights/lib → radar/shared}/sample.ts +1 -1
- package/skills/monkey-mini-app/templates/radar/theme.css +47 -0
- package/skills/monkey-mini-app/templates/radar/ui/brief.tsx +31 -0
- package/skills/monkey-mini-app/templates/radar/ui.tsx +131 -0
- package/skills/monkey-mini-app/templates/runner/main.api.ts +91 -0
- package/skills/monkey-mini-app/templates/runner/manifest.json +8 -0
- package/skills/monkey-mini-app/templates/runner/shared/events.ts +14 -0
- package/skills/monkey-mini-app/templates/runner/theme.css +46 -0
- package/skills/monkey-mini-app/templates/runner/ui.tsx +213 -0
- package/skills/monkey-mini-app/templates/sheets/main.api.ts +276 -0
- package/skills/monkey-mini-app/templates/sheets/manifest.json +8 -0
- package/skills/monkey-mini-app/templates/sheets/theme.css +46 -0
- package/skills/monkey-mini-app/templates/sheets/ui.tsx +419 -0
- package/skills/monkey-mini-app/templates/{todo → today}/main.api.ts +8 -8
- package/skills/monkey-mini-app/templates/today/manifest.json +8 -0
- package/skills/monkey-mini-app/templates/today/theme.css +45 -0
- package/skills/monkey-mini-app/templates/today/ui/item-row.tsx +25 -0
- package/skills/monkey-mini-app/templates/today/ui.tsx +406 -0
- package/skills/monkey-mini-app/templates/{monitor → watch}/main.api.ts +8 -8
- package/skills/monkey-mini-app/templates/watch/manifest.json +8 -0
- package/skills/monkey-mini-app/templates/watch/ui.tsx +187 -0
- package/skills/monkey-mini-app/tsconfig.json +31 -0
- package/skills/monkey-mini-app/types/cdn.d.ts +1 -0
- package/tsup.config.ts +1 -0
- package/skills/monkey-mini-app/templates/agentrun/main.api.ts +0 -78
- package/skills/monkey-mini-app/templates/agentrun/manifest.json +0 -9
- package/skills/monkey-mini-app/templates/agentrun/ui.tsx +0 -125
- package/skills/monkey-mini-app/templates/insights/main.api.ts +0 -101
- package/skills/monkey-mini-app/templates/insights/manifest.json +0 -9
- package/skills/monkey-mini-app/templates/insights/ui.tsx +0 -138
- package/skills/monkey-mini-app/templates/jira/manifest.json +0 -9
- package/skills/monkey-mini-app/templates/jira/ui.tsx +0 -318
- package/skills/monkey-mini-app/templates/monitor/manifest.json +0 -9
- package/skills/monkey-mini-app/templates/monitor/ui.tsx +0 -176
- package/skills/monkey-mini-app/templates/review/main.api.ts +0 -68
- package/skills/monkey-mini-app/templates/review/manifest.json +0 -9
- package/skills/monkey-mini-app/templates/review/ui.tsx +0 -159
- package/skills/monkey-mini-app/templates/todo/manifest.json +0 -8
- package/skills/monkey-mini-app/templates/todo/ui.tsx +0 -177
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/* name: 终端等宽 */
|
|
2
|
+
/* Look-owned palette: phosphor-on-black CRT is the identity — a host palette would turn the
|
|
3
|
+
well pink. Light mode is a paper well with deep green ink; dark is near-black with green
|
|
4
|
+
phosphor (#3dff6e). Radius is squared: rounds read as "chat app", not as a console. */
|
|
5
|
+
:root[data-mode="light"] {
|
|
6
|
+
--bg: #ecefe4;
|
|
7
|
+
--fg: #12290f;
|
|
8
|
+
--surface: #f7faf1;
|
|
9
|
+
--surface-fg: #12290f;
|
|
10
|
+
--border: #ccd5c0;
|
|
11
|
+
--muted: #dfe6d4;
|
|
12
|
+
--muted-fg: #4c5f44;
|
|
13
|
+
--primary: #157a24;
|
|
14
|
+
--primary-fg: #ffffff;
|
|
15
|
+
--secondary: #dfe6d4;
|
|
16
|
+
--secondary-fg: #12290f;
|
|
17
|
+
--accent: #e2ecd6;
|
|
18
|
+
--accent-fg: #12290f;
|
|
19
|
+
--destructive: #b42318;
|
|
20
|
+
--destructive-fg: #ffffff;
|
|
21
|
+
--ring: #157a24;
|
|
22
|
+
--input: #ccd5c0;
|
|
23
|
+
--radius: 8px;
|
|
24
|
+
--shadow: rgba(20, 40, 25, 0.12);
|
|
25
|
+
}
|
|
26
|
+
:root[data-mode="dark"] {
|
|
27
|
+
--bg: #0a0d08;
|
|
28
|
+
--fg: #3dff6e;
|
|
29
|
+
--surface: #060904;
|
|
30
|
+
--surface-fg: #3dff6e;
|
|
31
|
+
--border: #1d2a18;
|
|
32
|
+
--muted: #10180d;
|
|
33
|
+
--muted-fg: #5f8a55;
|
|
34
|
+
--primary: #3dff6e;
|
|
35
|
+
--primary-fg: #0a0d08;
|
|
36
|
+
--secondary: #10180d;
|
|
37
|
+
--secondary-fg: #3dff6e;
|
|
38
|
+
--accent: #12200f;
|
|
39
|
+
--accent-fg: #3dff6e;
|
|
40
|
+
--destructive: #ff5341;
|
|
41
|
+
--destructive-fg: #0a0d08;
|
|
42
|
+
--ring: #3dff6e;
|
|
43
|
+
--input: #1d2a18;
|
|
44
|
+
--radius: 8px;
|
|
45
|
+
--shadow: rgba(0, 0, 0, 0.55);
|
|
46
|
+
}
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import { useCallback, useEffect, useState } from "react";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
Badge,
|
|
5
|
+
Button,
|
|
6
|
+
Icon,
|
|
7
|
+
Input,
|
|
8
|
+
RunTimeline,
|
|
9
|
+
Terminal,
|
|
10
|
+
useApp,
|
|
11
|
+
} from "@monkey-mini-app/ui";
|
|
12
|
+
|
|
13
|
+
import { EV, type Run, type Step } from "./shared/events";
|
|
14
|
+
|
|
15
|
+
type AgentEvent =
|
|
16
|
+
| { type: "status"; status: string }
|
|
17
|
+
| { type: "text-delta"; text: string }
|
|
18
|
+
| { type: "tool"; phase: string; name: string }
|
|
19
|
+
| { type: "turn"; phase: string; turn: number }
|
|
20
|
+
| { type: "done"; text: string }
|
|
21
|
+
| { type: "error"; message: string };
|
|
22
|
+
type TimelineItem = {
|
|
23
|
+
id: string;
|
|
24
|
+
title: string;
|
|
25
|
+
description?: string;
|
|
26
|
+
time?: string;
|
|
27
|
+
status?: "pass" | "fail" | "running" | "skipped";
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
// Token hues only: under this look's phosphor palette a literal `bg-emerald-400` fights the
|
|
31
|
+
// ground, and the rule is colour = state, nothing else.
|
|
32
|
+
const LAMP: Record<string, string> = {
|
|
33
|
+
idle: "bg-muted-foreground/40",
|
|
34
|
+
running: "bg-primary/50",
|
|
35
|
+
done: "bg-primary",
|
|
36
|
+
cancelled: "bg-muted-foreground/70",
|
|
37
|
+
error: "bg-destructive",
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export default function Ui() {
|
|
41
|
+
const { call, on, onAny } = useApp();
|
|
42
|
+
const [goal, setGoal] = useState("");
|
|
43
|
+
const [run, setRun] = useState<Run | null>(null);
|
|
44
|
+
const [running, setRunning] = useState(false);
|
|
45
|
+
const [steps, setSteps] = useState<Step[]>([]);
|
|
46
|
+
const [live, setLive] = useState("");
|
|
47
|
+
const [error, setError] = useState<string | null>(null);
|
|
48
|
+
|
|
49
|
+
const applyRun = useCallback((next: Run) => {
|
|
50
|
+
setRun(next);
|
|
51
|
+
setRunning(next?.status === "running");
|
|
52
|
+
if (next?.status !== "running") {
|
|
53
|
+
// finished: the persisted snapshot is authoritative, drop the optimistic feed
|
|
54
|
+
setSteps(next.steps ?? []);
|
|
55
|
+
setLive(next.result ?? "");
|
|
56
|
+
}
|
|
57
|
+
}, []);
|
|
58
|
+
|
|
59
|
+
// ⭐ key: fetch the snapshot ONCE, then let ctx.push events keep it current — no interval polling.
|
|
60
|
+
useEffect(() => {
|
|
61
|
+
void (call("runStatus", {}) as Promise<Run>).then(applyRun).catch(() => {});
|
|
62
|
+
}, [call, applyRun]);
|
|
63
|
+
|
|
64
|
+
useEffect(() => {
|
|
65
|
+
const offRun = on(EV.run, (data) => applyRun(data as Run));
|
|
66
|
+
const offAgent = on(EV.agent, (data) => {
|
|
67
|
+
const ev = data as AgentEvent;
|
|
68
|
+
const at = Date.now();
|
|
69
|
+
if (ev.type === "text-delta") setLive((prev) => prev + ev.text);
|
|
70
|
+
else if (ev.type === "tool" && ev.phase === "start")
|
|
71
|
+
setSteps((p) => [...p, { phase: "tool", name: ev.name, at }]);
|
|
72
|
+
else if (ev.type === "turn" && ev.phase === "start")
|
|
73
|
+
setSteps((p) => [...p, { phase: "turn", turn: ev.turn, at }]);
|
|
74
|
+
else if (ev.type === "done")
|
|
75
|
+
setSteps((p) => [...p, { phase: "done", at }]);
|
|
76
|
+
else if (ev.type === "error")
|
|
77
|
+
setSteps((p) => [...p, { phase: "error", text: ev.message, at }]);
|
|
78
|
+
});
|
|
79
|
+
// Events dropped from the host replay buffer (long disconnect): refetch, don't guess.
|
|
80
|
+
const offAny = onAny((e) => {
|
|
81
|
+
if (e.name === "*" && (e.data as { gap?: boolean })?.gap) {
|
|
82
|
+
void (call("runStatus", {}) as Promise<Run>)
|
|
83
|
+
.then(applyRun)
|
|
84
|
+
.catch(() => {});
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
return () => {
|
|
88
|
+
offRun();
|
|
89
|
+
offAgent();
|
|
90
|
+
offAny();
|
|
91
|
+
};
|
|
92
|
+
}, [on, onAny, call, applyRun]);
|
|
93
|
+
|
|
94
|
+
async function start() {
|
|
95
|
+
setError(null);
|
|
96
|
+
setSteps([]);
|
|
97
|
+
setLive("");
|
|
98
|
+
try {
|
|
99
|
+
await call("start", { goal });
|
|
100
|
+
} catch (e) {
|
|
101
|
+
setError(String((e as Error)?.message || e));
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// ⭐ key: a run's phases on a time axis = RunTimeline. Plain ordered events = Timeline.
|
|
106
|
+
const items: TimelineItem[] = steps.map((s, i) => ({
|
|
107
|
+
id: String(i),
|
|
108
|
+
title:
|
|
109
|
+
s.phase === "tool"
|
|
110
|
+
? `调用工具 ${s.name ?? ""}`
|
|
111
|
+
: s.phase === "turn"
|
|
112
|
+
? `第 ${s.turn} 轮`
|
|
113
|
+
: s.phase === "done"
|
|
114
|
+
? "完成"
|
|
115
|
+
: s.phase,
|
|
116
|
+
description: s.text ?? (s.phase === "tool" ? "结束" : undefined),
|
|
117
|
+
time: new Date(s.at).toLocaleTimeString("zh-CN"),
|
|
118
|
+
status:
|
|
119
|
+
s.phase === "error"
|
|
120
|
+
? "fail"
|
|
121
|
+
: s.phase === "done"
|
|
122
|
+
? "pass"
|
|
123
|
+
: running && i === steps.length - 1
|
|
124
|
+
? "running"
|
|
125
|
+
: "skipped",
|
|
126
|
+
}));
|
|
127
|
+
|
|
128
|
+
const status = run?.status ?? "idle";
|
|
129
|
+
|
|
130
|
+
return (
|
|
131
|
+
// ⭐ Look: terminal — lamp header, a command bar, mono wells. Colour is state, nothing else.
|
|
132
|
+
<div className="flex h-full min-h-0 flex-col bg-background font-mono text-sm">
|
|
133
|
+
<div className="border-border text-muted-foreground flex items-center gap-2 border-b px-4 py-2.5 text-xs">
|
|
134
|
+
<span className={`size-2 rounded-full ${LAMP[status] ?? LAMP.idle}`} />
|
|
135
|
+
runner · {goal.trim() || "未指定目标"}
|
|
136
|
+
<Badge
|
|
137
|
+
variant={status === "error" ? "destructive" : "outline"}
|
|
138
|
+
className="ml-auto"
|
|
139
|
+
>
|
|
140
|
+
{status}
|
|
141
|
+
</Badge>
|
|
142
|
+
</div>
|
|
143
|
+
|
|
144
|
+
<div className="border-border flex flex-wrap items-center gap-2 border-b px-4 py-3">
|
|
145
|
+
<Icon.ChevronRight className="text-muted-foreground size-4 shrink-0" />
|
|
146
|
+
<Input
|
|
147
|
+
value={goal}
|
|
148
|
+
placeholder="读 packages/ui/src 下组件,总结导出清单写到 storage"
|
|
149
|
+
onChange={(e) => setGoal(e.target.value)}
|
|
150
|
+
onKeyDown={(e) => {
|
|
151
|
+
if (e.key === "Enter" && !running && goal.trim()) void start();
|
|
152
|
+
}}
|
|
153
|
+
className="h-8 min-w-52 flex-1 border-0 bg-transparent px-0 font-mono text-sm shadow-none focus-visible:ring-0"
|
|
154
|
+
/>
|
|
155
|
+
<Button
|
|
156
|
+
size="sm"
|
|
157
|
+
variant="outline"
|
|
158
|
+
onClick={() => void start()}
|
|
159
|
+
disabled={running || !goal.trim()}
|
|
160
|
+
>
|
|
161
|
+
<Icon.Play size={14} strokeWidth={2} /> 运行
|
|
162
|
+
</Button>
|
|
163
|
+
{running ? (
|
|
164
|
+
<Button
|
|
165
|
+
size="sm"
|
|
166
|
+
variant="ghost"
|
|
167
|
+
onClick={() => void call("cancel", {})}
|
|
168
|
+
>
|
|
169
|
+
<Icon.Square size={14} strokeWidth={2} /> 取消
|
|
170
|
+
</Button>
|
|
171
|
+
) : null}
|
|
172
|
+
</div>
|
|
173
|
+
{error ? (
|
|
174
|
+
<p className="text-destructive px-4 py-2 text-xs">{error}</p>
|
|
175
|
+
) : null}
|
|
176
|
+
|
|
177
|
+
<div className="border-border grid min-h-0 flex-1 grid-rows-[auto_1fr]">
|
|
178
|
+
<div className="border-border max-h-56 min-h-0 overflow-y-auto border-b px-4 py-3">
|
|
179
|
+
{items.length ? (
|
|
180
|
+
<RunTimeline items={items} />
|
|
181
|
+
) : (
|
|
182
|
+
<p className="text-muted-foreground text-xs">等待运行…</p>
|
|
183
|
+
)}
|
|
184
|
+
</div>
|
|
185
|
+
<div className="min-h-0 p-4">
|
|
186
|
+
{/* ⭐ Phosphor well: token surfaces (not the kit's hard zinc), green glow, scanlines
|
|
187
|
+
and a corner vignette on top. Square-ish corners — rounds read as a chat app. */}
|
|
188
|
+
<div
|
|
189
|
+
className="border-border relative h-full min-h-0 overflow-hidden rounded-lg border"
|
|
190
|
+
style={{
|
|
191
|
+
textShadow:
|
|
192
|
+
"0 0 6px color-mix(in oklch, var(--primary) 65%, transparent)",
|
|
193
|
+
}}
|
|
194
|
+
>
|
|
195
|
+
<Terminal
|
|
196
|
+
className="border-border bg-card text-card-foreground h-full rounded-lg"
|
|
197
|
+
lines={live ? live.split("\n") : ["$ 输出会实时写到这里", "$ █"]}
|
|
198
|
+
/>
|
|
199
|
+
<div
|
|
200
|
+
aria-hidden
|
|
201
|
+
className="pointer-events-none absolute inset-0"
|
|
202
|
+
style={{
|
|
203
|
+
backgroundImage:
|
|
204
|
+
"repeating-linear-gradient(0deg, color-mix(in oklch, var(--foreground) 7%, transparent) 0 1px, transparent 1px 3px)," +
|
|
205
|
+
"radial-gradient(120% 90% at 50% 40%, transparent 62%, var(--shadow))",
|
|
206
|
+
}}
|
|
207
|
+
/>
|
|
208
|
+
</div>
|
|
209
|
+
</div>
|
|
210
|
+
</div>
|
|
211
|
+
</div>
|
|
212
|
+
);
|
|
213
|
+
}
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
// ⭐ This template needs ONE library the platform does not ship. Before `mini_app_reload`:
|
|
2
|
+
// mini_app_install({ appId: "com.example.sheets", packages: [{ name: "exceljs" }] })
|
|
3
|
+
// It lands in this app's own node_modules (--ignore-scripts, lockfile committed,
|
|
4
|
+
// node_modules not). `ui.tsx` still cannot import it — the browser bundle has its own
|
|
5
|
+
// closed surface, so the workbook is parsed here and the UI only sees JSON.
|
|
6
|
+
import ExcelJS from "exceljs";
|
|
7
|
+
|
|
8
|
+
// ⭐ Platform module: full lodash on both sides. Aggregates below are the case it pays for.
|
|
9
|
+
import { mean, sum } from "lodash";
|
|
10
|
+
|
|
11
|
+
import { defineApp } from "@monkey-mini-app/api";
|
|
12
|
+
|
|
13
|
+
type SheetData = {
|
|
14
|
+
name: string;
|
|
15
|
+
headers: string[];
|
|
16
|
+
/** Capped preview rows; aggregates are computed over every row. */
|
|
17
|
+
rows: Record<string, string | number>[];
|
|
18
|
+
rowCount: number;
|
|
19
|
+
columns: {
|
|
20
|
+
header: string;
|
|
21
|
+
numeric: boolean;
|
|
22
|
+
count: number;
|
|
23
|
+
min?: number;
|
|
24
|
+
max?: number;
|
|
25
|
+
total?: number;
|
|
26
|
+
avg?: number;
|
|
27
|
+
}[];
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
type Report = {
|
|
31
|
+
id: string;
|
|
32
|
+
fileName: string;
|
|
33
|
+
createdAt: number;
|
|
34
|
+
sheetCount: number;
|
|
35
|
+
rowCount: number;
|
|
36
|
+
digest?: { headline: string; bullets: string[] };
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const PREVIEW_CAP = 300;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* An `.xlsx` cell is not always a primitive: formulas carry `{ result }`, rich text
|
|
43
|
+
* carries `richText[]`, dates are `Date`, hyperlinks wrap `{ text }`. Passing those
|
|
44
|
+
* straight to the UI gives `[object Object]` in half the columns.
|
|
45
|
+
*/
|
|
46
|
+
function cellText(value: unknown): string | number | null {
|
|
47
|
+
if (value === null || value === undefined) return null;
|
|
48
|
+
if (typeof value === "number" || typeof value === "boolean")
|
|
49
|
+
return typeof value === "boolean" ? String(value) : value;
|
|
50
|
+
if (value instanceof Date) return value.toISOString().slice(0, 10);
|
|
51
|
+
if (typeof value === "object") {
|
|
52
|
+
const v = value as Record<string, unknown>;
|
|
53
|
+
if ("result" in v) return cellText(v.result);
|
|
54
|
+
if ("text" in v) return cellText(v.text);
|
|
55
|
+
if (Array.isArray(v.richText)) {
|
|
56
|
+
return (v.richText as { text?: string }[])
|
|
57
|
+
.map((p) => p.text ?? "")
|
|
58
|
+
.join("");
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return String(value);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function toNumberOrNull(value: string | number | null): number | null {
|
|
65
|
+
if (typeof value === "number") return Number.isFinite(value) ? value : null;
|
|
66
|
+
if (value === null) return null;
|
|
67
|
+
const cleaned = String(value).replace(/[,\s%]/g, "");
|
|
68
|
+
if (!cleaned || !/^-?\d+(\.\d+)?$/.test(cleaned)) return null;
|
|
69
|
+
const n = Number(cleaned);
|
|
70
|
+
return Number.isFinite(n) ? n : null;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* ⭐ exceljs re-declares a **global** `interface Buffer extends ArrayBuffer`, which poisons the
|
|
75
|
+
* `Buffer` *type name* everywhere it is imported — so the app works in `Uint8Array` and hands
|
|
76
|
+
* the reader a plain ArrayBuffer. (`as any` would hide the next real mismatch.)
|
|
77
|
+
*/
|
|
78
|
+
function toArrayBuffer(b: Uint8Array): ArrayBuffer {
|
|
79
|
+
return b.buffer.slice(
|
|
80
|
+
b.byteOffset,
|
|
81
|
+
b.byteOffset + b.byteLength,
|
|
82
|
+
) as ArrayBuffer;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
async function parseWorkbook(
|
|
86
|
+
data: Uint8Array,
|
|
87
|
+
): Promise<{ sheets: SheetData[] }> {
|
|
88
|
+
const wb = new ExcelJS.Workbook();
|
|
89
|
+
// exceljs parses the bytes in-process: no temp file on disk, nothing uploaded.
|
|
90
|
+
await wb.xlsx.load(toArrayBuffer(data));
|
|
91
|
+
const sheets: SheetData[] = [];
|
|
92
|
+
wb.worksheets.forEach((ws) => {
|
|
93
|
+
if (!ws.rowCount) return;
|
|
94
|
+
const headerRow = ws.getRow(1);
|
|
95
|
+
const width = headerRow.cellCount;
|
|
96
|
+
const headers: string[] = [];
|
|
97
|
+
for (let c = 1; c <= width; c++) {
|
|
98
|
+
headers.push(String(cellText(headerRow.getCell(c).value) ?? `列${c}`));
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const matrix: (string | number | null)[][] = [];
|
|
102
|
+
ws.eachRow((row, rowNumber) => {
|
|
103
|
+
if (rowNumber === 1) return;
|
|
104
|
+
const line: (string | number | null)[] = [];
|
|
105
|
+
for (let c = 1; c <= width; c++)
|
|
106
|
+
line.push(cellText(row.getCell(c).value));
|
|
107
|
+
if (line.some((x) => x !== null && x !== "")) matrix.push(line);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
const columns = headers.map((header, i) => {
|
|
111
|
+
const nums = matrix
|
|
112
|
+
.map((r) => toNumberOrNull(r[i] ?? null))
|
|
113
|
+
.filter((n): n is number => n !== null);
|
|
114
|
+
// A column is numeric when most of its cells parse as numbers: one stray text
|
|
115
|
+
// cell in an amount column must not demote the whole column to text.
|
|
116
|
+
const numeric = nums.length > 0 && nums.length >= matrix.length * 0.6;
|
|
117
|
+
return {
|
|
118
|
+
header,
|
|
119
|
+
numeric,
|
|
120
|
+
count: matrix.length,
|
|
121
|
+
min: numeric ? Math.min(...nums) : undefined,
|
|
122
|
+
max: numeric ? Math.max(...nums) : undefined,
|
|
123
|
+
total: numeric ? Number(sum(nums).toFixed(2)) : undefined,
|
|
124
|
+
avg: numeric ? Number(mean(nums).toFixed(2)) : undefined,
|
|
125
|
+
};
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
sheets.push({
|
|
129
|
+
name: ws.name,
|
|
130
|
+
headers,
|
|
131
|
+
rowCount: matrix.length,
|
|
132
|
+
columns,
|
|
133
|
+
rows: matrix.slice(0, PREVIEW_CAP).map((r) => {
|
|
134
|
+
const obj: Record<string, string | number> = {};
|
|
135
|
+
headers.forEach((h, i) => {
|
|
136
|
+
obj[h] = (r[i] ?? "") as string | number;
|
|
137
|
+
});
|
|
138
|
+
return obj;
|
|
139
|
+
}),
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
return { sheets };
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function digestPrompt(sheets: SheetData[]): string {
|
|
146
|
+
const lines: string[] = [];
|
|
147
|
+
for (const s of sheets.slice(0, 6)) {
|
|
148
|
+
lines.push(`### ${s.name}(${s.rowCount} 行)`);
|
|
149
|
+
for (const c of s.columns.slice(0, 12)) {
|
|
150
|
+
lines.push(
|
|
151
|
+
c.numeric
|
|
152
|
+
? `- ${c.header}: n=${c.count} 合计=${c.total} 均值=${c.avg} 最小=${c.min} 最大=${c.max}`
|
|
153
|
+
: `- ${c.header}: 文本列,${c.count} 行`,
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return [
|
|
158
|
+
"下面是用户本机一份 Excel 的结构与数值汇总(已抽样,未逐行列出)。",
|
|
159
|
+
"用中文写业务结论,不要复述列名清单,不要提 lodash / exceljs / storage 这些实现细节。",
|
|
160
|
+
"",
|
|
161
|
+
lines.join("\n"),
|
|
162
|
+
"",
|
|
163
|
+
"返回 JSON:{ headline: 一句话结论, bullets: 3-5 条值得关注的点(含具体数字) }",
|
|
164
|
+
].join("\n");
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
async function loadSheets(ctx, id: string): Promise<SheetData[]> {
|
|
168
|
+
const stored = await ctx.storage.table("reports").get(id);
|
|
169
|
+
if (!stored || !Array.isArray(stored.sheets)) {
|
|
170
|
+
throw new Error("找不到该报表,请重新拖入文件");
|
|
171
|
+
}
|
|
172
|
+
return stored.sheets as SheetData[];
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
export default defineApp({
|
|
176
|
+
name: "表格台",
|
|
177
|
+
description: "文件进,格子上干活,哪里变了",
|
|
178
|
+
api: {
|
|
179
|
+
/** ⭐ History survives reload: the parse result lives on disk, not in a tab. */
|
|
180
|
+
async list(ctx) {
|
|
181
|
+
const index = await ctx.storage.get("index");
|
|
182
|
+
return Array.isArray(index) ? index : [];
|
|
183
|
+
},
|
|
184
|
+
|
|
185
|
+
/** Full report (incl. sheets) for a history row — index alone has no payload. */
|
|
186
|
+
async get(ctx, args) {
|
|
187
|
+
const id = String(args?.id ?? "");
|
|
188
|
+
const stored = await ctx.storage.table("reports").get(id);
|
|
189
|
+
if (!stored) throw new Error("找不到该报表,请重新拖入文件");
|
|
190
|
+
return stored;
|
|
191
|
+
},
|
|
192
|
+
|
|
193
|
+
async ingest(ctx, args) {
|
|
194
|
+
const fileName = String(args?.fileName ?? "").trim() || "未命名报表";
|
|
195
|
+
const base64 = String(args?.base64 ?? "");
|
|
196
|
+
if (!base64) throw new Error("文件内容为空");
|
|
197
|
+
|
|
198
|
+
const data = new Uint8Array(Buffer.from(base64, "base64"));
|
|
199
|
+
let sheets: SheetData[];
|
|
200
|
+
try {
|
|
201
|
+
sheets = (await parseWorkbook(data)).sheets;
|
|
202
|
+
} catch (cause) {
|
|
203
|
+
throw new Error(
|
|
204
|
+
`无法读取这个 Excel:${cause instanceof Error ? cause.message : String(cause)}(仅支持 .xlsx,旧版 .xls 需要先另存为 .xlsx)`,
|
|
205
|
+
);
|
|
206
|
+
}
|
|
207
|
+
if (!sheets.length) throw new Error("工作簿里没有带数据的表");
|
|
208
|
+
|
|
209
|
+
const id = "r_" + Date.now().toString(36);
|
|
210
|
+
const report = {
|
|
211
|
+
id,
|
|
212
|
+
fileName,
|
|
213
|
+
createdAt: Date.now(),
|
|
214
|
+
sheetCount: sheets.length,
|
|
215
|
+
rowCount: sheets.reduce((n, s) => n + s.rowCount, 0),
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
// ⭐ Big payload → its own table (one file per report); the index stays tiny so
|
|
219
|
+
// `list` is cheap. Same reason the UI gets preview rows, not the whole sheet.
|
|
220
|
+
await ctx.storage.table("reports").set(id, { ...report, sheets });
|
|
221
|
+
const index = [report, ...((await ctx.storage.get("index")) ?? [])].slice(
|
|
222
|
+
0,
|
|
223
|
+
30,
|
|
224
|
+
);
|
|
225
|
+
await ctx.storage.set("index", index);
|
|
226
|
+
|
|
227
|
+
return { ...report, sheets };
|
|
228
|
+
},
|
|
229
|
+
|
|
230
|
+
/** ⭐ The host's model, called from a button. No API key in this file, no second SDK. */
|
|
231
|
+
async digest(ctx, args) {
|
|
232
|
+
const id = String(args?.id ?? "");
|
|
233
|
+
const sheets = await loadSheets(ctx, id);
|
|
234
|
+
const text = await ctx.llm(digestPrompt(sheets), {
|
|
235
|
+
schema: {
|
|
236
|
+
type: "object",
|
|
237
|
+
properties: {
|
|
238
|
+
headline: { type: "string" },
|
|
239
|
+
bullets: { type: "array", items: { type: "string" } },
|
|
240
|
+
},
|
|
241
|
+
required: ["headline", "bullets"],
|
|
242
|
+
},
|
|
243
|
+
});
|
|
244
|
+
let digest = { headline: "模型没有返回结论", bullets: [] as string[] };
|
|
245
|
+
try {
|
|
246
|
+
const parsed = JSON.parse(text);
|
|
247
|
+
digest = {
|
|
248
|
+
headline: String(parsed.headline ?? digest.headline),
|
|
249
|
+
bullets: Array.isArray(parsed.bullets)
|
|
250
|
+
? parsed.bullets.map(String)
|
|
251
|
+
: [],
|
|
252
|
+
};
|
|
253
|
+
} catch {
|
|
254
|
+
digest = { headline: text.slice(0, 120), bullets: [] };
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
const stored = await ctx.storage.table("reports").get(id);
|
|
258
|
+
await ctx.storage.table("reports").set(id, { ...stored, digest });
|
|
259
|
+
const index = ((await ctx.storage.get("index")) ?? []).map((r) =>
|
|
260
|
+
r.id === id ? { ...r, digest } : r,
|
|
261
|
+
);
|
|
262
|
+
await ctx.storage.set("index", index);
|
|
263
|
+
return digest;
|
|
264
|
+
},
|
|
265
|
+
|
|
266
|
+
async remove(ctx, args) {
|
|
267
|
+
const id = String(args?.id ?? "");
|
|
268
|
+
await ctx.storage.table("reports").delete(id);
|
|
269
|
+
await ctx.storage.set(
|
|
270
|
+
"index",
|
|
271
|
+
((await ctx.storage.get("index")) ?? []).filter((r) => r.id !== id),
|
|
272
|
+
);
|
|
273
|
+
return { ok: true };
|
|
274
|
+
},
|
|
275
|
+
},
|
|
276
|
+
});
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/* name: 桌面分栏 */
|
|
2
|
+
/* Look-owned palette: walnut desk + amber desk-lamp. The papers are cream in BOTH modes —
|
|
3
|
+
a dark desk with lamp-lit paper is the desk; dark papers would read as mud. All ink is
|
|
4
|
+
dark in both modes for the same reason, so `--foreground` is never painted on the wood. */
|
|
5
|
+
:root[data-mode="light"] {
|
|
6
|
+
--bg: #8a6845;
|
|
7
|
+
--fg: #33260f;
|
|
8
|
+
--surface: #faf5ea;
|
|
9
|
+
--surface-fg: #33260f;
|
|
10
|
+
--border: #6b4f2c;
|
|
11
|
+
--muted: #ebdfc6;
|
|
12
|
+
--muted-fg: #74603f;
|
|
13
|
+
--primary: #a8741c;
|
|
14
|
+
--primary-fg: #fdf6e7;
|
|
15
|
+
--secondary: #efe3c8;
|
|
16
|
+
--secondary-fg: #33260f;
|
|
17
|
+
--accent: #e9d9b4;
|
|
18
|
+
--accent-fg: #33260f;
|
|
19
|
+
--destructive: #a13d2d;
|
|
20
|
+
--destructive-fg: #fff8ee;
|
|
21
|
+
--ring: #c98f2e;
|
|
22
|
+
--input: #c7ab7d;
|
|
23
|
+
--radius: 12px;
|
|
24
|
+
--shadow: rgba(48, 32, 12, 0.42);
|
|
25
|
+
}
|
|
26
|
+
:root[data-mode="dark"] {
|
|
27
|
+
--bg: #2f2311;
|
|
28
|
+
--fg: #2e2113;
|
|
29
|
+
--surface: #f0e6cf;
|
|
30
|
+
--surface-fg: #2e2113;
|
|
31
|
+
--border: #7a5a30;
|
|
32
|
+
--muted: #e2d5b8;
|
|
33
|
+
--muted-fg: #5f4d30;
|
|
34
|
+
--primary: #a8741c;
|
|
35
|
+
--primary-fg: #fdf6e7;
|
|
36
|
+
--secondary: #e6d9b6;
|
|
37
|
+
--secondary-fg: #2e2113;
|
|
38
|
+
--accent: #dfcf9f;
|
|
39
|
+
--accent-fg: #2e2113;
|
|
40
|
+
--destructive: #b04938;
|
|
41
|
+
--destructive-fg: #fff3ec;
|
|
42
|
+
--ring: #d9a643;
|
|
43
|
+
--input: #e2d3ae;
|
|
44
|
+
--radius: 12px;
|
|
45
|
+
--shadow: rgba(8, 5, 1, 0.6);
|
|
46
|
+
}
|