@hienlh/ppm 0.2.12 → 0.2.14
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/package.json
CHANGED
|
@@ -13,6 +13,34 @@ import type {
|
|
|
13
13
|
UsageInfo,
|
|
14
14
|
} from "./provider.interface.ts";
|
|
15
15
|
import { configService } from "../services/config.service.ts";
|
|
16
|
+
import { resolve } from "node:path";
|
|
17
|
+
import { homedir } from "node:os";
|
|
18
|
+
import { readFileSync, writeFileSync, existsSync, mkdirSync } from "node:fs";
|
|
19
|
+
|
|
20
|
+
/** Persistent PPM sessionId → SDK sessionId mapping */
|
|
21
|
+
const SESSION_MAP_FILE = resolve(homedir(), ".ppm", "session-map.json");
|
|
22
|
+
|
|
23
|
+
function loadSessionMap(): Record<string, string> {
|
|
24
|
+
try {
|
|
25
|
+
if (existsSync(SESSION_MAP_FILE)) return JSON.parse(readFileSync(SESSION_MAP_FILE, "utf-8"));
|
|
26
|
+
} catch {}
|
|
27
|
+
return {};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function saveSessionMapping(ppmId: string, sdkId: string): void {
|
|
31
|
+
const map = loadSessionMap();
|
|
32
|
+
map[ppmId] = sdkId;
|
|
33
|
+
try {
|
|
34
|
+
const dir = resolve(homedir(), ".ppm");
|
|
35
|
+
if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
|
|
36
|
+
writeFileSync(SESSION_MAP_FILE, JSON.stringify(map));
|
|
37
|
+
} catch {}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function getSdkSessionId(ppmId: string): string {
|
|
41
|
+
const map = loadSessionMap();
|
|
42
|
+
return map[ppmId] ?? ppmId;
|
|
43
|
+
}
|
|
16
44
|
|
|
17
45
|
/**
|
|
18
46
|
* Pending approval: canUseTool callback creates a promise,
|
|
@@ -225,12 +253,15 @@ export class ClaudeAgentSdkProvider implements AIProvider {
|
|
|
225
253
|
|
|
226
254
|
try {
|
|
227
255
|
const providerConfig = this.getProviderConfig();
|
|
256
|
+
// Resolve SDK's actual session ID for resume (may differ from PPM's UUID)
|
|
257
|
+
const sdkId = getSdkSessionId(sessionId);
|
|
258
|
+
console.log(`[sdk] query: session=${sessionId} sdkId=${sdkId} isFirst=${isFirstMessage} cwd=${meta.projectPath ?? "(none)"}`);
|
|
228
259
|
|
|
229
260
|
const q = query({
|
|
230
261
|
prompt: message,
|
|
231
262
|
options: {
|
|
232
263
|
sessionId: isFirstMessage ? sessionId : undefined,
|
|
233
|
-
resume: isFirstMessage ? undefined :
|
|
264
|
+
resume: isFirstMessage ? undefined : sdkId,
|
|
234
265
|
cwd: meta.projectPath,
|
|
235
266
|
// Use full Claude Code system prompt (coding guidelines, security, response style)
|
|
236
267
|
systemPrompt: { type: "preset", preset: "claude_code" },
|
|
@@ -285,7 +316,9 @@ export class ClaudeAgentSdkProvider implements AIProvider {
|
|
|
285
316
|
const initMsg = msg as any;
|
|
286
317
|
// SDK may assign a different session_id than our UUID
|
|
287
318
|
if (initMsg.session_id && initMsg.session_id !== sessionId) {
|
|
288
|
-
//
|
|
319
|
+
// Persist mapping so resume works after server restart
|
|
320
|
+
saveSessionMapping(sessionId, initMsg.session_id);
|
|
321
|
+
// Update our in-memory mapping
|
|
289
322
|
const oldMeta = this.activeSessions.get(sessionId);
|
|
290
323
|
if (oldMeta) {
|
|
291
324
|
this.activeSessions.set(initMsg.session_id, { ...oldMeta, id: initMsg.session_id });
|
|
@@ -298,7 +331,7 @@ export class ClaudeAgentSdkProvider implements AIProvider {
|
|
|
298
331
|
// the SDK has finished executing tools. Fetch tool_results from session history.
|
|
299
332
|
if (pendingToolCount > 0 && (msg.type === "assistant" || (msg as any).type === "partial" || (msg as any).type === "stream_event")) {
|
|
300
333
|
try {
|
|
301
|
-
const sessionMsgs = await getSessionMessages(
|
|
334
|
+
const sessionMsgs = await getSessionMessages(sdkId);
|
|
302
335
|
// Find the last user message — it contains tool_result blocks
|
|
303
336
|
const lastUserMsg = [...sessionMsgs].reverse().find(
|
|
304
337
|
(m: any) => m.type === "user",
|
|
@@ -403,7 +436,7 @@ export class ClaudeAgentSdkProvider implements AIProvider {
|
|
|
403
436
|
// Flush any remaining pending tool_results before finishing
|
|
404
437
|
if (pendingToolCount > 0) {
|
|
405
438
|
try {
|
|
406
|
-
const sessionMsgs = await getSessionMessages(
|
|
439
|
+
const sessionMsgs = await getSessionMessages(sdkId);
|
|
407
440
|
const lastUserMsg = [...sessionMsgs].reverse().find(
|
|
408
441
|
(m: any) => m.type === "user",
|
|
409
442
|
);
|
|
@@ -437,14 +470,20 @@ export class ClaudeAgentSdkProvider implements AIProvider {
|
|
|
437
470
|
|
|
438
471
|
// Surface non-success subtypes as errors so FE can display them
|
|
439
472
|
if (subtype && subtype !== "success") {
|
|
473
|
+
// Extract error detail from SDK result if available
|
|
474
|
+
const sdkError = result.error ?? result.error_message ?? result.message ?? "";
|
|
475
|
+
const sdkDetail = typeof sdkError === "string" ? sdkError : JSON.stringify(sdkError);
|
|
440
476
|
const errorMessages: Record<string, string> = {
|
|
441
477
|
error_max_turns: "Agent reached maximum turn limit.",
|
|
442
478
|
error_max_budget_usd: "Agent reached budget limit.",
|
|
443
479
|
error_during_execution: "Agent encountered an error during execution.",
|
|
444
480
|
};
|
|
481
|
+
const baseMsg = errorMessages[subtype] ?? `Agent stopped: ${subtype}`;
|
|
482
|
+
const fullMsg = sdkDetail ? `${baseMsg}\n${sdkDetail}` : baseMsg;
|
|
483
|
+
console.error(`[sdk] result error: subtype=${subtype} turns=${result.num_turns ?? 0} detail=${sdkDetail || "(none)"} raw=${JSON.stringify(result).slice(0, 500)}`);
|
|
445
484
|
yield {
|
|
446
485
|
type: "error",
|
|
447
|
-
message:
|
|
486
|
+
message: fullMsg,
|
|
448
487
|
};
|
|
449
488
|
}
|
|
450
489
|
|
|
@@ -493,7 +532,8 @@ export class ClaudeAgentSdkProvider implements AIProvider {
|
|
|
493
532
|
|
|
494
533
|
async getMessages(sessionId: string): Promise<ChatMessage[]> {
|
|
495
534
|
try {
|
|
496
|
-
const
|
|
535
|
+
const sdkId = getSdkSessionId(sessionId);
|
|
536
|
+
const messages = await getSessionMessages(sdkId);
|
|
497
537
|
const parsed = messages.map((msg) => parseSessionMessage(msg));
|
|
498
538
|
|
|
499
539
|
// Merge tool_result user messages into the preceding assistant message
|