@testchimp/cli 0.1.25 → 0.1.27

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.
@@ -284,15 +284,33 @@ export function buildCliProgram() {
284
284
  .description(TOOL_DEFINITIONS.find((t) => t.kebab === "get-test-scenarios").description)
285
285
  .addOption(jsonInputOption())
286
286
  .option("--scenario-ordinal-ids <csv>", "comma-separated TS-<n> numeric ids")
287
+ .option("--external-ids <csv>", "comma-separated external TMS ids (e.g. C12345,PROJ-101); server matches exact then numerical part")
287
288
  .action(async (opts) => {
288
289
  const body = {};
289
290
  if (opts.scenarioOrdinalIds) {
290
- body.scenarioOrdinalIds = String(opts.scenarioOrdinalIds)
291
+ const ids = String(opts.scenarioOrdinalIds)
291
292
  .split(",")
292
293
  .map((s) => Number(s.trim()))
293
294
  .filter((n) => Number.isFinite(n) && n > 0);
295
+ if (ids.length > 0)
296
+ body.scenarioOrdinalIds = ids;
297
+ }
298
+ if (opts.externalIds) {
299
+ const ids = String(opts.externalIds)
300
+ .split(",")
301
+ .map((s) => s.trim())
302
+ .filter((s) => s.length > 0);
303
+ if (ids.length > 0)
304
+ body.externalIds = ids;
294
305
  }
295
306
  const merged = mergeBodies(body, opts.jsonInput);
307
+ // Drop empty arrays so refine / merge with json-input does not fail misleadingly.
308
+ if (Array.isArray(merged.scenarioOrdinalIds) && merged.scenarioOrdinalIds.length === 0) {
309
+ delete merged.scenarioOrdinalIds;
310
+ }
311
+ if (Array.isArray(merged.externalIds) && merged.externalIds.length === 0) {
312
+ delete merged.externalIds;
313
+ }
296
314
  const out = await runTool("get-test-scenarios", merged, { postMcp });
297
315
  console.log(out);
298
316
  });
@@ -918,6 +936,33 @@ export function buildCliProgram() {
918
936
  const out = await runTool("mark-semantic-tests-distinct", merged, { postMcp });
919
937
  console.log(out);
920
938
  });
939
+ program
940
+ .command("list-semantic-nearby")
941
+ .description(TOOL_DEFINITIONS.find((t) => t.kebab === "list-semantic-nearby").description)
942
+ .addOption(jsonInputOption())
943
+ .action(async (opts) => {
944
+ const merged = mergeBodies({}, opts.jsonInput);
945
+ const out = await runTool("list-semantic-nearby", merged, { postMcp });
946
+ console.log(out);
947
+ });
948
+ program
949
+ .command("mark-entity-distinct")
950
+ .description(TOOL_DEFINITIONS.find((t) => t.kebab === "mark-entity-distinct").description)
951
+ .addOption(jsonInputOption())
952
+ .action(async (opts) => {
953
+ const merged = mergeBodies({}, opts.jsonInput);
954
+ const out = await runTool("mark-entity-distinct", merged, { postMcp });
955
+ console.log(out);
956
+ });
957
+ program
958
+ .command("unmark-entity-distinct")
959
+ .description(TOOL_DEFINITIONS.find((t) => t.kebab === "unmark-entity-distinct").description)
960
+ .addOption(jsonInputOption())
961
+ .action(async (opts) => {
962
+ const merged = mergeBodies({}, opts.jsonInput);
963
+ const out = await runTool("unmark-entity-distinct", merged, { postMcp });
964
+ console.log(out);
965
+ });
921
966
  program
922
967
  .command("get-requirement-quality-report")
923
968
  .description(TOOL_DEFINITIONS.find((t) => t.kebab === "get-requirement-quality-report").description)
@@ -226,7 +226,8 @@ export declare const getUserStoriesInput: z.ZodObject<{
226
226
  userStoryOrdinalIds: z.ZodArray<z.ZodCoercedNumber<unknown>>;
227
227
  }, z.core.$strip>;
228
228
  export declare const getTestScenariosInput: z.ZodObject<{
229
- scenarioOrdinalIds: z.ZodArray<z.ZodCoercedNumber<unknown>>;
229
+ scenarioOrdinalIds: z.ZodOptional<z.ZodArray<z.ZodCoercedNumber<unknown>>>;
230
+ externalIds: z.ZodOptional<z.ZodArray<z.ZodString>>;
230
231
  }, z.core.$strip>;
