@testchimp/cli 0.1.83 → 0.1.85

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.
@@ -1,6 +1,6 @@
1
1
  import assert from "node:assert/strict";
2
- import { afterEach, describe, it } from "node:test";
3
- import { getBackendUrl, postMcp } from "./client.js";
2
+ import { afterEach, beforeEach, describe, it } from "node:test";
3
+ import { getBackendUrl, isValidBotId, postIngress, postMcp, resetClientWarningsForTests, runWithRequestAuth, } from "./client.js";
4
4
  const originalBackendUrl = process.env.TESTCHIMP_BACKEND_URL;
5
5
  const originalApiKey = process.env.TESTCHIMP_API_KEY;
6
6
  const originalFetch = globalThis.fetch;
@@ -52,3 +52,131 @@ describe("postMcp", () => {
52
52
  assert.equal(requestInit?.redirect, "manual");
53
53
  });
54
54
  });
55
+ describe("request headers", () => {
56
+ const originalBotId = process.env.TESTCHIMP_BOT_ID;
57
+ const originalOauthToken = process.env.TESTCHIMP_OAUTH_TOKEN;
58
+ const originalIngressUrl = process.env.TESTCHIMP_INGRESS_URL;
59
+ const originalConsoleError = console.error;
60
+ beforeEach(() => {
61
+ process.env.TESTCHIMP_BACKEND_URL = "https://featureservice.example.com";
62
+ delete process.env.TESTCHIMP_API_KEY;
63
+ delete process.env.TESTCHIMP_BOT_ID;
64
+ delete process.env.TESTCHIMP_OAUTH_TOKEN;
65
+ delete process.env.TESTCHIMP_INGRESS_URL;
66
+ resetClientWarningsForTests();
67
+ });
68
+ afterEach(() => {
69
+ for (const [key, value] of [
70
+ ["TESTCHIMP_BOT_ID", originalBotId],
71
+ ["TESTCHIMP_OAUTH_TOKEN", originalOauthToken],
72
+ ["TESTCHIMP_INGRESS_URL", originalIngressUrl],
73
+ ]) {
74
+ if (value == null)
75
+ delete process.env[key];
76
+ else
77
+ process.env[key] = value;
78
+ }
79
+ console.error = originalConsoleError;
80
+ });
81
+ function captureFetch() {
82
+ const capture = { calls: [] };
83
+ globalThis.fetch = (async (input, init) => {
84
+ capture.calls.push({ url: String(input), init });
85
+ return new Response("{}", { status: 200 });
86
+ });
87
+ return capture;
88
+ }
89
+ it("sends exactly the legacy header set with an API key and no bot env", async () => {
90
+ process.env.TESTCHIMP_API_KEY = "test-key";
91
+ const capture = captureFetch();
92
+ await postMcp("/api/mcp/example", { a: 1 });
93
+ assert.equal(capture.calls[0].url, "https://featureservice.example.com/api/mcp/example");
94
+ assert.deepEqual(capture.calls[0].init?.headers, {
95
+ "Content-Type": "application/json",
96
+ "TestChimp-Api-Key": "test-key",
97
+ });
98
+ assert.equal(capture.calls[0].init?.body, JSON.stringify({ a: 1 }));
99
+ });
100
+ it("keeps the missing API key error when no credentials are set", async () => {
101
+ captureFetch();
102
+ await assert.rejects(postMcp("/api/mcp/example", {}), /TESTCHIMP_API_KEY is required/);
103
+ });
104
+ it("adds a valid bot-id header", async () => {
105
+ process.env.TESTCHIMP_API_KEY = "test-key";
106
+ process.env.TESTCHIMP_BOT_ID = "grok-bot_01";
107
+ const capture = captureFetch();
108
+ await postMcp("/api/mcp/example", {});
109
+ assert.deepEqual(capture.calls[0].init?.headers, {
110
+ "Content-Type": "application/json",
111
+ "TestChimp-Api-Key": "test-key",
112
+ "bot-id": "grok-bot_01",
113
+ });
114
+ });
115
+ it("drops an invalid bot id and warns once", async () => {
116
+ process.env.TESTCHIMP_API_KEY = "test-key";
117
+ process.env.TESTCHIMP_BOT_ID = "bad bot id";
118
+ const warnings = [];
119
+ console.error = (msg) => warnings.push(String(msg));
120
+ const capture = captureFetch();
121
+ await postMcp("/api/mcp/example", {});
122
+ await postMcp("/api/mcp/example", {});
123
+ assert.deepEqual(capture.calls[0].init?.headers, {
124
+ "Content-Type": "application/json",
125
+ "TestChimp-Api-Key": "test-key",
126
+ });
127
+ assert.equal(warnings.length, 1);
128
+ assert.match(warnings[0], /TESTCHIMP_BOT_ID/);
129
+ assert.equal(isValidBotId("x".repeat(64)), true);
130
+ assert.equal(isValidBotId("x".repeat(65)), false);
131
+ assert.equal(isValidBotId("bot\u0007"), false);
132
+ });
133
+ it("uses the OAuth token without requiring an API key", async () => {
134
+ process.env.TESTCHIMP_OAUTH_TOKEN = "jwt-token";
135
+ const capture = captureFetch();
136
+ await postMcp("/api/mcp/example", {});
137
+ assert.deepEqual(capture.calls[0].init?.headers, {
138
+ "Content-Type": "application/json",
139
+ Authorization: "Bearer jwt-token",
140
+ });
141
+ });
142
+ it("sends both the API key and the bearer when both are set", async () => {
143
+ process.env.TESTCHIMP_API_KEY = "test-key";
144
+ process.env.TESTCHIMP_OAUTH_TOKEN = "jwt-token";
145
+ process.env.TESTCHIMP_BOT_ID = "bot-1";
146
+ const capture = captureFetch();
147
+ await postMcp("/api/mcp/example", {});
148
+ assert.deepEqual(capture.calls[0].init?.headers, {
149
+ "Content-Type": "application/json",
150
+ "TestChimp-Api-Key": "test-key",
151
+ Authorization: "Bearer jwt-token",
152
+ "bot-id": "bot-1",
153
+ });
154
+ });
155
+ it("isolated request auth ignores env credentials", async () => {
156
+ process.env.TESTCHIMP_API_KEY = "server-key";
157
+ process.env.TESTCHIMP_BOT_ID = "server-bot";
158
+ const capture = captureFetch();
159
+ await runWithRequestAuth({ bearerToken: "caller-token", isolated: true }, () => postMcp("/api/mcp/example", {}));
160
+ assert.deepEqual(capture.calls[0].init?.headers, {
161
+ "Content-Type": "application/json",
162
+ Authorization: "Bearer caller-token",
163
+ });
164
+ });
165
+ it("posts to the ingress base or a trusted absolute URL", async () => {
166
+ process.env.TESTCHIMP_API_KEY = "test-key";
167
+ const capture = captureFetch();
168
+ await postIngress("/bot/events/ack", { eventIds: ["e1"] });
169
+ assert.equal(capture.calls[0].url, "https://ingress.testchimp.io/bot/events/ack");
170
+ assert.equal(capture.calls[0].init?.redirect, "manual");
171
+ await postIngress("https://ingress-staging.testchimp.io/bot/events/ack", {});
172
+ assert.equal(capture.calls[1].url, "https://ingress-staging.testchimp.io/bot/events/ack");
173
+ await postIngress("http://localhost:4302/bot/events/ack", {});
174
+ assert.equal(capture.calls[2].url, "http://localhost:4302/bot/events/ack");
175
+ await assert.rejects(postIngress("http://ingress.testchimp.io/bot/events/ack", {}), /must use https/);
176
+ await assert.rejects(postIngress("https://evil.example.com/bot/events/ack", {}), /untrusted ingress host/);
177
+ assert.equal(capture.calls.length, 3);
178
+ process.env.TESTCHIMP_INGRESS_URL = "https://ingress.customer.example/";
179
+ await postIngress("https://ingress.customer.example/bot/events/ack", {});
180
+ assert.equal(capture.calls[3].url, "https://ingress.customer.example/bot/events/ack");
181
+ });
182
+ });
@@ -18,9 +18,9 @@ export declare const listCoverageInput: z.ZodObject<{
18
18
  includeNonCoveredTestScenarios: z.ZodOptional<z.ZodBoolean>;
19
19
  branchName: z.ZodOptional<z.ZodString>;
20
20
  platform: z.ZodOptional<z.ZodEnum<{
21
+ android: "android";
21
22
  web: "web";
22
23
  ios: "ios";
23
- android: "android";
24
24
  }>>;
25
25
  recordTypes: z.ZodOptional<z.ZodArray<z.ZodEnum<{
26
26
  manual: "manual";
@@ -47,9 +47,9 @@ export declare const listExecutionInput: z.ZodObject<{
47
47
  scenarioId: z.ZodOptional<z.ZodString>;
48
48
  testId: z.ZodOptional<z.ZodString>;
49
49
  platform: z.ZodOptional<z.ZodEnum<{
50
+ android: "android";
50
51
  web: "web";
51
52
  ios: "ios";
52
- android: "android";
53
53
  }>>;
54
54
  dimensionFilters: z.ZodOptional<z.ZodArray<z.ZodObject<{
55
55
  dimension: z.ZodString;
@@ -70,9 +70,9 @@ export declare const suiteExecutionStatsInput: z.ZodObject<{
70
70
  scenarioId: z.ZodOptional<z.ZodString>;
71
71
  testId: z.ZodOptional<z.ZodString>;
72
72
  platform: z.ZodOptional<z.ZodEnum<{
73
+ android: "android";
73
74
  web: "web";
74
75
  ios: "ios";
75
- android: "android";
76
76
  }>>;
77
77
  dimensionFilters: z.ZodOptional<z.ZodArray<z.ZodObject<{
78
78
  dimension: z.ZodString;
@@ -794,6 +794,7 @@ export declare const updateGitFolderMappingInput: z.ZodObject<{
794
794
  testsFolderPath: z.ZodOptional<z.ZodString>;
795
795
  plansFolderPath: z.ZodOptional<z.ZodString>;
796
796
  repositoryFullName: z.ZodOptional<z.ZodString>;
797
+ plansBranch: z.ZodOptional<z.ZodString>;
797
798
  tests_folder_path: z.ZodOptional<z.ZodString>;
798
799
  plans_folder_path: z.ZodOptional<z.ZodString>;
799
800
  repository_full_name: z.ZodOptional<z.ZodString>;
@@ -827,14 +828,14 @@ export declare const executionScopeSchema: z.ZodObject<{
827
828
  release: z.ZodOptional<z.ZodString>;
828
829
  branchName: z.ZodOptional<z.ZodString>;
829
830
  platform: z.ZodOptional<z.ZodPipe<z.ZodEnum<{
831
+ android: "android";
830
832
  web: "web";
831
833
  ios: "ios";
832
- android: "android";
833
834
  UNKNOWN_EXECUTION_PLATFORM: "UNKNOWN_EXECUTION_PLATFORM";
834
835
  WEB_EXECUTION_PLATFORM: "WEB_EXECUTION_PLATFORM";
835
836
  IOS_EXECUTION_PLATFORM: "IOS_EXECUTION_PLATFORM";
836
837
  ANDROID_EXECUTION_PLATFORM: "ANDROID_EXECUTION_PLATFORM";
837
- }>, z.ZodTransform<"UNKNOWN_EXECUTION_PLATFORM" | "WEB_EXECUTION_PLATFORM" | "IOS_EXECUTION_PLATFORM" | "ANDROID_EXECUTION_PLATFORM", "web" | "ios" | "android" | "UNKNOWN_EXECUTION_PLATFORM" | "WEB_EXECUTION_PLATFORM" | "IOS_EXECUTION_PLATFORM" | "ANDROID_EXECUTION_PLATFORM">>>;
838
+ }>, z.ZodTransform<"UNKNOWN_EXECUTION_PLATFORM" | "WEB_EXECUTION_PLATFORM" | "IOS_EXECUTION_PLATFORM" | "ANDROID_EXECUTION_PLATFORM", "android" | "web" | "ios" | "UNKNOWN_EXECUTION_PLATFORM" | "WEB_EXECUTION_PLATFORM" | "IOS_EXECUTION_PLATFORM" | "ANDROID_EXECUTION_PLATFORM">>>;
838
839
  automationEmitsOnly: z.ZodOptional<z.ZodBoolean>;
839
840
  metadataFilters: z.ZodOptional<z.ZodArray<z.ZodObject<{
840
841
  key: z.ZodString;
@@ -867,14 +868,14 @@ export declare const listTruecoverageEventsInput: z.ZodObject<{
867
868
  release: z.ZodOptional<z.ZodString>;
868
869
  branchName: z.ZodOptional<z.ZodString>;
869
870
  platform: z.ZodOptional<z.ZodPipe<z.ZodEnum<{
871
+ android: "android";
870
872
  web: "web";
871
873
  ios: "ios";
872
- android: "android";
873
874
  UNKNOWN_EXECUTION_PLATFORM: "UNKNOWN_EXECUTION_PLATFORM";
874
875
  WEB_EXECUTION_PLATFORM: "WEB_EXECUTION_PLATFORM";
875
876
  IOS_EXECUTION_PLATFORM: "IOS_EXECUTION_PLATFORM";
876
877
  ANDROID_EXECUTION_PLATFORM: "ANDROID_EXECUTION_PLATFORM";
877
- }>, z.ZodTransform<"UNKNOWN_EXECUTION_PLATFORM" | "WEB_EXECUTION_PLATFORM" | "IOS_EXECUTION_PLATFORM" | "ANDROID_EXECUTION_PLATFORM", "web" | "ios" | "android" | "UNKNOWN_EXECUTION_PLATFORM" | "WEB_EXECUTION_PLATFORM" | "IOS_EXECUTION_PLATFORM" | "ANDROID_EXECUTION_PLATFORM">>>;
878
+ }>, z.ZodTransform<"UNKNOWN_EXECUTION_PLATFORM" | "WEB_EXECUTION_PLATFORM" | "IOS_EXECUTION_PLATFORM" | "ANDROID_EXECUTION_PLATFORM", "android" | "web" | "ios" | "UNKNOWN_EXECUTION_PLATFORM" | "WEB_EXECUTION_PLATFORM" | "IOS_EXECUTION_PLATFORM" | "ANDROID_EXECUTION_PLATFORM">>>;
878
879
  automationEmitsOnly: z.ZodOptional<z.ZodBoolean>;
879
880
  metadataFilters: z.ZodOptional<z.ZodArray<z.ZodObject<{
880
881
  key: z.ZodString;
@@ -906,14 +907,14 @@ export declare const listTruecoverageEventsInput: z.ZodObject<{
906
907
  release: z.ZodOptional<z.ZodString>;
907
908
  branchName: z.ZodOptional<z.ZodString>;
908
909
  platform: z.ZodOptional<z.ZodPipe<z.ZodEnum<{
910
+ android: "android";
909
911
  web: "web";
910
912
  ios: "ios";
911
- android: "android";
912
913
  UNKNOWN_EXECUTION_PLATFORM: "UNKNOWN_EXECUTION_PLATFORM";
913
914
  WEB_EXECUTION_PLATFORM: "WEB_EXECUTION_PLATFORM";
914
915
  IOS_EXECUTION_PLATFORM: "IOS_EXECUTION_PLATFORM";
915
916
  ANDROID_EXECUTION_PLATFORM: "ANDROID_EXECUTION_PLATFORM";
916
- }>, z.ZodTransform<"UNKNOWN_EXECUTION_PLATFORM" | "WEB_EXECUTION_PLATFORM" | "IOS_EXECUTION_PLATFORM" | "ANDROID_EXECUTION_PLATFORM", "web" | "ios" | "android" | "UNKNOWN_EXECUTION_PLATFORM" | "WEB_EXECUTION_PLATFORM" | "IOS_EXECUTION_PLATFORM" | "ANDROID_EXECUTION_PLATFORM">>>;
917
+ }>, z.ZodTransform<"UNKNOWN_EXECUTION_PLATFORM" | "WEB_EXECUTION_PLATFORM" | "IOS_EXECUTION_PLATFORM" | "ANDROID_EXECUTION_PLATFORM", "android" | "web" | "ios" | "UNKNOWN_EXECUTION_PLATFORM" | "WEB_EXECUTION_PLATFORM" | "IOS_EXECUTION_PLATFORM" | "ANDROID_EXECUTION_PLATFORM">>>;
917
918
  automationEmitsOnly: z.ZodOptional<z.ZodBoolean>;
918
919
  metadataFilters: z.ZodOptional<z.ZodArray<z.ZodObject<{
919
920
  key: z.ZodString;
@@ -948,14 +949,14 @@ export declare const getTruecoverageEventDetailsInput: z.ZodObject<{
948
949
  release: z.ZodOptional<z.ZodString>;
949
950
  branchName: z.ZodOptional<z.ZodString>;
950
951
  platform: z.ZodOptional<z.ZodPipe<z.ZodEnum<{
952
+ android: "android";
951
953
  web: "web";
952
954
  ios: "ios";
953
- android: "android";
954
955
  UNKNOWN_EXECUTION_PLATFORM: "UNKNOWN_EXECUTION_PLATFORM";
955
956
  WEB_EXECUTION_PLATFORM: "WEB_EXECUTION_PLATFORM";
956
957
  IOS_EXECUTION_PLATFORM: "IOS_EXECUTION_PLATFORM";
957
958
  ANDROID_EXECUTION_PLATFORM: "ANDROID_EXECUTION_PLATFORM";
958
- }>, z.ZodTransform<"UNKNOWN_EXECUTION_PLATFORM" | "WEB_EXECUTION_PLATFORM" | "IOS_EXECUTION_PLATFORM" | "ANDROID_EXECUTION_PLATFORM", "web" | "ios" | "android" | "UNKNOWN_EXECUTION_PLATFORM" | "WEB_EXECUTION_PLATFORM" | "IOS_EXECUTION_PLATFORM" | "ANDROID_EXECUTION_PLATFORM">>>;
959
+ }>, z.ZodTransform<"UNKNOWN_EXECUTION_PLATFORM" | "WEB_EXECUTION_PLATFORM" | "IOS_EXECUTION_PLATFORM" | "ANDROID_EXECUTION_PLATFORM", "android" | "web" | "ios" | "UNKNOWN_EXECUTION_PLATFORM" | "WEB_EXECUTION_PLATFORM" | "IOS_EXECUTION_PLATFORM" | "ANDROID_EXECUTION_PLATFORM">>>;
959
960
  automationEmitsOnly: z.ZodOptional<z.ZodBoolean>;
960
961
  metadataFilters: z.ZodOptional<z.ZodArray<z.ZodObject<{
961
962
  key: z.ZodString;
@@ -987,14 +988,14 @@ export declare const getTruecoverageEventDetailsInput: z.ZodObject<{
987
988
  release: z.ZodOptional<z.ZodString>;
988
989
  branchName: z.ZodOptional<z.ZodString>;
989
990
  platform: z.ZodOptional<z.ZodPipe<z.ZodEnum<{
991
+ android: "android";
990
992
  web: "web";
991
993
  ios: "ios";
992
- android: "android";
993
994
  UNKNOWN_EXECUTION_PLATFORM: "UNKNOWN_EXECUTION_PLATFORM";
994
995
  WEB_EXECUTION_PLATFORM: "WEB_EXECUTION_PLATFORM";
995
996
  IOS_EXECUTION_PLATFORM: "IOS_EXECUTION_PLATFORM";
996
997
  ANDROID_EXECUTION_PLATFORM: "ANDROID_EXECUTION_PLATFORM";
997
- }>, z.ZodTransform<"UNKNOWN_EXECUTION_PLATFORM" | "WEB_EXECUTION_PLATFORM" | "IOS_EXECUTION_PLATFORM" | "ANDROID_EXECUTION_PLATFORM", "web" | "ios" | "android" | "UNKNOWN_EXECUTION_PLATFORM" | "WEB_EXECUTION_PLATFORM" | "IOS_EXECUTION_PLATFORM" | "ANDROID_EXECUTION_PLATFORM">>>;
998
+ }>, z.ZodTransform<"UNKNOWN_EXECUTION_PLATFORM" | "WEB_EXECUTION_PLATFORM" | "IOS_EXECUTION_PLATFORM" | "ANDROID_EXECUTION_PLATFORM", "android" | "web" | "ios" | "UNKNOWN_EXECUTION_PLATFORM" | "WEB_EXECUTION_PLATFORM" | "IOS_EXECUTION_PLATFORM" | "ANDROID_EXECUTION_PLATFORM">>>;
998
999
  automationEmitsOnly: z.ZodOptional<z.ZodBoolean>;
999
1000
  metadataFilters: z.ZodOptional<z.ZodArray<z.ZodObject<{
1000
1001
  key: z.ZodString;
@@ -1029,14 +1030,14 @@ export declare const listTruecoverageChildEventTreeInput: z.ZodObject<{
1029
1030
  release: z.ZodOptional<z.ZodString>;
1030
1031
  branchName: z.ZodOptional<z.ZodString>;
1031
1032
  platform: z.ZodOptional<z.ZodPipe<z.ZodEnum<{
1033
+ android: "android";
1032
1034
  web: "web";
1033
1035
  ios: "ios";
1034
- android: "android";
1035
1036
  UNKNOWN_EXECUTION_PLATFORM: "UNKNOWN_EXECUTION_PLATFORM";
1036
1037
  WEB_EXECUTION_PLATFORM: "WEB_EXECUTION_PLATFORM";
1037
1038
  IOS_EXECUTION_PLATFORM: "IOS_EXECUTION_PLATFORM";
1038
1039
  ANDROID_EXECUTION_PLATFORM: "ANDROID_EXECUTION_PLATFORM";
1039
- }>, z.ZodTransform<"UNKNOWN_EXECUTION_PLATFORM" | "WEB_EXECUTION_PLATFORM" | "IOS_EXECUTION_PLATFORM" | "ANDROID_EXECUTION_PLATFORM", "web" | "ios" | "android" | "UNKNOWN_EXECUTION_PLATFORM" | "WEB_EXECUTION_PLATFORM" | "IOS_EXECUTION_PLATFORM" | "ANDROID_EXECUTION_PLATFORM">>>;
1040
+ }>, z.ZodTransform<"UNKNOWN_EXECUTION_PLATFORM" | "WEB_EXECUTION_PLATFORM" | "IOS_EXECUTION_PLATFORM" | "ANDROID_EXECUTION_PLATFORM", "android" | "web" | "ios" | "UNKNOWN_EXECUTION_PLATFORM" | "WEB_EXECUTION_PLATFORM" | "IOS_EXECUTION_PLATFORM" | "ANDROID_EXECUTION_PLATFORM">>>;
1040
1041
  automationEmitsOnly: z.ZodOptional<z.ZodBoolean>;
1041
1042
  metadataFilters: z.ZodOptional<z.ZodArray<z.ZodObject<{
1042
1043
  key: z.ZodString;
@@ -1068,14 +1069,14 @@ export declare const listTruecoverageChildEventTreeInput: z.ZodObject<{
1068
1069
  release: z.ZodOptional<z.ZodString>;
1069
1070
  branchName: z.ZodOptional<z.ZodString>;
1070
1071
  platform: z.ZodOptional<z.ZodPipe<z.ZodEnum<{
1072
+ android: "android";
1071
1073
  web: "web";
1072
1074
  ios: "ios";
1073
- android: "android";
1074
1075
  UNKNOWN_EXECUTION_PLATFORM: "UNKNOWN_EXECUTION_PLATFORM";
1075
1076
  WEB_EXECUTION_PLATFORM: "WEB_EXECUTION_PLATFORM";
1076
1077
  IOS_EXECUTION_PLATFORM: "IOS_EXECUTION_PLATFORM";
1077
1078
  ANDROID_EXECUTION_PLATFORM: "ANDROID_EXECUTION_PLATFORM";
1078
- }>, z.ZodTransform<"UNKNOWN_EXECUTION_PLATFORM" | "WEB_EXECUTION_PLATFORM" | "IOS_EXECUTION_PLATFORM" | "ANDROID_EXECUTION_PLATFORM", "web" | "ios" | "android" | "UNKNOWN_EXECUTION_PLATFORM" | "WEB_EXECUTION_PLATFORM" | "IOS_EXECUTION_PLATFORM" | "ANDROID_EXECUTION_PLATFORM">>>;
1079
+ }>, z.ZodTransform<"UNKNOWN_EXECUTION_PLATFORM" | "WEB_EXECUTION_PLATFORM" | "IOS_EXECUTION_PLATFORM" | "ANDROID_EXECUTION_PLATFORM", "android" | "web" | "ios" | "UNKNOWN_EXECUTION_PLATFORM" | "WEB_EXECUTION_PLATFORM" | "IOS_EXECUTION_PLATFORM" | "ANDROID_EXECUTION_PLATFORM">>>;
1079
1080
  automationEmitsOnly: z.ZodOptional<z.ZodBoolean>;
1080
1081
  metadataFilters: z.ZodOptional<z.ZodArray<z.ZodObject<{
1081
1082
  key: z.ZodString;
@@ -1111,14 +1112,14 @@ export declare const getTruecoverageEventTransitionInput: z.ZodObject<{
1111
1112
  release: z.ZodOptional<z.ZodString>;
1112
1113
  branchName: z.ZodOptional<z.ZodString>;
1113
1114
  platform: z.ZodOptional<z.ZodPipe<z.ZodEnum<{
1115
+ android: "android";
1114
1116
  web: "web";
1115
1117
  ios: "ios";
1116
- android: "android";
1117
1118
  UNKNOWN_EXECUTION_PLATFORM: "UNKNOWN_EXECUTION_PLATFORM";
1118
1119
  WEB_EXECUTION_PLATFORM: "WEB_EXECUTION_PLATFORM";
1119
1120
  IOS_EXECUTION_PLATFORM: "IOS_EXECUTION_PLATFORM";
1120
1121
  ANDROID_EXECUTION_PLATFORM: "ANDROID_EXECUTION_PLATFORM";
1121
- }>, z.ZodTransform<"UNKNOWN_EXECUTION_PLATFORM" | "WEB_EXECUTION_PLATFORM" | "IOS_EXECUTION_PLATFORM" | "ANDROID_EXECUTION_PLATFORM", "web" | "ios" | "android" | "UNKNOWN_EXECUTION_PLATFORM" | "WEB_EXECUTION_PLATFORM" | "IOS_EXECUTION_PLATFORM" | "ANDROID_EXECUTION_PLATFORM">>>;
1122
+ }>, z.ZodTransform<"UNKNOWN_EXECUTION_PLATFORM" | "WEB_EXECUTION_PLATFORM" | "IOS_EXECUTION_PLATFORM" | "ANDROID_EXECUTION_PLATFORM", "android" | "web" | "ios" | "UNKNOWN_EXECUTION_PLATFORM" | "WEB_EXECUTION_PLATFORM" | "IOS_EXECUTION_PLATFORM" | "ANDROID_EXECUTION_PLATFORM">>>;
1122
1123
  automationEmitsOnly: z.ZodOptional<z.ZodBoolean>;
1123
1124
  metadataFilters: z.ZodOptional<z.ZodArray<z.ZodObject<{
1124
1125
  key: z.ZodString;
@@ -1150,14 +1151,14 @@ export declare const getTruecoverageEventTransitionInput: z.ZodObject<{
1150
1151
  release: z.ZodOptional<z.ZodString>;
1151
1152
  branchName: z.ZodOptional<z.ZodString>;
1152
1153
  platform: z.ZodOptional<z.ZodPipe<z.ZodEnum<{
1154
+ android: "android";
1153
1155
  web: "web";
1154
1156
  ios: "ios";
1155
- android: "android";
1156
1157
  UNKNOWN_EXECUTION_PLATFORM: "UNKNOWN_EXECUTION_PLATFORM";
1157
1158
  WEB_EXECUTION_PLATFORM: "WEB_EXECUTION_PLATFORM";
1158
1159
  IOS_EXECUTION_PLATFORM: "IOS_EXECUTION_PLATFORM";
1159
1160
  ANDROID_EXECUTION_PLATFORM: "ANDROID_EXECUTION_PLATFORM";
1160
- }>, z.ZodTransform<"UNKNOWN_EXECUTION_PLATFORM" | "WEB_EXECUTION_PLATFORM" | "IOS_EXECUTION_PLATFORM" | "ANDROID_EXECUTION_PLATFORM", "web" | "ios" | "android" | "UNKNOWN_EXECUTION_PLATFORM" | "WEB_EXECUTION_PLATFORM" | "IOS_EXECUTION_PLATFORM" | "ANDROID_EXECUTION_PLATFORM">>>;
1161
+ }>, z.ZodTransform<"UNKNOWN_EXECUTION_PLATFORM" | "WEB_EXECUTION_PLATFORM" | "IOS_EXECUTION_PLATFORM" | "ANDROID_EXECUTION_PLATFORM", "android" | "web" | "ios" | "UNKNOWN_EXECUTION_PLATFORM" | "WEB_EXECUTION_PLATFORM" | "IOS_EXECUTION_PLATFORM" | "ANDROID_EXECUTION_PLATFORM">>>;
1161
1162
  automationEmitsOnly: z.ZodOptional<z.ZodBoolean>;
1162
1163
  metadataFilters: z.ZodOptional<z.ZodArray<z.ZodObject<{
1163
1164
  key: z.ZodString;
@@ -1204,14 +1205,14 @@ export declare const getTruecoverageEventTimeSeriesInput: z.ZodObject<{
1204
1205
  release: z.ZodOptional<z.ZodString>;
1205
1206
  branchName: z.ZodOptional<z.ZodString>;
1206
1207
  platform: z.ZodOptional<z.ZodPipe<z.ZodEnum<{
1208
+ android: "android";
1207
1209
  web: "web";
1208
1210
  ios: "ios";
1209
- android: "android";
1210
1211
  UNKNOWN_EXECUTION_PLATFORM: "UNKNOWN_EXECUTION_PLATFORM";
1211
1212
  WEB_EXECUTION_PLATFORM: "WEB_EXECUTION_PLATFORM";
1212
1213
  IOS_EXECUTION_PLATFORM: "IOS_EXECUTION_PLATFORM";
1213
1214
  ANDROID_EXECUTION_PLATFORM: "ANDROID_EXECUTION_PLATFORM";
1214
- }>, z.ZodTransform<"UNKNOWN_EXECUTION_PLATFORM" | "WEB_EXECUTION_PLATFORM" | "IOS_EXECUTION_PLATFORM" | "ANDROID_EXECUTION_PLATFORM", "web" | "ios" | "android" | "UNKNOWN_EXECUTION_PLATFORM" | "WEB_EXECUTION_PLATFORM" | "IOS_EXECUTION_PLATFORM" | "ANDROID_EXECUTION_PLATFORM">>>;
1215
+ }>, z.ZodTransform<"UNKNOWN_EXECUTION_PLATFORM" | "WEB_EXECUTION_PLATFORM" | "IOS_EXECUTION_PLATFORM" | "ANDROID_EXECUTION_PLATFORM", "android" | "web" | "ios" | "UNKNOWN_EXECUTION_PLATFORM" | "WEB_EXECUTION_PLATFORM" | "IOS_EXECUTION_PLATFORM" | "ANDROID_EXECUTION_PLATFORM">>>;
1215
1216
  automationEmitsOnly: z.ZodOptional<z.ZodBoolean>;
1216
1217
  metadataFilters: z.ZodOptional<z.ZodArray<z.ZodObject<{
1217
1218
  key: z.ZodString;
@@ -2007,3 +2008,71 @@ export declare const uploadAttachmentInput: z.ZodObject<{
2007
2008
  export declare const getBatchViewUrlInput: z.ZodObject<{
2008
2009
  batchInvocationId: z.ZodString;
2009
2010
  }, z.core.$strip>;
2011
+ export declare const botRoleSchema: z.ZodEnum<{
2012
+ QA_LEAD: "QA_LEAD";
2013
+ PM: "PM";
2014
+ QA_ENGINEER: "QA_ENGINEER";
2015
+ DEVELOPER: "DEVELOPER";
2016
+ }>;
2017
+ export declare const botCapabilitySchema: z.ZodEnum<{
2018
+ REQUIREMENTS_UPDATE: "REQUIREMENTS_UPDATE";
2019
+ E2E_AUTHORING: "E2E_AUTHORING";
2020
+ ISSUE_FIX: "ISSUE_FIX";
2021
+ MANUAL_TEST_COORDINATION: "MANUAL_TEST_COORDINATION";
2022
+ TEST_BATCH_FIX: "TEST_BATCH_FIX";
2023
+ QA_POSTURE: "QA_POSTURE";
2024
+ }>;
2025
+ export declare const botSubscriptionFilterSchema: z.ZodObject<{
2026
+ field: z.ZodString;
2027
+ op: z.ZodDefault<z.ZodLiteral<"eq">>;
2028
+ value: z.ZodString;
2029
+ }, z.core.$strip>;
2030
+ export declare const botSubscriptionSchema: z.ZodObject<{
2031
+ eventType: z.ZodString;
2032
+ filters: z.ZodOptional<z.ZodArray<z.ZodObject<{
2033
+ field: z.ZodString;
2034
+ op: z.ZodDefault<z.ZodLiteral<"eq">>;
2035
+ value: z.ZodString;
2036
+ }, z.core.$strip>>>;
2037
+ }, z.core.$strip>;
2038
+ export declare const registerBotProfileInput: z.ZodObject<{
2039
+ botId: z.ZodOptional<z.ZodString>;
2040
+ role: z.ZodEnum<{
2041
+ QA_LEAD: "QA_LEAD";
2042
+ PM: "PM";
2043
+ QA_ENGINEER: "QA_ENGINEER";
2044
+ DEVELOPER: "DEVELOPER";
2045
+ }>;
2046
+ responsibilities: z.ZodOptional<z.ZodString>;
2047
+ capabilities: z.ZodDefault<z.ZodArray<z.ZodEnum<{
2048
+ REQUIREMENTS_UPDATE: "REQUIREMENTS_UPDATE";
2049
+ E2E_AUTHORING: "E2E_AUTHORING";
2050
+ ISSUE_FIX: "ISSUE_FIX";
2051
+ MANUAL_TEST_COORDINATION: "MANUAL_TEST_COORDINATION";
2052
+ TEST_BATCH_FIX: "TEST_BATCH_FIX";
2053
+ QA_POSTURE: "QA_POSTURE";
2054
+ }>>>;
2055
+ subscriptions: z.ZodDefault<z.ZodArray<z.ZodObject<{
2056
+ eventType: z.ZodString;
2057
+ filters: z.ZodOptional<z.ZodArray<z.ZodObject<{
2058
+ field: z.ZodString;
2059
+ op: z.ZodDefault<z.ZodLiteral<"eq">>;
2060
+ value: z.ZodString;
2061
+ }, z.core.$strip>>>;
2062
+ }, z.core.$strip>>>;
2063
+ }, z.core.$strip>;
2064
+ export declare const getBotProfileInput: z.ZodObject<{
2065
+ botId: z.ZodOptional<z.ZodString>;
2066
+ }, z.core.$strip>;
2067
+ export declare const getMyTasksInput: z.ZodObject<{
2068
+ userId: z.ZodOptional<z.ZodString>;
2069
+ }, z.core.$strip>;
2070
+ export declare const listTestsAwaitingVerificationInput: z.ZodObject<{
2071
+ userId: z.ZodOptional<z.ZodString>;
2072
+ limit: z.ZodOptional<z.ZodNumber>;
2073
+ }, z.core.$strip>;
2074
+ export declare const MAX_BOT_ACK_EVENT_IDS = 100;
2075
+ export declare const ackBotEventsInput: z.ZodObject<{
2076
+ eventIds: z.ZodArray<z.ZodString>;
2077
+ ackUrl: z.ZodOptional<z.ZodString>;
2078
+ }, z.core.$strip>;
@@ -323,6 +323,10 @@ export const updateGitFolderMappingInput = z.object({
323
323
  testsFolderPath: z.string().min(1).optional(),
324
324
  plansFolderPath: z.string().min(1).optional(),
325
325
  repositoryFullName: z.string().optional(),
326
+ plansBranch: z
327
+ .string()
328
+ .optional()
329
+ .describe("Branch plans sync against. Empty string resets to the repository default branch."),
326
330
  tests_folder_path: z.string().min(1).optional(),
327
331
  plans_folder_path: z.string().min(1).optional(),
328
332
  repository_full_name: z.string().optional(),
@@ -1040,3 +1044,52 @@ export const uploadAttachmentInput = z.object({
1040
1044
  export const getBatchViewUrlInput = z.object({
1041
1045
  batchInvocationId: z.string().min(1),
1042
1046
  });
1047
+ export const botRoleSchema = z.enum(["QA_LEAD", "PM", "QA_ENGINEER", "DEVELOPER"]);
1048
+ export const botCapabilitySchema = z.enum([
1049
+ "REQUIREMENTS_UPDATE",
1050
+ "E2E_AUTHORING",
1051
+ "ISSUE_FIX",
1052
+ "MANUAL_TEST_COORDINATION",
1053
+ "TEST_BATCH_FIX",
1054
+ "QA_POSTURE",
1055
+ ]);
1056
+ export const botSubscriptionFilterSchema = z.object({
1057
+ /** Payload filter field, e.g. author / assignee / adder. */
1058
+ field: z.string().min(1),
1059
+ op: z.literal("eq").default("eq"),
1060
+ /** Literal value, or the token `me` (resolved to the bot's user). */
1061
+ value: z.string().min(1),
1062
+ });
1063
+ export const botSubscriptionSchema = z.object({
1064
+ /** Wire event type, e.g. git-push, issue-assigned, e2e-batch-completed. */
1065
+ eventType: z.string().min(1),
1066
+ filters: z.array(botSubscriptionFilterSchema).optional(),
1067
+ });
1068
+ export const registerBotProfileInput = z.object({
1069
+ /** Defaults to the bot-id header (TESTCHIMP_BOT_ID) or the OAuth token's bot. */
1070
+ botId: z.string().min(1).max(64).optional(),
1071
+ role: botRoleSchema,
1072
+ responsibilities: z.string().optional(),
1073
+ capabilities: z.array(botCapabilitySchema).default([]),
1074
+ subscriptions: z.array(botSubscriptionSchema).default([]),
1075
+ });
1076
+ export const getBotProfileInput = z.object({
1077
+ botId: z.string().min(1).max(64).optional(),
1078
+ });
1079
+ export const getMyTasksInput = z.object({
1080
+ /** Required with an API key; ignored with an OAuth token (the token's user is used). */
1081
+ userId: z.string().min(1).optional(),
1082
+ });
1083
+ export const listTestsAwaitingVerificationInput = z.object({
1084
+ userId: z.string().min(1).optional(),
1085
+ limit: z.number().int().positive().max(500).optional(),
1086
+ });
1087
+ export const MAX_BOT_ACK_EVENT_IDS = 100;
1088
+ export const ackBotEventsInput = z.object({
1089
+ eventIds: z
1090
+ .array(z.string().regex(/^[\x20-\x7e]+$/, "eventIds must be printable ASCII").min(1))
1091
+ .min(1)
1092
+ .max(MAX_BOT_ACK_EVENT_IDS),
1093
+ /** Webhook delivery ackUrl; defaults to ${TESTCHIMP_INGRESS_URL}/bot/events/ack. */
1094
+ ackUrl: z.string().min(1).optional(),
1095
+ });
@@ -1,10 +1,14 @@
1
1
  import { type ZodTypeAny } from "zod";
2
- import type { PostMcpFn } from "./client.js";
2
+ import { type PostIngressFn, type PostMcpFn } from "./client.js";
3
3
  import { type ProgressLog } from "./ephemeralWait.js";
4
4
  export interface ToolContext {
5
5
  postMcp: PostMcpFn;
6
+ /** Ingress poster (bot acks); defaults to the env-configured ingress client. */
7
+ postIngress?: PostIngressFn;
6
8
  onProgress?: ProgressLog;
7
9
  }
10
+ export declare const BOT_ACK_PATH = "/bot/events/ack";
11
+ export declare const BOT_ACK_UNSUPPORTED_MESSAGE: string;
8
12
  export interface ToolDefinition {
9
13
  kebab: string;
10
14
  description: string;