mdpush 1.3.0 → 1.3.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mdpush",
3
- "version": "1.3.0",
3
+ "version": "1.3.1",
4
4
  "type": "module",
5
5
  "engines": {
6
6
  "node": ">=20.0.0"
@@ -147,12 +147,59 @@ async function installOneSkill(slug, options) {
147
147
  if (failed) throw new Error(`${failed} file(s) failed`)
148
148
  }
149
149
 
150
- /** List published skills. */
151
- export async function skillListCommand() {
150
+ /** Fetch + print the catalog table. Returns the skills array (or []). */
151
+ async function printCatalog({ numbered = false } = {}) {
152
152
  const res = await apiRequest('/api/skills')
153
153
  const skills = await res.json()
154
- if (skills.length === 0) return console.log(chalk.yellow('No skills published.'))
155
- for (const s of skills) {
156
- console.log(`${chalk.cyan(s.slug.padEnd(24))} ${s.description || chalk.gray('(no description)')}`)
154
+ if (skills.length === 0) {
155
+ console.log(chalk.yellow('No skills published.'))
156
+ return []
157
+ }
158
+ skills.forEach((s, i) => {
159
+ const idx = numbered ? chalk.gray(`${String(i + 1).padStart(3)}. `) : ''
160
+ const cat = (s.category || '—').padEnd(10)
161
+ const installs = String(s.installCount ?? 0).padStart(4)
162
+ const desc = (s.description || '(no description)').slice(0, 80)
163
+ console.log(`${idx}${chalk.cyan(s.slug.padEnd(24))} ${chalk.magenta(cat)} ${chalk.gray(`⤓${installs}`)} ${desc}`)
164
+ })
165
+ return skills
166
+ }
167
+
168
+ /** List published skills (slug · category · installs · description). */
169
+ export async function skillListCommand() {
170
+ await printCatalog()
171
+ }
172
+
173
+ /**
174
+ * Interactive browse (`mdpush skill` with no subcommand) — numbered catalog,
175
+ * pick by number/comma list, installs the selection. Zero-dependency prompt
176
+ * via node:readline; falls back to plain list when stdin isn't a TTY.
177
+ */
178
+ export async function skillBrowseCommand() {
179
+ const skills = await printCatalog({ numbered: true })
180
+ if (skills.length === 0 || !process.stdin.isTTY) return
181
+
182
+ const readline = await import('node:readline/promises')
183
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout })
184
+ // Race against 'close' — an EOF on stdin (Ctrl-D, piped input running dry)
185
+ // would otherwise leave the question promise pending forever.
186
+ const answer = (await Promise.race([
187
+ rl.question(chalk.blue('\nInstall which? (numbers, comma-separated — empty to exit): ')),
188
+ new Promise(resolve => rl.once('close', () => resolve('')))
189
+ ])).trim()
190
+ rl.close()
191
+ // A TTY stdin touched by readline keeps the event loop alive after close —
192
+ // exit explicitly on every path (install failures already exit(1) upstream).
193
+ if (!answer) process.exit(0)
194
+
195
+ const picks = [...new Set(answer.split(/[\s,]+/))]
196
+ .map(n => skills[parseInt(n, 10) - 1])
197
+ .filter(Boolean)
198
+ .map(s => s.slug)
199
+ if (picks.length === 0) {
200
+ console.log(chalk.yellow('No valid selection.'))
201
+ process.exit(2)
157
202
  }
203
+ await skillInstallCommand(picks, {})
204
+ process.exit(0)
158
205
  }
package/src/index.js CHANGED
@@ -1,14 +1,18 @@
1
+ import { createRequire } from 'module'
1
2
  import { program } from 'commander'
3
+
4
+ // Single-source the CLI version from package.json (was hardcoded and stale)
5
+ const pkg = createRequire(import.meta.url)('../package.json')
2
6
  import { loginCommand } from './commands/login-command.js'
3
7
  import { pushCommand } from './commands/push-command.js'
4
8
  import { configCommand } from './commands/config-command.js'
5
9
  import { logoutCommand } from './commands/logout-command.js'
6
- import { skillPushCommand, skillInstallCommand, skillListCommand } from './commands/skill-command.js'
10
+ import { skillPushCommand, skillInstallCommand, skillListCommand, skillBrowseCommand } from './commands/skill-command.js'
7
11
 
8
12
  program
9
13
  .name('mdpush')
10
14
  .description('Push markdown, text, and HTML artifact files to sielay')
11
- .version('1.1.0')
15
+ .version(pkg.version)
12
16
 
13
17
  program.command('login')
14
18
  .description('Authenticate with server')
@@ -25,6 +29,7 @@ program.command('push')
25
29
 
26
30
  const skill = program.command('skill')
27
31
  .description('Publish and install Claude Code skill bundles (projects with kind=skill)')
32
+ .action(skillBrowseCommand) // bare `mdpush skill` → interactive browse
28
33
 
29
34
  skill.command('push')
30
35
  .description('Push a skill directory (must contain SKILL.md) to the server')