diff --git a/.codegraph/CODEGRAPH_REPORT.md b/.codegraph/CODEGRAPH_REPORT.md index a4c535b3..ca783aea 100644 --- a/.codegraph/CODEGRAPH_REPORT.md +++ b/.codegraph/CODEGRAPH_REPORT.md @@ -1,62 +1,40 @@ # CodeGraph Report -**Generated:** 2026-06-03T08:20:11.251Z +Report schema: 1 +Source fingerprint: sha256:327ee3443156f26862b82a89db69efde7240173d4730246aee39df4f13539c56 +Tool: codegraph +Tool version: 1.6.0 +Generation mode: local-index (codegraph status --json/files) ## Status -``` - -CodeGraph Status - -Project: /home/pc/StoryCraft-Studio - -Index Statistics: - Files: 959 - Nodes: 9.358 - Edges: 20.132 - DB Size: 17.29 MB - Backend: node:sqlite β€” built-in (full WAL) - Journal: wal - -Nodes by Kind: - import 3.564 - constant 1.571 - function 1.527 - file 942 - method 795 - interface 403 - type_alias 257 - variable 198 - class 93 - struct 6 - enum 1 - enum_member 1 - -Files by Language: - typescript 605 - tsx 304 - javascript 23 - yaml 17 - rust 8 - python 2 - -βœ“ Index is up to date - - +```text +Initialized: yes +Version: 1.6.0 +Files: 1407 +Nodes: 14945 +Edges: 55024 +Pending changes: {"added":0,"modified":0,"removed":0} +Worktree mismatch: none +Index built with: 1.6.0 +Reindex required: no ``` ## Files by Extension -- **.ts**: 605 -- **.tsx**: 304 -- **.mjs**: 17 -- **.yml**: 15 -- **.rs**: 8 +- **.ts**: 898 +- **.tsx**: 378 +- **.mjs**: 62 +- **.rs**: 21 +- **.mts**: 18 +- **.yml**: 18 - **.js**: 4 +- **.yaml**: 3 - **.cjs**: 2 -- **.yaml**: 2 - **.py**: 2 +- **.xml**: 1 --- -*Regenerate with: `pnpm run codegraph:report`* +*Regenerate with: `pnpm run graphs:report` (or `pnpm run codegraph:report` directly). Freshness +check: `pnpm run graphs:status`. Package: worldscript-studio.* diff --git a/.gitignore b/.gitignore index 2f916738..32d54615 100644 --- a/.gitignore +++ b/.gitignore @@ -72,9 +72,6 @@ features/**/*.html # Graphify β€” solo policy: only GRAPH_REPORT.md is committed; regenerate locally via pnpm run graphify:update graphify-out/* !graphify-out/GRAPH_REPORT.md -graphify-out/cache/ -graphify-out/manifest.json -graphify-out/cost.json # Runtime i18n: only bundle.json is deployed (sources live in locales//) public/locales/*/*.json diff --git a/.graphifyignore b/.graphifyignore index 78af973d..4fecd4b0 100644 --- a/.graphifyignore +++ b/.graphifyignore @@ -15,6 +15,17 @@ playwright-report/ # GraphiPy output (don't re-index the graph itself) graphify-out/ +# CodeGraph's own local index/DB β€” a second graph tool's runtime state, not source +.codegraph/ + +# Local tool config/metadata β€” never source +.claude/ +.git/ +.git + +# Sibling git worktrees (defensive β€” this repo is itself checked out under .worktrees/main/) +.worktrees/ + # Vendored/minified third-party bundles (not our source code; pollutes God Nodes/Communities) public/duckdb/ diff --git a/.vscode/tasks.json b/.vscode/tasks.json index cd16ca95..edbdea5a 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -64,6 +64,22 @@ "problemMatcher": [], "presentation": { "reveal": "silent", "panel": "shared" }, "group": { "kind": "build", "isDefault": false } + }, + { + "label": "Dual-Graph: status (freshness check)", + "type": "npm", + "script": "graphs:status", + "problemMatcher": [], + "presentation": { "reveal": "always", "panel": "shared" }, + "group": "none" + }, + { + "label": "Dual-Graph: refresh + regenerate reports", + "type": "npm", + "script": "graphs:refresh", + "problemMatcher": [], + "presentation": { "reveal": "always", "panel": "shared" }, + "group": { "kind": "build", "isDefault": false } } ] } diff --git a/AUDIT.md b/AUDIT.md index 7f9e5712..0f4a6851 100644 --- a/AUDIT.md +++ b/AUDIT.md @@ -6,6 +6,8 @@ **Release gate (2026-08-27 β€” v1.28.3):** Main CI/CD run `33113772841` (the push-triggered run for the release-prep merge commit) passed all applicable required and advisory jobs (Quality Gate Node 22+24, Tauri Rust Gate, Build, E2E, E2E Deep Coverage, Storybook, Lighthouse, Visual Regression, `CI Success`, `Deploy to GitHub Pages` β€” the last verified with a real `github-pages` Deployments API record for this exact commit, `state: success`); Core Rust Gate legitimately skipped (the release-prep commit touches `src-tauri/`, not `crates/`). CodeQL SAST run `33113772797` passed; 0 open code-scanning alerts. The tag-triggered Tauri workflow `33115805027` passed all 5 jobs (`Verify release tag`, `Bundle` for windows-latest/ubuntu-22.04/macos-latest, `GitHub Release`); the tag-triggered `CI / CD` run `33115805002` independently passed all applicable jobs including `E2E Tests (Playwright)` (`PR Size Governance` and `Deploy to GitHub Pages` legitimately skipped β€” restricted to `pull_request` and `refs/heads/main` respectively, neither of which a tag push satisfies) β€” no repeat of the non-deterministic tag-run E2E flake seen on v1.28.2's release. A parallel `Docker` workflow (`33115804967`) built and pushed `ghcr.io/qnbs/worldscript-studio` tagged `1.28.3`/`1.28`/`latest` (digest `sha256:b6e7d71b…`). The release publishes the same asset shape as v1.28.2: Linux x86_64 (rpm/deb/AppImage) and Windows x86_64 (msi/exe) artifacts with corresponding Minisign `.sig` files; macOS arm64 ships an unsigned `.dmg` installer plus a signed `.app.tar.gz` updater bundle (`.sig`) β€” no separate `.dmg.sig`; `latest.json` present; all 14 release assets uploaded successfully. Platform code-signing and notarization remain separate claims. No macOS x86_64 artifact, matching prior releases β€” Intel-macOS remains a gated qualification lane (ADR-0021). Landed via PR #530 (#527 fix β€” synchronous `isPortalActive` init + `isInitialLoad` guard on the bootstrap effect), PR #533 (E2E harness/precondition fix associated with #532 β€” `ensureWelcomePortalEntry()` deterministic startup-state precondition, including its own internal-reload-vs-autosave race and locale-independent WelcomePortal detection via a stable `data-testid`; #532's root cause stays open), and PR #534 (version bump + CHANGELOG/README release truth). +**Dual-graph tooling revalidated (2026-08-28):** Graphify and CodeGraph were audited end-to-end and both upgraded under a `controlled-upgrade` policy β€” `graphifyy` 0.8.26 β†’ 0.9.51, `@colbymchenry/codegraph` (last recorded here at 0.9.3, see the 2026-05-24 historical entry below) β†’ 1.6.0. Both tools' tested versions are now tracked in one place, [`config/graph-tools-versions.json`](config/graph-tools-versions.json) β€” this file references it rather than recording a version number that would drift independently. The old 0.9.3 value is historical provenance, while 1.6.0 is the current tested upgrade target. Fixed: a committed `CODEGRAPH_REPORT.md` that had been generated inside an unrelated project with no live index behind it; a `dual-graph-update.mjs` that swallowed every failure and always printed a false success epilogue (replaced by `scripts/graphs-cli.mjs`'s explicit `doctor`/`status`/`update`/`report`/`refresh`/`bootstrap` interface); an orphaned, never-invoked pre-commit script; and commit-SHA-based freshness (unsafe under squash merge) in favor of a worktree-aware content fingerprint (`scripts/graphSourceFingerprint.mjs`). CodeGraph source/index processing remains local, but its default anonymous telemetry and separate update check are network-capable; use `codegraph telemetry off`, `CODEGRAPH_TELEMETRY=0`, `DO_NOT_TRACK=1`, and `CODEGRAPH_NO_UPDATE_CHECK=1` as local controls. + **Release gate (2026-08-27 β€” v1.28.2):** Main CI/CD run `33064552219` passed all required and advisory jobs (Quality Gate Node 22+24, Tauri Rust Gate, Build, E2E, E2E Deep Coverage, Storybook, Lighthouse, Visual Regression, `CI Success`, `Deploy to GitHub Pages` β€” the last verified with real post-merge evidence, not just a green check: real `Set up job`/`Deploy to GitHub Pages`/`Complete job` steps and a genuine `github-pages` Deployments API record for this commit). Codecov project coverage 74.22% across 540 files. The tag-triggered Tauri workflow `33066539094` passed Ubuntu, Windows, and macOS bundle jobs plus GitHub Release generation and `latest.json`; a parallel `Docker` workflow built and pushed a container image to GHCR. The release publishes Linux x86_64 (rpm/deb/AppImage) and Windows x86_64 (msi/exe) artifacts with corresponding Minisign `.sig` files; macOS arm64 ships an unsigned `.dmg` installer plus a signed `.app.tar.gz` updater bundle (`.sig`) β€” no separate `.dmg.sig` is published; `latest.json` present. Platform code-signing and notarization remain separate claims. No macOS x86_64 artifact was available and it is omitted from the updater manifest, matching v1.28.1's pattern β€” Intel-macOS remains a gated qualification lane (ADR-0021), not yet in the production release matrix. Landed via PRs #519 (DA-06 docs truth), #520 (DA-05 DOCX export), #523 (#522 GitHub Pages deploy fix), and #524 (version bump + DA-03 gap fixes + the full onboarding-install-command doc-truth sweep). The separately-triggered tag CI/CD run (distinct from the main-push run above) hit a non-deterministic `tests/e2e/export.spec.ts` failure (`[Mobile Chrome]`, once also `[chromium]`) on the identical commit that passed cleanly on the main-push run; investigation ruled out cross-test/cross-run state persistence (ephemeral `ubuntu-latest` runners, fresh dev server and browser context per job/test) and traced it to a plausible pre-existing effect-ordering race between `hooks/useApp.ts`'s portal-activation effect and `App.tsx`'s auto-seed-blank-project effect, timing-sensitive rather than deterministic β€” filed as issue #527. Pre-existing and not introduced by v1.28.2. The published artifacts remain valid; the issue affects a timing-sensitive first-run/onboarding path present in the released code and is being addressed in a bounded follow-up intended for v1.28.3, not by amending v1.28.2. Fixed in v1.28.3 above via PR #530. **Release gate (2026-08-23 β€” v1.28.1):** Main CI/CD run `32616003387` passed all required and advisory jobs. The tag-triggered Tauri workflow `32616003394` passed Ubuntu, Windows, and macOS bundle jobs plus GitHub Release generation and `latest.json`. The release publishes Linux x86_64 (rpm/deb/AppImage), Windows x86_64 (msi/exe), and macOS arm64 (dmg/app.tar.gz) artifacts; platform code-signing and notarization remain separate claims. No macOS x86_64 artifact was available and it is omitted from the updater manifest, matching v1.28.0's pattern. diff --git a/CLAUDE.md b/CLAUDE.md index 2299051e..827a7f24 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -347,7 +347,7 @@ Rules: - Before answering architecture or codebase questions, read `graphify-out/GRAPH_REPORT.md` for god nodes and community structure - If `graphify-out/wiki/index.md` exists, navigate it instead of reading raw files - For cross-module "how does X relate to Y" questions, prefer `graphify query ""`, `graphify path "" ""`, or `graphify explain ""` over grep -- After modifying code files in this session, run `pnpm run graphify:update` (AST-only, no API cost). First-time setup: `pnpm run graphify:bootstrap`. +- After modifying code files in this session, run `pnpm run graphify:update` (AST-only, no API cost). First-time setup: `pnpm run graphify:bootstrap` (installs the exact version pinned in [`config/graph-tools-versions.json`](config/graph-tools-versions.json)). If in doubt whether the report is current, run `pnpm run graphs:status` first (FRESH/STALE, no mutation). ## codegraph @@ -357,8 +357,9 @@ Rules: - Before answering code-structure, caller/callee, or impact questions, use CodeGraph MCP tools (`codegraph_context`, `codegraph_impact`, `codegraph_trace`) - If `.codegraph/` exists, answer directly with CodeGraph β€” don't delegate exploration to a file-reading sub-agent - For "how does X reach Y", use `codegraph_trace` instead of manual Grep + Read chains -- After modifying code, the graph auto-syncs (2s debounce). For large refactors, run `pnpm run codegraph:update` +- After modifying code, the graph auto-syncs via a file watcher (debounced). For routine manual updates use `pnpm run codegraph:sync` (incremental) β€” `pnpm run codegraph:update` is a full rebuild (`codegraph index --force`), for large refactors or index-corruption recovery, not routine use - To find affected tests: `pnpm run codegraph:affected` +- First-time setup: `pnpm run codegraph:bootstrap` (installs the exact version pinned in [`config/graph-tools-versions.json`](config/graph-tools-versions.json)), then `codegraph init` ### Dual-Graph workflow - Architecture questions β†’ `graphify-out/GRAPH_REPORT.md` diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 04850cf2..897e299a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -63,8 +63,8 @@ CodeGraph provides **semantic code intelligence** via MCP β€” symbol-level calle **Install:** ```bash -npm install -g @colbymchenry/codegraph # or pnpm add -g -codegraph init -i # in repo root +pnpm run codegraph:bootstrap # installs the exact version pinned in config/graph-tools-versions.json +pnpm run codegraph:init # in repo root; initializes the local index through the verified resolver ``` **Agent setup (Kimi Code CLI):** add the MCP server to `~/.kimi/settings.json` (see `docs/codegraph.md` Β§ MCP Integration). diff --git a/README.md b/README.md index aff61b89..bc193c88 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ IndexedDB v8 PWA v3.0 i18n 19 locales β€” 2925 keys - 7219+ tests / 589 files + 7266+ tests / 591 files Codecov Coverage License MIT CI Status @@ -511,7 +511,7 @@ The Settings β†’ AI panel shows a live GPU status badge with adapter details and | **Document Export** | docx + jszip | Word-compatible `.docx` generation (lazy-loaded) | | **PWA** | Service Worker + Web App Manifest v3 | Offline support, installability, Workbox chunking | | **i18n** | Custom React Context (`I18nContext.tsx`) | 2925 keys Γ— 19 locales (de/en/es/fr/it + ar/he/fa RTL Beta + ja/zh/pt/el/fi/sv/hu/is/eu/ru/ko Beta); EN fallback; `localStorage` persistence | -| **Testing** | Vitest 4.x (7219+ tests / 589 files) + Playwright E2E | Unit/integration + cross-browser E2E; Stryker mutation (manual workflow) | +| **Testing** | Vitest 4.x (7266+ tests / 591 files) + Playwright E2E | Unit/integration + cross-browser E2E; Stryker mutation (manual workflow) | | **Code Quality** | Biome (lint + format) + TypeScript 7 (tsgo) strict | `--error-on-warnings` in CI; zero `any` policy | | **Visualization** | Force-directed graph | Interactive character relationship network | | **Desktop** | Tauri v2 | Cross-platform installer; auto-updater via `latest.json` | @@ -549,7 +549,7 @@ WorldScript-Studio/ β”‚ β”œβ”€β”€ sw.js # PWA Service Worker β”‚ └── manifest.json # PWA Web App Manifest v3 β”œβ”€β”€ tests/ -β”‚ β”œβ”€β”€ unit/ # Vitest unit tests (7219+ tests, 589 files) β€” count spans tests/, components/, packages/*/tests/, not just this folder +β”‚ β”œβ”€β”€ unit/ # Vitest unit tests (7266+ tests, 591 files) β€” count spans tests/, components/, packages/*/tests/, not just this folder β”‚ β”‚ β”œβ”€β”€ ai/ # aiSmallModules, aiCoreFallbackPaths β”‚ β”‚ └── settings/ # WebLlmPanel, AiSections β”‚ └── e2e/ # Playwright specs + helpers.ts @@ -711,7 +711,7 @@ The main pipeline is [`.github/workflows/ci.yml`](.github/workflows/ci.yml). Opt | `scorecard` | weekly + `main` push | OpenSSF Scorecard β€” SARIF uploaded to GitHub Code Scanning | **Current test metrics (2026-08-27, source-synchronized; CI remains authoritative for pass/fail):** -- **7219+ unit tests** across **589 test files** β€” CI is authoritative for pass/fail +- **7266+ unit tests** across **591 test files** β€” CI is authoritative for pass/fail - Coverage thresholds: lines β‰₯ 80 Β· branches β‰₯ 66 Β· functions β‰₯ 72 Β· statements β‰₯ 78 β€” enforced in CI (see Codecov badge for live metrics) - i18n: **2925 keys Γ— 19 locales** (en/de/fr/es/it + ar/he/fa RTL Beta + ja/zh/pt/el/fi/sv/hu/is/eu/ru/ko Beta) diff --git a/config/graph-tools-versions.json b/config/graph-tools-versions.json new file mode 100644 index 00000000..572299d4 --- /dev/null +++ b/config/graph-tools-versions.json @@ -0,0 +1,16 @@ +{ + "schemaVersion": 1, + "graphifyy": { + "testedVersion": "0.9.51", + "policy": "controlled-upgrade", + "installedFrom": "0.8.26", + "notes": "v0.9.0 changed node-ID format (repo-relative path instead of parent-dir+filename); this repo uses no Neo4j/Gephi export, so the only effect is a one-time large diff in graphify-out/GRAPH_REPORT.md on the first graphify update . after upgrading. v0.9.13 fixed the query-log feature (introduced in v0.8.31, after this repo's prior pin) to default OFF; GRAPHIFY_QUERY_LOG_DISABLE=1 is a real, documented hard-off guarantee if ever needed." + }, + "codegraph": { + "testedVersion": "1.6.0", + "policy": "controlled-upgrade", + "installedFrom": "1.1.3", + "notes": "Purely additive/corrective between 1.1.3 and 1.6.0 (no removed commands, no engines/dependency-shape change). Run a full `codegraph index` (not just sync) once immediately after upgrading -- several fixes require a re-index to take effect. Gains --no-color/NO_COLOR support (#1281, absent at 1.1.3) and CODEGRAPH_NO_UPDATE_CHECK=1 (#1243)." + }, + "reportSchemaVersion": 1 +} diff --git a/docs/codegraph.md b/docs/codegraph.md index 3edcdcb0..26a031fc 100644 --- a/docs/codegraph.md +++ b/docs/codegraph.md @@ -6,49 +6,62 @@ WorldScript Studio uses [CodeGraph](https://github.com/colbymchenry/codegraph) f CodeGraph builds a pre-indexed semantic knowledge graph of the codebase using Tree-sitter AST parsing and SQLite FTS5 full-text search. It exposes an MCP server that agents (Kimi Code CLI, Cursor, Claude Code) can query directly β€” eliminating expensive `Grep`/`ReadFile` exploration loops. -**Current index:** 260 files Β· 2.754 nodes Β· 2.443 edges Β· 4.81 MB SQLite (WAL mode) +**Current index stats:** see the committed report's own header β€” [`.codegraph/CODEGRAPH_REPORT.md`](../.codegraph/CODEGRAPH_REPORT.md). A hardcoded snapshot here always drifts; check `pnpm run graphs:status` for FRESH/STALE at a glance. -**Privacy:** 100% local. No data leaves the machine. +**Privacy:** source parsing and the local index stay on this machine; CodeGraph's anonymous telemetry is a separate network-capable feature and is on by default. Disable it before the first invocation when required with `codegraph telemetry off`, `CODEGRAPH_TELEMETRY=0`, or `DO_NOT_TRACK=1` (never commit local settings). Disable its separate background update check with `CODEGRAPH_NO_UPDATE_CHECK=1`; see [full disclosure](https://github.com/colbymchenry/codegraph/blob/main/TELEMETRY.md). + +**Version policy:** the single source of truth is [`config/graph-tools-versions.json`](../config/graph-tools-versions.json) β€” currently pinned to `@colbymchenry/codegraph@1.6.0` under a `controlled-upgrade` policy. Don't hardcode the version elsewhere. ## Installation -### One-time global install +### One-time global install (pinned) ```bash -npm install -g @colbymchenry/codegraph -# or: pnpm add -g @colbymchenry/codegraph +# Optional privacy-first session controls, set before the first CodeGraph command: +export CODEGRAPH_TELEMETRY=0 CODEGRAPH_NO_UPDATE_CHECK=1 +pnpm run codegraph:bootstrap # installs the exact pinned version from config/graph-tools-versions.json +# equivalent manually: npm install -g @colbymchenry/codegraph@ ``` -CodeGraph bundles its own Node runtime β€” nothing to compile. +CodeGraph is optional local developer tooling β€” this never adds it as a `package.json` dependency, and it bundles its own Node runtime (nothing to compile). ### Per-project initialization ```bash cd /path/to/WorldScript-Studio -codegraph init -i +pnpm run codegraph:init ``` -This creates `.codegraph/` and builds the full index. It automatically respects `.gitignore`. +This creates `.codegraph/` and builds the full index in one step (current versions no longer need a +separate `-i`/`--index` flag β€” indexing runs by default). It automatically respects `.gitignore`. ## pnpm Scripts | Script | Purpose | |--------|---------| +| `pnpm run codegraph:bootstrap` | Install the exact pinned version (see `config/graph-tools-versions.json`) | +| `pnpm run codegraph:init` | Initialize the local index through the verified command resolver | | `pnpm run codegraph:status` | Show index statistics | -| `pnpm run codegraph:update` | Force full re-index (`codegraph index --force`) | -| `pnpm run codegraph:sync` | Incremental sync (`codegraph sync`) | -| `pnpm run codegraph:report` | Generate `.codegraph/CODEGRAPH_REPORT.md` | +| `pnpm run codegraph:sync` | **Routine incremental update** (`codegraph sync`) β€” what `pnpm run graphs:update` runs | +| `pnpm run codegraph:update` | **Full rebuild** (`codegraph index --force`) β€” for large refactors or index corruption recovery, not routine use | +| `pnpm run codegraph:report` | Generate `.codegraph/CODEGRAPH_REPORT.md` (gated on a clean source tree) | | `pnpm run codegraph:affected` | Show test files affected by uncommitted changes | -| `pnpm run graphs:update` | Update **both** Graphify and CodeGraph sequentially | +| `pnpm run graphs:doctor` / `graphs:status` / `graphs:update` / `graphs:report` / `graphs:refresh` / `graphs:bootstrap` | Combined dual-graph interface β€” see [`dual-graph-setup.md`](dual-graph-setup.md) | ## Daily Workflow -### After large refactors +### Routine update (after normal edits) ```bash -pnpm run codegraph:update -# or update both graphs: -pnpm run graphs:update +pnpm run codegraph:sync # incremental β€” this is what graphs:update runs for CodeGraph +``` + +### After large refactors or suspected index corruption + +```bash +pnpm run codegraph:update # full rebuild (codegraph index --force) -- not the routine path +# after the full rebuild, regenerate the committed reports if needed: +pnpm run graphs:report ``` ### Find affected tests before committing @@ -106,12 +119,21 @@ This creates `.cursor/rules/codegraph.mdc` and configures the Cursor MCP client. ### Claude Code -Run once in the project: +Run once, without `--project` (registers a **user-level**, machine-personal MCP entry in +`~/.claude.json` rather than a repo-tracked `.mcp.json` β€” this is what's actually observed in +practice, so a fresh clone on a different machine needs to repeat this step, not inherit it from git): ```bash -codegraph install --target=claude --yes +codegraph install --target=claude ``` +**Known display quirk:** `claude mcp list` / `/mcp` may show `codegraph: ⊘ Disabled for this project` +even when the config genuinely does *not* disable it (verify: `~/.claude.json` β†’ +`projects[""].disabledMcpServers` should not contain `"codegraph"`) and the server itself +handshakes correctly (`codegraph serve --mcp` responds fine to a raw MCP `initialize` request). Treat +this as a stale health-check display issue, not a real disablement β€” if tools aren't available in a +session, re-check via `/mcp` in a fresh session before assuming a config problem. + ## VS Code: Tasks Four tasks are pre-defined in `.vscode/tasks.json`: @@ -126,7 +148,7 @@ Four tasks are pre-defined in `.vscode/tasks.json`: CodeGraph indexes every file not excluded by `.gitignore`. For WorldScript Studio: - **Indexed:** `app/`, `components/`, `features/`, `hooks/`, `services/`, `packages/`, `src-tauri/src/`, `workers/`, `tests/`, `locales/` -- **Excluded:** `node_modules/`, `dist/`, `src-tauri/target/`, `graphify-out/`, `.codegraph/` +- **Excluded:** `node_modules/`, `dist/`, `src-tauri/target/`, `graphify-out/`, `.codegraph/`, `.claude/`, `.git/`, sibling worktree paths Rust support is native β€” Tauri commands in `src-tauri/src/` are indexed alongside TypeScript. @@ -134,20 +156,20 @@ Rust support is native β€” Tauri commands in `src-tauri/src/` are indexed alongs Following the same policy as Graphify: -- **Committed:** `.codegraph/CODEGRAPH_REPORT.md` only +- **Committed:** `.codegraph/CODEGRAPH_REPORT.md` only β€” compact, deterministic, fingerprint-gated (see `scripts/codegraph-report.mjs`) - **Gitignored:** `.codegraph/codegraph.db`, `.codegraph/codegraph.db-shm`, `.codegraph/codegraph.db-wal` -- **Regenerate locally:** `pnpm run codegraph:update` or `pnpm run graphs:update` +- **Regenerate report locally:** `pnpm run codegraph:report` or `pnpm run graphs:report` (requires a clean source tree β€” refuses on `DIRTY_UNTRACKED_INPUT`) ## Troubleshooting | Problem | Solution | |---------|----------| -| **"CodeGraph not initialized"** | Run `codegraph init -i` in repo root | +| **"CodeGraph not initialized"** | Run `pnpm run codegraph:init` in repo root (current versions build the index in this one step) | | **"database is locked"** | Ensure WAL mode is active (`codegraph status` β†’ `Journal: wal`). If on a network share or WSL2 `/mnt/`, move the project to a local disk | -| **Missing symbols after save** | Wait 2s (auto-sync debounce) or run `codegraph sync` | -| **MCP server not connecting** | Verify `codegraph serve --mcp` works from the terminal. Check the path in your MCP config | -| **Index is stale** | `pnpm run codegraph:update` | -| **Large `.codegraph/` folder** | Normal β€” SQLite + WAL can be 5–15 MB for this codebase. It is gitignored | +| **Missing symbols after save** | Wait for the auto-sync debounce (`CODEGRAPH_WATCH_DEBOUNCE_MS`, default well under a second) or run `codegraph sync` | +| **MCP server not connecting / `claude mcp list` shows "Disabled"** | Verify `codegraph serve --mcp` responds to a raw `initialize` request from the terminal β€” if it does, this is the known display quirk above, not a real disablement. Check `~/.claude.json`'s `disabledMcpServers` for the exact repo-path key to confirm the config itself is clean | +| **Index feels stale after a large refactor** | `pnpm run codegraph:update` (full rebuild) β€” routine edits should use `pnpm run codegraph:sync` instead | +| **Large `.codegraph/` folder** | Normal β€” SQLite + WAL scales with codebase size. It is gitignored | ## See Also diff --git a/docs/dual-graph-setup.md b/docs/dual-graph-setup.md index d7f1be2e..e26d78be 100644 --- a/docs/dual-graph-setup.md +++ b/docs/dual-graph-setup.md @@ -17,23 +17,50 @@ WorldScript Studio uses **two complementary knowledge-graph tools** to provide m ## Quick Start for New Machines +Both tools' tested versions live in [`config/graph-tools-versions.json`](../config/graph-tools-versions.json) β€” the bootstrap commands below read from it, never hardcode a version here. + ```bash # 1. Node dependencies node scripts/dependency-state.mjs reconcile -# 2. Graphify (requires Python 3.10+) -pnpm run graphify:bootstrap # pip install graphifyy -pnpm run graphify:update # build AST graph +# 2. Optional privacy controls before the first CodeGraph invocation (local shell only) +export CODEGRAPH_TELEMETRY=0 CODEGRAPH_NO_UPDATE_CHECK=1 + +# 3. Install both tools at their pinned versions (Graphify needs Python 3.10+; CodeGraph needs Node/npm) +pnpm run graphs:bootstrap + +# 4. Read-only diagnostic: installed versions and any existing report freshness +pnpm run graphs:doctor -# 3. CodeGraph (requires Node/npm) -npm install -g @colbymchenry/codegraph -codegraph init -i +# 5. Initialize CodeGraph's local index for this worktree through the verified resolver +pnpm run codegraph:init -# 4. Configure your agent +# 6. Update local runtime state + regenerate the two committed reports (requires a clean tree) +pnpm run graphs:refresh + +# 7. Configure your agent's MCP client (local, machine-personal β€” not inherited from git) +# Claude Code β†’ codegraph install --target=claude (see docs/codegraph.md) +# Cursor β†’ codegraph install --target=cursor --yes # Kimi Code CLI β†’ add MCP server to ~/.kimi/settings.json (see docs/codegraph.md) -# Cursor β†’ run: codegraph install --target=cursor --yes + +# 8. Choose Graphify (architecture/topology) vs. CodeGraph (symbol/impact) vs. raw grep β€” +# see "Tool Selection Guide" below. ``` +`graphs:doctor` is safe before initialization: missing reports and an uninitialized CodeGraph index +are reported diagnostically. When reports exist it also displays their shared freshness diagnosis, +but it remains non-blocking for onboarding. Use `graphs:status` after setup as the authoritative, +non-zero freshness check; it requires both committed reports to exist and match the current source +fingerprint and tested tool versions. `graphs:status` can return non-zero for `MISSING`, `STALE` +(including a fingerprint mismatch), `VERSION_MISMATCH` (report schema or tool version), +`REPORT_INVALID` (metadata matches but the committed body is not a valid generated report), +`DIRTY_UNTRACKED_INPUT`, or an unstable source snapshot. + +For local admission, run `pnpm run ci:prepush` as required by the constrained-hardware policy. It +performs the change-aware lightweight checks and fails closed when evidence is ambiguous; full +repository lint, complete typecheck, i18n, coverage, E2E, and other heavyweight checks remain +cloud-CI gates rather than a second full local suite. + ## Daily Workflow ### Session Start (Plan Mode / Composer / Agent) @@ -50,8 +77,11 @@ Before planning or implementing: # Small changes (< 5 files) β€” nothing needed # CodeGraph auto-syncs via file watcher -# Large refactors / new modules: -pnpm run graphs:update # updates both Graphify and CodeGraph +# Large refactors / new modules β€” local runtime state only, doesn't touch committed reports: +pnpm run graphs:update + +# Before opening a PR β€” regenerate the committed reports too (requires a clean tree): +pnpm run graphs:refresh ``` ### Before Commits @@ -60,8 +90,9 @@ pnpm run graphs:update # updates both Graphify and CodeGraph # Optional: see which tests are affected pnpm run codegraph:affected -# Full quality gate -pnpm run lint && pnpm run typecheck && pnpm run i18n:check +# Required constrained-hardware gate (see docs/PR-CI-MERGE-WORKFLOW.md) β€” not the full +# lint/typecheck/i18n suite, which is CI-owned: +pnpm run ci:prepush ``` ## Tool Selection Guide @@ -77,7 +108,11 @@ pnpm run lint && pnpm run typecheck && pnpm run i18n:check | "Find all uses of `useAppDispatch`" | CodeGraph (`codegraph_search`) | β€” | | "Cross-module impact of a new AI provider" | Both | β€” | -## Prompt Templates for Kimi K2.6 +## Prompt Templates for Kimi K2.6 (optional reference β€” not required setup) + +Claude Code's own graph-usage instructions live directly in `CLAUDE.md` and don't need a separate +template. The templates below are optional reference material if you're driving this repo through +Kimi K2.6 or a similarly prompted agent that needs the same guidance spelled out explicitly. ### Template A: Feature Development @@ -159,20 +194,22 @@ workers/ β†’ CodeGraph: worker entrypoints | Problem | Solution | |---------|----------| -| Graphify not found | `pnpm run graphify:bootstrap` | -| CodeGraph not initialized | `codegraph init -i` | +| Graphify not found | `pnpm run graphify:bootstrap` (or `pnpm run graphs:bootstrap` for both tools) | +| CodeGraph not initialized | `codegraph init` (builds the index in this one step) | | CodeGraph DB locked | Ensure project is on local disk (not WSL `/mnt/` or network share) | -| Both reports outdated | `pnpm run graphs:update` | +| Both reports outdated | `pnpm run graphs:status` to confirm, then `pnpm run graphs:refresh` to regenerate (requires a clean tree) | +| Report generation refused (`DIRTY_UNTRACKED_INPUT`) | Commit or stash the listed paths first β€” reports are only generated from a stable, committable source state | | Slow Graphify build | Check `.graphifyignore`; ensure `node_modules/` is excluded | | Agent ignores CodeGraph | Add "Use CodeGraph first" to your session prompt | +| `claude mcp list` shows CodeGraph "Disabled" | Known display quirk β€” see `docs/codegraph.md`'s Claude Code section | ## Privacy & Security -- Both tools are **100% offline** -- No API keys required -- No data leaves the machine -- `.codegraph/` and `graphify-out/` are gitignored (only `*_REPORT.md` committed) -- Safe to use on proprietary code +- The source parsing and local index for the default AST/code-intelligence paths stay local, but CodeGraph's anonymous usage telemetry is enabled by default and can make network calls. Disable it with `codegraph telemetry off`, `CODEGRAPH_TELEMETRY=0`, or `DO_NOT_TRACK=1`; disable its separate update check with `CODEGRAPH_NO_UPDATE_CHECK=1` (full disclosure in [CodeGraph's TELEMETRY.md](https://github.com/colbymchenry/codegraph/blob/main/TELEMETRY.md)). +- Graphify's separate semantic/LLM rebuild mode (`/graphify .` in chat) is also networked and provider-dependent; the AST-only Graphify path does not require that mode. +- No API keys required for either tool's core functionality. +- Graphify can optionally log queries locally to `~/.cache/graphify-queries.log` β€” off by default since `graphifyy` v0.9.13 (see `docs/graphify.md`'s Privacy section for the exact env vars). +- `.codegraph/` and `graphify-out/` are gitignored (only `*_REPORT.md` committed). --- diff --git a/docs/graphify.md b/docs/graphify.md index 0c78738e..d46e3e1d 100644 --- a/docs/graphify.md +++ b/docs/graphify.md @@ -1,36 +1,45 @@ # Graphify β€” Knowledge Graph Setup -WorldScript Studio has a fully configured [graphify](https://github.com/safishamsi/graphify) knowledge graph. +WorldScript Studio has a fully configured [graphify](https://github.com/Graphify-Labs/graphify) knowledge graph (repo moved from `safishamsi/graphify`; the old URL still resolves). Graph output lives at `graphify-out/`. **Solo-repo policy (this project):** only `graphify-out/GRAPH_REPORT.md` is committed; `graph.json`, `graph.html`, and `cache/` stay local and are regenerated with `pnpm run graphify:update`. **Other docs:** CI and automation β†’ [`CI.md`](CI.md); full documentation map β†’ [`README.md`](../README.md#-documentation-hub) *Documentation Hub*; inventory of all maintainer `.md` files β†’ [`AUDIT.md`](../AUDIT.md). **Dual-Graph master guide:** [`docs/dual-graph-setup.md`](dual-graph-setup.md) β€” how Graphify and CodeGraph work together. -**Official PyPI name:** `graphifyy` (double **y**). The CLI is still `graphify`. `pip install graphify` can pull an **unrelated** package β€” always use `graphifyy`. -**Current pinned version:** `graphifyy==0.8.26` β€” install the same version locally for graph parity. +**Official PyPI name:** `graphifyy` (double **y**). The CLI is still `graphify`. `pip install graphify` can pull an **unrelated** package β€” always use `graphifyy`. +**Version policy:** the single source of truth is [`config/graph-tools-versions.json`](../config/graph-tools-versions.json) β€” currently pinned to `graphifyy==0.9.51` under a `controlled-upgrade` policy (see that file's `notes` for the evaluated 0.8.26β†’0.9.51 changes, including a self-migrating node-ID format change in v0.9.0). Don't hardcode the version elsewhere; `pnpm run graphify:bootstrap` reads it from there. --- ## Installation (Python) -Pick **one** install path; all provide the `graphify` command (or `python -m graphify`). +`pnpm run graphify:bootstrap` installs the exact pinned version automatically, trying these in order β€” +whichever is available on your machine β€” and never falling back to an unpinned "latest" install: -| Method | Command | Notes | -|--------|---------|--------| -| **pip** (common) | `pip install graphifyy` | On Windows, `graphify.exe` may land in `%APPDATA%\Python\Python3xx\Scripts` β€” often **not** on `PATH` until you add it. | -| **pipx** | `pipx install graphifyy` | Isolated env; run `pipx ensurepath` if the CLI is missing. | -| **uv** | `uv tool install graphifyy` | Often keeps tools on `PATH` without extra setup. | +| Priority | Method | Command it runs | +|----------|--------|--------| +| 1 | **uv** | `uv tool install --force graphifyy==` β€” replaces an older exact-pinned tool on `PATH` | +| 2 | **pipx** | `pipx install --force graphifyy==` β€” replaces an older isolated tool; run `pipx ensurepath` if the CLI is missing | +| 3 | **pip** | `python -m pip install graphifyy==` β€” on Windows, `graphify.exe` may land in `%APPDATA%\Python\Python3xx\Scripts`, often **not** on `PATH` until added | + +All three provide the same `graphify` command (or `python -m graphify`). Which one actually runs on a +given machine is local evidence of what's installed there, not a portability requirement β€” a fresh +clone on a different machine may resolve through a different one of the three, and that's fine. ### One-time setup in this repo From the repository root (after Node deps: `node scripts/dependency-state.mjs reconcile`): ```bash -pnpm run graphify:bootstrap # pip install graphifyy (first machine only; requires Python 3.11+ with pip) -pnpm run graphify:install # registers Claude / VS Code / Copilot integrations (upstream `graphify install`) -pnpm run graphify:hooks # optional: install post-commit / post-checkout hooks that run `graphify update .` +pnpm run graphify:bootstrap # installs the exact pinned version (see config/graph-tools-versions.json) pnpm run graphify:update # generate AST graph under graphify-out/ (no API cost) +pnpm run graphs:doctor # read-only: confirm installed version matches policy, check report freshness ``` +`pnpm run graphify:install` (registers Claude/VS Code/Copilot editor integrations) and +`pnpm run graphify:hooks` (git post-commit/post-checkout auto-update) are **optional, not part of the +one-time setup** β€” see the caution under [Automatic updates](#automatic-updates) below before running +either. + **Windows:** If `python` opens the Microsoft Store or `graphify` is β€œnot found”, install Python from **python.org** (tick **Add to PATH**), then run `pnpm run graphify:bootstrap` again. **pnpm wrappers:** [`scripts/graphify-cli.mjs`](../scripts/graphify-cli.mjs) tries `graphify` on `PATH`, then `py -m graphify` / `python -m graphify`, so **`pnpm run graphify:*` works even when Windows did not add pip’s `Scripts` folder to `PATH`**. @@ -45,48 +54,40 @@ Tasks are pre-defined in [`.vscode/tasks.json`](../.vscode/tasks.json) (e.g. **G | Component | Location | Purpose | |-----------|----------|---------| -| `.graphifyignore` | repo root | Excludes `node_modules/`, `dist/`, `coverage/`, `graphify-out/`, binaries, `.env` | +| `config/graph-tools-versions.json` | repo root `config/` | Sole version-policy source for both Graphify and CodeGraph | +| `.graphifyignore` | repo root | Excludes `node_modules/`, `dist/`, `coverage/`, `graphify-out/`, `.codegraph/`, `.claude/`, `.git/`, worktrees, binaries, `.env` | | Solo git policy | `.gitignore` | `graphify-out/*` ignored except `GRAPH_REPORT.md` (no multi-MB HTML/JSON history in git) | -| `graphify-update.mjs` | `scripts/` | Cleans ephemeral outputs, then `graphify update .` | +| `graphify-update.mjs` | `scripts/` | Cleans ephemeral outputs, then runs the heavy direct `graphify update .`; it may replace the native committed report, so prefer `graphs:update` for report-preserving maintenance | +| `graphify-report.mjs` | `scripts/` | Regenerates the committed compact `GRAPH_REPORT.md`, gated on a clean source tree | +| `graphify-bootstrap.mjs` | `scripts/` | Portable pinned install (uv β†’ pipx β†’ pip), reads `config/graph-tools-versions.json` | | `graphify-cli.mjs` | `scripts/` | PATH-independent launcher used by `pnpm run graphify:*` | +| `graphSourceFingerprint.mjs` | `scripts/` | Shared worktree-aware fingerprint module (freshness, both tools) | +| `graphs-cli.mjs` | `scripts/` | Combined dual-graph orchestrator β€” `pnpm run graphs:*` | | Claude Code integration | `CLAUDE.md` + `graphify install` | PreToolUse hook + instructions | | VS Code Copilot integration | `.github/copilot-instructions.md` | Copilot Chat reads the graph | -| Git hooks | optional, via `pnpm run graphify:hooks` | Auto `graphify update .` after commit/checkout | +| Git hooks | optional, via `pnpm run graphify:hooks` | Not recommended by default β€” see [Automatic updates](#automatic-updates) | ### npm/pnpm scripts | Script | Purpose | |--------|---------| -| `pnpm run graphify:bootstrap` | `pip install graphifyy` via Python (first-time setup) | -| `pnpm run graphify:install` | `graphify install` (skills / editor hooks) | -| `pnpm run graphify:update` | `graphify update .` β€” refresh AST graph (CPU/RAM heavy; not in pre-commit) | +| `pnpm run graphify:bootstrap` | Installs the exact pinned version (uv β†’ pipx β†’ pip) | +| `pnpm run graphify:install` | `graphify install` (skills / editor hooks) β€” inspect before running with `--project` | +| `pnpm run graphify:update` | Direct `graphify update .` refresh (CPU/RAM heavy; may rewrite `GRAPH_REPORT.md`; not in pre-commit) | | `GRAPHIFY_SKIP=1 pnpm run graphify:update` | Skip update (no-op) | -| `pnpm run graphify:hooks` | `graphify hook install` β€” git hooks for auto-update | +| `pnpm run graphify:hooks` | `graphify hook install` β€” not recommended by default, see above | | `pnpm run graphify:status` | `graphify hook status` | +| `pnpm run graphs:doctor` / `graphs:status` / `graphs:update` / `graphs:report` / `graphs:refresh` / `graphs:bootstrap` | Combined dual-graph interface β€” see [`dual-graph-setup.md`](dual-graph-setup.md) | --- -## Graph stats (last build: 2026-04-30) - -- **178 files** Β· ~102,700 words -- **566 nodes** Β· **703 edges** Β· **20 communities** -- 87 % EXTRACTED Β· 13 % INFERRED (88 inferred edges, avg confidence 0.8) -- Build cost: **0 tokens** (AST-only) +## Current graph stats -### God Nodes (most connected abstractions) - -| Rank | Node | Edges | -|------|------|-------| -| 1 | `IndexedDBService` | 38 | -| 2 | `FileSystemService` | 35 | -| 3 | `StorageManager` | 30 | -| 4 | `retryFs()` | 26 | -| 5 | `useTranslation()` | 18 | -| 6 | `sanitizePathSegment()` | 14 | -| 7 | `CollaborationService` | 14 | -| 8 | `useAppDispatch()` | 13 | -| 9 | `t()` | 13 | -| 10 | `useToast()` | 8 | +Hardcoding a stats snapshot here always drifts out of sync with the real graph on the next build β€” +this is exactly what happened to this section previously (it showed a build from months earlier). +**Current stats, God Nodes, and freshness live in the committed report's own header:** +[`graphify-out/GRAPH_REPORT.md`](../graphify-out/GRAPH_REPORT.md). Check `pnpm run graphs:status` to +see at a glance whether that report is `FRESH` or `STALE` relative to the current source tree. --- @@ -95,6 +96,8 @@ Tasks are pre-defined in [`.vscode/tasks.json`](../.vscode/tasks.json) (e.g. **G ### After code changes (no API cost) ```bash +pnpm run graphs:update # preferred: update local runtimes while preserving compact reports +# Direct maintenance only: may replace graphify-out/GRAPH_REPORT.md with native output. pnpm run graphify:update # or, if `graphify` is on your PATH: graphify update . @@ -141,27 +144,44 @@ Open `graphify-out/graph.html` in any browser β€” interactive D3 visualization o ## Automatic updates -After **`pnpm run graphify:hooks`**, Graphify can refresh the graph on **post-commit** and **post-checkout** (see `graphify hook status`). Without hooks, run **`pnpm run graphify:update`** after larger refactors. +`pnpm run graphify:hooks` (`graphify hook install`) can refresh the graph automatically on +**post-commit**/**post-checkout** via Graphify's *own* hook-installer β€” a separate mechanism from this +repo's `simple-git-hooks` setup. **Not recommended by default:** it appends to whatever hook file +already exists there rather than replacing it, so two independent hook-installing systems would +coexist unpredictably, and it adds latency to every commit on constrained hardware. Prefer explicit, +on-demand refresh instead: ```bash -pnpm run graphify:status +pnpm run graphs:update # local runtime state only; Graphify performs a heavy rebuild +pnpm run graphs:refresh # update + regenerate the committed report, strict β€” run before a PR +pnpm run graphs:status # fast read-only freshness check (FRESH/STALE), no mutation ``` +If you've measured a real, compelling benefit from the hooks on your own machine and understand the +dual-installer risk, `pnpm run graphify:hooks` remains available β€” but it's an opt-in exception, not +the default workflow this repo recommends. + --- -## Fine-tuning what gets indexed +## Privacy β€” query logging -Edit `.graphifyignore` (same syntax as `.gitignore`). Current exclusions: +Graphify can optionally log every `query`/`path`/`explain`/MCP query to `~/.cache/graphify-queries.log` +(JSON Lines: timestamp, question, corpus, nodes returned, duration). **This is OFF by default** as of +`graphifyy` v0.9.13 (the pinned `0.9.51` postdates that fix). If you ever want a hard guarantee it stays +off regardless of future config, set `GRAPHIFY_QUERY_LOG_DISABLE=1`; `GRAPHIFY_QUERY_LOG_ENABLE=1` / +`GRAPHIFY_QUERY_LOG=` opt back in if you ever want it. This is a local, per-machine preference β€” +never committed to the repo. The Graphify AST portion of `graphs:update` does not require network +access. The combined command also runs CodeGraph synchronization; its default telemetry and +update-check behavior is controlled by `codegraph telemetry off`, `CODEGRAPH_TELEMETRY=0`, +`DO_NOT_TRACK=1`, and the separate `CODEGRAPH_NO_UPDATE_CHECK=1` update-check control. Only the +semantic/LLM rebuild mode (`/graphify .` in chat, see [Full semantic rebuild](#full-semantic-rebuild-uses-llm-costs-tokens) +above) and this query log touch anything outside the local Graphify build. -``` -dist/ src-tauri/target/ node_modules/ -coverage/ reports/ test-results/ -playwright-report/ graphify-out/ -pnpm-lock.yaml *.lock *.log -*.png *.jpg *.woff *.woff2 ... (binary/media) -storybook-static/ .vscode/ .idea/ -.env .env.* -``` +--- + +## Fine-tuning what gets indexed + +Edit `.graphifyignore` (same syntax as `.gitignore`) β€” see the file itself for the current, authoritative exclusion list (build outputs, `node_modules/`, test artifacts, `graphify-out/` self-exclusion, `.codegraph/`'s own local index, `.claude/`, `.git/`, sibling git worktrees, binaries/media, secrets). Don't duplicate that list here where it can drift out of sync. --- @@ -221,7 +241,7 @@ The CLAUDE.md section also instructs Claude to: |---------|-----| | **Windows:** `graphify` not recognized after `pip install graphifyy` | Pip installs `graphify.exe` under **`%APPDATA%\Python\Python3xx\Scripts`** (see pip’s warning). Add that folder to your **user PATH**, open a new terminal, **or** use `pnpm run graphify:*` / `py -m graphify …` (see [`scripts/graphify-cli.mjs`](../scripts/graphify-cli.mjs)). | | **`graphify` / `uv` not on PATH** (uv/pipx) | Add uv’s bin (`uv tool dir` / `%USERPROFILE%\.local\bin`) or run `pipx ensurepath`; restart the terminal. | -| `graphify: command not found` | Prefer **`pnpm run graphify:update`** / **`pnpm run graphify:install`**, or install via **`pipx install graphifyy`** / **`uv tool install graphifyy`**. | +| `graphify: command not found` | Run **`pnpm run graphify:bootstrap`** to install the exact policy pin. For a PATH-only failure after installation, prefer **`pnpm run graphify:update`** / **`pnpm run graphify:install`**, whose wrapper also tries supported Python-module fallbacks. | | Graph is stale | `graphify update .` | | Hook not firing | `graphify hook install` | | VS Code Copilot not reading graph | `graphify vscode install` | diff --git a/graphify-out/GRAPH_REPORT.md b/graphify-out/GRAPH_REPORT.md index 9613f36b..f79cc940 100644 --- a/graphify-out/GRAPH_REPORT.md +++ b/graphify-out/GRAPH_REPORT.md @@ -1,4528 +1,169 @@ -# Graph Report - WorldScript-Studio (2026-08-01) +# Graph Report - worldscript-studio + +Report schema: 1 +Source fingerprint: sha256:327ee3443156f26862b82a89db69efde7240173d4730246aee39df4f13539c56 +Tool: graphify +Tool version: 0.9.51 +Generation mode: AST-only local build (graphify update .) ## Corpus Check -- 1826 files Β· ~1,906,559 words +- 2053 files Β· ~2,176,128 words - Verdict: corpus is large enough that graph structure adds value. ## Summary -- 67859 nodes Β· 78542 edges Β· 974 communities (914 shown, 60 thin omitted) -- Extraction: 98% EXTRACTED Β· 2% INFERRED Β· 0% AMBIGUOUS Β· INFERRED: 1585 edges (avg confidence: 0.8) +- 12269 nodes Β· 24866 edges Β· 713 communities (607 shown, 106 thin omitted) +- Extraction: 99% EXTRACTED Β· 1% INFERRED Β· 0% AMBIGUOUS Β· INFERRED: 286 edges (avg confidence: 0.83) - Token cost: 0 input Β· 0 output -## Graph Freshness -- Built from commit: `10261d38` -- Run `git rev-parse HEAD` and compare to check if the graph is stale. -- Run `graphify update .` after code changes (no API cost). - -## Community Hubs (Navigation) -- [[_COMMUNITY_Community 0|Community 0]] -- [[_COMMUNITY_Community 1|Community 1]] -- [[_COMMUNITY_Community 2|Community 2]] -- [[_COMMUNITY_Community 3|Community 3]] -- [[_COMMUNITY_Community 4|Community 4]] -- [[_COMMUNITY_Community 5|Community 5]] -- [[_COMMUNITY_Community 6|Community 6]] -- [[_COMMUNITY_Community 7|Community 7]] -- [[_COMMUNITY_Community 8|Community 8]] -- [[_COMMUNITY_Community 9|Community 9]] -- [[_COMMUNITY_Community 10|Community 10]] -- [[_COMMUNITY_Community 11|Community 11]] -- [[_COMMUNITY_Community 12|Community 12]] -- [[_COMMUNITY_Community 13|Community 13]] -- [[_COMMUNITY_Community 14|Community 14]] -- [[_COMMUNITY_Community 15|Community 15]] -- [[_COMMUNITY_Community 16|Community 16]] -- [[_COMMUNITY_Community 17|Community 17]] -- [[_COMMUNITY_Community 18|Community 18]] -- [[_COMMUNITY_Community 19|Community 19]] -- [[_COMMUNITY_Community 20|Community 20]] -- [[_COMMUNITY_Community 21|Community 21]] -- [[_COMMUNITY_Community 22|Community 22]] -- [[_COMMUNITY_Community 23|Community 23]] -- [[_COMMUNITY_Community 24|Community 24]] -- [[_COMMUNITY_Community 25|Community 25]] -- [[_COMMUNITY_Community 26|Community 26]] -- [[_COMMUNITY_Community 27|Community 27]] -- [[_COMMUNITY_Community 28|Community 28]] -- [[_COMMUNITY_Community 29|Community 29]] -- [[_COMMUNITY_Community 30|Community 30]] -- [[_COMMUNITY_Community 31|Community 31]] -- [[_COMMUNITY_Community 32|Community 32]] -- [[_COMMUNITY_Community 33|Community 33]] -- [[_COMMUNITY_Community 34|Community 34]] -- [[_COMMUNITY_Community 35|Community 35]] -- [[_COMMUNITY_Community 36|Community 36]] -- [[_COMMUNITY_Community 37|Community 37]] -- [[_COMMUNITY_Community 38|Community 38]] -- [[_COMMUNITY_Community 39|Community 39]] -- [[_COMMUNITY_Community 40|Community 40]] -- [[_COMMUNITY_Community 41|Community 41]] -- [[_COMMUNITY_Community 42|Community 42]] -- [[_COMMUNITY_Community 43|Community 43]] -- [[_COMMUNITY_Community 44|Community 44]] -- [[_COMMUNITY_Community 45|Community 45]] -- [[_COMMUNITY_Community 46|Community 46]] -- [[_COMMUNITY_Community 47|Community 47]] -- [[_COMMUNITY_Community 48|Community 48]] -- [[_COMMUNITY_Community 49|Community 49]] -- [[_COMMUNITY_Community 50|Community 50]] -- [[_COMMUNITY_Community 51|Community 51]] -- [[_COMMUNITY_Community 52|Community 52]] -- [[_COMMUNITY_Community 53|Community 53]] -- [[_COMMUNITY_Community 54|Community 54]] -- [[_COMMUNITY_Community 55|Community 55]] -- [[_COMMUNITY_Community 56|Community 56]] -- [[_COMMUNITY_Community 57|Community 57]] -- [[_COMMUNITY_Community 58|Community 58]] -- [[_COMMUNITY_Community 59|Community 59]] -- [[_COMMUNITY_Community 60|Community 60]] -- [[_COMMUNITY_Community 61|Community 61]] -- [[_COMMUNITY_Community 62|Community 62]] -- [[_COMMUNITY_Community 63|Community 63]] -- [[_COMMUNITY_Community 64|Community 64]] -- [[_COMMUNITY_Community 65|Community 65]] -- [[_COMMUNITY_Community 66|Community 66]] -- [[_COMMUNITY_Community 67|Community 67]] -- [[_COMMUNITY_Community 68|Community 68]] -- [[_COMMUNITY_Community 69|Community 69]] -- [[_COMMUNITY_Community 70|Community 70]] -- [[_COMMUNITY_Community 71|Community 71]] -- [[_COMMUNITY_Community 72|Community 72]] -- [[_COMMUNITY_Community 73|Community 73]] -- [[_COMMUNITY_Community 74|Community 74]] -- [[_COMMUNITY_Community 75|Community 75]] -- [[_COMMUNITY_Community 76|Community 76]] -- [[_COMMUNITY_Community 77|Community 77]] -- [[_COMMUNITY_Community 78|Community 78]] -- [[_COMMUNITY_Community 79|Community 79]] -- [[_COMMUNITY_Community 80|Community 80]] -- [[_COMMUNITY_Community 81|Community 81]] -- [[_COMMUNITY_Community 82|Community 82]] -- [[_COMMUNITY_Community 83|Community 83]] -- [[_COMMUNITY_Community 84|Community 84]] -- [[_COMMUNITY_Community 85|Community 85]] -- [[_COMMUNITY_Community 86|Community 86]] -- [[_COMMUNITY_Community 87|Community 87]] -- [[_COMMUNITY_Community 88|Community 88]] -- [[_COMMUNITY_Community 89|Community 89]] -- [[_COMMUNITY_Community 90|Community 90]] -- [[_COMMUNITY_Community 91|Community 91]] -- [[_COMMUNITY_Community 92|Community 92]] -- [[_COMMUNITY_Community 93|Community 93]] -- [[_COMMUNITY_Community 94|Community 94]] -- [[_COMMUNITY_Community 95|Community 95]] -- [[_COMMUNITY_Community 96|Community 96]] -- [[_COMMUNITY_Community 97|Community 97]] -- [[_COMMUNITY_Community 98|Community 98]] -- [[_COMMUNITY_Community 99|Community 99]] -- [[_COMMUNITY_Community 100|Community 100]] -- [[_COMMUNITY_Community 101|Community 101]] -- [[_COMMUNITY_Community 103|Community 103]] -- [[_COMMUNITY_Community 104|Community 104]] -- [[_COMMUNITY_Community 105|Community 105]] -- [[_COMMUNITY_Community 106|Community 106]] -- [[_COMMUNITY_Community 107|Community 107]] -- [[_COMMUNITY_Community 108|Community 108]] -- [[_COMMUNITY_Community 109|Community 109]] -- [[_COMMUNITY_Community 110|Community 110]] -- [[_COMMUNITY_Community 111|Community 111]] -- [[_COMMUNITY_Community 112|Community 112]] -- [[_COMMUNITY_Community 113|Community 113]] -- [[_COMMUNITY_Community 114|Community 114]] -- [[_COMMUNITY_Community 115|Community 115]] -- [[_COMMUNITY_Community 116|Community 116]] -- [[_COMMUNITY_Community 117|Community 117]] -- [[_COMMUNITY_Community 118|Community 118]] -- [[_COMMUNITY_Community 119|Community 119]] -- [[_COMMUNITY_Community 120|Community 120]] -- [[_COMMUNITY_Community 121|Community 121]] -- [[_COMMUNITY_Community 122|Community 122]] -- [[_COMMUNITY_Community 123|Community 123]] -- [[_COMMUNITY_Community 124|Community 124]] -- [[_COMMUNITY_Community 125|Community 125]] -- [[_COMMUNITY_Community 126|Community 126]] -- [[_COMMUNITY_Community 127|Community 127]] -- [[_COMMUNITY_Community 128|Community 128]] -- [[_COMMUNITY_Community 129|Community 129]] -- [[_COMMUNITY_Community 130|Community 130]] -- [[_COMMUNITY_Community 131|Community 131]] -- [[_COMMUNITY_Community 132|Community 132]] -- [[_COMMUNITY_Community 133|Community 133]] -- [[_COMMUNITY_Community 134|Community 134]] -- [[_COMMUNITY_Community 135|Community 135]] -- [[_COMMUNITY_Community 136|Community 136]] -- [[_COMMUNITY_Community 137|Community 137]] -- [[_COMMUNITY_Community 138|Community 138]] -- [[_COMMUNITY_Community 139|Community 139]] -- [[_COMMUNITY_Community 140|Community 140]] -- [[_COMMUNITY_Community 141|Community 141]] -- [[_COMMUNITY_Community 142|Community 142]] -- [[_COMMUNITY_Community 143|Community 143]] -- [[_COMMUNITY_Community 144|Community 144]] -- [[_COMMUNITY_Community 145|Community 145]] -- [[_COMMUNITY_Community 146|Community 146]] -- [[_COMMUNITY_Community 147|Community 147]] -- [[_COMMUNITY_Community 148|Community 148]] -- [[_COMMUNITY_Community 149|Community 149]] -- [[_COMMUNITY_Community 150|Community 150]] -- [[_COMMUNITY_Community 151|Community 151]] -- [[_COMMUNITY_Community 152|Community 152]] -- [[_COMMUNITY_Community 153|Community 153]] -- [[_COMMUNITY_Community 154|Community 154]] -- [[_COMMUNITY_Community 155|Community 155]] -- [[_COMMUNITY_Community 156|Community 156]] -- [[_COMMUNITY_Community 157|Community 157]] -- [[_COMMUNITY_Community 158|Community 158]] -- [[_COMMUNITY_Community 159|Community 159]] -- [[_COMMUNITY_Community 160|Community 160]] -- [[_COMMUNITY_Community 161|Community 161]] -- [[_COMMUNITY_Community 162|Community 162]] -- [[_COMMUNITY_Community 163|Community 163]] -- [[_COMMUNITY_Community 164|Community 164]] -- [[_COMMUNITY_Community 165|Community 165]] -- [[_COMMUNITY_Community 166|Community 166]] -- [[_COMMUNITY_Community 167|Community 167]] -- [[_COMMUNITY_Community 168|Community 168]] -- [[_COMMUNITY_Community 169|Community 169]] -- [[_COMMUNITY_Community 170|Community 170]] -- [[_COMMUNITY_Community 171|Community 171]] -- [[_COMMUNITY_Community 172|Community 172]] -- [[_COMMUNITY_Community 173|Community 173]] -- [[_COMMUNITY_Community 174|Community 174]] -- [[_COMMUNITY_Community 175|Community 175]] -- [[_COMMUNITY_Community 176|Community 176]] -- [[_COMMUNITY_Community 177|Community 177]] -- [[_COMMUNITY_Community 178|Community 178]] -- [[_COMMUNITY_Community 179|Community 179]] -- [[_COMMUNITY_Community 180|Community 180]] -- [[_COMMUNITY_Community 181|Community 181]] -- [[_COMMUNITY_Community 182|Community 182]] -- [[_COMMUNITY_Community 183|Community 183]] -- [[_COMMUNITY_Community 184|Community 184]] -- [[_COMMUNITY_Community 185|Community 185]] -- [[_COMMUNITY_Community 186|Community 186]] -- [[_COMMUNITY_Community 187|Community 187]] -- [[_COMMUNITY_Community 188|Community 188]] -- [[_COMMUNITY_Community 189|Community 189]] -- [[_COMMUNITY_Community 190|Community 190]] -- [[_COMMUNITY_Community 191|Community 191]] -- [[_COMMUNITY_Community 192|Community 192]] -- [[_COMMUNITY_Community 193|Community 193]] -- [[_COMMUNITY_Community 194|Community 194]] -- [[_COMMUNITY_Community 195|Community 195]] -- [[_COMMUNITY_Community 196|Community 196]] -- [[_COMMUNITY_Community 197|Community 197]] -- [[_COMMUNITY_Community 198|Community 198]] -- [[_COMMUNITY_Community 199|Community 199]] -- [[_COMMUNITY_Community 200|Community 200]] -- [[_COMMUNITY_Community 201|Community 201]] -- [[_COMMUNITY_Community 202|Community 202]] -- [[_COMMUNITY_Community 203|Community 203]] -- [[_COMMUNITY_Community 204|Community 204]] -- [[_COMMUNITY_Community 205|Community 205]] -- [[_COMMUNITY_Community 206|Community 206]] -- [[_COMMUNITY_Community 207|Community 207]] -- [[_COMMUNITY_Community 208|Community 208]] -- [[_COMMUNITY_Community 209|Community 209]] -- [[_COMMUNITY_Community 210|Community 210]] -- [[_COMMUNITY_Community 211|Community 211]] -- [[_COMMUNITY_Community 212|Community 212]] -- [[_COMMUNITY_Community 213|Community 213]] -- [[_COMMUNITY_Community 214|Community 214]] -- [[_COMMUNITY_Community 215|Community 215]] -- [[_COMMUNITY_Community 216|Community 216]] -- [[_COMMUNITY_Community 217|Community 217]] -- [[_COMMUNITY_Community 218|Community 218]] -- [[_COMMUNITY_Community 219|Community 219]] -- [[_COMMUNITY_Community 220|Community 220]] -- [[_COMMUNITY_Community 221|Community 221]] -- [[_COMMUNITY_Community 222|Community 222]] -- [[_COMMUNITY_Community 223|Community 223]] -- [[_COMMUNITY_Community 224|Community 224]] -- [[_COMMUNITY_Community 225|Community 225]] -- [[_COMMUNITY_Community 226|Community 226]] -- [[_COMMUNITY_Community 227|Community 227]] -- [[_COMMUNITY_Community 228|Community 228]] -- [[_COMMUNITY_Community 229|Community 229]] -- [[_COMMUNITY_Community 230|Community 230]] -- [[_COMMUNITY_Community 231|Community 231]] -- [[_COMMUNITY_Community 232|Community 232]] -- [[_COMMUNITY_Community 233|Community 233]] -- [[_COMMUNITY_Community 234|Community 234]] -- [[_COMMUNITY_Community 235|Community 235]] -- [[_COMMUNITY_Community 236|Community 236]] -- [[_COMMUNITY_Community 237|Community 237]] -- [[_COMMUNITY_Community 238|Community 238]] -- [[_COMMUNITY_Community 239|Community 239]] -- [[_COMMUNITY_Community 240|Community 240]] -- [[_COMMUNITY_Community 241|Community 241]] -- [[_COMMUNITY_Community 242|Community 242]] -- [[_COMMUNITY_Community 243|Community 243]] -- [[_COMMUNITY_Community 244|Community 244]] -- [[_COMMUNITY_Community 245|Community 245]] -- [[_COMMUNITY_Community 246|Community 246]] -- [[_COMMUNITY_Community 247|Community 247]] -- [[_COMMUNITY_Community 248|Community 248]] -- [[_COMMUNITY_Community 249|Community 249]] -- [[_COMMUNITY_Community 250|Community 250]] -- [[_COMMUNITY_Community 251|Community 251]] -- [[_COMMUNITY_Community 252|Community 252]] -- [[_COMMUNITY_Community 253|Community 253]] -- [[_COMMUNITY_Community 254|Community 254]] -- [[_COMMUNITY_Community 255|Community 255]] -- [[_COMMUNITY_Community 256|Community 256]] -- [[_COMMUNITY_Community 257|Community 257]] -- [[_COMMUNITY_Community 258|Community 258]] -- [[_COMMUNITY_Community 259|Community 259]] -- [[_COMMUNITY_Community 260|Community 260]] -- [[_COMMUNITY_Community 261|Community 261]] -- [[_COMMUNITY_Community 262|Community 262]] -- [[_COMMUNITY_Community 263|Community 263]] -- [[_COMMUNITY_Community 264|Community 264]] -- [[_COMMUNITY_Community 265|Community 265]] -- [[_COMMUNITY_Community 266|Community 266]] -- [[_COMMUNITY_Community 267|Community 267]] -- [[_COMMUNITY_Community 268|Community 268]] -- [[_COMMUNITY_Community 269|Community 269]] -- [[_COMMUNITY_Community 270|Community 270]] -- [[_COMMUNITY_Community 271|Community 271]] -- [[_COMMUNITY_Community 272|Community 272]] -- [[_COMMUNITY_Community 273|Community 273]] -- [[_COMMUNITY_Community 274|Community 274]] -- [[_COMMUNITY_Community 275|Community 275]] -- [[_COMMUNITY_Community 276|Community 276]] -- [[_COMMUNITY_Community 278|Community 278]] -- [[_COMMUNITY_Community 279|Community 279]] -- [[_COMMUNITY_Community 280|Community 280]] -- [[_COMMUNITY_Community 281|Community 281]] -- [[_COMMUNITY_Community 282|Community 282]] -- [[_COMMUNITY_Community 283|Community 283]] -- [[_COMMUNITY_Community 284|Community 284]] -- [[_COMMUNITY_Community 285|Community 285]] -- [[_COMMUNITY_Community 286|Community 286]] -- [[_COMMUNITY_Community 288|Community 288]] -- [[_COMMUNITY_Community 290|Community 290]] -- [[_COMMUNITY_Community 291|Community 291]] -- [[_COMMUNITY_Community 292|Community 292]] -- [[_COMMUNITY_Community 293|Community 293]] -- [[_COMMUNITY_Community 294|Community 294]] -- [[_COMMUNITY_Community 295|Community 295]] -- [[_COMMUNITY_Community 296|Community 296]] -- [[_COMMUNITY_Community 299|Community 299]] -- [[_COMMUNITY_Community 300|Community 300]] -- [[_COMMUNITY_Community 301|Community 301]] -- [[_COMMUNITY_Community 302|Community 302]] -- [[_COMMUNITY_Community 303|Community 303]] -- [[_COMMUNITY_Community 304|Community 304]] -- [[_COMMUNITY_Community 305|Community 305]] -- [[_COMMUNITY_Community 306|Community 306]] -- [[_COMMUNITY_Community 307|Community 307]] -- [[_COMMUNITY_Community 308|Community 308]] -- [[_COMMUNITY_Community 309|Community 309]] -- [[_COMMUNITY_Community 310|Community 310]] -- [[_COMMUNITY_Community 311|Community 311]] -- [[_COMMUNITY_Community 312|Community 312]] -- [[_COMMUNITY_Community 313|Community 313]] -- [[_COMMUNITY_Community 314|Community 314]] -- [[_COMMUNITY_Community 315|Community 315]] -- [[_COMMUNITY_Community 316|Community 316]] -- [[_COMMUNITY_Community 317|Community 317]] -- [[_COMMUNITY_Community 318|Community 318]] -- [[_COMMUNITY_Community 319|Community 319]] -- [[_COMMUNITY_Community 320|Community 320]] -- [[_COMMUNITY_Community 321|Community 321]] -- [[_COMMUNITY_Community 322|Community 322]] -- [[_COMMUNITY_Community 323|Community 323]] -- [[_COMMUNITY_Community 324|Community 324]] -- [[_COMMUNITY_Community 325|Community 325]] -- [[_COMMUNITY_Community 326|Community 326]] -- [[_COMMUNITY_Community 327|Community 327]] -- [[_COMMUNITY_Community 328|Community 328]] -- [[_COMMUNITY_Community 329|Community 329]] -- [[_COMMUNITY_Community 330|Community 330]] -- [[_COMMUNITY_Community 331|Community 331]] -- [[_COMMUNITY_Community 332|Community 332]] -- [[_COMMUNITY_Community 333|Community 333]] -- [[_COMMUNITY_Community 334|Community 334]] -- [[_COMMUNITY_Community 335|Community 335]] -- [[_COMMUNITY_Community 336|Community 336]] -- [[_COMMUNITY_Community 337|Community 337]] -- [[_COMMUNITY_Community 338|Community 338]] -- [[_COMMUNITY_Community 339|Community 339]] -- [[_COMMUNITY_Community 340|Community 340]] -- [[_COMMUNITY_Community 342|Community 342]] -- [[_COMMUNITY_Community 343|Community 343]] -- [[_COMMUNITY_Community 344|Community 344]] -- [[_COMMUNITY_Community 345|Community 345]] -- [[_COMMUNITY_Community 346|Community 346]] -- [[_COMMUNITY_Community 347|Community 347]] -- [[_COMMUNITY_Community 348|Community 348]] -- [[_COMMUNITY_Community 349|Community 349]] -- [[_COMMUNITY_Community 350|Community 350]] -- [[_COMMUNITY_Community 351|Community 351]] -- [[_COMMUNITY_Community 352|Community 352]] -- [[_COMMUNITY_Community 353|Community 353]] -- [[_COMMUNITY_Community 354|Community 354]] -- [[_COMMUNITY_Community 356|Community 356]] -- [[_COMMUNITY_Community 357|Community 357]] -- [[_COMMUNITY_Community 358|Community 358]] -- [[_COMMUNITY_Community 359|Community 359]] -- [[_COMMUNITY_Community 360|Community 360]] -- [[_COMMUNITY_Community 361|Community 361]] -- [[_COMMUNITY_Community 362|Community 362]] -- [[_COMMUNITY_Community 363|Community 363]] -- [[_COMMUNITY_Community 364|Community 364]] -- [[_COMMUNITY_Community 365|Community 365]] -- [[_COMMUNITY_Community 366|Community 366]] -- [[_COMMUNITY_Community 367|Community 367]] -- [[_COMMUNITY_Community 368|Community 368]] -- [[_COMMUNITY_Community 369|Community 369]] -- [[_COMMUNITY_Community 370|Community 370]] -- [[_COMMUNITY_Community 371|Community 371]] -- [[_COMMUNITY_Community 372|Community 372]] -- [[_COMMUNITY_Community 373|Community 373]] -- [[_COMMUNITY_Community 374|Community 374]] -- [[_COMMUNITY_Community 375|Community 375]] -- [[_COMMUNITY_Community 376|Community 376]] -- [[_COMMUNITY_Community 377|Community 377]] -- [[_COMMUNITY_Community 378|Community 378]] -- [[_COMMUNITY_Community 379|Community 379]] -- [[_COMMUNITY_Community 380|Community 380]] -- [[_COMMUNITY_Community 382|Community 382]] -- [[_COMMUNITY_Community 383|Community 383]] -- [[_COMMUNITY_Community 384|Community 384]] -- [[_COMMUNITY_Community 385|Community 385]] -- [[_COMMUNITY_Community 386|Community 386]] -- [[_COMMUNITY_Community 387|Community 387]] -- [[_COMMUNITY_Community 388|Community 388]] -- [[_COMMUNITY_Community 389|Community 389]] -- [[_COMMUNITY_Community 390|Community 390]] -- [[_COMMUNITY_Community 391|Community 391]] -- [[_COMMUNITY_Community 392|Community 392]] -- [[_COMMUNITY_Community 393|Community 393]] -- [[_COMMUNITY_Community 394|Community 394]] -- [[_COMMUNITY_Community 395|Community 395]] -- [[_COMMUNITY_Community 396|Community 396]] -- [[_COMMUNITY_Community 398|Community 398]] -- [[_COMMUNITY_Community 399|Community 399]] -- [[_COMMUNITY_Community 400|Community 400]] -- [[_COMMUNITY_Community 401|Community 401]] -- [[_COMMUNITY_Community 402|Community 402]] -- [[_COMMUNITY_Community 403|Community 403]] -- [[_COMMUNITY_Community 404|Community 404]] -- [[_COMMUNITY_Community 405|Community 405]] -- [[_COMMUNITY_Community 406|Community 406]] -- [[_COMMUNITY_Community 407|Community 407]] -- [[_COMMUNITY_Community 408|Community 408]] -- [[_COMMUNITY_Community 409|Community 409]] -- [[_COMMUNITY_Community 411|Community 411]] -- [[_COMMUNITY_Community 412|Community 412]] -- [[_COMMUNITY_Community 413|Community 413]] -- [[_COMMUNITY_Community 414|Community 414]] -- [[_COMMUNITY_Community 415|Community 415]] -- [[_COMMUNITY_Community 416|Community 416]] -- [[_COMMUNITY_Community 417|Community 417]] -- [[_COMMUNITY_Community 418|Community 418]] -- [[_COMMUNITY_Community 419|Community 419]] -- [[_COMMUNITY_Community 420|Community 420]] -- [[_COMMUNITY_Community 421|Community 421]] -- [[_COMMUNITY_Community 422|Community 422]] -- [[_COMMUNITY_Community 423|Community 423]] -- [[_COMMUNITY_Community 424|Community 424]] -- [[_COMMUNITY_Community 425|Community 425]] -- [[_COMMUNITY_Community 426|Community 426]] -- [[_COMMUNITY_Community 427|Community 427]] -- [[_COMMUNITY_Community 428|Community 428]] -- [[_COMMUNITY_Community 429|Community 429]] -- [[_COMMUNITY_Community 430|Community 430]] -- [[_COMMUNITY_Community 431|Community 431]] -- [[_COMMUNITY_Community 432|Community 432]] -- [[_COMMUNITY_Community 433|Community 433]] -- [[_COMMUNITY_Community 434|Community 434]] -- [[_COMMUNITY_Community 435|Community 435]] -- [[_COMMUNITY_Community 436|Community 436]] -- [[_COMMUNITY_Community 437|Community 437]] -- [[_COMMUNITY_Community 438|Community 438]] -- [[_COMMUNITY_Community 439|Community 439]] -- [[_COMMUNITY_Community 440|Community 440]] -- [[_COMMUNITY_Community 441|Community 441]] -- [[_COMMUNITY_Community 442|Community 442]] -- [[_COMMUNITY_Community 444|Community 444]] -- [[_COMMUNITY_Community 445|Community 445]] -- [[_COMMUNITY_Community 446|Community 446]] -- [[_COMMUNITY_Community 447|Community 447]] -- [[_COMMUNITY_Community 448|Community 448]] -- [[_COMMUNITY_Community 449|Community 449]] -- [[_COMMUNITY_Community 450|Community 450]] -- [[_COMMUNITY_Community 452|Community 452]] -- [[_COMMUNITY_Community 453|Community 453]] -- [[_COMMUNITY_Community 454|Community 454]] -- [[_COMMUNITY_Community 455|Community 455]] -- [[_COMMUNITY_Community 456|Community 456]] -- [[_COMMUNITY_Community 457|Community 457]] -- [[_COMMUNITY_Community 458|Community 458]] -- [[_COMMUNITY_Community 459|Community 459]] -- [[_COMMUNITY_Community 460|Community 460]] -- [[_COMMUNITY_Community 461|Community 461]] -- [[_COMMUNITY_Community 462|Community 462]] -- [[_COMMUNITY_Community 463|Community 463]] -- [[_COMMUNITY_Community 464|Community 464]] -- [[_COMMUNITY_Community 465|Community 465]] -- [[_COMMUNITY_Community 466|Community 466]] -- [[_COMMUNITY_Community 467|Community 467]] -- [[_COMMUNITY_Community 468|Community 468]] -- [[_COMMUNITY_Community 469|Community 469]] -- [[_COMMUNITY_Community 470|Community 470]] -- [[_COMMUNITY_Community 472|Community 472]] -- [[_COMMUNITY_Community 473|Community 473]] -- [[_COMMUNITY_Community 474|Community 474]] -- [[_COMMUNITY_Community 475|Community 475]] -- [[_COMMUNITY_Community 476|Community 476]] -- [[_COMMUNITY_Community 477|Community 477]] -- [[_COMMUNITY_Community 478|Community 478]] -- [[_COMMUNITY_Community 479|Community 479]] -- [[_COMMUNITY_Community 480|Community 480]] -- [[_COMMUNITY_Community 481|Community 481]] -- [[_COMMUNITY_Community 482|Community 482]] -- [[_COMMUNITY_Community 483|Community 483]] -- [[_COMMUNITY_Community 485|Community 485]] -- [[_COMMUNITY_Community 486|Community 486]] -- [[_COMMUNITY_Community 487|Community 487]] -- [[_COMMUNITY_Community 488|Community 488]] -- [[_COMMUNITY_Community 489|Community 489]] -- [[_COMMUNITY_Community 490|Community 490]] -- [[_COMMUNITY_Community 491|Community 491]] -- [[_COMMUNITY_Community 492|Community 492]] -- [[_COMMUNITY_Community 493|Community 493]] -- [[_COMMUNITY_Community 494|Community 494]] -- [[_COMMUNITY_Community 495|Community 495]] -- [[_COMMUNITY_Community 496|Community 496]] -- [[_COMMUNITY_Community 497|Community 497]] -- [[_COMMUNITY_Community 498|Community 498]] -- [[_COMMUNITY_Community 499|Community 499]] -- [[_COMMUNITY_Community 500|Community 500]] -- [[_COMMUNITY_Community 501|Community 501]] -- [[_COMMUNITY_Community 502|Community 502]] -- [[_COMMUNITY_Community 503|Community 503]] -- [[_COMMUNITY_Community 504|Community 504]] -- [[_COMMUNITY_Community 505|Community 505]] -- [[_COMMUNITY_Community 506|Community 506]] -- [[_COMMUNITY_Community 507|Community 507]] -- [[_COMMUNITY_Community 508|Community 508]] -- [[_COMMUNITY_Community 509|Community 509]] -- [[_COMMUNITY_Community 510|Community 510]] -- [[_COMMUNITY_Community 511|Community 511]] -- [[_COMMUNITY_Community 512|Community 512]] -- [[_COMMUNITY_Community 513|Community 513]] -- [[_COMMUNITY_Community 514|Community 514]] -- [[_COMMUNITY_Community 515|Community 515]] -- [[_COMMUNITY_Community 516|Community 516]] -- [[_COMMUNITY_Community 517|Community 517]] -- [[_COMMUNITY_Community 518|Community 518]] -- [[_COMMUNITY_Community 519|Community 519]] -- [[_COMMUNITY_Community 520|Community 520]] -- [[_COMMUNITY_Community 521|Community 521]] -- [[_COMMUNITY_Community 522|Community 522]] -- [[_COMMUNITY_Community 523|Community 523]] -- [[_COMMUNITY_Community 524|Community 524]] -- [[_COMMUNITY_Community 525|Community 525]] -- [[_COMMUNITY_Community 526|Community 526]] -- [[_COMMUNITY_Community 527|Community 527]] -- [[_COMMUNITY_Community 528|Community 528]] -- [[_COMMUNITY_Community 529|Community 529]] -- [[_COMMUNITY_Community 530|Community 530]] -- [[_COMMUNITY_Community 531|Community 531]] -- [[_COMMUNITY_Community 532|Community 532]] -- [[_COMMUNITY_Community 533|Community 533]] -- [[_COMMUNITY_Community 534|Community 534]] -- [[_COMMUNITY_Community 535|Community 535]] -- [[_COMMUNITY_Community 536|Community 536]] -- [[_COMMUNITY_Community 537|Community 537]] -- [[_COMMUNITY_Community 538|Community 538]] -- [[_COMMUNITY_Community 539|Community 539]] -- [[_COMMUNITY_Community 540|Community 540]] -- [[_COMMUNITY_Community 541|Community 541]] -- [[_COMMUNITY_Community 542|Community 542]] -- [[_COMMUNITY_Community 543|Community 543]] -- [[_COMMUNITY_Community 544|Community 544]] -- [[_COMMUNITY_Community 545|Community 545]] -- [[_COMMUNITY_Community 546|Community 546]] -- [[_COMMUNITY_Community 547|Community 547]] -- [[_COMMUNITY_Community 548|Community 548]] -- [[_COMMUNITY_Community 549|Community 549]] -- [[_COMMUNITY_Community 550|Community 550]] -- [[_COMMUNITY_Community 551|Community 551]] -- [[_COMMUNITY_Community 552|Community 552]] -- [[_COMMUNITY_Community 553|Community 553]] -- [[_COMMUNITY_Community 554|Community 554]] -- [[_COMMUNITY_Community 555|Community 555]] -- [[_COMMUNITY_Community 556|Community 556]] -- [[_COMMUNITY_Community 557|Community 557]] -- [[_COMMUNITY_Community 558|Community 558]] -- [[_COMMUNITY_Community 559|Community 559]] -- [[_COMMUNITY_Community 560|Community 560]] -- [[_COMMUNITY_Community 561|Community 561]] -- [[_COMMUNITY_Community 562|Community 562]] -- [[_COMMUNITY_Community 563|Community 563]] -- [[_COMMUNITY_Community 564|Community 564]] -- [[_COMMUNITY_Community 565|Community 565]] -- [[_COMMUNITY_Community 566|Community 566]] -- [[_COMMUNITY_Community 567|Community 567]] -- [[_COMMUNITY_Community 568|Community 568]] -- [[_COMMUNITY_Community 569|Community 569]] -- [[_COMMUNITY_Community 570|Community 570]] -- [[_COMMUNITY_Community 571|Community 571]] -- [[_COMMUNITY_Community 572|Community 572]] -- [[_COMMUNITY_Community 573|Community 573]] -- [[_COMMUNITY_Community 574|Community 574]] -- [[_COMMUNITY_Community 575|Community 575]] -- [[_COMMUNITY_Community 576|Community 576]] -- [[_COMMUNITY_Community 577|Community 577]] -- [[_COMMUNITY_Community 578|Community 578]] -- [[_COMMUNITY_Community 579|Community 579]] -- [[_COMMUNITY_Community 580|Community 580]] -- [[_COMMUNITY_Community 581|Community 581]] -- [[_COMMUNITY_Community 582|Community 582]] -- [[_COMMUNITY_Community 583|Community 583]] -- [[_COMMUNITY_Community 584|Community 584]] -- [[_COMMUNITY_Community 586|Community 586]] -- [[_COMMUNITY_Community 587|Community 587]] -- [[_COMMUNITY_Community 588|Community 588]] -- [[_COMMUNITY_Community 589|Community 589]] -- [[_COMMUNITY_Community 590|Community 590]] -- [[_COMMUNITY_Community 591|Community 591]] -- [[_COMMUNITY_Community 592|Community 592]] -- [[_COMMUNITY_Community 594|Community 594]] -- [[_COMMUNITY_Community 596|Community 596]] -- [[_COMMUNITY_Community 597|Community 597]] -- [[_COMMUNITY_Community 598|Community 598]] -- [[_COMMUNITY_Community 599|Community 599]] -- [[_COMMUNITY_Community 600|Community 600]] -- [[_COMMUNITY_Community 603|Community 603]] -- [[_COMMUNITY_Community 607|Community 607]] -- [[_COMMUNITY_Community 608|Community 608]] -- [[_COMMUNITY_Community 611|Community 611]] -- [[_COMMUNITY_Community 612|Community 612]] -- [[_COMMUNITY_Community 613|Community 613]] -- [[_COMMUNITY_Community 614|Community 614]] -- [[_COMMUNITY_Community 615|Community 615]] -- [[_COMMUNITY_Community 616|Community 616]] -- [[_COMMUNITY_Community 617|Community 617]] -- [[_COMMUNITY_Community 618|Community 618]] -- [[_COMMUNITY_Community 619|Community 619]] -- [[_COMMUNITY_Community 620|Community 620]] -- [[_COMMUNITY_Community 621|Community 621]] -- [[_COMMUNITY_Community 622|Community 622]] -- [[_COMMUNITY_Community 623|Community 623]] -- [[_COMMUNITY_Community 624|Community 624]] -- [[_COMMUNITY_Community 625|Community 625]] -- [[_COMMUNITY_Community 626|Community 626]] -- [[_COMMUNITY_Community 627|Community 627]] -- [[_COMMUNITY_Community 628|Community 628]] -- [[_COMMUNITY_Community 629|Community 629]] -- [[_COMMUNITY_Community 630|Community 630]] -- [[_COMMUNITY_Community 631|Community 631]] -- [[_COMMUNITY_Community 632|Community 632]] -- [[_COMMUNITY_Community 633|Community 633]] -- [[_COMMUNITY_Community 635|Community 635]] -- [[_COMMUNITY_Community 636|Community 636]] -- [[_COMMUNITY_Community 637|Community 637]] -- [[_COMMUNITY_Community 638|Community 638]] -- [[_COMMUNITY_Community 639|Community 639]] -- [[_COMMUNITY_Community 641|Community 641]] -- [[_COMMUNITY_Community 642|Community 642]] -- [[_COMMUNITY_Community 643|Community 643]] -- [[_COMMUNITY_Community 644|Community 644]] -- [[_COMMUNITY_Community 645|Community 645]] -- [[_COMMUNITY_Community 646|Community 646]] -- [[_COMMUNITY_Community 647|Community 647]] -- [[_COMMUNITY_Community 648|Community 648]] -- [[_COMMUNITY_Community 649|Community 649]] -- [[_COMMUNITY_Community 650|Community 650]] -- [[_COMMUNITY_Community 651|Community 651]] -- [[_COMMUNITY_Community 652|Community 652]] -- [[_COMMUNITY_Community 653|Community 653]] -- [[_COMMUNITY_Community 654|Community 654]] -- [[_COMMUNITY_Community 655|Community 655]] -- [[_COMMUNITY_Community 656|Community 656]] -- [[_COMMUNITY_Community 657|Community 657]] -- [[_COMMUNITY_Community 658|Community 658]] -- [[_COMMUNITY_Community 659|Community 659]] -- [[_COMMUNITY_Community 660|Community 660]] -- [[_COMMUNITY_Community 661|Community 661]] -- [[_COMMUNITY_Community 662|Community 662]] -- [[_COMMUNITY_Community 663|Community 663]] -- [[_COMMUNITY_Community 664|Community 664]] -- [[_COMMUNITY_Community 665|Community 665]] -- [[_COMMUNITY_Community 666|Community 666]] -- [[_COMMUNITY_Community 667|Community 667]] -- [[_COMMUNITY_Community 668|Community 668]] -- [[_COMMUNITY_Community 669|Community 669]] -- [[_COMMUNITY_Community 670|Community 670]] -- [[_COMMUNITY_Community 671|Community 671]] -- [[_COMMUNITY_Community 672|Community 672]] -- [[_COMMUNITY_Community 673|Community 673]] -- [[_COMMUNITY_Community 674|Community 674]] -- [[_COMMUNITY_Community 675|Community 675]] -- [[_COMMUNITY_Community 676|Community 676]] -- [[_COMMUNITY_Community 677|Community 677]] -- [[_COMMUNITY_Community 678|Community 678]] -- [[_COMMUNITY_Community 679|Community 679]] -- [[_COMMUNITY_Community 680|Community 680]] -- [[_COMMUNITY_Community 681|Community 681]] -- [[_COMMUNITY_Community 682|Community 682]] -- [[_COMMUNITY_Community 683|Community 683]] -- [[_COMMUNITY_Community 684|Community 684]] -- [[_COMMUNITY_Community 685|Community 685]] -- [[_COMMUNITY_Community 686|Community 686]] -- [[_COMMUNITY_Community 687|Community 687]] -- [[_COMMUNITY_Community 688|Community 688]] -- [[_COMMUNITY_Community 689|Community 689]] -- [[_COMMUNITY_Community 690|Community 690]] -- [[_COMMUNITY_Community 691|Community 691]] -- [[_COMMUNITY_Community 692|Community 692]] -- [[_COMMUNITY_Community 693|Community 693]] -- [[_COMMUNITY_Community 694|Community 694]] -- [[_COMMUNITY_Community 695|Community 695]] -- [[_COMMUNITY_Community 696|Community 696]] -- [[_COMMUNITY_Community 697|Community 697]] -- [[_COMMUNITY_Community 698|Community 698]] -- [[_COMMUNITY_Community 699|Community 699]] -- [[_COMMUNITY_Community 700|Community 700]] -- [[_COMMUNITY_Community 701|Community 701]] -- [[_COMMUNITY_Community 702|Community 702]] -- [[_COMMUNITY_Community 703|Community 703]] -- [[_COMMUNITY_Community 704|Community 704]] -- [[_COMMUNITY_Community 705|Community 705]] -- [[_COMMUNITY_Community 706|Community 706]] -- [[_COMMUNITY_Community 707|Community 707]] -- [[_COMMUNITY_Community 708|Community 708]] -- [[_COMMUNITY_Community 709|Community 709]] -- [[_COMMUNITY_Community 710|Community 710]] -- [[_COMMUNITY_Community 711|Community 711]] -- [[_COMMUNITY_Community 712|Community 712]] -- [[_COMMUNITY_Community 713|Community 713]] -- [[_COMMUNITY_Community 714|Community 714]] -- [[_COMMUNITY_Community 715|Community 715]] -- [[_COMMUNITY_Community 716|Community 716]] -- [[_COMMUNITY_Community 717|Community 717]] -- [[_COMMUNITY_Community 718|Community 718]] -- [[_COMMUNITY_Community 719|Community 719]] -- [[_COMMUNITY_Community 720|Community 720]] -- [[_COMMUNITY_Community 721|Community 721]] -- [[_COMMUNITY_Community 722|Community 722]] -- [[_COMMUNITY_Community 723|Community 723]] -- [[_COMMUNITY_Community 724|Community 724]] -- [[_COMMUNITY_Community 725|Community 725]] -- [[_COMMUNITY_Community 726|Community 726]] -- [[_COMMUNITY_Community 727|Community 727]] -- [[_COMMUNITY_Community 728|Community 728]] -- [[_COMMUNITY_Community 729|Community 729]] -- [[_COMMUNITY_Community 730|Community 730]] -- [[_COMMUNITY_Community 731|Community 731]] -- [[_COMMUNITY_Community 732|Community 732]] -- [[_COMMUNITY_Community 733|Community 733]] -- [[_COMMUNITY_Community 734|Community 734]] -- [[_COMMUNITY_Community 735|Community 735]] -- [[_COMMUNITY_Community 736|Community 736]] -- [[_COMMUNITY_Community 737|Community 737]] -- [[_COMMUNITY_Community 738|Community 738]] -- [[_COMMUNITY_Community 739|Community 739]] -- [[_COMMUNITY_Community 741|Community 741]] -- [[_COMMUNITY_Community 742|Community 742]] -- [[_COMMUNITY_Community 743|Community 743]] -- [[_COMMUNITY_Community 744|Community 744]] -- [[_COMMUNITY_Community 745|Community 745]] -- [[_COMMUNITY_Community 746|Community 746]] -- [[_COMMUNITY_Community 749|Community 749]] -- [[_COMMUNITY_Community 750|Community 750]] -- [[_COMMUNITY_Community 751|Community 751]] -- [[_COMMUNITY_Community 752|Community 752]] -- [[_COMMUNITY_Community 753|Community 753]] -- [[_COMMUNITY_Community 754|Community 754]] -- [[_COMMUNITY_Community 755|Community 755]] -- [[_COMMUNITY_Community 756|Community 756]] -- [[_COMMUNITY_Community 757|Community 757]] -- [[_COMMUNITY_Community 758|Community 758]] -- [[_COMMUNITY_Community 759|Community 759]] -- [[_COMMUNITY_Community 760|Community 760]] -- [[_COMMUNITY_Community 761|Community 761]] -- [[_COMMUNITY_Community 762|Community 762]] -- [[_COMMUNITY_Community 763|Community 763]] -- [[_COMMUNITY_Community 764|Community 764]] -- [[_COMMUNITY_Community 765|Community 765]] -- [[_COMMUNITY_Community 766|Community 766]] -- [[_COMMUNITY_Community 767|Community 767]] -- [[_COMMUNITY_Community 768|Community 768]] -- [[_COMMUNITY_Community 769|Community 769]] -- [[_COMMUNITY_Community 770|Community 770]] -- [[_COMMUNITY_Community 771|Community 771]] -- [[_COMMUNITY_Community 772|Community 772]] -- [[_COMMUNITY_Community 773|Community 773]] -- [[_COMMUNITY_Community 774|Community 774]] -- [[_COMMUNITY_Community 775|Community 775]] -- [[_COMMUNITY_Community 776|Community 776]] -- [[_COMMUNITY_Community 777|Community 777]] -- [[_COMMUNITY_Community 778|Community 778]] -- [[_COMMUNITY_Community 779|Community 779]] -- [[_COMMUNITY_Community 780|Community 780]] -- [[_COMMUNITY_Community 781|Community 781]] -- [[_COMMUNITY_Community 782|Community 782]] -- [[_COMMUNITY_Community 783|Community 783]] -- [[_COMMUNITY_Community 784|Community 784]] -- [[_COMMUNITY_Community 785|Community 785]] -- [[_COMMUNITY_Community 786|Community 786]] -- [[_COMMUNITY_Community 787|Community 787]] -- [[_COMMUNITY_Community 788|Community 788]] -- [[_COMMUNITY_Community 789|Community 789]] -- [[_COMMUNITY_Community 790|Community 790]] -- [[_COMMUNITY_Community 791|Community 791]] -- [[_COMMUNITY_Community 792|Community 792]] -- [[_COMMUNITY_Community 793|Community 793]] -- [[_COMMUNITY_Community 794|Community 794]] -- [[_COMMUNITY_Community 795|Community 795]] -- [[_COMMUNITY_Community 796|Community 796]] -- [[_COMMUNITY_Community 797|Community 797]] -- [[_COMMUNITY_Community 798|Community 798]] -- [[_COMMUNITY_Community 799|Community 799]] -- [[_COMMUNITY_Community 800|Community 800]] -- [[_COMMUNITY_Community 801|Community 801]] -- [[_COMMUNITY_Community 802|Community 802]] -- [[_COMMUNITY_Community 803|Community 803]] -- [[_COMMUNITY_Community 804|Community 804]] -- [[_COMMUNITY_Community 805|Community 805]] -- [[_COMMUNITY_Community 806|Community 806]] -- [[_COMMUNITY_Community 807|Community 807]] -- [[_COMMUNITY_Community 808|Community 808]] -- [[_COMMUNITY_Community 809|Community 809]] -- [[_COMMUNITY_Community 810|Community 810]] -- [[_COMMUNITY_Community 811|Community 811]] -- [[_COMMUNITY_Community 812|Community 812]] -- [[_COMMUNITY_Community 813|Community 813]] -- [[_COMMUNITY_Community 814|Community 814]] -- [[_COMMUNITY_Community 815|Community 815]] -- [[_COMMUNITY_Community 816|Community 816]] -- [[_COMMUNITY_Community 817|Community 817]] -- [[_COMMUNITY_Community 818|Community 818]] -- [[_COMMUNITY_Community 819|Community 819]] -- [[_COMMUNITY_Community 820|Community 820]] -- [[_COMMUNITY_Community 821|Community 821]] -- [[_COMMUNITY_Community 822|Community 822]] -- [[_COMMUNITY_Community 823|Community 823]] -- [[_COMMUNITY_Community 824|Community 824]] -- [[_COMMUNITY_Community 825|Community 825]] -- [[_COMMUNITY_Community 826|Community 826]] -- [[_COMMUNITY_Community 827|Community 827]] -- [[_COMMUNITY_Community 828|Community 828]] -- [[_COMMUNITY_Community 829|Community 829]] -- [[_COMMUNITY_Community 830|Community 830]] -- [[_COMMUNITY_Community 831|Community 831]] -- [[_COMMUNITY_Community 832|Community 832]] -- [[_COMMUNITY_Community 833|Community 833]] -- [[_COMMUNITY_Community 834|Community 834]] -- [[_COMMUNITY_Community 835|Community 835]] -- [[_COMMUNITY_Community 836|Community 836]] -- [[_COMMUNITY_Community 837|Community 837]] -- [[_COMMUNITY_Community 838|Community 838]] -- [[_COMMUNITY_Community 839|Community 839]] -- [[_COMMUNITY_Community 840|Community 840]] -- [[_COMMUNITY_Community 841|Community 841]] -- [[_COMMUNITY_Community 842|Community 842]] -- [[_COMMUNITY_Community 843|Community 843]] -- [[_COMMUNITY_Community 844|Community 844]] -- [[_COMMUNITY_Community 845|Community 845]] -- [[_COMMUNITY_Community 846|Community 846]] -- [[_COMMUNITY_Community 847|Community 847]] -- [[_COMMUNITY_Community 848|Community 848]] -- [[_COMMUNITY_Community 849|Community 849]] -- [[_COMMUNITY_Community 850|Community 850]] -- [[_COMMUNITY_Community 851|Community 851]] -- [[_COMMUNITY_Community 852|Community 852]] -- [[_COMMUNITY_Community 853|Community 853]] -- [[_COMMUNITY_Community 854|Community 854]] -- [[_COMMUNITY_Community 855|Community 855]] -- [[_COMMUNITY_Community 856|Community 856]] -- [[_COMMUNITY_Community 857|Community 857]] -- [[_COMMUNITY_Community 858|Community 858]] -- [[_COMMUNITY_Community 859|Community 859]] -- [[_COMMUNITY_Community 860|Community 860]] -- [[_COMMUNITY_Community 861|Community 861]] -- [[_COMMUNITY_Community 862|Community 862]] -- [[_COMMUNITY_Community 863|Community 863]] -- [[_COMMUNITY_Community 864|Community 864]] -- [[_COMMUNITY_Community 865|Community 865]] -- [[_COMMUNITY_Community 866|Community 866]] -- [[_COMMUNITY_Community 867|Community 867]] -- [[_COMMUNITY_Community 868|Community 868]] -- [[_COMMUNITY_Community 869|Community 869]] -- [[_COMMUNITY_Community 870|Community 870]] -- [[_COMMUNITY_Community 871|Community 871]] -- [[_COMMUNITY_Community 872|Community 872]] -- [[_COMMUNITY_Community 873|Community 873]] -- [[_COMMUNITY_Community 874|Community 874]] -- [[_COMMUNITY_Community 875|Community 875]] -- [[_COMMUNITY_Community 876|Community 876]] -- [[_COMMUNITY_Community 877|Community 877]] -- [[_COMMUNITY_Community 878|Community 878]] -- [[_COMMUNITY_Community 879|Community 879]] -- [[_COMMUNITY_Community 880|Community 880]] -- [[_COMMUNITY_Community 881|Community 881]] -- [[_COMMUNITY_Community 882|Community 882]] -- [[_COMMUNITY_Community 883|Community 883]] -- [[_COMMUNITY_Community 884|Community 884]] -- [[_COMMUNITY_Community 885|Community 885]] -- [[_COMMUNITY_Community 886|Community 886]] -- [[_COMMUNITY_Community 887|Community 887]] -- [[_COMMUNITY_Community 888|Community 888]] -- [[_COMMUNITY_Community 889|Community 889]] -- [[_COMMUNITY_Community 890|Community 890]] -- [[_COMMUNITY_Community 891|Community 891]] -- [[_COMMUNITY_Community 892|Community 892]] -- [[_COMMUNITY_Community 893|Community 893]] -- [[_COMMUNITY_Community 894|Community 894]] -- [[_COMMUNITY_Community 895|Community 895]] -- [[_COMMUNITY_Community 896|Community 896]] -- [[_COMMUNITY_Community 897|Community 897]] -- [[_COMMUNITY_Community 898|Community 898]] -- [[_COMMUNITY_Community 899|Community 899]] -- [[_COMMUNITY_Community 900|Community 900]] -- [[_COMMUNITY_Community 901|Community 901]] -- [[_COMMUNITY_Community 902|Community 902]] -- [[_COMMUNITY_Community 903|Community 903]] -- [[_COMMUNITY_Community 904|Community 904]] -- [[_COMMUNITY_Community 905|Community 905]] -- [[_COMMUNITY_Community 906|Community 906]] -- [[_COMMUNITY_Community 907|Community 907]] -- [[_COMMUNITY_Community 908|Community 908]] -- [[_COMMUNITY_Community 909|Community 909]] -- [[_COMMUNITY_Community 910|Community 910]] -- [[_COMMUNITY_Community 911|Community 911]] -- [[_COMMUNITY_Community 912|Community 912]] -- [[_COMMUNITY_Community 913|Community 913]] -- [[_COMMUNITY_Community 914|Community 914]] -- [[_COMMUNITY_Community 915|Community 915]] -- [[_COMMUNITY_Community 916|Community 916]] -- [[_COMMUNITY_Community 917|Community 917]] -- [[_COMMUNITY_Community 918|Community 918]] -- [[_COMMUNITY_Community 919|Community 919]] -- [[_COMMUNITY_Community 920|Community 920]] -- [[_COMMUNITY_Community 921|Community 921]] -- [[_COMMUNITY_Community 922|Community 922]] -- [[_COMMUNITY_Community 923|Community 923]] -- [[_COMMUNITY_Community 924|Community 924]] -- [[_COMMUNITY_Community 925|Community 925]] -- [[_COMMUNITY_Community 926|Community 926]] -- [[_COMMUNITY_Community 927|Community 927]] -- [[_COMMUNITY_Community 928|Community 928]] -- [[_COMMUNITY_Community 929|Community 929]] -- [[_COMMUNITY_Community 930|Community 930]] -- [[_COMMUNITY_Community 931|Community 931]] -- [[_COMMUNITY_Community 932|Community 932]] -- [[_COMMUNITY_Community 933|Community 933]] -- [[_COMMUNITY_Community 934|Community 934]] -- [[_COMMUNITY_Community 935|Community 935]] -- [[_COMMUNITY_Community 936|Community 936]] -- [[_COMMUNITY_Community 937|Community 937]] -- [[_COMMUNITY_Community 938|Community 938]] -- [[_COMMUNITY_Community 939|Community 939]] -- [[_COMMUNITY_Community 940|Community 940]] -- [[_COMMUNITY_Community 941|Community 941]] -- [[_COMMUNITY_Community 942|Community 942]] -- [[_COMMUNITY_Community 943|Community 943]] -- [[_COMMUNITY_Community 944|Community 944]] -- [[_COMMUNITY_Community 945|Community 945]] -- [[_COMMUNITY_Community 946|Community 946]] -- [[_COMMUNITY_Community 947|Community 947]] -- [[_COMMUNITY_Community 948|Community 948]] -- [[_COMMUNITY_Community 949|Community 949]] -- [[_COMMUNITY_Community 950|Community 950]] -- [[_COMMUNITY_Community 951|Community 951]] -- [[_COMMUNITY_Community 952|Community 952]] -- [[_COMMUNITY_Community 953|Community 953]] -- [[_COMMUNITY_Community 954|Community 954]] -- [[_COMMUNITY_Community 955|Community 955]] -- [[_COMMUNITY_Community 956|Community 956]] -- [[_COMMUNITY_Community 958|Community 958]] -- [[_COMMUNITY_Community 959|Community 959]] -- [[_COMMUNITY_Community 960|Community 960]] -- [[_COMMUNITY_Community 961|Community 961]] -- [[_COMMUNITY_Community 962|Community 962]] -- [[_COMMUNITY_Community 963|Community 963]] -- [[_COMMUNITY_Community 964|Community 964]] -- [[_COMMUNITY_Community 965|Community 965]] -- [[_COMMUNITY_Community 973|Community 973]] - ## God Nodes (most connected - your core abstractions) -1. `useTranslation()` - 203 edges -2. `useAppSelector` - 130 edges -3. `useAppDispatch()` - 124 edges -4. `en` - 85 edges -5. `de` - 85 edges -6. `es` - 85 edges -7. `fr` - 85 edges -8. `it` - 85 edges -9. `logger` - 83 edges -10. `scripts` - 77 edges +1. `useTranslation()` - 227 edges +2. `useAppSelector` - 144 edges +3. `useAppDispatch()` - 128 edges +4. `scripts` - 94 edges +5. `logger` - 94 edges +6. `WorkerBus` - 79 edges +7. `ProjectData` - 76 edges +8. `StorySection` - 70 edges +9. `Button` - 67 edges +10. `WorldScript Studio β€” Codebase Audit Report` - 61 edges ## Surprising Connections (you probably didn't know these) -- `ViewLoader()` --calls--> `useTranslation()` [INFERRED] +- `ViewLoader()` --calls--> `useTranslation()` [EXTRACTED] App.tsx β†’ hooks/useTranslation.ts -- `useTranslation()` --calls--> `IdbUnlockModal()` [INFERRED] - hooks/useTranslation.ts β†’ components/settings/IdbUnlockModal.tsx -- `useTranslation()` --calls--> `MapForm()` [INFERRED] - hooks/useTranslation.ts β†’ components/mind-map/MindMapListPanel.tsx -- `useGlobalCopilot()` --calls--> `useCommandExecutor()` [INFERRED] - hooks/useGlobalCopilot.ts β†’ contexts/CommandExecutorContext.tsx -- `useAnalytics()` --calls--> `useAppDispatch()` [INFERRED] - hooks/useAnalytics.ts β†’ app/hooks.ts +- `App()` --indirect_call--> `selectFeatureFlags()` [INFERRED] + App.tsx β†’ features/featureFlags/featureFlagsSlice.ts +- `App()` --indirect_call--> `selectProjectData()` [INFERRED] + App.tsx β†’ features/project/projectSelectors.ts +- `AdvancedAiSection()` --indirect_call--> `analyticsPersistenceAllowedNow()` [INFERRED] + components/settings/AiSections.tsx β†’ app/analyticsGate.ts +- `AssignPopover()` --calls--> `useAppDispatch()` [EXTRACTED] + components/scene-board/SubplotPanel.tsx β†’ app/hooks.ts ## Import Cycles -- 2-file cycle: `services/proForge/pipelineAgents/supervisorAgent.ts -> services/proForge/proForgeOrchestrator.ts -> services/proForge/pipelineAgents/supervisorAgent.ts` - 2-file cycle: `app/store.ts -> app/storeRef.ts -> app/store.ts` - 2-file cycle: `features/project/projectSlice.ts -> features/project/thunks/binderThunks.ts -> features/project/projectSlice.ts` - 2-file cycle: `features/project/projectSlice.ts -> features/project/thunks/projectManagementThunks.ts -> features/project/projectSlice.ts` -- 2-file cycle: `packages/ai-core/src/index.ts -> packages/ai-core/src/webllmOptimizer.ts -> packages/ai-core/src/index.ts` - 2-file cycle: `packages/ai-core/src/index.ts -> packages/ai-core/src/onnxRuntimeEngine.ts -> packages/ai-core/src/index.ts` -- 3-file cycle: `features/project/projectSlice.ts -> features/project/reducers/writingAnalyticsReducers.ts -> types.ts -> features/project/projectSlice.ts` -- 3-file cycle: `features/project/projectSlice.ts -> features/project/projectState.ts -> types.ts -> features/project/projectSlice.ts` -- 3-file cycle: `features/project/projectSlice.ts -> features/project/reducers/plotReducers.ts -> types.ts -> features/project/projectSlice.ts` -- 3-file cycle: `features/project/projectSlice.ts -> features/project/thunks/outlineThunks.ts -> types.ts -> features/project/projectSlice.ts` -- 3-file cycle: `app/store.ts -> features/project/projectSlice.ts -> features/project/thunks/outlineThunks.ts -> app/store.ts` -- 3-file cycle: `features/project/projectSlice.ts -> features/project/reducers/manuscriptReducers.ts -> types.ts -> features/project/projectSlice.ts` +- 2-file cycle: `packages/ai-core/src/index.ts -> packages/ai-core/src/webllmOptimizer.ts -> packages/ai-core/src/index.ts` - 3-file cycle: `features/project/adapters.ts -> types.ts -> features/project/projectSlice.ts -> features/project/adapters.ts` - 3-file cycle: `features/project/aiThunkUtils.ts -> types.ts -> features/project/projectSlice.ts -> features/project/aiThunkUtils.ts` +- 3-file cycle: `features/project/projectSlice.ts -> features/project/projectState.ts -> types.ts -> features/project/projectSlice.ts` - 3-file cycle: `features/project/projectSlice.ts -> features/project/reducers/binderReducers.ts -> types.ts -> features/project/projectSlice.ts` - 3-file cycle: `features/project/projectSlice.ts -> features/project/reducers/characterReducers.ts -> types.ts -> features/project/projectSlice.ts` - 3-file cycle: `features/project/projectSlice.ts -> features/project/reducers/interviewReducers.ts -> types.ts -> features/project/projectSlice.ts` +- 3-file cycle: `features/project/projectSlice.ts -> features/project/reducers/manuscriptReducers.ts -> types.ts -> features/project/projectSlice.ts` - 3-file cycle: `features/project/projectSlice.ts -> features/project/reducers/mindMapReducers.ts -> types.ts -> features/project/projectSlice.ts` - 3-file cycle: `features/project/projectSlice.ts -> features/project/reducers/outlineReducers.ts -> types.ts -> features/project/projectSlice.ts` +- 3-file cycle: `features/project/projectSlice.ts -> features/project/reducers/plotReducers.ts -> types.ts -> features/project/projectSlice.ts` - 3-file cycle: `features/project/projectSlice.ts -> features/project/reducers/relationshipReducers.ts -> types.ts -> features/project/projectSlice.ts` +- 3-file cycle: `features/project/projectSlice.ts -> features/project/reducers/storyObjectReducers.ts -> types.ts -> features/project/projectSlice.ts` +- 3-file cycle: `features/project/projectSlice.ts -> features/project/reducers/worldReducers.ts -> types.ts -> features/project/projectSlice.ts` +- 3-file cycle: `features/project/projectSlice.ts -> features/project/reducers/writingAnalyticsReducers.ts -> types.ts -> features/project/projectSlice.ts` +- 3-file cycle: `features/project/projectSlice.ts -> features/project/thunks/binderThunks.ts -> types.ts -> features/project/projectSlice.ts` -## Communities (974 total, 60 thin omitted) - -### Community 0 - "Community 0" -Cohesion: 0.05 -Nodes (45): ArticleList(), HelpView(), HelpViewUI(), iconMap, NavButton, HelpViewContext, useHelpViewContext(), catalogToHelpCategories() (+37 more) - -### Community 1 - "Community 1" -Cohesion: 0.07 -Nodes (30): deriveCloudSyncKey(), WebLlmModelId, engineCache, EngineCacheEntry, getCacheKey(), getWebLlmEngine(), listCachedWebLlmEngines(), MLCEngine (+22 more) - -### Community 2 - "Community 2" -Cohesion: 0.02 -Nodes (91): _clearLatencyHistory(), recordLatency(), assertLoraLocalOnly(), _clearPendingRequestsForTest(), isCustomOllamaModel(), planAcceptedManuscriptEdits(), buildRelationshipEdges(), clearCommunityTemplateCache() (+83 more) - -### Community 3 - "Community 3" -Cohesion: 0.02 -Nodes (75): makeContext(), AppDispatch, makeContext(), createFakeAdapter(), createFakeDevice(), makeCopilot(), makeContext(), withDuckDbRetry() (+67 more) - -### Community 4 - "Community 4" -Cohesion: 0.13 -Nodes (11): FsAssetStore, FsCodexStore, componentDidCatch(), FsCore, loadTauriApis(), retryFs(), sanitizePathSegment(), decompressData() (+3 more) - -### Community 5 - "Community 5" -Cohesion: 0.06 -Nodes (20): loadStoryCodex(), handleInvalidApiKey(), translate(), IdbAssetStore, IdbCodexStore, compressData(), IdbConnectionManager, retryDb() (+12 more) - -### Community 6 - "Community 6" -Cohesion: 0.13 -Nodes (7): isEcoMode(), addDebouncedListener(), createSttEngine(), createVadEngine(), resetVoiceService(), VoiceCommandService, getVoiceTestHarness() +## Knowledge Gaps +- **5194 isolated node(s):** `$schema`, `config:recommended`, `dependencyDashboard`, `prHourlyLimit`, `prConcurrentLimit` (+5189 more) + These have ≀1 connection - possible missing edges or undocumented components. +- **106 thin communities (<3 nodes) omitted from report** β€” run `graphify query` to explore isolated nodes. -### Community 7 - "Community 7" -Cohesion: 0.06 -Nodes (38): HighlightSegment, highlightSubsequence(), normalizeSearch(), scoreAgainstQuery(), subsequenceScore(), CrossProjectSearchPanel, CrossProjectSearchPanelConnected, CrossProjectSearchPanelProps (+30 more) +## Suggested Questions +_Questions this graph is uniquely positioned to answer:_ -### Community 8 - "Community 8" -Cohesion: 0.07 -Nodes (9): FeedbackService, routeTask(), initAdaptiveAiOnStartup(), SileroVadEngine, invokeRustTask(), createTtsEngine(), WebSpeechTtsEngine, WasmSttEngine (+1 more) +- **Why does `logger` connect `logger` to `SettingsView.tsx`, `useTranslation`, `localEmbeddingService.ts`, `App.tsx`, `localRagService.ts`, `store.ts`, `VoiceControlPanel.tsx`, `telemetryService.ts`, `ToolsPanel.tsx`, `storageService.ts`, `CharacterView.tsx`, `idbProjectStore.ts`, `proForgeOrchestrator.ts`, `shortcutActions.ts`, `Character`, `PipelineStage`, `types.ts`, `VersionControlPanel.tsx`, `aiInferenceCacheService.ts`, `computeShaderFactory.ts`, `loraDatasetBuilder.ts`, `worldScriptCompletionFetch.ts`, `geminiService.ts`, `I18nContext.tsx`, `loraEvaluationService.ts`, `dbConstants.ts`, `localAiDeviceProfiler.ts`, `index.tsx`, `fsCore.ts`, `benchmarkService.ts`, `libraryBackupService.ts`, `AudioNavigator`, `localAiFacade.ts`, `epubApiService.ts`, `deviceHealthService.ts`, `sanitizePathSegment`, `logger.ts`, `useVoice.ts`, `sttEngine.ts`, `ragPromptAssembly.ts`, `loraOllamaService.ts`, `useDuckDb.ts`, `voiceCommandService.ts`, `useConsistencyCheckerView.ts`, `kokoroTtsEngine.ts`, `IdbUnlockModal.tsx`, `loraTrainingService.ts`, `duckdbClient.ts`, `useApp.ts`, `projectFsStore.ts`, `loraAdapterService.ts`, `voiceTypes.ts`, `diagnosticAgent.test.ts`?** + _High betweenness centrality (0.020) - this node is a cross-community bridge._ +- **Why does `useTranslation()` connect `useTranslation` to `SettingsView.tsx`, `LoraTrainingWizard.tsx`, `App.tsx`, `projectSlice.ts`, `BookPreviewView.tsx`, `aiPolicy.ts`, `Dashboard.tsx`, `VoiceControlPanel.tsx`, `ToolsPanel.tsx`, `MindMapCanvas.tsx`, `useMindMapView.ts`, `viewContexts.test.tsx`, `Icon.tsx`, `proForgeOrchestrator.ts`, `SceneBoardView.tsx`, `types.ts`, `useCommandPalette.ts`, `VersionControlPanel.tsx`, `loraDatasetBuilder.ts`, `useCharacterInterviewsView.ts`, `ProgressTrackerView.tsx`, `sceneCommentsSlice.ts`, `CollaborationPanel.tsx`, `localAiDeviceProfiler.ts`, `encryptionMigrationJournal.ts`, `crossProjectIndexService.ts`, `ExportView.tsx`, `localAiFacade.ts`, `deviceHealthService.ts`, `sceneRevisionService.ts`, `ObjectsView.tsx`, `AiProviderCard.test.tsx`, `useConsistencyCheckerView.ts`, `PipelineReviewPanel.tsx`, `useHelpView.ts`, `useGlobalCopilot.ts`, `IdbUnlockModal.tsx`, `LocalAiDownloadProgress.tsx`, `GpuMetricsPanel.tsx`, `loraTrainingService.ts`, `useLanguageToolCheck.ts`, `storybookProviders.tsx`, `MindMapView.tsx`, `fallbackEvents.ts`, `useTransientUiStore`?** + _High betweenness centrality (0.017) - this node is a cross-community bridge._ +- **Why does `StoryCodex` connect `storageService.ts` to `storageEncryptionService.ts`, `geminiService.ts`, `viewContexts.test.tsx`, `idbProjectStore.ts`, `useConsistencyCheckerView.ts`, `types.ts`, `sanitizePathSegment`, `CloudSyncBackend`?** + _High betweenness centrality (0.012) - this node is a cross-community bridge._ +- **What connects `$schema`, `config:recommended`, `dependencyDashboard` to the rest of the system?** + _5194 weakly-connected nodes found - possible documentation gaps or missing edges._ +- **Should `SettingsView.tsx` be split into smaller, more focused modules?** + _Cohesion score 0.030653266331658293 - nodes in this community are weakly interconnected._ +- **Should `useTranslation` be split into smaller, more focused modules?** + _Cohesion score 0.031800766283524906 - nodes in this community are weakly interconnected._ +- **Should `primaryProtectedStoreAdapters.ts` be split into smaller, more focused modules?** + _Cohesion score 0.03211122047244094 - nodes in this community are weakly interconnected._ -### Community 9 - "Community 9" -Cohesion: 0.07 -Nodes (35): getActiveAiMode(), getLocalFallbackModel(), generateJson(), isAbortError(), extractDefaultsFromSlice(), extractFlagsFromSlice(), buildAiOpts(), cooperativeYield() (+27 more) +## Top 20 Communities by size (of 713 total) -### Community 10 - "Community 10" -Cohesion: 0.09 -Nodes (29): AttentionBuffers, clearShaderCache(), ComputePipeline, createAttentionBuffers(), createAttentionPipeline(), createComputePipeline(), createKvCachePipeline(), createMlpPipeline() (+21 more) +_693 smaller communities omitted from this committed summary β€” full detail in local graphify-out/graph.json / graph.html (gitignored, not committed). Rebuild anytime: `pnpm run graphify:update`._ -### Community 11 - "Community 11" -Cohesion: 0.07 -Nodes (20): LoraViewContext, LoraViewContextValue, useLoraViewContext(), AdapterCard(), formatBytes(), DEFAULT_PROMPTS, Ctx, estimateDatasetQuality (+12 more) +### Community 0 - "SettingsView.tsx" +Cohesion: 0.03 +Nodes (122): ApiKeySection(), containsAsciiControlCharacter(), isSyntacticallySafeGeminiApiKey(), SETTINGS_CATEGORY_STORAGE_KEY, AccessibilitySection(), PRESET_IDS, MODES, ConnectionTestStatus (+114 more) -### Community 12 - "Community 12" +### Community 2 - "primaryProtectedStoreAdapters.ts" Cohesion: 0.03 -Nodes (54): handleCopyForNotion(), handleDocxImport(), handleExport(), handlePasteImport(), handleBuildLocalRag(), handleRemoveKey(), handleSaveKey(), binderDepth() (+46 more) +Nodes (104): Props, beginEncryptionMigration(), EncryptionMigrationOperation, EncryptionMigrationPhase, releaseEncryptionMigrationOwnership(), createMigrationOperationId(), getRegisteredProtectedStoreAdapters(), resumeProductionEncryptionMigration() (+96 more) -### Community 13 - "Community 13" -Cohesion: 0.04 -Nodes (61): App(), Header(), useAppDispatch(), useAppSelectorShallow(), LANG_PREFERENCES, sanitizeSpeechTranscript(), stripControlChars(), computeTensionCurve() (+53 more) +### Community 1 - "useTranslation" +Cohesion: 0.03 +Nodes (100): analyticsPersistenceAllowedNow(), useAppDispatch(), useAppSelector, LoraView, WelcomePortal, AdvancedImportExport(), binderDepth(), BinderPanel() (+92 more) -### Community 14 - "Community 14" +### Community 11 - "scripts" Cohesion: 0.02 -Nodes (79): AnalyticsBootstrap(), clearBenchmarkResults(), getLocalUser(), getRandomColor(), AnalyticsBootstrap(), readMode(), writeMode(), featureFlagsPersistenceMiddleware() (+71 more) - -### Community 15 - "Community 15" -Cohesion: 0.11 -Nodes (21): ARCHETYPE_LABEL_KEYS, ArchetypeSelector(), TEMPLATES, InterviewPanel(), MessageBubble(), InterviewQuestionBar(), getQuestionsForArchetype(), getTemplateForArchetype() (+13 more) - -### Community 16 - "Community 16" -Cohesion: 0.09 -Nodes (10): loadAgent(), bindAbortSignal(), setRetryFeedback(), CircuitBreaker, ProForgeOrchestrator, SupervisorAgent, buildRootState(), isEditingStage() (+2 more) +Nodes (94): scripts, analyze, bench, build, build:edge, build:pages, build-storybook, build:turbo (+86 more) -### Community 17 - "Community 17" -Cohesion: 0.29 -Nodes (9): assertCommunityTemplates(), loadJson(), main(), assertCommunityTemplates(), COMMUNITY_REL, __dirname, loadJson(), main() (+1 more) - -### Community 18 - "Community 18" -Cohesion: 0.06 -Nodes (5): CloudSyncBackend, CloudSyncClient, decryptCloudPayload(), encryptCloudPayload(), normalizeSaveProjectInputToStoryProject() - -### Community 21 - "Community 21" -Cohesion: 0.10 -Nodes (15): decryptDuckDbData(), initDuckDbEncryption(), opfsEncryptionKey, decryptDuckDbData(), initDuckDbEncryption(), getOrCreateSalt(), idbDecrypt(), idbReadSecure() (+7 more) - -### Community 22 - "Community 22" -Cohesion: 0.07 -Nodes (33): AiTaskType, classifyDevice(), detectIsMobile(), DeviceHealthReport, getBatteryLevel(), getDeviceClass(), getHealthReport(), getMemoryInfo() (+25 more) - -### Community 23 - "Community 23" +### Community 3 - "App.tsx" Cohesion: 0.03 -Nodes (48): selectEnableVoiceWasm(), useMicLevel(), mockStartListening, mockStopListening, mockVoiceSettings, usePushToTalk(), mockCancelSpeech, mockCompleteOnboarding (+40 more) +Nodes (84): App(), AppProps, CopilotLauncher, CriticView, Dashboard, ManuscriptView, ScenarioWorkspaceView, SettingsView (+76 more) -### Community 24 - "Community 24" -Cohesion: 0.07 -Nodes (53): characterHeuristicGenerator(), recordHeuristicFallback(), characterHeuristicGenerator(), CharacterHeuristicLabels, CharacterHeuristicParams, MIDDLE_CYCLE, OutlineBeatKey, outlineHeuristicGenerator() (+45 more) - -### Community 25 - "Community 25" +### Community 4 - "projectSlice.ts" Cohesion: 0.05 -Nodes (12): createCancellationToken(), InferenceProgressEmitter, handleRetry(), isLocalAiBusy(), createTaskMessage(), ProgressEmitter, listener(), PriorityTaskQueue (+4 more) - -### Community 26 - "Community 26" -Cohesion: 0.01 -Nodes (282): sanitizeRoomInput(), stripControlChars(), ApiKeySection(), CharacterCard, DetailField, DetailFieldProps, TabButton, CollaborationPanelProps (+274 more) - -### Community 27 - "Community 27" -Cohesion: 0.02 -Nodes (116): initAdaptiveAiOnStartup(), ViewLoader(), BottomTabItem, NavItem, Sidebar(), SidebarProps, DESKTOP_COMMANDS, DesktopCommandId (+108 more) +Nodes (82): RootState, ToastContext, ToastContextType, useToast(), WorldView(), activeControllers, createDeduplicatedThunk(), DeduplicatedThunkAPI (+74 more) -### Community 28 - "Community 28" -Cohesion: 0.08 -Nodes (17): analyticsSlice, AnalyticsState, DuckDbPersistenceMode, DuckDbStatus, initialState, MigrationStatus, selectDuckDbError(), selectDuckDbStatus() (+9 more) - -### Community 29 - "Community 29" -Cohesion: 0.07 -Nodes (20): MockAudioContext, MockBufferSource, MockGain, NonEndingSource, TrackingContext, KokoroTtsEngine, MockAudioContext, MockBufferSource (+12 more) +### Community 5 - "storageEncryptionService.ts" +Cohesion: 0.04 +Nodes (78): AppDispatch, IdbUnlockStartupGuardOptions, log, useIdbUnlockStartupGuard(), decryptDuckDbData(), initDuckDbEncryption(), opfsEncryptionKey, clearCompletedEncryptionMigration() (+70 more) -### Community 30 - "Community 30" -Cohesion: 0.29 -Nodes (6): Complete, Empty, Half, meta, Story, Tall +### Community 12 - "CharacterView.tsx" +Cohesion: 0.04 +Nodes (70): CharacterView, WorldView, AIProfileModal(), CharacterCard, CharacterDossier(), CharacterViewUI(), DeleteConfirmationModal(), DetailField (+62 more) -### Community 31 - "Community 31" +### Community 8 - "Dashboard.tsx" Cohesion: 0.04 -Nodes (48): AiUsageSnapshot, aiUsageTracker, lastBySource, listeners, RawUsage, normalize(), useAiUsage(), useFirstUseFlag() (+40 more) +Nodes (66): OutlineGeneratorView, AuthorInsightsCard(), Dashboard(), DashboardHeader(), baseProps, BookOpenIcon(), CalendarIcon(), FlameIcon() (+58 more) -### Community 32 - "Community 32" +### Community 7 - "store.ts" Cohesion: 0.03 -Nodes (72): detectWebGpuSupport(), isAbortError(), runLocalTextGeneration(), runTransformersLayer(), runWebLlmLayer(), sanitizeForPrompt(), warnAiCore(), makeMockBus() (+64 more) - -### Community 33 - "Community 33" -Cohesion: 0.70 -Nodes (4): check_cuda_and_vram(), check_package(), check_python_version(), main() - -### Community 34 - "Community 34" -Cohesion: 0.01 -Nodes (202): aiApi, GenerateTextRequest, GenerateTextResponse, BENCH_OPTS, fixture, ProjectSliceState, seedUndoableState(), undoableProjectReducer (+194 more) - -### Community 35 - "Community 35" -Cohesion: 0.01 -Nodes (160): getAiErrorMessage(), TransientUiState, useTransientUiStore, applyPreset(), async(), makeStoreState(), CompileWizardModal(), AccordionSection (+152 more) - -### Community 36 - "Community 36" -Cohesion: 0.28 -Nodes (6): createStorageMock(), setupStorage(), SpeechSynthesisUtteranceMock, createStorageMock(), setupStorage(), SpeechSynthesisUtteranceMock +Nodes (64): aiApi, isAnalyticsPersistenceAllowed(), selectAnalyticsPersistenceAllowed, DebouncedEffectApi, getLocalFirstHandle(), initAdaptiveAiOnStartup(), initLocalFirstSyncOnStartup(), listenerMiddleware (+56 more) -### Community 37 - "Community 37" -Cohesion: 0.00 -Nodes (500): apiKey.connectionFailed, apiKey.connectionSuccess, apiKey.decryptFailed, apiKey.decryptFailedDetail, apiKey.invalidKey, apiKey.noInternet, apiKey.rateLimited, apiKey.test (+492 more) - -### Community 38 - "Community 38" -Cohesion: 0.00 -Nodes (500): apiKey.connectionFailed, apiKey.connectionSuccess, apiKey.decryptFailed, apiKey.decryptFailedDetail, apiKey.invalidKey, apiKey.noInternet, apiKey.rateLimited, apiKey.test (+492 more) - -### Community 39 - "Community 39" -Cohesion: 0.18 -Nodes (10): ProviderOptions, Room, SignalingConn, WebrtcConn, WebrtcProvider, WebrtcProviderEvents, Room, SignalingConn (+2 more) - -### Community 40 - "Community 40" -Cohesion: 0.00 -Nodes (500): settings.about.description, settings.about.githubDescription, settings.about.githubLabel, settings.about.liveDemo, settings.about.productName, settings.about.tauriVersion, settings.about.title, settings.about.versionLabel (+492 more) - -### Community 41 - "Community 41" -Cohesion: 0.00 -Nodes (500): apiKey.connectionFailed, apiKey.connectionSuccess, apiKey.decryptFailed, apiKey.decryptFailedDetail, apiKey.invalidKey, apiKey.noInternet, apiKey.rateLimited, apiKey.test (+492 more) - -### Community 42 - "Community 42" -Cohesion: 0.02 -Nodes (97): CloudSyncMetadata, CloudSyncPayload, buildConsistencyHints(), buildEntityId(), createStoryCodexEntity(), escapeRegExpLiteral(), extractStoryCodex(), normalizeCandidate() (+89 more) - -### Community 43 - "Community 43" -Cohesion: 0.10 -Nodes (22): EMPTY_DATASET, selectActiveAdapter, selectActiveAdapterId, selectCurrentTrainingRun, selectDatasetForProject(), selectIsBuilding, selectIsEvaluating, selectIsMerging (+14 more) - -### Community 44 - "Community 44" -Cohesion: 0.00 -Nodes (500): apiKey.connectionFailed, apiKey.connectionSuccess, apiKey.decryptFailed, apiKey.decryptFailedDetail, apiKey.invalidKey, apiKey.noInternet, apiKey.rateLimited, apiKey.test (+492 more) - -### Community 45 - "Community 45" -Cohesion: 0.00 -Nodes (500): settings.about.description, settings.about.githubDescription, settings.about.githubLabel, settings.about.liveDemo, settings.about.productName, settings.about.tauriVersion, settings.about.title, settings.about.versionLabel (+492 more) - -### Community 46 - "Community 46" -Cohesion: 0.00 -Nodes (500): apiKey.connectionFailed, apiKey.connectionSuccess, apiKey.decryptFailed, apiKey.decryptFailedDetail, apiKey.invalidKey, apiKey.noInternet, apiKey.rateLimited, apiKey.test (+492 more) - -### Community 47 - "Community 47" +### Community 10 - "ToolsPanel.tsx" Cohesion: 0.03 -Nodes (71): baseRun, defaultMetrics, mockContextBase, mockContextBase, mockDispatch, mockSetActiveView, mockSkipStage, mockSubmitReview (+63 more) - -### Community 48 - "Community 48" -Cohesion: 0.00 -Nodes (500): apiKey.connectionFailed, apiKey.connectionSuccess, apiKey.decryptFailed, apiKey.decryptFailedDetail, apiKey.invalidKey, apiKey.noInternet, apiKey.rateLimited, apiKey.test (+492 more) - -### Community 50 - "Community 50" -Cohesion: 0.00 -Nodes (500): settings.about.description, settings.about.githubDescription, settings.about.githubLabel, settings.about.liveDemo, settings.about.productName, settings.about.tauriVersion, settings.about.title, settings.about.versionLabel (+492 more) - -### Community 51 - "Community 51" -Cohesion: 0.00 -Nodes (500): apiKey.connectionFailed, apiKey.connectionSuccess, apiKey.decryptFailed, apiKey.decryptFailedDetail, apiKey.invalidKey, apiKey.noInternet, apiKey.rateLimited, apiKey.test (+492 more) - -### Community 52 - "Community 52" -Cohesion: 0.08 -Nodes (38): AiErrorCategory, AiErrorClassification, categoryFromMessage(), categoryFromStatus(), classificationFor(), classifyAiError(), extractStatus(), isOffline() (+30 more) +Nodes (64): WriterView, STATUS_COLORS, DebouncedTextarea, DebouncedTextareaProps, DictationButton(), DictationButtonProps, DictationInput, Textarea (+56 more) -### Community 53 - "Community 53" -Cohesion: 0.06 -Nodes (28): GROUP_COLORS, GroupCard(), GroupForm(), OBJECT_TYPES, ObjectCard(), ObjectForm(), ObjectsView(), ObjectsViewContent() (+20 more) - -### Community 54 - "Community 54" -Cohesion: 0.00 -Nodes (500): apiKey.connectionFailed, apiKey.connectionSuccess, apiKey.decryptFailed, apiKey.decryptFailedDetail, apiKey.invalidKey, apiKey.noInternet, apiKey.rateLimited, apiKey.test (+492 more) +### Community 15 - "viewContexts.test.tsx" +Cohesion: 0.04 +Nodes (63): CharacterGraphView, ConsistencyCheckerView, HelpView, TemplateView, CharacterForceGraph(), CharacterGraphUI(), ForceGraph2D, getRelationshipColor() (+55 more) -### Community 55 - "Community 55" +### Community 28 - "devDependencies" Cohesion: 0.03 -Nodes (39): defaultState, PlotBoardMode, plotBoardPersistenceMiddleware(), plotBoardSlice, PlotBoardState, selectActiveMode(), selectActiveSubplotFilter(), selectDrawFromSectionId() (+31 more) - -### Community 56 - "Community 56" -Cohesion: 0.06 -Nodes (62): isOpenRouterFreeModel(), baseOpts, AiModeIndicator(), AiModeIndicator(), MODE_DOT_TOKEN, MODE_TOKEN, mockGetApproxRpm, mockIsCircuitOpen (+54 more) - -### Community 57 - "Community 57" -Cohesion: 0.15 -Nodes (18): EMPTY_METRICS, EMPTY_RESULT, proForgeMachine, ApplyEditsInput, ExecutablePipelineStage, ProForgeMachineContext, ProForgeMachineEvent, ProForgeMachineInput (+10 more) - -### Community 58 - "Community 58" -Cohesion: 0.00 -Nodes (500): settings.about.description, settings.about.githubDescription, settings.about.githubLabel, settings.about.liveDemo, settings.about.productName, settings.about.tauriVersion, settings.about.title, settings.about.versionLabel (+492 more) - -### Community 59 - "Community 59" -Cohesion: 0.00 -Nodes (500): apiKey.connectionFailed, apiKey.connectionSuccess, apiKey.decryptFailed, apiKey.decryptFailedDetail, apiKey.invalidKey, apiKey.noInternet, apiKey.rateLimited, apiKey.test (+492 more) - -### Community 60 - "Community 60" -Cohesion: 0.00 -Nodes (500): apiKey.connectionFailed, apiKey.connectionSuccess, apiKey.decryptFailed, apiKey.decryptFailedDetail, apiKey.invalidKey, apiKey.noInternet, apiKey.rateLimited, apiKey.test (+492 more) - -### Community 61 - "Community 61" -Cohesion: 0.17 -Nodes (11): AsyncDuckDB, AsyncDuckDBConnection, ConsoleLogger, AsyncDuckDB, AsyncDuckDBConnection, ConsoleLogger, DuckDBBundle, DuckDBBundles (+3 more) - -### Community 62 - "Community 62" -Cohesion: 0.00 -Nodes (500): settings.about.description, settings.about.githubDescription, settings.about.githubLabel, settings.about.liveDemo, settings.about.productName, settings.about.tauriVersion, settings.about.title, settings.about.versionLabel (+492 more) - -### Community 63 - "Community 63" -Cohesion: 0.00 -Nodes (500): apiKey.connectionFailed, apiKey.connectionSuccess, apiKey.decryptFailed, apiKey.decryptFailedDetail, apiKey.invalidKey, apiKey.noInternet, apiKey.rateLimited, apiKey.test (+492 more) - -### Community 64 - "Community 64" -Cohesion: 0.00 -Nodes (500): apiKey.connectionFailed, apiKey.connectionSuccess, apiKey.decryptFailed, apiKey.decryptFailedDetail, apiKey.invalidKey, apiKey.noInternet, apiKey.rateLimited, apiKey.test (+492 more) - -### Community 65 - "Community 65" -Cohesion: 0.00 -Nodes (500): settings.about.description, settings.about.githubDescription, settings.about.githubLabel, settings.about.liveDemo, settings.about.productName, settings.about.tauriVersion, settings.about.title, settings.about.versionLabel (+492 more) - -### Community 66 - "Community 66" -Cohesion: 0.00 -Nodes (500): apiKey.connectionFailed, apiKey.connectionSuccess, apiKey.decryptFailed, apiKey.decryptFailedDetail, apiKey.invalidKey, apiKey.noInternet, apiKey.rateLimited, apiKey.test (+492 more) - -### Community 67 - "Community 67" -Cohesion: 0.00 -Nodes (500): apiKey.connectionFailed, apiKey.connectionSuccess, apiKey.decryptFailed, apiKey.decryptFailedDetail, apiKey.invalidKey, apiKey.noInternet, apiKey.rateLimited, apiKey.test (+492 more) - -### Community 68 - "Community 68" -Cohesion: 0.02 -Nodes (65): getFocusable(), onKeyDown(), renderSheet(), renderPanel(), render(), renderEdges(), renderEdges(), commentsAdapter (+57 more) - -### Community 69 - "Community 69" -Cohesion: 0.43 -Nodes (6): esc(), inline(), renderExportMarkdownToHtml(), esc(), inline(), renderExportMarkdownToHtml() - -### Community 70 - "Community 70" -Cohesion: 0.00 -Nodes (500): settings.about.description, settings.about.githubDescription, settings.about.githubLabel, settings.about.liveDemo, settings.about.productName, settings.about.tauriVersion, settings.about.title, settings.about.versionLabel (+492 more) - -### Community 71 - "Community 71" -Cohesion: 0.13 -Nodes (7): FoldableLayout, FoldAxis, NO_FOLD, useFoldableLayout(), useLongPress(), makeMediaQuery(), makePointerEvent() - -### Community 72 - "Community 72" -Cohesion: 0.33 -Nodes (5): isTauriBuild(), resolveViteBase(), isTauriBuild(), resolveViteBase(), deployBase - -### Community 73 - "Community 73" -Cohesion: 0.29 -Nodes (4): deployBase, __dirname, files, root - -### Community 74 - "Community 74" -Cohesion: 0.00 -Nodes (500): apiKey.connectionFailed, apiKey.connectionSuccess, apiKey.decryptFailed, apiKey.decryptFailedDetail, apiKey.invalidKey, apiKey.noInternet, apiKey.rateLimited, apiKey.test (+492 more) - -### Community 75 - "Community 75" -Cohesion: 0.00 -Nodes (500): apiKey.connectionFailed, apiKey.connectionSuccess, apiKey.decryptFailed, apiKey.decryptFailedDetail, apiKey.invalidKey, apiKey.noInternet, apiKey.rateLimited, apiKey.test (+492 more) - -### Community 76 - "Community 76" -Cohesion: 0.00 -Nodes (500): settings.about.description, settings.about.githubDescription, settings.about.githubLabel, settings.about.liveDemo, settings.about.productName, settings.about.tauriVersion, settings.about.title, settings.about.versionLabel (+492 more) - -### Community 77 - "Community 77" -Cohesion: 0.00 -Nodes (500): apiKey.connectionFailed, apiKey.connectionSuccess, apiKey.decryptFailed, apiKey.decryptFailedDetail, apiKey.invalidKey, apiKey.noInternet, apiKey.rateLimited, apiKey.test (+492 more) - -### Community 78 - "Community 78" -Cohesion: 0.00 -Nodes (500): apiKey.connectionFailed, apiKey.connectionSuccess, apiKey.decryptFailed, apiKey.decryptFailedDetail, apiKey.invalidKey, apiKey.noInternet, apiKey.rateLimited, apiKey.test (+492 more) - -### Community 79 - "Community 79" -Cohesion: 0.09 -Nodes (28): cosineSimilarity(), countWords(), enrichProjectIndex(), extractCharacterNames(), getDb(), indexProject(), listIndexedProjects(), removeProjectIndex() (+20 more) - -### Community 80 - "Community 80" -Cohesion: 0.08 -Nodes (27): embedBatch(), embeddingCache, EmbeddingVector, embedText(), l2Normalize(), makeCacheKey(), requestEmbedding(), truncate() (+19 more) - -### Community 81 - "Community 81" -Cohesion: 0.05 -Nodes (47): OllamaDeviceRecommendation, testAIConnection(), composeSignal(), isAbortError(), isTimeoutError(), LocalServerError, localServerFetch(), resolveFetch() (+39 more) - -### Community 82 - "Community 82" -Cohesion: 0.29 -Nodes (4): MockGoogleGenAI, mockGenerateContent, mockGenerateContentStream, MockGoogleGenAI +Nodes (63): @axe-core/playwright, @biomejs/biome, http-server, jsdom, lint-staged, devDependencies, @axe-core/playwright, @biomejs/biome (+55 more) -### Community 83 - "Community 83" -Cohesion: 0.00 -Nodes (500): settings.about.description, settings.about.githubDescription, settings.about.githubLabel, settings.about.liveDemo, settings.about.productName, settings.about.tauriVersion, settings.about.title, settings.about.versionLabel (+492 more) - -### Community 84 - "Community 84" -Cohesion: 0.00 -Nodes (500): apiKey.connectionFailed, apiKey.connectionSuccess, apiKey.decryptFailed, apiKey.decryptFailedDetail, apiKey.invalidKey, apiKey.noInternet, apiKey.rateLimited, apiKey.test (+492 more) - -### Community 85 - "Community 85" -Cohesion: 0.00 -Nodes (500): apiKey.connectionFailed, apiKey.connectionSuccess, apiKey.decryptFailed, apiKey.decryptFailedDetail, apiKey.invalidKey, apiKey.noInternet, apiKey.rateLimited, apiKey.test (+492 more) - -### Community 86 - "Community 86" +### Community 13 - "StorySection" Cohesion: 0.03 -Nodes (77): makeDeps(), buildPaletteCommandModels(), collectAllDefinitions(), resolveTitle(), runCommandById(), CommandSuggestion, getLocalAiSuggestions(), buildPaletteCommandModels() (+69 more) - -### Community 87 - "Community 87" -Cohesion: 0.00 -Nodes (500): settings.about.description, settings.about.githubDescription, settings.about.githubLabel, settings.about.liveDemo, settings.about.productName, settings.about.tauriVersion, settings.about.title, settings.about.versionLabel (+492 more) - -### Community 88 - "Community 88" -Cohesion: 0.00 -Nodes (500): apiKey.connectionFailed, apiKey.connectionSuccess, apiKey.decryptFailed, apiKey.decryptFailedDetail, apiKey.invalidKey, apiKey.noInternet, apiKey.rateLimited, apiKey.test (+492 more) - -### Community 89 - "Community 89" -Cohesion: 0.14 -Nodes (9): AnalyticsAgent, AnalyticsAgent, StubAgent, SupervisorAgent, DEFAULT_QUALITY_THRESHOLDS, PipelineAnalyticsReport, QualityThresholds, StageResult (+1 more) - -### Community 90 - "Community 90" -Cohesion: 0.00 -Nodes (500): apiKey.connectionFailed, apiKey.connectionSuccess, apiKey.decryptFailed, apiKey.decryptFailedDetail, apiKey.invalidKey, apiKey.noInternet, apiKey.rateLimited, apiKey.test (+492 more) - -### Community 91 - "Community 91" -Cohesion: 0.00 -Nodes (500): settings.about.description, settings.about.githubDescription, settings.about.githubLabel, settings.about.liveDemo, settings.about.productName, settings.about.tauriVersion, settings.about.title, settings.about.versionLabel (+492 more) +Nodes (61): ACT_GRADIENT_CLASSES, ActSwimlane(), ActSwimlaneProps, CanvasCardProps, MINIMAP_H, MINIMAP_W, PlotMinimap(), PlotMinimapProps (+53 more) -### Community 92 - "Community 92" -Cohesion: 0.00 -Nodes (500): apiKey.connectionFailed, apiKey.connectionSuccess, apiKey.decryptFailed, apiKey.decryptFailedDetail, apiKey.invalidKey, apiKey.noInternet, apiKey.rateLimited, apiKey.test (+492 more) - -### Community 93 - "Community 93" -Cohesion: 0.00 -Nodes (500): apiKey.connectionFailed, apiKey.connectionSuccess, apiKey.decryptFailed, apiKey.decryptFailedDetail, apiKey.invalidKey, apiKey.noInternet, apiKey.rateLimited, apiKey.test (+492 more) - -### Community 94 - "Community 94" -Cohesion: 0.00 -Nodes (500): settings.about.description, settings.about.githubDescription, settings.about.githubLabel, settings.about.liveDemo, settings.about.productName, settings.about.tauriVersion, settings.about.title, settings.about.versionLabel (+492 more) - -### Community 95 - "Community 95" -Cohesion: 0.00 -Nodes (500): apiKey.connectionFailed, apiKey.connectionSuccess, apiKey.decryptFailed, apiKey.decryptFailedDetail, apiKey.invalidKey, apiKey.noInternet, apiKey.rateLimited, apiKey.test (+492 more) - -### Community 96 - "Community 96" -Cohesion: 0.00 -Nodes (500): apiKey.connectionFailed, apiKey.connectionSuccess, apiKey.decryptFailed, apiKey.decryptFailedDetail, apiKey.invalidKey, apiKey.noInternet, apiKey.rateLimited, apiKey.test (+492 more) - -### Community 97 - "Community 97" -Cohesion: 0.00 -Nodes (500): settings.about.description, settings.about.githubDescription, settings.about.githubLabel, settings.about.liveDemo, settings.about.productName, settings.about.tauriVersion, settings.about.title, settings.about.versionLabel (+492 more) - -### Community 98 - "Community 98" +### Community 29 - "ROADMAP-QT-GPUI-DESKTOP.md" Cohesion: 0.03 -Nodes (75): BrowserProForgeCapabilityDeps, createBrowserProForgeCapability(), resolveNodeApiKey(), createNodeProForgeCapability(), makeUnavailableGateway(), NodeCapabilityOptions, payloadToSnapshot(), createBrowserProForgeCapability() (+67 more) - -### Community 99 - "Community 99" -Cohesion: 0.00 -Nodes (500): apiKey.connectionFailed, apiKey.connectionSuccess, apiKey.decryptFailed, apiKey.decryptFailedDetail, apiKey.invalidKey, apiKey.noInternet, apiKey.rateLimited, apiKey.test (+492 more) - -### Community 100 - "Community 100" -Cohesion: 0.05 -Nodes (52): CREATIVITY_TEMPERATURE, NodeGatewayOptions, NodeInferenceGateway, getLocalFallbackModel(), getLocalModelsReady(), getOpenRouterFallbackProvider(), getOpenRouterModel(), isCloudOnlyMode() (+44 more) +Nodes (60): 0. Executive decision, 11. CI architecture, 18. React reuse policy, 19. Qt licensing and compliance gate, 1. Strategic vision, 20. Project format and migration policy, 21. Collaboration architecture, 22. AI architecture (+52 more) -### Community 101 - "Community 101" +### Community 33 - "signing-core.mjs" Cohesion: 0.08 -Nodes (44): BASE_META, handleToggle(), handleDelete(), handleFileChange(), activateAdapter(), clearDatasetEntries(), deactivateAdapter(), deleteAdapter() (+36 more) - -### Community 103 - "Community 103" -Cohesion: 0.00 -Nodes (500): apiKey.connectionFailed, apiKey.connectionSuccess, apiKey.decryptFailed, apiKey.decryptFailedDetail, apiKey.invalidKey, apiKey.noInternet, apiKey.rateLimited, apiKey.test (+492 more) - -### Community 104 - "Community 104" -Cohesion: 0.03 -Nodes (68): DeadLetterQueue, openDlqDb(), storeClear(), storeGetAll(), createMockIDB(), CancellationToken, createCancellationToken(), CircuitBreaker (+60 more) - -### Community 105 - "Community 105" -Cohesion: 0.00 -Nodes (500): settings.about.description, settings.about.githubDescription, settings.about.githubLabel, settings.about.liveDemo, settings.about.productName, settings.about.tauriVersion, settings.about.title, settings.about.versionLabel (+492 more) - -### Community 106 - "Community 106" -Cohesion: 0.04 -Nodes (34): notifyLocalModelsReady(), GpuConsumer, GpuPriority, GpuResourceManager, PRIORITY_RANK, QueueEntry, InferenceProgressEmitter, INITIAL_SNAPSHOT (+26 more) - -### Community 107 - "Community 107" -Cohesion: 0.00 -Nodes (500): apiKey.connectionFailed, apiKey.connectionSuccess, apiKey.decryptFailed, apiKey.decryptFailedDetail, apiKey.invalidKey, apiKey.noInternet, apiKey.rateLimited, apiKey.test (+492 more) - -### Community 108 - "Community 108" -Cohesion: 0.29 -Nodes (6): Default, Disabled, meta, OPTIONS, Story, WithValue - -### Community 109 - "Community 109" -Cohesion: 0.00 -Nodes (500): apiKey.connectionFailed, apiKey.connectionSuccess, apiKey.decryptFailed, apiKey.decryptFailedDetail, apiKey.invalidKey, apiKey.noInternet, apiKey.rateLimited, apiKey.test (+492 more) - -### Community 110 - "Community 110" -Cohesion: 0.00 -Nodes (500): settings.about.description, settings.about.githubDescription, settings.about.githubLabel, settings.about.liveDemo, settings.about.productName, settings.about.tauriVersion, settings.about.title, settings.about.versionLabel (+492 more) - -### Community 111 - "Community 111" -Cohesion: 0.00 -Nodes (500): apiKey.connectionFailed, apiKey.connectionSuccess, apiKey.decryptFailed, apiKey.decryptFailedDetail, apiKey.invalidKey, apiKey.noInternet, apiKey.rateLimited, apiKey.test (+492 more) - -### Community 112 - "Community 112" -Cohesion: 0.00 -Nodes (500): settings.about.description, settings.about.githubDescription, settings.about.githubLabel, settings.about.liveDemo, settings.about.productName, settings.about.tauriVersion, settings.about.title, settings.about.versionLabel (+492 more) - -### Community 113 - "Community 113" -Cohesion: 0.00 -Nodes (500): apiKey.connectionFailed, apiKey.connectionSuccess, apiKey.decryptFailed, apiKey.decryptFailedDetail, apiKey.invalidKey, apiKey.noInternet, apiKey.rateLimited, apiKey.test (+492 more) - -### Community 114 - "Community 114" -Cohesion: 0.00 -Nodes (500): settings.about.description, settings.about.githubDescription, settings.about.githubLabel, settings.about.liveDemo, settings.about.productName, settings.about.tauriVersion, settings.about.title, settings.about.versionLabel (+492 more) - -### Community 115 - "Community 115" -Cohesion: 0.00 -Nodes (500): apiKey.connectionFailed, apiKey.connectionSuccess, apiKey.decryptFailed, apiKey.decryptFailedDetail, apiKey.invalidKey, apiKey.noInternet, apiKey.rateLimited, apiKey.test (+492 more) +Nodes (56): cwd, hookMode, identity, jsonMode, signing, summary, unsafeOverrides, aggregateDiagnosticState() (+48 more) -### Community 116 - "Community 116" -Cohesion: 0.12 -Nodes (13): Default, meta, Pills, Story, TABS, Underline, WithPanels, Tab (+5 more) - -### Community 117 - "Community 117" -Cohesion: 0.00 -Nodes (500): settings.about.description, settings.about.githubDescription, settings.about.githubLabel, settings.about.liveDemo, settings.about.productName, settings.about.tauriVersion, settings.about.title, settings.about.versionLabel (+492 more) - -### Community 118 - "Community 118" -Cohesion: 0.00 -Nodes (500): apiKey.connectionFailed, apiKey.connectionSuccess, apiKey.decryptFailed, apiKey.decryptFailedDetail, apiKey.invalidKey, apiKey.noInternet, apiKey.rateLimited, apiKey.test (+492 more) - -### Community 119 - "Community 119" -Cohesion: 0.00 -Nodes (500): settings.about.description, settings.about.githubDescription, settings.about.githubLabel, settings.about.liveDemo, settings.about.productName, settings.about.tauriVersion, settings.about.title, settings.about.versionLabel (+492 more) - -### Community 120 - "Community 120" -Cohesion: 0.00 -Nodes (500): apiKey.connectionFailed, apiKey.connectionSuccess, apiKey.decryptFailed, apiKey.decryptFailedDetail, apiKey.invalidKey, apiKey.noInternet, apiKey.rateLimited, apiKey.test (+492 more) - -### Community 121 - "Community 121" -Cohesion: 0.00 -Nodes (500): apiKey.connectionFailed, apiKey.connectionSuccess, apiKey.decryptFailed, apiKey.decryptFailedDetail, apiKey.invalidKey, apiKey.noInternet, apiKey.rateLimited, apiKey.test (+492 more) - -### Community 122 - "Community 122" -Cohesion: 0.00 -Nodes (500): apiKey.connectionFailed, apiKey.connectionSuccess, apiKey.decryptFailed, apiKey.decryptFailedDetail, apiKey.invalidKey, apiKey.noInternet, apiKey.rateLimited, apiKey.test (+492 more) - -### Community 123 - "Community 123" -Cohesion: 0.00 -Nodes (500): apiKey.connectionFailed, apiKey.connectionSuccess, apiKey.decryptFailed, apiKey.decryptFailedDetail, apiKey.invalidKey, apiKey.noInternet, apiKey.rateLimited, apiKey.test (+492 more) - -### Community 124 - "Community 124" -Cohesion: 0.15 -Nodes (8): makeMockTts(), FeedbackService, mockTtsEngine, VoiceServiceConfig, FeedbackEvent, TtsEngine, VoiceEventListener, VoiceFeedbackLevel - -### Community 125 - "Community 125" -Cohesion: 0.11 -Nodes (13): formatElapsed(), Heatmap(), ProgressTrackerInner(), ProgressTrackerView(), VelocityChart(), ProgressTrackerContext, ProgressTrackerContextType, useProgressTrackerContext() (+5 more) - -### Community 126 - "Community 126" -Cohesion: 0.40 -Nodes (3): HAPTIC_PATTERNS, HapticPattern, useHaptics() - -### Community 130 - "Community 130" -Cohesion: 0.13 -Nodes (17): BookPreviewView(), MockIntersectionObserver, BookPreviewInner(), BookPreviewView(), ControlsBar(), SectionArticle(), TocSidebar(), BookPreviewContext (+9 more) - -### Community 132 - "Community 132" -Cohesion: 0.07 -Nodes (39): deletePassphraseSentinel(), getPassphraseSentinel(), PassphraseSentinelStore, savePassphraseSentinel(), IndexedDBService, IdbCodexStore, compressData(), decompressData() (+31 more) - -### Community 133 - "Community 133" +### Community 17 - "Icon.tsx" Cohesion: 0.04 -Nodes (61): AdaptiveAiEngine, estimateLatency(), getTaskConfig(), selectModelForBackend(), AdaptiveAiEngine, AiTaskType, _clearLatencyHistory(), estimateLatency() (+53 more) - -### Community 134 - "Community 134" -Cohesion: 0.11 -Nodes (24): applyDictionary(), asInt(), asString(), cacheGet(), cacheSet(), checkText(), hashKey(), normalizeMatch() (+16 more) - -### Community 135 - "Community 135" -Cohesion: 0.02 -Nodes (78): analyticsPersistenceAllowedNow(), isAnalyticsPersistenceAllowed(), analyticsPersistenceAllowedNow(), isAnalyticsPersistenceAllowed(), DebouncedEffectApi, getLocalFirstHandle(), initLocalFirstSyncOnStartup(), listenerMiddleware (+70 more) +Nodes (55): ManuscriptDesktopLayout(), ManuscriptDesktopLayoutProps, ManuscriptEditor, TYPOS_DE, TYPOS_EN, ManuscriptMobileLayout(), ManuscriptMobileLayoutProps, NavigatorItem (+47 more) -### Community 136 - "Community 136" -Cohesion: 0.13 -Nodes (10): EcoModeListener, EcoModeService, ecoSvc, mockGenerateDeviceProfile, mockGetTaskConfig, mockGetWarmedModels, mockPrewarmModel, mockReleaseModel (+2 more) - -### Community 137 - "Community 137" -Cohesion: 0.17 -Nodes (11): SceneTimelinePanel(), SceneTimelinePanelProps, evaluateSceneTimeline(), parseSceneDurationMs(), parseSceneStartMs(), evaluateSceneTimeline(), parseSceneDurationMs(), parseSceneStartMs() (+3 more) - -### Community 138 - "Community 138" -Cohesion: 0.01 -Nodes (193): DeviceClass, useAppDispatch(), useAppSelector, useAppSelectorShallow(), RootState, AdvancedImportExport(), BinderPanel(), CharacterInterviewsView() (+185 more) - -### Community 139 - "Community 139" -Cohesion: 0.13 -Nodes (7): CHARACTER_TEXT_FIELDS, characterCompleteness(), filterByQuery(), ROSTER_SORT_OPTIONS, sortByMode(), WORLD_TEXT_FIELDS, worldCompleteness() - -### Community 140 - "Community 140" -Cohesion: 0.19 -Nodes (13): releaseComputeDevice(), dbNameForProject(), isIndexedDbAvailable(), persistProjectDoc(), clearPersisted(), readPersisted(), dbNameForProject(), DocPersistence (+5 more) - -### Community 141 - "Community 141" -Cohesion: 0.18 -Nodes (13): bootstrapTranslation(), isKnownPersistedTranslationKey(), resolveTranslation(), repairProjectI18nFields(), bootstrapTranslation(), I18N_BOOTSTRAP, isKnownPersistedTranslationKey(), KNOWN_PERSISTED_KEYS (+5 more) - -### Community 142 - "Community 142" -Cohesion: 0.01 -Nodes (206): templates.adventure.arc, templates.adventure.description, templates.adventure.name, templates.adventure.sections.1, templates.adventure.sections.2, templates.adventure.sections.3, templates.adventure.sections.4, templates.adventure.sections.5 (+198 more) - -### Community 143 - "Community 143" +### Community 23 - "types.ts" Cohesion: 0.05 -Nodes (56): FallbackOpts, resolveProviderFallbackChain(), _cleanupPendingRequest(), _deduplicateRequest(), deliverAnthropicResponse(), generateTextSingleProvider(), _pendingKey(), streamAiHelpResponse() (+48 more) - -### Community 144 - "Community 144" -Cohesion: 0.11 -Nodes (20): computeCentroid(), countWords(), estimateDatasetQuality(), exportAsJsonl(), extractScenePairs(), generateSyntheticPairs(), getEmbeddingService(), RawSection (+12 more) - -### Community 145 - "Community 145" -Cohesion: 0.01 -Nodes (206): templates.adventure.arc, templates.adventure.description, templates.adventure.name, templates.adventure.sections.1, templates.adventure.sections.2, templates.adventure.sections.3, templates.adventure.sections.4, templates.adventure.sections.5 (+198 more) - -### Community 146 - "Community 146" -Cohesion: 0.01 -Nodes (206): templates.adventure.arc, templates.adventure.description, templates.adventure.name, templates.adventure.sections.1, templates.adventure.sections.2, templates.adventure.sections.3, templates.adventure.sections.4, templates.adventure.sections.5 (+198 more) - -### Community 147 - "Community 147" -Cohesion: 0.33 -Nodes (3): fakeDb, storeData, TestDbService - -### Community 148 - "Community 148" -Cohesion: 0.01 -Nodes (206): templates.adventure.arc, templates.adventure.description, templates.adventure.name, templates.adventure.sections.1, templates.adventure.sections.2, templates.adventure.sections.3, templates.adventure.sections.4, templates.adventure.sections.5 (+198 more) - -### Community 149 - "Community 149" -Cohesion: 0.01 -Nodes (206): templates.adventure.arc, templates.adventure.description, templates.adventure.name, templates.adventure.sections.1, templates.adventure.sections.2, templates.adventure.sections.3, templates.adventure.sections.4, templates.adventure.sections.5 (+198 more) - -### Community 150 - "Community 150" -Cohesion: 0.15 -Nodes (8): getFocusable(), handleTabKey(), Left, meta, Right, Story, Drawer(), DrawerProps - -### Community 151 - "Community 151" -Cohesion: 0.01 -Nodes (206): templates.adventure.arc, templates.adventure.description, templates.adventure.name, templates.adventure.sections.1, templates.adventure.sections.2, templates.adventure.sections.3, templates.adventure.sections.4, templates.adventure.sections.5 (+198 more) - -### Community 152 - "Community 152" -Cohesion: 0.01 -Nodes (206): templates.adventure.arc, templates.adventure.description, templates.adventure.name, templates.adventure.sections.1, templates.adventure.sections.2, templates.adventure.sections.3, templates.adventure.sections.4, templates.adventure.sections.5 (+198 more) - -### Community 153 - "Community 153" -Cohesion: 0.01 -Nodes (206): templates.adventure.arc, templates.adventure.description, templates.adventure.name, templates.adventure.sections.1, templates.adventure.sections.2, templates.adventure.sections.3, templates.adventure.sections.4, templates.adventure.sections.5 (+198 more) - -### Community 154 - "Community 154" -Cohesion: 0.01 -Nodes (206): templates.adventure.arc, templates.adventure.description, templates.adventure.name, templates.adventure.sections.1, templates.adventure.sections.2, templates.adventure.sections.3, templates.adventure.sections.4, templates.adventure.sections.5 (+198 more) - -### Community 155 - "Community 155" -Cohesion: 0.01 -Nodes (206): templates.adventure.arc, templates.adventure.description, templates.adventure.name, templates.adventure.sections.1, templates.adventure.sections.2, templates.adventure.sections.3, templates.adventure.sections.4, templates.adventure.sections.5 (+198 more) - -### Community 156 - "Community 156" -Cohesion: 0.01 -Nodes (206): templates.adventure.arc, templates.adventure.description, templates.adventure.name, templates.adventure.sections.1, templates.adventure.sections.2, templates.adventure.sections.3, templates.adventure.sections.4, templates.adventure.sections.5 (+198 more) - -### Community 157 - "Community 157" -Cohesion: 0.01 -Nodes (206): templates.adventure.arc, templates.adventure.description, templates.adventure.name, templates.adventure.sections.1, templates.adventure.sections.2, templates.adventure.sections.3, templates.adventure.sections.4, templates.adventure.sections.5 (+198 more) - -### Community 158 - "Community 158" -Cohesion: 0.16 -Nodes (12): broadcast(), getAudioContextCtor(), start(), subscribers, teardown(), FakeAudioContext, WindowWithAudio, broadcast() (+4 more) - -### Community 159 - "Community 159" -Cohesion: 0.01 -Nodes (206): templates.adventure.arc, templates.adventure.description, templates.adventure.name, templates.adventure.sections.1, templates.adventure.sections.2, templates.adventure.sections.3, templates.adventure.sections.4, templates.adventure.sections.5 (+198 more) - -### Community 160 - "Community 160" -Cohesion: 0.01 -Nodes (206): templates.adventure.arc, templates.adventure.description, templates.adventure.name, templates.adventure.sections.1, templates.adventure.sections.2, templates.adventure.sections.3, templates.adventure.sections.4, templates.adventure.sections.5 (+198 more) - -### Community 161 - "Community 161" -Cohesion: 0.03 -Nodes (65): useCommandExecutor(), CharacterForceGraph(), CharacterGraphUI(), CharacterGraphView(), ForceGraph2D, GraphLink, GraphNode, RELATIONSHIP_COLORS (+57 more) - -### Community 162 - "Community 162" -Cohesion: 0.01 -Nodes (206): templates.adventure.arc, templates.adventure.description, templates.adventure.name, templates.adventure.sections.1, templates.adventure.sections.2, templates.adventure.sections.3, templates.adventure.sections.4, templates.adventure.sections.5 (+198 more) - -### Community 163 - "Community 163" -Cohesion: 0.01 -Nodes (206): templates.adventure.arc, templates.adventure.description, templates.adventure.name, templates.adventure.sections.1, templates.adventure.sections.2, templates.adventure.sections.3, templates.adventure.sections.4, templates.adventure.sections.5 (+198 more) - -### Community 164 - "Community 164" -Cohesion: 0.01 -Nodes (206): templates.adventure.arc, templates.adventure.description, templates.adventure.name, templates.adventure.sections.1, templates.adventure.sections.2, templates.adventure.sections.3, templates.adventure.sections.4, templates.adventure.sections.5 (+198 more) - -### Community 165 - "Community 165" -Cohesion: 0.01 -Nodes (206): templates.adventure.arc, templates.adventure.description, templates.adventure.name, templates.adventure.sections.1, templates.adventure.sections.2, templates.adventure.sections.3, templates.adventure.sections.4, templates.adventure.sections.5 (+198 more) - -### Community 166 - "Community 166" -Cohesion: 0.40 -Nodes (3): fakeDb, fakeStore, getService() - -### Community 167 - "Community 167" -Cohesion: 0.01 -Nodes (206): templates.adventure.arc, templates.adventure.description, templates.adventure.name, templates.adventure.sections.1, templates.adventure.sections.2, templates.adventure.sections.3, templates.adventure.sections.4, templates.adventure.sections.5 (+198 more) - -### Community 168 - "Community 168" -Cohesion: 0.17 -Nodes (9): buildVoiceCommandMap(), buildVoiceCommandMap(), STATIC_VOICE_COMMANDS, HybridIntentEngine, baseContext, IntentContext, IntentEngine, ParsedIntent (+1 more) - -### Community 169 - "Community 169" -Cohesion: 0.13 -Nodes (8): Resizer, ResizerProps, Default, ExtraLarge, Large, meta, Story, DEFAULT_PROPS - -### Community 170 - "Community 170" -Cohesion: 0.01 -Nodes (161): help.advanced.adaptiveAi.content, help.advanced.adaptiveAi.title, help.advanced.cloudSync.content, help.advanced.cloudSync.title, help.advanced.encryption.content, help.advanced.encryption.title, help.advanced.languages.content, help.advanced.languages.title (+153 more) - -### Community 171 - "Community 171" -Cohesion: 0.01 -Nodes (161): help.advanced.adaptiveAi.content, help.advanced.adaptiveAi.title, help.advanced.cloudSync.content, help.advanced.cloudSync.title, help.advanced.encryption.content, help.advanced.encryption.title, help.advanced.languages.content, help.advanced.languages.title (+153 more) - -### Community 172 - "Community 172" -Cohesion: 0.01 -Nodes (161): help.advanced.adaptiveAi.content, help.advanced.adaptiveAi.title, help.advanced.cloudSync.content, help.advanced.cloudSync.title, help.advanced.encryption.content, help.advanced.encryption.title, help.advanced.languages.content, help.advanced.languages.title (+153 more) - -### Community 173 - "Community 173" -Cohesion: 0.01 -Nodes (161): help.advanced.adaptiveAi.content, help.advanced.adaptiveAi.title, help.advanced.cloudSync.content, help.advanced.cloudSync.title, help.advanced.encryption.content, help.advanced.encryption.title, help.advanced.languages.content, help.advanced.languages.title (+153 more) - -### Community 174 - "Community 174" -Cohesion: 0.01 -Nodes (161): help.advanced.adaptiveAi.content, help.advanced.adaptiveAi.title, help.advanced.cloudSync.content, help.advanced.cloudSync.title, help.advanced.encryption.content, help.advanced.encryption.title, help.advanced.languages.content, help.advanced.languages.title (+153 more) - -### Community 175 - "Community 175" -Cohesion: 0.01 -Nodes (161): help.advanced.adaptiveAi.content, help.advanced.adaptiveAi.title, help.advanced.cloudSync.content, help.advanced.cloudSync.title, help.advanced.encryption.content, help.advanced.encryption.title, help.advanced.languages.content, help.advanced.languages.title (+153 more) - -### Community 176 - "Community 176" -Cohesion: 0.01 -Nodes (161): help.advanced.adaptiveAi.content, help.advanced.adaptiveAi.title, help.advanced.cloudSync.content, help.advanced.cloudSync.title, help.advanced.encryption.content, help.advanced.encryption.title, help.advanced.languages.content, help.advanced.languages.title (+153 more) - -### Community 177 - "Community 177" -Cohesion: 0.01 -Nodes (161): help.advanced.adaptiveAi.content, help.advanced.adaptiveAi.title, help.advanced.cloudSync.content, help.advanced.cloudSync.title, help.advanced.encryption.content, help.advanced.encryption.title, help.advanced.languages.content, help.advanced.languages.title (+153 more) - -### Community 178 - "Community 178" -Cohesion: 0.01 -Nodes (161): help.advanced.adaptiveAi.content, help.advanced.adaptiveAi.title, help.advanced.cloudSync.content, help.advanced.cloudSync.title, help.advanced.encryption.content, help.advanced.encryption.title, help.advanced.languages.content, help.advanced.languages.title (+153 more) - -### Community 179 - "Community 179" -Cohesion: 0.01 -Nodes (161): help.advanced.adaptiveAi.content, help.advanced.adaptiveAi.title, help.advanced.cloudSync.content, help.advanced.cloudSync.title, help.advanced.encryption.content, help.advanced.encryption.title, help.advanced.languages.content, help.advanced.languages.title (+153 more) - -### Community 180 - "Community 180" -Cohesion: 0.01 -Nodes (161): help.advanced.adaptiveAi.content, help.advanced.adaptiveAi.title, help.advanced.cloudSync.content, help.advanced.cloudSync.title, help.advanced.encryption.content, help.advanced.encryption.title, help.advanced.languages.content, help.advanced.languages.title (+153 more) - -### Community 181 - "Community 181" -Cohesion: 0.01 -Nodes (161): help.advanced.adaptiveAi.content, help.advanced.adaptiveAi.title, help.advanced.cloudSync.content, help.advanced.cloudSync.title, help.advanced.encryption.content, help.advanced.encryption.title, help.advanced.languages.content, help.advanced.languages.title (+153 more) - -### Community 182 - "Community 182" -Cohesion: 0.01 -Nodes (161): help.advanced.adaptiveAi.content, help.advanced.adaptiveAi.title, help.advanced.cloudSync.content, help.advanced.cloudSync.title, help.advanced.encryption.content, help.advanced.encryption.title, help.advanced.languages.content, help.advanced.languages.title (+153 more) - -### Community 183 - "Community 183" -Cohesion: 0.01 -Nodes (161): help.advanced.adaptiveAi.content, help.advanced.adaptiveAi.title, help.advanced.cloudSync.content, help.advanced.cloudSync.title, help.advanced.encryption.content, help.advanced.encryption.title, help.advanced.languages.content, help.advanced.languages.title (+153 more) +Nodes (55): formatKeysForDisplay(), ShortcutsSection(), STORY_TEMPLATES, getDefaultKeyboardShortcuts(), SHORTCUT_ACTION_REGISTRY, defaultDesktopSettings, defaultVoiceSettings, applyInitialTheme() (+47 more) -### Community 184 - "Community 184" -Cohesion: 0.01 -Nodes (161): help.advanced.adaptiveAi.content, help.advanced.adaptiveAi.title, help.advanced.cloudSync.content, help.advanced.cloudSync.title, help.advanced.encryption.content, help.advanced.encryption.title, help.advanced.languages.content, help.advanced.languages.title (+153 more) - -### Community 185 - "Community 185" -Cohesion: 0.04 -Nodes (42): accessibilityPresetDefaults(), normalizeAccessibilitySettings(), applyPreset(), Params, dummyApi, dummyShortcuts, mockFindMatchingShortcutAction, mockPerformShortcutAction (+34 more) - -### Community 186 - "Community 186" -Cohesion: 0.01 -Nodes (161): help.advanced.adaptiveAi.content, help.advanced.adaptiveAi.title, help.advanced.cloudSync.content, help.advanced.cloudSync.title, help.advanced.encryption.content, help.advanced.encryption.title, help.advanced.languages.content, help.advanced.languages.title (+153 more) - -### Community 187 - "Community 187" -Cohesion: 0.01 -Nodes (161): help.advanced.adaptiveAi.content, help.advanced.adaptiveAi.title, help.advanced.cloudSync.content, help.advanced.cloudSync.title, help.advanced.encryption.content, help.advanced.encryption.title, help.advanced.languages.content, help.advanced.languages.title (+153 more) - -### Community 188 - "Community 188" -Cohesion: 0.25 -Nodes (7): TemplateView(), baseContextValue, mockCloseModal, mockOnNavigate, mockOpenPreviewModal, mockSetFilter, mockSetModalState - -### Community 189 - "Community 189" -Cohesion: 0.01 -Nodes (161): help.advanced.adaptiveAi.content, help.advanced.adaptiveAi.title, help.advanced.cloudSync.content, help.advanced.cloudSync.title, help.advanced.encryption.content, help.advanced.encryption.title, help.advanced.languages.content, help.advanced.languages.title (+153 more) - -### Community 190 - "Community 190" -Cohesion: 0.01 -Nodes (161): help.advanced.adaptiveAi.content, help.advanced.adaptiveAi.title, help.advanced.cloudSync.content, help.advanced.cloudSync.title, help.advanced.encryption.content, help.advanced.encryption.title, help.advanced.languages.content, help.advanced.languages.title (+153 more) - -### Community 191 - "Community 191" -Cohesion: 0.16 -Nodes (11): Beta, CustomLabel, Decorative, Experimental, meta, New, Story, Badge (+3 more) - -### Community 192 - "Community 192" -Cohesion: 0.16 -Nodes (11): defaultProject(), mockComputeReadability, mockDispatch, mockEvaluateTimeline, mockSamplePlainText, mockToast, mockUnwrap, onNavigate (+3 more) - -### Community 193 - "Community 193" -Cohesion: 0.09 -Nodes (29): PAYLOAD, bankCache, clearMemoryBankCache(), clearProjectMemory(), deleteMemoryEntry(), getMemoryEntries(), idbAvailable(), keywordScorer() (+21 more) - -### Community 194 - "Community 194" -Cohesion: 0.21 -Nodes (10): makeContext(), makeLargeContext(), makeSection(), DEFAULT_CONFIG, makeContext(), makeLargeContext(), makeSection(), mockGenerate (+2 more) - -### Community 195 - "Community 195" -Cohesion: 0.18 -Nodes (4): pipeline(), mlcState, tabLeaderState, xenovaState - -### Community 196 - "Community 196" -Cohesion: 0.18 -Nodes (10): mockAbortPipeline, mockDispatch, mockDispose, mockOrchestrator, mockProForgeState, mockProject, mockRollbackTo, mockSkipStage (+2 more) - -### Community 197 - "Community 197" -Cohesion: 0.22 -Nodes (5): useResizablePanels(), useManuscriptLayout(), useMediaQuery(), makePointerEvent(), useResizablePanels() - -### Community 198 - "Community 198" -Cohesion: 0.02 -Nodes (114): writer.cancelledTag, writer.chapter.label, writer.coachmark.dismiss, writer.coachmark.flow.body, writer.coachmark.flow.title, writer.coachmark.focus.body, writer.coachmark.focus.title, writer.coachmark.proforge.body (+106 more) - -### Community 199 - "Community 199" -Cohesion: 0.02 -Nodes (114): writer.cancelledTag, writer.chapter.label, writer.coachmark.dismiss, writer.coachmark.flow.body, writer.coachmark.flow.title, writer.coachmark.focus.body, writer.coachmark.focus.title, writer.coachmark.proforge.body (+106 more) - -### Community 200 - "Community 200" -Cohesion: 0.02 -Nodes (114): writer.cancelledTag, writer.chapter.label, writer.coachmark.dismiss, writer.coachmark.flow.body, writer.coachmark.flow.title, writer.coachmark.focus.body, writer.coachmark.focus.title, writer.coachmark.proforge.body (+106 more) - -### Community 201 - "Community 201" -Cohesion: 0.02 -Nodes (114): writer.cancelledTag, writer.chapter.label, writer.coachmark.dismiss, writer.coachmark.flow.body, writer.coachmark.flow.title, writer.coachmark.focus.body, writer.coachmark.focus.title, writer.coachmark.proforge.body (+106 more) - -### Community 202 - "Community 202" -Cohesion: 0.03 -Nodes (66): MindMapView(), MindMapViewContext, useMindMapViewContext(), NewMindMapDraft, NewMindMapEdgeDraft, NewMindMapNodeDraft, MOCK_MAP, mockDispatch (+58 more) - -### Community 203 - "Community 203" -Cohesion: 0.09 -Nodes (13): ConsentRequiredError, ConsentRequiredError, createSttEngine(), SpeechRecognitionLike, SttEngineFactoryOptions, WebSpeechSttEngine, VoiceActivityCoordinator, AudioStreamConfig (+5 more) - -### Community 204 - "Community 204" -Cohesion: 0.02 -Nodes (114): writer.cancelledTag, writer.chapter.label, writer.coachmark.dismiss, writer.coachmark.flow.body, writer.coachmark.flow.title, writer.coachmark.focus.body, writer.coachmark.focus.title, writer.coachmark.proforge.body (+106 more) - -### Community 205 - "Community 205" -Cohesion: 0.02 -Nodes (114): writer.cancelledTag, writer.chapter.label, writer.coachmark.dismiss, writer.coachmark.flow.body, writer.coachmark.flow.title, writer.coachmark.focus.body, writer.coachmark.focus.title, writer.coachmark.proforge.body (+106 more) - -### Community 206 - "Community 206" -Cohesion: 0.02 -Nodes (114): writer.cancelledTag, writer.chapter.label, writer.coachmark.dismiss, writer.coachmark.flow.body, writer.coachmark.flow.title, writer.coachmark.focus.body, writer.coachmark.focus.title, writer.coachmark.proforge.body (+106 more) - -### Community 207 - "Community 207" -Cohesion: 0.13 -Nodes (24): assembleRAGPrompt(), buildRAGContextBlock(), deduplicateChunksBySection(), estimateTokens(), fetchRagChunks(), fitRagChunks(), sectionTitleFor(), truncateAtSentence() (+16 more) - -### Community 208 - "Community 208" -Cohesion: 0.02 -Nodes (114): writer.cancelledTag, writer.chapter.label, writer.coachmark.dismiss, writer.coachmark.flow.body, writer.coachmark.flow.title, writer.coachmark.focus.body, writer.coachmark.focus.title, writer.coachmark.proforge.body (+106 more) - -### Community 209 - "Community 209" -Cohesion: 0.02 -Nodes (114): writer.cancelledTag, writer.chapter.label, writer.coachmark.dismiss, writer.coachmark.flow.body, writer.coachmark.flow.title, writer.coachmark.focus.body, writer.coachmark.focus.title, writer.coachmark.proforge.body (+106 more) - -### Community 210 - "Community 210" -Cohesion: 0.04 -Nodes (41): Entry, PipelineLruCache, PipelineLruOptions, close(), onKey(), onPointerDown(), asPreparable(), getDuckDb() (+33 more) - -### Community 211 - "Community 211" -Cohesion: 0.27 -Nodes (11): esc(), isCodexExcerptEncryptionMigrationDone(), markerKey(), runCodexExcerptEncryptionMigration(), esc(), isCodexExcerptEncryptionMigrationDone(), markerKey(), PlaintextExcerptRow (+3 more) - -### Community 212 - "Community 212" -Cohesion: 0.06 -Nodes (33): FsAssetStore, FsCodexStore, base64ToBytes(), bytesToBase64(), compressData(), countProjectWords(), decompressData(), decryptText() (+25 more) - -### Community 213 - "Community 213" -Cohesion: 0.02 -Nodes (114): writer.cancelledTag, writer.chapter.label, writer.coachmark.dismiss, writer.coachmark.flow.body, writer.coachmark.flow.title, writer.coachmark.focus.body, writer.coachmark.focus.title, writer.coachmark.proforge.body (+106 more) - -### Community 214 - "Community 214" -Cohesion: 0.02 -Nodes (114): writer.cancelledTag, writer.chapter.label, writer.coachmark.dismiss, writer.coachmark.flow.body, writer.coachmark.flow.title, writer.coachmark.focus.body, writer.coachmark.focus.title, writer.coachmark.proforge.body (+106 more) - -### Community 215 - "Community 215" -Cohesion: 0.02 -Nodes (114): writer.cancelledTag, writer.chapter.label, writer.coachmark.dismiss, writer.coachmark.flow.body, writer.coachmark.flow.title, writer.coachmark.focus.body, writer.coachmark.focus.title, writer.coachmark.proforge.body (+106 more) - -### Community 216 - "Community 216" -Cohesion: 0.09 -Nodes (10): CopilotIntent, detectCopilotIntent(), DIAGNOSTIC_PATTERNS, DiagnosticSummary, EXPLAIN_VIEW_PATTERNS, runCopilotDiagnostic(), runCopilotDiagnostic(), ProForgeCapabilityLayer (+2 more) - -### Community 217 - "Community 217" -Cohesion: 0.02 -Nodes (114): writer.cancelledTag, writer.chapter.label, writer.coachmark.dismiss, writer.coachmark.flow.body, writer.coachmark.flow.title, writer.coachmark.focus.body, writer.coachmark.focus.title, writer.coachmark.proforge.body (+106 more) - -### Community 218 - "Community 218" -Cohesion: 0.02 -Nodes (114): writer.cancelledTag, writer.chapter.label, writer.coachmark.dismiss, writer.coachmark.flow.body, writer.coachmark.flow.title, writer.coachmark.focus.body, writer.coachmark.focus.title, writer.coachmark.proforge.body (+106 more) - -### Community 219 - "Community 219" -Cohesion: 0.02 -Nodes (114): writer.cancelledTag, writer.chapter.label, writer.coachmark.dismiss, writer.coachmark.flow.body, writer.coachmark.flow.title, writer.coachmark.focus.body, writer.coachmark.focus.title, writer.coachmark.proforge.body (+106 more) - -### Community 220 - "Community 220" -Cohesion: 0.07 -Nodes (40): navigateToCollaborationSettings(), criticalCombinations, E2EFlagKey, TestConfig, testConfigurations, navigateToCollaborationSettings(), clickNavItem(), ensureBlankProject() (+32 more) - -### Community 221 - "Community 221" -Cohesion: 0.02 -Nodes (114): writer.cancelledTag, writer.chapter.label, writer.coachmark.dismiss, writer.coachmark.flow.body, writer.coachmark.flow.title, writer.coachmark.focus.body, writer.coachmark.focus.title, writer.coachmark.proforge.body (+106 more) - -### Community 222 - "Community 222" -Cohesion: 0.02 -Nodes (114): writer.cancelledTag, writer.chapter.label, writer.coachmark.dismiss, writer.coachmark.flow.body, writer.coachmark.flow.title, writer.coachmark.focus.body, writer.coachmark.focus.title, writer.coachmark.proforge.body (+106 more) - -### Community 223 - "Community 223" -Cohesion: 0.02 -Nodes (114): writer.cancelledTag, writer.chapter.label, writer.coachmark.dismiss, writer.coachmark.flow.body, writer.coachmark.flow.title, writer.coachmark.focus.body, writer.coachmark.focus.title, writer.coachmark.proforge.body (+106 more) - -### Community 224 - "Community 224" -Cohesion: 0.02 -Nodes (114): writer.cancelledTag, writer.chapter.label, writer.coachmark.dismiss, writer.coachmark.flow.body, writer.coachmark.flow.title, writer.coachmark.focus.body, writer.coachmark.focus.title, writer.coachmark.proforge.body (+106 more) +### Community 6 - "ProjectData" +Cohesion: 0.05 +Nodes (54): SceneBoardViewContextType, charactersAdapter, worldsAdapter, initialState, ProjectData, ProjectSliceState, binderReducers, characterReducers (+46 more) -### Community 225 - "Community 225" -Cohesion: 0.02 -Nodes (111): dashboard.authorInsights.readability, dashboard.authorInsights.readabilityFootnote, dashboard.authorInsights.readabilityNeedMore, dashboard.authorInsights.readabilityScaleSuffix, dashboard.authorInsights.readabilityTooltip, dashboard.authorInsights.timeline, dashboard.authorInsights.timelineClear, dashboard.authorInsights.timelineWarnBadge (+103 more) - -### Community 226 - "Community 226" -Cohesion: 0.02 -Nodes (111): dashboard.authorInsights.readability, dashboard.authorInsights.readabilityFootnote, dashboard.authorInsights.readabilityNeedMore, dashboard.authorInsights.readabilityScaleSuffix, dashboard.authorInsights.readabilityTooltip, dashboard.authorInsights.timeline, dashboard.authorInsights.timelineClear, dashboard.authorInsights.timelineWarnBadge (+103 more) - -### Community 227 - "Community 227" -Cohesion: 0.02 -Nodes (111): dashboard.authorInsights.readability, dashboard.authorInsights.readabilityFootnote, dashboard.authorInsights.readabilityNeedMore, dashboard.authorInsights.readabilityScaleSuffix, dashboard.authorInsights.readabilityTooltip, dashboard.authorInsights.timeline, dashboard.authorInsights.timelineClear, dashboard.authorInsights.timelineWarnBadge (+103 more) - -### Community 228 - "Community 228" -Cohesion: 0.02 -Nodes (111): dashboard.authorInsights.readability, dashboard.authorInsights.readabilityFootnote, dashboard.authorInsights.readabilityNeedMore, dashboard.authorInsights.readabilityScaleSuffix, dashboard.authorInsights.readabilityTooltip, dashboard.authorInsights.timeline, dashboard.authorInsights.timelineClear, dashboard.authorInsights.timelineWarnBadge (+103 more) - -### Community 229 - "Community 229" -Cohesion: 0.02 -Nodes (111): dashboard.authorInsights.readability, dashboard.authorInsights.readabilityFootnote, dashboard.authorInsights.readabilityNeedMore, dashboard.authorInsights.readabilityScaleSuffix, dashboard.authorInsights.readabilityTooltip, dashboard.authorInsights.timeline, dashboard.authorInsights.timelineClear, dashboard.authorInsights.timelineWarnBadge (+103 more) - -### Community 230 - "Community 230" -Cohesion: 0.02 -Nodes (111): dashboard.authorInsights.readability, dashboard.authorInsights.readabilityFootnote, dashboard.authorInsights.readabilityNeedMore, dashboard.authorInsights.readabilityScaleSuffix, dashboard.authorInsights.readabilityTooltip, dashboard.authorInsights.timeline, dashboard.authorInsights.timelineClear, dashboard.authorInsights.timelineWarnBadge (+103 more) - -### Community 231 - "Community 231" -Cohesion: 0.02 -Nodes (111): dashboard.authorInsights.readability, dashboard.authorInsights.readabilityFootnote, dashboard.authorInsights.readabilityNeedMore, dashboard.authorInsights.readabilityScaleSuffix, dashboard.authorInsights.readabilityTooltip, dashboard.authorInsights.timeline, dashboard.authorInsights.timelineClear, dashboard.authorInsights.timelineWarnBadge (+103 more) - -### Community 232 - "Community 232" -Cohesion: 0.02 -Nodes (111): dashboard.authorInsights.readability, dashboard.authorInsights.readabilityFootnote, dashboard.authorInsights.readabilityNeedMore, dashboard.authorInsights.readabilityScaleSuffix, dashboard.authorInsights.readabilityTooltip, dashboard.authorInsights.timeline, dashboard.authorInsights.timelineClear, dashboard.authorInsights.timelineWarnBadge (+103 more) - -### Community 233 - "Community 233" -Cohesion: 0.02 -Nodes (111): dashboard.authorInsights.readability, dashboard.authorInsights.readabilityFootnote, dashboard.authorInsights.readabilityNeedMore, dashboard.authorInsights.readabilityScaleSuffix, dashboard.authorInsights.readabilityTooltip, dashboard.authorInsights.timeline, dashboard.authorInsights.timelineClear, dashboard.authorInsights.timelineWarnBadge (+103 more) - -### Community 234 - "Community 234" -Cohesion: 0.02 -Nodes (111): dashboard.authorInsights.readability, dashboard.authorInsights.readabilityFootnote, dashboard.authorInsights.readabilityNeedMore, dashboard.authorInsights.readabilityScaleSuffix, dashboard.authorInsights.readabilityTooltip, dashboard.authorInsights.timeline, dashboard.authorInsights.timelineClear, dashboard.authorInsights.timelineWarnBadge (+103 more) - -### Community 235 - "Community 235" -Cohesion: 0.02 -Nodes (111): dashboard.authorInsights.readability, dashboard.authorInsights.readabilityFootnote, dashboard.authorInsights.readabilityNeedMore, dashboard.authorInsights.readabilityScaleSuffix, dashboard.authorInsights.readabilityTooltip, dashboard.authorInsights.timeline, dashboard.authorInsights.timelineClear, dashboard.authorInsights.timelineWarnBadge (+103 more) - -### Community 236 - "Community 236" -Cohesion: 0.02 -Nodes (111): dashboard.authorInsights.readability, dashboard.authorInsights.readabilityFootnote, dashboard.authorInsights.readabilityNeedMore, dashboard.authorInsights.readabilityScaleSuffix, dashboard.authorInsights.readabilityTooltip, dashboard.authorInsights.timeline, dashboard.authorInsights.timelineClear, dashboard.authorInsights.timelineWarnBadge (+103 more) - -### Community 237 - "Community 237" -Cohesion: 0.02 -Nodes (111): dashboard.authorInsights.readability, dashboard.authorInsights.readabilityFootnote, dashboard.authorInsights.readabilityNeedMore, dashboard.authorInsights.readabilityScaleSuffix, dashboard.authorInsights.readabilityTooltip, dashboard.authorInsights.timeline, dashboard.authorInsights.timelineClear, dashboard.authorInsights.timelineWarnBadge (+103 more) - -### Community 238 - "Community 238" -Cohesion: 0.02 -Nodes (111): dashboard.authorInsights.readability, dashboard.authorInsights.readabilityFootnote, dashboard.authorInsights.readabilityNeedMore, dashboard.authorInsights.readabilityScaleSuffix, dashboard.authorInsights.readabilityTooltip, dashboard.authorInsights.timeline, dashboard.authorInsights.timelineClear, dashboard.authorInsights.timelineWarnBadge (+103 more) - -### Community 239 - "Community 239" -Cohesion: 0.02 -Nodes (111): dashboard.authorInsights.readability, dashboard.authorInsights.readabilityFootnote, dashboard.authorInsights.readabilityNeedMore, dashboard.authorInsights.readabilityScaleSuffix, dashboard.authorInsights.readabilityTooltip, dashboard.authorInsights.timeline, dashboard.authorInsights.timelineClear, dashboard.authorInsights.timelineWarnBadge (+103 more) - -### Community 240 - "Community 240" -Cohesion: 0.02 -Nodes (111): dashboard.authorInsights.readability, dashboard.authorInsights.readabilityFootnote, dashboard.authorInsights.readabilityNeedMore, dashboard.authorInsights.readabilityScaleSuffix, dashboard.authorInsights.readabilityTooltip, dashboard.authorInsights.timeline, dashboard.authorInsights.timelineClear, dashboard.authorInsights.timelineWarnBadge (+103 more) - -### Community 241 - "Community 241" -Cohesion: 0.19 -Nodes (3): WorkerPool, MockWorker, MockWorker - -### Community 242 - "Community 242" -Cohesion: 0.02 -Nodes (111): dashboard.authorInsights.readability, dashboard.authorInsights.readabilityFootnote, dashboard.authorInsights.readabilityNeedMore, dashboard.authorInsights.readabilityScaleSuffix, dashboard.authorInsights.readabilityTooltip, dashboard.authorInsights.timeline, dashboard.authorInsights.timelineClear, dashboard.authorInsights.timelineWarnBadge (+103 more) - -### Community 244 - "Community 244" -Cohesion: 0.02 -Nodes (111): dashboard.authorInsights.readability, dashboard.authorInsights.readabilityFootnote, dashboard.authorInsights.readabilityNeedMore, dashboard.authorInsights.readabilityScaleSuffix, dashboard.authorInsights.readabilityTooltip, dashboard.authorInsights.timeline, dashboard.authorInsights.timelineClear, dashboard.authorInsights.timelineWarnBadge (+103 more) - -### Community 245 - "Community 245" -Cohesion: 0.02 -Nodes (111): dashboard.authorInsights.readability, dashboard.authorInsights.readabilityFootnote, dashboard.authorInsights.readabilityNeedMore, dashboard.authorInsights.readabilityScaleSuffix, dashboard.authorInsights.readabilityTooltip, dashboard.authorInsights.timeline, dashboard.authorInsights.timelineClear, dashboard.authorInsights.timelineWarnBadge (+103 more) - -### Community 246 - "Community 246" -Cohesion: 0.02 -Nodes (95): export.ai.generateButton, export.ai.generating, export.ai.synopsis, export.ai.synopsisPlaceholder, export.ai.synopsisTitle, export.ai.title, export.appearanceLabel, export.backstoryLabel (+87 more) - -### Community 247 - "Community 247" -Cohesion: 0.02 -Nodes (95): export.ai.generateButton, export.ai.generating, export.ai.synopsis, export.ai.synopsisPlaceholder, export.ai.synopsisTitle, export.ai.title, export.appearanceLabel, export.backstoryLabel (+87 more) - -### Community 248 - "Community 248" -Cohesion: 0.02 -Nodes (95): export.ai.generateButton, export.ai.generating, export.ai.synopsis, export.ai.synopsisPlaceholder, export.ai.synopsisTitle, export.ai.title, export.appearanceLabel, export.backstoryLabel (+87 more) - -### Community 249 - "Community 249" -Cohesion: 0.02 -Nodes (95): export.ai.generateButton, export.ai.generating, export.ai.synopsis, export.ai.synopsisPlaceholder, export.ai.synopsisTitle, export.ai.title, export.appearanceLabel, export.backstoryLabel (+87 more) - -### Community 250 - "Community 250" -Cohesion: 0.02 -Nodes (95): export.ai.generateButton, export.ai.generating, export.ai.synopsis, export.ai.synopsisPlaceholder, export.ai.synopsisTitle, export.ai.title, export.appearanceLabel, export.backstoryLabel (+87 more) - -### Community 251 - "Community 251" -Cohesion: 0.02 -Nodes (95): export.ai.generateButton, export.ai.generating, export.ai.synopsis, export.ai.synopsisPlaceholder, export.ai.synopsisTitle, export.ai.title, export.appearanceLabel, export.backstoryLabel (+87 more) - -### Community 252 - "Community 252" -Cohesion: 0.02 -Nodes (95): export.ai.generateButton, export.ai.generating, export.ai.synopsis, export.ai.synopsisPlaceholder, export.ai.synopsisTitle, export.ai.title, export.appearanceLabel, export.backstoryLabel (+87 more) - -### Community 253 - "Community 253" -Cohesion: 0.02 -Nodes (95): export.ai.generateButton, export.ai.generating, export.ai.synopsis, export.ai.synopsisPlaceholder, export.ai.synopsisTitle, export.ai.title, export.appearanceLabel, export.backstoryLabel (+87 more) - -### Community 254 - "Community 254" -Cohesion: 0.02 -Nodes (95): export.ai.generateButton, export.ai.generating, export.ai.synopsis, export.ai.synopsisPlaceholder, export.ai.synopsisTitle, export.ai.title, export.appearanceLabel, export.backstoryLabel (+87 more) - -### Community 255 - "Community 255" -Cohesion: 0.02 -Nodes (95): export.ai.generateButton, export.ai.generating, export.ai.synopsis, export.ai.synopsisPlaceholder, export.ai.synopsisTitle, export.ai.title, export.appearanceLabel, export.backstoryLabel (+87 more) - -### Community 256 - "Community 256" -Cohesion: 0.02 -Nodes (95): export.ai.generateButton, export.ai.generating, export.ai.synopsis, export.ai.synopsisPlaceholder, export.ai.synopsisTitle, export.ai.title, export.appearanceLabel, export.backstoryLabel (+87 more) - -### Community 257 - "Community 257" -Cohesion: 0.02 -Nodes (95): export.ai.generateButton, export.ai.generating, export.ai.synopsis, export.ai.synopsisPlaceholder, export.ai.synopsisTitle, export.ai.title, export.appearanceLabel, export.backstoryLabel (+87 more) - -### Community 258 - "Community 258" -Cohesion: 0.02 -Nodes (95): export.ai.generateButton, export.ai.generating, export.ai.synopsis, export.ai.synopsisPlaceholder, export.ai.synopsisTitle, export.ai.title, export.appearanceLabel, export.backstoryLabel (+87 more) - -### Community 259 - "Community 259" -Cohesion: 0.02 -Nodes (95): export.ai.generateButton, export.ai.generating, export.ai.synopsis, export.ai.synopsisPlaceholder, export.ai.synopsisTitle, export.ai.title, export.appearanceLabel, export.backstoryLabel (+87 more) - -### Community 260 - "Community 260" -Cohesion: 0.02 -Nodes (95): export.ai.generateButton, export.ai.generating, export.ai.synopsis, export.ai.synopsisPlaceholder, export.ai.synopsisTitle, export.ai.title, export.appearanceLabel, export.backstoryLabel (+87 more) - -### Community 261 - "Community 261" -Cohesion: 0.02 -Nodes (95): export.ai.generateButton, export.ai.generating, export.ai.synopsis, export.ai.synopsisPlaceholder, export.ai.synopsisTitle, export.ai.title, export.appearanceLabel, export.backstoryLabel (+87 more) - -### Community 262 - "Community 262" -Cohesion: 0.02 -Nodes (95): export.ai.generateButton, export.ai.generating, export.ai.synopsis, export.ai.synopsisPlaceholder, export.ai.synopsisTitle, export.ai.title, export.appearanceLabel, export.backstoryLabel (+87 more) - -### Community 263 - "Community 263" -Cohesion: 0.02 -Nodes (95): export.ai.generateButton, export.ai.generating, export.ai.synopsis, export.ai.synopsisPlaceholder, export.ai.synopsisTitle, export.ai.title, export.appearanceLabel, export.backstoryLabel (+87 more) - -### Community 264 - "Community 264" -Cohesion: 0.02 -Nodes (95): export.ai.generateButton, export.ai.generating, export.ai.synopsis, export.ai.synopsisPlaceholder, export.ai.synopsisTitle, export.ai.title, export.appearanceLabel, export.backstoryLabel (+87 more) - -### Community 265 - "Community 265" -Cohesion: 0.02 -Nodes (85): de, help.aiStudio.critic.content, help.aiStudio.critic.title, help.aiStudio.localAi.content, help.aiStudio.localAi.title, help.aiStudio.plotAi.content, help.aiStudio.plotAi.title, help.aiStudio.providers.content (+77 more) - -### Community 266 - "Community 266" -Cohesion: 0.02 -Nodes (85): es, help.aiStudio.critic.content, help.aiStudio.critic.title, help.aiStudio.localAi.content, help.aiStudio.localAi.title, help.aiStudio.plotAi.content, help.aiStudio.plotAi.title, help.aiStudio.providers.content (+77 more) - -### Community 267 - "Community 267" -Cohesion: 0.02 -Nodes (85): en, help.aiStudio.critic.content, help.aiStudio.critic.title, help.aiStudio.localAi.content, help.aiStudio.localAi.title, help.aiStudio.plotAi.content, help.aiStudio.plotAi.title, help.aiStudio.providers.content (+77 more) - -### Community 268 - "Community 268" -Cohesion: 0.02 -Nodes (85): fr, help.aiStudio.critic.content, help.aiStudio.critic.title, help.aiStudio.localAi.content, help.aiStudio.localAi.title, help.aiStudio.plotAi.content, help.aiStudio.plotAi.title, help.aiStudio.providers.content (+77 more) - -### Community 269 - "Community 269" -Cohesion: 0.02 -Nodes (85): it, help.aiStudio.critic.content, help.aiStudio.critic.title, help.aiStudio.localAi.content, help.aiStudio.localAi.title, help.aiStudio.plotAi.content, help.aiStudio.plotAi.title, help.aiStudio.providers.content (+77 more) - -### Community 270 - "Community 270" -Cohesion: 0.04 -Nodes (51): start(), initWorkerBusOnStartup(), DuckDbRequestType, DuckDbResponse, errorMessage(), generateMessageId(), send(), TASK_TYPE (+43 more) - -### Community 271 - "Community 271" -Cohesion: 0.03 -Nodes (79): characterGraph.graphAriaLabel, characterGraph.legend, characterGraph.relationships, characterGraph.table.caption, characterGraph.table.empty, characterGraph.table.emptyHint, characterGraph.table.from, characterGraph.table.strength (+71 more) - -### Community 272 - "Community 272" -Cohesion: 0.03 -Nodes (79): characterGraph.graphAriaLabel, characterGraph.legend, characterGraph.relationships, characterGraph.table.caption, characterGraph.table.empty, characterGraph.table.emptyHint, characterGraph.table.from, characterGraph.table.strength (+71 more) - -### Community 273 - "Community 273" -Cohesion: 0.15 -Nodes (10): Horizontal, meta, OPTIONS, Story, Vertical, WithDisabledOption, RadioGroup, RadioGroupProps (+2 more) - -### Community 274 - "Community 274" -Cohesion: 0.03 -Nodes (79): characterGraph.graphAriaLabel, characterGraph.legend, characterGraph.relationships, characterGraph.table.caption, characterGraph.table.empty, characterGraph.table.emptyHint, characterGraph.table.from, characterGraph.table.strength (+71 more) - -### Community 275 - "Community 275" -Cohesion: 0.03 -Nodes (79): characterGraph.graphAriaLabel, characterGraph.legend, characterGraph.relationships, characterGraph.table.caption, characterGraph.table.empty, characterGraph.table.emptyHint, characterGraph.table.from, characterGraph.table.strength (+71 more) - -### Community 276 - "Community 276" -Cohesion: 0.03 -Nodes (79): characterGraph.graphAriaLabel, characterGraph.legend, characterGraph.relationships, characterGraph.table.caption, characterGraph.table.empty, characterGraph.table.emptyHint, characterGraph.table.from, characterGraph.table.strength (+71 more) - -### Community 278 - "Community 278" -Cohesion: 0.03 -Nodes (79): characterGraph.graphAriaLabel, characterGraph.legend, characterGraph.relationships, characterGraph.table.caption, characterGraph.table.empty, characterGraph.table.emptyHint, characterGraph.table.from, characterGraph.table.strength (+71 more) - -### Community 280 - "Community 280" -Cohesion: 0.25 -Nodes (6): stripExifFromImage(), mockBitmap, mockCanvas, mockDrawImage, mockGetContext, mockToBlob - -### Community 281 - "Community 281" -Cohesion: 0.03 -Nodes (79): characterGraph.graphAriaLabel, characterGraph.legend, characterGraph.relationships, characterGraph.table.caption, characterGraph.table.empty, characterGraph.table.emptyHint, characterGraph.table.from, characterGraph.table.strength (+71 more) - -### Community 282 - "Community 282" -Cohesion: 0.03 -Nodes (79): characterGraph.graphAriaLabel, characterGraph.legend, characterGraph.relationships, characterGraph.table.caption, characterGraph.table.empty, characterGraph.table.emptyHint, characterGraph.table.from, characterGraph.table.strength (+71 more) - -### Community 283 - "Community 283" -Cohesion: 0.03 -Nodes (79): characterGraph.graphAriaLabel, characterGraph.legend, characterGraph.relationships, characterGraph.table.caption, characterGraph.table.empty, characterGraph.table.emptyHint, characterGraph.table.from, characterGraph.table.strength (+71 more) - -### Community 284 - "Community 284" -Cohesion: 0.03 -Nodes (79): characterGraph.graphAriaLabel, characterGraph.legend, characterGraph.relationships, characterGraph.table.caption, characterGraph.table.empty, characterGraph.table.emptyHint, characterGraph.table.from, characterGraph.table.strength (+71 more) - -### Community 285 - "Community 285" -Cohesion: 0.06 -Nodes (9): IdbAssetStore, mockIdbStore, MockReq, retryDb(), IdbKeyStore, IdbProjectStore, IdbSnapshotStore, mockStore (+1 more) - -### Community 286 - "Community 286" -Cohesion: 0.03 -Nodes (79): characterGraph.graphAriaLabel, characterGraph.legend, characterGraph.relationships, characterGraph.table.caption, characterGraph.table.empty, characterGraph.table.emptyHint, characterGraph.table.from, characterGraph.table.strength (+71 more) - -### Community 288 - "Community 288" -Cohesion: 0.50 -Nodes (3): chromiumVoiceArgs, desktopChrome, mobileChrome - -### Community 290 - "Community 290" -Cohesion: 0.33 -Nodes (5): next, pkg, root, sw, swPath - -### Community 291 - "Community 291" -Cohesion: 0.33 -Nodes (5): args, __dirname, dist, result, root - -### Community 293 - "Community 293" -Cohesion: 0.33 -Nodes (5): argv, assetsDir, __dirname, files, root - -### Community 294 - "Community 294" -Cohesion: 0.33 -Nodes (5): cli, EPHEMERAL, outDir, result, root - -### Community 295 - "Community 295" -Cohesion: 0.29 -Nodes (6): assetsDir, __dirname, entry, files, report, totalBytes - -### Community 296 - "Community 296" -Cohesion: 0.18 -Nodes (10): cargo, cargoNew, cargoPath, __dirname, pkg, pkgPath, root, tauriConf (+2 more) - -### Community 300 - "Community 300" -Cohesion: 0.03 -Nodes (79): characterGraph.graphAriaLabel, characterGraph.legend, characterGraph.relationships, characterGraph.table.caption, characterGraph.table.empty, characterGraph.table.emptyHint, characterGraph.table.from, characterGraph.table.strength (+71 more) - -### Community 301 - "Community 301" -Cohesion: 0.03 -Nodes (79): characterGraph.graphAriaLabel, characterGraph.legend, characterGraph.relationships, characterGraph.table.caption, characterGraph.table.empty, characterGraph.table.emptyHint, characterGraph.table.from, characterGraph.table.strength (+71 more) - -### Community 302 - "Community 302" -Cohesion: 0.03 -Nodes (79): characterGraph.graphAriaLabel, characterGraph.legend, characterGraph.relationships, characterGraph.table.caption, characterGraph.table.empty, characterGraph.table.emptyHint, characterGraph.table.from, characterGraph.table.strength (+71 more) - -### Community 303 - "Community 303" -Cohesion: 0.03 -Nodes (79): characterGraph.graphAriaLabel, characterGraph.legend, characterGraph.relationships, characterGraph.table.caption, characterGraph.table.empty, characterGraph.table.emptyHint, characterGraph.table.from, characterGraph.table.strength (+71 more) - -### Community 304 - "Community 304" -Cohesion: 0.03 -Nodes (79): characterGraph.graphAriaLabel, characterGraph.legend, characterGraph.relationships, characterGraph.table.caption, characterGraph.table.empty, characterGraph.table.emptyHint, characterGraph.table.from, characterGraph.table.strength (+71 more) - -### Community 305 - "Community 305" -Cohesion: 0.12 -Nodes (20): initialState, loraSlice, StateWithLora, initial, mockAdapter, StepIndicator(), STEPS, DatasetSource (+12 more) - -### Community 306 - "Community 306" -Cohesion: 0.03 -Nodes (79): characterGraph.graphAriaLabel, characterGraph.legend, characterGraph.relationships, characterGraph.table.caption, characterGraph.table.empty, characterGraph.table.emptyHint, characterGraph.table.from, characterGraph.table.strength (+71 more) - -### Community 307 - "Community 307" -Cohesion: 0.03 -Nodes (79): characterGraph.graphAriaLabel, characterGraph.legend, characterGraph.relationships, characterGraph.table.caption, characterGraph.table.empty, characterGraph.table.emptyHint, characterGraph.table.from, characterGraph.table.strength (+71 more) - -### Community 308 - "Community 308" -Cohesion: 0.03 -Nodes (79): characterGraph.graphAriaLabel, characterGraph.legend, characterGraph.relationships, characterGraph.table.caption, characterGraph.table.empty, characterGraph.table.emptyHint, characterGraph.table.from, characterGraph.table.strength (+71 more) - -### Community 309 - "Community 309" -Cohesion: 0.03 -Nodes (76): lora.adapter.activate, lora.adapter.active, lora.adapter.deactivate, lora.adapter.delete, lora.adapter.export, lora.adapter.merge, lora.adapter.version, lora.dataset.accepted (+68 more) - -### Community 310 - "Community 310" -Cohesion: 0.03 -Nodes (76): lora.adapter.activate, lora.adapter.active, lora.adapter.deactivate, lora.adapter.delete, lora.adapter.export, lora.adapter.merge, lora.adapter.version, lora.dataset.accepted (+68 more) - -### Community 311 - "Community 311" -Cohesion: 0.03 -Nodes (76): lora.adapter.activate, lora.adapter.active, lora.adapter.deactivate, lora.adapter.delete, lora.adapter.export, lora.adapter.merge, lora.adapter.version, lora.dataset.accepted (+68 more) - -### Community 312 - "Community 312" -Cohesion: 0.03 -Nodes (76): lora.adapter.activate, lora.adapter.active, lora.adapter.deactivate, lora.adapter.delete, lora.adapter.export, lora.adapter.merge, lora.adapter.version, lora.dataset.accepted (+68 more) - -### Community 313 - "Community 313" -Cohesion: 0.03 -Nodes (76): lora.adapter.activate, lora.adapter.active, lora.adapter.deactivate, lora.adapter.delete, lora.adapter.export, lora.adapter.merge, lora.adapter.version, lora.dataset.accepted (+68 more) - -### Community 314 - "Community 314" -Cohesion: 0.03 -Nodes (76): lora.adapter.activate, lora.adapter.active, lora.adapter.deactivate, lora.adapter.delete, lora.adapter.export, lora.adapter.merge, lora.adapter.version, lora.dataset.accepted (+68 more) - -### Community 315 - "Community 315" -Cohesion: 0.03 -Nodes (76): lora.adapter.activate, lora.adapter.active, lora.adapter.deactivate, lora.adapter.delete, lora.adapter.export, lora.adapter.merge, lora.adapter.version, lora.dataset.accepted (+68 more) - -### Community 316 - "Community 316" -Cohesion: 0.03 -Nodes (76): lora.adapter.activate, lora.adapter.active, lora.adapter.deactivate, lora.adapter.delete, lora.adapter.export, lora.adapter.merge, lora.adapter.version, lora.dataset.accepted (+68 more) - -### Community 317 - "Community 317" -Cohesion: 0.03 -Nodes (76): lora.adapter.activate, lora.adapter.active, lora.adapter.deactivate, lora.adapter.delete, lora.adapter.export, lora.adapter.merge, lora.adapter.version, lora.dataset.accepted (+68 more) - -### Community 318 - "Community 318" -Cohesion: 0.03 -Nodes (76): lora.adapter.activate, lora.adapter.active, lora.adapter.deactivate, lora.adapter.delete, lora.adapter.export, lora.adapter.merge, lora.adapter.version, lora.dataset.accepted (+68 more) - -### Community 319 - "Community 319" -Cohesion: 0.03 -Nodes (76): lora.adapter.activate, lora.adapter.active, lora.adapter.deactivate, lora.adapter.delete, lora.adapter.export, lora.adapter.merge, lora.adapter.version, lora.dataset.accepted (+68 more) - -### Community 320 - "Community 320" -Cohesion: 0.03 -Nodes (76): lora.adapter.activate, lora.adapter.active, lora.adapter.deactivate, lora.adapter.delete, lora.adapter.export, lora.adapter.merge, lora.adapter.version, lora.dataset.accepted (+68 more) - -### Community 321 - "Community 321" -Cohesion: 0.03 -Nodes (76): lora.adapter.activate, lora.adapter.active, lora.adapter.deactivate, lora.adapter.delete, lora.adapter.export, lora.adapter.merge, lora.adapter.version, lora.dataset.accepted (+68 more) - -### Community 322 - "Community 322" -Cohesion: 0.03 -Nodes (76): lora.adapter.activate, lora.adapter.active, lora.adapter.deactivate, lora.adapter.delete, lora.adapter.export, lora.adapter.merge, lora.adapter.version, lora.dataset.accepted (+68 more) - -### Community 323 - "Community 323" -Cohesion: 0.03 -Nodes (76): lora.adapter.activate, lora.adapter.active, lora.adapter.deactivate, lora.adapter.delete, lora.adapter.export, lora.adapter.merge, lora.adapter.version, lora.dataset.accepted (+68 more) - -### Community 324 - "Community 324" -Cohesion: 0.03 -Nodes (76): lora.adapter.activate, lora.adapter.active, lora.adapter.deactivate, lora.adapter.delete, lora.adapter.export, lora.adapter.merge, lora.adapter.version, lora.dataset.accepted (+68 more) - -### Community 325 - "Community 325" -Cohesion: 0.03 -Nodes (76): lora.adapter.activate, lora.adapter.active, lora.adapter.deactivate, lora.adapter.delete, lora.adapter.export, lora.adapter.merge, lora.adapter.version, lora.dataset.accepted (+68 more) - -### Community 326 - "Community 326" -Cohesion: 0.03 -Nodes (76): lora.adapter.activate, lora.adapter.active, lora.adapter.deactivate, lora.adapter.delete, lora.adapter.export, lora.adapter.merge, lora.adapter.version, lora.dataset.accepted (+68 more) - -### Community 327 - "Community 327" -Cohesion: 0.03 -Nodes (76): lora.adapter.activate, lora.adapter.active, lora.adapter.deactivate, lora.adapter.delete, lora.adapter.export, lora.adapter.merge, lora.adapter.version, lora.dataset.accepted (+68 more) - -### Community 328 - "Community 328" -Cohesion: 0.03 -Nodes (77): scripts, analyze, bench, build, build:edge, build:pages, build-storybook, build:turbo (+69 more) - -### Community 329 - "Community 329" -Cohesion: 0.20 -Nodes (9): mockApplyProofreadSuggestion, mockDispatch, mockHandleGenerateLoglines, mockHandleProofread, mockHandleVisualizeScene, mockLoglineSuggestions, mockProofreadSuggestions, mockSelectLogline (+1 more) - -### Community 331 - "Community 331" -Cohesion: 0.03 -Nodes (69): de, dashboard.backup.exportJson, dashboard.backup.hint, dashboard.backup.importJson, dashboard.backup.latestSnapshot, dashboard.backup.openSettings, dashboard.backup.title, dashboard.backup.unnamedSnapshot (+61 more) - -### Community 332 - "Community 332" -Cohesion: 0.03 -Nodes (69): en, dashboard.backup.exportJson, dashboard.backup.hint, dashboard.backup.importJson, dashboard.backup.latestSnapshot, dashboard.backup.openSettings, dashboard.backup.title, dashboard.backup.unnamedSnapshot (+61 more) - -### Community 333 - "Community 333" -Cohesion: 0.03 -Nodes (67): manuscript.addSection, manuscript.binder.addFolder, manuscript.binder.addLink, manuscript.binder.addNote, manuscript.binder.assetsLocalHint, manuscript.binder.deleteFolder, manuscript.binder.deleteNode, manuscript.binder.empty (+59 more) - -### Community 334 - "Community 334" -Cohesion: 0.10 -Nodes (15): buildNormManuscriptExport(), paginateNormLines(), stripLightMarkdown(), wrapParagraphToLines(), wrapPlainTextToNormLines(), buildNormManuscriptExport(), paginateNormLines(), stripLightMarkdown() (+7 more) - -### Community 335 - "Community 335" -Cohesion: 0.03 -Nodes (67): manuscript.addSection, manuscript.binder.addFolder, manuscript.binder.addLink, manuscript.binder.addNote, manuscript.binder.assetsLocalHint, manuscript.binder.deleteFolder, manuscript.binder.deleteNode, manuscript.binder.empty (+59 more) - -### Community 336 - "Community 336" -Cohesion: 0.03 -Nodes (67): manuscript.addSection, manuscript.binder.addFolder, manuscript.binder.addLink, manuscript.binder.addNote, manuscript.binder.assetsLocalHint, manuscript.binder.deleteFolder, manuscript.binder.deleteNode, manuscript.binder.empty (+59 more) - -### Community 337 - "Community 337" -Cohesion: 0.03 -Nodes (67): manuscript.addSection, manuscript.binder.addFolder, manuscript.binder.addLink, manuscript.binder.addNote, manuscript.binder.assetsLocalHint, manuscript.binder.deleteFolder, manuscript.binder.deleteNode, manuscript.binder.empty (+59 more) - -### Community 338 - "Community 338" -Cohesion: 0.03 -Nodes (67): manuscript.addSection, manuscript.binder.addFolder, manuscript.binder.addLink, manuscript.binder.addNote, manuscript.binder.assetsLocalHint, manuscript.binder.deleteFolder, manuscript.binder.deleteNode, manuscript.binder.empty (+59 more) - -### Community 339 - "Community 339" -Cohesion: 0.03 -Nodes (67): manuscript.addSection, manuscript.binder.addFolder, manuscript.binder.addLink, manuscript.binder.addNote, manuscript.binder.assetsLocalHint, manuscript.binder.deleteFolder, manuscript.binder.deleteNode, manuscript.binder.empty (+59 more) - -### Community 340 - "Community 340" -Cohesion: 0.03 -Nodes (67): manuscript.addSection, manuscript.binder.addFolder, manuscript.binder.addLink, manuscript.binder.addNote, manuscript.binder.assetsLocalHint, manuscript.binder.deleteFolder, manuscript.binder.deleteNode, manuscript.binder.empty (+59 more) - -### Community 342 - "Community 342" -Cohesion: 0.03 -Nodes (67): manuscript.addSection, manuscript.binder.addFolder, manuscript.binder.addLink, manuscript.binder.addNote, manuscript.binder.assetsLocalHint, manuscript.binder.deleteFolder, manuscript.binder.deleteNode, manuscript.binder.empty (+59 more) - -### Community 343 - "Community 343" -Cohesion: 0.03 -Nodes (67): manuscript.addSection, manuscript.binder.addFolder, manuscript.binder.addLink, manuscript.binder.addNote, manuscript.binder.assetsLocalHint, manuscript.binder.deleteFolder, manuscript.binder.deleteNode, manuscript.binder.empty (+59 more) - -### Community 344 - "Community 344" -Cohesion: 0.03 -Nodes (67): manuscript.addSection, manuscript.binder.addFolder, manuscript.binder.addLink, manuscript.binder.addNote, manuscript.binder.assetsLocalHint, manuscript.binder.deleteFolder, manuscript.binder.deleteNode, manuscript.binder.empty (+59 more) - -### Community 345 - "Community 345" -Cohesion: 0.03 -Nodes (67): manuscript.addSection, manuscript.binder.addFolder, manuscript.binder.addLink, manuscript.binder.addNote, manuscript.binder.assetsLocalHint, manuscript.binder.deleteFolder, manuscript.binder.deleteNode, manuscript.binder.empty (+59 more) - -### Community 346 - "Community 346" -Cohesion: 0.04 -Nodes (65): AgentConstructor, EXECUTABLE_STAGES, loadAgent(), BaseAgent, CopyEditAgent, DiagnosticAgent, ProofAgent, FILTER_WORDS (+57 more) - -### Community 347 - "Community 347" -Cohesion: 0.22 -Nodes (6): FAKE_CLIENT, FAKE_KEY, mockDelete, mockGet, mockList, mockPut - -### Community 348 - "Community 348" -Cohesion: 0.03 -Nodes (67): manuscript.addSection, manuscript.binder.addFolder, manuscript.binder.addLink, manuscript.binder.addNote, manuscript.binder.assetsLocalHint, manuscript.binder.deleteFolder, manuscript.binder.deleteNode, manuscript.binder.empty (+59 more) - -### Community 349 - "Community 349" -Cohesion: 0.03 -Nodes (67): manuscript.addSection, manuscript.binder.addFolder, manuscript.binder.addLink, manuscript.binder.addNote, manuscript.binder.assetsLocalHint, manuscript.binder.deleteFolder, manuscript.binder.deleteNode, manuscript.binder.empty (+59 more) - -### Community 350 - "Community 350" -Cohesion: 0.26 -Nodes (10): applyFormula(), computeReadabilitySnapshot(), estimateSyllables(), getSyllablePattern(), applyFormula(), computeReadabilitySnapshot(), estimateSyllables(), getSyllablePattern() (+2 more) - -### Community 351 - "Community 351" -Cohesion: 0.03 -Nodes (67): manuscript.addSection, manuscript.binder.addFolder, manuscript.binder.addLink, manuscript.binder.addNote, manuscript.binder.assetsLocalHint, manuscript.binder.deleteFolder, manuscript.binder.deleteNode, manuscript.binder.empty (+59 more) - -### Community 352 - "Community 352" -Cohesion: 0.03 -Nodes (67): manuscript.addSection, manuscript.binder.addFolder, manuscript.binder.addLink, manuscript.binder.addNote, manuscript.binder.assetsLocalHint, manuscript.binder.deleteFolder, manuscript.binder.deleteNode, manuscript.binder.empty (+59 more) - -### Community 353 - "Community 353" -Cohesion: 0.03 -Nodes (67): manuscript.addSection, manuscript.binder.addFolder, manuscript.binder.addLink, manuscript.binder.addNote, manuscript.binder.assetsLocalHint, manuscript.binder.deleteFolder, manuscript.binder.deleteNode, manuscript.binder.empty (+59 more) - -### Community 354 - "Community 354" -Cohesion: 0.03 -Nodes (67): manuscript.addSection, manuscript.binder.addFolder, manuscript.binder.addLink, manuscript.binder.addNote, manuscript.binder.assetsLocalHint, manuscript.binder.deleteFolder, manuscript.binder.deleteNode, manuscript.binder.empty (+59 more) - -### Community 356 - "Community 356" -Cohesion: 0.15 -Nodes (3): AudioNavigator, AudioLandmark, AudioNavigator - -### Community 357 - "Community 357" -Cohesion: 0.03 -Nodes (67): manuscript.addSection, manuscript.binder.addFolder, manuscript.binder.addLink, manuscript.binder.addNote, manuscript.binder.assetsLocalHint, manuscript.binder.deleteFolder, manuscript.binder.deleteNode, manuscript.binder.empty (+59 more) - -### Community 358 - "Community 358" -Cohesion: 0.03 -Nodes (67): manuscript.addSection, manuscript.binder.addFolder, manuscript.binder.addLink, manuscript.binder.addNote, manuscript.binder.assetsLocalHint, manuscript.binder.deleteFolder, manuscript.binder.deleteNode, manuscript.binder.empty (+59 more) - -### Community 359 - "Community 359" -Cohesion: 0.03 -Nodes (65): copilot.annotationCount, copilot.announceClosed, copilot.announceOpened, copilot.apply, copilot.applyingChange, copilot.askAboutReviewItem, copilot.askCopilot, copilot.assistant (+57 more) - -### Community 360 - "Community 360" -Cohesion: 0.03 -Nodes (65): copilot.annotationCount, copilot.announceClosed, copilot.announceOpened, copilot.apply, copilot.applyingChange, copilot.askAboutReviewItem, copilot.askCopilot, copilot.assistant (+57 more) - -### Community 361 - "Community 361" -Cohesion: 0.03 -Nodes (65): copilot.annotationCount, copilot.announceClosed, copilot.announceOpened, copilot.apply, copilot.applyingChange, copilot.askAboutReviewItem, copilot.askCopilot, copilot.assistant (+57 more) - -### Community 362 - "Community 362" -Cohesion: 0.03 -Nodes (65): copilot.annotationCount, copilot.announceClosed, copilot.announceOpened, copilot.apply, copilot.applyingChange, copilot.askAboutReviewItem, copilot.askCopilot, copilot.assistant (+57 more) - -### Community 363 - "Community 363" -Cohesion: 0.03 -Nodes (65): copilot.annotationCount, copilot.announceClosed, copilot.announceOpened, copilot.apply, copilot.applyingChange, copilot.askAboutReviewItem, copilot.askCopilot, copilot.assistant (+57 more) - -### Community 364 - "Community 364" -Cohesion: 0.03 -Nodes (65): copilot.annotationCount, copilot.announceClosed, copilot.announceOpened, copilot.apply, copilot.applyingChange, copilot.askAboutReviewItem, copilot.askCopilot, copilot.assistant (+57 more) - -### Community 365 - "Community 365" -Cohesion: 0.03 -Nodes (65): copilot.annotationCount, copilot.announceClosed, copilot.announceOpened, copilot.apply, copilot.applyingChange, copilot.askAboutReviewItem, copilot.askCopilot, copilot.assistant (+57 more) - -### Community 366 - "Community 366" -Cohesion: 0.03 -Nodes (65): copilot.annotationCount, copilot.announceClosed, copilot.announceOpened, copilot.apply, copilot.applyingChange, copilot.askAboutReviewItem, copilot.askCopilot, copilot.assistant (+57 more) - -### Community 367 - "Community 367" -Cohesion: 0.03 -Nodes (65): copilot.annotationCount, copilot.announceClosed, copilot.announceOpened, copilot.apply, copilot.applyingChange, copilot.askAboutReviewItem, copilot.askCopilot, copilot.assistant (+57 more) - -### Community 368 - "Community 368" -Cohesion: 0.03 -Nodes (65): copilot.annotationCount, copilot.announceClosed, copilot.announceOpened, copilot.apply, copilot.applyingChange, copilot.askAboutReviewItem, copilot.askCopilot, copilot.assistant (+57 more) - -### Community 369 - "Community 369" -Cohesion: 0.03 -Nodes (65): copilot.annotationCount, copilot.announceClosed, copilot.announceOpened, copilot.apply, copilot.applyingChange, copilot.askAboutReviewItem, copilot.askCopilot, copilot.assistant (+57 more) - -### Community 370 - "Community 370" -Cohesion: 0.03 -Nodes (65): copilot.annotationCount, copilot.announceClosed, copilot.announceOpened, copilot.apply, copilot.applyingChange, copilot.askAboutReviewItem, copilot.askCopilot, copilot.assistant (+57 more) - -### Community 371 - "Community 371" -Cohesion: 0.03 -Nodes (65): copilot.annotationCount, copilot.announceClosed, copilot.announceOpened, copilot.apply, copilot.applyingChange, copilot.askAboutReviewItem, copilot.askCopilot, copilot.assistant (+57 more) - -### Community 372 - "Community 372" -Cohesion: 0.03 -Nodes (65): copilot.annotationCount, copilot.announceClosed, copilot.announceOpened, copilot.apply, copilot.applyingChange, copilot.askAboutReviewItem, copilot.askCopilot, copilot.assistant (+57 more) - -### Community 373 - "Community 373" -Cohesion: 0.03 -Nodes (65): copilot.annotationCount, copilot.announceClosed, copilot.announceOpened, copilot.apply, copilot.applyingChange, copilot.askAboutReviewItem, copilot.askCopilot, copilot.assistant (+57 more) - -### Community 374 - "Community 374" -Cohesion: 0.03 -Nodes (65): copilot.annotationCount, copilot.announceClosed, copilot.announceOpened, copilot.apply, copilot.applyingChange, copilot.askAboutReviewItem, copilot.askCopilot, copilot.assistant (+57 more) - -### Community 375 - "Community 375" -Cohesion: 0.03 -Nodes (65): copilot.annotationCount, copilot.announceClosed, copilot.announceOpened, copilot.apply, copilot.applyingChange, copilot.askAboutReviewItem, copilot.askCopilot, copilot.assistant (+57 more) - -### Community 376 - "Community 376" -Cohesion: 0.03 -Nodes (65): copilot.annotationCount, copilot.announceClosed, copilot.announceOpened, copilot.apply, copilot.applyingChange, copilot.askAboutReviewItem, copilot.askCopilot, copilot.assistant (+57 more) - -### Community 377 - "Community 377" -Cohesion: 0.03 -Nodes (65): copilot.annotationCount, copilot.announceClosed, copilot.announceOpened, copilot.apply, copilot.applyingChange, copilot.askAboutReviewItem, copilot.askCopilot, copilot.assistant (+57 more) - -### Community 378 - "Community 378" -Cohesion: 0.03 -Nodes (43): descriptor, run(), createDeniedConstructor(), createSandboxedRunner(), installRuntimeGuards(), normalizePluginSource(), restoreConstructor(), restoreRuntimeGuards() (+35 more) - -### Community 379 - "Community 379" -Cohesion: 0.03 -Nodes (61): outline.advanced.chaptersLabel, outline.advanced.charactersLabel, outline.advanced.charactersPlaceholder, outline.advanced.pacingDefault, outline.advanced.pacingFast, outline.advanced.pacingLabel, outline.advanced.pacingMedium, outline.advanced.pacingSlow (+53 more) - -### Community 380 - "Community 380" -Cohesion: 0.22 -Nodes (8): OutlineGeneratorView(), baseContextValue, mockHandleGenerate, mockOnNavigate, mockRegenerateSection, mockSetGenre, mockSetIdea, mockSetShowAdvanced - -### Community 382 - "Community 382" -Cohesion: 0.11 -Nodes (22): duckdbClient, isMigrated(), MigratableProjectData, runIfNeeded(), runMigrationWithRollback(), isRagVectorMigrationDone(), runRagVectorMigration(), StoredRagRecord (+14 more) - -### Community 383 - "Community 383" -Cohesion: 0.03 -Nodes (61): outline.advanced.chaptersLabel, outline.advanced.charactersLabel, outline.advanced.charactersPlaceholder, outline.advanced.pacingDefault, outline.advanced.pacingFast, outline.advanced.pacingLabel, outline.advanced.pacingMedium, outline.advanced.pacingSlow (+53 more) - -### Community 384 - "Community 384" -Cohesion: 0.03 -Nodes (61): outline.advanced.chaptersLabel, outline.advanced.charactersLabel, outline.advanced.charactersPlaceholder, outline.advanced.pacingDefault, outline.advanced.pacingFast, outline.advanced.pacingLabel, outline.advanced.pacingMedium, outline.advanced.pacingSlow (+53 more) - -### Community 385 - "Community 385" -Cohesion: 0.33 -Nodes (12): defaultPrefs, isPinnedCommand(), loadPalettePreferences(), PalettePreferences, recordRecentCommand(), savePalettePreferences(), togglePinnedCommand(), isPinnedCommand() (+4 more) - -### Community 386 - "Community 386" -Cohesion: 0.03 -Nodes (61): outline.advanced.chaptersLabel, outline.advanced.charactersLabel, outline.advanced.charactersPlaceholder, outline.advanced.pacingDefault, outline.advanced.pacingFast, outline.advanced.pacingLabel, outline.advanced.pacingMedium, outline.advanced.pacingSlow (+53 more) - -### Community 387 - "Community 387" -Cohesion: 0.29 -Nodes (6): mockEnqueue, mockGetWorkerBus, mockHandle, mockInvalidateCache, mockInvokeRustTask, mockIsRustAvailable - -### Community 388 - "Community 388" -Cohesion: 0.05 -Nodes (66): attachCause(), cleanPrompt(), sanitizePromptBlock(), stripControlChars(), handleTestConnection(), analyzeAsCritic(), assertOnline(), checkConsistency() (+58 more) - -### Community 389 - "Community 389" -Cohesion: 0.03 -Nodes (61): outline.advanced.chaptersLabel, outline.advanced.charactersLabel, outline.advanced.charactersPlaceholder, outline.advanced.pacingDefault, outline.advanced.pacingFast, outline.advanced.pacingLabel, outline.advanced.pacingMedium, outline.advanced.pacingSlow (+53 more) - -### Community 390 - "Community 390" -Cohesion: 0.03 -Nodes (61): outline.advanced.chaptersLabel, outline.advanced.charactersLabel, outline.advanced.charactersPlaceholder, outline.advanced.pacingDefault, outline.advanced.pacingFast, outline.advanced.pacingLabel, outline.advanced.pacingMedium, outline.advanced.pacingSlow (+53 more) - -### Community 391 - "Community 391" -Cohesion: 0.03 -Nodes (61): outline.advanced.chaptersLabel, outline.advanced.charactersLabel, outline.advanced.charactersPlaceholder, outline.advanced.pacingDefault, outline.advanced.pacingFast, outline.advanced.pacingLabel, outline.advanced.pacingMedium, outline.advanced.pacingSlow (+53 more) - -### Community 392 - "Community 392" -Cohesion: 0.03 -Nodes (61): outline.advanced.chaptersLabel, outline.advanced.charactersLabel, outline.advanced.charactersPlaceholder, outline.advanced.pacingDefault, outline.advanced.pacingFast, outline.advanced.pacingLabel, outline.advanced.pacingMedium, outline.advanced.pacingSlow (+53 more) - -### Community 393 - "Community 393" -Cohesion: 0.03 -Nodes (61): outline.advanced.chaptersLabel, outline.advanced.charactersLabel, outline.advanced.charactersPlaceholder, outline.advanced.pacingDefault, outline.advanced.pacingFast, outline.advanced.pacingLabel, outline.advanced.pacingMedium, outline.advanced.pacingSlow (+53 more) - -### Community 394 - "Community 394" -Cohesion: 0.03 -Nodes (61): outline.advanced.chaptersLabel, outline.advanced.charactersLabel, outline.advanced.charactersPlaceholder, outline.advanced.pacingDefault, outline.advanced.pacingFast, outline.advanced.pacingLabel, outline.advanced.pacingMedium, outline.advanced.pacingSlow (+53 more) - -### Community 395 - "Community 395" -Cohesion: 0.03 -Nodes (61): outline.advanced.chaptersLabel, outline.advanced.charactersLabel, outline.advanced.charactersPlaceholder, outline.advanced.pacingDefault, outline.advanced.pacingFast, outline.advanced.pacingLabel, outline.advanced.pacingMedium, outline.advanced.pacingSlow (+53 more) - -### Community 396 - "Community 396" -Cohesion: 0.03 -Nodes (61): outline.advanced.chaptersLabel, outline.advanced.charactersLabel, outline.advanced.charactersPlaceholder, outline.advanced.pacingDefault, outline.advanced.pacingFast, outline.advanced.pacingLabel, outline.advanced.pacingMedium, outline.advanced.pacingSlow (+53 more) - -### Community 398 - "Community 398" -Cohesion: 0.03 -Nodes (61): outline.advanced.chaptersLabel, outline.advanced.charactersLabel, outline.advanced.charactersPlaceholder, outline.advanced.pacingDefault, outline.advanced.pacingFast, outline.advanced.pacingLabel, outline.advanced.pacingMedium, outline.advanced.pacingSlow (+53 more) - -### Community 399 - "Community 399" -Cohesion: 0.03 -Nodes (61): outline.advanced.chaptersLabel, outline.advanced.charactersLabel, outline.advanced.charactersPlaceholder, outline.advanced.pacingDefault, outline.advanced.pacingFast, outline.advanced.pacingLabel, outline.advanced.pacingMedium, outline.advanced.pacingSlow (+53 more) - -### Community 400 - "Community 400" -Cohesion: 0.03 -Nodes (61): outline.advanced.chaptersLabel, outline.advanced.charactersLabel, outline.advanced.charactersPlaceholder, outline.advanced.pacingDefault, outline.advanced.pacingFast, outline.advanced.pacingLabel, outline.advanced.pacingMedium, outline.advanced.pacingSlow (+53 more) - -### Community 401 - "Community 401" -Cohesion: 0.03 -Nodes (61): outline.advanced.chaptersLabel, outline.advanced.charactersLabel, outline.advanced.charactersPlaceholder, outline.advanced.pacingDefault, outline.advanced.pacingFast, outline.advanced.pacingLabel, outline.advanced.pacingMedium, outline.advanced.pacingSlow (+53 more) - -### Community 402 - "Community 402" -Cohesion: 0.03 -Nodes (61): outline.advanced.chaptersLabel, outline.advanced.charactersLabel, outline.advanced.charactersPlaceholder, outline.advanced.pacingDefault, outline.advanced.pacingFast, outline.advanced.pacingLabel, outline.advanced.pacingMedium, outline.advanced.pacingSlow (+53 more) - -### Community 403 - "Community 403" -Cohesion: 0.03 -Nodes (61): outline.advanced.chaptersLabel, outline.advanced.charactersLabel, outline.advanced.charactersPlaceholder, outline.advanced.pacingDefault, outline.advanced.pacingFast, outline.advanced.pacingLabel, outline.advanced.pacingMedium, outline.advanced.pacingSlow (+53 more) - -### Community 404 - "Community 404" -Cohesion: 0.03 -Nodes (61): outline.advanced.chaptersLabel, outline.advanced.charactersLabel, outline.advanced.charactersPlaceholder, outline.advanced.pacingDefault, outline.advanced.pacingFast, outline.advanced.pacingLabel, outline.advanced.pacingMedium, outline.advanced.pacingSlow (+53 more) - -### Community 405 - "Community 405" -Cohesion: 0.03 -Nodes (59): portal.back, portal.demo.chapterContent, portal.demo.chapterTitle, portal.demo.logline, portal.demo.outline1Desc, portal.demo.outline1Title, portal.demo.outline2Desc, portal.demo.outline2Title (+51 more) - -### Community 406 - "Community 406" -Cohesion: 0.03 -Nodes (59): portal.back, portal.demo.chapterContent, portal.demo.chapterTitle, portal.demo.logline, portal.demo.outline1Desc, portal.demo.outline1Title, portal.demo.outline2Desc, portal.demo.outline2Title (+51 more) - -### Community 408 - "Community 408" -Cohesion: 0.03 -Nodes (59): portal.back, portal.demo.chapterContent, portal.demo.chapterTitle, portal.demo.logline, portal.demo.outline1Desc, portal.demo.outline1Title, portal.demo.outline2Desc, portal.demo.outline2Title (+51 more) - -### Community 409 - "Community 409" -Cohesion: 0.03 -Nodes (59): portal.back, portal.demo.chapterContent, portal.demo.chapterTitle, portal.demo.logline, portal.demo.outline1Desc, portal.demo.outline1Title, portal.demo.outline2Desc, portal.demo.outline2Title (+51 more) - -### Community 411 - "Community 411" -Cohesion: 0.03 -Nodes (59): portal.back, portal.demo.chapterContent, portal.demo.chapterTitle, portal.demo.logline, portal.demo.outline1Desc, portal.demo.outline1Title, portal.demo.outline2Desc, portal.demo.outline2Title (+51 more) - -### Community 412 - "Community 412" -Cohesion: 0.03 -Nodes (59): portal.back, portal.demo.chapterContent, portal.demo.chapterTitle, portal.demo.logline, portal.demo.outline1Desc, portal.demo.outline1Title, portal.demo.outline2Desc, portal.demo.outline2Title (+51 more) - -### Community 413 - "Community 413" -Cohesion: 0.08 -Nodes (51): CharacterCoOccurrenceRow, CrossProjectSearchRow, DailyProgressRow, duckdbCodexWrite(), duckdbCrossProjectWrite(), duckdbDualWrite(), DuckdbRagChunkWrite, duckdbRagWrite() (+43 more) - -### Community 414 - "Community 414" -Cohesion: 0.03 -Nodes (59): portal.back, portal.demo.chapterContent, portal.demo.chapterTitle, portal.demo.logline, portal.demo.outline1Desc, portal.demo.outline1Title, portal.demo.outline2Desc, portal.demo.outline2Title (+51 more) - -### Community 415 - "Community 415" -Cohesion: 0.03 -Nodes (59): portal.back, portal.demo.chapterContent, portal.demo.chapterTitle, portal.demo.logline, portal.demo.outline1Desc, portal.demo.outline1Title, portal.demo.outline2Desc, portal.demo.outline2Title (+51 more) - -### Community 416 - "Community 416" -Cohesion: 0.03 -Nodes (59): portal.back, portal.demo.chapterContent, portal.demo.chapterTitle, portal.demo.logline, portal.demo.outline1Desc, portal.demo.outline1Title, portal.demo.outline2Desc, portal.demo.outline2Title (+51 more) - -### Community 417 - "Community 417" -Cohesion: 0.03 -Nodes (59): portal.back, portal.demo.chapterContent, portal.demo.chapterTitle, portal.demo.logline, portal.demo.outline1Desc, portal.demo.outline1Title, portal.demo.outline2Desc, portal.demo.outline2Title (+51 more) - -### Community 420 - "Community 420" -Cohesion: 0.03 -Nodes (59): portal.back, portal.demo.chapterContent, portal.demo.chapterTitle, portal.demo.logline, portal.demo.outline1Desc, portal.demo.outline1Title, portal.demo.outline2Desc, portal.demo.outline2Title (+51 more) - -### Community 421 - "Community 421" -Cohesion: 0.03 -Nodes (59): portal.back, portal.demo.chapterContent, portal.demo.chapterTitle, portal.demo.logline, portal.demo.outline1Desc, portal.demo.outline1Title, portal.demo.outline2Desc, portal.demo.outline2Title (+51 more) - -### Community 422 - "Community 422" -Cohesion: 0.03 -Nodes (59): portal.back, portal.demo.chapterContent, portal.demo.chapterTitle, portal.demo.logline, portal.demo.outline1Desc, portal.demo.outline1Title, portal.demo.outline2Desc, portal.demo.outline2Title (+51 more) - -### Community 423 - "Community 423" -Cohesion: 0.03 -Nodes (59): portal.back, portal.demo.chapterContent, portal.demo.chapterTitle, portal.demo.logline, portal.demo.outline1Desc, portal.demo.outline1Title, portal.demo.outline2Desc, portal.demo.outline2Title (+51 more) - -### Community 424 - "Community 424" -Cohesion: 0.03 -Nodes (59): portal.back, portal.demo.chapterContent, portal.demo.chapterTitle, portal.demo.logline, portal.demo.outline1Desc, portal.demo.outline1Title, portal.demo.outline2Desc, portal.demo.outline2Title (+51 more) - -### Community 425 - "Community 425" -Cohesion: 0.03 -Nodes (59): portal.back, portal.demo.chapterContent, portal.demo.chapterTitle, portal.demo.logline, portal.demo.outline1Desc, portal.demo.outline1Title, portal.demo.outline2Desc, portal.demo.outline2Title (+51 more) - -### Community 426 - "Community 426" -Cohesion: 0.03 -Nodes (59): portal.back, portal.demo.chapterContent, portal.demo.chapterTitle, portal.demo.logline, portal.demo.outline1Desc, portal.demo.outline1Title, portal.demo.outline2Desc, portal.demo.outline2Title (+51 more) - -### Community 427 - "Community 427" -Cohesion: 0.03 -Nodes (59): portal.back, portal.demo.chapterContent, portal.demo.chapterTitle, portal.demo.logline, portal.demo.outline1Desc, portal.demo.outline1Title, portal.demo.outline2Desc, portal.demo.outline2Title (+51 more) - -### Community 428 - "Community 428" -Cohesion: 0.04 -Nodes (66): CREATIVITY_TO_TEMPERATURE, isLocalInferenceProvider(), isOrchestrationReadyProvider(), LOCAL_BACKEND_PRESET_DEFAULT_URL, LocalInferenceProvider, getActiveAiMode(), assertCloudAiAllowed(), assertCloudAiAllowedSync() (+58 more) - -### Community 429 - "Community 429" -Cohesion: 0.03 -Nodes (59): portal.back, portal.demo.chapterContent, portal.demo.chapterTitle, portal.demo.logline, portal.demo.outline1Desc, portal.demo.outline1Title, portal.demo.outline2Desc, portal.demo.outline2Title (+51 more) - -### Community 430 - "Community 430" -Cohesion: 0.25 -Nodes (5): Default, Disabled, FastDebounce, meta, Story - -### Community 431 - "Community 431" -Cohesion: 0.03 -Nodes (57): worlds.addNewManually, worlds.addNewManuallyHint, worlds.addNewWithAI, worlds.addNewWithAIHint, worlds.aiModal.button, worlds.aiModal.description, worlds.aiModal.placeholder, worlds.aiModal.title (+49 more) - -### Community 432 - "Community 432" -Cohesion: 0.03 -Nodes (57): worlds.addNewManually, worlds.addNewManuallyHint, worlds.addNewWithAI, worlds.addNewWithAIHint, worlds.aiModal.button, worlds.aiModal.description, worlds.aiModal.placeholder, worlds.aiModal.title (+49 more) - -### Community 433 - "Community 433" -Cohesion: 0.03 -Nodes (57): worlds.addNewManually, worlds.addNewManuallyHint, worlds.addNewWithAI, worlds.addNewWithAIHint, worlds.aiModal.button, worlds.aiModal.description, worlds.aiModal.placeholder, worlds.aiModal.title (+49 more) - -### Community 434 - "Community 434" -Cohesion: 0.03 -Nodes (57): worlds.addNewManually, worlds.addNewManuallyHint, worlds.addNewWithAI, worlds.addNewWithAIHint, worlds.aiModal.button, worlds.aiModal.description, worlds.aiModal.placeholder, worlds.aiModal.title (+49 more) - -### Community 435 - "Community 435" -Cohesion: 0.03 -Nodes (57): worlds.addNewManually, worlds.addNewManuallyHint, worlds.addNewWithAI, worlds.addNewWithAIHint, worlds.aiModal.button, worlds.aiModal.description, worlds.aiModal.placeholder, worlds.aiModal.title (+49 more) - -### Community 437 - "Community 437" -Cohesion: 0.03 -Nodes (57): worlds.addNewManually, worlds.addNewManuallyHint, worlds.addNewWithAI, worlds.addNewWithAIHint, worlds.aiModal.button, worlds.aiModal.description, worlds.aiModal.placeholder, worlds.aiModal.title (+49 more) - -### Community 438 - "Community 438" -Cohesion: 0.03 -Nodes (57): worlds.addNewManually, worlds.addNewManuallyHint, worlds.addNewWithAI, worlds.addNewWithAIHint, worlds.aiModal.button, worlds.aiModal.description, worlds.aiModal.placeholder, worlds.aiModal.title (+49 more) - -### Community 439 - "Community 439" -Cohesion: 0.03 -Nodes (57): worlds.addNewManually, worlds.addNewManuallyHint, worlds.addNewWithAI, worlds.addNewWithAIHint, worlds.aiModal.button, worlds.aiModal.description, worlds.aiModal.placeholder, worlds.aiModal.title (+49 more) - -### Community 440 - "Community 440" -Cohesion: 0.25 -Nodes (7): Checked, Disabled, DisabledChecked, meta, NoLabel, Story, Unchecked - -### Community 441 - "Community 441" -Cohesion: 0.03 -Nodes (57): worlds.addNewManually, worlds.addNewManuallyHint, worlds.addNewWithAI, worlds.addNewWithAIHint, worlds.aiModal.button, worlds.aiModal.description, worlds.aiModal.placeholder, worlds.aiModal.title (+49 more) - -### Community 442 - "Community 442" -Cohesion: 0.03 -Nodes (57): worlds.addNewManually, worlds.addNewManuallyHint, worlds.addNewWithAI, worlds.addNewWithAIHint, worlds.aiModal.button, worlds.aiModal.description, worlds.aiModal.placeholder, worlds.aiModal.title (+49 more) - -### Community 444 - "Community 444" -Cohesion: 0.03 -Nodes (57): worlds.addNewManually, worlds.addNewManuallyHint, worlds.addNewWithAI, worlds.addNewWithAIHint, worlds.aiModal.button, worlds.aiModal.description, worlds.aiModal.placeholder, worlds.aiModal.title (+49 more) - -### Community 445 - "Community 445" -Cohesion: 0.03 -Nodes (57): worlds.addNewManually, worlds.addNewManuallyHint, worlds.addNewWithAI, worlds.addNewWithAIHint, worlds.aiModal.button, worlds.aiModal.description, worlds.aiModal.placeholder, worlds.aiModal.title (+49 more) - -### Community 446 - "Community 446" -Cohesion: 0.03 -Nodes (57): worlds.addNewManually, worlds.addNewManuallyHint, worlds.addNewWithAI, worlds.addNewWithAIHint, worlds.aiModal.button, worlds.aiModal.description, worlds.aiModal.placeholder, worlds.aiModal.title (+49 more) - -### Community 448 - "Community 448" -Cohesion: 0.03 -Nodes (57): worlds.addNewManually, worlds.addNewManuallyHint, worlds.addNewWithAI, worlds.addNewWithAIHint, worlds.aiModal.button, worlds.aiModal.description, worlds.aiModal.placeholder, worlds.aiModal.title (+49 more) - -### Community 449 - "Community 449" -Cohesion: 0.03 -Nodes (57): worlds.addNewManually, worlds.addNewManuallyHint, worlds.addNewWithAI, worlds.addNewWithAIHint, worlds.aiModal.button, worlds.aiModal.description, worlds.aiModal.placeholder, worlds.aiModal.title (+49 more) - -### Community 450 - "Community 450" -Cohesion: 0.03 -Nodes (57): worlds.addNewManually, worlds.addNewManuallyHint, worlds.addNewWithAI, worlds.addNewWithAIHint, worlds.aiModal.button, worlds.aiModal.description, worlds.aiModal.placeholder, worlds.aiModal.title (+49 more) - -### Community 452 - "Community 452" -Cohesion: 0.03 -Nodes (57): worlds.addNewManually, worlds.addNewManuallyHint, worlds.addNewWithAI, worlds.addNewWithAIHint, worlds.aiModal.button, worlds.aiModal.description, worlds.aiModal.placeholder, worlds.aiModal.title (+49 more) - -### Community 453 - "Community 453" -Cohesion: 0.03 -Nodes (57): worlds.addNewManually, worlds.addNewManuallyHint, worlds.addNewWithAI, worlds.addNewWithAIHint, worlds.aiModal.button, worlds.aiModal.description, worlds.aiModal.placeholder, worlds.aiModal.title (+49 more) - -### Community 454 - "Community 454" -Cohesion: 0.03 -Nodes (57): worlds.addNewManually, worlds.addNewManuallyHint, worlds.addNewWithAI, worlds.addNewWithAIHint, worlds.aiModal.button, worlds.aiModal.description, worlds.aiModal.placeholder, worlds.aiModal.title (+49 more) - -### Community 455 - "Community 455" -Cohesion: 0.25 -Nodes (7): meta, PrimaryActionOnly, Story, TitleOnly, WithActions, WithDescription, WithIcon - -### Community 456 - "Community 456" -Cohesion: 0.05 -Nodes (25): CATALOG_FILE, catalogSrc, dedicatedUiFlags, dedicatedUiOnly, defaultFlags, ghostFlags, GREP_EXCLUDE, handlerFlags (+17 more) - -### Community 457 - "Community 457" -Cohesion: 0.04 -Nodes (54): dependencies, ai, @ai-sdk/google, @ai-sdk/openai, @ai-sdk/react, diff-match-patch, @dnd-kit/core, @dnd-kit/sortable (+46 more) - -### Community 458 - "Community 458" -Cohesion: 0.06 -Nodes (41): directiveMap(), headersCsp(), nginxHeaderCsp(), vercelCsp(), directiveTokens(), tauriCsp(), escapeRegExp(), extractHeadersFileValue() (+33 more) - -### Community 459 - "Community 459" -Cohesion: 0.06 -Nodes (38): queryRagSimilarity(), chunkSection(), hashEmbedText(), rebuildLocalRagIndex(), searchLocalRag(), retrieveContext(), retrieveContextViaDuckDb(), makeRecord() (+30 more) - -### Community 460 - "Community 460" -Cohesion: 0.04 -Nodes (49): objects.addGroup, objects.addObject, objects.allGroups, objects.assignToGroup, objects.cancel, objects.deleteGroup, objects.deleteGroupConfirm, objects.deleteObject (+41 more) - -### Community 461 - "Community 461" -Cohesion: 0.04 -Nodes (49): C-1: collab-transport Crypto Security Review, Changes, Deep Correction Plan β€” 2026-06-06, Dependency Hardening Update (2026-04-16), DevEx Sprint: Dual-Graph Codebase Intelligence (2026-05-24), Executive Summary, Files Changed in This Audit, Findings & fixes (+41 more) - -### Community 462 - "Community 462" -Cohesion: 0.04 -Nodes (49): objects.addGroup, objects.addObject, objects.allGroups, objects.assignToGroup, objects.cancel, objects.deleteGroup, objects.deleteGroupConfirm, objects.deleteObject (+41 more) - -### Community 463 - "Community 463" -Cohesion: 0.06 -Nodes (30): BinderNodeParsed, binderNodeSchema, binderNodeTypeSchema, characterArchetypeSchema, characterInterviewSchema, characterRelationshipSchema, characterSchema, charactersFieldSchema (+22 more) - -### Community 464 - "Community 464" -Cohesion: 0.04 -Nodes (49): objects.addGroup, objects.addObject, objects.allGroups, objects.assignToGroup, objects.cancel, objects.deleteGroup, objects.deleteGroupConfirm, objects.deleteObject (+41 more) - -### Community 465 - "Community 465" -Cohesion: 0.04 -Nodes (49): objects.addGroup, objects.addObject, objects.allGroups, objects.assignToGroup, objects.cancel, objects.deleteGroup, objects.deleteGroupConfirm, objects.deleteObject (+41 more) - -### Community 466 - "Community 466" -Cohesion: 0.04 -Nodes (49): objects.addGroup, objects.addObject, objects.allGroups, objects.assignToGroup, objects.cancel, objects.deleteGroup, objects.deleteGroupConfirm, objects.deleteObject (+41 more) - -### Community 467 - "Community 467" -Cohesion: 0.04 -Nodes (49): objects.addGroup, objects.addObject, objects.allGroups, objects.assignToGroup, objects.cancel, objects.deleteGroup, objects.deleteGroupConfirm, objects.deleteObject (+41 more) - -### Community 468 - "Community 468" -Cohesion: 0.04 -Nodes (49): objects.addGroup, objects.addObject, objects.allGroups, objects.assignToGroup, objects.cancel, objects.deleteGroup, objects.deleteGroupConfirm, objects.deleteObject (+41 more) - -### Community 469 - "Community 469" -Cohesion: 0.04 -Nodes (49): objects.addGroup, objects.addObject, objects.allGroups, objects.assignToGroup, objects.cancel, objects.deleteGroup, objects.deleteGroupConfirm, objects.deleteObject (+41 more) - -### Community 470 - "Community 470" -Cohesion: 0.04 -Nodes (49): objects.addGroup, objects.addObject, objects.allGroups, objects.assignToGroup, objects.cancel, objects.deleteGroup, objects.deleteGroupConfirm, objects.deleteObject (+41 more) - -### Community 472 - "Community 472" -Cohesion: 0.04 -Nodes (49): objects.addGroup, objects.addObject, objects.allGroups, objects.assignToGroup, objects.cancel, objects.deleteGroup, objects.deleteGroupConfirm, objects.deleteObject (+41 more) - -### Community 473 - "Community 473" -Cohesion: 0.07 -Nodes (13): baseTracker, mockDispatch, mockTracker, mockWritingHistory, computeStreak(), defaultState, progressTrackerPersistenceMiddleware(), progressTrackerSlice (+5 more) - -### Community 474 - "Community 474" -Cohesion: 0.04 -Nodes (49): objects.addGroup, objects.addObject, objects.allGroups, objects.assignToGroup, objects.cancel, objects.deleteGroup, objects.deleteGroupConfirm, objects.deleteObject (+41 more) - -### Community 475 - "Community 475" -Cohesion: 0.04 -Nodes (49): objects.addGroup, objects.addObject, objects.allGroups, objects.assignToGroup, objects.cancel, objects.deleteGroup, objects.deleteGroupConfirm, objects.deleteObject (+41 more) - -### Community 476 - "Community 476" -Cohesion: 0.04 -Nodes (49): objects.addGroup, objects.addObject, objects.allGroups, objects.assignToGroup, objects.cancel, objects.deleteGroup, objects.deleteGroupConfirm, objects.deleteObject (+41 more) - -### Community 477 - "Community 477" -Cohesion: 0.04 -Nodes (49): objects.addGroup, objects.addObject, objects.allGroups, objects.assignToGroup, objects.cancel, objects.deleteGroup, objects.deleteGroupConfirm, objects.deleteObject (+41 more) - -### Community 478 - "Community 478" -Cohesion: 0.04 -Nodes (49): objects.addGroup, objects.addObject, objects.allGroups, objects.assignToGroup, objects.cancel, objects.deleteGroup, objects.deleteGroupConfirm, objects.deleteObject (+41 more) - -### Community 479 - "Community 479" -Cohesion: 0.04 -Nodes (49): objects.addGroup, objects.addObject, objects.allGroups, objects.assignToGroup, objects.cancel, objects.deleteGroup, objects.deleteGroupConfirm, objects.deleteObject (+41 more) - -### Community 480 - "Community 480" -Cohesion: 0.04 -Nodes (49): objects.addGroup, objects.addObject, objects.allGroups, objects.assignToGroup, objects.cancel, objects.deleteGroup, objects.deleteGroupConfirm, objects.deleteObject (+41 more) - -### Community 481 - "Community 481" -Cohesion: 0.04 -Nodes (49): objects.addGroup, objects.addObject, objects.allGroups, objects.assignToGroup, objects.cancel, objects.deleteGroup, objects.deleteGroupConfirm, objects.deleteObject (+41 more) - -### Community 482 - "Community 482" -Cohesion: 0.11 -Nodes (20): clearLocalModels(), ClearLocalModelsResult, estimateLocalModelStorage(), hasCacheApi(), hasStorageEstimate(), listModelCacheNames(), LOCAL_MODEL_CACHE_PATTERNS, LocalModelStorageEstimate (+12 more) - -### Community 483 - "Community 483" -Cohesion: 0.04 -Nodes (49): objects.addGroup, objects.addObject, objects.allGroups, objects.assignToGroup, objects.cancel, objects.deleteGroup, objects.deleteGroupConfirm, objects.deleteObject (+41 more) - -### Community 485 - "Community 485" -Cohesion: 0.04 -Nodes (46): mindmap.addEdge, mindmap.addMap, mindmap.addNode, mindmap.cancel, mindmap.deleteEdge, mindmap.deleteMap, mindmap.deleteMapConfirm, mindmap.deleteNode (+38 more) - -### Community 486 - "Community 486" -Cohesion: 0.07 -Nodes (14): CollabEncryptionRequiredError, MockDoc, MockWebrtcProvider, AwarenessState, CollabEncryptionRequiredError, CollaborationService, DEFAULT_WEBRTC_SIGNALING_URLS, resolveWebRtcSignalingUrls() (+6 more) - -### Community 487 - "Community 487" -Cohesion: 0.04 -Nodes (46): 1. Add the Tool Type, 1. Create the Service, 2. Add the Prompt, 2. Register in aiProviderService, 3. Add i18n Keys, 3. Add Settings, 4. Add Tests, 4. Wire Up the UI (+38 more) - -### Community 488 - "Community 488" -Cohesion: 0.05 -Nodes (41): renderCompareLineWordCells(), SnapshotCard(), DiffView(), partialStorySectionFromSnapshot(), deleteRevision(), getDb(), listRevisions(), saveRevision() (+33 more) - -### Community 489 - "Community 489" -Cohesion: 0.04 -Nodes (46): mindmap.addEdge, mindmap.addMap, mindmap.addNode, mindmap.cancel, mindmap.deleteEdge, mindmap.deleteMap, mindmap.deleteMapConfirm, mindmap.deleteNode (+38 more) - -### Community 490 - "Community 490" -Cohesion: 0.04 -Nodes (46): mindmap.addEdge, mindmap.addMap, mindmap.addNode, mindmap.cancel, mindmap.deleteEdge, mindmap.deleteMap, mindmap.deleteMapConfirm, mindmap.deleteNode (+38 more) - -### Community 491 - "Community 491" -Cohesion: 0.04 -Nodes (46): mindmap.addEdge, mindmap.addMap, mindmap.addNode, mindmap.cancel, mindmap.deleteEdge, mindmap.deleteMap, mindmap.deleteMapConfirm, mindmap.deleteNode (+38 more) - -### Community 492 - "Community 492" -Cohesion: 0.04 -Nodes (46): mindmap.addEdge, mindmap.addMap, mindmap.addNode, mindmap.cancel, mindmap.deleteEdge, mindmap.deleteMap, mindmap.deleteMapConfirm, mindmap.deleteNode (+38 more) - -### Community 493 - "Community 493" -Cohesion: 0.04 -Nodes (46): mindmap.addEdge, mindmap.addMap, mindmap.addNode, mindmap.cancel, mindmap.deleteEdge, mindmap.deleteMap, mindmap.deleteMapConfirm, mindmap.deleteNode (+38 more) - -### Community 494 - "Community 494" -Cohesion: 0.04 -Nodes (46): mindmap.addEdge, mindmap.addMap, mindmap.addNode, mindmap.cancel, mindmap.deleteEdge, mindmap.deleteMap, mindmap.deleteMapConfirm, mindmap.deleteNode (+38 more) - -### Community 495 - "Community 495" -Cohesion: 0.04 -Nodes (46): mindmap.addEdge, mindmap.addMap, mindmap.addNode, mindmap.cancel, mindmap.deleteEdge, mindmap.deleteMap, mindmap.deleteMapConfirm, mindmap.deleteNode (+38 more) - -### Community 496 - "Community 496" -Cohesion: 0.04 -Nodes (46): mindmap.addEdge, mindmap.addMap, mindmap.addNode, mindmap.cancel, mindmap.deleteEdge, mindmap.deleteMap, mindmap.deleteMapConfirm, mindmap.deleteNode (+38 more) - -### Community 497 - "Community 497" -Cohesion: 0.04 -Nodes (46): mindmap.addEdge, mindmap.addMap, mindmap.addNode, mindmap.cancel, mindmap.deleteEdge, mindmap.deleteMap, mindmap.deleteMapConfirm, mindmap.deleteNode (+38 more) - -### Community 498 - "Community 498" -Cohesion: 0.04 -Nodes (46): mindmap.addEdge, mindmap.addMap, mindmap.addNode, mindmap.cancel, mindmap.deleteEdge, mindmap.deleteMap, mindmap.deleteMapConfirm, mindmap.deleteNode (+38 more) - -### Community 499 - "Community 499" -Cohesion: 0.04 -Nodes (46): mindmap.addEdge, mindmap.addMap, mindmap.addNode, mindmap.cancel, mindmap.deleteEdge, mindmap.deleteMap, mindmap.deleteMapConfirm, mindmap.deleteNode (+38 more) - -### Community 500 - "Community 500" -Cohesion: 0.04 -Nodes (46): mindmap.addEdge, mindmap.addMap, mindmap.addNode, mindmap.cancel, mindmap.deleteEdge, mindmap.deleteMap, mindmap.deleteMapConfirm, mindmap.deleteNode (+38 more) - -### Community 501 - "Community 501" -Cohesion: 0.04 -Nodes (46): mindmap.addEdge, mindmap.addMap, mindmap.addNode, mindmap.cancel, mindmap.deleteEdge, mindmap.deleteMap, mindmap.deleteMapConfirm, mindmap.deleteNode (+38 more) - -### Community 502 - "Community 502" -Cohesion: 0.04 -Nodes (46): mindmap.addEdge, mindmap.addMap, mindmap.addNode, mindmap.cancel, mindmap.deleteEdge, mindmap.deleteMap, mindmap.deleteMapConfirm, mindmap.deleteNode (+38 more) - -### Community 503 - "Community 503" -Cohesion: 0.04 -Nodes (46): mindmap.addEdge, mindmap.addMap, mindmap.addNode, mindmap.cancel, mindmap.deleteEdge, mindmap.deleteMap, mindmap.deleteMapConfirm, mindmap.deleteNode (+38 more) - -### Community 504 - "Community 504" -Cohesion: 0.04 -Nodes (46): mindmap.addEdge, mindmap.addMap, mindmap.addNode, mindmap.cancel, mindmap.deleteEdge, mindmap.deleteMap, mindmap.deleteMapConfirm, mindmap.deleteNode (+38 more) - -### Community 505 - "Community 505" -Cohesion: 0.04 -Nodes (46): mindmap.addEdge, mindmap.addMap, mindmap.addNode, mindmap.cancel, mindmap.deleteEdge, mindmap.deleteMap, mindmap.deleteMapConfirm, mindmap.deleteNode (+38 more) - -### Community 506 - "Community 506" -Cohesion: 0.04 -Nodes (46): mindmap.addEdge, mindmap.addMap, mindmap.addNode, mindmap.cancel, mindmap.deleteEdge, mindmap.deleteMap, mindmap.deleteMapConfirm, mindmap.deleteNode (+38 more) - -### Community 507 - "Community 507" -Cohesion: 0.04 -Nodes (45): AI Execution Modes, AI Services Architecture, Build and Development Commands, CI/CD and Deployment, Code Splitting, Code Style and Conventions, Comments, Commit Messages (+37 more) - -### Community 508 - "Community 508" -Cohesion: 0.04 -Nodes (45): Archived (v1.1.2 hotfix β€” done), Archived (v1.2.0 sprint β€” done), Carried over from v1.20.0, Coverage Sprint β€” Test Expansion + Maintenance (2026-05-26), Dependency-Hygiene Backlog (carried forward), DevEx β€” Dual-Graph Integration (2026-05-24), High (🟑), High (🟑) (+37 more) - -### Community 509 - "Community 509" -Cohesion: 0.04 -Nodes (44): 1. `@domain/ai-core` fehlt in `tsconfig.json` paths, 2. `tsc --noEmit` Timeout-Risiko, 3. ONNX Runtime Web Bundle-Size, 4. WGSL Fetch-Pfad relativ, 5. WebNN Detection Fallback, 6. Attention Shader Serial, 7. Compute Shader noch nicht in Produktionscode eingebunden, adaptiveAiEngine.ts (+36 more) - -### Community 511 - "Community 511" -Cohesion: 0.04 -Nodes (45): el, Add, AI, Back, Cancel, Chapter, Character, Close (+37 more) - -### Community 512 - "Community 512" -Cohesion: 0.04 -Nodes (45): fa, Add, AI, Back, Cancel, Chapter, Character, Close (+37 more) - -### Community 513 - "Community 513" -Cohesion: 0.04 -Nodes (45): fi, Add, AI, Back, Cancel, Chapter, Character, Close (+37 more) - -### Community 514 - "Community 514" -Cohesion: 0.04 -Nodes (45): hu, Add, AI, Back, Cancel, Chapter, Character, Close (+37 more) - -### Community 515 - "Community 515" -Cohesion: 0.04 -Nodes (45): is, Add, AI, Back, Cancel, Chapter, Character, Close (+37 more) - -### Community 516 - "Community 516" -Cohesion: 0.04 -Nodes (45): ja, Add, AI, Back, Cancel, Chapter, Character, Close (+37 more) - -### Community 517 - "Community 517" -Cohesion: 0.04 -Nodes (45): pt, Add, AI, Back, Cancel, Chapter, Character, Close (+37 more) - -### Community 518 - "Community 518" -Cohesion: 0.04 -Nodes (45): ru, Add, AI, Back, Cancel, Chapter, Character, Close (+37 more) - -### Community 519 - "Community 519" -Cohesion: 0.04 -Nodes (45): sv, Add, AI, Back, Cancel, Chapter, Character, Close (+37 more) - -### Community 520 - "Community 520" -Cohesion: 0.04 -Nodes (45): zh, Add, AI, Back, Cancel, Chapter, Character, Close (+37 more) - -### Community 521 - "Community 521" -Cohesion: 0.05 -Nodes (42): Agent Checklist β€” Post-Change Verification, AI Services, Architecture, Build & bundler gotchas (Vite 8 + rolldown), Cloud Sync (Cloudflare R2), Code comment convention (QNBS-v3), Code Splitting, codegraph (+34 more) - -### Community 522 - "Community 522" -Cohesion: 0.05 -Nodes (44): eu, Add, AI, Back, Cancel, Chapter, Character, Close (+36 more) - -### Community 523 - "Community 523" -Cohesion: 0.05 -Nodes (41): Architecture Decisions, Code Quality βœ… mostly completed, Codex Auto-Tracking (Story Codex), Ollama / Local-AI Integration βœ… completed, One-Click Library Export βœ…, Phase 3A β€” Cross-Project Search Service βœ…, Phase 3B β€” WebLLM Model Selector βœ…, Phase 3C β€” Collaboration Security Warning βœ… (+33 more) - -### Community 524 - "Community 524" -Cohesion: 0.05 -Nodes (41): app, security, windows, build, beforeBuildCommand, beforeDevCommand, devUrl, frontendDist (+33 more) - -### Community 525 - "Community 525" -Cohesion: 0.05 -Nodes (42): devDependencies, @axe-core/playwright, @biomejs/biome, fake-indexeddb, http-server, jsdom, @lhci/cli, lint-staged (+34 more) - -### Community 526 - "Community 526" -Cohesion: 0.05 -Nodes (37): characterInterviews.archetypeAlly, characterInterviews.archetypeDescription, characterInterviews.archetypeHerald, characterInterviews.archetypeHero, characterInterviews.archetypeLabel, characterInterviews.archetypeMentor, characterInterviews.archetypeShadow, characterInterviews.archetypeShapeshifter (+29 more) - -### Community 527 - "Community 527" -Cohesion: 0.05 -Nodes (37): characterInterviews.archetypeAlly, characterInterviews.archetypeDescription, characterInterviews.archetypeHerald, characterInterviews.archetypeHero, characterInterviews.archetypeLabel, characterInterviews.archetypeMentor, characterInterviews.archetypeShadow, characterInterviews.archetypeShapeshifter (+29 more) - -### Community 528 - "Community 528" -Cohesion: 0.05 -Nodes (37): characterInterviews.archetypeAlly, characterInterviews.archetypeDescription, characterInterviews.archetypeHerald, characterInterviews.archetypeHero, characterInterviews.archetypeLabel, characterInterviews.archetypeMentor, characterInterviews.archetypeShadow, characterInterviews.archetypeShapeshifter (+29 more) - -### Community 529 - "Community 529" -Cohesion: 0.05 -Nodes (37): characterInterviews.archetypeAlly, characterInterviews.archetypeDescription, characterInterviews.archetypeHerald, characterInterviews.archetypeHero, characterInterviews.archetypeLabel, characterInterviews.archetypeMentor, characterInterviews.archetypeShadow, characterInterviews.archetypeShapeshifter (+29 more) - -### Community 530 - "Community 530" -Cohesion: 0.05 -Nodes (37): characterInterviews.archetypeAlly, characterInterviews.archetypeDescription, characterInterviews.archetypeHerald, characterInterviews.archetypeHero, characterInterviews.archetypeLabel, characterInterviews.archetypeMentor, characterInterviews.archetypeShadow, characterInterviews.archetypeShapeshifter (+29 more) - -### Community 531 - "Community 531" -Cohesion: 0.05 -Nodes (37): characterInterviews.archetypeAlly, characterInterviews.archetypeDescription, characterInterviews.archetypeHerald, characterInterviews.archetypeHero, characterInterviews.archetypeLabel, characterInterviews.archetypeMentor, characterInterviews.archetypeShadow, characterInterviews.archetypeShapeshifter (+29 more) - -### Community 532 - "Community 532" -Cohesion: 0.05 -Nodes (37): characterInterviews.archetypeAlly, characterInterviews.archetypeDescription, characterInterviews.archetypeHerald, characterInterviews.archetypeHero, characterInterviews.archetypeLabel, characterInterviews.archetypeMentor, characterInterviews.archetypeShadow, characterInterviews.archetypeShapeshifter (+29 more) - -### Community 533 - "Community 533" -Cohesion: 0.05 -Nodes (37): characterInterviews.archetypeAlly, characterInterviews.archetypeDescription, characterInterviews.archetypeHerald, characterInterviews.archetypeHero, characterInterviews.archetypeLabel, characterInterviews.archetypeMentor, characterInterviews.archetypeShadow, characterInterviews.archetypeShapeshifter (+29 more) - -### Community 534 - "Community 534" -Cohesion: 0.05 -Nodes (37): characterInterviews.archetypeAlly, characterInterviews.archetypeDescription, characterInterviews.archetypeHerald, characterInterviews.archetypeHero, characterInterviews.archetypeLabel, characterInterviews.archetypeMentor, characterInterviews.archetypeShadow, characterInterviews.archetypeShapeshifter (+29 more) - -### Community 535 - "Community 535" -Cohesion: 0.05 -Nodes (37): characterInterviews.archetypeAlly, characterInterviews.archetypeDescription, characterInterviews.archetypeHerald, characterInterviews.archetypeHero, characterInterviews.archetypeLabel, characterInterviews.archetypeMentor, characterInterviews.archetypeShadow, characterInterviews.archetypeShapeshifter (+29 more) - -### Community 536 - "Community 536" -Cohesion: 0.05 -Nodes (37): characterInterviews.archetypeAlly, characterInterviews.archetypeDescription, characterInterviews.archetypeHerald, characterInterviews.archetypeHero, characterInterviews.archetypeLabel, characterInterviews.archetypeMentor, characterInterviews.archetypeShadow, characterInterviews.archetypeShapeshifter (+29 more) - -### Community 537 - "Community 537" -Cohesion: 0.05 -Nodes (37): characterInterviews.archetypeAlly, characterInterviews.archetypeDescription, characterInterviews.archetypeHerald, characterInterviews.archetypeHero, characterInterviews.archetypeLabel, characterInterviews.archetypeMentor, characterInterviews.archetypeShadow, characterInterviews.archetypeShapeshifter (+29 more) - -### Community 538 - "Community 538" -Cohesion: 0.05 -Nodes (37): characterInterviews.archetypeAlly, characterInterviews.archetypeDescription, characterInterviews.archetypeHerald, characterInterviews.archetypeHero, characterInterviews.archetypeLabel, characterInterviews.archetypeMentor, characterInterviews.archetypeShadow, characterInterviews.archetypeShapeshifter (+29 more) - -### Community 539 - "Community 539" -Cohesion: 0.05 -Nodes (37): characterInterviews.archetypeAlly, characterInterviews.archetypeDescription, characterInterviews.archetypeHerald, characterInterviews.archetypeHero, characterInterviews.archetypeLabel, characterInterviews.archetypeMentor, characterInterviews.archetypeShadow, characterInterviews.archetypeShapeshifter (+29 more) - -### Community 540 - "Community 540" -Cohesion: 0.05 -Nodes (37): characterInterviews.archetypeAlly, characterInterviews.archetypeDescription, characterInterviews.archetypeHerald, characterInterviews.archetypeHero, characterInterviews.archetypeLabel, characterInterviews.archetypeMentor, characterInterviews.archetypeShadow, characterInterviews.archetypeShapeshifter (+29 more) - -### Community 541 - "Community 541" -Cohesion: 0.05 -Nodes (37): characterInterviews.archetypeAlly, characterInterviews.archetypeDescription, characterInterviews.archetypeHerald, characterInterviews.archetypeHero, characterInterviews.archetypeLabel, characterInterviews.archetypeMentor, characterInterviews.archetypeShadow, characterInterviews.archetypeShapeshifter (+29 more) - -### Community 542 - "Community 542" -Cohesion: 0.05 -Nodes (37): characterInterviews.archetypeAlly, characterInterviews.archetypeDescription, characterInterviews.archetypeHerald, characterInterviews.archetypeHero, characterInterviews.archetypeLabel, characterInterviews.archetypeMentor, characterInterviews.archetypeShadow, characterInterviews.archetypeShapeshifter (+29 more) - -### Community 543 - "Community 543" -Cohesion: 0.05 -Nodes (37): characterInterviews.archetypeAlly, characterInterviews.archetypeDescription, characterInterviews.archetypeHerald, characterInterviews.archetypeHero, characterInterviews.archetypeLabel, characterInterviews.archetypeMentor, characterInterviews.archetypeShadow, characterInterviews.archetypeShapeshifter (+29 more) - -### Community 544 - "Community 544" -Cohesion: 0.05 -Nodes (37): characterInterviews.archetypeAlly, characterInterviews.archetypeDescription, characterInterviews.archetypeHerald, characterInterviews.archetypeHero, characterInterviews.archetypeLabel, characterInterviews.archetypeMentor, characterInterviews.archetypeShadow, characterInterviews.archetypeShapeshifter (+29 more) - -### Community 545 - "Community 545" -Cohesion: 0.06 -Nodes (35): Applying Accepted Edits, Architecture Principles, BaseAgent Abstract Class, Configuration, Dual-Purpose Architecture (Core Capability Layer + MCP), Empty States (X-3), Enabling ProForge, File Structure (+27 more) - -### Community 546 - "Community 546" -Cohesion: 0.23 -Nodes (15): createOllamaModelFromAdapter(), deleteOllamaModel(), generateModelfile(), getOllamaUrl(), listOllamaAdapterModels(), listOllamaModels(), OllamaModel, testOllamaAdapterPrompt() (+7 more) - -### Community 547 - "Community 547" -Cohesion: 0.17 -Nodes (19): abortTraining(), checkTrainingEnvironment(), generateOllamaModelfile(), mergeAdapter(), startTraining(), tauriInvoke(), tauriListen(), TrainingJobConfig (+11 more) - -### Community 549 - "Community 549" -Cohesion: 0.06 -Nodes (33): 1. Feature-Mapping (Ist β†’ Geplant), 2. Detaillierte Spezifikation: Command Palette (Weltklasse-Zielbild), 3. Detaillierte Spezifikation: Settings-Hub, 4. Detaillierte Spezifikation: Help-Hub, 5. SekundΓ€re Hilfsfunktionen (gemeinsames Design-System), 6. Architektur-Skizze (Ziel), 7. Priorisierte Umsetzung (nach deiner Vorgabe), 8. Risiken und Prinzipien (+25 more) - -### Community 550 - "Community 550" -Cohesion: 0.13 -Nodes (4): KokoroTtsEngine, WebRtcVadEngine, VoiceActivityCoordinator, workerBootstrap() - -### Community 552 - "Community 552" -Cohesion: 0.06 -Nodes (33): compilerOptions, allowImportingTsExtensions, esModuleInterop, exactOptionalPropertyTypes, isolatedModules, jsx, lib, module (+25 more) - -### Community 553 - "Community 553" -Cohesion: 0.10 -Nodes (29): hasMigrationMarker(), legacyDatabaseListed(), migrateLegacyWorldscriptDbIfNeeded(), openLegacyDatabase(), promisifyRequest(), readAllFromStore(), setMigrationMarker(), stateDbHasProjectOrSettings() (+21 more) - -### Community 554 - "Community 554" -Cohesion: 0.15 -Nodes (21): CacheEntry, clearOpenRouterModelCache(), fetchOpenRouterModels(), getOpenRouterModelCatalog(), isBrowser(), isValidCacheEntry(), logger, OpenRouterModel (+13 more) - -### Community 555 - "Community 555" -Cohesion: 0.06 -Nodes (32): 1. Übersicht & Ziele, 2. Phase 0 β€” Regression Audit, 3.1 IDB At-Rest Encryption UX Finalisierung, 3.2 Voice WASM Pipeline, 3.3 GPU Metrics & Diagnostics, 3. Phase 1 β€” Infrastructure & UX Hardening, 4.1 ONNX/Transformers.js Stubs β†’ Real Implementations, 4.2 LoRA Productionization (+24 more) - -### Community 556 - "Community 556" -Cohesion: 0.09 -Nodes (21): createImageRegistrar(), esc(), exportEpub(), exportEpubViaApi(), renderBody(), renderLine(), MockJSZip, stubDownload() (+13 more) - -### Community 557 - "Community 557" -Cohesion: 0.06 -Nodes (31): background_color, categories, description, dir, display, display_override, edge_side_panel, preferred_width (+23 more) - -### Community 558 - "Community 558" -Cohesion: 0.06 -Nodes (31): compilerOptions, allowImportingTsExtensions, esModuleInterop, exactOptionalPropertyTypes, isolatedModules, jsx, lib, module (+23 more) - -### Community 559 - "Community 559" -Cohesion: 0.48 -Nodes (3): decryptCloudPayload(), deriveCloudSyncKey(), encryptCloudPayload() - -### Community 560 - "Community 560" -Cohesion: 0.12 -Nodes (29): glossaryTranslate(), loadCheckpoint(), loadGlossary(), main(), maskPlaceholders(), parseArgs(), restorePlaceholders(), saveCheckpoint() (+21 more) - -### Community 561 - "Community 561" -Cohesion: 0.07 -Nodes (29): 4a. App.tsx Route hinzufΓΌgen, 4b. LoRA Settings UI erstellen, 4c. Redux β†’ Service Wiring, 4d. Worker-Seitige LoRA, 4e. Legacy generateText LoRA, AbortSignal durch die Schichten, Bekannte Blocker & Workarounds (Schnell-Lookup), Dateien, die beim Wiederaufnehmen direkt gebraucht werden (+21 more) - -### Community 562 - "Community 562" -Cohesion: 0.29 -Nodes (6): CharacterView(), baseContextValue, mockConfirmDelete, mockHandleAddNewManually, mockHandleAddNewWithAI, mockHandleSelect - -### Community 563 - "Community 563" -Cohesion: 0.07 -Nodes (29): checkers, concurrency, coverageAnalysis, htmlReporter, fileName, ignorePatterns, ignoreStatic, incremental (+21 more) - -### Community 564 - "Community 564" -Cohesion: 0.07 -Nodes (30): πŸ‘₯ Advanced Character Dossiers, πŸ€– AI Outline Generator, ✨ AI Writing Studio _(10 Specialized AI Tools)_, πŸ•ΈοΈ Character Relationship Graph _(Interactive Visualization)_, ⌨️ Command Palette & Productivity Hub, πŸ”­ Cross-Project Search _(v2 β€” Privacy-Preserving Index)_, πŸ“Š Dynamic Project Dashboard, πŸ” Encrypted Library Backup (+22 more) - -### Community 565 - "Community 565" -Cohesion: 0.29 -Nodes (6): ltMock, mockActiveSection, mockHandleContentChange, mockHandleMentionSelect, mockHandleTitleChange, mockMentions - -### Community 566 - "Community 566" -Cohesion: 0.16 -Nodes (19): ProjectPayload, baseOpts, capabilityCache, cli, CliOptions, getStartupPayload(), inlineCapability(), resolveCapability() (+11 more) - -### Community 567 - "Community 567" -Cohesion: 0.15 -Nodes (18): getActualKeyCount(), getActualLocaleCount(), getCanonicalProductionUrl(), getLatestReleasedVersion(), main(), scanForDrift(), scanForUrlDrift(), stripHistoricalSections() (+10 more) - -### Community 568 - "Community 568" -Cohesion: 0.07 -Nodes (26): βœ… 2026-05-31 Session β€” i18n Audit + Settings + CI Fixes, CI Fixes, βœ… Completed P0 items in this session, DEβ†’EN Developer Comment Translation, DE i18n Quality Fixes, Git status, i18n β€” Community Templates Localized, ⚠️ Known technical limitations (+18 more) - -### Community 569 - "Community 569" -Cohesion: 0.07 -Nodes (26): 1. STATUS: VOLLSTΓ„NDIG ABGESCHLOSSEN (alle Phasen 0–7), 2. NΓ„CHSTER SCHRITT (Copy-Paste Ready), 3. ERSTER BEFEHL NACH SITZUNGSSTART, 4. DATEI-INVENTAR (Wichtigste Dateien fΓΌr Phase 5), 5. BEKANNTE FALLSTRICKE (Lesen, bevor du codierst), 6. QUALITY GATES (Vor jeder Commit-Push-Entscheidung), 7. KONTEXT-SCHLÜSSELWΓ–RTER (FΓΌr Suche/Navigation), 8. NACHRICHT AN ZUKÜNFTIGES ICH / ANDEREN AGENTEN (+18 more) - -### Community 571 - "Community 571" -Cohesion: 0.08 -Nodes (25): βœ… Abgeschlossen, Code-Γ„nderungen dieser Sitzung, Detaillierter Fortschritt, Erweiterte Tests, Executive Summary, GeΓ€nderte Dateien, Git-Status (empfohlenes Commit-Paket), πŸ”„ In Arbeit / Teilweise (+17 more) - -### Community 572 - "Community 572" -Cohesion: 0.08 -Nodes (24): [1.11.0] β€” 2026-05-22, [1.17.0] β€” 2026-05-24, [1.17.1] β€” 2026-05-26, [1.18.1] β€” 2026-05-27, [1.23.1] β€” 2026-06-17, [1.24.3] β€” 2026-07-30, [1.6.1] β€” 2026-05-19, [1.9.0] β€” 2026-05-21 (+16 more) - -### Community 573 - "Community 573" -Cohesion: 0.08 -Nodes (24): Accessibility (WCAG 2.2 AA-oriented), Architecture, CI/CD Security Hardening (QNBS-v3), codegraph, Coding Standards, Collaboration, Commands, Copilot Instructions β€” WorldScript Studio (+16 more) - -### Community 574 - "Community 574" -Cohesion: 0.07 -Nodes (29): abortTrainingThunk, activateAdapterThunk, buildDatasetThunk, deactivateAdapterThunk, deleteAdapterThunk, evaluateAdapterThunk, loadAdaptersThunk, mergeAdapterThunk (+21 more) - -### Community 575 - "Community 575" -Cohesion: 0.08 -Nodes (24): SileroVadEngine, createVadEngine(), WebRtcVadEngine, log, downloadVoiceModels(), GetStateFn, getVoiceService(), HarnessWindow (+16 more) - -### Community 576 - "Community 576" -Cohesion: 0.08 -Nodes (25): [1.2.0] β€” 2026-05-02, Added, Added, Added, Added, Added, Added (Tests), Changed (+17 more) - -### Community 577 - "Community 577" -Cohesion: 0.08 -Nodes (23): sidebar.characterGraph, sidebar.characterInterviews, sidebar.characters, sidebar.consistencyChecker, sidebar.critic, sidebar.dashboard, sidebar.export, sidebar.help (+15 more) - -### Community 578 - "Community 578" -Cohesion: 0.09 -Nodes (14): fileHash(), update(), register(), checkForUpdate(), isTauriEnvironment(), registerServiceWorker(), ASSETS, destDir (+6 more) - -### Community 579 - "Community 579" -Cohesion: 0.08 -Nodes (23): Accessibility-Audit + Overhaul-Plan (WorldScript-Studio), Architektur-Integration (schlanke, wartbare Schicht), Character Graph ([`CharacterGraphView.tsx`](components/CharacterGraphView.tsx)), Command Palette ([`CommandPalette.tsx`](components/CommandPalette.tsx)), Consistency Checker / Critic / AI-lastige Views, Dashboard ([`Dashboard.tsx`](components/Dashboard.tsx)), Globales Layout / App-Shell ([`App.tsx`](App.tsx), [`Header.tsx`](components/Header.tsx), [`Sidebar.tsx`](components/Sidebar.tsx)), Help ([`HelpView.tsx`](components/HelpView.tsx), [`services/help/*`](services/help/)) (+15 more) - -### Community 580 - "Community 580" -Cohesion: 0.08 -Nodes (23): sidebar.characterGraph, sidebar.characterInterviews, sidebar.characters, sidebar.consistencyChecker, sidebar.critic, sidebar.dashboard, sidebar.export, sidebar.help (+15 more) - -### Community 581 - "Community 581" -Cohesion: 0.08 -Nodes (23): 5.1 ProForge Pipeline Caching, 5.2 RAG Compute Acceleration, 5.3 Plot-Board GPU Simulation, 5.4 Voice Pipeline Optimization, 5.5 Manuscript Live Features, 5.6 Feature-Flag-Integration, 5.7 i18n Keys, Datei-Inventar (Neu/Erweitert in diesem Cycle) (+15 more) - -### Community 582 - "Community 582" -Cohesion: 0.08 -Nodes (23): After Day 14 (final):, After Day 6 (end of Week 1):, After each major day block:, Context, Critical Files to Create (in order), Gap Analysis: StoryCraft vs CannaGuide Local-AI, Git Workflow:, Master Perfection Run v1.5 β€” Implementation Plan (+15 more) - -### Community 583 - "Community 583" -Cohesion: 0.08 -Nodes (23): sidebar.characterGraph, sidebar.characterInterviews, sidebar.characters, sidebar.consistencyChecker, sidebar.critic, sidebar.dashboard, sidebar.export, sidebar.help (+15 more) - -### Community 584 - "Community 584" -Cohesion: 0.08 -Nodes (23): sidebar.characterGraph, sidebar.characterInterviews, sidebar.characters, sidebar.consistencyChecker, sidebar.critic, sidebar.dashboard, sidebar.export, sidebar.help (+15 more) - -### Community 586 - "Community 586" -Cohesion: 0.08 -Nodes (23): sidebar.characterGraph, sidebar.characterInterviews, sidebar.characters, sidebar.consistencyChecker, sidebar.critic, sidebar.dashboard, sidebar.export, sidebar.help (+15 more) - -### Community 587 - "Community 587" -Cohesion: 0.08 -Nodes (23): sidebar.characterGraph, sidebar.characterInterviews, sidebar.characters, sidebar.consistencyChecker, sidebar.critic, sidebar.dashboard, sidebar.export, sidebar.help (+15 more) - -### Community 588 - "Community 588" -Cohesion: 0.08 -Nodes (23): sidebar.characterGraph, sidebar.characterInterviews, sidebar.characters, sidebar.consistencyChecker, sidebar.critic, sidebar.dashboard, sidebar.export, sidebar.help (+15 more) - -### Community 589 - "Community 589" -Cohesion: 0.08 -Nodes (23): sidebar.characterGraph, sidebar.characterInterviews, sidebar.characters, sidebar.consistencyChecker, sidebar.critic, sidebar.dashboard, sidebar.export, sidebar.help (+15 more) - -### Community 590 - "Community 590" -Cohesion: 0.08 -Nodes (23): sidebar.characterGraph, sidebar.characterInterviews, sidebar.characters, sidebar.consistencyChecker, sidebar.critic, sidebar.dashboard, sidebar.export, sidebar.help (+15 more) - -### Community 591 - "Community 591" -Cohesion: 0.08 -Nodes (23): sidebar.characterGraph, sidebar.characterInterviews, sidebar.characters, sidebar.consistencyChecker, sidebar.critic, sidebar.dashboard, sidebar.export, sidebar.help (+15 more) - -### Community 592 - "Community 592" -Cohesion: 0.08 -Nodes (23): sidebar.characterGraph, sidebar.characterInterviews, sidebar.characters, sidebar.consistencyChecker, sidebar.critic, sidebar.dashboard, sidebar.export, sidebar.help (+15 more) - -### Community 594 - "Community 594" -Cohesion: 0.08 -Nodes (23): sidebar.characterGraph, sidebar.characterInterviews, sidebar.characters, sidebar.consistencyChecker, sidebar.critic, sidebar.dashboard, sidebar.export, sidebar.help (+15 more) - -### Community 596 - "Community 596" -Cohesion: 0.08 -Nodes (23): sidebar.characterGraph, sidebar.characterInterviews, sidebar.characters, sidebar.consistencyChecker, sidebar.critic, sidebar.dashboard, sidebar.export, sidebar.help (+15 more) - -### Community 597 - "Community 597" -Cohesion: 0.08 -Nodes (23): sidebar.characterGraph, sidebar.characterInterviews, sidebar.characters, sidebar.consistencyChecker, sidebar.critic, sidebar.dashboard, sidebar.export, sidebar.help (+15 more) - -### Community 598 - "Community 598" -Cohesion: 0.08 -Nodes (23): sidebar.characterGraph, sidebar.characterInterviews, sidebar.characters, sidebar.consistencyChecker, sidebar.critic, sidebar.dashboard, sidebar.export, sidebar.help (+15 more) - -### Community 599 - "Community 599" -Cohesion: 0.08 -Nodes (23): sidebar.characterGraph, sidebar.characterInterviews, sidebar.characters, sidebar.consistencyChecker, sidebar.critic, sidebar.dashboard, sidebar.export, sidebar.help (+15 more) - -### Community 600 - "Community 600" -Cohesion: 0.08 -Nodes (23): sidebar.characterGraph, sidebar.characterInterviews, sidebar.characters, sidebar.consistencyChecker, sidebar.critic, sidebar.dashboard, sidebar.export, sidebar.help (+15 more) - -### Community 603 - "Community 603" -Cohesion: 0.08 -Nodes (23): sidebar.characterGraph, sidebar.characterInterviews, sidebar.characters, sidebar.consistencyChecker, sidebar.critic, sidebar.dashboard, sidebar.export, sidebar.help (+15 more) - -### Community 607 - "Community 607" -Cohesion: 0.29 -Nodes (6): Default, Disabled, meta, Story, WithLabel, WithValue - -### Community 608 - "Community 608" -Cohesion: 0.15 -Nodes (19): clearTelemetry(), ensureTable(), getRecentTelemetry(), InferenceTelemetryEntry, readLocalEntries(), recordInferenceTelemetry(), setTelemetryEnabled(), localStorageData (+11 more) - -### Community 611 - "Community 611" -Cohesion: 0.08 -Nodes (23): sidebar.characterGraph, sidebar.characterInterviews, sidebar.characters, sidebar.consistencyChecker, sidebar.critic, sidebar.dashboard, sidebar.export, sidebar.help (+15 more) - -### Community 612 - "Community 612" -Cohesion: 0.08 -Nodes (23): es, settings.about.tauriVersion, settings.categories.experimental, settings.categories.guide, settings.data.openDataFolder, settings.data.openDataFolderHint, settings.featureFlags.enableCharacterInterviews, settings.featureFlags.enableDuckDbAnalytics (+15 more) - -### Community 614 - "Community 614" -Cohesion: 0.12 -Nodes (23): applyTextEdit(), extractCodeBlock(), applyReviewEditsToSection(), containsDisallowedControlChar(), isValidRange(), nearestFreeOccurrence(), item(), validateProposedText() (+15 more) - -### Community 615 - "Community 615" -Cohesion: 0.09 -Nodes (23): fr, settings.about.tauriVersion, settings.categories.experimental, settings.categories.guide, settings.data.openDataFolder, settings.data.openDataFolderHint, settings.featureFlags.enableCharacterInterviews, settings.featureFlags.enableDuckDbAnalytics (+15 more) - -### Community 616 - "Community 616" -Cohesion: 0.09 -Nodes (23): it, settings.about.tauriVersion, settings.categories.experimental, settings.categories.guide, settings.data.openDataFolder, settings.data.openDataFolderHint, settings.featureFlags.enableCharacterInterviews, settings.featureFlags.enableDuckDbAnalytics (+15 more) - -### Community 617 - "Community 617" -Cohesion: 0.10 -Nodes (18): assertAll(), countTestFiles(), drift, E2E_DIR, fileCount, getTestFileCount(), keyCount, localeCount (+10 more) - -### Community 618 - "Community 618" -Cohesion: 0.09 -Nodes (22): dependsOn, outputs, cache, persistent, globalEnv, dependsOn, outputs, cache (+14 more) - -### Community 619 - "Community 619" -Cohesion: 0.07 -Nodes (30): CloudflarePagesContext, config, handler(), onRequest(), VALID_API_KEY, handler(), onRequest(), clientIdFor() (+22 more) - -### Community 620 - "Community 620" -Cohesion: 0.09 -Nodes (21): App-Inhalte β€” Help, Tour, FAQ, Command Palette, App-Inhalte β€” README / CHANGELOG / ROADMAP / AUDIT, App-Inhalte β€” Templates & Samples, Best-Practices-Spezifikation β€” App-Inhalte (verbindlich fΓΌr Umsetzung), Best-Practices-Spezifikation β€” Technik (zentrale Bereiche), CI/CD, Code & Architektur, Documentation (+13 more) - -### Community 621 - "Community 621" -Cohesion: 0.09 -Nodes (21): 1. Semantic Design Tokens, 2. RTL & CJK Support, 3. Reduced Motion, 4. Keyboard Navigation, Contributing, Design Principles, LanguageSelector, Migration Guide (+13 more) - -### Community 622 - "Community 622" -Cohesion: 0.09 -Nodes (21): 0. Executive summary β€” verified current state (corrects the original draft's premise, twice), 1. Ground rules for whoever executes this plan, 2. Phase 0 β€” Analysis & ADR (already substantially done by this plan; formalize on execution), 3. Phase 1 β€” Grok: native provider wiring (backend already works), 4.0 Track A β€” Desktop: native-HTTP fix (small, ships first, no new infrastructure), 4.1.1 The deployment-target problem, 4.1.2 Proxy design, 4.1 Track B β€” Web/PWA: serverless CORS proxy (the actual new architecture) (+13 more) - -### Community 623 - "Community 623" -Cohesion: 0.06 -Nodes (27): buildKeyModuleMap(), loadModuleData(), getLocales(), getModules(), getMtLocales(), __dirname, langs, modules (+19 more) - -### Community 624 - "Community 624" -Cohesion: 0.10 -Nodes (20): After code changes (no API cost), Automatic updates, Daily usage, Fine-tuning what gets indexed, Full semantic rebuild (uses LLM, costs tokens), God Nodes (most connected abstractions), Graph stats (last build: 2026-04-30), Graphify β€” Knowledge Graph Setup (+12 more) - -### Community 625 - "Community 625" -Cohesion: 0.10 -Nodes (19): After large refactors, Claude Code, CodeGraph β€” Semantic Code Intelligence Setup, Cursor, Daily Workflow, Find affected tests before committing, Installation, Kimi Code CLI (+11 more) - -### Community 626 - "Community 626" -Cohesion: 0.10 -Nodes (19): AI Prompt Injection Attack Tree, Attack Trees, Claude serverless proxy trust-model change (ADR-0016 Track B), Collaboration MITM Attack Tree, CSP connect-src: web-vs-Tauri asymmetry (ADR-0004), CSP script-src: `'wasm-unsafe-eval'` (ADR-0013), D - Denial of Service, Desktop (Tauri) Local File-Read Attack Tree (+11 more) - -### Community 627 - "Community 627" -Cohesion: 0.11 -Nodes (18): tags.adventure, tags.beginnerFriendly, tags.characterDriven, tags.classic, tags.commercial, tags.emotional, tags.epic, tags.fastPaced (+10 more) - -### Community 628 - "Community 628" -Cohesion: 0.11 -Nodes (18): tour.btn.done, tour.btn.next, tour.btn.prev, tour.help.startButton, tour.intro.body, tour.intro.title, tour.nav.body, tour.nav.title (+10 more) - -### Community 629 - "Community 629" -Cohesion: 0.11 -Nodes (18): tags.adventure, tags.beginnerFriendly, tags.characterDriven, tags.classic, tags.commercial, tags.emotional, tags.epic, tags.fastPaced (+10 more) - -### Community 630 - "Community 630" -Cohesion: 0.11 -Nodes (18): tour.btn.done, tour.btn.next, tour.btn.prev, tour.help.startButton, tour.intro.body, tour.intro.title, tour.nav.body, tour.nav.title (+10 more) - -### Community 631 - "Community 631" -Cohesion: 0.11 -Nodes (18): CI Reference β€” WorldScript Studio, Cloud CI-first vs local development, Commit messages, Composite setup action, CSP gates β€” which layer catches which failure class, E2E authoring (Playwright), Job graph, Local checks (without Act) (+10 more) - -### Community 632 - "Community 632" -Cohesion: 0.11 -Nodes (18): 0. Current state (2026-06-24), 0a. Reports digest (populated from maintainer-shared report pages), 1. Prioritisation framework (work top-down), 2. Execution model, 3. Findings inventory β€” TO BE POPULATED, 4. Likely hotspots (unverified β€” confirm against the real report), 4b. In-code `skipcq` does NOT attach to JSX-attribute issues (proven on PR #228), 4c. Long-term: retire the `any` test-mock suppressions (optional code-health track) (+10 more) - -### Community 633 - "Community 633" -Cohesion: 0.11 -Nodes (18): Baseline at Sprint Start (v1.5.0), Day 10 β€” Final QA + Docs + Release, Day 4 β€” Real-Time Book Preview, Day 5 β€” Reference Panel / Split-View, Day 6 β€” Per-Scene Revision History + Threaded Comments, Day 7 β€” Progress Tracker Dashboard, Days 1–3 β€” Plot-Board v2, Days 8–9 β€” Mobile Polish (+10 more) - -### Community 636 - "Community 636" -Cohesion: 0.11 -Nodes (18): tags.adventure, tags.beginnerFriendly, tags.characterDriven, tags.classic, tags.commercial, tags.emotional, tags.epic, tags.fastPaced (+10 more) - -### Community 637 - "Community 637" -Cohesion: 0.11 -Nodes (18): tour.btn.done, tour.btn.next, tour.btn.prev, tour.help.startButton, tour.intro.body, tour.intro.title, tour.nav.body, tour.nav.title (+10 more) - -### Community 638 - "Community 638" -Cohesion: 0.11 -Nodes (18): tags.adventure, tags.beginnerFriendly, tags.characterDriven, tags.classic, tags.commercial, tags.emotional, tags.epic, tags.fastPaced (+10 more) - -### Community 639 - "Community 639" -Cohesion: 0.03 -Nodes (49): EcoModeService, buildTimeoutSignal(), createLogger(), log(), run(), cryptoSrc, deps, failures (+41 more) - -### Community 641 - "Community 641" -Cohesion: 0.11 -Nodes (18): tour.btn.done, tour.btn.next, tour.btn.prev, tour.help.startButton, tour.intro.body, tour.intro.title, tour.nav.body, tour.nav.title (+10 more) - -### Community 642 - "Community 642" -Cohesion: 0.11 -Nodes (18): tags.adventure, tags.beginnerFriendly, tags.characterDriven, tags.classic, tags.commercial, tags.emotional, tags.epic, tags.fastPaced (+10 more) - -### Community 643 - "Community 643" -Cohesion: 0.11 -Nodes (18): tour.btn.done, tour.btn.next, tour.btn.prev, tour.help.startButton, tour.intro.body, tour.intro.title, tour.nav.body, tour.nav.title (+10 more) - -### Community 644 - "Community 644" -Cohesion: 0.11 -Nodes (18): tags.adventure, tags.beginnerFriendly, tags.characterDriven, tags.classic, tags.commercial, tags.emotional, tags.epic, tags.fastPaced (+10 more) - -### Community 645 - "Community 645" -Cohesion: 0.11 -Nodes (18): tour.btn.done, tour.btn.next, tour.btn.prev, tour.help.startButton, tour.intro.body, tour.intro.title, tour.nav.body, tour.nav.title (+10 more) - -### Community 646 - "Community 646" -Cohesion: 0.11 -Nodes (18): tags.adventure, tags.beginnerFriendly, tags.characterDriven, tags.classic, tags.commercial, tags.emotional, tags.epic, tags.fastPaced (+10 more) - -### Community 647 - "Community 647" -Cohesion: 0.11 -Nodes (18): tour.btn.done, tour.btn.next, tour.btn.prev, tour.help.startButton, tour.intro.body, tour.intro.title, tour.nav.body, tour.nav.title (+10 more) - -### Community 648 - "Community 648" -Cohesion: 0.11 -Nodes (18): tags.adventure, tags.beginnerFriendly, tags.characterDriven, tags.classic, tags.commercial, tags.emotional, tags.epic, tags.fastPaced (+10 more) - -### Community 649 - "Community 649" -Cohesion: 0.11 -Nodes (18): tour.btn.done, tour.btn.next, tour.btn.prev, tour.help.startButton, tour.intro.body, tour.intro.title, tour.nav.body, tour.nav.title (+10 more) - -### Community 651 - "Community 651" -Cohesion: 0.11 -Nodes (18): tags.adventure, tags.beginnerFriendly, tags.characterDriven, tags.classic, tags.commercial, tags.emotional, tags.epic, tags.fastPaced (+10 more) - -### Community 652 - "Community 652" -Cohesion: 0.11 -Nodes (18): tour.btn.done, tour.btn.next, tour.btn.prev, tour.help.startButton, tour.intro.body, tour.intro.title, tour.nav.body, tour.nav.title (+10 more) - -### Community 653 - "Community 653" -Cohesion: 0.11 -Nodes (18): tags.adventure, tags.beginnerFriendly, tags.characterDriven, tags.classic, tags.commercial, tags.emotional, tags.epic, tags.fastPaced (+10 more) - -### Community 654 - "Community 654" -Cohesion: 0.11 -Nodes (18): tour.btn.done, tour.btn.next, tour.btn.prev, tour.help.startButton, tour.intro.body, tour.intro.title, tour.nav.body, tour.nav.title (+10 more) - -### Community 655 - "Community 655" -Cohesion: 0.11 -Nodes (18): tags.adventure, tags.beginnerFriendly, tags.characterDriven, tags.classic, tags.commercial, tags.emotional, tags.epic, tags.fastPaced (+10 more) - -### Community 656 - "Community 656" -Cohesion: 0.11 -Nodes (18): tour.btn.done, tour.btn.next, tour.btn.prev, tour.help.startButton, tour.intro.body, tour.intro.title, tour.nav.body, tour.nav.title (+10 more) - -### Community 657 - "Community 657" -Cohesion: 0.11 -Nodes (18): act configuration, Backup, Common problems (installation), Installation β€” Low-End Local CI/CD (Ubuntu 20.04 Mate), Phase 0 β€” Evaluate baseline, Phase 1 β€” System base, Phase 2 β€” Docker CE (24.x) on Ubuntu 20.04, Phase 3 β€” Node 22 + pnpm (fnm, not apt) (+10 more) - -### Community 658 - "Community 658" -Cohesion: 0.11 -Nodes (18): tags.adventure, tags.beginnerFriendly, tags.characterDriven, tags.classic, tags.commercial, tags.emotional, tags.epic, tags.fastPaced (+10 more) - -### Community 659 - "Community 659" -Cohesion: 0.11 -Nodes (18): tour.btn.done, tour.btn.next, tour.btn.prev, tour.help.startButton, tour.intro.body, tour.intro.title, tour.nav.body, tour.nav.title (+10 more) - -### Community 660 - "Community 660" -Cohesion: 0.11 -Nodes (18): tags.adventure, tags.beginnerFriendly, tags.characterDriven, tags.classic, tags.commercial, tags.emotional, tags.epic, tags.fastPaced (+10 more) - -### Community 661 - "Community 661" -Cohesion: 0.11 -Nodes (18): tour.btn.done, tour.btn.next, tour.btn.prev, tour.help.startButton, tour.intro.body, tour.intro.title, tour.nav.body, tour.nav.title (+10 more) - -### Community 662 - "Community 662" -Cohesion: 0.11 -Nodes (18): tags.adventure, tags.beginnerFriendly, tags.characterDriven, tags.classic, tags.commercial, tags.emotional, tags.epic, tags.fastPaced (+10 more) - -### Community 663 - "Community 663" -Cohesion: 0.11 -Nodes (18): tour.btn.done, tour.btn.next, tour.btn.prev, tour.help.startButton, tour.intro.body, tour.intro.title, tour.nav.body, tour.nav.title (+10 more) - -### Community 664 - "Community 664" -Cohesion: 0.11 -Nodes (18): tags.adventure, tags.beginnerFriendly, tags.characterDriven, tags.classic, tags.commercial, tags.emotional, tags.epic, tags.fastPaced (+10 more) - -### Community 665 - "Community 665" -Cohesion: 0.11 -Nodes (18): tour.btn.done, tour.btn.next, tour.btn.prev, tour.help.startButton, tour.intro.body, tour.intro.title, tour.nav.body, tour.nav.title (+10 more) - -### Community 666 - "Community 666" -Cohesion: 0.11 -Nodes (18): tags.adventure, tags.beginnerFriendly, tags.characterDriven, tags.classic, tags.commercial, tags.emotional, tags.epic, tags.fastPaced (+10 more) - -### Community 667 - "Community 667" -Cohesion: 0.11 -Nodes (18): tour.btn.done, tour.btn.next, tour.btn.prev, tour.help.startButton, tour.intro.body, tour.intro.title, tour.nav.body, tour.nav.title (+10 more) - -### Community 668 - "Community 668" -Cohesion: 0.11 -Nodes (18): tags.adventure, tags.beginnerFriendly, tags.characterDriven, tags.classic, tags.commercial, tags.emotional, tags.epic, tags.fastPaced (+10 more) - -### Community 669 - "Community 669" -Cohesion: 0.11 -Nodes (18): tour.btn.done, tour.btn.next, tour.btn.prev, tour.help.startButton, tour.intro.body, tour.intro.title, tour.nav.body, tour.nav.title (+10 more) - -### Community 670 - "Community 670" -Cohesion: 0.11 -Nodes (18): tags.adventure, tags.beginnerFriendly, tags.characterDriven, tags.classic, tags.commercial, tags.emotional, tags.epic, tags.fastPaced (+10 more) - -### Community 671 - "Community 671" -Cohesion: 0.11 -Nodes (18): tour.btn.done, tour.btn.next, tour.btn.prev, tour.help.startButton, tour.intro.body, tour.intro.title, tour.nav.body, tour.nav.title (+10 more) - -### Community 672 - "Community 672" -Cohesion: 0.11 -Nodes (18): tags.adventure, tags.beginnerFriendly, tags.characterDriven, tags.classic, tags.commercial, tags.emotional, tags.epic, tags.fastPaced (+10 more) - -### Community 673 - "Community 673" -Cohesion: 0.11 -Nodes (18): tour.btn.done, tour.btn.next, tour.btn.prev, tour.help.startButton, tour.intro.body, tour.intro.title, tour.nav.body, tour.nav.title (+10 more) - -### Community 674 - "Community 674" -Cohesion: 0.11 -Nodes (18): author, description, engines, node, pnpm, keywords, lint-staged, .codegraph/** (+10 more) - -### Community 675 - "Community 675" -Cohesion: 0.11 -Nodes (19): 17. ~~Feature-Flag-System~~ βœ… FIXED, 18. Infinite Loop in codexService.extractStoryCodex βœ… FIXED (v1.1.2), 19. Modal Focus-Trap Cleanup Fragility βœ… FIXED (v1.1.2), 20. FOUC Theme Initialization βœ… FIXED (v1.1.2), 21. Untranslated FR/ES/IT Locales βœ… FIXED (v1.1.2), 22. CryptoKey Derived From Public Inputs βœ… FIXED (v1.2.0), 23. CSP img-src Too Permissive βœ… FIXED (v1.2.0), 24. Import JSON Without Schema Validation βœ… FIXED (v1.2.0) (+11 more) - -### Community 676 - "Community 676" -Cohesion: 0.11 -Nodes (17): desktop.menu.commandPalette, desktop.menu.edit, desktop.menu.export, desktop.menu.file, desktop.menu.help, desktop.menu.helpCenter, desktop.menu.settings, desktop.menu.view (+9 more) - -### Community 677 - "Community 677" -Cohesion: 0.11 -Nodes (17): desktop.menu.commandPalette, desktop.menu.edit, desktop.menu.export, desktop.menu.file, desktop.menu.help, desktop.menu.helpCenter, desktop.menu.settings, desktop.menu.view (+9 more) - -### Community 678 - "Community 678" -Cohesion: 0.11 -Nodes (17): 0. Status & when this runs, 0a. AI Review is NOT available on this account β€” do not trigger it, 10. Relationship to CodeAnt, 11. Observed behaviour log (append-only β€” keep this honest), 1. How DeepSource differs from the CodeAnt loop (read first), 2. The Iron Rule β€” loop until quiescent, 3. Fetch DeepSource findings from the CLI, 3a. Find and resolve DeepSource inline threads (+9 more) - -### Community 679 - "Community 679" -Cohesion: 0.11 -Nodes (17): A11y Sweep β€” `focus:ring` β†’ `focus-visible:ring` (WCAG 2.4.7), After CI is Green, Blank Screen Debug, Bug Fix: IDB At-Rest Encryption (4 root causes), CI Correction Loop (PRIORITY), Cloudflare Pages Deploy (pre-existing failure), Key Files Changed This Session, Open: Blank Screen on Live Demo (+9 more) - -### Community 680 - "Community 680" -Cohesion: 0.11 -Nodes (17): Data flow (read), Data flow (write), Encryption Per Store, Failure behavior, Implemented API, IndexedDB At-Rest Encryption β€” Implementation, Key Derivation, Migration Path (+9 more) - -### Community 681 - "Community 681" -Cohesion: 0.11 -Nodes (17): API Reference, Changelog, Executing a Plugin, Execution Timeout, Known Limitations, Overview, Permission Gating, Plugin System (Beta) (+9 more) - -### Community 682 - "Community 682" -Cohesion: 0.11 -Nodes (17): desktop.menu.commandPalette, desktop.menu.edit, desktop.menu.export, desktop.menu.file, desktop.menu.help, desktop.menu.helpCenter, desktop.menu.settings, desktop.menu.view (+9 more) - -### Community 683 - "Community 683" -Cohesion: 0.11 -Nodes (17): desktop.menu.commandPalette, desktop.menu.edit, desktop.menu.export, desktop.menu.file, desktop.menu.help, desktop.menu.helpCenter, desktop.menu.settings, desktop.menu.view (+9 more) - -### Community 684 - "Community 684" -Cohesion: 0.11 -Nodes (17): desktop.menu.commandPalette, desktop.menu.edit, desktop.menu.export, desktop.menu.file, desktop.menu.help, desktop.menu.helpCenter, desktop.menu.settings, desktop.menu.view (+9 more) - -### Community 685 - "Community 685" -Cohesion: 0.11 -Nodes (17): desktop.menu.commandPalette, desktop.menu.edit, desktop.menu.export, desktop.menu.file, desktop.menu.help, desktop.menu.helpCenter, desktop.menu.settings, desktop.menu.view (+9 more) - -### Community 686 - "Community 686" -Cohesion: 0.11 -Nodes (17): desktop.menu.commandPalette, desktop.menu.edit, desktop.menu.export, desktop.menu.file, desktop.menu.help, desktop.menu.helpCenter, desktop.menu.settings, desktop.menu.view (+9 more) - -### Community 687 - "Community 687" -Cohesion: 0.11 -Nodes (17): desktop.menu.commandPalette, desktop.menu.edit, desktop.menu.export, desktop.menu.file, desktop.menu.help, desktop.menu.helpCenter, desktop.menu.settings, desktop.menu.view (+9 more) - -### Community 688 - "Community 688" -Cohesion: 0.11 -Nodes (17): desktop.menu.commandPalette, desktop.menu.edit, desktop.menu.export, desktop.menu.file, desktop.menu.help, desktop.menu.helpCenter, desktop.menu.settings, desktop.menu.view (+9 more) - -### Community 689 - "Community 689" -Cohesion: 0.11 -Nodes (17): desktop.menu.commandPalette, desktop.menu.edit, desktop.menu.export, desktop.menu.file, desktop.menu.help, desktop.menu.helpCenter, desktop.menu.settings, desktop.menu.view (+9 more) - -### Community 690 - "Community 690" -Cohesion: 0.11 -Nodes (17): desktop.menu.commandPalette, desktop.menu.edit, desktop.menu.export, desktop.menu.file, desktop.menu.help, desktop.menu.helpCenter, desktop.menu.settings, desktop.menu.view (+9 more) - -### Community 691 - "Community 691" -Cohesion: 0.12 -Nodes (13): LocaleStatus, isRecord(), load(), tokens(), isRecord(), lines, load(), LOCALES_DIR (+5 more) - -### Community 692 - "Community 692" -Cohesion: 0.11 -Nodes (17): Aliases (from `bashrc-aliases.snippet`), Backup & Restore, Before commit / push (Forgejo), Caching, Close CI parity with act (on-demand, **evenings / before release**), Daily Driver β€” Low-End Local CI/CD, During development (standard, **without Docker**), Emergency RAM release (+9 more) - -### Community 693 - "Community 693" -Cohesion: 0.11 -Nodes (17): desktop.menu.commandPalette, desktop.menu.edit, desktop.menu.export, desktop.menu.file, desktop.menu.help, desktop.menu.helpCenter, desktop.menu.settings, desktop.menu.view (+9 more) - -### Community 694 - "Community 694" -Cohesion: 0.11 -Nodes (17): desktop.menu.commandPalette, desktop.menu.edit, desktop.menu.export, desktop.menu.file, desktop.menu.help, desktop.menu.helpCenter, desktop.menu.settings, desktop.menu.view (+9 more) - -### Community 695 - "Community 695" -Cohesion: 0.11 -Nodes (17): desktop.menu.commandPalette, desktop.menu.edit, desktop.menu.export, desktop.menu.file, desktop.menu.help, desktop.menu.helpCenter, desktop.menu.settings, desktop.menu.view (+9 more) - -### Community 696 - "Community 696" -Cohesion: 0.11 -Nodes (17): desktop.menu.commandPalette, desktop.menu.edit, desktop.menu.export, desktop.menu.file, desktop.menu.help, desktop.menu.helpCenter, desktop.menu.settings, desktop.menu.view (+9 more) - -### Community 697 - "Community 697" -Cohesion: 0.11 -Nodes (17): desktop.menu.commandPalette, desktop.menu.edit, desktop.menu.export, desktop.menu.file, desktop.menu.help, desktop.menu.helpCenter, desktop.menu.settings, desktop.menu.view (+9 more) - -### Community 698 - "Community 698" -Cohesion: 0.11 -Nodes (17): desktop.menu.commandPalette, desktop.menu.edit, desktop.menu.export, desktop.menu.file, desktop.menu.help, desktop.menu.helpCenter, desktop.menu.settings, desktop.menu.view (+9 more) - -### Community 699 - "Community 699" -Cohesion: 0.11 -Nodes (17): desktop.menu.commandPalette, desktop.menu.edit, desktop.menu.export, desktop.menu.file, desktop.menu.help, desktop.menu.helpCenter, desktop.menu.settings, desktop.menu.view (+9 more) - -### Community 700 - "Community 700" -Cohesion: 0.11 -Nodes (17): desktop.menu.commandPalette, desktop.menu.edit, desktop.menu.export, desktop.menu.file, desktop.menu.help, desktop.menu.helpCenter, desktop.menu.settings, desktop.menu.view (+9 more) - -### Community 701 - "Community 701" -Cohesion: 0.18 -Nodes (14): analyze_text(), count_sentences(), count_syllables(), counts_words_chars_and_spaces(), empty_text_is_all_zero(), flesch_score_is_finite_for_real_prose(), run_text_analyze(), RustTaskRequest (+6 more) - -### Community 702 - "Community 702" -Cohesion: 0.12 -Nodes (16): Baseline (pre-flight, before any code change), Node-only gates (cheap, run first), Post-close: merge + release (2026-07-29, later same day), WS-10 β€” Worker-generation duplication ADR, WS-11 β€” Re-audit + post-mortem close-out, WS-1 β€” CSP functional truth, WS-2 β€” CSP gate governance docs, WS-3 β€” Desktop key-derivation fix + doc truth-up (+8 more) - -### Community 703 - "Community 703" -Cohesion: 0.18 -Nodes (12): decrypt(), decryptJson(), encrypt(), encryptJson(), decrypt(), decryptJson(), deriveKey(), encrypt() (+4 more) - -### Community 704 - "Community 704" -Cohesion: 0.12 -Nodes (16): Bulk Locale Translation Guide, Community Contribution, Current Status (2026-06-07), Glossary overrides, Metrics Update Script, Option A: Google Cloud Translation API, Option B: DeepL API (Recommended for European languages), Post-Translation Checklist (+8 more) - -### Community 705 - "Community 705" -Cohesion: 0.12 -Nodes (16): Addendum β€” TypeScript strict-mode compliance sweep (same day, v1.18.1), Architecture changes, BaseAgent (`services/proForge/pipelineAgents/baseAgent.ts`) β€” NEW, Changes (47 files), Known open items (unchanged), listenerMiddleware.ts β€” `addDebouncedListener` factory, Next session priority, Quality gate at final push (+8 more) - -### Community 706 - "Community 706" -Cohesion: 0.29 -Nodes (6): Card, Default, meta, StatGrid, Story, Text - -### Community 707 - "Community 707" -Cohesion: 0.29 -Nodes (4): HarnessWindow, { mockSetVoiceSettings, mockPipeline, mockDispose, mockParse }, PrivateState, makeService() - -### Community 708 - "Community 708" -Cohesion: 0.12 -Nodes (16): 1. Sprache & Kommunikation, 2. Grundsatz: CI-Cloud-First, keine schwere lokale Last, 3.1 Threads abrufen, 3.2 Kommentare validieren & fixen, 3.3 Lokale QualitΓ€tsprΓΌfung, 3.4 Commit & Push, 3.5 Threads beantworten & schließen, 3.6 Re-Review triggern (+8 more) - -### Community 709 - "Community 709" -Cohesion: 0.19 -Nodes (16): collectSubtreeIds(), isHistoryPath(), main(), replaceFull(), replaceUrls(), walk(), __dirname, EXCLUDED_DIRS (+8 more) - -### Community 710 - "Community 710" -Cohesion: 0.12 -Nodes (14): collect(), baseline, baselinePath, byFile, byRule, __dirname, files, IGNORE_DIRS (+6 more) - -### Community 711 - "Community 711" -Cohesion: 0.12 -Nodes (15): After Code Changes, Before Commits, Daily Workflow, Dual-Graph Setup: Graphify + CodeGraph, Monorepo Structure in the Graphs, Philosophy: City Map + GPS, Privacy & Security, Prompt Templates for Kimi K2.6 (+7 more) - -### Community 712 - "Community 712" -Cohesion: 0.12 -Nodes (15): bin, proforge-mcp-server, dependencies, @modelcontextprotocol/sdk, description, devDependencies, tsx, name (+7 more) - -### Community 713 - "Community 713" -Cohesion: 0.13 -Nodes (14): dependencies, lib0, simple-peer, y-protocols, description, exports, main, name (+6 more) - -### Community 714 - "Community 714" -Cohesion: 0.13 -Nodes (14): 1. Corrected baseline (verified against live `main`, 2026-06-13), 2. Phase roadmap & status, 3. Batch log, 4. Decisions & follow-ups, 5. References, Batch 0.1 β€” Tracker reconciliation (PR #118, `e8252b6`+`6b3340d`), Batch 0.2 β€” Plugin sandbox adversarial validation (PR #118), Batch 1.1 β€” AI error taxonomy + fail-fast retry (Phase 1) (+6 more) - -### Community 715 - "Community 715" -Cohesion: 0.13 -Nodes (14): Bad example, CI quality gates, Code Quality Guide, Good example, Input validation for AI-generated content, Plugin sandboxing, Recommended local workflow before pushing, Rendering untrusted content (+6 more) - -### Community 716 - "Community 716" -Cohesion: 0.13 -Nodes (14): 0. When this runs β€” proactively, automatically, every PR, 1. The Iron Rule β€” loop until quiescent, 1a. Keep every PR under the ~100-file review limit (split when needed), 2. Fetch unresolved threads, 3. Validate, then fix or justify, 3a. Suppression ratchet β€” never add a new `biome-ignore`, 4. Local quality gate (low-end hardware β€” sequential, never parallel), 5. Commit & push (one wave = one commit) (+6 more) - -### Community 717 - "Community 717" -Cohesion: 0.13 -Nodes (14): 1. LanguageSelector Component (`components/ui/LanguageSelector.tsx`), βœ… 2026-06-06 Session β€” UI Modernization: LanguageSelector + RadioGroup + Tabs, 2. RadioGroup Component (`components/ui/RadioGroup.tsx`), 3. Tabs Component (`components/ui/Tabs.tsx`), 4. ToggleSwitch Fix (`components/settings/SettingsShared.tsx`), 5. i18n Key Additions, 6. Unit Tests, CI Status (at pause) (+6 more) - -### Community 718 - "Community 718" -Cohesion: 0.13 -Nodes (14): 1. DuckDB-WASM Analytics Layer (P0–P3), 2. Hybrid RAG β€” Wired End-to-End, 3. AI Provider Extensions, 4. Y-WebRTC E2E Encryption, 5. Performance, 6. i18n, 7. Quality Gate, Architecture (+6 more) - -### Community 719 - "Community 719" -Cohesion: 0.13 -Nodes (14): Chinese Simplified (zh), Common UI Verbs, Conventions, Core Domain Terms, Flags, Glossary expansion (v2.0), Greek (el), i18n Glossary β€” WorldScript Studio (+6 more) - -### Community 720 - "Community 720" -Cohesion: 0.13 -Nodes (14): Beat Sheet Presets, Components, Connection Types, Coordinate Systems, Drawing Connections, `features/plotBoard/plotBoardSlice.ts` β€” Ephemeral viewport / UI state, `features/project/projectSlice.ts` β€” Story content (undo-able), Key Constraints (+6 more) - -### Community 721 - "Community 721" -Cohesion: 0.13 -Nodes (14): 1. package.json, 2. Scripts, 3. tsconfig.tsgo.json, 4. CI Workflow (.github/workflows/ci.yml), Architecture, Changes Made, Configuration Files, Dual-Setup Pattern (+6 more) - -### Community 722 - "Community 722" -Cohesion: 0.13 -Nodes (14): 1. AI Execution Modes, 2. OpenRouter Provider, 3. Copilot v2, 4. Voice (Whisper WASM + Kokoro TTS), 5. PWA / Offline, 6. Core Paths, 7. Tauri Desktop Specific, 8. Security & Hardening (PR #114 β€” light manual checks) (+6 more) - -### Community 723 - "Community 723" -Cohesion: 0.17 -Nodes (12): stripComments(), stripToFixedPoint(), connectSrcLikeTokens(), group1(), indexCss, indexHtml, indexTsx, REQUIRED_IMPORT_PREFIXES (+4 more) - -### Community 724 - "Community 724" -Cohesion: 0.06 -Nodes (22): extractDedicatedUiFlags(), loadBundleKeys(), tauriCsp(), subscribeHeuristicFallback(), decompressData(), ALLOWLIST, CORE_LOCALES, en (+14 more) - -### Community 725 - "Community 725" -Cohesion: 0.13 -Nodes (14): πŸš€ A Creative Workflow, πŸ§ͺ CI & Local Validation, 🀝 Contributing, πŸ“š Documentation Hub, ⚠️ Legal Disclaimer, 🌐 Live Demo, πŸ’‘ Our Philosophy, πŸ“‚ Project Structure (+6 more) - -### Community 726 - "Community 726" -Cohesion: 0.13 -Nodes (15): [1.0.0] β€” 2025-01-01, Accessibility, Added, AI Integration (Google Gemini API), Collaboration, Core Application, Data Management, Desktop Application (+7 more) - -### Community 727 - "Community 727" -Cohesion: 0.13 -Nodes (6): AiInferenceCacheService, CacheEntry, hashKey(), LruEntry, AiInferenceCacheService, hashKey() - -### Community 728 - "Community 728" -Cohesion: 0.14 -Nodes (13): Base path matrix, Cloudflare Pages, Dashboard (recommended β€” no Wrangler in CI), Deployment β€” GitHub Pages, Vercel & Cloudflare Pages, GitHub Actions (optional), GitHub Pages (canonical upstream), Header invariants per host, Health check after push (+5 more) - -### Community 729 - "Community 729" -Cohesion: 0.17 -Nodes (11): Check, ChevronDown, Close, ErrorIcon, Info, meta, Microphone, Sizes (+3 more) - -### Community 730 - "Community 730" -Cohesion: 0.14 -Nodes (13): AI Thunk Utils (`features/project/aiThunkUtils.ts`), Architecture changes, Embedding Service (`services/ai/localEmbeddingService.ts`), Inference Worker (`workers/inference.worker.ts`), Known open items (unchanged from v1.17.1), Local AI Facade (`services/localAiFacade.ts`), Next session priority, No regressions introduced (+5 more) - -### Community 731 - "Community 731" -Cohesion: 0.14 -Nodes (13): Concrete next steps (do these in order), Environment reminders, βšͺ FOURTH β€” deferred native-desktop work (after the CodeAnt loop), πŸ”΄ (HISTORICAL) TOP PRIORITY β€” main CI is red and must go green before anything else, Leading hypothesis to confirm next session, βœ… RESOLVED 2026-06-20 β€” root cause was the undici override, fixed in commit `e2c73e93`, 🟑 SECOND β€” unmerged refactor branch `refactor/proforge-xstate-machine` (PR #180), Session Handoff β€” Main CI red (coverage collapse) + deferred CodeAnt loop (+5 more) - -### Community 732 - "Community 732" -Cohesion: 0.14 -Nodes (13): compilerOptions, allowImportingTsExtensions, esModuleInterop, lib, module, moduleResolution, noEmit, resolveJsonModule (+5 more) - -### Community 733 - "Community 733" -Cohesion: 0.13 -Nodes (16): CANDIDATE_PATHS, PORT, __dirname, LANG_CODES, main(), parseArgs(), ROOT, sleep() (+8 more) - -### Community 734 - "Community 734" -Cohesion: 0.15 -Nodes (12): AI Execution Mode β€” Audit, Perfection & OpenRouter, Carried over from v1.20.0, βœ… Completed (2026-06-11), Dependency-Hygiene Backlog (completed or superseded in v1.23), P0 β€” Release Unblock, P1 β€” AI Resilience & Core Reliability, P2 β€” Global Readiness & i18n, P3 β€” Architektur-Hardening & Performance (+4 more) - -### Community 735 - "Community 735" -Cohesion: 0.15 -Nodes (12): C-1 crypto.js findings, C-3 LoRA wiring scope, C-6 β€” RTL full translation (ar/he), C-7 β€” Coverage 85% / Branches 75% / Functions 80%, IDB at-rest encryption UX (C-SEC-5), Key decisions / fixes, PLANbib v1.7, Quality gate (at session end) (+4 more) - -### Community 736 - "Community 736" -Cohesion: 0.15 -Nodes (12): 14 CodeAnt AI Issues Fixed (commit `827a512`), CI/CD Infrastructure, CI Fixes (Priority 1), CI State at Handoff (2026-06-01 01:30 UTC+2), Commits in This Session, Docs (10 files updated), E2E Stabilisation: 24 Failures β†’ ~0, Open Items (carry forward) (+4 more) - -### Community 737 - "Community 737" -Cohesion: 0.20 -Nodes (9): Danger, Disabled, Ghost, Large, meta, Primary, Secondary, Small (+1 more) - -### Community 738 - "Community 738" -Cohesion: 0.15 -Nodes (12): characters, config, creativity, genrePreset, language, ragMode, logline, manuscript (+4 more) - -### Community 739 - "Community 739" -Cohesion: 0.15 -Nodes (12): 1. Correction, 2. Warning, 3. Temporary Ban, 4. Permanent Ban, Attribution, Contributor Covenant Code of Conduct, Enforcement, Enforcement Guidelines (+4 more) - -### Community 741 - "Community 741" -Cohesion: 0.18 -Nodes (10): DispatcherAction, isDispatcherAction(), isStreamGenerationThunk(), { mockAssembleRAGPrompt }, mockDispatch, mockState, StreamGenerationThunk, writerActions (+2 more) - -### Community 742 - "Community 742" -Cohesion: 0.21 -Nodes (11): makeAudioBuffer(), makeAudioContext(), makeMediaStream(), makeMediaStreamTrack(), mockPipelineFn, mockSamples, makeAudioBuffer(), makeAudioContext() (+3 more) - -### Community 743 - "Community 743" -Cohesion: 0.17 -Nodes (11): exports, main, name, optionalDependencies, @huggingface/transformers, @mlc-ai/web-llm, onnxruntime-web, private (+3 more) - -### Community 744 - "Community 744" -Cohesion: 0.33 -Nodes (5): mockDispatch, mockQueryDailyProgress, mockQuerySceneOverlaps, mockQueryStreak, mockQueryWeeklyProgress - -### Community 745 - "Community 745" -Cohesion: 0.17 -Nodes (5): appDataStore, fakeMixedDb, SnapshotRecord, snapshotStore, TestDbService - -### Community 746 - "Community 746" -Cohesion: 0.17 -Nodes (11): Architecture changes, B-1 β€” Storage Decomposition + Encryption Service, B-2 β€” WASM Voice Engine Scaffold, B-3 β€” collab-transport Vendor Fork, B-4 β€” Axe-Core E2E Gate, B-6 β€” StructuredLogger, Known issues to watch, Next session priorities (Phase 3) (+3 more) - -### Community 749 - "Community 749" -Cohesion: 0.17 -Nodes (11): 1. Locale inventory (SSOT: `i18n/locales.ts`), 2. LanguageTool reality β€” scaffold only, NOT a working grammar checker, 3. Editor seam for inline underlines (`components/manuscript/ManuscriptEditor.tsx`), 4. Existing docs / tooling to extend (do NOT duplicate), 5. **Verified LanguageTool support matrix** (dev.languagetool.org/languages, 2026-06-24), 6. Adjusted prioritization, 7. Tier elevation posture (honest, data-gated), 8. Risks / anti-patterns (and mitigations) (+3 more) - -### Community 750 - "Community 750" -Cohesion: 0.17 -Nodes (11): Hardware & browser requirements, Local AI β€” Setup & Troubleshooting, Model sizes (approximate on-disk), Ollama / LM Studio / vLLM servers (desktop only), Quick start, Related, Storage management, The fallback chain (+3 more) - -### Community 751 - "Community 751" -Cohesion: 0.17 -Nodes (11): Auto-update & signing, Build health & known blockers (2026-06-12), Build matrix, Desktop UX (v1.9), First-release checklist, GitHub Releases (tags only), Local parity, Outputs (+3 more) - -### Community 752 - "Community 752" -Cohesion: 0.17 -Nodes (11): 1. Architecture & build flow, 2. Placeholder & token rules (hard gate), 3. Tone & style by category, 4. Glossary usage, 5. RTL (`ar` / `he` / `fa`), 6. Per-language native-review checklist, 7. Common pitfalls, 8. Contribution workflow (new language or keys) (+3 more) - -### Community 753 - "Community 753" -Cohesion: 0.17 -Nodes (11): byRule, lint/a11y/useAriaPropsSupportedByRole, lint/a11y/useSemanticElements, lint/complexity/useArrowFunction, lint/correctness/noConstructorReturn, lint/correctness/noEmptyPattern, lint/correctness/useExhaustiveDependencies, lint/security/noDangerouslySetInnerHtml (+3 more) - -### Community 754 - "Community 754" -Cohesion: 0.17 -Nodes (5): FakeAudioContext, buildMocks(), FakeAudioContext, makeStt(), makeVad() - -### Community 756 - "Community 756" -Cohesion: 0.50 -Nodes (3): CloudSyncConfig, CloudSyncObjectMeta, BASE_CONFIG - -### Community 757 - "Community 757" -Cohesion: 0.18 -Nodes (10): Accessibility, Architecture (short), CI gates β€” cloud-first workflow, Content & copy, Internationalization, Plugin-style extensibility (lightweight), RTL & future locales, Security & privacy (product-facing) (+2 more) - -### Community 758 - "Community 758" -Cohesion: 0.18 -Nodes (10): Component authoring rules, Contrast compliance (WCAG 2.2), ⚠️ DEPRECATED bridge variables, Helper UI primitives, Principles, Semantic tokens (overview), Storybook, Tailwind v4 (+2 more) - -### Community 759 - "Community 759" -Cohesion: 0.18 -Nodes (10): Adding a custom rule, Heuristic Rules Reference, `high-repetition` β€” HighRepetitionRule, `missing-world-context` β€” MissingWorldContextRule, `open-loop` β€” OpenLoopRule, `overlength-scene` β€” OverlengthSceneRule, `plot-hole` β€” PlotHoleRule, `slow-pacing` β€” SlowPacingRule (+2 more) - -### Community 760 - "Community 760" -Cohesion: 0.18 -Nodes (10): 0. What is already DONE (merged to `main`, 2026-06-24/25), 1. Workstream A β€” add 5 new UI locales (one stacked PR each), 2. Closing / locale-dependent docs (after the 5 locales land), 3. Verification (whole tail), 4. Gotchas (learned this program β€” apply on resume), Deferred (do NOT add now β†’ ROADMAP only), Glossary, Per-locale recipe (reuse the existing pipeline β€” do NOT hand-roll) (+2 more) - -### Community 761 - "Community 761" -Cohesion: 0.20 -Nodes (9): ADR 0007 β€” Plugin Sandbox Model, Alternatives Considered, Consequences, Context, Decision, Negative / Trade-offs, Positive, Related Files (+1 more) - -### Community 762 - "Community 762" -Cohesion: 0.20 -Nodes (9): ADR 0016 β€” Native Grok provider + split Claude fix (desktop native-HTTP, web serverless proxy), Claude β€” two independent tracks, not one, Consequences, Context, Decision, Grok β€” native UI wiring (no new architecture), Ollama-in-PWA (adjacent follow-up, Issue #266, not part of this decision's core scope), References (+1 more) - -### Community 763 - "Community 763" -Cohesion: 0.20 -Nodes (9): 1. [High] MCP memory bank re-seeds on every request β†’ duplicate RAG results + unbounded growth, 2. [High] Copilot can get stuck in `streaming` when the panel is closed mid-response, 3. [Medium] MCP server crashes at import time on a bad `--project` file (bypasses startup error handling), 4. [Medium] Empty-string `runId` silently returns the most-recent run instead of erroring, 5. [Medium] Disabling the `enableGlobalCopilot` flag doesn't end the active session, 6. [Low–Medium] MCP error responses / startup log forward raw `err` text, ProForge MCP + Global Copilot β€” Follow-up Backlog (CodeAnt PR #107), Quick triage table (+1 more) - -### Community 764 - "Community 764" -Cohesion: 0.20 -Nodes (9): files, includes, maxSize, overrides, $schema, vcs, clientKind, enabled (+1 more) - -### Community 765 - "Community 765" -Cohesion: 0.20 -Nodes (9): Apply to chapter, Architecture overview, Chatting with the Copilot, Enabling, Global AI Copilot, Heuristics-Only mode, Opening the panel, Proactive insights (+1 more) - -### Community 766 - "Community 766" -Cohesion: 0.20 -Nodes (9): Changes, DS-1 β€” Undefined bridge variable sweep, DS-2 β€” `dark:` prefix elimination (100% complete), DS-5 Readiness, HK-4 β€” displayName additions, SB-1 β€” Storybook coverage (5 missing stories added), Sprint v1.16 β€” Design System Completion (DS-1 / DS-2 / SB-1 / HK-4), Summary (+1 more) - -### Community 767 - "Community 767" -Cohesion: 0.20 -Nodes (9): Conventions established in T0–T2 (reuse these), Deferred: dynamic Recent Projects (own PR, prerequisite for menu/tray Recent submenu), Definition of done (whole initiative), T3 β€” Native notifications (PR), T4 β€” First-class updater modal (PR), T5 β€” Pandoc UX + LoRA run-scoped abort (PR), T6 β€” Global shortcuts + Rust-compute expansion (PR), T7 β€” Native theme sync + Flow-Mode fullscreen + docs (PR) (+1 more) - -### Community 768 - "Community 768" -Cohesion: 0.40 -Nodes (4): Dashboard(), baseContextValue, baseProjectData, mockOnNavigate - -### Community 769 - "Community 769" -Cohesion: 0.20 -Nodes (9): Architecture, Claude Desktop (`claude_desktop_config.json`), Client configuration, Cline / Cursor / generic `mcpServers`, Environment, ProForge MCP Server, Run, Tools (+1 more) - -### Community 770 - "Community 770" -Cohesion: 0.20 -Nodes (9): dependencies, zod, exports, main, name, private, type, types (+1 more) - -### Community 771 - "Community 771" -Cohesion: 0.20 -Nodes (9): buildCommand, framework, github, silent, headers, installCommand, outputDirectory, rewrites (+1 more) - -### Community 772 - "Community 772" -Cohesion: 0.20 -Nodes (10): Copilot Apply-Flow Hardening (P1), Error Handling & Observability, Mutation Testing Expansion (P1), OpenRouter Provider Hardening (P1), P0/P1 Implementation β€” 2026-06-12, Plugin System Hardening (P0), Supply-Chain Hardening (P1), Tauri Build Pipeline (+2 more) - -### Community 773 - "Community 773" -Cohesion: 0.20 -Nodes (10): noUnusedImports, noUnusedVariables, rules, correctness, preset, security, style, noDangerouslySetInnerHtml (+2 more) - -### Community 774 - "Community 774" -Cohesion: 0.22 -Nodes (8): ADR 0002 β€” Local-AI stack layering and fallback chain, Consequences, Context, Decision, Honest degradation contract, Layered fallback chain (most β†’ least capable, capability-gated at runtime), References, Shared infrastructure (cross-cutting, not per-layer) - -### Community 775 - "Community 775" -Cohesion: 0.22 -Nodes (8): ADR 0003 β€” WorkerBus v2 hybrid routing and the Rust TaskSupervisor, Consequences, Context, Decision, Honest-failure contract, Layers, References, Rejected alternatives - -### Community 776 - "Community 776" -Cohesion: 0.22 -Nodes (8): ADR 0012 β€” Local AI server connectivity: route localhost HTTP through the Tauri HTTP plugin (web stays fetch), Alternatives considered, Consequences, Context, Decision, Root cause analysis, Update (2026-07-28): build-pipeline gap left the desktop path broken in packaged builds, Update (2026-07-30): decision #4 (PWA stays strictly desktop-only) narrowly widened by 0017 - -### Community 777 - "Community 777" -Cohesion: 0.22 -Nodes (8): ADR 0013 β€” CSP `'wasm-unsafe-eval'` and `frame-src blob:`, Alternatives rejected, Consequences, Context, Decision, Does this weaken the plugin sandbox?, One accepted, narrowly-scoped exception, References - -### Community 778 - "Community 778" -Cohesion: 0.22 -Nodes (8): Housekeeping findings (fixed in this audit), Invariant guard, Method, Next audit trigger, Result: fork matches upstream except for the three documented SC patches, `src/crypto.js` (3 intentional deviations), `src/y-webrtc.js` (1 intentional deviation, 3 call sites), Vendor-Fork Audit β€” `@domain/collab-transport` (y-webrtc) - -### Community 779 - "Community 779" -Cohesion: 0.22 -Nodes (8): Accessibility (WorldScript Studio), Architecture, Automated Checks, Component ARIA Patterns, Global, i18n, Manual Checks, v1.6 Additions (Plot-Board v2, Reference Panel, Progress Tracker) - -### Community 780 - "Community 780" -Cohesion: 0.22 -Nodes (8): 0. Prerequisites, 1. Register the locale (the only metadata edit), 2. Scaffold content, 3. Translate (machine-translation pass), 4. Gate locally (sequential β€” low-end hardware), 5. Smoke + ship, 6. Elevate quality (later), Adding a New Language β€” Playbook - -### Community 781 - "Community 781" -Cohesion: 0.22 -Nodes (8): CJK Note, Example: Character Sorting, i18n β€” Intl.Collator (ICU Sorting), Overview, Supported Locales, UI Integration Points, Usage, Writing-App Defaults - -### Community 782 - "Community 782" -Cohesion: 0.22 -Nodes (8): Example: Language Selector, Fallback Behavior, i18n β€” Intl.DisplayNames, Overview, Supported Locales, Supported Types, UI Integration Points, Usage - -### Community 783 - "Community 783" -Cohesion: 0.22 -Nodes (8): CJK Note, Example: Character Relationships, i18n β€” Intl.ListFormat, Options, Overview, Supported Locales, UI Integration Points, Usage - -### Community 784 - "Community 784" -Cohesion: 0.22 -Nodes (8): Charts, i18n Keys, Overview, Progress Tracker β€” Architecture & Reference, Session Keyboard Shortcut, Session Lifecycle, State Architecture, Streak Algorithm - -### Community 785 - "Community 785" -Cohesion: 0.40 -Nodes (4): Default, meta, Primary, Story - -### Community 786 - "Community 786" -Cohesion: 0.40 -Nodes (4): Default, Large, meta, Story - -### Community 787 - "Community 787" -Cohesion: 0.22 -Nodes (8): CI Audit β€” WorldScript Studio, Local reproduction (quick vs heavy), Next steps (maintainer), Risk register (open / monitor), Security jobs (already in `ci.yml`), Stabilizations applied (Audit 2026-05), Toolchain (local ↔ CI parity), Workflow inventory - -### Community 788 - "Community 788" -Cohesion: 0.22 -Nodes (6): common.sh script, ACT_CACHE_DIR, CI_LOG_DIR, FORGEJO_COMPOSE, PNPM_STORE_DIR, WORLDSCRIPT_CI_HOME - -### Community 789 - "Community 789" -Cohesion: 0.22 -Nodes (8): exports, ./tailwind-preset, main, name, private, type, types, version - -### Community 790 - "Community 790" -Cohesion: 0.42 -Nodes (6): emit(), main(), merge(), ProgressCallback, Emits JSON progress events on each training log step., train() - -### Community 791 - "Community 791" -Cohesion: 0.25 -Nodes (7): ADR 0015 β€” Worker-generation consolidation: v1 retired, WorkerBus v2 is the sole generation, Consequences, Context, Decision, Deliberately not changed, Parity gaps found and fixed before cutover (not assumed away), References - -### Community 792 - "Community 792" -Cohesion: 0.25 -Nodes (7): Adding a new operation, Files, Layering rule (do not break), ProForge Dual-Purpose Architecture β€” Maintainer Guide, The three layers, Trust levels, Verification - -### Community 793 - "Community 793" -Cohesion: 0.25 -Nodes (7): Drift Summary (2026-06-21 β€” v1.24 post-release: ProForge opt-in + catalog defaultOn derived), Feature Parity Matrix, Fix Roadmap, Legend, 🟑 Remaining Minor Partial Wiring, βœ… Resolved Drifts (2026-05-29 parity audit), WorldScript Studio β€” Feature Parity Matrix - -### Community 794 - "Community 794" -Cohesion: 0.25 -Nodes (7): Key architectural facts for next session, Master plan, Next immediate task: DB-1, Phase 1 backlog (after DB-1), Quality gate reminder, Sprint Handoff β€” 2026-05-22, What was completed today - -### Community 795 - "Community 795" -Cohesion: 0.25 -Nodes (7): CI, New files added this sprint (Phase 2), Notable architectural decisions, Quality gate at final push, Sprint Handoff β€” 2026-05-23, v2.0 Master Plan β€” ALL PHASES DONE, What's open for v2.1+ - -### Community 796 - "Community 796" -Cohesion: 0.25 -Nodes (7): Known open items (intentionally deferred to v2.x), Next session priority, No outstanding TODOs or FIXMEs in source, Quality gate at final push, Repository health, Sprint Handoff β€” 2026-05-24, What was completed today - -### Community 797 - "Community 797" -Cohesion: 0.25 -Nodes (7): Architecture (lazy loading), Goals, Help Center, Settings, StoryCraft Studio v1.9 β€” Sprint Notes, Tauri desktop, Verification - -### Community 798 - "Community 798" -Cohesion: 0.25 -Nodes (7): BCP47 Compatibility, Font Script Mapping, i18n β€” Intl.Locale API, Language Switch Logic, Overview, Supported Locales, Usage - -### Community 799 - "Community 799" -Cohesion: 0.25 -Nodes (6): Examples in UI, i18n β€” Intl.NumberFormat, Overview, Supported Locales, Usage, Writing-App Defaults - -### Community 800 - "Community 800" -Cohesion: 0.25 -Nodes (7): CJK Note, Example: Days Left, i18n β€” CLDR Plural Rules, Implementation Notes, Overview, Supported Languages, Usage - -### Community 801 - "Community 801" -Cohesion: 0.25 -Nodes (7): Example, i18n β€” Intl.RelativeTimeFormat, Options, Overview, Supported Locales, UI Integration Points, Usage - -### Community 802 - "Community 802" -Cohesion: 0.25 -Nodes (7): Glossary, Language Expansion 2026 β€” +6 Locales (fi, sv, hu, is, eu, fa), Layout watch-list (long-compound languages), RTL (`fa`) notes, Running the bulk translator (glossary-first, placeholder-masked, resumable), What shipped vs. what's machine-pending, Why these six - -### Community 803 - "Community 803" -Cohesion: 0.25 -Nodes (7): 1. What you get, 2. Privacy model (why self-hosted only), 3. Setup β€” run a local server, 4. Language coverage, 5. Architecture, 6. Limitations & future work, LanguageTool grammar & spelling integration - -### Community 804 - "Community 804" -Cohesion: 0.25 -Nodes (7): Code signing (Windows / macOS), Enable updates for end users, GitHub Secrets checklist, macOS code signing & notarization, Required for all platforms, Tauri auto-update & signing (v1.2.1+), Windows Authenticode signing (optional) - -### Community 805 - "Community 805" -Cohesion: 0.25 -Nodes (7): Disclosure and Embargo Policy, Known Active Security Work Items, Reporting a Vulnerability, Scope, Security Policy, Supported Versions, Threat Model - -### Community 806 - "Community 806" -Cohesion: 0.04 -Nodes (47): WorkerBus, createCancelMessage(), createPongMessage(), createResultMessage(), isCancelMessage(), isPingMessage(), isTaskMessage(), validateWorkerMessage() (+39 more) - -### Community 808 - "Community 808" -Cohesion: 0.25 -Nodes (8): Critical Findings (P0 β€” must fix before v1.20), Environment Fix, Follow-up Audit β€” 2026-05-31 (Phase 0 β€” Edge-AI Performance Audit), Important Findings (P1 β€” should fix in v1.20), Next Steps, Performance / Benchmark Gaps, Quality Gate Status (Phase 0 baseline), Status Reconciliation β€” verified in code 2026-06-02 - -### Community 809 - "Community 809" -Cohesion: 0.25 -Nodes (8): noLabelWithoutControl, noSvgWithoutTitle, useAriaPropsForRole, useAriaPropsSupportedByRole, useButtonType, useKeyWithClickEvents, useSemanticElements, a11y - -### Community 810 - "Community 810" -Cohesion: 0.25 -Nodes (8): noExcessiveCognitiveComplexity, noForEach, useLiteralKeys, useOptionalChain, level, options, maxAllowedComplexity, complexity - -### Community 811 - "Community 811" -Cohesion: 0.29 -Nodes (6): ADR 0004 β€” CSP `connect-src` and the BYOK `https:` tradeoff, Consequences, Context, Decision, References, Rejected alternatives - -### Community 812 - "Community 812" -Cohesion: 0.29 -Nodes (6): ADR 0005 β€” WebLLM inference offloaded to a dedicated WorkerBus v2 pool, Consequences, Context, Decision, References, Rejected alternatives - -### Community 813 - "Community 813" -Cohesion: 0.29 -Nodes (6): ADR 0010 β€” Self-hosted LanguageTool grammar checking via the editor overlay, Alternatives considered, Consequences, Context, CSP gap (fixed 2026-07-29, F-08 β€” broader than originally scoped), Decision - -### Community 814 - "Community 814" -Cohesion: 0.29 -Nodes (6): Baseline, Correction-loop findings (CodeRabbit), all confirmed real and fixed before merge, Execution β€” 4 stacked PRs, Final verification (this doc's own sprint, PR #291 β€” docs cleanup), Known, deliberately unresolved, WS Run Log β€” 2026-07-29 Worker-Generation Consolidation Sprint - -### Community 815 - "Community 815" -Cohesion: 0.29 -Nodes (6): A0.1 β€” Large-Manuscript Performance Harness, Recording & comparing baselines, Run it, Tuning the fixture, What each bench means, Why this exists - -### Community 816 - "Community 816" -Cohesion: 0.29 -Nodes (6): Coverage Ratchet Policy, Current state (2026-06-09), Deferred patch-coverage follow-ups, Procedure for the next ratchet, The rule, Why this exists - -### Community 817 - "Community 817" -Cohesion: 0.29 -Nodes (6): Code-derived findings (D0 β€” to confirm in the visual pass), Confirmed-good (no action), Desktop (Tauri) UI/UX Audit & Remediation Tracker, How desktop styling is scoped, Visual-pass findings (filled by the human screenshot pass), Visual pass β€” screenshot matrix (human, per OS) - -### Community 818 - "Community 818" -Cohesion: 0.29 -Nodes (6): Critical (πŸ”΄) β€” All Completed, High (🟑) β€” All Completed, Low (🟒) β€” Completed Items, Medium (🟠) β€” Completed Items, Post-v1.1 Hardening Batch (2026-04-18), StoryCraft Studio β€” Completed Tasks (v1.1 Cycle) - -### Community 819 - "Community 819" -Cohesion: 0.29 -Nodes (6): Beta Quality Audit, Feasibility without native review, Findings (2026-06), Honest limits, Method, Why promotion is conservative (not raw-coverage-driven) - -### Community 820 - "Community 820" -Cohesion: 0.29 -Nodes (6): Deferred (roadmap, not this program), i18n Program β€” Implementation Log, PR1 β€” Infrastructure, SSOT & audit (in progress), PR2 β€” Russian (`ru`) Β· in review, PR3 β€” Korean (`ko`) Β· in review, PR4 β€” Beta-to-Production elevation Β· in review - -### Community 821 - "Community 821" -Cohesion: 0.29 -Nodes (6): Install UX (optional), Local verification, Manifest ([public/manifest.json](../public/manifest.json)), PWA Audit β€” WorldScript Studio (v1.8), Runtime ([App.tsx](../App.tsx)), Service Worker ([public/sw.js](../public/sw.js)) - -### Community 822 - "Community 822" -Cohesion: 0.29 -Nodes (6): 9. Voice Feedback Strategies βœ… v1.0, Appendix: Recommended npm stack 2026, Executive Summary + Vision, Intelligent feedback, Non-intrusive, WorldScript Studio β€” Voice Full Support (opt-in) Master Plan v1.0 - -### Community 823 - "Community 823" -Cohesion: 0.29 -Nodes (7): Implementation Roadmap, Phase 1: Foundation βœ… COMPLETED (2026-05-24), Phase 2: Core WASM Engines (2026-05-31 Local AI Perfection β€” complete) βœ…, Phase 3: Model Download UI (v1.21, 2026-06-09) βœ… COMPLETE, Phase 4: Advanced NLU (v1.2), Phase 5: Deep App Integration (v1.2), Phase 6: Polish & Testing (v1.2) - -### Community 824 - "Community 824" -Cohesion: 0.29 -Nodes (6): Further reference, GitHub Actions β€” Optimization History, Goal, Overview table (historical target values), Permissions (guiding principle), Secrets - -### Community 825 - "Community 825" -Cohesion: 0.29 -Nodes (6): dependencyDashboard, extends, packageRules, prConcurrentLimit, prHourlyLimit, $schema - -### Community 826 - "Community 826" -Cohesion: 0.67 -Nodes (3): check(), green(), red() - -### Community 827 - "Community 827" -Cohesion: 0.29 -Nodes (6): ko, _meta, description, languages, lastUpdated, version - -### Community 829 - "Community 829" -Cohesion: 0.29 -Nodes (6): Audit automation, Audit log, CVE / advisory monitoring (audit finding F-7), `packages/collab-transport` (y-webrtc fork), `patches/y-webrtc@10.3.0.patch`, Vendor Forks β€” Maintenance Log - -### Community 830 - "Community 830" -Cohesion: 0.29 -Nodes (7): 10. ~~Device-Scoped Encryption Key~~ βœ… FIXED, 5. ~~Minimal Test Coverage~~ βœ… IMPROVED, 6. ~~`any` Type Casts in Multiple Hooks~~ βœ… PARTIALLY FIXED, 7. ~~Logger Middleware Performance in Dev~~ βœ… FIXED, 8. ~~No Per-View Error Boundaries~~ βœ… FIXED, 9. ~~P2P Collaboration Without Encryption~~ βœ… IMPROVED, High Priority Findings (🟑) - -### Community 831 - "Community 831" -Cohesion: 0.29 -Nodes (7): AI Local Inference Stack, Collaboration Encryption, Cross-Project-Search v2, Documentation, Follow-up Audit β€” 2026-05-18 (Master-Perfection-Plan v1.5 β€” Tasks 1–5), Tauri Release Pipeline, Testing - -### Community 832 - "Community 832" -Cohesion: 0.29 -Nodes (7): Critical Findings (Baseline), Executive Summary (Baseline), High-Priority Findings (Baseline), Historical Baseline Audit (2026-04-15), Low-Priority Findings (Baseline), Medium-Priority Findings (Baseline), Remediation Steps Applied Post-Baseline - -### Community 833 - "Community 833" -Cohesion: 0.29 -Nodes (7): css, linter, parser, linter, enabled, cssModules, tailwindDirectives - -### Community 834 - "Community 834" -Cohesion: 0.29 -Nodes (7): level, options, allow, suspicious, noArrayIndexKey, noConsole, noExplicitAny - -### Community 835 - "Community 835" -Cohesion: 0.29 -Nodes (7): 🌐 Custom Domain Setup, πŸš€ Deploying to GitHub Pages, ☁️ Deploying to Vercel (alternative), Getting Started, πŸ’» Local Development, Prerequisites, πŸ›  Troubleshooting - -### Community 836 - "Community 836" -Cohesion: 0.33 -Nodes (5): ADR 0001 β€” State-management boundaries: Redux Toolkit vs Zustand, Consequences, Context, Decision, References - -### Community 837 - "Community 837" -Cohesion: 0.33 -Nodes (5): ADR 0006 β€” (reserved, never issued), Consequences, Context, Decision, Status - -### Community 838 - "Community 838" -Cohesion: 0.33 -Nodes (5): ADR 0008 β€” Local-first data model: Yjs document as source of truth, Consequences, Context, Decision, References - -### Community 839 - "Community 839" -Cohesion: 0.33 -Nodes (5): ADR 0009 β€” XState for complex workflow orchestration (Redux + RTK Query + XState), Consequences, Context, Decision, References - -### Community 840 - "Community 840" -Cohesion: 0.33 -Nodes (5): ADR 0011 β€” AI heuristic fallbacks via a registry + provider-layer seam (no orchestrator class), Alternatives considered, Consequences, Context, Decision - -### Community 841 - "Community 841" -Cohesion: 0.33 -Nodes (5): ADR 0014 β€” Two live worker generations (v1 and WorkerBus v2), Consequences, Context, Decision, References - -### Community 842 - "Community 842" -Cohesion: 0.33 -Nodes (5): ADR 0017 β€” Opt-in direct browserβ†’Ollama connection in the web/PWA build, Consequences, Context, Decision, References - -### Community 843 - "Community 843" -Cohesion: 0.33 -Nodes (5): description, identifier, permissions, $schema, windows - -### Community 844 - "Community 844" +### Community 14 - "proForgeCapabilityLayer.ts" Cohesion: 0.05 -Nodes (44): main(), clearServiceWorkerCaches(), deleteAllIndexedDBDatabases(), runWipe(), wipeAllAppData(), useTTS(), formatArgs(), formatLogsForReport() (+36 more) - -### Community 845 - "Community 845" -Cohesion: 0.33 -Nodes (5): Adding a new generator, AI heuristic fallbacks, Covered features, How it works, Verifying manually - -### Community 846 - "Community 846" -Cohesion: 0.33 -Nodes (5): 1. RAG prompt assembly, 2. DuckDB 384-dim migration, 3. Tests, 4. Related docs, Sprint Reference β€” v1.8 RAG Prompt Assembly + UX - -### Community 847 - "Community 847" -Cohesion: 0.33 -Nodes (5): 1. Current state (as audited), 2. Gaps found, 3. What this program does, 4. Risks, i18n Audit & Improvement Plan - -### Community 848 - "Community 848" -Cohesion: 0.33 -Nodes (5): Beta β†’ Production Playbook, Raising a Beta locale toward Near-Production, Reaching Production, Tiers (the `status` field in `i18n/locales.ts`), What stays English by design - -### Community 849 - "Community 849" -Cohesion: 0.33 -Nodes (5): Common UI verbs / chrome, Conventions, Core domain terms, i18n Glossary β€” Arabic (ar) & Hebrew (he) RTL Beta, Scope note - -### Community 850 - "Community 850" -Cohesion: 0.33 -Nodes (5): Cold-start project titles (`initialProject.*`), GitHub β€œLanguages” bar, i18n runtime vs repo layout, Performance (solo), Repository housekeeping - -### Community 851 - "Community 851" -Cohesion: 0.33 -Nodes (5): Done-when, Iterative refinement (only if verification fails), ⚠️ Manual verification needed (do locally before relying on it), TODO β€” verify the PDF-iframe `sandbox` hardening (DeepSource JS-D010), What changed - -### Community 852 - "Community 852" -Cohesion: 0.33 -Nodes (6): 11. Full Control of All App Areas by Voice βœ… v1.0, AI features, Editor / Writing, Navigation, Plot Board, Settings - -### Community 853 - "Community 853" -Cohesion: 0.33 -Nodes (5): 1. ProForge pipeline β€” **implemented** (additive; live wiring behind `enableProForgeXState`), 2. Voice pipeline β€” **design only** (deferred), 3. Global Copilot session β€” **design only** (deferred), Testing pattern, XState machines - -### Community 854 - "Community 854" -Cohesion: 0.67 -Nodes (3): extractCatalogFlags(), extractHiddenFlags(), extractSectionFlags() - -### Community 855 - "Community 855" -Cohesion: 0.67 -Nodes (3): extractCatalogFlags(), extractHiddenFlags(), extractSectionFlags() - -### Community 856 - "Community 856" -Cohesion: 0.67 -Nodes (3): [1.5.0] β€” 2026-05-18, Added (v1.5 Master Perfection Run), Changed - -### Community 857 - "Community 857" -Cohesion: 0.33 -Nodes (5): Code of Conduct, Contributing to WorldScript Studio, Development Setup, How to Contribute, Security - -### Community 858 - "Community 858" -Cohesion: 0.33 -Nodes (5): Cross-project & backup, LanguageTool Integration, Local inference, Plugin System, Scene-level services - -### Community 859 - "Community 859" -Cohesion: 0.33 -Nodes (6): 11. ~~No DevContainer Configuration~~ βœ… FIXED, 12. ~~Redundant `deploy.yml` Workflow~~ βœ… FIXED, 13. ~~Version Mismatch: Tauri vs npm~~ βœ… FIXED, 15. ~~No Performance Budgets~~ βœ… FIXED, 16. ~~Potential Memory Leaks in ManuscriptView Resize~~ βœ… FIXED, Medium Priority Findings (🟠) - -### Community 860 - "Community 860" -Cohesion: 0.33 -Nodes (6): 17. No Feature Flags, 18. Console Logging Instead of Logging Framework, 19. ~~Storybook Has Only 3 Stories~~ βœ… FIXED, 20. No Request Deduplication for AI Calls, 21. ~~Render-Blocking Google Fonts `@import`~~ βœ… FIXED, Low Priority Findings (🟒) - -### Community 861 - "Community 861" -Cohesion: 0.33 -Nodes (6): AI, sync, and security, Architecture and platform, CI and verification, Follow-up Audit β€” 2026-05-06 (architecture stack), Residual risks / next audit targets, Storage and integrity - -### Community 862 - "Community 862" -Cohesion: 0.33 -Nodes (6): Documentation, ErrorBoundary Refactored, Follow-up Audit β€” 2026-05-18 Session 2 (i18n Comprehensive Sweep + TypeScript Hardening), i18n β€” All Hardcoded Strings Eliminated, Test Quality, TypeScript 6 Strict Fixes - -### Community 863 - "Community 863" -Cohesion: 0.33 -Nodes (6): formatter, formatter, enabled, indentStyle, indentWidth, lineWidth - -### Community 864 - "Community 864" -Cohesion: 0.33 -Nodes (6): [1.24.1] β€” 2026-07-28, Added, Changed, Fixed, Removed, Security - -### Community 865 - "Community 865" -Cohesion: 0.33 -Nodes (6): [1.25.0] β€” 2026-07-31, Added, Docs, Fixed, Security, Tests - -### Community 866 - "Community 866" -Cohesion: 0.40 -Nodes (4): Architecture, Global AI Copilot β€” Implementation Plan, Privacy & safety, Tasks - -### Community 867 - "Community 867" -Cohesion: 0.40 -Nodes (4): Backend, Current Status, Notes, Planned Components - -### Community 868 - "Community 868" -Cohesion: 0.40 -Nodes (4): Goals, Post-release, Sprint v1.10 β€” Mobile UX, Coverage 55 %, Deploy & Help, Validation - -### Community 869 - "Community 869" -Cohesion: 0.40 -Nodes (4): Goals, Key Files Changed, Sprint v1.11 β€” Stabilization: Deploy Fix, StorageBackend Resilience, Help Center Complete, Validation - -### Community 870 - "Community 870" -Cohesion: 0.40 -Nodes (4): Out of scope, Scope, Sprint v1.23 β€” Stabilisation & Verification (SCOPING STUB), Validation (per item, before merge) - -### Community 871 - "Community 871" -Cohesion: 0.40 -Nodes (4): Per-locale, Review & Elevation Log, Tiers, Translation Status Dashboard - -### Community 872 - "Community 872" -Cohesion: 0.40 -Nodes (5): 13. Privacy, Security, Offline-First, Performance βœ… v1.0, Offline-first βœ… v1.0, Performance βœ… v1.0, Privacy, Security - -### Community 873 - "Community 873" -Cohesion: 0.40 -Nodes (5): 15. Testing-Strategie βœ… v1.0, Accessibility Tests (v1.1), E2E Tests (Playwright) (v1.1), Integration Tests (v1.1), Unit Tests (Vitest) βœ… v1.0 - -### Community 874 - "Community 874" -Cohesion: 0.40 -Nodes (5): 2. Wake-Word, VAD, Continuous Listening & Microphone Handling, Continuous Listening βœ… v1.0, Microphone Handling βœ… v1.0, VAD βœ… v1.0, Wake-Word βœ… v1.0 - -### Community 876 - "Community 876" -Cohesion: 0.40 -Nodes (5): 1. ~~Hardcoded Language in AI Hooks~~ βœ… FIXED, 2. ~~Tauri CSP is `null` β€” No Content Security Policy~~ βœ… FIXED, 3. ~~No Request Cancellation for AI Thunks~~ βœ… FIXED, 4. ~~Auto-Save Memory Exhaustion Risk~~ βœ… FIXED, Critical Findings (πŸ”΄) - -### Community 877 - "Community 877" -Cohesion: 0.40 -Nodes (5): Biome (lint + format), CI/CD Pipeline, Environment & Configuration Findings, Git Configuration, Package.json - -### Community 878 - "Community 878" -Cohesion: 0.40 -Nodes (5): Code fix (AI provider), Documentation & DX alignment, Follow-up β€” 2026-05-02 (storage + welcome), Follow-up Audit β€” 2026-05-02, Outstanding - -### Community 879 - "Community 879" -Cohesion: 0.40 -Nodes (5): Edge-AI Perfection Cycle β€” 2026-05-31 (Phases 0–7 Complete), Known-debt items resolved, New files (Edge-AI Cycle), Phase-by-Phase Summary, WGSL shaders (all ?raw bundled) - -### Community 880 - "Community 880" -Cohesion: 0.40 -Nodes (5): source, assist, actions, enabled, organizeImports - -### Community 881 - "Community 881" -Cohesion: 0.40 -Nodes (5): quoteStyle, semicolons, trailingCommas, javascript, formatter - -### Community 882 - "Community 882" -Cohesion: 0.40 -Nodes (5): [1.1.0] β€” 2026-04-16, Added, Changed, Fixed, Security - -### Community 883 - "Community 883" -Cohesion: 0.40 -Nodes (5): [1.1.1] β€” 2026-04-17, Added, Changed, Fixed, Security - -### Community 884 - "Community 884" -Cohesion: 0.40 -Nodes (5): [1.20.0] β€” 2026-06-07, Added, Added, Fixed, Security - -### Community 885 - "Community 885" -Cohesion: 0.40 -Nodes (5): [1.21.0] β€” 2026-06-10, Added, Changed, Docs, Fixed - -### Community 886 - "Community 886" -Cohesion: 0.40 -Nodes (5): [1.24.0] β€” 2026-06-21, Added, Changed, Fixed, Security - -### Community 887 - "Community 887" -Cohesion: 0.40 -Nodes (5): [1.4.0] β€” 2026-05-12, Added, Changed, Documentation, Fixed - -### Community 888 - "Community 888" -Cohesion: 0.40 -Nodes (5): [1.6.2] β€” 2026-05-20, Added, Fixed, Refactored, Tests - -### Community 889 - "Community 889" -Cohesion: 0.40 -Nodes (5): Option A: Google Gemini / OpenAI / Claude / Grok (BYOK cloud), Option B: Ollama (local server), Option C: OpenRouter (free-tier cloud gateway), Option D: Browser-Native AI (WebGPU / ONNX / Transformers.js), πŸ” Setting Up AI - -### Community 890 - "Community 890" -Cohesion: 0.50 -Nodes (3): CodeGraph Report, Files by Extension, Status - -### Community 891 - "Community 891" -Cohesion: 0.50 -Nodes (3): enabled, plugins, notion-workspace - -### Community 892 - "Community 892" -Cohesion: 0.50 -Nodes (3): CodeAnt Correction-Loop Runbook β€” SUPERSEDED (tombstone), Current operational context (2026-06-24), Why this was retired (read if you arrived here from an old link) - -### Community 893 - "Community 893" -Cohesion: 0.50 -Nodes (3): Beta Completion Log, PR4 β€” status tiers, dashboard, help notice, Remaining work that needs native human review - -### Community 894 - "Community 894" -Cohesion: 0.50 -Nodes (4): 4. Speech-to-Text (STT) βœ… v1.0, Audio-Pipeline, Hybrid mode βœ… v1.0, Local high-quality solution - -### Community 895 - "Community 895" -Cohesion: 0.50 -Nodes (4): 8. ARIA UI Compatibility βœ… v1.0, Dynamic updates, Focus management βœ… v1.0, Semantic structure - -### Community 896 - "Community 896" -Cohesion: 0.50 -Nodes (3): ci-eco-start.sh script, FORGEJO_CONFIG_DIR, FORGEJO_DATA_DIR - -### Community 897 - "Community 897" -Cohesion: 0.83 -Nodes (3): mirror-github-to-forgejo.sh script, has_remote(), usage() - -### Community 898 - "Community 898" -Cohesion: 0.50 -Nodes (3): description, name, requestFramePermissions - -### Community 899 - "Community 899" -Cohesion: 0.50 -Nodes (3): extends, packageRules, $schema - -### Community 900 - "Community 900" -Cohesion: 0.50 -Nodes (4): CI / CD Hardening, Documentation, E2E / Testing, Follow-up Audit β€” 2026-05-17 (E2E mobile selectors + CI hardening) - -### Community 901 - "Community 901" -Cohesion: 0.50 -Nodes (4): CI Pipeline Improvements, E2E Stabilisation, Issues Resolved, Post-crash Session β€” 2026-06-01 (CI Hardening + CodeAnt + E2E Stabilisation) - -### Community 902 - "Community 902" -Cohesion: 0.50 -Nodes (4): CI: Stabilization, Follow-up Audit β€” 2026-05-31 (i18n Audit + Settings + CI Stabilization), i18n: Community Templates Localized, Settings: New Danger Zone features - -### Community 903 - "Community 903" -Cohesion: 0.50 -Nodes (4): CodeAnt AI review (11/11 addressed), Delivered, Files changed (non-locale), v1.23 OpenRouter Settings Section β€” Localization, Modern UI & Hardening (2026-06-13) - -### Community 904 - "Community 904" -Cohesion: 0.50 -Nodes (4): Documentation, Follow-up Audit β€” 2026-05-16 (Quality lift: WebLLM selector, cross-project search, test coverage), Product / Architecture, Quality / Testing - -### Community 905 - "Community 905" -Cohesion: 0.50 -Nodes (4): Documentation, Follow-up Audit β€” 2026-05-10 (Gold-Standard pipeline + strict lint/typecheck), Product / architecture, Tooling / DX - -### Community 906 - "Community 906" -Cohesion: 0.50 -Nodes (4): [1.10.0] β€” 2026-05-21, Added, Changed, Fixed - -### Community 907 - "Community 907" -Cohesion: 0.50 -Nodes (4): [1.19.0] β€” 2026-05-28, Added, Changed, Fixed - -### Community 908 - "Community 908" -Cohesion: 0.50 -Nodes (4): [1.22.0] β€” 2026-06-11, Added, Changed, Fixed - -### Community 909 - "Community 909" -Cohesion: 0.50 -Nodes (4): [1.23.0] β€” 2026-06-16, Added, Changed, Fixed - -### Community 910 - "Community 910" -Cohesion: 0.50 -Nodes (4): [1.24.2] β€” 2026-07-29, Documentation, Fixed, Security - -### Community 911 - "Community 911" -Cohesion: 0.50 -Nodes (4): [1.3.0] β€” 2026-05-08, Added, Changed, Fixed - -### Community 912 - "Community 912" -Cohesion: 0.50 -Nodes (4): [1.6.0] β€” 2026-05-19, Added (v1.6 β€” Plot-Board v2 & Writer Experience Sprint), Changed, Tests - -### Community 913 - "Community 913" -Cohesion: 0.50 -Nodes (4): [1.7.0] β€” 2026-05-20, Added, Changed, Fixed - -### Community 917 - "Community 917" -Cohesion: 0.67 -Nodes (3): 10. Text-to-Speech (TTS) βœ… v1.0, Integration βœ… v1.0, Modern alternatives - -### Community 918 - "Community 918" -Cohesion: 0.67 -Nodes (3): 12. Tiefe Integration in bestehende Codebase βœ… v1.0, Changed files (v1.0), Neue Dateien (v1.0 + v1.19.0 B-2) - -### Community 919 - "Community 919" -Cohesion: 0.67 -Nodes (3): 14. Error Handling, Graceful Degradation & Fallback βœ… v1.0, Error strategy, Graceful degradation βœ… v1.0 - -### Community 920 - "Community 920" -Cohesion: 0.67 -Nodes (3): 1. Overall Architecture, High-Level, Low-Level - -### Community 921 - "Community 921" -Cohesion: 0.67 -Nodes (3): 3. Web Speech API Alternativen (Moderne Stacks), Recommended stack 2026, Vergleich - -### Community 922 - "Community 922" -Cohesion: 0.67 -Nodes (3): 5. Context-Aware Intent Recognition & Command Engine βœ… v1.0, Architecture, Context awareness βœ… v1.0 - -### Community 923 - "Community 923" -Cohesion: 0.67 -Nodes (3): 6. Natural Language Understanding (NLU) βœ… v1.0 (rule-based), Approach: hybrid system, Examples of complex commands - -### Community 924 - "Community 924" -Cohesion: 0.67 -Nodes (3): 7. Accessible Audio Navigation per WCAG 2.2 βœ… v1.0, Audio landmarks βœ… v1.0, Conformance - -### Community 930 - "Community 930" -Cohesion: 0.67 -Nodes (3): Audit 2026-07-29 β€” CSP / Crypto / Truth (v1.24.2), Finding table, Post-mortem: why no gate caught F-01 for two months - -### Community 931 - "Community 931" -Cohesion: 0.67 -Nodes (3): Changes, TypeScript 7 Migration β€” 2026-06-04, Verification - -### Community 932 - "Community 932" -Cohesion: 0.67 -Nodes (3): Cross-links to recent engineering fixes, Follow-up Audit β€” 2026-05-06 (documentation inventory), Markdown corpus (maintainer-curated) - -### Community 933 - "Community 933" -Cohesion: 0.67 -Nodes (3): Current Status, Light Mode Theming (Resolved 2026-04-17), Tauri Feature Parity (historical baseline vs current β€” 2026-05) - -### Community 934 - "Community 934" -Cohesion: 0.67 -Nodes (3): Delivered, Files changed (non-locale), v1.21 Deep Audit Correction β€” 2026-06-09 (PR #89) - -### Community 935 - "Community 935" -Cohesion: 0.67 -Nodes (3): Documentation, Follow-up Audit β€” 2026-05-10 (Command Center & Helper UX), Product / architecture - -### Community 936 - "Community 936" -Cohesion: 0.67 -Nodes (3): Follow-up Audit β€” 2026-05-08 (v1.3.0 release engineering), Stability fixes (post-RC), Verification (release gate) - -### Community 937 - "Community 937" -Cohesion: 0.67 -Nodes (3): Follow-up Audit β€” 2026-05-19 (v1.5 Release + v1.6 Plot-Board v2 & Writer Experience), Released: v1.5.0 (2026-05-19, commit 7950039), Released: v1.6.0 (2026-05-19, commit 61c453e) - -### Community 938 - "Community 938" -Cohesion: 0.67 -Nodes (3): Follow-up Audit β€” 2026-05-20 (v1.6.1 + v1.6.2 β€” AI Models, Docker, plotBoardSlice Refactor, Locale-Aware Readability), Released: v1.6.1 (2026-05-19, commit aa9f21c), Released: v1.6.2 (2026-05-20, current) - -### Community 939 - "Community 939" -Cohesion: 0.67 -Nodes (3): [1.18.0] β€” 2026-05-27, Added, Fixed - -### Community 940 - "Community 940" -Cohesion: 0.67 -Nodes (3): [1.8.0] β€” 2026-05-21, Added, Fixed - -### Community 942 - "Community 942" -Cohesion: 0.67 -Nodes (3): βš™οΈ AI Execution Modes, 🧠 AI Provider Stack, WebGPU Hardware Detection - -## Knowledge Gaps -- **59640 isolated node(s):** `$schema`, `extends`, `packageRules`, `$schema`, `packageManager` (+59635 more) - These have ≀1 connection - possible missing edges or undocumented components. -- **60 thin communities (<3 nodes) omitted from report** β€” run `graphify query` to explore isolated nodes. - -## Suggested Questions -_Questions this graph is uniquely positioned to answer:_ - -- **Why does `useTranslation()` connect `Community 138` to `Community 0`, `Community 130`, `Community 7`, `Community 11`, `Community 12`, `Community 14`, `Community 15`, `Community 150`, `Community 23`, `Community 24`, `Community 26`, `Community 27`, `Community 31`, `Community 161`, `Community 34`, `Community 35`, `Community 42`, `Community 47`, `Community 305`, `Community 53`, `Community 55`, `Community 56`, `Community 68`, `Community 202`, `Community 81`, `Community 86`, `Community 488`?** - _High betweenness centrality (0.002) - this node is a cross-community bridge._ -- **Why does `fn()` connect `Community 3` to `Community 1`, `Community 2`, `Community 4`, `Community 388`, `Community 5`, `Community 138`, `Community 11`, `Community 13`, `Community 26`, `Community 32`, `Community 35`, `Community 806`, `Community 556`, `Community 428`, `Community 52`, `Community 185`, `Community 574`, `Community 194`, `Community 68`, `Community 197`, `Community 71`, `Community 210`, `Community 86`, `Community 216`, `Community 98`, `Community 482`, `Community 742`, `Community 104`, `Community 619`, `Community 754`, `Community 378`, `Community 124`?** - _High betweenness centrality (0.002) - this node is a cross-community bridge._ -- **What connects `$schema`, `extends`, `packageRules` to the rest of the system?** - _59641 weakly-connected nodes found - possible documentation gaps or missing edges._ -- **Should `Community 0` be split into smaller, more focused modules?** - _Cohesion score 0.045875251509054325 - nodes in this community are weakly interconnected._ -- **Should `Community 1` be split into smaller, more focused modules?** - _Cohesion score 0.07087486157253599 - nodes in this community are weakly interconnected._ -- **Should `Community 2` be split into smaller, more focused modules?** - _Cohesion score 0.021270396270396272 - nodes in this community are weakly interconnected._ -- **Should `Community 3` be split into smaller, more focused modules?** - _Cohesion score 0.01743295019157088 - nodes in this community are weakly interconnected._ \ No newline at end of file +Nodes (54): PipelineRun, getStartupPayload(), BrowserProForgeCapabilityDeps, createBrowserProForgeCapability(), applyEditsPure(), ApplyEditsResultSummary, buildAgentContext(), PartialConfigOverrides (+46 more) diff --git a/package.json b/package.json index 9f5504d4..de0fcb0e 100644 --- a/package.json +++ b/package.json @@ -52,18 +52,25 @@ "token:audit": "node scripts/audit-tokens.mjs", "guardrail:desktop-imports": "node scripts/check-tauri-import-boundary.mjs", "sync:readme": "node scripts/sync-readme-metrics.mjs", - "graphify": "node scripts/graphify-cli.mjs", - "graphify:install": "node scripts/graphify-cli.mjs install", - "graphify:update": "node scripts/graphify-update.mjs", + "graphify": "node scripts/graphs-cli.mjs graphify", + "graphify:install": "node scripts/graphs-cli.mjs graphify install", + "graphify:update": "node scripts/graphs-cli.mjs graphify update .", "graphify:bootstrap": "node scripts/graphify-bootstrap.mjs", - "graphify:hooks": "node scripts/graphify-cli.mjs hook install", - "graphify:status": "node scripts/graphify-cli.mjs hook status", - "codegraph:status": "codegraph status", - "codegraph:update": "codegraph index --force", - "codegraph:sync": "codegraph sync", + "graphify:hooks": "node scripts/graphs-cli.mjs graphify hook install", + "graphify:status": "node scripts/graphs-cli.mjs graphify hook status", + "codegraph:bootstrap": "node scripts/codegraph-bootstrap.mjs", + "codegraph:init": "node scripts/graphs-cli.mjs codegraph init", + "codegraph:status": "node scripts/graphs-cli.mjs codegraph status", + "codegraph:update": "node scripts/graphs-cli.mjs codegraph index --force", + "codegraph:sync": "node scripts/graphs-cli.mjs codegraph sync", "codegraph:report": "node scripts/codegraph-report.mjs", - "codegraph:affected": "git diff --name-only HEAD | codegraph affected --stdin", - "graphs:update": "node scripts/dual-graph-update.mjs", + "codegraph:affected": "git diff --name-only HEAD | node scripts/graphs-cli.mjs codegraph affected --stdin", + "graphs:bootstrap": "node scripts/graphs-cli.mjs bootstrap", + "graphs:doctor": "node scripts/graphs-cli.mjs doctor", + "graphs:status": "node scripts/graphs-cli.mjs status", + "graphs:update": "node scripts/graphs-cli.mjs update", + "graphs:report": "node scripts/graphs-cli.mjs report", + "graphs:refresh": "node scripts/graphs-cli.mjs refresh", "build": "vite build", "build:edge": "node scripts/build-edge.mjs", "build:pages": "vite build", diff --git a/scripts/codegraph-bootstrap.mjs b/scripts/codegraph-bootstrap.mjs new file mode 100644 index 00000000..7e53770e --- /dev/null +++ b/scripts/codegraph-bootstrap.mjs @@ -0,0 +1,45 @@ +#!/usr/bin/env node +/** + * Install @colbymchenry/codegraph at the exact version pinned in config/graph-tools-versions.json. + * CodeGraph is optional local developer tooling β€” this never touches package.json dependencies. + * Never falls through to an unpinned "latest" install. See docs/codegraph.md + */ +import { spawnSync } from 'node:child_process'; +import { readFileSync } from 'node:fs'; +import { join } from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { executeCodegraph } from './codegraph-report.mjs'; +import { matchesExactVersion } from './graphSourceFingerprint.mjs'; + +const root = join(fileURLToPath(new URL('.', import.meta.url)), '..'); +const policy = JSON.parse(readFileSync(join(root, 'config', 'graph-tools-versions.json'), 'utf-8')); +const version = policy.codegraph.testedVersion; +const pinnedSpec = `@colbymchenry/codegraph@${version}`; +const install = spawnSync('npm', ['install', '-g', pinnedSpec], { + stdio: 'inherit', + shell: process.platform === 'win32', + env: process.env, +}); + +if (install.status !== 0) { + process.stderr.write( + `[codegraph-bootstrap] Could not install ${pinnedSpec} via npm.\n` + + `Install manually: npm install -g ${pinnedSpec}\n`, + ); + process.exit(install.status ?? 1); +} + +// QNBS-v3: keep optional CodeGraph outside app dependencies while verifying the exact shared policy version. +const verify = executeCodegraph(['--version'], { + encoding: 'utf-8', +}); +const installedVersion = (verify.stdout ?? '').trim(); +if (verify.status !== 0 || !matchesExactVersion(installedVersion, version)) { + process.stderr.write( + `[codegraph-bootstrap] Installed but version verification failed. ` + + `Expected ${version}, got: ${installedVersion || '(no output)'}\n`, + ); + process.exit(1); +} + +console.log(`[codegraph-bootstrap] Installed ${pinnedSpec} (verified: ${installedVersion}).`); diff --git a/scripts/codegraph-report.d.mts b/scripts/codegraph-report.d.mts new file mode 100644 index 00000000..991dc889 --- /dev/null +++ b/scripts/codegraph-report.d.mts @@ -0,0 +1,23 @@ +import type { Buffer } from 'node:buffer'; + +export const REPORT_PATH: string; +export const DB_PATH: string; +export function resolveCodegraphCommand(): string; +export function executeCodegraph( + args: string[], + options?: Record, +): { + status: number | null; + stdout?: string | Buffer | null; + stderr?: string | Buffer | null; + error?: Error; +}; +export function redactPaths(text: string, opts?: { root?: string; home?: string }): string; +export function sanitize(text: string, opts?: { root?: string; home?: string }): string; +export function validateIndexStatus(status: unknown, expectedVersion: string): unknown; +export function validateFileList( + fileList: Array<{ path: string }>, + expectedCount: number, +): Array<{ path: string }>; +export function formatExtensionLines(fileList: Array<{ path: string }>): string; +export function generateReport(): number; diff --git a/scripts/codegraph-report.mjs b/scripts/codegraph-report.mjs index 0867c99b..d0bcc884 100644 --- a/scripts/codegraph-report.mjs +++ b/scripts/codegraph-report.mjs @@ -1,49 +1,310 @@ #!/usr/bin/env node /** - * Generates CODEGRAPH_REPORT.md from codegraph status + query output. - * QNBS-v3: mirrors graphify's GRAPH_REPORT.md policy for consistency. + * Generates the compact, deterministic .codegraph/CODEGRAPH_REPORT.md from a real local index. + * Fails loudly on any real failure β€” never embeds "Unavailable: " into a file that still + * looks like a successful report. Gated on a clean source tree (DIRTY_UNTRACKED_INPUT refuses to + * write) so the embedded fingerprint always matches a committable state. */ -import { execSync } from 'node:child_process'; -import { existsSync, writeFileSync } from 'node:fs'; - -const REPORT_PATH = '.codegraph/CODEGRAPH_REPORT.md'; - -if (!existsSync('.codegraph/codegraph.db')) { - console.error('❌ CodeGraph not initialized. Run: codegraph init -i'); - process.exit(1); -} - -let report = '# CodeGraph Report\n\n'; -report += `**Generated:** ${new Date().toISOString()}\n\n`; - -try { - const status = execSync('codegraph status', { encoding: 'utf-8' }); - report += `## Status\n\n\`\`\`\n${status}\n\`\`\`\n\n`; -} catch (e) { - report += `## Status\n\nUnavailable: ${String(e)}\n\n`; -} - -try { - const files = execSync('codegraph files --json', { encoding: 'utf-8' }); - const fileList = JSON.parse(files); - const byExt = fileList.reduce((acc, f) => { - const ext = f.path.split('.').pop() || 'none'; - acc[ext] = (acc[ext] || 0) + 1; - return acc; - }, {}); - report += '## Files by Extension\n\n'; - Object.entries(byExt) - .sort((a, b) => b[1] - a[1]) - .forEach(([ext, count]) => { - report += `- **.${ext}**: ${count}\n`; +import { spawnSync } from 'node:child_process'; +import { existsSync, readFileSync, renameSync, rmSync, writeFileSync } from 'node:fs'; +import { join } from 'node:path'; +import { pathToFileURL } from 'node:url'; +import { + buildMetadataBlock, + checkCleanState, + computeSourceFingerprint, + ROOT, +} from './graphSourceFingerprint.mjs'; + +export const REPORT_PATH = join(ROOT, '.codegraph', 'CODEGRAPH_REPORT.md'); +export const DB_PATH = join(ROOT, '.codegraph', 'codegraph.db'); + +function quoteWindowsCommandArg(value) { + if (/\r|\n/.test(value)) throw new Error('Windows command arguments cannot contain newlines'); + return `"${value.replaceAll('"', '\\"')}"`; +} + +function runCommand(command, args, options = {}) { + const isWindowsShim = process.platform === 'win32' && command.toLowerCase().endsWith('.cmd'); + const invocation = isWindowsShim + ? { + command: process.env.ComSpec ?? 'cmd.exe', + args: ['/d', '/s', '/c', `"${[command, ...args].map(quoteWindowsCommandArg).join(' ')}"`], + } + : { command, args }; + return spawnSync(invocation.command, invocation.args, { + ...options, + shell: false, + }); +} + +// QNBS-v3: resolve the same global executable and Windows shim for every CodeGraph operation. +export function resolveCodegraphCommand() { + const fallback = process.platform === 'win32' ? 'codegraph.cmd' : 'codegraph'; + const prefix = runCommand(process.platform === 'win32' ? 'npm.cmd' : 'npm', ['prefix', '-g'], { + encoding: 'utf-8', + stdio: ['ignore', 'pipe', 'ignore'], + }); + if (prefix.status !== 0 || prefix.error) return fallback; + const globalBin = + process.platform === 'win32' ? prefix.stdout.trim() : join(prefix.stdout.trim(), 'bin'); + const candidate = join(globalBin, process.platform === 'win32' ? 'codegraph.cmd' : 'codegraph'); + return existsSync(candidate) ? candidate : fallback; +} + +function resolveWindowsCodegraphEntrypoint(command) { + if (process.platform !== 'win32' || !command.toLowerCase().endsWith('.cmd')) return null; + const rootResult = runCommand('npm.cmd', ['root', '-g'], { + encoding: 'utf-8', + stdio: ['ignore', 'pipe', 'ignore'], + }); + if (rootResult.status !== 0 || rootResult.error) return null; + try { + const packageRoot = join(rootResult.stdout.trim(), '@colbymchenry', 'codegraph'); + const packageJson = JSON.parse(readFileSync(join(packageRoot, 'package.json'), 'utf-8')); + const bin = typeof packageJson.bin === 'string' ? packageJson.bin : packageJson.bin?.codegraph; + if (typeof bin !== 'string') return null; + const entrypoint = join(packageRoot, bin); + return existsSync(entrypoint) ? entrypoint : null; + } catch { + return null; + } +} + +// QNBS-v3: invoke Windows shims through their package entrypoint to avoid cmd.exe reparsing paths. +export function executeCodegraph(args, options = {}) { + const command = resolveCodegraphCommand(); + const entrypoint = resolveWindowsCodegraphEntrypoint(command); + const invocation = entrypoint + ? { command: process.execPath, args: [entrypoint, ...args] } + : { command, args }; + return runCommand(invocation.command, invocation.args, { + cwd: ROOT, + env: { ...process.env, NO_COLOR: '1' }, + ...options, + shell: false, + }); +} + +// QNBS-v3: sanitize terminal control sequences without adding a lint suppression for control bytes. +const ANSI_PATTERN = new RegExp( + `${String.fromCharCode(0x1b)}(?:\\][\\s\\S]*?(?:${String.fromCharCode(0x07)}|${String.fromCharCode(0x1b)}\\\\)|\\[[0-?]*[ -/]*[@-~])`, + 'g', +); + +/** Redact an absolute machine path (repo root or home dir) to a repo-relative or generic form. */ +export function redactPaths( + text, + { root = ROOT, home = process.env.HOME ?? process.env.USERPROFILE ?? '' } = {}, +) { + const replacePrefix = (input, target, replacement) => { + if (!target) return input; + const normalized = target.replace(/[\\/]$/, ''); + const variants = [ + ...new Set([normalized, normalized.replaceAll('/', '\\'), normalized.replaceAll('\\', '/')]), + ]; + let output = input; + for (const variant of variants) { + const escaped = variant.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + const flags = /^(?:[A-Za-z]:[\\/]|\\\\|\/\/)/.test(variant) ? 'gi' : 'g'; + output = output.replace( + new RegExp(`(^|[^A-Za-z0-9._-])${escaped}(?=$|[\\\\/])`, flags), + (_, prefix) => `${prefix}${replacement}`, + ); + } + return output; + }; + return replacePrefix(replacePrefix(text, root, '.'), home, '~'); +} + +/** Strips ANSI escape codes, then redacts absolute paths β€” the full committed-report safety pass. */ +export function sanitize(text, opts) { + return redactPaths(text.replace(ANSI_PATTERN, ''), opts); +} + +function runCodegraph(args) { + // QNBS-v3: preserve child-process failures so report generation cannot turn an unavailable CLI into success. + const result = executeCodegraph(args, { encoding: 'utf-8' }); + if (result.status !== 0 || result.error) { + throw new Error( + `codegraph ${args.join(' ')} failed (exit ${result.status ?? 'null'}): ${result.stderr ?? result.error?.message ?? ''}`, + ); + } + return result.stdout; +} + +function readPolicy() { + return JSON.parse(readFileSync(join(ROOT, 'config', 'graph-tools-versions.json'), 'utf-8')); +} + +// QNBS-v3: reject pending or mismatched index evidence before it can enter a committed report. +export function validateIndexStatus(status, expectedVersion) { + const pending = status?.pendingChanges; + const index = status?.index; + const counts = [status?.fileCount, status?.nodeCount, status?.edgeCount]; + if (status?.initialized !== true || status.version !== expectedVersion) { + throw new Error(`CodeGraph version/index mismatch; expected initialized ${expectedVersion}`); + } + if (counts.some((count) => !Number.isInteger(count) || count < 0)) { + throw new Error('CodeGraph status is incomplete: file/node/edge counts are required'); + } + if ( + !pending || + ['added', 'modified', 'removed'].some( + (field) => !Number.isInteger(pending[field]) || pending[field] !== 0, + ) || + status.worktreeMismatch != null + ) { + throw new Error('CodeGraph index is stale: pending changes or worktree mismatch reported'); + } + if (!index || index.builtWithVersion !== expectedVersion || index.reindexRecommended !== false) { + throw new Error('CodeGraph index requires reindexing or was built with another version'); + } + return status; +} + +// QNBS-v3: status counts and file evidence must describe the same complete index snapshot. +export function validateFileList(fileList, expectedCount) { + if (!Array.isArray(fileList) || fileList.some((file) => typeof file?.path !== 'string')) { + throw new Error('codegraph files --json returned an invalid file list'); + } + const uniquePaths = new Set(fileList.map((file) => file.path)); + if (fileList.length !== expectedCount || uniquePaths.size !== expectedCount) { + throw new Error('codegraph files --json count does not match codegraph status'); + } + return fileList; +} + +export function formatExtensionLines(fileList) { + const byExtension = new Map(); + for (const file of fileList) { + const extension = file.path.split('.').pop() || 'none'; + // QNBS-v3: reject control characters before filename-derived text reaches Markdown. + const hasUnsafeCharacter = [...extension].some((character) => { + const codePoint = character.codePointAt(0) ?? -1; + return ( + (codePoint >= 0 && codePoint <= 0x1f) || + (codePoint >= 0x7f && codePoint <= 0x9f) || + codePoint === 0x2028 || + codePoint === 0x2029 + ); }); - report += '\n'; -} catch (e) { - report += `## Files by Extension\n\nUnavailable: ${String(e)}\n\n`; + if (hasUnsafeCharacter) { + throw new Error('codegraph files --json returned an unsafe filename extension'); + } + byExtension.set(extension, (byExtension.get(extension) ?? 0) + 1); + } + return ( + [...byExtension.entries()] + // QNBS-v3: code-point ordering keeps equal-count reports identical across host locales. + .sort((a, b) => b[1] - a[1] || (a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0)) + .map(([extension, count]) => { + const safeExtension = extension.replace(/[\\`*_{}[\]()#+.!|>~-]/g, '\\$&'); + return `- **.${safeExtension}**: ${count}`; + }) + .join('\n') + ); +} + +function parseStatus(output, expectedVersion) { + try { + return validateIndexStatus(JSON.parse(output), expectedVersion); + } catch (error) { + if (error instanceof SyntaxError) + throw new Error(`could not parse codegraph status --json: ${error.message}`); + throw error; + } +} + +function compactStatus(status) { + return [ + `Initialized: ${status.initialized ? 'yes' : 'no'}`, + `Version: ${status.version}`, + `Files: ${status.fileCount}`, + `Nodes: ${status.nodeCount}`, + `Edges: ${status.edgeCount}`, + `Pending changes: ${JSON.stringify(status.pendingChanges)}`, + `Worktree mismatch: ${status.worktreeMismatch ?? 'none'}`, + `Index built with: ${status.index.builtWithVersion}`, + `Reindex required: ${status.index.reindexRecommended ? 'yes' : 'no'}`, + ].join('\n'); +} + +function writeCandidate(report) { + const candidate = `${REPORT_PATH}.tmp-${process.pid}`; + try { + writeFileSync(candidate, report); + renameSync(candidate, REPORT_PATH); + } catch (error) { + rmSync(candidate, { force: true }); + throw error; + } } -report += '---\n\n'; -report += '*Regenerate with: `pnpm run codegraph:report`*\n'; +// QNBS-v3: keep the previous report authoritative until stable evidence validates its replacement. +export function generateReport() { + if (!existsSync(DB_PATH)) { + console.error( + '[codegraph-report] SKIPPED_NOT_INITIALIZED β€” no local index. Run: pnpm run codegraph:update', + ); + return 1; + } + + const { clean, dirtyPaths } = checkCleanState(); + if (!clean) { + console.error( + `[codegraph-report] DIRTY_UNTRACKED_INPUT β€” refusing to write a committed report from an ` + + `unstable source state. Commit or stash first:\n ${dirtyPaths.join('\n ')}`, + ); + return 1; + } + + const previousReport = existsSync(REPORT_PATH) ? readFileSync(REPORT_PATH) : null; + let fingerprintBefore; + try { + fingerprintBefore = computeSourceFingerprint(); + const packageJson = JSON.parse(readFileSync(join(ROOT, 'package.json'), 'utf-8')); + const policy = readPolicy(); + const status = parseStatus(runCodegraph(['status', '--json']), policy.codegraph.testedVersion); + const filesOutput = runCodegraph(['files', '--json']); + let fileList; + try { + fileList = JSON.parse(filesOutput); + } catch (error) { + throw new Error(`could not parse codegraph files --json: ${error.message}`); + } + validateFileList(fileList, status.fileCount); -writeFileSync(REPORT_PATH, report); -console.log(`βœ… ${REPORT_PATH} generated.`); + const fingerprintAfter = computeSourceFingerprint(); + const afterState = checkCleanState(); + if (!afterState.clean || fingerprintBefore !== fingerprintAfter) { + throw new Error( + 'SOURCE_CHANGED_DURING_REPORT β€” source/index evidence is not one stable snapshot', + ); + } + const extLines = formatExtensionLines(fileList); + const metadata = buildMetadataBlock({ + tool: 'codegraph', + toolVersion: status.version, + generationMode: 'local-index (codegraph status --json/files)', + reportSchemaVersion: policy.reportSchemaVersion, + fingerprint: fingerprintAfter, + }); + const report = `# CodeGraph Report\n\n${metadata}\n\n## Status\n\n\`\`\`text\n${compactStatus(status)}\n\`\`\`\n\n## Files by Extension\n\n${extLines}\n\n---\n\n*Regenerate with: \`pnpm run graphs:report\` (or \`pnpm run codegraph:report\` directly). Freshness\ncheck: \`pnpm run graphs:status\`. Package: ${packageJson.name ?? 'worldscript-studio'}.*\n`; + writeCandidate(report); + if (!checkCleanState().clean || computeSourceFingerprint() !== fingerprintBefore) { + throw new Error('SOURCE_CHANGED_DURING_REPORT β€” source changed before report commit'); + } + console.log(`[codegraph-report] PASS β€” ${REPORT_PATH} generated.`); + return 0; + } catch (error) { + if (previousReport === null) rmSync(REPORT_PATH, { force: true }); + else writeFileSync(REPORT_PATH, previousReport); + console.error(`[codegraph-report] FAIL β€” ${error?.message ?? String(error)}`); + return 1; + } +} + +if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) { + process.exit(generateReport()); +} diff --git a/scripts/dual-graph-update.mjs b/scripts/dual-graph-update.mjs deleted file mode 100644 index a8539855..00000000 --- a/scripts/dual-graph-update.mjs +++ /dev/null @@ -1,43 +0,0 @@ -#!/usr/bin/env node -/** - * Unified update script for both Graphify and CodeGraph. - * QNBS-v3: Ensures both knowledge graphs stay in sync after large refactors. - */ -import { spawnSync } from 'node:child_process'; -import { existsSync } from 'node:fs'; - -console.log('πŸ”„ Dual-Graph Update started...\n'); - -// 1. Graphify update (AST-only, no API cost) -console.log('πŸ“Š Updating Graphify...'); -const graphifyResult = spawnSync(process.execPath, ['scripts/graphify-update.mjs'], { - stdio: 'inherit', - cwd: process.cwd(), -}); -if (graphifyResult.status !== 0) { - console.warn('⚠️ Graphify update returned non-zero. Continuing...'); -} - -// 2. CodeGraph update -if (existsSync('.codegraph/codegraph.db')) { - console.log('\nπŸ” Updating CodeGraph...'); - const cgResult = spawnSync('codegraph', ['index', '--force'], { - stdio: 'inherit', - }); - if (cgResult.status !== 0) { - console.warn('⚠️ CodeGraph index returned non-zero.'); - } - - console.log('\nπŸ“ Generating CodeGraph report...'); - const reportResult = spawnSync(process.execPath, ['scripts/codegraph-report.mjs'], { - stdio: 'inherit', - }); - if (reportResult.status !== 0) { - console.warn('⚠️ CodeGraph report generation failed.'); - } -} else { - console.log('\n⏭️ CodeGraph not initialized. Skipping. Run: codegraph init -i'); -} - -console.log('\nβœ… Dual-Graph Update complete.'); -console.log('Remember: Only GRAPH_REPORT.md and CODEGRAPH_REPORT.md should be committed.'); diff --git a/scripts/graphSourceFingerprint.d.mts b/scripts/graphSourceFingerprint.d.mts new file mode 100644 index 00000000..a94905ad --- /dev/null +++ b/scripts/graphSourceFingerprint.d.mts @@ -0,0 +1,13 @@ +export const ROOT: string; +export function listSourcePaths(cwd?: string): Array; +export function computeSourceFingerprint(cwd?: string): string; +export function matchesExactVersion(output: string, expectedVersion: string): boolean; +export function checkCleanState(cwd?: string): { clean: boolean; dirtyPaths: string[] }; +export function buildMetadataBlock(opts: { + tool: string; + toolVersion: string; + generationMode: string; + reportSchemaVersion: number; + cwd?: string; + fingerprint?: string; +}): string; diff --git a/scripts/graphSourceFingerprint.mjs b/scripts/graphSourceFingerprint.mjs new file mode 100644 index 00000000..c91a1c5c --- /dev/null +++ b/scripts/graphSourceFingerprint.mjs @@ -0,0 +1,396 @@ +#!/usr/bin/env node +/** + * Worktree-aware, deterministic content fingerprint for the dual-graph tooling. + * + * Freshness must never be keyed on a git commit SHA: a squash merge changes the SHA on + * content-equivalent code (PR_HEAD_SHA != SQUASH_MERGE_SHA), and a `git ls-tree ` based + * fingerprint only sees committed blobs, missing real, not-yet-committed working-tree edits. + * This module hashes the *current on-disk bytes* of every tracked-or-untracked-but-not-ignored + * source path (excluding generated graph output), so it reflects genuine current state. + */ +import { execFileSync } from 'node:child_process'; +import { createHash } from 'node:crypto'; +import { lstatSync, readFileSync, readlinkSync } from 'node:fs'; +import { join } from 'node:path'; +import { fileURLToPath, pathToFileURL } from 'node:url'; + +export const ROOT = join(fileURLToPath(new URL('.', import.meta.url)), '..'); + +/** Generated graph output and linked worktrees β€” never part of the fingerprint. */ +const EXCLUDED_PREFIXES = ['graphify-out/', '.codegraph/', '.worktrees/']; +// QNBS-v3: bounded retries make freshness fail closed instead of hashing a moving source tree. +const SNAPSHOT_ATTEMPTS = 3; + +function isExcluded(relPath) { + const comparable = Buffer.isBuffer(relPath) ? relPath.toString('utf8') : relPath; + return EXCLUDED_PREFIXES.some((prefix) => comparable.startsWith(prefix)); +} + +function parseNulRecords(output) { + const bytes = Buffer.isBuffer(output) ? output : Buffer.from(output); + const records = []; + let start = 0; + for (let end = 0; end <= bytes.length; end += 1) { + if (end !== bytes.length && bytes[end] !== 0) continue; + if (end > start) records.push(bytes.subarray(start, end)); + start = end + 1; + } + return records; +} + +function decodeGitPath(bytes) { + try { + return new TextDecoder('utf-8', { fatal: true }).decode(bytes); + } catch { + // QNBS-v3: retain undecodable Git pathname bytes so filesystem lookup cannot turn them into a deletion. + return Buffer.from(bytes); + } +} + +function pathBytes(relPath) { + return Buffer.isBuffer(relPath) ? relPath : Buffer.from(relPath, 'utf8'); +} + +function pathIdentity(relPath) { + return pathBytes(relPath).toString('hex'); +} + +function pathLabel(relPath) { + return Buffer.isBuffer(relPath) ? `path bytes 0x${relPath.toString('hex')}` : relPath; +} + +function pathForFingerprint(relPath) { + const bytes = pathBytes(relPath); + // QNBS-v3: length-prefix raw path bytes so newline and delimiter bytes cannot collide. + return `${bytes.length}:${bytes.toString('hex')}`; +} + +function compareGitPaths(left, right) { + return Buffer.compare(pathBytes(left), pathBytes(right)); +} + +function absolutePathFor(cwd, relPath) { + return Buffer.isBuffer(relPath) + ? Buffer.concat([Buffer.from(`${cwd}/`), relPath]) + : join(cwd, relPath); +} + +function listSparsePaths(cwd) { + return parseNulRecords( + execFileSync('git', ['ls-files', '-v', '-z'], { + cwd, + encoding: 'buffer', + }), + ) + .filter((record) => record.subarray(0, 2).toString('ascii') === 'S ') + .map((record) => decodeGitPath(record.subarray(2))); +} + +function listAssumeUnchangedPaths(cwd) { + return parseNulRecords( + execFileSync('git', ['ls-files', '-v', '-z'], { + cwd, + encoding: 'buffer', + }), + ) + .filter((record) => record.length > 1 && record[0] >= 0x61 && record[0] <= 0x7a) + .map((record) => decodeGitPath(record.subarray(2))); +} + +/** @param {string} output @param {string} expectedVersion */ +export function matchesExactVersion(output, expectedVersion) { + // QNBS-v3: compare the first declared CLI line so later warnings cannot satisfy a version pin. + const declared = String(output).trimStart().split(/\r?\n/, 1)[0].trim(); + return declared === expectedVersion || declared === `graphify ${expectedVersion}`; +} + +/** @param {string} cwd @returns {string[]} sorted, deduplicated repo-relative paths: tracked βˆͺ untracked-not-ignored. */ +export function listSourcePaths(cwd = ROOT) { + const tracked = parseNulRecords( + execFileSync('git', ['ls-files', '--cached', '--exclude-standard', '-z'], { + cwd, + encoding: 'buffer', + }), + ).map(decodeGitPath); + const untracked = parseNulRecords( + execFileSync('git', ['ls-files', '--others', '--exclude-standard', '-z'], { + cwd, + encoding: 'buffer', + }), + ).map(decodeGitPath); + const all = new Map(); + for (const path of [...tracked, ...untracked]) all.set(pathIdentity(path), path); + return [...all.values()].filter((p) => !isExcluded(p)).sort(compareGitPaths); +} + +function listTrackedEntries(cwd) { + const entries = new Map(); + for (const record of parseNulRecords( + execFileSync('git', ['ls-files', '--stage', '-z'], { + cwd, + encoding: 'buffer', + }), + )) { + const separator = record.indexOf(9); + if (separator < 0) throw new Error('git ls-files returned an invalid staged path record'); + const metadata = record.subarray(0, separator).toString('ascii').split(' '); + const mode = metadata[0]; + const objectId = metadata[1]; + const relPath = decodeGitPath(record.subarray(separator + 1)); + if (!/^(?:100\d{3}|120000|160000)$/.test(mode)) { + throw new Error(`invalid tracked file mode ${mode} for ${pathLabel(relPath)}`); + } + if (!/^[0-9a-f]+$/.test(objectId ?? '')) { + throw new Error(`invalid tracked object id for ${pathLabel(relPath)}`); + } + entries.set(pathIdentity(relPath), { mode, objectId }); + } + return entries; +} + +function enumerateSourcePaths(cwd) { + const sparsePaths = listSparsePaths(cwd).filter((relPath) => !isExcluded(relPath)); + const assumeUnchangedPaths = listAssumeUnchangedPaths(cwd).filter( + (relPath) => !isExcluded(relPath), + ); + if (sparsePaths.length > 0) { + throw new Error( + `SPARSE_CHECKOUT_UNSUPPORTED β€” tracked source paths are absent from this checkout: ${sparsePaths.map(pathLabel).join(', ')}`, + ); + } + if (assumeUnchangedPaths.length > 0) { + throw new Error( + `SOURCE_INDEX_FLAGS_UNSUPPORTED β€” tracked source paths have hidden worktree state: ${assumeUnchangedPaths.map(pathLabel).join(', ')}`, + ); + } + const trackedEntries = listTrackedEntries(cwd); + return { + paths: listSourcePaths(cwd), + tracked: new Set(trackedEntries.keys()), + entries: trackedEntries, + }; +} + +function isText(bytes) { + if (bytes.includes(0)) return false; + try { + const text = new TextDecoder('utf-8', { fatal: true }).decode(bytes); + const encoded = new TextEncoder().encode(text); + return ( + encoded.length === bytes.length && encoded.every((value, index) => value === bytes[index]) + ); + } catch { + return false; + } +} + +function hashBytes(bytes) { + const content = isText(bytes) + ? Buffer.from(new TextDecoder().decode(bytes).replace(/\r\n?/g, '\n'), 'utf8') + : bytes; + return createHash('sha256').update(content).digest('hex'); +} + +function hashDeletion(relPath) { + return createHash('sha256').update('deleted:').update(pathBytes(relPath)).digest('hex'); +} + +function hashSymlink(target) { + // QNBS-v3: raw symlink target bytes preserve source identity for non-UTF-8 link targets. + return createHash('sha256').update('symlink:').update(pathBytes(target)).digest('hex'); +} + +function hashGitlink(objectId) { + return createHash('sha256').update(`gitlink:${objectId}`).digest('hex'); +} + +function fileSignature(stat) { + return `${stat.dev}:${stat.ino}:${stat.size}:${stat.mtimeMs}`; +} + +function readSnapshot(cwd, enumeration) { + const lines = []; + for (const relPath of enumeration.paths) { + const absolutePath = absolutePathFor(cwd, relPath); + const label = pathLabel(relPath); + const entry = enumeration.entries.get(pathIdentity(relPath)) ?? { + mode: '100644', + objectId: null, + }; + const mode = entry.mode; + if (mode === '160000') { + // QNBS-v3: hash the Gitlink object identity without depending on a submodule worktree. + lines.push(`${mode}:${hashGitlink(entry.objectId)}:${pathForFingerprint(relPath)}`); + continue; + } + let before; + try { + before = lstatSync(absolutePath); + } catch (error) { + if (error?.code === 'ENOENT' && enumeration.tracked.has(pathIdentity(relPath))) { + lines.push(`${mode}:${hashDeletion(relPath)}:${pathForFingerprint(relPath)}`); + continue; + } + throw new Error(`source path disappeared during fingerprinting: ${label}`); + } + if (before.isSymbolicLink()) { + // QNBS-v3: hash the link target itself so symlink identity is portable and target-sensitive. + const target = readlinkSync(absolutePath, { encoding: 'buffer' }); + let after; + try { + after = lstatSync(absolutePath); + } catch { + throw new Error(`source path disappeared after reading symlink: ${label}`); + } + if (fileSignature(before) !== fileSignature(after)) { + throw new Error(`source symlink changed while being fingerprinted: ${label}`); + } + lines.push(`${mode}:${hashSymlink(target)}:${pathForFingerprint(relPath)}`); + continue; + } + if (mode === '120000') { + let target; + try { + target = readFileSync(absolutePath); + } catch (error) { + throw new Error( + `failed to read materialized symlink ${label} during fingerprinting: ${error?.message ?? String(error)}`, + ); + } + let after; + try { + after = lstatSync(absolutePath); + } catch { + throw new Error(`source path disappeared after reading materialized symlink: ${label}`); + } + if (fileSignature(before) !== fileSignature(after)) { + throw new Error(`materialized symlink changed while being fingerprinted: ${label}`); + } + // QNBS-v3: core.symlinks=false materializes mode-120000 links as target text. + lines.push(`${mode}:${hashSymlink(target)}:${pathForFingerprint(relPath)}`); + continue; + } + if (!before.isFile()) throw new Error(`source path is not a regular file: ${label}`); + let bytes; + try { + bytes = readFileSync(absolutePath); + } catch (error) { + throw new Error( + `failed to read ${label} during fingerprinting: ${error?.message ?? String(error)}`, + ); + } + let after; + try { + after = lstatSync(absolutePath); + } catch { + throw new Error(`source path disappeared after reading: ${label}`); + } + if (fileSignature(before) !== fileSignature(after)) { + throw new Error(`source path changed while being fingerprinted: ${label}`); + } + lines.push(`${mode}:${hashBytes(bytes)}:${pathForFingerprint(relPath)}`); + } + return lines; +} + +/** + * Deterministic SHA-256 over sorted `mode:sha256(content):path` lines for the current source. + * Git-normalized modes capture executable-bit semantics without hashing platform stat bits. + * @param {string} cwd + */ +export function computeSourceFingerprint(cwd = ROOT) { + // QNBS-v3: compare two bounded snapshots so reports never combine evidence from moving inputs. + let lastError; + for (let attempt = 1; attempt <= SNAPSHOT_ATTEMPTS; attempt += 1) { + try { + const firstEnumeration = enumerateSourcePaths(cwd); + const first = readSnapshot(cwd, firstEnumeration); + const secondEnumeration = enumerateSourcePaths(cwd); + if ( + firstEnumeration.paths.length !== secondEnumeration.paths.length || + firstEnumeration.paths.some( + (path, index) => pathIdentity(path) !== pathIdentity(secondEnumeration.paths[index]), + ) + ) { + throw new Error('source path set changed while fingerprinting'); + } + const second = readSnapshot(cwd, secondEnumeration); + if (first.join('\n') !== second.join('\n')) { + throw new Error('source content changed while fingerprinting'); + } + const digest = createHash('sha256').update(second.join('\n')).digest('hex'); + return `sha256:${digest}`; + } catch (error) { + lastError = error; + } + } + throw new Error( + `[graphSourceFingerprint] UNSTABLE_SOURCE β€” could not capture a stable source snapshot after ${SNAPSHOT_ATTEMPTS} attempts: ${lastError?.message ?? String(lastError)}`, + ); +} + +function parsePorcelainZ(output) { + const records = parseNulRecords(output); + const mutations = []; + for (let index = 0; index < records.length; index += 1) { + const record = records[index]; + if (record.length < 4) throw new Error('git status returned an invalid porcelain record'); + const status = record.subarray(0, 2).toString('ascii'); + const paths = [decodeGitPath(record.subarray(3))]; + if (status[0] === 'R' || status[0] === 'C' || status[1] === 'R' || status[1] === 'C') { + const related = records[++index]; + if (related == null) + throw new Error('git status rename/copy record is missing its peer path'); + paths.push(decodeGitPath(related)); + } + mutations.push(paths); + } + return mutations; +} + +/** + * Git status restricted to relevant source paths; NUL records preserve exact rename endpoints. + * @param {string} cwd + * @returns {{clean: boolean, dirtyPaths: string[]}} + */ +export function checkCleanState(cwd = ROOT) { + const statusOutput = execFileSync( + 'git', + ['status', '--porcelain=v1', '-z', '--untracked-files=all'], + { cwd, encoding: 'buffer' }, + ); + const dirtyPaths = [ + ...new Set( + parsePorcelainZ(statusOutput) + .filter((paths) => paths.some((relPath) => !isExcluded(relPath))) + .flat() + .map(pathLabel), + ), + ]; + return { clean: dirtyPaths.length === 0, dirtyPaths }; +} + +/** Standard metadata block embedded in both committed reports β€” no timestamp, no commit SHA. */ +export function buildMetadataBlock({ + tool, + toolVersion, + generationMode, + reportSchemaVersion, + cwd = ROOT, + fingerprint, +}) { + const validatedFingerprint = fingerprint ?? computeSourceFingerprint(cwd); + return [ + `Report schema: ${reportSchemaVersion}`, + `Source fingerprint: ${validatedFingerprint}`, + `Tool: ${tool}`, + `Tool version: ${toolVersion}`, + `Generation mode: ${generationMode}`, + ].join('\n'); +} + +if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) { + const { clean, dirtyPaths } = checkCleanState(); + console.log(`Source fingerprint: ${computeSourceFingerprint()}`); + console.log(clean ? 'Clean state: YES' : `Clean state: NO (dirty: ${dirtyPaths.join(', ')})`); +} diff --git a/scripts/graphify-bootstrap.mjs b/scripts/graphify-bootstrap.mjs index e4c0aefa..56449351 100644 --- a/scripts/graphify-bootstrap.mjs +++ b/scripts/graphify-bootstrap.mjs @@ -1,15 +1,24 @@ #!/usr/bin/env node /** - * One-shot: pip install graphifyy (official PyPI name has double "y"). - * Run once per machine, then `pnpm run graphify:update`. - * See docs/graphify.md + * Install graphifyy at the exact version pinned in config/graph-tools-versions.json. + * Tries uv, then pipx, then pip (in that priority order) β€” whichever is available on this + * machine β€” always the pinned version. Never falls through to an unpinned "latest" install; + * fails loudly instead so version drift is a visible decision, not a silent side effect. + * Run once per machine, then `pnpm run graphify:update`. See docs/graphify.md */ import { spawnSync } from 'node:child_process'; +import { existsSync, readFileSync } from 'node:fs'; +import { join } from 'node:path'; +import { fileURLToPath, pathToFileURL } from 'node:url'; +import { matchesExactVersion } from './graphSourceFingerprint.mjs'; -const pipInstall = ['-m', 'pip', 'install', '--upgrade', 'graphifyy']; +const root = join(fileURLToPath(new URL('.', import.meta.url)), '..'); +const policy = JSON.parse(readFileSync(join(root, 'config', 'graph-tools-versions.json'), 'utf-8')); +const version = policy.graphifyy.testedVersion; +const pinnedSpec = `graphifyy==${version}`; /** @param {string} cmd @param {string[]} args */ -function pip(cmd, args) { +function run(cmd, args) { return spawnSync(cmd, args, { stdio: 'inherit', shell: process.platform === 'win32', @@ -17,20 +26,200 @@ function pip(cmd, args) { }); } -for (const py of process.platform === 'win32' ? ['python', 'python3'] : ['python3', 'python']) { - const r = pip(py, pipInstall); - if (r.status === 0) process.exit(0); +/** @param {string} cmd @param {string[]} args */ +function capture(cmd, args) { + return spawnSync(cmd, args, { + encoding: 'utf-8', + env: process.env, + shell: process.platform === 'win32', + stdio: ['ignore', 'pipe', 'pipe'], + }); +} + +function quoteWindowsCommandArg(value) { + if (/\r|\n/.test(value)) throw new Error('Windows command arguments cannot contain newlines'); + return `"${value.replaceAll('"', '\\"')}"`; +} + +function runResolvedCommand(command, args, options = {}) { + const isWindowsShim = process.platform === 'win32' && command.toLowerCase().endsWith('.cmd'); + const invocation = isWindowsShim + ? { + command: process.env.ComSpec ?? 'cmd.exe', + args: ['/d', '/s', '/c', `"${[command, ...args].map(quoteWindowsCommandArg).join(' ')}"`], + } + : { command, args }; + return spawnSync(invocation.command, invocation.args, { + ...options, + encoding: 'utf-8', + env: process.env, + shell: false, + }); } -if (process.platform === 'win32') { - const r = pip('py', ['-3', ...pipInstall]); - if (r.status === 0) process.exit(0); +/** + * Resolve the launcher selected by an installer, retaining its path even when its bin directory + * is not present in PATH. The fallback wrapper remains the compatibility path for pip installs. + */ +export function resolveGraphifyExecutable() { + for (const installer of ['uv', 'pipx']) { + const executable = resolveInstallerExecutable(installer); + if (executable) return executable; + } + return process.platform === 'win32' ? 'graphify.exe' : 'graphify'; } -process.stderr.write( - `[graphify-bootstrap] Could not install graphifyy.\n` + - `Install Python 3.11+ from https://www.python.org/downloads/ (enable β€œAdd to PATH”), then:\n` + - ` python -m pip install --upgrade graphifyy\n` + - `PyPI package name is graphifyy (two y’s), CLI command remains: graphify\n`, -); -process.exit(1); +/** @param {string[]} args @param {import('node:child_process').SpawnSyncOptions} [options] */ +export function runGraphifyCommand(args, options = {}) { + const executable = resolveGraphifyExecutable(); + const result = runResolvedCommand(executable, args, options); + if (!result.error && result.status !== 127 && result.status !== 9009) return result; + return spawnSync(process.execPath, [join(root, 'scripts', 'graphify-cli.mjs'), ...args], { + ...options, + env: process.env, + }); +} + +// QNBS-v3: verify Python fallback installs through the interpreter that installed Graphify. +export const graphifyVersionCommand = (tool) => + tool === 'py' ? ['-3', '-m', 'graphify', '--version'] : ['-m', 'graphify', '--version']; + +function isUnavailable(result) { + return ( + result.error?.code === 'ENOENT' || + result.status === 127 || + result.status === 9009 || + /No module named ["']?pip["']?/i.test(`${result.stdout ?? ''}\n${result.stderr ?? ''}`) + ); +} + +/** + * @param {'uv'|'pipx'} installer + * @param {string} binDirectory + * @param {NodeJS.Platform} [platform] + */ +function installerExecutableCandidates(installer, binDirectory, platform = process.platform) { + if (installer !== 'uv' && installer !== 'pipx') return []; + const names = platform === 'win32' ? ['graphify.exe', 'graphify.cmd', 'graphify'] : ['graphify']; + return names.map((name) => join(binDirectory, name)); +} + +/** @param {'uv'|'pipx'} installer */ +function installerBinDirectory(installer) { + const args = + installer === 'uv' ? ['tool', 'dir', '--bin'] : ['environment', '--value', 'PIPX_BIN_DIR']; + const result = capture(installer, args); + if (result.status !== 0 || result.error) return null; + const binDirectory = result.stdout?.trim(); + return binDirectory || null; +} + +/** @param {'uv'|'pipx'} installer */ +function resolveInstallerExecutable(installer) { + const binDirectory = installerBinDirectory(installer); + if (!binDirectory) return null; + return ( + installerExecutableCandidates(installer, binDirectory).find((candidate) => + existsSync(candidate), + ) ?? null + ); +} + +/** @param {'uv'|'pipx'} installer */ +function verifyInstallerExecutable(installer) { + const executable = resolveInstallerExecutable(installer); + if (!executable) { + return { + status: 1, + output: '', + error: `could not resolve graphify from ${installer}'s application-bin directory`, + }; + } + const result = runResolvedCommand(executable, ['--version']); + return { + status: result.status, + output: `${result.stdout ?? ''}\n${result.stderr ?? ''}`, + error: result.error?.message ?? '', + }; +} + +const attempts = [ + { tool: 'uv', args: ['tool', 'install', '--force', pinnedSpec] }, + { tool: 'pipx', args: ['install', '--force', pinnedSpec] }, + ...(process.platform === 'win32' + ? [ + { tool: 'python', args: ['-m', 'pip', 'install', pinnedSpec] }, + { tool: 'python3', args: ['-m', 'pip', 'install', pinnedSpec] }, + { tool: 'py', args: ['-3', '-m', 'pip', 'install', pinnedSpec] }, + ] + : [ + { tool: 'python3', args: ['-m', 'pip', 'install', pinnedSpec] }, + { tool: 'python', args: ['-m', 'pip', 'install', pinnedSpec] }, + ]), +]; + +function main() { + for (const { tool, args } of attempts) { + if (tool === 'python' || tool === 'python3' || tool === 'py') { + const pipArgs = tool === 'py' ? ['-3', '-m', 'pip', '--version'] : ['-m', 'pip', '--version']; + const pipProbe = capture(tool, pipArgs); + if (isUnavailable(pipProbe)) continue; + if (pipProbe.status !== 0 || pipProbe.error) { + process.stderr.write( + `[graphify-bootstrap] ${tool} could not verify its pip module; refusing an unintended fallback.\n`, + ); + process.exit(pipProbe.status ?? 1); + } + } + const result = run(tool, args); + if (result.error?.code && result.error.code !== 'ENOENT') { + process.stderr.write(`[graphify-bootstrap] ${tool} failed: ${result.error.message}\n`); + process.exit(1); + } + if (result.status !== 0 && !isUnavailable(result)) { + process.stderr.write( + `[graphify-bootstrap] ${tool} could not install ${pinnedSpec}; refusing an unintended fallback.\n`, + ); + process.exit(result.status ?? 1); + } + if (isUnavailable(result)) continue; + if (result.status === 0) { + // QNBS-v3: verify the installer-owned executable so PATH drift cannot mask version mismatches. + const verify = + tool === 'uv' || tool === 'pipx' + ? verifyInstallerExecutable(tool) + : (() => { + const fallback = runResolvedCommand(tool, graphifyVersionCommand(tool)); + return { + status: fallback.status, + output: `${fallback.stdout ?? ''}\n${fallback.stderr ?? ''}`, + error: fallback.error?.message ?? '', + }; + })(); + if (verify.status === 0 && matchesExactVersion(verify.output, version)) { + console.log(`[graphify-bootstrap] Installed ${pinnedSpec} via ${tool} (verified).`); + process.exit(0); + } + process.stderr.write( + `[graphify-bootstrap] ${tool} installed ${pinnedSpec}, but its resolved launcher did not verify version ${version}.` + + (verify.error ? ` ${verify.error}` : '') + + '\n', + ); + process.exit(1); + } + } + + process.stderr.write( + `[graphify-bootstrap] Could not install ${pinnedSpec} via uv, pipx, or pip.\n` + + `Install one of those tools, or install manually:\n` + + ` uv tool install --force ${pinnedSpec}\n` + + ` pipx install --force ${pinnedSpec}\n` + + ` python -m pip install ${pinnedSpec}\n` + + `PyPI package name is graphifyy (two y's), CLI command remains: graphify\n`, + ); + process.exit(1); +} + +if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) { + main(); +} diff --git a/scripts/graphify-report.mjs b/scripts/graphify-report.mjs new file mode 100644 index 00000000..d1552253 --- /dev/null +++ b/scripts/graphify-report.mjs @@ -0,0 +1,325 @@ +#!/usr/bin/env node +/** + * Regenerates graphify-out/GRAPH_REPORT.md as a compact, bounded, deterministic public report. + * + * Graphify's own `graphify update .` writes a native GRAPH_REPORT.md directly (not something this + * repo authors from scratch) β€” but on a corpus this size that native report lists every single + * community in full (thousands of lines), which is too large and noisy to keep committed. This + * script runs the native update, then post-processes its output: keeps the small architecture-level + * sections as-is, truncates the community list to the top N by node count, and prepends this repo's + * own fingerprint-based freshness metadata (authoritative β€” graphify's own "Built from commit" line + * is informational only, see `graphs:status`). Full untruncated data stays local in + * graphify-out/graph.json / graph.html (gitignored) β€” rebuild anytime with `pnpm run graphify:update`. + * + * Fails loudly on any real failure. Gated on a clean source tree (DIRTY_UNTRACKED_INPUT refuses to + * write) so the embedded fingerprint always matches a committable state. + */ +import { existsSync, readFileSync, renameSync, rmSync, writeFileSync } from 'node:fs'; +import { join } from 'node:path'; +import { pathToFileURL } from 'node:url'; +import { sanitize } from './codegraph-report.mjs'; +import { runGraphifyCommand } from './graphify-bootstrap.mjs'; +import { + buildMetadataBlock, + checkCleanState, + computeSourceFingerprint, + matchesExactVersion, + ROOT, +} from './graphSourceFingerprint.mjs'; + +const REPORT_PATH = join(ROOT, 'graphify-out', 'GRAPH_REPORT.md'); +const PREVIOUS_COMPACT_BACKUP = `${REPORT_PATH}.previous-compact`; +const TOP_N_COMMUNITIES = 20; + +function loadPolicy() { + return JSON.parse(readFileSync(join(ROOT, 'config', 'graph-tools-versions.json'), 'utf-8')); +} + +// QNBS-v3: validate compact report structure before recovering or replacing transaction state. +export function isValidCompactReport(path) { + try { + const report = readFileSync(path, 'utf-8'); + return ( + report.startsWith('# Graph Report - ') && + /Report schema:\s*\d+/.test(report) && + /Source fingerprint:\s*sha256:[0-9a-f]{64}/.test(report) && + /Tool version:\s*\S+/.test(report) && + report.includes('\n\n## Summary\n') && + /^## Top \d+ Communities by size \(of \d+ total\)$/m.test(report) + ); + } catch { + return false; + } +} + +export function recoverOrphanedCompactReport(reportPath, backupPath) { + if (!existsSync(backupPath)) return false; + if (!isValidCompactReport(backupPath)) { + throw new Error('orphaned compact-report backup is invalid; refusing to discard it'); + } + if (existsSync(reportPath) && isValidCompactReport(reportPath)) return false; + // QNBS-v3: prefer the last valid compact snapshot over an interrupted native primary. + rmSync(reportPath, { force: true }); + // QNBS-v3: recover the last valid compact snapshot before opening a new transaction. + renameSync(backupPath, reportPath); + return true; +} + +function preparePreviousReport() { + recoverOrphanedCompactReport(REPORT_PATH, PREVIOUS_COMPACT_BACKUP); + const hadBackup = existsSync(REPORT_PATH); + if (existsSync(PREVIOUS_COMPACT_BACKUP)) { + if (!isValidCompactReport(PREVIOUS_COMPACT_BACKUP)) { + throw new Error('existing compact-report backup is invalid; refusing to discard it'); + } + rmSync(PREVIOUS_COMPACT_BACKUP); + } + if (hadBackup) renameSync(REPORT_PATH, PREVIOUS_COMPACT_BACKUP); + return hadBackup; +} + +function runGraphify(args, options = {}) { + return runGraphifyCommand(args, { cwd: ROOT, env: process.env, ...options }); +} + +function restorePreviousReport(hasBackup) { + rmSync(REPORT_PATH, { force: true }); + if (hasBackup && existsSync(PREVIOUS_COMPACT_BACKUP)) { + renameSync(PREVIOUS_COMPACT_BACKUP, REPORT_PATH); + } +} + +function parseProjectName() { + try { + const packageJson = JSON.parse(readFileSync(join(ROOT, 'package.json'), 'utf-8')); + return packageJson.name ?? 'project'; + } catch (error) { + throw new Error(`could not parse package.json: ${error?.message ?? String(error)}`); + } +} + +function reuseTopology(previous, titleLine, metadata) { + const generationMarker = previous.indexOf('Generation mode:'); + const bodyStart = previous.indexOf('\n\n', generationMarker); + if (!previous.startsWith('# Graph Report - ') || generationMarker < 0 || bodyStart < 0) { + throw new Error('previous compact report has invalid metadata and cannot be reused'); + } + return `${titleLine}\n\n${metadata}${previous.slice(bodyStart)}`; +} + +function writeCandidate(report) { + const candidate = `${REPORT_PATH}.tmp-${process.pid}`; + try { + writeFileSync(candidate, report); + renameSync(candidate, REPORT_PATH); + } catch (error) { + rmSync(candidate, { force: true }); + throw error; + } +} + +export function generateReport() { + let policy; + try { + policy = loadPolicy(); + } catch (error) { + console.error( + `[graphify-report] FAIL β€” could not parse graph-tools-versions.json: ${error.message}`, + ); + return 1; + } + const expectedVersion = policy.graphifyy.testedVersion; + const initialState = checkCleanState(); + if (!initialState.clean) { + console.error( + `[graphify-report] DIRTY_UNTRACKED_INPUT β€” refusing to write a committed report from an ` + + `unstable source state. Commit or stash first:\n ${initialState.dirtyPaths.join('\n ')}`, + ); + return 1; + } + + let fingerprintBefore; + try { + fingerprintBefore = computeSourceFingerprint(); + } catch (error) { + console.error(`[graphify-report] FAIL β€” ${error.message}`); + return 1; + } + + let projectName; + try { + projectName = parseProjectName(); + } catch (error) { + console.error(`[graphify-report] FAIL β€” ${error.message}`); + return 1; + } + const titleLine = `# Graph Report - ${projectName}`; + let hadBackup; + try { + hadBackup = preparePreviousReport(); + } catch (error) { + console.error(`[graphify-report] FAIL β€” ${error?.message ?? String(error)}`); + return 1; + } + try { + if (process.env.GRAPHIFY_SKIP === '1') { + throw new Error('GRAPHIFY_SKIP=1 is not valid for strict report generation'); + } + const updateResult = runGraphify(['update', '.'], { stdio: 'inherit' }); + if (updateResult.status !== 0) { + throw new Error('graphify update did not complete successfully'); + } + + const versionResult = runGraphify(['--version'], { + encoding: 'utf-8', + stdio: ['ignore', 'pipe', 'pipe'], + }); + const versionOutput = `${versionResult.stdout ?? ''}\n${versionResult.stderr ?? ''}`; + if (versionResult.status !== 0 || !matchesExactVersion(versionOutput, expectedVersion)) { + throw new Error( + `Graphify version mismatch: expected ${expectedVersion}, got ${versionOutput.trim() || '(no output)'}`, + ); + } + + if (computeSourceFingerprint() !== fingerprintBefore || !checkCleanState().clean) { + throw new Error('SOURCE_CHANGED_DURING_REPORT β€” source changed during Graphify generation'); + } + + let native; + if (existsSync(REPORT_PATH)) { + native = sanitize(readFileSync(REPORT_PATH, 'utf-8')); + } else if (hadBackup && isValidCompactReport(PREVIOUS_COMPACT_BACKUP)) { + const metadata = buildMetadataBlock({ + tool: 'graphify', + toolVersion: expectedVersion, + generationMode: 'AST-only local build (graphify update .)', + reportSchemaVersion: policy.reportSchemaVersion, + fingerprint: fingerprintBefore, + }); + native = reuseTopology(readFileSync(PREVIOUS_COMPACT_BACKUP, 'utf-8'), titleLine, metadata); + writeCandidate(native); + if (computeSourceFingerprint() !== fingerprintBefore || !checkCleanState().clean) { + throw new Error('SOURCE_CHANGED_DURING_REPORT β€” source changed before metadata refresh'); + } + rmSync(PREVIOUS_COMPACT_BACKUP, { force: true }); + console.log( + '[graphify-report] PASS β€” no topology change; compact report metadata refreshed.', + ); + return 0; + } else if (hadBackup) { + throw new Error('previous compact report is invalid; refusing topology reuse'); + } else { + throw new Error('graphify wrote no native report and no previous compact report exists'); + } + + if (!validateNativeGraphifyReport(native)) { + throw new Error('Graphify native report is missing a valid Communities (...) section'); + } + const sections = splitSections(native); + const KEEP_AS_IS = [ + 'Corpus Check', + 'Summary', + 'God Nodes', + 'Surprising Connections', + 'Import Cycles', + 'Knowledge Gaps', + 'Suggested Questions', + ]; + const communitiesSection = findSection(sections, 'Communities ('); + let compactCommunitiesBlock = ''; + let totalCommunities = 0; + let keptCommunities = 0; + if (communitiesSection) { + const totalMatch = communitiesSection.heading.match(/\((\d+) total/); + totalCommunities = totalMatch ? Number(totalMatch[1]) : 0; + const blocks = communitiesSection.body + .join('\n') + .split(/(?=^### )/m) + .map((block) => block.trim()) + .filter(Boolean); + const ranked = blocks + .map((block) => { + const nodeCountMatch = block.match(/Nodes \((\d+)\):/); + return { block, nodeCount: nodeCountMatch ? Number(nodeCountMatch[1]) : 0 }; + }) + .sort((a, b) => b.nodeCount - a.nodeCount); + const top = ranked.slice(0, TOP_N_COMMUNITIES); + keptCommunities = top.length; + compactCommunitiesBlock = top.map((community) => community.block).join('\n\n'); + } + const omittedCount = Math.max(0, totalCommunities - keptCommunities); + const communitiesHeading = `## Top ${keptCommunities} Communities by size (of ${totalCommunities} total)`; + const communitiesNote = + omittedCount > 0 + ? `\n\n_${omittedCount} smaller communities omitted from this committed summary β€” full detail in local graphify-out/graph.json / graph.html (gitignored, not committed). Rebuild anytime: \`pnpm run graphify:update\`._` + : ''; + const metadata = buildMetadataBlock({ + tool: 'graphify', + toolVersion: expectedVersion, + generationMode: 'AST-only local build (graphify update .)', + reportSchemaVersion: policy.reportSchemaVersion, + fingerprint: fingerprintBefore, + }); + const keptSectionsMarkdown = KEEP_AS_IS.map((heading) => { + const section = findSection(sections, heading); + return section ? `## ${section.heading}\n${section.body.join('\n').trim()}` : null; + }) + .filter(Boolean) + .join('\n\n'); + const report = `${titleLine}\n\n${metadata}\n\n${keptSectionsMarkdown}\n\n${communitiesHeading}${communitiesNote}\n\n${compactCommunitiesBlock}\n`; + writeCandidate(report); + if (computeSourceFingerprint() !== fingerprintBefore || !checkCleanState().clean) { + throw new Error('SOURCE_CHANGED_DURING_REPORT β€” source changed before report commit'); + } + rmSync(PREVIOUS_COMPACT_BACKUP, { force: true }); + console.log( + `[graphify-report] PASS β€” ${REPORT_PATH} generated (${keptCommunities}/${totalCommunities} communities kept).`, + ); + return 0; + } catch (error) { + restorePreviousReport(hadBackup); + console.error(`[graphify-report] FAIL β€” ${error?.message ?? String(error)}`); + return 1; + } +} + +/** Split the native report into ordered sections keyed by their `## Heading` line. */ +function splitSections(markdown) { + const lines = markdown.split('\n'); + /** @type {{heading: string, body: string[]}[]} */ + const sections = [{ heading: '__preamble__', body: [] }]; + for (const line of lines) { + if (line.startsWith('## ')) { + sections.push({ heading: line.slice(3).trim(), body: [] }); + } else { + sections[sections.length - 1].body.push(line); + } + } + return sections; +} + +function findSection(sections, headingPrefix) { + return sections.find((s) => s.heading.startsWith(headingPrefix)); +} + +// QNBS-v3: reject native Graphify output that cannot provide a trustworthy community snapshot. +export function validateNativeGraphifyReport(markdown) { + if (typeof markdown !== 'string') return false; + const sections = splitSections(markdown); + const communities = findSection(sections, 'Communities ('); + const totalMatch = communities?.heading.match( + /^Communities \((\d+) total(?:, (\d+) thin omitted)?\)$/, + ); + const total = totalMatch ? Number(totalMatch[1]) : 0; + const thin = totalMatch?.[2] == null ? 0 : Number(totalMatch[2]); + const hubs = findSection(sections, 'Community Hubs ('); + const hubCount = hubs?.body.filter((line) => line.startsWith('- ')).length ?? (total ? null : 0); + const blockCount = communities?.body.filter((line) => line.startsWith('### ')).length; + const validCounts = + hubCount != null && thin <= hubCount && hubCount <= total && blockCount === hubCount - thin; + return Boolean(totalMatch && validCounts && findSection(sections, 'Summary')); +} + +if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) { + process.exit(generateReport()); +} diff --git a/scripts/graphs-cli.mjs b/scripts/graphs-cli.mjs new file mode 100644 index 00000000..e4e78c7a --- /dev/null +++ b/scripts/graphs-cli.mjs @@ -0,0 +1,431 @@ +#!/usr/bin/env node +/** + * Dual-graph orchestration CLI: `node scripts/graphs-cli.mjs `. + * + * Every command's mutation scope is unambiguous: + * bootstrap β€” installs both tools at their pinned versions. Never touches the repo. + * doctor β€” read-only diagnostics. No mutation. + * status β€” fast, read-only freshness check. No mutation. + * update β€” updates LOCAL RUNTIME STATE only (Graphify build, CodeGraph incremental sync). + * Never touches the committed report files. + * report β€” the ONLY command that writes graphify-out/GRAPH_REPORT.md or + * .codegraph/CODEGRAPH_REPORT.md. Gated on a clean source tree. + * refresh β€” update then report, strict: fails non-zero if either tool can't update or + * report generation is refused/fails. This is what PR preparation runs. + * + * Status vocabulary: PASS, UPDATED, FRESH, STALE, VERSION_MISMATCH, SKIPPED_NOT_INSTALLED, + * SKIPPED_NOT_INITIALIZED, SKIPPED_NOT_CONFIGURED, DIRTY_UNTRACKED_INPUT, FAIL. An installed tool + * returning non-zero is always FAIL. No command ever prints a success epilogue after a swallowed + * failure. + */ +import { spawnSync } from 'node:child_process'; +import { existsSync, readFileSync, renameSync, rmSync } from 'node:fs'; +import { join } from 'node:path'; +import { pathToFileURL } from 'node:url'; +import { executeCodegraph } from './codegraph-report.mjs'; +import { runGraphifyCommand } from './graphify-bootstrap.mjs'; +import { recoverOrphanedCompactReport } from './graphify-report.mjs'; +import { + checkCleanState, + computeSourceFingerprint, + matchesExactVersion, + ROOT, +} from './graphSourceFingerprint.mjs'; + +const POLICY_PATH = join(ROOT, 'config', 'graph-tools-versions.json'); +const GRAPHIFY_OUTPUT_DIR = join(ROOT, 'graphify-out'); +const GRAPHIFY_REPORT = join(ROOT, 'graphify-out', 'GRAPH_REPORT.md'); +const GRAPHIFY_REPORT_BACKUP = `${GRAPHIFY_REPORT}.previous-compact`; +const CODEGRAPH_REPORT = join(ROOT, '.codegraph', 'CODEGRAPH_REPORT.md'); +const CODEGRAPH_DB = join(ROOT, '.codegraph', 'codegraph.db'); +const GRAPHIFY_EPHEMERAL_OUTPUTS = [ + 'manifest.json', + 'cost.json', + 'transcripts', + 'wiki', + 'obsidian', +]; + +function loadPolicy() { + return JSON.parse(readFileSync(POLICY_PATH, 'utf-8')); +} + +function runNode(script, args = [], options = {}) { + return spawnSync(process.execPath, [join(ROOT, 'scripts', script), ...args], { + cwd: ROOT, + stdio: 'inherit', + env: process.env, + ...options, + }); +} + +export function isSupportedCommand(command, availableCommands) { + return Boolean(command) && Object.hasOwn(availableCommands, command); +} + +export function strictRefreshFailure({ updateStatus, reportStatus, reportsFresh }) { + if (updateStatus !== 0) return 'update stage failed'; + if (reportStatus !== 0) return 'report stage failed'; + if (!reportsFresh) return 'final freshness check failed'; + return null; +} + +export function shouldSkipGraphifyUpdate(args, env = process.env) { + return args[0] === 'update' && env.GRAPHIFY_SKIP === '1'; +} + +// QNBS-v3: keep the routed dual-graph update from retaining stale Graphify sidecars. +export function cleanupGraphifyEphemeralOutputs(outputDir = GRAPHIFY_OUTPUT_DIR) { + for (const name of GRAPHIFY_EPHEMERAL_OUTPUTS) { + rmSync(join(outputDir, name), { recursive: true, force: true }); + } +} + +function runTool(command, args, options = {}) { + if (command === 'codegraph') return executeCodegraph(args, options); + if (command === 'graphify') return runGraphifyCommand(args, options); + return spawnSync(command, args, { cwd: ROOT, env: process.env, ...options }); +} + +export function versionProbeStatus(result) { + if (result.error?.code === 'ENOENT') return 'SKIPPED_NOT_INSTALLED'; + if (result.error || result.status == null || result.status !== 0) return 'FAIL'; + return `${result.stdout ?? ''}\n${result.stderr ?? ''}`.trim() ? 'AVAILABLE' : 'FAIL'; +} + +function commandVersion(cmd, args = ['--version']) { + const result = runTool(cmd, args, { encoding: 'utf-8', stdio: ['ignore', 'pipe', 'pipe'] }); + return { + status: versionProbeStatus(result), + output: `${result.stdout ?? ''}\n${result.stderr ?? ''}`.trim() || null, + exitCode: result.status, + }; +} + +function requireToolVersion(command, expected) { + const probe = commandVersion(command); + if (probe.status === 'SKIPPED_NOT_INSTALLED') throw new Error(`${command} is not available`); + if (probe.status === 'FAIL') { + throw new Error(`${command} version probe failed (exit ${probe.exitCode ?? 'null'})`); + } + if (!matchesExactVersion(probe.output, expected)) { + throw new Error(`${command} version mismatch: expected ${expected}, got ${probe.output}`); + } + return probe.output; +} + +export function prepareGraphifyReportBackup( + reportPath = GRAPHIFY_REPORT, + backupPath = GRAPHIFY_REPORT_BACKUP, +) { + recoverOrphanedCompactReport(reportPath, backupPath); + // QNBS-v3: runtime-only updates preserve report bytes even when the prior report is invalid. + const hadReport = existsSync(reportPath); + if (existsSync(backupPath)) { + // The recovery helper has validated this backup; replacing it is safe only after validation. + rmSync(backupPath); + } + if (hadReport) renameSync(reportPath, backupPath); + return hadReport; +} + +export function restoreGraphifyReportBackup( + hadReport, + reportPath = GRAPHIFY_REPORT, + backupPath = GRAPHIFY_REPORT_BACKUP, +) { + rmSync(reportPath, { force: true }); + if (hadReport) { + if (!existsSync(backupPath)) { + throw new Error('recoverable compact Graphify report backup is missing'); + } + renameSync(backupPath, reportPath); + } +} + +/** Extracts the first `Report schema: N` / `Source fingerprint: sha256:...` / `Tool version: X` + * lines from a committed report's metadata block. Returns null fields if the report is absent. */ +function readReportMetadata(path) { + if (!existsSync(path)) return { exists: false }; + const text = readFileSync(path, 'utf-8'); + const schema = text.match(/Report schema:\s*(\S+)/)?.[1] ?? null; + const fingerprint = text.match(/Source fingerprint:\s*(\S+)/)?.[1] ?? null; + const toolVersion = text.match(/Tool version:\s*(\S+)/)?.[1] ?? null; + const tool = text.match(/Tool:\s*(\S+)/)?.[1] ?? null; + return { exists: true, schema, fingerprint, toolVersion, tool, text }; +} + +export function validateReportStructure(text, tool) { + if (typeof text !== 'string') return false; + if (tool === 'graphify') { + return ( + text.startsWith('# Graph Report - ') && + text.includes('\n\n## Summary\n') && + /^## Top \d+ Communities by size \(of \d+ total\)$/m.test(text) + ); + } + if (tool === 'codegraph') { + const statusMatch = text.match( + /^# CodeGraph Report\n\n[\s\S]*?\n\n## Status\n\n```text\nInitialized: yes\nVersion: \S+\nFiles: (\d+)\nNodes: \d+\nEdges: \d+\nPending changes: \{"added":0,"modified":0,"removed":0\}\nWorktree mismatch: (?:none|\S+)\nIndex built with: \S+\nReindex required: no\n```\n\n## Files by Extension\n\n([\s\S]*?)\n\n---\n\n\*Regenerate with: `pnpm run graphs:report`[\s\S]*$/, + ); + if (!statusMatch) return false; + + const fileCount = Number(statusMatch[1]); + const extensionLines = statusMatch[2].trim() ? statusMatch[2].trim().split('\n') : []; + const extensionCounts = extensionLines.map((line) => { + const match = line.match( + /^- \*\*\.(?:[\p{L}\p{N}_$@%/,=?^ ]|\\[\\`*_{}[\]()#+.!|>~-])+\*\*: (\d+)$/u, + ); + if (!match) return null; + return Number(match[1]); + }); + return ( + extensionLines.length === extensionCounts.length && + extensionCounts.every((count) => count != null && count > 0) && + extensionCounts.reduce((total, count) => total + count, 0) === fileCount + ); + } + return false; +} + +// QNBS-v3: classify reports from schema, exact tool version, and current source fingerprint. +export function reportFreshness(meta, options, fingerprint) { + const { reportSchemaVersion: schema, expectedVersion: version, expectedTool: tool } = options; + if (!meta.exists) return 'MISSING'; + if (meta.schema !== String(schema) || meta.toolVersion !== version) return 'VERSION_MISMATCH'; + if (meta.fingerprint !== fingerprint) return 'STALE'; + if (meta.tool !== tool) return 'REPORT_INVALID'; + return validateReportStructure(meta.text, tool) ? 'FRESH' : 'REPORT_INVALID'; +} + +function doctor() { + const policy = loadPolicy(); + const graphifyVersion = commandVersion('graphify'); + const codegraphVersion = commandVersion('codegraph'); + const codegraphInitialized = existsSync(CODEGRAPH_DB); + + const versionLabel = (probe) => { + if (probe.status === 'SKIPPED_NOT_INSTALLED') return 'SKIPPED_NOT_INSTALLED'; + if (probe.status === 'FAIL') return `FAIL (version probe exit ${probe.exitCode ?? 'null'})`; + return `installed ${probe.output}`; + }; + + console.log('=== graphs:doctor ==='); + console.log( + `graphifyy: ${versionLabel(graphifyVersion)} ` + + `(policy: ${policy.graphifyy.testedVersion}, ${policy.graphifyy.policy})`, + ); + if ( + graphifyVersion.status === 'AVAILABLE' && + !matchesExactVersion(graphifyVersion.output, policy.graphifyy.testedVersion) + ) { + console.log(' -> VERSION_MISMATCH (run `pnpm run graphify:bootstrap` to align)'); + } + console.log( + `@colbymchenry/codegraph: ${versionLabel(codegraphVersion)} ` + + `(policy: ${policy.codegraph.testedVersion}, ${policy.codegraph.policy})`, + ); + if ( + codegraphVersion.status === 'AVAILABLE' && + !matchesExactVersion(codegraphVersion.output, policy.codegraph.testedVersion) + ) { + console.log(' -> VERSION_MISMATCH (run `pnpm run codegraph:bootstrap` to align)'); + } + console.log( + `CodeGraph local index: ${codegraphInitialized ? 'PASS (initialized)' : 'SKIPPED_NOT_INITIALIZED'}`, + ); + + const reportPaths = [ + ['Graphify report', GRAPHIFY_REPORT], + ['CodeGraph report', CODEGRAPH_REPORT], + ]; + let currentFingerprint = null; + if (reportPaths.some(([, path]) => existsSync(path))) { + try { + currentFingerprint = computeSourceFingerprint(); + } catch (error) { + console.log(`Report freshness: UNAVAILABLE (${error.message})`); + } + } + for (const [label, path] of reportPaths) { + const meta = readReportMetadata(path); + console.log( + meta.exists + ? `${label}: schema=${meta.schema ?? '?'} toolVersion=${meta.toolVersion ?? '?'} fingerprint=${meta.fingerprint ?? '?'} ` + + `freshness=${currentFingerprint ? reportFreshness(meta, { reportSchemaVersion: policy.reportSchemaVersion, expectedVersion: label.startsWith('Graphify') ? policy.graphifyy.testedVersion : policy.codegraph.testedVersion, expectedTool: label.startsWith('Graphify') ? 'graphify' : 'codegraph' }, currentFingerprint) : 'UNAVAILABLE'}` + : `${label}: SKIPPED_NOT_CONFIGURED (not generated yet)`, + ); + } + + console.log( + 'Privacy: run `graphify --help` / `codegraph telemetry status` to confirm local query-log and ' + + 'telemetry preferences (both local-only, never committed).', + ); +} + +function status() { + const policy = loadPolicy(); + let currentFingerprint; + try { + currentFingerprint = computeSourceFingerprint(); + } catch (error) { + console.error(`[graphs:status] FAIL β€” ${error.message}`); + process.exit(1); + } + const cleanState = checkCleanState(); + let anyStale = false; + if (!cleanState.clean) { + console.log(`Source state: DIRTY_UNTRACKED_INPUT (${cleanState.dirtyPaths.join(', ')})`); + anyStale = true; + } + for (const [label, path] of [ + ['graphify-out/GRAPH_REPORT.md', GRAPHIFY_REPORT], + ['.codegraph/CODEGRAPH_REPORT.md', CODEGRAPH_REPORT], + ]) { + const meta = readReportMetadata(path); + if (!meta.exists) { + console.log(`${label}: MISSING`); + anyStale = true; + continue; + } + const expectedVersion = (label[0] === 'g' ? policy.graphifyy : policy.codegraph).testedVersion; + const freshness = reportFreshness( + meta, + { ...policy, expectedVersion, expectedTool: label[0] === 'g' ? 'graphify' : 'codegraph' }, + currentFingerprint, + ); + if (freshness !== 'FRESH') anyStale = true; + console.log(`${label}: ${freshness}`); + } + process.exit(anyStale ? 1 : 0); +} + +function update() { + const policy = loadPolicy(); + let failed = false; + + if (process.env.GRAPHIFY_SKIP === '1') { + console.error( + '[graphs:update] FAIL β€” GRAPHIFY_SKIP=1 is not valid for strict dual-graph update.', + ); + process.exit(1); + } + try { + requireToolVersion('graphify', policy.graphifyy.testedVersion); + cleanupGraphifyEphemeralOutputs(); + const hadPreviousReport = prepareGraphifyReportBackup(); + try { + const graphifyResult = runTool('graphify', ['update', '.'], { stdio: 'inherit' }); + if (graphifyResult.status !== 0) throw new Error('Graphify update failed'); + restoreGraphifyReportBackup(hadPreviousReport); + } catch (error) { + restoreGraphifyReportBackup(hadPreviousReport); + throw error; + } finally { + cleanupGraphifyEphemeralOutputs(); + } + console.log('[graphs:update] graphify: UPDATED (committed report preserved)'); + } catch (error) { + console.error(`[graphs:update] graphify: FAIL β€” ${error.message}`); + failed = true; + } + + try { + requireToolVersion('codegraph', policy.codegraph.testedVersion); + if (!existsSync(CODEGRAPH_DB)) throw new Error('CodeGraph is not initialized'); + const result = runTool('codegraph', ['sync'], { stdio: 'inherit' }); + if (result.status !== 0) + throw new Error(`CodeGraph sync failed (exit ${result.status ?? 'null'})`); + console.log('[graphs:update] codegraph: UPDATED (sync)'); + } catch (error) { + console.error(`[graphs:update] codegraph: FAIL β€” ${error.message}`); + failed = true; + } + process.exit(failed ? 1 : 0); +} + +function report() { + const policy = loadPolicy(); + try { + requireToolVersion('graphify', policy.graphifyy.testedVersion); + if (!existsSync(CODEGRAPH_DB)) throw new Error('CodeGraph is not initialized'); + requireToolVersion('codegraph', policy.codegraph.testedVersion); + const syncResult = runTool('codegraph', ['sync'], { stdio: 'inherit' }); + if (syncResult.status !== 0) { + throw new Error(`CodeGraph sync failed (exit ${syncResult.status ?? 'null'})`); + } + const graphifyResult = runNode('graphify-report.mjs', [], { stdio: 'inherit' }); + if (graphifyResult.status !== 0) throw new Error('Graphify report generation failed'); + const codegraphResult = runNode('codegraph-report.mjs', [], { stdio: 'inherit' }); + if (codegraphResult.status !== 0) throw new Error('CodeGraph report generation failed'); + if (!existsSync(GRAPHIFY_REPORT) || !existsSync(CODEGRAPH_REPORT)) { + throw new Error('required report is absent after generation'); + } + process.exit(0); + } catch (error) { + console.error(`[graphs:report] FAIL β€” ${error.message}`); + process.exit(1); + } +} + +function refresh() { + console.log( + '[graphs:refresh] strict mode β€” synchronize once, report once, any failure is fatal.', + ); + const reportResult = spawnSync( + process.execPath, + [join(ROOT, 'scripts', 'graphs-cli.mjs'), 'report'], + { + cwd: ROOT, + stdio: 'inherit', + }, + ); + if (reportResult.status !== 0) { + console.error('[graphs:refresh] FAIL β€” synchronized report stage failed.'); + process.exit(1); + } + const statusResult = spawnSync( + process.execPath, + [join(ROOT, 'scripts', 'graphs-cli.mjs'), 'status'], + { cwd: ROOT, stdio: 'inherit', env: process.env }, + ); + if (statusResult.status !== 0) { + console.error('[graphs:refresh] FAIL β€” final freshness check failed.'); + process.exit(1); + } + console.log('[graphs:refresh] PASS'); +} + +function bootstrap() { + const graphifyResult = runNode('graphify-bootstrap.mjs'); + const codegraphResult = runNode('codegraph-bootstrap.mjs'); + const failed = graphifyResult.status !== 0 || codegraphResult.status !== 0; + process.exit(failed ? 1 : 0); +} + +function graphify(args) { + if (shouldSkipGraphifyUpdate(args)) { + console.log('[graphs:graphify] Skipped (GRAPHIFY_SKIP=1).'); + process.exit(0); + } + const result = runTool('graphify', args, { stdio: 'inherit' }); + process.exit(result.status ?? 1); +} + +// QNBS-v3: route direct CodeGraph scripts through the verified resolver on every platform. +function codegraph(args) { + const result = executeCodegraph(args, { stdio: 'inherit' }); + process.exit(result.status ?? 1); +} + +const commands = { bootstrap, doctor, status, update, report, refresh, codegraph, graphify }; + +if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) { + const command = process.argv[2]; + if (!isSupportedCommand(command, commands)) { + console.error(`Usage: node scripts/graphs-cli.mjs <${Object.keys(commands).join('|')}>`); + process.exit(1); + } + if (command === 'codegraph' || command === 'graphify') commands[command](process.argv.slice(3)); + else commands[command](); +} diff --git a/scripts/pre-commit-codegraph.mjs b/scripts/pre-commit-codegraph.mjs deleted file mode 100644 index 5019eb5e..00000000 --- a/scripts/pre-commit-codegraph.mjs +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env node -/** - * Optional pre-commit helper: runs codegraph affected and logs a reminder. - * Not enforced by default to keep commits fast. Exit code is always 0. - * QNBS-v3: informative only; does not block commits. - */ -import { execSync } from 'node:child_process'; -import { existsSync } from 'node:fs'; - -if (!existsSync('.codegraph/codegraph.db')) { - console.log('ℹ️ CodeGraph not initialized. Skipping affected-test analysis.'); - process.exit(0); -} - -try { - const affected = execSync('git diff --cached --name-only | codegraph affected --stdin --quiet', { - encoding: 'utf-8', - stdio: ['pipe', 'pipe', 'ignore'], - }); - if (affected.trim()) { - console.log('πŸ§ͺ CodeGraph detected affected test files:'); - console.log(affected); - console.log(`Run: pnpm exec vitest run ${affected.trim().split('\n').join(' ')}`); - } -} catch { - // Silently ignore if codegraph CLI is not on PATH or fails - process.exit(0); -} diff --git a/tests/unit/scripts/codegraphReport.test.ts b/tests/unit/scripts/codegraphReport.test.ts new file mode 100644 index 00000000..c8f7ba71 --- /dev/null +++ b/tests/unit/scripts/codegraphReport.test.ts @@ -0,0 +1,431 @@ +// @vitest-environment node + +import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; +import { afterEach, describe, expect, it } from 'vitest'; +// QNBS-v3: focused tests protect committed-report privacy, freshness, and strict orchestration. +import { + formatExtensionLines, + redactPaths, + sanitize, + validateFileList, + validateIndexStatus, +} from '../../../scripts/codegraph-report.mjs'; +import { ROOT } from '../../../scripts/graphSourceFingerprint.mjs'; + +const graphsCliModulePath = ['..', '..', '..', 'scripts', 'graphs-cli.mjs'].join('/'); +const graphsCli = (await import(graphsCliModulePath)) as unknown as { + isSupportedCommand: (command: string, availableCommands: object) => boolean; + strictRefreshFailure: (outcome: { + updateStatus: number; + reportStatus: number; + reportsFresh: boolean; + }) => string | null; + versionProbeStatus: (result: { + status: number | null; + stdout?: string; + stderr?: string; + error?: { code?: string }; + }) => string; + shouldSkipGraphifyUpdate: (args: string[], env?: NodeJS.ProcessEnv) => boolean; + prepareGraphifyReportBackup: (reportPath?: string, backupPath?: string) => boolean; + cleanupGraphifyEphemeralOutputs: (outputDir?: string) => void; + restoreGraphifyReportBackup: ( + hadReport: boolean, + reportPath?: string, + backupPath?: string, + ) => void; + reportFreshness: ( + meta: { + exists: boolean; + schema: string; + toolVersion: string; + fingerprint: string; + tool: string; + text: string; + }, + policy: { reportSchemaVersion: number; expectedVersion: string; expectedTool: string }, + fingerprint: string, + ) => string; +}; +const graphifyReport = (await import( + ['..', '..', '..', 'scripts', 'graphify-report.mjs'].join('/') +)) as { + recoverOrphanedCompactReport: (reportPath: string, backupPath: string) => boolean; + validateNativeGraphifyReport: (markdown: string) => boolean; +}; +const graphifyBootstrap = (await import( + ['..', '..', '..', 'scripts', 'graphify-bootstrap.mjs'].join('/') +)) as unknown as { graphifyVersionCommand: (tool: string) => string[] }; + +const temporaryDirectories: string[] = []; +afterEach(() => { + for (const directory of temporaryDirectories.splice(0)) + rmSync(directory, { recursive: true, force: true }); +}); + +type ReportMetadata = Parameters[0]; +const policy = { reportSchemaVersion: 1 }; +const reportMetadata = ( + tool: string, + toolVersion: string, + text: string, + fingerprint = 'sha256:current', +): ReportMetadata => ({ exists: true, schema: '1', toolVersion, fingerprint, tool, text }); +const reportFreshness = ( + metadata: ReportMetadata, + expectedVersion: string, + fingerprint = 'sha256:current', + expectedTool = metadata.tool, +) => graphsCli.reportFreshness(metadata, { ...policy, expectedVersion, expectedTool }, fingerprint); + +describe('codegraph-report sanitization', () => { + it('counts prototype-named extensions without reading inherited properties', () => { + expect(formatExtensionLines([{ path: 'one.constructor' }, { path: 'two.constructor' }])).toBe( + '- **.constructor**: 2', + ); + }); + + describe('sanitize (ANSI stripping)', () => { + it.each([ + ['color', '\x1b[32mβœ“\x1b[0m Indexed 260 files', 'βœ“ Indexed 260 files'], + [ + 'multiple colors', + '\x1b[1m\x1b[36mStatus\x1b[0m: \x1b[32mhealthy\x1b[0m', + 'Status: healthy', + ], + ['plain text', 'no color codes here', 'no color codes here'], + ['non-color CSI and OSC', 'before\x1b[2Kafter\x1b]0;secret title\x07done', 'beforeafterdone'], + ['OSC terminated by ST', 'before\x1b]0;secret title\x1b\\after', 'beforeafter'], + ])('sanitizes %s', (_label, input, expected) => expect(sanitize(input)).toBe(expected)); + }); + + describe('redactPaths (absolute-path sanitization)', () => { + it.each([ + [ + 'repo root', + 'Indexed /home/pc/WorldScript-Studio/.worktrees/main/services/foo.ts', + { root: '/home/pc/WorldScript-Studio/.worktrees/main', home: '' }, + 'Indexed ./services/foo.ts', + ], + [ + 'home directory', + 'Config at /home/pc/.codegraph/config.json', + { root: '', home: '/home/pc' }, + 'Config at ~/.codegraph/config.json', + ], + [ + 'root and home', + '/home/pc/WorldScript-Studio/.worktrees/main/foo.ts and /home/pc/.cache/x', + { root: '/home/pc/WorldScript-Studio/.worktrees/main', home: '/home/pc' }, + './foo.ts and ~/.cache/x', + ], + [ + 'unrelated substring', + 'x/home/pc/WorldScript-Studio/.worktrees/mainish /home/pc/WorldScript-Studio/.worktrees/main/src/index.ts', + { root: '/home/pc/WorldScript-Studio/.worktrees/main', home: '' }, + 'x/home/pc/WorldScript-Studio/.worktrees/mainish ./src/index.ts', + ], + [ + 'Windows root', + 'C:\\Work\\World\\src C:\\Work\\Worldish', + { root: 'C:\\Work\\World', home: '' }, + '.\\src C:\\Work\\Worldish', + ], + [ + 'UNC root', + '\\\\server\\share\\repo\\src\\a.ts', + { root: '\\\\SERVER\\Share\\Repo', home: '' }, + '.\\src\\a.ts', + ], + ])('redacts %s at a path boundary', (_label, input, options, expected) => { + expect(redactPaths(input, options)).toBe(expected); + }); + }); + + describe('sanitize (combined ANSI + path pass)', () => { + it('never leaves an absolute machine path or ANSI code in the sanitized output', () => { + const raw = + '\x1b[32m/home/pc/WorldScript-Studio/.worktrees/main/services/foo.ts\x1b[0m indexed'; + const clean = sanitize(raw, { + root: '/home/pc/WorldScript-Studio/.worktrees/main', + home: '/home/pc', + }); + expect(clean).not.toContain('\x1b['); + expect(clean).not.toContain('/home/pc'); + expect(clean).toBe('./services/foo.ts indexed'); + }); + }); + + // QNBS-v3: freshness tests keep source, index, metadata, and report structure aligned. + describe('CodeGraph machine-readable freshness contract', () => { + const current = { + initialized: true, + version: '1.6.0', + fileCount: 1, + nodeCount: 2, + edgeCount: 3, + pendingChanges: { added: 0, modified: 0, removed: 0 }, + worktreeMismatch: null, + index: { builtWithVersion: '1.6.0', reindexRecommended: false }, + }; + + it('accepts a current structured status', () => { + expect(validateIndexStatus(current, '1.6.0')).toBe(current); + }); + + it.each([ + ['pending sync', { ...current, pendingChanges: { added: 1, modified: 0, removed: 0 } }], + ['worktree mismatch', { ...current, worktreeMismatch: 'changed' }], + ['reindex required', { ...current, index: { ...current.index, reindexRecommended: true } }], + ['version mismatch', { ...current, version: '1.1.3' }], + ['decorated status version', { ...current, version: 'v1.6.0' }], + [ + 'decorated index version', + { ...current, index: { ...current.index, builtWithVersion: 'v1.6.0' } }, + ], + ])('rejects %s before report output can be accepted', (_label, status) => { + expect(() => validateIndexStatus(status, '1.6.0')).toThrow(); + }); + + it('rejects a status payload without complete report counts', () => { + expect(() => validateIndexStatus({ ...current, edgeCount: undefined }, '1.6.0')).toThrow( + /counts are required/, + ); + }); + + it.each([ + ['truncated', [{ path: 'a.ts' }]], + ['duplicate', [{ path: 'a.ts' }, { path: 'a.ts' }]], + ])('rejects %s CodeGraph file evidence', (_label, fileList) => { + expect(() => validateFileList(fileList, 2)).toThrow(/count/); + }); + + it.each([ + ['empty', {}], + ['partial', { added: 0, modified: 0 }], + ])('rejects %s pending-change counters', (_label, pendingChanges) => { + expect(() => validateIndexStatus({ ...current, pendingChanges }, '1.6.0')).toThrow(/stale/); + }); + + it('rejects filename-derived extensions containing control characters', () => { + expect(() => formatExtensionLines([{ path: 'a.ts\n## Injected' }])).toThrow(/unsafe/); + }); + + it('escapes Markdown punctuation in filename-derived extensions', () => { + expect(formatExtensionLines([{ path: 'a.t*s' }])).toBe('- **.t\\*s**: 1'); + }); + }); + + describe('strict orchestration contracts', () => { + it('preserves the direct Graphify update skip contract', () => { + expect(graphsCli.shouldSkipGraphifyUpdate(['update', '.'], { GRAPHIFY_SKIP: '1' })).toBe( + true, + ); + expect(graphsCli.shouldSkipGraphifyUpdate(['update', '.'], {})).toBe(false); + expect(graphsCli.shouldSkipGraphifyUpdate(['--version'], { GRAPHIFY_SKIP: '1' })).toBe(false); + }); + + it('routes Graphify hook commands through the verified launcher', () => { + const packageJson = JSON.parse(readFileSync(join(ROOT, 'package.json'), 'utf-8')) as { + scripts: Record; + }; + expect(packageJson.scripts['graphify:hooks']).toBe( + 'node scripts/graphs-cli.mjs graphify hook install', + ); + expect(packageJson.scripts['graphify:status']).toBe( + 'node scripts/graphs-cli.mjs graphify hook status', + ); + }); + + it('rejects inherited command names', () => { + expect(graphsCli.isSupportedCommand('toString', { refresh: true })).toBe(false); + expect(graphsCli.isSupportedCommand('refresh', { refresh: true })).toBe(true); + }); + + it.each([ + ['missing Graphify', { updateStatus: 1, reportStatus: 0, reportsFresh: true }], + ['missing CodeGraph', { updateStatus: 0, reportStatus: 1, reportsFresh: true }], + ['stale reports', { updateStatus: 0, reportStatus: 0, reportsFresh: false }], + ])('never reports strict refresh success for %s', (_label, outcome) => { + expect(graphsCli.strictRefreshFailure(outcome)).toBeTruthy(); + }); + + it('accepts strict refresh only after the final freshness postcondition', () => { + expect( + graphsCli.strictRefreshFailure({ updateStatus: 0, reportStatus: 0, reportsFresh: true }), + ).toBeNull(); + }); + }); + + it('distinguishes unavailable and broken installed tool probes', () => { + expect(graphsCli.versionProbeStatus({ status: null, error: { code: 'ENOENT' } })).toBe( + 'SKIPPED_NOT_INSTALLED', + ); + expect(graphsCli.versionProbeStatus({ status: 1, stderr: 'runtime failed' })).toBe('FAIL'); + expect(graphsCli.versionProbeStatus({ status: 0, stdout: 'graphify 0.9.51' })).toBe( + 'AVAILABLE', + ); + }); + + it('cleans Graphify sidecars around the routed runtime update', () => { + const directory = mkdtempSync(join(tmpdir(), 'graphs-ephemeral-test-')); + temporaryDirectories.push(directory); + writeFileSync(join(directory, 'manifest.json'), 'stale'); + writeFileSync(join(directory, 'cost.json'), 'stale'); + for (const name of ['transcripts', 'wiki', 'obsidian']) { + mkdirSync(join(directory, name)); + } + + graphsCli.cleanupGraphifyEphemeralOutputs(directory); + + for (const name of ['manifest.json', 'cost.json', 'transcripts', 'wiki', 'obsidian']) { + expect(existsSync(join(directory, name))).toBe(false); + } + }); + + // QNBS-v3: structural fixtures prevent metadata-only corruption from being reported fresh. + it('rejects metadata-only or truncated reports with otherwise current metadata', () => { + expect( + reportFreshness( + reportMetadata( + 'codegraph', + '1.6.0', + '# CodeGraph Report\n\nReport schema: 1\nSource fingerprint: sha256:current', + ), + '1.6.0', + ), + ).toBe('REPORT_INVALID'); + }); + + it('accepts an intact generated CodeGraph report as fresh', () => { + const report = + '# CodeGraph Report\n\nReport schema: 1\nSource fingerprint: sha256:current\n' + + 'Tool: codegraph\nTool version: 1.6.0\nGeneration mode: test\n\n' + + '## Status\n\n```text\nInitialized: yes\nVersion: 1.6.0\nFiles: 1\nNodes: 2\nEdges: 3\n' + + 'Pending changes: {"added":0,"modified":0,"removed":0}\n' + + 'Worktree mismatch: none\nIndex built with: 1.6.0\nReindex required: no\n```\n\n' + + '## Files by Extension\n\n- **.mjs**: 1\n\n' + + '---\n\n*Regenerate with: `pnpm run graphs:report`*'; + expect(reportFreshness(reportMetadata('codegraph', '1.6.0', report), '1.6.0')).toBe('FRESH'); + }); + + it('rejects CodeGraph reports with heading-only status', () => { + const report = + '# CodeGraph Report\n\nReport schema: 1\nSource fingerprint: sha256:current\n' + + 'Tool: codegraph\nTool version: 1.6.0\nGeneration mode: test\n\n' + + '## Status\n\n```text\nInitialized: yes\n```\n\n## Files by Extension\n\n' + + '- **.mjs**: 1\n\n---\n\n*Regenerate with: `pnpm run graphs:report`*'; + expect(reportFreshness(reportMetadata('codegraph', '1.6.0', report), '1.6.0')).toBe( + 'REPORT_INVALID', + ); + }); + + it('keeps stale classification ahead of body validation', () => { + expect( + reportFreshness(reportMetadata('codegraph', '1.6.0', 'truncated', 'sha256:old'), '1.6.0'), + ).toBe('STALE'); + }); + + it('preserves Graphify freshness checks and rejects cross-tool reports', () => { + const report = + '# Graph Report - project\n\nReport schema: 1\nSource fingerprint: sha256:current\n' + + 'Tool: graphify\nTool version: 0.9.51\nGeneration mode: test\n\n' + + '## Summary\n- valid\n\n## Top 1 Communities by size (of 1 total)\n'; + const mismatchMetadata = reportMetadata('graphify', '1.6.0', report); + const truncatedReport = report.replace('\n\n## Summary\n- valid\n', ''); + const truncatedMetadata = reportMetadata('graphify', '0.9.51', truncatedReport); + expect([ + reportFreshness(reportMetadata('graphify', '0.9.51', report), '0.9.51'), + reportFreshness(truncatedMetadata, '0.9.51'), + reportFreshness(mismatchMetadata, '1.6.0', 'sha256:current', 'codegraph'), + ]).toEqual(['FRESH', 'REPORT_INVALID', 'REPORT_INVALID']); + }); + + it.each([ + [ + 'missing communities', + '# Graph Report - project\n\n## Summary\n- partial\n\n## Knowledge Gaps\n- none\n', + false, + ], + [ + 'complete empty communities', + '# Graph Report - project\n\n## Summary\n- none\n\n## Knowledge Gaps\n- none\n\n## Communities (0 total)\n', + true, + ], + [ + 'missing knowledge gaps', + '# Graph Report - project\n\n## Summary\n- none\n\n## Communities (0 total)\n', + true, + ], + [ + 'incomplete declared count', + '# Graph Report - project\n\n## Summary\n- none\n\n## Knowledge Gaps\n- none\n\n## Community Hubs (Navigation)\n- Community 1\n- Community 2\n\n## Communities (3 total, 1 thin omitted)\n', + false, + ], + [ + 'complete declared count', + '# Graph Report - project\n\n## Summary\n- none\n\n## Community Hubs (Navigation)\n- Community 1\n- Community 2\n\n## Communities (3 total, 1 thin omitted)\n\n### Community 1\n', + true, + ], + ])('validates native Graphify output: %s', (_label, markdown, expected) => { + expect(graphifyReport.validateNativeGraphifyReport(markdown)).toBe(expected); + }); + + it.each([ + ['python', ['-m', 'graphify', '--version']], + ['python3', ['-m', 'graphify', '--version']], + ['py', ['-3', '-m', 'graphify', '--version']], + ])('uses the selected %s interpreter for fallback verification', (tool, args) => { + expect(graphifyBootstrap.graphifyVersionCommand(tool)).toEqual(args); + }); + + // QNBS-v3: recovery fixtures preserve the last valid compact snapshot across interruptions. + it('recovers a valid orphaned Graphify compact report before a new transaction', () => { + const directory = mkdtempSync(join(tmpdir(), 'graphify-report-test-')); + temporaryDirectories.push(directory); + const reportPath = join(directory, 'GRAPH_REPORT.md'); + const backupPath = `${reportPath}.previous-compact`; + const previous = + '# Graph Report - project\n\nReport schema: 1\nSource fingerprint: sha256:' + + 'a'.repeat(64) + + '\nTool: graphify\nTool version: 0.9.51\nGeneration mode: test\n\n' + + '## Summary\n- valid\n\n## Top 1 Communities by size (of 1 total)\n\n' + + '## Knowledge Gaps\n- none\n'; + writeFileSync(backupPath, previous); + expect(graphifyReport.recoverOrphanedCompactReport(reportPath, backupPath)).toBe(true); + expect(readFileSync(reportPath, 'utf-8')).toBe(previous); + expect(existsSync(backupPath)).toBe(false); + }); + + it('preserves an invalid compact report through runtime-only update backup handling', () => { + const directory = mkdtempSync(join(tmpdir(), 'graphs-update-test-')); + temporaryDirectories.push(directory); + const reportPath = join(directory, 'GRAPH_REPORT.md'); + const backupPath = `${reportPath}.previous-compact`; + const invalid = '# Graph Report - interrupted\nmetadata only\n'; + writeFileSync(reportPath, invalid); + expect(graphsCli.prepareGraphifyReportBackup(reportPath, backupPath)).toBe(true); + expect(existsSync(reportPath)).toBe(false); + graphsCli.restoreGraphifyReportBackup(true, reportPath, backupPath); + expect(readFileSync(reportPath, 'utf-8')).toBe(invalid); + }); + + it('recovers a valid compact backup over an interrupted native primary', () => { + const directory = mkdtempSync(join(tmpdir(), 'graphify-report-test-')); + temporaryDirectories.push(directory); + const reportPath = join(directory, 'GRAPH_REPORT.md'); + const backupPath = `${reportPath}.previous-compact`; + const previous = + '# Graph Report - project\n\nReport schema: 1\nSource fingerprint: sha256:' + + 'b'.repeat(64) + + '\nTool: graphify\nTool version: 0.9.51\nGeneration mode: test\n\n' + + '## Summary\n- valid\n\n## Top 1 Communities by size (of 1 total)\n\n' + + '## Knowledge Gaps\n- none\n'; + writeFileSync(reportPath, '# Native Graphify output\n## Communities (1 total)\n'); + writeFileSync(backupPath, previous); + expect(graphifyReport.recoverOrphanedCompactReport(reportPath, backupPath)).toBe(true); + expect(readFileSync(reportPath, 'utf-8')).toBe(previous); + }); +}); diff --git a/tests/unit/scripts/graphSourceFingerprint.test.ts b/tests/unit/scripts/graphSourceFingerprint.test.ts new file mode 100644 index 00000000..4ca31d1e --- /dev/null +++ b/tests/unit/scripts/graphSourceFingerprint.test.ts @@ -0,0 +1,322 @@ +// @vitest-environment node +import { execFileSync } from 'node:child_process'; +import { + chmodSync, + mkdirSync, + mkdtempSync, + rmSync, + symlinkSync, + unlinkSync, + writeFileSync, +} from 'node:fs'; +import { join } from 'node:path'; +import { afterEach, beforeEach, describe, expect, it } from 'vitest'; +// QNBS-v3: fixture coverage locks worktree deletion and portable content semantics used by reports. +import { + buildMetadataBlock, + checkCleanState, + computeSourceFingerprint, + listSourcePaths, + matchesExactVersion, +} from '../../../scripts/graphSourceFingerprint.mjs'; + +let fixtureDir: string; + +function git(args: string[], cwd = fixtureDir) { + return execFileSync('git', args, { cwd, encoding: 'utf-8' }); +} + +function initFixture() { + fixtureDir = mkdtempSync(join(process.cwd(), '.graph-fingerprint-test-')); + git(['init', '-q']); + git(['config', 'user.email', 'test@example.com']); + git(['config', 'user.name', 'Test']); + writeFileSync(join(fixtureDir, 'a.ts'), 'export const a = 1;\n'); + writeFileSync(join(fixtureDir, '.gitignore'), 'graphify-out/\n.codegraph/\n'); + git(['add', '-A']); + git(['commit', '-q', '-m', 'initial']); +} + +beforeEach(() => { + initFixture(); +}); + +afterEach(() => { + rmSync(fixtureDir, { recursive: true, force: true }); +}); + +describe('graphSourceFingerprint', () => { + it('is deterministic across repeated calls with no source change', () => { + const first = computeSourceFingerprint(fixtureDir); + const second = computeSourceFingerprint(fixtureDir); + expect(first).toBe(second); + expect(first).toMatch(/^sha256:[0-9a-f]{64}$/); + }); + + it('is worktree-aware: changes when an uncommitted file is edited', () => { + const before = computeSourceFingerprint(fixtureDir); + writeFileSync(join(fixtureDir, 'a.ts'), 'export const a = 2;\n'); + const after = computeSourceFingerprint(fixtureDir); + expect(after).not.toBe(before); + }); + + it('is worktree-aware: changes when a new untracked source file is added', () => { + const before = computeSourceFingerprint(fixtureDir); + writeFileSync(join(fixtureDir, 'b.ts'), 'export const b = 1;\n'); + const after = computeSourceFingerprint(fixtureDir); + expect(after).not.toBe(before); + }); + + it('preserves exact unusual Git path names through NUL enumeration', () => { + writeFileSync(join(fixtureDir, 'fΓ€ll.ts'), 'export const umlaut = true;\n'); + writeFileSync(join(fixtureDir, 'file with spaces.ts'), 'export const spaced = true;\n'); + expect(listSourcePaths(fixtureDir)).toEqual( + expect.arrayContaining(['fΓ€ll.ts', 'file with spaces.ts']), + ); + expect(computeSourceFingerprint(fixtureDir)).toMatch(/^sha256:[0-9a-f]{64}$/); + }); + + it('round-trips non-UTF-8 Git path bytes instead of treating the file as deleted', () => { + const rawName = Buffer.from('bad-\xff.ts', 'latin1'); + const rawPath = Buffer.concat([Buffer.from(fixtureDir), Buffer.from('/'), rawName]); + writeFileSync(rawPath, 'export const raw = 1;\n'); + git(['add', '-A']); + git(['commit', '-q', '-m', 'track raw pathname']); + expect( + listSourcePaths(fixtureDir).some((path) => Buffer.isBuffer(path) && path.equals(rawName)), + ).toBe(true); + const before = computeSourceFingerprint(fixtureDir); + writeFileSync(rawPath, 'export const raw = 2;\n'); + expect(computeSourceFingerprint(fixtureDir)).not.toBe(before); + }); + + it('refuses a sparse checkout instead of treating omitted tracked files as deletions', () => { + try { + git(['update-index', '--skip-worktree', 'a.ts']); + expect(() => computeSourceFingerprint(fixtureDir)).toThrow(/SPARSE_CHECKOUT_UNSUPPORTED/); + } finally { + git(['update-index', '--no-skip-worktree', 'a.ts']); + } + }); + + it('refuses assume-unchanged tracked source entries', () => { + git(['update-index', '--assume-unchanged', 'a.ts']); + expect(() => computeSourceFingerprint(fixtureDir)).toThrow(/SOURCE_INDEX_FLAGS_UNSUPPORTED/); + }); + + it('hashes symlink targets without following them', () => { + if (process.platform === 'win32') return; + symlinkSync('a.ts', join(fixtureDir, 'link.ts')); + git(['add', 'link.ts']); + const first = computeSourceFingerprint(fixtureDir); + // QNBS-v3: replace the tracked link to prove its target, not an extra path, changes the digest. + rmSync(join(fixtureDir, 'link.ts')); + symlinkSync('other.ts', join(fixtureDir, 'link.ts')); + expect(computeSourceFingerprint(fixtureDir)).not.toBe(first); + }); + + it('preserves raw bytes when a symlink target contains invalid UTF-8', () => { + if (process.platform === 'win32') return; + const linkPath = join(fixtureDir, 'raw-link.ts'); + symlinkSync(Buffer.from([0x62, 0x61, 0x64, 0x2d, 0xff]), linkPath); + git(['add', 'raw-link.ts']); + const first = computeSourceFingerprint(fixtureDir); + unlinkSync(linkPath); + symlinkSync(Buffer.from([0x62, 0x61, 0x64, 0x2d, 0xfe]), linkPath); + expect(computeSourceFingerprint(fixtureDir)).not.toBe(first); + }); + + it('hashes a materialized mode-120000 link like its symlink target', () => { + if (process.platform === 'win32') return; + symlinkSync('a.ts', join(fixtureDir, 'link.ts')); + git(['add', 'link.ts']); + const symlinkFingerprint = computeSourceFingerprint(fixtureDir); + rmSync(join(fixtureDir, 'link.ts')); + writeFileSync(join(fixtureDir, 'link.ts'), 'a.ts'); + expect(computeSourceFingerprint(fixtureDir)).toBe(symlinkFingerprint); + }); + + it('represents a tracked working-tree deletion without crashing', () => { + const before = computeSourceFingerprint(fixtureDir); + rmSync(join(fixtureDir, 'a.ts')); + const after = computeSourceFingerprint(fixtureDir); + expect(after).not.toBe(before); + expect(checkCleanState(fixtureDir)).toEqual({ clean: false, dirtyPaths: ['a.ts'] }); + }); + + it('treats equivalent UTF-8 LF and CRLF text as the same content', () => { + writeFileSync(join(fixtureDir, 'a.ts'), 'export const a = 2;\n'); + const lf = computeSourceFingerprint(fixtureDir); + writeFileSync(join(fixtureDir, 'a.ts'), 'export const a = 2;\r\n'); + expect(computeSourceFingerprint(fixtureDir)).toBe(lf); + }); + + it('keeps binary byte changes meaningful', () => { + writeFileSync(join(fixtureDir, 'image.bin'), Buffer.from([0, 10, 13, 255])); + const before = computeSourceFingerprint(fixtureDir); + writeFileSync(join(fixtureDir, 'image.bin'), Buffer.from([0, 10, 13, 254])); + expect(computeSourceFingerprint(fixtureDir)).not.toBe(before); + }); + + it('includes the normalized tracked executable mode', () => { + if (process.platform === 'win32') return; + const before = computeSourceFingerprint(fixtureDir); + chmodSync(join(fixtureDir, 'a.ts'), 0o755); + git(['update-index', '--chmod=+x', 'a.ts']); + expect(computeSourceFingerprint(fixtureDir)).not.toBe(before); + }); + + it('includes tracked Gitlink object identity', () => { + const childDir = join(fixtureDir, 'child'); + mkdirSync(childDir); + git(['init', '-q'], childDir); + git(['config', 'user.email', 'test@example.com'], childDir); + git(['config', 'user.name', 'Test'], childDir); + writeFileSync(join(childDir, 'nested.ts'), 'export const nested = 1;\n'); + git(['add', '-A'], childDir); + git(['commit', '-q', '-m', 'child initial'], childDir); + const firstObjectId = git(['rev-parse', 'HEAD'], childDir).trim(); + git(['update-index', '--add', '--cacheinfo', `160000,${firstObjectId},child`]); + const first = computeSourceFingerprint(fixtureDir); + writeFileSync(join(childDir, 'nested.ts'), 'export const nested = 2;\n'); + git(['add', '-A'], childDir); + git(['commit', '-q', '-m', 'child second'], childDir); + const secondObjectId = git(['rev-parse', 'HEAD'], childDir).trim(); + git(['update-index', '--add', '--cacheinfo', `160000,${secondObjectId},child`]); + expect(computeSourceFingerprint(fixtureDir)).not.toBe(first); + }); + + it('excludes graphify-out/** and .codegraph/** from the fingerprint', () => { + const before = computeSourceFingerprint(fixtureDir); + // Directories are gitignored per the fixture's .gitignore, so these paths must not + // participate even though they physically exist on disk. + mkdirSync(join(fixtureDir, 'graphify-out'), { recursive: true }); + writeFileSync(join(fixtureDir, 'graphify-out', 'GRAPH_REPORT.md'), 'irrelevant content'); + mkdirSync(join(fixtureDir, '.codegraph'), { recursive: true }); + writeFileSync(join(fixtureDir, '.codegraph', 'CODEGRAPH_REPORT.md'), 'irrelevant content'); + const after = computeSourceFingerprint(fixtureDir); + expect(after).toBe(before); + expect(listSourcePaths(fixtureDir)).not.toContain('graphify-out/GRAPH_REPORT.md'); + expect(listSourcePaths(fixtureDir)).not.toContain('.codegraph/CODEGRAPH_REPORT.md'); + }); + + it('excludes nested linked worktrees from the fingerprint', () => { + const before = computeSourceFingerprint(fixtureDir); + mkdirSync(join(fixtureDir, '.worktrees', 'feature'), { recursive: true }); + writeFileSync( + join(fixtureDir, '.worktrees', 'feature', 'nested.ts'), + 'export const nested = true;\n', + ); + expect(computeSourceFingerprint(fixtureDir)).toBe(before); + expect(listSourcePaths(fixtureDir)).not.toContain('.worktrees/feature/nested.ts'); + }); + + it('is independent of commit SHA and branch name for identical content', () => { + const onMain = computeSourceFingerprint(fixtureDir); + git(['checkout', '-q', '-b', 'other-branch']); + writeFileSync(join(fixtureDir, 'c.ts'), 'export const c = 1;\n'); + git(['add', '-A']); + git(['commit', '-q', '-m', 'second commit, different branch']); + // Different branch, different HEAD SHA, but the tracked *content* now differs too -- + // add the same file back out to isolate the branch/SHA-independence claim. + rmSync(join(fixtureDir, 'c.ts')); + git(['add', '-A']); + git(['commit', '-q', '-m', 'revert content to match main']); + const onOtherBranch = computeSourceFingerprint(fixtureDir); + expect(onOtherBranch).toBe(onMain); + }); + + describe('checkCleanState', () => { + it('reports clean when there are no relevant working-tree changes', () => { + const { clean, dirtyPaths } = checkCleanState(fixtureDir); + expect(clean).toBe(true); + expect(dirtyPaths).toEqual([]); + }); + + it('reports dirty (DIRTY_UNTRACKED_INPUT trigger) for an untracked source file', () => { + writeFileSync(join(fixtureDir, 'untracked.ts'), 'export const u = 1;\n'); + const { clean, dirtyPaths } = checkCleanState(fixtureDir); + expect(clean).toBe(false); + expect(dirtyPaths).toContain('untracked.ts'); + }); + + it('reports dirty for an uncommitted modification to a tracked file', () => { + writeFileSync(join(fixtureDir, 'a.ts'), 'export const a = 999;\n'); + const { clean, dirtyPaths } = checkCleanState(fixtureDir); + expect(clean).toBe(false); + expect(dirtyPaths).toContain('a.ts'); + }); + + it('reports both endpoints when an excluded report is renamed into source', () => { + mkdirSync(join(fixtureDir, 'graphify-out'), { recursive: true }); + writeFileSync(join(fixtureDir, 'graphify-out', 'old.md'), 'report\n'); + git(['add', '-f', 'graphify-out/old.md']); + git(['commit', '-q', '-m', 'track generated report']); + git(['mv', 'graphify-out/old.md', 'included.ts']); + const result = checkCleanState(fixtureDir); + expect(result.clean).toBe(false); + expect(result.dirtyPaths).toEqual( + expect.arrayContaining(['included.ts', 'graphify-out/old.md']), + ); + }); + + it('reports both endpoints when source is renamed into an excluded report path', () => { + mkdirSync(join(fixtureDir, 'graphify-out'), { recursive: true }); + git(['mv', 'a.ts', 'graphify-out/new.md']); + const result = checkCleanState(fixtureDir); + expect(result.clean).toBe(false); + expect(result.dirtyPaths).toContain('graphify-out/new.md'); + expect(result.dirtyPaths).toContain('a.ts'); + }); + + it('ignores a rename confined to excluded graph-output paths', () => { + mkdirSync(join(fixtureDir, 'graphify-out'), { recursive: true }); + mkdirSync(join(fixtureDir, '.codegraph'), { recursive: true }); + writeFileSync(join(fixtureDir, 'graphify-out', 'old.md'), 'report\n'); + git(['add', '-f', 'graphify-out/old.md']); + git(['commit', '-q', '-m', 'track generated report']); + git(['mv', 'graphify-out/old.md', '.codegraph/new.md']); + expect(checkCleanState(fixtureDir)).toEqual({ clean: true, dirtyPaths: [] }); + }); + }); + + describe('buildMetadataBlock', () => { + it('embeds schema, fingerprint, tool, and version but never a timestamp or commit SHA', () => { + const block = buildMetadataBlock({ + tool: 'graphifyy', + toolVersion: '0.9.51', + generationMode: 'AST-only local build', + reportSchemaVersion: 1, + cwd: fixtureDir, + }); + expect(block).toContain('Report schema: 1'); + expect(block).toContain('Tool: graphifyy'); + expect(block).toContain('Tool version: 0.9.51'); + expect(block).toMatch(/Source fingerprint: sha256:[0-9a-f]{64}/); + expect(block).not.toMatch(/Originating commit/i); + expect(block).not.toMatch(/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}/); // no ISO timestamp + }); + + it('uses a supplied validated fingerprint without recomputing it', () => { + const fingerprint = `sha256:${'a'.repeat(64)}`; + expect( + buildMetadataBlock({ + tool: 'codegraph', + toolVersion: '1.6.0', + generationMode: 'test', + reportSchemaVersion: 1, + cwd: fixtureDir, + fingerprint, + }), + ).toContain(`Source fingerprint: ${fingerprint}`); + }); + }); + + // QNBS-v3: version tests lock the shared continuation-rejection contract used by report gates. + it('shares exact version matching semantics with report generators', () => { + expect(matchesExactVersion('graphify 0.9.51', '0.9.51')).toBe(true); + expect(matchesExactVersion('1.6.0', '1.6.0')).toBe(true); + expect(matchesExactVersion('graphify 0.9.50\nwarning: 0.9.51', '0.9.51')).toBe(false); + expect(matchesExactVersion('graphify 0.9.51-rc.1', '0.9.51')).toBe(false); + }); +}); diff --git a/turbo.json b/turbo.json index 6aad271d..44122b85 100644 --- a/turbo.json +++ b/turbo.json @@ -6,6 +6,7 @@ "CF_PAGES", "CF_PAGES_BRANCH", "CF_PAGES_SKIP_WRANGLER", + "ComSpec", "CLOUDFLARE_MANUAL_DEPLOY", "CLOUDFLARE_PAGES_PROJECT", "DEPLOY_TARGET", @@ -17,6 +18,7 @@ "RUN_MOBILE_E2E", "RUN_REAL_VOICE_E2E", "SMOKE_PORT", + "USERPROFILE", "XDG_RUNTIME_DIR" ], "tasks": {