@ai-studio-3d/vyasa 0.1.0

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 (237) hide show
  1. package/README.md +69 -0
  2. package/data/common-kit.json +34 -0
  3. package/data/pricing.json +119 -0
  4. package/data/schema/AnalyticsData.json +214 -0
  5. package/data/schema/FoundationData.json +42 -0
  6. package/data/schema/KitData.json +321 -0
  7. package/data/schema/SearchData.json +173 -0
  8. package/data/schema/SessionDetailData.json +231 -0
  9. package/data/schema/SessionsListData.json +115 -0
  10. package/data/schema/WasteData.json +95 -0
  11. package/dist/cli.d.ts +3 -0
  12. package/dist/cli.d.ts.map +1 -0
  13. package/dist/cli.js +343 -0
  14. package/dist/cli.js.map +1 -0
  15. package/dist/core/billing/index.d.ts +4 -0
  16. package/dist/core/billing/index.d.ts.map +1 -0
  17. package/dist/core/billing/index.js +43 -0
  18. package/dist/core/billing/index.js.map +1 -0
  19. package/dist/core/budget/index.d.ts +30 -0
  20. package/dist/core/budget/index.d.ts.map +1 -0
  21. package/dist/core/budget/index.js +61 -0
  22. package/dist/core/budget/index.js.map +1 -0
  23. package/dist/core/codex/index.d.ts +3 -0
  24. package/dist/core/codex/index.d.ts.map +1 -0
  25. package/dist/core/codex/index.js +212 -0
  26. package/dist/core/codex/index.js.map +1 -0
  27. package/dist/core/cursor/index.d.ts +3 -0
  28. package/dist/core/cursor/index.d.ts.map +1 -0
  29. package/dist/core/cursor/index.js +304 -0
  30. package/dist/core/cursor/index.js.map +1 -0
  31. package/dist/core/cursor/scan.d.ts +28 -0
  32. package/dist/core/cursor/scan.d.ts.map +1 -0
  33. package/dist/core/cursor/scan.js +79 -0
  34. package/dist/core/cursor/scan.js.map +1 -0
  35. package/dist/core/decisions/index.d.ts +21 -0
  36. package/dist/core/decisions/index.d.ts.map +1 -0
  37. package/dist/core/decisions/index.js +133 -0
  38. package/dist/core/decisions/index.js.map +1 -0
  39. package/dist/core/dlp/index.d.ts +7 -0
  40. package/dist/core/dlp/index.d.ts.map +1 -0
  41. package/dist/core/dlp/index.js +115 -0
  42. package/dist/core/dlp/index.js.map +1 -0
  43. package/dist/core/health/index.d.ts +10 -0
  44. package/dist/core/health/index.d.ts.map +1 -0
  45. package/dist/core/health/index.js +21 -0
  46. package/dist/core/health/index.js.map +1 -0
  47. package/dist/core/index/index.d.ts +9 -0
  48. package/dist/core/index/index.d.ts.map +1 -0
  49. package/dist/core/index/index.js +103 -0
  50. package/dist/core/index/index.js.map +1 -0
  51. package/dist/core/index/ingest.d.ts +16 -0
  52. package/dist/core/index/ingest.d.ts.map +1 -0
  53. package/dist/core/index/ingest.js +184 -0
  54. package/dist/core/index/ingest.js.map +1 -0
  55. package/dist/core/index/platforms.d.ts +21 -0
  56. package/dist/core/index/platforms.d.ts.map +1 -0
  57. package/dist/core/index/platforms.js +44 -0
  58. package/dist/core/index/platforms.js.map +1 -0
  59. package/dist/core/index/pricing-map.d.ts +10 -0
  60. package/dist/core/index/pricing-map.d.ts.map +1 -0
  61. package/dist/core/index/pricing-map.js +16 -0
  62. package/dist/core/index/pricing-map.js.map +1 -0
  63. package/dist/core/index/progress.d.ts +26 -0
  64. package/dist/core/index/progress.d.ts.map +1 -0
  65. package/dist/core/index/progress.js +59 -0
  66. package/dist/core/index/progress.js.map +1 -0
  67. package/dist/core/index/scan.d.ts +9 -0
  68. package/dist/core/index/scan.d.ts.map +1 -0
  69. package/dist/core/index/scan.js +42 -0
  70. package/dist/core/index/scan.js.map +1 -0
  71. package/dist/core/index/statements.d.ts +18 -0
  72. package/dist/core/index/statements.d.ts.map +1 -0
  73. package/dist/core/index/statements.js +82 -0
  74. package/dist/core/index/statements.js.map +1 -0
  75. package/dist/core/index/tail.d.ts +42 -0
  76. package/dist/core/index/tail.d.ts.map +1 -0
  77. package/dist/core/index/tail.js +123 -0
  78. package/dist/core/index/tail.js.map +1 -0
  79. package/dist/core/jsonl/index.d.ts +3 -0
  80. package/dist/core/jsonl/index.d.ts.map +1 -0
  81. package/dist/core/jsonl/index.js +106 -0
  82. package/dist/core/jsonl/index.js.map +1 -0
  83. package/dist/core/jsonl-validate/index.d.ts +10 -0
  84. package/dist/core/jsonl-validate/index.d.ts.map +1 -0
  85. package/dist/core/jsonl-validate/index.js +40 -0
  86. package/dist/core/jsonl-validate/index.js.map +1 -0
  87. package/dist/core/kit/detection.d.ts +94 -0
  88. package/dist/core/kit/detection.d.ts.map +1 -0
  89. package/dist/core/kit/detection.js +312 -0
  90. package/dist/core/kit/detection.js.map +1 -0
  91. package/dist/core/kit/index.d.ts +12 -0
  92. package/dist/core/kit/index.d.ts.map +1 -0
  93. package/dist/core/kit/index.js +131 -0
  94. package/dist/core/kit/index.js.map +1 -0
  95. package/dist/core/kit/scan.d.ts +28 -0
  96. package/dist/core/kit/scan.d.ts.map +1 -0
  97. package/dist/core/kit/scan.js +432 -0
  98. package/dist/core/kit/scan.js.map +1 -0
  99. package/dist/core/recap/index.d.ts +18 -0
  100. package/dist/core/recap/index.d.ts.map +1 -0
  101. package/dist/core/recap/index.js +88 -0
  102. package/dist/core/recap/index.js.map +1 -0
  103. package/dist/core/repetition/index.d.ts +5 -0
  104. package/dist/core/repetition/index.d.ts.map +1 -0
  105. package/dist/core/repetition/index.js +0 -0
  106. package/dist/core/repetition/index.js.map +1 -0
  107. package/dist/core/schema/index.d.ts +514 -0
  108. package/dist/core/schema/index.d.ts.map +1 -0
  109. package/dist/core/schema/index.js +2 -0
  110. package/dist/core/schema/index.js.map +1 -0
  111. package/dist/core/schema-watch/index.d.ts +34 -0
  112. package/dist/core/schema-watch/index.d.ts.map +1 -0
  113. package/dist/core/schema-watch/index.js +87 -0
  114. package/dist/core/schema-watch/index.js.map +1 -0
  115. package/dist/core/search/index.d.ts +44 -0
  116. package/dist/core/search/index.d.ts.map +1 -0
  117. package/dist/core/search/index.js +641 -0
  118. package/dist/core/search/index.js.map +1 -0
  119. package/dist/core/settings/index.d.ts +24 -0
  120. package/dist/core/settings/index.d.ts.map +1 -0
  121. package/dist/core/settings/index.js +76 -0
  122. package/dist/core/settings/index.js.map +1 -0
  123. package/dist/core/share/bundle.d.ts +40 -0
  124. package/dist/core/share/bundle.d.ts.map +1 -0
  125. package/dist/core/share/bundle.js +158 -0
  126. package/dist/core/share/bundle.js.map +1 -0
  127. package/dist/core/share/canonical/from-claude.d.ts +13 -0
  128. package/dist/core/share/canonical/from-claude.d.ts.map +1 -0
  129. package/dist/core/share/canonical/from-claude.js +129 -0
  130. package/dist/core/share/canonical/from-claude.js.map +1 -0
  131. package/dist/core/share/canonical/from-codex.d.ts +18 -0
  132. package/dist/core/share/canonical/from-codex.d.ts.map +1 -0
  133. package/dist/core/share/canonical/from-codex.js +183 -0
  134. package/dist/core/share/canonical/from-codex.js.map +1 -0
  135. package/dist/core/share/canonical/to-claude.d.ts +15 -0
  136. package/dist/core/share/canonical/to-claude.d.ts.map +1 -0
  137. package/dist/core/share/canonical/to-claude.js +146 -0
  138. package/dist/core/share/canonical/to-claude.js.map +1 -0
  139. package/dist/core/share/canonical/to-codex.d.ts +21 -0
  140. package/dist/core/share/canonical/to-codex.d.ts.map +1 -0
  141. package/dist/core/share/canonical/to-codex.js +124 -0
  142. package/dist/core/share/canonical/to-codex.js.map +1 -0
  143. package/dist/core/share/canonical/tool-map.d.ts +61 -0
  144. package/dist/core/share/canonical/tool-map.d.ts.map +1 -0
  145. package/dist/core/share/canonical/tool-map.js +299 -0
  146. package/dist/core/share/canonical/tool-map.js.map +1 -0
  147. package/dist/core/share/canonical/types.d.ts +57 -0
  148. package/dist/core/share/canonical/types.d.ts.map +1 -0
  149. package/dist/core/share/canonical/types.js +9 -0
  150. package/dist/core/share/canonical/types.js.map +1 -0
  151. package/dist/core/share/import.d.ts +28 -0
  152. package/dist/core/share/import.d.ts.map +1 -0
  153. package/dist/core/share/import.js +174 -0
  154. package/dist/core/share/import.js.map +1 -0
  155. package/dist/core/share/manifest.d.ts +37 -0
  156. package/dist/core/share/manifest.d.ts.map +1 -0
  157. package/dist/core/share/manifest.js +31 -0
  158. package/dist/core/share/manifest.js.map +1 -0
  159. package/dist/core/share/preview.d.ts +4 -0
  160. package/dist/core/share/preview.d.ts.map +1 -0
  161. package/dist/core/share/preview.js +153 -0
  162. package/dist/core/share/preview.js.map +1 -0
  163. package/dist/core/share/primer.d.ts +19 -0
  164. package/dist/core/share/primer.d.ts.map +1 -0
  165. package/dist/core/share/primer.js +196 -0
  166. package/dist/core/share/primer.js.map +1 -0
  167. package/dist/core/share/resume.d.ts +10 -0
  168. package/dist/core/share/resume.d.ts.map +1 -0
  169. package/dist/core/share/resume.js +58 -0
  170. package/dist/core/share/resume.js.map +1 -0
  171. package/dist/core/share/scrub.d.ts +10 -0
  172. package/dist/core/share/scrub.d.ts.map +1 -0
  173. package/dist/core/share/scrub.js +198 -0
  174. package/dist/core/share/scrub.js.map +1 -0
  175. package/dist/core/share/tar.d.ts +12 -0
  176. package/dist/core/share/tar.d.ts.map +1 -0
  177. package/dist/core/share/tar.js +78 -0
  178. package/dist/core/share/tar.js.map +1 -0
  179. package/dist/core/tags/index.d.ts +48 -0
  180. package/dist/core/tags/index.d.ts.map +1 -0
  181. package/dist/core/tags/index.js +113 -0
  182. package/dist/core/tags/index.js.map +1 -0
  183. package/dist/core/today/index.d.ts +25 -0
  184. package/dist/core/today/index.d.ts.map +1 -0
  185. package/dist/core/today/index.js +42 -0
  186. package/dist/core/today/index.js.map +1 -0
  187. package/dist/core/waste/abandoned.d.ts +12 -0
  188. package/dist/core/waste/abandoned.d.ts.map +1 -0
  189. package/dist/core/waste/abandoned.js +127 -0
  190. package/dist/core/waste/abandoned.js.map +1 -0
  191. package/dist/core/waste/cache-miss.d.ts +9 -0
  192. package/dist/core/waste/cache-miss.d.ts.map +1 -0
  193. package/dist/core/waste/cache-miss.js +84 -0
  194. package/dist/core/waste/cache-miss.js.map +1 -0
  195. package/dist/core/waste/index.d.ts +12 -0
  196. package/dist/core/waste/index.d.ts.map +1 -0
  197. package/dist/core/waste/index.js +45 -0
  198. package/dist/core/waste/index.js.map +1 -0
  199. package/dist/core/waste/wrong-model.d.ts +11 -0
  200. package/dist/core/waste/wrong-model.d.ts.map +1 -0
  201. package/dist/core/waste/wrong-model.js +104 -0
  202. package/dist/core/waste/wrong-model.js.map +1 -0
  203. package/dist/db/index.d.ts +10 -0
  204. package/dist/db/index.d.ts.map +1 -0
  205. package/dist/db/index.js +29 -0
  206. package/dist/db/index.js.map +1 -0
  207. package/dist/db/migrate.d.ts +8 -0
  208. package/dist/db/migrate.d.ts.map +1 -0
  209. package/dist/db/migrate.js +282 -0
  210. package/dist/db/migrate.js.map +1 -0
  211. package/dist/server/events.d.ts +4 -0
  212. package/dist/server/events.d.ts.map +1 -0
  213. package/dist/server/events.js +54 -0
  214. package/dist/server/events.js.map +1 -0
  215. package/dist/server/index.d.ts +7 -0
  216. package/dist/server/index.d.ts.map +1 -0
  217. package/dist/server/index.js +238 -0
  218. package/dist/server/index.js.map +1 -0
  219. package/dist/server/routes/foundation.d.ts +2 -0
  220. package/dist/server/routes/foundation.d.ts.map +1 -0
  221. package/dist/server/routes/foundation.js +2 -0
  222. package/dist/server/routes/foundation.js.map +1 -0
  223. package/dist/server/routes/search.d.ts +2 -0
  224. package/dist/server/routes/search.d.ts.map +1 -0
  225. package/dist/server/routes/search.js +2 -0
  226. package/dist/server/routes/search.js.map +1 -0
  227. package/dist/server/routes/sessions.d.ts +2 -0
  228. package/dist/server/routes/sessions.d.ts.map +1 -0
  229. package/dist/server/routes/sessions.js +2 -0
  230. package/dist/server/routes/sessions.js.map +1 -0
  231. package/dist/server/routes/waste.d.ts +2 -0
  232. package/dist/server/routes/waste.d.ts.map +1 -0
  233. package/dist/server/routes/waste.js +2 -0
  234. package/dist/server/routes/waste.js.map +1 -0
  235. package/dist/web/assets/index-Ba1VvTj0.js +37 -0
  236. package/dist/web/index.html +12 -0
  237. package/package.json +76 -0
