Phase 005: vendor ArkScope, land the Arco style baseline, and fix bridge interpreter resolution

- Vendor ArkScope decorative layers (ScrambleTitle / IsometricWave) with provenance notes; decorative-only per AGENTS.md red lines
- Migrate theme tokens to Arco, register the Arco theme, and add hook adapter composables (useMessage / useDialog / useNotification) with matching signatures
- Sample pages: LoginView and AppSidebar on the new baseline; docs/arco-mapping.md and docs/ui-baseline.md land
- agent-bridge: prefer the PM-selected venv from facts.json over legacy in-tree venvs (legacy lacks the mcp extra, so every MCP server showed 0 tools / not connected)
- agent-bridge python (vendored, deliberate deviation): MCP discovery import fallback and pyyaml -> hermes_yaml so plugins and MCP work under the PM env; install the mcp extra via `hermes pm install --extra mcp`
- Chat-chain fragment: docs/chat-chain-changes/2026-10-17-phase005-arkscope-baseline.md

Verified: harness:check, test (2020 passed), test:e2e (30 passed), build all green; manual: plugins 100/0 warnings, MCP 6/6 servers connected with 104 tools.
This commit is contained in:
2026-10-17 09:45:30 +08:00
parent 4701bf0ad0
commit 4baccd5d88
106 changed files with 1493 additions and 221 deletions
@@ -0,0 +1,62 @@
import { Modal } from '@arco-design/web-vue'
import type { VNodeChild } from 'vue'
// Frozen API (Phase 005). Mirrors the Naive `useDialog` option names used in
// this repo (positiveText/onPositiveClick/...) and maps them onto Arco Modal.
// Extend this adapter instead of importing Arco's Modal directly in views.
export interface AppDialogOptions {
title?: string
content?: string | (() => VNodeChild)
positiveText?: string
negativeText?: string
// Naive semantics: resolving false (or rejecting) keeps the dialog open
// and shows no success close; anything else closes it.
onPositiveClick?: () => unknown | Promise<unknown>
onNegativeClick?: () => unknown | Promise<unknown>
onClose?: () => void
closable?: boolean
}
function normalize(options: AppDialogOptions) {
return {
title: options.title,
// RenderContent = string | (() => VNodeChild) — pass functions through;
// Arco invokes them itself.
content: options.content ?? '',
okText: options.positiveText,
cancelText: options.negativeText,
// Map naive's "resolve false / reject → keep open" onto Arco's onBeforeOk
// (async result false keeps the modal open; it also drives ok-button
// loading while pending, matching naive).
onBeforeOk: options.onPositiveClick
? async (): Promise<boolean> => {
try {
const result = await options.onPositiveClick!()
return result !== false
} catch {
return false
}
}
: undefined,
// Arco's onBeforeCancel is sync-only; a returned promise (naive async
// style with no explicit false) counts as "proceed".
onBeforeCancel: options.onNegativeClick
? (): boolean => options.onNegativeClick!() !== false
: undefined,
onClose: options.onClose,
closable: options.closable,
}
}
export function useDialog() {
return {
confirm: (options: AppDialogOptions) => Modal.confirm(normalize(options)),
info: (options: AppDialogOptions) => Modal.info(normalize(options)),
success: (options: AppDialogOptions) => Modal.success(normalize(options)),
error: (options: AppDialogOptions) => Modal.error(normalize(options)),
warning: (options: AppDialogOptions) => Modal.warning(normalize(options)),
}
}
export type AppDialog = ReturnType<typeof useDialog>
@@ -0,0 +1,53 @@
import { Message } from '@arco-design/web-vue'
import type { MessageConfig, MessageReturn } from '@arco-design/web-vue/es/message/interface'
// Frozen API (Phase 005). Naive-style call sites migrate here; extend this
// adapter instead of importing Arco's Message directly in views/components.
// Naive: message.success(text, { duration }) — Arco only accepts
// (config, appContext), so options must be merged into the config object.
export interface AppMessageOptions {
content: string
duration?: number
closable?: boolean
}
export type AppMessageContent = string | AppMessageOptions
export interface AppMessageCallOptions {
duration?: number
closable?: boolean
}
function toConfig(content: AppMessageContent, options?: AppMessageCallOptions): MessageConfig {
const config: MessageConfig =
typeof content === 'string' ? { content } : { ...content }
if (options?.duration !== undefined) config.duration = options.duration
if (options?.closable !== undefined) config.closable = options.closable
return config
}
// Naive's MessageReactive exposes destroy(); Arco's MessageReturn only
// exposes close(). Expose both so migrated call sites can use either.
export type AppMessageReturn = MessageReturn & { destroy: () => void }
function wrap(ret: MessageReturn): AppMessageReturn {
return { ...ret, destroy: () => ret.close() }
}
export function useMessage() {
return {
success: (content: AppMessageContent, options?: AppMessageCallOptions) =>
wrap(Message.success(toConfig(content, options))),
error: (content: AppMessageContent, options?: AppMessageCallOptions) =>
wrap(Message.error(toConfig(content, options))),
warning: (content: AppMessageContent, options?: AppMessageCallOptions) =>
wrap(Message.warning(toConfig(content, options))),
info: (content: AppMessageContent, options?: AppMessageCallOptions) =>
wrap(Message.info(toConfig(content, options))),
loading: (content: AppMessageContent, options?: AppMessageCallOptions) =>
wrap(Message.loading(toConfig(content, options))),
}
}
export type AppMessage = ReturnType<typeof useMessage>
@@ -0,0 +1,32 @@
import { Notification } from '@arco-design/web-vue'
// Frozen API (Phase 005). Mirrors the Naive `useNotification` option names
// (title/description) and maps description onto Arco's `content`.
// Extend this adapter instead of importing Arco's Notification directly in views.
export interface AppNotificationOptions {
title?: string
description?: string
duration?: number
}
function normalize(options: AppNotificationOptions) {
return {
title: options.title,
// NotificationConfig.content is required; fall back to the title so a
// bare title still renders.
content: options.description ?? options.title ?? '',
duration: options.duration,
}
}
export function useNotification() {
return {
success: (options: AppNotificationOptions) => Notification.success(normalize(options)),
error: (options: AppNotificationOptions) => Notification.error(normalize(options)),
warning: (options: AppNotificationOptions) => Notification.warning(normalize(options)),
info: (options: AppNotificationOptions) => Notification.info(normalize(options)),
}
}
export type AppNotification = ReturnType<typeof useNotification>
@@ -30,6 +30,8 @@ function applyClasses() {
isComic.value = style.value === 'comic'
document.documentElement.classList.toggle('dark', dark)
document.documentElement.classList.toggle('comic', isComic.value)
// Arco Design dark theme mechanism (Phase 005)
document.documentElement.setAttribute('arco-theme', dark ? 'dark' : 'light')
}
// Initial