@agent-native/core 0.173.2-nightly-20260825163448 → 0.174.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/corpus/README.md +1 -1
- package/corpus/templates/factory/AGENTS.md +1 -1
- package/corpus/templates/factory/actions/babysit-agent-native-pull-request.ts +23 -8
- package/corpus/templates/factory/actions/delete-factory.ts +174 -0
- package/corpus/templates/factory/actions/govern-agent-native-pull-request.ts +28 -20
- package/corpus/templates/factory/actions/poll-github-sources.ts +6 -0
- package/corpus/templates/factory/actions/poll-sentry-errors.ts +16 -1
- package/corpus/templates/factory/actions/poll-slack-channel.ts +12 -0
- package/corpus/templates/factory/actions/start-builder-for-item.ts +74 -42
- package/corpus/templates/factory/app/components/factory/FactorySettingsView.tsx +117 -1
- package/corpus/templates/factory/app/i18n/en-US.ts +12 -0
- package/corpus/templates/factory/app/routes/factory.tsx +6 -1
- package/corpus/templates/factory/changelog/2026-08-24-slack-polling-accepts-the-agentnative-bot-handle.md +6 -0
- package/corpus/templates/factory/changelog/2026-08-24-you-can-delete-a-user-created-factory-from-settings.md +6 -0
- package/corpus/templates/factory/server/lib/factory-automation-repair.ts +6 -0
- package/corpus/templates/factory/server/lib/factory-scope.ts +45 -1
- package/corpus/templates/factory/server/lib/require-factory-automation.ts +5 -0
- package/corpus/templates/factory/server/triage/slack-client.ts +10 -2
- package/corpus/templates/plan/server/plugins/core-routes.ts +6 -1
- package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +4 -1
- package/corpus/templates/slides/app/components/editor/canvas-interactions/slides-canvas-adapter.ts +4 -2
- package/dist/app-config/app-identity.d.ts +20 -0
- package/dist/app-config/app-identity.js +41 -0
- package/dist/app-config/app.d.ts +2 -0
- package/dist/app-config/app.js +14 -0
- package/dist/app-config/observability.d.ts +27 -0
- package/dist/app-config/observability.js +76 -0
- package/dist/app-config/schema.d.ts +13 -0
- package/dist/app-config/schema.js +2 -0
- package/dist/app-config/store.d.ts +14 -4
- package/dist/app-config/store.js +18 -3
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/routes.d.ts +1 -1
- package/dist/email-catalog/actions/list-email-log.js +2 -2
- package/dist/email-catalog/actions/list-transactional-emails.js +2 -2
- package/dist/email-catalog/registry.js +3 -3
- package/dist/mcp/connect-route.js +15 -2
- package/dist/notifications/routes.d.ts +3 -3
- package/dist/observability/index.d.ts +1 -2
- package/dist/observability/index.js +0 -1
- package/dist/observability/posthog-ai.js +11 -3
- package/dist/observability/sentiment.d.ts +0 -1
- package/dist/observability/sentiment.js +8 -5
- package/dist/observability/traces.js +6 -12
- package/dist/observability/types.d.ts +0 -7
- package/dist/observability/types.js +1 -12
- package/dist/progress/routes.d.ts +1 -1
- package/dist/provider-api/actions/custom-provider-registration.d.ts +4 -4
- package/dist/provider-api/actions/provider-api.d.ts +8 -8
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/secrets/routes.d.ts +3 -3
- package/dist/server/agent-chat/plugin-options.d.ts +17 -1
- package/dist/server/agent-chat-plugin.d.ts +10 -0
- package/dist/server/agent-chat-plugin.js +75 -67
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/core-routes/mcp-connect-options.d.ts +70 -0
- package/dist/server/core-routes/mcp-connect-options.js +77 -0
- package/dist/server/core-routes-plugin.d.ts +15 -11
- package/dist/server/core-routes-plugin.js +8 -7
- package/dist/server/edge.d.ts +1 -0
- package/dist/server/email-template.js +2 -2
- package/dist/server/email-templates.js +7 -7
- package/dist/server/email.js +4 -4
- package/dist/server/google-oauth.js +2 -2
- package/dist/server/http-response-telemetry.js +4 -4
- package/dist/server/identity-sso.js +1 -2
- package/dist/server/index.d.ts +1 -0
- package/dist/server/realtime-token.d.ts +1 -1
- package/dist/server/social-og-image.js +2 -2
- package/docs/content/observability.mdx +25 -31
- package/package.json +3 -3
- package/dist/server/app-name.d.ts +0 -33
- package/dist/server/app-name.js +0 -82
package/corpus/README.md
CHANGED
|
@@ -63,7 +63,7 @@ decisions, feedback, agent runs, and provider audit records.
|
|
|
63
63
|
| `get-factory-automation-health` | Inspect scheduler heartbeat and last error. |
|
|
64
64
|
| `suggest-factory-rules` | Mine feedback into proposals. |
|
|
65
65
|
| `reconcile-triage-run` | Persist callback/provider reconciliation. |
|
|
66
|
-
| `list-factories` / `get-factory-graph` | Inspect definitions, versions, and metrics. |
|
|
66
|
+
| `list-factories` / `get-factory-graph` / `delete-factory` | Inspect Factory definitions, versions, and metrics, or permanently delete a user-created Factory after exact-name confirmation. A committed delete whose follow-up read cannot confirm the row is gone returns `verified:false`, not a failed deletion. |
|
|
67
67
|
| `create-factory` | Create a factory from `/new-factory` with optional sources. |
|
|
68
68
|
| `save-factory-graph` | Create/version a graph with inspected `expectedGraphVersion`; never starts provider work. |
|
|
69
69
|
| graph history actions | Factory graph version history. |
|
|
@@ -8,7 +8,9 @@ import { triageItems } from "../server/db/schema.js";
|
|
|
8
8
|
import { DEFAULT_FACTORY_ID } from "../server/factory-graph/store.js";
|
|
9
9
|
import {
|
|
10
10
|
factoryIdSchema,
|
|
11
|
+
factoryStillPresent,
|
|
11
12
|
readTriageConfigRow,
|
|
13
|
+
requireExistingFactory,
|
|
12
14
|
} from "../server/lib/factory-scope.js";
|
|
13
15
|
import { requireFactoryAutomation } from "../server/lib/require-factory-automation.js";
|
|
14
16
|
import {
|
|
@@ -68,21 +70,34 @@ async function updateBabysitMetadata(
|
|
|
68
70
|
const db = getDb();
|
|
69
71
|
const item = (
|
|
70
72
|
await db
|
|
71
|
-
.select({
|
|
73
|
+
.select({
|
|
74
|
+
metadataJson: triageItems.metadataJson,
|
|
75
|
+
factoryId: triageItems.factoryId,
|
|
76
|
+
})
|
|
72
77
|
.from(triageItems)
|
|
73
78
|
.where(and(eq(triageItems.id, itemId), eq(triageItems.orgId, orgId)))
|
|
74
79
|
.limit(1)
|
|
75
80
|
)[0];
|
|
76
81
|
if (!item) throw new Error("Factory item disappeared during PR babysitting.");
|
|
82
|
+
const factoryId = item.factoryId ?? DEFAULT_FACTORY_ID;
|
|
77
83
|
const metadata = parseTriageMetadata(item.metadataJson);
|
|
78
84
|
Object.assign(metadata, patch);
|
|
79
|
-
await db
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
85
|
+
await db.transaction(async (tx) => {
|
|
86
|
+
await tx
|
|
87
|
+
.update(triageItems)
|
|
88
|
+
.set({
|
|
89
|
+
metadataJson: serializeTriageMetadata(metadata),
|
|
90
|
+
updatedAt: new Date().toISOString(),
|
|
91
|
+
})
|
|
92
|
+
.where(
|
|
93
|
+
and(
|
|
94
|
+
eq(triageItems.id, itemId),
|
|
95
|
+
eq(triageItems.orgId, orgId),
|
|
96
|
+
factoryStillPresent(tx as unknown as typeof db, orgId, factoryId),
|
|
97
|
+
),
|
|
98
|
+
);
|
|
99
|
+
await requireExistingFactory(tx as unknown as typeof db, orgId, factoryId);
|
|
100
|
+
});
|
|
86
101
|
}
|
|
87
102
|
|
|
88
103
|
export default defineAction({
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import { defineAction } from "@agent-native/core/action";
|
|
2
|
+
import { and, eq } from "drizzle-orm";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
|
|
5
|
+
import { getDb } from "../server/db/index.js";
|
|
6
|
+
import {
|
|
7
|
+
factoryAuditEvents,
|
|
8
|
+
factoryComments,
|
|
9
|
+
factoryDefinitions,
|
|
10
|
+
factoryGraphVersions,
|
|
11
|
+
triageConfig,
|
|
12
|
+
triageDecisions,
|
|
13
|
+
triageFeedback,
|
|
14
|
+
triageItems,
|
|
15
|
+
triageRules,
|
|
16
|
+
triageRuns,
|
|
17
|
+
} from "../server/db/schema.js";
|
|
18
|
+
import {
|
|
19
|
+
DEFAULT_FACTORY_ID,
|
|
20
|
+
readFactoryDefinition,
|
|
21
|
+
} from "../server/factory-graph/store.js";
|
|
22
|
+
import { resolveEnabledAutomationsFromSavedConfig } from "../server/lib/factory-automation-plan.js";
|
|
23
|
+
import {
|
|
24
|
+
factoryIdSchema,
|
|
25
|
+
readTriageConfigRow,
|
|
26
|
+
} from "../server/lib/factory-scope.js";
|
|
27
|
+
import {
|
|
28
|
+
requireWorkspaceMember,
|
|
29
|
+
workspaceMemberIdentityFromContext,
|
|
30
|
+
} from "../server/lib/require-workspace-member.js";
|
|
31
|
+
import {
|
|
32
|
+
ensureFactoryAutomations,
|
|
33
|
+
removeFactoryAutomationResources,
|
|
34
|
+
} from "../server/plugins/factory-scheduler-job.js";
|
|
35
|
+
|
|
36
|
+
export default defineAction({
|
|
37
|
+
description:
|
|
38
|
+
"Permanently delete a user-created Factory and all Factory-owned graph versions, comments, observations, rules, decisions, runs, feedback, audit events, settings, and scheduled automations. The default product-feedback Factory cannot be deleted. Requires the Factory's exact current name as confirmation; provider work already in progress is not cancelled. When the delete commits but the follow-up read cannot confirm the Factory is gone, the action returns ok with verified:false instead of reporting a failed deletion.",
|
|
39
|
+
schema: z.object({
|
|
40
|
+
factoryId: factoryIdSchema,
|
|
41
|
+
confirmName: z.string().trim().min(1).max(120),
|
|
42
|
+
}),
|
|
43
|
+
http: { method: "DELETE" },
|
|
44
|
+
needsApproval: true,
|
|
45
|
+
run: async ({ factoryId, confirmName }, context) => {
|
|
46
|
+
const { userEmail, orgId } = await requireWorkspaceMember(
|
|
47
|
+
workspaceMemberIdentityFromContext(context),
|
|
48
|
+
);
|
|
49
|
+
if (factoryId === DEFAULT_FACTORY_ID) {
|
|
50
|
+
throw new Error("The default Factory cannot be deleted.");
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const factory = await readFactoryDefinition(orgId, factoryId);
|
|
54
|
+
if (!factory) throw new Error("Factory not found.");
|
|
55
|
+
if (confirmName !== factory.name) {
|
|
56
|
+
throw new Error("Factory name confirmation does not match.");
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const config = await readTriageConfigRow(getDb(), orgId, factoryId);
|
|
60
|
+
const enabledNames = resolveEnabledAutomationsFromSavedConfig({
|
|
61
|
+
pollingEnabled: config?.pollingEnabled ?? 0,
|
|
62
|
+
githubPollingEnabled: config?.githubPollingEnabled ?? 0,
|
|
63
|
+
sentryPollingEnabled: config?.sentryPollingEnabled ?? 0,
|
|
64
|
+
slackChannelId: config?.slackChannelId,
|
|
65
|
+
repository: config?.repository,
|
|
66
|
+
sentryOrgSlug: config?.sentryOrgSlug,
|
|
67
|
+
sentryProjectSlug: config?.sentryProjectSlug,
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
const db = getDb();
|
|
71
|
+
try {
|
|
72
|
+
// Remove schedules before SQL so no new run can start; restore both if
|
|
73
|
+
// either step fails so a partial cleanup cannot disable a surviving Factory.
|
|
74
|
+
await removeFactoryAutomationResources(orgId, factoryId);
|
|
75
|
+
await db.transaction(async (tx) => {
|
|
76
|
+
const deleted = await tx
|
|
77
|
+
.delete(factoryDefinitions)
|
|
78
|
+
.where(
|
|
79
|
+
and(
|
|
80
|
+
eq(factoryDefinitions.id, factoryId),
|
|
81
|
+
eq(factoryDefinitions.orgId, orgId),
|
|
82
|
+
eq(factoryDefinitions.name, confirmName),
|
|
83
|
+
),
|
|
84
|
+
)
|
|
85
|
+
.returning({ id: factoryDefinitions.id });
|
|
86
|
+
if (deleted.length === 0) {
|
|
87
|
+
const existing = (
|
|
88
|
+
await tx
|
|
89
|
+
.select({ name: factoryDefinitions.name })
|
|
90
|
+
.from(factoryDefinitions)
|
|
91
|
+
.where(
|
|
92
|
+
and(
|
|
93
|
+
eq(factoryDefinitions.id, factoryId),
|
|
94
|
+
eq(factoryDefinitions.orgId, orgId),
|
|
95
|
+
),
|
|
96
|
+
)
|
|
97
|
+
.limit(1)
|
|
98
|
+
)[0];
|
|
99
|
+
if (existing) {
|
|
100
|
+
throw new Error(
|
|
101
|
+
"Factory changed before deletion. Confirm its current name and try again.",
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const scopedTables = [
|
|
107
|
+
factoryComments,
|
|
108
|
+
factoryGraphVersions,
|
|
109
|
+
factoryAuditEvents,
|
|
110
|
+
triageFeedback,
|
|
111
|
+
triageDecisions,
|
|
112
|
+
triageRuns,
|
|
113
|
+
triageRules,
|
|
114
|
+
triageItems,
|
|
115
|
+
triageConfig,
|
|
116
|
+
] as const;
|
|
117
|
+
for (const table of scopedTables) {
|
|
118
|
+
await tx
|
|
119
|
+
.delete(table)
|
|
120
|
+
.where(and(eq(table.orgId, orgId), eq(table.factoryId, factoryId)));
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
} catch (error) {
|
|
124
|
+
try {
|
|
125
|
+
await ensureFactoryAutomations(userEmail, orgId, factoryId, {
|
|
126
|
+
enabledNames,
|
|
127
|
+
});
|
|
128
|
+
} catch (repairError) {
|
|
129
|
+
throw new Error(
|
|
130
|
+
`Factory deletion failed and its automations could not be restored. Deletion error: ${
|
|
131
|
+
error instanceof Error ? error.message : String(error)
|
|
132
|
+
}. Restore error: ${
|
|
133
|
+
repairError instanceof Error
|
|
134
|
+
? repairError.message
|
|
135
|
+
: String(repairError)
|
|
136
|
+
}.`,
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
throw error;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
let remaining: Awaited<ReturnType<typeof readFactoryDefinition>>;
|
|
143
|
+
try {
|
|
144
|
+
remaining = await readFactoryDefinition(orgId, factoryId);
|
|
145
|
+
} catch (error) {
|
|
146
|
+
return {
|
|
147
|
+
ok: true,
|
|
148
|
+
factoryId,
|
|
149
|
+
name: factory.name,
|
|
150
|
+
verified: false,
|
|
151
|
+
verificationError:
|
|
152
|
+
error instanceof Error ? error.message : String(error),
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
if (remaining) {
|
|
156
|
+
try {
|
|
157
|
+
await ensureFactoryAutomations(userEmail, orgId, factoryId, {
|
|
158
|
+
enabledNames,
|
|
159
|
+
});
|
|
160
|
+
} catch (repairError) {
|
|
161
|
+
throw new Error(
|
|
162
|
+
`Factory still exists and its automations could not be restored. Restore error: ${
|
|
163
|
+
repairError instanceof Error
|
|
164
|
+
? repairError.message
|
|
165
|
+
: String(repairError)
|
|
166
|
+
}.`,
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
throw new Error("Factory deletion could not be verified.");
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return { ok: true, factoryId, name: factory.name, verified: true };
|
|
173
|
+
},
|
|
174
|
+
});
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
orgFactoryRunFilter,
|
|
17
17
|
orgFactoryScopedItemWhere,
|
|
18
18
|
readTriageConfigRow,
|
|
19
|
+
requireExistingFactory,
|
|
19
20
|
} from "../server/lib/factory-scope.js";
|
|
20
21
|
import { requireFactoryAutomation } from "../server/lib/require-factory-automation.js";
|
|
21
22
|
import {
|
|
@@ -343,28 +344,35 @@ export default defineAction({
|
|
|
343
344
|
itemId,
|
|
344
345
|
snapshot.headSha,
|
|
345
346
|
);
|
|
346
|
-
await getDb()
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
347
|
+
await getDb().transaction(async (tx) => {
|
|
348
|
+
await tx
|
|
349
|
+
.insert(triageDecisions)
|
|
350
|
+
.values({
|
|
351
|
+
id: decisionId,
|
|
352
|
+
itemId,
|
|
353
|
+
ruleId: null,
|
|
354
|
+
mode: "automation",
|
|
355
|
+
outcome: governance.autoMerge
|
|
356
|
+
? "auto_merge"
|
|
357
|
+
: governance.autoApprove
|
|
358
|
+
? "auto_approve"
|
|
359
|
+
: "needs_manual",
|
|
360
|
+
reason: `${reason} ${governance.reason}`.trim(),
|
|
361
|
+
guardResultsJson: JSON.stringify(governance.guardResults),
|
|
362
|
+
model: "factory-pr-governance",
|
|
363
|
+
promptVersion: 1,
|
|
364
|
+
createdAt: new Date().toISOString(),
|
|
365
|
+
ownerEmail: userEmail,
|
|
366
|
+
orgId,
|
|
367
|
+
factoryId,
|
|
368
|
+
})
|
|
369
|
+
.onConflictDoNothing();
|
|
370
|
+
await requireExistingFactory(
|
|
371
|
+
tx as unknown as ReturnType<typeof getDb>,
|
|
364
372
|
orgId,
|
|
365
373
|
factoryId,
|
|
366
|
-
|
|
367
|
-
|
|
374
|
+
);
|
|
375
|
+
});
|
|
368
376
|
}
|
|
369
377
|
|
|
370
378
|
if (!governance.autoApprove) {
|
|
@@ -8,6 +8,7 @@ import { repairFactoryAutomationsFromConfig } from "../server/lib/factory-automa
|
|
|
8
8
|
import {
|
|
9
9
|
factoryIdSchema,
|
|
10
10
|
readTriageConfigRow,
|
|
11
|
+
requireExistingFactory,
|
|
11
12
|
} from "../server/lib/factory-scope.js";
|
|
12
13
|
import { requireFactoryAutomation } from "../server/lib/require-factory-automation.js";
|
|
13
14
|
import {
|
|
@@ -239,6 +240,11 @@ export default defineAction({
|
|
|
239
240
|
});
|
|
240
241
|
pullRequestCount += 1;
|
|
241
242
|
}
|
|
243
|
+
await requireExistingFactory(
|
|
244
|
+
tx as unknown as ReturnType<typeof getDb>,
|
|
245
|
+
orgId,
|
|
246
|
+
factoryId,
|
|
247
|
+
);
|
|
242
248
|
});
|
|
243
249
|
|
|
244
250
|
if (issues.length === 0 && pullRequests.length === 0) {
|
|
@@ -7,7 +7,9 @@ import { triageConfig, triageItems } from "../server/db/schema.js";
|
|
|
7
7
|
import { repairFactoryAutomationsFromConfig } from "../server/lib/factory-automation-repair.js";
|
|
8
8
|
import {
|
|
9
9
|
factoryIdSchema,
|
|
10
|
+
factoryStillPresent,
|
|
10
11
|
readTriageConfigRow,
|
|
12
|
+
requireExistingFactory,
|
|
11
13
|
triageConfigUpdateRowId,
|
|
12
14
|
} from "../server/lib/factory-scope.js";
|
|
13
15
|
import { requireFactoryAutomation } from "../server/lib/require-factory-automation.js";
|
|
@@ -177,8 +179,21 @@ export default defineAction({
|
|
|
177
179
|
updatedAt: now,
|
|
178
180
|
})
|
|
179
181
|
.where(
|
|
180
|
-
and(
|
|
182
|
+
and(
|
|
183
|
+
eq(triageConfig.id, configRowId),
|
|
184
|
+
eq(triageConfig.orgId, orgId),
|
|
185
|
+
factoryStillPresent(
|
|
186
|
+
tx as unknown as ReturnType<typeof getDb>,
|
|
187
|
+
orgId,
|
|
188
|
+
factoryId,
|
|
189
|
+
),
|
|
190
|
+
),
|
|
181
191
|
);
|
|
192
|
+
await requireExistingFactory(
|
|
193
|
+
tx as unknown as ReturnType<typeof getDb>,
|
|
194
|
+
orgId,
|
|
195
|
+
factoryId,
|
|
196
|
+
);
|
|
182
197
|
});
|
|
183
198
|
|
|
184
199
|
if (observedIssues.length === 0) {
|
|
@@ -7,7 +7,9 @@ import { triageConfig, triageItems } from "../server/db/schema.js";
|
|
|
7
7
|
import { repairFactoryAutomationsFromConfig } from "../server/lib/factory-automation-repair.js";
|
|
8
8
|
import {
|
|
9
9
|
factoryIdSchema,
|
|
10
|
+
factoryStillPresent,
|
|
10
11
|
readTriageConfigRow,
|
|
12
|
+
requireExistingFactory,
|
|
11
13
|
triageConfigUpdateRowId,
|
|
12
14
|
} from "../server/lib/factory-scope.js";
|
|
13
15
|
import { requireFactoryAutomation } from "../server/lib/require-factory-automation.js";
|
|
@@ -159,9 +161,19 @@ export default defineAction({
|
|
|
159
161
|
and(
|
|
160
162
|
eq(triageConfig.id, configRowId),
|
|
161
163
|
eq(triageConfig.orgId, orgId),
|
|
164
|
+
factoryStillPresent(
|
|
165
|
+
tx as unknown as ReturnType<typeof getDb>,
|
|
166
|
+
orgId,
|
|
167
|
+
factoryId,
|
|
168
|
+
),
|
|
162
169
|
),
|
|
163
170
|
);
|
|
164
171
|
}
|
|
172
|
+
await requireExistingFactory(
|
|
173
|
+
tx as unknown as ReturnType<typeof getDb>,
|
|
174
|
+
orgId,
|
|
175
|
+
factoryId,
|
|
176
|
+
);
|
|
165
177
|
});
|
|
166
178
|
|
|
167
179
|
if (result.envelopes.length === 0) {
|
|
@@ -10,10 +10,12 @@ import {
|
|
|
10
10
|
} from "../server/db/schema.js";
|
|
11
11
|
import {
|
|
12
12
|
DEFAULT_FACTORY_ID,
|
|
13
|
+
factoryStillPresent,
|
|
13
14
|
orgFactoryItemFilter,
|
|
14
15
|
orgFactoryRunFilter,
|
|
16
|
+
readTriageConfigRow,
|
|
17
|
+
requireExistingFactory,
|
|
15
18
|
} from "../server/lib/factory-scope.js";
|
|
16
|
-
import { readTriageConfigRow } from "../server/lib/factory-scope.js";
|
|
17
19
|
import { requireFactoryAutomation } from "../server/lib/require-factory-automation.js";
|
|
18
20
|
import {
|
|
19
21
|
requireWorkspaceMember,
|
|
@@ -28,7 +30,10 @@ import {
|
|
|
28
30
|
serializeTriageMetadata,
|
|
29
31
|
} from "../server/triage/metadata.js";
|
|
30
32
|
import { detectOwnerOwnedArea } from "../server/triage/pr-policy.js";
|
|
31
|
-
import {
|
|
33
|
+
import {
|
|
34
|
+
createSlackReader,
|
|
35
|
+
isAgentNativeSlackUserName,
|
|
36
|
+
} from "../server/triage/slack-client.js";
|
|
32
37
|
|
|
33
38
|
/** Slack notifies only with `<@USERID>`. Plaintext @handles do not ping anyone. */
|
|
34
39
|
const REPLY_INSTRUCTION =
|
|
@@ -421,10 +426,23 @@ export default defineAction({
|
|
|
421
426
|
},
|
|
422
427
|
);
|
|
423
428
|
if (blocked) {
|
|
424
|
-
await db
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
429
|
+
await db.transaction(async (tx) => {
|
|
430
|
+
await tx
|
|
431
|
+
.update(triageItems)
|
|
432
|
+
.set({ status: "needs_manual", updatedAt: new Date().toISOString() })
|
|
433
|
+
.where(
|
|
434
|
+
and(
|
|
435
|
+
eq(triageItems.id, itemId),
|
|
436
|
+
eq(triageItems.orgId, orgId),
|
|
437
|
+
factoryStillPresent(tx as unknown as typeof db, orgId, factoryId),
|
|
438
|
+
),
|
|
439
|
+
);
|
|
440
|
+
await requireExistingFactory(
|
|
441
|
+
tx as unknown as typeof db,
|
|
442
|
+
orgId,
|
|
443
|
+
factoryId,
|
|
444
|
+
);
|
|
445
|
+
});
|
|
428
446
|
return {
|
|
429
447
|
ok: true,
|
|
430
448
|
started: false,
|
|
@@ -459,44 +477,57 @@ export default defineAction({
|
|
|
459
477
|
};
|
|
460
478
|
}
|
|
461
479
|
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
480
|
+
await db.transaction(async (tx) => {
|
|
481
|
+
if (retryableSlackRun) {
|
|
482
|
+
await tx
|
|
483
|
+
.update(triageRuns)
|
|
484
|
+
.set({
|
|
485
|
+
status: "submitted",
|
|
486
|
+
error: null,
|
|
487
|
+
completedAt: null,
|
|
488
|
+
heartbeatAt: now,
|
|
489
|
+
dispatchAttempts: (existing.dispatchAttempts ?? 0) + 1,
|
|
490
|
+
})
|
|
491
|
+
.where(
|
|
492
|
+
and(
|
|
493
|
+
eq(triageRuns.id, runId),
|
|
494
|
+
eq(triageRuns.orgId, orgId),
|
|
495
|
+
factoryStillPresent(tx as unknown as typeof db, orgId, factoryId),
|
|
496
|
+
),
|
|
497
|
+
);
|
|
498
|
+
} else {
|
|
499
|
+
await tx.insert(triageRuns).values({
|
|
500
|
+
id: runId,
|
|
501
|
+
itemId,
|
|
502
|
+
source: item.source,
|
|
503
|
+
provider: isSlack ? "bot-tag" : "builder-http",
|
|
504
|
+
dedupeKey,
|
|
505
|
+
approvalEmail: null,
|
|
466
506
|
status: "submitted",
|
|
467
|
-
|
|
468
|
-
|
|
507
|
+
progressLogJson: JSON.stringify([
|
|
508
|
+
{
|
|
509
|
+
at: now,
|
|
510
|
+
state: "submitted",
|
|
511
|
+
reason: `Factory automation ${context?.automation?.triggerName ?? "unknown"} recorded a clear bug.`,
|
|
512
|
+
},
|
|
513
|
+
]),
|
|
514
|
+
dispatchAttempts: 1,
|
|
515
|
+
needsContinuation: 0,
|
|
516
|
+
startedAt: now,
|
|
469
517
|
heartbeatAt: now,
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
dedupeKey,
|
|
480
|
-
approvalEmail: null,
|
|
481
|
-
status: "submitted",
|
|
482
|
-
progressLogJson: JSON.stringify([
|
|
483
|
-
{
|
|
484
|
-
at: now,
|
|
485
|
-
state: "submitted",
|
|
486
|
-
reason: `Factory automation ${context?.automation?.triggerName ?? "unknown"} recorded a clear bug.`,
|
|
487
|
-
},
|
|
488
|
-
]),
|
|
489
|
-
dispatchAttempts: 1,
|
|
490
|
-
needsContinuation: 0,
|
|
491
|
-
startedAt: now,
|
|
492
|
-
heartbeatAt: now,
|
|
493
|
-
completedAt: null,
|
|
494
|
-
error: null,
|
|
495
|
-
ownerEmail: item.ownerEmail,
|
|
518
|
+
completedAt: null,
|
|
519
|
+
error: null,
|
|
520
|
+
ownerEmail: item.ownerEmail,
|
|
521
|
+
orgId,
|
|
522
|
+
factoryId: item.factoryId ?? DEFAULT_FACTORY_ID,
|
|
523
|
+
});
|
|
524
|
+
}
|
|
525
|
+
await requireExistingFactory(
|
|
526
|
+
tx as unknown as typeof db,
|
|
496
527
|
orgId,
|
|
497
|
-
factoryId
|
|
498
|
-
|
|
499
|
-
}
|
|
528
|
+
factoryId,
|
|
529
|
+
);
|
|
530
|
+
});
|
|
500
531
|
|
|
501
532
|
try {
|
|
502
533
|
if (isSlack) {
|
|
@@ -603,7 +634,8 @@ export default defineAction({
|
|
|
603
634
|
const hasAgentNativeDisposition = feedbackThread.messages.some(
|
|
604
635
|
(message) =>
|
|
605
636
|
(message.user === agentNative.userId ||
|
|
606
|
-
message.username
|
|
637
|
+
(message.username != null &&
|
|
638
|
+
isAgentNativeSlackUserName(message.username))) &&
|
|
607
639
|
/^(Fixed|In progress|Clarification needed):/i.test(
|
|
608
640
|
message.text.trim(),
|
|
609
641
|
),
|