Commit Graph
520 Commits
Author SHA1 Message Date
Yuxiang LinandGitHub 17eed78876 Merge pull request #170 from Lum1104/feat/trendshift-badge
feat(readme,homepage): add Trendshift trending badge
2026-05-22 08:28:45 +08:00
Lum1104 33728f04a6 feat(readme,homepage): add Trendshift badge
Adds the Trendshift trending-repository badge just below the tagline on the
English README and all 7 localized variants, and to the homepage hero between
the action row and the Enterprise pill.
2026-05-22 08:27:43 +08:00
Yuxiang LinandGitHub ea4d17b484 Merge pull request #164 from Lum1104/feat/community-video
feat(readme,homepage): add Community section with Better Stack walkthrough video
2026-05-21 20:01:23 +08:00
Lum1104 db94d066a8 feat(readme,homepage): add Community section featuring Better Stack walkthrough video
Adds a Community section near the end of README (English + 7 localized
variants) and a CommunityVideo component on the homepage embedding the
YouTube walkthrough by Better Stack. Section invites future video / blog /
tutorial contributions to be featured here.
2026-05-21 19:57:09 +08:00
Yuxiang LinandGitHub 300056e789 Merge pull request #163 from Lum1104/fix/extract-structure-symlink-isCli
fix(skills/understand): extract-structure isCli silently no-ops via symlinked SKILL_DIR
2026-05-21 19:40:01 +08:00
Lum1104 d14d6f8f96 chore(release): bump version to 2.7.4 2026-05-21 19:36:17 +08:00
Lum1104 8a78c94fc6 fix(skills/understand): canonicalize isCli paths so symlinked SKILL_DIR runs main()
import.meta.url resolves through symlinks but pathToFileURL(process.argv[1])
preserves them, so extract-structure.mjs silently exited 0 without writing
output when invoked via the plugin's symlinked install path — the documented
Claude Code / Copilot CLI layout. Compare both sides via realpathSync and add
a post-write existence assertion plus caller-side guidance in the agent.

Closes #162
2026-05-21 19:36:14 +08:00
Yuxiang LinandGitHub 58411ac1f7 Merge pull request #155 from nieao/feat/onboarding-overlay
feat(dashboard): first-visit onboarding overlay
2026-05-21 11:09:34 +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 57a25ed4aa chore: remove Product Hunt promo from README and homepage hero 2026-05-20 08:53:03 +08:00
Lum1104 9d1318a0e7 feat(i18n): add Russian language support v2.7.3 2026-05-19 15:01:43 +08:00
Lum1104 0e39f227a4 chore(release): bump version to 2.7.3
Ships the fingerprints baseline fix (e7af9ae): every install since
2.7.0 had a broken Phase 7 step 2.5 that threw TypeError on the first
/understand run and left fingerprints.json empty/missing, which made
every subsequent auto-update escalate to FULL_UPDATE. This release
replaces the LLM-written script with a bundled build-fingerprints.mjs
and reorders Phase 7 to write fingerprints before meta.json.

Anyone upgrading from 2.7.0–2.7.2 should re-run /understand --full
to regenerate a valid baseline.
2026-05-18 10:13:22 +08:00
Lum1104 e7af9ae35e fix(skills/understand): bundle build-fingerprints.mjs and reorder Phase 7
The Phase 7 step 2.5 code example in SKILL.md called
buildFingerprintStore() with 2 arguments, but the real signature
requires 4 (projectDir, filePaths, registry: PluginRegistry,
gitCommitHash: string). It also omitted the required
`await TreeSitterPlugin.init()`. Any LLM following the example
threw TypeError on `registry.analyzeFile()` and never produced a
baseline — which is why fingerprints.json never existed in a usable
form after a fresh /understand, and is the root cause behind
issue #152's "every auto-update escalates to FULL_UPDATE" cascade.

