@camox/api-contract 0.58.1 → 0.59.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.
package/dist/threads.d.ts CHANGED
@@ -34,6 +34,19 @@ export declare const BRIEF_ENTRY = "camox.brief";
34
34
  * it at the end of the conversation; editors never see it, since the draft's card says so.
35
35
  */
36
36
  export declare const DRAFT_ENDED_ENTRY = "camox.draft-ended";
37
+ /**
38
+ * The kind of the transcript entry recording a member's push to the draft's code from their own
39
+ * checkout (ADR 0026), with a `pushDataSchema` as data. The model reads it as context, never
40
+ * answering it, and editors see who pushed, their commits, and whether they built.
41
+ */
42
+ export declare const PUSH_ENTRY = "camox.push";
43
+ /** How a pushed head's build ended: built, built with type errors, or built but not previewed. */
44
+ export declare const pushOutcomeSchema: z.ZodEnum<{
45
+ built: "built";
46
+ typeErrors: "typeErrors";
47
+ notPreviewed: "notPreviewed";
48
+ }>;
49
+ export type PushOutcome = z.infer<typeof pushOutcomeSchema>;
37
50
  /**
38
51
  * The agent's tool on Live handing a request off to a draft it starts (ADR 0025). A run whose
39
52
  * call of it went through ends on the draft's card.
@@ -80,6 +93,21 @@ export declare const threadSenderSchema: z.ZodObject<{
80
93
  export type ThreadSender = z.infer<typeof threadSenderSchema>;
81
94
  /** Whether `data` names a sender. */
82
95
  export declare const isSender: (data: unknown) => data is ThreadSender;
96
+ /** What a push's entry records: who pushed, their commits' subjects, oldest first, and the build. */
97
+ export declare const pushDataSchema: z.ZodObject<{
98
+ pusher: z.ZodObject<{
99
+ id: z.ZodString;
100
+ name: z.ZodString;
101
+ image: z.ZodNullable<z.ZodString>;
102
+ }, z.core.$strip>;
103
+ subjects: z.ZodArray<z.ZodString>;
104
+ outcome: z.ZodEnum<{
105
+ built: "built";
106
+ typeErrors: "typeErrors";
107
+ notPreviewed: "notPreviewed";
108
+ }>;
109
+ }, z.core.$strip>;
110
+ export type PushData = z.infer<typeof pushDataSchema>;
83
111
  /**
84
112
  * What an editor's message entry records: who sent it, the operation id it was sent with, and for
85
113
  * a message sent on Live as the agent handed the request off, the draft it went to with it.
@@ -233,7 +261,19 @@ export type ThreadMessage = {
233
261
  id: string;
234
262
  from: "draft";
235
263
  ended?: DraftOutcome;
236
- } & StartedDraftCard);
264
+ } & StartedDraftCard) |
265
+ /**
266
+ * A member's push to the draft's code from their own checkout: who pushed, their commits'
267
+ * subjects, oldest first, and how the pushed head built. It's no turn: the agent doesn't
268
+ * answer it.
269
+ */
270
+ {
271
+ id: string;
272
+ from: "push";
273
+ sender: ThreadSender;
274
+ subjects: string[];
275
+ outcome: PushOutcome;
276
+ };
237
277
  /** Everything the studio shows for a thread. */
