@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
|
@@ -43,7 +43,7 @@ export declare const visualizationStreamEnvelopeSchema: z.ZodObject<{
|
|
|
43
43
|
streamId: string;
|
|
44
44
|
sequence: number;
|
|
45
45
|
frameType: "patch" | "checkpoint" | "final";
|
|
46
|
-
phase: "structure" | "
|
|
46
|
+
phase: "structure" | "detail" | "settled" | "shell" | "narrative";
|
|
47
47
|
message?: string | undefined;
|
|
48
48
|
spec?: Record<string, unknown> | undefined;
|
|
49
49
|
checkpoint?: Record<string, unknown> | undefined;
|
|
@@ -52,7 +52,7 @@ export declare const visualizationStreamEnvelopeSchema: z.ZodObject<{
|
|
|
52
52
|
streamId: string;
|
|
53
53
|
sequence: number;
|
|
54
54
|
frameType: "patch" | "checkpoint" | "final";
|
|
55
|
-
phase: "structure" | "
|
|
55
|
+
phase: "structure" | "detail" | "settled" | "shell" | "narrative";
|
|
56
56
|
message?: string | undefined;
|
|
57
57
|
spec?: Record<string, unknown> | undefined;
|
|
58
58
|
checkpoint?: Record<string, unknown> | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auto-research.d.ts","sourceRoot":"","sources":["../../src/relay/auto-research.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAKH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,KAAK,EAAE,oBAAoB,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAEpF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAM/C,oDAAoD;AACpD,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,+CAA+C;AAC/C,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,YAAY,CAAC;IACpB,OAAO,EAAE,oBAAoB,CAAC;IAC9B,KAAK,EAAE,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;IACjC;0DACsD;IACtD,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACrC,6EAA6E;IAC7E,GAAG,EAAE,MAAM,CAAC;IACZ,kDAAkD;IAClD,MAAM,CAAC,EAAE;QAAE,KAAK,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAA;KAAE,CAAC;CAClD;AAED;;;GAGG;AACH,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;
|
|
1
|
+
{"version":3,"file":"auto-research.d.ts","sourceRoot":"","sources":["../../src/relay/auto-research.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAKH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,KAAK,EAAE,oBAAoB,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAEpF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAM/C,oDAAoD;AACpD,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,+CAA+C;AAC/C,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,YAAY,CAAC;IACpB,OAAO,EAAE,oBAAoB,CAAC;IAC9B,KAAK,EAAE,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;IACjC;0DACsD;IACtD,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACrC,6EAA6E;IAC7E,GAAG,EAAE,MAAM,CAAC;IACZ,kDAAkD;IAClD,MAAM,CAAC,EAAE;QAAE,KAAK,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAA;KAAE,CAAC;CAClD;AAED;;;GAGG;AACH,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAgsBD;;;;;;;;;;;GAWG;AACH,wBAAsB,kBAAkB,CACtC,KAAK,EAAE,iBAAiB,EACxB,IAAI,EAAE,gBAAgB,GACrB,OAAO,CAAC,IAAI,CAAC,CAsLf"}
|
|
@@ -560,7 +560,6 @@ function buildAutoResearchTask(projectPath, projectName, preRunContext = null) {
|
|
|
560
560
|
" - For LLM-powered extensions, use `ctx.modelRegistry` to call models",
|
|
561
561
|
" - Create files under `.spectral/extensions/auto-research/<name>/`",
|
|
562
562
|
" - Each extension needs an `index.ts` that registers its tools/commands",
|
|
563
|
-
" - Read `.spectral/agents/auto-research-templates.md` for proven extension templates",
|
|
564
563
|
"",
|
|
565
564
|
"4. **Validation** — Verify generated extensions:",
|
|
566
565
|
" - Ensure all imports resolve to available packages (see reference above)",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routing.d.ts","sourceRoot":"","sources":["../../src/relay/routing.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"routing.d.ts","sourceRoot":"","sources":["../../src/relay/routing.ts"],"names":[],"mappings":"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"}
|
package/dist/relay/routing.js
CHANGED
|
@@ -687,7 +687,6 @@ export async function dispatchRoute(match, body, deps) {
|
|
|
687
687
|
case "put_prompt_mutation_settings":
|
|
688
688
|
return handlePutPromptMutationSettings(deps.cwd ?? homedir(), asObject(body), deps.agentDir);
|
|
689
689
|
case "list_agents": {
|
|
690
|
-
const agentCwd = match.query?.get("cwd") || deps.cwd || homedir();
|
|
691
690
|
const teamId = match.query?.get("teamId") || undefined;
|
|
692
691
|
// Kick off cloud refresh in the background without blocking the response.
|
|
693
692
|
// The previous version awaited refreshCloudAgents (network → backend GraphQL)
|
|
@@ -701,7 +700,7 @@ export async function dispatchRoute(match, body, deps) {
|
|
|
701
700
|
logger?.error?.(`[dispatcher] cloud agent refresh failed:`, err);
|
|
702
701
|
});
|
|
703
702
|
}
|
|
704
|
-
const agents = handleListAgents(
|
|
703
|
+
const agents = handleListAgents(teamId);
|
|
705
704
|
return agents;
|
|
706
705
|
}
|
|
707
706
|
case "list_dev_processes":
|
|
@@ -9,7 +9,7 @@ export { hasMissingRequiredArguments } from "./tool-execution.js";
|
|
|
9
9
|
/** Maximum consecutive tool call errors before terminating the loop. */
|
|
10
10
|
const MAX_CONSECUTIVE_TOOL_ERRORS = 10;
|
|
11
11
|
/** Maximum retries for transient provider API errors. */
|
|
12
|
-
const MAX_API_RETRIES =
|
|
12
|
+
const MAX_API_RETRIES = 8;
|
|
13
13
|
/** Base backoff (ms) for transient API error retries; doubles per attempt. */
|
|
14
14
|
const API_RETRY_BASE_MS = 1000;
|
|
15
15
|
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-bridge.d.ts","sourceRoot":"","sources":["../../src/server/agent-bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AAaH,OAAO,EAQL,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACtB,MAAM,8BAA8B,CAAC;AAatC,OAAO,EAEL,KAAK,aAAa,EACnB,MAAM,8BAA8B,CAAC;AActC,OAAO,EACL,kBAAkB,IAAI,yBAAyB,EAEhD,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAC1D,OAAO,KAAK,EAAE,eAAe,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"agent-bridge.d.ts","sourceRoot":"","sources":["../../src/server/agent-bridge.ts"],"names":[],"mappings":"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"}
|
|
@@ -67,6 +67,7 @@ import listSecretsExtension from "../extensions/list-secrets.js";
|
|
|
67
67
|
import observationalMemory from "../memory/index.js";
|
|
68
68
|
import { OBSERVATIONAL_MEMORY_CONTEXT_CUSTOM_TYPE, OBSERVATIONAL_MEMORY_SNAPSHOT_CUSTOM_TYPE, } from "../memory/types.js";
|
|
69
69
|
import { fetchAllowedModels as defaultFetchAllowedModels, } from "../relay/models-fetch.js";
|
|
70
|
+
import { annotatedUserMessageText } from "./attachments/persist.js";
|
|
70
71
|
import { humanizeProviderError } from "./error-humanizer.js";
|
|
71
72
|
import { readStudioBinding, getBindingFilePath } from "../studio-binding.js";
|
|
72
73
|
// Facade imports: cohesive helpers extracted verbatim to `./agent-bridge/` modules.
|
|
@@ -342,7 +343,7 @@ export class AgentBridge {
|
|
|
342
343
|
// (or the settings-level default when the session has no override)
|
|
343
344
|
// triggers injection. "__none__", null, legacy "__auto__"/"__inherit__"
|
|
344
345
|
// and unknown names all resolve to no agent — never auto-detect.
|
|
345
|
-
const primaryAgent = resolveSelectedPrimaryAgent(selectedName, this.opts.
|
|
346
|
+
const primaryAgent = resolveSelectedPrimaryAgent(selectedName, this.opts.teamId);
|
|
346
347
|
if (!primaryAgent)
|
|
347
348
|
return;
|
|
348
349
|
const injected = injectPrimaryAgentPrompt(event.systemPrompt, primaryAgent);
|
|
@@ -439,9 +440,19 @@ export class AgentBridge {
|
|
|
439
440
|
const imageBlocks = (msg.images ?? [])
|
|
440
441
|
.map(toImageContent)
|
|
441
442
|
.filter((block) => block !== null);
|
|
443
|
+
// Attachment persistence (Option A): annotate rehydrated user
|
|
444
|
+
// messages whose attachments are still on disk, so the LLM sees
|
|
445
|
+
// the same saved-at hint the original prompt carried. Attachments
|
|
446
|
+
// that were swept (or never persisted) leave the text untouched.
|
|
447
|
+
const text = annotatedUserMessageText({
|
|
448
|
+
cwd: this.opts.cwd,
|
|
449
|
+
sessionId: this.opts.sessionId,
|
|
450
|
+
content: msg.content,
|
|
451
|
+
images: msg.images,
|
|
452
|
+
});
|
|
442
453
|
const content = imageBlocks.length > 0
|
|
443
|
-
? [...imageBlocks, { type: "text", text
|
|
444
|
-
:
|
|
454
|
+
? [...imageBlocks, { type: "text", text }]
|
|
455
|
+
: text;
|
|
445
456
|
sessionManager.appendMessage({
|
|
446
457
|
role: "user",
|
|
447
458
|
content,
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TTL GC for persisted chat attachments (`.spectral/attachments/<id>/`).
|
|
3
|
+
*
|
|
4
|
+
* Mirrors `src/server/offload-gc.ts`: the sweep removes per-session
|
|
5
|
+
* directories whose session no longer exists AND whose directory mtime is
|
|
6
|
+
* older than `SPECTRAL_ATTACHMENT_TTL_DAYS` (default 7). Sessions that still
|
|
7
|
+
* exist in the store are never swept, however old their attachments are.
|
|
8
|
+
*
|
|
9
|
+
* Best-effort and synchronous: callers fire-and-forget it (server startup,
|
|
10
|
+
* first prompt). Never throws.
|
|
11
|
+
*
|
|
12
|
+
* @module @spectral/server/attachments/cleanup
|
|
13
|
+
*/
|
|
14
|
+
/** Session dirs older than this (in days) are swept when their session is gone. */
|
|
15
|
+
export declare const DEFAULT_ATTACHMENT_TTL_DAYS = 7;
|
|
16
|
+
/** Effective TTL in ms (override via `SPECTRAL_ATTACHMENT_TTL_DAYS`). */
|
|
17
|
+
export declare function getAttachmentTtlMs(): number;
|
|
18
|
+
export interface AttachmentSweepResult {
|
|
19
|
+
removedSessions: number;
|
|
20
|
+
removedBytes: number;
|
|
21
|
+
}
|
|
22
|
+
export interface SweepAttachmentsOptions {
|
|
23
|
+
/** `.spectral/attachments` root to sweep (per project cwd). */
|
|
24
|
+
root: string;
|
|
25
|
+
/**
|
|
26
|
+
* Session ids that still exist — their directories are NEVER swept,
|
|
27
|
+
* however old. Omitted = treat every session as gone (TTL-only sweep).
|
|
28
|
+
*/
|
|
29
|
+
activeSessionIds?: Iterable<string>;
|
|
30
|
+
/** Epoch ms "now" (tests). Defaults to `Date.now()`. */
|
|
31
|
+
now?: number;
|
|
32
|
+
/** TTL override in ms (tests). Defaults to `getAttachmentTtlMs()`. */
|
|
33
|
+
ttlMs?: number;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Remove stale attachment session directories. A directory is removed only
|
|
37
|
+
* when BOTH: its name matches no active session id AND its mtime is older
|
|
38
|
+
* than the TTL. Dotfiles (`.gitignore`) and stray non-directories are left
|
|
39
|
+
* alone. Never throws.
|
|
40
|
+
*/
|
|
41
|
+
export declare function sweepAttachments(options: SweepAttachmentsOptions): AttachmentSweepResult;
|
|
42
|
+
//# sourceMappingURL=cleanup.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cleanup.d.ts","sourceRoot":"","sources":["../../../src/server/attachments/cleanup.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAOH,mFAAmF;AACnF,eAAO,MAAM,2BAA2B,IAAI,CAAC;AAE7C,yEAAyE;AACzE,wBAAgB,kBAAkB,IAAI,MAAM,CAG3C;AAsBD,MAAM,WAAW,qBAAqB;IACpC,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,uBAAuB;IACtC,+DAA+D;IAC/D,IAAI,EAAE,MAAM,CAAC;IACb;;;OAGG;IACH,gBAAgB,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IACpC,wDAAwD;IACxD,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,sEAAsE;IACtE,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,uBAAuB,GAAG,qBAAqB,CAuCxF"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TTL GC for persisted chat attachments (`.spectral/attachments/<id>/`).
|
|
3
|
+
*
|
|
4
|
+
* Mirrors `src/server/offload-gc.ts`: the sweep removes per-session
|
|
5
|
+
* directories whose session no longer exists AND whose directory mtime is
|
|
6
|
+
* older than `SPECTRAL_ATTACHMENT_TTL_DAYS` (default 7). Sessions that still
|
|
7
|
+
* exist in the store are never swept, however old their attachments are.
|
|
8
|
+
*
|
|
9
|
+
* Best-effort and synchronous: callers fire-and-forget it (server startup,
|
|
10
|
+
* first prompt). Never throws.
|
|
11
|
+
*
|
|
12
|
+
* @module @spectral/server/attachments/cleanup
|
|
13
|
+
*/
|
|
14
|
+
import { existsSync, readdirSync, rmSync, statSync } from "node:fs";
|
|
15
|
+
import { join } from "node:path";
|
|
16
|
+
import { envPositiveInt } from "../../sdk/coding-agent/core/tools/offload.js";
|
|
17
|
+
/** Session dirs older than this (in days) are swept when their session is gone. */
|
|
18
|
+
export const DEFAULT_ATTACHMENT_TTL_DAYS = 7;
|
|
19
|
+
/** Effective TTL in ms (override via `SPECTRAL_ATTACHMENT_TTL_DAYS`). */
|
|
20
|
+
export function getAttachmentTtlMs() {
|
|
21
|
+
return envPositiveInt("SPECTRAL_ATTACHMENT_TTL_DAYS", DEFAULT_ATTACHMENT_TTL_DAYS) *
|
|
22
|
+
24 * 60 * 60 * 1000;
|
|
23
|
+
}
|
|
24
|
+
function dirSizeBytes(dir) {
|
|
25
|
+
let total = 0;
|
|
26
|
+
let entries;
|
|
27
|
+
try {
|
|
28
|
+
entries = readdirSync(dir, { withFileTypes: true });
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
return 0;
|
|
32
|
+
}
|
|
33
|
+
for (const entry of entries) {
|
|
34
|
+
const full = join(dir, entry.name);
|
|
35
|
+
try {
|
|
36
|
+
if (entry.isDirectory())
|
|
37
|
+
total += dirSizeBytes(full);
|
|
38
|
+
else if (entry.isFile())
|
|
39
|
+
total += statSync(full).size;
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
// Skip unreadable entries — GC is best-effort.
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return total;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Remove stale attachment session directories. A directory is removed only
|
|
49
|
+
* when BOTH: its name matches no active session id AND its mtime is older
|
|
50
|
+
* than the TTL. Dotfiles (`.gitignore`) and stray non-directories are left
|
|
51
|
+
* alone. Never throws.
|
|
52
|
+
*/
|
|
53
|
+
export function sweepAttachments(options) {
|
|
54
|
+
const result = { removedSessions: 0, removedBytes: 0 };
|
|
55
|
+
const { root } = options;
|
|
56
|
+
if (!root || !existsSync(root))
|
|
57
|
+
return result;
|
|
58
|
+
const active = new Set(options.activeSessionIds ?? []);
|
|
59
|
+
const ttlMs = options.ttlMs ?? getAttachmentTtlMs();
|
|
60
|
+
const now = options.now ?? Date.now();
|
|
61
|
+
let entries;
|
|
62
|
+
try {
|
|
63
|
+
entries = readdirSync(root, { withFileTypes: true });
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
return result;
|
|
67
|
+
}
|
|
68
|
+
for (const entry of entries) {
|
|
69
|
+
// Only sweep session directories; leave `.gitignore` and strays alone.
|
|
70
|
+
if (!entry.isDirectory() || entry.name.startsWith("."))
|
|
71
|
+
continue;
|
|
72
|
+
if (active.has(entry.name))
|
|
73
|
+
continue;
|
|
74
|
+
const dir = join(root, entry.name);
|
|
75
|
+
let mtimeMs;
|
|
76
|
+
try {
|
|
77
|
+
const stat = statSync(dir);
|
|
78
|
+
if (!stat.isDirectory())
|
|
79
|
+
continue;
|
|
80
|
+
mtimeMs = stat.mtimeMs;
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
// `stat.mtimeMs` carries sub-ms precision while `Date.now()` does not —
|
|
86
|
+
// floor it so a directory created in the same millisecond as `now`
|
|
87
|
+
// (ttlMs = 0) is deterministically "older".
|
|
88
|
+
if (now - Math.floor(mtimeMs) < ttlMs)
|
|
89
|
+
continue;
|
|
90
|
+
try {
|
|
91
|
+
result.removedBytes += dirSizeBytes(dir);
|
|
92
|
+
rmSync(dir, { recursive: true, force: true });
|
|
93
|
+
result.removedSessions += 1;
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
// Best-effort.
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return result;
|
|
100
|
+
}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Attachment persistence (Option A) for Studio /agent image attachments.
|
|
3
|
+
*
|
|
4
|
+
* User-attached images arrive as relay `ImageAttachment`s — either inline
|
|
5
|
+
* base64 (`data`, legacy/small) or a backend-hosted url (`url`, optionally
|
|
6
|
+
* `imageId`). LLM providers see those natively, but agent TOOLS do not: a
|
|
7
|
+
* tool such as `image_generate` (reference images) or `read` can only use
|
|
8
|
+
* normal file paths. This module writes every attachment to
|
|
9
|
+
*
|
|
10
|
+
* <cwd>/.spectral/attachments/<sanitized sessionId>/<name>.<ext>
|
|
11
|
+
*
|
|
12
|
+
* so the prompt can be annotated with the saved absolute paths (see
|
|
13
|
+
* `formatAttachmentAnnotation`) and the agent can use the images as files.
|
|
14
|
+
*
|
|
15
|
+
* Guarantees:
|
|
16
|
+
* - NEVER throws and never rejects: every failure (fetch error, fs error,
|
|
17
|
+
* base64 decode) is reported through `onWarn` and the prompt proceeds.
|
|
18
|
+
* - Idempotent: the same imageId (or content hash) always maps to the same
|
|
19
|
+
* path, so re-sending an attachment overwrites the same file.
|
|
20
|
+
* - Sandboxed: every path segment is stripped to `[A-Za-z0-9_-]`, so a
|
|
21
|
+
* malicious sessionId/imageId/url can never traverse (`..` contains
|
|
22
|
+
* only dots → stripped → falls back to a safe name).
|
|
23
|
+
* - Capped: per-session file count and total size (both named consts).
|
|
24
|
+
*
|
|
25
|
+
* The stored session history is NEVER rewritten: callers keep persisting the
|
|
26
|
+
* original content to SQLite and only annotate the text handed to the agent.
|
|
27
|
+
*
|
|
28
|
+
* @module @spectral/server/attachments/persist
|
|
29
|
+
*/
|
|
30
|
+
import type { ImageAttachment } from "../wire.js";
|
|
31
|
+
/** Max persisted files per session directory — beyond this, persistence is skipped. */
|
|
32
|
+
export declare const MAX_FILES_PER_SESSION = 50;
|
|
33
|
+
/** Max total bytes per session directory (200 MB) — beyond this, persistence is skipped. */
|
|
34
|
+
export declare const MAX_TOTAL_ATTACHMENT_BYTES: number;
|
|
35
|
+
/** Wall-clock budget for one `persistAttachments()` call (url fetches dominate). */
|
|
36
|
+
export declare const PERSIST_DEADLINE_MS = 30000;
|
|
37
|
+
/** Per-request timeout for fetching a hosted/foreign image. */
|
|
38
|
+
export declare const FETCH_ATTACHMENT_TIMEOUT_MS = 10000;
|
|
39
|
+
/**
|
|
40
|
+
* Strip a path segment to `[A-Za-z0-9_-]` (length-capped). `..`, `/`, `\`,
|
|
41
|
+
* percent-encodings and unicode are all removed, so traversal is impossible:
|
|
42
|
+
* a fully-stripped segment collapses to `fallback` instead of becoming `""`.
|
|
43
|
+
*/
|
|
44
|
+
export declare function sanitizeSegment(input: string, fallback: string): string;
|
|
45
|
+
export declare function attachmentExtension(mimeType: string): string | null;
|
|
46
|
+
/**
|
|
47
|
+
* Sanitized file stem for an attachment, chosen deterministically so the
|
|
48
|
+
* same attachment always maps to the same path (idempotency):
|
|
49
|
+
* 1. sanitized `imageId`,
|
|
50
|
+
* 2. hosted image id extracted from `url`,
|
|
51
|
+
* 3. sha256 of `url` (foreign urls),
|
|
52
|
+
* 4. sha256 of the inline `data` payload.
|
|
53
|
+
* `null` when the attachment has none of the above.
|
|
54
|
+
*/
|
|
55
|
+
export declare function attachmentFileStem(image: ImageAttachment): string | null;
|
|
56
|
+
/** `stem.ext` for an attachment, or `null` when the mime/stem is unusable. */
|
|
57
|
+
export declare function attachmentFileName(image: ImageAttachment): string | null;
|
|
58
|
+
/** `<cwd>/.spectral/attachments` — the sweep root. Always absolute. */
|
|
59
|
+
export declare function attachmentsRootFor(cwd: string): string;
|
|
60
|
+
/** Per-session directory under the attachments root. Always absolute. */
|
|
61
|
+
export declare function attachmentsSessionDirFor(cwd: string, sessionId: string): string;
|
|
62
|
+
/** Absolute path an attachment would be persisted to, or `null` when unusable. */
|
|
63
|
+
export declare function attachmentPathFor(cwd: string, sessionId: string, image: ImageAttachment): string | null;
|
|
64
|
+
/**
|
|
65
|
+
* The persisted paths that still exist on disk for a message's attachments.
|
|
66
|
+
* Used by history rehydration: the annotation is only appended for files
|
|
67
|
+
* that are actually readable — an attachment persisted days ago may have
|
|
68
|
+
* been swept by `sweepAttachments()` in the meantime.
|
|
69
|
+
*/
|
|
70
|
+
export declare function existingAttachmentPaths(cwd: string, sessionId: string, images?: ImageAttachment[]): string[];
|
|
71
|
+
/**
|
|
72
|
+
* Prompt annotation for persisted attachments, e.g.
|
|
73
|
+
* `"\n\n[Attached images saved at: /abs/a.png, /abs/b.jpg]"`.
|
|
74
|
+
* Empty string when no path survived (nothing persisted / none exist).
|
|
75
|
+
*/
|
|
76
|
+
export declare function formatAttachmentAnnotation(paths: readonly string[]): string;
|
|
77
|
+
/**
|
|
78
|
+
* Rehydration twin of the prompt annotation: `content` plus the saved-at
|
|
79
|
+
* annotation for attachments that still exist on disk. Used by
|
|
80
|
+
* `agent-bridge.ts` when rebuilding prior user messages from
|
|
81
|
+
* `messages.images_json`, so the LLM context matches what the original
|
|
82
|
+
* prompt carried. Content is returned unchanged when nothing exists.
|
|
83
|
+
*/
|
|
84
|
+
export declare function annotatedUserMessageText(options: {
|
|
85
|
+
cwd: string;
|
|
86
|
+
sessionId?: string;
|
|
87
|
+
content: string;
|
|
88
|
+
images?: ImageAttachment[];
|
|
89
|
+
}): string;
|
|
90
|
+
/** One successfully persisted attachment. */
|
|
91
|
+
export interface PersistedAttachment {
|
|
92
|
+
path: string;
|
|
93
|
+
bytes: number;
|
|
94
|
+
}
|
|
95
|
+
export interface PersistAttachmentsInput {
|
|
96
|
+
/** Sanitized into the directory segment — never used raw. */
|
|
97
|
+
sessionId: string;
|
|
98
|
+
/** Project cwd; attachments land under `<cwd>/.spectral/attachments/`. */
|
|
99
|
+
cwd: string;
|
|
100
|
+
images?: ImageAttachment[];
|
|
101
|
+
/**
|
|
102
|
+
* Backend routing override. `serve.ts` already resolved both (the same
|
|
103
|
+
* credentials AgentBridge uses for inference), so the server passes them
|
|
104
|
+
* in instead of re-reading config + machine store. Falls back to
|
|
105
|
+
* `resolveBackendRouting()` when omitted.
|
|
106
|
+
*/
|
|
107
|
+
backendUrl?: string;
|
|
108
|
+
machineJwt?: string;
|
|
109
|
+
/** Injectable fetch for tests / alternative runtimes. */
|
|
110
|
+
fetchImpl?: typeof fetch;
|
|
111
|
+
/** Diagnostics sink — failures warn and continue. */
|
|
112
|
+
onWarn?: (message: string) => void;
|
|
113
|
+
/** Deadline override (tests). Defaults to `PERSIST_DEADLINE_MS`. */
|
|
114
|
+
deadlineMs?: number;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Persist every usable attachment of a user message to disk and return the
|
|
118
|
+
* saved absolute paths (annotation input). NEVER throws and never rejects:
|
|
119
|
+
* every per-image failure warns and continues, and the prompt must always
|
|
120
|
+
* proceed — a missing file is a degradation, not an error.
|
|
121
|
+
*
|
|
122
|
+
* Per-image flow:
|
|
123
|
+
* - `{data}` → base64-decoded and written directly,
|
|
124
|
+
* - `{url}` → bytes fetched through the hosted resolver machinery.
|
|
125
|
+
*
|
|
126
|
+
* Skips (with a warning) when: the mime type is outside the allowlist, the
|
|
127
|
+
* per-session file cap / total size cap / wall-clock deadline is reached, or
|
|
128
|
+
* the fetch/write fails.
|
|
129
|
+
*/
|
|
130
|
+
export declare function persistAttachments(input: PersistAttachmentsInput): Promise<PersistedAttachment[]>;
|
|
131
|
+
//# sourceMappingURL=persist.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"persist.d.ts","sourceRoot":"","sources":["../../../src/server/attachments/persist.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAaH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AASlD,uFAAuF;AACvF,eAAO,MAAM,qBAAqB,KAAK,CAAC;AAExC,4FAA4F;AAC5F,eAAO,MAAM,0BAA0B,QAAoB,CAAC;AAE5D,oFAAoF;AACpF,eAAO,MAAM,mBAAmB,QAAS,CAAC;AAE1C,+DAA+D;AAC/D,eAAO,MAAM,2BAA2B,QAAS,CAAC;AAiBlD;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAGvE;AAeD,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAInE;AAMD;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM,GAAG,IAAI,CAYxE;AAED,8EAA8E;AAC9E,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM,GAAG,IAAI,CAMxE;AAED,uEAAuE;AACvE,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED,yEAAyE;AACzE,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAE/E;AAED,kFAAkF;AAClF,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,eAAe,GACrB,MAAM,GAAG,IAAI,CAIf;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CACrC,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,MAAM,EACjB,MAAM,CAAC,EAAE,eAAe,EAAE,GACzB,MAAM,EAAE,CAaV;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAM3E;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE;IAChD,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,eAAe,EAAE,CAAC;CAC5B,GAAG,MAAM,CAGT;AAED,6CAA6C;AAC7C,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,uBAAuB;IACtC,6DAA6D;IAC7D,SAAS,EAAE,MAAM,CAAC;IAClB,0EAA0E;IAC1E,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,eAAe,EAAE,CAAC;IAC3B;;;;;OAKG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,yDAAyD;IACzD,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IACzB,qDAAqD;IACrD,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,oEAAoE;IACpE,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AA4JD;;;;;;;;;;;;;GAaG;AACH,wBAAsB,kBAAkB,CACtC,KAAK,EAAE,uBAAuB,GAC7B,OAAO,CAAC,mBAAmB,EAAE,CAAC,CA8EhC"}
|