@theoremjs/studio 0.0.0-stage → 0.3.2
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/LICENSE +21 -0
- package/README.md +295 -2
- package/agreement.d.ts +14 -0
- package/agreement.js +80 -0
- package/asks.d.ts +47 -0
- package/asks.js +54 -0
- package/browser-connection.d.ts +49 -0
- package/browser-connection.js +215 -0
- package/browser-engine.d.ts +11 -0
- package/browser-engine.js +11 -0
- package/browser-execution.d.ts +6 -0
- package/browser-execution.js +18 -0
- package/browser-live.d.ts +4 -0
- package/browser-live.js +132 -0
- package/browser-transport.d.ts +33 -0
- package/browser-transport.js +229 -0
- package/browser.d.ts +4 -0
- package/browser.js +4 -0
- package/canonical.d.ts +10 -0
- package/canonical.js +25 -0
- package/compile-workspace.d.ts +28 -0
- package/compile-workspace.js +295 -0
- package/compile.d.ts +65 -0
- package/compile.js +1605 -0
- package/concierge-demo.d.ts +17 -0
- package/concierge-demo.js +1230 -0
- package/conversation-key.d.ts +5 -0
- package/conversation-key.js +10 -0
- package/decision-example-images.d.ts +30 -0
- package/decision-example-images.js +30 -0
- package/deno.json +3 -0
- package/draft.d.ts +407 -0
- package/draft.js +505 -0
- package/editors.d.ts +29 -0
- package/editors.js +51 -0
- package/example-embedding-files.d.ts +11 -0
- package/example-embedding-files.js +20 -0
- package/example.d.ts +36 -0
- package/example.js +357 -0
- package/guardrail-probe.d.ts +100 -0
- package/guardrail-probe.js +722 -0
- package/held-credentials.d.ts +28 -0
- package/held-credentials.js +87 -0
- package/installed.mjs +40 -0
- package/lent-keys.d.ts +122 -0
- package/lent-keys.js +47 -0
- package/line-diff.d.ts +15 -0
- package/line-diff.js +41 -0
- package/live-connection.d.ts +22 -0
- package/live-connection.js +27 -0
- package/live-session-bridge.d.ts +15 -0
- package/live-session-bridge.js +202 -0
- package/map-line.d.ts +19 -0
- package/map-line.js +42 -0
- package/map.d.ts +154 -0
- package/map.js +525 -0
- package/media-accept.d.ts +19 -0
- package/media-accept.js +65 -0
- package/mod.d.ts +39 -0
- package/mod.js +33 -0
- package/origins.d.ts +52 -0
- package/origins.js +165 -0
- package/package.json +85 -4
- package/page/assets/Banner-BISz3nXA.js +2 -0
- package/page/assets/BottomSheet-BwfBDtje.js +1 -0
- package/page/assets/Card-Lp-0P5eL.js +1 -0
- package/page/assets/CardWall-CBRLdDZW.js +1 -0
- package/page/assets/Center-nHS1JSux.js +1 -0
- package/page/assets/CheckboxInput-Cj5pk-KI.js +2 -0
- package/page/assets/CodeBlock-C7XJ4ioE.js +51 -0
- package/page/assets/CollapsibleGroup-N7_SOjbm.js +2 -0
- package/page/assets/ContextMenu-CBu9H-9H.js +2 -0
- package/page/assets/DateInput-BGrQ5tPC.js +1 -0
- package/page/assets/Dialog-DELWQo-v.js +1 -0
- package/page/assets/EmptyState-C8W4JKBZ.js +1 -0
- package/page/assets/HoverCard-D1Y1ltWQ.js +1 -0
- package/page/assets/Icon-JrysT8aU.js +3 -0
- package/page/assets/IconAlertTriangle-BqAEqqdU.js +1 -0
- package/page/assets/IconButton-DlOGzJIX.js +1 -0
- package/page/assets/IconEye-BB5aY-wQ.js +1 -0
- package/page/assets/IconFileText-6zOFKKrF.js +1 -0
- package/page/assets/IconSearch-BTx66a40.js +1 -0
- package/page/assets/IconShield-DDOh7Gr5.js +1 -0
- package/page/assets/ItemSwipeLayer-Ckn4X6h9.js +1 -0
- package/page/assets/PaneState-BvA2tLQg.js +1 -0
- package/page/assets/PaneState-eUzUkNE8.css +1 -0
- package/page/assets/ScrollableArea-Ckugdj1N.js +1 -0
- package/page/assets/Section-DJ97F7QE.js +1 -0
- package/page/assets/SegmentedControlItem-h-aaXzyS.js +1 -0
- package/page/assets/SidePanel-BL32abk8.js +1 -0
- package/page/assets/StackItem-CQviqAfM.js +1 -0
- package/page/assets/Text-bum6zWWx.js +2 -0
- package/page/assets/TimestampHoverCard-DQIG0RZF.js +1 -0
- package/page/assets/ToolResultCharts-CgshSv9Q.js +1 -0
- package/page/assets/Tooltip-BH9xiRMl.js +1 -0
- package/page/assets/TraceInspector-_yZiz05W.js +1 -0
- package/page/assets/TraceOverview-BPO-HIYK.js +57 -0
- package/page/assets/VStack-CkVMcNiK.js +1 -0
- package/page/assets/_virtual_studio-type-sources-ByxqQaOG.js +12936 -0
- package/page/assets/arrive-DvbqpeRS.js +1 -0
- package/page/assets/browser-engine-CYq9DQAM.js +9 -0
- package/page/assets/browser-transport-D-2jDYe7.js +47 -0
- package/page/assets/codicon-DF1abBS2.ttf +0 -0
- package/page/assets/compile-egress-BSxOdX4K.js +23 -0
- package/page/assets/container.stylex-BmOi-8DQ.js +1 -0
- package/page/assets/createReactComponent-CZwsv6DD.js +1 -0
- package/page/assets/decision-example-images-CZGr7YIT.js +1 -0
- package/page/assets/devWarning-DxuplmRl.js +1 -0
- package/page/assets/editor-DjpsE8to.css +1 -0
- package/page/assets/editor.api-Cd3ViPQa.js +908 -0
- package/page/assets/editor.worker-6GY8RhDc.js +1 -0
- package/page/assets/editor.worker-BmdWdrHZ.js +33 -0
- package/page/assets/editors-BJX_S59A.js +1 -0
- package/page/assets/egress-automata-B5ZGE1mT.js +1 -0
- package/page/assets/embedding-space-view-CfQBPDxD.js +140 -0
- package/page/assets/encode-files-Bc3HJyAh.js +1 -0
- package/page/assets/export-agent-C3yyzXH8.js +43 -0
- package/page/assets/figtree-latin-400-normal-BD4aNku5.woff +0 -0
- package/page/assets/figtree-latin-400-normal-g7Dtegnw.woff2 +0 -0
- package/page/assets/figtree-latin-500-normal-BWnGEVsr.woff2 +0 -0
- package/page/assets/figtree-latin-500-normal-B_yy1phn.woff +0 -0
- package/page/assets/figtree-latin-600-normal-BM_oTo4n.woff +0 -0
- package/page/assets/figtree-latin-600-normal-Cv_xCTDl.woff2 +0 -0
- package/page/assets/figtree-latin-700-normal-BCCt2T1q.woff +0 -0
- package/page/assets/figtree-latin-700-normal-th6qEP7c.woff2 +0 -0
- package/page/assets/focusOutline.stylex-BT0kfa4t.js +1 -0
- package/page/assets/focusableSelector-DXZeMU85.js +1 -0
- package/page/assets/groupStyles-C7Ter7zC.js +1 -0
- package/page/assets/guardrail-tester-Gut5xK4a.js +9 -0
- package/page/assets/host-patterns-C9RMP16Q.js +1 -0
- package/page/assets/index-CvvmFKgS.js +105 -0
- package/page/assets/index-DOaHlqBo.css +1 -0
- package/page/assets/isRtlElement-BG33-k_H.js +1 -0
- package/page/assets/labels-provider-4TIWDvsE.js +3 -0
- package/page/assets/lent-keys-C32ems-I.js +1 -0
- package/page/assets/live-ingress-lDUGPwth.js +1 -0
- package/page/assets/live-messages-CnkL4GWi.js +1 -0
- package/page/assets/mergeProps-ptS-gIMz.js +1 -0
- package/page/assets/padding.stylex-B76907Zf.js +1 -0
- package/page/assets/preload-helper-DpV6A1kQ.js +1 -0
- package/page/assets/reader-BOCCYaRp.js +7 -0
- package/page/assets/register-CDgivxvX.js +2 -0
- package/page/assets/rolldown-runtime-hePW80VL.js +1 -0
- package/page/assets/schemas-BQ9Jydzb.js +56 -0
- package/page/assets/shaped-data-BcarWqd5.js +16 -0
- package/page/assets/sharedResizeObserver-4U9Xq5Oq.js +1 -0
- package/page/assets/stub-DhdcU_Ew.js +471 -0
- package/page/assets/studio-code-pane-C_SAbcOa.js +8 -0
- package/page/assets/studio-console-DZwlEsvr.js +3 -0
- package/page/assets/studio-decision-B0FnCAXA.js +1 -0
- package/page/assets/studio-embedding-CmA51HVo.js +2 -0
- package/page/assets/studio-host-console-By7hqu2l.js +2 -0
- package/page/assets/studio-live-BrcVQcyV.js +1 -0
- package/page/assets/studio-map-B_xSia-z.js +1 -0
- package/page/assets/studio-map-Bb06Tw1F.css +1 -0
- package/page/assets/studio-monaco-CbKf90i6.css +1 -0
- package/page/assets/studio-monaco-xfyfezQS.js +34 -0
- package/page/assets/studio-ts.worker-B-EXG4Sv.js +67741 -0
- package/page/assets/studio-ts.worker-BXtW3z-O.js +1 -0
- package/page/assets/studio-type-checker-BOvxudki.js +23 -0
- package/page/assets/themeProps-3IqahpCr.js +1 -0
- package/page/assets/tokens.stylex-DkHf0P9C.js +1 -0
- package/page/assets/tool-schema-idaOe2nI.js +18 -0
- package/page/assets/trace-patterns-DnYJa0nI.js +1 -0
- package/page/assets/trace-record-C3zNksA_.js +1 -0
- package/page/assets/trace-schema-9CdEyG6Q.js +1 -0
- package/page/assets/tree-DqyAMsbI.js +3 -0
- package/page/assets/turn-client-Du3Um3Mg.js +2 -0
- package/page/assets/types-BhfXQCLx.js +1 -0
- package/page/assets/typescript-20GgZ8PJ.js +1 -0
- package/page/assets/use-one-call-Hcs8YBp1.js +1 -0
- package/page/assets/useAdaptivePresentation-BzmPCddb.js +1 -0
- package/page/assets/useClipboard-BgGRxRMJ.js +1 -0
- package/page/assets/useContainerReveal-BFy8N_QU.js +1 -0
- package/page/assets/useDevWarning-Z9SoixOP.js +1 -0
- package/page/assets/useLayerDismissal-B_G7IWpC.js +1 -0
- package/page/assets/useMediaQuery-BCT0NUeZ.js +1 -0
- package/page/assets/useScrollLock-Dyf6PHJt.js +1 -0
- package/page/assets/useScrollableArea-0NzdiBCq.js +1 -0
- package/page/assets/useTooltip-CJM_xhLB.js +1 -0
- package/page/assets/workspace-DZALqEDX.js +1 -0
- package/page/assets/zip-DTcEfps6.js +1 -0
- package/page/index.html +90 -0
- package/page.mjs +49 -0
- package/people.d.ts +87 -0
- package/people.js +110 -0
- package/policy.d.ts +43 -0
- package/policy.js +102 -0
- package/ports.d.mts +32 -0
- package/ports.mjs +85 -0
- package/probe-battery.d.ts +13 -0
- package/probe-battery.js +404 -0
- package/providers.d.ts +149 -0
- package/providers.js +306 -0
- package/read-source.d.ts +48 -0
- package/read-source.js +1301 -0
- package/read-steps.d.ts +23 -0
- package/read-steps.js +2 -0
- package/reader.d.ts +11 -0
- package/reader.js +11 -0
- package/registrations.d.ts +83 -0
- package/registrations.js +1 -0
- package/requirements.d.ts +22 -0
- package/requirements.js +38 -0
- package/run-payload-core.d.ts +28 -0
- package/run-payload-core.js +123 -0
- package/run-payload.d.ts +32 -0
- package/run-payload.js +26 -0
- package/runtime-scope.d.ts +84 -0
- package/runtime-scope.js +308 -0
- package/runtime.d.ts +84 -0
- package/runtime.js +387 -0
- package/section-notes.d.ts +33 -0
- package/section-notes.js +38 -0
- package/serve-page.mjs +96 -0
- package/server/draft-decide.d.ts +72 -0
- package/server/draft-decide.js +111 -0
- package/server/draft-embedding.d.ts +3 -0
- package/server/draft-embedding.js +35 -0
- package/server/draft-handler.d.ts +82 -0
- package/server/draft-handler.js +213 -0
- package/server/draft-probe.d.ts +14 -0
- package/server/draft-probe.js +61 -0
- package/server/draft-replies.d.ts +22 -0
- package/server/draft-replies.js +46 -0
- package/server/edited-session.d.ts +28 -0
- package/server/edited-session.js +83 -0
- package/server/edits.d.ts +38 -0
- package/server/edits.js +195 -0
- package/server/handler.d.ts +133 -0
- package/server/handler.js +598 -0
- package/server/lent-draft.d.ts +19 -0
- package/server/lent-draft.js +23 -0
- package/server/live.d.ts +15 -0
- package/server/live.js +96 -0
- package/server/open-editor.d.ts +63 -0
- package/server/open-editor.js +115 -0
- package/server/origins.d.ts +18 -0
- package/server/origins.js +330 -0
- package/server/project-source.d.ts +208 -0
- package/server/project-source.js +1042 -0
- package/server/project.d.ts +22 -0
- package/server/project.js +56 -0
- package/server/run-traces.d.ts +20 -0
- package/server/run-traces.js +96 -0
- package/server/save-new.d.ts +29 -0
- package/server/save-new.js +514 -0
- package/server/save-plan.d.ts +46 -0
- package/server/save-plan.js +1134 -0
- package/server/save-remove.d.ts +21 -0
- package/server/save-remove.js +528 -0
- package/server/save-session.d.ts +96 -0
- package/server/save-session.js +418 -0
- package/server/save-wire.d.ts +235 -0
- package/server/save-wire.js +8 -0
- package/server/save.d.ts +52 -0
- package/server/save.js +209 -0
- package/server/serve.d.ts +23 -0
- package/server/serve.js +413 -0
- package/server/test-connection.d.ts +17 -0
- package/server/test-connection.js +362 -0
- package/server/test-key.d.ts +2 -0
- package/server/test-key.js +83 -0
- package/server/watch.d.ts +28 -0
- package/server/watch.js +93 -0
- package/server/zod-edit.d.ts +74 -0
- package/server/zod-edit.js +558 -0
- package/server.d.ts +8 -0
- package/server.js +8 -0
- package/setups.mjs +170 -0
- package/shared-carry.d.ts +114 -0
- package/shared-carry.js +523 -0
- package/shared-settings.d.ts +34 -0
- package/shared-settings.js +70 -0
- package/source.d.ts +75 -0
- package/source.js +414 -0
- package/start.mjs +169 -0
- package/stream-lines.d.ts +9 -0
- package/stream-lines.js +27 -0
- package/stub.d.ts +6 -0
- package/stub.js +33 -0
- package/surface.d.ts +53 -0
- package/surface.js +631 -0
- package/system-markup.d.ts +20 -0
- package/system-markup.js +51 -0
- package/tool-schema.d.ts +23 -0
- package/tool-schema.js +69 -0
- package/tools.d.ts +16 -0
- package/tools.js +91 -0
- package/traces.d.ts +24 -0
- package/traces.js +29 -0
- package/transport.d.ts +57 -0
- package/transport.js +187 -0
- package/tree.d.ts +32 -0
- package/tree.js +83 -0
- package/types.d.ts +62 -0
- package/types.js +6 -0
- package/ui/acting-as-button.d.ts +2 -0
- package/ui/acting-as-button.js +16 -0
- package/ui/add-provider.d.ts +13 -0
- package/ui/add-provider.js +20 -0
- package/ui/boot-mark.css +53 -0
- package/ui/boot-mark.d.ts +19 -0
- package/ui/boot-mark.js +128 -0
- package/ui/boot-paint.d.ts +8 -0
- package/ui/boot-paint.js +8 -0
- package/ui/brand-icons.d.ts +57 -0
- package/ui/brand-icons.js +148 -0
- package/ui/built/theme.css +830 -0
- package/ui/built/theme.css.d.ts +9 -0
- package/ui/built/theorem-studio.d.ts +13 -0
- package/ui/built/theorem-studio.js +705 -0
- package/ui/built/theorem-studio.variants.d.ts +28 -0
- package/ui/code/monaco-contributions.d.ts +45 -0
- package/ui/code/studio-code.d.ts +7 -0
- package/ui/code/studio-code.js +253 -0
- package/ui/code/studio-monaco.d.ts +44 -0
- package/ui/code/studio-monaco.js +48 -0
- package/ui/code/studio-ts.worker.d.ts +1 -0
- package/ui/code/studio-ts.worker.js +16 -0
- package/ui/code/studio-type-checker.d.ts +12 -0
- package/ui/code/studio-type-checker.js +308 -0
- package/ui/code/studio-type-sources.d.ts +26 -0
- package/ui/confirm-write.d.ts +12 -0
- package/ui/confirm-write.js +45 -0
- package/ui/diff-block.d.ts +21 -0
- package/ui/diff-block.js +17 -0
- package/ui/figtree.css +59 -0
- package/ui/file-place.d.ts +4 -0
- package/ui/file-place.js +26 -0
- package/ui/guardrail-tester.d.ts +18 -0
- package/ui/guardrail-tester.js +248 -0
- package/ui/inspector-context.d.ts +119 -0
- package/ui/inspector-context.js +84 -0
- package/ui/inspector.d.ts +247 -0
- package/ui/inspector.js +284 -0
- package/ui/lib/acting-as.d.ts +25 -0
- package/ui/lib/acting-as.js +90 -0
- package/ui/lib/boot-sequence.d.ts +32 -0
- package/ui/lib/boot-sequence.js +57 -0
- package/ui/lib/export-agent.d.ts +11 -0
- package/ui/lib/export-agent.js +335 -0
- package/ui/lib/facet-icons.d.ts +20 -0
- package/ui/lib/facet-icons.js +21 -0
- package/ui/lib/panel-motion.d.ts +8 -0
- package/ui/lib/panel-motion.js +74 -0
- package/ui/lib/project-address.d.ts +14 -0
- package/ui/lib/project-address.js +24 -0
- package/ui/lib/project-starting.d.ts +13 -0
- package/ui/lib/project-starting.js +30 -0
- package/ui/lib/project-traces.d.ts +17 -0
- package/ui/lib/project-traces.js +54 -0
- package/ui/lib/read-map.d.ts +30 -0
- package/ui/lib/read-map.js +173 -0
- package/ui/lib/read-progress.d.ts +14 -0
- package/ui/lib/read-progress.js +12 -0
- package/ui/lib/refusal-lines.d.ts +3 -0
- package/ui/lib/refusal-lines.js +8 -0
- package/ui/lib/studio-activity.d.ts +5 -0
- package/ui/lib/studio-activity.js +17 -0
- package/ui/lib/studio-console.d.ts +27 -0
- package/ui/lib/studio-console.js +9 -0
- package/ui/lib/studio-conversation.d.ts +20 -0
- package/ui/lib/studio-conversation.js +130 -0
- package/ui/lib/studio-examples.d.ts +31 -0
- package/ui/lib/studio-examples.js +25 -0
- package/ui/lib/studio-labels.d.ts +6 -0
- package/ui/lib/studio-labels.js +13 -0
- package/ui/lib/studio-map-kept.d.ts +17 -0
- package/ui/lib/studio-map-kept.js +48 -0
- package/ui/lib/studio-open.d.ts +22 -0
- package/ui/lib/studio-open.js +54 -0
- package/ui/lib/studio-page.d.ts +33 -0
- package/ui/lib/studio-page.js +121 -0
- package/ui/lib/studio-prefs.d.ts +26 -0
- package/ui/lib/studio-prefs.js +87 -0
- package/ui/lib/studio-project.d.ts +106 -0
- package/ui/lib/studio-project.js +177 -0
- package/ui/lib/studio-restore.d.ts +49 -0
- package/ui/lib/studio-restore.js +251 -0
- package/ui/lib/studio-run-open.d.ts +15 -0
- package/ui/lib/studio-run-open.js +16 -0
- package/ui/lib/studio-session.d.ts +34 -0
- package/ui/lib/studio-session.js +17 -0
- package/ui/lib/studio-settings.d.ts +15 -0
- package/ui/lib/studio-settings.js +48 -0
- package/ui/lib/studio-store.d.ts +64 -0
- package/ui/lib/studio-store.js +391 -0
- package/ui/lib/studio-watch.d.ts +12 -0
- package/ui/lib/studio-watch.js +27 -0
- package/ui/lib/tab-fills.d.ts +6 -0
- package/ui/lib/tab-fills.js +14 -0
- package/ui/lib/tool-credentials.d.ts +3 -0
- package/ui/lib/tool-credentials.js +23 -0
- package/ui/lib/tool-probe.d.ts +19 -0
- package/ui/lib/tool-probe.js +104 -0
- package/ui/lib/type-icons.d.ts +35 -0
- package/ui/lib/type-icons.js +38 -0
- package/ui/lib/when-idle.d.ts +5 -0
- package/ui/lib/when-idle.js +14 -0
- package/ui/lib/zip.d.ts +5 -0
- package/ui/lib/zip.js +8 -0
- package/ui/map-token.css +11 -0
- package/ui/map-token.d.ts +17 -0
- package/ui/map-token.js +29 -0
- package/ui/mcp-icon.d.ts +6 -0
- package/ui/mcp-icon.js +8 -0
- package/ui/motion.css +113 -0
- package/ui/pan.d.ts +32 -0
- package/ui/pan.js +90 -0
- package/ui/profile-editor.d.ts +33 -0
- package/ui/profile-editor.js +2638 -0
- package/ui/provider-editor.d.ts +15 -0
- package/ui/provider-editor.js +92 -0
- package/ui/read-map.css +48 -0
- package/ui/read-map.d.ts +7 -0
- package/ui/read-map.js +163 -0
- package/ui/refusal-detail.d.ts +4 -0
- package/ui/refusal-detail.js +21 -0
- package/ui/shared-change.d.ts +9 -0
- package/ui/shared-change.js +28 -0
- package/ui/shell-motion.css +121 -0
- package/ui/shell-motion.d.ts +73 -0
- package/ui/shell-motion.js +194 -0
- package/ui/studio-code-pane.d.ts +19 -0
- package/ui/studio-code-pane.js +44 -0
- package/ui/studio-compare.d.ts +80 -0
- package/ui/studio-compare.js +326 -0
- package/ui/studio-conflicts.d.ts +17 -0
- package/ui/studio-conflicts.js +87 -0
- package/ui/studio-connection.d.ts +64 -0
- package/ui/studio-connection.js +286 -0
- package/ui/studio-decision.d.ts +6 -0
- package/ui/studio-decision.js +49 -0
- package/ui/studio-embedding.d.ts +6 -0
- package/ui/studio-embedding.js +30 -0
- package/ui/studio-host-console.d.ts +6 -0
- package/ui/studio-host-console.js +17 -0
- package/ui/studio-host.d.ts +73 -0
- package/ui/studio-host.js +12 -0
- package/ui/studio-live.d.ts +17 -0
- package/ui/studio-live.js +26 -0
- package/ui/studio-map.css +273 -0
- package/ui/studio-map.d.ts +17 -0
- package/ui/studio-map.js +397 -0
- package/ui/studio-nav.d.ts +24 -0
- package/ui/studio-nav.js +17 -0
- package/ui/studio-no-project.d.ts +5 -0
- package/ui/studio-no-project.js +9 -0
- package/ui/studio-run.css +76 -0
- package/ui/studio-run.d.ts +14 -0
- package/ui/studio-run.js +119 -0
- package/ui/studio-runner.d.ts +45 -0
- package/ui/studio-runner.js +187 -0
- package/ui/studio-save.d.ts +49 -0
- package/ui/studio-save.js +307 -0
- package/ui/studio-screen.d.ts +61 -0
- package/ui/studio-screen.js +2078 -0
- package/ui/studio-settings.d.ts +31 -0
- package/ui/studio-settings.js +288 -0
- package/ui/studio-shell.css +27 -0
- package/ui/studio-shell.d.ts +43 -0
- package/ui/studio-shell.js +87 -0
- package/ui/studio-theme.d.ts +7 -0
- package/ui/studio-theme.js +94 -0
- package/ui/studio.css +427 -0
- package/ui/theorem-mark.css +84 -0
- package/ui/theorem-mark.d.ts +22 -0
- package/ui/theorem-mark.js +21 -0
- package/vite.d.mts +30 -0
- package/vite.mjs +277 -0
- package/workspace.d.ts +230 -0
- package/workspace.js +1054 -0
package/server/live.js
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A voice call with one of the project's live profiles: the page's socket on one side, the
|
|
3
|
+
* project's own session on the other. The call opens with the page's open message, as a call to
|
|
4
|
+
* the application's relay does.
|
|
5
|
+
*
|
|
6
|
+
* @module
|
|
7
|
+
*/
|
|
8
|
+
import { resolveObservabilityPolicy, runSession, TheoremError, } from '@theoremjs/agents';
|
|
9
|
+
import { clientError } from '@theoremjs/agents/host';
|
|
10
|
+
import { createMemorySessionStore, createTheoremSessionBoundary, parseLiveOpenMessage, } from '@theoremjs/react/server';
|
|
11
|
+
import { attachStudioLiveSession } from "../live-session-bridge.js";
|
|
12
|
+
import { STUDIO_READER } from "../reader.js";
|
|
13
|
+
/** The call's records reach the page through its own sink, so the bridge has no route to close. */
|
|
14
|
+
const NO_ROUTE = { metadata: {}, close: () => { } };
|
|
15
|
+
/**
|
|
16
|
+
* Where a call's trace goes: to the page, as each record is written. A call made in the studio is
|
|
17
|
+
* a test, so its records stay out of the store the profile writes to. A profile that records
|
|
18
|
+
* nothing sends nothing, and what the profile keeps private stays out, as in any trace.
|
|
19
|
+
*/
|
|
20
|
+
function pageSink(socket, profile) {
|
|
21
|
+
if (!resolveObservabilityPolicy(profile.observability).record)
|
|
22
|
+
return undefined;
|
|
23
|
+
return {
|
|
24
|
+
write: (record) => {
|
|
25
|
+
const line = { type: 'trace', record };
|
|
26
|
+
if (socket.readyState === WebSocket.OPEN)
|
|
27
|
+
socket.send(JSON.stringify(line));
|
|
28
|
+
return Promise.resolve();
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
/** The page's first message. A failure when it is malformed, or the page leaves before it. */
|
|
33
|
+
function openMessage(socket) {
|
|
34
|
+
return new Promise((resolve, reject) => {
|
|
35
|
+
const onMessage = (event) => {
|
|
36
|
+
socket.removeEventListener('close', onClose);
|
|
37
|
+
try {
|
|
38
|
+
resolve(parseLiveOpenMessage(typeof event.data === 'string' ? event.data : ''));
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
reject(error instanceof Error ? error : new Error(String(error)));
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
const onClose = () => {
|
|
45
|
+
socket.removeEventListener('message', onMessage);
|
|
46
|
+
// labels-exempt: internal diagnostic; the user reads error.network
|
|
47
|
+
reject(new TheoremError('network', 'Live socket closed before its first message'));
|
|
48
|
+
};
|
|
49
|
+
socket.addEventListener('message', onMessage, { once: true });
|
|
50
|
+
socket.addEventListener('close', onClose, { once: true });
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
/** Runs the call until either side ends it. A failure to open reaches the page worded, with its kind. */
|
|
54
|
+
async function relay(socket, profile, provider, boundary) {
|
|
55
|
+
let session;
|
|
56
|
+
try {
|
|
57
|
+
// Listen before anything waits: the page sends its open message as the socket opens.
|
|
58
|
+
const open = await openMessage(socket);
|
|
59
|
+
session = await runSession({ ...(await boundary.prepareLiveOpen(open)), profile: profile.id }, { ...provider, execution: boundary.toolExecution, pageExecution: boundary.pageExecution }, pageSink(socket, profile));
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
if (socket.readyState !== WebSocket.OPEN)
|
|
63
|
+
return;
|
|
64
|
+
socket.send(JSON.stringify({ type: 'error', ...clientError(error, profile.labels, STUDIO_READER) }));
|
|
65
|
+
socket.close(1011, 'session error');
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
// The page may have left while the session opened; its close event has already fired.
|
|
69
|
+
if (socket.readyState !== WebSocket.OPEN) {
|
|
70
|
+
await session.close('client disconnected');
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
await attachStudioLiveSession(socket, session, profile.id, crypto.randomUUID(), NO_ROUTE, profile.labels, {
|
|
74
|
+
clientEvents: STUDIO_READER,
|
|
75
|
+
pageResult: boundary.answerPageResult,
|
|
76
|
+
beforeEvent: async (event) => {
|
|
77
|
+
if ((event.type === 'done' || event.type === 'provider_checkpoint') && event.providerState)
|
|
78
|
+
await boundary.recordCheckpoint(event.providerState);
|
|
79
|
+
},
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
/** Serves a live profile: a socket upgrade starts a call, and anything else is told to upgrade. */
|
|
83
|
+
export function createStudioLiveHandler(profile, provider, upgrade) {
|
|
84
|
+
const sessionStore = createMemorySessionStore();
|
|
85
|
+
return async (request) => {
|
|
86
|
+
if (request.headers.get('upgrade')?.toLowerCase() !== 'websocket') {
|
|
87
|
+
return new Response(null, { status: 426, headers: { upgrade: 'websocket' } });
|
|
88
|
+
}
|
|
89
|
+
const boundary = await createTheoremSessionBoundary({ request, sessionStore });
|
|
90
|
+
const { socket, response } = upgrade(request);
|
|
91
|
+
if (boundary.setCookie)
|
|
92
|
+
response.headers.append('set-cookie', boundary.setCookie);
|
|
93
|
+
void relay(socket, profile, provider, boundary);
|
|
94
|
+
return response;
|
|
95
|
+
};
|
|
96
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Opens one of the project's files in the builder's editor, on a line. The
|
|
3
|
+
* studio starts the editor's own command and never a shell, and only for a
|
|
4
|
+
* file the project's setup reads.
|
|
5
|
+
*
|
|
6
|
+
* @module
|
|
7
|
+
*/
|
|
8
|
+
import type { OpenAnswer, OpenRequest } from './save-wire.ts';
|
|
9
|
+
/**
|
|
10
|
+
* The editor the studio starts: the one the command named, else the first of the environment's
|
|
11
|
+
* that opens in a window, else VS Code. A terminal editor in `$EDITOR` is passed over, since the
|
|
12
|
+
* studio has no terminal to run it in.
|
|
13
|
+
*/
|
|
14
|
+
export declare function chosenEditor(flag: string | undefined, environment: readonly (string | undefined)[]): string;
|
|
15
|
+
/** The command that opens `file` at `line` in an editor, or undefined when the studio does not know the editor. */
|
|
16
|
+
export declare function editorCommand(editor: string, file: string, line: number | undefined): {
|
|
17
|
+
command: string;
|
|
18
|
+
args: string[];
|
|
19
|
+
} | undefined;
|
|
20
|
+
/**
|
|
21
|
+
* Where an editor's command is when it is not on the path: inside its macOS app, in the machine's
|
|
22
|
+
* Applications folder and then the builder's own. Empty for an editor with no known app, and off macOS.
|
|
23
|
+
*/
|
|
24
|
+
export declare function installedCommands(editor: string, os: string | undefined, home: string | undefined): string[];
|
|
25
|
+
/**
|
|
26
|
+
* The machine's own way to open a file in its default editor, or undefined where it has none that
|
|
27
|
+
* is safe: macOS opens it as text and Linux asks the desktop. Windows is left out, since its
|
|
28
|
+
* default for a script is to run it.
|
|
29
|
+
*/
|
|
30
|
+
export declare function defaultOpener(os: string, file: string): {
|
|
31
|
+
command: string;
|
|
32
|
+
args: string[];
|
|
33
|
+
} | undefined;
|
|
34
|
+
/** What opening needs from the machine. */
|
|
35
|
+
export interface EditorHost {
|
|
36
|
+
/** The editor's command, as the builder set it when the studio started. */
|
|
37
|
+
editor: string;
|
|
38
|
+
/** The absolute path of a project file named from the project's folder, or undefined when the project has none there. */
|
|
39
|
+
place(file: string): string | undefined;
|
|
40
|
+
/** Starts a command without a shell. False when it did not start. */
|
|
41
|
+
start(command: string, args: string[]): boolean;
|
|
42
|
+
/** The machine's kind, as `defaultOpener` takes it; without one there is no default to fall back on. */
|
|
43
|
+
os?: string;
|
|
44
|
+
/** The builder's home folder, where an app of their own is installed. */
|
|
45
|
+
home?: string;
|
|
46
|
+
}
|
|
47
|
+
/** The editor the studio starts when the page names none, by the command the studio lists it under. */
|
|
48
|
+
export declare function defaultEditor(host: EditorHost): string;
|
|
49
|
+
/**
|
|
50
|
+
* Opens the file a request names, in the editor it names or else the one the studio started with.
|
|
51
|
+
* The answer says which editor, or why not and the place to go to by hand. An editor whose command
|
|
52
|
+
* is not on the path is started from its app. When the editor is not one the studio can start, or
|
|
53
|
+
* did not start, the machine's default editor opens the file instead.
|
|
54
|
+
*/
|
|
55
|
+
export declare function openInEditor(host: EditorHost, request: OpenRequest): OpenAnswer;
|
|
56
|
+
/**
|
|
57
|
+
* What the studio answers a request to open a file with, as a status and a body. Undefined when
|
|
58
|
+
* the request is not one.
|
|
59
|
+
*/
|
|
60
|
+
export declare function answerOpen(host: EditorHost, at: string, request: Request): Promise<{
|
|
61
|
+
status: number;
|
|
62
|
+
body: unknown;
|
|
63
|
+
} | undefined>;
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Opens one of the project's files in the builder's editor, on a line. The
|
|
3
|
+
* studio starts the editor's own command and never a shell, and only for a
|
|
4
|
+
* file the project's setup reads.
|
|
5
|
+
*
|
|
6
|
+
* @module
|
|
7
|
+
*/
|
|
8
|
+
import { basename } from 'node:path';
|
|
9
|
+
import { isEditorChoice, studioEditor } from "../editors.js";
|
|
10
|
+
/** The arguments each form of command takes for a file and a line. */
|
|
11
|
+
const LINE_ARGS = {
|
|
12
|
+
goto: (file, line) => ['-g', `${file}:${line}`],
|
|
13
|
+
colon: (file, line) => [`${file}:${line}`],
|
|
14
|
+
'line-flag': (file, line) => ['--line', String(line), file],
|
|
15
|
+
'l-flag': (file, line) => ['-l', String(line), file],
|
|
16
|
+
};
|
|
17
|
+
/** The command an editor setting names: `code --wait` is `code`. */
|
|
18
|
+
const commandOf = (editor) => editor.trim().split(/\s+/)[0] ?? '';
|
|
19
|
+
/** An editor's command name as the table has it: `/usr/local/bin/Code.exe` is `code`. */
|
|
20
|
+
function editorName(editor) {
|
|
21
|
+
return basename(commandOf(editor))
|
|
22
|
+
.toLowerCase()
|
|
23
|
+
.replace(/\.(exe|cmd|sh)$/, '');
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* The editor the studio starts: the one the command named, else the first of the environment's
|
|
27
|
+
* that opens in a window, else VS Code. A terminal editor in `$EDITOR` is passed over, since the
|
|
28
|
+
* studio has no terminal to run it in.
|
|
29
|
+
*/
|
|
30
|
+
export function chosenEditor(flag, environment) {
|
|
31
|
+
if (flag?.trim())
|
|
32
|
+
return flag;
|
|
33
|
+
return (environment.find((editor) => editor !== undefined && studioEditor(editorName(editor))) ?? 'code');
|
|
34
|
+
}
|
|
35
|
+
/** The command that opens `file` at `line` in an editor, or undefined when the studio does not know the editor. */
|
|
36
|
+
export function editorCommand(editor, file, line) {
|
|
37
|
+
const known = studioEditor(editorName(editor));
|
|
38
|
+
if (!known)
|
|
39
|
+
return undefined;
|
|
40
|
+
return {
|
|
41
|
+
command: commandOf(editor),
|
|
42
|
+
args: line === undefined ? [file] : LINE_ARGS[known.form](file, line),
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Where an editor's command is when it is not on the path: inside its macOS app, in the machine's
|
|
47
|
+
* Applications folder and then the builder's own. Empty for an editor with no known app, and off macOS.
|
|
48
|
+
*/
|
|
49
|
+
export function installedCommands(editor, os, home) {
|
|
50
|
+
const inApp = studioEditor(editorName(editor))?.macCommand;
|
|
51
|
+
if (os !== 'darwin' || !inApp)
|
|
52
|
+
return [];
|
|
53
|
+
return [`/Applications/${inApp}`, ...(home ? [`${home}/Applications/${inApp}`] : [])];
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* The machine's own way to open a file in its default editor, or undefined where it has none that
|
|
57
|
+
* is safe: macOS opens it as text and Linux asks the desktop. Windows is left out, since its
|
|
58
|
+
* default for a script is to run it.
|
|
59
|
+
*/
|
|
60
|
+
export function defaultOpener(os, file) {
|
|
61
|
+
if (os === 'darwin')
|
|
62
|
+
return { command: 'open', args: ['-t', file] };
|
|
63
|
+
if (os === 'linux')
|
|
64
|
+
return { command: 'xdg-open', args: [file] };
|
|
65
|
+
return undefined;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* A page may name the editor only by a command Settings offers, exactly: never a path or a
|
|
69
|
+
* command of its own, since the studio starts what is named.
|
|
70
|
+
*/
|
|
71
|
+
function isOpenRequest(body) {
|
|
72
|
+
const { file, line, editor } = (body ?? {});
|
|
73
|
+
if (editor !== undefined && (typeof editor !== 'string' || !isEditorChoice(editor)))
|
|
74
|
+
return false;
|
|
75
|
+
return typeof file === 'string' && (line === undefined || (Number.isInteger(line) && line > 0));
|
|
76
|
+
}
|
|
77
|
+
/** The editor the studio starts when the page names none, by the command the studio lists it under. */
|
|
78
|
+
export function defaultEditor(host) {
|
|
79
|
+
return editorName(host.editor);
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Opens the file a request names, in the editor it names or else the one the studio started with.
|
|
83
|
+
* The answer says which editor, or why not and the place to go to by hand. An editor whose command
|
|
84
|
+
* is not on the path is started from its app. When the editor is not one the studio can start, or
|
|
85
|
+
* did not start, the machine's default editor opens the file instead.
|
|
86
|
+
*/
|
|
87
|
+
export function openInEditor(host, request) {
|
|
88
|
+
const path = host.place(request.file);
|
|
89
|
+
if (path === undefined)
|
|
90
|
+
return { ok: false, reason: 'file' };
|
|
91
|
+
// Only a command the studio lists is taken from the page; `answerOpen` refuses any other.
|
|
92
|
+
const named = request.editor !== undefined && isEditorChoice(request.editor) ? request.editor : host.editor;
|
|
93
|
+
const editor = editorName(named);
|
|
94
|
+
const place = request.line === undefined ? path : `${path}:${request.line}`;
|
|
95
|
+
const run = editorCommand(named, path, request.line);
|
|
96
|
+
const commands = run ? [run.command, ...installedCommands(named, host.os, host.home)] : [];
|
|
97
|
+
if (run && commands.some((command) => host.start(command, run.args)))
|
|
98
|
+
return { ok: true, editor };
|
|
99
|
+
const other = host.os === undefined ? undefined : defaultOpener(host.os, path);
|
|
100
|
+
if (other && host.start(other.command, other.args))
|
|
101
|
+
return { ok: true, editor, byDefault: true };
|
|
102
|
+
return { ok: false, reason: run ? 'failed' : 'editor', editor, place };
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* What the studio answers a request to open a file with, as a status and a body. Undefined when
|
|
106
|
+
* the request is not one.
|
|
107
|
+
*/
|
|
108
|
+
export async function answerOpen(host, at, request) {
|
|
109
|
+
if (request.method !== 'POST' || new URL(request.url).pathname !== at)
|
|
110
|
+
return undefined;
|
|
111
|
+
const body = await request.json().catch(() => null);
|
|
112
|
+
return isOpenRequest(body)
|
|
113
|
+
? { status: 200, body: openInEditor(host, body) }
|
|
114
|
+
: { status: 400, body: {} };
|
|
115
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which of a project's settings its files set in code. The studio shows those
|
|
3
|
+
* and does not change them, and says where each one is. It also says where each
|
|
4
|
+
* value others read too is written, so a change to one is asked about first. It
|
|
5
|
+
* reads the same way Save plans a change (`save-plan.ts`), so what a row says is
|
|
6
|
+
* what Save would do. A tool's schema is open when it reads as Zod: Save changes
|
|
7
|
+
* it there, and says in its review which part, if any, is left for code.
|
|
8
|
+
*
|
|
9
|
+
* @module
|
|
10
|
+
*/
|
|
11
|
+
import { type ProjectSource } from './project-source.ts';
|
|
12
|
+
import type { ProjectOrigins } from './save-wire.ts';
|
|
13
|
+
/**
|
|
14
|
+
* The settings the project's files set in code, for each profile, tool, and provider the files
|
|
15
|
+
* define. One with none is left out. `decisions` names the decision profiles the studio
|
|
16
|
+
* shows: each one's questions and pictures are set in the setup module.
|
|
17
|
+
*/
|
|
18
|
+
export declare function sourceOrigins(project: ProjectSource, decisions?: readonly string[]): ProjectOrigins;
|
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which of a project's settings its files set in code. The studio shows those
|
|
3
|
+
* and does not change them, and says where each one is. It also says where each
|
|
4
|
+
* value others read too is written, so a change to one is asked about first. It
|
|
5
|
+
* reads the same way Save plans a change (`save-plan.ts`), so what a row says is
|
|
6
|
+
* what Save would do. A tool's schema is open when it reads as Zod: Save changes
|
|
7
|
+
* it there, and says in its review which part, if any, is left for code.
|
|
8
|
+
*
|
|
9
|
+
* @module
|
|
10
|
+
*/
|
|
11
|
+
import ts from 'typescript';
|
|
12
|
+
import { followed, holderOf, isHeldId, isInCall, isInTarget, isKernelName, propertyName, setupExport, shapeOf, unwrapped, usersOf, } from "./project-source.js";
|
|
13
|
+
import { NOT_PLAIN, plain } from "./save-plan.js";
|
|
14
|
+
import { readZod, zodObject } from "./zod-edit.js";
|
|
15
|
+
/** The most of an expression a row shows. */
|
|
16
|
+
const TEXT_LENGTH = 48;
|
|
17
|
+
/** An expression as the file writes it, on one line and cut to fit a row. */
|
|
18
|
+
function textOf(node, source) {
|
|
19
|
+
const text = node.getText(source).replace(/\s+/g, ' ');
|
|
20
|
+
return text.length > TEXT_LENGTH ? `${text.slice(0, TEXT_LENGTH - 1)}…` : text;
|
|
21
|
+
}
|
|
22
|
+
function lineOf(node, source) {
|
|
23
|
+
return source.getLineAndCharacterOfPosition(node.getStart(source)).line + 1;
|
|
24
|
+
}
|
|
25
|
+
/** A tool's schemas are its `input` and `output` in the file, written in Zod there. */
|
|
26
|
+
const TOOL_SCHEMAS = { input: 'inputSchema', output: 'outputSchema' };
|
|
27
|
+
class Reader {
|
|
28
|
+
project;
|
|
29
|
+
kind;
|
|
30
|
+
target;
|
|
31
|
+
found = [];
|
|
32
|
+
/** Where each value the walk followed a name to is written, the whole target first. */
|
|
33
|
+
written = [];
|
|
34
|
+
constructor(project, kind, target) {
|
|
35
|
+
this.project = project;
|
|
36
|
+
this.kind = kind;
|
|
37
|
+
this.target = target;
|
|
38
|
+
}
|
|
39
|
+
note(kind, path, at, more = {}) {
|
|
40
|
+
this.found.push({
|
|
41
|
+
path,
|
|
42
|
+
kind,
|
|
43
|
+
text: textOf(at.node, at.source),
|
|
44
|
+
file: at.source.fileName,
|
|
45
|
+
line: lineOf(at.node, at.source),
|
|
46
|
+
...more,
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
/** The whole target. */
|
|
50
|
+
read() {
|
|
51
|
+
const { options, source, env, call } = this.target;
|
|
52
|
+
// A function that makes the call holds it for each profile it makes.
|
|
53
|
+
const maker = call && holderOf({ node: options, source })?.name;
|
|
54
|
+
this.written.push({
|
|
55
|
+
path: [],
|
|
56
|
+
at: { node: options, source },
|
|
57
|
+
...(maker ? { name: maker } : {}),
|
|
58
|
+
});
|
|
59
|
+
this.walk({ node: options, source, env }, []);
|
|
60
|
+
}
|
|
61
|
+
/** What holds `at`: the target's own options, a constant or a function, or nothing the studio follows. */
|
|
62
|
+
regionOf(at) {
|
|
63
|
+
if (isInTarget(this.target, at))
|
|
64
|
+
return this.target.options;
|
|
65
|
+
return isInCall(this.target, at) ? this.target.call?.node : holderOf(at)?.initializer;
|
|
66
|
+
}
|
|
67
|
+
walk(at, path) {
|
|
68
|
+
const node = unwrapped(at.node);
|
|
69
|
+
if (plain(node) !== NOT_PLAIN)
|
|
70
|
+
return;
|
|
71
|
+
const here = { ...at, node };
|
|
72
|
+
const shape = shapeOf(this.project, here);
|
|
73
|
+
if (shape) {
|
|
74
|
+
this.object(shape, here, path);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
const whole = ts.isArrayLiteralExpression(node) &&
|
|
78
|
+
!node.elements.some((element) => ts.isSpreadElement(element) || ts.isOmittedExpression(element));
|
|
79
|
+
if (whole) {
|
|
80
|
+
for (const [index, element] of node.elements.entries())
|
|
81
|
+
this.walk({ ...at, node: element }, [...path, String(index)]);
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
this.named(here, path);
|
|
85
|
+
}
|
|
86
|
+
/** A value the files reach by a name, a call, or a key: read where it is written. */
|
|
87
|
+
named(at, path) {
|
|
88
|
+
const origin = followed(this.project, at);
|
|
89
|
+
if (origin.node === at.node && origin.source === at.source)
|
|
90
|
+
this.note('code', path, at);
|
|
91
|
+
else
|
|
92
|
+
this.enter(origin, path, at);
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* A value written somewhere other than where the walk is. In the target's own call it is the
|
|
96
|
+
* target's. In a constant or a function it is read there, with each line of other code that
|
|
97
|
+
* reads it too.
|
|
98
|
+
*/
|
|
99
|
+
enter(origin, path, from) {
|
|
100
|
+
if (isInTarget(this.target, origin) || isInCall(this.target, origin)) {
|
|
101
|
+
this.written.push({ path, at: origin });
|
|
102
|
+
this.walk(origin, path);
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
const holder = holderOf(origin);
|
|
106
|
+
if (!holder)
|
|
107
|
+
this.note('code', path, from);
|
|
108
|
+
else {
|
|
109
|
+
const users = usersOf(this.project, holder);
|
|
110
|
+
if (users.code && isHeldId(this.kind, path, origin)) {
|
|
111
|
+
this.note('constant', path, { node: holder.initializer.parent, source: holder.source }, { text: holder.name });
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
const readBy = users.readBy.map((read) => ({
|
|
115
|
+
file: read.source.fileName,
|
|
116
|
+
line: lineOf(read.node, read.source),
|
|
117
|
+
}));
|
|
118
|
+
this.written.push({ path, at: origin, name: holder.name, ...(users.code ? { readBy } : {}) });
|
|
119
|
+
this.walk(origin, path);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
object(shape, at, path) {
|
|
123
|
+
const { open } = shape;
|
|
124
|
+
const region = this.regionOf(at);
|
|
125
|
+
// The last one of a name is the one that counts.
|
|
126
|
+
for (const entry of [...shape.entries.values()].reverse()) {
|
|
127
|
+
const schema = this.kind === 'tool' && path.length === 0 ? TOOL_SCHEMAS[entry.key] : undefined;
|
|
128
|
+
const here = [...path, schema ?? entry.key];
|
|
129
|
+
const place = entry.property ? { node: entry.property, source: entry.source } : at;
|
|
130
|
+
if (schema) {
|
|
131
|
+
if (entry.value && !(open && !open.after.has(entry.key)))
|
|
132
|
+
this.schema(entry.value, here, place);
|
|
133
|
+
else
|
|
134
|
+
this.note('code', here, place);
|
|
135
|
+
} // A spread, or a key the file computes: what the object holds past it is not written here.
|
|
136
|
+
else if (open && !open.after.has(entry.key))
|
|
137
|
+
this.note('code', here, open);
|
|
138
|
+
// A model's provider is the name its line is built on: a change rewrites the name, never the provider's id.
|
|
139
|
+
else if (entry.receiver) {
|
|
140
|
+
const named = entry.value && ts.isIdentifier(unwrapped(entry.receiver.node));
|
|
141
|
+
if (!named)
|
|
142
|
+
this.note('code', here, { node: entry.receiver.node, source: entry.receiver.source });
|
|
143
|
+
}
|
|
144
|
+
else if (!entry.value)
|
|
145
|
+
this.note('code', here, place);
|
|
146
|
+
// A model's protocol is the kernel's name for it: Save rewrites the name.
|
|
147
|
+
else if (entry.key === 'protocol' && isKernelName(entry.value))
|
|
148
|
+
continue;
|
|
149
|
+
else if (entry.property && ts.isShorthandPropertyAssignment(entry.property))
|
|
150
|
+
this.named(entry.value, here);
|
|
151
|
+
else if (this.regionOf(entry.value) === region)
|
|
152
|
+
this.walk(entry.value, here);
|
|
153
|
+
else
|
|
154
|
+
this.enter(entry.value, here, place);
|
|
155
|
+
}
|
|
156
|
+
if (open)
|
|
157
|
+
this.note('spread', path, open, { written: [...open.after] });
|
|
158
|
+
}
|
|
159
|
+
/** A tool's schema. One that does not read as Zod is code's to change. */
|
|
160
|
+
schema(at, path, place) {
|
|
161
|
+
const read = readZod(this.project, at);
|
|
162
|
+
if (read)
|
|
163
|
+
this.zod(read, path, this.target.options);
|
|
164
|
+
else
|
|
165
|
+
this.note('code', path, place);
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Each constant a schema is written in, at the part of the schema it writes: the schema several
|
|
169
|
+
* tools take, a field's schema a constant holds. The place is the part's own `z.` call, so two
|
|
170
|
+
* tools that reach one call hold one value. `within` is what holds the schema around this one:
|
|
171
|
+
* the target's own call, or a constant.
|
|
172
|
+
*/
|
|
173
|
+
zod(read, path, within) {
|
|
174
|
+
/** Notes `node` at `at` when another constant than `outer` holds it, and says which one does. */
|
|
175
|
+
const reach = (node, source, at, outer) => {
|
|
176
|
+
const place = { node: node, source };
|
|
177
|
+
if (isInTarget(this.target, place))
|
|
178
|
+
return this.target.options;
|
|
179
|
+
if (this.target.call && isInCall(this.target, place))
|
|
180
|
+
return this.target.call.node;
|
|
181
|
+
const holder = holderOf(place);
|
|
182
|
+
if (!holder || holder.initializer === outer)
|
|
183
|
+
return outer;
|
|
184
|
+
const users = usersOf(this.project, holder);
|
|
185
|
+
const readBy = users.readBy.map((each) => ({
|
|
186
|
+
file: each.source.fileName,
|
|
187
|
+
line: lineOf(each.node, each.source),
|
|
188
|
+
}));
|
|
189
|
+
this.written.push({
|
|
190
|
+
path: at,
|
|
191
|
+
at: { node, source },
|
|
192
|
+
name: holder.name,
|
|
193
|
+
...(users.code ? { readBy } : {}),
|
|
194
|
+
});
|
|
195
|
+
return holder.initializer;
|
|
196
|
+
};
|
|
197
|
+
const { base } = read;
|
|
198
|
+
const around = reach(base.call, base.source, path, within);
|
|
199
|
+
const inside = (node, at) => {
|
|
200
|
+
const part = readZod(this.project, {
|
|
201
|
+
node,
|
|
202
|
+
source: base.source,
|
|
203
|
+
...(base.env ? { env: base.env } : {}),
|
|
204
|
+
});
|
|
205
|
+
if (part)
|
|
206
|
+
this.zod(part, at, around);
|
|
207
|
+
};
|
|
208
|
+
const [first] = base.call.arguments;
|
|
209
|
+
const list = first && base.name === 'union' ? unwrapped(first) : undefined;
|
|
210
|
+
if (first && base.name === 'array' && !ts.isSpreadElement(first))
|
|
211
|
+
inside(first, [...path, 'items']);
|
|
212
|
+
if (list && ts.isArrayLiteralExpression(list)) {
|
|
213
|
+
list.elements.forEach((member, index) => {
|
|
214
|
+
if (!ts.isSpreadElement(member))
|
|
215
|
+
inside(member, [...path, 'anyOf', String(index)]);
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
const object = zodObject(this.project, read);
|
|
219
|
+
if (!object)
|
|
220
|
+
return;
|
|
221
|
+
for (const entry of object.entries.values()) {
|
|
222
|
+
const part = entry.value && readZod(this.project, entry.value);
|
|
223
|
+
if (part)
|
|
224
|
+
this.zod(part, [...path, 'properties', entry.key], around);
|
|
225
|
+
}
|
|
226
|
+
// Which fields an extended object needs is its own to say.
|
|
227
|
+
if (object.extended)
|
|
228
|
+
reach(object.own.node, object.own.source, [...path, 'required'], around);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
function originsOf(project, kind, targets) {
|
|
232
|
+
const [target] = targets;
|
|
233
|
+
if (!target)
|
|
234
|
+
return { origins: [], written: [] };
|
|
235
|
+
if (targets.length > 1) {
|
|
236
|
+
// Written twice: the studio cannot tell which one runs.
|
|
237
|
+
const twice = {
|
|
238
|
+
path: [],
|
|
239
|
+
kind: 'twice',
|
|
240
|
+
file: target.file,
|
|
241
|
+
line: lineOf(target.options, target.source),
|
|
242
|
+
};
|
|
243
|
+
return { origins: [twice], written: [] };
|
|
244
|
+
}
|
|
245
|
+
const reader = new Reader(project, kind, target);
|
|
246
|
+
reader.read();
|
|
247
|
+
return { origins: reader.found, written: reader.written };
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Where a decision profile's questions or pictures are set: the setup module's export of `name`,
|
|
251
|
+
* at the profile's own key when it writes one. A profile does not hold them, so the studio shows
|
|
252
|
+
* them and does not change them. No place when the setup exports them another way.
|
|
253
|
+
*/
|
|
254
|
+
function setupOrigin(project, profileId, name) {
|
|
255
|
+
const origin = {
|
|
256
|
+
path: ['decision', name],
|
|
257
|
+
kind: 'code',
|
|
258
|
+
text: `export const ${name}`,
|
|
259
|
+
};
|
|
260
|
+
const source = project.files.get(project.entry);
|
|
261
|
+
const held = source && setupExport(source, name);
|
|
262
|
+
if (!source || !held)
|
|
263
|
+
return origin;
|
|
264
|
+
const value = held.initializer && unwrapped(held.initializer);
|
|
265
|
+
const own = value && ts.isObjectLiteralExpression(value)
|
|
266
|
+
? value.properties.findLast((property) => propertyName(property) === profileId)
|
|
267
|
+
: undefined;
|
|
268
|
+
return { ...origin, file: source.fileName, line: lineOf(own ?? held, source) };
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* The settings the project's files set in code, for each profile, tool, and provider the files
|
|
272
|
+
* define. One with none is left out. `decisions` names the decision profiles the studio
|
|
273
|
+
* shows: each one's questions and pictures are set in the setup module.
|
|
274
|
+
*/
|
|
275
|
+
export function sourceOrigins(project, decisions = []) {
|
|
276
|
+
const places = new Map();
|
|
277
|
+
const read = (kind, targets) => {
|
|
278
|
+
const origins = {};
|
|
279
|
+
const written = {};
|
|
280
|
+
for (const [name, held] of targets) {
|
|
281
|
+
const found = originsOf(project, kind, held);
|
|
282
|
+
if (found.origins.length)
|
|
283
|
+
origins[name] = found.origins;
|
|
284
|
+
written[name] = found.written;
|
|
285
|
+
for (const { at } of found.written) {
|
|
286
|
+
const place = places.get(at.node) ?? { site: places.size + 1, held: 0 };
|
|
287
|
+
places.set(at.node, { ...place, held: place.held + 1 });
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
return { origins, written };
|
|
291
|
+
};
|
|
292
|
+
const [profiles, tools] = [read('profile', project.profiles), read('tool', project.tools)];
|
|
293
|
+
const providers = read('provider', project.providers);
|
|
294
|
+
for (const id of decisions)
|
|
295
|
+
profiles.origins[id] = [
|
|
296
|
+
...(profiles.origins[id] ?? []),
|
|
297
|
+
setupOrigin(project, id, 'questions'),
|
|
298
|
+
setupOrigin(project, id, 'images'),
|
|
299
|
+
];
|
|
300
|
+
/** The places something else reads too, and under each of them the ones a setting has to itself. */
|
|
301
|
+
const sites = (written) => {
|
|
302
|
+
const sites = {};
|
|
303
|
+
for (const [name, held] of Object.entries(written)) {
|
|
304
|
+
const shared = held.filter(({ at }) => (places.get(at.node)?.held ?? 0) > 1);
|
|
305
|
+
const reached = held.filter((each) => shared.includes(each) || each.readBy);
|
|
306
|
+
const under = (path) => reached.some((each) => each.path.every((key, index) => path[index] === key));
|
|
307
|
+
const kept = held.filter((each) => under(each.path));
|
|
308
|
+
if (!reached.length)
|
|
309
|
+
continue;
|
|
310
|
+
sites[name] = kept.map(({ path, at, name: holder, readBy }) => ({
|
|
311
|
+
path,
|
|
312
|
+
site: places.get(at.node)?.site ?? 0,
|
|
313
|
+
shared: shared.some((each) => each.at.node === at.node),
|
|
314
|
+
...(holder ? { name: holder } : {}),
|
|
315
|
+
file: at.source.fileName,
|
|
316
|
+
line: lineOf(at.node, at.source),
|
|
317
|
+
...(readBy ? { readBy } : {}),
|
|
318
|
+
}));
|
|
319
|
+
}
|
|
320
|
+
return sites;
|
|
321
|
+
};
|
|
322
|
+
const held = { profiles: sites(profiles.written), tools: sites(tools.written) };
|
|
323
|
+
const some = Object.keys(held.profiles).length + Object.keys(held.tools).length > 0;
|
|
324
|
+
return {
|
|
325
|
+
profiles: profiles.origins,
|
|
326
|
+
tools: tools.origins,
|
|
327
|
+
providers: providers.origins,
|
|
328
|
+
...(some ? { sites: held } : {}),
|
|
329
|
+
};
|
|
330
|
+
}
|