agentic-qe 3.6.14 → 3.6.16
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/skills/skills-manifest.json +1 -1
- package/package.json +3 -2
- package/v3/CHANGELOG.md +42 -0
- package/v3/dist/cli/bundle.js +911 -354
- package/v3/dist/cli/commands/test.d.ts.map +1 -1
- package/v3/dist/cli/commands/test.js +6 -3
- package/v3/dist/cli/commands/test.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 +74 -27
- 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 +77 -21
- 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 +92 -17
- 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 +74 -15
- 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.d.ts.map +1 -1
- package/v3/dist/domains/test-generation/services/pattern-matcher.js +34 -7
- 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 +42 -9
- package/v3/dist/domains/test-generation/services/test-generator.js.map +1 -1
- package/v3/dist/mcp/bundle.js +550 -78
- 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/shared/sql-safety.d.ts +3 -0
- package/v3/dist/shared/sql-safety.d.ts.map +1 -1
- package/v3/dist/shared/sql-safety.js +12 -2
- package/v3/dist/shared/sql-safety.js.map +1 -1
- package/v3/dist/sync/cloud/postgres-writer.d.ts +6 -1
- package/v3/dist/sync/cloud/postgres-writer.d.ts.map +1 -1
- package/v3/dist/sync/cloud/postgres-writer.js +121 -46
- package/v3/dist/sync/cloud/postgres-writer.js.map +1 -1
- package/v3/dist/sync/interfaces.d.ts.map +1 -1
- package/v3/dist/sync/interfaces.js +97 -32
- package/v3/dist/sync/interfaces.js.map +1 -1
- package/v3/dist/sync/sync-agent.d.ts.map +1 -1
- package/v3/dist/sync/sync-agent.js +8 -24
- package/v3/dist/sync/sync-agent.js.map +1 -1
- package/v3/package.json +1 -1
package/v3/dist/cli/bundle.js
CHANGED
|
@@ -14,7 +14,7 @@ var __require = /* @__PURE__ */ ((x67) => typeof require !== "undefined" ? requi
|
|
|
14
14
|
var __esm = (fn, res) => function __init() {
|
|
15
15
|
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
16
16
|
};
|
|
17
|
-
var __commonJS = (cb, mod) => function
|
|
17
|
+
var __commonJS = (cb, mod) => function __require9() {
|
|
18
18
|
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
19
19
|
};
|
|
20
20
|
var __export = (target, all) => {
|
|
@@ -1082,11 +1082,19 @@ function validateTableName(tableName) {
|
|
|
1082
1082
|
return tableName;
|
|
1083
1083
|
}
|
|
1084
1084
|
function validateIdentifier(name) {
|
|
1085
|
-
|
|
1085
|
+
const parts = name.split(".");
|
|
1086
|
+
if (parts.length > 2) {
|
|
1086
1087
|
throw new Error(
|
|
1087
|
-
`Invalid SQL identifier: "${name}"
|
|
1088
|
+
`Invalid SQL identifier: "${name}" has too many parts (max: schema.table)`
|
|
1088
1089
|
);
|
|
1089
1090
|
}
|
|
1091
|
+
for (const part of parts) {
|
|
1092
|
+
if (!IDENTIFIER_REGEX.test(part)) {
|
|
1093
|
+
throw new Error(
|
|
1094
|
+
`Invalid SQL identifier: "${name}" \u2014 part "${part}" does not match pattern ${IDENTIFIER_REGEX}`
|
|
1095
|
+
);
|
|
1096
|
+
}
|
|
1097
|
+
}
|
|
1090
1098
|
return name;
|
|
1091
1099
|
}
|
|
1092
1100
|
var ALLOWED_TABLE_NAMES, IDENTIFIER_REGEX;
|
|
@@ -16856,63 +16864,6 @@ var init_hnswlib_node = __esm({
|
|
|
16856
16864
|
}
|
|
16857
16865
|
});
|
|
16858
16866
|
|
|
16859
|
-
// native-require:pg
|
|
16860
|
-
var pg_exports = {};
|
|
16861
|
-
__export(pg_exports, {
|
|
16862
|
-
DotProductAttention: () => DotProductAttention7,
|
|
16863
|
-
FlashAttention: () => FlashAttention7,
|
|
16864
|
-
HyperbolicAttention: () => HyperbolicAttention7,
|
|
16865
|
-
LinearAttention: () => LinearAttention7,
|
|
16866
|
-
MoEAttention: () => MoEAttention7,
|
|
16867
|
-
MultiHeadAttention: () => MultiHeadAttention7,
|
|
16868
|
-
RuvectorLayer: () => RuvectorLayer7,
|
|
16869
|
-
SonaEngine: () => SonaEngine7,
|
|
16870
|
-
TensorCompress: () => TensorCompress7,
|
|
16871
|
-
default: () => pg_default,
|
|
16872
|
-
differentiableSearch: () => differentiableSearch7,
|
|
16873
|
-
getCompressionLevel: () => getCompressionLevel7,
|
|
16874
|
-
hierarchicalForward: () => hierarchicalForward7,
|
|
16875
|
-
init: () => init7,
|
|
16876
|
-
pipeline: () => pipeline8
|
|
16877
|
-
});
|
|
16878
|
-
import { createRequire as createRequire7 } from "module";
|
|
16879
|
-
var __require8, __mod7, pg_default, RuvectorLayer7, TensorCompress7, differentiableSearch7, hierarchicalForward7, getCompressionLevel7, init7, FlashAttention7, DotProductAttention7, MultiHeadAttention7, HyperbolicAttention7, LinearAttention7, MoEAttention7, SonaEngine7, pipeline8;
|
|
16880
|
-
var init_pg = __esm({
|
|
16881
|
-
"native-require:pg"() {
|
|
16882
|
-
__require8 = createRequire7(import.meta.url);
|
|
16883
|
-
__mod7 = __require8("pg");
|
|
16884
|
-
pg_default = __mod7;
|
|
16885
|
-
({
|
|
16886
|
-
RuvectorLayer: (
|
|
16887
|
-
// @ruvector/gnn
|
|
16888
|
-
RuvectorLayer7
|
|
16889
|
-
),
|
|
16890
|
-
TensorCompress: TensorCompress7,
|
|
16891
|
-
differentiableSearch: differentiableSearch7,
|
|
16892
|
-
hierarchicalForward: hierarchicalForward7,
|
|
16893
|
-
getCompressionLevel: getCompressionLevel7,
|
|
16894
|
-
init: init7,
|
|
16895
|
-
FlashAttention: (
|
|
16896
|
-
// @ruvector/attention
|
|
16897
|
-
FlashAttention7
|
|
16898
|
-
),
|
|
16899
|
-
DotProductAttention: DotProductAttention7,
|
|
16900
|
-
MultiHeadAttention: MultiHeadAttention7,
|
|
16901
|
-
HyperbolicAttention: HyperbolicAttention7,
|
|
16902
|
-
LinearAttention: LinearAttention7,
|
|
16903
|
-
MoEAttention: MoEAttention7,
|
|
16904
|
-
SonaEngine: (
|
|
16905
|
-
// @ruvector/sona
|
|
16906
|
-
SonaEngine7
|
|
16907
|
-
),
|
|
16908
|
-
pipeline: (
|
|
16909
|
-
// @xenova/transformers
|
|
16910
|
-
pipeline8
|
|
16911
|
-
)
|
|
16912
|
-
} = __mod7 || {});
|
|
16913
|
-
}
|
|
16914
|
-
});
|
|
16915
|
-
|
|
16916
16867
|
// src/learning/qe-reasoning-bank.ts
|
|
16917
16868
|
var qe_reasoning_bank_exports = {};
|
|
16918
16869
|
__export(qe_reasoning_bank_exports, {
|
|
@@ -18314,57 +18265,57 @@ On promotion:
|
|
|
18314
18265
|
// native-require:prime-radiant-advanced-wasm
|
|
18315
18266
|
var prime_radiant_advanced_wasm_exports = {};
|
|
18316
18267
|
__export(prime_radiant_advanced_wasm_exports, {
|
|
18317
|
-
DotProductAttention: () =>
|
|
18318
|
-
FlashAttention: () =>
|
|
18319
|
-
HyperbolicAttention: () =>
|
|
18320
|
-
LinearAttention: () =>
|
|
18321
|
-
MoEAttention: () =>
|
|
18322
|
-
MultiHeadAttention: () =>
|
|
18323
|
-
RuvectorLayer: () =>
|
|
18324
|
-
SonaEngine: () =>
|
|
18325
|
-
TensorCompress: () =>
|
|
18268
|
+
DotProductAttention: () => DotProductAttention7,
|
|
18269
|
+
FlashAttention: () => FlashAttention7,
|
|
18270
|
+
HyperbolicAttention: () => HyperbolicAttention7,
|
|
18271
|
+
LinearAttention: () => LinearAttention7,
|
|
18272
|
+
MoEAttention: () => MoEAttention7,
|
|
18273
|
+
MultiHeadAttention: () => MultiHeadAttention7,
|
|
18274
|
+
RuvectorLayer: () => RuvectorLayer7,
|
|
18275
|
+
SonaEngine: () => SonaEngine7,
|
|
18276
|
+
TensorCompress: () => TensorCompress7,
|
|
18326
18277
|
default: () => prime_radiant_advanced_wasm_default,
|
|
18327
|
-
differentiableSearch: () =>
|
|
18328
|
-
getCompressionLevel: () =>
|
|
18329
|
-
hierarchicalForward: () =>
|
|
18330
|
-
init: () =>
|
|
18331
|
-
pipeline: () =>
|
|
18278
|
+
differentiableSearch: () => differentiableSearch7,
|
|
18279
|
+
getCompressionLevel: () => getCompressionLevel7,
|
|
18280
|
+
hierarchicalForward: () => hierarchicalForward7,
|
|
18281
|
+
init: () => init7,
|
|
18282
|
+
pipeline: () => pipeline8
|
|
18332
18283
|
});
|
|
18333
18284
|
import { createRequire as createRequire8 } from "module";
|
|
18334
|
-
var
|
|
18285
|
+
var __require8, __mod7, prime_radiant_advanced_wasm_default, RuvectorLayer7, TensorCompress7, differentiableSearch7, hierarchicalForward7, getCompressionLevel7, init7, FlashAttention7, DotProductAttention7, MultiHeadAttention7, HyperbolicAttention7, LinearAttention7, MoEAttention7, SonaEngine7, pipeline8;
|
|
18335
18286
|
var init_prime_radiant_advanced_wasm = __esm({
|
|
18336
18287
|
"native-require:prime-radiant-advanced-wasm"() {
|
|
18337
|
-
|
|
18338
|
-
|
|
18339
|
-
prime_radiant_advanced_wasm_default =
|
|
18288
|
+
__require8 = createRequire8(import.meta.url);
|
|
18289
|
+
__mod7 = __require8("prime-radiant-advanced-wasm");
|
|
18290
|
+
prime_radiant_advanced_wasm_default = __mod7;
|
|
18340
18291
|
({
|
|
18341
18292
|
RuvectorLayer: (
|
|
18342
18293
|
// @ruvector/gnn
|
|
18343
|
-
|
|
18294
|
+
RuvectorLayer7
|
|
18344
18295
|
),
|
|
18345
|
-
TensorCompress:
|
|
18346
|
-
differentiableSearch:
|
|
18347
|
-
hierarchicalForward:
|
|
18348
|
-
getCompressionLevel:
|
|
18349
|
-
init:
|
|
18296
|
+
TensorCompress: TensorCompress7,
|
|
18297
|
+
differentiableSearch: differentiableSearch7,
|
|
18298
|
+
hierarchicalForward: hierarchicalForward7,
|
|
18299
|
+
getCompressionLevel: getCompressionLevel7,
|
|
18300
|
+
init: init7,
|
|
18350
18301
|
FlashAttention: (
|
|
18351
18302
|
// @ruvector/attention
|
|
18352
|
-
|
|
18303
|
+
FlashAttention7
|
|
18353
18304
|
),
|
|
18354
|
-
DotProductAttention:
|
|
18355
|
-
MultiHeadAttention:
|
|
18356
|
-
HyperbolicAttention:
|
|
18357
|
-
LinearAttention:
|
|
18358
|
-
MoEAttention:
|
|
18305
|
+
DotProductAttention: DotProductAttention7,
|
|
18306
|
+
MultiHeadAttention: MultiHeadAttention7,
|
|
18307
|
+
HyperbolicAttention: HyperbolicAttention7,
|
|
18308
|
+
LinearAttention: LinearAttention7,
|
|
18309
|
+
MoEAttention: MoEAttention7,
|
|
18359
18310
|
SonaEngine: (
|
|
18360
18311
|
// @ruvector/sona
|
|
18361
|
-
|
|
18312
|
+
SonaEngine7
|
|
18362
18313
|
),
|
|
18363
18314
|
pipeline: (
|
|
18364
18315
|
// @xenova/transformers
|
|
18365
|
-
|
|
18316
|
+
pipeline8
|
|
18366
18317
|
)
|
|
18367
|
-
} =
|
|
18318
|
+
} = __mod7 || {});
|
|
18368
18319
|
}
|
|
18369
18320
|
});
|
|
18370
18321
|
|
|
@@ -25357,7 +25308,7 @@ var BaseTestGenerator = class _BaseTestGenerator {
|
|
|
25357
25308
|
for (const [typeKey, generator] of _BaseTestGenerator.TYPE_VALUE_TABLE) {
|
|
25358
25309
|
if (type.includes(typeKey)) return generator();
|
|
25359
25310
|
}
|
|
25360
|
-
return `
|
|
25311
|
+
return `{} /* TODO: provide ${param.name}: ${param.type || "unknown"} */`;
|
|
25361
25312
|
}
|
|
25362
25313
|
/**
|
|
25363
25314
|
* Generate test cases for a function based on its signature
|
|
@@ -25370,21 +25321,62 @@ var BaseTestGenerator = class _BaseTestGenerator {
|
|
|
25370
25321
|
const testCases = [];
|
|
25371
25322
|
const validParams = fn.parameters.map((p74) => this.generateTestValue(p74)).join(", ");
|
|
25372
25323
|
const fnCall = fn.isAsync ? `await ${fn.name}(${validParams})` : `${fn.name}(${validParams})`;
|
|
25324
|
+
const isVoid = fn.returnType === "void" || fn.returnType === "Promise<void>";
|
|
25325
|
+
let assertion = "expect(result).toBeDefined();";
|
|
25326
|
+
if (!isVoid) {
|
|
25327
|
+
if (/^(is|has|can)[A-Z]/.test(fn.name)) {
|
|
25328
|
+
assertion = "expect(typeof result).toBe('boolean');";
|
|
25329
|
+
} else if (/^(get|fetch|find)[A-Z]/.test(fn.name)) {
|
|
25330
|
+
assertion = "expect(result).not.toBeUndefined();";
|
|
25331
|
+
} else if (/^(create|build|make)[A-Z]/.test(fn.name)) {
|
|
25332
|
+
assertion = "expect(result).toBeTruthy();";
|
|
25333
|
+
} else if (fn.returnType) {
|
|
25334
|
+
const rt3 = fn.returnType.toLowerCase().replace(/promise<(.+)>/, "$1");
|
|
25335
|
+
if (rt3.includes("boolean")) assertion = "expect(typeof result).toBe('boolean');";
|
|
25336
|
+
else if (rt3.includes("number")) assertion = "expect(typeof result).toBe('number');";
|
|
25337
|
+
else if (rt3.includes("string")) assertion = "expect(typeof result).toBe('string');";
|
|
25338
|
+
else if (rt3.includes("[]") || rt3.includes("array")) assertion = "expect(Array.isArray(result)).toBe(true);";
|
|
25339
|
+
}
|
|
25340
|
+
}
|
|
25373
25341
|
testCases.push({
|
|
25374
25342
|
description: "should handle valid input correctly",
|
|
25375
25343
|
type: "happy-path",
|
|
25376
|
-
action: `const result = ${fnCall};`,
|
|
25377
|
-
assertion:
|
|
25344
|
+
action: isVoid ? `${fnCall};` : `const result = ${fnCall};`,
|
|
25345
|
+
assertion: isVoid ? `// void function \u2014 no return value to assert` : assertion
|
|
25378
25346
|
});
|
|
25347
|
+
const bodyText = fn.body || "";
|
|
25348
|
+
const hasExplicitThrow = /\bthrow\b/.test(bodyText) || /\bvalidat/i.test(bodyText);
|
|
25379
25349
|
for (const param of fn.parameters) {
|
|
25380
25350
|
if (!param.optional) {
|
|
25381
25351
|
const paramsWithUndefined = fn.parameters.map((p74) => p74.name === param.name ? "undefined" : this.generateTestValue(p74)).join(", ");
|
|
25382
|
-
|
|
25383
|
-
|
|
25384
|
-
|
|
25385
|
-
|
|
25386
|
-
|
|
25387
|
-
|
|
25352
|
+
if (hasExplicitThrow) {
|
|
25353
|
+
testCases.push({
|
|
25354
|
+
description: `should handle undefined ${param.name}`,
|
|
25355
|
+
type: "error-handling",
|
|
25356
|
+
action: fn.isAsync ? `const action = async () => await ${fn.name}(${paramsWithUndefined});` : `const action = () => ${fn.name}(${paramsWithUndefined});`,
|
|
25357
|
+
assertion: "expect(action).toThrow();"
|
|
25358
|
+
});
|
|
25359
|
+
} else {
|
|
25360
|
+
const undefinedCall = fn.isAsync ? `await ${fn.name}(${paramsWithUndefined})` : `${fn.name}(${paramsWithUndefined})`;
|
|
25361
|
+
testCases.push({
|
|
25362
|
+
description: `should handle undefined ${param.name}`,
|
|
25363
|
+
type: "edge-case",
|
|
25364
|
+
action: fn.isAsync ? `let threw = false;
|
|
25365
|
+
try {
|
|
25366
|
+
await ${fn.name}(${paramsWithUndefined});
|
|
25367
|
+
} catch (e) {
|
|
25368
|
+
threw = true;
|
|
25369
|
+
expect(e).toBeInstanceOf(Error);
|
|
25370
|
+
}` : `let threw = false;
|
|
25371
|
+
try {
|
|
25372
|
+
${fn.name}(${paramsWithUndefined});
|
|
25373
|
+
} catch (e) {
|
|
25374
|
+
threw = true;
|
|
25375
|
+
expect(e).toBeInstanceOf(Error);
|
|
25376
|
+
}`,
|
|
25377
|
+
assertion: `expect(true).toBe(true); // function either handles undefined or throws TypeError`
|
|
25378
|
+
});
|
|
25379
|
+
}
|
|
25388
25380
|
}
|
|
25389
25381
|
testCases.push(...this.generateBoundaryTestCases(fn, param));
|
|
25390
25382
|
}
|
|
@@ -25404,32 +25396,48 @@ var BaseTestGenerator = class _BaseTestGenerator {
|
|
|
25404
25396
|
generateBoundaryTestCases(fn, param) {
|
|
25405
25397
|
const testCases = [];
|
|
25406
25398
|
const type = param.type?.toLowerCase() || "";
|
|
25399
|
+
const wrapBoundaryAction = (call, isAsync) => {
|
|
25400
|
+
if (isAsync) {
|
|
25401
|
+
return `try {
|
|
25402
|
+
const result = await ${call};
|
|
25403
|
+
expect(result).toBeDefined();
|
|
25404
|
+
} catch (e) {
|
|
25405
|
+
expect(e).toBeInstanceOf(Error);
|
|
25406
|
+
}`;
|
|
25407
|
+
}
|
|
25408
|
+
return `try {
|
|
25409
|
+
const result = ${call};
|
|
25410
|
+
expect(result).toBeDefined();
|
|
25411
|
+
} catch (e) {
|
|
25412
|
+
expect(e).toBeInstanceOf(Error);
|
|
25413
|
+
}`;
|
|
25414
|
+
};
|
|
25407
25415
|
if (type.includes("string")) {
|
|
25408
25416
|
const paramsWithEmpty = fn.parameters.map((p74) => p74.name === param.name ? "''" : this.generateTestValue(p74)).join(", ");
|
|
25409
|
-
const emptyCall =
|
|
25417
|
+
const emptyCall = `${fn.name}(${paramsWithEmpty})`;
|
|
25410
25418
|
testCases.push({
|
|
25411
25419
|
description: `should handle empty string for ${param.name}`,
|
|
25412
25420
|
type: "boundary",
|
|
25413
|
-
action:
|
|
25414
|
-
assertion: "
|
|
25421
|
+
action: wrapBoundaryAction(emptyCall, fn.isAsync),
|
|
25422
|
+
assertion: ""
|
|
25415
25423
|
});
|
|
25416
25424
|
}
|
|
25417
25425
|
if (type.includes("number")) {
|
|
25418
25426
|
const paramsWithZero = fn.parameters.map((p74) => p74.name === param.name ? "0" : this.generateTestValue(p74)).join(", ");
|
|
25419
|
-
const zeroCall =
|
|
25427
|
+
const zeroCall = `${fn.name}(${paramsWithZero})`;
|
|
25420
25428
|
testCases.push({
|
|
25421
25429
|
description: `should handle zero for ${param.name}`,
|
|
25422
25430
|
type: "boundary",
|
|
25423
|
-
action:
|
|
25424
|
-
assertion: "
|
|
25431
|
+
action: wrapBoundaryAction(zeroCall, fn.isAsync),
|
|
25432
|
+
assertion: ""
|
|
25425
25433
|
});
|
|
25426
25434
|
const paramsWithNegative = fn.parameters.map((p74) => p74.name === param.name ? "-1" : this.generateTestValue(p74)).join(", ");
|
|
25427
|
-
const negativeCall =
|
|
25435
|
+
const negativeCall = `${fn.name}(${paramsWithNegative})`;
|
|
25428
25436
|
testCases.push({
|
|
25429
25437
|
description: `should handle negative value for ${param.name}`,
|
|
25430
25438
|
type: "edge-case",
|
|
25431
|
-
action:
|
|
25432
|
-
assertion: "
|
|
25439
|
+
action: wrapBoundaryAction(negativeCall, fn.isAsync),
|
|
25440
|
+
assertion: ""
|
|
25433
25441
|
});
|
|
25434
25442
|
}
|
|
25435
25443
|
if (type.includes("[]") || type.includes("array")) {
|
|
@@ -25527,24 +25535,31 @@ ${importStatement}
|
|
|
25527
25535
|
`;
|
|
25528
25536
|
if (dependencies && dependencies.imports.length > 0) {
|
|
25529
25537
|
const mockFn = this.framework === "vitest" ? "vi.fn()" : "jest.fn()";
|
|
25530
|
-
|
|
25538
|
+
const externalDeps = dependencies.imports.filter((dep) => !dep.startsWith("."));
|
|
25539
|
+
if (externalDeps.length > 0) {
|
|
25540
|
+
testCode += `
|
|
25531
25541
|
// Auto-generated mocks from Knowledge Graph dependency analysis
|
|
25532
25542
|
`;
|
|
25533
|
-
|
|
25534
|
-
|
|
25535
|
-
testCode += `${this.framework === "vitest" ? "vi" : "jest"}.mock('${dep}', () => ({ default: ${mockFn} }));
|
|
25543
|
+
for (const dep of externalDeps.slice(0, 10)) {
|
|
25544
|
+
testCode += `${this.framework === "vitest" ? "vi" : "jest"}.mock('${dep}', () => ({ default: ${mockFn} }));
|
|
25536
25545
|
`;
|
|
25537
|
-
|
|
25538
|
-
|
|
25546
|
+
}
|
|
25547
|
+
testCode += `
|
|
25548
|
+
`;
|
|
25549
|
+
} else {
|
|
25550
|
+
testCode += `
|
|
25539
25551
|
`;
|
|
25552
|
+
}
|
|
25540
25553
|
} else {
|
|
25541
25554
|
testCode += `
|
|
25542
25555
|
`;
|
|
25543
25556
|
}
|
|
25544
|
-
|
|
25557
|
+
const exportedFns = analysis.functions.filter((fn) => fn.isExported);
|
|
25558
|
+
const exportedClasses = analysis.classes.filter((cls) => cls.isExported);
|
|
25559
|
+
for (const fn of exportedFns) {
|
|
25545
25560
|
testCode += this.generateFunctionTests(fn, testType);
|
|
25546
25561
|
}
|
|
25547
|
-
for (const cls of
|
|
25562
|
+
for (const cls of exportedClasses) {
|
|
25548
25563
|
testCode += this.generateClassTests(cls, testType);
|
|
25549
25564
|
}
|
|
25550
25565
|
return testCode;
|
|
@@ -25631,24 +25646,68 @@ ${importStatement}
|
|
|
25631
25646
|
const validParams = method.parameters.map((p74) => this.generateTestValue(p74)).join(", ");
|
|
25632
25647
|
const methodCall = method.isAsync ? `await instance.${method.name}(${validParams})` : `instance.${method.name}(${validParams})`;
|
|
25633
25648
|
const asyncPrefix = method.isAsync ? "async " : "";
|
|
25649
|
+
const isVoid = method.returnType === "void" || method.returnType === "Promise<void>";
|
|
25650
|
+
let methodAssertion = "expect(result).toBeDefined();";
|
|
25651
|
+
if (!isVoid) {
|
|
25652
|
+
if (/^(is|has|can)[A-Z]/.test(method.name)) {
|
|
25653
|
+
methodAssertion = "expect(typeof result).toBe('boolean');";
|
|
25654
|
+
} else if (/^(get|fetch|find)[A-Z]/.test(method.name)) {
|
|
25655
|
+
methodAssertion = "expect(result).not.toBeUndefined();";
|
|
25656
|
+
} else if (/^(create|build|make)[A-Z]/.test(method.name)) {
|
|
25657
|
+
methodAssertion = "expect(result).toBeTruthy();";
|
|
25658
|
+
} else if (method.returnType) {
|
|
25659
|
+
const mrt = method.returnType.toLowerCase().replace(/promise<(.+)>/, "$1");
|
|
25660
|
+
if (mrt.includes("boolean")) methodAssertion = "expect(typeof result).toBe('boolean');";
|
|
25661
|
+
else if (mrt.includes("number")) methodAssertion = "expect(typeof result).toBe('number');";
|
|
25662
|
+
else if (mrt.includes("string")) methodAssertion = "expect(typeof result).toBe('string');";
|
|
25663
|
+
else if (mrt.includes("[]") || mrt.includes("array")) methodAssertion = "expect(Array.isArray(result)).toBe(true);";
|
|
25664
|
+
}
|
|
25665
|
+
}
|
|
25634
25666
|
code += ` it('should execute successfully', ${asyncPrefix}() => {
|
|
25635
25667
|
`;
|
|
25636
|
-
|
|
25668
|
+
if (isVoid) {
|
|
25669
|
+
code += ` ${methodCall};
|
|
25637
25670
|
`;
|
|
25638
|
-
|
|
25671
|
+
code += ` // void return \u2014 no assertion on result needed
|
|
25639
25672
|
`;
|
|
25673
|
+
} else {
|
|
25674
|
+
code += ` const result = ${methodCall};
|
|
25675
|
+
`;
|
|
25676
|
+
code += ` ${methodAssertion}
|
|
25677
|
+
`;
|
|
25678
|
+
}
|
|
25640
25679
|
code += ` });
|
|
25641
25680
|
`;
|
|
25681
|
+
const methodBody = method.body || "";
|
|
25682
|
+
const methodThrows = /\bthrow\b/.test(methodBody) || /\bvalidat/i.test(methodBody);
|
|
25642
25683
|
for (const param of method.parameters) {
|
|
25643
25684
|
if (!param.optional) {
|
|
25644
25685
|
const paramsWithUndefined = method.parameters.map((p74) => p74.name === param.name ? "undefined as any" : this.generateTestValue(p74)).join(", ");
|
|
25645
|
-
|
|
25646
|
-
|
|
25686
|
+
if (methodThrows) {
|
|
25687
|
+
code += `
|
|
25688
|
+
it('should handle invalid ${param.name}', ${asyncPrefix}() => {
|
|
25647
25689
|
`;
|
|
25648
|
-
|
|
25690
|
+
code += ` expect(() => instance.${method.name}(${paramsWithUndefined})).toThrow();
|
|
25649
25691
|
`;
|
|
25650
|
-
|
|
25692
|
+
code += ` });
|
|
25651
25693
|
`;
|
|
25694
|
+
} else {
|
|
25695
|
+
code += `
|
|
25696
|
+
it('should handle undefined ${param.name}', ${asyncPrefix}() => {
|
|
25697
|
+
`;
|
|
25698
|
+
code += ` try {
|
|
25699
|
+
`;
|
|
25700
|
+
code += ` ${method.isAsync ? "await " : ""}instance.${method.name}(${paramsWithUndefined});
|
|
25701
|
+
`;
|
|
25702
|
+
code += ` } catch (e) {
|
|
25703
|
+
`;
|
|
25704
|
+
code += ` expect(e).toBeInstanceOf(Error);
|
|
25705
|
+
`;
|
|
25706
|
+
code += ` }
|
|
25707
|
+
`;
|
|
25708
|
+
code += ` });
|
|
25709
|
+
`;
|
|
25710
|
+
}
|
|
25652
25711
|
}
|
|
25653
25712
|
}
|
|
25654
25713
|
code += ` });
|
|
@@ -25668,12 +25727,15 @@ ${importStatement}
|
|
|
25668
25727
|
let mockDeclarations = "";
|
|
25669
25728
|
if (dependencies && dependencies.imports.length > 0) {
|
|
25670
25729
|
const mockFn = this.framework === "vitest" ? "vi.fn()" : "jest.fn()";
|
|
25671
|
-
|
|
25730
|
+
const externalDeps = dependencies.imports.filter((dep) => !dep.startsWith("."));
|
|
25731
|
+
if (externalDeps.length > 0) {
|
|
25732
|
+
mockDeclarations += `
|
|
25672
25733
|
// Auto-generated mocks from Knowledge Graph dependency analysis
|
|
25673
25734
|
`;
|
|
25674
|
-
|
|
25675
|
-
|
|
25735
|
+
for (const dep of externalDeps.slice(0, 10)) {
|
|
25736
|
+
mockDeclarations += `${this.mockUtil}.mock('${dep}', () => ({ default: ${mockFn} }));
|
|
25676
25737
|
`;
|
|
25738
|
+
}
|
|
25677
25739
|
}
|
|
25678
25740
|
}
|
|
25679
25741
|
let similarityComment = "";
|
|
@@ -25950,10 +26012,11 @@ var MochaGenerator = class extends BaseTestGenerator {
|
|
|
25950
26012
|
const importStatement = this.generateImportStatement(exports, importPath, moduleName);
|
|
25951
26013
|
let sinonImport = "";
|
|
25952
26014
|
let stubSetup = "";
|
|
25953
|
-
|
|
26015
|
+
const externalDeps = dependencies?.imports.filter((dep) => !dep.startsWith(".")) || [];
|
|
26016
|
+
if (externalDeps.length > 0) {
|
|
25954
26017
|
sinonImport = `import sinon from 'sinon';
|
|
25955
26018
|
`;
|
|
25956
|
-
const depsToMock =
|
|
26019
|
+
const depsToMock = externalDeps.slice(0, 5);
|
|
25957
26020
|
stubSetup += ` // Auto-generated stubs from Knowledge Graph dependency analysis
|
|
25958
26021
|
`;
|
|
25959
26022
|
stubSetup += ` let stubs;
|
|
@@ -25986,10 +26049,12 @@ ${sinonImport}${importStatement}
|
|
|
25986
26049
|
|
|
25987
26050
|
describe('${moduleName} - ${testType} tests', function() {
|
|
25988
26051
|
${stubSetup}`;
|
|
25989
|
-
|
|
26052
|
+
const exportedFns = analysis.functions.filter((fn) => fn.isExported);
|
|
26053
|
+
const exportedClasses = analysis.classes.filter((cls) => cls.isExported);
|
|
26054
|
+
for (const fn of exportedFns) {
|
|
25990
26055
|
code += this.generateFunctionTests(fn, testType);
|
|
25991
26056
|
}
|
|
25992
|
-
for (const cls of
|
|
26057
|
+
for (const cls of exportedClasses) {
|
|
25993
26058
|
code += this.generateClassTests(cls, testType);
|
|
25994
26059
|
}
|
|
25995
26060
|
code += `});
|
|
@@ -26002,26 +26067,68 @@ ${stubSetup}`;
|
|
|
26002
26067
|
generateFunctionTests(fn, _testType) {
|
|
26003
26068
|
const validParams = fn.parameters.map((p74) => this.generateTestValue(p74)).join(", ");
|
|
26004
26069
|
const fnCall = fn.isAsync ? `await ${fn.name}(${validParams})` : `${fn.name}(${validParams})`;
|
|
26070
|
+
const isVoid = fn.returnType === "void" || fn.returnType === "Promise<void>";
|
|
26005
26071
|
let code = ` describe('${fn.name}', function() {
|
|
26006
26072
|
`;
|
|
26073
|
+
let chaiAssertion = "expect(result).to.not.be.undefined;";
|
|
26074
|
+
if (!isVoid) {
|
|
26075
|
+
if (/^(is|has|can)[A-Z]/.test(fn.name)) {
|
|
26076
|
+
chaiAssertion = "expect(typeof result).to.equal('boolean');";
|
|
26077
|
+
} else if (/^(get|fetch|find)[A-Z]/.test(fn.name)) {
|
|
26078
|
+
chaiAssertion = "expect(result).to.not.be.undefined;";
|
|
26079
|
+
} else if (/^(create|build|make)[A-Z]/.test(fn.name)) {
|
|
26080
|
+
chaiAssertion = "expect(result).to.be.ok;";
|
|
26081
|
+
} else if (fn.returnType) {
|
|
26082
|
+
const rt3 = fn.returnType.toLowerCase().replace(/promise<(.+)>/, "$1");
|
|
26083
|
+
if (rt3.includes("boolean")) chaiAssertion = "expect(typeof result).to.equal('boolean');";
|
|
26084
|
+
else if (rt3.includes("number")) chaiAssertion = "expect(typeof result).to.equal('number');";
|
|
26085
|
+
else if (rt3.includes("string")) chaiAssertion = "expect(typeof result).to.equal('string');";
|
|
26086
|
+
else if (rt3.includes("[]") || rt3.includes("array")) chaiAssertion = "expect(result).to.be.an('array');";
|
|
26087
|
+
}
|
|
26088
|
+
}
|
|
26007
26089
|
code += ` it('should handle valid input', ${fn.isAsync ? "async " : ""}function() {
|
|
26008
26090
|
`;
|
|
26009
|
-
|
|
26091
|
+
if (isVoid) {
|
|
26092
|
+
code += ` ${fnCall};
|
|
26093
|
+
`;
|
|
26094
|
+
} else {
|
|
26095
|
+
code += ` const result = ${fnCall};
|
|
26010
26096
|
`;
|
|
26011
|
-
|
|
26097
|
+
code += ` ${chaiAssertion}
|
|
26012
26098
|
`;
|
|
26099
|
+
}
|
|
26013
26100
|
code += ` });
|
|
26014
26101
|
`;
|
|
26102
|
+
const bodyText = fn.body || "";
|
|
26103
|
+
const hasExplicitThrow = /\bthrow\b/.test(bodyText) || /\bvalidat/i.test(bodyText);
|
|
26015
26104
|
for (const param of fn.parameters) {
|
|
26016
26105
|
if (!param.optional) {
|
|
26017
26106
|
const paramsWithUndefined = fn.parameters.map((p74) => p74.name === param.name ? "undefined" : this.generateTestValue(p74)).join(", ");
|
|
26018
|
-
|
|
26107
|
+
if (hasExplicitThrow) {
|
|
26108
|
+
code += `
|
|
26019
26109
|
it('should handle undefined ${param.name}', function() {
|
|
26020
26110
|
`;
|
|
26021
|
-
|
|
26111
|
+
code += ` expect(function() { ${fn.name}(${paramsWithUndefined}); }).to.throw();
|
|
26022
26112
|
`;
|
|
26023
|
-
|
|
26113
|
+
code += ` });
|
|
26114
|
+
`;
|
|
26115
|
+
} else {
|
|
26116
|
+
code += `
|
|
26117
|
+
it('should handle undefined ${param.name}', function() {
|
|
26118
|
+
`;
|
|
26119
|
+
code += ` try {
|
|
26120
|
+
`;
|
|
26121
|
+
code += ` ${fn.name}(${paramsWithUndefined});
|
|
26122
|
+
`;
|
|
26123
|
+
code += ` } catch (e) {
|
|
26124
|
+
`;
|
|
26125
|
+
code += ` expect(e).to.be.instanceOf(Error);
|
|
26024
26126
|
`;
|
|
26127
|
+
code += ` }
|
|
26128
|
+
`;
|
|
26129
|
+
code += ` });
|
|
26130
|
+
`;
|
|
26131
|
+
}
|
|
26025
26132
|
}
|
|
26026
26133
|
}
|
|
26027
26134
|
code += ` });
|
|
@@ -26053,15 +26160,35 @@ ${stubSetup}`;
|
|
|
26053
26160
|
code += ` });
|
|
26054
26161
|
`;
|
|
26055
26162
|
for (const method of cls.methods) {
|
|
26056
|
-
if (!method.name.startsWith("_")) {
|
|
26163
|
+
if (!method.name.startsWith("_") && !method.name.startsWith("#")) {
|
|
26057
26164
|
const methodParams = method.parameters.map((p74) => this.generateTestValue(p74)).join(", ");
|
|
26165
|
+
const isMethodVoid = method.returnType === "void" || method.returnType === "Promise<void>";
|
|
26166
|
+
let methodAssertion = "expect(result).to.not.be.undefined;";
|
|
26167
|
+
if (!isMethodVoid) {
|
|
26168
|
+
if (/^(is|has|can)[A-Z]/.test(method.name)) {
|
|
26169
|
+
methodAssertion = "expect(typeof result).to.equal('boolean');";
|
|
26170
|
+
} else if (/^(create|build|make)[A-Z]/.test(method.name)) {
|
|
26171
|
+
methodAssertion = "expect(result).to.be.ok;";
|
|
26172
|
+
} else if (method.returnType) {
|
|
26173
|
+
const mrt = method.returnType.toLowerCase().replace(/promise<(.+)>/, "$1");
|
|
26174
|
+
if (mrt.includes("boolean")) methodAssertion = "expect(typeof result).to.equal('boolean');";
|
|
26175
|
+
else if (mrt.includes("number")) methodAssertion = "expect(typeof result).to.equal('number');";
|
|
26176
|
+
else if (mrt.includes("string")) methodAssertion = "expect(typeof result).to.equal('string');";
|
|
26177
|
+
else if (mrt.includes("[]") || mrt.includes("array")) methodAssertion = "expect(result).to.be.an('array');";
|
|
26178
|
+
}
|
|
26179
|
+
}
|
|
26058
26180
|
code += `
|
|
26059
26181
|
it('${method.name} should work', ${method.isAsync ? "async " : ""}function() {
|
|
26060
26182
|
`;
|
|
26061
|
-
|
|
26183
|
+
if (isMethodVoid) {
|
|
26184
|
+
code += ` ${method.isAsync ? "await " : ""}instance.${method.name}(${methodParams});
|
|
26062
26185
|
`;
|
|
26063
|
-
|
|
26186
|
+
} else {
|
|
26187
|
+
code += ` const result = ${method.isAsync ? "await " : ""}instance.${method.name}(${methodParams});
|
|
26188
|
+
`;
|
|
26189
|
+
code += ` ${methodAssertion}
|
|
26064
26190
|
`;
|
|
26191
|
+
}
|
|
26065
26192
|
code += ` });
|
|
26066
26193
|
`;
|
|
26067
26194
|
}
|
|
@@ -26084,10 +26211,11 @@ ${stubSetup}`;
|
|
|
26084
26211
|
let sinonImport = "";
|
|
26085
26212
|
let stubSetup = "";
|
|
26086
26213
|
let stubTeardown = "";
|
|
26087
|
-
|
|
26214
|
+
const stubExternalDeps = dependencies?.imports.filter((dep) => !dep.startsWith(".")) || [];
|
|
26215
|
+
if (stubExternalDeps.length > 0) {
|
|
26088
26216
|
sinonImport = `import sinon from 'sinon';
|
|
26089
26217
|
`;
|
|
26090
|
-
const depsToMock =
|
|
26218
|
+
const depsToMock = stubExternalDeps.slice(0, 5);
|
|
26091
26219
|
stubSetup += `
|
|
26092
26220
|
// Auto-generated stubs from Knowledge Graph dependency analysis
|
|
26093
26221
|
`;
|
|
@@ -26258,12 +26386,13 @@ var PytestGenerator = class extends BaseTestGenerator {
|
|
|
26258
26386
|
const exports = this.extractExports(analysis.functions, analysis.classes);
|
|
26259
26387
|
const pythonImport = importPath.replace(/\//g, ".").replace(/\.(ts|js)$/, "");
|
|
26260
26388
|
const importStatement = exports.length > 0 ? `from ${pythonImport} import ${exports.join(", ")}` : `import ${pythonImport} as ${moduleName}`;
|
|
26389
|
+
const externalDeps = dependencies?.imports.filter((dep) => !dep.startsWith(".")) || [];
|
|
26261
26390
|
let mockImport = "";
|
|
26262
|
-
if (
|
|
26391
|
+
if (externalDeps.length > 0) {
|
|
26263
26392
|
mockImport = `from unittest.mock import patch, MagicMock
|
|
26264
26393
|
`;
|
|
26265
26394
|
}
|
|
26266
|
-
const depsToMock =
|
|
26395
|
+
const depsToMock = externalDeps.slice(0, 5);
|
|
26267
26396
|
const patchDecorators = depsToMock.map((dep) => {
|
|
26268
26397
|
const depModule = dep.replace(/\//g, ".").replace(/\.py$/, "");
|
|
26269
26398
|
return `@patch('${depModule}')`;
|
|
@@ -26276,10 +26405,12 @@ class Test${this.pascalCase(moduleName)}:
|
|
|
26276
26405
|
"""${testType} tests for ${moduleName}"""
|
|
26277
26406
|
|
|
26278
26407
|
`;
|
|
26279
|
-
|
|
26408
|
+
const exportedFns = analysis.functions.filter((fn) => fn.isExported);
|
|
26409
|
+
const exportedClasses = analysis.classes.filter((cls) => cls.isExported);
|
|
26410
|
+
for (const fn of exportedFns) {
|
|
26280
26411
|
code += this.generateFunctionTestsWithPatches(fn, testType, patchDecorators);
|
|
26281
26412
|
}
|
|
26282
|
-
for (const cls of
|
|
26413
|
+
for (const cls of exportedClasses) {
|
|
26283
26414
|
code += this.generateClassTests(cls, testType);
|
|
26284
26415
|
}
|
|
26285
26416
|
return code;
|
|
@@ -26299,15 +26430,36 @@ class Test${this.pascalCase(moduleName)}:
|
|
|
26299
26430
|
const allParams = mockParams ? `self, ${mockParams}` : "self";
|
|
26300
26431
|
const patchPrefix = patchDecorators.map((d74) => ` ${d74}
|
|
26301
26432
|
`).join("");
|
|
26433
|
+
const isVoid = fn.returnType === "void" || fn.returnType === "Promise<void>" || fn.returnType === "None";
|
|
26302
26434
|
let code = `${patchPrefix} def test_${fn.name}_valid_input(${allParams}):
|
|
26303
26435
|
`;
|
|
26304
26436
|
code += ` """Test ${fn.name} with valid input"""
|
|
26305
26437
|
`;
|
|
26306
|
-
|
|
26438
|
+
let pyAssertion = "assert result is not None";
|
|
26439
|
+
if (!isVoid) {
|
|
26440
|
+
if (/^(is|has|can)[A-Z]/.test(fn.name)) {
|
|
26441
|
+
pyAssertion = "assert isinstance(result, bool)";
|
|
26442
|
+
} else if (/^(create|build|make)[A-Z]/.test(fn.name)) {
|
|
26443
|
+
pyAssertion = "assert result";
|
|
26444
|
+
} else if (fn.returnType) {
|
|
26445
|
+
const rt3 = fn.returnType.toLowerCase().replace(/promise<(.+)>/, "$1");
|
|
26446
|
+
if (rt3.includes("boolean") || rt3.includes("bool")) pyAssertion = "assert isinstance(result, bool)";
|
|
26447
|
+
else if (rt3.includes("number") || rt3.includes("int") || rt3.includes("float")) pyAssertion = "assert isinstance(result, (int, float))";
|
|
26448
|
+
else if (rt3.includes("string") || rt3.includes("str")) pyAssertion = "assert isinstance(result, str)";
|
|
26449
|
+
else if (rt3.includes("[]") || rt3.includes("array") || rt3.includes("list")) pyAssertion = "assert isinstance(result, list)";
|
|
26450
|
+
}
|
|
26451
|
+
}
|
|
26452
|
+
if (isVoid) {
|
|
26453
|
+
code += ` ${fn.name}(${validParams}) # void function
|
|
26454
|
+
|
|
26455
|
+
`;
|
|
26456
|
+
} else {
|
|
26457
|
+
code += ` result = ${fn.name}(${validParams})
|
|
26307
26458
|
`;
|
|
26308
|
-
|
|
26459
|
+
code += ` ${pyAssertion}
|
|
26309
26460
|
|
|
26310
26461
|
`;
|
|
26462
|
+
}
|
|
26311
26463
|
for (const param of fn.parameters) {
|
|
26312
26464
|
if (!param.optional && param.type?.includes("str")) {
|
|
26313
26465
|
code += `${patchPrefix} def test_${fn.name}_empty_${param.name}(${allParams}):
|
|
@@ -26348,15 +26500,36 @@ class Test${cls.name}:
|
|
|
26348
26500
|
|
|
26349
26501
|
`;
|
|
26350
26502
|
for (const method of cls.methods) {
|
|
26351
|
-
if (!method.name.startsWith("_")) {
|
|
26503
|
+
if (!method.name.startsWith("_") && !method.name.startsWith("#")) {
|
|
26352
26504
|
const methodParams = method.parameters.map((p74) => this.generatePythonTestValue(p74)).join(", ");
|
|
26505
|
+
const isMethodVoid = method.returnType === "void" || method.returnType === "Promise<void>";
|
|
26506
|
+
let mAssertion = "assert result is not None";
|
|
26507
|
+
if (!isMethodVoid) {
|
|
26508
|
+
if (/^(is|has|can)[A-Z]/.test(method.name)) {
|
|
26509
|
+
mAssertion = "assert isinstance(result, bool)";
|
|
26510
|
+
} else if (/^(create|build|make)[A-Z]/.test(method.name)) {
|
|
26511
|
+
mAssertion = "assert result";
|
|
26512
|
+
} else if (method.returnType) {
|
|
26513
|
+
const mrt = method.returnType.toLowerCase().replace(/promise<(.+)>/, "$1");
|
|
26514
|
+
if (mrt.includes("boolean") || mrt.includes("bool")) mAssertion = "assert isinstance(result, bool)";
|
|
26515
|
+
else if (mrt.includes("number") || mrt.includes("int") || mrt.includes("float")) mAssertion = "assert isinstance(result, (int, float))";
|
|
26516
|
+
else if (mrt.includes("string") || mrt.includes("str")) mAssertion = "assert isinstance(result, str)";
|
|
26517
|
+
else if (mrt.includes("[]") || mrt.includes("array") || mrt.includes("list")) mAssertion = "assert isinstance(result, list)";
|
|
26518
|
+
}
|
|
26519
|
+
}
|
|
26353
26520
|
code += ` def test_${method.name}(self, instance):
|
|
26354
26521
|
`;
|
|
26355
|
-
|
|
26522
|
+
if (isMethodVoid) {
|
|
26523
|
+
code += ` instance.${method.name}(${methodParams})
|
|
26524
|
+
|
|
26356
26525
|
`;
|
|
26357
|
-
|
|
26526
|
+
} else {
|
|
26527
|
+
code += ` result = instance.${method.name}(${methodParams})
|
|
26528
|
+
`;
|
|
26529
|
+
code += ` ${mAssertion}
|
|
26358
26530
|
|
|
26359
26531
|
`;
|
|
26532
|
+
}
|
|
26360
26533
|
}
|
|
26361
26534
|
}
|
|
26362
26535
|
return code;
|
|
@@ -26374,11 +26547,11 @@ class Test${cls.name}:
|
|
|
26374
26547
|
const asyncDef = isAsync ? "async def" : "def";
|
|
26375
26548
|
let mockImports = "";
|
|
26376
26549
|
let mockPatches = "";
|
|
26377
|
-
|
|
26550
|
+
const stubExternalDeps = dependencies?.imports.filter((dep) => !dep.startsWith(".")) || [];
|
|
26551
|
+
if (stubExternalDeps.length > 0) {
|
|
26378
26552
|
mockImports = `from unittest.mock import patch, MagicMock
|
|
26379
26553
|
`;
|
|
26380
|
-
const
|
|
26381
|
-
for (const dep of depsToMock) {
|
|
26554
|
+
for (const dep of stubExternalDeps.slice(0, 5)) {
|
|
26382
26555
|
const depModule = dep.replace(/\//g, ".").replace(/\.py$/, "");
|
|
26383
26556
|
mockPatches += ` @patch('${depModule}')
|
|
26384
26557
|
`;
|
|
@@ -26541,12 +26714,214 @@ class Test${this.pascalCase(moduleName)}Coverage:
|
|
|
26541
26714
|
}
|
|
26542
26715
|
};
|
|
26543
26716
|
|
|
26717
|
+
// src/domains/test-generation/generators/node-test-generator.ts
|
|
26718
|
+
var NodeTestGenerator = class extends BaseTestGenerator {
|
|
26719
|
+
framework = "node-test";
|
|
26720
|
+
/**
|
|
26721
|
+
* Generate complete test file from analysis
|
|
26722
|
+
*/
|
|
26723
|
+
generateTests(context2) {
|
|
26724
|
+
const { moduleName, importPath, testType, patterns, analysis } = context2;
|
|
26725
|
+
if (!analysis || analysis.functions.length === 0 && analysis.classes.length === 0) {
|
|
26726
|
+
return this.generateStubTests(context2);
|
|
26727
|
+
}
|
|
26728
|
+
const patternComment = this.generatePatternComment(patterns);
|
|
26729
|
+
const exportedFunctions = analysis.functions.filter((fn) => fn.isExported);
|
|
26730
|
+
const exportedClasses = analysis.classes.filter((cls) => cls.isExported);
|
|
26731
|
+
const exports = this.extractExports(exportedFunctions, exportedClasses);
|
|
26732
|
+
const importStatement = this.generateImportStatement(exports, importPath, moduleName);
|
|
26733
|
+
let testCode = `${patternComment}import { describe, it, beforeEach } from 'node:test';
|
|
26734
|
+
import assert from 'node:assert';
|
|
26735
|
+
${importStatement}
|
|
26736
|
+
|
|
26737
|
+
`;
|
|
26738
|
+
for (const fn of exportedFunctions) {
|
|
26739
|
+
testCode += this.generateFunctionTests(fn, testType);
|
|
26740
|
+
}
|
|
26741
|
+
for (const cls of exportedClasses) {
|
|
26742
|
+
testCode += this.generateClassTests(cls, testType);
|
|
26743
|
+
}
|
|
26744
|
+
return testCode;
|
|
26745
|
+
}
|
|
26746
|
+
/**
|
|
26747
|
+
* Generate tests for a standalone function
|
|
26748
|
+
*/
|
|
26749
|
+
generateFunctionTests(fn, _testType) {
|
|
26750
|
+
const testCases = this.generateTestCasesForFunction(fn);
|
|
26751
|
+
let code = `describe('${fn.name}', () => {
|
|
26752
|
+
`;
|
|
26753
|
+
for (const testCase of testCases) {
|
|
26754
|
+
if (testCase.setup) {
|
|
26755
|
+
code += ` ${testCase.setup}
|
|
26756
|
+
|
|
26757
|
+
`;
|
|
26758
|
+
}
|
|
26759
|
+
const asyncPrefix = fn.isAsync ? "async " : "";
|
|
26760
|
+
code += ` it('${testCase.description}', ${asyncPrefix}() => {
|
|
26761
|
+
`;
|
|
26762
|
+
code += ` ${this.convertToAssert(testCase.action)}
|
|
26763
|
+
`;
|
|
26764
|
+
code += ` ${this.convertToAssert(testCase.assertion)}
|
|
26765
|
+
`;
|
|
26766
|
+
code += ` });
|
|
26767
|
+
|
|
26768
|
+
`;
|
|
26769
|
+
}
|
|
26770
|
+
code += `});
|
|
26771
|
+
|
|
26772
|
+
`;
|
|
26773
|
+
return code;
|
|
26774
|
+
}
|
|
26775
|
+
/**
|
|
26776
|
+
* Generate tests for a class
|
|
26777
|
+
*/
|
|
26778
|
+
generateClassTests(cls, testType) {
|
|
26779
|
+
let code = `describe('${cls.name}', () => {
|
|
26780
|
+
`;
|
|
26781
|
+
code += ` let instance;
|
|
26782
|
+
|
|
26783
|
+
`;
|
|
26784
|
+
const constructorArgs = cls.constructorParams?.map((p74) => this.generateTestValue(p74)).join(", ") || "";
|
|
26785
|
+
code += ` beforeEach(() => {
|
|
26786
|
+
`;
|
|
26787
|
+
code += ` instance = new ${cls.name}(${constructorArgs});
|
|
26788
|
+
`;
|
|
26789
|
+
code += ` });
|
|
26790
|
+
|
|
26791
|
+
`;
|
|
26792
|
+
code += ` it('should instantiate correctly', () => {
|
|
26793
|
+
`;
|
|
26794
|
+
code += ` assert.ok(instance instanceof ${cls.name});
|
|
26795
|
+
`;
|
|
26796
|
+
code += ` });
|
|
26797
|
+
|
|
26798
|
+
`;
|
|
26799
|
+
for (const method of cls.methods) {
|
|
26800
|
+
if (!method.name.startsWith("_") && !method.name.startsWith("#")) {
|
|
26801
|
+
code += this.generateMethodTest(method);
|
|
26802
|
+
}
|
|
26803
|
+
}
|
|
26804
|
+
code += `});
|
|
26805
|
+
|
|
26806
|
+
`;
|
|
26807
|
+
return code;
|
|
26808
|
+
}
|
|
26809
|
+
/**
|
|
26810
|
+
* Generate test for a class method
|
|
26811
|
+
*/
|
|
26812
|
+
generateMethodTest(method) {
|
|
26813
|
+
const validParams = method.parameters.map((p74) => this.generateTestValue(p74)).join(", ");
|
|
26814
|
+
const isVoid = method.returnType === "void" || method.returnType === "Promise<void>";
|
|
26815
|
+
const asyncPrefix = method.isAsync ? "async " : "";
|
|
26816
|
+
const methodCall = method.isAsync ? `await instance.${method.name}(${validParams})` : `instance.${method.name}(${validParams})`;
|
|
26817
|
+
let assertLine = "assert.ok(result !== undefined);";
|
|
26818
|
+
if (!isVoid) {
|
|
26819
|
+
const mLower = method.name.toLowerCase();
|
|
26820
|
+
if (/^(is|has|can)[A-Z]/.test(method.name)) {
|
|
26821
|
+
assertLine = "assert.strictEqual(typeof result, 'boolean');";
|
|
26822
|
+
} else if (/^(get|fetch|find)[A-Z]/.test(method.name)) {
|
|
26823
|
+
assertLine = "assert.ok(result !== undefined);";
|
|
26824
|
+
} else if (/^(create|build|make)[A-Z]/.test(method.name)) {
|
|
26825
|
+
assertLine = "assert.ok(result);";
|
|
26826
|
+
} else if (method.returnType) {
|
|
26827
|
+
const rt3 = method.returnType.toLowerCase().replace(/promise<(.+)>/, "$1");
|
|
26828
|
+
if (rt3.includes("boolean")) assertLine = "assert.strictEqual(typeof result, 'boolean');";
|
|
26829
|
+
else if (rt3.includes("number")) assertLine = "assert.strictEqual(typeof result, 'number');";
|
|
26830
|
+
else if (rt3.includes("string")) assertLine = "assert.strictEqual(typeof result, 'string');";
|
|
26831
|
+
else if (rt3.includes("[]") || rt3.includes("array")) assertLine = "assert.ok(Array.isArray(result));";
|
|
26832
|
+
}
|
|
26833
|
+
}
|
|
26834
|
+
let code = ` it('${method.name} should execute successfully', ${asyncPrefix}() => {
|
|
26835
|
+
`;
|
|
26836
|
+
if (isVoid) {
|
|
26837
|
+
code += ` ${methodCall};
|
|
26838
|
+
`;
|
|
26839
|
+
} else {
|
|
26840
|
+
code += ` const result = ${methodCall};
|
|
26841
|
+
`;
|
|
26842
|
+
code += ` ${assertLine}
|
|
26843
|
+
`;
|
|
26844
|
+
}
|
|
26845
|
+
code += ` });
|
|
26846
|
+
|
|
26847
|
+
`;
|
|
26848
|
+
return code;
|
|
26849
|
+
}
|
|
26850
|
+
/**
|
|
26851
|
+
* Generate stub tests when no AST analysis is available
|
|
26852
|
+
*/
|
|
26853
|
+
generateStubTests(context2) {
|
|
26854
|
+
const { moduleName, importPath, testType, patterns } = context2;
|
|
26855
|
+
const patternComment = this.generatePatternComment(patterns);
|
|
26856
|
+
return `${patternComment}import { describe, it } from 'node:test';
|
|
26857
|
+
import assert from 'node:assert';
|
|
26858
|
+
import { ${moduleName} } from '${importPath}';
|
|
26859
|
+
|
|
26860
|
+
describe('${moduleName}', () => {
|
|
26861
|
+
describe('${testType} tests', () => {
|
|
26862
|
+
it('should be defined', () => {
|
|
26863
|
+
assert.ok(${moduleName} !== undefined);
|
|
26864
|
+
});
|
|
26865
|
+
|
|
26866
|
+
it('should handle basic operations', () => {
|
|
26867
|
+
const moduleType = typeof ${moduleName};
|
|
26868
|
+
assert.ok(['function', 'object'].includes(moduleType));
|
|
26869
|
+
});
|
|
26870
|
+
|
|
26871
|
+
it('should handle error conditions', () => {
|
|
26872
|
+
assert.doesNotThrow(() => {
|
|
26873
|
+
const instance = typeof ${moduleName} === 'function'
|
|
26874
|
+
? new ${moduleName}()
|
|
26875
|
+
: ${moduleName};
|
|
26876
|
+
return instance;
|
|
26877
|
+
});
|
|
26878
|
+
});
|
|
26879
|
+
});
|
|
26880
|
+
});
|
|
26881
|
+
`;
|
|
26882
|
+
}
|
|
26883
|
+
/**
|
|
26884
|
+
* Generate coverage-focused tests for specific lines
|
|
26885
|
+
*/
|
|
26886
|
+
generateCoverageTests(moduleName, importPath, lines) {
|
|
26887
|
+
const funcName = this.camelCase(moduleName);
|
|
26888
|
+
const lineRange = this.formatLineRange(lines);
|
|
26889
|
+
return `// Coverage test for ${lineRange} in ${moduleName}
|
|
26890
|
+
import { describe, it } from 'node:test';
|
|
26891
|
+
import assert from 'node:assert';
|
|
26892
|
+
import { ${funcName} } from '${importPath}';
|
|
26893
|
+
|
|
26894
|
+
describe('${moduleName} coverage', () => {
|
|
26895
|
+
it('should exercise code path covering ${lineRange}', () => {
|
|
26896
|
+
const testInput = undefined; // Replace with appropriate input
|
|
26897
|
+
const result = ${funcName}(testInput);
|
|
26898
|
+
assert.ok(result !== undefined || result === undefined);
|
|
26899
|
+
});
|
|
26900
|
+
|
|
26901
|
+
it('should handle edge case for ${lineRange}', () => {
|
|
26902
|
+
assert.doesNotThrow(() => ${funcName}(null));
|
|
26903
|
+
});
|
|
26904
|
+
});
|
|
26905
|
+
`;
|
|
26906
|
+
}
|
|
26907
|
+
// ============================================================================
|
|
26908
|
+
// Helpers
|
|
26909
|
+
// ============================================================================
|
|
26910
|
+
/**
|
|
26911
|
+
* Convert expect() style assertions to node:assert
|
|
26912
|
+
*/
|
|
26913
|
+
convertToAssert(assertion) {
|
|
26914
|
+
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);");
|
|
26915
|
+
}
|
|
26916
|
+
};
|
|
26917
|
+
|
|
26544
26918
|
// src/domains/test-generation/factories/test-generator-factory.ts
|
|
26545
26919
|
var SUPPORTED_FRAMEWORKS = [
|
|
26546
26920
|
"jest",
|
|
26547
26921
|
"vitest",
|
|
26548
26922
|
"mocha",
|
|
26549
|
-
"pytest"
|
|
26923
|
+
"pytest",
|
|
26924
|
+
"node-test"
|
|
26550
26925
|
];
|
|
26551
26926
|
var DEFAULT_FRAMEWORK = "vitest";
|
|
26552
26927
|
var TestGeneratorFactory = class {
|
|
@@ -26608,6 +26983,8 @@ var TestGeneratorFactory = class {
|
|
|
26608
26983
|
return new MochaGenerator();
|
|
26609
26984
|
case "pytest":
|
|
26610
26985
|
return new PytestGenerator();
|
|
26986
|
+
case "node-test":
|
|
26987
|
+
return new NodeTestGenerator();
|
|
26611
26988
|
default:
|
|
26612
26989
|
throw new Error(`Unsupported test framework: ${framework}`);
|
|
26613
26990
|
}
|
|
@@ -27955,12 +28332,32 @@ ${sourceCode}
|
|
|
27955
28332
|
};
|
|
27956
28333
|
}
|
|
27957
28334
|
extractParameters(params, sourceFile) {
|
|
27958
|
-
|
|
27959
|
-
|
|
27960
|
-
|
|
27961
|
-
|
|
27962
|
-
|
|
27963
|
-
|
|
28335
|
+
let objectDestructureCount = 0;
|
|
28336
|
+
let arrayDestructureCount = 0;
|
|
28337
|
+
return params.map((param) => {
|
|
28338
|
+
let name = param.name.getText(sourceFile);
|
|
28339
|
+
let type = param.type?.getText(sourceFile);
|
|
28340
|
+
if (ts.isObjectBindingPattern(param.name)) {
|
|
28341
|
+
objectDestructureCount++;
|
|
28342
|
+
name = objectDestructureCount > 1 ? `options${objectDestructureCount}` : "options";
|
|
28343
|
+
if (!type) {
|
|
28344
|
+
const props = param.name.elements.map((el) => `${el.name.getText(sourceFile)}: unknown`).join(", ");
|
|
28345
|
+
type = `{ ${props} }`;
|
|
28346
|
+
}
|
|
28347
|
+
} else if (ts.isArrayBindingPattern(param.name)) {
|
|
28348
|
+
arrayDestructureCount++;
|
|
28349
|
+
name = arrayDestructureCount > 1 ? `items${arrayDestructureCount}` : "items";
|
|
28350
|
+
if (!type) {
|
|
28351
|
+
type = "unknown[]";
|
|
28352
|
+
}
|
|
28353
|
+
}
|
|
28354
|
+
return {
|
|
28355
|
+
name,
|
|
28356
|
+
type,
|
|
28357
|
+
optional: param.questionToken !== void 0,
|
|
28358
|
+
defaultValue: param.initializer?.getText(sourceFile)
|
|
28359
|
+
};
|
|
28360
|
+
});
|
|
27964
28361
|
}
|
|
27965
28362
|
calculateComplexity(node) {
|
|
27966
28363
|
let complexity = 1;
|
|
@@ -28019,12 +28416,18 @@ ${sourceCode}
|
|
|
28019
28416
|
const callees = [];
|
|
28020
28417
|
const callers = [];
|
|
28021
28418
|
const tsImports = sourceContent.matchAll(/(?:import|from)\s+['"]([^'"]+)['"]/g);
|
|
28022
|
-
const pyImports = sourceContent.matchAll(/(?:^|\n)\s*(?:from\s+(\S+)\s+import|import\s+(\S+))/g);
|
|
28023
28419
|
for (const match of tsImports) {
|
|
28024
28420
|
imports.push(match[1]);
|
|
28025
28421
|
}
|
|
28026
|
-
|
|
28027
|
-
|
|
28422
|
+
const isPython = filePath.endsWith(".py");
|
|
28423
|
+
if (isPython) {
|
|
28424
|
+
const pyImports = sourceContent.matchAll(/(?:^|\n)\s*(?:from\s+(\S+)\s+import|import\s+(\S+))/g);
|
|
28425
|
+
for (const match of pyImports) {
|
|
28426
|
+
const mod = match[1] || match[2];
|
|
28427
|
+
if (mod && /^[a-zA-Z_][\w.]*$/.test(mod)) {
|
|
28428
|
+
imports.push(mod);
|
|
28429
|
+
}
|
|
28430
|
+
}
|
|
28028
28431
|
}
|
|
28029
28432
|
const normalizedPath = filePath.replace(/\\/g, "/");
|
|
28030
28433
|
const baseName = normalizedPath.split("/").pop()?.replace(/\.(ts|js|tsx|jsx|py)$/, "") || "";
|
|
@@ -28486,7 +28889,7 @@ var PatternMatcherService = class _PatternMatcherService {
|
|
|
28486
28889
|
return template.replace("{{name}}", param.name);
|
|
28487
28890
|
}
|
|
28488
28891
|
}
|
|
28489
|
-
return `
|
|
28892
|
+
return `{} /* TODO: provide ${param.name}: ${param.type || "unknown"} */`;
|
|
28490
28893
|
}
|
|
28491
28894
|
/**
|
|
28492
28895
|
* Estimate number of branches from cyclomatic complexity
|
|
@@ -29402,12 +29805,32 @@ var TypeScriptASTParser = class {
|
|
|
29402
29805
|
* Extract parameter information
|
|
29403
29806
|
*/
|
|
29404
29807
|
extractParameters(params, sourceFile) {
|
|
29405
|
-
|
|
29406
|
-
|
|
29407
|
-
|
|
29408
|
-
|
|
29409
|
-
|
|
29410
|
-
|
|
29808
|
+
let objectDestructureCount = 0;
|
|
29809
|
+
let arrayDestructureCount = 0;
|
|
29810
|
+
return params.map((param) => {
|
|
29811
|
+
let name = param.name.getText(sourceFile);
|
|
29812
|
+
let type = param.type?.getText(sourceFile);
|
|
29813
|
+
if (ts2.isObjectBindingPattern(param.name)) {
|
|
29814
|
+
objectDestructureCount++;
|
|
29815
|
+
name = objectDestructureCount > 1 ? `options${objectDestructureCount}` : "options";
|
|
29816
|
+
if (!type) {
|
|
29817
|
+
const props = param.name.elements.map((el) => `${el.name.getText(sourceFile)}: unknown`).join(", ");
|
|
29818
|
+
type = `{ ${props} }`;
|
|
29819
|
+
}
|
|
29820
|
+
} else if (ts2.isArrayBindingPattern(param.name)) {
|
|
29821
|
+
arrayDestructureCount++;
|
|
29822
|
+
name = arrayDestructureCount > 1 ? `items${arrayDestructureCount}` : "items";
|
|
29823
|
+
if (!type) {
|
|
29824
|
+
type = "unknown[]";
|
|
29825
|
+
}
|
|
29826
|
+
}
|
|
29827
|
+
return {
|
|
29828
|
+
name,
|
|
29829
|
+
type,
|
|
29830
|
+
optional: param.questionToken !== void 0,
|
|
29831
|
+
defaultValue: param.initializer?.getText(sourceFile)
|
|
29832
|
+
};
|
|
29833
|
+
});
|
|
29411
29834
|
}
|
|
29412
29835
|
/**
|
|
29413
29836
|
* Calculate cyclomatic complexity of a node
|
|
@@ -114551,7 +114974,7 @@ function parsePipelineContent(content, sourcePath) {
|
|
|
114551
114974
|
if (errors.length > 0) {
|
|
114552
114975
|
return { success: false, errors };
|
|
114553
114976
|
}
|
|
114554
|
-
const
|
|
114977
|
+
const pipeline10 = {
|
|
114555
114978
|
name: parsed.name,
|
|
114556
114979
|
description: parsed.description,
|
|
114557
114980
|
version: parsed.version || "1.0.0",
|
|
@@ -114573,26 +114996,26 @@ function parsePipelineContent(content, sourcePath) {
|
|
|
114573
114996
|
tags: parsed.tags,
|
|
114574
114997
|
timeout: parsed.timeout
|
|
114575
114998
|
};
|
|
114576
|
-
for (let i58 = 0; i58 <
|
|
114577
|
-
const stage =
|
|
114999
|
+
for (let i58 = 0; i58 < pipeline10.stages.length; i58++) {
|
|
115000
|
+
const stage = pipeline10.stages[i58];
|
|
114578
115001
|
if (!stage.command) {
|
|
114579
115002
|
errors.push(`Stage ${i58 + 1} (${stage.name}) must have a "command" field`);
|
|
114580
115003
|
}
|
|
114581
115004
|
}
|
|
114582
115005
|
if (errors.length > 0) {
|
|
114583
|
-
return { success: false, pipeline:
|
|
115006
|
+
return { success: false, pipeline: pipeline10, errors };
|
|
114584
115007
|
}
|
|
114585
|
-
const workflow = convertToWorkflowDefinition(
|
|
115008
|
+
const workflow = convertToWorkflowDefinition(pipeline10, sourcePath);
|
|
114586
115009
|
return {
|
|
114587
115010
|
success: true,
|
|
114588
|
-
pipeline:
|
|
115011
|
+
pipeline: pipeline10,
|
|
114589
115012
|
workflow,
|
|
114590
115013
|
errors: []
|
|
114591
115014
|
};
|
|
114592
115015
|
}
|
|
114593
|
-
function convertToWorkflowDefinition(
|
|
114594
|
-
const workflowId = `pipeline-${
|
|
114595
|
-
const steps =
|
|
115016
|
+
function convertToWorkflowDefinition(pipeline10, sourcePath) {
|
|
115017
|
+
const workflowId = `pipeline-${pipeline10.name.replace(/\s+/g, "-").toLowerCase()}`;
|
|
115018
|
+
const steps = pipeline10.stages.map((stage, index) => {
|
|
114596
115019
|
const domainAction = mapCommandToDomainAction(stage.command);
|
|
114597
115020
|
const inputMapping = {};
|
|
114598
115021
|
if (stage.params) {
|
|
@@ -114626,7 +115049,7 @@ function convertToWorkflowDefinition(pipeline11, sourcePath) {
|
|
|
114626
115049
|
}
|
|
114627
115050
|
return step;
|
|
114628
115051
|
});
|
|
114629
|
-
const triggers =
|
|
115052
|
+
const triggers = pipeline10.triggers?.map((trigger) => {
|
|
114630
115053
|
const workflowTrigger = {
|
|
114631
115054
|
eventType: mapTriggerEventType(trigger),
|
|
114632
115055
|
sourceDomain: trigger.source_domain
|
|
@@ -114642,13 +115065,13 @@ function convertToWorkflowDefinition(pipeline11, sourcePath) {
|
|
|
114642
115065
|
});
|
|
114643
115066
|
return {
|
|
114644
115067
|
id: workflowId,
|
|
114645
|
-
name:
|
|
114646
|
-
description:
|
|
114647
|
-
version:
|
|
115068
|
+
name: pipeline10.name,
|
|
115069
|
+
description: pipeline10.description || `Pipeline from ${sourcePath || "inline YAML"}`,
|
|
115070
|
+
version: pipeline10.version || "1.0.0",
|
|
114648
115071
|
steps,
|
|
114649
115072
|
triggers,
|
|
114650
|
-
tags:
|
|
114651
|
-
timeout:
|
|
115073
|
+
tags: pipeline10.tags,
|
|
115074
|
+
timeout: pipeline10.timeout ? pipeline10.timeout * 1e3 : void 0
|
|
114652
115075
|
};
|
|
114653
115076
|
}
|
|
114654
115077
|
function mapCommandToDomainAction(command) {
|
|
@@ -114697,17 +115120,17 @@ function mapTriggerEventType(trigger) {
|
|
|
114697
115120
|
}
|
|
114698
115121
|
return event;
|
|
114699
115122
|
}
|
|
114700
|
-
function validatePipeline(
|
|
115123
|
+
function validatePipeline(pipeline10) {
|
|
114701
115124
|
const errors = [];
|
|
114702
115125
|
const warnings = [];
|
|
114703
|
-
if (!
|
|
115126
|
+
if (!pipeline10.name) {
|
|
114704
115127
|
errors.push({
|
|
114705
115128
|
path: "name",
|
|
114706
115129
|
message: "Pipeline name is required",
|
|
114707
115130
|
severity: "error"
|
|
114708
115131
|
});
|
|
114709
115132
|
}
|
|
114710
|
-
if (!
|
|
115133
|
+
if (!pipeline10.stages || pipeline10.stages.length === 0) {
|
|
114711
115134
|
errors.push({
|
|
114712
115135
|
path: "stages",
|
|
114713
115136
|
message: "Pipeline must have at least one stage",
|
|
@@ -114715,8 +115138,8 @@ function validatePipeline(pipeline11) {
|
|
|
114715
115138
|
});
|
|
114716
115139
|
} else {
|
|
114717
115140
|
const stageNames = /* @__PURE__ */ new Set();
|
|
114718
|
-
for (let i58 = 0; i58 <
|
|
114719
|
-
const stage =
|
|
115141
|
+
for (let i58 = 0; i58 < pipeline10.stages.length; i58++) {
|
|
115142
|
+
const stage = pipeline10.stages[i58];
|
|
114720
115143
|
const stagePath = `stages[${i58}]`;
|
|
114721
115144
|
if (stageNames.has(stage.name)) {
|
|
114722
115145
|
errors.push({
|
|
@@ -114744,7 +115167,7 @@ function validatePipeline(pipeline11) {
|
|
|
114744
115167
|
}
|
|
114745
115168
|
if (stage.depends_on) {
|
|
114746
115169
|
for (const dep of stage.depends_on) {
|
|
114747
|
-
if (!
|
|
115170
|
+
if (!pipeline10.stages.some((s70) => s70.name === dep)) {
|
|
114748
115171
|
errors.push({
|
|
114749
115172
|
path: `${stagePath}.depends_on`,
|
|
114750
115173
|
message: `Unknown dependency: ${dep}`,
|
|
@@ -114770,7 +115193,7 @@ function validatePipeline(pipeline11) {
|
|
|
114770
115193
|
}
|
|
114771
115194
|
}
|
|
114772
115195
|
}
|
|
114773
|
-
const circular = detectCircularDependencies(
|
|
115196
|
+
const circular = detectCircularDependencies(pipeline10.stages);
|
|
114774
115197
|
if (circular) {
|
|
114775
115198
|
errors.push({
|
|
114776
115199
|
path: "stages",
|
|
@@ -114779,18 +115202,18 @@ function validatePipeline(pipeline11) {
|
|
|
114779
115202
|
});
|
|
114780
115203
|
}
|
|
114781
115204
|
}
|
|
114782
|
-
if (
|
|
114783
|
-
if (!isValidCronExpression(
|
|
115205
|
+
if (pipeline10.schedule) {
|
|
115206
|
+
if (!isValidCronExpression(pipeline10.schedule)) {
|
|
114784
115207
|
errors.push({
|
|
114785
115208
|
path: "schedule",
|
|
114786
|
-
message: `Invalid cron expression: ${
|
|
115209
|
+
message: `Invalid cron expression: ${pipeline10.schedule}`,
|
|
114787
115210
|
severity: "error"
|
|
114788
115211
|
});
|
|
114789
115212
|
}
|
|
114790
115213
|
}
|
|
114791
|
-
if (
|
|
114792
|
-
for (let i58 = 0; i58 <
|
|
114793
|
-
const trigger =
|
|
115214
|
+
if (pipeline10.triggers) {
|
|
115215
|
+
for (let i58 = 0; i58 < pipeline10.triggers.length; i58++) {
|
|
115216
|
+
const trigger = pipeline10.triggers[i58];
|
|
114794
115217
|
const triggerPath = `triggers[${i58}]`;
|
|
114795
115218
|
if (!trigger.event) {
|
|
114796
115219
|
errors.push({
|
|
@@ -115449,7 +115872,7 @@ var ALL_DOMAINS2 = [
|
|
|
115449
115872
|
"enterprise-integration"
|
|
115450
115873
|
];
|
|
115451
115874
|
function getAQEVersion() {
|
|
115452
|
-
return true ? "3.6.
|
|
115875
|
+
return true ? "3.6.16" : "3.0.0";
|
|
115453
115876
|
}
|
|
115454
115877
|
function createDefaultConfig(projectName, projectRoot) {
|
|
115455
115878
|
return {
|
|
@@ -123549,11 +123972,11 @@ function createTestCommand(context2, cleanupAndExit2, ensureInitialized2) {
|
|
|
123549
123972
|
console.log(chalk9.gray(` Assertions: ${test.assertions}`));
|
|
123550
123973
|
if (test.testCode) {
|
|
123551
123974
|
console.log(chalk9.gray(` Test File: ${test.testFile}`));
|
|
123552
|
-
|
|
123553
|
-
|
|
123554
|
-
|
|
123555
|
-
|
|
123556
|
-
`);
|
|
123975
|
+
const fs23 = await import("fs");
|
|
123976
|
+
const testDir = path26.dirname(test.testFile);
|
|
123977
|
+
fs23.mkdirSync(testDir, { recursive: true });
|
|
123978
|
+
fs23.writeFileSync(test.testFile, test.testCode, "utf-8");
|
|
123979
|
+
console.log(chalk9.green(` Written to: ${test.testFile}`));
|
|
123557
123980
|
}
|
|
123558
123981
|
}
|
|
123559
123982
|
if (generated.tests.length > 10) {
|
|
@@ -125641,7 +126064,7 @@ var TASK_TYPES = [
|
|
|
125641
126064
|
];
|
|
125642
126065
|
var PRIORITIES = ["p0", "p1", "p2", "p3"];
|
|
125643
126066
|
var STATUSES = ["pending", "running", "completed", "failed", "cancelled"];
|
|
125644
|
-
var FRAMEWORKS = ["jest", "vitest", "pytest", "junit", "playwright", "cypress", "go-test"];
|
|
126067
|
+
var FRAMEWORKS = ["jest", "vitest", "pytest", "junit", "playwright", "cypress", "go-test", "node-test"];
|
|
125645
126068
|
var TEST_TYPES = ["unit", "integration", "e2e"];
|
|
125646
126069
|
var MEMORY_BACKENDS = ["sqlite", "agentdb", "hybrid"];
|
|
125647
126070
|
function generateBashCompletion() {
|
|
@@ -132588,16 +133011,15 @@ import ora2 from "ora";
|
|
|
132588
133011
|
var DEFAULT_SYNC_CONFIG = {
|
|
132589
133012
|
local: {
|
|
132590
133013
|
// PRIMARY: Root database (consolidated, MCP-active)
|
|
132591
|
-
|
|
132592
|
-
|
|
132593
|
-
rootMemoryDb: "
|
|
132594
|
-
|
|
132595
|
-
|
|
132596
|
-
|
|
132597
|
-
|
|
132598
|
-
|
|
132599
|
-
|
|
132600
|
-
v2PatternsDb: "../v2/data/ruvector-patterns.db"
|
|
133014
|
+
// Paths relative to process.cwd() which is the project root
|
|
133015
|
+
v3MemoryDb: "./.agentic-qe/memory.db",
|
|
133016
|
+
rootMemoryDb: "./.agentic-qe/memory.db",
|
|
133017
|
+
claudeFlowMemory: "./.claude-flow/memory/store.json",
|
|
133018
|
+
claudeFlowDaemon: "./.claude-flow/daemon-state.json",
|
|
133019
|
+
claudeFlowMetrics: "./.claude-flow/metrics/",
|
|
133020
|
+
intelligenceJson: "./v3/.ruvector/intelligence.json",
|
|
133021
|
+
swarmMemoryDb: "./.swarm/memory.db",
|
|
133022
|
+
v2PatternsDb: "./v2/data/ruvector-patterns.db"
|
|
132601
133023
|
},
|
|
132602
133024
|
cloud: {
|
|
132603
133025
|
project: process.env.GCP_PROJECT || "",
|
|
@@ -132613,82 +133035,150 @@ var DEFAULT_SYNC_CONFIG = {
|
|
|
132613
133035
|
batchSize: 1e3,
|
|
132614
133036
|
conflictResolution: "newer-wins",
|
|
132615
133037
|
sourcePriority: {
|
|
132616
|
-
|
|
132617
|
-
//
|
|
132618
|
-
|
|
132619
|
-
|
|
132620
|
-
|
|
133038
|
+
qePatterns: 1,
|
|
133039
|
+
// Primary QE learning data (12K+ records)
|
|
133040
|
+
sonaPatterns: 2,
|
|
133041
|
+
// Neural backbone patterns
|
|
133042
|
+
goapActions: 3,
|
|
133043
|
+
// Planning primitives
|
|
133044
|
+
kvStore: 4,
|
|
133045
|
+
// Key-value memory entries
|
|
133046
|
+
experiences: 5,
|
|
133047
|
+
// Captured RL experiences
|
|
133048
|
+
claudeFlowMemory: 6,
|
|
133049
|
+
intelligenceJson: 7
|
|
132621
133050
|
},
|
|
132622
133051
|
sources: [
|
|
132623
133052
|
// ============================================================
|
|
132624
|
-
// ROOT Memory - PRIMARY (Consolidated
|
|
132625
|
-
// All tables
|
|
133053
|
+
// ROOT Memory - PRIMARY (Consolidated database)
|
|
133054
|
+
// All tables in single database: .agentic-qe/memory.db
|
|
133055
|
+
//
|
|
133056
|
+
// NOTE (2026-02-20): Post-consolidation table mapping:
|
|
133057
|
+
// OLD v2 tables (removed) → NEW v3 tables (actual)
|
|
133058
|
+
// memory_entries → kv_store
|
|
133059
|
+
// learning_experiences → captured_experiences
|
|
133060
|
+
// patterns → qe_patterns (absorbed)
|
|
133061
|
+
// events → (removed, use dream_cycles/routing_outcomes)
|
|
132626
133062
|
// ============================================================
|
|
133063
|
+
// QE Patterns - PRIMARY learning data (12,150+ records)
|
|
133064
|
+
// Explicit columns to match cloud schema exactly
|
|
133065
|
+
{
|
|
133066
|
+
name: "root-qe-patterns",
|
|
133067
|
+
type: "sqlite",
|
|
133068
|
+
path: "./.agentic-qe/memory.db",
|
|
133069
|
+
targetTable: "aqe.qe_patterns",
|
|
133070
|
+
priority: "high",
|
|
133071
|
+
mode: "incremental",
|
|
133072
|
+
query: "SELECT id, pattern_type, qe_domain, domain, name, description, confidence, usage_count, success_rate, quality_score, tier, template_json, context_json, successful_uses, created_at, updated_at, last_used_at, tokens_used, input_tokens, output_tokens, latency_ms, reusable, reuse_count, average_token_savings, total_tokens_saved FROM qe_patterns",
|
|
133073
|
+
enabled: true
|
|
133074
|
+
},
|
|
133075
|
+
// SONA neural patterns (731+ records)
|
|
132627
133076
|
{
|
|
132628
133077
|
name: "root-sona-patterns",
|
|
132629
133078
|
type: "sqlite",
|
|
132630
|
-
path: "
|
|
133079
|
+
path: "./.agentic-qe/memory.db",
|
|
132631
133080
|
targetTable: "aqe.sona_patterns",
|
|
132632
133081
|
priority: "high",
|
|
132633
133082
|
mode: "incremental",
|
|
132634
133083
|
query: "SELECT * FROM sona_patterns",
|
|
132635
133084
|
enabled: true
|
|
132636
133085
|
},
|
|
133086
|
+
// GOAP actions (2,243+ records)
|
|
132637
133087
|
{
|
|
132638
133088
|
name: "root-goap-actions",
|
|
132639
133089
|
type: "sqlite",
|
|
132640
|
-
path: "
|
|
133090
|
+
path: "./.agentic-qe/memory.db",
|
|
132641
133091
|
targetTable: "aqe.goap_actions",
|
|
132642
133092
|
priority: "high",
|
|
132643
133093
|
mode: "incremental",
|
|
132644
133094
|
query: "SELECT * FROM goap_actions",
|
|
132645
133095
|
enabled: true
|
|
132646
133096
|
},
|
|
133097
|
+
// KV Store → cloud memory_entries (1,619+ records)
|
|
133098
|
+
// Only sync entries with valid JSON values (skip corrupt/HTML-embedded data)
|
|
132647
133099
|
{
|
|
132648
|
-
name: "root-
|
|
133100
|
+
name: "root-kv-store",
|
|
132649
133101
|
type: "sqlite",
|
|
132650
|
-
path: "
|
|
133102
|
+
path: "./.agentic-qe/memory.db",
|
|
132651
133103
|
targetTable: "aqe.memory_entries",
|
|
132652
133104
|
priority: "high",
|
|
132653
133105
|
mode: "incremental",
|
|
132654
|
-
query: "SELECT
|
|
133106
|
+
query: "SELECT key, namespace as partition, CASE WHEN json_valid(value) THEN value ELSE json_quote(value) END as value, created_at, expires_at FROM kv_store WHERE json_valid(value) OR json_valid(json_quote(value))",
|
|
132655
133107
|
enabled: true
|
|
132656
133108
|
},
|
|
133109
|
+
// Captured experiences → cloud learning_experiences (854+ records)
|
|
133110
|
+
// Cloud id is SERIAL (auto-increment) — omit local UUID id
|
|
132657
133111
|
{
|
|
132658
|
-
name: "root-
|
|
133112
|
+
name: "root-captured-experiences",
|
|
132659
133113
|
type: "sqlite",
|
|
132660
|
-
path: "
|
|
133114
|
+
path: "./.agentic-qe/memory.db",
|
|
132661
133115
|
targetTable: "aqe.learning_experiences",
|
|
132662
133116
|
priority: "high",
|
|
132663
133117
|
mode: "append",
|
|
132664
|
-
query: "SELECT
|
|
133118
|
+
query: "SELECT agent as agent_id, task as task_id, domain as task_type, COALESCE(result_json, '{}') as state, COALESCE(steps_json, '{}') as action, quality as reward, COALESCE(routing_json, '{}') as next_state, tags as episode_id, started_at as created_at FROM captured_experiences",
|
|
132665
133119
|
enabled: true
|
|
132666
133120
|
},
|
|
133121
|
+
// GOAP plans (91+ records)
|
|
132667
133122
|
{
|
|
132668
|
-
name: "root-
|
|
133123
|
+
name: "root-goap-plans",
|
|
132669
133124
|
type: "sqlite",
|
|
132670
|
-
path: "
|
|
132671
|
-
targetTable: "aqe.
|
|
133125
|
+
path: "./.agentic-qe/memory.db",
|
|
133126
|
+
targetTable: "aqe.goap_plans",
|
|
132672
133127
|
priority: "medium",
|
|
132673
133128
|
mode: "incremental",
|
|
132674
|
-
query: "SELECT
|
|
133129
|
+
query: "SELECT id, goal_id, action_sequence as sequence, initial_state, goal_state, action_sequence, total_cost, estimated_duration_ms as estimated_duration, status, created_at, completed_at FROM goap_plans",
|
|
132675
133130
|
enabled: true
|
|
132676
133131
|
},
|
|
133132
|
+
// RL Q-values (from SQLite, not JSON)
|
|
133133
|
+
// Use DISTINCT to avoid duplicate (state, action) pairs in same batch
|
|
132677
133134
|
{
|
|
132678
|
-
name: "root-
|
|
133135
|
+
name: "root-rl-q-values",
|
|
132679
133136
|
type: "sqlite",
|
|
132680
|
-
path: "
|
|
132681
|
-
targetTable: "aqe.
|
|
133137
|
+
path: "./.agentic-qe/memory.db",
|
|
133138
|
+
targetTable: "aqe.qlearning_patterns",
|
|
133139
|
+
priority: "medium",
|
|
133140
|
+
mode: "incremental",
|
|
133141
|
+
query: "SELECT DISTINCT state_key as state, action_key as action, q_value, visits, updated_at as last_update, created_at FROM rl_q_values GROUP BY state_key, action_key",
|
|
133142
|
+
enabled: true
|
|
133143
|
+
},
|
|
133144
|
+
// Routing outcomes (184+ records) - model routing decisions
|
|
133145
|
+
{
|
|
133146
|
+
name: "root-routing-outcomes",
|
|
133147
|
+
type: "sqlite",
|
|
133148
|
+
path: "./.agentic-qe/memory.db",
|
|
133149
|
+
targetTable: "aqe.routing_outcomes",
|
|
133150
|
+
priority: "medium",
|
|
133151
|
+
mode: "append",
|
|
133152
|
+
query: "SELECT * FROM routing_outcomes",
|
|
133153
|
+
enabled: true
|
|
133154
|
+
},
|
|
133155
|
+
// QE trajectories (320+ records) - execution traces
|
|
133156
|
+
{
|
|
133157
|
+
name: "root-qe-trajectories",
|
|
133158
|
+
type: "sqlite",
|
|
133159
|
+
path: "./.agentic-qe/memory.db",
|
|
133160
|
+
targetTable: "aqe.qe_trajectories",
|
|
133161
|
+
priority: "medium",
|
|
133162
|
+
mode: "append",
|
|
133163
|
+
query: "SELECT * FROM qe_trajectories",
|
|
133164
|
+
enabled: true
|
|
133165
|
+
},
|
|
133166
|
+
// Dream insights (660+ records) - consolidation results
|
|
133167
|
+
{
|
|
133168
|
+
name: "root-dream-insights",
|
|
133169
|
+
type: "sqlite",
|
|
133170
|
+
path: "./.agentic-qe/memory.db",
|
|
133171
|
+
targetTable: "aqe.dream_insights",
|
|
132682
133172
|
priority: "low",
|
|
132683
133173
|
mode: "append",
|
|
132684
|
-
query: "SELECT * FROM
|
|
133174
|
+
query: "SELECT * FROM dream_insights",
|
|
132685
133175
|
enabled: true
|
|
132686
133176
|
},
|
|
132687
133177
|
// Claude-Flow Memory (JSON)
|
|
132688
133178
|
{
|
|
132689
133179
|
name: "claude-flow-memory",
|
|
132690
133180
|
type: "json",
|
|
132691
|
-
path: "
|
|
133181
|
+
path: "./.claude-flow/memory/store.json",
|
|
132692
133182
|
targetTable: "aqe.claude_flow_memory",
|
|
132693
133183
|
priority: "medium",
|
|
132694
133184
|
mode: "full",
|
|
@@ -132698,7 +133188,7 @@ var DEFAULT_SYNC_CONFIG = {
|
|
|
132698
133188
|
{
|
|
132699
133189
|
name: "intelligence-qlearning",
|
|
132700
133190
|
type: "json",
|
|
132701
|
-
path: "
|
|
133191
|
+
path: "./v3/.ruvector/intelligence.json",
|
|
132702
133192
|
targetTable: "aqe.qlearning_patterns",
|
|
132703
133193
|
priority: "low",
|
|
132704
133194
|
mode: "full",
|
|
@@ -133450,7 +133940,9 @@ function createConnectionManager(config) {
|
|
|
133450
133940
|
init_sql_safety();
|
|
133451
133941
|
init_error_utils();
|
|
133452
133942
|
init_logging();
|
|
133943
|
+
import { createRequire as createRequire7 } from "module";
|
|
133453
133944
|
var logger14 = LoggerFactory.create("postgres-writer");
|
|
133945
|
+
var requirePg = createRequire7(import.meta.url);
|
|
133454
133946
|
var PostgresWriter = class {
|
|
133455
133947
|
client = null;
|
|
133456
133948
|
config;
|
|
@@ -133471,31 +133963,36 @@ var PostgresWriter = class {
|
|
|
133471
133963
|
if (!connection) {
|
|
133472
133964
|
throw new Error("No tunnel connection available");
|
|
133473
133965
|
}
|
|
133966
|
+
let pg;
|
|
133474
133967
|
try {
|
|
133475
|
-
|
|
133476
|
-
const Client = pg.Client || pg.default?.Client;
|
|
133477
|
-
if (Client) {
|
|
133478
|
-
const connectionConfig = {
|
|
133479
|
-
host: connection.host,
|
|
133480
|
-
port: connection.port,
|
|
133481
|
-
database: this.config.cloud.database,
|
|
133482
|
-
user: this.config.cloud.user,
|
|
133483
|
-
password: process.env.PGPASSWORD || "",
|
|
133484
|
-
connectionTimeoutMillis: this.config.connectionTimeout || 1e4
|
|
133485
|
-
};
|
|
133486
|
-
this.client = new Client(connectionConfig);
|
|
133487
|
-
await this.client.connect();
|
|
133488
|
-
this.connected = true;
|
|
133489
|
-
console.log(`[PostgresWriter] Connected to ${connection.host}:${connection.port}/${this.config.cloud.database}`);
|
|
133490
|
-
} else {
|
|
133491
|
-
throw new Error("pg Client not found");
|
|
133492
|
-
}
|
|
133968
|
+
pg = requirePg("pg");
|
|
133493
133969
|
} catch (e20) {
|
|
133494
|
-
logger14.debug("pg module not
|
|
133495
|
-
console.warn("[PostgresWriter] pg module not
|
|
133970
|
+
logger14.debug("pg module not installed, using mock mode", { error: e20 instanceof Error ? e20.message : String(e20) });
|
|
133971
|
+
console.warn("[PostgresWriter] pg module not installed, running in mock mode");
|
|
133496
133972
|
this.client = this.createMockClient();
|
|
133497
133973
|
this.connected = true;
|
|
133974
|
+
return;
|
|
133498
133975
|
}
|
|
133976
|
+
const pgDefault = pg.default;
|
|
133977
|
+
const Client = pg.Client || pgDefault?.Client;
|
|
133978
|
+
if (!Client) {
|
|
133979
|
+
console.warn("[PostgresWriter] pg.Client not found in module, running in mock mode");
|
|
133980
|
+
this.client = this.createMockClient();
|
|
133981
|
+
this.connected = true;
|
|
133982
|
+
return;
|
|
133983
|
+
}
|
|
133984
|
+
const connectionConfig = {
|
|
133985
|
+
host: connection.host,
|
|
133986
|
+
port: connection.port,
|
|
133987
|
+
database: this.config.cloud.database,
|
|
133988
|
+
user: this.config.cloud.user,
|
|
133989
|
+
password: process.env.PGPASSWORD || "",
|
|
133990
|
+
connectionTimeoutMillis: this.config.connectionTimeout || 1e4
|
|
133991
|
+
};
|
|
133992
|
+
this.client = new Client(connectionConfig);
|
|
133993
|
+
await this.client.connect();
|
|
133994
|
+
this.connected = true;
|
|
133995
|
+
console.log(`[PostgresWriter] Connected to ${connection.host}:${connection.port}/${this.config.cloud.database}`);
|
|
133499
133996
|
}
|
|
133500
133997
|
/**
|
|
133501
133998
|
* Begin a transaction
|
|
@@ -133545,8 +134042,28 @@ var PostgresWriter = class {
|
|
|
133545
134042
|
const batchSize = 100;
|
|
133546
134043
|
for (let i58 = 0; i58 < records.length; i58 += batchSize) {
|
|
133547
134044
|
const batch = records.slice(i58, i58 + batchSize);
|
|
133548
|
-
|
|
133549
|
-
|
|
134045
|
+
try {
|
|
134046
|
+
const inserted = await this.upsertBatch(table, batch, columns, conflictColumns, updateColumns, options?.skipIfExists);
|
|
134047
|
+
totalInserted += inserted;
|
|
134048
|
+
} catch (error) {
|
|
134049
|
+
const batchNum = Math.floor(i58 / batchSize) + 1;
|
|
134050
|
+
const totalBatches = Math.ceil(records.length / batchSize);
|
|
134051
|
+
logger14.debug(`Batch ${batchNum}/${totalBatches} failed for ${table}, retrying individually`, { error: toErrorMessage(error) });
|
|
134052
|
+
let recovered = 0;
|
|
134053
|
+
for (const record of batch) {
|
|
134054
|
+
try {
|
|
134055
|
+
const inserted = await this.upsertBatch(table, [record], columns, conflictColumns, updateColumns, options?.skipIfExists);
|
|
134056
|
+
recovered += inserted;
|
|
134057
|
+
} catch (retryError) {
|
|
134058
|
+
const recordId = record["id"] || record["key"] || "?";
|
|
134059
|
+
logger14.debug(`Skipped record ${String(recordId).slice(0, 50)} in ${table}`, { error: toErrorMessage(retryError) });
|
|
134060
|
+
}
|
|
134061
|
+
}
|
|
134062
|
+
totalInserted += recovered;
|
|
134063
|
+
if (recovered < batch.length) {
|
|
134064
|
+
console.warn(`[PostgresWriter] Batch ${batchNum}/${totalBatches} for ${table}: ${recovered}/${batch.length} recovered (${batch.length - recovered} skipped)`);
|
|
134065
|
+
}
|
|
134066
|
+
}
|
|
133550
134067
|
}
|
|
133551
134068
|
return totalInserted;
|
|
133552
134069
|
}
|
|
@@ -133589,7 +134106,7 @@ var PostgresWriter = class {
|
|
|
133589
134106
|
const result = await this.client.query(sql, params);
|
|
133590
134107
|
return result.rowCount || 0;
|
|
133591
134108
|
} catch (error) {
|
|
133592
|
-
|
|
134109
|
+
logger14.debug(`Upsert failed for ${table}`, { error: toErrorMessage(error) });
|
|
133593
134110
|
throw error;
|
|
133594
134111
|
}
|
|
133595
134112
|
}
|
|
@@ -133660,9 +134177,33 @@ var PostgresWriter = class {
|
|
|
133660
134177
|
return JSON.stringify(value);
|
|
133661
134178
|
}
|
|
133662
134179
|
if (typeof value === "object") {
|
|
133663
|
-
|
|
134180
|
+
let jsonStr = JSON.stringify(value);
|
|
134181
|
+
if (columnName && this.isJsonbColumn(columnName)) {
|
|
134182
|
+
jsonStr = jsonStr.replace(/\u0000/g, "");
|
|
134183
|
+
try {
|
|
134184
|
+
JSON.parse(jsonStr);
|
|
134185
|
+
} catch {
|
|
134186
|
+
return JSON.stringify(String(value));
|
|
134187
|
+
}
|
|
134188
|
+
}
|
|
134189
|
+
return jsonStr;
|
|
133664
134190
|
}
|
|
133665
134191
|
if (typeof value === "string") {
|
|
134192
|
+
if (value === "") {
|
|
134193
|
+
const timestampColumns = [
|
|
134194
|
+
"created_at",
|
|
134195
|
+
"updated_at",
|
|
134196
|
+
"last_used_at",
|
|
134197
|
+
"started_at",
|
|
134198
|
+
"ended_at",
|
|
134199
|
+
"completed_at",
|
|
134200
|
+
"expires_at",
|
|
134201
|
+
"last_update"
|
|
134202
|
+
];
|
|
134203
|
+
if (columnName && timestampColumns.includes(columnName)) {
|
|
134204
|
+
return null;
|
|
134205
|
+
}
|
|
134206
|
+
}
|
|
133666
134207
|
if (/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/.test(value)) {
|
|
133667
134208
|
return value;
|
|
133668
134209
|
}
|
|
@@ -133670,53 +134211,83 @@ var PostgresWriter = class {
|
|
|
133670
134211
|
if (!isNaN(numVal) && numVal > 9466848e5 && numVal < 41024448e5) {
|
|
133671
134212
|
return new Date(numVal).toISOString();
|
|
133672
134213
|
}
|
|
133673
|
-
|
|
133674
|
-
"
|
|
133675
|
-
|
|
133676
|
-
|
|
133677
|
-
|
|
133678
|
-
|
|
133679
|
-
|
|
133680
|
-
"metadata",
|
|
133681
|
-
"value",
|
|
133682
|
-
"payload",
|
|
133683
|
-
"context_json",
|
|
133684
|
-
"template_json",
|
|
133685
|
-
"execution_trace",
|
|
133686
|
-
"action_sequence",
|
|
133687
|
-
"initial_state",
|
|
133688
|
-
"goal_state",
|
|
133689
|
-
"sequence"
|
|
133690
|
-
];
|
|
133691
|
-
if (columnName && jsonbColumns.includes(columnName)) {
|
|
133692
|
-
if (!value.startsWith("{") && !value.startsWith("[") && !value.startsWith('"')) {
|
|
133693
|
-
return JSON.stringify(value);
|
|
134214
|
+
if (columnName && this.isJsonbColumn(columnName)) {
|
|
134215
|
+
const sanitized = value.replace(/\u0000/g, "");
|
|
134216
|
+
try {
|
|
134217
|
+
JSON.parse(sanitized);
|
|
134218
|
+
return sanitized;
|
|
134219
|
+
} catch {
|
|
134220
|
+
return JSON.stringify(sanitized);
|
|
133694
134221
|
}
|
|
133695
134222
|
}
|
|
133696
134223
|
}
|
|
133697
134224
|
return value;
|
|
133698
134225
|
}
|
|
133699
134226
|
/**
|
|
133700
|
-
*
|
|
134227
|
+
* Check if a column is a JSONB column
|
|
134228
|
+
*/
|
|
134229
|
+
isJsonbColumn(columnName) {
|
|
134230
|
+
const jsonbColumns = [
|
|
134231
|
+
"action_value",
|
|
134232
|
+
"state",
|
|
134233
|
+
"action",
|
|
134234
|
+
"next_state",
|
|
134235
|
+
"preconditions",
|
|
134236
|
+
"effects",
|
|
134237
|
+
"metadata",
|
|
134238
|
+
"value",
|
|
134239
|
+
"payload",
|
|
134240
|
+
"context_json",
|
|
134241
|
+
"template_json",
|
|
134242
|
+
"execution_trace",
|
|
134243
|
+
"action_sequence",
|
|
134244
|
+
"initial_state",
|
|
134245
|
+
"goal_state",
|
|
134246
|
+
"sequence",
|
|
134247
|
+
"task_json",
|
|
134248
|
+
"decision_json",
|
|
134249
|
+
"steps_json",
|
|
134250
|
+
"metadata_json"
|
|
134251
|
+
];
|
|
134252
|
+
return jsonbColumns.includes(columnName);
|
|
134253
|
+
}
|
|
134254
|
+
/**
|
|
134255
|
+
* Infer conflict columns from table name and available columns.
|
|
134256
|
+
* Only returns columns if the target table is known to have a matching unique constraint.
|
|
133701
134257
|
*/
|
|
133702
134258
|
inferConflictColumns(table, columns) {
|
|
133703
134259
|
const tableName = table.includes(".") ? table.split(".")[1] : table;
|
|
133704
|
-
|
|
134260
|
+
const tablesWithIdPK = [
|
|
134261
|
+
"qe_patterns",
|
|
134262
|
+
"sona_patterns",
|
|
134263
|
+
"goap_actions",
|
|
134264
|
+
"goap_plans",
|
|
134265
|
+
"patterns",
|
|
134266
|
+
"events",
|
|
134267
|
+
"routing_outcomes",
|
|
134268
|
+
"qe_trajectories",
|
|
134269
|
+
"dream_insights",
|
|
134270
|
+
"intelligence_memories"
|
|
134271
|
+
];
|
|
134272
|
+
if (columns.includes("id") && tablesWithIdPK.includes(tableName)) {
|
|
133705
134273
|
return ["id"];
|
|
133706
134274
|
}
|
|
133707
|
-
if (columns.includes("key") && columns.includes("source_env")) {
|
|
134275
|
+
if (tableName === "memory_entries" && columns.includes("key") && columns.includes("source_env")) {
|
|
133708
134276
|
if (columns.includes("partition")) {
|
|
133709
134277
|
return ["key", "partition", "source_env"];
|
|
133710
134278
|
}
|
|
133711
134279
|
return ["key", "source_env"];
|
|
133712
134280
|
}
|
|
133713
|
-
if (
|
|
134281
|
+
if (tableName === "claude_flow_memory" && columns.includes("key") && columns.includes("source_env")) {
|
|
134282
|
+
return ["key", "source_env"];
|
|
134283
|
+
}
|
|
134284
|
+
if (tableName === "qlearning_patterns" && columns.includes("state") && columns.includes("action") && columns.includes("source_env")) {
|
|
133714
134285
|
return ["state", "action", "source_env"];
|
|
133715
134286
|
}
|
|
133716
|
-
if (columns.includes("worker_type") && columns.includes("source_env")) {
|
|
134287
|
+
if (tableName === "claude_flow_workers" && columns.includes("worker_type") && columns.includes("source_env")) {
|
|
133717
134288
|
return ["worker_type", "source_env"];
|
|
133718
134289
|
}
|
|
133719
|
-
return
|
|
134290
|
+
return [];
|
|
133720
134291
|
}
|
|
133721
134292
|
/**
|
|
133722
134293
|
* Create mock client for testing without pg installed
|
|
@@ -133869,17 +134440,10 @@ var CloudSyncAgent = class {
|
|
|
133869
134440
|
return result;
|
|
133870
134441
|
}
|
|
133871
134442
|
if (this.writer && !this.config.sync.dryRun) {
|
|
133872
|
-
await this.writer.
|
|
133873
|
-
|
|
133874
|
-
|
|
133875
|
-
|
|
133876
|
-
});
|
|
133877
|
-
result.recordsSynced = written;
|
|
133878
|
-
await this.writer.commit();
|
|
133879
|
-
} catch (error) {
|
|
133880
|
-
await this.writer.rollback();
|
|
133881
|
-
throw error;
|
|
133882
|
-
}
|
|
134443
|
+
const written = await this.writer.upsert(source.targetTable, records, {
|
|
134444
|
+
skipIfExists: source.mode === "append"
|
|
134445
|
+
});
|
|
134446
|
+
result.recordsSynced = written;
|
|
133883
134447
|
} else {
|
|
133884
134448
|
result.recordsSynced = records.length;
|
|
133885
134449
|
this.log(`[DRY RUN] Would sync ${records.length} records to ${source.targetTable}`);
|
|
@@ -133919,15 +134483,8 @@ var CloudSyncAgent = class {
|
|
|
133919
134483
|
return result;
|
|
133920
134484
|
}
|
|
133921
134485
|
if (this.writer && !this.config.sync.dryRun) {
|
|
133922
|
-
await this.writer.
|
|
133923
|
-
|
|
133924
|
-
const written = await this.writer.upsert(source.targetTable, records);
|
|
133925
|
-
result.recordsSynced = written;
|
|
133926
|
-
await this.writer.commit();
|
|
133927
|
-
} catch (error) {
|
|
133928
|
-
await this.writer.rollback();
|
|
133929
|
-
throw error;
|
|
133930
|
-
}
|
|
134486
|
+
const written = await this.writer.upsert(source.targetTable, records);
|
|
134487
|
+
result.recordsSynced = written;
|
|
133931
134488
|
} else {
|
|
133932
134489
|
result.recordsSynced = records.length;
|
|
133933
134490
|
}
|
|
@@ -135653,22 +136210,22 @@ var CategoryAdapter = class {
|
|
|
135653
136210
|
* @param pipeline - The pipeline to verify
|
|
135654
136211
|
* @returns Type verification result
|
|
135655
136212
|
*/
|
|
135656
|
-
verifyPipeline(
|
|
136213
|
+
verifyPipeline(pipeline10) {
|
|
135657
136214
|
const startTime = Date.now();
|
|
135658
136215
|
this.clear();
|
|
135659
|
-
this.addType(
|
|
135660
|
-
this.addType(
|
|
135661
|
-
for (const element of
|
|
136216
|
+
this.addType(pipeline10.inputType, this.inferSchema(pipeline10.inputType));
|
|
136217
|
+
this.addType(pipeline10.outputType, this.inferSchema(pipeline10.outputType));
|
|
136218
|
+
for (const element of pipeline10.elements) {
|
|
135662
136219
|
this.addType(element.inputType, this.inferSchema(element.inputType));
|
|
135663
136220
|
this.addType(element.outputType, this.inferSchema(element.outputType));
|
|
135664
136221
|
}
|
|
135665
|
-
for (const element of
|
|
136222
|
+
for (const element of pipeline10.elements) {
|
|
135666
136223
|
this.addMorphism(element.inputType, element.outputType, element.name);
|
|
135667
136224
|
}
|
|
135668
|
-
const path26 = this.buildCompositionPath(
|
|
136225
|
+
const path26 = this.buildCompositionPath(pipeline10);
|
|
135669
136226
|
const compositionValid = this.verifyComposition(path26);
|
|
135670
136227
|
const mismatches = this.checkTypeConsistency();
|
|
135671
|
-
const warnings = this.generateWarnings(
|
|
136228
|
+
const warnings = this.generateWarnings(pipeline10, compositionValid, mismatches);
|
|
135672
136229
|
const durationMs = Date.now() - startTime;
|
|
135673
136230
|
const result = {
|
|
135674
136231
|
isValid: compositionValid && mismatches.length === 0,
|
|
@@ -135678,7 +136235,7 @@ var CategoryAdapter = class {
|
|
|
135678
136235
|
usedFallback: false
|
|
135679
136236
|
};
|
|
135680
136237
|
this.logger.info("Verified pipeline", {
|
|
135681
|
-
pipelineId:
|
|
136238
|
+
pipelineId: pipeline10.id,
|
|
135682
136239
|
isValid: result.isValid,
|
|
135683
136240
|
mismatchCount: mismatches.length,
|
|
135684
136241
|
warningCount: warnings.length,
|
|
@@ -135689,16 +136246,16 @@ var CategoryAdapter = class {
|
|
|
135689
136246
|
/**
|
|
135690
136247
|
* Build a composition path from a pipeline
|
|
135691
136248
|
*/
|
|
135692
|
-
buildCompositionPath(
|
|
135693
|
-
const path26 = [
|
|
135694
|
-
for (const element of
|
|
136249
|
+
buildCompositionPath(pipeline10) {
|
|
136250
|
+
const path26 = [pipeline10.inputType];
|
|
136251
|
+
for (const element of pipeline10.elements) {
|
|
135695
136252
|
if (element.inputType !== path26[path26.length - 1]) {
|
|
135696
136253
|
path26.push(element.inputType);
|
|
135697
136254
|
}
|
|
135698
136255
|
path26.push(element.outputType);
|
|
135699
136256
|
}
|
|
135700
|
-
if (path26[path26.length - 1] !==
|
|
135701
|
-
path26.push(
|
|
136257
|
+
if (path26[path26.length - 1] !== pipeline10.outputType) {
|
|
136258
|
+
path26.push(pipeline10.outputType);
|
|
135702
136259
|
}
|
|
135703
136260
|
return path26;
|
|
135704
136261
|
}
|
|
@@ -135744,21 +136301,21 @@ var CategoryAdapter = class {
|
|
|
135744
136301
|
/**
|
|
135745
136302
|
* Generate warnings for potential issues
|
|
135746
136303
|
*/
|
|
135747
|
-
generateWarnings(
|
|
136304
|
+
generateWarnings(pipeline10, compositionValid, mismatches) {
|
|
135748
136305
|
const warnings = [];
|
|
135749
136306
|
if (!compositionValid) {
|
|
135750
136307
|
warnings.push(
|
|
135751
|
-
`Pipeline '${
|
|
136308
|
+
`Pipeline '${pipeline10.id}' has an invalid composition chain. Types do not connect properly from input to output.`
|
|
135752
136309
|
);
|
|
135753
136310
|
}
|
|
135754
|
-
for (const element of
|
|
136311
|
+
for (const element of pipeline10.elements) {
|
|
135755
136312
|
if (element.inputType === "any" || element.outputType === "any") {
|
|
135756
136313
|
warnings.push(
|
|
135757
136314
|
`Element '${element.name}' uses 'any' type, which bypasses type safety.`
|
|
135758
136315
|
);
|
|
135759
136316
|
}
|
|
135760
136317
|
}
|
|
135761
|
-
for (const element of
|
|
136318
|
+
for (const element of pipeline10.elements) {
|
|
135762
136319
|
if (element.inputType.includes("<T>") || element.outputType.includes("<T>")) {
|
|
135763
136320
|
warnings.push(
|
|
135764
136321
|
`Element '${element.name}' has unconstrained generic types.`
|
|
@@ -136668,21 +137225,21 @@ var CoherenceService = class {
|
|
|
136668
137225
|
/**
|
|
136669
137226
|
* Verify type consistency in a pipeline
|
|
136670
137227
|
*/
|
|
136671
|
-
async verifyTypes(
|
|
137228
|
+
async verifyTypes(pipeline10) {
|
|
136672
137229
|
this.ensureInitialized();
|
|
136673
137230
|
if (this.categoryAdapter?.isInitialized()) {
|
|
136674
|
-
return this.categoryAdapter.verifyPipeline(
|
|
137231
|
+
return this.categoryAdapter.verifyPipeline(pipeline10);
|
|
136675
137232
|
}
|
|
136676
|
-
return this.verifyTypesWithFallback(
|
|
137233
|
+
return this.verifyTypesWithFallback(pipeline10);
|
|
136677
137234
|
}
|
|
136678
137235
|
/**
|
|
136679
137236
|
* Fallback type verification using simple matching
|
|
136680
137237
|
*/
|
|
136681
|
-
verifyTypesWithFallback(
|
|
137238
|
+
verifyTypesWithFallback(pipeline10) {
|
|
136682
137239
|
const startTime = Date.now();
|
|
136683
137240
|
const mismatches = [];
|
|
136684
|
-
let currentType =
|
|
136685
|
-
for (const element of
|
|
137241
|
+
let currentType = pipeline10.inputType;
|
|
137242
|
+
for (const element of pipeline10.elements) {
|
|
136686
137243
|
if (element.inputType !== currentType && currentType !== "any") {
|
|
136687
137244
|
mismatches.push({
|
|
136688
137245
|
location: element.name,
|
|
@@ -136693,10 +137250,10 @@ var CoherenceService = class {
|
|
|
136693
137250
|
}
|
|
136694
137251
|
currentType = element.outputType;
|
|
136695
137252
|
}
|
|
136696
|
-
if (currentType !==
|
|
137253
|
+
if (currentType !== pipeline10.outputType && currentType !== "any") {
|
|
136697
137254
|
mismatches.push({
|
|
136698
137255
|
location: "pipeline output",
|
|
136699
|
-
expected:
|
|
137256
|
+
expected: pipeline10.outputType,
|
|
136700
137257
|
actual: currentType,
|
|
136701
137258
|
severity: "critical"
|
|
136702
137259
|
});
|
|
@@ -139196,7 +139753,7 @@ import chalk28 from "chalk";
|
|
|
139196
139753
|
import path24 from "node:path";
|
|
139197
139754
|
import { createReadStream, createWriteStream } from "node:fs";
|
|
139198
139755
|
import { createGzip, createGunzip } from "node:zlib";
|
|
139199
|
-
import { pipeline as
|
|
139756
|
+
import { pipeline as pipeline9 } from "node:stream/promises";
|
|
139200
139757
|
init_qe_patterns();
|
|
139201
139758
|
var state2 = {
|
|
139202
139759
|
reasoningBank: null,
|
|
@@ -139324,7 +139881,7 @@ function getDbPath() {
|
|
|
139324
139881
|
}
|
|
139325
139882
|
async function compressFile(inputPath, outputPath) {
|
|
139326
139883
|
const gzPath = outputPath || `${inputPath}.gz`;
|
|
139327
|
-
await
|
|
139884
|
+
await pipeline9(
|
|
139328
139885
|
createReadStream(inputPath),
|
|
139329
139886
|
createGzip(),
|
|
139330
139887
|
createWriteStream(gzPath)
|
|
@@ -139332,7 +139889,7 @@ async function compressFile(inputPath, outputPath) {
|
|
|
139332
139889
|
return gzPath;
|
|
139333
139890
|
}
|
|
139334
139891
|
async function decompressFile(gzPath, outputPath) {
|
|
139335
|
-
await
|
|
139892
|
+
await pipeline9(
|
|
139336
139893
|
createReadStream(gzPath),
|
|
139337
139894
|
createGunzip(),
|
|
139338
139895
|
createWriteStream(outputPath)
|
|
@@ -140544,7 +141101,7 @@ async function cleanupAndExit(code = 0) {
|
|
|
140544
141101
|
process.exit(code);
|
|
140545
141102
|
}
|
|
140546
141103
|
var program = new Command18();
|
|
140547
|
-
var VERSION = true ? "3.6.
|
|
141104
|
+
var VERSION = true ? "3.6.16" : "0.0.0-dev";
|
|
140548
141105
|
program.name("aqe").description("Agentic QE - Domain-Driven Quality Engineering").version(VERSION);
|
|
140549
141106
|
var registry = createCommandRegistry(context, cleanupAndExit, ensureInitialized);
|
|
140550
141107
|
registry.registerAll(program);
|
|
@@ -140828,22 +141385,22 @@ Validating pipeline: ${file}
|
|
|
140828
141385
|
console.log("");
|
|
140829
141386
|
}
|
|
140830
141387
|
if (options.verbose && parseResult.pipeline) {
|
|
140831
|
-
const
|
|
141388
|
+
const pipeline10 = parseResult.pipeline;
|
|
140832
141389
|
console.log(chalk30.cyan("Pipeline Details:\n"));
|
|
140833
|
-
console.log(chalk30.gray(` Name: ${
|
|
140834
|
-
console.log(chalk30.gray(` Version: ${
|
|
140835
|
-
if (
|
|
140836
|
-
console.log(chalk30.gray(` Description: ${
|
|
141390
|
+
console.log(chalk30.gray(` Name: ${pipeline10.name}`));
|
|
141391
|
+
console.log(chalk30.gray(` Version: ${pipeline10.version || "1.0.0"}`));
|
|
141392
|
+
if (pipeline10.description) {
|
|
141393
|
+
console.log(chalk30.gray(` Description: ${pipeline10.description}`));
|
|
140837
141394
|
}
|
|
140838
|
-
if (
|
|
140839
|
-
console.log(chalk30.gray(` Schedule: ${
|
|
141395
|
+
if (pipeline10.schedule) {
|
|
141396
|
+
console.log(chalk30.gray(` Schedule: ${pipeline10.schedule} (${describeCronSchedule(pipeline10.schedule)})`));
|
|
140840
141397
|
}
|
|
140841
|
-
if (
|
|
140842
|
-
console.log(chalk30.gray(` Tags: ${
|
|
141398
|
+
if (pipeline10.tags && pipeline10.tags.length > 0) {
|
|
141399
|
+
console.log(chalk30.gray(` Tags: ${pipeline10.tags.join(", ")}`));
|
|
140843
141400
|
}
|
|
140844
141401
|
console.log(chalk30.cyan("\n Stages:"));
|
|
140845
|
-
for (let i58 = 0; i58 <
|
|
140846
|
-
const stage =
|
|
141402
|
+
for (let i58 = 0; i58 < pipeline10.stages.length; i58++) {
|
|
141403
|
+
const stage = pipeline10.stages[i58];
|
|
140847
141404
|
console.log(` ${i58 + 1}. ${chalk30.white(stage.name)}`);
|
|
140848
141405
|
console.log(chalk30.gray(` Command: ${stage.command}`));
|
|
140849
141406
|
if (stage.params) {
|
|
@@ -140856,9 +141413,9 @@ Validating pipeline: ${file}
|
|
|
140856
141413
|
console.log(chalk30.gray(` Timeout: ${stage.timeout}s`));
|
|
140857
141414
|
}
|
|
140858
141415
|
}
|
|
140859
|
-
if (
|
|
141416
|
+
if (pipeline10.triggers && pipeline10.triggers.length > 0) {
|
|
140860
141417
|
console.log(chalk30.cyan("\n Triggers:"));
|
|
140861
|
-
for (const trigger of
|
|
141418
|
+
for (const trigger of pipeline10.triggers) {
|
|
140862
141419
|
console.log(chalk30.gray(` * ${trigger.event}`));
|
|
140863
141420
|
if (trigger.branches) {
|
|
140864
141421
|
console.log(chalk30.gray(` Branches: ${trigger.branches.join(", ")}`));
|