238
278
  export type ThreadView = {
239
279
  messages: readonly ThreadMessage[];
@@ -305,6 +345,10 @@ type ThreadStep = {
305
345
  type: "build";
306
346
  status: BuildStatus;
307
347
  } |
348
+ /** A member's push, between turns. */
349
+ ({
350
+ type: "push";
351
+ } & PushData) |
308
352
  /**
309
353
  * The end of the turn sent the agent back to work, after its answer: the answer wasn't the
310
354
  * turn's last, and what the agent was told is never shown.
@@ -368,8 +412,7 @@ export type ThreadServerMessage =
368
412
  };
369
413
  /**
370
414
  * The code a thread closes its sockets with once it ended with its draft, and for good: it's
371
- * deleted, so reconnecting reaches nothing. A development draft, which stays open, gets a new
372
- * thread the next time the studio connects.
415
+ * deleted, so reconnecting reaches nothing.
373
416
  */
374
417
  export declare const THREAD_ENDED_CLOSE_CODE = 4000;
375
418
  /** The text of a message's content: its text parts, joined. */
package/dist/threads.js CHANGED
@@ -33,6 +33,18 @@ const BRIEF_ENTRY = "camox.brief";
33
33
  */
34
34
  const DRAFT_ENDED_ENTRY = "camox.draft-ended";
35
35
  /**
36
+ * The kind of the transcript entry recording a member's push to the draft's code from their own
37
+ * checkout (ADR 0026), with a `pushDataSchema` as data. The model reads it as context, never
38
+ * answering it, and editors see who pushed, their commits, and whether they built.
39
+ */
40
+ const PUSH_ENTRY = "camox.push";
41
+ /** How a pushed head's build ended: built, built with type errors, or built but not previewed. */
42
+ const pushOutcomeSchema = z.enum([
43
+ "built",
44
+ "typeErrors",
45
+ "notPreviewed"
46
+ ]);
47
+ /**
36
48
  * The agent's tool on Live handing a request off to a draft it starts (ADR 0025). A run whose
37
49
  * call of it went through ends on the draft's card.
38
50
  */
@@ -53,6 +65,12 @@ const threadSenderSchema = z.object({
53
65
  });
54
66
  /** Whether `data` names a sender. */
55
67
  const isSender = (data) => threadSenderSchema.safeParse(data).success;
68
+ /** What a push's entry records: who pushed, their commits' subjects, oldest first, and the build. */
69
+ const pushDataSchema = z.object({
70
+ pusher: threadSenderSchema,
71
+ subjects: z.array(z.string()),
72
+ outcome: pushOutcomeSchema
73
+ });
56
74
  /**
57
75
  * What an editor's message entry records: who sent it, the operation id it was sent with, and for
58
76
  * a message sent on Live as the agent handed the request off, the draft it went to with it.
@@ -134,8 +152,7 @@ const threadClientMessageSchema = z.discriminatedUnion("type", [
134
152
  ]);
135
153
  /**
136
154
  * The code a thread closes its sockets with once it ended with its draft, and for good: it's
137
- * deleted, so reconnecting reaches nothing. A development draft, which stays open, gets a new
138
- * thread the next time the studio connects.
155
+ * deleted, so reconnecting reaches nothing.
139
156
  */
140
157
  const THREAD_ENDED_CLOSE_CODE = 4e3;
141
158
  /** The text of a message's content: its text parts, joined. */
@@ -184,6 +201,14 @@ function threadStepOf(entry) {
184
201
  };
185
202
  }
186
203
  if (entry.kind === "camox.draft-ended") return void 0;
204
+ if (entry.kind === "camox.push") {
205
+ const push = pushDataSchema.safeParse(entry.data).data;
206
+ return push && {
207
+ id,
208
+ type: "push",
209
+ ...push
210
+ };
211
+ }
187
212
  const message = entry.model?.find((candidate) => candidate.role !== "system");
188
213
  if (!message) return void 0;
