ccqa 1.14.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,14 +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";
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";
190
248
  neverRun: "neverRun";
191
- notEvaluated: "notEvaluated";
192
249
  }>;
250
+ driftLabel: z.ZodOptional<z.ZodEnum<{
251
+ TEST_DRIFT: "TEST_DRIFT";
252
+ SPEC_CHANGE: "SPEC_CHANGE";
253
+ }>>;
193
254
  reason: z.ZodOptional<z.ZodEnum<{
255
+ notEvaluated: "notEvaluated";
194
256
  noSelectionInRange: "noSelectionInRange";
195
257
  selectionUnknown: "selectionUnknown";
196
258
  noDeployLog: "noDeployLog";
@@ -199,6 +261,14 @@ declare const RerunReportSchema: z.ZodObject<{
199
261
  deployedShaNotInLog: "deployedShaNotInLog";
200
262
  gapInRange: "gapInRange";
201
263
  }>>;
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>>;
202
272
  lastRun: z.ZodNullable<z.ZodObject<{
203
273
  gitHead: z.ZodString;
204
274
  runId: z.ZodString;
@@ -820,7 +890,7 @@ interface HubClient {
820
890
  }): Promise<Record<string, LastGreenEntry>>;
821
891
  /**
822
892
  * Per spec of one project/profile: is its last result still trustworthy?
823
- * Answers `ccqa run --only-hub-stale`. 404 when the project has no
893
+ * Answers `ccqa run --only-hub-rerun-needed`. 404 when the project has no
824
894
  * perspectives document — there is then no spec registered to compare
825
895
  * against a deploy, which the caller must report rather than read as
826
896
  * "nothing to run".
@@ -828,6 +898,26 @@ interface HubClient {
828
898
  getRerun(project: string, q: {
829
899
  profile: string;
830
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>;
831
921
  /**
832
922
  * Every spec's last `ccqa audit --report-to-hub` result, keyed by "feature/spec". No
833
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.14.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.14.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": {