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