@xiaobuyu/nodesign 0.0.1
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/LICENSE +661 -0
- package/README.md +140 -0
- package/bin/nodesign.js +176 -0
- package/package.json +104 -0
- package/server/api/README.md +45 -0
- package/server/api/_guard.js +75 -0
- package/server/api/admin.js +187 -0
- package/server/api/assets/docx-page.js +103 -0
- package/server/api/assets/helpers.js +22 -0
- package/server/api/assets/notes.js +144 -0
- package/server/api/assets.js +896 -0
- package/server/api/board.js +57 -0
- package/server/api/browse.js +138 -0
- package/server/api/canvas.js +444 -0
- package/server/api/chatai.js +324 -0
- package/server/api/exports/build-standalone.js +980 -0
- package/server/api/exports/cards.js +118 -0
- package/server/api/exports/docx-pdf.js +46 -0
- package/server/api/exports/export-page.js +142 -0
- package/server/api/exports/handoff.js +147 -0
- package/server/api/exports.js +690 -0
- package/server/api/instruction.js +75 -0
- package/server/api/local.js +115 -0
- package/server/api/me.js +116 -0
- package/server/api/memory.js +185 -0
- package/server/api/pending-changes.js +366 -0
- package/server/api/plugins.js +164 -0
- package/server/api/projects.js +220 -0
- package/server/api/publish.js +64 -0
- package/server/api/recent.js +73 -0
- package/server/api/sessions.js +589 -0
- package/server/api/skills.js +77 -0
- package/server/api/standalone-fit.js +168 -0
- package/server/api/turn-compose.js +180 -0
- package/server/api/turn-inflight.js +44 -0
- package/server/api/turn.js +669 -0
- package/server/auth/README.md +17 -0
- package/server/auth/middleware.js +138 -0
- package/server/auth/origin-guard.js +71 -0
- package/server/auth/session.js +108 -0
- package/server/auth/tier.js +113 -0
- package/server/auth/users-store.js +348 -0
- package/server/edit/README.md +29 -0
- package/server/engine/README.md +113 -0
- package/server/engine/agent/agent-shared.js +550 -0
- package/server/engine/agent/auto-mode-default-hard-deny.txt +4 -0
- package/server/engine/agent/auto-mode-rules.js +78 -0
- package/server/engine/agent/context.js +418 -0
- package/server/engine/agent/events.js +464 -0
- package/server/engine/agent/hooks/canvas-validate.js +199 -0
- package/server/engine/agent/hooks/failure.js +120 -0
- package/server/engine/agent/hooks/file-events.js +75 -0
- package/server/engine/agent/hooks/lifecycle.js +233 -0
- package/server/engine/agent/hooks/post-canvas-focus.js +80 -0
- package/server/engine/agent/hooks/post-guidance.js +206 -0
- package/server/engine/agent/hooks/post-subagent-report.js +104 -0
- package/server/engine/agent/hooks/post-trim.js +58 -0
- package/server/engine/agent/hooks/pre-board-neighborhood.js +34 -0
- package/server/engine/agent/hooks/pre-defaults.js +84 -0
- package/server/engine/agent/hooks/pre-injectors.js +277 -0
- package/server/engine/agent/hooks/pre-performance-log-guard.js +78 -0
- package/server/engine/agent/hooks/pre-starter-files.js +61 -0
- package/server/engine/agent/hooks/pre-workspace-scope-guard.js +78 -0
- package/server/engine/agent/hooks/site-validate.js +94 -0
- package/server/engine/agent/hooks/tool-prompts.js +31 -0
- package/server/engine/agent/hooks/turn-state-memory.js +56 -0
- package/server/engine/agent/hooks/user-prompt-submit.js +215 -0
- package/server/engine/agent/hooks.js +354 -0
- package/server/engine/agent/init-contract.js +69 -0
- package/server/engine/agent/isolation.js +159 -0
- package/server/engine/agent/model-context.js +359 -0
- package/server/engine/agent/model-table.js +292 -0
- package/server/engine/agent/plugin-loader.js +266 -0
- package/server/engine/agent/prompts/nodesign-prelude.md +336 -0
- package/server/engine/agent/prompts/tools/ask-user-question-protocol.md +71 -0
- package/server/engine/agent/prompts/tools/direct-edit-protocol.md +98 -0
- package/server/engine/agent/prompts/tools/generate-image-cookbook.gemini-gateway.md +583 -0
- package/server/engine/agent/prompts/tools/generate-image-cookbook.md +483 -0
- package/server/engine/agent/prompts/tools/hybrid-reference.md +100 -0
- package/server/engine/agent/prompts/tools/paint-still-cookbook.md +270 -0
- package/server/engine/agent/prompts/tools/roll-film-cookbook.md +70 -0
- package/server/engine/agent/prompts/tools/site-reference.md +106 -0
- package/server/engine/agent/prompts/tools/tweaks-syntax.md +125 -0
- package/server/engine/agent/prompts/tools/vision-checker-dispatch.md +48 -0
- package/server/engine/agent/session-loop.js +1024 -0
- package/server/engine/agent/session-model.js +164 -0
- package/server/engine/agent/skill.js +204 -0
- package/server/engine/agent/system-prompts.js +86 -0
- package/server/engine/agent/task-events.js +78 -0
- package/server/engine/agents/ds-extractor.md +132 -0
- package/server/engine/agents/explorer.md +190 -0
- package/server/engine/agents/index.js +230 -0
- package/server/engine/agents/schemas/design-system.json +156 -0
- package/server/engine/agents/schemas/tweak-schema.json +113 -0
- package/server/engine/agents/tweak-proposer.md +127 -0
- package/server/engine/agents/vision-checker.md +254 -0
- package/server/engine/browse/capture.js +422 -0
- package/server/engine/browse/card.js +137 -0
- package/server/engine/browse/handover.js +59 -0
- package/server/engine/browse/page-digest.js +119 -0
- package/server/engine/browse/refs.js +196 -0
- package/server/engine/browse/registry.js +307 -0
- package/server/engine/browse/screencast.js +170 -0
- package/server/engine/browse/state.js +121 -0
- package/server/engine/chatai/chat-log.js +79 -0
- package/server/engine/chatai/index.js +193 -0
- package/server/engine/chatai/openai-compat.js +152 -0
- package/server/engine/chatai/orchestrate.js +309 -0
- package/server/engine/chatai/perform.js +40 -0
- package/server/engine/chatai/summarize.js +79 -0
- package/server/engine/mcp/capability-gate.js +52 -0
- package/server/engine/mcp/index.js +339 -0
- package/server/engine/mcp/param-sanitizer.js +142 -0
- package/server/engine/mcp/tools/arrange-on-board.js +124 -0
- package/server/engine/mcp/tools/artifact-session.js +278 -0
- package/server/engine/mcp/tools/browse-computer.js +421 -0
- package/server/engine/mcp/tools/browse-find-batch.js +183 -0
- package/server/engine/mcp/tools/browse-screenshot.js +157 -0
- package/server/engine/mcp/tools/browse.js +480 -0
- package/server/engine/mcp/tools/build-docx.js +101 -0
- package/server/engine/mcp/tools/clear-pending-changes.js +99 -0
- package/server/engine/mcp/tools/create-on-board.js +155 -0
- package/server/engine/mcp/tools/crystallize-skill.js +168 -0
- package/server/engine/mcp/tools/deliver-files.js +0 -0
- package/server/engine/mcp/tools/explain-style.js +237 -0
- package/server/engine/mcp/tools/export-handoff.js +133 -0
- package/server/engine/mcp/tools/expose-tweaks.js +149 -0
- package/server/engine/mcp/tools/generate-image.js +842 -0
- package/server/engine/mcp/tools/get-computed-styles.js +164 -0
- package/server/engine/mcp/tools/get-pending-changes.js +205 -0
- package/server/engine/mcp/tools/h3box-ssh.js +84 -0
- package/server/engine/mcp/tools/helpers/acquire-page.js +82 -0
- package/server/engine/mcp/tools/helpers/motion-lab.js +554 -0
- package/server/engine/mcp/tools/helpers/motion-scroll.js +112 -0
- package/server/engine/mcp/tools/helpers/perception-page.js +215 -0
- package/server/engine/mcp/tools/helpers/reference-download.js +103 -0
- package/server/engine/mcp/tools/helpers/rembg-bridge.py +80 -0
- package/server/engine/mcp/tools/helpers/rembg.js +273 -0
- package/server/engine/mcp/tools/helpers/shot-pipeline.js +280 -0
- package/server/engine/mcp/tools/highlight.js +68 -0
- package/server/engine/mcp/tools/list-pages.js +222 -0
- package/server/engine/mcp/tools/lookup-tags.js +59 -0
- package/server/engine/mcp/tools/navigate-to-page.js +60 -0
- package/server/engine/mcp/tools/organize-board.js +64 -0
- package/server/engine/mcp/tools/paint-still.js +434 -0
- package/server/engine/mcp/tools/pin-to-board.js +130 -0
- package/server/engine/mcp/tools/preview-deck.js +130 -0
- package/server/engine/mcp/tools/profile-scroll.js +305 -0
- package/server/engine/mcp/tools/publish-site.js +102 -0
- package/server/engine/mcp/tools/query-elements.js +195 -0
- package/server/engine/mcp/tools/read-board.js +103 -0
- package/server/engine/mcp/tools/read-document.js +93 -0
- package/server/engine/mcp/tools/read-page.js +264 -0
- package/server/engine/mcp/tools/read-tavern-json.js +143 -0
- package/server/engine/mcp/tools/record-decision.js +140 -0
- package/server/engine/mcp/tools/relate-on-board.js +110 -0
- package/server/engine/mcp/tools/remove-background.js +391 -0
- package/server/engine/mcp/tools/report-issue.js +115 -0
- package/server/engine/mcp/tools/roll-film.js +266 -0
- package/server/engine/mcp/tools/screenshot-docx.js +138 -0
- package/server/engine/mcp/tools/screenshot-url.js +195 -0
- package/server/engine/mcp/tools/screenshot.js +583 -0
- package/server/engine/mcp/tools/tier-gate.js +96 -0
- package/server/engine/mcp/tools/trace-motion.js +215 -0
- package/server/engine/mcp/tools/web-search.js +548 -0
- package/server/engine/motion/inventory.js +349 -0
- package/server/engine/perception/session.js +235 -0
- package/server/engine/plugins/nodesign/.claude-plugin/plugin.json +5 -0
- package/server/engine/plugins/nodesign/skills/deskskill-engine-mini/SKILL.md +192 -0
- package/server/engine/plugins/nodesign/skills/deskskill-engine-mini/canvas.template.html +667 -0
- package/server/engine/plugins/nodesign/skills/deskskill-engine-mini/patterns/hybrid-grid.md +22 -0
- package/server/engine/plugins/nodesign/skills/deskskill-engine-mini/patterns/image-led-cover.md +25 -0
- package/server/engine/plugins/nodesign/skills/deskskill-engine-mini/patterns/portrait.md +23 -0
- package/server/engine/plugins/nodesign/skills/deskskill-engine-mini/patterns/quote-backdrop.md +21 -0
- package/server/engine/plugins/nodesign/skills/deskskill-engine-mini/patterns/section-divider.md +23 -0
- package/server/engine/plugins/nodesign/skills/deskskill-engine-mini/patterns/text-led.md +21 -0
- package/server/engine/plugins/nodesign/skills/docx-craft/SKILL.md +162 -0
- package/server/engine/plugins/nodesign/skills/docx-craft/references/token-schema.md +407 -0
- package/server/engine/plugins/nodesign/skills/docx-craft//346/226/207/346/241/243.template.json +80 -0
- package/server/engine/plugins/nodesign/skills/rp-craft/SKILL.md +228 -0
- package/server/engine/plugins/nodesign/skills/rp-craft/patterns//346/274/224/345/207/272/351/241/265-/346/234/200/345/260/217/345/256/236/347/216/260.html +78 -0
- package/server/engine/plugins/nodesign/skills/rp-craft//346/274/224/345/207/272.template.js +268 -0
- package/server/engine/plugins/nodesign/skills/site-craft/SKILL.md +323 -0
- package/server/engine/plugins/nodesign/skills/site-craft/patterns/build-lane.md +134 -0
- package/server/engine/plugins/nodesign/skills/site-craft/patterns/cutout-collage.md +61 -0
- package/server/engine/plugins/nodesign/skills/site-craft/patterns/mock-app.md +163 -0
- package/server/engine/plugins/nodesign/skills/site-craft/patterns/page-transitions.md +86 -0
- package/server/engine/runs/active-runs.js +698 -0
- package/server/engine/runs/live-turn.js +252 -0
- package/server/engine/runs/store.js +364 -0
- package/server/engine/runs/turn-relay.js +217 -0
- package/server/engine/runtime/workspace.js +164 -0
- package/server/index.js +235 -0
- package/server/lib/artifact-file-path.js +80 -0
- package/server/lib/artifact-target.js +284 -0
- package/server/lib/asset-refs.js +239 -0
- package/server/lib/async-queue.js +104 -0
- package/server/lib/auto-relations.js +130 -0
- package/server/lib/binding-types.js +60 -0
- package/server/lib/board-kind-sizes.js +62 -0
- package/server/lib/board-relations.js +133 -0
- package/server/lib/browse-proxy.js +180 -0
- package/server/lib/canvas-id.js +36 -0
- package/server/lib/cover.js +227 -0
- package/server/lib/danbooru-tags.js +291 -0
- package/server/lib/doc-extract.js +156 -0
- package/server/lib/docx/build-from-source.js +260 -0
- package/server/lib/docx/build.js +490 -0
- package/server/lib/docx/dump-styles.js +287 -0
- package/server/lib/docx/fonts/nodesign-cjk.conf +164 -0
- package/server/lib/docx/merge-runs.js +129 -0
- package/server/lib/docx/numbering.js +218 -0
- package/server/lib/docx/order.js +152 -0
- package/server/lib/docx/rawzip.js +172 -0
- package/server/lib/docx/render.js +92 -0
- package/server/lib/docx/text-lint.js +225 -0
- package/server/lib/docx/tokens.js +335 -0
- package/server/lib/docx/units.js +29 -0
- package/server/lib/docx/xml.js +291 -0
- package/server/lib/docx-pages.js +187 -0
- package/server/lib/export-collect.js +289 -0
- package/server/lib/export-package.js +210 -0
- package/server/lib/html-srcset.js +145 -0
- package/server/lib/image-variant.js +460 -0
- package/server/lib/ingress/forward-openai-chat.js +305 -0
- package/server/lib/ingress/openai-chat.js +491 -0
- package/server/lib/ingress/session-notice.js +66 -0
- package/server/lib/ingress/session-routes.js +68 -0
- package/server/lib/ingress/slot-probe.js +130 -0
- package/server/lib/ingress/upstream-billing.js +52 -0
- package/server/lib/ingress/upstream-fail-streak.js +72 -0
- package/server/lib/ingress/upstream-truncation.js +48 -0
- package/server/lib/issues-store.js +182 -0
- package/server/lib/kinds/deck.js +72 -0
- package/server/lib/kinds/docx.js +283 -0
- package/server/lib/kinds/file-kinds.js +113 -0
- package/server/lib/kinds/index.js +202 -0
- package/server/lib/kinds/site.js +161 -0
- package/server/lib/model-ingress.js +543 -0
- package/server/lib/moderation.js +255 -0
- package/server/lib/notice-store.js +103 -0
- package/server/lib/plugin-install.js +104 -0
- package/server/lib/plugin-validator.js +721 -0
- package/server/lib/publish-store.js +115 -0
- package/server/lib/quick-summary.js +52 -0
- package/server/lib/quota.js +270 -0
- package/server/lib/rate-window.js +29 -0
- package/server/lib/reference-assets.js +92 -0
- package/server/lib/region-shot.js +135 -0
- package/server/lib/safe-path.js +73 -0
- package/server/lib/sdk-session.js +33 -0
- package/server/lib/showcase-store.js +92 -0
- package/server/lib/site-publish.js +465 -0
- package/server/lib/ssrf-guard.js +432 -0
- package/server/lib/task-scan.js +158 -0
- package/server/lib/tavern-json.js +154 -0
- package/server/lib/video-variant.js +237 -0
- package/server/lib/workspace-path.js +33 -0
- package/server/ops/fix-sdk-musl.mjs +40 -0
- package/server/ops/install-macos-fonts.sh +114 -0
- package/server/ops/macos-fonts.conf +336 -0
- package/server/ops/sandbox-shim/bwrap +57 -0
- package/server/projects/assets-summary.js +119 -0
- package/server/projects/auto-name.js +53 -0
- package/server/projects/board-store.js +640 -0
- package/server/projects/move-entry.js +103 -0
- package/server/projects/store.js +270 -0
- package/server/projects/ui-config.js +54 -0
- package/server/projects/workspace-templates.js +53 -0
- package/server/projects/workspace.js +1025 -0
- package/server/runtime/capabilities.js +153 -0
- package/server/runtime/local-config.js +177 -0
- package/server/runtime/local-env.js +88 -0
- package/server/runtime/platform.js +342 -0
- package/server/runtime/profile.js +72 -0
- package/server/services/rembg-launcher.js +313 -0
- package/server/services/rembg-service.py +334 -0
- package/server/shared/README.md +25 -0
- package/server/shared/deck.js +54 -0
- package/server/shared/time.js +49 -0
- package/server/style-pipeline/README.md +53 -0
- package/server/ws/broker.js +36 -0
- package/server/ws/browse-channel.js +177 -0
- package/server/ws/index.js +386 -0
- package/web/README.md +89 -0
- package/web/dist/assets/BrowserWindow-Dc7J7CYc.js +11 -0
- package/web/dist/assets/DeckWindow-4G0xX7P3.js +16 -0
- package/web/dist/assets/DocxWindow-BXQsoPkh.js +16 -0
- package/web/dist/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
- package/web/dist/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
- package/web/dist/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
- package/web/dist/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
- package/web/dist/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
- package/web/dist/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
- package/web/dist/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
- package/web/dist/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
- package/web/dist/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
- package/web/dist/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
- package/web/dist/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
- package/web/dist/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
- package/web/dist/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
- package/web/dist/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
- package/web/dist/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
- package/web/dist/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
- package/web/dist/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
- package/web/dist/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
- package/web/dist/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
- package/web/dist/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
- package/web/dist/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
- package/web/dist/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
- package/web/dist/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
- package/web/dist/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
- package/web/dist/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
- package/web/dist/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
- package/web/dist/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
- package/web/dist/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
- package/web/dist/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
- package/web/dist/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
- package/web/dist/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
- package/web/dist/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
- package/web/dist/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
- package/web/dist/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
- package/web/dist/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
- package/web/dist/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
- package/web/dist/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
- package/web/dist/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
- package/web/dist/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
- package/web/dist/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
- package/web/dist/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
- package/web/dist/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
- package/web/dist/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
- package/web/dist/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
- package/web/dist/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
- package/web/dist/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
- package/web/dist/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
- package/web/dist/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
- package/web/dist/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
- package/web/dist/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
- package/web/dist/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
- package/web/dist/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
- package/web/dist/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
- package/web/dist/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
- package/web/dist/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
- package/web/dist/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
- package/web/dist/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
- package/web/dist/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
- package/web/dist/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
- package/web/dist/assets/SiteWindow-D6eS-2gM.js +18 -0
- package/web/dist/assets/again-D8tfgKKO.webp +0 -0
- package/web/dist/assets/caveat-nd-CP6HlsNg.woff2 +0 -0
- package/web/dist/assets/clock-xJhvfYpS.webp +0 -0
- package/web/dist/assets/film-cut-BBKMwH7q.webp +0 -0
- package/web/dist/assets/film-still-BZ_DL9Tt.webp +0 -0
- package/web/dist/assets/index-C0KUf6Wd.css +1 -0
- package/web/dist/assets/index-Cbl3ATvp.js +2125 -0
- package/web/dist/assets/ink-desk-BRbxeDsR.webp +0 -0
- package/web/dist/assets/ink-night-Bz4BT3XH.webp +0 -0
- package/web/dist/assets/ink-portrait-C0DM4V8Q.webp +0 -0
- package/web/dist/assets/longcang-regular-C0uvTuKa.woff2 +0 -0
- package/web/dist/assets/lxgw-nd-bold-DbRfiTgo.woff2 +0 -0
- package/web/dist/assets/lxgw-nd-regular-CpMw9Ehg.woff2 +0 -0
- package/web/dist/assets/pending-edit-apply-DTjo2geW.js +31 -0
- package/web/dist/assets/question-8H4HSqxh.webp +0 -0
- package/web/dist/assets/reject-BaPJqElj.webp +0 -0
- package/web/dist/assets/rotate-cw-LMT3x1Zj.js +11 -0
- package/web/dist/assets/rp-portrait-CbrGpew2.webp +0 -0
- package/web/dist/assets/rp-street-C4jVKjxx.webp +0 -0
- package/web/dist/assets/square-dashed-mouse-pointer-CBoAkfhi.js +11 -0
- package/web/dist/assets/tangle-DIxHVNuT.webp +0 -0
- package/web/dist/assets/thisone-BylZKglV.webp +0 -0
- package/web/dist/assets/thumb-DO1wfK1I.webp +0 -0
- package/web/dist/index.html +18 -0
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* server/engine/agent/model-table.js — 内置模型表与上游注册表(**只放数据,不放逻辑**)。
|
|
3
|
+
*
|
|
4
|
+
* 08-22 从 model-context.js 拆出来:那边顶在 600 行棘轮上,而本地分发版要在内置行之外合并用户
|
|
5
|
+
* 自己的插槽(runtime/local-config.js)。派生索引、断言、路由查表、picker 闸门全留在 model-context.js,
|
|
6
|
+
* 它 import 这两张表再与外部行合并成 UPSTREAMS / MODELS。改行仍然只改这里;加一家 brand 也在这里。
|
|
7
|
+
*
|
|
8
|
+
* 字段说明见 model-context.js 文件头(两条通路 / spoofing / 记账)。
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* API 上游注册表。keyEnv 是 env 变量名(真钥匙在 .env,不进代码不进 git)。
|
|
13
|
+
* authStyle:'x-api-key'(Anthropic 原生头)| 'bearer'(Authorization: Bearer)。
|
|
14
|
+
* countTokens:上游有没有 /v1/messages/count_tokens。false = 入口直接本地估算;
|
|
15
|
+
* true = 先转发,404 再回退本地(capability 探针缓存见 model-ingress.js)。
|
|
16
|
+
*/
|
|
17
|
+
export const UPSTREAMS_BUILTIN = Object.freeze({
|
|
18
|
+
lament: Object.freeze({
|
|
19
|
+
label: '中转站 api.lament0.link',
|
|
20
|
+
baseUrl: 'https://api.lament0.link',
|
|
21
|
+
keyEnv: 'NODESIGN_UPSTREAM_LAMENT_KEY',
|
|
22
|
+
authStyle: 'x-api-key',
|
|
23
|
+
countTokens: false, // 08-19 探针:404
|
|
24
|
+
}),
|
|
25
|
+
// 本地盒子(featurize 租的 5090 跑 llama-server,SSH 隧道 -L 到本机)。
|
|
26
|
+
// llama.cpp 2025-11-28 起原生带 /v1/messages(含 count_tokens、SSE、tool_use、
|
|
27
|
+
// vision;工具调用要 --jinja)—— 不需要任何协议转换层。authStyle 'none':
|
|
28
|
+
// llama-server 无鉴权,隧道只绑环回。箱子不开机时请求 ECONNREFUSED → 502,
|
|
29
|
+
// fail-loud 语义正确。
|
|
30
|
+
qwenLocal: Object.freeze({
|
|
31
|
+
label: '本地 llama-server(SSH 隧道)',
|
|
32
|
+
baseUrl: process.env.NODESIGN_UPSTREAM_QWEN_LOCAL_URL || 'http://127.0.0.1:8080',
|
|
33
|
+
keyEnv: null,
|
|
34
|
+
authStyle: 'none',
|
|
35
|
+
countTokens: true,
|
|
36
|
+
// ⚠️ llama.cpp 的图片解码走 stb_image,**它不认 webp**。而本站 turn-compose 的
|
|
37
|
+
// 白名单是放 webp 进来的(封面和截图链路正是产 webp)。解不开时 mtmd 会顺序
|
|
38
|
+
// 兜底 image → audio → video,最后那条要 ffprobe,盒上没装,于是上游返回的是
|
|
39
|
+
// 一句看不出真因的 400「Failed to load image or audio file」——
|
|
40
|
+
// 08-19 生产真撞过两次,日志里翻到 mtmd_helper 才定位到。
|
|
41
|
+
//
|
|
42
|
+
// 声明成"这个上游真解得开什么",入口负责把不在表里的转码过去(见
|
|
43
|
+
// model-ingress.normalizeImages)。不填 = 什么都能吃,中转站那两个上游维持原样。
|
|
44
|
+
imageFormats: Object.freeze(['image/png', 'image/jpeg']),
|
|
45
|
+
}),
|
|
46
|
+
// OpenCode Zen(08-21):免费 stealth 模型 Ox Alpha 只有 OpenAI chat 格式能用工具
|
|
47
|
+
// (它的 /v1/messages 桥一带 tools 就 [1210],四种写法探死)。protocol 'openai-chat'
|
|
48
|
+
// 让 ingress 走 lib/ingress/openai-chat.js 的协议转换而不是透传;其余上游没有这个
|
|
49
|
+
// 字段 = 透传 Anthropic。钥匙在 .env(NODESIGN_UPSTREAM_ZEN_KEY)。
|
|
50
|
+
zen: Object.freeze({
|
|
51
|
+
label: 'OpenCode Zen',
|
|
52
|
+
// 覆盖旋钮跟 qwenLocal 同款,**只给探针用**(假上游跑真 ingress+转换层,见 _probe-truncation-e2e.mjs);
|
|
53
|
+
// 生产 .env 里不设 → 真地址。
|
|
54
|
+
baseUrl: process.env.NODESIGN_UPSTREAM_ZEN_URL || 'https://opencode.ai/zen/v1',
|
|
55
|
+
keyEnv: 'NODESIGN_UPSTREAM_ZEN_KEY',
|
|
56
|
+
authStyle: 'bearer',
|
|
57
|
+
protocol: 'openai-chat',
|
|
58
|
+
countTokens: false, // 08-21 探针:404
|
|
59
|
+
}),
|
|
60
|
+
// 08-21 晚:Zen 第二入口 /zen/go(= OpenCode Go 订阅入口)。同钥匙、目录不同(Ox 叫 ox-alpha-free,x-preview-f-free 它回 401);
|
|
61
|
+
// 响应带 `cost`(流式在 [DONE] 之后补 {"choices":[],"cost":"…"})与 cached_tokens → lib/ingress/upstream-billing.js。'zen' 留着可切回
|
|
62
|
+
zenGo: Object.freeze({
|
|
63
|
+
label: 'OpenCode Zen Go',
|
|
64
|
+
baseUrl: process.env.NODESIGN_UPSTREAM_ZEN_GO_URL || 'https://opencode.ai/zen/go/v1', // 探针覆盖,同上
|
|
65
|
+
keyEnv: 'NODESIGN_UPSTREAM_ZEN_KEY',
|
|
66
|
+
authStyle: 'bearer',
|
|
67
|
+
protocol: 'openai-chat',
|
|
68
|
+
countTokens: false,
|
|
69
|
+
}),
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* 模型总表。字段:
|
|
74
|
+
* id appModel —— 全站唯一标识(session-config / NODESIGN_MODEL / 计量落表都用它)
|
|
75
|
+
* window 真实 context window(ContextUsageBar 分母 + hooks 警告分档)
|
|
76
|
+
* select 出现在前端 picker 的 {label, desc};没有 = 不对用户暴露
|
|
77
|
+
* api API 通路配置(没有 = 订阅通路):
|
|
78
|
+
* upstream UPSTREAMS 的 key
|
|
79
|
+
* wireModel 发给上游的真模型名(入口出口替换)
|
|
80
|
+
* sdkAlias 喂 SDK 的 spoof 名(必须是 SDK 认识的 Claude 名;⚠️全表唯一)
|
|
81
|
+
* fastModel 该路的 helper/subagent 模型(必须也是本表可路由的 id;
|
|
82
|
+
* 订阅的 haiku 在 API 模式不可用 —— binary 见 API key 即弃 OAuth,
|
|
83
|
+
* helper 请求同样走唯一的 BASE_URL)
|
|
84
|
+
* thinking 'strip'(出口删 thinking 字段,上游自决)| 'enabled8k'
|
|
85
|
+
* (出口把 adaptive 改写成 enabled+budget 8192,Kimi 实测需要)
|
|
86
|
+
* liftImages tool_result 里的图提升到 user message 顶层(Kimi 与 Gemini 桥
|
|
87
|
+
* 都丢 tool_result 图,08-19 探针实锤 + 修法验证)
|
|
88
|
+
* prices 每 1M token 的 USD {input, output, cacheRead, cacheWrite};
|
|
89
|
+
* 没填 = 沿用 SDK 按 alias 算的虚价(接真流量前先填)
|
|
90
|
+
*/
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* 模型出自谁家 —— 前端据此画身份标(picker 图标 / 画布精灵 / 舞台徽记)。
|
|
94
|
+
*
|
|
95
|
+
* **声明,不推断**:不许前端按 id 前缀猜(`/^claude-/` 那种),下一个模型名一变就全错。
|
|
96
|
+
* 每行必须写 brand,加载时断言(下面的派生循环),拼错当场炸。
|
|
97
|
+
* 新增一家 = 这里加一个名字 + 前端 ui/ModelMark.jsx 加一枚标;两边由
|
|
98
|
+
* web/src/components/ui/ModelMark.lint.test.js 对账(它直接读本文件的 BRANDS)。
|
|
99
|
+
*
|
|
100
|
+
* 口径(08-21 用户拍板):有自己标的用自己的(deepseek 蓝鲸、gemini 星),
|
|
101
|
+
* **隐身/神秘的免费行一律用供应商 OpenCode 的方块标**(Ox 这类不公开身份的模型)。
|
|
102
|
+
*/
|
|
103
|
+
// 'custom':本地分发版用户自己配的插槽(runtime/local-config.js)没填 brand 时的默认牌子,前端用通用标
|
|
104
|
+
export const BRANDS = Object.freeze(['claude', 'deepseek', 'opencode', 'gemini', 'qwen', 'custom']);
|
|
105
|
+
|
|
106
|
+
export const MODELS_BUILTIN = Object.freeze([
|
|
107
|
+
// ── 订阅通路(Claude 真名,零注入)──
|
|
108
|
+
{
|
|
109
|
+
id: 'claude-sonnet-5[1m]', window: 1_000_000, brand: 'claude',
|
|
110
|
+
select: { label: 'Sonnet 5', desc: '快 · 日常改稿和铺页够用', gate: 'subscription' },
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
id: 'claude-opus-5[1m]', window: 1_000_000, brand: 'claude',
|
|
114
|
+
select: { label: 'Opus 5', desc: '前端与审美更强 · 烧订阅额度快得多,重活再开', gate: 'subscription' },
|
|
115
|
+
},
|
|
116
|
+
{ id: 'claude-sonnet-5', window: 200_000, brand: 'claude' },
|
|
117
|
+
{ id: 'claude-opus-5', window: 200_000, brand: 'claude' },
|
|
118
|
+
{ id: 'claude-opus-4-7[1m]', window: 1_000_000, brand: 'claude' },
|
|
119
|
+
{ id: 'claude-sonnet-4-6[1m]', window: 1_000_000, brand: 'claude' },
|
|
120
|
+
{ id: 'claude-opus-4-7', window: 200_000, brand: 'claude' },
|
|
121
|
+
{ id: 'claude-sonnet-4-6', window: 200_000, brand: 'claude' },
|
|
122
|
+
{ id: 'claude-haiku-4-5', window: 200_000, brand: 'claude' },
|
|
123
|
+
// 只当 alias 用的订阅名(08-20):SDK 二进制认识的 1M 名里还空着的一个(strings 扫过:
|
|
124
|
+
// opus-4-6/4-7/4-8/5、sonnet-4-5-20250929/4-6/5 七个 [1m]),给 gemini-3.7-flash 行做 spoof。
|
|
125
|
+
{ id: 'claude-opus-4-6[1m]', window: 1_000_000, brand: 'claude' },
|
|
126
|
+
// 同上,给 ox-alpha 行做 spoof(08-21)
|
|
127
|
+
{ id: 'claude-opus-4-8[1m]', window: 1_000_000, brand: 'claude' },
|
|
128
|
+
// 同上,七个里最后一个空着的,给 ox-alpha-max 行做 spoof(08-21 晚)
|
|
129
|
+
{ id: 'claude-sonnet-4-5-20250929[1m]', window: 1_000_000, brand: 'claude' },
|
|
130
|
+
// alias 池现状(08-21 深夜清槽后):opus-4-6[1m]→gemini-3.7-flash、opus-4-7[1m]→deepseek-v4-flash-vision、opus-4-8[1m]→ox-alpha、
|
|
131
|
+
// opus-5[1m]→qwen、sonnet-4-5-20250929[1m]→ox-alpha-max、haiku-4-5→ox-alpha-helper;**sonnet-4-6[1m] 空着备用**;sonnet-5[1m] 是订阅默认行不许被路由
|
|
132
|
+
|
|
133
|
+
// ── API 通路 ──
|
|
134
|
+
// kimi-k2.6 行与 moonshot 上游 08-21 深夜清掉(用户:「把 kimi 3.1pro 的槽都清理一下」):NoDesk 退役后没走过流量,
|
|
135
|
+
// 它的 alias claude-opus-4-7[1m] 转给 deepseek-v4-flash-vision。'enabled8k' 的 thinking 档逻辑留在 transformForUpstream 里备用。
|
|
136
|
+
// 本地 Qwen(HauhauCS/Qwen3.8-27B-Uncensored-…-Aggressive-MTP-GGUF,底座官方
|
|
137
|
+
// Qwen3.8-27B,有视觉)。⚠️ window 必须跟箱子 llama-server 的 -c 一致:低了
|
|
138
|
+
// 会在 SDK 触发 auto-compact 之前先撞上游 400。262144 = 该模型原生上限
|
|
139
|
+
// (YaRN 可外推到 1M,但那要额外开 rope 参数且短上下文质量有代价,不默认走)。
|
|
140
|
+
// alias 用 1M 档:SDK 按 alias 查 rawMaxTokens,用 200k 名会让 auto-compact 在
|
|
141
|
+
// ~180k 就触发,白扔 80k。⚠️ 这个 alias 同时是线上可选的订阅模型名,安全性靠两点
|
|
142
|
+
// (改动前先确认它们还成立):①订阅会话根本不进 ingress,WIRE_LOOKUP 只服务
|
|
143
|
+
// API 会话;②repriceUsageDeltas 先看会话通路,订阅会话原样早退不 remap。
|
|
144
|
+
{
|
|
145
|
+
// window 必须等于盒上 llama-server 启动日志里的 `n_ctx_slot`(每槽上下文),低了 SDK
|
|
146
|
+
// 在 auto-compact 之前先撞上游 400。08-20 起盒子是 RTX 5090 32G:OrcaRouter Q5_K_M +
|
|
147
|
+
// 视觉 + MTP 投机 + 1 槽 × 131072,再留 ~5G 给同卡的 ComfyUI(noobai)。换回 96G 盒子
|
|
148
|
+
// 就是 262_144 × 3 槽。盒上配置住 ops/qwen-box/(serve-prod.sh),两边要一起改。
|
|
149
|
+
id: 'qwen3.8-27b', window: 131_072, brand: 'qwen',
|
|
150
|
+
// ⏸ **08-20 用户拍板从 picker 摘牌**(盒子按小时租,已关机)。删掉 `select` 一处,
|
|
151
|
+
// 三个消费方一起拒:GET /api/me/models 的清单、PUT /model 的校验、turn.js 的
|
|
152
|
+
// body.model 校验(都走 selectableModelsFor —— 所以摘牌不会留后门)。
|
|
153
|
+
// **线路原样留着**:下面 api 字段一个字没动,WIRE_LOOKUP / resolveSessionWire /
|
|
154
|
+
// 记账 reprice 全照旧;已经钉在 qwen 的老会话仍会路由过去,盒子没开就 502 fail-loud
|
|
155
|
+
// (这是设计,不是 bug)。同理 gemini-3.1-pro 那行也是「留行不留牌」,先例在下面。
|
|
156
|
+
// 复牌 = 把这一行放回来,别的都不用动:
|
|
157
|
+
// select: { label: 'Qwen3.8 27B(本地)', desc: '本地盒子 · 无审查 · 盒子没开时不可用', gate: 'localGen' },
|
|
158
|
+
// ⚠️ 复牌时别丢 `gate: 'localGen'` —— 跟 roll_film / paint_still 同一套批准制
|
|
159
|
+
// (admin 免批),它本来就跑在同一台本地盒子上,语义天然一致;没这个闸就是对
|
|
160
|
+
// 所有账号露出一个「一按就 502」的按钮。
|
|
161
|
+
// 无审查权重跑在自己租的盒子上(不出网、零成本、只对获批账号开)。这条路上
|
|
162
|
+
// prelude 的整节「底线」不注入 —— 站主 08-19 拍板,理由是那节是**平台对外
|
|
163
|
+
// 开放**才需要的产物政策(产物能一键挂到站主域名下),而这台盒子上跑的是
|
|
164
|
+
// 个人写作/角色扮演,那节只会让模型对正常输入畏手畏脚。
|
|
165
|
+
//
|
|
166
|
+
// 标记位住在表里而不是写成 `if (model === 'qwen3.8-27b')`:它是**模型属性**,
|
|
167
|
+
// 跟 gate / prices 同级。散在 session-loop 里就是给这张表开第二个真相源,
|
|
168
|
+
// 这个仓库为「同一件东西有多个实例」付过最贵的学费。以后再接一个无审查模型
|
|
169
|
+
// 只加这一个字段,一行逻辑都不用动。
|
|
170
|
+
uncensored: true,
|
|
171
|
+
// ⭐ **盒上 llama-server 的 `-np`(slot 数)应当等于 `NODESIGN_MAX_CONCURRENT_RUNS`。**
|
|
172
|
+
// slot 比闸多 → 白占显存(每路一份满窗 KV)
|
|
173
|
+
// slot 比闸少 → 请求在 llama-server 里排队,而 Nodesign 以为自己还有余量,
|
|
174
|
+
// 用户看到的是无解释的慢,不是「现在有点挤」那句诚实的 BUSY
|
|
175
|
+
// 08-19 的 96G 盒子两边都是 3(巧合不是设计);**08-20 起的 5090 32G 盒子是 `-np 1`
|
|
176
|
+
// 而闸仍是 3 —— 已知走偏**,出路是按模型给 maxConcurrent(⏸ 未拍板),在那之前
|
|
177
|
+
// 第 2 个 qwen 请求就是在盒上排队。盒上脚本在 ops/qwen-box/(serve.sh=96G,
|
|
178
|
+
// serve-prod.sh=5090),改任何一边都要改另一边;这条契约没法用 lint 拦 ——
|
|
179
|
+
// `server/lib/_ingress-check.mjs` 第 6 项会真查 /slots 比对,换机后跑一次。
|
|
180
|
+
api: {
|
|
181
|
+
upstream: 'qwenLocal', wireModel: 'qwen3.8-27b',
|
|
182
|
+
sdkAlias: 'claude-opus-5[1m]',
|
|
183
|
+
fastModel: 'qwen3.8-27b',
|
|
184
|
+
thinking: 'enabled8k',
|
|
185
|
+
// ⭐ 08-19 盒上体检 9/9:llama.cpp 的 /v1/messages **原生直通 tool_result 图片**
|
|
186
|
+
// (中转站 Gemini 桥正是死在这一项)。原样直通比提升到顶层更忠实,故关掉 lift。
|
|
187
|
+
liftImages: false,
|
|
188
|
+
prices: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, // 本地盒子按租金付费,token 记 0(不然按 opus-5 虚价记账)
|
|
189
|
+
},
|
|
190
|
+
},
|
|
191
|
+
// gemini-3.1-pro 行(中转-gemini-3.1-pro-preview,alias claude-sonnet-4-6[1m])08-21 深夜清掉:退了 picker 后只做体检对照,
|
|
192
|
+
// 对照改用 3.7 Flash 行;sonnet-4-6[1m] 这个 alias 名腾出来备用。中转站 thinking 参数零效果的结论见 08-20 记录。
|
|
193
|
+
{
|
|
194
|
+
id: 'gemini-3.7-flash', window: 1_000_000, brand: 'gemini',
|
|
195
|
+
// 08-20 用户拍板:要 3.7 Flash,先用中转站 + lift shim 顶着。它只在中转站的「反重力-」
|
|
196
|
+
// 通道上有(转卖 Antigravity OAuth 额度),今天体检 6/9:文本/视觉/非流式 tool_use/
|
|
197
|
+
// prompt cache 真命中(cache_read 8162)都好;流式 stop_reason 恒=end_turn(假上游实验证明
|
|
198
|
+
// CLI 认块不认 stop_reason,无功能后果);tool_result 图丢靠 liftImages 修。⛔硬伤是
|
|
199
|
+
// 「当前无可用凭证」500 说来就来、不分请求大小、一来就是整段时间 —— 所以同 qwen 走
|
|
200
|
+
// localGen 闸,label 写明不稳定,只给自己人。思考档在模型名里(-high/-medium/-low),
|
|
201
|
+
// 选 high 即"默认高";thinking 参数照旧 strip。
|
|
202
|
+
select: { label: 'Gemini 3.7 Flash(中转)', desc: '反重力通道 · 随时可能 500 · 思考档 high', gate: 'localGen' },
|
|
203
|
+
api: {
|
|
204
|
+
upstream: 'lament', wireModel: '反重力-流式抗截断/gemini-3.7-flash-high',
|
|
205
|
+
sdkAlias: 'claude-opus-4-6[1m]', // 3.7 Flash 真 1M 窗口,alias 诚实;见上面那行订阅名的注释
|
|
206
|
+
fastModel: 'gemini-3.7-flash',
|
|
207
|
+
thinking: 'strip',
|
|
208
|
+
liftImages: true,
|
|
209
|
+
// 官方促销价(2027-01-01 起翻倍 $1.5/$7.5);缓存命中按输入价一折。中转站计量单位不明,
|
|
210
|
+
// 这里的 USD 仍是配额/展示用的近似。
|
|
211
|
+
prices: { input: 0.75, output: 3.75, cacheRead: 0.075, cacheWrite: 0 },
|
|
212
|
+
},
|
|
213
|
+
},
|
|
214
|
+
// ── OpenCode Go · DeepSeek V4 Flash Vision Exp(08-21 深夜,第一条付费行)── /zen/go = OpenCode Go 订阅($10/月换 $12/5h·$30/周·$60/月):
|
|
215
|
+
// 额度内上游 cost 报 0、余额不扣 → 记账按**表价**(高峰价;北京 09-12/14-18 是高峰)让每用户日限跟 Go 池子一起受控,cost>0 以上游为准
|
|
216
|
+
// (context.applyUpstreamBilling)。探针:文本/图(webp)/工具/流式全通,首字 ~450ms,reasoning_effort 收;DeepSeek ZDR。先 gate localGen 试跑,过关改 'subscription'
|
|
217
|
+
{
|
|
218
|
+
// 真窗口 1M;用户 08-21 深夜拍板压缩窗口 272k(省钱:携带成本 ≈ 1M 的 1/4、缓存失手最坏 $0.12/轮;近 14 天 649 回合只压缩过 11 次)
|
|
219
|
+
id: 'deepseek-v4-flash-vision', window: 272_000, brand: 'deepseek',
|
|
220
|
+
// 08-21 深夜开闸给所有档(含 basic):basic 的 $5/天日限 + 表价记账管着它;pro/admin 不限
|
|
221
|
+
select: { label: 'DeepSeek V4 Flash · 视觉', desc: '快 · 有视觉 · 272k 上下文 · 按用量计入每日额度(高峰 $0.44/$1.32 缓存 $0.014)' },
|
|
222
|
+
api: {
|
|
223
|
+
upstream: 'zenGo', wireModel: 'deepseek-v4-flash-vision-exp',
|
|
224
|
+
sdkAlias: 'claude-opus-4-7[1m]', // kimi 退役腾出来的 1M 名;窗口由 CLAUDE_CODE_AUTO_COMPACT_WINDOW=272k 钉住
|
|
225
|
+
fastModel: 'ox-alpha-helper', // 一句话的活仍走免费 Ox helper
|
|
226
|
+
thinking: 'strip',
|
|
227
|
+
reasoningEffort: 'high',
|
|
228
|
+
maxOutput: 128_000,
|
|
229
|
+
prices: { input: 0.44, output: 1.32, cacheRead: 0.014, cacheWrite: 0 },
|
|
230
|
+
},
|
|
231
|
+
},
|
|
232
|
+
// ── OpenCode Zen · Ox Alpha(08-21,用户称「大事」的第一块)──
|
|
233
|
+
// 真 id x-preview-f-free(models.dev name "Ox Alpha Free";/models 列表里没有带 ox 的名,别按名猜)。
|
|
234
|
+
// 1M ctx / 131k out / 图+视频 / 工具 / reasoning effort low|high|max / 价 0;官方「free for
|
|
235
|
+
// the next week」(08-20 公告)+ zero-retention 不训练。大概率 GLM 系 stealth(错误码体系 +
|
|
236
|
+
// 社区指纹)。⚠️ 一周后要么变付费 GLM 要么下架 —— 这行是插件,闸和转换层才是耐久资产。
|
|
237
|
+
// 上线顺序:先 gate localGen 给 admin 试跑真任务,过关再开闸并设为全员默认。
|
|
238
|
+
{
|
|
239
|
+
id: 'ox-alpha', window: 1_000_000, brand: 'opencode',
|
|
240
|
+
// 08-21 经营态拍板:全员默认模型(default: true),公开注册号只能用它这类免费行。
|
|
241
|
+
select: { label: 'Ox Alpha(免费)', desc: '限时免费 · 1M 上下文 · 有视觉 · 人人可用 · 思考档 high', default: true },
|
|
242
|
+
api: {
|
|
243
|
+
upstream: 'zenGo', wireModel: 'ox-alpha-free', // 08-21 晚切 /zen/go 入口(主入口名 x-preview-f-free,upstream 'zen')
|
|
244
|
+
emptyRetries: 6, retryBudgetMs: 360_000, // 就地重发放宽,理由见 resolveWireModel 的 emptyRetries 注释
|
|
245
|
+
sdkAlias: 'claude-opus-4-8[1m]',
|
|
246
|
+
fastModel: 'ox-alpha-helper', // helper 走独立行才分得出 role(会话 env SMALL_FAST_MODEL 发的是 app id)
|
|
247
|
+
thinking: 'strip', // 出口不带 Anthropic thinking 字段;转换层按 reasoningEffort 发 reasoning_effort
|
|
248
|
+
// Ox 三档 low|high|max。08-21 小题实测 reasoning_tokens:不传≈27、low=0、high=3、max=27;
|
|
249
|
+
// 但上生产后 'max' 在真会话里想了 28,930 字 / 4 分 20 秒才出第一个字(用户看到的是
|
|
250
|
+
// "只有绿点没有回复")。改 'high':还想,但不把一轮耗在想上
|
|
251
|
+
reasoningEffort: 'high',
|
|
252
|
+
maxOutput: 131_072,
|
|
253
|
+
// 不设 liftImages:openai-chat 转换层本身就把 tool_result 里的图搬进随后的 user 消息
|
|
254
|
+
// (OpenAI 的 tool 角色消息装不下图,上游放了会挂死 120s)。同一件事只留一条路。
|
|
255
|
+
prices: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
256
|
+
},
|
|
257
|
+
},
|
|
258
|
+
{
|
|
259
|
+
// 同一个 Ox,思考档 max:真会话里 max 想过 28,930 字 / 4 分 20 秒才出首字,所以不做默认、
|
|
260
|
+
// 单独一行给愿意等的人。两行 protocol 同为 openai-chat,会话中途互切不触发 LANE_SWITCH
|
|
261
|
+
id: 'ox-alpha-max', window: 1_000_000, brand: 'opencode',
|
|
262
|
+
select: { label: 'Ox Alpha · 深想(免费)', desc: '同一个 Ox · 思考档 max · 想得久,首字可能等几分钟 · 重活再开' },
|
|
263
|
+
api: {
|
|
264
|
+
upstream: 'zenGo', wireModel: 'ox-alpha-free', // 08-21 晚切 /zen/go 入口(主入口名 x-preview-f-free,upstream 'zen')
|
|
265
|
+
emptyRetries: 6, retryBudgetMs: 360_000, // 就地重发放宽,理由见 resolveWireModel 的 emptyRetries 注释
|
|
266
|
+
sdkAlias: 'claude-sonnet-4-5-20250929[1m]',
|
|
267
|
+
fastModel: 'ox-alpha-helper', // helper 一句话的活用 low 档那行,不跟着深想
|
|
268
|
+
thinking: 'strip',
|
|
269
|
+
reasoningEffort: 'max',
|
|
270
|
+
maxOutput: 131_072,
|
|
271
|
+
prices: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
272
|
+
},
|
|
273
|
+
},
|
|
274
|
+
{
|
|
275
|
+
// Ox 的 helper 行(08-21 晚):不进 picker(无 select),只做两个 Ox 主行的 fastModel。
|
|
276
|
+
// 为什么要单独一行:session-loop 给 CLI 的 ANTHROPIC_SMALL_FAST_MODEL 是 app id,
|
|
277
|
+
// ox-alpha 主行自己当 fast 时 helper 请求和主请求同名,ingress 分不出 role、helper
|
|
278
|
+
// 也跟着 high 想。独立行 + alias haiku(表内空着的订阅名,helper 不需要 1M 窗)。
|
|
279
|
+
id: 'ox-alpha-helper', window: 1_000_000, brand: 'opencode',
|
|
280
|
+
api: {
|
|
281
|
+
upstream: 'zenGo', wireModel: 'ox-alpha-free', // 08-21 晚切 /zen/go 入口(主入口名 x-preview-f-free,upstream 'zen')
|
|
282
|
+
// helper 不放宽重发(走全局默认 2 次):它就是标题/分类器一句话的活,
|
|
283
|
+
// 接不上无所谓,多打几发只是白占上游并发。
|
|
284
|
+
sdkAlias: 'claude-haiku-4-5',
|
|
285
|
+
fastModel: 'ox-alpha-helper',
|
|
286
|
+
thinking: 'strip',
|
|
287
|
+
reasoningEffort: 'low',
|
|
288
|
+
maxOutput: 131_072,
|
|
289
|
+
prices: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
290
|
+
},
|
|
291
|
+
},
|
|
292
|
+
]);
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* server/engine/agent/plugin-loader.js — 已装 plugin 扫描 + 合并
|
|
3
|
+
*
|
|
4
|
+
* session-loop 启动时调用,扫三个来源的 plugin,合并成 SDK options 直接吃的形态:
|
|
5
|
+
*
|
|
6
|
+
* 1. **内置**:server/engine/plugins/nodesign/(PLUGIN_ROOT,恒存在)
|
|
7
|
+
* 2. **用户级**:<userHome>/.nodesign/plugins/<plugin>/(用户从 /skills 页面装)
|
|
8
|
+
* 3. **project 级**:<projects-data>/<pid>/shared/.claude/plugins/<plugin>/(从 SystemTab 装)
|
|
9
|
+
*
|
|
10
|
+
* 返回的形态对接 SDK:
|
|
11
|
+
* { plugins: [{ type: 'local', path }, ...], // 每个 plugin 一项
|
|
12
|
+
* skills: [skillName1, skillName2, ...] } // 所有 plugin 内 SKILL.md frontmatter.name 合集
|
|
13
|
+
*
|
|
14
|
+
* 现状:plugin discovery 是 startup-time,不支持 hot-reload。装新 plugin 后必须重启 session 才生效。
|
|
15
|
+
* 详见 plan 文件 § "Hot-reload v2"。
|
|
16
|
+
*
|
|
17
|
+
* 容错原则:
|
|
18
|
+
* - 单 plugin 不合规(缺 plugin.json / SKILL.md / frontmatter.name 等)→ 跳过该 plugin,
|
|
19
|
+
* warn 日志,**不影响其他 plugin 加载**
|
|
20
|
+
* - 三个 root 缺失(用户首次跑没装过任何用户级 plugin)→ 返空数组不报错
|
|
21
|
+
*
|
|
22
|
+
* 注意:本模块**只做发现**,不做格式深度校验。深度校验在 plugin-validator.js(上传时)。
|
|
23
|
+
* 这里假设已装的 plugin 是合规的(validator 通过才能装到目标位置)。
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
import { promises as fs } from 'node:fs';
|
|
27
|
+
import path from 'node:path';
|
|
28
|
+
import os from 'node:os';
|
|
29
|
+
|
|
30
|
+
import { PLUGIN_ROOT, parseFrontmatter } from './skill.js';
|
|
31
|
+
import { getSharedDir } from '../../projects/workspace.js';
|
|
32
|
+
|
|
33
|
+
/** 用户级 plugin 总根:~/.nodesign/plugins/。env override 给测试用 */
|
|
34
|
+
export function getUserPluginsBaseRoot() {
|
|
35
|
+
return process.env.NODESIGN_USER_PLUGINS_DIR
|
|
36
|
+
|| path.join(os.homedir(), '.nodesign', 'plugins');
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** 用户 id 只该是 users 表那种 `u_xxx`(登录墙关时是 `_anon`);别的一律不当目录名 */
|
|
40
|
+
const USER_DIR_RE = /^[A-Za-z0-9_-]{1,64}$/;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* 某个用户的 plugin 根:~/.nodesign/plugins/<userId>/
|
|
44
|
+
*
|
|
45
|
+
* 2026-07-30 分用户:原来所有人共用总根,任何登录用户装的 plugin 会加载进**每个人**
|
|
46
|
+
* 的 agent 会话(loader 对所有 project 都扫这个根),也能删掉别人的。project 级
|
|
47
|
+
* 早就按 owner 隔离了,用户级是内测隔离唯一漏网的一处。
|
|
48
|
+
*
|
|
49
|
+
* userId 缺失/不合法 → 返 null(调用方按"没有用户级 plugin"处理),不退回总根:
|
|
50
|
+
* 退回去就等于把漏洞留成 fallback。
|
|
51
|
+
*/
|
|
52
|
+
export function getUserPluginsRoot(userId) {
|
|
53
|
+
if (!userId || !USER_DIR_RE.test(String(userId))) return null;
|
|
54
|
+
return path.join(getUserPluginsBaseRoot(), String(userId));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** project 级 plugin 根:<shared>/.claude/plugins/ */
|
|
58
|
+
export function getProjectPluginsRoot(projectId) {
|
|
59
|
+
if (!projectId) return null;
|
|
60
|
+
return path.join(getSharedDir(projectId), '.claude', 'plugins');
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** 内置 plugin 根(PLUGIN_ROOT 的父目录,包含 nodesign) */
|
|
64
|
+
export function getBuiltinPluginsRoot() {
|
|
65
|
+
return path.dirname(PLUGIN_ROOT);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* 列单个 plugin root 下所有 plugin 目录,返带 manifest + skills 详情的列表。
|
|
70
|
+
*
|
|
71
|
+
* 跟 `scanPluginRoot`(内部用)的区别:这个 export 给 API / UI 用,返 manifest 完整字段
|
|
72
|
+
* + 每个 skill 的 id/name/version/description;scanPluginRoot 只返 SDK options 需要的
|
|
73
|
+
* skill name 字符串数组。
|
|
74
|
+
*
|
|
75
|
+
* @param {string} rootDir
|
|
76
|
+
* @returns {Promise<Array<{
|
|
77
|
+
* name, version, description, path,
|
|
78
|
+
* skills: Array<{id, name, version, description}>
|
|
79
|
+
* }>>}
|
|
80
|
+
*/
|
|
81
|
+
export async function listInstalledPluginsDetailed(rootDir) {
|
|
82
|
+
let entries;
|
|
83
|
+
try {
|
|
84
|
+
entries = await fs.readdir(rootDir, { withFileTypes: true });
|
|
85
|
+
} catch (err) {
|
|
86
|
+
if (err.code === 'ENOENT') return [];
|
|
87
|
+
throw err;
|
|
88
|
+
}
|
|
89
|
+
const out = [];
|
|
90
|
+
for (const entry of entries) {
|
|
91
|
+
if (!entry.isDirectory()) continue;
|
|
92
|
+
if (entry.name === '.staging') continue;
|
|
93
|
+
const pluginDir = path.join(rootDir, entry.name);
|
|
94
|
+
const manifestPath = path.join(pluginDir, '.claude-plugin', 'plugin.json');
|
|
95
|
+
let manifest;
|
|
96
|
+
try {
|
|
97
|
+
const raw = await fs.readFile(manifestPath, 'utf8');
|
|
98
|
+
manifest = JSON.parse(raw);
|
|
99
|
+
} catch { continue; }
|
|
100
|
+
if (!manifest?.name) continue;
|
|
101
|
+
|
|
102
|
+
const skillsDir = path.join(pluginDir, 'skills');
|
|
103
|
+
const skills = [];
|
|
104
|
+
let skillEntries;
|
|
105
|
+
try {
|
|
106
|
+
skillEntries = await fs.readdir(skillsDir, { withFileTypes: true });
|
|
107
|
+
} catch { skillEntries = []; }
|
|
108
|
+
for (const sk of skillEntries) {
|
|
109
|
+
if (!sk.isDirectory()) continue;
|
|
110
|
+
const skillFile = path.join(skillsDir, sk.name, 'SKILL.md');
|
|
111
|
+
try {
|
|
112
|
+
const raw = await fs.readFile(skillFile, 'utf8');
|
|
113
|
+
const { frontmatter } = parseFrontmatter(raw);
|
|
114
|
+
skills.push({
|
|
115
|
+
id: sk.name,
|
|
116
|
+
name: frontmatter.name || sk.name,
|
|
117
|
+
version: frontmatter.version || '0.0.0',
|
|
118
|
+
description: frontmatter.description || '',
|
|
119
|
+
});
|
|
120
|
+
} catch { /* skip broken */ }
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
out.push({
|
|
124
|
+
name: manifest.name,
|
|
125
|
+
version: manifest.version || '0.0.0',
|
|
126
|
+
description: manifest.description || '',
|
|
127
|
+
path: pluginDir,
|
|
128
|
+
skills,
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
return out;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* 扫单个 plugin root 下所有 plugin 目录,返回每个 plugin 的 {path, skills}
|
|
136
|
+
*
|
|
137
|
+
* @param {string} rootDir
|
|
138
|
+
* @param {string} sourceLabel - 'builtin' | 'user' | 'project',仅用于日志
|
|
139
|
+
* @returns {Promise<Array<{ path: string, name: string, skills: string[] }>>}
|
|
140
|
+
*/
|
|
141
|
+
async function scanPluginRoot(rootDir, sourceLabel) {
|
|
142
|
+
let entries;
|
|
143
|
+
try {
|
|
144
|
+
entries = await fs.readdir(rootDir, { withFileTypes: true });
|
|
145
|
+
} catch (err) {
|
|
146
|
+
if (err.code === 'ENOENT') return [];
|
|
147
|
+
console.warn(`[plugin-loader] scan ${sourceLabel} root failed (${err.code}):`, err.message);
|
|
148
|
+
return [];
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const results = [];
|
|
152
|
+
for (const entry of entries) {
|
|
153
|
+
if (!entry.isDirectory()) continue;
|
|
154
|
+
const pluginDir = path.join(rootDir, entry.name);
|
|
155
|
+
const manifestPath = path.join(pluginDir, '.claude-plugin', 'plugin.json');
|
|
156
|
+
|
|
157
|
+
let manifest;
|
|
158
|
+
try {
|
|
159
|
+
const raw = await fs.readFile(manifestPath, 'utf8');
|
|
160
|
+
manifest = JSON.parse(raw);
|
|
161
|
+
} catch (err) {
|
|
162
|
+
// ENOENT = 不是 plugin 目录(也许是其他随机文件夹),静默跳
|
|
163
|
+
if (err.code !== 'ENOENT') {
|
|
164
|
+
console.warn(`[plugin-loader] ${sourceLabel}/${entry.name} manifest 不合规,跳过:${err.message}`);
|
|
165
|
+
}
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (!manifest?.name) {
|
|
170
|
+
console.warn(`[plugin-loader] ${sourceLabel}/${entry.name} plugin.json 缺 name,跳过`);
|
|
171
|
+
continue;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// 扫该 plugin 内所有 skills/<id>/SKILL.md,取 frontmatter.name 作为 SDK skill name
|
|
175
|
+
const skillsDir = path.join(pluginDir, 'skills');
|
|
176
|
+
const skillNames = [];
|
|
177
|
+
let skillEntries;
|
|
178
|
+
try {
|
|
179
|
+
skillEntries = await fs.readdir(skillsDir, { withFileTypes: true });
|
|
180
|
+
} catch (err) {
|
|
181
|
+
if (err.code !== 'ENOENT') {
|
|
182
|
+
console.warn(`[plugin-loader] ${manifest.name} skills/ 读取失败:${err.message}`);
|
|
183
|
+
}
|
|
184
|
+
// 没 skills/ 子目录也允许(SDK 可能有别的 plugin 组件,未来扩展),不算 error
|
|
185
|
+
results.push({ path: pluginDir, name: manifest.name, skills: [] });
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
for (const sk of skillEntries) {
|
|
190
|
+
if (!sk.isDirectory()) continue;
|
|
191
|
+
const skillFile = path.join(skillsDir, sk.name, 'SKILL.md');
|
|
192
|
+
try {
|
|
193
|
+
const raw = await fs.readFile(skillFile, 'utf8');
|
|
194
|
+
const { frontmatter } = parseFrontmatter(raw);
|
|
195
|
+
if (frontmatter?.name) {
|
|
196
|
+
skillNames.push(frontmatter.name);
|
|
197
|
+
} else {
|
|
198
|
+
console.warn(`[plugin-loader] ${manifest.name}/${sk.name} SKILL.md 缺 frontmatter.name,跳过`);
|
|
199
|
+
}
|
|
200
|
+
} catch (err) {
|
|
201
|
+
if (err.code !== 'ENOENT') {
|
|
202
|
+
console.warn(`[plugin-loader] ${manifest.name}/${sk.name}/SKILL.md 读取失败:${err.message}`);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
results.push({ path: pluginDir, name: manifest.name, skills: skillNames });
|
|
208
|
+
}
|
|
209
|
+
return results;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* 加载所有已装 plugin(内置 + 用户级 + project 级),返回 SDK options 形态。
|
|
214
|
+
*
|
|
215
|
+
* @param {object} opts
|
|
216
|
+
* @param {string} [opts.projectId] - 不传则跳过 project 级扫描
|
|
217
|
+
* @param {string} [opts.userId] - 项目 owner 的用户 id;不传则跳过用户级扫描
|
|
218
|
+
* (不是"退回全局共享根"——那正是要修掉的东西)
|
|
219
|
+
* @returns {Promise<{
|
|
220
|
+
* plugins: Array<{ type: 'local', path: string }>,
|
|
221
|
+
* skills: string[],
|
|
222
|
+
* diagnostics: { builtin: number, user: number, project: number }
|
|
223
|
+
* }>}
|
|
224
|
+
*/
|
|
225
|
+
export async function loadInstalledPlugins({ projectId, userId } = {}) {
|
|
226
|
+
const userRoot = getUserPluginsRoot(userId);
|
|
227
|
+
// 三 root 并行扫
|
|
228
|
+
const [builtin, user, projectLocal] = await Promise.all([
|
|
229
|
+
scanPluginRoot(path.dirname(PLUGIN_ROOT), 'builtin')
|
|
230
|
+
// builtin root = `server/engine/plugins/`(PLUGIN_ROOT 的父目录),里面只该有 nodesign
|
|
231
|
+
// 但为了将来支持系统自带多个 plugin,统一扫
|
|
232
|
+
.then(items => items.filter(p => p.path === PLUGIN_ROOT)),
|
|
233
|
+
userRoot ? scanPluginRoot(userRoot, 'user') : Promise.resolve([]),
|
|
234
|
+
projectId
|
|
235
|
+
? scanPluginRoot(getProjectPluginsRoot(projectId), 'project')
|
|
236
|
+
: Promise.resolve([]),
|
|
237
|
+
]);
|
|
238
|
+
|
|
239
|
+
// 合并 + 去重(按 plugin name)—— 用户级或 project 级如果撞内置 name,跳过后者(内置优先)
|
|
240
|
+
const seenNames = new Set();
|
|
241
|
+
const plugins = [];
|
|
242
|
+
const skills = [];
|
|
243
|
+
|
|
244
|
+
for (const p of [...builtin, ...user, ...projectLocal]) {
|
|
245
|
+
if (seenNames.has(p.name)) {
|
|
246
|
+
console.warn(`[plugin-loader] plugin name \`${p.name}\` 重复(来源冲突),保留先发现的,跳后续`);
|
|
247
|
+
continue;
|
|
248
|
+
}
|
|
249
|
+
seenNames.add(p.name);
|
|
250
|
+
plugins.push({ type: 'local', path: p.path });
|
|
251
|
+
for (const skillName of p.skills) {
|
|
252
|
+
// SDK skills 列表也去重(两个 plugin 同 skill name 取先发现的)
|
|
253
|
+
if (!skills.includes(skillName)) skills.push(skillName);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
return {
|
|
258
|
+
plugins,
|
|
259
|
+
skills,
|
|
260
|
+
diagnostics: {
|
|
261
|
+
builtin: builtin.length,
|
|
262
|
+
user: user.length,
|
|
263
|
+
project: projectLocal.length,
|
|
264
|
+
},
|
|
265
|
+
};
|
|
266
|
+
}
|