zdashboard 2.0.0 → 2.1.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 +19 -0
- package/dist/cli.js +313 -86
- package/dist/cli.js.map +1 -1
- package/dist/web/assets/{MdViewer-DHLa9u9L.js → MdViewer-C8ZG_xn1.js} +1 -1
- package/dist/web/assets/Workspace-Cz1A_IXM.js +1 -0
- package/dist/web/assets/{file-text-D4672ckY.js → file-text-DqCOBCjz.js} +1 -1
- package/dist/web/assets/{index-BRLQFQ6k.js → index-B9eiA0v2.js} +1 -1
- package/dist/web/assets/index-D58_bWw5.css +1 -0
- package/dist/web/assets/{index-Deg587va.js → index-DkOVCCZ3.js} +22 -19
- package/dist/web/assets/{katex.min-D64GJ8fh.js → katex.min-DAmb8ZJI.js} +1 -1
- package/dist/web/assets/web-8ZBVzAEO.js +26 -0
- package/dist/web/assets/{web-2je-DAWY.js → web-CEyEoz0i.js} +5 -5
- package/dist/web/assets/{web-DqBNmBY8.js → web-CXHaDUKR.js} +11 -11
- package/dist/web/assets/{web-C0d3eOAl.js → web-CrX-i-rZ.js} +2 -2
- package/dist/web/assets/{web-Bgs6ipDo.js → web-D_b3sVrp.js} +2 -2
- package/dist/web/assets/web-M4KeFgZw.js +2 -0
- package/dist/web/assets/{web-4tpIem4N.js → web-Y4h9oNHC.js} +2 -2
- package/dist/web/index.html +2 -2
- package/package.json +1 -1
- package/dist/web/assets/index-Dqj3ddhK.css +0 -1
- package/dist/web/assets/web-DIAM7Pif.js +0 -26
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli.ts","../src/server/detect.ts","../src/core/server.ts","../package.json","../src/core/reload.ts","../src/server/spec-scan.ts","../src/core/tree.ts","../src/core/manifest.ts","../src/server/just-runner.ts","../src/plugins/just/index.ts","../src/server/bugs.ts","../src/server/api/fetch.ts","../src/server/errors.ts","../src/plugins/bugs/index.ts","../src/server/review-store.ts","../src/plugins/review/index.ts","../src/plugins/apply/scan.ts","../src/plugins/apply/index.ts","../src/server/design-assets.ts","../src/plugins/design/index.ts","../src/plugins/view/index.ts"],"sourcesContent":["import path from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { access, readdir } from 'node:fs/promises';\nimport { detect } from './server/detect.js';\nimport type { DetectResult } from './server/detect.js';\nimport { Context, Service } from 'cordis';\nimport { ServerService, PLUGIN_STATIC_PREFIX } from './core/server.js';\nimport { ReloadService } from './core/reload.js';\nimport { apply as treeApply } from './core/tree.js';\nimport { DashboardService } from './core/manifest.js';\nimport { apply as justApply } from './plugins/just/index.js';\nimport { apply as bugsApply } from './plugins/bugs/index.js';\nimport { apply as reviewApply } from './plugins/review/index.js';\nimport { apply as applyApply } from './plugins/apply/index.js';\nimport { apply as designApply } from './plugins/design/index.js';\nimport { apply as viewApply } from './plugins/view/index.js';\n\nconst __dirname = path.dirname(fileURLToPath(import.meta.url));\n\nfunction parseArgs() {\n const args = process.argv.slice(2);\n const opts: Record<string, string | boolean> = {};\n for (let i = 0; i < args.length; i++) {\n const a = args[i];\n if (a.startsWith('--')) {\n const key = a.slice(2);\n const next = args[i + 1];\n if (next && !next.startsWith('--')) {\n opts[key] = next;\n i++;\n } else {\n opts[key] = true;\n }\n }\n }\n return {\n dir: typeof opts.dir === 'string' ? opts.dir : process.cwd(),\n port: typeof opts.port === 'string' ? Number(opts.port) : 4190,\n open: !!opts.open,\n page: typeof opts.page === 'string' ? opts.page : null,\n plugins: typeof opts.plugins === 'string' ? opts.plugins : null,\n };\n}\n\nasync function pathExists(p: string): Promise<boolean> {\n try { await access(p); return true; } catch { return false; }\n}\n\nasync function loadExternal(ctx: Context, dir: string, root: string) {\n if (!dir) return;\n let tsxLoaded = false;\n try {\n const { register } = await import('tsx/esm/api');\n register();\n tsxLoaded = true;\n } catch {\n // tsx not available\n }\n\n try {\n const entries = await pathExists(dir) ? await readdir(dir, { withFileTypes: true }) : [];\n for (const ent of entries) {\n if (!ent.isDirectory()) continue;\n const candidates = tsxLoaded ? ['index.ts', 'index.js', 'index.mjs'] : ['index.js', 'index.mjs'];\n for (const name of candidates) {\n const p = path.join(dir, ent.name, name);\n if (await pathExists(p)) {\n try {\n const mod = await import(p);\n const plugin = mod.default ?? mod;\n if (plugin?.apply) {\n try {\n await ctx.plugin(plugin, { root });\n } catch (e) {\n console.error(`[zdashboard] failed to apply plugin ${ent.name}:`, e);\n break;\n }\n // 自动接线约定:mode === 目录名时补 external 标记与 viewerUrl\n const m = ctx.dashboard.get(ent.name);\n if (m && m.mode === ent.name) {\n const patch: Record<string, unknown> = { external: true };\n const webDir = path.join(dir, ent.name, 'web');\n if (await pathExists(path.join(webDir, 'index.html'))) {\n ctx.server.static(`${PLUGIN_STATIC_PREFIX}${ent.name}/`, webDir);\n if (!m.viewerUrl) patch.viewerUrl = `${PLUGIN_STATIC_PREFIX}${ent.name}/`;\n }\n ctx.dashboard.register({ ...m, ...patch });\n }\n }\n } catch (e) {\n console.error(`[zdashboard] failed to load plugin ${ent.name}:`, e);\n }\n break;\n }\n }\n }\n } catch {\n // ignore\n }\n}\n\nasync function main() {\n const args = parseArgs();\n const root = path.resolve(args.dir);\n const appDir = path.resolve(__dirname, 'web');\n\n const det = await detect(root);\n\n const ctx = new Context();\n\n // core services\n ctx.plugin(ServerService, { root, appDir, port: args.port, open: args.open, detect: det, page: args.page });\n ctx.plugin(ReloadService, { root });\n ctx.plugin(treeApply, { root });\n ctx.plugin(DashboardService);\n\n // built-in plugins\n const plugins = [\n { name: 'just', apply: justApply },\n { name: 'bugs', apply: bugsApply },\n { name: 'review', apply: reviewApply },\n { name: 'apply', apply: applyApply },\n { name: 'design', apply: designApply },\n { name: 'view', apply: viewApply },\n ];\n for (const p of plugins) {\n try {\n ctx.plugin(p.apply, { root });\n } catch (e) {\n console.error(`[zdashboard] plugin ${p.name} failed:`, e);\n }\n }\n\n // external plugins\n if (args.plugins) {\n await loadExternal(ctx, path.resolve(args.plugins), root);\n }\n return ctx;\n}\n\nawait main().catch((e) => {\n console.error(e);\n process.exit(1);\n});\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport { execFile } from 'node:child_process';\n\nexport interface DetectResult {\n hasOpenspec: boolean;\n hasDocs: boolean;\n hasJust: boolean;\n hasBugs: boolean;\n}\n\nfunction justAvailable(cwd: string): Promise<boolean> {\n return new Promise((resolve) => {\n const child = execFile('just', ['--list', '--unsorted'], { cwd, timeout: 5000 }, (err) => {\n resolve(!err);\n });\n if (child.killed) resolve(false);\n });\n}\n\nexport async function detect(root: string): Promise<DetectResult> {\n const hasOpenspec = fs.existsSync(path.join(root, 'openspec'));\n const hasDocs = fs.existsSync(path.join(root, 'docs'));\n const hasJust = await justAvailable(root);\n const hasBugs = fs.existsSync(path.join(root, '.zgoal', 'config.yaml'));\n return { hasOpenspec, hasDocs, hasJust, hasBugs };\n}\n","import http from 'node:http';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport crypto from 'node:crypto';\nimport { exec } from 'node:child_process';\nimport { fileURLToPath } from 'node:url';\nimport pkg from '../../package.json' with { type: 'json' };\nimport type { Context, DetectResult } from 'cordis';\nimport { Service } from 'cordis';\n\nconst VERSION = pkg.version;\nconst __dirname = path.dirname(fileURLToPath(import.meta.url));\n\nexport interface ServerOptions {\n root: string;\n appDir: string;\n port: number;\n open: boolean;\n page: string | null;\n detect: DetectResult;\n}\n\ndeclare module 'cordis' {\n interface Context {\n server: ServerService;\n }\n}\n\nconst MIME: Record<string, string> = {\n '.html': 'text/html; charset=utf-8', '.htm': 'text/html; charset=utf-8',\n '.css': 'text/css; charset=utf-8', '.js': 'application/javascript; charset=utf-8',\n '.mjs': 'application/javascript; charset=utf-8', '.json': 'application/json; charset=utf-8',\n '.svg': 'image/svg+xml', '.png': 'image/png', '.ico': 'image/x-icon',\n '.jpg': 'image/jpeg', '.jpeg': 'image/jpeg', '.gif': 'image/gif', '.webp': 'image/webp',\n '.md': 'text/markdown; charset=utf-8', '.txt': 'text/plain; charset=utf-8',\n '.sql': 'text/plain; charset=utf-8', '.csv': 'text/plain; charset=utf-8',\n '.tsv': 'text/plain; charset=utf-8', '.yaml': 'text/yaml; charset=utf-8',\n '.yml': 'text/yaml; charset=utf-8', '.xml': 'application/xml; charset=utf-8',\n '.py': 'text/plain; charset=utf-8', '.ts': 'text/plain; charset=utf-8',\n '.java': 'text/plain; charset=utf-8', '.go': 'text/plain; charset=utf-8',\n '.rs': 'text/plain; charset=utf-8', '.rb': 'text/plain; charset=utf-8',\n '.php': 'text/plain; charset=utf-8', '.c': 'text/plain; charset=utf-8',\n '.cpp': 'text/plain; charset=utf-8', '.h': 'text/plain; charset=utf-8',\n '.cs': 'text/plain; charset=utf-8', '.swift': 'text/plain; charset=utf-8',\n '.kt': 'text/plain; charset=utf-8', '.scala': 'text/plain; charset=utf-8',\n '.sh': 'text/plain; charset=utf-8', '.bash': 'text/plain; charset=utf-8',\n '.zsh': 'text/plain; charset=utf-8', '.fish': 'text/plain; charset=utf-8',\n '.env': 'text/plain; charset=utf-8', '.gitignore': 'text/plain; charset=utf-8',\n '.dockerfile': 'text/plain; charset=utf-8',\n '.woff': 'font/woff', '.woff2': 'font/woff2', '.ttf': 'font/woff',\n '.map': 'application/json; charset=utf-8',\n};\n\nconst INJECT = `<script>(function(){try{var es=new EventSource('/__reload');es.addEventListener('reload',function(){location.reload();});es.onerror=function(){es.close();};}catch(e){}document.addEventListener('click',function(e){var t=e.target;if(t&&t.closest){var a=t.closest('a[target]');if(a&&a.target!=='_self'){a.target='_self';}}},true);})();</script>`;\n\nexport const PLUGIN_STATIC_PREFIX = '/__plugin/';\n\nexport class ServerService extends Service {\n stopToken: string;\n private root: string;\n private appDir: string;\n private open: boolean;\n private page: string | null;\n private det: DetectResult;\n private routes = new Map<string, (req: http.IncomingMessage, res: http.ServerResponse) => void>();\n private sses = new Map<string, (res: http.ServerResponse) => (() => void) | void>();\n private prefixStatic = new Map<string, string>();\n private server?: http.Server;\n\n constructor(ctx: Context, config: ServerOptions) {\n super(ctx, 'server');\n this.stopToken = crypto.randomBytes(12).toString('hex');\n this.root = config.root;\n this.appDir = config.appDir;\n this.open = config.open;\n this.page = config.page;\n this.det = config.detect;\n ctx.effect(() => () => this.dispose());\n\n this.route('/__config', (_req, res) => {\n res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8', 'Cache-Control': 'no-cache' });\n res.end(JSON.stringify({ stopToken: this.stopToken, version: VERSION, root: this.root }));\n });\n\n this.route('/__stop', async (req, res) => {\n if (req.headers['x-stop-token'] !== this.stopToken) {\n res.writeHead(403);\n res.end('forbidden');\n return;\n }\n res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' });\n res.end('{\"ok\":true}');\n this.stop();\n });\n\n this.start(config.port);\n }\n\n\n route(path: string, handler: (req: http.IncomingMessage, res: http.ServerResponse) => void) {\n this.routes.set(path, handler);\n this.ctx.effect(() => () => this.routes.delete(path));\n }\n\n sse(path: string, onConnect: (res: http.ServerResponse) => (() => void) | void) {\n this.sses.set(path, onConnect);\n this.ctx.effect(() => () => this.sses.delete(path));\n }\n\n static(prefix: string, dir: string) {\n this.prefixStatic.set(prefix, dir);\n this.ctx.effect(() => () => this.prefixStatic.delete(prefix));\n }\n\n private serveFile(filePath: string, res: http.ServerResponse, injectHtml: boolean) {\n fs.readFile(filePath, (err, data) => {\n if (err) { res.writeHead(404); return res.end('Not found'); }\n const ext = path.extname(filePath).toLowerCase();\n const ct = MIME[ext] ?? 'application/octet-stream';\n let body = data;\n if (injectHtml && ext === '.html') {\n const s = data.toString('utf8');\n body = Buffer.from(s.indexOf('</body>') >= 0 ? s.replace('</body>', INJECT + '</body>') : s + INJECT);\n }\n res.writeHead(200, { 'Content-Type': ct, 'Cache-Control': 'no-cache' });\n res.end(body);\n });\n }\n\n private servePrefix(url: string, res: http.ServerResponse): boolean {\n for (const [prefix, dir] of this.prefixStatic) {\n if (url.indexOf(prefix) === 0) {\n let rel = this.safeDecode(url.slice(prefix.length));\n if (!rel || rel === '/' || !path.extname(rel)) rel = path.join(rel || '', 'index.html');\n const fp = path.join(dir, rel);\n if (fp.indexOf(dir + path.sep) !== 0) { res.writeHead(403); return res.end('Forbidden'); }\n this.serveFile(fp, res, true);\n return true;\n }\n }\n return false;\n }\n\n private safeDecode(raw: string): string {\n try { return decodeURIComponent(raw); } catch { return raw; }\n }\n\n private handler = (req: http.IncomingMessage, res: http.ServerResponse) => {\n try {\n const rawUrl = req.url || '/';\n const url = rawUrl.split('?')[0];\n\n const rh = this.routes.get(url);\n if (rh) { rh(req, res); return; }\n const sh = this.sses.get(url);\n if (sh) {\n res.writeHead(200, { 'Content-Type': 'text/event-stream', 'Cache-Control': 'no-cache', Connection: 'keep-alive' });\n res.write(': connected\\n\\n');\n const cleanup = sh(res);\n req.on('close', () => { cleanup?.(); });\n return;\n }\n\n if (this.servePrefix(url, res)) return;\n\n if (url === '/' || url.indexOf('/__app/') === 0 || url.indexOf('/assets/') === 0) {\n let fp = this.appDir;\n if (url !== '/') fp = path.join(this.appDir, this.safeDecode(url));\n if (url.indexOf('/__app/') === 0) fp = path.join(this.appDir, url.slice(7));\n if (fp !== this.appDir && fp.indexOf(this.appDir + path.sep) !== 0) { res.writeHead(403); return res.end('Forbidden'); }\n if (url === '/') fp = path.join(this.appDir, 'index.html');\n return this.serveFile(fp, res, false);\n }\n\n const fp = path.join(this.root, this.safeDecode(url));\n if (fp !== this.root && fp.indexOf(this.root + path.sep) !== 0) { res.writeHead(403); return res.end('Forbidden'); }\n return this.serveFile(fp, res, true);\n } catch (e) {\n try { res.writeHead(400); res.end('bad request'); } catch {}\n console.error('[zdashboard] handler error', e);\n }\n };\n\n start(port: number) {\n this.server = http.createServer(this.handler);\n this.server.on('error', (err: NodeJS.ErrnoException) => {\n if (err.code === 'EADDRINUSE') {\n console.log(`[zdashboard] port ${port} busy, trying ${port + 1}`);\n this.start(port + 1);\n } else throw err;\n });\n this.server.listen(port, '127.0.0.1', () => {\n const u = `http://localhost:${port}`;\n const target = this.page ? `${u}#${this.page}` : u;\n console.log(`[zdashboard] v${VERSION} dashboard -> ${u}`);\n console.log(`[zdashboard] project -> ${this.root}`);\n console.log(`[zdashboard] detect -> openspec:${this.det.hasOpenspec} docs:${this.det.hasDocs} just:${this.det.hasJust} bugs:${this.det.hasBugs}`);\n if (this.open) exec(process.platform === 'darwin' ? `open ${target}` : `start ${target}`);\n });\n }\n\n stop() {\n if (this.server) { try { this.server.close(); } catch {} }\n setTimeout(() => {\n try { this.ctx.root.fiber.dispose(); } catch {}\n process.exit(0);\n }, 50);\n }\n\n dispose() {\n if (this.server) { try { this.server.close(); } catch {} }\n }\n}\n","{\n \"name\": \"zdashboard\",\n \"version\": \"2.0.0\",\n \"description\": \"ZCode skill dashboard platform — pluggable viewers for zdesign/zview/zreview/zgoal\",\n \"type\": \"module\",\n \"bin\": {\n \"zdashboard\": \"./dist/cli.js\"\n },\n \"files\": [\n \"dist\"\n ],\n \"publishConfig\": {\n \"access\": \"public\"\n },\n \"scripts\": {\n \"dev\": \"vite\",\n \"build\": \"tsup && vite build\",\n \"build:web\": \"vite build\",\n \"build:node\": \"tsup\",\n \"start\": \"node dist/cli.js\",\n \"preview\": \"vite preview\"\n },\n \"dependencies\": {\n \"@radix-ui/react-scroll-area\": \"^1.2.0\",\n \"@radix-ui/react-separator\": \"^1.1.0\",\n \"@radix-ui/react-slot\": \"^1.1.0\",\n \"@radix-ui/react-tooltip\": \"^1.1.2\",\n \"@uidotdev/usehooks\": \"^2.4.0\",\n \"ansi-to-react\": \"^6.1.6\",\n \"class-variance-authority\": \"^0.7.0\",\n \"clsx\": \"^2.1.1\",\n \"cordis\": \"4.0.0-rc.8\",\n \"cosmokit\": \"^1.8.1\",\n \"date-fns\": \"^3.6.0\",\n \"filesize\": \"^11.0.0\",\n \"highlight.js\": \"^11.11.1\",\n \"katex\": \"^0.16.11\",\n \"ky\": \"^1.7.0\",\n \"lodash-es\": \"^4.17.21\",\n \"lucide-react\": \"^0.460.0\",\n \"react\": \"^18.3.1\",\n \"react-dom\": \"^18.3.1\",\n \"react-error-boundary\": \"^5.0.0\",\n \"react-markdown\": \"^9.0.1\",\n \"rehype-autolink-headings\": \"^7.1.0\",\n \"rehype-highlight\": \"^7.0.1\",\n \"rehype-katex\": \"^7.0.1\",\n \"rehype-raw\": \"^7.0.0\",\n \"rehype-slug\": \"^6.0.0\",\n \"remark-frontmatter\": \"^5.0.0\",\n \"remark-gfm\": \"^4.0.0\",\n \"remark-math\": \"^6.0.0\",\n \"sonner\": \"^1.5.0\",\n \"tailwind-merge\": \"^2.5.4\",\n \"tsx\": \"^4.7.0\",\n \"use-debounce\": \"^10.0.0\",\n \"yaml\": \"^2.9.0\"\n },\n \"devDependencies\": {\n \"@tailwindcss/typography\": \"^0.5.20\",\n \"@testing-library/jest-dom\": \"^7.0.1\",\n \"@testing-library/react\": \"^16.3.2\",\n \"@types/lodash-es\": \"^4.17.12\",\n \"@types/node\": \"^22.9.0\",\n \"@types/react\": \"^18.3.12\",\n \"@types/react-dom\": \"^18.3.1\",\n \"@vitejs/plugin-react\": \"^4.7.0\",\n \"autoprefixer\": \"^10.4.20\",\n \"jsdom\": \"^30.0.1\",\n \"postcss\": \"^8.4.49\",\n \"tailwindcss\": \"^3.4.14\",\n \"tailwindcss-animate\": \"^1.0.7\",\n \"tsup\": \"^8.3.5\",\n \"typescript\": \"^5.6.3\",\n \"vite\": \"^5.4.10\",\n \"vitest\": \"^1.6.0\"\n },\n \"pnpm\": {\n \"onlyBuiltDependencies\": [\n \"esbuild\"\n ]\n }\n}\n","import fs from 'node:fs';\nimport http from 'node:http';\nimport { Service } from 'cordis';\nimport type { Context } from 'cordis';\n\ndeclare module 'cordis' {\n interface Context {\n reload: ReloadService;\n }\n}\n\nconst WATCH_DEBOUNCE_MS = 150;\n\nexport class ReloadService extends Service {\n static inject = ['server'];\n private clients = new Set<http.ServerResponse>();\n private watcher?: fs.FSWatcher;\n private timer?: NodeJS.Timeout;\n\n constructor(ctx: Context, config: { root: string }) {\n super(ctx, 'reload');\n this.ctx.effect(() => () => this.dispose());\n\n this.ctx.server.sse('/__reload', (res) => {\n this.clients.add(res);\n return () => this.clients.delete(res);\n });\n\n try {\n this.watcher = fs.watch(config.root, { recursive: true }, () => {\n if (this.timer) clearTimeout(this.timer);\n this.timer = setTimeout(() => {\n this.broadcast('reload');\n this.broadcast('files');\n }, WATCH_DEBOUNCE_MS);\n });\n } catch {\n // watch unavailable - static only\n }\n }\n\n broadcast(ev: string, data: unknown = '') {\n const payload = `event: ${ev}\\ndata: ${JSON.stringify(data == null ? '' : data)}\\n\\n`;\n for (const c of this.clients) {\n try { c.write(payload); } catch {}\n }\n }\n\n dispose() {\n if (this.watcher) { try { this.watcher.close(); } catch {} }\n if (this.timer) { clearTimeout(this.timer); }\n for (const c of this.clients) { try { c.end(); } catch {} }\n this.clients.clear();\n }\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\n\nexport type NodeKind = 'file' | 'dir' | 'log';\nexport interface TreeNode {\n name: string;\n kind: NodeKind;\n path?: string; // file: 相对 root 的路径(点击预览用)\n defaultCollapsed?: boolean;\n children?: TreeNode[];\n}\n\nfunction walkFiles(absDir: string, relDir: string, depth = 0): TreeNode[] {\n if (depth > 4) return [];\n let ents: fs.Dirent[];\n try { ents = fs.readdirSync(absDir, { withFileTypes: true }); } catch { return []; }\n const nodes: TreeNode[] = [];\n for (const ent of ents) {\n if (ent.name.startsWith('.') || ent.name === 'node_modules') continue;\n const rel = relDir ? `${relDir}/${ent.name}` : ent.name;\n if (ent.isDirectory()) {\n nodes.push({ name: ent.name, kind: 'dir', children: walkFiles(path.join(absDir, ent.name), rel, depth + 1) });\n } else {\n nodes.push({ name: ent.name, kind: 'file', path: rel });\n }\n }\n nodes.sort((a, b) => (a.kind === b.kind ? a.name.localeCompare(b.name) : a.kind === 'dir' ? -1 : 1));\n return nodes;\n}\n\n/** 方案模式树形扫描:openspec 感知 + docs 聚合 + 其他兜底 */\nexport function scanTree(root: string, hasOpenspec: boolean, hasDocs: boolean): TreeNode[] {\n const tree: TreeNode[] = [];\n if (hasOpenspec && fs.existsSync(path.join(root, 'openspec', 'changes'))) {\n const changesDir = path.join(root, 'openspec', 'changes');\n const active: TreeNode[] = [];\n const archived: TreeNode[] = [];\n for (const ent of fs.readdirSync(changesDir, { withFileTypes: true })) {\n if (!ent.isDirectory() || ent.name.startsWith('.') || ent.name === 'archive') continue;\n active.push({ name: ent.name, kind: 'dir', children: walkFiles(path.join(changesDir, ent.name), `openspec/changes/${ent.name}`) });\n }\n active.sort((a, b) => a.name.localeCompare(b.name));\n const archiveDir = path.join(changesDir, 'archive');\n if (fs.existsSync(archiveDir)) {\n for (const ent of fs.readdirSync(archiveDir, { withFileTypes: true })) {\n if (!ent.isDirectory() || ent.name.startsWith('.')) continue;\n archived.push({ name: ent.name, kind: 'dir', children: walkFiles(path.join(archiveDir, ent.name), `openspec/changes/archive/${ent.name}`) });\n }\n archived.sort((a, b) => b.name.localeCompare(a.name)); // 日期前缀倒序\n }\n if (active.length) tree.push({ name: `进行中 (${active.length})`, kind: 'dir', children: active });\n if (archived.length) tree.push({ name: 'archive', kind: 'dir', defaultCollapsed: true, children: archived });\n const specsDir = path.join(root, 'openspec', 'specs');\n if (fs.existsSync(specsDir)) {\n const specs = walkFiles(specsDir, 'openspec/specs');\n if (specs.length) tree.push({ name: 'specs', kind: 'dir', children: specs });\n }\n }\n if (hasDocs && fs.existsSync(path.join(root, 'docs'))) {\n const docs = walkFiles(path.join(root, 'docs'), 'docs');\n if (docs.length) tree.push({ name: 'docs', kind: 'dir', children: docs });\n }\n const skip = new Set(['openspec', 'docs', 'node_modules', '.git', 'dist', 'test-server']);\n // \"其他\"只收根目录的 md 文档(README/CLAUDE 等);构建配置(pom.xml/justfile 等)不收——对\"方案+日志\"定位是噪音\n const etc: TreeNode[] = [];\n try {\n for (const ent of fs.readdirSync(root, { withFileTypes: true })) {\n if (ent.name.startsWith('.') || skip.has(ent.name)) continue;\n const ext = path.extname(ent.name).toLowerCase();\n if (ent.isFile() && (ext === '.md' || ext === '.markdown')) etc.push({ name: ent.name, kind: 'file', path: ent.name });\n }\n } catch (e) { console.error('[zdashboard] scan root etc failed:', e); }\n etc.sort((a, b) => a.name.localeCompare(b.name));\n if (etc.length) tree.push({ name: `其他 (${etc.length})`, kind: 'dir', children: etc });\n return tree;\n}\n","import type { Context } from 'cordis';\nimport { scanTree } from '../server/spec-scan.js';\nimport { detect } from '../server/detect.js';\nimport type { DetectResult } from '../server/detect.js';\n\nexport const apply = {\n inject: ['server'] as const,\n apply(ctx: Context, config: { root: string }) {\n let cached: { p: Promise<DetectResult>; v?: DetectResult } | null = null;\n const getDet = async (): Promise<DetectResult> => {\n if (cached?.v) return cached.v;\n if (!cached) cached = { p: detect(config.root).catch(() => ({ hasOpenspec: false, hasDocs: false, hasJust: false, hasBugs: false } as DetectResult)) };\n const d = await cached.p;\n cached.v = d;\n return d;\n };\n\n const server = ctx.server;\n if (server?.route) {\n server.route('/__files', async (_req, res) => {\n try {\n const d = await getDet();\n const tree = scanTree(config.root, d.hasOpenspec, d.hasDocs);\n res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8', 'Cache-Control': 'no-cache' });\n res.end(JSON.stringify({ tree, ...d }));\n } catch {\n res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8', 'Cache-Control': 'no-cache' });\n res.end(JSON.stringify({ tree: [], hasOpenspec: false, hasDocs: false, hasJust: false, hasBugs: false }));\n }\n });\n }\n },\n};\n","import { Service } from 'cordis';\nimport type { Context } from 'cordis';\n\ndeclare module 'cordis' {\n interface Context {\n dashboard: DashboardService;\n }\n}\n\nexport interface PluginManifest {\n mode: string;\n label: string;\n icon: string;\n description?: string;\n viewerUrl?: string; // 同源 URL,前端 iframe 渲染\n external?: boolean;\n}\n\nexport class DashboardService extends Service {\n static inject = ['server'];\n private plugins = new Map<string, PluginManifest>();\n\n constructor(ctx: Context) {\n super(ctx, 'dashboard');\n this.ctx.effect(() => () => this.plugins.clear());\n\n this.ctx.server.route('/__plugins', (_req, res) => {\n res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8', 'Cache-Control': 'no-cache' });\n res.end(JSON.stringify({ plugins: Array.from(this.plugins.values()) }));\n });\n }\n\n register(manifest: PluginManifest) {\n this.plugins.set(manifest.mode, manifest);\n this.ctx.effect(() => () => this.plugins.delete(manifest.mode));\n }\n\n list() {\n return Array.from(this.plugins.values());\n }\n\n get(mode: string): PluginManifest | undefined {\n return this.plugins.get(mode);\n }\n}\n","import { spawn, execFile, type ChildProcess } from 'node:child_process';\n\nexport interface Recipe { name: string; description: string; }\nexport type JustState = 'idle' | 'running' | 'exited';\nexport type JustEvent =\n | { type: 'log'; text: string }\n | { type: 'clear' }\n | { type: 'state'; state: JustState; recipe: string | null; code: number | null };\n\nconst MAX_BUFFER = 1000;\n\nexport class JustRunner {\n private cwd: string;\n private child: ChildProcess | null = null;\n private recipe: string | null = null;\n private state: JustState = 'idle';\n private code: number | null = null;\n private buffer: string[] = [];\n private pending = ''; // 行缓冲:块缓冲输出(如 maven)的 chunk 会在行中间断开,攒到 \\n 才切行\n private clients = new Set<(ev: JustEvent) => void>();\n private recipesCache: Recipe[] | null = null;\n\n constructor(cwd: string) { this.cwd = cwd; }\n\n recipes(): Promise<Recipe[]> {\n if (this.recipesCache) return Promise.resolve(this.recipesCache);\n return new Promise((resolve) => {\n execFile('just', ['--list', '--unsorted'], { cwd: this.cwd, maxBuffer: 1 << 20, timeout: 8000 }, (err, stdout) => {\n if (err) { resolve([]); return; }\n const out: Recipe[] = [];\n const seen = new Set<string>();\n for (const line of stdout.split(/\\r?\\n/).slice(1)) { // 跳过 \"Available recipes:\"\n const trimmed = line.trim();\n if (!trimmed) continue;\n const hashIdx = trimmed.indexOf('#');\n const sig = (hashIdx >= 0 ? trimmed.slice(0, hashIdx) : trimmed).trim();\n if (!sig) continue;\n const name = sig.split(/\\s+/)[0]; // \"hello msg=...\" -> \"hello\"\n if (seen.has(name)) continue;\n seen.add(name);\n out.push({ name, description: hashIdx >= 0 ? trimmed.slice(hashIdx + 1).trim() : '' });\n }\n this.recipesCache = out;\n resolve(out);\n });\n });\n }\n\n subscribe(fn: (ev: JustEvent) => void): () => void {\n this.clients.add(fn);\n // 连上即重放:历史日志 + 当前状态\n for (const text of this.buffer) fn({ type: 'log', text });\n fn({ type: 'state', state: this.state, recipe: this.recipe, code: this.code });\n return () => this.clients.delete(fn);\n }\n\n private emit(ev: JustEvent) { for (const fn of this.clients) fn(ev); }\n\n info() { return { state: this.state, recipe: this.recipe, code: this.code }; }\n\n /** 启动 recipe(调用方须先用 recipes() 校验名字);自动停旧进程 */\n start(recipe: string) {\n this.killChild();\n this.recipe = recipe;\n this.code = null;\n this.state = 'running';\n this.buffer = [];\n this.pending = '';\n this.emit({ type: 'clear' }); // 广播清屏:已连接的订阅者同步清掉上一个任务的残留日志\n this.emit({ type: 'state', state: 'running', recipe, code: null });\n const child = spawn('just', [recipe], {\n cwd: this.cwd,\n shell: true,\n env: {\n ...process.env,\n FORCE_COLOR: '1', // node 生态(chalk 等)\n // maven 检测非 tty 会关颜色;经 MAVEN_OPTS 强制开(保留用户已有值)\n MAVEN_OPTS: `${process.env.MAVEN_OPTS ?? ''} -Dstyle.color=always`.trim(),\n CI: '',\n },\n });\n this.child = child;\n const push = (d: Buffer) => {\n this.pending += d.toString();\n let idx: number;\n while ((idx = this.pending.indexOf('\\n')) >= 0) {\n const line = this.pending.slice(0, idx + 1);\n this.pending = this.pending.slice(idx + 1);\n this.pushLine(line);\n }\n // 无 \\n 的尾巴留在 pending,等下个 chunk(块缓冲输出会在行中断开,不能当独立行)\n };\n child.stdout?.on('data', push);\n child.stderr?.on('data', push);\n child.on('error', (err) => { this.pushLine(`[zdashboard] spawn error: ${err.message}\\n`); });\n child.on('exit', (code) => {\n if (this.pending) { this.pushLine(this.pending + '\\n'); this.pending = ''; } // flush 末尾无换行的残留\n this.child = null;\n this.state = 'exited';\n this.code = code ?? 0;\n this.emit({ type: 'state', state: 'exited', recipe: this.recipe, code: this.code });\n });\n }\n\n private pushLine(line: string) {\n this.buffer.push(line);\n if (this.buffer.length > MAX_BUFFER) this.buffer.shift();\n this.emit({ type: 'log', text: line });\n }\n\n stop() {\n this.killChild();\n }\n\n restart(recipe?: string) {\n const target = recipe ?? this.recipe;\n if (target) this.start(target);\n }\n\n private killChild() {\n const child = this.child;\n if (child?.pid) {\n try {\n if (process.platform === 'win32') spawn('taskkill', ['/PID', String(child.pid), '/T', '/F']);\n else child.kill('SIGTERM');\n } catch { /* 已退出 */ }\n }\n this.child = null;\n }\n}\n","import type { Context } from 'cordis';\nimport http from 'node:http';\nimport { JustRunner } from '../../server/just-runner.js';\n\nexport const apply = {\n inject: ['server', 'dashboard'] as const,\n apply(ctx: Context, config: { root: string }) {\n const root = config.root;\n\n ctx.inject(['server'], () => {\n if (!ctx.server?.route) return;\n\n const runner = new JustRunner(root);\n ctx.effect(() => () => runner.stop());\n\n ctx.server.route('/__just/recipes', async (_req, res) => {\n res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8', 'Cache-Control': 'no-cache' });\n try {\n const recipes = await runner.recipes();\n res.end(JSON.stringify(recipes));\n } catch {\n res.end(JSON.stringify([]));\n }\n });\n\n ctx.server.sse('/__just/logs', (res) => {\n const unsub = runner.subscribe((ev) => {\n res.write(`data: ${JSON.stringify(ev)}\\n\\n`);\n });\n return unsub;\n });\n\n ctx.server.route('/__just/start', async (req, res) => {\n if (req.headers['x-stop-token'] !== ctx.server.stopToken) { res.writeHead(403); res.end('forbidden'); return; }\n const body = await readBody(req);\n let recipe: string | undefined;\n try { recipe = JSON.parse(body || '{}').recipe; } catch {}\n const target = recipe ?? runner.info().recipe;\n if (!target) { res.writeHead(400); res.end('{\"error\":\"no recipe\"}'); return; }\n const recipes = await runner.recipes();\n if (!recipes.some((r) => r.name === target)) { res.writeHead(403); res.end('{\"error\":\"unknown recipe\"}'); return; }\n runner.start(target);\n res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' });\n res.end(JSON.stringify(runner.info()));\n });\n\n ctx.server.route('/__just/stop', async (req, res) => {\n if (req.headers['x-stop-token'] !== ctx.server.stopToken) { res.writeHead(403); res.end('forbidden'); return; }\n runner.stop();\n res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' });\n res.end(JSON.stringify(runner.info()));\n });\n\n ctx.server.route('/__just/restart', async (req, res) => {\n if (req.headers['x-stop-token'] !== ctx.server.stopToken) { res.writeHead(403); res.end('forbidden'); return; }\n const body = await readBody(req);\n let recipe: string | undefined;\n try { recipe = JSON.parse(body || '{}').recipe; } catch {}\n const target = recipe ?? runner.info().recipe;\n if (!target) { res.writeHead(400); res.end('{\"error\":\"no recipe\"}'); return; }\n const recipes = await runner.recipes();\n if (!recipes.some((r) => r.name === target)) { res.writeHead(403); res.end('{\"error\":\"unknown recipe\"}'); return; }\n runner.restart(target);\n res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' });\n res.end(JSON.stringify(runner.info()));\n });\n\n ctx.dashboard.register({ mode: 'just', label: 'Just Runner', icon: '📜', description: 'Just 任务日志与执行' });\n });\n },\n};\n\nasync function readBody(req: http.IncomingMessage): Promise<string> {\n return new Promise((resolve) => {\n let data = '';\n req.on('data', (c: string | Buffer) => { data += c; });\n req.on('end', () => resolve(data));\n });\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport { fetchJson } from './api/fetch.js';\n\n/** .zgoal/config.yaml(zgoal skill 的禅道凭据配置,扁平 key: value) */\nexport interface ZgoalConfig {\n url: string;\n account: string;\n password?: string;\n token?: string;\n product: number;\n}\n\nexport interface ZenBug {\n id: number;\n title: string;\n severity: number | string;\n pri: number | string;\n status: string;\n assignedTo: string;\n openedBy?: string;\n /** 指派给 config.account 的本人 */\n mine: boolean;\n}\n\nexport type BugsResult =\n | { ok: true; url: string; total: number; bugs: ZenBug[] }\n | { ok: false; error: string };\n\n/** 极简扁平 yaml 解析(仅 key: value 行,够 .zgoal/config.yaml 用) */\nfunction loadZgoalConfig(root: string): ZgoalConfig | null {\n const file = path.join(root, '.zgoal', 'config.yaml');\n if (!fs.existsSync(file)) return null;\n const kv: Record<string, string> = {};\n for (const line of fs.readFileSync(file, 'utf8').split('\\n')) {\n const m = line.match(/^\\s*([A-Za-z_]\\w*)\\s*:\\s*(.+?)\\s*$/);\n if (m && !m[2].startsWith('#')) kv[m[1]] = m[2].replace(/^[\"']|[\"']$/g, '');\n }\n const product = Number(kv.product);\n if (!kv.url || !product) return null;\n return {\n url: kv.url.replace(/\\/+$/, ''),\n account: kv.account ?? '',\n password: kv.password,\n token: kv.token,\n product,\n };\n}\n\nlet tokenCache: { key: string; token: string; at: number } | null = null;\n\nasync function getToken(cfg: ZgoalConfig): Promise<string> {\n if (cfg.token) return cfg.token;\n const key = `${cfg.url}|${cfg.account}|${cfg.password ?? ''}`;\n if (tokenCache && tokenCache.key === key && Date.now() - tokenCache.at < 10 * 60_000) return tokenCache.token;\n const json = await fetchJson(`${cfg.url}/api.php/v1/tokens`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ account: cfg.account, password: cfg.password }),\n });\n const token = typeof json.token === 'string' ? json.token : '';\n if (!token) throw new Error('token 获取失败:检查 account / password');\n tokenCache = { key, token, at: Date.now() };\n return token;\n}\n\nfunction normBug(b: Record<string, unknown>, account: string): ZenBug {\n const assigned = b.assignedTo;\n const assignedTo =\n typeof assigned === 'string'\n ? assigned\n : assigned && typeof assigned === 'object' && 'realname' in (assigned as Record<string, unknown>)\n ? String((assigned as Record<string, unknown>).realname ?? '')\n : '';\n const assignedAccount =\n typeof assigned === 'string'\n ? assigned\n : assigned && typeof assigned === 'object'\n ? String((assigned as Record<string, unknown>).account ?? '')\n : '';\n const mine = !!account && (assignedAccount === account || assignedTo === account);\n return {\n id: Number(b.id),\n title: String(b.title ?? ''),\n severity: (b.severity as number | string) ?? 4,\n pri: (b.pri as number | string) ?? 3,\n status: String(b.status ?? ''),\n assignedTo,\n openedBy: typeof b.openedBy === 'string' ? b.openedBy : undefined,\n mine,\n };\n}\n\n/** 只读拉取禅道 bug 列表(GET,绝不写)。失败返回 ok:false,不抛。 */\nexport async function fetchBugs(root: string): Promise<BugsResult> {\n const cfg = loadZgoalConfig(root);\n if (!cfg) return { ok: false, error: '.zgoal/config.yaml 缺失或 url/product 未配置(由 zgoal skill 创建)' };\n try {\n const token = await getToken(cfg);\n const json = await fetchJson(\n `${cfg.url}/api.php/v1/products/${cfg.product}/bugs?page=1&limit=100`,\n { headers: { Token: token } },\n );\n const raw = Array.isArray(json.bugs) ? (json.bugs as Record<string, unknown>[]) : [];\n return { ok: true, url: cfg.url, total: Number(json.total ?? raw.length), bugs: raw.map((b) => normBug(b, cfg.account)) };\n } catch (e) {\n const msg = e instanceof Error ? e.message : String(e);\n return { ok: false, error: `禅道请求失败(${msg})——检查 url / 凭据 / 是否开启 RESTful API v1` };\n }\n}\n","import ky from 'ky';\nimport { HttpError, NetworkError } from '../errors.js';\n\nexport async function fetchJson(url: string, init?: RequestInit): Promise<Record<string, unknown>> {\n try {\n const res = await ky(url, { ...init, timeout: 8000, retry: 2 });\n return await res.json() as Record<string, unknown>;\n } catch (e) {\n if (e instanceof HttpError) throw e;\n if (e instanceof Error && e.name === 'TimeoutError') {\n throw new NetworkError(`请求超时: ${url}`);\n }\n if (e instanceof Error && e.name === 'HTTPError') {\n throw new HttpError((e as Error & { status?: number }).status ?? 500, e.message);\n }\n throw new NetworkError(`请求失败: ${url}`, e);\n }\n}\n","export class HttpError extends Error {\n constructor(\n public status: number,\n message: string,\n public body?: unknown,\n ) {\n super(message);\n this.name = 'HttpError';\n }\n}\n\nexport class NetworkError extends Error {\n constructor(message: string, public cause?: unknown) {\n super(message);\n this.name = 'NetworkError';\n }\n}\n\nexport function isHttpError(e: unknown): e is HttpError {\n return e instanceof HttpError;\n}\n","import type { Context } from 'cordis';\nimport { fetchBugs } from '../../server/bugs.js';\n\nexport const apply = {\n inject: ['server', 'dashboard'] as const,\n apply(ctx: Context, config: { root: string }) {\n const root = config.root;\n\n ctx.inject(['server'], () => {\n if (!ctx.server?.route) return;\n\n ctx.dashboard.register({ mode: 'bugs', label: '禅道 Bugs', icon: '🎯', description: '只读 bug 列表' });\n\n ctx.server.route('/__bugs', async (_req, res) => {\n res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8', 'Cache-Control': 'no-cache' });\n try {\n const result = await fetchBugs(root);\n res.end(JSON.stringify(result));\n } catch (e) {\n res.end(JSON.stringify({ ok: false, error: e instanceof Error ? e.message : 'unknown error' }));\n }\n });\n\n });\n },\n};\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport YAML from 'yaml';\n\nexport type ItemState = 'open' | 'answered' | 'accepted' | 'dismissed';\nexport type ReviewStatus = 'draft' | 'reviewing' | 'passed' | 'rejected';\n\nexport interface ReviewItem {\n id: string;\n doc?: string;\n category?: string;\n severity?: 'high' | 'medium' | 'low';\n state: ItemState;\n question: string;\n answer?: string;\n}\n\nexport interface ReviewData {\n status: ReviewStatus;\n items: ReviewItem[];\n}\n\nconst REVIEW_FILE = 'review.yaml';\n\nexport class ReviewStore {\n private root: string;\n private file: string;\n private onChange?: () => void;\n\n constructor(root: string, onChange?: () => void) {\n this.root = root;\n this.file = path.join(root, REVIEW_FILE);\n this.onChange = onChange;\n }\n\n exists(): boolean { return fs.existsSync(this.file); }\n\n read(): ReviewData {\n try {\n const parsed = YAML.parse(fs.readFileSync(this.file, 'utf8')) as ReviewData;\n if (!parsed || !Array.isArray(parsed.items)) return { status: 'draft', items: [] };\n return parsed;\n } catch {\n return { status: 'draft', items: [] };\n }\n }\n\n private write(data: ReviewData) {\n fs.writeFileSync(this.file, YAML.stringify(data), 'utf8');\n this.onChange?.();\n }\n\n updateItem(id: string, patch: { answer?: string; state?: ItemState }): ReviewData {\n const data = this.read();\n const item = data.items.find((i) => i.id === id);\n if (!item) throw new Error(`item ${id} not found`);\n if (patch.answer !== undefined) item.answer = patch.answer;\n if (patch.state !== undefined) item.state = patch.state;\n if (patch.state === 'answered' && !patch.answer && !item.answer) item.answer = '';\n this.write(data);\n return data;\n }\n\n setStatus(status: ReviewStatus): ReviewData {\n const data = this.read();\n if (status === 'passed' && data.items.some((i) => i.state === 'open')) {\n throw new Error('存在未处理的评审项(open),不能通过');\n }\n data.status = status;\n this.write(data);\n return data;\n }\n\n docs(): string[] {\n try {\n return fs.readdirSync(this.root)\n .filter((f) => /\\.(md|markdown)$/i.test(f) && fs.statSync(path.join(this.root, f)).isFile())\n .sort();\n } catch { return []; }\n }\n}\n","import type { Context } from 'cordis';\nimport http from 'node:http';\nimport { ReviewStore, type ItemState, type ReviewStatus } from '../../server/review-store.js';\n\nexport const apply = {\n inject: ['server', 'dashboard', 'reload'] as const,\n apply(ctx: Context, config: { root: string }) {\n const root = config.root;\n\n ctx.inject(['server'], () => {\n if (!ctx.server?.route) return;\n\n ctx.dashboard.register({ mode: 'review', label: '文档评审', icon: '✅', description: 'review.yaml 逐项对齐' });\n\n const reviewStore = new ReviewStore(root, () => {\n ctx.reload.broadcast('files');\n });\n\n ctx.server.route('/__review', async (_req, res) => {\n res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8', 'Cache-Control': 'no-cache' });\n res.end(JSON.stringify(reviewStore.read()));\n });\n\n ctx.server.route('/__review/item', async (req, res) => {\n if (req.headers['x-stop-token'] !== ctx.server.stopToken) { res.writeHead(403); res.end('forbidden'); return; }\n try {\n const body = JSON.parse(await readBody(req) || '{}');\n const data = reviewStore.updateItem(body.id, { answer: body.answer, state: body.state as ItemState | undefined });\n res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8', 'Cache-Control': 'no-cache' });\n res.end(JSON.stringify(data));\n } catch (e) {\n res.writeHead(400, { 'Content-Type': 'application/json; charset=utf-8' });\n res.end(JSON.stringify({ error: e instanceof Error ? e.message : 'unknown error' }));\n }\n });\n\n ctx.server.route('/__review/status', async (req, res) => {\n if (req.headers['x-stop-token'] !== ctx.server.stopToken) { res.writeHead(403); res.end('forbidden'); return; }\n try {\n const body = JSON.parse(await readBody(req) || '{}');\n const data = reviewStore.setStatus(body.status as ReviewStatus);\n res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8', 'Cache-Control': 'no-cache' });\n res.end(JSON.stringify(data));\n } catch (e) {\n res.writeHead(400, { 'Content-Type': 'application/json; charset=utf-8' });\n res.end(JSON.stringify({ error: e instanceof Error ? e.message : 'unknown error' }));\n }\n });\n\n ctx.server.route('/__docs', async (_req, res) => {\n res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8', 'Cache-Control': 'no-cache' });\n res.end(JSON.stringify(reviewStore.docs()));\n });\n });\n },\n};\n\nasync function readBody(req: http.IncomingMessage): Promise<string> {\n return new Promise((resolve) => {\n let data = '';\n req.on('data', (c: string | Buffer) => { data += c; });\n req.on('end', () => resolve(data));\n });\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\n\nexport interface ChangeSummary {\n name: string;\n path: string;\n total: number;\n done: number;\n hasProposal: boolean;\n hasDesign: boolean;\n}\n\nexport interface ChangeDetail extends ChangeSummary {\n proposal?: string;\n design?: string;\n tasks: string;\n}\n\nfunction countTasks(md: string): { total: number; done: number } {\n const all = (md.match(/^\\s*-\\s*\\[[ xX]\\]\\s*/gm) || []).length;\n const done = (md.match(/^\\s*-\\s*\\[[xX]\\]\\s*/gm) || []).length;\n return { total: all, done };\n}\n\nfunction readText(p: string): string {\n try { return fs.readFileSync(p, 'utf8'); } catch { return ''; }\n}\n\nexport function scanApplyChanges(root: string): ChangeSummary[] {\n const changesDir = path.join(root, 'openspec', 'changes');\n if (!fs.existsSync(changesDir)) return [];\n const out: ChangeSummary[] = [];\n for (const ent of fs.readdirSync(changesDir, { withFileTypes: true })) {\n if (!ent.isDirectory() || ent.name.startsWith('.') || ent.name === 'archive') continue;\n const dir = path.join(changesDir, ent.name);\n const tasks = readText(path.join(dir, 'tasks.md'));\n const { total, done } = countTasks(tasks);\n out.push({\n name: ent.name,\n path: `openspec/changes/${ent.name}`,\n total,\n done,\n hasProposal: fs.existsSync(path.join(dir, 'proposal.md')),\n hasDesign: fs.existsSync(path.join(dir, 'design.md')),\n });\n }\n out.sort((a, b) => a.name.localeCompare(b.name));\n return out;\n}\n\nexport function readApplyChange(root: string, name: string): ChangeDetail {\n const dir = path.join(root, 'openspec', 'changes', name);\n const proposal = readText(path.join(dir, 'proposal.md'));\n const design = readText(path.join(dir, 'design.md'));\n const tasks = readText(path.join(dir, 'tasks.md'));\n const { total, done } = countTasks(tasks);\n return {\n name,\n path: `openspec/changes/${name}`,\n total,\n done,\n hasProposal: !!proposal,\n hasDesign: !!design,\n proposal,\n design,\n tasks,\n };\n}\n","import type { Context } from 'cordis';\nimport { scanApplyChanges, readApplyChange } from './scan.js';\n\nexport const apply = {\n inject: ['server', 'dashboard'] as const,\n apply(ctx: Context, config: { root: string }) {\n const root = config.root;\n\n ctx.inject(['server'], () => {\n if (!ctx.server?.route) return;\n\n ctx.dashboard.register({ mode: 'apply', label: '执行进度', icon: '⚙️', description: 'OpenSpec change 任务进度' });\n\n ctx.server.route('/__apply', async (_req, res) => {\n res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8', 'Cache-Control': 'no-cache' });\n res.end(JSON.stringify(scanApplyChanges(root)));\n });\n\n ctx.server.route('/__apply/change', async (req, res) => {\n const url = new URL(req.url || '', 'http://x');\n const name = url.searchParams.get('name');\n if (!name) {\n res.writeHead(400);\n res.end(JSON.stringify({ error: 'missing name' }));\n return;\n }\n if (name.includes('..') || name.includes('/') || name.includes('\\\\')) {\n res.writeHead(400);\n res.end(JSON.stringify({ error: 'invalid name' }));\n return;\n }\n try {\n const data = readApplyChange(root, name);\n res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8', 'Cache-Control': 'no-cache' });\n res.end(JSON.stringify(data));\n } catch (e) {\n res.writeHead(400);\n res.end(JSON.stringify({ error: e instanceof Error ? e.message : 'unknown error' }));\n }\n });\n });\n },\n};\n","import fs from 'node:fs';\nimport path from 'node:path';\n\nexport type AssetType = 'page' | 'component' | 'icon' | 'token' | 'md' | 'video' | 'audio' | 'pdf' | 'code' | 'font' | 'other';\n\nconst PAGE_EXTS = ['.html', '.htm'];\nconst ICON_EXTS = ['.svg', '.png', '.ico', '.jpg', '.jpeg', '.gif', '.webp'];\nconst VIDEO_EXTS = ['.mp4', '.webm', '.mov', '.ogg', '.ogv'];\nconst AUDIO_EXTS = ['.mp3', '.wav', '.flac', '.aac', '.m4a'];\nconst CODE_EXTS = ['.js', '.mjs', '.ts', '.tsx', '.jsx', '.css', '.json', '.txt', '.xml', '.yml', '.yaml', '.sh', '.md'];\nconst FONT_EXTS = ['.woff', '.woff2', '.ttf', '.otf'];\nconst TOKEN_RE = /token|theme|design|color|palette|typograph/i;\n\nexport function categorize(rel: string, ext: string): AssetType {\n if (rel.indexOf('components/') === 0) return 'component';\n if (VIDEO_EXTS.includes(ext)) return 'video';\n if (AUDIO_EXTS.includes(ext)) return 'audio';\n if (ext === '.pdf') return 'pdf';\n if (ext === '.md') return 'md';\n if (FONT_EXTS.includes(ext)) return 'font';\n if (ICON_EXTS.includes(ext)) return 'icon';\n if (PAGE_EXTS.includes(ext)) return 'page';\n if (CODE_EXTS.includes(ext)) return TOKEN_RE.test(rel) && (ext === '.css' || ext === '.json') ? 'token' : 'code';\n return 'other';\n}\n\nexport interface AssetFile { path: string; name: string; ext: string; type: AssetType; }\nexport type ScanResult = Record<AssetType, AssetFile[]>;\n\nexport function scanAssets(root: string): ScanResult {\n const out: ScanResult = {} as ScanResult;\n const keys: AssetType[] = ['page','component','icon','token','md','video','audio','pdf','code','font','other'];\n for (const k of keys) out[k] = [];\n const SKIP = new Set(['node_modules', '.git', 'dist', 'build', 'coverage', '.next', '.cache']);\n function walk(dir: string, rel: string) {\n let ents: fs.Dirent[];\n try { ents = fs.readdirSync(dir, { withFileTypes: true }); } catch { return; }\n for (const ent of ents) {\n if (ent.name.startsWith('.') || SKIP.has(ent.name)) continue;\n const r = rel ? `${rel}/${ent.name}` : ent.name;\n if (ent.isDirectory()) { walk(path.join(dir, ent.name), r); continue; }\n const ext = path.extname(ent.name).toLowerCase();\n const t = categorize(r, ext);\n out[t].push({ path: r, name: ent.name, ext, type: t });\n }\n }\n walk(root, '');\n return out;\n}\n","import type { Context } from 'cordis';\nimport { scanAssets } from '../../server/design-assets.js';\n\nexport const apply = {\n inject: ['server', 'dashboard'] as const,\n apply(ctx: Context, config: { root: string }) {\n const root = config.root;\n\n ctx.inject(['server'], () => {\n if (!ctx.server?.route) return;\n\n ctx.dashboard.register({ mode: 'design', label: '设计资产', icon: '🎨', description: '页面/组件/图标/Token 分类预览' });\n\n ctx.server.route('/__design/assets', async (_req, res) => {\n res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8', 'Cache-Control': 'no-cache' });\n res.end(JSON.stringify(scanAssets(root)));\n });\n });\n },\n};\n","import type { Context } from 'cordis';\n\nexport const apply = {\n inject: ['dashboard'] as const,\n apply(ctx: Context) {\n ctx.dashboard.register({ mode: 'view', label: '项目浏览', icon: '👁️', description: 'openspec / docs / 文档预览' });\n },\n};\n"],"mappings":"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","names":["path","fileURLToPath","fs","path","path","fs","fp","fs","Service","fs","path","Service","execFile","apply","fs","path","path","fs","apply","fs","path","apply","readBody","fs","path","apply","fs","path","apply","apply","__dirname","path","fileURLToPath","apply"]}
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts","../src/server/detect.ts","../src/core/server.ts","../package.json","../src/core/instance.ts","../src/core/open-url.ts","../src/core/reload.ts","../src/server/spec-scan.ts","../src/core/tree.ts","../src/core/manifest.ts","../src/server/just-runner.ts","../src/plugins/just/index.ts","../src/server/bugs.ts","../src/server/api/fetch.ts","../src/server/errors.ts","../src/plugins/bugs/index.ts","../src/server/review-store.ts","../src/plugins/review/index.ts","../src/plugins/apply/scan.ts","../src/plugins/apply/index.ts","../src/server/design-assets.ts","../src/plugins/design/index.ts","../src/plugins/view/index.ts","../src/plugins/stats/index.ts"],"sourcesContent":["import path from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { access, readdir } from 'node:fs/promises';\nimport { exec } from 'node:child_process';\nimport { detect } from './server/detect.js';\nimport type { DetectResult } from './server/detect.js';\nimport { Context, Service } from 'cordis';\nimport { ServerService, PLUGIN_STATIC_PREFIX } from './core/server.js';\nimport { ReloadService } from './core/reload.js';\nimport { apply as treeApply } from './core/tree.js';\nimport { DashboardService } from './core/manifest.js';\nimport {\n findReusable,\n stopInstance,\n writeRecord,\n clearRecord,\n} from './core/instance.js';\nimport { apply as justApply } from './plugins/just/index.js';\nimport { apply as bugsApply } from './plugins/bugs/index.js';\nimport { apply as reviewApply } from './plugins/review/index.js';\nimport { apply as applyApply } from './plugins/apply/index.js';\nimport { apply as designApply } from './plugins/design/index.js';\nimport { apply as viewApply } from './plugins/view/index.js';\nimport { apply as statsApply } from './plugins/stats/index.js';\n\nconst __dirname = path.dirname(fileURLToPath(import.meta.url));\n\nfunction parseArgs() {\n const args = process.argv.slice(2);\n const opts: Record<string, string | boolean> = {};\n for (let i = 0; i < args.length; i++) {\n const a = args[i];\n if (a.startsWith('--')) {\n const key = a.slice(2);\n const next = args[i + 1];\n if (next && !next.startsWith('--')) {\n opts[key] = next;\n i++;\n } else {\n opts[key] = true;\n }\n }\n }\n return {\n dir: typeof opts.dir === 'string' ? opts.dir : process.cwd(),\n port: typeof opts.port === 'string' ? Number(opts.port) : 4190,\n open: !!opts.open,\n page: typeof opts.page === 'string' ? opts.page : null,\n restart: !!opts.restart,\n plugins: typeof opts.plugins === 'string' ? opts.plugins : null,\n };\n}\n\nasync function pathExists(p: string): Promise<boolean> {\n try { await access(p); return true; } catch { return false; }\n}\n\nasync function loadExternal(ctx: Context, dir: string, root: string) {\n if (!dir) return;\n let tsxLoaded = false;\n try {\n const { register } = await import('tsx/esm/api');\n register();\n tsxLoaded = true;\n } catch {\n // tsx not available\n }\n\n try {\n const entries = await pathExists(dir) ? await readdir(dir, { withFileTypes: true }) : [];\n for (const ent of entries) {\n if (!ent.isDirectory()) continue;\n const candidates = tsxLoaded ? ['index.ts', 'index.js', 'index.mjs'] : ['index.js', 'index.mjs'];\n for (const name of candidates) {\n const p = path.join(dir, ent.name, name);\n if (await pathExists(p)) {\n try {\n const mod = await import(p);\n const plugin = mod.default ?? mod;\n if (plugin?.apply) {\n try {\n await ctx.plugin(plugin, { root });\n } catch (e) {\n console.error(`[zdashboard] failed to apply plugin ${ent.name}:`, e);\n break;\n }\n // 自动接线约定:mode === 目录名时补 external 标记与 viewerUrl\n const m = ctx.dashboard.get(ent.name);\n if (m && m.mode === ent.name) {\n const patch: Record<string, unknown> = { external: true };\n const webDir = path.join(dir, ent.name, 'web');\n if (await pathExists(path.join(webDir, 'index.html'))) {\n ctx.server.static(`${PLUGIN_STATIC_PREFIX}${ent.name}/`, webDir);\n if (!m.viewerUrl) patch.viewerUrl = `${PLUGIN_STATIC_PREFIX}${ent.name}/`;\n }\n ctx.dashboard.register({ ...m, ...patch });\n }\n }\n } catch (e) {\n console.error(`[zdashboard] failed to load plugin ${ent.name}:`, e);\n }\n break;\n }\n }\n }\n } catch {\n // ignore\n }\n}\n\nasync function main() {\n const args = parseArgs();\n const root = path.resolve(args.dir);\n\n // --- instance reuse (before creating Context) ---\n const existing = await findReusable(root);\n if (existing && !args.restart) {\n const u = `http://localhost:${existing.port}` + (args.page ? `#${args.page}` : '');\n if (args.open) openUrl(u);\n console.log(`[zdashboard] 已复用实例 ${u}(--restart 可强制重开)`);\n // 管道场景下 stdout 是异步写,显式等 flush 再 exit,避免日志被截断\n await new Promise<void>((resolve) => process.stdout.write('', () => resolve()));\n process.exit(0);\n }\n if (existing && args.restart) {\n console.log(`[zdashboard] --restart:停止旧实例 pid=${existing.pid}`);\n await stopInstance(existing);\n }\n\n const appDir = path.resolve(__dirname, 'web');\n\n const det = await detect(root);\n\n const ctx = new Context();\n\n // core services\n ctx.plugin(ServerService, {\n root,\n appDir,\n port: args.port,\n open: args.open,\n detect: det,\n page: args.page,\n onListen: (port: number) => writeRecord(root, port),\n });\n ctx.plugin(ReloadService, { root });\n ctx.plugin(treeApply, { root });\n ctx.plugin(DashboardService);\n\n // built-in plugins\n const plugins = [\n { name: 'stats', apply: statsApply },\n { name: 'just', apply: justApply },\n { name: 'bugs', apply: bugsApply },\n { name: 'review', apply: reviewApply },\n { name: 'apply', apply: applyApply },\n { name: 'design', apply: designApply },\n { name: 'view', apply: viewApply },\n ];\n for (const p of plugins) {\n try {\n ctx.plugin(p.apply, { root });\n } catch (e) {\n console.error(`[zdashboard] plugin ${p.name} failed:`, e);\n }\n }\n\n // external plugins\n if (args.plugins) {\n await loadExternal(ctx, path.resolve(args.plugins), root);\n }\n\n // graceful shutdown: clear .zdev record on SIGTERM / SIGINT\n const shutdown = () => {\n try { clearRecord(root); } catch {}\n process.exit(0);\n };\n process.on('SIGTERM', shutdown);\n process.on('SIGINT', shutdown);\n\n return ctx;\n}\n\nawait main().catch((e) => {\n console.error(e);\n process.exit(1);\n});\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport { execFile } from 'node:child_process';\n\nexport interface DetectResult {\n hasOpenspec: boolean;\n hasDocs: boolean;\n hasJust: boolean;\n hasBugs: boolean;\n}\n\nfunction justAvailable(cwd: string): Promise<boolean> {\n return new Promise((resolve) => {\n const child = execFile('just', ['--list', '--unsorted'], { cwd, timeout: 5000 }, (err) => {\n resolve(!err);\n });\n if (child.killed) resolve(false);\n });\n}\n\nexport async function detect(root: string): Promise<DetectResult> {\n const hasOpenspec = fs.existsSync(path.join(root, 'openspec'));\n const hasDocs = fs.existsSync(path.join(root, 'docs'));\n const hasJust = await justAvailable(root);\n const hasBugs = fs.existsSync(path.join(root, '.zgoal', 'config.yaml'));\n return { hasOpenspec, hasDocs, hasJust, hasBugs };\n}\n","import http from 'node:http';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport crypto from 'node:crypto';\nimport { fileURLToPath } from 'node:url';\nimport pkg from '../../package.json' with { type: 'json' };\nimport type { Context, DetectResult } from 'cordis';\nimport { Service } from 'cordis';\nimport { clearRecord } from './instance.js';\nimport { openUrl } from './open-url.js';\n\nconst VERSION = pkg.version;\nconst __dirname = path.dirname(fileURLToPath(import.meta.url));\n\nexport interface ServerOptions {\n root: string;\n appDir: string;\n port: number;\n open: boolean;\n page: string | null;\n detect: DetectResult;\n onListen?: (port: number) => void;\n}\n\ndeclare module 'cordis' {\n interface Context {\n server: ServerService;\n }\n}\n\nconst MIME: Record<string, string> = {\n '.html': 'text/html; charset=utf-8', '.htm': 'text/html; charset=utf-8',\n '.css': 'text/css; charset=utf-8', '.js': 'application/javascript; charset=utf-8',\n '.mjs': 'application/javascript; charset=utf-8', '.json': 'application/json; charset=utf-8',\n '.svg': 'image/svg+xml', '.png': 'image/png', '.ico': 'image/x-icon',\n '.jpg': 'image/jpeg', '.jpeg': 'image/jpeg', '.gif': 'image/gif', '.webp': 'image/webp',\n '.md': 'text/markdown; charset=utf-8', '.txt': 'text/plain; charset=utf-8',\n '.sql': 'text/plain; charset=utf-8', '.csv': 'text/plain; charset=utf-8',\n '.tsv': 'text/plain; charset=utf-8', '.yaml': 'text/yaml; charset=utf-8',\n '.yml': 'text/yaml; charset=utf-8', '.xml': 'application/xml; charset=utf-8',\n '.py': 'text/plain; charset=utf-8', '.ts': 'text/plain; charset=utf-8',\n '.java': 'text/plain; charset=utf-8', '.go': 'text/plain; charset=utf-8',\n '.rs': 'text/plain; charset=utf-8', '.rb': 'text/plain; charset=utf-8',\n '.php': 'text/plain; charset=utf-8', '.c': 'text/plain; charset=utf-8',\n '.cpp': 'text/plain; charset=utf-8', '.h': 'text/plain; charset=utf-8',\n '.cs': 'text/plain; charset=utf-8', '.swift': 'text/plain; charset=utf-8',\n '.kt': 'text/plain; charset=utf-8', '.scala': 'text/plain; charset=utf-8',\n '.sh': 'text/plain; charset=utf-8', '.bash': 'text/plain; charset=utf-8',\n '.zsh': 'text/plain; charset=utf-8', '.fish': 'text/plain; charset=utf-8',\n '.env': 'text/plain; charset=utf-8', '.gitignore': 'text/plain; charset=utf-8',\n '.dockerfile': 'text/plain; charset=utf-8',\n '.woff': 'font/woff', '.woff2': 'font/woff2', '.ttf': 'font/woff',\n '.map': 'application/json; charset=utf-8',\n};\n\nconst INJECT = `<script>(function(){try{var es=new EventSource('/__reload');es.addEventListener('reload',function(){location.reload();});es.onerror=function(){es.close();};}catch(e){}document.addEventListener('click',function(e){var t=e.target;if(t&&t.closest){var a=t.closest('a[target]');if(a&&a.target!=='_self'){a.target='_self';}}},true);})();</script>`;\n\nexport const PLUGIN_STATIC_PREFIX = '/__plugin/';\n\nexport class ServerService extends Service {\n stopToken: string;\n private root: string;\n private appDir: string;\n private open: boolean;\n private page: string | null;\n private det: DetectResult;\n private routes = new Map<string, (req: http.IncomingMessage, res: http.ServerResponse) => void>();\n private sses = new Map<string, (res: http.ServerResponse) => (() => void) | void>();\n private prefixStatic = new Map<string, string>();\n private server?: http.Server;\n private onListen?: (port: number) => void;\n\n constructor(ctx: Context, config: ServerOptions) {\n super(ctx, 'server');\n this.stopToken = crypto.randomBytes(12).toString('hex');\n this.root = config.root;\n this.appDir = config.appDir;\n this.open = config.open;\n this.page = config.page;\n this.det = config.detect;\n this.onListen = config.onListen;\n ctx.effect(() => () => this.dispose());\n\n this.route('/__config', (_req, res) => {\n res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8', 'Cache-Control': 'no-cache' });\n res.end(JSON.stringify({ stopToken: this.stopToken, version: VERSION, root: this.root }));\n });\n\n this.route('/__stop', async (req, res) => {\n if (req.headers['x-stop-token'] !== this.stopToken) {\n res.writeHead(403);\n res.end('forbidden');\n return;\n }\n res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' });\n res.end('{\"ok\":true}');\n this.stop();\n });\n\n this.start(config.port);\n }\n\n\n route(path: string, handler: (req: http.IncomingMessage, res: http.ServerResponse) => void) {\n this.routes.set(path, handler);\n this.ctx.effect(() => () => this.routes.delete(path));\n }\n\n sse(path: string, onConnect: (res: http.ServerResponse) => (() => void) | void) {\n this.sses.set(path, onConnect);\n this.ctx.effect(() => () => this.sses.delete(path));\n }\n\n static(prefix: string, dir: string) {\n this.prefixStatic.set(prefix, dir);\n this.ctx.effect(() => () => this.prefixStatic.delete(prefix));\n }\n\n private serveFile(filePath: string, res: http.ServerResponse, injectHtml: boolean) {\n fs.readFile(filePath, (err, data) => {\n if (err) { res.writeHead(404); return res.end('Not found'); }\n const ext = path.extname(filePath).toLowerCase();\n const ct = MIME[ext] ?? 'application/octet-stream';\n let body = data;\n if (injectHtml && ext === '.html') {\n const s = data.toString('utf8');\n body = Buffer.from(s.indexOf('</body>') >= 0 ? s.replace('</body>', INJECT + '</body>') : s + INJECT);\n }\n res.writeHead(200, { 'Content-Type': ct, 'Cache-Control': 'no-cache' });\n res.end(body);\n });\n }\n\n private servePrefix(url: string, res: http.ServerResponse): boolean {\n for (const [prefix, dir] of this.prefixStatic) {\n if (url.indexOf(prefix) === 0) {\n let rel = this.safeDecode(url.slice(prefix.length));\n if (!rel || rel === '/' || !path.extname(rel)) rel = path.join(rel || '', 'index.html');\n const fp = path.join(dir, rel);\n if (fp.indexOf(dir + path.sep) !== 0) { res.writeHead(403); return res.end('Forbidden'); }\n this.serveFile(fp, res, true);\n return true;\n }\n }\n return false;\n }\n\n private safeDecode(raw: string): string {\n try { return decodeURIComponent(raw); } catch { return raw; }\n }\n\n private handler = (req: http.IncomingMessage, res: http.ServerResponse) => {\n try {\n const rawUrl = req.url || '/';\n const url = rawUrl.split('?')[0];\n\n const rh = this.routes.get(url);\n if (rh) { rh(req, res); return; }\n const sh = this.sses.get(url);\n if (sh) {\n res.writeHead(200, { 'Content-Type': 'text/event-stream', 'Cache-Control': 'no-cache', Connection: 'keep-alive' });\n res.write(': connected\\n\\n');\n const cleanup = sh(res);\n req.on('close', () => { cleanup?.(); });\n return;\n }\n\n if (this.servePrefix(url, res)) return;\n\n if (url === '/' || url.indexOf('/__app/') === 0 || url.indexOf('/assets/') === 0) {\n let fp = this.appDir;\n if (url !== '/') fp = path.join(this.appDir, this.safeDecode(url));\n if (url.indexOf('/__app/') === 0) fp = path.join(this.appDir, url.slice(7));\n if (fp !== this.appDir && fp.indexOf(this.appDir + path.sep) !== 0) { res.writeHead(403); return res.end('Forbidden'); }\n if (url === '/') fp = path.join(this.appDir, 'index.html');\n return this.serveFile(fp, res, false);\n }\n\n const fp = path.join(this.root, this.safeDecode(url));\n if (fp !== this.root && fp.indexOf(this.root + path.sep) !== 0) { res.writeHead(403); return res.end('Forbidden'); }\n return this.serveFile(fp, res, true);\n } catch (e) {\n try { res.writeHead(400); res.end('bad request'); } catch {}\n console.error('[zdashboard] handler error', e);\n }\n };\n\n start(port: number) {\n this.server = http.createServer(this.handler);\n this.server.on('error', (err: NodeJS.ErrnoException) => {\n if (err.code === 'EADDRINUSE') {\n console.log(`[zdashboard] port ${port} busy, trying ${port + 1}`);\n this.start(port + 1);\n } else throw err;\n });\n this.server.listen(port, '127.0.0.1', () => {\n const u = `http://localhost:${port}`;\n const target = this.page ? `${u}#${this.page}` : u;\n console.log(`[zdashboard] v${VERSION} dashboard -> ${u}`);\n console.log(`[zdashboard] project -> ${this.root}`);\n console.log(`[zdashboard] detect -> openspec:${this.det.hasOpenspec} docs:${this.det.hasDocs} just:${this.det.hasJust} bugs:${this.det.hasBugs}`);\n if (this.open) openUrl(target);\n this.onListen?.(port);\n });\n }\n\n stop() {\n if (this.server) { try { this.server.close(); } catch {} }\n try { clearRecord(this.root); } catch {}\n setTimeout(() => {\n try { this.ctx.root.fiber.dispose(); } catch {}\n process.exit(0);\n }, 50);\n }\n\n dispose() {\n if (this.server) { try { this.server.close(); } catch {} }\n try { clearRecord(this.root); } catch {}\n }\n}\n","{\n \"name\": \"zdashboard\",\n \"version\": \"2.1.0\",\n \"description\": \"ZCode skill dashboard platform — pluggable viewers for zdesign/zview/zreview/zgoal\",\n \"type\": \"module\",\n \"bin\": {\n \"zdashboard\": \"./dist/cli.js\"\n },\n \"files\": [\n \"dist\"\n ],\n \"publishConfig\": {\n \"access\": \"public\"\n },\n \"scripts\": {\n \"dev\": \"vite\",\n \"build\": \"tsup && vite build\",\n \"build:web\": \"vite build\",\n \"build:node\": \"tsup\",\n \"start\": \"node dist/cli.js\",\n \"preview\": \"vite preview\"\n },\n \"dependencies\": {\n \"@radix-ui/react-scroll-area\": \"^1.2.0\",\n \"@radix-ui/react-separator\": \"^1.1.0\",\n \"@radix-ui/react-slot\": \"^1.1.0\",\n \"@radix-ui/react-tooltip\": \"^1.1.2\",\n \"@uidotdev/usehooks\": \"^2.4.0\",\n \"ansi-to-react\": \"^6.1.6\",\n \"class-variance-authority\": \"^0.7.0\",\n \"clsx\": \"^2.1.1\",\n \"cordis\": \"4.0.0-rc.8\",\n \"cosmokit\": \"^1.8.1\",\n \"date-fns\": \"^3.6.0\",\n \"filesize\": \"^11.0.0\",\n \"highlight.js\": \"^11.11.1\",\n \"katex\": \"^0.16.11\",\n \"ky\": \"^1.7.0\",\n \"lodash-es\": \"^4.17.21\",\n \"lucide-react\": \"^0.460.0\",\n \"react\": \"^18.3.1\",\n \"react-dom\": \"^18.3.1\",\n \"react-error-boundary\": \"^5.0.0\",\n \"react-markdown\": \"^9.0.1\",\n \"rehype-autolink-headings\": \"^7.1.0\",\n \"rehype-highlight\": \"^7.0.1\",\n \"rehype-katex\": \"^7.0.1\",\n \"rehype-raw\": \"^7.0.0\",\n \"rehype-slug\": \"^6.0.0\",\n \"remark-frontmatter\": \"^5.0.0\",\n \"remark-gfm\": \"^4.0.0\",\n \"remark-math\": \"^6.0.0\",\n \"sonner\": \"^1.5.0\",\n \"tailwind-merge\": \"^2.5.4\",\n \"tsx\": \"^4.7.0\",\n \"use-debounce\": \"^10.0.0\",\n \"yaml\": \"^2.9.0\"\n },\n \"devDependencies\": {\n \"@tailwindcss/typography\": \"^0.5.20\",\n \"@testing-library/jest-dom\": \"^7.0.1\",\n \"@testing-library/react\": \"^16.3.2\",\n \"@types/lodash-es\": \"^4.17.12\",\n \"@types/node\": \"^22.9.0\",\n \"@types/react\": \"^18.3.12\",\n \"@types/react-dom\": \"^18.3.1\",\n \"@vitejs/plugin-react\": \"^4.7.0\",\n \"autoprefixer\": \"^10.4.20\",\n \"jsdom\": \"^30.0.1\",\n \"postcss\": \"^8.4.49\",\n \"tailwindcss\": \"^3.4.14\",\n \"tailwindcss-animate\": \"^1.0.7\",\n \"tsup\": \"^8.3.5\",\n \"typescript\": \"^5.6.3\",\n \"vite\": \"^5.4.10\",\n \"vitest\": \"^1.6.0\"\n },\n \"pnpm\": {\n \"onlyBuiltDependencies\": [\n \"esbuild\"\n ]\n }\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\n\nexport interface InstanceRecord {\n pid: number;\n port: number;\n root: string;\n startedAt: string;\n}\n\nexport const RECORD_FILE = '.zdev/dashboard.json';\nexport const VERIFY_TIMEOUT_MS = 1500;\nexport const STOP_POLL_MS = 2000;\nexport const STOP_POLL_INTERVAL_MS = 100;\nexport const STOP_FINAL_WAIT_MS = 100;\n\nfunction recordPath(root: string): string {\n return path.join(root, RECORD_FILE);\n}\n\nexport function readRecord(root: string): InstanceRecord | null {\n try {\n const fp = recordPath(root);\n const raw = fs.readFileSync(fp, 'utf-8');\n const rec = JSON.parse(raw) as Partial<InstanceRecord>;\n if (\n typeof rec.pid === 'number' &&\n typeof rec.port === 'number' &&\n typeof rec.root === 'string' &&\n typeof rec.startedAt === 'string'\n ) {\n return rec as InstanceRecord;\n }\n return null;\n } catch {\n return null;\n }\n}\n\nexport function writeRecord(root: string, port: number): void {\n fs.mkdirSync(path.dirname(recordPath(root)), { recursive: true });\n const rec: InstanceRecord = {\n pid: process.pid,\n port,\n root,\n startedAt: new Date().toISOString(),\n };\n fs.writeFileSync(recordPath(root), JSON.stringify(rec, null, 2) + '\\n');\n}\n\nexport function clearRecord(root: string): void {\n try {\n // 属主校验:记录若已指向别的实例(并发双启落败者),不得误删胜者记录\n const rec = readRecord(root);\n if (rec && rec.pid !== process.pid) return;\n fs.unlinkSync(recordPath(root));\n } catch {\n // best-effort\n }\n}\n\nexport function isAlive(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch (e) {\n if ((e as NodeJS.ErrnoException).code === 'ESRCH') return false;\n // EPERM or other → process exists, we just can't signal it\n return true;\n }\n}\n\nasync function fetchWithTimeout(url: string): Promise<Response> {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), VERIFY_TIMEOUT_MS);\n try {\n return await fetch(url, { signal: controller.signal });\n } finally {\n clearTimeout(timer);\n }\n}\n\nexport async function verifyRoot(port: number, root: string): Promise<boolean> {\n try {\n const res = await fetchWithTimeout(`http://127.0.0.1:${port}/__config`);\n if (res.status !== 200) return false;\n const body = await res.json();\n if (typeof body.root !== 'string') return false;\n return body.root === root;\n } catch {\n return false;\n }\n}\n\nexport async function findReusable(root: string): Promise<InstanceRecord | null> {\n const rec = readRecord(root);\n if (!rec) return null;\n if (!isAlive(rec.pid)) return null;\n if (!(await verifyRoot(rec.port, root))) return null;\n return rec;\n}\n\nexport async function stopInstance(record: InstanceRecord): Promise<void> {\n try {\n process.kill(record.pid, 'SIGTERM');\n } catch {\n return;\n }\n\n const deadline = Date.now() + STOP_POLL_MS;\n while (Date.now() < deadline) {\n if (!isAlive(record.pid)) return;\n await new Promise((r) => setTimeout(r, STOP_POLL_INTERVAL_MS));\n }\n\n // still alive → SIGKILL\n try {\n process.kill(record.pid, 'SIGKILL');\n } catch {\n // ignore\n }\n await new Promise((r) => setTimeout(r, STOP_FINAL_WAIT_MS));\n}\n","import { exec } from 'node:child_process';\n\n/** 跨平台打开浏览器(macOS open / Windows start / Linux xdg-open) */\nexport function openUrl(url: string): void {\n const cmd =\n process.platform === 'darwin' ? 'open' :\n process.platform === 'win32' ? 'start' :\n 'xdg-open';\n exec(`${cmd} ${url}`);\n}\n","import fs from 'node:fs';\nimport http from 'node:http';\nimport { Service } from 'cordis';\nimport type { Context } from 'cordis';\n\ndeclare module 'cordis' {\n interface Context {\n reload: ReloadService;\n }\n}\n\nconst WATCH_DEBOUNCE_MS = 150;\n\nexport class ReloadService extends Service {\n static inject = ['server'];\n private clients = new Set<http.ServerResponse>();\n private watcher?: fs.FSWatcher;\n private timer?: NodeJS.Timeout;\n\n constructor(ctx: Context, config: { root: string }) {\n super(ctx, 'reload');\n this.ctx.effect(() => () => this.dispose());\n\n this.ctx.server.sse('/__reload', (res) => {\n this.clients.add(res);\n return () => this.clients.delete(res);\n });\n\n try {\n this.watcher = fs.watch(config.root, { recursive: true }, () => {\n if (this.timer) clearTimeout(this.timer);\n this.timer = setTimeout(() => {\n this.broadcast('reload');\n this.broadcast('files');\n }, WATCH_DEBOUNCE_MS);\n });\n } catch {\n // watch unavailable - static only\n }\n }\n\n broadcast(ev: string, data: unknown = '') {\n const payload = `event: ${ev}\\ndata: ${JSON.stringify(data == null ? '' : data)}\\n\\n`;\n for (const c of this.clients) {\n try { c.write(payload); } catch {}\n }\n }\n\n dispose() {\n if (this.watcher) { try { this.watcher.close(); } catch {} }\n if (this.timer) { clearTimeout(this.timer); }\n for (const c of this.clients) { try { c.end(); } catch {} }\n this.clients.clear();\n }\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\n\nexport type NodeKind = 'file' | 'dir' | 'log';\nexport interface TreeNode {\n name: string;\n kind: NodeKind;\n path?: string; // file: 相对 root 的路径(点击预览用)\n defaultCollapsed?: boolean;\n children?: TreeNode[];\n}\n\nfunction walkFiles(absDir: string, relDir: string, depth = 0): TreeNode[] {\n if (depth > 4) return [];\n let ents: fs.Dirent[];\n try { ents = fs.readdirSync(absDir, { withFileTypes: true }); } catch { return []; }\n const nodes: TreeNode[] = [];\n for (const ent of ents) {\n if (ent.name.startsWith('.') || ent.name === 'node_modules') continue;\n const rel = relDir ? `${relDir}/${ent.name}` : ent.name;\n if (ent.isDirectory()) {\n nodes.push({ name: ent.name, kind: 'dir', children: walkFiles(path.join(absDir, ent.name), rel, depth + 1) });\n } else {\n nodes.push({ name: ent.name, kind: 'file', path: rel });\n }\n }\n nodes.sort((a, b) => (a.kind === b.kind ? a.name.localeCompare(b.name) : a.kind === 'dir' ? -1 : 1));\n return nodes;\n}\n\n/** 方案模式树形扫描:openspec 感知 + docs 聚合 + 其他兜底 */\nexport function scanTree(root: string, hasOpenspec: boolean, hasDocs: boolean): TreeNode[] {\n const tree: TreeNode[] = [];\n if (hasOpenspec && fs.existsSync(path.join(root, 'openspec', 'changes'))) {\n const changesDir = path.join(root, 'openspec', 'changes');\n const active: TreeNode[] = [];\n const archived: TreeNode[] = [];\n for (const ent of fs.readdirSync(changesDir, { withFileTypes: true })) {\n if (!ent.isDirectory() || ent.name.startsWith('.') || ent.name === 'archive') continue;\n active.push({ name: ent.name, kind: 'dir', children: walkFiles(path.join(changesDir, ent.name), `openspec/changes/${ent.name}`) });\n }\n active.sort((a, b) => a.name.localeCompare(b.name));\n const archiveDir = path.join(changesDir, 'archive');\n if (fs.existsSync(archiveDir)) {\n for (const ent of fs.readdirSync(archiveDir, { withFileTypes: true })) {\n if (!ent.isDirectory() || ent.name.startsWith('.')) continue;\n archived.push({ name: ent.name, kind: 'dir', children: walkFiles(path.join(archiveDir, ent.name), `openspec/changes/archive/${ent.name}`) });\n }\n archived.sort((a, b) => b.name.localeCompare(a.name)); // 日期前缀倒序\n }\n if (active.length) tree.push({ name: `进行中 (${active.length})`, kind: 'dir', children: active });\n if (archived.length) tree.push({ name: 'archive', kind: 'dir', defaultCollapsed: true, children: archived });\n const specsDir = path.join(root, 'openspec', 'specs');\n if (fs.existsSync(specsDir)) {\n const specs = walkFiles(specsDir, 'openspec/specs');\n if (specs.length) tree.push({ name: 'specs', kind: 'dir', children: specs });\n }\n }\n if (hasDocs && fs.existsSync(path.join(root, 'docs'))) {\n const docs = walkFiles(path.join(root, 'docs'), 'docs');\n if (docs.length) tree.push({ name: 'docs', kind: 'dir', children: docs });\n }\n const skip = new Set(['openspec', 'docs', 'node_modules', '.git', 'dist', 'test-server']);\n // \"其他\"只收根目录的 md 文档(README/CLAUDE 等);构建配置(pom.xml/justfile 等)不收——对\"方案+日志\"定位是噪音\n const etc: TreeNode[] = [];\n try {\n for (const ent of fs.readdirSync(root, { withFileTypes: true })) {\n if (ent.name.startsWith('.') || skip.has(ent.name)) continue;\n const ext = path.extname(ent.name).toLowerCase();\n if (ent.isFile() && (ext === '.md' || ext === '.markdown')) etc.push({ name: ent.name, kind: 'file', path: ent.name });\n }\n } catch (e) { console.error('[zdashboard] scan root etc failed:', e); }\n etc.sort((a, b) => a.name.localeCompare(b.name));\n if (etc.length) tree.push({ name: `其他 (${etc.length})`, kind: 'dir', children: etc });\n return tree;\n}\n","import type { Context } from 'cordis';\nimport { scanTree } from '../server/spec-scan.js';\nimport { detect } from '../server/detect.js';\nimport type { DetectResult } from '../server/detect.js';\n\nexport const apply = {\n inject: ['server'] as const,\n apply(ctx: Context, config: { root: string }) {\n let cached: { p: Promise<DetectResult>; v?: DetectResult } | null = null;\n const getDet = async (): Promise<DetectResult> => {\n if (cached?.v) return cached.v;\n if (!cached) cached = { p: detect(config.root).catch(() => ({ hasOpenspec: false, hasDocs: false, hasJust: false, hasBugs: false } as DetectResult)) };\n const d = await cached.p;\n cached.v = d;\n return d;\n };\n\n const server = ctx.server;\n if (server?.route) {\n server.route('/__files', async (_req, res) => {\n try {\n const d = await getDet();\n const tree = scanTree(config.root, d.hasOpenspec, d.hasDocs);\n res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8', 'Cache-Control': 'no-cache' });\n res.end(JSON.stringify({ tree, ...d }));\n } catch {\n res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8', 'Cache-Control': 'no-cache' });\n res.end(JSON.stringify({ tree: [], hasOpenspec: false, hasDocs: false, hasJust: false, hasBugs: false }));\n }\n });\n }\n },\n};\n","import { Service } from 'cordis';\nimport type { Context } from 'cordis';\n\ndeclare module 'cordis' {\n interface Context {\n dashboard: DashboardService;\n }\n}\n\nexport interface PluginManifest {\n mode: string;\n label: string;\n icon: string;\n description?: string;\n viewerUrl?: string; // 同源 URL,前端 iframe 渲染\n external?: boolean;\n}\n\nexport class DashboardService extends Service {\n static inject = ['server'];\n private plugins = new Map<string, PluginManifest>();\n\n constructor(ctx: Context) {\n super(ctx, 'dashboard');\n this.ctx.effect(() => () => this.plugins.clear());\n\n this.ctx.server.route('/__plugins', (_req, res) => {\n res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8', 'Cache-Control': 'no-cache' });\n res.end(JSON.stringify({ plugins: Array.from(this.plugins.values()) }));\n });\n }\n\n register(manifest: PluginManifest) {\n this.plugins.set(manifest.mode, manifest);\n this.ctx.effect(() => () => this.plugins.delete(manifest.mode));\n }\n\n list() {\n return Array.from(this.plugins.values());\n }\n\n get(mode: string): PluginManifest | undefined {\n return this.plugins.get(mode);\n }\n}\n","import { spawn, execFile, type ChildProcess } from 'node:child_process';\n\nexport interface Recipe { name: string; description: string; }\nexport type JustState = 'idle' | 'running' | 'exited';\nexport type JustEvent =\n | { type: 'log'; text: string }\n | { type: 'clear' }\n | { type: 'state'; state: JustState; recipe: string | null; code: number | null };\n\nconst MAX_BUFFER = 1000;\n\nexport class JustRunner {\n private cwd: string;\n private child: ChildProcess | null = null;\n private recipe: string | null = null;\n private state: JustState = 'idle';\n private code: number | null = null;\n private buffer: string[] = [];\n private pending = ''; // 行缓冲:块缓冲输出(如 maven)的 chunk 会在行中间断开,攒到 \\n 才切行\n private clients = new Set<(ev: JustEvent) => void>();\n private recipesCache: Recipe[] | null = null;\n\n constructor(cwd: string) { this.cwd = cwd; }\n\n recipes(): Promise<Recipe[]> {\n if (this.recipesCache) return Promise.resolve(this.recipesCache);\n return new Promise((resolve) => {\n execFile('just', ['--list', '--unsorted'], { cwd: this.cwd, maxBuffer: 1 << 20, timeout: 8000 }, (err, stdout) => {\n if (err) { resolve([]); return; }\n const out: Recipe[] = [];\n const seen = new Set<string>();\n for (const line of stdout.split(/\\r?\\n/).slice(1)) { // 跳过 \"Available recipes:\"\n const trimmed = line.trim();\n if (!trimmed) continue;\n const hashIdx = trimmed.indexOf('#');\n const sig = (hashIdx >= 0 ? trimmed.slice(0, hashIdx) : trimmed).trim();\n if (!sig) continue;\n const name = sig.split(/\\s+/)[0]; // \"hello msg=...\" -> \"hello\"\n if (seen.has(name)) continue;\n seen.add(name);\n out.push({ name, description: hashIdx >= 0 ? trimmed.slice(hashIdx + 1).trim() : '' });\n }\n this.recipesCache = out;\n resolve(out);\n });\n });\n }\n\n subscribe(fn: (ev: JustEvent) => void): () => void {\n this.clients.add(fn);\n // 连上即重放:历史日志 + 当前状态\n for (const text of this.buffer) fn({ type: 'log', text });\n fn({ type: 'state', state: this.state, recipe: this.recipe, code: this.code });\n return () => this.clients.delete(fn);\n }\n\n private emit(ev: JustEvent) { for (const fn of this.clients) fn(ev); }\n\n info() { return { state: this.state, recipe: this.recipe, code: this.code }; }\n\n /** 启动 recipe(调用方须先用 recipes() 校验名字);自动停旧进程 */\n start(recipe: string) {\n this.killChild();\n this.recipe = recipe;\n this.code = null;\n this.state = 'running';\n this.buffer = [];\n this.pending = '';\n this.emit({ type: 'clear' }); // 广播清屏:已连接的订阅者同步清掉上一个任务的残留日志\n this.emit({ type: 'state', state: 'running', recipe, code: null });\n const child = spawn('just', [recipe], {\n cwd: this.cwd,\n shell: true,\n env: {\n ...process.env,\n FORCE_COLOR: '1', // node 生态(chalk 等)\n // maven 检测非 tty 会关颜色;经 MAVEN_OPTS 强制开(保留用户已有值)\n MAVEN_OPTS: `${process.env.MAVEN_OPTS ?? ''} -Dstyle.color=always`.trim(),\n CI: '',\n },\n });\n this.child = child;\n const push = (d: Buffer) => {\n this.pending += d.toString();\n let idx: number;\n while ((idx = this.pending.indexOf('\\n')) >= 0) {\n const line = this.pending.slice(0, idx + 1);\n this.pending = this.pending.slice(idx + 1);\n this.pushLine(line);\n }\n // 无 \\n 的尾巴留在 pending,等下个 chunk(块缓冲输出会在行中断开,不能当独立行)\n };\n child.stdout?.on('data', push);\n child.stderr?.on('data', push);\n child.on('error', (err) => { this.pushLine(`[zdashboard] spawn error: ${err.message}\\n`); });\n child.on('exit', (code) => {\n if (this.pending) { this.pushLine(this.pending + '\\n'); this.pending = ''; } // flush 末尾无换行的残留\n this.child = null;\n this.state = 'exited';\n this.code = code ?? 0;\n this.emit({ type: 'state', state: 'exited', recipe: this.recipe, code: this.code });\n });\n }\n\n private pushLine(line: string) {\n this.buffer.push(line);\n if (this.buffer.length > MAX_BUFFER) this.buffer.shift();\n this.emit({ type: 'log', text: line });\n }\n\n stop() {\n this.killChild();\n }\n\n restart(recipe?: string) {\n const target = recipe ?? this.recipe;\n if (target) this.start(target);\n }\n\n private killChild() {\n const child = this.child;\n if (child?.pid) {\n try {\n if (process.platform === 'win32') spawn('taskkill', ['/PID', String(child.pid), '/T', '/F']);\n else child.kill('SIGTERM');\n } catch { /* 已退出 */ }\n }\n this.child = null;\n }\n}\n","import type { Context } from 'cordis';\nimport http from 'node:http';\nimport { JustRunner } from '../../server/just-runner.js';\n\nexport const apply = {\n inject: ['server', 'dashboard'] as const,\n apply(ctx: Context, config: { root: string }) {\n const root = config.root;\n\n ctx.inject(['server'], () => {\n if (!ctx.server?.route) return;\n\n const runner = new JustRunner(root);\n ctx.effect(() => () => runner.stop());\n\n ctx.server.route('/__just/recipes', async (_req, res) => {\n res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8', 'Cache-Control': 'no-cache' });\n try {\n const recipes = await runner.recipes();\n res.end(JSON.stringify(recipes));\n } catch {\n res.end(JSON.stringify([]));\n }\n });\n\n ctx.server.sse('/__just/logs', (res) => {\n const unsub = runner.subscribe((ev) => {\n res.write(`data: ${JSON.stringify(ev)}\\n\\n`);\n });\n return unsub;\n });\n\n ctx.server.route('/__just/start', async (req, res) => {\n if (req.headers['x-stop-token'] !== ctx.server.stopToken) { res.writeHead(403); res.end('forbidden'); return; }\n const body = await readBody(req);\n let recipe: string | undefined;\n try { recipe = JSON.parse(body || '{}').recipe; } catch {}\n const target = recipe ?? runner.info().recipe;\n if (!target) { res.writeHead(400); res.end('{\"error\":\"no recipe\"}'); return; }\n const recipes = await runner.recipes();\n if (!recipes.some((r) => r.name === target)) { res.writeHead(403); res.end('{\"error\":\"unknown recipe\"}'); return; }\n runner.start(target);\n res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' });\n res.end(JSON.stringify(runner.info()));\n });\n\n ctx.server.route('/__just/stop', async (req, res) => {\n if (req.headers['x-stop-token'] !== ctx.server.stopToken) { res.writeHead(403); res.end('forbidden'); return; }\n runner.stop();\n res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' });\n res.end(JSON.stringify(runner.info()));\n });\n\n ctx.server.route('/__just/restart', async (req, res) => {\n if (req.headers['x-stop-token'] !== ctx.server.stopToken) { res.writeHead(403); res.end('forbidden'); return; }\n const body = await readBody(req);\n let recipe: string | undefined;\n try { recipe = JSON.parse(body || '{}').recipe; } catch {}\n const target = recipe ?? runner.info().recipe;\n if (!target) { res.writeHead(400); res.end('{\"error\":\"no recipe\"}'); return; }\n const recipes = await runner.recipes();\n if (!recipes.some((r) => r.name === target)) { res.writeHead(403); res.end('{\"error\":\"unknown recipe\"}'); return; }\n runner.restart(target);\n res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' });\n res.end(JSON.stringify(runner.info()));\n });\n\n ctx.dashboard.register({ mode: 'just', label: 'Just Runner', icon: '📜', description: 'Just 任务日志与执行' });\n });\n },\n};\n\nasync function readBody(req: http.IncomingMessage): Promise<string> {\n return new Promise((resolve) => {\n let data = '';\n req.on('data', (c: string | Buffer) => { data += c; });\n req.on('end', () => resolve(data));\n });\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport { fetchJson } from './api/fetch.js';\n\n/** .zgoal/config.yaml(zgoal skill 的禅道凭据配置,扁平 key: value) */\nexport interface ZgoalConfig {\n url: string;\n account: string;\n password?: string;\n token?: string;\n product: number;\n}\n\nexport interface ZenBug {\n id: number;\n title: string;\n severity: number | string;\n pri: number | string;\n status: string;\n assignedTo: string;\n openedBy?: string;\n /** 指派给 config.account 的本人 */\n mine: boolean;\n}\n\nexport type BugsResult =\n | { ok: true; url: string; total: number; bugs: ZenBug[] }\n | { ok: false; error: string };\n\n/** 极简扁平 yaml 解析(仅 key: value 行,够 .zgoal/config.yaml 用) */\nfunction loadZgoalConfig(root: string): ZgoalConfig | null {\n const file = path.join(root, '.zgoal', 'config.yaml');\n if (!fs.existsSync(file)) return null;\n const kv: Record<string, string> = {};\n for (const line of fs.readFileSync(file, 'utf8').split('\\n')) {\n const m = line.match(/^\\s*([A-Za-z_]\\w*)\\s*:\\s*(.+?)\\s*$/);\n if (m && !m[2].startsWith('#')) kv[m[1]] = m[2].replace(/^[\"']|[\"']$/g, '');\n }\n const product = Number(kv.product);\n if (!kv.url || !product) return null;\n return {\n url: kv.url.replace(/\\/+$/, ''),\n account: kv.account ?? '',\n password: kv.password,\n token: kv.token,\n product,\n };\n}\n\nlet tokenCache: { key: string; token: string; at: number } | null = null;\n\nasync function getToken(cfg: ZgoalConfig): Promise<string> {\n if (cfg.token) return cfg.token;\n const key = `${cfg.url}|${cfg.account}|${cfg.password ?? ''}`;\n if (tokenCache && tokenCache.key === key && Date.now() - tokenCache.at < 10 * 60_000) return tokenCache.token;\n const json = await fetchJson(`${cfg.url}/api.php/v1/tokens`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ account: cfg.account, password: cfg.password }),\n });\n const token = typeof json.token === 'string' ? json.token : '';\n if (!token) throw new Error('token 获取失败:检查 account / password');\n tokenCache = { key, token, at: Date.now() };\n return token;\n}\n\nfunction normBug(b: Record<string, unknown>, account: string): ZenBug {\n const assigned = b.assignedTo;\n const assignedTo =\n typeof assigned === 'string'\n ? assigned\n : assigned && typeof assigned === 'object' && 'realname' in (assigned as Record<string, unknown>)\n ? String((assigned as Record<string, unknown>).realname ?? '')\n : '';\n const assignedAccount =\n typeof assigned === 'string'\n ? assigned\n : assigned && typeof assigned === 'object'\n ? String((assigned as Record<string, unknown>).account ?? '')\n : '';\n const mine = !!account && (assignedAccount === account || assignedTo === account);\n return {\n id: Number(b.id),\n title: String(b.title ?? ''),\n severity: (b.severity as number | string) ?? 4,\n pri: (b.pri as number | string) ?? 3,\n status: String(b.status ?? ''),\n assignedTo,\n openedBy: typeof b.openedBy === 'string' ? b.openedBy : undefined,\n mine,\n };\n}\n\n/** 只读拉取禅道 bug 列表(GET,绝不写)。失败返回 ok:false,不抛。 */\nexport async function fetchBugs(root: string): Promise<BugsResult> {\n const cfg = loadZgoalConfig(root);\n if (!cfg) return { ok: false, error: '.zgoal/config.yaml 缺失或 url/product 未配置(由 zgoal skill 创建)' };\n try {\n const token = await getToken(cfg);\n const json = await fetchJson(\n `${cfg.url}/api.php/v1/products/${cfg.product}/bugs?page=1&limit=100`,\n { headers: { Token: token } },\n );\n const raw = Array.isArray(json.bugs) ? (json.bugs as Record<string, unknown>[]) : [];\n return { ok: true, url: cfg.url, total: Number(json.total ?? raw.length), bugs: raw.map((b) => normBug(b, cfg.account)) };\n } catch (e) {\n const msg = e instanceof Error ? e.message : String(e);\n return { ok: false, error: `禅道请求失败(${msg})——检查 url / 凭据 / 是否开启 RESTful API v1` };\n }\n}\n","import ky from 'ky';\nimport { HttpError, NetworkError } from '../errors.js';\n\nexport async function fetchJson(url: string, init?: RequestInit): Promise<Record<string, unknown>> {\n try {\n const res = await ky(url, { ...init, timeout: 8000, retry: 2 });\n return await res.json() as Record<string, unknown>;\n } catch (e) {\n if (e instanceof HttpError) throw e;\n if (e instanceof Error && e.name === 'TimeoutError') {\n throw new NetworkError(`请求超时: ${url}`);\n }\n if (e instanceof Error && e.name === 'HTTPError') {\n throw new HttpError((e as Error & { status?: number }).status ?? 500, e.message);\n }\n throw new NetworkError(`请求失败: ${url}`, e);\n }\n}\n","export class HttpError extends Error {\n constructor(\n public status: number,\n message: string,\n public body?: unknown,\n ) {\n super(message);\n this.name = 'HttpError';\n }\n}\n\nexport class NetworkError extends Error {\n constructor(message: string, public cause?: unknown) {\n super(message);\n this.name = 'NetworkError';\n }\n}\n\nexport function isHttpError(e: unknown): e is HttpError {\n return e instanceof HttpError;\n}\n","import type { Context } from 'cordis';\nimport { fetchBugs } from '../../server/bugs.js';\n\nexport const apply = {\n inject: ['server', 'dashboard'] as const,\n apply(ctx: Context, config: { root: string }) {\n const root = config.root;\n\n ctx.inject(['server'], () => {\n if (!ctx.server?.route) return;\n\n ctx.dashboard.register({ mode: 'bugs', label: '禅道 Bugs', icon: '🎯', description: '只读 bug 列表' });\n\n ctx.server.route('/__bugs', async (_req, res) => {\n res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8', 'Cache-Control': 'no-cache' });\n try {\n const result = await fetchBugs(root);\n res.end(JSON.stringify(result));\n } catch (e) {\n res.end(JSON.stringify({ ok: false, error: e instanceof Error ? e.message : 'unknown error' }));\n }\n });\n\n });\n },\n};\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport YAML from 'yaml';\n\nexport type ItemState = 'open' | 'answered' | 'accepted' | 'dismissed';\nexport type ReviewStatus = 'draft' | 'reviewing' | 'passed' | 'rejected';\n\nexport interface ReviewItem {\n id: string;\n doc?: string;\n category?: string;\n severity?: 'high' | 'medium' | 'low';\n state: ItemState;\n question: string;\n answer?: string;\n}\n\nexport interface ReviewData {\n status: ReviewStatus;\n items: ReviewItem[];\n}\n\nconst REVIEW_FILE = 'review.yaml';\n\nexport class ReviewStore {\n private root: string;\n private file: string;\n private onChange?: () => void;\n\n constructor(root: string, onChange?: () => void) {\n this.root = root;\n this.file = path.join(root, REVIEW_FILE);\n this.onChange = onChange;\n }\n\n exists(): boolean { return fs.existsSync(this.file); }\n\n read(): ReviewData {\n try {\n const parsed = YAML.parse(fs.readFileSync(this.file, 'utf8')) as ReviewData;\n if (!parsed || !Array.isArray(parsed.items)) return { status: 'draft', items: [] };\n return parsed;\n } catch {\n return { status: 'draft', items: [] };\n }\n }\n\n private write(data: ReviewData) {\n fs.writeFileSync(this.file, YAML.stringify(data), 'utf8');\n this.onChange?.();\n }\n\n updateItem(id: string, patch: { answer?: string; state?: ItemState }): ReviewData {\n const data = this.read();\n const item = data.items.find((i) => i.id === id);\n if (!item) throw new Error(`item ${id} not found`);\n if (patch.answer !== undefined) item.answer = patch.answer;\n if (patch.state !== undefined) item.state = patch.state;\n if (patch.state === 'answered' && !patch.answer && !item.answer) item.answer = '';\n this.write(data);\n return data;\n }\n\n setStatus(status: ReviewStatus): ReviewData {\n const data = this.read();\n if (status === 'passed' && data.items.some((i) => i.state === 'open')) {\n throw new Error('存在未处理的评审项(open),不能通过');\n }\n data.status = status;\n this.write(data);\n return data;\n }\n\n docs(): string[] {\n try {\n return fs.readdirSync(this.root)\n .filter((f) => /\\.(md|markdown)$/i.test(f) && fs.statSync(path.join(this.root, f)).isFile())\n .sort();\n } catch { return []; }\n }\n}\n","import type { Context } from 'cordis';\nimport http from 'node:http';\nimport { ReviewStore, type ItemState, type ReviewStatus } from '../../server/review-store.js';\n\nexport const apply = {\n inject: ['server', 'dashboard', 'reload'] as const,\n apply(ctx: Context, config: { root: string }) {\n const root = config.root;\n\n ctx.inject(['server'], () => {\n if (!ctx.server?.route) return;\n\n ctx.dashboard.register({ mode: 'review', label: '文档评审', icon: '✅', description: 'review.yaml 逐项对齐' });\n\n const reviewStore = new ReviewStore(root, () => {\n ctx.reload.broadcast('files');\n });\n\n ctx.server.route('/__review', async (_req, res) => {\n res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8', 'Cache-Control': 'no-cache' });\n res.end(JSON.stringify(reviewStore.read()));\n });\n\n ctx.server.route('/__review/item', async (req, res) => {\n if (req.headers['x-stop-token'] !== ctx.server.stopToken) { res.writeHead(403); res.end('forbidden'); return; }\n try {\n const body = JSON.parse(await readBody(req) || '{}');\n const data = reviewStore.updateItem(body.id, { answer: body.answer, state: body.state as ItemState | undefined });\n res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8', 'Cache-Control': 'no-cache' });\n res.end(JSON.stringify(data));\n } catch (e) {\n res.writeHead(400, { 'Content-Type': 'application/json; charset=utf-8' });\n res.end(JSON.stringify({ error: e instanceof Error ? e.message : 'unknown error' }));\n }\n });\n\n ctx.server.route('/__review/status', async (req, res) => {\n if (req.headers['x-stop-token'] !== ctx.server.stopToken) { res.writeHead(403); res.end('forbidden'); return; }\n try {\n const body = JSON.parse(await readBody(req) || '{}');\n const data = reviewStore.setStatus(body.status as ReviewStatus);\n res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8', 'Cache-Control': 'no-cache' });\n res.end(JSON.stringify(data));\n } catch (e) {\n res.writeHead(400, { 'Content-Type': 'application/json; charset=utf-8' });\n res.end(JSON.stringify({ error: e instanceof Error ? e.message : 'unknown error' }));\n }\n });\n\n ctx.server.route('/__docs', async (_req, res) => {\n res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8', 'Cache-Control': 'no-cache' });\n res.end(JSON.stringify(reviewStore.docs()));\n });\n });\n },\n};\n\nasync function readBody(req: http.IncomingMessage): Promise<string> {\n return new Promise((resolve) => {\n let data = '';\n req.on('data', (c: string | Buffer) => { data += c; });\n req.on('end', () => resolve(data));\n });\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\n\nexport interface ChangeSummary {\n name: string;\n path: string;\n total: number;\n done: number;\n hasProposal: boolean;\n hasDesign: boolean;\n}\n\nexport interface ChangeDetail extends ChangeSummary {\n proposal?: string;\n design?: string;\n tasks: string;\n}\n\nfunction countTasks(md: string): { total: number; done: number } {\n const all = (md.match(/^\\s*-\\s*\\[[ xX]\\]\\s*/gm) || []).length;\n const done = (md.match(/^\\s*-\\s*\\[[xX]\\]\\s*/gm) || []).length;\n return { total: all, done };\n}\n\nfunction readText(p: string): string {\n try { return fs.readFileSync(p, 'utf8'); } catch { return ''; }\n}\n\nexport function scanApplyChanges(root: string): ChangeSummary[] {\n const changesDir = path.join(root, 'openspec', 'changes');\n if (!fs.existsSync(changesDir)) return [];\n const out: ChangeSummary[] = [];\n for (const ent of fs.readdirSync(changesDir, { withFileTypes: true })) {\n if (!ent.isDirectory() || ent.name.startsWith('.') || ent.name === 'archive') continue;\n const dir = path.join(changesDir, ent.name);\n const tasks = readText(path.join(dir, 'tasks.md'));\n const { total, done } = countTasks(tasks);\n out.push({\n name: ent.name,\n path: `openspec/changes/${ent.name}`,\n total,\n done,\n hasProposal: fs.existsSync(path.join(dir, 'proposal.md')),\n hasDesign: fs.existsSync(path.join(dir, 'design.md')),\n });\n }\n out.sort((a, b) => a.name.localeCompare(b.name));\n return out;\n}\n\nexport function readApplyChange(root: string, name: string): ChangeDetail {\n const dir = path.join(root, 'openspec', 'changes', name);\n const proposal = readText(path.join(dir, 'proposal.md'));\n const design = readText(path.join(dir, 'design.md'));\n const tasks = readText(path.join(dir, 'tasks.md'));\n const { total, done } = countTasks(tasks);\n return {\n name,\n path: `openspec/changes/${name}`,\n total,\n done,\n hasProposal: !!proposal,\n hasDesign: !!design,\n proposal,\n design,\n tasks,\n };\n}\n","import type { Context } from 'cordis';\nimport { scanApplyChanges, readApplyChange } from './scan.js';\n\nexport const apply = {\n inject: ['server', 'dashboard'] as const,\n apply(ctx: Context, config: { root: string }) {\n const root = config.root;\n\n ctx.inject(['server'], () => {\n if (!ctx.server?.route) return;\n\n ctx.dashboard.register({ mode: 'apply', label: '执行进度', icon: '⚙️', description: 'OpenSpec change 任务进度' });\n\n ctx.server.route('/__apply', async (_req, res) => {\n res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8', 'Cache-Control': 'no-cache' });\n res.end(JSON.stringify(scanApplyChanges(root)));\n });\n\n ctx.server.route('/__apply/change', async (req, res) => {\n const url = new URL(req.url || '', 'http://x');\n const name = url.searchParams.get('name');\n if (!name) {\n res.writeHead(400);\n res.end(JSON.stringify({ error: 'missing name' }));\n return;\n }\n if (name.includes('..') || name.includes('/') || name.includes('\\\\')) {\n res.writeHead(400);\n res.end(JSON.stringify({ error: 'invalid name' }));\n return;\n }\n try {\n const data = readApplyChange(root, name);\n res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8', 'Cache-Control': 'no-cache' });\n res.end(JSON.stringify(data));\n } catch (e) {\n res.writeHead(400);\n res.end(JSON.stringify({ error: e instanceof Error ? e.message : 'unknown error' }));\n }\n });\n });\n },\n};\n","import fs from 'node:fs';\nimport path from 'node:path';\n\nexport type AssetType = 'page' | 'component' | 'icon' | 'token' | 'md' | 'video' | 'audio' | 'pdf' | 'font' | 'other';\n\nconst PAGE_EXTS = ['.html', '.htm'];\nconst ICON_EXTS = ['.svg', '.png', '.ico', '.jpg', '.jpeg', '.gif', '.webp'];\nconst VIDEO_EXTS = ['.mp4', '.webm', '.mov', '.ogg', '.ogv'];\nconst AUDIO_EXTS = ['.mp3', '.wav', '.flac', '.aac', '.m4a'];\nconst CODE_EXTS = ['.js', '.mjs', '.ts', '.tsx', '.jsx', '.css', '.json', '.txt', '.xml', '.yml', '.yaml', '.sh', '.md'];\nconst FONT_EXTS = ['.woff', '.woff2', '.ttf', '.otf'];\nconst TOKEN_RE = /token|theme|design|color|palette|typograph/i;\n\nexport function categorize(rel: string, ext: string): AssetType | null {\n if (rel.indexOf('components/') === 0) return 'component';\n if (VIDEO_EXTS.includes(ext)) return 'video';\n if (AUDIO_EXTS.includes(ext)) return 'audio';\n if (ext === '.pdf') return 'pdf';\n if (ext === '.md') return 'md';\n if (FONT_EXTS.includes(ext)) return 'font';\n if (ICON_EXTS.includes(ext)) return 'icon';\n if (PAGE_EXTS.includes(ext)) return 'page';\n if (CODE_EXTS.includes(ext)) {\n if (TOKEN_RE.test(rel) && (ext === '.css' || ext === '.json')) return 'token';\n return null;\n }\n return 'other';\n}\n\nexport interface AssetFile { path: string; name: string; ext: string; type: AssetType; }\nexport type ScanResult = Record<AssetType, AssetFile[]>;\n\nexport function scanAssets(root: string): ScanResult {\n const out: ScanResult = {} as ScanResult;\n const keys: AssetType[] = ['page','component','icon','token','md','video','audio','pdf','font','other'];\n for (const k of keys) out[k] = [];\n const SKIP = new Set(['node_modules', '.git', 'dist', 'build', 'coverage', '.next', '.cache']);\n function walk(dir: string, rel: string) {\n let ents: fs.Dirent[];\n try { ents = fs.readdirSync(dir, { withFileTypes: true }); } catch { return; }\n for (const ent of ents) {\n if (ent.name.startsWith('.') || SKIP.has(ent.name)) continue;\n const r = rel ? `${rel}/${ent.name}` : ent.name;\n if (ent.isDirectory()) { walk(path.join(dir, ent.name), r); continue; }\n const ext = path.extname(ent.name).toLowerCase();\n const t = categorize(r, ext);\n if (t) out[t].push({ path: r, name: ent.name, ext, type: t });\n }\n }\n walk(root, '');\n return out;\n}\n","import type { Context } from 'cordis';\nimport { scanAssets } from '../../server/design-assets.js';\n\nexport const apply = {\n inject: ['server', 'dashboard'] as const,\n apply(ctx: Context, config: { root: string }) {\n const root = config.root;\n\n ctx.inject(['server'], () => {\n if (!ctx.server?.route) return;\n\n ctx.dashboard.register({ mode: 'design', label: '设计资产', icon: '🎨', description: '页面/组件/图标/Token 分类预览' });\n\n ctx.server.route('/__design/assets', async (_req, res) => {\n res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8', 'Cache-Control': 'no-cache' });\n res.end(JSON.stringify(scanAssets(root)));\n });\n });\n },\n};\n","import type { Context } from 'cordis';\n\nexport const apply = {\n inject: ['dashboard'] as const,\n apply(ctx: Context) {\n ctx.dashboard.register({ mode: 'view', label: '项目浏览', icon: '👁️', description: 'openspec / docs / 文档预览' });\n },\n};\n","import type { Context } from 'cordis';\nimport fs from 'node:fs';\nimport path from 'node:path';\n\ninterface Stats {\n root: string;\n files: number;\n dirs: number;\n totalSize: number;\n byExt: { ext: string; count: number }[];\n markdown: number;\n openspec: { active: number; archived: number };\n hasJust: boolean;\n}\n\nconst SKIP_DIRS = new Set(['node_modules', '.git', 'dist', 'build', '.next', '.cache']);\n\nfunction scan(root: string): Stats {\n const stats: Stats = {\n root: path.basename(root),\n files: 0,\n dirs: 0,\n totalSize: 0,\n byExt: [],\n markdown: 0,\n openspec: { active: 0, archived: 0 },\n hasJust: fs.existsSync(path.join(root, 'justfile')),\n };\n const extMap = new Map<string, number>();\n\n const walk = (dir: string) => {\n let ents: fs.Dirent[];\n try { ents = fs.readdirSync(dir, { withFileTypes: true }); } catch { return; }\n for (const ent of ents) {\n if (ent.name.startsWith('.') || SKIP_DIRS.has(ent.name)) continue;\n const abs = path.join(dir, ent.name);\n if (ent.isDirectory()) { stats.dirs++; walk(abs); continue; }\n stats.files++;\n try { stats.totalSize += fs.statSync(abs).size; } catch {}\n const ext = path.extname(ent.name).toLowerCase() || '(无扩展名)';\n extMap.set(ext, (extMap.get(ext) ?? 0) + 1);\n if (ext === '.md' || ext === '.markdown') stats.markdown++;\n }\n };\n walk(root);\n\n const changesDir = path.join(root, 'openspec', 'changes');\n if (fs.existsSync(changesDir)) {\n for (const ent of fs.readdirSync(changesDir, { withFileTypes: true })) {\n if (!ent.isDirectory() || ent.name.startsWith('.')) continue;\n if (ent.name === 'archive') {\n try {\n stats.openspec.archived = fs.readdirSync(path.join(changesDir, 'archive'), { withFileTypes: true })\n .filter(e => e.isDirectory() && !e.name.startsWith('.')).length;\n } catch { /* ignore */ }\n } else stats.openspec.active++;\n }\n }\n\n stats.byExt = Array.from(extMap.entries())\n .map(([ext, count]) => ({ ext, count }))\n .sort((a, b) => b.count - a.count)\n .slice(0, 10);\n return stats;\n}\n\nexport const apply = {\n inject: ['server', 'dashboard'] as const,\n apply(ctx: Context, config: { root: string }) {\n ctx.inject(['server', 'dashboard'], () => {\n const server = (ctx as any).server;\n const dashboard = (ctx as any).dashboard;\n if (!server?.route || !dashboard?.register) return;\n\n dashboard.register({\n mode: 'stats',\n label: '项目统计',\n icon: '📊',\n description: '项目文件统计 · 扫描生成',\n });\n\n server.route('/__stats/data', (_req: unknown, res: import('node:http').ServerResponse) => {\n res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8', 'Cache-Control': 'no-cache' });\n res.end(JSON.stringify(scan(config.root)));\n });\n });\n },\n};\n"],"mappings":"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","names":["path","fileURLToPath","fs","path","fs","path","openUrl","path","fs","fp","openUrl","fs","Service","fs","path","Service","execFile","apply","fs","path","path","fs","apply","fs","path","apply","readBody","fs","path","apply","fs","path","apply","apply","fs","path","apply","__dirname","path","fileURLToPath","apply"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{r as c,j as r}from"./index-
|
|
1
|
+
import{r as c,j as r}from"./index-DkOVCCZ3.js";import{r as d,a as u,b as m,c as x,d as h,e as g,f}from"./katex.min-DAmb8ZJI.js";import{M as b,r as y}from"./index-B9eiA0v2.js";function j({children:n}){const t=c.useRef(null),[i,s]=c.useState(!1),a=async()=>{var e;const p=((e=t.current)==null?void 0:e.innerText)??"";try{await navigator.clipboard.writeText(p),s(!0),setTimeout(()=>s(!1),1500)}catch(o){console.error("[zdashboard] clipboard copy failed:",o)}};return r.jsxs("div",{className:"not-prose relative my-4 group",children:[r.jsx("button",{onClick:a,className:"absolute right-2 top-2 z-10 px-2 py-0.5 rounded border border-border bg-background/80 text-[11px] opacity-0 group-hover:opacity-100 transition-opacity",children:i?"已复制":"复制"}),r.jsx("pre",{ref:t,className:"overflow-auto rounded-md border bg-[#0d1117] p-3 text-xs leading-relaxed",children:n})]})}function N({path:n}){const[t,i]=c.useState(null);if(c.useEffect(()=>{let e=!0;return fetch("/"+encodeURI(n),{cache:"no-store"}).then(o=>o.text()).then(o=>{e&&i(o)}).catch(()=>{e&&i("")}),()=>{e=!1}},[n]),t===null)return r.jsx("p",{className:"p-3 text-xs text-muted-foreground",children:"加载中…"});const s=t.match(/^---\n([\s\S]*?)\n---\n?/),a=(s==null?void 0:s[1])??null,p=a?t.slice(s[0].length):t;return r.jsxs("div",{className:"prose dark:prose-invert mx-auto max-w-3xl p-8 prose-headings:scroll-mt-4 prose-pre:bg-transparent prose-pre:p-0 prose-pre:m-0",children:[a&&r.jsxs("details",{className:"not-prose mb-4 rounded border p-3 text-sm",children:[r.jsx("summary",{className:"cursor-pointer font-medium",children:"YAML frontmatter"}),r.jsx("pre",{className:"mt-2 whitespace-pre-wrap text-xs",children:a})]}),r.jsx(b,{remarkPlugins:[y,g,f],rehypePlugins:[d,u,[m,{behavior:"wrap",properties:{className:["no-underline"]}}],[x,{detect:!0,ignoreMissing:!0}],[h,{strict:!1}]],components:{pre:({children:e})=>r.jsx(j,{children:e}),a:({href:e,children:o})=>{const l=e==null?void 0:e.startsWith("http");return r.jsx("a",{href:e,target:l?"_blank":void 0,rel:l?"noreferrer noopener":void 0,children:o})}},children:p})]})}export{N as M};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{r as l,j as e}from"./index-DkOVCCZ3.js";function x(){const[t,r]=l.useState(null),[a,d]=l.useState(null);if(l.useEffect(()=>{fetch("/__stats/data",{cache:"no-store"}).then(s=>s.json()).then(r).catch(s=>d(s.message))},[]),a)return e.jsx("div",{className:"flex h-full items-center justify-center text-destructive",children:e.jsxs("p",{children:["加载失败: ",a]})});if(!t)return e.jsx("div",{className:"flex h-full items-center justify-center text-muted-foreground",children:e.jsx("p",{children:"加载中…"})});const n=(t.totalSize/1024/1024).toFixed(2),o=Math.max(...t.byExt.map(s=>s.count),1);return e.jsx("div",{className:"h-full overflow-auto",children:e.jsxs("div",{className:"mx-auto max-w-6xl p-6",children:[e.jsx("h1",{className:"text-lg font-semibold mb-1",children:"📊 项目统计"}),e.jsx("p",{className:"text-xs text-muted-foreground mb-5",children:"后端 fs 扫描 + 前端渲染 · 改文件即时刷新"}),e.jsx("div",{className:"grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-5 gap-3 mb-6",children:[{label:"文件",value:t.files},{label:"目录",value:t.dirs},{label:"总大小",value:`${n} MB`},{label:"Markdown",value:t.markdown},{label:"变更 进行/归档",value:`${t.openspec.active}/${t.openspec.archived}`}].map(s=>e.jsxs("div",{className:"rounded-lg border bg-background p-4",children:[e.jsx("div",{className:"text-xl font-bold",children:s.value}),e.jsx("div",{className:"text-[11px] text-muted-foreground mt-1",children:s.label})]},s.label))}),e.jsx("h2",{className:"text-xs font-medium text-muted-foreground mb-3",children:"文件类型 Top 10"}),e.jsx("div",{className:"space-y-2",children:t.byExt.map(s=>e.jsxs("div",{className:"flex items-center gap-3 text-xs",children:[e.jsx("span",{className:"w-16 font-mono text-foreground truncate",children:s.ext}),e.jsx("div",{className:"flex-1 h-2 bg-muted rounded-full overflow-hidden",children:e.jsx("div",{className:"h-full bg-primary rounded-full",style:{width:`${(s.count/o*100).toFixed(1)}%`}})}),e.jsx("span",{className:"w-8 text-right font-mono text-muted-foreground",children:s.count})]},s.ext))}),e.jsxs("div",{className:"mt-5 flex items-center gap-2 text-xs",children:[e.jsxs("span",{className:`inline-flex items-center gap-1 px-2 py-0.5 rounded border ${t.hasJust?"text-emerald-600 border-emerald-500/30 bg-emerald-500/10":"text-muted-foreground border-border"}`,children:["justfile ",t.hasJust?"✓":"✗"]}),e.jsxs("span",{className:"text-muted-foreground",children:["root: ",t.root]})]})]})})}export{x as default};
|