- Rename dsh-better-sidebar → dsh-apes-sidebar across 74 files (262 occurrences)
- Bump version 0.18.0 → 1.0.0 (package.json + dsh.plugin.json + SIDEBAR_SERVICE_VERSION)
- Add forkedFrom metadata to package.json (upstream pin: commit 9e1a034)
- Add fork notice banner to README.md (MIT attribution preserved)
- Keep original MIT copyright (c) 2026 dsh-external
- Full gate green: typecheck + build (6 bundles) + test (1241 passed / 9 skipped)
140 lines
7.0 KiB
Bash
Executable File
140 lines
7.0 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Consumer-facing type surface check: build a tiny standalone consumer that
|
|
# imports `dsh-apes-sidebar/client/service` WITHOUT @types/node and with
|
|
# skipLibCheck: false, then type-check it with the repo's tsc.
|
|
#
|
|
# This is the exact scenario the v0.12.0 API work cares about: the shipped
|
|
# declaration graph (service.d.ts -> context-types.d.ts -> state/api) must
|
|
# resolve and type-check for a browser-only plugin author. Run AFTER
|
|
# `pnpm build` (the check reads lib/types).
|
|
set -euo pipefail
|
|
cd "$(dirname "$0")/.."
|
|
|
|
# Git Bash (MSYS) `ln -s` deep-copies directories by default — copying this
|
|
# repo (node_modules + full .git history) would be catastrophic. Force real
|
|
# native symlinks instead: the GitHub Windows runners (Developer Mode, admin
|
|
# user) can create them, and nativestrict makes ln fail loudly rather than
|
|
# silently falling back to a copy. Inert on Linux/macOS.
|
|
export MSYS="winsymlinks:nativestrict"
|
|
|
|
# The check reads the BUILT declaration surface (lib/types) — fail loudly
|
|
# instead of silently passing when the build output is missing.
|
|
if [ ! -f lib/types/client/service.d.ts ]; then
|
|
echo "[check-consumer-types] FAIL: lib/types/client/service.d.ts not found — run 'pnpm build' first." >&2
|
|
exit 1
|
|
fi
|
|
|
|
WORK="$(mktemp -d)"
|
|
trap 'rm -rf "$WORK"' EXIT
|
|
|
|
mkdir -p "$WORK/node_modules"
|
|
# Resolve link targets to their PHYSICAL path first: under pnpm,
|
|
# node_modules/@deepseek-ai/cordis is itself a symlink/junction into .pnpm,
|
|
# and on Windows a native symlink pointing AT a junction does not traverse
|
|
# for tsc (TS2307 on a link that visibly exists). Node's NATIVE realpath
|
|
# (GetFinalPathNameByHandle on Windows) expands junctions, which bash-level
|
|
# resolution may leave untouched; node is guaranteed here (tsc runs below).
|
|
resolve_dir() { node -e 'process.stdout.write(require("node:fs").realpathSync.native(process.argv[1]))' "$1"; }
|
|
ln -s "$(resolve_dir "$(pwd)")" "$WORK/node_modules/dsh-apes-sidebar"
|
|
# The vendored cordis base (and, through its realpath, cosmokit / standard-schema)
|
|
# must resolve so the consumer can type `Context` against the DSH runtime scope.
|
|
mkdir -p "$WORK/node_modules/@deepseek-ai"
|
|
ln -s "$(resolve_dir "$(pwd)/node_modules/@deepseek-ai/cordis")" "$WORK/node_modules/@deepseek-ai/cordis"
|
|
# Loud guard: both links must resolve to a package root, or tsc below would
|
|
# report misleading module-resolution errors.
|
|
for pkg_json in "$WORK/node_modules/dsh-apes-sidebar/package.json" "$WORK/node_modules/@deepseek-ai/cordis/package.json"; do
|
|
if [ ! -f "$pkg_json" ]; then
|
|
echo "[check-consumer-types] FAIL: $pkg_json does not resolve (broken link). Link layer:" >&2
|
|
ls -la "$WORK/node_modules" "$WORK/node_modules/@deepseek-ai" >&2 || true
|
|
exit 1
|
|
fi
|
|
done
|
|
|
|
cat > "$WORK/check.ts" <<'EOF'
|
|
import { SIDEBAR_FEATURES, SIDEBAR_SERVICE_VERSION } from 'dsh-apes-sidebar/client/service'
|
|
import type {} from 'dsh-apes-sidebar/client/service'
|
|
import type {
|
|
BetterSidebarService, FileViewerDescriptor, OpenTabSeed, SidebarSettingsRenderProps,
|
|
TabComponentProps, TabDescriptor,
|
|
} from 'dsh-apes-sidebar/client/service'
|
|
import type { SessionScope, SidebarSnapshot, SidebarState, SidebarStore, SidebarTab } from 'dsh-apes-sidebar/client/service'
|
|
import type { SidebarPrefs } from 'dsh-apes-sidebar/client/service'
|
|
// The vendored-cordis path: `Context` from '@deepseek-ai/cordis' plus the
|
|
// side-effect type import above must expose `ctx.betterSidebar` — the consumer
|
|
// never needs to import this package's own Context type.
|
|
import type { Context as VendoredContext } from '@deepseek-ai/cordis'
|
|
|
|
declare const ctx: { betterSidebar: BetterSidebarService }
|
|
const tab: TabDescriptor = {
|
|
id: 'x:tab',
|
|
title: 'X',
|
|
single: true,
|
|
badge: (_ctx, _scope, state: SidebarState) => state.expanded.length,
|
|
onOpen: (_tab: SidebarTab, _scope: SessionScope) => {},
|
|
onClose: (_tab: SidebarTab, _scope: SessionScope) => {},
|
|
createTab: (state: SidebarState) => ({ tab: { id: 'x:1', type: 'x:tab', title: 'X', meta: {} } }),
|
|
settings: {
|
|
toggles: [{ key: 'autoOpenSubagent', title: 'A' }],
|
|
pluginToggles: [{ key: 'k', title: 'K', type: 'number', min: 0, max: 9 }],
|
|
render: (props: SidebarSettingsRenderProps) => { props.updatePluginSetting('a', 1); return null },
|
|
},
|
|
component: (props: TabComponentProps) => null,
|
|
}
|
|
ctx.betterSidebar.registerTab(tab)
|
|
const viewer: FileViewerDescriptor = {
|
|
id: 'x:csv', exts: ['csv'], fetchStrategy: 'custom',
|
|
load: (_path, _scope, signal?: AbortSignal) => { void signal; return Promise.resolve([]) },
|
|
component: () => null,
|
|
}
|
|
ctx.betterSidebar.registerFileViewer(viewer)
|
|
const seed: OpenTabSeed = { type: 'x:tab', title: 'X', meta: { a: 1 } }
|
|
ctx.betterSidebar.openTab(seed, { sessionId: 's1' })
|
|
ctx.betterSidebar.openFile({ sessionId: 's1' }, '/p/a.csv')
|
|
ctx.betterSidebar.updateTab('t', { meta: { b: 2 } })
|
|
const snap: SidebarSnapshot = ctx.betterSidebar.getSnapshot()
|
|
const prefs: SidebarPrefs = snap.prefs
|
|
const store: SidebarStore = null as unknown as SidebarStore
|
|
void prefs; void store; void ctx.betterSidebar.version; void ctx.betterSidebar.features
|
|
void SIDEBAR_SERVICE_VERSION; void SIDEBAR_FEATURES
|
|
// Vendored-cordis augmentation path.
|
|
declare const vctx: VendoredContext
|
|
vctx.betterSidebar.registerTab(tab)
|
|
vctx.betterSidebar.registerFileViewer(viewer)
|
|
void vctx.betterSidebar.getSnapshot()
|
|
EOF
|
|
|
|
cat > "$WORK/tsconfig.json" <<'EOF'
|
|
{
|
|
"compilerOptions": {
|
|
"target": "ES2023", "module": "esnext", "moduleResolution": "bundler",
|
|
"strict": true, "noEmit": true, "skipLibCheck": false, "types": [],
|
|
"jsx": "react-jsx", "lib": ["ES2023", "DOM"]
|
|
},
|
|
"include": ["check.ts"]
|
|
}
|
|
EOF
|
|
|
|
echo "[check-consumer-types] type-checking a browser-only consumer (no @types/node)..."
|
|
echo "[check-consumer-types] pass 1: skipLibCheck: true (the realistic consumer experience) — must be fully clean"
|
|
./node_modules/.bin/tsc -p "$WORK/tsconfig.json" --skipLibCheck true
|
|
echo "[check-consumer-types] pass 2: skipLibCheck: false — OUR declaration surface (lib/types/**) must be clean"
|
|
echo "[check-consumer-types] (upstream cordis/cosmokit declaration noise is filtered out; it predates this plugin)"
|
|
set +e
|
|
./node_modules/.bin/tsc -p "$WORK/tsconfig.json" --skipLibCheck false > "$WORK/strict.log" 2>&1
|
|
STATUS=$?
|
|
set -e
|
|
# Fail only on errors that mention OUR package / declarations / the fixture.
|
|
# Upstream noise (vendored cordis / cosmokit declaration warnings under the
|
|
# repo's pinned TS lib) lives anywhere under node_modules and is filtered.
|
|
if grep -E "dsh-apes-sidebar|lib/types|check\.ts" "$WORK/strict.log" | grep -vE "node_modules/[^ ]*(cordis|cosmokit)"; then
|
|
echo "[check-consumer-types] FAIL: errors in the dsh-apes-sidebar declaration surface:" >&2
|
|
grep -E "dsh-apes-sidebar|lib/types|check\.ts" "$WORK/strict.log" >&2
|
|
exit 1
|
|
fi
|
|
if [ "$STATUS" -ne 0 ]; then
|
|
echo "[check-consumer-types] pass 2 note: strict mode only reports upstream declaration noise:"
|
|
grep -v "dsh-apes-sidebar\|lib/types\|check\.ts" "$WORK/strict.log" | head -5 || true
|
|
fi
|
|
echo "[check-consumer-types] OK: the client/service declaration surface is node-free and self-contained."
|
|
|