@testchimp/cli 0.1.18 → 0.1.20

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.
@@ -849,6 +849,133 @@ export function buildCliProgram() {
849
849
  const out = await runTool("mark-semantic-tests-distinct", merged, { postMcp });
850
850
  console.log(out);
851
851
  });
852
+ program
853
+ .command("get-requirement-quality-report")
854
+ .description(TOOL_DEFINITIONS.find((t) => t.kebab === "get-requirement-quality-report").description)
855
+ .addOption(jsonInputOption())
856
+ .option("--subject-type <STORY|SCENARIO>", "STORY for US-<n>, SCENARIO for TS-<n>")
857
+ .option("--subject-entity-id <id>", "Platform subject entity id")
858
+ .option("--ordinal-id <n>", "Numeric part of US-<n> or TS-<n>")
859
+ .action(async (opts) => {
860
+ const body = {};
861
+ if (opts.subjectType)
862
+ body.subjectType = String(opts.subjectType).trim();
863
+ if (opts.subjectEntityId)
864
+ body.subjectEntityId = String(opts.subjectEntityId).trim();
865
+ if (opts.ordinalId != null)
866
+ body.ordinalId = Number(opts.ordinalId);
867
+ const merged = mergeBodies(body, opts.jsonInput);
868
+ if (!merged.subjectType || String(merged.subjectType).trim() === "") {
869
+ throw new Error("subjectType is required (STORY | SCENARIO)");
870
+ }
871
+ const out = await runTool("get-requirement-quality-report", {
872
+ subjectType: String(merged.subjectType).trim(),
873
+ ...(merged.subjectEntityId ? { subjectEntityId: String(merged.subjectEntityId).trim() } : {}),
874
+ ...(merged.ordinalId != null ? { ordinalId: Number(merged.ordinalId) } : {}),
875
+ }, { postMcp });
876
+ console.log(out);
877
+ });
878
+ program
879
+ .command("report-requirement-quality-findings")
880
+ .description(TOOL_DEFINITIONS.find((t) => t.kebab === "report-requirement-quality-findings").description)
881
+ .addOption(jsonInputOption())
882
+ .option("--report-file <path>", "Path to RequirementQualityReport JSON (camelCase)")
883
+ .option("--subject-type <STORY|SCENARIO>", "Merge into report.subject when resolving entity id")
884
+ .option("--subject-entity-id <id>", "Platform subject entity id (story DB id or scenario UUID)")
885
+ .option("--ordinal-id <n>", "US-<n> or TS-<n> numeric id; resolves subjectEntityId via get-report")
886
+ .action(async (opts) => {
887
+ const body = {};
888
+ if (opts.reportFile)
889
+ body.reportFile = String(opts.reportFile);
890
+ if (opts.subjectType)
891
+ body.subjectType = String(opts.subjectType).trim();
892
+ if (opts.subjectEntityId)
893
+ body.subjectEntityId = String(opts.subjectEntityId).trim();
894
+ if (opts.ordinalId != null)
895
+ body.ordinalId = Number(opts.ordinalId);
896
+ const merged = mergeBodies(body, opts.jsonInput);
897
+ const out = await runTool("report-requirement-quality-findings", merged, { postMcp });
898
+ console.log(out);
899
+ });
900
+ // Workflow policy + traceability tools (US-181). Prefer --json-input for nested TestLocator.
901
+ program
902
+ .command("report-agent-action")
903
+ .description(TOOL_DEFINITIONS.find((t) => t.kebab === "report-agent-action").description)
904
+ .addOption(jsonInputOption())
905
+ .requiredOption("--workflow-id <id>", "Catalog workflow id")
906
+ .requiredOption("--workflow-execution-id <ulid>", "Stable ULID for the whole run")
907
+ .requiredOption("--action-type <type>", "CREATED|UPDATED|DELETED|ANALYZED|ACTION_COMPLETED|ACTION_FAILED")
908
+ .option("--policy-file <name>", "Policy filename")
909
+ .option("--policy-version <semver>", "Policy version from frontmatter")
910
+ .option("--git-sha <sha>", "Current HEAD sha")
911
+ .option("--actor-type <type>", "LOCAL_AGENT|CLOUD_AGENT (or local-agent|cloud-agent)")
912
+ .option("--user-id <id>", "Optional user id for traceability")
913
+ .option("--branch-name <name>", "Git branch")
914
+ .option("--entity-type <type>", "test|story|scenario|issue|workflow|…")
915
+ .option("--entity-identity <ordinal>", "Project-scoped ordinal id (mutually exclusive with --test-json)")
916
+ .option("--test-json <json>", "TestLocator JSON (folderPath/fileName/testSuite/testName)")
917
+ .option("--detail-json <json>", "Optional detail payload")
918
+ .action(async (opts) => {
919
+ const body = {
920
+ workflowId: String(opts.workflowId),
921
+ workflowExecutionId: String(opts.workflowExecutionId),
922
+ actionType: String(opts.actionType),
923
+ };
924
+ if (opts.policyFile)
925
+ body.policyFile = String(opts.policyFile);
926
+ if (opts.policyVersion)
927
+ body.policyVersion = String(opts.policyVersion);
928
+ if (opts.gitSha)
929
+ body.gitSha = String(opts.gitSha);
930
+ if (opts.actorType)
931
+ body.actorType = String(opts.actorType);
932
+ if (opts.userId)
933
+ body.userId = String(opts.userId);
934
+ if (opts.branchName)
935
+ body.branchName = String(opts.branchName);
936
+ if (opts.entityType)
937
+ body.entityType = String(opts.entityType);
938
+ if (opts.entityIdentity)
939
+ body.entityIdentity = String(opts.entityIdentity);
940
+ if (opts.testJson)
941
+ body.test = JSON.parse(String(opts.testJson));
942
+ if (opts.detailJson)
943
+ body.detailJson = String(opts.detailJson);
944
+ const merged = mergeBodies(body, opts.jsonInput);
945
+ console.log(await runTool("report-agent-action", merged, { postMcp }));
946
+ });
947
+ program
948
+ .command("get-last-run-workflow-detail")
949
+ .description(TOOL_DEFINITIONS.find((t) => t.kebab === "get-last-run-workflow-detail").description)
950
+ .addOption(jsonInputOption())
951
+ .requiredOption("--workflow-id <id>", "Catalog workflow id")
952
+ .option("--branch-name <name>", "Optional branch filter (omit for any branch)")
953
+ .option("--user-id <id>", "Optional per-user last run")
954
+ .action(async (opts) => {
955
+ const body = { workflowId: String(opts.workflowId) };
956
+ if (opts.branchName)
957
+ body.branchName = String(opts.branchName);
958
+ if (opts.userId)
959
+ body.userId = String(opts.userId);
960
+ const merged = mergeBodies(body, opts.jsonInput);
961
+ console.log(await runTool("get-last-run-workflow-detail", merged, { postMcp }));
962
+ });
963
+ for (const kebab of [
964
+ "list-workflow-executions",
965
+ "get-workflow-execution",
966
+ "get-policy",
967
+ "list-policies",
968
+ "list-workflow-catalog",
969
+ ]) {
970
+ program
971
+ .command(kebab)
972
+ .description(TOOL_DEFINITIONS.find((t) => t.kebab === kebab).description)
973
+ .addOption(jsonInputOption())
974
+ .action(async (opts) => {
975
+ const merged = mergeBodies({}, opts.jsonInput);
976
+ console.log(await runTool(kebab, merged, { postMcp }));
977
+ });
978
+ }
852
979
  program.on("--help", () => {
853
980
  /* default */
854
981
  });
