@cueloop/client 0.1.0-alpha.9 → 0.1.0-alpha.91
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/native/build-pty.sh +51 -0
- package/native/build.sh +82 -0
- package/native/darwin-arm64/libcuelooppty.dylib +0 -0
- package/native/darwin-arm64/libcueloopvt.dylib +0 -0
- package/native/src/pty.zig +193 -0
- package/native/src/shim.zig +114 -0
- package/package.json +42 -34
- package/src/App.appearance.test.tsx +53 -0
- package/src/App.autoclose.test.tsx +77 -51
- package/src/App.diff.test.tsx +259 -45
- package/src/App.export.test.tsx +58 -41
- package/src/App.focus.test.ts +89 -0
- package/src/App.identity.test.tsx +78 -0
- package/src/App.plan-render.test.tsx +209 -0
- package/src/App.plan-review.test.tsx +330 -161
- package/src/App.prototype-markdown.test.tsx +128 -0
- package/src/App.prototype.test.tsx +176 -0
- package/src/App.readonly.test.tsx +129 -67
- package/src/App.regression.test.tsx +94 -0
- package/src/App.rendering.test.tsx +61 -35
- package/src/App.share-dialog.test.tsx +172 -0
- package/src/App.submit-confirm.test.tsx +264 -0
- package/src/App.test.tsx +402 -126
- package/src/App.toast.test.tsx +98 -0
- package/src/App.tsx +1406 -1060
- package/src/App.visual.test.tsx +57 -0
- package/src/App.walk.test.tsx +299 -0
- package/src/App.workbench.test.tsx +787 -0
- package/src/__snapshots__/view-plan.regression.test.ts.snap +100 -0
- package/src/annotation-palette.ts +62 -0
- package/src/ansi-screen.test.ts +28 -0
- package/src/ansi-screen.ts +72 -0
- package/src/app-key-state.ts +61 -0
- package/src/app-screens.tsx +577 -0
- package/src/app-view-model.ts +168 -0
- package/src/attribution.test.ts +31 -0
- package/src/attribution.ts +42 -0
- package/src/client-extension-registry.test.tsx +61 -0
- package/src/client-extension-registry.ts +159 -0
- package/src/clipboard.test.ts +23 -0
- package/src/clipboard.ts +33 -0
- package/src/components/AnnotatableFileView.stories.tsx +42 -0
- package/src/components/AnnotatableFileView.test.tsx +102 -0
- package/src/components/AnnotatableFileView.tsx +134 -0
- package/src/components/AnnotationCards.stories.tsx +86 -0
- package/src/components/AnnotationCards.tsx +341 -0
- package/src/components/AnsiScreen.stories.tsx +12 -0
- package/src/components/AnsiScreen.tsx +28 -0
- package/src/components/AppHeader.stories.tsx +50 -0
- package/src/components/AppHeader.tsx +83 -0
- package/src/components/AppShell.brand.test.tsx +58 -0
- package/src/components/AppShell.extensions.test.tsx +191 -0
- package/src/components/AppShell.stories.tsx +89 -0
- package/src/components/AppShell.tsx +362 -0
- package/src/components/AppShell.zoom.test.tsx +135 -0
- package/src/components/BareWorkbenchFileView.stories.tsx +27 -0
- package/src/components/BareWorkbenchFileView.tsx +64 -0
- package/src/components/Breadcrumb.stories.tsx +19 -0
- package/src/components/Breadcrumb.tsx +45 -0
- package/src/components/ChangesColumn.stories.tsx +44 -0
- package/src/components/ChangesColumn.tsx +199 -0
- package/src/components/ChangesFileTree.test.tsx +61 -0
- package/src/components/CodeBlock.stories.tsx +42 -0
- package/src/components/CodeBlock.tsx +84 -0
- package/src/components/CompletionOverlay.stories.tsx +37 -0
- package/src/components/CompletionOverlay.tsx +77 -0
- package/src/components/ConfirmCard.stories.tsx +37 -0
- package/src/components/ConfirmCard.tsx +150 -0
- package/src/components/ConfirmDialog.stories.tsx +21 -0
- package/src/components/ConfirmDialog.tsx +72 -0
- package/src/components/DiffContentView.scroll.test.tsx +149 -0
- package/src/components/DiffContentView.split.test.tsx +140 -0
- package/src/components/DiffContentView.stories.tsx +80 -0
- package/src/components/DiffContentView.syntax.test.tsx +82 -0
- package/src/components/DiffContentView.tsx +906 -0
- package/src/components/DiscussionMarkerRail.stories.tsx +54 -0
- package/src/components/DiscussionMarkerRail.tsx +186 -0
- package/src/components/EditorGrid.stories.tsx +59 -0
- package/src/components/EditorGrid.tabs.test.tsx +118 -0
- package/src/components/EditorGrid.tsx +426 -0
- package/src/components/EditorGrid.zoom.test.tsx +68 -0
- package/src/components/ExtensionZone.stories.tsx +28 -0
- package/src/components/ExtensionZone.tsx +145 -0
- package/src/components/FileContentsView.stories.tsx +16 -0
- package/src/components/FileContentsView.test.tsx +29 -0
- package/src/components/FileContentsView.tsx +98 -0
- package/src/components/GridTabContent.stories.tsx +59 -0
- package/src/components/GridTabContent.tsx +182 -0
- package/src/components/HandleChipsInput.stories.tsx +24 -0
- package/src/components/HandleChipsInput.test.tsx +35 -0
- package/src/components/HandleChipsInput.tsx +145 -0
- package/src/components/KeybindsDialog.stories.tsx +31 -0
- package/src/components/KeybindsDialog.tsx +103 -0
- package/src/components/MarkdownGridBlock.stories.tsx +33 -0
- package/src/components/MarkdownGridBlock.tsx +72 -0
- package/src/components/MarkdownThreadEditor.stories.tsx +15 -0
- package/src/components/MarkdownThreadEditor.test.tsx +98 -0
- package/src/components/MarkdownThreadEditor.tsx +162 -0
- package/src/components/MenuBar.stories.tsx +28 -0
- package/src/components/MenuBar.tsx +44 -0
- package/src/components/NavModeHint.stories.tsx +40 -0
- package/src/components/NavModeHint.tsx +31 -0
- package/src/components/OverlayScrollbar.stories.tsx +33 -0
- package/src/components/OverlayScrollbar.test.tsx +139 -0
- package/src/components/OverlayScrollbar.tsx +129 -0
- package/src/components/PaneGrid.stories.tsx +84 -0
- package/src/components/PaneGrid.tsx +128 -0
- package/src/components/PanelColumn.stories.tsx +25 -0
- package/src/components/PanelColumn.tsx +98 -0
- package/src/components/ProjectTreeView.stories.tsx +25 -0
- package/src/components/ProjectTreeView.test.tsx +75 -0
- package/src/components/ProjectTreeView.tsx +125 -0
- package/src/components/PromptDialog.stories.tsx +36 -0
- package/src/components/PromptDialog.test.tsx +61 -0
- package/src/components/PromptDialog.tsx +99 -0
- package/src/components/PrototypeContentView.stories.tsx +19 -0
- package/src/components/PrototypeContentView.tsx +446 -0
- package/src/components/RootOverlay.stories.tsx +45 -0
- package/src/components/RootOverlay.tsx +48 -0
- package/src/components/ScrollArea.stories.tsx +20 -0
- package/src/components/ScrollArea.tsx +44 -0
- package/src/components/SettingsDialog.stories.tsx +117 -0
- package/src/components/SettingsDialog.tsx +186 -0
- package/src/components/SettingsRows.stories.tsx +18 -0
- package/src/components/SettingsRows.tsx +112 -0
- package/src/components/ShareDialog.stories.tsx +121 -0
- package/src/components/ShareDialog.tsx +552 -0
- package/src/components/ShellHeader.stories.tsx +50 -0
- package/src/components/ShellHeader.tsx +137 -0
- package/src/components/SlashComposer.stories.tsx +37 -0
- package/src/components/SlashComposer.tsx +87 -0
- package/src/components/ThreadFooter.stories.tsx +30 -0
- package/src/components/ThreadFooter.test.tsx +47 -0
- package/src/components/ThreadFooter.tsx +76 -0
- package/src/components/ThreadTree.stories.tsx +46 -0
- package/src/components/ThreadTree.tsx +255 -0
- package/src/components/ThreadView.selection.test.tsx +951 -0
- package/src/components/ThreadView.slash.test.tsx +146 -0
- package/src/components/ThreadView.stories.tsx +26 -0
- package/src/components/ThreadView.tsx +525 -0
- package/src/components/Toast.stories.tsx +19 -0
- package/src/components/Toast.tsx +52 -0
- package/src/components/Tooltip.stories.tsx +26 -0
- package/src/components/Tooltip.tsx +72 -0
- package/src/components/TreePane.stories.tsx +106 -0
- package/src/components/TreePane.tsx +157 -0
- package/src/components/WalkWizard.stories.tsx +100 -0
- package/src/components/WalkWizard.tsx +150 -0
- package/src/components/WelcomePlayground.stories.tsx +12 -0
- package/src/components/WelcomePlayground.test.tsx +49 -0
- package/src/components/WelcomePlayground.tsx +139 -0
- package/src/components/WorkspacePanels.stories.tsx +36 -0
- package/src/components/WorkspacePanels.tsx +116 -0
- package/src/components/__snapshots__/stories.test.tsx.snap +2264 -0
- package/src/components/diff-content-view-layout.test.ts +198 -0
- package/src/components/diff-content-view-layout.ts +84 -0
- package/src/components/editor-grid.test.ts +86 -0
- package/src/components/editor-grid.ts +138 -0
- package/src/components/file-tree.test.ts +60 -0
- package/src/components/file-tree.ts +112 -0
- package/src/components/menu-control.stories.tsx +35 -0
- package/src/components/menu-control.tsx +43 -0
- package/src/components/pages/Workspace.stories.tsx +181 -0
- package/src/components/primitives/Button.stories.tsx +32 -0
- package/src/components/primitives/Button.tsx +59 -0
- package/src/components/primitives/Card.stories.tsx +25 -0
- package/src/components/primitives/Card.tsx +63 -0
- package/src/components/primitives/Dialog.stories.tsx +24 -0
- package/src/components/primitives/Dialog.test.tsx +37 -0
- package/src/components/primitives/Dialog.tsx +71 -0
- package/src/components/primitives/DialogActions.stories.tsx +20 -0
- package/src/components/primitives/DialogActions.tsx +39 -0
- package/src/components/primitives/IconButton.stories.tsx +36 -0
- package/src/components/primitives/IconButton.tsx +62 -0
- package/src/components/primitives/StatusBar.stories.tsx +11 -0
- package/src/components/primitives/StatusBar.tsx +23 -0
- package/src/components/primitives/Switch.stories.tsx +17 -0
- package/src/components/primitives/Switch.tsx +32 -0
- package/src/components/primitives/Tabs.stories.tsx +29 -0
- package/src/components/primitives/Tabs.tsx +102 -0
- package/src/components/primitives/Toolbar.stories.tsx +17 -0
- package/src/components/primitives/Toolbar.tsx +14 -0
- package/src/components/primitives/Tree.stories.tsx +124 -0
- package/src/components/primitives/Tree.tsx +100 -0
- package/src/components/primitives/frame.test.ts +12 -0
- package/src/components/primitives/frame.ts +17 -0
- package/src/components/primitives/icons.ts +61 -0
- package/src/components/primitives/tree-model.test.ts +99 -0
- package/src/components/primitives/tree-model.ts +137 -0
- package/src/components/quick-actions-editor.stories.tsx +58 -0
- package/src/components/quick-actions-editor.test.tsx +117 -0
- package/src/components/quick-actions-editor.tsx +226 -0
- package/src/components/share-dialog-store.ts +58 -0
- package/src/components/stories-app.tsx +193 -0
- package/src/components/stories.test.tsx +74 -0
- package/src/components/story-fixtures.ts +102 -0
- package/src/components/story-tree.test.ts +108 -0
- package/src/components/story.ts +159 -0
- package/src/components/syntax-highlight.ts +133 -0
- package/src/components/terminal-pane.test.tsx +40 -0
- package/src/components/terminal-pane.ts +199 -0
- package/src/components/theme-context.stories.tsx +46 -0
- package/src/components/theme-context.tsx +37 -0
- package/src/components/thread-tree.test.ts +134 -0
- package/src/components/thread-tree.ts +109 -0
- package/src/components/truncate-text.ts +7 -0
- package/src/components/truncate-title.test.ts +31 -0
- package/src/components/truncate-title.ts +15 -0
- package/src/config-identity.test.ts +78 -0
- package/src/config.test.ts +579 -34
- package/src/config.ts +533 -57
- package/src/diff-fold.test.ts +78 -0
- package/src/diff-fold.ts +126 -0
- package/src/diff-hunk-curate.test.ts +315 -0
- package/src/diff-hunk-curate.ts +153 -0
- package/src/diff-intraline.test.ts +238 -0
- package/src/diff-intraline.ts +236 -0
- package/src/diff-syntax.test.ts +112 -0
- package/src/diff-syntax.ts +179 -0
- package/src/discussions.ts +79 -0
- package/src/editor.test.ts +149 -0
- package/src/editor.ts +139 -9
- package/src/ghostty-terminal.test.ts +85 -0
- package/src/ghostty-terminal.ts +199 -0
- package/src/github-identity.test.ts +58 -0
- package/src/github-identity.ts +41 -0
- package/src/herdr.test.ts +9 -34
- package/src/herdr.ts +25 -21
- package/src/index.ts +29 -0
- package/src/integrations.test.ts +41 -0
- package/src/integrations.ts +32 -0
- package/src/intent-dispatch.test.ts +724 -0
- package/src/intent-dispatch.ts +690 -0
- package/src/key-bindings.test.ts +156 -0
- package/src/key-bindings.ts +459 -0
- package/src/keymap.test.ts +456 -115
- package/src/keymap.ts +315 -81
- package/src/kitty-image.test.ts +66 -0
- package/src/kitty-image.ts +138 -0
- package/src/launch-layout.test.ts +78 -0
- package/src/launch-layout.ts +62 -0
- package/src/mark-runs.ts +121 -0
- package/src/markdown-editor-syntax-style.ts +50 -0
- package/src/markdown-grid.test.ts +101 -0
- package/src/markdown-grid.ts +203 -0
- package/src/markdown-highlight.test.ts +61 -0
- package/src/markdown-highlight.ts +122 -0
- package/src/pasted-image.test.ts +67 -0
- package/src/pasted-image.ts +60 -0
- package/src/perf/otlp-trace.test.ts +116 -0
- package/src/perf/otlp-trace.ts +130 -0
- package/src/perf/perf-report.ts +17 -0
- package/src/perf/perf-timings.test.ts +18 -0
- package/src/perf/perf-timings.ts +38 -0
- package/src/prototype-browser.test.ts +81 -0
- package/src/prototype-browser.ts +329 -0
- package/src/prototype-pixels.tsx +35 -0
- package/src/pty.test.ts +81 -0
- package/src/pty.ts +245 -0
- package/src/ready-signal.test.ts +85 -0
- package/src/ready-signal.ts +52 -0
- package/src/run.ts +85 -12
- package/src/serve.test.ts +24 -12
- package/src/serve.ts +52 -10
- package/src/share.ts +237 -0
- package/src/skills.test.ts +74 -0
- package/src/skills.ts +75 -0
- package/src/slash-palette.test.ts +103 -0
- package/src/slash-palette.ts +129 -0
- package/src/split-diff.test.ts +110 -0
- package/src/split-diff.ts +149 -0
- package/src/test-support.test.ts +264 -0
- package/src/test-support.ts +369 -0
- package/src/theme-presets.test.ts +51 -0
- package/src/theme-presets.ts +219 -0
- package/src/theme.ts +88 -19
- package/src/thread-chords.test.ts +79 -0
- package/src/thread-chords.ts +163 -0
- package/src/thread-code-syntax.ts +45 -0
- package/src/thread-controller.curate.test.ts +476 -0
- package/src/thread-controller.derivation.test.ts +62 -0
- package/src/thread-controller.live-diff.test.ts +322 -0
- package/src/thread-controller.optimistic.test.ts +69 -0
- package/src/thread-controller.share.test.ts +561 -0
- package/src/thread-controller.switch-cache.test.ts +176 -0
- package/src/thread-controller.tree.test.ts +261 -0
- package/src/thread-controller.ts +2050 -0
- package/src/thread-selection.test.ts +210 -0
- package/src/thread-selection.ts +243 -0
- package/src/tree-view.test.ts +128 -0
- package/src/tree-view.ts +153 -0
- package/src/use-annotation-surface.tsx +975 -0
- package/src/use-changes-workbench.ts +190 -0
- package/src/use-frame-measure.ts +41 -0
- package/src/use-remember-layout.ts +31 -0
- package/src/use-repo-changes.ts +87 -0
- package/src/use-settings-dialog.tsx +364 -0
- package/src/use-terminal-virtualizer.ts +259 -0
- package/src/use-thread-body-editing.tsx +58 -0
- package/src/version.ts +5 -0
- package/src/view-diff.test.ts +279 -9
- package/src/view-diff.ts +460 -24
- package/src/view-plan.regression.test.ts +60 -0
- package/src/view-plan.test.ts +545 -0
- package/src/view-plan.ts +1019 -0
- package/src/visual/contrast.test.ts +35 -0
- package/src/visual/contrast.ts +33 -0
- package/src/walk.test.ts +121 -0
- package/src/walk.ts +74 -0
- package/src/workbench-snapshot.test.ts +99 -0
- package/src/workbench-snapshot.ts +59 -0
- package/src/session-controller.ts +0 -398
- package/src/syntax.test.ts +0 -41
- package/src/syntax.ts +0 -88
- package/src/view.test.ts +0 -157
- package/src/view.ts +0 -364
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
# Build libcuelooppty: the flat forkpty(3) FFI shim in src/pty.zig. Pure libc, so
|
|
3
|
+
# unlike build.sh this needs no Ghostty clone - just the pinned Zig toolchain.
|
|
4
|
+
# Output lands in native/<os>-<arch>/libcuelooppty.{dylib,so}. Requires curl.
|
|
5
|
+
set -eu
|
|
6
|
+
|
|
7
|
+
ZIG_VERSION="0.16.0"
|
|
8
|
+
|
|
9
|
+
here="$(cd "$(dirname "$0")" && pwd)"
|
|
10
|
+
work="${TMPDIR:-/tmp}/cueloop-libghostty-build"
|
|
11
|
+
mkdir -p "$work"
|
|
12
|
+
export ZIG_GLOBAL_CACHE_DIR="$work/zig-gcache"
|
|
13
|
+
export ZIG_LOCAL_CACHE_DIR="$work/zig-lcache"
|
|
14
|
+
cd "$work"
|
|
15
|
+
|
|
16
|
+
arch="$(uname -m)"; os="$(uname -s | tr '[:upper:]' '[:lower:]')"
|
|
17
|
+
case "$os" in darwin) zig_os="macos"; dylib="libcuelooppty.dylib";; linux) zig_os="linux"; dylib="libcuelooppty.so";; *) echo "unsupported os $os" >&2; exit 1;; esac
|
|
18
|
+
case "$arch-$os" in
|
|
19
|
+
arm64-darwin|aarch64-linux) zig_arch="aarch64"; bun_arch="arm64";;
|
|
20
|
+
x86_64-darwin|x86_64-linux) zig_arch="x86_64"; bun_arch="x64";;
|
|
21
|
+
*) echo "unsupported architecture $arch on $os" >&2; exit 1;;
|
|
22
|
+
esac
|
|
23
|
+
case "$zig_arch-$zig_os" in
|
|
24
|
+
aarch64-macos) zig_sha="b23d70deaa879b5c2d486ed3316f7eaa53e84acf6fc9cc747de152450d401489";;
|
|
25
|
+
x86_64-macos) zig_sha="0387557ed1877bc6a2e1802c8391953baddba76081876301c522f52977b52ba7";;
|
|
26
|
+
aarch64-linux) zig_sha="ea4b09bfb22ec6f6c6ceac57ab63efb6b46e17ab08d21f69f3a48b38e1534f17";;
|
|
27
|
+
x86_64-linux) zig_sha="70e49664a74374b48b51e6f3fdfbf437f6395d42509050588bd49abe52ba3d00";;
|
|
28
|
+
esac
|
|
29
|
+
outdir="$here/${os}-${bun_arch}"
|
|
30
|
+
zig_archive="zig-$zig_arch-$zig_os-$ZIG_VERSION.tar.xz"
|
|
31
|
+
|
|
32
|
+
if [ ! -f "$zig_archive" ]; then
|
|
33
|
+
echo "== fetching zig $ZIG_VERSION =="
|
|
34
|
+
curl -fsSL -o "$zig_archive" "https://ziglang.org/download/$ZIG_VERSION/$zig_archive"
|
|
35
|
+
fi
|
|
36
|
+
printf '%s %s\n' "$zig_sha" "$zig_archive" | shasum -a 256 -c -
|
|
37
|
+
|
|
38
|
+
build_root="$(mktemp -d "$work/native-pty-build.XXXXXX")"
|
|
39
|
+
trap 'rm -rf "$build_root"' EXIT HUP INT TERM
|
|
40
|
+
tar -xf "$zig_archive" -C "$build_root"
|
|
41
|
+
zig="$build_root/zig-$zig_arch-$zig_os-$ZIG_VERSION/zig"
|
|
42
|
+
|
|
43
|
+
echo "== building pty shim -> $outdir/$dylib =="
|
|
44
|
+
mkdir -p "$outdir"
|
|
45
|
+
if [ "$os" = "darwin" ]; then
|
|
46
|
+
"$zig" build-lib -dynamic -OReleaseFast -lc -femit-bin="$outdir/$dylib" \
|
|
47
|
+
-install_name "@rpath/$dylib" "$here/src/pty.zig"
|
|
48
|
+
else
|
|
49
|
+
"$zig" build-lib -dynamic -OReleaseFast -lc -femit-bin="$outdir/$dylib" "$here/src/pty.zig"
|
|
50
|
+
fi
|
|
51
|
+
echo "== done: $outdir/$dylib =="
|
package/native/build.sh
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
# Rebuild libcueloopvt.dylib: libghostty-vt (Ghostty's VT core) statically linked
|
|
3
|
+
# behind the flat FFI shim. Pinned to a Ghostty commit + Zig 0.16.0.
|
|
4
|
+
# Output lands in native/<os>-<arch>/libcueloopvt.dylib. Requires curl and git.
|
|
5
|
+
set -eu
|
|
6
|
+
|
|
7
|
+
GHOSTTY_COMMIT="5834a0e3df621802e9578e4562d88b0c2ad4ada8"
|
|
8
|
+
ZIG_VERSION="0.16.0"
|
|
9
|
+
|
|
10
|
+
here="$(cd "$(dirname "$0")" && pwd)"
|
|
11
|
+
work="${TMPDIR:-/tmp}/cueloop-libghostty-build"
|
|
12
|
+
mkdir -p "$work"
|
|
13
|
+
export ZIG_GLOBAL_CACHE_DIR="$work/zig-gcache"
|
|
14
|
+
export ZIG_LOCAL_CACHE_DIR="$work/zig-lcache"
|
|
15
|
+
cd "$work"
|
|
16
|
+
|
|
17
|
+
# Host triple for the Bun prebuilt dir and Zig download. The two tools use
|
|
18
|
+
# different architecture names.
|
|
19
|
+
arch="$(uname -m)"; os="$(uname -s | tr '[:upper:]' '[:lower:]')"
|
|
20
|
+
case "$os" in darwin) zig_os="macos"; dylib="libcueloopvt.dylib";; linux) zig_os="linux"; dylib="libcueloopvt.so";; *) echo "unsupported os $os" >&2; exit 1;; esac
|
|
21
|
+
case "$arch-$os" in
|
|
22
|
+
arm64-darwin|aarch64-linux) zig_arch="aarch64"; bun_arch="arm64";;
|
|
23
|
+
x86_64-darwin|x86_64-linux) zig_arch="x86_64"; bun_arch="x64";;
|
|
24
|
+
*) echo "unsupported architecture $arch on $os" >&2; exit 1;;
|
|
25
|
+
esac
|
|
26
|
+
case "$zig_arch-$zig_os" in
|
|
27
|
+
aarch64-macos) zig_sha="b23d70deaa879b5c2d486ed3316f7eaa53e84acf6fc9cc747de152450d401489";;
|
|
28
|
+
x86_64-macos) zig_sha="0387557ed1877bc6a2e1802c8391953baddba76081876301c522f52977b52ba7";;
|
|
29
|
+
aarch64-linux) zig_sha="ea4b09bfb22ec6f6c6ceac57ab63efb6b46e17ab08d21f69f3a48b38e1534f17";;
|
|
30
|
+
x86_64-linux) zig_sha="70e49664a74374b48b51e6f3fdfbf437f6395d42509050588bd49abe52ba3d00";;
|
|
31
|
+
esac
|
|
32
|
+
outdir="$here/${os}-${bun_arch}"
|
|
33
|
+
zig_archive="zig-$zig_arch-$zig_os-$ZIG_VERSION.tar.xz"
|
|
34
|
+
|
|
35
|
+
if [ ! -f "$zig_archive" ]; then
|
|
36
|
+
echo "== fetching zig $ZIG_VERSION =="
|
|
37
|
+
curl -fsSL -o "$zig_archive" "https://ziglang.org/download/$ZIG_VERSION/$zig_archive"
|
|
38
|
+
fi
|
|
39
|
+
printf '%s %s\n' "$zig_sha" "$zig_archive" | shasum -a 256 -c -
|
|
40
|
+
|
|
41
|
+
if [ ! -d ghostty ]; then
|
|
42
|
+
echo "== cloning ghostty @ $GHOSTTY_COMMIT =="
|
|
43
|
+
mkdir ghostty && cd ghostty && git init -q
|
|
44
|
+
git remote add origin https://github.com/ghostty-org/ghostty.git
|
|
45
|
+
cd ..
|
|
46
|
+
fi
|
|
47
|
+
if ! git -C ghostty cat-file -e "$GHOSTTY_COMMIT^{commit}" 2>/dev/null; then
|
|
48
|
+
git -C ghostty fetch -q --depth 1 origin "$GHOSTTY_COMMIT"
|
|
49
|
+
fi
|
|
50
|
+
|
|
51
|
+
# Build only from fresh trees materialized from the verified archive and exact
|
|
52
|
+
# Git object. Cached working-tree edits and stale install outputs cannot enter.
|
|
53
|
+
build_root="$(mktemp -d "$work/native-build.XXXXXX")"
|
|
54
|
+
trap 'rm -rf "$build_root"' EXIT HUP INT TERM
|
|
55
|
+
tar -xf "$zig_archive" -C "$build_root"
|
|
56
|
+
zig="$build_root/zig-$zig_arch-$zig_os-$ZIG_VERSION/zig"
|
|
57
|
+
ghostty_source="$build_root/ghostty"
|
|
58
|
+
mkdir "$ghostty_source"
|
|
59
|
+
git -C ghostty archive "$GHOSTTY_COMMIT" | tar -x -C "$ghostty_source"
|
|
60
|
+
|
|
61
|
+
echo "== building libghostty-vt (ReleaseFast) =="
|
|
62
|
+
cd "$ghostty_source"
|
|
63
|
+
# The final xcframework packaging step can fail while the .a we need is produced,
|
|
64
|
+
# so tolerate a non-zero exit here but assert the static lib exists below.
|
|
65
|
+
vt_install="$build_root/vt-install"
|
|
66
|
+
"$zig" build -Demit-lib-vt -Doptimize=ReleaseFast --prefix "$vt_install" || true
|
|
67
|
+
cd ..
|
|
68
|
+
staticlib="$vt_install/lib/libghostty-vt.a"
|
|
69
|
+
[ -f "$staticlib" ] || { echo "build failed: $staticlib not produced" >&2; exit 1; }
|
|
70
|
+
|
|
71
|
+
echo "== linking shim -> $outdir/$dylib =="
|
|
72
|
+
mkdir -p "$outdir"
|
|
73
|
+
if [ "$os" = "darwin" ]; then
|
|
74
|
+
"$zig" build-lib -dynamic -OReleaseFast -lc -femit-bin="$outdir/$dylib" \
|
|
75
|
+
-install_name "@rpath/$dylib" \
|
|
76
|
+
-I"$vt_install/include" "$here/src/shim.zig" "$staticlib" \
|
|
77
|
+
-framework CoreFoundation -framework CoreText -framework CoreGraphics
|
|
78
|
+
else
|
|
79
|
+
"$zig" build-lib -dynamic -OReleaseFast -lc -femit-bin="$outdir/$dylib" \
|
|
80
|
+
-I"$vt_install/include" "$here/src/shim.zig" "$staticlib" -lm -lpthread
|
|
81
|
+
fi
|
|
82
|
+
echo "== done: $outdir/$dylib =="
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
// Flat, FFI-trivial pseudo-terminal over libc forkpty(3). Exposes exactly what
|
|
2
|
+
// the embedded Agent-tab terminal needs: spawn a child on a PTY, non-blocking
|
|
3
|
+
// read of its output, write, resize, and reap. Handles are small ints into a
|
|
4
|
+
// fixed table so bun:ffi only ever passes ints and byte pointers, never structs.
|
|
5
|
+
//
|
|
6
|
+
// Packed-argument contract (avoids shell parsing and per-token FFI marshalling):
|
|
7
|
+
// argv_packed: "arg0\0arg1\0...\0" - NUL-separated, terminated by an empty
|
|
8
|
+
// token (a trailing extra NUL).
|
|
9
|
+
// env_packed: "K=V\0K=V\0...\0" - same shape; empty means inherit parent.
|
|
10
|
+
// cwd: a plain C string, or empty to keep the parent's directory.
|
|
11
|
+
|
|
12
|
+
const std = @import("std");
|
|
13
|
+
const builtin = @import("builtin");
|
|
14
|
+
|
|
15
|
+
const c = @cImport({
|
|
16
|
+
@cInclude("unistd.h");
|
|
17
|
+
@cInclude("fcntl.h");
|
|
18
|
+
@cInclude("errno.h");
|
|
19
|
+
@cInclude("signal.h");
|
|
20
|
+
@cInclude("stdlib.h");
|
|
21
|
+
@cInclude("string.h");
|
|
22
|
+
@cInclude("termios.h");
|
|
23
|
+
@cInclude("sys/ioctl.h");
|
|
24
|
+
@cInclude("sys/wait.h");
|
|
25
|
+
if (builtin.os.tag == .macos) @cInclude("util.h") else @cInclude("pty.h");
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
extern var environ: [*c][*c]u8;
|
|
29
|
+
|
|
30
|
+
const MAX_SESSIONS = 64;
|
|
31
|
+
const MAX_TOKENS = 1024;
|
|
32
|
+
|
|
33
|
+
const PtySession = struct {
|
|
34
|
+
in_use: bool = false,
|
|
35
|
+
master_fd: c_int = -1,
|
|
36
|
+
pid: c.pid_t = 0,
|
|
37
|
+
reaped: bool = false,
|
|
38
|
+
exit_code: c_int = 0,
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
var sessions = [_]PtySession{.{}} ** MAX_SESSIONS;
|
|
42
|
+
|
|
43
|
+
// Split a double-NUL-terminated packed buffer into a NULL-terminated array of
|
|
44
|
+
// pointers into that same buffer. Returns the token count, or -1 on overflow.
|
|
45
|
+
fn splitPacked(packed_buffer: [*c]u8, out: [][*c]u8) c_int {
|
|
46
|
+
var count: usize = 0;
|
|
47
|
+
var cursor: [*c]u8 = packed_buffer;
|
|
48
|
+
while (cursor[0] != 0) {
|
|
49
|
+
if (count >= out.len - 1) return -1;
|
|
50
|
+
out[count] = cursor;
|
|
51
|
+
count += 1;
|
|
52
|
+
cursor += c.strlen(cursor) + 1;
|
|
53
|
+
}
|
|
54
|
+
out[count] = null;
|
|
55
|
+
return @intCast(count);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Reap the child once, recording its exit status. WNOHANG unless `block`.
|
|
59
|
+
fn reapSession(session: *PtySession, block: bool) void {
|
|
60
|
+
if (session.reaped) return;
|
|
61
|
+
var status: c_int = 0;
|
|
62
|
+
const result = c.waitpid(session.pid, &status, if (block) 0 else c.WNOHANG);
|
|
63
|
+
if (result != session.pid) return;
|
|
64
|
+
session.reaped = true;
|
|
65
|
+
if (c.WIFEXITED(status)) {
|
|
66
|
+
session.exit_code = c.WEXITSTATUS(status);
|
|
67
|
+
} else if (c.WIFSIGNALED(status)) {
|
|
68
|
+
session.exit_code = 128 + c.WTERMSIG(status);
|
|
69
|
+
} else {
|
|
70
|
+
session.exit_code = -1;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
fn sessionOf(handle: c_int) ?*PtySession {
|
|
75
|
+
if (handle < 0 or handle >= MAX_SESSIONS) return null;
|
|
76
|
+
const session = &sessions[@intCast(handle)];
|
|
77
|
+
if (!session.in_use) return null;
|
|
78
|
+
return session;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Spawn `argv_packed` on a fresh PTY sized cols x rows, in cwd, with env_packed
|
|
82
|
+
// (or the parent's env when empty). Returns a session handle, or -1 on failure.
|
|
83
|
+
export fn cueloop_pty_spawn(argv_packed: [*c]u8, cwd: [*c]const u8, env_packed: [*c]u8, cols: c_int, rows: c_int) c_int {
|
|
84
|
+
var handle: c_int = -1;
|
|
85
|
+
for (0..MAX_SESSIONS) |index| {
|
|
86
|
+
if (!sessions[index].in_use) {
|
|
87
|
+
handle = @intCast(index);
|
|
88
|
+
break;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
if (handle < 0) return -1;
|
|
92
|
+
|
|
93
|
+
var argv: [MAX_TOKENS][*c]u8 = undefined;
|
|
94
|
+
if (splitPacked(argv_packed, &argv) < 1) return -1;
|
|
95
|
+
|
|
96
|
+
var envp: [MAX_TOKENS][*c]u8 = undefined;
|
|
97
|
+
const have_env = env_packed != null and env_packed[0] != 0;
|
|
98
|
+
if (have_env and splitPacked(env_packed, &envp) < 0) return -1;
|
|
99
|
+
|
|
100
|
+
var winsize = std.mem.zeroes(c.struct_winsize);
|
|
101
|
+
winsize.ws_col = @intCast(cols);
|
|
102
|
+
winsize.ws_row = @intCast(rows);
|
|
103
|
+
|
|
104
|
+
var master_fd: c_int = -1;
|
|
105
|
+
const pid = c.forkpty(&master_fd, null, null, &winsize);
|
|
106
|
+
if (pid < 0) return -1;
|
|
107
|
+
|
|
108
|
+
if (pid == 0) {
|
|
109
|
+
// Child: adopt cwd/env then exec; _exit on any failure so a broken child never runs JS.
|
|
110
|
+
if (cwd != null and cwd[0] != 0) {
|
|
111
|
+
if (c.chdir(cwd) != 0) c._exit(127);
|
|
112
|
+
}
|
|
113
|
+
if (have_env) environ = &envp;
|
|
114
|
+
_ = c.execvp(argv[0], &argv);
|
|
115
|
+
c._exit(127);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Parent: non-blocking master so reads can poll without stalling the loop.
|
|
119
|
+
const flags = c.fcntl(master_fd, c.F_GETFL, @as(c_int, 0));
|
|
120
|
+
_ = c.fcntl(master_fd, c.F_SETFL, flags | c.O_NONBLOCK);
|
|
121
|
+
|
|
122
|
+
sessions[@intCast(handle)] = .{
|
|
123
|
+
.in_use = true,
|
|
124
|
+
.master_fd = master_fd,
|
|
125
|
+
.pid = pid,
|
|
126
|
+
.reaped = false,
|
|
127
|
+
.exit_code = 0,
|
|
128
|
+
};
|
|
129
|
+
return handle;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export fn cueloop_pty_write(handle: c_int, data: [*c]const u8, len: c_int) c_int {
|
|
133
|
+
const session = sessionOf(handle) orelse return -1;
|
|
134
|
+
const written = c.write(session.master_fd, data, @intCast(len));
|
|
135
|
+
return @intCast(written);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Non-blocking read of child output. Returns bytes read (>0), 0 when nothing is
|
|
139
|
+
// available yet, -2 once the child has exited and its output is drained, or -1.
|
|
140
|
+
export fn cueloop_pty_read(handle: c_int, buf: [*c]u8, len: c_int) c_int {
|
|
141
|
+
const session = sessionOf(handle) orelse return -1;
|
|
142
|
+
const bytes_read = c.read(session.master_fd, buf, @intCast(len));
|
|
143
|
+
if (bytes_read > 0) return @intCast(bytes_read);
|
|
144
|
+
if (bytes_read == 0) {
|
|
145
|
+
reapSession(session, true);
|
|
146
|
+
return -2; // EOF: slave closed
|
|
147
|
+
}
|
|
148
|
+
const err = std.c._errno().*;
|
|
149
|
+
if (err == c.EAGAIN or err == c.EWOULDBLOCK) {
|
|
150
|
+
reapSession(session, false);
|
|
151
|
+
return if (session.reaped) -2 else 0; // exited with no more output vs still running
|
|
152
|
+
}
|
|
153
|
+
if (err == c.EIO) {
|
|
154
|
+
reapSession(session, true);
|
|
155
|
+
return -2; // Linux: slave gone
|
|
156
|
+
}
|
|
157
|
+
return -1;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export fn cueloop_pty_resize(handle: c_int, cols: c_int, rows: c_int) c_int {
|
|
161
|
+
const session = sessionOf(handle) orelse return -1;
|
|
162
|
+
var winsize = std.mem.zeroes(c.struct_winsize);
|
|
163
|
+
winsize.ws_col = @intCast(cols);
|
|
164
|
+
winsize.ws_row = @intCast(rows);
|
|
165
|
+
return c.ioctl(session.master_fd, c.TIOCSWINSZ, &winsize);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
export fn cueloop_pty_kill(handle: c_int) c_int {
|
|
169
|
+
const session = sessionOf(handle) orelse return -1;
|
|
170
|
+
return c.kill(session.pid, c.SIGTERM);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export fn cueloop_pty_get_pid(handle: c_int) c_int {
|
|
174
|
+
const session = sessionOf(handle) orelse return -1;
|
|
175
|
+
return @intCast(session.pid);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export fn cueloop_pty_get_exit_code(handle: c_int) c_int {
|
|
179
|
+
const session = sessionOf(handle) orelse return -1;
|
|
180
|
+
reapSession(session, true);
|
|
181
|
+
return session.exit_code;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
export fn cueloop_pty_close(handle: c_int) void {
|
|
185
|
+
const session = sessionOf(handle) orelse return;
|
|
186
|
+
// Close the master first (hangs up the child), then block to reap it: after the
|
|
187
|
+
// SIGTERM from kill() plus this SIGHUP a well-behaved child exits at once, so the
|
|
188
|
+
// wait returns promptly and never leaves a zombie.
|
|
189
|
+
if (session.master_fd >= 0) _ = c.close(session.master_fd);
|
|
190
|
+
reapSession(session, true);
|
|
191
|
+
session.in_use = false;
|
|
192
|
+
session.master_fd = -1;
|
|
193
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
// Flat FFI wrapper over libghostty-vt. It hides the allocator vtable, the
|
|
2
|
+
// by-value GhosttyPoint that bun:ffi cannot pass, and packed-cell decoding.
|
|
3
|
+
const std = @import("std");
|
|
4
|
+
const ghostty = @cImport({
|
|
5
|
+
@cInclude("ghostty/vt/types.h");
|
|
6
|
+
@cInclude("ghostty/vt/allocator.h");
|
|
7
|
+
@cInclude("ghostty/vt/terminal.h");
|
|
8
|
+
@cInclude("ghostty/vt/point.h");
|
|
9
|
+
@cInclude("ghostty/vt/grid_ref.h");
|
|
10
|
+
@cInclude("ghostty/vt/screen.h");
|
|
11
|
+
@cInclude("ghostty/vt/style.h");
|
|
12
|
+
@cInclude("ghostty/vt/color.h");
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
const CvtCell = extern struct {
|
|
16
|
+
codepoint: u32,
|
|
17
|
+
fg_r: u8,
|
|
18
|
+
fg_g: u8,
|
|
19
|
+
fg_b: u8,
|
|
20
|
+
fg_kind: u8,
|
|
21
|
+
bg_r: u8,
|
|
22
|
+
bg_g: u8,
|
|
23
|
+
bg_b: u8,
|
|
24
|
+
bg_kind: u8,
|
|
25
|
+
width: u8,
|
|
26
|
+
flags: u8,
|
|
27
|
+
_pad: u16,
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
comptime {
|
|
31
|
+
std.debug.assert(@sizeOf(CvtCell) == 16);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export fn cvt_new(cols: u16, rows: u16) ?*anyopaque {
|
|
35
|
+
var terminal: ghostty.GhosttyTerminal = null;
|
|
36
|
+
if (ghostty.ghostty_terminal_new(null, &terminal, cols, rows) != ghostty.GHOSTTY_SUCCESS) {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
return terminal;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export fn cvt_free(terminal: ?*anyopaque) void {
|
|
43
|
+
if (terminal) |handle| ghostty.ghostty_terminal_free(@ptrCast(handle));
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export fn cvt_write(terminal: *anyopaque, data: [*]const u8, len: usize) void {
|
|
47
|
+
ghostty.ghostty_terminal_vt_write(@ptrCast(terminal), data, len);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export fn cvt_resize(terminal: *anyopaque, cols: u16, rows: u16) void {
|
|
51
|
+
// Cell pixel size does not affect the character grid.
|
|
52
|
+
_ = ghostty.ghostty_terminal_resize(@ptrCast(terminal), cols, rows, 1, 1);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Writes [col u16 LE, row u16 LE, visible u8] into the caller's eight bytes.
|
|
56
|
+
export fn cvt_cursor(terminal: *anyopaque, out: [*]u8) void {
|
|
57
|
+
var x: u16 = 0;
|
|
58
|
+
var y: u16 = 0;
|
|
59
|
+
var visible = false;
|
|
60
|
+
_ = ghostty.ghostty_terminal_get(@ptrCast(terminal), ghostty.GHOSTTY_TERMINAL_DATA_CURSOR_X, &x);
|
|
61
|
+
_ = ghostty.ghostty_terminal_get(@ptrCast(terminal), ghostty.GHOSTTY_TERMINAL_DATA_CURSOR_Y, &y);
|
|
62
|
+
_ = ghostty.ghostty_terminal_get(@ptrCast(terminal), ghostty.GHOSTTY_TERMINAL_DATA_CURSOR_VISIBLE, &visible);
|
|
63
|
+
out[0] = @truncate(x);
|
|
64
|
+
out[1] = @truncate(x >> 8);
|
|
65
|
+
out[2] = @truncate(y);
|
|
66
|
+
out[3] = @truncate(y >> 8);
|
|
67
|
+
out[4] = @intFromBool(visible);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
fn decodeColor(color: *const ghostty.GhosttyStyleColor, red: *u8, green: *u8, blue: *u8, kind: *u8) void {
|
|
71
|
+
if (color.tag == ghostty.GHOSTTY_STYLE_COLOR_RGB) {
|
|
72
|
+
kind.* = 2;
|
|
73
|
+
red.* = color.value.rgb.r;
|
|
74
|
+
green.* = color.value.rgb.g;
|
|
75
|
+
blue.* = color.value.rgb.b;
|
|
76
|
+
} else if (color.tag == ghostty.GHOSTTY_STYLE_COLOR_PALETTE) {
|
|
77
|
+
kind.* = 1;
|
|
78
|
+
red.* = @intCast(color.value.palette);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export fn cvt_cell(terminal: *anyopaque, x: u16, y: u32, out: *CvtCell) c_int {
|
|
83
|
+
out.* = std.mem.zeroes(CvtCell);
|
|
84
|
+
|
|
85
|
+
var point: ghostty.GhosttyPoint = undefined;
|
|
86
|
+
point.tag = ghostty.GHOSTTY_POINT_TAG_VIEWPORT;
|
|
87
|
+
point.value.coordinate.x = x;
|
|
88
|
+
point.value.coordinate.y = y;
|
|
89
|
+
|
|
90
|
+
var reference: ghostty.GhosttyGridRef = undefined;
|
|
91
|
+
if (ghostty.ghostty_terminal_grid_ref(@ptrCast(terminal), point, &reference) != ghostty.GHOSTTY_SUCCESS) return -1;
|
|
92
|
+
|
|
93
|
+
var cell: ghostty.GhosttyCell = undefined;
|
|
94
|
+
if (ghostty.ghostty_grid_ref_cell(&reference, &cell) != ghostty.GHOSTTY_SUCCESS) return -1;
|
|
95
|
+
|
|
96
|
+
_ = ghostty.ghostty_cell_get(cell, ghostty.GHOSTTY_CELL_DATA_CODEPOINT, &out.codepoint);
|
|
97
|
+
var width: u32 = 0;
|
|
98
|
+
_ = ghostty.ghostty_cell_get(cell, ghostty.GHOSTTY_CELL_DATA_WIDE, &width);
|
|
99
|
+
out.width = @intCast(width);
|
|
100
|
+
|
|
101
|
+
var style: ghostty.GhosttyStyle = undefined;
|
|
102
|
+
ghostty.ghostty_style_default(&style);
|
|
103
|
+
if (ghostty.ghostty_grid_ref_style(&reference, &style) == ghostty.GHOSTTY_SUCCESS) {
|
|
104
|
+
decodeColor(&style.fg_color, &out.fg_r, &out.fg_g, &out.fg_b, &out.fg_kind);
|
|
105
|
+
decodeColor(&style.bg_color, &out.bg_r, &out.bg_g, &out.bg_b, &out.bg_kind);
|
|
106
|
+
if (style.bold) out.flags |= 1;
|
|
107
|
+
if (style.italic) out.flags |= 2;
|
|
108
|
+
if (style.underline != 0) out.flags |= 4;
|
|
109
|
+
if (style.inverse) out.flags |= 8;
|
|
110
|
+
if (style.faint) out.flags |= 16;
|
|
111
|
+
if (style.strikethrough) out.flags |= 32;
|
|
112
|
+
}
|
|
113
|
+
return 0;
|
|
114
|
+
}
|
package/package.json
CHANGED
|
@@ -1,46 +1,54 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cueloop/client",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.91",
|
|
4
|
+
"description": "The cueloop review UI: projection renderer, keyboard grammar, review rail",
|
|
5
|
+
"homepage": "https://github.com/mmurakaru/cueloop#readme",
|
|
6
|
+
"bugs": {
|
|
7
|
+
"url": "https://github.com/mmurakaru/cueloop/issues"
|
|
8
|
+
},
|
|
4
9
|
"license": "Apache-2.0",
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "git+https://github.com/mmurakaru/cueloop.git",
|
|
13
|
+
"directory": "packages/client"
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"src",
|
|
17
|
+
"native",
|
|
18
|
+
"README.md"
|
|
19
|
+
],
|
|
5
20
|
"type": "module",
|
|
6
21
|
"exports": {
|
|
7
|
-
".": "./src/index.ts"
|
|
22
|
+
".": "./src/index.ts",
|
|
23
|
+
"./config": "./src/config.ts",
|
|
24
|
+
"./slash-palette": "./src/slash-palette.ts"
|
|
25
|
+
},
|
|
26
|
+
"publishConfig": {
|
|
27
|
+
"access": "public"
|
|
8
28
|
},
|
|
9
29
|
"dependencies": {
|
|
10
|
-
"@cueloop/daemon": "0.1.0-alpha.
|
|
11
|
-
"@cueloop/extension-api": "0.1.0-alpha.
|
|
12
|
-
"@cueloop/integration-obsidian": "0.1.0-alpha.
|
|
13
|
-
"@cueloop/schema": "0.1.0-alpha.
|
|
14
|
-
"@opentui/core": "^0.
|
|
15
|
-
"@opentui/
|
|
16
|
-
"@opentui/
|
|
17
|
-
"@
|
|
18
|
-
"
|
|
19
|
-
"
|
|
30
|
+
"@cueloop/daemon": "0.1.0-alpha.91",
|
|
31
|
+
"@cueloop/extension-api": "0.1.0-alpha.91",
|
|
32
|
+
"@cueloop/integration-obsidian": "0.1.0-alpha.91",
|
|
33
|
+
"@cueloop/schema": "0.1.0-alpha.91",
|
|
34
|
+
"@opentui/core": "^0.5.11",
|
|
35
|
+
"@opentui/keymap": "0.5.11",
|
|
36
|
+
"@opentui/react": "^0.5.11",
|
|
37
|
+
"@opentui/ssh": "0.5.11",
|
|
38
|
+
"@pierre/diffs": "^1.4.1",
|
|
39
|
+
"@tanstack/virtual-core": "^3.17.11",
|
|
40
|
+
"diff": "^9",
|
|
41
|
+
"puppeteer-core": "^25.10.0",
|
|
42
|
+
"react": "^19.3.0",
|
|
43
|
+
"valibot": "^1.5.0",
|
|
44
|
+
"zustand": "^5.0.15"
|
|
20
45
|
},
|
|
21
46
|
"devDependencies": {
|
|
22
|
-
"@types/react": "^19.
|
|
23
|
-
"ssh2": "^1.
|
|
24
|
-
"
|
|
47
|
+
"@types/react": "^19.3.0",
|
|
48
|
+
"@types/ssh2": "^1.15.6",
|
|
49
|
+
"ssh2": "^1.17.0"
|
|
25
50
|
},
|
|
26
|
-
"publishConfig": {
|
|
27
|
-
"access": "public"
|
|
28
|
-
},
|
|
29
|
-
"files": [
|
|
30
|
-
"src",
|
|
31
|
-
"README.md"
|
|
32
|
-
],
|
|
33
51
|
"engines": {
|
|
34
52
|
"bun": ">=1.3.0"
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
"type": "git",
|
|
38
|
-
"url": "git+https://github.com/mmurakaru/cueloop.git",
|
|
39
|
-
"directory": "packages/client"
|
|
40
|
-
},
|
|
41
|
-
"homepage": "https://github.com/mmurakaru/cueloop#readme",
|
|
42
|
-
"bugs": {
|
|
43
|
-
"url": "https://github.com/mmurakaru/cueloop/issues"
|
|
44
|
-
},
|
|
45
|
-
"description": "The cueloop review UI: projection renderer, keyboard grammar, review rail"
|
|
46
|
-
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/** The App renders in a light virtual terminal: passing appearance="light" threads the light branded theme through the provider without breaking the mount (the char frame is color-blind, so this covers propagation and wiring, not the pixel colors). */
|
|
2
|
+
|
|
3
|
+
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
|
4
|
+
import { mkdtempSync, rmSync } from "node:fs";
|
|
5
|
+
import { tmpdir } from "node:os";
|
|
6
|
+
import { join } from "node:path";
|
|
7
|
+
import React from "react";
|
|
8
|
+
import { DaemonServer } from "@cueloop/daemon";
|
|
9
|
+
import type { Thread } from "@cueloop/schema";
|
|
10
|
+
import { App } from "./App";
|
|
11
|
+
import { isolateUserConfig, settle, waitForText, renderReadyApp } from "./test-support";
|
|
12
|
+
|
|
13
|
+
const PLAN = "# Sync Plan\n\n## Steps\n\n- flush the queue\n";
|
|
14
|
+
|
|
15
|
+
let home: string;
|
|
16
|
+
let server: DaemonServer;
|
|
17
|
+
let session: Thread;
|
|
18
|
+
let restoreUserConfig: () => void;
|
|
19
|
+
|
|
20
|
+
beforeEach(() => {
|
|
21
|
+
home = mkdtempSync(join(tmpdir(), "cueloop-appearance-"));
|
|
22
|
+
restoreUserConfig = isolateUserConfig(home);
|
|
23
|
+
server = new DaemonServer({ home, idleExitMs: 0 });
|
|
24
|
+
server.start();
|
|
25
|
+
session = server.core.sessionCreate({
|
|
26
|
+
workspace: { repoRoot: "/repo", branch: "main" },
|
|
27
|
+
artifact: { type: "plan", content: PLAN, meta: { title: "Sync Plan", planPath: "plan.md" } },
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
afterEach(() => {
|
|
31
|
+
restoreUserConfig();
|
|
32
|
+
server.stop();
|
|
33
|
+
rmSync(home, { recursive: true, force: true });
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
describe("appearance", () => {
|
|
37
|
+
test("renders the review on a light terminal", async () => {
|
|
38
|
+
// Arrange + Act
|
|
39
|
+
const setup = await renderReadyApp(
|
|
40
|
+
<App home={home} sessionId={session.id} appearance="light" />,
|
|
41
|
+
{
|
|
42
|
+
width: 120,
|
|
43
|
+
height: 32,
|
|
44
|
+
},
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
// Assert
|
|
48
|
+
await waitForText(setup, "cueloop");
|
|
49
|
+
await waitForText(setup, "Sync Plan");
|
|
50
|
+
await settle(setup);
|
|
51
|
+
expect(setup.captureCharFrame()).toContain("flush the queue");
|
|
52
|
+
});
|
|
53
|
+
});
|