ccqa 1.15.0 → 1.16.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.
@@ -173,6 +173,51 @@ declare const DeployEntrySchema: z.ZodObject<{
173
173
  gapBefore: z.ZodDefault<z.ZodBoolean>;
174
174
  }, z.core.$strip>;
175
175
  type DeployEntry = z.infer<typeof DeployEntrySchema>;
176
+ /** Body of `POST /projects/:project/locks?profile=`. */
177
+ declare const AcquireLocksRequestSchema: z.ZodObject<{
178
+ specs: z.ZodArray<z.ZodString>;
179
+ kind: z.ZodEnum<{
180
+ run: "run";
181
+ audit: "audit";
182
+ }>;
183
+ holder: z.ZodString;
184
+ ttlSeconds: z.ZodNumber;
185
+ }, z.core.$strip>;
186
+ type AcquireLocksRequest = z.infer<typeof AcquireLocksRequestSchema>;
187
+ /**
188
+ * Which specs the caller may work on. `denied` is not an error: another job got
189
+ * there first, and skipping those is the whole point.
190
+ */
191
+ declare const AcquireLocksResponseSchema: z.ZodObject<{
192
+ granted: z.ZodArray<z.ZodString>;
193
+ denied: z.ZodArray<z.ZodString>;
194
+ }, z.core.$strip>;
195
+ type AcquireLocksResponse = z.infer<typeof AcquireLocksResponseSchema>;
196
+ /** Body of `GET /projects/:project/audit-needed?profile=`: one answer per spec. */
197
+ declare const AuditNeedReportSchema: z.ZodObject<{
198
+ project: z.ZodString;
199
+ profile: z.ZodString;
200
+ specs: z.ZodRecord<z.ZodString, z.ZodObject<{
201
+ because: z.ZodEnum<{
202
+ cannotTell: "cannotTell";
203
+ neverAudited: "neverAudited";
204
+ deployReached: "deployReached";
205
+ held: "held";
206
+ current: "current";
207
+ }>;
208
+ reason: z.ZodOptional<z.ZodEnum<{
209
+ notEvaluated: "notEvaluated";
210
+ noSelectionInRange: "noSelectionInRange";
211
+ selectionUnknown: "selectionUnknown";
212
+ noDeployLog: "noDeployLog";
213
+ unknownDeployedSha: "unknownDeployedSha";
214
+ ambiguousDeployedSha: "ambiguousDeployedSha";
215
+ deployedShaNotInLog: "deployedShaNotInLog";
216
+ gapInRange: "gapInRange";
217
+ }>>;
218
+ }, z.core.$strip>>;
219
+ }, z.core.$strip>;
220
+ type AuditNeedReport = z.infer<typeof AuditNeedReportSchema>;
176
221
  /** Body of `GET /projects/:project/rerun?profile=`: one verdict per spec in the perspectives document. */