231
232
  export declare const getManualSessionDetailsInput: z.ZodObject<{
232
233
  manualSessionId: z.ZodString;
@@ -923,6 +924,64 @@ export declare const markSemanticTestsDistinctInput: z.ZodObject<{
923
924
  testName: z.ZodString;
924
925
  }, z.core.$strip>;
925
926
  }, z.core.$strip>;
927
+ /** LinkedEntityType names for semantic nearby (embedding-capable). */
928
+ export declare const semanticNearbyEntityTypeSchema: z.ZodEnum<{
929
+ STORY: "STORY";
930
+ SCENARIO: "SCENARIO";
931
+ TEST: "TEST";
932
+ ISSUE: "ISSUE";
933
+ EVENT: "EVENT";
934
+ }>;
935
+ export declare const listSemanticNearbyInput: z.ZodObject<{
936
+ sourceEntityType: z.ZodEnum<{
937
+ STORY: "STORY";
938
+ SCENARIO: "SCENARIO";
939
+ TEST: "TEST";
940
+ ISSUE: "ISSUE";
941
+ EVENT: "EVENT";
942
+ }>;
943
+ sourceTest: z.ZodOptional<z.ZodObject<{
944
+ folderPath: z.ZodOptional<z.ZodArray<z.ZodString>>;
945
+ fileName: z.ZodString;
946
+ testSuite: z.ZodOptional<z.ZodArray<z.ZodString>>;
947
+ testName: z.ZodString;
948
+ }, z.core.$strip>>;
949
+ sourceOrdinalId: z.ZodOptional<z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>>;
950
+ sourceEventTitle: z.ZodOptional<z.ZodString>;
951
+ targetEntityTypes: z.ZodOptional<z.ZodArray<z.ZodEnum<{
952
+ STORY: "STORY";
953
+ SCENARIO: "SCENARIO";
954
+ TEST: "TEST";
955
+ ISSUE: "ISSUE";
956
+ EVENT: "EVENT";
957
+ }>>>;
958
+ limit: z.ZodOptional<z.ZodNumber>;
959
+ }, z.core.$strip>;
960
+ export declare const markEntityDistinctInput: z.ZodObject<{
961
+ entityType: z.ZodEnum<{
962
+ STORY: "STORY";
963
+ SCENARIO: "SCENARIO";
964
+ TEST: "TEST";
965
+ ISSUE: "ISSUE";
966
+ EVENT: "EVENT";
967
+ }>;
968
+ focusTest: z.ZodOptional<z.ZodObject<{
969
+ folderPath: z.ZodOptional<z.ZodArray<z.ZodString>>;
970
+ fileName: z.ZodString;
971
+ testSuite: z.ZodOptional<z.ZodArray<z.ZodString>>;
972
+ testName: z.ZodString;
973
+ }, z.core.$strip>>;
974
+ otherTest: z.ZodOptional<z.ZodObject<{
975
+ folderPath: z.ZodOptional<z.ZodArray<z.ZodString>>;
976
+ fileName: z.ZodString;
977
+ testSuite: z.ZodOptional<z.ZodArray<z.ZodString>>;
978
+ testName: z.ZodString;
979
+ }, z.core.$strip>>;
980
+ focusOrdinalId: z.ZodOptional<z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>>;
981
+ otherOrdinalId: z.ZodOptional<z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>>;
982
+ focusEventTitle: z.ZodOptional<z.ZodString>;
983
+ otherEventTitle: z.ZodOptional<z.ZodString>;
984
+ }, z.core.$strip>;
926
985
  /** RequirementSubjectType — proto enum names (JsonFormat camelCase on wire). */
