@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.
Files changed (35) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/assets/skills/ppm/SKILL.md +1 -1
  3. package/assets/skills/ppm/references/http-api.md +1 -1
  4. package/dist/web/assets/{audio-preview-DPUWgkFM.js → audio-preview-CKyqt8Qa.js} +1 -1
  5. package/dist/web/assets/{chat-tab-jeH2KOyI.js → chat-tab-6xXNp6td.js} +3 -3
  6. package/dist/web/assets/{code-editor-D689bNqg.js → code-editor-DWNVyji6.js} +2 -2
  7. package/dist/web/assets/{conflict-editor-BBLBwDP3.js → conflict-editor-pC5U_tzr.js} +1 -1
  8. package/dist/web/assets/{database-viewer-Dn_XmPuG.js → database-viewer-Qp7wc8sJ.js} +1 -1
  9. package/dist/web/assets/{diff-viewer-BawweIzs.js → diff-viewer-FyAyKn4J.js} +1 -1
  10. package/dist/web/assets/{extension-webview-CnW4FmbT.js → extension-webview-CVylZpkv.js} +1 -1
  11. package/dist/web/assets/{git-log-panel-DOtefVWL.js → git-log-panel-BA4xxiZR.js} +1 -1
  12. package/dist/web/assets/{glide-data-grid-ckYYsHxU.js → glide-data-grid-PZOzxnWV.js} +1 -1
  13. package/dist/web/assets/{image-preview-vivCL0Rz.js → image-preview-meDqzT6e.js} +1 -1
  14. package/dist/web/assets/{index-tXhZwam6.js → index-Drwzii_w.js} +3 -3
  15. package/dist/web/assets/keybindings-store-D6R_grEQ.js +1 -0
  16. package/dist/web/assets/{markdown-renderer-BiLohd4E.js → markdown-renderer-BPuu5Czn.js} +1 -1
  17. package/dist/web/assets/notification-store-eSbjsPHn.js +1 -0
  18. package/dist/web/assets/{pdf-preview-CZxInEra.js → pdf-preview-CE6iGnyw.js} +1 -1
  19. package/dist/web/assets/{port-forwarding-tab-cEuRXpkT.js → port-forwarding-tab-Bm2K9NO-.js} +1 -1
  20. package/dist/web/assets/{postgres-viewer-DotG-n6G.js → postgres-viewer-D72BwBOg.js} +1 -1
  21. package/dist/web/assets/{settings-tab-DCNSHpkk.js → settings-tab-BTT3CCTS.js} +1 -1
  22. package/dist/web/assets/{sql-query-editor-wMM7vxn4.js → sql-query-editor-BiVMmcK3.js} +1 -1
  23. package/dist/web/assets/{sqlite-viewer-fczUQ3pm.js → sqlite-viewer-CKdZF5AA.js} +1 -1
  24. package/dist/web/assets/{system-monitor-tab-DnjKZ6kX.js → system-monitor-tab-PIhMDYPP.js} +1 -1
  25. package/dist/web/assets/{terminal-tab-4VTsRAv_.js → terminal-tab-BHFM5N0l.js} +1 -1
  26. package/dist/web/assets/{video-preview-Aabd59Fv.js → video-preview-DC5PWgPo.js} +1 -1
  27. package/dist/web/index.html +1 -1
  28. package/dist/web/sw.js +1 -1
  29. package/package.json +1 -1
  30. package/packages/ext-git-graph/src/webview-html.ts +2 -2
  31. package/src/providers/claude-agent-sdk.ts +55 -15
  32. package/src/services/db.service.ts +7 -4
  33. package/src/web/lib/score-file-search.ts +18 -0
  34. package/dist/web/assets/keybindings-store-BPLIbuiX.js +0 -1
  35. 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
- initialCtrl.push(firstMsg);
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(firstMsg);
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
- // Always re-push firstMsg — SDK needs a user message from the generator
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(firstMsg);
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(firstMsg);
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(firstMsg);
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(firstMsg);
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(firstMsg);
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
- // Escape LIKE wildcards so user input is treated as literal text
1223
- const escaped = query.replace(/[%_\\]/g, "\\$&");
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 tc.table_name LIKE ? ESCAPE '\\'
1231
+ WHERE ${whereClauses}
1229
1232
  ORDER BY tc.table_name, c.name
1230
1233
  LIMIT 50`,
1231
- ).all(`%${escaped}%`) as Array<TableCacheRow & { connection_name: string; connection_type: string; connection_color: string | null }>;
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};