@joekytc/dsh-swarm 0.1.2 → 0.3.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 +177 -140
- package/README.zh-CN.md +173 -126
- package/client/BoardCard.tsx +24 -2
- package/client/ConfigSection.tsx +162 -0
- package/client/ConfigSelect.tsx +71 -0
- package/client/KanbanBoard.tsx +3 -0
- package/client/KanbanTab.tsx +4 -3
- package/client/TaskDrawer.tsx +4 -26
- package/client/WorkflowRail.tsx +3 -1
- package/client/config-store.ts +92 -0
- package/client/config.css +110 -0
- package/client/index.ts +39 -4
- package/client/kanban.css +88 -2
- package/client/session-bridge.ts +39 -0
- package/client/timeline-model.ts +12 -1
- package/client/workflow-model.ts +3 -1
- package/lib/client.js +519 -56
- package/lib/config.d.ts +26 -2
- package/lib/config.js +20 -1
- package/lib/dispatcher/agent-runner.d.ts +37 -7
- package/lib/dispatcher/agent-runner.js +239 -86
- package/lib/dispatcher/chain-auditor.d.ts +4 -4
- package/lib/dispatcher/chain-auditor.js +14 -9
- package/lib/dispatcher/dispatcher.d.ts +69 -10
- package/lib/dispatcher/dispatcher.js +281 -42
- package/lib/dispatcher/event-waker.d.ts +1 -1
- package/lib/dispatcher/event-waker.js +2 -2
- package/lib/dispatcher/git-credentials.d.ts +2 -2
- package/lib/dispatcher/git-credentials.js +2 -2
- package/lib/dispatcher/model-candidates.d.ts +1 -1
- package/lib/dispatcher/model-candidates.js +1 -1
- package/lib/dispatcher/session-events.d.ts +12 -16
- package/lib/dispatcher/session-events.js +18 -6
- package/lib/dispatcher/target-repo.d.ts +2 -2
- package/lib/dispatcher/target-repo.js +3 -3
- package/lib/dispatcher/v-orchestrator.d.ts +44 -11
- package/lib/dispatcher/v-orchestrator.js +257 -49
- package/lib/dispatcher/watchdog.d.ts +1 -1
- package/lib/dispatcher/watchdog.js +2 -2
- package/lib/domain/config-override.d.ts +52 -0
- package/lib/domain/config-override.js +138 -0
- package/lib/domain/delivery-contract.d.ts +4 -3
- package/lib/domain/delivery-contract.js +30 -18
- package/lib/domain/delivery-evidence.d.ts +1 -1
- package/lib/domain/delivery-evidence.js +1 -1
- package/lib/domain/event-store.js +1 -1
- package/lib/domain/gate-policy.d.ts +26 -0
- package/lib/domain/gate-policy.js +44 -0
- package/lib/domain/im-message.d.ts +15 -0
- package/lib/domain/im-message.js +149 -0
- package/lib/domain/kanban-service.d.ts +28 -12
- package/lib/domain/kanban-service.js +73 -30
- package/lib/domain/memory.js +1 -1
- package/lib/domain/ocr-review.d.ts +47 -0
- package/lib/domain/ocr-review.js +105 -0
- package/lib/domain/permissions.js +6 -6
- package/lib/domain/planning-checklist.d.ts +5 -0
- package/lib/domain/planning-checklist.js +80 -6
- package/lib/domain/projection.js +8 -7
- package/lib/domain/review-evidence.js +1 -1
- package/lib/domain/state-machine.js +3 -2
- package/lib/domain/task-parents.js +1 -1
- package/lib/domain/types.d.ts +5 -5
- package/lib/index.js +28 -25
- package/lib/roles/clean-fs-tools.d.ts +22 -0
- package/lib/roles/clean-fs-tools.js +117 -0
- package/lib/roles/preset-installer.js +3 -3
- package/lib/roles/skill-installer.d.ts +6 -0
- package/lib/roles/skill-installer.js +32 -0
- package/lib/roles/toolsets.d.ts +71 -15
- package/lib/roles/toolsets.js +418 -68
- package/lib/roles/wiki-worker.d.ts +1 -0
- package/lib/roles/wiki-worker.js +12 -4
- package/lib/routes/kanban-http.d.ts +28 -2
- package/lib/routes/kanban-http.js +199 -6
- package/lib/routes/kanban-sse.d.ts +1 -1
- package/lib/routes/kanban-sse.js +1 -1
- package/lib/routes/planning-driver.d.ts +6 -2
- package/lib/routes/planning-driver.js +15 -7
- package/lib/routes/prefix-router.d.ts +19 -3
- package/lib/routes/prefix-router.js +40 -3
- package/lib/services/config-provider.d.ts +38 -0
- package/lib/services/config-provider.js +92 -0
- package/lib/services/gate-runner.d.ts +24 -0
- package/lib/services/gate-runner.js +87 -0
- package/lib/services/im-delivery.d.ts +94 -0
- package/lib/services/im-delivery.js +263 -0
- package/lib/services/kanban-provider.d.ts +6 -2
- package/lib/services/kanban-provider.js +41 -3
- package/lib/services/llm-catalog.d.ts +35 -0
- package/lib/services/llm-catalog.js +19 -0
- package/lib/services/ocr-cli.d.ts +35 -0
- package/lib/services/ocr-cli.js +128 -0
- package/lib/tools/kanban-tools.d.ts +2 -2
- package/lib/tools/kanban-tools.js +2 -1
- package/lib/tools/main-session-tools.d.ts +22 -3
- package/lib/tools/main-session-tools.js +135 -30
- package/lib/tools/ocr-review-tools.d.ts +11 -0
- package/lib/tools/ocr-review-tools.js +63 -0
- package/lib/tools/planning-tools.d.ts +8 -1
- package/lib/tools/planning-tools.js +44 -15
- package/lib/tools/prefetch-tools.js +1 -0
- package/lib/tools/spec-card-tools.js +1 -0
- package/lib/tools/wiki-tools.js +6 -5
- package/lib/wiki/kb-linkage.d.ts +9 -2
- package/lib/wiki/kb-linkage.js +3 -3
- package/lib/wiki/local-kb-client.d.ts +14 -0
- package/lib/wiki/local-kb-client.js +101 -0
- package/lib/wiki/local-kb.d.ts +6 -0
- package/lib/wiki/local-kb.js +25 -0
- package/lib/wiki/memory-recall.d.ts +14 -6
- package/lib/wiki/memory-recall.js +17 -13
- package/lib/wiki/page-path.d.ts +9 -3
- package/lib/wiki/page-path.js +33 -12
- package/lib/wiki/wiki-vault-client.d.ts +3 -3
- package/lib/wiki/wiki-vault-client.js +6 -6
- package/package.json +16 -11
- package/personas/kanban-d/agent.cordis.yml +5 -5
- package/personas/kanban-d/preset.yml +1 -1
- package/personas/kanban-dt/agent.cordis.yml +25 -7
- package/personas/kanban-dt/preset.yml +1 -1
- package/personas/kanban-p/agent.cordis.yml +19 -3
- package/personas/kanban-p/preset.yml +1 -1
- package/personas/kanban-pt/agent.cordis.yml +39 -9
- package/personas/kanban-pt/preset.yml +1 -1
- package/personas/kanban-v/agent.cordis.yml +3 -3
- package/personas/kanban-w/agent.cordis.yml +37 -18
- package/personas/kanban-w/preset.yml +1 -1
- package/personas/persona-d.md +1 -1
- package/personas/persona-dt.md +13 -5
- package/personas/persona-p.md +5 -2
- package/personas/persona-pt.md +13 -6
- package/personas/persona-v.md +2 -2
- package/personas/persona-w.md +11 -9
- package/personas/swarm/agent.cordis.yml +43 -0
- package/personas/swarm/preset.yml +5 -0
- package/skills/grill-me/SKILL.md +71 -0
- package/skills/llm-wiki-skill/.mise.toml +2 -0
- package/skills/llm-wiki-skill/.nvmrc +1 -0
- package/skills/llm-wiki-skill/AGENTS.md +173 -0
- package/skills/llm-wiki-skill/CHANGELOG.md +548 -0
- package/skills/llm-wiki-skill/CLAUDE.md +152 -0
- package/skills/llm-wiki-skill/HERMES.md +44 -0
- package/skills/llm-wiki-skill/README.en.md +261 -0
- package/skills/llm-wiki-skill/README.md +291 -0
- package/skills/llm-wiki-skill/SKILL.md +1133 -0
- package/skills/llm-wiki-skill/assets/graph-demo.gif +0 -0
- package/skills/llm-wiki-skill/assets/graph-preview.png +0 -0
- package/skills/llm-wiki-skill/deps/LICENSE-d3.txt +13 -0
- package/skills/llm-wiki-skill/deps/LICENSE-marked.txt +44 -0
- package/skills/llm-wiki-skill/deps/LICENSE-purify.txt +568 -0
- package/skills/llm-wiki-skill/deps/LICENSE-roughjs.txt +21 -0
- package/skills/llm-wiki-skill/deps/baoyu-url-to-markdown/SKILL.md +261 -0
- package/skills/llm-wiki-skill/deps/baoyu-url-to-markdown/references/config/first-time-setup.md +106 -0
- package/skills/llm-wiki-skill/deps/baoyu-url-to-markdown/scripts/cdp.ts +179 -0
- package/skills/llm-wiki-skill/deps/baoyu-url-to-markdown/scripts/constants.ts +13 -0
- package/skills/llm-wiki-skill/deps/baoyu-url-to-markdown/scripts/defuddle-converter.ts +58 -0
- package/skills/llm-wiki-skill/deps/baoyu-url-to-markdown/scripts/html-to-markdown.ts +135 -0
- package/skills/llm-wiki-skill/deps/baoyu-url-to-markdown/scripts/legacy-converter.ts +629 -0
- package/skills/llm-wiki-skill/deps/baoyu-url-to-markdown/scripts/main.ts +314 -0
- package/skills/llm-wiki-skill/deps/baoyu-url-to-markdown/scripts/markdown-conversion-shared.ts +305 -0
- package/skills/llm-wiki-skill/deps/baoyu-url-to-markdown/scripts/media-localizer.ts +317 -0
- package/skills/llm-wiki-skill/deps/baoyu-url-to-markdown/scripts/package.json +14 -0
- package/skills/llm-wiki-skill/deps/baoyu-url-to-markdown/scripts/paths.ts +29 -0
- package/skills/llm-wiki-skill/deps/baoyu-url-to-markdown/scripts/vendor/baoyu-chrome-cdp/package.json +9 -0
- package/skills/llm-wiki-skill/deps/baoyu-url-to-markdown/scripts/vendor/baoyu-chrome-cdp/src/index.test.ts +307 -0
- package/skills/llm-wiki-skill/deps/baoyu-url-to-markdown/scripts/vendor/baoyu-chrome-cdp/src/index.ts +523 -0
- package/skills/llm-wiki-skill/deps/d3.min.js +2 -0
- package/skills/llm-wiki-skill/deps/marked.min.js +6 -0
- package/skills/llm-wiki-skill/deps/purify.min.js +3 -0
- package/skills/llm-wiki-skill/deps/rough.min.js +7 -0
- package/skills/llm-wiki-skill/deps/youtube-transcript/SKILL.md +47 -0
- package/skills/llm-wiki-skill/deps/youtube-transcript/scripts/get_transcript.py +72 -0
- package/skills/llm-wiki-skill/designs/graph-edge-legibility/graph-edge-treatments.html +480 -0
- package/skills/llm-wiki-skill/docs/design/oriental-atlas/DESIGN.md +183 -0
- package/skills/llm-wiki-skill/docs/design/oriental-atlas/README.md +10 -0
- package/skills/llm-wiki-skill/docs/design/oriental-atlas/design-brief.md +170 -0
- package/skills/llm-wiki-skill/docs/design/oriental-atlas/oriental-editorial-atlas.html +1908 -0
- package/skills/llm-wiki-skill/docs/design/oriental-atlas/reviews/result-review.md +68 -0
- package/skills/llm-wiki-skill/docs/graph/2026-06-16-interaction-risk-audit.md +88 -0
- package/skills/llm-wiki-skill/docs/graph/2026-06-16-interaction-test-coverage-map.md +212 -0
- package/skills/llm-wiki-skill/docs/graph/performance/2026-06-18-phase-0-2-baseline.md +86 -0
- package/skills/llm-wiki-skill/docs/graph/performance/2026-06-18-phase-1-3-dom-svg-large-baseline.md +85 -0
- package/skills/llm-wiki-skill/docs/graph/performance/2026-06-18-phase-1-4-disposable-validation-gate.md +97 -0
- package/skills/llm-wiki-skill/docs/graph/performance/2026-06-18-phase-2-4-global-renderer-trial-matrix.md +168 -0
- package/skills/llm-wiki-skill/docs/graph/performance/2026-06-19-phase-6-1-sigma-graphology-trial.md +71 -0
- package/skills/llm-wiki-skill/docs/graph/performance/2026-06-19-phase-6-2-vis-network-trial.md +78 -0
- package/skills/llm-wiki-skill/docs/graph/performance/2026-06-19-phase-6-3-aggregation-fallback-trial.md +72 -0
- package/skills/llm-wiki-skill/docs/graph/performance/2026-06-19-phase-6-4-global-renderer-route-decision.md +94 -0
- package/skills/llm-wiki-skill/docs/graph/performance/2026-06-19-sigma-global-production-integration-result.md +102 -0
- package/skills/llm-wiki-skill/docs/graph/performance/artifacts/2026-06-18-phase-0-2/stage-4.5-offline-dense-wheel.json +9 -0
- package/skills/llm-wiki-skill/docs/graph/performance/artifacts/2026-06-18-phase-0-2/stage-4.5-offline-dense-wheel.png +0 -0
- package/skills/llm-wiki-skill/docs/graph/performance/artifacts/2026-06-18-phase-0-2/stage-4.5-offline-navigation.png +0 -0
- package/skills/llm-wiki-skill/docs/spark/2026-06-15-omp-tool-status-events-design.md +174 -0
- package/skills/llm-wiki-skill/docs/spark/2026-06-16-graph-interaction-geometry-design.md +832 -0
- package/skills/llm-wiki-skill/docs/spark/2026-06-16-graph-six-layer-architecture-design.md +577 -0
- package/skills/llm-wiki-skill/docs/spark/2026-06-17-static-renderer-coordination-split-design.md +172 -0
- package/skills/llm-wiki-skill/docs/spark/2026-06-18-large-graph-global-community-design.md +909 -0
- package/skills/llm-wiki-skill/docs/spark/2026-06-19-sigma-global-graph-renderer-design.md +360 -0
- package/skills/llm-wiki-skill/docs/spark/2026-06-20-paper-ui-port-design.md +162 -0
- package/skills/llm-wiki-skill/docs/spark/2026-06-20-paper-ui-v2-shell-alignment-design.md +384 -0
- package/skills/llm-wiki-skill/docs/spark/2026-06-21-graph-experience-completion-design.md +534 -0
- package/skills/llm-wiki-skill/docs/spark/2026-06-22-chat-auto-scroll-design.md +185 -0
- package/skills/llm-wiki-skill/docs/spark/2026-06-22-graph-community-node-visual-design.md +266 -0
- package/skills/llm-wiki-skill/docs/spark/2026-06-25-sigma-overlay-refactor-perf-design.md +170 -0
- package/skills/llm-wiki-skill/docs/spark/2026-06-26-global-sigma-community-spotlight-design.md +393 -0
- package/skills/llm-wiki-skill/docs/spark/mockups/2026-06-18-large-graph-global-community-flow.html +746 -0
- package/skills/llm-wiki-skill/install.ps1 +87 -0
- package/skills/llm-wiki-skill/install.sh +722 -0
- package/skills/llm-wiki-skill/package-lock.json +11171 -0
- package/skills/llm-wiki-skill/package.json +24 -0
- package/skills/llm-wiki-skill/packages/graph-engine/package.json +37 -0
- package/skills/llm-wiki-skill/packages/graph-engine/src/anim/.gitkeep +1 -0
- package/skills/llm-wiki-skill/packages/graph-engine/src/anim/index.ts +179 -0
- package/skills/llm-wiki-skill/packages/graph-engine/src/architecture.ts +79 -0
- package/skills/llm-wiki-skill/packages/graph-engine/src/diff.ts +121 -0
- package/skills/llm-wiki-skill/packages/graph-engine/src/facade.ts +1406 -0
- package/skills/llm-wiki-skill/packages/graph-engine/src/graph-node.ts +37 -0
- package/skills/llm-wiki-skill/packages/graph-engine/src/index.ts +25 -0
- package/skills/llm-wiki-skill/packages/graph-engine/src/layout/edge-geometry.ts +17 -0
- package/skills/llm-wiki-skill/packages/graph-engine/src/layout/index.ts +16 -0
- package/skills/llm-wiki-skill/packages/graph-engine/src/layout/spatial-index.ts +509 -0
- package/skills/llm-wiki-skill/packages/graph-engine/src/model/atlas.ts +18 -0
- package/skills/llm-wiki-skill/packages/graph-engine/src/model/index.ts +10 -0
- package/skills/llm-wiki-skill/packages/graph-engine/src/model/labels.ts +11 -0
- package/skills/llm-wiki-skill/packages/graph-engine/src/model/layout.ts +81 -0
- package/skills/llm-wiki-skill/packages/graph-engine/src/model/learning.ts +8 -0
- package/skills/llm-wiki-skill/packages/graph-engine/src/model/legacy-helpers.ts +1379 -0
- package/skills/llm-wiki-skill/packages/graph-engine/src/model/queue.ts +7 -0
- package/skills/llm-wiki-skill/packages/graph-engine/src/model/storage.ts +4 -0
- package/skills/llm-wiki-skill/packages/graph-engine/src/model/visibility.ts +9 -0
- package/skills/llm-wiki-skill/packages/graph-engine/src/render/.gitkeep +1 -0
- package/skills/llm-wiki-skill/packages/graph-engine/src/render/adapter.ts +443 -0
- package/skills/llm-wiki-skill/packages/graph-engine/src/render/aggregation-containers.ts +64 -0
- package/skills/llm-wiki-skill/packages/graph-engine/src/render/community-cloud-geometry.ts +178 -0
- package/skills/llm-wiki-skill/packages/graph-engine/src/render/community-wash.ts +238 -0
- package/skills/llm-wiki-skill/packages/graph-engine/src/render/community-washes.ts +19 -0
- package/skills/llm-wiki-skill/packages/graph-engine/src/render/compat-contract.ts +14 -0
- package/skills/llm-wiki-skill/packages/graph-engine/src/render/controller.ts +705 -0
- package/skills/llm-wiki-skill/packages/graph-engine/src/render/controls.ts +288 -0
- package/skills/llm-wiki-skill/packages/graph-engine/src/render/dom-svg-renderer.ts +180 -0
- package/skills/llm-wiki-skill/packages/graph-engine/src/render/edges.ts +51 -0
- package/skills/llm-wiki-skill/packages/graph-engine/src/render/geometry.ts +380 -0
- package/skills/llm-wiki-skill/packages/graph-engine/src/render/gestures.ts +673 -0
- package/skills/llm-wiki-skill/packages/graph-engine/src/render/graph-renderer-root.ts +387 -0
- package/skills/llm-wiki-skill/packages/graph-engine/src/render/hit-testing.ts +56 -0
- package/skills/llm-wiki-skill/packages/graph-engine/src/render/host-dom.ts +14 -0
- package/skills/llm-wiki-skill/packages/graph-engine/src/render/hover-card.ts +37 -0
- package/skills/llm-wiki-skill/packages/graph-engine/src/render/index.ts +213 -0
- package/skills/llm-wiki-skill/packages/graph-engine/src/render/keyboard.ts +48 -0
- package/skills/llm-wiki-skill/packages/graph-engine/src/render/legend.ts +25 -0
- package/skills/llm-wiki-skill/packages/graph-engine/src/render/minimap.ts +45 -0
- package/skills/llm-wiki-skill/packages/graph-engine/src/render/model.ts +1339 -0
- package/skills/llm-wiki-skill/packages/graph-engine/src/render/node-drag-lifecycle.ts +94 -0
- package/skills/llm-wiki-skill/packages/graph-engine/src/render/nodes.ts +103 -0
- package/skills/llm-wiki-skill/packages/graph-engine/src/render/offline-reader.ts +209 -0
- package/skills/llm-wiki-skill/packages/graph-engine/src/render/overlays-presenter.ts +192 -0
- package/skills/llm-wiki-skill/packages/graph-engine/src/render/overlays.ts +73 -0
- package/skills/llm-wiki-skill/packages/graph-engine/src/render/pin-position.ts +51 -0
- package/skills/llm-wiki-skill/packages/graph-engine/src/render/preview.ts +65 -0
- package/skills/llm-wiki-skill/packages/graph-engine/src/render/relation-focus.ts +91 -0
- package/skills/llm-wiki-skill/packages/graph-engine/src/render/render-context.ts +85 -0
- package/skills/llm-wiki-skill/packages/graph-engine/src/render/render-pipeline.ts +871 -0
- package/skills/llm-wiki-skill/packages/graph-engine/src/render/render-styles.ts +1405 -0
- package/skills/llm-wiki-skill/packages/graph-engine/src/render/renderer-surface.ts +75 -0
- package/skills/llm-wiki-skill/packages/graph-engine/src/render/search.ts +57 -0
- package/skills/llm-wiki-skill/packages/graph-engine/src/render/sigma-coordinates.ts +44 -0
- package/skills/llm-wiki-skill/packages/graph-engine/src/render/sigma-global-drag.ts +246 -0
- package/skills/llm-wiki-skill/packages/graph-engine/src/render/sigma-global-renderer.ts +1425 -0
- package/skills/llm-wiki-skill/packages/graph-engine/src/render/sigma-overlay-svg.ts +121 -0
- package/skills/llm-wiki-skill/packages/graph-engine/src/render/simulation-bridge.ts +59 -0
- package/skills/llm-wiki-skill/packages/graph-engine/src/render/state.ts +262 -0
- package/skills/llm-wiki-skill/packages/graph-engine/src/render/toolbar.ts +40 -0
- package/skills/llm-wiki-skill/packages/graph-engine/src/render/viewport.ts +336 -0
- package/skills/llm-wiki-skill/packages/graph-engine/src/select/.gitkeep +1 -0
- package/skills/llm-wiki-skill/packages/graph-engine/src/select/index.ts +189 -0
- package/skills/llm-wiki-skill/packages/graph-engine/src/sim/index.ts +372 -0
- package/skills/llm-wiki-skill/packages/graph-engine/src/sim/pins.ts +84 -0
- package/skills/llm-wiki-skill/packages/graph-engine/src/summary/index.ts +447 -0
- package/skills/llm-wiki-skill/packages/graph-engine/src/themes/.gitkeep +1 -0
- package/skills/llm-wiki-skill/packages/graph-engine/src/themes/index.ts +8 -0
- package/skills/llm-wiki-skill/packages/graph-engine/src/themes/tokens.ts +117 -0
- package/skills/llm-wiki-skill/packages/graph-engine/src/types/d3-quadtree.d.ts +22 -0
- package/skills/llm-wiki-skill/packages/graph-engine/src/types.ts +531 -0
- package/skills/llm-wiki-skill/packages/graph-engine/test/aggregation-fallback-trial-adapter.test.ts +115 -0
- package/skills/llm-wiki-skill/packages/graph-engine/test/aggregation-fallback-trial-adapter.ts +222 -0
- package/skills/llm-wiki-skill/packages/graph-engine/test/anim.test.ts +121 -0
- package/skills/llm-wiki-skill/packages/graph-engine/test/architecture.test.ts +63 -0
- package/skills/llm-wiki-skill/packages/graph-engine/test/community-cloud-geometry.test.ts +86 -0
- package/skills/llm-wiki-skill/packages/graph-engine/test/community-wash.test.ts +97 -0
- package/skills/llm-wiki-skill/packages/graph-engine/test/diff.test.ts +133 -0
- package/skills/llm-wiki-skill/packages/graph-engine/test/facade.test.ts +1369 -0
- package/skills/llm-wiki-skill/packages/graph-engine/test/geometry.test.ts +147 -0
- package/skills/llm-wiki-skill/packages/graph-engine/test/gestures.test.ts +768 -0
- package/skills/llm-wiki-skill/packages/graph-engine/test/graph-layout.test.ts +110 -0
- package/skills/llm-wiki-skill/packages/graph-engine/test/helpers.test.ts +287 -0
- package/skills/llm-wiki-skill/packages/graph-engine/test/interaction-contract.test.ts +106 -0
- package/skills/llm-wiki-skill/packages/graph-engine/test/keyboard.test.ts +59 -0
- package/skills/llm-wiki-skill/packages/graph-engine/test/large-fixtures.test.ts +47 -0
- package/skills/llm-wiki-skill/packages/graph-engine/test/large-graph-fixtures.ts +420 -0
- package/skills/llm-wiki-skill/packages/graph-engine/test/learning.test.ts +259 -0
- package/skills/llm-wiki-skill/packages/graph-engine/test/node-drag-lifecycle.test.ts +166 -0
- package/skills/llm-wiki-skill/packages/graph-engine/test/overlays.test.ts +115 -0
- package/skills/llm-wiki-skill/packages/graph-engine/test/preview.test.ts +56 -0
- package/skills/llm-wiki-skill/packages/graph-engine/test/queue.test.ts +114 -0
- package/skills/llm-wiki-skill/packages/graph-engine/test/relation-focus.test.ts +115 -0
- package/skills/llm-wiki-skill/packages/graph-engine/test/render-model.test.ts +1030 -0
- package/skills/llm-wiki-skill/packages/graph-engine/test/renderer-adapter-contract.test.ts +271 -0
- package/skills/llm-wiki-skill/packages/graph-engine/test/renderer-boundary.test.ts +618 -0
- package/skills/llm-wiki-skill/packages/graph-engine/test/renderer-lifecycle.test.ts +1711 -0
- package/skills/llm-wiki-skill/packages/graph-engine/test/route-continuity.test.ts +284 -0
- package/skills/llm-wiki-skill/packages/graph-engine/test/runtime-state.test.ts +281 -0
- package/skills/llm-wiki-skill/packages/graph-engine/test/search-and-legend.test.ts +124 -0
- package/skills/llm-wiki-skill/packages/graph-engine/test/select.test.ts +168 -0
- package/skills/llm-wiki-skill/packages/graph-engine/test/sigma-coordinates.test.ts +50 -0
- package/skills/llm-wiki-skill/packages/graph-engine/test/sigma-global-renderer.test.ts +2210 -0
- package/skills/llm-wiki-skill/packages/graph-engine/test/sigma-trial-adapter.test.ts +82 -0
- package/skills/llm-wiki-skill/packages/graph-engine/test/sigma-trial-adapter.ts +271 -0
- package/skills/llm-wiki-skill/packages/graph-engine/test/sim.test.ts +207 -0
- package/skills/llm-wiki-skill/packages/graph-engine/test/simulation-bridge.test.ts +96 -0
- package/skills/llm-wiki-skill/packages/graph-engine/test/spatial-index.test.ts +222 -0
- package/skills/llm-wiki-skill/packages/graph-engine/test/state.test.ts +189 -0
- package/skills/llm-wiki-skill/packages/graph-engine/test/summary-contract.test.ts +422 -0
- package/skills/llm-wiki-skill/packages/graph-engine/test/themes.test.ts +62 -0
- package/skills/llm-wiki-skill/packages/graph-engine/test/toolbar.test.ts +64 -0
- package/skills/llm-wiki-skill/packages/graph-engine/test/viewport.test.ts +213 -0
- package/skills/llm-wiki-skill/packages/graph-engine/test/vis-network-trial-adapter.test.ts +82 -0
- package/skills/llm-wiki-skill/packages/graph-engine/test/vis-network-trial-adapter.ts +186 -0
- package/skills/llm-wiki-skill/packages/graph-engine/tsconfig.json +17 -0
- package/skills/llm-wiki-skill/packages/graph-engine/vite.config.ts +15 -0
- package/skills/llm-wiki-skill/platforms/claude/CLAUDE.md +37 -0
- package/skills/llm-wiki-skill/platforms/claude/companions/llm-wiki-upgrade/SKILL.md +95 -0
- package/skills/llm-wiki-skill/platforms/codex/AGENTS.md +23 -0
- package/skills/llm-wiki-skill/platforms/hermes/README.md +31 -0
- package/skills/llm-wiki-skill/platforms/openclaw/README.md +31 -0
- package/skills/llm-wiki-skill/scripts/adapter-state.sh +424 -0
- package/skills/llm-wiki-skill/scripts/build-graph-data.sh +395 -0
- package/skills/llm-wiki-skill/scripts/build-graph-html.sh +459 -0
- package/skills/llm-wiki-skill/scripts/cache.sh +352 -0
- package/skills/llm-wiki-skill/scripts/create-source-page.sh +100 -0
- package/skills/llm-wiki-skill/scripts/delete-helper.sh +68 -0
- package/skills/llm-wiki-skill/scripts/graph-analysis.js +732 -0
- package/skills/llm-wiki-skill/scripts/hook-session-start.sh +46 -0
- package/skills/llm-wiki-skill/scripts/init-wiki.sh +95 -0
- package/skills/llm-wiki-skill/scripts/lib/source-signal-eligibility.js +158 -0
- package/skills/llm-wiki-skill/scripts/lint-fix.sh +114 -0
- package/skills/llm-wiki-skill/scripts/lint-runner.sh +217 -0
- package/skills/llm-wiki-skill/scripts/runtime-context.sh +77 -0
- package/skills/llm-wiki-skill/scripts/shared-config.sh +83 -0
- package/skills/llm-wiki-skill/scripts/source-record-contract.tsv +10 -0
- package/skills/llm-wiki-skill/scripts/source-registry.sh +349 -0
- package/skills/llm-wiki-skill/scripts/source-registry.tsv +10 -0
- package/skills/llm-wiki-skill/scripts/source-signal-coverage.js +83 -0
- package/skills/llm-wiki-skill/scripts/validate-step1.sh +144 -0
- package/skills/llm-wiki-skill/scripts/wiki-compat.sh +267 -0
- package/skills/llm-wiki-skill/setup.sh +8 -0
- package/skills/llm-wiki-skill/templates/entity-template.md +30 -0
- package/skills/llm-wiki-skill/templates/graph-styles/wash/footer.html +27 -0
- package/skills/llm-wiki-skill/templates/graph-styles/wash/graph-wash-helpers.js +1326 -0
- package/skills/llm-wiki-skill/templates/graph-styles/wash/graph-wash.js +1009 -0
- package/skills/llm-wiki-skill/templates/graph-styles/wash/header.html +2002 -0
- package/skills/llm-wiki-skill/templates/index-en-template.md +51 -0
- package/skills/llm-wiki-skill/templates/index-template.md +51 -0
- package/skills/llm-wiki-skill/templates/log-en-template.md +11 -0
- package/skills/llm-wiki-skill/templates/log-template.md +11 -0
- package/skills/llm-wiki-skill/templates/overview-en-template.md +41 -0
- package/skills/llm-wiki-skill/templates/overview-template.md +41 -0
- package/skills/llm-wiki-skill/templates/purpose-en-template.md +16 -0
- package/skills/llm-wiki-skill/templates/purpose-template.md +16 -0
- package/skills/llm-wiki-skill/templates/query-template.md +19 -0
- package/skills/llm-wiki-skill/templates/schema-template.md +185 -0
- package/skills/llm-wiki-skill/templates/source-template.md +51 -0
- package/skills/llm-wiki-skill/templates/synthesis-template.md +25 -0
- package/skills/llm-wiki-skill/templates/topic-template.md +35 -0
- package/skills/llm-wiki-skill/tests/adapter-state.sh +338 -0
- package/skills/llm-wiki-skill/tests/browser/graph-aggregation-fallback-trial.ts +737 -0
- package/skills/llm-wiki-skill/tests/browser/graph-community-node-map.mjs +255 -0
- package/skills/llm-wiki-skill/tests/browser/graph-community-wash-interactions.mjs +170 -0
- package/skills/llm-wiki-skill/tests/browser/graph-default-behavior.mjs +630 -0
- package/skills/llm-wiki-skill/tests/browser/graph-density-preview.mjs +53 -0
- package/skills/llm-wiki-skill/tests/browser/graph-html-insights.mjs +41 -0
- package/skills/llm-wiki-skill/tests/browser/graph-large-performance.ts +689 -0
- package/skills/llm-wiki-skill/tests/browser/graph-node-slim.mjs +75 -0
- package/skills/llm-wiki-skill/tests/browser/graph-offline-phase-6.mjs +660 -0
- package/skills/llm-wiki-skill/tests/browser/graph-renderer-trial-shared.ts +291 -0
- package/skills/llm-wiki-skill/tests/browser/graph-sigma-global-production.ts +1437 -0
- package/skills/llm-wiki-skill/tests/browser/graph-sigma-graphology-trial.ts +949 -0
- package/skills/llm-wiki-skill/tests/browser/graph-stage-4-5.mjs +815 -0
- package/skills/llm-wiki-skill/tests/browser/graph-vis-network-trial.ts +762 -0
- package/skills/llm-wiki-skill/tests/browser/graph-workbench-interactions.mjs +730 -0
- package/skills/llm-wiki-skill/tests/browser/validate-graph-trial-result.mjs +149 -0
- package/skills/llm-wiki-skill/tests/expected/graph-data-empty.json +60 -0
- package/skills/llm-wiki-skill/tests/expected/graph-data-sample.json +396 -0
- package/skills/llm-wiki-skill/tests/expected/graph-interactive-basic.html +1736 -0
- package/skills/llm-wiki-skill/tests/expected/lint-output.txt +44 -0
- package/skills/llm-wiki-skill/tests/fixtures/coverage-sample-wiki/index.md +1 -0
- package/skills/llm-wiki-skill/tests/fixtures/coverage-sample-wiki/wiki/entities/Alpha.md +10 -0
- package/skills/llm-wiki-skill/tests/fixtures/coverage-sample-wiki/wiki/entities/Beta.md +7 -0
- package/skills/llm-wiki-skill/tests/fixtures/coverage-sample-wiki/wiki/entities/Delta.md +8 -0
- package/skills/llm-wiki-skill/tests/fixtures/coverage-sample-wiki/wiki/entities/Gamma.md +8 -0
- package/skills/llm-wiki-skill/tests/fixtures/coverage-sample-wiki/wiki/queries/20260422-abc.md +10 -0
- package/skills/llm-wiki-skill/tests/fixtures/coverage-sample-wiki/wiki/synthesis/Crystal.md +8 -0
- package/skills/llm-wiki-skill/tests/fixtures/coverage-sample-wiki/wiki/topics/Overview.md +9 -0
- package/skills/llm-wiki-skill/tests/fixtures/graph-data-empty-wiki/wiki/entities/.gitkeep +0 -0
- package/skills/llm-wiki-skill/tests/fixtures/graph-data-sample-wiki/purpose.md +3 -0
- package/skills/llm-wiki-skill/tests/fixtures/graph-data-sample-wiki/wiki/entities/Attention.md +7 -0
- package/skills/llm-wiki-skill/tests/fixtures/graph-data-sample-wiki/wiki/entities/Decoder.md +7 -0
- package/skills/llm-wiki-skill/tests/fixtures/graph-data-sample-wiki/wiki/entities/Encoder.md +7 -0
- package/skills/llm-wiki-skill/tests/fixtures/graph-data-sample-wiki/wiki/entities/GPT.md +7 -0
- package/skills/llm-wiki-skill/tests/fixtures/graph-data-sample-wiki/wiki/entities/Transformer.md +13 -0
- package/skills/llm-wiki-skill/tests/fixtures/graph-data-sample-wiki/wiki/sources/paper.md +9 -0
- package/skills/llm-wiki-skill/tests/fixtures/graph-data-sample-wiki/wiki/topics/arch.md +12 -0
- package/skills/llm-wiki-skill/tests/fixtures/graph-data-sample-wiki/wiki/topics/finetune.md +9 -0
- package/skills/llm-wiki-skill/tests/fixtures/graph-interactive-basic/wiki/graph-data.json +40 -0
- package/skills/llm-wiki-skill/tests/fixtures/graph-interactive-dense/wiki/graph-data.json +3965 -0
- package/skills/llm-wiki-skill/tests/fixtures/graph-interactive-multicomm/wiki/graph-data.json +212 -0
- package/skills/llm-wiki-skill/tests/fixtures/lint-sample-wiki/index.md +14 -0
- package/skills/llm-wiki-skill/tests/fixtures/lint-sample-wiki/wiki/entities/C++.md +6 -0
- package/skills/llm-wiki-skill/tests/fixtures/lint-sample-wiki/wiki/entities/Lonely.md +4 -0
- package/skills/llm-wiki-skill/tests/fixtures/lint-sample-wiki/wiki/entities/Other.md +8 -0
- package/skills/llm-wiki-skill/tests/fixtures/lint-sample-wiki/wiki/entities/Real.md +7 -0
- package/skills/llm-wiki-skill/tests/fixtures/lint-sample-wiki/wiki/sources/2026-01-01-test-source.md +15 -0
- package/skills/llm-wiki-skill/tests/fixtures/lint-sample-wiki/wiki/sources/2026-02-01-inline-img.md +12 -0
- package/skills/llm-wiki-skill/tests/fixtures/lint-sample-wiki/wiki/topics/AIbasic.md +3 -0
- package/skills/llm-wiki-skill/tests/graph-aggregation-fallback-trial.regression-1.sh +46 -0
- package/skills/llm-wiki-skill/tests/graph-analysis-helper.regression-1.sh +237 -0
- package/skills/llm-wiki-skill/tests/graph-browser-large-performance.regression-1.sh +39 -0
- package/skills/llm-wiki-skill/tests/graph-browser-stage-4-5.regression-1.sh +163 -0
- package/skills/llm-wiki-skill/tests/graph-build-failures.regression-1.sh +91 -0
- package/skills/llm-wiki-skill/tests/graph-community-node-map.regression-1.sh +107 -0
- package/skills/llm-wiki-skill/tests/graph-community-wash-interactions.regression-1.sh +35 -0
- package/skills/llm-wiki-skill/tests/graph-data-confidence-merge.regression-1.sh +309 -0
- package/skills/llm-wiki-skill/tests/graph-data-source-paths.regression-1.sh +49 -0
- package/skills/llm-wiki-skill/tests/graph-default-behavior.regression-1.sh +35 -0
- package/skills/llm-wiki-skill/tests/graph-html-a11y.regression-1.sh +50 -0
- package/skills/llm-wiki-skill/tests/graph-html-brand-link.regression-1.sh +47 -0
- package/skills/llm-wiki-skill/tests/graph-html-density.regression-1.sh +228 -0
- package/skills/llm-wiki-skill/tests/graph-html-drawer-neighbors.regression-1.sh +47 -0
- package/skills/llm-wiki-skill/tests/graph-html-insights.regression-1.sh +80 -0
- package/skills/llm-wiki-skill/tests/graph-html-long-label.regression-1.sh +92 -0
- package/skills/llm-wiki-skill/tests/graph-html-minimap.regression-1.sh +51 -0
- package/skills/llm-wiki-skill/tests/graph-html-mobile.regression-1.sh +48 -0
- package/skills/llm-wiki-skill/tests/graph-html-oriental-atlas-contract.regression-1.sh +94 -0
- package/skills/llm-wiki-skill/tests/graph-html-oriental-design-contract.regression-1.sh +82 -0
- package/skills/llm-wiki-skill/tests/graph-html-search.regression-1.sh +52 -0
- package/skills/llm-wiki-skill/tests/graph-html-styles.regression-1.sh +66 -0
- package/skills/llm-wiki-skill/tests/graph-html-toolbar.regression-1.sh +62 -0
- package/skills/llm-wiki-skill/tests/graph-offline-phase-6.regression-1.sh +51 -0
- package/skills/llm-wiki-skill/tests/graph-sigma-global-production.regression-1.sh +64 -0
- package/skills/llm-wiki-skill/tests/graph-sigma-graphology-trial.regression-1.sh +46 -0
- package/skills/llm-wiki-skill/tests/graph-vis-network-trial.regression-1.sh +46 -0
- package/skills/llm-wiki-skill/tests/graph-workbench-interactions.regression-1.sh +151 -0
- package/skills/llm-wiki-skill/tests/js/graph-wash-bootstrap.test.js +110 -0
- package/skills/llm-wiki-skill/tests/js/graph-wash-helpers.test.js +296 -0
- package/skills/llm-wiki-skill/tests/js/graph-wash-learning.test.js +260 -0
- package/skills/llm-wiki-skill/tests/js/graph-wash-queue.test.js +115 -0
- package/skills/llm-wiki-skill/tests/js/graph-wash-runtime-state.test.js +282 -0
- package/skills/llm-wiki-skill/tests/js/source-signal-coverage.test.js +48 -0
- package/skills/llm-wiki-skill/tests/js/source-signal-eligibility.test.js +202 -0
- package/skills/llm-wiki-skill/tests/lib/graph-html-engine-helpers.sh +110 -0
- package/skills/llm-wiki-skill/tests/lint-output.regression-1.sh +32 -0
- package/skills/llm-wiki-skill/tests/regression.sh +1754 -0
- package/skills/llm-wiki-skill/workbench/AGENTS.md +110 -0
- package/skills/llm-wiki-skill/workbench/CLAUDE.md +55 -0
- package/skills/llm-wiki-skill/workbench/LICENSE +21 -0
- package/skills/llm-wiki-skill/workbench/PRODUCT.md +1353 -0
- package/skills/llm-wiki-skill/workbench/README.md +30 -0
- package/skills/llm-wiki-skill/workbench/docs/current-kb-retrieval-design.md +587 -0
- package/skills/llm-wiki-skill/workbench/docs/graph-evolution-1-design.md +210 -0
- package/skills/llm-wiki-skill/workbench/docs/stage-2-design.md +1139 -0
- package/skills/llm-wiki-skill/workbench/docs/stage-3-design.md +1269 -0
- package/skills/llm-wiki-skill/workbench/docs/stage-3.5-design.md +1164 -0
- package/skills/llm-wiki-skill/workbench/docs/stage-4-design.md +504 -0
- package/skills/llm-wiki-skill/workbench/docs/stage-4.5-design.md +195 -0
- package/skills/llm-wiki-skill/workbench/docs/superpowers/specs/2026-05-28-resizable-preview-layout-design.md +165 -0
- package/skills/llm-wiki-skill/workbench/docs/superpowers/specs/2026-05-28-settings-panel-scroll-fix.md +50 -0
- package/skills/llm-wiki-skill/workbench/server/package.json +31 -0
- package/skills/llm-wiki-skill/workbench/server/src/agent.ts +457 -0
- package/skills/llm-wiki-skill/workbench/server/src/artifacts.ts +248 -0
- package/skills/llm-wiki-skill/workbench/server/src/auth.ts +164 -0
- package/skills/llm-wiki-skill/workbench/server/src/config.ts +130 -0
- package/skills/llm-wiki-skill/workbench/server/src/conversations.test.ts +159 -0
- package/skills/llm-wiki-skill/workbench/server/src/conversations.ts +270 -0
- package/skills/llm-wiki-skill/workbench/server/src/digest/batch.ts +189 -0
- package/skills/llm-wiki-skill/workbench/server/src/digest/concurrency.test.ts +36 -0
- package/skills/llm-wiki-skill/workbench/server/src/digest/concurrency.ts +31 -0
- package/skills/llm-wiki-skill/workbench/server/src/digest/subagent.ts +91 -0
- package/skills/llm-wiki-skill/workbench/server/src/extensions/artifacts.ts +81 -0
- package/skills/llm-wiki-skill/workbench/server/src/extensions/knowledge-base.ts +263 -0
- package/skills/llm-wiki-skill/workbench/server/src/extensions/new-wiki.ts +42 -0
- package/skills/llm-wiki-skill/workbench/server/src/extensions/synthesis.ts +172 -0
- package/skills/llm-wiki-skill/workbench/server/src/graph-watcher.test.ts +196 -0
- package/skills/llm-wiki-skill/workbench/server/src/graph.test.ts +113 -0
- package/skills/llm-wiki-skill/workbench/server/src/graph.ts +351 -0
- package/skills/llm-wiki-skill/workbench/server/src/index.ts +1148 -0
- package/skills/llm-wiki-skill/workbench/server/src/knowledge-bases.test.ts +30 -0
- package/skills/llm-wiki-skill/workbench/server/src/knowledge-bases.ts +321 -0
- package/skills/llm-wiki-skill/workbench/server/src/pages.test.ts +41 -0
- package/skills/llm-wiki-skill/workbench/server/src/pages.ts +160 -0
- package/skills/llm-wiki-skill/workbench/server/src/retrieval.test.ts +151 -0
- package/skills/llm-wiki-skill/workbench/server/src/retrieval.ts +427 -0
- package/skills/llm-wiki-skill/workbench/server/src/tool-status-events.test.ts +363 -0
- package/skills/llm-wiki-skill/workbench/server/src/tool-status-events.ts +616 -0
- package/skills/llm-wiki-skill/workbench/server/src/wiki-init.test.ts +19 -0
- package/skills/llm-wiki-skill/workbench/server/src/wiki-init.ts +188 -0
- package/skills/llm-wiki-skill/workbench/server/tsconfig.json +10 -0
- package/skills/llm-wiki-skill/workbench/tsconfig.json +20 -0
- package/skills/llm-wiki-skill/workbench/web/README.md +73 -0
- package/skills/llm-wiki-skill/workbench/web/components.json +21 -0
- package/skills/llm-wiki-skill/workbench/web/eslint.config.js +22 -0
- package/skills/llm-wiki-skill/workbench/web/index.html +16 -0
- package/skills/llm-wiki-skill/workbench/web/package.json +54 -0
- package/skills/llm-wiki-skill/workbench/web/src/App.tsx +1195 -0
- package/skills/llm-wiki-skill/workbench/web/src/components/AddExternalDialog.tsx +375 -0
- package/skills/llm-wiki-skill/workbench/web/src/components/AppearancePanel.tsx +158 -0
- package/skills/llm-wiki-skill/workbench/web/src/components/ArtifactView.tsx +15 -0
- package/skills/llm-wiki-skill/workbench/web/src/components/BatchDigestPanel.tsx +117 -0
- package/skills/llm-wiki-skill/workbench/web/src/components/ChatPanel.tsx +890 -0
- package/skills/llm-wiki-skill/workbench/web/src/components/CommandMenu.tsx +75 -0
- package/skills/llm-wiki-skill/workbench/web/src/components/ExportButtons.tsx +58 -0
- package/skills/llm-wiki-skill/workbench/web/src/components/GraphPanel.tsx +800 -0
- package/skills/llm-wiki-skill/workbench/web/src/components/GraphReader.tsx +52 -0
- package/skills/llm-wiki-skill/workbench/web/src/components/GraphSelection.tsx +100 -0
- package/skills/llm-wiki-skill/workbench/web/src/components/GraphSummaryDrawer.tsx +269 -0
- package/skills/llm-wiki-skill/workbench/web/src/components/MainViewTabs.tsx +69 -0
- package/skills/llm-wiki-skill/workbench/web/src/components/MarkdownView.tsx +106 -0
- package/skills/llm-wiki-skill/workbench/web/src/components/NewWikiDialog.tsx +103 -0
- package/skills/llm-wiki-skill/workbench/web/src/components/RefMenu.tsx +44 -0
- package/skills/llm-wiki-skill/workbench/web/src/components/RightDrawer.tsx +298 -0
- package/skills/llm-wiki-skill/workbench/web/src/components/SearchPanel.tsx +165 -0
- package/skills/llm-wiki-skill/workbench/web/src/components/SettingsPanel.tsx +320 -0
- package/skills/llm-wiki-skill/workbench/web/src/components/Sidebar.tsx +354 -0
- package/skills/llm-wiki-skill/workbench/web/src/components/ToolHistorySummary.tsx +111 -0
- package/skills/llm-wiki-skill/workbench/web/src/components/ToolStatusRunway.tsx +70 -0
- package/skills/llm-wiki-skill/workbench/web/src/components/TopBar.tsx +348 -0
- package/skills/llm-wiki-skill/workbench/web/src/components/renderers/DownloadOnlyRenderer.tsx +88 -0
- package/skills/llm-wiki-skill/workbench/web/src/components/renderers/HtmlRenderer.tsx +92 -0
- package/skills/llm-wiki-skill/workbench/web/src/components/ui/button.tsx +52 -0
- package/skills/llm-wiki-skill/workbench/web/src/components/ui/command.tsx +50 -0
- package/skills/llm-wiki-skill/workbench/web/src/components/ui/dialog.tsx +156 -0
- package/skills/llm-wiki-skill/workbench/web/src/components/ui/input.tsx +21 -0
- package/skills/llm-wiki-skill/workbench/web/src/components/ui/tooltip.tsx +57 -0
- package/skills/llm-wiki-skill/workbench/web/src/index.css +4204 -0
- package/skills/llm-wiki-skill/workbench/web/src/lib/api.ts +648 -0
- package/skills/llm-wiki-skill/workbench/web/src/lib/appearance.ts +114 -0
- package/skills/llm-wiki-skill/workbench/web/src/lib/drawer-layout.ts +41 -0
- package/skills/llm-wiki-skill/workbench/web/src/lib/drawer-state.ts +168 -0
- package/skills/llm-wiki-skill/workbench/web/src/lib/graph-reader.ts +25 -0
- package/skills/llm-wiki-skill/workbench/web/src/lib/graph-selection-drawer.ts +35 -0
- package/skills/llm-wiki-skill/workbench/web/src/lib/graph-selection.ts +96 -0
- package/skills/llm-wiki-skill/workbench/web/src/lib/graph-summary-actions.ts +184 -0
- package/skills/llm-wiki-skill/workbench/web/src/lib/legacy-tool-status.ts +113 -0
- package/skills/llm-wiki-skill/workbench/web/src/lib/model-roles.ts +20 -0
- package/skills/llm-wiki-skill/workbench/web/src/lib/search-filter.ts +104 -0
- package/skills/llm-wiki-skill/workbench/web/src/lib/sse.ts +72 -0
- package/skills/llm-wiki-skill/workbench/web/src/lib/tool-status-format.ts +170 -0
- package/skills/llm-wiki-skill/workbench/web/src/lib/tool-status-model.ts +392 -0
- package/skills/llm-wiki-skill/workbench/web/src/lib/utils.ts +10 -0
- package/skills/llm-wiki-skill/workbench/web/src/lib/view-status.ts +16 -0
- package/skills/llm-wiki-skill/workbench/web/src/lib/wiki-links.ts +32 -0
- package/skills/llm-wiki-skill/workbench/web/src/main.tsx +10 -0
- package/skills/llm-wiki-skill/workbench/web/test/api.test.ts +61 -0
- package/skills/llm-wiki-skill/workbench/web/test/app-shell-drawer-layout.test.tsx +48 -0
- package/skills/llm-wiki-skill/workbench/web/test/appearance-panel.test.tsx +121 -0
- package/skills/llm-wiki-skill/workbench/web/test/appearance.test.ts +262 -0
- package/skills/llm-wiki-skill/workbench/web/test/chat-host-source.test.tsx +22 -0
- package/skills/llm-wiki-skill/workbench/web/test/chat-panel-auto-scroll.test.tsx +311 -0
- package/skills/llm-wiki-skill/workbench/web/test/chat-panel-bubbles.test.tsx +48 -0
- package/skills/llm-wiki-skill/workbench/web/test/chat-panel-composer.test.tsx +86 -0
- package/skills/llm-wiki-skill/workbench/web/test/chat-panel-tool-status.test.tsx +26 -0
- package/skills/llm-wiki-skill/workbench/web/test/export-batch-paper.test.tsx +101 -0
- package/skills/llm-wiki-skill/workbench/web/test/graph-drawer-state.test.ts +257 -0
- package/skills/llm-wiki-skill/workbench/web/test/graph-panel-paper.test.tsx +200 -0
- package/skills/llm-wiki-skill/workbench/web/test/graph-reader-request.test.ts +32 -0
- package/skills/llm-wiki-skill/workbench/web/test/graph-reader.test.ts +62 -0
- package/skills/llm-wiki-skill/workbench/web/test/graph-selection-drawer.test.ts +56 -0
- package/skills/llm-wiki-skill/workbench/web/test/graph-selection.test.ts +83 -0
- package/skills/llm-wiki-skill/workbench/web/test/graph-summary-actions.test.ts +188 -0
- package/skills/llm-wiki-skill/workbench/web/test/main-view-tabs.test.tsx +34 -0
- package/skills/llm-wiki-skill/workbench/web/test/markdown-view.test.tsx +34 -0
- package/skills/llm-wiki-skill/workbench/web/test/popup-menus.test.tsx +85 -0
- package/skills/llm-wiki-skill/workbench/web/test/render.test.tsx +30 -0
- package/skills/llm-wiki-skill/workbench/web/test/render.tsx +38 -0
- package/skills/llm-wiki-skill/workbench/web/test/right-drawer-graph-summary.test.tsx +287 -0
- package/skills/llm-wiki-skill/workbench/web/test/right-drawer-interactions.test.tsx +182 -0
- package/skills/llm-wiki-skill/workbench/web/test/search-filter.test.ts +65 -0
- package/skills/llm-wiki-skill/workbench/web/test/search-panel.test.tsx +155 -0
- package/skills/llm-wiki-skill/workbench/web/test/setup-dom.ts +66 -0
- package/skills/llm-wiki-skill/workbench/web/test/sidebar-v2-source.test.ts +17 -0
- package/skills/llm-wiki-skill/workbench/web/test/sidebar.test.tsx +110 -0
- package/skills/llm-wiki-skill/workbench/web/test/tool-history-summary.test.tsx +150 -0
- package/skills/llm-wiki-skill/workbench/web/test/tool-status-format.test.ts +107 -0
- package/skills/llm-wiki-skill/workbench/web/test/tool-status-model.test.ts +324 -0
- package/skills/llm-wiki-skill/workbench/web/test/tool-status-runway.test.ts +159 -0
- package/skills/llm-wiki-skill/workbench/web/test/topbar.test.tsx +248 -0
- package/skills/llm-wiki-skill/workbench/web/test/visual/paper-ui.ts +898 -0
- package/skills/llm-wiki-skill/workbench/web/test/wiki-links.test.ts +23 -0
- package/skills/llm-wiki-skill/workbench/web/test-results/paper-ui/actual/.gitkeep +1 -0
- package/skills/llm-wiki-skill/workbench/web/test-results/paper-ui/baseline/.gitkeep +1 -0
- package/skills/llm-wiki-skill/workbench/web/tsconfig.app.json +30 -0
- package/skills/llm-wiki-skill/workbench/web/tsconfig.json +7 -0
- package/skills/llm-wiki-skill/workbench/web/tsconfig.node.json +24 -0
- package/skills/llm-wiki-skill/workbench/web/vite.config.ts +28 -0
|
@@ -0,0 +1,660 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { createRequire } from "node:module";
|
|
3
|
+
import fs from "node:fs/promises";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { pathToFileURL } from "node:url";
|
|
6
|
+
|
|
7
|
+
const require = createRequire(import.meta.url);
|
|
8
|
+
const { chromium } = require("playwright");
|
|
9
|
+
|
|
10
|
+
const basicHtml = process.env.GRAPH_OFFLINE_PHASE_6_BASIC_HTML || "";
|
|
11
|
+
const denseHtml = process.env.GRAPH_OFFLINE_PHASE_6_DENSE_HTML || "";
|
|
12
|
+
const multicommHtml = process.env.GRAPH_OFFLINE_PHASE_6_MULTICOMM_HTML || "";
|
|
13
|
+
const artifactDir = process.env.GRAPH_OFFLINE_PHASE_6_ARTIFACT_DIR || "";
|
|
14
|
+
const executablePath = process.env.GRAPH_OFFLINE_PHASE_6_CHROME_EXECUTABLE || "";
|
|
15
|
+
|
|
16
|
+
assert.notEqual(basicHtml, "", "GRAPH_OFFLINE_PHASE_6_BASIC_HTML must point at generated basic HTML");
|
|
17
|
+
assert.notEqual(denseHtml, "", "GRAPH_OFFLINE_PHASE_6_DENSE_HTML must point at generated dense HTML");
|
|
18
|
+
assert.notEqual(multicommHtml, "", "GRAPH_OFFLINE_PHASE_6_MULTICOMM_HTML must point at generated multicomm HTML");
|
|
19
|
+
|
|
20
|
+
const browser = await chromium.launch(executablePath ? { executablePath } : {});
|
|
21
|
+
try {
|
|
22
|
+
const basic = await runBasicOfflineChecks(browser);
|
|
23
|
+
const dense = await runFixtureSmoke(browser, denseHtml, "dense");
|
|
24
|
+
const multicomm = await runFixtureSmoke(browser, multicommHtml, "multicomm");
|
|
25
|
+
const evidence = { basic, dense, multicomm };
|
|
26
|
+
if (artifactDir) {
|
|
27
|
+
await fs.mkdir(artifactDir, { recursive: true });
|
|
28
|
+
await fs.writeFile(path.join(artifactDir, "phase-6-offline-interactions.json"), `${JSON.stringify(evidence, null, 2)}\n`);
|
|
29
|
+
}
|
|
30
|
+
console.log(JSON.stringify(evidence, null, 2));
|
|
31
|
+
} finally {
|
|
32
|
+
await browser.close();
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async function runBasicOfflineChecks(browser) {
|
|
36
|
+
const page = await openOfflinePage(browser, basicHtml, { width: 1440, height: 960 });
|
|
37
|
+
const evidence = {
|
|
38
|
+
html: basicHtml,
|
|
39
|
+
viewport: "1440x960",
|
|
40
|
+
wheelTargets: {},
|
|
41
|
+
rootScroll: {},
|
|
42
|
+
hover: {},
|
|
43
|
+
drag: {},
|
|
44
|
+
reader: {},
|
|
45
|
+
pinPersistence: {},
|
|
46
|
+
theme: {}
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
evidence.wheelTargets.blank = await assertWheelZoomsFromReset(page, () => findBlankPoint(page), "blank");
|
|
50
|
+
evidence.wheelTargets.node = await assertWheelZoomsFromReset(page, () => visibleNodeCenter(page), "node");
|
|
51
|
+
evidence.wheelTargets.communityWash = await assertWheelZoomsFromReset(page, () => findCommunityWashPoint(page, "t1"), "community wash");
|
|
52
|
+
|
|
53
|
+
await resetGraphView(page);
|
|
54
|
+
evidence.rootScroll = await assertGraphRootScrollResets(page);
|
|
55
|
+
evidence.hover.beforeZoom = await hoverNodeAndMeasure(page, null, {
|
|
56
|
+
preferCenter: true,
|
|
57
|
+
roomLeft: 120,
|
|
58
|
+
roomRight: 360,
|
|
59
|
+
roomTop: 120,
|
|
60
|
+
roomBottom: 180
|
|
61
|
+
});
|
|
62
|
+
evidence.hover.node = evidence.hover.beforeZoom.target;
|
|
63
|
+
evidence.hover.zoom = await assertWheelZooms(page, await nodeCenter(page, evidence.hover.node.id), "hovered node");
|
|
64
|
+
evidence.hover.afterZoom = await hoverNodeAndMeasure(page, evidence.hover.node.id);
|
|
65
|
+
assert.equal(
|
|
66
|
+
evidence.hover.afterZoom.target.id,
|
|
67
|
+
evidence.hover.node.id,
|
|
68
|
+
"offline hover after zoom should stay on the same node"
|
|
69
|
+
);
|
|
70
|
+
assertHoverStaysNearAnchor(evidence.hover.beforeZoom, "offline hover before zoom should stay near its node");
|
|
71
|
+
assertHoverStaysNearAnchor(evidence.hover.afterZoom, "offline hover after zoom should stay near its node");
|
|
72
|
+
|
|
73
|
+
await resetGraphView(page);
|
|
74
|
+
const dragNode = await visibleNode(page, { roomRight: 360 });
|
|
75
|
+
evidence.drag = await dragNodeAndMeasure(page, dragNode.id);
|
|
76
|
+
evidence.pinPersistence = await assertPinPersistsAfterReload(page, dragNode.id);
|
|
77
|
+
|
|
78
|
+
evidence.reader = await assertBuiltInReader(page);
|
|
79
|
+
evidence.theme = await assertThemeToggle(page);
|
|
80
|
+
|
|
81
|
+
if (artifactDir) {
|
|
82
|
+
await page.screenshot({ path: path.join(artifactDir, "phase-6-offline-basic.png"), fullPage: true });
|
|
83
|
+
}
|
|
84
|
+
await page.close();
|
|
85
|
+
return roundObject(evidence);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
async function runFixtureSmoke(browser, html, name) {
|
|
89
|
+
const page = await openOfflinePage(browser, html, { width: 1280, height: 860 });
|
|
90
|
+
const before = await layerTransform(page);
|
|
91
|
+
const point = await visibleNodeCenter(page);
|
|
92
|
+
await page.mouse.move(point.x, point.y);
|
|
93
|
+
await page.mouse.wheel(0, -360);
|
|
94
|
+
const after = await waitForLayerTransform(page, before);
|
|
95
|
+
assert.notEqual(after, before, `${name} offline graph should zoom over a node`);
|
|
96
|
+
const counts = await page.evaluate(() => ({
|
|
97
|
+
nodes: document.querySelectorAll(".node").length,
|
|
98
|
+
edges: document.querySelectorAll(".edge").length,
|
|
99
|
+
communities: document.querySelectorAll(".community-wash").length,
|
|
100
|
+
hasReactDrawer: Boolean(document.querySelector(".drawer-panel-open"))
|
|
101
|
+
}));
|
|
102
|
+
assert.ok(counts.nodes > 0, `${name} offline graph should render nodes`);
|
|
103
|
+
assert.equal(counts.hasReactDrawer, false, `${name} offline graph should not depend on the React host drawer`);
|
|
104
|
+
await page.close();
|
|
105
|
+
return { html, before, after, counts };
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
async function openOfflinePage(browser, html, viewport) {
|
|
109
|
+
const page = await browser.newPage({ viewport });
|
|
110
|
+
await page.addInitScript(() => {
|
|
111
|
+
window.__graphOfflinePhase6 = {
|
|
112
|
+
round(value) {
|
|
113
|
+
return Math.round(value * 1000) / 1000;
|
|
114
|
+
},
|
|
115
|
+
roundRect(rect) {
|
|
116
|
+
return {
|
|
117
|
+
left: this.round(rect.left),
|
|
118
|
+
top: this.round(rect.top),
|
|
119
|
+
right: this.round(rect.right),
|
|
120
|
+
bottom: this.round(rect.bottom),
|
|
121
|
+
width: this.round(rect.width),
|
|
122
|
+
height: this.round(rect.height)
|
|
123
|
+
};
|
|
124
|
+
},
|
|
125
|
+
relativeRect(rect, rootRect) {
|
|
126
|
+
return {
|
|
127
|
+
left: this.round(rect.left - rootRect.left),
|
|
128
|
+
top: this.round(rect.top - rootRect.top),
|
|
129
|
+
right: this.round(rect.right - rootRect.left),
|
|
130
|
+
bottom: this.round(rect.bottom - rootRect.top),
|
|
131
|
+
width: this.round(rect.width),
|
|
132
|
+
height: this.round(rect.height)
|
|
133
|
+
};
|
|
134
|
+
},
|
|
135
|
+
relativePoint(point, rootRect) {
|
|
136
|
+
return {
|
|
137
|
+
x: this.round(point.x - rootRect.left),
|
|
138
|
+
y: this.round(point.y - rootRect.top)
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
});
|
|
143
|
+
await page.goto(pathToFileURL(html).href);
|
|
144
|
+
await page.waitForSelector("[data-llm-wiki-graph-root='true']");
|
|
145
|
+
await page.waitForSelector("[data-viewport-layer='true']");
|
|
146
|
+
await page.waitForSelector(".node");
|
|
147
|
+
return page;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
async function assertWheelZooms(page, point, label) {
|
|
151
|
+
const before = await layerTransform(page);
|
|
152
|
+
await page.mouse.move(point.x, point.y);
|
|
153
|
+
await page.mouse.wheel(0, -420);
|
|
154
|
+
const after = await waitForLayerTransform(page, before);
|
|
155
|
+
assert.notEqual(after, before, `offline wheel over ${label} should zoom`);
|
|
156
|
+
return { before, after, point: roundedPoint(point) };
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
async function assertWheelZoomsFromReset(page, pointFactory, label) {
|
|
160
|
+
await resetGraphView(page);
|
|
161
|
+
await waitForGraphMotionSettled(page);
|
|
162
|
+
const point = await pointFactory();
|
|
163
|
+
return assertWheelZooms(page, point, label);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
async function hoverNodeAndMeasure(page, preferredId = null, targetOptions = {}) {
|
|
167
|
+
const target = await visibleNode(page, { ...targetOptions, preferredId });
|
|
168
|
+
const id = target.id;
|
|
169
|
+
await waitForNodeMotionSettled(page, id);
|
|
170
|
+
let lastProbe = null;
|
|
171
|
+
for (let attempt = 0; attempt < 5; attempt += 1) {
|
|
172
|
+
await movePointerAwayFromGraphObjects(page);
|
|
173
|
+
await waitForNodeMotionSettled(page, id);
|
|
174
|
+
const point = await nodeCenter(page, id);
|
|
175
|
+
await page.mouse.move(point.x, point.y, { steps: 4 });
|
|
176
|
+
await page.waitForTimeout(450);
|
|
177
|
+
const probe = await hoverProbe(page, id, point);
|
|
178
|
+
lastProbe = probe;
|
|
179
|
+
if (probe.preview.state === "open" && probe.preview.kind === "node" && probe.hit.closestNode === id) break;
|
|
180
|
+
}
|
|
181
|
+
assert.ok(
|
|
182
|
+
lastProbe?.preview.state === "open" && lastProbe.preview.kind === "node" && lastProbe.hit.closestNode === id,
|
|
183
|
+
`offline hover preview for ${id} should open after pointer enters node: ${JSON.stringify(lastProbe)}`
|
|
184
|
+
);
|
|
185
|
+
await page.locator(".graph-hover-preview-title").waitFor();
|
|
186
|
+
const measurement = await page.evaluate((id) => {
|
|
187
|
+
const root = document.querySelector("[data-llm-wiki-graph-root='true']");
|
|
188
|
+
const node = document.querySelector(`.node[data-id="${CSS.escape(id)}"]`);
|
|
189
|
+
const preview = document.querySelector(".graph-hover-preview");
|
|
190
|
+
if (!root || !node || !preview) throw new Error("Missing hover measurement elements");
|
|
191
|
+
const rootRect = root.getBoundingClientRect();
|
|
192
|
+
const nodeRect = node.getBoundingClientRect();
|
|
193
|
+
const previewRect = preview.getBoundingClientRect();
|
|
194
|
+
const nodeAnchor = {
|
|
195
|
+
x: nodeRect.left + nodeRect.width / 2,
|
|
196
|
+
y: nodeRect.top + nodeRect.height / 2
|
|
197
|
+
};
|
|
198
|
+
return {
|
|
199
|
+
target: {
|
|
200
|
+
id,
|
|
201
|
+
label: node.querySelector(".node-name")?.textContent || node.textContent?.trim() || id
|
|
202
|
+
},
|
|
203
|
+
nodeAnchor: window.__graphOfflinePhase6.relativePoint(nodeAnchor, rootRect),
|
|
204
|
+
preview: window.__graphOfflinePhase6.relativeRect(previewRect, rootRect),
|
|
205
|
+
offset: {
|
|
206
|
+
x: previewRect.left - nodeAnchor.x,
|
|
207
|
+
y: previewRect.bottom - nodeAnchor.y
|
|
208
|
+
}
|
|
209
|
+
};
|
|
210
|
+
}, id);
|
|
211
|
+
await assertBoxInsideViewport(page, ".graph-hover-preview", `offline hover preview for ${id}`);
|
|
212
|
+
await assertGraphRootNotScrolled(page, `offline hover preview for ${id}`);
|
|
213
|
+
return roundObject({ ...measurement, target });
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
async function hoverProbe(page, id, point) {
|
|
217
|
+
return page.evaluate(({ id, point }) => {
|
|
218
|
+
const root = document.querySelector("[data-llm-wiki-graph-root='true']");
|
|
219
|
+
const node = document.querySelector(`.node[data-id="${CSS.escape(id)}"]`);
|
|
220
|
+
const preview = document.querySelector(".graph-hover-preview");
|
|
221
|
+
if (!root || !node || !preview) throw new Error("Missing hover probe elements");
|
|
222
|
+
const hit = document.elementFromPoint(point.x, point.y);
|
|
223
|
+
const nodeRect = node.getBoundingClientRect();
|
|
224
|
+
const rootRect = root.getBoundingClientRect();
|
|
225
|
+
return {
|
|
226
|
+
point: window.__graphOfflinePhase6.relativePoint(point, rootRect),
|
|
227
|
+
rootScroll: { left: root.scrollLeft, top: root.scrollTop },
|
|
228
|
+
nodeRect: window.__graphOfflinePhase6.relativeRect(nodeRect, rootRect),
|
|
229
|
+
nodeHovered: node.matches(":hover"),
|
|
230
|
+
hit: {
|
|
231
|
+
tag: hit?.tagName || "",
|
|
232
|
+
className: typeof hit?.className === "string" ? hit.className : hit?.className?.baseVal || "",
|
|
233
|
+
closestNode: hit?.closest?.(".node")?.dataset?.id || "",
|
|
234
|
+
closestWash: hit?.closest?.(".community-wash")?.dataset?.communityId || ""
|
|
235
|
+
},
|
|
236
|
+
preview: {
|
|
237
|
+
state: preview.dataset.state || "",
|
|
238
|
+
kind: preview.dataset.kind || "",
|
|
239
|
+
textLength: preview.textContent?.length || 0
|
|
240
|
+
}
|
|
241
|
+
};
|
|
242
|
+
}, { id, point });
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
async function movePointerAwayFromGraphObjects(page) {
|
|
246
|
+
const point = await findBlankPoint(page);
|
|
247
|
+
await page.mouse.move(point.x, point.y, { steps: 3 });
|
|
248
|
+
await page.waitForTimeout(80);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
async function dragNodeAndMeasure(page, id) {
|
|
252
|
+
await waitForNodeMotionSettled(page, id);
|
|
253
|
+
const start = await nodeCenter(page, id);
|
|
254
|
+
const target = { x: start.x + 360, y: start.y + 28 };
|
|
255
|
+
await page.mouse.move(start.x, start.y);
|
|
256
|
+
await page.mouse.down();
|
|
257
|
+
await page.mouse.move(target.x, target.y, { steps: 8 });
|
|
258
|
+
await page.waitForTimeout(80);
|
|
259
|
+
const during = await nodeCenter(page, id);
|
|
260
|
+
const pointerDistance = Math.hypot(during.x - target.x, during.y - target.y);
|
|
261
|
+
assert.ok(pointerDistance <= 48, `offline dragged node should stay under pointer, distance=${pointerDistance.toFixed(1)}`);
|
|
262
|
+
await page.mouse.up();
|
|
263
|
+
await page.waitForSelector(`.node[data-id="${cssString(id)}"][data-pinned="true"]`);
|
|
264
|
+
await page.waitForTimeout(140);
|
|
265
|
+
const after = await page.locator(`.node[data-id="${cssString(id)}"]`).evaluate((node) => {
|
|
266
|
+
const root = document.querySelector("[data-llm-wiki-graph-root='true']");
|
|
267
|
+
if (!root) throw new Error("Missing root after drag");
|
|
268
|
+
const rootRect = root.getBoundingClientRect();
|
|
269
|
+
const rect = node.getBoundingClientRect();
|
|
270
|
+
return {
|
|
271
|
+
center: {
|
|
272
|
+
x: rect.left + rect.width / 2 - rootRect.left,
|
|
273
|
+
y: rect.top + rect.height / 2 - rootRect.top
|
|
274
|
+
},
|
|
275
|
+
pinned: node.dataset.pinned,
|
|
276
|
+
dragging: root.dataset.dragging || ""
|
|
277
|
+
};
|
|
278
|
+
});
|
|
279
|
+
assert.equal(after.pinned, "true", "offline drag should commit a pin");
|
|
280
|
+
assert.equal(after.dragging, "", "offline drag should not remain stuck");
|
|
281
|
+
return roundObject({ start, target, during, pointerDistance, after });
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
async function assertPinPersistsAfterReload(page, id) {
|
|
285
|
+
const key = await page.evaluate(() => window.__LLM_WIKI_GRAPH_PINS_KEY__ || "");
|
|
286
|
+
assert.notEqual(key, "", "offline graph pins key should be exposed");
|
|
287
|
+
const before = await page.evaluate((key) => JSON.parse(window.localStorage.getItem(key) || "{}"), key);
|
|
288
|
+
assert.ok(Object.keys(before).length >= 1, "offline drag should write at least one pin");
|
|
289
|
+
for (const pin of Object.values(before)) {
|
|
290
|
+
assert.equal(pin.coordinateSpace, "world", "offline persisted pins should be explicit world coordinates");
|
|
291
|
+
}
|
|
292
|
+
await page.reload();
|
|
293
|
+
await page.waitForSelector("[data-llm-wiki-graph-root='true']");
|
|
294
|
+
await page.waitForSelector(`.node[data-id="${cssString(id)}"][data-pinned="true"]`);
|
|
295
|
+
const pinnedCount = await page.locator("[data-llm-wiki-graph-root='true']").evaluate((root) => root.dataset.pinnedCount || "");
|
|
296
|
+
assert.equal(pinnedCount, "1", "offline pin should survive reload");
|
|
297
|
+
const unmarkedWorldPin = { x: 333, y: 222 };
|
|
298
|
+
const pinKey = await nodePinKey(page, id);
|
|
299
|
+
await page.evaluate(({ key, id, pin }) => {
|
|
300
|
+
window.localStorage.setItem(key, JSON.stringify({
|
|
301
|
+
[id]: pin
|
|
302
|
+
}));
|
|
303
|
+
}, { key, id: pinKey, pin: unmarkedWorldPin });
|
|
304
|
+
await page.reload();
|
|
305
|
+
await page.waitForSelector("[data-llm-wiki-graph-root='true']");
|
|
306
|
+
await page.waitForSelector(`.node[data-id="${cssString(id)}"][data-pinned="true"]`);
|
|
307
|
+
await resetGraphView(page);
|
|
308
|
+
await page.waitForTimeout(120);
|
|
309
|
+
const unmarkedWorldCenter = await page.locator(`.node[data-id="${cssString(id)}"]`).evaluate((node) => {
|
|
310
|
+
return {
|
|
311
|
+
worldPoint: {
|
|
312
|
+
x: Number(node.dataset.worldX || node.dataset.liveX || Number.NaN),
|
|
313
|
+
y: Number(node.dataset.worldY || node.dataset.liveY || Number.NaN)
|
|
314
|
+
},
|
|
315
|
+
pinned: node.dataset.pinned || ""
|
|
316
|
+
};
|
|
317
|
+
});
|
|
318
|
+
assert.equal(unmarkedWorldCenter.pinned, "true", "offline unmarked localStorage pin should reload as pinned");
|
|
319
|
+
const worldDistance = Math.hypot(
|
|
320
|
+
unmarkedWorldCenter.worldPoint.x - unmarkedWorldPin.x,
|
|
321
|
+
unmarkedWorldCenter.worldPoint.y - unmarkedWorldPin.y
|
|
322
|
+
);
|
|
323
|
+
assert.ok(
|
|
324
|
+
worldDistance <= 0.01,
|
|
325
|
+
`offline unmarked localStorage pin should stay in world coordinates, distance=${worldDistance.toFixed(2)}`
|
|
326
|
+
);
|
|
327
|
+
return { key, storedPins: before, pinnedCount, unmarkedWorldPin, pinKey, unmarkedWorldCenter, worldDistance };
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
async function assertBuiltInReader(page, id) {
|
|
331
|
+
await resetGraphView(page);
|
|
332
|
+
const target = id ? await visibleNode(page, { preferredId: id }) : await visibleNode(page);
|
|
333
|
+
await clickNodeByPointer(page, target.id);
|
|
334
|
+
await page.waitForSelector(".graph-reader[data-state='open']");
|
|
335
|
+
await page.locator(".graph-reader-title", { hasText: target.label }).waitFor();
|
|
336
|
+
await page.locator(".graph-reader-body").waitFor();
|
|
337
|
+
assert.equal(await page.locator(".drawer-panel-open").count(), 0, "offline graph should not open the React host drawer");
|
|
338
|
+
const snapshot = await page.locator(".graph-reader[data-state='open']").evaluate((reader) => ({
|
|
339
|
+
title: reader.querySelector(".graph-reader-title")?.textContent || "",
|
|
340
|
+
bodyLength: reader.querySelector(".graph-reader-body")?.textContent?.length || 0,
|
|
341
|
+
hasHostDrawer: Boolean(document.querySelector(".drawer-panel-open"))
|
|
342
|
+
}));
|
|
343
|
+
await page.keyboard.press("Escape");
|
|
344
|
+
await page.waitForSelector(".graph-reader[data-state='closed']");
|
|
345
|
+
return { ...snapshot, target };
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
async function assertThemeToggle(page) {
|
|
349
|
+
const before = await graphTheme(page);
|
|
350
|
+
await page.getByRole("button", { name: before === "shan-shui" ? "切换墨夜主题" : "切换山水主题" }).click();
|
|
351
|
+
const after = await waitForGraphThemeChange(page, before);
|
|
352
|
+
await page.getByRole("button", { name: after === "shan-shui" ? "切换墨夜主题" : "切换山水主题" }).click();
|
|
353
|
+
const restored = await waitForGraphThemeChange(page, after);
|
|
354
|
+
assert.equal(restored, before, "offline theme toggle should restore the original theme");
|
|
355
|
+
return { before, after, restored };
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
async function assertGraphRootScrollResets(page) {
|
|
359
|
+
const before = await graphRootScroll(page);
|
|
360
|
+
await page.locator("[data-llm-wiki-graph-root='true']").evaluate((root) => {
|
|
361
|
+
root.scrollLeft = 120;
|
|
362
|
+
root.scrollTop = 240;
|
|
363
|
+
});
|
|
364
|
+
await page.waitForFunction(() => {
|
|
365
|
+
const root = document.querySelector("[data-llm-wiki-graph-root='true']");
|
|
366
|
+
return root && root.scrollLeft === 0 && root.scrollTop === 0;
|
|
367
|
+
});
|
|
368
|
+
const after = await graphRootScroll(page);
|
|
369
|
+
assert.deepEqual(after, { left: 0, top: 0 }, "offline graph root native scroll should reset to zero");
|
|
370
|
+
return { before, after };
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
async function assertGraphRootNotScrolled(page, label) {
|
|
374
|
+
const scroll = await graphRootScroll(page);
|
|
375
|
+
assert.deepEqual(scroll, { left: 0, top: 0 }, `${label}: graph root native scroll should stay at zero`);
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
async function resetGraphView(page) {
|
|
379
|
+
const before = await layerTransform(page);
|
|
380
|
+
await page.getByRole("button", { name: "回全图" }).click();
|
|
381
|
+
await page.waitForTimeout(220);
|
|
382
|
+
const after = await layerTransform(page);
|
|
383
|
+
if (after === before) await page.waitForTimeout(120);
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
async function layerTransform(page) {
|
|
387
|
+
return page.locator("[data-viewport-layer='true']").evaluate((element) => element.style.transform);
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
async function waitForLayerTransform(page, previous) {
|
|
391
|
+
await page.waitForFunction(
|
|
392
|
+
(previous) => document.querySelector("[data-viewport-layer='true']")?.style.transform !== previous,
|
|
393
|
+
previous,
|
|
394
|
+
{ timeout: 3000 }
|
|
395
|
+
);
|
|
396
|
+
return layerTransform(page);
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
async function nodeCenter(page, id) {
|
|
400
|
+
return page.locator(`.node[data-id="${cssString(id)}"]`).evaluate((node) => {
|
|
401
|
+
const rect = node.getBoundingClientRect();
|
|
402
|
+
return {
|
|
403
|
+
x: rect.left + rect.width / 2,
|
|
404
|
+
y: rect.top + rect.height / 2
|
|
405
|
+
};
|
|
406
|
+
});
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
async function nodePinKey(page, id) {
|
|
410
|
+
return page.evaluate((id) => {
|
|
411
|
+
const dataEl = document.getElementById("graph-data");
|
|
412
|
+
const graphData = dataEl?.textContent ? JSON.parse(dataEl.textContent) : null;
|
|
413
|
+
const node = graphData?.nodes?.find((item) => item.id === id);
|
|
414
|
+
if (!node) return id;
|
|
415
|
+
const existing = node.source_path || node.path || node.source;
|
|
416
|
+
if (existing) return String(existing);
|
|
417
|
+
const nodeId = String(node.id || id);
|
|
418
|
+
const baseId = nodeId.endsWith(".md") ? nodeId.slice(0, -3) : nodeId;
|
|
419
|
+
const type = String(node.type || "");
|
|
420
|
+
const directory = type === "topic"
|
|
421
|
+
? "topics"
|
|
422
|
+
: type === "source"
|
|
423
|
+
? "sources"
|
|
424
|
+
: type === "comparison"
|
|
425
|
+
? "comparisons"
|
|
426
|
+
: type === "synthesis"
|
|
427
|
+
? "synthesis"
|
|
428
|
+
: type === "query"
|
|
429
|
+
? "queries"
|
|
430
|
+
: "entities";
|
|
431
|
+
return `wiki/${directory}/${baseId}.md`;
|
|
432
|
+
}, id);
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
async function visibleNodeCenter(page, preferredId = null, options = {}) {
|
|
436
|
+
const targetOptions = typeof preferredId === "object" && preferredId !== null
|
|
437
|
+
? preferredId
|
|
438
|
+
: { ...options, preferredId };
|
|
439
|
+
const node = await visibleNode(page, targetOptions);
|
|
440
|
+
return node.center;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
async function visibleNode(page, options = {}) {
|
|
444
|
+
const {
|
|
445
|
+
preferredId = null,
|
|
446
|
+
roomLeft = 0,
|
|
447
|
+
roomRight = 0,
|
|
448
|
+
roomTop = 0,
|
|
449
|
+
roomBottom = 0,
|
|
450
|
+
preferCenter = false
|
|
451
|
+
} = options;
|
|
452
|
+
await waitForGraphMotionSettled(page);
|
|
453
|
+
const candidate = await page.evaluate((options) => {
|
|
454
|
+
const { preferredId, roomLeft, roomRight, roomTop, roomBottom, preferCenter } = options;
|
|
455
|
+
const root = document.querySelector("[data-llm-wiki-graph-root='true']");
|
|
456
|
+
if (!root) throw new Error("Missing graph root");
|
|
457
|
+
const rootRect = root.getBoundingClientRect();
|
|
458
|
+
const viewportWidth = window.innerWidth;
|
|
459
|
+
const viewportHeight = window.innerHeight;
|
|
460
|
+
const minX = Math.max(rootRect.left + roomLeft, 0);
|
|
461
|
+
const maxX = Math.min(rootRect.right - roomRight, viewportWidth);
|
|
462
|
+
const minY = Math.max(rootRect.top + roomTop, 0);
|
|
463
|
+
const maxY = Math.min(rootRect.bottom - roomBottom, viewportHeight);
|
|
464
|
+
const ideal = {
|
|
465
|
+
x: minX + Math.max(0, maxX - minX) / 2,
|
|
466
|
+
y: minY + Math.max(0, maxY - minY) / 2
|
|
467
|
+
};
|
|
468
|
+
const nodes = Array.from(document.querySelectorAll(".node"));
|
|
469
|
+
const measurements = nodes.map((node) => {
|
|
470
|
+
const rect = node.getBoundingClientRect();
|
|
471
|
+
const center = {
|
|
472
|
+
x: rect.left + rect.width / 2,
|
|
473
|
+
y: rect.top + rect.height / 2
|
|
474
|
+
};
|
|
475
|
+
const hit = document.elementFromPoint(center.x, center.y);
|
|
476
|
+
const centerHitsNode = hit?.closest?.(".node") === node;
|
|
477
|
+
const visibleLeft = Math.max(rect.left, minX);
|
|
478
|
+
const visibleRight = Math.min(rect.right, maxX);
|
|
479
|
+
const visibleTop = Math.max(rect.top, minY);
|
|
480
|
+
const visibleBottom = Math.min(rect.bottom, maxY);
|
|
481
|
+
const visibleArea = Math.max(0, visibleRight - visibleLeft) * Math.max(0, visibleBottom - visibleTop);
|
|
482
|
+
const centerInViewport = center.x >= rootRect.left
|
|
483
|
+
&& center.x >= minX
|
|
484
|
+
&& center.x <= maxX
|
|
485
|
+
&& center.y >= minY
|
|
486
|
+
&& center.y <= maxY;
|
|
487
|
+
const centerDistance = Math.hypot(center.x - ideal.x, center.y - ideal.y);
|
|
488
|
+
return {
|
|
489
|
+
id: node.dataset.id || "",
|
|
490
|
+
label: node.querySelector(".node-name")?.textContent || node.textContent?.trim() || node.dataset.id || "",
|
|
491
|
+
center,
|
|
492
|
+
rect: window.__graphOfflinePhase6.relativeRect(rect, rootRect),
|
|
493
|
+
visibleArea,
|
|
494
|
+
centerDistance,
|
|
495
|
+
centerHitsNode,
|
|
496
|
+
centerInViewport
|
|
497
|
+
};
|
|
498
|
+
}).filter((item) => item.id && item.visibleArea > 0);
|
|
499
|
+
const preferred = preferredId
|
|
500
|
+
? measurements.find((item) => item.id === preferredId && item.centerInViewport && item.centerHitsNode)
|
|
501
|
+
: null;
|
|
502
|
+
if (preferred) return preferred;
|
|
503
|
+
const best = measurements
|
|
504
|
+
.filter((item) => item.centerInViewport && item.centerHitsNode)
|
|
505
|
+
.sort((a, b) => preferCenter
|
|
506
|
+
? a.centerDistance - b.centerDistance || b.visibleArea - a.visibleArea
|
|
507
|
+
: b.visibleArea - a.visibleArea || a.centerDistance - b.centerDistance
|
|
508
|
+
)[0];
|
|
509
|
+
if (best) return best;
|
|
510
|
+
throw new Error(`Could not find an interactable visible node: ${JSON.stringify(measurements)}`);
|
|
511
|
+
}, { preferredId, roomLeft, roomRight, roomTop, roomBottom, preferCenter });
|
|
512
|
+
return roundObject(candidate);
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
async function clickNodeByPointer(page, id) {
|
|
516
|
+
const node = await visibleNode(page, { preferredId: id });
|
|
517
|
+
await movePointerAwayFromGraphObjects(page);
|
|
518
|
+
await page.mouse.move(node.center.x, node.center.y, { steps: 4 });
|
|
519
|
+
await page.mouse.down();
|
|
520
|
+
await page.mouse.up();
|
|
521
|
+
return node;
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
async function waitForGraphMotionSettled(page) {
|
|
525
|
+
const firstId = await firstNodeId(page);
|
|
526
|
+
await waitForNodeMotionSettled(page, firstId);
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
async function waitForNodeMotionSettled(page, id) {
|
|
530
|
+
let previous = await nodeCenter(page, id);
|
|
531
|
+
for (let sample = 0; sample < 12; sample += 1) {
|
|
532
|
+
await page.waitForTimeout(140);
|
|
533
|
+
const next = await nodeCenter(page, id);
|
|
534
|
+
const distance = Math.hypot(next.x - previous.x, next.y - previous.y);
|
|
535
|
+
if (distance <= 1.5) return;
|
|
536
|
+
previous = next;
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
async function firstNodeId(page) {
|
|
541
|
+
return page.locator(".node").first().evaluate((node) => node.dataset.id || "");
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
async function findBlankPoint(page) {
|
|
545
|
+
return page.evaluate(() => {
|
|
546
|
+
const root = document.querySelector("[data-llm-wiki-graph-root='true']");
|
|
547
|
+
if (!root) throw new Error("Missing graph root");
|
|
548
|
+
const rect = root.getBoundingClientRect();
|
|
549
|
+
const blocked = ".node,.community-wash,.edge,.graph-toolbar,.mini-map,.graph-search,.graph-reader,.graph-selection-panel";
|
|
550
|
+
const xs = [0.08, 0.16, 0.28, 0.42, 0.58, 0.74, 0.88];
|
|
551
|
+
const ys = [0.18, 0.32, 0.48, 0.64, 0.8, 0.9];
|
|
552
|
+
for (const ry of ys) {
|
|
553
|
+
for (const rx of xs) {
|
|
554
|
+
const x = rect.left + rect.width * rx;
|
|
555
|
+
const y = rect.top + rect.height * ry;
|
|
556
|
+
const hit = document.elementFromPoint(x, y);
|
|
557
|
+
if (!hit || !root.contains(hit)) continue;
|
|
558
|
+
if (hit.closest(blocked)) continue;
|
|
559
|
+
return { x, y };
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
throw new Error("Could not find blank graph point");
|
|
563
|
+
});
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
async function findCommunityWashPoint(page, communityId) {
|
|
567
|
+
return page.evaluate((communityId) => {
|
|
568
|
+
const wash = document.querySelector(`.community-wash[data-community-id="${CSS.escape(communityId)}"]`) || document.querySelector(".community-wash");
|
|
569
|
+
if (!wash) throw new Error("Missing community wash");
|
|
570
|
+
const rect = wash.getBoundingClientRect();
|
|
571
|
+
const candidates = [
|
|
572
|
+
[0.5, 0.18],
|
|
573
|
+
[0.2, 0.5],
|
|
574
|
+
[0.8, 0.5],
|
|
575
|
+
[0.5, 0.82],
|
|
576
|
+
[0.32, 0.32],
|
|
577
|
+
[0.68, 0.68],
|
|
578
|
+
[0.5, 0.5]
|
|
579
|
+
];
|
|
580
|
+
for (const [rx, ry] of candidates) {
|
|
581
|
+
const x = rect.left + rect.width * rx;
|
|
582
|
+
const y = rect.top + rect.height * ry;
|
|
583
|
+
if (document.elementFromPoint(x, y)?.closest?.(".community-wash") === wash) {
|
|
584
|
+
return { x, y, communityId: wash.dataset.communityId || "" };
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
throw new Error("Could not find exposed community wash point");
|
|
588
|
+
}, communityId);
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
async function assertBoxInsideViewport(page, selector, label) {
|
|
592
|
+
const box = await page.locator(selector).first().boundingBox();
|
|
593
|
+
assert.ok(box, `${label}: ${selector} should have a bounding box`);
|
|
594
|
+
const viewport = page.viewportSize();
|
|
595
|
+
assert.ok(viewport, `${label}: viewport should be available`);
|
|
596
|
+
assert.ok(box.x >= -1, `${label}: ${selector} should not overflow left`);
|
|
597
|
+
assert.ok(box.y >= -1, `${label}: ${selector} should not overflow top`);
|
|
598
|
+
assert.ok(box.x + box.width <= viewport.width + 1, `${label}: ${selector} should not overflow right`);
|
|
599
|
+
assert.ok(box.y + box.height <= viewport.height + 1, `${label}: ${selector} should not overflow bottom`);
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
async function graphRootScroll(page) {
|
|
603
|
+
return page.locator("[data-llm-wiki-graph-root='true']").evaluate((root) => ({
|
|
604
|
+
left: root.scrollLeft,
|
|
605
|
+
top: root.scrollTop
|
|
606
|
+
}));
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
async function graphTheme(page) {
|
|
610
|
+
return page.locator(".llm-wiki-graph-engine").evaluate((root) => root.dataset.theme || "");
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
async function waitForGraphThemeChange(page, previous) {
|
|
614
|
+
await page.waitForFunction((previous) => {
|
|
615
|
+
const next = document.querySelector(".llm-wiki-graph-engine")?.dataset.theme || "";
|
|
616
|
+
return next && next !== previous;
|
|
617
|
+
}, previous);
|
|
618
|
+
return graphTheme(page);
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
function assertHoverStaysNearAnchor(measurement, message) {
|
|
622
|
+
const preview = measurement.preview;
|
|
623
|
+
const anchor = measurement.nodeAnchor;
|
|
624
|
+
const horizontalGap = preview.left > anchor.x
|
|
625
|
+
? preview.left - anchor.x
|
|
626
|
+
: anchor.x > preview.right
|
|
627
|
+
? anchor.x - preview.right
|
|
628
|
+
: 0;
|
|
629
|
+
const verticalGap = preview.top > anchor.y
|
|
630
|
+
? preview.top - anchor.y
|
|
631
|
+
: anchor.y > preview.bottom
|
|
632
|
+
? anchor.y - preview.bottom
|
|
633
|
+
: 0;
|
|
634
|
+
assert.ok(horizontalGap <= 180, `${message}: horizontal gap ${horizontalGap.toFixed(2)}px`);
|
|
635
|
+
assert.ok(verticalGap <= 140, `${message}: vertical gap ${verticalGap.toFixed(2)}px`);
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
function cssString(value) {
|
|
639
|
+
return String(value).replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
function roundedPoint(point) {
|
|
643
|
+
return {
|
|
644
|
+
x: round(point.x),
|
|
645
|
+
y: round(point.y)
|
|
646
|
+
};
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
function roundObject(value) {
|
|
650
|
+
if (Array.isArray(value)) return value.map(roundObject);
|
|
651
|
+
if (value && typeof value === "object") {
|
|
652
|
+
return Object.fromEntries(Object.entries(value).map(([key, item]) => [key, roundObject(item)]));
|
|
653
|
+
}
|
|
654
|
+
if (typeof value === "number") return round(value);
|
|
655
|
+
return value;
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
function round(value) {
|
|
659
|
+
return Math.round(value * 1000) / 1000;
|
|
660
|
+
}
|