@agent-native/core 0.161.8 → 0.161.10
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/corpus/README.md +1 -1
- package/corpus/templates/calendar/changelog/2026-08-18-calendar-event-time-editing-respects-the-event-timezone.md +6 -0
- package/corpus/templates/clips/app/components/player/video-player.tsx +1 -1
- package/corpus/templates/clips/app/i18n/en-US.ts +1 -1
- package/corpus/templates/clips/changelog/2026-08-18-centered-clip-play-button-and-comment-panel-hint.md +6 -0
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +180 -37
- package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +18 -3
- package/corpus/templates/design/app/components/layout/Layout.tsx +4 -1
- package/corpus/templates/design/app/hooks/use-navigation-state.ts +13 -2
- package/corpus/templates/design/app/i18n-data.ts +11 -0
- package/corpus/templates/design/app/lib/agent-chat.ts +30 -0
- package/corpus/templates/design/app/lib/builder-host-chat.ts +34 -0
- package/corpus/templates/design/app/lib/builder-host-origin.ts +31 -0
- package/corpus/templates/design/app/lib/embed-chrome.ts +70 -0
- package/corpus/templates/design/app/lib/shell-design.ts +113 -0
- package/corpus/templates/design/app/pages/design-editor/code-layer-state.ts +89 -0
- package/corpus/templates/design/app/pages/design-editor/nudge-intent.ts +85 -12
- package/corpus/templates/design/app/pages/design-editor/pending-edits.ts +43 -19
- package/corpus/templates/design/app/pages/design-editor/screen-command-utils.ts +9 -2
- package/corpus/templates/design/app/pages/design-editor/tool-state.ts +13 -0
- package/corpus/templates/design/app/root.tsx +23 -1
- package/corpus/templates/design/server/lib/fusion-screens.ts +17 -1
- package/corpus/templates/design/server/plugins/builder-host-embed-headers.ts +37 -0
- package/corpus/templates/design/server/routes/[...page].get.ts +1 -0
- package/corpus/templates/design/shared/builder-preview-url.ts +113 -0
- package/corpus/templates/design/shared/full-app.ts +19 -0
- package/corpus/templates/design/shared/shell-screens.ts +139 -0
- package/corpus/templates/design/shared/source-mode.ts +10 -0
- package/corpus/templates/factory/actions/start-builder-for-item.ts +241 -22
- package/corpus/templates/factory/server/plugins/agent-chat.ts +9 -5
- package/corpus/templates/factory/server/plugins/factory-scheduler-job.ts +50 -14
- package/corpus/templates/factory/server/triage/builder-executor.ts +1 -0
- package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +231 -9
- package/corpus/templates/slides/app/context/DeckContext.tsx +99 -3
- package/corpus/templates/slides/app/i18n/en-US.ts +6 -0
- package/corpus/templates/slides/app/pages/DeckEditor.tsx +8 -2
- package/dist/agent/chat-health-alert.d.ts +25 -0
- package/dist/agent/chat-health-alert.js +132 -0
- package/dist/client/RuntimeConfigNotice.js +3 -0
- package/dist/client/api-surface.d.ts +19 -0
- package/dist/client/api-surface.js +32 -0
- package/dist/client/application-state.js +4 -0
- package/dist/client/builder-frame.d.ts +6 -0
- package/dist/client/builder-frame.js +1 -1
- package/dist/client/client-status-requests.js +5 -0
- package/dist/client/host/index.d.ts +1 -0
- package/dist/client/host/index.js +1 -0
- package/dist/client/use-action.d.ts +1 -1
- package/dist/client/use-action.js +17 -0
- package/dist/client/use-session.js +5 -0
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/routes.d.ts +1 -1
- package/dist/observability/routes.d.ts +5 -5
- package/dist/progress/routes.d.ts +1 -1
- package/dist/provider-api/actions/custom-provider-registration.d.ts +9 -9
- package/dist/provider-api/actions/provider-api.d.ts +11 -11
- package/dist/provider-api/corpus-jobs.d.ts +2 -2
- package/dist/secrets/routes.d.ts +9 -9
- package/dist/server/agent-chat-plugin.js +15 -2
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/realtime-token.d.ts +1 -1
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/package.json +1 -1
- /package/corpus/templates/design/app/routes/{visual-edit.$id.tsx → visual-edit_.$id.tsx} +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { defineAction } from "@agent-native/core/action";
|
|
2
|
-
import { and, eq } from "drizzle-orm";
|
|
2
|
+
import { and, eq, inArray } from "drizzle-orm";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
|
|
5
5
|
import { getDb } from "../server/db/index.js";
|
|
@@ -26,22 +26,107 @@ import { detectOwnerOwnedArea } from "../server/triage/pr-policy.js";
|
|
|
26
26
|
import { createSlackReader } from "../server/triage/slack-client.js";
|
|
27
27
|
|
|
28
28
|
const replyTextPrefix =
|
|
29
|
-
"@
|
|
29
|
+
"@builder.io please run /address-feedback in the repo to address this feedback. Read the address-feedback, address-feedback-with-replies, review-latest-feedback, and review-prs skills as relevant, inspect the full thread and linked evidence, and fix the owning boundary. Please send a PR when ready.";
|
|
30
|
+
const legacyReplyTextPrefix = "@builderio please fix this in a reply.";
|
|
30
31
|
|
|
31
|
-
|
|
32
|
+
type RelatedFeedbackItem = {
|
|
32
33
|
id: string;
|
|
33
34
|
sourceUrl: string | null;
|
|
34
|
-
|
|
35
|
+
title: string;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const startedTriageRunStatuses = new Set([
|
|
39
|
+
"submitted",
|
|
40
|
+
"acknowledged",
|
|
41
|
+
"running",
|
|
42
|
+
"completed",
|
|
43
|
+
"timed_out",
|
|
44
|
+
"reconciliation_required",
|
|
45
|
+
]);
|
|
46
|
+
|
|
47
|
+
export function hasFeedbackCluster(metadata: Record<string, unknown>): boolean {
|
|
48
|
+
return (
|
|
49
|
+
(typeof metadata.feedbackClusterRepresentativeId === "string" &&
|
|
50
|
+
metadata.feedbackClusterRepresentativeId.trim().length > 0) ||
|
|
51
|
+
(Array.isArray(metadata.feedbackClusterItemIds) &&
|
|
52
|
+
metadata.feedbackClusterItemIds.length > 0)
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function isStartedTriageRunStatus(status: string): boolean {
|
|
57
|
+
return startedTriageRunStatuses.has(status);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function relatedDispatchConflictReason(
|
|
61
|
+
item: Pick<RelatedFeedbackItem, "id">,
|
|
62
|
+
metadata: Record<string, unknown>,
|
|
63
|
+
runStatuses: readonly string[],
|
|
64
|
+
): string | null {
|
|
65
|
+
if (hasFeedbackCluster(metadata)) {
|
|
66
|
+
return `Related Factory item ${item.id} already belongs to a feedback cluster.`;
|
|
67
|
+
}
|
|
68
|
+
if (runStatuses.some(isStartedTriageRunStatus)) {
|
|
69
|
+
return `Related Factory item ${item.id} already has a started Builder run.`;
|
|
70
|
+
}
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function ownerOwnedAreaValuesForItem(
|
|
75
|
+
item: Pick<RelatedFeedbackItem, "title"> & {
|
|
76
|
+
summary: string | null;
|
|
77
|
+
repository: string | null;
|
|
78
|
+
},
|
|
79
|
+
metadata: Record<string, unknown>,
|
|
80
|
+
): Array<string | undefined> {
|
|
81
|
+
return [
|
|
82
|
+
item.title,
|
|
83
|
+
item.summary ?? undefined,
|
|
84
|
+
item.repository ?? undefined,
|
|
85
|
+
typeof metadata.productArea === "string" ? metadata.productArea : undefined,
|
|
86
|
+
typeof metadata.path === "string" ? metadata.path : undefined,
|
|
87
|
+
];
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export function replyTextForItem(
|
|
91
|
+
item: {
|
|
92
|
+
id: string;
|
|
93
|
+
sourceUrl: string | null;
|
|
94
|
+
},
|
|
95
|
+
relatedItems: RelatedFeedbackItem[] = [],
|
|
96
|
+
): string {
|
|
97
|
+
const relatedText =
|
|
98
|
+
relatedItems.length > 0
|
|
99
|
+
? [
|
|
100
|
+
"Related feedback in the same issue cluster - inspect and fix all of these too:",
|
|
101
|
+
...relatedItems.map(
|
|
102
|
+
(related) =>
|
|
103
|
+
`- ${related.title} (${related.id})${related.sourceUrl ? `: ${related.sourceUrl}` : ""}`,
|
|
104
|
+
),
|
|
105
|
+
]
|
|
106
|
+
: [];
|
|
35
107
|
return [
|
|
36
108
|
replyTextPrefix,
|
|
37
109
|
`Factory item: ${item.id}`,
|
|
38
110
|
item.sourceUrl ? `Source: ${item.sourceUrl}` : "",
|
|
39
|
-
|
|
111
|
+
...relatedText,
|
|
112
|
+
"Please include the Factory item, every related item, and their source links in the PR description, and make sure the fix covers the whole cluster rather than one report.",
|
|
40
113
|
]
|
|
41
114
|
.filter(Boolean)
|
|
42
115
|
.join("\n");
|
|
43
116
|
}
|
|
44
117
|
|
|
118
|
+
function relatedFeedbackSummary(relatedItems: RelatedFeedbackItem[]): string {
|
|
119
|
+
if (relatedItems.length === 0) return "";
|
|
120
|
+
return [
|
|
121
|
+
"Related feedback in the same issue cluster:",
|
|
122
|
+
...relatedItems.map(
|
|
123
|
+
(related) =>
|
|
124
|
+
`- ${related.title} (${related.id})${related.sourceUrl ? `: ${related.sourceUrl}` : ""}`,
|
|
125
|
+
),
|
|
126
|
+
"Read and address every related report in one change.",
|
|
127
|
+
].join("\n");
|
|
128
|
+
}
|
|
129
|
+
|
|
45
130
|
async function writeMetadata(
|
|
46
131
|
itemId: string,
|
|
47
132
|
orgId: string,
|
|
@@ -104,17 +189,31 @@ async function recordDecision(input: {
|
|
|
104
189
|
|
|
105
190
|
export default defineAction({
|
|
106
191
|
description:
|
|
107
|
-
"Start the governed clear-bug Builder flow for a Factory item. Slack items are kept in-thread by adding 👀 and tagging @
|
|
192
|
+
"Start the governed clear-bug Builder flow for a Factory item. Slack items are kept in-thread by adding 👀 and tagging @builder.io; grouped Slack repeats share one Builder thread. GitHub issues and Sentry errors use the Builder agent run API. Owner-managed Clips, Design, and Content items are always left for their owner.",
|
|
108
193
|
schema: z.object({
|
|
109
194
|
itemId: z.string().min(1),
|
|
110
195
|
clearBug: z.boolean(),
|
|
111
196
|
reason: z.string().trim().min(1).max(4_000),
|
|
112
197
|
productUxImplications: z.boolean().default(false),
|
|
113
198
|
clearErrorReport: z.string().trim().max(8_000).optional(),
|
|
199
|
+
relatedItemIds: z
|
|
200
|
+
.array(z.string().trim().min(1))
|
|
201
|
+
.max(10)
|
|
202
|
+
.default([])
|
|
203
|
+
.describe(
|
|
204
|
+
"Other Factory item ids in the same verified feedback cluster; dispatches one Builder thread for the whole group.",
|
|
205
|
+
),
|
|
114
206
|
}),
|
|
115
207
|
http: false,
|
|
116
208
|
run: async (
|
|
117
|
-
{
|
|
209
|
+
{
|
|
210
|
+
itemId,
|
|
211
|
+
clearBug,
|
|
212
|
+
reason,
|
|
213
|
+
productUxImplications,
|
|
214
|
+
clearErrorReport,
|
|
215
|
+
relatedItemIds,
|
|
216
|
+
},
|
|
118
217
|
context,
|
|
119
218
|
) => {
|
|
120
219
|
const { userEmail, orgId } = await requireWorkspaceMember(
|
|
@@ -135,6 +234,65 @@ export default defineAction({
|
|
|
135
234
|
)[0];
|
|
136
235
|
if (!item) throw new Error("Factory item not found.");
|
|
137
236
|
const metadata = parseTriageMetadata(item.metadataJson);
|
|
237
|
+
const relatedIds = [...new Set(relatedItemIds)].filter(
|
|
238
|
+
(relatedId) => relatedId !== itemId,
|
|
239
|
+
);
|
|
240
|
+
const relatedItems =
|
|
241
|
+
relatedIds.length > 0
|
|
242
|
+
? await db
|
|
243
|
+
.select()
|
|
244
|
+
.from(triageItems)
|
|
245
|
+
.where(
|
|
246
|
+
and(
|
|
247
|
+
eq(triageItems.orgId, orgId),
|
|
248
|
+
inArray(triageItems.id, relatedIds),
|
|
249
|
+
),
|
|
250
|
+
)
|
|
251
|
+
: [];
|
|
252
|
+
if (relatedItems.length !== relatedIds.length) {
|
|
253
|
+
throw new Error("One or more related Factory items were not found.");
|
|
254
|
+
}
|
|
255
|
+
if (relatedItems.some((related) => related.source !== item.source)) {
|
|
256
|
+
throw new Error(
|
|
257
|
+
"Grouped Factory items must come from the same feedback source.",
|
|
258
|
+
);
|
|
259
|
+
}
|
|
260
|
+
if (
|
|
261
|
+
item.source === "slack" &&
|
|
262
|
+
relatedItems.some((related) => !related.channelId || !related.threadTs)
|
|
263
|
+
) {
|
|
264
|
+
throw new Error(
|
|
265
|
+
"Grouped Slack feedback is missing a channel or thread identity.",
|
|
266
|
+
);
|
|
267
|
+
}
|
|
268
|
+
const relatedMetadata = new Map(
|
|
269
|
+
relatedItems.map((related) => [
|
|
270
|
+
related.id,
|
|
271
|
+
parseTriageMetadata(related.metadataJson),
|
|
272
|
+
]),
|
|
273
|
+
);
|
|
274
|
+
const relatedRunRows =
|
|
275
|
+
relatedIds.length > 0
|
|
276
|
+
? await db
|
|
277
|
+
.select({ itemId: triageRuns.itemId, status: triageRuns.status })
|
|
278
|
+
.from(triageRuns)
|
|
279
|
+
.where(
|
|
280
|
+
and(
|
|
281
|
+
eq(triageRuns.orgId, orgId),
|
|
282
|
+
inArray(triageRuns.itemId, relatedIds),
|
|
283
|
+
),
|
|
284
|
+
)
|
|
285
|
+
: [];
|
|
286
|
+
for (const related of relatedItems) {
|
|
287
|
+
const conflictReason = relatedDispatchConflictReason(
|
|
288
|
+
related,
|
|
289
|
+
relatedMetadata.get(related.id) ?? {},
|
|
290
|
+
relatedRunRows
|
|
291
|
+
.filter((run) => run.itemId === related.id)
|
|
292
|
+
.map((run) => run.status),
|
|
293
|
+
);
|
|
294
|
+
if (conflictReason) throw new Error(conflictReason);
|
|
295
|
+
}
|
|
138
296
|
const ownerOwnedArea = detectOwnerOwnedArea([
|
|
139
297
|
item.title,
|
|
140
298
|
item.summary,
|
|
@@ -144,6 +302,18 @@ export default defineAction({
|
|
|
144
302
|
: undefined,
|
|
145
303
|
typeof metadata.path === "string" ? metadata.path : undefined,
|
|
146
304
|
]);
|
|
305
|
+
const relatedOwnerOwnedArea =
|
|
306
|
+
relatedItems
|
|
307
|
+
.map((related) =>
|
|
308
|
+
detectOwnerOwnedArea(
|
|
309
|
+
ownerOwnedAreaValuesForItem(
|
|
310
|
+
related,
|
|
311
|
+
relatedMetadata.get(related.id) ?? {},
|
|
312
|
+
),
|
|
313
|
+
),
|
|
314
|
+
)
|
|
315
|
+
.find(Boolean) ?? null;
|
|
316
|
+
const ownerManagedArea = ownerOwnedArea ?? relatedOwnerOwnedArea ?? null;
|
|
147
317
|
const guardResults = [
|
|
148
318
|
{
|
|
149
319
|
code: "unknown_change",
|
|
@@ -159,12 +329,12 @@ export default defineAction({
|
|
|
159
329
|
? "Product or UX implications require manual ownership."
|
|
160
330
|
: "No product or UX decision was detected.",
|
|
161
331
|
},
|
|
162
|
-
...(
|
|
332
|
+
...(ownerManagedArea
|
|
163
333
|
? [
|
|
164
334
|
{
|
|
165
335
|
code: "owner_owned",
|
|
166
336
|
passed: false,
|
|
167
|
-
reason: `${
|
|
337
|
+
reason: `${ownerManagedArea} is fully owned by its product owner and is excluded from autonomous Builder work.`,
|
|
168
338
|
},
|
|
169
339
|
]
|
|
170
340
|
: []),
|
|
@@ -198,7 +368,7 @@ export default defineAction({
|
|
|
198
368
|
decisionId,
|
|
199
369
|
clearBug,
|
|
200
370
|
productUxImplications,
|
|
201
|
-
ownerOwnedArea:
|
|
371
|
+
ownerOwnedArea: ownerManagedArea,
|
|
202
372
|
guardResults,
|
|
203
373
|
},
|
|
204
374
|
},
|
|
@@ -302,13 +472,20 @@ export default defineAction({
|
|
|
302
472
|
const workspace =
|
|
303
473
|
config?.slackWorkspace === "secondary" ? "secondary" : "primary";
|
|
304
474
|
const slack = createSlackReader({ ownerEmail: userEmail, orgId });
|
|
305
|
-
|
|
475
|
+
for (const feedbackItem of [item, ...relatedItems]) {
|
|
476
|
+
const feedbackMetadata =
|
|
477
|
+
feedbackItem.id === itemId
|
|
478
|
+
? metadata
|
|
479
|
+
: parseTriageMetadata(feedbackItem.metadataJson);
|
|
480
|
+
if (metadataBoolean(feedbackMetadata, "slackEyesReactedAt")) {
|
|
481
|
+
continue;
|
|
482
|
+
}
|
|
306
483
|
const reaction = await slack.addEyesReaction(
|
|
307
484
|
workspace,
|
|
308
|
-
|
|
309
|
-
|
|
485
|
+
feedbackItem.channelId!,
|
|
486
|
+
feedbackItem.threadTs!,
|
|
310
487
|
);
|
|
311
|
-
await writeMetadata(
|
|
488
|
+
await writeMetadata(feedbackItem.id, orgId, {
|
|
312
489
|
slackEyesReactedAt: new Date().toISOString(),
|
|
313
490
|
slackEyesReactionAlreadyPresent: reaction.already_present,
|
|
314
491
|
});
|
|
@@ -319,11 +496,21 @@ export default defineAction({
|
|
|
319
496
|
item.threadTs,
|
|
320
497
|
100,
|
|
321
498
|
);
|
|
499
|
+
const hasCurrentBuilderReply = thread.messages.some((message) =>
|
|
500
|
+
message.text.includes(replyTextPrefix),
|
|
501
|
+
);
|
|
502
|
+
const hasLegacyBuilderReply = thread.messages.some((message) =>
|
|
503
|
+
message.text.includes(legacyReplyTextPrefix),
|
|
504
|
+
);
|
|
505
|
+
const hasRelatedClusterDetails = thread.messages.some((message) =>
|
|
506
|
+
message.text.includes(
|
|
507
|
+
"Related feedback in the same issue cluster - inspect and fix all of these too:",
|
|
508
|
+
),
|
|
509
|
+
);
|
|
322
510
|
if (
|
|
323
511
|
thread.has_more &&
|
|
324
|
-
!
|
|
325
|
-
|
|
326
|
-
)
|
|
512
|
+
!hasCurrentBuilderReply &&
|
|
513
|
+
!hasLegacyBuilderReply
|
|
327
514
|
) {
|
|
328
515
|
throw new Error(
|
|
329
516
|
"Slack thread is truncated; refusing to risk a duplicate Builder handoff.",
|
|
@@ -331,21 +518,47 @@ export default defineAction({
|
|
|
331
518
|
}
|
|
332
519
|
if (
|
|
333
520
|
!metadataBoolean(metadata, "slackBuilderReplyAt") &&
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
)
|
|
521
|
+
((!hasCurrentBuilderReply && !hasLegacyBuilderReply) ||
|
|
522
|
+
(relatedItems.length > 0 && !hasRelatedClusterDetails))
|
|
337
523
|
) {
|
|
338
524
|
const posted = await slack.postThreadReply(
|
|
339
525
|
workspace,
|
|
340
526
|
item.channelId,
|
|
341
527
|
item.threadTs,
|
|
342
|
-
replyTextForItem(item),
|
|
528
|
+
replyTextForItem(item, relatedItems),
|
|
343
529
|
);
|
|
344
530
|
await writeMetadata(itemId, orgId, {
|
|
345
531
|
slackBuilderReplyAt: new Date().toISOString(),
|
|
346
532
|
slackBuilderReplyTs: posted.ts,
|
|
347
533
|
});
|
|
348
534
|
}
|
|
535
|
+
const clusterItemIds = [itemId, ...relatedItems.map(({ id }) => id)];
|
|
536
|
+
const clusterMetadata = {
|
|
537
|
+
feedbackClusterRepresentativeId: itemId,
|
|
538
|
+
feedbackClusterItemIds: clusterItemIds,
|
|
539
|
+
feedbackClusterGroupedAt: new Date().toISOString(),
|
|
540
|
+
};
|
|
541
|
+
await writeMetadata(itemId, orgId, clusterMetadata);
|
|
542
|
+
for (const related of relatedItems) {
|
|
543
|
+
await writeMetadata(related.id, orgId, clusterMetadata);
|
|
544
|
+
await db
|
|
545
|
+
.update(triageItems)
|
|
546
|
+
.set({
|
|
547
|
+
status: "automation_started",
|
|
548
|
+
updatedAt: new Date().toISOString(),
|
|
549
|
+
})
|
|
550
|
+
.where(
|
|
551
|
+
and(eq(triageItems.id, related.id), eq(triageItems.orgId, orgId)),
|
|
552
|
+
);
|
|
553
|
+
await recordDecision({
|
|
554
|
+
itemId: related.id,
|
|
555
|
+
userEmail,
|
|
556
|
+
orgId,
|
|
557
|
+
outcome: "propose_fix",
|
|
558
|
+
reason: `Grouped with Factory item ${itemId}: ${reason}`,
|
|
559
|
+
guardResults,
|
|
560
|
+
});
|
|
561
|
+
}
|
|
349
562
|
await db
|
|
350
563
|
.update(triageItems)
|
|
351
564
|
.set({
|
|
@@ -363,7 +576,11 @@ export default defineAction({
|
|
|
363
576
|
source: item.source,
|
|
364
577
|
sourceUrl: item.sourceUrl,
|
|
365
578
|
summary: "Tagged Builder in the Slack thread and requested a PR.",
|
|
366
|
-
details: {
|
|
579
|
+
details: {
|
|
580
|
+
provider: "bot-tag",
|
|
581
|
+
runId,
|
|
582
|
+
relatedItemIds: relatedItems.map(({ id }) => id),
|
|
583
|
+
},
|
|
367
584
|
},
|
|
368
585
|
);
|
|
369
586
|
return {
|
|
@@ -385,8 +602,10 @@ export default defineAction({
|
|
|
385
602
|
summary: item.summary,
|
|
386
603
|
sourceUrl: item.sourceUrl,
|
|
387
604
|
instructions: [
|
|
605
|
+
"Run /address-feedback in the repository and read the address-feedback, address-feedback-with-replies, review-latest-feedback, and review-prs skills as relevant. Inspect all linked evidence and repeat reports, then fix the smallest owning boundary and verify it before opening the PR.",
|
|
388
606
|
reason,
|
|
389
607
|
clearErrorReport ? `Error report:\n${clearErrorReport}` : "",
|
|
608
|
+
relatedFeedbackSummary(relatedItems),
|
|
390
609
|
]
|
|
391
610
|
.filter(Boolean)
|
|
392
611
|
.join("\n\n"),
|
|
@@ -87,11 +87,15 @@ requests, broad UX suggestions, vague questions, and incomplete context stay
|
|
|
87
87
|
manual. Clips, Design, and Content are fully owner-managed: never react, tag
|
|
88
88
|
Builder, auto-approve, or auto-merge those items. Slack clear bugs use the
|
|
89
89
|
thread-preserving start-builder-for-item flow; GitHub and Sentry clear bugs use
|
|
90
|
-
the Builder agent-run flow.
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
90
|
+
the Builder agent-run flow. Slack repeat reports must be clustered by underlying
|
|
91
|
+
symptom, with one Builder thread for the cluster and 👀 on every grouped report.
|
|
92
|
+
Use /address-feedback for the repository feedback workflow. For pull requests,
|
|
93
|
+
follow review-prs: read the complete diff and review evidence, verify current
|
|
94
|
+
BuilderIO membership, preserve the ultra-scary safety gate, and distinguish
|
|
95
|
+
unknown or unresolved checks from clean ones. Auto-merge also requires a
|
|
96
|
+
verified Factory Builder run. When a user says to do a review-gated item now,
|
|
97
|
+
use the explicit approval action, which records the approver and applies the
|
|
98
|
+
rule's configured executor policy. Keep Slack replies concise and link to the
|
|
95
99
|
Factory item when a review is needed. The scheduled builder-io-bot PR babysitter
|
|
96
100
|
posts its exact feedback-fix request through GitHub, persists a 20-minute quiet
|
|
97
101
|
window, and never approves or merges.`,
|
|
@@ -181,12 +181,21 @@ const AUTOMATION_SEEDS: AutomationSeed[] = [
|
|
|
181
181
|
body: `
|
|
182
182
|
# Factory Slack feedback triage
|
|
183
183
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
184
|
+
Follow the repository's address-feedback, address-feedback-with-replies, and
|
|
185
|
+
review-latest-feedback skills for this workflow, and use review-prs when a PR
|
|
186
|
+
needs review. Read the Factory configuration. When Slack polling is enabled
|
|
187
|
+
and a channel is configured, call poll-slack-channel first. Then list at most 5
|
|
188
|
+
new or changed Slack items by passing needsReview true, source slack, and limit
|
|
189
|
+
5. Use one additional bounded recent Slack lookup with needsReview false,
|
|
190
|
+
source slack, and limit 20 only to find possible repeat reports; never list the
|
|
191
|
+
full queue or use an action's default page size.
|
|
192
|
+
|
|
193
|
+
Call get-slack-feedback-context for every new item and every possible repeat
|
|
194
|
+
that may belong to the same issue before classifying it. Read the full parent,
|
|
195
|
+
replies, reactions, and linked evidence. An unreadable or truncated thread is
|
|
196
|
+
not a clear bug and must stay manual. Search recent Slack history, local Git
|
|
197
|
+
history, merged PRs, and linked issues for repeats or an existing fix when
|
|
198
|
+
those sources are available.
|
|
190
199
|
|
|
191
200
|
Start work only for a clear bug: a concrete broken behavior, reproducible
|
|
192
201
|
failure, error, regression, stuck run, incorrect result, or a report with a
|
|
@@ -201,10 +210,20 @@ and concrete auth or configuration failures. Use those examples to recognize
|
|
|
201
210
|
the shape of a bug, not to turn similar-sounding reports into automatic work.
|
|
202
211
|
|
|
203
212
|
For a clear bug outside Clips, Design, and Content, call start-builder-for-item
|
|
204
|
-
with clearBug true and a short evidence-grounded reason.
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
213
|
+
with clearBug true and a short evidence-grounded reason. If multiple reports
|
|
214
|
+
describe the same underlying issue, treat them as one similar-feedback cluster:
|
|
215
|
+
read and eyeball every report, choose one representative, and call
|
|
216
|
+
start-builder-for-item once with the other Factory item ids in relatedItemIds.
|
|
217
|
+
The action adds 👀 to every grouped Slack thread but posts one Builder reply in
|
|
218
|
+
the representative thread. Do not start one Builder thread per duplicate.
|
|
219
|
+
Separate reports only when their failure modes, surfaces, or owners differ.
|
|
220
|
+
|
|
221
|
+
The Builder reply must tag @builder.io with the dot and tell it to run
|
|
222
|
+
/address-feedback. It must point Builder to the relevant repository skills,
|
|
223
|
+
the representative source, every related source, and the need to fix the
|
|
224
|
+
underlying boundary across the whole cluster. Never add the reaction or tag
|
|
225
|
+
Builder for owner-managed Clips, Design, or Content work, or for a non-bug
|
|
226
|
+
report.
|
|
208
227
|
|
|
209
228
|
Keep each run bounded. Preserve action errors and do not claim a Builder reply,
|
|
210
229
|
PR, merge, or fix unless an action returned that state.
|
|
@@ -274,6 +293,19 @@ confirmation.
|
|
|
274
293
|
body: `
|
|
275
294
|
# Factory pull-request governance
|
|
276
295
|
|
|
296
|
+
Follow the repository's review-prs skill. Read the full PR title, body, linked
|
|
297
|
+
issue and source links, complete changed-file diff including generated and
|
|
298
|
+
migration files, every human and bot review comment and reply, actual check
|
|
299
|
+
conclusions, and the affected ownership boundary. Verify current BuilderIO
|
|
300
|
+
organization membership through the GitHub organization API; never infer it
|
|
301
|
+
from a name, email, association, branch, or bot label. Never approve external
|
|
302
|
+
or unverified authors. Apply the skill's ultra-scary gate for auth, permissions,
|
|
303
|
+
tenant isolation, secrets, destructive data loss, RCE, SSRF, payments,
|
|
304
|
+
deployment, or unexplained dependency and infrastructure risk. Record failed,
|
|
305
|
+
pending, skipped, unknown, and unresolved ordinary feedback accurately - never
|
|
306
|
+
call it clean just because the author is internal. Sid's verified Design-owner
|
|
307
|
+
exception still does not waive membership or the ultra-scary gate.
|
|
308
|
+
|
|
277
309
|
Read the Factory configuration. When GitHub polling is enabled and a repository
|
|
278
310
|
is configured, call poll-github-sources with includeIssues false and
|
|
279
311
|
includePullRequests true. List at most 3 new or changed pull requests by
|
|
@@ -281,11 +313,15 @@ passing needsReview true, source github, and limit 3. Never list the full queue
|
|
|
281
313
|
or use the action's default page size.
|
|
282
314
|
|
|
283
315
|
For each open agent-native PR, inspect the item and classify whether it is a
|
|
284
|
-
clear bug fix or has product or UX implications.
|
|
316
|
+
clear bug fix or has product or UX implications. Avoid duplicate review noise
|
|
317
|
+
when no commit, review, comment, or check result changed. Call
|
|
285
318
|
govern-agent-native-pull-request with the item id, repository, pull request
|
|
286
319
|
number, clearBug, productUxImplications, and a short reason. The action fetches
|
|
287
|
-
fresh CI and review evidence before approving or merging.
|
|
288
|
-
|
|
320
|
+
fresh CI and review evidence before approving or merging. For a verified
|
|
321
|
+
current BuilderIO member, the internal-author exception means ordinary failed,
|
|
322
|
+
pending, skipped, or unknown checks and unresolved ordinary feedback do not by
|
|
323
|
+
themselves block approval; record their exact states and never call them clean.
|
|
324
|
+
The exception does not waive membership, ownership, or the ultra-scary gate.
|
|
289
325
|
|
|
290
326
|
Only auto-merge when the PR proves its Factory origin by retaining the Factory
|
|
291
327
|
item id or source link in the PR description, or by using the Factory branch
|
|
@@ -352,7 +388,7 @@ function defaultGithubPollingEnabled(): 0 | 1 {
|
|
|
352
388
|
function automationPromptGuard(name: string): string | undefined {
|
|
353
389
|
switch (name) {
|
|
354
390
|
case "factory-slack-feedback":
|
|
355
|
-
return "Runtime safety bound: call list-triage-items with needsReview true, source slack, and limit
|
|
391
|
+
return "Runtime safety bound: call list-triage-items with needsReview true, source slack, and limit 5; process at most five new Slack items sequentially, and never use the default page size.";
|
|
356
392
|
case "factory-sentry-errors":
|
|
357
393
|
return "Runtime safety bound: call list-triage-items with needsReview true, source sentry, and limit 3; process at most three Sentry items.";
|
|
358
394
|
case "factory-github-issues":
|
|
@@ -71,6 +71,7 @@ export async function startBuilderRun(
|
|
|
71
71
|
input.sourceUrl ? `Source: ${input.sourceUrl}` : "",
|
|
72
72
|
input.repository ? `Repository: ${input.repository}` : "",
|
|
73
73
|
input.instructions ? `Triage instructions: ${input.instructions}` : "",
|
|
74
|
+
"Run /address-feedback in the repository and read the address-feedback, address-feedback-with-replies, review-latest-feedback, and review-prs skills as relevant. Search for repeat reports, fix the smallest owning boundary, and verify the full path before opening the pull request.",
|
|
74
75
|
"Inspect the repository, make the smallest safe fix, run validation, and open a pull request.",
|
|
75
76
|
"Include the Factory item id and source link in the pull request description.",
|
|
76
77
|
"Do not touch protected areas: auth/session/identity, credentials/vault, migrations, payments, security, or publishable packages.",
|