@agent-native/core 0.136.4 → 0.137.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/corpus/README.md +1 -1
- package/corpus/templates/clips/.agents/skills/recording/SKILL.md +53 -0
- package/corpus/templates/clips/actions/import-loom-recording.ts +7 -0
- package/corpus/templates/clips/actions/lib/loom-import-job.ts +24 -4
- package/corpus/templates/clips/app/components/import-menu.tsx +109 -0
- package/corpus/templates/clips/app/components/library/library-grid.tsx +8 -18
- package/corpus/templates/clips/app/components/library/library-layout.tsx +14 -50
- package/corpus/templates/clips/app/components/library/sort-menu.tsx +20 -6
- package/corpus/templates/clips/app/components/recorder/pre-record-panel.tsx +10 -34
- package/corpus/templates/clips/app/routes/_app.library._index.tsx +0 -2
- package/corpus/templates/clips/changelog/2026-08-03-restart-during-a-recording-now-immediately-starts-a-fresh-ta.md +6 -0
- package/corpus/templates/clips/changelog/2026-08-04-cleaner-library-controls-with-an-icon-only-sort-button.md +6 -0
- package/corpus/templates/clips/changelog/2026-08-04-upload-and-loom-imports-now-live-under-one-import-menu.md +6 -0
- package/corpus/templates/clips/desktop/src/app.tsx +81 -30
- package/corpus/templates/clips/desktop/src/lib/recorder.ts +436 -158
- package/corpus/templates/clips/server/lib/post-finalize-dispatch.ts +14 -1
- package/corpus/templates/clips/server/plugins/auth.ts +9 -0
- package/corpus/templates/clips/server/routes/api/_agent-native-background/post-finalize-worker.post.ts +13 -0
- package/corpus/templates/content/actions/_database-utils.ts +6 -0
- package/corpus/templates/content/actions/bind-content-database-source-field.ts +273 -97
- package/corpus/templates/content/actions/change-content-database-source-role.ts +65 -29
- package/corpus/templates/content/actions/configure-document-property.ts +113 -32
- package/corpus/templates/content/actions/delete-content-database.ts +5 -7
- package/corpus/templates/content/actions/delete-document-property.ts +109 -62
- package/corpus/templates/content/actions/delete-document.ts +178 -36
- package/corpus/templates/content/actions/duplicate-database-item.ts +27 -0
- package/corpus/templates/content/actions/duplicate-database-items.ts +31 -1
- package/corpus/templates/content/actions/permanently-delete-document.ts +4 -6
- package/corpus/templates/content/actions/remove-database-items.ts +13 -0
- package/corpus/templates/content/actions/set-document-property.ts +69 -1
- package/corpus/templates/content/actions/upsert-database-item-by-key.ts +814 -0
- package/corpus/templates/content/parity/matrix.md +1 -1
- package/corpus/templates/content/parity/matrix.ts +1 -0
- package/corpus/templates/content/server/db/schema.ts +27 -0
- package/corpus/templates/content/server/plugins/db.ts +24 -0
- package/corpus/templates/design/app/components/design/BreakpointBar.tsx +122 -114
- package/corpus/templates/design/app/components/design/CanvasContextMenu.tsx +2 -2
- package/corpus/templates/design/app/components/design/EditPanel.tsx +68 -34
- package/corpus/templates/design/app/components/design/KeyboardShortcutsPanel.tsx +78 -4
- package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +8 -0
- package/corpus/templates/design/app/components/design/QuestionFlow.tsx +5 -2
- package/corpus/templates/design/app/components/design/edit-panel/panel-primitives.tsx +10 -9
- package/corpus/templates/design/app/components/design/inspector/AutoLayoutMatrix.tsx +31 -69
- package/corpus/templates/design/app/components/design/inspector/design-icons.tsx +80 -106
- package/corpus/templates/design/app/components/design/multi-screen/types.ts +4 -0
- package/corpus/templates/design/app/hooks/use-editor-preferences.ts +75 -0
- package/corpus/templates/design/app/i18n-data.ts +8 -0
- package/corpus/templates/design/app/i18n-keyboard-shortcuts.ts +61 -0
- package/corpus/templates/design/app/pages/design-editor/editor-preferences.ts +98 -0
- package/corpus/templates/design/app/pages/design-editor/nudge-intent.ts +491 -0
- package/corpus/templates/design/app/pages/design-editor/paste-placement.ts +133 -0
- package/corpus/templates/design/app/pages/design-editor/png-export-render.ts +8 -0
- package/corpus/templates/design/app/pages/design-editor/selection-state.ts +5 -12
- package/corpus/templates/design/changelog/2026-08-03-arrow-keys-now-reorder-a-layer-inside-an-auto-layout-frame.md +6 -0
- package/corpus/templates/design/changelog/2026-08-03-auto-layout-flow-icons-show-the-direction-at-a-glance-instea.md +6 -0
- package/corpus/templates/design/changelog/2026-08-03-auto-layout-icons-share-one-outlined-square-style-so-flow-ga.md +6 -0
- package/corpus/templates/design/changelog/2026-08-03-export-has-a-named-preview-section-you-can-expand-replacing-.md +6 -0
- package/corpus/templates/design/changelog/2026-08-03-export-preview-shows-the-selected-element-instead-of-the-who.md +6 -0
- package/corpus/templates/design/changelog/2026-08-03-inspector-sections-show-an-expand-indicator-so-it-is-clear-w.md +6 -0
- package/corpus/templates/design/changelog/2026-08-03-paste-lands-inside-a-selected-frame-instead-of-beside-it.md +6 -0
- package/corpus/templates/design/changelog/2026-08-03-the-add-breakpoint-button-sits-outside-the-breakpoint-select.md +6 -0
- package/corpus/templates/design/changelog/2026-08-03-the-agent-s-follow-up-questions-keep-space-below-the-continu.md +6 -0
- package/corpus/templates/design/changelog/2026-08-03-the-agent-s-follow-up-questions-share-the-chat-panel-s-backg.md +6 -0
- package/corpus/templates/design/changelog/2026-08-03-the-export-panel-no-longer-stacks-a-duplicate-export-block-o.md +6 -0
- package/corpus/templates/design/changelog/2026-08-03-the-text-tool-uses-a-t-icon-matching-the-letter-it-inserts.md +6 -0
- package/corpus/templates/factory/.env.example +17 -0
- package/corpus/templates/factory/AGENTS.md +27 -17
- package/corpus/templates/factory/README.md +19 -9
- package/corpus/templates/factory/actions/get-slack-feedback-context.ts +90 -0
- package/corpus/templates/factory/actions/get-triage-config.ts +14 -3
- package/corpus/templates/factory/actions/govern-agent-native-pull-request.ts +386 -0
- package/corpus/templates/factory/actions/list-factory-automations.ts +53 -0
- package/corpus/templates/factory/actions/list-triage-items.ts +7 -2
- package/corpus/templates/factory/actions/poll-github-sources.ts +203 -0
- package/corpus/templates/factory/actions/poll-sentry-errors.ts +161 -0
- package/corpus/templates/factory/actions/poll-slack-channel.ts +4 -2
- package/corpus/templates/factory/actions/run-factory-automation.ts +42 -0
- package/corpus/templates/factory/actions/save-factory-automation.ts +69 -0
- package/corpus/templates/factory/actions/save-triage-config.ts +28 -2
- package/corpus/templates/factory/actions/start-builder-for-item.ts +411 -0
- package/corpus/templates/factory/app/components/factory/FactoryCanvas.tsx +14 -3
- package/corpus/templates/factory/app/components/ui/checkbox.tsx +1 -0
- package/corpus/templates/factory/app/hooks/use-navigation-state.ts +7 -0
- package/corpus/templates/factory/app/i18n/en-US.ts +35 -1
- package/corpus/templates/factory/app/routes/factory.tsx +462 -9
- package/corpus/templates/factory/changelog/2026-08-04-added-organization-owned-factory-automations-for-slack-bug-t.md +6 -0
- package/corpus/templates/factory/changelog/2026-08-04-automation-editor-controls-and-model-picker.md +6 -0
- package/corpus/templates/factory/netlify.toml +2 -2
- package/corpus/templates/factory/server/connectors/credentials.ts +6 -5
- package/corpus/templates/factory/server/connectors/slack.ts +133 -5
- package/corpus/templates/factory/server/db/schema.ts +6 -0
- package/corpus/templates/factory/server/lib/require-factory-automation.ts +65 -0
- package/corpus/templates/factory/server/plugins/agent-chat.ts +29 -11
- package/corpus/templates/factory/server/plugins/auth.ts +1 -0
- package/corpus/templates/factory/server/plugins/factory-migrations.ts +12 -0
- package/corpus/templates/factory/server/plugins/factory-scheduler-job.ts +218 -67
- package/corpus/templates/factory/server/triage/builder-executor.ts +4 -0
- package/corpus/templates/factory/server/triage/contracts.ts +14 -1
- package/corpus/templates/factory/server/triage/github-client.ts +404 -0
- package/corpus/templates/factory/server/triage/metadata.ts +44 -0
- package/corpus/templates/factory/server/triage/pr-babysit.ts +5 -5
- package/corpus/templates/factory/server/triage/pr-policy.ts +144 -0
- package/corpus/templates/factory/server/triage/sentry-client.ts +180 -0
- package/corpus/templates/factory/server/triage/slack-client.ts +43 -0
- package/corpus/templates/factory/server/triage/slack-poller.ts +9 -2
- package/corpus/templates/plan/.agents/skills/visual-plan/SKILL.md +27 -0
- package/corpus/templates/plan/.agents/skills/visual-plan/references/canvas.md +14 -4
- package/corpus/templates/plan/.agents/skills/visual-plan/references/wireframe.md +7 -0
- package/corpus/templates/plan/.agents/skills/visual-recap/references/wireframe.md +7 -0
- package/corpus/templates/plan/actions/create-plan-design.ts +8 -6
- package/corpus/templates/plan/actions/create-prototype-plan.ts +8 -6
- package/corpus/templates/plan/actions/create-ui-plan.ts +7 -7
- package/corpus/templates/plan/actions/get-plan-blocks.ts +7 -1
- package/corpus/templates/plan/actions/validate-plan-input.ts +39 -0
- package/corpus/templates/plan/app/components/plan/CanvasArea.tsx +167 -11
- package/corpus/templates/plan/app/i18n/en-US.ts +1 -0
- package/corpus/templates/plan/changelog/2026-08-04-canvas-zoom-controls-now-explain-the-command-ctrl-plus-scrol.md +6 -0
- package/corpus/templates/plan/changelog/2026-08-04-pinch-to-zoom-is-now-supported-on-touchscreens-in-visual-pla.md +6 -0
- package/corpus/templates/plan/shared/plan-content.ts +17 -2
- package/dist/cli/skills-content/canvas.d.ts +3 -3
- package/dist/cli/skills-content/canvas.js +16 -5
- package/dist/cli/skills-content/visual-plan-skill.d.ts +1 -1
- package/dist/cli/skills-content/visual-plan-skill.js +27 -0
- package/dist/cli/skills-content/wireframe.d.ts +2 -2
- package/dist/cli/skills-content/wireframe.js +7 -0
- package/dist/client/AgentPanel.js +23 -8
- package/dist/client/api-path.d.ts +6 -0
- package/dist/client/api-path.js +55 -0
- package/dist/client/onboarding/FirstRunOnboarding.d.ts +3 -0
- package/dist/client/onboarding/FirstRunOnboarding.js +93 -0
- package/dist/client/onboarding/first-run-enabled.d.ts +2 -0
- package/dist/client/onboarding/first-run-enabled.js +9 -0
- package/dist/client/onboarding/index.d.ts +2 -1
- package/dist/client/onboarding/index.js +1 -0
- package/dist/client/onboarding/use-onboarding.d.ts +6 -1
- package/dist/client/onboarding/use-onboarding.js +32 -1
- package/dist/client/route-state.js +10 -0
- package/dist/client/settings/SecretsSection.js +32 -8
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/connections/catalog.d.ts +4 -4
- package/dist/connections/catalog.js +3 -3
- package/dist/db/index.d.ts +1 -1
- package/dist/db/index.js +1 -1
- package/dist/localization/default-messages.d.ts +5 -0
- package/dist/localization/default-messages.js +5 -0
- package/dist/mcp/screen-memory-stdio.d.ts +7 -7
- package/dist/observability/routes.d.ts +3 -3
- package/dist/onboarding/app-profile.d.ts +4 -0
- package/dist/onboarding/app-profile.js +378 -0
- package/dist/onboarding/index.d.ts +2 -1
- package/dist/onboarding/index.js +1 -0
- package/dist/onboarding/plugin.d.ts +2 -0
- package/dist/onboarding/plugin.js +21 -1
- package/dist/onboarding/types.d.ts +19 -0
- 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 +12 -12
- package/dist/secrets/routes.d.ts +2 -2
- package/dist/secrets/routes.js +41 -17
- package/dist/server/auth.js +21 -1
- package/dist/server/better-auth-instance.d.ts +3 -2
- package/dist/server/better-auth-instance.js +9 -7
- package/dist/server/email-markdown.js +3 -8
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/dist/shared/first-run-onboarding.d.ts +3 -0
- package/dist/shared/first-run-onboarding.js +3 -0
- package/dist/triggers/index.d.ts +3 -0
- package/dist/triggers/index.js +5 -0
- package/docs/content/cross-app-sso.mdx +26 -0
- package/package.json +1 -1
|
@@ -26,9 +26,35 @@ export interface ChannelHistoryResult {
|
|
|
26
26
|
next_cursor?: string;
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
+
export interface ThreadRepliesResult {
|
|
30
|
+
messages: SlackMessage[];
|
|
31
|
+
has_more: boolean;
|
|
32
|
+
next_cursor?: string;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface SlackReactionResult {
|
|
36
|
+
added: boolean;
|
|
37
|
+
already_present: boolean;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface SlackPostMessageResult {
|
|
41
|
+
ok?: boolean;
|
|
42
|
+
error?: string;
|
|
43
|
+
channel: string;
|
|
44
|
+
ts: string;
|
|
45
|
+
message?: SlackMessage;
|
|
46
|
+
}
|
|
47
|
+
|
|
29
48
|
const cache = new Map<string, { value: unknown; expiresAt: number }>();
|
|
30
49
|
const cacheTtlMs = 120_000;
|
|
31
50
|
|
|
51
|
+
function invalidateWorkspaceCache(workspace: Workspace): void {
|
|
52
|
+
const prefix = `${workspace}:`;
|
|
53
|
+
for (const key of cache.keys()) {
|
|
54
|
+
if (key.startsWith(prefix)) cache.delete(key);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
32
58
|
async function getToken(
|
|
33
59
|
workspace: Workspace,
|
|
34
60
|
tokenResolver?: SlackTokenResolver,
|
|
@@ -60,12 +86,40 @@ async function slackApi<T>(
|
|
|
60
86
|
`Slack API error ${response.status}: ${await response.text()}`,
|
|
61
87
|
);
|
|
62
88
|
const data = (await response.json()) as T & { ok?: boolean; error?: string };
|
|
63
|
-
if (data.ok
|
|
89
|
+
if (data.ok !== true)
|
|
64
90
|
throw new Error(`Slack API error: ${data.error ?? "unknown_error"}`);
|
|
65
91
|
cache.set(cacheKey, { value: data, expiresAt: Date.now() + cacheTtlMs });
|
|
66
92
|
return data;
|
|
67
93
|
}
|
|
68
94
|
|
|
95
|
+
async function slackWrite<T extends { ok?: boolean; error?: string }>(
|
|
96
|
+
workspace: Workspace,
|
|
97
|
+
method: string,
|
|
98
|
+
body: Record<string, string>,
|
|
99
|
+
tokenResolver?: SlackTokenResolver,
|
|
100
|
+
): Promise<T> {
|
|
101
|
+
const token = await getToken(workspace, tokenResolver);
|
|
102
|
+
const response = await fetch(`https://slack.com/api/${method}`, {
|
|
103
|
+
method: "POST",
|
|
104
|
+
headers: {
|
|
105
|
+
Authorization: `Bearer ${token}`,
|
|
106
|
+
"Content-Type": "application/json; charset=utf-8",
|
|
107
|
+
},
|
|
108
|
+
body: JSON.stringify(body),
|
|
109
|
+
});
|
|
110
|
+
if (!response.ok)
|
|
111
|
+
throw new Error(
|
|
112
|
+
`Slack API error ${response.status}: ${await response.text()}`,
|
|
113
|
+
);
|
|
114
|
+
const data = (await response.json()) as T;
|
|
115
|
+
if (data.ok !== true)
|
|
116
|
+
throw new Error(`Slack API error: ${data.error ?? "unknown_error"}`);
|
|
117
|
+
// A successful reaction or message write makes cached reads stale. This is
|
|
118
|
+
// especially important when a retry follows a partially recorded handoff.
|
|
119
|
+
invalidateWorkspaceCache(workspace);
|
|
120
|
+
return data;
|
|
121
|
+
}
|
|
122
|
+
|
|
69
123
|
export async function getChannelHistory(
|
|
70
124
|
workspace: Workspace,
|
|
71
125
|
channelId: string,
|
|
@@ -83,7 +137,10 @@ export async function getChannelHistory(
|
|
|
83
137
|
messages?: SlackMessage[];
|
|
84
138
|
has_more?: boolean;
|
|
85
139
|
}>(workspace, "conversations.history", params, tokenResolver);
|
|
86
|
-
|
|
140
|
+
if (!Array.isArray(data.messages)) {
|
|
141
|
+
throw new Error("Slack history response is missing messages.");
|
|
142
|
+
}
|
|
143
|
+
const messages = data.messages;
|
|
87
144
|
return {
|
|
88
145
|
messages,
|
|
89
146
|
has_more: Boolean(data.has_more),
|
|
@@ -100,13 +157,19 @@ export async function getChannelHistory(
|
|
|
100
157
|
},
|
|
101
158
|
body: JSON.stringify({ channel: channelId }),
|
|
102
159
|
});
|
|
103
|
-
const joinedData = (await joined.json()) as {
|
|
104
|
-
|
|
160
|
+
const joinedData = (await joined.json()) as {
|
|
161
|
+
ok?: boolean;
|
|
162
|
+
error?: string;
|
|
163
|
+
};
|
|
164
|
+
if (joinedData.ok !== true) throw error;
|
|
105
165
|
const data = await slackApi<{
|
|
106
166
|
messages?: SlackMessage[];
|
|
107
167
|
has_more?: boolean;
|
|
108
168
|
}>(workspace, "conversations.history", params, tokenResolver);
|
|
109
|
-
|
|
169
|
+
if (!Array.isArray(data.messages)) {
|
|
170
|
+
throw new Error("Slack history response is missing messages.");
|
|
171
|
+
}
|
|
172
|
+
const messages = data.messages;
|
|
110
173
|
return {
|
|
111
174
|
messages,
|
|
112
175
|
has_more: Boolean(data.has_more),
|
|
@@ -115,6 +178,71 @@ export async function getChannelHistory(
|
|
|
115
178
|
}
|
|
116
179
|
}
|
|
117
180
|
|
|
181
|
+
export async function getThread(
|
|
182
|
+
workspace: Workspace,
|
|
183
|
+
channelId: string,
|
|
184
|
+
threadTs: string,
|
|
185
|
+
limit = 100,
|
|
186
|
+
cursor?: string,
|
|
187
|
+
tokenResolver?: SlackTokenResolver,
|
|
188
|
+
): Promise<ThreadRepliesResult> {
|
|
189
|
+
const params: Record<string, string> = {
|
|
190
|
+
channel: channelId,
|
|
191
|
+
ts: threadTs,
|
|
192
|
+
limit: String(Math.min(Math.max(limit, 1), 100)),
|
|
193
|
+
};
|
|
194
|
+
if (cursor) params.cursor = cursor;
|
|
195
|
+
const data = await slackApi<{
|
|
196
|
+
messages?: SlackMessage[];
|
|
197
|
+
has_more?: boolean;
|
|
198
|
+
response_metadata?: { next_cursor?: string };
|
|
199
|
+
}>(workspace, "conversations.replies", params, tokenResolver);
|
|
200
|
+
if (!Array.isArray(data.messages)) {
|
|
201
|
+
throw new Error("Slack thread response is missing messages.");
|
|
202
|
+
}
|
|
203
|
+
return {
|
|
204
|
+
messages: data.messages,
|
|
205
|
+
has_more: Boolean(data.has_more),
|
|
206
|
+
next_cursor: data.response_metadata?.next_cursor || undefined,
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
export async function addEyesReaction(
|
|
211
|
+
workspace: Workspace,
|
|
212
|
+
channelId: string,
|
|
213
|
+
timestamp: string,
|
|
214
|
+
tokenResolver?: SlackTokenResolver,
|
|
215
|
+
): Promise<SlackReactionResult> {
|
|
216
|
+
try {
|
|
217
|
+
await slackWrite(
|
|
218
|
+
workspace,
|
|
219
|
+
"reactions.add",
|
|
220
|
+
{ channel: channelId, timestamp, name: "eyes" },
|
|
221
|
+
tokenResolver,
|
|
222
|
+
);
|
|
223
|
+
return { added: true, already_present: false };
|
|
224
|
+
} catch (error) {
|
|
225
|
+
if (!String(error).includes("already_reacted")) throw error;
|
|
226
|
+
return { added: false, already_present: true };
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
export async function postThreadReply(
|
|
231
|
+
workspace: Workspace,
|
|
232
|
+
channelId: string,
|
|
233
|
+
threadTs: string,
|
|
234
|
+
text: string,
|
|
235
|
+
tokenResolver?: SlackTokenResolver,
|
|
236
|
+
): Promise<SlackPostMessageResult> {
|
|
237
|
+
const data = await slackWrite<SlackPostMessageResult>(
|
|
238
|
+
workspace,
|
|
239
|
+
"chat.postMessage",
|
|
240
|
+
{ channel: channelId, thread_ts: threadTs, text },
|
|
241
|
+
tokenResolver,
|
|
242
|
+
);
|
|
243
|
+
return data;
|
|
244
|
+
}
|
|
245
|
+
|
|
118
246
|
export async function getTeamInfo(
|
|
119
247
|
workspace: Workspace,
|
|
120
248
|
tokenResolver?: SlackTokenResolver,
|
|
@@ -114,6 +114,12 @@ export const triageConfig = table("factory_config", {
|
|
|
114
114
|
lastSlackTs: text("last_slack_ts"),
|
|
115
115
|
slackHistoryCursor: text("slack_history_cursor"),
|
|
116
116
|
repository: text("repository"),
|
|
117
|
+
githubPollingEnabled: integer("github_polling_enabled").notNull().default(0),
|
|
118
|
+
sentryPollingEnabled: integer("sentry_polling_enabled").notNull().default(0),
|
|
119
|
+
sentryOrgSlug: text("sentry_org_slug"),
|
|
120
|
+
sentryProjectSlug: text("sentry_project_slug"),
|
|
121
|
+
sentryEnvironment: text("sentry_environment"),
|
|
122
|
+
lastSentrySeenAt: text("last_sentry_seen_at"),
|
|
117
123
|
createdAt: text("created_at").notNull().default(now()),
|
|
118
124
|
updatedAt: text("updated_at").notNull().default(now()),
|
|
119
125
|
ownerEmail: text("owner_email").notNull(),
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import type { ActionRunContext } from "@agent-native/core/action";
|
|
2
|
+
import { listAutomationDefinitions } from "@agent-native/core/triggers";
|
|
3
|
+
|
|
4
|
+
import type { WorkspaceMemberIdentity } from "./require-workspace-member.js";
|
|
5
|
+
|
|
6
|
+
const FACTORY_AUTOMATION_NAMES = {
|
|
7
|
+
builderDispatch: new Set([
|
|
8
|
+
"factory-slack-feedback",
|
|
9
|
+
"factory-sentry-errors",
|
|
10
|
+
"factory-github-issues",
|
|
11
|
+
]),
|
|
12
|
+
governance: new Set(["factory-pr-governance"]),
|
|
13
|
+
sourcePolling: new Set([
|
|
14
|
+
"factory-slack-feedback",
|
|
15
|
+
"factory-sentry-errors",
|
|
16
|
+
"factory-github-issues",
|
|
17
|
+
"factory-pr-governance",
|
|
18
|
+
]),
|
|
19
|
+
} as const;
|
|
20
|
+
|
|
21
|
+
export type FactoryAutomationRole = keyof typeof FACTORY_AUTOMATION_NAMES;
|
|
22
|
+
|
|
23
|
+
function workspaceOwnerEmail(): string | undefined {
|
|
24
|
+
const email = process.env.WORKSPACE_OWNER_EMAIL?.trim().toLowerCase(); // guard:allow-env-credential - deployment owner identity, not a user credential
|
|
25
|
+
if (!email || /[\r\n]/.test(email)) return undefined;
|
|
26
|
+
return email;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export async function requireFactoryAutomation(
|
|
30
|
+
context: ActionRunContext | undefined,
|
|
31
|
+
identity: Pick<WorkspaceMemberIdentity, "userEmail" | "orgId">,
|
|
32
|
+
role: FactoryAutomationRole,
|
|
33
|
+
): Promise<void> {
|
|
34
|
+
if (context?.caller !== "automation") {
|
|
35
|
+
throw new Error("This action is only available to Factory automations.");
|
|
36
|
+
}
|
|
37
|
+
const lineage = context.automation;
|
|
38
|
+
const expectedNames = FACTORY_AUTOMATION_NAMES[role];
|
|
39
|
+
if (!lineage || !expectedNames.has(lineage.triggerName)) {
|
|
40
|
+
throw new Error(
|
|
41
|
+
"The action was not invoked by a governed Factory automation.",
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const definition = (
|
|
46
|
+
await listAutomationDefinitions(
|
|
47
|
+
{ userEmail: identity.userEmail, orgId: identity.orgId },
|
|
48
|
+
"organization",
|
|
49
|
+
)
|
|
50
|
+
).find((entry) => entry.resource.id === lineage.triggerId);
|
|
51
|
+
const ownerEmail = workspaceOwnerEmail();
|
|
52
|
+
if (
|
|
53
|
+
!definition ||
|
|
54
|
+
definition.name !== lineage.triggerName ||
|
|
55
|
+
definition.meta.domain !== "factory" ||
|
|
56
|
+
definition.meta.orgId !== identity.orgId ||
|
|
57
|
+
definition.meta.runAs !== "creator" ||
|
|
58
|
+
!ownerEmail ||
|
|
59
|
+
definition.meta.createdBy?.trim().toLowerCase() !== ownerEmail
|
|
60
|
+
) {
|
|
61
|
+
throw new Error(
|
|
62
|
+
"The action was not invoked by a governed Factory automation.",
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
@@ -17,7 +17,14 @@ const INITIAL_TOOL_NAMES = [
|
|
|
17
17
|
"list-triage-items",
|
|
18
18
|
"get-triage-item",
|
|
19
19
|
"poll-slack-channel",
|
|
20
|
+
"get-slack-feedback-context",
|
|
21
|
+
"poll-github-sources",
|
|
22
|
+
"poll-sentry-errors",
|
|
20
23
|
"evaluate-triage-item",
|
|
24
|
+
"start-builder-for-item",
|
|
25
|
+
"govern-agent-native-pull-request",
|
|
26
|
+
"babysit-pull-request",
|
|
27
|
+
"approve-factory-item",
|
|
21
28
|
"list-triage-rules",
|
|
22
29
|
"get-triage-config",
|
|
23
30
|
"navigate",
|
|
@@ -31,16 +38,18 @@ const options = {
|
|
|
31
38
|
resolveOrgId: async (event) => (await getOrgContext(event)).orgId,
|
|
32
39
|
systemPrompt: `You are the Factory agent.
|
|
33
40
|
|
|
34
|
-
Factory is a visual factory builder. It observes Slack feedback
|
|
35
|
-
evidence, renders the current factory graph, and
|
|
36
|
-
|
|
41
|
+
Factory is a visual factory builder. It observes Slack feedback, GitHub issues,
|
|
42
|
+
Sentry errors, and pull-request evidence, renders the current factory graph, and
|
|
43
|
+
executes only the explicit automation prompts that are stored in the organization.
|
|
44
|
+
Use the Factory actions as the source of truth. When a user asks to
|
|
37
45
|
create or change a factory, first inspect the current graph, then propose a complete
|
|
38
46
|
versioned graph through save-factory-graph with source=ai and a concise changeSummary.
|
|
39
47
|
Never hide a graph change in prose: the visual map and the saved graph must agree.
|
|
40
|
-
The graph is currently a reviewable blueprint, not the runtime router:
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
48
|
+
The graph is currently a reviewable blueprint, not the runtime router: automation
|
|
49
|
+
markdown resources are the runtime prompts, while enabled triage rules are evaluated
|
|
50
|
+
in parallel against the same evidence. Do not claim that an edge changes execution.
|
|
51
|
+
For rule or guard changes, use the triage rule actions and preserve
|
|
52
|
+
normalizeTriagePolicyGuards; do not encode policy in graph JSON.
|
|
44
53
|
Use add-factory-comment for durable comments attached to the selected node or edge.
|
|
45
54
|
Explain the evidence and guard results before proposing work.
|
|
46
55
|
When discussing agent failures, preserve these measured taxonomy labels exactly:
|
|
@@ -49,10 +58,19 @@ overloaded_error, and Missing provider authentication. Always inspect interactiv
|
|
|
49
58
|
and scheduled job populations separately; scheduled runs have ids beginning with
|
|
50
59
|
job- and must not be hidden by an interactive-only query.
|
|
51
60
|
Never bypass a hard guard or claim that a provider action happened without a
|
|
52
|
-
durable run record and a confirmed terminal callback.
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
61
|
+
durable run record and a confirmed terminal callback. A clear bug means concrete
|
|
62
|
+
broken behavior, reproducible failure, error, regression, stuck run, incorrect
|
|
63
|
+
result, or a specific failing path with enough evidence to investigate. Feature
|
|
64
|
+
requests, broad UX suggestions, vague questions, and incomplete context stay
|
|
65
|
+
manual. Clips, Design, and Content are fully owner-managed: never react, tag
|
|
66
|
+
Builder, auto-approve, or auto-merge those items. Slack clear bugs use the
|
|
67
|
+
thread-preserving start-builder-for-item flow; GitHub and Sentry clear bugs use
|
|
68
|
+
the Builder agent-run flow. For pull requests, auto-approval requires an internal
|
|
69
|
+
BuilderIO author, a clear bug, passing CI, and handled review feedback. Auto-merge
|
|
70
|
+
also requires a verified Factory Builder run. When a user says to do a review-gated
|
|
71
|
+
item now, use the explicit approval action, which records the approver and applies
|
|
72
|
+
the rule's configured executor policy. Keep Slack replies concise and link to the
|
|
73
|
+
Factory item when a review is needed.`,
|
|
56
74
|
} satisfies AgentChatPluginOptions;
|
|
57
75
|
|
|
58
76
|
export default createAgentChatPlugin(options);
|
|
@@ -236,6 +236,18 @@ const migrations = [
|
|
|
236
236
|
ON factory_comments (org_id, factory_id, created_at);
|
|
237
237
|
`,
|
|
238
238
|
},
|
|
239
|
+
{
|
|
240
|
+
version: 16,
|
|
241
|
+
name: "factory-source-polling-settings",
|
|
242
|
+
sql: `
|
|
243
|
+
ALTER TABLE factory_config ADD COLUMN github_polling_enabled INTEGER NOT NULL DEFAULT 0;
|
|
244
|
+
ALTER TABLE factory_config ADD COLUMN sentry_polling_enabled INTEGER NOT NULL DEFAULT 0;
|
|
245
|
+
ALTER TABLE factory_config ADD COLUMN sentry_org_slug TEXT;
|
|
246
|
+
ALTER TABLE factory_config ADD COLUMN sentry_project_slug TEXT;
|
|
247
|
+
ALTER TABLE factory_config ADD COLUMN sentry_environment TEXT;
|
|
248
|
+
ALTER TABLE factory_config ADD COLUMN last_sentry_seen_at TEXT;
|
|
249
|
+
`,
|
|
250
|
+
},
|
|
239
251
|
];
|
|
240
252
|
|
|
241
253
|
export const runFactoryMigrations = runMigrations(migrations, {
|