ccqa 1.8.3 → 1.9.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.
@@ -55,6 +55,12 @@ declare const RunSchema: z.ZodObject<{
55
55
  runUrl: z.ZodOptional<z.ZodNullable<z.ZodString>>;
56
56
  reportCreatedAt: z.ZodString;
57
57
  createdAt: z.ZodString;
58
+ deployedSha: z.ZodOptional<z.ZodNullable<z.ZodString>>;
59
+ deployedShaSource: z.ZodOptional<z.ZodNullable<z.ZodEnum<{
60
+ "hub-deploy-log": "hub-deploy-log";
61
+ client: "client";
62
+ }>>>;
63
+ deployedShaAmbiguous: z.ZodOptional<z.ZodBoolean>;
58
64
  }, z.core.$strip>;
59
65
  type Run = z.infer<typeof RunSchema>;
60
66
  /**
@@ -143,6 +149,100 @@ declare const LastGreenEntrySchema: z.ZodObject<{
143
149
  at: z.ZodString;
144
150
  }, z.core.$strip>;
145
151
  type LastGreenEntry = z.infer<typeof LastGreenEntrySchema>;
152
+ /** One deploy, as the consumer's deploy job reported it (ADR-0010). */
153
+ declare const DeployEntrySchema: z.ZodObject<{
154
+ index: z.ZodNumber;
155
+ sha: z.ZodString;
156
+ previousSha: z.ZodNullable<z.ZodString>;
157
+ at: z.ZodString;
158
+ ref: z.ZodOptional<z.ZodString>;
159
+ runUrl: z.ZodOptional<z.ZodString>;
160
+ changedPaths: z.ZodNullable<z.ZodArray<z.ZodString>>;
161
+ truncated: z.ZodDefault<z.ZodBoolean>;
162
+ gapBefore: z.ZodDefault<z.ZodBoolean>;
163
+ }, z.core.$strip>;
164
+ type DeployEntry = z.infer<typeof DeployEntrySchema>;
165
+ /** Body of `GET /projects/:project/rerun?profile=`: one verdict per spec in the perspectives document. */
166
+ declare const RerunReportSchema: z.ZodObject<{
167
+ project: z.ZodString;
168
+ profile: z.ZodString;
169
+ deployHead: z.ZodNullable<z.ZodObject<{
170
+ index: z.ZodNumber;
171
+ sha: z.ZodString;
172
+ at: z.ZodString;
173
+ }, z.core.$strip>>;
174
+ specs: z.ZodRecord<z.ZodString, z.ZodObject<{
175
+ state: z.ZodEnum<{
176
+ unknown: "unknown";
177
+ needed: "needed";
178
+ notNeeded: "notNeeded";
179
+ neverRun: "neverRun";
180
+ notEvaluated: "notEvaluated";
181
+ }>;
182
+ reason: z.ZodOptional<z.ZodEnum<{
183
+ noRelatedPaths: "noRelatedPaths";
184
+ noDeployLog: "noDeployLog";
185
+ unknownDeployedSha: "unknownDeployedSha";
186
+ ambiguousDeployedSha: "ambiguousDeployedSha";
187
+ deployedShaNotInLog: "deployedShaNotInLog";
188
+ gapInRange: "gapInRange";
189
+ truncatedInRange: "truncatedInRange";
190
+ }>>;
191
+ lastRun: z.ZodNullable<z.ZodObject<{
192
+ gitHead: z.ZodString;
193
+ runId: z.ZodString;
194
+ at: z.ZodString;
195
+ deployedSha: z.ZodOptional<z.ZodNullable<z.ZodString>>;
196
+ deployedShaAmbiguous: z.ZodOptional<z.ZodBoolean>;
197
+ }, z.core.$strip>>;
198
+ lastGreen: z.ZodNullable<z.ZodObject<{
199
+ gitHead: z.ZodString;
200
+ runId: z.ZodString;
201
+ at: z.ZodString;
202
+ deployedSha: z.ZodOptional<z.ZodNullable<z.ZodString>>;
203
+ deployedShaAmbiguous: z.ZodOptional<z.ZodBoolean>;
204
+ }, z.core.$strip>>;
205
+ lastRed: z.ZodNullable<z.ZodObject<{
206
+ gitHead: z.ZodString;
207
+ runId: z.ZodString;
208
+ at: z.ZodString;
209
+ deployedSha: z.ZodOptional<z.ZodNullable<z.ZodString>>;
210
+ deployedShaAmbiguous: z.ZodOptional<z.ZodBoolean>;
211
+ }, z.core.$strip>>;
212
+ touchedBy: z.ZodOptional<z.ZodArray<z.ZodString>>;
213
+ touchedByDeploy: z.ZodOptional<z.ZodNullable<z.ZodObject<{
214
+ index: z.ZodNumber;
215
+ sha: z.ZodString;
216
+ at: z.ZodString;
217
+ }, z.core.$strip>>>;
218
+ }, z.core.$strip>>;
219
+ }, z.core.$strip>;
220
+ type RerunReport = z.infer<typeof RerunReportSchema>;
221
+ /** Body of `POST /projects/:project/deploys?profile=` — what the deploy job shipped. */
222
+ declare const RecordDeployRequestSchema: z.ZodObject<{
223
+ sha: z.ZodString;
224
+ previousSha: z.ZodOptional<z.ZodNullable<z.ZodString>>;
225
+ changedPaths: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodString>>>;
226
+ ref: z.ZodOptional<z.ZodString>;
227
+ runUrl: z.ZodOptional<z.ZodString>;
228
+ }, z.core.$strip>;
229
+ type RecordDeployRequest = z.infer<typeof RecordDeployRequestSchema>;
230
+ /** Body of `GET /projects/:project/deploys?profile=` — newest last, as stored. */
231
+ declare const DeployLogResponseSchema: z.ZodObject<{
232
+ entries: z.ZodArray<z.ZodObject<{
233
+ index: z.ZodNumber;
234
+ sha: z.ZodString;
235
+ previousSha: z.ZodNullable<z.ZodString>;
236
+ at: z.ZodString;
237
+ ref: z.ZodOptional<z.ZodString>;
238
+ runUrl: z.ZodOptional<z.ZodString>;
239
+ changedPaths: z.ZodNullable<z.ZodArray<z.ZodString>>;
240
+ truncated: z.ZodDefault<z.ZodBoolean>;
241
+ gapBefore: z.ZodDefault<z.ZodBoolean>;
242
+ }, z.core.$strip>>;
243
+ nextIndex: z.ZodNumber;
244
+ }, z.core.$strip>;
245
+ type DeployLogResponse = z.infer<typeof DeployLogResponseSchema>;
146
246
  //#endregion
