agentic-qe 3.6.15 → 3.6.17
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/.claude/agents/v3/qe-queen-coordinator.md +9 -3
- package/.claude/skills/skills-manifest.json +1 -1
- package/package.json +1 -1
- package/v3/CHANGELOG.md +45 -0
- package/v3/assets/agents/v3/qe-queen-coordinator.md +9 -3
- package/v3/dist/cli/bundle.js +1944 -685
- package/v3/dist/cli/commands/sync.d.ts.map +1 -1
- package/v3/dist/cli/commands/sync.js +83 -1
- package/v3/dist/cli/commands/sync.js.map +1 -1
- package/v3/dist/cli/completions/index.d.ts +1 -1
- package/v3/dist/cli/completions/index.d.ts.map +1 -1
- package/v3/dist/cli/completions/index.js +1 -1
- package/v3/dist/cli/completions/index.js.map +1 -1
- package/v3/dist/cli/wizards/test-wizard.d.ts +1 -1
- package/v3/dist/cli/wizards/test-wizard.d.ts.map +1 -1
- package/v3/dist/cli/wizards/test-wizard.js +8 -1
- package/v3/dist/cli/wizards/test-wizard.js.map +1 -1
- package/v3/dist/coordination/task-executor.js.map +1 -1
- package/v3/dist/domains/test-generation/factories/test-generator-factory.d.ts.map +1 -1
- package/v3/dist/domains/test-generation/factories/test-generator-factory.js +4 -1
- package/v3/dist/domains/test-generation/factories/test-generator-factory.js.map +1 -1
- package/v3/dist/domains/test-generation/generators/base-test-generator.d.ts.map +1 -1
- package/v3/dist/domains/test-generation/generators/base-test-generator.js +26 -1
- package/v3/dist/domains/test-generation/generators/base-test-generator.js.map +1 -1
- package/v3/dist/domains/test-generation/generators/index.d.ts +1 -0
- package/v3/dist/domains/test-generation/generators/index.d.ts.map +1 -1
- package/v3/dist/domains/test-generation/generators/index.js +1 -0
- package/v3/dist/domains/test-generation/generators/index.js.map +1 -1
- package/v3/dist/domains/test-generation/generators/jest-vitest-generator.d.ts.map +1 -1
- package/v3/dist/domains/test-generation/generators/jest-vitest-generator.js +26 -2
- package/v3/dist/domains/test-generation/generators/jest-vitest-generator.js.map +1 -1
- package/v3/dist/domains/test-generation/generators/mocha-generator.d.ts.map +1 -1
- package/v3/dist/domains/test-generation/generators/mocha-generator.js +50 -5
- package/v3/dist/domains/test-generation/generators/mocha-generator.js.map +1 -1
- package/v3/dist/domains/test-generation/generators/node-test-generator.d.ts +54 -0
- package/v3/dist/domains/test-generation/generators/node-test-generator.d.ts.map +1 -0
- package/v3/dist/domains/test-generation/generators/node-test-generator.js +222 -0
- package/v3/dist/domains/test-generation/generators/node-test-generator.js.map +1 -0
- package/v3/dist/domains/test-generation/generators/pytest-generator.d.ts.map +1 -1
- package/v3/dist/domains/test-generation/generators/pytest-generator.js +47 -5
- package/v3/dist/domains/test-generation/generators/pytest-generator.js.map +1 -1
- package/v3/dist/domains/test-generation/interfaces/test-generator.interface.d.ts +1 -1
- package/v3/dist/domains/test-generation/interfaces/test-generator.interface.d.ts.map +1 -1
- package/v3/dist/domains/test-generation/interfaces.d.ts +2 -2
- package/v3/dist/domains/test-generation/interfaces.d.ts.map +1 -1
- package/v3/dist/domains/test-generation/plugin.js.map +1 -1
- package/v3/dist/domains/test-generation/services/pattern-matcher.js +32 -6
- package/v3/dist/domains/test-generation/services/pattern-matcher.js.map +1 -1
- package/v3/dist/domains/test-generation/services/test-generator.d.ts.map +1 -1
- package/v3/dist/domains/test-generation/services/test-generator.js +31 -6
- package/v3/dist/domains/test-generation/services/test-generator.js.map +1 -1
- package/v3/dist/mcp/bundle.js +666 -46
- package/v3/dist/mcp/handlers/agent-handlers.d.ts +3 -0
- package/v3/dist/mcp/handlers/agent-handlers.d.ts.map +1 -1
- package/v3/dist/mcp/handlers/agent-handlers.js +16 -9
- package/v3/dist/mcp/handlers/agent-handlers.js.map +1 -1
- package/v3/dist/mcp/handlers/core-handlers.d.ts +32 -0
- package/v3/dist/mcp/handlers/core-handlers.d.ts.map +1 -1
- package/v3/dist/mcp/handlers/core-handlers.js +45 -1
- package/v3/dist/mcp/handlers/core-handlers.js.map +1 -1
- package/v3/dist/mcp/handlers/handler-factory.d.ts +9 -1
- package/v3/dist/mcp/handlers/handler-factory.d.ts.map +1 -1
- package/v3/dist/mcp/handlers/handler-factory.js +94 -2
- package/v3/dist/mcp/handlers/handler-factory.js.map +1 -1
- package/v3/dist/mcp/handlers/memory-handlers.d.ts +2 -0
- package/v3/dist/mcp/handlers/memory-handlers.d.ts.map +1 -1
- package/v3/dist/mcp/handlers/memory-handlers.js +90 -1
- package/v3/dist/mcp/handlers/memory-handlers.js.map +1 -1
- package/v3/dist/mcp/protocol-server.d.ts +7 -0
- package/v3/dist/mcp/protocol-server.d.ts.map +1 -1
- package/v3/dist/mcp/protocol-server.js +56 -2
- package/v3/dist/mcp/protocol-server.js.map +1 -1
- package/v3/dist/mcp/tools/test-generation/generate.d.ts +1 -1
- package/v3/dist/mcp/tools/test-generation/generate.d.ts.map +1 -1
- package/v3/dist/mcp/tools/test-generation/generate.js.map +1 -1
- package/v3/dist/mcp/transport/stdio.d.ts +18 -0
- package/v3/dist/mcp/transport/stdio.d.ts.map +1 -1
- package/v3/dist/mcp/transport/stdio.js +72 -5
- package/v3/dist/mcp/transport/stdio.js.map +1 -1
- package/v3/dist/mcp/types.d.ts +2 -0
- package/v3/dist/mcp/types.d.ts.map +1 -1
- package/v3/dist/sync/cloud/index.d.ts +1 -0
- package/v3/dist/sync/cloud/index.d.ts.map +1 -1
- package/v3/dist/sync/cloud/index.js +1 -0
- package/v3/dist/sync/cloud/index.js.map +1 -1
- package/v3/dist/sync/cloud/postgres-reader.d.ts +63 -0
- package/v3/dist/sync/cloud/postgres-reader.d.ts.map +1 -0
- package/v3/dist/sync/cloud/postgres-reader.js +225 -0
- package/v3/dist/sync/cloud/postgres-reader.js.map +1 -0
- package/v3/dist/sync/index.d.ts +5 -2
- package/v3/dist/sync/index.d.ts.map +1 -1
- package/v3/dist/sync/index.js +7 -2
- package/v3/dist/sync/index.js.map +1 -1
- package/v3/dist/sync/interfaces.d.ts +49 -0
- package/v3/dist/sync/interfaces.d.ts.map +1 -1
- package/v3/dist/sync/interfaces.js +160 -0
- package/v3/dist/sync/interfaces.js.map +1 -1
- package/v3/dist/sync/pull-agent.d.ts +102 -0
- package/v3/dist/sync/pull-agent.d.ts.map +1 -0
- package/v3/dist/sync/pull-agent.js +354 -0
- package/v3/dist/sync/pull-agent.js.map +1 -0
- package/v3/dist/sync/sync-agent.d.ts.map +1 -1
- package/v3/dist/sync/sync-agent.js +9 -0
- package/v3/dist/sync/sync-agent.js.map +1 -1
- package/v3/dist/sync/writers/index.d.ts +7 -0
- package/v3/dist/sync/writers/index.d.ts.map +1 -0
- package/v3/dist/sync/writers/index.js +7 -0
- package/v3/dist/sync/writers/index.js.map +1 -0
- package/v3/dist/sync/writers/sqlite-writer.d.ts +69 -0
- package/v3/dist/sync/writers/sqlite-writer.d.ts.map +1 -0
- package/v3/dist/sync/writers/sqlite-writer.js +249 -0
- package/v3/dist/sync/writers/sqlite-writer.js.map +1 -0
- package/v3/package.json +1 -1
package/v3/dist/mcp/bundle.js
CHANGED
|
@@ -27141,6 +27141,7 @@ var StdioTransport = class {
|
|
|
27141
27141
|
rl = null;
|
|
27142
27142
|
requestHandler = null;
|
|
27143
27143
|
notificationHandler = null;
|
|
27144
|
+
errorHandler = null;
|
|
27144
27145
|
running = false;
|
|
27145
27146
|
metrics = {
|
|
27146
27147
|
messagesReceived: 0,
|
|
@@ -27185,22 +27186,29 @@ var StdioTransport = class {
|
|
|
27185
27186
|
});
|
|
27186
27187
|
});
|
|
27187
27188
|
this.rl.on("close", () => {
|
|
27189
|
+
const wasRunning = this.running;
|
|
27188
27190
|
this.running = false;
|
|
27191
|
+
if (wasRunning && this.errorHandler) {
|
|
27192
|
+
this.errorHandler(new Error("Transport connection closed unexpectedly"));
|
|
27193
|
+
}
|
|
27189
27194
|
});
|
|
27190
27195
|
this.rl.on("error", (err4) => {
|
|
27191
27196
|
this.metrics.errors++;
|
|
27192
27197
|
console.error("[StdioTransport] Readline error:", err4);
|
|
27198
|
+
if (this.errorHandler) {
|
|
27199
|
+
this.errorHandler(err4);
|
|
27200
|
+
}
|
|
27193
27201
|
});
|
|
27194
27202
|
}
|
|
27195
27203
|
/**
|
|
27196
27204
|
* Stop listening
|
|
27197
27205
|
*/
|
|
27198
27206
|
stop() {
|
|
27207
|
+
this.running = false;
|
|
27199
27208
|
if (this.rl) {
|
|
27200
27209
|
this.rl.close();
|
|
27201
27210
|
this.rl = null;
|
|
27202
27211
|
}
|
|
27203
|
-
this.running = false;
|
|
27204
27212
|
}
|
|
27205
27213
|
/**
|
|
27206
27214
|
* Send a response
|
|
@@ -27219,6 +27227,24 @@ var StdioTransport = class {
|
|
|
27219
27227
|
};
|
|
27220
27228
|
await this.write(JSON.stringify(notification));
|
|
27221
27229
|
}
|
|
27230
|
+
/**
|
|
27231
|
+
* Set error handler for transport-level errors
|
|
27232
|
+
*/
|
|
27233
|
+
onError(handler) {
|
|
27234
|
+
this.errorHandler = handler;
|
|
27235
|
+
}
|
|
27236
|
+
/**
|
|
27237
|
+
* Reconnect the transport by re-attaching to stdin/stdout.
|
|
27238
|
+
* Closes the existing readline interface and creates a new one.
|
|
27239
|
+
*/
|
|
27240
|
+
reconnect() {
|
|
27241
|
+
if (this.rl) {
|
|
27242
|
+
this.rl.close();
|
|
27243
|
+
this.rl = null;
|
|
27244
|
+
}
|
|
27245
|
+
this.running = false;
|
|
27246
|
+
this.start();
|
|
27247
|
+
}
|
|
27222
27248
|
/**
|
|
27223
27249
|
* Get transport metrics
|
|
27224
27250
|
*/
|
|
@@ -27321,13 +27347,50 @@ var StdioTransport = class {
|
|
|
27321
27347
|
};
|
|
27322
27348
|
await this.sendResponse(response);
|
|
27323
27349
|
}
|
|
27324
|
-
|
|
27350
|
+
/**
|
|
27351
|
+
* Write with retry and backpressure handling.
|
|
27352
|
+
* Retries up to 3 times with exponential backoff before rejecting.
|
|
27353
|
+
*/
|
|
27354
|
+
async write(data) {
|
|
27355
|
+
const maxAttempts = 3;
|
|
27356
|
+
const backoffDelays = [0, 500, 1e3];
|
|
27357
|
+
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
27358
|
+
try {
|
|
27359
|
+
await this.writeOnce(data);
|
|
27360
|
+
return;
|
|
27361
|
+
} catch (err4) {
|
|
27362
|
+
if (attempt < maxAttempts - 1) {
|
|
27363
|
+
console.error(
|
|
27364
|
+
`[StdioTransport] Write attempt ${attempt + 1} failed, retrying in ${backoffDelays[attempt + 1]}ms...`
|
|
27365
|
+
);
|
|
27366
|
+
await new Promise((r54) => setTimeout(r54, backoffDelays[attempt + 1]));
|
|
27367
|
+
} else {
|
|
27368
|
+
throw err4;
|
|
27369
|
+
}
|
|
27370
|
+
}
|
|
27371
|
+
}
|
|
27372
|
+
}
|
|
27373
|
+
/**
|
|
27374
|
+
* Single write attempt with 120s timeout and backpressure (drain) handling.
|
|
27375
|
+
*/
|
|
27376
|
+
async writeOnce(data) {
|
|
27377
|
+
const message = data + "\n";
|
|
27378
|
+
if (this.outputStream.writableNeedDrain) {
|
|
27379
|
+
await new Promise((resolve9, reject) => {
|
|
27380
|
+
const drainTimeout = setTimeout(() => {
|
|
27381
|
+
reject(new Error("Transport drain timeout after 30 seconds"));
|
|
27382
|
+
}, 3e4);
|
|
27383
|
+
this.outputStream.once("drain", () => {
|
|
27384
|
+
clearTimeout(drainTimeout);
|
|
27385
|
+
resolve9();
|
|
27386
|
+
});
|
|
27387
|
+
});
|
|
27388
|
+
}
|
|
27325
27389
|
return new Promise((resolve9, reject) => {
|
|
27326
|
-
const message = data + "\n";
|
|
27327
27390
|
const writeTimeout = setTimeout(() => {
|
|
27328
27391
|
this.metrics.errors++;
|
|
27329
|
-
reject(new Error("Transport write timeout after
|
|
27330
|
-
},
|
|
27392
|
+
reject(new Error("Transport write timeout after 120 seconds"));
|
|
27393
|
+
}, 12e4);
|
|
27331
27394
|
this.outputStream.write(message, "utf-8", (error) => {
|
|
27332
27395
|
clearTimeout(writeTimeout);
|
|
27333
27396
|
if (error) {
|
|
@@ -38683,11 +38746,27 @@ var BaseTestGenerator = class _BaseTestGenerator {
|
|
|
38683
38746
|
const validParams = fn.parameters.map((p74) => this.generateTestValue(p74)).join(", ");
|
|
38684
38747
|
const fnCall = fn.isAsync ? `await ${fn.name}(${validParams})` : `${fn.name}(${validParams})`;
|
|
38685
38748
|
const isVoid = fn.returnType === "void" || fn.returnType === "Promise<void>";
|
|
38749
|
+
let assertion = "expect(result).toBeDefined();";
|
|
38750
|
+
if (!isVoid) {
|
|
38751
|
+
if (/^(is|has|can)[A-Z]/.test(fn.name)) {
|
|
38752
|
+
assertion = "expect(typeof result).toBe('boolean');";
|
|
38753
|
+
} else if (/^(get|fetch|find)[A-Z]/.test(fn.name)) {
|
|
38754
|
+
assertion = "expect(result).not.toBeUndefined();";
|
|
38755
|
+
} else if (/^(create|build|make)[A-Z]/.test(fn.name)) {
|
|
38756
|
+
assertion = "expect(result).toBeTruthy();";
|
|
38757
|
+
} else if (fn.returnType) {
|
|
38758
|
+
const rt3 = fn.returnType.toLowerCase().replace(/promise<(.+)>/, "$1");
|
|
38759
|
+
if (rt3.includes("boolean")) assertion = "expect(typeof result).toBe('boolean');";
|
|
38760
|
+
else if (rt3.includes("number")) assertion = "expect(typeof result).toBe('number');";
|
|
38761
|
+
else if (rt3.includes("string")) assertion = "expect(typeof result).toBe('string');";
|
|
38762
|
+
else if (rt3.includes("[]") || rt3.includes("array")) assertion = "expect(Array.isArray(result)).toBe(true);";
|
|
38763
|
+
}
|
|
38764
|
+
}
|
|
38686
38765
|
testCases.push({
|
|
38687
38766
|
description: "should handle valid input correctly",
|
|
38688
38767
|
type: "happy-path",
|
|
38689
38768
|
action: isVoid ? `${fnCall};` : `const result = ${fnCall};`,
|
|
38690
|
-
assertion: isVoid ? `// void function \u2014 no return value to assert` :
|
|
38769
|
+
assertion: isVoid ? `// void function \u2014 no return value to assert` : assertion
|
|
38691
38770
|
});
|
|
38692
38771
|
const bodyText = fn.body || "";
|
|
38693
38772
|
const hasExplicitThrow = /\bthrow\b/.test(bodyText) || /\bvalidat/i.test(bodyText);
|
|
@@ -38992,6 +39071,22 @@ ${importStatement}
|
|
|
38992
39071
|
const methodCall = method.isAsync ? `await instance.${method.name}(${validParams})` : `instance.${method.name}(${validParams})`;
|
|
38993
39072
|
const asyncPrefix = method.isAsync ? "async " : "";
|
|
38994
39073
|
const isVoid = method.returnType === "void" || method.returnType === "Promise<void>";
|
|
39074
|
+
let methodAssertion = "expect(result).toBeDefined();";
|
|
39075
|
+
if (!isVoid) {
|
|
39076
|
+
if (/^(is|has|can)[A-Z]/.test(method.name)) {
|
|
39077
|
+
methodAssertion = "expect(typeof result).toBe('boolean');";
|
|
39078
|
+
} else if (/^(get|fetch|find)[A-Z]/.test(method.name)) {
|
|
39079
|
+
methodAssertion = "expect(result).not.toBeUndefined();";
|
|
39080
|
+
} else if (/^(create|build|make)[A-Z]/.test(method.name)) {
|
|
39081
|
+
methodAssertion = "expect(result).toBeTruthy();";
|
|
39082
|
+
} else if (method.returnType) {
|
|
39083
|
+
const mrt = method.returnType.toLowerCase().replace(/promise<(.+)>/, "$1");
|
|
39084
|
+
if (mrt.includes("boolean")) methodAssertion = "expect(typeof result).toBe('boolean');";
|
|
39085
|
+
else if (mrt.includes("number")) methodAssertion = "expect(typeof result).toBe('number');";
|
|
39086
|
+
else if (mrt.includes("string")) methodAssertion = "expect(typeof result).toBe('string');";
|
|
39087
|
+
else if (mrt.includes("[]") || mrt.includes("array")) methodAssertion = "expect(Array.isArray(result)).toBe(true);";
|
|
39088
|
+
}
|
|
39089
|
+
}
|
|
38995
39090
|
code += ` it('should execute successfully', ${asyncPrefix}() => {
|
|
38996
39091
|
`;
|
|
38997
39092
|
if (isVoid) {
|
|
@@ -39002,7 +39097,7 @@ ${importStatement}
|
|
|
39002
39097
|
} else {
|
|
39003
39098
|
code += ` const result = ${methodCall};
|
|
39004
39099
|
`;
|
|
39005
|
-
code += `
|
|
39100
|
+
code += ` ${methodAssertion}
|
|
39006
39101
|
`;
|
|
39007
39102
|
}
|
|
39008
39103
|
code += ` });
|
|
@@ -39399,6 +39494,22 @@ ${stubSetup}`;
|
|
|
39399
39494
|
const isVoid = fn.returnType === "void" || fn.returnType === "Promise<void>";
|
|
39400
39495
|
let code = ` describe('${fn.name}', function() {
|
|
39401
39496
|
`;
|
|
39497
|
+
let chaiAssertion = "expect(result).to.not.be.undefined;";
|
|
39498
|
+
if (!isVoid) {
|
|
39499
|
+
if (/^(is|has|can)[A-Z]/.test(fn.name)) {
|
|
39500
|
+
chaiAssertion = "expect(typeof result).to.equal('boolean');";
|
|
39501
|
+
} else if (/^(get|fetch|find)[A-Z]/.test(fn.name)) {
|
|
39502
|
+
chaiAssertion = "expect(result).to.not.be.undefined;";
|
|
39503
|
+
} else if (/^(create|build|make)[A-Z]/.test(fn.name)) {
|
|
39504
|
+
chaiAssertion = "expect(result).to.be.ok;";
|
|
39505
|
+
} else if (fn.returnType) {
|
|
39506
|
+
const rt3 = fn.returnType.toLowerCase().replace(/promise<(.+)>/, "$1");
|
|
39507
|
+
if (rt3.includes("boolean")) chaiAssertion = "expect(typeof result).to.equal('boolean');";
|
|
39508
|
+
else if (rt3.includes("number")) chaiAssertion = "expect(typeof result).to.equal('number');";
|
|
39509
|
+
else if (rt3.includes("string")) chaiAssertion = "expect(typeof result).to.equal('string');";
|
|
39510
|
+
else if (rt3.includes("[]") || rt3.includes("array")) chaiAssertion = "expect(result).to.be.an('array');";
|
|
39511
|
+
}
|
|
39512
|
+
}
|
|
39402
39513
|
code += ` it('should handle valid input', ${fn.isAsync ? "async " : ""}function() {
|
|
39403
39514
|
`;
|
|
39404
39515
|
if (isVoid) {
|
|
@@ -39407,7 +39518,7 @@ ${stubSetup}`;
|
|
|
39407
39518
|
} else {
|
|
39408
39519
|
code += ` const result = ${fnCall};
|
|
39409
39520
|
`;
|
|
39410
|
-
code += `
|
|
39521
|
+
code += ` ${chaiAssertion}
|
|
39411
39522
|
`;
|
|
39412
39523
|
}
|
|
39413
39524
|
code += ` });
|
|
@@ -39473,19 +39584,33 @@ ${stubSetup}`;
|
|
|
39473
39584
|
code += ` });
|
|
39474
39585
|
`;
|
|
39475
39586
|
for (const method of cls.methods) {
|
|
39476
|
-
if (!method.name.startsWith("_")) {
|
|
39587
|
+
if (!method.name.startsWith("_") && !method.name.startsWith("#")) {
|
|
39477
39588
|
const methodParams = method.parameters.map((p74) => this.generateTestValue(p74)).join(", ");
|
|
39478
|
-
const
|
|
39589
|
+
const isMethodVoid = method.returnType === "void" || method.returnType === "Promise<void>";
|
|
39590
|
+
let methodAssertion = "expect(result).to.not.be.undefined;";
|
|
39591
|
+
if (!isMethodVoid) {
|
|
39592
|
+
if (/^(is|has|can)[A-Z]/.test(method.name)) {
|
|
39593
|
+
methodAssertion = "expect(typeof result).to.equal('boolean');";
|
|
39594
|
+
} else if (/^(create|build|make)[A-Z]/.test(method.name)) {
|
|
39595
|
+
methodAssertion = "expect(result).to.be.ok;";
|
|
39596
|
+
} else if (method.returnType) {
|
|
39597
|
+
const mrt = method.returnType.toLowerCase().replace(/promise<(.+)>/, "$1");
|
|
39598
|
+
if (mrt.includes("boolean")) methodAssertion = "expect(typeof result).to.equal('boolean');";
|
|
39599
|
+
else if (mrt.includes("number")) methodAssertion = "expect(typeof result).to.equal('number');";
|
|
39600
|
+
else if (mrt.includes("string")) methodAssertion = "expect(typeof result).to.equal('string');";
|
|
39601
|
+
else if (mrt.includes("[]") || mrt.includes("array")) methodAssertion = "expect(result).to.be.an('array');";
|
|
39602
|
+
}
|
|
39603
|
+
}
|
|
39479
39604
|
code += `
|
|
39480
39605
|
it('${method.name} should work', ${method.isAsync ? "async " : ""}function() {
|
|
39481
39606
|
`;
|
|
39482
|
-
if (
|
|
39607
|
+
if (isMethodVoid) {
|
|
39483
39608
|
code += ` ${method.isAsync ? "await " : ""}instance.${method.name}(${methodParams});
|
|
39484
39609
|
`;
|
|
39485
39610
|
} else {
|
|
39486
39611
|
code += ` const result = ${method.isAsync ? "await " : ""}instance.${method.name}(${methodParams});
|
|
39487
39612
|
`;
|
|
39488
|
-
code += `
|
|
39613
|
+
code += ` ${methodAssertion}
|
|
39489
39614
|
`;
|
|
39490
39615
|
}
|
|
39491
39616
|
code += ` });
|
|
@@ -39734,6 +39859,20 @@ class Test${this.pascalCase(moduleName)}:
|
|
|
39734
39859
|
`;
|
|
39735
39860
|
code += ` """Test ${fn.name} with valid input"""
|
|
39736
39861
|
`;
|
|
39862
|
+
let pyAssertion = "assert result is not None";
|
|
39863
|
+
if (!isVoid) {
|
|
39864
|
+
if (/^(is|has|can)[A-Z]/.test(fn.name)) {
|
|
39865
|
+
pyAssertion = "assert isinstance(result, bool)";
|
|
39866
|
+
} else if (/^(create|build|make)[A-Z]/.test(fn.name)) {
|
|
39867
|
+
pyAssertion = "assert result";
|
|
39868
|
+
} else if (fn.returnType) {
|
|
39869
|
+
const rt3 = fn.returnType.toLowerCase().replace(/promise<(.+)>/, "$1");
|
|
39870
|
+
if (rt3.includes("boolean") || rt3.includes("bool")) pyAssertion = "assert isinstance(result, bool)";
|
|
39871
|
+
else if (rt3.includes("number") || rt3.includes("int") || rt3.includes("float")) pyAssertion = "assert isinstance(result, (int, float))";
|
|
39872
|
+
else if (rt3.includes("string") || rt3.includes("str")) pyAssertion = "assert isinstance(result, str)";
|
|
39873
|
+
else if (rt3.includes("[]") || rt3.includes("array") || rt3.includes("list")) pyAssertion = "assert isinstance(result, list)";
|
|
39874
|
+
}
|
|
39875
|
+
}
|
|
39737
39876
|
if (isVoid) {
|
|
39738
39877
|
code += ` ${fn.name}(${validParams}) # void function
|
|
39739
39878
|
|
|
@@ -39741,7 +39880,7 @@ class Test${this.pascalCase(moduleName)}:
|
|
|
39741
39880
|
} else {
|
|
39742
39881
|
code += ` result = ${fn.name}(${validParams})
|
|
39743
39882
|
`;
|
|
39744
|
-
code += `
|
|
39883
|
+
code += ` ${pyAssertion}
|
|
39745
39884
|
|
|
39746
39885
|
`;
|
|
39747
39886
|
}
|
|
@@ -39785,19 +39924,33 @@ class Test${cls.name}:
|
|
|
39785
39924
|
|
|
39786
39925
|
`;
|
|
39787
39926
|
for (const method of cls.methods) {
|
|
39788
|
-
if (!method.name.startsWith("_")) {
|
|
39927
|
+
if (!method.name.startsWith("_") && !method.name.startsWith("#")) {
|
|
39789
39928
|
const methodParams = method.parameters.map((p74) => this.generatePythonTestValue(p74)).join(", ");
|
|
39790
|
-
const
|
|
39929
|
+
const isMethodVoid = method.returnType === "void" || method.returnType === "Promise<void>";
|
|
39930
|
+
let mAssertion = "assert result is not None";
|
|
39931
|
+
if (!isMethodVoid) {
|
|
39932
|
+
if (/^(is|has|can)[A-Z]/.test(method.name)) {
|
|
39933
|
+
mAssertion = "assert isinstance(result, bool)";
|
|
39934
|
+
} else if (/^(create|build|make)[A-Z]/.test(method.name)) {
|
|
39935
|
+
mAssertion = "assert result";
|
|
39936
|
+
} else if (method.returnType) {
|
|
39937
|
+
const mrt = method.returnType.toLowerCase().replace(/promise<(.+)>/, "$1");
|
|
39938
|
+
if (mrt.includes("boolean") || mrt.includes("bool")) mAssertion = "assert isinstance(result, bool)";
|
|
39939
|
+
else if (mrt.includes("number") || mrt.includes("int") || mrt.includes("float")) mAssertion = "assert isinstance(result, (int, float))";
|
|
39940
|
+
else if (mrt.includes("string") || mrt.includes("str")) mAssertion = "assert isinstance(result, str)";
|
|
39941
|
+
else if (mrt.includes("[]") || mrt.includes("array") || mrt.includes("list")) mAssertion = "assert isinstance(result, list)";
|
|
39942
|
+
}
|
|
39943
|
+
}
|
|
39791
39944
|
code += ` def test_${method.name}(self, instance):
|
|
39792
39945
|
`;
|
|
39793
|
-
if (
|
|
39946
|
+
if (isMethodVoid) {
|
|
39794
39947
|
code += ` instance.${method.name}(${methodParams})
|
|
39795
39948
|
|
|
39796
39949
|
`;
|
|
39797
39950
|
} else {
|
|
39798
39951
|
code += ` result = instance.${method.name}(${methodParams})
|
|
39799
39952
|
`;
|
|
39800
|
-
code += `
|
|
39953
|
+
code += ` ${mAssertion}
|
|
39801
39954
|
|
|
39802
39955
|
`;
|
|
39803
39956
|
}
|
|
@@ -39985,12 +40138,214 @@ class Test${this.pascalCase(moduleName)}Coverage:
|
|
|
39985
40138
|
}
|
|
39986
40139
|
};
|
|
39987
40140
|
|
|
40141
|
+
// src/domains/test-generation/generators/node-test-generator.ts
|
|
40142
|
+
var NodeTestGenerator = class extends BaseTestGenerator {
|
|
40143
|
+
framework = "node-test";
|
|
40144
|
+
/**
|
|
40145
|
+
* Generate complete test file from analysis
|
|
40146
|
+
*/
|
|
40147
|
+
generateTests(context) {
|
|
40148
|
+
const { moduleName, importPath, testType, patterns, analysis } = context;
|
|
40149
|
+
if (!analysis || analysis.functions.length === 0 && analysis.classes.length === 0) {
|
|
40150
|
+
return this.generateStubTests(context);
|
|
40151
|
+
}
|
|
40152
|
+
const patternComment = this.generatePatternComment(patterns);
|
|
40153
|
+
const exportedFunctions = analysis.functions.filter((fn) => fn.isExported);
|
|
40154
|
+
const exportedClasses = analysis.classes.filter((cls) => cls.isExported);
|
|
40155
|
+
const exports = this.extractExports(exportedFunctions, exportedClasses);
|
|
40156
|
+
const importStatement = this.generateImportStatement(exports, importPath, moduleName);
|
|
40157
|
+
let testCode = `${patternComment}import { describe, it, beforeEach } from 'node:test';
|
|
40158
|
+
import assert from 'node:assert';
|
|
40159
|
+
${importStatement}
|
|
40160
|
+
|
|
40161
|
+
`;
|
|
40162
|
+
for (const fn of exportedFunctions) {
|
|
40163
|
+
testCode += this.generateFunctionTests(fn, testType);
|
|
40164
|
+
}
|
|
40165
|
+
for (const cls of exportedClasses) {
|
|
40166
|
+
testCode += this.generateClassTests(cls, testType);
|
|
40167
|
+
}
|
|
40168
|
+
return testCode;
|
|
40169
|
+
}
|
|
40170
|
+
/**
|
|
40171
|
+
* Generate tests for a standalone function
|
|
40172
|
+
*/
|
|
40173
|
+
generateFunctionTests(fn, _testType) {
|
|
40174
|
+
const testCases = this.generateTestCasesForFunction(fn);
|
|
40175
|
+
let code = `describe('${fn.name}', () => {
|
|
40176
|
+
`;
|
|
40177
|
+
for (const testCase of testCases) {
|
|
40178
|
+
if (testCase.setup) {
|
|
40179
|
+
code += ` ${testCase.setup}
|
|
40180
|
+
|
|
40181
|
+
`;
|
|
40182
|
+
}
|
|
40183
|
+
const asyncPrefix = fn.isAsync ? "async " : "";
|
|
40184
|
+
code += ` it('${testCase.description}', ${asyncPrefix}() => {
|
|
40185
|
+
`;
|
|
40186
|
+
code += ` ${this.convertToAssert(testCase.action)}
|
|
40187
|
+
`;
|
|
40188
|
+
code += ` ${this.convertToAssert(testCase.assertion)}
|
|
40189
|
+
`;
|
|
40190
|
+
code += ` });
|
|
40191
|
+
|
|
40192
|
+
`;
|
|
40193
|
+
}
|
|
40194
|
+
code += `});
|
|
40195
|
+
|
|
40196
|
+
`;
|
|
40197
|
+
return code;
|
|
40198
|
+
}
|
|
40199
|
+
/**
|
|
40200
|
+
* Generate tests for a class
|
|
40201
|
+
*/
|
|
40202
|
+
generateClassTests(cls, testType) {
|
|
40203
|
+
let code = `describe('${cls.name}', () => {
|
|
40204
|
+
`;
|
|
40205
|
+
code += ` let instance;
|
|
40206
|
+
|
|
40207
|
+
`;
|
|
40208
|
+
const constructorArgs = cls.constructorParams?.map((p74) => this.generateTestValue(p74)).join(", ") || "";
|
|
40209
|
+
code += ` beforeEach(() => {
|
|
40210
|
+
`;
|
|
40211
|
+
code += ` instance = new ${cls.name}(${constructorArgs});
|
|
40212
|
+
`;
|
|
40213
|
+
code += ` });
|
|
40214
|
+
|
|
40215
|
+
`;
|
|
40216
|
+
code += ` it('should instantiate correctly', () => {
|
|
40217
|
+
`;
|
|
40218
|
+
code += ` assert.ok(instance instanceof ${cls.name});
|
|
40219
|
+
`;
|
|
40220
|
+
code += ` });
|
|
40221
|
+
|
|
40222
|
+
`;
|
|
40223
|
+
for (const method of cls.methods) {
|
|
40224
|
+
if (!method.name.startsWith("_") && !method.name.startsWith("#")) {
|
|
40225
|
+
code += this.generateMethodTest(method);
|
|
40226
|
+
}
|
|
40227
|
+
}
|
|
40228
|
+
code += `});
|
|
40229
|
+
|
|
40230
|
+
`;
|
|
40231
|
+
return code;
|
|
40232
|
+
}
|
|
40233
|
+
/**
|
|
40234
|
+
* Generate test for a class method
|
|
40235
|
+
*/
|
|
40236
|
+
generateMethodTest(method) {
|
|
40237
|
+
const validParams = method.parameters.map((p74) => this.generateTestValue(p74)).join(", ");
|
|
40238
|
+
const isVoid = method.returnType === "void" || method.returnType === "Promise<void>";
|
|
40239
|
+
const asyncPrefix = method.isAsync ? "async " : "";
|
|
40240
|
+
const methodCall = method.isAsync ? `await instance.${method.name}(${validParams})` : `instance.${method.name}(${validParams})`;
|
|
40241
|
+
let assertLine = "assert.ok(result !== undefined);";
|
|
40242
|
+
if (!isVoid) {
|
|
40243
|
+
const mLower = method.name.toLowerCase();
|
|
40244
|
+
if (/^(is|has|can)[A-Z]/.test(method.name)) {
|
|
40245
|
+
assertLine = "assert.strictEqual(typeof result, 'boolean');";
|
|
40246
|
+
} else if (/^(get|fetch|find)[A-Z]/.test(method.name)) {
|
|
40247
|
+
assertLine = "assert.ok(result !== undefined);";
|
|
40248
|
+
} else if (/^(create|build|make)[A-Z]/.test(method.name)) {
|
|
40249
|
+
assertLine = "assert.ok(result);";
|
|
40250
|
+
} else if (method.returnType) {
|
|
40251
|
+
const rt3 = method.returnType.toLowerCase().replace(/promise<(.+)>/, "$1");
|
|
40252
|
+
if (rt3.includes("boolean")) assertLine = "assert.strictEqual(typeof result, 'boolean');";
|
|
40253
|
+
else if (rt3.includes("number")) assertLine = "assert.strictEqual(typeof result, 'number');";
|
|
40254
|
+
else if (rt3.includes("string")) assertLine = "assert.strictEqual(typeof result, 'string');";
|
|
40255
|
+
else if (rt3.includes("[]") || rt3.includes("array")) assertLine = "assert.ok(Array.isArray(result));";
|
|
40256
|
+
}
|
|
40257
|
+
}
|
|
40258
|
+
let code = ` it('${method.name} should execute successfully', ${asyncPrefix}() => {
|
|
40259
|
+
`;
|
|
40260
|
+
if (isVoid) {
|
|
40261
|
+
code += ` ${methodCall};
|
|
40262
|
+
`;
|
|
40263
|
+
} else {
|
|
40264
|
+
code += ` const result = ${methodCall};
|
|
40265
|
+
`;
|
|
40266
|
+
code += ` ${assertLine}
|
|
40267
|
+
`;
|
|
40268
|
+
}
|
|
40269
|
+
code += ` });
|
|
40270
|
+
|
|
40271
|
+
`;
|
|
40272
|
+
return code;
|
|
40273
|
+
}
|
|
40274
|
+
/**
|
|
40275
|
+
* Generate stub tests when no AST analysis is available
|
|
40276
|
+
*/
|
|
40277
|
+
generateStubTests(context) {
|
|
40278
|
+
const { moduleName, importPath, testType, patterns } = context;
|
|
40279
|
+
const patternComment = this.generatePatternComment(patterns);
|
|
40280
|
+
return `${patternComment}import { describe, it } from 'node:test';
|
|
40281
|
+
import assert from 'node:assert';
|
|
40282
|
+
import { ${moduleName} } from '${importPath}';
|
|
40283
|
+
|
|
40284
|
+
describe('${moduleName}', () => {
|
|
40285
|
+
describe('${testType} tests', () => {
|
|
40286
|
+
it('should be defined', () => {
|
|
40287
|
+
assert.ok(${moduleName} !== undefined);
|
|
40288
|
+
});
|
|
40289
|
+
|
|
40290
|
+
it('should handle basic operations', () => {
|
|
40291
|
+
const moduleType = typeof ${moduleName};
|
|
40292
|
+
assert.ok(['function', 'object'].includes(moduleType));
|
|
40293
|
+
});
|
|
40294
|
+
|
|
40295
|
+
it('should handle error conditions', () => {
|
|
40296
|
+
assert.doesNotThrow(() => {
|
|
40297
|
+
const instance = typeof ${moduleName} === 'function'
|
|
40298
|
+
? new ${moduleName}()
|
|
40299
|
+
: ${moduleName};
|
|
40300
|
+
return instance;
|
|
40301
|
+
});
|
|
40302
|
+
});
|
|
40303
|
+
});
|
|
40304
|
+
});
|
|
40305
|
+
`;
|
|
40306
|
+
}
|
|
40307
|
+
/**
|
|
40308
|
+
* Generate coverage-focused tests for specific lines
|
|
40309
|
+
*/
|
|
40310
|
+
generateCoverageTests(moduleName, importPath, lines) {
|
|
40311
|
+
const funcName = this.camelCase(moduleName);
|
|
40312
|
+
const lineRange = this.formatLineRange(lines);
|
|
40313
|
+
return `// Coverage test for ${lineRange} in ${moduleName}
|
|
40314
|
+
import { describe, it } from 'node:test';
|
|
40315
|
+
import assert from 'node:assert';
|
|
40316
|
+
import { ${funcName} } from '${importPath}';
|
|
40317
|
+
|
|
40318
|
+
describe('${moduleName} coverage', () => {
|
|
40319
|
+
it('should exercise code path covering ${lineRange}', () => {
|
|
40320
|
+
const testInput = undefined; // Replace with appropriate input
|
|
40321
|
+
const result = ${funcName}(testInput);
|
|
40322
|
+
assert.ok(result !== undefined || result === undefined);
|
|
40323
|
+
});
|
|
40324
|
+
|
|
40325
|
+
it('should handle edge case for ${lineRange}', () => {
|
|
40326
|
+
assert.doesNotThrow(() => ${funcName}(null));
|
|
40327
|
+
});
|
|
40328
|
+
});
|
|
40329
|
+
`;
|
|
40330
|
+
}
|
|
40331
|
+
// ============================================================================
|
|
40332
|
+
// Helpers
|
|
40333
|
+
// ============================================================================
|
|
40334
|
+
/**
|
|
40335
|
+
* Convert expect() style assertions to node:assert
|
|
40336
|
+
*/
|
|
40337
|
+
convertToAssert(assertion) {
|
|
40338
|
+
return assertion.replace(/expect\(typeof ([^)]+)\)\.toBe\('([^']+)'\);?/g, "assert.strictEqual(typeof $1, '$2');").replace(/expect\(Array\.isArray\(([^)]+)\)\)\.toBe\(true\);?/g, "assert.ok(Array.isArray($1));").replace(/expect\(([^)]+)\)\.toThrow\(\);?/g, "assert.throws($1);").replace(/expect\(([^)]+)\)\.not\.toThrow\(\);?/g, "assert.doesNotThrow($1);").replace(/expect\(([^)]+)\)\.toBeInstanceOf\(([^)]+)\);?/g, "assert.ok($1 instanceof $2);").replace(/expect\(([^)]+)\)\.toBeDefined\(\);?/g, "assert.ok($1 !== undefined);").replace(/expect\(([^)]+)\)\.not\.toBeUndefined\(\);?/g, "assert.ok($1 !== undefined);").replace(/expect\(([^)]+)\)\.toBeUndefined\(\);?/g, "assert.strictEqual($1, undefined);").replace(/expect\(([^)]+)\)\.toBeTruthy\(\);?/g, "assert.ok($1);").replace(/expect\(([^)]+)\)\.toBeFalsy\(\);?/g, "assert.ok(!$1);").replace(/expect\(([^)]+)\)\.toBe\(([^)]+)\);?/g, "assert.strictEqual($1, $2);").replace(/expect\(([^)]+)\)\.toEqual\(([^)]+)\);?/g, "assert.deepStrictEqual($1, $2);");
|
|
40339
|
+
}
|
|
40340
|
+
};
|
|
40341
|
+
|
|
39988
40342
|
// src/domains/test-generation/factories/test-generator-factory.ts
|
|
39989
40343
|
var SUPPORTED_FRAMEWORKS = [
|
|
39990
40344
|
"jest",
|
|
39991
40345
|
"vitest",
|
|
39992
40346
|
"mocha",
|
|
39993
|
-
"pytest"
|
|
40347
|
+
"pytest",
|
|
40348
|
+
"node-test"
|
|
39994
40349
|
];
|
|
39995
40350
|
var DEFAULT_FRAMEWORK = "vitest";
|
|
39996
40351
|
var TestGeneratorFactory = class {
|
|
@@ -40052,6 +40407,8 @@ var TestGeneratorFactory = class {
|
|
|
40052
40407
|
return new MochaGenerator();
|
|
40053
40408
|
case "pytest":
|
|
40054
40409
|
return new PytestGenerator();
|
|
40410
|
+
case "node-test":
|
|
40411
|
+
return new NodeTestGenerator();
|
|
40055
40412
|
default:
|
|
40056
40413
|
throw new Error(`Unsupported test framework: ${framework}`);
|
|
40057
40414
|
}
|
|
@@ -41399,12 +41756,32 @@ ${sourceCode}
|
|
|
41399
41756
|
};
|
|
41400
41757
|
}
|
|
41401
41758
|
extractParameters(params, sourceFile) {
|
|
41402
|
-
|
|
41403
|
-
|
|
41404
|
-
|
|
41405
|
-
|
|
41406
|
-
|
|
41407
|
-
|
|
41759
|
+
let objectDestructureCount = 0;
|
|
41760
|
+
let arrayDestructureCount = 0;
|
|
41761
|
+
return params.map((param) => {
|
|
41762
|
+
let name = param.name.getText(sourceFile);
|
|
41763
|
+
let type = param.type?.getText(sourceFile);
|
|
41764
|
+
if (ts.isObjectBindingPattern(param.name)) {
|
|
41765
|
+
objectDestructureCount++;
|
|
41766
|
+
name = objectDestructureCount > 1 ? `options${objectDestructureCount}` : "options";
|
|
41767
|
+
if (!type) {
|
|
41768
|
+
const props = param.name.elements.map((el) => `${el.name.getText(sourceFile)}: unknown`).join(", ");
|
|
41769
|
+
type = `{ ${props} }`;
|
|
41770
|
+
}
|
|
41771
|
+
} else if (ts.isArrayBindingPattern(param.name)) {
|
|
41772
|
+
arrayDestructureCount++;
|
|
41773
|
+
name = arrayDestructureCount > 1 ? `items${arrayDestructureCount}` : "items";
|
|
41774
|
+
if (!type) {
|
|
41775
|
+
type = "unknown[]";
|
|
41776
|
+
}
|
|
41777
|
+
}
|
|
41778
|
+
return {
|
|
41779
|
+
name,
|
|
41780
|
+
type,
|
|
41781
|
+
optional: param.questionToken !== void 0,
|
|
41782
|
+
defaultValue: param.initializer?.getText(sourceFile)
|
|
41783
|
+
};
|
|
41784
|
+
});
|
|
41408
41785
|
}
|
|
41409
41786
|
calculateComplexity(node) {
|
|
41410
41787
|
let complexity = 1;
|
|
@@ -43419,12 +43796,32 @@ var TypeScriptASTParser = class {
|
|
|
43419
43796
|
* Extract parameter information
|
|
43420
43797
|
*/
|
|
43421
43798
|
extractParameters(params, sourceFile) {
|
|
43422
|
-
|
|
43423
|
-
|
|
43424
|
-
|
|
43425
|
-
|
|
43426
|
-
|
|
43427
|
-
|
|
43799
|
+
let objectDestructureCount = 0;
|
|
43800
|
+
let arrayDestructureCount = 0;
|
|
43801
|
+
return params.map((param) => {
|
|
43802
|
+
let name = param.name.getText(sourceFile);
|
|
43803
|
+
let type = param.type?.getText(sourceFile);
|
|
43804
|
+
if (ts2.isObjectBindingPattern(param.name)) {
|
|
43805
|
+
objectDestructureCount++;
|
|
43806
|
+
name = objectDestructureCount > 1 ? `options${objectDestructureCount}` : "options";
|
|
43807
|
+
if (!type) {
|
|
43808
|
+
const props = param.name.elements.map((el) => `${el.name.getText(sourceFile)}: unknown`).join(", ");
|
|
43809
|
+
type = `{ ${props} }`;
|
|
43810
|
+
}
|
|
43811
|
+
} else if (ts2.isArrayBindingPattern(param.name)) {
|
|
43812
|
+
arrayDestructureCount++;
|
|
43813
|
+
name = arrayDestructureCount > 1 ? `items${arrayDestructureCount}` : "items";
|
|
43814
|
+
if (!type) {
|
|
43815
|
+
type = "unknown[]";
|
|
43816
|
+
}
|
|
43817
|
+
}
|
|
43818
|
+
return {
|
|
43819
|
+
name,
|
|
43820
|
+
type,
|
|
43821
|
+
optional: param.questionToken !== void 0,
|
|
43822
|
+
defaultValue: param.initializer?.getText(sourceFile)
|
|
43823
|
+
};
|
|
43824
|
+
});
|
|
43428
43825
|
}
|
|
43429
43826
|
/**
|
|
43430
43827
|
* Calculate cyclomatic complexity of a node
|
|
@@ -137639,8 +138036,83 @@ function generateV2LearningFeedback(agentType) {
|
|
|
137639
138036
|
return {
|
|
137640
138037
|
enabled: true,
|
|
137641
138038
|
agentId: generateAgentId(agentType),
|
|
137642
|
-
message: "
|
|
138039
|
+
message: "Experience captured asynchronously via learning pipeline"
|
|
138040
|
+
};
|
|
138041
|
+
}
|
|
138042
|
+
async function captureExecutionLearning(agentType, toolName, params, result, durationMs) {
|
|
138043
|
+
const agentId = generateAgentId(agentType);
|
|
138044
|
+
try {
|
|
138045
|
+
const { kernel } = getFleetState();
|
|
138046
|
+
if (!kernel) {
|
|
138047
|
+
return { enabled: false, agentId, message: "Learning engine not available - kernel not initialized" };
|
|
138048
|
+
}
|
|
138049
|
+
const engine = await getLearningEngineForCapture();
|
|
138050
|
+
if (!engine) {
|
|
138051
|
+
return { enabled: false, agentId, message: "Learning engine not available" };
|
|
138052
|
+
}
|
|
138053
|
+
const captureService = engine.getExperienceCaptureService();
|
|
138054
|
+
if (!captureService) {
|
|
138055
|
+
return { enabled: false, agentId, message: "Experience capture service not available" };
|
|
138056
|
+
}
|
|
138057
|
+
const domain = toolNameToDomain(toolName);
|
|
138058
|
+
const experienceId = captureService.startCapture(
|
|
138059
|
+
`${toolName}: ${JSON.stringify(params).slice(0, 200)}`,
|
|
138060
|
+
{
|
|
138061
|
+
agent: agentType,
|
|
138062
|
+
domain: domain || void 0,
|
|
138063
|
+
metadata: {
|
|
138064
|
+
tool: toolName,
|
|
138065
|
+
durationMs
|
|
138066
|
+
}
|
|
138067
|
+
}
|
|
138068
|
+
);
|
|
138069
|
+
captureService.recordStep(experienceId, {
|
|
138070
|
+
action: `execute-${toolName}`,
|
|
138071
|
+
result: typeof result === "object" ? JSON.stringify(result).slice(0, 500) : String(result).slice(0, 500),
|
|
138072
|
+
quality: 0.7
|
|
138073
|
+
// Default quality for successful tool execution
|
|
138074
|
+
});
|
|
138075
|
+
const captureResult = await captureService.completeCapture(experienceId, {
|
|
138076
|
+
success: true,
|
|
138077
|
+
quality: 0.7
|
|
138078
|
+
});
|
|
138079
|
+
if (captureResult.success) {
|
|
138080
|
+
const experience = captureResult.value;
|
|
138081
|
+
return {
|
|
138082
|
+
enabled: true,
|
|
138083
|
+
agentId,
|
|
138084
|
+
message: `Experience captured: ${experience.id} (domain: ${domain || "general"}, quality: ${experience.quality})`,
|
|
138085
|
+
experienceId: experience.id,
|
|
138086
|
+
domain: domain || "general"
|
|
138087
|
+
};
|
|
138088
|
+
}
|
|
138089
|
+
return { enabled: true, agentId, message: "Experience capture completed (no pattern extracted)" };
|
|
138090
|
+
} catch (error) {
|
|
138091
|
+
return {
|
|
138092
|
+
enabled: false,
|
|
138093
|
+
agentId,
|
|
138094
|
+
message: `Learning capture failed: ${toErrorMessage(error)}`
|
|
138095
|
+
};
|
|
138096
|
+
}
|
|
138097
|
+
}
|
|
138098
|
+
function toolNameToDomain(toolName) {
|
|
138099
|
+
const mapping = {
|
|
138100
|
+
"test_generate_enhanced": "test-generation",
|
|
138101
|
+
"test_execute_parallel": "test-execution",
|
|
138102
|
+
"coverage_analyze_sublinear": "coverage-analysis",
|
|
138103
|
+
"quality_assess": "quality-assessment",
|
|
138104
|
+
"security_scan_comprehensive": "security-compliance",
|
|
138105
|
+
"contract_validate": "contract-testing",
|
|
138106
|
+
"accessibility_test": "visual-accessibility",
|
|
138107
|
+
"chaos_test": "chaos-resilience",
|
|
138108
|
+
"defect_predict": "defect-intelligence",
|
|
138109
|
+
"requirements_validate": "requirements-validation",
|
|
138110
|
+
"code_index": "code-intelligence"
|
|
137643
138111
|
};
|
|
138112
|
+
return mapping[toolName] || null;
|
|
138113
|
+
}
|
|
138114
|
+
async function getLearningEngineForCapture() {
|
|
138115
|
+
return getLearningEngine();
|
|
137644
138116
|
}
|
|
137645
138117
|
function analyzeComplexity(sourceCode) {
|
|
137646
138118
|
const lines = sourceCode.split("\n").length;
|
|
@@ -137946,6 +138418,14 @@ function createDomainHandler(config) {
|
|
|
137946
138418
|
domain,
|
|
137947
138419
|
result.duration
|
|
137948
138420
|
);
|
|
138421
|
+
captureExecutionLearning(
|
|
138422
|
+
`qe-${domain}`,
|
|
138423
|
+
taskType,
|
|
138424
|
+
params,
|
|
138425
|
+
data,
|
|
138426
|
+
result.duration
|
|
138427
|
+
).catch(() => {
|
|
138428
|
+
});
|
|
137949
138429
|
return {
|
|
137950
138430
|
success: true,
|
|
137951
138431
|
data: mappedResult
|
|
@@ -153615,7 +154095,9 @@ var state = {
|
|
|
153615
154095
|
router: null,
|
|
153616
154096
|
workflowOrchestrator: null,
|
|
153617
154097
|
initialized: false,
|
|
153618
|
-
initTime: null
|
|
154098
|
+
initTime: null,
|
|
154099
|
+
topology: "hierarchical",
|
|
154100
|
+
agentLevels: /* @__PURE__ */ new Map()
|
|
153619
154101
|
};
|
|
153620
154102
|
function getFleetState() {
|
|
153621
154103
|
return state;
|
|
@@ -153623,6 +154105,23 @@ function getFleetState() {
|
|
|
153623
154105
|
function isFleetInitialized() {
|
|
153624
154106
|
return state.initialized && state.kernel !== null && state.queen !== null;
|
|
153625
154107
|
}
|
|
154108
|
+
function assignAgentLevel(agentId, domain) {
|
|
154109
|
+
if (state.topology !== "hierarchical") {
|
|
154110
|
+
const info2 = { agentId, domain, level: "worker", spawnedAt: /* @__PURE__ */ new Date() };
|
|
154111
|
+
state.agentLevels.set(agentId, info2);
|
|
154112
|
+
return "worker";
|
|
154113
|
+
}
|
|
154114
|
+
const existingLead = Array.from(state.agentLevels.values()).find(
|
|
154115
|
+
(a37) => a37.domain === domain && a37.level === "lead"
|
|
154116
|
+
);
|
|
154117
|
+
const level = existingLead ? "worker" : "lead";
|
|
154118
|
+
const info = { agentId, domain, level, spawnedAt: /* @__PURE__ */ new Date() };
|
|
154119
|
+
state.agentLevels.set(agentId, info);
|
|
154120
|
+
return level;
|
|
154121
|
+
}
|
|
154122
|
+
function getAgentLevel(agentId) {
|
|
154123
|
+
return state.agentLevels.get(agentId);
|
|
154124
|
+
}
|
|
153626
154125
|
async function handleFleetInit(params) {
|
|
153627
154126
|
try {
|
|
153628
154127
|
if (state.initialized && state.kernel && state.queen) {
|
|
@@ -153687,11 +154186,13 @@ async function handleFleetInit(params) {
|
|
|
153687
154186
|
registerDomainWorkflowActions(state.kernel, state.workflowOrchestrator);
|
|
153688
154187
|
state.initialized = true;
|
|
153689
154188
|
state.initTime = /* @__PURE__ */ new Date();
|
|
154189
|
+
state.topology = params.topology || "hierarchical";
|
|
154190
|
+
state.agentLevels.clear();
|
|
153690
154191
|
return {
|
|
153691
154192
|
success: true,
|
|
153692
154193
|
data: {
|
|
153693
154194
|
fleetId: state.fleetId,
|
|
153694
|
-
topology:
|
|
154195
|
+
topology: state.topology,
|
|
153695
154196
|
maxAgents: params.maxAgents || 15,
|
|
153696
154197
|
// Return user-facing domains (12) - coordination is internal
|
|
153697
154198
|
enabledDomains: userFacingDomains,
|
|
@@ -153851,6 +154352,8 @@ async function disposeFleet() {
|
|
|
153851
154352
|
state.initialized = false;
|
|
153852
154353
|
state.fleetId = null;
|
|
153853
154354
|
state.initTime = null;
|
|
154355
|
+
state.topology = "hierarchical";
|
|
154356
|
+
state.agentLevels.clear();
|
|
153854
154357
|
}
|
|
153855
154358
|
function registerDomainWorkflowActions(kernel, orchestrator) {
|
|
153856
154359
|
const reqValAPI = kernel.getDomainAPI("requirements-validation");
|
|
@@ -155124,14 +155627,18 @@ async function handleAgentList(params) {
|
|
|
155124
155627
|
if (typeof params.limit === "number") {
|
|
155125
155628
|
agents = agents.slice(0, params.limit);
|
|
155126
155629
|
}
|
|
155127
|
-
const result = agents.map((agent) =>
|
|
155128
|
-
|
|
155129
|
-
|
|
155130
|
-
|
|
155131
|
-
|
|
155132
|
-
|
|
155133
|
-
|
|
155134
|
-
|
|
155630
|
+
const result = agents.map((agent) => {
|
|
155631
|
+
const levelInfo = getAgentLevel(agent.id);
|
|
155632
|
+
return {
|
|
155633
|
+
id: agent.id,
|
|
155634
|
+
domain: agent.domain,
|
|
155635
|
+
type: agent.type,
|
|
155636
|
+
status: agent.status,
|
|
155637
|
+
name: agent.name,
|
|
155638
|
+
startedAt: agent.startedAt?.toISOString(),
|
|
155639
|
+
level: levelInfo?.level
|
|
155640
|
+
};
|
|
155641
|
+
});
|
|
155135
155642
|
return {
|
|
155136
155643
|
success: true,
|
|
155137
155644
|
data: result
|
|
@@ -155165,6 +155672,7 @@ async function handleAgentSpawn(params) {
|
|
|
155165
155672
|
}
|
|
155166
155673
|
const balancer = getLoadBalancer();
|
|
155167
155674
|
balancer.registerAgent(result.value);
|
|
155675
|
+
const level = assignAgentLevel(result.value, params.domain);
|
|
155168
155676
|
return {
|
|
155169
155677
|
success: true,
|
|
155170
155678
|
data: {
|
|
@@ -155172,7 +155680,8 @@ async function handleAgentSpawn(params) {
|
|
|
155172
155680
|
domain: params.domain,
|
|
155173
155681
|
type: params.type || "worker",
|
|
155174
155682
|
status: "spawned",
|
|
155175
|
-
capabilities: params.capabilities || ["general"]
|
|
155683
|
+
capabilities: params.capabilities || ["general"],
|
|
155684
|
+
level
|
|
155176
155685
|
}
|
|
155177
155686
|
};
|
|
155178
155687
|
} catch (error) {
|
|
@@ -155732,6 +156241,17 @@ async function handleMemoryStore(params) {
|
|
|
155732
156241
|
await kernel.memory.set(fullKey, params.value, {
|
|
155733
156242
|
ttl: params.ttl
|
|
155734
156243
|
});
|
|
156244
|
+
try {
|
|
156245
|
+
const textForEmbedding = `${params.key} ${JSON.stringify(params.value)}`;
|
|
156246
|
+
const embedding = textToSimpleEmbedding(textForEmbedding);
|
|
156247
|
+
await kernel.memory.storeVector(fullKey, embedding, {
|
|
156248
|
+
key: params.key,
|
|
156249
|
+
namespace,
|
|
156250
|
+
storedAt: Date.now()
|
|
156251
|
+
});
|
|
156252
|
+
} catch (vecErr) {
|
|
156253
|
+
console.warn(`[MemoryHandler] Vector indexing failed for ${params.key}: ${toErrorMessage(vecErr)}`);
|
|
156254
|
+
}
|
|
155735
156255
|
if (isMemoryWriteGateEnabled()) {
|
|
155736
156256
|
memoryWriteGateIntegration.registerPattern(
|
|
155737
156257
|
createMemoryPattern(params.key, params.value, namespace)
|
|
@@ -155795,6 +156315,9 @@ async function handleMemoryRetrieve(params) {
|
|
|
155795
156315
|
};
|
|
155796
156316
|
}
|
|
155797
156317
|
}
|
|
156318
|
+
function isNaturalLanguageQuery(pattern) {
|
|
156319
|
+
return pattern.includes(" ") && !pattern.includes("*") && !pattern.includes("?");
|
|
156320
|
+
}
|
|
155798
156321
|
async function handleMemoryQuery(params) {
|
|
155799
156322
|
if (!isFleetInitialized()) {
|
|
155800
156323
|
return {
|
|
@@ -155807,6 +156330,34 @@ async function handleMemoryQuery(params) {
|
|
|
155807
156330
|
const namespace = params.namespace || "default";
|
|
155808
156331
|
const limit = params.limit || 100;
|
|
155809
156332
|
const offset = params.offset || 0;
|
|
156333
|
+
const useSemantic = params.semantic === true || params.semantic !== false && params.pattern && isNaturalLanguageQuery(params.pattern);
|
|
156334
|
+
if (useSemantic && params.pattern) {
|
|
156335
|
+
try {
|
|
156336
|
+
const embedding = textToSimpleEmbedding(params.pattern);
|
|
156337
|
+
const vectorResults = await kernel.memory.vectorSearch(embedding, limit + offset);
|
|
156338
|
+
const filtered = namespace !== "default" ? vectorResults.filter((r54) => r54.key.startsWith(`${namespace}:`)) : vectorResults;
|
|
156339
|
+
const paginatedResults = filtered.slice(offset, offset + limit);
|
|
156340
|
+
const entries2 = paginatedResults.map((r54) => {
|
|
156341
|
+
const parts = r54.key.split(":");
|
|
156342
|
+
return {
|
|
156343
|
+
key: parts.length > 1 ? parts.slice(1).join(":") : r54.key,
|
|
156344
|
+
namespace: parts.length > 1 ? parts[0] : namespace,
|
|
156345
|
+
score: r54.score
|
|
156346
|
+
};
|
|
156347
|
+
});
|
|
156348
|
+
return {
|
|
156349
|
+
success: true,
|
|
156350
|
+
data: {
|
|
156351
|
+
entries: entries2,
|
|
156352
|
+
total: filtered.length,
|
|
156353
|
+
hasMore: offset + limit < filtered.length,
|
|
156354
|
+
searchType: "semantic"
|
|
156355
|
+
}
|
|
156356
|
+
};
|
|
156357
|
+
} catch (vectorError) {
|
|
156358
|
+
console.error(`[MemoryHandler] Semantic search failed, falling back to pattern: ${toErrorMessage(vectorError)}`);
|
|
156359
|
+
}
|
|
156360
|
+
}
|
|
155810
156361
|
const pattern = params.pattern ? `${namespace}:${params.pattern}` : `${namespace}:*`;
|
|
155811
156362
|
const keys = await kernel.memory.search(pattern, limit + offset);
|
|
155812
156363
|
const paginatedKeys = keys.slice(offset, offset + limit);
|
|
@@ -155823,7 +156374,8 @@ async function handleMemoryQuery(params) {
|
|
|
155823
156374
|
data: {
|
|
155824
156375
|
entries,
|
|
155825
156376
|
total: keys.length,
|
|
155826
|
-
hasMore: offset + limit < keys.length
|
|
156377
|
+
hasMore: offset + limit < keys.length,
|
|
156378
|
+
searchType: "pattern"
|
|
155827
156379
|
}
|
|
155828
156380
|
};
|
|
155829
156381
|
} catch (error) {
|
|
@@ -155833,6 +156385,26 @@ async function handleMemoryQuery(params) {
|
|
|
155833
156385
|
};
|
|
155834
156386
|
}
|
|
155835
156387
|
}
|
|
156388
|
+
function textToSimpleEmbedding(text2) {
|
|
156389
|
+
const dimension = 768;
|
|
156390
|
+
const embedding = new Array(dimension).fill(0);
|
|
156391
|
+
const words = text2.toLowerCase().split(/\s+/);
|
|
156392
|
+
for (const word of words) {
|
|
156393
|
+
let hash = 0;
|
|
156394
|
+
for (let i58 = 0; i58 < word.length; i58++) {
|
|
156395
|
+
hash = (hash << 5) - hash + word.charCodeAt(i58) | 0;
|
|
156396
|
+
}
|
|
156397
|
+
const idx = Math.abs(hash) % dimension;
|
|
156398
|
+
embedding[idx] += 1;
|
|
156399
|
+
}
|
|
156400
|
+
const magnitude2 = Math.sqrt(embedding.reduce((sum, v62) => sum + v62 * v62, 0));
|
|
156401
|
+
if (magnitude2 > 0) {
|
|
156402
|
+
for (let i58 = 0; i58 < dimension; i58++) {
|
|
156403
|
+
embedding[i58] /= magnitude2;
|
|
156404
|
+
}
|
|
156405
|
+
}
|
|
156406
|
+
return embedding;
|
|
156407
|
+
}
|
|
155836
156408
|
async function handleMemoryDelete(params) {
|
|
155837
156409
|
if (!isFleetInitialized()) {
|
|
155838
156410
|
return {
|
|
@@ -156562,6 +157134,9 @@ var MCPProtocolServer = class {
|
|
|
156562
157134
|
monitor = getPerformanceMonitor();
|
|
156563
157135
|
// AG-UI EventAdapter for streaming events to HTTP clients
|
|
156564
157136
|
eventAdapter;
|
|
157137
|
+
// Connection recovery state
|
|
157138
|
+
reconnecting = false;
|
|
157139
|
+
pendingRequests = [];
|
|
156565
157140
|
constructor(config = {}) {
|
|
156566
157141
|
this.config = {
|
|
156567
157142
|
name: config.name ?? "agentic-qe-v3",
|
|
@@ -156604,9 +157179,53 @@ var MCPProtocolServer = class {
|
|
|
156604
157179
|
this.transport.onNotification(async (notification) => {
|
|
156605
157180
|
await this.handleNotification(notification);
|
|
156606
157181
|
});
|
|
157182
|
+
this.transport.onError(async (error) => {
|
|
157183
|
+
console.error(`[MCP] Transport error: ${error.message}`);
|
|
157184
|
+
await this.attemptReconnect();
|
|
157185
|
+
});
|
|
156607
157186
|
this.transport.start();
|
|
156608
157187
|
console.error(`[MCP] ${this.config.name} v${this.config.version} started`);
|
|
156609
157188
|
}
|
|
157189
|
+
/**
|
|
157190
|
+
* Attempt to reconnect the transport with exponential backoff.
|
|
157191
|
+
* Buffers requests during the reconnection window and replays them after success.
|
|
157192
|
+
*/
|
|
157193
|
+
async attemptReconnect() {
|
|
157194
|
+
if (this.reconnecting) return;
|
|
157195
|
+
this.reconnecting = true;
|
|
157196
|
+
const maxAttempts = 3;
|
|
157197
|
+
const baseDelay = 1e3;
|
|
157198
|
+
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
157199
|
+
const delay = baseDelay * Math.pow(2, attempt);
|
|
157200
|
+
console.error(`[MCP] Reconnect attempt ${attempt + 1}/${maxAttempts} in ${delay}ms...`);
|
|
157201
|
+
await new Promise((r54) => setTimeout(r54, delay));
|
|
157202
|
+
try {
|
|
157203
|
+
this.transport.reconnect();
|
|
157204
|
+
console.error(`[MCP] Reconnected after ${attempt + 1} attempt(s)`);
|
|
157205
|
+
this.reconnecting = false;
|
|
157206
|
+
const buffered2 = [...this.pendingRequests];
|
|
157207
|
+
this.pendingRequests = [];
|
|
157208
|
+
for (const { resolve: resolve9, request } of buffered2) {
|
|
157209
|
+
try {
|
|
157210
|
+
const result = await this.handleRequest(request);
|
|
157211
|
+
resolve9(result);
|
|
157212
|
+
} catch (err4) {
|
|
157213
|
+
console.error(`[MCP] Failed to replay buffered request: ${request.method}`);
|
|
157214
|
+
}
|
|
157215
|
+
}
|
|
157216
|
+
return;
|
|
157217
|
+
} catch (err4) {
|
|
157218
|
+
console.error(`[MCP] Reconnect attempt ${attempt + 1} failed: ${err4 instanceof Error ? err4.message : err4}`);
|
|
157219
|
+
}
|
|
157220
|
+
}
|
|
157221
|
+
this.reconnecting = false;
|
|
157222
|
+
console.error("[MCP] All reconnect attempts failed. Tools unavailable until transport is restored.");
|
|
157223
|
+
const buffered = [...this.pendingRequests];
|
|
157224
|
+
this.pendingRequests = [];
|
|
157225
|
+
for (const { reject } of buffered) {
|
|
157226
|
+
reject(new Error("MCP connection lost and reconnect failed"));
|
|
157227
|
+
}
|
|
157228
|
+
}
|
|
156610
157229
|
/**
|
|
156611
157230
|
* Stop the MCP server
|
|
156612
157231
|
*/
|
|
@@ -157092,11 +157711,12 @@ var MCPProtocolServer = class {
|
|
|
157092
157711
|
this.registerTool({
|
|
157093
157712
|
definition: {
|
|
157094
157713
|
name: "memory_query",
|
|
157095
|
-
description: "Query memory with pattern matching",
|
|
157714
|
+
description: "Query memory with pattern matching or HNSW semantic search",
|
|
157096
157715
|
category: "memory",
|
|
157097
157716
|
parameters: [
|
|
157098
|
-
{ name: "pattern", type: "string", description: "Key pattern" },
|
|
157099
|
-
{ name: "namespace", type: "string", description: "Memory namespace" }
|
|
157717
|
+
{ name: "pattern", type: "string", description: "Key pattern (glob) or natural language query (for semantic search)" },
|
|
157718
|
+
{ name: "namespace", type: "string", description: "Memory namespace" },
|
|
157719
|
+
{ name: "semantic", type: "boolean", description: "Use HNSW vector search instead of pattern matching. Auto-detected when pattern contains spaces and no wildcards." }
|
|
157100
157720
|
]
|
|
157101
157721
|
},
|
|
157102
157722
|
handler: (params) => handleMemoryQuery(params)
|