chub-dev 0.2.0-beta.2 → 0.2.0-beta.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/dist/registry.json +1 -1
- package/package.json +1 -1
- package/src/commands/get.js +18 -37
- package/src/index.js +10 -11
package/dist/registry.json
CHANGED
package/package.json
CHANGED
package/src/commands/get.js
CHANGED
|
@@ -7,17 +7,14 @@ import { output, error, info } from '../lib/output.js';
|
|
|
7
7
|
import { trackEvent } from '../lib/analytics.js';
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
|
-
*
|
|
11
|
-
* @param {string} type - "doc" or "skill"
|
|
12
|
-
* @param {string[]} ids - one or more entry ids
|
|
13
|
-
* @param {object} opts - command options (lang, version, output, full)
|
|
14
|
-
* @param {object} globalOpts - global options (json)
|
|
10
|
+
* Fetch one or more entries by ID. Auto-detects doc vs skill per entry.
|
|
15
11
|
*/
|
|
16
|
-
async function fetchEntries(
|
|
12
|
+
async function fetchEntries(ids, opts, globalOpts) {
|
|
17
13
|
const results = [];
|
|
18
14
|
|
|
19
15
|
for (const id of ids) {
|
|
20
|
-
|
|
16
|
+
// Search both docs and skills — auto-detect type
|
|
17
|
+
const result = getEntry(id);
|
|
21
18
|
|
|
22
19
|
if (result.ambiguous) {
|
|
23
20
|
error(
|
|
@@ -27,10 +24,11 @@ async function fetchEntries(type, ids, opts, globalOpts) {
|
|
|
27
24
|
}
|
|
28
25
|
|
|
29
26
|
if (!result.entry) {
|
|
30
|
-
error(`Entry "${id}" not found
|
|
27
|
+
error(`Entry "${id}" not found.`, globalOpts);
|
|
31
28
|
}
|
|
32
29
|
|
|
33
30
|
const entry = result.entry;
|
|
31
|
+
const type = entry.languages ? 'doc' : 'skill';
|
|
34
32
|
const resolved = resolveDocPath(entry, opts.lang, opts.version);
|
|
35
33
|
|
|
36
34
|
if (!resolved) {
|
|
@@ -52,10 +50,10 @@ async function fetchEntries(type, ids, opts, globalOpts) {
|
|
|
52
50
|
try {
|
|
53
51
|
if (opts.full && resolved.files.length > 0) {
|
|
54
52
|
const allFiles = await fetchDocFull(resolved.source, resolved.path, resolved.files);
|
|
55
|
-
results.push({ id: entry.id, files: allFiles, path: resolved.path });
|
|
53
|
+
results.push({ id: entry.id, type, files: allFiles, path: resolved.path });
|
|
56
54
|
} else {
|
|
57
55
|
const content = await fetchDoc(resolved.source, entryFile.filePath);
|
|
58
|
-
results.push({ id: entry.id, content, path: entryFile.filePath });
|
|
56
|
+
results.push({ id: entry.id, type, content, path: entryFile.filePath });
|
|
59
57
|
}
|
|
60
58
|
} catch (err) {
|
|
61
59
|
error(err.message, globalOpts);
|
|
@@ -64,7 +62,7 @@ async function fetchEntries(type, ids, opts, globalOpts) {
|
|
|
64
62
|
|
|
65
63
|
// Track fetches
|
|
66
64
|
for (const r of results) {
|
|
67
|
-
trackEvent(type === 'doc' ? 'doc_fetched' : 'skill_fetched', {
|
|
65
|
+
trackEvent(r.type === 'doc' ? 'doc_fetched' : 'skill_fetched', {
|
|
68
66
|
entry_id: r.id,
|
|
69
67
|
full: !!opts.full,
|
|
70
68
|
lang: opts.lang || undefined,
|
|
@@ -74,7 +72,6 @@ async function fetchEntries(type, ids, opts, globalOpts) {
|
|
|
74
72
|
// Output
|
|
75
73
|
if (opts.output) {
|
|
76
74
|
if (opts.full) {
|
|
77
|
-
// --full -o: write individual files preserving directory structure
|
|
78
75
|
for (const r of results) {
|
|
79
76
|
if (r.files) {
|
|
80
77
|
const baseDir = ids.length > 1 ? join(opts.output, r.id) : opts.output;
|
|
@@ -111,18 +108,16 @@ async function fetchEntries(type, ids, opts, globalOpts) {
|
|
|
111
108
|
}
|
|
112
109
|
}
|
|
113
110
|
if (globalOpts.json) {
|
|
114
|
-
console.log(JSON.stringify(results.map((r) => ({ id: r.id, path: opts.output }))));
|
|
111
|
+
console.log(JSON.stringify(results.map((r) => ({ id: r.id, type: r.type, path: opts.output }))));
|
|
115
112
|
}
|
|
116
113
|
} else {
|
|
117
|
-
// stdout
|
|
118
114
|
if (results.length === 1 && !results[0].files) {
|
|
119
115
|
output(
|
|
120
|
-
{ id: results[0].id, content: results[0].content, path: results[0].path },
|
|
116
|
+
{ id: results[0].id, type: results[0].type, content: results[0].content, path: results[0].path },
|
|
121
117
|
(data) => process.stdout.write(data.content),
|
|
122
118
|
globalOpts
|
|
123
119
|
);
|
|
124
120
|
} else {
|
|
125
|
-
// Concatenate all content (--full to stdout, or multiple entries)
|
|
126
121
|
const parts = results.flatMap((r) => {
|
|
127
122
|
if (r.files) {
|
|
128
123
|
return r.files.map((f) => `# FILE: ${f.name}\n\n${f.content}`);
|
|
@@ -131,7 +126,7 @@ async function fetchEntries(type, ids, opts, globalOpts) {
|
|
|
131
126
|
});
|
|
132
127
|
const combined = parts.join('\n\n---\n\n');
|
|
133
128
|
output(
|
|
134
|
-
results.map((r) => ({ id: r.id, path: r.path })),
|
|
129
|
+
results.map((r) => ({ id: r.id, type: r.type, path: r.path })),
|
|
135
130
|
() => process.stdout.write(combined),
|
|
136
131
|
globalOpts
|
|
137
132
|
);
|
|
@@ -140,29 +135,15 @@ async function fetchEntries(type, ids, opts, globalOpts) {
|
|
|
140
135
|
}
|
|
141
136
|
|
|
142
137
|
export function registerGetCommand(program) {
|
|
143
|
-
|
|
144
|
-
.command('get')
|
|
145
|
-
.description('
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
.command('docs <ids...>')
|
|
149
|
-
.description('Fetch documentation content')
|
|
150
|
-
.option('--lang <language>', 'Language variant')
|
|
151
|
-
.option('--version <version>', 'Specific version')
|
|
152
|
-
.option('-o, --output <path>', 'Write to file or directory')
|
|
153
|
-
.option('--full', 'Fetch all files (not just entry point)')
|
|
154
|
-
.action(async (ids, opts) => {
|
|
155
|
-
const globalOpts = program.optsWithGlobals();
|
|
156
|
-
await fetchEntries('doc', ids, opts, globalOpts);
|
|
157
|
-
});
|
|
158
|
-
|
|
159
|
-
get
|
|
160
|
-
.command('skills <ids...>')
|
|
161
|
-
.description('Fetch skill content')
|
|
138
|
+
program
|
|
139
|
+
.command('get <ids...>')
|
|
140
|
+
.description('Fetch docs or skills by ID (auto-detects type)')
|
|
141
|
+
.option('--lang <language>', 'Language variant (for docs)')
|
|
142
|
+
.option('--version <version>', 'Specific version (for docs)')
|
|
162
143
|
.option('-o, --output <path>', 'Write to file or directory')
|
|
163
144
|
.option('--full', 'Fetch all files (not just entry point)')
|
|
164
145
|
.action(async (ids, opts) => {
|
|
165
146
|
const globalOpts = program.optsWithGlobals();
|
|
166
|
-
await fetchEntries(
|
|
147
|
+
await fetchEntries(ids, opts, globalOpts);
|
|
167
148
|
});
|
|
168
149
|
}
|
package/src/index.js
CHANGED
|
@@ -26,17 +26,16 @@ ${chalk.bold.underline('Getting Started')}
|
|
|
26
26
|
${chalk.dim('$')} chub search ${chalk.dim('# list everything available')}
|
|
27
27
|
${chalk.dim('$')} chub search "stripe" ${chalk.dim('# fuzzy search')}
|
|
28
28
|
${chalk.dim('$')} chub search stripe/payments ${chalk.dim('# exact id → full detail')}
|
|
29
|
-
${chalk.dim('$')} chub get
|
|
30
|
-
${chalk.dim('$')} chub get
|
|
31
|
-
${chalk.dim('$')} chub get
|
|
32
|
-
${chalk.dim('$')} chub get
|
|
33
|
-
${chalk.dim('$')} chub get
|
|
29
|
+
${chalk.dim('$')} chub get stripe/api ${chalk.dim('# print doc to terminal')}
|
|
30
|
+
${chalk.dim('$')} chub get stripe/api -o doc.md ${chalk.dim('# save to file')}
|
|
31
|
+
${chalk.dim('$')} chub get openai/chat --lang py ${chalk.dim('# specific language')}
|
|
32
|
+
${chalk.dim('$')} chub get pw-community/login-flows ${chalk.dim('# fetch a skill')}
|
|
33
|
+
${chalk.dim('$')} chub get openai/chat stripe/api ${chalk.dim('# fetch multiple')}
|
|
34
34
|
|
|
35
35
|
${chalk.bold.underline('Commands')}
|
|
36
36
|
|
|
37
37
|
${chalk.bold('search')} [query] Search docs and skills (no query = list all)
|
|
38
|
-
${chalk.bold('get
|
|
39
|
-
${chalk.bold('get skills')} <ids...> Fetch skill content
|
|
38
|
+
${chalk.bold('get')} <ids...> Fetch docs or skills by ID
|
|
40
39
|
${chalk.bold('update')} Refresh the cached registry
|
|
41
40
|
${chalk.bold('cache')} status|clear Manage the local cache
|
|
42
41
|
${chalk.bold('build')} <content-dir> Build registry from content directory
|
|
@@ -56,10 +55,10 @@ ${chalk.bold.underline('Agent Piping Patterns')}
|
|
|
56
55
|
|
|
57
56
|
${chalk.dim('# Search → pick → fetch → save')}
|
|
58
57
|
${chalk.dim('$')} ID=$(chub search "stripe" --json | jq -r '.results[0].id')
|
|
59
|
-
${chalk.dim('$')} chub get
|
|
58
|
+
${chalk.dim('$')} chub get "$ID" --lang js -o .context/stripe.md
|
|
60
59
|
|
|
61
|
-
${chalk.dim('# Fetch multiple
|
|
62
|
-
${chalk.dim('$')} chub get
|
|
60
|
+
${chalk.dim('# Fetch multiple at once')}
|
|
61
|
+
${chalk.dim('$')} chub get openai/chat stripe/api -o .context/
|
|
63
62
|
|
|
64
63
|
${chalk.bold.underline('Multi-Source Config')} ${chalk.dim('(~/.chub/config.yaml)')}
|
|
65
64
|
|
|
@@ -69,7 +68,7 @@ ${chalk.bold.underline('Multi-Source Config')} ${chalk.dim('(~/.chub/config.yaml
|
|
|
69
68
|
${chalk.dim(' - name: internal')}
|
|
70
69
|
${chalk.dim(' path: /path/to/local/docs')}
|
|
71
70
|
|
|
72
|
-
${chalk.dim('# On id collision, use source: prefix: chub get
|
|
71
|
+
${chalk.dim('# On id collision, use source: prefix: chub get internal:openai/chat')}
|
|
73
72
|
`);
|
|
74
73
|
}
|
|
75
74
|
|