@@ -711,3 +711,390 @@ export declare const markSemanticTestsDistinctInput: z.ZodObject<{
711
711
  testName: z.ZodString;
712
712
  }, z.core.$strip>;
713
713
  }, z.core.$strip>;
714
+ /** RequirementSubjectType — proto enum names (JsonFormat camelCase on wire). */
715
+ export declare const requirementSubjectTypeSchema: z.ZodEnum<{
716
+ STORY: "STORY";
717
+ SCENARIO: "SCENARIO";
718
+ }>;
719
+ /** RequirementFindingSeverity — proto enum names. */
720
+ export declare const requirementFindingSeveritySchema: z.ZodEnum<{
721
+ CRITICAL: "CRITICAL";
722
+ MAJOR: "MAJOR";
723
+ MINOR: "MINOR";
724
+ }>;
725
+ /** RequirementFindingUserState — proto enum names. */
726
+ export declare const requirementFindingUserStateSchema: z.ZodEnum<{
727
+ ACTIVE: "ACTIVE";
728
+ IGNORED: "IGNORED";
729
+ APPLIED: "APPLIED";
730
+ }>;
731
+ /** RequirementQualityReportSource — proto enum names. */
732
+ export declare const requirementQualityReportSourceSchema: z.ZodEnum<{
733
+ CLOUD: "CLOUD";
734
+ LOCAL_AGENT: "LOCAL_AGENT";
735
+ }>;
736
+ /** SuggestedFixKind — proto enum names. */
737
+ export declare const suggestedFixKindSchema: z.ZodEnum<{
738
+ OTHER: "OTHER";
739
+ REWORD_EXCERPT: "REWORD_EXCERPT";
740
+ REWRITE_SECTION: "REWRITE_SECTION";
741
+ ADD_CONTENT: "ADD_CONTENT";
742
+ CREATE_SCENARIO: "CREATE_SCENARIO";
743
+ CREATE_STORY: "CREATE_STORY";
744
+ DELETE_SCENARIO: "DELETE_SCENARIO";
745
+ DELETE_STORY: "DELETE_STORY";
746
+ LINK_OR_UNLINK: "LINK_OR_UNLINK";
747
+ }>;
748
+ /** TextReplacement (requirement_quality.proto) — camelCase wire shape. */
749
+ export declare const textReplacementSchema: z.ZodObject<{
750
+ originalExcerpt: z.ZodOptional<z.ZodString>;
751
+ suggestedText: z.ZodOptional<z.ZodString>;
752
+ contextBefore: z.ZodOptional<z.ZodString>;
753
+ contextAfter: z.ZodOptional<z.ZodString>;
754
+ }, z.core.$strip>;
755
+ /** SuggestedFix (requirement_quality.proto). isDestructive is derived server-side from kind. */
756
+ export declare const suggestedFixSchema: z.ZodObject<{
757
+ kind: z.ZodOptional<z.ZodEnum<{
758
+ OTHER: "OTHER";
759
+ REWORD_EXCERPT: "REWORD_EXCERPT";
760
+ REWRITE_SECTION: "REWRITE_SECTION";
761
+ ADD_CONTENT: "ADD_CONTENT";
762
+ CREATE_SCENARIO: "CREATE_SCENARIO";
763
+ CREATE_STORY: "CREATE_STORY";
764
+ DELETE_SCENARIO: "DELETE_SCENARIO";
765
+ DELETE_STORY: "DELETE_STORY";
766
+ LINK_OR_UNLINK: "LINK_OR_UNLINK";
767
+ }>>;
768
+ isDestructive: z.ZodOptional<z.ZodBoolean>;
769
+ targetEntityType: z.ZodOptional<z.ZodString>;
770
+ targetOrdinalId: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
771
+ summary: z.ZodOptional<z.ZodString>;
772
+ agentPrompt: z.ZodOptional<z.ZodString>;
773
+ replacements: z.ZodOptional<z.ZodArray<z.ZodObject<{
774
+ originalExcerpt: z.ZodOptional<z.ZodString>;
775
+ suggestedText: z.ZodOptional<z.ZodString>;
776
+ contextBefore: z.ZodOptional<z.ZodString>;
777
+ contextAfter: z.ZodOptional<z.ZodString>;
778
+ }, z.core.$strip>>>;
779
+ rationale: z.ZodOptional<z.ZodString>;
780
+ }, z.core.$strip>;
781
+ /** RequirementQualityFinding (requirement_quality.proto). */
782
+ export declare const requirementQualityFindingSchema: z.ZodObject<{
783
+ id: z.ZodOptional<z.ZodString>;
784
+ fingerprint: z.ZodOptional<z.ZodString>;
785
+ analyst: z.ZodOptional<z.ZodString>;
786
+ severity: z.ZodOptional<z.ZodEnum<{
787
+ CRITICAL: "CRITICAL";
788
+ MAJOR: "MAJOR";
789
+ MINOR: "MINOR";
790
+ }>>;
791
+ confidence: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
792
+ title: z.ZodOptional<z.ZodString>;
793
+ detail: z.ZodOptional<z.ZodString>;
794
+ suggestedFix: z.ZodOptional<z.ZodObject<{
795
+ kind: z.ZodOptional<z.ZodEnum<{
796
+ OTHER: "OTHER";
797
+ REWORD_EXCERPT: "REWORD_EXCERPT";
798
+ REWRITE_SECTION: "REWRITE_SECTION";
799
+ ADD_CONTENT: "ADD_CONTENT";
800
+ CREATE_SCENARIO: "CREATE_SCENARIO";
801
+ CREATE_STORY: "CREATE_STORY";
802
+ DELETE_SCENARIO: "DELETE_SCENARIO";
803
+ DELETE_STORY: "DELETE_STORY";
804
+ LINK_OR_UNLINK: "LINK_OR_UNLINK";
805
+ }>>;
806
+ isDestructive: z.ZodOptional<z.ZodBoolean>;
807
+ targetEntityType: z.ZodOptional<z.ZodString>;
808
+ targetOrdinalId: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
809
+ summary: z.ZodOptional<z.ZodString>;
810
+ agentPrompt: z.ZodOptional<z.ZodString>;
811
+ replacements: z.ZodOptional<z.ZodArray<z.ZodObject<{
812
+ originalExcerpt: z.ZodOptional<z.ZodString>;
813
+ suggestedText: z.ZodOptional<z.ZodString>;
814
+ contextBefore: z.ZodOptional<z.ZodString>;
815
+ contextAfter: z.ZodOptional<z.ZodString>;
816
+ }, z.core.$strip>>>;
817
+ rationale: z.ZodOptional<z.ZodString>;
818
+ }, z.core.$strip>>;
819
+ userState: z.ZodOptional<z.ZodEnum<{
820
+ ACTIVE: "ACTIVE";
821
+ IGNORED: "IGNORED";
822
+ APPLIED: "APPLIED";
823
+ }>>;
824
+ }, z.core.$strip>;
825
+ /** RequirementQualityMetrics (requirement_quality.proto) — scores 0-100, counts among ACTIVE findings. */
826
+ export declare const requirementQualityMetricsSchema: z.ZodObject<{
827
+ overall: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
828
+ clarity: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
829
+ completeness: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
830
+ testability: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
831
+ consistency: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
832
+ ambiguityRisk: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
833
+ scenarioCoverage: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
834
+ criticalCount: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
835
+ majorCount: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
836
+ minorCount: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
837
+ }, z.core.$strip>;
838
+ /** RequirementQualitySubject (requirement_quality.proto). subjectEntityId is the platform-internal id. */
839
+ export declare const requirementQualitySubjectSchema: z.ZodObject<{
840
+ subjectType: z.ZodOptional<z.ZodEnum<{
841
+ STORY: "STORY";
842
+ SCENARIO: "SCENARIO";
843
+ }>>;
844
+ subjectEntityId: z.ZodOptional<z.ZodString>;
845
+ ordinalId: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
846
+ title: z.ZodOptional<z.ZodString>;
847
+ }, z.core.$strip>;
848
+ /** RequirementQualityReport (requirement_quality.proto) — full upload body shape. */
849
+ export declare const requirementQualityReportSchema: z.ZodObject<{
850
+ id: z.ZodOptional<z.ZodString>;
851
+ projectId: z.ZodOptional<z.ZodString>;
852
+ subject: z.ZodOptional<z.ZodObject<{
853
+ subjectType: z.ZodOptional<z.ZodEnum<{
854
+ STORY: "STORY";
855
+ SCENARIO: "SCENARIO";
856
+ }>>;
857
+ subjectEntityId: z.ZodOptional<z.ZodString>;
858
+ ordinalId: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
859
+ title: z.ZodOptional<z.ZodString>;
860
+ }, z.core.$strip>>;
861
+ source: z.ZodOptional<z.ZodEnum<{
862
+ CLOUD: "CLOUD";
863
+ LOCAL_AGENT: "LOCAL_AGENT";
864
+ }>>;
865
+ metrics: z.ZodOptional<z.ZodObject<{
866
+ overall: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
867
+ clarity: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
868
+ completeness: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
869
+ testability: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
870
+ consistency: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
871
+ ambiguityRisk: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
872
+ scenarioCoverage: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
873
+ criticalCount: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
874
+ majorCount: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
875
+ minorCount: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
876
+ }, z.core.$strip>>;
877
+ findings: z.ZodOptional<z.ZodArray<z.ZodObject<{
878
+ id: z.ZodOptional<z.ZodString>;
879
+ fingerprint: z.ZodOptional<z.ZodString>;
880
+ analyst: z.ZodOptional<z.ZodString>;
881
+ severity: z.ZodOptional<z.ZodEnum<{
882
+ CRITICAL: "CRITICAL";
883
+ MAJOR: "MAJOR";
884
+ MINOR: "MINOR";
885
+ }>>;
886
+ confidence: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
887
+ title: z.ZodOptional<z.ZodString>;
888
+ detail: z.ZodOptional<z.ZodString>;
889
+ suggestedFix: z.ZodOptional<z.ZodObject<{
890
+ kind: z.ZodOptional<z.ZodEnum<{
891
+ OTHER: "OTHER";
892
+ REWORD_EXCERPT: "REWORD_EXCERPT";
893
+ REWRITE_SECTION: "REWRITE_SECTION";
894
+ ADD_CONTENT: "ADD_CONTENT";
895
+ CREATE_SCENARIO: "CREATE_SCENARIO";
896
+ CREATE_STORY: "CREATE_STORY";
897
+ DELETE_SCENARIO: "DELETE_SCENARIO";
898
+ DELETE_STORY: "DELETE_STORY";
899
+ LINK_OR_UNLINK: "LINK_OR_UNLINK";
900
+ }>>;
901
+ isDestructive: z.ZodOptional<z.ZodBoolean>;
902
+ targetEntityType: z.ZodOptional<z.ZodString>;
903
+ targetOrdinalId: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
904
+ summary: z.ZodOptional<z.ZodString>;
905
+ agentPrompt: z.ZodOptional<z.ZodString>;
906
+ replacements: z.ZodOptional<z.ZodArray<z.ZodObject<{
907
+ originalExcerpt: z.ZodOptional<z.ZodString>;
908
+ suggestedText: z.ZodOptional<z.ZodString>;
909
+ contextBefore: z.ZodOptional<z.ZodString>;
910
+ contextAfter: z.ZodOptional<z.ZodString>;
911
+ }, z.core.$strip>>>;
912
+ rationale: z.ZodOptional<z.ZodString>;
913
+ }, z.core.$strip>>;
914
+ userState: z.ZodOptional<z.ZodEnum<{
915
+ ACTIVE: "ACTIVE";
916
+ IGNORED: "IGNORED";
917
+ APPLIED: "APPLIED";
918
+ }>>;
919
+ }, z.core.$strip>>>;
920
+ createdAtMillis: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
921
+ jobId: z.ZodOptional<z.ZodString>;
922
+ contentFingerprint: z.ZodOptional<z.ZodString>;
923
+ scoresUpdatedAtMillis: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
924
+ }, z.core.$strip>;
925
+ export declare const getRequirementQualityReportInput: z.ZodObject<{
926
+ subjectType: z.ZodEnum<{
927
+ STORY: "STORY";
928
+ SCENARIO: "SCENARIO";
929
+ }>;
930
+ subjectEntityId: z.ZodOptional<z.ZodString>;
931
+ ordinalId: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
932
+ }, z.core.$strip>;
933
+ export declare const reportRequirementQualityFindingsInput: z.ZodObject<{
934
+ report: z.ZodOptional<z.ZodObject<{
935
+ id: z.ZodOptional<z.ZodString>;
936
+ projectId: z.ZodOptional<z.ZodString>;
937
+ subject: z.ZodOptional<z.ZodObject<{
938
+ subjectType: z.ZodOptional<z.ZodEnum<{
939
+ STORY: "STORY";
940
+ SCENARIO: "SCENARIO";
941
+ }>>;
942
+ subjectEntityId: z.ZodOptional<z.ZodString>;
943
+ ordinalId: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
944
+ title: z.ZodOptional<z.ZodString>;
945
+ }, z.core.$strip>>;
946
+ source: z.ZodOptional<z.ZodEnum<{
947
+ CLOUD: "CLOUD";
948
+ LOCAL_AGENT: "LOCAL_AGENT";
949
+ }>>;
950
+ metrics: z.ZodOptional<z.ZodObject<{
951
+ overall: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
952
+ clarity: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
953
+ completeness: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
954
+ testability: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
955
+ consistency: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
956
+ ambiguityRisk: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
957
+ scenarioCoverage: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
958
+ criticalCount: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
959
+ majorCount: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
960
+ minorCount: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
961
+ }, z.core.$strip>>;
962
+ findings: z.ZodOptional<z.ZodArray<z.ZodObject<{
963
+ id: z.ZodOptional<z.ZodString>;
964
+ fingerprint: z.ZodOptional<z.ZodString>;
965
+ analyst: z.ZodOptional<z.ZodString>;
966
+ severity: z.ZodOptional<z.ZodEnum<{
967
+ CRITICAL: "CRITICAL";
968
+ MAJOR: "MAJOR";
969
+ MINOR: "MINOR";
970
+ }>>;
971
+ confidence: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
972
+ title: z.ZodOptional<z.ZodString>;
973
+ detail: z.ZodOptional<z.ZodString>;
974
+ suggestedFix: z.ZodOptional<z.ZodObject<{
975
+ kind: z.ZodOptional<z.ZodEnum<{
976
+ OTHER: "OTHER";
977
+ REWORD_EXCERPT: "REWORD_EXCERPT";
978
+ REWRITE_SECTION: "REWRITE_SECTION";
979
+ ADD_CONTENT: "ADD_CONTENT";
980
+ CREATE_SCENARIO: "CREATE_SCENARIO";
981
+ CREATE_STORY: "CREATE_STORY";
982
+ DELETE_SCENARIO: "DELETE_SCENARIO";
983
+ DELETE_STORY: "DELETE_STORY";
984
+ LINK_OR_UNLINK: "LINK_OR_UNLINK";
985
+ }>>;
986
+ isDestructive: z.ZodOptional<z.ZodBoolean>;
987
+ targetEntityType: z.ZodOptional<z.ZodString>;
988
+ targetOrdinalId: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
989
+ summary: z.ZodOptional<z.ZodString>;
990
+ agentPrompt: z.ZodOptional<z.ZodString>;
991
+ replacements: z.ZodOptional<z.ZodArray<z.ZodObject<{
992
+ originalExcerpt: z.ZodOptional<z.ZodString>;
993
+ suggestedText: z.ZodOptional<z.ZodString>;
994
+ contextBefore: z.ZodOptional<z.ZodString>;
995
+ contextAfter: z.ZodOptional<z.ZodString>;
996
+ }, z.core.$strip>>>;
997
+ rationale: z.ZodOptional<z.ZodString>;
998
+ }, z.core.$strip>>;
999
+ userState: z.ZodOptional<z.ZodEnum<{
1000
+ ACTIVE: "ACTIVE";
1001
+ IGNORED: "IGNORED";
1002
+ APPLIED: "APPLIED";
1003
+ }>>;
1004
+ }, z.core.$strip>>>;
1005
+ createdAtMillis: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
1006
+ jobId: z.ZodOptional<z.ZodString>;
1007
+ contentFingerprint: z.ZodOptional<z.ZodString>;
1008
+ scoresUpdatedAtMillis: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
1009
+ }, z.core.$strip>>;
1010
+ reportFile: z.ZodOptional<z.ZodString>;
1011
+ subjectType: z.ZodOptional<z.ZodEnum<{
1012
+ STORY: "STORY";
1013
+ SCENARIO: "SCENARIO";
1014
+ }>>;
1015
+ subjectEntityId: z.ZodOptional<z.ZodString>;
1016
+ ordinalId: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
1017
+ }, z.core.$strip>;
1018
+ export declare const agentActorTypeSchema: z.ZodEnum<{
1019
+ LOCAL_AGENT: "LOCAL_AGENT";
1020
+ CLOUD_AGENT: "CLOUD_AGENT";
1021
+ "local-agent": "local-agent";
1022
+ "cloud-agent": "cloud-agent";
1023
+ }>;
1024
+ export declare const agentActionTypeSchema: z.ZodEnum<{
1025
+ failed: "failed";
1026
+ CREATED: "CREATED";
1027
+ UPDATED: "UPDATED";
1028
+ DELETED: "DELETED";
1029
+ ANALYZED: "ANALYZED";
1030
+ ACTION_COMPLETED: "ACTION_COMPLETED";
1031
+ ACTION_FAILED: "ACTION_FAILED";
1032
+ created: "created";
1033
+ updated: "updated";
1034
+ deleted: "deleted";
1035
+ analyzed: "analyzed";
1036
+ completed: "completed";
1037
+ action_completed: "action_completed";
1038
+ action_failed: "action_failed";
1039
+ }>;
1040
+ export declare const reportAgentActionInput: z.ZodObject<{
1041
+ workflowId: z.ZodString;
1042
+ workflowExecutionId: z.ZodString;
1043
+ policyFile: z.ZodOptional<z.ZodString>;
1044
+ policyVersion: z.ZodOptional<z.ZodString>;
1045
+ gitSha: z.ZodOptional<z.ZodString>;
1046
+ actorType: z.ZodOptional<z.ZodEnum<{
1047
+ LOCAL_AGENT: "LOCAL_AGENT";
1048
+ CLOUD_AGENT: "CLOUD_AGENT";
1049
+ "local-agent": "local-agent";
1050
+ "cloud-agent": "cloud-agent";
1051
+ }>>;
1052
+ userId: z.ZodOptional<z.ZodString>;
1053
+ branchName: z.ZodOptional<z.ZodString>;
1054
+ entityType: z.ZodOptional<z.ZodString>;
1055
+ entityIdentity: z.ZodOptional<z.ZodString>;
1056
+ test: z.ZodOptional<z.ZodObject<{
1057
+ folderPath: z.ZodOptional<z.ZodArray<z.ZodString>>;
1058
+ fileName: z.ZodString;
1059
+ testSuite: z.ZodOptional<z.ZodArray<z.ZodString>>;
1060
+ testName: z.ZodString;
1061
+ }, z.core.$strip>>;
1062
+ actionType: z.ZodEnum<{
1063
+ failed: "failed";
1064
+ CREATED: "CREATED";
1065
+ UPDATED: "UPDATED";
1066
+ DELETED: "DELETED";
1067
+ ANALYZED: "ANALYZED";
1068
+ ACTION_COMPLETED: "ACTION_COMPLETED";
1069
+ ACTION_FAILED: "ACTION_FAILED";
1070
+ created: "created";
1071
+ updated: "updated";
1072
+ deleted: "deleted";
1073
+ analyzed: "analyzed";
1074
+ completed: "completed";
1075
+ action_completed: "action_completed";
1076
+ action_failed: "action_failed";
1077
+ }>;
1078
+ detailJson: z.ZodOptional<z.ZodString>;
1079
+ }, z.core.$strip>;
1080
+ export declare const getLastRunWorkflowDetailInput: z.ZodObject<{
1081
+ workflowId: z.ZodString;
1082
+ branchName: z.ZodOptional<z.ZodString>;
1083
+ userId: z.ZodOptional<z.ZodString>;
1084
+ }, z.core.$strip>;
1085
+ export declare const listWorkflowExecutionsInput: z.ZodObject<{
1086
+ workflowId: z.ZodOptional<z.ZodString>;
1087
+ limit: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
1088
+ offset: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
1089
+ }, z.core.$strip>;
1090
+ export declare const getWorkflowExecutionInput: z.ZodObject<{
1091
+ workflowExecutionId: z.ZodString;
1092
+ includeActions: z.ZodOptional<z.ZodBoolean>;
1093
+ }, z.core.$strip>;
1094
+ export declare const getPolicyInput: z.ZodObject<{
1095
+ policyFileName: z.ZodString;
1096
+ }, z.core.$strip>;
1097
+ export declare const listPoliciesInput: z.ZodObject<{
1098
+ workflowId: z.ZodOptional<z.ZodString>;
1099
+ }, z.core.$strip>;
1100
+ export declare const listWorkflowCatalogInput: z.ZodObject<{}, z.core.$strip>;
@@ -377,3 +377,191 @@ export const markSemanticTestsDistinctInput = z.object({
377
377
  focusTest: testLocatorSchema,
378
378
  distinctTest: testLocatorSchema,
379
379
  });
