@sentry/junior-plugin-api 0.256.0 → 0.258.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/index.d.ts +2087 -2107
- package/dist/index.js +1093 -1260
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -1,1406 +1,1239 @@
|
|
|
1
|
-
// src/object-annotations.ts
|
|
2
|
-
import { z as z3 } from "zod";
|
|
3
|
-
|
|
4
|
-
// src/object-facts.ts
|
|
5
1
|
import { z } from "zod";
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
2
|
+
// src/object-facts.ts
|
|
3
|
+
const text = z.string().trim().min(1).max(160);
|
|
4
|
+
const count = z.number().int().nonnegative();
|
|
5
|
+
/** Small, provider-neutral facts. Missing values mean unknown, not success. */
|
|
6
|
+
const objectFactsSchema = z.discriminatedUnion("type", [
|
|
7
|
+
z.strictObject({
|
|
8
|
+
type: z.literal("code_change"),
|
|
9
|
+
author: text.optional(),
|
|
10
|
+
sourceBranch: text.optional(),
|
|
11
|
+
targetBranch: text.optional(),
|
|
12
|
+
reviewers: z.array(text).max(5).optional(),
|
|
13
|
+
review: z.enum([
|
|
14
|
+
"required",
|
|
15
|
+
"approved",
|
|
16
|
+
"changes_requested"
|
|
17
|
+
]).optional(),
|
|
18
|
+
checks: z.strictObject({
|
|
19
|
+
passed: count,
|
|
20
|
+
failed: count,
|
|
21
|
+
pending: count
|
|
22
|
+
}).optional(),
|
|
23
|
+
mergeable: z.boolean().optional(),
|
|
24
|
+
changedFiles: count.optional(),
|
|
25
|
+
additions: count.optional(),
|
|
26
|
+
deletions: count.optional()
|
|
27
|
+
}),
|
|
28
|
+
z.strictObject({
|
|
29
|
+
type: z.literal("task"),
|
|
30
|
+
assignees: z.array(text).max(5).optional(),
|
|
31
|
+
priority: text.optional(),
|
|
32
|
+
project: text.optional(),
|
|
33
|
+
cycle: text.optional(),
|
|
34
|
+
dueDate: z.iso.date().optional(),
|
|
35
|
+
labels: z.array(text).max(5).optional()
|
|
36
|
+
}),
|
|
37
|
+
z.strictObject({
|
|
38
|
+
type: z.literal("deployment"),
|
|
39
|
+
project: text.optional(),
|
|
40
|
+
environment: text.optional(),
|
|
41
|
+
revision: text.optional(),
|
|
42
|
+
branch: text.optional()
|
|
43
|
+
}),
|
|
44
|
+
z.strictObject({
|
|
45
|
+
type: z.literal("calendar_event"),
|
|
46
|
+
when: text.optional(),
|
|
47
|
+
attendees: z.array(text).max(5).optional()
|
|
48
|
+
})
|
|
47
49
|
]);
|
|
50
|
+
/** Show at most four card attributes, in priority order, on every surface. */
|
|
48
51
|
function objectFactFields(facts) {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
}
|
|
83
|
-
return fields.slice(0, 4);
|
|
52
|
+
if (!facts) return [];
|
|
53
|
+
const fields = [];
|
|
54
|
+
const list = (values) => values?.length ? `${values.join(", ")}${values.length === 5 ? " (up to 5 shown)" : ""}` : void 0;
|
|
55
|
+
function add(key, label, value) {
|
|
56
|
+
if (value !== void 0 && value !== "") fields.push({
|
|
57
|
+
key,
|
|
58
|
+
label,
|
|
59
|
+
value: String(value)
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
switch (facts.type) {
|
|
63
|
+
case "code_change":
|
|
64
|
+
add("sourceBranch", "Branch", facts.sourceBranch);
|
|
65
|
+
break;
|
|
66
|
+
case "task":
|
|
67
|
+
add("assignees", "Assignees", facts.assignees?.length === 0 ? "Unassigned" : list(facts.assignees));
|
|
68
|
+
add("priority", "Priority", facts.priority);
|
|
69
|
+
add("project", "Project", facts.project);
|
|
70
|
+
add("cycle", "Cycle", facts.cycle);
|
|
71
|
+
add("dueDate", "Due", facts.dueDate);
|
|
72
|
+
add("labels", "Labels", list(facts.labels));
|
|
73
|
+
break;
|
|
74
|
+
case "deployment":
|
|
75
|
+
add("environment", "Environment", facts.environment);
|
|
76
|
+
add("project", "Project", facts.project);
|
|
77
|
+
add("revision", "Revision", facts.revision);
|
|
78
|
+
add("branch", "Branch", facts.branch);
|
|
79
|
+
break;
|
|
80
|
+
case "calendar_event":
|
|
81
|
+
add("when", "When", facts.when);
|
|
82
|
+
add("attendees", "Attendees", list(facts.attendees));
|
|
83
|
+
}
|
|
84
|
+
return fields.slice(0, 4);
|
|
84
85
|
}
|
|
85
|
-
|
|
86
86
|
// src/object-presentation.ts
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
87
|
+
/** Native object types. `task` is the stored name for a Ticket. */
|
|
88
|
+
const objectTypeSchema = z.enum([
|
|
89
|
+
"task",
|
|
90
|
+
"code_change",
|
|
91
|
+
"automation",
|
|
92
|
+
"deployment",
|
|
93
|
+
"calendar_event",
|
|
94
|
+
"item"
|
|
95
95
|
]);
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
96
|
+
const objectTypeLabels = {
|
|
97
|
+
task: "Ticket",
|
|
98
|
+
code_change: "Code change",
|
|
99
|
+
automation: "Automation",
|
|
100
|
+
deployment: "Deployment",
|
|
101
|
+
calendar_event: "Calendar event",
|
|
102
|
+
item: "Item"
|
|
103
103
|
};
|
|
104
|
+
/** Resolve identity and state without replacing the type icon with a warning. */
|
|
104
105
|
function objectPresentation(object) {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
106
|
+
const type = object.objectType === "item" && object.facts?.type === "deployment" ? "deployment" : object.objectType;
|
|
107
|
+
const status = object.status?.toLowerCase();
|
|
108
|
+
let icon = {
|
|
109
|
+
task: "issue-opened",
|
|
110
|
+
code_change: "git-pull-request",
|
|
111
|
+
automation: "workflow",
|
|
112
|
+
deployment: "rocket",
|
|
113
|
+
calendar_event: "calendar",
|
|
114
|
+
item: "package"
|
|
115
|
+
}[type];
|
|
116
|
+
let tone = type === "automation" ? "info" : "neutral";
|
|
117
|
+
if (type === "code_change") {
|
|
118
|
+
if (status === "draft") icon = "git-pull-request-draft";
|
|
119
|
+
if (status === "closed") {
|
|
120
|
+
icon = "git-pull-request-closed";
|
|
121
|
+
tone = "danger";
|
|
122
|
+
}
|
|
123
|
+
if (status === "merged") {
|
|
124
|
+
icon = "git-merge";
|
|
125
|
+
tone = "accent";
|
|
126
|
+
}
|
|
127
|
+
if (status === "open") tone = "success";
|
|
128
|
+
} else if (type === "task") {
|
|
129
|
+
if (status === "closed") {
|
|
130
|
+
icon = "issue-closed";
|
|
131
|
+
tone = "accent";
|
|
132
|
+
}
|
|
133
|
+
if (status === "open") tone = "success";
|
|
134
|
+
} else if (type === "deployment") {
|
|
135
|
+
if (status === "ready" || status === "succeeded") tone = "success";
|
|
136
|
+
if (status === "error" || status === "failed") tone = "danger";
|
|
137
|
+
if (status === "building" || status === "in_progress") tone = "info";
|
|
138
|
+
}
|
|
139
|
+
if (status === "warning" || status === "blocked") tone = "warning";
|
|
140
|
+
return {
|
|
141
|
+
icon,
|
|
142
|
+
tone,
|
|
143
|
+
label: objectTypeLabels[type]
|
|
144
|
+
};
|
|
140
145
|
}
|
|
146
|
+
/** Public, versioned asset path shared by Slack delivery and the web host. */
|
|
141
147
|
function objectIconPath(icon) {
|
|
142
|
-
|
|
148
|
+
return `/_junior/dashboard/object-icons/v1/${icon}.png`;
|
|
143
149
|
}
|
|
144
|
-
|
|
145
150
|
// src/object-annotations.ts
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
)
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
})
|
|
170
|
-
|
|
151
|
+
/**
|
|
152
|
+
* Verified facts shared by Conversation annotations and Message cards.
|
|
153
|
+
* Plugins select small facts from responses they already have. Each surface owns
|
|
154
|
+
* its layout. Omit unknown facts; do not infer approval or passing checks.
|
|
155
|
+
*
|
|
156
|
+
* These facts support both compact previews and full details. Each surface
|
|
157
|
+
* selects the fields it needs; preview rules must not remove saved facts.
|
|
158
|
+
*
|
|
159
|
+
* Keep raw responses, diffs, logs, credentials, and comments out of this schema.
|
|
160
|
+
* See "Object facts" in packages/junior/src/chat/conversations/README.md.
|
|
161
|
+
*/
|
|
162
|
+
const objectAnnotationSchema = z.object({
|
|
163
|
+
kind: z.literal("object"),
|
|
164
|
+
key: z.string().trim().min(1).max(256),
|
|
165
|
+
label: z.string().trim().min(1).max(256),
|
|
166
|
+
objectType: objectTypeSchema,
|
|
167
|
+
title: z.string().trim().min(1).max(512),
|
|
168
|
+
url: z.url().max(2048).refine((value) => ["http:", "https:"].includes(new URL(value).protocol)).nullable(),
|
|
169
|
+
description: z.string().max(4e3).optional(),
|
|
170
|
+
status: z.string().trim().min(1).max(100).optional(),
|
|
171
|
+
trigger: z.string().max(4e3).optional(),
|
|
172
|
+
warning: z.string().max(1e3).optional(),
|
|
173
|
+
displayType: z.string().trim().min(1).max(80).optional(),
|
|
174
|
+
sourceUpdatedAt: z.iso.datetime({ offset: true }).optional(),
|
|
175
|
+
facts: objectFactsSchema.refine((facts) => new TextEncoder().encode(JSON.stringify(facts)).length <= 4096, "Object facts must not exceed 4 KiB").optional()
|
|
176
|
+
}).strict().refine((annotation) => !annotation.facts || (annotation.facts.type === "deployment" ? annotation.objectType === "deployment" || annotation.objectType === "item" : annotation.facts.type === annotation.objectType), "Object facts must match the object type");
|
|
177
|
+
/** A saved object snapshot with its trusted owner. */
|
|
178
|
+
const ownedObjectAnnotationSchema = objectAnnotationSchema.safeExtend({ plugin: z.string().min(1) });
|
|
171
179
|
// src/object-icons.ts
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
"git-pull-request-draft": [
|
|
185
|
-
"M3.25 1A2.25 2.25 0 0 1 4 5.372v5.256a2.251 2.251 0 1 1-1.5 0V5.372A2.251 2.251 0 0 1 3.25 1Zm9.5 14a2.25 2.25 0 1 1 0-4.5 2.25 2.25 0 0 1 0 4.5ZM2.5 3.25a.75.75 0 1 0 1.5 0 .75.75 0 0 0-1.5 0ZM3.25 12a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Zm9.5 0a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5ZM14 7.5a1.25 1.25 0 1 1-2.5 0 1.25 1.25 0 0 1 2.5 0Zm0-4.25a1.25 1.25 0 1 1-2.5 0 1.25 1.25 0 0 1 2.5 0Z"
|
|
186
|
-
],
|
|
187
|
-
"git-pull-request-closed": [
|
|
188
|
-
"M3.25 1A2.25 2.25 0 0 1 4 5.372v5.256a2.251 2.251 0 1 1-1.5 0V5.372A2.251 2.251 0 0 1 3.25 1Zm9.5 5.5a.75.75 0 0 1 .75.75v3.378a2.251 2.251 0 1 1-1.5 0V7.25a.75.75 0 0 1 .75-.75Zm-2.03-5.273a.75.75 0 0 1 1.06 0l.97.97.97-.97a.748.748 0 0 1 1.265.332.75.75 0 0 1-.205.729l-.97.97.97.97a.751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018l-.97-.97-.97.97a.749.749 0 0 1-1.275-.326.749.749 0 0 1 .215-.734l.97-.97-.97-.97a.75.75 0 0 1 0-1.06ZM2.5 3.25a.75.75 0 1 0 1.5 0 .75.75 0 0 0-1.5 0ZM3.25 12a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Zm9.5 0a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Z"
|
|
189
|
-
],
|
|
190
|
-
"git-merge": [
|
|
191
|
-
"M5.45 5.154A4.25 4.25 0 0 0 9.25 7.5h1.378a2.251 2.251 0 1 1 0 1.5H9.25A5.734 5.734 0 0 1 5 7.123v3.505a2.25 2.25 0 1 1-1.5 0V5.372a2.25 2.25 0 1 1 1.95-.218ZM4.25 13.5a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Zm8.5-4.5a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5ZM5 3.25a.75.75 0 1 0 0 .005V3.25Z"
|
|
192
|
-
],
|
|
193
|
-
workflow: [
|
|
194
|
-
"M0 1.75C0 .784.784 0 1.75 0h3.5C6.216 0 7 .784 7 1.75v3.5A1.75 1.75 0 0 1 5.25 7H4v4a1 1 0 0 0 1 1h4v-1.25C9 9.784 9.784 9 10.75 9h3.5c.966 0 1.75.784 1.75 1.75v3.5A1.75 1.75 0 0 1 14.25 16h-3.5A1.75 1.75 0 0 1 9 14.25v-.75H5A2.5 2.5 0 0 1 2.5 11V7h-.75A1.75 1.75 0 0 1 0 5.25Zm1.75-.25a.25.25 0 0 0-.25.25v3.5c0 .138.112.25.25.25h3.5a.25.25 0 0 0 .25-.25v-3.5a.25.25 0 0 0-.25-.25Zm9 9a.25.25 0 0 0-.25.25v3.5c0 .138.112.25.25.25h3.5a.25.25 0 0 0 .25-.25v-3.5a.25.25 0 0 0-.25-.25Z"
|
|
195
|
-
],
|
|
196
|
-
rocket: [
|
|
197
|
-
"M14.064 0h.186C15.216 0 16 .784 16 1.75v.186a8.752 8.752 0 0 1-2.564 6.186l-.458.459c-.314.314-.641.616-.979.904v3.207c0 .608-.315 1.172-.833 1.49l-2.774 1.707a.749.749 0 0 1-1.11-.418l-.954-3.102a1.214 1.214 0 0 1-.145-.125L3.754 9.816a1.218 1.218 0 0 1-.124-.145L.528 8.717a.749.749 0 0 1-.418-1.11l1.71-2.774A1.748 1.748 0 0 1 3.31 4h3.204c.288-.338.59-.665.904-.979l.459-.458A8.749 8.749 0 0 1 14.064 0ZM8.938 3.623h-.002l-.458.458c-.76.76-1.437 1.598-2.02 2.5l-1.5 2.317 2.143 2.143 2.317-1.5c.902-.583 1.74-1.26 2.499-2.02l.459-.458a7.25 7.25 0 0 0 2.123-5.127V1.75a.25.25 0 0 0-.25-.25h-.186a7.249 7.249 0 0 0-5.125 2.123ZM3.56 14.56c-.732.732-2.334 1.045-3.005 1.148a.234.234 0 0 1-.201-.064.234.234 0 0 1-.064-.201c.103-.671.416-2.273 1.15-3.003a1.502 1.502 0 1 1 2.12 2.12Zm6.94-3.935c-.088.06-.177.118-.266.175l-2.35 1.521.548 1.783 1.949-1.2a.25.25 0 0 0 .119-.213ZM3.678 8.116 5.2 5.766c.058-.09.117-.178.176-.266H3.309a.25.25 0 0 0-.213.119l-1.2 1.95ZM12 5a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"
|
|
198
|
-
],
|
|
199
|
-
calendar: [
|
|
200
|
-
"M4.75 0a.75.75 0 0 1 .75.75V2h5V.75a.75.75 0 0 1 1.5 0V2h1.25c.966 0 1.75.784 1.75 1.75v10.5A1.75 1.75 0 0 1 13.25 16H2.75A1.75 1.75 0 0 1 1 14.25V3.75C1 2.784 1.784 2 2.75 2H4V.75A.75.75 0 0 1 4.75 0ZM2.5 7.5v6.75c0 .138.112.25.25.25h10.5a.25.25 0 0 0 .25-.25V7.5Zm10.75-4H2.75a.25.25 0 0 0-.25.25V6h11V3.75a.25.25 0 0 0-.25-.25Z"
|
|
201
|
-
],
|
|
202
|
-
package: [
|
|
203
|
-
"m8.878.392 5.25 3.045c.54.314.872.89.872 1.514v6.098a1.75 1.75 0 0 1-.872 1.514l-5.25 3.045a1.75 1.75 0 0 1-1.756 0l-5.25-3.045A1.75 1.75 0 0 1 1 11.049V4.951c0-.624.332-1.201.872-1.514L7.122.392a1.75 1.75 0 0 1 1.756 0ZM7.875 1.69l-4.63 2.685L8 7.133l4.755-2.758-4.63-2.685a.248.248 0 0 0-.25 0ZM2.5 5.677v5.372c0 .09.047.171.125.216l4.625 2.683V8.432Zm6.25 8.271 4.625-2.683a.25.25 0 0 0 .125-.216V5.677L8.75 8.432Z"
|
|
204
|
-
]
|
|
180
|
+
/** Original Octicons paths, shared by web and Slack image assets. */
|
|
181
|
+
const objectIconPaths = {
|
|
182
|
+
"issue-opened": ["M8 9.5a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Z", "M8 0a8 8 0 1 1 0 16A8 8 0 0 1 8 0ZM1.5 8a6.5 6.5 0 1 0 13 0 6.5 6.5 0 0 0-13 0Z"],
|
|
183
|
+
"issue-closed": ["M11.28 6.78a.75.75 0 0 0-1.06-1.06L7.25 8.69 5.78 7.22a.75.75 0 0 0-1.06 1.06l2 2a.75.75 0 0 0 1.06 0l3.5-3.5Z", "M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0Zm-1.5 0a6.5 6.5 0 1 0-13 0 6.5 6.5 0 0 0 13 0Z"],
|
|
184
|
+
"git-pull-request": ["M1.5 3.25a2.25 2.25 0 1 1 3 2.122v5.256a2.251 2.251 0 1 1-1.5 0V5.372A2.25 2.25 0 0 1 1.5 3.25Zm5.677-.177L9.573.677A.25.25 0 0 1 10 .854V2.5h1A2.5 2.5 0 0 1 13.5 5v5.628a2.251 2.251 0 1 1-1.5 0V5a1 1 0 0 0-1-1h-1v1.646a.25.25 0 0 1-.427.177L7.177 3.427a.25.25 0 0 1 0-.354ZM3.75 2.5a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Zm0 9.5a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Zm8.25.75a.75.75 0 1 0 1.5 0 .75.75 0 0 0-1.5 0Z"],
|
|
185
|
+
"git-pull-request-draft": ["M3.25 1A2.25 2.25 0 0 1 4 5.372v5.256a2.251 2.251 0 1 1-1.5 0V5.372A2.251 2.251 0 0 1 3.25 1Zm9.5 14a2.25 2.25 0 1 1 0-4.5 2.25 2.25 0 0 1 0 4.5ZM2.5 3.25a.75.75 0 1 0 1.5 0 .75.75 0 0 0-1.5 0ZM3.25 12a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Zm9.5 0a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5ZM14 7.5a1.25 1.25 0 1 1-2.5 0 1.25 1.25 0 0 1 2.5 0Zm0-4.25a1.25 1.25 0 1 1-2.5 0 1.25 1.25 0 0 1 2.5 0Z"],
|
|
186
|
+
"git-pull-request-closed": ["M3.25 1A2.25 2.25 0 0 1 4 5.372v5.256a2.251 2.251 0 1 1-1.5 0V5.372A2.251 2.251 0 0 1 3.25 1Zm9.5 5.5a.75.75 0 0 1 .75.75v3.378a2.251 2.251 0 1 1-1.5 0V7.25a.75.75 0 0 1 .75-.75Zm-2.03-5.273a.75.75 0 0 1 1.06 0l.97.97.97-.97a.748.748 0 0 1 1.265.332.75.75 0 0 1-.205.729l-.97.97.97.97a.751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018l-.97-.97-.97.97a.749.749 0 0 1-1.275-.326.749.749 0 0 1 .215-.734l.97-.97-.97-.97a.75.75 0 0 1 0-1.06ZM2.5 3.25a.75.75 0 1 0 1.5 0 .75.75 0 0 0-1.5 0ZM3.25 12a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Zm9.5 0a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Z"],
|
|
187
|
+
"git-merge": ["M5.45 5.154A4.25 4.25 0 0 0 9.25 7.5h1.378a2.251 2.251 0 1 1 0 1.5H9.25A5.734 5.734 0 0 1 5 7.123v3.505a2.25 2.25 0 1 1-1.5 0V5.372a2.25 2.25 0 1 1 1.95-.218ZM4.25 13.5a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Zm8.5-4.5a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5ZM5 3.25a.75.75 0 1 0 0 .005V3.25Z"],
|
|
188
|
+
workflow: ["M0 1.75C0 .784.784 0 1.75 0h3.5C6.216 0 7 .784 7 1.75v3.5A1.75 1.75 0 0 1 5.25 7H4v4a1 1 0 0 0 1 1h4v-1.25C9 9.784 9.784 9 10.75 9h3.5c.966 0 1.75.784 1.75 1.75v3.5A1.75 1.75 0 0 1 14.25 16h-3.5A1.75 1.75 0 0 1 9 14.25v-.75H5A2.5 2.5 0 0 1 2.5 11V7h-.75A1.75 1.75 0 0 1 0 5.25Zm1.75-.25a.25.25 0 0 0-.25.25v3.5c0 .138.112.25.25.25h3.5a.25.25 0 0 0 .25-.25v-3.5a.25.25 0 0 0-.25-.25Zm9 9a.25.25 0 0 0-.25.25v3.5c0 .138.112.25.25.25h3.5a.25.25 0 0 0 .25-.25v-3.5a.25.25 0 0 0-.25-.25Z"],
|
|
189
|
+
rocket: ["M14.064 0h.186C15.216 0 16 .784 16 1.75v.186a8.752 8.752 0 0 1-2.564 6.186l-.458.459c-.314.314-.641.616-.979.904v3.207c0 .608-.315 1.172-.833 1.49l-2.774 1.707a.749.749 0 0 1-1.11-.418l-.954-3.102a1.214 1.214 0 0 1-.145-.125L3.754 9.816a1.218 1.218 0 0 1-.124-.145L.528 8.717a.749.749 0 0 1-.418-1.11l1.71-2.774A1.748 1.748 0 0 1 3.31 4h3.204c.288-.338.59-.665.904-.979l.459-.458A8.749 8.749 0 0 1 14.064 0ZM8.938 3.623h-.002l-.458.458c-.76.76-1.437 1.598-2.02 2.5l-1.5 2.317 2.143 2.143 2.317-1.5c.902-.583 1.74-1.26 2.499-2.02l.459-.458a7.25 7.25 0 0 0 2.123-5.127V1.75a.25.25 0 0 0-.25-.25h-.186a7.249 7.249 0 0 0-5.125 2.123ZM3.56 14.56c-.732.732-2.334 1.045-3.005 1.148a.234.234 0 0 1-.201-.064.234.234 0 0 1-.064-.201c.103-.671.416-2.273 1.15-3.003a1.502 1.502 0 1 1 2.12 2.12Zm6.94-3.935c-.088.06-.177.118-.266.175l-2.35 1.521.548 1.783 1.949-1.2a.25.25 0 0 0 .119-.213ZM3.678 8.116 5.2 5.766c.058-.09.117-.178.176-.266H3.309a.25.25 0 0 0-.213.119l-1.2 1.95ZM12 5a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"],
|
|
190
|
+
calendar: ["M4.75 0a.75.75 0 0 1 .75.75V2h5V.75a.75.75 0 0 1 1.5 0V2h1.25c.966 0 1.75.784 1.75 1.75v10.5A1.75 1.75 0 0 1 13.25 16H2.75A1.75 1.75 0 0 1 1 14.25V3.75C1 2.784 1.784 2 2.75 2H4V.75A.75.75 0 0 1 4.75 0ZM2.5 7.5v6.75c0 .138.112.25.25.25h10.5a.25.25 0 0 0 .25-.25V7.5Zm10.75-4H2.75a.25.25 0 0 0-.25.25V6h11V3.75a.25.25 0 0 0-.25-.25Z"],
|
|
191
|
+
package: ["m8.878.392 5.25 3.045c.54.314.872.89.872 1.514v6.098a1.75 1.75 0 0 1-.872 1.514l-5.25 3.045a1.75 1.75 0 0 1-1.756 0l-5.25-3.045A1.75 1.75 0 0 1 1 11.049V4.951c0-.624.332-1.201.872-1.514L7.122.392a1.75 1.75 0 0 1 1.756 0ZM7.875 1.69l-4.63 2.685L8 7.133l4.755-2.758-4.63-2.685a.248.248 0 0 0-.25 0ZM2.5 5.677v5.372c0 .09.047.171.125.216l4.625 2.683V8.432Zm6.25 8.271 4.625-2.683a.25.25 0 0 0 .125-.216V5.677L8.75 8.432Z"]
|
|
205
192
|
};
|
|
206
|
-
|
|
207
193
|
// src/annotations.ts
|
|
208
|
-
import { z as z4 } from "zod";
|
|
209
194
|
function usesHttpProtocol(value) {
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
195
|
+
try {
|
|
196
|
+
const protocol = new URL(value).protocol;
|
|
197
|
+
return protocol === "http:" || protocol === "https:";
|
|
198
|
+
} catch {
|
|
199
|
+
return false;
|
|
200
|
+
}
|
|
216
201
|
}
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
202
|
+
/**
|
|
203
|
+
* Link an object to a Conversation when the owner has no typed object preview.
|
|
204
|
+
* Keep a stable key, compact label, source URL, and optional short context or
|
|
205
|
+
* status. Do not fetch a full object merely to save a link. Rich preview intent
|
|
206
|
+
* belongs to objectAnnotationSchema, not a second set of resource-link fields.
|
|
207
|
+
*/
|
|
208
|
+
const resourceLinkAnnotationSchema = z.object({
|
|
209
|
+
kind: z.literal("resource_link"),
|
|
210
|
+
objectType: objectTypeSchema.optional(),
|
|
211
|
+
key: z.string().trim().min(1).max(256),
|
|
212
|
+
label: z.string().trim().min(1).max(256),
|
|
213
|
+
url: z.string().url().max(2048).refine(usesHttpProtocol, "URL must use HTTP or HTTPS."),
|
|
214
|
+
description: z.string().trim().min(1).max(512).optional(),
|
|
215
|
+
status: z.enum([
|
|
216
|
+
"open",
|
|
217
|
+
"draft",
|
|
218
|
+
"closed",
|
|
219
|
+
"merged",
|
|
220
|
+
"warning"
|
|
221
|
+
]).optional()
|
|
225
222
|
}).strict();
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
"git-pull-request",
|
|
236
|
-
"triangle-alert"
|
|
223
|
+
/** Core-known annotation shapes that plugins may attach to a conversation. */
|
|
224
|
+
const conversationAnnotationInputSchema = z.discriminatedUnion("kind", [resourceLinkAnnotationSchema, objectAnnotationSchema]);
|
|
225
|
+
const conversationSidebarIconSchema = z.enum([
|
|
226
|
+
"circle-dot",
|
|
227
|
+
"circle-dashed",
|
|
228
|
+
"circle-x",
|
|
229
|
+
"git-merge",
|
|
230
|
+
"git-pull-request",
|
|
231
|
+
"triangle-alert"
|
|
237
232
|
]);
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
233
|
+
const conversationSidebarAnnotationSchema = z.object({
|
|
234
|
+
icon: conversationSidebarIconSchema.optional(),
|
|
235
|
+
objectType: objectTypeSchema.optional(),
|
|
236
|
+
status: z.string().trim().min(1).max(100).optional(),
|
|
237
|
+
key: z.string().trim().min(1).max(256),
|
|
238
|
+
label: z.string().trim().min(1).max(256)
|
|
244
239
|
}).strict();
|
|
245
|
-
|
|
246
240
|
// src/code.ts
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
241
|
+
const codeChangeStateSchema = z.enum([
|
|
242
|
+
"closed",
|
|
243
|
+
"merged",
|
|
244
|
+
"open"
|
|
245
|
+
]);
|
|
246
|
+
const codeChangeInputSchema = z.object({
|
|
247
|
+
closedAt: z.date().optional(),
|
|
248
|
+
conversationIds: z.array(z.string().min(1)).default([]),
|
|
249
|
+
mergedAt: z.date().optional(),
|
|
250
|
+
number: z.number().int().positive(),
|
|
251
|
+
openedAt: z.date(),
|
|
252
|
+
providerId: z.string().min(1),
|
|
253
|
+
repository: z.object({
|
|
254
|
+
name: z.string().min(1),
|
|
255
|
+
providerId: z.string().min(1),
|
|
256
|
+
url: z.string().url().optional()
|
|
257
|
+
}).strict(),
|
|
258
|
+
state: codeChangeStateSchema,
|
|
259
|
+
title: z.string().min(1).optional(),
|
|
260
|
+
updatedAt: z.date(),
|
|
261
|
+
url: z.string().url().optional()
|
|
265
262
|
}).strict();
|
|
266
|
-
|
|
267
263
|
// src/conversation-events.ts
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
"warning"
|
|
264
|
+
const conversationEventNameSchema = z.string().trim().min(1).max(64).regex(/^[a-z][a-z0-9_]*$/);
|
|
265
|
+
const conversationEventIconSchema = z.enum([
|
|
266
|
+
"activity",
|
|
267
|
+
"brain",
|
|
268
|
+
"calendar",
|
|
269
|
+
"check",
|
|
270
|
+
"database",
|
|
271
|
+
"info",
|
|
272
|
+
"key",
|
|
273
|
+
"link",
|
|
274
|
+
"sparkles",
|
|
275
|
+
"warning"
|
|
281
276
|
]);
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
277
|
+
const conversationEventDetailSchema = z.object({
|
|
278
|
+
content: z.string().min(1).max(32768).optional(),
|
|
279
|
+
description: z.string().trim().min(1).max(2e3).optional(),
|
|
280
|
+
metadata: z.array(z.string().trim().min(1).max(120)).max(8).optional(),
|
|
281
|
+
title: z.string().trim().min(1).max(4e3)
|
|
287
282
|
}).strict();
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
283
|
+
/** Safe, core-rendered presentation for one plugin conversation event. */
|
|
284
|
+
const conversationEventPresentationSchema = z.object({
|
|
285
|
+
details: z.array(conversationEventDetailSchema).max(100).optional(),
|
|
286
|
+
icon: conversationEventIconSchema.optional(),
|
|
287
|
+
preview: z.string().trim().min(1).max(500).optional(),
|
|
288
|
+
title: z.string().trim().min(1).max(120)
|
|
293
289
|
}).strict();
|
|
290
|
+
/** Define one typed, versioned plugin-owned conversation event. */
|
|
294
291
|
function defineConversationEvent(definition) {
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
292
|
+
const identity = z.object({
|
|
293
|
+
name: conversationEventNameSchema,
|
|
294
|
+
version: z.number().int().positive()
|
|
295
|
+
}).strict().parse({
|
|
296
|
+
name: definition.name,
|
|
297
|
+
version: definition.version
|
|
298
|
+
});
|
|
299
|
+
let eventDefinition;
|
|
300
|
+
const createEvent = (data) => ({
|
|
301
|
+
data: definition.schema.parse(data),
|
|
302
|
+
definition: eventDefinition
|
|
303
|
+
});
|
|
304
|
+
eventDefinition = Object.assign(createEvent, {
|
|
305
|
+
eventName: identity.name,
|
|
306
|
+
version: identity.version,
|
|
307
|
+
parse(data) {
|
|
308
|
+
return definition.schema.parse(data);
|
|
309
|
+
},
|
|
310
|
+
renderEvent(data) {
|
|
311
|
+
const parsed = definition.schema.parse(data);
|
|
312
|
+
const presentation = definition.renderEvent(parsed);
|
|
313
|
+
return presentation === void 0 ? void 0 : conversationEventPresentationSchema.parse(presentation);
|
|
314
|
+
}
|
|
315
|
+
});
|
|
316
|
+
return eventDefinition;
|
|
317
317
|
}
|
|
318
|
-
|
|
319
318
|
// src/schemas.ts
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
);
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
319
|
+
const slackTeamIdSchema = z.string().regex(/^T[A-Z0-9]+$/);
|
|
320
|
+
const slackConversationIdSchema = z.string().regex(/^(C|G|D)[A-Z0-9]+$/);
|
|
321
|
+
const localConversationIdSchema = z.string().regex(/^local:[a-z0-9_-]+:[a-z0-9][a-z0-9_-]*$/);
|
|
322
|
+
/** Exact non-blank actor user id that rejects the sentinel "unknown". */
|
|
323
|
+
const actorUserIdSchema = z.string().min(1).refine((value) => value === value.trim() && value.toLowerCase() !== "unknown");
|
|
324
|
+
const exactActorUserIdSchema = actorUserIdSchema;
|
|
325
|
+
const nonBlankStringSchema = z.string().refine((value) => value.trim().length > 0);
|
|
326
|
+
const exactNonBlankStringSchema = nonBlankStringSchema.refine((value) => value === value.trim());
|
|
327
|
+
/** Complete Slack Location associated with a Conversation. */
|
|
328
|
+
const slackLocationSchema = z.object({
|
|
329
|
+
/** Stable SQL identity used by Location configuration and reporting. */
|
|
330
|
+
id: nonBlankStringSchema,
|
|
331
|
+
provider: exactNonBlankStringSchema
|
|
332
|
+
}).strict().extend({
|
|
333
|
+
provider: z.literal("slack"),
|
|
334
|
+
teamId: slackTeamIdSchema,
|
|
335
|
+
channelId: slackConversationIdSchema,
|
|
336
|
+
threadTs: exactNonBlankStringSchema.optional()
|
|
336
337
|
}).strict();
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
338
|
+
/** Complete Location types supported by Junior. */
|
|
339
|
+
const locationSchema = z.discriminatedUnion("provider", [slackLocationSchema]);
|
|
340
|
+
/** Runtime platform names supported by plugin public contracts. */
|
|
341
|
+
const platformSchema = z.enum(["slack", "local"]);
|
|
342
|
+
/** Runtime source visibility visible to plugins. */
|
|
343
|
+
const sourceVisibilitySchema = z.enum(["public", "private"]);
|
|
344
|
+
/** Provider-neutral visibility of a routed destination. */
|
|
345
|
+
const destinationVisibilitySchema = z.enum(["public", "private"]);
|
|
346
|
+
/** Runtime-owned Slack address for routing future work or side effects. */
|
|
347
|
+
const slackDestinationSchema = z.object({
|
|
348
|
+
platform: z.literal("slack"),
|
|
349
|
+
teamId: slackTeamIdSchema,
|
|
350
|
+
channelId: slackConversationIdSchema,
|
|
351
|
+
threadTs: exactNonBlankStringSchema.optional()
|
|
342
352
|
}).strict();
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
var sourceVisibilitySchema = z7.enum(["public", "private"]);
|
|
348
|
-
var destinationVisibilitySchema = z7.enum(["public", "private"]);
|
|
349
|
-
var slackAddressSchema = z7.object({
|
|
350
|
-
platform: z7.literal("slack"),
|
|
351
|
-
teamId: slackTeamIdSchema,
|
|
352
|
-
channelId: slackConversationIdSchema,
|
|
353
|
-
threadTs: exactNonBlankStringSchema.optional()
|
|
353
|
+
/** Runtime-owned local CLI conversation address. */
|
|
354
|
+
const localDestinationSchema = z.object({
|
|
355
|
+
platform: z.literal("local"),
|
|
356
|
+
conversationId: localConversationIdSchema
|
|
354
357
|
}).strict();
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
358
|
+
/** Runtime-owned provider-neutral address for routing future work or side effects. */
|
|
359
|
+
const destinationSchema = z.discriminatedUnion("platform", [slackDestinationSchema, localDestinationSchema]);
|
|
360
|
+
/** One visible effect after successful automated work. */
|
|
361
|
+
const taskOutcomeSchema = z.object({
|
|
362
|
+
action: z.literal("send_message"),
|
|
363
|
+
destination: slackDestinationSchema
|
|
359
364
|
}).strict();
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
365
|
+
/** Runtime-owned Slack input Source. */
|
|
366
|
+
const slackSourceSchema = z.object({
|
|
367
|
+
kind: z.literal("slack"),
|
|
368
|
+
teamId: slackTeamIdSchema,
|
|
369
|
+
channelId: slackConversationIdSchema,
|
|
370
|
+
visibility: sourceVisibilitySchema,
|
|
371
|
+
messageTs: nonBlankStringSchema.optional(),
|
|
372
|
+
threadTs: nonBlankStringSchema.optional()
|
|
367
373
|
}).strict();
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
messageTs: nonBlankStringSchema.optional(),
|
|
374
|
-
threadTs: nonBlankStringSchema.optional()
|
|
374
|
+
/** Runtime-owned local CLI input Source. */
|
|
375
|
+
const localSourceSchema = z.object({
|
|
376
|
+
kind: z.literal("local"),
|
|
377
|
+
visibility: z.literal("private"),
|
|
378
|
+
conversationId: localConversationIdSchema
|
|
375
379
|
}).strict();
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
+
/** Runtime-owned dashboard input Source. */
|
|
381
|
+
const webSourceSchema = z.object({
|
|
382
|
+
kind: z.literal("web"),
|
|
383
|
+
visibility: sourceVisibilitySchema,
|
|
384
|
+
conversationId: exactNonBlankStringSchema
|
|
380
385
|
}).strict();
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
+
/** Runtime-owned Event input Source. */
|
|
387
|
+
const eventSourceSchema = z.object({
|
|
388
|
+
kind: z.literal("event"),
|
|
389
|
+
eventKey: exactNonBlankStringSchema,
|
|
390
|
+
eventType: exactNonBlankStringSchema,
|
|
391
|
+
identifier: exactNonBlankStringSchema,
|
|
392
|
+
namespace: exactNonBlankStringSchema
|
|
393
|
+
}).strict();
|
|
394
|
+
const automationSourceFields = {
|
|
395
|
+
automationId: exactNonBlankStringSchema.optional(),
|
|
396
|
+
automationRunId: exactNonBlankStringSchema.optional()
|
|
397
|
+
};
|
|
398
|
+
/** Runtime-owned Scheduled automation input Source. */
|
|
399
|
+
const scheduledAutomationSourceSchema = z.object({
|
|
400
|
+
kind: z.literal("scheduled_automation"),
|
|
401
|
+
...automationSourceFields
|
|
386
402
|
}).strict();
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
identifier: exactNonBlankStringSchema,
|
|
392
|
-
namespace: exactNonBlankStringSchema
|
|
403
|
+
/** Runtime-owned Event automation input Source. */
|
|
404
|
+
const eventAutomationSourceSchema = z.object({
|
|
405
|
+
kind: z.literal("event_automation"),
|
|
406
|
+
...automationSourceFields
|
|
393
407
|
}).strict();
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
408
|
+
/** Runtime-owned Plugin dispatch input Source. */
|
|
409
|
+
const pluginDispatchSourceSchema = z.object({ kind: z.literal("plugin_dispatch") }).strict();
|
|
410
|
+
/** Runtime-owned Agent invocation input Source. */
|
|
411
|
+
const agentInvocationSourceSchema = z.object({ kind: z.literal("agent_invocation") }).strict();
|
|
412
|
+
const currentSourceSchema = z.discriminatedUnion("kind", [
|
|
413
|
+
slackSourceSchema,
|
|
414
|
+
localSourceSchema,
|
|
415
|
+
webSourceSchema,
|
|
416
|
+
eventSourceSchema,
|
|
417
|
+
scheduledAutomationSourceSchema,
|
|
418
|
+
eventAutomationSourceSchema,
|
|
419
|
+
pluginDispatchSourceSchema,
|
|
420
|
+
agentInvocationSourceSchema
|
|
407
421
|
]);
|
|
408
422
|
function normalizeStoredSource(value) {
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
423
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return value;
|
|
424
|
+
const source = value;
|
|
425
|
+
if ("kind" in source) {
|
|
426
|
+
const kind = typeof source.kind === "string" ? {
|
|
427
|
+
event_task: "event_automation",
|
|
428
|
+
resource_event: "event",
|
|
429
|
+
scheduled_task: "scheduled_automation"
|
|
430
|
+
}[source.kind] : void 0;
|
|
431
|
+
return kind ? {
|
|
432
|
+
...source,
|
|
433
|
+
kind
|
|
434
|
+
} : value;
|
|
435
|
+
}
|
|
436
|
+
if (source.platform !== "slack" && source.platform !== "local" && source.platform !== "web") return value;
|
|
437
|
+
const { location: _location, platform: kind, ...fields } = source;
|
|
438
|
+
return {
|
|
439
|
+
...fields,
|
|
440
|
+
kind
|
|
441
|
+
};
|
|
427
442
|
}
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
);
|
|
448
|
-
var actorProfileSchema = {
|
|
449
|
-
email: nonBlankStringSchema.optional(),
|
|
450
|
-
fullName: nonBlankStringSchema.optional(),
|
|
451
|
-
userId: exactActorUserIdSchema,
|
|
452
|
-
userName: nonBlankStringSchema.optional()
|
|
443
|
+
/** Runtime-owned input Source. Stored `platform` and Location fields normalize on read. */
|
|
444
|
+
const sourceSchema = z.preprocess(normalizeStoredSource, currentSourceSchema);
|
|
445
|
+
/** Stable user credential subject shape accepted from plugins. */
|
|
446
|
+
const pluginCredentialSubjectSchema = z.discriminatedUnion("allowedWhen", [z.object({
|
|
447
|
+
type: z.literal("user"),
|
|
448
|
+
userId: exactActorUserIdSchema,
|
|
449
|
+
allowedWhen: z.literal("private-direct-conversation")
|
|
450
|
+
}).strict(), z.object({
|
|
451
|
+
type: z.literal("user"),
|
|
452
|
+
userId: exactActorUserIdSchema,
|
|
453
|
+
allowedWhen: z.literal("scheduled-automation"),
|
|
454
|
+
taskId: exactNonBlankStringSchema
|
|
455
|
+
}).strict()]);
|
|
456
|
+
/** Shared exact actor profile fields for platform-scoped actors. */
|
|
457
|
+
const actorProfileSchema = {
|
|
458
|
+
email: nonBlankStringSchema.optional(),
|
|
459
|
+
fullName: nonBlankStringSchema.optional(),
|
|
460
|
+
userId: exactActorUserIdSchema,
|
|
461
|
+
userName: nonBlankStringSchema.optional()
|
|
453
462
|
};
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
463
|
+
const slackActorSchema = z.object({
|
|
464
|
+
...actorProfileSchema,
|
|
465
|
+
platform: z.literal("slack"),
|
|
466
|
+
teamId: slackTeamIdSchema
|
|
458
467
|
}).strict();
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
468
|
+
const localActorSchema = z.object({
|
|
469
|
+
...actorProfileSchema,
|
|
470
|
+
platform: z.literal("local")
|
|
462
471
|
}).strict();
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
472
|
+
const webActorSchema = z.object({
|
|
473
|
+
...actorProfileSchema,
|
|
474
|
+
platform: z.literal("web")
|
|
466
475
|
}).strict();
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
476
|
+
const systemActorSchema = z.object({
|
|
477
|
+
platform: z.literal("system"),
|
|
478
|
+
name: exactActorUserIdSchema
|
|
470
479
|
}).strict();
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
480
|
+
/** Runtime-provided actor identity visible to plugin hooks. */
|
|
481
|
+
const actorSchema = z.discriminatedUnion("platform", [
|
|
482
|
+
slackActorSchema,
|
|
483
|
+
localActorSchema,
|
|
484
|
+
webActorSchema,
|
|
485
|
+
systemActorSchema
|
|
476
486
|
]);
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
487
|
+
/** Core-owned provider account linked to a user when verified. */
|
|
488
|
+
const identitySchema = z.object({
|
|
489
|
+
displayName: nonBlankStringSchema.optional(),
|
|
490
|
+
handle: nonBlankStringSchema.optional(),
|
|
491
|
+
id: exactNonBlankStringSchema,
|
|
492
|
+
provider: exactNonBlankStringSchema,
|
|
493
|
+
providerSubjectId: exactNonBlankStringSchema,
|
|
494
|
+
providerTenantId: exactNonBlankStringSchema.optional()
|
|
484
495
|
}).strict();
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
496
|
+
/** Core-owned person with every linked provider identity. */
|
|
497
|
+
const userSchema = z.object({
|
|
498
|
+
displayName: nonBlankStringSchema.optional(),
|
|
499
|
+
email: nonBlankStringSchema.max(320),
|
|
500
|
+
id: exactNonBlankStringSchema,
|
|
501
|
+
identities: z.array(identitySchema).max(100),
|
|
502
|
+
/** True only for Junior admins. Missing means not an admin. */
|
|
503
|
+
isAdmin: z.literal(true).optional()
|
|
492
504
|
}).strict();
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
if (value.length > 512) {
|
|
533
|
-
ctx.addIssue({
|
|
534
|
-
code: z7.ZodIssueCode.custom,
|
|
535
|
-
message: "Dispatch metadata value exceeds the maximum length",
|
|
536
|
-
path: [key]
|
|
537
|
-
});
|
|
538
|
-
}
|
|
539
|
-
}
|
|
505
|
+
const dispatchMetadataSchema = z.record(z.string(), z.string()).superRefine((metadata, ctx) => {
|
|
506
|
+
const entries = Object.entries(metadata);
|
|
507
|
+
if (entries.length > 20) {
|
|
508
|
+
ctx.addIssue({
|
|
509
|
+
code: z.ZodIssueCode.custom,
|
|
510
|
+
message: "Dispatch metadata has too many keys"
|
|
511
|
+
});
|
|
512
|
+
return;
|
|
513
|
+
}
|
|
514
|
+
for (const [key, value] of entries) {
|
|
515
|
+
if (!key.trim()) {
|
|
516
|
+
ctx.addIssue({
|
|
517
|
+
code: z.ZodIssueCode.custom,
|
|
518
|
+
message: "Dispatch metadata values must be strings",
|
|
519
|
+
path: [key]
|
|
520
|
+
});
|
|
521
|
+
continue;
|
|
522
|
+
}
|
|
523
|
+
if (key.length > 128) ctx.addIssue({
|
|
524
|
+
code: z.ZodIssueCode.custom,
|
|
525
|
+
message: "Dispatch metadata key exceeds the maximum length",
|
|
526
|
+
path: [key]
|
|
527
|
+
});
|
|
528
|
+
if (/[\r\n]/.test(key)) ctx.addIssue({
|
|
529
|
+
code: z.ZodIssueCode.custom,
|
|
530
|
+
message: "Dispatch metadata keys must be single-line strings",
|
|
531
|
+
path: [key]
|
|
532
|
+
});
|
|
533
|
+
if (/[\r\n]/.test(value)) ctx.addIssue({
|
|
534
|
+
code: z.ZodIssueCode.custom,
|
|
535
|
+
message: "Dispatch metadata values must be single-line strings",
|
|
536
|
+
path: [key]
|
|
537
|
+
});
|
|
538
|
+
if (value.length > 512) ctx.addIssue({
|
|
539
|
+
code: z.ZodIssueCode.custom,
|
|
540
|
+
message: "Dispatch metadata value exceeds the maximum length",
|
|
541
|
+
path: [key]
|
|
542
|
+
});
|
|
543
|
+
}
|
|
540
544
|
});
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
545
|
+
/** Compact destination-visible context explaining what produced a reply. */
|
|
546
|
+
const replyAttributionSchema = z.object({
|
|
547
|
+
label: exactNonBlankStringSchema.pipe(z.string().max(48)).refine((value) => !/[\r\n]/.test(value)),
|
|
548
|
+
detail: exactNonBlankStringSchema.pipe(z.string().max(128)).refine((value) => !/[\r\n]/.test(value)).optional()
|
|
544
549
|
}).strict();
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
550
|
+
/** Plugin dispatch request accepted by Junior core. */
|
|
551
|
+
const dispatchOptionsSchema = z.object({
|
|
552
|
+
idempotencyKey: nonBlankStringSchema.pipe(z.string().max(512)),
|
|
553
|
+
credentialSubject: pluginCredentialSubjectSchema.optional(),
|
|
554
|
+
destination: slackDestinationSchema,
|
|
555
|
+
destinationVisibility: destinationVisibilitySchema,
|
|
556
|
+
input: nonBlankStringSchema.pipe(z.string().max(32e3)),
|
|
557
|
+
metadata: dispatchMetadataSchema.optional(),
|
|
558
|
+
replyAttribution: replyAttributionSchema.optional()
|
|
553
559
|
}).strict();
|
|
554
|
-
|
|
555
560
|
// src/context.ts
|
|
561
|
+
/** Build a normalized Slack source from runtime-owned Slack coordinates. */
|
|
556
562
|
function createSlackSource(input) {
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
563
|
+
return {
|
|
564
|
+
kind: "slack",
|
|
565
|
+
visibility: input.visibility,
|
|
566
|
+
teamId: input.teamId,
|
|
567
|
+
channelId: input.channelId,
|
|
568
|
+
...input.messageTs ? { messageTs: input.messageTs } : void 0,
|
|
569
|
+
...input.threadTs ? { threadTs: input.threadTs } : void 0
|
|
570
|
+
};
|
|
565
571
|
}
|
|
572
|
+
/** Build a normalized local source from a local conversation id. */
|
|
566
573
|
function createLocalSource(conversationId) {
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
574
|
+
return {
|
|
575
|
+
kind: "local",
|
|
576
|
+
visibility: "private",
|
|
577
|
+
conversationId
|
|
578
|
+
};
|
|
572
579
|
}
|
|
580
|
+
/** Build a normalized web/dashboard source from a conversation id. */
|
|
573
581
|
function createWebSource(conversationId, visibility = "public") {
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
582
|
+
return {
|
|
583
|
+
kind: "web",
|
|
584
|
+
visibility,
|
|
585
|
+
conversationId
|
|
586
|
+
};
|
|
579
587
|
}
|
|
588
|
+
/** Build a normalized Event Source from one matched event. */
|
|
580
589
|
function createEventSource(input) {
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
590
|
+
return {
|
|
591
|
+
kind: "event",
|
|
592
|
+
eventKey: input.eventKey,
|
|
593
|
+
eventType: input.eventType,
|
|
594
|
+
identifier: input.identifier,
|
|
595
|
+
namespace: input.namespace
|
|
596
|
+
};
|
|
588
597
|
}
|
|
598
|
+
/** Return whether a source is private to a person or restricted group. */
|
|
589
599
|
function isPrivateSource(source) {
|
|
590
|
-
|
|
600
|
+
return "visibility" in source && source.visibility === "private";
|
|
591
601
|
}
|
|
602
|
+
/** Return the stable source identity used for idempotency and attribution. */
|
|
592
603
|
function getSourceKey(source) {
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
case "event_automation":
|
|
608
|
-
case "plugin_dispatch":
|
|
609
|
-
case "agent_invocation":
|
|
610
|
-
return void 0;
|
|
611
|
-
}
|
|
604
|
+
switch (source.kind) {
|
|
605
|
+
case "web":
|
|
606
|
+
case "local": return source.conversationId;
|
|
607
|
+
case "slack": {
|
|
608
|
+
const messageKey = source.threadTs ?? source.messageTs;
|
|
609
|
+
if (!messageKey) return;
|
|
610
|
+
return `slack:${source.teamId}:${source.channelId}:${messageKey}`;
|
|
611
|
+
}
|
|
612
|
+
case "event": return `event:${source.namespace}:${source.eventKey}`;
|
|
613
|
+
case "scheduled_automation":
|
|
614
|
+
case "event_automation":
|
|
615
|
+
case "plugin_dispatch":
|
|
616
|
+
case "agent_invocation": return;
|
|
617
|
+
}
|
|
612
618
|
}
|
|
619
|
+
/** Narrow a runtime destination to the Slack-specific address shape. */
|
|
613
620
|
function isSlackDestination(destination) {
|
|
614
|
-
|
|
621
|
+
return destination?.platform === "slack";
|
|
615
622
|
}
|
|
616
|
-
|
|
617
623
|
// src/prompt.ts
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
kind: promptContextKindSchema,
|
|
625
|
-
version: z8.number().int().positive(),
|
|
626
|
-
content: z8.record(z8.string(), z8.unknown())
|
|
624
|
+
const promptContextKindSchema = z.string().trim().min(1).max(64).regex(/^[a-z][a-z0-9_-]*$/);
|
|
625
|
+
const promptMessageSchema = z.object({ text: z.string().trim().min(1).max(8e3) }).strict();
|
|
626
|
+
const promptContextSchema = z.object({
|
|
627
|
+
kind: promptContextKindSchema,
|
|
628
|
+
version: z.number().int().positive(),
|
|
629
|
+
content: z.record(z.string(), z.unknown())
|
|
627
630
|
}).strict();
|
|
631
|
+
/** Define one typed, versioned plugin context contribution. */
|
|
628
632
|
function definePromptContext(definition) {
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
633
|
+
const identity = promptContextSchema.pick({
|
|
634
|
+
kind: true,
|
|
635
|
+
version: true
|
|
636
|
+
}).parse({
|
|
637
|
+
kind: definition.kind,
|
|
638
|
+
version: definition.version
|
|
639
|
+
});
|
|
640
|
+
return (content) => {
|
|
641
|
+
const parsed = definition.schema.parse(content);
|
|
642
|
+
return {
|
|
643
|
+
context: {
|
|
644
|
+
...identity,
|
|
645
|
+
content: parsed
|
|
646
|
+
},
|
|
647
|
+
renderPrompt: () => definition.renderPrompt(parsed)
|
|
648
|
+
};
|
|
649
|
+
};
|
|
637
650
|
}
|
|
638
|
-
|
|
639
651
|
// src/events.ts
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
JSON.stringify(value)
|
|
656
|
-
).byteLength;
|
|
657
|
-
if (jsonBytes > EVENT_DATA_MAX_JSON_BYTES) {
|
|
658
|
-
context.addIssue({
|
|
659
|
-
code: "custom",
|
|
660
|
-
message: `Event data may be at most ${EVENT_DATA_MAX_JSON_BYTES} JSON bytes.`
|
|
661
|
-
});
|
|
662
|
-
}
|
|
652
|
+
const EVENT_SUMMARY_MAX_LENGTH = 4e3;
|
|
653
|
+
const EVENT_TEXT_MAX_LENGTH = 8e3;
|
|
654
|
+
const EVENT_DATA_MAX_KEYS = 32;
|
|
655
|
+
const EVENT_DATA_MAX_JSON_BYTES = 4e3;
|
|
656
|
+
const EVENT_GUIDANCE_MAX_LENGTH = 1e3;
|
|
657
|
+
/** Small trusted data from the plugin. The agent should not look these up again. */
|
|
658
|
+
const eventDataSchema = z.record(z.string(), z.unknown()).superRefine((value, context) => {
|
|
659
|
+
if (Object.keys(value).length > 32) context.addIssue({
|
|
660
|
+
code: "custom",
|
|
661
|
+
message: `Event data may include at most 32 keys.`
|
|
662
|
+
});
|
|
663
|
+
if (new TextEncoder().encode(JSON.stringify(value)).byteLength > 4e3) context.addIssue({
|
|
664
|
+
code: "custom",
|
|
665
|
+
message: `Event data may be at most ${EVENT_DATA_MAX_JSON_BYTES} JSON bytes.`
|
|
666
|
+
});
|
|
663
667
|
});
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
);
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
668
|
+
/** Canonical dotted event type published and selected across plugins. */
|
|
669
|
+
const eventTypeSchema = z.string().regex(/^[a-z][a-z0-9_-]*(?:\.[a-z][a-z0-9_-]*)+$/).describe("Canonical dotted event type, such as issue.closed or pull_request.review.changes_requested.");
|
|
670
|
+
const resourceTypeSchema = z.string().regex(/^[a-z][a-z0-9_]*$/).describe("Canonical plugin-defined resource type, such as issue or pull_request.");
|
|
671
|
+
const EVENT_MATCH_FIELD_NAME = /^[a-z][a-zA-Z0-9]*$/;
|
|
672
|
+
/** One exact value a watch or event automation may require on trusted event data. */
|
|
673
|
+
const eventMatchFieldSchema = z.object({
|
|
674
|
+
kind: z.enum([
|
|
675
|
+
"boolean",
|
|
676
|
+
"string",
|
|
677
|
+
"number"
|
|
678
|
+
]),
|
|
679
|
+
description: z.string().trim().min(1).max(200),
|
|
680
|
+
enum: z.array(z.string().min(1)).min(1).optional()
|
|
675
681
|
}).strict().superRefine((field, context) => {
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
});
|
|
682
|
-
}
|
|
682
|
+
if (field.enum && field.kind !== "string") context.addIssue({
|
|
683
|
+
code: "custom",
|
|
684
|
+
message: "Event match field enum requires kind \"string\".",
|
|
685
|
+
path: ["enum"]
|
|
686
|
+
});
|
|
683
687
|
});
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
});
|
|
690
|
-
}
|
|
688
|
+
const eventMatchFieldsSchema = z.record(z.string().regex(EVENT_MATCH_FIELD_NAME), eventMatchFieldSchema).superRefine((fields, context) => {
|
|
689
|
+
if (Object.keys(fields).length > 32) context.addIssue({
|
|
690
|
+
code: "custom",
|
|
691
|
+
message: `Event match keys may include at most 32 keys.`
|
|
692
|
+
});
|
|
691
693
|
});
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
code: "custom",
|
|
712
|
-
message: `Event match field "${key}" cannot use a boolean list.`,
|
|
713
|
-
path: [key]
|
|
714
|
-
});
|
|
715
|
-
}
|
|
716
|
-
}
|
|
694
|
+
/** Exact trusted values required before a watch or event automation runs. */
|
|
695
|
+
const eventMatchSchema = z.record(z.string().regex(EVENT_MATCH_FIELD_NAME), z.union([
|
|
696
|
+
z.boolean(),
|
|
697
|
+
z.number().finite(),
|
|
698
|
+
z.string().min(1),
|
|
699
|
+
z.array(z.union([z.number().finite(), z.string().min(1)])).min(1)
|
|
700
|
+
])).superRefine((match, context) => {
|
|
701
|
+
if (Object.keys(match).length > 32) context.addIssue({
|
|
702
|
+
code: "custom",
|
|
703
|
+
message: `Event match may include at most 32 keys.`
|
|
704
|
+
});
|
|
705
|
+
for (const [key, value] of Object.entries(match)) {
|
|
706
|
+
if (!Array.isArray(value)) continue;
|
|
707
|
+
if (value.some((entry) => typeof entry === "boolean")) context.addIssue({
|
|
708
|
+
code: "custom",
|
|
709
|
+
message: `Event match field "${key}" cannot use a boolean list.`,
|
|
710
|
+
path: [key]
|
|
711
|
+
});
|
|
712
|
+
}
|
|
717
713
|
});
|
|
718
714
|
function stableMatchValue(value) {
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
return String(left).localeCompare(String(right));
|
|
725
|
-
});
|
|
715
|
+
if (!Array.isArray(value)) return value;
|
|
716
|
+
return [...value].sort((left, right) => {
|
|
717
|
+
if (typeof left === "number" && typeof right === "number") return left - right;
|
|
718
|
+
return String(left).localeCompare(String(right));
|
|
719
|
+
});
|
|
726
720
|
}
|
|
721
|
+
/** Stable JSON for one match object. List order does not matter. */
|
|
727
722
|
function stableEventMatchKey(match) {
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
Object.fromEntries(
|
|
731
|
-
Object.entries(match).sort(([left], [right]) => left.localeCompare(right)).map(([key, value]) => [key, stableMatchValue(value)])
|
|
732
|
-
)
|
|
733
|
-
);
|
|
723
|
+
if (!match || Object.keys(match).length === 0) return "";
|
|
724
|
+
return JSON.stringify(Object.fromEntries(Object.entries(match).sort(([left], [right]) => left.localeCompare(right)).map(([key, value]) => [key, stableMatchValue(value)])));
|
|
734
725
|
}
|
|
726
|
+
/** Return whether trusted event data matches one exact match object. */
|
|
735
727
|
function eventMatches(match, data) {
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
728
|
+
if (!match || Object.keys(match).length === 0) return true;
|
|
729
|
+
if (!data) return false;
|
|
730
|
+
for (const [key, expected] of Object.entries(match)) {
|
|
731
|
+
const actual = data[key];
|
|
732
|
+
if (actual === void 0) return false;
|
|
733
|
+
if (Array.isArray(expected)) {
|
|
734
|
+
if (!expected.some((value) => Object.is(value, actual))) return false;
|
|
735
|
+
continue;
|
|
736
|
+
}
|
|
737
|
+
if (!Object.is(expected, actual)) return false;
|
|
738
|
+
}
|
|
739
|
+
return true;
|
|
748
740
|
}
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
741
|
+
/** The identifier shape of one resource type. */
|
|
742
|
+
const eventIdentifierSchema = z.object({
|
|
743
|
+
/** Shown to the agent, such as "owner/repo#number". */
|
|
744
|
+
format: z.string().trim().min(1).max(200),
|
|
745
|
+
/** Matches a normalized identifier of this resource type. */
|
|
746
|
+
pattern: z.instanceof(RegExp)
|
|
754
747
|
}).strict();
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
eventTypeSchema,
|
|
763
|
-
z9.string().trim().min(1).max(EVENT_GUIDANCE_MAX_LENGTH)
|
|
764
|
-
).optional()
|
|
748
|
+
const pluginEventTypeSchema = z.object({
|
|
749
|
+
type: resourceTypeSchema,
|
|
750
|
+
identifier: eventIdentifierSchema.optional(),
|
|
751
|
+
supportedEvents: z.array(eventTypeSchema).min(1),
|
|
752
|
+
suggestedEvents: z.array(eventTypeSchema).optional(),
|
|
753
|
+
matchFields: eventMatchFieldsSchema.optional(),
|
|
754
|
+
guidance: z.record(eventTypeSchema, z.string().trim().min(1).max(EVENT_GUIDANCE_MAX_LENGTH)).optional()
|
|
765
755
|
}).strict().superRefine((resourceType, context) => {
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
}
|
|
795
|
-
if (!supported.has(eventType)) {
|
|
796
|
-
context.addIssue({
|
|
797
|
-
code: "custom",
|
|
798
|
-
message: `Suggested event type "${eventType}" is not supported.`,
|
|
799
|
-
path: ["suggestedEvents", index]
|
|
800
|
-
});
|
|
801
|
-
}
|
|
802
|
-
suggested.add(eventType);
|
|
803
|
-
});
|
|
756
|
+
const supported = /* @__PURE__ */ new Set();
|
|
757
|
+
resourceType.supportedEvents.forEach((eventType, index) => {
|
|
758
|
+
if (supported.has(eventType)) context.addIssue({
|
|
759
|
+
code: "custom",
|
|
760
|
+
message: `Duplicate supported event type "${eventType}".`,
|
|
761
|
+
path: ["supportedEvents", index]
|
|
762
|
+
});
|
|
763
|
+
supported.add(eventType);
|
|
764
|
+
});
|
|
765
|
+
for (const eventType of Object.keys(resourceType.guidance ?? {})) if (!supported.has(eventType)) context.addIssue({
|
|
766
|
+
code: "custom",
|
|
767
|
+
message: `Guidance event type "${eventType}" is not supported.`,
|
|
768
|
+
path: ["guidance", eventType]
|
|
769
|
+
});
|
|
770
|
+
const suggested = /* @__PURE__ */ new Set();
|
|
771
|
+
resourceType.suggestedEvents?.forEach((eventType, index) => {
|
|
772
|
+
if (suggested.has(eventType)) context.addIssue({
|
|
773
|
+
code: "custom",
|
|
774
|
+
message: `Duplicate suggested event type "${eventType}".`,
|
|
775
|
+
path: ["suggestedEvents", index]
|
|
776
|
+
});
|
|
777
|
+
if (!supported.has(eventType)) context.addIssue({
|
|
778
|
+
code: "custom",
|
|
779
|
+
message: `Suggested event type "${eventType}" is not supported.`,
|
|
780
|
+
path: ["suggestedEvents", index]
|
|
781
|
+
});
|
|
782
|
+
suggested.add(eventType);
|
|
783
|
+
});
|
|
804
784
|
});
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
785
|
+
const pluginEventsSchema = z.object({
|
|
786
|
+
resourceTypes: z.array(pluginEventTypeSchema).min(1),
|
|
787
|
+
isEnabled: z.function({
|
|
788
|
+
input: [],
|
|
789
|
+
output: z.boolean()
|
|
790
|
+
}).optional(),
|
|
791
|
+
normalizeIdentifier: z.function({
|
|
792
|
+
input: [z.string()],
|
|
793
|
+
output: z.string()
|
|
794
|
+
}).optional()
|
|
809
795
|
}).strict().superRefine((registration, context) => {
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
796
|
+
const seen = /* @__PURE__ */ new Set();
|
|
797
|
+
registration.resourceTypes.forEach((resourceType, index) => {
|
|
798
|
+
if (seen.has(resourceType.type)) context.addIssue({
|
|
799
|
+
code: "custom",
|
|
800
|
+
message: `Duplicate resource type "${resourceType.type}".`,
|
|
801
|
+
path: [
|
|
802
|
+
"resourceTypes",
|
|
803
|
+
index,
|
|
804
|
+
"type"
|
|
805
|
+
]
|
|
806
|
+
});
|
|
807
|
+
seen.add(resourceType.type);
|
|
808
|
+
});
|
|
821
809
|
});
|
|
810
|
+
/** Apply a plugin's identifier convention at event boundaries. */
|
|
822
811
|
function normalizeEventIdentifier(registration, identifier) {
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
}
|
|
828
|
-
return normalized;
|
|
812
|
+
const trimmed = identifier.trim();
|
|
813
|
+
const normalized = (registration?.normalizeIdentifier?.(trimmed) ?? trimmed).trim();
|
|
814
|
+
if (!normalized) throw new Error("Event identifier must not normalize to empty");
|
|
815
|
+
return normalized;
|
|
829
816
|
}
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
817
|
+
const subscribableResourceSchema = z.object({
|
|
818
|
+
identifier: z.string().min(1),
|
|
819
|
+
label: z.string().min(1),
|
|
820
|
+
namespace: z.string().min(1),
|
|
821
|
+
suggestedEvents: z.array(eventTypeSchema).optional(),
|
|
822
|
+
supportedEvents: z.array(eventTypeSchema),
|
|
823
|
+
type: resourceTypeSchema
|
|
837
824
|
}).strict();
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
825
|
+
/** Result returned after a temporary watch is created. */
|
|
826
|
+
const watchResultSchema = z.object({
|
|
827
|
+
events: z.array(eventTypeSchema).min(1),
|
|
828
|
+
id: z.string().min(1)
|
|
841
829
|
}).strict();
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
830
|
+
/**
|
|
831
|
+
* One person involved in an Event, named by a provider identity or an email.
|
|
832
|
+
* Core resolves linked people to mentions. It drops people it cannot resolve.
|
|
833
|
+
*/
|
|
834
|
+
const eventPersonSchema = z.union([z.object({
|
|
835
|
+
provider: z.string().min(1),
|
|
836
|
+
handle: z.string().min(1)
|
|
837
|
+
}).strict(), z.object({ email: z.string().trim().min(3) }).strict()]);
|
|
838
|
+
const eventInputSchema = z.object({
|
|
839
|
+
objectType: objectTypeSchema.optional(),
|
|
840
|
+
eventKey: z.string().min(1),
|
|
841
|
+
eventType: eventTypeSchema,
|
|
842
|
+
identifier: z.string().min(1),
|
|
843
|
+
occurredAtMs: z.number().finite(),
|
|
844
|
+
terminal: z.boolean().optional(),
|
|
845
|
+
trustedSummary: z.string().min(1).transform((value) => value.slice(0, EVENT_SUMMARY_MAX_LENGTH)),
|
|
846
|
+
/** Trusted structured facts. Prefer ids and urls over long prose. */
|
|
847
|
+
data: eventDataSchema.optional(),
|
|
848
|
+
untrustedText: z.string().transform((value) => value.slice(0, EVENT_TEXT_MAX_LENGTH)).optional(),
|
|
849
|
+
/** People involved in the change. Watch Events list them as mentions. */
|
|
850
|
+
people: z.array(eventPersonSchema).max(20).optional()
|
|
862
851
|
}).strict();
|
|
863
|
-
|
|
864
|
-
namespace: z9.string().min(1)
|
|
865
|
-
});
|
|
866
|
-
|
|
852
|
+
const eventSchema = eventInputSchema.extend({ namespace: z.string().min(1) });
|
|
867
853
|
// src/tasks.ts
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
854
|
+
/**
|
|
855
|
+
* Public plugin background-task contracts.
|
|
856
|
+
*
|
|
857
|
+
* Plugins register small task handlers. Junior core owns scheduling, delivery,
|
|
858
|
+
* retries, and the bounded run projection.
|
|
859
|
+
*/
|
|
860
|
+
/**
|
|
861
|
+
* Runtime-owned provenance for a transcript message: whether it is a durable
|
|
862
|
+
* instruction or ambient context, plus the actor identity when known. Missing
|
|
863
|
+
* provenance on an entry means unattributed context.
|
|
864
|
+
*/
|
|
865
|
+
const pluginRunTranscriptProvenanceSchema = z.object({
|
|
866
|
+
authority: z.enum(["instruction", "context"]),
|
|
867
|
+
actor: actorSchema.optional()
|
|
872
868
|
}).strict();
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
transcript: z10.array(pluginRunTranscriptEntrySchema)
|
|
869
|
+
/** One normalized transcript entry from the completed run exposed to plugin tasks. */
|
|
870
|
+
const pluginRunTranscriptEntrySchema = z.discriminatedUnion("type", [z.object({
|
|
871
|
+
type: z.literal("message"),
|
|
872
|
+
role: z.enum(["user", "assistant"]),
|
|
873
|
+
text: z.string().min(1),
|
|
874
|
+
provenance: pluginRunTranscriptProvenanceSchema.optional(),
|
|
875
|
+
isRunActor: z.boolean().optional()
|
|
876
|
+
}).strict(), z.object({
|
|
877
|
+
type: z.literal("toolResult"),
|
|
878
|
+
toolName: z.string().min(1),
|
|
879
|
+
isError: z.boolean(),
|
|
880
|
+
text: z.string().min(1).optional()
|
|
881
|
+
}).strict()]);
|
|
882
|
+
/** Runtime-owned completed-run projection exposed to plugin tasks. */
|
|
883
|
+
const pluginRunContextSchema = z.object({
|
|
884
|
+
/** User linked to the Actor, when known. */
|
|
885
|
+
actorUserId: z.string().min(1).optional(),
|
|
886
|
+
completedAtMs: z.number().finite(),
|
|
887
|
+
conversationId: z.string().min(1),
|
|
888
|
+
destination: destinationSchema,
|
|
889
|
+
/** Location associated with this Conversation. */
|
|
890
|
+
locationId: z.string().min(1).optional(),
|
|
891
|
+
/**
|
|
892
|
+
* All distinct actors annotated on this run's committed instruction-authority
|
|
893
|
+
* messages, in first-seen order. Attribution provenance only, never an
|
|
894
|
+
* authority source: a plugin must not treat membership here as credential,
|
|
895
|
+
* subject, or scope ownership. Derived from full-run provenance, so it can
|
|
896
|
+
* exceed the actors visible in the transcript slice. Usually `[run.actor]`;
|
|
897
|
+
* possibly empty for system runs with no human instructions.
|
|
898
|
+
*/
|
|
899
|
+
actors: z.array(actorSchema),
|
|
900
|
+
/**
|
|
901
|
+
* The single actor this run executes as. Absent only for actor-less legacy
|
|
902
|
+
* system records, so authority-sensitive plugins must fail closed.
|
|
903
|
+
*/
|
|
904
|
+
actor: actorSchema.optional(),
|
|
905
|
+
runId: z.string().min(1),
|
|
906
|
+
source: sourceSchema,
|
|
907
|
+
transcript: z.array(pluginRunTranscriptEntrySchema)
|
|
913
908
|
}).strict();
|
|
914
|
-
|
|
915
909
|
// src/tools.ts
|
|
916
|
-
|
|
910
|
+
/** Thrown when a plugin tool rejects invalid model or user input. */
|
|
917
911
|
var PluginToolInputError = class extends Error {
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
912
|
+
constructor(message, options) {
|
|
913
|
+
super(message, options);
|
|
914
|
+
this.name = "PluginToolInputError";
|
|
915
|
+
}
|
|
922
916
|
};
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
]);
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
917
|
+
const pluginToolContentSchema = z.discriminatedUnion("type", [z.object({
|
|
918
|
+
type: z.literal("text"),
|
|
919
|
+
text: z.string()
|
|
920
|
+
}).strict(), z.object({
|
|
921
|
+
type: z.literal("image"),
|
|
922
|
+
data: z.string(),
|
|
923
|
+
mimeType: z.string()
|
|
924
|
+
}).strict()]);
|
|
925
|
+
const pluginToolContinuationSchema = z.object({
|
|
926
|
+
arguments: z.record(z.string(), z.unknown()),
|
|
927
|
+
reason: z.string().min(1).optional()
|
|
934
928
|
}).strict();
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
929
|
+
/** Shared optional fields for canonical plugin tool outputs. */
|
|
930
|
+
const pluginToolOutputSchema = z.object({
|
|
931
|
+
/** Object results to save and show with the next reply. Omit for silent updates. */
|
|
932
|
+
objectAnnotations: z.array(objectAnnotationSchema).optional(),
|
|
933
|
+
target: z.string().min(1).optional(),
|
|
934
|
+
truncated: z.boolean().optional(),
|
|
935
|
+
continuation: pluginToolContinuationSchema.optional()
|
|
941
936
|
}).passthrough();
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
937
|
+
/**
|
|
938
|
+
* Tool-declared approval mode.
|
|
939
|
+
*
|
|
940
|
+
* `auto` delegates to core policy, `review` enters Guardian review, and
|
|
941
|
+
* `approve` permits execution without review. Plugin tool helpers normalize
|
|
942
|
+
* omission to `auto`.
|
|
943
|
+
*
|
|
944
|
+
* Core resolves the effective mode immediately before execution.
|
|
945
|
+
*/
|
|
946
|
+
const toolApprovalModeSchema = z.enum([
|
|
947
|
+
"auto",
|
|
948
|
+
"review",
|
|
949
|
+
"approve"
|
|
950
|
+
]);
|
|
951
|
+
const REQUIRED_TOOL_ANNOTATION_KEYS = [
|
|
952
|
+
"destructiveHint",
|
|
953
|
+
"idempotentHint",
|
|
954
|
+
"openWorldHint",
|
|
955
|
+
"readOnlyHint"
|
|
948
956
|
];
|
|
957
|
+
/** Return behavioral annotation keys that a tool did not declare. */
|
|
949
958
|
function missingToolAnnotationKeys(annotations) {
|
|
950
|
-
|
|
951
|
-
(key) => typeof annotations?.[key] !== "boolean"
|
|
952
|
-
);
|
|
959
|
+
return REQUIRED_TOOL_ANNOTATION_KEYS.filter((key) => typeof annotations?.[key] !== "boolean");
|
|
953
960
|
}
|
|
954
961
|
function isPluginToolOutputEnvelope(value) {
|
|
955
|
-
|
|
962
|
+
return value !== null && typeof value === "object" && Array.isArray(value.content) && "details" in value;
|
|
956
963
|
}
|
|
957
964
|
function formatZodPath(path) {
|
|
958
|
-
|
|
965
|
+
return path.length > 0 ? path.map(String).join(".") : "root";
|
|
959
966
|
}
|
|
960
967
|
function formatPluginToolInputError(error) {
|
|
961
|
-
|
|
962
|
-
return `Invalid tool arguments: ${details || "input did not match schema"}`;
|
|
968
|
+
return `Invalid tool arguments: ${error.issues.slice(0, 5).map((issue) => `${formatZodPath(issue.path)}: ${issue.message}`).join("; ") || "input did not match schema"}`;
|
|
963
969
|
}
|
|
964
970
|
function parsePluginToolInput(schema, args) {
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
cause: result.error
|
|
969
|
-
});
|
|
970
|
-
}
|
|
971
|
-
return result.data;
|
|
971
|
+
const result = schema.safeParse(args);
|
|
972
|
+
if (!result.success) throw new PluginToolInputError(formatPluginToolInputError(result.error), { cause: result.error });
|
|
973
|
+
return result.data;
|
|
972
974
|
}
|
|
973
975
|
function createZodTool(definition, helperName) {
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
...execute ? {
|
|
1005
|
-
async execute(input, options) {
|
|
1006
|
-
const result = await execute(
|
|
1007
|
-
input,
|
|
1008
|
-
options
|
|
1009
|
-
);
|
|
1010
|
-
if (isPluginToolOutputEnvelope(result)) {
|
|
1011
|
-
return {
|
|
1012
|
-
content: z11.array(pluginToolContentSchema).parse(result.content),
|
|
1013
|
-
details: outputSchema.parse(result.details)
|
|
1014
|
-
};
|
|
1015
|
-
}
|
|
1016
|
-
return outputSchema.parse(result);
|
|
1017
|
-
}
|
|
1018
|
-
} : void 0
|
|
1019
|
-
};
|
|
976
|
+
const { inputSchema, outputSchema, prepareArguments, execute, ...tool } = definition;
|
|
977
|
+
let modelInputSchema;
|
|
978
|
+
let modelOutputSchema;
|
|
979
|
+
try {
|
|
980
|
+
modelInputSchema = z.toJSONSchema(inputSchema);
|
|
981
|
+
} catch (error) {
|
|
982
|
+
throw new TypeError(`${helperName}() inputSchema must be representable as JSON Schema.`, { cause: error });
|
|
983
|
+
}
|
|
984
|
+
try {
|
|
985
|
+
modelOutputSchema = z.toJSONSchema(outputSchema);
|
|
986
|
+
} catch (error) {
|
|
987
|
+
throw new TypeError(`${helperName}() outputSchema must be representable as JSON Schema.`, { cause: error });
|
|
988
|
+
}
|
|
989
|
+
return {
|
|
990
|
+
...tool,
|
|
991
|
+
approvalMode: tool.approvalMode ?? "auto",
|
|
992
|
+
inputSchema: modelInputSchema,
|
|
993
|
+
outputSchema: modelOutputSchema,
|
|
994
|
+
prepareArguments(args) {
|
|
995
|
+
return parsePluginToolInput(inputSchema, prepareArguments ? prepareArguments(args) : args);
|
|
996
|
+
},
|
|
997
|
+
...execute ? { async execute(input, options) {
|
|
998
|
+
const result = await execute(input, options);
|
|
999
|
+
if (isPluginToolOutputEnvelope(result)) return {
|
|
1000
|
+
content: z.array(pluginToolContentSchema).parse(result.content),
|
|
1001
|
+
details: outputSchema.parse(result.details)
|
|
1002
|
+
};
|
|
1003
|
+
return outputSchema.parse(result);
|
|
1004
|
+
} } : void 0
|
|
1005
|
+
};
|
|
1020
1006
|
}
|
|
1007
|
+
/** Define a plugin tool with Zod input parsing and validated structured results. */
|
|
1021
1008
|
function zodTool(definition) {
|
|
1022
|
-
|
|
1009
|
+
return createZodTool(definition, "zodTool");
|
|
1023
1010
|
}
|
|
1011
|
+
/** Define a plugin tool with Zod input parsing and the structured result contract. */
|
|
1024
1012
|
function definePluginTool(definition) {
|
|
1025
|
-
|
|
1013
|
+
return createZodTool(definition, "definePluginTool");
|
|
1026
1014
|
}
|
|
1027
|
-
|
|
1028
1015
|
// src/operations.ts
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
}).strict(),
|
|
1040
|
-
pluginName: nonBlankStringSchema
|
|
1016
|
+
/** Per-request context Junior passes to authenticated plugin product API routes. */
|
|
1017
|
+
const pluginApiRouteRequestContextSchema = z.object({
|
|
1018
|
+
auth: z.object({ user: z.object({
|
|
1019
|
+
email: z.string().nullable().optional(),
|
|
1020
|
+
emailVerified: z.boolean().optional(),
|
|
1021
|
+
/** Junior-wide admin role, read from the user record on each request. */
|
|
1022
|
+
isAdmin: z.boolean(),
|
|
1023
|
+
name: z.string().nullable().optional()
|
|
1024
|
+
}).strict() }).strict(),
|
|
1025
|
+
pluginName: nonBlankStringSchema
|
|
1041
1026
|
}).strict();
|
|
1042
|
-
|
|
1043
1027
|
// src/credentials.ts
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
provider: pluginProviderNameSchema,
|
|
1053
|
-
scope: nonBlankStringSchema.optional(),
|
|
1054
|
-
type: z13.literal("oauth")
|
|
1028
|
+
const pluginProviderNameSchema = z.string().regex(/^[a-z][a-z0-9-]*$/);
|
|
1029
|
+
const pluginGrantNameSchema = z.string().regex(/^[a-z][a-z0-9.-]*$/);
|
|
1030
|
+
const pluginGrantAccessSchema = z.union([z.literal("read"), z.literal("write")]);
|
|
1031
|
+
/** Runtime schema for provider authorization a plugin may request. */
|
|
1032
|
+
const pluginAuthorizationSchema = z.object({
|
|
1033
|
+
provider: pluginProviderNameSchema,
|
|
1034
|
+
scope: nonBlankStringSchema.optional(),
|
|
1035
|
+
type: z.literal("oauth")
|
|
1055
1036
|
}).strict();
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1037
|
+
/** Runtime schema for a provider account attached to stored OAuth tokens. */
|
|
1038
|
+
const pluginProviderAccountSchema = z.object({
|
|
1039
|
+
displayName: nonBlankStringSchema.optional(),
|
|
1040
|
+
handle: nonBlankStringSchema.optional(),
|
|
1041
|
+
id: nonBlankStringSchema,
|
|
1042
|
+
label: nonBlankStringSchema.optional(),
|
|
1043
|
+
url: nonBlankStringSchema.optional(),
|
|
1044
|
+
/**
|
|
1045
|
+
* Email addresses that the provider verified for this account. Junior
|
|
1046
|
+
* uses them only to link the account to a person and does not store them
|
|
1047
|
+
* with the tokens.
|
|
1048
|
+
*/
|
|
1049
|
+
verifiedEmails: z.array(nonBlankStringSchema).optional()
|
|
1062
1050
|
}).strict();
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1051
|
+
/** Runtime schema for OAuth tokens stored by the host for plugin credentials. */
|
|
1052
|
+
const pluginStoredTokensSchema = z.object({
|
|
1053
|
+
account: pluginProviderAccountSchema.optional(),
|
|
1054
|
+
accessToken: nonBlankStringSchema,
|
|
1055
|
+
expiresAt: z.number().finite().optional(),
|
|
1056
|
+
refreshToken: nonBlankStringSchema,
|
|
1057
|
+
refreshTokenExpiresAt: z.number().finite().optional(),
|
|
1058
|
+
scope: nonBlankStringSchema.optional()
|
|
1070
1059
|
}).strict();
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1060
|
+
/** Runtime schema for a plugin-defined outbound credential grant. */
|
|
1061
|
+
const pluginGrantSchema = z.object({
|
|
1062
|
+
access: pluginGrantAccessSchema,
|
|
1063
|
+
leaseScope: nonBlankStringSchema.optional(),
|
|
1064
|
+
name: pluginGrantNameSchema,
|
|
1065
|
+
reason: nonBlankStringSchema.optional(),
|
|
1066
|
+
requirements: z.array(nonBlankStringSchema).min(1).optional()
|
|
1077
1067
|
}).strict();
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1068
|
+
/** Runtime schema for plugin-issued header mutations. */
|
|
1069
|
+
const pluginCredentialHeaderTransformSchema = z.object({
|
|
1070
|
+
domain: z.string().min(1),
|
|
1071
|
+
headers: z.record(z.string(), z.string()).refine((headers) => Object.keys(headers).length > 0)
|
|
1081
1072
|
}).strict();
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1073
|
+
/** Runtime schema for a short-lived plugin-issued credential lease. */
|
|
1074
|
+
const pluginCredentialLeaseSchema = z.object({
|
|
1075
|
+
account: pluginProviderAccountSchema.optional(),
|
|
1076
|
+
authorization: pluginAuthorizationSchema.optional(),
|
|
1077
|
+
expiresAt: z.string().refine((value) => Number.isFinite(Date.parse(value))),
|
|
1078
|
+
headerTransforms: z.array(pluginCredentialHeaderTransformSchema).min(1)
|
|
1087
1079
|
}).strict();
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1080
|
+
/** Runtime schema for the result returned by a plugin credential hook. */
|
|
1081
|
+
const pluginCredentialResultSchema = z.discriminatedUnion("type", [
|
|
1082
|
+
z.object({
|
|
1083
|
+
lease: pluginCredentialLeaseSchema,
|
|
1084
|
+
type: z.literal("lease")
|
|
1085
|
+
}).strict(),
|
|
1086
|
+
z.object({
|
|
1087
|
+
authorization: pluginAuthorizationSchema.optional(),
|
|
1088
|
+
message: nonBlankStringSchema,
|
|
1089
|
+
type: z.literal("needed")
|
|
1090
|
+
}).strict(),
|
|
1091
|
+
z.object({
|
|
1092
|
+
message: nonBlankStringSchema,
|
|
1093
|
+
type: z.literal("unavailable")
|
|
1094
|
+
}).strict()
|
|
1102
1095
|
]);
|
|
1096
|
+
/** Interrupt sandbox egress so Junior can start provider authorization. */
|
|
1103
1097
|
var EgressAuthRequired = class extends Error {
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1098
|
+
authorization;
|
|
1099
|
+
constructor(message, options) {
|
|
1100
|
+
super(message, { cause: options?.cause });
|
|
1101
|
+
this.name = "EgressAuthRequired";
|
|
1102
|
+
this.authorization = options?.authorization;
|
|
1103
|
+
}
|
|
1110
1104
|
};
|
|
1105
|
+
/** Deny provider egress before Junior issues credentials for a disallowed operation. */
|
|
1111
1106
|
var EgressPolicyDenied = class extends Error {
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1107
|
+
constructor(message, options) {
|
|
1108
|
+
super(message, { cause: options?.cause });
|
|
1109
|
+
this.name = "EgressPolicyDenied";
|
|
1110
|
+
}
|
|
1116
1111
|
};
|
|
1117
|
-
|
|
1118
1112
|
// src/egress-policy.ts
|
|
1113
|
+
/**
|
|
1114
|
+
* Deny provider egress when a plugin policy does not allow the request.
|
|
1115
|
+
*
|
|
1116
|
+
* Call from a plugin `grantForEgress` hook before returning a write grant.
|
|
1117
|
+
*/
|
|
1119
1118
|
function enforceEgressPolicy(input) {
|
|
1120
|
-
|
|
1121
|
-
throw new EgressPolicyDenied(input.denialMessage);
|
|
1122
|
-
}
|
|
1119
|
+
if (!input.allowed) throw new EgressPolicyDenied(input.denialMessage);
|
|
1123
1120
|
}
|
|
1124
|
-
|
|
1125
1121
|
// src/registration.ts
|
|
1126
|
-
|
|
1127
|
-
|
|
1122
|
+
const PLUGIN_NAME_RE = /^[a-z][a-z0-9-]*$/;
|
|
1123
|
+
const USER_PAGE_ID_RE = /^[a-z][a-z0-9-]*$/;
|
|
1124
|
+
/** Define one Junior plugin registration for app and build-time wiring. */
|
|
1128
1125
|
function defineJuniorPlugin(plugin) {
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
throw new Error(
|
|
1164
|
-
`Junior plugin "${name}" manifest.description is required.`
|
|
1165
|
-
);
|
|
1166
|
-
}
|
|
1167
|
-
if (plugin.userPages !== void 0 && !Array.isArray(plugin.userPages)) {
|
|
1168
|
-
throw new Error(`Junior plugin "${name}" userPages must be an array.`);
|
|
1169
|
-
}
|
|
1170
|
-
if (plugin.conversationEvents !== void 0 && !Array.isArray(plugin.conversationEvents)) {
|
|
1171
|
-
throw new Error(
|
|
1172
|
-
`Junior plugin "${name}" conversationEvents must be an array.`
|
|
1173
|
-
);
|
|
1174
|
-
}
|
|
1175
|
-
if (plugin.events !== void 0) {
|
|
1176
|
-
const parsed = pluginEventsSchema.safeParse(plugin.events);
|
|
1177
|
-
if (!parsed.success) {
|
|
1178
|
-
throw new Error(`Junior plugin "${name}" events is invalid.`, {
|
|
1179
|
-
cause: parsed.error
|
|
1180
|
-
});
|
|
1181
|
-
}
|
|
1182
|
-
}
|
|
1183
|
-
const conversationEventIds = /* @__PURE__ */ new Set();
|
|
1184
|
-
for (const event of plugin.conversationEvents ?? []) {
|
|
1185
|
-
if (!event || typeof event !== "object" && typeof event !== "function" || typeof event.parse !== "function" || typeof event.renderEvent !== "function") {
|
|
1186
|
-
throw new Error(
|
|
1187
|
-
`Junior plugin "${name}" conversation event definitions must be created with defineConversationEvent().`
|
|
1188
|
-
);
|
|
1189
|
-
}
|
|
1190
|
-
const id = `${event.eventName}@${event.version}`;
|
|
1191
|
-
if (conversationEventIds.has(id)) {
|
|
1192
|
-
throw new Error(
|
|
1193
|
-
`Junior plugin "${name}" has duplicate conversation event "${id}".`
|
|
1194
|
-
);
|
|
1195
|
-
}
|
|
1196
|
-
conversationEventIds.add(id);
|
|
1197
|
-
}
|
|
1198
|
-
const userPageIds = /* @__PURE__ */ new Set();
|
|
1199
|
-
for (const page of plugin.userPages ?? []) {
|
|
1200
|
-
if (!page || typeof page !== "object") {
|
|
1201
|
-
throw new Error(`Junior plugin "${name}" user pages must be objects.`);
|
|
1202
|
-
}
|
|
1203
|
-
if (typeof page.id !== "string" || page.id.length > 64 || !USER_PAGE_ID_RE.test(page.id)) {
|
|
1204
|
-
throw new Error(
|
|
1205
|
-
`Junior plugin "${name}" user page id "${page.id}" must be a lowercase identifier.`
|
|
1206
|
-
);
|
|
1207
|
-
}
|
|
1208
|
-
if (userPageIds.has(page.id)) {
|
|
1209
|
-
throw new Error(
|
|
1210
|
-
`Junior plugin "${name}" has duplicate user page id "${page.id}".`
|
|
1211
|
-
);
|
|
1212
|
-
}
|
|
1213
|
-
if (typeof page.label !== "string" || !page.label.trim() || page.label.length > 80 || typeof page.description !== "string" || !page.description.trim() || page.description.length > 500) {
|
|
1214
|
-
throw new Error(
|
|
1215
|
-
`Junior plugin "${name}" user page "${page.id}" requires label and description.`
|
|
1216
|
-
);
|
|
1217
|
-
}
|
|
1218
|
-
if (page.navigation !== void 0 && page.navigation !== "primary" && page.navigation !== "profile" && page.navigation !== "admin") {
|
|
1219
|
-
throw new Error(
|
|
1220
|
-
`Junior plugin "${name}" user page "${page.id}" navigation must be "primary", "profile", or "admin".`
|
|
1221
|
-
);
|
|
1222
|
-
}
|
|
1223
|
-
if (typeof page.read !== "function") {
|
|
1224
|
-
throw new Error(
|
|
1225
|
-
`Junior plugin "${name}" user page "${page.id}" requires a read function.`
|
|
1226
|
-
);
|
|
1227
|
-
}
|
|
1228
|
-
userPageIds.add(page.id);
|
|
1229
|
-
}
|
|
1230
|
-
return {
|
|
1231
|
-
...plugin
|
|
1232
|
-
};
|
|
1126
|
+
if ("pluginConfig" in plugin) throw new Error("pluginConfig is no longer supported. Put runtime metadata in manifest or plugin registration fields.");
|
|
1127
|
+
if ("name" in plugin) throw new Error("defineJuniorPlugin() uses manifest.name for identity.");
|
|
1128
|
+
const manifest = plugin.manifest;
|
|
1129
|
+
if (!manifest) throw new Error("defineJuniorPlugin() requires a manifest. Use a package name string in defineJuniorPlugins([...]) for plugin.yaml packages.");
|
|
1130
|
+
const name = manifest.name;
|
|
1131
|
+
if (!name) throw new Error("Junior plugin manifest.name is required.");
|
|
1132
|
+
if (!PLUGIN_NAME_RE.test(name)) throw new Error(`Junior plugin registration name "${name}" must be a lowercase plugin identifier.`);
|
|
1133
|
+
if (name === "junior") throw new Error("Junior plugin registration name \"junior\" is reserved for native host events.");
|
|
1134
|
+
if (typeof manifest.displayName !== "string" || !manifest.displayName.trim()) throw new Error(`Junior plugin "${name}" manifest.displayName is required.`);
|
|
1135
|
+
if (typeof manifest.description !== "string" || !manifest.description.trim()) throw new Error(`Junior plugin "${name}" manifest.description is required.`);
|
|
1136
|
+
if (plugin.userPages !== void 0 && !Array.isArray(plugin.userPages)) throw new Error(`Junior plugin "${name}" userPages must be an array.`);
|
|
1137
|
+
if (plugin.conversationEvents !== void 0 && !Array.isArray(plugin.conversationEvents)) throw new Error(`Junior plugin "${name}" conversationEvents must be an array.`);
|
|
1138
|
+
if (plugin.events !== void 0) {
|
|
1139
|
+
const parsed = pluginEventsSchema.safeParse(plugin.events);
|
|
1140
|
+
if (!parsed.success) throw new Error(`Junior plugin "${name}" events is invalid.`, { cause: parsed.error });
|
|
1141
|
+
}
|
|
1142
|
+
const conversationEventIds = /* @__PURE__ */ new Set();
|
|
1143
|
+
for (const event of plugin.conversationEvents ?? []) {
|
|
1144
|
+
if (!event || typeof event !== "object" && typeof event !== "function" || typeof event.parse !== "function" || typeof event.renderEvent !== "function") throw new Error(`Junior plugin "${name}" conversation event definitions must be created with defineConversationEvent().`);
|
|
1145
|
+
const id = `${event.eventName}@${event.version}`;
|
|
1146
|
+
if (conversationEventIds.has(id)) throw new Error(`Junior plugin "${name}" has duplicate conversation event "${id}".`);
|
|
1147
|
+
conversationEventIds.add(id);
|
|
1148
|
+
}
|
|
1149
|
+
const userPageIds = /* @__PURE__ */ new Set();
|
|
1150
|
+
for (const page of plugin.userPages ?? []) {
|
|
1151
|
+
if (!page || typeof page !== "object") throw new Error(`Junior plugin "${name}" user pages must be objects.`);
|
|
1152
|
+
if (typeof page.id !== "string" || page.id.length > 64 || !USER_PAGE_ID_RE.test(page.id)) throw new Error(`Junior plugin "${name}" user page id "${page.id}" must be a lowercase identifier.`);
|
|
1153
|
+
if (userPageIds.has(page.id)) throw new Error(`Junior plugin "${name}" has duplicate user page id "${page.id}".`);
|
|
1154
|
+
if (typeof page.label !== "string" || !page.label.trim() || page.label.length > 80 || typeof page.description !== "string" || !page.description.trim() || page.description.length > 500) throw new Error(`Junior plugin "${name}" user page "${page.id}" requires label and description.`);
|
|
1155
|
+
if (page.navigation !== void 0 && page.navigation !== "primary" && page.navigation !== "profile" && page.navigation !== "admin") throw new Error(`Junior plugin "${name}" user page "${page.id}" navigation must be "primary", "profile", or "admin".`);
|
|
1156
|
+
if (typeof page.read !== "function") throw new Error(`Junior plugin "${name}" user page "${page.id}" requires a read function.`);
|
|
1157
|
+
userPageIds.add(page.id);
|
|
1158
|
+
}
|
|
1159
|
+
return { ...plugin };
|
|
1233
1160
|
}
|
|
1234
|
-
|
|
1235
1161
|
// src/user-pages.ts
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1162
|
+
/**
|
|
1163
|
+
* Core-rendered plugin user pages.
|
|
1164
|
+
*
|
|
1165
|
+
* Plugins own bounded data projection; Junior owns viewer authorization,
|
|
1166
|
+
* routing, response validation, and browser rendering.
|
|
1167
|
+
*/
|
|
1168
|
+
const userPageIdSchema = nonBlankStringSchema.max(64).regex(/^[a-z][a-z0-9-]*$/);
|
|
1169
|
+
const userPageLabelSchema = nonBlankStringSchema.max(80);
|
|
1170
|
+
const userPageDescriptionSchema = nonBlankStringSchema.max(500);
|
|
1171
|
+
const userPageNavigationSchema = z.enum([
|
|
1172
|
+
"primary",
|
|
1173
|
+
"profile",
|
|
1174
|
+
"admin"
|
|
1175
|
+
]);
|
|
1176
|
+
const pluginUserPageMetricSchema = z.object({
|
|
1177
|
+
detail: nonBlankStringSchema.max(500).optional(),
|
|
1178
|
+
label: nonBlankStringSchema.max(80),
|
|
1179
|
+
tone: z.enum([
|
|
1180
|
+
"good",
|
|
1181
|
+
"neutral",
|
|
1182
|
+
"warning"
|
|
1183
|
+
]).optional(),
|
|
1184
|
+
value: nonBlankStringSchema.max(120)
|
|
1246
1185
|
}).strict();
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1186
|
+
const pluginUserPageMetadataSchema = z.object({
|
|
1187
|
+
label: nonBlankStringSchema.max(80),
|
|
1188
|
+
value: nonBlankStringSchema.max(500)
|
|
1250
1189
|
}).strict();
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1190
|
+
const pluginUserPageActionSchema = z.object({
|
|
1191
|
+
confirmation: nonBlankStringSchema.max(500).optional(),
|
|
1192
|
+
href: nonBlankStringSchema.max(500).regex(/^\/api\/plugins\/[a-z][a-z0-9-]*(?:\/|$)/),
|
|
1193
|
+
label: nonBlankStringSchema.max(80),
|
|
1194
|
+
/**
|
|
1195
|
+
* `DELETE` sends a request and refreshes the page. `GET` opens the plugin
|
|
1196
|
+
* route in the browser, for flows such as an OAuth redirect.
|
|
1197
|
+
*/
|
|
1198
|
+
method: z.enum(["DELETE", "GET"]),
|
|
1199
|
+
tone: z.enum(["danger", "neutral"]).optional()
|
|
1261
1200
|
}).strict();
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1201
|
+
const pluginUserPageRecordSchema = z.object({
|
|
1202
|
+
actions: z.array(pluginUserPageActionSchema).max(4).optional(),
|
|
1203
|
+
description: nonBlankStringSchema.max(1e3).optional(),
|
|
1204
|
+
id: nonBlankStringSchema.max(128),
|
|
1205
|
+
metadata: z.array(pluginUserPageMetadataSchema).max(8).optional(),
|
|
1206
|
+
title: nonBlankStringSchema.max(4e3)
|
|
1268
1207
|
}).strict();
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1208
|
+
/** Bounded list content returned by a plugin-owned user page. */
|
|
1209
|
+
const pluginUserPageContentSchema = z.object({
|
|
1210
|
+
emptyText: nonBlankStringSchema.max(500).optional(),
|
|
1211
|
+
metrics: z.array(pluginUserPageMetricSchema).max(6).optional(),
|
|
1212
|
+
nextCursor: nonBlankStringSchema.max(1e3).optional(),
|
|
1213
|
+
records: z.array(pluginUserPageRecordSchema).max(100),
|
|
1214
|
+
searchPlaceholder: nonBlankStringSchema.max(120).optional(),
|
|
1215
|
+
type: z.literal("list")
|
|
1276
1216
|
}).strict();
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1217
|
+
const pluginUserPageLinkSchema = z.object({
|
|
1218
|
+
description: userPageDescriptionSchema,
|
|
1219
|
+
id: userPageIdSchema,
|
|
1220
|
+
label: userPageLabelSchema,
|
|
1221
|
+
navigation: userPageNavigationSchema,
|
|
1222
|
+
pluginDisplayName: nonBlankStringSchema.max(200),
|
|
1223
|
+
pluginName: nonBlankStringSchema.max(100)
|
|
1284
1224
|
}).strict();
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1225
|
+
const pluginUserPageLinksSchema = z.array(pluginUserPageLinkSchema);
|
|
1226
|
+
/** Optional cursor token for one plugin user page reader. */
|
|
1227
|
+
const pluginUserPageCursorSchema = nonBlankStringSchema.max(1e3).optional();
|
|
1228
|
+
/** Optional filter token for one plugin user page reader. */
|
|
1229
|
+
const pluginUserPageFilterSchema = nonBlankStringSchema.max(64).optional();
|
|
1230
|
+
/** Optional free-text query for one plugin user page reader. */
|
|
1231
|
+
const pluginUserPageQuerySchema = z.string().trim().max(200).optional();
|
|
1232
|
+
/** Validated query state passed to one plugin user page reader. */
|
|
1233
|
+
const pluginUserPageInputSchema = z.object({
|
|
1234
|
+
cursor: pluginUserPageCursorSchema,
|
|
1235
|
+
filter: pluginUserPageFilterSchema,
|
|
1236
|
+
limit: z.number().int().min(1).max(50),
|
|
1237
|
+
query: pluginUserPageQuerySchema
|
|
1294
1238
|
}).strict();
|
|
1295
|
-
export {
|
|
1296
|
-
EVENT_DATA_MAX_JSON_BYTES,
|
|
1297
|
-
EVENT_DATA_MAX_KEYS,
|
|
1298
|
-
EVENT_GUIDANCE_MAX_LENGTH,
|
|
1299
|
-
EVENT_SUMMARY_MAX_LENGTH,
|
|
1300
|
-
EVENT_TEXT_MAX_LENGTH,
|
|
1301
|
-
EgressAuthRequired,
|
|
1302
|
-
EgressPolicyDenied,
|
|
1303
|
-
PluginToolInputError,
|
|
1304
|
-
REQUIRED_TOOL_ANNOTATION_KEYS,
|
|
1305
|
-
actorSchema,
|
|
1306
|
-
actorUserIdSchema,
|
|
1307
|
-
agentInvocationSourceSchema,
|
|
1308
|
-
codeChangeInputSchema,
|
|
1309
|
-
codeChangeStateSchema,
|
|
1310
|
-
conversationAnnotationInputSchema,
|
|
1311
|
-
conversationEventIconSchema,
|
|
1312
|
-
conversationEventPresentationSchema,
|
|
1313
|
-
conversationSidebarAnnotationSchema,
|
|
1314
|
-
conversationSidebarIconSchema,
|
|
1315
|
-
createEventSource,
|
|
1316
|
-
createLocalSource,
|
|
1317
|
-
createSlackSource,
|
|
1318
|
-
createWebSource,
|
|
1319
|
-
defineConversationEvent,
|
|
1320
|
-
defineJuniorPlugin,
|
|
1321
|
-
definePluginTool,
|
|
1322
|
-
definePromptContext,
|
|
1323
|
-
destinationSchema,
|
|
1324
|
-
destinationVisibilitySchema,
|
|
1325
|
-
dispatchOptionsSchema,
|
|
1326
|
-
enforceEgressPolicy,
|
|
1327
|
-
eventAutomationSourceSchema,
|
|
1328
|
-
eventDataSchema,
|
|
1329
|
-
eventIdentifierSchema,
|
|
1330
|
-
eventInputSchema,
|
|
1331
|
-
eventMatchFieldSchema,
|
|
1332
|
-
eventMatchFieldsSchema,
|
|
1333
|
-
eventMatchSchema,
|
|
1334
|
-
eventMatches,
|
|
1335
|
-
eventPersonSchema,
|
|
1336
|
-
eventSchema,
|
|
1337
|
-
eventSourceSchema,
|
|
1338
|
-
eventTypeSchema,
|
|
1339
|
-
getSourceKey,
|
|
1340
|
-
identitySchema,
|
|
1341
|
-
isPrivateSource,
|
|
1342
|
-
isSlackDestination,
|
|
1343
|
-
localActorSchema,
|
|
1344
|
-
localDestinationSchema,
|
|
1345
|
-
localSourceSchema,
|
|
1346
|
-
locationSchema,
|
|
1347
|
-
missingToolAnnotationKeys,
|
|
1348
|
-
nonBlankStringSchema,
|
|
1349
|
-
normalizeEventIdentifier,
|
|
1350
|
-
objectAnnotationSchema,
|
|
1351
|
-
objectFactFields,
|
|
1352
|
-
objectFactsSchema,
|
|
1353
|
-
objectIconPath,
|
|
1354
|
-
objectIconPaths,
|
|
1355
|
-
objectPresentation,
|
|
1356
|
-
objectTypeSchema,
|
|
1357
|
-
ownedObjectAnnotationSchema,
|
|
1358
|
-
platformSchema,
|
|
1359
|
-
pluginApiRouteRequestContextSchema,
|
|
1360
|
-
pluginAuthorizationSchema,
|
|
1361
|
-
pluginCredentialHeaderTransformSchema,
|
|
1362
|
-
pluginCredentialLeaseSchema,
|
|
1363
|
-
pluginCredentialResultSchema,
|
|
1364
|
-
pluginCredentialSubjectSchema,
|
|
1365
|
-
pluginDispatchSourceSchema,
|
|
1366
|
-
pluginEventTypeSchema,
|
|
1367
|
-
pluginEventsSchema,
|
|
1368
|
-
pluginGrantSchema,
|
|
1369
|
-
pluginProviderAccountSchema,
|
|
1370
|
-
pluginRunContextSchema,
|
|
1371
|
-
pluginRunTranscriptEntrySchema,
|
|
1372
|
-
pluginRunTranscriptProvenanceSchema,
|
|
1373
|
-
pluginStoredTokensSchema,
|
|
1374
|
-
pluginToolContentSchema,
|
|
1375
|
-
pluginToolContinuationSchema,
|
|
1376
|
-
pluginToolOutputSchema,
|
|
1377
|
-
pluginUserPageContentSchema,
|
|
1378
|
-
pluginUserPageCursorSchema,
|
|
1379
|
-
pluginUserPageFilterSchema,
|
|
1380
|
-
pluginUserPageInputSchema,
|
|
1381
|
-
pluginUserPageLinkSchema,
|
|
1382
|
-
pluginUserPageLinksSchema,
|
|
1383
|
-
pluginUserPageQuerySchema,
|
|
1384
|
-
promptContextSchema,
|
|
1385
|
-
promptMessageSchema,
|
|
1386
|
-
replyAttributionSchema,
|
|
1387
|
-
resourceLinkAnnotationSchema,
|
|
1388
|
-
resourceTypeSchema,
|
|
1389
|
-
scheduledAutomationSourceSchema,
|
|
1390
|
-
slackActorSchema,
|
|
1391
|
-
slackDestinationSchema,
|
|
1392
|
-
slackLocationSchema,
|
|
1393
|
-
slackSourceSchema,
|
|
1394
|
-
sourceSchema,
|
|
1395
|
-
sourceVisibilitySchema,
|
|
1396
|
-
stableEventMatchKey,
|
|
1397
|
-
subscribableResourceSchema,
|
|
1398
|
-
systemActorSchema,
|
|
1399
|
-
taskOutcomeSchema,
|
|
1400
|
-
toolApprovalModeSchema,
|
|
1401
|
-
userSchema,
|
|
1402
|
-
watchResultSchema,
|
|
1403
|
-
webActorSchema,
|
|
1404
|
-
webSourceSchema,
|
|
1405
|
-
zodTool
|
|
1406
|
-
};
|
|
1239
|
+
export { EVENT_DATA_MAX_JSON_BYTES, EVENT_DATA_MAX_KEYS, EVENT_GUIDANCE_MAX_LENGTH, EVENT_SUMMARY_MAX_LENGTH, EVENT_TEXT_MAX_LENGTH, EgressAuthRequired, EgressPolicyDenied, PluginToolInputError, REQUIRED_TOOL_ANNOTATION_KEYS, actorSchema, actorUserIdSchema, agentInvocationSourceSchema, codeChangeInputSchema, codeChangeStateSchema, conversationAnnotationInputSchema, conversationEventIconSchema, conversationEventPresentationSchema, conversationSidebarAnnotationSchema, conversationSidebarIconSchema, createEventSource, createLocalSource, createSlackSource, createWebSource, defineConversationEvent, defineJuniorPlugin, definePluginTool, definePromptContext, destinationSchema, destinationVisibilitySchema, dispatchOptionsSchema, enforceEgressPolicy, eventAutomationSourceSchema, eventDataSchema, eventIdentifierSchema, eventInputSchema, eventMatchFieldSchema, eventMatchFieldsSchema, eventMatchSchema, eventMatches, eventPersonSchema, eventSchema, eventSourceSchema, eventTypeSchema, getSourceKey, identitySchema, isPrivateSource, isSlackDestination, localActorSchema, localDestinationSchema, localSourceSchema, locationSchema, missingToolAnnotationKeys, nonBlankStringSchema, normalizeEventIdentifier, objectAnnotationSchema, objectFactFields, objectFactsSchema, objectIconPath, objectIconPaths, objectPresentation, objectTypeSchema, ownedObjectAnnotationSchema, platformSchema, pluginApiRouteRequestContextSchema, pluginAuthorizationSchema, pluginCredentialHeaderTransformSchema, pluginCredentialLeaseSchema, pluginCredentialResultSchema, pluginCredentialSubjectSchema, pluginDispatchSourceSchema, pluginEventTypeSchema, pluginEventsSchema, pluginGrantSchema, pluginProviderAccountSchema, pluginRunContextSchema, pluginRunTranscriptEntrySchema, pluginRunTranscriptProvenanceSchema, pluginStoredTokensSchema, pluginToolContentSchema, pluginToolContinuationSchema, pluginToolOutputSchema, pluginUserPageContentSchema, pluginUserPageCursorSchema, pluginUserPageFilterSchema, pluginUserPageInputSchema, pluginUserPageLinkSchema, pluginUserPageLinksSchema, pluginUserPageQuerySchema, promptContextSchema, promptMessageSchema, replyAttributionSchema, resourceLinkAnnotationSchema, resourceTypeSchema, scheduledAutomationSourceSchema, slackActorSchema, slackDestinationSchema, slackLocationSchema, slackSourceSchema, sourceSchema, sourceVisibilitySchema, stableEventMatchKey, subscribableResourceSchema, systemActorSchema, taskOutcomeSchema, toolApprovalModeSchema, userSchema, watchResultSchema, webActorSchema, webSourceSchema, zodTool };
|