@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
|
@@ -1,41 +1,146 @@
|
|
|
1
|
+
import { resolveOrgIdForEmail } from "@agent-native/core/org";
|
|
1
2
|
import {
|
|
2
|
-
|
|
3
|
+
organizationResourceOwner,
|
|
3
4
|
resourceGetByPath,
|
|
4
5
|
resourcePut,
|
|
6
|
+
WORKSPACE_OWNER,
|
|
5
7
|
} from "@agent-native/core/resources";
|
|
6
8
|
import { defineNitroPlugin } from "@agent-native/core/server";
|
|
9
|
+
import { and, eq } from "drizzle-orm";
|
|
7
10
|
|
|
8
|
-
|
|
11
|
+
import { getDb } from "../db/index.js";
|
|
12
|
+
import { triageConfig } from "../db/schema.js";
|
|
9
13
|
|
|
10
|
-
const
|
|
11
|
-
|
|
14
|
+
const LEGACY_JOB_PATH = "jobs/factory-observation-scheduler.md";
|
|
15
|
+
const DEFAULT_SLACK_CHANNEL_ID = "C0ATH3CCZT4";
|
|
16
|
+
const DEFAULT_SLACK_CHANNEL_NAME = "product-agent-native-feedback";
|
|
12
17
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
type AutomationSeed = {
|
|
19
|
+
name: string;
|
|
20
|
+
schedule: string;
|
|
21
|
+
timezone?: string;
|
|
22
|
+
body: string;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const AUTOMATION_SEEDS: AutomationSeed[] = [
|
|
26
|
+
{
|
|
27
|
+
name: "factory-slack-feedback",
|
|
28
|
+
schedule: "* * * * *",
|
|
29
|
+
body: `
|
|
30
|
+
# Factory Slack feedback triage
|
|
31
|
+
|
|
32
|
+
Read the Factory configuration. When Slack polling is enabled and a channel is
|
|
33
|
+
configured, call poll-slack-channel first. Then list a bounded page of
|
|
34
|
+
received Slack items and call get-slack-feedback-context for each item before
|
|
35
|
+
classifying it.
|
|
36
|
+
|
|
37
|
+
Start work only for a clear bug: a concrete broken behavior, reproducible
|
|
38
|
+
failure, error, regression, stuck run, incorrect result, or a report with a
|
|
39
|
+
specific failing path and enough evidence to investigate. Do not treat feature
|
|
40
|
+
requests, wish-list ideas, broad UX suggestions, vague questions, or an
|
|
41
|
+
incomplete/truncated thread as clear bugs. The user's historical eyeball
|
|
42
|
+
reactions are calibration evidence, not an automatic authorization signal.
|
|
43
|
+
That history is strongest for concrete failures such as stuck or never-starting
|
|
44
|
+
runs, incorrect object/object output, disk-full or database-locked errors,
|
|
45
|
+
stale loops, broken uploads or duplicate imports, missing scaffolding or docs,
|
|
46
|
+
and concrete auth or configuration failures. Use those examples to recognize
|
|
47
|
+
the shape of a bug, not to turn similar-sounding reports into automatic work.
|
|
48
|
+
|
|
49
|
+
For a clear bug outside Clips, Design, and Content, call start-builder-for-item
|
|
50
|
+
with clearBug true and a short evidence-grounded reason. That action adds the
|
|
51
|
+
eyes reaction and tags @builderio in the Slack thread, asking Builder to fix
|
|
52
|
+
it in a reply and send a PR. Never add the reaction or tag Builder for
|
|
53
|
+
owner-managed Clips, Design, or Content work, or for a non-bug report.
|
|
54
|
+
|
|
55
|
+
Keep each run bounded. Preserve action errors and do not claim a Builder reply,
|
|
56
|
+
PR, merge, or fix unless an action returned that state.
|
|
57
|
+
`,
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
name: "factory-sentry-errors",
|
|
61
|
+
schedule: "0 9 * * *",
|
|
62
|
+
timezone: "America/Los_Angeles",
|
|
63
|
+
body: `
|
|
64
|
+
# Factory Sentry error triage
|
|
65
|
+
|
|
66
|
+
Read the Factory configuration. When Sentry polling is enabled and a Sentry
|
|
67
|
+
organization is configured, call poll-sentry-errors. List a bounded page of
|
|
68
|
+
received Sentry items and inspect the title, culprit, level, event count, and
|
|
69
|
+
errorReport metadata.
|
|
70
|
+
|
|
71
|
+
Only classify a concrete unresolved error as a clear bug when the Sentry
|
|
72
|
+
evidence is sufficient to investigate. Do not dispatch on noise, expected
|
|
73
|
+
errors, product ideas, or incomplete provider responses. Clips, Design, and
|
|
74
|
+
Content errors are owner-managed and must remain needs_manual.
|
|
75
|
+
|
|
76
|
+
For each eligible clear bug, call start-builder-for-item with clearBug true,
|
|
77
|
+
an evidence-grounded reason, and clearErrorReport containing only the bounded
|
|
78
|
+
Sentry evidence. Builder should open a PR; do not claim it did so until the
|
|
79
|
+
run callback or PR observation confirms it.
|
|
80
|
+
`,
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
name: "factory-github-issues",
|
|
84
|
+
schedule: "* * * * *",
|
|
85
|
+
body: `
|
|
86
|
+
# Factory GitHub issue triage
|
|
21
87
|
|
|
22
|
-
|
|
88
|
+
Read the Factory configuration. When GitHub source polling is enabled and a
|
|
89
|
+
repository is configured, call poll-github-sources with includeIssues true and
|
|
90
|
+
includePullRequests false. List a bounded page of received github_issue items.
|
|
91
|
+
|
|
92
|
+
Treat an issue as a clear bug only when it has a concrete error report,
|
|
93
|
+
reproduction, incorrect behavior, regression, or specific failing path. Do
|
|
94
|
+
not dispatch feature requests, vague questions, or issues without enough
|
|
95
|
+
evidence. Clips, Design, and Content remain owner-managed.
|
|
96
|
+
|
|
97
|
+
For each eligible item call start-builder-for-item with clearBug true,
|
|
98
|
+
evidence-grounded reason, and the bounded issue body as clearErrorReport.
|
|
99
|
+
Preserve failures and never report a successful Builder run without its action
|
|
100
|
+
confirmation.
|
|
101
|
+
`,
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
name: "factory-pr-governance",
|
|
105
|
+
schedule: "*/5 * * * *",
|
|
106
|
+
body: `
|
|
107
|
+
# Factory pull-request governance
|
|
108
|
+
|
|
109
|
+
Read the Factory configuration. When GitHub polling is enabled and a repository
|
|
110
|
+
is configured, call poll-github-sources with includeIssues false and
|
|
111
|
+
includePullRequests true. List a bounded page of github pull-request items.
|
|
112
|
+
|
|
113
|
+
For each open agent-native PR, inspect the item and classify whether it is a
|
|
114
|
+
clear bug fix or has product or UX implications. Call
|
|
115
|
+
govern-agent-native-pull-request with the item id, repository, pull request
|
|
116
|
+
number, clearBug, productUxImplications, and a short reason. The action fetches
|
|
117
|
+
fresh CI and review evidence before approving or merging. Clear internal bug
|
|
118
|
+
fixes with passing CI and handled review feedback may be auto-approved.
|
|
119
|
+
|
|
120
|
+
Only auto-merge when the PR proves its Factory origin by retaining the Factory
|
|
121
|
+
item id or source link in the PR description, or by using the Factory branch
|
|
122
|
+
name. A normal open PR must never be treated as a Builder-triggered run.
|
|
123
|
+
|
|
124
|
+
Never auto-approve or auto-merge Clips, Design, or Content PRs. Those apps are
|
|
125
|
+
fully owned by their product owners. Auto-merge is limited to PRs with a
|
|
126
|
+
verified Factory Builder run; all other PRs can at most pass the approval
|
|
127
|
+
policy. Do not call GitHub write actions directly or claim a merge unless the
|
|
128
|
+
governance action confirms it.
|
|
129
|
+
`,
|
|
130
|
+
},
|
|
131
|
+
];
|
|
132
|
+
|
|
133
|
+
function workspaceOwnerEmail(): string | undefined {
|
|
23
134
|
const email = process.env.WORKSPACE_OWNER_EMAIL?.trim().toLowerCase(); // guard:allow-env-credential - deployment owner identity, not a user credential
|
|
24
135
|
if (!email || /[\r\n]/.test(email)) return undefined;
|
|
25
136
|
return email;
|
|
26
137
|
}
|
|
27
138
|
|
|
28
|
-
function
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
.slice(4, end)
|
|
34
|
-
.match(new RegExp(`^${key}:\\s*(.*)$`, "m"));
|
|
35
|
-
return match ? match[1].trim() : null;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function setFrontmatterField(content: string, key: string, value: string) {
|
|
139
|
+
function setFrontmatterField(
|
|
140
|
+
content: string,
|
|
141
|
+
key: string,
|
|
142
|
+
value: string,
|
|
143
|
+
): string {
|
|
39
144
|
if (!content.startsWith("---\n")) return content;
|
|
40
145
|
const end = content.indexOf("\n---", 4);
|
|
41
146
|
if (end === -1) return content;
|
|
@@ -47,70 +152,116 @@ function setFrontmatterField(content: string, key: string, value: string) {
|
|
|
47
152
|
return `${content.slice(0, end)}\n${key}: ${value}${content.slice(end)}`;
|
|
48
153
|
}
|
|
49
154
|
|
|
50
|
-
function
|
|
155
|
+
function automationContent(
|
|
156
|
+
ownerEmail: string,
|
|
157
|
+
orgId: string,
|
|
158
|
+
seed: AutomationSeed,
|
|
159
|
+
): string {
|
|
51
160
|
return `---
|
|
52
|
-
schedule: "
|
|
53
|
-
enabled: true
|
|
54
|
-
|
|
161
|
+
schedule: "${seed.schedule}"
|
|
162
|
+
${seed.timezone ? `timezone: ${seed.timezone}\n` : ""}enabled: true
|
|
163
|
+
triggerType: schedule
|
|
164
|
+
domain: factory
|
|
165
|
+
orgId: ${orgId}
|
|
166
|
+
createdBy: ${ownerEmail}
|
|
55
167
|
runAs: creator
|
|
56
168
|
---
|
|
57
|
-
${
|
|
169
|
+
${seed.body.trim()}
|
|
170
|
+
`;
|
|
58
171
|
}
|
|
59
172
|
|
|
60
|
-
async function
|
|
61
|
-
const existing = await resourceGetByPath(WORKSPACE_OWNER,
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
if (
|
|
65
|
-
if (!ownerEmail) {
|
|
66
|
-
throw new Error(
|
|
67
|
-
"WORKSPACE_OWNER_EMAIL is required to seed the Factory scheduler",
|
|
68
|
-
);
|
|
69
|
-
}
|
|
173
|
+
async function disableLegacyObserver(): Promise<void> {
|
|
174
|
+
const existing = await resourceGetByPath(WORKSPACE_OWNER, LEGACY_JOB_PATH);
|
|
175
|
+
if (!existing) return;
|
|
176
|
+
const disabled = setFrontmatterField(existing.content, "enabled", "false");
|
|
177
|
+
if (disabled !== existing.content) {
|
|
70
178
|
await resourcePut(
|
|
71
179
|
WORKSPACE_OWNER,
|
|
72
|
-
|
|
73
|
-
|
|
180
|
+
LEGACY_JOB_PATH,
|
|
181
|
+
disabled,
|
|
182
|
+
"text/markdown",
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
async function ensureOrganizationAutomations(
|
|
188
|
+
ownerEmail: string,
|
|
189
|
+
orgId: string,
|
|
190
|
+
): Promise<void> {
|
|
191
|
+
const owner = organizationResourceOwner(orgId);
|
|
192
|
+
for (const seed of AUTOMATION_SEEDS) {
|
|
193
|
+
const path = `jobs/${seed.name}.md`;
|
|
194
|
+
if (await resourceGetByPath(owner, path)) continue;
|
|
195
|
+
await resourcePut(
|
|
196
|
+
owner,
|
|
197
|
+
path,
|
|
198
|
+
automationContent(ownerEmail, orgId, seed),
|
|
74
199
|
"text/markdown",
|
|
75
200
|
);
|
|
76
|
-
return;
|
|
77
201
|
}
|
|
202
|
+
}
|
|
78
203
|
|
|
204
|
+
async function ensureDefaultTriageConfig(
|
|
205
|
+
ownerEmail: string,
|
|
206
|
+
orgId: string,
|
|
207
|
+
): Promise<void> {
|
|
208
|
+
const db = getDb();
|
|
209
|
+
const existing = (
|
|
210
|
+
await db
|
|
211
|
+
.select({ id: triageConfig.id })
|
|
212
|
+
.from(triageConfig)
|
|
213
|
+
.where(and(eq(triageConfig.id, orgId), eq(triageConfig.orgId, orgId)))
|
|
214
|
+
.limit(1)
|
|
215
|
+
)[0];
|
|
216
|
+
if (existing) return;
|
|
217
|
+
const now = new Date().toISOString();
|
|
218
|
+
await db.insert(triageConfig).values({
|
|
219
|
+
id: orgId,
|
|
220
|
+
slackWorkspace: "primary",
|
|
221
|
+
slackChannelId: DEFAULT_SLACK_CHANNEL_ID,
|
|
222
|
+
slackChannelName: DEFAULT_SLACK_CHANNEL_NAME,
|
|
223
|
+
pollingEnabled: 1,
|
|
224
|
+
githubPollingEnabled: 0,
|
|
225
|
+
sentryPollingEnabled: 0,
|
|
226
|
+
lastSlackTs: null,
|
|
227
|
+
slackHistoryCursor: null,
|
|
228
|
+
repository: null,
|
|
229
|
+
sentryOrgSlug: null,
|
|
230
|
+
sentryProjectSlug: null,
|
|
231
|
+
sentryEnvironment: null,
|
|
232
|
+
lastSentrySeenAt: null,
|
|
233
|
+
createdAt: now,
|
|
234
|
+
updatedAt: now,
|
|
235
|
+
ownerEmail,
|
|
236
|
+
orgId,
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
async function ensureSchedulerJobs(): Promise<void> {
|
|
241
|
+
const ownerEmail = workspaceOwnerEmail();
|
|
79
242
|
if (!ownerEmail) {
|
|
80
|
-
const runAs = readFrontmatterField(existing.content, "runAs");
|
|
81
|
-
const createdBy = readFrontmatterField(existing.content, "createdBy");
|
|
82
|
-
if (runAs === "creator" && createdBy) return;
|
|
83
243
|
throw new Error(
|
|
84
|
-
"WORKSPACE_OWNER_EMAIL is required to
|
|
244
|
+
"WORKSPACE_OWNER_EMAIL is required to seed Factory automations",
|
|
85
245
|
);
|
|
86
246
|
}
|
|
87
|
-
|
|
88
|
-
if (
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
) {
|
|
92
|
-
await resourcePut(
|
|
93
|
-
WORKSPACE_OWNER,
|
|
94
|
-
JOB_PATH,
|
|
95
|
-
jobContent(ownerEmail),
|
|
96
|
-
"text/markdown",
|
|
247
|
+
const orgId = await resolveOrgIdForEmail(ownerEmail);
|
|
248
|
+
if (!orgId) {
|
|
249
|
+
throw new Error(
|
|
250
|
+
"The Factory deployment owner must belong to an organization before automations can be seeded",
|
|
97
251
|
);
|
|
98
|
-
return;
|
|
99
252
|
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
"runAs",
|
|
104
|
-
"creator",
|
|
105
|
-
);
|
|
106
|
-
if (migrated === existing.content) return;
|
|
107
|
-
await resourcePut(WORKSPACE_OWNER, JOB_PATH, migrated, "text/markdown");
|
|
253
|
+
await ensureDefaultTriageConfig(ownerEmail, orgId);
|
|
254
|
+
await ensureOrganizationAutomations(ownerEmail, orgId);
|
|
255
|
+
await disableLegacyObserver();
|
|
108
256
|
}
|
|
109
257
|
|
|
110
258
|
export default defineNitroPlugin(async () => {
|
|
111
259
|
try {
|
|
112
|
-
await
|
|
260
|
+
await ensureSchedulerJobs();
|
|
113
261
|
} catch (error) {
|
|
114
|
-
console.error(
|
|
262
|
+
console.error(
|
|
263
|
+
"[factory-scheduler-job] failed to seed organization automations:",
|
|
264
|
+
error,
|
|
265
|
+
);
|
|
115
266
|
}
|
|
116
267
|
});
|
|
@@ -8,6 +8,7 @@ export interface BuilderExecutorInput {
|
|
|
8
8
|
repository?: string | null;
|
|
9
9
|
summary?: string | null;
|
|
10
10
|
sourceUrl?: string | null;
|
|
11
|
+
instructions?: string | null;
|
|
11
12
|
}
|
|
12
13
|
|
|
13
14
|
export interface BuilderExecutorResult {
|
|
@@ -63,12 +64,15 @@ export async function startBuilderRun(
|
|
|
63
64
|
const branchName = `factory/${input.itemId.slice(0, 12)}`;
|
|
64
65
|
const prompt = [
|
|
65
66
|
"Work on this approved Factory item.",
|
|
67
|
+
`Factory item: ${input.itemId}`,
|
|
66
68
|
input.summary
|
|
67
69
|
? `Feedback: ${input.summary}`
|
|
68
70
|
: "No feedback summary was supplied.",
|
|
69
71
|
input.sourceUrl ? `Source: ${input.sourceUrl}` : "",
|
|
70
72
|
input.repository ? `Repository: ${input.repository}` : "",
|
|
73
|
+
input.instructions ? `Triage instructions: ${input.instructions}` : "",
|
|
71
74
|
"Inspect the repository, make the smallest safe fix, run validation, and open a pull request.",
|
|
75
|
+
"Include the Factory item id and source link in the pull request description.",
|
|
72
76
|
"Do not touch protected areas: auth/session/identity, credentials/vault, migrations, payments, security, or publishable packages.",
|
|
73
77
|
]
|
|
74
78
|
.filter(Boolean)
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
|
|
3
|
-
export const triageSourceSchema = z.enum([
|
|
3
|
+
export const triageSourceSchema = z.enum([
|
|
4
|
+
"slack",
|
|
5
|
+
"github",
|
|
6
|
+
"github_issue",
|
|
7
|
+
"sentry",
|
|
8
|
+
]);
|
|
4
9
|
export type TriageSource = z.infer<typeof triageSourceSchema>;
|
|
5
10
|
|
|
6
11
|
export const triageItemStatusSchema = z.enum([
|
|
@@ -12,6 +17,10 @@ export const triageItemStatusSchema = z.enum([
|
|
|
12
17
|
"needs_manual",
|
|
13
18
|
"failed",
|
|
14
19
|
"reconciliation_required",
|
|
20
|
+
"automation_started",
|
|
21
|
+
"pr_observed",
|
|
22
|
+
"auto_approved",
|
|
23
|
+
"merged",
|
|
15
24
|
]);
|
|
16
25
|
export type TriageItemStatus = z.infer<typeof triageItemStatusSchema>;
|
|
17
26
|
|
|
@@ -37,6 +46,8 @@ export const triageDecisionOutcomeSchema = z.enum([
|
|
|
37
46
|
"needs_manual",
|
|
38
47
|
"propose_fix",
|
|
39
48
|
"propose_review",
|
|
49
|
+
"auto_approve",
|
|
50
|
+
"auto_merge",
|
|
40
51
|
]);
|
|
41
52
|
export type TriageDecisionOutcome = z.infer<typeof triageDecisionOutcomeSchema>;
|
|
42
53
|
|
|
@@ -68,6 +79,7 @@ export const triageGuardCodeSchema = z.enum([
|
|
|
68
79
|
"path_denied",
|
|
69
80
|
"diff_too_large",
|
|
70
81
|
"unknown_change",
|
|
82
|
+
"owner_owned",
|
|
71
83
|
]);
|
|
72
84
|
export type TriageGuardCode = z.infer<typeof triageGuardCodeSchema>;
|
|
73
85
|
|
|
@@ -81,6 +93,7 @@ export const hardNeverAutomateGuardCodes: TriageGuardCode[] = [
|
|
|
81
93
|
"payments",
|
|
82
94
|
"security",
|
|
83
95
|
"publishable_package",
|
|
96
|
+
"owner_owned",
|
|
84
97
|
];
|
|
85
98
|
|
|
86
99
|
export const triagePolicyGuardsSchema = z.object({
|