@kb-labs/scaffold 2.94.0 → 2.98.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.
- package/README.md +5 -0
- package/dist/commands/doctor.js +13 -4
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/scaffold.js +12 -10
- package/dist/commands/scaffold.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +4 -8
- package/dist/index.js.map +1 -1
- package/dist/manifest.d.ts +6 -10
- package/dist/manifest.js +4 -8
- package/dist/manifest.js.map +1 -1
- package/package.json +10 -8
- package/templates/plugin/blocks/base/files/README.md.eta +134 -24
- package/templates/plugin/blocks/base/files/packages/__name__-entry/src/commands/hello.ts.eta +26 -11
- package/templates/plugin/blocks/base/files/packages/__name__-entry/src/utils/error.ts.eta +63 -0
- package/templates/plugin/blocks/base/manifest.patch.yaml +1 -3
- package/templates/plugin/blocks/cli/files/packages/__name__-entry/src/commands/ping.ts.eta +14 -6
- package/templates/plugin/blocks/cli/manifest.patch.yaml +1 -3
package/README.md
ADDED
package/dist/commands/doctor.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { resolve } from 'path';
|
|
2
|
-
import { defineCommand } from '@kb-labs/sdk';
|
|
2
|
+
import { defineCommand, handleError } from '@kb-labs/sdk';
|
|
3
3
|
import { scanRoot } from '@kb-labs/scaffold-core';
|
|
4
4
|
|
|
5
5
|
// src/commands/doctor.ts
|
|
@@ -10,11 +10,20 @@ var doctor_default = defineCommand({
|
|
|
10
10
|
async execute(ctx, input) {
|
|
11
11
|
const root = resolve(input.path ?? ".kb/plugins");
|
|
12
12
|
const workspaceRoot = ctx.cwd ?? process.cwd();
|
|
13
|
-
|
|
13
|
+
let scan;
|
|
14
|
+
try {
|
|
15
|
+
scan = await scanRoot(root, { workspaceRoot });
|
|
16
|
+
} catch (err) {
|
|
17
|
+
handleError(ctx, err, input.json);
|
|
18
|
+
return { exitCode: 1 };
|
|
19
|
+
}
|
|
14
20
|
const { errorCount, warnCount } = scan.findings.reduce(
|
|
15
21
|
(acc, f) => {
|
|
16
|
-
if (f.severity === "error")
|
|
17
|
-
|
|
22
|
+
if (f.severity === "error") {
|
|
23
|
+
acc.errorCount++;
|
|
24
|
+
} else if (f.severity === "warn") {
|
|
25
|
+
acc.warnCount++;
|
|
26
|
+
}
|
|
18
27
|
return acc;
|
|
19
28
|
},
|
|
20
29
|
{ errorCount: 0, warnCount: 0 }
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/commands/doctor.ts"],"names":[],"mappings":";;;;;AAiBA,IAAO,iBAAQ,aAAA,CAAc;AAAA,EAC3B,EAAA,EAAI,iBAAA;AAAA,EACJ,WAAA,EAAa,8CAAA;AAAA,EAEb,OAAA,EAAS;AAAA,IACP,MAAM,OAAA,CACJ,GAAA,EACA,KAAA,EACuB;AACvB,MAAA,MAAM,IAAA,GAAO,OAAA,CAAQ,KAAA,CAAM,IAAA,IAAQ,aAAa,CAAA;AAChD,MAAA,MAAM,aAAA,GAAgB,GAAA,CAAI,GAAA,IAAO,OAAA,CAAQ,GAAA,EAAI;AAC7C,MAAA,
|
|
1
|
+
{"version":3,"sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"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","file":"doctor.js","sourcesContent":["import { resolve } from 'node:path';\nimport { defineCommand, handleError, type PluginContextV3 } from '@kb-labs/sdk';\nimport { scanRoot, type Finding } from '@kb-labs/scaffold-core';\n\ninterface DoctorFlags {\n path?: string;\n json?: boolean;\n}\n\ntype DoctorResult = {\n exitCode: number;\n result?: {\n packagesScanned: number;\n findings: Finding[];\n };\n};\n\nexport default defineCommand({\n id: 'scaffold:doctor',\n description: 'Scan user-authored plugins for common issues',\n\n handler: {\n async execute(\n ctx: PluginContextV3,\n input: DoctorFlags,\n ): Promise<DoctorResult> {\n const root = resolve(input.path ?? '.kb/plugins');\n const workspaceRoot = ctx.cwd ?? process.cwd();\n let scan: Awaited<ReturnType<typeof scanRoot>>;\n try {\n scan = await scanRoot(root, { workspaceRoot });\n } catch (err) {\n handleError(ctx, err, input.json);\n return { exitCode: 1 };\n }\n\n const { errorCount, warnCount } = scan.findings.reduce(\n (acc, f) => {\n if (f.severity === 'error') { acc.errorCount++; }\n else if (f.severity === 'warn') { acc.warnCount++; }\n return acc;\n },\n { errorCount: 0, warnCount: 0 },\n );\n const hasErrors = errorCount > 0;\n\n if (input.json) {\n ctx.ui?.json?.({\n root,\n packagesScanned: scan.packagesScanned,\n findings: scan.findings,\n });\n } else if (scan.findings.length === 0) {\n ctx.ui?.success?.(`Scanned ${scan.packagesScanned} package(s) — no issues found.`, {\n title: 'scaffold doctor',\n sections: [\n { items: [`Path: ${root}`] },\n ],\n });\n } else {\n const byPkg = new Map<string, Finding[]>();\n for (const f of scan.findings) {\n const list = byPkg.get(f.package) ?? [];\n list.push(f);\n byPkg.set(f.package, list);\n }\n\n const sections = Array.from(byPkg.entries()).map(([pkg, findings]) => ({\n header: pkg,\n items: findings.map((f) => `${f.severity.toUpperCase()} ${f.message}`),\n }));\n\n if (hasErrors) {\n ctx.ui?.error?.(`Found ${errorCount} error(s), ${warnCount} warning(s) in ${scan.packagesScanned} package(s).`, {\n title: 'scaffold doctor',\n sections,\n });\n } else {\n ctx.ui?.warn?.(`Found ${warnCount} warning(s) in ${scan.packagesScanned} package(s).`, {\n title: 'scaffold doctor',\n sections,\n });\n }\n }\n\n return {\n exitCode: hasErrors ? 1 : 0,\n result: {\n packagesScanned: scan.packagesScanned,\n findings: scan.findings,\n },\n };\n },\n },\n});\n"]}
|
|
@@ -3,7 +3,7 @@ import { fileURLToPath } from 'url';
|
|
|
3
3
|
import { createRequire } from 'module';
|
|
4
4
|
import { readFile, mkdir, writeFile } from 'fs/promises';
|
|
5
5
|
import { createHash } from 'crypto';
|
|
6
|
-
import { defineCommand } from '@kb-labs/sdk';
|
|
6
|
+
import { defineCommand, validationError, handleError } from '@kb-labs/sdk';
|
|
7
7
|
import { listEntities, runValidator, loadEntity, resolveBlocks, build, inspectTarget, formatTree, writeFiles } from '@kb-labs/scaffold-core';
|
|
8
8
|
import { formatCommandHelp } from '@kb-labs/shared-cli-ui';
|
|
9
9
|
|
|
@@ -50,7 +50,9 @@ async function detectVersions() {
|
|
|
50
50
|
return { sdk, devkit, commandKit };
|
|
51
51
|
}
|
|
52
52
|
function parsePositional(argv) {
|
|
53
|
-
if (!argv || argv.length === 0)
|
|
53
|
+
if (!argv || argv.length === 0) {
|
|
54
|
+
return {};
|
|
55
|
+
}
|
|
54
56
|
const positional = argv.filter((a) => !a.startsWith("-"));
|
|
55
57
|
return { entity: positional[0], name: positional[1] };
|
|
56
58
|
}
|
|
@@ -60,7 +62,7 @@ async function runDefault(ctx, rawInput) {
|
|
|
60
62
|
const { entity: entityArg, name: nameArg } = parsePositional(input.argv);
|
|
61
63
|
const available = await listEntities(TEMPLATES_ROOT);
|
|
62
64
|
if (available.length === 0) {
|
|
63
|
-
ctx
|
|
65
|
+
validationError(ctx, "No scaffold templates found. Reinstall @kb-labs/scaffold.");
|
|
64
66
|
return { exitCode: 1 };
|
|
65
67
|
}
|
|
66
68
|
if (!entityArg) {
|
|
@@ -74,7 +76,7 @@ async function runDefault(ctx, rawInput) {
|
|
|
74
76
|
return { exitCode: 1 };
|
|
75
77
|
}
|
|
76
78
|
if (!available.includes(entityArg)) {
|
|
77
|
-
ctx
|
|
79
|
+
validationError(ctx, `Unknown entity "${entityArg}". Available: ${available.join(", ")}`);
|
|
78
80
|
return { exitCode: 1 };
|
|
79
81
|
}
|
|
80
82
|
if (!nameArg) {
|
|
@@ -88,8 +90,7 @@ async function runDefault(ctx, rawInput) {
|
|
|
88
90
|
}
|
|
89
91
|
const problem = runValidator("npmName", nameArg);
|
|
90
92
|
if (problem) {
|
|
91
|
-
ctx
|
|
92
|
-
ctx.ui?.info?.("Name must be lowercase, no spaces, valid npm package name.");
|
|
93
|
+
validationError(ctx, `Invalid name "${nameArg}": ${problem}`, "Name must be lowercase, no spaces, valid npm package name.");
|
|
93
94
|
return { exitCode: 1 };
|
|
94
95
|
}
|
|
95
96
|
const entity = await loadEntity(TEMPLATES_ROOT, entityArg);
|
|
@@ -112,7 +113,7 @@ async function runDefault(ctx, rawInput) {
|
|
|
112
113
|
try {
|
|
113
114
|
resolveBlocks(entity.blocks, selectedBlocks);
|
|
114
115
|
} catch (e) {
|
|
115
|
-
ctx
|
|
116
|
+
handleError(ctx, e);
|
|
116
117
|
return { exitCode: 1 };
|
|
117
118
|
}
|
|
118
119
|
for (const blockId of selectedBlocks) {
|
|
@@ -153,8 +154,7 @@ async function runDefault(ctx, rawInput) {
|
|
|
153
154
|
if (input.force) {
|
|
154
155
|
ctx.ui?.warn?.(`--force: overwriting ${outRoot}`);
|
|
155
156
|
} else {
|
|
156
|
-
ctx
|
|
157
|
-
ctx.ui?.info?.("Use --force to overwrite.");
|
|
157
|
+
validationError(ctx, `Output directory "${outRoot}" already exists and is not empty.`, "Use --force to overwrite.");
|
|
158
158
|
return { exitCode: 1 };
|
|
159
159
|
}
|
|
160
160
|
}
|
|
@@ -204,7 +204,9 @@ async function linkWithMarketplace(entryPkgDir, projectRoot) {
|
|
|
204
204
|
const pkgJsonPath = resolve(entryPkgDir, "package.json");
|
|
205
205
|
const pkgRaw = await readFile(pkgJsonPath, "utf8");
|
|
206
206
|
const pkg = JSON.parse(pkgRaw);
|
|
207
|
-
if (!pkg.name)
|
|
207
|
+
if (!pkg.name) {
|
|
208
|
+
return "failed";
|
|
209
|
+
}
|
|
208
210
|
const hash = createHash("sha256").update(pkgRaw).digest("base64");
|
|
209
211
|
const provides = ["plugin", "cli-command"];
|
|
210
212
|
const resolvedPath = relative(projectRoot, resolve(entryPkgDir));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/commands/scaffold.ts"],"names":[],"mappings":"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","file":"scaffold.js","sourcesContent":["import { dirname, resolve, relative } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { createRequire } from 'node:module';\nimport { readFile, writeFile, mkdir } from 'node:fs/promises';\nimport { createHash } from 'node:crypto';\nimport {\n defineCommand,\n type PluginContextV3,\n type CLIInput,\n} from '@kb-labs/sdk';\nimport {\n build,\n inspectTarget,\n formatTree,\n listEntities,\n loadEntity,\n resolveBlocks,\n runValidator,\n writeFiles,\n} from '@kb-labs/scaffold-core';\nimport type {\n RenderContext,\n} from '@kb-labs/scaffold-contracts';\nimport { formatCommandHelp } from '@kb-labs/shared-cli-ui';\n\nconst here = dirname(fileURLToPath(import.meta.url));\nconst TEMPLATES_ROOT = resolve(here, '..', '..', 'templates');\n\nconst SCAFFOLD_FLAGS = [\n { name: 'scope', description: 'npm scope, e.g. @my-org' },\n { name: 'blocks', description: 'comma-separated block ids to include' },\n { name: 'out', description: 'custom output directory' },\n { name: 'force', description: 'overwrite existing output directory' },\n { name: 'dry-run', description: 'preview files without writing' },\n];\n\ninterface ScaffoldFlags {\n blocks?: string;\n force?: boolean;\n 'dry-run'?: boolean;\n out?: string;\n scope?: string;\n mode?: string;\n}\n\ntype ScaffoldResult = {\n exitCode: number;\n result?: { outRoot: string; files: number };\n};\n\nasync function readVersion(pkgPath: string): Promise<string> {\n try {\n const raw = await readFile(pkgPath, 'utf8');\n const parsed = JSON.parse(raw) as { version?: string };\n return parsed.version ?? '0.0.0';\n } catch {\n return '0.0.0';\n }\n}\n\nconst FALLBACK_VERSIONS = {\n sdk: '2.18.0',\n devkit: '2.28.0',\n commandKit: '2.30.0',\n} as const;\n\nasync function detectVersions(): Promise<Record<string, string>> {\n const req = createRequire(import.meta.url);\n const readPkg = async (spec: string, fallback: string): Promise<string> => {\n try {\n const resolved = req.resolve(spec);\n const v = await readVersion(resolved);\n return v === '0.0.0' ? fallback : v;\n } catch {\n return fallback;\n }\n };\n const [sdk, devkit, commandKit] = await Promise.all([\n readPkg('@kb-labs/sdk/package.json', FALLBACK_VERSIONS.sdk),\n readPkg('@kb-labs/devkit/package.json', FALLBACK_VERSIONS.devkit),\n readPkg('@kb-labs/shared-command-kit/package.json', FALLBACK_VERSIONS.commandKit),\n ]);\n return { sdk, devkit, commandKit };\n}\n\nfunction parsePositional(argv: string[] | undefined): {\n entity?: string;\n name?: string;\n} {\n if (!argv || argv.length === 0) return {};\n const positional = argv.filter((a) => !a.startsWith('-'));\n return { entity: positional[0], name: positional[1] };\n}\n\nasync function runDefault(\n ctx: PluginContextV3,\n rawInput: CLIInput<ScaffoldFlags>,\n): Promise<ScaffoldResult> {\n const start = Date.now();\n const input = { ...rawInput.flags, argv: rawInput.argv };\n\n const { entity: entityArg, name: nameArg } = parsePositional(input.argv);\n\n const available = await listEntities(TEMPLATES_ROOT);\n if (available.length === 0) {\n ctx.ui?.error?.('No scaffold templates found. Reinstall @kb-labs/scaffold.');\n return { exitCode: 1 };\n }\n\n if (!entityArg) {\n ctx.ui?.write?.(formatCommandHelp({\n title: 'kb scaffold run',\n description: 'Scaffold a new plugin, adapter, or other entity from a template.',\n examples: available.map((e) => `kb scaffold run ${e} my-${e}`),\n flags: SCAFFOLD_FLAGS,\n }) + '\\n');\n ctx.ui?.info?.(`Available entities: ${available.join(', ')}`);\n return { exitCode: 1 };\n }\n\n if (!available.includes(entityArg)) {\n ctx.ui?.error?.(`Unknown entity \"${entityArg}\". Available: ${available.join(', ')}`);\n return { exitCode: 1 };\n }\n\n if (!nameArg) {\n ctx.ui?.write?.(formatCommandHelp({\n title: `kb scaffold run ${entityArg} <name>`,\n description: `Scaffold a new ${entityArg}. Provide a name to continue.`,\n examples: [`kb scaffold run ${entityArg} my-${entityArg}`],\n flags: SCAFFOLD_FLAGS,\n }) + '\\n');\n return { exitCode: 1 };\n }\n\n const problem = runValidator('npmName', nameArg);\n if (problem) {\n ctx.ui?.error?.(`Invalid name \"${nameArg}\": ${problem}`);\n ctx.ui?.info?.('Name must be lowercase, no spaces, valid npm package name.');\n return { exitCode: 1 };\n }\n\n const entity = await loadEntity(TEMPLATES_ROOT, entityArg);\n\n const vars: Record<string, unknown> = {};\n for (const v of entity.variables) {\n if (v.name === 'scope' && input.scope !== undefined) {\n vars[v.name] = input.scope;\n } else if (v.name === 'mode' && input.mode !== undefined) {\n vars[v.name] = input.mode;\n } else {\n vars[v.name] = v.default ?? '';\n }\n }\n\n let selectedBlocks: string[];\n if (input.blocks) {\n selectedBlocks = input.blocks\n .split(',')\n .map((s) => s.trim())\n .filter(Boolean);\n } else {\n selectedBlocks = entity.defaults?.blocks ?? entity.blocks.map((b) => b.id);\n }\n\n try {\n resolveBlocks(entity.blocks, selectedBlocks);\n } catch (e) {\n ctx.ui?.error?.((e as Error).message);\n return { exitCode: 1 };\n }\n\n for (const blockId of selectedBlocks) {\n const block = entity.blocks.find((b) => b.id === blockId);\n for (const v of block?.variables ?? []) {\n vars[v.name] = v.default ?? '';\n }\n }\n\n const scope = (vars.scope as string) ?? input.scope ?? '';\n const mode = (input.mode ?? (vars.mode as string) ?? 'in-workspace') as\n | 'in-workspace'\n | 'standalone';\n\n const versions = await detectVersions();\n\n const context: RenderContext = {\n name: nameArg,\n scope,\n vars,\n blocks: selectedBlocks,\n mode,\n versions,\n };\n\n const result = await build({\n entity,\n selectedBlockIds: selectedBlocks,\n context,\n });\n\n const outRoot = input.out ?? result.outRoot;\n const state = await inspectTarget(outRoot);\n\n if (input['dry-run']) {\n ctx.ui?.success?.('Dry run complete', {\n title: 'scaffold run — dry run',\n sections: [\n { header: 'Would write to', items: [outRoot] },\n { header: 'Files', items: formatTree(result.files).split('\\n').filter(Boolean) },\n ],\n });\n return { exitCode: 0, result: { outRoot, files: result.files.length } };\n }\n\n if (state.exists && !state.empty) {\n if (input.force) {\n ctx.ui?.warn?.(`--force: overwriting ${outRoot}`);\n } else {\n ctx.ui?.error?.(`Output directory \"${outRoot}\" already exists and is not empty.`);\n ctx.ui?.info?.('Use --force to overwrite.');\n return { exitCode: 1 };\n }\n }\n\n await writeFiles({ outRoot, files: result.files, force: input.force });\n\n const entryPkgDir =\n entityArg === 'plugin'\n ? `${outRoot}/packages/${nameArg}-entry`\n : outRoot;\n\n const linked = await linkWithMarketplace(entryPkgDir, ctx.cwd);\n\n const registrationNote =\n linked === 'ok'\n ? 'Registered in .kb/marketplace.lock'\n : `Not auto-registered — run: kb marketplace plugins link ${entryPkgDir}`;\n\n const timing = Date.now() - start;\n\n ctx.ui?.success?.(`Scaffolded ${entityArg} \"${nameArg}\"`, {\n title: 'scaffold run',\n sections: [\n {\n header: 'Output',\n items: [outRoot],\n },\n {\n header: 'Marketplace',\n items: [registrationNote],\n },\n {\n header: 'Next steps',\n items: [\n `cd ${outRoot}`,\n 'pnpm install',\n 'pnpm -w build',\n `pnpm kb ${nameArg} hello # try it`,\n `pnpm kb scaffold doctor --path ${dirname(outRoot)}`,\n ],\n },\n ],\n timing,\n });\n\n return {\n exitCode: 0,\n result: { outRoot, files: result.files.length },\n };\n}\n\ntype LinkOutcome = 'ok' | 'no-shell' | 'failed';\n\n/**\n * Register a scaffolded plugin in the project-scope marketplace.lock.\n * Uses projectRoot (ctx.cwd) so the lock lives alongside the project config.\n */\nasync function linkWithMarketplace(entryPkgDir: string, projectRoot: string): Promise<LinkOutcome> {\n try {\n const lockPath = resolve(projectRoot, '.kb', 'marketplace.lock');\n\n let lock: { schema: string; installed: Record<string, unknown> };\n try {\n lock = JSON.parse(await readFile(lockPath, 'utf8'));\n } catch {\n lock = { schema: 'kb.marketplace/2', installed: {} };\n }\n\n const pkgJsonPath = resolve(entryPkgDir, 'package.json');\n const pkgRaw = await readFile(pkgJsonPath, 'utf8');\n const pkg = JSON.parse(pkgRaw) as { name?: string; version?: string; kb?: { manifest?: string } };\n if (!pkg.name) return 'failed';\n\n const hash = createHash('sha256').update(pkgRaw).digest('base64');\n const provides: string[] = ['plugin', 'cli-command'];\n const resolvedPath = relative(projectRoot, resolve(entryPkgDir));\n const pluginId = pkg.name.replace(/-entry$/, '');\n\n lock.installed[pluginId] = {\n version: pkg.version ?? '0.1.0',\n integrity: `sha256-${hash}`,\n resolvedPath: `./${resolvedPath}`,\n installedAt: new Date().toISOString(),\n source: 'local',\n primaryKind: 'plugin',\n provides,\n enabled: true,\n };\n\n await mkdir(dirname(lockPath), { recursive: true });\n await writeFile(lockPath, JSON.stringify(lock, null, 2));\n return 'ok';\n } catch {\n return 'failed';\n }\n}\n\nexport default defineCommand({\n id: 'scaffold:run',\n description: 'Scaffold <entity> <name> from blocks',\n\n handler: {\n execute: runDefault,\n },\n});\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/commands/scaffold.ts"],"names":[],"mappings":"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","file":"scaffold.js","sourcesContent":["import { dirname, resolve, relative } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { createRequire } from 'node:module';\nimport { readFile, writeFile, mkdir } from 'node:fs/promises';\nimport { createHash } from 'node:crypto';\nimport {\n defineCommand,\n validationError,\n handleError,\n type PluginContextV3,\n type CLIInput,\n} from '@kb-labs/sdk';\nimport {\n build,\n inspectTarget,\n formatTree,\n listEntities,\n loadEntity,\n resolveBlocks,\n runValidator,\n writeFiles,\n} from '@kb-labs/scaffold-core';\nimport type {\n RenderContext,\n} from '@kb-labs/scaffold-contracts';\nimport { formatCommandHelp } from '@kb-labs/shared-cli-ui';\n\nconst here = dirname(fileURLToPath(import.meta.url));\nconst TEMPLATES_ROOT = resolve(here, '..', '..', 'templates');\n\nconst SCAFFOLD_FLAGS = [\n { name: 'scope', description: 'npm scope, e.g. @my-org' },\n { name: 'blocks', description: 'comma-separated block ids to include' },\n { name: 'out', description: 'custom output directory' },\n { name: 'force', description: 'overwrite existing output directory' },\n { name: 'dry-run', description: 'preview files without writing' },\n];\n\ninterface ScaffoldFlags {\n blocks?: string;\n force?: boolean;\n 'dry-run'?: boolean;\n out?: string;\n scope?: string;\n mode?: string;\n}\n\ntype ScaffoldResult = {\n exitCode: number;\n result?: { outRoot: string; files: number };\n};\n\nasync function readVersion(pkgPath: string): Promise<string> {\n try {\n const raw = await readFile(pkgPath, 'utf8');\n const parsed = JSON.parse(raw) as { version?: string };\n return parsed.version ?? '0.0.0';\n } catch {\n return '0.0.0';\n }\n}\n\nconst FALLBACK_VERSIONS = {\n sdk: '2.18.0',\n devkit: '2.28.0',\n commandKit: '2.30.0',\n} as const;\n\nasync function detectVersions(): Promise<Record<string, string>> {\n const req = createRequire(import.meta.url);\n const readPkg = async (spec: string, fallback: string): Promise<string> => {\n try {\n const resolved = req.resolve(spec);\n const v = await readVersion(resolved);\n return v === '0.0.0' ? fallback : v;\n } catch {\n return fallback;\n }\n };\n const [sdk, devkit, commandKit] = await Promise.all([\n readPkg('@kb-labs/sdk/package.json', FALLBACK_VERSIONS.sdk),\n readPkg('@kb-labs/devkit/package.json', FALLBACK_VERSIONS.devkit),\n readPkg('@kb-labs/shared-command-kit/package.json', FALLBACK_VERSIONS.commandKit),\n ]);\n return { sdk, devkit, commandKit };\n}\n\nfunction parsePositional(argv: string[] | undefined): {\n entity?: string;\n name?: string;\n} {\n if (!argv || argv.length === 0) { return {}; }\n const positional = argv.filter((a) => !a.startsWith('-'));\n return { entity: positional[0], name: positional[1] };\n}\n\nasync function runDefault(\n ctx: PluginContextV3,\n rawInput: CLIInput<ScaffoldFlags>,\n): Promise<ScaffoldResult> {\n const start = Date.now();\n const input = { ...rawInput.flags, argv: rawInput.argv };\n\n const { entity: entityArg, name: nameArg } = parsePositional(input.argv);\n\n const available = await listEntities(TEMPLATES_ROOT);\n if (available.length === 0) {\n validationError(ctx, 'No scaffold templates found. Reinstall @kb-labs/scaffold.');\n return { exitCode: 1 };\n }\n\n if (!entityArg) {\n ctx.ui?.write?.(formatCommandHelp({\n title: 'kb scaffold run',\n description: 'Scaffold a new plugin, adapter, or other entity from a template.',\n examples: available.map((e) => `kb scaffold run ${e} my-${e}`),\n flags: SCAFFOLD_FLAGS,\n }) + '\\n');\n ctx.ui?.info?.(`Available entities: ${available.join(', ')}`);\n return { exitCode: 1 };\n }\n\n if (!available.includes(entityArg)) {\n validationError(ctx, `Unknown entity \"${entityArg}\". Available: ${available.join(', ')}`);\n return { exitCode: 1 };\n }\n\n if (!nameArg) {\n ctx.ui?.write?.(formatCommandHelp({\n title: `kb scaffold run ${entityArg} <name>`,\n description: `Scaffold a new ${entityArg}. Provide a name to continue.`,\n examples: [`kb scaffold run ${entityArg} my-${entityArg}`],\n flags: SCAFFOLD_FLAGS,\n }) + '\\n');\n return { exitCode: 1 };\n }\n\n const problem = runValidator('npmName', nameArg);\n if (problem) {\n validationError(ctx, `Invalid name \"${nameArg}\": ${problem}`, 'Name must be lowercase, no spaces, valid npm package name.');\n return { exitCode: 1 };\n }\n\n const entity = await loadEntity(TEMPLATES_ROOT, entityArg);\n\n const vars: Record<string, unknown> = {};\n for (const v of entity.variables) {\n if (v.name === 'scope' && input.scope !== undefined) {\n vars[v.name] = input.scope;\n } else if (v.name === 'mode' && input.mode !== undefined) {\n vars[v.name] = input.mode;\n } else {\n vars[v.name] = v.default ?? '';\n }\n }\n\n let selectedBlocks: string[];\n if (input.blocks) {\n selectedBlocks = input.blocks\n .split(',')\n .map((s) => s.trim())\n .filter(Boolean);\n } else {\n selectedBlocks = entity.defaults?.blocks ?? entity.blocks.map((b) => b.id);\n }\n\n try {\n resolveBlocks(entity.blocks, selectedBlocks);\n } catch (e) {\n handleError(ctx, e);\n return { exitCode: 1 };\n }\n\n for (const blockId of selectedBlocks) {\n const block = entity.blocks.find((b) => b.id === blockId);\n for (const v of block?.variables ?? []) {\n vars[v.name] = v.default ?? '';\n }\n }\n\n const scope = (vars.scope as string) ?? input.scope ?? '';\n const mode = (input.mode ?? (vars.mode as string) ?? 'in-workspace') as\n | 'in-workspace'\n | 'standalone';\n\n const versions = await detectVersions();\n\n const context: RenderContext = {\n name: nameArg,\n scope,\n vars,\n blocks: selectedBlocks,\n mode,\n versions,\n };\n\n const result = await build({\n entity,\n selectedBlockIds: selectedBlocks,\n context,\n });\n\n const outRoot = input.out ?? result.outRoot;\n const state = await inspectTarget(outRoot);\n\n if (input['dry-run']) {\n ctx.ui?.success?.('Dry run complete', {\n title: 'scaffold run — dry run',\n sections: [\n { header: 'Would write to', items: [outRoot] },\n { header: 'Files', items: formatTree(result.files).split('\\n').filter(Boolean) },\n ],\n });\n return { exitCode: 0, result: { outRoot, files: result.files.length } };\n }\n\n if (state.exists && !state.empty) {\n if (input.force) {\n ctx.ui?.warn?.(`--force: overwriting ${outRoot}`);\n } else {\n validationError(ctx, `Output directory \"${outRoot}\" already exists and is not empty.`, 'Use --force to overwrite.');\n return { exitCode: 1 };\n }\n }\n\n await writeFiles({ outRoot, files: result.files, force: input.force });\n\n const entryPkgDir =\n entityArg === 'plugin'\n ? `${outRoot}/packages/${nameArg}-entry`\n : outRoot;\n\n const linked = await linkWithMarketplace(entryPkgDir, ctx.cwd);\n\n const registrationNote =\n linked === 'ok'\n ? 'Registered in .kb/marketplace.lock'\n : `Not auto-registered — run: kb marketplace plugins link ${entryPkgDir}`;\n\n const timing = Date.now() - start;\n\n ctx.ui?.success?.(`Scaffolded ${entityArg} \"${nameArg}\"`, {\n title: 'scaffold run',\n sections: [\n {\n header: 'Output',\n items: [outRoot],\n },\n {\n header: 'Marketplace',\n items: [registrationNote],\n },\n {\n header: 'Next steps',\n items: [\n `cd ${outRoot}`,\n 'pnpm install',\n 'pnpm -w build',\n `pnpm kb ${nameArg} hello # try it`,\n `pnpm kb scaffold doctor --path ${dirname(outRoot)}`,\n ],\n },\n ],\n timing,\n });\n\n return {\n exitCode: 0,\n result: { outRoot, files: result.files.length },\n };\n}\n\ntype LinkOutcome = 'ok' | 'no-shell' | 'failed';\n\n/**\n * Register a scaffolded plugin in the project-scope marketplace.lock.\n * Uses projectRoot (ctx.cwd) so the lock lives alongside the project config.\n */\nasync function linkWithMarketplace(entryPkgDir: string, projectRoot: string): Promise<LinkOutcome> {\n try {\n const lockPath = resolve(projectRoot, '.kb', 'marketplace.lock');\n\n let lock: { schema: string; installed: Record<string, unknown> };\n try {\n lock = JSON.parse(await readFile(lockPath, 'utf8'));\n } catch {\n lock = { schema: 'kb.marketplace/2', installed: {} };\n }\n\n const pkgJsonPath = resolve(entryPkgDir, 'package.json');\n const pkgRaw = await readFile(pkgJsonPath, 'utf8');\n const pkg = JSON.parse(pkgRaw) as { name?: string; version?: string; kb?: { manifest?: string } };\n if (!pkg.name) { return 'failed'; }\n\n const hash = createHash('sha256').update(pkgRaw).digest('base64');\n const provides: string[] = ['plugin', 'cli-command'];\n const resolvedPath = relative(projectRoot, resolve(entryPkgDir));\n const pluginId = pkg.name.replace(/-entry$/, '');\n\n lock.installed[pluginId] = {\n version: pkg.version ?? '0.1.0',\n integrity: `sha256-${hash}`,\n resolvedPath: `./${resolvedPath}`,\n installedAt: new Date().toISOString(),\n source: 'local',\n primaryKind: 'plugin',\n provides,\n enabled: true,\n };\n\n await mkdir(dirname(lockPath), { recursive: true });\n await writeFile(lockPath, JSON.stringify(lock, null, 2));\n return 'ok';\n } catch {\n return 'failed';\n }\n}\n\nexport default defineCommand({\n id: 'scaffold:run',\n description: 'Scaffold <entity> <name> from blocks',\n\n handler: {\n execute: runDefault,\n },\n});\n"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { default as manifest } from './manifest.js';
|
|
2
|
-
import '@kb-labs/
|
|
2
|
+
import '@kb-labs/plugin-contracts';
|
package/dist/index.js
CHANGED
|
@@ -20,20 +20,18 @@ var manifest = {
|
|
|
20
20
|
version: "0.1.0",
|
|
21
21
|
display: {
|
|
22
22
|
name: "Scaffold",
|
|
23
|
-
description: "
|
|
23
|
+
description: "Entity scaffolder for plugins and adapters",
|
|
24
24
|
tags: ["scaffold", "generator", "dx"]
|
|
25
25
|
},
|
|
26
26
|
cli: {
|
|
27
27
|
groupMeta: [
|
|
28
|
-
{
|
|
28
|
+
{ path: "scaffold", describe: "Scaffold KB Labs entities" }
|
|
29
29
|
],
|
|
30
30
|
commands: [
|
|
31
31
|
{
|
|
32
|
-
|
|
33
|
-
group: "scaffold",
|
|
32
|
+
path: "scaffold run",
|
|
34
33
|
describe: "Scaffold <entity> <name> from blocks",
|
|
35
34
|
handler: "./commands/scaffold.js#default",
|
|
36
|
-
handlerPath: "./commands/scaffold.js",
|
|
37
35
|
flags: [
|
|
38
36
|
{
|
|
39
37
|
name: "blocks",
|
|
@@ -80,11 +78,9 @@ var manifest = {
|
|
|
80
78
|
]
|
|
81
79
|
},
|
|
82
80
|
{
|
|
83
|
-
|
|
84
|
-
group: "scaffold",
|
|
81
|
+
path: "scaffold doctor",
|
|
85
82
|
describe: "Scan user plugins for common issues",
|
|
86
83
|
handler: "./commands/doctor.js#default",
|
|
87
|
-
handlerPath: "./commands/doctor.js",
|
|
88
84
|
flags: [
|
|
89
85
|
{
|
|
90
86
|
name: "path",
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/manifest.ts"],"names":[],"mappings":";;;AAEA,IAAM,cAAc,kBAAA,EAAmB,CACpC,IAAA,CAAK,gBAAgB,EACrB,MAAA,CAAO;AAAA,EACN,IAAA,EAAM,WAAA;AAAA,EACN,KAAA,EAAO;AAAA,IACL,gBAAA;AAAA,IACA,sBAAA;AAAA,IACA,YAAA;AAAA,IACA;AAAA;AAEJ,CAAC,EACA,SAAA,CAAU;AAAA;AAAA;AAAA,EAGT,KAAA,EAAO,CAAC,IAAI;AACd,CAAC,CAAA,CACA,WAAW,EAAE,SAAA,EAAW,MAAQ,QAAA,EAAU,GAAA,EAAK,CAAA,CAC/C,KAAA,EAAM;AAET,IAAM,QAAA,GAAW;AAAA,EACf,MAAA,EAAQ,aAAA;AAAA,EACR,EAAA,EAAI,mBAAA;AAAA,EACJ,OAAA,EAAS,OAAA;AAAA,EACT,OAAA,EAAS;AAAA,IACP,IAAA,EAAM,UAAA;AAAA,IACN,WAAA,
|
|
1
|
+
{"version":3,"sources":["../src/manifest.ts"],"names":[],"mappings":";;;AAEA,IAAM,cAAc,kBAAA,EAAmB,CACpC,IAAA,CAAK,gBAAgB,EACrB,MAAA,CAAO;AAAA,EACN,IAAA,EAAM,WAAA;AAAA,EACN,KAAA,EAAO;AAAA,IACL,gBAAA;AAAA,IACA,sBAAA;AAAA,IACA,YAAA;AAAA,IACA;AAAA;AAEJ,CAAC,EACA,SAAA,CAAU;AAAA;AAAA;AAAA,EAGT,KAAA,EAAO,CAAC,IAAI;AACd,CAAC,CAAA,CACA,WAAW,EAAE,SAAA,EAAW,MAAQ,QAAA,EAAU,GAAA,EAAK,CAAA,CAC/C,KAAA,EAAM;AAET,IAAM,QAAA,GAAW;AAAA,EACf,MAAA,EAAQ,aAAA;AAAA,EACR,EAAA,EAAI,mBAAA;AAAA,EACJ,OAAA,EAAS,OAAA;AAAA,EACT,OAAA,EAAS;AAAA,IACP,IAAA,EAAM,UAAA;AAAA,IACN,WAAA,EAAa,4CAAA;AAAA,IACb,IAAA,EAAM,CAAC,UAAA,EAAY,WAAA,EAAa,IAAI;AAAA,GACtC;AAAA,EACA,GAAA,EAAK;AAAA,IACH,SAAA,EAAW;AAAA,MACT,EAAE,IAAA,EAAM,UAAA,EAAY,QAAA,EAAU,2BAAA;AAA4B,KAC5D;AAAA,IACA,QAAA,EAAU;AAAA,MACR;AAAA,QACE,IAAA,EAAM,cAAA;AAAA,QACN,QAAA,EAAU,sCAAA;AAAA,QACV,OAAA,EAAS,gCAAA;AAAA,QACT,KAAA,EAAO;AAAA,UACL;AAAA,YACE,IAAA,EAAM,QAAA;AAAA,YACN,IAAA,EAAM,QAAA;AAAA,YACN,WAAA,EAAa;AAAA,WACf;AAAA,UACA;AAAA,YACE,IAAA,EAAM,KAAA;AAAA,YACN,KAAA,EAAO,GAAA;AAAA,YACP,IAAA,EAAM,SAAA;AAAA,YACN,WAAA,EAAa;AAAA,WACf;AAAA,UACA;AAAA,YACE,IAAA,EAAM,OAAA;AAAA,YACN,IAAA,EAAM,SAAA;AAAA,YACN,WAAA,EAAa;AAAA,WACf;AAAA,UACA;AAAA,YACE,IAAA,EAAM,SAAA;AAAA,YACN,IAAA,EAAM,SAAA;AAAA,YACN,WAAA,EAAa;AAAA,WACf;AAAA,UACA;AAAA,YACE,IAAA,EAAM,KAAA;AAAA,YACN,IAAA,EAAM,QAAA;AAAA,YACN,WAAA,EAAa;AAAA,WACf;AAAA,UACA;AAAA,YACE,IAAA,EAAM,OAAA;AAAA,YACN,IAAA,EAAM,QAAA;AAAA,YACN,WAAA,EAAa;AAAA,WACf;AAAA,UACA;AAAA,YACE,IAAA,EAAM,MAAA;AAAA,YACN,IAAA,EAAM,QAAA;AAAA,YACN,WAAA,EACE;AAAA;AACJ,SACF;AAAA,QACA,QAAA,EAAU;AAAA,UACR,kCAAA;AAAA,UACA,8CAAA;AAAA,UACA,+CAAA;AAAA,UACA;AAAA;AACF,OACF;AAAA,MACA;AAAA,QACE,IAAA,EAAM,iBAAA;AAAA,QACN,QAAA,EAAU,qCAAA;AAAA,QACV,OAAA,EAAS,8BAAA;AAAA,QACT,KAAA,EAAO;AAAA,UACL;AAAA,YACE,IAAA,EAAM,MAAA;AAAA,YACN,IAAA,EAAM,QAAA;AAAA,YACN,WAAA,EAAa;AAAA,WACf;AAAA,UACA;AAAA,YACE,IAAA,EAAM,MAAA;AAAA,YACN,IAAA,EAAM,SAAA;AAAA,YACN,WAAA,EAAa;AAAA;AACf,SACF;AAAA,QACA,QAAA,EAAU;AAAA,UACR,oBAAA;AAAA,UACA,qCAAA;AAAA,UACA;AAAA;AACF;AACF;AACF,GACF;AAAA,EACA;AACF,CAAA;AAEA,IAAO,gBAAA,GAAQ","file":"index.js","sourcesContent":["import { combinePermissions, kbPlatformPreset } from '@kb-labs/sdk';\n\nconst permissions = combinePermissions()\n .with(kbPlatformPreset)\n .withFs({\n mode: 'readWrite',\n allow: [\n '.kb/plugins/**',\n '.kb/marketplace.lock',\n 'plugins/**',\n 'adapters/**',\n ],\n })\n .withShell({\n // Needed to call `kb marketplace plugins link` after scaffolding,\n // so the generated plugin lands in .kb/marketplace.lock automatically.\n allow: ['kb'],\n })\n .withQuotas({ timeoutMs: 120000, memoryMb: 256 })\n .build();\n\nconst manifest = {\n schema: 'kb.plugin/3',\n id: '@kb-labs/scaffold',\n version: '0.1.0',\n display: {\n name: 'Scaffold',\n description: 'Entity scaffolder for plugins and adapters',\n tags: ['scaffold', 'generator', 'dx'],\n },\n cli: {\n groupMeta: [\n { path: 'scaffold', describe: 'Scaffold KB Labs entities' },\n ],\n commands: [\n {\n path: 'scaffold run',\n describe: 'Scaffold <entity> <name> from blocks',\n handler: './commands/scaffold.js#default',\n flags: [\n {\n name: 'blocks',\n type: 'string',\n description: 'Comma-separated block ids',\n },\n {\n name: 'yes',\n alias: 'y',\n type: 'boolean',\n description: 'Accept defaults and skip prompts',\n },\n {\n name: 'force',\n type: 'boolean',\n description: 'Overwrite non-empty target directory',\n },\n {\n name: 'dry-run',\n type: 'boolean',\n description: 'Print the tree that would be written and exit',\n },\n {\n name: 'out',\n type: 'string',\n description: 'Override the output directory',\n },\n {\n name: 'scope',\n type: 'string',\n description: 'npm scope for the generated package',\n },\n {\n name: 'mode',\n type: 'string',\n description:\n 'Layout mode: \"in-workspace\" (workspace:* deps) or \"standalone\" (semver deps + pnpm-workspace.yaml)',\n },\n ],\n examples: [\n 'kb scaffold run plugin my-plugin',\n 'kb scaffold run adapter my-llm --blocks base',\n 'kb scaffold run plugin ui --scope @acme --yes',\n 'kb scaffold run plugin demo --dry-run',\n ],\n },\n {\n path: 'scaffold doctor',\n describe: 'Scan user plugins for common issues',\n handler: './commands/doctor.js#default',\n flags: [\n {\n name: 'path',\n type: 'string',\n description: 'Path to scan (default: .kb/plugins)',\n },\n {\n name: 'json',\n type: 'boolean',\n description: 'Emit JSON instead of text',\n },\n ],\n examples: [\n 'kb scaffold doctor',\n 'kb scaffold doctor --path ./plugins',\n 'kb scaffold doctor --json',\n ],\n },\n ],\n },\n permissions,\n} as const;\n\nexport default manifest;\n"]}
|
package/dist/manifest.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as _kb_labs_plugin_contracts from '@kb-labs/plugin-contracts';
|
|
2
2
|
|
|
3
3
|
declare const manifest: {
|
|
4
4
|
readonly schema: "kb.plugin/3";
|
|
@@ -6,20 +6,18 @@ declare const manifest: {
|
|
|
6
6
|
readonly version: "0.1.0";
|
|
7
7
|
readonly display: {
|
|
8
8
|
readonly name: "Scaffold";
|
|
9
|
-
readonly description: "
|
|
9
|
+
readonly description: "Entity scaffolder for plugins and adapters";
|
|
10
10
|
readonly tags: readonly ["scaffold", "generator", "dx"];
|
|
11
11
|
};
|
|
12
12
|
readonly cli: {
|
|
13
13
|
readonly groupMeta: readonly [{
|
|
14
|
-
readonly
|
|
14
|
+
readonly path: "scaffold";
|
|
15
15
|
readonly describe: "Scaffold KB Labs entities";
|
|
16
16
|
}];
|
|
17
17
|
readonly commands: readonly [{
|
|
18
|
-
readonly
|
|
19
|
-
readonly group: "scaffold";
|
|
18
|
+
readonly path: "scaffold run";
|
|
20
19
|
readonly describe: "Scaffold <entity> <name> from blocks";
|
|
21
20
|
readonly handler: "./commands/scaffold.js#default";
|
|
22
|
-
readonly handlerPath: "./commands/scaffold.js";
|
|
23
21
|
readonly flags: readonly [{
|
|
24
22
|
readonly name: "blocks";
|
|
25
23
|
readonly type: "string";
|
|
@@ -52,11 +50,9 @@ declare const manifest: {
|
|
|
52
50
|
}];
|
|
53
51
|
readonly examples: readonly ["kb scaffold run plugin my-plugin", "kb scaffold run adapter my-llm --blocks base", "kb scaffold run plugin ui --scope @acme --yes", "kb scaffold run plugin demo --dry-run"];
|
|
54
52
|
}, {
|
|
55
|
-
readonly
|
|
56
|
-
readonly group: "scaffold";
|
|
53
|
+
readonly path: "scaffold doctor";
|
|
57
54
|
readonly describe: "Scan user plugins for common issues";
|
|
58
55
|
readonly handler: "./commands/doctor.js#default";
|
|
59
|
-
readonly handlerPath: "./commands/doctor.js";
|
|
60
56
|
readonly flags: readonly [{
|
|
61
57
|
readonly name: "path";
|
|
62
58
|
readonly type: "string";
|
|
@@ -69,7 +65,7 @@ declare const manifest: {
|
|
|
69
65
|
readonly examples: readonly ["kb scaffold doctor", "kb scaffold doctor --path ./plugins", "kb scaffold doctor --json"];
|
|
70
66
|
}];
|
|
71
67
|
};
|
|
72
|
-
readonly permissions:
|
|
68
|
+
readonly permissions: _kb_labs_plugin_contracts.PermissionSpec;
|
|
73
69
|
};
|
|
74
70
|
|
|
75
71
|
export { manifest as default };
|
package/dist/manifest.js
CHANGED
|
@@ -20,20 +20,18 @@ var manifest = {
|
|
|
20
20
|
version: "0.1.0",
|
|
21
21
|
display: {
|
|
22
22
|
name: "Scaffold",
|
|
23
|
-
description: "
|
|
23
|
+
description: "Entity scaffolder for plugins and adapters",
|
|
24
24
|
tags: ["scaffold", "generator", "dx"]
|
|
25
25
|
},
|
|
26
26
|
cli: {
|
|
27
27
|
groupMeta: [
|
|
28
|
-
{
|
|
28
|
+
{ path: "scaffold", describe: "Scaffold KB Labs entities" }
|
|
29
29
|
],
|
|
30
30
|
commands: [
|
|
31
31
|
{
|
|
32
|
-
|
|
33
|
-
group: "scaffold",
|
|
32
|
+
path: "scaffold run",
|
|
34
33
|
describe: "Scaffold <entity> <name> from blocks",
|
|
35
34
|
handler: "./commands/scaffold.js#default",
|
|
36
|
-
handlerPath: "./commands/scaffold.js",
|
|
37
35
|
flags: [
|
|
38
36
|
{
|
|
39
37
|
name: "blocks",
|
|
@@ -80,11 +78,9 @@ var manifest = {
|
|
|
80
78
|
]
|
|
81
79
|
},
|
|
82
80
|
{
|
|
83
|
-
|
|
84
|
-
group: "scaffold",
|
|
81
|
+
path: "scaffold doctor",
|
|
85
82
|
describe: "Scan user plugins for common issues",
|
|
86
83
|
handler: "./commands/doctor.js#default",
|
|
87
|
-
handlerPath: "./commands/doctor.js",
|
|
88
84
|
flags: [
|
|
89
85
|
{
|
|
90
86
|
name: "path",
|
package/dist/manifest.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/manifest.ts"],"names":[],"mappings":";;;AAEA,IAAM,cAAc,kBAAA,EAAmB,CACpC,IAAA,CAAK,gBAAgB,EACrB,MAAA,CAAO;AAAA,EACN,IAAA,EAAM,WAAA;AAAA,EACN,KAAA,EAAO;AAAA,IACL,gBAAA;AAAA,IACA,sBAAA;AAAA,IACA,YAAA;AAAA,IACA;AAAA;AAEJ,CAAC,EACA,SAAA,CAAU;AAAA;AAAA;AAAA,EAGT,KAAA,EAAO,CAAC,IAAI;AACd,CAAC,CAAA,CACA,WAAW,EAAE,SAAA,EAAW,MAAQ,QAAA,EAAU,GAAA,EAAK,CAAA,CAC/C,KAAA,EAAM;AAET,IAAM,QAAA,GAAW;AAAA,EACf,MAAA,EAAQ,aAAA;AAAA,EACR,EAAA,EAAI,mBAAA;AAAA,EACJ,OAAA,EAAS,OAAA;AAAA,EACT,OAAA,EAAS;AAAA,IACP,IAAA,EAAM,UAAA;AAAA,IACN,WAAA,
|
|
1
|
+
{"version":3,"sources":["../src/manifest.ts"],"names":[],"mappings":";;;AAEA,IAAM,cAAc,kBAAA,EAAmB,CACpC,IAAA,CAAK,gBAAgB,EACrB,MAAA,CAAO;AAAA,EACN,IAAA,EAAM,WAAA;AAAA,EACN,KAAA,EAAO;AAAA,IACL,gBAAA;AAAA,IACA,sBAAA;AAAA,IACA,YAAA;AAAA,IACA;AAAA;AAEJ,CAAC,EACA,SAAA,CAAU;AAAA;AAAA;AAAA,EAGT,KAAA,EAAO,CAAC,IAAI;AACd,CAAC,CAAA,CACA,WAAW,EAAE,SAAA,EAAW,MAAQ,QAAA,EAAU,GAAA,EAAK,CAAA,CAC/C,KAAA,EAAM;AAET,IAAM,QAAA,GAAW;AAAA,EACf,MAAA,EAAQ,aAAA;AAAA,EACR,EAAA,EAAI,mBAAA;AAAA,EACJ,OAAA,EAAS,OAAA;AAAA,EACT,OAAA,EAAS;AAAA,IACP,IAAA,EAAM,UAAA;AAAA,IACN,WAAA,EAAa,4CAAA;AAAA,IACb,IAAA,EAAM,CAAC,UAAA,EAAY,WAAA,EAAa,IAAI;AAAA,GACtC;AAAA,EACA,GAAA,EAAK;AAAA,IACH,SAAA,EAAW;AAAA,MACT,EAAE,IAAA,EAAM,UAAA,EAAY,QAAA,EAAU,2BAAA;AAA4B,KAC5D;AAAA,IACA,QAAA,EAAU;AAAA,MACR;AAAA,QACE,IAAA,EAAM,cAAA;AAAA,QACN,QAAA,EAAU,sCAAA;AAAA,QACV,OAAA,EAAS,gCAAA;AAAA,QACT,KAAA,EAAO;AAAA,UACL;AAAA,YACE,IAAA,EAAM,QAAA;AAAA,YACN,IAAA,EAAM,QAAA;AAAA,YACN,WAAA,EAAa;AAAA,WACf;AAAA,UACA;AAAA,YACE,IAAA,EAAM,KAAA;AAAA,YACN,KAAA,EAAO,GAAA;AAAA,YACP,IAAA,EAAM,SAAA;AAAA,YACN,WAAA,EAAa;AAAA,WACf;AAAA,UACA;AAAA,YACE,IAAA,EAAM,OAAA;AAAA,YACN,IAAA,EAAM,SAAA;AAAA,YACN,WAAA,EAAa;AAAA,WACf;AAAA,UACA;AAAA,YACE,IAAA,EAAM,SAAA;AAAA,YACN,IAAA,EAAM,SAAA;AAAA,YACN,WAAA,EAAa;AAAA,WACf;AAAA,UACA;AAAA,YACE,IAAA,EAAM,KAAA;AAAA,YACN,IAAA,EAAM,QAAA;AAAA,YACN,WAAA,EAAa;AAAA,WACf;AAAA,UACA;AAAA,YACE,IAAA,EAAM,OAAA;AAAA,YACN,IAAA,EAAM,QAAA;AAAA,YACN,WAAA,EAAa;AAAA,WACf;AAAA,UACA;AAAA,YACE,IAAA,EAAM,MAAA;AAAA,YACN,IAAA,EAAM,QAAA;AAAA,YACN,WAAA,EACE;AAAA;AACJ,SACF;AAAA,QACA,QAAA,EAAU;AAAA,UACR,kCAAA;AAAA,UACA,8CAAA;AAAA,UACA,+CAAA;AAAA,UACA;AAAA;AACF,OACF;AAAA,MACA;AAAA,QACE,IAAA,EAAM,iBAAA;AAAA,QACN,QAAA,EAAU,qCAAA;AAAA,QACV,OAAA,EAAS,8BAAA;AAAA,QACT,KAAA,EAAO;AAAA,UACL;AAAA,YACE,IAAA,EAAM,MAAA;AAAA,YACN,IAAA,EAAM,QAAA;AAAA,YACN,WAAA,EAAa;AAAA,WACf;AAAA,UACA;AAAA,YACE,IAAA,EAAM,MAAA;AAAA,YACN,IAAA,EAAM,SAAA;AAAA,YACN,WAAA,EAAa;AAAA;AACf,SACF;AAAA,QACA,QAAA,EAAU;AAAA,UACR,oBAAA;AAAA,UACA,qCAAA;AAAA,UACA;AAAA;AACF;AACF;AACF,GACF;AAAA,EACA;AACF,CAAA;AAEA,IAAO,gBAAA,GAAQ","file":"manifest.js","sourcesContent":["import { combinePermissions, kbPlatformPreset } from '@kb-labs/sdk';\n\nconst permissions = combinePermissions()\n .with(kbPlatformPreset)\n .withFs({\n mode: 'readWrite',\n allow: [\n '.kb/plugins/**',\n '.kb/marketplace.lock',\n 'plugins/**',\n 'adapters/**',\n ],\n })\n .withShell({\n // Needed to call `kb marketplace plugins link` after scaffolding,\n // so the generated plugin lands in .kb/marketplace.lock automatically.\n allow: ['kb'],\n })\n .withQuotas({ timeoutMs: 120000, memoryMb: 256 })\n .build();\n\nconst manifest = {\n schema: 'kb.plugin/3',\n id: '@kb-labs/scaffold',\n version: '0.1.0',\n display: {\n name: 'Scaffold',\n description: 'Entity scaffolder for plugins and adapters',\n tags: ['scaffold', 'generator', 'dx'],\n },\n cli: {\n groupMeta: [\n { path: 'scaffold', describe: 'Scaffold KB Labs entities' },\n ],\n commands: [\n {\n path: 'scaffold run',\n describe: 'Scaffold <entity> <name> from blocks',\n handler: './commands/scaffold.js#default',\n flags: [\n {\n name: 'blocks',\n type: 'string',\n description: 'Comma-separated block ids',\n },\n {\n name: 'yes',\n alias: 'y',\n type: 'boolean',\n description: 'Accept defaults and skip prompts',\n },\n {\n name: 'force',\n type: 'boolean',\n description: 'Overwrite non-empty target directory',\n },\n {\n name: 'dry-run',\n type: 'boolean',\n description: 'Print the tree that would be written and exit',\n },\n {\n name: 'out',\n type: 'string',\n description: 'Override the output directory',\n },\n {\n name: 'scope',\n type: 'string',\n description: 'npm scope for the generated package',\n },\n {\n name: 'mode',\n type: 'string',\n description:\n 'Layout mode: \"in-workspace\" (workspace:* deps) or \"standalone\" (semver deps + pnpm-workspace.yaml)',\n },\n ],\n examples: [\n 'kb scaffold run plugin my-plugin',\n 'kb scaffold run adapter my-llm --blocks base',\n 'kb scaffold run plugin ui --scope @acme --yes',\n 'kb scaffold run plugin demo --dry-run',\n ],\n },\n {\n path: 'scaffold doctor',\n describe: 'Scan user plugins for common issues',\n handler: './commands/doctor.js#default',\n flags: [\n {\n name: 'path',\n type: 'string',\n description: 'Path to scan (default: .kb/plugins)',\n },\n {\n name: 'json',\n type: 'boolean',\n description: 'Emit JSON instead of text',\n },\n ],\n examples: [\n 'kb scaffold doctor',\n 'kb scaffold doctor --path ./plugins',\n 'kb scaffold doctor --json',\n ],\n },\n ],\n },\n permissions,\n} as const;\n\nexport default manifest;\n"]}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kb-labs/scaffold",
|
|
3
3
|
"description": "Generic entity scaffolder for KB Labs plugins, adapters, and friends.",
|
|
4
|
-
"version": "2.
|
|
4
|
+
"version": "2.98.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
7
7
|
"types": "./dist/index.d.ts",
|
|
@@ -20,10 +20,10 @@
|
|
|
20
20
|
"templates"
|
|
21
21
|
],
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@kb-labs/
|
|
24
|
-
"@kb-labs/
|
|
25
|
-
"@kb-labs/scaffold-core": "2.
|
|
26
|
-
"@kb-labs/
|
|
23
|
+
"@kb-labs/shared-cli-ui": "2.98.0",
|
|
24
|
+
"@kb-labs/sdk": "2.22.0",
|
|
25
|
+
"@kb-labs/scaffold-core": "2.98.0",
|
|
26
|
+
"@kb-labs/scaffold-contracts": "2.98.0"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
29
|
"@types/node": "^24.3.3",
|
|
@@ -31,9 +31,10 @@
|
|
|
31
31
|
"rimraf": "^6.0.1",
|
|
32
32
|
"tsup": "^8.5.0",
|
|
33
33
|
"typescript": "^5.6.3",
|
|
34
|
-
"vitest": "^3.2.
|
|
35
|
-
"@kb-labs/
|
|
36
|
-
"@kb-labs/
|
|
34
|
+
"vitest": "^3.2.6",
|
|
35
|
+
"@kb-labs/plugin-contracts": "2.98.0",
|
|
36
|
+
"@kb-labs/devkit": "2.98.0",
|
|
37
|
+
"@kb-labs/shared-testing-e2e": "2.98.0"
|
|
37
38
|
},
|
|
38
39
|
"engines": {
|
|
39
40
|
"node": ">=20.0.0",
|
|
@@ -49,6 +50,7 @@
|
|
|
49
50
|
"dev": "tsup --watch",
|
|
50
51
|
"lint": "eslint src --ext .ts",
|
|
51
52
|
"test": "vitest run --passWithNoTests",
|
|
53
|
+
"test:cli": "vitest run --config vitest.cli.config.ts --passWithNoTests",
|
|
52
54
|
"test:watch": "vitest",
|
|
53
55
|
"type-check": "tsc --noEmit"
|
|
54
56
|
}
|
|
@@ -1,8 +1,131 @@
|
|
|
1
1
|
# <%= it.scope ? it.scope + '/' : '' %><%= it.name %>
|
|
2
2
|
|
|
3
|
-
<%= it.vars.description %>
|
|
3
|
+
> <%= it.vars.description %>
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+

|
|
6
|
+

|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## Overview
|
|
11
|
+
|
|
12
|
+
<!-- TODO: 2-3 sentences describing what this plugin solves from the user's perspective. -->
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Features
|
|
17
|
+
|
|
18
|
+
<!-- TODO: bullet list of key user-facing capabilities -->
|
|
19
|
+
- Feature one
|
|
20
|
+
- Feature two
|
|
21
|
+
- Feature three
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Requirements
|
|
26
|
+
|
|
27
|
+
**KB Labs platform** `>= 0.1.0`
|
|
28
|
+
|
|
29
|
+
**Platform services**
|
|
30
|
+
|
|
31
|
+
| Service | Required | Purpose |
|
|
32
|
+
|---------|----------|---------|
|
|
33
|
+
| `llm` | Optional | AI-powered generation |
|
|
34
|
+
| `cache` | Required | Result caching |
|
|
35
|
+
| `storage` | Required | Persistent state |
|
|
36
|
+
|
|
37
|
+
<!-- TODO: add / remove rows based on what the manifest declares -->
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## Installation
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
pnpm kb marketplace install <%= it.scope ? it.scope + '/' : '' %><%= it.name %>-entry
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Commands
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
kb <%= it.name %> hello # say hi
|
|
53
|
+
kb <%= it.name %> hello --who=World # same, explicit
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
| Command | Description |
|
|
57
|
+
|---------|-------------|
|
|
58
|
+
| `kb <%= it.name %> hello` | Greet the platform |
|
|
59
|
+
|
|
60
|
+
<!-- TODO: replace with real commands once implemented -->
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## Configuration
|
|
65
|
+
|
|
66
|
+
```jsonc
|
|
67
|
+
{
|
|
68
|
+
"<%= it.name %>": {
|
|
69
|
+
// TODO: document config options here
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
<!--
|
|
77
|
+
## REST API
|
|
78
|
+
|
|
79
|
+
Base path: `/<%= it.name %>`
|
|
80
|
+
|
|
81
|
+
| Method | Path | Description |
|
|
82
|
+
|--------|------|-------------|
|
|
83
|
+
| `GET` | `/<%= it.name %>/status` | Plugin status |
|
|
84
|
+
|
|
85
|
+
Remove the comment markers above/below if this plugin registers REST routes.
|
|
86
|
+
-->
|
|
87
|
+
|
|
88
|
+
<!--
|
|
89
|
+
## Studio
|
|
90
|
+
|
|
91
|
+
Adds a **<%= it.name %>** section to KB Labs Studio.
|
|
92
|
+
|
|
93
|
+
| Page | Route | Description |
|
|
94
|
+
|------|-------|-------------|
|
|
95
|
+
| Overview | `/p/<%= it.name %>` | Status and quick actions |
|
|
96
|
+
|
|
97
|
+
Remove the comment markers above/below if this plugin adds Studio pages.
|
|
98
|
+
-->
|
|
99
|
+
|
|
100
|
+
## Permissions
|
|
101
|
+
|
|
102
|
+
| Category | Scope | Reason |
|
|
103
|
+
|----------|-------|--------|
|
|
104
|
+
| Filesystem | `.kb/<%= it.name %>/**` | Plugin state |
|
|
105
|
+
| Platform | `llm`, `cache` | Core functionality |
|
|
106
|
+
|
|
107
|
+
<!-- TODO: update to match manifest permissions -->
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## Changelog
|
|
112
|
+
|
|
113
|
+
### 0.1.0
|
|
114
|
+
|
|
115
|
+
- Initial release
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## License
|
|
120
|
+
|
|
121
|
+
<%= it.vars.license %>
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
<details>
|
|
126
|
+
<summary>Development</summary>
|
|
127
|
+
|
|
128
|
+
**Layout**
|
|
6
129
|
|
|
7
130
|
```
|
|
8
131
|
packages/
|
|
@@ -11,44 +134,31 @@ packages/
|
|
|
11
134
|
<%= it.name %>-entry/ # V3 manifest + CLI command handlers
|
|
12
135
|
```
|
|
13
136
|
|
|
14
|
-
|
|
15
|
-
depends on `contracts`. The runtime discovers the plugin through the `"kb"`
|
|
16
|
-
field in `<%= it.name %>-entry/package.json`.
|
|
17
|
-
|
|
18
|
-
## Getting started
|
|
137
|
+
**Getting started**
|
|
19
138
|
|
|
20
139
|
```bash
|
|
21
140
|
pnpm install
|
|
22
141
|
pnpm -w build
|
|
23
|
-
pnpm kb <%= it.name %> hello
|
|
24
|
-
pnpm kb <%= it.name %> hello --who=World # same, explicit
|
|
142
|
+
pnpm kb <%= it.name %> hello
|
|
25
143
|
```
|
|
26
144
|
|
|
27
|
-
|
|
145
|
+
**What to edit**
|
|
28
146
|
|
|
29
|
-
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
`@kb-labs/core-*` or `@kb-labs/platform-*`.
|
|
33
|
-
- **CLI surface:** [packages/<%= it.name %>-entry/src/manifest.ts](./packages/<%= it.name %>-entry/src/manifest.ts)
|
|
34
|
-
Add more commands by appending to `cli.commands[]` and creating a handler
|
|
35
|
-
in `src/commands/`.
|
|
36
|
-
- **Shared types:** [packages/<%= it.name %>-contracts/src/index.ts](./packages/<%= it.name %>-contracts/src/index.ts)
|
|
37
|
-
Input/output shapes go here so `core` and `entry` agree on them.
|
|
147
|
+
- Business logic: `packages/<%= it.name %>-core/src/hello.ts`
|
|
148
|
+
- CLI commands: `packages/<%= it.name %>-entry/src/manifest.ts`
|
|
149
|
+
- Shared types: `packages/<%= it.name %>-contracts/src/index.ts`
|
|
38
150
|
|
|
39
|
-
|
|
151
|
+
**Link into a workspace**
|
|
40
152
|
|
|
41
153
|
```bash
|
|
42
154
|
pnpm kb marketplace plugins link .
|
|
43
155
|
pnpm kb plugins clear-cache
|
|
44
156
|
```
|
|
45
157
|
|
|
46
|
-
|
|
158
|
+
**Health check**
|
|
47
159
|
|
|
48
160
|
```bash
|
|
49
161
|
pnpm kb scaffold doctor --path .
|
|
50
162
|
```
|
|
51
163
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
<%= it.vars.license %>
|
|
164
|
+
</details>
|
package/templates/plugin/blocks/base/files/packages/__name__-entry/src/commands/hello.ts.eta
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { defineCommand, type CLIInput, type PluginContextV3 } from '@kb-labs/sdk';
|
|
2
2
|
import { hello } from '<%= it.scope ? it.scope + '/' : '' %><%= it.name %>-core';
|
|
3
|
+
import { handleError, validationError } from '../utils/error.js';
|
|
3
4
|
|
|
4
5
|
type HelloFlags = {
|
|
5
6
|
who?: string;
|
|
@@ -9,10 +10,12 @@ type HelloFlags = {
|
|
|
9
10
|
/**
|
|
10
11
|
* `kb <%= it.name %> hello` — prints a friendly greeting.
|
|
11
12
|
*
|
|
12
|
-
* This handler demonstrates the
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
13
|
+
* This handler demonstrates the standard error-handling pattern:
|
|
14
|
+
* 1. Validate args/flags with validationError() — before the try/catch
|
|
15
|
+
* 2. Wrap the core call in try/catch, forward errors via handleError()
|
|
16
|
+
* 3. In JSON mode: success = raw data, errors = { ok: false, error: { ... } }
|
|
17
|
+
*
|
|
18
|
+
* See src/utils/error.ts to extend handleError() for your API error class.
|
|
16
19
|
*/
|
|
17
20
|
export default defineCommand({
|
|
18
21
|
id: '<%= it.name %>:hello',
|
|
@@ -20,15 +23,27 @@ export default defineCommand({
|
|
|
20
23
|
|
|
21
24
|
handler: {
|
|
22
25
|
async execute(ctx: PluginContextV3, input: CLIInput<HelloFlags>) {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
} else {
|
|
28
|
-
ctx.ui?.info?.(greeting);
|
|
26
|
+
// 1. Validate — synchronous, before try/catch
|
|
27
|
+
if (input.flags.who !== undefined && input.flags.who.trim() === '') {
|
|
28
|
+
validationError(ctx, '--who cannot be empty', input.flags.json);
|
|
29
|
+
return { exitCode: 1, result: null };
|
|
29
30
|
}
|
|
30
31
|
|
|
31
|
-
|
|
32
|
+
// 2. Call core, wrap in try/catch
|
|
33
|
+
try {
|
|
34
|
+
const { greeting } = hello({ who: input.flags.who ?? 'World' });
|
|
35
|
+
|
|
36
|
+
if (input.flags.json) {
|
|
37
|
+
ctx.ui?.json?.({ greeting });
|
|
38
|
+
} else {
|
|
39
|
+
ctx.ui?.info?.(greeting);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return { exitCode: 0, result: { greeting } };
|
|
43
|
+
} catch (err) {
|
|
44
|
+
handleError(ctx, err, input.flags.json);
|
|
45
|
+
return { exitCode: 1, result: null };
|
|
46
|
+
}
|
|
32
47
|
},
|
|
33
48
|
},
|
|
34
49
|
});
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import type { PluginContextV3 } from '@kb-labs/sdk';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Output a structured error from a command handler.
|
|
5
|
+
*
|
|
6
|
+
* In JSON mode → { ok: false, error: { code, message, hint? } }
|
|
7
|
+
* In CLI mode → ctx.ui.error() with formatted hint/cause box
|
|
8
|
+
*
|
|
9
|
+
* Usage — wrap every API call in try/catch:
|
|
10
|
+
*
|
|
11
|
+
* try {
|
|
12
|
+
* const result = await someApiCall();
|
|
13
|
+
* ...
|
|
14
|
+
* } catch (err) {
|
|
15
|
+
* handleError(ctx, err, input.flags.json);
|
|
16
|
+
* return { exitCode: 1, result: null };
|
|
17
|
+
* }
|
|
18
|
+
*
|
|
19
|
+
* Extend for your plugin's API error class:
|
|
20
|
+
*
|
|
21
|
+
* import { YourApiError } from '@<%= it.scope ? it.scope + '/' : '' %><%= it.name %>-core';
|
|
22
|
+
* if (err instanceof YourApiError) {
|
|
23
|
+
* const hint = err.status === 401 ? 'Check your API key'
|
|
24
|
+
* : err.status === 404 ? 'Resource not found — verify the ID'
|
|
25
|
+
* : 'API error';
|
|
26
|
+
* if (isJson) {
|
|
27
|
+
* ctx.ui?.json?.({ ok: false, error: { code: err.code, message: err.message, status: err.status, hint } });
|
|
28
|
+
* } else {
|
|
29
|
+
* ctx.ui?.error?.(err.message, { hint, cause: `API ${err.status} (${err.code})` });
|
|
30
|
+
* }
|
|
31
|
+
* return;
|
|
32
|
+
* }
|
|
33
|
+
*/
|
|
34
|
+
export function handleError(ctx: PluginContextV3, err: unknown, isJson?: boolean): void {
|
|
35
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
36
|
+
|
|
37
|
+
if (isJson) {
|
|
38
|
+
ctx.ui?.json?.({ ok: false, error: { code: 'INTERNAL_ERROR', message } });
|
|
39
|
+
} else {
|
|
40
|
+
ctx.ui?.error?.(message);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Output a validation error (missing positional arg or required flag).
|
|
46
|
+
* Call BEFORE the try/catch — this is synchronous and never throws.
|
|
47
|
+
*
|
|
48
|
+
* if (!id) {
|
|
49
|
+
* validationError(ctx, 'id is required', 'Usage: kb <%= it.name %> cmd <id>', input.flags.json);
|
|
50
|
+
* return { exitCode: 1, result: null };
|
|
51
|
+
* }
|
|
52
|
+
*/
|
|
53
|
+
export function validationError(
|
|
54
|
+
ctx: PluginContextV3,
|
|
55
|
+
message: string,
|
|
56
|
+
isJson?: boolean,
|
|
57
|
+
): void {
|
|
58
|
+
if (isJson) {
|
|
59
|
+
ctx.ui?.json?.({ ok: false, error: { code: 'INVALID_ARGS', message } });
|
|
60
|
+
} else {
|
|
61
|
+
ctx.ui?.error?.(message);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -9,11 +9,9 @@ cli:
|
|
|
9
9
|
- name: "<%= it.name %>"
|
|
10
10
|
description: "<%= it.vars.description %>"
|
|
11
11
|
commands:
|
|
12
|
-
-
|
|
13
|
-
group: "<%= it.name %>"
|
|
12
|
+
- path: "<%= it.name %> hello"
|
|
14
13
|
describe: "Say hello from <%= it.name %>"
|
|
15
14
|
handler: "./commands/hello.js#default"
|
|
16
|
-
handlerPath: "./commands/hello.js"
|
|
17
15
|
flags:
|
|
18
16
|
- name: who
|
|
19
17
|
type: string
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { defineCommand, type CLIInput, type PluginContextV3 } from '@kb-labs/sdk';
|
|
2
|
+
import { handleError } from '../utils/error.js';
|
|
2
3
|
|
|
3
4
|
type PingFlags = { json?: boolean };
|
|
4
5
|
|
|
@@ -13,13 +14,20 @@ export default defineCommand({
|
|
|
13
14
|
|
|
14
15
|
handler: {
|
|
15
16
|
async execute(ctx: PluginContextV3, input: CLIInput<PingFlags>) {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
try {
|
|
18
|
+
const payload = { ok: true, at: new Date().toISOString() };
|
|
19
|
+
|
|
20
|
+
if (input.flags.json) {
|
|
21
|
+
ctx.ui?.json?.(payload);
|
|
22
|
+
} else {
|
|
23
|
+
ctx.ui?.info?.(`pong @ ${payload.at}`);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return { exitCode: 0, result: payload };
|
|
27
|
+
} catch (err) {
|
|
28
|
+
handleError(ctx, err, input.flags.json);
|
|
29
|
+
return { exitCode: 1, result: null };
|
|
21
30
|
}
|
|
22
|
-
return { exitCode: 0, result: payload };
|
|
23
31
|
},
|
|
24
32
|
},
|
|
25
33
|
});
|