380
+ /** RequirementSubjectType — proto enum names (JsonFormat camelCase on wire). */
381
+ export const requirementSubjectTypeSchema = z.enum(["STORY", "SCENARIO"]);
382
+ /** RequirementFindingSeverity — proto enum names. */
383
+ export const requirementFindingSeveritySchema = z.enum(["CRITICAL", "MAJOR", "MINOR"]);
384
+ /** RequirementFindingUserState — proto enum names. */
385
+ export const requirementFindingUserStateSchema = z.enum(["ACTIVE", "IGNORED", "APPLIED"]);
386
+ /** RequirementQualityReportSource — proto enum names. */
387
+ export const requirementQualityReportSourceSchema = z.enum(["CLOUD", "LOCAL_AGENT"]);
388
+ /** SuggestedFixKind — proto enum names. */
389
+ export const suggestedFixKindSchema = z.enum([
390
+ "REWORD_EXCERPT",
391
+ "REWRITE_SECTION",
392
+ "ADD_CONTENT",
393
+ "CREATE_SCENARIO",
394
+ "CREATE_STORY",
395
+ "DELETE_SCENARIO",
396
+ "DELETE_STORY",
397
+ "LINK_OR_UNLINK",
398
+ "OTHER",
399
+ ]);
400
+ /** TextReplacement (requirement_quality.proto) — camelCase wire shape. */
401
+ export const textReplacementSchema = z.object({
402
+ originalExcerpt: z.string().optional(),
403
+ suggestedText: z.string().optional(),
404
+ contextBefore: z.string().optional(),
405
+ contextAfter: z.string().optional(),
406
+ });
407
+ /** SuggestedFix (requirement_quality.proto). isDestructive is derived server-side from kind. */
408
+ export const suggestedFixSchema = z.object({
409
+ kind: suggestedFixKindSchema.optional(),
410
+ isDestructive: z.boolean().optional(),
411
+ /** "STORY" | "SCENARIO" — target of the fix (may differ from the finding's own subject). */
412
+ targetEntityType: z.string().optional(),
413
+ targetOrdinalId: z.coerce.number().int().optional(),
414
+ summary: z.string().optional(),
415
+ agentPrompt: z.string().optional(),
416
+ replacements: z.array(textReplacementSchema).optional(),
417
+ rationale: z.string().optional(),
418
+ });
419
+ /** RequirementQualityFinding (requirement_quality.proto). */
420
+ export const requirementQualityFindingSchema = z.object({
421
+ id: z.string().optional(),
422
+ fingerprint: z.string().optional(),
423
+ analyst: z.string().optional(),
424
+ severity: requirementFindingSeveritySchema.optional(),
425
+ confidence: z.coerce.number().int().optional(),
426
+ title: z.string().optional(),
427
+ detail: z.string().optional(),
428
+ suggestedFix: suggestedFixSchema.optional(),
429
+ /** Omit (defaults ACTIVE server-side) for new findings; set explicitly to carry forward IGNORED/APPLIED. */
430
+ userState: requirementFindingUserStateSchema.optional(),
431
+ });
432
+ /** RequirementQualityMetrics (requirement_quality.proto) — scores 0-100, counts among ACTIVE findings. */
433
+ export const requirementQualityMetricsSchema = z.object({
434
+ overall: z.coerce.number().int().optional(),
435
+ clarity: z.coerce.number().int().optional(),
436
+ completeness: z.coerce.number().int().optional(),
437
+ testability: z.coerce.number().int().optional(),
438
+ consistency: z.coerce.number().int().optional(),
439
+ ambiguityRisk: z.coerce.number().int().optional(),
440
+ scenarioCoverage: z.coerce.number().int().optional(),
441
+ criticalCount: z.coerce.number().int().optional(),
442
+ majorCount: z.coerce.number().int().optional(),
443
+ minorCount: z.coerce.number().int().optional(),
444
+ });
445
+ /** RequirementQualitySubject (requirement_quality.proto). subjectEntityId is the platform-internal id. */
446
+ export const requirementQualitySubjectSchema = z.object({
447
+ subjectType: requirementSubjectTypeSchema.optional(),
448
+ subjectEntityId: z.string().optional(),
449
+ ordinalId: z.coerce.number().int().optional(),
450
+ title: z.string().optional(),
451
+ });
452
+ /** RequirementQualityReport (requirement_quality.proto) — full upload body shape. */
453
+ export const requirementQualityReportSchema = z.object({
454
+ id: z.string().optional(),
455
+ projectId: z.string().optional(),
456
+ subject: requirementQualitySubjectSchema.optional(),
457
+ source: requirementQualityReportSourceSchema.optional(),
458
+ metrics: requirementQualityMetricsSchema.optional(),
459
+ findings: z.array(requirementQualityFindingSchema).optional(),
460
+ createdAtMillis: z.coerce.number().optional(),
461
+ jobId: z.string().optional(),
462
+ contentFingerprint: z.string().optional(),
463
+ scoresUpdatedAtMillis: z.coerce.number().optional(),
464
+ });
465
+ const requirementSubjectRefinement = (v, ctx) => {
466
+ const entityId = (v.subjectEntityId ?? "").trim();
467
+ const ordinal = v.ordinalId;
468
+ if (entityId === "" && (ordinal == null || ordinal <= 0)) {
469
+ ctx.addIssue({
470
+ code: z.ZodIssueCode.custom,
471
+ message: "Provide subjectEntityId or ordinalId",
472
+ });
473
+ }
474
+ };
475
+ export const getRequirementQualityReportInput = z
476
+ .object({
477
+ subjectType: requirementSubjectTypeSchema,
478
+ subjectEntityId: z.string().optional(),
479
+ ordinalId: z.coerce.number().int().positive().optional(),
480
+ })
481
+ .superRefine(requirementSubjectRefinement);
482
+ export const reportRequirementQualityFindingsInput = z
483
+ .object({
484
+ /** Full RequirementQualityReport JSON object (camelCase, requirement_quality.proto). */
485
+ report: requirementQualityReportSchema.optional(),
486
+ /** Path to RequirementQualityReport JSON file. */
487
+ reportFile: z.string().optional(),
488
+ /** Convenience: merged into report.subject when report lacks subjectEntityId. */
489
+ subjectType: requirementSubjectTypeSchema.optional(),
490
+ subjectEntityId: z.string().optional(),
491
+ ordinalId: z.coerce.number().int().positive().optional(),
492
+ })
493
+ .superRefine((v, ctx) => {
494
+ const hasReport = v.report != null && Object.keys(v.report).length > 0;
495
+ const hasFile = (v.reportFile ?? "").trim() !== "";
496
+ if (!hasReport && !hasFile) {
497
+ ctx.addIssue({
498
+ code: z.ZodIssueCode.custom,
499
+ message: "Provide report object, reportFile path, or full body via --json-input",
500
+ });
501
+ }
502
+ });
503
+ export const agentActorTypeSchema = z.enum(["LOCAL_AGENT", "CLOUD_AGENT", "local-agent", "cloud-agent"]);
504
+ export const agentActionTypeSchema = z.enum([
505
+ "CREATED",
506
+ "UPDATED",
507
+ "DELETED",
508
+ "ANALYZED",
509
+ "ACTION_COMPLETED",
510
+ "ACTION_FAILED",
511
+ "created",
512
+ "updated",
513
+ "deleted",
514
+ "analyzed",
515
+ "completed",
516
+ "failed",
517
+ "action_completed",
518
+ "action_failed",
519
+ ]);
520
+ export const reportAgentActionInput = z
521
+ .object({
522
+ workflowId: z.string().min(1),
523
+ workflowExecutionId: z.string().min(1),
524
+ policyFile: z.string().optional(),
525
+ policyVersion: z.string().optional(),
526
+ gitSha: z.string().optional(),
527
+ actorType: agentActorTypeSchema.optional(),
528
+ userId: z.string().optional(),
529
+ branchName: z.string().optional(),
530
+ entityType: z.string().optional(),
531
+ /** Project-scoped ordinal id (or explicitly provided execution/batch id). Mutually exclusive with `test`. */
532
+ entityIdentity: z.string().optional(),
533
+ /** SmartTest TestLocator. Mutually exclusive with `entityIdentity`. */
534
+ test: testLocatorSchema.optional(),
535
+ actionType: agentActionTypeSchema,
536
+ detailJson: z.string().optional(),
537
+ })
538
+ .superRefine((val, ctx) => {
539
+ if (val.test && val.entityIdentity) {
540
+ ctx.addIssue({
541
+ code: z.ZodIssueCode.custom,
542
+ message: "Provide either test (TestLocator) or entityIdentity (ordinal), not both",
543
+ path: ["test"],
544
+ });
545
+ }
546
+ });
547
+ export const getLastRunWorkflowDetailInput = z.object({
548
+ workflowId: z.string().min(1),
549
+ branchName: z.string().optional(),
550
+ userId: z.string().optional(),
551
+ });
552
+ export const listWorkflowExecutionsInput = z.object({
553
+ workflowId: z.string().optional(),
554
+ limit: z.coerce.number().int().positive().max(200).optional(),
555
+ offset: z.coerce.number().int().nonnegative().optional(),
556
+ });
557
+ export const getWorkflowExecutionInput = z.object({
558
+ workflowExecutionId: z.string().min(1),
559
+ includeActions: z.boolean().optional(),
560
+ });
561
+ export const getPolicyInput = z.object({
562
+ policyFileName: z.string().min(1),
563
+ });
564
+ export const listPoliciesInput = z.object({
565
+ workflowId: z.string().optional(),
566
+ });
567
+ export const listWorkflowCatalogInput = z.object({});
@@ -85,6 +85,43 @@ function listExecutionBody(args) {
85
85
  body.offset = args.offset;
86
86
  return body;
87
87
  }