147
247
  //#region src/prompts/prompt-names.d.ts
148
248
  /**
@@ -337,6 +437,7 @@ declare const RunReportDataSchema: z.ZodObject<{
337
437
  promptVersion: z.ZodString;
338
438
  customPromptVersion: z.ZodDefault<z.ZodNullable<z.ZodString>>;
339
439
  triageUserPromptHash: z.ZodOptional<z.ZodString>;
440
+ deployedSha: z.ZodOptional<z.ZodString>;
340
441
  results: z.ZodArray<z.ZodObject<{
341
442
  feature: z.ZodString;
342
443
  spec: z.ZodString;
@@ -568,12 +669,20 @@ interface HubPromptMeta {
568
669
  meta: Record<string, unknown>;
569
670
  }
570
671
  interface HubClient {
571
- /** Push a report directory (as a tar.gz) for an already-finished `ccqa run`. */
672
+ /**
673
+ * Push a report directory (as a tar.gz) for an already-finished `ccqa run`.
674
+ *
675
+ * `deployedSha` asserts the commit the environment was running *when the run
676
+ * started*. Without it the hub falls back to its deploy-log head, which by
677
+ * push time is the head after the run — a deploy that landed mid-run would
678
+ * then read as that run's baseline.
679
+ */
572
680
  pushRun(archive: Uint8Array, meta: {
573
681
  project: string;
574
682
  branch?: string;
575
683
  profile?: string;
576
684
  kind?: "run" | "drift";
685
+ deployedSha?: string;
577
686
  }): Promise<Run>;
578
687
  /**
579
688
  * Open a `running` run to push results into incrementally. Returns the new
@@ -581,6 +690,10 @@ interface HubClient {
581
690
  * would leave a second open run); callers degrade to local-only on failure.
582
691
  * `gitHead` stamps the run's commit at open time, so even a run that dies
583
692
  * before its final reconcile patch is attributable to a commit.
693
+ *
694
+ * `deployedSha` does the same for the environment's commit. The hub would
695
+ * otherwise read its own deploy-log head here, and the open happens after
696
+ * the deterministic phase, not before the first spec.
584
697
  */
