@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,117 @@
|
|
|
1
|
+
import { useEffect, useState } from "react";
|
|
2
|
+
|
|
3
|
+
import { Badge, Button, Icon, Terminal, useApp } from "@monkey-mini-app/ui";
|
|
4
|
+
|
|
5
|
+
type Job = { id: string; title: string };
|
|
6
|
+
type Run = {
|
|
7
|
+
id: string;
|
|
8
|
+
title: string;
|
|
9
|
+
command: string;
|
|
10
|
+
stdout: string;
|
|
11
|
+
stderr: string;
|
|
12
|
+
exitCode: number;
|
|
13
|
+
at: number;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export default function Ui() {
|
|
17
|
+
const { call } = useApp();
|
|
18
|
+
const [jobs, setJobs] = useState<Job[]>([]);
|
|
19
|
+
const [run, setRun] = useState<Run | null>(null);
|
|
20
|
+
const [busy, setBusy] = useState<string | null>(null);
|
|
21
|
+
const [error, setError] = useState<string | null>(null);
|
|
22
|
+
|
|
23
|
+
useEffect(() => {
|
|
24
|
+
void call("jobs", {}).then((d) =>
|
|
25
|
+
setJobs((d as { jobs: Job[] }).jobs ?? []),
|
|
26
|
+
);
|
|
27
|
+
}, [call]);
|
|
28
|
+
|
|
29
|
+
async function runJob(id: string) {
|
|
30
|
+
setBusy(id);
|
|
31
|
+
setError(null);
|
|
32
|
+
try {
|
|
33
|
+
setRun((await call("run", { id })) as Run);
|
|
34
|
+
} catch (e) {
|
|
35
|
+
setError(String((e as Error)?.message || e));
|
|
36
|
+
} finally {
|
|
37
|
+
setBusy(null);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const lines = run
|
|
42
|
+
? [
|
|
43
|
+
`$ ${run.command}`,
|
|
44
|
+
run.stdout.trim() || "(no stdout)",
|
|
45
|
+
run.stderr.trim() ? `stderr:\n${run.stderr.trim()}` : "",
|
|
46
|
+
`exit ${run.exitCode}`,
|
|
47
|
+
].filter(Boolean)
|
|
48
|
+
: ["点一个按钮。没有对话框,没有模型。"];
|
|
49
|
+
|
|
50
|
+
return (
|
|
51
|
+
// ⭐ Look: terminal — buttons on top, kit Terminal well below. Never a prompt box.
|
|
52
|
+
<div className="flex h-full min-h-0 flex-col bg-background">
|
|
53
|
+
<div className="flex items-center gap-2 border-b px-4 py-3">
|
|
54
|
+
{/* one state lamp, not three decorative traffic lights: colour = state, and a literal
|
|
55
|
+
`fill-emerald-400` would fight this look's phosphor ground. */}
|
|
56
|
+
<span
|
|
57
|
+
className={`size-2 rounded-full ${busy ? "bg-primary/50" : run ? (run.exitCode === 0 ? "bg-primary" : "bg-destructive") : "bg-muted-foreground/40"}`}
|
|
58
|
+
/>
|
|
59
|
+
<span className="font-mono text-xs">chores</span>
|
|
60
|
+
{run ? (
|
|
61
|
+
<Badge
|
|
62
|
+
variant={run.exitCode === 0 ? "default" : "destructive"}
|
|
63
|
+
className="ml-auto"
|
|
64
|
+
>
|
|
65
|
+
{run.exitCode === 0 ? "ok" : "fail"}
|
|
66
|
+
</Badge>
|
|
67
|
+
) : null}
|
|
68
|
+
</div>
|
|
69
|
+
<div className="flex flex-wrap gap-2 px-4 py-3">
|
|
70
|
+
{jobs.map((j) => (
|
|
71
|
+
<Button
|
|
72
|
+
key={j.id}
|
|
73
|
+
size="sm"
|
|
74
|
+
variant="outline"
|
|
75
|
+
disabled={busy !== null}
|
|
76
|
+
onClick={() => void runJob(j.id)}
|
|
77
|
+
>
|
|
78
|
+
{busy === j.id ? (
|
|
79
|
+
<Icon.Loader2 className="animate-spin" size={14} />
|
|
80
|
+
) : (
|
|
81
|
+
<Icon.Play size={14} />
|
|
82
|
+
)}
|
|
83
|
+
{j.title}
|
|
84
|
+
</Button>
|
|
85
|
+
))}
|
|
86
|
+
</div>
|
|
87
|
+
{error ? <p className="text-destructive px-4 text-sm">{error}</p> : null}
|
|
88
|
+
<div className="min-h-0 flex-1 p-3">
|
|
89
|
+
{/* ⭐ Same phosphor well as `runner`: token surfaces instead of the kit's hard zinc,
|
|
90
|
+
green glow, scanlines + vignette on a click-through overlay. */}
|
|
91
|
+
<div
|
|
92
|
+
className="border-border relative h-full min-h-0 overflow-hidden rounded-lg border"
|
|
93
|
+
style={{
|
|
94
|
+
textShadow:
|
|
95
|
+
"0 0 6px color-mix(in oklch, var(--primary) 65%, transparent)",
|
|
96
|
+
}}
|
|
97
|
+
>
|
|
98
|
+
<Terminal
|
|
99
|
+
className="bg-card text-card-foreground h-full rounded-lg"
|
|
100
|
+
lines={
|
|
101
|
+
lines.length ? lines : ["$ 挑一个上面的按钮,本机跑一条", "$ █"]
|
|
102
|
+
}
|
|
103
|
+
/>
|
|
104
|
+
<div
|
|
105
|
+
aria-hidden
|
|
106
|
+
className="pointer-events-none absolute inset-0"
|
|
107
|
+
style={{
|
|
108
|
+
backgroundImage:
|
|
109
|
+
"repeating-linear-gradient(0deg, color-mix(in oklch, var(--foreground) 7%, transparent) 0 1px, transparent 1px 3px)," +
|
|
110
|
+
"radial-gradient(120% 90% at 50% 40%, transparent 62%, var(--shadow))",
|
|
111
|
+
}}
|
|
112
|
+
/>
|
|
113
|
+
</div>
|
|
114
|
+
</div>
|
|
115
|
+
</div>
|
|
116
|
+
);
|
|
117
|
+
}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { defineApp } from "@monkey-mini-app/api";
|
|
2
2
|
|
|
3
|
-
export default
|
|
3
|
+
export default defineApp({
|
|
4
4
|
name: "骨架示例",
|
|
5
5
|
description: "最小可运行:一次 call 往返 + 读 Host 配置",
|
|
6
6
|
api: {
|
|
7
|
-
// ⭐
|
|
7
|
+
// ⭐ key: every method receives the same ctx — appId / appDir / storage / config / log / capabilities (unused on this page)
|
|
8
8
|
async ping(ctx) {
|
|
9
9
|
return {
|
|
10
|
-
appId: ctx.appId, //
|
|
11
|
-
theme: ctx.config?.theme ?? "light", //
|
|
10
|
+
appId: ctx.appId, // reverse-DNS id of the current mini-app
|
|
11
|
+
theme: ctx.config?.theme ?? "light", // follows the Host theme (changeable in Settings / top bar)
|
|
12
12
|
now: Date.now(),
|
|
13
13
|
};
|
|
14
14
|
},
|
|
@@ -1,20 +1,29 @@
|
|
|
1
1
|
import { useEffect, useState } from "react";
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
|
|
3
|
+
import {
|
|
4
|
+
AppShell,
|
|
5
|
+
Badge,
|
|
6
|
+
Card,
|
|
7
|
+
CardContent,
|
|
8
|
+
CardHeader,
|
|
9
|
+
CardTitle,
|
|
10
|
+
Icon,
|
|
11
|
+
PageHeader,
|
|
12
|
+
useApp,
|
|
13
|
+
} from "@monkey-mini-app/ui";
|
|
5
14
|
|
|
6
15
|
type Ping = { appId: string; theme: string; now: number };
|
|
7
16
|
|
|
8
17
|
export default function Ui() {
|
|
9
|
-
// ⭐
|
|
10
|
-
// method
|
|
11
|
-
const { call } =
|
|
18
|
+
// ⭐ key: the backend is reachable through **one** entry only — useApp().call(method, args)
|
|
19
|
+
// method must be a key of defineApp({ api }); the UI never imports main.api.ts.
|
|
20
|
+
const { call } = useApp();
|
|
12
21
|
const [data, setData] = useState<Ping | null>(null);
|
|
13
22
|
const [loading, setLoading] = useState(true);
|
|
14
23
|
const [error, setError] = useState<string | null>(null);
|
|
15
24
|
|
|
16
25
|
useEffect(() => {
|
|
17
|
-
// ⭐
|
|
26
|
+
// ⭐ key: don't setState after the component unmounts (long/slow tasks with cancellation: see radar / runner)
|
|
18
27
|
let alive = true;
|
|
19
28
|
(async () => {
|
|
20
29
|
try {
|
|
@@ -35,8 +44,8 @@ export default function Ui() {
|
|
|
35
44
|
const label = error ? "出错" : loading ? "连接中" : "正常";
|
|
36
45
|
|
|
37
46
|
return (
|
|
38
|
-
// ⭐
|
|
39
|
-
//
|
|
47
|
+
// ⭐ key: wrap the page in AppShell (optional sidebar/header), use PageHeader for the page header.
|
|
48
|
+
// This is the "skeleton baseline"; other templates put lists/kanban/charts inside main.
|
|
40
49
|
<AppShell header={<PageHeader title="骨架示例" description="最小可运行结构" />}>
|
|
41
50
|
<div className="max-w-xl">
|
|
42
51
|
<Card>
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { EV, type Payload, type Progress } from "../shared/events";
|
|
2
|
+
import { SAMPLE_ITEMS } from "../shared/sample";
|
|
3
|
+
|
|
4
|
+
const DIGEST_SCHEMA = {
|
|
5
|
+
type: "object",
|
|
6
|
+
properties: {
|
|
7
|
+
headline: { type: "string" },
|
|
8
|
+
bullets: { type: "array", items: { type: "string" } },
|
|
9
|
+
},
|
|
10
|
+
required: ["headline", "bullets"],
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
function parseDigest(raw: string): { headline: string; bullets: string[] } {
|
|
14
|
+
let value: { headline?: unknown; bullets?: unknown };
|
|
15
|
+
try {
|
|
16
|
+
value = JSON.parse(raw);
|
|
17
|
+
} catch {
|
|
18
|
+
throw new Error("模型没有返回 JSON:" + String(raw).slice(0, 180));
|
|
19
|
+
}
|
|
20
|
+
const headline = String(value?.headline ?? "").trim();
|
|
21
|
+
const bullets = Array.isArray(value.bullets)
|
|
22
|
+
? value.bullets.map((b) => String(b).trim()).filter(Boolean).slice(0, 3)
|
|
23
|
+
: [];
|
|
24
|
+
if (!headline || bullets.length !== 3) throw new Error("摘要格式不对");
|
|
25
|
+
return { headline, bullets };
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function sleep(ms: number, signal?: AbortSignal) {
|
|
29
|
+
return new Promise<void>((resolve) => {
|
|
30
|
+
if (signal?.aborted) return resolve();
|
|
31
|
+
const t = setTimeout(resolve, ms);
|
|
32
|
+
signal?.addEventListener(
|
|
33
|
+
"abort",
|
|
34
|
+
() => {
|
|
35
|
+
clearTimeout(t);
|
|
36
|
+
resolve();
|
|
37
|
+
},
|
|
38
|
+
{ once: true },
|
|
39
|
+
);
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// ⭐ key: long job lives in api/ (backend only). UI must not import this file.
|
|
44
|
+
export async function runRefresh(ctx): Promise<Payload> {
|
|
45
|
+
const items = SAMPLE_ITEMS.slice(0, 8);
|
|
46
|
+
const report = async (partial: Partial<Progress>) => {
|
|
47
|
+
const next: Progress = { running: true, step: "refresh", done: 0, total: 3, ...partial };
|
|
48
|
+
await ctx.storage.set("progress", next);
|
|
49
|
+
ctx.push(EV.progress, next);
|
|
50
|
+
};
|
|
51
|
+
try {
|
|
52
|
+
await report({ step: "fetch·sample 8/8", done: 1 });
|
|
53
|
+
if (ctx.signal?.aborted) throw new Error("cancelled");
|
|
54
|
+
await sleep(300, ctx.signal);
|
|
55
|
+
|
|
56
|
+
await report({ step: "summarize#1/1", done: 2 });
|
|
57
|
+
const raw = await ctx.llm(
|
|
58
|
+
"根据这些标题写一条中文 headline,以及恰好 3 条中文 bullets。不要前言:\n" +
|
|
59
|
+
items.map((i) => "- " + i.title).join("\n"),
|
|
60
|
+
{ schema: DIGEST_SCHEMA },
|
|
61
|
+
);
|
|
62
|
+
if (ctx.signal?.aborted) throw new Error("cancelled");
|
|
63
|
+
const digest = parseDigest(raw);
|
|
64
|
+
|
|
65
|
+
const payload: Payload = { items, digest, at: Date.now() };
|
|
66
|
+
await ctx.storage.set("latest", payload);
|
|
67
|
+
const done: Progress = { running: false, step: "done", done: 3, total: 3 };
|
|
68
|
+
await ctx.storage.set("progress", done);
|
|
69
|
+
ctx.push(EV.progress, done);
|
|
70
|
+
ctx.push(EV.latest, payload);
|
|
71
|
+
return payload;
|
|
72
|
+
} catch (cause) {
|
|
73
|
+
const message = cause instanceof Error ? cause.message : String(cause);
|
|
74
|
+
const failed: Progress = { running: false, step: "failed", done: 0, total: 3, error: message };
|
|
75
|
+
await ctx.storage.set("progress", failed);
|
|
76
|
+
ctx.push(EV.progress, failed);
|
|
77
|
+
throw new Error("摘要失败:" + message);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { defineApp } from "@monkey-mini-app/api";
|
|
2
|
+
|
|
3
|
+
import { runRefresh } from "./api/scan";
|
|
4
|
+
import { type Payload, type Progress } from "./shared/events";
|
|
5
|
+
import { SAMPLE_ITEMS } from "./shared/sample";
|
|
6
|
+
|
|
7
|
+
export default defineApp({
|
|
8
|
+
name: "信息雷达",
|
|
9
|
+
description: "拉源、做简报、长任务可取消",
|
|
10
|
+
api: {
|
|
11
|
+
async latest(ctx): Promise<Payload> {
|
|
12
|
+
return (await ctx.storage.get("latest")) || { items: SAMPLE_ITEMS, digest: null, at: 0 };
|
|
13
|
+
},
|
|
14
|
+
|
|
15
|
+
// fire-and-forget: returns immediately; api/scan.ts pushes progress over SSE
|
|
16
|
+
async scan(ctx) {
|
|
17
|
+
void runRefresh(ctx);
|
|
18
|
+
return { ok: true };
|
|
19
|
+
},
|
|
20
|
+
|
|
21
|
+
async scanStatus(ctx): Promise<Progress> {
|
|
22
|
+
return (await ctx.storage.get("progress")) || { running: false, step: "idle", done: 0, total: 3 };
|
|
23
|
+
},
|
|
24
|
+
|
|
25
|
+
async refresh(ctx) {
|
|
26
|
+
return runRefresh(ctx);
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
});
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// ⭐ key: names AND payloads live here so ui.tsx and api/ cannot drift.
|
|
2
|
+
// Pure isomorphic: no React, no ctx, no DOM, no Node.
|
|
3
|
+
export const EV = {
|
|
4
|
+
progress: "progress",
|
|
5
|
+
latest: "latest",
|
|
6
|
+
} as const;
|
|
7
|
+
|
|
8
|
+
export type Events = {
|
|
9
|
+
progress: {
|
|
10
|
+
running: boolean;
|
|
11
|
+
step: string;
|
|
12
|
+
done: number;
|
|
13
|
+
total: number;
|
|
14
|
+
error?: string;
|
|
15
|
+
};
|
|
16
|
+
latest: {
|
|
17
|
+
items: { title: string; link?: string }[];
|
|
18
|
+
digest: { headline: string; bullets: string[] } | null;
|
|
19
|
+
at: number;
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export type EventName = keyof Events;
|
|
24
|
+
export type Progress = Events["progress"];
|
|
25
|
+
export type Payload = Events["latest"];
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export type FeedItem = { title: string; link?: string };
|
|
2
2
|
|
|
3
|
-
//
|
|
3
|
+
// Built-in sample feed: no network by default so it runs offline (teaches "prove the full pipeline with a sample")
|
|
4
4
|
export const SAMPLE_ITEMS: FeedItem[] = [
|
|
5
5
|
{ title: "TypeScript 5.7 发布:更快的类型检查与更好的模块解析", link: "https://example.com/ts57" },
|
|
6
6
|
{ title: "Vite 6 默认启用 Rolldown 路线图", link: "https://example.com/vite6" },
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/* name: 编辑排版 */
|
|
2
|
+
/* Look-owned palette: paper and ink are the identity — under the default kit palette the
|
|
3
|
+
page is just text and reads as "unfinished". Light is newsprint with vermilion (E1),
|
|
4
|
+
dark is cool night-reading stock with ultramarine (E2). Radius is small: this look is
|
|
5
|
+
rules and type, not cards. */
|
|
6
|
+
:root[data-mode="light"] {
|
|
7
|
+
--bg: #f6f2e9;
|
|
8
|
+
--fg: #1c1a16;
|
|
9
|
+
--surface: #fffdf7;
|
|
10
|
+
--surface-fg: #1c1a16;
|
|
11
|
+
--border: #e0d9c9;
|
|
12
|
+
--muted: #ece5d6;
|
|
13
|
+
--muted-fg: #6d675c;
|
|
14
|
+
--primary: #c0402a;
|
|
15
|
+
--primary-fg: #fff8f5;
|
|
16
|
+
--secondary: #efe8da;
|
|
17
|
+
--secondary-fg: #1c1a16;
|
|
18
|
+
--accent: #f1e9d9;
|
|
19
|
+
--accent-fg: #1c1a16;
|
|
20
|
+
--destructive: #8f2d22;
|
|
21
|
+
--destructive-fg: #fff4f1;
|
|
22
|
+
--ring: #c0402a;
|
|
23
|
+
--input: #d9d2c2;
|
|
24
|
+
--radius: 6px;
|
|
25
|
+
--shadow: rgba(60, 50, 30, 0.18);
|
|
26
|
+
}
|
|
27
|
+
:root[data-mode="dark"] {
|
|
28
|
+
--bg: #14161a;
|
|
29
|
+
--fg: #e8eaee;
|
|
30
|
+
--surface: #191c22;
|
|
31
|
+
--surface-fg: #e8eaee;
|
|
32
|
+
--border: #262a31;
|
|
33
|
+
--muted: #1d2128;
|
|
34
|
+
--muted-fg: #9aa0aa;
|
|
35
|
+
--primary: #7f95f5;
|
|
36
|
+
--primary-fg: #0f1216;
|
|
37
|
+
--secondary: #1d2128;
|
|
38
|
+
--secondary-fg: #e8eaee;
|
|
39
|
+
--accent: #1a2030;
|
|
40
|
+
--accent-fg: #e8eaee;
|
|
41
|
+
--destructive: #ff6b63;
|
|
42
|
+
--destructive-fg: #14060a;
|
|
43
|
+
--ring: #7f95f5;
|
|
44
|
+
--input: #2a2d31;
|
|
45
|
+
--radius: 6px;
|
|
46
|
+
--shadow: rgba(0, 0, 0, 0.5);
|
|
47
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { Payload } from "../shared/events";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* UI-only. The brief is an article, not a card: kicker → serif display → numbered bullets,
|
|
5
|
+
* limited measure. That is the whole `editorial` grammar (references/looks/editorial.md).
|
|
6
|
+
*/
|
|
7
|
+
export function Brief({ data, stale }: { data: Payload | null; stale: boolean }) {
|
|
8
|
+
const digest = data?.digest;
|
|
9
|
+
return (
|
|
10
|
+
<article className="max-w-2xl">
|
|
11
|
+
<p className="text-muted-foreground text-xs tracking-[0.2em] uppercase">
|
|
12
|
+
本期简报 {data?.at ? `· ${new Date(data.at).toLocaleDateString("zh-CN")}` : ""}
|
|
13
|
+
</p>
|
|
14
|
+
<h2 className="mt-3 font-serif text-3xl leading-snug font-bold tracking-tight">
|
|
15
|
+
{digest ? digest.headline : stale ? "还没有简报,点右上角整理一次" : "正在整理…"}
|
|
16
|
+
</h2>
|
|
17
|
+
{digest?.bullets?.length ? (
|
|
18
|
+
<ol className="text-muted-foreground mt-6 flex list-none flex-col gap-4 p-0">
|
|
19
|
+
{digest.bullets.map((b, i) => (
|
|
20
|
+
<li key={i} className="flex gap-4 text-sm leading-relaxed">
|
|
21
|
+
<span className="text-primary font-mono text-xs tabular-nums">
|
|
22
|
+
{String(i + 1).padStart(2, "0")}
|
|
23
|
+
</span>
|
|
24
|
+
<span className="text-foreground">{b}</span>
|
|
25
|
+
</li>
|
|
26
|
+
))}
|
|
27
|
+
</ol>
|
|
28
|
+
) : null}
|
|
29
|
+
</article>
|
|
30
|
+
);
|
|
31
|
+
}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { useEffect, useState } from "react";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
AppShell,
|
|
5
|
+
Button,
|
|
6
|
+
DetailPanel,
|
|
7
|
+
Icon,
|
|
8
|
+
PageHeader,
|
|
9
|
+
Progress,
|
|
10
|
+
Separator,
|
|
11
|
+
useApp,
|
|
12
|
+
} from "@monkey-mini-app/ui";
|
|
13
|
+
|
|
14
|
+
import { EV, type Payload, type Progress as ScanProgress } from "./shared/events";
|
|
15
|
+
import { Brief } from "./ui/brief";
|
|
16
|
+
|
|
17
|
+
type Item = Payload["items"][number];
|
|
18
|
+
|
|
19
|
+
export default function Ui() {
|
|
20
|
+
const { call, on } = useApp();
|
|
21
|
+
const [data, setData] = useState<Payload | null>(null);
|
|
22
|
+
const [progress, setProgress] = useState<ScanProgress | null>(null);
|
|
23
|
+
const [selected, setSelected] = useState<Item | null>(null);
|
|
24
|
+
const [error, setError] = useState<string | null>(null);
|
|
25
|
+
|
|
26
|
+
const load = async () => setData((await call("latest", {})) as Payload);
|
|
27
|
+
|
|
28
|
+
// ⭐ key: on(EV.progress) / ctx.push(EV.progress) — the name exists only in shared/events.ts.
|
|
29
|
+
useEffect(() => {
|
|
30
|
+
const offProgress = on(EV.progress, (d) => {
|
|
31
|
+
const p = d as ScanProgress;
|
|
32
|
+
setProgress(p);
|
|
33
|
+
if (!p.running && !p.error) void load();
|
|
34
|
+
if (p.error) setError(p.error);
|
|
35
|
+
});
|
|
36
|
+
const offLatest = on(EV.latest, (d) => setData(d as Payload));
|
|
37
|
+
return () => {
|
|
38
|
+
offProgress();
|
|
39
|
+
offLatest();
|
|
40
|
+
};
|
|
41
|
+
}, [on]);
|
|
42
|
+
|
|
43
|
+
async function run() {
|
|
44
|
+
setError(null);
|
|
45
|
+
try {
|
|
46
|
+
await call("scan", {}); // fire-and-forget start, returns immediately
|
|
47
|
+
} catch (e) {
|
|
48
|
+
setError(String((e as Error)?.message || e));
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
useEffect(() => {
|
|
53
|
+
void load();
|
|
54
|
+
}, [call]);
|
|
55
|
+
|
|
56
|
+
const items = data?.items ?? [];
|
|
57
|
+
const running = Boolean(progress?.running);
|
|
58
|
+
const pct = progress && progress.total ? Math.round((progress.done / progress.total) * 100) : 0;
|
|
59
|
+
|
|
60
|
+
return (
|
|
61
|
+
<AppShell
|
|
62
|
+
header={
|
|
63
|
+
<PageHeader
|
|
64
|
+
title="信息雷达"
|
|
65
|
+
description="公开头条 · 模型整理成三条要点"
|
|
66
|
+
actions={
|
|
67
|
+
<Button disabled={running} onClick={() => void run()}>
|
|
68
|
+
<Icon.Sparkles size={16} strokeWidth={2} /> 整理
|
|
69
|
+
</Button>
|
|
70
|
+
}
|
|
71
|
+
/>
|
|
72
|
+
}
|
|
73
|
+
>
|
|
74
|
+
{/* ⭐ Look: editorial — one prose column, hairline rules, a numbered index. No card soup. */}
|
|
75
|
+
<div className="mx-auto flex h-full min-h-0 w-full max-w-3xl flex-col gap-6 overflow-y-auto px-2 py-2">
|
|
76
|
+
{running ? (
|
|
77
|
+
<div className="flex items-center gap-3">
|
|
78
|
+
<Progress value={pct} className="h-1 flex-1" />
|
|
79
|
+
<span className="text-muted-foreground font-mono text-xs">{progress?.step}</span>
|
|
80
|
+
</div>
|
|
81
|
+
) : null}
|
|
82
|
+
{error ? <p className="text-destructive text-sm">{error}</p> : null}
|
|
83
|
+
|
|
84
|
+
<Brief data={data} stale={!running} />
|
|
85
|
+
|
|
86
|
+
<Separator />
|
|
87
|
+
|
|
88
|
+
<section>
|
|
89
|
+
<p className="text-muted-foreground mb-2 text-xs tracking-[0.2em] uppercase">
|
|
90
|
+
来源索引 · {items.length}
|
|
91
|
+
</p>
|
|
92
|
+
<ul className="list-none p-0">
|
|
93
|
+
{items.map((it, i) => (
|
|
94
|
+
<li key={it.title + i} className="border-border border-b last:border-b-0">
|
|
95
|
+
<button
|
|
96
|
+
type="button"
|
|
97
|
+
onClick={() => setSelected(it)}
|
|
98
|
+
className="hover:bg-muted/50 flex w-full items-baseline gap-4 px-2 py-3 text-left"
|
|
99
|
+
>
|
|
100
|
+
<span className="text-muted-foreground font-mono text-xs tabular-nums">
|
|
101
|
+
{String(i + 1).padStart(2, "0")}
|
|
102
|
+
</span>
|
|
103
|
+
<span className="min-w-0 flex-1 truncate text-sm">{it.title}</span>
|
|
104
|
+
<Icon.ArrowUpRight size={14} strokeWidth={2} className="text-muted-foreground shrink-0" />
|
|
105
|
+
</button>
|
|
106
|
+
</li>
|
|
107
|
+
))}
|
|
108
|
+
</ul>
|
|
109
|
+
</section>
|
|
110
|
+
</div>
|
|
111
|
+
|
|
112
|
+
{/* reading a source is still a sheet — the look governs the page, not every overlay */}
|
|
113
|
+
<DetailPanel
|
|
114
|
+
open={Boolean(selected)}
|
|
115
|
+
onOpenChange={(o) => {
|
|
116
|
+
if (!o) setSelected(null);
|
|
117
|
+
}}
|
|
118
|
+
title={selected?.title ?? ""}
|
|
119
|
+
>
|
|
120
|
+
<div className="flex flex-col gap-3">
|
|
121
|
+
<p className="text-sm">{selected?.title}</p>
|
|
122
|
+
{selected?.link ? (
|
|
123
|
+
<a href={selected.link} target="_blank" rel="noreferrer" className="text-primary text-xs hover:underline">
|
|
124
|
+
阅读原文
|
|
125
|
+
</a>
|
|
126
|
+
) : null}
|
|
127
|
+
</div>
|
|
128
|
+
</DetailPanel>
|
|
129
|
+
</AppShell>
|
|
130
|
+
);
|
|
131
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { defineApp } from "@monkey-mini-app/api";
|
|
2
|
+
|
|
3
|
+
import { EV, type Run, type Step } from "./shared/events";
|
|
4
|
+
|
|
5
|
+
// ⭐ key: ctx.agent is the entry point for "have the model do one multi-step job"; it returns the final string.
|
|
6
|
+
// Progress reaches the UI over `ctx.push(...)` (SSE) — no polling. `streamTo` mirrors the agent's own
|
|
7
|
+
// events onto one channel; lifecycle changes are pushed explicitly.
|
|
8
|
+
// The run is ALSO persisted, so reopening the app shows the last run instead of a blank screen.
|
|
9
|
+
// Cancellation: a module-level AbortController (the app module loads once, so a var can hold it).
|
|
10
|
+
|
|
11
|
+
const EMPTY: Run = { goal: "", status: "idle", steps: [], result: "", startedAt: 0 };
|
|
12
|
+
|
|
13
|
+
let currentAbort: AbortController | null = null;
|
|
14
|
+
|
|
15
|
+
async function load(ctx: { storage: { get(k: string): Promise<unknown> } }): Promise<Run> {
|
|
16
|
+
return ((await ctx.storage.get("run")) as Run) || EMPTY;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** Persist + stream one change. Storage is the snapshot, `push` is the live feed. */
|
|
20
|
+
async function save(ctx, run: Run, patch?: Partial<Run>) {
|
|
21
|
+
const next: Run = { ...run, ...(patch || {}) };
|
|
22
|
+
await ctx.storage.set("run", next);
|
|
23
|
+
ctx.push(EV.run, next);
|
|
24
|
+
return next;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export default defineApp({
|
|
28
|
+
name: "执行器",
|
|
29
|
+
description: "模型自己走多步,UI 就是这条 run,可取消",
|
|
30
|
+
api: {
|
|
31
|
+
/** Snapshot for first paint: fetch once on mount, then live-update from events. */
|
|
32
|
+
async runStatus(ctx) {
|
|
33
|
+
return load(ctx);
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
// start returns immediately; the agent runs in the background and pushes as it goes
|
|
37
|
+
async start(ctx, args?: { goal?: string }) {
|
|
38
|
+
const goal = String(args?.goal ?? "").trim();
|
|
39
|
+
if (!goal) throw new Error("请输入目标");
|
|
40
|
+
currentAbort?.abort();
|
|
41
|
+
const ac = new AbortController();
|
|
42
|
+
currentAbort = ac;
|
|
43
|
+
|
|
44
|
+
let run = await save(ctx, { ...EMPTY, goal, startedAt: Date.now() }, { status: "running" });
|
|
45
|
+
|
|
46
|
+
void ctx
|
|
47
|
+
.agent(goal, {
|
|
48
|
+
signal: ac.signal,
|
|
49
|
+
maxIterations: 12,
|
|
50
|
+
// ⭐ streamTo uses the same name the UI subscribes to (EV.agent)
|
|
51
|
+
streamTo: EV.agent,
|
|
52
|
+
onEvent: async (ev) => {
|
|
53
|
+
// onEvent still runs — use it to keep the durable snapshot, not to feed the UI
|
|
54
|
+
if (ev.type !== "tool" && ev.type !== "turn" && ev.type !== "done" && ev.type !== "error") {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
const step: Step =
|
|
58
|
+
ev.type === "tool"
|
|
59
|
+
? { phase: "tool", name: ev.name, at: Date.now() }
|
|
60
|
+
: ev.type === "turn"
|
|
61
|
+
? { phase: "turn", turn: ev.turn, at: Date.now() }
|
|
62
|
+
: ev.type === "done"
|
|
63
|
+
? { phase: "done", at: Date.now() }
|
|
64
|
+
: { phase: "error", text: ev.message, at: Date.now() };
|
|
65
|
+
run = { ...run, steps: [...run.steps, step] };
|
|
66
|
+
await ctx.storage.set("run", run);
|
|
67
|
+
},
|
|
68
|
+
})
|
|
69
|
+
.then(async (text) => {
|
|
70
|
+
const cur = await load(ctx);
|
|
71
|
+
await save(ctx, cur, { status: "done", result: text.slice(-4000) });
|
|
72
|
+
if (currentAbort === ac) currentAbort = null;
|
|
73
|
+
})
|
|
74
|
+
.catch(async (cause) => {
|
|
75
|
+
const msg = String((cause as Error)?.message || cause);
|
|
76
|
+
const cur = await load(ctx);
|
|
77
|
+
await save(ctx, cur, { status: "error", result: msg });
|
|
78
|
+
if (currentAbort === ac) currentAbort = null;
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
return { ok: true, started: true };
|
|
82
|
+
},
|
|
83
|
+
|
|
84
|
+
async cancel(ctx) {
|
|
85
|
+
currentAbort?.abort();
|
|
86
|
+
currentAbort = null;
|
|
87
|
+
await save(ctx, await load(ctx), { status: "cancelled" });
|
|
88
|
+
return { ok: true };
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export type Step = { phase: string; name?: string; turn?: number; text?: string; at: number };
|
|
2
|
+
export type Run = { goal: string; status: string; steps: Step[]; result: string; startedAt: number };
|
|
3
|
+
|
|
4
|
+
export const EV = {
|
|
5
|
+
run: "run",
|
|
6
|
+
agent: "agent",
|
|
7
|
+
} as const;
|
|
8
|
+
|
|
9
|
+
export type Events = {
|
|
10
|
+
run: Run;
|
|
11
|
+
agent: unknown;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export type EventName = keyof Events;
|