codeimpact 0.3.2 → 0.4.0

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
@@ -8663,22 +8663,1290 @@ var init_research_trust = __esm({
8663
8663
  }
8664
8664
  });
8665
8665
 
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";
8666
+ // src/core/agents/hardcoded-knowledge.ts
8667
+ var TECH_KNOWLEDGE, FEATURE_NAME_RULES, FEATURE_NAME_PITFALLS, WELL_KNOWN_FEATURES, DIR_PURPOSE_MAP, SCOPE_LABELS, DOC_SOURCE_REGISTRY;
8668
+ var init_hardcoded_knowledge = __esm({
8669
+ "src/core/agents/hardcoded-knowledge.ts"() {
8670
+ "use strict";
8671
+ TECH_KNOWLEDGE = {
8672
+ "express": {
8673
+ rules: [
8674
+ "Use Router() for modular route definitions",
8675
+ "Always register error handler middleware last (4 args: err, req, res, next)"
8676
+ ],
8677
+ pitfalls: [
8678
+ "Forgetting to call next() in middleware causes request to hang",
8679
+ "Async errors in handlers need explicit try/catch or express-async-errors"
8680
+ ]
8681
+ },
8682
+ "hono": {
8683
+ rules: [
8684
+ "Use app.route() for modular route grouping",
8685
+ "Return c.json() or c.text() \u2014 do not use res.send()"
8686
+ ],
8687
+ pitfalls: [
8688
+ "Hono middleware must call next() or return a Response \u2014 skipping both hangs the request"
8689
+ ]
8690
+ },
8691
+ "better-sqlite3": {
8692
+ rules: [
8693
+ "Use db.prepare().all() for SELECT, db.prepare().run() for INSERT/UPDATE/DELETE",
8694
+ "better-sqlite3 is synchronous \u2014 do NOT use async/await with db calls",
8695
+ "All database access should go through a single module"
8696
+ ],
8697
+ pitfalls: [
8698
+ "db.exec() returns nothing \u2014 using it for SELECT gives undefined",
8699
+ 'WAL mode must be set once after opening: db.pragma("journal_mode = WAL")'
8700
+ ]
8701
+ },
8702
+ "stripe": {
8703
+ rules: [
8704
+ "Always verify webhook signatures before processing events",
8705
+ "Use idempotency keys for payment creation to prevent double-charges"
8706
+ ],
8707
+ pitfalls: [
8708
+ "Stripe webhook events may arrive out of order \u2014 handle idempotently",
8709
+ "stripe.webhooks.constructEvent() throws on invalid signature \u2014 wrap in try/catch"
8710
+ ]
8711
+ },
8712
+ "jsonwebtoken": {
8713
+ rules: [
8714
+ "Always use jwt.verify() \u2014 never trust jwt.decode() alone",
8715
+ "Set explicit expiration (expiresIn) on all tokens"
8716
+ ],
8717
+ pitfalls: [
8718
+ "Using jwt.decode() without verify() is a security vulnerability",
8719
+ 'The "none" algorithm attack \u2014 always specify algorithms: ["HS256"]'
8720
+ ]
8721
+ },
8722
+ "@modelcontextprotocol/sdk": {
8723
+ rules: [
8724
+ "Use server.tool() to register MCP tools with zod schema validation",
8725
+ "All tool handlers must return { content: [...] } response objects"
8726
+ ],
8727
+ pitfalls: [
8728
+ "Tool names must be unique across the server \u2014 duplicates silently overwrite",
8729
+ "Forgetting to call server.connect(transport) means no requests are handled"
8730
+ ]
8731
+ },
8732
+ "prisma": {
8733
+ rules: [
8734
+ "Run npx prisma generate after schema changes",
8735
+ "Use transactions for multi-table operations: prisma.$transaction()"
8736
+ ],
8737
+ pitfalls: [
8738
+ "Forgetting prisma generate after schema change causes type mismatches at runtime",
8739
+ "N+1 queries \u2014 use include/select to eagerly load relations"
8740
+ ]
8741
+ },
8742
+ "zod": {
8743
+ rules: [
8744
+ "Define schemas once, derive TypeScript types with z.infer<typeof schema>",
8745
+ "Use .safeParse() in handlers for graceful error handling"
8746
+ ],
8747
+ pitfalls: [
8748
+ ".parse() throws on invalid data \u2014 use .safeParse() in request handlers"
8749
+ ]
8750
+ },
8751
+ "vitest": {
8752
+ rules: [
8753
+ "Use describe/it/expect patterns for test organization",
8754
+ "Use vi.mock() for module mocking, vi.fn() for function stubs"
8755
+ ],
8756
+ pitfalls: [
8757
+ "vi.mock() is hoisted to top of file \u2014 cannot access variables from outer scope"
8758
+ ]
8759
+ },
8760
+ "web-tree-sitter": {
8761
+ rules: [
8762
+ "Initialize Parser with await Parser.init() before use",
8763
+ "Load language WASM files with Parser.Language.load()"
8764
+ ],
8765
+ pitfalls: [
8766
+ "Parser.init() must complete before any parsing \u2014 race condition if not awaited",
8767
+ "WASM files must be bundled/copied to dist \u2014 not resolved from node_modules at runtime"
8768
+ ]
8769
+ },
8770
+ "@xenova/transformers": {
8771
+ rules: [
8772
+ "Use pipeline() for high-level tasks, AutoModel for custom inference",
8773
+ "Cache downloaded models by setting env.cacheDir"
8774
+ ],
8775
+ pitfalls: [
8776
+ "First model load downloads weights (~100MB+) \u2014 cache for subsequent runs",
8777
+ "ONNX runtime may fail on some architectures \u2014 test on target platform"
8778
+ ]
8779
+ },
8780
+ "chokidar": {
8781
+ rules: [
8782
+ "Use chokidar.watch() with ignored patterns to skip node_modules",
8783
+ 'Handle both "add" and "change" events for file watching'
8784
+ ],
8785
+ pitfalls: [
8786
+ "Not closing watcher on process exit leaks file handles",
8787
+ "Rapid file changes may fire multiple events \u2014 debounce handlers"
8788
+ ]
8789
+ },
8790
+ "react": {
8791
+ rules: [
8792
+ "Components must be pure \u2014 same props must produce same output",
8793
+ "Use useState for local UI state, useReducer for complex state logic",
8794
+ "Memoize expensive computations with useMemo, callbacks with useCallback"
8795
+ ],
8796
+ pitfalls: [
8797
+ "Missing key prop in lists causes React reconciliation bugs \u2014 always use stable keys",
8798
+ "useEffect with missing deps causes stale closures \u2014 lint rules catch most cases",
8799
+ "Setting state during render causes infinite re-render loop"
8800
+ ]
8801
+ },
8802
+ "react-router-dom": {
8803
+ rules: [
8804
+ "Use <Link> for navigation \u2014 never use <a href> for internal routes",
8805
+ "Use useNavigate() for programmatic navigation in event handlers"
8806
+ ],
8807
+ pitfalls: [
8808
+ "Routes must be nested under a <Router> provider \u2014 missing it causes runtime crash",
8809
+ "useSearchParams() returns URLSearchParams \u2014 .get() returns null not undefined"
8810
+ ]
8811
+ },
8812
+ "react-hook-form": {
8813
+ rules: [
8814
+ "Use register() for uncontrolled inputs, Controller for controlled (MUI, Radix)",
8815
+ "Define validation with zod resolver \u2014 avoid inline validate functions"
8816
+ ],
8817
+ pitfalls: [
8818
+ "Forgetting to call handleSubmit() wrapper \u2014 form submits without validation",
8819
+ "watch() causes re-render on every change \u2014 use getValues() for one-time reads"
8820
+ ]
8821
+ },
8822
+ "tailwindcss": {
8823
+ rules: [
8824
+ "Use Tailwind utility classes \u2014 avoid custom CSS unless absolutely necessary",
8825
+ "Use cn() or clsx() for conditional class merging"
8826
+ ],
8827
+ pitfalls: [
8828
+ "Dynamic class names like `bg-${color}-500` are purged \u2014 use full class names",
8829
+ "Order matters for conflicting utilities \u2014 last class wins"
8830
+ ]
8831
+ },
8832
+ "vite": {
8833
+ rules: [
8834
+ "Use import.meta.env for env variables \u2014 must be prefixed with VITE_",
8835
+ "Configure aliases in vite.config.ts resolve.alias"
8836
+ ],
8837
+ pitfalls: [
8838
+ "process.env is not available in Vite \u2014 use import.meta.env instead",
8839
+ "Environment variables without VITE_ prefix are not exposed to client code"
8840
+ ]
8841
+ },
8842
+ "next": {
8843
+ rules: [
8844
+ 'Use server components by default \u2014 add "use client" only when needed',
8845
+ "Data fetching in server components \u2014 no useEffect for initial data"
8846
+ ],
8847
+ pitfalls: [
8848
+ "Importing client-only code (useState, useEffect) in server components crashes build",
8849
+ "next/image requires explicit width/height or fill prop \u2014 missing causes error"
8850
+ ]
8851
+ },
8852
+ "framer-motion": {
8853
+ rules: [
8854
+ "Use motion.div (not regular div) for animated elements",
8855
+ "Define variants objects for reusable animation states"
8856
+ ],
8857
+ pitfalls: [
8858
+ "AnimatePresence requires direct children to have unique key props",
8859
+ "Exit animations only work when component is direct child of AnimatePresence"
8860
+ ]
8861
+ },
8862
+ "d3": {
8863
+ rules: [
8864
+ "Use D3 for data transforms/scales, React for DOM rendering \u2014 avoid d3.select in React",
8865
+ "Use useRef to get DOM reference for D3 direct DOM manipulation when needed"
8866
+ ],
8867
+ pitfalls: [
8868
+ "Mixing D3 DOM manipulation with React causes conflicts \u2014 pick one rendering strategy",
8869
+ "D3 scales are mutable \u2014 creating them in render without useMemo causes bugs"
8870
+ ]
8871
+ },
8872
+ "zustand": {
8873
+ rules: [
8874
+ "Create stores with create() \u2014 use selectors to prevent unnecessary re-renders",
8875
+ "Keep store state serializable \u2014 no functions or class instances in state"
8876
+ ],
8877
+ pitfalls: [
8878
+ "Not using selectors subscribes to entire store \u2014 causes excess re-renders",
8879
+ "Mutating state directly (state.x = y) does not trigger re-render \u2014 use set()"
8880
+ ]
8881
+ },
8882
+ "@tanstack/react-query": {
8883
+ rules: [
8884
+ "Use useQuery for GET, useMutation for POST/PUT/DELETE",
8885
+ "Set staleTime to avoid unnecessary refetches \u2014 default 0 refetches every mount"
8886
+ ],
8887
+ pitfalls: [
8888
+ "Forgetting queryClient.invalidateQueries after mutation shows stale data",
8889
+ "Query keys must be serializable arrays \u2014 objects in keys cause cache misses"
8890
+ ]
8891
+ }
8892
+ };
8893
+ FEATURE_NAME_RULES = {
8894
+ server: [
8895
+ "All tool/resource handlers must validate inputs before processing",
8896
+ "Return structured error responses \u2014 never throw raw errors to clients"
8897
+ ],
8898
+ storage: [
8899
+ "All database access should go through this module \u2014 no direct imports elsewhere",
8900
+ "Use transactions for multi-step operations to ensure consistency"
8901
+ ],
8902
+ indexing: [
8903
+ "Index operations should be idempotent \u2014 reindexing same file produces same result",
8904
+ "Handle parse errors gracefully \u2014 a broken file should not crash the indexer"
8905
+ ],
8906
+ core: [
8907
+ "Core modules should have no side effects on import",
8908
+ "Export types alongside functions for downstream consumers"
8909
+ ],
8910
+ test: [
8911
+ "Tests should be deterministic \u2014 no reliance on external services or timing",
8912
+ "Clean up temporary files and directories in afterEach/afterAll hooks"
8913
+ ],
8914
+ knowledge: [
8915
+ "Skill files must follow the agentskills.io SKILL.md format",
8916
+ "Generated content must use marker comments to preserve manual edits"
8917
+ ],
8918
+ doc: [
8919
+ "Generated docs must be kept in sync with source code changes",
8920
+ "Use relative paths for internal links"
8921
+ ],
8922
+ auth: [
8923
+ "Never store plain-text passwords \u2014 use bcrypt or argon2",
8924
+ "Validate and sanitize all user inputs before processing"
8925
+ ],
8926
+ api: [
8927
+ "All endpoints must validate request bodies/params before processing",
8928
+ "Return consistent error response shapes across all endpoints"
8929
+ ],
8930
+ components: [
8931
+ "Components should be pure \u2014 derive UI from props, avoid internal side effects",
8932
+ "Use composition over inheritance \u2014 prefer small, focused components",
8933
+ "Co-locate styles, types, and tests with the component file"
8934
+ ],
8935
+ pages: [
8936
+ "Pages handle routing and data fetching \u2014 delegate UI to components",
8937
+ "Keep page components thin \u2014 extract business logic to hooks or services"
8938
+ ],
8939
+ hooks: [
8940
+ 'Custom hooks must start with "use" prefix',
8941
+ "Keep hooks focused on one concern \u2014 avoid monolithic hooks",
8942
+ "Hooks should be reusable \u2014 avoid coupling to specific component internals"
8943
+ ],
8944
+ layouts: [
8945
+ "Layouts define page structure \u2014 children should not assume layout behavior",
8946
+ "Keep layouts thin \u2014 avoid business logic in layout wrappers"
8947
+ ],
8948
+ views: [
8949
+ "Views handle routing and data fetching \u2014 delegate UI to components",
8950
+ "Keep view components thin \u2014 extract business logic to hooks or services"
8951
+ ],
8952
+ services: [
8953
+ "Services handle API communication \u2014 keep HTTP details out of components",
8954
+ "Return typed responses \u2014 avoid returning raw API responses"
8955
+ ],
8956
+ stores: [
8957
+ "Keep store state minimal \u2014 derive computed values instead of storing them",
8958
+ "Actions should be thin \u2014 delegate complex logic to services"
8959
+ ],
8960
+ store: [
8961
+ "Keep store state minimal \u2014 derive computed values instead of storing them",
8962
+ "Actions should be thin \u2014 delegate complex logic to services"
8963
+ ],
8964
+ contexts: [
8965
+ "Context should hold only values that many components need \u2014 avoid overuse",
8966
+ "Split large contexts into focused providers to prevent unnecessary re-renders"
8967
+ ],
8968
+ providers: [
8969
+ "Provider order matters \u2014 auth before data fetching, theme before UI",
8970
+ "Keep providers thin \u2014 initialize services, do not embed business logic"
8971
+ ],
8972
+ routes: [
8973
+ "Route definitions should be declarative \u2014 avoid complex inline logic",
8974
+ "Use lazy loading for route components to optimize bundle size"
8975
+ ]
8976
+ };
8977
+ FEATURE_NAME_PITFALLS = {
8978
+ server: [
8979
+ "Unhandled promise rejections in handlers crash the process \u2014 always catch async errors",
8980
+ "Adding middleware order matters \u2014 auth before route handlers"
8981
+ ],
8982
+ storage: [
8983
+ "Forgetting to close database connections leaks file handles",
8984
+ "Concurrent writes without transactions may cause data corruption"
8985
+ ],
8986
+ indexing: [
8987
+ "Large files can cause out-of-memory \u2014 set size limits on parsed content",
8988
+ "File paths must be normalized (forward slashes) for cross-platform compatibility"
8989
+ ],
8990
+ core: [
8991
+ "Circular imports between core modules cause runtime errors \u2014 check dependency direction",
8992
+ "Changing public API signatures breaks downstream consumers"
8993
+ ],
8994
+ test: [
8995
+ "Tests sharing mutable state between runs cause flaky failures",
8996
+ "Temp directories not cleaned up fill disk over repeated test runs"
8997
+ ],
8998
+ components: [
8999
+ "Missing key prop in lists causes React reconciliation bugs \u2014 always use stable keys",
9000
+ "Direct DOM manipulation bypasses React \u2014 use refs only when necessary",
9001
+ "Prop drilling through 3+ levels signals need for context or composition"
9002
+ ],
9003
+ pages: [
9004
+ "Data fetching in render causes waterfall requests \u2014 use loaders or top-level hooks",
9005
+ "Missing error boundaries let one page crash the whole app"
9006
+ ],
9007
+ hooks: [
9008
+ "Missing deps in useEffect cause stale closures \u2014 React will warn but won't auto-fix",
9009
+ "Hooks called conditionally break React \u2014 hooks must be called in same order every render"
9010
+ ],
9011
+ services: [
9012
+ "Not handling API errors shows raw errors to users \u2014 always catch and transform",
9013
+ "Caching stale data causes UI inconsistency \u2014 invalidate cache on mutations"
9014
+ ],
9015
+ stores: [
9016
+ "Mutating state directly causes silent bugs \u2014 always return new references",
9017
+ "Large store updates trigger unnecessary re-renders \u2014 split into focused slices"
9018
+ ],
9019
+ store: [
9020
+ "Mutating state directly causes silent bugs \u2014 always return new references",
9021
+ "Large store updates trigger unnecessary re-renders \u2014 split into focused slices"
9022
+ ]
9023
+ };
9024
+ WELL_KNOWN_FEATURES = /* @__PURE__ */ new Set([
9025
+ "server",
9026
+ "storage",
9027
+ "indexing",
9028
+ "core",
9029
+ "test",
9030
+ "knowledge",
9031
+ "doc",
9032
+ "auth",
9033
+ "api",
9034
+ "billing",
9035
+ "cli",
9036
+ "components",
9037
+ "pages",
9038
+ "hooks",
9039
+ "layouts",
9040
+ "views",
9041
+ "services",
9042
+ "stores",
9043
+ "store",
9044
+ "contexts",
9045
+ "providers",
9046
+ "routes"
9047
+ ]);
9048
+ DIR_PURPOSE_MAP = {
9049
+ // Backend
9050
+ core: "Core business logic and domain modules",
9051
+ server: "Server, transports, and request handling",
9052
+ storage: "Database access and persistence",
9053
+ indexing: "Code indexing and symbol extraction",
9054
+ api: "API routes and handlers",
9055
+ auth: "Authentication and authorization",
9056
+ billing: "Payment processing",
9057
+ test: "Tests and evaluation harness",
9058
+ tests: "Tests and evaluation harness",
9059
+ doc: "Documentation",
9060
+ knowledge: "AI knowledge system",
9061
+ cli: "Command-line interface",
9062
+ base: "Base configuration and fixtures",
9063
+ src: "Application source code",
9064
+ lib: "Shared utilities",
9065
+ // Frontend / React
9066
+ components: "Reusable UI components",
9067
+ pages: "Page-level route components",
9068
+ hooks: "Custom React hooks",
9069
+ layouts: "Page layout wrappers",
9070
+ views: "View components (page-level)",
9071
+ features: "Feature modules (co-located logic + UI)",
9072
+ services: "API client and service layer",
9073
+ stores: "State management (stores/slices)",
9074
+ store: "State management (stores/slices)",
9075
+ utils: "Utility functions and helpers",
9076
+ contexts: "React context providers",
9077
+ providers: "App-level providers and wrappers",
9078
+ routes: "Route definitions and navigation",
9079
+ assets: "Static assets (images, fonts, icons)",
9080
+ styles: "Global styles and theme configuration",
9081
+ types: "TypeScript type definitions",
9082
+ config: "App configuration",
9083
+ middleware: "Request/response middleware",
9084
+ models: "Data models and schemas",
9085
+ controllers: "Request handlers (MVC)",
9086
+ resolvers: "GraphQL resolvers",
9087
+ schemas: "Data schemas and validation",
9088
+ migrations: "Database migrations",
9089
+ // Go
9090
+ cmd: "CLI entry points and commands",
9091
+ pkg: "Reusable library packages",
9092
+ internal: "Private packages (unexported)",
9093
+ // Rust
9094
+ bin: "Binary entry points",
9095
+ benches: "Benchmarks",
9096
+ // Python
9097
+ templates: "Template files (HTML, Jinja2)",
9098
+ static: "Static files for web serving",
9099
+ management: "Management commands (Django)",
9100
+ // General
9101
+ scripts: "Build/deploy/automation scripts",
9102
+ tools: "Developer tools and utilities",
9103
+ docs: "Documentation",
9104
+ examples: "Example code and demos",
9105
+ fixtures: "Test fixtures and sample data",
9106
+ mocks: "Mock objects for testing",
9107
+ helpers: "Helper functions and utilities",
9108
+ adapters: "External service adapters",
9109
+ ports: "Port interfaces (hexagonal architecture)",
9110
+ domain: "Domain logic (DDD)",
9111
+ entities: "Domain entities",
9112
+ repositories: "Data access repositories",
9113
+ handlers: "Request/event handlers",
9114
+ events: "Event definitions and dispatchers",
9115
+ jobs: "Background jobs and workers",
9116
+ workers: "Background workers",
9117
+ queues: "Job queue definitions",
9118
+ cron: "Scheduled task definitions"
9119
+ };
9120
+ SCOPE_LABELS = {
9121
+ "@radix-ui": "Radix UI (shadcn/ui primitives)",
9122
+ "@tanstack": "TanStack (query/router/table)",
9123
+ "@trpc": "tRPC",
9124
+ "@nestjs": "NestJS",
9125
+ "@prisma": "Prisma",
9126
+ "@aws-sdk": "AWS SDK",
9127
+ "@google-cloud": "Google Cloud SDK",
9128
+ "@azure": "Azure SDK",
9129
+ "@mui": "Material UI",
9130
+ "@chakra-ui": "Chakra UI",
9131
+ "@headlessui": "Headless UI",
9132
+ "@mantine": "Mantine",
9133
+ "@emotion": "Emotion CSS",
9134
+ "@testing-library": "Testing Library",
9135
+ "@storybook": "Storybook",
9136
+ "@sentry": "Sentry",
9137
+ "@opentelemetry": "OpenTelemetry",
9138
+ "@supabase": "Supabase",
9139
+ "@firebase": "Firebase",
9140
+ "@stripe": "Stripe SDK"
9141
+ };
9142
+ DOC_SOURCE_REGISTRY = [
9143
+ {
9144
+ packageNames: ["express"],
9145
+ docsUrl: "https://expressjs.com/en/api.html",
9146
+ apiRefUrl: "https://expressjs.com/en/4x/api.html",
9147
+ changelogUrl: "https://github.com/expressjs/express/blob/master/History.md"
9148
+ },
9149
+ {
9150
+ packageNames: ["react", "react-dom"],
9151
+ docsUrl: "https://react.dev/reference/react",
9152
+ apiRefUrl: "https://react.dev/reference/react",
9153
+ changelogUrl: "https://github.com/facebook/react/blob/main/CHANGELOG.md"
9154
+ },
9155
+ {
9156
+ packageNames: ["next"],
9157
+ docsUrl: "https://nextjs.org/docs",
9158
+ apiRefUrl: "https://nextjs.org/docs/api-reference",
9159
+ changelogUrl: "https://github.com/vercel/next.js/releases"
9160
+ },
9161
+ {
9162
+ packageNames: ["typescript"],
9163
+ docsUrl: "https://www.typescriptlang.org/docs/",
9164
+ changelogUrl: "https://www.typescriptlang.org/docs/handbook/release-notes/overview.html"
9165
+ },
9166
+ {
9167
+ packageNames: ["vitest"],
9168
+ docsUrl: "https://vitest.dev/api/",
9169
+ apiRefUrl: "https://vitest.dev/api/",
9170
+ changelogUrl: "https://github.com/vitest-dev/vitest/releases"
9171
+ },
9172
+ {
9173
+ packageNames: ["jest"],
9174
+ docsUrl: "https://jestjs.io/docs/api",
9175
+ apiRefUrl: "https://jestjs.io/docs/expect"
9176
+ },
9177
+ {
9178
+ packageNames: ["prisma", "@prisma/client"],
9179
+ docsUrl: "https://www.prisma.io/docs",
9180
+ apiRefUrl: "https://www.prisma.io/docs/reference/api-reference",
9181
+ changelogUrl: "https://github.com/prisma/prisma/releases"
9182
+ },
9183
+ {
9184
+ packageNames: ["stripe"],
9185
+ docsUrl: "https://docs.stripe.com/api",
9186
+ changelogUrl: "https://docs.stripe.com/changelog"
9187
+ },
9188
+ {
9189
+ packageNames: ["@modelcontextprotocol/sdk"],
9190
+ docsUrl: "https://modelcontextprotocol.io/docs",
9191
+ apiRefUrl: "https://github.com/modelcontextprotocol/typescript-sdk"
9192
+ },
9193
+ {
9194
+ packageNames: ["better-sqlite3"],
9195
+ docsUrl: "https://github.com/WiseLibs/better-sqlite3/blob/master/docs/api.md",
9196
+ apiRefUrl: "https://github.com/WiseLibs/better-sqlite3/blob/master/docs/api.md"
9197
+ },
9198
+ {
9199
+ packageNames: ["zod"],
9200
+ docsUrl: "https://zod.dev/",
9201
+ apiRefUrl: "https://zod.dev/"
9202
+ },
9203
+ {
9204
+ packageNames: ["tailwindcss"],
9205
+ docsUrl: "https://tailwindcss.com/docs"
9206
+ },
9207
+ {
9208
+ packageNames: ["vite"],
9209
+ docsUrl: "https://vitejs.dev/guide/",
9210
+ apiRefUrl: "https://vitejs.dev/config/"
9211
+ },
9212
+ {
9213
+ packageNames: ["passport"],
9214
+ docsUrl: "https://www.passportjs.org/docs/"
9215
+ },
9216
+ {
9217
+ packageNames: ["jsonwebtoken"],
9218
+ docsUrl: "https://github.com/auth0/node-jsonwebtoken#readme"
9219
+ },
9220
+ {
9221
+ packageNames: ["axios"],
9222
+ docsUrl: "https://axios-http.com/docs/intro",
9223
+ apiRefUrl: "https://axios-http.com/docs/api_intro"
9224
+ },
9225
+ {
9226
+ packageNames: ["fastify"],
9227
+ docsUrl: "https://fastify.dev/docs/latest/",
9228
+ apiRefUrl: "https://fastify.dev/docs/latest/Reference/"
9229
+ },
9230
+ {
9231
+ packageNames: ["drizzle-orm"],
9232
+ docsUrl: "https://orm.drizzle.team/docs/overview"
9233
+ },
9234
+ {
9235
+ packageNames: ["trpc", "@trpc/server", "@trpc/client"],
9236
+ docsUrl: "https://trpc.io/docs"
9237
+ },
9238
+ {
9239
+ packageNames: ["hono"],
9240
+ docsUrl: "https://hono.dev/docs/",
9241
+ apiRefUrl: "https://hono.dev/docs/api/hono"
9242
+ }
9243
+ ];
9244
+ }
9245
+ });
9246
+
9247
+ // src/core/agents/universal-inference.ts
9248
+ import { existsSync as existsSync25, readFileSync as readFileSync20, readdirSync as readdirSync7 } from "fs";
8668
9249
  import { join as join25 } from "path";
