clearclaw 0.7.0 → 0.9.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/README.md +53 -7
- package/dist/channel/slack.d.ts +18 -1
- package/dist/channel/slack.js +227 -27
- package/dist/channel/telegram.d.ts +20 -1
- package/dist/channel/telegram.js +146 -33
- package/dist/config.d.ts +37 -1
- package/dist/config.js +118 -0
- package/dist/engine/acp.d.ts +9 -4
- package/dist/engine/acp.js +301 -29
- package/dist/engine/claude-code.d.ts +19 -2
- package/dist/engine/claude-code.js +121 -33
- package/dist/engine/mcp-http.d.ts +9 -0
- package/dist/engine/mcp-http.js +59 -0
- package/dist/engine/registry.d.ts +10 -7
- package/dist/engine/registry.js +99 -16
- package/dist/engine/session-transcript.d.ts +14 -0
- package/dist/engine/session-transcript.js +38 -0
- package/dist/format.d.ts +1 -1
- package/dist/format.js +42 -7
- package/dist/index.js +18 -23
- package/dist/orchestrator.d.ts +38 -4
- package/dist/orchestrator.js +854 -167
- package/dist/plan-usage.d.ts +6 -0
- package/dist/plan-usage.js +31 -0
- package/dist/prompt.d.ts +6 -2
- package/dist/prompt.js +75 -21
- package/dist/scheduler.d.ts +15 -0
- package/dist/scheduler.js +82 -0
- package/dist/transcribe.d.ts +13 -0
- package/dist/transcribe.js +157 -0
- package/dist/types.d.ts +77 -5
- package/package.json +11 -4
- package/patches/README.md +13 -0
- package/patches/codex-acp-1.11.0.patch +38 -0
- package/prompts/SYSTEM.md +66 -16
- package/scripts/patch-codex-acp.mjs +32 -0
- package/prompts/ONBOARDING.md +0 -56
package/dist/index.js
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { execFileSync } from "node:child_process";
|
|
3
2
|
import readline from "node:readline";
|
|
4
3
|
import { Config } from "./config.js";
|
|
5
4
|
import log, { initLogger } from "./logger.js";
|
|
6
|
-
import { createEngineMap, ENGINE_NAMES,
|
|
5
|
+
import { createEngineMap, ENGINE_NAMES, resolveEnginePath } from "./engine/registry.js";
|
|
7
6
|
import { TelegramChannel } from "./channel/telegram.js";
|
|
8
7
|
import { SlackChannel } from "./channel/slack.js";
|
|
9
8
|
import { Orchestrator } from "./orchestrator.js";
|
|
@@ -41,9 +40,8 @@ async function runDaemon() {
|
|
|
41
40
|
log.warn({ err }, "[pairing] failed to send pairing message");
|
|
42
41
|
});
|
|
43
42
|
};
|
|
44
|
-
const channel = createChannel(config.channel, (userId) => config.isAuthorized(userId), onUnauthorizedDM);
|
|
45
|
-
|
|
46
|
-
await new Orchestrator({ channel, engines: createEngineMap(enginePaths), config }).start();
|
|
43
|
+
const channel = createChannel(config.channel, (userId) => config.isAuthorized(userId), onUnauthorizedDM, () => config.listAuthorizedUserIds());
|
|
44
|
+
await new Orchestrator({ channel, engines: createEngineMap(config.engines), config }).start();
|
|
47
45
|
}
|
|
48
46
|
async function runApprove(args) {
|
|
49
47
|
const code = args[0];
|
|
@@ -58,6 +56,8 @@ async function runApprove(args) {
|
|
|
58
56
|
process.exit(1);
|
|
59
57
|
}
|
|
60
58
|
config.approveUser(pairing.userId, pairing.userName);
|
|
59
|
+
// Pairings only originate from a root DM, so this chat is home's destination.
|
|
60
|
+
config.connectHomeWorkspace(pairing.chatId);
|
|
61
61
|
console.log(`Approved ${pairing.userName} (${pairing.userId})`);
|
|
62
62
|
}
|
|
63
63
|
const SETUP_TIMEOUT_MS = 5 * 60 * 1000;
|
|
@@ -89,6 +89,7 @@ async function runSetup() {
|
|
|
89
89
|
channelConfig = { type: "telegram", botToken };
|
|
90
90
|
}
|
|
91
91
|
let engineName;
|
|
92
|
+
let resolvedPath;
|
|
92
93
|
const engineList = ENGINE_NAMES.join("/");
|
|
93
94
|
while (true) {
|
|
94
95
|
engineName = (await ask(`Default engine [${engineList}]: `)).trim().toLowerCase();
|
|
@@ -96,23 +97,14 @@ async function runSetup() {
|
|
|
96
97
|
console.log(` Please enter one of: ${engineList}`);
|
|
97
98
|
continue;
|
|
98
99
|
}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
console.log(` "${cmd}" not found on PATH. Install it first or choose another engine.`);
|
|
106
|
-
continue;
|
|
107
|
-
}
|
|
100
|
+
try {
|
|
101
|
+
resolvedPath = resolveEnginePath(engineName);
|
|
102
|
+
break;
|
|
103
|
+
}
|
|
104
|
+
catch (err) {
|
|
105
|
+
console.log(` ${err.message}`);
|
|
108
106
|
}
|
|
109
|
-
break;
|
|
110
107
|
}
|
|
111
|
-
// Resolve executable path for the chosen engine
|
|
112
|
-
const cmd = engineCommand(engineName);
|
|
113
|
-
const resolvedPath = cmd
|
|
114
|
-
? execFileSync("which", [cmd], { encoding: "utf-8" }).trim()
|
|
115
|
-
: engineName; // SDK-based engines don't have a standalone binary
|
|
116
108
|
const config = new Config();
|
|
117
109
|
config.setChannel(channelConfig);
|
|
118
110
|
config.setEngines([
|
|
@@ -120,11 +112,12 @@ async function runSetup() {
|
|
|
120
112
|
]);
|
|
121
113
|
console.log("Saved to ~/.clearclaw/config.json\n");
|
|
122
114
|
config.resolve();
|
|
115
|
+
config.ensureHomeWorkspace();
|
|
123
116
|
let resolveFirstDM;
|
|
124
117
|
const firstDM = new Promise((r) => {
|
|
125
118
|
resolveFirstDM = r;
|
|
126
119
|
});
|
|
127
|
-
channel = createChannel(config.channel, (userId) => config.isAuthorized(userId), (chatId, user) => resolveFirstDM({ chatId, user }));
|
|
120
|
+
channel = createChannel(config.channel, (userId) => config.isAuthorized(userId), (chatId, user) => resolveFirstDM({ chatId, user }), () => config.listAuthorizedUserIds());
|
|
128
121
|
console.log("Connecting...");
|
|
129
122
|
await channel.connect();
|
|
130
123
|
console.log("Connected! Waiting for a DM — message the bot from your chat app.\n");
|
|
@@ -148,6 +141,8 @@ async function runSetup() {
|
|
|
148
141
|
return;
|
|
149
142
|
}
|
|
150
143
|
config.approveUser(pairing.userId, pairing.userName);
|
|
144
|
+
// Pairings only originate from a root DM, so this chat is home's destination.
|
|
145
|
+
config.connectHomeWorkspace(pairing.chatId);
|
|
151
146
|
console.log(` Approved ${pairing.userName} (${pairing.userId})`);
|
|
152
147
|
await channel.sendMessage(chatId, "You're approved! The bot is being set up — you'll be able to chat soon.");
|
|
153
148
|
console.log("\nSetup complete! Start the daemon:\n clearclaw daemon\n");
|
|
@@ -158,9 +153,9 @@ async function runSetup() {
|
|
|
158
153
|
rl.close();
|
|
159
154
|
}
|
|
160
155
|
}
|
|
161
|
-
function createChannel(ch, isAuthorized, onUnauthorizedDM) {
|
|
156
|
+
function createChannel(ch, isAuthorized, onUnauthorizedDM, authorizedUserIds) {
|
|
162
157
|
if (ch.type === "slack") {
|
|
163
|
-
return new SlackChannel(ch.botToken, ch.appToken, isAuthorized, onUnauthorizedDM);
|
|
158
|
+
return new SlackChannel(ch.botToken, ch.appToken, isAuthorized, onUnauthorizedDM, authorizedUserIds);
|
|
164
159
|
}
|
|
165
160
|
return new TelegramChannel(ch.botToken, isAuthorized, onUnauthorizedDM);
|
|
166
161
|
}
|
package/dist/orchestrator.d.ts
CHANGED
|
@@ -1,31 +1,65 @@
|
|
|
1
1
|
import type { Config } from "./config.js";
|
|
2
|
-
import type { Channel, Engine } from "./types.js";
|
|
2
|
+
import type { Attachment, Channel, Engine, InboundMessage, MessageOrigin } from "./types.js";
|
|
3
3
|
export interface OrchestratorOpts {
|
|
4
4
|
channel: Channel;
|
|
5
5
|
engines: Map<string, Engine>;
|
|
6
6
|
config: Config;
|
|
7
|
+
transcribe?: (att: Attachment) => Promise<string>;
|
|
7
8
|
}
|
|
8
9
|
export declare class Orchestrator {
|
|
9
10
|
private channel;
|
|
10
11
|
private engines;
|
|
11
12
|
private config;
|
|
12
13
|
private chats;
|
|
13
|
-
private
|
|
14
|
+
private creatingWorkspaces;
|
|
15
|
+
private scheduler;
|
|
16
|
+
private planUsage;
|
|
17
|
+
private transcribe;
|
|
14
18
|
constructor(opts: OrchestratorOpts);
|
|
15
19
|
private chat;
|
|
16
20
|
private engineFor;
|
|
17
21
|
start(): Promise<void>;
|
|
18
22
|
stop(): Promise<void>;
|
|
19
|
-
/**
|
|
23
|
+
/** Deliver a synthetic message to a named workspace and trigger its turn. */
|
|
24
|
+
deliverToWorkspace(workspaceName: string, origin: MessageOrigin, text: string): boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Everything creation can reject without touching the platform. Runs before the
|
|
27
|
+
* confirmation, so the user is never asked to approve a doomed spawn, and again
|
|
28
|
+
* inside creation, where it is the authoritative check.
|
|
29
|
+
*/
|
|
30
|
+
private validateNewWorkspace;
|
|
31
|
+
/** Shared creation path for standalone projects and peers, with optional manual binding. */
|
|
32
|
+
private createWorkspace;
|
|
33
|
+
/** Grouping is best-effort: it never fails a lifecycle operation, but it is never silent either. */
|
|
34
|
+
private groupChat;
|
|
35
|
+
private deliverInitialBrief;
|
|
36
|
+
/** An unbound chat can connect without starting a temporary agent or sharing home's session. */
|
|
37
|
+
private connectWorkspace;
|
|
38
|
+
private peerRuntime;
|
|
39
|
+
/** Effective behavior: Explicit setting or home→assistant / project→relay. */
|
|
20
40
|
private effectiveBehavior;
|
|
21
|
-
/**
|
|
41
|
+
/** Permission mode a chat runs in until /mode picks one. */
|
|
42
|
+
private baseMode;
|
|
43
|
+
/** Enqueue a message and drain — immediately for relay, debounced for assistant. */
|
|
22
44
|
private enqueueMessage;
|
|
23
45
|
private scheduleDebounce;
|
|
24
46
|
private processQueuedMessages;
|
|
25
47
|
private executeTurn;
|
|
48
|
+
private persistSessionId;
|
|
49
|
+
/** Native selection works even when the workspace's engine cannot run. */
|
|
50
|
+
private selectEngine;
|
|
51
|
+
/**
|
|
52
|
+
* Turn audio attachments into message text. Engines can't consume audio, so it never
|
|
53
|
+
* reaches them; the echo lets the user catch a bad transcription before the agent acts.
|
|
54
|
+
*/
|
|
55
|
+
private transcribeVoice;
|
|
26
56
|
private routeMessage;
|
|
27
57
|
private routeEngineEvent;
|
|
58
|
+
private routeTextChunk;
|
|
59
|
+
private publishTextSegment;
|
|
60
|
+
private flushTextSegment;
|
|
28
61
|
private buildMcpTools;
|
|
29
62
|
private handlePermission;
|
|
30
63
|
private updateStatusMessage;
|
|
31
64
|
}
|
|
65
|
+
export declare function buildPrompt(messages: InboundMessage[]): string;
|