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