@messenger-agent/claude-agent 0.24.0-alpha.2 → 0.24.0-alpha.4

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,16 +1,4 @@
1
- import { randomUUID } from "node:crypto";
2
- import { mkdirSync } from "node:fs";
3
- import { dirname, join } from "node:path";
4
- import { DatabaseSync } from "node:sqlite";
5
- import { appConfig } from "./config.js";
6
- /** SDK tool names whose permission request is satisfied by a later client response. */
7
- export const PENDING_ASK_TOOL_NAMES = ["AskUserQuestion"];
8
- export const PENDING_APPROVAL_TOOL_NAMES = ["ExitPlanMode"];
9
- const pendingTools = new Map();
10
- const DB_PATH = join(appConfig.dataDir, "pending-asks.sqlite");
11
- mkdirSync(dirname(DB_PATH), { recursive: true });
12
- const db = new DatabaseSync(DB_PATH);
13
- db.exec(`
1
+ import{randomUUID as s}from"node:crypto";import{mkdirSync as v}from"node:fs";import{dirname as E,join as k}from"node:path";import{DatabaseSync as A}from"node:sqlite";import{appConfig as m}from"./config.js";const X=["AskUserQuestion"],B=["ExitPlanMode"],d=new Map,_=k(m.dataDir,"pending-asks.sqlite");v(E(_),{recursive:!0});const i=new A(_);i.exec(`
14
2
  CREATE TABLE IF NOT EXISTS pending_tools (
15
3
  tool_call_id TEXT PRIMARY KEY,
16
4
  id TEXT NOT NULL,
@@ -27,8 +15,7 @@ db.exec(`
27
15
  );
28
16
  CREATE INDEX IF NOT EXISTS idx_pending_tools_conversation_updated
29
17
  ON pending_tools (conversation_id, updated_at);
30
- `);
31
- const stmtUpsert = db.prepare(`
18
+ `);const x=i.prepare(`
32
19
  INSERT INTO pending_tools (
33
20
  tool_call_id, id, kind, conversation_id, workdir, model, agent_mode, tool_name, input_json, approval_json, created_at, updated_at
34
21
  ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
@@ -43,241 +30,13 @@ const stmtUpsert = db.prepare(`
43
30
  input_json = excluded.input_json,
44
31
  approval_json = excluded.approval_json,
45
32
  updated_at = excluded.updated_at
46
- `);
47
- const stmtGetByToolCallId = db.prepare(`SELECT * FROM pending_tools WHERE tool_call_id = ?`);
48
- const stmtFindByConversation = db.prepare(`
33
+ `),N=i.prepare("SELECT * FROM pending_tools WHERE tool_call_id = ?"),P=i.prepare(`
49
34
  SELECT * FROM pending_tools
50
35
  WHERE conversation_id = ?
51
36
  ORDER BY updated_at DESC, created_at DESC
52
37
  LIMIT 1
53
- `);
54
- const stmtUpdateConversation = db.prepare(`
38
+ `),O=i.prepare(`
55
39
  UPDATE pending_tools
56
40
  SET conversation_id = ?, updated_at = ?
57
41
  WHERE conversation_id = ?
58
- `);
59
- const stmtDelete = db.prepare(`DELETE FROM pending_tools WHERE tool_call_id = ?`);
60
- const stmtList = db.prepare(`SELECT * FROM pending_tools ORDER BY updated_at DESC, created_at DESC`);
61
- function createWait(record) {
62
- let resolve;
63
- let reject;
64
- const promise = new Promise((promiseResolve, promiseReject) => {
65
- resolve = promiseResolve;
66
- reject = promiseReject;
67
- });
68
- return { record, resolve, reject, promise };
69
- }
70
- function rowToRecord(row) {
71
- try {
72
- const input = JSON.parse(row.input_json);
73
- const base = {
74
- id: row.id,
75
- conversationId: row.conversation_id,
76
- toolCallId: row.tool_call_id,
77
- workdir: row.workdir,
78
- model: row.model ?? undefined,
79
- agentMode: row.agent_mode ?? undefined,
80
- input,
81
- createdAt: row.created_at,
82
- updatedAt: row.updated_at,
83
- };
84
- if (row.kind === "approval") {
85
- const approval = row.approval_json ? JSON.parse(row.approval_json) : {};
86
- if (row.tool_name !== "ExitPlanMode" || typeof approval.approveId !== "string")
87
- return undefined;
88
- return {
89
- ...base,
90
- kind: "approval",
91
- toolName: "ExitPlanMode",
92
- approveId: approval.approveId,
93
- };
94
- }
95
- if (row.kind !== "ask_user" || row.tool_name !== "AskUserQuestion")
96
- return undefined;
97
- return {
98
- ...base,
99
- kind: "ask_user",
100
- toolName: "AskUserQuestion",
101
- };
102
- }
103
- catch {
104
- return undefined;
105
- }
106
- }
107
- function persistPendingTool(record) {
108
- stmtUpsert.run(record.toolCallId, record.id, record.kind, record.conversationId, record.workdir, record.model ?? null, record.agentMode ?? null, record.toolName, JSON.stringify(record.input), record.kind === "approval" ? JSON.stringify({ approveId: record.approveId }) : null, record.createdAt, record.updatedAt);
109
- }
110
- function hydrateWait(record) {
111
- const existing = pendingTools.get(record.toolCallId);
112
- if (existing)
113
- return existing;
114
- const wait = createWait(record);
115
- pendingTools.set(record.toolCallId, wait);
116
- return wait;
117
- }
118
- function loadPendingTool(toolCallId) {
119
- const existing = pendingTools.get(toolCallId)?.record;
120
- if (existing)
121
- return existing;
122
- const row = stmtGetByToolCallId.get(toolCallId);
123
- const record = row ? rowToRecord(row) : undefined;
124
- if (!record)
125
- return undefined;
126
- hydrateWait(record);
127
- return record;
128
- }
129
- function findPendingToolByConversation(conversationId) {
130
- const existing = Array.from(pendingTools.values(), (wait) => wait.record)
131
- .filter((record) => record.conversationId === conversationId)
132
- .sort((a, b) => b.updatedAt.localeCompare(a.updatedAt))[0];
133
- if (existing)
134
- return existing;
135
- const row = stmtFindByConversation.get(conversationId);
136
- const record = row ? rowToRecord(row) : undefined;
137
- if (!record)
138
- return undefined;
139
- hydrateWait(record);
140
- return record;
141
- }
142
- export function savePendingAsk(params) {
143
- const existing = pendingTools.get(params.toolCallId);
144
- if (existing?.record.kind === "ask_user")
145
- return existing.record;
146
- const now = new Date().toISOString();
147
- const record = {
148
- id: randomUUID(),
149
- kind: "ask_user",
150
- conversationId: params.conversationId,
151
- toolCallId: params.toolCallId,
152
- workdir: params.workdir,
153
- model: params.model,
154
- agentMode: params.agentMode,
155
- toolName: params.toolName,
156
- input: params.input,
157
- createdAt: now,
158
- updatedAt: now,
159
- };
160
- pendingTools.set(params.toolCallId, createWait(record));
161
- persistPendingTool(record);
162
- return record;
163
- }
164
- export function loadPendingAsk(toolCallId) {
165
- const record = loadPendingTool(toolCallId);
166
- return record?.kind === "ask_user" ? record : undefined;
167
- }
168
- export function findPendingAskByConversation(conversationId) {
169
- const record = findPendingToolByConversation(conversationId);
170
- return record?.kind === "ask_user" ? record : undefined;
171
- }
172
- export function savePendingApproval(params) {
173
- const existing = pendingTools.get(params.toolCallId);
174
- if (existing?.record.kind === "approval")
175
- return existing.record;
176
- const now = new Date().toISOString();
177
- const record = {
178
- id: randomUUID(),
179
- kind: "approval",
180
- conversationId: params.conversationId,
181
- toolCallId: params.toolCallId,
182
- workdir: params.workdir,
183
- model: params.model,
184
- agentMode: params.agentMode,
185
- toolName: params.toolName,
186
- input: params.input,
187
- approveId: randomUUID(),
188
- createdAt: now,
189
- updatedAt: now,
190
- };
191
- pendingTools.set(params.toolCallId, createWait(record));
192
- persistPendingTool(record);
193
- return record;
194
- }
195
- export function loadPendingApproval(toolCallId) {
196
- const record = loadPendingTool(toolCallId);
197
- return record?.kind === "approval" ? record : undefined;
198
- }
199
- export function findPendingApprovalByConversation(conversationId) {
200
- const record = findPendingToolByConversation(conversationId);
201
- return record?.kind === "approval" ? record : undefined;
202
- }
203
- export function loadPendingClientTool(toolCallId) {
204
- return loadPendingTool(toolCallId);
205
- }
206
- export function findPendingClientToolByConversation(conversationId) {
207
- return findPendingToolByConversation(conversationId);
208
- }
209
- export function updatePendingAskConversation(previousConversationId, conversationId) {
210
- updatePendingClientToolConversation(previousConversationId, conversationId);
211
- }
212
- export function updatePendingClientToolConversation(previousConversationId, conversationId) {
213
- const now = new Date().toISOString();
214
- let matched = false;
215
- for (const wait of pendingTools.values()) {
216
- if (wait.record.conversationId === previousConversationId) {
217
- wait.record.conversationId = conversationId;
218
- wait.record.updatedAt = now;
219
- matched = true;
220
- }
221
- }
222
- if (!matched)
223
- return;
224
- stmtUpdateConversation.run(conversationId, now, previousConversationId);
225
- }
226
- export function waitPendingAsk(toolCallId) {
227
- return pendingTools.get(toolCallId)?.promise;
228
- }
229
- export function answerPendingAsk(toolCallId, answer) {
230
- const wait = pendingTools.get(toolCallId) ?? (loadPendingAsk(toolCallId) ? pendingTools.get(toolCallId) : undefined);
231
- if (!wait)
232
- return false;
233
- if (wait.record.kind !== "ask_user")
234
- return false;
235
- pendingTools.delete(toolCallId);
236
- stmtDelete.run(toolCallId);
237
- wait.resolve(answer);
238
- return true;
239
- }
240
- export function waitPendingApproval(toolCallId) {
241
- return pendingTools.get(toolCallId)?.promise;
242
- }
243
- export function answerPendingApproval(toolCallId, answer) {
244
- const wait = pendingTools.get(toolCallId) ?? (loadPendingApproval(toolCallId) ? pendingTools.get(toolCallId) : undefined);
245
- if (!wait)
246
- return false;
247
- if (wait.record.kind !== "approval")
248
- return false;
249
- pendingTools.delete(toolCallId);
250
- stmtDelete.run(toolCallId);
251
- wait.resolve(answer);
252
- return true;
253
- }
254
- export function deletePendingAsk(toolCallId, options = {}) {
255
- deletePendingClientTool(toolCallId, options);
256
- }
257
- export function deletePendingClientTool(toolCallId, options = {}) {
258
- const wait = pendingTools.get(toolCallId);
259
- pendingTools.delete(toolCallId);
260
- stmtDelete.run(toolCallId);
261
- if (wait && options.rejectWait) {
262
- wait.reject(new Error(`Pending client tool was cancelled: ${toolCallId}`));
263
- }
264
- }
265
- export function listPendingAsks() {
266
- return listPendingClientTools().filter((record) => record.kind === "ask_user");
267
- }
268
- export function listPendingClientTools() {
269
- const records = new Map();
270
- for (const row of stmtList.all()) {
271
- const record = rowToRecord(row);
272
- if (record)
273
- records.set(record.toolCallId, record);
274
- }
275
- for (const wait of pendingTools.values()) {
276
- records.set(wait.record.toolCallId, wait.record);
277
- }
278
- return Array.from(records.values()).sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
279
- }
280
- export function closePendingToolsDatabaseForTest() {
281
- pendingTools.clear();
282
- db.close();
283
- }
42
+ `),l=i.prepare("DELETE FROM pending_tools WHERE tool_call_id = ?"),I=i.prepare("SELECT * FROM pending_tools ORDER BY updated_at DESC, created_at DESC");function u(e){let n,t;const o=new Promise((r,a)=>{n=r,t=a});return{record:e,resolve:n,reject:t,promise:o}}function c(e){try{const n=JSON.parse(e.input_json),t={id:e.id,conversationId:e.conversation_id,toolCallId:e.tool_call_id,workdir:e.workdir,model:e.model??void 0,agentMode:e.agent_mode??void 0,input:n,createdAt:e.created_at,updatedAt:e.updated_at};if(e.kind==="approval"){const o=e.approval_json?JSON.parse(e.approval_json):{};return e.tool_name!=="ExitPlanMode"||typeof o.approveId!="string"?void 0:{...t,kind:"approval",toolName:"ExitPlanMode",approveId:o.approveId}}return e.kind!=="ask_user"||e.tool_name!=="AskUserQuestion"?void 0:{...t,kind:"ask_user",toolName:"AskUserQuestion"}}catch{return}}function g(e){x.run(e.toolCallId,e.id,e.kind,e.conversationId,e.workdir,e.model??null,e.agentMode??null,e.toolName,JSON.stringify(e.input),e.kind==="approval"?JSON.stringify({approveId:e.approveId}):null,e.createdAt,e.updatedAt)}function T(e){const n=d.get(e.toolCallId);if(n)return n;const t=u(e);return d.set(e.toolCallId,t),t}function p(e){const n=d.get(e)?.record;if(n)return n;const t=N.get(e),o=t?c(t):void 0;if(o)return T(o),o}function f(e){const n=Array.from(d.values(),r=>r.record).filter(r=>r.conversationId===e).sort((r,a)=>a.updatedAt.localeCompare(r.updatedAt))[0];if(n)return n;const t=P.get(e),o=t?c(t):void 0;if(o)return T(o),o}function F(e){const n=d.get(e.toolCallId);if(n?.record.kind==="ask_user")return n.record;const t=new Date().toISOString(),o={id:s(),kind:"ask_user",conversationId:e.conversationId,toolCallId:e.toolCallId,workdir:e.workdir,model:e.model,agentMode:e.agentMode,toolName:e.toolName,input:e.input,createdAt:t,updatedAt:t};return d.set(e.toolCallId,u(o)),g(o),o}function S(e){const n=p(e);return n?.kind==="ask_user"?n:void 0}function W(e){const n=f(e);return n?.kind==="ask_user"?n:void 0}function H(e){const n=d.get(e.toolCallId);if(n?.record.kind==="approval")return n.record;const t=new Date().toISOString(),o={id:s(),kind:"approval",conversationId:e.conversationId,toolCallId:e.toolCallId,workdir:e.workdir,model:e.model,agentMode:e.agentMode,toolName:e.toolName,input:e.input,approveId:s(),createdAt:t,updatedAt:t};return d.set(e.toolCallId,u(o)),g(o),o}function C(e){const n=p(e);return n?.kind==="approval"?n:void 0}function b(e){const n=f(e);return n?.kind==="approval"?n:void 0}function J(e){return p(e)}function Y(e){return f(e)}function h(e,n){L(e,n)}function L(e,n){const t=new Date().toISOString();let o=!1;for(const r of d.values())r.record.conversationId===e&&(r.record.conversationId=n,r.record.updatedAt=t,o=!0);o&&O.run(n,t,e)}function G(e){return d.get(e)?.promise}function Q(e,n){const t=d.get(e)??(S(e)?d.get(e):void 0);return!t||t.record.kind!=="ask_user"?!1:(d.delete(e),l.run(e),t.resolve(n),!0)}function K(e){return d.get(e)?.promise}function V(e,n){const t=d.get(e)??(C(e)?d.get(e):void 0);return!t||t.record.kind!=="approval"?!1:(d.delete(e),l.run(e),t.resolve(n),!0)}function q(e,n={}){w(e,n)}function w(e,n={}){const t=d.get(e);d.delete(e),l.run(e),t&&n.rejectWait&&t.reject(new Error(`Pending client tool was cancelled: ${e}`))}function $(){return D().filter(e=>e.kind==="ask_user")}function D(){const e=new Map;for(const n of I.all()){const t=c(n);t&&e.set(t.toolCallId,t)}for(const n of d.values())e.set(n.record.toolCallId,n.record);return Array.from(e.values()).sort((n,t)=>t.updatedAt.localeCompare(n.updatedAt))}function z(){d.clear(),i.close()}export{B as PENDING_APPROVAL_TOOL_NAMES,X as PENDING_ASK_TOOL_NAMES,V as answerPendingApproval,Q as answerPendingAsk,z as closePendingToolsDatabaseForTest,q as deletePendingAsk,w as deletePendingClientTool,b as findPendingApprovalByConversation,W as findPendingAskByConversation,Y as findPendingClientToolByConversation,$ as listPendingAsks,D as listPendingClientTools,C as loadPendingApproval,S as loadPendingAsk,J as loadPendingClientTool,H as savePendingApproval,F as savePendingAsk,h as updatePendingAskConversation,L as updatePendingClientToolConversation,K as waitPendingApproval,G as waitPendingAsk};
@@ -1,42 +1,6 @@
1
- import { existsSync, readFileSync } from "node:fs";
2
- import { fileURLToPath } from "node:url";
3
- import { logger } from "@messenger-agent/shared/logger";
4
- const DEFAULT_TEMPLATE_PATHS = [
5
- fileURLToPath(new URL("./assets/codex-home/AGENTS.md", import.meta.url)),
6
- fileURLToPath(new URL("../../../assets/codex-home/AGENTS.md", import.meta.url)),
7
- "/app/assets/codex-home/AGENTS.md",
8
- ];
9
- const CLAUDE_MANAGED_TASK_TOOLS = [
10
- "search_managed_tasks",
11
- "get_managed_task",
12
- "create_managed_task",
13
- "update_managed_task",
14
- "apply_managed_task_patch",
15
- "delete_managed_task",
16
- ];
17
- const CLAUDE_TASK_GUIDANCE = [
18
- "## Claude Managed Task Tools",
19
- "",
20
- "When the user asks to create, update, inspect, continue, summarize, or delete managed tasks, use the managed task MCP tools. The available tool basenames are: " +
21
- CLAUDE_MANAGED_TASK_TOOLS.map((name) => `\`${name}\``).join(", ") +
22
- ". Claude may expose them with an MCP namespace such as `mcp__managed_tasks__<tool>`.",
23
- "",
24
- ].join("\n");
25
- const CLAUDE_RESPONSE_STYLE_GUIDANCE = [
26
- "## Response Style",
27
- "",
28
- "Do not use emoji in responses.",
29
- "Use Markdown headings, bold, and italic formatting sparingly.",
30
- "Other Markdown formatting, such as lists, inline code, links, and code blocks, may be used as needed.",
31
- "",
32
- ].join("\n");
33
- const CLAUDE_PLATFORM_GUIDANCE = `${CLAUDE_TASK_GUIDANCE}\n${CLAUDE_RESPONSE_STYLE_GUIDANCE}`;
34
- export function loadClaudePlatformInstructions(templatePath) {
35
- const path = [templatePath ?? process.env.CLAUDE_MEMORY_TEMPLATE_PATH, ...DEFAULT_TEMPLATE_PATHS].find((candidate) => Boolean(candidate && existsSync(candidate)));
36
- if (!path) {
37
- logger.warn("Claude platform instructions template not found");
38
- return CLAUDE_PLATFORM_GUIDANCE;
39
- }
40
- return `${readFileSync(path, "utf-8").trimEnd()}\n\n${CLAUDE_PLATFORM_GUIDANCE}`;
41
- }
42
- export const claudePlatformInstructions = loadClaudePlatformInstructions();
1
+ import{existsSync as o,readFileSync as m}from"node:fs";import{fileURLToPath as s}from"node:url";import{logger as r}from"@messenger-agent/shared/logger";const d=[s(new URL("./assets/codex-home/AGENTS.md",import.meta.url)),s(new URL("../../../assets/codex-home/AGENTS.md",import.meta.url)),"/app/assets/codex-home/AGENTS.md"],i=["search_managed_tasks","get_managed_task","create_managed_task","update_managed_task","apply_managed_task_patch","delete_managed_task"],l=["## Claude Managed Task Tools","","When the user asks to create, update, inspect, continue, summarize, or delete managed tasks, use the managed task MCP tools. The available tool basenames are: "+i.map(e=>`\`${e}\``).join(", ")+". Claude may expose them with an MCP namespace such as `mcp__managed_tasks__<tool>`.",""].join(`
2
+ `),_=["## Response Style","","Do not use emoji in responses.","Use Markdown headings, bold, and italic formatting sparingly.","Other Markdown formatting, such as lists, inline code, links, and code blocks, may be used as needed.",""].join(`
3
+ `),n=`${l}
4
+ ${_}`;function c(e){const a=[e??process.env.CLAUDE_MEMORY_TEMPLATE_PATH,...d].find(t=>!!(t&&o(t)));return a?`${m(a,"utf-8").trimEnd()}
5
+
6
+ ${n}`:(r.warn("Claude platform instructions template not found"),n)}const A=c();export{A as claudePlatformInstructions,c as loadClaudePlatformInstructions};