9250
+ function inferTechRulesAndPitfalls(tech, researchDir) {
9251
+ const result = { rules: [], pitfalls: [] };
9252
+ if (researchDir) {
9253
+ const research = extractRulesFromResearch(tech, researchDir);
9254
+ result.rules.push(...research.rules);
9255
+ result.pitfalls.push(...research.pitfalls);
9256
+ }
9257
+ const hardcoded = TECH_KNOWLEDGE[tech.name];
9258
+ if (hardcoded) {
9259
+ for (const rule of hardcoded.rules) {
9260
+ if (!result.rules.includes(rule)) result.rules.push(rule);
9261
+ }
9262
+ for (const pitfall of hardcoded.pitfalls) {
9263
+ if (!result.pitfalls.includes(pitfall)) result.pitfalls.push(pitfall);
9264
+ }
9265
+ }
9266
+ if (result.rules.length === 0 || result.pitfalls.length === 0) {
9267
+ const category = classifyTechnology(tech);
9268
+ const categoryKnowledge = CATEGORY_RULES[category];
9269
+ if (categoryKnowledge) {
9270
+ if (result.rules.length === 0) result.rules.push(...categoryKnowledge.rules);
9271
+ if (result.pitfalls.length === 0) result.pitfalls.push(...categoryKnowledge.pitfalls);
9272
+ }
9273
+ }
9274
+ if (result.rules.length === 0) {
9275
+ result.rules.push(
9276
+ `Follow ${tech.name} documentation for API usage patterns`,
9277
+ "Pin dependency version to avoid unexpected breaking changes"
9278
+ );
9279
+ }
9280
+ if (result.pitfalls.length === 0) {
9281
+ result.pitfalls.push(
9282
+ `Check ${tech.name} changelog when upgrading for breaking changes`,
9283
+ "Ensure error handling covers all library-specific error types"
9284
+ );
9285
+ }
9286
+ return result;
9287
+ }
9288
+ function classifyFeature(feature, importGraph) {
9289
+ const name = feature.name.toLowerCase();
9290
+ if (/^(server|api|routes?|controllers?|handlers?|endpoints?)$/.test(name)) return "api-layer";
9291
+ if (/^(storage|db|database|models?|repositories|entities|migrations?)$/.test(name)) return "data-layer";
9292
+ if (/^(core|domain|business|logic|engine|services?)$/.test(name)) return "business-logic";
9293
+ if (/^(components?|ui|views?|pages?|layouts?|widgets?)$/.test(name)) return "ui-components";
9294
+ if (/^(stores?|state|contexts?|providers?|hooks?)$/.test(name)) return "state-management";
9295
+ if (/^(tests?|spec|__tests__|e2e|integration|fixtures?)$/.test(name)) return "testing";
9296
+ if (/^(cli|cmd|commands?)$/.test(name)) return "cli";
9297
+ if (/^(auth|authentication|authorization|security|identity)$/.test(name)) return "auth";
9298
+ if (/^(docs?|documentation|knowledge)$/.test(name)) return "documentation";
9299
+ if (/^(infra|infrastructure|deploy|ci|scripts?|tools?|config)$/.test(name)) return "infrastructure";
9300
+ if (/^(utils?|helpers?|lib|shared|common|pkg|internal)$/.test(name)) return "utility";
9301
+ if (feature.testFiles.length > 0 && feature.fileCount > 0) {
9302
+ if (feature.testFiles.length / feature.fileCount > 0.5) return "testing";
9303
+ }
9304
+ if (importGraph) {
9305
+ const featurePaths = new Set(feature.paths.map((p) => p.replace("/**", "")));
9306
+ let importedByOthers = 0;
9307
+ for (const [file2, imports] of importGraph) {
9308
+ if (featurePaths.has(file2)) continue;
9309
+ for (const imp of imports) {
9310
+ for (const fp of featurePaths) {
9311
+ if (imp.startsWith(fp)) importedByOthers++;
9312
+ }
9313
+ }
9314
+ }
9315
+ if (importedByOthers > 10) return "utility";
9316
+ }
9317
+ const techNames = feature.technologies.map((t) => t.toLowerCase());
9318
+ if (techNames.some((t) => /prisma|typeorm|sqlalchemy|diesel|gorm|sequelize|drizzle/.test(t))) return "data-layer";
9319
+ if (techNames.some((t) => /react|vue|svelte|angular|solid/.test(t))) return "ui-components";
9320
+ if (techNames.some((t) => /express|fastify|hono|flask|gin|actix|django|rails/.test(t))) return "api-layer";
9321
+ return "generic";
9322
+ }
9323
+ function inferDirectoryPurpose(dirName, context) {
9324
+ const lower = dirName.toLowerCase();
9325
+ const hardcoded = DIR_PURPOSE_MAP[lower];
9326
+ if (hardcoded) return hardcoded;
9327
+ if (/^(spec|__tests__|test_|_test)/.test(lower)) return "Tests and test helpers";
9328
+ if (/^(build|dist|out|target|bin)$/.test(lower)) return "Build output";
9329
+ if (/^(vendor|third[_-]?party|extern)/.test(lower)) return "Third-party vendored code";
9330
+ if (/^(proto|protobuf|grpc)/.test(lower)) return "Protocol buffer definitions";
9331
+ if (/^(gen|generated)/.test(lower)) return "Auto-generated code";
9332
+ if (/^(i18n|l10n|locale|translations?)/.test(lower)) return "Internationalization and localization";
9333
+ if (/^(plugin|extension|addon)s?$/.test(lower)) return "Plugin/extension modules";
9334
+ if (/^(seed|seeds|fixtures|testdata)$/.test(lower)) return "Seed data and test fixtures";
9335
+ if (/^(public|static|assets|resources|res)$/.test(lower)) return "Static assets and resources";
9336
+ if (/^(cache|tmp|temp)$/.test(lower)) return "Temporary/cache files";
9337
+ if (context) {
9338
+ if (context.dominantExtensions) {
9339
+ const exts = context.dominantExtensions;
9340
+ if (exts.some((e) => /\.(test|spec)\.(ts|js|py|go|rs)$/.test(e))) return "Tests and test helpers";
9341
+ if (exts.some((e) => /\.(css|scss|less|styl)$/.test(e))) return "Stylesheets";
9342
+ if (exts.some((e) => /\.(html|hbs|ejs|pug|jinja2?)$/.test(e))) return "Template files";
9343
+ if (exts.some((e) => /\.(proto)$/.test(e))) return "Protocol buffer definitions";
9344
+ }
9345
+ if (context.technologies) {
9346
+ if (context.technologies.some((t) => /react|vue|svelte|angular/.test(t))) return "UI components";
9347
+ if (context.technologies.some((t) => /express|fastify|flask|gin/.test(t))) return "Server handlers";
9348
+ }
9349
+ }
9350
+ return `${capitalize(dirName)} module`;
9351
+ }
9352
+ function inferDataFlowFromGraph(features, importGraph) {
9353
+ const names = features.map((f) => f.name);
9354
+ if (importGraph && importGraph.size > 0) {
9355
+ const flow = inferFlowFromTopology(features, importGraph);
9356
+ if (flow.length >= 2) return flow;
9357
+ }
9358
+ return inferFlowFromNames(names);
9359
+ }
9360
+ function inferFlowFromTopology(features, importGraph) {
9361
+ const featurePathMap = /* @__PURE__ */ new Map();
9362
+ for (const f of features) {
9363
+ for (const p of f.paths) {
9364
+ const clean = p.replace("/**", "");
9365
+ featurePathMap.set(clean, f.name);
9366
+ }
9367
+ }
9368
+ const edges = /* @__PURE__ */ new Map();
9369
+ for (const [file2, imports] of importGraph) {
9370
+ const sourceFeature = findFeatureForFile(file2, featurePathMap);
9371
+ if (!sourceFeature) continue;
9372
+ for (const imp of imports) {
9373
+ const targetFeature = findFeatureForFile(imp, featurePathMap);
9374
+ if (!targetFeature || targetFeature === sourceFeature) continue;
9375
+ if (!edges.has(sourceFeature)) edges.set(sourceFeature, /* @__PURE__ */ new Map());
9376
+ const edgeMap = edges.get(sourceFeature);
9377
+ edgeMap.set(targetFeature, (edgeMap.get(targetFeature) || 0) + 1);
9378
+ }
9379
+ }
9380
+ const inDegree = /* @__PURE__ */ new Map();
9381
+ const outDegree = /* @__PURE__ */ new Map();
9382
+ for (const f of features) {
9383
+ inDegree.set(f.name, 0);
9384
+ outDegree.set(f.name, 0);
9385
+ }
9386
+ for (const [source, targets] of edges) {
9387
+ for (const [target, weight] of targets) {
9388
+ inDegree.set(target, (inDegree.get(target) || 0) + weight);
9389
+ outDegree.set(source, (outDegree.get(source) || 0) + weight);
9390
+ }
9391
+ }
9392
+ const sorted = features.map((f) => ({
9393
+ name: f.name,
9394
+ score: (outDegree.get(f.name) || 0) - (inDegree.get(f.name) || 0)
9395
+ })).sort((a, b) => b.score - a.score).map((f) => capitalize(f.name));
9396
+ return sorted.slice(0, 6);
9397
+ }
9398
+ function findFeatureForFile(file2, featurePathMap) {
9399
+ for (const [path, feature] of featurePathMap) {
9400
+ if (file2.startsWith(path)) return feature;
9401
+ }
9402
+ return null;
9403
+ }
9404
+ function inferFlowFromNames(names) {
9405
+ const flow = [];
9406
+ const isFrontend = names.some((n) => /^(components?|pages?|views?|hooks?|widgets?)$/.test(n));
9407
+ if (isFrontend) {
9408
+ flow.push("User");
9409
+ if (names.some((n) => /^(pages?|views?)$/.test(n))) flow.push("Pages");
9410
+ if (names.some((n) => /^(components?|widgets?)$/.test(n))) flow.push("Components");
9411
+ if (names.some((n) => /^hooks?$/.test(n))) flow.push("Hooks");
9412
+ if (names.some((n) => /^services?$/.test(n))) flow.push("Services");
9413
+ if (names.some((n) => /^(stores?|state)$/.test(n))) flow.push("Store");
9414
+ return flow.length >= 2 ? flow : [];
9415
+ }
9416
+ if (names.some((n) => /^(server|api)$/.test(n))) flow.push("Request");
9417
+ if (names.includes("server")) flow.push("Server");
9418
+ if (names.includes("api")) flow.push("API");
9419
+ if (names.some((n) => /^(controllers?|handlers?)$/.test(n))) flow.push("Controllers");
9420
+ if (names.includes("core")) flow.push("Core");
9421
+ if (names.some((n) => /^services?$/.test(n))) flow.push("Services");
9422
+ if (names.some((n) => /^(storage|db|database)$/.test(n))) flow.push("Storage");
9423
+ if (names.some((n) => /^(indexing|search)$/.test(n))) flow.push("Indexer");
9424
+ if (names.some((n) => /^(cmd|cli)$/.test(n)) && flow.length === 0) {
9425
+ flow.push("CLI");
9426
+ if (names.includes("core")) flow.push("Core");
9427
+ if (names.some((n) => /^(pkg|lib)$/.test(n))) flow.push("Lib");
9428
+ }
9429
+ return flow.length >= 2 ? flow : [];
9430
+ }
9431
+ function inferScopeLabel(scope, memberCount, researchDir) {
9432
+ const hardcoded = SCOPE_LABELS[scope];
9433
+ if (hardcoded) return hardcoded;
9434
+ if (researchDir) {
9435
+ try {
9436
+ if (existsSync25(researchDir)) {
9437
+ const files = readdirSync7(researchDir);
9438
+ const scopeClean = scope.replace("@", "");
9439
+ const match = files.find((f) => f.startsWith(scopeClean));
9440
+ if (match) {
9441
+ const content = readFileSync20(join25(researchDir, match), "utf-8");
9442
+ const titleMatch = content.match(/^#\s+(.+?)(?:\s+—|\s+v)/m);
9443
+ if (titleMatch?.[1]) return titleMatch[1];
9444
+ }
9445
+ }
9446
+ } catch {
9447
+ }
9448
+ }
9449
+ return `${scope} (${memberCount} packages)`;
9450
+ }
9451
+ function inferDocSource(packageName, source) {
9452
+ for (const entry of DOC_SOURCE_REGISTRY) {
9453
+ if (entry.packageNames.includes(packageName)) return entry;
9454
+ }
9455
+ const ecosystem = detectEcosystem(packageName, source);
9456
+ switch (ecosystem) {
9457
+ case "npm":
9458
+ return {
9459
+ packageNames: [packageName],
9460
+ docsUrl: `https://www.npmjs.com/package/${packageName}`
9461
+ };
9462
+ case "go":
9463
+ return {
9464
+ packageNames: [packageName],
9465
+ docsUrl: `https://pkg.go.dev/${packageName}`
9466
+ };
9467
+ case "rust":
9468
+ return {
9469
+ packageNames: [packageName],
9470
+ docsUrl: `https://docs.rs/${packageName}`
9471
+ };
9472
+ case "python":
9473
+ return {
9474
+ packageNames: [packageName],
9475
+ docsUrl: `https://pypi.org/project/${packageName}`
9476
+ };
9477
+ case "ruby":
9478
+ return {
9479
+ packageNames: [packageName],
9480
+ docsUrl: `https://rubygems.org/gems/${packageName}`
9481
+ };
9482
+ case "java":
9483
+ return {
9484
+ packageNames: [packageName],
9485
+ docsUrl: `https://mvnrepository.com/artifact/${packageName}`
9486
+ };
9487
+ case "dotnet":
9488
+ return {
9489
+ packageNames: [packageName],
9490
+ docsUrl: `https://www.nuget.org/packages/${packageName}`
9491
+ };
9492
+ default:
9493
+ return null;
9494
+ }
9495
+ }
9496
+ function detectEcosystem(packageName, source) {
9497
+ if (source) {
9498
+ if (/package\.json|package-lock|yarn\.lock|pnpm-lock|bun\.lock/.test(source)) return "npm";
9499
+ if (/go\.mod|go\.sum/.test(source)) return "go";
9500
+ if (/Cargo\.toml|Cargo\.lock/.test(source)) return "rust";
9501
+ if (/requirements\.txt|setup\.py|pyproject\.toml|Pipfile|poetry\.lock/.test(source)) return "python";
9502
+ if (/Gemfile|\.gemspec/.test(source)) return "ruby";
9503
+ if (/pom\.xml|build\.gradle/.test(source)) return "java";
9504
+ if (/\.csproj|\.sln|nuget/.test(source)) return "dotnet";
9505
+ }
9506
+ if (packageName.startsWith("@") || /^[a-z][\w.-]*$/.test(packageName)) return "npm";
9507
+ if (packageName.includes("/") && !packageName.startsWith("@")) return "go";
9508
+ return "unknown";
9509
+ }
9510
+ function extractRulesFromResearch(tech, researchDir) {
9511
+ const result = { rules: [], pitfalls: [] };
9512
+ const safeName = tech.name.replace(/^@/, "").replace(/\//g, "__");
9513
+ const candidates = [
9514
+ join25(researchDir, `${safeName}@${tech.version}.md`),
9515
+ join25(researchDir, `${tech.name}@${tech.version}.md`)
9516
+ ];
9517
+ let content = null;
9518
+ for (const candidate of candidates) {
9519
+ if (existsSync25(candidate)) {
9520
+ try {
9521
+ content = readFileSync20(candidate, "utf-8");
9522
+ break;
9523
+ } catch {
9524
+ }
9525
+ }
9526
+ }
9527
+ if (!content) {
9528
+ try {
9529
+ if (existsSync25(researchDir)) {
9530
+ const files = readdirSync7(researchDir);
9531
+ const match = files.find((f) => f.startsWith(`${safeName}@`));
9532
+ if (match) {
9533
+ content = readFileSync20(join25(researchDir, match), "utf-8");
9534
+ }
9535
+ }
9536
+ } catch {
9537
+ }
9538
+ }
9539
+ if (!content) return result;
9540
+ const trustMatch = content.match(/trust_score:\s*([\d.]+)/);
9541
+ if (trustMatch) {
9542
+ const trustScore = parseFloat(trustMatch[1]);
9543
+ if (trustScore < 0.5) return result;
9544
+ }
9545
+ const apiRules = extractBulletPoints(content, "Key API Patterns");
9546
+ result.rules.push(...apiRules.slice(0, 5));
9547
+ const pitfalls = extractBulletPoints(content, "Common Pitfalls");
9548
+ result.pitfalls.push(...pitfalls.slice(0, 5));
9549
+ const breakingChanges = extractBulletPoints(content, "Breaking Changes");
9550
+ result.pitfalls.push(...breakingChanges.slice(0, 3));
9551
+ return result;
9552
+ }
9553
+ function extractBulletPoints(content, sectionName) {
9554
+ const lines = content.split("\n");
9555
+ const points = [];
9556
+ let inSection = false;
9557
+ for (const line of lines) {
9558
+ if (line.match(new RegExp(`^##\\s+.*${escapeRegex2(sectionName)}`, "i"))) {
9559
+ inSection = true;
9560
+ continue;
9561
+ }
9562
+ if (inSection && line.match(/^##\s/)) {
9563
+ break;
9564
+ }
9565
+ if (inSection) {
9566
+ const bulletMatch = line.match(/^[-*]\s+(.+)/);
9567
+ if (bulletMatch?.[1]) {
9568
+ const text = bulletMatch[1].trim();
9569
+ if (text.length > 10 && text.length < 200) {
9570
+ points.push(text);
9571
+ }
9572
+ }
9573
+ }
9574
+ }
9575
+ return points;
9576
+ }
9577
+ function escapeRegex2(str) {
9578
+ return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
9579
+ }
9580
+ function classifyTechnology(tech) {
9581
+ const name = tech.name.toLowerCase();
9582
+ 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";
9583
+ if (/^(react|vue|svelte|angular|solid|preact|lit|qwik|next|nuxt|gatsby|remix|astro|sveltekit)$/.test(name)) return "ui-framework";
9584
+ if (/prisma|typeorm|sqlalchemy|diesel|gorm|sequelize|mongoose|drizzle|knex|bookshelf|objection|mikro-orm|ecto/.test(name)) return "orm";
9585
+ if (/vitest|jest|pytest|mocha|jasmine|chai|supertest|testing-library|playwright|cypress|selenium/.test(name)) return "testing";
9586
+ if (/passport|jsonwebtoken|jwt|oauth|bcrypt|argon2|lucia|next-auth|auth0|clerk|supertokens/.test(name)) return "auth";
9587
+ if (/stripe|paypal|braintree|square|adyen|mollie/.test(name)) return "payment";
9588
+ if (/vite|webpack|esbuild|rollup|parcel|turbopack|swc|babel|tsc/.test(name)) return "build-tool";
9589
+ if (/zustand|redux|mobx|jotai|recoil|pinia|vuex|xstate|ngrx/.test(name)) return "state-management";
9590
+ if (/tailwind|styled-components|emotion|css-modules|sass|less|postcss|bootstrap|bulma/.test(name)) return "css-framework";
9591
+ if (/^(zod|yup|joi|ajv|superstruct|io-ts|valibot|typebox)$/.test(name)) return "validation";
9592
+ if (/^(axios|got|ky|node-fetch|undici|superagent|request)$/.test(name)) return "api-client";
9593
+ if (/better-sqlite3|pg|mysql2|redis|ioredis|mongodb|mariadb|sqlite3|tedious/.test(name)) return "database-driver";
9594
+ if (/winston|pino|bunyan|log4js|morgan|loglevel|consola/.test(name)) return "logging";
9595
+ return "general";
9596
+ }
9597
+ function deriveFeatureRules(feature, technologies, researchDir) {
9598
+ const rules = [];
9599
+ if (WELL_KNOWN_FEATURES.has(feature.name)) {
9600
+ const nameRules = FEATURE_NAME_RULES[feature.name];
9601
+ if (nameRules) rules.push(...nameRules);
9602
+ const techRules = [];
9603
+ for (const tech of technologies) {
9604
+ const inferred = inferTechRulesAndPitfalls(tech, researchDir);
9605
+ techRules.push(...inferred.rules);
9606
+ }
9607
+ for (const tr of techRules.slice(0, 2)) {
9608
+ if (!rules.some((r) => r.includes(tr.split(" ")[0] || ""))) {
9609
+ rules.push(tr);
9610
+ }
9611
+ }
9612
+ } else {
9613
+ for (const tech of technologies) {
9614
+ const inferred = inferTechRulesAndPitfalls(tech, researchDir);
9615
+ rules.push(...inferred.rules);
9616
+ }
9617
+ if (rules.length === 0) {
9618
+ const category = classifyFeature(feature);
9619
+ const categoryRules = FEATURE_CATEGORY_RULES[category];
9620
+ if (categoryRules) {
9621
+ rules.push(...categoryRules);
9622
+ } else {
9623
+ const nameRules = FEATURE_NAME_RULES[feature.name];
9624
+ rules.push(...nameRules || [
9625
+ "Follow existing patterns in this module for consistency",
9626
+ "Export public API from index file \u2014 keep internal helpers unexported"
9627
+ ]);
9628
+ }
9629
+ }
9630
+ }
9631
+ if (feature.paths.length > 0) {
9632
+ const scope = feature.paths[0]?.replace("/**", "") || "";
9633
+ rules.push(`Changes here should not import from other feature directories \u2014 keep ${scope} self-contained`);
9634
+ }
9635
+ return rules;
9636
+ }
9637
+ function deriveFeaturePitfalls(feature, technologies, researchDir) {
9638
+ const pitfalls = [];
9639
+ if (WELL_KNOWN_FEATURES.has(feature.name)) {
9640
+ const namePitfalls = FEATURE_NAME_PITFALLS[feature.name];
9641
+ if (namePitfalls) pitfalls.push(...namePitfalls);
9642
+ for (const tech of technologies) {
9643
+ const inferred = inferTechRulesAndPitfalls(tech, researchDir);
9644
+ for (const p of inferred.pitfalls.slice(0, 1)) {
9645
+ if (!pitfalls.includes(p)) pitfalls.push(p);
9646
+ }
9647
+ }
9648
+ } else {
9649
+ for (const tech of technologies) {
9650
+ const inferred = inferTechRulesAndPitfalls(tech, researchDir);
9651
+ pitfalls.push(...inferred.pitfalls);
9652
+ }
9653
+ if (pitfalls.length === 0) {
9654
+ const namePitfalls = FEATURE_NAME_PITFALLS[feature.name];
9655
+ if (namePitfalls) {
9656
+ pitfalls.push(...namePitfalls);
9657
+ } else {
9658
+ const category = classifyFeature(feature);
9659
+ const categoryPitfalls = FEATURE_CATEGORY_PITFALLS[category];
9660
+ if (categoryPitfalls) {
9661
+ pitfalls.push(...categoryPitfalls);
9662
+ } else {
9663
+ pitfalls.push(
9664
+ "Check for null/undefined before property access on external data",
9665
+ "Changing exports may break other modules that depend on this feature"
9666
+ );
9667
+ }
9668
+ }
9669
+ }
9670
+ }
9671
+ return pitfalls;
9672
+ }
9673
+ function capitalize(str) {
9674
+ return str.charAt(0).toUpperCase() + str.slice(1).replace(/-/g, " ");
9675
+ }
9676
+ var CATEGORY_RULES, FEATURE_CATEGORY_RULES, FEATURE_CATEGORY_PITFALLS;
9677
+ var init_universal_inference = __esm({
9678
+ "src/core/agents/universal-inference.ts"() {
9679
+ "use strict";
9680
+ init_hardcoded_knowledge();
9681
+ CATEGORY_RULES = {
9682
+ "web-framework": {
9683
+ rules: [
9684
+ "Validate all user inputs at the boundary \u2014 never trust request data",
9685
+ "Use middleware for cross-cutting concerns (auth, logging, CORS)",
9686
+ "Return consistent error response shapes across all endpoints"
9687
+ ],
9688
+ pitfalls: [
9689
+ "Unhandled async errors crash the server \u2014 always use error middleware",
9690
+ "Missing input validation leads to injection vulnerabilities"
9691
+ ]
9692
+ },
9693
+ "ui-framework": {
9694
+ rules: [
9695
+ "Components should be pure \u2014 same props must produce same output",
9696
+ "Use composition over inheritance \u2014 prefer small, focused components",
9697
+ "Keep components focused on one responsibility"
9698
+ ],
9699
+ pitfalls: [
9700
+ "Mutating state directly causes rendering bugs \u2014 always create new references",
9701
+ "Missing key props in lists causes reconciliation bugs"
9702
+ ]
9703
+ },
9704
+ "orm": {
9705
+ rules: [
9706
+ "Use migrations for all schema changes \u2014 never modify production DB directly",
9707
+ "Use transactions for multi-table operations",
9708
+ "Select only needed fields to avoid over-fetching"
9709
+ ],
9710
+ pitfalls: [
9711
+ "N+1 query problem \u2014 use eager loading or batch queries for relations",
9712
+ "Forgetting to run migrations after schema changes causes runtime errors"
9713
+ ]
9714
+ },
9715
+ "testing": {
9716
+ rules: [
9717
+ "Tests should be deterministic \u2014 no reliance on external services or timing",
9718
+ "Clean up test state between runs to prevent flaky failures",
9719
+ "Use descriptive test names that explain the expected behavior"
9720
+ ],
9721
+ pitfalls: [
9722
+ "Shared mutable state between tests causes flaky failures",
9723
+ "Mocking too much makes tests pass but misses real integration bugs"
9724
+ ]
9725
+ },
9726
+ "auth": {
9727
+ rules: [
9728
+ "Never store plain-text passwords \u2014 use bcrypt or argon2",
9729
+ "Set explicit token expiration \u2014 never issue non-expiring tokens",
9730
+ "Validate tokens on every request \u2014 never trust client-side auth state"
9731
+ ],
9732
+ pitfalls: [
9733
+ "Using weak algorithms (MD5, SHA1) for password hashing is a security vulnerability",
9734
+ "Not revoking tokens on logout allows session reuse"
9735
+ ]
9736
+ },
9737
+ "payment": {
9738
+ rules: [
9739
+ "Always verify webhook signatures before processing payment events",
9740
+ "Use idempotency keys for payment operations to prevent double-charges",
9741
+ "Log all payment events for audit trails"
9742
+ ],
9743
+ pitfalls: [
9744
+ "Webhook events may arrive out of order \u2014 handle idempotently",
9745
+ "Not handling declined payments gracefully shows raw errors to users"
9746
+ ]
9747
+ },
9748
+ "build-tool": {
9749
+ rules: [
9750
+ "Configure source maps for debugging in development",
9751
+ "Set up separate dev/prod build configurations"
9752
+ ],
9753
+ pitfalls: [
9754
+ "Large bundle sizes slow page load \u2014 use code splitting and tree shaking",
9755
+ "Misconfigured output paths overwrite source files"
9756
+ ]
9757
+ },
9758
+ "state-management": {
9759
+ rules: [
9760
+ "Keep store state minimal \u2014 derive computed values instead of storing them",
9761
+ "Use selectors to prevent unnecessary re-renders",
9762
+ "Keep store state serializable for debugging and persistence"
9763
+ ],
9764
+ pitfalls: [
9765
+ "Mutating state directly causes silent bugs \u2014 always use the update API",
9766
+ "Subscribing to entire store causes excessive re-renders"
9767
+ ]
9768
+ },
9769
+ "css-framework": {
9770
+ rules: [
9771
+ "Follow the framework's utility-first or component-based approach consistently",
9772
+ "Use conditional class merging utilities for dynamic styles"
9773
+ ],
9774
+ pitfalls: [
9775
+ "Dynamic class names may be purged in production \u2014 use full static class names",
9776
+ "Overriding framework styles with !important leads to unmaintainable CSS"
9777
+ ]
9778
+ },
9779
+ "validation": {
9780
+ rules: [
9781
+ "Define schemas once \u2014 derive types from schemas to keep them in sync",
9782
+ "Validate at system boundaries \u2014 user input, API responses, config files"
9783
+ ],
9784
+ pitfalls: [
9785
+ "Throwing on validation failure crashes the app \u2014 use safe parse methods in handlers",
9786
+ "Missing optional field validation causes runtime errors on undefined access"
9787
+ ]
9788
+ },
9789
+ "api-client": {
9790
+ rules: [
9791
+ "Set request timeouts to prevent hanging on unresponsive servers",
9792
+ "Handle network errors and HTTP errors separately"
9793
+ ],
9794
+ pitfalls: [
9795
+ "Not handling network errors shows cryptic errors to users",
9796
+ "Forgetting to set Content-Type header causes request parsing failures"
9797
+ ]
9798
+ },
9799
+ "database-driver": {
9800
+ rules: [
9801
+ "Use parameterized queries \u2014 never concatenate user input into SQL",
9802
+ "Use connection pooling for concurrent requests",
9803
+ "Close connections properly to prevent resource leaks"
9804
+ ],
9805
+ pitfalls: [
9806
+ "SQL injection from string concatenation \u2014 always use parameterized queries",
9807
+ "Not closing connections leaks file handles or socket connections"
9808
+ ]
9809
+ },
9810
+ "logging": {
9811
+ rules: [
9812
+ "Use structured logging (JSON) for machine-parseable log output",
9813
+ "Set appropriate log levels \u2014 debug in dev, info/warn in production"
9814
+ ],
9815
+ pitfalls: [
9816
+ "Logging sensitive data (passwords, tokens) is a security risk",
9817
+ "Synchronous logging in hot paths impacts performance"
9818
+ ]
9819
+ },
9820
+ "general": {
9821
+ rules: [
9822
+ "Follow existing patterns in this module for consistency",
9823
+ "Pin dependency versions to avoid unexpected breaking changes"
9824
+ ],
9825
+ pitfalls: [
9826
+ "Check changelog when upgrading for breaking changes",
9827
+ "Ensure error handling covers library-specific error types"
9828
+ ]
9829
+ }
9830
+ };
9831
+ FEATURE_CATEGORY_RULES = {
9832
+ "api-layer": [
9833
+ "All endpoints must validate request bodies/params before processing",
9834
+ "Return consistent error response shapes across all endpoints"
9835
+ ],
9836
+ "data-layer": [
9837
+ "All database access should go through this module \u2014 no direct imports elsewhere",
9838
+ "Use transactions for multi-step operations to ensure consistency"
9839
+ ],
9840
+ "business-logic": [
9841
+ "Core modules should have no side effects on import",
9842
+ "Export types alongside functions for downstream consumers"
9843
+ ],
9844
+ "ui-components": [
9845
+ "Components should be pure \u2014 derive UI from props, avoid internal side effects",
9846
+ "Use composition over inheritance \u2014 prefer small, focused components"
9847
+ ],
9848
+ "state-management": [
9849
+ "Keep store state minimal \u2014 derive computed values instead of storing them",
9850
+ "Actions should be thin \u2014 delegate complex logic to services"
9851
+ ],
9852
+ "testing": [
9853
+ "Tests should be deterministic \u2014 no reliance on external services or timing",
9854
+ "Clean up temporary files and directories in teardown hooks"
9855
+ ],
9856
+ "cli": [
9857
+ "Validate all command-line arguments before processing",
9858
+ "Provide helpful error messages with usage hints on invalid input"
9859
+ ],
9860
+ "auth": [
9861
+ "Never store plain-text passwords \u2014 use bcrypt or argon2",
9862
+ "Validate and sanitize all user inputs before processing"
9863
+ ],
9864
+ "documentation": [
9865
+ "Generated docs must be kept in sync with source code changes",
9866
+ "Use relative paths for internal links"
9867
+ ],
9868
+ "infrastructure": [
9869
+ "Configuration should be environment-aware (dev/staging/prod)",
9870
+ "Scripts should be idempotent \u2014 safe to run multiple times"
9871
+ ],
9872
+ "utility": [
9873
+ "Utility functions should be pure \u2014 no side effects",
9874
+ "Export public API from index file \u2014 keep internal helpers unexported"
9875
+ ],
9876
+ "generic": [
9877
+ "Follow existing patterns in this module for consistency",
9878
+ "Export public API from index file \u2014 keep internal helpers unexported"
9879
+ ]
9880
+ };
9881
+ FEATURE_CATEGORY_PITFALLS = {
9882
+ "api-layer": [
9883
+ "Unhandled async errors crash the server \u2014 always catch errors in handlers",
9884
+ "Missing input validation leads to injection vulnerabilities"
9885
+ ],
9886
+ "data-layer": [
9887
+ "Forgetting to close connections leaks file handles",
9888
+ "Concurrent writes without transactions may cause data corruption"
9889
+ ],
9890
+ "business-logic": [
9891
+ "Circular imports between core modules cause runtime errors \u2014 check dependency direction",
9892
+ "Changing public API signatures breaks downstream consumers"
9893
+ ],
9894
+ "ui-components": [
9895
+ "Missing key prop in lists causes reconciliation bugs \u2014 always use stable keys",
9896
+ "Direct DOM manipulation bypasses the framework \u2014 use refs only when necessary"
9897
+ ],
9898
+ "state-management": [
9899
+ "Mutating state directly causes silent bugs \u2014 always return new references",
9900
+ "Large store updates trigger unnecessary re-renders \u2014 split into focused slices"
9901
+ ],
9902
+ "testing": [
9903
+ "Tests sharing mutable state between runs cause flaky failures",
9904
+ "Temp directories not cleaned up fill disk over repeated test runs"
9905
+ ],
9906
+ "cli": [
9907
+ "Missing error handling on subprocess execution causes silent failures",
9908
+ "Not quoting file paths breaks on paths with spaces"
9909
+ ],
9910
+ "auth": [
9911
+ "Using weak hashing algorithms is a security vulnerability",
9912
+ "Not revoking tokens on logout allows session reuse"
9913
+ ],
9914
+ "documentation": [
9915
+ "Stale documentation is worse than no documentation",
9916
+ "Broken internal links confuse users \u2014 validate links on changes"
9917
+ ],
9918
+ "infrastructure": [
9919
+ "Hardcoded secrets in config files are a security risk \u2014 use environment variables",
9920
+ "Non-idempotent scripts cause issues on re-run"
9921
+ ],
9922
+ "utility": [
9923
+ "Changing utility signatures breaks all callers \u2014 check usage before modifying",
9924
+ "Missing error handling in utilities propagates errors to all consumers"
9925
+ ],
9926
+ "generic": [
9927
+ "Check for null/undefined before property access on external data",
9928
+ "Changing exports may break other modules that depend on this feature"
9929
+ ]
9930
+ };
9931
+ }
9932
+ });
9933
+
9934
+ // src/core/agents/research-engine.ts
9935
+ import { existsSync as existsSync26, readFileSync as readFileSync21, writeFileSync as writeFileSync15, mkdirSync as mkdirSync15, readdirSync as readdirSync8 } from "fs";
9936
+ import { join as join26 } from "path";
8669
9937
  async function researchTechnology(projectPath, tech, options) {
8670
9938
  const paths = getAgentWorkspacePaths(projectPath);
8671
9939
  const safeName = tech.name.replace(/^@/, "").replace(/\//g, "__");
8672
9940
  const fileName = `${safeName}@${tech.version}.md`;
8673
- const filePath = join25(paths.researchDir, fileName);
9941
+ const filePath = join26(paths.researchDir, fileName);
8674
9942
  const relPath = `research/${fileName}`;
8675
- if (!options.force && existsSync25(filePath)) {
9943
+ if (!options.force && existsSync26(filePath)) {
8676
9944
  const existing = readResearchFile(filePath);
8677
9945
  if (existing && !isStale(existing, options.cadenceHours)) {
8678
9946
  return { technology: tech.name, version: tech.version, file: relPath, status: "cached" };
8679
9947
  }
8680
9948
  }
8681
- const docSource = findDocSource(tech.name);
9949
+ const docSource = inferDocSource(tech.name, tech.source);
8682
9950
  if (!docSource) {
8683
9951
  const stub = generateStubResearch(tech);
8684
9952
  mkdirSync15(paths.researchDir, { recursive: true });
@@ -8688,10 +9956,10 @@ async function researchTechnology(projectPath, tech, options) {
8688
9956
  try {
8689
9957
  const fetchFn = options.fetchFn || defaultFetch;
8690
9958
  const content = await fetchAndDistill(tech, docSource, fetchFn, options.maxTokensPerTech);
9959
+ const isNew = !existsSync26(filePath);
8691
9960
  mkdirSync15(paths.researchDir, { recursive: true });
8692
9961
  writeFileSync15(filePath, content);
8693
9962
  const tokenCount = estimateTokens4(content);
8694
- const isNew = !existsSync25(filePath);
8695
9963
  return {
8696
9964
  technology: tech.name,
8697
9965
  version: tech.version,
@@ -8700,7 +9968,7 @@ async function researchTechnology(projectPath, tech, options) {
8700
9968
  tokenCount
8701
9969
  };
8702
9970
  } catch (err) {
8703
- if (!existsSync25(filePath)) {
9971
+ if (!existsSync26(filePath)) {
8704
9972
  const stub = generateStubResearch(tech);
8705
9973
  mkdirSync15(paths.researchDir, { recursive: true });
8706
9974
  writeFileSync15(filePath, stub);
@@ -8722,14 +9990,6 @@ async function researchAllTechnologies(projectPath, technologies, options) {
8722
9990
  }
8723
9991
  return results;
8724
9992
  }
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
9993
  async function fetchAndDistill(tech, docSource, fetchFn, maxTokens) {
8734
9994
  const urls = [docSource.docsUrl];
8735
9995
  if (docSource.apiRefUrl && docSource.apiRefUrl !== docSource.docsUrl) {
@@ -8895,7 +10155,7 @@ function generateStubResearch(tech) {
8895
10155
  }
8896
10156
  function readResearchFile(filePath) {
8897
10157
  try {
8898
- const content = readFileSync20(filePath, "utf-8");
10158
+ const content = readFileSync21(filePath, "utf-8");
8899
10159
  const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---/);
8900
10160
  if (!frontmatterMatch) return null;
8901
10161
  const fm = frontmatterMatch[1] || "";
@@ -8920,16 +10180,16 @@ function readResearchFile(filePath) {
8920
10180
  function getResearchContent(projectPath, technology, version2) {
8921
10181
  const paths = getAgentWorkspacePaths(projectPath);
8922
10182
  if (version2) {
8923
- const exactPath = join25(paths.researchDir, `${technology}@${version2}.md`);
8924
- if (existsSync25(exactPath)) {
8925
- return readFileSync20(exactPath, "utf-8");
10183
+ const exactPath = join26(paths.researchDir, `${technology}@${version2}.md`);
10184
+ if (existsSync26(exactPath)) {
10185
+ return readFileSync21(exactPath, "utf-8");
8926
10186
  }
8927
10187
  }
8928
- if (existsSync25(paths.researchDir)) {
8929
- const files = readdirSync7(paths.researchDir);
10188
+ if (existsSync26(paths.researchDir)) {
10189
+ const files = readdirSync8(paths.researchDir);
8930
10190
  const match = files.find((f) => f.startsWith(`${technology}@`));
8931
10191
  if (match) {
8932
- return readFileSync20(join25(paths.researchDir, match), "utf-8");
10192
+ return readFileSync21(join26(paths.researchDir, match), "utf-8");
8933
10193
  }
8934
10194
  }
8935
10195
  return null;
@@ -8992,114 +10252,12 @@ function htmlToMarkdown(html) {
8992
10252
  text = text.trim();
8993
10253
  return text;
8994
10254
  }
8995
- var DOC_SOURCE_REGISTRY;
8996
10255
  var init_research_engine = __esm({
8997
10256
  "src/core/agents/research-engine.ts"() {
8998
10257
  "use strict";
8999
10258
  init_workspace2();
9000
10259
  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
- ];
10260
+ init_universal_inference();
9103
10261
  }
9104
10262
  });
9105
10263
 
@@ -9431,8 +10589,8 @@ var init_diagnosis_table = __esm({
9431
10589
  });
9432
10590
 
9433
10591
  // 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";
10592
+ import { existsSync as existsSync27, readFileSync as readFileSync22, writeFileSync as writeFileSync16, readdirSync as readdirSync9 } from "fs";
10593
+ import { join as join27 } from "path";
9436
10594
  function learnFromOutcome(db, projectPath, outcome) {
9437
10595
  if (outcome.result === "success") {
9438
10596
  confirmRelatedLessons(projectPath, outcome);
@@ -9602,7 +10760,7 @@ function promoteLessons(db, projectPath) {
9602
10760
  const agentFiles = findAgentFiles(paths);
9603
10761
  const skillFiles = findSkillFiles(paths);
9604
10762
  for (const filePath of agentFiles) {
9605
- const content = readFileSync21(filePath, "utf-8");
10763
+ const content = readFileSync22(filePath, "utf-8");
9606
10764
  if (!content.includes("## Lessons Learned")) continue;
9607
10765
  const lessonsMatch = content.match(/## Lessons Learned\n([\s\S]*?)(?=\n##|\n<!-- |$)/);
9608
10766
  if (!lessonsMatch || !lessonsMatch[1]) continue;
@@ -9614,8 +10772,8 @@ function promoteLessons(db, projectPath) {
9614
10772
  const confirmations = countConfirmations(db, fingerprint);
9615
10773
  if (confirmations >= 3) {
9616
10774
  const featureName = extractFeatureFromPath(filePath);
9617
- const skillPath = featureName ? join26(paths.featuresDir, featureName, "SKILL.md") : join26(paths.projectDir, "SKILL.md");
9618
- if (existsSync26(skillPath)) {
10775
+ const skillPath = featureName ? join27(paths.featuresDir, featureName, "SKILL.md") : join27(paths.projectDir, "SKILL.md");
10776
+ if (existsSync27(skillPath)) {
9619
10777
  const ruleAdded = addRuleToSkill(skillPath, lessonContent, config2);
9620
10778
  if (ruleAdded) {
9621
10779
  const updatedContent = content.replace(lesson, `${lesson} [promoted]`);
@@ -9634,9 +10792,9 @@ function diagnoseFailure(failure, db, projectPath) {
9634
10792
  const isInScope = (filePath, agentName) => {
9635
10793
  const paths = getAgentWorkspacePaths(projectPath);
9636
10794
  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");
10795
+ const agentPath = join27(paths.featuresDir, name, "AGENT.md");
10796
+ if (!existsSync27(agentPath)) return true;
10797
+ const agentContent = readFileSync22(agentPath, "utf-8");
9640
10798
  return fileMatchesAgentScope(filePath, agentContent);
9641
10799
  };
9642
10800
  const ctx = {
@@ -9662,10 +10820,10 @@ function fileMatchesAgentScope(filePath, agentMdContent) {
9662
10820
  function patchSkillWithFix(projectPath, outcome, diagnosis, config2) {
9663
10821
  const paths = getAgentWorkspacePaths(projectPath);
9664
10822
  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");
10823
+ const featureSkillPath = join27(paths.featuresDir, agentName, "SKILL.md");
10824
+ const targetPath = existsSync27(featureSkillPath) ? featureSkillPath : join27(paths.projectDir, "SKILL.md");
10825
+ if (!existsSync27(targetPath)) return null;
10826
+ const content = readFileSync22(targetPath, "utf-8");
9669
10827
  const pitfallEntry = `- ${diagnosis.description.slice(0, 150)} \u2192 Fix: ${outcome.fixApplied.slice(0, 100)}`;
9670
10828
  if (!content.includes(config2.markers.start)) return null;
9671
10829
  const startIdx = content.indexOf(config2.markers.start);
@@ -9708,9 +10866,9 @@ function identifyAffectedTechnologies(outcome, projectPath) {
9708
10866
  techs.push(pkg);
9709
10867
  }
9710
10868
  }
9711
- if (existsSync26(paths.researchDir)) {
10869
+ if (existsSync27(paths.researchDir)) {
9712
10870
  try {
9713
- const researchFiles = readdirSync8(paths.researchDir);
10871
+ const researchFiles = readdirSync9(paths.researchDir);
9714
10872
  for (const file2 of researchFiles) {
9715
10873
  const techName = file2.replace(/@.*\.md$/, "");
9716
10874
  if (outcome.errorMessage && outcome.errorMessage.toLowerCase().includes(techName.toLowerCase())) {
@@ -9733,9 +10891,9 @@ function confirmRelatedLessons(projectPath, outcome) {
9733
10891
  if (outcome.relatedSkills.length === 0) return;
9734
10892
  const paths = getAgentWorkspacePaths(projectPath);
9735
10893
  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");
10894
+ const agentPath = join27(paths.featuresDir, agentName, "AGENT.md");
10895
+ if (!existsSync27(agentPath)) return;
10896
+ const content = readFileSync22(agentPath, "utf-8");
9739
10897
  const taskWords = outcome.task.toLowerCase().split(/\W+/).filter((w) => w.length > 3);
9740
10898
  let updated = content;
9741
10899
  let changed = false;
@@ -9763,28 +10921,28 @@ function writeLesson(projectPath, failure, diagnosis, config2) {
9763
10921
  return null;
9764
10922
  case "scope-error": {
9765
10923
  const agentName = failure.agent.replace(/-agent$/, "");
9766
- targetPath = join26(paths.featuresDir, agentName, "AGENT.md");
10924
+ targetPath = join27(paths.featuresDir, agentName, "AGENT.md");
9767
10925
  break;
9768
10926
  }
9769
10927
  case "wrong-assumption":
9770
10928
  case "missing-test": {
9771
10929
  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");
10930
+ const featurePath = join27(paths.featuresDir, agentName, "AGENT.md");
10931
+ targetPath = existsSync27(featurePath) ? featurePath : join27(paths.projectDir, "AGENT.md");
9774
10932
  break;
9775
10933
  }
9776
10934
  case "missing-convention":
9777
- targetPath = join26(paths.projectDir, "AGENT.md");
10935
+ targetPath = join27(paths.projectDir, "AGENT.md");
9778
10936
  break;
9779
10937
  case "external-change":
9780
10938
  default:
9781
- targetPath = join26(paths.projectDir, "AGENT.md");
10939
+ targetPath = join27(paths.projectDir, "AGENT.md");
9782
10940
  break;
9783
10941
  }
9784
- if (!existsSync26(targetPath)) return null;
10942
+ if (!existsSync27(targetPath)) return null;
9785
10943
  const evidenceRef = failure.fixApplied ? ` Fix: ${failure.fixApplied.slice(0, 80)}` : "";
9786
10944
  const lessonText = `- ${today}: ${diagnosis.description.slice(0, 200)}${evidenceRef} (outcome: ${failure.id.slice(0, 8)})`;
9787
- const existing = readFileSync21(targetPath, "utf-8");
10945
+ const existing = readFileSync22(targetPath, "utf-8");
9788
10946
  const fingerprint = computeErrorFingerprint(diagnosis.description);
9789
10947
  if (existing.includes(fingerprint.slice(0, 30))) {
9790
10948
  return null;
@@ -9807,7 +10965,7 @@ function writeLesson(projectPath, failure, diagnosis, config2) {
9807
10965
  return targetPath;
9808
10966
  }
9809
10967
  function addRuleToSkill(skillPath, ruleContent, config2) {
9810
- const content = readFileSync21(skillPath, "utf-8");
10968
+ const content = readFileSync22(skillPath, "utf-8");
9811
10969
  if (!content.includes(config2.markers.start)) return false;
9812
10970
  const startIdx = content.indexOf(config2.markers.start);
9813
10971
  const endIdx = content.indexOf(config2.markers.end);
@@ -9885,7 +11043,7 @@ function decayOldLessons(projectPath, maxAgeDays = 90) {
9885
11043
  const cutoff = new Date(Date.now() - maxAgeDays * 24 * 60 * 60 * 1e3).toISOString().split("T")[0];
9886
11044
  const agentFiles = findAgentFiles(paths);
9887
11045
  for (const filePath of agentFiles) {
9888
- const content = readFileSync21(filePath, "utf-8");
11046
+ const content = readFileSync22(filePath, "utf-8");
9889
11047
  if (!content.includes(config2.markers.start)) continue;
9890
11048
  const updated = content.replace(
9891
11049
  /^(- \d{4}-\d{2}-\d{2}: .+?)(?<!\[unconfirmed\])(?<!\[confirmed\])(?<!\[promoted\])$/gm,
@@ -9906,14 +11064,14 @@ function decayOldLessons(projectPath, maxAgeDays = 90) {
9906
11064
  }
9907
11065
  function findAgentFiles(paths) {
9908
11066
  const files = [];
9909
- const superAgent = join26(paths.projectDir, "AGENT.md");
9910
- if (existsSync26(superAgent)) files.push(superAgent);
9911
- if (existsSync26(paths.featuresDir)) {
11067
+ const superAgent = join27(paths.projectDir, "AGENT.md");
11068
+ if (existsSync27(superAgent)) files.push(superAgent);
11069
+ if (existsSync27(paths.featuresDir)) {
9912
11070
  try {
9913
- const features = readdirSync8(paths.featuresDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
11071
+ const features = readdirSync9(paths.featuresDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
9914
11072
  for (const feature of features) {
9915
- const agentPath = join26(paths.featuresDir, feature, "AGENT.md");
9916
- if (existsSync26(agentPath)) files.push(agentPath);
11073
+ const agentPath = join27(paths.featuresDir, feature, "AGENT.md");
11074
+ if (existsSync27(agentPath)) files.push(agentPath);
9917
11075
  }
9918
11076
  } catch {
9919
11077
  }
@@ -9922,14 +11080,14 @@ function findAgentFiles(paths) {
9922
11080
  }
9923
11081
  function findSkillFiles(paths) {
9924
11082
  const files = [];
9925
- const projectSkill = join26(paths.projectDir, "SKILL.md");
9926
- if (existsSync26(projectSkill)) files.push(projectSkill);
9927
- if (existsSync26(paths.featuresDir)) {
11083
+ const projectSkill = join27(paths.projectDir, "SKILL.md");
11084
+ if (existsSync27(projectSkill)) files.push(projectSkill);
11085
+ if (existsSync27(paths.featuresDir)) {
9928
11086
  try {
9929
- const features = readdirSync8(paths.featuresDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
11087
+ const features = readdirSync9(paths.featuresDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
9930
11088
  for (const feature of features) {
9931
- const skillPath = join26(paths.featuresDir, feature, "SKILL.md");
9932
- if (existsSync26(skillPath)) files.push(skillPath);
11089
+ const skillPath = join27(paths.featuresDir, feature, "SKILL.md");
11090
+ if (existsSync27(skillPath)) files.push(skillPath);
9933
11091
  }
9934
11092
  } catch {
9935
11093
  }
@@ -10082,8 +11240,8 @@ var init_telemetry = __esm({
10082
11240
  });
10083
11241
 
10084
11242
  // src/core/agents/tech-detector.ts
10085
- import { existsSync as existsSync28, readFileSync as readFileSync23 } from "fs";
10086
- import { join as join29 } from "path";
11243
+ import { existsSync as existsSync29, readFileSync as readFileSync24 } from "fs";
11244
+ import { join as join30 } from "path";
10087
11245
  function detectTechnologies(projectPath) {
10088
11246
  const technologies = [];
10089
11247
  const seen = /* @__PURE__ */ new Set();
@@ -10111,23 +11269,23 @@ function detectTechnologies(projectPath) {
10111
11269
  return technologies;
10112
11270
  }
10113
11271
  function detectFromLockfiles(projectPath) {
10114
- const npmLock = join29(projectPath, "package-lock.json");
10115
- if (existsSync28(npmLock)) {
11272
+ const npmLock = join30(projectPath, "package-lock.json");
11273
+ if (existsSync29(npmLock)) {
10116
11274
  return parsePackageLock(npmLock);
10117
11275
  }
10118
- const pnpmLock = join29(projectPath, "pnpm-lock.yaml");
10119
- if (existsSync28(pnpmLock)) {
11276
+ const pnpmLock = join30(projectPath, "pnpm-lock.yaml");
11277
+ if (existsSync29(pnpmLock)) {
10120
11278
  return parsePnpmLock(pnpmLock);
10121
11279
  }
10122
- const yarnLock = join29(projectPath, "yarn.lock");
10123
- if (existsSync28(yarnLock)) {
11280
+ const yarnLock = join30(projectPath, "yarn.lock");
11281
+ if (existsSync29(yarnLock)) {
10124
11282
  return parseYarnLock(yarnLock);
10125
11283
  }
10126
11284
  return [];
10127
11285
  }
10128
11286
  function parsePackageLock(lockPath) {
10129
11287
  try {
10130
- const content = JSON.parse(readFileSync23(lockPath, "utf-8"));
11288
+ const content = JSON.parse(readFileSync24(lockPath, "utf-8"));
10131
11289
  const techs = [];
10132
11290
  if (content.packages) {
10133
11291
  for (const [key, pkg] of Object.entries(content.packages)) {
@@ -10162,7 +11320,7 @@ function parsePackageLock(lockPath) {
10162
11320
  }
10163
11321
  function parsePnpmLock(lockPath) {
10164
11322
  try {
10165
- const content = readFileSync23(lockPath, "utf-8");
11323
+ const content = readFileSync24(lockPath, "utf-8");
10166
11324
  const techs = [];
10167
11325
  const packageRegex = /^\s*[/'"]?(@?[^@\s'":]+)@(\d+\.\d+\.\d+[^'":]*)/gm;
10168
11326
  let match;
@@ -10187,7 +11345,7 @@ function parsePnpmLock(lockPath) {
10187
11345
  }
10188
11346
  function parseYarnLock(lockPath) {
10189
11347
  try {
10190
- const content = readFileSync23(lockPath, "utf-8");
11348
+ const content = readFileSync24(lockPath, "utf-8");
10191
11349
  const techs = [];
10192
11350
  const seen = /* @__PURE__ */ new Set();
10193
11351
  const lines = content.split("\n");
@@ -10221,10 +11379,10 @@ function parseYarnLock(lockPath) {
10221
11379
  }
10222
11380
  function detectFromManifests(projectPath) {
10223
11381
  const techs = [];
10224
- const pkgPath = join29(projectPath, "package.json");
10225
- if (existsSync28(pkgPath)) {
11382
+ const pkgPath = join30(projectPath, "package.json");
11383
+ if (existsSync29(pkgPath)) {
10226
11384
  try {
10227
- const pkg = JSON.parse(readFileSync23(pkgPath, "utf-8"));
11385
+ const pkg = JSON.parse(readFileSync24(pkgPath, "utf-8"));
10228
11386
  const allDeps = {
10229
11387
  ...pkg.dependencies,
10230
11388
  ...pkg.devDependencies
@@ -10239,10 +11397,10 @@ function detectFromManifests(projectPath) {
10239
11397
  } catch {
10240
11398
  }
10241
11399
  }
10242
- const reqPath = join29(projectPath, "requirements.txt");
10243
- if (existsSync28(reqPath)) {
11400
+ const reqPath = join30(projectPath, "requirements.txt");
11401
+ if (existsSync29(reqPath)) {
10244
11402
  try {
10245
- const content = readFileSync23(reqPath, "utf-8");
11403
+ const content = readFileSync24(reqPath, "utf-8");
10246
11404
  for (const line of content.split("\n")) {
10247
11405
  const match = line.match(/^([a-zA-Z0-9_-]+)==([^\s]+)/);
10248
11406
  if (match && match[1] && match[2]) {
@@ -10252,10 +11410,10 @@ function detectFromManifests(projectPath) {
10252
11410
  } catch {
10253
11411
  }
10254
11412
  }
10255
- const goModPath = join29(projectPath, "go.mod");
10256
- if (existsSync28(goModPath)) {
11413
+ const goModPath = join30(projectPath, "go.mod");
11414
+ if (existsSync29(goModPath)) {
10257
11415
  try {
10258
- const content = readFileSync23(goModPath, "utf-8");
11416
+ const content = readFileSync24(goModPath, "utf-8");
10259
11417
  const reqRegex = /^\s+([^\s]+)\s+v([^\s]+)/gm;
10260
11418
  let match;
10261
11419
  while ((match = reqRegex.exec(content)) !== null) {
@@ -10266,10 +11424,10 @@ function detectFromManifests(projectPath) {
10266
11424
  } catch {
10267
11425
  }
10268
11426
  }
10269
- const cargoPath = join29(projectPath, "Cargo.toml");
10270
- if (existsSync28(cargoPath)) {
11427
+ const cargoPath = join30(projectPath, "Cargo.toml");
11428
+ if (existsSync29(cargoPath)) {
10271
11429
  try {
10272
- const content = readFileSync23(cargoPath, "utf-8");
11430
+ const content = readFileSync24(cargoPath, "utf-8");
10273
11431
  const depRegex = /^([a-zA-Z0-9_-]+)\s*=\s*"([^"]+)"/gm;
10274
11432
  let match;
10275
11433
  let inDeps = false;
@@ -10297,12 +11455,12 @@ function detectFromManifests(projectPath) {
10297
11455
  function detectFromConfigFiles(projectPath) {
10298
11456
  const techs = [];
10299
11457
  for (const detection of CONFIG_DETECTIONS) {
10300
- const filePath = join29(projectPath, detection.file);
10301
- if (existsSync28(filePath)) {
11458
+ const filePath = join30(projectPath, detection.file);
11459
+ if (existsSync29(filePath)) {
10302
11460
  let version2 = "detected";
10303
11461
  if (detection.versionExtractor) {
10304
11462
  try {
10305
- const content = readFileSync23(filePath, "utf-8");
11463
+ const content = readFileSync24(filePath, "utf-8");
10306
11464
  version2 = detection.versionExtractor(content) || "detected";
10307
11465
  } catch {
10308
11466
  }
@@ -10317,43 +11475,43 @@ function detectFromConfigFiles(projectPath) {
10317
11475
  return techs;
10318
11476
  }
10319
11477
  function detectMonorepo(projectPath) {
10320
- const pnpmWorkspace = join29(projectPath, "pnpm-workspace.yaml");
10321
- if (existsSync28(pnpmWorkspace)) {
10322
- const content = readFileSync23(pnpmWorkspace, "utf-8");
11478
+ const pnpmWorkspace = join30(projectPath, "pnpm-workspace.yaml");
11479
+ if (existsSync29(pnpmWorkspace)) {
11480
+ const content = readFileSync24(pnpmWorkspace, "utf-8");
10323
11481
  const packages = extractWorkspacePatterns(content);
10324
11482
  return { type: "pnpm", packages, rootPath: projectPath };
10325
11483
  }
10326
- if (existsSync28(join29(projectPath, "turbo.json"))) {
10327
- const pkgJson = join29(projectPath, "package.json");
11484
+ if (existsSync29(join30(projectPath, "turbo.json"))) {
11485
+ const pkgJson = join30(projectPath, "package.json");
10328
11486
  let packages = [];
10329
- if (existsSync28(pkgJson)) {
11487
+ if (existsSync29(pkgJson)) {
10330
11488
  try {
10331
- const pkg = JSON.parse(readFileSync23(pkgJson, "utf-8"));
11489
+ const pkg = JSON.parse(readFileSync24(pkgJson, "utf-8"));
10332
11490
  packages = Array.isArray(pkg.workspaces) ? pkg.workspaces : pkg.workspaces?.packages || [];
10333
11491
  } catch {
10334
11492
  }
10335
11493
  }
10336
11494
  return { type: "turborepo", packages, rootPath: projectPath };
10337
11495
  }
10338
- const pkgPath = join29(projectPath, "package.json");
10339
- if (existsSync28(pkgPath)) {
11496
+ const pkgPath = join30(projectPath, "package.json");
11497
+ if (existsSync29(pkgPath)) {
10340
11498
  try {
10341
- const pkg = JSON.parse(readFileSync23(pkgPath, "utf-8"));
11499
+ const pkg = JSON.parse(readFileSync24(pkgPath, "utf-8"));
10342
11500
  if (pkg.workspaces) {
10343
11501
  const patterns = Array.isArray(pkg.workspaces) ? pkg.workspaces : pkg.workspaces.packages || [];
10344
- const type = existsSync28(join29(projectPath, "yarn.lock")) ? "yarn-workspaces" : "npm-workspaces";
11502
+ const type = existsSync29(join30(projectPath, "yarn.lock")) ? "yarn-workspaces" : "npm-workspaces";
10345
11503
  return { type, packages: patterns, rootPath: projectPath };
10346
11504
  }
10347
11505
  } catch {
10348
11506
  }
10349
11507
  }
10350
- if (existsSync28(join29(projectPath, "nx.json"))) {
11508
+ if (existsSync29(join30(projectPath, "nx.json"))) {
10351
11509
  return { type: "nx", packages: ["packages/*", "apps/*"], rootPath: projectPath };
10352
11510
  }
10353
- const lernaPath = join29(projectPath, "lerna.json");
10354
- if (existsSync28(lernaPath)) {
11511
+ const lernaPath = join30(projectPath, "lerna.json");
11512
+ if (existsSync29(lernaPath)) {
10355
11513
  try {
10356
- const lerna = JSON.parse(readFileSync23(lernaPath, "utf-8"));
11514
+ const lerna = JSON.parse(readFileSync24(lernaPath, "utf-8"));
10357
11515
  return { type: "lerna", packages: lerna.packages || ["packages/*"], rootPath: projectPath };
10358
11516
  } catch {
10359
11517
  }
@@ -10418,8 +11576,8 @@ var init_tech_detector = __esm({
10418
11576
  });
10419
11577
 
10420
11578
  // 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";
11579
+ import { existsSync as existsSync30, readFileSync as readFileSync25, readdirSync as readdirSync11 } from "fs";
11580
+ import { join as join31, relative as relative7, basename as basename10 } from "path";
10423
11581
  function detectFeatures(input) {
10424
11582
  const { projectPath, config: config2, importGraph, indexedFiles, fileTechMap } = input;
10425
11583
  let candidates = [];
@@ -10480,15 +11638,15 @@ function findSubPackageJsons(projectPath) {
10480
11638
  function walk(dir, depth) {
10481
11639
  if (depth > maxDepth) return;
10482
11640
  try {
10483
- const entries = readdirSync10(dir, { withFileTypes: true });
11641
+ const entries = readdirSync11(dir, { withFileTypes: true });
10484
11642
  for (const entry of entries) {
10485
11643
  if (!entry.isDirectory()) continue;
10486
11644
  const lower = entry.name.toLowerCase();
10487
11645
  if (lower === "node_modules" || lower === ".git" || lower === "dist") continue;
10488
11646
  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) {
11647
+ const subDir = join31(dir, entry.name);
11648
+ const pkgJson = join31(subDir, "package.json");
11649
+ if (existsSync30(pkgJson) && subDir !== projectPath) {
10492
11650
  results.push(subDir);
10493
11651
  }
10494
11652
  walk(subDir, depth + 1);
@@ -10502,20 +11660,20 @@ function findSubPackageJsons(projectPath) {
10502
11660
  function detectCodeownerFeatures(projectPath, indexedFiles) {
10503
11661
  const features = [];
10504
11662
  const codeownersLocations = [
10505
- join30(projectPath, "CODEOWNERS"),
10506
- join30(projectPath, ".github", "CODEOWNERS"),
10507
- join30(projectPath, "docs", "CODEOWNERS")
11663
+ join31(projectPath, "CODEOWNERS"),
11664
+ join31(projectPath, ".github", "CODEOWNERS"),
11665
+ join31(projectPath, "docs", "CODEOWNERS")
10508
11666
  ];
10509
11667
  let codeownersPath = null;
10510
11668
  for (const loc of codeownersLocations) {
10511
- if (existsSync29(loc)) {
11669
+ if (existsSync30(loc)) {
10512
11670
  codeownersPath = loc;
10513
11671
  break;
10514
11672
  }
10515
11673
  }
10516
11674
  if (!codeownersPath) return features;
10517
11675
  try {
10518
- const content = readFileSync24(codeownersPath, "utf-8");
11676
+ const content = readFileSync25(codeownersPath, "utf-8");
10519
11677
  const entries = parseCodeowners(content);
10520
11678
  for (const entry of entries) {
10521
11679
  const matchingFiles = indexedFiles.filter((f) => matchCodeownerPattern(f, entry.pattern));
@@ -10787,8 +11945,8 @@ var init_feature_detector = __esm({
10787
11945
 
10788
11946
  // src/core/agents/git-operations.ts
10789
11947
  import { execSync as execSync9 } from "child_process";
10790
- import { existsSync as existsSync30 } from "fs";
10791
- import { join as join31 } from "path";
11948
+ import { existsSync as existsSync31 } from "fs";
11949
+ import { join as join32 } from "path";
10792
11950
  function isGitRepo(projectPath) {
10793
11951
  try {
10794
11952
  git(projectPath, "rev-parse --is-inside-work-tree");
@@ -10830,7 +11988,7 @@ function commitChanges(projectPath, options) {
10830
11988
  }
10831
11989
  } else {
10832
11990
  git(projectPath, "add .code-impact/");
10833
- if (existsSync30(join31(projectPath, "AGENTS.md"))) {
11991
+ if (existsSync31(join32(projectPath, "AGENTS.md"))) {
10834
11992
  git(projectPath, "add AGENTS.md");
10835
11993
  }
10836
11994
  }
@@ -10950,7 +12108,7 @@ var init_git_operations = __esm({
10950
12108
  });
10951
12109
 
10952
12110
  // src/core/agents/marker-writer.ts
10953
- import { existsSync as existsSync31, readFileSync as readFileSync25, writeFileSync as writeFileSync18, mkdirSync as mkdirSync16 } from "fs";
12111
+ import { existsSync as existsSync32, readFileSync as readFileSync26, writeFileSync as writeFileSync18, mkdirSync as mkdirSync16 } from "fs";
10954
12112
  import { dirname as dirname13 } from "path";
10955
12113
  function writeMarkedFile(filePath, frontmatter, sections, options) {
10956
12114
  const result = {
@@ -10970,8 +12128,8 @@ function writeMarkedFile(filePath, frontmatter, sections, options) {
10970
12128
  result.tokenCount = estimateTokens5(autoContent);
10971
12129
  return result;
10972
12130
  }
10973
- if (existsSync31(filePath)) {
10974
- const existing = readFileSync25(filePath, "utf-8");
12131
+ if (existsSync32(filePath)) {
12132
+ const existing = readFileSync26(filePath, "utf-8");
10975
12133
  if (existing.includes(options.markers.start)) {
10976
12134
  const existingAutoContent = extractAutoContent(existing, options.markers);
10977
12135
  const existingHash = computeContentHash(existingAutoContent);
@@ -11192,19 +12350,19 @@ var init_token_budget = __esm({
11192
12350
  });
11193
12351
 
11194
12352
  // 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";
12353
+ import { existsSync as existsSync33, readFileSync as readFileSync27, mkdirSync as mkdirSync17 } from "fs";
12354
+ import { join as join34 } from "path";
11197
12355
  function generateProjectFiles(input) {
11198
12356
  const { projectPath, intelligence, technologies, features, index } = input;
11199
12357
  const config2 = readAgentConfig(projectPath);
11200
12358
  const paths = getAgentWorkspacePaths(projectPath);
11201
12359
  const result = { filesWritten: [], filesSkipped: [] };
11202
12360
  mkdirSync17(paths.projectDir, { recursive: true });
11203
- const skillPath = join33(paths.projectDir, "SKILL.md");
12361
+ const skillPath = join34(paths.projectDir, "SKILL.md");
11204
12362
  writeMarkedFile2(skillPath, renderProjectSkill(intelligence, technologies, config2, projectPath), config2, result, "project_skill");
11205
- const convPath = join33(paths.projectDir, "CONVENTIONS.md");
12363
+ const convPath = join34(paths.projectDir, "CONVENTIONS.md");
11206
12364
  writeMarkedFile2(convPath, renderConventions(intelligence, config2), config2, result, "project_conventions");
11207
- const archPath = join33(paths.projectDir, "ARCHITECTURE.md");
12365
+ const archPath = join34(paths.projectDir, "ARCHITECTURE.md");
11208
12366
  writeMarkedFile2(archPath, renderArchitecture(intelligence, config2), config2, result, "project_architecture");
11209
12367
  return result;
11210
12368
  }
@@ -11214,9 +12372,9 @@ function generateFeatureFiles(input) {
11214
12372
  const paths = getAgentWorkspacePaths(projectPath);
11215
12373
  const result = { filesWritten: [], filesSkipped: [] };
11216
12374
  for (const feature of features) {
11217
- const featureDir = join33(paths.featuresDir, feature.name);
12375
+ const featureDir = join34(paths.featuresDir, feature.name);
11218
12376
  mkdirSync17(featureDir, { recursive: true });
11219
- const skillPath = join33(featureDir, "SKILL.md");
12377
+ const skillPath = join34(featureDir, "SKILL.md");
11220
12378
  const featureTechs = technologies.filter((t) => feature.technologies.includes(t.name));
11221
12379
  writeMarkedFile2(skillPath, renderFeatureSkill(feature, featureTechs, config2), config2, result, "feature_skill");
11222
12380
  }
@@ -11274,7 +12432,7 @@ function renderProjectSkill(intel, technologies, config2, projectPath) {
11274
12432
  } else {
11275
12433
  for (const dir of intel.codebase.keyDirectories) {
11276
12434
  const dirName = dir.split("/").pop() || dir;
11277
- const purpose = inferDirPurpose(dirName);
12435
+ const purpose = inferDirectoryPurpose(dirName);
11278
12436
  lines.push(`| ${dir}/ | ${purpose} |`);
11279
12437
  }
11280
12438
  }
@@ -11376,8 +12534,10 @@ function renderArchitecture(intel, config2) {
11376
12534
  return { frontmatter, autoContent: lines.join("\n") };
11377
12535
  }
11378
12536
  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`);
12537
+ const grouped = groupScopedPackages(technologies);
12538
+ const techNames = grouped.map((t) => t.name);
12539
+ const researchTechs = technologies.slice(0, 15);
12540
+ const researchRefs = researchTechs.map((t) => `research/${t.name}@${t.version}.md`);
11381
12541
  const frontmatter = [
11382
12542
  "---",
11383
12543
  `name: ${feature.name}-feature`,
@@ -11390,7 +12550,7 @@ function renderFeatureSkill(feature, technologies, config2) {
11390
12550
  ` research_refs: [${researchRefs.join(", ")}]`,
11391
12551
  "---",
11392
12552
  "",
11393
- `# ${capitalize(feature.name)} Feature`
12553
+ `# ${capitalize2(feature.name)} Feature`
11394
12554
  ].join("\n");
11395
12555
  const lines = [];
11396
12556
  lines.push("## Scope");
@@ -11410,14 +12570,16 @@ function renderFeatureSkill(feature, technologies, config2) {
11410
12570
  if (feature.owner) {
11411
12571
  lines.push(`- Owner: ${feature.owner}`);
11412
12572
  }
11413
- if (technologies.length > 0) {
11414
- lines.push(`- Technologies: ${techNames.join(", ")}`);
12573
+ if (grouped.length > 0) {
12574
+ const displayTechs = techNames.slice(0, 10);
12575
+ const suffix = techNames.length > 10 ? `, +${techNames.length - 10} more` : "";
12576
+ lines.push(`- Technologies: ${displayTechs.join(", ")}${suffix}`);
11415
12577
  }
11416
12578
  lines.push("");
11417
12579
  if (researchRefs.length > 0) {
11418
12580
  lines.push("## Research References");
11419
12581
  for (const ref of researchRefs) {
11420
- const tech = technologies.find((t) => ref.includes(t.name));
12582
+ const tech = researchTechs.find((t) => ref.includes(t.name));
11421
12583
  if (tech) {
11422
12584
  lines.push(`- [${tech.name} v${tech.version}](../${ref})`);
11423
12585
  }
@@ -11425,13 +12587,13 @@ function renderFeatureSkill(feature, technologies, config2) {
11425
12587
  lines.push("");
11426
12588
  }
11427
12589
  lines.push("## Rules");
11428
- const rules = deriveRules(feature, technologies);
12590
+ const rules = deriveFeatureRules(feature, technologies);
11429
12591
  for (const rule of rules) {
11430
12592
  lines.push(`- ${rule}`);
11431
12593
  }
11432
12594
  lines.push("");
11433
12595
  lines.push("## Pitfalls");
11434
- const pitfalls = derivePitfalls(feature, technologies);
12596
+ const pitfalls = deriveFeaturePitfalls(feature, technologies);
11435
12597
  for (const pitfall of pitfalls) {
11436
12598
  lines.push(`- ${pitfall}`);
11437
12599
  }
@@ -11502,150 +12664,7 @@ function summarizeTestFiles(testFiles) {
11502
12664
  }
11503
12665
  return globs;
11504
12666
  }
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) {
12667
+ function capitalize2(str) {
11649
12668
  return str.charAt(0).toUpperCase() + str.slice(1).replace(/-/g, " ");
11650
12669
  }
11651
12670
  function filterDirectDependencies(technologies, projectPath) {
@@ -11657,13 +12676,13 @@ function filterDirectDependencies(technologies, projectPath) {
11657
12676
  }
11658
12677
  if (directNames.size === 0) {
11659
12678
  const searchPaths = [
11660
- projectPath ? join33(projectPath, "package.json") : "",
11661
- join33(process.cwd(), "package.json")
12679
+ projectPath ? join34(projectPath, "package.json") : "",
12680
+ join34(process.cwd(), "package.json")
11662
12681
  ].filter(Boolean);
11663
12682
  for (const p of searchPaths) {
11664
12683
  try {
11665
- if (existsSync32(p)) {
11666
- const pkg = JSON.parse(readFileSync26(p, "utf-8"));
12684
+ if (existsSync33(p)) {
12685
+ const pkg = JSON.parse(readFileSync27(p, "utf-8"));
11667
12686
  for (const d of Object.keys(pkg.dependencies || {})) directNames.add(d);
11668
12687
  for (const d of Object.keys(pkg.devDependencies || {})) directNames.add(d);
11669
12688
  break;
@@ -11680,151 +12699,50 @@ function filterDirectDependencies(technologies, projectPath) {
11680
12699
  /^@parcel\//,
11681
12700
  /^@biomejs\//
11682
12701
  ];
12702
+ let filtered;
11683
12703
  if (directNames.size > 0) {
11684
- return technologies.filter((t) => directNames.has(t.name)).filter((t) => !skipPatterns.some((p) => p.test(t.name)));
12704
+ filtered = technologies.filter((t) => directNames.has(t.name)).filter((t) => !skipPatterns.some((p) => p.test(t.name)));
12705
+ } else {
12706
+ filtered = technologies.filter((t) => !skipPatterns.some((p) => p.test(t.name))).slice(0, 30);
12707
+ }
12708
+ return groupScopedPackages(filtered);
12709
+ }
12710
+ function groupScopedPackages(techs) {
12711
+ const scopeMap = /* @__PURE__ */ new Map();
12712
+ const ungrouped = [];
12713
+ for (const t of techs) {
12714
+ const m = t.name.match(/^(@[^/]+)\//);
12715
+ if (m) {
12716
+ const scope = m[1];
12717
+ if (!scopeMap.has(scope)) scopeMap.set(scope, []);
12718
+ scopeMap.get(scope).push(t);
12719
+ } else {
12720
+ ungrouped.push(t);
12721
+ }
12722
+ }
12723
+ const result = [...ungrouped];
12724
+ for (const [scope, members] of scopeMap.entries()) {
12725
+ if (members.length >= 3) {
12726
+ const label = inferScopeLabel(scope, members.length);
12727
+ result.push({
12728
+ name: label,
12729
+ version: members[0].version,
12730
+ source: members[0].source,
12731
+ importPaths: members.flatMap((m) => m.importPaths || [])
12732
+ });
12733
+ } else {
12734
+ result.push(...members);
12735
+ }
11685
12736
  }
11686
- return technologies.filter((t) => !skipPatterns.some((p) => p.test(t.name))).slice(0, 20);
12737
+ return result;
11687
12738
  }
11688
- var TECH_KNOWLEDGE, WELL_KNOWN_FEATURES;
11689
12739
  var init_generator = __esm({
11690
12740
  "src/core/agents/generator.ts"() {
11691
12741
  "use strict";
11692
12742
  init_workspace2();
11693
12743
  init_marker_writer();
11694
12744
  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
- ]);
12745
+ init_universal_inference();
11828
12746
  }
11829
12747
  });
11830
12748
 
@@ -12132,8 +13050,8 @@ var init_co_change_analyzer = __esm({
12132
13050
  });
12133
13051
 
12134
13052
  // 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";
13053
+ import { existsSync as existsSync34, readdirSync as readdirSync12, statSync as statSync6 } from "fs";
13054
+ import { join as join35 } from "path";
12137
13055
  function analyzeLifecycle(projectPath, features, config2 = DEFAULT_LIFECYCLE_CONFIG, executor = new RealGitExecutor()) {
12138
13056
  const startTime = Date.now();
12139
13057
  const proposals = [];
@@ -12179,14 +13097,14 @@ function analyzeLifecycle(projectPath, features, config2 = DEFAULT_LIFECYCLE_CON
12179
13097
  }
12180
13098
  }
12181
13099
  const paths = getAgentWorkspacePaths(projectPath);
12182
- if (existsSync33(paths.featuresDir)) {
13100
+ if (existsSync34(paths.featuresDir)) {
12183
13101
  try {
12184
- const featureDirs = readdirSync11(paths.featuresDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
13102
+ const featureDirs = readdirSync12(paths.featuresDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
12185
13103
  const activeFeatureNames = new Set(features.map((f) => f.name));
12186
13104
  const cutoffDate = Date.now() - config2.pruneInactiveDays * 24 * 60 * 60 * 1e3;
12187
13105
  for (const dirName of featureDirs) {
12188
13106
  if (!activeFeatureNames.has(dirName)) {
12189
- const dirPath = join34(paths.featuresDir, dirName);
13107
+ const dirPath = join35(paths.featuresDir, dirName);
12190
13108
  const stat = statSync6(dirPath);
12191
13109
  if (stat.mtimeMs < cutoffDate) {
12192
13110
  proposals.push({
@@ -12234,8 +13152,8 @@ var init_lifecycle = __esm({
12234
13152
  });
12235
13153
 
12236
13154
  // 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";
13155
+ import { existsSync as existsSync35, readFileSync as readFileSync28, readdirSync as readdirSync13 } from "fs";
13156
+ import { join as join36, relative as relative9 } from "path";
12239
13157
  function agentsInit(projectPath) {
12240
13158
  const paths = initAgentWorkspace(projectPath);
12241
13159
  return {
@@ -12311,7 +13229,7 @@ async function agentsGenerate(options) {
12311
13229
  currentIndex.reResearchQueue = [];
12312
13230
  writeAgentIndex(projectPath, currentIndex);
12313
13231
  }
12314
- const intel = intelligence || createMinimalIntelligence(projectPath, technologies, features);
13232
+ const intel = intelligence || createMinimalIntelligence(projectPath, technologies, features, importGraph);
12315
13233
  const genInput = {
12316
13234
  projectPath,
12317
13235
  intelligence: intel,
@@ -12421,8 +13339,8 @@ function agentsStatus(projectPath) {
12421
13339
  const paths = getAgentWorkspacePaths(projectPath);
12422
13340
  let researchFiles = 0;
12423
13341
  let staleResearch = 0;
12424
- if (existsSync34(paths.researchDir)) {
12425
- const files = readdirSync12(paths.researchDir);
13342
+ if (existsSync35(paths.researchDir)) {
13343
+ const files = readdirSync13(paths.researchDir);
12426
13344
  researchFiles = files.filter((f) => f.endsWith(".md")).length;
12427
13345
  const now = Date.now();
12428
13346
  for (const [tech, timestamp] of Object.entries(index.lastResearch)) {
@@ -12455,10 +13373,10 @@ function getIndexedFilesFromFS(projectPath) {
12455
13373
  function walk(dir, depth) {
12456
13374
  if (depth > 5) return;
12457
13375
  try {
12458
- const entries = readdirSync12(dir, { withFileTypes: true });
13376
+ const entries = readdirSync13(dir, { withFileTypes: true });
12459
13377
  for (const entry of entries) {
12460
13378
  if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === "dist") continue;
12461
- const fullPath = join35(dir, entry.name);
13379
+ const fullPath = join36(dir, entry.name);
12462
13380
  if (entry.isDirectory()) {
12463
13381
  walk(fullPath, depth + 1);
12464
13382
  } else {
@@ -12492,7 +13410,7 @@ function filterTopTechnologies(technologies) {
12492
13410
  ];
12493
13411
  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
13412
  }
12495
- function createMinimalIntelligence(projectPath, technologies, features) {
13413
+ function createMinimalIntelligence(projectPath, technologies, features, importGraph) {
12496
13414
  const sourceFiles = getIndexedFilesFromFS(projectPath);
12497
13415
  const codeFiles = sourceFiles.filter(
12498
13416
  (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 +13418,7 @@ function createMinimalIntelligence(projectPath, technologies, features) {
12500
13418
  let totalLines = 0;
12501
13419
  for (const f of codeFiles.slice(0, 500)) {
12502
13420
  try {
12503
- const content = readFileSync27(join35(projectPath, f), "utf-8");
13421
+ const content = readFileSync28(join36(projectPath, f), "utf-8");
12504
13422
  totalLines += content.split("\n").length;
12505
13423
  } catch {
12506
13424
  }
@@ -12515,7 +13433,7 @@ function createMinimalIntelligence(projectPath, technologies, features) {
12515
13433
  const layers = features.map((f) => ({
12516
13434
  name: f.name.charAt(0).toUpperCase() + f.name.slice(1),
12517
13435
  directory: f.paths[0]?.replace("/**", "") || f.name,
12518
- purpose: inferLayerPurpose(f.name),
13436
+ purpose: inferDirectoryPurpose(f.name),
12519
13437
  fileCount: f.fileCount
12520
13438
  }));
12521
13439
  const testFramework = detectTestFramework(projectPath);
@@ -12532,7 +13450,7 @@ function createMinimalIntelligence(projectPath, technologies, features) {
12532
13450
  },
12533
13451
  architecture: {
12534
13452
  layers,
12535
- dataFlow: inferDataFlow(features),
13453
+ dataFlow: inferDataFlowFromGraph(features, importGraph),
12536
13454
  keyComponents: [],
12537
13455
  patternCategories: {},
12538
13456
  topPatterns: [],
@@ -12563,7 +13481,7 @@ function buildFileTechMap(projectPath, indexedFiles, technologies) {
12563
13481
  );
12564
13482
  for (const file2 of sourceFiles.slice(0, 300)) {
12565
13483
  try {
12566
- const content = readFileSync27(join35(projectPath, file2), "utf-8");
13484
+ const content = readFileSync28(join36(projectPath, file2), "utf-8");
12567
13485
  const techs = /* @__PURE__ */ new Set();
12568
13486
  const importRegex = /(?:from\s+['"]|require\s*\(\s*['"])([^./'"@][^'"]*|@[^/'"]+\/[^'"]+)/g;
12569
13487
  let match;
@@ -12601,39 +13519,11 @@ function extToLanguage(ext) {
12601
13519
  };
12602
13520
  return map2[ext] || null;
12603
13521
  }
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
13522
  function detectTestFramework(projectPath) {
12633
- const pkgPath = join35(projectPath, "package.json");
12634
- if (existsSync34(pkgPath)) {
13523
+ const pkgPath = join36(projectPath, "package.json");
13524
+ if (existsSync35(pkgPath)) {
12635
13525
  try {
12636
- const pkg = JSON.parse(readFileSync27(pkgPath, "utf-8"));
13526
+ const pkg = JSON.parse(readFileSync28(pkgPath, "utf-8"));
12637
13527
  const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
12638
13528
  if (allDeps["vitest"]) return "vitest";
12639
13529
  if (allDeps["jest"]) return "jest";
@@ -12654,6 +13544,7 @@ var init_orchestrator = __esm({
12654
13544
  init_research_engine();
12655
13545
  init_generator();
12656
13546
  init_agent_generator();
13547
+ init_universal_inference();
12657
13548
  init_git_operations();
12658
13549
  init_improvement_engine();
12659
13550
  init_outcome_storage();
@@ -12663,8 +13554,8 @@ var init_orchestrator = __esm({
12663
13554
  });
12664
13555
 
12665
13556
  // 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";
13557
+ import { existsSync as existsSync36, readFileSync as readFileSync29, writeFileSync as writeFileSync20, mkdirSync as mkdirSync18, cpSync, readdirSync as readdirSync14 } from "fs";
13558
+ import { join as join37, relative as relative10, dirname as dirname15 } from "path";
12668
13559
  function migrateKnowledge(options) {
12669
13560
  const { projectPath, dryRun = false, backup = false } = options;
12670
13561
  const result = {
@@ -12673,8 +13564,8 @@ function migrateKnowledge(options) {
12673
13564
  skipped: [],
12674
13565
  conflicts: []
12675
13566
  };
12676
- const knowledgeDir = join36(projectPath, "knowledge");
12677
- if (!existsSync35(knowledgeDir)) {
13567
+ const knowledgeDir = join37(projectPath, "knowledge");
13568
+ if (!existsSync36(knowledgeDir)) {
12678
13569
  result.skipped.push({ source: "knowledge/", reason: "Directory does not exist" });
12679
13570
  return result;
12680
13571
  }
@@ -12683,7 +13574,7 @@ function migrateKnowledge(options) {
12683
13574
  }
12684
13575
  const paths = getAgentWorkspacePaths(projectPath);
12685
13576
  if (backup && !dryRun) {
12686
- const backupDir = join36(projectPath, `knowledge-backup-${Date.now()}`);
13577
+ const backupDir = join37(projectPath, `knowledge-backup-${Date.now()}`);
12687
13578
  cpSync(knowledgeDir, backupDir, { recursive: true });
12688
13579
  result.backupDir = backupDir;
12689
13580
  }
@@ -12696,7 +13587,7 @@ function migrateKnowledge(options) {
12696
13587
  continue;
12697
13588
  }
12698
13589
  const targetPath = resolveTargetPath(paths, classification);
12699
- if (existsSync35(targetPath) && !dryRun) {
13590
+ if (existsSync36(targetPath) && !dryRun) {
12700
13591
  const merged = mergeSkills(skillFile, targetPath);
12701
13592
  if (merged) {
12702
13593
  result.conflicts.push({ source: relPath, target: relative10(projectPath, targetPath), resolution: "merged" });
@@ -12720,10 +13611,10 @@ function migrateKnowledge(options) {
12720
13611
  function discoverSkillFiles(dir) {
12721
13612
  const files = [];
12722
13613
  function walk(current) {
12723
- if (!existsSync35(current)) return;
12724
- const entries = readdirSync13(current, { withFileTypes: true });
13614
+ if (!existsSync36(current)) return;
13615
+ const entries = readdirSync14(current, { withFileTypes: true });
12725
13616
  for (const entry of entries) {
12726
- const fullPath = join36(current, entry.name);
13617
+ const fullPath = join37(current, entry.name);
12727
13618
  if (entry.isDirectory()) {
12728
13619
  walk(fullPath);
12729
13620
  } else if (entry.name === "SKILL.md" || entry.name.endsWith(".skill.md")) {
@@ -12760,19 +13651,19 @@ function classifySkillPath(relPath) {
12760
13651
  function resolveTargetPath(paths, classification) {
12761
13652
  switch (classification.type) {
12762
13653
  case "technology":
12763
- return join36(paths.projectDir, `${classification.name}-SKILL.md`);
13654
+ return join37(paths.projectDir, `${classification.name}-SKILL.md`);
12764
13655
  case "feature":
12765
- return join36(paths.featuresDir, classification.name, "SKILL.md");
13656
+ return join37(paths.featuresDir, classification.name, "SKILL.md");
12766
13657
  case "project":
12767
- return join36(paths.projectDir, "SKILL.md");
13658
+ return join37(paths.projectDir, "SKILL.md");
12768
13659
  default:
12769
- return join36(paths.projectDir, `${classification.name}-SKILL.md`);
13660
+ return join37(paths.projectDir, `${classification.name}-SKILL.md`);
12770
13661
  }
12771
13662
  }
12772
13663
  function mergeSkills(sourcePath, targetPath) {
12773
13664
  try {
12774
- const sourceContent = readFileSync28(sourcePath, "utf-8");
12775
- const targetContent = readFileSync28(targetPath, "utf-8");
13665
+ const sourceContent = readFileSync29(sourcePath, "utf-8");
13666
+ const targetContent = readFileSync29(targetPath, "utf-8");
12776
13667
  const sourceRules = extractSection2(sourceContent, "Rules");
12777
13668
  const sourcePitfalls = extractSection2(sourceContent, "Pitfalls");
12778
13669
  if (!sourceRules && !sourcePitfalls) return false;
@@ -12835,9 +13726,16 @@ __export(agents_exports, {
12835
13726
  DEFAULT_OUTPUT_DIR: () => DEFAULT_OUTPUT_DIR,
12836
13727
  DEFAULT_TRUST_CONFIG: () => DEFAULT_TRUST_CONFIG,
12837
13728
  DIAGNOSIS_RULES: () => DIAGNOSIS_RULES,
13729
+ DIR_PURPOSE_MAP: () => DIR_PURPOSE_MAP,
13730
+ DOC_SOURCE_REGISTRY: () => DOC_SOURCE_REGISTRY,
13731
+ FEATURE_NAME_PITFALLS: () => FEATURE_NAME_PITFALLS,
13732
+ FEATURE_NAME_RULES: () => FEATURE_NAME_RULES,
12838
13733
  MockGitExecutor: () => MockGitExecutor,
12839
13734
  RealGitExecutor: () => RealGitExecutor,
13735
+ SCOPE_LABELS: () => SCOPE_LABELS,
12840
13736
  SECTION_PRIORITIES: () => SECTION_PRIORITIES,
13737
+ TECH_KNOWLEDGE: () => TECH_KNOWLEDGE,
13738
+ WELL_KNOWN_FEATURES: () => WELL_KNOWN_FEATURES,
12841
13739
  agentWorkspaceExists: () => agentWorkspaceExists,
12842
13740
  agentsGenerate: () => agentsGenerate,
12843
13741
  agentsInit: () => agentsInit,
@@ -12845,6 +13743,8 @@ __export(agents_exports, {
12845
13743
  analyzeCoChanges: () => analyzeCoChanges,
12846
13744
  analyzeLifecycle: () => analyzeLifecycle,
12847
13745
  assessTrust: () => assessTrust,
13746
+ classifyFeature: () => classifyFeature,
13747
+ classifyTechnology: () => classifyTechnology,
12848
13748
  commitAndPush: () => commitAndPush,
12849
13749
  commitChanges: () => commitChanges,
12850
13750
  computeContentHash: () => computeContentHash,
@@ -12856,6 +13756,8 @@ __export(agents_exports, {
12856
13756
  createOutcomeTable: () => createOutcomeTable,
12857
13757
  createTelemetryTable: () => createTelemetryTable,
12858
13758
  decayOldLessons: () => decayOldLessons,
13759
+ deriveFeaturePitfalls: () => deriveFeaturePitfalls,
13760
+ deriveFeatureRules: () => deriveFeatureRules,
12859
13761
  detectFeatures: () => detectFeatures,
12860
13762
  detectMonorepo: () => detectMonorepo,
12861
13763
  detectProvider: () => detectProvider,
@@ -12868,6 +13770,7 @@ __export(agents_exports, {
12868
13770
  ensureFeatureDir: () => ensureFeatureDir,
12869
13771
  estimateTokens: () => estimateTokens6,
12870
13772
  extractManualContent: () => extractManualContent,
13773
+ extractRulesFromResearch: () => extractRulesFromResearch,
12871
13774
  findMergeCandidates: () => findMergeCandidates,
12872
13775
  generateAgentFiles: () => generateAgentFiles,
12873
13776
  generateAgentsShim: () => generateAgentsShim,
@@ -12884,6 +13787,11 @@ __export(agents_exports, {
12884
13787
  getResearchContent: () => getResearchContent,
12885
13788
  getSectionPriority: () => getSectionPriority,
12886
13789
  hasChanges: () => hasChanges,
13790
+ inferDataFlowFromGraph: () => inferDataFlowFromGraph,
13791
+ inferDirectoryPurpose: () => inferDirectoryPurpose,
13792
+ inferDocSource: () => inferDocSource,
13793
+ inferScopeLabel: () => inferScopeLabel,
13794
+ inferTechRulesAndPitfalls: () => inferTechRulesAndPitfalls,
12887
13795
  initAgentWorkspace: () => initAgentWorkspace,
12888
13796
  isGitRepo: () => isGitRepo,
12889
13797
  learnFromOutcome: () => learnFromOutcome,
@@ -12929,6 +13837,8 @@ var init_agents = __esm({
12929
13837
  init_co_change_analyzer();
12930
13838
  init_lifecycle();
12931
13839
  init_telemetry();
13840
+ init_hardcoded_knowledge();
13841
+ init_universal_inference();
12932
13842
  }
12933
13843
  });
12934
13844
 
@@ -31291,8 +32201,8 @@ ${decision.files.map((f) => `- \`${f}\``).join("\n")}
31291
32201
  getExistingADRFiles(dir) {
31292
32202
  if (!existsSync6(dir)) return [];
31293
32203
  try {
31294
- const { readdirSync: readdirSync14 } = __require("fs");
31295
- return readdirSync14(dir).filter((f) => /^\d{4}-.*\.md$/.test(f)).sort();
32204
+ const { readdirSync: readdirSync15 } = __require("fs");
32205
+ return readdirSync15(dir).filter((f) => /^\d{4}-.*\.md$/.test(f)).sort();
31296
32206
  } catch {
31297
32207
  return [];
31298
32208
  }
@@ -43758,12 +44668,12 @@ var SkillEvolutionEngine = class {
43758
44668
  }
43759
44669
  }
43760
44670
  findSkillFile(dir, skillId) {
43761
- const { readdirSync: readdirSync14, statSync: statSync8 } = __require("fs");
43762
- const { join: join38 } = __require("path");
44671
+ const { readdirSync: readdirSync15, statSync: statSync8 } = __require("fs");
44672
+ const { join: join39 } = __require("path");
43763
44673
  if (!existsSync20(dir)) return null;
43764
- const entries = readdirSync14(dir);
44674
+ const entries = readdirSync15(dir);
43765
44675
  for (const entry of entries) {
43766
- const fullPath = join38(dir, entry);
44676
+ const fullPath = join39(dir, entry);
43767
44677
  const stat = statSync8(fullPath);
43768
44678
  if (stat.isDirectory()) {
43769
44679
  const found = this.findSkillFile(fullPath, skillId);
@@ -49200,8 +50110,8 @@ init_research_engine();
49200
50110
  init_outcome_storage();
49201
50111
  init_improvement_engine();
49202
50112
  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";
50113
+ import { existsSync as existsSync28, readFileSync as readFileSync23, readdirSync as readdirSync10, writeFileSync as writeFileSync17 } from "fs";
50114
+ import { join as join28 } from "path";
49205
50115
  async function handleMemoryAgents(engine, input) {
49206
50116
  const projectPath = engine.getProjectPath();
49207
50117
  if (!agentWorkspaceExists(projectPath)) {
@@ -49242,34 +50152,34 @@ function handleListSkills(projectPath, input) {
49242
50152
  if (!input.scope || input.scope === "project") {
49243
50153
  const projectFiles = ["SKILL.md", "CONVENTIONS.md", "ARCHITECTURE.md"];
49244
50154
  for (const file2 of projectFiles) {
49245
- const filePath = join27(paths.projectDir, file2);
49246
- if (existsSync27(filePath)) {
50155
+ const filePath = join28(paths.projectDir, file2);
50156
+ if (existsSync28(filePath)) {
49247
50157
  skills.push({ name: file2.replace(".md", "").toLowerCase(), type: "project", path: `project/${file2}`, source: ".code-impact" });
49248
50158
  }
49249
50159
  }
49250
50160
  }
49251
50161
  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);
50162
+ if (existsSync28(paths.featuresDir)) {
50163
+ const features = readdirSync10(paths.featuresDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
49254
50164
  for (const feature of features) {
49255
50165
  if (input.feature && feature !== input.feature) continue;
49256
- const skillPath = join27(paths.featuresDir, feature, "SKILL.md");
49257
- if (existsSync27(skillPath)) {
50166
+ const skillPath = join28(paths.featuresDir, feature, "SKILL.md");
50167
+ if (existsSync28(skillPath)) {
49258
50168
  skills.push({ name: `${feature}-skill`, type: "feature", path: `features/${feature}/SKILL.md`, source: ".code-impact" });
49259
50169
  }
49260
50170
  }
49261
50171
  }
49262
50172
  }
49263
- const legacySkillsDir = join27(projectPath, "knowledge", "skills");
49264
- if (existsSync27(legacySkillsDir)) {
50173
+ const legacySkillsDir = join28(projectPath, "knowledge", "skills");
50174
+ if (existsSync28(legacySkillsDir)) {
49265
50175
  try {
49266
50176
  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);
50177
+ const scopeDir = join28(legacySkillsDir, scope);
50178
+ if (!existsSync28(scopeDir)) continue;
50179
+ const skillDirs = readdirSync10(scopeDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
49270
50180
  for (const skillName of skillDirs) {
49271
- const skillPath = join27(scopeDir, skillName, "SKILL.md");
49272
- if (existsSync27(skillPath)) {
50181
+ const skillPath = join28(scopeDir, skillName, "SKILL.md");
50182
+ if (existsSync28(skillPath)) {
49273
50183
  const alreadyListed = skills.some((s) => s.name === skillName || s.name === `${skillName}-skill`);
49274
50184
  if (!alreadyListed) {
49275
50185
  skills.push({
@@ -49295,9 +50205,9 @@ function handleListSkills(projectPath, input) {
49295
50205
  function handleListAgents(projectPath) {
49296
50206
  const paths = getAgentWorkspacePaths(projectPath);
49297
50207
  const agents = [];
49298
- const superAgentPath = join27(paths.projectDir, "AGENT.md");
49299
- if (existsSync27(superAgentPath)) {
49300
- const content = readFileSync22(superAgentPath, "utf-8");
50208
+ const superAgentPath = join28(paths.projectDir, "AGENT.md");
50209
+ if (existsSync28(superAgentPath)) {
50210
+ const content = readFileSync23(superAgentPath, "utf-8");
49301
50211
  const agent = parseAgentMd(content);
49302
50212
  if (agent) {
49303
50213
  agents.push({
@@ -49308,12 +50218,12 @@ function handleListAgents(projectPath) {
49308
50218
  });
49309
50219
  }
49310
50220
  }
49311
- if (existsSync27(paths.featuresDir)) {
49312
- const features = readdirSync9(paths.featuresDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
50221
+ if (existsSync28(paths.featuresDir)) {
50222
+ const features = readdirSync10(paths.featuresDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
49313
50223
  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");
50224
+ const agentPath = join28(paths.featuresDir, feature, "AGENT.md");
50225
+ if (existsSync28(agentPath)) {
50226
+ const content = readFileSync23(agentPath, "utf-8");
49317
50227
  const agent = parseAgentMd(content);
49318
50228
  if (agent) {
49319
50229
  agents.push({
@@ -49338,32 +50248,32 @@ function handleGetSkill(projectPath, input) {
49338
50248
  return { success: false, action: "get_skill", message: "Missing required parameter: name" };
49339
50249
  }
49340
50250
  const paths = getAgentWorkspacePaths(projectPath);
49341
- const projectFile = join27(paths.projectDir, `${input.name.toUpperCase()}.md`);
49342
- if (existsSync27(projectFile)) {
50251
+ const projectFile = join28(paths.projectDir, `${input.name.toUpperCase()}.md`);
50252
+ if (existsSync28(projectFile)) {
49343
50253
  return {
49344
50254
  success: true,
49345
50255
  action: "get_skill",
49346
50256
  message: `Found project skill: ${input.name}`,
49347
- data: { content: readFileSync22(projectFile, "utf-8"), path: `project/${input.name.toUpperCase()}.md` }
50257
+ data: { content: readFileSync23(projectFile, "utf-8"), path: `project/${input.name.toUpperCase()}.md` }
49348
50258
  };
49349
50259
  }
49350
- const skillFile = join27(paths.projectDir, "SKILL.md");
49351
- if (input.name === "project-overview" && existsSync27(skillFile)) {
50260
+ const skillFile = join28(paths.projectDir, "SKILL.md");
50261
+ if (input.name === "project-overview" && existsSync28(skillFile)) {
49352
50262
  return {
49353
50263
  success: true,
49354
50264
  action: "get_skill",
49355
50265
  message: "Found project skill",
49356
- data: { content: readFileSync22(skillFile, "utf-8"), path: "project/SKILL.md" }
50266
+ data: { content: readFileSync23(skillFile, "utf-8"), path: "project/SKILL.md" }
49357
50267
  };
49358
50268
  }
49359
50269
  const featureName = input.name.replace(/-skill$/, "").replace(/-feature$/, "");
49360
- const featureSkill = join27(paths.featuresDir, featureName, "SKILL.md");
49361
- if (existsSync27(featureSkill)) {
50270
+ const featureSkill = join28(paths.featuresDir, featureName, "SKILL.md");
50271
+ if (existsSync28(featureSkill)) {
49362
50272
  return {
49363
50273
  success: true,
49364
50274
  action: "get_skill",
49365
50275
  message: `Found feature skill: ${featureName}`,
49366
- data: { content: readFileSync22(featureSkill, "utf-8"), path: `features/${featureName}/SKILL.md` }
50276
+ data: { content: readFileSync23(featureSkill, "utf-8"), path: `features/${featureName}/SKILL.md` }
49367
50277
  };
49368
50278
  }
49369
50279
  return { success: false, action: "get_skill", message: `Skill not found: ${input.name}` };
@@ -49374,9 +50284,9 @@ function handleGetAgent(projectPath, input) {
49374
50284
  }
49375
50285
  const paths = getAgentWorkspacePaths(projectPath);
49376
50286
  if (input.name === "project-coordinator") {
49377
- const superPath = join27(paths.projectDir, "AGENT.md");
49378
- if (existsSync27(superPath)) {
49379
- const content = readFileSync22(superPath, "utf-8");
50287
+ const superPath = join28(paths.projectDir, "AGENT.md");
50288
+ if (existsSync28(superPath)) {
50289
+ const content = readFileSync23(superPath, "utf-8");
49380
50290
  const agent = parseAgentMd(content);
49381
50291
  return {
49382
50292
  success: true,
@@ -49387,9 +50297,9 @@ function handleGetAgent(projectPath, input) {
49387
50297
  }
49388
50298
  }
49389
50299
  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");
50300
+ const agentPath = join28(paths.featuresDir, featureName, "AGENT.md");
50301
+ if (existsSync28(agentPath)) {
50302
+ const content = readFileSync23(agentPath, "utf-8");
49393
50303
  const agent = parseAgentMd(content);
49394
50304
  return {
49395
50305
  success: true,
@@ -49422,15 +50332,15 @@ function handleValidateAction(projectPath, input) {
49422
50332
  const paths = getAgentWorkspacePaths(projectPath);
49423
50333
  let agentDef = null;
49424
50334
  if (input.agent === "project-coordinator") {
49425
- const superPath = join27(paths.projectDir, "AGENT.md");
49426
- if (existsSync27(superPath)) {
49427
- agentDef = parseAgentMd(readFileSync22(superPath, "utf-8"));
50335
+ const superPath = join28(paths.projectDir, "AGENT.md");
50336
+ if (existsSync28(superPath)) {
50337
+ agentDef = parseAgentMd(readFileSync23(superPath, "utf-8"));
49428
50338
  }
49429
50339
  } else {
49430
50340
  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"));
50341
+ const agentPath = join28(paths.featuresDir, featureName, "AGENT.md");
50342
+ if (existsSync28(agentPath)) {
50343
+ agentDef = parseAgentMd(readFileSync23(agentPath, "utf-8"));
49434
50344
  }
49435
50345
  }
49436
50346
  if (!agentDef) {
@@ -49531,11 +50441,11 @@ function handleProposeImprovement(projectPath, input) {
49531
50441
  createdAt: (/* @__PURE__ */ new Date()).toISOString()
49532
50442
  };
49533
50443
  const paths = getAgentWorkspacePaths(projectPath);
49534
- const proposalsPath = join27(paths.root, "proposals.json");
50444
+ const proposalsPath = join28(paths.root, "proposals.json");
49535
50445
  let proposals = [];
49536
- if (existsSync27(proposalsPath)) {
50446
+ if (existsSync28(proposalsPath)) {
49537
50447
  try {
49538
- proposals = JSON.parse(readFileSync22(proposalsPath, "utf-8"));
50448
+ proposals = JSON.parse(readFileSync23(proposalsPath, "utf-8"));
49539
50449
  } catch {
49540
50450
  }
49541
50451
  }
@@ -53234,13 +54144,13 @@ var StreamableHTTPServerTransport = class {
53234
54144
  };
53235
54145
 
53236
54146
  // src/utils/config.ts
53237
- import { join as join28, resolve as resolve2 } from "path";
54147
+ import { join as join29, resolve as resolve2 } from "path";
53238
54148
  function getDefaultConfig(projectPath) {
53239
54149
  const normalizedPath = resolve2(projectPath);
53240
54150
  return {
53241
54151
  projectPath: normalizedPath,
53242
54152
  // Store in project directory (standard practice like .git/, .vscode/)
53243
- dataDir: join28(normalizedPath, ".codeimpact"),
54153
+ dataDir: join29(normalizedPath, ".codeimpact"),
53244
54154
  maxTokens: 6e3,
53245
54155
  embeddingModel: "Xenova/all-MiniLM-L6-v2",
53246
54156
  // Fallback model, faster and smaller
@@ -53594,9 +54504,9 @@ To connect clients, run in each project:`);
53594
54504
  };
53595
54505
 
53596
54506
  // src/cli/commands.ts
53597
- import { join as join37, resolve as resolve3 } from "path";
54507
+ import { join as join38, resolve as resolve3 } from "path";
53598
54508
  import { fileURLToPath as fileURLToPath2 } from "url";
53599
- import { existsSync as existsSync36, readFileSync as readFileSync29, writeFileSync as writeFileSync21, mkdirSync as mkdirSync19 } from "fs";
54509
+ import { existsSync as existsSync37, readFileSync as readFileSync30, writeFileSync as writeFileSync21, mkdirSync as mkdirSync19 } from "fs";
53600
54510
  import { homedir as homedir2 } from "os";
53601
54511
  var projectManager = new ProjectManager();
53602
54512
  function listProjects() {
@@ -53711,10 +54621,10 @@ function exportDecisions(projectPath, options = {}) {
53711
54621
  message: `Project not registered: ${targetPath}. Use "codeimpact projects add ${targetPath}" first.`
53712
54622
  };
53713
54623
  }
53714
- let dbPath = join37(projectInfo.dataDir, "codeimpact.db");
53715
- if (!existsSync36(dbPath)) {
53716
- const oldDbPath = join37(projectInfo.dataDir, "codeimpact.db");
53717
- if (existsSync36(oldDbPath)) {
54624
+ let dbPath = join38(projectInfo.dataDir, "codeimpact.db");
54625
+ if (!existsSync37(dbPath)) {
54626
+ const oldDbPath = join38(projectInfo.dataDir, "codeimpact.db");
54627
+ if (existsSync37(oldDbPath)) {
53718
54628
  dbPath = oldDbPath;
53719
54629
  } else {
53720
54630
  return {
@@ -53741,17 +54651,17 @@ function exportDecisions(projectPath, options = {}) {
53741
54651
  });
53742
54652
  return {
53743
54653
  success: true,
53744
- message: `Exported ${exportedFiles.length} ADR files to ${options.outputDir || join37(targetPath, "docs", "decisions")}`,
54654
+ message: `Exported ${exportedFiles.length} ADR files to ${options.outputDir || join38(targetPath, "docs", "decisions")}`,
53745
54655
  data: exportedFiles
53746
54656
  };
53747
54657
  }
53748
54658
  function findDatabasePath(projectInfo) {
53749
- const centralizedPath = join37(projectInfo.dataDir, "codeimpact.db");
53750
- if (existsSync36(centralizedPath)) {
54659
+ const centralizedPath = join38(projectInfo.dataDir, "codeimpact.db");
54660
+ if (existsSync37(centralizedPath)) {
53751
54661
  return centralizedPath;
53752
54662
  }
53753
- const projectLocalPath = join37(projectInfo.path, ".codeimpact", "codeimpact.db");
53754
- if (existsSync36(projectLocalPath)) {
54663
+ const projectLocalPath = join38(projectInfo.path, ".codeimpact", "codeimpact.db");
54664
+ if (existsSync37(projectLocalPath)) {
53755
54665
  return projectLocalPath;
53756
54666
  }
53757
54667
  return null;
@@ -54313,8 +55223,8 @@ function showProject(projectId) {
54313
55223
  function configureMCPClient(clientName, configPath, serverName, projectPath) {
54314
55224
  let config2 = { mcpServers: {} };
54315
55225
  try {
54316
- if (existsSync36(configPath)) {
54317
- const content = readFileSync29(configPath, "utf-8");
55226
+ if (existsSync37(configPath)) {
55227
+ const content = readFileSync30(configPath, "utf-8");
54318
55228
  config2 = JSON.parse(content);
54319
55229
  } else {
54320
55230
  const sep = process.platform === "win32" ? "\\" : "/";
@@ -54350,8 +55260,8 @@ function configureMCPClient(clientName, configPath, serverName, projectPath) {
54350
55260
  function configureProjectMCP(configPath, projectPath) {
54351
55261
  let config2 = { mcpServers: {} };
54352
55262
  try {
54353
- if (existsSync36(configPath)) {
54354
- const content = readFileSync29(configPath, "utf-8");
55263
+ if (existsSync37(configPath)) {
55264
+ const content = readFileSync30(configPath, "utf-8");
54355
55265
  config2 = JSON.parse(content);
54356
55266
  }
54357
55267
  } catch {
@@ -54383,7 +55293,7 @@ function configureProjectMCP(configPath, projectPath) {
54383
55293
  }
54384
55294
  }
54385
55295
  function configureClaudeMD(projectPath) {
54386
- const claudeMdPath = join37(projectPath, "CLAUDE.md");
55296
+ const claudeMdPath = join38(projectPath, "CLAUDE.md");
54387
55297
  const codeimpactSection = `
54388
55298
  ## CodeImpact Integration
54389
55299
 
@@ -54453,8 +55363,8 @@ codeimpact reindex
54453
55363
  `;
54454
55364
  try {
54455
55365
  let existingContent = "";
54456
- if (existsSync36(claudeMdPath)) {
54457
- existingContent = readFileSync29(claudeMdPath, "utf-8");
55366
+ if (existsSync37(claudeMdPath)) {
55367
+ existingContent = readFileSync30(claudeMdPath, "utf-8");
54458
55368
  if (existingContent.includes("## CodeImpact Integration")) {
54459
55369
  const startMarker = "## CodeImpact Integration";
54460
55370
  const startIndex = existingContent.indexOf(startMarker);
@@ -54485,18 +55395,18 @@ ${codeimpactSection}`;
54485
55395
  }
54486
55396
  }
54487
55397
  function configureCursorProjectMCP(projectPath) {
54488
- const cursorDir = join37(projectPath, ".cursor");
54489
- const configPath = join37(cursorDir, "mcp.json");
55398
+ const cursorDir = join38(projectPath, ".cursor");
55399
+ const configPath = join38(cursorDir, "mcp.json");
54490
55400
  try {
54491
- if (!existsSync36(cursorDir)) {
55401
+ if (!existsSync37(cursorDir)) {
54492
55402
  mkdirSync19(cursorDir, { recursive: true });
54493
55403
  }
54494
55404
  } catch {
54495
55405
  }
54496
55406
  let config2 = { mcpServers: {} };
54497
55407
  try {
54498
- if (existsSync36(configPath)) {
54499
- const content = readFileSync29(configPath, "utf-8");
55408
+ if (existsSync37(configPath)) {
55409
+ const content = readFileSync30(configPath, "utf-8");
54500
55410
  config2 = JSON.parse(content);
54501
55411
  }
54502
55412
  } catch {
@@ -54527,7 +55437,7 @@ function configureCursorProjectMCP(projectPath) {
54527
55437
  }
54528
55438
  }
54529
55439
  function configureCursorRules(projectPath) {
54530
- const cursorRulesPath = join37(projectPath, ".cursorrules");
55440
+ const cursorRulesPath = join38(projectPath, ".cursorrules");
54531
55441
  const codeimpactSection = `
54532
55442
  # CodeImpact Integration
54533
55443
 
@@ -54591,8 +55501,8 @@ codeimpact stats
54591
55501
  `;
54592
55502
  try {
54593
55503
  let existingContent = "";
54594
- if (existsSync36(cursorRulesPath)) {
54595
- existingContent = readFileSync29(cursorRulesPath, "utf-8");
55504
+ if (existsSync37(cursorRulesPath)) {
55505
+ existingContent = readFileSync30(cursorRulesPath, "utf-8");
54596
55506
  if (existingContent.includes("# CodeImpact Integration")) {
54597
55507
  const startMarker = "# CodeImpact Integration";
54598
55508
  const startIndex = existingContent.indexOf(startMarker);
@@ -54621,11 +55531,11 @@ codeimpact stats
54621
55531
  }
54622
55532
  }
54623
55533
  function configureOpenCode(projectPath) {
54624
- const configPath = join37(projectPath, "opencode.json");
55534
+ const configPath = join38(projectPath, "opencode.json");
54625
55535
  let config2 = {};
54626
55536
  try {
54627
- if (existsSync36(configPath)) {
54628
- const content = readFileSync29(configPath, "utf-8");
55537
+ if (existsSync37(configPath)) {
55538
+ const content = readFileSync30(configPath, "utf-8");
54629
55539
  config2 = JSON.parse(content);
54630
55540
  }
54631
55541
  } catch {
@@ -54661,8 +55571,8 @@ function configureOpenCode(projectPath) {
54661
55571
  function configureRemoteMCPClient(clientName, configPath, serverName, serverUrl) {
54662
55572
  let config2 = { mcpServers: {} };
54663
55573
  try {
54664
- if (existsSync36(configPath)) {
54665
- config2 = JSON.parse(readFileSync29(configPath, "utf-8"));
55574
+ if (existsSync37(configPath)) {
55575
+ config2 = JSON.parse(readFileSync30(configPath, "utf-8"));
54666
55576
  }
54667
55577
  } catch {
54668
55578
  }
@@ -54670,7 +55580,7 @@ function configureRemoteMCPClient(clientName, configPath, serverName, serverUrl)
54670
55580
  config2.mcpServers[serverName] = { url: serverUrl };
54671
55581
  try {
54672
55582
  const dir = configPath.substring(0, configPath.lastIndexOf("/") || configPath.lastIndexOf("\\"));
54673
- if (dir && !existsSync36(dir)) mkdirSync19(dir, { recursive: true });
55583
+ if (dir && !existsSync37(dir)) mkdirSync19(dir, { recursive: true });
54674
55584
  writeFileSync21(configPath, JSON.stringify(config2, null, 2));
54675
55585
  return { success: true, message: `${clientName}: ${configPath}` };
54676
55586
  } catch (err) {
@@ -54690,27 +55600,27 @@ function initProject(projectPath, serverUrl) {
54690
55600
  const failedClients = [];
54691
55601
  let claudeConfigPath;
54692
55602
  if (platform === "win32") {
54693
- claudeConfigPath = join37(homedir2(), "AppData", "Roaming", "Claude", "claude_desktop_config.json");
55603
+ claudeConfigPath = join38(homedir2(), "AppData", "Roaming", "Claude", "claude_desktop_config.json");
54694
55604
  } else if (platform === "darwin") {
54695
- claudeConfigPath = join37(homedir2(), "Library", "Application Support", "Claude", "claude_desktop_config.json");
55605
+ claudeConfigPath = join38(homedir2(), "Library", "Application Support", "Claude", "claude_desktop_config.json");
54696
55606
  } else {
54697
- claudeConfigPath = join37(homedir2(), ".config", "claude", "claude_desktop_config.json");
55607
+ claudeConfigPath = join38(homedir2(), ".config", "claude", "claude_desktop_config.json");
54698
55608
  }
54699
55609
  if (serverUrl) {
54700
55610
  const remoteProjectUrl = `${serverUrl}/mcp?project=${encodeURIComponent(resolve3(targetPath))}`;
54701
55611
  const claudeResult = configureRemoteMCPClient("Claude Desktop", claudeConfigPath, serverName, remoteProjectUrl);
54702
55612
  if (claudeResult.success) configuredClients.push(claudeResult.message);
54703
55613
  else failedClients.push(claudeResult.message);
54704
- const claudeCodeConfigPath = join37(targetPath, ".mcp.json");
55614
+ const claudeCodeConfigPath = join38(targetPath, ".mcp.json");
54705
55615
  const claudeCodeResult = configureRemoteMCPClient("Claude Code", claudeCodeConfigPath, "codeimpact", remoteProjectUrl);
54706
55616
  if (claudeCodeResult.success) configuredClients.push(claudeCodeResult.message);
54707
55617
  let cursorConfigPath;
54708
55618
  if (platform === "win32") {
54709
- cursorConfigPath = join37(homedir2(), "AppData", "Roaming", "Cursor", "User", "globalStorage", "cursor.mcp", "mcp.json");
55619
+ cursorConfigPath = join38(homedir2(), "AppData", "Roaming", "Cursor", "User", "globalStorage", "cursor.mcp", "mcp.json");
54710
55620
  } else if (platform === "darwin") {
54711
- cursorConfigPath = join37(homedir2(), "Library", "Application Support", "Cursor", "User", "globalStorage", "cursor.mcp", "mcp.json");
55621
+ cursorConfigPath = join38(homedir2(), "Library", "Application Support", "Cursor", "User", "globalStorage", "cursor.mcp", "mcp.json");
54712
55622
  } else {
54713
- cursorConfigPath = join37(homedir2(), ".config", "Cursor", "User", "globalStorage", "cursor.mcp", "mcp.json");
55623
+ cursorConfigPath = join38(homedir2(), ".config", "Cursor", "User", "globalStorage", "cursor.mcp", "mcp.json");
54714
55624
  }
54715
55625
  const cursorResult = configureRemoteMCPClient("Cursor (global)", cursorConfigPath, serverName, remoteProjectUrl);
54716
55626
  if (cursorResult.success) configuredClients.push(cursorResult.message);
@@ -54722,16 +55632,16 @@ function initProject(projectPath, serverUrl) {
54722
55632
  const openCodeResult = configureOpenCode(targetPath);
54723
55633
  if (openCodeResult.success) configuredClients.push(openCodeResult.message);
54724
55634
  else failedClients.push(openCodeResult.message);
54725
- const claudeCodeConfigPath = join37(targetPath, ".mcp.json");
55635
+ const claudeCodeConfigPath = join38(targetPath, ".mcp.json");
54726
55636
  const claudeCodeResult = configureProjectMCP(claudeCodeConfigPath, targetPath);
54727
55637
  if (claudeCodeResult.success) configuredClients.push(claudeCodeResult.message);
54728
55638
  let cursorConfigPath;
54729
55639
  if (platform === "win32") {
54730
- cursorConfigPath = join37(homedir2(), "AppData", "Roaming", "Cursor", "User", "globalStorage", "cursor.mcp", "mcp.json");
55640
+ cursorConfigPath = join38(homedir2(), "AppData", "Roaming", "Cursor", "User", "globalStorage", "cursor.mcp", "mcp.json");
54731
55641
  } else if (platform === "darwin") {
54732
- cursorConfigPath = join37(homedir2(), "Library", "Application Support", "Cursor", "User", "globalStorage", "cursor.mcp", "mcp.json");
55642
+ cursorConfigPath = join38(homedir2(), "Library", "Application Support", "Cursor", "User", "globalStorage", "cursor.mcp", "mcp.json");
54733
55643
  } else {
54734
- cursorConfigPath = join37(homedir2(), ".config", "Cursor", "User", "globalStorage", "cursor.mcp", "mcp.json");
55644
+ cursorConfigPath = join38(homedir2(), ".config", "Cursor", "User", "globalStorage", "cursor.mcp", "mcp.json");
54735
55645
  }
54736
55646
  const cursorGlobalResult = configureMCPClient("Cursor (global)", cursorConfigPath, serverName, targetPath);
54737
55647
  if (cursorGlobalResult.success) configuredClients.push(cursorGlobalResult.message);