88
+ function requirementQualitySubjectBody(subjectType, opts) {
89
+ const body = { subjectType };
90
+ const entityId = (opts.subjectEntityId ?? "").trim();
91
+ if (entityId !== "")
92
+ body.subjectEntityId = entityId;
93
+ if (opts.ordinalId != null && opts.ordinalId > 0)
94
+ body.ordinalId = opts.ordinalId;
95
+ return body;
96
+ }
97
+ /** Resolve platform subjectEntityId from explicit id or get-requirement-quality-report via ordinal. */
98
+ async function resolveRequirementSubjectEntityId(postMcp, subjectType, opts) {
99
+ const explicit = (opts.subjectEntityId ?? "").trim();
100
+ if (explicit !== "")
101
+ return explicit;
102
+ if (opts.ordinalId == null || opts.ordinalId <= 0) {
103
+ throw new Error("Provide subjectEntityId or ordinalId");
104
+ }
105
+ const json = await postMcp("/api/mcp/get_requirement_quality_report", requirementQualitySubjectBody(subjectType, { ordinalId: opts.ordinalId }));
106
+ const parsed = JSON.parse(json);
107
+ const resolved = (parsed.report?.subject?.subjectEntityId ?? "").trim();
108
+ if (resolved !== "")
109
+ return resolved;
110
+ throw new Error(`Cannot resolve subjectEntityId for ${subjectType} ordinal ${opts.ordinalId}. ` +
111
+ "Provide --subject-entity-id, or confirm the story/scenario ordinal exists in this project " +
112
+ "(get-requirement-quality-report resolves entity id by ordinal even when no prior report exists).");
113
+ }
114
+ async function loadRequirementQualityReportJson(args) {
115
+ if (args.report != null && Object.keys(args.report).length > 0) {
116
+ return { ...args.report };
117
+ }
118
+ if (args.reportFile != null && args.reportFile.trim() !== "") {
119
+ const { readFile } = await import("node:fs/promises");
120
+ const raw = await readFile(args.reportFile.trim(), "utf8");
121
+ return JSON.parse(raw);
122
+ }
123
+ return {};
124
+ }
88
125
  export const TOOL_DEFINITIONS = [
89
126
  {
90
127
  kebab: "get-requirement-coverage",
@@ -691,6 +728,176 @@ export const TOOL_DEFINITIONS = [
691
728
  });
692
729
  },
