@parall/claude-agent 1.15.1 → 1.17.0
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/dispatch.d.ts.map +1 -1
- package/dist/dispatch.js +5 -22
- package/dist/index.js +1 -1
- package/dist/workspace.d.ts +3 -1
- package/dist/workspace.d.ts.map +1 -1
- package/dist/workspace.js +34 -14
- package/package.json +4 -4
- package/src/dispatch.ts +5 -22
- package/src/index.ts +1 -1
- package/src/workspace.ts +38 -14
package/dist/dispatch.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dispatch.d.ts","sourceRoot":"","sources":["../src/dispatch.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,eAAe,EACf,eAAe,EACf,YAAY,EACZ,QAAQ,EACR,YAAY,EACb,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAErD,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAE5D,KAAK,wBAAwB,GAAG,IAAI,CAClC,iBAAiB,EACf,gBAAgB,GAChB,cAAc,GACd,oBAAoB,GACpB,WAAW,GACX,YAAY,GACZ,iBAAiB,GACjB,OAAO,GACP,gBAAgB,GAChB,cAAc,CACjB,GAAG;IACF,cAAc,EAAE,oBAAoB,CAAC;CACtC,CAAC;
|
|
1
|
+
{"version":3,"file":"dispatch.d.ts","sourceRoot":"","sources":["../src/dispatch.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,eAAe,EACf,eAAe,EACf,YAAY,EACZ,QAAQ,EACR,YAAY,EACb,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAErD,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAE5D,KAAK,wBAAwB,GAAG,IAAI,CAClC,iBAAiB,EACf,gBAAgB,GAChB,cAAc,GACd,oBAAoB,GACpB,WAAW,GACX,YAAY,GACZ,iBAAiB,GACjB,OAAO,GACP,gBAAgB,GAChB,cAAc,CACjB,GAAG;IACF,cAAc,EAAE,oBAAoB,CAAC;CACtC,CAAC;AAEF,qBAAa,iBAAkB,YAAW,eAAe;IAC3C,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAJ,IAAI,EAAE,wBAAwB;IAEpD,QAAQ,CAAC,EAAE,YAAY,EAAE,UAAU,EAAE,OAAO,EAAE,EAAE,YAAY,GAAG,aAAa,CAAC,YAAY,CAAC;IAwFjG,WAAW,CAAC,EAAE,UAAU,EAAE,EAAE,QAAQ;IAIpC,WAAW,CAAC,EAAE,IAAI,EAAE,EAAE,eAAe;IAIrC,OAAO,CAAC,SAAS;CAkClB"}
|
package/dist/dispatch.js
CHANGED
|
@@ -1,21 +1,6 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
2
|
import { spawn } from "node:child_process";
|
|
3
3
|
import { parseClaudeStreamJson } from "./output-parser.js";
|
|
4
|
-
function extractBashCommand(input) {
|
|
5
|
-
if (!input || typeof input !== "object")
|
|
6
|
-
return undefined;
|
|
7
|
-
const command = input.command;
|
|
8
|
-
return typeof command === "string" && command.trim() ? command.trim() : undefined;
|
|
9
|
-
}
|
|
10
|
-
function isParallSendCommand(command) {
|
|
11
|
-
if (!command)
|
|
12
|
-
return false;
|
|
13
|
-
const normalized = command.replace(/\s+/g, " ").trim();
|
|
14
|
-
const invokesParallCli = /(?:^| )(?:parall|npx @parall\/cli(?:@latest)?|pnpm (?:exec|dlx) parall)(?: |$)/.test(normalized);
|
|
15
|
-
if (!invokesParallCli)
|
|
16
|
-
return false;
|
|
17
|
-
return /\b(messages send|dm)\b/.test(normalized);
|
|
18
|
-
}
|
|
19
4
|
export class ClaudeCodeAdapter {
|
|
20
5
|
opts;
|
|
21
6
|
constructor(opts) {
|
|
@@ -54,7 +39,6 @@ export class ClaudeCodeAdapter {
|
|
|
54
39
|
});
|
|
55
40
|
const groupKey = randomUUID();
|
|
56
41
|
let sawError = false;
|
|
57
|
-
let suppressProjectedText = false;
|
|
58
42
|
let completed = false;
|
|
59
43
|
try {
|
|
60
44
|
for await (const event of parseClaudeStreamJson(proc.stdout)) {
|
|
@@ -62,20 +46,19 @@ export class ClaudeCodeAdapter {
|
|
|
62
46
|
this.opts.sessionManager.recordSessionId(sessionKey, event.sessionId);
|
|
63
47
|
continue;
|
|
64
48
|
}
|
|
65
|
-
if (event.type === "tool_call" && isParallSendCommand(extractBashCommand(event.input))) {
|
|
66
|
-
suppressProjectedText = true;
|
|
67
|
-
}
|
|
68
49
|
if (event.type === "error") {
|
|
69
50
|
sawError = true;
|
|
70
51
|
yield event;
|
|
71
52
|
continue;
|
|
72
53
|
}
|
|
73
54
|
if (event.type === "text") {
|
|
74
|
-
|
|
75
|
-
|
|
55
|
+
// Runtime output contract (symmetric with OpenClaw channel): Claude's
|
|
56
|
+
// plain text is never projected as a chat message. To reply, the agent
|
|
57
|
+
// must explicitly run `parall messages send` / `dm` via Bash. Text
|
|
58
|
+
// events are still recorded as suppressed session steps for audit.
|
|
76
59
|
yield {
|
|
77
60
|
...event,
|
|
78
|
-
project,
|
|
61
|
+
project: false,
|
|
79
62
|
groupKey,
|
|
80
63
|
};
|
|
81
64
|
continue;
|
package/dist/index.js
CHANGED
|
@@ -15,8 +15,8 @@ function createLogger(prefix) {
|
|
|
15
15
|
}
|
|
16
16
|
async function main() {
|
|
17
17
|
const config = resolveClaudeAgentConfig(process.env);
|
|
18
|
-
ensureClaudeWorkspace(config.workspaceDir);
|
|
19
18
|
const log = createLogger("claude-agent");
|
|
19
|
+
ensureClaudeWorkspace(config.workspaceDir, log);
|
|
20
20
|
const client = new ParallClient({
|
|
21
21
|
baseUrl: config.apiUrl,
|
|
22
22
|
token: config.apiKey,
|
package/dist/workspace.d.ts
CHANGED
package/dist/workspace.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workspace.d.ts","sourceRoot":"","sources":["../src/workspace.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"workspace.d.ts","sourceRoot":"","sources":["../src/workspace.ts"],"names":[],"mappings":"AAkCA,wBAAgB,qBAAqB,CACnC,YAAY,EAAE,MAAM,EACpB,GAAG,CAAC,EAAE;IAAE,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;CAAE,QA0BtC"}
|
package/dist/workspace.js
CHANGED
|
@@ -2,35 +2,55 @@ import * as fs from "node:fs";
|
|
|
2
2
|
import * as path from "node:path";
|
|
3
3
|
const CLAUDE_MD = `# CLAUDE.md
|
|
4
4
|
|
|
5
|
-
You are an agent in Parall IM. You participate in chats, handle tasks, and
|
|
5
|
+
You are an agent in Parall IM. You participate in chats, handle tasks, and interact exclusively through the Parall CLI.
|
|
6
6
|
|
|
7
7
|
## Message Model
|
|
8
8
|
|
|
9
9
|
Incoming events are rendered as structured \`[Event: ...]\` blocks.
|
|
10
|
-
|
|
10
|
+
Each event includes \`[Chat: ... (prll://cht_xxx)]\` — use that chat ID (or full URI) when replying.
|
|
11
|
+
|
|
12
|
+
**Your plain-text output is not delivered to anyone** — it is recorded as suppressed thinking in your session steps and discarded from the chat.
|
|
13
|
+
To say something in a chat, you **must** invoke the Parall CLI via the Bash tool. To stay silent, simply do not invoke it.
|
|
11
14
|
|
|
12
15
|
## Parall CLI
|
|
13
16
|
|
|
14
|
-
|
|
17
|
+
All outbound interactions go through \`@parall/cli\`. Credentials are pre-injected as environment variables — no setup needed.
|
|
15
18
|
|
|
16
|
-
- \`npx @parall/cli@latest messages send
|
|
17
|
-
- \`npx @parall/cli@latest
|
|
18
|
-
- \`npx @parall/cli@latest
|
|
19
|
+
- \`npx --yes @parall/cli@latest messages send prll://cht_xxx --text "..."\` — reply into the triggering chat
|
|
20
|
+
- \`npx --yes @parall/cli@latest dm prll://usr_xxx --text "..." [--no-reply]\` — direct message another user
|
|
21
|
+
- \`npx --yes @parall/cli@latest tasks update prll://tsk_xxx --status in_progress\` — task state
|
|
22
|
+
- \`npx --yes @parall/cli@latest no-reply [--reason "..."]\` — explicitly declare this turn silent (audit signal; not required for silence, just clarifies intent)
|
|
19
23
|
|
|
20
|
-
|
|
21
|
-
\`PRLL_API_URL\`, \`PRLL_API_KEY\`, \`PRLL_ORG_ID\`, \`PRLL_SESSION_ID\`, \`PRLL_CHAT_ID\`, \`PRLL_TRIGGER_MESSAGE_ID\`, \`PRLL_STEP_ID_FILE\`.
|
|
24
|
+
Available env: \`PRLL_API_URL\`, \`PRLL_API_KEY\`, \`PRLL_ORG_ID\`, \`PRLL_SESSION_ID\`, \`PRLL_CHAT_ID\`, \`PRLL_TRIGGER_MESSAGE_ID\`, \`PRLL_STEP_ID_FILE\`.
|
|
22
25
|
|
|
23
26
|
## Guardrails
|
|
24
27
|
|
|
25
|
-
-
|
|
26
|
-
-
|
|
27
|
-
-
|
|
28
|
+
- A dispatch may coalesce multiple events. Decide per event whether to reply via \`messages send\` / \`dm\` — events you do not act on simply receive no reply.
|
|
29
|
+
- If an event carries \`[Hint: no_reply]\`, do not send anything for that event. \`no-reply\` is optional and only useful as an explicit intent marker.
|
|
30
|
+
- Never try to "speak" by typing sentences like "No response needed" / "Noted" / "OK" — they are discarded, so they accomplish nothing except polluting your session log.
|
|
31
|
+
- Keep CLI replies concise and task-focused.
|
|
28
32
|
`;
|
|
29
|
-
export function ensureClaudeWorkspace(workspaceDir) {
|
|
33
|
+
export function ensureClaudeWorkspace(workspaceDir, log) {
|
|
30
34
|
fs.mkdirSync(workspaceDir, { recursive: true });
|
|
31
35
|
fs.mkdirSync(path.join(workspaceDir, ".claude"), { recursive: true });
|
|
36
|
+
// CLAUDE.md is bridge-managed: always overwrite so a hosted PVC keeps the
|
|
37
|
+
// current guardrails (e.g. the `no-reply` instruction). Operators must not
|
|
38
|
+
// hand-edit this file — workspace customizations should go into AGENTS.md
|
|
39
|
+
// / SOUL.md / TOOLS.md, which are env-driven and untouched here. Surface a
|
|
40
|
+
// warning when we replace a file whose content diverges, so an operator
|
|
41
|
+
// who did edit it locally gets a signal instead of silently losing changes.
|
|
32
42
|
const claudeMdPath = path.join(workspaceDir, "CLAUDE.md");
|
|
33
|
-
if (
|
|
34
|
-
|
|
43
|
+
if (log) {
|
|
44
|
+
try {
|
|
45
|
+
const existing = fs.readFileSync(claudeMdPath, "utf8");
|
|
46
|
+
if (existing !== CLAUDE_MD) {
|
|
47
|
+
log.warn(`claude-agent: overwriting divergent ${claudeMdPath} with bridge-managed template ` +
|
|
48
|
+
`(local edits to CLAUDE.md are not preserved — customize AGENTS.md / SOUL.md / TOOLS.md instead)`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
// file missing or unreadable — first-boot case, no warning needed
|
|
53
|
+
}
|
|
35
54
|
}
|
|
55
|
+
fs.writeFileSync(claudeMdPath, CLAUDE_MD, "utf8");
|
|
36
56
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@parall/claude-agent",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.17.0",
|
|
4
4
|
"description": "Claude Code bridge runtime for self-hosted Parall agents",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -25,9 +25,9 @@
|
|
|
25
25
|
"src"
|
|
26
26
|
],
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@parall/
|
|
29
|
-
"@parall/
|
|
30
|
-
"@parall/
|
|
28
|
+
"@parall/sdk": "1.17.0",
|
|
29
|
+
"@parall/agent-core": "1.17.0",
|
|
30
|
+
"@parall/cli": "1.17.0"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
33
|
"@types/node": "^22.0.0",
|
package/src/dispatch.ts
CHANGED
|
@@ -26,20 +26,6 @@ type ClaudeCodeAdapterOptions = Pick<
|
|
|
26
26
|
sessionManager: ClaudeSessionManager;
|
|
27
27
|
};
|
|
28
28
|
|
|
29
|
-
function extractBashCommand(input: unknown): string | undefined {
|
|
30
|
-
if (!input || typeof input !== "object") return undefined;
|
|
31
|
-
const command = (input as { command?: unknown }).command;
|
|
32
|
-
return typeof command === "string" && command.trim() ? command.trim() : undefined;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
function isParallSendCommand(command: string | undefined): boolean {
|
|
36
|
-
if (!command) return false;
|
|
37
|
-
const normalized = command.replace(/\s+/g, " ").trim();
|
|
38
|
-
const invokesParallCli = /(?:^| )(?:parall|npx @parall\/cli(?:@latest)?|pnpm (?:exec|dlx) parall)(?: |$)/.test(normalized);
|
|
39
|
-
if (!invokesParallCli) return false;
|
|
40
|
-
return /\b(messages send|dm)\b/.test(normalized);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
29
|
export class ClaudeCodeAdapter implements DispatchAdapter {
|
|
44
30
|
constructor(private readonly opts: ClaudeCodeAdapterOptions) {}
|
|
45
31
|
|
|
@@ -82,7 +68,6 @@ export class ClaudeCodeAdapter implements DispatchAdapter {
|
|
|
82
68
|
|
|
83
69
|
const groupKey = randomUUID();
|
|
84
70
|
let sawError = false;
|
|
85
|
-
let suppressProjectedText = false;
|
|
86
71
|
let completed = false;
|
|
87
72
|
|
|
88
73
|
try {
|
|
@@ -92,10 +77,6 @@ export class ClaudeCodeAdapter implements DispatchAdapter {
|
|
|
92
77
|
continue;
|
|
93
78
|
}
|
|
94
79
|
|
|
95
|
-
if (event.type === "tool_call" && isParallSendCommand(extractBashCommand(event.input))) {
|
|
96
|
-
suppressProjectedText = true;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
80
|
if (event.type === "error") {
|
|
100
81
|
sawError = true;
|
|
101
82
|
yield event;
|
|
@@ -103,11 +84,13 @@ export class ClaudeCodeAdapter implements DispatchAdapter {
|
|
|
103
84
|
}
|
|
104
85
|
|
|
105
86
|
if (event.type === "text") {
|
|
106
|
-
|
|
107
|
-
|
|
87
|
+
// Runtime output contract (symmetric with OpenClaw channel): Claude's
|
|
88
|
+
// plain text is never projected as a chat message. To reply, the agent
|
|
89
|
+
// must explicitly run `parall messages send` / `dm` via Bash. Text
|
|
90
|
+
// events are still recorded as suppressed session steps for audit.
|
|
108
91
|
yield {
|
|
109
92
|
...event,
|
|
110
|
-
project,
|
|
93
|
+
project: false,
|
|
111
94
|
groupKey,
|
|
112
95
|
};
|
|
113
96
|
continue;
|
package/src/index.ts
CHANGED
|
@@ -24,8 +24,8 @@ function createLogger(prefix: string) {
|
|
|
24
24
|
|
|
25
25
|
async function main() {
|
|
26
26
|
const config = resolveClaudeAgentConfig(process.env);
|
|
27
|
-
ensureClaudeWorkspace(config.workspaceDir);
|
|
28
27
|
const log = createLogger("claude-agent");
|
|
28
|
+
ensureClaudeWorkspace(config.workspaceDir, log);
|
|
29
29
|
|
|
30
30
|
const client = new ParallClient({
|
|
31
31
|
baseUrl: config.apiUrl,
|
package/src/workspace.ts
CHANGED
|
@@ -3,37 +3,61 @@ import * as path from "node:path";
|
|
|
3
3
|
|
|
4
4
|
const CLAUDE_MD = `# CLAUDE.md
|
|
5
5
|
|
|
6
|
-
You are an agent in Parall IM. You participate in chats, handle tasks, and
|
|
6
|
+
You are an agent in Parall IM. You participate in chats, handle tasks, and interact exclusively through the Parall CLI.
|
|
7
7
|
|
|
8
8
|
## Message Model
|
|
9
9
|
|
|
10
10
|
Incoming events are rendered as structured \`[Event: ...]\` blocks.
|
|
11
|
-
|
|
11
|
+
Each event includes \`[Chat: ... (prll://cht_xxx)]\` — use that chat ID (or full URI) when replying.
|
|
12
|
+
|
|
13
|
+
**Your plain-text output is not delivered to anyone** — it is recorded as suppressed thinking in your session steps and discarded from the chat.
|
|
14
|
+
To say something in a chat, you **must** invoke the Parall CLI via the Bash tool. To stay silent, simply do not invoke it.
|
|
12
15
|
|
|
13
16
|
## Parall CLI
|
|
14
17
|
|
|
15
|
-
|
|
18
|
+
All outbound interactions go through \`@parall/cli\`. Credentials are pre-injected as environment variables — no setup needed.
|
|
16
19
|
|
|
17
|
-
- \`npx @parall/cli@latest messages send
|
|
18
|
-
- \`npx @parall/cli@latest
|
|
19
|
-
- \`npx @parall/cli@latest
|
|
20
|
+
- \`npx --yes @parall/cli@latest messages send prll://cht_xxx --text "..."\` — reply into the triggering chat
|
|
21
|
+
- \`npx --yes @parall/cli@latest dm prll://usr_xxx --text "..." [--no-reply]\` — direct message another user
|
|
22
|
+
- \`npx --yes @parall/cli@latest tasks update prll://tsk_xxx --status in_progress\` — task state
|
|
23
|
+
- \`npx --yes @parall/cli@latest no-reply [--reason "..."]\` — explicitly declare this turn silent (audit signal; not required for silence, just clarifies intent)
|
|
20
24
|
|
|
21
|
-
|
|
22
|
-
\`PRLL_API_URL\`, \`PRLL_API_KEY\`, \`PRLL_ORG_ID\`, \`PRLL_SESSION_ID\`, \`PRLL_CHAT_ID\`, \`PRLL_TRIGGER_MESSAGE_ID\`, \`PRLL_STEP_ID_FILE\`.
|
|
25
|
+
Available env: \`PRLL_API_URL\`, \`PRLL_API_KEY\`, \`PRLL_ORG_ID\`, \`PRLL_SESSION_ID\`, \`PRLL_CHAT_ID\`, \`PRLL_TRIGGER_MESSAGE_ID\`, \`PRLL_STEP_ID_FILE\`.
|
|
23
26
|
|
|
24
27
|
## Guardrails
|
|
25
28
|
|
|
26
|
-
-
|
|
27
|
-
-
|
|
28
|
-
-
|
|
29
|
+
- A dispatch may coalesce multiple events. Decide per event whether to reply via \`messages send\` / \`dm\` — events you do not act on simply receive no reply.
|
|
30
|
+
- If an event carries \`[Hint: no_reply]\`, do not send anything for that event. \`no-reply\` is optional and only useful as an explicit intent marker.
|
|
31
|
+
- Never try to "speak" by typing sentences like "No response needed" / "Noted" / "OK" — they are discarded, so they accomplish nothing except polluting your session log.
|
|
32
|
+
- Keep CLI replies concise and task-focused.
|
|
29
33
|
`;
|
|
30
34
|
|
|
31
|
-
export function ensureClaudeWorkspace(
|
|
35
|
+
export function ensureClaudeWorkspace(
|
|
36
|
+
workspaceDir: string,
|
|
37
|
+
log?: { warn: (msg: string) => void },
|
|
38
|
+
) {
|
|
32
39
|
fs.mkdirSync(workspaceDir, { recursive: true });
|
|
33
40
|
fs.mkdirSync(path.join(workspaceDir, ".claude"), { recursive: true });
|
|
34
41
|
|
|
42
|
+
// CLAUDE.md is bridge-managed: always overwrite so a hosted PVC keeps the
|
|
43
|
+
// current guardrails (e.g. the `no-reply` instruction). Operators must not
|
|
44
|
+
// hand-edit this file — workspace customizations should go into AGENTS.md
|
|
45
|
+
// / SOUL.md / TOOLS.md, which are env-driven and untouched here. Surface a
|
|
46
|
+
// warning when we replace a file whose content diverges, so an operator
|
|
47
|
+
// who did edit it locally gets a signal instead of silently losing changes.
|
|
35
48
|
const claudeMdPath = path.join(workspaceDir, "CLAUDE.md");
|
|
36
|
-
if (
|
|
37
|
-
|
|
49
|
+
if (log) {
|
|
50
|
+
try {
|
|
51
|
+
const existing = fs.readFileSync(claudeMdPath, "utf8");
|
|
52
|
+
if (existing !== CLAUDE_MD) {
|
|
53
|
+
log.warn(
|
|
54
|
+
`claude-agent: overwriting divergent ${claudeMdPath} with bridge-managed template ` +
|
|
55
|
+
`(local edits to CLAUDE.md are not preserved — customize AGENTS.md / SOUL.md / TOOLS.md instead)`,
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
} catch {
|
|
59
|
+
// file missing or unreadable — first-boot case, no warning needed
|
|
60
|
+
}
|
|
38
61
|
}
|
|
62
|
+
fs.writeFileSync(claudeMdPath, CLAUDE_MD, "utf8");
|
|
39
63
|
}
|