salmon-loop 0.3.1 → 0.3.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.
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import crypto from 'node:crypto';
|
|
1
2
|
import { normalizePermissionMode } from '../../core/config/index.js';
|
|
2
3
|
import { buildA2AAgentCard, createAcpFormalAgent, createAgentServerRuntime, createInteractionFacade, createSalmonTaskExecutor, createTaskEventBus, createPluginRegistry, createPromptRegistry, getUserAcpSessionStorePath, GitSnapshotCheckpointService, getLogger, mergeResolvedExtensions, PACKAGE_VERSION, PlainReporter, PluginLoader, resolveExtensions, resolveExecutionProfile, runSalmonLoop, setPluginRegistry, setPromptRegistry, startAcpStdioServer, StderrReporter, } from '../../core/facades/cli-serve.js';
|
|
3
4
|
import { readPlan } from '../../core/plan/index.js';
|
|
@@ -222,7 +223,19 @@ export async function handleServeCommand(_options, command) {
|
|
|
222
223
|
return;
|
|
223
224
|
}
|
|
224
225
|
const [scheme, token] = authHeader.split(' ');
|
|
225
|
-
|
|
226
|
+
let isAuthenticated = false;
|
|
227
|
+
if (scheme?.toLowerCase() === 'bearer' && token) {
|
|
228
|
+
const tokenBuffer = Buffer.from(token);
|
|
229
|
+
for (const authToken of authTokens) {
|
|
230
|
+
const authTokenBuffer = Buffer.from(authToken);
|
|
231
|
+
if (tokenBuffer.length === authTokenBuffer.length &&
|
|
232
|
+
crypto.timingSafeEqual(tokenBuffer, authTokenBuffer)) {
|
|
233
|
+
isAuthenticated = true;
|
|
234
|
+
break;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
if (!isAuthenticated) {
|
|
226
239
|
res.status(401).json({ error: 'Unauthorized' });
|
|
227
240
|
return;
|
|
228
241
|
}
|
|
@@ -14,7 +14,7 @@ export const CommandSuggestionList = ({ suggestions, selectedIndex, parentComman
|
|
|
14
14
|
return (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: COLORS.border.subtle, marginTop: 0, marginBottom: 0, paddingX: 0, width: "100%", children: [_jsx(Box, { flexDirection: "column", paddingY: 0, children: suggestions.map((item, index) => {
|
|
15
15
|
const isSelected = index === selectedIndex;
|
|
16
16
|
const hasSubcommands = !!item.command?.subcommands?.length;
|
|
17
|
-
return (_jsxs(Box, { flexDirection: "row", paddingX: 1, children: [_jsx(Box, { width: 2, children: _jsx(Text, { color: COLORS.semantic.salmon, children: isSelected ? '
|
|
17
|
+
return (_jsxs(Box, { flexDirection: "row", paddingX: 1, children: [_jsx(Box, { width: 2, children: _jsx(Text, { color: COLORS.semantic.salmon, children: isSelected ? '❯ ' : ' ' }) }), _jsx(Box, { width: maxNameLength + 4, children: _jsx(Text, { color: isSelected ? COLORS.semantic.cyan : COLORS.semantic.blue, bold: isSelected, children: item.name }) }), _jsx(Box, { width: 2, marginRight: 1, children: hasSubcommands ? _jsx(Text, { color: COLORS.text.muted, children: "\u203A" }) : _jsx(Text, { children: " " }) }), _jsx(Box, { flexGrow: 1, children: _jsx(Text, { color: isSelected ? COLORS.text.primary : COLORS.text.muted, wrap: "truncate", children: item.description }) })] }, `${item.name}-${index}`));
|
|
18
18
|
}) }), suggestions[selectedIndex]?.command?.usage && (_jsxs(Box, { flexDirection: "row", borderStyle: "single", borderTop: true, borderLeft: false, borderRight: false, borderBottom: false, borderColor: COLORS.border.subtle, paddingX: 1, paddingY: 0, children: [_jsx(Text, { color: COLORS.semantic.blue, children: "TIP: " }), _jsx(Text, { color: COLORS.text.muted, children: "Usage: " }), _jsx(Text, { color: COLORS.text.primary, children: suggestions[selectedIndex].command?.usage })] })), _jsxs(Box, { flexDirection: "row", borderStyle: "single", borderTop: true, borderLeft: false, borderRight: false, borderBottom: false, borderColor: COLORS.border.subtle, paddingX: 1, paddingY: 0, justifyContent: "space-between", children: [_jsxs(Box, { children: [_jsx(Text, { color: COLORS.semantic.salmon, children: "\u2502 " }), _jsx(Text, { color: COLORS.semantic.blue, bold: true, children: title })] }), _jsx(Box, { children: _jsx(Text, { color: COLORS.text.muted, dimColor: true, children: "\u2191\u2193 nav \u00B7 \u23CE select \u00B7 esc close" }) })] })] }));
|
|
19
19
|
};
|
|
20
20
|
//# sourceMappingURL=CommandSuggestionList.js.map
|
|
@@ -214,25 +214,48 @@ export class ContextService {
|
|
|
214
214
|
return true;
|
|
215
215
|
}
|
|
216
216
|
async evictExpiredEntries() {
|
|
217
|
-
|
|
218
|
-
|
|
217
|
+
const entries = Array.from(await this.cacheStore.entries());
|
|
218
|
+
const now = Date.now();
|
|
219
|
+
const expiredEntries = entries.filter(([, entry]) => {
|
|
220
|
+
const last = this.getEntryTimestamp(entry);
|
|
221
|
+
return last && now - last > this.cacheTtlMs;
|
|
222
|
+
});
|
|
223
|
+
for (let i = 0; i < expiredEntries.length; i += 10) {
|
|
224
|
+
const chunk = expiredEntries.slice(i, i + 10);
|
|
225
|
+
await Promise.all(chunk.map(([key, entry]) => this.isExpired(key, entry)));
|
|
219
226
|
}
|
|
220
227
|
}
|
|
221
228
|
async evictLruIfNeeded() {
|
|
222
|
-
|
|
229
|
+
const size = await this.cacheStore.size();
|
|
230
|
+
if (size <= this.cacheMaxEntries)
|
|
231
|
+
return;
|
|
232
|
+
const excess = size - this.cacheMaxEntries;
|
|
233
|
+
const entries = Array.from(await this.cacheStore.entries());
|
|
234
|
+
if (excess === 1) {
|
|
223
235
|
let victimKey;
|
|
224
236
|
let victimTs = Number.POSITIVE_INFINITY;
|
|
225
|
-
for (const [key, entry] of
|
|
237
|
+
for (const [key, entry] of entries) {
|
|
226
238
|
const ts = this.getEntryTimestamp(entry);
|
|
227
239
|
if (ts < victimTs) {
|
|
228
240
|
victimTs = ts;
|
|
229
241
|
victimKey = key;
|
|
230
242
|
}
|
|
231
243
|
}
|
|
232
|
-
if (
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
244
|
+
if (victimKey) {
|
|
245
|
+
await this.cacheStore.delete(victimKey);
|
|
246
|
+
this.cacheMetrics.evictions += 1;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
else {
|
|
250
|
+
entries.sort((a, b) => (this.getEntryTimestamp(a[1]) || 0) - (this.getEntryTimestamp(b[1]) || 0));
|
|
251
|
+
const victims = entries.slice(0, excess);
|
|
252
|
+
for (let i = 0; i < victims.length; i += 10) {
|
|
253
|
+
const chunk = victims.slice(i, i + 10);
|
|
254
|
+
await Promise.all(chunk.map(async ([key]) => {
|
|
255
|
+
await this.cacheStore.delete(key);
|
|
256
|
+
this.cacheMetrics.evictions += 1;
|
|
257
|
+
}));
|
|
258
|
+
}
|
|
236
259
|
}
|
|
237
260
|
}
|
|
238
261
|
async getCacheStats() {
|
|
@@ -306,19 +306,26 @@ export class ChatSessionManager {
|
|
|
306
306
|
const analysis = this.pruningEngine.analyzeSessions(sessions);
|
|
307
307
|
let deleted = 0;
|
|
308
308
|
let archived = 0;
|
|
309
|
+
const CHUNK_SIZE = 10;
|
|
309
310
|
// Delete low-priority sessions
|
|
310
|
-
for (
|
|
311
|
-
|
|
312
|
-
|
|
311
|
+
for (let i = 0; i < analysis.sessionsToDelete.length; i += CHUNK_SIZE) {
|
|
312
|
+
const chunk = analysis.sessionsToDelete.slice(i, i + CHUNK_SIZE);
|
|
313
|
+
await Promise.all(chunk.map(async (sessionId) => {
|
|
314
|
+
await this.deleteSession(sessionId);
|
|
315
|
+
deleted++;
|
|
316
|
+
}));
|
|
313
317
|
}
|
|
314
318
|
// Archive medium-priority sessions
|
|
315
|
-
for (
|
|
316
|
-
const
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
319
|
+
for (let i = 0; i < analysis.sessionsToArchive.length; i += CHUNK_SIZE) {
|
|
320
|
+
const chunk = analysis.sessionsToArchive.slice(i, i + CHUNK_SIZE);
|
|
321
|
+
await Promise.all(chunk.map(async (sessionId) => {
|
|
322
|
+
const session = sessions.find((s) => s.meta.id === sessionId);
|
|
323
|
+
if (session) {
|
|
324
|
+
await this.archiveSession(session);
|
|
325
|
+
await this.deleteSession(sessionId);
|
|
326
|
+
archived++;
|
|
327
|
+
}
|
|
328
|
+
}));
|
|
322
329
|
}
|
|
323
330
|
return {
|
|
324
331
|
deleted,
|