@agent-native/core 0.146.3 → 0.146.5
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/analytics/.agents/skills/dashboard-management/SKILL.md +13 -10
- package/corpus/templates/analytics/.agents/skills/self-modifying-code/SKILL.md +7 -3
- package/corpus/templates/analytics/.agents/skills/upgrade-agent-native/SKILL.md +5 -2
- package/corpus/templates/analytics/actions/compose-dashboard.ts +53 -6
- package/corpus/templates/analytics/actions/dashboard-mutation-api.ts +8 -2
- package/corpus/templates/analytics/actions/migrate-first-party-analytics-to-bigquery.ts +3 -1
- package/corpus/templates/analytics/actions/mutate-dashboard.ts +48 -9
- package/corpus/templates/analytics/actions/update-dashboard.ts +80 -6
- package/corpus/templates/analytics/app/components/layout/CommandPalette.tsx +1 -1
- package/corpus/templates/analytics/app/components/layout/Layout.tsx +1 -1
- package/corpus/templates/analytics/app/pages/Settings.tsx +5 -1
- package/corpus/templates/analytics/app/routes/agent.tsx +7 -5
- package/corpus/templates/analytics/changelog/2026-08-07-dashboard-creation-and-edits-now-save-faster-with-reliable-s.md +6 -0
- package/corpus/templates/analytics/seeds/dashboards/agent-native-templates-first-party.json +19 -19
- package/corpus/templates/analytics/server/jobs/analytics-bigquery-backfill.ts +21 -2
- package/corpus/templates/analytics/server/lib/bigquery.ts +59 -24
- package/corpus/templates/analytics/server/lib/canonical-first-party-dashboard-repair.ts +44 -8
- package/corpus/templates/analytics/server/lib/dashboard-catalog.ts +3 -5
- package/corpus/templates/analytics/server/lib/first-party-analytics-backend.ts +33 -69
- package/corpus/templates/analytics/server/lib/first-party-metric-catalog.ts +90 -24
- package/corpus/templates/analytics/server/lib/real-data-actions.ts +1 -1
- package/corpus/templates/analytics/server/plugins/agent-chat.ts +17 -2
- package/corpus/templates/analytics/shared/dashboard-report-timeouts.ts +2 -0
- package/corpus/templates/assets/.agents/skills/self-modifying-code/SKILL.md +7 -3
- package/corpus/templates/assets/.agents/skills/upgrade-agent-native/SKILL.md +5 -2
- package/corpus/templates/assets/app/components/layout/Layout.tsx +1 -1
- package/corpus/templates/assets/app/routes/agent.tsx +7 -5
- package/corpus/templates/assets/app/routes/settings.tsx +7 -2
- package/corpus/templates/assets/netlify.toml +1 -1
- package/corpus/templates/assets/package.json +1 -0
- package/corpus/templates/assets/scripts/migrate-production.ts +24 -0
- package/corpus/templates/assets/server/plugins/creative-context.ts +1 -1
- package/corpus/templates/assets/server/plugins/db.ts +1 -1
- package/corpus/templates/assets/tsconfig.json +1 -0
- package/corpus/templates/brain/.agents/skills/self-modifying-code/SKILL.md +7 -3
- package/corpus/templates/brain/.agents/skills/upgrade-agent-native/SKILL.md +5 -2
- package/corpus/templates/brain/app/components/layout/Layout.tsx +1 -1
- package/corpus/templates/brain/app/lib/brain.ts +4 -2
- package/corpus/templates/brain/app/root.tsx +1 -1
- package/corpus/templates/brain/app/routes/agent.tsx +10 -2
- package/corpus/templates/brain/netlify.toml +1 -1
- package/corpus/templates/brain/package.json +2 -0
- package/corpus/templates/brain/scripts/migrate-production.ts +24 -0
- package/corpus/templates/brain/server/plugins/db.ts +1 -1
- package/corpus/templates/brain/tsconfig.json +1 -0
- package/corpus/templates/calendar/.agents/skills/self-modifying-code/SKILL.md +7 -3
- package/corpus/templates/calendar/.agents/skills/upgrade-agent-native/SKILL.md +5 -2
- package/corpus/templates/calendar/app/components/layout/AppLayout.tsx +1 -1
- package/corpus/templates/calendar/app/root.tsx +1 -1
- package/corpus/templates/calendar/app/routes/_app.agent.tsx +8 -16
- package/corpus/templates/calendar/netlify.toml +1 -1
- package/corpus/templates/calendar/package.json +1 -0
- package/corpus/templates/calendar/scripts/migrate-production.ts +24 -0
- package/corpus/templates/calendar/server/plugins/db.ts +1 -1
- package/corpus/templates/calendar/tsconfig.json +1 -0
- package/corpus/templates/chat/.agents/skills/self-modifying-code/SKILL.md +7 -3
- package/corpus/templates/chat/.agents/skills/upgrade-agent-native/SKILL.md +5 -2
- package/corpus/templates/chat/app/hooks/use-navigation-state.ts +5 -2
- package/corpus/templates/chat/app/routes/agent.tsx +7 -31
- package/corpus/templates/chat/netlify.toml +1 -1
- package/corpus/templates/chat/package.json +1 -0
- package/corpus/templates/chat/scripts/migrate-production.ts +31 -0
- package/corpus/templates/chat/tsconfig.json +1 -0
- package/corpus/templates/clips/.agents/skills/self-modifying-code/SKILL.md +7 -3
- package/corpus/templates/clips/.agents/skills/upgrade-agent-native/SKILL.md +5 -2
- package/corpus/templates/clips/app/components/library/library-layout.tsx +1 -1
- package/corpus/templates/clips/app/root.tsx +1 -1
- package/corpus/templates/clips/app/routes/_app.agent.tsx +9 -7
- package/corpus/templates/clips/netlify.toml +1 -1
- package/corpus/templates/clips/package.json +1 -0
- package/corpus/templates/clips/scripts/migrate-production.ts +24 -0
- package/corpus/templates/clips/server/plugins/db.ts +1 -1
- package/corpus/templates/clips/tsconfig.json +1 -0
- package/corpus/templates/content/.agents/skills/self-modifying-code/SKILL.md +7 -3
- package/corpus/templates/content/.agents/skills/upgrade-agent-native/SKILL.md +5 -2
- package/corpus/templates/content/app/components/layout/Layout.tsx +1 -1
- package/corpus/templates/content/app/root.tsx +1 -1
- package/corpus/templates/content/app/routes/_app.agent.tsx +9 -8
- package/corpus/templates/content/app/routes/_app.settings.tsx +7 -2
- package/corpus/templates/content/netlify.toml +1 -1
- package/corpus/templates/content/package.json +2 -0
- package/corpus/templates/content/scripts/migrate-production.ts +28 -0
- package/corpus/templates/content/server/plugins/creative-context.ts +1 -1
- package/corpus/templates/content/server/plugins/db.ts +2 -2
- package/corpus/templates/crm/.agents/skills/upgrade-agent-native/SKILL.md +5 -2
- package/corpus/templates/crm/app/components/crm/RecordActions.tsx +4 -1
- package/corpus/templates/crm/app/components/layout/CrmLayout.tsx +1 -1
- package/corpus/templates/crm/app/routes/agent.tsx +10 -2
- package/corpus/templates/crm/netlify.toml +1 -1
- package/corpus/templates/crm/package.json +2 -0
- package/corpus/templates/crm/scripts/migrate-production.ts +24 -0
- package/corpus/templates/crm/server/plugins/db.ts +1 -1
- package/corpus/templates/crm/tsconfig.json +1 -0
- package/corpus/templates/design/.agents/skills/self-modifying-code/SKILL.md +7 -3
- package/corpus/templates/design/.agents/skills/upgrade-agent-native/SKILL.md +5 -2
- package/corpus/templates/design/app/components/layout/Layout.tsx +1 -1
- package/corpus/templates/design/app/root.tsx +1 -1
- package/corpus/templates/design/app/routes/agent.tsx +9 -7
- package/corpus/templates/design/app/routes/settings.tsx +7 -2
- package/corpus/templates/design/netlify.toml +1 -1
- package/corpus/templates/design/package.json +1 -0
- package/corpus/templates/design/scripts/migrate-production.ts +24 -0
- package/corpus/templates/design/server/plugins/creative-context.ts +1 -1
- package/corpus/templates/design/server/plugins/db.ts +1 -1
- package/corpus/templates/design/tsconfig.json +1 -0
- package/corpus/templates/dispatch/.agents/skills/self-modifying-code/SKILL.md +7 -3
- package/corpus/templates/dispatch/.agents/skills/upgrade-agent-native/SKILL.md +5 -2
- package/corpus/templates/dispatch/app/root.tsx +5 -2
- package/corpus/templates/dispatch/app/routes/agent.tsx +7 -7
- package/corpus/templates/dispatch/netlify.toml +1 -1
- package/corpus/templates/dispatch/package.json +1 -0
- package/corpus/templates/dispatch/scripts/migrate-production.ts +23 -0
- package/corpus/templates/dispatch/tsconfig.json +1 -0
- package/corpus/templates/factory/.agents/skills/self-modifying-code/SKILL.md +7 -3
- package/corpus/templates/factory/.agents/skills/upgrade-agent-native/SKILL.md +5 -2
- package/corpus/templates/factory/app/components/layout/Layout.tsx +1 -1
- package/corpus/templates/factory/app/hooks/use-navigation-state.ts +5 -2
- package/corpus/templates/factory/app/root.tsx +1 -1
- package/corpus/templates/factory/app/routes/agent.tsx +9 -14
- package/corpus/templates/factory/netlify.toml +1 -1
- package/corpus/templates/factory/package.json +1 -0
- package/corpus/templates/factory/scripts/migrate-production.ts +31 -0
- package/corpus/templates/factory/server/plugins/factory-scheduler-job.ts +2 -0
- package/corpus/templates/factory/tsconfig.json +1 -0
- package/corpus/templates/forms/.agents/skills/self-modifying-code/SKILL.md +7 -3
- package/corpus/templates/forms/.agents/skills/upgrade-agent-native/SKILL.md +5 -2
- package/corpus/templates/forms/app/components/layout/Layout.tsx +1 -1
- package/corpus/templates/forms/app/root.tsx +1 -1
- package/corpus/templates/forms/app/routes/_app.agent.tsx +9 -7
- package/corpus/templates/forms/netlify.toml +1 -1
- package/corpus/templates/forms/package.json +2 -0
- package/corpus/templates/forms/scripts/migrate-production.ts +24 -0
- package/corpus/templates/forms/server/plugins/db.ts +1 -1
- package/corpus/templates/forms/tsconfig.json +1 -0
- package/corpus/templates/macros/.agents/skills/upgrade-agent-native/SKILL.md +5 -2
- package/corpus/templates/macros/app/components/layout/AppLayout.tsx +5 -3
- package/corpus/templates/macros/app/root.tsx +1 -1
- package/corpus/templates/macros/app/routes/agent.tsx +9 -6
- package/corpus/templates/macros/netlify.toml +1 -1
- package/corpus/templates/macros/package.json +1 -0
- package/corpus/templates/macros/scripts/migrate-production.ts +24 -0
- package/corpus/templates/macros/server/plugins/db.ts +1 -1
- package/corpus/templates/macros/tsconfig.json +1 -0
- package/corpus/templates/mail/.agents/skills/self-modifying-code/SKILL.md +7 -3
- package/corpus/templates/mail/.agents/skills/upgrade-agent-native/SKILL.md +5 -2
- package/corpus/templates/mail/app/components/layout/AppLayout.tsx +8 -2
- package/corpus/templates/mail/app/components/layout/CommandPalette.tsx +1 -1
- package/corpus/templates/mail/app/routes/agent.tsx +9 -6
- package/corpus/templates/mail/netlify.toml +1 -1
- package/corpus/templates/mail/package.json +1 -0
- package/corpus/templates/mail/scripts/migrate-production.ts +24 -0
- package/corpus/templates/mail/server/plugins/db.ts +1 -1
- package/corpus/templates/mail/tsconfig.json +1 -0
- package/corpus/templates/plan/.agents/skills/self-modifying-code/SKILL.md +7 -3
- package/corpus/templates/plan/.agents/skills/upgrade-agent-native/SKILL.md +5 -2
- package/corpus/templates/plan/app/components/layout/Layout.tsx +1 -1
- package/corpus/templates/plan/app/root.tsx +1 -1
- package/corpus/templates/plan/app/routes/agent.tsx +9 -6
- package/corpus/templates/plan/netlify.toml +1 -1
- package/corpus/templates/plan/package.json +1 -0
- package/corpus/templates/plan/scripts/migrate-production.ts +24 -0
- package/corpus/templates/plan/server/plugins/00-mcp.ts +3 -2
- package/corpus/templates/plan/server/plugins/db.ts +1 -1
- package/corpus/templates/plan/tsconfig.json +1 -0
- package/corpus/templates/slides/.agents/skills/self-modifying-code/SKILL.md +7 -3
- package/corpus/templates/slides/.agents/skills/upgrade-agent-native/SKILL.md +5 -2
- package/corpus/templates/slides/app/components/editor/ImageGenPanel.tsx +8 -12
- package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +39 -2
- package/corpus/templates/slides/app/components/layout/Layout.tsx +1 -1
- package/corpus/templates/slides/app/i18n/en-US.ts +1 -0
- package/corpus/templates/slides/app/lib/create-deck-generation.ts +22 -5
- package/corpus/templates/slides/app/pages/Index.tsx +20 -5
- package/corpus/templates/slides/app/root.tsx +1 -1
- package/corpus/templates/slides/app/routes/agent.tsx +6 -9
- package/corpus/templates/slides/app/routes/settings.tsx +7 -2
- package/corpus/templates/slides/netlify.toml +1 -1
- package/corpus/templates/slides/package.json +1 -0
- package/corpus/templates/slides/scripts/migrate-production.ts +24 -0
- package/corpus/templates/slides/server/plugins/creative-context.ts +1 -1
- package/corpus/templates/slides/server/plugins/db.ts +1 -1
- package/corpus/templates/slides/tsconfig.json +1 -0
- package/corpus/templates/tasks/.agents/skills/self-modifying-code/SKILL.md +7 -3
- package/corpus/templates/tasks/.agents/skills/upgrade-agent-native/SKILL.md +5 -2
- package/corpus/templates/tasks/app/components/layout/Layout.tsx +1 -1
- package/corpus/templates/tasks/app/routes/agent.tsx +10 -2
- package/corpus/templates/tasks/netlify.toml +1 -1
- package/corpus/templates/tasks/package.json +1 -0
- package/corpus/templates/tasks/scripts/migrate-production.ts +24 -0
- package/corpus/templates/tasks/server/plugins/db.ts +1 -1
- package/corpus/templates/tasks/tsconfig.json +1 -0
- package/dist/action.d.ts +2 -0
- package/dist/agent/production-agent.d.ts +1 -0
- package/dist/agent/production-agent.js +2 -0
- package/dist/agent/thread-data-builder.d.ts +4 -0
- package/dist/agent/thread-data-builder.js +44 -0
- package/dist/automations/service.d.ts +1 -0
- package/dist/automations/service.js +21 -2
- package/dist/cli/create.js +20 -2
- package/dist/client/agent-page/AgentJobsTab.js +3 -1
- package/dist/client/agent-page/AutomationDetailsDialog.js +9 -2
- package/dist/client/index.d.ts +1 -1
- package/dist/client/navigation/index.d.ts +1 -1
- package/dist/client/navigation/index.js +1 -1
- package/dist/client/org/OrgSwitcher.js +1 -1
- package/dist/client/settings/SettingsPanel.d.ts +8 -0
- package/dist/client/settings/SettingsPanel.js +16 -1
- package/dist/client/settings/index.d.ts +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/db/migrations.js +7 -13
- package/dist/file-upload/actions/upload-image.d.ts +1 -1
- package/dist/jobs/actions/list-automation-runs.d.ts +1 -0
- package/dist/jobs/actions/list-automation-runs.js +9 -2
- package/dist/jobs/actions/list-recurring-jobs.js +3 -1
- package/dist/jobs/actions/manage-recurring-job.js +1 -1
- package/dist/jobs/actions/run-automation-now.js +1 -0
- package/dist/jobs/background-automation-runner.js +2 -0
- package/dist/jobs/frontmatter.d.ts +2 -0
- package/dist/jobs/frontmatter.js +4 -0
- package/dist/jobs/run-history.d.ts +4 -0
- package/dist/jobs/run-history.js +28 -8
- package/dist/jobs/run-now.d.ts +4 -1
- package/dist/jobs/run-now.js +4 -3
- package/dist/jobs/scheduler.js +18 -0
- package/dist/jobs/tools.d.ts +3 -2
- package/dist/jobs/tools.js +26 -12
- package/dist/localization/default-messages.d.ts +1 -0
- package/dist/localization/default-messages.js +1 -0
- package/dist/navigation/index.d.ts +1 -0
- package/dist/navigation/index.js +34 -0
- package/dist/notifications/routes.d.ts +1 -1
- package/dist/observability/routes.d.ts +1 -1
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/server/action-routes.d.ts +2 -0
- package/dist/server/action-routes.js +1 -0
- package/dist/server/agent-chat-plugin.js +3 -2
- package/dist/server/builder-browser.js +24 -8
- package/dist/templates/chat/.agents/skills/self-modifying-code/SKILL.md +7 -3
- package/dist/templates/chat/.agents/skills/upgrade-agent-native/SKILL.md +5 -2
- package/dist/templates/chat/app/hooks/use-navigation-state.ts +5 -2
- package/dist/templates/chat/app/routes/agent.tsx +7 -31
- package/dist/templates/chat/netlify.toml +1 -1
- package/dist/templates/chat/package.json +1 -0
- package/dist/templates/chat/scripts/migrate-production.ts +31 -0
- package/dist/templates/chat/tsconfig.json +1 -0
- package/dist/templates/default/.agents/skills/self-modifying-code/SKILL.md +7 -3
- package/dist/templates/default/.agents/skills/upgrade-agent-native/SKILL.md +5 -2
- package/dist/templates/default/app/routes/_index.tsx +1 -1
- package/dist/templates/default/app/routes/agent.tsx +7 -25
- package/dist/templates/default/package.json +1 -0
- package/dist/templates/default/scripts/migrate-production.ts +31 -0
- package/dist/templates/default/tsconfig.json +1 -0
- package/dist/templates/headless/.agents/skills/upgrade-agent-native/SKILL.md +5 -2
- package/dist/templates/workspace-core/.agents/skills/self-modifying-code/SKILL.md +7 -3
- package/dist/templates/workspace-core/.agents/skills/upgrade-agent-native/SKILL.md +5 -2
- package/dist/templates/workspace-root/AGENTS.md +2 -1
- package/dist/triggers/actions/list-automations.js +1 -1
- package/dist/triggers/actions/manage-automation.js +5 -1
- package/dist/triggers/actions.d.ts +1 -1
- package/dist/triggers/actions.js +21 -15
- package/dist/triggers/dispatcher.js +17 -2
- package/dist/triggers/routes.d.ts +1 -0
- package/dist/triggers/routes.js +1 -0
- package/package.json +3 -3
- package/src/templates/chat/.agents/skills/self-modifying-code/SKILL.md +7 -3
- package/src/templates/chat/.agents/skills/upgrade-agent-native/SKILL.md +5 -2
- package/src/templates/chat/app/hooks/use-navigation-state.ts +5 -2
- package/src/templates/chat/app/routes/agent.tsx +7 -31
- package/src/templates/chat/netlify.toml +1 -1
- package/src/templates/chat/package.json +1 -0
- package/src/templates/chat/scripts/migrate-production.ts +31 -0
- package/src/templates/chat/tsconfig.json +1 -0
- package/src/templates/default/.agents/skills/self-modifying-code/SKILL.md +7 -3
- package/src/templates/default/.agents/skills/upgrade-agent-native/SKILL.md +5 -2
- package/src/templates/default/app/routes/_index.tsx +1 -1
- package/src/templates/default/app/routes/agent.tsx +7 -25
- package/src/templates/default/package.json +1 -0
- package/src/templates/default/scripts/migrate-production.ts +31 -0
- package/src/templates/default/tsconfig.json +1 -0
- package/src/templates/headless/.agents/skills/upgrade-agent-native/SKILL.md +5 -2
- package/src/templates/workspace-core/.agents/skills/self-modifying-code/SKILL.md +7 -3
- package/src/templates/workspace-core/.agents/skills/upgrade-agent-native/SKILL.md +5 -2
- package/src/templates/workspace-root/AGENTS.md +2 -1
|
@@ -114,6 +114,14 @@ export function buildAssistantMessage(events, runId, options = {}) {
|
|
|
114
114
|
});
|
|
115
115
|
continue;
|
|
116
116
|
}
|
|
117
|
+
if (event.type === "approval_required") {
|
|
118
|
+
const matchingIndex = findApprovalToolCallIndex(content, event.tool ?? "unknown", event.toolCallId);
|
|
119
|
+
const part = content[matchingIndex];
|
|
120
|
+
if (part?.type === "tool-call") {
|
|
121
|
+
part.approval = { approvalKey: event.approvalKey };
|
|
122
|
+
}
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
117
125
|
if (event.type === "tool_done") {
|
|
118
126
|
const eventToolCallId = event.id?.trim();
|
|
119
127
|
let matchingIndex = -1;
|
|
@@ -339,6 +347,42 @@ function normalizeAttachmentIdentity(attachments) {
|
|
|
339
347
|
contentType: att?.contentType,
|
|
340
348
|
}));
|
|
341
349
|
}
|
|
350
|
+
function findApprovalToolCallIndex(content, toolName, toolCallId) {
|
|
351
|
+
if (toolCallId) {
|
|
352
|
+
for (let i = content.length - 1; i >= 0; i--) {
|
|
353
|
+
const part = content[i];
|
|
354
|
+
if (part.type === "tool-call" &&
|
|
355
|
+
part.toolCallId === toolCallId &&
|
|
356
|
+
part.result === undefined) {
|
|
357
|
+
return i;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
// Older tool_start events without an id use one reader-local tc_N id.
|
|
361
|
+
// Only accept that fallback when it is unambiguous, so a replayed approval
|
|
362
|
+
// cannot attach its key to another same-name call.
|
|
363
|
+
const readerLocalCandidates = [];
|
|
364
|
+
for (let i = 0; i < content.length; i += 1) {
|
|
365
|
+
const part = content[i];
|
|
366
|
+
if (part.type === "tool-call" &&
|
|
367
|
+
part.toolName === toolName &&
|
|
368
|
+
part.result === undefined &&
|
|
369
|
+
typeof part.toolCallId === "string" &&
|
|
370
|
+
/^tc_\d+$/.test(part.toolCallId)) {
|
|
371
|
+
readerLocalCandidates.push(i);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
return readerLocalCandidates.length === 1 ? readerLocalCandidates[0] : -1;
|
|
375
|
+
}
|
|
376
|
+
for (let i = content.length - 1; i >= 0; i--) {
|
|
377
|
+
const part = content[i];
|
|
378
|
+
if (part.type === "tool-call" &&
|
|
379
|
+
part.toolName === toolName &&
|
|
380
|
+
part.result === undefined) {
|
|
381
|
+
return i;
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
return -1;
|
|
385
|
+
}
|
|
342
386
|
// Strip the render-only `toolCallId` before fingerprinting. The id is generated
|
|
343
387
|
// differently depending on who built the message — the server now scopes it by
|
|
344
388
|
// run (`${runId}:tc_1`) while the client's live stream uses a bare counter
|
|
@@ -11,7 +11,11 @@ function normalizeActor(actor) {
|
|
|
11
11
|
const userEmail = actor.userEmail.trim().toLowerCase();
|
|
12
12
|
if (!userEmail)
|
|
13
13
|
throw httpError("Not authenticated.", 401);
|
|
14
|
-
return {
|
|
14
|
+
return {
|
|
15
|
+
userEmail,
|
|
16
|
+
orgId: actor.orgId?.trim() || null,
|
|
17
|
+
appId: actor.appId?.trim() || null,
|
|
18
|
+
};
|
|
15
19
|
}
|
|
16
20
|
function automationName(path) {
|
|
17
21
|
return path.replace(/^jobs\//, "").replace(/\.md$/, "");
|
|
@@ -56,6 +60,12 @@ async function requireOrganizationMembership(actor) {
|
|
|
56
60
|
function isOrganizationAdmin(membership) {
|
|
57
61
|
return membership.role === "owner" || membership.role === "admin";
|
|
58
62
|
}
|
|
63
|
+
function automationBelongsToApp(meta, appId) {
|
|
64
|
+
const ownerAppId = meta.appId?.trim();
|
|
65
|
+
if (!ownerAppId || !appId?.trim())
|
|
66
|
+
return true;
|
|
67
|
+
return ownerAppId === appId.trim();
|
|
68
|
+
}
|
|
59
69
|
async function mutationAccess(actorInput, resource, meta) {
|
|
60
70
|
const actor = normalizeActor(actorInput);
|
|
61
71
|
const resourceOrgId = organizationIdFromResourceOwner(resource.owner);
|
|
@@ -83,7 +93,10 @@ async function mutationAccess(actorInput, resource, meta) {
|
|
|
83
93
|
*/
|
|
84
94
|
export async function canUpdateAutomationResource(actorInput, resource) {
|
|
85
95
|
const { meta } = parseJobResource(resource.content);
|
|
86
|
-
|
|
96
|
+
const actor = normalizeActor(actorInput);
|
|
97
|
+
if (!automationBelongsToApp(meta, actor.appId))
|
|
98
|
+
return false;
|
|
99
|
+
return (await mutationAccess(actor, resource, meta)).canUpdate;
|
|
87
100
|
}
|
|
88
101
|
function assertExplicitAutomation(resource) {
|
|
89
102
|
const parsed = parseJobResource(resource.content);
|
|
@@ -111,6 +124,9 @@ async function readDefinition(actorInput, scope, name) {
|
|
|
111
124
|
throw httpError(`Automation "${automationName(path)}" not found.`, 404);
|
|
112
125
|
}
|
|
113
126
|
const definition = assertExplicitAutomation(resource);
|
|
127
|
+
if (!automationBelongsToApp(definition.meta, actor.appId)) {
|
|
128
|
+
throw httpError(`Automation "${automationName(path)}" not found.`, 404);
|
|
129
|
+
}
|
|
114
130
|
const access = await mutationAccess(actor, resource, definition.meta);
|
|
115
131
|
return {
|
|
116
132
|
...definition,
|
|
@@ -138,6 +154,8 @@ export async function listAutomationDefinitions(actorInput, scope) {
|
|
|
138
154
|
const parsed = parseJobResource(resource.content);
|
|
139
155
|
if (parsed.classification.kind !== "automation")
|
|
140
156
|
continue;
|
|
157
|
+
if (!automationBelongsToApp(parsed.meta, actor.appId))
|
|
158
|
+
continue;
|
|
141
159
|
const isCreator = parsed.meta.createdBy?.trim().toLowerCase() === actor.userEmail;
|
|
142
160
|
automations.push({
|
|
143
161
|
resource,
|
|
@@ -197,6 +215,7 @@ export async function defineAutomation(actorInput, input) {
|
|
|
197
215
|
condition: input.condition?.trim() || undefined,
|
|
198
216
|
mode: "agentic",
|
|
199
217
|
domain: input.domain?.trim() || undefined,
|
|
218
|
+
appId: actor.appId || undefined,
|
|
200
219
|
delegatedPolicyId: input.delegatedPolicyId?.trim() || undefined,
|
|
201
220
|
createdBy: actor.userEmail,
|
|
202
221
|
orgId: input.scope === "organization" ? actor.orgId : undefined,
|
package/dist/cli/create.js
CHANGED
|
@@ -2593,7 +2593,11 @@ function rewriteNetlifyToml(appDir, appName, mode) {
|
|
|
2593
2593
|
return;
|
|
2594
2594
|
try {
|
|
2595
2595
|
let content = fs.readFileSync(netlifyPath, "utf-8");
|
|
2596
|
-
|
|
2596
|
+
// Tolerate escaped quotes inside the command. Every template's build
|
|
2597
|
+
// command now contains `\"` (the release-migration step's CONTEXT test),
|
|
2598
|
+
// and a naive [^"]* stops at the first one — which silently dropped the
|
|
2599
|
+
// NETLIFY_DATABASE_URL_UNPOOLED override for the four templates that use it.
|
|
2600
|
+
const originalCommand = content.match(/^\s*command = "((?:[^"\\]|\\.)*)"$/m)?.[1];
|
|
2597
2601
|
const usesUnpooledDatabase = originalCommand?.includes("NETLIFY_DATABASE_URL_UNPOOLED") ?? false;
|
|
2598
2602
|
const buildCommand = mode === "workspace"
|
|
2599
2603
|
? `APP_BASE_PATH=/${appName} VITE_APP_BASE_PATH=/${appName} NITRO_PRESET=netlify pnpm --filter ${appName} build`
|
|
@@ -2602,7 +2606,21 @@ function rewriteNetlifyToml(appDir, appName, mode) {
|
|
|
2602
2606
|
const buildDatabasePrefix = usesUnpooledDatabase
|
|
2603
2607
|
? 'DATABASE_URL=\\"${NETLIFY_DATABASE_URL_UNPOOLED:-$DATABASE_URL}\\" '
|
|
2604
2608
|
: "";
|
|
2605
|
-
const
|
|
2609
|
+
const releaseDatabasePrefix = usesUnpooledDatabase
|
|
2610
|
+
? 'DATABASE_URL=\\"${NETLIFY_DATABASE_URL_UNPOOLED:-$DATABASE_URL}\\" '
|
|
2611
|
+
: "";
|
|
2612
|
+
// Migrate at RELEASE, never on the request path. On serverless "migrate on
|
|
2613
|
+
// first use" means migrate on every cold start; a production incident
|
|
2614
|
+
// traced a multi-hour outage to schema introspection running concurrently
|
|
2615
|
+
// on requests. Generated for every app so a fresh `create` + Netlify
|
|
2616
|
+
// connect just works, with no flag to remember.
|
|
2617
|
+
const releaseMigrations = ' && if [ \\"${CONTEXT:-}\\" = \\"production\\" ]; then ' +
|
|
2618
|
+
releaseDatabasePrefix +
|
|
2619
|
+
(mode === "workspace"
|
|
2620
|
+
? `pnpm --filter ${appName} migrate:production`
|
|
2621
|
+
: "pnpm migrate:production") +
|
|
2622
|
+
"; fi";
|
|
2623
|
+
const command = `${databaseSetup} && ${buildDatabasePrefix}${buildCommand}${releaseMigrations}`;
|
|
2606
2624
|
const publishPath = mode === "workspace" ? `apps/${appName}/dist` : "dist";
|
|
2607
2625
|
const functionsPath = mode === "workspace"
|
|
2608
2626
|
? `apps/${appName}/.netlify/functions-internal`
|
|
@@ -213,7 +213,9 @@ export function AgentJobsTab({ canManageOrg = false, hideHeader = false, }) {
|
|
|
213
213
|
: t("jobs.paused", { defaultValue: "Paused" }) }), resource.lastStatus ? (_jsx("span", { className: "rounded-full bg-muted px-2 py-0.5 text-[10px] font-medium text-muted-foreground", children: resource.lastStatus })) : null] }), _jsx("p", { className: "mt-1 text-sm text-muted-foreground", children: triggerDescription }), _jsx("p", { className: "hidden", children: instructions }), lastRun || nextRun || lastCheck ? (_jsxs("div", { className: "hidden", children: [nextRun ? (_jsxs("span", { children: [t("jobs.nextRun", { defaultValue: "Next run" }), ":", " ", nextRun] })) : null, _jsxs("span", { children: [t("jobs.lastRun", { defaultValue: "Last run" }), ":", " ", lastRun ??
|
|
214
214
|
t("jobs.neverRan", { defaultValue: "Never" })] }), !lastRun && lastCheck ? (_jsxs("span", { children: [t("jobs.lastChecked", {
|
|
215
215
|
defaultValue: "Last checked",
|
|
216
|
-
}), ": ", lastCheck] })) : null] })) : null, resource.lastError ? (_jsxs("
|
|
216
|
+
}), ": ", lastCheck] })) : null] })) : null, resource.lastError ? (_jsxs("div", { className: "mt-2 flex items-start gap-1.5 text-[11px] text-destructive", children: [_jsx(IconAlertTriangle, { className: "mt-px size-3 shrink-0" }), _jsx("span", { className: "min-w-0 break-words", children: resource.lastError }), _jsx("button", { type: "button", className: "shrink-0 font-medium text-foreground underline-offset-4 hover:underline", onClick: () => setDetailsTarget(entry), children: t("jobs.viewDetails", {
|
|
217
|
+
defaultValue: "View details",
|
|
218
|
+
}) })] })) : null] }), _jsxs("div", { className: "flex shrink-0 items-center gap-2", children: [resource.canUpdate ? (_jsx("button", { type: "button", role: "switch", "aria-checked": resource.enabled, "aria-label": resource.enabled
|
|
217
219
|
? "Pause automation"
|
|
218
220
|
: "Resume automation", disabled: mutationPending, onClick: () => mutateEntry(entry, "update", {
|
|
219
221
|
enabled: !resource.enabled,
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
2
|
+
import { Button } from "@agent-native/toolkit/ui/button";
|
|
3
|
+
import { IconAlertTriangle, IconExternalLink, IconLoader2, } from "@tabler/icons-react";
|
|
4
|
+
import { requestAgentChatThreadOpen } from "../agent-chat.js";
|
|
3
5
|
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, } from "../components/ui/dialog.js";
|
|
4
6
|
import { useT } from "../i18n.js";
|
|
5
7
|
import { useAutomationRuns } from "./use-jobs.js";
|
|
@@ -28,5 +30,10 @@ export function AutomationDetailsDialog({ open, name, triggerSummary, fields, co
|
|
|
28
30
|
defaultValue: "Could not load run history.",
|
|
29
31
|
}) })) : runs.length === 0 ? (_jsx("p", { className: "mt-1 text-xs text-muted-foreground", children: t("jobs.noRuns", {
|
|
30
32
|
defaultValue: "This automation has not executed yet. Only real executions are recorded here.",
|
|
31
|
-
}) })) : (_jsx("ul", { className: "mt-2 divide-y divide-border/60 border-y border-border/60", children: runs.map((run) => (_jsxs("li", { className: "flex items-center gap-2 py-1.5 text-xs", children: [_jsx(RunStatusDot, { status: run.status }), _jsx("span", { className: "shrink-0 text-muted-foreground", children: formatTimestamp(run.startedAt) }), _jsx("span", { className: "shrink-0 font-medium", children: run.status }), run.error ? (_jsx("span", { className: "min-w-0 flex-1 truncate text-muted-foreground", title: run.error, children: run.error })) : (_jsx("span", { className: "min-w-0 flex-1" })), run.finishedAt ? (_jsxs("span", { className: "shrink-0 tabular-nums text-muted-foreground", children: [Math.round((run.finishedAt - run.startedAt) / 1000), "s"] })) : null
|
|
33
|
+
}) })) : (_jsx("ul", { className: "mt-2 divide-y divide-border/60 border-y border-border/60", children: runs.map((run) => (_jsxs("li", { className: "flex items-center gap-2 py-1.5 text-xs", children: [_jsx(RunStatusDot, { status: run.status }), _jsx("span", { className: "shrink-0 text-muted-foreground", children: formatTimestamp(run.startedAt) }), _jsx("span", { className: "shrink-0 font-medium", children: run.status }), run.error ? (_jsx("span", { className: "min-w-0 flex-1 truncate text-muted-foreground", title: run.error, children: run.error })) : (_jsx("span", { className: "min-w-0 flex-1" })), run.finishedAt ? (_jsxs("span", { className: "shrink-0 tabular-nums text-muted-foreground", children: [Math.round((run.finishedAt - run.startedAt) / 1000), "s"] })) : null, run.error && run.threadId ? (_jsxs(Button, { type: "button", variant: "ghost", size: "sm", className: "h-6 shrink-0 gap-1 px-1.5 text-[11px]", onClick: () => {
|
|
34
|
+
requestAgentChatThreadOpen({
|
|
35
|
+
threadId: run.threadId,
|
|
36
|
+
});
|
|
37
|
+
onClose();
|
|
38
|
+
}, children: [_jsx(IconExternalLink, { className: "size-3" }), "Open thread"] })) : null] }, run.id))) }))] })] })] }) }));
|
|
32
39
|
}
|
package/dist/client/index.d.ts
CHANGED
|
@@ -13,7 +13,7 @@ export { AgentNativeI18nProvider, LanguagePicker, getLocaleInitScript, localeDir
|
|
|
13
13
|
export { AgentNativeIcon } from "./components/icons/AgentNativeIcon.js";
|
|
14
14
|
export { FeatureFlagsEditor, evaluatedFeatureFlagValues, featureFlagValue, useFeatureFlag, useFeatureFlags, type FeatureFlagActor, type FeatureFlagMetadata, type FeatureFlagRules, type SetFeatureFlagInput, } from "./feature-flags/index.js";
|
|
15
15
|
export { withBuilderUtmTrackingParams } from "../shared/builder-link-tracking.js";
|
|
16
|
-
export { SettingsPanel, SettingsTabsPage, SecretsSection, getAgentSettingsSearchTabs, openBuilderConnectPopup, useAgentSettingsTabs, useBuilderConnectFlow, useBuilderStatus, withBuilderConnectTrackingParams, type BuilderConnectFlow, type BuilderConnectFlowOptions, type BuilderConnectStartOptions, type BuilderStatus, type AgentSettingsSearchTab, type OpenBuilderConnectPopupOptions, type SecretsSectionProps, type SettingsPanelProps, type SettingsSearchEntry, type SettingsTabItem, type SettingsTabsPageProps, } from "./settings/index.js";
|
|
16
|
+
export { SettingsPanel, SettingsTabsPage, SecretsSection, getAgentSettingsSearchTabs, openBuilderConnectPopup, useAgentSettingsTabs, type AgentSettingsTabFactory, type AgentSettingsTabFactoryContext, useBuilderConnectFlow, useBuilderStatus, withBuilderConnectTrackingParams, type BuilderConnectFlow, type BuilderConnectFlowOptions, type BuilderConnectStartOptions, type BuilderStatus, type AgentSettingsSearchTab, type OpenBuilderConnectPopupOptions, type SecretsSectionProps, type SettingsPanelProps, type SettingsSearchEntry, type SettingsTabItem, type SettingsTabsPageProps, } from "./settings/index.js";
|
|
17
17
|
export { DevDatabaseLink, type DevDatabaseLinkProps, } from "./db-admin/DevDatabaseLink.js";
|
|
18
18
|
export { DbAdminPage } from "./db-admin/DbAdminPage.js";
|
|
19
19
|
export { installRouteChunkRecovery, reloadForStaleChunk, recoverFromStaleChunkError, } from "./route-chunk-recovery.js";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { agentNativePath, appApiPath, appBasePath, appPath, } from "../api-path.js";
|
|
2
2
|
export { useAgentRouteState, useSemanticNavigationState, type AgentRouteLocation, type SemanticNavigationCommandEnvelope, type UseAgentRouteStateOptions, type UseAgentRouteStateResult, type UseSemanticNavigationStateOptions, type UseSemanticNavigationStateResult, } from "../route-state.js";
|
|
3
3
|
export { COMMAND_MENU_OPEN_EVENT, CommandMenu, openAgentSidebar, openAgentSettings, openCommandMenu, submitToAgent, useCommandMenuShortcut, type CommandMenuProps, type CommandMenuDoc, type CommandDocsGroupProps, type CommandGroupProps, type CommandItemProps, type CommandShortcutProps, } from "../CommandMenu.js";
|
|
4
|
-
export { buildOpenRouteLink, buildOpenRoutePath, buildResourceRoute, buildSettingsRoute, buildStandardAppRoute, buildTeamRoute, createStandardOpenPathResolver, STANDARD_APP_ROUTES, STANDARD_SETTINGS_TABS, type BuildResourceRouteOptions, type BuildStandardAppRouteOptions, type NavigationLink, type NavigationTarget, type StandardAppRouteId, type StandardOpenPathResolverOptions, type StandardOpenPathRoute, type StandardSettingsTabId, } from "../../navigation/index.js";
|
|
4
|
+
export { buildOpenRouteLink, buildOpenRoutePath, buildLegacyAgentSettingsRoute, buildResourceRoute, buildSettingsRoute, buildStandardAppRoute, buildTeamRoute, createStandardOpenPathResolver, STANDARD_APP_ROUTES, STANDARD_SETTINGS_TABS, type BuildResourceRouteOptions, type BuildStandardAppRouteOptions, type NavigationLink, type NavigationTarget, type StandardAppRouteId, type StandardOpenPathResolverOptions, type StandardOpenPathRoute, type StandardSettingsTabId, } from "../../navigation/index.js";
|
|
5
5
|
export { postNavigate, isInAgentEmbed, AGENT_NAVIGATE_MESSAGE_TYPE, type AgentNavigateMessage, } from "../embed.js";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { agentNativePath, appApiPath, appBasePath, appPath, } from "../api-path.js";
|
|
2
2
|
export { useAgentRouteState, useSemanticNavigationState, } from "../route-state.js";
|
|
3
3
|
export { COMMAND_MENU_OPEN_EVENT, CommandMenu, openAgentSidebar, openAgentSettings, openCommandMenu, submitToAgent, useCommandMenuShortcut, } from "../CommandMenu.js";
|
|
4
|
-
export { buildOpenRouteLink, buildOpenRoutePath, buildResourceRoute, buildSettingsRoute, buildStandardAppRoute, buildTeamRoute, createStandardOpenPathResolver, STANDARD_APP_ROUTES, STANDARD_SETTINGS_TABS, } from "../../navigation/index.js";
|
|
4
|
+
export { buildOpenRouteLink, buildOpenRoutePath, buildLegacyAgentSettingsRoute, buildResourceRoute, buildSettingsRoute, buildStandardAppRoute, buildTeamRoute, createStandardOpenPathResolver, STANDARD_APP_ROUTES, STANDARD_SETTINGS_TABS, } from "../../navigation/index.js";
|
|
5
5
|
export { postNavigate, isInAgentEmbed, AGENT_NAVIGATE_MESSAGE_TYPE, } from "../embed.js";
|
|
@@ -32,7 +32,7 @@ const SWITCHER_BUTTON_CLASS = "flex w-full items-center gap-2 rounded-md border-
|
|
|
32
32
|
const COMPACT_SWITCHER_BUTTON_CLASS = "flex items-center justify-center rounded-md border-0 bg-accent/50 p-1.5 text-muted-foreground hover:bg-accent/70 hover:text-foreground focus:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-60 cursor-pointer";
|
|
33
33
|
const DEFAULT_ORGANIZATION_SETTINGS_PATH = "/settings/organization";
|
|
34
34
|
const DEFAULT_PROFILE_PATH = "/settings/account";
|
|
35
|
-
const DEFAULT_AGENT_PATH = "/agent";
|
|
35
|
+
const DEFAULT_AGENT_PATH = "/settings/agent";
|
|
36
36
|
const APP_ICON_MAP = {
|
|
37
37
|
Mail: IconMail,
|
|
38
38
|
CalendarDays: IconCalendar,
|
|
@@ -26,7 +26,15 @@ export interface AgentSettingsTabsOptions {
|
|
|
26
26
|
extensionTools?: boolean;
|
|
27
27
|
/** Optional page-level settings to show in the Agent section. */
|
|
28
28
|
agentAdditionalContent?: React.ReactNode;
|
|
29
|
+
/** Optional app-owned tabs that share the Agent settings scope. */
|
|
30
|
+
agentAdditionalTabFactories?: AgentSettingsTabFactory[];
|
|
29
31
|
}
|
|
32
|
+
export interface AgentSettingsTabFactoryContext {
|
|
33
|
+
scope: "user";
|
|
34
|
+
canManageOrg?: boolean;
|
|
35
|
+
scopeControl: React.ReactNode;
|
|
36
|
+
}
|
|
37
|
+
export type AgentSettingsTabFactory = (context: AgentSettingsTabFactoryContext) => SettingsTabItem;
|
|
30
38
|
export declare function areExtensionSettingsEnabled(options?: AgentSettingsTabsOptions): boolean;
|
|
31
39
|
export declare function SettingsPanel(props: SettingsPanelProps): React.JSX.Element;
|
|
32
40
|
export declare function ConnectionsSettingsContent({ settingsPanelProps, }: {
|
|
@@ -13,6 +13,7 @@ import { BuilderBMark } from "../builder-mark.js";
|
|
|
13
13
|
import { Popover, PopoverContent, PopoverTrigger, } from "../components/ui/popover.js";
|
|
14
14
|
import { Tooltip, TooltipContent, TooltipTrigger, } from "../components/ui/tooltip.js";
|
|
15
15
|
import { useT } from "../i18n.js";
|
|
16
|
+
import { useOrg } from "../org/hooks.js";
|
|
16
17
|
import { TeamPage } from "../org/TeamPage.js";
|
|
17
18
|
import { BuilderConnectCard } from "../setup-connections/BuilderConnectCard.js";
|
|
18
19
|
import { callAction } from "../use-action.js";
|
|
@@ -1073,8 +1074,11 @@ export function AgentSettingsContent({ className, sections = AGENT_SETTINGS_SECT
|
|
|
1073
1074
|
}
|
|
1074
1075
|
export function useAgentSettingsTabs(options = {}) {
|
|
1075
1076
|
const { isDevMode, canToggle, setDevMode } = useDevMode();
|
|
1077
|
+
const { data: org } = useOrg();
|
|
1078
|
+
const canManageOrg = !org?.orgId || org.role === "owner" || org.role === "admin";
|
|
1076
1079
|
const extensionToolsEnabled = areExtensionSettingsEnabled(options);
|
|
1077
1080
|
const agentAdditionalContent = options.agentAdditionalContent;
|
|
1081
|
+
const agentAdditionalTabFactories = options.agentAdditionalTabFactories ?? [];
|
|
1078
1082
|
const baseProps = useMemo(() => ({
|
|
1079
1083
|
isDevMode,
|
|
1080
1084
|
onToggleDevMode: () => {
|
|
@@ -1082,6 +1086,11 @@ export function useAgentSettingsTabs(options = {}) {
|
|
|
1082
1086
|
},
|
|
1083
1087
|
showDevToggle: canToggle,
|
|
1084
1088
|
}), [canToggle, isDevMode, setDevMode]);
|
|
1089
|
+
const additionalTabs = useMemo(() => agentAdditionalTabFactories.map((factory) => factory({
|
|
1090
|
+
scope: "user",
|
|
1091
|
+
canManageOrg,
|
|
1092
|
+
scopeControl: null,
|
|
1093
|
+
})), [agentAdditionalTabFactories, canManageOrg]);
|
|
1085
1094
|
return useMemo(() => {
|
|
1086
1095
|
const searchTabs = getAgentSettingsSearchTabs();
|
|
1087
1096
|
const searchTab = (id) => {
|
|
@@ -1247,6 +1256,12 @@ export function useAgentSettingsTabs(options = {}) {
|
|
|
1247
1256
|
],
|
|
1248
1257
|
content: _jsx(AgentWorkspaceContent, { activeTab: "agents", overview: null }),
|
|
1249
1258
|
},
|
|
1259
|
+
...additionalTabs,
|
|
1250
1260
|
];
|
|
1251
|
-
}, [
|
|
1261
|
+
}, [
|
|
1262
|
+
agentAdditionalContent,
|
|
1263
|
+
additionalTabs,
|
|
1264
|
+
baseProps,
|
|
1265
|
+
extensionToolsEnabled,
|
|
1266
|
+
]);
|
|
1252
1267
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { AgentSettingsContent, areExtensionSettingsEnabled, SettingsPanel, useAgentSettingsTabs, type AgentSettingsTabsOptions, type SettingsPanelProps, } from "./SettingsPanel.js";
|
|
1
|
+
export { AgentSettingsContent, areExtensionSettingsEnabled, SettingsPanel, useAgentSettingsTabs, type AgentSettingsTabFactory, type AgentSettingsTabFactoryContext, type AgentSettingsTabsOptions, type SettingsPanelProps, } from "./SettingsPanel.js";
|
|
2
2
|
export { getAgentSettingsSearchTabs, type AgentSettingsSearchTab, } from "./agent-settings-search.js";
|
|
3
3
|
export { SettingsTabsPage, type SettingsSearchEntry, type SettingsTabItem, type SettingsTabsPageProps, } from "./SettingsTabsPage.js";
|
|
4
4
|
export { AccountSettingsCard, AccountSettingsForm, type AccountSettingsCardProps, type AccountSettingsFormProps, } from "./AccountSettingsCard.js";
|
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
* Body: { json: any, fieldName?: string, type?: "map"|"array", requestSource?: string }
|
|
14
14
|
*/
|
|
15
15
|
export declare const postCollabJson: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
|
|
16
|
-
ok?: undefined;
|
|
17
16
|
error: string;
|
|
17
|
+
ok?: undefined;
|
|
18
18
|
} | {
|
|
19
19
|
error?: undefined;
|
|
20
20
|
ok: boolean;
|
package/dist/db/migrations.js
CHANGED
|
@@ -245,19 +245,8 @@ function isServerlessRequestRuntime() {
|
|
|
245
245
|
process.env.VERCEL === "1");
|
|
246
246
|
}
|
|
247
247
|
/**
|
|
248
|
-
* Whether this
|
|
249
|
-
* is safe.
|
|
250
|
-
*
|
|
251
|
-
* Without this, "skip in serverless" silently means "never migrate" for any app
|
|
252
|
-
* that has no release entrypoint — and at the time this was written exactly one
|
|
253
|
-
* of seventeen templates had one. Existing tables keep working, so nothing
|
|
254
|
-
* fails; a newly added migration just never applies, and a fresh deploy comes
|
|
255
|
-
* up with missing tables. That is a skip indistinguishable from success, which
|
|
256
|
-
* is the failure mode this repo bans.
|
|
257
|
-
*
|
|
258
|
-
* So the request-path skip is opt-in per app. An app sets this once it owns a
|
|
259
|
-
* release migration step (see templates/analytics/scripts/migrate-production.ts
|
|
260
|
-
* and the `migrate:production` build step in its netlify.toml).
|
|
248
|
+
* Whether this deployment has a release-time migration runner. Request-path
|
|
249
|
+
* migration skipping is safe only when that runner owns schema setup.
|
|
261
250
|
*/
|
|
262
251
|
function appMigratesAtRelease() {
|
|
263
252
|
const raw = process.env.AGENT_NATIVE_RELEASE_MIGRATIONS?.trim();
|
|
@@ -675,6 +664,11 @@ export function runMigrations(migrations, options) {
|
|
|
675
664
|
!!globalThis.process?.env?.VERCEL ||
|
|
676
665
|
"__cf_env" in globalThis ||
|
|
677
666
|
"__env__" in globalThis;
|
|
667
|
+
// A release migration runs in the same Netlify environment as a request,
|
|
668
|
+
// but it must fail the deploy when DDL fails instead of publishing an
|
|
669
|
+
// app against an incomplete schema.
|
|
670
|
+
if (isMigrationAuthorizedRuntime())
|
|
671
|
+
throw err;
|
|
678
672
|
if (typeof globalThis.process?.exit === "function" && !isServerless) {
|
|
679
673
|
process.exit(1);
|
|
680
674
|
}
|
|
@@ -17,11 +17,11 @@ declare const _default: import("../../action.js").ActionDefinition<{
|
|
|
17
17
|
id?: undefined;
|
|
18
18
|
provider?: undefined;
|
|
19
19
|
} | {
|
|
20
|
+
error?: undefined;
|
|
20
21
|
configured?: undefined;
|
|
21
22
|
connectPath?: undefined;
|
|
22
23
|
url: string;
|
|
23
24
|
id: string;
|
|
24
25
|
provider: string;
|
|
25
|
-
error?: undefined;
|
|
26
26
|
}>;
|
|
27
27
|
export default _default;
|
|
@@ -9,12 +9,13 @@ export default defineAction({
|
|
|
9
9
|
schema: z.object({
|
|
10
10
|
name: z.string().min(1),
|
|
11
11
|
scope: scopeSchema.default("personal"),
|
|
12
|
+
appId: z.string().trim().min(1).optional(),
|
|
12
13
|
limit: z.number().int().min(1).max(100).optional(),
|
|
13
14
|
}),
|
|
14
15
|
http: { method: "GET" },
|
|
15
16
|
readOnly: true,
|
|
16
17
|
parallelSafe: true,
|
|
17
|
-
run: async ({ name, scope, limit }, ctx) => {
|
|
18
|
+
run: async ({ name, scope, appId: requestedAppId, limit }, ctx) => {
|
|
18
19
|
const userEmail = ctx?.userEmail;
|
|
19
20
|
if (!userEmail)
|
|
20
21
|
throw new Error("Not authenticated.");
|
|
@@ -23,6 +24,12 @@ export default defineAction({
|
|
|
23
24
|
const owner = scope === "organization"
|
|
24
25
|
? organizationResourceOwner(ctx.orgId)
|
|
25
26
|
: userEmail;
|
|
26
|
-
|
|
27
|
+
const appId = ctx?.appId === "dispatch" ? requestedAppId : ctx?.appId;
|
|
28
|
+
return listAutomationRuns({
|
|
29
|
+
owners: [owner],
|
|
30
|
+
automation: name,
|
|
31
|
+
appId,
|
|
32
|
+
limit,
|
|
33
|
+
});
|
|
27
34
|
},
|
|
28
35
|
});
|
|
@@ -4,7 +4,7 @@ import { organizationResourceOwner, resourceGetByPath, resourceList, } from "../
|
|
|
4
4
|
import { describeCron, effectiveTimezone, isValidCron, nextOccurrence, } from "../cron.js";
|
|
5
5
|
import { classifyJobResource } from "../frontmatter.js";
|
|
6
6
|
import { parseJobFrontmatter } from "../scheduler.js";
|
|
7
|
-
import { authorizeJobMutation } from "../tools.js";
|
|
7
|
+
import { authorizeJobMutation, jobBelongsToApp } from "../tools.js";
|
|
8
8
|
const scopeSchema = z.enum(["personal", "organization"]);
|
|
9
9
|
function jobName(path) {
|
|
10
10
|
return path.replace(/^jobs\//, "").replace(/\.md$/, "");
|
|
@@ -57,6 +57,8 @@ export default defineAction({
|
|
|
57
57
|
continue;
|
|
58
58
|
}
|
|
59
59
|
const { meta, body } = parseJobFrontmatter(full.content);
|
|
60
|
+
if (!jobBelongsToApp(meta, ctx?.appId))
|
|
61
|
+
continue;
|
|
60
62
|
const canUpdate = scope === "personal" || !(await authorizeJobMutation(owner, meta));
|
|
61
63
|
jobs.push({
|
|
62
64
|
id: full.id,
|
|
@@ -41,7 +41,7 @@ export default defineAction({
|
|
|
41
41
|
statusCode: 400,
|
|
42
42
|
});
|
|
43
43
|
}
|
|
44
|
-
const denied = await authorizeJobMutation(resource.owner, meta);
|
|
44
|
+
const denied = await authorizeJobMutation(resource.owner, meta, ctx.appId);
|
|
45
45
|
if (denied)
|
|
46
46
|
throw Object.assign(new Error(denied), { statusCode: 403 });
|
|
47
47
|
if (operation === "delete") {
|
|
@@ -168,6 +168,7 @@ export async function runBackgroundAutomation(options, deps) {
|
|
|
168
168
|
path: automation.resource.path,
|
|
169
169
|
scope: options.orgId ? "organization" : "personal",
|
|
170
170
|
orgId: options.orgId ?? null,
|
|
171
|
+
appId: deps.appId,
|
|
171
172
|
});
|
|
172
173
|
}
|
|
173
174
|
catch (err) {
|
|
@@ -307,6 +308,7 @@ async function executeBackgroundAutomation(options, deps, historyId) {
|
|
|
307
308
|
threadId: thread.id,
|
|
308
309
|
ownerEmail,
|
|
309
310
|
orgId,
|
|
311
|
+
appId: deps.appId,
|
|
310
312
|
actionCaller: options.actionCaller,
|
|
311
313
|
automation: options.actionAutomation,
|
|
312
314
|
runId,
|
|
@@ -46,6 +46,8 @@ export interface JobFrontmatter {
|
|
|
46
46
|
mode?: JobExecutionMode;
|
|
47
47
|
/** Domain tag for filtering in per-template UIs. */
|
|
48
48
|
domain?: string;
|
|
49
|
+
/** Explicit application owner used by the recurring-job scheduler. */
|
|
50
|
+
appId?: string;
|
|
49
51
|
/**
|
|
50
52
|
* Optional application-owned policy id carried into actions by the trusted
|
|
51
53
|
* trigger dispatcher. It is not model-supplied action input.
|
package/dist/jobs/frontmatter.js
CHANGED
|
@@ -130,6 +130,9 @@ function parseKnownField(meta, key, rawValue) {
|
|
|
130
130
|
case "domain":
|
|
131
131
|
meta.domain = value;
|
|
132
132
|
break;
|
|
133
|
+
case "appId":
|
|
134
|
+
meta.appId = value || undefined;
|
|
135
|
+
break;
|
|
133
136
|
case "delegatedPolicyId":
|
|
134
137
|
meta.delegatedPolicyId = value || undefined;
|
|
135
138
|
break;
|
|
@@ -194,6 +197,7 @@ export function buildJobResourceContent(meta, body) {
|
|
|
194
197
|
if (meta.mode)
|
|
195
198
|
lines.push(`mode: ${meta.mode}`);
|
|
196
199
|
pushString(lines, "domain", meta.domain);
|
|
200
|
+
pushString(lines, "appId", meta.appId);
|
|
197
201
|
pushString(lines, "delegatedPolicyId", meta.delegatedPolicyId);
|
|
198
202
|
// Keep the long-standing human-readable owner shape used by existing
|
|
199
203
|
// resources and diagnostics; values that can contain free-form text use
|
|
@@ -13,6 +13,7 @@ export interface AutomationRun {
|
|
|
13
13
|
path: string;
|
|
14
14
|
scope: string | null;
|
|
15
15
|
orgId: string | null;
|
|
16
|
+
appId: string | null;
|
|
16
17
|
runId: string | null;
|
|
17
18
|
threadId: string | null;
|
|
18
19
|
status: AutomationRunStatus;
|
|
@@ -26,6 +27,7 @@ export interface StartAutomationRunInput {
|
|
|
26
27
|
path: string;
|
|
27
28
|
scope?: string | null;
|
|
28
29
|
orgId?: string | null;
|
|
30
|
+
appId?: string | null;
|
|
29
31
|
runId?: string | null;
|
|
30
32
|
threadId?: string | null;
|
|
31
33
|
/** A pre-created row still waiting for its background worker handoff. */
|
|
@@ -49,6 +51,7 @@ export declare function claimAutomationRun(id: string): Promise<boolean>;
|
|
|
49
51
|
* redeliver it because claimAutomationRun is an atomic CAS.
|
|
50
52
|
*/
|
|
51
53
|
export declare function listUnclaimedAutomationRuns(options?: {
|
|
54
|
+
appId?: string | null;
|
|
52
55
|
olderThanMs?: number;
|
|
53
56
|
limit?: number;
|
|
54
57
|
}): Promise<AutomationRun[]>;
|
|
@@ -69,5 +72,6 @@ export declare function deleteAutomationRuns(owner: string, automation: string):
|
|
|
69
72
|
export declare function listAutomationRuns(options: {
|
|
70
73
|
owners: string[];
|
|
71
74
|
automation: string;
|
|
75
|
+
appId?: string | null;
|
|
72
76
|
limit?: number;
|
|
73
77
|
}): Promise<AutomationRun[]>;
|
package/dist/jobs/run-history.js
CHANGED
|
@@ -46,6 +46,7 @@ export const AUTOMATION_RUN_MIGRATIONS = [
|
|
|
46
46
|
path TEXT NOT NULL,
|
|
47
47
|
scope TEXT,
|
|
48
48
|
org_id TEXT,
|
|
49
|
+
app_id TEXT,
|
|
49
50
|
run_id TEXT,
|
|
50
51
|
thread_id TEXT,
|
|
51
52
|
status TEXT NOT NULL DEFAULT 'running',
|
|
@@ -70,6 +71,11 @@ export const AUTOMATION_RUN_MIGRATIONS = [
|
|
|
70
71
|
sql: `ALTER TABLE ${TABLE}
|
|
71
72
|
ADD COLUMN IF NOT EXISTS dispatch_pending INTEGER NOT NULL DEFAULT 0`,
|
|
72
73
|
},
|
|
74
|
+
{
|
|
75
|
+
version: 4,
|
|
76
|
+
name: "automation-runs-app-id",
|
|
77
|
+
sql: `ALTER TABLE ${TABLE} ADD COLUMN IF NOT EXISTS app_id TEXT`,
|
|
78
|
+
},
|
|
73
79
|
];
|
|
74
80
|
export async function runAutomationRunMigrations(nitroApp) {
|
|
75
81
|
await runMigrations(AUTOMATION_RUN_MIGRATIONS, {
|
|
@@ -86,10 +92,11 @@ async function ensureTable() {
|
|
|
86
92
|
id TEXT PRIMARY KEY,
|
|
87
93
|
owner TEXT NOT NULL,
|
|
88
94
|
automation TEXT NOT NULL,
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
95
|
+
path TEXT NOT NULL,
|
|
96
|
+
scope TEXT,
|
|
97
|
+
org_id TEXT,
|
|
98
|
+
app_id TEXT,
|
|
99
|
+
run_id TEXT,
|
|
93
100
|
thread_id TEXT,
|
|
94
101
|
status TEXT NOT NULL DEFAULT 'running',
|
|
95
102
|
started_at ${intType()} NOT NULL,
|
|
@@ -113,6 +120,7 @@ async function ensureTable() {
|
|
|
113
120
|
for (const [name, definition] of [
|
|
114
121
|
["claimed_at", `${intType()}`],
|
|
115
122
|
["dispatch_pending", `${intType()} NOT NULL DEFAULT 0`],
|
|
123
|
+
["app_id", "TEXT"],
|
|
116
124
|
]) {
|
|
117
125
|
if (columns.has(name))
|
|
118
126
|
continue;
|
|
@@ -148,6 +156,7 @@ function toRun(row, now) {
|
|
|
148
156
|
path: String(row.path),
|
|
149
157
|
scope: row.scope == null ? null : String(row.scope),
|
|
150
158
|
orgId: row.org_id == null ? null : String(row.org_id),
|
|
159
|
+
appId: row.app_id == null ? null : String(row.app_id),
|
|
151
160
|
runId: row.run_id == null ? null : String(row.run_id),
|
|
152
161
|
threadId: row.thread_id == null ? null : String(row.thread_id),
|
|
153
162
|
status,
|
|
@@ -169,8 +178,8 @@ export async function startAutomationRun(input) {
|
|
|
169
178
|
await ensureTable();
|
|
170
179
|
const id = randomUUID();
|
|
171
180
|
await getDbExec().execute({
|
|
172
|
-
sql: `INSERT INTO ${TABLE} (id, owner, automation, path, scope, org_id, run_id, thread_id, status, started_at, dispatch_pending)
|
|
173
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, 'running', ?, ?)`,
|
|
181
|
+
sql: `INSERT INTO ${TABLE} (id, owner, automation, path, scope, org_id, app_id, run_id, thread_id, status, started_at, dispatch_pending)
|
|
182
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, 'running', ?, ?)`,
|
|
174
183
|
args: [
|
|
175
184
|
id,
|
|
176
185
|
input.owner,
|
|
@@ -178,6 +187,7 @@ export async function startAutomationRun(input) {
|
|
|
178
187
|
input.path,
|
|
179
188
|
input.scope ?? null,
|
|
180
189
|
input.orgId ?? null,
|
|
190
|
+
input.appId ?? null,
|
|
181
191
|
input.runId ?? null,
|
|
182
192
|
input.threadId ?? null,
|
|
183
193
|
Date.now(),
|
|
@@ -213,14 +223,21 @@ export async function claimAutomationRun(id) {
|
|
|
213
223
|
*/
|
|
214
224
|
export async function listUnclaimedAutomationRuns(options) {
|
|
215
225
|
await ensureTable();
|
|
226
|
+
const appId = options?.appId?.trim() || null;
|
|
216
227
|
const olderThanMs = Math.max(options?.olderThanMs ?? 10_000, 0);
|
|
217
228
|
const limit = Math.min(Math.max(options?.limit ?? 50, 1), 100);
|
|
229
|
+
const appFilter = appId ? " AND (app_id = ? OR app_id IS NULL)" : "";
|
|
218
230
|
const result = await getDbExec().execute({
|
|
219
231
|
sql: `SELECT * FROM ${TABLE}
|
|
220
232
|
WHERE dispatch_pending = 1 AND (claimed_at IS NULL OR claimed_at <= ?) AND status = 'running'
|
|
233
|
+
${appFilter}
|
|
221
234
|
AND started_at <= ?
|
|
222
235
|
ORDER BY started_at ASC LIMIT ${limit}`,
|
|
223
|
-
args: [
|
|
236
|
+
args: [
|
|
237
|
+
Date.now() - CLAIM_LEASE_MS,
|
|
238
|
+
...(appId ? [appId] : []),
|
|
239
|
+
Date.now() - olderThanMs,
|
|
240
|
+
],
|
|
224
241
|
});
|
|
225
242
|
const now = Date.now();
|
|
226
243
|
return (result.rows ?? []).map((row) => toRun(row, now));
|
|
@@ -314,11 +331,14 @@ export async function listAutomationRuns(options) {
|
|
|
314
331
|
if (!owners.length)
|
|
315
332
|
return [];
|
|
316
333
|
const limit = Math.min(Math.max(options.limit ?? 20, 1), 100);
|
|
334
|
+
const appId = options.appId?.trim() || null;
|
|
317
335
|
const placeholders = owners.map(() => "?").join(", ");
|
|
336
|
+
const appFilter = appId ? " AND (app_id = ? OR app_id IS NULL)" : "";
|
|
318
337
|
const result = await getDbExec().execute({
|
|
319
338
|
sql: `SELECT * FROM ${TABLE} WHERE owner IN (${placeholders}) AND automation = ?
|
|
339
|
+
${appFilter}
|
|
320
340
|
ORDER BY started_at DESC LIMIT ${limit}`,
|
|
321
|
-
args: [...owners, options.automation],
|
|
341
|
+
args: [...owners, options.automation, ...(appId ? [appId] : [])],
|
|
322
342
|
});
|
|
323
343
|
const now = Date.now();
|
|
324
344
|
return (result.rows ?? []).map((row) => toRun(row, now));
|