177
222
  declare const RerunReportSchema: z.ZodObject<{
178
223
  project: z.ZodString;
@@ -183,15 +228,31 @@ declare const RerunReportSchema: z.ZodObject<{
183
228
  at: z.ZodString;
184
229
  }, z.core.$strip>>;
185
230
  specs: z.ZodRecord<z.ZodString, z.ZodObject<{
186
- state: z.ZodEnum<{
187
- unknown: "unknown";
188
- needed: "needed";
189
- notNeeded: "notNeeded";
190
- blocked: "blocked";
231
+ verdict: z.ZodEnum<{
232
+ inProgress: "inProgress";
233
+ needsRepair: "needsRepair";
234
+ rerunNeeded: "rerunNeeded";
235
+ verified: "verified";
236
+ unanswerable: "unanswerable";
237
+ }>;
238
+ audit: z.ZodEnum<{
239
+ due: "due";
240
+ clean: "clean";
241
+ drifted: "drifted";
242
+ undecided: "undecided";
243
+ cannotTell: "cannotTell";
244
+ }>;
245
+ execution: z.ZodEnum<{
246
+ passed: "passed";
247
+ failed: "failed";
191
248
  neverRun: "neverRun";
192
- notEvaluated: "notEvaluated";
193
249
  }>;
250
+ driftLabel: z.ZodOptional<z.ZodEnum<{
251
+ TEST_DRIFT: "TEST_DRIFT";
252
+ SPEC_CHANGE: "SPEC_CHANGE";
253
+ }>>;
194
254
  reason: z.ZodOptional<z.ZodEnum<{
255
+ notEvaluated: "notEvaluated";
195
256
  noSelectionInRange: "noSelectionInRange";
196
257
  selectionUnknown: "selectionUnknown";
197
258
  noDeployLog: "noDeployLog";
@@ -200,10 +261,14 @@ declare const RerunReportSchema: z.ZodObject<{
200
261
  deployedShaNotInLog: "deployedShaNotInLog";
201
262
  gapInRange: "gapInRange";
202
263
  }>>;
203
- blockedReason: z.ZodOptional<z.ZodEnum<{
204
- testDrift: "testDrift";
205
- specChange: "specChange";
206
- }>>;
264
+ heldBy: z.ZodNullable<z.ZodObject<{
265
+ kind: z.ZodEnum<{
266
+ run: "run";
267
+ audit: "audit";
268
+ }>;
269
+ holder: z.ZodString;
270
+ expiresAt: z.ZodString;
271
+ }, z.core.$strip>>;
207
272
  lastRun: z.ZodNullable<z.ZodObject<{
208
273
  gitHead: z.ZodString;
209
274
  runId: z.ZodString;
@@ -833,6 +898,26 @@ interface HubClient {
833
898
  getRerun(project: string, q: {
834
899
  profile: string;
835
900
  }): Promise<RerunReport>;
901
+ /**
902
+ * Per spec of one project/profile: has a deploy landed on the code it covers
903
+ * since the audit last read it? Answers `ccqa audit
904
+ * --only-hub-audit-needed`. 404 on a project with no perspectives document,
905
+ * for the same reason `getRerun` does.
906
+ */
907
+ getAuditNeed(project: string, q: {
908
+ profile: string;
909
+ }): Promise<AuditNeedReport>;
910
+ /**
911
+ * Take the specs that are free, so a second job does not start on one this
912
+ * run is already working. `denied` is part of the answer, not an error.
913
+ */
914
+ acquireLocks(project: string, q: {
915
+ profile: string;
916
+ }, body: AcquireLocksRequest): Promise<AcquireLocksResponse>;
917
+ /** Drop everything `runId` holds. Safe to call when it holds nothing. */
918
+ releaseLocks(project: string, q: {
919
+ profile: string;
920
+ }, holder: string): Promise<void>;
836
921
  /**
837
922
  * Every spec's last `ccqa audit --report-to-hub` result, keyed by "feature/spec". No
838
923
  * profile — drift asks whether a spec still describes the code, not
@@ -168,6 +168,23 @@ function createHubClient(opts) {
168
168
  getRerun(project, q) {
169
169
  return json(`/api/v1/projects/${encodeURIComponent(project)}/rerun?${queryString({ profile: q.profile })}`);
170
170
  },
171
+ acquireLocks(project, q, body) {
172
+ return json(`${locksPath(project)}?${queryString({ profile: q.profile })}`, {
173
+ method: "POST",
174
+ headers: { "Content-Type": "application/json" },
175
+ body: JSON.stringify(body)
176
+ });
177
+ },
178
+ async releaseLocks(project, q, holder) {
179
+ await request(`${locksPath(project)}?${queryString({ profile: q.profile })}`, {
180
+ method: "DELETE",
181
+ headers: { "Content-Type": "application/json" },
182
+ body: JSON.stringify({ holder })
183
+ });
184
+ },
185
+ getAuditNeed(project, q) {
186
+ return json(`/api/v1/projects/${encodeURIComponent(project)}/audit-needed?${queryString({ profile: q.profile })}`);
187
+ },
171
188
  getDriftLedger(project) {
172
189
  return json(`/api/v1/projects/${encodeURIComponent(project)}/drift`);
173
190
  },
@@ -269,6 +286,9 @@ function promptsPath(project) {
269
286
  function deploysPath(project) {
270
287
  return `/api/v1/projects/${encodeURIComponent(project)}/deploys`;
271
288
  }
289
+ function locksPath(project) {
290
+ return `/api/v1/projects/${encodeURIComponent(project)}/locks`;
291
+ }
272
292
  /** Perspectives are one document per project: `/api/v1/projects/<project>/perspectives`. */
273
293
  function perspectivesPath(project) {
274
294
  return `/api/v1/projects/${encodeURIComponent(project)}/perspectives`;
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ccqa",
3
- "version": "1.15.0",
3
+ "version": "1.16.0",
4
4
  "type": "module",
5
5
  "description": "Browser test recorder powered by Claude Code and agent-browser",
6
6
  "repository": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ccqa",
3
- "version": "1.15.0",
3
+ "version": "1.16.0",
4
4
  "type": "module",
5
5
  "description": "Browser test recorder powered by Claude Code and agent-browser",
6
6
  "repository": {