585
698
  openRun(meta: {
586
699
  project: string;
@@ -588,6 +701,7 @@ interface HubClient {
588
701
  profile?: string;
589
702
  kind?: "run" | "drift";
590
703
  gitHead?: string;
704
+ deployedSha?: string;
591
705
  /** CI run id (GITHUB_RUN_ID) and its run URL, stamped at open time so an
592
706
  * interrupted incremental run still links back to its CI run. */
593
707
  ciRunId?: string;
@@ -628,6 +742,22 @@ interface HubClient {
628
742
  branch: string;
629
743
  fallbackBranch?: string;
630
744
  }): Promise<Record<string, LastGreenEntry>>;
745
+ /**
746
+ * Per spec of one project/profile: is its last result still trustworthy?
747
+ * Answers `ccqa run --changed=last-run`. 404 when the project has no
748
+ * perspectives document — there is then no `relatedPaths` to match a deploy
749
+ * against, which the caller must report rather than read as "nothing to run".
750
+ */
751
+ getRerun(project: string, q: {
752
+ profile: string;
753
+ }): Promise<RerunReport>;
754
+ /** Tell the hub what a deploy shipped (`ccqa hub deploy record`). */
755
+ recordDeploy(project: string, profile: string, body: RecordDeployRequest): Promise<DeployEntry>;
756
+ /** The profile's retained deploy log, oldest first; `limit` keeps the newest N. */
757
+ getDeployLog(project: string, q: {
758
+ profile: string;
759
+ limit?: number;
760
+ }): Promise<DeployLogResponse>;
631
761
  putSession(project: string, profile: string, name: string, storageState: unknown): Promise<void>;
632
762
  getSession(project: string, profile: string, name: string): Promise<unknown>;
633
763
  listSessions(project: string, profile: string): Promise<{
@@ -98,6 +98,7 @@ function createHubClient(opts) {
98
98
  if (meta.branch) params.set("branch", meta.branch);
99
99
  if (meta.profile) params.set("profile", meta.profile);
100
100
  if (meta.kind) params.set("kind", meta.kind);
101
+ if (meta.deployedSha) params.set("deployedSha", meta.deployedSha);
101
102
  return json(`/api/v1/runs?${params}`, {
102
103
  method: "POST",
103
104
  headers: { "Content-Type": "application/gzip" },
@@ -110,6 +111,7 @@ function createHubClient(opts) {
110
111
  if (meta.profile) params.set("profile", meta.profile);
111
112
  if (meta.kind) params.set("kind", meta.kind);
112
113
  if (meta.gitHead) params.set("gitHead", meta.gitHead);
114
+ if (meta.deployedSha) params.set("deployedSha", meta.deployedSha);
113
115
  if (meta.ciRunId) params.set("ciRunId", meta.ciRunId);
114
116
  if (meta.runUrl) params.set("runUrl", meta.runUrl);
115
117
  return json(`/api/v1/runs/open?${params}`, { method: "POST" });
@@ -163,6 +165,22 @@ function createHubClient(opts) {
163
165
  const { entries } = await json(`/api/v1/projects/${encodeURIComponent(project)}/last-green?${params}`);
164
166
  return entries;
165
167
  },
168
+ getRerun(project, q) {
169
+ return json(`/api/v1/projects/${encodeURIComponent(project)}/rerun?${queryString({ profile: q.profile })}`);
170
+ },
171
+ recordDeploy(project, profile, body) {
172
+ return json(`${deploysPath(project)}?${queryString({ profile })}`, {
173
+ method: "POST",
174
+ headers: { "Content-Type": "application/json" },
175
+ body: JSON.stringify(body)
176
+ });
177
+ },
178
+ getDeployLog(project, q) {
179
+ return json(`${deploysPath(project)}?${queryString({
180
+ profile: q.profile,
181
+ limit: q.limit
182
+ })}`);
183
+ },
166
184
  async listProjects() {
167
185
  const { projects } = await json("/api/v1/projects");
168
186
  return projects;
@@ -244,6 +262,10 @@ function scopePath(project, kind, profile) {
244
262
  function promptsPath(project) {
245
263
  return `/api/v1/projects/${encodeURIComponent(project)}/prompts`;
246
264
  }
265
+ /** The deploy log is per project, selected by a `?profile=` query param: `/api/v1/projects/<project>/deploys`. */
266
+ function deploysPath(project) {
267
+ return `/api/v1/projects/${encodeURIComponent(project)}/deploys`;
268
+ }
247
269
  /** Perspectives are one document per project: `/api/v1/projects/<project>/perspectives`. */
248
270
  function perspectivesPath(project) {
249
271
  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.8.3",
3
+ "version": "1.9.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.8.3",
3
+ "version": "1.9.0",
4
4
  "type": "module",
5
5
  "description": "Browser test recorder powered by Claude Code and agent-browser",
6
6
  "repository": {