codmir 0.3.3 → 0.4.0

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.
@@ -9,6 +9,7 @@ var CodmirClient = class {
9
9
  };
10
10
  this.tickets = new TicketsAPI(this.config);
11
11
  this.testCases = new TestCasesAPI(this.config);
12
+ this.testing = new TestingAPI(this.config);
12
13
  }
13
14
  /**
14
15
  * Make an HTTP request to the codmir API
@@ -267,6 +268,75 @@ var TestCasesAPI = class {
267
268
  );
268
269
  }
269
270
  };
271
+ var TestingAPI = class {
272
+ constructor(config) {
273
+ this.config = config;
274
+ }
275
+ async request(method, path, body) {
276
+ const url = `${this.config.baseUrl}${path}`;
277
+ const headers = {
278
+ "Content-Type": "application/json",
279
+ ...this.config.headers
280
+ };
281
+ if (this.config.apiKey) {
282
+ headers["X-API-Key"] = this.config.apiKey;
283
+ }
284
+ const controller = new AbortController();
285
+ const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);
286
+ try {
287
+ const response = await fetch(url, {
288
+ method,
289
+ headers,
290
+ body: body ? JSON.stringify(body) : void 0,
291
+ signal: controller.signal
292
+ });
293
+ clearTimeout(timeoutId);
294
+ if (!response.ok) {
295
+ const errorData = await response.json().catch(() => ({}));
296
+ const error = new Error(errorData.error || `HTTP ${response.status}`);
297
+ error.statusCode = response.status;
298
+ error.response = errorData;
299
+ throw error;
300
+ }
301
+ if (response.status === 204) {
302
+ return {};
303
+ }
304
+ return await response.json();
305
+ } catch (error) {
306
+ clearTimeout(timeoutId);
307
+ if (error.name === "AbortError") {
308
+ const timeoutError = new Error("Request timeout");
309
+ timeoutError.statusCode = 408;
310
+ throw timeoutError;
311
+ }
312
+ throw error;
313
+ }
314
+ }
315
+ async submitTestRun(payload) {
316
+ return this.request("POST", "/api/testing/test-runs", payload);
317
+ }
318
+ async listTestRuns(projectId, options) {
319
+ const params = new URLSearchParams({ projectId });
320
+ if (options?.limit) params.set("limit", String(options.limit));
321
+ if (options?.suite) params.set("suite", options.suite);
322
+ const response = await this.request(
323
+ "GET",
324
+ `/api/testing/test-runs?${params.toString()}`
325
+ );
326
+ return response.runs || [];
327
+ }
328
+ async requestCoverageInsight(payload) {
329
+ return this.request("POST", "/api/testing/coverage-insight", payload);
330
+ }
331
+ async listCoverageInsights(projectId, limit = 5) {
332
+ const params = new URLSearchParams({ projectId, limit: String(limit) });
333
+ const response = await this.request(
334
+ "GET",
335
+ `/api/testing/coverage-insight?${params.toString()}`
336
+ );
337
+ return response.reports || [];
338
+ }
339
+ };
270
340
 
271
341
  export {
272
342
  CodmirClient
package/dist/cli/index.js CHANGED
@@ -137,8 +137,8 @@ var require_package = __commonJS({
137
137
  "package.json"(exports2, module2) {
138
138
  module2.exports = {
139
139
  name: "codmir",
140
- version: "0.3.3",
141
- description: "Official codmir SDK - CLI and SDK for AI-powered development: codebase analysis, task replication, usage tracking, and intelligent automation",
140
+ version: "0.4.0",
141
+ description: "Official codmir SDK - AI that prevents wasted engineering time. CLI, SDK, voice assistant, codebase analysis, and intelligent automation.",
142
142
  main: "dist/index.js",
143
143
  module: "dist/index.mjs",
144
144
  types: "dist/index.d.ts",
@@ -150,6 +150,16 @@ var require_package = __commonJS({
150
150
  types: "./dist/index.d.ts",
151
151
  require: "./dist/index.js",
152
152
  import: "./dist/index.mjs"
153
+ },
154
+ "./voice-agent": {
155
+ types: "./dist/voice-agent/index.d.ts",
156
+ require: "./dist/voice-agent/index.js",
157
+ import: "./dist/voice-agent/index.mjs"
158
+ },
159
+ "./voice-daemon": {
160
+ types: "./dist/voice-daemon/index.d.ts",
161
+ require: "./dist/voice-daemon/index.js",
162
+ import: "./dist/voice-daemon/index.mjs"
153
163
  }
154
164
  },
155
165
  files: [
@@ -159,7 +169,7 @@ var require_package = __commonJS({
159
169
  "runkit-example.js"
160
170
  ],
161
171
  scripts: {
162
- build: "tsup src/index.ts src/cli/index.ts --format cjs,esm --dts --clean",
172
+ build: "tsup src/index.ts src/cli/index.ts src/voice-agent/index.ts src/voice-daemon/index.ts --format cjs,esm --dts --clean",
163
173
  dev: "tsup src/index.ts src/cli/index.ts --format cjs,esm --dts --watch",
164
174
  prepublishOnly: "pnpm build",
165
175
  test: "jest",
@@ -185,7 +195,11 @@ var require_package = __commonJS({
185
195
  "tasks",
186
196
  "automation",
187
197
  "multi-agent",
188
- "ai-assistant"
198
+ "ai-assistant",
199
+ "voice-assistant",
200
+ "speech-recognition",
201
+ "voice-daemon",
202
+ "wake-word"
189
203
  ],
190
204
  author: "codmir",
191
205
  license: "MIT",
@@ -210,12 +224,16 @@ var require_package = __commonJS({
210
224
  "@semantic-release/release-notes-generator": "^14.0.0",
211
225
  "@types/node": "^20.10.0",
212
226
  "@types/prompts": "^2.4.9",
227
+ "@types/ws": "^8.18.1",
228
+ "@types/blessed": "^0.1.25",
213
229
  "conventional-changelog-conventionalcommits": "^8.0.0",
214
230
  "semantic-release": "^24.0.0",
215
231
  tsup: "^8.0.1",
216
232
  typescript: "^5.8.3"
217
233
  },
218
234
  dependencies: {
235
+ blessed: "^0.1.81",
236
+ "blessed-contrib": "^4.11.0",
219
237
  chalk: "^5.3.0",
220
238
  clipboardy: "^5.0.1",
221
239
  commander: "^12.0.0",
@@ -1080,6 +1098,7 @@ var CodmirClient = class {
1080
1098
  };
1081
1099
  this.tickets = new TicketsAPI(this.config);
1082
1100
  this.testCases = new TestCasesAPI(this.config);
1101
+ this.testing = new TestingAPI(this.config);
1083
1102
  }
1084
1103
  /**
1085
1104
  * Make an HTTP request to the codmir API
@@ -1338,6 +1357,75 @@ var TestCasesAPI = class {
1338
1357
  );
1339
1358
  }
1340
1359
  };
1360
+ var TestingAPI = class {
1361
+ constructor(config) {
1362
+ this.config = config;
1363
+ }
1364
+ async request(method, path8, body) {
1365
+ const url = `${this.config.baseUrl}${path8}`;
1366
+ const headers = {
1367
+ "Content-Type": "application/json",
1368
+ ...this.config.headers
1369
+ };
1370
+ if (this.config.apiKey) {
1371
+ headers["X-API-Key"] = this.config.apiKey;
1372
+ }
1373
+ const controller = new AbortController();
1374
+ const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);
1375
+ try {
1376
+ const response = await fetch(url, {
1377
+ method,
1378
+ headers,
1379
+ body: body ? JSON.stringify(body) : void 0,
1380
+ signal: controller.signal
1381
+ });
1382
+ clearTimeout(timeoutId);
1383
+ if (!response.ok) {
1384
+ const errorData = await response.json().catch(() => ({}));
1385
+ const error = new Error(errorData.error || `HTTP ${response.status}`);
1386
+ error.statusCode = response.status;
1387
+ error.response = errorData;
1388
+ throw error;
1389
+ }
1390
+ if (response.status === 204) {
1391
+ return {};
1392
+ }
1393
+ return await response.json();
1394
+ } catch (error) {
1395
+ clearTimeout(timeoutId);
1396
+ if (error.name === "AbortError") {
1397
+ const timeoutError = new Error("Request timeout");
1398
+ timeoutError.statusCode = 408;
1399
+ throw timeoutError;
1400
+ }
1401
+ throw error;
1402
+ }
1403
+ }
1404
+ async submitTestRun(payload) {
1405
+ return this.request("POST", "/api/testing/test-runs", payload);
1406
+ }
1407
+ async listTestRuns(projectId, options) {
1408
+ const params = new URLSearchParams({ projectId });
1409
+ if (options?.limit) params.set("limit", String(options.limit));
1410
+ if (options?.suite) params.set("suite", options.suite);
1411
+ const response = await this.request(
1412
+ "GET",
1413
+ `/api/testing/test-runs?${params.toString()}`
1414
+ );
1415
+ return response.runs || [];
1416
+ }
1417
+ async requestCoverageInsight(payload) {
1418
+ return this.request("POST", "/api/testing/coverage-insight", payload);
1419
+ }
1420
+ async listCoverageInsights(projectId, limit = 5) {
1421
+ const params = new URLSearchParams({ projectId, limit: String(limit) });
1422
+ const response = await this.request(
1423
+ "GET",
1424
+ `/api/testing/coverage-insight?${params.toString()}`
1425
+ );
1426
+ return response.reports || [];
1427
+ }
1428
+ };
1341
1429
 
1342
1430
  // src/cli/commands/link.ts
1343
1431
  var import_prompts2 = __toESM(require("prompts"));
@@ -2251,30 +2339,34 @@ function handleCouncilMessage(message, context) {
2251
2339
  console.log("");
2252
2340
  break;
2253
2341
  case "round-start":
2254
- printRoundHeader(message.round);
2342
+ printRoundHeader(message.round ?? 0);
2255
2343
  roundResponses.length = 0;
2256
2344
  break;
2257
- case "member-thinking":
2345
+ case "member-thinking": {
2346
+ const role = message.role ?? "architect";
2258
2347
  const thinkSpinner = (0, import_ora3.default)({
2259
- text: `${ROLE_ICONS[message.role]} ${capitalize(message.role)} is analyzing...`,
2348
+ text: `${ROLE_ICONS[role]} ${capitalize(role)} is analyzing...`,
2260
2349
  color: "yellow"
2261
2350
  }).start();
2262
2351
  onSpinnerUpdate(thinkSpinner);
2263
2352
  break;
2264
- case "member-response":
2353
+ }
2354
+ case "member-response": {
2265
2355
  if (currentSpinner) currentSpinner.stop();
2266
- const roleColor = ROLE_COLORS[message.role] || import_chalk10.default.white;
2267
- const icon = ROLE_ICONS[message.role] || "\u{1F916}";
2356
+ const role = message.role ?? "architect";
2357
+ const roleColor = ROLE_COLORS[role] || import_chalk10.default.white;
2358
+ const icon = ROLE_ICONS[role] || "\u{1F916}";
2268
2359
  console.log("");
2269
- console.log(roleColor.bold(`${icon} ${capitalize(message.role)}:`));
2270
- const formatted = formatResponse(message.content);
2360
+ console.log(roleColor.bold(`${icon} ${capitalize(role)}:`));
2361
+ const formatted = formatResponse(typeof message.content === "string" ? message.content : "");
2271
2362
  console.log(import_chalk10.default.gray(` ${formatted}`));
2272
2363
  console.log("");
2273
2364
  roundResponses.push(message);
2274
2365
  break;
2366
+ }
2275
2367
  case "round-complete":
2276
- const agreementCount = message.agreements || 0;
2277
- const totalMembers = message.totalMembers || roundResponses.length;
2368
+ const agreementCount = typeof message.agreements === "number" ? message.agreements : 0;
2369
+ const totalMembers = typeof message.totalMembers === "number" ? message.totalMembers : roundResponses.length;
2278
2370
  const agreementPercent = Math.round(agreementCount / totalMembers * 100);
2279
2371
  console.log(import_chalk10.default.gray(` Agreement: ${agreementCount}/${totalMembers} (${agreementPercent}%)`));
2280
2372
  console.log("");
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  CodmirClient
4
- } from "../chunk-LXEEBTWT.mjs";
4
+ } from "../chunk-GU32P57R.mjs";
5
5
  import {
6
6
  analyzeCommand,
7
7
  clearConfig,
@@ -25,8 +25,8 @@ var require_package = __commonJS({
25
25
  "package.json"(exports, module) {
26
26
  module.exports = {
27
27
  name: "codmir",
28
- version: "0.3.3",
29
- description: "Official codmir SDK - CLI and SDK for AI-powered development: codebase analysis, task replication, usage tracking, and intelligent automation",
28
+ version: "0.4.0",
29
+ description: "Official codmir SDK - AI that prevents wasted engineering time. CLI, SDK, voice assistant, codebase analysis, and intelligent automation.",
30
30
  main: "dist/index.js",
31
31
  module: "dist/index.mjs",
32
32
  types: "dist/index.d.ts",
@@ -38,6 +38,16 @@ var require_package = __commonJS({
38
38
  types: "./dist/index.d.ts",
39
39
  require: "./dist/index.js",
40
40
  import: "./dist/index.mjs"
41
+ },
42
+ "./voice-agent": {
43
+ types: "./dist/voice-agent/index.d.ts",
44
+ require: "./dist/voice-agent/index.js",
45
+ import: "./dist/voice-agent/index.mjs"
46
+ },
47
+ "./voice-daemon": {
48
+ types: "./dist/voice-daemon/index.d.ts",
49
+ require: "./dist/voice-daemon/index.js",
50
+ import: "./dist/voice-daemon/index.mjs"
41
51
  }
42
52
  },
43
53
  files: [
@@ -47,7 +57,7 @@ var require_package = __commonJS({
47
57
  "runkit-example.js"
48
58
  ],
49
59
  scripts: {
50
- build: "tsup src/index.ts src/cli/index.ts --format cjs,esm --dts --clean",
60
+ build: "tsup src/index.ts src/cli/index.ts src/voice-agent/index.ts src/voice-daemon/index.ts --format cjs,esm --dts --clean",
51
61
  dev: "tsup src/index.ts src/cli/index.ts --format cjs,esm --dts --watch",
52
62
  prepublishOnly: "pnpm build",
53
63
  test: "jest",
@@ -73,7 +83,11 @@ var require_package = __commonJS({
73
83
  "tasks",
74
84
  "automation",
75
85
  "multi-agent",
76
- "ai-assistant"
86
+ "ai-assistant",
87
+ "voice-assistant",
88
+ "speech-recognition",
89
+ "voice-daemon",
90
+ "wake-word"
77
91
  ],
78
92
  author: "codmir",
79
93
  license: "MIT",
@@ -98,12 +112,16 @@ var require_package = __commonJS({
98
112
  "@semantic-release/release-notes-generator": "^14.0.0",
99
113
  "@types/node": "^20.10.0",
100
114
  "@types/prompts": "^2.4.9",
115
+ "@types/ws": "^8.18.1",
116
+ "@types/blessed": "^0.1.25",
101
117
  "conventional-changelog-conventionalcommits": "^8.0.0",
102
118
  "semantic-release": "^24.0.0",
103
119
  tsup: "^8.0.1",
104
120
  typescript: "^5.8.3"
105
121
  },
106
122
  dependencies: {
123
+ blessed: "^0.1.81",
124
+ "blessed-contrib": "^4.11.0",
107
125
  chalk: "^5.3.0",
108
126
  clipboardy: "^5.0.1",
109
127
  commander: "^12.0.0",
@@ -1190,30 +1208,34 @@ function handleCouncilMessage(message, context) {
1190
1208
  console.log("");
1191
1209
  break;
1192
1210
  case "round-start":
1193
- printRoundHeader(message.round);
1211
+ printRoundHeader(message.round ?? 0);
1194
1212
  roundResponses.length = 0;
1195
1213
  break;
1196
- case "member-thinking":
1214
+ case "member-thinking": {
1215
+ const role = message.role ?? "architect";
1197
1216
  const thinkSpinner = ora2({
1198
- text: `${ROLE_ICONS[message.role]} ${capitalize(message.role)} is analyzing...`,
1217
+ text: `${ROLE_ICONS[role]} ${capitalize(role)} is analyzing...`,
1199
1218
  color: "yellow"
1200
1219
  }).start();
1201
1220
  onSpinnerUpdate(thinkSpinner);
1202
1221
  break;
1203
- case "member-response":
1222
+ }
1223
+ case "member-response": {
1204
1224
  if (currentSpinner) currentSpinner.stop();
1205
- const roleColor = ROLE_COLORS[message.role] || chalk9.white;
1206
- const icon = ROLE_ICONS[message.role] || "\u{1F916}";
1225
+ const role = message.role ?? "architect";
1226
+ const roleColor = ROLE_COLORS[role] || chalk9.white;
1227
+ const icon = ROLE_ICONS[role] || "\u{1F916}";
1207
1228
  console.log("");
1208
- console.log(roleColor.bold(`${icon} ${capitalize(message.role)}:`));
1209
- const formatted = formatResponse(message.content);
1229
+ console.log(roleColor.bold(`${icon} ${capitalize(role)}:`));
1230
+ const formatted = formatResponse(typeof message.content === "string" ? message.content : "");
1210
1231
  console.log(chalk9.gray(` ${formatted}`));
1211
1232
  console.log("");
1212
1233
  roundResponses.push(message);
1213
1234
  break;
1235
+ }
1214
1236
  case "round-complete":
1215
- const agreementCount = message.agreements || 0;
1216
- const totalMembers = message.totalMembers || roundResponses.length;
1237
+ const agreementCount = typeof message.agreements === "number" ? message.agreements : 0;
1238
+ const totalMembers = typeof message.totalMembers === "number" ? message.totalMembers : roundResponses.length;
1217
1239
  const agreementPercent = Math.round(agreementCount / totalMembers * 100);
1218
1240
  console.log(chalk9.gray(` Agreement: ${agreementCount}/${totalMembers} (${agreementPercent}%)`));
1219
1241
  console.log("");
package/dist/index.d.mts CHANGED
@@ -88,6 +88,51 @@ interface CreateTestCaseInput {
88
88
  interface UpdateTestCaseInput extends Partial<CreateTestCaseInput> {
89
89
  status?: TestCaseStatus;
90
90
  }
91
+ interface TestRunArtifact {
92
+ label?: string;
93
+ type?: string;
94
+ url: string;
95
+ }
96
+ interface TestRunSummaryInput {
97
+ projectId: string;
98
+ sprintId?: string;
99
+ suite: string;
100
+ framework?: string;
101
+ passCount: number;
102
+ failCount: number;
103
+ flakyCount?: number;
104
+ durationMs?: number;
105
+ commitSha?: string;
106
+ releaseTrainId?: string;
107
+ artifacts?: TestRunArtifact[];
108
+ }
109
+ interface TestRunRecord extends TestRunSummaryInput {
110
+ id: string;
111
+ createdAt: string;
112
+ }
113
+ interface CoverageFeatureBreakdown {
114
+ name: string;
115
+ coverage: number;
116
+ risk?: string;
117
+ }
118
+ interface CoverageInsightRequest {
119
+ projectId: string;
120
+ sprintId?: string;
121
+ linesPct: number;
122
+ branchesPct?: number;
123
+ statementsPct?: number;
124
+ functionsPct?: number;
125
+ features?: CoverageFeatureBreakdown[];
126
+ }
127
+ interface CoverageSuggestedTest {
128
+ title: string;
129
+ reason?: string;
130
+ }
131
+ interface CoverageInsight extends CoverageInsightRequest {
132
+ id: string;
133
+ createdAt: string;
134
+ suggestedTests?: CoverageSuggestedTest[] | null;
135
+ }
91
136
  interface ApiResponse<T> {
92
137
  data?: T;
93
138
  error?: string;
@@ -132,6 +177,7 @@ declare class CodmirClient {
132
177
  private readonly config;
133
178
  readonly tickets: TicketsAPI;
134
179
  readonly testCases: TestCasesAPI;
180
+ readonly testing: TestingAPI;
135
181
  constructor(config: CodmirClientConfig);
136
182
  /**
137
183
  * Make an HTTP request to the codmir API
@@ -216,5 +262,34 @@ declare class TestCasesAPI {
216
262
  */