189
214
  if (message.role === "user") {
@@ -338,6 +363,15 @@ function threadViewOf({ steps, running, toolCalls = [], callingTools = false, dr
338
363
  case "build":
339
364
  status = step.status;
340
365
  break;
366
+ case "push":
367
+ messages.push({
368
+ id: step.id,
369
+ from: "push",
370
+ sender: step.pusher,
371
+ subjects: step.subjects,
372
+ outcome: step.outcome
373
+ });
374
+ break;
341
375
  case "tools":
342
376
  unfinished = false;
343
377
  break;
@@ -418,4 +452,4 @@ function reduceThreadFrame(state, frame) {
418
452
  }
419
453
 
420
454
  //#endregion
421
- export { BRIEF_ENTRY, BUILD_STATUS_ENTRY, DRAFT_ENDED_ENTRY, EDITOR_MESSAGE_ENTRY, EMPTY_THREAD_STATE, EMPTY_THREAD_VIEW, RECONCILE_ENTRY, RUN_STOPPED_ENTRY, START_DRAFT_TOOL, THREAD_ENDED_CLOSE_CODE, buildStatusDataSchema, buildStatusSchema, editorMessageDataSchema, isSender, reconcileDataSchema, reduceThreadEvents, reduceThreadFrame, reduceThreadState, startedDraftCardSchema, startedDraftSchema, textOf, threadClientMessageSchema, threadSenderSchema, threadViewOf, touchKindSchema, touchSchema, touchedBatchSchema };
455
+ export { BRIEF_ENTRY, BUILD_STATUS_ENTRY, DRAFT_ENDED_ENTRY, EDITOR_MESSAGE_ENTRY, EMPTY_THREAD_STATE, EMPTY_THREAD_VIEW, PUSH_ENTRY, RECONCILE_ENTRY, RUN_STOPPED_ENTRY, START_DRAFT_TOOL, THREAD_ENDED_CLOSE_CODE, buildStatusDataSchema, buildStatusSchema, editorMessageDataSchema, isSender, pushDataSchema, pushOutcomeSchema, reconcileDataSchema, reduceThreadEvents, reduceThreadFrame, reduceThreadState, startedDraftCardSchema, startedDraftSchema, textOf, threadClientMessageSchema, threadSenderSchema, threadViewOf, touchKindSchema, touchSchema, touchedBatchSchema };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camox/api-contract",
3
- "version": "0.58.1",
3
+ "version": "0.59.0",
4
4
  "license": "MIT",
5
5
  "files": [
6
6
  "src",
package/src/drafts.ts CHANGED
@@ -31,25 +31,10 @@ export const PUBLISHING_DRAFT_VAR = "CAMOX_PUBLISHING_DRAFT";
31
31
  */
32
32
  export const DRAFT_CREATE_HEADER = "x-camox-draft-create";
33
33
 
34
- /**
35
- * The `x-camox-draft` value naming the caller's own development draft in the project a request
36
- * acts on (ADR 0006, ADR 0011). Dev mode and the CLI always send it.
37
- */
38
- export const DEVELOPMENT_DRAFT = "development";
39
-
40
- /**
41
- * oRPC error code for a request naming the development draft before dev mode created it: the
42
- * first dev-mode sync after login does, so the site has to run locally once first.
43
- */
44
- export const NO_DEVELOPMENT_DRAFT_ERROR = "NO_DEVELOPMENT_DRAFT";
45
-
46
34
  /** URL search param carrying the current draft's id in the studio and the rendered site. */
47
35
  export const DRAFT_SEARCH_PARAM = "camox-draft";
48
36
 
49
- /** A regular draft is a named set of edits; a development draft backs a dev server. */
50
- export type DraftKind = "regular" | "development";
51
-
52
- /** How a regular draft ended. */
37
+ /** How a draft ended. */
53
38
  export type DraftOutcome = "published" | "deleted";
54
39
 
55
40
  /** Who ended a draft, how and when, from its ended-drafts record (ADR 0009, ADR 0011). */
@@ -140,7 +125,7 @@ export const LIVE_READ_ONLY_ERROR = "LIVE_READ_ONLY";
140
125
  // for one on Live. Every procedure is listed, so a new one fails the type check until it's
141
126
  // classified and can't be forgotten. Procedures that only fill a generated value (ADR 0012),
142
127
  // like `generateSummary`, write no content. A synced block's shared content is written through
143
- // `blocks` and `repeatableItems`. Releases and dev-mode sync aren't listed.
128
+ // `blocks` and `repeatableItems`. Releases aren't listed.
144
129
  const BLOCK_WRITES: Record<keyof Router["blocks"], boolean> = {
145
130
  get: false,
146
131
  getPageMarkdown: false,
@@ -223,7 +208,7 @@ const LOCALE_WRITES: Record<keyof Router["locales"], boolean> = {
223
208
  addBack: true,
224
209
  };
225
210
 
226
- // `definitions` is absent: its sync is a release or a dev sync, never a studio content write.
211
+ // `definitions` is absent: its sync is a release, never a studio content write.
227
212
  const CONTENT_WRITES: Partial<Record<keyof Router, Record<string, boolean>>> = {
228
213
  blocks: BLOCK_WRITES,
229
214
  locales: LOCALE_WRITES,
package/src/projects.ts CHANGED
@@ -42,8 +42,12 @@ export const projectSlugSchema = /* @__PURE__ */ z
42
42
  "Use lowercase letters, digits and hyphens, without a hyphen at either end",
43
43
  );
44
44
 
45
- /** The address a project's website is served at: its Project Slug's `camox.site` subdomain. */
46
- export const projectWebsiteUrl = (slug: string) => `https://${slug}.camox.site`;
45
+ /**
46
+ * The address a project's website is served at: its Custom Domain when it has one, else its
47
+ * Project Slug's `camox.site` subdomain, which then redirects to it (ADR 0028).
48
+ */
49
+ export const projectWebsiteUrl = (project: { slug: string; customDomain: string | null }) =>
50
+ `https://${project.customDomain ?? `${project.slug}.camox.site`}`;
47
51
 
48
52
  /** Why a slug can't be given to a new project. */
49
53
  export type UnavailableSlugReason = "invalid" | "reserved" | "taken";
package/src/threads.ts CHANGED
@@ -45,6 +45,17 @@ export const BRIEF_ENTRY = "camox.brief";
45
45
  */
46
46
  export const DRAFT_ENDED_ENTRY = "camox.draft-ended";
47
47
 
48
+ /**
49
+ * The kind of the transcript entry recording a member's push to the draft's code from their own
50
+ * checkout (ADR 0026), with a `pushDataSchema` as data. The model reads it as context, never
51
+ * answering it, and editors see who pushed, their commits, and whether they built.
52
+ */
53
+ export const PUSH_ENTRY = "camox.push";
54
+
55
+ /** How a pushed head's build ended: built, built with type errors, or built but not previewed. */
56
+ export const pushOutcomeSchema = z.enum(["built", "typeErrors", "notPreviewed"]);
57
+ export type PushOutcome = z.infer<typeof pushOutcomeSchema>;
58
+
48
59
  /**
49
60
  * The agent's tool on Live handing a request off to a draft it starts (ADR 0025). A run whose
50
61
  * call of it went through ends on the draft's card.
@@ -85,6 +96,14 @@ export type ThreadSender = z.infer<typeof threadSenderSchema>;
85
96
  export const isSender = (data: unknown): data is ThreadSender =>
86
97
  threadSenderSchema.safeParse(data).success;
87
98
 
99
+ /** What a push's entry records: who pushed, their commits' subjects, oldest first, and the build. */
100
+ export const pushDataSchema = z.object({
101
+ pusher: threadSenderSchema,
102
+ subjects: z.array(z.string()),
103
+ outcome: pushOutcomeSchema,
104
+ });
105
+ export type PushData = z.infer<typeof pushDataSchema>;
106
+
88
107
  /**
89
108
  * What an editor's message entry records: who sent it, the operation id it was sent with, and for
90
109
  * a message sent on Live as the agent handed the request off, the draft it went to with it.
@@ -166,7 +185,13 @@ export type ThreadMessage =
166
185
  * the draft's card, with its current name, which opens it. Once the draft ended, it has its
167
186
  * last name and how it ended, and opens nothing. The turn is finished.
168
187
  */
169
- | ({ id: string; from: "draft"; ended?: DraftOutcome } & StartedDraftCard);
188
+ | ({ id: string; from: "draft"; ended?: DraftOutcome } & StartedDraftCard)
189
+ /**
190
+ * A member's push to the draft's code from their own checkout: who pushed, their commits'
191
+ * subjects, oldest first, and how the pushed head built. It's no turn: the agent doesn't
192
+ * answer it.
193
+ */
194
+ | { id: string; from: "push"; sender: ThreadSender; subjects: string[]; outcome: PushOutcome };
170
195
 
171
196
  /** Everything the studio shows for a thread. */
172
197
  export type ThreadView = {
@@ -226,6 +251,8 @@ type ThreadStep = { id: string } & (
226
251
  | ({ type: "draft" } & StartedDraftCard)
227
252
  /** Where the build of the turn's code stands, as the turn ends. */
228
253
  | { type: "build"; status: BuildStatus }
254
+ /** A member's push, between turns. */
255
+ | ({ type: "push" } & PushData)
229
256
  /**
230
257
  * The end of the turn sent the agent back to work, after its answer: the answer wasn't the
231
258
  * turn's last, and what the agent was told is never shown.
@@ -275,8 +302,7 @@ export type ThreadServerMessage =
275
302
 
276
303
  /**
277
304
  * The code a thread closes its sockets with once it ended with its draft, and for good: it's
278
- * deleted, so reconnecting reaches nothing. A development draft, which stays open, gets a new
279
- * thread the next time the studio connects.
305
+ * deleted, so reconnecting reaches nothing.
280
306
  */
281
307
  export const THREAD_ENDED_CLOSE_CODE = 4000;
282
308
 
@@ -315,6 +341,10 @@ function threadStepOf(entry: EntryRecord): ThreadStep | undefined {
315
341
  }
316
342
  // Only the model reads it: as a user message, it would otherwise read as Pi continuing a run.
317
343
  if (entry.kind === DRAFT_ENDED_ENTRY) return undefined;
344
+ if (entry.kind === PUSH_ENTRY) {
345
+ const push = pushDataSchema.safeParse(entry.data).data;
346
+ return push && { id, type: "push", ...push };
347
+ }
318
348
  const message = entry.model?.find((candidate) => candidate.role !== "system");
319
349
  if (!message) return undefined;
320
350
  if (message.role === "user") {
@@ -462,6 +492,16 @@ export function threadViewOf({
462
492
  case "build":
463
493
  status = step.status;
464
494
  break;
495
+ case "push":
496
+ // Pushes land between turns: one doesn't end a turn, nor start one.
497
+ messages.push({
498
+ id: step.id,
499
+ from: "push",
500
+ sender: step.pusher,
501
+ subjects: step.subjects,
502
+ outcome: step.outcome,
503
+ });
504
+ break;
465
505
  case "tools":
466
506
  unfinished = false;
467
507
  break;