@kb-labs/scaffold 2.37.0 → 2.39.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.
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as _kb_labs_shared_command_kit from '@kb-labs/shared-command-kit';
|
|
2
|
-
import {
|
|
2
|
+
import { Finding } from '@kb-labs/scaffold-core';
|
|
3
3
|
|
|
4
4
|
interface DoctorFlags {
|
|
5
5
|
path?: string;
|
|
@@ -7,9 +7,7 @@ interface DoctorFlags {
|
|
|
7
7
|
}
|
|
8
8
|
declare const _default: _kb_labs_shared_command_kit.CommandHandlerV3<unknown, DoctorFlags, {
|
|
9
9
|
packagesScanned: number;
|
|
10
|
-
findings:
|
|
11
|
-
findings: infer F;
|
|
12
|
-
} ? F : never : never;
|
|
10
|
+
findings: Finding[];
|
|
13
11
|
}>;
|
|
14
12
|
|
|
15
13
|
export { _default as default };
|
package/dist/commands/doctor.js
CHANGED
|
@@ -3,11 +3,6 @@ import { defineCommand } from '@kb-labs/sdk';
|
|
|
3
3
|
import { scanRoot } from '@kb-labs/scaffold-core';
|
|
4
4
|
|
|
5
5
|
// src/commands/doctor.ts
|
|
6
|
-
var GLYPH = {
|
|
7
|
-
info: "\u2139",
|
|
8
|
-
warn: "\u26A0",
|
|
9
|
-
error: "\u2717"
|
|
10
|
-
};
|
|
11
6
|
var doctor_default = defineCommand({
|
|
12
7
|
id: "scaffold:doctor",
|
|
13
8
|
description: "Scan user-authored plugins for common issues",
|
|
@@ -16,35 +11,49 @@ var doctor_default = defineCommand({
|
|
|
16
11
|
const root = resolve(input.path ?? ".kb/plugins");
|
|
17
12
|
const workspaceRoot = ctx.cwd ?? process.cwd();
|
|
18
13
|
const scan = await scanRoot(root, { workspaceRoot });
|
|
19
|
-
const
|
|
14
|
+
const { errorCount, warnCount } = scan.findings.reduce(
|
|
15
|
+
(acc, f) => {
|
|
16
|
+
if (f.severity === "error") acc.errorCount++;
|
|
17
|
+
else if (f.severity === "warn") acc.warnCount++;
|
|
18
|
+
return acc;
|
|
19
|
+
},
|
|
20
|
+
{ errorCount: 0, warnCount: 0 }
|
|
21
|
+
);
|
|
22
|
+
const hasErrors = errorCount > 0;
|
|
20
23
|
if (input.json) {
|
|
21
24
|
ctx.ui?.json?.({
|
|
22
25
|
root,
|
|
23
26
|
packagesScanned: scan.packagesScanned,
|
|
24
27
|
findings: scan.findings
|
|
25
28
|
});
|
|
29
|
+
} else if (scan.findings.length === 0) {
|
|
30
|
+
ctx.ui?.success?.(`Scanned ${scan.packagesScanned} package(s) \u2014 no issues found.`, {
|
|
31
|
+
title: "scaffold doctor",
|
|
32
|
+
sections: [
|
|
33
|
+
{ items: [`Path: ${root}`] }
|
|
34
|
+
]
|
|
35
|
+
});
|
|
26
36
|
} else {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
37
|
+
const byPkg = /* @__PURE__ */ new Map();
|
|
38
|
+
for (const f of scan.findings) {
|
|
39
|
+
const list = byPkg.get(f.package) ?? [];
|
|
40
|
+
list.push(f);
|
|
41
|
+
byPkg.set(f.package, list);
|
|
42
|
+
}
|
|
43
|
+
const sections = Array.from(byPkg.entries()).map(([pkg, findings]) => ({
|
|
44
|
+
header: pkg,
|
|
45
|
+
items: findings.map((f) => `${f.severity.toUpperCase()} ${f.message}`)
|
|
46
|
+
}));
|
|
47
|
+
if (hasErrors) {
|
|
48
|
+
ctx.ui?.error?.(`Found ${errorCount} error(s), ${warnCount} warning(s) in ${scan.packagesScanned} package(s).`, {
|
|
49
|
+
title: "scaffold doctor",
|
|
50
|
+
sections
|
|
51
|
+
});
|
|
32
52
|
} else {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
byPkg.set(f.package, list);
|
|
38
|
-
}
|
|
39
|
-
for (const [pkg, list] of byPkg) {
|
|
40
|
-
ctx.ui?.info?.(`
|
|
41
|
-
${pkg}`);
|
|
42
|
-
for (const f of list) {
|
|
43
|
-
ctx.ui?.info?.(
|
|
44
|
-
` ${GLYPH[f.severity] ?? "-"} ${f.severity.toUpperCase()}: ${f.message}`
|
|
45
|
-
);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
53
|
+
ctx.ui?.warn?.(`Found ${warnCount} warning(s) in ${scan.packagesScanned} package(s).`, {
|
|
54
|
+
title: "scaffold doctor",
|
|
55
|
+
sections
|
|
56
|
+
});
|
|
48
57
|
}
|
|
49
58
|
}
|
|
50
59
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/commands/doctor.ts"],"names":[],"mappings":";;;;;
|
|
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, 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 const scan = await scanRoot(root, { workspaceRoot });\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"]}
|
|
@@ -4,26 +4,19 @@ import { createRequire } from 'module';
|
|
|
4
4
|
import { readFile, mkdir, writeFile } from 'fs/promises';
|
|
5
5
|
import { createHash } from 'crypto';
|
|
6
6
|
import { defineCommand } from '@kb-labs/sdk';
|
|
7
|
-
import { listEntities,
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
// src/commands/scaffold.ts
|
|
11
|
-
function outro(msg) {
|
|
12
|
-
outro$1(msg);
|
|
13
|
-
}
|
|
14
|
-
function info(msg) {
|
|
15
|
-
log.info(msg);
|
|
16
|
-
}
|
|
17
|
-
function warn(msg) {
|
|
18
|
-
log.warn(msg);
|
|
19
|
-
}
|
|
20
|
-
function error(msg) {
|
|
21
|
-
log.error(msg);
|
|
22
|
-
}
|
|
7
|
+
import { listEntities, runValidator, loadEntity, resolveBlocks, build, inspectTarget, formatTree, writeFiles } from '@kb-labs/scaffold-core';
|
|
8
|
+
import { formatCommandHelp } from '@kb-labs/shared-cli-ui';
|
|
23
9
|
|
|
24
10
|
// src/commands/scaffold.ts
|
|
25
11
|
var here = dirname(fileURLToPath(import.meta.url));
|
|
26
12
|
var TEMPLATES_ROOT = resolve(here, "..", "..", "templates");
|
|
13
|
+
var SCAFFOLD_FLAGS = [
|
|
14
|
+
{ name: "scope", description: "npm scope, e.g. @my-org" },
|
|
15
|
+
{ name: "blocks", description: "comma-separated block ids to include" },
|
|
16
|
+
{ name: "out", description: "custom output directory" },
|
|
17
|
+
{ name: "force", description: "overwrite existing output directory" },
|
|
18
|
+
{ name: "dry-run", description: "preview files without writing" }
|
|
19
|
+
];
|
|
27
20
|
async function readVersion(pkgPath) {
|
|
28
21
|
try {
|
|
29
22
|
const raw = await readFile(pkgPath, "utf8");
|
|
@@ -62,29 +55,44 @@ function parsePositional(argv) {
|
|
|
62
55
|
return { entity: positional[0], name: positional[1] };
|
|
63
56
|
}
|
|
64
57
|
async function runDefault(ctx, rawInput) {
|
|
58
|
+
const start = Date.now();
|
|
65
59
|
const input = { ...rawInput.flags, argv: rawInput.argv };
|
|
66
60
|
const { entity: entityArg, name: nameArg } = parsePositional(input.argv);
|
|
67
61
|
const available = await listEntities(TEMPLATES_ROOT);
|
|
68
62
|
if (available.length === 0) {
|
|
69
|
-
error(
|
|
63
|
+
ctx.ui?.error?.("No scaffold templates found. Reinstall @kb-labs/scaffold.");
|
|
70
64
|
return { exitCode: 1 };
|
|
71
65
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
66
|
+
if (!entityArg) {
|
|
67
|
+
ctx.ui?.write?.(formatCommandHelp({
|
|
68
|
+
title: "kb scaffold run",
|
|
69
|
+
description: "Scaffold a new plugin, adapter, or other entity from a template.",
|
|
70
|
+
examples: available.map((e) => `kb scaffold run ${e} my-${e}`),
|
|
71
|
+
flags: SCAFFOLD_FLAGS
|
|
72
|
+
}) + "\n");
|
|
73
|
+
ctx.ui?.info?.(`Available entities: ${available.join(", ")}`);
|
|
74
|
+
return { exitCode: 1 };
|
|
75
|
+
}
|
|
76
|
+
if (!available.includes(entityArg)) {
|
|
77
|
+
ctx.ui?.error?.(`Unknown entity "${entityArg}". Available: ${available.join(", ")}`);
|
|
75
78
|
return { exitCode: 1 };
|
|
76
79
|
}
|
|
77
|
-
const entity = await loadEntity(TEMPLATES_ROOT, entityId);
|
|
78
80
|
if (!nameArg) {
|
|
79
|
-
|
|
81
|
+
ctx.ui?.write?.(formatCommandHelp({
|
|
82
|
+
title: `kb scaffold run ${entityArg} <name>`,
|
|
83
|
+
description: `Scaffold a new ${entityArg}. Provide a name to continue.`,
|
|
84
|
+
examples: [`kb scaffold run ${entityArg} my-${entityArg}`],
|
|
85
|
+
flags: SCAFFOLD_FLAGS
|
|
86
|
+
}) + "\n");
|
|
80
87
|
return { exitCode: 1 };
|
|
81
88
|
}
|
|
82
89
|
const problem = runValidator("npmName", nameArg);
|
|
83
90
|
if (problem) {
|
|
84
|
-
error(`Invalid name "${nameArg}": ${problem}`);
|
|
91
|
+
ctx.ui?.error?.(`Invalid name "${nameArg}": ${problem}`);
|
|
92
|
+
ctx.ui?.info?.("Name must be lowercase, no spaces, valid npm package name.");
|
|
85
93
|
return { exitCode: 1 };
|
|
86
94
|
}
|
|
87
|
-
const
|
|
95
|
+
const entity = await loadEntity(TEMPLATES_ROOT, entityArg);
|
|
88
96
|
const vars = {};
|
|
89
97
|
for (const v of entity.variables) {
|
|
90
98
|
if (v.name === "scope" && input.scope !== void 0) {
|
|
@@ -104,7 +112,7 @@ async function runDefault(ctx, rawInput) {
|
|
|
104
112
|
try {
|
|
105
113
|
resolveBlocks(entity.blocks, selectedBlocks);
|
|
106
114
|
} catch (e) {
|
|
107
|
-
error(e.message);
|
|
115
|
+
ctx.ui?.error?.(e.message);
|
|
108
116
|
return { exitCode: 1 };
|
|
109
117
|
}
|
|
110
118
|
for (const blockId of selectedBlocks) {
|
|
@@ -117,7 +125,7 @@ async function runDefault(ctx, rawInput) {
|
|
|
117
125
|
const mode = input.mode ?? vars.mode ?? "in-workspace";
|
|
118
126
|
const versions = await detectVersions();
|
|
119
127
|
const context = {
|
|
120
|
-
name,
|
|
128
|
+
name: nameArg,
|
|
121
129
|
scope,
|
|
122
130
|
vars,
|
|
123
131
|
blocks: selectedBlocks,
|
|
@@ -132,46 +140,58 @@ async function runDefault(ctx, rawInput) {
|
|
|
132
140
|
const outRoot = input.out ?? result.outRoot;
|
|
133
141
|
const state = await inspectTarget(outRoot);
|
|
134
142
|
if (input["dry-run"]) {
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
143
|
+
ctx.ui?.success?.("Dry run complete", {
|
|
144
|
+
title: "scaffold run \u2014 dry run",
|
|
145
|
+
sections: [
|
|
146
|
+
{ header: "Would write to", items: [outRoot] },
|
|
147
|
+
{ header: "Files", items: formatTree(result.files).split("\n").filter(Boolean) }
|
|
148
|
+
]
|
|
149
|
+
});
|
|
139
150
|
return { exitCode: 0, result: { outRoot, files: result.files.length } };
|
|
140
151
|
}
|
|
141
152
|
if (state.exists && !state.empty) {
|
|
142
153
|
if (input.force) {
|
|
143
|
-
warn(`--force: overwriting ${outRoot}`);
|
|
154
|
+
ctx.ui?.warn?.(`--force: overwriting ${outRoot}`);
|
|
144
155
|
} else {
|
|
145
|
-
error(`
|
|
156
|
+
ctx.ui?.error?.(`Output directory "${outRoot}" already exists and is not empty.`);
|
|
157
|
+
ctx.ui?.info?.("Use --force to overwrite.");
|
|
146
158
|
return { exitCode: 1 };
|
|
147
159
|
}
|
|
148
160
|
}
|
|
149
161
|
await writeFiles({ outRoot, files: result.files, force: input.force });
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
const
|
|
153
|
-
const
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
162
|
+
const entryPkgDir = entityArg === "plugin" ? `${outRoot}/packages/${nameArg}-entry` : outRoot;
|
|
163
|
+
const linked = await linkWithMarketplace(entryPkgDir);
|
|
164
|
+
const registrationNote = linked === "ok" ? "Registered in .kb/marketplace.lock" : `Not auto-registered \u2014 run: kb marketplace plugins link ${entryPkgDir}`;
|
|
165
|
+
const timing = Date.now() - start;
|
|
166
|
+
ctx.ui?.success?.(`Scaffolded ${entityArg} "${nameArg}"`, {
|
|
167
|
+
title: "scaffold run",
|
|
168
|
+
sections: [
|
|
169
|
+
{
|
|
170
|
+
header: "Output",
|
|
171
|
+
items: [outRoot]
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
header: "Marketplace",
|
|
175
|
+
items: [registrationNote]
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
header: "Next steps",
|
|
179
|
+
items: [
|
|
180
|
+
"pnpm install",
|
|
181
|
+
"pnpm -w build",
|
|
182
|
+
`pnpm kb ${nameArg} hello # try it`,
|
|
183
|
+
`pnpm kb scaffold doctor --path ${dirname(outRoot)}`
|
|
184
|
+
]
|
|
185
|
+
}
|
|
186
|
+
],
|
|
187
|
+
timing
|
|
188
|
+
});
|
|
169
189
|
return {
|
|
170
190
|
exitCode: 0,
|
|
171
191
|
result: { outRoot, files: result.files.length }
|
|
172
192
|
};
|
|
173
193
|
}
|
|
174
|
-
async function linkWithMarketplace(
|
|
194
|
+
async function linkWithMarketplace(entryPkgDir) {
|
|
175
195
|
try {
|
|
176
196
|
const selfPath = fileURLToPath(import.meta.url);
|
|
177
197
|
const nmIdx = selfPath.lastIndexOf("/node_modules/");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/ui/prompt.ts","../../src/commands/scaffold.ts"],"names":["clackOutro","runValidator"],"mappings":"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","file":"scaffold.js","sourcesContent":["import {\n intro as clackIntro,\n outro as clackOutro,\n text,\n confirm,\n select,\n multiselect,\n isCancel,\n cancel,\n log,\n} from '@clack/prompts';\nimport type { Variable } from '@kb-labs/scaffold-contracts';\nimport { runValidator } from '@kb-labs/scaffold-core';\n\nexport function intro(msg: string): void {\n clackIntro(msg);\n}\nexport function outro(msg: string): void {\n clackOutro(msg);\n}\n\nexport function info(msg: string): void {\n log.info(msg);\n}\nexport function warn(msg: string): void {\n log.warn(msg);\n}\nexport function error(msg: string): void {\n log.error(msg);\n}\n\nfunction abortOnCancel<T>(value: T | symbol): T {\n if (isCancel(value)) {\n cancel('Aborted.');\n process.exit(130);\n }\n return value as T;\n}\n\nexport async function askVariable(\n variable: Variable,\n defaults: Record<string, unknown>,\n): Promise<unknown> {\n const preset = defaults[variable.name] ?? variable.default;\n\n switch (variable.type) {\n case 'boolean': {\n const result = await confirm({\n message: variable.describe,\n initialValue: typeof preset === 'boolean' ? preset : false,\n });\n return abortOnCancel(result);\n }\n case 'select': {\n if (!variable.choices || variable.choices.length === 0) {\n throw new Error(`Variable \"${variable.name}\" is select but has no choices`);\n }\n const result = await select({\n message: variable.describe,\n options: variable.choices.map((c) => ({ value: c.value, label: c.label })),\n initialValue: (preset as string) ?? variable.choices[0]?.value,\n });\n return abortOnCancel(result);\n }\n case 'multiselect': {\n if (!variable.choices || variable.choices.length === 0) {\n throw new Error(`Variable \"${variable.name}\" is multiselect but has no choices`);\n }\n const result = await multiselect({\n message: variable.describe,\n options: variable.choices.map((c) => ({ value: c.value, label: c.label })),\n initialValues: Array.isArray(preset) ? (preset as string[]) : [],\n required: false,\n });\n return abortOnCancel(result);\n }\n case 'string':\n default: {\n const result = await text({\n message: variable.describe,\n initialValue: typeof preset === 'string' ? preset : '',\n validate: variable.validate\n ? (value: string) => runValidator(variable.validate!, value) ?? undefined\n : undefined,\n });\n return abortOnCancel(result);\n }\n }\n}\n\nexport async function askBlocks(\n options: { value: string; label: string; hint?: string }[],\n initialValues: string[],\n): Promise<string[]> {\n const result = await multiselect({\n message: 'Pick blocks to include',\n options,\n initialValues,\n required: true,\n });\n return abortOnCancel(result) as string[];\n}\n\nexport async function confirmOverwrite(path: string): Promise<boolean> {\n const result = await confirm({\n message: `Target \"${path}\" is not empty. Overwrite?`,\n initialValue: false,\n });\n return abortOnCancel(result);\n}\n","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 {\n error,\n info,\n outro,\n warn,\n} from '../ui/prompt.js';\n\nconst here = dirname(fileURLToPath(import.meta.url));\nconst TEMPLATES_ROOT = resolve(here, '..', '..', 'templates');\n\ninterface ScaffoldFlags {\n blocks?: string;\n yes?: boolean;\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\n// Conservative fallbacks — bumped when we cut a new scaffold release.\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 // Use require.resolve from this module as the anchor. Works under pnpm's\n // virtual store because createRequire follows node's resolution rules.\n const req = createRequire(import.meta.url);\n const readPkg = async (\n spec: string,\n fallback: string,\n ): 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 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 error(`No entities found in templates root: ${TEMPLATES_ROOT}`);\n return { exitCode: 1 };\n }\n\n // Resolve entity.\n const entityId = entityArg ?? available[0]!;\n if (!available.includes(entityId)) {\n error(`Unknown entity: ${entityId}. Available: ${available.join(', ')}`);\n return { exitCode: 1 };\n }\n\n const entity = await loadEntity(TEMPLATES_ROOT, entityId);\n\n // Resolve name — required positional.\n if (!nameArg) {\n error('Usage: kb scaffold run <entity> <name> [flags]');\n return { exitCode: 1 };\n }\n const problem = runValidator('npmName', nameArg);\n if (problem) {\n error(`Invalid name \"${nameArg}\": ${problem}`);\n return { exitCode: 1 };\n }\n const name = nameArg;\n\n // Collect entity-level variables — flags override, then entity defaults.\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 // Select blocks — flag overrides, then entity defaults.\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 // Collect block-specific variables — use defaults.\n try {\n resolveBlocks(entity.blocks, selectedBlocks);\n } catch (e) {\n error((e as Error).message);\n return { exitCode: 1 };\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,\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 info(`Would write to: ${outRoot}`);\n info('Tree:');\n info(formatTree(result.files));\n outro('Dry run complete.');\n return { exitCode: 0, result: { outRoot, files: result.files.length } };\n }\n\n if (state.exists && !state.empty) {\n if (input.force) {\n warn(`--force: overwriting ${outRoot}`);\n } else {\n error(`Target \"${outRoot}\" 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 ctx.ui?.success?.(`Scaffolded ${entityId} \"${name}\"`);\n info(`Output: ${outRoot}`);\n\n // The package that carries `\"kb\": { \"manifest\": \"...\" }` is the target\n // marketplace.link needs. For plugin entity → <outRoot>/packages/<name>-entry.\n // For adapter entity → <outRoot> itself.\n const entryPkgDir =\n entityId === 'plugin'\n ? `${outRoot}/packages/${name}-entry`\n : outRoot;\n\n const linked = await linkWithMarketplace(ctx, entryPkgDir);\n if (linked === 'ok') {\n info('Registered in .kb/marketplace.lock');\n } else if (linked === 'no-shell') {\n warn('Could not auto-register (no shell). Run manually:');\n info(` kb marketplace plugins link ${entryPkgDir}`);\n } else {\n warn('Auto-register failed — register manually:');\n info(` kb marketplace plugins link ${entryPkgDir}`);\n }\n\n info('Next steps:');\n info(' pnpm install');\n info(' pnpm -w build');\n info(` pnpm kb ${name} hello # try it`);\n info(` pnpm kb scaffold doctor --path ${dirname(outRoot)}`);\n outro('Done.');\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 directly in marketplace.lock.\n *\n * Writes to the platform-level lock file so the CLI picks up the plugin\n * without needing the marketplace service running.\n */\nasync function linkWithMarketplace(\n ctx: PluginContextV3,\n entryPkgDir: string,\n): Promise<LinkOutcome> {\n try {\n // Resolve platform dir from this module's location.\n // Scaffold lives in <platformDir>/node_modules/@kb-labs/scaffold/dist/commands/scaffold.js\n // so we walk up to find the dir containing node_modules.\n const selfPath = fileURLToPath(import.meta.url);\n const nmIdx = selfPath.lastIndexOf('/node_modules/');\n if (nmIdx < 0) return 'failed';\n const platformDir = selfPath.slice(0, nmIdx);\n\n const lockPath = resolve(platformDir, '.kb', 'marketplace.lock');\n\n // Read existing lock or create empty.\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 // Read plugin's package.json for metadata.\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 // Compute integrity hash.\n const hash = createHash('sha256').update(pkgRaw).digest('base64');\n\n // Read manifest to extract provides (best-effort).\n const provides: string[] = ['plugin', 'cli-command'];\n\n // Resolve relative path from platform dir.\n const resolvedPath = relative(platformDir, resolve(entryPkgDir));\n\n // Build the plugin ID: strip -entry suffix for cleaner names.\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 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);\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 '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 directly in marketplace.lock.\n */\nasync function linkWithMarketplace(entryPkgDir: string): Promise<LinkOutcome> {\n try {\n const selfPath = fileURLToPath(import.meta.url);\n const nmIdx = selfPath.lastIndexOf('/node_modules/');\n if (nmIdx < 0) return 'failed';\n const platformDir = selfPath.slice(0, nmIdx);\n\n const lockPath = resolve(platformDir, '.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(platformDir, 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/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.39.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
|
-
"@
|
|
24
|
-
"@kb-labs/
|
|
25
|
-
"@kb-labs/
|
|
26
|
-
"@kb-labs/
|
|
23
|
+
"@kb-labs/scaffold-core": "2.39.0",
|
|
24
|
+
"@kb-labs/shared-cli-ui": "2.39.0",
|
|
25
|
+
"@kb-labs/scaffold-contracts": "2.39.0",
|
|
26
|
+
"@kb-labs/sdk": "2.20.0"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
29
|
"@types/node": "^24.3.3",
|
|
@@ -32,8 +32,8 @@
|
|
|
32
32
|
"tsup": "^8.5.0",
|
|
33
33
|
"typescript": "^5.6.3",
|
|
34
34
|
"vitest": "^3.2.4",
|
|
35
|
-
"@kb-labs/
|
|
36
|
-
"@kb-labs/
|
|
35
|
+
"@kb-labs/devkit": "2.39.0",
|
|
36
|
+
"@kb-labs/plugin-contracts": "2.39.0"
|
|
37
37
|
},
|
|
38
38
|
"engines": {
|
|
39
39
|
"node": ">=20.0.0",
|