feat(desktop): embed BoosAPI Desktop client as a subproject

Vendor the rebranded BoosAPI Desktop client (Tauri + Vue) into metapi as
a monorepo subdirectory under desktop/. Source only — node_modules,
dist, Cargo target and the upstream .git history are excluded.

desktop/ keeps its own independent Cargo workspace (desktop/src-tauri
with crates/*); it is not part of the backend boosapi crate, so a
`cargo check` at the metapi root still compiles only the backend. Build
the desktop app from desktop/src-tauri per desktop/README.md.

Note: app icons are still placeholder assets pending the final BoosAPI
logo. The updater signing keys live outside the repo and are not
included.
This commit is contained in:
boos
2026-06-22 11:32:57 +08:00
parent d9c78ecc73
commit e0a5f57793
2305 changed files with 449355 additions and 0 deletions
@@ -0,0 +1,15 @@
import type { NodeComponentProps } from 'markstream-react';
interface ThinkingNodeData {
node: {
type: 'thinking';
content: string;
loading?: boolean;
attrs?: Array<{
name: string;
value: string | boolean;
}>;
};
}
export declare function ThinkingNode(props: NodeComponentProps<ThinkingNodeData['node']>): import("react/jsx-runtime").JSX.Element;
export default ThinkingNode;
//# sourceMappingURL=ThinkingNode.d.ts.map
@@ -0,0 +1,100 @@
import type { NodeComponentProps } from 'markstream-react'
import type { ReactNode } from 'react'
import { NodeRenderer } from 'markstream-react'
import { PLAYGROUND_CUSTOM_HTML_TAGS } from '../../../playground-react18/src/shared/markstreamPlayground'
interface ThinkingNodeData {
node: {
type: 'thinking'
content: string
loading?: boolean
attrs?: Array<{ name: string, value: string | boolean }>
}
}
type ThinkingNodeProps = Partial<NodeComponentProps<ThinkingNodeData['node']>> & {
children?: ReactNode
}
function getResolvedNode(props: ThinkingNodeProps): ThinkingNodeData['node'] {
if (props.node)
return props.node
return {
type: 'thinking',
content: '',
loading: false,
}
}
export function ThinkingNode(props: ThinkingNodeProps) {
const node = getResolvedNode(props)
const dotsClass = node.loading ? 'thinking-dots visible' : 'thinking-dots hidden'
const ctx = props.ctx
const inheritedCustomId = props.customId ?? ctx?.customId
const inheritedIsDark = props.isDark ?? ctx?.isDark
const inheritedTypewriter = props.typewriter ?? ctx?.typewriter ?? true
const hasStructuredNode = Boolean(props.node)
return (
<div className="thinking-node p-4 my-4 bg-blue-50 dark:bg-blue-900/40 rounded-md border-l-4 border-blue-400 flex items-start gap-3">
<div className="flex-shrink-0 mt-1">
<div className="w-9 h-9 rounded-full bg-blue-200 dark:bg-blue-700 flex items-center justify-center text-blue-700 dark:text-blue-100">
<svg className="w-5 h-5" viewBox="0 0 24 24" fill="none" aria-hidden="true">
<path
d="M12 3C7.03 3 3 6.58 3 11c0 1.86.66 3.57 1.77 4.98L4 21l5.2-1.9C10.06 19.35 11 19.5 12 19.5c4.97 0 9-3.58 9-8.5S16.97 3 12 3z"
stroke="currentColor"
strokeWidth="0.8"
fill="currentColor"
opacity="0.9"
/>
</svg>
</div>
</div>
<div className="flex-1">
<div className="flex items-baseline gap-3">
<strong className="text-sm">Thinking</strong>
<span className="text-xs text-slate-500 dark:text-slate-300">(assistant)</span>
<span className="ml-2" aria-hidden="true">
<span className={dotsClass} aria-hidden="true">
<span className="dot dot-1" />
<span className="dot dot-2" />
<span className="dot dot-3" />
</span>
</span>
</div>
<div className="mt-1 text-sm leading-relaxed text-slate-800 dark:text-slate-100">
{node.loading && <span className="sr-only" aria-live="polite">Thinking…</span>}
<div className="content-area">
{hasStructuredNode
? (
<NodeRenderer
content={String(node.content ?? '')}
customId={inheritedCustomId}
customHtmlTags={PLAYGROUND_CUSTOM_HTML_TAGS}
isDark={inheritedIsDark}
themes={ctx?.codeBlockThemes?.themes}
codeBlockDarkTheme={ctx?.codeBlockThemes?.darkTheme}
codeBlockLightTheme={ctx?.codeBlockThemes?.lightTheme}
codeBlockMonacoOptions={ctx?.codeBlockThemes?.monacoOptions}
codeBlockMinWidth={ctx?.codeBlockThemes?.minWidth}
codeBlockMaxWidth={ctx?.codeBlockThemes?.maxWidth}
codeBlockProps={ctx?.codeBlockProps}
codeBlockStream={ctx?.codeBlockStream}
renderCodeBlocksAsPre={ctx?.renderCodeBlocksAsPre}
typewriter={inheritedTypewriter}
viewportPriority={false}
deferNodesUntilVisible={false}
batchRendering={false}
maxLiveNodes={0}
/>
)
: props.children}
</div>
</div>
</div>
</div>
)
}
export default ThinkingNode