927
986
  export declare const requirementSubjectTypeSchema: z.ZodEnum<{
928
987
  STORY: "STORY";
@@ -1233,11 +1292,11 @@ export declare const agentActionEntityTypeSchema: z.ZodEnum<{
1233
1292
  SCENARIO: "SCENARIO";
1234
1293
  ISSUE: "ISSUE";
1235
1294
  TEST_EXECUTION: "TEST_EXECUTION";
1295
+ EVENT: "EVENT";
1236
1296
  USER_STORY: "USER_STORY";
1237
1297
  POLICY: "POLICY";
1238
1298
  TEST_INVOCATION_BATCH: "TEST_INVOCATION_BATCH";
1239
1299
  EXPLORATION: "EXPLORATION";
1240
- EVENT: "EVENT";
1241
1300
  WORKFLOW: "WORKFLOW";
1242
1301
  }>;
1243
1302
  export declare const agentActionTypeSchema: z.ZodEnum<{
@@ -1294,11 +1353,11 @@ export declare const reportAgentActionInput: z.ZodObject<{
1294
1353
  SCENARIO: "SCENARIO";
1295
1354
  ISSUE: "ISSUE";
1296
1355
  TEST_EXECUTION: "TEST_EXECUTION";
1356
+ EVENT: "EVENT";
1297
1357
  USER_STORY: "USER_STORY";
1298
1358
  POLICY: "POLICY";
1299
1359
  TEST_INVOCATION_BATCH: "TEST_INVOCATION_BATCH";
1300
1360
  EXPLORATION: "EXPLORATION";
1301
- EVENT: "EVENT";
1302
1361
  WORKFLOW: "WORKFLOW";
1303
1362
  }>;
1304
1363
  entityIdentity: z.ZodOptional<z.ZodString>;
@@ -111,8 +111,12 @@ export const getUserStoriesInput = z
111
111
  });
112
112
  export const getTestScenariosInput = z
113
113
  .object({
114
- scenarioOrdinalIds: z.array(z.coerce.number().int().positive()).min(1),
115
- });
114
+ scenarioOrdinalIds: z.array(z.coerce.number().int().positive()).min(1).optional(),
115
+ /** Full TMS external ids (e.g. C12345, PROJ-101). Server matches exact then numerical part. */
116
+ externalIds: z.array(z.string().min(1)).min(1).optional(),
117
+ })
118
+ .refine((v) => (v.scenarioOrdinalIds != null && v.scenarioOrdinalIds.length > 0) ||
119
+ (v.externalIds != null && v.externalIds.length > 0), { message: "Provide scenarioOrdinalIds and/or externalIds (non-empty)" });
116
120
  export const getManualSessionDetailsInput = z.object({
117
121
  manualSessionId: z.string().min(1),
118
122
  });
@@ -413,6 +417,83 @@ export const markSemanticTestsDistinctInput = z.object({
413
417
  focusTest: testLocatorSchema,
414
418
  distinctTest: testLocatorSchema,
415
419
  });
420
+ /** LinkedEntityType names for semantic nearby (embedding-capable). */
421
+ export const semanticNearbyEntityTypeSchema = z.enum([
422
+ "STORY",
423
+ "SCENARIO",
424
+ "TEST",
425
+ "ISSUE",
426
+ "EVENT",
427
+ ]);
428
+ export const listSemanticNearbyInput = z
429
+ .object({
430
+ sourceEntityType: semanticNearbyEntityTypeSchema,
431
+ sourceTest: testLocatorSchema.optional(),
432
+ sourceOrdinalId: z.union([z.number(), z.string()]).optional(),
433
+ sourceEventTitle: z.string().optional(),
434
+ targetEntityTypes: z.array(semanticNearbyEntityTypeSchema).optional(),
435
+ limit: z.number().int().positive().optional(),
436
+ })
437
+ .superRefine((val, ctx) => {
438
+ if (val.sourceEntityType === "TEST" && !val.sourceTest) {
439
+ ctx.addIssue({
440
+ code: z.ZodIssueCode.custom,
441
+ message: "TEST requires sourceTest (TestLocator)",
442
+ path: ["sourceTest"],
443
+ });
444
+ }
445
+ if ((val.sourceEntityType === "STORY" ||
446
+ val.sourceEntityType === "SCENARIO" ||
447
+ val.sourceEntityType === "ISSUE") &&
448
+ (val.sourceOrdinalId == null || String(val.sourceOrdinalId).trim() === "")) {
449
+ ctx.addIssue({
450
+ code: z.ZodIssueCode.custom,
451
+ message: `${val.sourceEntityType} requires sourceOrdinalId`,
452
+ path: ["sourceOrdinalId"],
453
+ });
454
+ }
455
+ if (val.sourceEntityType === "EVENT" && !(val.sourceEventTitle ?? "").trim()) {
456
+ ctx.addIssue({
457
+ code: z.ZodIssueCode.custom,
458
+ message: "EVENT requires sourceEventTitle",
459
+ path: ["sourceEventTitle"],
460
+ });
461
+ }
462
+ });
463
+ export const markEntityDistinctInput = z
464
+ .object({
465
+ entityType: semanticNearbyEntityTypeSchema,
466
+ focusTest: testLocatorSchema.optional(),
467
+ otherTest: testLocatorSchema.optional(),
468
+ focusOrdinalId: z.union([z.number(), z.string()]).optional(),
469
+ otherOrdinalId: z.union([z.number(), z.string()]).optional(),
470
+ focusEventTitle: z.string().optional(),
471
+ otherEventTitle: z.string().optional(),
472
+ })
473
+ .superRefine((val, ctx) => {
474
+ if (val.entityType === "TEST") {
475
+ if (!val.focusTest || !val.otherTest) {
476
+ ctx.addIssue({
477
+ code: z.ZodIssueCode.custom,
478
+ message: "TEST requires focusTest and otherTest",
479
+ });
480
+ }
481
+ }
482
+ else if (val.entityType === "EVENT") {
483
+ if (!(val.focusEventTitle ?? "").trim() || !(val.otherEventTitle ?? "").trim()) {
484
+ ctx.addIssue({
485
+ code: z.ZodIssueCode.custom,
486
+ message: "EVENT requires focusEventTitle and otherEventTitle",
487
+ });
488
+ }
489
+ }
490
+ else if (val.focusOrdinalId == null || val.otherOrdinalId == null) {
491
+ ctx.addIssue({
492
+ code: z.ZodIssueCode.custom,
493
+ message: `${val.entityType} requires focusOrdinalId and otherOrdinalId`,
494
+ });
495
+ }
496
+ });
416
497
  /** RequirementSubjectType — proto enum names (JsonFormat camelCase on wire). */