@@ -0,0 +1,312 @@
1
+ /**
2
+ * Returns per-skill usage statistics over the lookback window.
3
+ * Skill firings are tool_calls with tool='Skill' and input_json containing
4
+ * {"skill": "<plugin>:<name>"} (plugin-installed)
5
+ * {"skill": "<name>"} (loose)
6
+ * The canonical id from the call is the join key.
7
+ */
8
+ export function loadSkillUsage(db, lookbackDays) {
9
+ const sinceMs = Date.now() - lookbackDays * 24 * 60 * 60 * 1000;
10
+ const sinceIso = new Date(sinceMs).toISOString();
11
+ // JSON parsing in SQL would require json_extract on a million-row scan; pulling
12
+ // candidate rows to JS is faster for the row counts we care about (typically
13
+ // single-digit thousands of Skill calls).
14
+ const rows = db
15
+ .prepare(`
16
+ SELECT tc.input_json, m.ts
17
+ FROM tool_calls tc
18
+ JOIN messages m ON m.id = tc.message_id
19
+ WHERE tc.tool = 'Skill'
20
+ AND m.ts >= ?
21
+ `)
22
+ .all(sinceIso);
23
+ const out = new Map();
24
+ for (const r of rows) {
25
+ if (!r.input_json)
26
+ continue;
27
+ let id;
28
+ try {
29
+ const obj = JSON.parse(r.input_json);
30
+ if (typeof obj.skill !== 'string')
31
+ continue;
32
+ id = obj.skill;
33
+ }
34
+ catch {
35
+ continue;
36
+ }
37
+ const tsMs = Date.parse(r.ts);
38
+ if (!Number.isFinite(tsMs))
39
+ continue;
40
+ const cur = out.get(id);
41
+ if (!cur) {
42
+ out.set(id, { count: 1, lastUsedMs: tsMs });
43
+ }
44
+ else {
45
+ cur.count++;
46
+ if (tsMs > cur.lastUsedMs)
47
+ cur.lastUsedMs = tsMs;
48
+ }
49
+ }
50
+ return out;
51
+ }
52
+ /**
53
+ * Returns per-MCP-server usage statistics over the lookback window. Server
54
+ * name is the token between the first two '__' in the tool name (e.g.
55
+ * `mcp__chrome-devtools__navigate_page` → 'chrome-devtools').
56
+ */
57
+ export function loadMcpUsage(db, lookbackDays) {
58
+ const sinceMs = Date.now() - lookbackDays * 24 * 60 * 60 * 1000;
59
+ const sinceIso = new Date(sinceMs).toISOString();
60
+ const rows = db
61
+ .prepare(`
62
+ SELECT tc.tool, m.ts
63
+ FROM tool_calls tc
64
+ JOIN messages m ON m.id = tc.message_id
65
+ WHERE tc.tool LIKE 'mcp__%'
66
+ AND m.ts >= ?
67
+ `)
68
+ .all(sinceIso);
69
+ const out = new Map();
70
+ for (const r of rows) {
71
+ // tool format: mcp__<server>__<method>. Server name may contain hyphens but
72
+ // not '__' — splitting on '__' and taking element [1] is safe.
73
+ const parts = r.tool.split('__');
74
+ if (parts.length < 3)
75
+ continue;
76
+ const server = parts[1];
77
+ if (!server)
78
+ continue;
79
+ const tsMs = Date.parse(r.ts);
80
+ if (!Number.isFinite(tsMs))
81
+ continue;
82
+ const cur = out.get(server);
83
+ if (!cur) {
84
+ out.set(server, { count: 1, lastUsedMs: tsMs });
85
+ }
86
+ else {
87
+ cur.count++;
88
+ if (tsMs > cur.lastUsedMs)
89
+ cur.lastUsedMs = tsMs;
90
+ }
91
+ }
92
+ return out;
93
+ }
94
+ /**
95
+ * Returns every non-Skill, non-MCP tool_call in the window paired with its
96
+ * input_json. Used by the gap detector to grep for "replaces" patterns.
97
+ * Limited to the tool names we currently emit patterns against, to avoid
98
+ * pulling 100K+ Read/Edit rows.
99
+ */
100
+ export function loadCandidateToolCalls(db, lookbackDays, toolFilter) {
101
+ if (toolFilter.length === 0)
102
+ return [];
103
+ const sinceMs = Date.now() - lookbackDays * 24 * 60 * 60 * 1000;
104
+ const sinceIso = new Date(sinceMs).toISOString();
105
+ const placeholders = toolFilter.map(() => '?').join(',');
106
+ return db
107
+ .prepare(`
108
+ SELECT tc.tool, tc.input_json, m.ts
109
+ FROM tool_calls tc
110
+ JOIN messages m ON m.id = tc.message_id
111
+ WHERE tc.tool IN (${placeholders})
112
+ AND m.ts >= ?
113
+ `)
114
+ .all(...toolFilter, sinceIso);
115
+ }
116
+ // ─── State hydration ──────────────────────────────────────────────────────────
117
+ /**
118
+ * Annotates each SkillState with its usage stats from the tool_calls table.
119
+ *
120
+ * Plugin skills can fire under EITHER '<plugin>:<name>' OR bare '<name>' depending
121
+ * on how the user invoked them — verified in real data (e.g. `update-config`
122
+ * appears as bare even though it's plugin-bundled). Merge both keys so we don't
123
+ * surface false-positive zombies for skills that are actually being used.
124
+ */
125
+ export function hydrateSkillUsage(skills, usage) {
126
+ return skills.map((s) => {
127
+ const primary = usage.get(s.id);
128
+ const bare = s.plugin ? usage.get(s.name) : undefined;
129
+ if (!primary && !bare)
130
+ return s;
131
+ const count = (primary?.count ?? 0) + (bare?.count ?? 0);
132
+ const lastMs = Math.max(primary?.lastUsedMs ?? 0, bare?.lastUsedMs ?? 0);
133
+ return { ...s, usageCount: count, lastUsedMs: lastMs || null };
134
+ });
135
+ }
136
+ export function hydrateMcpUsage(mcps, usage) {
137
+ return mcps.map((m) => {
138
+ const u = usage.get(m.id);
139
+ if (!u)
140
+ return m;
141
+ return { ...m, usageCount: u.count, lastUsedMs: u.lastUsedMs };
142
+ });
143
+ }
144
+ // ─── Gap detection ────────────────────────────────────────────────────────────
145
+ /**
146
+ * Parses a "replaces" pattern of the form "tool:substring". Returns null on
147
+ * malformed entries (logged at the call site).
148
+ */
149
+ function parseReplacePattern(pat) {
150
+ const idx = pat.indexOf(':');
151
+ if (idx < 0)
152
+ return null;
153
+ const tool = pat.slice(0, idx);
154
+ const needle = pat.slice(idx + 1);
155
+ if (!tool || !needle)
156
+ return null;
157
+ return { tool, needle };
158
+ }
159
+ /**
160
+ * For each common-kit item not already installed, build a GapItem. For MCP
161
+ * gaps, count tool_calls matching the `replaces` patterns over the lookback
162
+ * window — these are loosely the calls an MCP server would handle directly,
163
+ * eliminating the need for shelling out / fetching.
164
+ *
165
+ * Savings heuristic for MCP: we currently surface the match count as a
166
+ * "potential reduction" signal (rendered in the UI as "N calls would be
167
+ * replaced") but do NOT compute dollar savings — Bash/WebFetch cost lives in
168
+ * the assistant's output tokens around the call, which we don't attribute
169
+ * per-tool. So potentialSavingsCents stays 0 in V1 unless the kit grows entries
170
+ * with a model-aware estimate; matchingCallCount is the actionable number.
171
+ */
172
+ export function detectGaps(kit, installedSkillIds, installedMcpIds, candidateCalls) {
173
+ const gaps = [];
174
+ // Skills — flat membership check; no savings heuristic in V1.
175
+ for (const s of kit.skills) {
176
+ if (installedSkillIds.has(s.id))
177
+ continue;
178
+ gaps.push({
179
+ kind: 'skill',
180
+ id: s.id,
181
+ purpose: s.purpose,
182
+ installCommand: s.install,
183
+ potentialSavingsCents: 0,
184
+ matchingCallCount: 0,
185
+ });
186
+ }
187
+ // MCP — count `replaces` matches on candidate tool_calls.
188
+ for (const m of kit.mcpServers) {
189
+ if (installedMcpIds.has(m.id))
190
+ continue;
191
+ let matchCount = 0;
192
+ if (m.replaces && m.replaces.length > 0) {
193
+ const patterns = m.replaces
194
+ .map(parseReplacePattern)
195
+ .filter((p) => p !== null);
196
+ for (const call of candidateCalls) {
197
+ for (const p of patterns) {
198
+ if (call.tool !== p.tool)
199
+ continue;
200
+ const hay = call.input_json ?? '';
201
+ if (hay.includes(p.needle)) {
202
+ matchCount++;
203
+ break; // count each call at most once
204
+ }
205
+ }
206
+ }
207
+ }
208
+ gaps.push({
209
+ kind: 'mcp',
210
+ id: m.id,
211
+ purpose: m.purpose,
212
+ installCommand: m.install,
213
+ potentialSavingsCents: 0,
214
+ matchingCallCount: matchCount,
215
+ });
216
+ }
217
+ // Rank: MCP gaps with matches first (descending), then unmatched, then skills.
218
+ gaps.sort((a, b) => {
219
+ if (b.matchingCallCount !== a.matchingCallCount)
220
+ return b.matchingCallCount - a.matchingCallCount;
221
+ if (a.kind !== b.kind)
222
+ return a.kind === 'mcp' ? -1 : 1;
223
+ return a.id.localeCompare(b.id);
224
+ });
225
+ return gaps;
226
+ }
227
+ /** Returns the union of tool names referenced by the kit's `replaces` patterns. */
228
+ export function collectReplacedTools(kit) {
229
+ const set = new Set();
230
+ for (const m of kit.mcpServers) {
231
+ for (const p of m.replaces ?? []) {
232
+ const parsed = parseReplacePattern(p);
233
+ if (parsed)
234
+ set.add(parsed.tool);
235
+ }
236
+ }
237
+ return Array.from(set);
238
+ }
239
+ // ─── Zombie detection ─────────────────────────────────────────────────────────
240
+ /**
241
+ * A skill or MCP server is a "zombie" when it's installed on the filesystem
242
+ * but has not been invoked in the lookback window. We treat usageCount=0 as
243
+ * the threshold (the spec mentions "below threshold like 2 over 30d for skills"
244
+ * — but for V1 we use the strict zero gate since the user has few-to-no skills
245
+ * installed, and a single intentional use is enough to "save" a skill from the
246
+ * list).
247
+ */
248
+ export function detectZombies(skills, mcp) {
249
+ const out = [];
250
+ for (const s of skills) {
251
+ if (s.usageCount > 0)
252
+ continue;
253
+ out.push({
254
+ kind: 'skill',
255
+ id: s.id,
256
+ displayName: s.name,
257
+ platform: s.platform,
258
+ scope: s.scope,
259
+ projectPath: s.projectPath,
260
+ installedAtMs: s.installedAtMs,
261
+ lastUsedMs: s.lastUsedMs,
262
+ usageCount: s.usageCount,
263
+ removeCommand: removeCommandForSkill(s),
264
+ });
265
+ }
266
+ for (const m of mcp) {
267
+ if (m.usageCount > 0)
268
+ continue;
269
+ out.push({
270
+ kind: 'mcp',
271
+ id: m.id,
272
+ displayName: m.id,
273
+ platform: m.platform,
274
+ scope: m.scope,
275
+ projectPath: m.projectPath,
276
+ installedAtMs: m.installedAtMs,
277
+ lastUsedMs: m.lastUsedMs,
278
+ usageCount: m.usageCount,
279
+ removeCommand: removeCommandForMcp(m),
280
+ });
281
+ }
282
+ // Oldest installs first — those are the most clearly forgotten.
283
+ out.sort((a, b) => a.installedAtMs - b.installedAtMs);
284
+ return out;
285
+ }
286
+ function removeCommandForSkill(s) {
287
+ if (s.plugin) {
288
+ // Plugin-installed skills can't be removed in isolation — uninstalling the
289
+ // plugin removes them all. Surface that affordance instead.
290
+ if (s.platform === 'claude-code')
291
+ return `claude plugin uninstall ${s.plugin}`;
292
+ if (s.platform === 'codex')
293
+ return `codex plugin uninstall ${s.plugin}`;
294
+ }
295
+ // Loose skills: just nuke the directory
296
+ // `dirname` gives us the skill folder above SKILL.md
297
+ const skillDir = s.sourcePath.replace(/\/SKILL\.md$/, '');
298
+ return `rm -rf "${skillDir}"`;
299
+ }
300
+ function removeCommandForMcp(m) {
301
+ if (m.platform === 'claude-code') {
302
+ return m.scope === 'project'
303
+ ? `claude mcp remove ${m.id} --scope project`
304
+ : `claude mcp remove ${m.id}`;
305
+ }
306
+ if (m.platform === 'cursor') {
307
+ // Cursor edits mcp.json by hand or via Settings UI — there's no CLI.
308
+ return `Edit ${m.sourcePath} and remove the "${m.id}" entry`;
309
+ }
310
+ return `Remove "${m.id}" from ${m.sourcePath}`;
311
+ }
312
+ //# sourceMappingURL=detection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detection.js","sourceRoot":"","sources":["../../../src/core/kit/detection.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import Database from 'better-sqlite3';
2
+ import type { KitData, KitPlatform } from '../schema/index.js';
3
+ export interface GetKitOptions {
4
+ lookbackDays?: number;
5
+ platform?: KitPlatform;
6
+ /** Override the common-kit.json path (tests). */
7
+ commonKitPath?: string;
8
+ /** Override project roots (tests). When omitted, derived from sessions table. */
9
+ projectRoots?: string[];
10
+ }
11
+ export declare function getKit(db: Database.Database, opts?: GetKitOptions): Promise<KitData>;
12
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/kit/index.ts"],"names":[],"mappings":"AAIA,OAAO,QAAQ,MAAM,gBAAgB,CAAA;AACrC,OAAO,KAAK,EACV,OAAO,EAIP,WAAW,EACZ,MAAM,oBAAoB,CAAA;AAuB3B,MAAM,WAAW,aAAa;IAC5B,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,EAAE,WAAW,CAAA;IACtB,iDAAiD;IACjD,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,iFAAiF;IACjF,YAAY,CAAC,EAAE,MAAM,EAAE,CAAA;CACxB;AAwED,wBAAsB,MAAM,CAC1B,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,IAAI,GAAE,aAAkB,GACvB,OAAO,CAAC,OAAO,CAAC,CA2DlB"}
@@ -0,0 +1,131 @@
1
+ import { readFile } from 'node:fs/promises';
2
+ import { existsSync } from 'node:fs';
3
+ import { dirname, join } from 'node:path';
4
+ import { fileURLToPath } from 'node:url';
5
+ import { scanGlobalSkills, scanProjectSkills, scanGlobalMcp, scanProjectMcp, decodeClaudeProjectSlug, } from './scan.js';
6
+ import { detectGaps, detectZombies, hydrateMcpUsage, hydrateSkillUsage, loadCandidateToolCalls, loadMcpUsage, loadSkillUsage, collectReplacedTools, } from './detection.js';
7
+ const __filename = fileURLToPath(import.meta.url);
8
+ const __dirname = dirname(__filename);
9
+ const DEFAULT_LOOKBACK_DAYS = 30;
10
+ /** Loads data/common-kit.json. Searches up from this file because the runtime
11
+ * layout is dist/core/kit/index.js with data/ at the package root.
12
+ * Falls back to a minimal empty kit if the file is missing/malformed. */
13
+ async function loadCommonKit(overridePath) {
14
+ const empty = { version: 1, skills: [], mcpServers: [] };
15
+ const candidates = [];
16
+ if (overridePath)
17
+ candidates.push(overridePath);
18
+ candidates.push(join(__dirname, '../../../data/common-kit.json'), join(__dirname, '../../../../data/common-kit.json'));
19
+ for (const p of candidates) {
20
+ if (!existsSync(p))
21
+ continue;
22
+ try {
23
+ const text = await readFile(p, 'utf8');
24
+ return JSON.parse(text);
25
+ }
26
+ catch (err) {
27
+ console.error(`[vyasa] kit: failed to load common-kit.json at ${p}:`, err);
28
+ return empty;
29
+ }
30
+ }
31
+ return empty;
32
+ }
33
+ /** Distinct project paths derived from sessions. Claude rows store a slug
34
+ * (`-Users-abhinav-foo`); Codex/Cursor store absolute paths. Decode the
35
+ * Claude slug back to a path and dedupe. */
36
+ function deriveProjectRoots(db) {
37
+ const rows = db
38
+ .prepare('SELECT DISTINCT project, platform FROM sessions WHERE project IS NOT NULL')
39
+ .all();
40
+ const set = new Set();
41
+ for (const r of rows) {
42
+ if (!r.project)
43
+ continue;
44
+ if (r.platform === 'claude-code') {
45
+ // Claude slugs start with '-' for absolute paths; if it doesn't, treat
46
+ // as-is (project might be a literal name from a non-absolute cwd).
47
+ const decoded = decodeClaudeProjectSlug(r.project);
48
+ if (decoded.startsWith('/'))
49
+ set.add(decoded);
50
+ }
51
+ else {
52
+ // Codex + Cursor store absolute paths already
53
+ if (r.project.startsWith('/'))
54
+ set.add(r.project);
55
+ }
56
+ }
57
+ return Array.from(set);
58
+ }
59
+ /** Build a per-project inventory by grouping skills + MCP by their projectPath.
60
+ * Projects with no installs are omitted. */
61
+ function groupByProject(skills, mcp) {
62
+ const map = new Map();
63
+ for (const s of skills) {
64
+ if (s.scope !== 'project' || !s.projectPath)
65
+ continue;
66
+ const entry = map.get(s.projectPath) ?? { project: s.projectPath, skills: [], mcp: [] };
67
+ entry.skills.push(s);
68
+ map.set(s.projectPath, entry);
69
+ }
70
+ for (const m of mcp) {
71
+ if (m.scope !== 'project' || !m.projectPath)
72
+ continue;
73
+ const entry = map.get(m.projectPath) ?? { project: m.projectPath, skills: [], mcp: [] };
74
+ entry.mcp.push(m);
75
+ map.set(m.projectPath, entry);
76
+ }
77
+ return Array.from(map.values()).sort((a, b) => a.project.localeCompare(b.project));
78
+ }
79
+ export async function getKit(db, opts = {}) {
80
+ const lookbackDays = opts.lookbackDays ?? DEFAULT_LOOKBACK_DAYS;
81
+ const projectRoots = opts.projectRoots ?? deriveProjectRoots(db);
82
+ // Filesystem scan (parallel)
83
+ const [globalSkillsRaw, globalMcpRaw, projectSkillsRaw, projectMcpRaw] = await Promise.all([
84
+ scanGlobalSkills(),
85
+ scanGlobalMcp(),
86
+ scanProjectSkills(projectRoots),
87
+ scanProjectMcp(projectRoots),
88
+ ]);
89
+ // Usage hydration
90
+ const skillUsage = loadSkillUsage(db, lookbackDays);
91
+ const mcpUsage = loadMcpUsage(db, lookbackDays);
92
+ let globalSkills = hydrateSkillUsage(globalSkillsRaw, skillUsage);
93
+ let globalMcp = hydrateMcpUsage(globalMcpRaw, mcpUsage);
94
+ let projectSkills = hydrateSkillUsage(projectSkillsRaw, skillUsage);
95
+ let projectMcp = hydrateMcpUsage(projectMcpRaw, mcpUsage);
96
+ // Platform filter (post-hydration so usage data is still complete for tests)
97
+ if (opts.platform) {
98
+ const p = opts.platform;
99
+ globalSkills = globalSkills.filter((s) => s.platform === p);
100
+ globalMcp = globalMcp.filter((m) => m.platform === p);
101
+ projectSkills = projectSkills.filter((s) => s.platform === p);
102
+ projectMcp = projectMcp.filter((m) => m.platform === p);
103
+ }
104
+ // Detection
105
+ const kit = await loadCommonKit(opts.commonKitPath);
106
+ const installedSkillIds = new Set();
107
+ for (const s of [...globalSkills, ...projectSkills])
108
+ installedSkillIds.add(s.id);
109
+ // Also accept bare-name match: a plugin-installed skill like 'superpowers:brainstorming'
110
+ // satisfies a common-kit entry whose id is 'brainstorming' (the user installed it
111
+ // via a plugin instead of as a loose ~/.claude/skills/<id>/ skill).
112
+ for (const s of [...globalSkills, ...projectSkills]) {
113
+ if (s.plugin)
114
+ installedSkillIds.add(s.name);
115
+ }
116
+ const installedMcpIds = new Set();
117
+ for (const m of [...globalMcp, ...projectMcp])
118
+ installedMcpIds.add(m.id);
119
+ const candidateTools = collectReplacedTools(kit);
120
+ const candidateCalls = loadCandidateToolCalls(db, lookbackDays, candidateTools);
121
+ const gaps = detectGaps(kit, installedSkillIds, installedMcpIds, candidateCalls);
122
+ const zombies = detectZombies([...globalSkills, ...projectSkills], [...globalMcp, ...projectMcp]);
123
+ return {
124
+ lookbackDays,
125
+ gaps,
126
+ zombies,
127
+ globalInstalled: { skills: globalSkills, mcp: globalMcp },
128
+ projectInstalled: groupByProject(projectSkills, projectMcp),
129
+ };
130
+ }
131
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/core/kit/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ import { platform } from 'node:os';
2
+ import type { SkillState, McpState } from '../schema/index.js';
3
+ export declare function scanGlobalSkills(): Promise<SkillState[]>;
4
+ /**
5
+ * Scans likely project-scoped skill dirs under each given project root.
6
+ * `projectRoots` should be absolute paths that look like project working
7
+ * directories (decoded from session.project where possible).
8
+ */
9
+ export declare function scanProjectSkills(projectRoots: string[]): Promise<SkillState[]>;
10
+ export declare function scanGlobalMcp(): Promise<McpState[]>;
11
+ /**
12
+ * Returns MCP servers declared at project-scope for the given roots:
13
+ * • Claude: ~/.claude.json's projects[<root>].mcpServers
14
+ * • Cursor: <root>/.cursor/mcp.json
15
+ */
16
+ export declare function scanProjectMcp(projectRoots: string[]): Promise<McpState[]>;
17
+ /**
18
+ * Claude encodes the project working dir as a slug — `/Users/abhinav/foo` becomes
19
+ * `-Users-abhinav-foo`. The encoding is lossy: literal dashes inside path
20
+ * components (e.g. `claude-tool`) get merged with the separator dashes. We
21
+ * recover the true path by probing the filesystem — try the naive split first,
22
+ * then merge adjacent segments left-to-right until we find a directory that
23
+ * exists. Longest matching prefix wins. Falls back to the naive split (which
24
+ * won't `existsSync`, so callers harmlessly skip it) when no resolution is possible.
25
+ */
26
+ export declare function decodeClaudeProjectSlug(slug: string): string;
27
+ export { platform as osPlatform };
28
+ //# sourceMappingURL=scan.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scan.d.ts","sourceRoot":"","sources":["../../../src/core/kit/scan.ts"],"names":[],"mappings":"AAEA,OAAO,EAAW,QAAQ,EAAE,MAAM,SAAS,CAAA;AAE3C,OAAO,KAAK,EAAe,UAAU,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAA;AAkM3E,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC,CAkD9D;AAED;;;;GAIG;AACH,wBAAsB,iBAAiB,CAAC,YAAY,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAgDrF;AA2BD,wBAAsB,aAAa,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC,CAoDzD;AAED;;;;GAIG;AACH,wBAAsB,cAAc,CAAC,YAAY,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,CAmDhF;AASD;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAM5D;AAuCD,OAAO,EAAE,QAAQ,IAAI,UAAU,EAAE,CAAA"}