codeimpact 0.3.2 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -8203,7 +8203,13 @@ var init_workspace2 = __esm({
8203
8203
  ".git/**",
8204
8204
  "coverage/**",
8205
8205
  ".next/**",
8206
- "build/**"
8206
+ "build/**",
8207
+ "venv/**",
8208
+ ".venv/**",
8209
+ "env/**",
8210
+ "__pycache__/**",
8211
+ "vendor/**",
8212
+ "knowledge/**"
8207
8213
  ],
8208
8214
  markers: {
8209
8215
  start: "<!-- code-impact:auto-start -->",
@@ -8663,22 +8669,1290 @@ var init_research_trust = __esm({
8663
8669
  }
8664
8670
  });
8665
8671
 
8666
- // src/core/agents/research-engine.ts
8667
- import { existsSync as existsSync25, readFileSync as readFileSync20, writeFileSync as writeFileSync15, mkdirSync as mkdirSync15, readdirSync as readdirSync7 } from "fs";
8672
+ // src/core/agents/hardcoded-knowledge.ts
8673
+ var TECH_KNOWLEDGE, FEATURE_NAME_RULES, FEATURE_NAME_PITFALLS, WELL_KNOWN_FEATURES, DIR_PURPOSE_MAP, SCOPE_LABELS, DOC_SOURCE_REGISTRY;
8674
+ var init_hardcoded_knowledge = __esm({
8675
+ "src/core/agents/hardcoded-knowledge.ts"() {
8676
+ "use strict";
8677
+ TECH_KNOWLEDGE = {
8678
+ "express": {
8679
+ rules: [
8680
+ "Use Router() for modular route definitions",
8681
+ "Always register error handler middleware last (4 args: err, req, res, next)"
8682
+ ],
8683
+ pitfalls: [
8684
+ "Forgetting to call next() in middleware causes request to hang",
8685
+ "Async errors in handlers need explicit try/catch or express-async-errors"
8686
+ ]
8687
+ },
8688
+ "hono": {
8689
+ rules: [
8690
+ "Use app.route() for modular route grouping",
8691
+ "Return c.json() or c.text() \u2014 do not use res.send()"
8692
+ ],
8693
+ pitfalls: [
8694
+ "Hono middleware must call next() or return a Response \u2014 skipping both hangs the request"
8695
+ ]
8696
+ },
8697
+ "better-sqlite3": {
8698
+ rules: [
8699
+ "Use db.prepare().all() for SELECT, db.prepare().run() for INSERT/UPDATE/DELETE",
8700
+ "better-sqlite3 is synchronous \u2014 do NOT use async/await with db calls",
8701
+ "All database access should go through a single module"
8702
+ ],
8703
+ pitfalls: [
8704
+ "db.exec() returns nothing \u2014 using it for SELECT gives undefined",
8705
+ 'WAL mode must be set once after opening: db.pragma("journal_mode = WAL")'
8706
+ ]
8707
+ },
8708
+ "stripe": {
8709
+ rules: [
8710
+ "Always verify webhook signatures before processing events",
8711
+ "Use idempotency keys for payment creation to prevent double-charges"
8712
+ ],
8713
+ pitfalls: [
8714
+ "Stripe webhook events may arrive out of order \u2014 handle idempotently",
8715
+ "stripe.webhooks.constructEvent() throws on invalid signature \u2014 wrap in try/catch"
8716
+ ]
8717
+ },
8718
+ "jsonwebtoken": {
8719
+ rules: [
8720
+ "Always use jwt.verify() \u2014 never trust jwt.decode() alone",
8721
+ "Set explicit expiration (expiresIn) on all tokens"
8722
+ ],
8723
+ pitfalls: [
8724
+ "Using jwt.decode() without verify() is a security vulnerability",
8725
+ 'The "none" algorithm attack \u2014 always specify algorithms: ["HS256"]'
8726
+ ]
8727
+ },
8728
+ "@modelcontextprotocol/sdk": {
8729
+ rules: [
8730
+ "Use server.tool() to register MCP tools with zod schema validation",
8731
+ "All tool handlers must return { content: [...] } response objects"
8732
+ ],
8733
+ pitfalls: [
8734
+ "Tool names must be unique across the server \u2014 duplicates silently overwrite",
8735
+ "Forgetting to call server.connect(transport) means no requests are handled"
8736
+ ]
8737
+ },
8738
+ "prisma": {
8739
+ rules: [
8740
+ "Run npx prisma generate after schema changes",
8741
+ "Use transactions for multi-table operations: prisma.$transaction()"
8742
+ ],
8743
+ pitfalls: [
8744
+ "Forgetting prisma generate after schema change causes type mismatches at runtime",
8745
+ "N+1 queries \u2014 use include/select to eagerly load relations"
8746
+ ]
8747
+ },
8748
+ "zod": {
8749
+ rules: [
8750
+ "Define schemas once, derive TypeScript types with z.infer<typeof schema>",
8751
+ "Use .safeParse() in handlers for graceful error handling"
8752
+ ],
8753
+ pitfalls: [
8754
+ ".parse() throws on invalid data \u2014 use .safeParse() in request handlers"
8755
+ ]
8756
+ },
8757
+ "vitest": {
8758
+ rules: [
8759
+ "Use describe/it/expect patterns for test organization",
8760
+ "Use vi.mock() for module mocking, vi.fn() for function stubs"
8761
+ ],
8762
+ pitfalls: [
8763
+ "vi.mock() is hoisted to top of file \u2014 cannot access variables from outer scope"
8764
+ ]
8765
+ },
8766
+ "web-tree-sitter": {
8767
+ rules: [
8768
+ "Initialize Parser with await Parser.init() before use",
8769
+ "Load language WASM files with Parser.Language.load()"
8770
+ ],
8771
+ pitfalls: [
8772
+ "Parser.init() must complete before any parsing \u2014 race condition if not awaited",
8773
+ "WASM files must be bundled/copied to dist \u2014 not resolved from node_modules at runtime"
8774
+ ]
8775
+ },
8776
+ "@xenova/transformers": {
8777
+ rules: [
8778
+ "Use pipeline() for high-level tasks, AutoModel for custom inference",
8779
+ "Cache downloaded models by setting env.cacheDir"
8780
+ ],
8781
+ pitfalls: [
8782
+ "First model load downloads weights (~100MB+) \u2014 cache for subsequent runs",
8783
+ "ONNX runtime may fail on some architectures \u2014 test on target platform"
8784
+ ]
8785
+ },
8786
+ "chokidar": {
8787
+ rules: [
8788
+ "Use chokidar.watch() with ignored patterns to skip node_modules",
8789
+ 'Handle both "add" and "change" events for file watching'
8790
+ ],
8791
+ pitfalls: [
8792
+ "Not closing watcher on process exit leaks file handles",
8793
+ "Rapid file changes may fire multiple events \u2014 debounce handlers"
8794
+ ]
8795
+ },
8796
+ "react": {
8797
+ rules: [
8798
+ "Components must be pure \u2014 same props must produce same output",
8799
+ "Use useState for local UI state, useReducer for complex state logic",
8800
+ "Memoize expensive computations with useMemo, callbacks with useCallback"
8801
+ ],
8802
+ pitfalls: [
8803
+ "Missing key prop in lists causes React reconciliation bugs \u2014 always use stable keys",
8804
+ "useEffect with missing deps causes stale closures \u2014 lint rules catch most cases",
8805
+ "Setting state during render causes infinite re-render loop"
8806
+ ]
8807
+ },
8808
+ "react-router-dom": {
8809
+ rules: [
8810
+ "Use <Link> for navigation \u2014 never use <a href> for internal routes",
8811
+ "Use useNavigate() for programmatic navigation in event handlers"
8812
+ ],
8813
+ pitfalls: [
8814
+ "Routes must be nested under a <Router> provider \u2014 missing it causes runtime crash",
8815
+ "useSearchParams() returns URLSearchParams \u2014 .get() returns null not undefined"
8816
+ ]
8817
+ },
8818
+ "react-hook-form": {
8819
+ rules: [
8820
+ "Use register() for uncontrolled inputs, Controller for controlled (MUI, Radix)",
8821
+ "Define validation with zod resolver \u2014 avoid inline validate functions"
8822
+ ],
8823
+ pitfalls: [
8824
+ "Forgetting to call handleSubmit() wrapper \u2014 form submits without validation",
8825
+ "watch() causes re-render on every change \u2014 use getValues() for one-time reads"
8826
+ ]
8827
+ },
8828
+ "tailwindcss": {
8829
+ rules: [
8830
+ "Use Tailwind utility classes \u2014 avoid custom CSS unless absolutely necessary",
8831
+ "Use cn() or clsx() for conditional class merging"
8832
+ ],
8833
+ pitfalls: [
8834
+ "Dynamic class names like `bg-${color}-500` are purged \u2014 use full class names",
8835
+ "Order matters for conflicting utilities \u2014 last class wins"
8836
+ ]
8837
+ },
8838
+ "vite": {
8839
+ rules: [
8840
+ "Use import.meta.env for env variables \u2014 must be prefixed with VITE_",
8841
+ "Configure aliases in vite.config.ts resolve.alias"
8842
+ ],
8843
+ pitfalls: [
8844
+ "process.env is not available in Vite \u2014 use import.meta.env instead",
8845
+ "Environment variables without VITE_ prefix are not exposed to client code"
8846
+ ]
8847
+ },
8848
+ "next": {
8849
+ rules: [
8850
+ 'Use server components by default \u2014 add "use client" only when needed',
8851
+ "Data fetching in server components \u2014 no useEffect for initial data"
8852
+ ],
8853
+ pitfalls: [
8854
+ "Importing client-only code (useState, useEffect) in server components crashes build",
8855
+ "next/image requires explicit width/height or fill prop \u2014 missing causes error"
8856
+ ]
8857
+ },
8858
+ "framer-motion": {
8859
+ rules: [
8860
+ "Use motion.div (not regular div) for animated elements",
8861
+ "Define variants objects for reusable animation states"
8862
+ ],
8863
+ pitfalls: [
8864
+ "AnimatePresence requires direct children to have unique key props",
8865
+ "Exit animations only work when component is direct child of AnimatePresence"
8866
+ ]
8867
+ },
8868
+ "d3": {
8869
+ rules: [
8870
+ "Use D3 for data transforms/scales, React for DOM rendering \u2014 avoid d3.select in React",
8871
+ "Use useRef to get DOM reference for D3 direct DOM manipulation when needed"
8872
+ ],
8873
+ pitfalls: [
8874
+ "Mixing D3 DOM manipulation with React causes conflicts \u2014 pick one rendering strategy",
8875
+ "D3 scales are mutable \u2014 creating them in render without useMemo causes bugs"
8876
+ ]
8877
+ },
8878
+ "zustand": {
8879
+ rules: [
8880
+ "Create stores with create() \u2014 use selectors to prevent unnecessary re-renders",
8881
+ "Keep store state serializable \u2014 no functions or class instances in state"
8882
+ ],
8883
+ pitfalls: [
8884
+ "Not using selectors subscribes to entire store \u2014 causes excess re-renders",
8885
+ "Mutating state directly (state.x = y) does not trigger re-render \u2014 use set()"
8886
+ ]
8887
+ },
8888
+ "@tanstack/react-query": {
8889
+ rules: [
8890
+ "Use useQuery for GET, useMutation for POST/PUT/DELETE",
8891
+ "Set staleTime to avoid unnecessary refetches \u2014 default 0 refetches every mount"
8892
+ ],
8893
+ pitfalls: [
8894
+ "Forgetting queryClient.invalidateQueries after mutation shows stale data",
8895
+ "Query keys must be serializable arrays \u2014 objects in keys cause cache misses"
8896
+ ]
8897
+ }
8898
+ };
8899
+ FEATURE_NAME_RULES = {
8900
+ server: [
8901
+ "All tool/resource handlers must validate inputs before processing",
8902
+ "Return structured error responses \u2014 never throw raw errors to clients"
8903
+ ],
8904
+ storage: [
8905
+ "All database access should go through this module \u2014 no direct imports elsewhere",
8906
+ "Use transactions for multi-step operations to ensure consistency"
8907
+ ],
8908
+ indexing: [
8909
+ "Index operations should be idempotent \u2014 reindexing same file produces same result",
8910
+ "Handle parse errors gracefully \u2014 a broken file should not crash the indexer"
8911
+ ],
8912
+ core: [
8913
+ "Core modules should have no side effects on import",
8914
+ "Export types alongside functions for downstream consumers"
8915
+ ],
8916
+ test: [
8917
+ "Tests should be deterministic \u2014 no reliance on external services or timing",
8918
+ "Clean up temporary files and directories in afterEach/afterAll hooks"
8919
+ ],
8920
+ knowledge: [
8921
+ "Skill files must follow the agentskills.io SKILL.md format",
8922
+ "Generated content must use marker comments to preserve manual edits"
8923
+ ],
8924
+ doc: [
8925
+ "Generated docs must be kept in sync with source code changes",
8926
+ "Use relative paths for internal links"
8927
+ ],
8928
+ auth: [
8929
+ "Never store plain-text passwords \u2014 use bcrypt or argon2",
8930
+ "Validate and sanitize all user inputs before processing"
8931
+ ],
8932
+ api: [
8933
+ "All endpoints must validate request bodies/params before processing",
8934
+ "Return consistent error response shapes across all endpoints"
8935
+ ],
8936
+ components: [
8937
+ "Components should be pure \u2014 derive UI from props, avoid internal side effects",
8938
+ "Use composition over inheritance \u2014 prefer small, focused components",
8939
+ "Co-locate styles, types, and tests with the component file"
8940
+ ],
8941
+ pages: [
8942
+ "Pages handle routing and data fetching \u2014 delegate UI to components",
8943
+ "Keep page components thin \u2014 extract business logic to hooks or services"
8944
+ ],
8945
+ hooks: [
8946
+ 'Custom hooks must start with "use" prefix',
8947
+ "Keep hooks focused on one concern \u2014 avoid monolithic hooks",
8948
+ "Hooks should be reusable \u2014 avoid coupling to specific component internals"
8949
+ ],
8950
+ layouts: [
8951
+ "Layouts define page structure \u2014 children should not assume layout behavior",
8952
+ "Keep layouts thin \u2014 avoid business logic in layout wrappers"
8953
+ ],
8954
+ views: [
8955
+ "Views handle routing and data fetching \u2014 delegate UI to components",
8956
+ "Keep view components thin \u2014 extract business logic to hooks or services"
8957
+ ],
8958
+ services: [
8959
+ "Services handle API communication \u2014 keep HTTP details out of components",
8960
+ "Return typed responses \u2014 avoid returning raw API responses"
8961
+ ],
8962
+ stores: [
8963
+ "Keep store state minimal \u2014 derive computed values instead of storing them",
8964
+ "Actions should be thin \u2014 delegate complex logic to services"
8965
+ ],
8966
+ store: [
8967
+ "Keep store state minimal \u2014 derive computed values instead of storing them",
8968
+ "Actions should be thin \u2014 delegate complex logic to services"
8969
+ ],
8970
+ contexts: [
8971
+ "Context should hold only values that many components need \u2014 avoid overuse",
8972
+ "Split large contexts into focused providers to prevent unnecessary re-renders"
8973
+ ],
8974
+ providers: [
8975
+ "Provider order matters \u2014 auth before data fetching, theme before UI",
8976
+ "Keep providers thin \u2014 initialize services, do not embed business logic"
8977
+ ],
8978
+ routes: [
8979
+ "Route definitions should be declarative \u2014 avoid complex inline logic",
8980
+ "Use lazy loading for route components to optimize bundle size"
8981
+ ]
8982
+ };
8983
+ FEATURE_NAME_PITFALLS = {
8984
+ server: [
8985
+ "Unhandled promise rejections in handlers crash the process \u2014 always catch async errors",
8986
+ "Adding middleware order matters \u2014 auth before route handlers"
8987
+ ],
8988
+ storage: [
8989
+ "Forgetting to close database connections leaks file handles",
8990
+ "Concurrent writes without transactions may cause data corruption"
8991
+ ],
8992
+ indexing: [
8993
+ "Large files can cause out-of-memory \u2014 set size limits on parsed content",
8994
+ "File paths must be normalized (forward slashes) for cross-platform compatibility"
8995
+ ],
8996
+ core: [
8997
+ "Circular imports between core modules cause runtime errors \u2014 check dependency direction",
8998
+ "Changing public API signatures breaks downstream consumers"
8999
+ ],
9000
+ test: [
9001
+ "Tests sharing mutable state between runs cause flaky failures",
9002
+ "Temp directories not cleaned up fill disk over repeated test runs"
9003
+ ],
9004
+ components: [
9005
+ "Missing key prop in lists causes React reconciliation bugs \u2014 always use stable keys",
9006
+ "Direct DOM manipulation bypasses React \u2014 use refs only when necessary",
9007
+ "Prop drilling through 3+ levels signals need for context or composition"
9008
+ ],
9009
+ pages: [
9010
+ "Data fetching in render causes waterfall requests \u2014 use loaders or top-level hooks",
9011
+ "Missing error boundaries let one page crash the whole app"
9012
+ ],
9013
+ hooks: [
9014
+ "Missing deps in useEffect cause stale closures \u2014 React will warn but won't auto-fix",
9015
+ "Hooks called conditionally break React \u2014 hooks must be called in same order every render"
9016
+ ],
9017
+ services: [
9018
+ "Not handling API errors shows raw errors to users \u2014 always catch and transform",
9019
+ "Caching stale data causes UI inconsistency \u2014 invalidate cache on mutations"
9020
+ ],
9021
+ stores: [
9022
+ "Mutating state directly causes silent bugs \u2014 always return new references",
9023
+ "Large store updates trigger unnecessary re-renders \u2014 split into focused slices"
9024
+ ],
9025
+ store: [
9026
+ "Mutating state directly causes silent bugs \u2014 always return new references",
9027
+ "Large store updates trigger unnecessary re-renders \u2014 split into focused slices"
9028
+ ]
9029
+ };
9030
+ WELL_KNOWN_FEATURES = /* @__PURE__ */ new Set([
9031
+ "server",
9032
+ "storage",
9033
+ "indexing",
9034
+ "core",
9035
+ "test",
9036
+ "knowledge",
9037
+ "doc",
9038
+ "auth",
9039
+ "api",
9040
+ "billing",
9041
+ "cli",
9042
+ "components",
9043
+ "pages",
9044
+ "hooks",
9045
+ "layouts",
9046
+ "views",
9047
+ "services",
9048
+ "stores",
9049
+ "store",
9050
+ "contexts",
9051
+ "providers",
9052
+ "routes"
9053
+ ]);
9054
+ DIR_PURPOSE_MAP = {
9055
+ // Backend
9056
+ core: "Core business logic and domain modules",
9057
+ server: "Server, transports, and request handling",
9058
+ storage: "Database access and persistence",
9059
+ indexing: "Code indexing and symbol extraction",
9060
+ api: "API routes and handlers",
9061
+ auth: "Authentication and authorization",
9062
+ billing: "Payment processing",
9063
+ test: "Tests and evaluation harness",
9064
+ tests: "Tests and evaluation harness",
9065
+ doc: "Documentation",
9066
+ knowledge: "AI knowledge system",
9067
+ cli: "Command-line interface",
9068
+ base: "Base configuration and fixtures",
9069
+ src: "Application source code",
9070
+ lib: "Shared utilities",
9071
+ // Frontend / React
9072
+ components: "Reusable UI components",
9073
+ pages: "Page-level route components",
9074
+ hooks: "Custom React hooks",
9075
+ layouts: "Page layout wrappers",
9076
+ views: "View components (page-level)",
9077
+ features: "Feature modules (co-located logic + UI)",
9078
+ services: "API client and service layer",
9079
+ stores: "State management (stores/slices)",
9080
+ store: "State management (stores/slices)",
9081
+ utils: "Utility functions and helpers",
9082
+ contexts: "React context providers",
9083
+ providers: "App-level providers and wrappers",
9084
+ routes: "Route definitions and navigation",
9085
+ assets: "Static assets (images, fonts, icons)",
9086
+ styles: "Global styles and theme configuration",
9087
+ types: "TypeScript type definitions",
9088
+ config: "App configuration",
9089
+ middleware: "Request/response middleware",
9090
+ models: "Data models and schemas",
9091
+ controllers: "Request handlers (MVC)",
9092
+ resolvers: "GraphQL resolvers",
9093
+ schemas: "Data schemas and validation",
9094
+ migrations: "Database migrations",
9095
+ // Go
9096
+ cmd: "CLI entry points and commands",
9097
+ pkg: "Reusable library packages",
9098
+ internal: "Private packages (unexported)",
9099
+ // Rust
9100
+ bin: "Binary entry points",
9101
+ benches: "Benchmarks",
9102
+ // Python
9103
+ templates: "Template files (HTML, Jinja2)",
9104
+ static: "Static files for web serving",
9105
+ management: "Management commands (Django)",
9106
+ // General
9107
+ scripts: "Build/deploy/automation scripts",
9108
+ tools: "Developer tools and utilities",
9109
+ docs: "Documentation",
9110
+ examples: "Example code and demos",
9111
+ fixtures: "Test fixtures and sample data",
9112
+ mocks: "Mock objects for testing",
9113
+ helpers: "Helper functions and utilities",
9114
+ adapters: "External service adapters",
9115
+ ports: "Port interfaces (hexagonal architecture)",
9116
+ domain: "Domain logic (DDD)",
9117
+ entities: "Domain entities",
9118
+ repositories: "Data access repositories",
9119
+ handlers: "Request/event handlers",
9120
+ events: "Event definitions and dispatchers",
9121
+ jobs: "Background jobs and workers",
9122
+ workers: "Background workers",
9123
+ queues: "Job queue definitions",
9124
+ cron: "Scheduled task definitions"
9125
+ };
9126
+ SCOPE_LABELS = {
9127
+ "@radix-ui": "Radix UI (shadcn/ui primitives)",
9128
+ "@tanstack": "TanStack (query/router/table)",
9129
+ "@trpc": "tRPC",
9130
+ "@nestjs": "NestJS",
9131
+ "@prisma": "Prisma",
9132
+ "@aws-sdk": "AWS SDK",
9133
+ "@google-cloud": "Google Cloud SDK",
9134
+ "@azure": "Azure SDK",
9135
+ "@mui": "Material UI",
9136
+ "@chakra-ui": "Chakra UI",
9137
+ "@headlessui": "Headless UI",
9138
+ "@mantine": "Mantine",
9139
+ "@emotion": "Emotion CSS",
9140
+ "@testing-library": "Testing Library",
9141
+ "@storybook": "Storybook",
9142
+ "@sentry": "Sentry",
9143
+ "@opentelemetry": "OpenTelemetry",
9144
+ "@supabase": "Supabase",
9145
+ "@firebase": "Firebase",
9146
+ "@stripe": "Stripe SDK"
9147
+ };
9148
+ DOC_SOURCE_REGISTRY = [
9149
+ {
9150
+ packageNames: ["express"],
9151
+ docsUrl: "https://expressjs.com/en/api.html",
9152
+ apiRefUrl: "https://expressjs.com/en/4x/api.html",
9153
+ changelogUrl: "https://github.com/expressjs/express/blob/master/History.md"
9154
+ },
9155
+ {
9156
+ packageNames: ["react", "react-dom"],
9157
+ docsUrl: "https://react.dev/reference/react",
9158
+ apiRefUrl: "https://react.dev/reference/react",
9159
+ changelogUrl: "https://github.com/facebook/react/blob/main/CHANGELOG.md"
9160
+ },
9161
+ {
9162
+ packageNames: ["next"],
9163
+ docsUrl: "https://nextjs.org/docs",
9164
+ apiRefUrl: "https://nextjs.org/docs/api-reference",
9165
+ changelogUrl: "https://github.com/vercel/next.js/releases"
9166
+ },
9167
+ {
9168
+ packageNames: ["typescript"],
9169
+ docsUrl: "https://www.typescriptlang.org/docs/",
9170
+ changelogUrl: "https://www.typescriptlang.org/docs/handbook/release-notes/overview.html"
9171
+ },
9172
+ {
9173
+ packageNames: ["vitest"],
9174
+ docsUrl: "https://vitest.dev/api/",
9175
+ apiRefUrl: "https://vitest.dev/api/",
9176
+ changelogUrl: "https://github.com/vitest-dev/vitest/releases"
9177
+ },
9178
+ {
9179
+ packageNames: ["jest"],
9180
+ docsUrl: "https://jestjs.io/docs/api",
9181
+ apiRefUrl: "https://jestjs.io/docs/expect"
9182
+ },
9183
+ {
9184
+ packageNames: ["prisma", "@prisma/client"],
9185
+ docsUrl: "https://www.prisma.io/docs",
9186
+ apiRefUrl: "https://www.prisma.io/docs/reference/api-reference",
9187
+ changelogUrl: "https://github.com/prisma/prisma/releases"
9188
+ },
9189
+ {
9190
+ packageNames: ["stripe"],
9191
+ docsUrl: "https://docs.stripe.com/api",
9192
+ changelogUrl: "https://docs.stripe.com/changelog"
9193
+ },
9194
+ {
9195
+ packageNames: ["@modelcontextprotocol/sdk"],
9196
+ docsUrl: "https://modelcontextprotocol.io/docs",
9197
+ apiRefUrl: "https://github.com/modelcontextprotocol/typescript-sdk"
9198
+ },
9199
+ {
9200
+ packageNames: ["better-sqlite3"],
9201
+ docsUrl: "https://github.com/WiseLibs/better-sqlite3/blob/master/docs/api.md",
9202
+ apiRefUrl: "https://github.com/WiseLibs/better-sqlite3/blob/master/docs/api.md"
9203
+ },
9204
+ {
9205
+ packageNames: ["zod"],
9206
+ docsUrl: "https://zod.dev/",
9207
+ apiRefUrl: "https://zod.dev/"
9208
+ },
9209
+ {
9210
+ packageNames: ["tailwindcss"],
9211
+ docsUrl: "https://tailwindcss.com/docs"
9212
+ },
9213
+ {
9214
+ packageNames: ["vite"],
9215
+ docsUrl: "https://vitejs.dev/guide/",
9216
+ apiRefUrl: "https://vitejs.dev/config/"
9217
+ },
9218
+ {
9219
+ packageNames: ["passport"],
9220
+ docsUrl: "https://www.passportjs.org/docs/"
9221
+ },
9222
+ {
9223
+ packageNames: ["jsonwebtoken"],
9224
+ docsUrl: "https://github.com/auth0/node-jsonwebtoken#readme"
9225
+ },
9226
+ {
9227
+ packageNames: ["axios"],
9228
+ docsUrl: "https://axios-http.com/docs/intro",
9229
+ apiRefUrl: "https://axios-http.com/docs/api_intro"
9230
+ },
9231
+ {
9232
+ packageNames: ["fastify"],
9233
+ docsUrl: "https://fastify.dev/docs/latest/",
9234
+ apiRefUrl: "https://fastify.dev/docs/latest/Reference/"
9235
+ },
9236
+ {
9237
+ packageNames: ["drizzle-orm"],
9238
+ docsUrl: "https://orm.drizzle.team/docs/overview"
9239
+ },
9240
+ {
9241
+ packageNames: ["trpc", "@trpc/server", "@trpc/client"],
9242
+ docsUrl: "https://trpc.io/docs"
9243
+ },
9244
+ {
9245
+ packageNames: ["hono"],
9246
+ docsUrl: "https://hono.dev/docs/",
9247
+ apiRefUrl: "https://hono.dev/docs/api/hono"
9248
+ }
9249
+ ];
9250
+ }
9251
+ });
9252
+
9253
+ // src/core/agents/universal-inference.ts
9254
+ import { existsSync as existsSync25, readFileSync as readFileSync20, readdirSync as readdirSync7 } from "fs";
8668
9255
  import { join as join25 } from "path";
9256
+ function inferTechRulesAndPitfalls(tech, researchDir) {
9257
+ const result = { rules: [], pitfalls: [] };
9258
+ if (researchDir) {
9259
+ const research = extractRulesFromResearch(tech, researchDir);
9260
+ result.rules.push(...research.rules);
9261
+ result.pitfalls.push(...research.pitfalls);
9262
+ }
9263
+ const hardcoded = TECH_KNOWLEDGE[tech.name];
9264
+ if (hardcoded) {
9265
+ for (const rule of hardcoded.rules) {
9266
+ if (!result.rules.includes(rule)) result.rules.push(rule);
9267
+ }
9268
+ for (const pitfall of hardcoded.pitfalls) {
9269
+ if (!result.pitfalls.includes(pitfall)) result.pitfalls.push(pitfall);
9270
+ }
9271
+ }
9272
+ if (result.rules.length === 0 || result.pitfalls.length === 0) {
9273
+ const category = classifyTechnology(tech);
9274
+ const categoryKnowledge = CATEGORY_RULES[category];
9275
+ if (categoryKnowledge) {
9276
+ if (result.rules.length === 0) result.rules.push(...categoryKnowledge.rules);
9277
+ if (result.pitfalls.length === 0) result.pitfalls.push(...categoryKnowledge.pitfalls);
9278
+ }
9279
+ }
9280
+ if (result.rules.length === 0) {
9281
+ result.rules.push(
9282
+ `Follow ${tech.name} documentation for API usage patterns`,
9283
+ "Pin dependency version to avoid unexpected breaking changes"
9284
+ );
9285
+ }
9286
+ if (result.pitfalls.length === 0) {
9287
+ result.pitfalls.push(
9288
+ `Check ${tech.name} changelog when upgrading for breaking changes`,
9289
+ "Ensure error handling covers all library-specific error types"
9290
+ );
9291
+ }
9292
+ return result;
9293
+ }
9294
+ function classifyFeature(feature, importGraph) {
9295
+ const name = feature.name.toLowerCase();
9296
+ if (/^(server|api|routes?|controllers?|handlers?|endpoints?)$/.test(name)) return "api-layer";
9297
+ if (/^(storage|db|database|models?|repositories|entities|migrations?)$/.test(name)) return "data-layer";
9298
+ if (/^(core|domain|business|logic|engine|services?)$/.test(name)) return "business-logic";
9299
+ if (/^(components?|ui|views?|pages?|layouts?|widgets?)$/.test(name)) return "ui-components";
9300
+ if (/^(stores?|state|contexts?|providers?|hooks?)$/.test(name)) return "state-management";
9301
+ if (/^(tests?|spec|__tests__|e2e|integration|fixtures?)$/.test(name)) return "testing";
9302
+ if (/^(cli|cmd|commands?)$/.test(name)) return "cli";
9303
+ if (/^(auth|authentication|authorization|security|identity)$/.test(name)) return "auth";
9304
+ if (/^(docs?|documentation|knowledge)$/.test(name)) return "documentation";
9305
+ if (/^(infra|infrastructure|deploy|ci|scripts?|tools?|config)$/.test(name)) return "infrastructure";
9306
+ if (/^(utils?|helpers?|lib|shared|common|pkg|internal)$/.test(name)) return "utility";
9307
+ if (feature.testFiles.length > 0 && feature.fileCount > 0) {
9308
+ if (feature.testFiles.length / feature.fileCount > 0.5) return "testing";
9309
+ }
9310
+ if (importGraph) {
9311
+ const featurePaths = new Set(feature.paths.map((p) => p.replace("/**", "")));
9312
+ let importedByOthers = 0;
9313
+ for (const [file2, imports] of importGraph) {
9314
+ if (featurePaths.has(file2)) continue;
9315
+ for (const imp of imports) {
9316
+ for (const fp of featurePaths) {
9317
+ if (imp.startsWith(fp)) importedByOthers++;
9318
+ }
9319
+ }
9320
+ }
9321
+ if (importedByOthers > 10) return "utility";
9322
+ }
9323
+ const techNames = feature.technologies.map((t) => t.toLowerCase());
9324
+ if (techNames.some((t) => /prisma|typeorm|sqlalchemy|diesel|gorm|sequelize|drizzle/.test(t))) return "data-layer";
9325
+ if (techNames.some((t) => /react|vue|svelte|angular|solid/.test(t))) return "ui-components";
9326
+ if (techNames.some((t) => /express|fastify|hono|flask|gin|actix|django|rails/.test(t))) return "api-layer";
9327
+ return "generic";
9328
+ }
9329
+ function inferDirectoryPurpose(dirName, context) {
9330
+ const lower = dirName.toLowerCase();
9331
+ const hardcoded = DIR_PURPOSE_MAP[lower];
9332
+ if (hardcoded) return hardcoded;
9333
+ if (/^(spec|__tests__|test_|_test)/.test(lower)) return "Tests and test helpers";
9334
+ if (/^(build|dist|out|target|bin)$/.test(lower)) return "Build output";
9335
+ if (/^(vendor|third[_-]?party|extern)/.test(lower)) return "Third-party vendored code";
9336
+ if (/^(proto|protobuf|grpc)/.test(lower)) return "Protocol buffer definitions";
9337
+ if (/^(gen|generated)/.test(lower)) return "Auto-generated code";
9338
+ if (/^(i18n|l10n|locale|translations?)/.test(lower)) return "Internationalization and localization";
9339
+ if (/^(plugin|extension|addon)s?$/.test(lower)) return "Plugin/extension modules";
9340
+ if (/^(seed|seeds|fixtures|testdata)$/.test(lower)) return "Seed data and test fixtures";
9341
+ if (/^(public|static|assets|resources|res)$/.test(lower)) return "Static assets and resources";
9342
+ if (/^(cache|tmp|temp)$/.test(lower)) return "Temporary/cache files";
9343
+ if (context) {
9344
+ if (context.dominantExtensions) {
9345
+ const exts = context.dominantExtensions;
9346
+ if (exts.some((e) => /\.(test|spec)\.(ts|js|py|go|rs)$/.test(e))) return "Tests and test helpers";
9347
+ if (exts.some((e) => /\.(css|scss|less|styl)$/.test(e))) return "Stylesheets";
9348
+ if (exts.some((e) => /\.(html|hbs|ejs|pug|jinja2?)$/.test(e))) return "Template files";
9349
+ if (exts.some((e) => /\.(proto)$/.test(e))) return "Protocol buffer definitions";
9350
+ }
9351
+ if (context.technologies) {
9352
+ if (context.technologies.some((t) => /react|vue|svelte|angular/.test(t))) return "UI components";
9353
+ if (context.technologies.some((t) => /express|fastify|flask|gin/.test(t))) return "Server handlers";
9354
+ }
9355
+ }
9356
+ return `${capitalize(dirName)} module`;
9357
+ }
9358
+ function inferDataFlowFromGraph(features, importGraph) {
9359
+ const names = features.map((f) => f.name);
9360
+ if (importGraph && importGraph.size > 0) {
9361
+ const flow = inferFlowFromTopology(features, importGraph);
9362
+ if (flow.length >= 2) return flow;
9363
+ }
9364
+ return inferFlowFromNames(names);
9365
+ }
9366
+ function inferFlowFromTopology(features, importGraph) {
9367
+ const featurePathMap = /* @__PURE__ */ new Map();
9368
+ for (const f of features) {
9369
+ for (const p of f.paths) {
9370
+ const clean = p.replace("/**", "");
9371
+ featurePathMap.set(clean, f.name);
9372
+ }
9373
+ }
9374
+ const edges = /* @__PURE__ */ new Map();
9375
+ for (const [file2, imports] of importGraph) {
9376
+ const sourceFeature = findFeatureForFile(file2, featurePathMap);
9377
+ if (!sourceFeature) continue;
9378
+ for (const imp of imports) {
9379
+ const targetFeature = findFeatureForFile(imp, featurePathMap);
9380
+ if (!targetFeature || targetFeature === sourceFeature) continue;
9381
+ if (!edges.has(sourceFeature)) edges.set(sourceFeature, /* @__PURE__ */ new Map());
9382
+ const edgeMap = edges.get(sourceFeature);
9383
+ edgeMap.set(targetFeature, (edgeMap.get(targetFeature) || 0) + 1);
9384
+ }
9385
+ }
9386
+ const inDegree = /* @__PURE__ */ new Map();
9387
+ const outDegree = /* @__PURE__ */ new Map();
9388
+ for (const f of features) {
9389
+ inDegree.set(f.name, 0);
9390
+ outDegree.set(f.name, 0);
9391
+ }
9392
+ for (const [source, targets] of edges) {
9393
+ for (const [target, weight] of targets) {
9394
+ inDegree.set(target, (inDegree.get(target) || 0) + weight);
9395
+ outDegree.set(source, (outDegree.get(source) || 0) + weight);
9396
+ }
9397
+ }
9398
+ const sorted = features.map((f) => ({
9399
+ name: f.name,
9400
+ score: (outDegree.get(f.name) || 0) - (inDegree.get(f.name) || 0)
9401
+ })).sort((a, b) => b.score - a.score).map((f) => capitalize(f.name));
9402
+ return sorted.slice(0, 6);
9403
+ }
9404
+ function findFeatureForFile(file2, featurePathMap) {
9405
+ for (const [path, feature] of featurePathMap) {
9406
+ if (file2.startsWith(path)) return feature;
9407
+ }
9408
+ return null;
9409
+ }
9410
+ function inferFlowFromNames(names) {
9411
+ const flow = [];
9412
+ const isFrontend = names.some((n) => /^(components?|pages?|views?|hooks?|widgets?)$/.test(n));
9413
+ if (isFrontend) {
9414
+ flow.push("User");
9415
+ if (names.some((n) => /^(pages?|views?)$/.test(n))) flow.push("Pages");
9416
+ if (names.some((n) => /^(components?|widgets?)$/.test(n))) flow.push("Components");
9417
+ if (names.some((n) => /^hooks?$/.test(n))) flow.push("Hooks");
9418
+ if (names.some((n) => /^services?$/.test(n))) flow.push("Services");
9419
+ if (names.some((n) => /^(stores?|state)$/.test(n))) flow.push("Store");
9420
+ return flow.length >= 2 ? flow : [];
9421
+ }
9422
+ if (names.some((n) => /^(server|api)$/.test(n))) flow.push("Request");
9423
+ if (names.includes("server")) flow.push("Server");
9424
+ if (names.includes("api")) flow.push("API");
9425
+ if (names.some((n) => /^(controllers?|handlers?)$/.test(n))) flow.push("Controllers");
9426
+ if (names.includes("core")) flow.push("Core");
9427
+ if (names.some((n) => /^services?$/.test(n))) flow.push("Services");
9428
+ if (names.some((n) => /^(storage|db|database)$/.test(n))) flow.push("Storage");
9429
+ if (names.some((n) => /^(indexing|search)$/.test(n))) flow.push("Indexer");
9430
+ if (names.some((n) => /^(cmd|cli)$/.test(n)) && flow.length === 0) {
9431
+ flow.push("CLI");
9432
+ if (names.includes("core")) flow.push("Core");
9433
+ if (names.some((n) => /^(pkg|lib)$/.test(n))) flow.push("Lib");
9434
+ }
9435
+ return flow.length >= 2 ? flow : [];
9436
+ }
9437
+ function inferScopeLabel(scope, memberCount, researchDir) {
9438
+ const hardcoded = SCOPE_LABELS[scope];
9439
+ if (hardcoded) return hardcoded;
9440
+ if (researchDir) {
9441
+ try {
9442
+ if (existsSync25(researchDir)) {
9443
+ const files = readdirSync7(researchDir);
9444
+ const scopeClean = scope.replace("@", "");
9445
+ const match = files.find((f) => f.startsWith(scopeClean));
9446
+ if (match) {
9447
+ const content = readFileSync20(join25(researchDir, match), "utf-8");
9448
+ const titleMatch = content.match(/^#\s+(.+?)(?:\s+—|\s+v)/m);
9449
+ if (titleMatch?.[1]) return titleMatch[1];
9450
+ }
9451
+ }
9452
+ } catch {
9453
+ }
9454
+ }
9455
+ return `${scope} (${memberCount} packages)`;
9456
+ }
9457
+ function inferDocSource(packageName, source) {
9458
+ for (const entry of DOC_SOURCE_REGISTRY) {
9459
+ if (entry.packageNames.includes(packageName)) return entry;
9460
+ }
9461
+ const ecosystem = detectEcosystem(packageName, source);
9462
+ switch (ecosystem) {
9463
+ case "npm":
9464
+ return {
9465
+ packageNames: [packageName],
9466
+ docsUrl: `https://www.npmjs.com/package/${packageName}`
9467
+ };
9468
+ case "go":
9469
+ return {
9470
+ packageNames: [packageName],
9471
+ docsUrl: `https://pkg.go.dev/${packageName}`
9472
+ };
9473
+ case "rust":
9474
+ return {
9475
+ packageNames: [packageName],
9476
+ docsUrl: `https://docs.rs/${packageName}`
9477
+ };
9478
+ case "python":
9479
+ return {
9480
+ packageNames: [packageName],
9481
+ docsUrl: `https://pypi.org/project/${packageName}`
9482
+ };
9483
+ case "ruby":
9484
+ return {
9485
+ packageNames: [packageName],
9486
+ docsUrl: `https://rubygems.org/gems/${packageName}`
9487
+ };
9488
+ case "java":
9489
+ return {
9490
+ packageNames: [packageName],
9491
+ docsUrl: `https://mvnrepository.com/artifact/${packageName}`
9492
+ };
9493
+ case "dotnet":
9494
+ return {
9495
+ packageNames: [packageName],
9496
+ docsUrl: `https://www.nuget.org/packages/${packageName}`
9497
+ };
9498
+ default:
9499
+ return null;
9500
+ }
9501
+ }
9502
+ function detectEcosystem(packageName, source) {
9503
+ if (source) {
9504
+ if (/package\.json|package-lock|yarn\.lock|pnpm-lock|bun\.lock/.test(source)) return "npm";
9505
+ if (/go\.mod|go\.sum/.test(source)) return "go";
9506
+ if (/Cargo\.toml|Cargo\.lock/.test(source)) return "rust";
9507
+ if (/requirements\.txt|setup\.py|pyproject\.toml|Pipfile|poetry\.lock/.test(source)) return "python";
9508
+ if (/Gemfile|\.gemspec/.test(source)) return "ruby";
9509
+ if (/pom\.xml|build\.gradle/.test(source)) return "java";
9510
+ if (/\.csproj|\.sln|nuget/.test(source)) return "dotnet";
9511
+ }
9512
+ if (packageName.startsWith("@") || /^[a-z][\w.-]*$/.test(packageName)) return "npm";
9513
+ if (packageName.includes("/") && !packageName.startsWith("@")) return "go";
9514
+ return "unknown";
9515
+ }
9516
+ function extractRulesFromResearch(tech, researchDir) {
9517
+ const result = { rules: [], pitfalls: [] };
9518
+ const safeName = tech.name.replace(/^@/, "").replace(/\//g, "__");
9519
+ const candidates = [
9520
+ join25(researchDir, `${safeName}@${tech.version}.md`),
9521
+ join25(researchDir, `${tech.name}@${tech.version}.md`)
9522
+ ];
9523
+ let content = null;
9524
+ for (const candidate of candidates) {
9525
+ if (existsSync25(candidate)) {
9526
+ try {
9527
+ content = readFileSync20(candidate, "utf-8");
9528
+ break;
9529
+ } catch {
9530
+ }
9531
+ }
9532
+ }
9533
+ if (!content) {
9534
+ try {
9535
+ if (existsSync25(researchDir)) {
9536
+ const files = readdirSync7(researchDir);
9537
+ const match = files.find((f) => f.startsWith(`${safeName}@`));
9538
+ if (match) {
9539
+ content = readFileSync20(join25(researchDir, match), "utf-8");
9540
+ }
9541
+ }
9542
+ } catch {
9543
+ }
9544
+ }
9545
+ if (!content) return result;
9546
+ const trustMatch = content.match(/trust_score:\s*([\d.]+)/);
9547
+ if (trustMatch) {
9548
+ const trustScore = parseFloat(trustMatch[1]);
9549
+ if (trustScore < 0.5) return result;
9550
+ }
9551
+ const apiRules = extractBulletPoints(content, "Key API Patterns");
9552
+ result.rules.push(...apiRules.slice(0, 5));
9553
+ const pitfalls = extractBulletPoints(content, "Common Pitfalls");
9554
+ result.pitfalls.push(...pitfalls.slice(0, 5));
9555
+ const breakingChanges = extractBulletPoints(content, "Breaking Changes");
9556
+ result.pitfalls.push(...breakingChanges.slice(0, 3));
9557
+ return result;
9558
+ }
9559
+ function extractBulletPoints(content, sectionName) {
9560
+ const lines = content.split("\n");
9561
+ const points = [];
9562
+ let inSection = false;
9563
+ for (const line of lines) {
9564
+ if (line.match(new RegExp(`^##\\s+.*${escapeRegex2(sectionName)}`, "i"))) {
9565
+ inSection = true;
9566
+ continue;
9567
+ }
9568
+ if (inSection && line.match(/^##\s/)) {
9569
+ break;
9570
+ }
9571
+ if (inSection) {
9572
+ const bulletMatch = line.match(/^[-*]\s+(.+)/);
9573
+ if (bulletMatch?.[1]) {
9574
+ const text = bulletMatch[1].trim();
9575
+ if (text.length > 10 && text.length < 200) {
9576
+ points.push(text);
9577
+ }
9578
+ }
9579
+ }
9580
+ }
9581
+ return points;
9582
+ }
9583
+ function escapeRegex2(str) {
9584
+ return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
9585
+ }
9586
+ function classifyTechnology(tech) {
9587
+ const name = tech.name.toLowerCase();
9588
+ if (/^(express|fastify|hono|koa|flask|gin|actix|django|rails|spring|laravel|fiber|echo|chi|rocket|axum|phoenix|sinatra|bottle)$/.test(name)) return "web-framework";
9589
+ if (/^(react|vue|svelte|angular|solid|preact|lit|qwik|next|nuxt|gatsby|remix|astro|sveltekit)$/.test(name)) return "ui-framework";
9590
+ if (/prisma|typeorm|sqlalchemy|diesel|gorm|sequelize|mongoose|drizzle|knex|bookshelf|objection|mikro-orm|ecto/.test(name)) return "orm";
9591
+ if (/vitest|jest|pytest|mocha|jasmine|chai|supertest|testing-library|playwright|cypress|selenium/.test(name)) return "testing";
9592
+ if (/passport|jsonwebtoken|jwt|oauth|bcrypt|argon2|lucia|next-auth|auth0|clerk|supertokens/.test(name)) return "auth";
9593
+ if (/stripe|paypal|braintree|square|adyen|mollie/.test(name)) return "payment";
9594
+ if (/vite|webpack|esbuild|rollup|parcel|turbopack|swc|babel|tsc/.test(name)) return "build-tool";
9595
+ if (/zustand|redux|mobx|jotai|recoil|pinia|vuex|xstate|ngrx/.test(name)) return "state-management";
9596
+ if (/tailwind|styled-components|emotion|css-modules|sass|less|postcss|bootstrap|bulma/.test(name)) return "css-framework";
9597
+ if (/^(zod|yup|joi|ajv|superstruct|io-ts|valibot|typebox)$/.test(name)) return "validation";
9598
+ if (/^(axios|got|ky|node-fetch|undici|superagent|request)$/.test(name)) return "api-client";
9599
+ if (/better-sqlite3|pg|mysql2|redis|ioredis|mongodb|mariadb|sqlite3|tedious/.test(name)) return "database-driver";
9600
+ if (/winston|pino|bunyan|log4js|morgan|loglevel|consola/.test(name)) return "logging";
9601
+ return "general";
9602
+ }
9603
+ function deriveFeatureRules(feature, technologies, researchDir) {
9604
+ const rules = [];
9605
+ if (WELL_KNOWN_FEATURES.has(feature.name)) {
9606
+ const nameRules = FEATURE_NAME_RULES[feature.name];
9607
+ if (nameRules) rules.push(...nameRules);
9608
+ const techRules = [];
9609
+ for (const tech of technologies) {
9610
+ const inferred = inferTechRulesAndPitfalls(tech, researchDir);
9611
+ techRules.push(...inferred.rules);
9612
+ }
9613
+ for (const tr of techRules.slice(0, 2)) {
9614
+ if (!rules.some((r) => r.includes(tr.split(" ")[0] || ""))) {
9615
+ rules.push(tr);
9616
+ }
9617
+ }
9618
+ } else {
9619
+ for (const tech of technologies) {
9620
+ const inferred = inferTechRulesAndPitfalls(tech, researchDir);
9621
+ rules.push(...inferred.rules);
9622
+ }
9623
+ if (rules.length === 0) {
9624
+ const category = classifyFeature(feature);
9625
+ const categoryRules = FEATURE_CATEGORY_RULES[category];
9626
+ if (categoryRules) {
9627
+ rules.push(...categoryRules);
9628
+ } else {
9629
+ const nameRules = FEATURE_NAME_RULES[feature.name];
9630
+ rules.push(...nameRules || [
9631
+ "Follow existing patterns in this module for consistency",
9632
+ "Export public API from index file \u2014 keep internal helpers unexported"
9633
+ ]);
9634
+ }
9635
+ }
9636
+ }
9637
+ if (feature.paths.length > 0) {
9638
+ const scope = feature.paths[0]?.replace("/**", "") || "";
9639
+ rules.push(`Changes here should not import from other feature directories \u2014 keep ${scope} self-contained`);
9640
+ }
9641
+ return rules;
9642
+ }
9643
+ function deriveFeaturePitfalls(feature, technologies, researchDir) {
9644
+ const pitfalls = [];
9645
+ if (WELL_KNOWN_FEATURES.has(feature.name)) {
9646
+ const namePitfalls = FEATURE_NAME_PITFALLS[feature.name];
9647
+ if (namePitfalls) pitfalls.push(...namePitfalls);
9648
+ for (const tech of technologies) {
9649
+ const inferred = inferTechRulesAndPitfalls(tech, researchDir);
9650
+ for (const p of inferred.pitfalls.slice(0, 1)) {
9651
+ if (!pitfalls.includes(p)) pitfalls.push(p);
9652
+ }
9653
+ }
9654
+ } else {
9655
+ for (const tech of technologies) {
9656
+ const inferred = inferTechRulesAndPitfalls(tech, researchDir);
9657
+ pitfalls.push(...inferred.pitfalls);
9658
+ }
9659
+ if (pitfalls.length === 0) {
9660
+ const namePitfalls = FEATURE_NAME_PITFALLS[feature.name];
9661
+ if (namePitfalls) {
9662
+ pitfalls.push(...namePitfalls);
9663
+ } else {
9664
+ const category = classifyFeature(feature);
9665
+ const categoryPitfalls = FEATURE_CATEGORY_PITFALLS[category];
9666
+ if (categoryPitfalls) {
9667
+ pitfalls.push(...categoryPitfalls);
9668
+ } else {
9669
+ pitfalls.push(
9670
+ "Check for null/undefined before property access on external data",
9671
+ "Changing exports may break other modules that depend on this feature"
9672
+ );
9673
+ }
9674
+ }
9675
+ }
9676
+ }
9677
+ return pitfalls;
9678
+ }
9679
+ function capitalize(str) {
9680
+ return str.charAt(0).toUpperCase() + str.slice(1).replace(/-/g, " ");
9681
+ }
9682
+ var CATEGORY_RULES, FEATURE_CATEGORY_RULES, FEATURE_CATEGORY_PITFALLS;
9683
+ var init_universal_inference = __esm({
9684
+ "src/core/agents/universal-inference.ts"() {
9685
+ "use strict";
9686
+ init_hardcoded_knowledge();
9687
+ CATEGORY_RULES = {
9688
+ "web-framework": {
9689
+ rules: [
9690
+ "Validate all user inputs at the boundary \u2014 never trust request data",
9691
+ "Use middleware for cross-cutting concerns (auth, logging, CORS)",
9692
+ "Return consistent error response shapes across all endpoints"
9693
+ ],
9694
+ pitfalls: [
9695
+ "Unhandled async errors crash the server \u2014 always use error middleware",
9696
+ "Missing input validation leads to injection vulnerabilities"
9697
+ ]
9698
+ },
9699
+ "ui-framework": {
9700
+ rules: [
9701
+ "Components should be pure \u2014 same props must produce same output",
9702
+ "Use composition over inheritance \u2014 prefer small, focused components",
9703
+ "Keep components focused on one responsibility"
9704
+ ],
9705
+ pitfalls: [
9706
+ "Mutating state directly causes rendering bugs \u2014 always create new references",
9707
+ "Missing key props in lists causes reconciliation bugs"
9708
+ ]
9709
+ },
9710
+ "orm": {
9711
+ rules: [
9712
+ "Use migrations for all schema changes \u2014 never modify production DB directly",
9713
+ "Use transactions for multi-table operations",
9714
+ "Select only needed fields to avoid over-fetching"
9715
+ ],
9716
+ pitfalls: [
9717
+ "N+1 query problem \u2014 use eager loading or batch queries for relations",
9718
+ "Forgetting to run migrations after schema changes causes runtime errors"
9719
+ ]
9720
+ },
9721
+ "testing": {
9722
+ rules: [
9723
+ "Tests should be deterministic \u2014 no reliance on external services or timing",
9724
+ "Clean up test state between runs to prevent flaky failures",
9725
+ "Use descriptive test names that explain the expected behavior"
9726
+ ],
9727
+ pitfalls: [
9728
+ "Shared mutable state between tests causes flaky failures",
9729
+ "Mocking too much makes tests pass but misses real integration bugs"
9730
+ ]
9731
+ },
9732
+ "auth": {
9733
+ rules: [
9734
+ "Never store plain-text passwords \u2014 use bcrypt or argon2",
9735
+ "Set explicit token expiration \u2014 never issue non-expiring tokens",
9736
+ "Validate tokens on every request \u2014 never trust client-side auth state"
9737
+ ],
9738
+ pitfalls: [
9739
+ "Using weak algorithms (MD5, SHA1) for password hashing is a security vulnerability",
9740
+ "Not revoking tokens on logout allows session reuse"
9741
+ ]
9742
+ },
9743
+ "payment": {
9744
+ rules: [
9745
+ "Always verify webhook signatures before processing payment events",
9746
+ "Use idempotency keys for payment operations to prevent double-charges",
9747
+ "Log all payment events for audit trails"
9748
+ ],
9749
+ pitfalls: [
9750
+ "Webhook events may arrive out of order \u2014 handle idempotently",
9751
+ "Not handling declined payments gracefully shows raw errors to users"
9752
+ ]
9753
+ },
9754
+ "build-tool": {
9755
+ rules: [
9756
+ "Configure source maps for debugging in development",
9757
+ "Set up separate dev/prod build configurations"
9758
+ ],
9759
+ pitfalls: [
9760
+ "Large bundle sizes slow page load \u2014 use code splitting and tree shaking",
9761
+ "Misconfigured output paths overwrite source files"
9762
+ ]
9763
+ },
9764
+ "state-management": {
9765
+ rules: [
9766
+ "Keep store state minimal \u2014 derive computed values instead of storing them",
9767
+ "Use selectors to prevent unnecessary re-renders",
9768
+ "Keep store state serializable for debugging and persistence"
9769
+ ],
9770
+ pitfalls: [
9771
+ "Mutating state directly causes silent bugs \u2014 always use the update API",
9772
+ "Subscribing to entire store causes excessive re-renders"
9773
+ ]
9774
+ },
9775
+ "css-framework": {
9776
+ rules: [
9777
+ "Follow the framework's utility-first or component-based approach consistently",
9778
+ "Use conditional class merging utilities for dynamic styles"
9779
+ ],
9780
+ pitfalls: [
9781
+ "Dynamic class names may be purged in production \u2014 use full static class names",
9782
+ "Overriding framework styles with !important leads to unmaintainable CSS"
9783
+ ]
9784
+ },
9785
+ "validation": {
9786
+ rules: [
9787
+ "Define schemas once \u2014 derive types from schemas to keep them in sync",
9788
+ "Validate at system boundaries \u2014 user input, API responses, config files"
9789
+ ],
9790
+ pitfalls: [
9791
+ "Throwing on validation failure crashes the app \u2014 use safe parse methods in handlers",
9792
+ "Missing optional field validation causes runtime errors on undefined access"
9793
+ ]
9794
+ },
9795
+ "api-client": {
9796
+ rules: [
9797
+ "Set request timeouts to prevent hanging on unresponsive servers",
9798
+ "Handle network errors and HTTP errors separately"
9799
+ ],
9800
+ pitfalls: [
9801
+ "Not handling network errors shows cryptic errors to users",
9802
+ "Forgetting to set Content-Type header causes request parsing failures"
9803
+ ]
9804
+ },
9805
+ "database-driver": {
9806
+ rules: [
9807
+ "Use parameterized queries \u2014 never concatenate user input into SQL",
9808
+ "Use connection pooling for concurrent requests",
9809
+ "Close connections properly to prevent resource leaks"
9810
+ ],
9811
+ pitfalls: [
9812
+ "SQL injection from string concatenation \u2014 always use parameterized queries",
9813
+ "Not closing connections leaks file handles or socket connections"
9814
+ ]
9815
+ },
9816
+ "logging": {
9817
+ rules: [
9818
+ "Use structured logging (JSON) for machine-parseable log output",
9819
+ "Set appropriate log levels \u2014 debug in dev, info/warn in production"
9820
+ ],
9821
+ pitfalls: [
9822
+ "Logging sensitive data (passwords, tokens) is a security risk",
9823
+ "Synchronous logging in hot paths impacts performance"
9824
+ ]
9825
+ },
9826
+ "general": {
9827
+ rules: [
9828
+ "Follow existing patterns in this module for consistency",
9829
+ "Pin dependency versions to avoid unexpected breaking changes"
9830
+ ],
9831
+ pitfalls: [
9832
+ "Check changelog when upgrading for breaking changes",
9833
+ "Ensure error handling covers library-specific error types"
9834
+ ]
9835
+ }
9836
+ };
9837
+ FEATURE_CATEGORY_RULES = {
9838
+ "api-layer": [
9839
+ "All endpoints must validate request bodies/params before processing",
9840
+ "Return consistent error response shapes across all endpoints"
9841
+ ],
9842
+ "data-layer": [
9843
+ "All database access should go through this module \u2014 no direct imports elsewhere",
9844
+ "Use transactions for multi-step operations to ensure consistency"
9845
+ ],
9846
+ "business-logic": [
9847
+ "Core modules should have no side effects on import",
9848
+ "Export types alongside functions for downstream consumers"
9849
+ ],
9850
+ "ui-components": [
9851
+ "Components should be pure \u2014 derive UI from props, avoid internal side effects",
9852
+ "Use composition over inheritance \u2014 prefer small, focused components"
9853
+ ],
9854
+ "state-management": [
9855
+ "Keep store state minimal \u2014 derive computed values instead of storing them",
9856
+ "Actions should be thin \u2014 delegate complex logic to services"
9857
+ ],
9858
+ "testing": [
9859
+ "Tests should be deterministic \u2014 no reliance on external services or timing",
9860
+ "Clean up temporary files and directories in teardown hooks"
9861
+ ],
9862
+ "cli": [
9863
+ "Validate all command-line arguments before processing",
9864
+ "Provide helpful error messages with usage hints on invalid input"
9865
+ ],
9866
+ "auth": [
9867
+ "Never store plain-text passwords \u2014 use bcrypt or argon2",
9868
+ "Validate and sanitize all user inputs before processing"
9869
+ ],
9870
+ "documentation": [
9871
+ "Generated docs must be kept in sync with source code changes",
9872
+ "Use relative paths for internal links"
9873
+ ],
9874
+ "infrastructure": [
9875
+ "Configuration should be environment-aware (dev/staging/prod)",
9876
+ "Scripts should be idempotent \u2014 safe to run multiple times"
9877
+ ],
9878
+ "utility": [
9879
+ "Utility functions should be pure \u2014 no side effects",
9880
+ "Export public API from index file \u2014 keep internal helpers unexported"
9881
+ ],
9882
+ "generic": [
9883
+ "Follow existing patterns in this module for consistency",
9884
+ "Export public API from index file \u2014 keep internal helpers unexported"
9885
+ ]
9886
+ };
9887
+ FEATURE_CATEGORY_PITFALLS = {
9888
+ "api-layer": [
9889
+ "Unhandled async errors crash the server \u2014 always catch errors in handlers",
9890
+ "Missing input validation leads to injection vulnerabilities"
9891
+ ],
9892
+ "data-layer": [
9893
+ "Forgetting to close connections leaks file handles",
9894
+ "Concurrent writes without transactions may cause data corruption"
9895
+ ],
9896
+ "business-logic": [
9897
+ "Circular imports between core modules cause runtime errors \u2014 check dependency direction",
9898
+ "Changing public API signatures breaks downstream consumers"
9899
+ ],
9900
+ "ui-components": [
9901
+ "Missing key prop in lists causes reconciliation bugs \u2014 always use stable keys",
9902
+ "Direct DOM manipulation bypasses the framework \u2014 use refs only when necessary"
9903
+ ],
9904
+ "state-management": [
9905
+ "Mutating state directly causes silent bugs \u2014 always return new references",
9906
+ "Large store updates trigger unnecessary re-renders \u2014 split into focused slices"
9907
+ ],
9908
+ "testing": [
9909
+ "Tests sharing mutable state between runs cause flaky failures",
9910
+ "Temp directories not cleaned up fill disk over repeated test runs"
9911
+ ],
9912
+ "cli": [
9913
+ "Missing error handling on subprocess execution causes silent failures",
9914
+ "Not quoting file paths breaks on paths with spaces"
9915
+ ],
9916
+ "auth": [
9917
+ "Using weak hashing algorithms is a security vulnerability",
9918
+ "Not revoking tokens on logout allows session reuse"
9919
+ ],
9920
+ "documentation": [
9921
+ "Stale documentation is worse than no documentation",
9922
+ "Broken internal links confuse users \u2014 validate links on changes"
9923
+ ],
9924
+ "infrastructure": [
9925
+ "Hardcoded secrets in config files are a security risk \u2014 use environment variables",
9926
+ "Non-idempotent scripts cause issues on re-run"
9927
+ ],
9928
+ "utility": [
9929
+ "Changing utility signatures breaks all callers \u2014 check usage before modifying",
9930
+ "Missing error handling in utilities propagates errors to all consumers"
9931
+ ],
9932
+ "generic": [
9933
+ "Check for null/undefined before property access on external data",
9934
+ "Changing exports may break other modules that depend on this feature"
9935
+ ]
9936
+ };
9937
+ }
9938
+ });
9939
+
9940
+ // src/core/agents/research-engine.ts
9941
+ import { existsSync as existsSync26, readFileSync as readFileSync21, writeFileSync as writeFileSync15, mkdirSync as mkdirSync15, readdirSync as readdirSync8 } from "fs";
9942
+ import { join as join26 } from "path";
8669
9943
  async function researchTechnology(projectPath, tech, options) {
8670
9944
  const paths = getAgentWorkspacePaths(projectPath);
8671
9945
  const safeName = tech.name.replace(/^@/, "").replace(/\//g, "__");
8672
9946
  const fileName = `${safeName}@${tech.version}.md`;
8673
- const filePath = join25(paths.researchDir, fileName);
9947
+ const filePath = join26(paths.researchDir, fileName);
8674
9948
  const relPath = `research/${fileName}`;
8675
- if (!options.force && existsSync25(filePath)) {
9949
+ if (!options.force && existsSync26(filePath)) {
8676
9950
  const existing = readResearchFile(filePath);
8677
9951
  if (existing && !isStale(existing, options.cadenceHours)) {
8678
9952
  return { technology: tech.name, version: tech.version, file: relPath, status: "cached" };
8679
9953
  }
8680
9954
  }
8681
- const docSource = findDocSource(tech.name);
9955
+ const docSource = inferDocSource(tech.name, tech.source);
8682
9956
  if (!docSource) {
8683
9957
  const stub = generateStubResearch(tech);
8684
9958
  mkdirSync15(paths.researchDir, { recursive: true });
@@ -8688,10 +9962,10 @@ async function researchTechnology(projectPath, tech, options) {
8688
9962
  try {
8689
9963
  const fetchFn = options.fetchFn || defaultFetch;
8690
9964
  const content = await fetchAndDistill(tech, docSource, fetchFn, options.maxTokensPerTech);
9965
+ const isNew = !existsSync26(filePath);
8691
9966
  mkdirSync15(paths.researchDir, { recursive: true });
8692
9967
  writeFileSync15(filePath, content);
8693
9968
  const tokenCount = estimateTokens4(content);
8694
- const isNew = !existsSync25(filePath);
8695
9969
  return {
8696
9970
  technology: tech.name,
8697
9971
  version: tech.version,
@@ -8700,7 +9974,7 @@ async function researchTechnology(projectPath, tech, options) {
8700
9974
  tokenCount
8701
9975
  };
8702
9976
  } catch (err) {
8703
- if (!existsSync25(filePath)) {
9977
+ if (!existsSync26(filePath)) {
8704
9978
  const stub = generateStubResearch(tech);
8705
9979
  mkdirSync15(paths.researchDir, { recursive: true });
8706
9980
  writeFileSync15(filePath, stub);
@@ -8722,14 +9996,6 @@ async function researchAllTechnologies(projectPath, technologies, options) {
8722
9996
  }
8723
9997
  return results;
8724
9998
  }
8725
- function findDocSource(packageName) {
8726
- for (const source of DOC_SOURCE_REGISTRY) {
8727
- if (source.packageNames.includes(packageName)) {
8728
- return source;
8729
- }
8730
- }
8731
- return null;
8732
- }
8733
9999
  async function fetchAndDistill(tech, docSource, fetchFn, maxTokens) {
8734
10000
  const urls = [docSource.docsUrl];
8735
10001
  if (docSource.apiRefUrl && docSource.apiRefUrl !== docSource.docsUrl) {
@@ -8895,7 +10161,7 @@ function generateStubResearch(tech) {
8895
10161
  }
8896
10162
  function readResearchFile(filePath) {
8897
10163
  try {
8898
- const content = readFileSync20(filePath, "utf-8");
10164
+ const content = readFileSync21(filePath, "utf-8");
8899
10165
  const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---/);
8900
10166
  if (!frontmatterMatch) return null;
8901
10167
  const fm = frontmatterMatch[1] || "";
@@ -8920,16 +10186,16 @@ function readResearchFile(filePath) {
8920
10186
  function getResearchContent(projectPath, technology, version2) {
8921
10187
  const paths = getAgentWorkspacePaths(projectPath);
8922
10188
  if (version2) {
8923
- const exactPath = join25(paths.researchDir, `${technology}@${version2}.md`);
8924
- if (existsSync25(exactPath)) {
8925
- return readFileSync20(exactPath, "utf-8");
10189
+ const exactPath = join26(paths.researchDir, `${technology}@${version2}.md`);
10190
+ if (existsSync26(exactPath)) {
10191
+ return readFileSync21(exactPath, "utf-8");
8926
10192
  }
8927
10193
  }
8928
- if (existsSync25(paths.researchDir)) {
8929
- const files = readdirSync7(paths.researchDir);
10194
+ if (existsSync26(paths.researchDir)) {
10195
+ const files = readdirSync8(paths.researchDir);
8930
10196
  const match = files.find((f) => f.startsWith(`${technology}@`));
8931
10197
  if (match) {
8932
- return readFileSync20(join25(paths.researchDir, match), "utf-8");
10198
+ return readFileSync21(join26(paths.researchDir, match), "utf-8");
8933
10199
  }
8934
10200
  }
8935
10201
  return null;
@@ -8992,114 +10258,12 @@ function htmlToMarkdown(html) {
8992
10258
  text = text.trim();
8993
10259
  return text;
8994
10260
  }
8995
- var DOC_SOURCE_REGISTRY;
8996
10261
  var init_research_engine = __esm({
8997
10262
  "src/core/agents/research-engine.ts"() {
8998
10263
  "use strict";
8999
10264
  init_workspace2();
9000
10265
  init_research_trust();
9001
- DOC_SOURCE_REGISTRY = [
9002
- {
9003
- packageNames: ["express"],
9004
- docsUrl: "https://expressjs.com/en/api.html",
9005
- apiRefUrl: "https://expressjs.com/en/4x/api.html",
9006
- changelogUrl: "https://github.com/expressjs/express/blob/master/History.md"
9007
- },
9008
- {
9009
- packageNames: ["react", "react-dom"],
9010
- docsUrl: "https://react.dev/reference/react",
9011
- apiRefUrl: "https://react.dev/reference/react",
9012
- changelogUrl: "https://github.com/facebook/react/blob/main/CHANGELOG.md"
9013
- },
9014
- {
9015
- packageNames: ["next"],
9016
- docsUrl: "https://nextjs.org/docs",
9017
- apiRefUrl: "https://nextjs.org/docs/api-reference",
9018
- changelogUrl: "https://github.com/vercel/next.js/releases"
9019
- },
9020
- {
9021
- packageNames: ["typescript"],
9022
- docsUrl: "https://www.typescriptlang.org/docs/",
9023
- changelogUrl: "https://www.typescriptlang.org/docs/handbook/release-notes/overview.html"
9024
- },
9025
- {
9026
- packageNames: ["vitest"],
9027
- docsUrl: "https://vitest.dev/api/",
9028
- apiRefUrl: "https://vitest.dev/api/",
9029
- changelogUrl: "https://github.com/vitest-dev/vitest/releases"
9030
- },
9031
- {
9032
- packageNames: ["jest"],
9033
- docsUrl: "https://jestjs.io/docs/api",
9034
- apiRefUrl: "https://jestjs.io/docs/expect"
9035
- },
9036
- {
9037
- packageNames: ["prisma", "@prisma/client"],
9038
- docsUrl: "https://www.prisma.io/docs",
9039
- apiRefUrl: "https://www.prisma.io/docs/reference/api-reference",
9040
- changelogUrl: "https://github.com/prisma/prisma/releases"
9041
- },
9042
- {
9043
- packageNames: ["stripe"],
9044
- docsUrl: "https://docs.stripe.com/api",
9045
- changelogUrl: "https://docs.stripe.com/changelog"
9046
- },
9047
- {
9048
- packageNames: ["@modelcontextprotocol/sdk"],
9049
- docsUrl: "https://modelcontextprotocol.io/docs",
9050
- apiRefUrl: "https://github.com/modelcontextprotocol/typescript-sdk"
9051
- },
9052
- {
9053
- packageNames: ["better-sqlite3"],
9054
- docsUrl: "https://github.com/WiseLibs/better-sqlite3/blob/master/docs/api.md",
9055
- apiRefUrl: "https://github.com/WiseLibs/better-sqlite3/blob/master/docs/api.md"
9056
- },
9057
- {
9058
- packageNames: ["zod"],
9059
- docsUrl: "https://zod.dev/",
9060
- apiRefUrl: "https://zod.dev/"
9061
- },
9062
- {
9063
- packageNames: ["tailwindcss"],
9064
- docsUrl: "https://tailwindcss.com/docs"
9065
- },
9066
- {
9067
- packageNames: ["vite"],
9068
- docsUrl: "https://vitejs.dev/guide/",
9069
- apiRefUrl: "https://vitejs.dev/config/"
9070
- },
9071
- {
9072
- packageNames: ["passport"],
9073
- docsUrl: "https://www.passportjs.org/docs/"
9074
- },
9075
- {
9076
- packageNames: ["jsonwebtoken"],
9077
- docsUrl: "https://github.com/auth0/node-jsonwebtoken#readme"
9078
- },
9079
- {
9080
- packageNames: ["axios"],
9081
- docsUrl: "https://axios-http.com/docs/intro",
9082
- apiRefUrl: "https://axios-http.com/docs/api_intro"
9083
- },
9084
- {
9085
- packageNames: ["fastify"],
9086
- docsUrl: "https://fastify.dev/docs/latest/",
9087
- apiRefUrl: "https://fastify.dev/docs/latest/Reference/"
9088
- },
9089
- {
9090
- packageNames: ["drizzle-orm"],
9091
- docsUrl: "https://orm.drizzle.team/docs/overview"
9092
- },
9093
- {
9094
- packageNames: ["trpc", "@trpc/server", "@trpc/client"],
9095
- docsUrl: "https://trpc.io/docs"
9096
- },
9097
- {
9098
- packageNames: ["hono"],
9099
- docsUrl: "https://hono.dev/docs/",
9100
- apiRefUrl: "https://hono.dev/docs/api/hono"
9101
- }
9102
- ];
10266
+ init_universal_inference();
9103
10267
  }
9104
10268
  });
9105
10269
 
@@ -9431,8 +10595,8 @@ var init_diagnosis_table = __esm({
9431
10595
  });
9432
10596
 
9433
10597
  // src/core/agents/improvement-engine.ts
9434
- import { existsSync as existsSync26, readFileSync as readFileSync21, writeFileSync as writeFileSync16, readdirSync as readdirSync8 } from "fs";
9435
- import { join as join26 } from "path";
10598
+ import { existsSync as existsSync27, readFileSync as readFileSync22, writeFileSync as writeFileSync16, readdirSync as readdirSync9 } from "fs";
10599
+ import { join as join27 } from "path";
9436
10600
  function learnFromOutcome(db, projectPath, outcome) {
9437
10601
  if (outcome.result === "success") {
9438
10602
  confirmRelatedLessons(projectPath, outcome);
@@ -9602,7 +10766,7 @@ function promoteLessons(db, projectPath) {
9602
10766
  const agentFiles = findAgentFiles(paths);
9603
10767
  const skillFiles = findSkillFiles(paths);
9604
10768
  for (const filePath of agentFiles) {
9605
- const content = readFileSync21(filePath, "utf-8");
10769
+ const content = readFileSync22(filePath, "utf-8");
9606
10770
  if (!content.includes("## Lessons Learned")) continue;
9607
10771
  const lessonsMatch = content.match(/## Lessons Learned\n([\s\S]*?)(?=\n##|\n<!-- |$)/);
9608
10772
  if (!lessonsMatch || !lessonsMatch[1]) continue;
@@ -9614,8 +10778,8 @@ function promoteLessons(db, projectPath) {
9614
10778
  const confirmations = countConfirmations(db, fingerprint);
9615
10779
  if (confirmations >= 3) {
9616
10780
  const featureName = extractFeatureFromPath(filePath);
9617
- const skillPath = featureName ? join26(paths.featuresDir, featureName, "SKILL.md") : join26(paths.projectDir, "SKILL.md");
9618
- if (existsSync26(skillPath)) {
10781
+ const skillPath = featureName ? join27(paths.featuresDir, featureName, "SKILL.md") : join27(paths.projectDir, "SKILL.md");
10782
+ if (existsSync27(skillPath)) {
9619
10783
  const ruleAdded = addRuleToSkill(skillPath, lessonContent, config2);
9620
10784
  if (ruleAdded) {
9621
10785
  const updatedContent = content.replace(lesson, `${lesson} [promoted]`);
@@ -9634,9 +10798,9 @@ function diagnoseFailure(failure, db, projectPath) {
9634
10798
  const isInScope = (filePath, agentName) => {
9635
10799
  const paths = getAgentWorkspacePaths(projectPath);
9636
10800
  const name = agentName.replace(/-agent$/, "");
9637
- const agentPath = join26(paths.featuresDir, name, "AGENT.md");
9638
- if (!existsSync26(agentPath)) return true;
9639
- const agentContent = readFileSync21(agentPath, "utf-8");
10801
+ const agentPath = join27(paths.featuresDir, name, "AGENT.md");
10802
+ if (!existsSync27(agentPath)) return true;
10803
+ const agentContent = readFileSync22(agentPath, "utf-8");
9640
10804
  return fileMatchesAgentScope(filePath, agentContent);
9641
10805
  };
9642
10806
  const ctx = {
@@ -9662,10 +10826,10 @@ function fileMatchesAgentScope(filePath, agentMdContent) {
9662
10826
  function patchSkillWithFix(projectPath, outcome, diagnosis, config2) {
9663
10827
  const paths = getAgentWorkspacePaths(projectPath);
9664
10828
  const agentName = outcome.agent.replace(/-agent$/, "");
9665
- const featureSkillPath = join26(paths.featuresDir, agentName, "SKILL.md");
9666
- const targetPath = existsSync26(featureSkillPath) ? featureSkillPath : join26(paths.projectDir, "SKILL.md");
9667
- if (!existsSync26(targetPath)) return null;
9668
- const content = readFileSync21(targetPath, "utf-8");
10829
+ const featureSkillPath = join27(paths.featuresDir, agentName, "SKILL.md");
10830
+ const targetPath = existsSync27(featureSkillPath) ? featureSkillPath : join27(paths.projectDir, "SKILL.md");
10831
+ if (!existsSync27(targetPath)) return null;
10832
+ const content = readFileSync22(targetPath, "utf-8");
9669
10833
  const pitfallEntry = `- ${diagnosis.description.slice(0, 150)} \u2192 Fix: ${outcome.fixApplied.slice(0, 100)}`;
9670
10834
  if (!content.includes(config2.markers.start)) return null;
9671
10835
  const startIdx = content.indexOf(config2.markers.start);
@@ -9708,9 +10872,9 @@ function identifyAffectedTechnologies(outcome, projectPath) {
9708
10872
  techs.push(pkg);
9709
10873
  }
9710
10874
  }
9711
- if (existsSync26(paths.researchDir)) {
10875
+ if (existsSync27(paths.researchDir)) {
9712
10876
  try {
9713
- const researchFiles = readdirSync8(paths.researchDir);
10877
+ const researchFiles = readdirSync9(paths.researchDir);
9714
10878
  for (const file2 of researchFiles) {
9715
10879
  const techName = file2.replace(/@.*\.md$/, "");
9716
10880
  if (outcome.errorMessage && outcome.errorMessage.toLowerCase().includes(techName.toLowerCase())) {
@@ -9733,9 +10897,9 @@ function confirmRelatedLessons(projectPath, outcome) {
9733
10897
  if (outcome.relatedSkills.length === 0) return;
9734
10898
  const paths = getAgentWorkspacePaths(projectPath);
9735
10899
  const agentName = outcome.agent.replace(/-agent$/, "");
9736
- const agentPath = join26(paths.featuresDir, agentName, "AGENT.md");
9737
- if (!existsSync26(agentPath)) return;
9738
- const content = readFileSync21(agentPath, "utf-8");
10900
+ const agentPath = join27(paths.featuresDir, agentName, "AGENT.md");
10901
+ if (!existsSync27(agentPath)) return;
10902
+ const content = readFileSync22(agentPath, "utf-8");
9739
10903
  const taskWords = outcome.task.toLowerCase().split(/\W+/).filter((w) => w.length > 3);
9740
10904
  let updated = content;
9741
10905
  let changed = false;
@@ -9763,28 +10927,28 @@ function writeLesson(projectPath, failure, diagnosis, config2) {
9763
10927
  return null;
9764
10928
  case "scope-error": {
9765
10929
  const agentName = failure.agent.replace(/-agent$/, "");
9766
- targetPath = join26(paths.featuresDir, agentName, "AGENT.md");
10930
+ targetPath = join27(paths.featuresDir, agentName, "AGENT.md");
9767
10931
  break;
9768
10932
  }
9769
10933
  case "wrong-assumption":
9770
10934
  case "missing-test": {
9771
10935
  const agentName = failure.agent.replace(/-agent$/, "");
9772
- const featurePath = join26(paths.featuresDir, agentName, "AGENT.md");
9773
- targetPath = existsSync26(featurePath) ? featurePath : join26(paths.projectDir, "AGENT.md");
10936
+ const featurePath = join27(paths.featuresDir, agentName, "AGENT.md");
10937
+ targetPath = existsSync27(featurePath) ? featurePath : join27(paths.projectDir, "AGENT.md");
9774
10938
  break;
9775
10939
  }
9776
10940
  case "missing-convention":
9777
- targetPath = join26(paths.projectDir, "AGENT.md");
10941
+ targetPath = join27(paths.projectDir, "AGENT.md");
9778
10942
  break;
9779
10943
  case "external-change":
9780
10944
  default:
9781
- targetPath = join26(paths.projectDir, "AGENT.md");
10945
+ targetPath = join27(paths.projectDir, "AGENT.md");
9782
10946
  break;
9783
10947
  }
9784
- if (!existsSync26(targetPath)) return null;
10948
+ if (!existsSync27(targetPath)) return null;
9785
10949
  const evidenceRef = failure.fixApplied ? ` Fix: ${failure.fixApplied.slice(0, 80)}` : "";
9786
10950
  const lessonText = `- ${today}: ${diagnosis.description.slice(0, 200)}${evidenceRef} (outcome: ${failure.id.slice(0, 8)})`;
9787
- const existing = readFileSync21(targetPath, "utf-8");
10951
+ const existing = readFileSync22(targetPath, "utf-8");
9788
10952
  const fingerprint = computeErrorFingerprint(diagnosis.description);
9789
10953
  if (existing.includes(fingerprint.slice(0, 30))) {
9790
10954
  return null;
@@ -9807,7 +10971,7 @@ function writeLesson(projectPath, failure, diagnosis, config2) {
9807
10971
  return targetPath;
9808
10972
  }
9809
10973
  function addRuleToSkill(skillPath, ruleContent, config2) {
9810
- const content = readFileSync21(skillPath, "utf-8");
10974
+ const content = readFileSync22(skillPath, "utf-8");
9811
10975
  if (!content.includes(config2.markers.start)) return false;
9812
10976
  const startIdx = content.indexOf(config2.markers.start);
9813
10977
  const endIdx = content.indexOf(config2.markers.end);
@@ -9885,7 +11049,7 @@ function decayOldLessons(projectPath, maxAgeDays = 90) {
9885
11049
  const cutoff = new Date(Date.now() - maxAgeDays * 24 * 60 * 60 * 1e3).toISOString().split("T")[0];
9886
11050
  const agentFiles = findAgentFiles(paths);
9887
11051
  for (const filePath of agentFiles) {
9888
- const content = readFileSync21(filePath, "utf-8");
11052
+ const content = readFileSync22(filePath, "utf-8");
9889
11053
  if (!content.includes(config2.markers.start)) continue;
9890
11054
  const updated = content.replace(
9891
11055
  /^(- \d{4}-\d{2}-\d{2}: .+?)(?<!\[unconfirmed\])(?<!\[confirmed\])(?<!\[promoted\])$/gm,
@@ -9906,14 +11070,14 @@ function decayOldLessons(projectPath, maxAgeDays = 90) {
9906
11070
  }
9907
11071
  function findAgentFiles(paths) {
9908
11072
  const files = [];
9909
- const superAgent = join26(paths.projectDir, "AGENT.md");
9910
- if (existsSync26(superAgent)) files.push(superAgent);
9911
- if (existsSync26(paths.featuresDir)) {
11073
+ const superAgent = join27(paths.projectDir, "AGENT.md");
11074
+ if (existsSync27(superAgent)) files.push(superAgent);
11075
+ if (existsSync27(paths.featuresDir)) {
9912
11076
  try {
9913
- const features = readdirSync8(paths.featuresDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
11077
+ const features = readdirSync9(paths.featuresDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
9914
11078
  for (const feature of features) {
9915
- const agentPath = join26(paths.featuresDir, feature, "AGENT.md");
9916
- if (existsSync26(agentPath)) files.push(agentPath);
11079
+ const agentPath = join27(paths.featuresDir, feature, "AGENT.md");
11080
+ if (existsSync27(agentPath)) files.push(agentPath);
9917
11081
  }
9918
11082
  } catch {
9919
11083
  }
@@ -9922,14 +11086,14 @@ function findAgentFiles(paths) {
9922
11086
  }
9923
11087
  function findSkillFiles(paths) {
9924
11088
  const files = [];
9925
- const projectSkill = join26(paths.projectDir, "SKILL.md");
9926
- if (existsSync26(projectSkill)) files.push(projectSkill);
9927
- if (existsSync26(paths.featuresDir)) {
11089
+ const projectSkill = join27(paths.projectDir, "SKILL.md");
11090
+ if (existsSync27(projectSkill)) files.push(projectSkill);
11091
+ if (existsSync27(paths.featuresDir)) {
9928
11092
  try {
9929
- const features = readdirSync8(paths.featuresDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
11093
+ const features = readdirSync9(paths.featuresDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
9930
11094
  for (const feature of features) {
9931
- const skillPath = join26(paths.featuresDir, feature, "SKILL.md");
9932
- if (existsSync26(skillPath)) files.push(skillPath);
11095
+ const skillPath = join27(paths.featuresDir, feature, "SKILL.md");
11096
+ if (existsSync27(skillPath)) files.push(skillPath);
9933
11097
  }
9934
11098
  } catch {
9935
11099
  }
@@ -10082,8 +11246,8 @@ var init_telemetry = __esm({
10082
11246
  });
10083
11247
 
10084
11248
  // src/core/agents/tech-detector.ts
10085
- import { existsSync as existsSync28, readFileSync as readFileSync23 } from "fs";
10086
- import { join as join29 } from "path";
11249
+ import { existsSync as existsSync29, readFileSync as readFileSync24 } from "fs";
11250
+ import { join as join30 } from "path";
10087
11251
  function detectTechnologies(projectPath) {
10088
11252
  const technologies = [];
10089
11253
  const seen = /* @__PURE__ */ new Set();
@@ -10111,23 +11275,23 @@ function detectTechnologies(projectPath) {
10111
11275
  return technologies;
10112
11276
  }
10113
11277
  function detectFromLockfiles(projectPath) {
10114
- const npmLock = join29(projectPath, "package-lock.json");
10115
- if (existsSync28(npmLock)) {
11278
+ const npmLock = join30(projectPath, "package-lock.json");
11279
+ if (existsSync29(npmLock)) {
10116
11280
  return parsePackageLock(npmLock);
10117
11281
  }
10118
- const pnpmLock = join29(projectPath, "pnpm-lock.yaml");
10119
- if (existsSync28(pnpmLock)) {
11282
+ const pnpmLock = join30(projectPath, "pnpm-lock.yaml");
11283
+ if (existsSync29(pnpmLock)) {
10120
11284
  return parsePnpmLock(pnpmLock);
10121
11285
  }
10122
- const yarnLock = join29(projectPath, "yarn.lock");
10123
- if (existsSync28(yarnLock)) {
11286
+ const yarnLock = join30(projectPath, "yarn.lock");
11287
+ if (existsSync29(yarnLock)) {
10124
11288
  return parseYarnLock(yarnLock);
10125
11289
  }
10126
11290
  return [];
10127
11291
  }
10128
11292
  function parsePackageLock(lockPath) {
10129
11293
  try {
10130
- const content = JSON.parse(readFileSync23(lockPath, "utf-8"));
11294
+ const content = JSON.parse(readFileSync24(lockPath, "utf-8"));
10131
11295
  const techs = [];
10132
11296
  if (content.packages) {
10133
11297
  for (const [key, pkg] of Object.entries(content.packages)) {
@@ -10162,7 +11326,7 @@ function parsePackageLock(lockPath) {
10162
11326
  }
10163
11327
  function parsePnpmLock(lockPath) {
10164
11328
  try {
10165
- const content = readFileSync23(lockPath, "utf-8");
11329
+ const content = readFileSync24(lockPath, "utf-8");
10166
11330
  const techs = [];
10167
11331
  const packageRegex = /^\s*[/'"]?(@?[^@\s'":]+)@(\d+\.\d+\.\d+[^'":]*)/gm;
10168
11332
  let match;
@@ -10187,7 +11351,7 @@ function parsePnpmLock(lockPath) {
10187
11351
  }
10188
11352
  function parseYarnLock(lockPath) {
10189
11353
  try {
10190
- const content = readFileSync23(lockPath, "utf-8");
11354
+ const content = readFileSync24(lockPath, "utf-8");
10191
11355
  const techs = [];
10192
11356
  const seen = /* @__PURE__ */ new Set();
10193
11357
  const lines = content.split("\n");
@@ -10221,28 +11385,37 @@ function parseYarnLock(lockPath) {
10221
11385
  }
10222
11386
  function detectFromManifests(projectPath) {
10223
11387
  const techs = [];
10224
- const pkgPath = join29(projectPath, "package.json");
10225
- if (existsSync28(pkgPath)) {
10226
- try {
10227
- const pkg = JSON.parse(readFileSync23(pkgPath, "utf-8"));
10228
- const allDeps = {
10229
- ...pkg.dependencies,
10230
- ...pkg.devDependencies
10231
- };
10232
- for (const [name, versionRange] of Object.entries(allDeps)) {
10233
- techs.push({
10234
- name,
10235
- version: cleanSemverRange(versionRange),
10236
- source: "package.json"
10237
- });
11388
+ const pkgPaths = [
11389
+ join30(projectPath, "package.json"),
11390
+ ...["frontend", "backend", "client", "server", "web", "app"].map((d) => join30(projectPath, d, "package.json"))
11391
+ ];
11392
+ const seenPkgs = /* @__PURE__ */ new Set();
11393
+ for (const pkgPath of pkgPaths) {
11394
+ if (existsSync29(pkgPath)) {
11395
+ try {
11396
+ const pkg = JSON.parse(readFileSync24(pkgPath, "utf-8"));
11397
+ const allDeps = {
11398
+ ...pkg.dependencies,
11399
+ ...pkg.devDependencies
11400
+ };
11401
+ for (const [name, versionRange] of Object.entries(allDeps)) {
11402
+ if (!seenPkgs.has(name)) {
11403
+ seenPkgs.add(name);
11404
+ techs.push({
11405
+ name,
11406
+ version: cleanSemverRange(versionRange),
11407
+ source: "package.json"
11408
+ });
11409
+ }
11410
+ }
11411
+ } catch {
10238
11412
  }
10239
- } catch {
10240
11413
  }
10241
11414
  }
10242
- const reqPath = join29(projectPath, "requirements.txt");
10243
- if (existsSync28(reqPath)) {
11415
+ const reqPath = join30(projectPath, "requirements.txt");
11416
+ if (existsSync29(reqPath)) {
10244
11417
  try {
10245
- const content = readFileSync23(reqPath, "utf-8");
11418
+ const content = readFileSync24(reqPath, "utf-8");
10246
11419
  for (const line of content.split("\n")) {
10247
11420
  const match = line.match(/^([a-zA-Z0-9_-]+)==([^\s]+)/);
10248
11421
  if (match && match[1] && match[2]) {
@@ -10252,10 +11425,10 @@ function detectFromManifests(projectPath) {
10252
11425
  } catch {
10253
11426
  }
10254
11427
  }
10255
- const goModPath = join29(projectPath, "go.mod");
10256
- if (existsSync28(goModPath)) {
11428
+ const goModPath = join30(projectPath, "go.mod");
11429
+ if (existsSync29(goModPath)) {
10257
11430
  try {
10258
- const content = readFileSync23(goModPath, "utf-8");
11431
+ const content = readFileSync24(goModPath, "utf-8");
10259
11432
  const reqRegex = /^\s+([^\s]+)\s+v([^\s]+)/gm;
10260
11433
  let match;
10261
11434
  while ((match = reqRegex.exec(content)) !== null) {
@@ -10266,10 +11439,10 @@ function detectFromManifests(projectPath) {
10266
11439
  } catch {
10267
11440
  }
10268
11441
  }
10269
- const cargoPath = join29(projectPath, "Cargo.toml");
10270
- if (existsSync28(cargoPath)) {
11442
+ const cargoPath = join30(projectPath, "Cargo.toml");
11443
+ if (existsSync29(cargoPath)) {
10271
11444
  try {
10272
- const content = readFileSync23(cargoPath, "utf-8");
11445
+ const content = readFileSync24(cargoPath, "utf-8");
10273
11446
  const depRegex = /^([a-zA-Z0-9_-]+)\s*=\s*"([^"]+)"/gm;
10274
11447
  let match;
10275
11448
  let inDeps = false;
@@ -10297,12 +11470,12 @@ function detectFromManifests(projectPath) {
10297
11470
  function detectFromConfigFiles(projectPath) {
10298
11471
  const techs = [];
10299
11472
  for (const detection of CONFIG_DETECTIONS) {
10300
- const filePath = join29(projectPath, detection.file);
10301
- if (existsSync28(filePath)) {
11473
+ const filePath = join30(projectPath, detection.file);
11474
+ if (existsSync29(filePath)) {
10302
11475
  let version2 = "detected";
10303
11476
  if (detection.versionExtractor) {
10304
11477
  try {
10305
- const content = readFileSync23(filePath, "utf-8");
11478
+ const content = readFileSync24(filePath, "utf-8");
10306
11479
  version2 = detection.versionExtractor(content) || "detected";
10307
11480
  } catch {
10308
11481
  }
@@ -10317,43 +11490,43 @@ function detectFromConfigFiles(projectPath) {
10317
11490
  return techs;
10318
11491
  }
10319
11492
  function detectMonorepo(projectPath) {
10320
- const pnpmWorkspace = join29(projectPath, "pnpm-workspace.yaml");
10321
- if (existsSync28(pnpmWorkspace)) {
10322
- const content = readFileSync23(pnpmWorkspace, "utf-8");
11493
+ const pnpmWorkspace = join30(projectPath, "pnpm-workspace.yaml");
11494
+ if (existsSync29(pnpmWorkspace)) {
11495
+ const content = readFileSync24(pnpmWorkspace, "utf-8");
10323
11496
  const packages = extractWorkspacePatterns(content);
10324
11497
  return { type: "pnpm", packages, rootPath: projectPath };
10325
11498
  }
10326
- if (existsSync28(join29(projectPath, "turbo.json"))) {
10327
- const pkgJson = join29(projectPath, "package.json");
11499
+ if (existsSync29(join30(projectPath, "turbo.json"))) {
11500
+ const pkgJson = join30(projectPath, "package.json");
10328
11501
  let packages = [];
10329
- if (existsSync28(pkgJson)) {
11502
+ if (existsSync29(pkgJson)) {
10330
11503
  try {
10331
- const pkg = JSON.parse(readFileSync23(pkgJson, "utf-8"));
11504
+ const pkg = JSON.parse(readFileSync24(pkgJson, "utf-8"));
10332
11505
  packages = Array.isArray(pkg.workspaces) ? pkg.workspaces : pkg.workspaces?.packages || [];
10333
11506
  } catch {
10334
11507
  }
10335
11508
  }
10336
11509
  return { type: "turborepo", packages, rootPath: projectPath };
10337
11510
  }
10338
- const pkgPath = join29(projectPath, "package.json");
10339
- if (existsSync28(pkgPath)) {
11511
+ const pkgPath = join30(projectPath, "package.json");
11512
+ if (existsSync29(pkgPath)) {
10340
11513
  try {
10341
- const pkg = JSON.parse(readFileSync23(pkgPath, "utf-8"));
11514
+ const pkg = JSON.parse(readFileSync24(pkgPath, "utf-8"));
10342
11515
  if (pkg.workspaces) {
10343
11516
  const patterns = Array.isArray(pkg.workspaces) ? pkg.workspaces : pkg.workspaces.packages || [];
10344
- const type = existsSync28(join29(projectPath, "yarn.lock")) ? "yarn-workspaces" : "npm-workspaces";
11517
+ const type = existsSync29(join30(projectPath, "yarn.lock")) ? "yarn-workspaces" : "npm-workspaces";
10345
11518
  return { type, packages: patterns, rootPath: projectPath };
10346
11519
  }
10347
11520
  } catch {
10348
11521
  }
10349
11522
  }
10350
- if (existsSync28(join29(projectPath, "nx.json"))) {
11523
+ if (existsSync29(join30(projectPath, "nx.json"))) {
10351
11524
  return { type: "nx", packages: ["packages/*", "apps/*"], rootPath: projectPath };
10352
11525
  }
10353
- const lernaPath = join29(projectPath, "lerna.json");
10354
- if (existsSync28(lernaPath)) {
11526
+ const lernaPath = join30(projectPath, "lerna.json");
11527
+ if (existsSync29(lernaPath)) {
10355
11528
  try {
10356
- const lerna = JSON.parse(readFileSync23(lernaPath, "utf-8"));
11529
+ const lerna = JSON.parse(readFileSync24(lernaPath, "utf-8"));
10357
11530
  return { type: "lerna", packages: lerna.packages || ["packages/*"], rootPath: projectPath };
10358
11531
  } catch {
10359
11532
  }
@@ -10418,8 +11591,8 @@ var init_tech_detector = __esm({
10418
11591
  });
10419
11592
 
10420
11593
  // src/core/agents/feature-detector.ts
10421
- import { existsSync as existsSync29, readFileSync as readFileSync24, readdirSync as readdirSync10 } from "fs";
10422
- import { join as join30, relative as relative7, basename as basename10 } from "path";
11594
+ import { existsSync as existsSync30, readFileSync as readFileSync25, readdirSync as readdirSync11 } from "fs";
11595
+ import { join as join31, relative as relative7, basename as basename10 } from "path";
10423
11596
  function detectFeatures(input) {
10424
11597
  const { projectPath, config: config2, importGraph, indexedFiles, fileTechMap } = input;
10425
11598
  let candidates = [];
@@ -10480,15 +11653,15 @@ function findSubPackageJsons(projectPath) {
10480
11653
  function walk(dir, depth) {
10481
11654
  if (depth > maxDepth) return;
10482
11655
  try {
10483
- const entries = readdirSync10(dir, { withFileTypes: true });
11656
+ const entries = readdirSync11(dir, { withFileTypes: true });
10484
11657
  for (const entry of entries) {
10485
11658
  if (!entry.isDirectory()) continue;
10486
11659
  const lower = entry.name.toLowerCase();
10487
11660
  if (lower === "node_modules" || lower === ".git" || lower === "dist") continue;
10488
11661
  if (EXCLUDED_FEATURE_DIRS.has(lower)) continue;
10489
- const subDir = join30(dir, entry.name);
10490
- const pkgJson = join30(subDir, "package.json");
10491
- if (existsSync29(pkgJson) && subDir !== projectPath) {
11662
+ const subDir = join31(dir, entry.name);
11663
+ const pkgJson = join31(subDir, "package.json");
11664
+ if (existsSync30(pkgJson) && subDir !== projectPath) {
10492
11665
  results.push(subDir);
10493
11666
  }
10494
11667
  walk(subDir, depth + 1);
@@ -10502,20 +11675,20 @@ function findSubPackageJsons(projectPath) {
10502
11675
  function detectCodeownerFeatures(projectPath, indexedFiles) {
10503
11676
  const features = [];
10504
11677
  const codeownersLocations = [
10505
- join30(projectPath, "CODEOWNERS"),
10506
- join30(projectPath, ".github", "CODEOWNERS"),
10507
- join30(projectPath, "docs", "CODEOWNERS")
11678
+ join31(projectPath, "CODEOWNERS"),
11679
+ join31(projectPath, ".github", "CODEOWNERS"),
11680
+ join31(projectPath, "docs", "CODEOWNERS")
10508
11681
  ];
10509
11682
  let codeownersPath = null;
10510
11683
  for (const loc of codeownersLocations) {
10511
- if (existsSync29(loc)) {
11684
+ if (existsSync30(loc)) {
10512
11685
  codeownersPath = loc;
10513
11686
  break;
10514
11687
  }
10515
11688
  }
10516
11689
  if (!codeownersPath) return features;
10517
11690
  try {
10518
- const content = readFileSync24(codeownersPath, "utf-8");
11691
+ const content = readFileSync25(codeownersPath, "utf-8");
10519
11692
  const entries = parseCodeowners(content);
10520
11693
  for (const entry of entries) {
10521
11694
  const matchingFiles = indexedFiles.filter((f) => matchCodeownerPattern(f, entry.pattern));
@@ -10759,10 +11932,15 @@ var init_feature_detector = __esm({
10759
11932
  ".next",
10760
11933
  ".nuxt",
10761
11934
  ".output",
10762
- // Dependencies
11935
+ // Dependencies / virtual environments
10763
11936
  "node_modules",
10764
11937
  ".yarn",
10765
11938
  ".pnpm-store",
11939
+ "venv",
11940
+ ".venv",
11941
+ "env",
11942
+ "virtualenv",
11943
+ "ENV",
10766
11944
  // CI / config
10767
11945
  ".github",
10768
11946
  ".gitlab",
@@ -10787,8 +11965,8 @@ var init_feature_detector = __esm({
10787
11965
 
10788
11966
  // src/core/agents/git-operations.ts
10789
11967
  import { execSync as execSync9 } from "child_process";
10790
- import { existsSync as existsSync30 } from "fs";
10791
- import { join as join31 } from "path";
11968
+ import { existsSync as existsSync31 } from "fs";
11969
+ import { join as join32 } from "path";
10792
11970
  function isGitRepo(projectPath) {
10793
11971
  try {
10794
11972
  git(projectPath, "rev-parse --is-inside-work-tree");
@@ -10830,7 +12008,7 @@ function commitChanges(projectPath, options) {
10830
12008
  }
10831
12009
  } else {
10832
12010
  git(projectPath, "add .code-impact/");
10833
- if (existsSync30(join31(projectPath, "AGENTS.md"))) {
12011
+ if (existsSync31(join32(projectPath, "AGENTS.md"))) {
10834
12012
  git(projectPath, "add AGENTS.md");
10835
12013
  }
10836
12014
  }
@@ -10950,7 +12128,7 @@ var init_git_operations = __esm({
10950
12128
  });
10951
12129
 
10952
12130
  // src/core/agents/marker-writer.ts
10953
- import { existsSync as existsSync31, readFileSync as readFileSync25, writeFileSync as writeFileSync18, mkdirSync as mkdirSync16 } from "fs";
12131
+ import { existsSync as existsSync32, readFileSync as readFileSync26, writeFileSync as writeFileSync18, mkdirSync as mkdirSync16 } from "fs";
10954
12132
  import { dirname as dirname13 } from "path";
10955
12133
  function writeMarkedFile(filePath, frontmatter, sections, options) {
10956
12134
  const result = {
@@ -10970,8 +12148,8 @@ function writeMarkedFile(filePath, frontmatter, sections, options) {
10970
12148
  result.tokenCount = estimateTokens5(autoContent);
10971
12149
  return result;
10972
12150
  }
10973
- if (existsSync31(filePath)) {
10974
- const existing = readFileSync25(filePath, "utf-8");
12151
+ if (existsSync32(filePath)) {
12152
+ const existing = readFileSync26(filePath, "utf-8");
10975
12153
  if (existing.includes(options.markers.start)) {
10976
12154
  const existingAutoContent = extractAutoContent(existing, options.markers);
10977
12155
  const existingHash = computeContentHash(existingAutoContent);
@@ -11192,19 +12370,19 @@ var init_token_budget = __esm({
11192
12370
  });
11193
12371
 
11194
12372
  // src/core/agents/generator.ts
11195
- import { existsSync as existsSync32, readFileSync as readFileSync26, mkdirSync as mkdirSync17 } from "fs";
11196
- import { join as join33 } from "path";
12373
+ import { existsSync as existsSync33, readFileSync as readFileSync27, mkdirSync as mkdirSync17 } from "fs";
12374
+ import { join as join34 } from "path";
11197
12375
  function generateProjectFiles(input) {
11198
12376
  const { projectPath, intelligence, technologies, features, index } = input;
11199
12377
  const config2 = readAgentConfig(projectPath);
11200
12378
  const paths = getAgentWorkspacePaths(projectPath);
11201
12379
  const result = { filesWritten: [], filesSkipped: [] };
11202
12380
  mkdirSync17(paths.projectDir, { recursive: true });
11203
- const skillPath = join33(paths.projectDir, "SKILL.md");
12381
+ const skillPath = join34(paths.projectDir, "SKILL.md");
11204
12382
  writeMarkedFile2(skillPath, renderProjectSkill(intelligence, technologies, config2, projectPath), config2, result, "project_skill");
11205
- const convPath = join33(paths.projectDir, "CONVENTIONS.md");
12383
+ const convPath = join34(paths.projectDir, "CONVENTIONS.md");
11206
12384
  writeMarkedFile2(convPath, renderConventions(intelligence, config2), config2, result, "project_conventions");
11207
- const archPath = join33(paths.projectDir, "ARCHITECTURE.md");
12385
+ const archPath = join34(paths.projectDir, "ARCHITECTURE.md");
11208
12386
  writeMarkedFile2(archPath, renderArchitecture(intelligence, config2), config2, result, "project_architecture");
11209
12387
  return result;
11210
12388
  }
@@ -11214,9 +12392,9 @@ function generateFeatureFiles(input) {
11214
12392
  const paths = getAgentWorkspacePaths(projectPath);
11215
12393
  const result = { filesWritten: [], filesSkipped: [] };
11216
12394
  for (const feature of features) {
11217
- const featureDir = join33(paths.featuresDir, feature.name);
12395
+ const featureDir = join34(paths.featuresDir, feature.name);
11218
12396
  mkdirSync17(featureDir, { recursive: true });
11219
- const skillPath = join33(featureDir, "SKILL.md");
12397
+ const skillPath = join34(featureDir, "SKILL.md");
11220
12398
  const featureTechs = technologies.filter((t) => feature.technologies.includes(t.name));
11221
12399
  writeMarkedFile2(skillPath, renderFeatureSkill(feature, featureTechs, config2), config2, result, "feature_skill");
11222
12400
  }
@@ -11274,7 +12452,7 @@ function renderProjectSkill(intel, technologies, config2, projectPath) {
11274
12452
  } else {
11275
12453
  for (const dir of intel.codebase.keyDirectories) {
11276
12454
  const dirName = dir.split("/").pop() || dir;
11277
- const purpose = inferDirPurpose(dirName);
12455
+ const purpose = inferDirectoryPurpose(dirName);
11278
12456
  lines.push(`| ${dir}/ | ${purpose} |`);
11279
12457
  }
11280
12458
  }
@@ -11376,8 +12554,10 @@ function renderArchitecture(intel, config2) {
11376
12554
  return { frontmatter, autoContent: lines.join("\n") };
11377
12555
  }
11378
12556
  function renderFeatureSkill(feature, technologies, config2) {
11379
- const techNames = technologies.map((t) => t.name);
11380
- const researchRefs = technologies.map((t) => `research/${t.name}@${t.version}.md`);
12557
+ const grouped = groupScopedPackages(technologies);
12558
+ const techNames = grouped.map((t) => t.name);
12559
+ const researchTechs = technologies.slice(0, 15);
12560
+ const researchRefs = researchTechs.map((t) => `research/${t.name}@${t.version}.md`);
11381
12561
  const frontmatter = [
11382
12562
  "---",
11383
12563
  `name: ${feature.name}-feature`,
@@ -11390,7 +12570,7 @@ function renderFeatureSkill(feature, technologies, config2) {
11390
12570
  ` research_refs: [${researchRefs.join(", ")}]`,
11391
12571
  "---",
11392
12572
  "",
11393
- `# ${capitalize(feature.name)} Feature`
12573
+ `# ${capitalize2(feature.name)} Feature`
11394
12574
  ].join("\n");
11395
12575
  const lines = [];
11396
12576
  lines.push("## Scope");
@@ -11410,14 +12590,16 @@ function renderFeatureSkill(feature, technologies, config2) {
11410
12590
  if (feature.owner) {
11411
12591
  lines.push(`- Owner: ${feature.owner}`);
11412
12592
  }
11413
- if (technologies.length > 0) {
11414
- lines.push(`- Technologies: ${techNames.join(", ")}`);
12593
+ if (grouped.length > 0) {
12594
+ const displayTechs = techNames.slice(0, 10);
12595
+ const suffix = techNames.length > 10 ? `, +${techNames.length - 10} more` : "";
12596
+ lines.push(`- Technologies: ${displayTechs.join(", ")}${suffix}`);
11415
12597
  }
11416
12598
  lines.push("");
11417
12599
  if (researchRefs.length > 0) {
11418
12600
  lines.push("## Research References");
11419
12601
  for (const ref of researchRefs) {
11420
- const tech = technologies.find((t) => ref.includes(t.name));
12602
+ const tech = researchTechs.find((t) => ref.includes(t.name));
11421
12603
  if (tech) {
11422
12604
  lines.push(`- [${tech.name} v${tech.version}](../${ref})`);
11423
12605
  }
@@ -11425,13 +12607,13 @@ function renderFeatureSkill(feature, technologies, config2) {
11425
12607
  lines.push("");
11426
12608
  }
11427
12609
  lines.push("## Rules");
11428
- const rules = deriveRules(feature, technologies);
12610
+ const rules = deriveFeatureRules(feature, technologies);
11429
12611
  for (const rule of rules) {
11430
12612
  lines.push(`- ${rule}`);
11431
12613
  }
11432
12614
  lines.push("");
11433
12615
  lines.push("## Pitfalls");
11434
- const pitfalls = derivePitfalls(feature, technologies);
12616
+ const pitfalls = deriveFeaturePitfalls(feature, technologies);
11435
12617
  for (const pitfall of pitfalls) {
11436
12618
  lines.push(`- ${pitfall}`);
11437
12619
  }
@@ -11502,150 +12684,7 @@ function summarizeTestFiles(testFiles) {
11502
12684
  }
11503
12685
  return globs;
11504
12686
  }
11505
- function inferDirPurpose(dirName) {
11506
- const purposes = {
11507
- core: "Core business logic and domain modules",
11508
- server: "Server, transports, and request handling",
11509
- storage: "Database access and persistence",
11510
- indexing: "Code indexing and symbol extraction",
11511
- api: "API routes and handlers",
11512
- auth: "Authentication and authorization",
11513
- billing: "Payment processing",
11514
- test: "Tests and evaluation harness",
11515
- doc: "Documentation",
11516
- knowledge: "AI knowledge system",
11517
- cli: "Command-line interface",
11518
- base: "Base configuration and fixtures",
11519
- src: "Application source code",
11520
- lib: "Shared utilities"
11521
- };
11522
- return purposes[dirName.toLowerCase()] || `${dirName} module`;
11523
- }
11524
- function deriveRules(feature, technologies) {
11525
- const rules = [];
11526
- if (WELL_KNOWN_FEATURES.has(feature.name)) {
11527
- rules.push(...getFeatureNameRules(feature.name));
11528
- const techRules = [];
11529
- for (const tech of technologies) {
11530
- const knowledge = TECH_KNOWLEDGE[tech.name];
11531
- if (knowledge) techRules.push(...knowledge.rules);
11532
- }
11533
- for (const tr of techRules.slice(0, 2)) {
11534
- if (!rules.some((r) => r.includes(tr.split(" ")[0] || ""))) {
11535
- rules.push(tr);
11536
- }
11537
- }
11538
- } else {
11539
- for (const tech of technologies) {
11540
- const knowledge = TECH_KNOWLEDGE[tech.name];
11541
- if (knowledge) rules.push(...knowledge.rules);
11542
- }
11543
- if (rules.length === 0) {
11544
- rules.push(...getFeatureNameRules(feature.name));
11545
- }
11546
- }
11547
- if (feature.paths.length > 0) {
11548
- const scope = feature.paths[0]?.replace("/**", "") || "";
11549
- rules.push(`Changes here should not import from other feature directories \u2014 keep ${scope} self-contained`);
11550
- }
11551
- return rules;
11552
- }
11553
- function derivePitfalls(feature, technologies) {
11554
- const pitfalls = [];
11555
- if (WELL_KNOWN_FEATURES.has(feature.name)) {
11556
- pitfalls.push(...getFeatureNamePitfalls(feature.name));
11557
- for (const tech of technologies) {
11558
- const knowledge = TECH_KNOWLEDGE[tech.name];
11559
- if (knowledge) {
11560
- for (const p of knowledge.pitfalls.slice(0, 1)) {
11561
- if (!pitfalls.includes(p)) pitfalls.push(p);
11562
- }
11563
- }
11564
- }
11565
- } else {
11566
- for (const tech of technologies) {
11567
- const knowledge = TECH_KNOWLEDGE[tech.name];
11568
- if (knowledge) pitfalls.push(...knowledge.pitfalls);
11569
- }
11570
- if (pitfalls.length === 0) {
11571
- pitfalls.push(...getFeatureNamePitfalls(feature.name));
11572
- }
11573
- }
11574
- return pitfalls;
11575
- }
11576
- function getFeatureNameRules(name) {
11577
- const rules = {
11578
- server: [
11579
- "All tool/resource handlers must validate inputs before processing",
11580
- "Return structured error responses \u2014 never throw raw errors to clients"
11581
- ],
11582
- storage: [
11583
- "All database access should go through this module \u2014 no direct imports elsewhere",
11584
- "Use transactions for multi-step operations to ensure consistency"
11585
- ],
11586
- indexing: [
11587
- "Index operations should be idempotent \u2014 reindexing same file produces same result",
11588
- "Handle parse errors gracefully \u2014 a broken file should not crash the indexer"
11589
- ],
11590
- core: [
11591
- "Core modules should have no side effects on import",
11592
- "Export types alongside functions for downstream consumers"
11593
- ],
11594
- test: [
11595
- "Tests should be deterministic \u2014 no reliance on external services or timing",
11596
- "Clean up temporary files and directories in afterEach/afterAll hooks"
11597
- ],
11598
- knowledge: [
11599
- "Skill files must follow the agentskills.io SKILL.md format",
11600
- "Generated content must use marker comments to preserve manual edits"
11601
- ],
11602
- doc: [
11603
- "Generated docs must be kept in sync with source code changes",
11604
- "Use relative paths for internal links"
11605
- ],
11606
- auth: [
11607
- "Never store plain-text passwords \u2014 use bcrypt or argon2",
11608
- "Validate and sanitize all user inputs before processing"
11609
- ],
11610
- api: [
11611
- "All endpoints must validate request bodies/params before processing",
11612
- "Return consistent error response shapes across all endpoints"
11613
- ]
11614
- };
11615
- return rules[name] || [
11616
- "Follow existing patterns in this module for consistency",
11617
- "Export public API from index.ts \u2014 keep internal helpers unexported"
11618
- ];
11619
- }
11620
- function getFeatureNamePitfalls(name) {
11621
- const pitfalls = {
11622
- server: [
11623
- "Unhandled promise rejections in handlers crash the process \u2014 always catch async errors",
11624
- "Adding middleware order matters \u2014 auth before route handlers"
11625
- ],
11626
- storage: [
11627
- "Forgetting to close database connections leaks file handles",
11628
- "Concurrent writes without transactions may cause data corruption"
11629
- ],
11630
- indexing: [
11631
- "Large files can cause out-of-memory \u2014 set size limits on parsed content",
11632
- "File paths must be normalized (forward slashes) for cross-platform compatibility"
11633
- ],
11634
- core: [
11635
- "Circular imports between core modules cause runtime errors \u2014 check dependency direction",
11636
- "Changing public API signatures breaks downstream consumers"
11637
- ],
11638
- test: [
11639
- "Tests sharing mutable state between runs cause flaky failures",
11640
- "Temp directories not cleaned up fill disk over repeated test runs"
11641
- ]
11642
- };
11643
- return pitfalls[name] || [
11644
- "Check for null/undefined before property access on external data",
11645
- "Changing exports may break other modules that depend on this feature"
11646
- ];
11647
- }
11648
- function capitalize(str) {
12687
+ function capitalize2(str) {
11649
12688
  return str.charAt(0).toUpperCase() + str.slice(1).replace(/-/g, " ");
11650
12689
  }
11651
12690
  function filterDirectDependencies(technologies, projectPath) {
@@ -11657,13 +12696,13 @@ function filterDirectDependencies(technologies, projectPath) {
11657
12696
  }
11658
12697
  if (directNames.size === 0) {
11659
12698
  const searchPaths = [
11660
- projectPath ? join33(projectPath, "package.json") : "",
11661
- join33(process.cwd(), "package.json")
12699
+ projectPath ? join34(projectPath, "package.json") : "",
12700
+ join34(process.cwd(), "package.json")
11662
12701
  ].filter(Boolean);
11663
12702
  for (const p of searchPaths) {
11664
12703
  try {
11665
- if (existsSync32(p)) {
11666
- const pkg = JSON.parse(readFileSync26(p, "utf-8"));
12704
+ if (existsSync33(p)) {
12705
+ const pkg = JSON.parse(readFileSync27(p, "utf-8"));
11667
12706
  for (const d of Object.keys(pkg.dependencies || {})) directNames.add(d);
11668
12707
  for (const d of Object.keys(pkg.devDependencies || {})) directNames.add(d);
11669
12708
  break;
@@ -11680,151 +12719,50 @@ function filterDirectDependencies(technologies, projectPath) {
11680
12719
  /^@parcel\//,
11681
12720
  /^@biomejs\//
11682
12721
  ];
12722
+ let filtered;
11683
12723
  if (directNames.size > 0) {
11684
- return technologies.filter((t) => directNames.has(t.name)).filter((t) => !skipPatterns.some((p) => p.test(t.name)));
12724
+ filtered = technologies.filter((t) => directNames.has(t.name)).filter((t) => !skipPatterns.some((p) => p.test(t.name)));
12725
+ } else {
12726
+ filtered = technologies.filter((t) => !skipPatterns.some((p) => p.test(t.name))).slice(0, 30);
12727
+ }
12728
+ return groupScopedPackages(filtered);
12729
+ }
12730
+ function groupScopedPackages(techs) {
12731
+ const scopeMap = /* @__PURE__ */ new Map();
12732
+ const ungrouped = [];
12733
+ for (const t of techs) {
12734
+ const m = t.name.match(/^(@[^/]+)\//);
12735
+ if (m) {
12736
+ const scope = m[1];
12737
+ if (!scopeMap.has(scope)) scopeMap.set(scope, []);
12738
+ scopeMap.get(scope).push(t);
12739
+ } else {
12740
+ ungrouped.push(t);
12741
+ }
12742
+ }
12743
+ const result = [...ungrouped];
12744
+ for (const [scope, members] of scopeMap.entries()) {
12745
+ if (members.length >= 3) {
12746
+ const label = inferScopeLabel(scope, members.length);
12747
+ result.push({
12748
+ name: label,
12749
+ version: members[0].version,
12750
+ source: members[0].source,
12751
+ importPaths: members.flatMap((m) => m.importPaths || [])
12752
+ });
12753
+ } else {
12754
+ result.push(...members);
12755
+ }
11685
12756
  }
11686
- return technologies.filter((t) => !skipPatterns.some((p) => p.test(t.name))).slice(0, 20);
12757
+ return result;
11687
12758
  }
11688
- var TECH_KNOWLEDGE, WELL_KNOWN_FEATURES;
11689
12759
  var init_generator = __esm({
11690
12760
  "src/core/agents/generator.ts"() {
11691
12761
  "use strict";
11692
12762
  init_workspace2();
11693
12763
  init_marker_writer();
11694
12764
  init_token_budget();
11695
- TECH_KNOWLEDGE = {
11696
- "express": {
11697
- rules: [
11698
- "Use Router() for modular route definitions",
11699
- "Always register error handler middleware last (4 args: err, req, res, next)"
11700
- ],
11701
- pitfalls: [
11702
- "Forgetting to call next() in middleware causes request to hang",
11703
- "Async errors in handlers need explicit try/catch or express-async-errors"
11704
- ]
11705
- },
11706
- "hono": {
11707
- rules: [
11708
- "Use app.route() for modular route grouping",
11709
- "Return c.json() or c.text() \u2014 do not use res.send()"
11710
- ],
11711
- pitfalls: [
11712
- "Hono middleware must call next() or return a Response \u2014 skipping both hangs the request"
11713
- ]
11714
- },
11715
- "better-sqlite3": {
11716
- rules: [
11717
- "Use db.prepare().all() for SELECT, db.prepare().run() for INSERT/UPDATE/DELETE",
11718
- "better-sqlite3 is synchronous \u2014 do NOT use async/await with db calls",
11719
- "All database access should go through a single module"
11720
- ],
11721
- pitfalls: [
11722
- "db.exec() returns nothing \u2014 using it for SELECT gives undefined",
11723
- 'WAL mode must be set once after opening: db.pragma("journal_mode = WAL")'
11724
- ]
11725
- },
11726
- "stripe": {
11727
- rules: [
11728
- "Always verify webhook signatures before processing events",
11729
- "Use idempotency keys for payment creation to prevent double-charges"
11730
- ],
11731
- pitfalls: [
11732
- "Stripe webhook events may arrive out of order \u2014 handle idempotently",
11733
- "stripe.webhooks.constructEvent() throws on invalid signature \u2014 wrap in try/catch"
11734
- ]
11735
- },
11736
- "jsonwebtoken": {
11737
- rules: [
11738
- "Always use jwt.verify() \u2014 never trust jwt.decode() alone",
11739
- "Set explicit expiration (expiresIn) on all tokens"
11740
- ],
11741
- pitfalls: [
11742
- "Using jwt.decode() without verify() is a security vulnerability",
11743
- 'The "none" algorithm attack \u2014 always specify algorithms: ["HS256"]'
11744
- ]
11745
- },
11746
- "@modelcontextprotocol/sdk": {
11747
- rules: [
11748
- "Use server.tool() to register MCP tools with zod schema validation",
11749
- "All tool handlers must return { content: [...] } response objects"
11750
- ],
11751
- pitfalls: [
11752
- "Tool names must be unique across the server \u2014 duplicates silently overwrite",
11753
- "Forgetting to call server.connect(transport) means no requests are handled"
11754
- ]
11755
- },
11756
- "prisma": {
11757
- rules: [
11758
- "Run npx prisma generate after schema changes",
11759
- "Use transactions for multi-table operations: prisma.$transaction()"
11760
- ],
11761
- pitfalls: [
11762
- "Forgetting prisma generate after schema change causes type mismatches at runtime",
11763
- "N+1 queries \u2014 use include/select to eagerly load relations"
11764
- ]
11765
- },
11766
- "zod": {
11767
- rules: [
11768
- "Define schemas once, derive TypeScript types with z.infer<typeof schema>",
11769
- "Use .safeParse() in handlers for graceful error handling"
11770
- ],
11771
- pitfalls: [
11772
- ".parse() throws on invalid data \u2014 use .safeParse() in request handlers"
11773
- ]
11774
- },
11775
- "vitest": {
11776
- rules: [
11777
- "Use describe/it/expect patterns for test organization",
11778
- "Use vi.mock() for module mocking, vi.fn() for function stubs"
11779
- ],
11780
- pitfalls: [
11781
- "vi.mock() is hoisted to top of file \u2014 cannot access variables from outer scope"
11782
- ]
11783
- },
11784
- "web-tree-sitter": {
11785
- rules: [
11786
- "Initialize Parser with await Parser.init() before use",
11787
- "Load language WASM files with Parser.Language.load()"
11788
- ],
11789
- pitfalls: [
11790
- "Parser.init() must complete before any parsing \u2014 race condition if not awaited",
11791
- "WASM files must be bundled/copied to dist \u2014 not resolved from node_modules at runtime"
11792
- ]
11793
- },
11794
- "@xenova/transformers": {
11795
- rules: [
11796
- "Use pipeline() for high-level tasks, AutoModel for custom inference",
11797
- "Cache downloaded models by setting env.cacheDir"
11798
- ],
11799
- pitfalls: [
11800
- "First model load downloads weights (~100MB+) \u2014 cache for subsequent runs",
11801
- "ONNX runtime may fail on some architectures \u2014 test on target platform"
11802
- ]
11803
- },
11804
- "chokidar": {
11805
- rules: [
11806
- "Use chokidar.watch() with ignored patterns to skip node_modules",
11807
- 'Handle both "add" and "change" events for file watching'
11808
- ],
11809
- pitfalls: [
11810
- "Not closing watcher on process exit leaks file handles",
11811
- "Rapid file changes may fire multiple events \u2014 debounce handlers"
11812
- ]
11813
- }
11814
- };
11815
- WELL_KNOWN_FEATURES = /* @__PURE__ */ new Set([
11816
- "server",
11817
- "storage",
11818
- "indexing",
11819
- "core",
11820
- "test",
11821
- "knowledge",
11822
- "doc",
11823
- "auth",
11824
- "api",
11825
- "billing",
11826
- "cli"
11827
- ]);
12765
+ init_universal_inference();
11828
12766
  }
11829
12767
  });
11830
12768
 
@@ -12132,8 +13070,8 @@ var init_co_change_analyzer = __esm({
12132
13070
  });
12133
13071
 
12134
13072
  // src/core/agents/lifecycle.ts
12135
- import { existsSync as existsSync33, readdirSync as readdirSync11, statSync as statSync6 } from "fs";
12136
- import { join as join34 } from "path";
13073
+ import { existsSync as existsSync34, readdirSync as readdirSync12, statSync as statSync6 } from "fs";
13074
+ import { join as join35 } from "path";
12137
13075
  function analyzeLifecycle(projectPath, features, config2 = DEFAULT_LIFECYCLE_CONFIG, executor = new RealGitExecutor()) {
12138
13076
  const startTime = Date.now();
12139
13077
  const proposals = [];
@@ -12179,14 +13117,14 @@ function analyzeLifecycle(projectPath, features, config2 = DEFAULT_LIFECYCLE_CON
12179
13117
  }
12180
13118
  }
12181
13119
  const paths = getAgentWorkspacePaths(projectPath);
12182
- if (existsSync33(paths.featuresDir)) {
13120
+ if (existsSync34(paths.featuresDir)) {
12183
13121
  try {
12184
- const featureDirs = readdirSync11(paths.featuresDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
13122
+ const featureDirs = readdirSync12(paths.featuresDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
12185
13123
  const activeFeatureNames = new Set(features.map((f) => f.name));
12186
13124
  const cutoffDate = Date.now() - config2.pruneInactiveDays * 24 * 60 * 60 * 1e3;
12187
13125
  for (const dirName of featureDirs) {
12188
13126
  if (!activeFeatureNames.has(dirName)) {
12189
- const dirPath = join34(paths.featuresDir, dirName);
13127
+ const dirPath = join35(paths.featuresDir, dirName);
12190
13128
  const stat = statSync6(dirPath);
12191
13129
  if (stat.mtimeMs < cutoffDate) {
12192
13130
  proposals.push({
@@ -12234,8 +13172,8 @@ var init_lifecycle = __esm({
12234
13172
  });
12235
13173
 
12236
13174
  // src/core/agents/orchestrator.ts
12237
- import { existsSync as existsSync34, readFileSync as readFileSync27, readdirSync as readdirSync12 } from "fs";
12238
- import { join as join35, relative as relative9 } from "path";
13175
+ import { existsSync as existsSync35, readFileSync as readFileSync28, readdirSync as readdirSync13 } from "fs";
13176
+ import { join as join36, relative as relative9 } from "path";
12239
13177
  function agentsInit(projectPath) {
12240
13178
  const paths = initAgentWorkspace(projectPath);
12241
13179
  return {
@@ -12311,7 +13249,7 @@ async function agentsGenerate(options) {
12311
13249
  currentIndex.reResearchQueue = [];
12312
13250
  writeAgentIndex(projectPath, currentIndex);
12313
13251
  }
12314
- const intel = intelligence || createMinimalIntelligence(projectPath, technologies, features);
13252
+ const intel = intelligence || createMinimalIntelligence(projectPath, technologies, features, importGraph);
12315
13253
  const genInput = {
12316
13254
  projectPath,
12317
13255
  intelligence: intel,
@@ -12421,8 +13359,8 @@ function agentsStatus(projectPath) {
12421
13359
  const paths = getAgentWorkspacePaths(projectPath);
12422
13360
  let researchFiles = 0;
12423
13361
  let staleResearch = 0;
12424
- if (existsSync34(paths.researchDir)) {
12425
- const files = readdirSync12(paths.researchDir);
13362
+ if (existsSync35(paths.researchDir)) {
13363
+ const files = readdirSync13(paths.researchDir);
12426
13364
  researchFiles = files.filter((f) => f.endsWith(".md")).length;
12427
13365
  const now = Date.now();
12428
13366
  for (const [tech, timestamp] of Object.entries(index.lastResearch)) {
@@ -12455,10 +13393,10 @@ function getIndexedFilesFromFS(projectPath) {
12455
13393
  function walk(dir, depth) {
12456
13394
  if (depth > 5) return;
12457
13395
  try {
12458
- const entries = readdirSync12(dir, { withFileTypes: true });
13396
+ const entries = readdirSync13(dir, { withFileTypes: true });
12459
13397
  for (const entry of entries) {
12460
13398
  if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === "dist") continue;
12461
- const fullPath = join35(dir, entry.name);
13399
+ const fullPath = join36(dir, entry.name);
12462
13400
  if (entry.isDirectory()) {
12463
13401
  walk(fullPath, depth + 1);
12464
13402
  } else {
@@ -12492,7 +13430,7 @@ function filterTopTechnologies(technologies) {
12492
13430
  ];
12493
13431
  return technologies.filter((t) => !skipPatterns.some((p) => p.test(t.name))).filter((t) => t.source.includes("lock") || t.source === "package.json").slice(0, 20);
12494
13432
  }
12495
- function createMinimalIntelligence(projectPath, technologies, features) {
13433
+ function createMinimalIntelligence(projectPath, technologies, features, importGraph) {
12496
13434
  const sourceFiles = getIndexedFilesFromFS(projectPath);
12497
13435
  const codeFiles = sourceFiles.filter(
12498
13436
  (f) => /\.(ts|tsx|js|jsx|py|go|rs|java|rb|php|cs|cpp|c|h)$/.test(f) && !f.includes("node_modules") && !f.includes("dist")
@@ -12500,7 +13438,7 @@ function createMinimalIntelligence(projectPath, technologies, features) {
12500
13438
  let totalLines = 0;
12501
13439
  for (const f of codeFiles.slice(0, 500)) {
12502
13440
  try {
12503
- const content = readFileSync27(join35(projectPath, f), "utf-8");
13441
+ const content = readFileSync28(join36(projectPath, f), "utf-8");
12504
13442
  totalLines += content.split("\n").length;
12505
13443
  } catch {
12506
13444
  }
@@ -12515,7 +13453,7 @@ function createMinimalIntelligence(projectPath, technologies, features) {
12515
13453
  const layers = features.map((f) => ({
12516
13454
  name: f.name.charAt(0).toUpperCase() + f.name.slice(1),
12517
13455
  directory: f.paths[0]?.replace("/**", "") || f.name,
12518
- purpose: inferLayerPurpose(f.name),
13456
+ purpose: inferDirectoryPurpose(f.name),
12519
13457
  fileCount: f.fileCount
12520
13458
  }));
12521
13459
  const testFramework = detectTestFramework(projectPath);
@@ -12532,7 +13470,7 @@ function createMinimalIntelligence(projectPath, technologies, features) {
12532
13470
  },
12533
13471
  architecture: {
12534
13472
  layers,
12535
- dataFlow: inferDataFlow(features),
13473
+ dataFlow: inferDataFlowFromGraph(features, importGraph),
12536
13474
  keyComponents: [],
12537
13475
  patternCategories: {},
12538
13476
  topPatterns: [],
@@ -12563,7 +13501,7 @@ function buildFileTechMap(projectPath, indexedFiles, technologies) {
12563
13501
  );
12564
13502
  for (const file2 of sourceFiles.slice(0, 300)) {
12565
13503
  try {
12566
- const content = readFileSync27(join35(projectPath, file2), "utf-8");
13504
+ const content = readFileSync28(join36(projectPath, file2), "utf-8");
12567
13505
  const techs = /* @__PURE__ */ new Set();
12568
13506
  const importRegex = /(?:from\s+['"]|require\s*\(\s*['"])([^./'"@][^'"]*|@[^/'"]+\/[^'"]+)/g;
12569
13507
  let match;
@@ -12601,39 +13539,11 @@ function extToLanguage(ext) {
12601
13539
  };
12602
13540
  return map2[ext] || null;
12603
13541
  }
12604
- function inferLayerPurpose(featureName) {
12605
- const purposes = {
12606
- core: "Core business logic and domain modules",
12607
- server: "MCP server, transports, and request handling",
12608
- storage: "Database access and persistence layer",
12609
- indexing: "Code indexing, parsing, and symbol extraction",
12610
- api: "API routes, handlers, and middleware",
12611
- auth: "Authentication and authorization",
12612
- billing: "Payment processing and subscription management",
12613
- test: "Test fixtures, harness, and evaluation scenarios",
12614
- doc: "Documentation generation and management",
12615
- knowledge: "AI knowledge system and skill management",
12616
- cli: "Command-line interface",
12617
- base: "Base configuration and shared utilities"
12618
- };
12619
- return purposes[featureName] || `${featureName} module`;
12620
- }
12621
- function inferDataFlow(features) {
12622
- const names = features.map((f) => f.name);
12623
- const flow = [];
12624
- if (names.includes("server") || names.includes("api")) flow.push("Request");
12625
- if (names.includes("server")) flow.push("Server");
12626
- if (names.includes("api")) flow.push("API");
12627
- if (names.includes("core")) flow.push("Core");
12628
- if (names.includes("storage")) flow.push("Storage");
12629
- if (names.includes("indexing")) flow.push("Indexer");
12630
- return flow.length >= 2 ? flow : [];
12631
- }
12632
13542
  function detectTestFramework(projectPath) {
12633
- const pkgPath = join35(projectPath, "package.json");
12634
- if (existsSync34(pkgPath)) {
13543
+ const pkgPath = join36(projectPath, "package.json");
13544
+ if (existsSync35(pkgPath)) {
12635
13545
  try {
12636
- const pkg = JSON.parse(readFileSync27(pkgPath, "utf-8"));
13546
+ const pkg = JSON.parse(readFileSync28(pkgPath, "utf-8"));
12637
13547
  const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
12638
13548
  if (allDeps["vitest"]) return "vitest";
12639
13549
  if (allDeps["jest"]) return "jest";
@@ -12654,6 +13564,7 @@ var init_orchestrator = __esm({
12654
13564
  init_research_engine();
12655
13565
  init_generator();
12656
13566
  init_agent_generator();
13567
+ init_universal_inference();
12657
13568
  init_git_operations();
12658
13569
  init_improvement_engine();
12659
13570
  init_outcome_storage();
@@ -12663,8 +13574,8 @@ var init_orchestrator = __esm({
12663
13574
  });
12664
13575
 
12665
13576
  // src/core/agents/migration.ts
12666
- import { existsSync as existsSync35, readFileSync as readFileSync28, writeFileSync as writeFileSync20, mkdirSync as mkdirSync18, cpSync, readdirSync as readdirSync13 } from "fs";
12667
- import { join as join36, relative as relative10, dirname as dirname15 } from "path";
13577
+ import { existsSync as existsSync36, readFileSync as readFileSync29, writeFileSync as writeFileSync20, mkdirSync as mkdirSync18, cpSync, readdirSync as readdirSync14 } from "fs";
13578
+ import { join as join37, relative as relative10, dirname as dirname15 } from "path";
12668
13579
  function migrateKnowledge(options) {
12669
13580
  const { projectPath, dryRun = false, backup = false } = options;
12670
13581
  const result = {
@@ -12673,8 +13584,8 @@ function migrateKnowledge(options) {
12673
13584
  skipped: [],
12674
13585
  conflicts: []
12675
13586
  };
12676
- const knowledgeDir = join36(projectPath, "knowledge");
12677
- if (!existsSync35(knowledgeDir)) {
13587
+ const knowledgeDir = join37(projectPath, "knowledge");
13588
+ if (!existsSync36(knowledgeDir)) {
12678
13589
  result.skipped.push({ source: "knowledge/", reason: "Directory does not exist" });
12679
13590
  return result;
12680
13591
  }
@@ -12683,7 +13594,7 @@ function migrateKnowledge(options) {
12683
13594
  }
12684
13595
  const paths = getAgentWorkspacePaths(projectPath);
12685
13596
  if (backup && !dryRun) {
12686
- const backupDir = join36(projectPath, `knowledge-backup-${Date.now()}`);
13597
+ const backupDir = join37(projectPath, `knowledge-backup-${Date.now()}`);
12687
13598
  cpSync(knowledgeDir, backupDir, { recursive: true });
12688
13599
  result.backupDir = backupDir;
12689
13600
  }
@@ -12696,7 +13607,7 @@ function migrateKnowledge(options) {
12696
13607
  continue;
12697
13608
  }
12698
13609
  const targetPath = resolveTargetPath(paths, classification);
12699
- if (existsSync35(targetPath) && !dryRun) {
13610
+ if (existsSync36(targetPath) && !dryRun) {
12700
13611
  const merged = mergeSkills(skillFile, targetPath);
12701
13612
  if (merged) {
12702
13613
  result.conflicts.push({ source: relPath, target: relative10(projectPath, targetPath), resolution: "merged" });
@@ -12720,10 +13631,10 @@ function migrateKnowledge(options) {
12720
13631
  function discoverSkillFiles(dir) {
12721
13632
  const files = [];
12722
13633
  function walk(current) {
12723
- if (!existsSync35(current)) return;
12724
- const entries = readdirSync13(current, { withFileTypes: true });
13634
+ if (!existsSync36(current)) return;
13635
+ const entries = readdirSync14(current, { withFileTypes: true });
12725
13636
  for (const entry of entries) {
12726
- const fullPath = join36(current, entry.name);
13637
+ const fullPath = join37(current, entry.name);
12727
13638
  if (entry.isDirectory()) {
12728
13639
  walk(fullPath);
12729
13640
  } else if (entry.name === "SKILL.md" || entry.name.endsWith(".skill.md")) {
@@ -12760,19 +13671,19 @@ function classifySkillPath(relPath) {
12760
13671
  function resolveTargetPath(paths, classification) {
12761
13672
  switch (classification.type) {
12762
13673
  case "technology":
12763
- return join36(paths.projectDir, `${classification.name}-SKILL.md`);
13674
+ return join37(paths.projectDir, `${classification.name}-SKILL.md`);
12764
13675
  case "feature":
12765
- return join36(paths.featuresDir, classification.name, "SKILL.md");
13676
+ return join37(paths.featuresDir, classification.name, "SKILL.md");
12766
13677
  case "project":
12767
- return join36(paths.projectDir, "SKILL.md");
13678
+ return join37(paths.projectDir, "SKILL.md");
12768
13679
  default:
12769
- return join36(paths.projectDir, `${classification.name}-SKILL.md`);
13680
+ return join37(paths.projectDir, `${classification.name}-SKILL.md`);
12770
13681
  }
12771
13682
  }
12772
13683
  function mergeSkills(sourcePath, targetPath) {
12773
13684
  try {
12774
- const sourceContent = readFileSync28(sourcePath, "utf-8");
12775
- const targetContent = readFileSync28(targetPath, "utf-8");
13685
+ const sourceContent = readFileSync29(sourcePath, "utf-8");
13686
+ const targetContent = readFileSync29(targetPath, "utf-8");
12776
13687
  const sourceRules = extractSection2(sourceContent, "Rules");
12777
13688
  const sourcePitfalls = extractSection2(sourceContent, "Pitfalls");
12778
13689
  if (!sourceRules && !sourcePitfalls) return false;
@@ -12835,9 +13746,16 @@ __export(agents_exports, {
12835
13746
  DEFAULT_OUTPUT_DIR: () => DEFAULT_OUTPUT_DIR,
12836
13747
  DEFAULT_TRUST_CONFIG: () => DEFAULT_TRUST_CONFIG,
12837
13748
  DIAGNOSIS_RULES: () => DIAGNOSIS_RULES,
13749
+ DIR_PURPOSE_MAP: () => DIR_PURPOSE_MAP,
13750
+ DOC_SOURCE_REGISTRY: () => DOC_SOURCE_REGISTRY,
13751
+ FEATURE_NAME_PITFALLS: () => FEATURE_NAME_PITFALLS,
13752
+ FEATURE_NAME_RULES: () => FEATURE_NAME_RULES,
12838
13753
  MockGitExecutor: () => MockGitExecutor,
12839
13754
  RealGitExecutor: () => RealGitExecutor,
13755
+ SCOPE_LABELS: () => SCOPE_LABELS,
12840
13756
  SECTION_PRIORITIES: () => SECTION_PRIORITIES,
13757
+ TECH_KNOWLEDGE: () => TECH_KNOWLEDGE,
13758
+ WELL_KNOWN_FEATURES: () => WELL_KNOWN_FEATURES,
12841
13759
  agentWorkspaceExists: () => agentWorkspaceExists,
12842
13760
  agentsGenerate: () => agentsGenerate,
12843
13761
  agentsInit: () => agentsInit,
@@ -12845,6 +13763,8 @@ __export(agents_exports, {
12845
13763
  analyzeCoChanges: () => analyzeCoChanges,
12846
13764
  analyzeLifecycle: () => analyzeLifecycle,
12847
13765
  assessTrust: () => assessTrust,
13766
+ classifyFeature: () => classifyFeature,
13767
+ classifyTechnology: () => classifyTechnology,
12848
13768
  commitAndPush: () => commitAndPush,
12849
13769
  commitChanges: () => commitChanges,
12850
13770
  computeContentHash: () => computeContentHash,
@@ -12856,6 +13776,8 @@ __export(agents_exports, {
12856
13776
  createOutcomeTable: () => createOutcomeTable,
12857
13777
  createTelemetryTable: () => createTelemetryTable,
12858
13778
  decayOldLessons: () => decayOldLessons,
13779
+ deriveFeaturePitfalls: () => deriveFeaturePitfalls,
13780
+ deriveFeatureRules: () => deriveFeatureRules,
12859
13781
  detectFeatures: () => detectFeatures,
12860
13782
  detectMonorepo: () => detectMonorepo,
12861
13783
  detectProvider: () => detectProvider,
@@ -12868,6 +13790,7 @@ __export(agents_exports, {
12868
13790
  ensureFeatureDir: () => ensureFeatureDir,
12869
13791
  estimateTokens: () => estimateTokens6,
12870
13792
  extractManualContent: () => extractManualContent,
13793
+ extractRulesFromResearch: () => extractRulesFromResearch,
12871
13794
  findMergeCandidates: () => findMergeCandidates,
12872
13795
  generateAgentFiles: () => generateAgentFiles,
12873
13796
  generateAgentsShim: () => generateAgentsShim,
@@ -12884,6 +13807,11 @@ __export(agents_exports, {
12884
13807
  getResearchContent: () => getResearchContent,
12885
13808
  getSectionPriority: () => getSectionPriority,
12886
13809
  hasChanges: () => hasChanges,
13810
+ inferDataFlowFromGraph: () => inferDataFlowFromGraph,
13811
+ inferDirectoryPurpose: () => inferDirectoryPurpose,
13812
+ inferDocSource: () => inferDocSource,
13813
+ inferScopeLabel: () => inferScopeLabel,
13814
+ inferTechRulesAndPitfalls: () => inferTechRulesAndPitfalls,
12887
13815
  initAgentWorkspace: () => initAgentWorkspace,
12888
13816
  isGitRepo: () => isGitRepo,
12889
13817
  learnFromOutcome: () => learnFromOutcome,
@@ -12929,6 +13857,8 @@ var init_agents = __esm({
12929
13857
  init_co_change_analyzer();
12930
13858
  init_lifecycle();
12931
13859
  init_telemetry();
13860
+ init_hardcoded_knowledge();
13861
+ init_universal_inference();
12932
13862
  }
12933
13863
  });
12934
13864
 
@@ -27397,8 +28327,21 @@ var EXCLUDED_PATH_PATTERNS = [
27397
28327
  ".pytest_cache",
27398
28328
  "vendor/",
27399
28329
  ".venv/",
27400
- "venv/"
28330
+ "venv/",
28331
+ "env/",
28332
+ "knowledge/"
27401
28333
  ];
28334
+ function PATH_EXCLUSION_SQL(col = "path") {
28335
+ return `${col} NOT LIKE '%node_modules%'
28336
+ AND ${col} NOT LIKE '%.git%'
28337
+ AND ${col} NOT LIKE '%/dist/%'
28338
+ AND ${col} NOT LIKE '%/build/%'
28339
+ AND ${col} NOT LIKE '%/venv/%'
28340
+ AND ${col} NOT LIKE '%/.venv/%'
28341
+ AND ${col} NOT LIKE '%/env/%'
28342
+ AND ${col} NOT LIKE '%__pycache__%'
28343
+ AND ${col} NOT LIKE '%/knowledge/%'`;
28344
+ }
27402
28345
  var Tier2Storage = class {
27403
28346
  db;
27404
28347
  constructor(db) {
@@ -27455,10 +28398,7 @@ var Tier2Storage = class {
27455
28398
  size_bytes as sizeBytes, line_count as lineCount,
27456
28399
  last_modified as lastModified, indexed_at as indexedAt
27457
28400
  FROM files
27458
- WHERE path NOT LIKE '%node_modules%'
27459
- AND path NOT LIKE '%.git%'
27460
- AND path NOT LIKE '%/dist/%'
27461
- AND path NOT LIKE '%/build/%'
28401
+ WHERE ${PATH_EXCLUSION_SQL("path")}
27462
28402
  ORDER BY path
27463
28403
  `);
27464
28404
  return stmt.all();
@@ -27466,10 +28406,7 @@ var Tier2Storage = class {
27466
28406
  getFileCount() {
27467
28407
  const stmt = this.db.prepare(`
27468
28408
  SELECT COUNT(*) as count FROM files
27469
- WHERE path NOT LIKE '%node_modules%'
27470
- AND path NOT LIKE '%.git%'
27471
- AND path NOT LIKE '%/dist/%'
27472
- AND path NOT LIKE '%/build/%'
28409
+ WHERE ${PATH_EXCLUSION_SQL("path")}
27473
28410
  `);
27474
28411
  const result = stmt.get();
27475
28412
  return result.count;
@@ -27477,10 +28414,7 @@ var Tier2Storage = class {
27477
28414
  getTotalLines() {
27478
28415
  const stmt = this.db.prepare(`
27479
28416
  SELECT COALESCE(SUM(line_count), 0) as total FROM files
27480
- WHERE path NOT LIKE '%node_modules%'
27481
- AND path NOT LIKE '%.git%'
27482
- AND path NOT LIKE '%/dist/%'
27483
- AND path NOT LIKE '%/build/%'
28417
+ WHERE ${PATH_EXCLUSION_SQL("path")}
27484
28418
  `);
27485
28419
  const result = stmt.get();
27486
28420
  return result.total;
@@ -27489,10 +28423,7 @@ var Tier2Storage = class {
27489
28423
  const stmt = this.db.prepare(`
27490
28424
  SELECT DISTINCT language FROM files
27491
28425
  WHERE language IS NOT NULL
27492
- AND path NOT LIKE '%node_modules%'
27493
- AND path NOT LIKE '%.git%'
27494
- AND path NOT LIKE '%/dist/%'
27495
- AND path NOT LIKE '%/build/%'
28426
+ AND ${PATH_EXCLUSION_SQL("path")}
27496
28427
  ORDER BY language
27497
28428
  `);
27498
28429
  const results = stmt.all();
@@ -27830,10 +28761,7 @@ var Tier2Storage = class {
27830
28761
  FROM symbols s
27831
28762
  JOIN files f ON s.file_id = f.id
27832
28763
  WHERE s.name LIKE ?
27833
- AND f.path NOT LIKE '%node_modules%'
27834
- AND f.path NOT LIKE '%.git%'
27835
- AND f.path NOT LIKE '%/dist/%'
27836
- AND f.path NOT LIKE '%/build/%'
28764
+ AND ${PATH_EXCLUSION_SQL("f.path")}
27837
28765
  `;
27838
28766
  const params = [`%${name}%`];
27839
28767
  if (kind) {
@@ -27864,10 +28792,7 @@ var Tier2Storage = class {
27864
28792
  FROM symbols s
27865
28793
  JOIN files f ON s.file_id = f.id
27866
28794
  WHERE s.name = ?
27867
- AND f.path NOT LIKE '%node_modules%'
27868
- AND f.path NOT LIKE '%.git%'
27869
- AND f.path NOT LIKE '%/dist/%'
27870
- AND f.path NOT LIKE '%/build/%'
28795
+ AND ${PATH_EXCLUSION_SQL("f.path")}
27871
28796
  `;
27872
28797
  const params = [name];
27873
28798
  if (kind) {
@@ -27895,10 +28820,7 @@ var Tier2Storage = class {
27895
28820
  const stmt = this.db.prepare(`
27896
28821
  SELECT COUNT(*) as count FROM symbols s
27897
28822
  JOIN files f ON s.file_id = f.id
27898
- WHERE f.path NOT LIKE '%node_modules%'
27899
- AND f.path NOT LIKE '%.git%'
27900
- AND f.path NOT LIKE '%/dist/%'
27901
- AND f.path NOT LIKE '%/build/%'
28823
+ WHERE ${PATH_EXCLUSION_SQL("f.path")}
27902
28824
  `);
27903
28825
  const result = stmt.get();
27904
28826
  return result.count;
@@ -28010,10 +28932,7 @@ var Tier2Storage = class {
28010
28932
  e.local_name as localName, e.is_default as isDefault, e.line_number as lineNumber
28011
28933
  FROM exports e
28012
28934
  JOIN files f ON e.file_id = f.id
28013
- WHERE f.path NOT LIKE '%node_modules%'
28014
- AND f.path NOT LIKE '%.git%'
28015
- AND f.path NOT LIKE '%/dist/%'
28016
- AND f.path NOT LIKE '%/build/%'
28935
+ WHERE ${PATH_EXCLUSION_SQL("f.path")}
28017
28936
  ORDER BY f.path, e.line_number
28018
28937
  `);
28019
28938
  const rows = stmt.all();
@@ -28037,10 +28956,7 @@ var Tier2Storage = class {
28037
28956
  i.is_namespace as isNamespace, i.line_number as lineNumber
28038
28957
  FROM imports i
28039
28958
  JOIN files f ON i.file_id = f.id
28040
- WHERE f.path NOT LIKE '%node_modules%'
28041
- AND f.path NOT LIKE '%.git%'
28042
- AND f.path NOT LIKE '%/dist/%'
28043
- AND f.path NOT LIKE '%/build/%'
28959
+ WHERE ${PATH_EXCLUSION_SQL("f.path")}
28044
28960
  ORDER BY f.path, i.line_number
28045
28961
  `);
28046
28962
  const rows = stmt.all();
@@ -28244,12 +29160,69 @@ var Tier2Storage = class {
28244
29160
  );
28245
29161
  return result?.path || null;
28246
29162
  }
29163
+ // Cached path aliases from tsconfig/jsconfig
29164
+ pathAliases = null;
29165
+ /**
29166
+ * Load path aliases from tsconfig.json/jsconfig.json.
29167
+ * Caches result for subsequent calls.
29168
+ */
29169
+ getPathAliases(projectPath) {
29170
+ if (this.pathAliases) return this.pathAliases;
29171
+ this.pathAliases = /* @__PURE__ */ new Map();
29172
+ const commonAliases = {
29173
+ "@": "src",
29174
+ "~": "src",
29175
+ "#": "src"
29176
+ };
29177
+ for (const [alias, target] of Object.entries(commonAliases)) {
29178
+ this.pathAliases.set(alias, target);
29179
+ }
29180
+ if (projectPath) {
29181
+ const { existsSync: existsSync38, readFileSync: readFileSync31 } = __require("fs");
29182
+ const { join: join39 } = __require("path");
29183
+ for (const configFile of ["tsconfig.json", "jsconfig.json"]) {
29184
+ const configPath = join39(projectPath, configFile);
29185
+ if (existsSync38(configPath)) {
29186
+ try {
29187
+ const raw = readFileSync31(configPath, "utf-8").replace(/\/\/.*$/gm, "").replace(/\/\*[\s\S]*?\*\//g, "");
29188
+ const config2 = JSON.parse(raw);
29189
+ const baseUrl = config2.compilerOptions?.baseUrl || ".";
29190
+ if (config2.compilerOptions?.paths) {
29191
+ for (const [alias, targets] of Object.entries(config2.compilerOptions.paths)) {
29192
+ const aliasKey = alias.replace("/*", "").replace("*", "");
29193
+ const target = targets[0];
29194
+ if (target) {
29195
+ const targetPath = target.replace("/*", "").replace("*", "").replace("./", "");
29196
+ const resolved = baseUrl === "." ? targetPath : `${baseUrl}/${targetPath}`;
29197
+ this.pathAliases.set(aliasKey, resolved);
29198
+ }
29199
+ }
29200
+ }
29201
+ break;
29202
+ } catch {
29203
+ }
29204
+ }
29205
+ }
29206
+ }
29207
+ return this.pathAliases;
29208
+ }
28247
29209
  /**
28248
29210
  * Resolve an import path to a file record in the database.
28249
29211
  * Used by indexer to build the dependencies table.
28250
29212
  */
28251
- resolveImportToFile(sourceFilePath, importPath) {
28252
- if (!importPath.startsWith(".") && !importPath.startsWith("/")) return null;
29213
+ resolveImportToFile(sourceFilePath, importPath, projectPath) {
29214
+ if (!importPath.startsWith(".") && !importPath.startsWith("/")) {
29215
+ const aliases = this.getPathAliases(projectPath);
29216
+ let resolved2 = false;
29217
+ for (const [alias, target] of aliases) {
29218
+ if (importPath === alias || importPath.startsWith(alias + "/")) {
29219
+ importPath = importPath.replace(alias, target);
29220
+ resolved2 = true;
29221
+ break;
29222
+ }
29223
+ }
29224
+ if (!resolved2) return null;
29225
+ }
28253
29226
  const sourceDir = sourceFilePath.split(/[/\\]/).slice(0, -1).join("/");
28254
29227
  let resolved = importPath;
28255
29228
  if (importPath.startsWith("./")) {
@@ -29570,7 +30543,7 @@ var Indexer = class extends EventEmitter2 {
29570
30543
  language,
29571
30544
  stats.size,
29572
30545
  lineCount,
29573
- Math.floor(stats.mtimeMs)
30546
+ Math.floor(stats.mtimeMs / 1e3)
29574
30547
  );
29575
30548
  const embedding = await this.embeddingGenerator.embed(content);
29576
30549
  this.tier2.upsertEmbedding(fileId, embedding);
@@ -29595,7 +30568,7 @@ var Indexer = class extends EventEmitter2 {
29595
30568
  if (parsed.imports.length > 0) {
29596
30569
  this.tier2.clearDependencies(fileId);
29597
30570
  for (const imp of parsed.imports) {
29598
- const targetFile = this.tier2.resolveImportToFile(relativePath, imp.importedFrom);
30571
+ const targetFile = this.tier2.resolveImportToFile(relativePath, imp.importedFrom, this.config.projectPath);
29599
30572
  if (targetFile) {
29600
30573
  this.tier2.addDependency(fileId, targetFile.id, "imports");
29601
30574
  }
@@ -30114,7 +31087,18 @@ ${body}`.trim();
30114
31087
  async extractFromComments() {
30115
31088
  const decisions = [];
30116
31089
  const patterns = ["**/*.ts", "**/*.js", "**/*.py", "**/*.go", "**/*.java", "**/*.rs"];
30117
- const ignorePatterns = ["**/node_modules/**", "**/.git/**", "**/dist/**", "**/build/**"];
31090
+ const ignorePatterns = [
31091
+ "**/node_modules/**",
31092
+ "**/.git/**",
31093
+ "**/dist/**",
31094
+ "**/build/**",
31095
+ "**/venv/**",
31096
+ "**/.venv/**",
31097
+ "**/env/**",
31098
+ "**/__pycache__/**",
31099
+ "**/vendor/**",
31100
+ "**/knowledge/**"
31101
+ ];
30118
31102
  for (const pattern of patterns) {
30119
31103
  try {
30120
31104
  const files = await glob2(pattern, {
@@ -30165,7 +31149,7 @@ ${body}`.trim();
30165
31149
  try {
30166
31150
  const files = await glob2(pattern, {
30167
31151
  cwd: this.projectPath,
30168
- ignore: ["**/node_modules/**"],
31152
+ ignore: ["**/node_modules/**", "**/venv/**", "**/.venv/**", "**/env/**", "**/knowledge/**"],
30169
31153
  absolute: true,
30170
31154
  nodir: true
30171
31155
  });
@@ -31017,6 +32001,12 @@ var ProjectManager = class {
31017
32001
  "**/build/**",
31018
32002
  "**/.next/**",
31019
32003
  "**/coverage/**",
32004
+ "**/venv/**",
32005
+ "**/.venv/**",
32006
+ "**/env/**",
32007
+ "**/__pycache__/**",
32008
+ "**/vendor/**",
32009
+ "**/knowledge/**",
31020
32010
  "**/*.min.js",
31021
32011
  "**/*.min.css",
31022
32012
  "**/*.map",
@@ -31291,8 +32281,8 @@ ${decision.files.map((f) => `- \`${f}\``).join("\n")}
31291
32281
  getExistingADRFiles(dir) {
31292
32282
  if (!existsSync6(dir)) return [];
31293
32283
  try {
31294
- const { readdirSync: readdirSync14 } = __require("fs");
31295
- return readdirSync14(dir).filter((f) => /^\d{4}-.*\.md$/.test(f)).sort();
32284
+ const { readdirSync: readdirSync15 } = __require("fs");
32285
+ return readdirSync15(dir).filter((f) => /^\d{4}-.*\.md$/.test(f)).sort();
31296
32286
  } catch {
31297
32287
  return [];
31298
32288
  }
@@ -33628,8 +34618,11 @@ ${decisionList}
33628
34618
  const rows = this.db.prepare(
33629
34619
  `SELECT path FROM files WHERE language IS NOT NULL`
33630
34620
  ).all();
34621
+ const excludeDirs = ["knowledge/", ".code-impact/", "node_modules/", "venv/", ".venv/", "env/", "__pycache__/"];
33631
34622
  for (const row of rows) {
33632
- const parts = row.path.replace(/\\/g, "/").split("/");
34623
+ const normalized = row.path.replace(/\\/g, "/");
34624
+ if (excludeDirs.some((d) => normalized.includes(d))) continue;
34625
+ const parts = normalized.split("/");
33633
34626
  if (parts.length < 2) continue;
33634
34627
  const dir = parts.slice(0, -1).join("/");
33635
34628
  const existing = groups.get(dir) || [];
@@ -40423,6 +41416,7 @@ var CodeVerifier = class {
40423
41416
  this.nodeModulesPath = join15(projectPath, "node_modules");
40424
41417
  this.loadPackageJson();
40425
41418
  }
41419
+ subPackageJsons = [];
40426
41420
  loadPackageJson() {
40427
41421
  const packageJsonPath = join15(this.projectPath, "package.json");
40428
41422
  if (existsSync16(packageJsonPath)) {
@@ -40432,6 +41426,16 @@ var CodeVerifier = class {
40432
41426
  this.packageJson = null;
40433
41427
  }
40434
41428
  }
41429
+ const subDirs = ["frontend", "backend", "client", "server", "web", "app", "packages"];
41430
+ for (const sub of subDirs) {
41431
+ const subPath = join15(this.projectPath, sub, "package.json");
41432
+ if (existsSync16(subPath)) {
41433
+ try {
41434
+ this.subPackageJsons.push(JSON.parse(readFileSync12(subPath, "utf-8")));
41435
+ } catch {
41436
+ }
41437
+ }
41438
+ }
40435
41439
  }
40436
41440
  /**
40437
41441
  * Run full verification on code
@@ -40819,15 +41823,17 @@ var CodeVerifier = class {
40819
41823
  }
40820
41824
  getPackageDependencies() {
40821
41825
  const deps = /* @__PURE__ */ new Set();
40822
- if (!this.packageJson) return deps;
40823
- const allDeps = {
40824
- ...this.packageJson.dependencies || {},
40825
- ...this.packageJson.devDependencies || {},
40826
- ...this.packageJson.peerDependencies || {},
40827
- ...this.packageJson.optionalDependencies || {}
40828
- };
40829
- for (const pkg of Object.keys(allDeps)) {
40830
- deps.add(pkg);
41826
+ const pkgs = this.packageJson ? [this.packageJson, ...this.subPackageJsons] : this.subPackageJsons;
41827
+ for (const pkg of pkgs) {
41828
+ const allDeps = {
41829
+ ...pkg.dependencies || {},
41830
+ ...pkg.devDependencies || {},
41831
+ ...pkg.peerDependencies || {},
41832
+ ...pkg.optionalDependencies || {}
41833
+ };
41834
+ for (const name of Object.keys(allDeps)) {
41835
+ deps.add(name);
41836
+ }
40831
41837
  }
40832
41838
  return deps;
40833
41839
  }
@@ -43758,12 +44764,12 @@ var SkillEvolutionEngine = class {
43758
44764
  }
43759
44765
  }
43760
44766
  findSkillFile(dir, skillId) {
43761
- const { readdirSync: readdirSync14, statSync: statSync8 } = __require("fs");
43762
- const { join: join38 } = __require("path");
44767
+ const { readdirSync: readdirSync15, statSync: statSync8 } = __require("fs");
44768
+ const { join: join39 } = __require("path");
43763
44769
  if (!existsSync20(dir)) return null;
43764
- const entries = readdirSync14(dir);
44770
+ const entries = readdirSync15(dir);
43765
44771
  for (const entry of entries) {
43766
- const fullPath = join38(dir, entry);
44772
+ const fullPath = join39(dir, entry);
43767
44773
  const stat = statSync8(fullPath);
43768
44774
  if (stat.isDirectory()) {
43769
44775
  const found = this.findSkillFile(fullPath, skillId);
@@ -49200,8 +50206,8 @@ init_research_engine();
49200
50206
  init_outcome_storage();
49201
50207
  init_improvement_engine();
49202
50208
  init_telemetry();
49203
- import { existsSync as existsSync27, readFileSync as readFileSync22, readdirSync as readdirSync9, writeFileSync as writeFileSync17 } from "fs";
49204
- import { join as join27 } from "path";
50209
+ import { existsSync as existsSync28, readFileSync as readFileSync23, readdirSync as readdirSync10, writeFileSync as writeFileSync17 } from "fs";
50210
+ import { join as join28 } from "path";
49205
50211
  async function handleMemoryAgents(engine, input) {
49206
50212
  const projectPath = engine.getProjectPath();
49207
50213
  if (!agentWorkspaceExists(projectPath)) {
@@ -49242,34 +50248,34 @@ function handleListSkills(projectPath, input) {
49242
50248
  if (!input.scope || input.scope === "project") {
49243
50249
  const projectFiles = ["SKILL.md", "CONVENTIONS.md", "ARCHITECTURE.md"];
49244
50250
  for (const file2 of projectFiles) {
49245
- const filePath = join27(paths.projectDir, file2);
49246
- if (existsSync27(filePath)) {
50251
+ const filePath = join28(paths.projectDir, file2);
50252
+ if (existsSync28(filePath)) {
49247
50253
  skills.push({ name: file2.replace(".md", "").toLowerCase(), type: "project", path: `project/${file2}`, source: ".code-impact" });
49248
50254
  }
49249
50255
  }
49250
50256
  }
49251
50257
  if (!input.scope || input.scope === "feature") {
49252
- if (existsSync27(paths.featuresDir)) {
49253
- const features = readdirSync9(paths.featuresDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
50258
+ if (existsSync28(paths.featuresDir)) {
50259
+ const features = readdirSync10(paths.featuresDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
49254
50260
  for (const feature of features) {
49255
50261
  if (input.feature && feature !== input.feature) continue;
49256
- const skillPath = join27(paths.featuresDir, feature, "SKILL.md");
49257
- if (existsSync27(skillPath)) {
50262
+ const skillPath = join28(paths.featuresDir, feature, "SKILL.md");
50263
+ if (existsSync28(skillPath)) {
49258
50264
  skills.push({ name: `${feature}-skill`, type: "feature", path: `features/${feature}/SKILL.md`, source: ".code-impact" });
49259
50265
  }
49260
50266
  }
49261
50267
  }
49262
50268
  }
49263
- const legacySkillsDir = join27(projectPath, "knowledge", "skills");
49264
- if (existsSync27(legacySkillsDir)) {
50269
+ const legacySkillsDir = join28(projectPath, "knowledge", "skills");
50270
+ if (existsSync28(legacySkillsDir)) {
49265
50271
  try {
49266
50272
  for (const scope of ["technology", "feature", "core", "risk"]) {
49267
- const scopeDir = join27(legacySkillsDir, scope);
49268
- if (!existsSync27(scopeDir)) continue;
49269
- const skillDirs = readdirSync9(scopeDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
50273
+ const scopeDir = join28(legacySkillsDir, scope);
50274
+ if (!existsSync28(scopeDir)) continue;
50275
+ const skillDirs = readdirSync10(scopeDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
49270
50276
  for (const skillName of skillDirs) {
49271
- const skillPath = join27(scopeDir, skillName, "SKILL.md");
49272
- if (existsSync27(skillPath)) {
50277
+ const skillPath = join28(scopeDir, skillName, "SKILL.md");
50278
+ if (existsSync28(skillPath)) {
49273
50279
  const alreadyListed = skills.some((s) => s.name === skillName || s.name === `${skillName}-skill`);
49274
50280
  if (!alreadyListed) {
49275
50281
  skills.push({
@@ -49295,9 +50301,9 @@ function handleListSkills(projectPath, input) {
49295
50301
  function handleListAgents(projectPath) {
49296
50302
  const paths = getAgentWorkspacePaths(projectPath);
49297
50303
  const agents = [];
49298
- const superAgentPath = join27(paths.projectDir, "AGENT.md");
49299
- if (existsSync27(superAgentPath)) {
49300
- const content = readFileSync22(superAgentPath, "utf-8");
50304
+ const superAgentPath = join28(paths.projectDir, "AGENT.md");
50305
+ if (existsSync28(superAgentPath)) {
50306
+ const content = readFileSync23(superAgentPath, "utf-8");
49301
50307
  const agent = parseAgentMd(content);
49302
50308
  if (agent) {
49303
50309
  agents.push({
@@ -49308,12 +50314,12 @@ function handleListAgents(projectPath) {
49308
50314
  });
49309
50315
  }
49310
50316
  }
49311
- if (existsSync27(paths.featuresDir)) {
49312
- const features = readdirSync9(paths.featuresDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
50317
+ if (existsSync28(paths.featuresDir)) {
50318
+ const features = readdirSync10(paths.featuresDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
49313
50319
  for (const feature of features) {
49314
- const agentPath = join27(paths.featuresDir, feature, "AGENT.md");
49315
- if (existsSync27(agentPath)) {
49316
- const content = readFileSync22(agentPath, "utf-8");
50320
+ const agentPath = join28(paths.featuresDir, feature, "AGENT.md");
50321
+ if (existsSync28(agentPath)) {
50322
+ const content = readFileSync23(agentPath, "utf-8");
49317
50323
  const agent = parseAgentMd(content);
49318
50324
  if (agent) {
49319
50325
  agents.push({
@@ -49338,32 +50344,32 @@ function handleGetSkill(projectPath, input) {
49338
50344
  return { success: false, action: "get_skill", message: "Missing required parameter: name" };
49339
50345
  }
49340
50346
  const paths = getAgentWorkspacePaths(projectPath);
49341
- const projectFile = join27(paths.projectDir, `${input.name.toUpperCase()}.md`);
49342
- if (existsSync27(projectFile)) {
50347
+ const projectFile = join28(paths.projectDir, `${input.name.toUpperCase()}.md`);
50348
+ if (existsSync28(projectFile)) {
49343
50349
  return {
49344
50350
  success: true,
49345
50351
  action: "get_skill",
49346
50352
  message: `Found project skill: ${input.name}`,
49347
- data: { content: readFileSync22(projectFile, "utf-8"), path: `project/${input.name.toUpperCase()}.md` }
50353
+ data: { content: readFileSync23(projectFile, "utf-8"), path: `project/${input.name.toUpperCase()}.md` }
49348
50354
  };
49349
50355
  }
49350
- const skillFile = join27(paths.projectDir, "SKILL.md");
49351
- if (input.name === "project-overview" && existsSync27(skillFile)) {
50356
+ const skillFile = join28(paths.projectDir, "SKILL.md");
50357
+ if (input.name === "project-overview" && existsSync28(skillFile)) {
49352
50358
  return {
49353
50359
  success: true,
49354
50360
  action: "get_skill",
49355
50361
  message: "Found project skill",
49356
- data: { content: readFileSync22(skillFile, "utf-8"), path: "project/SKILL.md" }
50362
+ data: { content: readFileSync23(skillFile, "utf-8"), path: "project/SKILL.md" }
49357
50363
  };
49358
50364
  }
49359
50365
  const featureName = input.name.replace(/-skill$/, "").replace(/-feature$/, "");
49360
- const featureSkill = join27(paths.featuresDir, featureName, "SKILL.md");
49361
- if (existsSync27(featureSkill)) {
50366
+ const featureSkill = join28(paths.featuresDir, featureName, "SKILL.md");
50367
+ if (existsSync28(featureSkill)) {
49362
50368
  return {
49363
50369
  success: true,
49364
50370
  action: "get_skill",
49365
50371
  message: `Found feature skill: ${featureName}`,
49366
- data: { content: readFileSync22(featureSkill, "utf-8"), path: `features/${featureName}/SKILL.md` }
50372
+ data: { content: readFileSync23(featureSkill, "utf-8"), path: `features/${featureName}/SKILL.md` }
49367
50373
  };
49368
50374
  }
49369
50375
  return { success: false, action: "get_skill", message: `Skill not found: ${input.name}` };
@@ -49374,9 +50380,9 @@ function handleGetAgent(projectPath, input) {
49374
50380
  }
49375
50381
  const paths = getAgentWorkspacePaths(projectPath);
49376
50382
  if (input.name === "project-coordinator") {
49377
- const superPath = join27(paths.projectDir, "AGENT.md");
49378
- if (existsSync27(superPath)) {
49379
- const content = readFileSync22(superPath, "utf-8");
50383
+ const superPath = join28(paths.projectDir, "AGENT.md");
50384
+ if (existsSync28(superPath)) {
50385
+ const content = readFileSync23(superPath, "utf-8");
49380
50386
  const agent = parseAgentMd(content);
49381
50387
  return {
49382
50388
  success: true,
@@ -49387,9 +50393,9 @@ function handleGetAgent(projectPath, input) {
49387
50393
  }
49388
50394
  }
49389
50395
  const featureName = input.name.replace(/-agent$/, "");
49390
- const agentPath = join27(paths.featuresDir, featureName, "AGENT.md");
49391
- if (existsSync27(agentPath)) {
49392
- const content = readFileSync22(agentPath, "utf-8");
50396
+ const agentPath = join28(paths.featuresDir, featureName, "AGENT.md");
50397
+ if (existsSync28(agentPath)) {
50398
+ const content = readFileSync23(agentPath, "utf-8");
49393
50399
  const agent = parseAgentMd(content);
49394
50400
  return {
49395
50401
  success: true,
@@ -49422,15 +50428,15 @@ function handleValidateAction(projectPath, input) {
49422
50428
  const paths = getAgentWorkspacePaths(projectPath);
49423
50429
  let agentDef = null;
49424
50430
  if (input.agent === "project-coordinator") {
49425
- const superPath = join27(paths.projectDir, "AGENT.md");
49426
- if (existsSync27(superPath)) {
49427
- agentDef = parseAgentMd(readFileSync22(superPath, "utf-8"));
50431
+ const superPath = join28(paths.projectDir, "AGENT.md");
50432
+ if (existsSync28(superPath)) {
50433
+ agentDef = parseAgentMd(readFileSync23(superPath, "utf-8"));
49428
50434
  }
49429
50435
  } else {
49430
50436
  const featureName = input.agent.replace(/-agent$/, "");
49431
- const agentPath = join27(paths.featuresDir, featureName, "AGENT.md");
49432
- if (existsSync27(agentPath)) {
49433
- agentDef = parseAgentMd(readFileSync22(agentPath, "utf-8"));
50437
+ const agentPath = join28(paths.featuresDir, featureName, "AGENT.md");
50438
+ if (existsSync28(agentPath)) {
50439
+ agentDef = parseAgentMd(readFileSync23(agentPath, "utf-8"));
49434
50440
  }
49435
50441
  }
49436
50442
  if (!agentDef) {
@@ -49531,11 +50537,11 @@ function handleProposeImprovement(projectPath, input) {
49531
50537
  createdAt: (/* @__PURE__ */ new Date()).toISOString()
49532
50538
  };
49533
50539
  const paths = getAgentWorkspacePaths(projectPath);
49534
- const proposalsPath = join27(paths.root, "proposals.json");
50540
+ const proposalsPath = join28(paths.root, "proposals.json");
49535
50541
  let proposals = [];
49536
- if (existsSync27(proposalsPath)) {
50542
+ if (existsSync28(proposalsPath)) {
49537
50543
  try {
49538
- proposals = JSON.parse(readFileSync22(proposalsPath, "utf-8"));
50544
+ proposals = JSON.parse(readFileSync23(proposalsPath, "utf-8"));
49539
50545
  } catch {
49540
50546
  }
49541
50547
  }
@@ -53234,20 +54240,20 @@ var StreamableHTTPServerTransport = class {
53234
54240
  };
53235
54241
 
53236
54242
  // src/utils/config.ts
53237
- import { join as join28, resolve as resolve2 } from "path";
54243
+ import { join as join29, resolve as resolve2 } from "path";
53238
54244
  function getDefaultConfig(projectPath) {
53239
54245
  const normalizedPath = resolve2(projectPath);
53240
54246
  return {
53241
54247
  projectPath: normalizedPath,
53242
54248
  // Store in project directory (standard practice like .git/, .vscode/)
53243
- dataDir: join28(normalizedPath, ".codeimpact"),
54249
+ dataDir: join29(normalizedPath, ".codeimpact"),
53244
54250
  maxTokens: 6e3,
53245
54251
  embeddingModel: "Xenova/all-MiniLM-L6-v2",
53246
54252
  // Fallback model, faster and smaller
53247
54253
  watchIgnore: [
53248
54254
  // ===== CodeImpact =====
53249
54255
  "**/.codeimpact/**",
53250
- "**/.codeimpact/**",
54256
+ "**/knowledge/**",
53251
54257
  // ===== Version Control =====
53252
54258
  "**/.git/**",
53253
54259
  "**/.svn/**",
@@ -53594,9 +54600,9 @@ To connect clients, run in each project:`);
53594
54600
  };
53595
54601
 
53596
54602
  // src/cli/commands.ts
53597
- import { join as join37, resolve as resolve3 } from "path";
54603
+ import { join as join38, resolve as resolve3 } from "path";
53598
54604
  import { fileURLToPath as fileURLToPath2 } from "url";
53599
- import { existsSync as existsSync36, readFileSync as readFileSync29, writeFileSync as writeFileSync21, mkdirSync as mkdirSync19 } from "fs";
54605
+ import { existsSync as existsSync37, readFileSync as readFileSync30, writeFileSync as writeFileSync21, mkdirSync as mkdirSync19 } from "fs";
53600
54606
  import { homedir as homedir2 } from "os";
53601
54607
  var projectManager = new ProjectManager();
53602
54608
  function listProjects() {
@@ -53711,10 +54717,10 @@ function exportDecisions(projectPath, options = {}) {
53711
54717
  message: `Project not registered: ${targetPath}. Use "codeimpact projects add ${targetPath}" first.`
53712
54718
  };
53713
54719
  }
53714
- let dbPath = join37(projectInfo.dataDir, "codeimpact.db");
53715
- if (!existsSync36(dbPath)) {
53716
- const oldDbPath = join37(projectInfo.dataDir, "codeimpact.db");
53717
- if (existsSync36(oldDbPath)) {
54720
+ let dbPath = join38(projectInfo.dataDir, "codeimpact.db");
54721
+ if (!existsSync37(dbPath)) {
54722
+ const oldDbPath = join38(projectInfo.dataDir, "codeimpact.db");
54723
+ if (existsSync37(oldDbPath)) {
53718
54724
  dbPath = oldDbPath;
53719
54725
  } else {
53720
54726
  return {
@@ -53741,17 +54747,17 @@ function exportDecisions(projectPath, options = {}) {
53741
54747
  });
53742
54748
  return {
53743
54749
  success: true,
53744
- message: `Exported ${exportedFiles.length} ADR files to ${options.outputDir || join37(targetPath, "docs", "decisions")}`,
54750
+ message: `Exported ${exportedFiles.length} ADR files to ${options.outputDir || join38(targetPath, "docs", "decisions")}`,
53745
54751
  data: exportedFiles
53746
54752
  };
53747
54753
  }
53748
54754
  function findDatabasePath(projectInfo) {
53749
- const centralizedPath = join37(projectInfo.dataDir, "codeimpact.db");
53750
- if (existsSync36(centralizedPath)) {
54755
+ const centralizedPath = join38(projectInfo.dataDir, "codeimpact.db");
54756
+ if (existsSync37(centralizedPath)) {
53751
54757
  return centralizedPath;
53752
54758
  }
53753
- const projectLocalPath = join37(projectInfo.path, ".codeimpact", "codeimpact.db");
53754
- if (existsSync36(projectLocalPath)) {
54759
+ const projectLocalPath = join38(projectInfo.path, ".codeimpact", "codeimpact.db");
54760
+ if (existsSync37(projectLocalPath)) {
53755
54761
  return projectLocalPath;
53756
54762
  }
53757
54763
  return null;
@@ -54313,8 +55319,8 @@ function showProject(projectId) {
54313
55319
  function configureMCPClient(clientName, configPath, serverName, projectPath) {
54314
55320
  let config2 = { mcpServers: {} };
54315
55321
  try {
54316
- if (existsSync36(configPath)) {
54317
- const content = readFileSync29(configPath, "utf-8");
55322
+ if (existsSync37(configPath)) {
55323
+ const content = readFileSync30(configPath, "utf-8");
54318
55324
  config2 = JSON.parse(content);
54319
55325
  } else {
54320
55326
  const sep = process.platform === "win32" ? "\\" : "/";
@@ -54350,8 +55356,8 @@ function configureMCPClient(clientName, configPath, serverName, projectPath) {
54350
55356
  function configureProjectMCP(configPath, projectPath) {
54351
55357
  let config2 = { mcpServers: {} };
54352
55358
  try {
54353
- if (existsSync36(configPath)) {
54354
- const content = readFileSync29(configPath, "utf-8");
55359
+ if (existsSync37(configPath)) {
55360
+ const content = readFileSync30(configPath, "utf-8");
54355
55361
  config2 = JSON.parse(content);
54356
55362
  }
54357
55363
  } catch {
@@ -54383,7 +55389,7 @@ function configureProjectMCP(configPath, projectPath) {
54383
55389
  }
54384
55390
  }
54385
55391
  function configureClaudeMD(projectPath) {
54386
- const claudeMdPath = join37(projectPath, "CLAUDE.md");
55392
+ const claudeMdPath = join38(projectPath, "CLAUDE.md");
54387
55393
  const codeimpactSection = `
54388
55394
  ## CodeImpact Integration
54389
55395
 
@@ -54453,8 +55459,8 @@ codeimpact reindex
54453
55459
  `;
54454
55460
  try {
54455
55461
  let existingContent = "";
54456
- if (existsSync36(claudeMdPath)) {
54457
- existingContent = readFileSync29(claudeMdPath, "utf-8");
55462
+ if (existsSync37(claudeMdPath)) {
55463
+ existingContent = readFileSync30(claudeMdPath, "utf-8");
54458
55464
  if (existingContent.includes("## CodeImpact Integration")) {
54459
55465
  const startMarker = "## CodeImpact Integration";
54460
55466
  const startIndex = existingContent.indexOf(startMarker);
@@ -54485,18 +55491,18 @@ ${codeimpactSection}`;
54485
55491
  }
54486
55492
  }
54487
55493
  function configureCursorProjectMCP(projectPath) {
54488
- const cursorDir = join37(projectPath, ".cursor");
54489
- const configPath = join37(cursorDir, "mcp.json");
55494
+ const cursorDir = join38(projectPath, ".cursor");
55495
+ const configPath = join38(cursorDir, "mcp.json");
54490
55496
  try {
54491
- if (!existsSync36(cursorDir)) {
55497
+ if (!existsSync37(cursorDir)) {
54492
55498
  mkdirSync19(cursorDir, { recursive: true });
54493
55499
  }
54494
55500
  } catch {
54495
55501
  }
54496
55502
  let config2 = { mcpServers: {} };
54497
55503
  try {
54498
- if (existsSync36(configPath)) {
54499
- const content = readFileSync29(configPath, "utf-8");
55504
+ if (existsSync37(configPath)) {
55505
+ const content = readFileSync30(configPath, "utf-8");
54500
55506
  config2 = JSON.parse(content);
54501
55507
  }
54502
55508
  } catch {
@@ -54527,7 +55533,7 @@ function configureCursorProjectMCP(projectPath) {
54527
55533
  }
54528
55534
  }
54529
55535
  function configureCursorRules(projectPath) {
54530
- const cursorRulesPath = join37(projectPath, ".cursorrules");
55536
+ const cursorRulesPath = join38(projectPath, ".cursorrules");
54531
55537
  const codeimpactSection = `
54532
55538
  # CodeImpact Integration
54533
55539
 
@@ -54591,8 +55597,8 @@ codeimpact stats
54591
55597
  `;
54592
55598
  try {
54593
55599
  let existingContent = "";
54594
- if (existsSync36(cursorRulesPath)) {
54595
- existingContent = readFileSync29(cursorRulesPath, "utf-8");
55600
+ if (existsSync37(cursorRulesPath)) {
55601
+ existingContent = readFileSync30(cursorRulesPath, "utf-8");
54596
55602
  if (existingContent.includes("# CodeImpact Integration")) {
54597
55603
  const startMarker = "# CodeImpact Integration";
54598
55604
  const startIndex = existingContent.indexOf(startMarker);
@@ -54621,11 +55627,11 @@ codeimpact stats
54621
55627
  }
54622
55628
  }
54623
55629
  function configureOpenCode(projectPath) {
54624
- const configPath = join37(projectPath, "opencode.json");
55630
+ const configPath = join38(projectPath, "opencode.json");
54625
55631
  let config2 = {};
54626
55632
  try {
54627
- if (existsSync36(configPath)) {
54628
- const content = readFileSync29(configPath, "utf-8");
55633
+ if (existsSync37(configPath)) {
55634
+ const content = readFileSync30(configPath, "utf-8");
54629
55635
  config2 = JSON.parse(content);
54630
55636
  }
54631
55637
  } catch {
@@ -54661,8 +55667,8 @@ function configureOpenCode(projectPath) {
54661
55667
  function configureRemoteMCPClient(clientName, configPath, serverName, serverUrl) {
54662
55668
  let config2 = { mcpServers: {} };
54663
55669
  try {
54664
- if (existsSync36(configPath)) {
54665
- config2 = JSON.parse(readFileSync29(configPath, "utf-8"));
55670
+ if (existsSync37(configPath)) {
55671
+ config2 = JSON.parse(readFileSync30(configPath, "utf-8"));
54666
55672
  }
54667
55673
  } catch {
54668
55674
  }
@@ -54670,7 +55676,7 @@ function configureRemoteMCPClient(clientName, configPath, serverName, serverUrl)
54670
55676
  config2.mcpServers[serverName] = { url: serverUrl };
54671
55677
  try {
54672
55678
  const dir = configPath.substring(0, configPath.lastIndexOf("/") || configPath.lastIndexOf("\\"));
54673
- if (dir && !existsSync36(dir)) mkdirSync19(dir, { recursive: true });
55679
+ if (dir && !existsSync37(dir)) mkdirSync19(dir, { recursive: true });
54674
55680
  writeFileSync21(configPath, JSON.stringify(config2, null, 2));
54675
55681
  return { success: true, message: `${clientName}: ${configPath}` };
54676
55682
  } catch (err) {
@@ -54690,27 +55696,27 @@ function initProject(projectPath, serverUrl) {
54690
55696
  const failedClients = [];
54691
55697
  let claudeConfigPath;
54692
55698
  if (platform === "win32") {
54693
- claudeConfigPath = join37(homedir2(), "AppData", "Roaming", "Claude", "claude_desktop_config.json");
55699
+ claudeConfigPath = join38(homedir2(), "AppData", "Roaming", "Claude", "claude_desktop_config.json");
54694
55700
  } else if (platform === "darwin") {
54695
- claudeConfigPath = join37(homedir2(), "Library", "Application Support", "Claude", "claude_desktop_config.json");
55701
+ claudeConfigPath = join38(homedir2(), "Library", "Application Support", "Claude", "claude_desktop_config.json");
54696
55702
  } else {
54697
- claudeConfigPath = join37(homedir2(), ".config", "claude", "claude_desktop_config.json");
55703
+ claudeConfigPath = join38(homedir2(), ".config", "claude", "claude_desktop_config.json");
54698
55704
  }
54699
55705
  if (serverUrl) {
54700
55706
  const remoteProjectUrl = `${serverUrl}/mcp?project=${encodeURIComponent(resolve3(targetPath))}`;
54701
55707
  const claudeResult = configureRemoteMCPClient("Claude Desktop", claudeConfigPath, serverName, remoteProjectUrl);
54702
55708
  if (claudeResult.success) configuredClients.push(claudeResult.message);
54703
55709
  else failedClients.push(claudeResult.message);
54704
- const claudeCodeConfigPath = join37(targetPath, ".mcp.json");
55710
+ const claudeCodeConfigPath = join38(targetPath, ".mcp.json");
54705
55711
  const claudeCodeResult = configureRemoteMCPClient("Claude Code", claudeCodeConfigPath, "codeimpact", remoteProjectUrl);
54706
55712
  if (claudeCodeResult.success) configuredClients.push(claudeCodeResult.message);
54707
55713
  let cursorConfigPath;
54708
55714
  if (platform === "win32") {
54709
- cursorConfigPath = join37(homedir2(), "AppData", "Roaming", "Cursor", "User", "globalStorage", "cursor.mcp", "mcp.json");
55715
+ cursorConfigPath = join38(homedir2(), "AppData", "Roaming", "Cursor", "User", "globalStorage", "cursor.mcp", "mcp.json");
54710
55716
  } else if (platform === "darwin") {
54711
- cursorConfigPath = join37(homedir2(), "Library", "Application Support", "Cursor", "User", "globalStorage", "cursor.mcp", "mcp.json");
55717
+ cursorConfigPath = join38(homedir2(), "Library", "Application Support", "Cursor", "User", "globalStorage", "cursor.mcp", "mcp.json");
54712
55718
  } else {
54713
- cursorConfigPath = join37(homedir2(), ".config", "Cursor", "User", "globalStorage", "cursor.mcp", "mcp.json");
55719
+ cursorConfigPath = join38(homedir2(), ".config", "Cursor", "User", "globalStorage", "cursor.mcp", "mcp.json");
54714
55720
  }
54715
55721
  const cursorResult = configureRemoteMCPClient("Cursor (global)", cursorConfigPath, serverName, remoteProjectUrl);
54716
55722
  if (cursorResult.success) configuredClients.push(cursorResult.message);
@@ -54722,16 +55728,16 @@ function initProject(projectPath, serverUrl) {
54722
55728
  const openCodeResult = configureOpenCode(targetPath);
54723
55729
  if (openCodeResult.success) configuredClients.push(openCodeResult.message);
54724
55730
  else failedClients.push(openCodeResult.message);
54725
- const claudeCodeConfigPath = join37(targetPath, ".mcp.json");
55731
+ const claudeCodeConfigPath = join38(targetPath, ".mcp.json");
54726
55732
  const claudeCodeResult = configureProjectMCP(claudeCodeConfigPath, targetPath);
54727
55733
  if (claudeCodeResult.success) configuredClients.push(claudeCodeResult.message);
54728
55734
  let cursorConfigPath;
54729
55735
  if (platform === "win32") {
54730
- cursorConfigPath = join37(homedir2(), "AppData", "Roaming", "Cursor", "User", "globalStorage", "cursor.mcp", "mcp.json");
55736
+ cursorConfigPath = join38(homedir2(), "AppData", "Roaming", "Cursor", "User", "globalStorage", "cursor.mcp", "mcp.json");
54731
55737
  } else if (platform === "darwin") {
54732
- cursorConfigPath = join37(homedir2(), "Library", "Application Support", "Cursor", "User", "globalStorage", "cursor.mcp", "mcp.json");
55738
+ cursorConfigPath = join38(homedir2(), "Library", "Application Support", "Cursor", "User", "globalStorage", "cursor.mcp", "mcp.json");
54733
55739
  } else {
54734
- cursorConfigPath = join37(homedir2(), ".config", "Cursor", "User", "globalStorage", "cursor.mcp", "mcp.json");
55740
+ cursorConfigPath = join38(homedir2(), ".config", "Cursor", "User", "globalStorage", "cursor.mcp", "mcp.json");
54735
55741
  }
54736
55742
  const cursorGlobalResult = configureMCPClient("Cursor (global)", cursorConfigPath, serverName, targetPath);
54737
55743
  if (cursorGlobalResult.success) configuredClients.push(cursorGlobalResult.message);