@agent-native/core 0.168.7 → 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/sync-calendars.ts +10 -29
- 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/struct-routes.d.ts +1 -1
- package/dist/file-upload/actions/upload-image.d.ts +1 -1
- package/dist/observability/routes.d.ts +3 -3
- package/dist/progress/routes.d.ts +1 -1
- package/dist/secrets/routes.d.ts +6 -6
- package/dist/server/realtime-token.d.ts +1 -1
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/package.json +1 -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
|
});
|
|
@@ -4,6 +4,12 @@ import { z } from "zod";
|
|
|
4
4
|
|
|
5
5
|
import { getDb } from "../server/db/index.js";
|
|
6
6
|
import { triageItems, triageDecisions } from "../server/db/schema.js";
|
|
7
|
+
import { DEFAULT_FACTORY_ID } from "../server/factory-graph/store.js";
|
|
8
|
+
import {
|
|
9
|
+
factoryIdSchema,
|
|
10
|
+
orgFactoryDecisionFilter,
|
|
11
|
+
orgFactoryItemFilter,
|
|
12
|
+
} from "../server/lib/factory-scope.js";
|
|
7
13
|
import {
|
|
8
14
|
requireWorkspaceMember,
|
|
9
15
|
workspaceMemberIdentityFromContext,
|
|
@@ -18,6 +24,7 @@ export default defineAction({
|
|
|
18
24
|
description:
|
|
19
25
|
"List the Factory observation queue. Results are scoped to the active workspace and include the latest shadow decision summary. Scheduled reviewers must pass needsReview true with a bounded source and limit so unchanged items are not re-reviewed.",
|
|
20
26
|
schema: z.object({
|
|
27
|
+
factoryId: factoryIdSchema.default(DEFAULT_FACTORY_ID),
|
|
21
28
|
status: triageItemStatusSchema.optional(),
|
|
22
29
|
source: triageSourceSchema.optional(),
|
|
23
30
|
needsReview: z.boolean().default(false),
|
|
@@ -25,7 +32,7 @@ export default defineAction({
|
|
|
25
32
|
}),
|
|
26
33
|
http: { method: "GET" },
|
|
27
34
|
readOnly: true,
|
|
28
|
-
run: async ({ status, source, needsReview, limit }, context) => {
|
|
35
|
+
run: async ({ factoryId, status, source, needsReview, limit }, context) => {
|
|
29
36
|
const { userEmail, orgId } = await requireWorkspaceMember(
|
|
30
37
|
workspaceMemberIdentityFromContext(context),
|
|
31
38
|
);
|
|
@@ -41,7 +48,7 @@ export default defineAction({
|
|
|
41
48
|
.from(triageItems)
|
|
42
49
|
.where(
|
|
43
50
|
and(
|
|
44
|
-
|
|
51
|
+
orgFactoryItemFilter(orgId, factoryId),
|
|
45
52
|
needsReview
|
|
46
53
|
? inArray(triageItems.status, reviewStatuses)
|
|
47
54
|
: status
|
|
@@ -56,7 +63,7 @@ export default defineAction({
|
|
|
56
63
|
const decisions = await db
|
|
57
64
|
.select()
|
|
58
65
|
.from(triageDecisions)
|
|
59
|
-
.where(
|
|
66
|
+
.where(orgFactoryDecisionFilter(orgId, factoryId))
|
|
60
67
|
.orderBy(desc(triageDecisions.createdAt))
|
|
61
68
|
.limit(500);
|
|
62
69
|
const latestByItem = new Map<string, (typeof decisions)[number]>();
|
|
@@ -116,6 +123,7 @@ export default defineAction({
|
|
|
116
123
|
decision: item.latestDecision?.outcome ?? null,
|
|
117
124
|
},
|
|
118
125
|
},
|
|
126
|
+
factoryId,
|
|
119
127
|
);
|
|
120
128
|
}
|
|
121
129
|
return listedItems;
|
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
import { defineAction } from "@agent-native/core/action";
|
|
2
|
-
import { desc
|
|
2
|
+
import { desc } from "drizzle-orm";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
|
|
5
5
|
import { getDb } from "../server/db/index.js";
|
|
6
6
|
import { triageRules } from "../server/db/schema.js";
|
|
7
|
+
import { DEFAULT_FACTORY_ID } from "../server/factory-graph/store.js";
|
|
8
|
+
import {
|
|
9
|
+
factoryIdSchema,
|
|
10
|
+
orgFactoryRuleFilter,
|
|
11
|
+
} from "../server/lib/factory-scope.js";
|
|
7
12
|
import {
|
|
8
13
|
requireWorkspaceMember,
|
|
9
14
|
workspaceMemberIdentityFromContext,
|
|
@@ -13,17 +18,19 @@ import { normalizeTriagePolicyGuards } from "../server/triage/contracts.js";
|
|
|
13
18
|
export default defineAction({
|
|
14
19
|
description:
|
|
15
20
|
"List editable Factory rules for the active workspace. Rules are disabled or shadow-only until the owner explicitly promotes them.",
|
|
16
|
-
schema: z.object({
|
|
21
|
+
schema: z.object({
|
|
22
|
+
factoryId: factoryIdSchema.default(DEFAULT_FACTORY_ID),
|
|
23
|
+
}),
|
|
17
24
|
http: { method: "GET" },
|
|
18
25
|
readOnly: true,
|
|
19
|
-
run: async (
|
|
26
|
+
run: async ({ factoryId }, context) => {
|
|
20
27
|
const { orgId } = await requireWorkspaceMember(
|
|
21
28
|
workspaceMemberIdentityFromContext(context),
|
|
22
29
|
);
|
|
23
30
|
const rows = await getDb()
|
|
24
31
|
.select()
|
|
25
32
|
.from(triageRules)
|
|
26
|
-
.where(
|
|
33
|
+
.where(orgFactoryRuleFilter(orgId, factoryId))
|
|
27
34
|
.orderBy(desc(triageRules.updatedAt));
|
|
28
35
|
return rows.map((row) => ({
|
|
29
36
|
...row,
|
|
@@ -3,7 +3,12 @@ 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 { repairFactoryAutomationsFromConfig } from "../server/lib/factory-automation-repair.js";
|
|
8
|
+
import {
|
|
9
|
+
factoryIdSchema,
|
|
10
|
+
readTriageConfigRow,
|
|
11
|
+
} from "../server/lib/factory-scope.js";
|
|
7
12
|
import { requireFactoryAutomation } from "../server/lib/require-factory-automation.js";
|
|
8
13
|
import {
|
|
9
14
|
requireWorkspaceMember,
|
|
@@ -30,11 +35,12 @@ export default defineAction({
|
|
|
30
35
|
description:
|
|
31
36
|
"Poll the configured GitHub repository for bounded open issues and pull requests and record them in the Factory queue. This does not write to GitHub.",
|
|
32
37
|
schema: z.object({
|
|
38
|
+
factoryId: factoryIdSchema,
|
|
33
39
|
includeIssues: z.boolean().default(true),
|
|
34
40
|
includePullRequests: z.boolean().default(true),
|
|
35
41
|
}),
|
|
36
42
|
http: false,
|
|
37
|
-
run: async ({ includeIssues, includePullRequests }, context) => {
|
|
43
|
+
run: async ({ factoryId, includeIssues, includePullRequests }, context) => {
|
|
38
44
|
const { userEmail, orgId } = await requireWorkspaceMember(
|
|
39
45
|
workspaceMemberIdentityFromContext(context),
|
|
40
46
|
);
|
|
@@ -42,14 +48,11 @@ export default defineAction({
|
|
|
42
48
|
context,
|
|
43
49
|
{ userEmail, orgId },
|
|
44
50
|
"sourcePolling",
|
|
51
|
+
factoryId,
|
|
45
52
|
);
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
.from(triageConfig)
|
|
50
|
-
.where(and(eq(triageConfig.id, orgId), eq(triageConfig.orgId, orgId)))
|
|
51
|
-
.limit(1)
|
|
52
|
-
)[0];
|
|
53
|
+
const db = getDb();
|
|
54
|
+
const config = await readTriageConfigRow(db, orgId, factoryId);
|
|
55
|
+
await repairFactoryAutomationsFromConfig(userEmail, orgId, factoryId);
|
|
53
56
|
if (config?.githubPollingEnabled !== 1) {
|
|
54
57
|
throw new Error("Enable GitHub polling before polling GitHub sources.");
|
|
55
58
|
}
|
|
@@ -68,7 +71,6 @@ export default defineAction({
|
|
|
68
71
|
? client.listOpenPullRequests(repository, 50)
|
|
69
72
|
: Promise.resolve([]),
|
|
70
73
|
]);
|
|
71
|
-
const db = getDb();
|
|
72
74
|
const now = new Date().toISOString();
|
|
73
75
|
let issueCount = 0;
|
|
74
76
|
let pullRequestCount = 0;
|
|
@@ -81,6 +83,7 @@ export default defineAction({
|
|
|
81
83
|
externalId: `${repositoryName}#${issue.number}`,
|
|
82
84
|
},
|
|
83
85
|
orgId,
|
|
86
|
+
factoryId,
|
|
84
87
|
);
|
|
85
88
|
const existing = (
|
|
86
89
|
await tx
|
|
@@ -133,6 +136,7 @@ export default defineAction({
|
|
|
133
136
|
updatedAt,
|
|
134
137
|
ownerEmail: existing?.ownerEmail ?? userEmail,
|
|
135
138
|
orgId,
|
|
139
|
+
factoryId,
|
|
136
140
|
})
|
|
137
141
|
.onConflictDoUpdate({
|
|
138
142
|
target: triageItems.id,
|
|
@@ -144,6 +148,7 @@ export default defineAction({
|
|
|
144
148
|
metadataJson: metadata,
|
|
145
149
|
lastSeenAt,
|
|
146
150
|
updatedAt,
|
|
151
|
+
factoryId,
|
|
147
152
|
},
|
|
148
153
|
});
|
|
149
154
|
issueCount += 1;
|
|
@@ -158,6 +163,7 @@ export default defineAction({
|
|
|
158
163
|
pullRequestNumber: pullRequest.number,
|
|
159
164
|
},
|
|
160
165
|
orgId,
|
|
166
|
+
factoryId,
|
|
161
167
|
);
|
|
162
168
|
const existing = (
|
|
163
169
|
await tx
|
|
@@ -213,6 +219,7 @@ export default defineAction({
|
|
|
213
219
|
updatedAt,
|
|
214
220
|
ownerEmail: existing?.ownerEmail ?? userEmail,
|
|
215
221
|
orgId,
|
|
222
|
+
factoryId,
|
|
216
223
|
})
|
|
217
224
|
.onConflictDoUpdate({
|
|
218
225
|
target: triageItems.id,
|
|
@@ -227,6 +234,7 @@ export default defineAction({
|
|
|
227
234
|
metadataJson: metadata,
|
|
228
235
|
lastSeenAt,
|
|
229
236
|
updatedAt,
|
|
237
|
+
factoryId,
|
|
230
238
|
},
|
|
231
239
|
});
|
|
232
240
|
pullRequestCount += 1;
|
|
@@ -244,6 +252,7 @@ export default defineAction({
|
|
|
244
252
|
summary: "No open GitHub issues or pull requests were observed.",
|
|
245
253
|
details: { repository: repositoryName },
|
|
246
254
|
},
|
|
255
|
+
factoryId,
|
|
247
256
|
);
|
|
248
257
|
} else {
|
|
249
258
|
for (const issue of issues) {
|
|
@@ -259,12 +268,14 @@ export default defineAction({
|
|
|
259
268
|
externalId: `${repositoryName}#${issue.number}`,
|
|
260
269
|
},
|
|
261
270
|
orgId,
|
|
271
|
+
factoryId,
|
|
262
272
|
),
|
|
263
273
|
source: "github_issue",
|
|
264
274
|
sourceUrl: issue.htmlUrl,
|
|
265
275
|
summary: issue.title,
|
|
266
276
|
details: { repository: repositoryName, number: issue.number },
|
|
267
277
|
},
|
|
278
|
+
factoryId,
|
|
268
279
|
);
|
|
269
280
|
}
|
|
270
281
|
for (const pullRequest of pullRequests) {
|
|
@@ -282,18 +293,21 @@ export default defineAction({
|
|
|
282
293
|
pullRequestNumber: pullRequest.number,
|
|
283
294
|
},
|
|
284
295
|
orgId,
|
|
296
|
+
factoryId,
|
|
285
297
|
),
|
|
286
298
|
source: "github",
|
|
287
299
|
sourceUrl: pullRequest.htmlUrl,
|
|
288
300
|
summary: pullRequest.title,
|
|
289
301
|
details: { repository: repositoryName, number: pullRequest.number },
|
|
290
302
|
},
|
|
303
|
+
factoryId,
|
|
291
304
|
);
|
|
292
305
|
}
|
|
293
306
|
}
|
|
294
307
|
|
|
295
308
|
return {
|
|
296
309
|
ok: true,
|
|
310
|
+
factoryId,
|
|
297
311
|
repository: repositoryName,
|
|
298
312
|
issues: issueCount,
|
|
299
313
|
pullRequests: pullRequestCount,
|