@kabmo-labs/kabmo 0.7.0 → 0.9.0
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 +7 -0
- package/dist/client/index.html +1 -1
- package/dist/client/index.js +403 -384
- package/dist/client/static/js/{index-0wvbca0b.js → index-bpptfkz2.js} +905 -875
- package/dist/client/static/js/index-k315p1e8.css +1 -0
- package/package.json +10 -1
- package/src/client/components/common/code-surface/documents.test.ts +120 -0
- package/src/client/components/common/code-surface/documents.ts +201 -0
- package/src/client/components/common/code-surface/extensions.test.ts +110 -0
- package/src/client/components/common/code-surface/extensions.ts +162 -0
- package/src/client/components/common/code-surface/handle.ts +102 -0
- package/src/client/components/common/code-surface/index.tsx +253 -314
- package/src/client/components/common/code-surface/keymap.test.ts +133 -0
- package/src/client/components/common/code-surface/keymap.ts +267 -0
- package/src/client/components/common/code-surface/marks.ts +74 -0
- package/src/client/components/common/code-surface/shiki.ts +234 -0
- package/src/client/components/common/code-surface/sync.test.ts +185 -0
- package/src/client/components/common/code-surface/sync.ts +58 -0
- package/src/client/components/common/code-surface/theme.test.ts +202 -0
- package/src/client/components/common/code-surface/theme.ts +111 -0
- package/src/client/components/common/editor-view-buttons/index.test.tsx +148 -0
- package/src/client/components/common/editor-view-buttons/index.tsx +109 -0
- package/src/client/components/common/header-controls/index.tsx +24 -1
- package/src/client/components/common/header-controls/shell-chrome.test.tsx +272 -0
- package/src/client/components/common/shell-update-button/Modal.tsx +163 -0
- package/src/client/components/common/shell-update-button/index.test.tsx +251 -0
- package/src/client/components/common/shell-update-button/index.tsx +125 -0
- package/src/client/components/common/toolbar-row/index.test.tsx +166 -0
- package/src/client/components/common/toolbar-row/index.tsx +189 -0
- package/src/client/components/common/workspace-options-menu/index.tsx +19 -1
- package/src/client/components/layout/desktop-layout/TopNavbar.tsx +5 -6
- package/src/client/components/layout/desktop-layout/WorkspacePanels.tsx +41 -78
- package/src/client/components/layout/desktop-layout/index.tsx +55 -69
- package/src/client/components/layout/desktop-layout/resizer/index.tsx +6 -3
- package/src/client/components/layout/session-sidebar/CategoryHeader.tsx +24 -0
- package/src/client/components/layout/session-sidebar/CategoryHeader.worktree.test.tsx +126 -0
- package/src/client/components/layout/session-sidebar/CategoryItem.tsx +4 -0
- package/src/client/components/layout/session-sidebar/Footer.tsx +8 -15
- package/src/client/components/layout/session-sidebar/SessionItem.tsx +12 -0
- package/src/client/components/layout/session-sidebar/SessionList.tsx +4 -0
- package/src/client/components/layout/session-sidebar/SessionsView.tsx +24 -0
- package/src/client/components/layout/session-sidebar/WorktreeBadge.test.ts +48 -0
- package/src/client/components/layout/session-sidebar/WorktreeBadge.tsx +55 -0
- package/src/client/components/mobile/LayoutWrapper.tsx +23 -16
- package/src/client/components/mobile/RightSidebar.tsx +21 -10
- package/src/client/components/mobile/SessionSidebar.tsx +8 -0
- package/src/client/components/mobile/header-titlebar.test.tsx +172 -0
- package/src/client/components/mobile/mobile-main-view/Header.tsx +10 -1
- package/src/client/components/mobile/mobile-right-sidebar/FullDiff.tsx +3 -0
- package/src/client/components/mobile/mobile-right-sidebar/FullEditor.tsx +63 -38
- package/src/client/components/mobile/mobile-right-sidebar/OutlineButton.test.tsx +137 -0
- package/src/client/components/mobile/mobile-right-sidebar/OutlineButton.tsx +14 -3
- package/src/client/components/mobile/mobile-session-sidebar/Footer.tsx +9 -21
- package/src/client/components/mobile/mobile-session-sidebar/Header.tsx +6 -2
- package/src/client/components/mobile/mobile-session-sidebar/Item.tsx +16 -0
- package/src/client/components/mobile/mobile-session-sidebar/List.tsx +4 -0
- package/src/client/components/mobile/mobile-session-sidebar/SessionRow.tsx +5 -0
- package/src/client/components/mobile/mobile-session-sidebar/WorktreeDialog.tsx +49 -0
- package/src/client/components/mobile/worktree-session.ts +51 -0
- package/src/client/components/settings/Modal.tsx +8 -0
- package/src/client/components/settings/categories/AppearanceSettings.tsx +3 -0
- package/src/client/components/settings/categories/ProjectSettings.tsx +22 -8
- package/src/client/components/settings/categories/appearance-settings/EditorThemeSection.test.tsx +167 -0
- package/src/client/components/settings/categories/appearance-settings/EditorThemeSection.tsx +184 -0
- package/src/client/components/settings/categories/project-settings/WorktreeSettings.tsx +146 -0
- package/src/client/components/settings/categories/project-settings/worktree-row.test.ts +83 -0
- package/src/client/components/settings/categories/project-settings/worktree-row.ts +47 -0
- package/src/client/components/workspace/chat-timeline/EmptyWorkspacePrompt.tsx +36 -55
- package/src/client/components/workspace/chat-timeline/PendingChatView.tsx +8 -0
- package/src/client/components/workspace/chat-timeline/SystemNotice.tsx +9 -4
- package/src/client/components/workspace/chat-timeline/TaskResultContent.tsx +9 -7
- package/src/client/components/workspace/chat-timeline/index.tsx +5 -0
- package/src/client/components/workspace/chat-timeline/target-picker/WorkspacePicker.test.tsx +132 -0
- package/src/client/components/workspace/chat-timeline/target-picker/WorkspacePicker.tsx +120 -0
- package/src/client/components/workspace/chat-timeline/target-picker/WorktreePicker.test.tsx +319 -0
- package/src/client/components/workspace/chat-timeline/target-picker/WorktreePicker.tsx +285 -0
- package/src/client/components/workspace/chat-timeline/tool-renderers/ask-panel/index.test.ts +2 -0
- package/src/client/components/workspace/chat-timeline/tool-renderers/hashline-patch/index.tsx +34 -29
- package/src/client/components/workspace/chat-timeline/tool-renderers/panels/AstEdit.tsx +11 -9
- package/src/client/components/workspace/chat-timeline/tool-renderers/panels/Bash.tsx +10 -7
- package/src/client/components/workspace/chat-timeline/tool-renderers/panels/Edit.tsx +25 -8
- package/src/client/components/workspace/chat-timeline/tool-renderers/panels/Eval.test.tsx +146 -0
- package/src/client/components/workspace/chat-timeline/tool-renderers/panels/Eval.tsx +32 -17
- package/src/client/components/workspace/chat-timeline/tool-renderers/panels/FileMatches.test.ts +114 -0
- package/src/client/components/workspace/chat-timeline/tool-renderers/panels/FileMatches.tsx +111 -0
- package/src/client/components/workspace/chat-timeline/tool-renderers/panels/Read.tsx +7 -7
- package/src/client/components/workspace/chat-timeline/tool-renderers/panels/SearchTool.tsx +9 -59
- package/src/client/components/workspace/chat-timeline/tool-renderers/shared/ArtifactBody.tsx +2 -7
- package/src/client/components/workspace/chat-timeline/tool-renderers/shared/DiffView.test.ts +27 -28
- package/src/client/components/workspace/chat-timeline/tool-renderers/shared/DiffView.tsx +39 -26
- package/src/client/components/workspace/chat-timeline/tool-renderers/shared/ExcerptCode.tsx +8 -8
- package/src/client/components/workspace/chat-timeline/tool-renderers/shared/HighlightedCode.tsx +35 -0
- package/src/client/components/workspace/chat-timeline/tool-renderers/shared/JsonCodeBlock.tsx +4 -4
- package/src/client/components/workspace/diff-panel/MergeDiffView.tsx +179 -0
- package/src/client/components/workspace/diff-panel/ThemedMergeDiffView.tsx +24 -0
- package/src/client/components/workspace/diff-panel/Toolbar.tsx +224 -186
- package/src/client/components/workspace/diff-panel/ToolbarSegments.tsx +98 -0
- package/src/client/components/workspace/diff-panel/index.tsx +76 -145
- package/src/client/components/workspace/diff-panel/merge.ts +315 -0
- package/src/client/components/workspace/editor/Body.tsx +4 -7
- package/src/client/components/workspace/editor/CommandPalette.tsx +2 -2
- package/src/client/components/workspace/editor/FileDocument.tsx +58 -63
- package/src/client/components/workspace/editor/FilePane.tsx +4 -7
- package/src/client/components/workspace/editor/FindWidget.tsx +7 -2
- package/src/client/components/workspace/editor/Toolbar.tsx +220 -123
- package/src/client/components/workspace/editor/index.tsx +7 -9
- package/src/client/components/workspace/file-explorer/ContextMenu.tsx +2 -1
- package/src/client/components/workspace/file-explorer/Modals.tsx +40 -12
- package/src/client/components/workspace/file-explorer/OutlineSection.test.tsx +18 -0
- package/src/client/components/workspace/file-explorer/OutlineSection.tsx +10 -3
- package/src/client/components/workspace/file-explorer/RootMenu.tsx +14 -5
- package/src/client/components/workspace/file-explorer/Toolbar.tsx +74 -0
- package/src/client/components/workspace/file-explorer/TreeItem.tsx +38 -3
- package/src/client/components/workspace/file-explorer/filter.ts +47 -0
- package/src/client/components/workspace/file-explorer/index.tsx +77 -64
- package/src/client/components/workspace/file-explorer/local-edit.test.ts +135 -0
- package/src/client/components/workspace/search-panel/Body.tsx +1 -1
- package/src/client/components/workspace/worktree-modal/index.test.tsx +118 -0
- package/src/client/components/workspace/worktree-modal/index.tsx +261 -0
- package/src/client/hooks/chat/omp/reconnect.test.ts +338 -0
- package/src/client/hooks/chat/omp/reconnect.ts +187 -0
- package/src/client/hooks/chat/omp/run-liveness.test.ts +71 -0
- package/src/client/hooks/chat/omp/run-liveness.ts +65 -0
- package/src/client/hooks/chat/omp/session-list.activity.test.ts +114 -0
- package/src/client/hooks/chat/omp/session-list.test-util.ts +164 -0
- package/src/client/hooks/chat/omp/session-list.test.ts +30 -150
- package/src/client/hooks/chat/omp/session-list.tsx +69 -9
- package/src/client/hooks/chat/timeline/generating.ts +19 -2
- package/src/client/hooks/chat/timeline/index.ts +27 -28
- package/src/client/hooks/chat/timeline/lost-run.test.ts +329 -0
- package/src/client/hooks/chat/timeline/lost-run.ts +177 -0
- package/src/client/hooks/chat/timeline/send-execute.test.ts +2 -0
- package/src/client/hooks/chat/timeline/send-steer.test.ts +2 -0
- package/src/client/hooks/chat/timeline/send.test.ts +2 -0
- package/src/client/hooks/chat/timeline/send.ts +11 -1
- package/src/client/hooks/chat/timeline/session-load.test-util.ts +205 -0
- package/src/client/hooks/chat/timeline/session-load.test.ts +61 -162
- package/src/client/hooks/chat/timeline/session-load.ts +69 -37
- package/src/client/hooks/chat/timeline/session-switch.test.ts +65 -0
- package/src/client/hooks/chat/timeline/session-switch.ts +63 -0
- package/src/client/hooks/chat/timeline/spawn-target.ts +52 -0
- package/src/client/hooks/chat/timeline/tool-open.test.ts +74 -0
- package/src/client/hooks/chat/timeline/tool-open.ts +52 -8
- package/src/client/hooks/code/deferred-highlight.test.ts +182 -0
- package/src/client/hooks/code/deferred-highlight.ts +129 -0
- package/src/client/hooks/editor/find-state.ts +1 -1
- package/src/client/hooks/editor/theme.test.ts +206 -0
- package/src/client/hooks/editor/theme.ts +82 -0
- package/src/client/hooks/editor/use-editor-drop.test.ts +101 -0
- package/src/client/hooks/editor/use-editor-drop.ts +67 -14
- package/src/client/hooks/editor/use-editor-find.ts +7 -7
- package/src/client/hooks/editor/use-outline-view.test.ts +182 -0
- package/src/client/hooks/editor/use-outline-view.ts +94 -7
- package/src/client/hooks/editor/use-scroll-restore.test.ts +55 -2
- package/src/client/hooks/editor/use-scroll-restore.ts +124 -4
- package/src/client/hooks/editor/use-search-reveal.ts +1 -1
- package/src/client/hooks/ui/long-press.test.ts +174 -0
- package/src/client/hooks/ui/long-press.ts +112 -0
- package/src/client/hooks/ui/settings-modal.ts +56 -0
- package/src/client/hooks/ui/updates/shell-download.test.ts +75 -0
- package/src/client/hooks/ui/updates/shell-download.ts +153 -28
- package/src/client/hooks/ui/updates/shell-offer.test.ts +213 -0
- package/src/client/hooks/ui/updates/shell-update.test.ts +140 -0
- package/src/client/hooks/ui/updates/shell-update.ts +119 -0
- package/src/client/hooks/workspace/diff-file.ts +29 -10
- package/src/client/hooks/workspace/diff-git-actions.ts +147 -0
- package/src/client/hooks/workspace/editor-view.ts +61 -0
- package/src/client/hooks/workspace/file-create.ts +41 -11
- package/src/client/hooks/workspace/file-listing.ts +56 -1
- package/src/client/hooks/workspace/file-tabs.test.ts +62 -5
- package/src/client/hooks/workspace/file-tabs.ts +24 -11
- package/src/client/hooks/workspace/file-tree-actions.ts +37 -5
- package/src/client/hooks/workspace/navbar-session-actions.ts +72 -0
- package/src/client/hooks/workspace/worktree/index.ts +165 -0
- package/src/client/lib/desktop/bridge.ts +45 -0
- package/src/client/lib/search-reveal.ts +1 -1
- package/src/client/main.tsx +5 -1
- package/src/client/tailwind.css +56 -8
- package/src/server/index.ts +7 -2
- package/src/server/lib/auth/guard.test.ts +28 -0
- package/src/server/lib/auth/guard.ts +10 -0
- package/src/server/lib/bundler/titlebar-css.test.ts +42 -1
- package/src/server/lib/db/schema.ts +4 -0
- package/src/server/lib/db/worktree-registry.server.ts +91 -0
- package/src/server/lib/fs/canonical.ts +52 -0
- package/src/server/lib/fs/relative-path.ts +48 -0
- package/src/server/lib/fs/root-worktree.test.ts +116 -0
- package/src/server/lib/fs/root.ts +39 -10
- package/src/server/lib/fs/worktree/carry.ts +134 -0
- package/src/server/lib/fs/worktree/create.test.ts +249 -0
- package/src/server/lib/fs/worktree/create.ts +262 -0
- package/src/server/lib/fs/worktree/errors.ts +43 -0
- package/src/server/lib/fs/worktree/list.test.ts +207 -0
- package/src/server/lib/fs/worktree/list.ts +142 -0
- package/src/server/lib/fs/worktree/location.test.ts +206 -0
- package/src/server/lib/fs/worktree/location.ts +114 -0
- package/src/server/lib/fs/worktree/project-id.ts +53 -0
- package/src/server/lib/fs/worktree/remove.test.ts +242 -0
- package/src/server/lib/fs/worktree/remove.ts +152 -0
- package/src/server/lib/fs/worktree/settings.server.ts +56 -0
- package/src/server/lib/fs/worktree/topology.ts +142 -0
- package/src/server/lib/lifecycle/claim-port.test.ts +156 -0
- package/src/server/lib/lifecycle/port-guard.test.ts +20 -164
- package/src/server/lib/lifecycle/port-guard.ts +39 -7
- package/src/server/lib/lifecycle/probe-health.test.ts +166 -0
- package/src/server/lib/lifecycle/probe.test.ts +77 -164
- package/src/server/lib/lifecycle/probe.ts +121 -13
- package/src/server/lib/omp/rpc/frame-fold-signals.test.ts +112 -0
- package/src/server/lib/omp/rpc/frame-fold.ts +10 -5
- package/src/server/lib/omp/session/sidebar-activity.server.test.ts +162 -0
- package/src/server/lib/omp/session/sidebar-activity.server.ts +70 -0
- package/src/server/lib/omp/session/sidebar-data.canonical.test.ts +155 -0
- package/src/server/lib/omp/session/sidebar-data.server.ts +28 -1
- package/src/server/lib/omp/session/telemetry/compute.ts +13 -1
- package/src/server/lib/omp/session/telemetry.test.ts +33 -0
- package/src/server/lib/panels/local-edits.server.ts +33 -0
- package/src/server/lib/panels/sync.fixture.test-util.ts +92 -0
- package/src/server/lib/panels/sync.local-edits.test.ts +150 -0
- package/src/server/lib/panels/sync.server.test.ts +125 -147
- package/src/server/lib/panels/sync.server.ts +153 -48
- package/src/server/lib/realtime/signals.server.ts +10 -0
- package/src/server/lib/realtime/topics/catalog.server.ts +4 -1
- package/src/server/lib/realtime/topics.server.ts +16 -0
- package/src/server/lib/updates/shell-assets.test.ts +114 -0
- package/src/server/lib/updates/shell-assets.ts +200 -0
- package/src/server/lib/updates/shell-cache.ts +105 -0
- package/src/server/lib/updates/shell-pages.test.ts +187 -0
- package/src/server/lib/updates/shell-pages.ts +157 -0
- package/src/server/lib/updates/shell-release-desktop.test.ts +166 -0
- package/src/server/lib/updates/shell-release.test.ts +59 -71
- package/src/server/lib/updates/shell-release.ts +178 -198
- package/src/server/routes/fs/action-create.test.ts +18 -13
- package/src/server/routes/fs/action-nested.test.ts +184 -0
- package/src/server/routes/fs/action.ts +47 -16
- package/src/server/routes/fs/git-merge.test.ts +11 -1
- package/src/server/routes/fs/read.test.ts +24 -7
- package/src/server/routes/fs/scope.test.ts +15 -10
- package/src/server/routes/fs/scope.ts +3 -14
- package/src/server/routes/index.ts +2 -0
- package/src/server/routes/updates/android.ts +6 -1
- package/src/server/routes/updates/desktop.ts +59 -0
- package/src/server/routes/updates/index.ts +2 -0
- package/src/server/routes/updates/ios.ts +5 -1
- package/src/server/routes/worktrees/create.ts +138 -0
- package/src/server/routes/worktrees/index.ts +25 -0
- package/src/server/routes/worktrees/list.ts +134 -0
- package/src/server/routes/worktrees/remove.ts +102 -0
- package/src/server/routes/worktrees/routes.test.ts +326 -0
- package/src/server/routes/worktrees/shared.ts +90 -0
- package/src/shared/lib/chat/timeline/omp-callbacks.test.ts +36 -0
- package/src/shared/lib/chat/timeline/omp-callbacks.ts +18 -0
- package/src/shared/lib/chat/timeline/run-signals.test.ts +2 -0
- package/src/shared/lib/code/editor/comment-syntax.test.ts +37 -0
- package/src/shared/lib/code/editor/comment-syntax.ts +55 -0
- package/src/shared/lib/code/editor/find-replace.test.ts +134 -0
- package/src/shared/lib/code/editor/{find.ts → find-replace.ts} +23 -107
- package/src/shared/lib/code/editor/{find.test.ts → find-scan.test.ts} +19 -73
- package/src/shared/lib/code/editor/find-scan.ts +177 -0
- package/src/shared/lib/code/editor/keymap.ts +3 -3
- package/src/shared/lib/code/editor/lines.test.ts +7 -55
- package/src/shared/lib/code/editor/lines.ts +8 -48
- package/src/shared/lib/code/editor/marks.test.ts +4 -5
- package/src/shared/lib/code/editor/marks.ts +13 -25
- package/src/shared/lib/code/editor/theme-loader.ts +97 -0
- package/src/shared/lib/code/editor/themes.generated.ts +156 -0
- package/src/shared/lib/code/editor/themes.test.ts +165 -0
- package/src/shared/lib/code/editor/themes.ts +165 -0
- package/src/shared/lib/code/highlight-memo.test.ts +103 -0
- package/src/shared/lib/code/highlight-memo.ts +149 -0
- package/src/shared/lib/code/highlighter-warmup.ts +112 -0
- package/src/shared/lib/code/highlighter.ts +3 -1
- package/src/shared/lib/code/idle.ts +37 -0
- package/src/shared/lib/code/outline/rows.test.ts +96 -0
- package/src/shared/lib/code/outline/rows.ts +94 -0
- package/src/shared/lib/code/syntax-highlight.test.ts +1 -79
- package/src/shared/lib/code/syntax-highlight.ts +2 -3
- package/src/shared/lib/fs/file-kind-classify.test.ts +25 -11
- package/src/shared/lib/fs/file-kind.ts +47 -13
- package/src/shared/lib/fs/file-tree.test.ts +183 -0
- package/src/shared/lib/fs/file-tree.ts +159 -0
- package/src/shared/lib/fs/file-url.test.ts +52 -0
- package/src/shared/lib/fs/file-url.ts +37 -0
- package/src/shared/lib/fs/patch-sides.test.ts +114 -0
- package/src/shared/lib/fs/patch-sides.ts +139 -0
- package/src/shared/lib/fs/paths.test.ts +24 -1
- package/src/shared/lib/fs/paths.ts +17 -0
- package/src/shared/lib/fs/worktree/settings-keys.ts +18 -0
- package/src/shared/lib/omp/session/prewarm.ts +7 -0
- package/src/shared/lib/realtime/protocol.ts +16 -0
- package/src/shared/lib/ui/toolbar-overflow.test.ts +83 -0
- package/src/shared/lib/ui/toolbar-overflow.ts +86 -0
- package/src/shared/lib/updates/shell-arch.ts +54 -0
- package/src/shared/lib/updates/shell-ua.ts +24 -4
- package/src/shared/lib/workspace/active-project.ts +23 -0
- package/src/shared/lib/workspace/editor-view-mode.test.ts +70 -0
- package/src/shared/lib/workspace/editor-view-mode.ts +48 -0
- package/src/shared/lib/workspace/panel-widths.test.ts +30 -0
- package/src/shared/lib/workspace/panel-widths.ts +25 -5
- package/src/shared/lib/workspace/session-state/cache.ts +159 -0
- package/src/shared/lib/workspace/session-state/harness.test-util.ts +55 -0
- package/src/shared/lib/workspace/session-state/merge.ts +100 -0
- package/src/shared/lib/workspace/session-state/store-load.test.ts +206 -0
- package/src/shared/lib/workspace/session-state/store.test.ts +17 -139
- package/src/shared/lib/workspace/session-state/store.ts +92 -130
- package/src/shared/lib/workspace/workspace-modules.test.ts +49 -1
- package/src/shared/lib/workspace/workspace-panel-widths.ts +124 -0
- package/src/shared/lib/workspace/worktree/branch-name.test.ts +95 -0
- package/src/shared/lib/workspace/worktree/branch-name.ts +115 -0
- package/src/shared/lib/workspace/worktree/types.ts +104 -0
- package/src/shared/types/fs.ts +10 -0
- package/src/shared/types/realtime.ts +29 -0
- package/src/shared/types/settings/state.ts +10 -0
- package/src/shared/types/workspace.ts +14 -0
- package/src/test-support/file-explorer-disk.test-util.ts +76 -0
- package/src/test-support/file-explorer.test-util.ts +71 -40
- package/src/test-support/loopback.ts +183 -0
- package/dist/client/static/js/index-nzyjf92m.css +0 -1
- package/src/client/components/common/code-editor/handler.test.ts +0 -274
- package/src/client/components/common/code-editor/handler.ts +0 -175
- package/src/client/components/common/code-editor/index.tsx +0 -314
- package/src/client/components/common/code-surface/measure.ts +0 -148
- package/src/client/components/workspace/diff-panel/SplitView.tsx +0 -209
- package/src/client/components/workspace/diff-panel/UnifiedView.tsx +0 -150
- package/src/client/hooks/editor/scroll-container.test.ts +0 -102
- package/src/client/hooks/editor/scroll-container.ts +0 -26
- package/src/client/hooks/editor/use-code-window.ts +0 -100
- package/src/client/hooks/editor/use-editor-history.test.ts +0 -216
- package/src/client/hooks/editor/use-editor-history.ts +0 -134
- package/src/client/hooks/editor/use-occurrences.test.ts +0 -236
- package/src/client/hooks/editor/use-occurrences.ts +0 -98
- package/src/shared/lib/code/editor/commands.test.ts +0 -155
- package/src/shared/lib/code/editor/commands.ts +0 -260
- package/src/shared/lib/code/editor/edits.test.ts +0 -100
- package/src/shared/lib/code/editor/edits.ts +0 -122
- package/src/shared/lib/code/editor/history.test.ts +0 -118
- package/src/shared/lib/code/editor/history.ts +0 -101
- package/src/shared/lib/code/editor/layers.test.ts +0 -77
- package/src/shared/lib/code/editor/layers.ts +0 -67
- package/src/shared/lib/code/editor/line-edits.test.ts +0 -131
- package/src/shared/lib/code/editor/line-edits.ts +0 -159
- package/src/shared/lib/code/editor/occurrences.test.ts +0 -117
- package/src/shared/lib/code/editor/occurrences.ts +0 -111
- package/src/shared/lib/code/editor/reset-css.test.ts +0 -35
- package/src/shared/lib/code/editor/reset-css.ts +0 -32
- package/src/shared/lib/code/editor/text-commands.test.ts +0 -178
- package/src/shared/lib/code/editor/text-commands.ts +0 -154
- package/src/shared/lib/code/lazy-window.test.ts +0 -161
- package/src/shared/lib/code/lazy-window.ts +0 -156
- package/src/shared/lib/code/windowed-highlight.ts +0 -114
- package/src/shared/lib/fs/diff-parser.test.ts +0 -116
- package/src/shared/lib/fs/diff-parser.ts +0 -213
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* The DESKTOP half of the shell-release read: which artifact a per-architecture
|
|
8
|
+
* shell installs, and when the answer is only the release page.
|
|
9
|
+
*
|
|
10
|
+
* Split from `shell-release.test.ts` because that file is at the repo's 350-line
|
|
11
|
+
* ceiling, and the two questions are separable: the mobile pair resolves ONE
|
|
12
|
+
* artifact for every device, while the desktop trio's answer depends on the
|
|
13
|
+
* architecture the shell reported.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { beforeEach, describe, expect, test } from 'bun:test';
|
|
17
|
+
|
|
18
|
+
import { fetchShellRelease, resetShellReleaseCache } from '@/server/lib/updates/shell-release';
|
|
19
|
+
|
|
20
|
+
/** A fetch double that answers one body. */
|
|
21
|
+
function stubFetch(body: unknown) {
|
|
22
|
+
const calls: string[] = [];
|
|
23
|
+
const impl = (async (input: string | URL | Request) => {
|
|
24
|
+
calls.push(String(input));
|
|
25
|
+
return {
|
|
26
|
+
ok: true,
|
|
27
|
+
json: async () => body,
|
|
28
|
+
text: async () => (typeof body === 'string' ? body : JSON.stringify(body)),
|
|
29
|
+
} as Response;
|
|
30
|
+
}) as unknown as typeof fetch;
|
|
31
|
+
return { impl, calls };
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
describe('fetchShellRelease — desktop architectures', () => {
|
|
35
|
+
// The cache is process-wide (see `resetShellReleaseCache`), so every case
|
|
36
|
+
// starts from a cold one or it reads the previous case's answer.
|
|
37
|
+
beforeEach(() => resetShellReleaseCache());
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* A desktop probe WITHOUT an architecture answers the RELEASE PAGE.
|
|
41
|
+
*
|
|
42
|
+
* Every desktop artifact is per-architecture, and a console served to another
|
|
43
|
+
* machine cannot know which one the window asking runs on. Naming one arch's
|
|
44
|
+
* file would hand half the readers a build that will not launch, so the link is
|
|
45
|
+
* the page that lists all of them and `direct` says it is not installable.
|
|
46
|
+
*/
|
|
47
|
+
test('a desktop probe without an arch answers the release page', async () => {
|
|
48
|
+
const { impl } = stubFetch([
|
|
49
|
+
{
|
|
50
|
+
html_url: 'https://x/app',
|
|
51
|
+
assets: [
|
|
52
|
+
{ name: 'Kabmo-0.2.0-mac-arm64.zip', browser_download_url: 'https://x/mac-arm.zip' },
|
|
53
|
+
{ name: 'Kabmo-0.2.0-mac-x64.dmg', browser_download_url: 'https://x/mac-x64.dmg' },
|
|
54
|
+
],
|
|
55
|
+
},
|
|
56
|
+
]);
|
|
57
|
+
|
|
58
|
+
expect(await fetchShellRelease('macos', impl)).toEqual({
|
|
59
|
+
url: 'https://x/app',
|
|
60
|
+
latest: '0.2.0',
|
|
61
|
+
releaseUrl: 'https://x/app',
|
|
62
|
+
direct: false,
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* WITH an architecture it answers that machine's own installer.
|
|
68
|
+
*
|
|
69
|
+
* This is what makes the desktop self-update possible at all: the shell
|
|
70
|
+
* reports its arch over the bridge, and the console names ONE file instead of
|
|
71
|
+
* a page a human has to read.
|
|
72
|
+
*/
|
|
73
|
+
test('a desktop probe with an arch answers that arch’s installer', async () => {
|
|
74
|
+
const { impl } = stubFetch([
|
|
75
|
+
{
|
|
76
|
+
html_url: 'https://x/app',
|
|
77
|
+
assets: [
|
|
78
|
+
{ name: 'Kabmo-0.2.0-mac-x64.zip', browser_download_url: 'https://x/mac-x64.zip' },
|
|
79
|
+
{ name: 'Kabmo-0.2.0-mac-arm64.zip', browser_download_url: 'https://x/mac-arm.zip' },
|
|
80
|
+
],
|
|
81
|
+
},
|
|
82
|
+
]);
|
|
83
|
+
|
|
84
|
+
expect(await fetchShellRelease('macos', impl, 'arm64')).toEqual({
|
|
85
|
+
url: 'https://x/mac-arm.zip',
|
|
86
|
+
latest: '0.2.0',
|
|
87
|
+
releaseUrl: 'https://x/app',
|
|
88
|
+
direct: true,
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
test('an arch the release does not publish keeps the page, never the sibling', async () => {
|
|
93
|
+
// A build that only shipped x64 must not be installed on an arm64 machine:
|
|
94
|
+
// the page is a correct answer, the other architecture's file is not.
|
|
95
|
+
const { impl } = stubFetch([
|
|
96
|
+
{
|
|
97
|
+
html_url: 'https://x/app',
|
|
98
|
+
assets: [
|
|
99
|
+
{ name: 'Kabmo-0.2.0-mac-x64.zip', browser_download_url: 'https://x/mac-x64.zip' },
|
|
100
|
+
],
|
|
101
|
+
},
|
|
102
|
+
]);
|
|
103
|
+
|
|
104
|
+
expect(await fetchShellRelease('macos', impl, 'arm64')).toEqual({
|
|
105
|
+
url: 'https://x/app',
|
|
106
|
+
latest: '0.2.0',
|
|
107
|
+
releaseUrl: 'https://x/app',
|
|
108
|
+
direct: false,
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
test('the self-update file is the ONE file that shell can install', async () => {
|
|
113
|
+
// macOS installs from the `.zip` (ditto extracts it); the `.dmg` beside it is
|
|
114
|
+
// for a human. Windows installs from the Inno `.exe`; Linux from the
|
|
115
|
+
// AppImage, which is the only one of its four formats a shell can replace.
|
|
116
|
+
const mac = stubFetch([
|
|
117
|
+
{
|
|
118
|
+
html_url: 'https://x/app',
|
|
119
|
+
assets: [
|
|
120
|
+
{ name: 'Kabmo-0.2.0-mac-arm64.dmg', browser_download_url: 'https://x/mac-arm.dmg' },
|
|
121
|
+
{ name: 'Kabmo-0.2.0-mac-arm64.zip', browser_download_url: 'https://x/mac-arm.zip' },
|
|
122
|
+
],
|
|
123
|
+
},
|
|
124
|
+
]);
|
|
125
|
+
expect((await fetchShellRelease('macos', mac.impl, 'arm64'))?.url).toBe('https://x/mac-arm.zip');
|
|
126
|
+
|
|
127
|
+
const win = stubFetch([
|
|
128
|
+
{
|
|
129
|
+
html_url: 'https://x/app',
|
|
130
|
+
assets: [
|
|
131
|
+
{ name: 'Kabmo-0.2.0-win-x64-setup.exe', browser_download_url: 'https://x/win-x64.exe' },
|
|
132
|
+
],
|
|
133
|
+
},
|
|
134
|
+
]);
|
|
135
|
+
expect((await fetchShellRelease('windows', win.impl, 'x64'))?.url).toBe('https://x/win-x64.exe');
|
|
136
|
+
|
|
137
|
+
const linux = stubFetch([
|
|
138
|
+
{
|
|
139
|
+
html_url: 'https://x/app',
|
|
140
|
+
assets: [
|
|
141
|
+
{ name: 'Kabmo-0.2.0-linux-x86_64.tar.gz', browser_download_url: 'https://x/linux.tgz' },
|
|
142
|
+
{ name: 'Kabmo-0.2.0-linux-x86_64.AppImage', browser_download_url: 'https://x/linux.AppImage' },
|
|
143
|
+
],
|
|
144
|
+
},
|
|
145
|
+
]);
|
|
146
|
+
expect((await fetchShellRelease('linux', linux.impl, 'x64'))?.url).toBe('https://x/linux.AppImage');
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
test('the arch is part of the cache key', async () => {
|
|
150
|
+
// One console is routinely shared by a whole team, and two machines on it
|
|
151
|
+
// differ only by architecture. A shared slot would answer the second one with
|
|
152
|
+
// the first one's installer.
|
|
153
|
+
const release = {
|
|
154
|
+
html_url: 'https://x/app',
|
|
155
|
+
assets: [
|
|
156
|
+
{ name: 'Kabmo-0.3.0-mac-arm64.zip', browser_download_url: 'https://x/arm.zip' },
|
|
157
|
+
{ name: 'Kabmo-0.3.0-mac-x64.zip', browser_download_url: 'https://x/x64.zip' },
|
|
158
|
+
],
|
|
159
|
+
};
|
|
160
|
+
expect((await fetchShellRelease('macos', stubFetch([release]).impl, 'arm64'))?.url).toBe('https://x/arm.zip');
|
|
161
|
+
|
|
162
|
+
const { impl, calls } = stubFetch([release]);
|
|
163
|
+
expect((await fetchShellRelease('macos', impl, 'x64'))?.url).toBe('https://x/x64.zip');
|
|
164
|
+
expect(calls.length, 'a different arch is a different question').toBeGreaterThan(0);
|
|
165
|
+
});
|
|
166
|
+
});
|
|
@@ -5,75 +5,16 @@
|
|
|
5
5
|
|
|
6
6
|
import { beforeEach, describe, expect, test } from 'bun:test';
|
|
7
7
|
|
|
8
|
-
import { fetchShellRelease, resetShellReleaseCache
|
|
8
|
+
import { fetchShellRelease, resetShellReleaseCache } from '@/server/lib/updates/shell-release';
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
|
-
*
|
|
12
|
-
* release TAG names the SERVER version, and the two move independently. A parser
|
|
13
|
-
* that read the tag would compare a server version against a shell version.
|
|
11
|
+
* A fetch double that answers one body, and counts its calls.
|
|
14
12
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
13
|
+
* `text()` is provided as well as `json()`: the public-pages fallback reads Atom
|
|
14
|
+
* and HTML, and a stub that only answered `json()` would throw inside it and make
|
|
15
|
+
* a broken parse look like a clean "no release" — the exact confusion these
|
|
16
|
+
* tests exist to prevent.
|
|
17
17
|
*/
|
|
18
|
-
describe('versionFromAssetName', () => {
|
|
19
|
-
test('reads the version the release workflows write', () => {
|
|
20
|
-
expect(versionFromAssetName('android', 'Kabmo-0.5.0-android.apk')).toBe('0.5.0');
|
|
21
|
-
expect(versionFromAssetName('ios', 'Kabmo-0.1.0-ios.ipa')).toBe('0.1.0');
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* The old spelling is still READ, and that is not sentiment.
|
|
26
|
-
*
|
|
27
|
-
* These names are the only record of a published shell, and every release
|
|
28
|
-
* already on GitHub carries `kabmo-android-v<v>.apk`. A parser that only knew
|
|
29
|
-
* the new scheme would answer "no update" for an installed shell the moment
|
|
30
|
-
* this shipped — silently, because a name that does not match reads exactly
|
|
31
|
-
* like a release with no artifact.
|
|
32
|
-
*/
|
|
33
|
-
test('still reads the legacy spelling every published release carries', () => {
|
|
34
|
-
expect(versionFromAssetName('android', 'kabmo-android-v0.5.0.apk')).toBe('0.5.0');
|
|
35
|
-
expect(versionFromAssetName('ios', 'kabmo-ios-v0.1.0.ipa')).toBe('0.1.0');
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
test('ignores anything that is not that shell’s artifact', () => {
|
|
39
|
-
expect(versionFromAssetName('android', 'Kabmo-1.2.3-android.apk.zip')).toBeNull();
|
|
40
|
-
expect(versionFromAssetName('android', 'source.tar.gz')).toBeNull();
|
|
41
|
-
expect(versionFromAssetName('android', 'Kabmo-latest-android.apk')).toBeNull();
|
|
42
|
-
expect(versionFromAssetName('android', 'Kabmo--android.apk')).toBeNull();
|
|
43
|
-
expect(versionFromAssetName('android', '')).toBeNull();
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* The desktop assets share the `Kabmo-` prefix, so the EXTENSION is what keeps
|
|
48
|
-
* them out. A probe that matched on the prefix alone would offer a Mac `.dmg`
|
|
49
|
-
* to an Android phone.
|
|
50
|
-
*/
|
|
51
|
-
test('does not read a desktop asset as a mobile one', () => {
|
|
52
|
-
for (const name of [
|
|
53
|
-
'Kabmo-0.1.2-mac-arm64.zip',
|
|
54
|
-
'Kabmo-0.1.2-mac-arm64.dmg',
|
|
55
|
-
'Kabmo-0.1.0-win-x64-setup.exe',
|
|
56
|
-
'Kabmo-0.1.0-linux-x86_64.tar.gz',
|
|
57
|
-
'Kabmo-0.1.0-linux-amd64.deb',
|
|
58
|
-
'Kabmo-0.1.0-linux-x86_64.AppImage',
|
|
59
|
-
]) {
|
|
60
|
-
expect(versionFromAssetName('android', name), name).toBeNull();
|
|
61
|
-
expect(versionFromAssetName('ios', name), name).toBeNull();
|
|
62
|
-
}
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
test('does not accept one shell’s asset for the other', () => {
|
|
66
|
-
// The two probes read the SAME release list, so a parser that ignored the
|
|
67
|
-
// kind would let an iOS probe answer with the APK (and offer an `.apk` to an
|
|
68
|
-
// iPhone).
|
|
69
|
-
expect(versionFromAssetName('ios', 'Kabmo-0.5.0-android.apk')).toBeNull();
|
|
70
|
-
expect(versionFromAssetName('android', 'Kabmo-0.1.0-ios.ipa')).toBeNull();
|
|
71
|
-
expect(versionFromAssetName('ios', 'kabmo-android-v1.2.3.apk')).toBeNull();
|
|
72
|
-
expect(versionFromAssetName('android', 'kabmo-ios-v1.2.3.ipa')).toBeNull();
|
|
73
|
-
});
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
/** A fetch double that answers one body, and counts its calls. */
|
|
77
18
|
function stubFetch(body: unknown, ok = true) {
|
|
78
19
|
const calls: string[] = [];
|
|
79
20
|
const impl = (async (input: string | URL | Request) => {
|
|
@@ -81,11 +22,45 @@ function stubFetch(body: unknown, ok = true) {
|
|
|
81
22
|
return {
|
|
82
23
|
ok,
|
|
83
24
|
json: async () => body,
|
|
25
|
+
text: async () => (typeof body === 'string' ? body : JSON.stringify(body)),
|
|
84
26
|
} as Response;
|
|
85
27
|
}) as unknown as typeof fetch;
|
|
86
28
|
return { impl, calls };
|
|
87
29
|
}
|
|
88
30
|
|
|
31
|
+
/**
|
|
32
|
+
* A double that routes by URL, for the two-path probe.
|
|
33
|
+
*
|
|
34
|
+
* `api` answers the REST read (or fails, which is what a spent quota does) and
|
|
35
|
+
* `pages` answers the Atom feed and each release's asset fragment. Returning
|
|
36
|
+
* `null` for a route means "this request fails", which is how the fallback is
|
|
37
|
+
* entered at all.
|
|
38
|
+
*/
|
|
39
|
+
function routedFetch(routes: {
|
|
40
|
+
api?: unknown;
|
|
41
|
+
atom?: string;
|
|
42
|
+
assets?: Record<string, string>;
|
|
43
|
+
}) {
|
|
44
|
+
const calls: string[] = [];
|
|
45
|
+
const impl = (async (input: string | URL | Request) => {
|
|
46
|
+
const url = String(input);
|
|
47
|
+
calls.push(url);
|
|
48
|
+
|
|
49
|
+
if (url.includes('/repos/')) {
|
|
50
|
+
if (routes.api === undefined) return { ok: false, json: async () => ({}), text: async () => '' } as Response;
|
|
51
|
+
return { ok: true, json: async () => routes.api, text: async () => JSON.stringify(routes.api) } as Response;
|
|
52
|
+
}
|
|
53
|
+
if (url.endsWith('/releases.atom')) {
|
|
54
|
+
const body = routes.atom ?? '';
|
|
55
|
+
return { ok: Boolean(routes.atom), json: async () => ({}), text: async () => body } as Response;
|
|
56
|
+
}
|
|
57
|
+
const tag = url.slice(url.lastIndexOf('/') + 1);
|
|
58
|
+
const body = routes.assets?.[decodeURIComponent(tag)];
|
|
59
|
+
return { ok: body !== undefined, json: async () => ({}), text: async () => body ?? '' } as Response;
|
|
60
|
+
}) as unknown as typeof fetch;
|
|
61
|
+
return { impl, calls };
|
|
62
|
+
}
|
|
63
|
+
|
|
89
64
|
describe('fetchShellRelease', () => {
|
|
90
65
|
// The cache is process-wide (see `resetShellReleaseCache`), so every case
|
|
91
66
|
// starts from a cold one or it reads the previous case's answer.
|
|
@@ -109,6 +84,7 @@ describe('fetchShellRelease', () => {
|
|
|
109
84
|
url: 'https://x/Kabmo-1.2.3-android.apk',
|
|
110
85
|
latest: '1.2.3',
|
|
111
86
|
releaseUrl: 'https://github.com/kabmo-labs/kabmo/releases/tag/v9.9.9',
|
|
87
|
+
direct: true,
|
|
112
88
|
});
|
|
113
89
|
});
|
|
114
90
|
|
|
@@ -127,6 +103,7 @@ describe('fetchShellRelease', () => {
|
|
|
127
103
|
url: 'https://x/i.ipa',
|
|
128
104
|
latest: '0.4.0',
|
|
129
105
|
releaseUrl: 'https://x/app',
|
|
106
|
+
direct: true,
|
|
130
107
|
});
|
|
131
108
|
});
|
|
132
109
|
|
|
@@ -155,6 +132,7 @@ describe('fetchShellRelease', () => {
|
|
|
155
132
|
url: 'https://x/new.apk',
|
|
156
133
|
latest: '0.6.0',
|
|
157
134
|
releaseUrl: 'https://x/r',
|
|
135
|
+
direct: true,
|
|
158
136
|
});
|
|
159
137
|
});
|
|
160
138
|
|
|
@@ -208,6 +186,7 @@ describe('fetchShellRelease', () => {
|
|
|
208
186
|
url: 'https://x/a.apk',
|
|
209
187
|
latest: '0.3.0',
|
|
210
188
|
releaseUrl: 'https://x/app',
|
|
189
|
+
direct: true,
|
|
211
190
|
});
|
|
212
191
|
});
|
|
213
192
|
|
|
@@ -237,19 +216,28 @@ describe('fetchShellRelease', () => {
|
|
|
237
216
|
{ html_url: 'https://x', assets: [{ name: 'notes.md' }] },
|
|
238
217
|
{ html_url: 'https://y', assets: [] },
|
|
239
218
|
]);
|
|
240
|
-
expect(await fetchShellRelease('android', impl)).toEqual({
|
|
219
|
+
expect(await fetchShellRelease('android', impl)).toEqual({
|
|
220
|
+
url: null,
|
|
221
|
+
latest: null,
|
|
222
|
+
releaseUrl: null,
|
|
223
|
+
direct: false,
|
|
224
|
+
});
|
|
241
225
|
});
|
|
242
226
|
|
|
243
227
|
test('answers null when the probe fails', async () => {
|
|
244
|
-
// An offline box
|
|
245
|
-
//
|
|
246
|
-
//
|
|
247
|
-
|
|
228
|
+
// An offline box must not take the sidebar down, and a failure must not be
|
|
229
|
+
// read as "no newer version" either — it is simply no offer. BOTH paths are
|
|
230
|
+
// down here: the API refuses and the feed is unreachable, which is the only
|
|
231
|
+
// shape that means "cannot ask" rather than "nothing published".
|
|
232
|
+
const { impl } = routedFetch({});
|
|
248
233
|
expect(await fetchShellRelease('android', impl)).toBeNull();
|
|
249
234
|
});
|
|
250
235
|
|
|
251
236
|
test('answers null when the body is malformed', async () => {
|
|
252
|
-
|
|
237
|
+
// The API answers 200 with something that is not a release list, and the
|
|
238
|
+
// feed is unreachable — the API's answer is a failed probe, not an empty
|
|
239
|
+
// repository.
|
|
240
|
+
const { impl } = routedFetch({ api: { assets: 'nope' } });
|
|
253
241
|
expect(await fetchShellRelease('android', impl)).toBeNull();
|
|
254
242
|
});
|
|
255
243
|
});
|