Commit Graph
352 Commits
Author SHA1 Message Date
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
Yuxiang LinandGitHub 09ede1917f Merge pull request #419 from chengyongru/feat/nanobot-support
feat(install): add Nanobot platform support
2026-06-11 16:28:17 +08:00
chienvon 7254852f4a sync egonex organization metadata 2026-06-09 14:26:48 -07:00
chengyongru 8de0b3b11d feat(install): add Nanobot platform support 2026-06-09 16:52:35 +08:00
Yuxiang LinandGitHub ef7adac58e Merge pull request #347 from tirth8205/feat/kotlin-extractor
feat(core): add Kotlin structural analysis via tree-sitter
2026-06-09 13:25:10 +08:00
Yuxiang LinandGitHub 13a39c01cb Merge pull request #359 from tirth8205/fix/import-resolver-nodenext-rewrite
fix(extract-import-map): apply NodeNext .js→.ts rewrite (#294)
2026-06-09 13:23:21 +08:00
ZebangChengandGitHub 5c1e35f90b Merge pull request #387 from tirth8205/fix/phase7-cleanup-mv-trash
fix(skill): use mv-to-trash + delayed purge for Phase 7 cleanup (#301)
2026-06-06 18:47:00 +08:00
ZebangChengandGitHub 3281fd15e0 Merge pull request #346 from tirth8205/perf/understand-pipeline
perf(understand): parallelise file I/O in compute-batches + extract-import-map (#76)
2026-06-06 16:25:49 +08:00
Tirth KananiandClaude Opus 4.7 b3da919223 fix(skill): use mv-to-trash + delayed purge for Phase 7 cleanup (#301)
Phase 7's `rm -rf` of the just-created `intermediate/` and `tmp/` dirs
trips destructive-action gates on hardened hosts (e.g. freshness-window
checks that flag deleting paths created moments earlier). Move them into
a timestamped `.trash-<epoch>/` instead; Phase 0 reclaims the space once
the trash is older than 7 days, well past any freshness window. Behavior
on normal hosts is unchanged — disk usage is identical after the next
run's purge.

Closes #301

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-05 16:56:42 +01:00
Tirth KananiandClaude Opus 4.7 1f8d165f86 fix(extract-import-map): preserve deterministic stderr order across concurrent loaders
Addresses the regression flagged by ZebangCheng on #346: under the
parallelised `buildResolutionContext`, `loadTsConfigs` /
`loadGoModules` / `loadPhpAutoloads` ran concurrently but each wrote
warnings to stderr inline as it iterated read results, so a fixture
with both a malformed `tsconfig.json` and a malformed `composer.json`
could emit `composer, tsconfig` instead of the pre-PR `tsconfig,
composer` depending on I/O timing.

Each loader now buffers its warnings into a returned array and the
caller drains them in canonical order (tsconfig → go → php) after
`Promise.all`, restoring byte-identical stderr output. Added a
regression test that fixtures both malformed configs and asserts the
tsconfig warning precedes the composer warning in stderr.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-05 16:19:31 +01:00
Bozheng LongandClaude Opus 4.8 92e76190aa feat(understand): auto-detect conversation language on first run
When /understand runs with no --language flag and no stored outputLanguage,
step 3.6 now infers the conversation language and — only when it is non-English
— confirms once before generating, then persists the choice to config.json.
English conversations keep the exact same silent `en` path; --language flag and
stored config still take priority. README documents the behavior; version
bumped 2.7.5 -> 2.7.6 across all five manifests (user-visible behavior change).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 21:19:52 +08:00
Tirth KananiandClaude Opus 4.7 143b4e492f Merge branch 'main' into fix/import-resolver-nodenext-rewrite
Resolve conflict in tests/skill/understand/test_extract_import_map.test.mjs
by keeping both new test groups — they cover independent fixes that should
coexist:
  - upstream #214: tsconfig path-alias targets with leading "./"
  - this PR  #294: NodeNext .js → .ts rewrite for ESM TypeScript imports

The extract-import-map.mjs script auto-merged cleanly; both fixes are
already present in the merged source.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-01 10:25:37 +01:00
Tirth Kanani a6c653e36b fix(extract-import-map): apply NodeNext .js→.ts rewrite (#294)
Fixes the silent near-edgeless-graph regression on any modern ESM
TypeScript project. Reported in #294 with full repro + root-cause
analysis.

### Why this matters

Under `moduleResolution: NodeNext` (or `Node16` / `Bundler` with
explicit extensions — the default for new TS-ESM projects since 2023),
TypeScript does NOT rewrite import specifiers during compilation:

  // src/index.ts — real, idiomatic NodeNext source
  import { x } from './config.js';   // on disk: config.ts

Before this fix, `probeWithExtensions` only tried APPENDING extensions
to the import specifier:

  './config.js' → not in fileSet
  './config.js.ts', './config.js.tsx', './config.js.js', ... → all miss
  → returns null → edge dropped at merge as dangling

Net result on the reporter's repro: a knowledge graph with hundreds of
file nodes and almost no `imports` edges between them — silently
removing exactly the dependency structure the graph is meant to show.

### Fix

New `NODENEXT_REWRITES` table maps each compiled-output extension to
the TypeScript source extensions that could have produced it:

  .js   → [.ts, .tsx, .js, .jsx]
  .jsx  → [.tsx, .jsx]
  .mjs  → [.mts, .mjs, .ts]
  .cjs  → [.cts, .cjs, .ts]

`probeWithExtensions` now applies the rewrite when the import already
ends with one of these extensions and no such file exists on disk. The
rewrite runs BEFORE the legacy append-extensions loop — otherwise
`./foo.js` would generate the nonsense candidate `foo.js.ts` and the
append loop would never reach the actual `foo.ts`.

### Disambiguation

If both `config.ts` and `config.js` exist on disk (rare, but possible
during a partial migration), `import './config.js'` still resolves to
the .js — that's an exact-disk match and what NodeNext compilation
actually does. The rewrite only kicks in when the .js doesn't exist.

### Tests

6 new tests in `test_extract_import_map.test.mjs`:
- The main #294 case (`.js → .ts`)
- `.jsx → .tsx` and `.mjs → .mts` rewrites
- Disambiguation when both `.ts` and `.js` exist on disk
- Pure-JS projects still work (real `.js → .js` imports)
- Historical no-extension probes unaffected
- Missing files still return null (rewrite can't invent targets)

Total: 202 tests passing (was 196).

Closes #294
2026-05-31 22:31:23 +01: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
Tirth KananiandClaude Opus 4.7 eea73b656d perf(understand): parallelise file I/O in compute-batches + extract-import-map (#76)
The /understand pipeline reads every code file twice during analysis:
once in compute-batches (`extractExports` for the cross-batch neighbour
map) and once again in extract-import-map (per-language config loaders).
Both sites used sequential `readFileSync` loops, so on the iOS repo in
issue #226 (~15k files) the disk-read time was effectively serialised
behind a single libuv thread while the rest of the pool sat idle.

## Changes

- `extractExports` now batches files into `IO_PARALLELISM = 64` slices
  and issues all `readFile` calls in each slice through `Promise.all`,
  letting libuv's worker-thread pool overlap disk reads. The
  tree-sitter parse stays on the main thread because `web-tree-sitter`
  is single-threaded WASM — pipelining the I/O while parses run is
  where the wall-time savings come from.
- `loadTsConfigs`, `loadGoModules`, `loadPhpAutoloads` and
  `buildResolutionContext` switch to async / `Promise.all` for the
  same reason. `buildResolutionContext` also runs the three loader
  passes concurrently (`Promise.all([...])`) since they're independent.
- A small `readFilesParallel(paths)` helper is added at the top of
  `extract-import-map.mjs` so the three loaders share the same
  error-preserving shape.

## Why behavior stays identical

- Each loader collects its candidate paths in `files[]` order *before*
  issuing reads, then iterates `reads` in the same order to emit
  warnings + populate output maps. So stderr order and the final map
  contents are byte-identical to the previous sequential loops.
- `extractExports` collects per-file errors in-place in the
  `Promise.all` callbacks and emits warnings during the post-read
  serial loop, again in chunk order — so warning text and order match
  the previous implementation.
- Tree-sitter parsing is unchanged: parses still run serially on the
  main thread, just with reads pipelined alongside.

## What's NOT in this PR

- `buildFingerprintStore` and `analyzeChanges` in `core/fingerprint.ts`
  have the same sequential pattern. They're left alone here because
  they're part of the public `@understand-anything/core` API; making
  them async would be a breaking change worth its own discussion.
  Internal-only `.mjs` scripts are safe to refactor without API churn.
- No change to scan-project: most of its sync I/O is `statSync`
  (metadata, not content) plus a handful of small `.gitignore` /
  `.understandignore` reads. The parallelism win is marginal there.

## Verification

- `pnpm lint` clean
- `pnpm --filter @understand-anything/core build` clean
- `pnpm --filter @understand-anything/skill build` clean
- `pnpm test`: 196/196 — including
  `test_compute_batches.test.mjs` (19 tests) and
  `test_extract_import_map.test.mjs` (40 tests), which exercise both
  changed pipelines end-to-end with fixture projects. No output
  diff vs main.

Refs #76

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-31 20:25:39 +01:00
Zebang Cheng 928b997c57 fix(skill): preserve scan-result.json across Phase 7 cleanup for incremental runs (#293) 2026-05-29 15:33:31 +00:00
ZebangChengandGitHub d40d6b6204 Merge pull request #227 from ZebangCheng/fix/tsconfig-path-leading-dot-slash
fix(extract-import-map): normalize tsconfig path-alias candidates with leading "./" (#214)
2026-05-26 13:09:25 +08:00
Adam HerringandClaude Opus 4.7 b4d856d3b8 fix(scan-project): preserve non-ASCII path bytes via git ls-files -z
`enumerateViaGit` ran `git ls-files -co --exclude-standard` (newline-separated
output) and then `split('\n').map(trim)` on the result. Without `-z`,
`git ls-files` C-escapes any byte outside the locale's "safe" set and wraps
the path in double quotes — for example, a directory named `30. 🏗️ docs/`
comes back as `"30. \360\237\217\227\357\270\217 docs/"`. Downstream
consumers then can't round-trip those octal-quoted strings to real disk
paths, so every file under such directories is silently dropped from the
scan.

This is particularly biting on Windows (where the issue surfaces even with
UTF-8 locale settings) and for any project that uses emoji, accented
characters, or CJK codepoints in directory names — which is increasingly
common in design/spec/journal trees.

The fix is to use `-z` (NUL-terminated output), the same approach git
itself documents for downstream consumers (e.g. `xargs -0`). NUL-separated
chunks are raw bytes, so every codepoint round-trips back to its real disk
path on every platform. Split on `\0` instead of `\n`; drop the now-
unnecessary `.trim()`.

Verified on a real project with emoji-prefixed directory names:

  bare `git ls-files`:
    "30. \360\237\217\227\357\270\217\360\237\247\231\342\200\215..."

  `git ls-files -z`:
    30. 🏗️🧙‍♂️🔮 BD-CCSP/01. Demo's/DEMO--...

Discovered during a multi-agent scan of an Atlas Intelligence spoke repo;
~33 design-intent files in `30. 🏗️ BD-{app}/` directories were silently
dropped per scan. Full report: atlas-intelligence-io/fleet-feedback#491.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-25 11:09:20 -07:00
Zebang Cheng d9ae3c290c fix(extract-import-map): normalize tsconfig path-alias candidates with leading "./" (#214) 2026-05-25 14:02:01 +00:00
Yuxiang LinandGitHub 470cc01dc5 Merge pull request #200 from AsimRaza10/fix/agent-model-omit-inherit
fix(agents): omit `model: inherit` so non-Claude tools don't see a bad model id
2026-05-24 21:12:57 +08: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 0566ea8b6b fix(agents): omit model: inherit so non-Claude tools don't see a bad model id
`model: inherit` is a Claude Code-specific keyword that means "use the
parent session's model." Other tools that read the same agent frontmatter
(opencode, codex, etc.) don't understand it and instead try to use
`inherit` as a literal model id, which the configured provider rejects.

Reproduction (from #167): opencode + deepseek runs `/understand`, the
project-scanner subagent dispatches with `model: inherit`, deepseek
returns `ProviderModelNotFoundError`, and the pipeline halts on every
subagent dispatch.

With the field omitted, each platform falls back to its own configured
default:
- Claude Code: user's default subagent model
- opencode / codex / etc.: globally configured model

Note for Claude Code Opus users: subagents will no longer auto-inherit
the Opus session model. If you want the previous behavior, set your
default subagent model globally — that single setting now controls all
nine agents.

Closes #167
2026-05-24 10:50:26 +05:00
Yuxiang LinandGitHub 42d70c3f9c Merge pull request #186 from AsimRaza10/fix/tailwind-source-detection
fix(dashboard): explicit @source for Tailwind v4 (fixes #179)
2026-05-24 10:10:58 +08:00
devangpratap 31ae12b65c fix(ux): add progress reporting to /understand pipeline
Adds phase status lines, batch progress with total count, and phase
completion confirmations to the skill definition. Users now see
[Phase N/7] headers and Batch X/N during analysis instead of
unnumbered batch lines with no context.

Fixes #182
2026-05-23 14:18:26 -04: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
Yuxiang LinandGitHub 35699dd82b Merge pull request #171 from Derrick-xn/docs/update-skill-graph-reference
docs(skills): update graph structure references
2026-05-23 16:10:55 +08: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
Yuxiang LinandGitHub 4bd6f78dff Merge pull request #161 from okwn/contrib/understand-anything/eslint-tooling
chore: add ESLint tooling with TypeScript support
2026-05-23 15:47:52 +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
Ubuntu 11c5123d61 fix: correct GitHub URL in onboarding guide footer
The generated onboarding markdown linked to a nonexistent repository
(anthropics/understand-anything) instead of the actual project URL
(Lum1104/Understand-Anything).
2026-05-22 20:23:21 +08:00
初晨 a30c226bf4 docs(skills): update graph structure references 2026-05-22 12:08:44 +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
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
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