@hienlh/ppm 0.13.0 → 0.13.3
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 +30 -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-J5neETTY.js → audio-preview-R7cq1uhJ.js} +1 -1
- package/dist/web/assets/chat-tab-umei1UkV.js +12 -0
- package/dist/web/assets/{code-editor-tMfcFaQ5.js → code-editor-BTosKXkr.js} +2 -2
- package/dist/web/assets/{conflict-editor-FydCxWTC.js → conflict-editor-dzofjxab.js} +1 -1
- package/dist/web/assets/{database-viewer-Celi1puH.js → database-viewer-5Uf8Rrls.js} +1 -1
- package/dist/web/assets/{diff-viewer-NgDJLTk9.js → diff-viewer-DKLeIBkK.js} +1 -1
- package/dist/web/assets/{extension-webview-xWAdCj3q.js → extension-webview-HILvTnnn.js} +1 -1
- package/dist/web/assets/{image-preview-C6bFkdZD.js → image-preview-0cJMnFZK.js} +1 -1
- package/dist/web/assets/index-Bce0weeW.css +2 -0
- package/dist/web/assets/index-DDBvHVVr.js +27 -0
- package/dist/web/assets/{markdown-renderer-BAnnk1pI.js → markdown-renderer-D0MrsVJB.js} +1 -1
- package/dist/web/assets/{pdf-preview-BNuFTSOL.js → pdf-preview-BBVDS-z5.js} +1 -1
- package/dist/web/assets/{port-forwarding-tab-BbDlGxAs.js → port-forwarding-tab-ByKzBs-R.js} +1 -1
- package/dist/web/assets/{postgres-viewer-Cman1YRO.js → postgres-viewer-BnCbdR7g.js} +1 -1
- package/dist/web/assets/{settings-tab-n5X_Dbu4.js → settings-tab-BPdzUw3v.js} +1 -1
- package/dist/web/assets/{sqlite-viewer-D6JT11uu.js → sqlite-viewer-D6mSIIx2.js} +1 -1
- package/dist/web/assets/{terminal-tab-B4kMthYo.js → terminal-tab-BLIA53mt.js} +1 -1
- package/dist/web/assets/{video-preview-BftQOOzF.js → video-preview-CKaht6nI.js} +1 -1
- package/dist/web/index.html +2 -2
- package/dist/web/sw.js +1 -1
- package/package.json +1 -1
- package/src/index.ts +0 -0
- package/src/providers/claude-agent-sdk.ts +5 -2
- package/src/server/index.ts +12 -4
- package/src/server/routes/chat.ts +10 -1
- package/src/server/ws/chat.ts +29 -2
- package/src/services/autostart-generator.ts +3 -1
- package/src/services/autostart-register.ts +17 -0
- package/src/services/sd-notify.ts +27 -0
- package/src/services/supervisor.ts +31 -5
- package/src/types/chat.ts +1 -1
- package/src/web/components/chat/chat-history-bar.tsx +2 -9
- package/src/web/components/chat/chat-history-panel.tsx +2 -9
- package/src/web/components/chat/chat-welcome.tsx +1 -18
- package/src/web/components/chat/message-list.tsx +6 -5
- package/src/web/components/layout/command-palette.tsx +35 -12
- package/src/web/components/layout/draggable-tab.tsx +12 -5
- package/src/web/hooks/use-chat.ts +6 -0
- package/src/web/hooks/use-notification-badge.ts +7 -7
- package/src/web/lib/favicon.ts +37 -15
- package/src/web/lib/format-date.ts +21 -0
- package/src/web/lib/score-file-search.ts +41 -21
- package/src/web/styles/globals.css +12 -0
- package/bun.lock +0 -2062
- package/bunfig.toml +0 -2
- package/dist/web/assets/chat-tab-sVHRa1Fz.js +0 -12
- package/dist/web/assets/index-BMhiElt6.css +0 -2
- package/dist/web/assets/index-DtbAoxyy.js +0 -23
|
@@ -6,6 +6,10 @@
|
|
|
6
6
|
* > path contains(3) > fuzzy filename(4) > fuzzy path(5)
|
|
7
7
|
*
|
|
8
8
|
* Tie-breakers: shorter filename, fewer path segments.
|
|
9
|
+
*
|
|
10
|
+
* Hot-path note: callers pass PRE-LOWERCASED strings to avoid repeated
|
|
11
|
+
* allocations per keystroke. Use `scoreFileSearch` (convenience wrapper)
|
|
12
|
+
* for ad-hoc calls; use `scoreFileSearchFast` for the inner loop.
|
|
9
13
|
*/
|
|
10
14
|
|
|
11
15
|
export interface FileSearchScore {
|
|
@@ -20,7 +24,7 @@ export interface FileSearchScore {
|
|
|
20
24
|
}
|
|
21
25
|
|
|
22
26
|
/** Extract filename from a path */
|
|
23
|
-
function getFilename(path: string): string {
|
|
27
|
+
export function getFilename(path: string): string {
|
|
24
28
|
const i = Math.max(path.lastIndexOf("/"), path.lastIndexOf("\\"));
|
|
25
29
|
return i >= 0 ? path.slice(i + 1) : path;
|
|
26
30
|
}
|
|
@@ -43,42 +47,58 @@ function fuzzyGap(query: string, text: string): number {
|
|
|
43
47
|
return gap;
|
|
44
48
|
}
|
|
45
49
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
+
/**
|
|
51
|
+
* Fast scoring — requires pre-lowercased inputs. Use for tight loops.
|
|
52
|
+
* All string params MUST already be lowercase.
|
|
53
|
+
*/
|
|
54
|
+
export function scoreFileSearchFast(
|
|
55
|
+
qLower: string,
|
|
56
|
+
filenameLower: string,
|
|
57
|
+
pathLower: string,
|
|
58
|
+
labelLen: number,
|
|
59
|
+
depth: number,
|
|
50
60
|
): FileSearchScore | null {
|
|
51
|
-
const q = query.toLowerCase();
|
|
52
|
-
const nameLower = label.toLowerCase();
|
|
53
|
-
const pathLower = path.toLowerCase();
|
|
54
|
-
const filename = getFilename(pathLower);
|
|
55
|
-
const depth = path.split("/").length;
|
|
56
|
-
|
|
57
61
|
// Tier 0: exact filename match
|
|
58
|
-
if (
|
|
62
|
+
if (filenameLower === qLower) return { tier: 0, offset: 0, nameLen: labelLen, depth };
|
|
59
63
|
|
|
60
64
|
// Tier 1: filename starts with query
|
|
61
|
-
if (
|
|
65
|
+
if (filenameLower.startsWith(qLower)) return { tier: 1, offset: 0, nameLen: labelLen, depth };
|
|
62
66
|
|
|
63
67
|
// Tier 2: filename contains query as substring
|
|
64
|
-
const fnIdx =
|
|
65
|
-
if (fnIdx >= 0) return { tier: 2, offset: fnIdx, nameLen:
|
|
68
|
+
const fnIdx = filenameLower.indexOf(qLower);
|
|
69
|
+
if (fnIdx >= 0) return { tier: 2, offset: fnIdx, nameLen: labelLen, depth };
|
|
66
70
|
|
|
67
71
|
// Tier 3: full path contains query as substring
|
|
68
|
-
const pathIdx = pathLower.indexOf(
|
|
69
|
-
if (pathIdx >= 0) return { tier: 3, offset: pathIdx, nameLen:
|
|
72
|
+
const pathIdx = pathLower.indexOf(qLower);
|
|
73
|
+
if (pathIdx >= 0) return { tier: 3, offset: pathIdx, nameLen: labelLen, depth };
|
|
70
74
|
|
|
71
75
|
// Tier 4: fuzzy match on filename
|
|
72
|
-
const fnGap = fuzzyGap(
|
|
73
|
-
if (fnGap >= 0) return { tier: 4, offset: fnGap, nameLen:
|
|
76
|
+
const fnGap = fuzzyGap(qLower, filenameLower);
|
|
77
|
+
if (fnGap >= 0) return { tier: 4, offset: fnGap, nameLen: labelLen, depth };
|
|
74
78
|
|
|
75
79
|
// Tier 5: fuzzy match on full path
|
|
76
|
-
const pathGap = fuzzyGap(
|
|
77
|
-
if (pathGap >= 0) return { tier: 5, offset: pathGap, nameLen:
|
|
80
|
+
const pathGap = fuzzyGap(qLower, pathLower);
|
|
81
|
+
if (pathGap >= 0) return { tier: 5, offset: pathGap, nameLen: labelLen, depth };
|
|
78
82
|
|
|
79
83
|
return null;
|
|
80
84
|
}
|
|
81
85
|
|
|
86
|
+
/** Convenience wrapper — lowers inputs on the fly. Use for ad-hoc calls. */
|
|
87
|
+
export function scoreFileSearch(
|
|
88
|
+
query: string,
|
|
89
|
+
label: string,
|
|
90
|
+
path: string,
|
|
91
|
+
): FileSearchScore | null {
|
|
92
|
+
const pathLower = path.toLowerCase();
|
|
93
|
+
return scoreFileSearchFast(
|
|
94
|
+
query.toLowerCase(),
|
|
95
|
+
getFilename(pathLower),
|
|
96
|
+
pathLower,
|
|
97
|
+
label.length,
|
|
98
|
+
path.split("/").length,
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
|
|
82
102
|
/** Compare two scores — for Array.sort (ascending = best first) */
|
|
83
103
|
export function compareScores(a: FileSearchScore, b: FileSearchScore): number {
|
|
84
104
|
return (
|
|
@@ -294,3 +294,15 @@ html, body {
|
|
|
294
294
|
@media (prefers-reduced-motion: reduce) {
|
|
295
295
|
.markdown-content.is-streaming > *:last-child { animation: none; }
|
|
296
296
|
}
|
|
297
|
+
|
|
298
|
+
/* Tab streaming indicator — 3 dots bouncing inside chat bubble icon (Messenger typing style) */
|
|
299
|
+
@keyframes tabTypingBounce {
|
|
300
|
+
0%, 60%, 100% { transform: translateY(0); }
|
|
301
|
+
30% { transform: translateY(-1.5px); }
|
|
302
|
+
}
|
|
303
|
+
.tab-typing-dot {
|
|
304
|
+
animation: tabTypingBounce 1s ease-in-out infinite;
|
|
305
|
+
}
|
|
306
|
+
@media (prefers-reduced-motion: reduce) {
|
|
307
|
+
.tab-typing-dot { animation: none; }
|
|
308
|
+
}
|