693
730
  },
731
+ {
732
+ kebab: "get-requirement-quality-report",
733
+ description: "Fetch the stored requirement quality report (metrics + findings with user states) for a user story or test scenario. " +
734
+ "Use before local DeFOSPAM to dedupe: do not re-report findings already IGNORED or APPLIED (match by fingerprint). " +
735
+ "Pass subjectType STORY|SCENARIO plus subjectEntityId or ordinalId (numeric part of US-<n> / TS-<n>). " +
736
+ "When no prior report exists, response still includes report.subject with resolved subjectEntityId.",
737
+ inputSchema: S.getRequirementQualityReportInput,
738
+ execute: async (args, { postMcp }) => {
739
+ const a = args;
740
+ return postMcp("/api/mcp/get_requirement_quality_report", requirementQualitySubjectBody(a.subjectType, {
741
+ subjectEntityId: a.subjectEntityId,
742
+ ordinalId: a.ordinalId,
743
+ }));
744
+ },
745
+ },
746
+ {
747
+ kebab: "report-requirement-quality-findings",
748
+ description: "Upload a DeFOSPAM / requirement quality analysis report for a user story or test scenario (local-agent path). " +
749
+ "Pass full RequirementQualityReport JSON via --report-file or --json-input {\"report\":{...}}. " +
750
+ "report.subject.subjectEntityId is required; use --subject-type + --ordinal-id to resolve via get-requirement-quality-report, " +
751
+ "or set subjectEntityId explicitly. Backend merges IGNORED/APPLIED findings carry-forward on re-report.",
752
+ inputSchema: S.reportRequirementQualityFindingsInput,
753
+ execute: async (args, { postMcp }) => {
754
+ const a = args;
755
+ const report = await loadRequirementQualityReportJson(a);
756
+ const subjectRaw = (report.subject ?? {});
757
+ const subjectType = (a.subjectType ?? subjectRaw.subjectType);
758
+ const ordinalId = a.ordinalId ??
759
+ (typeof subjectRaw.ordinalId === "number" ? subjectRaw.ordinalId : undefined);
760
+ let subjectEntityId = (a.subjectEntityId ?? (typeof subjectRaw.subjectEntityId === "string" ? subjectRaw.subjectEntityId : "")).trim();
761
+ if (subjectEntityId === "" && subjectType != null) {
762
+ subjectEntityId = await resolveRequirementSubjectEntityId(postMcp, subjectType, {
763
+ ordinalId,
764
+ });
765
+ }
766
+ if (subjectEntityId === "") {
767
+ throw new Error("report.subject.subjectEntityId is required (set in report JSON, --subject-entity-id, or resolvable via --ordinal-id)");
768
+ }
769
+ const mergedSubject = {
770
+ ...subjectRaw,
771
+ ...(subjectType != null ? { subjectType } : {}),
772
+ subjectEntityId,
773
+ ...(ordinalId != null ? { ordinalId } : {}),
774
+ };
775
+ report.subject = mergedSubject;
776
+ return postMcp("/api/mcp/report_requirement_quality_findings", { report });
777
+ },
778
+ },
779
+ {
780
+ kebab: "report-agent-action",
781
+ description: "Report a mutating agent action under a stable workflow-execution-id (ULID). " +
782
+ "First call for an id creates the workflow_executions row; later calls append agent_actions. " +
783
+ "Identity: pass `test` (TestLocator: folderPath/fileName/testSuite/testName) for SmartTests, " +
784
+ "or `entityIdentity` as a project-scoped ordinal id for stories/scenarios/issues " +
785
+ "(or an execution/batch id only when the prompt explicitly provided it). Do not use platform UUIDs.",
786
+ inputSchema: S.reportAgentActionInput,
787
+ execute: async (args, { postMcp }) => {
788
+ const a = args;
789
+ const actorRaw = (a.actorType ?? "local-agent").toString();
790
+ const actorType = actorRaw.toUpperCase().replace(/-/g, "_") === "CLOUD_AGENT" ? "CLOUD_AGENT" : "LOCAL_AGENT";
791
+ const actionNorm = a.actionType.toString().toUpperCase().replace(/-/g, "_");
792
+ let actionType = actionNorm;
793
+ if (actionNorm === "COMPLETED" || actionNorm === "ACTION_COMPLETED") {
794
+ actionType = "ACTION_COMPLETED";
795
+ }
796
+ else if (actionNorm === "FAILED" || actionNorm === "ACTION_FAILED") {
797
+ actionType = "ACTION_FAILED";
798
+ }
799
+ const body = {
800
+ workflowId: a.workflowId,
801
+ workflowExecutionId: a.workflowExecutionId,
802
+ actionType,
803
+ actorType,
804
+ };
805
+ if (a.policyFile)
806
+ body.policyFile = a.policyFile;
807
+ if (a.policyVersion)
808
+ body.policyVersion = a.policyVersion;
809
+ if (a.gitSha)
810
+ body.gitSha = a.gitSha;
811
+ if (a.userId)
812
+ body.userId = a.userId;
813
+ else if (process.env.TESTCHIMP_USER_ID)
814
+ body.userId = process.env.TESTCHIMP_USER_ID;
815
+ if (a.branchName)
816
+ body.branchName = a.branchName;
817
+ if (a.entityType)
818
+ body.entityType = a.entityType;
819
+ if (a.test) {
820
+ body.test = a.test;
821
+ }
822
+ else if (a.entityIdentity) {
823
+ body.entityIdentity = a.entityIdentity;
824
+ }
825
+ if (a.detailJson)
826
+ body.detailJson = a.detailJson;
827
+ return postMcp("/api/mcp/report_agent_action", body);
828
+ },
829
+ },
830
+ {
831
+ kebab: "get-last-run-workflow-detail",
832
+ description: "Fetch the last workflow execution for a workflow-id on a branch (optional userId for per-user last run). " +
833
+ "Used for since-last-run scoping.",
834
+ inputSchema: S.getLastRunWorkflowDetailInput,
835
+ execute: async (args, { postMcp }) => {
836
+ const a = args;
837
+ const body = {
838
+ workflowId: a.workflowId,
839
+ branchName: a.branchName,
840
+ };
841
+ if (a.userId)
842
+ body.userId = a.userId;
843
+ return postMcp("/api/mcp/get_last_run_workflow_detail", body);
844
+ },
845
+ },
846
+ {
847
+ kebab: "list-workflow-executions",
848
+ description: "List recent workflow executions for the project, optionally filtered by workflowId.",
849
+ inputSchema: S.listWorkflowExecutionsInput,
850
+ execute: async (args, { postMcp }) => {
851
+ const a = args;
852
+ const body = {};
853
+ if (a.workflowId)
854
+ body.workflowId = a.workflowId;
855
+ if (a.limit != null)
856
+ body.limit = a.limit;
857
+ if (a.offset != null)
858
+ body.offset = a.offset;
859
+ return postMcp("/api/mcp/list_workflow_executions", body);
860
+ },
861
+ },
862
+ {
863
+ kebab: "get-workflow-execution",
864
+ description: "Get a workflow execution by id; pass includeActions=true for the action timeline.",
865
+ inputSchema: S.getWorkflowExecutionInput,
866
+ execute: async (args, { postMcp }) => {
867
+ const a = args;
868
+ return postMcp("/api/mcp/get_workflow_execution", {
869
+ workflowExecutionId: a.workflowExecutionId,
870
+ includeActions: a.includeActions ?? true,
871
+ });
872
+ },
873
+ },
874
+ {
875
+ kebab: "get-policy",
876
+ description: "Fetch a workflow policy file by name (e.g. run-qa.policy.md) from the platform POLICY_FILE store.",
877
+ inputSchema: S.getPolicyInput,
878
+ execute: async (args, { postMcp }) => {
879
+ const a = args;
880
+ return postMcp("/api/mcp/get_policy", { policyFileName: a.policyFileName });
881
+ },
882
+ },
883
+ {
884
+ kebab: "list-policies",
885
+ description: "List policy files for an optional workflow-id. Marks isDefault when filename is <workflow-id>.policy.md.",
886
+ inputSchema: S.listPoliciesInput,
887
+ execute: async (args, { postMcp }) => {
888
+ const a = args;
889
+ const body = {};
890
+ if (a.workflowId)
891
+ body.workflowId = a.workflowId;
892
+ return postMcp("/api/mcp/list_policies", body);
893
+ },
894
+ },
895
+ {
896
+ kebab: "list-workflow-catalog",
897
+ description: "List supported TestChimp workflows with Active / Disabled / Missing Config status for the project.",
898
+ inputSchema: S.listWorkflowCatalogInput,
899
+ execute: async (_args, { postMcp }) => postMcp("/api/mcp/list_workflow_catalog", {}),
900
+ },
694
901
  ];
695
902
  const TOOL_BY_KEBAB = new Map(TOOL_DEFINITIONS.map((t) => [t.kebab, t]));
696
903
  export function getToolDefinition(kebab) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@testchimp/cli",
3
- "version": "0.1.18",
3
+ "version": "0.1.20",
4
4
  "description": "TestChimp CLI and MCP server — coverage, plans, EaaS, TrueCoverage (calls /api/mcp/*)",
5
5
  "type": "module",
6
6
  "main": "dist/bin/testchimp.js",