@app-vitals/agent-admin 0.13.0 → 0.13.2
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/e2e/test-server.ts +5 -5
- package/openapi.json +12 -19
- package/openapi.platform.json +11 -18
- package/package.json +2 -2
- package/prisma/client/internal/class.ts +4 -4
- package/prisma/client/internal/prismaNamespace.ts +0 -1
- package/prisma/client/internal/prismaNamespaceBrowser.ts +0 -1
- package/prisma/client/models/Agent.ts +62 -137
- package/prisma/migrations/20261030000000_drop_agent_type_name/migration.sql +8 -0
- package/prisma/schema/schema.prisma +3 -4
- package/src/account-lifecycle.integration.test.ts +1 -1
- package/src/account-trial-warning-sweeper.integration.test.ts +1 -1
- package/src/admin-local-agent.smoke.test.ts +12 -12
- package/src/admin-ui-pages.ts +2 -2
- package/src/admin-ui-pages.unit.test.ts +2 -2
- package/src/admin-ui.fixtures.ts +6 -6
- package/src/admin-ui.smoke.test.ts +39 -39
- package/src/admin-ui.ts +8 -8
- package/src/agent-cron-jobs.integration.test.ts +8 -7
- package/src/agent-cron-jobs.ts +4 -5
- package/src/agent-cron-jobs.unit.test.ts +23 -23
- package/src/agent-patch-author-allowlist.integration.test.ts +4 -4
- package/src/agent-specialty-backfill.integration.test.ts +98 -53
- package/src/agents-api.integration.test.ts +20 -20
- package/src/agents-api.smoke.test.ts +76 -77
- package/src/agents-api.ts +9 -14
- package/src/agents.integration.test.ts +40 -53
- package/src/agents.ts +33 -46
- package/src/agents.unit.test.ts +28 -35
- package/src/api.smoke.test.ts +24 -2
- package/src/api.ts +15 -16
- package/src/openapi-schemas.ts +14 -7
- package/src/slack-provisioning-service.integration.test.ts +2 -2
- package/src/slack-provisioning.integration.test.ts +2 -2
- package/src/specialty-manifest-loader.ts +32 -32
- package/src/specialty-manifest-loader.unit.test.ts +8 -8
- package/src/startup-policy-reconcile.unit.test.ts +1 -1
- package/src/trial-expiry-sweeper.integration.test.ts +1 -1
- package/src/trial-expiry-warning-sweeper.integration.test.ts +1 -1
- package/src/agent-specialty.ts +0 -22
- package/src/agent-specialty.unit.test.ts +0 -43
|
@@ -28,7 +28,7 @@ import { identityCrypto } from "./token-crypto.ts";
|
|
|
28
28
|
// ─── Fake SpecialtyManifestResolver ────────────────────────────────────────
|
|
29
29
|
//
|
|
30
30
|
// Mirrors the shape used by agent-cron-jobs.unit.test.ts's fakeRegistry —
|
|
31
|
-
// resolves a fixed set of manifests by
|
|
31
|
+
// resolves a fixed set of manifests by specialty, with tryGetManifest()
|
|
32
32
|
// returning undefined (no fallback) for anything not in the map.
|
|
33
33
|
|
|
34
34
|
const CODING_MANIFEST: SpecialtyManifest = {
|
|
@@ -72,11 +72,11 @@ function fakeSpecialtyRegistry(
|
|
|
72
72
|
},
|
|
73
73
|
): AdminDeps["specialtyRegistry"] {
|
|
74
74
|
return {
|
|
75
|
-
getManifest(
|
|
76
|
-
return byType[
|
|
75
|
+
getManifest(specialty: string) {
|
|
76
|
+
return byType[specialty] ?? (byType.coding as SpecialtyManifest);
|
|
77
77
|
},
|
|
78
|
-
tryGetManifest(
|
|
79
|
-
return byType[
|
|
78
|
+
tryGetManifest(specialty: string) {
|
|
79
|
+
return byType[specialty];
|
|
80
80
|
},
|
|
81
81
|
listTypes() {
|
|
82
82
|
return Object.entries(byType).map(([name, manifest]) => ({
|
|
@@ -240,7 +240,7 @@ function makeMockDeps(): AdminDeps {
|
|
|
240
240
|
reviewAuthorAllowlist: [],
|
|
241
241
|
patchAuthorAllowlist: [],
|
|
242
242
|
restrictSlackToMembers: input.restrictSlackToMembers ?? false,
|
|
243
|
-
|
|
243
|
+
specialty: "coding",
|
|
244
244
|
createdAt: new Date("2024-01-01"),
|
|
245
245
|
updatedAt: new Date("2024-01-01"),
|
|
246
246
|
missingRequiredEnv: [],
|
|
@@ -251,13 +251,13 @@ function makeMockDeps(): AdminDeps {
|
|
|
251
251
|
id: AGENT_ID,
|
|
252
252
|
name: "Existing Agent",
|
|
253
253
|
selfHosted: false,
|
|
254
|
-
|
|
254
|
+
specialty: "coding",
|
|
255
255
|
},
|
|
256
256
|
{
|
|
257
257
|
id: "agent-other-id",
|
|
258
258
|
name: "Other Agent",
|
|
259
259
|
selfHosted: false,
|
|
260
|
-
|
|
260
|
+
specialty: "coding",
|
|
261
261
|
},
|
|
262
262
|
],
|
|
263
263
|
getSummary: async (id: string) =>
|
|
@@ -266,7 +266,7 @@ function makeMockDeps(): AdminDeps {
|
|
|
266
266
|
id: AGENT_ID,
|
|
267
267
|
name: "Existing Agent",
|
|
268
268
|
selfHosted: false,
|
|
269
|
-
|
|
269
|
+
specialty: "coding",
|
|
270
270
|
}
|
|
271
271
|
: null,
|
|
272
272
|
getDetail: async (id: string) =>
|
|
@@ -280,7 +280,7 @@ function makeMockDeps(): AdminDeps {
|
|
|
280
280
|
reviewAuthorAllowlist: [],
|
|
281
281
|
patchAuthorAllowlist: [],
|
|
282
282
|
restrictSlackToMembers: false,
|
|
283
|
-
|
|
283
|
+
specialty: "coding",
|
|
284
284
|
createdAt: new Date("2024-01-01"),
|
|
285
285
|
updatedAt: new Date("2024-01-01"),
|
|
286
286
|
missingRequiredEnv: [],
|
|
@@ -312,7 +312,7 @@ function makeMockDeps(): AdminDeps {
|
|
|
312
312
|
reviewAuthorAllowlist: [],
|
|
313
313
|
patchAuthorAllowlist: [],
|
|
314
314
|
restrictSlackToMembers: input.restrictSlackToMembers ?? false,
|
|
315
|
-
|
|
315
|
+
specialty: "coding",
|
|
316
316
|
createdAt: new Date("2024-01-01"),
|
|
317
317
|
updatedAt: new Date("2024-01-01"),
|
|
318
318
|
missingRequiredEnv: [],
|
|
@@ -343,7 +343,7 @@ function makeMockDeps(): AdminDeps {
|
|
|
343
343
|
reviewAuthorAllowlist: input.reviewAuthorAllowlist ?? [],
|
|
344
344
|
patchAuthorAllowlist: input.patchAuthorAllowlist ?? [],
|
|
345
345
|
restrictSlackToMembers: input.restrictSlackToMembers ?? false,
|
|
346
|
-
|
|
346
|
+
specialty: "coding",
|
|
347
347
|
createdAt: new Date("2024-01-01"),
|
|
348
348
|
updatedAt: new Date("2024-01-01"),
|
|
349
349
|
missingRequiredEnv: [],
|
|
@@ -1651,7 +1651,7 @@ describe("admin API — POST /agents", () => {
|
|
|
1651
1651
|
const app = createAdminApp(deps);
|
|
1652
1652
|
const res = await app.request("/agents", {
|
|
1653
1653
|
method: "POST",
|
|
1654
|
-
body: JSON.stringify({ name: "New Agent",
|
|
1654
|
+
body: JSON.stringify({ name: "New Agent", specialty: "coding" }),
|
|
1655
1655
|
headers: {
|
|
1656
1656
|
"Content-Type": "application/json",
|
|
1657
1657
|
Authorization: `Bearer ${ADMIN_API_KEY}`,
|
|
@@ -1669,7 +1669,7 @@ describe("admin API — POST /agents", () => {
|
|
|
1669
1669
|
reviewAuthorAllowlist: [],
|
|
1670
1670
|
patchAuthorAllowlist: [],
|
|
1671
1671
|
restrictSlackToMembers: false,
|
|
1672
|
-
|
|
1672
|
+
specialty: "coding",
|
|
1673
1673
|
missingRequiredEnv: [],
|
|
1674
1674
|
});
|
|
1675
1675
|
expect(typeof body.createdAt).toBe("string");
|
|
@@ -1680,7 +1680,7 @@ describe("admin API — POST /agents", () => {
|
|
|
1680
1680
|
const app = createAdminApp(makeMockDeps());
|
|
1681
1681
|
const res = await app.request("/agents", {
|
|
1682
1682
|
method: "POST",
|
|
1683
|
-
body: JSON.stringify({ name: "Cookie Agent",
|
|
1683
|
+
body: JSON.stringify({ name: "Cookie Agent", specialty: "coding" }),
|
|
1684
1684
|
headers: {
|
|
1685
1685
|
"Content-Type": "application/json",
|
|
1686
1686
|
Cookie: `admin_session=${cookie}`,
|
|
@@ -1717,7 +1717,7 @@ describe("admin API — POST /agents", () => {
|
|
|
1717
1717
|
const app = createAdminApp(deps);
|
|
1718
1718
|
const res = await app.request("/agents", {
|
|
1719
1719
|
method: "POST",
|
|
1720
|
-
body: JSON.stringify({ name: "Owned Agent",
|
|
1720
|
+
body: JSON.stringify({ name: "Owned Agent", specialty: "coding" }),
|
|
1721
1721
|
headers: {
|
|
1722
1722
|
"Content-Type": "application/json",
|
|
1723
1723
|
Cookie: `admin_session=${cookie}`,
|
|
@@ -1735,7 +1735,7 @@ describe("admin API — POST /agents", () => {
|
|
|
1735
1735
|
method: "POST",
|
|
1736
1736
|
body: JSON.stringify({
|
|
1737
1737
|
name: "Spoof Agent",
|
|
1738
|
-
|
|
1738
|
+
specialty: "coding",
|
|
1739
1739
|
ownerEmail: "attacker@evil.example",
|
|
1740
1740
|
}),
|
|
1741
1741
|
headers: {
|
|
@@ -1755,7 +1755,7 @@ describe("admin API — POST /agents", () => {
|
|
|
1755
1755
|
method: "POST",
|
|
1756
1756
|
body: JSON.stringify({
|
|
1757
1757
|
name: "Key Agent",
|
|
1758
|
-
|
|
1758
|
+
specialty: "coding",
|
|
1759
1759
|
ownerEmail: "attacker@evil.example",
|
|
1760
1760
|
}),
|
|
1761
1761
|
headers: {
|
|
@@ -1775,7 +1775,7 @@ describe("admin API — POST /agents", () => {
|
|
|
1775
1775
|
const app = createAdminApp(deps);
|
|
1776
1776
|
const res = await app.request("/agents", {
|
|
1777
1777
|
method: "POST",
|
|
1778
|
-
body: JSON.stringify({ name: "Ops Agent",
|
|
1778
|
+
body: JSON.stringify({ name: "Ops Agent", specialty: "coding" }),
|
|
1779
1779
|
headers: {
|
|
1780
1780
|
"Content-Type": "application/json",
|
|
1781
1781
|
Authorization: `Bearer ${ADMIN_API_KEY}`,
|
|
@@ -1791,7 +1791,7 @@ describe("admin API — POST /agents", () => {
|
|
|
1791
1791
|
method: "POST",
|
|
1792
1792
|
body: JSON.stringify({
|
|
1793
1793
|
name: "Collider",
|
|
1794
|
-
|
|
1794
|
+
specialty: "coding",
|
|
1795
1795
|
reposRaw: "acme/api\nglobex/api",
|
|
1796
1796
|
}),
|
|
1797
1797
|
headers: {
|
|
@@ -1809,7 +1809,7 @@ describe("admin API — POST /agents", () => {
|
|
|
1809
1809
|
const app = createAdminApp(makeMockDeps());
|
|
1810
1810
|
const res = await app.request("/agents", {
|
|
1811
1811
|
method: "POST",
|
|
1812
|
-
body: JSON.stringify({ name: "New Agent",
|
|
1812
|
+
body: JSON.stringify({ name: "New Agent", specialty: "coding" }),
|
|
1813
1813
|
headers: { "Content-Type": "application/json" },
|
|
1814
1814
|
});
|
|
1815
1815
|
expect(res.status).toBe(401);
|
|
@@ -1832,7 +1832,7 @@ describe("admin API — POST /agents", () => {
|
|
|
1832
1832
|
const app = createAdminApp(deps);
|
|
1833
1833
|
const res = await app.request("/agents", {
|
|
1834
1834
|
method: "POST",
|
|
1835
|
-
body: JSON.stringify({ name: "New Agent",
|
|
1835
|
+
body: JSON.stringify({ name: "New Agent", specialty: "coding" }),
|
|
1836
1836
|
headers: {
|
|
1837
1837
|
"Content-Type": "application/json",
|
|
1838
1838
|
Authorization: "Bearer not-a-real-key",
|
|
@@ -1853,7 +1853,7 @@ describe("admin API — POST /agents", () => {
|
|
|
1853
1853
|
const app = createAdminApp(deps);
|
|
1854
1854
|
const res = await app.request("/agents", {
|
|
1855
1855
|
method: "POST",
|
|
1856
|
-
body: JSON.stringify({ name: "New Agent",
|
|
1856
|
+
body: JSON.stringify({ name: "New Agent", specialty: "coding" }),
|
|
1857
1857
|
headers: {
|
|
1858
1858
|
"Content-Type": "application/json",
|
|
1859
1859
|
Authorization: "Bearer per-agent-token",
|
|
@@ -1867,7 +1867,7 @@ describe("admin API — POST /agents", () => {
|
|
|
1867
1867
|
const app = createAdminApp(deps);
|
|
1868
1868
|
const res = await app.request("/agents", {
|
|
1869
1869
|
method: "POST",
|
|
1870
|
-
body: JSON.stringify({
|
|
1870
|
+
body: JSON.stringify({ specialty: "coding" }),
|
|
1871
1871
|
headers: {
|
|
1872
1872
|
"Content-Type": "application/json",
|
|
1873
1873
|
Authorization: `Bearer ${ADMIN_API_KEY}`,
|
|
@@ -1878,12 +1878,12 @@ describe("admin API — POST /agents", () => {
|
|
|
1878
1878
|
expect(createCalls()).toBe(0);
|
|
1879
1879
|
});
|
|
1880
1880
|
|
|
1881
|
-
it("unresolvable
|
|
1881
|
+
it("unresolvable specialty → 4xx and no Agent row created", async () => {
|
|
1882
1882
|
const { deps, createCalls } = makeMockDepsCountingCreateCalls();
|
|
1883
1883
|
const app = createAdminApp(deps);
|
|
1884
1884
|
const res = await app.request("/agents", {
|
|
1885
1885
|
method: "POST",
|
|
1886
|
-
body: JSON.stringify({ name: "New Agent",
|
|
1886
|
+
body: JSON.stringify({ name: "New Agent", specialty: "no-such-type" }),
|
|
1887
1887
|
headers: {
|
|
1888
1888
|
"Content-Type": "application/json",
|
|
1889
1889
|
Authorization: `Bearer ${ADMIN_API_KEY}`,
|
|
@@ -1997,7 +1997,7 @@ describe("admin API — delete agent", () => {
|
|
|
1997
1997
|
reviewAuthorAllowlist: [],
|
|
1998
1998
|
patchAuthorAllowlist: [],
|
|
1999
1999
|
restrictSlackToMembers: false,
|
|
2000
|
-
|
|
2000
|
+
specialty: "coding",
|
|
2001
2001
|
createdAt: new Date("2024-01-01"),
|
|
2002
2002
|
updatedAt: new Date("2024-01-01"),
|
|
2003
2003
|
missingRequiredEnv: [],
|
|
@@ -2262,7 +2262,7 @@ describe("admin API — POST /agents/reconcile", () => {
|
|
|
2262
2262
|
id: AGENT_ID,
|
|
2263
2263
|
name: "Regular Agent",
|
|
2264
2264
|
selfHosted: false,
|
|
2265
|
-
|
|
2265
|
+
specialty: "coding",
|
|
2266
2266
|
ownerEmail: "jane.doe@example.com",
|
|
2267
2267
|
anthropicIdentityName: null,
|
|
2268
2268
|
anthropicServiceAccountId: null,
|
|
@@ -2348,7 +2348,6 @@ describe("admin API — POST /agents/reconcile", () => {
|
|
|
2348
2348
|
id: AGENT_ID,
|
|
2349
2349
|
name: "Regular Agent",
|
|
2350
2350
|
selfHosted: false,
|
|
2351
|
-
typeName: "coding",
|
|
2352
2351
|
specialty: "coding",
|
|
2353
2352
|
});
|
|
2354
2353
|
});
|
|
@@ -2378,7 +2377,7 @@ function makeStripDeps(): {
|
|
|
2378
2377
|
id,
|
|
2379
2378
|
name: id,
|
|
2380
2379
|
selfHosted,
|
|
2381
|
-
|
|
2380
|
+
specialty: "coding",
|
|
2382
2381
|
});
|
|
2383
2382
|
const deps: AdminDeps = {
|
|
2384
2383
|
...base,
|
|
@@ -2688,7 +2687,7 @@ describe("admin API — provision agent", () => {
|
|
|
2688
2687
|
id: AGENT_ID,
|
|
2689
2688
|
name: "Self-Hosted Agent",
|
|
2690
2689
|
selfHosted: true,
|
|
2691
|
-
|
|
2690
|
+
specialty: "coding",
|
|
2692
2691
|
}
|
|
2693
2692
|
: null,
|
|
2694
2693
|
},
|
|
@@ -2725,13 +2724,13 @@ describe("admin API — selfHosted field", () => {
|
|
|
2725
2724
|
id: AGENT_ID,
|
|
2726
2725
|
name: "Existing Agent",
|
|
2727
2726
|
selfHosted: false,
|
|
2728
|
-
|
|
2727
|
+
specialty: "coding",
|
|
2729
2728
|
},
|
|
2730
2729
|
{
|
|
2731
2730
|
id: "agent-other-id",
|
|
2732
2731
|
name: "Other Agent",
|
|
2733
2732
|
selfHosted: true,
|
|
2734
|
-
|
|
2733
|
+
specialty: "coding",
|
|
2735
2734
|
},
|
|
2736
2735
|
],
|
|
2737
2736
|
},
|
|
@@ -2863,13 +2862,13 @@ describe("admin API — selfHosted field", () => {
|
|
|
2863
2862
|
id: AGENT_ID,
|
|
2864
2863
|
name: "Regular Agent",
|
|
2865
2864
|
selfHosted: false,
|
|
2866
|
-
|
|
2865
|
+
specialty: "coding",
|
|
2867
2866
|
},
|
|
2868
2867
|
{
|
|
2869
2868
|
id: "self-hosted-id",
|
|
2870
2869
|
name: "Self-Hosted Agent",
|
|
2871
2870
|
selfHosted: true,
|
|
2872
|
-
|
|
2871
|
+
specialty: "coding",
|
|
2873
2872
|
},
|
|
2874
2873
|
],
|
|
2875
2874
|
},
|
|
@@ -3087,7 +3086,7 @@ describe("admin API — owner and Anthropic identity fields (PAI-2.5)", () => {
|
|
|
3087
3086
|
reviewAuthorAllowlist: [],
|
|
3088
3087
|
patchAuthorAllowlist: [],
|
|
3089
3088
|
restrictSlackToMembers: false,
|
|
3090
|
-
|
|
3089
|
+
specialty: "coding",
|
|
3091
3090
|
createdAt: new Date("2024-01-01"),
|
|
3092
3091
|
updatedAt: new Date("2024-01-01"),
|
|
3093
3092
|
missingRequiredEnv: [],
|
|
@@ -3149,7 +3148,7 @@ describe("admin API — owner and Anthropic identity fields (PAI-2.5)", () => {
|
|
|
3149
3148
|
id: AGENT_ID,
|
|
3150
3149
|
name: "Existing Agent",
|
|
3151
3150
|
selfHosted: false,
|
|
3152
|
-
|
|
3151
|
+
specialty: "coding",
|
|
3153
3152
|
ownerEmail: "jane.doe@example.com",
|
|
3154
3153
|
anthropicIdentityName: "shipwright-existing-agent",
|
|
3155
3154
|
anthropicServiceAccountId: "svac_01ABC",
|
|
@@ -3169,16 +3168,16 @@ describe("admin API — owner and Anthropic identity fields (PAI-2.5)", () => {
|
|
|
3169
3168
|
});
|
|
3170
3169
|
});
|
|
3171
3170
|
|
|
3172
|
-
// ───
|
|
3171
|
+
// ─── specialty field smoke tests ───────────────────────────────────────────────
|
|
3173
3172
|
|
|
3174
|
-
describe("admin API —
|
|
3173
|
+
describe("admin API — specialty field", () => {
|
|
3175
3174
|
let cookie: string;
|
|
3176
3175
|
|
|
3177
3176
|
beforeAll(async () => {
|
|
3178
3177
|
cookie = await makeSessionCookie();
|
|
3179
3178
|
});
|
|
3180
3179
|
|
|
3181
|
-
it("GET /agents includes
|
|
3180
|
+
it("GET /agents includes specialty in each list entry", async () => {
|
|
3182
3181
|
const app = createAdminApp(makeMockDeps());
|
|
3183
3182
|
const res = await app.request("/agents", {
|
|
3184
3183
|
headers: { Cookie: `admin_session=${cookie}` },
|
|
@@ -3186,17 +3185,17 @@ describe("admin API — typeName field", () => {
|
|
|
3186
3185
|
expect(res.status).toBe(200);
|
|
3187
3186
|
const body = await res.json();
|
|
3188
3187
|
expect(Array.isArray(body)).toBe(true);
|
|
3189
|
-
expect(body[0].
|
|
3188
|
+
expect(body[0].specialty).toBe("coding");
|
|
3190
3189
|
});
|
|
3191
3190
|
|
|
3192
|
-
it("GET /agents/:id includes
|
|
3191
|
+
it("GET /agents/:id includes specialty in the full record", async () => {
|
|
3193
3192
|
const app = createAdminApp(makeMockDeps());
|
|
3194
3193
|
const res = await app.request(`/agents/${AGENT_ID}`, {
|
|
3195
3194
|
headers: { Cookie: `admin_session=${cookie}` },
|
|
3196
3195
|
});
|
|
3197
3196
|
expect(res.status).toBe(200);
|
|
3198
3197
|
const body = await res.json();
|
|
3199
|
-
expect(body.
|
|
3198
|
+
expect(body.specialty).toBe("coding");
|
|
3200
3199
|
});
|
|
3201
3200
|
|
|
3202
3201
|
it.each([
|
|
@@ -3260,7 +3259,7 @@ describe("admin API — missingRequiredEnv field", () => {
|
|
|
3260
3259
|
reviewAuthorAllowlist: [],
|
|
3261
3260
|
patchAuthorAllowlist: [],
|
|
3262
3261
|
restrictSlackToMembers: false,
|
|
3263
|
-
|
|
3262
|
+
specialty: "coding",
|
|
3264
3263
|
createdAt: new Date("2024-01-01"),
|
|
3265
3264
|
updatedAt: new Date("2024-01-01"),
|
|
3266
3265
|
missingRequiredEnv: ["CLAUDE_CODE_OAUTH_TOKEN"],
|
|
@@ -3331,7 +3330,7 @@ describe("admin API — repos field", () => {
|
|
|
3331
3330
|
reviewAuthorAllowlist: [],
|
|
3332
3331
|
patchAuthorAllowlist: [],
|
|
3333
3332
|
restrictSlackToMembers: false,
|
|
3334
|
-
|
|
3333
|
+
specialty: "coding",
|
|
3335
3334
|
createdAt: new Date("2024-01-01"),
|
|
3336
3335
|
updatedAt: new Date("2024-01-01"),
|
|
3337
3336
|
missingRequiredEnv: [],
|
|
@@ -3349,7 +3348,7 @@ describe("admin API — repos field", () => {
|
|
|
3349
3348
|
reviewAuthorAllowlist: [],
|
|
3350
3349
|
patchAuthorAllowlist: [],
|
|
3351
3350
|
restrictSlackToMembers: false,
|
|
3352
|
-
|
|
3351
|
+
specialty: "coding",
|
|
3353
3352
|
createdAt: new Date("2024-01-01"),
|
|
3354
3353
|
updatedAt: new Date("2024-01-01"),
|
|
3355
3354
|
missingRequiredEnv: [],
|
|
@@ -3387,7 +3386,7 @@ describe("admin API — repos field", () => {
|
|
|
3387
3386
|
reviewAuthorAllowlist: [],
|
|
3388
3387
|
patchAuthorAllowlist: [],
|
|
3389
3388
|
restrictSlackToMembers: false,
|
|
3390
|
-
|
|
3389
|
+
specialty: "coding",
|
|
3391
3390
|
createdAt: new Date("2024-01-01"),
|
|
3392
3391
|
updatedAt: new Date("2024-01-01"),
|
|
3393
3392
|
missingRequiredEnv: [],
|
|
@@ -3405,7 +3404,7 @@ describe("admin API — repos field", () => {
|
|
|
3405
3404
|
reviewAuthorAllowlist: [],
|
|
3406
3405
|
patchAuthorAllowlist: [],
|
|
3407
3406
|
restrictSlackToMembers: false,
|
|
3408
|
-
|
|
3407
|
+
specialty: "coding",
|
|
3409
3408
|
createdAt: new Date("2024-01-01"),
|
|
3410
3409
|
updatedAt: new Date("2024-01-01"),
|
|
3411
3410
|
missingRequiredEnv: [],
|
|
@@ -3481,7 +3480,7 @@ describe("admin API — reviewAuthorAllowlist field", () => {
|
|
|
3481
3480
|
reviewAuthorAllowlist: [],
|
|
3482
3481
|
patchAuthorAllowlist: [],
|
|
3483
3482
|
restrictSlackToMembers: false,
|
|
3484
|
-
|
|
3483
|
+
specialty: "coding",
|
|
3485
3484
|
createdAt: new Date("2024-01-01"),
|
|
3486
3485
|
updatedAt: new Date("2024-01-01"),
|
|
3487
3486
|
missingRequiredEnv: [],
|
|
@@ -3503,7 +3502,7 @@ describe("admin API — reviewAuthorAllowlist field", () => {
|
|
|
3503
3502
|
reviewAuthorAllowlist: input.reviewAuthorAllowlist ?? [],
|
|
3504
3503
|
patchAuthorAllowlist: [],
|
|
3505
3504
|
restrictSlackToMembers: false,
|
|
3506
|
-
|
|
3505
|
+
specialty: "coding",
|
|
3507
3506
|
createdAt: new Date("2024-01-01"),
|
|
3508
3507
|
updatedAt: new Date("2024-01-01"),
|
|
3509
3508
|
missingRequiredEnv: [],
|
|
@@ -3541,7 +3540,7 @@ describe("admin API — reviewAuthorAllowlist field", () => {
|
|
|
3541
3540
|
reviewAuthorAllowlist: ["octocat"],
|
|
3542
3541
|
patchAuthorAllowlist: [],
|
|
3543
3542
|
restrictSlackToMembers: false,
|
|
3544
|
-
|
|
3543
|
+
specialty: "coding",
|
|
3545
3544
|
createdAt: new Date("2024-01-01"),
|
|
3546
3545
|
updatedAt: new Date("2024-01-01"),
|
|
3547
3546
|
missingRequiredEnv: [],
|
|
@@ -3563,7 +3562,7 @@ describe("admin API — reviewAuthorAllowlist field", () => {
|
|
|
3563
3562
|
reviewAuthorAllowlist: input.reviewAuthorAllowlist ?? [],
|
|
3564
3563
|
patchAuthorAllowlist: [],
|
|
3565
3564
|
restrictSlackToMembers: false,
|
|
3566
|
-
|
|
3565
|
+
specialty: "coding",
|
|
3567
3566
|
createdAt: new Date("2024-01-01"),
|
|
3568
3567
|
updatedAt: new Date("2024-01-01"),
|
|
3569
3568
|
missingRequiredEnv: [],
|
|
@@ -3624,7 +3623,7 @@ describe("admin API — reviewAuthorAllowlist field", () => {
|
|
|
3624
3623
|
reviewAuthorAllowlist: [],
|
|
3625
3624
|
patchAuthorAllowlist: [],
|
|
3626
3625
|
restrictSlackToMembers: false,
|
|
3627
|
-
|
|
3626
|
+
specialty: "coding",
|
|
3628
3627
|
createdAt: new Date("2024-01-01"),
|
|
3629
3628
|
updatedAt: new Date("2024-01-01"),
|
|
3630
3629
|
missingRequiredEnv: [],
|
|
@@ -3642,7 +3641,7 @@ describe("admin API — reviewAuthorAllowlist field", () => {
|
|
|
3642
3641
|
reviewAuthorAllowlist: input.reviewAuthorAllowlist ?? [],
|
|
3643
3642
|
patchAuthorAllowlist: [],
|
|
3644
3643
|
restrictSlackToMembers: false,
|
|
3645
|
-
|
|
3644
|
+
specialty: "coding",
|
|
3646
3645
|
createdAt: new Date("2024-01-01"),
|
|
3647
3646
|
updatedAt: new Date("2024-01-01"),
|
|
3648
3647
|
missingRequiredEnv: [],
|
|
@@ -3712,7 +3711,7 @@ describe("admin API — patchAuthorAllowlist field", () => {
|
|
|
3712
3711
|
reviewAuthorAllowlist: [],
|
|
3713
3712
|
patchAuthorAllowlist: [],
|
|
3714
3713
|
restrictSlackToMembers: false,
|
|
3715
|
-
|
|
3714
|
+
specialty: "coding",
|
|
3716
3715
|
createdAt: new Date("2024-01-01"),
|
|
3717
3716
|
updatedAt: new Date("2024-01-01"),
|
|
3718
3717
|
missingRequiredEnv: [],
|
|
@@ -3734,7 +3733,7 @@ describe("admin API — patchAuthorAllowlist field", () => {
|
|
|
3734
3733
|
reviewAuthorAllowlist: [],
|
|
3735
3734
|
patchAuthorAllowlist: input.patchAuthorAllowlist ?? [],
|
|
3736
3735
|
restrictSlackToMembers: false,
|
|
3737
|
-
|
|
3736
|
+
specialty: "coding",
|
|
3738
3737
|
createdAt: new Date("2024-01-01"),
|
|
3739
3738
|
updatedAt: new Date("2024-01-01"),
|
|
3740
3739
|
missingRequiredEnv: [],
|
|
@@ -3801,7 +3800,7 @@ describe("admin API — trialExpiresAt field", () => {
|
|
|
3801
3800
|
reviewAuthorAllowlist: [],
|
|
3802
3801
|
patchAuthorAllowlist: [],
|
|
3803
3802
|
restrictSlackToMembers: false,
|
|
3804
|
-
|
|
3803
|
+
specialty: "coding",
|
|
3805
3804
|
createdAt: new Date("2024-01-01"),
|
|
3806
3805
|
updatedAt: new Date("2024-01-01"),
|
|
3807
3806
|
missingRequiredEnv: [],
|
|
@@ -3825,7 +3824,7 @@ describe("admin API — trialExpiresAt field", () => {
|
|
|
3825
3824
|
reviewAuthorAllowlist: [],
|
|
3826
3825
|
patchAuthorAllowlist: [],
|
|
3827
3826
|
restrictSlackToMembers: false,
|
|
3828
|
-
|
|
3827
|
+
specialty: "coding",
|
|
3829
3828
|
createdAt: new Date("2024-01-01"),
|
|
3830
3829
|
updatedAt: new Date("2024-01-01"),
|
|
3831
3830
|
missingRequiredEnv: [],
|
|
@@ -3875,7 +3874,7 @@ describe("admin API — trialExpiresAt field", () => {
|
|
|
3875
3874
|
reviewAuthorAllowlist: [],
|
|
3876
3875
|
patchAuthorAllowlist: [],
|
|
3877
3876
|
restrictSlackToMembers: false,
|
|
3878
|
-
|
|
3877
|
+
specialty: "coding",
|
|
3879
3878
|
createdAt: new Date("2024-01-01"),
|
|
3880
3879
|
updatedAt: new Date("2024-01-01"),
|
|
3881
3880
|
missingRequiredEnv: [],
|
|
@@ -3899,7 +3898,7 @@ describe("admin API — trialExpiresAt field", () => {
|
|
|
3899
3898
|
reviewAuthorAllowlist: [],
|
|
3900
3899
|
patchAuthorAllowlist: [],
|
|
3901
3900
|
restrictSlackToMembers: false,
|
|
3902
|
-
|
|
3901
|
+
specialty: "coding",
|
|
3903
3902
|
createdAt: new Date("2024-01-01"),
|
|
3904
3903
|
updatedAt: new Date("2024-01-01"),
|
|
3905
3904
|
missingRequiredEnv: [],
|
|
@@ -3953,7 +3952,7 @@ describe("admin API — trialExpiresAt field", () => {
|
|
|
3953
3952
|
reviewAuthorAllowlist: [],
|
|
3954
3953
|
patchAuthorAllowlist: [],
|
|
3955
3954
|
restrictSlackToMembers: false,
|
|
3956
|
-
|
|
3955
|
+
specialty: "coding",
|
|
3957
3956
|
createdAt: new Date("2024-01-01"),
|
|
3958
3957
|
updatedAt: new Date("2024-01-01"),
|
|
3959
3958
|
missingRequiredEnv: [],
|
|
@@ -3998,7 +3997,7 @@ describe("admin API — trialExpiresAt field", () => {
|
|
|
3998
3997
|
reviewAuthorAllowlist: [],
|
|
3999
3998
|
patchAuthorAllowlist: [],
|
|
4000
3999
|
restrictSlackToMembers: false,
|
|
4001
|
-
|
|
4000
|
+
specialty: "coding",
|
|
4002
4001
|
createdAt: new Date("2024-01-01"),
|
|
4003
4002
|
updatedAt: new Date("2024-01-01"),
|
|
4004
4003
|
missingRequiredEnv: [],
|
|
@@ -5175,7 +5174,7 @@ describe("non-admin session cookie scoping", () => {
|
|
|
5175
5174
|
(
|
|
5176
5175
|
await req(app, memberCookie, "/agents", "POST", {
|
|
5177
5176
|
name: "x",
|
|
5178
|
-
|
|
5177
|
+
specialty: "coding",
|
|
5179
5178
|
})
|
|
5180
5179
|
).status,
|
|
5181
5180
|
).toBe(403);
|
|
@@ -5261,32 +5260,32 @@ describe("admin API — account users create and delete agents (SSP-4.2)", () =>
|
|
|
5261
5260
|
},
|
|
5262
5261
|
});
|
|
5263
5262
|
|
|
5264
|
-
it("account user creates an agent stamped with their own accountId and the self-serve
|
|
5263
|
+
it("account user creates an agent stamped with their own accountId and the self-serve specialty", async () => {
|
|
5265
5264
|
const { deps, created } = makeAccountDeps("acct-a");
|
|
5266
5265
|
const res = await post(
|
|
5267
5266
|
createAdminApp(deps),
|
|
5268
|
-
{ name: "Mine",
|
|
5267
|
+
{ name: "Mine", specialty: "coding" },
|
|
5269
5268
|
await accountCookie(),
|
|
5270
5269
|
);
|
|
5271
5270
|
expect(res.status).toBe(200);
|
|
5272
5271
|
expect(created).toHaveLength(1);
|
|
5273
5272
|
expect(created[0]).toMatchObject({
|
|
5274
5273
|
accountId: "acct-a",
|
|
5275
|
-
|
|
5274
|
+
specialty: getSelfServeSpecialty(),
|
|
5276
5275
|
});
|
|
5277
5276
|
});
|
|
5278
5277
|
|
|
5279
|
-
it("ignores a client-supplied accountId and
|
|
5278
|
+
it("ignores a client-supplied accountId and specialty", async () => {
|
|
5280
5279
|
const { deps, created } = makeAccountDeps("acct-a");
|
|
5281
5280
|
const res = await post(
|
|
5282
5281
|
createAdminApp(deps),
|
|
5283
|
-
{ name: "Sneaky",
|
|
5282
|
+
{ name: "Sneaky", specialty: "other-type", accountId: "acct-b" },
|
|
5284
5283
|
await accountCookie(),
|
|
5285
5284
|
);
|
|
5286
5285
|
expect(res.status).toBe(200);
|
|
5287
5286
|
expect(created[0]).toMatchObject({
|
|
5288
5287
|
accountId: "acct-a",
|
|
5289
|
-
|
|
5288
|
+
specialty: getSelfServeSpecialty(),
|
|
5290
5289
|
});
|
|
5291
5290
|
});
|
|
5292
5291
|
|
|
@@ -5294,7 +5293,7 @@ describe("admin API — account users create and delete agents (SSP-4.2)", () =>
|
|
|
5294
5293
|
const { deps, created } = makeAccountDeps(null);
|
|
5295
5294
|
const res = await post(
|
|
5296
5295
|
createAdminApp(deps),
|
|
5297
|
-
{ name: "Nope",
|
|
5296
|
+
{ name: "Nope", specialty: "coding" },
|
|
5298
5297
|
await accountCookie(),
|
|
5299
5298
|
);
|
|
5300
5299
|
expect(res.status).toBe(403);
|
|
@@ -5305,7 +5304,7 @@ describe("admin API — account users create and delete agents (SSP-4.2)", () =>
|
|
|
5305
5304
|
const { deps, created } = makeAccountDeps("acct-a");
|
|
5306
5305
|
const res = await post(
|
|
5307
5306
|
createAdminApp(deps),
|
|
5308
|
-
{ name: "Admin Made",
|
|
5307
|
+
{ name: "Admin Made", specialty: "coding", accountId: "acct-b" },
|
|
5309
5308
|
await makeSessionCookie(),
|
|
5310
5309
|
);
|
|
5311
5310
|
expect(res.status).toBe(200);
|
|
@@ -5327,7 +5326,7 @@ describe("admin API — account users create and delete agents (SSP-4.2)", () =>
|
|
|
5327
5326
|
});
|
|
5328
5327
|
const res = await post(
|
|
5329
5328
|
app,
|
|
5330
|
-
{ name: "Q",
|
|
5329
|
+
{ name: "Q", specialty: "coding" },
|
|
5331
5330
|
await accountCookie(),
|
|
5332
5331
|
);
|
|
5333
5332
|
expect(res.status).toBe(403);
|
|
@@ -5863,7 +5862,7 @@ describe("admin API — Anthropic credential guards (WIF-2.1)", () => {
|
|
|
5863
5862
|
it("rejects claudeCodeOauthToken for an in-cluster agent under federation (400)", async () => {
|
|
5864
5863
|
const { provisioner, res } = create(true, {
|
|
5865
5864
|
name: "Fed Agent",
|
|
5866
|
-
|
|
5865
|
+
specialty: "coding",
|
|
5867
5866
|
runtime: "in-cluster",
|
|
5868
5867
|
claudeCodeOauthToken: "sk-ant-oat-secret",
|
|
5869
5868
|
});
|
|
@@ -5878,7 +5877,7 @@ describe("admin API — Anthropic credential guards (WIF-2.1)", () => {
|
|
|
5878
5877
|
it("rejects anthropicApiKey for an in-cluster agent under federation (400)", async () => {
|
|
5879
5878
|
const { res } = create(true, {
|
|
5880
5879
|
name: "Fed Agent",
|
|
5881
|
-
|
|
5880
|
+
specialty: "coding",
|
|
5882
5881
|
runtime: "in-cluster",
|
|
5883
5882
|
anthropicApiKey: "sk-ant-api-secret",
|
|
5884
5883
|
});
|
|
@@ -5888,7 +5887,7 @@ describe("admin API — Anthropic credential guards (WIF-2.1)", () => {
|
|
|
5888
5887
|
it("allows credentials for a self-hosted agent under federation", async () => {
|
|
5889
5888
|
const { res } = create(true, {
|
|
5890
5889
|
name: "Local Agent",
|
|
5891
|
-
|
|
5890
|
+
specialty: "coding",
|
|
5892
5891
|
claudeCodeOauthToken: "tok",
|
|
5893
5892
|
});
|
|
5894
5893
|
expect((await res).status).toBe(200);
|
|
@@ -5897,7 +5896,7 @@ describe("admin API — Anthropic credential guards (WIF-2.1)", () => {
|
|
|
5897
5896
|
it("allows credentials when federation is disabled", async () => {
|
|
5898
5897
|
const { res } = create(undefined, {
|
|
5899
5898
|
name: "Plain Agent",
|
|
5900
|
-
|
|
5899
|
+
specialty: "coding",
|
|
5901
5900
|
runtime: "in-cluster",
|
|
5902
5901
|
claudeCodeOauthToken: "tok",
|
|
5903
5902
|
});
|
|
@@ -5923,7 +5922,7 @@ describe("admin API — POST/DELETE /agents/:id/repos", () => {
|
|
|
5923
5922
|
reviewAuthorAllowlist: [],
|
|
5924
5923
|
patchAuthorAllowlist: [],
|
|
5925
5924
|
restrictSlackToMembers: false,
|
|
5926
|
-
|
|
5925
|
+
specialty: "coding",
|
|
5927
5926
|
createdAt: new Date("2024-01-01"),
|
|
5928
5927
|
updatedAt: new Date("2024-01-01"),
|
|
5929
5928
|
missingRequiredEnv: [],
|