neuronlayer 0.1.0 → 1.1.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/README.md +203 -123
- package/dist/index.js +635 -710
- package/dist/index.js.map +7 -0
- package/package.json +67 -63
- package/CONTRIBUTING.md +0 -127
- package/esbuild.config.js +0 -26
- package/src/cli/commands.ts +0 -382
- package/src/core/adr-exporter.ts +0 -253
- package/src/core/architecture/architecture-enforcement.ts +0 -228
- package/src/core/architecture/duplicate-detector.ts +0 -288
- package/src/core/architecture/index.ts +0 -6
- package/src/core/architecture/pattern-learner.ts +0 -306
- package/src/core/architecture/pattern-library.ts +0 -403
- package/src/core/architecture/pattern-validator.ts +0 -324
- package/src/core/change-intelligence/bug-correlator.ts +0 -444
- package/src/core/change-intelligence/change-intelligence.ts +0 -221
- package/src/core/change-intelligence/change-tracker.ts +0 -334
- package/src/core/change-intelligence/fix-suggester.ts +0 -340
- package/src/core/change-intelligence/index.ts +0 -5
- package/src/core/code-verifier.ts +0 -843
- package/src/core/confidence/confidence-scorer.ts +0 -251
- package/src/core/confidence/conflict-checker.ts +0 -289
- package/src/core/confidence/index.ts +0 -5
- package/src/core/confidence/source-tracker.ts +0 -263
- package/src/core/confidence/warning-detector.ts +0 -241
- package/src/core/context-rot/compaction.ts +0 -284
- package/src/core/context-rot/context-health.ts +0 -243
- package/src/core/context-rot/context-rot-prevention.ts +0 -213
- package/src/core/context-rot/critical-context.ts +0 -221
- package/src/core/context-rot/drift-detector.ts +0 -255
- package/src/core/context-rot/index.ts +0 -7
- package/src/core/context.ts +0 -263
- package/src/core/decision-extractor.ts +0 -339
- package/src/core/decisions.ts +0 -69
- package/src/core/deja-vu.ts +0 -421
- package/src/core/engine.ts +0 -1455
- package/src/core/feature-context.ts +0 -726
- package/src/core/ghost-mode.ts +0 -412
- package/src/core/learning.ts +0 -485
- package/src/core/living-docs/activity-tracker.ts +0 -296
- package/src/core/living-docs/architecture-generator.ts +0 -428
- package/src/core/living-docs/changelog-generator.ts +0 -348
- package/src/core/living-docs/component-generator.ts +0 -230
- package/src/core/living-docs/doc-engine.ts +0 -110
- package/src/core/living-docs/doc-validator.ts +0 -282
- package/src/core/living-docs/index.ts +0 -8
- package/src/core/project-manager.ts +0 -297
- package/src/core/summarizer.ts +0 -267
- package/src/core/test-awareness/change-validator.ts +0 -499
- package/src/core/test-awareness/index.ts +0 -5
- package/src/index.ts +0 -49
- package/src/indexing/ast.ts +0 -563
- package/src/indexing/embeddings.ts +0 -85
- package/src/indexing/indexer.ts +0 -245
- package/src/indexing/watcher.ts +0 -78
- package/src/server/gateways/aggregator.ts +0 -374
- package/src/server/gateways/index.ts +0 -473
- package/src/server/gateways/memory-ghost.ts +0 -343
- package/src/server/gateways/memory-query.ts +0 -452
- package/src/server/gateways/memory-record.ts +0 -346
- package/src/server/gateways/memory-review.ts +0 -410
- package/src/server/gateways/memory-status.ts +0 -517
- package/src/server/gateways/memory-verify.ts +0 -392
- package/src/server/gateways/router.ts +0 -434
- package/src/server/gateways/types.ts +0 -610
- package/src/server/mcp.ts +0 -154
- package/src/server/resources.ts +0 -85
- package/src/server/tools.ts +0 -2261
- package/src/storage/database.ts +0 -262
- package/src/storage/tier1.ts +0 -135
- package/src/storage/tier2.ts +0 -764
- package/src/storage/tier3.ts +0 -123
- package/src/types/documentation.ts +0 -619
- package/src/types/index.ts +0 -222
- package/src/utils/config.ts +0 -193
- package/src/utils/files.ts +0 -117
- package/src/utils/time.ts +0 -37
- package/src/utils/tokens.ts +0 -52
package/dist/index.js
CHANGED
|
@@ -8,8 +8,7 @@ var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
|
8
8
|
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
9
9
|
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
10
10
|
}) : x)(function(x) {
|
|
11
|
-
if (typeof require !== "undefined")
|
|
12
|
-
return require.apply(this, arguments);
|
|
11
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
13
12
|
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
14
13
|
});
|
|
15
14
|
var __commonJS = (cb, mod) => function __require2() {
|
|
@@ -2048,38 +2047,28 @@ var require_fast_deep_equal = __commonJS({
|
|
|
2048
2047
|
"node_modules/fast-deep-equal/index.js"(exports, module) {
|
|
2049
2048
|
"use strict";
|
|
2050
2049
|
module.exports = function equal(a, b) {
|
|
2051
|
-
if (a === b)
|
|
2052
|
-
return true;
|
|
2050
|
+
if (a === b) return true;
|
|
2053
2051
|
if (a && b && typeof a == "object" && typeof b == "object") {
|
|
2054
|
-
if (a.constructor !== b.constructor)
|
|
2055
|
-
return false;
|
|
2052
|
+
if (a.constructor !== b.constructor) return false;
|
|
2056
2053
|
var length, i, keys;
|
|
2057
2054
|
if (Array.isArray(a)) {
|
|
2058
2055
|
length = a.length;
|
|
2059
|
-
if (length != b.length)
|
|
2060
|
-
return false;
|
|
2056
|
+
if (length != b.length) return false;
|
|
2061
2057
|
for (i = length; i-- !== 0; )
|
|
2062
|
-
if (!equal(a[i], b[i]))
|
|
2063
|
-
return false;
|
|
2058
|
+
if (!equal(a[i], b[i])) return false;
|
|
2064
2059
|
return true;
|
|
2065
2060
|
}
|
|
2066
|
-
if (a.constructor === RegExp)
|
|
2067
|
-
|
|
2068
|
-
if (a.
|
|
2069
|
-
return a.valueOf() === b.valueOf();
|
|
2070
|
-
if (a.toString !== Object.prototype.toString)
|
|
2071
|
-
return a.toString() === b.toString();
|
|
2061
|
+
if (a.constructor === RegExp) return a.source === b.source && a.flags === b.flags;
|
|
2062
|
+
if (a.valueOf !== Object.prototype.valueOf) return a.valueOf() === b.valueOf();
|
|
2063
|
+
if (a.toString !== Object.prototype.toString) return a.toString() === b.toString();
|
|
2072
2064
|
keys = Object.keys(a);
|
|
2073
2065
|
length = keys.length;
|
|
2074
|
-
if (length !== Object.keys(b).length)
|
|
2075
|
-
return false;
|
|
2066
|
+
if (length !== Object.keys(b).length) return false;
|
|
2076
2067
|
for (i = length; i-- !== 0; )
|
|
2077
|
-
if (!Object.prototype.hasOwnProperty.call(b, keys[i]))
|
|
2078
|
-
return false;
|
|
2068
|
+
if (!Object.prototype.hasOwnProperty.call(b, keys[i])) return false;
|
|
2079
2069
|
for (i = length; i-- !== 0; ) {
|
|
2080
2070
|
var key = keys[i];
|
|
2081
|
-
if (!equal(a[key], b[key]))
|
|
2082
|
-
return false;
|
|
2071
|
+
if (!equal(a[key], b[key])) return false;
|
|
2083
2072
|
}
|
|
2084
2073
|
return true;
|
|
2085
2074
|
}
|
|
@@ -3235,8 +3224,7 @@ var require_utils = __commonJS({
|
|
|
3235
3224
|
function findToken(str, token) {
|
|
3236
3225
|
let ind = 0;
|
|
3237
3226
|
for (let i = 0; i < str.length; i++) {
|
|
3238
|
-
if (str[i] === token)
|
|
3239
|
-
ind++;
|
|
3227
|
+
if (str[i] === token) ind++;
|
|
3240
3228
|
}
|
|
3241
3229
|
return ind;
|
|
3242
3230
|
}
|
|
@@ -3694,8 +3682,7 @@ var require_fast_uri = __commonJS({
|
|
|
3694
3682
|
const options = Object.assign({}, opts);
|
|
3695
3683
|
const uriTokens = [];
|
|
3696
3684
|
const schemeHandler = getSchemeHandler(options.scheme || component.scheme);
|
|
3697
|
-
if (schemeHandler && schemeHandler.serialize)
|
|
3698
|
-
schemeHandler.serialize(component, options);
|
|
3685
|
+
if (schemeHandler && schemeHandler.serialize) schemeHandler.serialize(component, options);
|
|
3699
3686
|
if (component.path !== void 0) {
|
|
3700
3687
|
if (!options.skipEscape) {
|
|
3701
3688
|
component.path = escape(component.path);
|
|
@@ -4744,6 +4731,7 @@ var require_pattern = __commonJS({
|
|
|
4744
4731
|
"use strict";
|
|
4745
4732
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4746
4733
|
var code_1 = require_code2();
|
|
4734
|
+
var util_1 = require_util();
|
|
4747
4735
|
var codegen_1 = require_codegen();
|
|
4748
4736
|
var error2 = {
|
|
4749
4737
|
message: ({ schemaCode }) => (0, codegen_1.str)`must match pattern "${schemaCode}"`,
|
|
@@ -4756,10 +4744,18 @@ var require_pattern = __commonJS({
|
|
|
4756
4744
|
$data: true,
|
|
4757
4745
|
error: error2,
|
|
4758
4746
|
code(cxt) {
|
|
4759
|
-
const { data, $data, schema, schemaCode, it } = cxt;
|
|
4747
|
+
const { gen, data, $data, schema, schemaCode, it } = cxt;
|
|
4760
4748
|
const u = it.opts.unicodeRegExp ? "u" : "";
|
|
4761
|
-
|
|
4762
|
-
|
|
4749
|
+
if ($data) {
|
|
4750
|
+
const { regExp } = it.opts.code;
|
|
4751
|
+
const regExpCode = regExp.code === "new RegExp" ? (0, codegen_1._)`new RegExp` : (0, util_1.useFunc)(gen, regExp);
|
|
4752
|
+
const valid = gen.let("valid");
|
|
4753
|
+
gen.try(() => gen.assign(valid, (0, codegen_1._)`${regExpCode}(${schemaCode}, ${u}).test(${data})`), () => gen.assign(valid, false));
|
|
4754
|
+
cxt.fail$data((0, codegen_1._)`!${valid}`);
|
|
4755
|
+
} else {
|
|
4756
|
+
const regExp = (0, code_1.usePattern)(cxt, schema);
|
|
4757
|
+
cxt.fail$data((0, codegen_1._)`!${regExp}.test(${data})`);
|
|
4758
|
+
}
|
|
4763
4759
|
}
|
|
4764
4760
|
};
|
|
4765
4761
|
exports.default = def;
|
|
@@ -15218,7 +15214,7 @@ function _stringbool(Classes, _params) {
|
|
|
15218
15214
|
type: "pipe",
|
|
15219
15215
|
in: stringSchema,
|
|
15220
15216
|
out: booleanSchema,
|
|
15221
|
-
transform: (input, payload) => {
|
|
15217
|
+
transform: ((input, payload) => {
|
|
15222
15218
|
let data = input;
|
|
15223
15219
|
if (params.case !== "sensitive")
|
|
15224
15220
|
data = data.toLowerCase();
|
|
@@ -15237,14 +15233,14 @@ function _stringbool(Classes, _params) {
|
|
|
15237
15233
|
});
|
|
15238
15234
|
return {};
|
|
15239
15235
|
}
|
|
15240
|
-
},
|
|
15241
|
-
reverseTransform: (input, _payload) => {
|
|
15236
|
+
}),
|
|
15237
|
+
reverseTransform: ((input, _payload) => {
|
|
15242
15238
|
if (input === true) {
|
|
15243
15239
|
return truthyArray[0] || "true";
|
|
15244
15240
|
} else {
|
|
15245
15241
|
return falsyArray[0] || "false";
|
|
15246
15242
|
}
|
|
15247
|
-
},
|
|
15243
|
+
}),
|
|
15248
15244
|
error: params.error
|
|
15249
15245
|
});
|
|
15250
15246
|
return codec2;
|
|
@@ -16482,10 +16478,10 @@ var ZodType2 = /* @__PURE__ */ $constructor("ZodType", (inst, def) => {
|
|
|
16482
16478
|
inst.with = inst.check;
|
|
16483
16479
|
inst.clone = (def2, params) => clone(inst, def2, params);
|
|
16484
16480
|
inst.brand = () => inst;
|
|
16485
|
-
inst.register = (reg, meta3) => {
|
|
16481
|
+
inst.register = ((reg, meta3) => {
|
|
16486
16482
|
reg.add(inst, meta3);
|
|
16487
16483
|
return inst;
|
|
16488
|
-
};
|
|
16484
|
+
});
|
|
16489
16485
|
inst.parse = (data, params) => parse2(inst, data, params, { callee: inst.parse });
|
|
16490
16486
|
inst.safeParse = (data, params) => safeParse3(inst, data, params);
|
|
16491
16487
|
inst.parseAsync = async (data, params) => parseAsync2(inst, data, params, { callee: inst.parseAsync });
|
|
@@ -20126,6 +20122,147 @@ var ExperimentalServerTasks = class {
|
|
|
20126
20122
|
requestStream(request, resultSchema, options) {
|
|
20127
20123
|
return this._server.requestStream(request, resultSchema, options);
|
|
20128
20124
|
}
|
|
20125
|
+
/**
|
|
20126
|
+
* Sends a sampling request and returns an AsyncGenerator that yields response messages.
|
|
20127
|
+
* The generator is guaranteed to end with either a 'result' or 'error' message.
|
|
20128
|
+
*
|
|
20129
|
+
* For task-augmented requests, yields 'taskCreated' and 'taskStatus' messages
|
|
20130
|
+
* before the final result.
|
|
20131
|
+
*
|
|
20132
|
+
* @example
|
|
20133
|
+
* ```typescript
|
|
20134
|
+
* const stream = server.experimental.tasks.createMessageStream({
|
|
20135
|
+
* messages: [{ role: 'user', content: { type: 'text', text: 'Hello' } }],
|
|
20136
|
+
* maxTokens: 100
|
|
20137
|
+
* }, {
|
|
20138
|
+
* onprogress: (progress) => {
|
|
20139
|
+
* // Handle streaming tokens via progress notifications
|
|
20140
|
+
* console.log('Progress:', progress.message);
|
|
20141
|
+
* }
|
|
20142
|
+
* });
|
|
20143
|
+
*
|
|
20144
|
+
* for await (const message of stream) {
|
|
20145
|
+
* switch (message.type) {
|
|
20146
|
+
* case 'taskCreated':
|
|
20147
|
+
* console.log('Task created:', message.task.taskId);
|
|
20148
|
+
* break;
|
|
20149
|
+
* case 'taskStatus':
|
|
20150
|
+
* console.log('Task status:', message.task.status);
|
|
20151
|
+
* break;
|
|
20152
|
+
* case 'result':
|
|
20153
|
+
* console.log('Final result:', message.result);
|
|
20154
|
+
* break;
|
|
20155
|
+
* case 'error':
|
|
20156
|
+
* console.error('Error:', message.error);
|
|
20157
|
+
* break;
|
|
20158
|
+
* }
|
|
20159
|
+
* }
|
|
20160
|
+
* ```
|
|
20161
|
+
*
|
|
20162
|
+
* @param params - The sampling request parameters
|
|
20163
|
+
* @param options - Optional request options (timeout, signal, task creation params, onprogress, etc.)
|
|
20164
|
+
* @returns AsyncGenerator that yields ResponseMessage objects
|
|
20165
|
+
*
|
|
20166
|
+
* @experimental
|
|
20167
|
+
*/
|
|
20168
|
+
createMessageStream(params, options) {
|
|
20169
|
+
const clientCapabilities = this._server.getClientCapabilities();
|
|
20170
|
+
if ((params.tools || params.toolChoice) && !clientCapabilities?.sampling?.tools) {
|
|
20171
|
+
throw new Error("Client does not support sampling tools capability.");
|
|
20172
|
+
}
|
|
20173
|
+
if (params.messages.length > 0) {
|
|
20174
|
+
const lastMessage = params.messages[params.messages.length - 1];
|
|
20175
|
+
const lastContent = Array.isArray(lastMessage.content) ? lastMessage.content : [lastMessage.content];
|
|
20176
|
+
const hasToolResults = lastContent.some((c) => c.type === "tool_result");
|
|
20177
|
+
const previousMessage = params.messages.length > 1 ? params.messages[params.messages.length - 2] : void 0;
|
|
20178
|
+
const previousContent = previousMessage ? Array.isArray(previousMessage.content) ? previousMessage.content : [previousMessage.content] : [];
|
|
20179
|
+
const hasPreviousToolUse = previousContent.some((c) => c.type === "tool_use");
|
|
20180
|
+
if (hasToolResults) {
|
|
20181
|
+
if (lastContent.some((c) => c.type !== "tool_result")) {
|
|
20182
|
+
throw new Error("The last message must contain only tool_result content if any is present");
|
|
20183
|
+
}
|
|
20184
|
+
if (!hasPreviousToolUse) {
|
|
20185
|
+
throw new Error("tool_result blocks are not matching any tool_use from the previous message");
|
|
20186
|
+
}
|
|
20187
|
+
}
|
|
20188
|
+
if (hasPreviousToolUse) {
|
|
20189
|
+
const toolUseIds = new Set(previousContent.filter((c) => c.type === "tool_use").map((c) => c.id));
|
|
20190
|
+
const toolResultIds = new Set(lastContent.filter((c) => c.type === "tool_result").map((c) => c.toolUseId));
|
|
20191
|
+
if (toolUseIds.size !== toolResultIds.size || ![...toolUseIds].every((id) => toolResultIds.has(id))) {
|
|
20192
|
+
throw new Error("ids of tool_result blocks and tool_use blocks from previous message do not match");
|
|
20193
|
+
}
|
|
20194
|
+
}
|
|
20195
|
+
}
|
|
20196
|
+
return this.requestStream({
|
|
20197
|
+
method: "sampling/createMessage",
|
|
20198
|
+
params
|
|
20199
|
+
}, CreateMessageResultSchema, options);
|
|
20200
|
+
}
|
|
20201
|
+
/**
|
|
20202
|
+
* Sends an elicitation request and returns an AsyncGenerator that yields response messages.
|
|
20203
|
+
* The generator is guaranteed to end with either a 'result' or 'error' message.
|
|
20204
|
+
*
|
|
20205
|
+
* For task-augmented requests (especially URL-based elicitation), yields 'taskCreated'
|
|
20206
|
+
* and 'taskStatus' messages before the final result.
|
|
20207
|
+
*
|
|
20208
|
+
* @example
|
|
20209
|
+
* ```typescript
|
|
20210
|
+
* const stream = server.experimental.tasks.elicitInputStream({
|
|
20211
|
+
* mode: 'url',
|
|
20212
|
+
* message: 'Please authenticate',
|
|
20213
|
+
* elicitationId: 'auth-123',
|
|
20214
|
+
* url: 'https://example.com/auth'
|
|
20215
|
+
* }, {
|
|
20216
|
+
* task: { ttl: 300000 } // Task-augmented for long-running auth flow
|
|
20217
|
+
* });
|
|
20218
|
+
*
|
|
20219
|
+
* for await (const message of stream) {
|
|
20220
|
+
* switch (message.type) {
|
|
20221
|
+
* case 'taskCreated':
|
|
20222
|
+
* console.log('Task created:', message.task.taskId);
|
|
20223
|
+
* break;
|
|
20224
|
+
* case 'taskStatus':
|
|
20225
|
+
* console.log('Task status:', message.task.status);
|
|
20226
|
+
* break;
|
|
20227
|
+
* case 'result':
|
|
20228
|
+
* console.log('User action:', message.result.action);
|
|
20229
|
+
* break;
|
|
20230
|
+
* case 'error':
|
|
20231
|
+
* console.error('Error:', message.error);
|
|
20232
|
+
* break;
|
|
20233
|
+
* }
|
|
20234
|
+
* }
|
|
20235
|
+
* ```
|
|
20236
|
+
*
|
|
20237
|
+
* @param params - The elicitation request parameters
|
|
20238
|
+
* @param options - Optional request options (timeout, signal, task creation params, etc.)
|
|
20239
|
+
* @returns AsyncGenerator that yields ResponseMessage objects
|
|
20240
|
+
*
|
|
20241
|
+
* @experimental
|
|
20242
|
+
*/
|
|
20243
|
+
elicitInputStream(params, options) {
|
|
20244
|
+
const clientCapabilities = this._server.getClientCapabilities();
|
|
20245
|
+
const mode = params.mode ?? "form";
|
|
20246
|
+
switch (mode) {
|
|
20247
|
+
case "url": {
|
|
20248
|
+
if (!clientCapabilities?.elicitation?.url) {
|
|
20249
|
+
throw new Error("Client does not support url elicitation.");
|
|
20250
|
+
}
|
|
20251
|
+
break;
|
|
20252
|
+
}
|
|
20253
|
+
case "form": {
|
|
20254
|
+
if (!clientCapabilities?.elicitation?.form) {
|
|
20255
|
+
throw new Error("Client does not support form elicitation.");
|
|
20256
|
+
}
|
|
20257
|
+
break;
|
|
20258
|
+
}
|
|
20259
|
+
}
|
|
20260
|
+
const normalizedParams = mode === "form" && params.mode === void 0 ? { ...params, mode: "form" } : params;
|
|
20261
|
+
return this.requestStream({
|
|
20262
|
+
method: "elicitation/create",
|
|
20263
|
+
params: normalizedParams
|
|
20264
|
+
}, ElicitResultSchema, options);
|
|
20265
|
+
}
|
|
20129
20266
|
/**
|
|
20130
20267
|
* Gets the current status of a task.
|
|
20131
20268
|
*
|
|
@@ -20684,7 +20821,7 @@ var StdioServerTransport = class {
|
|
|
20684
20821
|
};
|
|
20685
20822
|
|
|
20686
20823
|
// src/core/engine.ts
|
|
20687
|
-
import { join as
|
|
20824
|
+
import { join as join13, basename as basename6 } from "path";
|
|
20688
20825
|
import { existsSync as existsSync13, mkdirSync as mkdirSync6, readFileSync as readFileSync10 } from "fs";
|
|
20689
20826
|
|
|
20690
20827
|
// src/storage/database.ts
|
|
@@ -21133,8 +21270,7 @@ var Tier2Storage = class {
|
|
|
21133
21270
|
getEmbedding(fileId) {
|
|
21134
21271
|
const stmt = this.db.prepare("SELECT embedding, dimension FROM embeddings WHERE file_id = ?");
|
|
21135
21272
|
const result = stmt.get(fileId);
|
|
21136
|
-
if (!result)
|
|
21137
|
-
return null;
|
|
21273
|
+
if (!result) return null;
|
|
21138
21274
|
return new Float32Array(result.embedding.buffer, result.embedding.byteOffset, result.dimension);
|
|
21139
21275
|
}
|
|
21140
21276
|
getAllEmbeddings() {
|
|
@@ -21173,8 +21309,7 @@ var Tier2Storage = class {
|
|
|
21173
21309
|
return searchResults;
|
|
21174
21310
|
}
|
|
21175
21311
|
cosineSimilarity(a, b) {
|
|
21176
|
-
if (a.length !== b.length)
|
|
21177
|
-
return 0;
|
|
21312
|
+
if (a.length !== b.length) return 0;
|
|
21178
21313
|
let dotProduct = 0;
|
|
21179
21314
|
let normA = 0;
|
|
21180
21315
|
let normB = 0;
|
|
@@ -21218,8 +21353,7 @@ var Tier2Storage = class {
|
|
|
21218
21353
|
getDecision(id) {
|
|
21219
21354
|
const stmt = this.db.prepare("SELECT * FROM decisions WHERE id = ?");
|
|
21220
21355
|
const row = stmt.get(id);
|
|
21221
|
-
if (!row)
|
|
21222
|
-
return null;
|
|
21356
|
+
if (!row) return null;
|
|
21223
21357
|
return {
|
|
21224
21358
|
id: row.id,
|
|
21225
21359
|
title: row.title,
|
|
@@ -21356,8 +21490,7 @@ var Tier2Storage = class {
|
|
|
21356
21490
|
getProjectSummary() {
|
|
21357
21491
|
const stmt = this.db.prepare("SELECT name, description, languages, key_directories, architecture_notes FROM project_summary WHERE id = 1");
|
|
21358
21492
|
const row = stmt.get();
|
|
21359
|
-
if (!row)
|
|
21360
|
-
return null;
|
|
21493
|
+
if (!row) return null;
|
|
21361
21494
|
return {
|
|
21362
21495
|
name: row.name,
|
|
21363
21496
|
description: row.description,
|
|
@@ -21468,8 +21601,7 @@ var Tier2Storage = class {
|
|
|
21468
21601
|
query += " LIMIT 1";
|
|
21469
21602
|
const stmt = this.db.prepare(query);
|
|
21470
21603
|
const row = stmt.get(...params);
|
|
21471
|
-
if (!row)
|
|
21472
|
-
return null;
|
|
21604
|
+
if (!row) return null;
|
|
21473
21605
|
return {
|
|
21474
21606
|
id: row.id,
|
|
21475
21607
|
fileId: row.fileId,
|
|
@@ -21577,8 +21709,7 @@ var Tier2Storage = class {
|
|
|
21577
21709
|
// Phase 2: Dependency graph helpers
|
|
21578
21710
|
getFileDependencies(filePath) {
|
|
21579
21711
|
const file2 = this.getFile(filePath);
|
|
21580
|
-
if (!file2)
|
|
21581
|
-
return [];
|
|
21712
|
+
if (!file2) return [];
|
|
21582
21713
|
const imports = this.getImportsByFile(file2.id);
|
|
21583
21714
|
const deps = [];
|
|
21584
21715
|
for (const imp of imports) {
|
|
@@ -21657,8 +21788,7 @@ var Tier3Storage = class {
|
|
|
21657
21788
|
const sessions = this.getRecentSessions(50);
|
|
21658
21789
|
const results = [];
|
|
21659
21790
|
for (const session of sessions) {
|
|
21660
|
-
if (!session.summary)
|
|
21661
|
-
continue;
|
|
21791
|
+
if (!session.summary) continue;
|
|
21662
21792
|
const summaryLower = session.summary.toLowerCase();
|
|
21663
21793
|
let matchCount = 0;
|
|
21664
21794
|
for (const keyword of keywords) {
|
|
@@ -21709,8 +21839,7 @@ var EmbeddingGenerator = class {
|
|
|
21709
21839
|
this.modelName = modelName;
|
|
21710
21840
|
}
|
|
21711
21841
|
async initialize() {
|
|
21712
|
-
if (this.initialized)
|
|
21713
|
-
return;
|
|
21842
|
+
if (this.initialized) return;
|
|
21714
21843
|
if (this.initializing) {
|
|
21715
21844
|
while (this.initializing) {
|
|
21716
21845
|
await new Promise((resolve3) => setTimeout(resolve3, 100));
|
|
@@ -21765,127 +21894,29 @@ var EmbeddingGenerator = class {
|
|
|
21765
21894
|
};
|
|
21766
21895
|
|
|
21767
21896
|
// src/indexing/ast.ts
|
|
21768
|
-
|
|
21769
|
-
|
|
21770
|
-
|
|
21771
|
-
|
|
21772
|
-
wasmFile: "tree-sitter-typescript.wasm",
|
|
21773
|
-
extensions: [".ts", ".tsx"],
|
|
21774
|
-
queries: {
|
|
21775
|
-
functions: `
|
|
21776
|
-
(function_declaration name: (identifier) @name) @func
|
|
21777
|
-
(arrow_function) @func
|
|
21778
|
-
(method_definition name: (property_identifier) @name) @func
|
|
21779
|
-
`,
|
|
21780
|
-
classes: `
|
|
21781
|
-
(class_declaration name: (type_identifier) @name) @class
|
|
21782
|
-
`,
|
|
21783
|
-
interfaces: `
|
|
21784
|
-
(interface_declaration name: (type_identifier) @name) @interface
|
|
21785
|
-
`,
|
|
21786
|
-
types: `
|
|
21787
|
-
(type_alias_declaration name: (type_identifier) @name) @type
|
|
21788
|
-
`,
|
|
21789
|
-
imports: `
|
|
21790
|
-
(import_statement) @import
|
|
21791
|
-
`,
|
|
21792
|
-
exports: `
|
|
21793
|
-
(export_statement) @export
|
|
21794
|
-
`
|
|
21795
|
-
}
|
|
21796
|
-
},
|
|
21797
|
-
javascript: {
|
|
21798
|
-
wasmFile: "tree-sitter-javascript.wasm",
|
|
21799
|
-
extensions: [".js", ".jsx", ".mjs", ".cjs"],
|
|
21800
|
-
queries: {
|
|
21801
|
-
functions: `
|
|
21802
|
-
(function_declaration name: (identifier) @name) @func
|
|
21803
|
-
(arrow_function) @func
|
|
21804
|
-
(method_definition name: (property_identifier) @name) @func
|
|
21805
|
-
`,
|
|
21806
|
-
classes: `
|
|
21807
|
-
(class_declaration name: (identifier) @name) @class
|
|
21808
|
-
`,
|
|
21809
|
-
imports: `
|
|
21810
|
-
(import_statement) @import
|
|
21811
|
-
`,
|
|
21812
|
-
exports: `
|
|
21813
|
-
(export_statement) @export
|
|
21814
|
-
`
|
|
21815
|
-
}
|
|
21816
|
-
},
|
|
21817
|
-
python: {
|
|
21818
|
-
wasmFile: "tree-sitter-python.wasm",
|
|
21819
|
-
extensions: [".py"],
|
|
21820
|
-
queries: {
|
|
21821
|
-
functions: `
|
|
21822
|
-
(function_definition name: (identifier) @name) @func
|
|
21823
|
-
`,
|
|
21824
|
-
classes: `
|
|
21825
|
-
(class_definition name: (identifier) @name) @class
|
|
21826
|
-
`,
|
|
21827
|
-
imports: `
|
|
21828
|
-
(import_statement) @import
|
|
21829
|
-
(import_from_statement) @import
|
|
21830
|
-
`
|
|
21831
|
-
}
|
|
21832
|
-
}
|
|
21897
|
+
var LANGUAGE_EXTENSIONS = {
|
|
21898
|
+
typescript: [".ts", ".tsx"],
|
|
21899
|
+
javascript: [".js", ".jsx", ".mjs", ".cjs"],
|
|
21900
|
+
python: [".py"]
|
|
21833
21901
|
};
|
|
21834
21902
|
var ASTParser = class {
|
|
21835
|
-
|
|
21836
|
-
languages = /* @__PURE__ */ new Map();
|
|
21837
|
-
initialized = false;
|
|
21838
|
-
dataDir;
|
|
21839
|
-
constructor(dataDir) {
|
|
21840
|
-
this.dataDir = dataDir;
|
|
21903
|
+
constructor(_dataDir) {
|
|
21841
21904
|
}
|
|
21842
21905
|
async initialize() {
|
|
21843
|
-
if (this.initialized)
|
|
21844
|
-
return;
|
|
21845
|
-
try {
|
|
21846
|
-
await Parser.init();
|
|
21847
|
-
this.parser = new Parser();
|
|
21848
|
-
this.initialized = true;
|
|
21849
|
-
console.error("AST Parser initialized");
|
|
21850
|
-
} catch (error2) {
|
|
21851
|
-
console.error("Failed to initialize AST parser:", error2);
|
|
21852
|
-
throw error2;
|
|
21853
|
-
}
|
|
21854
|
-
}
|
|
21855
|
-
async loadLanguage(langName) {
|
|
21856
|
-
if (this.languages.has(langName)) {
|
|
21857
|
-
return this.languages.get(langName);
|
|
21858
|
-
}
|
|
21859
|
-
const config2 = LANGUAGE_CONFIGS[langName];
|
|
21860
|
-
if (!config2) {
|
|
21861
|
-
return null;
|
|
21862
|
-
}
|
|
21863
|
-
try {
|
|
21864
|
-
const wasmDir = join2(this.dataDir, "wasm");
|
|
21865
|
-
const wasmPath = join2(wasmDir, config2.wasmFile);
|
|
21866
|
-
console.error(`Language ${langName} WASM not available yet`);
|
|
21867
|
-
return null;
|
|
21868
|
-
} catch (error2) {
|
|
21869
|
-
console.error(`Failed to load language ${langName}:`, error2);
|
|
21870
|
-
return null;
|
|
21871
|
-
}
|
|
21872
21906
|
}
|
|
21873
21907
|
getLanguageForFile(filePath) {
|
|
21874
21908
|
const ext = filePath.slice(filePath.lastIndexOf(".")).toLowerCase();
|
|
21875
|
-
for (const [lang,
|
|
21876
|
-
if (
|
|
21909
|
+
for (const [lang, extensions] of Object.entries(LANGUAGE_EXTENSIONS)) {
|
|
21910
|
+
if (extensions.includes(ext)) {
|
|
21877
21911
|
return lang;
|
|
21878
21912
|
}
|
|
21879
21913
|
}
|
|
21880
21914
|
return null;
|
|
21881
21915
|
}
|
|
21882
21916
|
async parseFile(filePath, content) {
|
|
21883
|
-
if (!this.initialized) {
|
|
21884
|
-
await this.initialize();
|
|
21885
|
-
}
|
|
21886
21917
|
return this.parseWithRegex(filePath, content);
|
|
21887
21918
|
}
|
|
21888
|
-
// Regex-based parsing
|
|
21919
|
+
// Regex-based parsing for symbol extraction
|
|
21889
21920
|
parseWithRegex(filePath, content) {
|
|
21890
21921
|
const symbols = [];
|
|
21891
21922
|
const imports = [];
|
|
@@ -22120,8 +22151,7 @@ var ASTParser = class {
|
|
|
22120
22151
|
const trimmed = line.trim();
|
|
22121
22152
|
const lineNum = i + 1;
|
|
22122
22153
|
const indent = line.length - line.trimStart().length;
|
|
22123
|
-
if (trimmed.startsWith("#"))
|
|
22124
|
-
continue;
|
|
22154
|
+
if (trimmed.startsWith("#")) continue;
|
|
22125
22155
|
let match = trimmed.match(patterns.function);
|
|
22126
22156
|
if (match && match[1]) {
|
|
22127
22157
|
symbols.push({
|
|
@@ -22209,8 +22239,7 @@ var ASTParser = class {
|
|
|
22209
22239
|
findPythonBlockEnd(lines, startIndex, baseIndent) {
|
|
22210
22240
|
for (let i = startIndex + 1; i < lines.length; i++) {
|
|
22211
22241
|
const line = lines[i] || "";
|
|
22212
|
-
if (line.trim() === "")
|
|
22213
|
-
continue;
|
|
22242
|
+
if (line.trim() === "") continue;
|
|
22214
22243
|
const indent = line.length - line.trimStart().length;
|
|
22215
22244
|
if (indent <= baseIndent) {
|
|
22216
22245
|
return i;
|
|
@@ -22369,12 +22398,9 @@ var CODE_EXTENSIONS = new Set(Object.keys(LANGUAGE_MAP));
|
|
|
22369
22398
|
function detectLanguage(filePath) {
|
|
22370
22399
|
const ext = extname(filePath).toLowerCase();
|
|
22371
22400
|
const filename = filePath.split(/[/\\]/).pop()?.toLowerCase() || "";
|
|
22372
|
-
if (filename === "dockerfile")
|
|
22373
|
-
|
|
22374
|
-
if (filename === "
|
|
22375
|
-
return "makefile";
|
|
22376
|
-
if (filename === "cmakelists.txt")
|
|
22377
|
-
return "cmake";
|
|
22401
|
+
if (filename === "dockerfile") return "dockerfile";
|
|
22402
|
+
if (filename === "makefile") return "makefile";
|
|
22403
|
+
if (filename === "cmakelists.txt") return "cmake";
|
|
22378
22404
|
return LANGUAGE_MAP[ext] || "plaintext";
|
|
22379
22405
|
}
|
|
22380
22406
|
function isCodeFile(filePath) {
|
|
@@ -22392,8 +22418,7 @@ function getPreview(content, maxLength = 1e3) {
|
|
|
22392
22418
|
return content.slice(0, maxLength) + "\n... [truncated]";
|
|
22393
22419
|
}
|
|
22394
22420
|
function countLines(content) {
|
|
22395
|
-
if (!content)
|
|
22396
|
-
return 0;
|
|
22421
|
+
if (!content) return 0;
|
|
22397
22422
|
return content.split("\n").length;
|
|
22398
22423
|
}
|
|
22399
22424
|
|
|
@@ -22604,13 +22629,12 @@ var Indexer = class extends EventEmitter2 {
|
|
|
22604
22629
|
};
|
|
22605
22630
|
|
|
22606
22631
|
// src/core/context.ts
|
|
22607
|
-
import { dirname as
|
|
22632
|
+
import { dirname as dirname3, basename } from "path";
|
|
22608
22633
|
|
|
22609
22634
|
// src/utils/tokens.ts
|
|
22610
22635
|
var AVG_CHARS_PER_TOKEN = 4;
|
|
22611
22636
|
function estimateTokens(text) {
|
|
22612
|
-
if (!text)
|
|
22613
|
-
return 0;
|
|
22637
|
+
if (!text) return 0;
|
|
22614
22638
|
return Math.ceil(text.length / AVG_CHARS_PER_TOKEN);
|
|
22615
22639
|
}
|
|
22616
22640
|
var TokenBudget = class {
|
|
@@ -22801,7 +22825,7 @@ ${result.preview}
|
|
|
22801
22825
|
const filesViewed = this.tier1.getFilesViewed();
|
|
22802
22826
|
return results.map((r) => {
|
|
22803
22827
|
let score = r.similarity;
|
|
22804
|
-
if (currentFile &&
|
|
22828
|
+
if (currentFile && dirname3(r.file) === dirname3(currentFile)) {
|
|
22805
22829
|
score *= 1.5;
|
|
22806
22830
|
}
|
|
22807
22831
|
const hoursSinceModified = (Date.now() - r.lastModified) / 36e5;
|
|
@@ -22903,7 +22927,7 @@ ${tags.join(" ")}`;
|
|
|
22903
22927
|
// src/core/decision-extractor.ts
|
|
22904
22928
|
import { execSync } from "child_process";
|
|
22905
22929
|
import { readFileSync as readFileSync3, existsSync as existsSync3 } from "fs";
|
|
22906
|
-
import { join as
|
|
22930
|
+
import { join as join3 } from "path";
|
|
22907
22931
|
import { glob as glob2 } from "glob";
|
|
22908
22932
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
22909
22933
|
var COMMIT_PATTERNS = [
|
|
@@ -22943,7 +22967,7 @@ var DecisionExtractor = class {
|
|
|
22943
22967
|
isGitRepo;
|
|
22944
22968
|
constructor(projectPath) {
|
|
22945
22969
|
this.projectPath = projectPath;
|
|
22946
|
-
this.isGitRepo = existsSync3(
|
|
22970
|
+
this.isGitRepo = existsSync3(join3(projectPath, ".git"));
|
|
22947
22971
|
}
|
|
22948
22972
|
async extractAll() {
|
|
22949
22973
|
const decisions = [];
|
|
@@ -23229,8 +23253,7 @@ var LearningEngine = class {
|
|
|
23229
23253
|
updateFileAccess(filePath) {
|
|
23230
23254
|
const fileStmt = this.db.prepare("SELECT id FROM files WHERE path = ?");
|
|
23231
23255
|
const file2 = fileStmt.get(filePath);
|
|
23232
|
-
if (!file2)
|
|
23233
|
-
return;
|
|
23256
|
+
if (!file2) return;
|
|
23234
23257
|
const stmt = this.db.prepare(`
|
|
23235
23258
|
INSERT INTO file_access (file_id, access_count, last_accessed, relevance_score)
|
|
23236
23259
|
VALUES (?, 1, unixepoch(), 0.5)
|
|
@@ -23246,16 +23269,14 @@ var LearningEngine = class {
|
|
|
23246
23269
|
getPersonalizedBoost(filePath) {
|
|
23247
23270
|
const fileStmt = this.db.prepare("SELECT id FROM files WHERE path = ?");
|
|
23248
23271
|
const file2 = fileStmt.get(filePath);
|
|
23249
|
-
if (!file2)
|
|
23250
|
-
return 1;
|
|
23272
|
+
if (!file2) return 1;
|
|
23251
23273
|
const stmt = this.db.prepare(`
|
|
23252
23274
|
SELECT access_count, last_accessed, relevance_score
|
|
23253
23275
|
FROM file_access
|
|
23254
23276
|
WHERE file_id = ?
|
|
23255
23277
|
`);
|
|
23256
23278
|
const stats = stmt.get(file2.id);
|
|
23257
|
-
if (!stats)
|
|
23258
|
-
return 1;
|
|
23279
|
+
if (!stats) return 1;
|
|
23259
23280
|
const frequencyBoost = 1 + Math.log10(1 + stats.accessCount) * 0.2;
|
|
23260
23281
|
const hoursSinceAccess = (Date.now() / 1e3 - stats.lastAccessed) / 3600;
|
|
23261
23282
|
const recencyBoost = Math.exp(-hoursSinceAccess / 168);
|
|
@@ -23594,53 +23615,31 @@ var FileSummarizer = class {
|
|
|
23594
23615
|
inferPurpose(fileName, content, symbols) {
|
|
23595
23616
|
const lowerName = fileName.toLowerCase();
|
|
23596
23617
|
const lowerContent = content.toLowerCase();
|
|
23597
|
-
if (lowerName.includes("middleware"))
|
|
23598
|
-
|
|
23599
|
-
if (lowerName.includes("
|
|
23600
|
-
|
|
23601
|
-
if (lowerName.includes("
|
|
23602
|
-
|
|
23603
|
-
if (lowerName.includes("
|
|
23604
|
-
|
|
23605
|
-
if (lowerName.includes("
|
|
23606
|
-
|
|
23607
|
-
if (lowerName.includes("
|
|
23608
|
-
|
|
23609
|
-
if (lowerName.includes("
|
|
23610
|
-
|
|
23611
|
-
if (lowerName.includes("
|
|
23612
|
-
|
|
23613
|
-
if (lowerName.includes("
|
|
23614
|
-
|
|
23615
|
-
if (
|
|
23616
|
-
|
|
23617
|
-
if (
|
|
23618
|
-
return "Tests";
|
|
23619
|
-
if (lowerName.includes("hook"))
|
|
23620
|
-
return "React hooks";
|
|
23621
|
-
if (lowerName.includes("context"))
|
|
23622
|
-
return "React context provider";
|
|
23623
|
-
if (lowerName.includes("store"))
|
|
23624
|
-
return "State management";
|
|
23625
|
-
if (lowerName.includes("api"))
|
|
23626
|
-
return "API client/definitions";
|
|
23627
|
-
if (lowerName.includes("auth"))
|
|
23628
|
-
return "Authentication";
|
|
23629
|
-
if (lowerName.includes("db") || lowerName.includes("database"))
|
|
23630
|
-
return "Database operations";
|
|
23631
|
-
if (lowerContent.includes("express") && lowerContent.includes("router"))
|
|
23632
|
-
return "Express router";
|
|
23633
|
-
if (lowerContent.includes("mongoose") || lowerContent.includes("prisma"))
|
|
23634
|
-
return "Database model";
|
|
23635
|
-
if (lowerContent.includes("usestate") || lowerContent.includes("useeffect"))
|
|
23636
|
-
return "React component";
|
|
23637
|
-
if (lowerContent.includes("describe(") && lowerContent.includes("it("))
|
|
23638
|
-
return "Test suite";
|
|
23618
|
+
if (lowerName.includes("middleware")) return "Request middleware/interceptor";
|
|
23619
|
+
if (lowerName.includes("route") || lowerName.includes("router")) return "API route definitions";
|
|
23620
|
+
if (lowerName.includes("controller")) return "Request handler/controller";
|
|
23621
|
+
if (lowerName.includes("service")) return "Business logic service";
|
|
23622
|
+
if (lowerName.includes("model")) return "Data model definitions";
|
|
23623
|
+
if (lowerName.includes("schema")) return "Schema/validation definitions";
|
|
23624
|
+
if (lowerName.includes("util") || lowerName.includes("helper")) return "Utility functions";
|
|
23625
|
+
if (lowerName.includes("config")) return "Configuration";
|
|
23626
|
+
if (lowerName.includes("constant")) return "Constants/enums";
|
|
23627
|
+
if (lowerName.includes("type") || lowerName.includes("interface")) return "Type definitions";
|
|
23628
|
+
if (lowerName.includes("test") || lowerName.includes("spec")) return "Tests";
|
|
23629
|
+
if (lowerName.includes("hook")) return "React hooks";
|
|
23630
|
+
if (lowerName.includes("context")) return "React context provider";
|
|
23631
|
+
if (lowerName.includes("store")) return "State management";
|
|
23632
|
+
if (lowerName.includes("api")) return "API client/definitions";
|
|
23633
|
+
if (lowerName.includes("auth")) return "Authentication";
|
|
23634
|
+
if (lowerName.includes("db") || lowerName.includes("database")) return "Database operations";
|
|
23635
|
+
if (lowerContent.includes("express") && lowerContent.includes("router")) return "Express router";
|
|
23636
|
+
if (lowerContent.includes("mongoose") || lowerContent.includes("prisma")) return "Database model";
|
|
23637
|
+
if (lowerContent.includes("usestate") || lowerContent.includes("useeffect")) return "React component";
|
|
23638
|
+
if (lowerContent.includes("describe(") && lowerContent.includes("it(")) return "Test suite";
|
|
23639
23639
|
const hasClasses = symbols.some((s) => s.kind === "class");
|
|
23640
23640
|
const hasInterfaces = symbols.some((s) => s.kind === "interface");
|
|
23641
23641
|
const hasFunctions = symbols.some((s) => s.kind === "function");
|
|
23642
|
-
if (hasInterfaces && !hasClasses && !hasFunctions)
|
|
23643
|
-
return "Type definitions";
|
|
23642
|
+
if (hasInterfaces && !hasClasses && !hasFunctions) return "Type definitions";
|
|
23644
23643
|
if (hasClasses && symbols.filter((s) => s.kind === "class").length === 1) {
|
|
23645
23644
|
const className = symbols.find((s) => s.kind === "class")?.name;
|
|
23646
23645
|
return `${className} implementation`;
|
|
@@ -23704,8 +23703,7 @@ var FileSummarizer = class {
|
|
|
23704
23703
|
// Get summaries for multiple files
|
|
23705
23704
|
getSummaries(fileIds) {
|
|
23706
23705
|
const result = /* @__PURE__ */ new Map();
|
|
23707
|
-
if (fileIds.length === 0)
|
|
23708
|
-
return result;
|
|
23706
|
+
if (fileIds.length === 0) return result;
|
|
23709
23707
|
const placeholders = fileIds.map(() => "?").join(",");
|
|
23710
23708
|
const stmt = this.db.prepare(`
|
|
23711
23709
|
SELECT file_id, summary
|
|
@@ -23721,8 +23719,7 @@ var FileSummarizer = class {
|
|
|
23721
23719
|
// Check if summary needs regeneration
|
|
23722
23720
|
needsRegeneration(fileId, fileLastModified) {
|
|
23723
23721
|
const summary = this.getSummary(fileId);
|
|
23724
|
-
if (!summary)
|
|
23725
|
-
return true;
|
|
23722
|
+
if (!summary) return true;
|
|
23726
23723
|
return fileLastModified > summary.generatedAt;
|
|
23727
23724
|
}
|
|
23728
23725
|
// Get compression ratio stats
|
|
@@ -23746,7 +23743,7 @@ var FileSummarizer = class {
|
|
|
23746
23743
|
|
|
23747
23744
|
// src/core/project-manager.ts
|
|
23748
23745
|
import { existsSync as existsSync4, mkdirSync as mkdirSync3, readFileSync as readFileSync4, writeFileSync as writeFileSync2, readdirSync } from "fs";
|
|
23749
|
-
import { join as
|
|
23746
|
+
import { join as join4, basename as basename2, resolve } from "path";
|
|
23750
23747
|
import { createHash as createHash3 } from "crypto";
|
|
23751
23748
|
import { homedir } from "os";
|
|
23752
23749
|
import Database2 from "better-sqlite3";
|
|
@@ -23755,8 +23752,8 @@ var ProjectManager = class {
|
|
|
23755
23752
|
registry;
|
|
23756
23753
|
baseDataDir;
|
|
23757
23754
|
constructor() {
|
|
23758
|
-
this.baseDataDir =
|
|
23759
|
-
this.registryPath =
|
|
23755
|
+
this.baseDataDir = join4(homedir(), ".neuronlayer");
|
|
23756
|
+
this.registryPath = join4(this.baseDataDir, "registry.json");
|
|
23760
23757
|
if (!existsSync4(this.baseDataDir)) {
|
|
23761
23758
|
mkdirSync3(this.baseDataDir, { recursive: true });
|
|
23762
23759
|
}
|
|
@@ -23791,7 +23788,7 @@ var ProjectManager = class {
|
|
|
23791
23788
|
getProjectDataDir(projectPath) {
|
|
23792
23789
|
const projectId = this.generateProjectId(projectPath);
|
|
23793
23790
|
const projectName = basename2(projectPath);
|
|
23794
|
-
return
|
|
23791
|
+
return join4(this.baseDataDir, "projects", `${projectName}-${projectId}`);
|
|
23795
23792
|
}
|
|
23796
23793
|
// Register a new project or update existing
|
|
23797
23794
|
registerProject(projectPath) {
|
|
@@ -23861,8 +23858,7 @@ var ProjectManager = class {
|
|
|
23861
23858
|
// Update project stats
|
|
23862
23859
|
updateProjectStats(projectId, stats) {
|
|
23863
23860
|
const project = this.registry.projects[projectId];
|
|
23864
|
-
if (!project)
|
|
23865
|
-
return;
|
|
23861
|
+
if (!project) return;
|
|
23866
23862
|
if (stats.totalFiles !== void 0) {
|
|
23867
23863
|
project.totalFiles = stats.totalFiles;
|
|
23868
23864
|
}
|
|
@@ -23906,27 +23902,25 @@ var ProjectManager = class {
|
|
|
23906
23902
|
const discovered = [];
|
|
23907
23903
|
const homeDir = homedir();
|
|
23908
23904
|
const searchDirs = [
|
|
23909
|
-
|
|
23910
|
-
|
|
23911
|
-
|
|
23912
|
-
|
|
23913
|
-
|
|
23914
|
-
|
|
23915
|
-
|
|
23916
|
-
|
|
23917
|
-
|
|
23918
|
-
|
|
23919
|
-
|
|
23905
|
+
join4(homeDir, "projects"),
|
|
23906
|
+
join4(homeDir, "Projects"),
|
|
23907
|
+
join4(homeDir, "code"),
|
|
23908
|
+
join4(homeDir, "Code"),
|
|
23909
|
+
join4(homeDir, "dev"),
|
|
23910
|
+
join4(homeDir, "Development"),
|
|
23911
|
+
join4(homeDir, "workspace"),
|
|
23912
|
+
join4(homeDir, "repos"),
|
|
23913
|
+
join4(homeDir, "github"),
|
|
23914
|
+
join4(homeDir, "Desktop"),
|
|
23915
|
+
join4(homeDir, "Documents")
|
|
23920
23916
|
];
|
|
23921
23917
|
for (const searchDir of searchDirs) {
|
|
23922
|
-
if (!existsSync4(searchDir))
|
|
23923
|
-
continue;
|
|
23918
|
+
if (!existsSync4(searchDir)) continue;
|
|
23924
23919
|
try {
|
|
23925
23920
|
const entries = readdirSync(searchDir, { withFileTypes: true });
|
|
23926
23921
|
for (const entry of entries) {
|
|
23927
|
-
if (!entry.isDirectory())
|
|
23928
|
-
|
|
23929
|
-
const projectPath = join5(searchDir, entry.name);
|
|
23922
|
+
if (!entry.isDirectory()) continue;
|
|
23923
|
+
const projectPath = join4(searchDir, entry.name);
|
|
23930
23924
|
const projectIndicators = [
|
|
23931
23925
|
"package.json",
|
|
23932
23926
|
"Cargo.toml",
|
|
@@ -23938,7 +23932,7 @@ var ProjectManager = class {
|
|
|
23938
23932
|
".git"
|
|
23939
23933
|
];
|
|
23940
23934
|
const isProject = projectIndicators.some(
|
|
23941
|
-
(indicator) => existsSync4(
|
|
23935
|
+
(indicator) => existsSync4(join4(projectPath, indicator))
|
|
23942
23936
|
);
|
|
23943
23937
|
if (isProject) {
|
|
23944
23938
|
discovered.push(projectPath);
|
|
@@ -23953,7 +23947,7 @@ var ProjectManager = class {
|
|
|
23953
23947
|
getProjectDatabases() {
|
|
23954
23948
|
const result = [];
|
|
23955
23949
|
for (const project of this.listProjects()) {
|
|
23956
|
-
const dbPath =
|
|
23950
|
+
const dbPath = join4(project.dataDir, "neuronlayer.db");
|
|
23957
23951
|
if (existsSync4(dbPath)) {
|
|
23958
23952
|
try {
|
|
23959
23953
|
const db = new Database2(dbPath, { readonly: true });
|
|
@@ -23977,7 +23971,7 @@ var ProjectManager = class {
|
|
|
23977
23971
|
|
|
23978
23972
|
// src/core/adr-exporter.ts
|
|
23979
23973
|
import { existsSync as existsSync5, mkdirSync as mkdirSync4, writeFileSync as writeFileSync3 } from "fs";
|
|
23980
|
-
import { join as
|
|
23974
|
+
import { join as join5 } from "path";
|
|
23981
23975
|
var ADRExporter = class {
|
|
23982
23976
|
projectPath;
|
|
23983
23977
|
constructor(projectPath) {
|
|
@@ -23985,7 +23979,7 @@ var ADRExporter = class {
|
|
|
23985
23979
|
}
|
|
23986
23980
|
// Export a single decision to ADR file
|
|
23987
23981
|
exportDecision(decision, options = {}) {
|
|
23988
|
-
const outputDir = options.outputDir ||
|
|
23982
|
+
const outputDir = options.outputDir || join5(this.projectPath, "docs", "decisions");
|
|
23989
23983
|
const format = options.format || "madr";
|
|
23990
23984
|
if (!existsSync5(outputDir)) {
|
|
23991
23985
|
mkdirSync4(outputDir, { recursive: true });
|
|
@@ -23994,7 +23988,7 @@ var ADRExporter = class {
|
|
|
23994
23988
|
const nextNumber = this.getNextADRNumber(existingFiles);
|
|
23995
23989
|
const slug = this.slugify(decision.title);
|
|
23996
23990
|
const filename = `${String(nextNumber).padStart(4, "0")}-${slug}.md`;
|
|
23997
|
-
const filePath =
|
|
23991
|
+
const filePath = join5(outputDir, filename);
|
|
23998
23992
|
let content;
|
|
23999
23993
|
switch (format) {
|
|
24000
23994
|
case "madr":
|
|
@@ -24014,7 +24008,7 @@ var ADRExporter = class {
|
|
|
24014
24008
|
// Export all decisions
|
|
24015
24009
|
exportAllDecisions(decisions, options = {}) {
|
|
24016
24010
|
const exportedFiles = [];
|
|
24017
|
-
const outputDir = options.outputDir ||
|
|
24011
|
+
const outputDir = options.outputDir || join5(this.projectPath, "docs", "decisions");
|
|
24018
24012
|
const sorted = [...decisions].sort(
|
|
24019
24013
|
(a, b) => a.createdAt.getTime() - b.createdAt.getTime()
|
|
24020
24014
|
);
|
|
@@ -24030,7 +24024,7 @@ var ADRExporter = class {
|
|
|
24030
24024
|
}
|
|
24031
24025
|
// Generate index file
|
|
24032
24026
|
generateIndex(decisions, outputDir) {
|
|
24033
|
-
const indexPath =
|
|
24027
|
+
const indexPath = join5(outputDir, "README.md");
|
|
24034
24028
|
const lines = [
|
|
24035
24029
|
"# Architecture Decision Records",
|
|
24036
24030
|
"",
|
|
@@ -24054,7 +24048,7 @@ var ADRExporter = class {
|
|
|
24054
24048
|
lines.push("");
|
|
24055
24049
|
lines.push("---");
|
|
24056
24050
|
lines.push("");
|
|
24057
|
-
lines.push("*Generated by
|
|
24051
|
+
lines.push("*Generated by NeuronLayer*");
|
|
24058
24052
|
writeFileSync3(indexPath, lines.join("\n"));
|
|
24059
24053
|
return indexPath;
|
|
24060
24054
|
}
|
|
@@ -24101,7 +24095,7 @@ ${decision.supersededBy ? `## Superseded By
|
|
|
24101
24095
|
This decision has been superseded by [ADR ${decision.supersededBy}](./${decision.supersededBy}.md).
|
|
24102
24096
|
` : ""}
|
|
24103
24097
|
---
|
|
24104
|
-
*Exported from
|
|
24098
|
+
*Exported from NeuronLayer*
|
|
24105
24099
|
`;
|
|
24106
24100
|
}
|
|
24107
24101
|
// Nygard format (original ADR format)
|
|
@@ -24135,7 +24129,7 @@ ${decision.files.length > 0 ? `## Related Files
|
|
|
24135
24129
|
${decision.files.map((f) => `- ${f}`).join("\n")}
|
|
24136
24130
|
` : ""}
|
|
24137
24131
|
---
|
|
24138
|
-
*Exported from
|
|
24132
|
+
*Exported from NeuronLayer*
|
|
24139
24133
|
`;
|
|
24140
24134
|
}
|
|
24141
24135
|
// Simple format
|
|
@@ -24157,12 +24151,11 @@ ${decision.files.length > 0 ? `## Related Files
|
|
|
24157
24151
|
${decision.files.map((f) => `- \`${f}\``).join("\n")}
|
|
24158
24152
|
` : ""}
|
|
24159
24153
|
---
|
|
24160
|
-
*Exported from
|
|
24154
|
+
*Exported from NeuronLayer*
|
|
24161
24155
|
`;
|
|
24162
24156
|
}
|
|
24163
24157
|
getExistingADRFiles(dir) {
|
|
24164
|
-
if (!existsSync5(dir))
|
|
24165
|
-
return [];
|
|
24158
|
+
if (!existsSync5(dir)) return [];
|
|
24166
24159
|
try {
|
|
24167
24160
|
const { readdirSync: readdirSync4 } = __require("fs");
|
|
24168
24161
|
return readdirSync4(dir).filter((f) => /^\d{4}-.*\.md$/.test(f)).sort();
|
|
@@ -24171,8 +24164,7 @@ ${decision.files.map((f) => `- \`${f}\``).join("\n")}
|
|
|
24171
24164
|
}
|
|
24172
24165
|
}
|
|
24173
24166
|
getNextADRNumber(existingFiles) {
|
|
24174
|
-
if (existingFiles.length === 0)
|
|
24175
|
-
return 1;
|
|
24167
|
+
if (existingFiles.length === 0) return 1;
|
|
24176
24168
|
const numbers = existingFiles.map((f) => parseInt(f.split("-")[0] || "0", 10)).filter((n) => !isNaN(n));
|
|
24177
24169
|
return Math.max(...numbers, 0) + 1;
|
|
24178
24170
|
}
|
|
@@ -24184,7 +24176,7 @@ ${decision.files.map((f) => `- \`${f}\``).join("\n")}
|
|
|
24184
24176
|
// src/core/feature-context.ts
|
|
24185
24177
|
import { EventEmitter as EventEmitter3 } from "events";
|
|
24186
24178
|
import { readFileSync as readFileSync6, writeFileSync as writeFileSync4, existsSync as existsSync6, mkdirSync as mkdirSync5 } from "fs";
|
|
24187
|
-
import { dirname as
|
|
24179
|
+
import { dirname as dirname4, join as join6, basename as basename3 } from "path";
|
|
24188
24180
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
24189
24181
|
var MAX_FILES = 20;
|
|
24190
24182
|
var MAX_CHANGES = 50;
|
|
@@ -24204,7 +24196,7 @@ var FeatureContextManager = class extends EventEmitter3 {
|
|
|
24204
24196
|
super();
|
|
24205
24197
|
this.projectPath = projectPath;
|
|
24206
24198
|
this.dataDir = dataDir;
|
|
24207
|
-
this.persistPath =
|
|
24199
|
+
this.persistPath = join6(dataDir, "feature-context.json");
|
|
24208
24200
|
this.load();
|
|
24209
24201
|
this.startInactivityTimer();
|
|
24210
24202
|
}
|
|
@@ -24220,8 +24212,7 @@ var FeatureContextManager = class extends EventEmitter3 {
|
|
|
24220
24212
|
this.recordChange(filePath, diff, linesChanged);
|
|
24221
24213
|
}
|
|
24222
24214
|
touchFile(filePath) {
|
|
24223
|
-
if (!this.current)
|
|
24224
|
-
return;
|
|
24215
|
+
if (!this.current) return;
|
|
24225
24216
|
const relativePath = this.toRelativePath(filePath);
|
|
24226
24217
|
const existing = this.current.files.find((f) => f.path === relativePath);
|
|
24227
24218
|
if (existing) {
|
|
@@ -24243,8 +24234,7 @@ var FeatureContextManager = class extends EventEmitter3 {
|
|
|
24243
24234
|
}
|
|
24244
24235
|
// ========== CHANGE TRACKING ==========
|
|
24245
24236
|
recordChange(filePath, diff, linesChanged) {
|
|
24246
|
-
if (!this.current)
|
|
24247
|
-
return;
|
|
24237
|
+
if (!this.current) return;
|
|
24248
24238
|
const relativePath = this.toRelativePath(filePath);
|
|
24249
24239
|
this.current.changes.unshift({
|
|
24250
24240
|
file: relativePath,
|
|
@@ -24265,8 +24255,7 @@ var FeatureContextManager = class extends EventEmitter3 {
|
|
|
24265
24255
|
// ========== QUERY TRACKING ==========
|
|
24266
24256
|
onQuery(query, filesUsed) {
|
|
24267
24257
|
this.ensureContext();
|
|
24268
|
-
if (!this.current)
|
|
24269
|
-
return;
|
|
24258
|
+
if (!this.current) return;
|
|
24270
24259
|
const relativeFiles = filesUsed.map((f) => this.toRelativePath(f));
|
|
24271
24260
|
this.current.queries.unshift({
|
|
24272
24261
|
query,
|
|
@@ -24283,8 +24272,7 @@ var FeatureContextManager = class extends EventEmitter3 {
|
|
|
24283
24272
|
// ========== HOT CACHE ==========
|
|
24284
24273
|
async preloadFile(filePath) {
|
|
24285
24274
|
const relativePath = this.toRelativePath(filePath);
|
|
24286
|
-
if (this.fileContents.has(relativePath))
|
|
24287
|
-
return;
|
|
24275
|
+
if (this.fileContents.has(relativePath)) return;
|
|
24288
24276
|
try {
|
|
24289
24277
|
const absolutePath = this.toAbsolutePath(relativePath);
|
|
24290
24278
|
const content = readFileSync6(absolutePath, "utf-8");
|
|
@@ -24327,8 +24315,7 @@ var FeatureContextManager = class extends EventEmitter3 {
|
|
|
24327
24315
|
};
|
|
24328
24316
|
}
|
|
24329
24317
|
generateSummary() {
|
|
24330
|
-
if (!this.current)
|
|
24331
|
-
return "";
|
|
24318
|
+
if (!this.current) return "";
|
|
24332
24319
|
const topFiles = this.current.files.sort((a, b) => b.touchCount - a.touchCount).slice(0, 5).map((f) => basename3(f.path)).join(", ");
|
|
24333
24320
|
const recentChanges = this.current.changes.length;
|
|
24334
24321
|
const durationMs = Date.now() - this.current.startedAt.getTime();
|
|
@@ -24345,8 +24332,7 @@ var FeatureContextManager = class extends EventEmitter3 {
|
|
|
24345
24332
|
return this.recent;
|
|
24346
24333
|
}
|
|
24347
24334
|
getCurrentSummary() {
|
|
24348
|
-
if (!this.current)
|
|
24349
|
-
return null;
|
|
24335
|
+
if (!this.current) return null;
|
|
24350
24336
|
return {
|
|
24351
24337
|
name: this.current.name,
|
|
24352
24338
|
files: this.current.files.length,
|
|
@@ -24382,16 +24368,14 @@ var FeatureContextManager = class extends EventEmitter3 {
|
|
|
24382
24368
|
return this.current;
|
|
24383
24369
|
}
|
|
24384
24370
|
setContextName(name) {
|
|
24385
|
-
if (!this.current)
|
|
24386
|
-
return false;
|
|
24371
|
+
if (!this.current) return false;
|
|
24387
24372
|
this.current.name = name;
|
|
24388
24373
|
this.save();
|
|
24389
24374
|
return true;
|
|
24390
24375
|
}
|
|
24391
24376
|
switchToRecent(contextId) {
|
|
24392
24377
|
const found = this.recent.find((c) => c.id === contextId);
|
|
24393
|
-
if (!found)
|
|
24394
|
-
return false;
|
|
24378
|
+
if (!found) return false;
|
|
24395
24379
|
if (this.current) {
|
|
24396
24380
|
this.current.status = "paused";
|
|
24397
24381
|
this.recent.unshift(this.current);
|
|
@@ -24407,16 +24391,14 @@ var FeatureContextManager = class extends EventEmitter3 {
|
|
|
24407
24391
|
}
|
|
24408
24392
|
reloadFiles() {
|
|
24409
24393
|
this.fileContents.clear();
|
|
24410
|
-
if (!this.current)
|
|
24411
|
-
return;
|
|
24394
|
+
if (!this.current) return;
|
|
24412
24395
|
const topFiles = this.current.files.sort((a, b) => b.touchCount - a.touchCount).slice(0, 10);
|
|
24413
24396
|
for (const file2 of topFiles) {
|
|
24414
24397
|
this.preloadFile(file2.path);
|
|
24415
24398
|
}
|
|
24416
24399
|
}
|
|
24417
24400
|
completeContext() {
|
|
24418
|
-
if (!this.current)
|
|
24419
|
-
return false;
|
|
24401
|
+
if (!this.current) return false;
|
|
24420
24402
|
this.current.status = "completed";
|
|
24421
24403
|
this.recent.unshift(this.current);
|
|
24422
24404
|
this.recent = this.recent.slice(0, MAX_RECENT_CONTEXTS);
|
|
@@ -24431,8 +24413,7 @@ var FeatureContextManager = class extends EventEmitter3 {
|
|
|
24431
24413
|
clearInterval(this.inactivityTimer);
|
|
24432
24414
|
}
|
|
24433
24415
|
this.inactivityTimer = setInterval(() => {
|
|
24434
|
-
if (!this.current)
|
|
24435
|
-
return;
|
|
24416
|
+
if (!this.current) return;
|
|
24436
24417
|
const inactiveMs = Date.now() - this.current.lastActiveAt.getTime();
|
|
24437
24418
|
if (inactiveMs > TTL_MINUTES * 60 * 1e3) {
|
|
24438
24419
|
this.current.status = "paused";
|
|
@@ -24444,7 +24425,7 @@ var FeatureContextManager = class extends EventEmitter3 {
|
|
|
24444
24425
|
// ========== PERSISTENCE ==========
|
|
24445
24426
|
save() {
|
|
24446
24427
|
try {
|
|
24447
|
-
const dir =
|
|
24428
|
+
const dir = dirname4(this.persistPath);
|
|
24448
24429
|
if (!existsSync6(dir)) {
|
|
24449
24430
|
mkdirSync5(dir, { recursive: true });
|
|
24450
24431
|
}
|
|
@@ -24507,7 +24488,7 @@ var FeatureContextManager = class extends EventEmitter3 {
|
|
|
24507
24488
|
if (relativePath.startsWith(this.projectPath)) {
|
|
24508
24489
|
return relativePath;
|
|
24509
24490
|
}
|
|
24510
|
-
return
|
|
24491
|
+
return join6(this.projectPath, relativePath);
|
|
24511
24492
|
}
|
|
24512
24493
|
// ========== CONTEXT RESURRECTION ==========
|
|
24513
24494
|
/**
|
|
@@ -24584,8 +24565,7 @@ var FeatureContextManager = class extends EventEmitter3 {
|
|
|
24584
24565
|
];
|
|
24585
24566
|
for (let i = 0; i < Math.min(3, context.queries.length); i++) {
|
|
24586
24567
|
const query = context.queries[i];
|
|
24587
|
-
if (!query)
|
|
24588
|
-
continue;
|
|
24568
|
+
if (!query) continue;
|
|
24589
24569
|
for (const pattern of errorPatterns) {
|
|
24590
24570
|
if (pattern.test(query.query)) {
|
|
24591
24571
|
return query.query;
|
|
@@ -24707,7 +24687,7 @@ var FeatureContextManager = class extends EventEmitter3 {
|
|
|
24707
24687
|
|
|
24708
24688
|
// src/core/living-docs/architecture-generator.ts
|
|
24709
24689
|
import { existsSync as existsSync7, readFileSync as readFileSync7, readdirSync as readdirSync2 } from "fs";
|
|
24710
|
-
import { basename as basename4, join as
|
|
24690
|
+
import { basename as basename4, join as join7 } from "path";
|
|
24711
24691
|
var ArchitectureGenerator = class _ArchitectureGenerator {
|
|
24712
24692
|
projectPath;
|
|
24713
24693
|
tier2;
|
|
@@ -24785,16 +24765,15 @@ var ArchitectureGenerator = class _ArchitectureGenerator {
|
|
|
24785
24765
|
detectLayers() {
|
|
24786
24766
|
const layers = [];
|
|
24787
24767
|
const layerMap = /* @__PURE__ */ new Map();
|
|
24788
|
-
const srcDir = existsSync7(
|
|
24768
|
+
const srcDir = existsSync7(join7(this.projectPath, "src")) ? join7(this.projectPath, "src") : this.projectPath;
|
|
24789
24769
|
try {
|
|
24790
24770
|
const entries = readdirSync2(srcDir, { withFileTypes: true });
|
|
24791
24771
|
for (const entry of entries) {
|
|
24792
|
-
if (!entry.isDirectory())
|
|
24793
|
-
continue;
|
|
24772
|
+
if (!entry.isDirectory()) continue;
|
|
24794
24773
|
const dirName = entry.name.toLowerCase();
|
|
24795
24774
|
const layerName = _ArchitectureGenerator.LAYER_MAPPING[dirName];
|
|
24796
24775
|
if (layerName) {
|
|
24797
|
-
const dirPath =
|
|
24776
|
+
const dirPath = join7(srcDir, entry.name);
|
|
24798
24777
|
const relativePath = dirPath.replace(this.projectPath, "").replace(/^[/\\]/, "");
|
|
24799
24778
|
const files = this.getFilesInDirectory(relativePath);
|
|
24800
24779
|
if (files.length > 0) {
|
|
@@ -24837,12 +24816,12 @@ var ArchitectureGenerator = class _ArchitectureGenerator {
|
|
|
24837
24816
|
}
|
|
24838
24817
|
getFilesInDirectory(relativePath) {
|
|
24839
24818
|
const files = [];
|
|
24840
|
-
const absolutePath =
|
|
24819
|
+
const absolutePath = join7(this.projectPath, relativePath);
|
|
24841
24820
|
try {
|
|
24842
24821
|
const entries = readdirSync2(absolutePath, { withFileTypes: true });
|
|
24843
24822
|
for (const entry of entries) {
|
|
24844
24823
|
if (entry.isFile() && this.isCodeFile(entry.name)) {
|
|
24845
|
-
files.push(
|
|
24824
|
+
files.push(join7(relativePath, entry.name));
|
|
24846
24825
|
}
|
|
24847
24826
|
}
|
|
24848
24827
|
} catch {
|
|
@@ -24858,8 +24837,7 @@ var ArchitectureGenerator = class _ArchitectureGenerator {
|
|
|
24858
24837
|
for (const layer of layers) {
|
|
24859
24838
|
for (const filePath of layer.files.slice(0, 5)) {
|
|
24860
24839
|
const file2 = this.tier2.getFile(filePath);
|
|
24861
|
-
if (!file2)
|
|
24862
|
-
continue;
|
|
24840
|
+
if (!file2) continue;
|
|
24863
24841
|
const symbols = this.tier2.getSymbolsByFile(file2.id);
|
|
24864
24842
|
const exports = symbols.filter((s) => s.exported);
|
|
24865
24843
|
if (exports.length > 0) {
|
|
@@ -24878,18 +24856,12 @@ var ArchitectureGenerator = class _ArchitectureGenerator {
|
|
|
24878
24856
|
inferComponentPurpose(filePath, symbols) {
|
|
24879
24857
|
const name = basename4(filePath, ".ts").toLowerCase();
|
|
24880
24858
|
const mainExport = symbols.find((s) => s.kind === "class" || s.kind === "function");
|
|
24881
|
-
if (name.includes("engine"))
|
|
24882
|
-
|
|
24883
|
-
if (name.includes("
|
|
24884
|
-
|
|
24885
|
-
if (name.includes("
|
|
24886
|
-
|
|
24887
|
-
if (name.includes("indexer"))
|
|
24888
|
-
return "Content indexing";
|
|
24889
|
-
if (name.includes("context"))
|
|
24890
|
-
return "Context management";
|
|
24891
|
-
if (name.includes("config"))
|
|
24892
|
-
return "Configuration handling";
|
|
24859
|
+
if (name.includes("engine")) return "Main orchestration engine";
|
|
24860
|
+
if (name.includes("server")) return "Server implementation";
|
|
24861
|
+
if (name.includes("storage")) return "Data storage management";
|
|
24862
|
+
if (name.includes("indexer")) return "Content indexing";
|
|
24863
|
+
if (name.includes("context")) return "Context management";
|
|
24864
|
+
if (name.includes("config")) return "Configuration handling";
|
|
24893
24865
|
if (mainExport) {
|
|
24894
24866
|
return `Provides ${mainExport.name}`;
|
|
24895
24867
|
}
|
|
@@ -24978,7 +24950,7 @@ var ArchitectureGenerator = class _ArchitectureGenerator {
|
|
|
24978
24950
|
}
|
|
24979
24951
|
getProjectDependencies() {
|
|
24980
24952
|
const deps = [];
|
|
24981
|
-
const packageJsonPath =
|
|
24953
|
+
const packageJsonPath = join7(this.projectPath, "package.json");
|
|
24982
24954
|
if (existsSync7(packageJsonPath)) {
|
|
24983
24955
|
try {
|
|
24984
24956
|
const pkg = JSON.parse(readFileSync7(packageJsonPath, "utf-8"));
|
|
@@ -25006,7 +24978,7 @@ var ArchitectureGenerator = class _ArchitectureGenerator {
|
|
|
25006
24978
|
} catch {
|
|
25007
24979
|
}
|
|
25008
24980
|
}
|
|
25009
|
-
const requirementsPath =
|
|
24981
|
+
const requirementsPath = join7(this.projectPath, "requirements.txt");
|
|
25010
24982
|
if (existsSync7(requirementsPath)) {
|
|
25011
24983
|
try {
|
|
25012
24984
|
const content = readFileSync7(requirementsPath, "utf-8");
|
|
@@ -25051,7 +25023,7 @@ var ArchitectureGenerator = class _ArchitectureGenerator {
|
|
|
25051
25023
|
// src/core/living-docs/component-generator.ts
|
|
25052
25024
|
import { execSync as execSync2 } from "child_process";
|
|
25053
25025
|
import { existsSync as existsSync8 } from "fs";
|
|
25054
|
-
import { basename as basename5, extname as extname2, join as
|
|
25026
|
+
import { basename as basename5, extname as extname2, join as join8 } from "path";
|
|
25055
25027
|
var ComponentGenerator = class {
|
|
25056
25028
|
projectPath;
|
|
25057
25029
|
tier2;
|
|
@@ -25059,7 +25031,7 @@ var ComponentGenerator = class {
|
|
|
25059
25031
|
constructor(projectPath, tier2) {
|
|
25060
25032
|
this.projectPath = projectPath;
|
|
25061
25033
|
this.tier2 = tier2;
|
|
25062
|
-
this.isGitRepo = existsSync8(
|
|
25034
|
+
this.isGitRepo = existsSync8(join8(projectPath, ".git"));
|
|
25063
25035
|
}
|
|
25064
25036
|
async generate(filePath) {
|
|
25065
25037
|
const file2 = this.tier2.getFile(filePath);
|
|
@@ -25165,8 +25137,7 @@ var ComponentGenerator = class {
|
|
|
25165
25137
|
const lines = output.trim().split("\n").filter(Boolean);
|
|
25166
25138
|
for (const line of lines) {
|
|
25167
25139
|
const [hash2, subject, author, dateStr] = line.split("|");
|
|
25168
|
-
if (!hash2 || !subject)
|
|
25169
|
-
continue;
|
|
25140
|
+
if (!hash2 || !subject) continue;
|
|
25170
25141
|
const { added, removed } = this.getCommitLineChanges(hash2, filePath);
|
|
25171
25142
|
history.push({
|
|
25172
25143
|
date: new Date(dateStr || Date.now()),
|
|
@@ -25229,7 +25200,7 @@ var ComponentGenerator = class {
|
|
|
25229
25200
|
// src/core/living-docs/changelog-generator.ts
|
|
25230
25201
|
import { execSync as execSync3 } from "child_process";
|
|
25231
25202
|
import { existsSync as existsSync9 } from "fs";
|
|
25232
|
-
import { join as
|
|
25203
|
+
import { join as join9 } from "path";
|
|
25233
25204
|
var ChangelogGenerator = class {
|
|
25234
25205
|
projectPath;
|
|
25235
25206
|
db;
|
|
@@ -25237,7 +25208,7 @@ var ChangelogGenerator = class {
|
|
|
25237
25208
|
constructor(projectPath, db) {
|
|
25238
25209
|
this.projectPath = projectPath;
|
|
25239
25210
|
this.db = db;
|
|
25240
|
-
this.isGitRepo = existsSync9(
|
|
25211
|
+
this.isGitRepo = existsSync9(join9(projectPath, ".git"));
|
|
25241
25212
|
}
|
|
25242
25213
|
async generate(options = {}) {
|
|
25243
25214
|
if (!this.isGitRepo) {
|
|
@@ -25298,8 +25269,7 @@ var ChangelogGenerator = class {
|
|
|
25298
25269
|
const lines = output.trim().split("\n").filter(Boolean);
|
|
25299
25270
|
for (const line of lines) {
|
|
25300
25271
|
const [hash2, subject, author, dateStr] = line.split("|");
|
|
25301
|
-
if (!hash2 || !subject)
|
|
25302
|
-
continue;
|
|
25272
|
+
if (!hash2 || !subject) continue;
|
|
25303
25273
|
const { files, additions, deletions } = this.getCommitStats(hash2);
|
|
25304
25274
|
commits.push({
|
|
25305
25275
|
hash: hash2.slice(0, 8),
|
|
@@ -25332,10 +25302,8 @@ var ChangelogGenerator = class {
|
|
|
25332
25302
|
}
|
|
25333
25303
|
const insertMatch = line.match(/(\d+)\s+insertion/);
|
|
25334
25304
|
const deleteMatch = line.match(/(\d+)\s+deletion/);
|
|
25335
|
-
if (insertMatch)
|
|
25336
|
-
|
|
25337
|
-
if (deleteMatch)
|
|
25338
|
-
deletions = parseInt(deleteMatch[1], 10);
|
|
25305
|
+
if (insertMatch) additions = parseInt(insertMatch[1], 10);
|
|
25306
|
+
if (deleteMatch) deletions = parseInt(deleteMatch[1], 10);
|
|
25339
25307
|
}
|
|
25340
25308
|
return { files, additions, deletions };
|
|
25341
25309
|
} catch {
|
|
@@ -25605,10 +25573,8 @@ var DocValidator = class {
|
|
|
25605
25573
|
if (filePath.includes("index.") || filePath.includes("/src/")) {
|
|
25606
25574
|
return "high";
|
|
25607
25575
|
}
|
|
25608
|
-
if (dependents.length >= 5)
|
|
25609
|
-
|
|
25610
|
-
if (dependents.length >= 2)
|
|
25611
|
-
return "medium";
|
|
25576
|
+
if (dependents.length >= 5) return "high";
|
|
25577
|
+
if (dependents.length >= 2) return "medium";
|
|
25612
25578
|
return "low";
|
|
25613
25579
|
}
|
|
25614
25580
|
mapSymbolKindToType(kind) {
|
|
@@ -25666,20 +25632,15 @@ var DocValidator = class {
|
|
|
25666
25632
|
formatTimeDiff(later, earlier) {
|
|
25667
25633
|
const diffMs = later.getTime() - earlier.getTime();
|
|
25668
25634
|
const diffDays = Math.floor(diffMs / (24 * 60 * 60 * 1e3));
|
|
25669
|
-
if (diffDays === 0)
|
|
25670
|
-
|
|
25671
|
-
if (diffDays
|
|
25672
|
-
|
|
25673
|
-
if (diffDays < 7)
|
|
25674
|
-
return `${diffDays} days`;
|
|
25675
|
-
if (diffDays < 30)
|
|
25676
|
-
return `${Math.floor(diffDays / 7)} weeks`;
|
|
25635
|
+
if (diffDays === 0) return "today";
|
|
25636
|
+
if (diffDays === 1) return "1 day";
|
|
25637
|
+
if (diffDays < 7) return `${diffDays} days`;
|
|
25638
|
+
if (diffDays < 30) return `${Math.floor(diffDays / 7)} weeks`;
|
|
25677
25639
|
return `${Math.floor(diffDays / 30)} months`;
|
|
25678
25640
|
}
|
|
25679
25641
|
calculateScore(outdated, undocumented) {
|
|
25680
25642
|
const totalFiles = this.tier2.getFileCount();
|
|
25681
|
-
if (totalFiles === 0)
|
|
25682
|
-
return 100;
|
|
25643
|
+
if (totalFiles === 0) return 100;
|
|
25683
25644
|
const outdatedPenalty = outdated.length / totalFiles * 30;
|
|
25684
25645
|
const highUndoc = undocumented.filter((u) => u.importance === "high").length;
|
|
25685
25646
|
const mediumUndoc = undocumented.filter((u) => u.importance === "medium").length;
|
|
@@ -25694,7 +25655,7 @@ var DocValidator = class {
|
|
|
25694
25655
|
// src/core/living-docs/activity-tracker.ts
|
|
25695
25656
|
import { execSync as execSync4 } from "child_process";
|
|
25696
25657
|
import { existsSync as existsSync10 } from "fs";
|
|
25697
|
-
import { join as
|
|
25658
|
+
import { join as join10 } from "path";
|
|
25698
25659
|
var ActivityTracker = class {
|
|
25699
25660
|
projectPath;
|
|
25700
25661
|
db;
|
|
@@ -25704,7 +25665,7 @@ var ActivityTracker = class {
|
|
|
25704
25665
|
this.projectPath = projectPath;
|
|
25705
25666
|
this.db = db;
|
|
25706
25667
|
this.tier2 = tier2;
|
|
25707
|
-
this.isGitRepo = existsSync10(
|
|
25668
|
+
this.isGitRepo = existsSync10(join10(projectPath, ".git"));
|
|
25708
25669
|
}
|
|
25709
25670
|
async whatHappened(since, scope) {
|
|
25710
25671
|
const sinceDate = this.parseSinceString(since);
|
|
@@ -25795,8 +25756,7 @@ var ActivityTracker = class {
|
|
|
25795
25756
|
const lines = output.trim().split("\n").filter(Boolean);
|
|
25796
25757
|
for (const line of lines) {
|
|
25797
25758
|
const [hash2, subject, author, dateStr] = line.split("|");
|
|
25798
|
-
if (!hash2 || !subject)
|
|
25799
|
-
continue;
|
|
25759
|
+
if (!hash2 || !subject) continue;
|
|
25800
25760
|
const files = this.getCommitFiles(hash2);
|
|
25801
25761
|
changes.push({
|
|
25802
25762
|
timestamp: new Date(dateStr || Date.now()),
|
|
@@ -26023,8 +25983,7 @@ var ContextHealthMonitor = class {
|
|
|
26023
25983
|
}
|
|
26024
25984
|
removeChunk(id) {
|
|
26025
25985
|
const index = this.contextChunks.findIndex((c) => c.id === id);
|
|
26026
|
-
if (index === -1)
|
|
26027
|
-
return false;
|
|
25986
|
+
if (index === -1) return false;
|
|
26028
25987
|
const chunk = this.contextChunks[index];
|
|
26029
25988
|
this.currentTokens -= chunk.tokens;
|
|
26030
25989
|
this.contextChunks.splice(index, 1);
|
|
@@ -26254,8 +26213,7 @@ var DriftDetector = class {
|
|
|
26254
26213
|
const earlier = messages[i];
|
|
26255
26214
|
for (let j = i + 1; j < messages.length; j++) {
|
|
26256
26215
|
const later = messages[j];
|
|
26257
|
-
if (earlier.role !== "assistant" || later.role !== "assistant")
|
|
26258
|
-
continue;
|
|
26216
|
+
if (earlier.role !== "assistant" || later.role !== "assistant") continue;
|
|
26259
26217
|
for (const pattern of CONTRADICTION_PATTERNS) {
|
|
26260
26218
|
const earlierMatch = earlier.content.match(pattern.earlier);
|
|
26261
26219
|
const laterMatch = later.content.match(pattern.later);
|
|
@@ -26441,8 +26399,7 @@ var CompactionEngine = class {
|
|
|
26441
26399
|
};
|
|
26442
26400
|
}
|
|
26443
26401
|
generateSummaries(chunks) {
|
|
26444
|
-
if (chunks.length === 0)
|
|
26445
|
-
return [];
|
|
26402
|
+
if (chunks.length === 0) return [];
|
|
26446
26403
|
const grouped = {};
|
|
26447
26404
|
for (const chunk of chunks) {
|
|
26448
26405
|
if (!grouped[chunk.type]) {
|
|
@@ -26452,8 +26409,7 @@ var CompactionEngine = class {
|
|
|
26452
26409
|
}
|
|
26453
26410
|
const summaries = [];
|
|
26454
26411
|
for (const [type, typeChunks] of Object.entries(grouped)) {
|
|
26455
|
-
if (typeChunks.length === 0)
|
|
26456
|
-
continue;
|
|
26412
|
+
if (typeChunks.length === 0) continue;
|
|
26457
26413
|
const allContent = typeChunks.map((c) => c.content).join(" ");
|
|
26458
26414
|
const summary = this.extractiveSummarize(allContent, type);
|
|
26459
26415
|
summaries.push(summary);
|
|
@@ -26622,8 +26578,7 @@ var CriticalContextManager = class {
|
|
|
26622
26578
|
WHERE id = ?
|
|
26623
26579
|
`);
|
|
26624
26580
|
const row = stmt.get(id);
|
|
26625
|
-
if (!row)
|
|
26626
|
-
return null;
|
|
26581
|
+
if (!row) return null;
|
|
26627
26582
|
return {
|
|
26628
26583
|
id: row.id,
|
|
26629
26584
|
type: row.type,
|
|
@@ -26953,16 +26908,13 @@ ${code}` : code;
|
|
|
26953
26908
|
}
|
|
26954
26909
|
switch (patternName) {
|
|
26955
26910
|
case "error-handling":
|
|
26956
|
-
if (/catch\s*\(\s*\w+\s*\)\s*\{[\s\S]*\}/.test(code))
|
|
26957
|
-
confidence += 10;
|
|
26911
|
+
if (/catch\s*\(\s*\w+\s*\)\s*\{[\s\S]*\}/.test(code)) confidence += 10;
|
|
26958
26912
|
break;
|
|
26959
26913
|
case "async-await":
|
|
26960
|
-
if (/await\s+[^;]+;/.test(code) && /async\s+/.test(code))
|
|
26961
|
-
confidence += 10;
|
|
26914
|
+
if (/await\s+[^;]+;/.test(code) && /async\s+/.test(code)) confidence += 10;
|
|
26962
26915
|
break;
|
|
26963
26916
|
case "null-check":
|
|
26964
|
-
if (/\?\.\w+/.test(code) || /!==?\s*null/.test(code))
|
|
26965
|
-
confidence += 10;
|
|
26917
|
+
if (/\?\.\w+/.test(code) || /!==?\s*null/.test(code)) confidence += 10;
|
|
26966
26918
|
break;
|
|
26967
26919
|
}
|
|
26968
26920
|
return Math.min(95, confidence);
|
|
@@ -26975,8 +26927,7 @@ ${code}` : code;
|
|
|
26975
26927
|
const pattern = CODE_PATTERNS.find((p) => p.name === patternName);
|
|
26976
26928
|
if (pattern && pattern.regex.test(preview)) {
|
|
26977
26929
|
examples.push(file2.path);
|
|
26978
|
-
if (examples.length >= 3)
|
|
26979
|
-
break;
|
|
26930
|
+
if (examples.length >= 3) break;
|
|
26980
26931
|
}
|
|
26981
26932
|
}
|
|
26982
26933
|
return examples;
|
|
@@ -27351,8 +27302,7 @@ var ConflictChecker = class {
|
|
|
27351
27302
|
const conflicts = [];
|
|
27352
27303
|
try {
|
|
27353
27304
|
const codeApproach = this.extractApproach(code);
|
|
27354
|
-
if (!codeApproach)
|
|
27355
|
-
return [];
|
|
27305
|
+
if (!codeApproach) return [];
|
|
27356
27306
|
const codeEmbedding = await this.embeddingGenerator.embed(codeApproach);
|
|
27357
27307
|
const relatedDecisions = this.tier2.searchDecisions(codeEmbedding, 5);
|
|
27358
27308
|
for (const related of relatedDecisions) {
|
|
@@ -27498,8 +27448,7 @@ var ConfidenceScorer = class _ConfidenceScorer {
|
|
|
27498
27448
|
};
|
|
27499
27449
|
}
|
|
27500
27450
|
calculateCodeScore(matches) {
|
|
27501
|
-
if (matches.length === 0)
|
|
27502
|
-
return 0;
|
|
27451
|
+
if (matches.length === 0) return 0;
|
|
27503
27452
|
let totalWeight = 0;
|
|
27504
27453
|
let weightedSum = 0;
|
|
27505
27454
|
for (const match of matches) {
|
|
@@ -27510,14 +27459,12 @@ var ConfidenceScorer = class _ConfidenceScorer {
|
|
|
27510
27459
|
return totalWeight > 0 ? weightedSum / totalWeight : 0;
|
|
27511
27460
|
}
|
|
27512
27461
|
calculateDecisionScore(matches) {
|
|
27513
|
-
if (matches.length === 0)
|
|
27514
|
-
return 50;
|
|
27462
|
+
if (matches.length === 0) return 50;
|
|
27515
27463
|
const totalRelevance = matches.reduce((sum, m) => sum + m.relevance, 0);
|
|
27516
27464
|
return totalRelevance / matches.length;
|
|
27517
27465
|
}
|
|
27518
27466
|
calculatePatternScore(matches) {
|
|
27519
|
-
if (matches.length === 0)
|
|
27520
|
-
return 30;
|
|
27467
|
+
if (matches.length === 0) return 30;
|
|
27521
27468
|
const totalConfidence = matches.reduce((sum, m) => sum + m.confidence, 0);
|
|
27522
27469
|
return totalConfidence / matches.length;
|
|
27523
27470
|
}
|
|
@@ -27525,12 +27472,9 @@ var ConfidenceScorer = class _ConfidenceScorer {
|
|
|
27525
27472
|
return codeScore * WEIGHTS.codebase + decisionScore * WEIGHTS.decision + patternScore * WEIGHTS.pattern;
|
|
27526
27473
|
}
|
|
27527
27474
|
determineLevel(score) {
|
|
27528
|
-
if (score >= THRESHOLDS.high)
|
|
27529
|
-
|
|
27530
|
-
if (score >= THRESHOLDS.
|
|
27531
|
-
return "medium";
|
|
27532
|
-
if (score >= THRESHOLDS.low)
|
|
27533
|
-
return "low";
|
|
27475
|
+
if (score >= THRESHOLDS.high) return "high";
|
|
27476
|
+
if (score >= THRESHOLDS.medium) return "medium";
|
|
27477
|
+
if (score >= THRESHOLDS.low) return "low";
|
|
27534
27478
|
return "guessing";
|
|
27535
27479
|
}
|
|
27536
27480
|
generateReasoning(level, sources, warnings) {
|
|
@@ -27585,10 +27529,13 @@ var ConfidenceScorer = class _ConfidenceScorer {
|
|
|
27585
27529
|
switch (level) {
|
|
27586
27530
|
case "high":
|
|
27587
27531
|
return "\u{1F7E2}";
|
|
27532
|
+
// Green circle
|
|
27588
27533
|
case "medium":
|
|
27589
27534
|
return "\u{1F7E1}";
|
|
27535
|
+
// Yellow circle
|
|
27590
27536
|
case "low":
|
|
27591
27537
|
return "\u{1F7E0}";
|
|
27538
|
+
// Orange circle
|
|
27592
27539
|
case "guessing":
|
|
27593
27540
|
return "\u{1F534}";
|
|
27594
27541
|
}
|
|
@@ -27665,8 +27612,7 @@ var ChangeTracker = class {
|
|
|
27665
27612
|
`git log --oneline -${limit} --format="%H|%an|%ad|%s" --date=unix`,
|
|
27666
27613
|
{ cwd: this.projectPath, encoding: "utf-8", maxBuffer: 10 * 1024 * 1024 }
|
|
27667
27614
|
).trim();
|
|
27668
|
-
if (!logOutput)
|
|
27669
|
-
return 0;
|
|
27615
|
+
if (!logOutput) return 0;
|
|
27670
27616
|
const commits = logOutput.split("\n").filter(Boolean);
|
|
27671
27617
|
let synced = 0;
|
|
27672
27618
|
for (const commitLine of commits) {
|
|
@@ -27676,20 +27622,17 @@ var ChangeTracker = class {
|
|
|
27676
27622
|
const existing = this.db.prepare(
|
|
27677
27623
|
"SELECT id FROM change_history WHERE commit_hash = ?"
|
|
27678
27624
|
).get(hash2);
|
|
27679
|
-
if (existing)
|
|
27680
|
-
continue;
|
|
27625
|
+
if (existing) continue;
|
|
27681
27626
|
try {
|
|
27682
27627
|
const filesOutput = execSync5(
|
|
27683
27628
|
`git show --numstat --format="" ${hash2}`,
|
|
27684
27629
|
{ cwd: this.projectPath, encoding: "utf-8", maxBuffer: 10 * 1024 * 1024 }
|
|
27685
27630
|
).trim();
|
|
27686
|
-
if (!filesOutput)
|
|
27687
|
-
continue;
|
|
27631
|
+
if (!filesOutput) continue;
|
|
27688
27632
|
const files = filesOutput.split("\n").filter(Boolean);
|
|
27689
27633
|
for (const fileLine of files) {
|
|
27690
27634
|
const [added, removed, filePath] = fileLine.split(" ");
|
|
27691
|
-
if (!filePath)
|
|
27692
|
-
continue;
|
|
27635
|
+
if (!filePath) continue;
|
|
27693
27636
|
let diff = "";
|
|
27694
27637
|
try {
|
|
27695
27638
|
const fullDiff = execSync5(
|
|
@@ -27729,10 +27672,8 @@ var ChangeTracker = class {
|
|
|
27729
27672
|
}
|
|
27730
27673
|
}
|
|
27731
27674
|
inferChangeType(added, removed, _filePath) {
|
|
27732
|
-
if (removed === 0 && added > 0)
|
|
27733
|
-
|
|
27734
|
-
if (added === 0 && removed > 0)
|
|
27735
|
-
return "delete";
|
|
27675
|
+
if (removed === 0 && added > 0) return "add";
|
|
27676
|
+
if (added === 0 && removed > 0) return "delete";
|
|
27736
27677
|
return "modify";
|
|
27737
27678
|
}
|
|
27738
27679
|
// Query changes
|
|
@@ -27829,8 +27770,7 @@ var ChangeTracker = class {
|
|
|
27829
27770
|
return this.queryChanges({ since }).changes;
|
|
27830
27771
|
}
|
|
27831
27772
|
parseSince(since) {
|
|
27832
|
-
if (since instanceof Date)
|
|
27833
|
-
return since;
|
|
27773
|
+
if (since instanceof Date) return since;
|
|
27834
27774
|
const now = /* @__PURE__ */ new Date();
|
|
27835
27775
|
const lower = since.toLowerCase();
|
|
27836
27776
|
if (lower === "today") {
|
|
@@ -28082,12 +28022,9 @@ var BugCorrelator = class {
|
|
|
28082
28022
|
score += 40;
|
|
28083
28023
|
}
|
|
28084
28024
|
const hoursAgo = (Date.now() - change.timestamp.getTime()) / (1e3 * 60 * 60);
|
|
28085
|
-
if (hoursAgo < 2)
|
|
28086
|
-
|
|
28087
|
-
else if (hoursAgo <
|
|
28088
|
-
score += 20;
|
|
28089
|
-
else if (hoursAgo < 24)
|
|
28090
|
-
score += 10;
|
|
28025
|
+
if (hoursAgo < 2) score += 30;
|
|
28026
|
+
else if (hoursAgo < 6) score += 20;
|
|
28027
|
+
else if (hoursAgo < 24) score += 10;
|
|
28091
28028
|
const diffLower = change.diff.toLowerCase();
|
|
28092
28029
|
let keywordMatches = 0;
|
|
28093
28030
|
for (const keyword of keywords) {
|
|
@@ -28113,8 +28050,7 @@ var BugCorrelator = class {
|
|
|
28113
28050
|
findSimilarBugs(error2, limit = 5) {
|
|
28114
28051
|
try {
|
|
28115
28052
|
const keywords = error2.split(/\s+/).filter((w) => w.length > 3).slice(0, 5).join(" OR ");
|
|
28116
|
-
if (!keywords)
|
|
28117
|
-
return [];
|
|
28053
|
+
if (!keywords) return [];
|
|
28118
28054
|
const rows = this.db.prepare(`
|
|
28119
28055
|
SELECT id, error, cause, fix_diff, file, timestamp, status
|
|
28120
28056
|
FROM bug_history
|
|
@@ -28150,8 +28086,7 @@ var BugCorrelator = class {
|
|
|
28150
28086
|
const words2 = new Set(error2.toLowerCase().split(/\s+/));
|
|
28151
28087
|
let matches = 0;
|
|
28152
28088
|
for (const word of words1) {
|
|
28153
|
-
if (words2.has(word))
|
|
28154
|
-
matches++;
|
|
28089
|
+
if (words2.has(word)) matches++;
|
|
28155
28090
|
}
|
|
28156
28091
|
const total = Math.max(words1.size, words2.size);
|
|
28157
28092
|
return total > 0 ? Math.round(matches / total * 100) : 0;
|
|
@@ -28186,14 +28121,11 @@ var BugCorrelator = class {
|
|
|
28186
28121
|
return parts.join(". ");
|
|
28187
28122
|
}
|
|
28188
28123
|
getSuggestedFix(pastBugs, _error) {
|
|
28189
|
-
if (pastBugs.length === 0)
|
|
28190
|
-
return null;
|
|
28124
|
+
if (pastBugs.length === 0) return null;
|
|
28191
28125
|
const bestMatch = pastBugs.find((bug) => bug.fix || bug.fixDiff);
|
|
28192
28126
|
if (bestMatch) {
|
|
28193
|
-
if (bestMatch.fix)
|
|
28194
|
-
|
|
28195
|
-
if (bestMatch.fixDiff)
|
|
28196
|
-
return `Apply similar fix:
|
|
28127
|
+
if (bestMatch.fix) return bestMatch.fix;
|
|
28128
|
+
if (bestMatch.fixDiff) return `Apply similar fix:
|
|
28197
28129
|
${bestMatch.fixDiff.slice(0, 200)}`;
|
|
28198
28130
|
}
|
|
28199
28131
|
return null;
|
|
@@ -28525,8 +28457,7 @@ var ChangeIntelligence = class {
|
|
|
28525
28457
|
}
|
|
28526
28458
|
// Initialize by syncing git history
|
|
28527
28459
|
initialize() {
|
|
28528
|
-
if (this.initialized)
|
|
28529
|
-
return 0;
|
|
28460
|
+
if (this.initialized) return 0;
|
|
28530
28461
|
const synced = this.changeTracker.syncFromGit(100);
|
|
28531
28462
|
this.initialized = true;
|
|
28532
28463
|
return synced;
|
|
@@ -28692,8 +28623,7 @@ var PatternLibrary = class {
|
|
|
28692
28623
|
}
|
|
28693
28624
|
seedDefaultPatterns() {
|
|
28694
28625
|
const count = this.db.prepare("SELECT COUNT(*) as count FROM patterns").get();
|
|
28695
|
-
if (count.count > 0)
|
|
28696
|
-
return;
|
|
28626
|
+
if (count.count > 0) return;
|
|
28697
28627
|
const defaultPatterns = [
|
|
28698
28628
|
{
|
|
28699
28629
|
name: "Error Handling",
|
|
@@ -28930,8 +28860,7 @@ export function MyComponent({ value, onChange }: Props) {
|
|
|
28930
28860
|
// Add example to pattern
|
|
28931
28861
|
addExample(id, example, isAntiPattern = false) {
|
|
28932
28862
|
const pattern = this.getPattern(id);
|
|
28933
|
-
if (!pattern)
|
|
28934
|
-
return false;
|
|
28863
|
+
if (!pattern) return false;
|
|
28935
28864
|
const field = isAntiPattern ? "anti_patterns" : "examples";
|
|
28936
28865
|
const current = isAntiPattern ? pattern.antiPatterns : pattern.examples;
|
|
28937
28866
|
current.push(example);
|
|
@@ -28944,8 +28873,7 @@ export function MyComponent({ value, onChange }: Props) {
|
|
|
28944
28873
|
// Add rule to pattern
|
|
28945
28874
|
addRule(id, rule) {
|
|
28946
28875
|
const pattern = this.getPattern(id);
|
|
28947
|
-
if (!pattern)
|
|
28948
|
-
return false;
|
|
28876
|
+
if (!pattern) return false;
|
|
28949
28877
|
pattern.rules.push(rule);
|
|
28950
28878
|
this.db.prepare("UPDATE patterns SET rules = ? WHERE id = ?").run(
|
|
28951
28879
|
JSON.stringify(pattern.rules),
|
|
@@ -29078,8 +29006,7 @@ var PatternLearner = class {
|
|
|
29078
29006
|
let patternsLearned = 0;
|
|
29079
29007
|
let examplesAdded = 0;
|
|
29080
29008
|
for (const file2 of files) {
|
|
29081
|
-
if (!file2.preview)
|
|
29082
|
-
continue;
|
|
29009
|
+
if (!file2.preview) continue;
|
|
29083
29010
|
const filePatterns = this.detectPatterns(file2.preview);
|
|
29084
29011
|
for (const detected of filePatterns) {
|
|
29085
29012
|
categories[detected.category] = (categories[detected.category] || 0) + 1;
|
|
@@ -29314,8 +29241,7 @@ var PatternValidator = class {
|
|
|
29314
29241
|
const patterns = category ? this.patternLibrary.getPatternsByCategory(category) : this.patternLibrary.getAllPatterns();
|
|
29315
29242
|
const matchedPattern = this.findBestMatch(code, patterns);
|
|
29316
29243
|
for (const rule of VALIDATION_RULES) {
|
|
29317
|
-
if (rule.category !== "all" && rule.category !== category)
|
|
29318
|
-
continue;
|
|
29244
|
+
if (rule.category !== "all" && rule.category !== category) continue;
|
|
29319
29245
|
const matches = rule.check.test(code);
|
|
29320
29246
|
if (rule.isViolation && matches) {
|
|
29321
29247
|
violations.push({
|
|
@@ -29399,18 +29325,12 @@ var PatternValidator = class {
|
|
|
29399
29325
|
}
|
|
29400
29326
|
// Detect what category of code this is
|
|
29401
29327
|
detectCategory(code) {
|
|
29402
|
-
if (/try\s*\{[\s\S]*catch/.test(code))
|
|
29403
|
-
|
|
29404
|
-
if (/
|
|
29405
|
-
|
|
29406
|
-
if (/
|
|
29407
|
-
|
|
29408
|
-
if (/if\s*\(\s*!?\w+\s*(?:===?|!==?)/.test(code))
|
|
29409
|
-
return "validation";
|
|
29410
|
-
if (/async\s+function|await\s+/.test(code))
|
|
29411
|
-
return "data_fetching";
|
|
29412
|
-
if (/console\.|logger\./.test(code))
|
|
29413
|
-
return "logging";
|
|
29328
|
+
if (/try\s*\{[\s\S]*catch/.test(code)) return "error_handling";
|
|
29329
|
+
if (/fetch\s*\(|axios\.|api\./.test(code)) return "api_call";
|
|
29330
|
+
if (/function\s+\w+.*\{[\s\S]*return\s*[(<]/.test(code)) return "component";
|
|
29331
|
+
if (/if\s*\(\s*!?\w+\s*(?:===?|!==?)/.test(code)) return "validation";
|
|
29332
|
+
if (/async\s+function|await\s+/.test(code)) return "data_fetching";
|
|
29333
|
+
if (/console\.|logger\./.test(code)) return "logging";
|
|
29414
29334
|
return null;
|
|
29415
29335
|
}
|
|
29416
29336
|
// Find the best matching pattern
|
|
@@ -29447,14 +29367,12 @@ var PatternValidator = class {
|
|
|
29447
29367
|
calculateSimilarity(code1, code2) {
|
|
29448
29368
|
const tokens1 = this.tokenize(code1);
|
|
29449
29369
|
const tokens2 = this.tokenize(code2);
|
|
29450
|
-
if (tokens1.length === 0 || tokens2.length === 0)
|
|
29451
|
-
return 0;
|
|
29370
|
+
if (tokens1.length === 0 || tokens2.length === 0) return 0;
|
|
29452
29371
|
const set1 = new Set(tokens1);
|
|
29453
29372
|
const set2 = new Set(tokens2);
|
|
29454
29373
|
let matches = 0;
|
|
29455
29374
|
for (const token of set1) {
|
|
29456
|
-
if (set2.has(token))
|
|
29457
|
-
matches++;
|
|
29375
|
+
if (set2.has(token)) matches++;
|
|
29458
29376
|
}
|
|
29459
29377
|
return matches / Math.max(set1.size, set2.size) * 100;
|
|
29460
29378
|
}
|
|
@@ -29551,15 +29469,13 @@ var DuplicateDetector = class {
|
|
|
29551
29469
|
const intentLower = intent.toLowerCase();
|
|
29552
29470
|
const intentWords = intentLower.split(/\s+/);
|
|
29553
29471
|
for (const [_key, func] of this.functionIndex) {
|
|
29554
|
-
if (!func.exported)
|
|
29555
|
-
continue;
|
|
29472
|
+
if (!func.exported) continue;
|
|
29556
29473
|
let relevance = 0;
|
|
29557
29474
|
const funcLower = func.name.toLowerCase();
|
|
29558
29475
|
const docLower = (func.docstring || "").toLowerCase();
|
|
29559
29476
|
const combined = `${funcLower} ${docLower}`;
|
|
29560
29477
|
for (const word of intentWords) {
|
|
29561
|
-
if (word.length < 3)
|
|
29562
|
-
continue;
|
|
29478
|
+
if (word.length < 3) continue;
|
|
29563
29479
|
if (funcLower.includes(word)) {
|
|
29564
29480
|
relevance += 30;
|
|
29565
29481
|
}
|
|
@@ -29603,17 +29519,14 @@ var DuplicateDetector = class {
|
|
|
29603
29519
|
calculateNameSimilarity(name1, name2) {
|
|
29604
29520
|
const lower1 = name1.toLowerCase();
|
|
29605
29521
|
const lower2 = name2.toLowerCase();
|
|
29606
|
-
if (lower1 === lower2)
|
|
29607
|
-
|
|
29608
|
-
if (lower1.includes(lower2) || lower2.includes(lower1))
|
|
29609
|
-
return 70;
|
|
29522
|
+
if (lower1 === lower2) return 100;
|
|
29523
|
+
if (lower1.includes(lower2) || lower2.includes(lower1)) return 70;
|
|
29610
29524
|
const tokens1 = this.camelCaseToTokens(name1);
|
|
29611
29525
|
const tokens2 = this.camelCaseToTokens(name2);
|
|
29612
29526
|
let matches = 0;
|
|
29613
29527
|
for (const t1 of tokens1) {
|
|
29614
29528
|
for (const t2 of tokens2) {
|
|
29615
|
-
if (t1 === t2)
|
|
29616
|
-
matches++;
|
|
29529
|
+
if (t1 === t2) matches++;
|
|
29617
29530
|
}
|
|
29618
29531
|
}
|
|
29619
29532
|
const totalTokens = Math.max(tokens1.length, tokens2.length);
|
|
@@ -29627,8 +29540,7 @@ var DuplicateDetector = class {
|
|
|
29627
29540
|
let total = 0;
|
|
29628
29541
|
for (const key of Object.keys(struct1)) {
|
|
29629
29542
|
total++;
|
|
29630
|
-
if (struct1[key] === struct2[key])
|
|
29631
|
-
matches++;
|
|
29543
|
+
if (struct1[key] === struct2[key]) matches++;
|
|
29632
29544
|
}
|
|
29633
29545
|
return total > 0 ? matches / total * 100 : 0;
|
|
29634
29546
|
}
|
|
@@ -29650,8 +29562,7 @@ var DuplicateDetector = class {
|
|
|
29650
29562
|
// Extract parameters from signature
|
|
29651
29563
|
extractParameters(signature) {
|
|
29652
29564
|
const match = signature.match(/\(([^)]*)\)/);
|
|
29653
|
-
if (!match)
|
|
29654
|
-
return [];
|
|
29565
|
+
if (!match) return [];
|
|
29655
29566
|
return match[1].split(",").map((p) => p.trim()).filter(Boolean).map((p) => p.split(":")[0].trim());
|
|
29656
29567
|
}
|
|
29657
29568
|
// Extract return type from signature
|
|
@@ -29669,8 +29580,7 @@ var DuplicateDetector = class {
|
|
|
29669
29580
|
let exportedFunctions = 0;
|
|
29670
29581
|
const byPurpose = {};
|
|
29671
29582
|
for (const [_key, func] of this.functionIndex) {
|
|
29672
|
-
if (func.exported)
|
|
29673
|
-
exportedFunctions++;
|
|
29583
|
+
if (func.exported) exportedFunctions++;
|
|
29674
29584
|
const purpose = this.detectPurpose(func.name) || "other";
|
|
29675
29585
|
byPurpose[purpose] = (byPurpose[purpose] || 0) + 1;
|
|
29676
29586
|
}
|
|
@@ -29697,8 +29607,7 @@ var ArchitectureEnforcement = class {
|
|
|
29697
29607
|
}
|
|
29698
29608
|
// Initialize by learning patterns from codebase
|
|
29699
29609
|
initialize() {
|
|
29700
|
-
if (this.initialized)
|
|
29701
|
-
return { patternsLearned: 0, examplesAdded: 0 };
|
|
29610
|
+
if (this.initialized) return { patternsLearned: 0, examplesAdded: 0 };
|
|
29702
29611
|
const result = this.patternLearner.learnFromCodebase();
|
|
29703
29612
|
this.initialized = true;
|
|
29704
29613
|
return {
|
|
@@ -29848,7 +29757,7 @@ ${category.toUpperCase()}:`);
|
|
|
29848
29757
|
|
|
29849
29758
|
// src/core/test-awareness/test-indexer.ts
|
|
29850
29759
|
import { existsSync as existsSync11, readFileSync as readFileSync8 } from "fs";
|
|
29851
|
-
import { join as
|
|
29760
|
+
import { join as join11 } from "path";
|
|
29852
29761
|
|
|
29853
29762
|
// src/core/test-awareness/test-parser.ts
|
|
29854
29763
|
import { createHash as createHash4 } from "crypto";
|
|
@@ -29905,10 +29814,8 @@ var TestParser = class {
|
|
|
29905
29814
|
if (inTest) {
|
|
29906
29815
|
testContent += "\n" + line;
|
|
29907
29816
|
for (const char of line) {
|
|
29908
|
-
if (char === "{" || char === "(")
|
|
29909
|
-
|
|
29910
|
-
if (char === "}" || char === ")")
|
|
29911
|
-
braceCount--;
|
|
29817
|
+
if (char === "{" || char === "(") braceCount++;
|
|
29818
|
+
if (char === "}" || char === ")") braceCount--;
|
|
29912
29819
|
}
|
|
29913
29820
|
if (braceCount <= 0) {
|
|
29914
29821
|
const assertions = this.extractJsAssertions(testContent, testStartLine);
|
|
@@ -30039,20 +29946,16 @@ var TestParser = class {
|
|
|
30039
29946
|
testContent = line;
|
|
30040
29947
|
braceCount = 0;
|
|
30041
29948
|
for (const char of line) {
|
|
30042
|
-
if (char === "{")
|
|
30043
|
-
|
|
30044
|
-
if (char === "}")
|
|
30045
|
-
braceCount--;
|
|
29949
|
+
if (char === "{") braceCount++;
|
|
29950
|
+
if (char === "}") braceCount--;
|
|
30046
29951
|
}
|
|
30047
29952
|
continue;
|
|
30048
29953
|
}
|
|
30049
29954
|
if (inTest) {
|
|
30050
29955
|
testContent += "\n" + line;
|
|
30051
29956
|
for (const char of line) {
|
|
30052
|
-
if (char === "{")
|
|
30053
|
-
|
|
30054
|
-
if (char === "}")
|
|
30055
|
-
braceCount--;
|
|
29957
|
+
if (char === "{") braceCount++;
|
|
29958
|
+
if (char === "}") braceCount--;
|
|
30056
29959
|
}
|
|
30057
29960
|
if (braceCount <= 0) {
|
|
30058
29961
|
const assertions = this.extractGoAssertions(testContent, testStartLine);
|
|
@@ -30091,13 +29994,10 @@ var TestParser = class {
|
|
|
30091
29994
|
const namespaceImport = match[2];
|
|
30092
29995
|
const defaultImport = match[3];
|
|
30093
29996
|
const source = match[4];
|
|
30094
|
-
if (!source)
|
|
30095
|
-
continue;
|
|
29997
|
+
if (!source) continue;
|
|
30096
29998
|
const symbols = [...namedImports];
|
|
30097
|
-
if (namespaceImport)
|
|
30098
|
-
|
|
30099
|
-
if (defaultImport)
|
|
30100
|
-
symbols.push(defaultImport);
|
|
29999
|
+
if (namespaceImport) symbols.push(`* as ${namespaceImport}`);
|
|
30000
|
+
if (defaultImport) symbols.push(defaultImport);
|
|
30101
30001
|
imports.push({
|
|
30102
30002
|
source,
|
|
30103
30003
|
symbols,
|
|
@@ -30110,8 +30010,7 @@ var TestParser = class {
|
|
|
30110
30010
|
const destructured = destructuredStr ? destructuredStr.split(",").map((s) => s.trim()).filter(Boolean) : [];
|
|
30111
30011
|
const variable = match[2];
|
|
30112
30012
|
const source = match[3];
|
|
30113
|
-
if (!source)
|
|
30114
|
-
continue;
|
|
30013
|
+
if (!source) continue;
|
|
30115
30014
|
const symbols = destructured.length > 0 ? destructured : variable ? [variable] : [];
|
|
30116
30015
|
imports.push({
|
|
30117
30016
|
source,
|
|
@@ -30128,8 +30027,7 @@ var TestParser = class {
|
|
|
30128
30027
|
while ((match = fromImportRegex.exec(content)) !== null) {
|
|
30129
30028
|
const source = match[1];
|
|
30130
30029
|
const importedItemsStr = match[2];
|
|
30131
|
-
if (!source || !importedItemsStr)
|
|
30132
|
-
continue;
|
|
30030
|
+
if (!source || !importedItemsStr) continue;
|
|
30133
30031
|
const importedItems = importedItemsStr.split(",").map((s) => {
|
|
30134
30032
|
const trimmed = s.trim();
|
|
30135
30033
|
const parts = trimmed.split(/\s+as\s+/);
|
|
@@ -30144,8 +30042,7 @@ var TestParser = class {
|
|
|
30144
30042
|
const importRegex = /^import\s+([\w.]+)(?:\s+as\s+(\w+))?/gm;
|
|
30145
30043
|
while ((match = importRegex.exec(content)) !== null) {
|
|
30146
30044
|
const source = match[1];
|
|
30147
|
-
if (!source)
|
|
30148
|
-
continue;
|
|
30045
|
+
if (!source) continue;
|
|
30149
30046
|
const sourceParts = source.split(".");
|
|
30150
30047
|
const alias = match[2] ?? sourceParts[sourceParts.length - 1] ?? source;
|
|
30151
30048
|
imports.push({
|
|
@@ -30162,8 +30059,7 @@ var TestParser = class {
|
|
|
30162
30059
|
let match;
|
|
30163
30060
|
while ((match = singleImportRegex.exec(content)) !== null) {
|
|
30164
30061
|
const source = match[1];
|
|
30165
|
-
if (!source)
|
|
30166
|
-
continue;
|
|
30062
|
+
if (!source) continue;
|
|
30167
30063
|
const sourceParts = source.split("/");
|
|
30168
30064
|
const pkg = sourceParts[sourceParts.length - 1] ?? source;
|
|
30169
30065
|
imports.push({
|
|
@@ -30175,15 +30071,13 @@ var TestParser = class {
|
|
|
30175
30071
|
const importBlockRegex = /import\s*\(\s*([\s\S]*?)\s*\)/g;
|
|
30176
30072
|
while ((match = importBlockRegex.exec(content)) !== null) {
|
|
30177
30073
|
const block = match[1];
|
|
30178
|
-
if (!block)
|
|
30179
|
-
continue;
|
|
30074
|
+
if (!block) continue;
|
|
30180
30075
|
const lineRegex = /(?:(\w+)\s+)?"([^"]+)"/g;
|
|
30181
30076
|
let lineMatch;
|
|
30182
30077
|
while ((lineMatch = lineRegex.exec(block)) !== null) {
|
|
30183
30078
|
const alias = lineMatch[1];
|
|
30184
30079
|
const source = lineMatch[2];
|
|
30185
|
-
if (!source)
|
|
30186
|
-
continue;
|
|
30080
|
+
if (!source) continue;
|
|
30187
30081
|
const sourceParts = source.split("/");
|
|
30188
30082
|
const pkg = alias ?? sourceParts[sourceParts.length - 1] ?? source;
|
|
30189
30083
|
imports.push({
|
|
@@ -30198,8 +30092,7 @@ var TestParser = class {
|
|
|
30198
30092
|
getCoveredFilesFromImports(imports) {
|
|
30199
30093
|
return imports.filter((imp) => imp.isRelative).map((imp) => {
|
|
30200
30094
|
let path = imp.source;
|
|
30201
|
-
if (path.startsWith("./"))
|
|
30202
|
-
path = path.slice(2);
|
|
30095
|
+
if (path.startsWith("./")) path = path.slice(2);
|
|
30203
30096
|
if (!path.match(/\.[jt]sx?$|\.py$|\.go$/)) {
|
|
30204
30097
|
return path;
|
|
30205
30098
|
}
|
|
@@ -30227,8 +30120,7 @@ var TestParser = class {
|
|
|
30227
30120
|
];
|
|
30228
30121
|
for (let i = 0; i < lines.length; i++) {
|
|
30229
30122
|
const line = lines[i];
|
|
30230
|
-
if (!line)
|
|
30231
|
-
continue;
|
|
30123
|
+
if (!line) continue;
|
|
30232
30124
|
const lineNum = startLine + i;
|
|
30233
30125
|
for (const pattern of patterns) {
|
|
30234
30126
|
const match = line.match(pattern.regex);
|
|
@@ -30268,8 +30160,7 @@ var TestParser = class {
|
|
|
30268
30160
|
];
|
|
30269
30161
|
for (let i = 0; i < lines.length; i++) {
|
|
30270
30162
|
const line = lines[i];
|
|
30271
|
-
if (!line)
|
|
30272
|
-
continue;
|
|
30163
|
+
if (!line) continue;
|
|
30273
30164
|
const lineNum = startLine + i;
|
|
30274
30165
|
for (const pattern of patterns) {
|
|
30275
30166
|
const match = line.match(pattern.regex);
|
|
@@ -30305,8 +30196,7 @@ var TestParser = class {
|
|
|
30305
30196
|
];
|
|
30306
30197
|
for (let i = 0; i < lines.length; i++) {
|
|
30307
30198
|
const line = lines[i];
|
|
30308
|
-
if (!line)
|
|
30309
|
-
continue;
|
|
30199
|
+
if (!line) continue;
|
|
30310
30200
|
const lineNum = startLine + i;
|
|
30311
30201
|
for (const pattern of patterns) {
|
|
30312
30202
|
const match = line.match(pattern.regex);
|
|
@@ -30429,37 +30319,34 @@ var TestIndexer = class {
|
|
|
30429
30319
|
this.parser = new TestParser();
|
|
30430
30320
|
}
|
|
30431
30321
|
detectFramework() {
|
|
30432
|
-
const packageJsonPath =
|
|
30322
|
+
const packageJsonPath = join11(this.projectPath, "package.json");
|
|
30433
30323
|
if (existsSync11(packageJsonPath)) {
|
|
30434
30324
|
try {
|
|
30435
30325
|
const pkg = JSON.parse(readFileSync8(packageJsonPath, "utf-8"));
|
|
30436
30326
|
const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
30437
|
-
if (allDeps["vitest"])
|
|
30438
|
-
|
|
30439
|
-
if (allDeps["
|
|
30440
|
-
return "jest";
|
|
30441
|
-
if (allDeps["mocha"])
|
|
30442
|
-
return "mocha";
|
|
30327
|
+
if (allDeps["vitest"]) return "vitest";
|
|
30328
|
+
if (allDeps["jest"]) return "jest";
|
|
30329
|
+
if (allDeps["mocha"]) return "mocha";
|
|
30443
30330
|
} catch {
|
|
30444
30331
|
}
|
|
30445
30332
|
}
|
|
30446
30333
|
const pytestConfigs = ["pytest.ini", "pyproject.toml", "setup.cfg", "conftest.py"];
|
|
30447
30334
|
for (const config2 of pytestConfigs) {
|
|
30448
|
-
if (existsSync11(
|
|
30449
|
-
const content = readFileSync8(
|
|
30335
|
+
if (existsSync11(join11(this.projectPath, config2))) {
|
|
30336
|
+
const content = readFileSync8(join11(this.projectPath, config2), "utf-8");
|
|
30450
30337
|
if (content.includes("[pytest]") || content.includes("pytest") || config2 === "conftest.py") {
|
|
30451
30338
|
return "pytest";
|
|
30452
30339
|
}
|
|
30453
30340
|
}
|
|
30454
30341
|
}
|
|
30455
|
-
const goMod =
|
|
30342
|
+
const goMod = join11(this.projectPath, "go.mod");
|
|
30456
30343
|
if (existsSync11(goMod)) {
|
|
30457
30344
|
return "go";
|
|
30458
30345
|
}
|
|
30459
30346
|
const vitestConfigs = ["vitest.config.ts", "vitest.config.js", "vite.config.ts", "vite.config.js"];
|
|
30460
30347
|
for (const config2 of vitestConfigs) {
|
|
30461
|
-
if (existsSync11(
|
|
30462
|
-
const content = readFileSync8(
|
|
30348
|
+
if (existsSync11(join11(this.projectPath, config2))) {
|
|
30349
|
+
const content = readFileSync8(join11(this.projectPath, config2), "utf-8");
|
|
30463
30350
|
if (content.includes("vitest") || content.includes("test:")) {
|
|
30464
30351
|
return "vitest";
|
|
30465
30352
|
}
|
|
@@ -30467,19 +30354,16 @@ var TestIndexer = class {
|
|
|
30467
30354
|
}
|
|
30468
30355
|
const jestConfigs = ["jest.config.ts", "jest.config.js", "jest.config.json"];
|
|
30469
30356
|
for (const config2 of jestConfigs) {
|
|
30470
|
-
if (existsSync11(
|
|
30357
|
+
if (existsSync11(join11(this.projectPath, config2))) {
|
|
30471
30358
|
return "jest";
|
|
30472
30359
|
}
|
|
30473
30360
|
}
|
|
30474
30361
|
const hasJsTests = this.hasFilesMatching(["**/*.test.ts", "**/*.spec.ts"]);
|
|
30475
30362
|
const hasPyTests = this.hasFilesMatching(["**/test_*.py", "**/*_test.py"]);
|
|
30476
30363
|
const hasGoTests = this.hasFilesMatching(["**/*_test.go"]);
|
|
30477
|
-
if (hasGoTests)
|
|
30478
|
-
|
|
30479
|
-
if (
|
|
30480
|
-
return "pytest";
|
|
30481
|
-
if (hasJsTests)
|
|
30482
|
-
return "jest";
|
|
30364
|
+
if (hasGoTests) return "go";
|
|
30365
|
+
if (hasPyTests) return "pytest";
|
|
30366
|
+
if (hasJsTests) return "jest";
|
|
30483
30367
|
return "unknown";
|
|
30484
30368
|
}
|
|
30485
30369
|
hasFilesMatching(patterns) {
|
|
@@ -30490,8 +30374,7 @@ var TestIndexer = class {
|
|
|
30490
30374
|
ignore: IGNORE_PATTERNS,
|
|
30491
30375
|
nodir: true
|
|
30492
30376
|
});
|
|
30493
|
-
if (files.length > 0)
|
|
30494
|
-
return true;
|
|
30377
|
+
if (files.length > 0) return true;
|
|
30495
30378
|
} catch {
|
|
30496
30379
|
}
|
|
30497
30380
|
}
|
|
@@ -30510,7 +30393,7 @@ var TestIndexer = class {
|
|
|
30510
30393
|
absolute: false
|
|
30511
30394
|
});
|
|
30512
30395
|
for (const file2 of files) {
|
|
30513
|
-
const absolutePath =
|
|
30396
|
+
const absolutePath = join11(this.projectPath, file2);
|
|
30514
30397
|
const tests = this.parseTestFile(absolutePath, file2);
|
|
30515
30398
|
allTests.push(...tests);
|
|
30516
30399
|
}
|
|
@@ -30522,8 +30405,7 @@ var TestIndexer = class {
|
|
|
30522
30405
|
}
|
|
30523
30406
|
parseTestFile(absolutePath, relativePath) {
|
|
30524
30407
|
const cached2 = this.testCache.get(relativePath);
|
|
30525
|
-
if (cached2)
|
|
30526
|
-
return cached2;
|
|
30408
|
+
if (cached2) return cached2;
|
|
30527
30409
|
try {
|
|
30528
30410
|
const content = readFileSync8(absolutePath, "utf-8");
|
|
30529
30411
|
const tests = this.parser.parseFile(content, relativePath, this.framework);
|
|
@@ -30638,7 +30520,7 @@ var TestIndexer = class {
|
|
|
30638
30520
|
absolute: false
|
|
30639
30521
|
});
|
|
30640
30522
|
for (const file2 of files) {
|
|
30641
|
-
const absolutePath =
|
|
30523
|
+
const absolutePath = join11(this.projectPath, file2);
|
|
30642
30524
|
const tests = this.parseTestFile(absolutePath, file2);
|
|
30643
30525
|
allTests.push(...tests);
|
|
30644
30526
|
}
|
|
@@ -30896,8 +30778,7 @@ var ChangeValidator = class {
|
|
|
30896
30778
|
let match;
|
|
30897
30779
|
while ((match = pattern.exec(code)) !== null) {
|
|
30898
30780
|
const captured = match[1];
|
|
30899
|
-
if (!captured)
|
|
30900
|
-
continue;
|
|
30781
|
+
if (!captured) continue;
|
|
30901
30782
|
if (captured.includes(",")) {
|
|
30902
30783
|
const names = captured.split(",").map((s) => {
|
|
30903
30784
|
const parts = s.trim().split(/\s+as\s+/);
|
|
@@ -30915,12 +30796,9 @@ var ChangeValidator = class {
|
|
|
30915
30796
|
const hasAdditions = parsed.addedLines.length > 0 || parsed.modifiedFunctions.some((f) => f.changeType === "added");
|
|
30916
30797
|
const hasDeletions = parsed.removedLines.length > 0 || parsed.modifiedFunctions.some((f) => f.changeType === "removed");
|
|
30917
30798
|
const hasModifications = parsed.modifiedFunctions.some((f) => f.changeType === "modified" || f.changeType === "signature_changed");
|
|
30918
|
-
if (hasDeletions && !hasAdditions)
|
|
30919
|
-
|
|
30920
|
-
if (hasAdditions &&
|
|
30921
|
-
return "add";
|
|
30922
|
-
if (hasModifications || hasAdditions && hasDeletions)
|
|
30923
|
-
return "modify";
|
|
30799
|
+
if (hasDeletions && !hasAdditions) return "delete";
|
|
30800
|
+
if (hasAdditions && !hasDeletions && !hasModifications) return "add";
|
|
30801
|
+
if (hasModifications || hasAdditions && hasDeletions) return "modify";
|
|
30924
30802
|
return "refactor";
|
|
30925
30803
|
}
|
|
30926
30804
|
calculateRisk(parsed, affectedTests) {
|
|
@@ -30938,10 +30816,8 @@ var ChangeValidator = class {
|
|
|
30938
30816
|
if (affectedTests.length > 10) {
|
|
30939
30817
|
riskScore += 15;
|
|
30940
30818
|
}
|
|
30941
|
-
if (riskScore >= 50)
|
|
30942
|
-
|
|
30943
|
-
if (riskScore >= 25)
|
|
30944
|
-
return "medium";
|
|
30819
|
+
if (riskScore >= 50) return "high";
|
|
30820
|
+
if (riskScore >= 25) return "medium";
|
|
30945
30821
|
return "low";
|
|
30946
30822
|
}
|
|
30947
30823
|
generateReasoning(parsed, affectedTests, risk) {
|
|
@@ -31085,8 +30961,7 @@ var TestSuggester = class {
|
|
|
31085
30961
|
return updates;
|
|
31086
30962
|
}
|
|
31087
30963
|
generateAssertionUpdate(failure) {
|
|
31088
|
-
if (!failure.assertion)
|
|
31089
|
-
return null;
|
|
30964
|
+
if (!failure.assertion) return null;
|
|
31090
30965
|
const assertion = failure.assertion;
|
|
31091
30966
|
let after = assertion.code;
|
|
31092
30967
|
let reason = failure.reason;
|
|
@@ -31335,8 +31210,7 @@ func Test${functionName}(t *testing.T) {
|
|
|
31335
31210
|
}
|
|
31336
31211
|
parseParameters(signature) {
|
|
31337
31212
|
const match = signature.match(/\(([^)]*)\)/);
|
|
31338
|
-
if (!match || !match[1]?.trim())
|
|
31339
|
-
return [];
|
|
31213
|
+
if (!match || !match[1]?.trim()) return [];
|
|
31340
31214
|
return match[1].split(",").map((p) => p.trim()).filter(Boolean).map((p) => {
|
|
31341
31215
|
const parts = p.split(/[:\s]+/);
|
|
31342
31216
|
const firstPart = parts[0];
|
|
@@ -31345,48 +31219,31 @@ func Test${functionName}(t *testing.T) {
|
|
|
31345
31219
|
}
|
|
31346
31220
|
getExampleValue(param) {
|
|
31347
31221
|
const lower = param.toLowerCase();
|
|
31348
|
-
if (lower.includes("name") || lower.includes("str") || lower.includes("text"))
|
|
31349
|
-
|
|
31350
|
-
if (lower.includes("
|
|
31351
|
-
|
|
31352
|
-
if (lower.includes("
|
|
31353
|
-
|
|
31354
|
-
if (lower.includes("
|
|
31355
|
-
return "true";
|
|
31356
|
-
if (lower.includes("list") || lower.includes("array") || lower.includes("items"))
|
|
31357
|
-
return "[]";
|
|
31358
|
-
if (lower.includes("obj") || lower.includes("data") || lower.includes("options"))
|
|
31359
|
-
return "{}";
|
|
31360
|
-
if (lower.includes("fn") || lower.includes("callback") || lower.includes("handler"))
|
|
31361
|
-
return "() => {}";
|
|
31222
|
+
if (lower.includes("name") || lower.includes("str") || lower.includes("text")) return "'test'";
|
|
31223
|
+
if (lower.includes("id")) return "'123'";
|
|
31224
|
+
if (lower.includes("num") || lower.includes("count") || lower.includes("index")) return "1";
|
|
31225
|
+
if (lower.includes("flag") || lower.includes("is") || lower.includes("has")) return "true";
|
|
31226
|
+
if (lower.includes("list") || lower.includes("array") || lower.includes("items")) return "[]";
|
|
31227
|
+
if (lower.includes("obj") || lower.includes("data") || lower.includes("options")) return "{}";
|
|
31228
|
+
if (lower.includes("fn") || lower.includes("callback") || lower.includes("handler")) return "() => {}";
|
|
31362
31229
|
return "/* TODO */";
|
|
31363
31230
|
}
|
|
31364
31231
|
getPythonExampleValue(param) {
|
|
31365
31232
|
const lower = param.toLowerCase();
|
|
31366
|
-
if (lower.includes("name") || lower.includes("str") || lower.includes("text"))
|
|
31367
|
-
|
|
31368
|
-
if (lower.includes("
|
|
31369
|
-
|
|
31370
|
-
if (lower.includes("
|
|
31371
|
-
|
|
31372
|
-
if (lower.includes("flag") || lower.includes("is") || lower.includes("has"))
|
|
31373
|
-
return "True";
|
|
31374
|
-
if (lower.includes("list") || lower.includes("array") || lower.includes("items"))
|
|
31375
|
-
return "[]";
|
|
31376
|
-
if (lower.includes("obj") || lower.includes("data") || lower.includes("dict"))
|
|
31377
|
-
return "{}";
|
|
31233
|
+
if (lower.includes("name") || lower.includes("str") || lower.includes("text")) return '"test"';
|
|
31234
|
+
if (lower.includes("id")) return '"123"';
|
|
31235
|
+
if (lower.includes("num") || lower.includes("count") || lower.includes("index")) return "1";
|
|
31236
|
+
if (lower.includes("flag") || lower.includes("is") || lower.includes("has")) return "True";
|
|
31237
|
+
if (lower.includes("list") || lower.includes("array") || lower.includes("items")) return "[]";
|
|
31238
|
+
if (lower.includes("obj") || lower.includes("data") || lower.includes("dict")) return "{}";
|
|
31378
31239
|
return "None # TODO";
|
|
31379
31240
|
}
|
|
31380
31241
|
getGoExampleValue(param) {
|
|
31381
31242
|
const lower = param.toLowerCase();
|
|
31382
|
-
if (lower.includes("name") || lower.includes("str") || lower.includes("text"))
|
|
31383
|
-
|
|
31384
|
-
if (lower.includes("
|
|
31385
|
-
|
|
31386
|
-
if (lower.includes("num") || lower.includes("count") || lower.includes("index"))
|
|
31387
|
-
return "1";
|
|
31388
|
-
if (lower.includes("flag") || lower.includes("is") || lower.includes("has"))
|
|
31389
|
-
return "true";
|
|
31243
|
+
if (lower.includes("name") || lower.includes("str") || lower.includes("text")) return '"test"';
|
|
31244
|
+
if (lower.includes("id")) return '"123"';
|
|
31245
|
+
if (lower.includes("num") || lower.includes("count") || lower.includes("index")) return "1";
|
|
31246
|
+
if (lower.includes("flag") || lower.includes("is") || lower.includes("has")) return "true";
|
|
31390
31247
|
return "nil /* TODO */";
|
|
31391
31248
|
}
|
|
31392
31249
|
formatTestUpdates(updates) {
|
|
@@ -31972,24 +31829,15 @@ function formatTimeAgo(date4) {
|
|
|
31972
31829
|
const diffDays = Math.floor(diffMs / (1e3 * 60 * 60 * 24));
|
|
31973
31830
|
const diffWeeks = Math.floor(diffDays / 7);
|
|
31974
31831
|
const diffMonths = Math.floor(diffDays / 30);
|
|
31975
|
-
if (diffMins < 1)
|
|
31976
|
-
|
|
31977
|
-
if (
|
|
31978
|
-
|
|
31979
|
-
if (
|
|
31980
|
-
|
|
31981
|
-
if (
|
|
31982
|
-
|
|
31983
|
-
if (
|
|
31984
|
-
return `${diffDays} days ago`;
|
|
31985
|
-
if (diffWeeks === 1)
|
|
31986
|
-
return "1 week ago";
|
|
31987
|
-
if (diffWeeks < 4)
|
|
31988
|
-
return `${diffWeeks} weeks ago`;
|
|
31989
|
-
if (diffMonths === 1)
|
|
31990
|
-
return "1 month ago";
|
|
31991
|
-
if (diffMonths < 12)
|
|
31992
|
-
return `${diffMonths} months ago`;
|
|
31832
|
+
if (diffMins < 1) return "just now";
|
|
31833
|
+
if (diffMins < 60) return `${diffMins} minute${diffMins > 1 ? "s" : ""} ago`;
|
|
31834
|
+
if (diffHours < 24) return `${diffHours} hour${diffHours > 1 ? "s" : ""} ago`;
|
|
31835
|
+
if (diffDays === 1) return "yesterday";
|
|
31836
|
+
if (diffDays < 7) return `${diffDays} days ago`;
|
|
31837
|
+
if (diffWeeks === 1) return "1 week ago";
|
|
31838
|
+
if (diffWeeks < 4) return `${diffWeeks} weeks ago`;
|
|
31839
|
+
if (diffMonths === 1) return "1 month ago";
|
|
31840
|
+
if (diffMonths < 12) return `${diffMonths} months ago`;
|
|
31993
31841
|
return date4.toLocaleDateString();
|
|
31994
31842
|
}
|
|
31995
31843
|
function formatTimeAgoWithContext(date4, action, file2) {
|
|
@@ -32077,8 +31925,7 @@ var DejaVuDetector = class {
|
|
|
32077
31925
|
const embedding = await this.embeddingGenerator.embed(query);
|
|
32078
31926
|
const searchResults = this.tier2.search(embedding, 10);
|
|
32079
31927
|
for (const result of searchResults) {
|
|
32080
|
-
if (result.similarity < this.SIMILARITY_THRESHOLD)
|
|
32081
|
-
continue;
|
|
31928
|
+
if (result.similarity < this.SIMILARITY_THRESHOLD) continue;
|
|
32082
31929
|
const usageStmt = this.db.prepare(`
|
|
32083
31930
|
SELECT ue.query, ue.timestamp, qp.avg_usefulness
|
|
32084
31931
|
FROM usage_events ue
|
|
@@ -32129,8 +31976,7 @@ var DejaVuDetector = class {
|
|
|
32129
31976
|
`);
|
|
32130
31977
|
const rows = stmt.all(this.MAX_AGE_DAYS);
|
|
32131
31978
|
for (const row of rows) {
|
|
32132
|
-
if (!row.query)
|
|
32133
|
-
continue;
|
|
31979
|
+
if (!row.query) continue;
|
|
32134
31980
|
const similarity = this.calculateTextSimilarity(query, row.query);
|
|
32135
31981
|
if (similarity >= this.SIMILARITY_THRESHOLD * 0.8) {
|
|
32136
31982
|
const resultFiles = row.result_files ? this.parseJsonArray(row.result_files) : [];
|
|
@@ -32258,8 +32104,7 @@ var DejaVuDetector = class {
|
|
|
32258
32104
|
return Math.exp(-diffDays / (this.MAX_AGE_DAYS / 3));
|
|
32259
32105
|
}
|
|
32260
32106
|
parseJsonArray(json2) {
|
|
32261
|
-
if (!json2)
|
|
32262
|
-
return [];
|
|
32107
|
+
if (!json2) return [];
|
|
32263
32108
|
try {
|
|
32264
32109
|
const parsed = JSON.parse(json2);
|
|
32265
32110
|
return Array.isArray(parsed) ? parsed : [];
|
|
@@ -32275,7 +32120,7 @@ var DejaVuDetector = class {
|
|
|
32275
32120
|
|
|
32276
32121
|
// src/core/code-verifier.ts
|
|
32277
32122
|
import { existsSync as existsSync12, readFileSync as readFileSync9 } from "fs";
|
|
32278
|
-
import { join as
|
|
32123
|
+
import { join as join12, dirname as dirname6, extname as extname4 } from "path";
|
|
32279
32124
|
var SECURITY_PATTERNS2 = [
|
|
32280
32125
|
// SQL Injection
|
|
32281
32126
|
{
|
|
@@ -32520,11 +32365,11 @@ var CodeVerifier = class {
|
|
|
32520
32365
|
nodeModulesPath;
|
|
32521
32366
|
constructor(projectPath) {
|
|
32522
32367
|
this.projectPath = projectPath;
|
|
32523
|
-
this.nodeModulesPath =
|
|
32368
|
+
this.nodeModulesPath = join12(projectPath, "node_modules");
|
|
32524
32369
|
this.loadPackageJson();
|
|
32525
32370
|
}
|
|
32526
32371
|
loadPackageJson() {
|
|
32527
|
-
const packageJsonPath =
|
|
32372
|
+
const packageJsonPath = join12(this.projectPath, "package.json");
|
|
32528
32373
|
if (existsSync12(packageJsonPath)) {
|
|
32529
32374
|
try {
|
|
32530
32375
|
this.packageJson = JSON.parse(readFileSync9(packageJsonPath, "utf-8"));
|
|
@@ -32677,7 +32522,7 @@ var CodeVerifier = class {
|
|
|
32677
32522
|
}
|
|
32678
32523
|
const packageName = this.getPackageName(importPath);
|
|
32679
32524
|
if (!packages.has(packageName)) {
|
|
32680
|
-
const nodeModulePath =
|
|
32525
|
+
const nodeModulePath = join12(this.nodeModulesPath, packageName);
|
|
32681
32526
|
if (existsSync12(nodeModulePath)) {
|
|
32682
32527
|
issues.push({
|
|
32683
32528
|
package: packageName,
|
|
@@ -32706,40 +32551,36 @@ var CodeVerifier = class {
|
|
|
32706
32551
|
let match;
|
|
32707
32552
|
const esPattern = new RegExp(IMPORT_PATTERNS.esImport.source, "g");
|
|
32708
32553
|
while ((match = esPattern.exec(code)) !== null) {
|
|
32709
|
-
if (match[1])
|
|
32710
|
-
imports.add(match[1]);
|
|
32554
|
+
if (match[1]) imports.add(match[1]);
|
|
32711
32555
|
}
|
|
32712
32556
|
const dynamicPattern = new RegExp(IMPORT_PATTERNS.dynamicImport.source, "g");
|
|
32713
32557
|
while ((match = dynamicPattern.exec(code)) !== null) {
|
|
32714
|
-
if (match[1])
|
|
32715
|
-
imports.add(match[1]);
|
|
32558
|
+
if (match[1]) imports.add(match[1]);
|
|
32716
32559
|
}
|
|
32717
32560
|
const requirePattern = new RegExp(IMPORT_PATTERNS.require.source, "g");
|
|
32718
32561
|
while ((match = requirePattern.exec(code)) !== null) {
|
|
32719
|
-
if (match[1])
|
|
32720
|
-
imports.add(match[1]);
|
|
32562
|
+
if (match[1]) imports.add(match[1]);
|
|
32721
32563
|
}
|
|
32722
32564
|
return imports;
|
|
32723
32565
|
}
|
|
32724
32566
|
verifyRelativeImport(importPath, file2, issues) {
|
|
32725
|
-
if (!file2)
|
|
32726
|
-
|
|
32727
|
-
const baseDir = dirname7(join13(this.projectPath, file2));
|
|
32567
|
+
if (!file2) return;
|
|
32568
|
+
const baseDir = dirname6(join12(this.projectPath, file2));
|
|
32728
32569
|
const possibleExtensions = [".ts", ".tsx", ".js", ".jsx", ".json", ""];
|
|
32729
32570
|
const possibleIndexes = ["index.ts", "index.tsx", "index.js", "index.jsx"];
|
|
32730
32571
|
let found = false;
|
|
32731
32572
|
for (const ext of possibleExtensions) {
|
|
32732
|
-
const fullPath =
|
|
32573
|
+
const fullPath = join12(baseDir, importPath + ext);
|
|
32733
32574
|
if (existsSync12(fullPath)) {
|
|
32734
32575
|
found = true;
|
|
32735
32576
|
break;
|
|
32736
32577
|
}
|
|
32737
32578
|
}
|
|
32738
32579
|
if (!found) {
|
|
32739
|
-
const dirPath =
|
|
32580
|
+
const dirPath = join12(baseDir, importPath);
|
|
32740
32581
|
if (existsSync12(dirPath)) {
|
|
32741
32582
|
for (const indexFile of possibleIndexes) {
|
|
32742
|
-
if (existsSync12(
|
|
32583
|
+
if (existsSync12(join12(dirPath, indexFile))) {
|
|
32743
32584
|
found = true;
|
|
32744
32585
|
break;
|
|
32745
32586
|
}
|
|
@@ -32757,7 +32598,7 @@ var CodeVerifier = class {
|
|
|
32757
32598
|
}
|
|
32758
32599
|
verifyPackageImport(importPath, issues, warnings) {
|
|
32759
32600
|
const packageName = this.getPackageName(importPath);
|
|
32760
|
-
const nodeModulePath =
|
|
32601
|
+
const nodeModulePath = join12(this.nodeModulesPath, packageName);
|
|
32761
32602
|
if (!existsSync12(nodeModulePath)) {
|
|
32762
32603
|
issues.push({
|
|
32763
32604
|
import: importPath,
|
|
@@ -32769,7 +32610,7 @@ var CodeVerifier = class {
|
|
|
32769
32610
|
}
|
|
32770
32611
|
if (importPath !== packageName) {
|
|
32771
32612
|
const subpath = importPath.slice(packageName.length + 1);
|
|
32772
|
-
const subpathFull =
|
|
32613
|
+
const subpathFull = join12(nodeModulePath, subpath);
|
|
32773
32614
|
const possibleExtensions = [".js", ".json", ""];
|
|
32774
32615
|
let found = false;
|
|
32775
32616
|
for (const ext of possibleExtensions) {
|
|
@@ -32778,7 +32619,7 @@ var CodeVerifier = class {
|
|
|
32778
32619
|
break;
|
|
32779
32620
|
}
|
|
32780
32621
|
}
|
|
32781
|
-
const pkgJsonPath =
|
|
32622
|
+
const pkgJsonPath = join12(nodeModulePath, "package.json");
|
|
32782
32623
|
if (!found && existsSync12(pkgJsonPath)) {
|
|
32783
32624
|
try {
|
|
32784
32625
|
const pkgJson = JSON.parse(readFileSync9(pkgJsonPath, "utf-8"));
|
|
@@ -32810,8 +32651,7 @@ var CodeVerifier = class {
|
|
|
32810
32651
|
}
|
|
32811
32652
|
getPackageDependencies() {
|
|
32812
32653
|
const deps = /* @__PURE__ */ new Set();
|
|
32813
|
-
if (!this.packageJson)
|
|
32814
|
-
return deps;
|
|
32654
|
+
if (!this.packageJson) return deps;
|
|
32815
32655
|
const allDeps = {
|
|
32816
32656
|
...this.packageJson.dependencies || {},
|
|
32817
32657
|
...this.packageJson.devDependencies || {},
|
|
@@ -32865,10 +32705,8 @@ var CodeVerifier = class {
|
|
|
32865
32705
|
if (highSeverityCount >= 2) {
|
|
32866
32706
|
return "fail";
|
|
32867
32707
|
}
|
|
32868
|
-
if (score >= 70)
|
|
32869
|
-
|
|
32870
|
-
if (score >= 40)
|
|
32871
|
-
return "warning";
|
|
32708
|
+
if (score >= 70) return "pass";
|
|
32709
|
+
if (score >= 40) return "warning";
|
|
32872
32710
|
return "fail";
|
|
32873
32711
|
}
|
|
32874
32712
|
buildSummary(results, verdict) {
|
|
@@ -32901,7 +32739,7 @@ var CodeVerifier = class {
|
|
|
32901
32739
|
};
|
|
32902
32740
|
|
|
32903
32741
|
// src/core/engine.ts
|
|
32904
|
-
var
|
|
32742
|
+
var NeuronLayerEngine = class {
|
|
32905
32743
|
config;
|
|
32906
32744
|
db;
|
|
32907
32745
|
tier1;
|
|
@@ -32936,7 +32774,7 @@ var MemoryLayerEngine = class {
|
|
|
32936
32774
|
if (!existsSync13(config2.dataDir)) {
|
|
32937
32775
|
mkdirSync6(config2.dataDir, { recursive: true });
|
|
32938
32776
|
}
|
|
32939
|
-
const dbPath =
|
|
32777
|
+
const dbPath = join13(config2.dataDir, "neuronlayer.db");
|
|
32940
32778
|
this.db = initializeDatabase(dbPath);
|
|
32941
32779
|
this.tier1 = new Tier1Storage(config2.dataDir);
|
|
32942
32780
|
this.tier2 = new Tier2Storage(this.db);
|
|
@@ -33032,9 +32870,8 @@ var MemoryLayerEngine = class {
|
|
|
33032
32870
|
});
|
|
33033
32871
|
}
|
|
33034
32872
|
async initialize() {
|
|
33035
|
-
if (this.initialized)
|
|
33036
|
-
|
|
33037
|
-
console.error(`Initializing MemoryLayer for: ${this.config.projectPath}`);
|
|
32873
|
+
if (this.initialized) return;
|
|
32874
|
+
console.error(`Initializing NeuronLayer for: ${this.config.projectPath}`);
|
|
33038
32875
|
try {
|
|
33039
32876
|
this.initializationStatus = "indexing";
|
|
33040
32877
|
await this.indexer.performInitialIndex();
|
|
@@ -33054,7 +32891,7 @@ var MemoryLayerEngine = class {
|
|
|
33054
32891
|
this.startBackgroundIntelligence();
|
|
33055
32892
|
this.initialized = true;
|
|
33056
32893
|
this.initializationStatus = "ready";
|
|
33057
|
-
console.error("
|
|
32894
|
+
console.error("NeuronLayer initialized");
|
|
33058
32895
|
} catch (error2) {
|
|
33059
32896
|
this.initializationStatus = "error";
|
|
33060
32897
|
throw error2;
|
|
@@ -33135,7 +32972,7 @@ var MemoryLayerEngine = class {
|
|
|
33135
32972
|
return this.tier2.searchDecisions(embedding, limit);
|
|
33136
32973
|
}
|
|
33137
32974
|
async getFileContext(filePath) {
|
|
33138
|
-
const absolutePath =
|
|
32975
|
+
const absolutePath = join13(this.config.projectPath, filePath);
|
|
33139
32976
|
if (!existsSync13(absolutePath)) {
|
|
33140
32977
|
return null;
|
|
33141
32978
|
}
|
|
@@ -33222,7 +33059,7 @@ ${decision.description}`;
|
|
|
33222
33059
|
const commonDirs = ["src", "lib", "app", "pages", "components", "api", "server", "client", "core"];
|
|
33223
33060
|
const found = [];
|
|
33224
33061
|
for (const dir of commonDirs) {
|
|
33225
|
-
if (existsSync13(
|
|
33062
|
+
if (existsSync13(join13(this.config.projectPath, dir))) {
|
|
33226
33063
|
found.push(dir);
|
|
33227
33064
|
}
|
|
33228
33065
|
}
|
|
@@ -33230,7 +33067,7 @@ ${decision.description}`;
|
|
|
33230
33067
|
}
|
|
33231
33068
|
detectDependencies() {
|
|
33232
33069
|
const deps = [];
|
|
33233
|
-
const packageJsonPath =
|
|
33070
|
+
const packageJsonPath = join13(this.config.projectPath, "package.json");
|
|
33234
33071
|
if (existsSync13(packageJsonPath)) {
|
|
33235
33072
|
try {
|
|
33236
33073
|
const pkg = JSON.parse(readFileSync10(packageJsonPath, "utf-8"));
|
|
@@ -33242,7 +33079,7 @@ ${decision.description}`;
|
|
|
33242
33079
|
} catch {
|
|
33243
33080
|
}
|
|
33244
33081
|
}
|
|
33245
|
-
const requirementsPath =
|
|
33082
|
+
const requirementsPath = join13(this.config.projectPath, "requirements.txt");
|
|
33246
33083
|
if (existsSync13(requirementsPath)) {
|
|
33247
33084
|
try {
|
|
33248
33085
|
const content = readFileSync10(requirementsPath, "utf-8");
|
|
@@ -33299,7 +33136,7 @@ ${decision.description}`;
|
|
|
33299
33136
|
let fetched = 0;
|
|
33300
33137
|
for (const filePath of predicted) {
|
|
33301
33138
|
if (!this.learningEngine.isInHotCache(filePath)) {
|
|
33302
|
-
const absolutePath =
|
|
33139
|
+
const absolutePath = join13(this.config.projectPath, filePath);
|
|
33303
33140
|
if (existsSync13(absolutePath)) {
|
|
33304
33141
|
try {
|
|
33305
33142
|
const content = readFileSync10(absolutePath, "utf-8");
|
|
@@ -33315,8 +33152,7 @@ ${decision.description}`;
|
|
|
33315
33152
|
// Phase 3: Get file summary (compressed representation)
|
|
33316
33153
|
getFileSummary(filePath) {
|
|
33317
33154
|
const file2 = this.tier2.getFile(filePath);
|
|
33318
|
-
if (!file2)
|
|
33319
|
-
return null;
|
|
33155
|
+
if (!file2) return null;
|
|
33320
33156
|
const cached2 = this.summarizer.getSummary(file2.id);
|
|
33321
33157
|
if (cached2 && !this.summarizer.needsRegeneration(file2.id, file2.lastModified)) {
|
|
33322
33158
|
return cached2.summary;
|
|
@@ -33903,7 +33739,7 @@ ${description}`;
|
|
|
33903
33739
|
return this.codeVerifier.checkDependencies(code);
|
|
33904
33740
|
}
|
|
33905
33741
|
shutdown() {
|
|
33906
|
-
console.error("Shutting down
|
|
33742
|
+
console.error("Shutting down NeuronLayer...");
|
|
33907
33743
|
if (this.backgroundInterval) {
|
|
33908
33744
|
clearInterval(this.backgroundInterval);
|
|
33909
33745
|
this.backgroundInterval = null;
|
|
@@ -33989,8 +33825,7 @@ function isErrorMessage(str) {
|
|
|
33989
33825
|
return errorPatterns.some((pattern) => pattern.test(str));
|
|
33990
33826
|
}
|
|
33991
33827
|
function detectQueryAction(input) {
|
|
33992
|
-
if (input.action)
|
|
33993
|
-
return input.action;
|
|
33828
|
+
if (input.action) return input.action;
|
|
33994
33829
|
if (input.code && input.code.length > 20) {
|
|
33995
33830
|
if (containsCode(input.code)) {
|
|
33996
33831
|
return "confidence";
|
|
@@ -34011,10 +33846,8 @@ function detectQueryAction(input) {
|
|
|
34011
33846
|
return "context";
|
|
34012
33847
|
}
|
|
34013
33848
|
function detectRecordType(input) {
|
|
34014
|
-
if (input.type)
|
|
34015
|
-
|
|
34016
|
-
if (input.action)
|
|
34017
|
-
return input.action;
|
|
33849
|
+
if (input.type) return input.type;
|
|
33850
|
+
if (input.action) return input.action;
|
|
34018
33851
|
if (input.pattern_id && input.code) {
|
|
34019
33852
|
return "example";
|
|
34020
33853
|
}
|
|
@@ -34081,8 +33914,7 @@ function validateRecordInput(input) {
|
|
|
34081
33914
|
return { valid: true, type };
|
|
34082
33915
|
}
|
|
34083
33916
|
function detectReviewAction(input) {
|
|
34084
|
-
if (input.action)
|
|
34085
|
-
return input.action;
|
|
33917
|
+
if (input.action) return input.action;
|
|
34086
33918
|
if (input.error && isErrorMessage(input.error)) {
|
|
34087
33919
|
return "bugs";
|
|
34088
33920
|
}
|
|
@@ -34119,8 +33951,7 @@ function getReviewChecks(input) {
|
|
|
34119
33951
|
};
|
|
34120
33952
|
}
|
|
34121
33953
|
function detectStatusAction(input) {
|
|
34122
|
-
if (input.action)
|
|
34123
|
-
return input.action;
|
|
33954
|
+
if (input.action) return input.action;
|
|
34124
33955
|
if (input.since) {
|
|
34125
33956
|
if (input.author || input.file) {
|
|
34126
33957
|
return "changed";
|
|
@@ -34214,10 +34045,8 @@ function calculateRiskScore(patternResult, conflicts, testResult, confidence) {
|
|
|
34214
34045
|
return Math.min(100, riskScore);
|
|
34215
34046
|
}
|
|
34216
34047
|
function getVerdict(riskScore) {
|
|
34217
|
-
if (riskScore >= 70)
|
|
34218
|
-
|
|
34219
|
-
if (riskScore >= 30)
|
|
34220
|
-
return "warning";
|
|
34048
|
+
if (riskScore >= 70) return "reject";
|
|
34049
|
+
if (riskScore >= 30) return "warning";
|
|
34221
34050
|
return "approve";
|
|
34222
34051
|
}
|
|
34223
34052
|
function aggregateReviewResults(patternResult, conflicts, confidence, existingAlternatives, testResult, sourcesUsed) {
|
|
@@ -35593,12 +35422,9 @@ async function handleMemoryVerify(engine, input) {
|
|
|
35593
35422
|
if (runAll || checks.includes("imports") || checks.includes("security") || checks.includes("dependencies")) {
|
|
35594
35423
|
sourcesUsed.push("code_verifier");
|
|
35595
35424
|
const verifierChecks = [];
|
|
35596
|
-
if (runAll || checks.includes("imports"))
|
|
35597
|
-
|
|
35598
|
-
if (runAll || checks.includes("
|
|
35599
|
-
verifierChecks.push("security");
|
|
35600
|
-
if (runAll || checks.includes("dependencies"))
|
|
35601
|
-
verifierChecks.push("dependencies");
|
|
35425
|
+
if (runAll || checks.includes("imports")) verifierChecks.push("imports");
|
|
35426
|
+
if (runAll || checks.includes("security")) verifierChecks.push("security");
|
|
35427
|
+
if (runAll || checks.includes("dependencies")) verifierChecks.push("dependencies");
|
|
35602
35428
|
const verification = await engine.verifyCode(input.code, input.file, verifierChecks);
|
|
35603
35429
|
if (verification.imports) {
|
|
35604
35430
|
response.imports = {
|
|
@@ -35710,10 +35536,8 @@ function calculateVerdict(response) {
|
|
|
35710
35536
|
if (hallucinatedImports >= 2) {
|
|
35711
35537
|
return "fail";
|
|
35712
35538
|
}
|
|
35713
|
-
if (response.score >= 70)
|
|
35714
|
-
|
|
35715
|
-
if (response.score >= 40)
|
|
35716
|
-
return "warning";
|
|
35539
|
+
if (response.score >= 70) return "pass";
|
|
35540
|
+
if (response.score >= 40) return "warning";
|
|
35717
35541
|
return "fail";
|
|
35718
35542
|
}
|
|
35719
35543
|
function buildSummary(response) {
|
|
@@ -35740,12 +35564,9 @@ function buildSummary(response) {
|
|
|
35740
35564
|
const high = response.security.issues.filter((i) => i.severity === "high").length;
|
|
35741
35565
|
const medium = response.security.issues.filter((i) => i.severity === "medium").length;
|
|
35742
35566
|
const secParts = [];
|
|
35743
|
-
if (critical > 0)
|
|
35744
|
-
|
|
35745
|
-
if (
|
|
35746
|
-
secParts.push(`${high} high`);
|
|
35747
|
-
if (medium > 0)
|
|
35748
|
-
secParts.push(`${medium} medium`);
|
|
35567
|
+
if (critical > 0) secParts.push(`${critical} critical`);
|
|
35568
|
+
if (high > 0) secParts.push(`${high} high`);
|
|
35569
|
+
if (medium > 0) secParts.push(`${medium} medium`);
|
|
35749
35570
|
parts.push(`Security: ${secParts.join(", ")}`);
|
|
35750
35571
|
}
|
|
35751
35572
|
}
|
|
@@ -36136,7 +35957,7 @@ var standaloneDefinitions = [
|
|
|
36136
35957
|
},
|
|
36137
35958
|
{
|
|
36138
35959
|
name: "discover_projects",
|
|
36139
|
-
description: "Find git repositories on the system. Use when user wants to add/register a project to
|
|
35960
|
+
description: "Find git repositories on the system. Use when user wants to add/register a project to NeuronLayer.",
|
|
36140
35961
|
inputSchema: {
|
|
36141
35962
|
type: "object",
|
|
36142
35963
|
properties: {}
|
|
@@ -36337,6 +36158,7 @@ async function handleToolCall(engine, toolName, args) {
|
|
|
36337
36158
|
query
|
|
36338
36159
|
};
|
|
36339
36160
|
}
|
|
36161
|
+
// Phase 4: Multi-project tools
|
|
36340
36162
|
case "list_projects": {
|
|
36341
36163
|
const projects = engine.listProjects();
|
|
36342
36164
|
const activeProject = engine.getActiveProject();
|
|
@@ -36459,6 +36281,7 @@ async function handleToolCall(engine, toolName, args) {
|
|
|
36459
36281
|
}))
|
|
36460
36282
|
};
|
|
36461
36283
|
}
|
|
36284
|
+
// Phase 5: Active Feature Context tools
|
|
36462
36285
|
case "get_active_context": {
|
|
36463
36286
|
const hotContext = engine.getHotContext();
|
|
36464
36287
|
const summary = engine.getActiveContextSummary();
|
|
@@ -36544,6 +36367,7 @@ async function handleToolCall(engine, toolName, args) {
|
|
|
36544
36367
|
} : null
|
|
36545
36368
|
};
|
|
36546
36369
|
}
|
|
36370
|
+
// Phase 6: Living Documentation tools
|
|
36547
36371
|
case "generate_docs": {
|
|
36548
36372
|
const path = args.path;
|
|
36549
36373
|
const type = args.type || (path ? "component" : "architecture");
|
|
@@ -36765,6 +36589,7 @@ async function handleToolCall(engine, toolName, args) {
|
|
|
36765
36589
|
message: items.length === 0 ? "All exported code is documented!" : `Found ${items.length} undocumented items across ${byFile.size} files`
|
|
36766
36590
|
};
|
|
36767
36591
|
}
|
|
36592
|
+
// Phase 7: Context Rot Prevention tools
|
|
36768
36593
|
case "get_context_health": {
|
|
36769
36594
|
const includeHistory = args.include_history;
|
|
36770
36595
|
const health = engine.getContextHealth();
|
|
@@ -36857,6 +36682,7 @@ async function handleToolCall(engine, toolName, args) {
|
|
|
36857
36682
|
message: items.length === 0 ? "No critical context marked. Consider marking important decisions and requirements." : `${items.length} critical items will be preserved during compaction`
|
|
36858
36683
|
};
|
|
36859
36684
|
}
|
|
36685
|
+
// Phase 8: Confidence Scoring tools
|
|
36860
36686
|
case "get_confidence": {
|
|
36861
36687
|
const code = args.code;
|
|
36862
36688
|
const context = args.context;
|
|
@@ -36966,6 +36792,7 @@ async function handleToolCall(engine, toolName, args) {
|
|
|
36966
36792
|
message: result.hasConflicts ? `Found ${result.conflicts.length} conflict(s) with past decisions` : "No conflicts with past decisions"
|
|
36967
36793
|
};
|
|
36968
36794
|
}
|
|
36795
|
+
// Phase 9: Change Intelligence tools
|
|
36969
36796
|
case "what_changed": {
|
|
36970
36797
|
const since = args.since;
|
|
36971
36798
|
const file2 = args.file;
|
|
@@ -37067,6 +36894,7 @@ async function handleToolCall(engine, toolName, args) {
|
|
|
37067
36894
|
message: suggestions.length === 0 ? "No fix suggestions available" : `Found ${suggestions.length} fix suggestion(s)`
|
|
37068
36895
|
};
|
|
37069
36896
|
}
|
|
36897
|
+
// Phase 10: Architecture Enforcement tools
|
|
37070
36898
|
case "validate_pattern": {
|
|
37071
36899
|
const code = args.code;
|
|
37072
36900
|
const type = args.type;
|
|
@@ -37216,6 +37044,7 @@ async function handleToolCall(engine, toolName, args) {
|
|
|
37216
37044
|
message: `${stats.patterns.total} patterns learned, ${stats.functions.total} functions indexed`
|
|
37217
37045
|
};
|
|
37218
37046
|
}
|
|
37047
|
+
// Phase 11: Test-Aware Suggestions tools
|
|
37219
37048
|
case "get_related_tests": {
|
|
37220
37049
|
const file2 = args.file;
|
|
37221
37050
|
const fn = args.function;
|
|
@@ -37323,13 +37152,13 @@ async function handleToolCall(engine, toolName, args) {
|
|
|
37323
37152
|
// src/server/resources.ts
|
|
37324
37153
|
var resourceDefinitions = [
|
|
37325
37154
|
{
|
|
37326
|
-
uri: "
|
|
37155
|
+
uri: "neuronlayer://decisions/recent",
|
|
37327
37156
|
name: "Recent Decisions",
|
|
37328
37157
|
description: "Last 10 architectural decisions made in this project",
|
|
37329
37158
|
mimeType: "application/json"
|
|
37330
37159
|
},
|
|
37331
37160
|
{
|
|
37332
|
-
uri: "
|
|
37161
|
+
uri: "neuronlayer://project/overview",
|
|
37333
37162
|
name: "Project Overview",
|
|
37334
37163
|
description: "High-level project summary including languages, files, and structure",
|
|
37335
37164
|
mimeType: "text/markdown"
|
|
@@ -37337,7 +37166,7 @@ var resourceDefinitions = [
|
|
|
37337
37166
|
];
|
|
37338
37167
|
async function handleResourceRead(engine, uri) {
|
|
37339
37168
|
switch (uri) {
|
|
37340
|
-
case "
|
|
37169
|
+
case "neuronlayer://decisions/recent": {
|
|
37341
37170
|
const decisions = engine.getRecentDecisions(10);
|
|
37342
37171
|
const contents = JSON.stringify(
|
|
37343
37172
|
decisions.map((d) => ({
|
|
@@ -37353,7 +37182,7 @@ async function handleResourceRead(engine, uri) {
|
|
|
37353
37182
|
);
|
|
37354
37183
|
return { contents, mimeType: "application/json" };
|
|
37355
37184
|
}
|
|
37356
|
-
case "
|
|
37185
|
+
case "neuronlayer://project/overview": {
|
|
37357
37186
|
const summary = engine.getProjectSummary();
|
|
37358
37187
|
const markdown = `# ${summary.name}
|
|
37359
37188
|
|
|
@@ -37393,10 +37222,10 @@ var MCPServer = class {
|
|
|
37393
37222
|
server;
|
|
37394
37223
|
engine;
|
|
37395
37224
|
constructor(config2) {
|
|
37396
|
-
this.engine = new
|
|
37225
|
+
this.engine = new NeuronLayerEngine(config2);
|
|
37397
37226
|
this.server = new Server(
|
|
37398
37227
|
{
|
|
37399
|
-
name: "
|
|
37228
|
+
name: "neuronlayer",
|
|
37400
37229
|
version: "0.1.0"
|
|
37401
37230
|
},
|
|
37402
37231
|
{
|
|
@@ -37480,7 +37309,7 @@ var MCPServer = class {
|
|
|
37480
37309
|
async start() {
|
|
37481
37310
|
const transport = new StdioServerTransport();
|
|
37482
37311
|
await this.server.connect(transport);
|
|
37483
|
-
console.error("
|
|
37312
|
+
console.error("NeuronLayer MCP server started");
|
|
37484
37313
|
this.engine.initialize().catch((err) => {
|
|
37485
37314
|
console.error("Engine initialization error:", err);
|
|
37486
37315
|
});
|
|
@@ -37499,19 +37328,19 @@ var MCPServer = class {
|
|
|
37499
37328
|
};
|
|
37500
37329
|
|
|
37501
37330
|
// src/utils/config.ts
|
|
37502
|
-
import { join as
|
|
37331
|
+
import { join as join14, resolve as resolve2 } from "path";
|
|
37503
37332
|
function getDefaultConfig(projectPath) {
|
|
37504
37333
|
const normalizedPath = resolve2(projectPath);
|
|
37505
37334
|
return {
|
|
37506
37335
|
projectPath: normalizedPath,
|
|
37507
37336
|
// Store in project directory (standard practice like .git/, .vscode/)
|
|
37508
|
-
dataDir:
|
|
37337
|
+
dataDir: join14(normalizedPath, ".neuronlayer"),
|
|
37509
37338
|
maxTokens: 6e3,
|
|
37510
37339
|
embeddingModel: "Xenova/all-MiniLM-L6-v2",
|
|
37511
37340
|
// Fallback model, faster and smaller
|
|
37512
37341
|
watchIgnore: [
|
|
37513
|
-
// =====
|
|
37514
|
-
"**/.
|
|
37342
|
+
// ===== NeuronLayer =====
|
|
37343
|
+
"**/.neuronlayer/**",
|
|
37515
37344
|
// ===== Version Control =====
|
|
37516
37345
|
"**/.git/**",
|
|
37517
37346
|
"**/.svn/**",
|
|
@@ -37667,8 +37496,9 @@ function parseArgs(args) {
|
|
|
37667
37496
|
}
|
|
37668
37497
|
|
|
37669
37498
|
// src/cli/commands.ts
|
|
37670
|
-
import { join as
|
|
37671
|
-
import { existsSync as existsSync14 } from "fs";
|
|
37499
|
+
import { join as join15 } from "path";
|
|
37500
|
+
import { existsSync as existsSync14, readFileSync as readFileSync11, writeFileSync as writeFileSync5, mkdirSync as mkdirSync7 } from "fs";
|
|
37501
|
+
import { homedir as homedir2 } from "os";
|
|
37672
37502
|
var projectManager = new ProjectManager();
|
|
37673
37503
|
function listProjects() {
|
|
37674
37504
|
const projects = projectManager.listProjects();
|
|
@@ -37676,7 +37506,7 @@ function listProjects() {
|
|
|
37676
37506
|
if (projects.length === 0) {
|
|
37677
37507
|
return {
|
|
37678
37508
|
success: true,
|
|
37679
|
-
message: 'No projects registered. Use "
|
|
37509
|
+
message: 'No projects registered. Use "neuronlayer projects add <path>" to add one.'
|
|
37680
37510
|
};
|
|
37681
37511
|
}
|
|
37682
37512
|
const lines = ["Registered Projects:", ""];
|
|
@@ -37756,7 +37586,7 @@ function discoverProjects() {
|
|
|
37756
37586
|
lines.push(` ${path}`);
|
|
37757
37587
|
lines.push("");
|
|
37758
37588
|
}
|
|
37759
|
-
lines.push('Use "
|
|
37589
|
+
lines.push('Use "neuronlayer projects add <path>" to register a project.');
|
|
37760
37590
|
return {
|
|
37761
37591
|
success: true,
|
|
37762
37592
|
message: lines.join("\n"),
|
|
@@ -37770,7 +37600,7 @@ function exportDecisions(projectPath, options = {}) {
|
|
|
37770
37600
|
if (!activeProject) {
|
|
37771
37601
|
return {
|
|
37772
37602
|
success: false,
|
|
37773
|
-
message: 'No project specified and no active project. Use "
|
|
37603
|
+
message: 'No project specified and no active project. Use "neuronlayer projects switch <id>" first.'
|
|
37774
37604
|
};
|
|
37775
37605
|
}
|
|
37776
37606
|
targetPath = activeProject.path;
|
|
@@ -37779,10 +37609,10 @@ function exportDecisions(projectPath, options = {}) {
|
|
|
37779
37609
|
if (!projectInfo) {
|
|
37780
37610
|
return {
|
|
37781
37611
|
success: false,
|
|
37782
|
-
message: `Project not registered: ${targetPath}. Use "
|
|
37612
|
+
message: `Project not registered: ${targetPath}. Use "neuronlayer projects add ${targetPath}" first.`
|
|
37783
37613
|
};
|
|
37784
37614
|
}
|
|
37785
|
-
const dbPath =
|
|
37615
|
+
const dbPath = join15(projectInfo.dataDir, "neuronlayer.db");
|
|
37786
37616
|
if (!existsSync14(dbPath)) {
|
|
37787
37617
|
return {
|
|
37788
37618
|
success: false,
|
|
@@ -37807,7 +37637,7 @@ function exportDecisions(projectPath, options = {}) {
|
|
|
37807
37637
|
});
|
|
37808
37638
|
return {
|
|
37809
37639
|
success: true,
|
|
37810
|
-
message: `Exported ${exportedFiles.length} ADR files to ${options.outputDir ||
|
|
37640
|
+
message: `Exported ${exportedFiles.length} ADR files to ${options.outputDir || join15(targetPath, "docs", "decisions")}`,
|
|
37811
37641
|
data: exportedFiles
|
|
37812
37642
|
};
|
|
37813
37643
|
}
|
|
@@ -37821,7 +37651,7 @@ function showProject(projectId) {
|
|
|
37821
37651
|
if (!project) {
|
|
37822
37652
|
return {
|
|
37823
37653
|
success: false,
|
|
37824
|
-
message: projectId ? `Project not found: ${projectId}` : 'No active project. Use "
|
|
37654
|
+
message: projectId ? `Project not found: ${projectId}` : 'No active project. Use "neuronlayer projects switch <id>" first.'
|
|
37825
37655
|
};
|
|
37826
37656
|
}
|
|
37827
37657
|
const lines = [
|
|
@@ -37840,14 +37670,103 @@ function showProject(projectId) {
|
|
|
37840
37670
|
data: project
|
|
37841
37671
|
};
|
|
37842
37672
|
}
|
|
37673
|
+
function configureMCPClient(clientName, configPath, serverName, projectPath) {
|
|
37674
|
+
let config2 = { mcpServers: {} };
|
|
37675
|
+
try {
|
|
37676
|
+
if (existsSync14(configPath)) {
|
|
37677
|
+
const content = readFileSync11(configPath, "utf-8");
|
|
37678
|
+
config2 = JSON.parse(content);
|
|
37679
|
+
} else {
|
|
37680
|
+
const sep = process.platform === "win32" ? "\\" : "/";
|
|
37681
|
+
const configDir = configPath.substring(0, configPath.lastIndexOf(sep));
|
|
37682
|
+
mkdirSync7(configDir, { recursive: true });
|
|
37683
|
+
}
|
|
37684
|
+
} catch {
|
|
37685
|
+
}
|
|
37686
|
+
if (!config2.mcpServers) {
|
|
37687
|
+
config2.mcpServers = {};
|
|
37688
|
+
}
|
|
37689
|
+
config2.mcpServers[serverName] = {
|
|
37690
|
+
command: "npx",
|
|
37691
|
+
args: ["-y", "neuronlayer", "--project", projectPath]
|
|
37692
|
+
};
|
|
37693
|
+
try {
|
|
37694
|
+
writeFileSync5(configPath, JSON.stringify(config2, null, 2));
|
|
37695
|
+
return { success: true, message: `${clientName}: ${configPath}` };
|
|
37696
|
+
} catch (err) {
|
|
37697
|
+
return { success: false, message: `${clientName}: Failed - ${err instanceof Error ? err.message : String(err)}` };
|
|
37698
|
+
}
|
|
37699
|
+
}
|
|
37700
|
+
function initProject(projectPath) {
|
|
37701
|
+
const targetPath = projectPath || process.cwd();
|
|
37702
|
+
const addResult = addProject(targetPath);
|
|
37703
|
+
if (!addResult.success) {
|
|
37704
|
+
return addResult;
|
|
37705
|
+
}
|
|
37706
|
+
const projectInfo = addResult.data;
|
|
37707
|
+
const serverName = `neuronlayer-${projectInfo.name.toLowerCase().replace(/[^a-z0-9]/g, "-")}`;
|
|
37708
|
+
const platform = process.platform;
|
|
37709
|
+
const configuredClients = [];
|
|
37710
|
+
const failedClients = [];
|
|
37711
|
+
let claudeConfigPath;
|
|
37712
|
+
if (platform === "win32") {
|
|
37713
|
+
claudeConfigPath = join15(homedir2(), "AppData", "Roaming", "Claude", "claude_desktop_config.json");
|
|
37714
|
+
} else if (platform === "darwin") {
|
|
37715
|
+
claudeConfigPath = join15(homedir2(), "Library", "Application Support", "Claude", "claude_desktop_config.json");
|
|
37716
|
+
} else {
|
|
37717
|
+
claudeConfigPath = join15(homedir2(), ".config", "claude", "claude_desktop_config.json");
|
|
37718
|
+
}
|
|
37719
|
+
const claudeResult = configureMCPClient("Claude Desktop", claudeConfigPath, serverName, targetPath);
|
|
37720
|
+
if (claudeResult.success) {
|
|
37721
|
+
configuredClients.push(claudeResult.message);
|
|
37722
|
+
} else {
|
|
37723
|
+
failedClients.push(claudeResult.message);
|
|
37724
|
+
}
|
|
37725
|
+
const openCodeConfigPath = join15(homedir2(), ".opencode", "config.json");
|
|
37726
|
+
const openCodeResult = configureMCPClient("OpenCode", openCodeConfigPath, serverName, targetPath);
|
|
37727
|
+
if (openCodeResult.success) {
|
|
37728
|
+
configuredClients.push(openCodeResult.message);
|
|
37729
|
+
} else {
|
|
37730
|
+
failedClients.push(openCodeResult.message);
|
|
37731
|
+
}
|
|
37732
|
+
const claudeCodeConfigPath = join15(homedir2(), ".claude.json");
|
|
37733
|
+
const claudeCodeResult = configureMCPClient("Claude Code", claudeCodeConfigPath, serverName, targetPath);
|
|
37734
|
+
if (claudeCodeResult.success) {
|
|
37735
|
+
configuredClients.push(claudeCodeResult.message);
|
|
37736
|
+
}
|
|
37737
|
+
let message = `
|
|
37738
|
+
NeuronLayer initialized!
|
|
37739
|
+
|
|
37740
|
+
Project: ${projectInfo.name}
|
|
37741
|
+
Path: ${targetPath}
|
|
37742
|
+
Data: ${projectInfo.dataDir}
|
|
37743
|
+
|
|
37744
|
+
Configured MCP Clients:
|
|
37745
|
+
${configuredClients.map((c) => " \u2713 " + c).join("\n")}
|
|
37746
|
+
`;
|
|
37747
|
+
if (failedClients.length > 0) {
|
|
37748
|
+
message += `
|
|
37749
|
+
Failed:
|
|
37750
|
+
${failedClients.map((c) => " \u2717 " + c).join("\n")}`;
|
|
37751
|
+
}
|
|
37752
|
+
message += `
|
|
37753
|
+
|
|
37754
|
+
Restart your AI tools to activate.`;
|
|
37755
|
+
return {
|
|
37756
|
+
success: true,
|
|
37757
|
+
message: message.trim(),
|
|
37758
|
+
data: { projectInfo, serverName, configuredClients }
|
|
37759
|
+
};
|
|
37760
|
+
}
|
|
37843
37761
|
function printHelp() {
|
|
37844
37762
|
console.log(`
|
|
37845
|
-
|
|
37763
|
+
NeuronLayer CLI - Persistent Memory for AI Coding Assistants
|
|
37846
37764
|
|
|
37847
37765
|
USAGE:
|
|
37848
|
-
|
|
37766
|
+
neuronlayer [command] [options]
|
|
37849
37767
|
|
|
37850
37768
|
COMMANDS:
|
|
37769
|
+
init [path] Initialize project + auto-configure Claude Desktop
|
|
37851
37770
|
(no command) Start MCP server for Claude Desktop
|
|
37852
37771
|
projects list List all registered projects
|
|
37853
37772
|
projects add <path> Add a project to the registry
|
|
@@ -37864,25 +37783,29 @@ OPTIONS:
|
|
|
37864
37783
|
--format <type> ADR format: madr, nygard, simple
|
|
37865
37784
|
|
|
37866
37785
|
EXAMPLES:
|
|
37786
|
+
# Quick setup (auto-configures Claude Desktop)
|
|
37787
|
+
cd /path/to/project
|
|
37788
|
+
neuronlayer init
|
|
37789
|
+
|
|
37867
37790
|
# Start MCP server
|
|
37868
|
-
|
|
37791
|
+
neuronlayer --project /path/to/project
|
|
37869
37792
|
|
|
37870
37793
|
# List all projects
|
|
37871
|
-
|
|
37794
|
+
neuronlayer projects list
|
|
37872
37795
|
|
|
37873
37796
|
# Add a new project
|
|
37874
|
-
|
|
37797
|
+
neuronlayer projects add /path/to/my-project
|
|
37875
37798
|
|
|
37876
37799
|
# Switch active project
|
|
37877
|
-
|
|
37800
|
+
neuronlayer projects switch abc123
|
|
37878
37801
|
|
|
37879
37802
|
# Export decisions to ADR files
|
|
37880
|
-
|
|
37803
|
+
neuronlayer export --format madr
|
|
37881
37804
|
|
|
37882
37805
|
# Discover projects
|
|
37883
|
-
|
|
37806
|
+
neuronlayer projects discover
|
|
37884
37807
|
|
|
37885
|
-
For more information, visit: https://github.com/
|
|
37808
|
+
For more information, visit: https://github.com/abhisavakar/neuronlayer
|
|
37886
37809
|
`);
|
|
37887
37810
|
}
|
|
37888
37811
|
function executeCLI(args) {
|
|
@@ -37894,6 +37817,13 @@ function executeCLI(args) {
|
|
|
37894
37817
|
case "-h":
|
|
37895
37818
|
printHelp();
|
|
37896
37819
|
break;
|
|
37820
|
+
case "init": {
|
|
37821
|
+
const path = args[1];
|
|
37822
|
+
const result = initProject(path);
|
|
37823
|
+
console.log(result.message);
|
|
37824
|
+
if (!result.success) process.exit(1);
|
|
37825
|
+
break;
|
|
37826
|
+
}
|
|
37897
37827
|
case "projects": {
|
|
37898
37828
|
switch (subcommand) {
|
|
37899
37829
|
case "list":
|
|
@@ -37903,47 +37833,43 @@ function executeCLI(args) {
|
|
|
37903
37833
|
const path = args[2];
|
|
37904
37834
|
if (!path) {
|
|
37905
37835
|
console.error("Error: Project path required.");
|
|
37906
|
-
console.error("Usage:
|
|
37836
|
+
console.error("Usage: neuronlayer projects add <path>");
|
|
37907
37837
|
process.exit(1);
|
|
37908
37838
|
}
|
|
37909
37839
|
const result = addProject(path);
|
|
37910
37840
|
console.log(result.message);
|
|
37911
|
-
if (!result.success)
|
|
37912
|
-
process.exit(1);
|
|
37841
|
+
if (!result.success) process.exit(1);
|
|
37913
37842
|
break;
|
|
37914
37843
|
}
|
|
37915
37844
|
case "remove": {
|
|
37916
37845
|
const id = args[2];
|
|
37917
37846
|
if (!id) {
|
|
37918
37847
|
console.error("Error: Project ID required.");
|
|
37919
|
-
console.error("Usage:
|
|
37848
|
+
console.error("Usage: neuronlayer projects remove <id>");
|
|
37920
37849
|
process.exit(1);
|
|
37921
37850
|
}
|
|
37922
37851
|
const result = removeProject(id);
|
|
37923
37852
|
console.log(result.message);
|
|
37924
|
-
if (!result.success)
|
|
37925
|
-
process.exit(1);
|
|
37853
|
+
if (!result.success) process.exit(1);
|
|
37926
37854
|
break;
|
|
37927
37855
|
}
|
|
37928
37856
|
case "switch": {
|
|
37929
37857
|
const id = args[2];
|
|
37930
37858
|
if (!id) {
|
|
37931
37859
|
console.error("Error: Project ID required.");
|
|
37932
|
-
console.error("Usage:
|
|
37860
|
+
console.error("Usage: neuronlayer projects switch <id>");
|
|
37933
37861
|
process.exit(1);
|
|
37934
37862
|
}
|
|
37935
37863
|
const result = switchProject(id);
|
|
37936
37864
|
console.log(result.message);
|
|
37937
|
-
if (!result.success)
|
|
37938
|
-
process.exit(1);
|
|
37865
|
+
if (!result.success) process.exit(1);
|
|
37939
37866
|
break;
|
|
37940
37867
|
}
|
|
37941
37868
|
case "show": {
|
|
37942
37869
|
const id = args[2];
|
|
37943
37870
|
const result = showProject(id);
|
|
37944
37871
|
console.log(result.message);
|
|
37945
|
-
if (!result.success)
|
|
37946
|
-
process.exit(1);
|
|
37872
|
+
if (!result.success) process.exit(1);
|
|
37947
37873
|
break;
|
|
37948
37874
|
}
|
|
37949
37875
|
case "discover":
|
|
@@ -37972,8 +37898,7 @@ function executeCLI(args) {
|
|
|
37972
37898
|
}
|
|
37973
37899
|
const result = exportDecisions(void 0, { outputDir, format });
|
|
37974
37900
|
console.log(result.message);
|
|
37975
|
-
if (!result.success)
|
|
37976
|
-
process.exit(1);
|
|
37901
|
+
if (!result.success) process.exit(1);
|
|
37977
37902
|
break;
|
|
37978
37903
|
}
|
|
37979
37904
|
default:
|
|
@@ -37986,26 +37911,26 @@ function executeCLI(args) {
|
|
|
37986
37911
|
async function main() {
|
|
37987
37912
|
const args = process.argv.slice(2);
|
|
37988
37913
|
const firstArg = args[0];
|
|
37989
|
-
const cliCommands = ["projects", "export", "help", "--help", "-h"];
|
|
37914
|
+
const cliCommands = ["init", "projects", "export", "help", "--help", "-h"];
|
|
37990
37915
|
if (firstArg && cliCommands.includes(firstArg)) {
|
|
37991
37916
|
executeCLI(args);
|
|
37992
37917
|
return;
|
|
37993
37918
|
}
|
|
37994
37919
|
if (args.length === 0 && process.stdin.isTTY) {
|
|
37995
37920
|
printHelp();
|
|
37996
|
-
console.log("\nTo start as MCP server, use:
|
|
37921
|
+
console.log("\nTo start as MCP server, use: neuronlayer --project <path>\n");
|
|
37997
37922
|
return;
|
|
37998
37923
|
}
|
|
37999
37924
|
const { projectPath } = parseArgs(args);
|
|
38000
37925
|
const config2 = getDefaultConfig(projectPath);
|
|
38001
|
-
console.error("
|
|
37926
|
+
console.error("NeuronLayer starting...");
|
|
38002
37927
|
console.error(`Project: ${config2.projectPath}`);
|
|
38003
37928
|
console.error(`Data directory: ${config2.dataDir}`);
|
|
38004
37929
|
const server = new MCPServer(config2);
|
|
38005
37930
|
try {
|
|
38006
37931
|
await server.start();
|
|
38007
37932
|
} catch (error2) {
|
|
38008
|
-
console.error("Failed to start
|
|
37933
|
+
console.error("Failed to start NeuronLayer:", error2);
|
|
38009
37934
|
process.exit(1);
|
|
38010
37935
|
}
|
|
38011
37936
|
}
|