Commit Graph
223 Commits
Author SHA1 Message Date
thejeshandClaude Opus 4.7 a0155c5b48 refactor(skills): extract generate-ignore.mjs from SKILL.md inline one-liner
Replaces the duplicated Node.js block in Phase 0.5 with a call into
`generateStarterIgnoreFile` via a thin wrapper script, mirroring the
scan-project.mjs pattern. Removes ~40 lines of duplicated logic; single
source of truth in @understand-anything/core.

Also tightens code review nits:
- Add 3 tests: stable language-group ordering, all-commented invariant
  on empty dirs, suffix-glob rejects non-directory entries
- Clarify comments on EXACT_DIR_NAMES (ecosystem mix, not Python) and
  SUFFIX_DIR_GLOBS (unanchored String.endsWith match)
- Type detectDirectories' readdirSync result explicitly (Dirent[]) to
  pin the utf-8 encoding overload

Refs #76

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-16 12:02:53 -07:00
thejeshandClaude Opus 4.7 f5682bf2b8 feat(core): broaden .understandignore starter — C#/Java/Go test patterns
Detect C# project-suffix dirs (Foo.Tests/, Foo.UnitTests/) and PascalCase
test dirs (Tests/, UnitTests/, IntegrationTests/) via case-insensitive
match; group test-file suggestions by language (JS, C#, Java, Go).

Keeps all suggestions commented-out — same opt-in model as today. Updates
SKILL.md Phase 0.5 inline generator to stay in sync with the TS module.

Refs #76

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-16 11:53:33 -07:00
thejesh a555f4dd2a fix(core): DartExtractor — call graph coverage for codex P2 findings
Two gaps in the call-graph walker, both flagged by codex on #435:

1. `const Foo(...)` / `new Foo(...)` constructor calls were silently
   dropped. The grammar emits these as `const_object_expression` /
   `new_expression` containing `arguments` directly — they bypass the
   `selector > argument_part` shape the walker relied on. Added a
   dedicated branch that records the inner `type_identifier` as the
   callee. Critical for Flutter widget trees where
   `runApp(const MyApp())` would otherwise lose the MyApp construction
   edge.

2. When a getter / setter / constructor / factory_constructor has a
   body, its `method_signature` wraps `getter_signature` /
   `setter_signature` / `constructor_signature` /
   `factory_constructor_signature` instead of `function_signature`. The
   walker only looked for `function_signature`, so `pendingName`
   stayed null and the sibling `function_body` was walked with an
   empty stack — calls inside ctor/factory/getter/setter bodies were
   silently dropped even though those members were already extracted
   as functions. Now dispatch across all five signature variants,
   using `constructorName` for the (factory) constructor pair to
   match what `collectClassBody` pushes.

Tests: 41 → 47 dart cases (+6); full core 733 → 739; no regressions.
2026-06-15 02:50:06 -07:00
thejesh 68777feb1d feat(core): DartExtractor — broaden coverage per review (#436)
Incorporates stronger pieces from the prior Dart attempts (#348, #415)
that @Lum1104 called out:

- `extractParams` now walks `optional_formal_parameters` (covers both
  optional positional `[...]` AND named `{...}` parameters — the Dart
  grammar uses one wrapper for both).
- New `extractParamName` helper extracts the user-visible field name
  from `this.field` and `super.field` initializer parameters by
  unwrapping `constructor_param` / `super_formal_parameter`.
- `collectClassBody` now routes `getter_signature` and `setter_signature`
  in both shapes:
    - concrete: `method_signature > getter_signature` + sibling function_body
    - abstract: `declaration > getter_signature`
  Setters use the same path. The previous limitation assertion
  (`methods).not.toContain("value")`) flipped to a positive
  `.toContain("value")`.
- Added import/export edge-case tests: `dart:` SDK URIs, multi-import
  declaration-order preservation, and `export ... show` clauses.
- Added a comma-list field test (`int a, b, c;`).

Underscore-prefix visibility carries through naturally to all new code
paths via the existing `isExported` gate inside `pushMethod`; explicit
test added for an underscore-prefixed getter.

Test counts: 28 → 41 dart cases; full core suite 720 → 733; no
regressions.
2026-06-13 07:49:48 -07:00
thejeshandClaude Opus 4.7 a1ee028c35 feat(core): DartExtractor — call graph extraction
Implements extractCallGraph with a sibling-aware walk that pairs each
function_signature with its subsequent function_body sibling (Dart's
AST differs from Kotlin's: signature and body are siblings, not
parent/child). Detects call sites via selector nodes containing
argument_part; uses startIndex for sibling lookup (web-tree-sitter
returns new wrapper objects per child() call, making === unreliable).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-13 05:41:43 -07:00
thejeshandClaude Sonnet 4.6 23d6b1a39c test(core): DartExtractor — visibility rule (underscore prefix)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-13 05:36:23 -07:00
thejeshandClaude Sonnet 4.6 798c1747b9 feat(core): DartExtractor — import directives (package/relative/show/as) + export directives
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-13 05:35:00 -07:00
thejeshandClaude Sonnet 4.6 fd1d1c6450 feat(core): DartExtractor — enum declarations
Adds enum_declaration handling to DartExtractor: enum constants are surfaced
as properties[] so the structural graph captures Color.red / Color.green etc.
Implements Task 9 of the Dart language support plan (TDD, 16/16 dart tests
pass, full suite 708/708).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-13 05:26:12 -07:00
thejeshandClaude Sonnet 4.6 306ee2c070 feat(core): DartExtractor — extension declarations (named + anonymous)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-13 05:24:30 -07:00
thejeshandClaude Sonnet 4.6 05ce514db5 feat(core): DartExtractor — mixin declarations
Add mixin_declaration handling to extractStructure, folding mixins into
classes[] (same convention as class_definition). The `on` constraint
sibling is intentionally ignored for graph purposes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-13 05:19:11 -07:00
thejeshandClaude Sonnet 4.6 893208efb3 feat(core): DartExtractor — constructor naming (default/named/factory)
Add constructorName() helper and extend collectClassBody() to surface
unnamed constructors as "ClassName", named constructors as "Class.named",
and factory named constructors as "Class.named" in methods[]/functions[].
Probe confirmed plan's AST shapes match exactly; extractReturnType returns
undefined for all constructor forms (factory keyword is an unnamed node).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-13 05:12:41 -07:00
thejeshandClaude Sonnet 4.6 f4fc802743 feat(core): DartExtractor — class extraction with fields + methods
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-13 05:08:47 -07:00
thejeshandClaude Sonnet 4.6 136f85c1c8 feat(core): DartExtractor — top-level function extraction
Add TDD tests and implement extractTopLevelFunction with helpers for
extracting function name, params, and return type (including generics
where the grammar emits type_identifier + type_arguments as siblings).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-13 04:58:56 -07:00
thejesh 072bab798c feat(core): scaffold DartExtractor + register in builtinExtractors
Empty extractor that satisfies the LanguageExtractor interface so the
plugin pipeline can load it. Real extraction logic lands in subsequent
TDD commits.
2026-06-13 04:50:00 -07:00
thejesh 62932684c6 feat(core): register dart LanguageConfig
Adds the Dart language config and wires it into builtinLanguageConfigs
so .dart files are recognized by the language registry. References the
vendored @understand-anything/tree-sitter-dart-wasm package for grammar
loading.

No extractor yet — structural extraction lands in the next commit.
2026-06-13 04:46:13 -07:00
thejesh 3587ffa7a3 feat(tree-sitter-dart-wasm): vendor freshly-built dart WASM grammar
The upstream tree-sitter-dart@1.0.0 ships a pre-`dylink.0` wasm that
fails to load in web-tree-sitter@0.26.x. The grammar source itself is
sound — rebuilding with the current tree-sitter-cli + wasi-sdk produces
a working dylink.0 wasm. Vendor that artifact as a workspace-internal
package so @understand-anything/core can depend on it via workspace:*.

BUILD.md documents the provenance and rebuild instructions.
2026-06-13 04:42:58 -07:00
chienvon 7254852f4a sync egonex organization metadata 2026-06-09 14:26:48 -07:00
Tirth KananiandClaude Opus 4.7 235f2fafc8 feat(core): add Kotlin structural analysis via tree-sitter
Wires Kotlin into the existing tree-sitter pipeline so .kt and .kts
files now produce functions, classes, data classes, sealed classes,
interfaces, objects, imports, exports, and call-graph edges — matching
the behavior of the other language extractors.

## Why @tree-sitter-grammars/tree-sitter-kotlin

The standard `tree-sitter-kotlin` (v0.3.8) ships only native bindings.
The new `@tree-sitter-grammars/tree-sitter-kotlin@1.1.0` ships a
prebuilt `.wasm` (loads cleanly with `web-tree-sitter@^0.26.6`,
nodeTypeCount=289, parses class_declaration / function_declaration as
expected). Same shape that PR1 used for Swift, just a different
publisher because the repomix WASM bundle does not include Kotlin.

`@tree-sitter-grammars` is the official tree-sitter org's GitHub
account, so this is the canonical upstream WASM source for Kotlin.

## Notes for reviewers

- `kotlinConfig` already existed as a stub (no `treeSitter` field), so
  Android / JVM / Gradle codebases currently produce no structural
  edges between `.kt` files. This PR adds the `treeSitter` field; the
  existing plugin loader picks it up unchanged.
- **Visibility rule differs from Swift**: Kotlin's default visibility
  is `public`, so the extractor treats *every* declaration with no
  modifier as exported. Only an explicit `private` opts out. `internal`
  and `protected` remain exported in the project-graph sense because
  they are still resolvable from other files (within the module / via
  inheritance).
- `class_declaration` in tree-sitter-kotlin is overloaded for class,
  data class, sealed class, and interface (distinguished by the keyword
  child and `modifiers > class_modifier`). The extractor handles all
  four uniformly.
- `object_declaration` is a separate node type (Kotlin singletons) —
  treated as a class-like entry with its own `name` and members.
- Primary-constructor parameters marked `val` / `var` are surfaced as
  class properties; plain `parameter`s without `val/var` are
  constructor-only and are NOT counted as properties (matching Kotlin
  semantics).
- Import handling distinguishes the three forms: plain dotted
  (`import a.b.C`), wildcard (`import a.b.*` → specifier `"*"`), and
  aliased (`import a.b.C as Foo` → specifier `"Foo"`).

## Verification

- `pnpm lint` clean
- `pnpm --filter @understand-anything/core build` clean
- `pnpm --filter @understand-anything/skill build` clean
- `pnpm --filter @understand-anything/core test`: **692/692** (+22 new
  Kotlin tests, matching the bar set by go-extractor.test.ts /
  swift-extractor.test.ts)
- `pnpm test`: 196/196 (no regressions)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-31 20:42:12 +01:00
Yuxiang LinandGitHub a59a573a1d Merge pull request #204 from Lum1104/feat/semantic-batching-and-output-chunking
fix(#159): semantic batching + bundled importMap + Phase 1 speedup
2026-05-24 20:12:14 +08:00
Asim Raza 96c412bcc1 fix(dashboard): add explicit @source for Tailwind v4 detection
Tailwind v4's default source detection walks the nearest .git and
collects tracked files via git ls-files. When the dashboard sources
sit inside a gitignored subtree of an ancestor repo (e.g. the default
marketplace install path ~/.claude/plugins/cache/, which is ignored by
~/.claude/.gitignore), detection returns 0 files and the Oxide engine
skips all utility generation — the dashboard renders unstyled.

Adding explicit @source directives is the supported Tailwind v4 escape
hatch and is a no-op for installs where automatic detection works.

Verified: built CSS bundle jumps from ~9 KB to ~55 KB and utility
classes (.flex, .grid, .absolute, .w-full, .h-full) are present.

Fixes #179
2026-05-23 18:23:17 +05:00
Ved PrakashandLum1104 4ef12f39a6 chore(dependencies): update astro and vite versions in package.json and pnpm-lock.yaml
Bumps astro to version 6.3.7 and vite to version 6.4.2 across relevant package files to ensure compatibility and access to the latest features.
2026-05-23 15:58:37 +08:00
Lum1104 a1261b4883 chore(lint): switch to recommended baseline, fix errors, wire into CI
- typescript-eslint preset: strict -> recommended for a usable first-pass
  baseline (per PR discussion); ratchet up in a follow-up.
- Drop the projectService/parserOptions block. Neither `recommended` nor
  `strict` is type-aware, so it was unused; removing it also avoids the
  pnpm-workspace tsconfig-resolution failure mode flagged in review.
- Add Node + browser globals via the `globals` package so .mjs scripts and
  the dashboard stop hitting `no-undef`.
- Expand ignores: built bundles (**/public/**), Astro generated (.astro/),
  and .private/ (eval scratch). Cuts 2400+ errors in vendored output.
- Allow `_`-prefixed unused vars/args/caught errors; skip irregular
  whitespace inside comments (json-parser intentionally embeds ZWSP-escaped
  block-comment examples in JSDoc).
- Fix the residual 13 genuine errors: drop dead imports/vars, replace
  two `as any[]` in schema.ts with `Array<Record<string, unknown>>`,
  drop unused destructure in change-classifier, drop unused catch binding
  in extract-structure.mjs.
- Add EOF newline to eslint.config.mjs.
- Refresh pnpm-lock.yaml.
- Add `pnpm lint` step to .github/workflows/ci.yml so the tooling
  actually enforces something.

pnpm lint now exits 0 locally; 33+13 test files / 1445 tests still pass.
2026-05-23 15:26:39 +08:00
Lum1104 9dfcce73a5 refactor(onboarding): theme tokens, lifted state, a11y
- Replace hardcoded hex with var(--color-*) and CJK font stacks with
  var(--font-sans) / var(--font-heading) so the overlay tracks the theme
  picker and uses the project's typography (DM Serif Display).
- Lift dismiss/visibility state to Dashboard (shouldShowOnboarding +
  showOnboarding useState + dismissOnboarding callback). Gate the
  Suspense mount with a boolean so the lazy chunk is only fetched on
  first visit, matching the PathFinderModal / KeyboardShortcutsHelp
  mount pattern.
- Add capture-phase Escape handler (stopPropagation prevents the global
  shortcut chain from also firing) and role="dialog" / aria-modal /
  aria-labelledby on the card for screen readers.
2026-05-21 11:07:02 +08:00
Lum1104 a29585874e fix(onboarding): include class/function in node-type description
Schema (packages/core/src/schema.ts) defines node types: file, function,
class, module, concept, config, document, ... The welcome step body only
listed "file, concept, entity, claim", missing the most common code-side
types. Updated all 6 locales (en / zh / zh-TW / ja / ko / ru) to mention
file / class / function from code plus concept / entity / claim from the
knowledge wiki.
2026-05-21 11:06:54 +08:00
Lum1104 8f85b85679 fix(onboarding): wire to i18n + add missing ua-fade-in keyframes
- Replace hardcoded Chinese strings with t.onboarding.* via useI18n
- Add `onboarding` namespace to en / zh / zh-TW / ja / ko / ru locales
- Inject @keyframes ua-fade-in (was referenced in inline style but
  never defined, so the overlay popped in instead of fading)
2026-05-21 10:56:10 +08:00
Lum1104 cd09d4fe09 Merge branch 'main' into feat/onboarding-overlay 2026-05-21 10:33:16 +08:00
Lum1104 9d1318a0e7 feat(i18n): add Russian language support 2026-05-19 15:01:43 +08:00
Yuxiang LinandGitHub 4c6f7c3e0b Merge pull request #142 from zhushen12580/feature/language-parameter
feat: Add --language parameter for localized content generation
2026-05-12 11:07:14 +08:00
zhushen 2083342199 fix: Address code review feedback for PR #142
- Remove invalid allowBuilds from pnpm-workspace.yaml (use onlyBuiltDependencies in root package.json)
- Use data-testid for search input selector (fixes / keyboard shortcut for non-English locales)
2026-05-12 11:02:13 +08:00
zhushen a3ec91bf39 feat(dashboard): Complete i18n translation for all UI components 2026-05-12 01:53:58 +08:00
Lum1104andClaude Opus 4.7 1779cbd9a7 feat(dashboard): allow ACCESS_TOKEN override via env var
Honor UNDERSTAND_ACCESS_TOKEN if set, falling back to the random 16-byte
hex token. Lets the dev token survive across server restarts so shared
dashboard URLs don't rot, and makes the auth path easier to script in
tests.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 22:02:58 +08:00
zhushen e1650f627c fix: Wrap MobileLayout with I18nProvider; use outputLanguage key in config
P1: MobileLayout was missing I18nProvider wrapper, causing useI18n
    to throw error on mobile devices. Now both desktop and mobile
    layouts are wrapped with I18nProvider.

P2: SKILL.md used 'language' key but Dashboard reads 'outputLanguage'.
    Fixed config.json key name to match ProjectConfig type definition.

All tests passed:
- Core: 670 tests
- Dashboard: 42 tests
2026-05-11 20:30:50 +08:00
zhushen 752fe59e0c feat(dashboard): Add i18n support for localized UI text
- Add outputLanguage field to ProjectConfig type
- Create /config.json endpoint in vite.config.ts
- Build locale files for 5 languages (en, zh, zh-TW, ja, ko)
- Add I18nProvider context and useI18n hook
- Update 5 components (ProjectOverview, NodeInfo, FileExplorer, FilterPanel, PersonaSelector)
- Dashboard reads language from config.json and displays localized UI

All tests passed:
- Core: 670 tests
- Dashboard: 42 tests
2026-05-11 19:00:05 +08:00
Xingkai98 e29f461574 fix(dashboard): reset fn toggle on view switch; hide detail toolbar in domain view
- Issue 1: setDetailLevel now resets showFunctionsInClassView so the fn
  toggle doesn't resurrect when re-entering class view after a file-view
  round-trip.
- Issue 2: detail-level toolbar (Files/+Classes/fn) now gated on
  viewMode !== "domain" so it doesn't render in domain view where it has
  no effect.
2026-05-10 16:24:26 +08:00
Kai XingandGitHub f23291f9ea Merge branch 'Lum1104:main' into feat/dashboard-file-class-views 2026-05-10 15:40:06 +08:00
nieaoandClaude Opus 4.7 562eba412c feat(dashboard): first-visit onboarding overlay
Add a 5-step modal that walks new users through the dashboard's core operations
on first visit. Auto-hides via localStorage after dismiss; can be force-shown
with `?onboard=force` for screenshots and demos.

## What it teaches

1. What the graph represents (entities/relations from code or wiki)
2. Three view buttons (Overview / Learn / Deep Dive) — each answers a different
   question
3. Search + node click — find by name, click for details panel
4. Layer switch + Project Tour — drill into a category, or follow a guided
   walkthrough
5. Hidden features (Filter / Export / Path / Theme) and Shift+? for keyboard
   shortcuts

## Design

- Inline styles, no extra CSS file — easier to land in the existing structure
- Lazy-loaded via Suspense like the other modals (KeyboardShortcutsHelp,
  PathFinderModal) so it ships in a separate chunk
- Architectural-minimalism dark palette consistent with the existing dashboard:
  off-black surface, warm accent (#c8a882), Noto Serif SC headings, generous
  whitespace
- localStorage key `ua-onboarding-dismissed-v1` — versioned so future content
  changes can re-trigger
- Accessible: keyboard-navigable buttons, click-outside to close (without
  remembering dismiss), explicit "不再显示" / "Skip" affordance

## Tested

- Windows 11 + Chrome via Playwright: 5 steps render, progress bar tracks,
  prev/next/dismiss/finish all work, localStorage persists dismiss across
  reloads, `?onboard=force` re-shows for testing
- No new dependencies (uses React 19 hooks already present)
- No changes to data flow, store, or other components — strictly additive

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 19:15:05 +08:00
Yuxiang LinandGitHub 3eb7700a8f Merge pull request #122 from Lum1104/feat/issue-113-tested-by-coverage
feat: deterministic tested_by edges + dashboard badge (#113)
2026-05-09 11:18:27 +08:00
Xingkai98andClaude Opus 4.6 c1bc4bfac1 feat(dashboard): add file/class dual-view toggle to reduce graph clutter
Add detailLevel state ("file" | "class") to separate architecture-level
file dependencies from code-structure class views. File view shows only
file nodes and file→file edges (imports/depends_on), eliminating ~85%
of nodes/edges that previously caused severe zoom/pan lag. Class view
adds class nodes via contains edges with an optional function toggle.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-09 01:57:10 +08:00
Yuxiang LinandGitHub 5a2ffb1e0f feat: customizable heading font via theme settings (#121)
Add a `headingFont` option to ThemeConfig that lets users switch
heading typography between Serif (default), Sans, and Mono via the
existing Theme Picker UI.

- New `--font-heading` CSS custom property (defaults to `--font-serif`)
- Theme engine applies the selected font on config change
- ThemePicker gets a "Heading Font" toggle section
- All 15 component files updated from `font-serif` to `font-heading`
- Selection persists in localStorage alongside other theme settings
- Backwards-compatible: existing configs without `headingFont` default to serif

Closes #120
2026-05-08 22:20:47 +08:00
Lum1104andClaude Opus 4.7 c49c46d974 fix(pipeline): close 12 sources of silent data loss in graph extraction
A deep audit of the project-scanner → file-analyzer → merge pipeline
turned up a wide range of silent data-loss bugs. Each one alone is
small; together they were producing graphs with very few import edges,
missing sub-file nodes for non-code formats, and inconsistent metrics.

Root-cause fixes (high impact):

- project-scanner.md: extend import-pattern table to resolve absolute
  imports for Python (`from a.b.c import x`), TS/JS (tsconfig.json
  paths/baseUrl aliases), Java/Kotlin (`com.foo.Bar` ↔ file paths),
  Ruby (`require 'foo/bar'` load-path), PHP (composer PSR-4 namespaces),
  and C/C++ (`#include` headers). Was relative-only, which produced
  empty importMap entries for the majority of real projects.
- project-scanner.md: add `.ps1`, `.bat`, `.cmd`, `.jsonc` to language
  table; require non-null `language` field with an explicit fallback.
- file-analyzer.md: document `sections`, `definitions`, `services`,
  `endpoints`, `steps`, `resources` in the extraction-output schema and
  spell out the sub-file node-creation rules per category. Was missing,
  so per-table / endpoint / resource nodes were never created from
  SQL / OpenAPI / Terraform / K8s / Dockerfile parser output.
- file-analyzer.md: add explicit source-reading fallback rules for
  PowerShell, Batch, Bash, Swift, Kotlin (no tree-sitter coverage).
- yaml-parser: declare `kubernetes`, `docker-compose`, `github-actions`,
  `openapi` languages so files the language-registry tags with those
  ids actually get section extraction. Recognize quoted top-level keys
  (e.g. `"on":` in GitHub Actions). Emit one section per entry for
  array-root YAML documents.
- json-parser: declare `json-schema`, `openapi`; add `stripJsoncSyntax`
  helper that removes line / block comments and trailing commas before
  parse so `.jsonc` files (wrangler, tsconfig with comments) parse cleanly.
- shell-parser: declare `jenkinsfile`. Tighten function-detection regex
  to require a reachable `{` brace so `name() echo hi` and patterns
  appearing inside heredocs are no longer false-positives.
- markdown-parser: track fenced-code-block state and skip headings
  inside ``` / ~~~ blocks (`# install` shell comments were being
  emitted as level-1 sections).
- merge-batch-graphs.py: add `article`, `entity`, `topic`, `claim`,
  `source` to VALID_NODE_PREFIXES and TYPE_TO_PREFIX so knowledge-base
  node types stop being flagged unknown / coerced to `file:`. Add
  `direction` to the edge dedup key so `forward` and `bidirectional`
  variants of the same (src, tgt, type) don't overwrite each other.
  Use a placeholder in bare-id fallback when `filePath` is missing on
  function/class nodes so unrelated `parse()` functions don't merge.
- typescript-extractor: actually compute `isDefault` for default
  exports (was always emitted as `false` from buildResult).
- extract-structure.mjs: match `wc -l` semantics for `totalLines` so
  the scanner's `sizeLines` and the extractor's `totalLines` agree on
  POSIX text files. Filter the parser-imports fallback to relative-only
  so `importCount` semantics stay *internal-import* whether the scanner
  resolved them or not. Drop unused `isCode` local.

Tests: +19 cases covering JSONC parsing, markdown fenced-code skip,
YAML quoted-keys / array-root, shell function false-positives,
extract-structure import fallback semantics + totalLines off-by-one.
764 passing (was 745).

Bumps version to 2.6.2 across the five tracked manifests.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 21:44:24 +08:00
Denis BalanandGitHub 53248fea8b Merge pull request #117 from DenisBalan/patch-1
Fix dashboard URL format in vite.config.ts
2026-05-07 10:14:13 +08:00
Lum1104andClaude Opus 4.7 6c257a55f0 feat(dashboard): tested badge on node cards (#113)
Render a small green dot next to the complexity badge whenever a node's
tags contain "tested" — surfacing the deterministic linker's signal so
users can see at a glance which files have paired tests.

Plumb node.tags through both CustomNodeData construction sites in
GraphView.tsx; KnowledgeGraphView.tsx already passes tags.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 22:20:40 +08:00
Buzzwoo Team E-Com 92a13eadb5 feat: customizable heading font via theme settings
Add a `headingFont` option to ThemeConfig that lets users switch
heading typography between Serif (default), Sans, and Mono via the
existing Theme Picker UI.

- New `--font-heading` CSS custom property (defaults to `--font-serif`)
- Theme engine applies the selected font on config change
- ThemePicker gets a "Heading Font" toggle section
- All 15 component files updated from `font-serif` to `font-heading`
- Selection persists in localStorage alongside other theme settings
- Backwards-compatible: existing configs without `headingFont` default to serif

Closes #120
2026-05-06 16:13:28 +02:00
Lum1104andClaude Opus 4.7 880e223bb4 feat(dashboard): add mobile layout and responsive fixes
Bumps to 2.6.0.

- MobileLayout activates via useIsMobile at <768px with bottom-tab
  navigation (Graph/Info/Files); panes stay mounted (visibility
  toggle) to preserve ReactFlow dimensions and FileExplorer state.
- MobileDrawer holds persona, view mode, diff, node-type filters,
  layers, and tool buttons (Filter/Export/Path/Theme/Help).
- Selecting a node auto-pivots to Info; CodeViewer is always
  fullscreen on mobile; SearchBar collapses to a 🔍 toggle.
- Homepage Hero/Footer/Install responsive: drop nowrap on title and
  tagline, stack title spans for editorial wrap, full-width CTAs at
  <480px, narrow-width spacing refinements.
- Desktop dashboard: sidebar telescopes 260/300/360px, header gaps
  tighten, Path button label collapses to icon at narrow widths.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 16:25:56 +08:00
Lum1104andClaude Opus 4.7 6e0d1c11ea feat(dashboard): add favicon to match homepage branding
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 19:52:08 +08:00
Lum1104andClaude Opus 4.7 61356da3dc fix(dashboard): suppress TourFitView overlay flicker after fallback
Follow-up on the Codex P2: now that `useNodes` is in the effect deps,
every node update during a step that already timed out re-enters the
poll, sets `tourFitPending=true`, runs RAF for 4s, hits the silent
fallback path, and clears the flag. Visually the "Locating tour
highlight…" overlay would flash on every reflow even though the user
has already given up waiting. Skip the pending flag once
`fallbackKeyRef` matches the current step — the retry still runs
silently so a late Stage 2 can still upgrade to the proper fit.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 19:27:30 +08:00
Lum1104andClaude Opus 4.7 75368dc103 fix(dashboard): TourFitView timeout no longer freezes refit
Codex review on PR #114: when the RAF poll window expires before
highlighted nodes have been measured, the timeout fallback was setting
`fittedKeyRef.current = targetKey`, marking the step as fitted even
though the proper highlight fit never ran. If Stage 2 layout landed
after the 4s cap, the effect early-returned on the next nodes update
because the target key already matched, so the camera stayed pinned to
the fallback layer fit instead of zooming onto the actual highlights.

Fix:

  - Subscribe to React Flow's user-node array via `useNodes()` so the
    effect re-fires when Stage 2 finally produces the highlighted ids
    after the per-step RAF poll has already given up.
  - On timeout, pan into the layer for usability but do NOT set
    `fittedKeyRef`. The next nodes update gets another shot at the
    highlight fit, and on success `fittedKeyRef` records the proper fit.
  - Use a separate `fallbackKeyRef` to ensure the fallback `fitView`
    fires at most once per step — without this, every subsequent nodes
    update during the unready window would trigger a viewport jump.
  - Reset both refs when `tourHighlightedNodeIds` clears (stop tour).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 19:24:09 +08:00
Lum1104andClaude Opus 4.7 f58f0edd62 fix(dashboard): clear pendingFocusContainer on layer/state resets
Codex review on PR #114 flagged that `layerResetIfChanged` cleared
`containerLayoutCache` and `expandedContainers` but left
`pendingFocusContainer` intact. Because container ids collide across
layers (the very reason the cache reset exists), a manual expand in
layer A that hadn't yet hit its 1.2s clear timer could leak its id
into layer B's namespace and recenter the viewport on an unrelated
container right after navigation.

The same hazard applies to every other reset path that drops the
container caches. Add `pendingFocusContainer: null` to all of them:

  - layerResetIfChanged (tour cross-layer reset, the originally flagged
    site)
  - drillIntoLayer
  - navigateToOverview
  - setFocusNode
  - setPersona
  - setGraph
  - toggleNodeTypeFilter
  - clearContainerLayouts

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 19:21:06 +08:00
Lum1104andClaude Opus 4.7 4b86c696a5 fix(dashboard): tour navigation glitches across layers
Four related issues that surfaced while walking the Learn-mode tour
through a multi-layer project (microservices-demo):

1. Tour auto-expand never released. The tour effect that expands
   highlighted nodes' containers had no corresponding collapse when the
   step changed, so containers accumulated open as the user advanced.
   Track the set of containers we expanded and release any not needed
   by the current step; user-toggled containers are never tracked here,
   so they're never auto-collapsed.

2. Manual container toggle yanked off-screen. Stage 2 reflow shifted
   the just-clicked container away from the cursor. `toggleContainer`
   now records `pendingFocusContainer` on expand; GraphView locks the
   viewport onto that container's centre with the current zoom so it
   appears to expand in place.

3. Tour fitView fired before highlighted children existed. A single
   RAF after `tourHighlightedNodeIds` change wasn't enough — child
   nodes only appear once Stage 2 layout writes
   `containerLayoutCache`, and React Flow only knows their absolute
   position after a measure pass. `useNodes()` doesn't fire on
   measure completion, so we poll `getInternalNode().measured` each
   frame (up to ~4s) and call `fitView({ nodes })` once every
   highlight is measured, with `maxZoom: 1.2 / minZoom: 0.4`. While
   waiting, a new `tourFitPending` flag drives a "Locating tour
   highlight…" overlay so the user knows the layout is still settling.

4. Cross-layer tour transitions reused stale Stage 2 cache. Container
   ids derive from per-layer state (folder names in folder strategy,
   `container:cluster-N` in community strategy) and collide across
   layers — API Contracts and Load Testing both produce
   `container:cluster-0`. `setTourStep` / `nextTourStep` /
   `prevTourStep` / `startTour` didn't reset the container caches the
   way `drillIntoLayer` does, so when tour crossed a layer the new
   layer's expanded containers hit the previous layer's cache, Stage 2
   skipped its rerun, and children never showed. Extracted
   `layerResetIfChanged` and applied it in all four tour actions.

Verified end-to-end against microservices-demo via headless Chrome:
all 15 tour steps now expand the right container(s), zoom onto the
referenced files, and collapse the previous step's auto-expansions.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 19:06:39 +08:00
d 🔹andClaude Opus 4.7 988533a550 fix(dashboard): preserve any-layer-wins membership for filterNodes
Reviewer @Lum1104 (PR #112) caught a silent semantic regression: the new
`filterNodes` reads layer membership through `nodeIdToLayerId.get(node.id)`,
which is first-wins. The pre-#112 path was any-layer-wins —
`layers.some(layer => filters.layerIds.has(layer.id) && layer.nodeIds.includes(node.id))`.
For a node X listed in both L1 and L2 with only L2 selected, the old code
kept X; the new code dropped it. The schema permits multi-layer membership,
so this was a behavior change, not a bug fix.

Fix: keep two distinct indexes in the store. Both are rebuilt once on
`setGraph`, so the O(1)-per-node performance win from #112 is preserved.

  - `nodeIdToLayerId: Map<string, string>` — first-matching-layer wins.
    Drives navigation (drillIntoLayer / tour step → layer / sidebar
    history) where one canonical layer is the right answer. Unchanged.

  - `nodeIdToLayerIds: Map<string, Set<string>>` — every layer the node
    belongs to. Drives `filterNodes` membership checks. Restores
    any-layer-wins exactly.

`filterNodes` now iterates the (small) layer-id set per node looking for
intersection with `filters.layerIds`. ExportMenu reads
`nodeIdToLayerIds` from the store.

Verified locally:

  - Added `filters.test.ts` regression: node in (L1, L2) with only L2
    selected must pass. Failed against the first-wins implementation;
    passes now.
  - `pnpm --filter @understand-anything/dashboard test` — 42 / 42 pass
    (was 41; +1 multi-layer regression test; perf-guard at 100 layers ×
    100 nodes still <50 ms).
  - `pnpm --filter @understand-anything/dashboard exec tsc --noEmit` — clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 17:16:42 +08:00