217
263
  delete(projectId: string, testCaseId: string | number): Promise<void>;
218
264
  }
265
+ declare class TestingAPI {
266
+ private config;
267
+ constructor(config: Required<CodmirClientConfig>);
268
+ private request;
269
+ submitTestRun(payload: TestRunSummaryInput): Promise<{
270
+ run: TestRunRecord;
271
+ summary: {
272
+ framework: string;
273
+ passRate: number;
274
+ totalDurationMs: number;
275
+ };
276
+ }>;
277
+ listTestRuns(projectId: string, options?: {
278
+ limit?: number;
279
+ suite?: string;
280
+ }): Promise<TestRunRecord[]>;
281
+ requestCoverageInsight(payload: CoverageInsightRequest): Promise<{
282
+ report: CoverageInsight;
283
+ insights: {
284
+ coverageGauge: number;
285
+ featureBreakdown?: CoverageInsightRequest['features'];
286
+ suggestedTests: {
287
+ title: string;
288
+ reason?: string;
289
+ }[];
290
+ };
291
+ }>;
292
+ listCoverageInsights(projectId: string, limit?: number): Promise<CoverageInsight[]>;
293
+ }
219
294
 
220
- export { type ApiResponse, CodmirClient, type CodmirClientConfig, CodmirError, type CreateTestCaseInput, type CreateTicketInput, type PaginatedResponse, type TestCase, type TestCasePriority, type TestCaseStatus, type TestCaseStep, type TestCaseTemplate, type Ticket, type TicketPriority, type TicketStatus, type TicketType, type UpdateTestCaseInput, type UpdateTicketInput, type User };
295
+ export { type ApiResponse, CodmirClient, type CodmirClientConfig, CodmirError, type CoverageFeatureBreakdown, type CoverageInsight, type CoverageInsightRequest, type CoverageSuggestedTest, type CreateTestCaseInput, type CreateTicketInput, type PaginatedResponse, type TestCase, type TestCasePriority, type TestCaseStatus, type TestCaseStep, type TestCaseTemplate, type TestRunArtifact, type TestRunRecord, type TestRunSummaryInput, type Ticket, type TicketPriority, type TicketStatus, type TicketType, type UpdateTestCaseInput, type UpdateTicketInput, type User };
package/dist/index.d.ts CHANGED
@@ -88,6 +88,51 @@ interface CreateTestCaseInput {
88
88
  interface UpdateTestCaseInput extends Partial<CreateTestCaseInput> {
89
89
  status?: TestCaseStatus;
90
90
  }
91
+ interface TestRunArtifact {
92
+ label?: string;
93
+ type?: string;
94
+ url: string;
95
+ }
96
+ interface TestRunSummaryInput {
97
+ projectId: string;
98
+ sprintId?: string;
99
+ suite: string;
100
+ framework?: string;
101
+ passCount: number;
102
+ failCount: number;
103
+ flakyCount?: number;
104
+ durationMs?: number;
105
+ commitSha?: string;
106
+ releaseTrainId?: string;
107
+ artifacts?: TestRunArtifact[];
108
+ }
109
+ interface TestRunRecord extends TestRunSummaryInput {
110
+ id: string;
111
+ createdAt: string;
112
+ }
113
+ interface CoverageFeatureBreakdown {
114
+ name: string;
115
+ coverage: number;
116
+ risk?: string;
117
+ }
118
+ interface CoverageInsightRequest {
119
+ projectId: string;
120
+ sprintId?: string;
121
+ linesPct: number;
122
+ branchesPct?: number;
123
+ statementsPct?: number;
124
+ functionsPct?: number;
125
+ features?: CoverageFeatureBreakdown[];
126
+ }
127
+ interface CoverageSuggestedTest {
128
+ title: string;
129
+ reason?: string;
130
+ }
131
+ interface CoverageInsight extends CoverageInsightRequest {
132
+ id: string;
133
+ createdAt: string;
134
+ suggestedTests?: CoverageSuggestedTest[] | null;
135
+ }
91
136
  interface ApiResponse<T> {
92
137
  data?: T;
93
138
  error?: string;
@@ -132,6 +177,7 @@ declare class CodmirClient {
132
177
  private readonly config;
133
178
  readonly tickets: TicketsAPI;
134
179
  readonly testCases: TestCasesAPI;
180
+ readonly testing: TestingAPI;
135
181
  constructor(config: CodmirClientConfig);
136
182
  /**
137
183
  * Make an HTTP request to the codmir API
@@ -216,5 +262,34 @@ declare class TestCasesAPI {
216
262
  */
217
263
  delete(projectId: string, testCaseId: string | number): Promise<void>;
218
264
  }
265
+ declare class TestingAPI {
266
+ private config;
267
+ constructor(config: Required<CodmirClientConfig>);
268
+ private request;
269
+ submitTestRun(payload: TestRunSummaryInput): Promise<{
270
+ run: TestRunRecord;
271
+ summary: {
272
+ framework: string;
273
+ passRate: number;
274
+ totalDurationMs: number;
275
+ };
276
+ }>;
277
+ listTestRuns(projectId: string, options?: {
278
+ limit?: number;
279
+ suite?: string;
280
+ }): Promise<TestRunRecord[]>;
281
+ requestCoverageInsight(payload: CoverageInsightRequest): Promise<{
282
+ report: CoverageInsight;
283
+ insights: {
284
+ coverageGauge: number;
285
+ featureBreakdown?: CoverageInsightRequest['features'];
286
+ suggestedTests: {
287
+ title: string;
288
+ reason?: string;
289
+ }[];
290
+ };
291
+ }>;
292
+ listCoverageInsights(projectId: string, limit?: number): Promise<CoverageInsight[]>;
293
+ }
219
294
 
220
- export { type ApiResponse, CodmirClient, type CodmirClientConfig, CodmirError, type CreateTestCaseInput, type CreateTicketInput, type PaginatedResponse, type TestCase, type TestCasePriority, type TestCaseStatus, type TestCaseStep, type TestCaseTemplate, type Ticket, type TicketPriority, type TicketStatus, type TicketType, type UpdateTestCaseInput, type UpdateTicketInput, type User };
295
+ export { type ApiResponse, CodmirClient, type CodmirClientConfig, CodmirError, type CoverageFeatureBreakdown, type CoverageInsight, type CoverageInsightRequest, type CoverageSuggestedTest, type CreateTestCaseInput, type CreateTicketInput, type PaginatedResponse, type TestCase, type TestCasePriority, type TestCaseStatus, type TestCaseStep, type TestCaseTemplate, type TestRunArtifact, type TestRunRecord, type TestRunSummaryInput, type Ticket, type TicketPriority, type TicketStatus, type TicketType, type UpdateTestCaseInput, type UpdateTicketInput, type User };
package/dist/index.js CHANGED
@@ -35,6 +35,7 @@ var CodmirClient = class {
35
35
  };
36
36
  this.tickets = new TicketsAPI(this.config);
37
37
  this.testCases = new TestCasesAPI(this.config);
38
+ this.testing = new TestingAPI(this.config);
38
39
  }
39
40
  /**
40
41
  * Make an HTTP request to the codmir API
@@ -293,6 +294,75 @@ var TestCasesAPI = class {
293
294
  );
294
295
  }
295
296
  };
297
+ var TestingAPI = class {
298
+ constructor(config) {
299
+ this.config = config;
300
+ }
301
+ async request(method, path, body) {
302
+ const url = `${this.config.baseUrl}${path}`;
303
+ const headers = {
304
+ "Content-Type": "application/json",
305
+ ...this.config.headers
306
+ };
307
+ if (this.config.apiKey) {
308
+ headers["X-API-Key"] = this.config.apiKey;
309
+ }
310
+ const controller = new AbortController();
311
+ const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);
312
+ try {
313
+ const response = await fetch(url, {
314
+ method,
315
+ headers,
316
+ body: body ? JSON.stringify(body) : void 0,
317
+ signal: controller.signal
318
+ });
319
+ clearTimeout(timeoutId);
320
+ if (!response.ok) {
321
+ const errorData = await response.json().catch(() => ({}));
322
+ const error = new Error(errorData.error || `HTTP ${response.status}`);
323
+ error.statusCode = response.status;
324
+ error.response = errorData;
325
+ throw error;
326
+ }
327
+ if (response.status === 204) {
328
+ return {};
329
+ }
330
+ return await response.json();
331
+ } catch (error) {
332
+ clearTimeout(timeoutId);
333
+ if (error.name === "AbortError") {
334
+ const timeoutError = new Error("Request timeout");
335
+ timeoutError.statusCode = 408;
336
+ throw timeoutError;
337
+ }
338
+ throw error;
339
+ }
340
+ }
341
+ async submitTestRun(payload) {
342
+ return this.request("POST", "/api/testing/test-runs", payload);
343
+ }
344
+ async listTestRuns(projectId, options) {
345
+ const params = new URLSearchParams({ projectId });
346
+ if (options?.limit) params.set("limit", String(options.limit));
347
+ if (options?.suite) params.set("suite", options.suite);
348
+ const response = await this.request(
349
+ "GET",
350
+ `/api/testing/test-runs?${params.toString()}`
351
+ );
352
+ return response.runs || [];
353
+ }
354
+ async requestCoverageInsight(payload) {
355
+ return this.request("POST", "/api/testing/coverage-insight", payload);
356
+ }
357
+ async listCoverageInsights(projectId, limit = 5) {
358
+ const params = new URLSearchParams({ projectId, limit: String(limit) });
359
+ const response = await this.request(
360
+ "GET",
361
+ `/api/testing/coverage-insight?${params.toString()}`
362
+ );
363
+ return response.reports || [];
364
+ }
365
+ };
296
366
  // Annotate the CommonJS export names for ESM import in node:
297
367
  0 && (module.exports = {
298
368
  CodmirClient
package/dist/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  CodmirClient
3
- } from "./chunk-LXEEBTWT.mjs";
3
+ } from "./chunk-GU32P57R.mjs";
4
4
  import "./chunk-EBO3CZXG.mjs";
5
5
  export {
6
6
  CodmirClient