agent-relay-server 0.57.2 → 0.58.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/docs/openapi.json +151 -1
- package/package.json +2 -2
- package/public/assets/display-CketawEF.js.map +1 -1
- package/src/db/index.ts +2 -0
- package/src/db/project-entries.ts +270 -0
- package/src/db/projects.ts +304 -0
- package/src/db/schema.ts +50 -0
- package/src/db/teams.ts +13 -2
- package/src/mcp-project-tools.ts +352 -0
- package/src/mcp.ts +3 -0
- package/src/project-ingest.ts +186 -0
- package/src/routes/index.ts +5 -0
- package/src/routes/projects.ts +55 -0
- package/src/runtime-tokens.ts +6 -0
- package/src/security.ts +4 -0
- package/src/services/spawn-agent.ts +7 -1
- package/src/services/team.ts +5 -1
- package/src/token-db.ts +3 -3
package/src/security.ts
CHANGED
|
@@ -206,6 +206,7 @@ export function requiredScopeFor(method: string, pathname: string): string | nul
|
|
|
206
206
|
if (pathname.startsWith("/api/pairs")) return method === "GET" ? "pairs:read" : "pairs:write";
|
|
207
207
|
if (pathname.startsWith("/api/teams")) return method === "GET" ? "teams:read" : "teams:write";
|
|
208
208
|
if (pathname.startsWith("/api/blackboard")) return method === "GET" ? "blackboard:read" : "blackboard:write";
|
|
209
|
+
if (pathname.startsWith("/api/projects")) return method === "GET" ? "project:read" : "project:write";
|
|
209
210
|
// Insights config (the feature toggle) stays admin-only via the default; only the
|
|
210
211
|
// mechanical observation feed is writable by lower-privilege callers.
|
|
211
212
|
if (pathname === "/api/insights/observations") return method === "GET" ? "insights:read" : "insights:write";
|
|
@@ -282,6 +283,9 @@ export function requiredComponentScopeFor(method: string, pathname: string): str
|
|
|
282
283
|
if (pathname.startsWith("/api/plans")) return method === "GET" ? "plans:read" : "plans:write";
|
|
283
284
|
if (pathname.startsWith("/api/teams")) return method === "GET" ? "teams:read" : "teams:write";
|
|
284
285
|
if (pathname.startsWith("/api/blackboard")) return method === "GET" ? "blackboard:read" : "blackboard:write";
|
|
286
|
+
// Fail-closed default returns system:admin, so this case is load-bearing: without it
|
|
287
|
+
// every /api/projects call from a scoped component token would 403-blackhole (#405).
|
|
288
|
+
if (pathname.startsWith("/api/projects")) return method === "GET" ? "project:read" : "project:write";
|
|
285
289
|
// The Runner posts the #184 context-gathering signal here (source:"server") via its
|
|
286
290
|
// provider token. Without this case the path fell through to the system:admin default
|
|
287
291
|
// below and every observation was 403-dropped — the whole Insights feed stayed empty.
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
// deliberately out of scope here — this slice converges the two external TRANSPORTS.
|
|
26
26
|
import type { SpawnProvider } from "agent-relay-sdk";
|
|
27
27
|
import { stringValue } from "agent-relay-sdk";
|
|
28
|
-
import { countLiveSpawnedAgents, createActivityEvent, ensureTeam, getAgent, listAgents, setAgentTeam, ValidationError } from "../db";
|
|
28
|
+
import { countLiveSpawnedAgents, createActivityEvent, ensureTeam, getAgent, listAgents, resolveProjectForCwd, setAgentTeam, ValidationError } from "../db";
|
|
29
29
|
import { createCommand } from "../commands-db";
|
|
30
30
|
import { emitCommandEvent } from "../command-events";
|
|
31
31
|
import { buildSpawnCommand, generateSpawnRequestId, resolveSpawnModelParams } from "../spawn-command";
|
|
@@ -192,6 +192,11 @@ export async function spawnAgent(input: SpawnAgentInput, ctx: AuthContext): Prom
|
|
|
192
192
|
const callerTeam = callerId ? (caller?.teamId ? { id: caller.teamId } : ensureTeam(callerId)) : undefined;
|
|
193
193
|
if (callerId && callerTeam && !caller?.teamId) setAgentTeam(callerId, callerTeam.id);
|
|
194
194
|
|
|
195
|
+
// #405 — durable project binding: the project whose registered root contains the spawn cwd.
|
|
196
|
+
// Stamped on the child token's constraints (identity-only, like teamId) so callerProject(auth)
|
|
197
|
+
// resolves it. Absent (graceful) when the cwd is inside no registered root.
|
|
198
|
+
const callerProject = resolveProjectForCwd(resolvedCwd);
|
|
199
|
+
|
|
195
200
|
// Child runner token. `agentInitiated` (set whenever an agent is the caller) forces a
|
|
196
201
|
// non-spawn-capable child (no grandchildren); `spawnedBy` stamps authoritative lineage the
|
|
197
202
|
// child can't forge (it registers with spawnedBy = caller, read from the signed token).
|
|
@@ -211,6 +216,7 @@ export async function spawnAgent(input: SpawnAgentInput, ctx: AuthContext): Prom
|
|
|
211
216
|
profile: input.profile || undefined,
|
|
212
217
|
...(callerId ? { agentInitiated: true, spawnedBy: callerId } : {}),
|
|
213
218
|
...(callerTeam ? { teamId: callerTeam.id } : {}),
|
|
219
|
+
...(callerProject ? { projectId: callerProject.id } : {}),
|
|
214
220
|
});
|
|
215
221
|
|
|
216
222
|
// #413 — default the report-back obligation ON for an agent coordinator handing a worker a
|
package/src/services/team.ts
CHANGED
|
@@ -56,7 +56,7 @@ export function setCallerTeamBrief(ctx: AuthContext, input: TeamBriefInput): Tea
|
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
export function dissolveTeamById(teamId: string, input: TeamDissolveServiceInput = {}): Team {
|
|
59
|
-
const team = dissolveTeam(teamId, input);
|
|
59
|
+
const { team, unpromotedBlackboard } = dissolveTeam(teamId, input);
|
|
60
60
|
emitRelayEvent({
|
|
61
61
|
type: "team.dissolved",
|
|
62
62
|
source: "system",
|
|
@@ -65,6 +65,10 @@ export function dissolveTeamById(teamId: string, input: TeamDissolveServiceInput
|
|
|
65
65
|
teamId: team.id,
|
|
66
66
|
outcomeStatus: team.outcomeStatus ?? null,
|
|
67
67
|
reason: team.outcomeSummary ?? null,
|
|
68
|
+
// Surface (don't auto-promote) the lossy findings the team is leaving behind so a
|
|
69
|
+
// coordinator/operator can decide what to lift into durable project knowledge (#404).
|
|
70
|
+
unpromotedBlackboardCount: unpromotedBlackboard.count,
|
|
71
|
+
unpromotedBlackboard: unpromotedBlackboard.entries,
|
|
68
72
|
},
|
|
69
73
|
});
|
|
70
74
|
return team;
|
package/src/token-db.ts
CHANGED
|
@@ -57,7 +57,7 @@ const BUILT_IN_PROFILES: Array<Omit<TokenProfile, "createdAt" | "updatedAt">> =
|
|
|
57
57
|
name: "Provider Agent",
|
|
58
58
|
description: "Coding-agent runtime access for messages, commands, tasks, and scoped memory reads.",
|
|
59
59
|
role: "provider",
|
|
60
|
-
scope: ["agent:read", "agent:write", "message:read", "message:send", "command:read", "command:write", "task:read", "task:write", "memory:read", "artifact:read", "artifact:write", "mcp:use", "plans:read", "plans:write", "teams:read", "teams:write", "blackboard:read", "blackboard:write", "insights:write"],
|
|
60
|
+
scope: ["agent:read", "agent:write", "message:read", "message:send", "command:read", "command:write", "task:read", "task:write", "memory:read", "artifact:read", "artifact:write", "mcp:use", "plans:read", "plans:write", "teams:read", "teams:write", "blackboard:read", "blackboard:write", "project:read", "project:write", "insights:write"],
|
|
61
61
|
ttlSeconds: 24 * 60 * 60,
|
|
62
62
|
builtIn: true,
|
|
63
63
|
createdBy: "system",
|
|
@@ -67,7 +67,7 @@ const BUILT_IN_PROFILES: Array<Omit<TokenProfile, "createdAt" | "updatedAt">> =
|
|
|
67
67
|
name: "Provider Child Agent",
|
|
68
68
|
description: "Delegated child-agent runtime access, constrained to its parent and spawn request.",
|
|
69
69
|
role: "provider",
|
|
70
|
-
scope: ["agent:read", "agent:write", "message:read", "message:send", "command:read", "command:write", "task:read", "task:write", "memory:read", "artifact:read", "artifact:write", "mcp:use", "teams:read", "blackboard:read", "blackboard:write", "insights:write"],
|
|
70
|
+
scope: ["agent:read", "agent:write", "message:read", "message:send", "command:read", "command:write", "task:read", "task:write", "memory:read", "artifact:read", "artifact:write", "mcp:use", "teams:read", "blackboard:read", "blackboard:write", "project:read", "project:write", "insights:write"],
|
|
71
71
|
constraints: { canDelegate: false },
|
|
72
72
|
ttlSeconds: 2 * 60 * 60,
|
|
73
73
|
builtIn: true,
|
|
@@ -78,7 +78,7 @@ const BUILT_IN_PROFILES: Array<Omit<TokenProfile, "createdAt" | "updatedAt">> =
|
|
|
78
78
|
name: "Provider Interactive Agent",
|
|
79
79
|
description: "User-launched provider runtime access constrained to its own agent and cwd for long interactive sessions.",
|
|
80
80
|
role: "provider",
|
|
81
|
-
scope: ["agent:read", "agent:write", "message:read", "message:send", "command:read", "command:write", "task:read", "task:write", "memory:read", "artifact:read", "artifact:write", "mcp:use", "teams:read", "blackboard:read", "blackboard:write", "insights:write"],
|
|
81
|
+
scope: ["agent:read", "agent:write", "message:read", "message:send", "command:read", "command:write", "task:read", "task:write", "memory:read", "artifact:read", "artifact:write", "mcp:use", "teams:read", "blackboard:read", "blackboard:write", "project:read", "project:write", "insights:write"],
|
|
82
82
|
constraints: { terminalAttach: false, logsRead: false, canDelegate: false },
|
|
83
83
|
ttlSeconds: 30 * 24 * 60 * 60,
|
|
84
84
|
builtIn: true,
|