@parall/claude-agent 1.15.1

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.
@@ -0,0 +1,87 @@
1
+ import * as fs from "node:fs";
2
+ import * as path from "node:path";
3
+ import { randomUUID } from "node:crypto";
4
+ import type { ForkSessionHandle } from "@parall/agent-core";
5
+
6
+ type PersistedMainSession = {
7
+ runtimeKey: string;
8
+ sessionId: string;
9
+ };
10
+
11
+ type ClaudeSessionManagerLogger = {
12
+ warn(message: string): void;
13
+ };
14
+
15
+ export class ClaudeSessionManager {
16
+ private readonly sessionIds = new Map<string, string>();
17
+ private readonly pendingForkParents = new Map<string, string>();
18
+
19
+ constructor(
20
+ private readonly mainSessionKey: string,
21
+ private readonly stateFilePath: string,
22
+ private readonly logger?: ClaudeSessionManagerLogger,
23
+ ) {
24
+ this.restore();
25
+ }
26
+
27
+ getResumeArgs(sessionKey: string): string[] {
28
+ const existing = this.sessionIds.get(sessionKey);
29
+ if (existing) return ["--resume", existing];
30
+
31
+ const parent = this.pendingForkParents.get(sessionKey);
32
+ if (parent) return ["--resume", parent, "--fork-session"];
33
+
34
+ return [];
35
+ }
36
+
37
+ recordSessionId(sessionKey: string, sessionId: string) {
38
+ this.sessionIds.set(sessionKey, sessionId);
39
+ this.pendingForkParents.delete(sessionKey);
40
+ if (sessionKey === this.mainSessionKey) {
41
+ this.persist(sessionId);
42
+ }
43
+ }
44
+
45
+ createForkSession(parentSessionKey: string): ForkSessionHandle | null {
46
+ const parentSessionId = this.sessionIds.get(parentSessionKey);
47
+ if (!parentSessionId) return null;
48
+
49
+ const sessionKey = `claude-fork:${randomUUID()}`;
50
+ this.pendingForkParents.set(sessionKey, parentSessionId);
51
+ return {
52
+ sessionKey,
53
+ parentSessionId,
54
+ };
55
+ }
56
+
57
+ cleanupFork(sessionKey: string) {
58
+ this.pendingForkParents.delete(sessionKey);
59
+ this.sessionIds.delete(sessionKey);
60
+ }
61
+
62
+ private restore() {
63
+ try {
64
+ const raw = fs.readFileSync(this.stateFilePath, "utf8");
65
+ const parsed = JSON.parse(raw) as Partial<PersistedMainSession>;
66
+ if (parsed.runtimeKey === this.mainSessionKey && typeof parsed.sessionId === "string" && parsed.sessionId.trim()) {
67
+ this.sessionIds.set(this.mainSessionKey, parsed.sessionId.trim());
68
+ }
69
+ } catch {
70
+ // No persisted main session yet.
71
+ }
72
+ }
73
+
74
+ private persist(sessionId: string) {
75
+ try {
76
+ fs.mkdirSync(path.dirname(this.stateFilePath), { recursive: true });
77
+ fs.writeFileSync(this.stateFilePath, JSON.stringify({
78
+ runtimeKey: this.mainSessionKey,
79
+ sessionId,
80
+ }, null, 2));
81
+ } catch (error) {
82
+ this.logger?.warn(
83
+ `claude-agent: failed to persist main session state at ${this.stateFilePath}: ${String(error)}`,
84
+ );
85
+ }
86
+ }
87
+ }
@@ -0,0 +1,39 @@
1
+ import * as fs from "node:fs";
2
+ import * as path from "node:path";
3
+
4
+ const CLAUDE_MD = `# CLAUDE.md
5
+
6
+ You are an agent in Parall IM. You participate in chats, handle tasks, and can use Parall CLI commands for advanced operations.
7
+
8
+ ## Message Model
9
+
10
+ Incoming events are rendered as structured \`[Event: ...]\` blocks.
11
+ Reply with plain text when you want Parall to project your response back into the triggering chat.
12
+
13
+ ## Parall CLI
14
+
15
+ Use CLI only when you need an explicit side effect instead of plain-text projection:
16
+
17
+ - \`npx @parall/cli@latest messages send CHT_ID --text "..." \`
18
+ - \`npx @parall/cli@latest tasks update TSK_ID --status in_progress\`
19
+ - \`npx @parall/cli@latest dm USER_ID --text "..." --no-reply\`
20
+
21
+ Credentials are already injected through environment variables:
22
+ \`PRLL_API_URL\`, \`PRLL_API_KEY\`, \`PRLL_ORG_ID\`, \`PRLL_SESSION_ID\`, \`PRLL_CHAT_ID\`, \`PRLL_TRIGGER_MESSAGE_ID\`, \`PRLL_STEP_ID_FILE\`.
23
+
24
+ ## Guardrails
25
+
26
+ - If an event includes \`[Hint: no_reply]\`, do not send a reply.
27
+ - Prefer plain text over CLI for normal chat replies.
28
+ - Keep replies concise and task-focused.
29
+ `;
30
+
31
+ export function ensureClaudeWorkspace(workspaceDir: string) {
32
+ fs.mkdirSync(workspaceDir, { recursive: true });
33
+ fs.mkdirSync(path.join(workspaceDir, ".claude"), { recursive: true });
34
+
35
+ const claudeMdPath = path.join(workspaceDir, "CLAUDE.md");
36
+ if (!fs.existsSync(claudeMdPath)) {
37
+ fs.writeFileSync(claudeMdPath, CLAUDE_MD, "utf8");
38
+ }
39
+ }