skilld 1.7.4 → 2.0.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 (156) hide show
  1. package/dist/_chunks/add.mjs +66 -0
  2. package/dist/_chunks/add.mjs.map +1 -0
  3. package/dist/_chunks/agent-prompt.mjs +88 -0
  4. package/dist/_chunks/agent-prompt.mjs.map +1 -0
  5. package/dist/_chunks/agent.mjs +81 -57
  6. package/dist/_chunks/agent.mjs.map +1 -1
  7. package/dist/_chunks/args.mjs +42 -0
  8. package/dist/_chunks/args.mjs.map +1 -0
  9. package/dist/_chunks/assemble.mjs +10 -7
  10. package/dist/_chunks/assemble.mjs.map +1 -1
  11. package/dist/_chunks/author.mjs +33 -17
  12. package/dist/_chunks/author.mjs.map +1 -1
  13. package/dist/_chunks/cache.mjs +143 -183
  14. package/dist/_chunks/cache.mjs.map +1 -1
  15. package/dist/_chunks/cache2.mjs +7 -6
  16. package/dist/_chunks/cache2.mjs.map +1 -1
  17. package/dist/_chunks/client.mjs +117 -0
  18. package/dist/_chunks/client.mjs.map +1 -0
  19. package/dist/_chunks/core.mjs +5 -5
  20. package/dist/_chunks/detect.mjs +53 -43
  21. package/dist/_chunks/detect.mjs.map +1 -1
  22. package/dist/_chunks/eject.mjs +69 -0
  23. package/dist/_chunks/eject.mjs.map +1 -0
  24. package/dist/_chunks/embedding-cache2.mjs +1 -1
  25. package/dist/_chunks/env.mjs +19 -0
  26. package/dist/_chunks/env.mjs.map +1 -0
  27. package/dist/_chunks/install-many.mjs +376 -0
  28. package/dist/_chunks/install-many.mjs.map +1 -0
  29. package/dist/_chunks/install.mjs +81 -326
  30. package/dist/_chunks/install.mjs.map +1 -1
  31. package/dist/_chunks/intro.mjs +63 -0
  32. package/dist/_chunks/intro.mjs.map +1 -0
  33. package/dist/_chunks/list.mjs +2 -2
  34. package/dist/_chunks/list.mjs.map +1 -1
  35. package/dist/_chunks/lockfile.mjs +3 -2
  36. package/dist/_chunks/lockfile.mjs.map +1 -1
  37. package/dist/_chunks/login.mjs +233 -0
  38. package/dist/_chunks/login.mjs.map +1 -0
  39. package/dist/_chunks/logout.mjs +27 -0
  40. package/dist/_chunks/logout.mjs.map +1 -0
  41. package/dist/_chunks/map.mjs +11 -0
  42. package/dist/_chunks/map.mjs.map +1 -0
  43. package/dist/_chunks/markdown.mjs +79 -54
  44. package/dist/_chunks/markdown.mjs.map +1 -1
  45. package/dist/_chunks/menu.mjs +33 -0
  46. package/dist/_chunks/menu.mjs.map +1 -0
  47. package/dist/_chunks/model-picker.mjs +61 -0
  48. package/dist/_chunks/model-picker.mjs.map +1 -0
  49. package/dist/_chunks/monorepo.mjs +4 -2
  50. package/dist/_chunks/monorepo.mjs.map +1 -1
  51. package/dist/_chunks/package-json.mjs.map +1 -1
  52. package/dist/_chunks/paths.mjs +3 -5
  53. package/dist/_chunks/paths.mjs.map +1 -1
  54. package/dist/_chunks/{sync-pipeline.mjs → pipeline.mjs} +346 -313
  55. package/dist/_chunks/pipeline.mjs.map +1 -0
  56. package/dist/_chunks/pool2.mjs +1 -1
  57. package/dist/_chunks/portable.mjs +151 -0
  58. package/dist/_chunks/portable.mjs.map +1 -0
  59. package/dist/_chunks/prepare-hook.mjs +2 -0
  60. package/dist/_chunks/prepare-hook2.mjs +61 -0
  61. package/dist/_chunks/prepare-hook2.mjs.map +1 -0
  62. package/dist/_chunks/prepare.mjs +47 -3
  63. package/dist/_chunks/prepare.mjs.map +1 -1
  64. package/dist/_chunks/prepare2.mjs +7 -6
  65. package/dist/_chunks/prepare2.mjs.map +1 -1
  66. package/dist/_chunks/prompts.mjs +484 -74
  67. package/dist/_chunks/prompts.mjs.map +1 -1
  68. package/dist/_chunks/pull.mjs +219 -0
  69. package/dist/_chunks/pull.mjs.map +1 -0
  70. package/dist/_chunks/regex.mjs +19 -0
  71. package/dist/_chunks/regex.mjs.map +1 -0
  72. package/dist/_chunks/retriv.mjs +2 -171
  73. package/dist/_chunks/retriv2.mjs +159 -0
  74. package/dist/_chunks/retriv2.mjs.map +1 -0
  75. package/dist/_chunks/sanitize.mjs +12 -9
  76. package/dist/_chunks/sanitize.mjs.map +1 -1
  77. package/dist/_chunks/search-helpers.mjs +8 -6
  78. package/dist/_chunks/search-helpers.mjs.map +1 -1
  79. package/dist/_chunks/search-interactive.mjs +23 -20
  80. package/dist/_chunks/search-interactive.mjs.map +1 -1
  81. package/dist/_chunks/search.mjs +3 -3
  82. package/dist/_chunks/search.mjs.map +1 -1
  83. package/dist/_chunks/semver.mjs +2755 -1
  84. package/dist/_chunks/semver.mjs.map +1 -1
  85. package/dist/_chunks/skill-installer2.mjs +10 -11
  86. package/dist/_chunks/skill-installer2.mjs.map +1 -1
  87. package/dist/_chunks/skills.mjs +6 -7
  88. package/dist/_chunks/skills.mjs.map +1 -1
  89. package/dist/_chunks/store.mjs +107 -0
  90. package/dist/_chunks/store.mjs.map +1 -0
  91. package/dist/_chunks/sync.mjs +411 -910
  92. package/dist/_chunks/sync.mjs.map +1 -1
  93. package/dist/_chunks/sync2.mjs +2 -5
  94. package/dist/_chunks/telemetry.mjs +26 -0
  95. package/dist/_chunks/telemetry.mjs.map +1 -0
  96. package/dist/_chunks/uninstall.mjs +12 -9
  97. package/dist/_chunks/uninstall.mjs.map +1 -1
  98. package/dist/_chunks/update.mjs +171 -0
  99. package/dist/_chunks/update.mjs.map +1 -0
  100. package/dist/_chunks/upload.mjs +3 -3
  101. package/dist/_chunks/validate.mjs +1 -1
  102. package/dist/_chunks/version.mjs +16 -17
  103. package/dist/_chunks/version.mjs.map +1 -1
  104. package/dist/_chunks/whoami.mjs +21 -0
  105. package/dist/_chunks/whoami.mjs.map +1 -0
  106. package/dist/_chunks/wizard.mjs +2 -190
  107. package/dist/_chunks/wizard2.mjs +200 -0
  108. package/dist/_chunks/wizard2.mjs.map +1 -0
  109. package/dist/cli.mjs +72 -53
  110. package/dist/cli.mjs.map +1 -1
  111. package/dist/prepare.mjs +4 -3
  112. package/dist/prepare.mjs.map +1 -1
  113. package/dist/retriv/worker.d.mts +5 -1
  114. package/dist/retriv/worker.d.mts.map +1 -1
  115. package/dist/retriv/worker.mjs +1 -1
  116. package/package.json +19 -28
  117. package/dist/_chunks/author-group.mjs +0 -17
  118. package/dist/_chunks/author-group.mjs.map +0 -1
  119. package/dist/_chunks/cli-helpers.mjs +0 -335
  120. package/dist/_chunks/cli-helpers.mjs.map +0 -1
  121. package/dist/_chunks/cli-helpers2.mjs +0 -2
  122. package/dist/_chunks/index.d.mts +0 -344
  123. package/dist/_chunks/index.d.mts.map +0 -1
  124. package/dist/_chunks/index2.d.mts +0 -279
  125. package/dist/_chunks/index2.d.mts.map +0 -1
  126. package/dist/_chunks/index3.d.mts +0 -44
  127. package/dist/_chunks/index3.d.mts.map +0 -1
  128. package/dist/_chunks/index4.d.mts +0 -553
  129. package/dist/_chunks/index4.d.mts.map +0 -1
  130. package/dist/_chunks/package-registry.mjs +0 -465
  131. package/dist/_chunks/package-registry.mjs.map +0 -1
  132. package/dist/_chunks/retriv.mjs.map +0 -1
  133. package/dist/_chunks/setup.mjs +0 -17
  134. package/dist/_chunks/setup.mjs.map +0 -1
  135. package/dist/_chunks/sources.mjs +0 -2654
  136. package/dist/_chunks/sources.mjs.map +0 -1
  137. package/dist/_chunks/sync-pipeline.mjs.map +0 -1
  138. package/dist/_chunks/sync-registry.mjs +0 -65
  139. package/dist/_chunks/sync-registry.mjs.map +0 -1
  140. package/dist/_chunks/types.d.mts +0 -76
  141. package/dist/_chunks/types.d.mts.map +0 -1
  142. package/dist/_chunks/types2.d.mts +0 -88
  143. package/dist/_chunks/types2.d.mts.map +0 -1
  144. package/dist/_chunks/wizard.mjs.map +0 -1
  145. package/dist/agent/index.d.mts +0 -2
  146. package/dist/agent/index.mjs +0 -4
  147. package/dist/cache/index.d.mts +0 -2
  148. package/dist/cache/index.mjs +0 -5
  149. package/dist/index.d.mts +0 -6
  150. package/dist/index.mjs +0 -6
  151. package/dist/retriv/index.d.mts +0 -3
  152. package/dist/retriv/index.mjs +0 -2
  153. package/dist/sources/index.d.mts +0 -3
  154. package/dist/sources/index.mjs +0 -3
  155. package/dist/types.d.mts +0 -4
  156. package/dist/types.mjs +0 -1
