@hienlh/ppm 0.13.59 → 0.13.61
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/CHANGELOG.md +10 -0
- package/assets/skills/ppm/SKILL.md +1 -1
- package/assets/skills/ppm/references/http-api.md +1 -1
- package/dist/web/assets/{audio-preview-DPUWgkFM.js → audio-preview-CKyqt8Qa.js} +1 -1
- package/dist/web/assets/{chat-tab-jeH2KOyI.js → chat-tab-6xXNp6td.js} +3 -3
- package/dist/web/assets/{code-editor-D689bNqg.js → code-editor-DWNVyji6.js} +2 -2
- package/dist/web/assets/{conflict-editor-BBLBwDP3.js → conflict-editor-pC5U_tzr.js} +1 -1
- package/dist/web/assets/{database-viewer-Dn_XmPuG.js → database-viewer-Qp7wc8sJ.js} +1 -1
- package/dist/web/assets/{diff-viewer-BawweIzs.js → diff-viewer-FyAyKn4J.js} +1 -1
- package/dist/web/assets/{extension-webview-CnW4FmbT.js → extension-webview-CVylZpkv.js} +1 -1
- package/dist/web/assets/{git-log-panel-DOtefVWL.js → git-log-panel-BA4xxiZR.js} +1 -1
- package/dist/web/assets/{glide-data-grid-ckYYsHxU.js → glide-data-grid-PZOzxnWV.js} +1 -1
- package/dist/web/assets/{image-preview-vivCL0Rz.js → image-preview-meDqzT6e.js} +1 -1
- package/dist/web/assets/{index-tXhZwam6.js → index-Drwzii_w.js} +3 -3
- package/dist/web/assets/keybindings-store-D6R_grEQ.js +1 -0
- package/dist/web/assets/{markdown-renderer-BiLohd4E.js → markdown-renderer-BPuu5Czn.js} +1 -1
- package/dist/web/assets/notification-store-eSbjsPHn.js +1 -0
- package/dist/web/assets/{pdf-preview-CZxInEra.js → pdf-preview-CE6iGnyw.js} +1 -1
- package/dist/web/assets/{port-forwarding-tab-cEuRXpkT.js → port-forwarding-tab-Bm2K9NO-.js} +1 -1
- package/dist/web/assets/{postgres-viewer-DotG-n6G.js → postgres-viewer-D72BwBOg.js} +1 -1
- package/dist/web/assets/{settings-tab-DCNSHpkk.js → settings-tab-BTT3CCTS.js} +1 -1
- package/dist/web/assets/{sql-query-editor-wMM7vxn4.js → sql-query-editor-BiVMmcK3.js} +1 -1
- package/dist/web/assets/{sqlite-viewer-fczUQ3pm.js → sqlite-viewer-CKdZF5AA.js} +1 -1
- package/dist/web/assets/{system-monitor-tab-DnjKZ6kX.js → system-monitor-tab-PIhMDYPP.js} +1 -1
- package/dist/web/assets/{terminal-tab-4VTsRAv_.js → terminal-tab-BHFM5N0l.js} +1 -1
- package/dist/web/assets/{video-preview-Aabd59Fv.js → video-preview-DC5PWgPo.js} +1 -1
- package/dist/web/index.html +1 -1
- package/dist/web/sw.js +1 -1
- package/package.json +1 -1
- package/packages/ext-git-graph/src/webview-html.ts +2 -2
- package/src/providers/claude-agent-sdk.ts +55 -15
- package/src/services/db.service.ts +7 -4
- package/src/web/lib/score-file-search.ts +18 -0
- package/dist/web/assets/keybindings-store-BPLIbuiX.js +0 -1
- package/dist/web/assets/notification-store-DfPnCRYc.js +0 -1
|
@@ -102,6 +102,10 @@ interface StreamingSession {
|
|
|
102
102
|
meta: Session;
|
|
103
103
|
query: any;
|
|
104
104
|
controller: MessageController;
|
|
105
|
+
/** Latest user message content — updated on follow-ups for accurate retry */
|
|
106
|
+
lastUserContent: string;
|
|
107
|
+
/** Latest user message images — updated on follow-ups for accurate retry */
|
|
108
|
+
lastUserImages?: Array<{ data: string; mediaType: string }>;
|
|
105
109
|
}
|
|
106
110
|
|
|
107
111
|
/**
|
|
@@ -550,6 +554,9 @@ export class ClaudeAgentSdkProvider implements AIProvider {
|
|
|
550
554
|
session_id: sessionId,
|
|
551
555
|
priority: opts?.priority ?? 'next',
|
|
552
556
|
});
|
|
557
|
+
// Track latest message for retry paths (fixes stale firstMsg bug)
|
|
558
|
+
ss.lastUserContent = content;
|
|
559
|
+
ss.lastUserImages = opts?.images;
|
|
553
560
|
console.log(`[sdk] pushMessage: session=${sessionId} priority=${opts?.priority ?? 'next'}`);
|
|
554
561
|
}
|
|
555
562
|
|
|
@@ -607,6 +614,9 @@ export class ClaudeAgentSdkProvider implements AIProvider {
|
|
|
607
614
|
session_id: sessionId,
|
|
608
615
|
priority: opts?.priority ?? 'next',
|
|
609
616
|
});
|
|
617
|
+
// Track latest message for retry paths (fixes stale firstMsg bug)
|
|
618
|
+
existingStream.lastUserContent = message;
|
|
619
|
+
existingStream.lastUserImages = opts?.images;
|
|
610
620
|
console.log(`[sdk] sendMessage follow-up: session=${sessionId} pushed to generator`);
|
|
611
621
|
return; // Events flow through first-message's consumer loop
|
|
612
622
|
}
|
|
@@ -864,8 +874,32 @@ export class ClaudeAgentSdkProvider implements AIProvider {
|
|
|
864
874
|
session_id: sessionId,
|
|
865
875
|
};
|
|
866
876
|
|
|
877
|
+
// Build a retry message from the LATEST user content (not the stale firstMsg).
|
|
878
|
+
// Follow-ups via pushMessage update lastUserContent on the streaming session,
|
|
879
|
+
// so retries after token refresh correctly replay the current turn.
|
|
880
|
+
// Also returns the raw content/images for re-populating the new streaming session.
|
|
881
|
+
const buildRetryMsg = () => {
|
|
882
|
+
const ss = this.streamingSessions.get(sessionId);
|
|
883
|
+
const content = ss?.lastUserContent ?? message;
|
|
884
|
+
const images = ss?.lastUserImages;
|
|
885
|
+
return {
|
|
886
|
+
msg: {
|
|
887
|
+
type: 'user' as const,
|
|
888
|
+
message: buildMessageParam(content, images),
|
|
889
|
+
parent_tool_use_id: null,
|
|
890
|
+
session_id: sessionId,
|
|
891
|
+
},
|
|
892
|
+
lastUserContent: content,
|
|
893
|
+
lastUserImages: images,
|
|
894
|
+
};
|
|
895
|
+
};
|
|
896
|
+
|
|
867
897
|
const { generator: streamGen, controller: initialCtrl } = createMessageChannel();
|
|
868
|
-
|
|
898
|
+
// On crash retry, use buildRetryMsg to get the latest user message (not the stale firstMsg)
|
|
899
|
+
const initRetry = crashRetryCount > 0 ? buildRetryMsg() : null;
|
|
900
|
+
initialCtrl.push(initRetry?.msg ?? firstMsg);
|
|
901
|
+
const initContent = initRetry?.lastUserContent ?? message;
|
|
902
|
+
const initImages = initRetry?.lastUserImages ?? opts?.images;
|
|
869
903
|
|
|
870
904
|
const initialQuery = query({
|
|
871
905
|
prompt: streamGen,
|
|
@@ -875,7 +909,7 @@ export class ClaudeAgentSdkProvider implements AIProvider {
|
|
|
875
909
|
canUseTool,
|
|
876
910
|
} as any,
|
|
877
911
|
});
|
|
878
|
-
this.streamingSessions.set(sessionId, { meta, query: initialQuery, controller: initialCtrl });
|
|
912
|
+
this.streamingSessions.set(sessionId, { meta, query: initialQuery, controller: initialCtrl, lastUserContent: initContent, lastUserImages: initImages });
|
|
879
913
|
this.activeQueries.set(sessionId, initialQuery);
|
|
880
914
|
let eventSource: AsyncIterable<any> = initialQuery;
|
|
881
915
|
console.log(`[sdk] session=${sessionId} query() created, waiting for first SDK event...`);
|
|
@@ -924,16 +958,17 @@ export class ClaudeAgentSdkProvider implements AIProvider {
|
|
|
924
958
|
retryCount++;
|
|
925
959
|
console.warn(`[sdk] transient error on first event — retrying (attempt ${retryCount}/${MAX_RETRIES})`);
|
|
926
960
|
// Close current streaming session (uses streamingSessions, not stale closure refs)
|
|
961
|
+
const retry1 = buildRetryMsg();
|
|
927
962
|
closeCurrentStream();
|
|
928
963
|
const { generator: retryGen, controller: retryCtrl } = createMessageChannel();
|
|
929
|
-
retryCtrl.push(
|
|
964
|
+
retryCtrl.push(retry1.msg);
|
|
930
965
|
// Retry with resume (safe even if JSONL doesn't exist yet — SDK handles gracefully)
|
|
931
966
|
const retryOpts = { ...queryOptions, sessionId: undefined, resume: sessionId };
|
|
932
967
|
const rq = query({
|
|
933
968
|
prompt: retryGen,
|
|
934
969
|
options: { ...retryOpts, ...(permissionHooks && { hooks: permissionHooks }), canUseTool } as any,
|
|
935
970
|
});
|
|
936
|
-
this.streamingSessions.set(sessionId, { meta, query: rq, controller: retryCtrl });
|
|
971
|
+
this.streamingSessions.set(sessionId, { meta, query: rq, controller: retryCtrl, lastUserContent: retry1.lastUserContent, lastUserImages: retry1.lastUserImages });
|
|
937
972
|
this.activeQueries.set(sessionId, rq);
|
|
938
973
|
eventSource = rq;
|
|
939
974
|
continue retryLoop;
|
|
@@ -994,17 +1029,18 @@ export class ClaudeAgentSdkProvider implements AIProvider {
|
|
|
994
1029
|
authRetryCount = recovered.newRetryCount;
|
|
995
1030
|
account = recovered.account;
|
|
996
1031
|
const retryEnv = this.buildQueryEnv(meta.projectPath, account);
|
|
1032
|
+
const retry2 = buildRetryMsg();
|
|
997
1033
|
closeCurrentStream();
|
|
998
1034
|
const { generator: earlyAuthGen, controller: earlyAuthCtrl } = createMessageChannel();
|
|
999
|
-
//
|
|
1035
|
+
// Re-push current turn's message — SDK needs a user message from the generator
|
|
1000
1036
|
// even with resume (resume loads JSONL history, generator provides current turn)
|
|
1001
|
-
earlyAuthCtrl.push(
|
|
1037
|
+
earlyAuthCtrl.push(retry2.msg);
|
|
1002
1038
|
const retryOpts = { ...queryOptions, sessionId: undefined, resume: sessionId, env: retryEnv };
|
|
1003
1039
|
const rq = query({
|
|
1004
1040
|
prompt: earlyAuthGen,
|
|
1005
1041
|
options: { ...retryOpts, ...(permissionHooks && { hooks: permissionHooks }), canUseTool } as any,
|
|
1006
1042
|
});
|
|
1007
|
-
this.streamingSessions.set(sessionId, { meta, query: rq, controller: earlyAuthCtrl });
|
|
1043
|
+
this.streamingSessions.set(sessionId, { meta, query: rq, controller: earlyAuthCtrl, lastUserContent: retry2.lastUserContent, lastUserImages: retry2.lastUserImages });
|
|
1008
1044
|
this.activeQueries.set(sessionId, rq);
|
|
1009
1045
|
eventSource = rq;
|
|
1010
1046
|
continue retryLoop;
|
|
@@ -1151,15 +1187,16 @@ export class ClaudeAgentSdkProvider implements AIProvider {
|
|
|
1151
1187
|
authRetryCount = recovered.newRetryCount;
|
|
1152
1188
|
account = recovered.account;
|
|
1153
1189
|
const retryEnv = this.buildQueryEnv(meta.projectPath, account);
|
|
1190
|
+
const retry3 = buildRetryMsg();
|
|
1154
1191
|
closeCurrentStream();
|
|
1155
1192
|
const { generator: authRetryGen, controller: authRetryCtrl } = createMessageChannel();
|
|
1156
|
-
authRetryCtrl.push(
|
|
1193
|
+
authRetryCtrl.push(retry3.msg);
|
|
1157
1194
|
const retryOpts = { ...queryOptions, sessionId: undefined, resume: sessionId, env: retryEnv };
|
|
1158
1195
|
const rq = query({
|
|
1159
1196
|
prompt: authRetryGen,
|
|
1160
1197
|
options: { ...retryOpts, ...(permissionHooks && { hooks: permissionHooks }), canUseTool } as any,
|
|
1161
1198
|
});
|
|
1162
|
-
this.streamingSessions.set(sessionId, { meta, query: rq, controller: authRetryCtrl });
|
|
1199
|
+
this.streamingSessions.set(sessionId, { meta, query: rq, controller: authRetryCtrl, lastUserContent: retry3.lastUserContent, lastUserImages: retry3.lastUserImages });
|
|
1163
1200
|
this.activeQueries.set(sessionId, rq);
|
|
1164
1201
|
eventSource = rq;
|
|
1165
1202
|
continue retryLoop;
|
|
@@ -1189,16 +1226,17 @@ export class ClaudeAgentSdkProvider implements AIProvider {
|
|
|
1189
1226
|
yield { type: "error", message: `Rate limited. Auto-retrying in ${backoff / 1000}s... (${rateLimitRetryCount}/${MAX_RATE_LIMIT_RETRIES})` };
|
|
1190
1227
|
await new Promise((r) => setTimeout(r, backoff));
|
|
1191
1228
|
// Close current streaming session and recreate with (potentially new) account env.
|
|
1229
|
+
const retry4 = buildRetryMsg();
|
|
1192
1230
|
closeCurrentStream();
|
|
1193
1231
|
const rlRetryEnv = this.buildQueryEnv(meta.projectPath, account);
|
|
1194
1232
|
const { generator: rlRetryGen, controller: rlRetryCtrl } = createMessageChannel();
|
|
1195
|
-
rlRetryCtrl.push(
|
|
1233
|
+
rlRetryCtrl.push(retry4.msg);
|
|
1196
1234
|
const retryOpts = { ...queryOptions, sessionId: undefined, resume: sessionId, env: rlRetryEnv };
|
|
1197
1235
|
const rq = query({
|
|
1198
1236
|
prompt: rlRetryGen,
|
|
1199
1237
|
options: { ...retryOpts, ...(permissionHooks && { hooks: permissionHooks }), canUseTool } as any,
|
|
1200
1238
|
});
|
|
1201
|
-
this.streamingSessions.set(sessionId, { meta, query: rq, controller: rlRetryCtrl });
|
|
1239
|
+
this.streamingSessions.set(sessionId, { meta, query: rq, controller: rlRetryCtrl, lastUserContent: retry4.lastUserContent, lastUserImages: retry4.lastUserImages });
|
|
1202
1240
|
this.activeQueries.set(sessionId, rq);
|
|
1203
1241
|
eventSource = rq;
|
|
1204
1242
|
continue retryLoop;
|
|
@@ -1284,16 +1322,17 @@ export class ClaudeAgentSdkProvider implements AIProvider {
|
|
|
1284
1322
|
}
|
|
1285
1323
|
yield { type: "error", message: `Rate limited. Auto-retrying in ${backoff / 1000}s... (${rateLimitRetryCount}/${MAX_RATE_LIMIT_RETRIES})` };
|
|
1286
1324
|
await new Promise((r) => setTimeout(r, backoff));
|
|
1325
|
+
const retry5 = buildRetryMsg();
|
|
1287
1326
|
closeCurrentStream();
|
|
1288
1327
|
const rlRetryEnv = this.buildQueryEnv(meta.projectPath, account);
|
|
1289
1328
|
const { generator: rlRetryGen, controller: rlRetryCtrl } = createMessageChannel();
|
|
1290
|
-
rlRetryCtrl.push(
|
|
1329
|
+
rlRetryCtrl.push(retry5.msg);
|
|
1291
1330
|
const retryOpts = { ...queryOptions, sessionId: undefined, resume: sessionId, env: rlRetryEnv };
|
|
1292
1331
|
const rq = query({
|
|
1293
1332
|
prompt: rlRetryGen,
|
|
1294
1333
|
options: { ...retryOpts, ...(permissionHooks && { hooks: permissionHooks }), canUseTool } as any,
|
|
1295
1334
|
});
|
|
1296
|
-
this.streamingSessions.set(sessionId, { meta, query: rq, controller: rlRetryCtrl });
|
|
1335
|
+
this.streamingSessions.set(sessionId, { meta, query: rq, controller: rlRetryCtrl, lastUserContent: retry5.lastUserContent, lastUserImages: retry5.lastUserImages });
|
|
1297
1336
|
this.activeQueries.set(sessionId, rq);
|
|
1298
1337
|
eventSource = rq;
|
|
1299
1338
|
continue retryLoop;
|
|
@@ -1312,16 +1351,17 @@ export class ClaudeAgentSdkProvider implements AIProvider {
|
|
|
1312
1351
|
if (recovered) {
|
|
1313
1352
|
authRetryCount = recovered.newRetryCount;
|
|
1314
1353
|
account = recovered.account;
|
|
1354
|
+
const retry6 = buildRetryMsg();
|
|
1315
1355
|
closeCurrentStream();
|
|
1316
1356
|
const retryEnv = this.buildQueryEnv(meta.projectPath, account);
|
|
1317
1357
|
const { generator: authRetryGen2, controller: authRetryCtrl2 } = createMessageChannel();
|
|
1318
|
-
authRetryCtrl2.push(
|
|
1358
|
+
authRetryCtrl2.push(retry6.msg);
|
|
1319
1359
|
const retryOpts = { ...queryOptions, sessionId: undefined, resume: sessionId, env: retryEnv };
|
|
1320
1360
|
const rq = query({
|
|
1321
1361
|
prompt: authRetryGen2,
|
|
1322
1362
|
options: { ...retryOpts, ...(permissionHooks && { hooks: permissionHooks }), canUseTool } as any,
|
|
1323
1363
|
});
|
|
1324
|
-
this.streamingSessions.set(sessionId, { meta, query: rq, controller: authRetryCtrl2 });
|
|
1364
|
+
this.streamingSessions.set(sessionId, { meta, query: rq, controller: authRetryCtrl2, lastUserContent: retry6.lastUserContent, lastUserImages: retry6.lastUserImages });
|
|
1325
1365
|
this.activeQueries.set(sessionId, rq);
|
|
1326
1366
|
eventSource = rq;
|
|
1327
1367
|
continue retryLoop;
|
|
@@ -1219,16 +1219,19 @@ export function deleteTableCache(connectionId: number): void {
|
|
|
1219
1219
|
}
|
|
1220
1220
|
|
|
1221
1221
|
export function searchTableCache(query: string): Array<TableCacheRow & { connection_name: string; connection_type: string; connection_color: string | null }> {
|
|
1222
|
-
//
|
|
1223
|
-
const
|
|
1222
|
+
// Split on spaces so "company parent" matches "company_parents", "company.parent", etc.
|
|
1223
|
+
const words = query.trim().split(/\s+/).filter(Boolean);
|
|
1224
|
+
if (words.length === 0) return [];
|
|
1225
|
+
const params = words.map((w) => `%${w.replace(/[%_\\]/g, "\\$&")}%`);
|
|
1226
|
+
const whereClauses = params.map(() => `tc.table_name LIKE ? ESCAPE '\\'`).join(" AND ");
|
|
1224
1227
|
return getDb().query(
|
|
1225
1228
|
`SELECT tc.*, c.name as connection_name, c.type as connection_type, c.color as connection_color
|
|
1226
1229
|
FROM connection_table_cache tc
|
|
1227
1230
|
JOIN connections c ON tc.connection_id = c.id
|
|
1228
|
-
WHERE
|
|
1231
|
+
WHERE ${whereClauses}
|
|
1229
1232
|
ORDER BY tc.table_name, c.name
|
|
1230
1233
|
LIMIT 50`,
|
|
1231
|
-
).all(
|
|
1234
|
+
).all(...params) as Array<TableCacheRow & { connection_name: string; connection_type: string; connection_color: string | null }>;
|
|
1232
1235
|
}
|
|
1233
1236
|
|
|
1234
1237
|
// ---------------------------------------------------------------------------
|
|
@@ -58,6 +58,24 @@ export function scoreFileSearchFast(
|
|
|
58
58
|
labelLen: number,
|
|
59
59
|
depth: number,
|
|
60
60
|
): FileSearchScore | null {
|
|
61
|
+
// Multi-word query: score each word independently, require all to match
|
|
62
|
+
if (qLower.includes(" ")) {
|
|
63
|
+
const words = qLower.split(/\s+/).filter(Boolean);
|
|
64
|
+
if (words.length === 0) return null;
|
|
65
|
+
if (words.length === 1) {
|
|
66
|
+
return scoreFileSearchFast(words[0]!, filenameLower, pathLower, labelLen, depth);
|
|
67
|
+
}
|
|
68
|
+
let maxTier = 0;
|
|
69
|
+
let totalOffset = 0;
|
|
70
|
+
for (const word of words) {
|
|
71
|
+
const s = scoreFileSearchFast(word, filenameLower, pathLower, labelLen, depth);
|
|
72
|
+
if (!s) return null;
|
|
73
|
+
maxTier = Math.max(maxTier, s.tier);
|
|
74
|
+
totalOffset += s.offset;
|
|
75
|
+
}
|
|
76
|
+
return { tier: maxTier, offset: totalOffset, nameLen: labelLen, depth };
|
|
77
|
+
}
|
|
78
|
+
|
|
61
79
|
// Tier 0: exact filename match
|
|
62
80
|
if (filenameLower === qLower) return { tier: 0, offset: 0, nameLen: labelLen, depth };
|
|
63
81
|
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import"./vendor-markdown-0Mxgxy0L.js";import"./api-client-DiZgVOok.js";import{D as e}from"./index-tXhZwam6.js";export{e as useKeybindingsStore};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import"./vendor-markdown-0Mxgxy0L.js";import"./api-client-DiZgVOok.js";import{P as e}from"./index-tXhZwam6.js";export{e as useNotificationStore};
|