@gricha/perry 0.1.5 → 0.1.7
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/dist/agent/router.js +72 -34
- package/dist/agent/run.js +3 -0
- package/dist/agent/web/assets/index-BTiTEcB0.js +104 -0
- package/dist/agent/web/assets/index-D2_-UqVf.css +1 -0
- package/dist/agent/web/index.html +2 -2
- package/dist/config/loader.js +16 -0
- package/dist/index.js +185 -1
- package/dist/sessions/cache.js +52 -0
- package/dist/ssh/discovery.js +96 -0
- package/dist/ssh/index.js +2 -0
- package/dist/ssh/sync.js +80 -0
- package/dist/workspace/manager.js +63 -4
- package/dist/workspace/state.js +9 -0
- package/package.json +3 -2
- package/dist/agent/web/assets/index-BGbqUzMS.js +0 -104
- package/dist/agent/web/assets/index-CHEQQv1U.css +0 -1
package/dist/agent/router.js
CHANGED
|
@@ -7,6 +7,7 @@ import { HOST_WORKSPACE_NAME } from '../shared/types';
|
|
|
7
7
|
import { getDockerVersion, execInContainer } from '../docker';
|
|
8
8
|
import { saveAgentConfig } from '../config/loader';
|
|
9
9
|
import { setSessionName, getSessionNamesForWorkspace, deleteSessionName, } from '../sessions/metadata';
|
|
10
|
+
import { discoverSSHKeys } from '../ssh/discovery';
|
|
10
11
|
import { parseClaudeSessionContent } from '../sessions/parser';
|
|
11
12
|
import { discoverAllSessions, getSessionDetails as getAgentSessionDetails, getSessionMessages, findSessionMessages, } from '../sessions/agents';
|
|
12
13
|
const WorkspaceStatusSchema = z.enum(['running', 'stopped', 'creating', 'error']);
|
|
@@ -21,6 +22,7 @@ const WorkspaceInfoSchema = z.object({
|
|
|
21
22
|
created: z.string(),
|
|
22
23
|
repo: z.string().optional(),
|
|
23
24
|
ports: WorkspacePortsSchema,
|
|
25
|
+
lastUsed: z.string().optional(),
|
|
24
26
|
});
|
|
25
27
|
const CredentialsSchema = z.object({
|
|
26
28
|
env: z.record(z.string(), z.string()),
|
|
@@ -47,6 +49,23 @@ const CodingAgentsSchema = z.object({
|
|
|
47
49
|
})
|
|
48
50
|
.optional(),
|
|
49
51
|
});
|
|
52
|
+
const SSHKeyConfigSchema = z.object({
|
|
53
|
+
copy: z.array(z.string()),
|
|
54
|
+
authorize: z.array(z.string()),
|
|
55
|
+
});
|
|
56
|
+
const SSHSettingsSchema = z.object({
|
|
57
|
+
autoAuthorizeHostKeys: z.boolean(),
|
|
58
|
+
global: SSHKeyConfigSchema,
|
|
59
|
+
workspaces: z.record(z.string(), SSHKeyConfigSchema.partial()),
|
|
60
|
+
});
|
|
61
|
+
const SSHKeyInfoSchema = z.object({
|
|
62
|
+
name: z.string(),
|
|
63
|
+
path: z.string(),
|
|
64
|
+
publicKeyPath: z.string(),
|
|
65
|
+
type: z.enum(['ed25519', 'rsa', 'ecdsa', 'dsa', 'unknown']),
|
|
66
|
+
fingerprint: z.string(),
|
|
67
|
+
hasPrivateKey: z.boolean(),
|
|
68
|
+
});
|
|
50
69
|
function mapErrorToORPC(err, defaultMessage) {
|
|
51
70
|
const message = err instanceof Error ? err.message : defaultMessage;
|
|
52
71
|
if (message.includes('not found')) {
|
|
@@ -154,6 +173,16 @@ export function createRouter(ctx) {
|
|
|
154
173
|
results,
|
|
155
174
|
};
|
|
156
175
|
});
|
|
176
|
+
const touchWorkspace = os
|
|
177
|
+
.input(z.object({ name: z.string() }))
|
|
178
|
+
.output(WorkspaceInfoSchema)
|
|
179
|
+
.handler(async ({ input }) => {
|
|
180
|
+
const workspace = await ctx.workspaces.touch(input.name);
|
|
181
|
+
if (!workspace) {
|
|
182
|
+
throw new ORPCError('NOT_FOUND', { message: 'Workspace not found' });
|
|
183
|
+
}
|
|
184
|
+
return workspace;
|
|
185
|
+
});
|
|
157
186
|
const getInfo = os.handler(async () => {
|
|
158
187
|
let dockerVersion = 'unknown';
|
|
159
188
|
try {
|
|
@@ -210,6 +239,27 @@ export function createRouter(ctx) {
|
|
|
210
239
|
await saveAgentConfig(newConfig, ctx.configDir);
|
|
211
240
|
return input;
|
|
212
241
|
});
|
|
242
|
+
const getSSHSettings = os.output(SSHSettingsSchema).handler(async () => {
|
|
243
|
+
const config = ctx.config.get();
|
|
244
|
+
return (config.ssh || {
|
|
245
|
+
autoAuthorizeHostKeys: true,
|
|
246
|
+
global: { copy: [], authorize: [] },
|
|
247
|
+
workspaces: {},
|
|
248
|
+
});
|
|
249
|
+
});
|
|
250
|
+
const updateSSHSettings = os
|
|
251
|
+
.input(SSHSettingsSchema)
|
|
252
|
+
.output(SSHSettingsSchema)
|
|
253
|
+
.handler(async ({ input }) => {
|
|
254
|
+
const currentConfig = ctx.config.get();
|
|
255
|
+
const newConfig = { ...currentConfig, ssh: input };
|
|
256
|
+
ctx.config.set(newConfig);
|
|
257
|
+
await saveAgentConfig(newConfig, ctx.configDir);
|
|
258
|
+
return input;
|
|
259
|
+
});
|
|
260
|
+
const listSSHKeys = os.output(z.array(SSHKeyInfoSchema)).handler(async () => {
|
|
261
|
+
return discoverSSHKeys();
|
|
262
|
+
});
|
|
213
263
|
async function listHostSessions(input) {
|
|
214
264
|
const limit = input.limit ?? 50;
|
|
215
265
|
const offset = input.offset ?? 0;
|
|
@@ -550,42 +600,23 @@ export function createRouter(ctx) {
|
|
|
550
600
|
await deleteSessionName(ctx.stateDir, input.workspaceName, input.sessionId);
|
|
551
601
|
return { success: true };
|
|
552
602
|
});
|
|
553
|
-
const
|
|
603
|
+
const getRecentSessions = os
|
|
554
604
|
.input(z.object({
|
|
555
|
-
|
|
556
|
-
limit: z.number().optional().default(100),
|
|
557
|
-
offset: z.number().optional().default(0),
|
|
605
|
+
limit: z.number().optional().default(10),
|
|
558
606
|
}))
|
|
559
607
|
.handler(async ({ input }) => {
|
|
560
|
-
const
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
allSessions.push({
|
|
573
|
-
...session,
|
|
574
|
-
workspaceName: workspace.name,
|
|
575
|
-
});
|
|
576
|
-
}
|
|
577
|
-
}
|
|
578
|
-
catch {
|
|
579
|
-
continue;
|
|
580
|
-
}
|
|
581
|
-
}
|
|
582
|
-
allSessions.sort((a, b) => new Date(b.lastActivity).getTime() - new Date(a.lastActivity).getTime());
|
|
583
|
-
const paginatedSessions = allSessions.slice(input.offset, input.offset + input.limit);
|
|
584
|
-
return {
|
|
585
|
-
sessions: paginatedSessions,
|
|
586
|
-
total: allSessions.length,
|
|
587
|
-
hasMore: input.offset + input.limit < allSessions.length,
|
|
588
|
-
};
|
|
608
|
+
const recent = await ctx.sessionsCache.getRecent(input.limit);
|
|
609
|
+
return { sessions: recent };
|
|
610
|
+
});
|
|
611
|
+
const recordSessionAccess = os
|
|
612
|
+
.input(z.object({
|
|
613
|
+
workspaceName: z.string(),
|
|
614
|
+
sessionId: z.string(),
|
|
615
|
+
agentType: z.enum(['claude-code', 'opencode', 'codex']),
|
|
616
|
+
}))
|
|
617
|
+
.handler(async ({ input }) => {
|
|
618
|
+
await ctx.sessionsCache.recordAccess(input.workspaceName, input.sessionId, input.agentType);
|
|
619
|
+
return { success: true };
|
|
589
620
|
});
|
|
590
621
|
const getHostInfo = os.handler(async () => {
|
|
591
622
|
const config = ctx.config.get();
|
|
@@ -621,13 +652,15 @@ export function createRouter(ctx) {
|
|
|
621
652
|
logs: getLogs,
|
|
622
653
|
sync: syncWorkspace,
|
|
623
654
|
syncAll: syncAllWorkspaces,
|
|
655
|
+
touch: touchWorkspace,
|
|
624
656
|
},
|
|
625
657
|
sessions: {
|
|
626
658
|
list: listSessions,
|
|
627
|
-
listAll: listAllSessions,
|
|
628
659
|
get: getSession,
|
|
629
660
|
rename: renameSession,
|
|
630
661
|
clearName: clearSessionName,
|
|
662
|
+
getRecent: getRecentSessions,
|
|
663
|
+
recordAccess: recordSessionAccess,
|
|
631
664
|
},
|
|
632
665
|
host: {
|
|
633
666
|
info: getHostInfo,
|
|
@@ -647,6 +680,11 @@ export function createRouter(ctx) {
|
|
|
647
680
|
get: getAgents,
|
|
648
681
|
update: updateAgents,
|
|
649
682
|
},
|
|
683
|
+
ssh: {
|
|
684
|
+
get: getSSHSettings,
|
|
685
|
+
update: updateSSHSettings,
|
|
686
|
+
listKeys: listSSHKeys,
|
|
687
|
+
},
|
|
650
688
|
},
|
|
651
689
|
};
|
|
652
690
|
}
|
package/dist/agent/run.js
CHANGED
|
@@ -10,6 +10,7 @@ import { ChatWebSocketServer } from '../chat/websocket';
|
|
|
10
10
|
import { OpencodeWebSocketServer } from '../chat/opencode-websocket';
|
|
11
11
|
import { createRouter } from './router';
|
|
12
12
|
import { serveStatic } from './static';
|
|
13
|
+
import { SessionsCacheManager } from '../sessions/cache';
|
|
13
14
|
import pkg from '../../package.json';
|
|
14
15
|
const startTime = Date.now();
|
|
15
16
|
function sendJson(res, status, data) {
|
|
@@ -19,6 +20,7 @@ function sendJson(res, status, data) {
|
|
|
19
20
|
function createAgentServer(configDir, config) {
|
|
20
21
|
let currentConfig = config;
|
|
21
22
|
const workspaces = new WorkspaceManager(configDir, currentConfig);
|
|
23
|
+
const sessionsCache = new SessionsCacheManager(configDir);
|
|
22
24
|
const isWorkspaceRunning = async (name) => {
|
|
23
25
|
if (name === HOST_WORKSPACE_NAME) {
|
|
24
26
|
return currentConfig.allowHostAccess === true;
|
|
@@ -52,6 +54,7 @@ function createAgentServer(configDir, config) {
|
|
|
52
54
|
stateDir: configDir,
|
|
53
55
|
startTime,
|
|
54
56
|
terminalServer,
|
|
57
|
+
sessionsCache,
|
|
55
58
|
});
|
|
56
59
|
const rpcHandler = new RPCHandler(router);
|
|
57
60
|
const server = createServer(async (req, res) => {
|