diff --git a/.claude/skills/gitnexus/gitnexus-cli/SKILL.md b/.claude/skills/gitnexus/gitnexus-cli/SKILL.md new file mode 100644 index 0000000..b73ea7e --- /dev/null +++ b/.claude/skills/gitnexus/gitnexus-cli/SKILL.md @@ -0,0 +1,86 @@ +--- +name: gitnexus-cli +description: "Use when the user needs to run GitNexus CLI commands like analyze/index a repo, check status, clean the index, generate a wiki, or list indexed repos. Examples: \"Index this repo\", \"Reanalyze the codebase\", \"Generate a wiki\"" +--- + +# GitNexus CLI Commands + +Commands below use `node .gitnexus/run.cjs ` — the project-local runner `gitnexus analyze` drops next to the index. It auto-selects an available runner at call time (global `gitnexus`, else `pnpm dlx`, else `npx`), so no package-manager assumption and no global install is required. + +> **Not analyzed yet, or `node .gitnexus/run.cjs` reports `Cannot find module`** (the gitignored runner is absent — e.g. a fresh clone or `git clean`)? (Re)generate it with `npx gitnexus analyze` from the project root. On **npm 11.x**, if `npx` crashes during install (`node.target is null`), install once with `npm i -g gitnexus` (then `gitnexus analyze`) or use `pnpm --allow-build=@ladybugdb/core --allow-build=gitnexus --allow-build=tree-sitter dlx gitnexus@latest analyze`. See [#1939](https://github.com/abhigyanpatwari/GitNexus/issues/1939). + +## Commands + +### analyze — Build or refresh the index + +```bash +node .gitnexus/run.cjs analyze +``` + +Run from the project root. This parses all source files, builds the knowledge graph, writes it to `.gitnexus/`, and generates CLAUDE.md / AGENTS.md context files. + +| Flag | Effect | +| -------------- | ---------------------------------------------------------------- | +| `--force` | Force full re-index even if up to date | +| `--embeddings` | Enable embedding generation for semantic search (off by default) | +| `--drop-embeddings` | Drop existing embeddings on rebuild. By default, an `analyze` without `--embeddings` preserves them. | +| `--pdg` | Build the program-dependence layers used by `explain` and `pdg_query` (taint, CDG, and REACHING_DEF). | + +**When to run:** First time in a project, after major code changes, or when `gitnexus://repo/{name}/context` reports the index is stale. In Claude Code, a PostToolUse hook detects staleness after `git commit` and `git merge` and notifies the agent to run `analyze` — the hook does not run analyze itself, to avoid blocking the agent for up to 120s and risking KuzuDB corruption on timeout. + +### status — Check index freshness + +```bash +node .gitnexus/run.cjs status +``` + +Shows whether the current repo has a GitNexus index, when it was last updated, and symbol/relationship counts. Use this to check if re-indexing is needed. + +### clean — Delete the index + +```bash +node .gitnexus/run.cjs clean +``` + +Deletes the `.gitnexus/` directory and unregisters the repo from the global registry. Use before re-indexing if the index is corrupt or after removing GitNexus from a project. + +| Flag | Effect | +| --------- | ------------------------------------------------- | +| `--force` | Skip confirmation prompt | +| `--all` | Clean all indexed repos, not just the current one | + +### wiki — Generate documentation from the graph + +```bash +node .gitnexus/run.cjs wiki +``` + +Generates repository documentation from the knowledge graph using an LLM. Requires an API key (saved to `~/.gitnexus/config.json` on first use). + +| Flag | Effect | +| ------------------- | ----------------------------------------- | +| `--force` | Force full regeneration | +| `--model ` | LLM model (default: minimax/minimax-m2.5) | +| `--base-url ` | LLM API base URL | +| `--api-key ` | LLM API key | +| `--concurrency ` | Parallel LLM calls (default: 3) | +| `--gist` | Publish wiki as a public GitHub Gist | + +### list — Show all indexed repos + +```bash +node .gitnexus/run.cjs list +``` + +Lists all repositories registered in `~/.gitnexus/registry.json`. The MCP `list_repos` tool provides the same information. + +## After Indexing + +1. **Read `gitnexus://repo/{name}/context`** to verify the index loaded +2. Use the other GitNexus skills (`exploring`, `debugging`, `impact-analysis`, `refactoring`) for your task + +## Troubleshooting + +- **"Not inside a git repository"**: Run from a directory inside a git repo +- **Index is stale after re-analyzing**: Restart Claude Code to reload the MCP server +- **Embeddings slow**: Omit `--embeddings` (it's off by default) or set `OPENAI_API_KEY` for faster API-based embedding diff --git a/.claude/skills/gitnexus/gitnexus-debugging/SKILL.md b/.claude/skills/gitnexus/gitnexus-debugging/SKILL.md new file mode 100644 index 0000000..4a33e58 --- /dev/null +++ b/.claude/skills/gitnexus/gitnexus-debugging/SKILL.md @@ -0,0 +1,101 @@ +--- +name: gitnexus-debugging +description: "Use when the user is debugging a bug, tracing an error, or asking why something fails. Examples: \"Why is X failing?\", \"Where does this error come from?\", \"Trace this bug\"" +--- + +# Debugging with GitNexus + +## When to Use + +- "Why is this function failing?" +- "Trace where this error comes from" +- "Who calls this method?" +- "This endpoint returns 500" +- Investigating bugs, errors, or unexpected behavior + +## Workflow + +``` +1. query({search_query: ""}) → Find related execution flows +2. context({name: ""}) → See callers/callees/processes +3. READ gitnexus://repo/{name}/process/{name} → Trace execution flow +4. cypher({statement: "MATCH path..."}) → Custom traces if needed +``` + +> If "Index is stale" → run `node .gitnexus/run.cjs analyze` in terminal. + +## Checklist + +``` +- [ ] Understand the symptom (error message, unexpected behavior) +- [ ] query for error text or related code +- [ ] Identify the suspect function from returned processes +- [ ] context to see callers and callees +- [ ] Trace execution flow via process resource if applicable +- [ ] cypher for custom call chain traces if needed +- [ ] Read source files to confirm root cause +``` + +## Debugging Patterns + +| Symptom | GitNexus Approach | +| -------------------- | ---------------------------------------------------------- | +| Error message | `query` for error text → `context` on throw sites | +| Wrong return value | `context` on the function → trace callees for data flow | +| Intermittent failure | `context` → look for external calls, async deps | +| Performance issue | `context` → find symbols with many callers (hot paths) | +| Recent regression | `detect_changes` to see what your changes affect | +| "How does A reach B?" | `trace` between the two symbols — shortest call chain in one call | + +## Tools + +**query** — find code related to error: + +``` +query({search_query: "payment validation error"}) +→ Processes: CheckoutFlow, ErrorHandling +→ Symbols: validatePayment, handlePaymentError, PaymentException +``` + +**context** — full context for a suspect: + +``` +context({name: "validatePayment"}) +→ Incoming calls: processCheckout, webhookHandler +→ Outgoing calls: verifyCard, fetchRates (external API!) +→ Processes: CheckoutFlow (step 3/7) +``` + +**cypher** — custom call chain traces: + +```cypher +MATCH path = (a)-[:CodeRelation {type: 'CALLS'}*1..2]->(b:Function {name: "validatePayment"}) +RETURN [n IN nodes(path) | n.name] AS chain +``` + +**trace** — shortest call chain between two symbols ("how does A reach B?"), one call instead of chaining `context` hops: + +``` +trace({ from: "processCheckout", to: "fetchRates" }) +→ status: ok, hopCount: 3 +→ hops: processCheckout → validatePayment → verifyCard → fetchRates +→ edges: CALLS (1.0), CALLS (0.95), CALLS (1.0) +``` + +When no path exists, `trace` reports the furthest reachable node — exactly where the chain breaks (dynamic dispatch, reflection, or an external boundary). + +## Example: "Payment endpoint returns 500 intermittently" + +``` +1. query({search_query: "payment error handling"}) + → Processes: CheckoutFlow, ErrorHandling + → Symbols: validatePayment, handlePaymentError + +2. context({name: "validatePayment"}) + → Outgoing calls: verifyCard, fetchRates (external API!) + +3. READ gitnexus://repo/my-app/process/CheckoutFlow + → Step 3: validatePayment → calls fetchRates (external) + +4. Root cause: fetchRates calls external API without proper timeout +``` diff --git a/.claude/skills/gitnexus/gitnexus-exploring/SKILL.md b/.claude/skills/gitnexus/gitnexus-exploring/SKILL.md new file mode 100644 index 0000000..f483c2f --- /dev/null +++ b/.claude/skills/gitnexus/gitnexus-exploring/SKILL.md @@ -0,0 +1,78 @@ +--- +name: gitnexus-exploring +description: "Use when the user asks how code works, wants to understand architecture, trace execution flows, or explore unfamiliar parts of the codebase. Examples: \"How does X work?\", \"What calls this function?\", \"Show me the auth flow\"" +--- + +# Exploring Codebases with GitNexus + +## When to Use + +- "How does authentication work?" +- "What's the project structure?" +- "Show me the main components" +- "Where is the database logic?" +- Understanding code you haven't seen before + +## Workflow + +``` +1. READ gitnexus://repos → Discover indexed repos +2. READ gitnexus://repo/{name}/context → Codebase overview, check staleness +3. query({search_query: ""}) → Find related execution flows +4. context({name: ""}) → Deep dive on specific symbol +5. READ gitnexus://repo/{name}/process/{name} → Trace full execution flow +``` + +> If step 2 says "Index is stale" → run `node .gitnexus/run.cjs analyze` in terminal. + +## Checklist + +``` +- [ ] READ gitnexus://repo/{name}/context +- [ ] query for the concept you want to understand +- [ ] Review returned processes (execution flows) +- [ ] context on key symbols for callers/callees +- [ ] READ process resource for full execution traces +- [ ] Read source files for implementation details +``` + +## Resources + +| Resource | What you get | +| --------------------------------------- | ------------------------------------------------------- | +| `gitnexus://repo/{name}/context` | Stats, staleness warning (~150 tokens) | +| `gitnexus://repo/{name}/clusters` | All functional areas with cohesion scores (~300 tokens) | +| `gitnexus://repo/{name}/cluster/{name}` | Area members with file paths (~500 tokens) | +| `gitnexus://repo/{name}/process/{name}` | Step-by-step execution trace (~200 tokens) | + +## Tools + +**query** — find execution flows related to a concept: + +``` +query({search_query: "payment processing"}) +→ Processes: CheckoutFlow, RefundFlow, WebhookHandler +→ Symbols grouped by flow with file locations +``` + +**context** — 360-degree view of a symbol: + +``` +context({name: "validateUser"}) +→ Incoming calls: loginHandler, apiMiddleware +→ Outgoing calls: checkToken, getUserById +→ Processes: LoginFlow (step 2/5), TokenRefresh (step 1/3) +``` + +## Example: "How does payment processing work?" + +``` +1. READ gitnexus://repo/my-app/context → 918 symbols, 45 processes +2. query({search_query: "payment processing"}) + → CheckoutFlow: processPayment → validateCard → chargeStripe + → RefundFlow: initiateRefund → calculateRefund → processRefund +3. context({name: "processPayment"}) + → Incoming: checkoutHandler, webhookHandler + → Outgoing: validateCard, chargeStripe, saveTransaction +4. Read src/payments/processor.ts for implementation details +``` diff --git a/.claude/skills/gitnexus/gitnexus-guide/SKILL.md b/.claude/skills/gitnexus/gitnexus-guide/SKILL.md new file mode 100644 index 0000000..c966161 --- /dev/null +++ b/.claude/skills/gitnexus/gitnexus-guide/SKILL.md @@ -0,0 +1,138 @@ +--- +name: gitnexus-guide +description: "Use when the user asks about GitNexus itself — available tools, how to query the knowledge graph, MCP resources, graph schema, or workflow reference. Examples: \"What GitNexus tools are available?\", \"How do I use GitNexus?\"" +--- + +# GitNexus Guide + +Quick reference for all GitNexus MCP tools, resources, and the knowledge graph schema. + +## Always Start Here + +For any task involving code understanding, debugging, impact analysis, or refactoring: + +1. **Read `gitnexus://repo/{name}/context`** — codebase overview + check index freshness +2. **Match your task to a skill below** and **read that skill file** +3. **Follow the skill's workflow and checklist** + +> If step 1 warns the index is stale, run `node .gitnexus/run.cjs analyze` in the terminal first. + +## Skills + +| Task | Skill to read | +| -------------------------------------------- | ------------------- | +| Understand architecture / "How does X work?" | `gitnexus-exploring` | +| Blast radius / "What breaks if I change X?" | `gitnexus-impact-analysis` | +| Trace bugs / "Why is X failing?" | `gitnexus-debugging` | +| Rename / extract / split / refactor | `gitnexus-refactoring` | +| Tools, resources, schema reference | `gitnexus-guide` (this file) | +| Index, status, clean, wiki CLI commands | `gitnexus-cli` | + +## Tools Reference + +| Tool | What it gives you | +| ---------------- | ------------------------------------------------------------------------ | +| `query` | Process-grouped code intelligence — execution flows related to a concept | +| `context` | 360-degree symbol view — categorized refs, processes it participates in | +| `impact` | Symbol blast radius — what breaks at depth 1/2/3 with confidence | +| `trace` | Shortest path between two symbols — "how does A reach B?" in one call | +| `detect_changes` | Git-diff impact — what do your current changes affect | +| `rename` | Multi-file coordinated rename with confidence-tagged edits | +| `cypher` | Raw graph queries (read `gitnexus://repo/{name}/schema` first) | +| `explain` | Persisted taint findings — source→sink data flows (needs `analyze --pdg`) | +| `pdg_query` | Control/data dependence — what gates X (CDG) / where Y flows (REACHING_DEF); needs `analyze --pdg` | +| `check` | Check graph invariants such as circular imports | +| `route_map` | API route map — which components/hooks fetch which endpoints, and the handler files that serve them | +| `shape_check` | Response-shape drift — keys each route returns vs keys its consumers access (flags MISMATCH) | +| `api_impact` | Pre-change report for an API route — consumers, middleware, shape mismatches, risk level | +| `tool_map` | MCP/RPC tool definitions and the files that handle them | +| `group_list` | List configured multi-repo groups, or one group's config | +| `group_sync` | Rebuild a group's Contract Registry (cross-repo HTTP contract links); run after `group.yaml` changes or member re-index | +| `list_repos` | Discover indexed repos (paginated — `limit`/`offset`) | + +### Paginating `list_repos` + +`list_repos` is paginated so a large registry is not truncated by MCP/LLM token limits. It takes optional `limit` (default **50**, max **200**) and `offset`, and returns: + +```jsonc +{ + "repositories": [ + { "name": "...", "path": "...", "indexedAt": "...", "lastCommit": "...", "stats": { } } + ], + "pagination": { + "total": 437, + "limit": 50, + "offset": 0, + "returned": 50, + "hasMore": true, + "nextOffset": 50 + } +} +``` + +To enumerate **every** repository, keep calling with `offset` set to `pagination.nextOffset` until `hasMore` is `false`: + +```text +list_repos {} → repos 1–50, nextOffset 50, hasMore true +list_repos { offset: 50 } → repos 51–100, nextOffset 100, hasMore true +… +list_repos { offset: 400 } → repos 401–437, hasMore false (done) +``` + +Notes: `offset` ≥ `total` returns an empty page (with `total` still reported). Out-of-range or malformed `limit`/`offset` (non-integer, `limit` outside `[1, 200]`, `offset < 0`) are rejected with a clear error — `limit` above the max is rejected, not silently capped. The order is deterministic (lower-cased name, then path), so paging never skips or duplicates an entry while the registry is unchanged. + +### Taint findings (`explain`) + +`explain` returns taint findings recorded by `gitnexus analyze --pdg` — intra-procedural `TAINTED` edges plus cross-function `TAINT_PATH` hops where the interprocedural taint phase found a function-level source→sink chain. Each finding includes a sink category (command-injection, code-injection, path-traversal, sql-injection, xss), source/sink lines, and the ordered hop path with the variable carried on each hop. + +- `explain {}` — enumerate all findings for the repo (bounded by `limit`, deterministic order) +- `explain { target: "src/vuln.ts" }` — findings in a file (suffix path match accepted) +- `explain { target: "runUserCommand" }` — findings in a function (resolved like `context`; ambiguous names return ranked candidates) + +A repo indexed without `--pdg` returns a clear "no taint layer" note. Caveats: closure/callback, property/field, and implicit flows are not modeled, and interprocedural findings are function-level `TAINT_PATH` hops rather than statement-level path proof, so the absence of a finding is **not** proof of safety. `SANITIZES` (sanitizer-kill) edges are queryable via `cypher`. + +### Control & data dependence (`pdg_query`) + +`pdg_query` reads the control/data-dependence layers `gitnexus analyze --pdg` records (CDG + REACHING_DEF, basic-block granular) — the control/data analog of `explain`. It is **always anchored** (a `target` file path or symbol, resolved like `context`) and has two modes: + +- `pdg_query { mode: "controls", target: "..." }` — CDG: "under what condition does X run?". Each edge is a controlling predicate block → dependent block with the branch sense (`'T'`/`'F'`) in `reason`; an edge into an early `return`/`throw` is flagged `guard: true` (guard-clause discovery — the sense depends on the predicate, so don't filter guards by a fixed label). +- `pdg_query { mode: "flows", target: "...", variable?: "..." }` — REACHING_DEF def→use edges within the function; pass `variable` to trace one binding. + +A repo indexed without `--pdg` returns a "no PDG layer" note (or "status unknown" when the layer can't be confirmed). Intra-procedural only — cross-function flow is taint's domain (`explain`). The raw CDG/REACHING_DEF edges are also queryable via `cypher`. See the `gitnexus-pdg-query` skill for the full query surface. + +### Shortest path between two symbols (`trace`) + +`trace` answers "how does A reach B?" in one call — the shortest directed path over `CALLS` (plus `HAS_METHOD`, so a class-rooted trace descends into its methods) instead of chaining 3–8 `context`/`impact` hops by hand. + +- `trace { from: "validateUser", to: "executeQuery" }` — shortest path between two symbols. +- Disambiguate common names with `from_uid`/`to_uid` (zero-ambiguity) or `from_file`/`to_file`; an ambiguous name returns ranked candidates. +- `maxDepth` (default 10, max 30) bounds the search; `includeTests` (default false) lets the traversal pass through test-file symbols. + +Returns ordered `hops` (each `{ name, filePath, startLine }`) and an aligned `edges[]` of `{ relType, confidence }`, so call hops and containment (`HAS_METHOD`) hops stay distinguishable. When no path exists it reports the **furthest** reachable node (where the chain breaks) and sets `truncated: true` if a traversal cap was hit first. Every result carries a `status`: `ok` / `no_path` / `ambiguous` / `not_found` / `error`. + +Cross-repo (experimental): pass `repo: "@groupName"` to trace across a group's member repos — the path may cross **one** `ContractLink` boundary (reported as a `CONTRACT_LINK` hop with the bridged contract in `crossings[]`). Omit `to` entirely to follow `from`'s outgoing HTTP call to whatever provider endpoint it lands on. Groups are configured via `group_list` / `group_sync`. + +## Resources Reference + +Lightweight reads (~100-500 tokens) for navigation: + +| Resource | Content | +| ---------------------------------------------- | ----------------------------------------- | +| `gitnexus://repo/{name}/context` | Stats, staleness check | +| `gitnexus://repo/{name}/clusters` | All functional areas with cohesion scores | +| `gitnexus://repo/{name}/cluster/{clusterName}` | Area members | +| `gitnexus://repo/{name}/processes` | All execution flows | +| `gitnexus://repo/{name}/process/{processName}` | Step-by-step trace | +| `gitnexus://repo/{name}/schema` | Graph schema for Cypher | + +## Graph Schema + +**Nodes:** File, Folder, Function, Class, Interface, Method, CodeElement, Community, Process, Route, Tool, plus language-specific types (Struct, Enum, Trait, Impl, Namespace, Module, …) and BasicBlock (`--pdg` indexes only). The full node list lives in `gitnexus://repo/{name}/schema`. +**Edges (via CodeRelation.type):** CALLS, IMPORTS, EXTENDS, IMPLEMENTS, DEFINES, CONTAINS, MEMBER_OF, HAS_METHOD, HAS_PROPERTY, ACCESSES, METHOD_OVERRIDES, METHOD_IMPLEMENTS, STEP_IN_PROCESS, HANDLES_ROUTE, FETCHES, HANDLES_TOOL, ENTRY_POINT_OF, WRAPS, QUERIES, INJECTS, plus `--pdg`-only types (CFG, REACHING_DEF, TAINTED, SANITIZES, TAINT_PATH, CDG — zero rows on a default index). + +Read `gitnexus://repo/{name}/schema` before writing Cypher — it is the authoritative schema for the indexed repo. + +```cypher +MATCH (caller)-[:CodeRelation {type: 'CALLS'}]->(f:Function {name: "myFunc"}) +RETURN caller.name, caller.filePath +``` diff --git a/.claude/skills/gitnexus/gitnexus-impact-analysis/SKILL.md b/.claude/skills/gitnexus/gitnexus-impact-analysis/SKILL.md new file mode 100644 index 0000000..45eb7ce --- /dev/null +++ b/.claude/skills/gitnexus/gitnexus-impact-analysis/SKILL.md @@ -0,0 +1,97 @@ +--- +name: gitnexus-impact-analysis +description: "Use when the user wants to know what will break if they change something, or needs safety analysis before editing code. Examples: \"Is it safe to change X?\", \"What depends on this?\", \"What will break?\"" +--- + +# Impact Analysis with GitNexus + +## When to Use + +- "Is it safe to change this function?" +- "What will break if I modify X?" +- "Show me the blast radius" +- "Who uses this code?" +- Before making non-trivial code changes +- Before committing — to understand what your changes affect + +## Workflow + +``` +1. impact({target: "X", direction: "upstream"}) → What depends on this +2. READ gitnexus://repo/{name}/processes → Check affected execution flows +3. detect_changes() → Map current git changes to affected flows +4. Assess risk and report to user +``` + +> If "Index is stale" → run `node .gitnexus/run.cjs analyze` in terminal. + +## Checklist + +``` +- [ ] impact({target, direction: "upstream"}) to find dependents +- [ ] Review d=1 items first (these WILL BREAK) +- [ ] Check high-confidence (>0.8) dependencies +- [ ] READ processes to check affected execution flows +- [ ] detect_changes() for pre-commit check +- [ ] Assess risk level and report to user +``` + +## Understanding Output + +| Depth | Risk Level | Meaning | +| ----- | ---------------- | ------------------------ | +| d=1 | **WILL BREAK** | Direct callers/importers | +| d=2 | LIKELY AFFECTED | Indirect dependencies | +| d=3 | MAY NEED TESTING | Transitive effects | + +## Risk Assessment + +| Affected | Risk | +| ------------------------------ | -------- | +| <5 symbols, few processes | LOW | +| 5-15 symbols, 2-5 processes | MEDIUM | +| >15 symbols or many processes | HIGH | +| Critical path (auth, payments) | CRITICAL | + +## Tools + +**impact** — the primary tool for symbol blast radius: + +``` +impact({ + target: "validateUser", + direction: "upstream", + minConfidence: 0.8, + maxDepth: 3 +}) + +→ d=1 (WILL BREAK): + - loginHandler (src/auth/login.ts:42) [CALLS, 100%] + - apiMiddleware (src/api/middleware.ts:15) [CALLS, 100%] + +→ d=2 (LIKELY AFFECTED): + - authRouter (src/routes/auth.ts:22) [CALLS, 95%] +``` + +**detect_changes** — git-diff based impact analysis: + +``` +detect_changes({scope: "staged"}) + +→ Changed: 5 symbols in 3 files +→ Affected: LoginFlow, TokenRefresh, APIMiddlewarePipeline +→ Risk: MEDIUM +``` + +## Example: "What breaks if I change validateUser?" + +``` +1. impact({target: "validateUser", direction: "upstream"}) + → d=1: loginHandler, apiMiddleware (WILL BREAK) + → d=2: authRouter, sessionManager (LIKELY AFFECTED) + +2. READ gitnexus://repo/my-app/processes + → LoginFlow and TokenRefresh touch validateUser + +3. Risk: 2 direct callers, 2 processes = MEDIUM +``` diff --git a/.claude/skills/gitnexus/gitnexus-refactoring/SKILL.md b/.claude/skills/gitnexus/gitnexus-refactoring/SKILL.md new file mode 100644 index 0000000..2dbb71c --- /dev/null +++ b/.claude/skills/gitnexus/gitnexus-refactoring/SKILL.md @@ -0,0 +1,121 @@ +--- +name: gitnexus-refactoring +description: "Use when the user wants to rename, extract, split, move, or restructure code safely. Examples: \"Rename this function\", \"Extract this into a module\", \"Refactor this class\", \"Move this to a separate file\"" +--- + +# Refactoring with GitNexus + +## When to Use + +- "Rename this function safely" +- "Extract this into a module" +- "Split this service" +- "Move this to a new file" +- Any task involving renaming, extracting, splitting, or restructuring code + +## Workflow + +``` +1. impact({target: "X", direction: "upstream"}) → Map all dependents +2. query({search_query: "X"}) → Find execution flows involving X +3. context({name: "X"}) → See all incoming/outgoing refs +4. Plan update order: interfaces → implementations → callers → tests +``` + +> If "Index is stale" → run `node .gitnexus/run.cjs analyze` in terminal. + +## Checklists + +### Rename Symbol + +``` +- [ ] rename({symbol_name: "oldName", new_name: "newName", dry_run: true}) — preview all edits +- [ ] Review graph edits (high confidence) and text_search edits (review carefully) +- [ ] If satisfied: rename({..., dry_run: false}) — apply edits +- [ ] detect_changes() — verify only expected files changed +- [ ] Run tests for affected processes +``` + +### Extract Module + +``` +- [ ] context({name: target}) — see all incoming/outgoing refs +- [ ] impact({target, direction: "upstream"}) — find all external callers +- [ ] Define new module interface +- [ ] Extract code, update imports +- [ ] detect_changes() — verify affected scope +- [ ] Run tests for affected processes +``` + +### Split Function/Service + +``` +- [ ] context({name: target}) — understand all callees +- [ ] Group callees by responsibility +- [ ] impact({target, direction: "upstream"}) — map callers to update +- [ ] Create new functions/services +- [ ] Update callers +- [ ] detect_changes() — verify affected scope +- [ ] Run tests for affected processes +``` + +## Tools + +**rename** — automated multi-file rename: + +``` +rename({symbol_name: "validateUser", new_name: "authenticateUser", dry_run: true}) +→ 12 edits across 8 files +→ 10 graph edits (high confidence), 2 text_search edits (review) +→ Changes: [{file_path, edits: [{line, old_text, new_text, confidence}]}] +``` + +**impact** — map all dependents first: + +``` +impact({target: "validateUser", direction: "upstream"}) +→ d=1: loginHandler, apiMiddleware, testUtils +→ Affected Processes: LoginFlow, TokenRefresh +``` + +**detect_changes** — verify your changes after refactoring: + +``` +detect_changes({scope: "all"}) +→ Changed: 8 files, 12 symbols +→ Affected processes: LoginFlow, TokenRefresh +→ Risk: MEDIUM +``` + +**cypher** — custom reference queries: + +```cypher +MATCH (caller)-[:CodeRelation {type: 'CALLS'}]->(f:Function {name: "validateUser"}) +RETURN caller.name, caller.filePath ORDER BY caller.filePath +``` + +## Risk Rules + +| Risk Factor | Mitigation | +| ------------------- | ----------------------------------------- | +| Many callers (>5) | Use rename for automated updates | +| Cross-area refs | Use detect_changes after to verify scope | +| String/dynamic refs | query to find them | +| External/public API | Version and deprecate properly | + +## Example: Rename `validateUser` to `authenticateUser` + +``` +1. rename({symbol_name: "validateUser", new_name: "authenticateUser", dry_run: true}) + → 12 edits: 10 graph (safe), 2 text_search (review) + → Files: validator.ts, login.ts, middleware.ts, config.json... + +2. Review text_search edits (config.json: dynamic reference!) + +3. rename({symbol_name: "validateUser", new_name: "authenticateUser", dry_run: false}) + → Applied 12 edits across 8 files + +4. detect_changes({scope: "all"}) + → Affected: LoginFlow, TokenRefresh + → Risk: MEDIUM — run tests for these flows +``` diff --git a/.gitnexus/lbug b/.gitnexus/lbug index ae67321..d8b74ba 100644 Binary files a/.gitnexus/lbug and b/.gitnexus/lbug differ diff --git a/.gitnexus/lbug.wal b/.gitnexus/lbug.wal deleted file mode 100644 index 96362eb..0000000 Binary files a/.gitnexus/lbug.wal and /dev/null differ diff --git a/.playwright-cli/console-2026-08-16T07-11-48-915Z.log b/.playwright-cli/console-2026-08-16T07-11-48-915Z.log new file mode 100644 index 0000000..91eab82 --- /dev/null +++ b/.playwright-cli/console-2026-08-16T07-11-48-915Z.log @@ -0,0 +1 @@ +[ 159ms] [INFO] %cDownload the React DevTools for a better development experience: https://react.dev/link/react-devtools font-weight:bold @ http://127.0.0.1:5173/node_modules/.vite/deps/react-dom_client.js?v=9a31a45b:20102 diff --git a/.playwright-cli/console-2026-08-16T07-19-15-689Z.log b/.playwright-cli/console-2026-08-16T07-19-15-689Z.log new file mode 100644 index 0000000..d9352ba --- /dev/null +++ b/.playwright-cli/console-2026-08-16T07-19-15-689Z.log @@ -0,0 +1 @@ +[ 158ms] [INFO] %cDownload the React DevTools for a better development experience: https://react.dev/link/react-devtools font-weight:bold @ http://127.0.0.1:5173/node_modules/.vite/deps/react-dom_client.js?v=9a31a45b:20102 diff --git a/.playwright-cli/page-2026-08-16T07-11-14-950Z.yml b/.playwright-cli/page-2026-08-16T07-11-14-950Z.yml new file mode 100644 index 0000000..e69de29 diff --git a/.playwright-cli/page-2026-08-16T07-11-49-316Z.yml b/.playwright-cli/page-2026-08-16T07-11-49-316Z.yml new file mode 100644 index 0000000..bee3d66 --- /dev/null +++ b/.playwright-cli/page-2026-08-16T07-11-49-316Z.yml @@ -0,0 +1,70 @@ +- main [ref=e3]: + - generic: + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - region "年度费用模板" [ref=e4]: + - generic "筛选条件" [ref=e5]: + - button "省市区" [ref=e6] [cursor=pointer] + - button "自然地理区位" [ref=e12] [cursor=pointer] + - button "设施类别" [ref=e17] [cursor=pointer] + - button "建筑性质" [ref=e23] [cursor=pointer] + - button "建设阶段" [ref=e28] [cursor=pointer] + - button "规划形式" [ref=e35] [cursor=pointer] + - button "时间" [ref=e42] [cursor=pointer] + - button "面积" [ref=e46] [cursor=pointer] + - region "年度总费用图表" [ref=e54]: + - generic [ref=e55]: + - button "纵坐标:造价(元)" [ref=e57] [cursor=pointer]: 造价(元) + - generic [ref=e58]: 正在加载数据 + - generic [ref=e59]: + - figure "图表,共有0个系列": + - generic [ref=e60]: + - img "interactive chart" + - region [ref=e61] + - toolbar "标注" [ref=e62]: + - button "库" [ref=e63] [cursor=pointer] + - button "指" [ref=e64] [cursor=pointer] + - button "均" [ref=e65] [cursor=pointer] + - button "Line Tool" [disabled] [ref=e66] + - button "Text Tool" [disabled] [ref=e67] + - button "Shape Tool" [disabled] [ref=e68] + - button "Fibonacci Tool" [disabled] [ref=e69] + - button "全屏(F11)" [ref=e70] [cursor=pointer] + - button "Clear annotations" [disabled] [ref=e71] + - button "切换到表格" [ref=e72] [cursor=pointer]: + - generic: 趋 + - status: + - generic: 请选择右侧分类项 + - toolbar "缩放" [ref=e73]: + - button "缩小" [disabled] [ref=e74] + - button "放大" [ref=e75] [cursor=pointer] + - button "左移" [disabled] [ref=e76] + - button "右移" [disabled] [ref=e77] + - button "重置" [disabled] [ref=e78] + - generic [ref=e79]: 正在加载数据 + - button "收起选择区" [expanded] [ref=e81] [cursor=pointer] + - complementary "选择内容" [ref=e85]: + - tablist "选择内容切换项" [ref=e86]: + - tab "自然地理区位" [selected] [ref=e87] [cursor=pointer] + - tab "设施类别" [ref=e88] [cursor=pointer] + - tab "建设阶段" [ref=e89] [cursor=pointer] + - tab "规划形式" [ref=e90] [cursor=pointer] + - generic [ref=e91]: + - generic [ref=e92]: 自然地理区位 + - generic [ref=e93]: 加载中 \ No newline at end of file diff --git a/.playwright-cli/page-2026-08-16T07-12-14-673Z.yml b/.playwright-cli/page-2026-08-16T07-12-14-673Z.yml new file mode 100644 index 0000000..534e35b --- /dev/null +++ b/.playwright-cli/page-2026-08-16T07-12-14-673Z.yml @@ -0,0 +1,80 @@ +- main [ref=e3]: + - generic: + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - region "年度费用模板" [ref=e4]: + - generic "筛选条件" [ref=e5]: + - button "省市区" [ref=e6] [cursor=pointer] + - button "自然地理区位" [ref=e12] [cursor=pointer] + - button "设施类别" [ref=e17] [cursor=pointer] + - button "建筑性质" [active] [ref=e23] [cursor=pointer] + - button "建设阶段" [ref=e28] [cursor=pointer] + - button "规划形式" [ref=e35] [cursor=pointer] + - button "时间" [ref=e42] [cursor=pointer] + - button "面积" [ref=e46] [cursor=pointer] + - region "年度总费用图表" [ref=e54]: + - generic [ref=e55]: + - button "纵坐标:造价(元)" [ref=e57] [cursor=pointer]: 造价(元) + - generic [ref=e58]: "Expected property name or '}' in JSON at position 1 (line 1 column 2)" + - generic [ref=e59]: + - figure "图表,共有0个系列": + - generic [ref=e60]: + - img "interactive chart" + - region [ref=e61] + - toolbar "标注" [ref=e62]: + - button "库" [ref=e63] [cursor=pointer] + - button "指" [ref=e64] [cursor=pointer] + - button "均" [ref=e65] [cursor=pointer] + - button "Line Tool" [disabled] [ref=e66] + - button "Text Tool" [disabled] [ref=e67] + - button "Shape Tool" [disabled] [ref=e68] + - button "Fibonacci Tool" [disabled] [ref=e69] + - button "全屏(F11)" [ref=e70] [cursor=pointer] + - button "Clear annotations" [disabled] [ref=e71] + - button "切换到表格" [ref=e72] [cursor=pointer]: + - generic: 趋 + - status: + - generic: 请选择右侧分类项 + - toolbar "缩放" [ref=e73]: + - button "缩小" [disabled] [ref=e74] + - button "放大" [ref=e75] [cursor=pointer] + - button "左移" [disabled] [ref=e76] + - button "右移" [disabled] [ref=e77] + - button "重置" [disabled] [ref=e78] + - button "收起选择区" [expanded] [ref=e81] [cursor=pointer] + - complementary "选择内容" [ref=e85]: + - tablist "选择内容切换项" [ref=e86]: + - tab "自然地理区位" [selected] [ref=e87] [cursor=pointer] + - tab "设施类别" [ref=e88] [cursor=pointer] + - tab "建设阶段" [ref=e89] [cursor=pointer] + - tab "规划形式" [ref=e90] [cursor=pointer] + - generic [ref=e91]: + - generic [ref=e92]: 自然地理区位 + - generic [ref=e93]: "Expected property name or '}' in JSON at position 1 (line 1 column 2)" + - dialog "建筑性质筛选" [ref=e94]: + - generic [ref=e95]: + - heading "建筑性质" [level=2] [ref=e96] + - button "关闭" [ref=e97] [cursor=pointer]: × + - searchbox "搜索" [ref=e99] + - generic [ref=e100]: 未选择 + - generic [ref=e101]: "Expected property name or '}' in JSON at position 1 (line 1 column 2)" + - generic [ref=e103]: + - button "清空当前" [ref=e104] [cursor=pointer] + - button "取消" [ref=e105] [cursor=pointer] + - button "确认" [ref=e106] [cursor=pointer] \ No newline at end of file diff --git a/.playwright-cli/page-2026-08-16T07-13-28-337Z.yml b/.playwright-cli/page-2026-08-16T07-13-28-337Z.yml new file mode 100644 index 0000000..73db60d --- /dev/null +++ b/.playwright-cli/page-2026-08-16T07-13-28-337Z.yml @@ -0,0 +1,69 @@ +- main [ref=e3]: + - generic: + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - region "年度费用模板" [ref=e4]: + - generic "筛选条件" [ref=e5]: + - button "省市区" [ref=e6] [cursor=pointer] + - button "自然地理区位" [ref=e12] [cursor=pointer] + - button "设施类别" [ref=e17] [cursor=pointer] + - button "建筑性质" [ref=e23] [cursor=pointer] + - button "建设阶段" [ref=e28] [cursor=pointer] + - button "规划形式" [ref=e35] [cursor=pointer] + - button "时间" [ref=e42] [cursor=pointer] + - button "面积" [ref=e46] [cursor=pointer] + - region "年度总费用图表" [ref=e54]: + - generic [ref=e55]: + - button "纵坐标:造价(元)" [ref=e57] [cursor=pointer]: 造价(元) + - generic [ref=e58]: "Expected property name or '}' in JSON at position 1 (line 1 column 2)" + - generic [ref=e59]: + - figure "图表,共有0个系列": + - generic [ref=e60]: + - img "interactive chart" + - region [ref=e61] + - toolbar "标注" [ref=e62]: + - button "库" [ref=e63] [cursor=pointer] + - button "指" [ref=e64] [cursor=pointer] + - button "均" [ref=e65] [cursor=pointer] + - button "Line Tool" [disabled] [ref=e66] + - button "Text Tool" [disabled] [ref=e67] + - button "Shape Tool" [disabled] [ref=e68] + - button "Fibonacci Tool" [disabled] [ref=e69] + - button "全屏(F11)" [ref=e70] [cursor=pointer] + - button "Clear annotations" [disabled] [ref=e71] + - button "切换到表格" [ref=e72] [cursor=pointer]: + - generic: 趋 + - status: + - generic: 请选择右侧分类项 + - toolbar "缩放" [ref=e73]: + - button "缩小" [disabled] [ref=e74] + - button "放大" [ref=e75] [cursor=pointer] + - button "左移" [disabled] [ref=e76] + - button "右移" [disabled] [ref=e77] + - button "重置" [disabled] [ref=e78] + - button "收起选择区" [expanded] [ref=e81] [cursor=pointer] + - complementary "选择内容" [ref=e85]: + - tablist "选择内容切换项" [ref=e86]: + - tab "自然地理区位" [selected] [ref=e87] [cursor=pointer] + - tab "设施类别" [ref=e88] [cursor=pointer] + - tab "建设阶段" [ref=e89] [cursor=pointer] + - tab "规划形式" [ref=e90] [cursor=pointer] + - generic [ref=e91]: + - generic [ref=e92]: 自然地理区位 + - generic [ref=e93]: "Expected property name or '}' in JSON at position 1 (line 1 column 2)" \ No newline at end of file diff --git a/.playwright-cli/page-2026-08-16T07-13-47-595Z.yml b/.playwright-cli/page-2026-08-16T07-13-47-595Z.yml new file mode 100644 index 0000000..349ff18 --- /dev/null +++ b/.playwright-cli/page-2026-08-16T07-13-47-595Z.yml @@ -0,0 +1,86 @@ +- main [ref=e3]: + - generic: + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - region "年度费用模板" [ref=e4]: + - generic "筛选条件" [ref=e5]: + - button "省市区" [ref=e6] [cursor=pointer] + - button "自然地理区位" [ref=e12] [cursor=pointer] + - button "设施类别" [ref=e17] [cursor=pointer] + - button "建筑性质" [active] [ref=e23] [cursor=pointer] + - button "建设阶段" [ref=e28] [cursor=pointer] + - button "规划形式" [ref=e35] [cursor=pointer] + - button "时间" [ref=e42] [cursor=pointer] + - button "面积" [ref=e46] [cursor=pointer] + - region "年度总费用图表" [ref=e54]: + - generic [ref=e55]: + - button "纵坐标:造价(元)" [ref=e57] [cursor=pointer]: 造价(元) + - generic [ref=e58]: "Expected property name or '}' in JSON at position 1 (line 1 column 2)" + - generic [ref=e59]: + - figure "图表,共有0个系列": + - generic [ref=e60]: + - img "interactive chart" + - region [ref=e61] + - toolbar "标注" [ref=e62]: + - button "库" [ref=e63] [cursor=pointer] + - button "指" [ref=e64] [cursor=pointer] + - button "均" [ref=e65] [cursor=pointer] + - button "Line Tool" [disabled] [ref=e66] + - button "Text Tool" [disabled] [ref=e67] + - button "Shape Tool" [disabled] [ref=e68] + - button "Fibonacci Tool" [disabled] [ref=e69] + - button "全屏(F11)" [ref=e70] [cursor=pointer] + - button "Clear annotations" [disabled] [ref=e71] + - button "切换到表格" [ref=e72] [cursor=pointer]: + - generic: 趋 + - status: + - generic: 请选择右侧分类项 + - toolbar "缩放" [ref=e73]: + - button "缩小" [disabled] [ref=e74] + - button "放大" [ref=e75] [cursor=pointer] + - button "左移" [disabled] [ref=e76] + - button "右移" [disabled] [ref=e77] + - button "重置" [disabled] [ref=e78] + - button "收起选择区" [expanded] [ref=e81] [cursor=pointer] + - complementary "选择内容" [ref=e85]: + - tablist "选择内容切换项" [ref=e86]: + - tab "自然地理区位" [selected] [ref=e87] [cursor=pointer] + - tab "设施类别" [ref=e88] [cursor=pointer] + - tab "建设阶段" [ref=e89] [cursor=pointer] + - tab "规划形式" [ref=e90] [cursor=pointer] + - generic [ref=e91]: + - generic [ref=e92]: 自然地理区位 + - generic [ref=e93]: "Expected property name or '}' in JSON at position 1 (line 1 column 2)" + - dialog "建筑性质筛选" [ref=e108]: + - generic [ref=e109]: + - heading "建筑性质" [level=2] [ref=e110] + - button "关闭" [ref=e111] [cursor=pointer]: × + - searchbox "搜索" [ref=e113] + - generic [ref=e114]: 未选择 + - tree [ref=e116]: + - treeitem [ref=e117]: + - button "公共建筑" [ref=e120] [cursor=pointer] + - treeitem [ref=e123]: + - button "民用建筑" [ref=e126] [cursor=pointer] + - treeitem [ref=e129]: + - button "工业建筑" [ref=e132] [cursor=pointer] + - generic [ref=e135]: + - button "清空当前" [ref=e136] [cursor=pointer] + - button "取消" [ref=e137] [cursor=pointer] + - button "确认" [ref=e138] [cursor=pointer] \ No newline at end of file diff --git a/.playwright-cli/page-2026-08-16T07-14-31-423Z.yml b/.playwright-cli/page-2026-08-16T07-14-31-423Z.yml new file mode 100644 index 0000000..7238b2b --- /dev/null +++ b/.playwright-cli/page-2026-08-16T07-14-31-423Z.yml @@ -0,0 +1,82 @@ +- main [ref=e3]: + - generic: + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - region "年度费用模板" [ref=e4]: + - generic "筛选条件" [ref=e5]: + - button "省市区" [ref=e6] [cursor=pointer] + - button "自然地理区位" [ref=e12] [cursor=pointer] + - button "设施类别" [ref=e17] [cursor=pointer] + - button "建筑性质" [ref=e23] [cursor=pointer] + - button "建设阶段" [ref=e28] [cursor=pointer] + - button "规划形式" [ref=e35] [cursor=pointer] + - button "时间" [ref=e42] [cursor=pointer] + - button "面积" [ref=e46] [cursor=pointer] + - region "年度总费用图表" [ref=e54]: + - generic [ref=e55]: + - button "纵坐标:造价(元)" [ref=e57] [cursor=pointer]: 造价(元) + - generic [ref=e58]: "Expected property name or '}' in JSON at position 1 (line 1 column 2)" + - generic [ref=e59]: + - figure "图表,共有0个系列": + - generic [ref=e60]: + - img "interactive chart" + - region [ref=e61] + - toolbar "标注" [ref=e62]: + - button "库" [ref=e63] [cursor=pointer] + - button "指" [ref=e64] [cursor=pointer] + - button "均" [ref=e65] [cursor=pointer] + - button "Line Tool" [disabled] [ref=e66] + - button "Text Tool" [disabled] [ref=e67] + - button "Shape Tool" [disabled] [ref=e68] + - button "Fibonacci Tool" [disabled] [ref=e69] + - button "全屏(F11)" [ref=e70] [cursor=pointer] + - button "Clear annotations" [disabled] [ref=e71] + - button "切换到表格" [ref=e72] [cursor=pointer]: + - generic: 趋 + - status: + - generic: 请选择右侧分类项 + - toolbar "缩放" [ref=e73]: + - button "缩小" [disabled] [ref=e74] + - button "放大" [ref=e75] [cursor=pointer] + - button "左移" [disabled] [ref=e76] + - button "右移" [disabled] [ref=e77] + - button "重置" [disabled] [ref=e78] + - button "收起选择区" [expanded] [ref=e81] [cursor=pointer] + - complementary "选择内容" [ref=e85]: + - tablist "选择内容切换项" [ref=e86]: + - tab "自然地理区位" [selected] [ref=e87] [cursor=pointer] + - tab "设施类别" [ref=e88] [cursor=pointer] + - tab "建设阶段" [ref=e89] [cursor=pointer] + - tab "规划形式" [ref=e90] [cursor=pointer] + - generic [ref=e91]: + - generic [ref=e92]: 自然地理区位 + - generic [ref=e93]: "Expected property name or '}' in JSON at position 1 (line 1 column 2)" + - dialog "建筑性质筛选" [ref=e108]: + - generic [ref=e109]: + - heading "建筑性质" [level=2] [ref=e110] + - button "关闭" [ref=e111] [cursor=pointer]: × + - searchbox "搜索" [ref=e113]: 公共 + - generic [ref=e114]: 已选 1 项 + - tree [ref=e139]: + - treeitem [ref=e140]: + - button "公共建筑" [active] [pressed] [ref=e143] [cursor=pointer] + - generic [ref=e135]: + - button "清空当前" [ref=e136] [cursor=pointer] + - button "取消" [ref=e137] [cursor=pointer] + - button "确认" [ref=e138] [cursor=pointer] \ No newline at end of file diff --git a/.playwright-cli/page-2026-08-16T07-14-45-319Z.yml b/.playwright-cli/page-2026-08-16T07-14-45-319Z.yml new file mode 100644 index 0000000..8979fca --- /dev/null +++ b/.playwright-cli/page-2026-08-16T07-14-45-319Z.yml @@ -0,0 +1,72 @@ +- main [ref=e3]: + - generic: + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - region "年度费用模板" [ref=e4]: + - generic "筛选条件" [ref=e5]: + - button "省市区" [ref=e6] [cursor=pointer] + - button "自然地理区位" [ref=e12] [cursor=pointer] + - button "设施类别" [ref=e17] [cursor=pointer] + - button "建筑性质 1" [pressed] [ref=e146] [cursor=pointer]: + - generic [ref=e27]: 建筑性质 + - strong [ref=e147]: "1" + - button "建设阶段" [ref=e28] [cursor=pointer] + - button "规划形式" [ref=e35] [cursor=pointer] + - button "时间" [ref=e42] [cursor=pointer] + - button "面积" [ref=e46] [cursor=pointer] + - button "清空" [ref=e148] [cursor=pointer] + - region "年度总费用图表" [ref=e54]: + - generic [ref=e55]: + - button "纵坐标:造价(元)" [ref=e57] [cursor=pointer]: 造价(元) + - generic [ref=e149]: "Expected property name or '}' in JSON at position 1 (line 1 column 2)" + - generic [ref=e59]: + - figure "图表,共有0个系列": + - generic [ref=e60]: + - img "interactive chart" + - region [ref=e61] + - toolbar "标注" [ref=e62]: + - button "库" [ref=e63] [cursor=pointer] + - button "指" [ref=e64] [cursor=pointer] + - button "均" [ref=e65] [cursor=pointer] + - button "Line Tool" [disabled] [ref=e66] + - button "Text Tool" [disabled] [ref=e67] + - button "Shape Tool" [disabled] [ref=e68] + - button "Fibonacci Tool" [disabled] [ref=e69] + - button "全屏(F11)" [ref=e70] [cursor=pointer] + - button "Clear annotations" [disabled] [ref=e71] + - button "切换到表格" [ref=e72] [cursor=pointer]: + - generic: 趋 + - status: + - generic: 请选择右侧分类项 + - toolbar "缩放" [ref=e73]: + - button "缩小" [disabled] [ref=e74] + - button "放大" [ref=e75] [cursor=pointer] + - button "左移" [disabled] [ref=e76] + - button "右移" [disabled] [ref=e77] + - button "重置" [disabled] [ref=e78] + - button "收起选择区" [expanded] [ref=e81] [cursor=pointer] + - complementary "选择内容" [ref=e85]: + - tablist "选择内容切换项" [ref=e86]: + - tab "自然地理区位" [selected] [ref=e87] [cursor=pointer] + - tab "设施类别" [ref=e88] [cursor=pointer] + - tab "建设阶段" [ref=e89] [cursor=pointer] + - tab "规划形式" [ref=e90] [cursor=pointer] + - generic [ref=e91]: + - generic [ref=e92]: 自然地理区位 + - generic [ref=e93]: "Expected property name or '}' in JSON at position 1 (line 1 column 2)" \ No newline at end of file diff --git a/.playwright-cli/page-2026-08-16T07-15-28-927Z.yml b/.playwright-cli/page-2026-08-16T07-15-28-927Z.yml new file mode 100644 index 0000000..c6ec3c0 --- /dev/null +++ b/.playwright-cli/page-2026-08-16T07-15-28-927Z.yml @@ -0,0 +1,89 @@ +- main [ref=e3]: + - generic: + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - region "年度费用模板" [ref=e4]: + - generic "筛选条件" [ref=e5]: + - button "省市区" [ref=e6] [cursor=pointer] + - button "自然地理区位" [ref=e12] [cursor=pointer] + - button "设施类别" [ref=e17] [cursor=pointer] + - button "建筑性质 1" [active] [pressed] [ref=e146] [cursor=pointer]: + - generic [ref=e27]: 建筑性质 + - strong [ref=e147]: "1" + - button "建设阶段" [ref=e28] [cursor=pointer] + - button "规划形式" [ref=e35] [cursor=pointer] + - button "时间" [ref=e42] [cursor=pointer] + - button "面积" [ref=e46] [cursor=pointer] + - button "清空" [ref=e148] [cursor=pointer] + - region "年度总费用图表" [ref=e54]: + - generic [ref=e55]: + - button "纵坐标:造价(元)" [ref=e57] [cursor=pointer]: 造价(元) + - generic [ref=e149]: "Expected property name or '}' in JSON at position 1 (line 1 column 2)" + - generic [ref=e59]: + - figure "图表,共有0个系列": + - generic [ref=e60]: + - img "interactive chart" + - region [ref=e61] + - toolbar "标注" [ref=e62]: + - button "库" [ref=e63] [cursor=pointer] + - button "指" [ref=e64] [cursor=pointer] + - button "均" [ref=e65] [cursor=pointer] + - button "Line Tool" [disabled] [ref=e66] + - button "Text Tool" [disabled] [ref=e67] + - button "Shape Tool" [disabled] [ref=e68] + - button "Fibonacci Tool" [disabled] [ref=e69] + - button "全屏(F11)" [ref=e70] [cursor=pointer] + - button "Clear annotations" [disabled] [ref=e71] + - button "切换到表格" [ref=e72] [cursor=pointer]: + - generic: 趋 + - status: + - generic: 请选择右侧分类项 + - toolbar "缩放" [ref=e73]: + - button "缩小" [disabled] [ref=e74] + - button "放大" [ref=e75] [cursor=pointer] + - button "左移" [disabled] [ref=e76] + - button "右移" [disabled] [ref=e77] + - button "重置" [disabled] [ref=e78] + - button "收起选择区" [expanded] [ref=e81] [cursor=pointer] + - complementary "选择内容" [ref=e85]: + - tablist "选择内容切换项" [ref=e86]: + - tab "自然地理区位" [selected] [ref=e87] [cursor=pointer] + - tab "设施类别" [ref=e88] [cursor=pointer] + - tab "建设阶段" [ref=e89] [cursor=pointer] + - tab "规划形式" [ref=e90] [cursor=pointer] + - generic [ref=e91]: + - generic [ref=e92]: 自然地理区位 + - generic [ref=e93]: "Expected property name or '}' in JSON at position 1 (line 1 column 2)" + - dialog "建筑性质筛选" [ref=e150]: + - generic [ref=e151]: + - heading "建筑性质" [level=2] [ref=e152] + - button "关闭" [ref=e153] [cursor=pointer]: × + - searchbox "搜索" [ref=e155] + - generic [ref=e156]: 已选 1 项 + - tree [ref=e158]: + - treeitem [ref=e159]: + - button "公共建筑" [pressed] [ref=e162] [cursor=pointer] + - treeitem [ref=e165]: + - button "民用建筑" [ref=e168] [cursor=pointer] + - treeitem [ref=e171]: + - button "工业建筑" [ref=e174] [cursor=pointer] + - generic [ref=e177]: + - button "清空当前" [ref=e178] [cursor=pointer] + - button "取消" [ref=e179] [cursor=pointer] + - button "确认" [ref=e180] [cursor=pointer] \ No newline at end of file diff --git a/.playwright-cli/page-2026-08-16T07-18-55-077Z.yml b/.playwright-cli/page-2026-08-16T07-18-55-077Z.yml new file mode 100644 index 0000000..e69de29 diff --git a/.playwright-cli/page-2026-08-16T07-19-16-089Z.yml b/.playwright-cli/page-2026-08-16T07-19-16-089Z.yml new file mode 100644 index 0000000..bee3d66 --- /dev/null +++ b/.playwright-cli/page-2026-08-16T07-19-16-089Z.yml @@ -0,0 +1,70 @@ +- main [ref=e3]: + - generic: + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - region "年度费用模板" [ref=e4]: + - generic "筛选条件" [ref=e5]: + - button "省市区" [ref=e6] [cursor=pointer] + - button "自然地理区位" [ref=e12] [cursor=pointer] + - button "设施类别" [ref=e17] [cursor=pointer] + - button "建筑性质" [ref=e23] [cursor=pointer] + - button "建设阶段" [ref=e28] [cursor=pointer] + - button "规划形式" [ref=e35] [cursor=pointer] + - button "时间" [ref=e42] [cursor=pointer] + - button "面积" [ref=e46] [cursor=pointer] + - region "年度总费用图表" [ref=e54]: + - generic [ref=e55]: + - button "纵坐标:造价(元)" [ref=e57] [cursor=pointer]: 造价(元) + - generic [ref=e58]: 正在加载数据 + - generic [ref=e59]: + - figure "图表,共有0个系列": + - generic [ref=e60]: + - img "interactive chart" + - region [ref=e61] + - toolbar "标注" [ref=e62]: + - button "库" [ref=e63] [cursor=pointer] + - button "指" [ref=e64] [cursor=pointer] + - button "均" [ref=e65] [cursor=pointer] + - button "Line Tool" [disabled] [ref=e66] + - button "Text Tool" [disabled] [ref=e67] + - button "Shape Tool" [disabled] [ref=e68] + - button "Fibonacci Tool" [disabled] [ref=e69] + - button "全屏(F11)" [ref=e70] [cursor=pointer] + - button "Clear annotations" [disabled] [ref=e71] + - button "切换到表格" [ref=e72] [cursor=pointer]: + - generic: 趋 + - status: + - generic: 请选择右侧分类项 + - toolbar "缩放" [ref=e73]: + - button "缩小" [disabled] [ref=e74] + - button "放大" [ref=e75] [cursor=pointer] + - button "左移" [disabled] [ref=e76] + - button "右移" [disabled] [ref=e77] + - button "重置" [disabled] [ref=e78] + - generic [ref=e79]: 正在加载数据 + - button "收起选择区" [expanded] [ref=e81] [cursor=pointer] + - complementary "选择内容" [ref=e85]: + - tablist "选择内容切换项" [ref=e86]: + - tab "自然地理区位" [selected] [ref=e87] [cursor=pointer] + - tab "设施类别" [ref=e88] [cursor=pointer] + - tab "建设阶段" [ref=e89] [cursor=pointer] + - tab "规划形式" [ref=e90] [cursor=pointer] + - generic [ref=e91]: + - generic [ref=e92]: 自然地理区位 + - generic [ref=e93]: 加载中 \ No newline at end of file diff --git a/.playwright-cli/page-2026-08-16T07-19-36-679Z.yml b/.playwright-cli/page-2026-08-16T07-19-36-679Z.yml new file mode 100644 index 0000000..c6bcf90 --- /dev/null +++ b/.playwright-cli/page-2026-08-16T07-19-36-679Z.yml @@ -0,0 +1,85 @@ +- main [ref=e3]: + - generic: + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - generic: 众为数字化管理平台 + - region "年度费用模板" [ref=e4]: + - generic "筛选条件" [ref=e5]: + - button "省市区" [ref=e6] [cursor=pointer] + - button "自然地理区位" [ref=e12] [cursor=pointer] + - button "设施类别" [ref=e17] [cursor=pointer] + - button "建筑性质" [active] [ref=e23] [cursor=pointer] + - button "建设阶段" [ref=e28] [cursor=pointer] + - button "规划形式" [ref=e35] [cursor=pointer] + - button "时间" [ref=e42] [cursor=pointer] + - button "面积" [ref=e46] [cursor=pointer] + - region "年度总费用图表" [ref=e54]: + - generic [ref=e55]: + - button "纵坐标:造价(元)" [ref=e57] [cursor=pointer]: 造价(元) + - generic [ref=e59]: + - figure "图表,共有0个系列": + - generic [ref=e60]: + - img "interactive chart" + - region [ref=e61] + - toolbar "标注" [ref=e62]: + - button "库" [ref=e63] [cursor=pointer] + - button "指" [ref=e64] [cursor=pointer] + - button "均" [ref=e65] [cursor=pointer] + - button "Line Tool" [disabled] [ref=e66] + - button "Text Tool" [disabled] [ref=e67] + - button "Shape Tool" [disabled] [ref=e68] + - button "Fibonacci Tool" [disabled] [ref=e69] + - button "全屏(F11)" [ref=e70] [cursor=pointer] + - button "Clear annotations" [disabled] [ref=e71] + - button "切换到表格" [ref=e72] [cursor=pointer]: + - generic: 趋 + - status: + - generic: 请选择右侧分类项 + - toolbar "缩放" [ref=e73]: + - button "缩小" [disabled] [ref=e74] + - button "放大" [ref=e75] [cursor=pointer] + - button "左移" [disabled] [ref=e76] + - button "右移" [disabled] [ref=e77] + - button "重置" [disabled] [ref=e78] + - button "收起选择区" [expanded] [ref=e81] [cursor=pointer] + - complementary "选择内容" [ref=e85]: + - tablist "选择内容切换项" [ref=e86]: + - tab "自然地理区位" [selected] [ref=e87] [cursor=pointer] + - tab "设施类别" [ref=e88] [cursor=pointer] + - tab "建设阶段" [ref=e89] [cursor=pointer] + - tab "规划形式" [ref=e90] [cursor=pointer] + - generic [ref=e91]: + - generic [ref=e92]: 自然地理区位 + - generic [ref=e93]: 接口待接入 + - dialog "建筑性质筛选" [ref=e94]: + - generic [ref=e95]: + - heading "建筑性质" [level=2] [ref=e96] + - button "关闭" [ref=e97] [cursor=pointer]: × + - searchbox "搜索" [ref=e99] + - generic [ref=e100]: 未选择 + - tree [ref=e102]: + - treeitem [ref=e103]: + - button "公共建筑" [ref=e106] [cursor=pointer] + - treeitem [ref=e109]: + - button "民用建筑" [ref=e112] [cursor=pointer] + - treeitem [ref=e115]: + - button "工业建筑" [ref=e118] [cursor=pointer] + - generic [ref=e121]: + - button "清空当前" [ref=e122] [cursor=pointer] + - button "取消" [ref=e123] [cursor=pointer] + - button "确认" [ref=e124] [cursor=pointer] \ No newline at end of file diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..48c3817 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,44 @@ + +# GitNexus — Code Intelligence + +This project is indexed by GitNexus as **agchart** (187 symbols, 490 relationships, 20 execution flows). Use the GitNexus MCP tools to understand code, assess impact, and navigate safely. + +> Index stale? Run `node .gitnexus/run.cjs analyze` from the project root — it auto-selects an available runner. No `.gitnexus/run.cjs` yet? `npx gitnexus analyze` (npm 11 crash → `npm i -g gitnexus`; #1939). + +## Always Do + +- **MUST run impact analysis before editing any symbol.** Before modifying a function, class, or method, run `impact({target: "symbolName", direction: "upstream"})` and report the blast radius (direct callers, affected processes, risk level) to the user. +- **MUST run `detect_changes()` before committing** to verify your changes only affect expected symbols and execution flows. For regression review, compare against the default branch: `detect_changes({scope: "compare", base_ref: "main"})`. +- **MUST warn the user** if impact analysis returns HIGH or CRITICAL risk before proceeding with edits. +- When exploring unfamiliar code, use `query({search_query: "concept"})` to find execution flows instead of grepping. It returns process-grouped results ranked by relevance. +- When you need full context on a specific symbol — callers, callees, which execution flows it participates in — use `context({name: "symbolName"})`. +- For security review, `explain({target: "fileOrSymbol"})` lists taint findings (source→sink flows; needs `analyze --pdg`). + +## Never Do + +- NEVER edit a function, class, or method without first running `impact` on it. +- NEVER ignore HIGH or CRITICAL risk warnings from impact analysis. +- NEVER rename symbols with find-and-replace — use `rename` which understands the call graph. +- NEVER commit changes without running `detect_changes()` to check affected scope. + +## Resources + +| Resource | Use for | +|----------|---------| +| `gitnexus://repo/agchart/context` | Codebase overview, check index freshness | +| `gitnexus://repo/agchart/clusters` | All functional areas | +| `gitnexus://repo/agchart/processes` | All execution flows | +| `gitnexus://repo/agchart/process/{name}` | Step-by-step execution trace | + +## CLI + +| Task | Read this skill file | +|------|---------------------| +| Understand architecture / "How does X work?" | `.claude/skills/gitnexus/gitnexus-exploring/SKILL.md` | +| Blast radius / "What breaks if I change X?" | `.claude/skills/gitnexus/gitnexus-impact-analysis/SKILL.md` | +| Trace bugs / "Why is X failing?" | `.claude/skills/gitnexus/gitnexus-debugging/SKILL.md` | +| Rename / extract / split / refactor | `.claude/skills/gitnexus/gitnexus-refactoring/SKILL.md` | +| Tools, resources, schema reference | `.claude/skills/gitnexus/gitnexus-guide/SKILL.md` | +| Index, status, clean, wiki CLI commands | `.claude/skills/gitnexus/gitnexus-cli/SKILL.md` | + + \ No newline at end of file diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..48c3817 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,44 @@ + +# GitNexus — Code Intelligence + +This project is indexed by GitNexus as **agchart** (187 symbols, 490 relationships, 20 execution flows). Use the GitNexus MCP tools to understand code, assess impact, and navigate safely. + +> Index stale? Run `node .gitnexus/run.cjs analyze` from the project root — it auto-selects an available runner. No `.gitnexus/run.cjs` yet? `npx gitnexus analyze` (npm 11 crash → `npm i -g gitnexus`; #1939). + +## Always Do + +- **MUST run impact analysis before editing any symbol.** Before modifying a function, class, or method, run `impact({target: "symbolName", direction: "upstream"})` and report the blast radius (direct callers, affected processes, risk level) to the user. +- **MUST run `detect_changes()` before committing** to verify your changes only affect expected symbols and execution flows. For regression review, compare against the default branch: `detect_changes({scope: "compare", base_ref: "main"})`. +- **MUST warn the user** if impact analysis returns HIGH or CRITICAL risk before proceeding with edits. +- When exploring unfamiliar code, use `query({search_query: "concept"})` to find execution flows instead of grepping. It returns process-grouped results ranked by relevance. +- When you need full context on a specific symbol — callers, callees, which execution flows it participates in — use `context({name: "symbolName"})`. +- For security review, `explain({target: "fileOrSymbol"})` lists taint findings (source→sink flows; needs `analyze --pdg`). + +## Never Do + +- NEVER edit a function, class, or method without first running `impact` on it. +- NEVER ignore HIGH or CRITICAL risk warnings from impact analysis. +- NEVER rename symbols with find-and-replace — use `rename` which understands the call graph. +- NEVER commit changes without running `detect_changes()` to check affected scope. + +## Resources + +| Resource | Use for | +|----------|---------| +| `gitnexus://repo/agchart/context` | Codebase overview, check index freshness | +| `gitnexus://repo/agchart/clusters` | All functional areas | +| `gitnexus://repo/agchart/processes` | All execution flows | +| `gitnexus://repo/agchart/process/{name}` | Step-by-step execution trace | + +## CLI + +| Task | Read this skill file | +|------|---------------------| +| Understand architecture / "How does X work?" | `.claude/skills/gitnexus/gitnexus-exploring/SKILL.md` | +| Blast radius / "What breaks if I change X?" | `.claude/skills/gitnexus/gitnexus-impact-analysis/SKILL.md` | +| Trace bugs / "Why is X failing?" | `.claude/skills/gitnexus/gitnexus-debugging/SKILL.md` | +| Rename / extract / split / refactor | `.claude/skills/gitnexus/gitnexus-refactoring/SKILL.md` | +| Tools, resources, schema reference | `.claude/skills/gitnexus/gitnexus-guide/SKILL.md` | +| Index, status, clean, wiki CLI commands | `.claude/skills/gitnexus/gitnexus-cli/SKILL.md` | + + \ No newline at end of file diff --git a/output/playwright/building-nature/desktop-dialog.png b/output/playwright/building-nature/desktop-dialog.png new file mode 100644 index 0000000..ec26fa1 Binary files /dev/null and b/output/playwright/building-nature/desktop-dialog.png differ diff --git a/output/playwright/building-nature/mobile-dialog.png b/output/playwright/building-nature/mobile-dialog.png new file mode 100644 index 0000000..77437e6 Binary files /dev/null and b/output/playwright/building-nature/mobile-dialog.png differ diff --git a/output/playwright/building-nature/mobile-toolbar.png b/output/playwright/building-nature/mobile-toolbar.png new file mode 100644 index 0000000..fd52e0f Binary files /dev/null and b/output/playwright/building-nature/mobile-toolbar.png differ diff --git a/output/playwright/building-nature/playwright-cli.json b/output/playwright/building-nature/playwright-cli.json new file mode 100644 index 0000000..379c59a --- /dev/null +++ b/output/playwright/building-nature/playwright-cli.json @@ -0,0 +1,14 @@ +{ + "browser": { + "launchOptions": { + "headless": true, + "executablePath": "C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe" + }, + "contextOptions": { + "viewport": { + "width": 1440, + "height": 900 + } + } + } +} diff --git a/src/App.tsx b/src/App.tsx index 47f648e..ce3668e 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -12,7 +12,7 @@ import { } from 'ag-grid-community'; import type { AgCartesianChartOptions } from 'ag-charts-community'; import { ModuleRegistry } from 'ag-charts-community'; -import { Building2, CalendarRange, Construction, LayoutGrid, Library, LocateFixed, MapPinned, PanelRightClose, PanelRightOpen, Ruler, Waypoints } from 'lucide-react'; +import { Building2, CalendarRange, Construction, House, LayoutGrid, Library, LocateFixed, MapPinned, PanelRightClose, PanelRightOpen, Ruler, Waypoints } from 'lucide-react'; import { AnnotationsModule, ContextMenuModule, @@ -29,6 +29,12 @@ AgGridModuleRegistry.registerModules([AgGridAllCommunityModule]); const API_BASE_URL = 'https://nest.zwgczx.com/api/v1'; // const API_BASE_URL = 'http://127.0.0.1:9089/api/v1'; +const API_ROUTES = { + filterTree: '/zw/getBuildingFacilityObjectFilterTree', + filterTreeSearch: '/zw/getBuildingFacilityObjectFilterTreeSearch', + statsBatch: '/zw/getBuildingFacilityObjectStatsBatch', +} as const; + const statisticOptions = [ { key: 'minValue', label: '最低值', shortLabel: '低' }, { key: 'maxValue', label: '最高值', shortLabel: '高' }, @@ -67,6 +73,7 @@ const filterOptions = [ { key: 'region', label: '省市区', icon: MapPinned }, { key: 'geoLocation', label: '自然地理区位', icon: LocateFixed }, { key: 'facilityType', label: '设施类别', icon: Building2 }, + { key: 'buildingNature', label: '建筑性质', icon: House }, { key: 'constructionStage', label: '建设阶段', icon: Construction }, { key: 'planningForm', label: '规划形式', icon: LayoutGrid }, { key: 'time', label: '时间', icon: CalendarRange }, @@ -121,6 +128,26 @@ const contentTreeConfigs = { }, } as const; +const buildingNatureBrowserConfig = { + conditionEndpoint: '/api/public/browser/condition/256', + dataEndpoint: '/api/public/browser/data/256', + treeid: '95504', + fieldid: '316390', + searchbrowserid: '36523', + browserParams: { + requestid: '', + isshowsearchtab: '1', + workflowid: '182028', + wfid: '182028', + billid: '-1815', + f_weaver_belongto_userid: '', + f_weaver_belongto_usertype: '', + wf_isagent: '', + wf_beagenter: '', + wfCreater: '', + }, +} as const; + const chartLineColors = ['#0078a8', '#d14d72', '#1f8f4d', '#d96f23', '#6b5cc8', '#0d7680', '#9a6b12', '#b24b38']; const defaultTemplateFilterNode = { id: '3', @@ -583,6 +610,10 @@ function isIndicatorTreeFilterKey(filterKey: FilterKey): filterKey is 'indicator return filterKey === 'indicatorTree'; } +function isBuildingNatureFilterKey(filterKey: FilterKey): filterKey is 'buildingNature' { + return filterKey === 'buildingNature'; +} + function isRangeFilterKey(filterKey: FilterKey): filterKey is RangeFilterKey { return filterKey === 'time' || filterKey === 'area'; } @@ -750,6 +781,7 @@ function App() { region: false, geoLocation: false, facilityType: false, + buildingNature: false, constructionStage: false, planningForm: false, time: false, @@ -795,6 +827,7 @@ function App() { region: [], geoLocation: [], facilityType: [], + buildingNature: [], constructionStage: [], planningForm: [], time: [], @@ -806,6 +839,7 @@ function App() { region: false, geoLocation: false, facilityType: false, + buildingNature: false, constructionStage: false, planningForm: false, time: false, @@ -817,6 +851,7 @@ function App() { region: null, geoLocation: null, facilityType: null, + buildingNature: null, constructionStage: null, planningForm: null, time: null, @@ -828,6 +863,7 @@ function App() { region: [], geoLocation: [], facilityType: [], + buildingNature: [], constructionStage: [], planningForm: [], time: [], @@ -839,6 +875,7 @@ function App() { region: false, geoLocation: false, facilityType: false, + buildingNature: false, constructionStage: false, planningForm: false, time: false, @@ -850,6 +887,7 @@ function App() { region: null, geoLocation: null, facilityType: null, + buildingNature: null, constructionStage: null, planningForm: null, time: null, @@ -861,6 +899,7 @@ function App() { region: [], geoLocation: [], facilityType: [], + buildingNature: [], constructionStage: [], planningForm: [], time: [], @@ -878,6 +917,7 @@ function App() { region: 0, geoLocation: 0, facilityType: 0, + buildingNature: 0, constructionStage: 0, planningForm: 0, time: 0, @@ -1201,6 +1241,7 @@ function App() { .filter((filter) => filter.nodes.length > 0), [ appliedFilters.area, + appliedFilters.buildingNature, appliedFilters.constructionStage, appliedFilters.facilityType, appliedFilters.geoLocation, @@ -1259,6 +1300,65 @@ function App() { return normalizeTreeRows(rows); }; + const fetchBuildingNatureFilterTree = async (nodeId?: string, signal?: AbortSignal) => { + const treeParams = { + ...browserTreeDefaults, + ...buildingNatureBrowserConfig.browserParams, + treeid: buildingNatureBrowserConfig.treeid, + cube_treeid: buildingNatureBrowserConfig.treeid, + searchbrowserid: buildingNatureBrowserConfig.searchbrowserid, + fieldid: buildingNatureBrowserConfig.fieldid, + }; + const requestOptions: RequestInit = { + credentials: 'include', + signal, + headers: { + 'X-Requested-With': 'XMLHttpRequest', + }, + }; + + if (!nodeId) { + const conditionResponse = await fetch( + `${buildingNatureBrowserConfig.conditionEndpoint}?${buildQuery(treeParams)}`, + requestOptions, + ); + if (!conditionResponse.ok) { + throw new Error(`建筑性质浏览条件加载失败:HTTP ${conditionResponse.status}`); + } + const conditionPayload = await conditionResponse.json() as { status?: boolean; msg?: string }; + if (conditionPayload.status === false) { + throw new Error(conditionPayload.msg || '建筑性质浏览条件加载失败'); + } + } + + const dataParams = nodeId + ? { + ...treeParams, + type: '2', + id: nodeId, + isVirtual: '', + } + : { + ...treeParams, + pageSize: '10', + current: '1', + min: '1', + max: '10', + }; + const dataResponse = await fetch( + `${buildingNatureBrowserConfig.dataEndpoint}?${buildQuery(dataParams)}`, + requestOptions, + ); + if (!dataResponse.ok) { + throw new Error(`建筑性质浏览数据加载失败:HTTP ${dataResponse.status}`); + } + const dataPayload = await dataResponse.json() as { status?: boolean; msg?: string }; + if (dataPayload.status === false) { + throw new Error(dataPayload.msg || '建筑性质浏览数据加载失败'); + } + return normalizeTreeRows(pickArray(dataPayload)); + }; + const normalizeBackendTree = (nodes: TreeNode[]): TreeNode[] => nodes.map((node) => ({ ...node, hasChildren: node.children.length > 0 || node.hasChildren, @@ -1284,7 +1384,7 @@ function App() { }; const fetchRegionFilterTree = async (signal?: AbortSignal) => { - const response = await fetch(`${API_BASE_URL}/zw/getBuildingFunctionCostFilterTree?${buildQuery({ key: 'region' })}`, { + const response = await fetch(`${API_BASE_URL}${API_ROUTES.filterTree}?${buildQuery({ key: 'region' })}`, { signal, headers: { 'X-Requested-With': 'XMLHttpRequest', @@ -1299,7 +1399,7 @@ function App() { }; const fetchTemplateLibraryTree = async (signal?: AbortSignal) => { - const response = await fetch(`${API_BASE_URL}/zw/getBuildingFunctionCostFilterTree?${buildQuery({ key: 'templateLibrary' })}`, { + const response = await fetch(`${API_BASE_URL}${API_ROUTES.filterTree}?${buildQuery({ key: 'templateLibrary' })}`, { signal, headers: { 'X-Requested-With': 'XMLHttpRequest', @@ -1314,7 +1414,7 @@ function App() { }; const fetchIndicatorTree = async (signal?: AbortSignal) => { - const response = await fetch(`${API_BASE_URL}/zw/getBuildingFunctionCostFilterTree?${buildQuery({ key: 'indicatorTree', templateId: selectedTemplateId })}`, { + const response = await fetch(`${API_BASE_URL}${API_ROUTES.filterTree}?${buildQuery({ key: 'indicatorTree', templateId: selectedTemplateId })}`, { signal, headers: { 'X-Requested-With': 'XMLHttpRequest', @@ -1329,7 +1429,7 @@ function App() { }; const fetchBackendFilterTreeSearch = async (filterKey: FilterKey, keyword: string, signal?: AbortSignal) => { - const response = await fetch(`${API_BASE_URL}/zw/getBuildingFunctionCostFilterTreeSearch?${buildQuery({ + const response = await fetch(`${API_BASE_URL}${API_ROUTES.filterTreeSearch}?${buildQuery({ key: filterKey, keyword, nodePrefix: isContentFilterKey(filterKey) ? getTreeNodePrefix(filterTreeByKey[filterKey]) : '', @@ -1372,6 +1472,12 @@ function App() { }; const loadFilterTree = async (filterKey: FilterKey, keyword?: string, signal?: AbortSignal) => { + if (isBuildingNatureFilterKey(filterKey)) { + const nodes = filterTreeByKey.buildingNature.length > 0 + ? filterTreeByKey.buildingNature + : await fetchBuildingNatureFilterTree(undefined, signal); + return keyword?.trim() ? filterTreeNodesByKeyword(nodes, keyword) : nodes; + } if (filterKey === 'region') { const nodes = await fetchRegionFilterTree(signal); return keyword?.trim() ? filterTreeNodesByKeyword(nodes, keyword) : nodes; @@ -1578,7 +1684,7 @@ function App() { return; } - if (isTemplateFilterKey(filterKey) || filterKey === 'indicatorTree') { + if (isTemplateFilterKey(filterKey) || filterKey === 'indicatorTree' || isBuildingNatureFilterKey(filterKey)) { filterSearchTimerRef.current = window.setTimeout(() => { setFilterSearchLoadingByKey((current) => ({ ...current, [filterKey]: true })); setFilterSearchErrorByKey((current) => ({ ...current, [filterKey]: null })); @@ -1635,10 +1741,13 @@ function App() { })), })); - if (node.loaded || !isContentFilterKey(filterModalKey)) return; + if (node.loaded || (!isContentFilterKey(filterModalKey) && !isBuildingNatureFilterKey(filterModalKey))) return; const currentFilterKey = filterModalKey; - fetchContentTree(currentFilterKey, nodeId) + const childRequest = isBuildingNatureFilterKey(currentFilterKey) + ? fetchBuildingNatureFilterTree(nodeId) + : fetchContentTree(currentFilterKey, nodeId); + childRequest .then((children) => { setFilterTreeByKey((current) => ({ ...current, @@ -1895,7 +2004,7 @@ function App() { return; } - const response = await fetch(`${API_BASE_URL}/zw/getBuildingFunctionCostStatsBatch`, { + const response = await fetch(`${API_BASE_URL}${API_ROUTES.statsBatch}`, { method: 'POST', signal: controller.signal, headers: { @@ -2437,6 +2546,7 @@ function App() { region: [], geoLocation: [], facilityType: [], + buildingNature: [], constructionStage: [], planningForm: [], time: [],