Replace the LLM-written script with a bundled `build-fingerprints.mjs`
that mirrors `extract-structure.mjs`: resolves @understand-anything/core
via createRequire, initializes TreeSitterPlugin + PluginRegistry
correctly, calls buildFingerprintStore with all four arguments, and
persists via saveFingerprints. Smoke-tested on this repo (3 files,
correct functions/classes/imports extracted).

Reorder Phase 7 so fingerprints are written BEFORE meta.json. If
fingerprint generation fails, the new step explicitly says to abort
Phase 7 — meta.json must not advance without a valid baseline, or
the next auto-update sees a fresh commit hash with no fingerprints
and classifies every file as STRUCTURAL.

Affects every install since 2.7.0 (when the broken example was
introduced). Users running /understand --full on 2.7.3+ will get
a usable fingerprints.json on the first try.
2026-05-18 10:13:02 +08:00
Lum1104 97fa2f3cab chore(release): bump version to 2.7.2
Ships two auto-update fixes:
- #153 (5304ff0): apply .understandignore in Phase 0 so user-excluded
  paths don't inflate the structural-change count.
- #152 (dd8b724): LOAD-PATCH-SAVE template for Phase 3d fingerprints
  merge, with guard against silent load failure.
2026-05-18 09:59:05 +08:00
Lum1104 dd8b724c99 fix(hooks/auto-update): make fingerprints merge unambiguous in Phase 3d
Fixes #152. Phase 3d step 3 instructed the LLM to "merge with existing
fingerprints (keep unchanged files as-is)" but the prose was vague
enough that the LLM-written script frequently wrote only the freshly
re-analyzed batch entries to fingerprints.json, discarding every other
file's fingerprint. The next auto-update saw N-batch_size files with
no stored fingerprint → classified as STRUCTURAL → exceeded the 30-file
threshold → FULL_UPDATE permanently, burning hundreds of thousands of
tokens on every subsequent commit.

