@aexol/spectral 0.9.246 → 0.9.249
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/CHANGELOG.md +27 -0
- package/dist/agent/agents.d.ts +11 -9
- package/dist/agent/agents.d.ts.map +1 -1
- package/dist/agent/agents.js +19 -87
- package/dist/agent/index.d.ts +3 -3
- package/dist/agent/index.d.ts.map +1 -1
- package/dist/agent/index.js +7 -54
- package/dist/commands/serve.d.ts.map +1 -1
- package/dist/commands/serve.js +21 -0
- package/dist/generated/zeus/const.d.ts.map +1 -1
- package/dist/generated/zeus/const.js +240 -2
- package/dist/generated/zeus/index.d.ts +1205 -0
- package/dist/generated/zeus/index.d.ts.map +1 -1
- package/dist/mcp/ui-stream-types.d.ts +2 -2
- package/dist/relay/auto-research.d.ts.map +1 -1
- package/dist/relay/auto-research.js +0 -1
- package/dist/relay/routing.d.ts.map +1 -1
- package/dist/relay/routing.js +1 -2
- package/dist/sdk/agent-core/agent-loop.js +1 -1
- package/dist/server/agent-bridge.d.ts.map +1 -1
- package/dist/server/agent-bridge.js +14 -3
- package/dist/server/attachments/cleanup.d.ts +42 -0
- package/dist/server/attachments/cleanup.d.ts.map +1 -0
- package/dist/server/attachments/cleanup.js +100 -0
- package/dist/server/attachments/persist.d.ts +131 -0
- package/dist/server/attachments/persist.d.ts.map +1 -0
- package/dist/server/attachments/persist.js +406 -0
- package/dist/server/handlers/agent-settings.d.ts +1 -1
- package/dist/server/handlers/agent-settings.d.ts.map +1 -1
- package/dist/server/handlers/agent-settings.js +2 -2
- package/dist/server/session-stream.d.ts +5 -0
- package/dist/server/session-stream.d.ts.map +1 -1
- package/dist/server/session-stream.js +51 -1
- package/dist/server/storage.d.ts +6 -0
- package/dist/server/storage.d.ts.map +1 -1
- package/dist/server/storage.js +9 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,33 @@ All notable changes to `@aexol/spectral` are documented here. Format follows
|
|
|
5
5
|
|
|
6
6
|
## [Unreleased]
|
|
7
7
|
|
|
8
|
+
## [0.9.249] - 2026-10-06
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
|
|
12
|
+
- Release housekeeping for v0.9.249: cli-node version bump to 0.9.249, npm
|
|
13
|
+
lockfile version sync in `package-lock.json` (the root and package entries
|
|
14
|
+
were left at 0.9.247 by the v0.9.248 release), and Nix package version sync
|
|
15
|
+
in `nix/packages/spectral-cli.nix`.
|
|
16
|
+
|
|
17
|
+
## [0.9.247] - 2026-10-04
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
|
|
21
|
+
- Added a public built-in model catalog: new `publicModelCatalog` GraphQL
|
|
22
|
+
query (`BuiltInModelCatalogEntry`) exposing built-in UserModels with credit
|
|
23
|
+
pricing per 1M tokens, measured average TPS (output tokens over measured
|
|
24
|
+
duration rows only), owner-configured fallback tok/s on BaseModel,
|
|
25
|
+
last-request time, 30-day request count, and status. The `/models` landing
|
|
26
|
+
page was rebuilt around `models-catalog-section.tsx`.
|
|
27
|
+
- Added `durationMs` capture on CreditUsageEvent in the backend generate and
|
|
28
|
+
refine flows, with database migrations `20261004122612` and
|
|
29
|
+
`20261004135152`.
|
|
30
|
+
- Added cli-node attachment support: persist and cleanup in
|
|
31
|
+
`src/server/attachments` with tests, plus serve, agent-bridge,
|
|
32
|
+
session-stream, and storage changes.
|
|
33
|
+
- Added a Fallback tok/s input to the admin base-models tab.
|
|
34
|
+
|
|
8
35
|
## [0.9.231] - 2026-09-23
|
|
9
36
|
|
|
10
37
|
### Added
|
package/dist/agent/agents.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
export type AgentScope = "user" | "project" | "both";
|
|
2
1
|
export type AgentMode = "primary" | "subagent";
|
|
3
2
|
export interface AgentConfig {
|
|
4
3
|
name: string;
|
|
@@ -6,13 +5,9 @@ export interface AgentConfig {
|
|
|
6
5
|
mode: AgentMode;
|
|
7
6
|
model?: string;
|
|
8
7
|
systemPrompt: string;
|
|
9
|
-
source: "
|
|
8
|
+
source: "cloud" | "system";
|
|
10
9
|
filePath: string;
|
|
11
10
|
}
|
|
12
|
-
export interface AgentDiscoveryResult {
|
|
13
|
-
agents: AgentConfig[];
|
|
14
|
-
projectAgentsDir: string | null;
|
|
15
|
-
}
|
|
16
11
|
export declare const SYSTEM_AGENTS: AgentConfig[];
|
|
17
12
|
export declare function setCloudAgents(agents: AgentConfig[], teamId?: string): void;
|
|
18
13
|
/**
|
|
@@ -35,8 +30,15 @@ export declare function refreshCloudAgents(opts: {
|
|
|
35
30
|
machineJwt: string;
|
|
36
31
|
teamId?: string;
|
|
37
32
|
}): Promise<CloudAgentRefreshResult>;
|
|
38
|
-
|
|
39
|
-
|
|
33
|
+
/**
|
|
34
|
+
* Discover all agents available to a session: built-in system agents
|
|
35
|
+
* (SYSTEM_AGENTS, read-only) plus cloud agents from the backend cache
|
|
36
|
+
* (refreshCloudAgents, managed in Aexol Studio). Cloud agents override
|
|
37
|
+
* system agents on name collision. Never throws and never touches the
|
|
38
|
+
* network — offline / logged-out sessions simply get the system agents.
|
|
39
|
+
*/
|
|
40
|
+
export declare function discoverAgents(teamId?: string): AgentConfig[];
|
|
41
|
+
export declare function discoverPrimaryAgent(teamId?: string): AgentConfig | null;
|
|
40
42
|
/**
|
|
41
43
|
* Resolve the primary agent for a session.
|
|
42
44
|
*
|
|
@@ -46,7 +48,7 @@ export declare function discoverPrimaryAgent(cwd: string, scope?: AgentScope, ag
|
|
|
46
48
|
* resolves to `null` (no fallback to auto-detect), so a stale selection never
|
|
47
49
|
* silently injects an arbitrary primary agent.
|
|
48
50
|
*/
|
|
49
|
-
export declare function resolveSelectedPrimaryAgent(selectedName: string | null | undefined,
|
|
51
|
+
export declare function resolveSelectedPrimaryAgent(selectedName: string | null | undefined, teamId?: string): AgentConfig | null;
|
|
50
52
|
/**
|
|
51
53
|
* Prepend the primary agent's system prompt above the base system prompt.
|
|
52
54
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agents.d.ts","sourceRoot":"","sources":["../../src/agent/agents.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"agents.d.ts","sourceRoot":"","sources":["../../src/agent/agents.ts"],"names":[],"mappings":"AAOA,MAAM,MAAM,SAAS,GAAG,SAAS,GAAG,UAAU,CAAC;AAC/C,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,SAAS,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,OAAO,GAAG,QAAQ,CAAC;IAC3B,QAAQ,EAAE,MAAM,CAAC;CAClB;AA6ED,eAAO,MAAM,aAAa,EAAE,WAAW,EAkDtC,CAAC;AAkBF,wBAAgB,cAAc,CAAC,MAAM,EAAE,WAAW,EAAE,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAO3E;AACD;;;;GAIG;AACH,MAAM,MAAM,uBAAuB,GAAG;IACpC,yEAAyE;IACzE,YAAY,EAAE,IAAI,CAAC;IACnB,6CAA6C;IAC7C,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG;IACF,YAAY,EAAE,KAAK,CAAC;IACpB,4EAA4E;IAC5E,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,wBAAsB,kBAAkB,CAAC,IAAI,EAAE;IAC7C,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,GAAG,OAAO,CAAC,uBAAuB,CAAC,CA6EnC;AACD;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC5B,MAAM,CAAC,EAAE,MAAM,GACd,WAAW,EAAE,CAMf;AACD,wBAAgB,oBAAoB,CAClC,MAAM,CAAC,EAAE,MAAM,GACd,WAAW,GAAG,IAAI,CAiBpB;AACD;;;;;;;;GAQG;AACH,wBAAgB,2BAA2B,CACzC,YAAY,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EACvC,MAAM,CAAC,EAAE,MAAM,GACd,WAAW,GAAG,IAAI,CAgBpB;AACD;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,MAAM,GAAG,SAAS,EACxB,YAAY,EAAE,IAAI,CAChB,WAAW,EACX,MAAM,GAAG,aAAa,GAAG,cAAc,GAAG,OAAO,GAAG,QAAQ,CAC7D,GAAG,IAAI,GACP,MAAM,GAAG,SAAS,CAQpB;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,IAAI,CACT,WAAW,EACX,MAAM,GAAG,aAAa,GAAG,cAAc,GAAG,OAAO,GAAG,QAAQ,CAC7D,GAAG,IAAI,GACP,MAAM,CAYR"}
|
package/dist/agent/agents.js
CHANGED
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
import * as fs from "node:fs";
|
|
2
|
-
import * as path from "node:path";
|
|
3
1
|
import chalk from "chalk";
|
|
4
|
-
import { getAgentDir, parseFrontmatter } from "../sdk/coding-agent/index.js";
|
|
5
2
|
import { classifyGraphqlError, createBackendClient, graphqlErrorMessage, scalars, } from "../generated/graphql-client.js";
|
|
6
3
|
const GHOST_SYSTEM_PROMPT = [
|
|
7
4
|
"You are ghost, the built-in system orchestrator. Your job is to plan, coordinate, and integrate — not to do the work yourself. Delegate through the `subagent` tool to these subagents:",
|
|
@@ -119,44 +116,6 @@ export const SYSTEM_AGENTS = [
|
|
|
119
116
|
filePath: "system:fork",
|
|
120
117
|
},
|
|
121
118
|
];
|
|
122
|
-
function loadAgentsFromDir(dir, source) {
|
|
123
|
-
const agents = [];
|
|
124
|
-
if (!fs.existsSync(dir))
|
|
125
|
-
return agents;
|
|
126
|
-
let entries;
|
|
127
|
-
try {
|
|
128
|
-
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
129
|
-
}
|
|
130
|
-
catch {
|
|
131
|
-
return agents;
|
|
132
|
-
}
|
|
133
|
-
for (const entry of entries) {
|
|
134
|
-
if (!entry.name.endsWith(".md") ||
|
|
135
|
-
(!entry.isFile() && !entry.isSymbolicLink()))
|
|
136
|
-
continue;
|
|
137
|
-
const filePath = path.join(dir, entry.name);
|
|
138
|
-
let content;
|
|
139
|
-
try {
|
|
140
|
-
content = fs.readFileSync(filePath, "utf-8");
|
|
141
|
-
}
|
|
142
|
-
catch {
|
|
143
|
-
continue;
|
|
144
|
-
}
|
|
145
|
-
const { frontmatter, body } = parseFrontmatter(content);
|
|
146
|
-
if (!frontmatter.name || !frontmatter.description)
|
|
147
|
-
continue;
|
|
148
|
-
agents.push({
|
|
149
|
-
name: frontmatter.name,
|
|
150
|
-
description: frontmatter.description,
|
|
151
|
-
mode: frontmatter.mode === "primary" ? "primary" : "subagent",
|
|
152
|
-
model: frontmatter.model,
|
|
153
|
-
systemPrompt: body,
|
|
154
|
-
source,
|
|
155
|
-
filePath,
|
|
156
|
-
});
|
|
157
|
-
}
|
|
158
|
-
return agents;
|
|
159
|
-
}
|
|
160
119
|
const LEGACY_CLOUD_TEAM = "__legacy__";
|
|
161
120
|
const cloudAgentsByTeam = new Map();
|
|
162
121
|
function getCloudAgentCache(teamId) {
|
|
@@ -251,55 +210,32 @@ export async function refreshCloudAgents(opts) {
|
|
|
251
210
|
cache.inFlight = refresh;
|
|
252
211
|
return refresh;
|
|
253
212
|
}
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
let currentDir = cwd;
|
|
264
|
-
while (true) {
|
|
265
|
-
const candidate = path.join(currentDir, ".spectral", "agents");
|
|
266
|
-
if (isDirectory(candidate))
|
|
267
|
-
return candidate;
|
|
268
|
-
const parentDir = path.dirname(currentDir);
|
|
269
|
-
if (parentDir === currentDir)
|
|
270
|
-
return null;
|
|
271
|
-
currentDir = parentDir;
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
export function discoverAgents(cwd, scope, agentDir, teamId) {
|
|
275
|
-
const userDir = path.join(agentDir ?? getAgentDir(), "agents");
|
|
276
|
-
const projectAgentsDir = findNearestProjectAgentsDir(cwd);
|
|
277
|
-
const userAgents = scope === "project" ? [] : loadAgentsFromDir(userDir, "user");
|
|
278
|
-
const projectAgents = scope === "user" || !projectAgentsDir
|
|
279
|
-
? []
|
|
280
|
-
: loadAgentsFromDir(projectAgentsDir, "project");
|
|
281
|
-
const cloudAgents = scope === "both"
|
|
282
|
-
? getCloudAgentCache(teamId ?? LEGACY_CLOUD_TEAM).agents
|
|
283
|
-
: [];
|
|
213
|
+
/**
|
|
214
|
+
* Discover all agents available to a session: built-in system agents
|
|
215
|
+
* (SYSTEM_AGENTS, read-only) plus cloud agents from the backend cache
|
|
216
|
+
* (refreshCloudAgents, managed in Aexol Studio). Cloud agents override
|
|
217
|
+
* system agents on name collision. Never throws and never touches the
|
|
218
|
+
* network — offline / logged-out sessions simply get the system agents.
|
|
219
|
+
*/
|
|
220
|
+
export function discoverAgents(teamId) {
|
|
221
|
+
const cloudAgents = getCloudAgentCache(teamId ?? LEGACY_CLOUD_TEAM).agents;
|
|
284
222
|
const agentMap = new Map();
|
|
285
223
|
for (const agent of SYSTEM_AGENTS)
|
|
286
224
|
agentMap.set(agent.name, agent);
|
|
287
225
|
for (const agent of cloudAgents)
|
|
288
226
|
agentMap.set(agent.name, agent);
|
|
289
|
-
|
|
290
|
-
agentMap.set(agent.name, agent);
|
|
291
|
-
for (const agent of userAgents)
|
|
292
|
-
agentMap.set(agent.name, agent);
|
|
293
|
-
return { agents: Array.from(agentMap.values()), projectAgentsDir };
|
|
227
|
+
return Array.from(agentMap.values());
|
|
294
228
|
}
|
|
295
|
-
export function discoverPrimaryAgent(
|
|
296
|
-
const
|
|
229
|
+
export function discoverPrimaryAgent(teamId) {
|
|
230
|
+
const agents = discoverAgents(teamId);
|
|
297
231
|
const primaries = agents.filter((a) => a.mode === "primary");
|
|
298
232
|
if (primaries.length === 0)
|
|
299
233
|
return null;
|
|
300
234
|
if (primaries.length > 1) {
|
|
301
|
-
|
|
302
|
-
|
|
235
|
+
// Cloud agents override built-in system agents (same precedence as
|
|
236
|
+
// discovery): a cloud primary always wins over the built-in ghost.
|
|
237
|
+
const cloudPrimary = primaries.find((a) => a.source === "cloud");
|
|
238
|
+
const chosen = cloudPrimary ?? primaries[0];
|
|
303
239
|
console.warn(chalk.yellow(`Multiple primary agents found (${primaries.map((a) => a.name).join(", ")}). Using "${chosen.name}".`));
|
|
304
240
|
return chosen;
|
|
305
241
|
}
|
|
@@ -314,7 +250,7 @@ export function discoverPrimaryAgent(cwd, scope = "both", agentDir, teamId) {
|
|
|
314
250
|
* resolves to `null` (no fallback to auto-detect), so a stale selection never
|
|
315
251
|
* silently injects an arbitrary primary agent.
|
|
316
252
|
*/
|
|
317
|
-
export function resolveSelectedPrimaryAgent(selectedName,
|
|
253
|
+
export function resolveSelectedPrimaryAgent(selectedName, teamId) {
|
|
318
254
|
if (selectedName === undefined ||
|
|
319
255
|
selectedName === null ||
|
|
320
256
|
selectedName === "__auto__" ||
|
|
@@ -322,7 +258,7 @@ export function resolveSelectedPrimaryAgent(selectedName, cwd, agentDir, teamId)
|
|
|
322
258
|
selectedName === "__none__") {
|
|
323
259
|
return null;
|
|
324
260
|
}
|
|
325
|
-
const
|
|
261
|
+
const agents = discoverAgents(teamId);
|
|
326
262
|
return (agents.find((agent) => agent.mode === "primary" && agent.name === selectedName) ?? null);
|
|
327
263
|
}
|
|
328
264
|
/**
|
|
@@ -360,11 +296,7 @@ export function agentMetadataBlock(agent) {
|
|
|
360
296
|
}
|
|
361
297
|
const sourceLabel = agent.source === "cloud"
|
|
362
298
|
? "cloud backend (managed in Aexol Studio; not a local file)"
|
|
363
|
-
: agent
|
|
364
|
-
? "project file (.spectral/agents)"
|
|
365
|
-
: agent.source === "system"
|
|
366
|
-
? "built-in system agent (read-only)"
|
|
367
|
-
: "user file (~/.spectral/agents)";
|
|
299
|
+
: "built-in system agent (read-only)";
|
|
368
300
|
lines.push(`Source: ${sourceLabel}`);
|
|
369
301
|
return `\n\n## Agent metadata\n${lines.map((l) => `- ${l}`).join("\n")}`;
|
|
370
302
|
}
|
package/dist/agent/index.d.ts
CHANGED
|
@@ -12,9 +12,9 @@
|
|
|
12
12
|
* - Parallel: { tasks: [{ agent, task }, ...] } (max 8, 4 concurrent)
|
|
13
13
|
* - Chain: { chain: [{ agent, task: "... {previous} ..." }, ...] }
|
|
14
14
|
*
|
|
15
|
-
*
|
|
16
|
-
* -
|
|
17
|
-
* -
|
|
15
|
+
* Agents come from two sources only:
|
|
16
|
+
* - Built-in system agents (SYSTEM_AGENTS, read-only)
|
|
17
|
+
* - Cloud agents from the backend cache (managed in Aexol Studio /agents)
|
|
18
18
|
*
|
|
19
19
|
* Subagents use an in-process `agentLoop()` for:
|
|
20
20
|
* - Clean context isolation (fresh messages array)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/agent/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,OAAO,KAAK,EAEX,UAAU,EAEV,SAAS,EAET,MAAM,4BAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/agent/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,OAAO,KAAK,EAEX,UAAU,EAEV,SAAS,EAET,MAAM,4BAA4B,CAAC;AAoBpC,OAAO,EACN,KAAK,YAAY,EACjB,KAAK,gBAAgB,EAKrB,MAAM,8BAA8B,CAAC;AAItC,OAAO,EACN,KAAK,WAAW,EAIhB,MAAM,aAAa,CAAC;AAErB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAGN,KAAK,cAAc,EACnB,MAAM,uCAAuC,CAAC;AAS/C,OAAO,KAAK,EAAE,sBAAsB,EAAgB,MAAM,6CAA6C,CAAC;AAyGxG;;;;;;;;;GASG;AACH,wBAAgB,yBAAyB,CACxC,gBAAgB,EAAE,MAAM,GAAG,SAAS,EACpC,KAAK,EAAE,IAAI,CAAC,WAAW,EAAE,MAAM,GAAG,aAAa,GAAG,cAAc,GAAG,OAAO,GAAG,QAAQ,CAAC,GACpF,MAAM,CAYR;AAyND;;;GAGG;AACH,wBAAgB,oCAAoC,CACnD,cAAc,EAAE,gBAAgB,CAAC,gBAAgB,CAAC,GAChD,IAAI,CAAC,sBAAsB,EAAE,WAAW,GAAG,cAAc,CAAC,CAe5D;AAgCD,wBAAgB,oBAAoB,CACnC,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,YAAY,EACjB,GAAG,EAAE,gBAAgB,EACrB,SAAS,CAAC,EAAE,MAAM,GAChB,SAAS,EAAE,CAkDb;AAyBD;;;;;;;;;;GAUG;AACH;;;;;;GAMG;AACH,MAAM,WAAW,wBAAwB;IACxC,IAAI,EAAE,uBAAuB,CAAC;IAC9B,6EAA6E;IAC7E,GAAG,EAAE,cAAc,CAAC;CACpB;AAED,8EAA8E;AAC9E,MAAM,MAAM,qBAAqB,GAAG,UAAU,GAAG,wBAAwB,CAAC;AAmF1E,2FAA2F;AAC3F,wBAAgB,+BAA+B,CAC9C,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,IAAI,CAAC,GACtD,IAAI,CAEN;AAmBD;;;;;;GAMG;AACH,wBAAgB,0BAA0B,CACzC,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,QAAQ,EAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,GAC9D,MAAM,CAiBR;AAqlBD,MAAM,CAAC,OAAO,UAAU,iBAAiB,CACxC,GAAG,EAAE,YAAY,EACjB,IAAI,CAAC,EAAE;IACN,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,iBAAiB,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAC;IACjD,MAAM,CAAC,EAAE,MAAM,CAAC;CAChB,GACC,IAAI,CAmaN"}
|
package/dist/agent/index.js
CHANGED
|
@@ -12,9 +12,9 @@
|
|
|
12
12
|
* - Parallel: { tasks: [{ agent, task }, ...] } (max 8, 4 concurrent)
|
|
13
13
|
* - Chain: { chain: [{ agent, task: "... {previous} ..." }, ...] }
|
|
14
14
|
*
|
|
15
|
-
*
|
|
16
|
-
* -
|
|
17
|
-
* -
|
|
15
|
+
* Agents come from two sources only:
|
|
16
|
+
* - Built-in system agents (SYSTEM_AGENTS, read-only)
|
|
17
|
+
* - Cloud agents from the backend cache (managed in Aexol Studio /agents)
|
|
18
18
|
*
|
|
19
19
|
* Subagents use an in-process `agentLoop()` for:
|
|
20
20
|
* - Clean context isolation (fresh messages array)
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
*/
|
|
32
32
|
import { agentLoop, agentLoopContinue, } from "../sdk/agent-core/index.js";
|
|
33
33
|
import { buildIsolatedRequestTimePrunedMessagesResult, COMPACT_CONTEXT_TOOL_NAME, } from "../memory/tools/compact-context.js";
|
|
34
|
-
import { isRateLimitError, isTransientApiError, isContextOverflow, isPaymentRequiredError,
|
|
34
|
+
import { isRateLimitError, isTransientApiError, isContextOverflow, isPaymentRequiredError, streamSimple, } from "../sdk/ai/index.js";
|
|
35
35
|
import { RETRY_DEFAULT_BASE_DELAY_MS, RETRY_DEFAULT_MAX_RETRIES, RETRY_MAX_BACKOFF_DELAY_MS, } from "../sdk/coding-agent/index.js";
|
|
36
36
|
import { mutateSystemPrompt } from "../sdk/coding-agent/core/system-prompt-mutator.js";
|
|
37
37
|
import { sleep } from "../sdk/coding-agent/utils/sleep.js";
|
|
@@ -929,10 +929,6 @@ const ChainItem = Type.Object({
|
|
|
929
929
|
}),
|
|
930
930
|
cwd: Type.Optional(Type.String({ description: "Working directory for the agent process" })),
|
|
931
931
|
});
|
|
932
|
-
const AgentScopeSchema = StringEnum(["user", "project", "both"], {
|
|
933
|
-
description: 'Which agent directories to use. Default: "both" (user + project agents).',
|
|
934
|
-
default: "both",
|
|
935
|
-
});
|
|
936
932
|
const SubagentParams = Type.Object({
|
|
937
933
|
agent: Type.Optional(Type.String({
|
|
938
934
|
description: "Known agent name to invoke (single mode; use names from the available agents list)",
|
|
@@ -948,11 +944,6 @@ const SubagentParams = Type.Object({
|
|
|
948
944
|
description: "Sequential steps of {agent, task}; {previous} substitutes the previous step's output (max 8 steps)",
|
|
949
945
|
minItems: 1,
|
|
950
946
|
})),
|
|
951
|
-
agentScope: Type.Optional(AgentScopeSchema),
|
|
952
|
-
confirmProjectAgents: Type.Optional(Type.Boolean({
|
|
953
|
-
description: "Prompt before running project-local agents. Default: true.",
|
|
954
|
-
default: true,
|
|
955
|
-
})),
|
|
956
947
|
cwd: Type.Optional(Type.String({
|
|
957
948
|
description: "Working directory for the agent process (single mode)",
|
|
958
949
|
})),
|
|
@@ -972,8 +963,8 @@ export default function subagentExtension(ext, opts) {
|
|
|
972
963
|
description: [
|
|
973
964
|
"Delegate tasks to specialized subagents with isolated context.",
|
|
974
965
|
"Modes: single (agent + task), parallel (tasks array), chain (sequential with {previous} placeholder).",
|
|
975
|
-
|
|
976
|
-
|
|
966
|
+
"Agents come from two sources only: built-in system agents (read-only) and cloud agents from the backend cache (managed in Aexol Studio /agents).",
|
|
967
|
+
"Local agent files are not read; manage cloud agents in the Studio /agents page.",
|
|
977
968
|
"Exactly one mode per call.",
|
|
978
969
|
'Single (one task): {"agent":"researcher","task":"<full self-contained task text>"}',
|
|
979
970
|
'Parallel (independent tasks; max 8, 4 run concurrently): {"tasks":[{"agent":"researcher","task":"..."},{"agent":"executor","task":"..."}]}',
|
|
@@ -1003,30 +994,23 @@ export default function subagentExtension(ext, opts) {
|
|
|
1003
994
|
],
|
|
1004
995
|
details: {
|
|
1005
996
|
mode: "single",
|
|
1006
|
-
agentScope: (params.agentScope ?? "both"),
|
|
1007
|
-
projectAgentsDir: null,
|
|
1008
997
|
results: [],
|
|
1009
998
|
},
|
|
1010
999
|
};
|
|
1011
1000
|
}
|
|
1012
|
-
const agentScope = params.agentScope ?? "both";
|
|
1013
|
-
const discovery = discoverAgents(ctx.cwd, agentScope, undefined, opts?.teamId);
|
|
1014
1001
|
// Merge registration-time disabled list (from session start) with the
|
|
1015
1002
|
// live disabled list (just read from disk) so both are honored.
|
|
1016
1003
|
const disabledSet = new Set([
|
|
1017
1004
|
...(opts?.disabledAgents ?? []),
|
|
1018
1005
|
...(liveSettings.disabledSubagents ?? []),
|
|
1019
1006
|
]);
|
|
1020
|
-
const agents =
|
|
1021
|
-
const confirmProjectAgents = params.confirmProjectAgents ?? false;
|
|
1007
|
+
const agents = discoverAgents(opts?.teamId).filter((a) => !disabledSet.has(a.name));
|
|
1022
1008
|
const hasChain = (params.chain?.length ?? 0) > 0;
|
|
1023
1009
|
const hasTasks = (params.tasks?.length ?? 0) > 0;
|
|
1024
1010
|
const hasSingle = Boolean(params.agent && params.task);
|
|
1025
1011
|
const modeCount = Number(hasChain) + Number(hasTasks) + Number(hasSingle);
|
|
1026
1012
|
const makeDetails = (mode) => (results) => ({
|
|
1027
1013
|
mode,
|
|
1028
|
-
agentScope,
|
|
1029
|
-
projectAgentsDir: discovery.projectAgentsDir,
|
|
1030
1014
|
results,
|
|
1031
1015
|
});
|
|
1032
1016
|
// Forward internal subagent tool lifecycle events to the bridge so the
|
|
@@ -1112,37 +1096,6 @@ export default function subagentExtension(ext, opts) {
|
|
|
1112
1096
|
details: makeDetails("single")([]),
|
|
1113
1097
|
};
|
|
1114
1098
|
}
|
|
1115
|
-
// Security: if project-local agents are enabled, confirm with user.
|
|
1116
|
-
// In headless mode (no TUI), project-local agents are silently allowed —
|
|
1117
|
-
// the caller is already trusted (it's the coding agent itself).
|
|
1118
|
-
if ((agentScope === "project" || agentScope === "both") &&
|
|
1119
|
-
confirmProjectAgents &&
|
|
1120
|
-
ctx.hasUI) {
|
|
1121
|
-
const requestedAgentNames = new Set();
|
|
1122
|
-
if (params.chain)
|
|
1123
|
-
for (const step of params.chain)
|
|
1124
|
-
requestedAgentNames.add(step.agent.replace(/^@/, ""));
|
|
1125
|
-
if (params.tasks)
|
|
1126
|
-
for (const t of params.tasks)
|
|
1127
|
-
requestedAgentNames.add(t.agent.replace(/^@/, ""));
|
|
1128
|
-
if (params.agent)
|
|
1129
|
-
requestedAgentNames.add(params.agent.replace(/^@/, ""));
|
|
1130
|
-
const projectAgentsRequested = Array.from(requestedAgentNames)
|
|
1131
|
-
.map((name) => agents.find((a) => a.name === name))
|
|
1132
|
-
.filter((a) => a?.source === "project");
|
|
1133
|
-
if (projectAgentsRequested.length > 0) {
|
|
1134
|
-
const names = projectAgentsRequested.map((a) => a.name).join(", ");
|
|
1135
|
-
const dir = discovery.projectAgentsDir ?? "(unknown)";
|
|
1136
|
-
const ok = await ctx.ui.confirm("Run project-local agents?", `Agents: ${names}\nSource: ${dir}\n\nProject agents are repo-controlled. Only continue for trusted repositories.`);
|
|
1137
|
-
if (!ok)
|
|
1138
|
-
return {
|
|
1139
|
-
content: [
|
|
1140
|
-
{ type: "text", text: "Canceled: project-local agents not approved." },
|
|
1141
|
-
],
|
|
1142
|
-
details: makeDetails(hasChain ? "chain" : hasTasks ? "parallel" : "single")([]),
|
|
1143
|
-
};
|
|
1144
|
-
}
|
|
1145
|
-
}
|
|
1146
1099
|
// ── Chain mode ──────────────────────────────────────────────
|
|
1147
1100
|
if (params.chain && params.chain.length > 0) {
|
|
1148
1101
|
if (params.chain.length > MAX_CHAIN_STEPS)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"serve.d.ts","sourceRoot":"","sources":["../../src/commands/serve.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAwBH,OAAO,EAAE,WAAW,EAAmB,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"serve.d.ts","sourceRoot":"","sources":["../../src/commands/serve.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAwBH,OAAO,EAAE,WAAW,EAAmB,MAAM,oBAAoB,CAAC;AAgBlE,OAAO,KAAK,EAAE,aAAa,EAAc,MAAM,6BAA6B,CAAC;AAC7E,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AAGnE,OAAO,EAAmB,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAsBrE;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAazD;AAED,MAAM,WAAW,eAAe;IAC9B,8CAA8C;IAC9C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,cAAc,EAAE,OAAO,CAAC;CACzB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,eAAe,CA6B9D;AAED,MAAM,WAAW,eAAe;IAC9B,iEAAiE;IACjE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,4CAA4C;IAC5C,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,uCAAuC;IACvC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,wCAAwC;IACxC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,yDAAyD;IACzD,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,6EAA6E;IAC7E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,4CAA4C;IAC5C,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IACzB,+DAA+D;IAC/D,aAAa,CAAC,EAAE,qBAAqB,CAAC,OAAO,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC;IAC9E;;;;;OAKG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,cAAc;IAC7B,qCAAqC;IACrC,KAAK,EAAE,YAAY,CAAC;IACpB,wDAAwD;IACxD,OAAO,EAAE,oBAAoB,CAAC;IAC9B,4CAA4C;IAC5C,KAAK,EAAE,WAAW,CAAC;IACnB,+CAA+C;IAC/C,SAAS,EAAE,MAAM,CAAC;IAClB,4CAA4C;IAC5C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED,wBAAsB,QAAQ,CAAC,IAAI,GAAE,eAAoB,GAAG,OAAO,CAAC,cAAc,CAAC,CAurBlF;AAmFD;;;;GAIG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,cAAc,CAAC,CAsB5E"}
|
package/dist/commands/serve.js
CHANGED
|
@@ -43,6 +43,8 @@ import { getFanoutManager } from "../server/fanout/fanout-manager.js";
|
|
|
43
43
|
import { detachAllSubscribers, handleAutoOptimizeFrame, handleAutoResearchFrame, handleCancelTurn, handleClientMessage, handleRestRequest, handleStopToolCall, handleSubscribe, } from "../relay/dispatcher.js";
|
|
44
44
|
import { ensureMachineRegistered } from "../relay/registration.js";
|
|
45
45
|
import { saveMachine } from "../relay/machine-store.js";
|
|
46
|
+
import { sweepAttachments } from "../server/attachments/cleanup.js";
|
|
47
|
+
import { attachmentsRootFor } from "../server/attachments/persist.js";
|
|
46
48
|
import { SessionStreamManager } from "../server/session-stream.js";
|
|
47
49
|
import { gracefulShutdown } from "../server/shutdown.js";
|
|
48
50
|
import { getLiveMcpState } from "../mcp/state-getter.js";
|
|
@@ -175,6 +177,25 @@ export async function runServe(opts = {}) {
|
|
|
175
177
|
// Best-effort.
|
|
176
178
|
}
|
|
177
179
|
});
|
|
180
|
+
// GC for stale persisted chat attachments (`.spectral/attachments/<id>/`).
|
|
181
|
+
// Fire-and-forget like the offload sweep: never blocks server startup and
|
|
182
|
+
// never takes down serving. Sweeps every known project root (attachments
|
|
183
|
+
// live under the session's project cwd) plus the fallback cwd.
|
|
184
|
+
setImmediate(() => {
|
|
185
|
+
try {
|
|
186
|
+
const activeSessionIds = new Set(store.listAllSessionIds());
|
|
187
|
+
const roots = new Set([attachmentsRootFor(cwd)]);
|
|
188
|
+
for (const project of store.listProjects()) {
|
|
189
|
+
roots.add(attachmentsRootFor(project.path));
|
|
190
|
+
}
|
|
191
|
+
for (const root of roots) {
|
|
192
|
+
sweepAttachments({ root, activeSessionIds });
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
catch {
|
|
196
|
+
// Best-effort.
|
|
197
|
+
}
|
|
198
|
+
});
|
|
178
199
|
// Mutable holder for the meta-event publisher. Bound below once we
|
|
179
200
|
// have both `relay` (the send target) and `registration.record.machineId`
|
|
180
201
|
// (the canonical machineId the backend uses to fan out). The manager
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"const.d.ts","sourceRoot":"","sources":["../../../src/generated/zeus/const.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAC,GAAG,
|
|
1
|
+
{"version":3,"file":"const.d.ts","sourceRoot":"","sources":["../../../src/generated/zeus/const.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAC,GAAG,CAw4B5C,CAAA;AAED,eAAO,MAAM,WAAW,EAAE,MAAM,CAAC,MAAM,EAAC,GAAG,CAg1C1C,CAAA;AAED,eAAO,MAAM,GAAG;;;;CAIf,CAAA"}
|