@notis_ai/cli 0.2.18 → 0.2.19
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 +542 -146
- package/bin/check-runtime.js +15 -0
- package/bin/notis.js +2 -0
- package/config/notis_app_design_rules.json +320 -0
- package/config/portal-route-roots.json +45 -0
- package/dist/agent-hooks/notis-agent-hook.mjs +42325 -18273
- package/dist/base-skills/notis-cli/.notis-base-skill.json +1 -0
- package/dist/base-skills/notis-cli/SKILL.md +51 -280
- package/dist/base-skills/notis-cli/references/app-delivery.md +17 -0
- package/dist/base-skills/notis-cli/references/intelligence.md +94 -0
- package/dist/base-skills/notis-cli/references/native-databases.md +21 -0
- package/dist/base-skills/notis-cli/references/tool-examples.md +56 -0
- package/dist/base-skills/notis-cli/references/troubleshooting.md +67 -0
- package/dist/base-skills/notis-query/.notis-base-skill.json +1 -0
- package/dist/base-skills/notis-query/SKILL.md +35 -699
- package/dist/base-skills/notis-query/references/database-discovery.md +59 -0
- package/dist/base-skills/notis-query/references/documents.md +74 -0
- package/dist/base-skills/notis-query/references/query.md +76 -0
- package/dist/base-skills/notis-spaces/.notis-base-skill.json +1 -0
- package/dist/base-skills/notis-spaces/SKILL.md +218 -0
- package/dist/base-skills/notis-spaces/references/architecture.md +116 -0
- package/dist/base-skills/notis-spaces/references/context.md +81 -0
- package/dist/base-skills/notis-spaces/references/design.md +141 -0
- package/dist/base-skills/notis-spaces/references/fixtures.md +29 -0
- package/dist/base-skills/notis-spaces/references/memory.md +58 -0
- package/dist/base-skills/notis-spaces/references/reading.md +73 -0
- package/dist/base-skills/notis-spaces/references/release.md +120 -0
- package/dist/base-skills/notis-spaces/references/reports.md +77 -0
- package/dist/base-skills/notis-spaces/references/sdk.md +273 -0
- package/dist/base-skills/notis-spaces/references/store.md +118 -0
- package/dist/base-skills/notis-spaces/references/troubleshooting.md +28 -0
- package/dist/base-skills/notis-spaces/references/views.md +229 -0
- package/{template/packages → dist}/sdk/package.json +9 -10
- package/dist/sdk/src/agentContext.ts +36 -0
- package/dist/sdk/src/bundleModule.ts +175 -0
- package/dist/sdk/src/components/Dialog.tsx +103 -0
- package/dist/sdk/src/components/DocumentEditor.tsx +113 -0
- package/dist/sdk/src/components/DocumentPage.tsx +184 -0
- package/{template/packages → dist}/sdk/src/components/Markdown.tsx +9 -3
- package/{template/packages → dist}/sdk/src/components/MarkdownEditor.tsx +26 -5
- package/{template/packages → dist}/sdk/src/components/MultiSelectActionBar.tsx +95 -12
- package/{template/packages → dist}/sdk/src/components/MultiSelectCheckbox.tsx +4 -2
- package/dist/sdk/src/components/NotisCommentBoundary.tsx +172 -0
- package/{template/packages → dist}/sdk/src/components/NotisSelectionBoundary.tsx +9 -5
- package/dist/sdk/src/components/RecordComponents.tsx +111 -0
- package/dist/sdk/src/components/Skeleton.tsx +38 -0
- package/dist/sdk/src/config.ts +31 -0
- package/{template/packages → dist}/sdk/src/documents.ts +21 -6
- package/dist/sdk/src/hooks/useAction.ts +28 -0
- package/dist/sdk/src/hooks/useAgentContext.ts +23 -0
- package/{template/packages → dist}/sdk/src/hooks/useBackend.ts +3 -2
- package/dist/sdk/src/hooks/useCloudComputer.ts +94 -0
- package/dist/sdk/src/hooks/useCloudComputerShell.ts +114 -0
- package/{template/packages → dist}/sdk/src/hooks/useCollectionInteractions.ts +157 -147
- package/dist/sdk/src/hooks/useDatabaseSchema.ts +50 -0
- package/{template/packages → dist}/sdk/src/hooks/useDatabaseSubscription.ts +2 -2
- package/dist/sdk/src/hooks/useDocument.ts +51 -0
- package/{template/packages → dist}/sdk/src/hooks/useDocuments.ts +25 -59
- package/{template/packages → dist}/sdk/src/hooks/useHandover.ts +7 -7
- package/dist/sdk/src/hooks/useLongPressSelection.ts +79 -0
- package/dist/sdk/src/hooks/useMarqueeSelection.ts +194 -0
- package/{template/packages → dist}/sdk/src/hooks/useMultiSelect.ts +2 -8
- package/dist/sdk/src/hooks/useNativeDocumentBody.ts +50 -0
- package/dist/sdk/src/hooks/useNativeDocuments.ts +143 -0
- package/{template/packages → dist}/sdk/src/hooks/useNotis.ts +6 -1
- package/dist/sdk/src/hooks/useNotisNavigation.ts +70 -0
- package/dist/sdk/src/hooks/useQuery.ts +81 -0
- package/dist/sdk/src/hooks/useToolQuery.ts +12 -0
- package/dist/sdk/src/hooks/useTopBarSearch.ts +102 -0
- package/dist/sdk/src/hooks/useTopBarTitleLeaf.ts +75 -0
- package/{template/packages → dist}/sdk/src/hooks/useUpsertDocument.ts +1 -1
- package/dist/sdk/src/hooks/useViewParams.ts +195 -0
- package/dist/sdk/src/hooks/useViewerReads.ts +129 -0
- package/{template/packages → dist}/sdk/src/index.ts +64 -1
- package/{template/packages → dist}/sdk/src/interactions/actions.ts +14 -1
- package/{template/packages → dist}/sdk/src/interactions/shortcuts.tsx +129 -23
- package/dist/sdk/src/interactions/visibility.ts +13 -0
- package/{template/packages → dist}/sdk/src/interactions.ts +5 -1
- package/dist/sdk/src/nativeData.ts +39 -0
- package/{template/packages → dist}/sdk/src/provider.tsx +9 -4
- package/dist/sdk/src/queryCache.ts +292 -0
- package/dist/sdk/src/queryErrors.ts +51 -0
- package/dist/sdk/src/runtime.ts +675 -0
- package/dist/sdk/src/runtimeModules.ts +33 -0
- package/dist/sdk/src/space.ts +442 -0
- package/dist/sdk/src/standardViewParams.ts +36 -0
- package/{template/packages → dist}/sdk/src/styles.css +81 -16
- package/dist/sdk/src/tailwind.ts +66 -0
- package/dist/sdk/src/ui/charts/RenderChartData.tsx +25 -0
- package/dist/sdk/src/ui/engine/core.ts +392 -0
- package/dist/sdk/src/ui/engine/dom.ts +183 -0
- package/dist/sdk/src/ui/engine/hooks.ts +195 -0
- package/dist/sdk/src/ui/engine/instance.ts +63 -0
- package/dist/sdk/src/ui/engine/keycapContext.ts +2 -0
- package/dist/sdk/src/ui/engine/registry.ts +262 -0
- package/dist/sdk/src/ui/engine/types.ts +62 -0
- package/dist/sdk/src/ui/icons.tsx +91 -0
- package/dist/sdk/src/ui/util.ts +83 -0
- package/dist/sdk/src/viewPeriod.ts +26 -0
- package/dist/sdk/src/vite.ts +92 -0
- package/dist/sdk/src/words/actions.ts +295 -0
- package/dist/sdk/src/words/clashes.ts +158 -0
- package/dist/sdk/src/words/format.ts +136 -0
- package/dist/sdk/src/words/index.ts +13 -0
- package/dist/sdk/src/words/keymap.ts +72 -0
- package/dist/sdk/src/words/keys.ts +297 -0
- package/dist/sdk/src/words/shell.ts +46 -0
- package/dist/sdk/src/words/types.ts +65 -0
- package/dist/skill-sync/index.js +832 -151
- package/dist/skill-sync/index.js.map +4 -4
- package/dist/skill-sync-worker.mjs +3941 -0
- package/dist/space-harness/host.js +1460 -0
- package/dist/space-sdk/dist/chunk-ZSN57ATH.js +5 -0
- package/dist/space-sdk/dist/index.js +15 -0
- package/dist/space-sdk/dist/ui.js +18 -0
- package/dist/space-sdk/package.json +33 -0
- package/dist/space-sdk/src/agentContext.d.ts +36 -0
- package/dist/space-sdk/src/components/Dialog.d.ts +20 -0
- package/dist/space-sdk/src/components/DocumentEditor.d.ts +46 -0
- package/dist/space-sdk/src/components/DocumentPage.d.ts +53 -0
- package/dist/space-sdk/src/components/Markdown.d.ts +18 -0
- package/dist/space-sdk/src/components/MarkdownEditor.d.ts +11 -0
- package/dist/space-sdk/src/components/MultiSelectActionBar.d.ts +31 -0
- package/dist/space-sdk/src/components/MultiSelectCheckbox.d.ts +14 -0
- package/dist/space-sdk/src/components/MultiSelectDragOverlay.d.ts +8 -0
- package/dist/space-sdk/src/components/NotisCommentBoundary.d.ts +36 -0
- package/dist/space-sdk/src/components/NotisSelectionBoundary.d.ts +16 -0
- package/dist/space-sdk/src/components/RecordComponents.d.ts +64 -0
- package/dist/space-sdk/src/components/ShortcutHints.d.ts +12 -0
- package/dist/space-sdk/src/components/Skeleton.d.ts +23 -0
- package/dist/space-sdk/src/config.ts +31 -0
- package/dist/space-sdk/src/documents.d.ts +59 -0
- package/dist/space-sdk/src/hooks/useAction.d.ts +8 -0
- package/dist/space-sdk/src/hooks/useActiveResource.d.ts +3 -0
- package/dist/space-sdk/src/hooks/useAgentContext.d.ts +7 -0
- package/dist/space-sdk/src/hooks/useBackend.d.ts +23 -0
- package/dist/space-sdk/src/hooks/useCloudComputer.d.ts +45 -0
- package/dist/space-sdk/src/hooks/useCloudComputerShell.d.ts +49 -0
- package/dist/space-sdk/src/hooks/useCollectionInteractions.d.ts +118 -0
- package/dist/space-sdk/src/hooks/useDatabaseSchema.d.ts +14 -0
- package/dist/space-sdk/src/hooks/useDatabaseSubscription.d.ts +26 -0
- package/dist/space-sdk/src/hooks/useDocument.d.ts +22 -0
- package/dist/space-sdk/src/hooks/useDocuments.d.ts +31 -0
- package/dist/space-sdk/src/hooks/useHandover.d.ts +43 -0
- package/dist/space-sdk/src/hooks/useLongPressSelection.d.ts +9 -0
- package/dist/space-sdk/src/hooks/useMarqueeSelection.d.ts +57 -0
- package/dist/space-sdk/src/hooks/useMultiSelect.d.ts +51 -0
- package/dist/space-sdk/src/hooks/useNativeDocumentBody.d.ts +24 -0
- package/dist/space-sdk/src/hooks/useNativeDocuments.d.ts +55 -0
- package/dist/space-sdk/src/hooks/useNotis.d.ts +25 -0
- package/dist/space-sdk/src/hooks/useNotisNavigation.d.ts +33 -0
- package/dist/space-sdk/src/hooks/useQuery.d.ts +22 -0
- package/dist/space-sdk/src/hooks/useTool.d.ts +20 -0
- package/dist/space-sdk/src/hooks/useToolQuery.d.ts +3 -0
- package/dist/space-sdk/src/hooks/useTools.d.ts +15 -0
- package/dist/space-sdk/src/hooks/useTopBarSearch.d.ts +48 -0
- package/dist/space-sdk/src/hooks/useTopBarTitleLeaf.d.ts +24 -0
- package/dist/space-sdk/src/hooks/useUpsertDocument.d.ts +27 -0
- package/dist/space-sdk/src/hooks/useViewParams.d.ts +76 -0
- package/dist/space-sdk/src/hooks/useViewerReads.d.ts +38 -0
- package/dist/space-sdk/src/index.d.ts +98 -0
- package/dist/space-sdk/src/interactions/actions.d.ts +33 -0
- package/dist/space-sdk/src/interactions/shortcuts.d.ts +42 -0
- package/dist/space-sdk/src/interactions/visibility.d.ts +2 -0
- package/dist/space-sdk/src/nativeData.d.ts +66 -0
- package/dist/space-sdk/src/provider.d.ts +17 -0
- package/dist/space-sdk/src/queryCache.d.ts +45 -0
- package/dist/space-sdk/src/queryErrors.ts +51 -0
- package/dist/space-sdk/src/runtime.d.ts +615 -0
- package/dist/space-sdk/src/runtimeModules.ts +33 -0
- package/dist/space-sdk/src/space.ts +442 -0
- package/dist/space-sdk/src/standardViewParams.d.ts +15 -0
- package/dist/space-sdk/src/tailwind-candidates.d.ts +3418 -0
- package/dist/space-sdk/src/tailwind.ts +66 -0
- package/dist/space-sdk/src/ui/actions/ActionToast.d.ts +15 -0
- package/dist/space-sdk/src/ui/actions/actionWords.d.ts +16 -0
- package/dist/space-sdk/src/ui/actions/index.d.ts +7 -0
- package/dist/space-sdk/src/ui/actions/useActions.d.ts +69 -0
- package/dist/space-sdk/src/ui/actions/useToast.d.ts +41 -0
- package/dist/space-sdk/src/ui/blocks/Tabs.d.ts +139 -0
- package/dist/space-sdk/src/ui/blocks/blocks.d.ts +217 -0
- package/dist/space-sdk/src/ui/blocks/index.d.ts +4 -0
- package/dist/space-sdk/src/ui/board/BoardView.d.ts +36 -0
- package/dist/space-sdk/src/ui/board/boardModel.d.ts +46 -0
- package/dist/space-sdk/src/ui/board/boardWords.d.ts +9 -0
- package/dist/space-sdk/src/ui/board/index.d.ts +5 -0
- package/dist/space-sdk/src/ui/calendar/CalendarView.d.ts +49 -0
- package/dist/space-sdk/src/ui/calendar/DayPicker.d.ts +23 -0
- package/dist/space-sdk/src/ui/calendar/calendarMath.d.ts +81 -0
- package/dist/space-sdk/src/ui/charts/Chart.d.ts +203 -0
- package/dist/space-sdk/src/ui/charts/ChartTable.d.ts +37 -0
- package/dist/space-sdk/src/ui/charts/RenderChartData.d.ts +16 -0
- package/dist/space-sdk/src/ui/charts/StatRow.d.ts +59 -0
- package/dist/space-sdk/src/ui/charts/chartData.d.ts +84 -0
- package/dist/space-sdk/src/ui/comments/CommentPane.d.ts +58 -0
- package/dist/space-sdk/src/ui/comments/commentModel.d.ts +157 -0
- package/dist/space-sdk/src/ui/comments/commentWords.d.ts +60 -0
- package/dist/space-sdk/src/ui/comments/index.d.ts +4 -0
- package/dist/space-sdk/src/ui/comments/useComments.d.ts +146 -0
- package/dist/space-sdk/src/ui/engine/HelpSheet.d.ts +12 -0
- package/dist/space-sdk/src/ui/engine/KeyboardEngine.d.ts +27 -0
- package/dist/space-sdk/src/ui/engine/core.d.ts +73 -0
- package/dist/space-sdk/src/ui/engine/hooks.d.ts +64 -0
- package/dist/space-sdk/src/ui/engine/index.d.ts +14 -0
- package/dist/space-sdk/src/ui/engine/instance.d.ts +21 -0
- package/dist/space-sdk/src/ui/engine/keycapContext.d.ts +2 -0
- package/dist/space-sdk/src/ui/engine/registry.d.ts +77 -0
- package/dist/space-sdk/src/ui/engine/step.d.ts +11 -0
- package/dist/space-sdk/src/ui/engine/types.d.ts +54 -0
- package/dist/space-sdk/src/ui/fields/fieldWords.d.ts +56 -0
- package/dist/space-sdk/src/ui/fields/fields.d.ts +162 -0
- package/dist/space-sdk/src/ui/fields/index.d.ts +5 -0
- package/dist/space-sdk/src/ui/fields/useFieldDraft.d.ts +22 -0
- package/dist/space-sdk/src/ui/gallery/AttachmentGallery.d.ts +53 -0
- package/dist/space-sdk/src/ui/gallery/ImageViewer.d.ts +27 -0
- package/dist/space-sdk/src/ui/gallery/galleryWords.d.ts +95 -0
- package/dist/space-sdk/src/ui/gallery/index.d.ts +5 -0
- package/dist/space-sdk/src/ui/icons.d.ts +13 -0
- package/dist/space-sdk/src/ui/index.d.ts +54 -0
- package/dist/space-sdk/src/ui/keycap/Keycap.d.ts +22 -0
- package/dist/space-sdk/src/ui/keycap/index.d.ts +2 -0
- package/dist/space-sdk/src/ui/layout/Panels.d.ts +50 -0
- package/dist/space-sdk/src/ui/layout/chatPanelEdge.d.ts +77 -0
- package/dist/space-sdk/src/ui/layout/index.d.ts +5 -0
- package/dist/space-sdk/src/ui/layout/panelMath.d.ts +91 -0
- package/dist/space-sdk/src/ui/list/ListReader.d.ts +380 -0
- package/dist/space-sdk/src/ui/list/Row.d.ts +145 -0
- package/dist/space-sdk/src/ui/list/SelectionBar.d.ts +65 -0
- package/dist/space-sdk/src/ui/list/index.d.ts +14 -0
- package/dist/space-sdk/src/ui/list/rowState.d.ts +22 -0
- package/dist/space-sdk/src/ui/list/useListKeys.d.ts +89 -0
- package/dist/space-sdk/src/ui/list/useReorder.d.ts +86 -0
- package/dist/space-sdk/src/ui/list/useSelection.d.ts +90 -0
- package/dist/space-sdk/src/ui/open/OpenAsMenu.d.ts +15 -0
- package/dist/space-sdk/src/ui/open/index.d.ts +6 -0
- package/dist/space-sdk/src/ui/open/openModeStore.d.ts +39 -0
- package/dist/space-sdk/src/ui/open/useOpenMode.d.ts +17 -0
- package/dist/space-sdk/src/ui/overlay/Menu.d.ts +88 -0
- package/dist/space-sdk/src/ui/overlay/Popover.d.ts +28 -0
- package/dist/space-sdk/src/ui/overlay/Tooltip.d.ts +19 -0
- package/dist/space-sdk/src/ui/overlay/index.d.ts +9 -0
- package/dist/space-sdk/src/ui/overlay/layerRoot.d.ts +24 -0
- package/dist/space-sdk/src/ui/overlay/position.d.ts +31 -0
- package/dist/space-sdk/src/ui/period/PeriodPicker.d.ts +30 -0
- package/dist/space-sdk/src/ui/period/dateFormat.d.ts +50 -0
- package/dist/space-sdk/src/ui/period/dateWords.d.ts +88 -0
- package/dist/space-sdk/src/ui/period/periods.d.ts +70 -0
- package/dist/space-sdk/src/ui/period/usePeriod.d.ts +23 -0
- package/dist/space-sdk/src/ui/present/index.d.ts +3 -0
- package/dist/space-sdk/src/ui/present/presentWords.d.ts +27 -0
- package/dist/space-sdk/src/ui/present/screens.d.ts +36 -0
- package/dist/space-sdk/src/ui/present/useAudienceScreen.d.ts +38 -0
- package/dist/space-sdk/src/ui/styles.d.ts +21 -0
- package/dist/space-sdk/src/ui/timeline/TimelineView.d.ts +44 -0
- package/dist/space-sdk/src/ui/timeline/timelineMath.d.ts +123 -0
- package/dist/space-sdk/src/viewPeriod.d.ts +8 -0
- package/dist/space-sdk/src/vite.ts +92 -0
- package/dist/space-sdk/src/words/actions.ts +295 -0
- package/dist/space-sdk/src/words/clashes.ts +158 -0
- package/dist/space-sdk/src/words/format.ts +136 -0
- package/dist/space-sdk/src/words/index.ts +13 -0
- package/dist/space-sdk/src/words/keymap.ts +72 -0
- package/dist/space-sdk/src/words/keys.ts +297 -0
- package/dist/space-sdk/src/words/shell.ts +46 -0
- package/dist/space-sdk/src/words/types.ts +65 -0
- package/dist/view-renderer/dist/host.css +1 -0
- package/dist/view-renderer/dist/host.js +2374 -0
- package/dist/view-renderer/dist/theme.css +73 -0
- package/dist/view-renderer/src/dom.js +212 -0
- package/dist/view-renderer/src/errors.js +8 -0
- package/dist/view-renderer/src/host.tsx +250 -0
- package/dist/view-renderer/src/index.js +4 -0
- package/dist/view-renderer/src/png.js +213 -0
- package/dist/view-renderer/src/pool.js +110 -0
- package/dist/view-renderer/src/remote-broker.js +59 -0
- package/dist/view-renderer/src/renderer.js +271 -0
- package/package.json +21 -11
- package/skills/notis-cli/AGENT_INSTRUCTIONS.md +63 -12
- package/skills/notis-onboarding/BRIEF.md +14 -9
- package/skills/notis-query/cli.md +1 -1
- package/skills/notis-spaces/cli.md +540 -0
- package/src/cli.js +8 -8
- package/src/command-specs/agents.js +121 -8
- package/src/command-specs/auth.js +3 -3
- package/src/command-specs/diagnostics.js +97 -20
- package/src/command-specs/documents.js +158 -0
- package/src/command-specs/files.js +29 -0
- package/src/command-specs/handover.js +331 -79
- package/src/command-specs/helpers.js +50 -40
- package/src/command-specs/index.js +14 -5
- package/src/command-specs/meta.js +38 -9
- package/src/command-specs/onboarding.js +1 -1
- package/src/command-specs/profile.js +42 -1
- package/src/command-specs/skills.js +314 -9
- package/src/command-specs/smoke.js +16 -4
- package/src/command-specs/spaces.js +783 -0
- package/src/command-specs/tools.js +118 -21
- package/src/command-specs/version-history.js +20 -0
- package/src/command-specs/views.js +69 -0
- package/src/runtime/agent-browser.js +178 -267
- package/src/runtime/agent-setup.js +172 -13
- package/src/runtime/app-boundary-validator.js +338 -2
- package/src/runtime/app-data-literals.js +82 -0
- package/src/runtime/app-platform.js +750 -1570
- package/src/runtime/auth-recovery.js +17 -0
- package/src/runtime/base-skills.d.ts +11 -0
- package/src/runtime/base-skills.js +100 -3
- package/src/runtime/computer-identity.d.ts +30 -0
- package/src/runtime/computer-identity.js +151 -0
- package/src/runtime/config-lock.js +135 -0
- package/src/runtime/confined-space-build.js +74 -0
- package/src/runtime/confined-space-verify.js +49 -0
- package/src/runtime/delegated-context.js +5 -21
- package/src/runtime/native-record-files.js +47 -0
- package/src/runtime/oauth.js +342 -31
- package/src/runtime/profiles.js +19 -112
- package/src/runtime/retired-sdk-files.js +24 -0
- package/src/runtime/retry.js +150 -0
- package/src/runtime/skill-sync/cloud-client.ts +33 -8
- package/src/runtime/skill-sync/index.ts +443 -106
- package/src/runtime/skill-sync/local-scanner.ts +248 -32
- package/src/runtime/skill-sync/native-identity.ts +102 -0
- package/src/runtime/skill-sync/native-plan.ts +70 -0
- package/src/runtime/skill-sync/symlink-manager.ts +66 -16
- package/src/runtime/skill-sync/sync-plan.ts +34 -2
- package/src/runtime/skill-sync/types.ts +54 -0
- package/src/runtime/skill-sync/write-cloud-skill.ts +4 -4
- package/src/runtime/skill-sync-service.js +109 -0
- package/src/runtime/source-root.js +32 -0
- package/src/runtime/space-collection-scaffold.js +107 -0
- package/src/runtime/space-database-structures.js +229 -0
- package/src/runtime/space-fixture-broker.js +68 -0
- package/src/runtime/space-lock.js +337 -0
- package/src/runtime/space-platform.js +133 -0
- package/src/runtime/space-source.js +290 -0
- package/src/runtime/space-test-server.js +354 -0
- package/src/runtime/space-verification.js +94 -0
- package/src/runtime/space-verify-browser-worker.js +51 -0
- package/src/runtime/space-view-manifest.js +368 -0
- package/src/runtime/sync-skills.d.ts +5 -1
- package/src/runtime/sync-skills.js +11 -2
- package/src/runtime/tool-confirmation.js +138 -0
- package/src/runtime/transport.js +118 -24
- package/src/runtime/upsell.js +219 -0
- package/src/runtime/view-render.js +49 -0
- package/src/skill-sync-worker-entry.js +2 -0
- package/src/skill-sync-worker.js +114 -0
- package/src/space-harness-host.ts +122 -0
- package/template/.harness/index.html.tmpl +9 -352
- package/template/app/globals.css +29 -3
- package/template/app/layout.tsx +2 -6
- package/template/components/ui/badge.tsx +7 -4
- package/template/components/ui/button.tsx +1 -1
- package/template/components/ui/native-select.tsx +24 -0
- package/template/notis.config.ts +4 -36
- package/template/package-lock.json +1800 -1867
- package/template/package.json +16 -14
- package/template/postcss.config.mjs +1 -1
- package/template/tailwind.config.ts +1 -6
- package/template/tsconfig.json +1 -0
- package/template/vite.config.ts +2 -2
- package/dist/base-skills/notis-apps/SKILL.md +0 -613
- package/skills/notis-apps/cli.md +0 -285
- package/src/command-specs/apps.js +0 -3011
- package/src/runtime/app-changelog.js +0 -79
- package/src/runtime/app-dev-consumers.js +0 -154
- package/src/runtime/app-dev-host-lock.js +0 -80
- package/src/runtime/app-dev-process-identity.js +0 -111
- package/src/runtime/app-dev-roots.js +0 -284
- package/src/runtime/app-dev-server.js +0 -1140
- package/src/runtime/app-dev-sessions.js +0 -185
- package/src/runtime/app-registry-scaffolds.js +0 -367
- package/src/runtime/assets/store-screenshot-dark.png +0 -0
- package/src/runtime/cli-mode.generated.js +0 -5
- package/src/runtime/cli-mode.js +0 -34
- package/src/runtime/store-screenshot.js +0 -143
- package/template/CHANGELOG.md +0 -5
- package/template/app/page.tsx +0 -60
- package/template/components/ui/card.tsx +0 -56
- package/template/packages/sdk/src/components/DocumentEditor.tsx +0 -103
- package/template/packages/sdk/src/config.ts +0 -259
- package/template/packages/sdk/src/hooks/useCloudComputer.ts +0 -97
- package/template/packages/sdk/src/hooks/useDatabaseSchema.ts +0 -85
- package/template/packages/sdk/src/hooks/useDocument.ts +0 -78
- package/template/packages/sdk/src/hooks/useNotisNavigation.ts +0 -52
- package/template/packages/sdk/src/hooks/useTopBarSearch.ts +0 -73
- package/template/packages/sdk/src/runtime.ts +0 -439
- package/template/packages/sdk/src/vite.ts +0 -56
- package/template/packages/sdk/tsconfig.json +0 -15
- /package/{template/packages → dist}/sdk/src/components/MultiSelectDragOverlay.tsx +0 -0
- /package/{template/packages → dist}/sdk/src/components/ShortcutHints.tsx +0 -0
- /package/{template/packages → dist}/sdk/src/hooks/useActiveResource.ts +0 -0
- /package/{template/packages → dist}/sdk/src/hooks/useTool.ts +0 -0
- /package/{template/packages → dist}/sdk/src/hooks/useTools.ts +0 -0
- /package/{template/packages → dist}/sdk/src/ui.ts +0 -0
|
@@ -1,109 +1,7 @@
|
|
|
1
1
|
import { spawn, spawnSync } from 'node:child_process';
|
|
2
|
-
import { mkdirSync,
|
|
2
|
+
import { mkdirSync, writeFileSync } from 'node:fs';
|
|
3
3
|
import { dirname } from 'node:path';
|
|
4
4
|
|
|
5
|
-
export const HIDE_HARNESS_STATUS_SCRIPT =
|
|
6
|
-
"(() => { const el = document.getElementById('harness-status'); if (el) el.style.opacity = '0'; return true; })()";
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Prepare the mounted harness page for a listing capture: remove the debug
|
|
10
|
-
* banner and the layout the harness adds around the app (top padding for the
|
|
11
|
-
* banner, 100vh min-height) so content height can be measured and framed
|
|
12
|
-
* without artificial whitespace.
|
|
13
|
-
*/
|
|
14
|
-
const PREPARE_CAPTURE_SCRIPT =
|
|
15
|
-
"(() => { const s = document.getElementById('harness-status'); if (s) s.style.display = 'none';" +
|
|
16
|
-
" const r = document.getElementById('root'); if (r) { r.style.paddingTop = '0'; r.style.minHeight = '0'; }" +
|
|
17
|
-
" document.body.style.minHeight = '0'; document.documentElement.style.minHeight = '0'; return true; })()";
|
|
18
|
-
|
|
19
|
-
const FONTS_STATUS_SCRIPT =
|
|
20
|
-
"(() => (document.fonts ? document.fonts.status : 'loaded'))()";
|
|
21
|
-
|
|
22
|
-
const CONTENT_HEIGHT_SCRIPT =
|
|
23
|
-
'(() => { const r = document.getElementById(\'root\');' +
|
|
24
|
-
' if (!r) return Math.ceil(document.documentElement.scrollHeight);' +
|
|
25
|
-
' return Math.ceil(Math.max(r.scrollHeight, r.getBoundingClientRect().height)); })()';
|
|
26
|
-
|
|
27
|
-
// CSS viewport bounds for content-aware framing. Content shorter than the
|
|
28
|
-
// minimum gets a little breathing room; content taller than the maximum is
|
|
29
|
-
// cropped at the frame rather than shrunk into unreadably small text.
|
|
30
|
-
const MIN_CSS_VIEWPORT_HEIGHT = 720;
|
|
31
|
-
const MAX_CSS_VIEWPORT_HEIGHT = 1500;
|
|
32
|
-
|
|
33
|
-
function pngDimensions(path) {
|
|
34
|
-
try {
|
|
35
|
-
const buffer = readFileSync(path);
|
|
36
|
-
if (buffer.length < 24 || buffer.readUInt32BE(12) !== 0x49484452) {
|
|
37
|
-
return null;
|
|
38
|
-
}
|
|
39
|
-
return { width: buffer.readUInt32BE(16), height: buffer.readUInt32BE(20) };
|
|
40
|
-
} catch {
|
|
41
|
-
return null;
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Pick a CSS viewport that frames `contentHeight` at the output aspect ratio,
|
|
47
|
-
* with a deviceScaleFactor that maps it back to exactly outputWidth x
|
|
48
|
-
* outputHeight physical pixels. Width snaps to a multiple of 8 so the height
|
|
49
|
-
* stays integral for the common 16:10 target.
|
|
50
|
-
*/
|
|
51
|
-
function fitCssViewport(contentHeight, outputWidth, outputHeight) {
|
|
52
|
-
const aspect = outputWidth / outputHeight;
|
|
53
|
-
const cssH = Math.min(
|
|
54
|
-
MAX_CSS_VIEWPORT_HEIGHT,
|
|
55
|
-
Math.max(MIN_CSS_VIEWPORT_HEIGHT, Math.round(contentHeight)),
|
|
56
|
-
);
|
|
57
|
-
const cssW = Math.round((cssH * aspect) / 8) * 8;
|
|
58
|
-
return {
|
|
59
|
-
width: cssW,
|
|
60
|
-
height: Math.round(cssW / aspect),
|
|
61
|
-
scale: outputWidth / cssW,
|
|
62
|
-
};
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
async function evalNumber(sessionName, script, fallback = null) {
|
|
66
|
-
const result = await runAgentBrowser(
|
|
67
|
-
['--session', sessionName, '--json', 'eval', script],
|
|
68
|
-
{ timeoutMs: 5000 },
|
|
69
|
-
);
|
|
70
|
-
if (result.exitCode !== 0) {
|
|
71
|
-
return fallback;
|
|
72
|
-
}
|
|
73
|
-
try {
|
|
74
|
-
const payload = parseAgentBrowserJson(result.stdout);
|
|
75
|
-
const raw = payload?.data?.result ?? payload?.result ?? payload?.data ?? null;
|
|
76
|
-
const value = typeof raw === 'string' ? JSON.parse(raw) : raw;
|
|
77
|
-
return Number.isFinite(value) ? value : fallback;
|
|
78
|
-
} catch {
|
|
79
|
-
return fallback;
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
async function waitForFonts(sessionName, timeoutMs = 3000) {
|
|
84
|
-
const deadline = Date.now() + timeoutMs;
|
|
85
|
-
while (Date.now() < deadline) {
|
|
86
|
-
const result = await runAgentBrowser(
|
|
87
|
-
['--session', sessionName, '--json', 'eval', FONTS_STATUS_SCRIPT],
|
|
88
|
-
{ timeoutMs: 5000 },
|
|
89
|
-
);
|
|
90
|
-
if (result.exitCode !== 0) {
|
|
91
|
-
return;
|
|
92
|
-
}
|
|
93
|
-
try {
|
|
94
|
-
const payload = parseAgentBrowserJson(result.stdout);
|
|
95
|
-
const raw = payload?.data?.result ?? payload?.result ?? payload?.data ?? null;
|
|
96
|
-
const status = typeof raw === 'string' && raw.startsWith('"') ? JSON.parse(raw) : raw;
|
|
97
|
-
if (status !== 'loading') {
|
|
98
|
-
return;
|
|
99
|
-
}
|
|
100
|
-
} catch {
|
|
101
|
-
return;
|
|
102
|
-
}
|
|
103
|
-
await delay(150);
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
5
|
async function setViewport(sessionName, width, height, scale = null) {
|
|
108
6
|
const args = ['--session', sessionName, 'set', 'viewport', String(width), String(height)];
|
|
109
7
|
if (scale != null) {
|
|
@@ -135,9 +33,11 @@ function runAgentBrowser(args, { timeoutMs = 30_000 } = {}) {
|
|
|
135
33
|
let stdout = '';
|
|
136
34
|
let stderr = '';
|
|
137
35
|
let timedOut = false;
|
|
36
|
+
let hardStop;
|
|
138
37
|
const timer = setTimeout(() => {
|
|
139
38
|
timedOut = true;
|
|
140
39
|
child.kill('SIGTERM');
|
|
40
|
+
hardStop = setTimeout(() => child.kill('SIGKILL'), 2000);
|
|
141
41
|
}, timeoutMs);
|
|
142
42
|
|
|
143
43
|
child.stdout.on('data', (chunk) => {
|
|
@@ -147,7 +47,7 @@ function runAgentBrowser(args, { timeoutMs = 30_000 } = {}) {
|
|
|
147
47
|
stderr += chunk.toString();
|
|
148
48
|
});
|
|
149
49
|
child.on('error', (error) => {
|
|
150
|
-
clearTimeout(timer);
|
|
50
|
+
clearTimeout(timer); clearTimeout(hardStop);
|
|
151
51
|
resolvePromise({
|
|
152
52
|
exitCode: 1,
|
|
153
53
|
stdout,
|
|
@@ -156,7 +56,7 @@ function runAgentBrowser(args, { timeoutMs = 30_000 } = {}) {
|
|
|
156
56
|
});
|
|
157
57
|
});
|
|
158
58
|
child.on('close', (code) => {
|
|
159
|
-
clearTimeout(timer);
|
|
59
|
+
clearTimeout(timer); clearTimeout(hardStop);
|
|
160
60
|
resolvePromise({
|
|
161
61
|
exitCode: timedOut ? 124 : (code ?? 1),
|
|
162
62
|
stdout,
|
|
@@ -227,10 +127,19 @@ export async function runHarnessRoute({
|
|
|
227
127
|
sessionName,
|
|
228
128
|
timeoutMs = 10_000,
|
|
229
129
|
snapshotPath = null,
|
|
130
|
+
designViewports = DEFAULT_DESIGN_VIEWPORTS,
|
|
131
|
+
waitForRuntime = false,
|
|
132
|
+
signal,
|
|
230
133
|
}) {
|
|
134
|
+
const cancelled = () => ({ mounted: false, renderStarted: false, runtimeCalls: [],
|
|
135
|
+
errors: [{ phase: 'browser', message: 'Verification cancelled.' }], snapshotPath: null, tool_error: null });
|
|
136
|
+
if (signal?.aborted) return cancelled();
|
|
231
137
|
const opened = await runAgentBrowser(['--session', sessionName, 'open', url], {
|
|
232
138
|
timeoutMs: Math.min(Math.max(timeoutMs, 5000), 30_000),
|
|
233
139
|
});
|
|
140
|
+
// Let an in-flight open settle before the owner closes its browser. Closing
|
|
141
|
+
// concurrently with open can leave a newly launched browser behind.
|
|
142
|
+
if (signal?.aborted) return cancelled();
|
|
234
143
|
if (opened.exitCode !== 0) {
|
|
235
144
|
return {
|
|
236
145
|
mounted: false,
|
|
@@ -243,20 +152,26 @@ export async function runHarnessRoute({
|
|
|
243
152
|
}
|
|
244
153
|
|
|
245
154
|
const deadline = Date.now() + timeoutMs;
|
|
246
|
-
|
|
155
|
+
let readySince = null;
|
|
156
|
+
while (Date.now() < deadline && !signal?.aborted) {
|
|
247
157
|
const lastRead = await readHarness(sessionName, 5000);
|
|
248
158
|
if (!lastRead.ok) {
|
|
159
|
+
readySince = null;
|
|
249
160
|
await delay(250);
|
|
250
161
|
continue;
|
|
251
162
|
}
|
|
252
163
|
const harness = lastRead.harness;
|
|
253
|
-
if (
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
164
|
+
if (Array.isArray(harness?.errors) && harness.errors.length > 0) break;
|
|
165
|
+
const pending = (harness?.runtimeCalls || []).some(call => call?.ok == null);
|
|
166
|
+
if (harness?.mounted && (!waitForRuntime || !pending)) {
|
|
167
|
+
readySince ??= Date.now();
|
|
168
|
+
if (Date.now() - readySince >= 250) break;
|
|
169
|
+
} else readySince = null;
|
|
257
170
|
await delay(250);
|
|
258
171
|
}
|
|
259
172
|
|
|
173
|
+
if (signal?.aborted) return cancelled();
|
|
174
|
+
|
|
260
175
|
const finalRead = await readHarness(sessionName, 5000);
|
|
261
176
|
if (!finalRead.ok) {
|
|
262
177
|
return {
|
|
@@ -282,183 +197,179 @@ export async function runHarnessRoute({
|
|
|
282
197
|
}
|
|
283
198
|
}
|
|
284
199
|
|
|
285
|
-
const
|
|
200
|
+
const runtimeCalls = Array.isArray(harness.runtimeCalls) ? harness.runtimeCalls : [];
|
|
201
|
+
const timedOut = (!harness.mounted || (waitForRuntime && runtimeCalls.some(call => call?.ok == null))) && Date.now() >= deadline;
|
|
202
|
+
|
|
203
|
+
// Design assertions only mean something on a mounted route. Loading
|
|
204
|
+
// placeholders are excused while a runtime call is still in flight.
|
|
205
|
+
let design = [];
|
|
206
|
+
let designToolError = null;
|
|
207
|
+
if (harness.mounted && Array.isArray(designViewports) && designViewports.length > 0) {
|
|
208
|
+
await delay(500);
|
|
209
|
+
const pending = runtimeCalls.some((call) => call && call.ok == null);
|
|
210
|
+
const collected = await collectDesignFindings(sessionName, {
|
|
211
|
+
viewports: designViewports,
|
|
212
|
+
skipLoadingCheck: pending,
|
|
213
|
+
});
|
|
214
|
+
design = collected.findings;
|
|
215
|
+
designToolError = collected.tool_error;
|
|
216
|
+
}
|
|
217
|
+
|
|
286
218
|
return {
|
|
287
219
|
mounted: Boolean(harness.mounted),
|
|
288
220
|
renderStarted: Boolean(harness.renderStarted),
|
|
289
221
|
errors: Array.isArray(harness.errors) ? harness.errors : [],
|
|
290
|
-
runtimeCalls
|
|
222
|
+
runtimeCalls,
|
|
291
223
|
snapshotPath: savedSnapshotPath,
|
|
292
224
|
timed_out: timedOut,
|
|
293
225
|
tool_error: null,
|
|
226
|
+
design,
|
|
227
|
+
design_tool_error: designToolError,
|
|
294
228
|
raw: harness,
|
|
295
229
|
};
|
|
296
230
|
}
|
|
297
231
|
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
width = 2000,
|
|
313
|
-
height = 1250,
|
|
314
|
-
timeoutMs = 15_000,
|
|
315
|
-
}) {
|
|
316
|
-
const opened = await runAgentBrowser(['--session', sessionName, 'open', url], {
|
|
317
|
-
timeoutMs: Math.min(Math.max(timeoutMs, 5000), 30_000),
|
|
318
|
-
});
|
|
319
|
-
if (opened.exitCode !== 0) {
|
|
320
|
-
return { ok: false, mounted: false, screenshotPath: null, tool_error: commandError('open', opened) };
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
// Initial fixed frame so mount/layout happen at a deterministic size; the
|
|
324
|
-
// scale keeps physical output at width x height from the very first paint.
|
|
325
|
-
const initial = fitCssViewport(900, width, height);
|
|
326
|
-
let scaledViewport = await setViewport(
|
|
327
|
-
sessionName,
|
|
328
|
-
initial.width,
|
|
329
|
-
initial.height,
|
|
330
|
-
initial.scale,
|
|
331
|
-
);
|
|
332
|
-
if (!scaledViewport) {
|
|
333
|
-
// Older agent-browser without deviceScaleFactor support: fall back to a
|
|
334
|
-
// plain fixed viewport at output size.
|
|
335
|
-
await setViewport(sessionName, width, height);
|
|
336
|
-
}
|
|
232
|
+
export async function closeAgentBrowserSessionResult(sessionName) {
|
|
233
|
+
const started = Date.now();
|
|
234
|
+
// agent-browser waits up to 30s for CDP Browser.close and then up to 5s
|
|
235
|
+
// for its owned Chrome process. Do not kill the client at the start of the
|
|
236
|
+
// provider's shutdown grace period and lose its actual close acknowledgement.
|
|
237
|
+
const result = await runAgentBrowser(['--session', sessionName, '--json', 'close'], { timeoutMs: 40_000 });
|
|
238
|
+
let acknowledged = false;
|
|
239
|
+
try {
|
|
240
|
+
const reply = parseAgentBrowserJson(result.stdout);
|
|
241
|
+
acknowledged = reply?.success === true && reply?.data?.closed === true;
|
|
242
|
+
} catch { /* Missing acknowledgement is a failed cleanup, never a pass. */ }
|
|
243
|
+
return { ok: result.exitCode === 0 && acknowledged, exit_code: result.exitCode,
|
|
244
|
+
timed_out: Boolean(result.timedOut), duration_ms: Date.now() - started };
|
|
245
|
+
}
|
|
337
246
|
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
247
|
+
// ---------------------------------------------------------------------------
|
|
248
|
+
// Runtime design assertions.
|
|
249
|
+
//
|
|
250
|
+
// The static design lint (app-boundary-validator.js) catches banned class
|
|
251
|
+
// names. This script runs in the mounted harness page and catches what a
|
|
252
|
+
// regex cannot: a bordered box nested in a bordered box across files, tinted
|
|
253
|
+
// panels stacked three deep, text that computes below 12px, horizontal
|
|
254
|
+
// overflow at a phone width, and loading placeholders that outlive the data.
|
|
255
|
+
// Palette colors are deliberately not checked here: at runtime a token and a
|
|
256
|
+
// hardcoded hue resolve to the same RGB, so that stays with the static lint.
|
|
257
|
+
// ---------------------------------------------------------------------------
|
|
258
|
+
export const DESIGN_ASSERTIONS_MARKER = '__notisDesignAssertions';
|
|
259
|
+
|
|
260
|
+
export const DESIGN_ASSERTIONS_SCRIPT = `(() => {
|
|
261
|
+
/* ${DESIGN_ASSERTIONS_MARKER} */
|
|
262
|
+
const root = document.getElementById('root') || document.body;
|
|
263
|
+
const out = [];
|
|
264
|
+
const seen = new Set();
|
|
265
|
+
const push = (kind, el, extra) => {
|
|
266
|
+
const cls = String(el.className && el.className.baseVal !== undefined ? el.className.baseVal : el.className || '').trim().slice(0, 80);
|
|
267
|
+
const text = (el.textContent || '').trim().replace(/\\s+/g, ' ').slice(0, 60);
|
|
268
|
+
const snippet = el.tagName.toLowerCase() + (cls ? '.' + cls.split(/\\s+/).slice(0, 6).join('.') : '') + (text ? ' "' + text + '"' : '');
|
|
269
|
+
const key = kind + '|' + snippet;
|
|
270
|
+
if (seen.has(key)) return;
|
|
271
|
+
seen.add(key);
|
|
272
|
+
out.push(Object.assign({ kind, snippet }, extra || {}));
|
|
273
|
+
};
|
|
274
|
+
const controls = new Set(['INPUT', 'SELECT', 'TEXTAREA', 'BUTTON', 'A', 'SUMMARY']);
|
|
275
|
+
const isControl = (el) => controls.has(el.tagName) || /^(button|checkbox|switch|radio|combobox|textbox|tab|menuitem)$/.test(el.getAttribute('role') || '');
|
|
276
|
+
const visible = (el) => { const r = el.getBoundingClientRect(); return r.width > 0 && r.height > 0; };
|
|
277
|
+
const isBox = (el) => {
|
|
278
|
+
const cs = getComputedStyle(el);
|
|
279
|
+
if (!['borderTopWidth', 'borderRightWidth', 'borderBottomWidth', 'borderLeftWidth'].every((k) => parseFloat(cs[k]) > 0)) return false;
|
|
280
|
+
if (/rgba\\(\\d+, \\d+, \\d+, 0\\)|transparent/.test(cs.borderTopColor)) return false;
|
|
281
|
+
const r = el.getBoundingClientRect();
|
|
282
|
+
return r.width > 40 && r.height > 20;
|
|
283
|
+
};
|
|
284
|
+
const bg = (el) => getComputedStyle(el).backgroundColor;
|
|
285
|
+
const transparent = (c) => !c || c === 'transparent' || /rgba\\(\\d+, \\d+, \\d+, 0\\)/.test(c);
|
|
286
|
+
const isPanel = (el) => {
|
|
287
|
+
if (transparent(bg(el))) return false;
|
|
288
|
+
if (parseFloat(getComputedStyle(el).borderRadius) <= 0) return false;
|
|
289
|
+
const r = el.getBoundingClientRect();
|
|
290
|
+
return r.width > 160 && r.height > 48;
|
|
291
|
+
};
|
|
292
|
+
const all = Array.from(root.querySelectorAll('*'));
|
|
293
|
+
for (const el of all) {
|
|
294
|
+
if (!visible(el) || isControl(el)) continue;
|
|
295
|
+
if (isBox(el)) {
|
|
296
|
+
let p = el.parentElement; let depth = 0;
|
|
297
|
+
while (p && p !== root && depth < 6) { if (!isControl(p) && isBox(p)) { push('nested_border_box', el); break; } p = p.parentElement; depth += 1; }
|
|
353
298
|
}
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
return { ok: false, mounted, screenshotPath: null, errors: lastErrors, tool_error: null };
|
|
359
|
-
}
|
|
360
|
-
if (!mounted) {
|
|
361
|
-
return {
|
|
362
|
-
ok: false,
|
|
363
|
-
mounted: false,
|
|
364
|
-
screenshotPath: null,
|
|
365
|
-
errors: [],
|
|
366
|
-
timed_out: true,
|
|
367
|
-
tool_error: lastReadError || {
|
|
368
|
-
phase: 'harness',
|
|
369
|
-
message: 'Timed out waiting for window.__harness.mounted.',
|
|
370
|
-
},
|
|
371
|
-
};
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
// Strip harness chrome (debug banner, banner padding, 100vh min-height) so
|
|
375
|
-
// the frame contains only the app, then wait for webfonts before measuring.
|
|
376
|
-
await runAgentBrowser(
|
|
377
|
-
['--session', sessionName, 'eval', PREPARE_CAPTURE_SCRIPT],
|
|
378
|
-
{ timeoutMs: 5000 },
|
|
379
|
-
);
|
|
380
|
-
await waitForFonts(sessionName);
|
|
381
|
-
|
|
382
|
-
// Fit the CSS viewport to the rendered content. Content height depends on
|
|
383
|
-
// viewport width, so refine once after the first resize reflows the page.
|
|
384
|
-
let framing = null;
|
|
385
|
-
if (scaledViewport) {
|
|
386
|
-
let contentHeight = await evalNumber(sessionName, CONTENT_HEIGHT_SCRIPT);
|
|
387
|
-
for (let pass = 0; contentHeight != null && pass < 2; pass += 1) {
|
|
388
|
-
const fitted = fitCssViewport(contentHeight, width, height);
|
|
389
|
-
if (framing && fitted.width === framing.width) {
|
|
390
|
-
break;
|
|
391
|
-
}
|
|
392
|
-
scaledViewport = await setViewport(sessionName, fitted.width, fitted.height, fitted.scale);
|
|
393
|
-
if (!scaledViewport) {
|
|
394
|
-
framing = null;
|
|
395
|
-
await setViewport(sessionName, width, height);
|
|
396
|
-
break;
|
|
397
|
-
}
|
|
398
|
-
framing = { ...fitted, content_height: contentHeight };
|
|
399
|
-
await delay(150);
|
|
400
|
-
const remeasured = await evalNumber(sessionName, CONTENT_HEIGHT_SCRIPT);
|
|
401
|
-
if (remeasured == null || Math.abs(remeasured - contentHeight) <= 32) {
|
|
402
|
-
framing.content_height = remeasured ?? contentHeight;
|
|
403
|
-
break;
|
|
404
|
-
}
|
|
405
|
-
contentHeight = remeasured;
|
|
299
|
+
if (isPanel(el)) {
|
|
300
|
+
let p = el.parentElement; let panels = 0;
|
|
301
|
+
while (p && p !== root) { if (isPanel(p)) panels += 1; p = p.parentElement; }
|
|
302
|
+
if (panels >= 2) push('nested_tinted_panel', el, { depth: panels + 1 });
|
|
406
303
|
}
|
|
407
304
|
}
|
|
305
|
+
const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT);
|
|
306
|
+
let node;
|
|
307
|
+
while ((node = walker.nextNode())) {
|
|
308
|
+
const text = (node.textContent || '').trim();
|
|
309
|
+
if (!text) continue;
|
|
310
|
+
const el = node.parentElement;
|
|
311
|
+
if (!el || !visible(el)) continue;
|
|
312
|
+
const size = parseFloat(getComputedStyle(el).fontSize);
|
|
313
|
+
if (size > 0 && size < 12) push('text_below_12px', el, { font_size: size });
|
|
314
|
+
if (/^Loading(\\.{3}|\\u2026)?(\\s|$)/.test(text)) push('loading_placeholder_after_mount', el);
|
|
315
|
+
}
|
|
316
|
+
if (root.querySelector('[data-notis-content-skeleton]')) push('loading_placeholder_after_mount', root.querySelector('[data-notis-content-skeleton]'));
|
|
317
|
+
const doc = document.documentElement;
|
|
318
|
+
if (doc.scrollWidth > doc.clientWidth + 1) out.push({ kind: 'horizontal_overflow', snippet: 'document', scroll_width: doc.scrollWidth, client_width: doc.clientWidth });
|
|
319
|
+
return JSON.stringify(out.slice(0, 40));
|
|
320
|
+
})()`;
|
|
408
321
|
|
|
409
|
-
|
|
410
|
-
|
|
322
|
+
export const DEFAULT_DESIGN_VIEWPORTS = [
|
|
323
|
+
{ name: 'desktop', width: 1280, height: 900 },
|
|
324
|
+
{ name: 'mobile', width: 390, height: 844 },
|
|
325
|
+
];
|
|
411
326
|
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
327
|
+
/**
|
|
328
|
+
* Evaluate the design assertions in the current page. Returns an array of
|
|
329
|
+
* findings, or `{ tool_error }` when agent-browser could not run the script.
|
|
330
|
+
*/
|
|
331
|
+
export async function evalDesignAssertions(sessionName, { viewport = null, timeoutMs = 8000 } = {}) {
|
|
332
|
+
const result = await runAgentBrowser(
|
|
333
|
+
['--session', sessionName, '--json', 'eval', DESIGN_ASSERTIONS_SCRIPT],
|
|
334
|
+
{ timeoutMs },
|
|
335
|
+
);
|
|
336
|
+
if (result.exitCode !== 0) {
|
|
337
|
+
return { tool_error: commandError('design_eval', result) };
|
|
416
338
|
}
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
339
|
+
try {
|
|
340
|
+
const payload = parseAgentBrowserJson(result.stdout);
|
|
341
|
+
const raw = payload?.data?.result ?? payload?.result ?? payload?.data ?? null;
|
|
342
|
+
const value = typeof raw === 'string' ? JSON.parse(raw) : raw;
|
|
343
|
+
if (!Array.isArray(value)) throw new Error('Design evaluation did not return a findings array.');
|
|
344
|
+
return value.map((finding) => ({ ...finding, viewport: viewport || finding.viewport || null }));
|
|
345
|
+
} catch (error) {
|
|
346
|
+
return { tool_error: { phase: 'design_eval_parse', message: error.message } };
|
|
421
347
|
}
|
|
348
|
+
}
|
|
422
349
|
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
350
|
+
/**
|
|
351
|
+
* Run every requested viewport. Missing browser checks are incomplete proof,
|
|
352
|
+
* not a passing design result, even when static source lint passed.
|
|
353
|
+
*/
|
|
354
|
+
export async function collectDesignFindings(sessionName, { viewports = DEFAULT_DESIGN_VIEWPORTS, settleMs = 350, skipLoadingCheck = false } = {}) {
|
|
355
|
+
const findings = [];
|
|
356
|
+
let toolError = null;
|
|
357
|
+
for (const viewport of viewports) {
|
|
358
|
+
const applied = await setViewport(sessionName, viewport.width, viewport.height);
|
|
359
|
+
if (!applied) {
|
|
360
|
+
toolError ||= { phase: 'design_viewport', message: `Could not set ${viewport.name} viewport.` };
|
|
361
|
+
continue;
|
|
362
|
+
}
|
|
363
|
+
await delay(settleMs);
|
|
364
|
+
const result = await evalDesignAssertions(sessionName, { viewport: viewport.name });
|
|
365
|
+
if (Array.isArray(result)) {
|
|
366
|
+
for (const finding of result) {
|
|
367
|
+
if (skipLoadingCheck && finding.kind === 'loading_placeholder_after_mount') continue;
|
|
368
|
+
findings.push(finding);
|
|
369
|
+
}
|
|
370
|
+
} else if (!toolError) {
|
|
371
|
+
toolError = result.tool_error;
|
|
436
372
|
}
|
|
437
|
-
framing = null;
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
if (focusSelector) {
|
|
441
|
-
framing = {
|
|
442
|
-
...(framing || {}),
|
|
443
|
-
focus_selector: focusSelector,
|
|
444
|
-
source_dimensions: dimensions,
|
|
445
|
-
};
|
|
446
373
|
}
|
|
447
|
-
|
|
448
|
-
return {
|
|
449
|
-
ok: true,
|
|
450
|
-
mounted: true,
|
|
451
|
-
screenshotPath,
|
|
452
|
-
errors: lastErrors,
|
|
453
|
-
timed_out: false,
|
|
454
|
-
tool_error: null,
|
|
455
|
-
framing,
|
|
456
|
-
};
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
export async function closeAgentBrowserSession(sessionName) {
|
|
460
|
-
const result = await runAgentBrowser(['--session', sessionName, 'close'], {
|
|
461
|
-
timeoutMs: 5000,
|
|
462
|
-
});
|
|
463
|
-
return result.exitCode === 0;
|
|
374
|
+
return { findings, tool_error: toolError };
|
|
464
375
|
}
|