@@ -0,0 +1,219 @@
1
+ import { t as autoResolveAgent } from "./agent-prompt.mjs";
2
+ import { t as sharedArgs } from "./args.mjs";
3
+ import { n as loadSession } from "./store.mjs";
4
+ import { t as createRegistryClient } from "./client.mjs";
5
+ import { t as track } from "./telemetry.mjs";
6
+ import { t as installSkills } from "./install-many.mjs";
7
+ import { styleText } from "node:util";
8
+ import * as p from "@clack/prompts";
9
+ import { defineCommand } from "citty";
10
+ function manifestItemKey(item) {
11
+ if (item.kind === "gh") return item.name ? `${item.owner}/${item.repo}/${item.name}` : `${item.owner}/${item.repo}`;
12
+ return item.package ?? `${item.kind}:unknown`;
13
+ }
14
+ function manifestToSources(items) {
15
+ const npm = [];
16
+ const crate = [];
17
+ const ghByRepo = /* @__PURE__ */ new Map();
18
+ for (const item of items) {
19
+ if (item.kind === "npm" && item.package) {
20
+ npm.push({ source: {
21
+ type: "npm",
22
+ package: item.package
23
+ } });
24
+ continue;
25
+ }
26
+ if (item.kind === "crate" && item.package) {
27
+ crate.push({ source: {
28
+ type: "crate",
29
+ package: item.package
30
+ } });
31
+ continue;
32
+ }
33
+ if (item.kind === "gh" && item.owner && item.repo) {
34
+ const key = `${item.owner}/${item.repo}`;
35
+ const group = ghByRepo.get(key) ?? {
36
+ owner: item.owner,
37
+ repo: item.repo,
38
+ names: []
39
+ };
40
+ if (item.name && !group.names.includes(item.name)) group.names.push(item.name);
41
+ ghByRepo.set(key, group);
42
+ }
43
+ }
44
+ const gh = [];
45
+ for (const group of ghByRepo.values()) gh.push({
46
+ source: {
47
+ type: "git",
48
+ source: {
49
+ type: "github",
50
+ owner: group.owner,
51
+ repo: group.repo
52
+ }
53
+ },
54
+ skillFilter: group.names.length ? group.names.join(",") : void 0
55
+ });
56
+ return [
57
+ ...gh,
58
+ ...npm,
59
+ ...crate
60
+ ];
61
+ }
62
+ function badgeFor(status, result) {
63
+ switch (status) {
64
+ case "pass": return styleText("green", "✓ audited");
65
+ case "warn": return styleText("yellow", `⚠ warn${result.summary ? `: ${result.summary}` : ""}`);
66
+ case "fail": return styleText("red", `✗ fail${result.summary ? `: ${result.summary}` : ""}`);
67
+ case "unaudited": return styleText("gray", "? unaudited");
68
+ }
69
+ }
70
+ async function pickCollection(collections, slug) {
71
+ if (slug) {
72
+ const match = collections.find((c) => c.slug === slug);
73
+ if (!match) {
74
+ p.log.error(`No collection with slug "${slug}". Available: ${collections.map((c) => c.slug).join(", ")}`);
75
+ return null;
76
+ }
77
+ return match;
78
+ }
79
+ if (collections.length === 0) {
80
+ p.log.warn("You have no collections on skilld.dev. Create one at https://skilld.dev/me/collections");
81
+ return null;
82
+ }
83
+ if (collections.length === 1) return collections[0];
84
+ const choice = await p.select({
85
+ message: "Pick a collection",
86
+ options: collections.map((c) => ({
87
+ label: c.name,
88
+ value: c.slug,
89
+ hint: `${c.itemCount} skills`
90
+ }))
91
+ });
92
+ if (p.isCancel(choice)) return null;
93
+ return collections.find((c) => c.slug === choice) ?? null;
94
+ }
95
+ const pullCommandDef = defineCommand({
96
+ meta: {
97
+ name: "pull",
98
+ description: "Install skills from one of your collections"
99
+ },
100
+ args: {
101
+ "collection": {
102
+ type: "string",
103
+ description: "Collection slug to pull",
104
+ valueHint: "slug"
105
+ },
106
+ "all": {
107
+ type: "boolean",
108
+ description: "Install every item without prompting"
109
+ },
110
+ "allow-unsafe": {
111
+ type: "boolean",
112
+ description: "Install items that fail the audit gate"
113
+ },
114
+ ...sharedArgs
115
+ },
116
+ async run({ args }) {
117
+ const agent = autoResolveAgent(args.agent);
118
+ if (!agent) {
119
+ p.log.error("No target agent detected.\n Pass --agent <name> (claude-code, cursor, codex, …), or run `skilld config` to set a default.");
120
+ process.exitCode = 1;
121
+ return;
122
+ }
123
+ const session = await loadSession();
124
+ if (!session) {
125
+ p.log.error("Not logged in. Run `skilld login` first.");
126
+ process.exitCode = 1;
127
+ return;
128
+ }
129
+ const client = createRegistryClient({ session });
130
+ const picked = await pickCollection(await client.my.collections(), args.collection);
131
+ if (!picked) return;
132
+ const manifest = await client.fetchCollection(session.login, picked.slug);
133
+ if (!manifest) {
134
+ p.log.error(`Failed to load collection manifest for @${session.login}/${picked.slug}.`);
135
+ process.exitCode = 1;
136
+ return;
137
+ }
138
+ if (manifest.items.length === 0) {
139
+ p.log.warn("Collection is empty.");
140
+ return;
141
+ }
142
+ const auditCache = /* @__PURE__ */ new Map();
143
+ const auditByKey = /* @__PURE__ */ new Map();
144
+ const spin = p.spinner();
145
+ spin.start(`Auditing ${manifest.items.length} items`);
146
+ await Promise.all(manifest.items.map(async (item) => {
147
+ if (item.kind !== "gh" || !item.owner || !item.repo || !item.name) {
148
+ auditByKey.set(manifestItemKey(item), {
149
+ status: "unaudited",
150
+ audits: []
151
+ });
152
+ return;
153
+ }
154
+ const result = await client.audit({
155
+ owner: item.owner,
156
+ repo: item.repo,
157
+ name: item.name
158
+ });
159
+ auditCache.set(`${item.owner}/${item.repo}/${item.name}`, result);
160
+ auditByKey.set(manifestItemKey(item), result);
161
+ }));
162
+ spin.stop(`Audited ${manifest.items.length} items`);
163
+ track({
164
+ event: "pull-checklist",
165
+ surface: "cli:pull",
166
+ sourceKind: "collection",
167
+ slug: `${session.login}/${picked.slug}`,
168
+ agent
169
+ });
170
+ let selected;
171
+ if (args.all || args.yes) selected = manifest.items.filter((item) => {
172
+ const audit = auditByKey.get(manifestItemKey(item));
173
+ return args["allow-unsafe"] || audit?.status !== "fail";
174
+ });
175
+ else {
176
+ const choice = await p.multiselect({
177
+ message: `Select skills from ${manifest.name}`,
178
+ required: false,
179
+ initialValues: manifest.items.filter((item) => auditByKey.get(manifestItemKey(item))?.status !== "fail").map(manifestItemKey),
180
+ options: manifest.items.map((item) => {
181
+ const key = manifestItemKey(item);
182
+ const audit = auditByKey.get(key) ?? {
183
+ status: "unaudited",
184
+ audits: []
185
+ };
186
+ return {
187
+ label: `${key} ${styleText("gray", `(${item.kind})`)}`,
188
+ value: key,
189
+ hint: badgeFor(audit.status, audit)
190
+ };
191
+ })
192
+ });
193
+ if (p.isCancel(choice)) return;
194
+ const chosen = new Set(choice);
195
+ selected = manifest.items.filter((item) => chosen.has(manifestItemKey(item)));
196
+ }
197
+ const sources = manifestToSources(selected);
198
+ if (sources.length === 0) {
199
+ p.log.info("Nothing to install.");
200
+ return;
201
+ }
202
+ const summary = await installSkills(sources.map(({ source, skillFilter }) => source.type === "git" ? {
203
+ ...source,
204
+ skillFilter
205
+ } : source), {
206
+ agent,
207
+ surface: "cli:pull",
208
+ yes: args.yes,
209
+ force: args.force,
210
+ debug: args.debug,
211
+ allowUnsafe: args["allow-unsafe"],
212
+ auditCache
213
+ });
214
+ p.outro(`${summary.installed} installed · ${summary.skipped} skipped · ${summary.failed} failed`);
215
+ }
216
+ });
217
+ export { pullCommandDef };
218
+
219
+ //# sourceMappingURL=pull.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pull.mjs","names":[],"sources":["../../src/commands/pull.ts"],"sourcesContent":["/**\n * `skilld pull` — install skills from one of the user's collections.\n *\n * Headline authed command. Pulls the user's collections from skilld.dev,\n * optionally lets them pick one, fans out audit checks in parallel, and\n * presents a multiselect checklist with audit-status badges before handing\n * the selection to `installSkills` (surface = `cli:pull`).\n */\n\nimport type { SkillSource } from '../core/prefix.ts'\nimport type { AuditResult, AuditStatus, CollectionManifest, CollectionManifestItem, CollectionSummary } from '../registry/client.ts'\nimport { styleText } from 'node:util'\nimport * as p from '@clack/prompts'\nimport { defineCommand } from 'citty'\nimport { loadSession } from '../auth/store.ts'\nimport { autoResolveAgent } from '../cli/agent-prompt.ts'\nimport { sharedArgs } from '../cli/args.ts'\nimport { createRegistryClient } from '../registry/client.ts'\nimport { track } from '../telemetry.ts'\nimport { installSkills } from './sync/install-many.ts'\n\nfunction manifestItemKey(item: CollectionManifestItem): string {\n if (item.kind === 'gh')\n return item.name ? `${item.owner}/${item.repo}/${item.name}` : `${item.owner}/${item.repo}`\n return item.package ?? `${item.kind}:unknown`\n}\n\n/**\n * Convert selected manifest items into `installSkills` inputs. Multiple gh\n * items in the same repo collapse to one `git` source carrying the union of\n * picked skill names as `skillFilter`, so a repo with N skills installs in\n * one `syncGitSkills` call instead of N redundant ones.\n */\nfunction manifestToSources(items: CollectionManifestItem[]): Array<{ source: SkillSource, skillFilter?: string }> {\n const npm: Array<{ source: SkillSource, skillFilter?: string }> = []\n const crate: Array<{ source: SkillSource, skillFilter?: string }> = []\n const ghByRepo = new Map<string, { owner: string, repo: string, names: string[] }>()\n\n for (const item of items) {\n if (item.kind === 'npm' && item.package) {\n npm.push({ source: { type: 'npm', package: item.package } })\n continue\n }\n if (item.kind === 'crate' && item.package) {\n crate.push({ source: { type: 'crate', package: item.package } })\n continue\n }\n if (item.kind === 'gh' && item.owner && item.repo) {\n const key = `${item.owner}/${item.repo}`\n const group = ghByRepo.get(key) ?? { owner: item.owner, repo: item.repo, names: [] }\n if (item.name && !group.names.includes(item.name))\n group.names.push(item.name)\n ghByRepo.set(key, group)\n }\n }\n\n const gh: Array<{ source: SkillSource, skillFilter?: string }> = []\n for (const group of ghByRepo.values()) {\n gh.push({\n source: { type: 'git', source: { type: 'github', owner: group.owner, repo: group.repo } },\n skillFilter: group.names.length ? group.names.join(',') : undefined,\n })\n }\n\n return [...gh, ...npm, ...crate]\n}\n\nfunction badgeFor(status: AuditStatus, result: AuditResult): string {\n switch (status) {\n case 'pass':\n return styleText('green', '✓ audited')\n case 'warn':\n return styleText('yellow', `⚠ warn${result.summary ? `: ${result.summary}` : ''}`)\n case 'fail':\n return styleText('red', `✗ fail${result.summary ? `: ${result.summary}` : ''}`)\n case 'unaudited':\n return styleText('gray', '? unaudited')\n }\n}\n\nasync function pickCollection(collections: CollectionSummary[], slug?: string): Promise<CollectionSummary | null> {\n if (slug) {\n const match = collections.find(c => c.slug === slug)\n if (!match) {\n p.log.error(`No collection with slug \"${slug}\". Available: ${collections.map(c => c.slug).join(', ')}`)\n return null\n }\n return match\n }\n if (collections.length === 0) {\n p.log.warn('You have no collections on skilld.dev. Create one at https://skilld.dev/me/collections')\n return null\n }\n if (collections.length === 1)\n return collections[0]!\n\n const choice = await p.select({\n message: 'Pick a collection',\n options: collections.map(c => ({ label: c.name, value: c.slug, hint: `${c.itemCount} skills` })),\n })\n if (p.isCancel(choice))\n return null\n return collections.find(c => c.slug === choice) ?? null\n}\n\nexport const pullCommandDef = defineCommand({\n meta: { name: 'pull', description: 'Install skills from one of your collections' },\n args: {\n 'collection': { type: 'string', description: 'Collection slug to pull', valueHint: 'slug' },\n 'all': { type: 'boolean', description: 'Install every item without prompting' },\n 'allow-unsafe': { type: 'boolean', description: 'Install items that fail the audit gate' },\n ...sharedArgs,\n },\n async run({ args }) {\n const agent = autoResolveAgent(args.agent)\n if (!agent) {\n p.log.error('No target agent detected.\\n Pass --agent <name> (claude-code, cursor, codex, …), or run `skilld config` to set a default.')\n process.exitCode = 1\n return\n }\n\n const session = await loadSession()\n if (!session) {\n p.log.error('Not logged in. Run `skilld login` first.')\n process.exitCode = 1\n return\n }\n\n const client = createRegistryClient({ session })\n const collections = await client.my.collections()\n const picked = await pickCollection(collections, args.collection)\n if (!picked)\n return\n\n const manifest = await client.fetchCollection(session.login, picked.slug) as CollectionManifest | null\n if (!manifest) {\n p.log.error(`Failed to load collection manifest for @${session.login}/${picked.slug}.`)\n process.exitCode = 1\n return\n }\n if (manifest.items.length === 0) {\n p.log.warn('Collection is empty.')\n return\n }\n\n const auditCache = new Map<string, AuditResult>()\n const auditByKey = new Map<string, AuditResult>()\n\n const spin = p.spinner()\n spin.start(`Auditing ${manifest.items.length} items`)\n await Promise.all(manifest.items.map(async (item) => {\n // Audit needs the full (owner, repo, name) tuple. gh manifest items\n // carry `name` directly; npm/crate items don't, so they're unaudited\n // here and re-evaluated inside `installSkills` after resolve.\n if (item.kind !== 'gh' || !item.owner || !item.repo || !item.name) {\n auditByKey.set(manifestItemKey(item), { status: 'unaudited', audits: [] })\n return\n }\n const result = await client.audit({ owner: item.owner, repo: item.repo, name: item.name })\n auditCache.set(`${item.owner}/${item.repo}/${item.name}`, result)\n auditByKey.set(manifestItemKey(item), result)\n }))\n spin.stop(`Audited ${manifest.items.length} items`)\n\n track({\n event: 'pull-checklist',\n surface: 'cli:pull',\n sourceKind: 'collection',\n slug: `${session.login}/${picked.slug}`,\n agent,\n })\n\n let selected: CollectionManifestItem[]\n if (args.all || args.yes) {\n selected = manifest.items.filter((item) => {\n const audit = auditByKey.get(manifestItemKey(item))\n return args['allow-unsafe'] || audit?.status !== 'fail'\n })\n }\n else {\n const choice = await p.multiselect({\n message: `Select skills from ${manifest.name}`,\n required: false,\n initialValues: manifest.items\n .filter(item => auditByKey.get(manifestItemKey(item))?.status !== 'fail')\n .map(manifestItemKey),\n options: manifest.items.map((item) => {\n const key = manifestItemKey(item)\n const audit = auditByKey.get(key) ?? { status: 'unaudited' as const, audits: [] }\n return {\n label: `${key} ${styleText('gray', `(${item.kind})`)}`,\n value: key,\n hint: badgeFor(audit.status, audit),\n }\n }),\n })\n if (p.isCancel(choice))\n return\n const chosen = new Set(choice as string[])\n selected = manifest.items.filter(item => chosen.has(manifestItemKey(item)))\n }\n\n const sources = manifestToSources(selected)\n if (sources.length === 0) {\n p.log.info('Nothing to install.')\n return\n }\n // Carry per-source `skillFilter` on the git variant of SkillSource so\n // multiple skills under one repo collapse into a single syncGitSkills call.\n const items: SkillSource[] = sources.map(({ source, skillFilter }) =>\n source.type === 'git' ? { ...source, skillFilter } : source,\n )\n\n const summary = await installSkills(items, {\n agent,\n surface: 'cli:pull',\n yes: args.yes,\n force: args.force,\n debug: args.debug,\n allowUnsafe: args['allow-unsafe'],\n auditCache,\n })\n\n p.outro(`${summary.installed} installed · ${summary.skipped} skipped · ${summary.failed} failed`)\n },\n})\n"],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ const API_CHANGE_BULLET_RE = /^- (?:BREAKING|DEPRECATED|NEW): /m;
2
+ const COMMA_OR_WHITESPACE_RE = /[,\s]+/;
3
+ const GIT_PROTOCOL_PREFIX_RE = /^git:\/\//;
4
+ const GIT_SUFFIX_RE = /\.git$/;
5
+ const GITHUB_SSH_URL_PREFIX_RE = /^ssh:\/\/git@github\.com/;
6
+ const GIT_PLUS_PREFIX_RE = /^git\+/;
7
+ const LEADING_SLASH_RE = /^\//;
8
+ const README_FILENAME_RE = /^readme\.md$/i;
9
+ const SECTION_HEADING_RE = /^##\s/m;
10
+ const SEMVER_MAJOR_MINOR_RE = /^(\d+)\.(\d+)/;
11
+ const SOURCE_LINK_RE = /\[source\]/;
12
+ const TRAILING_SLASH_RE = /\/$/;
13
+ const V_PREFIX_RE = /^v/;
14
+ const VERSION_RANGE_PREFIX_RE = /^[\^~>=<]+/;
15
+ const NPM_SCOPE_PREFIX_RE = /^@/;
16
+ const NPM_SCOPE_WITH_SLASH_RE = /^@.*\//;
17
+ export { GIT_PROTOCOL_PREFIX_RE as a, NPM_SCOPE_PREFIX_RE as c, SECTION_HEADING_RE as d, SEMVER_MAJOR_MINOR_RE as f, V_PREFIX_RE as g, VERSION_RANGE_PREFIX_RE as h, GIT_PLUS_PREFIX_RE as i, NPM_SCOPE_WITH_SLASH_RE as l, TRAILING_SLASH_RE as m, COMMA_OR_WHITESPACE_RE as n, GIT_SUFFIX_RE as o, SOURCE_LINK_RE as p, GITHUB_SSH_URL_PREFIX_RE as r, LEADING_SLASH_RE as s, API_CHANGE_BULLET_RE as t, README_FILENAME_RE as u };
18
+
19
+ //# sourceMappingURL=regex.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"regex.mjs","names":[],"sources":["../../src/core/regex.ts"],"sourcesContent":["export const API_CHANGE_BULLET_RE = /^- (?:BREAKING|DEPRECATED|NEW): /m\nexport const COMMA_OR_WHITESPACE_RE = /[,\\s]+/\nexport const GIT_PROTOCOL_PREFIX_RE = /^git:\\/\\//\nexport const GIT_SUFFIX_RE = /\\.git$/\nexport const GITHUB_SSH_URL_PREFIX_RE = /^ssh:\\/\\/git@github\\.com/\nexport const GIT_PLUS_PREFIX_RE = /^git\\+/\nexport const LEADING_SLASH_RE = /^\\//\nexport const README_FILENAME_RE = /^readme\\.md$/i\nexport const SECTION_HEADING_RE = /^##\\s/m\nexport const SEMVER_MAJOR_MINOR_RE = /^(\\d+)\\.(\\d+)/\nexport const SOURCE_LINK_RE = /\\[source\\]/\nexport const TRAILING_SLASH_RE = /\\/$/\nexport const V_PREFIX_RE = /^v/\nexport const VERSION_RANGE_PREFIX_RE = /^[\\^~>=<]+/\nexport const NPM_SCOPE_PREFIX_RE = /^@/\nexport const NPM_SCOPE_WITH_SLASH_RE = /^@.*\\//\n"],"mappings":"AAAA,MAAa,uBAAuB;AACpC,MAAa,yBAAyB;AACtC,MAAa,yBAAyB;AACtC,MAAa,gBAAgB;AAC7B,MAAa,2BAA2B;AACxC,MAAa,qBAAqB;AAClC,MAAa,mBAAmB;AAChC,MAAa,qBAAqB;AAClC,MAAa,qBAAqB;AAClC,MAAa,wBAAwB;AACrC,MAAa,iBAAiB;AAC9B,MAAa,oBAAoB;AACjC,MAAa,cAAc;AAC3B,MAAa,0BAA0B;AACvC,MAAa,sBAAsB;AACnC,MAAa,0BAA0B"}
@@ -1,171 +1,2 @@
1
- import { a as stripFrontmatter } from "./markdown.mjs";
2
- var SearchDepsUnavailableError = class extends Error {
3
- constructor(cause, message) {
4
- super(message ?? "Search dependencies unavailable (sqlite-vec or retriv not installed). Search indexing skipped.");
5
- this.name = "SearchDepsUnavailableError";
6
- this.cause = cause;
7
- }
8
- };
9
- let _fts5Available = null;
10
- function checkFts5() {
11
- if (_fts5Available !== null) return _fts5Available;
12
- const nodeSqlite = globalThis.process?.getBuiltinModule?.("node:sqlite");
13
- if (!nodeSqlite) {
14
- _fts5Available = false;
15
- return false;
16
- }
17
- const db = new nodeSqlite.DatabaseSync(":memory:");
18
- try {
19
- db.exec("CREATE VIRTUAL TABLE _fts5_probe USING fts5(content)");
20
- db.exec("DROP TABLE _fts5_probe");
21
- _fts5Available = true;
22
- } catch {
23
- _fts5Available = false;
24
- } finally {
25
- db.close();
26
- }
27
- return _fts5Available;
28
- }
29
- async function getDb(config) {
30
- if (!checkFts5()) throw new SearchDepsUnavailableError(/* @__PURE__ */ new Error("FTS5 module not available"), "SQLite FTS5 module not available. Search indexing skipped. On Windows, run from WSL where FTS5 is included.");
31
- let createRetriv, autoChunker, sqliteMod, sqliteVec, transformersJs, cachedEmbeddings;
32
- try {
33
- [{createRetriv}, {autoChunker}, sqliteMod, sqliteVec, {transformersJs}, {cachedEmbeddings}] = await Promise.all([
34
- import("retriv"),
35
- import("retriv/chunkers/auto"),
36
- import("retriv/db/sqlite"),
37
- import("sqlite-vec"),
38
- import("retriv/embeddings/transformers-js"),
39
- import("./embedding-cache.mjs")
40
- ]);
41
- } catch (err) {
42
- if (err?.code === "ERR_MODULE_NOT_FOUND") throw new SearchDepsUnavailableError(err);
43
- throw err;
44
- }
45
- const embeddings = await cachedEmbeddings(transformersJs());
46
- return createRetriv({
47
- driver: sqliteMod.default({
48
- path: config.dbPath,
49
- embeddings,
50
- sqliteVec
51
- }),
52
- chunking: autoChunker()
53
- });
54
- }
55
- async function createIndexDirect(documents, config) {
56
- const db = await getDb(config);
57
- if (config.removeIds?.length) await db.remove?.(config.removeIds);
58
- await db.index(documents, { onProgress: config.onProgress });
59
- await db.close?.();
60
- }
61
- async function createIndex(documents, config) {
62
- const { createIndexInWorker } = await import("./pool.mjs");
63
- return createIndexInWorker(documents, config);
64
- }
65
- async function listIndexIds(config) {
66
- const nodeSqlite = globalThis.process?.getBuiltinModule?.("node:sqlite");
67
- if (!nodeSqlite) return [];
68
- const db = new nodeSqlite.DatabaseSync(config.dbPath, {
69
- open: true,
70
- readOnly: true
71
- });
72
- try {
73
- return db.prepare("SELECT id FROM documents_meta").all().map((r) => r.id);
74
- } finally {
75
- db.close();
76
- }
77
- }
78
- async function removeFromIndex(ids, config) {
79
- if (ids.length === 0) return;
80
- const db = await getDb(config);
81
- await db.remove?.(ids);
82
- await db.close?.();
83
- }
84
- async function search(query, config, options = {}) {
85
- const { limit = 10, filter } = options;
86
- const db = await getDb(config);
87
- const results = await db.search(query, {
88
- limit,
89
- filter,
90
- returnContent: true,
91
- returnMetadata: true,
92
- returnMeta: true
93
- });
94
- await db.close?.();
95
- return results.map((r) => ({
96
- id: r.id,
97
- content: r.content ?? "",
98
- score: r.score,
99
- metadata: r.metadata ?? {},
100
- highlights: r._meta?.highlights ?? [],
101
- lineRange: r._chunk?.lineRange,
102
- entities: r._chunk?.entities,
103
- scope: r._chunk?.scope
104
- }));
105
- }
106
- async function searchSnippets(query, config, options = {}) {
107
- return toSnippets(await search(query, config, options));
108
- }
109
- function toSnippets(results) {
110
- return results.map((r) => {
111
- const content = stripFrontmatter(r.content);
112
- const source = r.metadata.source || r.id;
113
- const lines = content.split("\n").length;
114
- return {
115
- package: r.metadata.package || "unknown",
116
- source,
117
- lineStart: r.lineRange?.[0] ?? 1,
118
- lineEnd: r.lineRange?.[1] ?? lines,
119
- content,
120
- score: r.score,
121
- highlights: r.highlights,
122
- entities: r.entities,
123
- scope: r.scope
124
- };
125
- });
126
- }
127
- async function openPool(dbPaths) {
128
- const pool = /* @__PURE__ */ new Map();
129
- await Promise.all(dbPaths.map(async (dbPath) => {
130
- const db = await getDb({ dbPath });
131
- pool.set(dbPath, db);
132
- }));
133
- return pool;
134
- }
135
- async function searchPooled(query, pool, options = {}) {
136
- const { limit = 10, filter } = options;
137
- const fetchLimit = limit * 2;
138
- const allResults = await Promise.all(Array.from(pool.values(), async (db) => {
139
- return (await db.search(query, {
140
- limit: fetchLimit,
141
- filter,
142
- returnContent: true,
143
- returnMetadata: true,
144
- returnMeta: true
145
- })).map((r) => ({
146
- id: r.id,
147
- content: r.content ?? "",
148
- score: r.score,
149
- metadata: r.metadata ?? {},
150
- highlights: r._meta?.highlights ?? [],
151
- lineRange: r._chunk?.lineRange,
152
- entities: r._chunk?.entities,
153
- scope: r._chunk?.scope
154
- }));
155
- }));
156
- const seen = /* @__PURE__ */ new Set();
157
- return toSnippets(allResults.flat().sort((a, b) => b.score - a.score).filter((r) => {
158
- const lr = r.lineRange;
159
- const key = `${r.metadata.source || r.id}:${lr?.[0]}-${lr?.[1]}`;
160
- if (seen.has(key)) return false;
161
- seen.add(key);
162
- return true;
163
- }).slice(0, limit));
164
- }
165
- async function closePool(pool) {
166
- await Promise.all(Array.from(pool.values(), (db) => db.close?.()));
167
- pool.clear();
168
- }
169
- export { getDb as a, removeFromIndex as c, searchSnippets as d, createIndexDirect as i, search as l, closePool as n, listIndexIds as o, createIndex as r, openPool as s, SearchDepsUnavailableError as t, searchPooled as u };
170
-
171
- //# sourceMappingURL=retriv.mjs.map
1
+ import { i as getDb } from "./retriv2.mjs";
2
+ export { getDb };
@@ -0,0 +1,159 @@
1
+ import { a as stripFrontmatter } from "./markdown.mjs";
2
+ var SearchDepsUnavailableError = class extends Error {
3
+ constructor(cause, message) {
4
+ super(message ?? "Search dependencies unavailable (sqlite-vec or retriv not installed). Search indexing skipped.");
5
+ this.name = "SearchDepsUnavailableError";
6
+ this.cause = cause;
7
+ }
8
+ };
9
+ let _fts5Available = null;
10
+ function checkFts5() {
11
+ if (_fts5Available !== null) return _fts5Available;
12
+ const nodeSqlite = globalThis.process?.getBuiltinModule?.("node:sqlite");
13
+ if (!nodeSqlite) {
14
+ _fts5Available = false;
15
+ return false;
16
+ }
17
+ const db = new nodeSqlite.DatabaseSync(":memory:");
18
+ try {
19
+ db.exec("CREATE VIRTUAL TABLE _fts5_probe USING fts5(content)");
20
+ db.exec("DROP TABLE _fts5_probe");
21
+ _fts5Available = true;
22
+ } catch {
23
+ _fts5Available = false;
24
+ } finally {
25
+ db.close();
26
+ }
27
+ return _fts5Available;
28
+ }
29
+ async function getDb(config) {
30
+ if (!checkFts5()) throw new SearchDepsUnavailableError(/* @__PURE__ */ new Error("FTS5 module not available"), "SQLite FTS5 module not available. Search indexing skipped. On Windows, run from WSL where FTS5 is included.");
31
+ let createRetriv, autoChunker, sqliteMod, sqliteVec, transformersJs, cachedEmbeddings;
32
+ try {
33
+ [{createRetriv}, {autoChunker}, sqliteMod, sqliteVec, {transformersJs}, {cachedEmbeddings}] = await Promise.all([
34
+ import("retriv"),
35
+ import("retriv/chunkers/auto"),
36
+ import("retriv/db/sqlite"),
37
+ import("sqlite-vec"),
38
+ import("retriv/embeddings/transformers-js"),
39
+ import("./embedding-cache.mjs")
40
+ ]);
41
+ } catch (err) {
42
+ if (err?.code === "ERR_MODULE_NOT_FOUND") throw new SearchDepsUnavailableError(err);
43
+ throw err;
44
+ }
45
+ const embeddings = await cachedEmbeddings(transformersJs());
46
+ return createRetriv({
47
+ driver: sqliteMod.default({
48
+ path: config.dbPath,
49
+ embeddings,
50
+ sqliteVec
51
+ }),
52
+ chunking: autoChunker()
53
+ });
54
+ }
55
+ async function createIndex(documents, config) {
56
+ const { createIndexInWorker } = await import("./pool.mjs");
57
+ return createIndexInWorker(documents, config);
58
+ }
59
+ async function listIndexIds(config) {
60
+ const nodeSqlite = globalThis.process?.getBuiltinModule?.("node:sqlite");
61
+ if (!nodeSqlite) return [];
62
+ const db = new nodeSqlite.DatabaseSync(config.dbPath, {
63
+ open: true,
64
+ readOnly: true
65
+ });
66
+ try {
67
+ return db.prepare("SELECT id FROM documents_meta").all().map((r) => r.id);
68
+ } finally {
69
+ db.close();
70
+ }
71
+ }
72
+ async function search(query, config, options = {}) {
73
+ const { limit = 10, filter } = options;
74
+ const db = await getDb(config);
75
+ const results = await db.search(query, {
76
+ limit,
77
+ filter,
78
+ returnContent: true,
79
+ returnMetadata: true,
80
+ returnMeta: true
81
+ });
82
+ await db.close?.();
83
+ return results.map((r) => ({
84
+ id: r.id,
85
+ content: r.content ?? "",
86
+ score: r.score,
87
+ metadata: r.metadata ?? {},
88
+ highlights: r._meta?.highlights ?? [],
89
+ lineRange: r._chunk?.lineRange,
90
+ entities: r._chunk?.entities,
91
+ scope: r._chunk?.scope
92
+ }));
93
+ }
94
+ async function searchSnippets(query, config, options = {}) {
95
+ return toSnippets(await search(query, config, options));
96
+ }
97
+ function toSnippets(results) {
98
+ return results.map((r) => {
99
+ const content = stripFrontmatter(r.content);
100
+ const source = r.metadata.source || r.id;
101
+ const lines = content.split("\n").length;
102
+ return {
103
+ package: r.metadata.package || "unknown",
104
+ source,
105
+ lineStart: r.lineRange?.[0] ?? 1,
106
+ lineEnd: r.lineRange?.[1] ?? lines,
107
+ content,
108
+ score: r.score,
109
+ highlights: r.highlights,
110
+ entities: r.entities,
111
+ scope: r.scope
112
+ };
113
+ });
114
+ }
115
+ async function openPool(dbPaths) {
116
+ const pool = /* @__PURE__ */ new Map();
117
+ await Promise.all(dbPaths.map(async (dbPath) => {
118
+ const db = await getDb({ dbPath });
119
+ pool.set(dbPath, db);
120
+ }));
121
+ return pool;
122
+ }
123
+ async function searchPooled(query, pool, options = {}) {
124
+ const { limit = 10, filter } = options;
125
+ const fetchLimit = limit * 2;
126
+ const allResults = await Promise.all(Array.from(pool.values(), async (db) => {
127
+ return (await db.search(query, {
128
+ limit: fetchLimit,
129
+ filter,
130
+ returnContent: true,
131
+ returnMetadata: true,
132
+ returnMeta: true
133
+ })).map((r) => ({
134
+ id: r.id,
135
+ content: r.content ?? "",
136
+ score: r.score,
137
+ metadata: r.metadata ?? {},
138
+ highlights: r._meta?.highlights ?? [],
139
+ lineRange: r._chunk?.lineRange,
140
+ entities: r._chunk?.entities,
141
+ scope: r._chunk?.scope
142
+ }));
143
+ }));
144
+ const seen = /* @__PURE__ */ new Set();
145
+ return toSnippets(allResults.flat().sort((a, b) => b.score - a.score).filter((r) => {
146
+ const lr = r.lineRange;
147
+ const key = `${r.metadata.source || r.id}:${lr?.[0]}-${lr?.[1]}`;
148
+ if (seen.has(key)) return false;
149
+ seen.add(key);
150
+ return true;
151
+ }).slice(0, limit));
152
+ }
153
+ async function closePool(pool) {
154
+ await Promise.all(Array.from(pool.values(), (db) => db.close?.()));
155
+ pool.clear();
156
+ }
157
+ export { listIndexIds as a, searchPooled as c, getDb as i, searchSnippets as l, closePool as n, openPool as o, createIndex as r, search as s, SearchDepsUnavailableError as t };
158
+
159
+ //# sourceMappingURL=retriv2.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retriv2.mjs","names":[],"sources":["../../src/retriv/index.ts"],"sourcesContent":["import type { ChunkEntity, Document, IndexConfig, IndexPhase, IndexProgress, SearchFilter, SearchOptions, SearchResult, SearchSnippet } from './types.ts'\nimport { stripFrontmatter } from '../core/markdown.ts'\n\nexport type { ChunkEntity, Document, IndexConfig, IndexPhase, IndexProgress, SearchFilter, SearchOptions, SearchResult, SearchSnippet }\n\ntype RetrivInstance = Awaited<ReturnType<typeof getDb>>\n\nexport class SearchDepsUnavailableError extends Error {\n constructor(cause: unknown, message?: string) {\n super(message ?? 'Search dependencies unavailable (sqlite-vec or retriv not installed). Search indexing skipped.')\n this.name = 'SearchDepsUnavailableError'\n this.cause = cause\n }\n}\n\nlet _fts5Available: boolean | null = null\n\n/**\n * Probe whether SQLite FTS5 module is available.\n * Windows Node.js binaries often ship without FTS5 compiled in.\n */\nfunction checkFts5(): boolean {\n if (_fts5Available !== null)\n return _fts5Available\n const nodeSqlite = globalThis.process?.getBuiltinModule?.('node:sqlite') as typeof import('node:sqlite') | undefined\n if (!nodeSqlite) {\n _fts5Available = false\n return false\n }\n const db = new nodeSqlite.DatabaseSync(':memory:')\n try {\n db.exec('CREATE VIRTUAL TABLE _fts5_probe USING fts5(content)')\n db.exec('DROP TABLE _fts5_probe')\n _fts5Available = true\n }\n catch {\n _fts5Available = false\n }\n finally {\n db.close()\n }\n return _fts5Available\n}\n\n// Dynamic imports: retriv/chunkers/auto eagerly loads typescript which may not be installed (e.g. npx)\nexport async function getDb(config: Pick<IndexConfig, 'dbPath'>) {\n if (!checkFts5())\n throw new SearchDepsUnavailableError(new Error('FTS5 module not available'), 'SQLite FTS5 module not available. Search indexing skipped. On Windows, run from WSL where FTS5 is included.')\n\n let createRetriv, autoChunker, sqliteMod, sqliteVec, transformersJs, cachedEmbeddings\n try {\n ;([\n { createRetriv },\n { autoChunker },\n sqliteMod,\n sqliteVec,\n { transformersJs },\n { cachedEmbeddings },\n ] = await Promise.all([\n import('retriv'),\n import('retriv/chunkers/auto'),\n import('retriv/db/sqlite'),\n import('sqlite-vec'),\n import('retriv/embeddings/transformers-js'),\n import('./embedding-cache.ts'),\n ]))\n }\n catch (err: any) {\n if (err?.code === 'ERR_MODULE_NOT_FOUND')\n throw new SearchDepsUnavailableError(err)\n throw err\n }\n const embeddings = await cachedEmbeddings(transformersJs())\n return createRetriv({\n driver: sqliteMod.default({\n path: config.dbPath,\n embeddings,\n sqliteVec,\n }),\n chunking: autoChunker(),\n })\n}\n\n/**\n * Index documents in a background worker thread.\n * Falls back to direct indexing if worker fails to spawn.\n */\nexport async function createIndex(\n documents: Document[],\n config: IndexConfig & { removeIds?: string[] },\n): Promise<void> {\n // Dynamic import justified: search/searchSnippets shouldn't pull in worker_threads\n const { createIndexInWorker } = await import('./pool.ts')\n return createIndexInWorker(documents, config)\n}\n\n/**\n * List all raw document IDs in an existing index.\n * Returns chunk IDs (e.g. \"doc-id#chunk-0\") for chunked docs.\n * Queries sqlite directly to bypass createRetriv's parent-ID deduplication,\n * so callers can use these IDs for exact removal and parent-ID grouping.\n */\nexport async function listIndexIds(\n config: Pick<IndexConfig, 'dbPath'>,\n): Promise<string[]> {\n const nodeSqlite = globalThis.process?.getBuiltinModule?.('node:sqlite') as typeof import('node:sqlite') | undefined\n if (!nodeSqlite)\n return []\n const db = new nodeSqlite.DatabaseSync(config.dbPath, { open: true, readOnly: true })\n try {\n const rows = db.prepare('SELECT id FROM documents_meta').all() as Array<{ id: string }>\n return rows.map(r => r.id)\n }\n finally {\n db.close()\n }\n}\n\nexport async function search(\n query: string,\n config: IndexConfig,\n options: SearchOptions = {},\n): Promise<SearchResult[]> {\n const { limit = 10, filter } = options\n const db = await getDb(config)\n const results = await db.search(query, { limit, filter, returnContent: true, returnMetadata: true, returnMeta: true })\n await db.close?.()\n\n return results.map(r => ({\n id: r.id,\n content: r.content ?? '',\n score: r.score,\n metadata: r.metadata ?? {},\n highlights: r._meta?.highlights ?? [],\n lineRange: r._chunk?.lineRange,\n entities: r._chunk?.entities,\n scope: r._chunk?.scope,\n }))\n}\n\n/**\n * Search and return formatted snippets\n */\nexport async function searchSnippets(\n query: string,\n config: IndexConfig,\n options: SearchOptions = {},\n): Promise<SearchSnippet[]> {\n const results = await search(query, config, options)\n return toSnippets(results)\n}\n\nfunction toSnippets(results: SearchResult[]): SearchSnippet[] {\n return results.map((r) => {\n const content = stripFrontmatter(r.content)\n const source = r.metadata.source || r.id\n const lines = content.split('\\n').length\n\n return {\n package: r.metadata.package || 'unknown',\n source,\n lineStart: r.lineRange?.[0] ?? 1,\n lineEnd: r.lineRange?.[1] ?? lines,\n content,\n score: r.score,\n highlights: r.highlights,\n entities: r.entities,\n scope: r.scope,\n }\n })\n}\n\n// ── Pooled DB access for interactive search ──\n\nexport async function openPool(dbPaths: string[]): Promise<Map<string, RetrivInstance>> {\n const pool = new Map<string, RetrivInstance>()\n await Promise.all(dbPaths.map(async (dbPath) => {\n const db = await getDb({ dbPath })\n pool.set(dbPath, db)\n }))\n return pool\n}\n\nexport async function searchPooled(\n query: string,\n pool: Map<string, RetrivInstance>,\n options: SearchOptions = {},\n): Promise<SearchSnippet[]> {\n const { limit = 10, filter } = options\n const fetchLimit = limit * 2 // Over-fetch to compensate for dedup\n const allResults = await Promise.all(\n Array.from(pool.values(), async (db) => {\n const results = await db.search(query, { limit: fetchLimit, filter, returnContent: true, returnMetadata: true, returnMeta: true })\n return results.map(r => ({\n id: r.id,\n content: r.content ?? '',\n score: r.score,\n metadata: r.metadata ?? {},\n highlights: r._meta?.highlights ?? [],\n lineRange: r._chunk?.lineRange as [number, number] | undefined,\n entities: r._chunk?.entities,\n scope: r._chunk?.scope,\n }))\n }),\n )\n // Deduplicate by source+lineRange (overlapping chunks from same doc)\n const seen = new Set<string>()\n const merged = allResults.flat()\n .sort((a, b) => b.score - a.score)\n .filter((r) => {\n const lr = r.lineRange\n const key = `${r.metadata.source || r.id}:${lr?.[0]}-${lr?.[1]}`\n if (seen.has(key))\n return false\n seen.add(key)\n return true\n })\n .slice(0, limit)\n return toSnippets(merged)\n}\n\nexport async function closePool(pool: Map<string, RetrivInstance>): Promise<void> {\n await Promise.all(Array.from(pool.values(), db => db.close?.()))\n pool.clear()\n}\n"],"mappings":"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"}