417
498
  export const requirementSubjectTypeSchema = z.enum(["STORY", "SCENARIO"]);
418
499
  /** RequirementFindingSeverity — proto enum names. */
@@ -258,15 +258,20 @@ export const TOOL_DEFINITIONS = [
258
258
  },
259
259
  {
260
260
  kebab: "get-test-scenarios",
261
- description: "Fetch test scenarios from the TestChimp platform by ordinal id (numeric part of TS-<n>). " +
262
- "Returns full plan markdown content, title, platform file path, and linked user story ordinal ids. " +
263
- "Use when plan files are not yet synced to the repo.",
261
+ description: "Fetch test scenarios from the TestChimp platform by ordinal id (numeric part of TS-<n>) " +
262
+ "and/or external TMS ids (e.g. C12345, PROJ-101 server strips prefixes and matches numerical part). " +
263
+ "Returns full plan markdown content, title, platform file path, linked user story ordinal ids, " +
264
+ "and external_source / external_system_id when present. " +
265
+ "Use when plan files are not yet synced to the repo, or when linking imported tests to scenarios by TMS id.",
264
266
  inputSchema: S.getTestScenariosInput,
265
267
  execute: async (args, { postMcp }) => {
266
268
  const a = args;
267
- return postMcp("/api/mcp/get_test_scenarios", {
268
- scenarioOrdinalIds: a.scenarioOrdinalIds,
269
- });
269
+ const body = {};
270
+ if (a.scenarioOrdinalIds?.length)
271
+ body.scenarioOrdinalIds = a.scenarioOrdinalIds;
272
+ if (a.externalIds?.length)
273
+ body.externalIds = a.externalIds;
274
+ return postMcp("/api/mcp/get_test_scenarios", body);
270
275
  },
271
276
  },
272
277
  {
@@ -323,6 +328,8 @@ export const TOOL_DEFINITIONS = [
323
328
  "Use simple fields for common creates, or pass the full curated contract via --json-input " +
324
329
  "(description, issueType, category, severity, status, reportedReleaseId, dueDateMillis, assignee, " +
325
330
  "linkTargets, labels, source, environment, attachments, artifactReference). " +
331
+ "For /testchimp implement TASK_ISSUE creates: set labels=[\"TestChimp Implement\"] (not source), " +
332
+ "severity from task priority, category (e.g. FUNCTIONAL), and linkTargets for STORY and/or SCENARIO ordinals. " +
326
333
  "Optional agentTraceability (or flat workflowId/policyFile/…) records CREATED Activity inline — " +
327
334
  "prefer this over a separate report-agent-action for issue creates. " +
328
335
  "Authenticated via project API key; project is resolved from the key.",
@@ -778,6 +785,75 @@ export const TOOL_DEFINITIONS = [
778
785
  });
779
786
  },
