incur 0.4.2 → 0.4.4
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/Cli.d.ts.map +1 -1
- package/dist/Cli.js +19 -15
- package/dist/Cli.js.map +1 -1
- package/dist/Skill.d.ts.map +1 -1
- package/dist/Skill.js +4 -5
- package/dist/Skill.js.map +1 -1
- package/dist/SyncSkills.d.ts.map +1 -1
- package/dist/SyncSkills.js +22 -17
- package/dist/SyncSkills.js.map +1 -1
- package/dist/internal/command.d.ts +42 -0
- package/dist/internal/command.d.ts.map +1 -1
- package/dist/internal/command.js +5 -0
- package/dist/internal/command.js.map +1 -1
- package/package.json +1 -1
- package/src/Cli.test.ts +9 -0
- package/src/Cli.ts +20 -14
- package/src/Completions.test.ts +2 -0
- package/src/Skill.test.ts +8 -0
- package/src/Skill.ts +7 -5
- package/src/SyncSkills.test.ts +31 -0
- package/src/SyncSkills.ts +22 -18
- package/src/internal/command.ts +15 -2
package/src/SyncSkills.ts
CHANGED
|
@@ -2,6 +2,7 @@ import fsSync from 'node:fs'
|
|
|
2
2
|
import fs from 'node:fs/promises'
|
|
3
3
|
import os from 'node:os'
|
|
4
4
|
import path from 'node:path'
|
|
5
|
+
import { parse as yamlParse } from 'yaml'
|
|
5
6
|
|
|
6
7
|
import { formatExamples } from './Cli.js'
|
|
7
8
|
import * as Agents from './internal/agents.js'
|
|
@@ -30,9 +31,8 @@ export async function sync(
|
|
|
30
31
|
: path.join(tmpDir, 'SKILL.md')
|
|
31
32
|
await fs.mkdir(path.dirname(filePath), { recursive: true })
|
|
32
33
|
await fs.writeFile(filePath, `${file.content}\n`)
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
skills.push({ name: nameMatch?.[1] ?? (file.dir || name), description: descMatch?.[1] })
|
|
34
|
+
const meta = parseFrontmatter(file.content)
|
|
35
|
+
skills.push({ name: meta.name ?? (file.dir || name), description: meta.description })
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
// Include additional SKILL.md files matched by glob patterns
|
|
@@ -42,16 +42,14 @@ export async function sync(
|
|
|
42
42
|
for await (const match of fs.glob(globPattern, { cwd })) {
|
|
43
43
|
try {
|
|
44
44
|
const content = await fs.readFile(path.resolve(cwd, match), 'utf8')
|
|
45
|
-
const
|
|
45
|
+
const meta = parseFrontmatter(content)
|
|
46
46
|
const skillName =
|
|
47
|
-
pattern === '_root' ? (
|
|
47
|
+
pattern === '_root' ? (meta.name ?? name) : path.basename(path.dirname(match))
|
|
48
48
|
const dest = path.join(tmpDir, skillName, 'SKILL.md')
|
|
49
49
|
await fs.mkdir(path.dirname(dest), { recursive: true })
|
|
50
50
|
await fs.writeFile(dest, content)
|
|
51
|
-
if (!skills.some((s) => s.name === skillName))
|
|
52
|
-
|
|
53
|
-
skills.push({ name: skillName, description: descMatch?.[1], external: true })
|
|
54
|
-
}
|
|
51
|
+
if (!skills.some((s) => s.name === skillName))
|
|
52
|
+
skills.push({ name: skillName, description: meta.description, external: true })
|
|
55
53
|
} catch {}
|
|
56
54
|
}
|
|
57
55
|
}
|
|
@@ -148,12 +146,11 @@ export async function list(
|
|
|
148
146
|
const installed = readInstalledSkills(name, { cwd })
|
|
149
147
|
|
|
150
148
|
for (const file of files) {
|
|
151
|
-
const
|
|
152
|
-
const
|
|
153
|
-
const skillName = nameMatch?.[1] ?? (file.dir || name)
|
|
149
|
+
const meta = parseFrontmatter(file.content)
|
|
150
|
+
const skillName = meta.name ?? (file.dir || name)
|
|
154
151
|
skills.push({
|
|
155
152
|
name: skillName,
|
|
156
|
-
description:
|
|
153
|
+
description: meta.description,
|
|
157
154
|
installed: installed.has(skillName),
|
|
158
155
|
})
|
|
159
156
|
}
|
|
@@ -165,14 +162,12 @@ export async function list(
|
|
|
165
162
|
for await (const match of fs.glob(globPattern, { cwd })) {
|
|
166
163
|
try {
|
|
167
164
|
const content = await fs.readFile(path.resolve(cwd, match), 'utf8')
|
|
168
|
-
const
|
|
169
|
-
const skillName =
|
|
170
|
-
pattern === '_root' ? (nameMatch?.[1] ?? name) : path.basename(path.dirname(match))
|
|
165
|
+
const meta = parseFrontmatter(content)
|
|
166
|
+
const skillName = pattern === '_root' ? (meta.name ?? name) : path.basename(path.dirname(match))
|
|
171
167
|
if (!skills.some((s) => s.name === skillName)) {
|
|
172
|
-
const descMatch = content.match(/^description:\s*(.+)$/m)
|
|
173
168
|
skills.push({
|
|
174
169
|
name: skillName,
|
|
175
|
-
description:
|
|
170
|
+
description: meta.description,
|
|
176
171
|
installed: installed.has(skillName),
|
|
177
172
|
})
|
|
178
173
|
}
|
|
@@ -284,6 +279,15 @@ function collectEntries(
|
|
|
284
279
|
return result.sort((a, b) => (a.name ?? '').localeCompare(b.name ?? ''))
|
|
285
280
|
}
|
|
286
281
|
|
|
282
|
+
function parseFrontmatter(content: string): { description?: string | undefined; name?: string | undefined } {
|
|
283
|
+
const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---/)
|
|
284
|
+
if (!match) return {}
|
|
285
|
+
|
|
286
|
+
const meta = yamlParse(match[1]!)
|
|
287
|
+
if (!meta || typeof meta !== 'object') return {}
|
|
288
|
+
return meta as { description?: string | undefined; name?: string | undefined }
|
|
289
|
+
}
|
|
290
|
+
|
|
287
291
|
/** Resolves the package root from the executing bin script (`process.argv[1]`). Walks up from the bin's directory looking for `package.json`. Falls back to `process.cwd()`. */
|
|
288
292
|
function resolvePackageRoot(): string {
|
|
289
293
|
const bin = process.argv[1]
|
package/src/internal/command.ts
CHANGED
|
@@ -350,9 +350,16 @@ export type CommandMeta<options extends z.ZodObject<any> | undefined = undefined
|
|
|
350
350
|
options?: options | undefined
|
|
351
351
|
}
|
|
352
352
|
|
|
353
|
+
/** @internal Metadata for a built-in subcommand. */
|
|
354
|
+
type BuiltinSubcommandMeta<options extends z.ZodObject<any> | undefined = undefined> =
|
|
355
|
+
CommandMeta<options> & {
|
|
356
|
+
/** Alternative names for this built-in subcommand. */
|
|
357
|
+
aliases?: string[] | undefined
|
|
358
|
+
}
|
|
359
|
+
|
|
353
360
|
/** @internal Creates a builtin subcommand with typesafe alias inference. */
|
|
354
361
|
function subcommand<const options extends z.ZodObject<any> | undefined = undefined>(
|
|
355
|
-
def:
|
|
362
|
+
def: BuiltinSubcommandMeta<options> & { name: string },
|
|
356
363
|
) {
|
|
357
364
|
return def
|
|
358
365
|
}
|
|
@@ -425,6 +432,7 @@ export const builtinCommands = [
|
|
|
425
432
|
}),
|
|
426
433
|
subcommand({
|
|
427
434
|
name: 'list',
|
|
435
|
+
aliases: ['ls'],
|
|
428
436
|
description: 'List skills',
|
|
429
437
|
}),
|
|
430
438
|
],
|
|
@@ -435,7 +443,7 @@ export const builtinCommands = [
|
|
|
435
443
|
args?: z.ZodObject<any> | undefined
|
|
436
444
|
description: string
|
|
437
445
|
hint?: ((name: string) => string) | undefined
|
|
438
|
-
subcommands?: (
|
|
446
|
+
subcommands?: (BuiltinSubcommandMeta<z.ZodObject<any>> & { name: string })[] | undefined
|
|
439
447
|
}[]
|
|
440
448
|
|
|
441
449
|
/** @internal Finds a builtin command by its name or alias. */
|
|
@@ -443,6 +451,11 @@ export function findBuiltin(token: string) {
|
|
|
443
451
|
return builtinCommands.find((b) => b.name === token || b.aliases?.includes(token))
|
|
444
452
|
}
|
|
445
453
|
|
|
454
|
+
/** @internal Finds a builtin subcommand by its name or alias. */
|
|
455
|
+
export function findBuiltinSubcommand(builtin: (typeof builtinCommands)[number], token: string) {
|
|
456
|
+
return builtin.subcommands?.find((sub) => sub.name === token || sub.aliases?.includes(token))
|
|
457
|
+
}
|
|
458
|
+
|
|
446
459
|
/** @internal Checks if a token matches a builtin command by name or alias. */
|
|
447
460
|
export function isBuiltin(token: string) {
|
|
448
461
|
return builtinCommands.some((b) => b.name === token || b.aliases?.includes(token))
|