@camox/api-contract 0.72.0 → 0.75.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/claim-links.d.ts +17 -0
- package/dist/claim-links.js +17 -0
- package/dist/drafts.d.ts +7 -32
- package/dist/drafts.js +94 -110
- package/dist/query-keys.d.ts +3 -0
- package/dist/query-keys.js +1 -0
- package/dist/router.d.ts +1517 -347
- package/dist/{patrol.d.ts → specialists.d.ts} +34 -30
- package/dist/{patrol.js → specialists.js} +20 -11
- package/dist/threads.d.ts +51 -6
- package/dist/threads.js +44 -8
- package/package.json +8 -4
- package/src/claim-links.ts +23 -0
- package/src/drafts.ts +11 -37
- package/src/query-keys.ts +5 -1
- package/src/{patrol.ts → specialists.ts} +40 -31
- package/src/threads.ts +57 -6
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
//#region src/
|
|
1
|
+
//#region src/specialists.d.ts
|
|
2
2
|
/**
|
|
3
|
-
* The
|
|
3
|
+
* The Specialists (ADR 0024): every specialist of a project, the work each did as reports, as the
|
|
4
4
|
* studio shows it at the top of the Agent Sidebar. The API reads it for one scope, a draft or
|
|
5
5
|
* Live, and names each report's subject, so the studio needs no entity loaded to show it.
|
|
6
6
|
*/
|
|
7
|
-
/** Every
|
|
8
|
-
export declare const
|
|
9
|
-
/** A
|
|
10
|
-
export type
|
|
7
|
+
/** Every specialist's stable id. The registry in the API lists them all. */
|
|
8
|
+
export declare const SPECIALIST_IDS: readonly ["translator", "seoManager", "linkChecker"];
|
|
9
|
+
/** A specialist's stable id. */
|
|
10
|
+
export type SpecialistId = (typeof SPECIALIST_IDS)[number];
|
|
11
11
|
/**
|
|
12
12
|
* What a structured report says was done. Each has a failed form, by the report's outcome. A
|
|
13
13
|
* merge with Live's localization reads as a translation.
|
|
@@ -15,7 +15,7 @@ export type PatrollerId = (typeof PATROLLER_IDS)[number];
|
|
|
15
15
|
export type ReportVerb = "translated" | "mergedWithLive" | "wroteSeo" | "describedFile" | "publishedCatchUp" | "removedLink" | "fixedLink";
|
|
16
16
|
/** What a report can be about. */
|
|
17
17
|
export type ReportEntity = "page" | "block" | "sharedContent" | "repeatableItem" | "record" | "file";
|
|
18
|
-
/** A report's subject, named as the Canvas names it, read when the
|
|
18
|
+
/** A report's subject, named as the Canvas names it, read when the Specialists is. */
|
|
19
19
|
export type ReportSubject = {
|
|
20
20
|
entity: ReportEntity;
|
|
21
21
|
id: string;
|
|
@@ -44,10 +44,10 @@ export declare const reportLocale: (summary: {
|
|
|
44
44
|
/** Whether the work was done, or failed. A failure shows in its report only. */
|
|
45
45
|
export type ReportOutcome = "done" | "failed";
|
|
46
46
|
/**
|
|
47
|
-
* Where a
|
|
48
|
-
* publish
|
|
47
|
+
* Where a specialist is on duty, in drafts or on Live: it works as you go, or is off there (ADR
|
|
48
|
+
* 0034). None checks when you publish: publishing never waits on Camox (ADR 0043).
|
|
49
49
|
*/
|
|
50
|
-
export type
|
|
50
|
+
export type SpecialistDuty = "asYouGo" | "off";
|
|
51
51
|
/**
|
|
52
52
|
* Where the studio shows a report's subject: a page on the Canvas, with the block and repeatable
|
|
53
53
|
* item to select on it, a collection record, or a file.
|
|
@@ -66,7 +66,7 @@ export type ReportPlace = {
|
|
|
66
66
|
fileId: string;
|
|
67
67
|
};
|
|
68
68
|
export type ReportView = {
|
|
69
|
-
/** Unique among the
|
|
69
|
+
/** Unique among the specialist's reports in the view. */
|
|
70
70
|
id: string;
|
|
71
71
|
summary: ReportSummary;
|
|
72
72
|
outcome: ReportOutcome;
|
|
@@ -84,6 +84,7 @@ export type ReportView = {
|
|
|
84
84
|
* What a finding is about (ADR 0034), by its kind:
|
|
85
85
|
* - `missingPage`: a link to a page that doesn't exist, the page's name as it was last known.
|
|
86
86
|
* - `brokenLink`: an external link that failed, and how.
|
|
87
|
+
* - `missingMetaTitle`: a page whose meta title is written by hand, and empty.
|
|
87
88
|
* A link's `url` is as content stores it: a page link's is `camox:page:<id>`, and `text` is what
|
|
88
89
|
* the link reads.
|
|
89
90
|
*/
|
|
@@ -97,6 +98,8 @@ export type FindingAbout = {
|
|
|
97
98
|
url: string;
|
|
98
99
|
text: string;
|
|
99
100
|
failure: LinkFailure;
|
|
101
|
+
} | {
|
|
102
|
+
kind: "missingMetaTitle";
|
|
100
103
|
};
|
|
101
104
|
/** How a link failed: an HTTP error status, no connection (DNS included), or no answer in time. */
|
|
102
105
|
export type LinkFailure = {
|
|
@@ -129,14 +132,17 @@ export type FindingView = {
|
|
|
129
132
|
fieldKind: string | null;
|
|
130
133
|
/** When it was first raised, in milliseconds since the epoch. */
|
|
131
134
|
raisedAt: number;
|
|
132
|
-
/**
|
|
135
|
+
/**
|
|
136
|
+
* Whether it's Live's. A draft shows Live's findings on the content it still holds, and fixes
|
|
137
|
+
* them there.
|
|
138
|
+
*/
|
|
133
139
|
live: boolean;
|
|
134
140
|
/** Where its content shows, as for reports. */
|
|
135
141
|
place: ReportPlace | null;
|
|
136
142
|
};
|
|
137
143
|
/**
|
|
138
144
|
* A finding as one sentence, as the studio, emails, Briefs and refusals word it: "“About us” in
|
|
139
|
-
* Footer links to About, a page that no longer exists".
|
|
145
|
+
* Footer links to About, a page that no longer exists", or "Pricing has no meta title".
|
|
140
146
|
*/
|
|
141
147
|
export declare function findingSentence(finding: Pick<FindingView, "about" | "subject">): string;
|
|
142
148
|
/**
|
|
@@ -159,27 +165,27 @@ export type DismissalView = {
|
|
|
159
165
|
export type ApplyResult = {
|
|
160
166
|
applied: boolean;
|
|
161
167
|
};
|
|
162
|
-
/** How many subjects a
|
|
168
|
+
/** How many subjects a specialist is on in one locale, a locale's tag. */
|
|
163
169
|
export type LocaleCount = {
|
|
164
170
|
locale: string;
|
|
165
171
|
count: number;
|
|
166
172
|
};
|
|
167
173
|
/**
|
|
168
|
-
* What a
|
|
174
|
+
* What a specialist is on: the one subject when there's one, and how many subjects in each
|
|
169
175
|
* locale, the most first. A subject in several locales counts in each.
|
|
170
176
|
*/
|
|
171
|
-
export type
|
|
177
|
+
export type SpecialistWorking = {
|
|
172
178
|
subject: ReportSubject | null;
|
|
173
179
|
locales: LocaleCount[];
|
|
174
180
|
};
|
|
175
|
-
export type
|
|
176
|
-
id:
|
|
181
|
+
export type SpecialistView = {
|
|
182
|
+
id: SpecialistId;
|
|
177
183
|
/** Its role, as editors know it: "Translator", "SEO manager". */
|
|
178
184
|
role: string;
|
|
179
185
|
/** Its duty in the scope viewed. Off there, it still has its reports. */
|
|
180
|
-
duty:
|
|
186
|
+
duty: SpecialistDuty;
|
|
181
187
|
/** Null when it isn't working in the scope. */
|
|
182
|
-
working:
|
|
188
|
+
working: SpecialistWorking | null;
|
|
183
189
|
/**
|
|
184
190
|
* When it last finished a check in the scope, whether it found anything or not, or null when it
|
|
185
191
|
* never checked there.
|
|
@@ -202,17 +208,15 @@ export type PatrollerView = {
|
|
|
202
208
|
/** The project's dismissals of its findings, the newest first. */
|
|
203
209
|
dismissals: DismissalView[];
|
|
204
210
|
};
|
|
211
|
+
/** Every specialist of the registry, the latest activity first; never-worked ones last. */
|
|
212
|
+
export type SpecialistsView = {
|
|
213
|
+
specialists: SpecialistView[];
|
|
214
|
+
};
|
|
205
215
|
/**
|
|
206
|
-
*
|
|
207
|
-
*
|
|
216
|
+
* URL search param the studio opens a specialist's findings from, by its id, as the email about
|
|
217
|
+
* Live's new findings links to them. The studio drops it once opened.
|
|
208
218
|
*/
|
|
209
|
-
export
|
|
210
|
-
|
|
211
|
-
patrolDraft: {
|
|
212
|
-
id: string;
|
|
213
|
-
name: string | null;
|
|
214
|
-
} | null;
|
|
215
|
-
};
|
|
216
|
-
/** How many reports the Patrol shows of each patroller; the rest are counted. */
|
|
219
|
+
export declare const SPECIALIST_SEARCH_PARAM = "camox-specialist";
|
|
220
|
+
/** How many reports the Specialists shows of each specialist; the rest are counted. */
|
|
217
221
|
export declare const REPORTS_SHOWN = 5;
|
|
218
222
|
//#endregion
|
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
//#region src/
|
|
1
|
+
//#region src/specialists.ts
|
|
2
2
|
/**
|
|
3
|
-
* The
|
|
3
|
+
* The Specialists (ADR 0024): every specialist of a project, the work each did as reports, as the
|
|
4
4
|
* studio shows it at the top of the Agent Sidebar. The API reads it for one scope, a draft or
|
|
5
5
|
* Live, and names each report's subject, so the studio needs no entity loaded to show it.
|
|
6
6
|
*/
|
|
7
|
-
/** Every
|
|
8
|
-
const
|
|
7
|
+
/** Every specialist's stable id. The registry in the API lists them all. */
|
|
8
|
+
const SPECIALIST_IDS = [
|
|
9
9
|
"translator",
|
|
10
10
|
"seoManager",
|
|
11
11
|
"linkChecker"
|
|
12
12
|
];
|
|
13
13
|
/** The locale a summary's work was in: a structured summary's, if any. A text summary has none. */
|
|
14
14
|
const reportLocale = (summary) => summary.kind === "structured" ? summary.locale : null;
|
|
15
|
-
/** What a finding is about, after where it is: "links to About, a page that no longer exists". */
|
|
16
|
-
function
|
|
15
|
+
/** What a link finding is about, after where it is: "links to About, a page that no longer exists". */
|
|
16
|
+
function linkSentence(about) {
|
|
17
17
|
switch (about.kind) {
|
|
18
18
|
case "missingPage": return about.page === null ? "links to a page that no longer exists" : `links to ${about.page}, a page that no longer exists`;
|
|
19
19
|
case "brokenLink": {
|
|
@@ -25,20 +25,29 @@ function aboutSentence(about) {
|
|
|
25
25
|
}
|
|
26
26
|
/**
|
|
27
27
|
* A finding as one sentence, as the studio, emails, Briefs and refusals word it: "“About us” in
|
|
28
|
-
* Footer links to About, a page that no longer exists".
|
|
28
|
+
* Footer links to About, a page that no longer exists", or "Pricing has no meta title".
|
|
29
29
|
*/
|
|
30
30
|
function findingSentence(finding) {
|
|
31
|
-
|
|
31
|
+
const { about, subject } = finding;
|
|
32
|
+
if (about.kind === "missingMetaTitle") return `${subject.name} has no meta title`;
|
|
33
|
+
return `“${about.text}” in ${subject.name} ${linkSentence(about)}`;
|
|
32
34
|
}
|
|
33
35
|
/**
|
|
34
36
|
* A finding as one sentence where its content is already shown, as the studio's sidebar shows it
|
|
35
37
|
* by its field: "“About us” links to About, a page that no longer exists".
|
|
36
38
|
*/
|
|
37
39
|
function findingSentenceInPlace(finding) {
|
|
38
|
-
|
|
40
|
+
const { about } = finding;
|
|
41
|
+
if (about.kind === "missingMetaTitle") return "The page has no meta title";
|
|
42
|
+
return `“${about.text}” ${linkSentence(about)}`;
|
|
39
43
|
}
|
|
40
|
-
/**
|
|
44
|
+
/**
|
|
45
|
+
* URL search param the studio opens a specialist's findings from, by its id, as the email about
|
|
46
|
+
* Live's new findings links to them. The studio drops it once opened.
|
|
47
|
+
*/
|
|
48
|
+
const SPECIALIST_SEARCH_PARAM = "camox-specialist";
|
|
49
|
+
/** How many reports the Specialists shows of each specialist; the rest are counted. */
|
|
41
50
|
const REPORTS_SHOWN = 5;
|
|
42
51
|
|
|
43
52
|
//#endregion
|
|
44
|
-
export {
|
|
53
|
+
export { REPORTS_SHOWN, SPECIALIST_IDS, SPECIALIST_SEARCH_PARAM, findingSentence, findingSentenceInPlace, reportLocale };
|
package/dist/threads.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { DraftOutcome } from "./drafts.js";
|
|
2
2
|
import { z } from "zod";
|
|
3
|
-
import { AgentEvent } from "@earendil-works/pi-durable";
|
|
4
3
|
import { Message } from "@earendil-works/pi-ai";
|
|
4
|
+
import { AgentEvent } from "@earendil-works/pi-durable";
|
|
5
5
|
//#region src/threads.d.ts
|
|
6
6
|
/**
|
|
7
7
|
* The kind of the transcript entry recording an editor's message, with its sender and the
|
|
@@ -35,8 +35,7 @@ export declare const RECONCILE_ENTRY = "camox.reconcile";
|
|
|
35
35
|
/**
|
|
36
36
|
* The kind of the transcript entry opening a draft's thread a Live thread handed a request off
|
|
37
37
|
* to: the Brief, which the model reads ahead of the editor's messages, and editors see collapsed
|
|
38
|
-
* after them, so the request reads on as they sent it.
|
|
39
|
-
* too, with their `operationId` as data, and start the agent's run, which acts for Camox.
|
|
38
|
+
* after them, so the request reads on as they sent it.
|
|
40
39
|
*/
|
|
41
40
|
export declare const BRIEF_ENTRY = "camox.brief";
|
|
42
41
|
/**
|
|
@@ -109,6 +108,30 @@ export declare const codeRequestDataSchema: z.ZodObject<{
|
|
|
109
108
|
reconciling: z.ZodOptional<z.ZodBoolean>;
|
|
110
109
|
}, z.core.$strip>;
|
|
111
110
|
export type CodeRequestData = z.infer<typeof codeRequestDataSchema>;
|
|
111
|
+
/**
|
|
112
|
+
* The draft thread's agent's tool asking the Connected Agents following its turn questions, which
|
|
113
|
+
* their waiting calls come back with as the agent works on (ADR 0042). The model calls it itself,
|
|
114
|
+
* never from a script.
|
|
115
|
+
*/
|
|
116
|
+
export declare const ASK_TOOL = "askConnectedAgent";
|
|
117
|
+
/**
|
|
118
|
+
* The kind of the transcript entry recording questions the agent asked the Connected Agents
|
|
119
|
+
* following its turn, with a `questionsDataSchema` as data. Neither the model nor editors read
|
|
120
|
+
* it: questions are never a thread's messages, and never end its turn.
|
|
121
|
+
*/
|
|
122
|
+
export declare const QUESTIONS_ENTRY = "camox.questions";
|
|
123
|
+
/**
|
|
124
|
+
* What a questions entry records: the questions, in the order the agent asked them, and the
|
|
125
|
+
* Connected Agents they were asked of, each by its member's id and client id.
|
|
126
|
+
*/
|
|
127
|
+
export declare const questionsDataSchema: z.ZodObject<{
|
|
128
|
+
questions: z.ZodArray<z.ZodString>;
|
|
129
|
+
to: z.ZodArray<z.ZodObject<{
|
|
130
|
+
memberId: z.ZodString;
|
|
131
|
+
clientId: z.ZodString;
|
|
132
|
+
}, z.core.$strip>>;
|
|
133
|
+
}, z.core.$strip>;
|
|
134
|
+
export type QuestionsData = z.infer<typeof questionsDataSchema>;
|
|
112
135
|
/** Whether `name` is a tool handing work to an agent of its own (`HANDING_OFF_TOOLS`). */
|
|
113
136
|
export declare const handsOff: (name: string) => boolean;
|
|
114
137
|
/**
|
|
@@ -167,9 +190,17 @@ export declare const connectedAgentClientSchema: z.ZodObject<{
|
|
|
167
190
|
verified: z.ZodBoolean;
|
|
168
191
|
}, z.core.$strip>;
|
|
169
192
|
export type ConnectedAgentClient = z.infer<typeof connectedAgentClientSchema>;
|
|
193
|
+
/** An Attachment a Connected Agent's message carries: an image the agent sees with it. */
|
|
194
|
+
export declare const messageAttachmentSchema: z.ZodObject<{
|
|
195
|
+
id: z.ZodString;
|
|
196
|
+
filename: z.ZodString;
|
|
197
|
+
mimeType: z.ZodString;
|
|
198
|
+
url: z.ZodString;
|
|
199
|
+
}, z.core.$strip>;
|
|
200
|
+
export type MessageAttachmentData = z.infer<typeof messageAttachmentSchema>;
|
|
170
201
|
/**
|
|
171
|
-
* What a Connected Agent's message entry records: the member it acts as, its client,
|
|
172
|
-
* operation id it was sent with.
|
|
202
|
+
* What a Connected Agent's message entry records: the member it acts as, its client, the
|
|
203
|
+
* operation id it was sent with, and whether it answers the agent's questions (ADR 0042).
|
|
173
204
|
*/
|
|
174
205
|
export declare const connectedAgentMessageDataSchema: z.ZodObject<{
|
|
175
206
|
member: z.ZodObject<{
|
|
@@ -182,6 +213,13 @@ export declare const connectedAgentMessageDataSchema: z.ZodObject<{
|
|
|
182
213
|
verified: z.ZodBoolean;
|
|
183
214
|
}, z.core.$strip>;
|
|
184
215
|
operationId: z.ZodOptional<z.ZodString>;
|
|
216
|
+
answer: z.ZodOptional<z.ZodBoolean>;
|
|
217
|
+
attachments: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
218
|
+
id: z.ZodString;
|
|
219
|
+
filename: z.ZodString;
|
|
220
|
+
mimeType: z.ZodString;
|
|
221
|
+
url: z.ZodString;
|
|
222
|
+
}, z.core.$strip>>>;
|
|
185
223
|
}, z.core.$strip>;
|
|
186
224
|
export type ConnectedAgentMessageData = z.infer<typeof connectedAgentMessageDataSchema>;
|
|
187
225
|
/** What a push's entry records: who pushed, their commits' subjects, oldest first, and the build. */
|
|
@@ -315,7 +353,9 @@ export type ThreadMessage = {
|
|
|
315
353
|
} |
|
|
316
354
|
/**
|
|
317
355
|
* A member's Connected Agent's message: the member's own AI, in its client, writing as itself.
|
|
318
|
-
* Never shown as the member's own words.
|
|
356
|
+
* Never shown as the member's own words. An answer to the agent's questions shows as the
|
|
357
|
+
* context the draft was built on, collapsed, as a Brief does, rather than as a request
|
|
358
|
+
* (ADR 0042).
|
|
319
359
|
*/
|
|
320
360
|
{
|
|
321
361
|
id: string;
|
|
@@ -323,6 +363,9 @@ export type ThreadMessage = {
|
|
|
323
363
|
member: ThreadSender;
|
|
324
364
|
client: ConnectedAgentClient;
|
|
325
365
|
text: string;
|
|
366
|
+
answer: boolean;
|
|
367
|
+
/** The images it carries for the agent to see, if any (ADR 0044). */
|
|
368
|
+
attachments?: MessageAttachmentData[];
|
|
326
369
|
} |
|
|
327
370
|
/** Camox's own message, starting a turn it began itself: why it did. */
|
|
328
371
|
{
|
|
@@ -474,6 +517,8 @@ type ThreadStep = {
|
|
|
474
517
|
member: ThreadSender;
|
|
475
518
|
client: ConnectedAgentClient;
|
|
476
519
|
text: string;
|
|
520
|
+
answer: boolean;
|
|
521
|
+
attachments?: MessageAttachmentData[];
|
|
477
522
|
} |
|
|
478
523
|
/** Camox starting a turn of its own, saying why. */
|
|
479
524
|
{
|
package/dist/threads.js
CHANGED
|
@@ -33,8 +33,7 @@ const RECONCILE_ENTRY = "camox.reconcile";
|
|
|
33
33
|
/**
|
|
34
34
|
* The kind of the transcript entry opening a draft's thread a Live thread handed a request off
|
|
35
35
|
* to: the Brief, which the model reads ahead of the editor's messages, and editors see collapsed
|
|
36
|
-
* after them, so the request reads on as they sent it.
|
|
37
|
-
* too, with their `operationId` as data, and start the agent's run, which acts for Camox.
|
|
36
|
+
* after them, so the request reads on as they sent it.
|
|
38
37
|
*/
|
|
39
38
|
const BRIEF_ENTRY = "camox.brief";
|
|
40
39
|
/**
|
|
@@ -101,6 +100,29 @@ const CODE_REQUEST_ENTRY = "camox.code-request";
|
|
|
101
100
|
/** What a Code Agent's request records: as an Artifact Agent's, and whether Camox reconciles. */
|
|
102
101
|
const codeRequestDataSchema = artifactRequestDataSchema.extend({ reconciling: z.boolean().optional() });
|
|
103
102
|
/**
|
|
103
|
+
* The draft thread's agent's tool asking the Connected Agents following its turn questions, which
|
|
104
|
+
* their waiting calls come back with as the agent works on (ADR 0042). The model calls it itself,
|
|
105
|
+
* never from a script.
|
|
106
|
+
*/
|
|
107
|
+
const ASK_TOOL = "askConnectedAgent";
|
|
108
|
+
/**
|
|
109
|
+
* The kind of the transcript entry recording questions the agent asked the Connected Agents
|
|
110
|
+
* following its turn, with a `questionsDataSchema` as data. Neither the model nor editors read
|
|
111
|
+
* it: questions are never a thread's messages, and never end its turn.
|
|
112
|
+
*/
|
|
113
|
+
const QUESTIONS_ENTRY = "camox.questions";
|
|
114
|
+
/**
|
|
115
|
+
* What a questions entry records: the questions, in the order the agent asked them, and the
|
|
116
|
+
* Connected Agents they were asked of, each by its member's id and client id.
|
|
117
|
+
*/
|
|
118
|
+
const questionsDataSchema = z.object({
|
|
119
|
+
questions: z.array(z.string()).min(1),
|
|
120
|
+
to: z.array(z.object({
|
|
121
|
+
memberId: z.string(),
|
|
122
|
+
clientId: z.string()
|
|
123
|
+
}))
|
|
124
|
+
});
|
|
125
|
+
/**
|
|
104
126
|
* The agent's tools handing work to an agent of its own, in a conversation beside the thread's,
|
|
105
127
|
* whose answer they return: editors see what that agent does as the agent's.
|
|
106
128
|
*/
|
|
@@ -160,14 +182,24 @@ const connectedAgentClientSchema = z.object({
|
|
|
160
182
|
name: z.string(),
|
|
161
183
|
verified: z.boolean()
|
|
162
184
|
});
|
|
185
|
+
/** An Attachment a Connected Agent's message carries: an image the agent sees with it. */
|
|
186
|
+
const messageAttachmentSchema = z.object({
|
|
187
|
+
id: z.string(),
|
|
188
|
+
filename: z.string(),
|
|
189
|
+
mimeType: z.string(),
|
|
190
|
+
url: z.string()
|
|
191
|
+
});
|
|
163
192
|
/**
|
|
164
|
-
* What a Connected Agent's message entry records: the member it acts as, its client,
|
|
165
|
-
* operation id it was sent with.
|
|
193
|
+
* What a Connected Agent's message entry records: the member it acts as, its client, the
|
|
194
|
+
* operation id it was sent with, and whether it answers the agent's questions (ADR 0042).
|
|
166
195
|
*/
|
|
167
196
|
const connectedAgentMessageDataSchema = z.object({
|
|
168
197
|
member: threadSenderSchema,
|
|
169
198
|
client: connectedAgentClientSchema,
|
|
170
|
-
operationId: z.string().optional()
|
|
199
|
+
operationId: z.string().optional(),
|
|
200
|
+
answer: z.boolean().optional(),
|
|
201
|
+
/** The images the message carries for the agent to see, as studios list them (ADR 0044). */
|
|
202
|
+
attachments: z.array(messageAttachmentSchema).optional()
|
|
171
203
|
});
|
|
172
204
|
/** What a push's entry records: who pushed, their commits' subjects, oldest first, and the build. */
|
|
173
205
|
const pushDataSchema = z.object({
|
|
@@ -395,7 +427,9 @@ function threadStepOf(entry) {
|
|
|
395
427
|
name: data.client.name,
|
|
396
428
|
verified: data.client.verified
|
|
397
429
|
},
|
|
398
|
-
text: editorTextOf(message.content)
|
|
430
|
+
text: editorTextOf(message.content),
|
|
431
|
+
answer: data.answer ?? false,
|
|
432
|
+
...data.attachments?.length && { attachments: data.attachments }
|
|
399
433
|
};
|
|
400
434
|
}
|
|
401
435
|
if (entry.kind === "camox.brief") return {
|
|
@@ -500,7 +534,9 @@ function threadViewOf({ steps, running, toolCalls = [], callingTools = false, ch
|
|
|
500
534
|
from: "connectedAgent",
|
|
501
535
|
member: step.member,
|
|
502
536
|
client: step.client,
|
|
503
|
-
text: step.text
|
|
537
|
+
text: step.text,
|
|
538
|
+
answer: step.answer,
|
|
539
|
+
...step.attachments && { attachments: step.attachments }
|
|
504
540
|
});
|
|
505
541
|
waiting = step.id;
|
|
506
542
|
break;
|
|
@@ -736,4 +772,4 @@ function reduceThreadFrame(state, frame) {
|
|
|
736
772
|
}
|
|
737
773
|
|
|
738
774
|
//#endregion
|
|
739
|
-
export { ARTIFACT_REQUEST_ENTRY, ARTIFACT_TOOL, BRIEF_ENTRY, BUILD_STATUS_ENTRY, BUILD_TOOL, CHANGING_TOOLS, CODE_REQUEST_ENTRY, CODE_TOOL, CONNECTED_AGENT_MESSAGE_ENTRY, DRAFT_CARD_ENTRY, DRAFT_ENDED_ENTRY, EDITOR_MESSAGE_ENTRY, EMPTY_THREAD_STATE, EMPTY_THREAD_VIEW, LOOK_TOOL, PUSH_ENTRY, RECONCILE_ENTRY, RUN_STOPPED_ENTRY, START_DRAFT_TOOL, THREAD_ENDED_CLOSE_CODE, agentActivitySchema, artifactRequestDataSchema, buildStatusDataSchema, buildStatusSchema, codeRequestDataSchema, connectedAgentClientSchema, connectedAgentMessageDataSchema, editorMessageDataSchema, editorSelectionSchema, editorTextOf, editorWhereSchema, handOffDetailsSchema, handsOff, isSender, pushDataSchema, pushOutcomeSchema, reconcileDataSchema, reduceThreadEvents, reduceThreadFrame, reduceThreadState, startedDraftCardSchema, startedDraftSchema, textOf, threadClientMessageSchema, threadSenderSchema, threadViewOf, touchKindSchema, touchSchema, touchedBatchSchema };
|
|
775
|
+
export { ARTIFACT_REQUEST_ENTRY, ARTIFACT_TOOL, ASK_TOOL, BRIEF_ENTRY, BUILD_STATUS_ENTRY, BUILD_TOOL, CHANGING_TOOLS, CODE_REQUEST_ENTRY, CODE_TOOL, CONNECTED_AGENT_MESSAGE_ENTRY, DRAFT_CARD_ENTRY, DRAFT_ENDED_ENTRY, EDITOR_MESSAGE_ENTRY, EMPTY_THREAD_STATE, EMPTY_THREAD_VIEW, LOOK_TOOL, PUSH_ENTRY, QUESTIONS_ENTRY, RECONCILE_ENTRY, RUN_STOPPED_ENTRY, START_DRAFT_TOOL, THREAD_ENDED_CLOSE_CODE, agentActivitySchema, artifactRequestDataSchema, buildStatusDataSchema, buildStatusSchema, codeRequestDataSchema, connectedAgentClientSchema, connectedAgentMessageDataSchema, editorMessageDataSchema, editorSelectionSchema, editorTextOf, editorWhereSchema, handOffDetailsSchema, handsOff, isSender, messageAttachmentSchema, pushDataSchema, pushOutcomeSchema, questionsDataSchema, 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.
|
|
3
|
+
"version": "0.75.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"files": [
|
|
6
6
|
"src",
|
|
@@ -44,9 +44,9 @@
|
|
|
44
44
|
"types": "./dist/locales.d.ts",
|
|
45
45
|
"default": "./dist/locales.js"
|
|
46
46
|
},
|
|
47
|
-
"./
|
|
48
|
-
"types": "./dist/
|
|
49
|
-
"default": "./dist/
|
|
47
|
+
"./specialists": {
|
|
48
|
+
"types": "./dist/specialists.d.ts",
|
|
49
|
+
"default": "./dist/specialists.js"
|
|
50
50
|
},
|
|
51
51
|
"./router": {
|
|
52
52
|
"types": "./dist/router.d.ts",
|
|
@@ -55,6 +55,10 @@
|
|
|
55
55
|
"./layout-routes": {
|
|
56
56
|
"types": "./dist/layout-routes.d.ts",
|
|
57
57
|
"default": "./dist/layout-routes.js"
|
|
58
|
+
},
|
|
59
|
+
"./claim-links": {
|
|
60
|
+
"types": "./dist/claim-links.d.ts",
|
|
61
|
+
"default": "./dist/claim-links.js"
|
|
58
62
|
}
|
|
59
63
|
},
|
|
60
64
|
"dependencies": {
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { projectWebsiteUrl } from "./projects";
|
|
2
|
+
|
|
3
|
+
/** URL search param carrying a Claim Link's token on the website it links to. */
|
|
4
|
+
export const CLAIM_LINK_SEARCH_PARAM = "camox-claim";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Where a Claim Link stands: `open` until it's claimed, revoked by an operator, or blocked, when a
|
|
8
|
+
* claim was refused because someone who isn't an operator joined its organization (ADR 0041).
|
|
9
|
+
*/
|
|
10
|
+
export type ClaimLinkState = "open" | "claimed" | "revoked" | "blocked";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* A Claim Link: the project's address, its Custom Domain if it has one, else its `camox.site`
|
|
14
|
+
* subdomain, with the link's token.
|
|
15
|
+
*/
|
|
16
|
+
export function claimLinkUrl(
|
|
17
|
+
project: { slug: string; customDomain: string | null },
|
|
18
|
+
token: string,
|
|
19
|
+
) {
|
|
20
|
+
const url = new URL("/", projectWebsiteUrl(project));
|
|
21
|
+
url.searchParams.set(CLAIM_LINK_SEARCH_PARAM, token);
|
|
22
|
+
return url.toString();
|
|
23
|
+
}
|
package/src/drafts.ts
CHANGED
|
@@ -164,12 +164,6 @@ export type EndedDraft = {
|
|
|
164
164
|
*/
|
|
165
165
|
export const DRAFT_ENDED_ERROR_CODE = "DRAFT_ENDED";
|
|
166
166
|
|
|
167
|
-
/**
|
|
168
|
-
* oRPC error code for a publish whose token no longer matches Live: Live changed since the
|
|
169
|
-
* preview, so nothing was applied and the caller reviews the new preview.
|
|
170
|
-
*/
|
|
171
|
-
export const CONFLICTS_CHANGED_ERROR = "CONFLICTS_CHANGED";
|
|
172
|
-
|
|
173
167
|
/**
|
|
174
168
|
* oRPC error code for a publish of a draft with code whose revision isn't the one the review
|
|
175
169
|
* showed: the agent left a newer one, or the draft is already publishing. The caller reviews
|
|
@@ -179,15 +173,16 @@ export const REVISION_CHANGED_ERROR = "REVISION_CHANGED";
|
|
|
179
173
|
|
|
180
174
|
/**
|
|
181
175
|
* Why a publish with code went back to the review instead of landing: the agent left a revision
|
|
182
|
-
* after the one the review showed,
|
|
183
|
-
*
|
|
184
|
-
*
|
|
185
|
-
*
|
|
176
|
+
* after the one the review showed, the draft got a blocker, Live's code moved and the draft's
|
|
177
|
+
* merge of it clashed (the "doesn't merge with Live's" blocker, which Camox's turn fixes), Live's
|
|
178
|
+
* code moved and the draft took too long to merge it, or the publish failed on Camox's side.
|
|
179
|
+
* `conflictsChanged` is only stored by publishes before ADR 0043, which aborted when Live changed.
|
|
186
180
|
*/
|
|
187
181
|
export const PUBLISH_ABORT_REASONS = [
|
|
188
182
|
"revisionChanged",
|
|
189
183
|
"conflictsChanged",
|
|
190
184
|
"blocked",
|
|
185
|
+
"codeDoesNotBuild",
|
|
191
186
|
"codeDoesNotMerge",
|
|
192
187
|
"liveCodeMoved",
|
|
193
188
|
"failed",
|
|
@@ -198,36 +193,13 @@ export type PublishAbortReason = (typeof PUBLISH_ABORT_REASONS)[number];
|
|
|
198
193
|
/** oRPC error code for a publish refused because the draft still has blockers. */
|
|
199
194
|
export const PUBLISH_BLOCKED_ERROR = "PUBLISH_BLOCKED";
|
|
200
195
|
|
|
201
|
-
/**
|
|
202
|
-
* oRPC error code for a publish refused because the draft still has pending translations: every
|
|
203
|
-
* locale goes live together, and there is no publishing anyway (ADR 0033).
|
|
204
|
-
*/
|
|
205
|
-
export const TRANSLATIONS_PENDING_ERROR = "TRANSLATIONS_PENDING";
|
|
206
|
-
|
|
207
|
-
/**
|
|
208
|
-
* oRPC error code for a publish refused because the draft has open findings, each to fix or for a
|
|
209
|
-
* member to dismiss: there is no publishing past them (ADR 0033).
|
|
210
|
-
*/
|
|
211
|
-
export const FINDINGS_OPEN_ERROR = "FINDINGS_OPEN";
|
|
212
|
-
|
|
213
|
-
/**
|
|
214
|
-
* oRPC error code for a publish refused because a patroller's check at publish hasn't read the
|
|
215
|
-
* draft's latest changes yet: publishing waits for it (ADR 0033).
|
|
216
|
-
*/
|
|
217
|
-
export const CHECKS_RUNNING_ERROR = "CHECKS_RUNNING";
|
|
218
|
-
|
|
219
196
|
/**
|
|
220
197
|
* Why the publish tool published nothing of a draft with changes, and returned a fresh preview to
|
|
221
|
-
* review again, by the error code of each:
|
|
222
|
-
*
|
|
223
|
-
* running, or the draft's code changed since the preview.
|
|
198
|
+
* review again, by the error code of each: the draft has blockers, or the draft's code changed
|
|
199
|
+
* since the preview.
|
|
224
200
|
*/
|
|
225
201
|
export const NOT_PUBLISHED_CODES = {
|
|
226
|
-
conflictsChanged: CONFLICTS_CHANGED_ERROR,
|
|
227
202
|
blocked: PUBLISH_BLOCKED_ERROR,
|
|
228
|
-
translating: TRANSLATIONS_PENDING_ERROR,
|
|
229
|
-
findings: FINDINGS_OPEN_ERROR,
|
|
230
|
-
checking: CHECKS_RUNNING_ERROR,
|
|
231
203
|
revisionChanged: REVISION_CHANGED_ERROR,
|
|
232
204
|
} as const;
|
|
233
205
|
|
|
@@ -339,7 +311,7 @@ const LOCALE_WRITES: Record<keyof Router["locales"], boolean> = {
|
|
|
339
311
|
|
|
340
312
|
// Applying a finding's fix edits content as the member would; dismissing one is the project's,
|
|
341
313
|
// never content (ADR 0034).
|
|
342
|
-
const
|
|
314
|
+
const SPECIALISTS_WRITES: Record<keyof Router["specialists"], boolean> = {
|
|
343
315
|
get: false,
|
|
344
316
|
applyFix: true,
|
|
345
317
|
dismissFinding: false,
|
|
@@ -352,7 +324,9 @@ const CONTENT_WRITES: Partial<Record<keyof Router, Record<string, boolean>>> = {
|
|
|
352
324
|
collectionDefinitions: COLLECTION_WRITES,
|
|
353
325
|
files: FILE_WRITES,
|
|
354
326
|
pages: PAGE_WRITES,
|
|
355
|
-
|
|
327
|
+
specialists: SPECIALISTS_WRITES,
|
|
328
|
+
// The old name of `specialists`, for studios not yet upgraded (ADR 0019).
|
|
329
|
+
patrol: SPECIALISTS_WRITES,
|
|
356
330
|
repeatableItems: ITEM_WRITES,
|
|
357
331
|
};
|
|
358
332
|
|
package/src/query-keys.ts
CHANGED
|
@@ -59,7 +59,11 @@ export const queryKeys = {
|
|
|
59
59
|
// The draft a viewer is in, scoped to it like content.
|
|
60
60
|
get: ["camox", "drafts", "get"],
|
|
61
61
|
},
|
|
62
|
-
// The
|
|
62
|
+
// The Specialists of a scope: their reports and pending work.
|
|
63
|
+
specialists: {
|
|
64
|
+
get: ["camox", "specialists"],
|
|
65
|
+
},
|
|
66
|
+
// Where studios not yet upgraded to the specialists cache them (ADR 0019).
|
|
63
67
|
patrol: {
|
|
64
68
|
get: ["camox", "patrol"],
|
|
65
69
|
},
|