@agent-native/core 0.168.6 → 0.168.9
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/actions/mutate-dashboard.ts +8 -1
- package/corpus/templates/calendar/actions/delete-event.ts +34 -18
- package/corpus/templates/calendar/actions/delete-events.ts +13 -1
- package/corpus/templates/calendar/app/components/calendar/EventDetailPanel.tsx +22 -3
- package/corpus/templates/calendar/app/lib/calendar-timezone.ts +19 -0
- package/corpus/templates/calendar/server/lib/google-api.ts +18 -1
- package/corpus/templates/clips/actions/finalize-meeting.ts +16 -0
- package/corpus/templates/clips/actions/list-meetings.ts +1 -0
- package/corpus/templates/clips/actions/list-recordings.ts +14 -0
- package/corpus/templates/clips/actions/sync-calendars.ts +10 -29
- package/corpus/templates/clips/app/components/library/recording-card.tsx +2 -2
- package/corpus/templates/clips/app/components/player/delete-recording-menu.tsx +20 -3
- package/corpus/templates/clips/app/hooks/use-library.ts +1 -0
- package/corpus/templates/clips/app/routes/r.$recordingId.tsx +12 -5
- package/corpus/templates/clips/desktop/src/hooks/useMeetingTranscription.ts +28 -12
- package/corpus/templates/clips/desktop/src/lib/meeting-stop.ts +16 -0
- package/corpus/templates/clips/server/lib/calendar-event-meetings.ts +19 -9
- package/corpus/templates/factory/.agents/skills/factory-graphs/SKILL.md +5 -0
- package/corpus/templates/factory/AGENTS.md +12 -22
- package/corpus/templates/factory/README.md +11 -8
- package/corpus/templates/factory/actions/approve-factory-item.ts +35 -8
- package/corpus/templates/factory/actions/babysit-agent-native-pull-request.ts +24 -9
- package/corpus/templates/factory/actions/create-factory.ts +211 -0
- package/corpus/templates/factory/actions/evaluate-triage-item.ts +29 -5
- package/corpus/templates/factory/actions/get-factory-graph.ts +1 -1
- package/corpus/templates/factory/actions/get-slack-feedback-context.ts +20 -11
- package/corpus/templates/factory/actions/get-triage-config.ts +13 -12
- package/corpus/templates/factory/actions/get-triage-item.ts +28 -6
- package/corpus/templates/factory/actions/govern-agent-native-pull-request.ts +33 -17
- package/corpus/templates/factory/actions/ingest-github-observation.ts +10 -4
- package/corpus/templates/factory/actions/list-factory-audit.ts +11 -4
- package/corpus/templates/factory/actions/list-factory-automations.ts +34 -12
- package/corpus/templates/factory/actions/list-triage-items.ts +11 -3
- package/corpus/templates/factory/actions/list-triage-rules.ts +11 -4
- package/corpus/templates/factory/actions/poll-github-sources.ts +24 -10
- package/corpus/templates/factory/actions/poll-sentry-errors.ts +26 -11
- package/corpus/templates/factory/actions/poll-slack-channel.ts +31 -13
- package/corpus/templates/factory/actions/reconcile-triage-run.ts +59 -9
- package/corpus/templates/factory/actions/record-triage-feedback.ts +14 -3
- package/corpus/templates/factory/actions/run-factory-automation.ts +12 -2
- package/corpus/templates/factory/actions/save-factory-automation.ts +82 -21
- package/corpus/templates/factory/actions/save-factory-graph.ts +10 -1
- package/corpus/templates/factory/actions/save-triage-config.ts +90 -36
- package/corpus/templates/factory/actions/save-triage-rule.ts +16 -3
- package/corpus/templates/factory/actions/start-builder-for-item.ts +28 -20
- package/corpus/templates/factory/actions/suggest-factory-rules.ts +11 -4
- package/corpus/templates/factory/actions/view-screen.ts +22 -30
- package/corpus/templates/factory/app/components/factory/FactorySettingsView.tsx +7 -2
- package/corpus/templates/factory/app/components/factory/FactoryWorkspaceActions.tsx +7 -22
- package/corpus/templates/factory/app/components/factory/NewFactoryForm.tsx +260 -0
- package/corpus/templates/factory/app/components/layout/Layout.tsx +1 -1
- package/corpus/templates/factory/app/components/layout/Sidebar.tsx +2 -1
- package/corpus/templates/factory/app/hooks/use-navigation-state.ts +3 -3
- package/corpus/templates/factory/app/i18n/en-US.ts +18 -1
- package/corpus/templates/factory/app/routes/factory.tsx +78 -62
- package/corpus/templates/factory/app/routes/{factory-settings.tsx → new-factory.tsx} +12 -9
- package/corpus/templates/factory/server/db/schema.ts +18 -3
- package/corpus/templates/factory/server/factory-graph/contracts.ts +24 -0
- package/corpus/templates/factory/server/factory-graph/store.ts +16 -9
- package/corpus/templates/factory/server/lib/factory-automation-plan.ts +136 -0
- package/corpus/templates/factory/server/lib/factory-automation-repair.ts +31 -0
- package/corpus/templates/factory/server/lib/factory-scope.ts +416 -0
- package/corpus/templates/factory/server/lib/require-factory-automation.ts +11 -0
- package/corpus/templates/factory/server/plugins/agent-chat.ts +4 -2
- package/corpus/templates/factory/server/plugins/factory-migrations.ts +80 -0
- package/corpus/templates/factory/server/plugins/factory-scheduler-job.ts +142 -43
- package/corpus/templates/factory/server/triage/audit.ts +4 -0
- package/corpus/templates/factory/server/triage/ids.ts +4 -0
- package/dist/cli/native-dependencies.js +4 -1
- package/dist/client/AgentPanel.d.ts +5 -1
- package/dist/client/AgentPanel.js +9 -4
- package/dist/client/agent-chat/index.d.ts +1 -1
- package/dist/client/agent-chat/index.js +1 -1
- package/dist/client/chat-first/apps-rail.js +6 -6
- package/dist/client/chat-first/primary-nav.js +14 -6
- package/dist/client/integrations/IntegrationsPanel.d.ts +15 -0
- package/dist/client/integrations/IntegrationsPanel.js +29 -21
- package/dist/client/integrations/index.d.ts +1 -1
- package/dist/client/integrations/index.js +1 -1
- package/dist/client/resources/McpIntegrationDialog.js +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/notifications/routes.d.ts +1 -1
- package/dist/progress/routes.d.ts +1 -1
- package/dist/resources/handlers.d.ts +3 -3
- package/dist/server/ssr-handler.js +19 -1
- package/package.json +1 -1
|
@@ -11,6 +11,12 @@ import {
|
|
|
11
11
|
triageItems,
|
|
12
12
|
triageRules,
|
|
13
13
|
} from "../server/db/schema.js";
|
|
14
|
+
import { DEFAULT_FACTORY_ID } from "../server/factory-graph/store.js";
|
|
15
|
+
import {
|
|
16
|
+
factoryIdSchema,
|
|
17
|
+
orgFactoryItemFilter,
|
|
18
|
+
orgFactoryRuleFilter,
|
|
19
|
+
} from "../server/lib/factory-scope.js";
|
|
14
20
|
import {
|
|
15
21
|
requireWorkspaceMember,
|
|
16
22
|
workspaceMemberIdentityFromContext,
|
|
@@ -25,9 +31,12 @@ import { evaluateStructuredGuards } from "../server/triage/guards.js";
|
|
|
25
31
|
export default defineAction({
|
|
26
32
|
description:
|
|
27
33
|
"Triage one Factory item against enabled rules and append structured guard decisions. This records proposals only and never changes a provider.",
|
|
28
|
-
schema: z.object({
|
|
34
|
+
schema: z.object({
|
|
35
|
+
factoryId: factoryIdSchema.default(DEFAULT_FACTORY_ID),
|
|
36
|
+
itemId: z.string().min(1),
|
|
37
|
+
}),
|
|
29
38
|
http: { method: "POST" },
|
|
30
|
-
run: async ({ itemId }, context) => {
|
|
39
|
+
run: async ({ factoryId, itemId }, context) => {
|
|
31
40
|
const { userEmail, orgId } = await requireWorkspaceMember(
|
|
32
41
|
workspaceMemberIdentityFromContext(context),
|
|
33
42
|
);
|
|
@@ -36,7 +45,12 @@ export default defineAction({
|
|
|
36
45
|
await db
|
|
37
46
|
.select()
|
|
38
47
|
.from(triageItems)
|
|
39
|
-
.where(
|
|
48
|
+
.where(
|
|
49
|
+
and(
|
|
50
|
+
eq(triageItems.id, itemId),
|
|
51
|
+
orgFactoryItemFilter(orgId, factoryId),
|
|
52
|
+
),
|
|
53
|
+
)
|
|
40
54
|
.limit(1)
|
|
41
55
|
)[0];
|
|
42
56
|
if (!item) throw new Error("Triage item not found");
|
|
@@ -44,7 +58,9 @@ export default defineAction({
|
|
|
44
58
|
const rules = await db
|
|
45
59
|
.select()
|
|
46
60
|
.from(triageRules)
|
|
47
|
-
.where(
|
|
61
|
+
.where(
|
|
62
|
+
and(eq(triageRules.enabled, 1), orgFactoryRuleFilter(orgId, factoryId)),
|
|
63
|
+
);
|
|
48
64
|
const metadata = parseMetadata(item.metadataJson);
|
|
49
65
|
const evidence = {
|
|
50
66
|
repository: item.repository ?? undefined,
|
|
@@ -77,6 +93,7 @@ export default defineAction({
|
|
|
77
93
|
{
|
|
78
94
|
action: "evaluate-triage-item",
|
|
79
95
|
kind: "decision",
|
|
96
|
+
factoryId,
|
|
80
97
|
status: "skipped",
|
|
81
98
|
itemId,
|
|
82
99
|
source: item.source,
|
|
@@ -116,6 +133,7 @@ export default defineAction({
|
|
|
116
133
|
createdAt: now,
|
|
117
134
|
ownerEmail: userEmail,
|
|
118
135
|
orgId,
|
|
136
|
+
factoryId,
|
|
119
137
|
};
|
|
120
138
|
});
|
|
121
139
|
|
|
@@ -131,7 +149,12 @@ export default defineAction({
|
|
|
131
149
|
: "shadow_decided",
|
|
132
150
|
updatedAt: now,
|
|
133
151
|
})
|
|
134
|
-
.where(
|
|
152
|
+
.where(
|
|
153
|
+
and(
|
|
154
|
+
eq(triageItems.id, itemId),
|
|
155
|
+
orgFactoryItemFilter(orgId, factoryId),
|
|
156
|
+
),
|
|
157
|
+
);
|
|
135
158
|
});
|
|
136
159
|
|
|
137
160
|
for (const decision of decisions) {
|
|
@@ -141,6 +164,7 @@ export default defineAction({
|
|
|
141
164
|
{
|
|
142
165
|
action: "evaluate-triage-item",
|
|
143
166
|
kind: "decision",
|
|
167
|
+
factoryId,
|
|
144
168
|
itemId,
|
|
145
169
|
source: item.source,
|
|
146
170
|
sourceUrl: item.sourceUrl,
|
|
@@ -28,7 +28,7 @@ export default defineAction({
|
|
|
28
28
|
const row = await readFactoryDefinition(orgId, factoryId);
|
|
29
29
|
const fallback = defaultFactoryDefinition();
|
|
30
30
|
const graph = row ? parseFactoryGraph(row.graphJson) : fallback.graph;
|
|
31
|
-
const metrics = await readFactoryMetrics(orgId);
|
|
31
|
+
const metrics = await readFactoryMetrics(orgId, factoryId);
|
|
32
32
|
|
|
33
33
|
const metricValues: Record<string, number> = {
|
|
34
34
|
items: metrics.totalItems,
|
|
@@ -3,7 +3,13 @@ import { and, eq } from "drizzle-orm";
|
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
|
|
5
5
|
import { getDb } from "../server/db/index.js";
|
|
6
|
-
import {
|
|
6
|
+
import { triageItems } from "../server/db/schema.js";
|
|
7
|
+
import { DEFAULT_FACTORY_ID } from "../server/factory-graph/store.js";
|
|
8
|
+
import {
|
|
9
|
+
factoryIdSchema,
|
|
10
|
+
orgFactoryItemFilter,
|
|
11
|
+
readTriageConfigRow,
|
|
12
|
+
} from "../server/lib/factory-scope.js";
|
|
7
13
|
import {
|
|
8
14
|
requireWorkspaceMember,
|
|
9
15
|
workspaceMemberIdentityFromContext,
|
|
@@ -14,10 +20,13 @@ import { createSlackReader } from "../server/triage/slack-client.js";
|
|
|
14
20
|
export default defineAction({
|
|
15
21
|
description:
|
|
16
22
|
"Read the bounded full Slack thread for one Factory feedback item. Use this before deciding whether a report is a clear bug; unreadable or truncated context is not a green light.",
|
|
17
|
-
schema: z.object({
|
|
23
|
+
schema: z.object({
|
|
24
|
+
factoryId: factoryIdSchema.default(DEFAULT_FACTORY_ID),
|
|
25
|
+
itemId: z.string().min(1),
|
|
26
|
+
}),
|
|
18
27
|
http: { method: "GET" },
|
|
19
28
|
readOnly: true,
|
|
20
|
-
run: async ({ itemId }, context) => {
|
|
29
|
+
run: async ({ factoryId, itemId }, context) => {
|
|
21
30
|
const { userEmail, orgId } = await requireWorkspaceMember(
|
|
22
31
|
workspaceMemberIdentityFromContext(context),
|
|
23
32
|
);
|
|
@@ -25,7 +34,12 @@ export default defineAction({
|
|
|
25
34
|
await getDb()
|
|
26
35
|
.select()
|
|
27
36
|
.from(triageItems)
|
|
28
|
-
.where(
|
|
37
|
+
.where(
|
|
38
|
+
and(
|
|
39
|
+
eq(triageItems.id, itemId),
|
|
40
|
+
orgFactoryItemFilter(orgId, factoryId),
|
|
41
|
+
),
|
|
42
|
+
)
|
|
29
43
|
.limit(1)
|
|
30
44
|
)[0];
|
|
31
45
|
if (!item) throw new Error("Factory item not found.");
|
|
@@ -33,13 +47,7 @@ export default defineAction({
|
|
|
33
47
|
throw new Error("Factory item is not a readable Slack feedback item.");
|
|
34
48
|
}
|
|
35
49
|
|
|
36
|
-
const config = (
|
|
37
|
-
await getDb()
|
|
38
|
-
.select({ slackWorkspace: triageConfig.slackWorkspace })
|
|
39
|
-
.from(triageConfig)
|
|
40
|
-
.where(and(eq(triageConfig.id, orgId), eq(triageConfig.orgId, orgId)))
|
|
41
|
-
.limit(1)
|
|
42
|
-
)[0];
|
|
50
|
+
const config = await readTriageConfigRow(getDb(), orgId, factoryId);
|
|
43
51
|
const workspace =
|
|
44
52
|
config?.slackWorkspace === "secondary" ? "secondary" : "primary";
|
|
45
53
|
const slack = createSlackReader({ ownerEmail: userEmail, orgId });
|
|
@@ -66,6 +74,7 @@ export default defineAction({
|
|
|
66
74
|
messageCount: messages.length,
|
|
67
75
|
},
|
|
68
76
|
},
|
|
77
|
+
factoryId,
|
|
69
78
|
);
|
|
70
79
|
|
|
71
80
|
return {
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { defineAction } from "@agent-native/core/action";
|
|
2
2
|
import { getEmailReadiness } from "@agent-native/core/server";
|
|
3
|
-
import { and, eq } from "drizzle-orm";
|
|
4
3
|
import { z } from "zod";
|
|
5
4
|
|
|
6
5
|
import { getDb } from "../server/db/index.js";
|
|
7
|
-
import {
|
|
6
|
+
import { DEFAULT_FACTORY_ID } from "../server/factory-graph/store.js";
|
|
7
|
+
import {
|
|
8
|
+
factoryIdSchema,
|
|
9
|
+
readTriageConfigRow,
|
|
10
|
+
} from "../server/lib/factory-scope.js";
|
|
8
11
|
import {
|
|
9
12
|
requireWorkspaceMember,
|
|
10
13
|
workspaceMemberIdentityFromContext,
|
|
@@ -12,24 +15,21 @@ import {
|
|
|
12
15
|
|
|
13
16
|
export default defineAction({
|
|
14
17
|
description:
|
|
15
|
-
"Read Factory observation settings for the
|
|
16
|
-
schema: z.object({
|
|
18
|
+
"Read Factory observation settings for the selected factory. Secret values are never returned.",
|
|
19
|
+
schema: z.object({
|
|
20
|
+
factoryId: factoryIdSchema.default(DEFAULT_FACTORY_ID),
|
|
21
|
+
}),
|
|
17
22
|
http: { method: "GET" },
|
|
18
23
|
readOnly: true,
|
|
19
|
-
run: async (
|
|
24
|
+
run: async ({ factoryId }, context) => {
|
|
20
25
|
const { orgId } = await requireWorkspaceMember(
|
|
21
26
|
workspaceMemberIdentityFromContext(context),
|
|
22
27
|
);
|
|
23
28
|
const emailReadiness = await getEmailReadiness();
|
|
24
|
-
const row = (
|
|
25
|
-
await getDb()
|
|
26
|
-
.select()
|
|
27
|
-
.from(triageConfig)
|
|
28
|
-
.where(and(eq(triageConfig.id, orgId), eq(triageConfig.orgId, orgId)))
|
|
29
|
-
.limit(1)
|
|
30
|
-
)[0];
|
|
29
|
+
const row = await readTriageConfigRow(getDb(), orgId, factoryId);
|
|
31
30
|
if (!row) {
|
|
32
31
|
return {
|
|
32
|
+
factoryId,
|
|
33
33
|
slackWorkspace: "primary",
|
|
34
34
|
slackChannelId: null,
|
|
35
35
|
slackChannelName: null,
|
|
@@ -51,6 +51,7 @@ export default defineAction({
|
|
|
51
51
|
}
|
|
52
52
|
return {
|
|
53
53
|
...row,
|
|
54
|
+
factoryId,
|
|
54
55
|
pollingEnabled: row.pollingEnabled === 1,
|
|
55
56
|
githubPollingEnabled: row.githubPollingEnabled === 1,
|
|
56
57
|
sentryPollingEnabled: row.sentryPollingEnabled === 1,
|
|
@@ -9,6 +9,14 @@ import {
|
|
|
9
9
|
triageItems,
|
|
10
10
|
triageRuns,
|
|
11
11
|
} from "../server/db/schema.js";
|
|
12
|
+
import { DEFAULT_FACTORY_ID } from "../server/factory-graph/store.js";
|
|
13
|
+
import {
|
|
14
|
+
factoryIdSchema,
|
|
15
|
+
orgFactoryDecisionFilter,
|
|
16
|
+
orgFactoryFeedbackFilter,
|
|
17
|
+
orgFactoryItemFilter,
|
|
18
|
+
orgFactoryRunFilter,
|
|
19
|
+
} from "../server/lib/factory-scope.js";
|
|
12
20
|
import {
|
|
13
21
|
requireWorkspaceMember,
|
|
14
22
|
workspaceMemberIdentityFromContext,
|
|
@@ -18,10 +26,13 @@ import { recordFactoryAudit } from "../server/triage/audit.js";
|
|
|
18
26
|
export default defineAction({
|
|
19
27
|
description:
|
|
20
28
|
"Inspect one Factory item, including its append-only shadow decisions, feedback, and run reconciliation state.",
|
|
21
|
-
schema: z.object({
|
|
29
|
+
schema: z.object({
|
|
30
|
+
factoryId: factoryIdSchema.default(DEFAULT_FACTORY_ID),
|
|
31
|
+
itemId: z.string().min(1),
|
|
32
|
+
}),
|
|
22
33
|
http: { method: "GET" },
|
|
23
34
|
readOnly: true,
|
|
24
|
-
run: async ({ itemId }, context) => {
|
|
35
|
+
run: async ({ factoryId, itemId }, context) => {
|
|
25
36
|
const { userEmail, orgId } = await requireWorkspaceMember(
|
|
26
37
|
workspaceMemberIdentityFromContext(context),
|
|
27
38
|
);
|
|
@@ -30,7 +41,12 @@ export default defineAction({
|
|
|
30
41
|
await db
|
|
31
42
|
.select()
|
|
32
43
|
.from(triageItems)
|
|
33
|
-
.where(
|
|
44
|
+
.where(
|
|
45
|
+
and(
|
|
46
|
+
eq(triageItems.id, itemId),
|
|
47
|
+
orgFactoryItemFilter(orgId, factoryId),
|
|
48
|
+
),
|
|
49
|
+
)
|
|
34
50
|
.limit(1)
|
|
35
51
|
)[0];
|
|
36
52
|
if (!item) throw new Error("Triage item not found");
|
|
@@ -41,19 +57,24 @@ export default defineAction({
|
|
|
41
57
|
.where(
|
|
42
58
|
and(
|
|
43
59
|
eq(triageDecisions.itemId, itemId),
|
|
44
|
-
|
|
60
|
+
orgFactoryDecisionFilter(orgId, factoryId),
|
|
45
61
|
),
|
|
46
62
|
)
|
|
47
63
|
.orderBy(asc(triageDecisions.createdAt));
|
|
48
64
|
const feedback = await db
|
|
49
65
|
.select()
|
|
50
66
|
.from(triageFeedback)
|
|
51
|
-
.where(
|
|
67
|
+
.where(orgFactoryFeedbackFilter(orgId, factoryId))
|
|
52
68
|
.orderBy(asc(triageFeedback.createdAt));
|
|
53
69
|
const runs = await db
|
|
54
70
|
.select()
|
|
55
71
|
.from(triageRuns)
|
|
56
|
-
.where(
|
|
72
|
+
.where(
|
|
73
|
+
and(
|
|
74
|
+
eq(triageRuns.itemId, itemId),
|
|
75
|
+
orgFactoryRunFilter(orgId, factoryId),
|
|
76
|
+
),
|
|
77
|
+
)
|
|
57
78
|
.orderBy(asc(triageRuns.startedAt));
|
|
58
79
|
|
|
59
80
|
const matchingFeedback = feedback.filter((entry) =>
|
|
@@ -76,6 +97,7 @@ export default defineAction({
|
|
|
76
97
|
coverage: item.coverage,
|
|
77
98
|
},
|
|
78
99
|
},
|
|
100
|
+
factoryId,
|
|
79
101
|
);
|
|
80
102
|
|
|
81
103
|
return {
|
|
@@ -6,10 +6,17 @@ import { resolveConnectorSecret } from "../server/connectors/credentials.js";
|
|
|
6
6
|
import { getDb } from "../server/db/index.js";
|
|
7
7
|
import {
|
|
8
8
|
triageDecisions,
|
|
9
|
-
triageConfig,
|
|
10
9
|
triageItems,
|
|
11
10
|
triageRuns,
|
|
12
11
|
} from "../server/db/schema.js";
|
|
12
|
+
import { DEFAULT_FACTORY_ID } from "../server/factory-graph/store.js";
|
|
13
|
+
import {
|
|
14
|
+
factoryIdSchema,
|
|
15
|
+
orgFactoryItemFilter,
|
|
16
|
+
orgFactoryRunFilter,
|
|
17
|
+
orgFactoryScopedItemWhere,
|
|
18
|
+
readTriageConfigRow,
|
|
19
|
+
} from "../server/lib/factory-scope.js";
|
|
13
20
|
import { requireFactoryAutomation } from "../server/lib/require-factory-automation.js";
|
|
14
21
|
import {
|
|
15
22
|
requireWorkspaceMember,
|
|
@@ -50,11 +57,12 @@ function requiredAiServicesEnv(
|
|
|
50
57
|
async function hasVerifiedFactoryRun(input: {
|
|
51
58
|
itemId: string | undefined;
|
|
52
59
|
orgId: string;
|
|
60
|
+
factoryId: string;
|
|
53
61
|
pullRequestBody: string | null;
|
|
54
62
|
headRef: string;
|
|
55
63
|
}): Promise<boolean> {
|
|
56
64
|
const db = getDb();
|
|
57
|
-
const runConditions = [
|
|
65
|
+
const runConditions = [orgFactoryRunFilter(input.orgId, input.factoryId)];
|
|
58
66
|
if (input.itemId) {
|
|
59
67
|
runConditions.push(eq(triageRuns.itemId, input.itemId));
|
|
60
68
|
}
|
|
@@ -91,7 +99,7 @@ async function hasVerifiedFactoryRun(input: {
|
|
|
91
99
|
const items = await db
|
|
92
100
|
.select({ id: triageItems.id, sourceUrl: triageItems.sourceUrl })
|
|
93
101
|
.from(triageItems)
|
|
94
|
-
.where(
|
|
102
|
+
.where(orgFactoryItemFilter(input.orgId, input.factoryId))
|
|
95
103
|
.orderBy(desc(triageItems.updatedAt))
|
|
96
104
|
.limit(100);
|
|
97
105
|
return items.some((item) => {
|
|
@@ -108,6 +116,7 @@ export default defineAction({
|
|
|
108
116
|
description:
|
|
109
117
|
"Govern one agent-native pull request after fetching bounded GitHub and ai-services evidence. Auto-approve only under the current review-prs membership, owner, evidence, and ultra-scary gates. Never auto-merge. Clips, Design, and Content feedback remains owner-managed while their verified PR-owner exceptions still apply.",
|
|
110
118
|
schema: z.object({
|
|
119
|
+
factoryId: factoryIdSchema.default(DEFAULT_FACTORY_ID),
|
|
111
120
|
repo: z.string().trim().min(1).max(256),
|
|
112
121
|
pullRequestNumber: z.number().int().positive(),
|
|
113
122
|
itemId: z.string().min(1).optional(),
|
|
@@ -118,6 +127,7 @@ export default defineAction({
|
|
|
118
127
|
http: false,
|
|
119
128
|
run: async (
|
|
120
129
|
{
|
|
130
|
+
factoryId,
|
|
121
131
|
repo,
|
|
122
132
|
pullRequestNumber,
|
|
123
133
|
itemId,
|
|
@@ -130,15 +140,16 @@ export default defineAction({
|
|
|
130
140
|
const { userEmail, orgId } = await requireWorkspaceMember(
|
|
131
141
|
workspaceMemberIdentityFromContext(context),
|
|
132
142
|
);
|
|
133
|
-
await requireFactoryAutomation(
|
|
143
|
+
await requireFactoryAutomation(
|
|
144
|
+
context,
|
|
145
|
+
{ userEmail, orgId },
|
|
146
|
+
"governance",
|
|
147
|
+
factoryId,
|
|
148
|
+
);
|
|
134
149
|
const repository = repositoryRef(repo);
|
|
135
150
|
const configuredRepository = (
|
|
136
|
-
await getDb()
|
|
137
|
-
|
|
138
|
-
.from(triageConfig)
|
|
139
|
-
.where(and(eq(triageConfig.id, orgId), eq(triageConfig.orgId, orgId)))
|
|
140
|
-
.limit(1)
|
|
141
|
-
)[0]?.repository;
|
|
151
|
+
await readTriageConfigRow(getDb(), orgId, factoryId)
|
|
152
|
+
)?.repository;
|
|
142
153
|
if (!configuredRepository || configuredRepository.trim() !== repo.trim()) {
|
|
143
154
|
throw new Error(
|
|
144
155
|
"PR governance is restricted to the configured Factory repository.",
|
|
@@ -152,7 +163,7 @@ export default defineAction({
|
|
|
152
163
|
pullRequestNumber: triageItems.pullRequestNumber,
|
|
153
164
|
})
|
|
154
165
|
.from(triageItems)
|
|
155
|
-
.where(
|
|
166
|
+
.where(orgFactoryScopedItemWhere(itemId, orgId, factoryId))
|
|
156
167
|
.limit(1)
|
|
157
168
|
)[0];
|
|
158
169
|
if (
|
|
@@ -178,7 +189,7 @@ export default defineAction({
|
|
|
178
189
|
status: "pr_observed",
|
|
179
190
|
updatedAt: new Date().toISOString(),
|
|
180
191
|
})
|
|
181
|
-
.where(
|
|
192
|
+
.where(orgFactoryScopedItemWhere(itemId, orgId, factoryId));
|
|
182
193
|
}
|
|
183
194
|
return {
|
|
184
195
|
ok: true,
|
|
@@ -222,6 +233,7 @@ export default defineAction({
|
|
|
222
233
|
"Skipped the pull request because it already has a current non-dismissed approval.",
|
|
223
234
|
details: { repo, pullRequestNumber },
|
|
224
235
|
},
|
|
236
|
+
factoryId,
|
|
225
237
|
);
|
|
226
238
|
if (itemId) {
|
|
227
239
|
await getDb()
|
|
@@ -230,7 +242,7 @@ export default defineAction({
|
|
|
230
242
|
status: "pr_observed",
|
|
231
243
|
updatedAt: new Date().toISOString(),
|
|
232
244
|
})
|
|
233
|
-
.where(
|
|
245
|
+
.where(orgFactoryScopedItemWhere(itemId, orgId, factoryId));
|
|
234
246
|
}
|
|
235
247
|
return {
|
|
236
248
|
ok: true,
|
|
@@ -267,6 +279,7 @@ export default defineAction({
|
|
|
267
279
|
const factoryTriggered = await hasVerifiedFactoryRun({
|
|
268
280
|
itemId,
|
|
269
281
|
orgId,
|
|
282
|
+
factoryId,
|
|
270
283
|
pullRequestBody: pullRequest.body,
|
|
271
284
|
headRef: pullRequest.headRef,
|
|
272
285
|
});
|
|
@@ -312,6 +325,7 @@ export default defineAction({
|
|
|
312
325
|
guardResults: governance.guardResults,
|
|
313
326
|
},
|
|
314
327
|
},
|
|
328
|
+
factoryId,
|
|
315
329
|
);
|
|
316
330
|
|
|
317
331
|
if (itemId) {
|
|
@@ -319,7 +333,7 @@ export default defineAction({
|
|
|
319
333
|
await getDb()
|
|
320
334
|
.select()
|
|
321
335
|
.from(triageItems)
|
|
322
|
-
.where(
|
|
336
|
+
.where(orgFactoryScopedItemWhere(itemId, orgId, factoryId))
|
|
323
337
|
.limit(1)
|
|
324
338
|
)[0];
|
|
325
339
|
if (!item) throw new Error("Factory item not found for PR governance.");
|
|
@@ -348,6 +362,7 @@ export default defineAction({
|
|
|
348
362
|
createdAt: new Date().toISOString(),
|
|
349
363
|
ownerEmail: userEmail,
|
|
350
364
|
orgId,
|
|
365
|
+
factoryId,
|
|
351
366
|
})
|
|
352
367
|
.onConflictDoNothing();
|
|
353
368
|
}
|
|
@@ -360,7 +375,7 @@ export default defineAction({
|
|
|
360
375
|
status: governance.ownerOwnedArea ? "needs_manual" : "pr_observed",
|
|
361
376
|
updatedAt: new Date().toISOString(),
|
|
362
377
|
})
|
|
363
|
-
.where(
|
|
378
|
+
.where(orgFactoryScopedItemWhere(itemId, orgId, factoryId));
|
|
364
379
|
}
|
|
365
380
|
return {
|
|
366
381
|
ok: true,
|
|
@@ -381,7 +396,7 @@ export default defineAction({
|
|
|
381
396
|
status: triageItems.status,
|
|
382
397
|
})
|
|
383
398
|
.from(triageItems)
|
|
384
|
-
.where(
|
|
399
|
+
.where(orgFactoryScopedItemWhere(itemId, orgId, factoryId))
|
|
385
400
|
.limit(1)
|
|
386
401
|
)[0];
|
|
387
402
|
if (!item) throw new Error("Factory item disappeared after PR approval.");
|
|
@@ -410,7 +425,7 @@ export default defineAction({
|
|
|
410
425
|
status: "auto_approved",
|
|
411
426
|
updatedAt: new Date().toISOString(),
|
|
412
427
|
})
|
|
413
|
-
.where(
|
|
428
|
+
.where(orgFactoryScopedItemWhere(itemId, orgId, factoryId));
|
|
414
429
|
}
|
|
415
430
|
} else {
|
|
416
431
|
approvalUrl = (
|
|
@@ -437,6 +452,7 @@ export default defineAction({
|
|
|
437
452
|
"Approved the pull request under the current review-prs policy.",
|
|
438
453
|
details: { repo, pullRequestNumber, approvalUrl },
|
|
439
454
|
},
|
|
455
|
+
factoryId,
|
|
440
456
|
);
|
|
441
457
|
return {
|
|
442
458
|
ok: true,
|
|
@@ -3,6 +3,8 @@ import { z } from "zod";
|
|
|
3
3
|
|
|
4
4
|
import { getDb } from "../server/db/index.js";
|
|
5
5
|
import { triageItems } from "../server/db/schema.js";
|
|
6
|
+
import { DEFAULT_FACTORY_ID } from "../server/factory-graph/store.js";
|
|
7
|
+
import { factoryIdSchema } from "../server/lib/factory-scope.js";
|
|
6
8
|
import {
|
|
7
9
|
requireWorkspaceMember,
|
|
8
10
|
workspaceMemberIdentityFromContext,
|
|
@@ -31,6 +33,7 @@ export default defineAction({
|
|
|
31
33
|
description:
|
|
32
34
|
"Ingest one read-only GitHub pull-request observation from the existing ai-services boundary into Factory. This action records evidence only and never writes to GitHub.",
|
|
33
35
|
schema: z.object({
|
|
36
|
+
factoryId: factoryIdSchema.default(DEFAULT_FACTORY_ID),
|
|
34
37
|
repo: z.string().trim().min(1).max(256),
|
|
35
38
|
pullRequestNumber: z.number().int().positive(),
|
|
36
39
|
headSha: z.string().trim().min(1).max(128),
|
|
@@ -50,8 +53,9 @@ export default defineAction({
|
|
|
50
53
|
const { userEmail, orgId } = await requireWorkspaceMember(
|
|
51
54
|
workspaceMemberIdentityFromContext(context),
|
|
52
55
|
);
|
|
53
|
-
const
|
|
54
|
-
const
|
|
56
|
+
const { factoryId, ...observation } = input;
|
|
57
|
+
const envelope = pullRequestSnapshotToEnvelope(observation);
|
|
58
|
+
const id = itemDedupeKey(envelope, orgId, factoryId);
|
|
55
59
|
const now = new Date().toISOString();
|
|
56
60
|
const db = getDb();
|
|
57
61
|
|
|
@@ -77,6 +81,7 @@ export default defineAction({
|
|
|
77
81
|
updatedAt: now,
|
|
78
82
|
ownerEmail: userEmail,
|
|
79
83
|
orgId,
|
|
84
|
+
factoryId,
|
|
80
85
|
})
|
|
81
86
|
.onConflictDoUpdate({
|
|
82
87
|
target: triageItems.id,
|
|
@@ -105,10 +110,11 @@ export default defineAction({
|
|
|
105
110
|
repository: envelope.repository,
|
|
106
111
|
pullRequestNumber: envelope.pullRequestNumber,
|
|
107
112
|
coverage: envelope.coverage,
|
|
108
|
-
reviewCount:
|
|
109
|
-
checkCount:
|
|
113
|
+
reviewCount: observation.reviews.length,
|
|
114
|
+
checkCount: observation.checks.length,
|
|
110
115
|
},
|
|
111
116
|
},
|
|
117
|
+
factoryId,
|
|
112
118
|
);
|
|
113
119
|
|
|
114
120
|
return {
|
|
@@ -8,6 +8,10 @@ import { z } from "zod";
|
|
|
8
8
|
|
|
9
9
|
import { getDb } from "../server/db/index.js";
|
|
10
10
|
import { factoryAuditEvents } from "../server/db/schema.js";
|
|
11
|
+
import {
|
|
12
|
+
factoryIdSchema,
|
|
13
|
+
readAutomationFactoryId,
|
|
14
|
+
} from "../server/lib/factory-scope.js";
|
|
11
15
|
import {
|
|
12
16
|
requireWorkspaceMember,
|
|
13
17
|
workspaceMemberIdentityFromContext,
|
|
@@ -18,13 +22,13 @@ export default defineAction({
|
|
|
18
22
|
"List recent Factory automation runs with the bounded source observations, decisions, and external actions recorded for each run.",
|
|
19
23
|
agentTool: false,
|
|
20
24
|
schema: z.object({
|
|
21
|
-
factoryId:
|
|
25
|
+
factoryId: factoryIdSchema,
|
|
22
26
|
automation: z.string().trim().min(1).optional(),
|
|
23
27
|
limit: z.coerce.number().int().min(1).max(50).default(20),
|
|
24
28
|
}),
|
|
25
29
|
http: { method: "GET" },
|
|
26
30
|
readOnly: true,
|
|
27
|
-
run: async ({ automation, limit }, context) => {
|
|
31
|
+
run: async ({ factoryId, automation, limit }, context) => {
|
|
28
32
|
const { userEmail, orgId } = await requireWorkspaceMember(
|
|
29
33
|
workspaceMemberIdentityFromContext(context),
|
|
30
34
|
);
|
|
@@ -33,8 +37,10 @@ export default defineAction({
|
|
|
33
37
|
"organization",
|
|
34
38
|
);
|
|
35
39
|
const factoryDefinitions = definitions.filter(
|
|
36
|
-
({ meta, name }) =>
|
|
37
|
-
meta.domain === "factory" &&
|
|
40
|
+
({ meta, name, resource }) =>
|
|
41
|
+
meta.domain === "factory" &&
|
|
42
|
+
readAutomationFactoryId(meta, resource.content) === factoryId &&
|
|
43
|
+
(!automation || name === automation),
|
|
38
44
|
);
|
|
39
45
|
const runGroups = await Promise.all(
|
|
40
46
|
factoryDefinitions.map(async ({ name, resource }) =>
|
|
@@ -60,6 +66,7 @@ export default defineAction({
|
|
|
60
66
|
.where(
|
|
61
67
|
and(
|
|
62
68
|
eq(factoryAuditEvents.orgId, orgId),
|
|
69
|
+
eq(factoryAuditEvents.factoryId, factoryId),
|
|
63
70
|
inArray(factoryAuditEvents.automationRunId, runIds),
|
|
64
71
|
),
|
|
65
72
|
)
|
|
@@ -5,32 +5,58 @@ import {
|
|
|
5
5
|
} from "@agent-native/core/triggers";
|
|
6
6
|
import { z } from "zod";
|
|
7
7
|
|
|
8
|
+
import { readFactoryDefinition } from "../server/factory-graph/store.js";
|
|
9
|
+
import {
|
|
10
|
+
DEFAULT_FACTORY_ID,
|
|
11
|
+
factoryIdSchema,
|
|
12
|
+
readAutomationFactoryId,
|
|
13
|
+
resolveAutomationDisplayName,
|
|
14
|
+
} from "../server/lib/factory-scope.js";
|
|
8
15
|
import {
|
|
9
16
|
requireWorkspaceMember,
|
|
10
17
|
workspaceMemberIdentityFromContext,
|
|
11
18
|
} from "../server/lib/require-workspace-member.js";
|
|
12
19
|
|
|
20
|
+
function automationRunHistoryKey(path: string): string {
|
|
21
|
+
return path.replace(/^jobs\//, "").replace(/\.md$/, "");
|
|
22
|
+
}
|
|
23
|
+
|
|
13
24
|
export default defineAction({
|
|
14
25
|
description:
|
|
15
26
|
"List the organization-scoped Factory automations with their trigger, editable prompt, model, schedule, enabled state, and recent runs.",
|
|
16
27
|
agentTool: false,
|
|
17
|
-
schema: z.object({ factoryId:
|
|
28
|
+
schema: z.object({ factoryId: factoryIdSchema }),
|
|
18
29
|
http: { method: "GET" },
|
|
19
30
|
readOnly: true,
|
|
20
|
-
run: async (
|
|
31
|
+
run: async ({ factoryId }, context) => {
|
|
21
32
|
const { userEmail, orgId } = await requireWorkspaceMember(
|
|
22
33
|
workspaceMemberIdentityFromContext(context),
|
|
23
34
|
);
|
|
35
|
+
const factory = await readFactoryDefinition(orgId, factoryId);
|
|
36
|
+
if (!factory && factoryId !== DEFAULT_FACTORY_ID) {
|
|
37
|
+
throw new Error("Factory not found.");
|
|
38
|
+
}
|
|
24
39
|
const definitions = await listAutomationDefinitions(
|
|
25
40
|
{ userEmail, orgId, appId: "factory" },
|
|
26
41
|
"organization",
|
|
27
42
|
);
|
|
43
|
+
const scoped = definitions.filter(
|
|
44
|
+
({ meta, resource }) =>
|
|
45
|
+
meta.domain === "factory" &&
|
|
46
|
+
readAutomationFactoryId(meta, resource.content) === factoryId,
|
|
47
|
+
);
|
|
28
48
|
return Promise.all(
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
49
|
+
scoped.map(async ({ resource, name, meta, body, canUpdate }) => {
|
|
50
|
+
const runs = await listAutomationRuns({
|
|
51
|
+
owners: [resource.owner],
|
|
52
|
+
automation: automationRunHistoryKey(resource.path),
|
|
53
|
+
appId: "factory",
|
|
54
|
+
limit: 20,
|
|
55
|
+
});
|
|
56
|
+
return {
|
|
32
57
|
id: resource.id,
|
|
33
58
|
name,
|
|
59
|
+
displayName: resolveAutomationDisplayName(name, resource.content),
|
|
34
60
|
prompt: body,
|
|
35
61
|
body,
|
|
36
62
|
model: meta.model ?? null,
|
|
@@ -46,13 +72,9 @@ export default defineAction({
|
|
|
46
72
|
? new Date(resource.updatedAt).toISOString()
|
|
47
73
|
: null,
|
|
48
74
|
canUpdate,
|
|
49
|
-
runs:
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
appId: "factory",
|
|
53
|
-
limit: 20,
|
|
54
|
-
}),
|
|
55
|
-
})),
|
|
75
|
+
runs: runs.filter((run) => run.path === resource.path),
|
|
76
|
+
};
|
|
77
|
+
}),
|
|
56
78
|
);
|
|
57
79
|
},
|
|
58
80
|
});
|