Replace the four-bullet description with an explicit LOAD-PATCH-SAVE
script template:

  1. LOAD ALL existing entries from fingerprints.json (never skip).
  2. PATCH or REMOVE each path in filesToReanalyze (inline deletion
     handling so the spec doesn't need a separate deletedFiles list).
  3. GUARD: if the file existed and was non-empty but loaded as {},
     abort the write — silent load failure would otherwise clobber
     every fingerprint.
  4. SAVE the full dict back.

The reporter's dry-run showed this restores 81/97 files to COSMETIC
classification on their project (zero LLM tokens) instead of all 97
incorrectly forced into STRUCTURAL.

Note: a related ordering bug exists in skills/understand/SKILL.md
Phase 7 (meta.json written before fingerprints.json — silent failure
in step 2.5 leaves stale fingerprints). That's a separate fix in a
different file and is intentionally not bundled here.
2026-05-18 09:58:45 +08:00
Lum1104 5304ff06f3 fix(hooks/auto-update): apply .understandignore exclusions in Phase 0
Fixes #153. Phase 0 step 7 filters changed files to source extensions
only and never reads `.understandignore`, so files in user-excluded
paths (migrations, vendored code, tests) count as structural changes
and can spuriously escalate the action to FULL_UPDATE. The reporter
saw 50 → 38 structural files after applying their ignore patterns
(below the 30-file FULL_UPDATE threshold, ARCHITECTURE_UPDATE would
have sufficed).

Add step 9 that delegates to `createIgnoreFilter` from
`@understand-anything/core` via $CLAUDE_PLUGIN_ROOT. Same code path
as /understand's project-scanner Step 2.5, so the auto-update honors
the exact same patterns (hardcoded defaults + user .understandignore
files at both standard locations + `!` negation semantics).

If $CLAUDE_PLUGIN_ROOT can't be resolved, fail loud rather than
silently skipping — a silent skip reproduces the original bug.
2026-05-18 09:58:11 +08:00
Lum1104 2da74848e5 chore(release): bump version to 2.7.1
Ships the fixes that landed on main after the 2.7.0 cut:

- #139 (f3ea1a3): understand-knowledge — Windows path separators in
  wikilink resolution + omit empty `category` so KnowledgeMetaSchema's
  `z.string().optional()` no longer drops every article node. Closes #151.
- #147 (fafb888): understand-domain — resolve $PLUGIN_ROOT at runtime
  for symlink installs.
- f71bad5: understand — persist canonical edge direction during merge,
  fixing the 153k auto-correction cascade. Closes #140.
2026-05-18 09:48:44 +08:00
Lum1104 f71bad5267 fix(skills/understand): persist canonical edge direction during merge
Fixes #140. merge-batch-graphs.py already defaulted missing `direction`
to "forward" when building the dedup key, but the value was never written
back onto the edge — so the generated knowledge-graph.json shipped without
the field and the dashboard validator emitted one auto-correction per
edge (153k on the reporter's Go codebase).

Mirror the dashboard schema validator at packages/core/src/schema.ts:
lowercase the value, map "both"/"mutual" → "bidirectional", fall back to
"forward" for missing or invalid values, and persist the result onto the
edge before it enters edges_by_key. This also closes a latent dedup leak
where "Forward" and "forward" (or "both" and "bidirectional") would have
produced separate dedup keys.
2026-05-18 09:27:06 +08:00
Yuxiang LinandGitHub a5644ca3b0 Merge pull request #139 from nieao/fix/windows-compat
fix(understand-knowledge): Windows path + zod schema null compatibility
2026-05-17 22:07:38 +08:00
Yuxiang LinandGitHub cde871990c Merge pull request #147 from rustanacexd/fix/understand-domain-plugin-root
fix(skills/understand-domain): resolve plugin root for agent prompt loading (#146)
2026-05-13 10:20:33 +08:00
Rustan Corpuz fafb888422 fix(skills/understand-domain): resolve plugin root at runtime for symlink installs
Fixes #146. Ports the $PLUGIN_ROOT resolution pattern from understand/SKILL.md
to understand-domain/SKILL.md, including:
- Symlink resolution for ~/.agents/skills/understand-domain
- Copilot fallback for ~/.copilot/skills/understand-domain
- Detailed error diagnostics listing all checked paths
- Phase 4 agent prompt path now uses $PLUGIN_ROOT/agents/domain-analyzer.md
2026-05-12 15:00:55 +08:00
Lum1104andClaude Opus 4.7 9ab6724dca docs(homepage): add author homepage link below enterprise contact
A second pill mirroring the Enterprise one, linking to https://lum.is-a.dev/.
Same gold/amber styling, 0.6rem gap below the Enterprise pill so the two read
as one "contact" group, anim-5 so both pills enter together. Full mobile
breakpoint mirror.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 15:00:44 +08:00
Lum1104andClaude Opus 4.7 04c84ab4a4 chore(release): bump version to 2.7.0
Includes since 2.6.3: Hermes (#91), Cline (#116), KIMI CLI (#134)
platform support; dashboard ACCESS_TOKEN env override; README cleanup
(slogan rewrite, drop outdated overview gifs, move thanks to footer).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 14:27:12 +08:00
Yuxiang LinandGitHub 8b96a8b1ce Merge pull request #145 from zhushen12580/fix/code-review-feedback
docs: Add --language parameter documentation to all READMEs
2026-05-12 14:22:05 +08:00
zhushen 208921be3b docs: Add --language parameter documentation to all READMEs 2026-05-12 11:30:02 +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 31a775d65f feat(install): add KIMI CLI platform support (#134)
KIMI CLI scans ~/.kimi/skills/ (its brand path) for SKILL.md per the
official skill discovery spec, so distribution follows the same
folder-symlink pattern as Hermes / Cline / OpenClaw. install.sh and
install.ps1 register the `kimi` platform; README × 7 updated for the
one-line install title, <platform> values, and compatibility table.

Closes #134

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 22:11:48 +08:00
Lum1104andClaude Opus 4.7 b2fed42eac feat(install): add Cline platform support (#116)
Cline natively scans ~/.cline/skills/ for SKILL.md, so distribution
follows the same folder-symlink pattern as Hermes / OpenClaw /
Antigravity. install.sh and install.ps1 register the `cline` platform;
README × 7 (English + 6 locales) updated for the one-line install
title, <platform> values, and the compatibility table.

Closes #116

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 22:10:37 +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
zhushen 656289121c feat: Add --language parameter for localized content generation
Adds --language parameter to /understand command to generate knowledge
graph content in user-specified language.

Changes:
- Update argument-hint and Options documentation in SKILL.md
- Add language parsing logic in Phase 0 (language normalization,
  config persistence, LANGUAGE_DIRECTIVE template)
- Inject language directive into agent dispatch prompts for all
  content-generating phases (Phase 1-5)
- Add language directive handling instructions in agent definitions
- Create locales/ directory with template files for:
  - English (en.md) - default
  - Chinese Simplified (zh.md)
  - Chinese Traditional (zh-TW.md)
  - Japanese (ja.md)
  - Korean (ko.md)

Locale files provide language-specific guidance for:
- Tag naming conventions
- Summary writing style
- Technical term handling
- Layer name translations

Closes #141
2026-05-11 12:20:05 +08:00
Lum1104andClaude Opus 4.7 788aa90802 feat(install): add Hermes platform; refresh README (#91)
- install.sh / install.ps1: register `hermes` platform (folder-style
  symlink to ~/.hermes/skills/understand-anything/). No new directories
  or plugin manifests needed — Hermes scans skills via os.walk(...,
  followlinks=True) and reads SKILL.md frontmatter directly.
- README × 7 (English + 6 locales): one-line install title, `<platform>`
  values, and compatibility table updated for both Hermes and Vibe CLI
  (locale READMEs were missing Vibe).
- README × 7: drop top-of-page Star History Rank badge and the TIP-style
  thanks blockquote; rewrite the slogan into a longer line about quietly
  teaching how the pieces fit; move a single italic thanks line between
  Star History and the MIT footer.
- README × 7: remove the two outdated overview-*.gif blocks. The
  Features section already opens with a NOTE callout linking to the live
  demo, which serves as the visual entry instead.
- Delete assets/overview-{structural,domain}.gif (8.1 MB of orphaned
  binaries) from the working tree.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 10:33:36 +08:00
Yuxiang LinandGitHub 40519ee5ff Merge pull request #138 from voidborne-d/fix/worktree-paths
fix(skills): redirect PROJECT_ROOT out of git worktrees (closes #133)
2026-05-10 20:13:28 +08:00
Yuxiang LinandGitHub e638ed8303 Merge pull request #132 from Xingkai98/feat/dashboard-file-class-views
feat(dashboard): add file/class dual-view toggle to reduce graph clutter
2026-05-10 17:44:04 +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
Yuxiang LinandGitHub a381c41ef6 Merge pull request #124 from tipich/fix/windows-pnpm10-compat
fix(skill): make /understand work on Windows + pnpm 10
2026-05-10 09:38:18 +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
nieaoandClaude Opus 4.7 f3ea1a3088 fix(understand-knowledge): Windows path + zod schema null compatibility
Four single-line fixes that make `/understand-knowledge` work end-to-end on Windows.

## Root causes

1. Path separator mismatch (3 occurrences in parse-knowledge-base.py)
   - `str(rel.with_suffix(""))` returns backslash-separated stems on Windows
     (e.g. `entities\foo`), while wikilinks always use forward slashes
     (`[[entities/foo]]`).
   - Result: name_map keys and article_ids hold `entities\foo`, while
     `resolve_wikilink()` looks up `entities/foo` -> 100% miss.
   - Tested on Windows 11 + Python 3.14: 151/151 wikilinks unresolved,
     0 edges built from wikilinks.

   Fix: use `rel.with_suffix("").as_posix()` in all three places
   (lines 235, 316, 330 on main).

2. Null vs missing field (1 occurrence)
   - `"category": category or None` writes `null` when category is empty.
   - `KnowledgeMetaSchema.category` in packages/core/src/schema.ts is
     `z.string().optional()`, which accepts `undefined`/missing but
     rejects `null`.
   - Result: every article node fails GraphNodeSchema validation in the
     dashboard (`Invalid input: expected string, received null`),
     all nodes get dropped, dashboard renders empty.

   Fix: omit the field when empty using dict spread.

## After

Tested with a 27-article Karpathy wiki on Windows:
- before: 151 unresolved wikilinks, 0 edges, 0 nodes rendered in dashboard
- after:  0 unresolved, 110 wikilink edges + 23 LLM-implicit edges,
          all 53 nodes (article/topic/entity/claim) render correctly

No behavior change on macOS/Linux: `as_posix()` is a no-op when the OS
already uses `/`, and dict spread produces the same key as the previous
truthy branch.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 15:38:13 +08:00
d 🔹 b962a3dc33 fix(skills): redirect PROJECT_ROOT out of git worktrees (#133)
When /understand or /understand-domain runs from a CWD inside an
ephemeral git worktree (the default for parallel-agent / isolation
sessions), every output file goes to the worktree path. Claude Code
deletes the worktree on session end, taking knowledge-graph.json,
domain-graph.json, meta.json, intermediate batches and ~hundreds of K
of analysis tokens with it.

Resolve PROJECT_ROOT through a worktree check before any output:
compare git rev-parse --git-dir against --git-common-dir; in a normal
checkout (and in a submodule) they're the same path, in a worktree they
differ and parent(--git-common-dir) is the main repo root.
UNDERSTAND_NO_WORKTREE_REDIRECT=1 opts out for the rare per-worktree
case.

- skills/understand/SKILL.md Phase 0 step 1: add the redirect after
  PROJECT_ROOT is set from $ARGUMENTS or CWD, so an explicit arg path
  is also rescued from a worktree but can be opted out of.
- skills/understand-domain/SKILL.md: add an explicit Phase 0 (it
  previously inferred "current project" implicitly), then thread
  $PROJECT_ROOT through Phases 2-5 so subsequent steps honor the
  redirect.
- New worktree-redirect.test.mjs: 5 vitest cases covering main repo,
  worktree root, worktree subdir, opt-out env var, and non-git CWD.
  Mirrors the bash snippet inline (no shared lib in this repo).

Submodule false-positive ruled out by probe — submodules see git-dir
== git-common-dir (both point at <super>/.git/modules/<name>).
2026-05-09 12:58:46 +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
Lum1104andClaude Opus 4.7 a4bdc1c99d fix(merge): keep max-weight tested_by edge in Pass 1 dedup (#113)
Codex P2: link_tests Pass 1 dropped duplicate (production, test) pairs
purely by arrival order — when two batches both emitted a tested_by
edge for the same pair with different confidences (0.3 vs 0.9), the
edge that happened to iterate first won. The general Step 6 deduper
at line 762 mirrors `weight > existing.weight` semantics but it only
ever saw one of the duplicates, so it couldn't rescue the heavier one.

Refactor Pass 1 to mirror Step 6's weight comparison locally:

  - Track `pair_to_idx` mapping each kept (prod, test) pair to its
    slot in the compacted edges list. On a duplicate, look up the
    existing kept edge and compare weights; if the new edge is
    strictly heavier, swap (if needed) and replace the slot. Tie or
    lighter → drop the new edge.
  - Defer the swap operation until we know an edge will survive — no
    point canonicalizing a doomed duplicate.
  - Track surviving swap pairs in a separate `swapped_pairs` set so
    the `swapped` counter reflects the FINAL output, not the wasted
    work on edges that were later replaced. This means: replacing a
    swapped edge with a heavier canonical one drops the swap from
    the count; replacing a canonical edge with a heavier swapped one
    adds it.
  - Extract the swap-in-place mutation into `_swap_tested_by_in_place`
    so it can be invoked from both code paths.

Five new unit tests cover all four weight-vs-direction combinations
plus a tie case (existing test_drops_duplicate_canonical_edges, which
still passes — tie → keep first, no swap counted).

microservices-demo regression check unchanged: 7 → 7 edges, 3 swapped,
0 dropped, 7 tagged.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 11:05:43 +08:00
Lum1104andClaude Opus 4.7 4bb22fd9af feat(merge): swap-then-supplement tested_by linker (#113)
Strip-and-rederive (current PR behaviour) drops real coverage signal on
projects whose test layout doesn't match a naming convention. On the
Google microservices-demo the LLM had emitted 7 valid tested_by edges
(3 with inverted direction); the strip pass dropped them and the path-
convention rederive could only re-pair 4 of them. Net: 7 → 4 edges,
3 production files lost their tested signal.

Replace strip-and-rederive with two-pass swap-then-supplement:

  Pass 1 — walk LLM tested_by edges. Canonical (production → test)
  edges pass through unchanged. Inverted (test → production) edges are
  flipped in place; description gets a `[direction corrected]` audit
  marker. Edges with no recoverable meaning (test↔test, prod↔prod,
  orphan endpoint, duplicate pair) are dropped.

  Pass 2 — for tests not yet paired by Pass 1, walk path-convention
  candidates and emit a fresh production → test edge for the first
  match. Pairs already covered by Pass 1 are skipped.

Tagging is consolidated into a final pass over all canonical edges so
production nodes get the "tested" tag whether the edge came from
Pass 1 (canonical / swapped) or Pass 2 (supplement).

Multi-language audit of production_candidates revealed three real-world
gaps surfaced by re-checking microservices-demo and common project
layouts:

  - JS/TS walk-out only handled `__tests__/`. Extended to also walk out
    of `<dir>/test/`, `<dir>/spec/`, and `<dir>/tests/` (some JS/TS
    projects use these instead of __tests__/).
  - Python walk-out only handled top-level `tests/`. Added in-package
    `<pkg>/tests/test_<name>.py` → `<pkg>/<name>.py` (Django app style
    and any project that colocates tests with the package).
  - C# only had sibling fallback. Added two new mirrors:
      * `<svc>/tests/X.cs` ↔ `<svc>/X.cs` and `<svc>/src/.../X.cs`
        (microservices-demo cartservice exact layout).
      * `<App>.Tests/Foo/BarTests.cs` ↔ `<App>/Foo/Bar.cs`
        (.NET sibling-project convention).

Go is intentionally not changed — the "one _test.go covers several
.go files in the same package" pattern is now solved by Pass 1
(swapping LLM edges), not by trying to invent multi-pair path heuristics.

The file-analyzer prompt is updated: the `tested_by` row is restored
in the schema table because we now use those edges as evidence (Pass 1
canonicalizes the direction). The note explains direction will be
auto-corrected so the LLM doesn't need to be defensive about it.

link_tests now returns a 4-tuple (added, dropped, tagged, swapped);
the merge_and_normalize report distinguishes "edges produced
(supplement)" from "edges flipped" from "edges dropped".

Real-world validation on microservices-demo:
  before:   7 tested_by edges, 3 inverted, 0 tagged
  after PR: 4 tested_by edges, 0 inverted, 4 tagged   ← strip-and-rederive
  this:     7 tested_by edges, 0 inverted, 7 tagged   ← swap-then-supplement

Tests: 47 pass (was 37). New cases cover all swap branches, the
shippingservice "one test, many sources" regression, and each new
language pattern.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 10:45:22 +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