780
787
  },
788
+ {
789
+ kebab: "list-semantic-nearby",
790
+ description: "List semantically nearby entities across types (Story/Scenario/Test/Issue/Event). " +
791
+ "TEST uses TestLocator; STORY/SCENARIO/ISSUE use sourceOrdinalId; EVENT uses sourceEventTitle. " +
792
+ "Response TEST hits include TestLocator (never platform test_id).",
793
+ inputSchema: S.listSemanticNearbyInput,
794
+ execute: async (args, { postMcp }) => {
795
+ const a = args;
796
+ const body = {
797
+ sourceEntityType: a.sourceEntityType,
798
+ };
799
+ if (a.sourceTest)
800
+ body.sourceTest = a.sourceTest;
801
+ if (a.sourceOrdinalId != null)
802
+ body.sourceOrdinalId = Number(a.sourceOrdinalId);
803
+ if (a.sourceEventTitle)
804
+ body.sourceEventTitle = a.sourceEventTitle;
805
+ if (a.targetEntityTypes?.length)
806
+ body.targetEntityTypes = a.targetEntityTypes;
807
+ if (a.limit != null)
808
+ body.limit = a.limit;
809
+ return postMcp("/api/mcp/list_semantic_nearby", body);
810
+ },
811
+ },
812
+ {
813
+ kebab: "mark-entity-distinct",
814
+ description: "Mark two same-type entities as distinct. TEST uses TestLocators; " +
815
+ "STORY/SCENARIO/ISSUE use ordinals; EVENT uses titles.",
816
+ inputSchema: S.markEntityDistinctInput,
817
+ execute: async (args, { postMcp }) => {
818
+ const a = args;
819
+ const body = { entityType: a.entityType };
820
+ if (a.focusTest)
821
+ body.focusTest = a.focusTest;
822
+ if (a.otherTest)
823
+ body.otherTest = a.otherTest;
824
+ if (a.focusOrdinalId != null)
825
+ body.focusOrdinalId = Number(a.focusOrdinalId);
826
+ if (a.otherOrdinalId != null)
827
+ body.otherOrdinalId = Number(a.otherOrdinalId);
828
+ if (a.focusEventTitle)
829
+ body.focusEventTitle = a.focusEventTitle;
830
+ if (a.otherEventTitle)
831
+ body.otherEventTitle = a.otherEventTitle;
832
+ return postMcp("/api/mcp/mark_entity_distinct", body);
833
+ },
834
+ },
835
+ {
836
+ kebab: "unmark-entity-distinct",
837
+ description: "Remove a distinct mark between two same-type entities (same identity rules as mark-entity-distinct).",
838
+ inputSchema: S.markEntityDistinctInput,
839
+ execute: async (args, { postMcp }) => {
840
+ const a = args;
841
+ const body = { entityType: a.entityType };
842
+ if (a.focusTest)
843
+ body.focusTest = a.focusTest;
844
+ if (a.otherTest)
845
+ body.otherTest = a.otherTest;
846
+ if (a.focusOrdinalId != null)
847
+ body.focusOrdinalId = Number(a.focusOrdinalId);
848
+ if (a.otherOrdinalId != null)
849
+ body.otherOrdinalId = Number(a.otherOrdinalId);
850
+ if (a.focusEventTitle)
851
+ body.focusEventTitle = a.focusEventTitle;
852
+ if (a.otherEventTitle)
853
+ body.otherEventTitle = a.otherEventTitle;
854
+ return postMcp("/api/mcp/unmark_entity_distinct", body);
855
+ },
856
+ },
781
857
  {
782
858
  kebab: "get-requirement-quality-report",
783
859
  description: "Fetch the stored requirement quality report (metrics + findings with user states) for a user story or test scenario. " +
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@testchimp/cli",
3
- "version": "0.1.25",
3
+ "version": "0.1.27",
4
4
  "description": "TestChimp CLI and MCP server \u2014 coverage, plans, EaaS, TrueCoverage (calls /api/mcp/*)",
5
5
  "type": "module",
6
6
  "main": "dist/bin/testchimp.js",