@kb-labs/scaffold 2.29.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.
Files changed (59) hide show
  1. package/dist/commands/doctor.d.ts +15 -0
  2. package/dist/commands/doctor.js +63 -0
  3. package/dist/commands/doctor.js.map +1 -0
  4. package/dist/commands/scaffold.d.ts +18 -0
  5. package/dist/commands/scaffold.js +196 -0
  6. package/dist/commands/scaffold.js.map +1 -0
  7. package/dist/index.d.ts +2 -0
  8. package/dist/index.js +114 -0
  9. package/dist/index.js.map +1 -0
  10. package/dist/manifest.d.ts +75 -0
  11. package/dist/manifest.js +114 -0
  12. package/dist/manifest.js.map +1 -0
  13. package/package.json +55 -0
  14. package/templates/adapter/blocks/base/block.yaml +4 -0
  15. package/templates/adapter/blocks/base/files/README.md.eta +28 -0
  16. package/templates/adapter/blocks/base/files/package.json.eta +37 -0
  17. package/templates/adapter/blocks/base/files/src/manifest.ts.eta +24 -0
  18. package/templates/adapter/blocks/base/files/tsconfig.json +8 -0
  19. package/templates/adapter/blocks/base/files/tsup.config.ts +10 -0
  20. package/templates/adapter/blocks/base/files/vitest.config.ts +12 -0
  21. package/templates/adapter/blocks/provider-example/block.yaml +6 -0
  22. package/templates/adapter/blocks/provider-example/files/src/index.ts.eta +6 -0
  23. package/templates/adapter/blocks/provider-example/files/src/llm.ts.eta +46 -0
  24. package/templates/adapter/entity.yaml +37 -0
  25. package/templates/plugin/blocks/base/block.yaml +5 -0
  26. package/templates/plugin/blocks/base/files/README.md.eta +54 -0
  27. package/templates/plugin/blocks/base/files/package.json.eta +14 -0
  28. package/templates/plugin/blocks/base/files/packages/__name__-contracts/package.json.eta +29 -0
  29. package/templates/plugin/blocks/base/files/packages/__name__-contracts/src/index.ts.eta +14 -0
  30. package/templates/plugin/blocks/base/files/packages/__name__-contracts/tsconfig.json +8 -0
  31. package/templates/plugin/blocks/base/files/packages/__name__-contracts/tsup.config.ts +10 -0
  32. package/templates/plugin/blocks/base/files/packages/__name__-contracts/vitest.config.ts +12 -0
  33. package/templates/plugin/blocks/base/files/packages/__name__-core/package.json.eta +33 -0
  34. package/templates/plugin/blocks/base/files/packages/__name__-core/src/hello.ts.eta +59 -0
  35. package/templates/plugin/blocks/base/files/packages/__name__-core/src/index.ts.eta +1 -0
  36. package/templates/plugin/blocks/base/files/packages/__name__-core/tests/hello.test.ts.eta +16 -0
  37. package/templates/plugin/blocks/base/files/packages/__name__-core/tsconfig.json +8 -0
  38. package/templates/plugin/blocks/base/files/packages/__name__-core/tsup.config.ts +10 -0
  39. package/templates/plugin/blocks/base/files/packages/__name__-core/vitest.config.ts +12 -0
  40. package/templates/plugin/blocks/base/files/packages/__name__-entry/eslint.config.js +3 -0
  41. package/templates/plugin/blocks/base/files/packages/__name__-entry/package.json.eta +41 -0
  42. package/templates/plugin/blocks/base/files/packages/__name__-entry/src/commands/hello.ts.eta +39 -0
  43. package/templates/plugin/blocks/base/files/packages/__name__-entry/src/index.ts.eta +4 -0
  44. package/templates/plugin/blocks/base/files/packages/__name__-entry/tsconfig.json +8 -0
  45. package/templates/plugin/blocks/base/files/packages/__name__-entry/tsup.config.ts +10 -0
  46. package/templates/plugin/blocks/base/files/packages/__name__-entry/vitest.config.ts +12 -0
  47. package/templates/plugin/blocks/base/files/pnpm-workspace.yaml.eta +3 -0
  48. package/templates/plugin/blocks/base/files/tsconfig.base.json +3 -0
  49. package/templates/plugin/blocks/base/manifest.patch.yaml +28 -0
  50. package/templates/plugin/blocks/base/manifest.snippets.yaml +4 -0
  51. package/templates/plugin/blocks/cli/block.yaml +5 -0
  52. package/templates/plugin/blocks/cli/files/packages/__name__-entry/src/commands/ping.ts.eta +25 -0
  53. package/templates/plugin/blocks/cli/manifest.patch.yaml +14 -0
  54. package/templates/plugin/blocks/contracts/block.yaml +5 -0
  55. package/templates/plugin/blocks/contracts/files/packages/__name__-contracts/src/events.ts.eta +13 -0
  56. package/templates/plugin/blocks/rest/block.yaml +6 -0
  57. package/templates/plugin/blocks/rest/files/packages/__name__-entry/src/rest/hello.ts.eta +22 -0
  58. package/templates/plugin/blocks/rest/manifest.patch.yaml +9 -0
  59. package/templates/plugin/entity.yaml +39 -0
@@ -0,0 +1,15 @@
1
+ import * as _kb_labs_shared_command_kit from '@kb-labs/shared-command-kit';
2
+ import { scanRoot } from '@kb-labs/scaffold-core';
3
+
4
+ interface DoctorFlags {
5
+ path?: string;
6
+ json?: boolean;
7
+ }
8
+ declare const _default: _kb_labs_shared_command_kit.CommandHandlerV3<unknown, DoctorFlags, {
9
+ packagesScanned: number;
10
+ findings: ReturnType<typeof scanRoot> extends Promise<infer R> ? R extends {
11
+ findings: infer F;
12
+ } ? F : never : never;
13
+ }>;
14
+
15
+ export { _default as default };
@@ -0,0 +1,63 @@
1
+ import { resolve } from 'path';
2
+ import { defineCommand } from '@kb-labs/sdk';
3
+ import { scanRoot } from '@kb-labs/scaffold-core';
4
+
5
+ // src/commands/doctor.ts
6
+ var GLYPH = {
7
+ info: "\u2139",
8
+ warn: "\u26A0",
9
+ error: "\u2717"
10
+ };
11
+ var doctor_default = defineCommand({
12
+ id: "scaffold:doctor",
13
+ description: "Scan user-authored plugins for common issues",
14
+ handler: {
15
+ async execute(ctx, input) {
16
+ const root = resolve(input.path ?? ".kb/plugins");
17
+ const workspaceRoot = ctx.cwd ?? process.cwd();
18
+ const scan = await scanRoot(root, { workspaceRoot });
19
+ const hasErrors = scan.findings.some((f) => f.severity === "error");
20
+ if (input.json) {
21
+ ctx.ui?.json?.({
22
+ root,
23
+ packagesScanned: scan.packagesScanned,
24
+ findings: scan.findings
25
+ });
26
+ } else {
27
+ ctx.ui?.info?.(
28
+ `Scanned ${scan.packagesScanned} package(s) under ${root}`
29
+ );
30
+ if (scan.findings.length === 0) {
31
+ ctx.ui?.success?.("No issues found.");
32
+ } else {
33
+ const byPkg = /* @__PURE__ */ new Map();
34
+ for (const f of scan.findings) {
35
+ const list = byPkg.get(f.package) ?? [];
36
+ list.push(f);
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
+ }
48
+ }
49
+ }
50
+ return {
51
+ exitCode: hasErrors ? 1 : 0,
52
+ result: {
53
+ packagesScanned: scan.packagesScanned,
54
+ findings: scan.findings
55
+ }
56
+ };
57
+ }
58
+ }
59
+ });
60
+
61
+ export { doctor_default as default };
62
+ //# sourceMappingURL=doctor.js.map
63
+ //# sourceMappingURL=doctor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/commands/doctor.ts"],"names":[],"mappings":";;;;;AAqBA,IAAM,KAAA,GAAgC;AAAA,EACpC,IAAA,EAAM,QAAA;AAAA,EACN,IAAA,EAAM,QAAA;AAAA,EACN,KAAA,EAAO;AACT,CAAA;AAEA,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,MAAM,OAAO,MAAM,QAAA,CAAS,IAAA,EAAM,EAAE,eAAe,CAAA;AAEnD,MAAA,MAAM,SAAA,GAAY,KAAK,QAAA,CAAS,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,aAAa,OAAO,CAAA;AAElE,MAAA,IAAI,MAAM,IAAA,EAAM;AACd,QAAA,GAAA,CAAI,IAAI,IAAA,GAAO;AAAA,UACb,IAAA;AAAA,UACA,iBAAiB,IAAA,CAAK,eAAA;AAAA,UACtB,UAAU,IAAA,CAAK;AAAA,SAChB,CAAA;AAAA,MACH,CAAA,MAAO;AACL,QAAA,GAAA,CAAI,EAAA,EAAI,IAAA;AAAA,UACN,CAAA,QAAA,EAAW,IAAA,CAAK,eAAe,CAAA,kBAAA,EAAqB,IAAI,CAAA;AAAA,SAC1D;AACA,QAAA,IAAI,IAAA,CAAK,QAAA,CAAS,MAAA,KAAW,CAAA,EAAG;AAC9B,UAAA,GAAA,CAAI,EAAA,EAAI,UAAU,kBAAkB,CAAA;AAAA,QACtC,CAAA,MAAO;AACL,UAAA,MAAM,KAAA,uBAAY,GAAA,EAAkC;AACpD,UAAA,KAAA,MAAW,CAAA,IAAK,KAAK,QAAA,EAAU;AAC7B,YAAA,MAAM,OAAO,KAAA,CAAM,GAAA,CAAI,CAAA,CAAE,OAAO,KAAK,EAAC;AACtC,YAAA,IAAA,CAAK,KAAK,CAAC,CAAA;AACX,YAAA,KAAA,CAAM,GAAA,CAAI,CAAA,CAAE,OAAA,EAAS,IAAI,CAAA;AAAA,UAC3B;AACA,UAAA,KAAA,MAAW,CAAC,GAAA,EAAK,IAAI,CAAA,IAAK,KAAA,EAAO;AAC/B,YAAA,GAAA,CAAI,IAAI,IAAA,GAAO;AAAA,EAAA,EAAO,GAAG,CAAA,CAAE,CAAA;AAC3B,YAAA,KAAA,MAAW,KAAK,IAAA,EAAM;AACpB,cAAA,GAAA,CAAI,EAAA,EAAI,IAAA;AAAA,gBACN,CAAA,IAAA,EAAO,KAAA,CAAM,CAAA,CAAE,QAAQ,CAAA,IAAK,GAAG,CAAA,CAAA,EAAI,CAAA,CAAE,QAAA,CAAS,WAAA,EAAa,CAAA,EAAA,EAAK,EAAE,OAAO,CAAA;AAAA,eAC3E;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAEA,MAAA,OAAO;AAAA,QACL,QAAA,EAAU,YAAY,CAAA,GAAI,CAAA;AAAA,QAC1B,MAAA,EAAQ;AAAA,UACN,iBAAiB,IAAA,CAAK,eAAA;AAAA,UACtB,UAAU,IAAA,CAAK;AAAA;AACjB,OACF;AAAA,IACF;AAAA;AAEJ,CAAC","file":"doctor.js","sourcesContent":["import { resolve } from 'node:path';\nimport { defineCommand, type PluginContextV3 } from '@kb-labs/sdk';\nimport { scanRoot } 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: ReturnType<typeof scanRoot> extends Promise<infer R>\n ? R extends { findings: infer F }\n ? F\n : never\n : never;\n };\n};\n\nconst GLYPH: Record<string, string> = {\n info: 'ℹ',\n warn: '⚠',\n error: '✗',\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 hasErrors = scan.findings.some((f) => f.severity === 'error');\n\n if (input.json) {\n ctx.ui?.json?.({\n root,\n packagesScanned: scan.packagesScanned,\n findings: scan.findings,\n });\n } else {\n ctx.ui?.info?.(\n `Scanned ${scan.packagesScanned} package(s) under ${root}`,\n );\n if (scan.findings.length === 0) {\n ctx.ui?.success?.('No issues found.');\n } else {\n const byPkg = new Map<string, typeof scan.findings>();\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 for (const [pkg, list] of byPkg) {\n ctx.ui?.info?.(`\\n ${pkg}`);\n for (const f of list) {\n ctx.ui?.info?.(\n ` ${GLYPH[f.severity] ?? '-'} ${f.severity.toUpperCase()}: ${f.message}`,\n );\n }\n }\n }\n }\n\n return {\n exitCode: hasErrors ? 1 : 0,\n result: {\n packagesScanned: scan.packagesScanned,\n findings: scan.findings,\n } as never,\n };\n },\n },\n});\n"]}
@@ -0,0 +1,18 @@
1
+ import * as _kb_labs_shared_command_kit from '@kb-labs/shared-command-kit';
2
+
3
+ interface ScaffoldFlags {
4
+ blocks?: string;
5
+ yes?: boolean;
6
+ force?: boolean;
7
+ 'dry-run'?: boolean;
8
+ out?: string;
9
+ scope?: string;
10
+ mode?: string;
11
+ argv?: string[];
12
+ }
13
+ declare const _default: _kb_labs_shared_command_kit.CommandHandlerV3<unknown, ScaffoldFlags, {
14
+ outRoot: string;
15
+ files: number;
16
+ }>;
17
+
18
+ export { _default as default };
@@ -0,0 +1,196 @@
1
+ import { dirname, resolve } from 'path';
2
+ import { fileURLToPath } from 'url';
3
+ import { createRequire } from 'module';
4
+ import { readFile } from 'fs/promises';
5
+ import { defineCommand } from '@kb-labs/sdk';
6
+ import { listEntities, loadEntity, runValidator, resolveBlocks, build, inspectTarget, formatTree, writeFiles } from '@kb-labs/scaffold-core';
7
+ import { log, outro as outro$1 } from '@clack/prompts';
8
+
9
+ // src/commands/scaffold.ts
10
+ function outro(msg) {
11
+ outro$1(msg);
12
+ }
13
+ function info(msg) {
14
+ log.info(msg);
15
+ }
16
+ function warn(msg) {
17
+ log.warn(msg);
18
+ }
19
+ function error(msg) {
20
+ log.error(msg);
21
+ }
22
+
23
+ // src/commands/scaffold.ts
24
+ var here = dirname(fileURLToPath(import.meta.url));
25
+ var TEMPLATES_ROOT = resolve(here, "..", "..", "templates");
26
+ async function readVersion(pkgPath) {
27
+ try {
28
+ const raw = await readFile(pkgPath, "utf8");
29
+ const parsed = JSON.parse(raw);
30
+ return parsed.version ?? "0.0.0";
31
+ } catch {
32
+ return "0.0.0";
33
+ }
34
+ }
35
+ var FALLBACK_VERSIONS = {
36
+ sdk: "2.18.0",
37
+ devkit: "2.28.0"
38
+ };
39
+ async function detectVersions() {
40
+ const req = createRequire(import.meta.url);
41
+ const readPkg = async (spec, fallback) => {
42
+ try {
43
+ const resolved = req.resolve(spec);
44
+ const v = await readVersion(resolved);
45
+ return v === "0.0.0" ? fallback : v;
46
+ } catch {
47
+ return fallback;
48
+ }
49
+ };
50
+ const [sdk, devkit] = await Promise.all([
51
+ readPkg("@kb-labs/sdk/package.json", FALLBACK_VERSIONS.sdk),
52
+ readPkg("@kb-labs/devkit/package.json", FALLBACK_VERSIONS.devkit)
53
+ ]);
54
+ return { sdk, devkit };
55
+ }
56
+ function parsePositional(argv) {
57
+ if (!argv || argv.length === 0) return {};
58
+ const positional = argv.filter((a) => !a.startsWith("-"));
59
+ return { entity: positional[0], name: positional[1] };
60
+ }
61
+ async function runDefault(ctx, input) {
62
+ const { entity: entityArg, name: nameArg } = parsePositional(input.argv);
63
+ const available = await listEntities(TEMPLATES_ROOT);
64
+ if (available.length === 0) {
65
+ error(`No entities found in templates root: ${TEMPLATES_ROOT}`);
66
+ return { exitCode: 1 };
67
+ }
68
+ const entityId = entityArg ?? available[0];
69
+ if (!available.includes(entityId)) {
70
+ error(`Unknown entity: ${entityId}. Available: ${available.join(", ")}`);
71
+ return { exitCode: 1 };
72
+ }
73
+ const entity = await loadEntity(TEMPLATES_ROOT, entityId);
74
+ if (!nameArg) {
75
+ error("Usage: kb scaffold run <entity> <name> [flags]");
76
+ return { exitCode: 1 };
77
+ }
78
+ const problem = runValidator("npmName", nameArg);
79
+ if (problem) {
80
+ error(`Invalid name "${nameArg}": ${problem}`);
81
+ return { exitCode: 1 };
82
+ }
83
+ const name = nameArg;
84
+ const vars = {};
85
+ for (const v of entity.variables) {
86
+ if (v.name === "scope" && input.scope !== void 0) {
87
+ vars[v.name] = input.scope;
88
+ } else if (v.name === "mode" && input.mode !== void 0) {
89
+ vars[v.name] = input.mode;
90
+ } else {
91
+ vars[v.name] = v.default ?? "";
92
+ }
93
+ }
94
+ let selectedBlocks;
95
+ if (input.blocks) {
96
+ selectedBlocks = input.blocks.split(",").map((s) => s.trim()).filter(Boolean);
97
+ } else {
98
+ selectedBlocks = entity.defaults?.blocks ?? entity.blocks.map((b) => b.id);
99
+ }
100
+ try {
101
+ resolveBlocks(entity.blocks, selectedBlocks);
102
+ } catch (e) {
103
+ error(e.message);
104
+ return { exitCode: 1 };
105
+ }
106
+ for (const blockId of selectedBlocks) {
107
+ const block = entity.blocks.find((b) => b.id === blockId);
108
+ for (const v of block?.variables ?? []) {
109
+ vars[v.name] = v.default ?? "";
110
+ }
111
+ }
112
+ const scope = vars.scope ?? input.scope ?? "";
113
+ const mode = vars.mode ?? "in-workspace";
114
+ const versions = await detectVersions();
115
+ const context = {
116
+ name,
117
+ scope,
118
+ vars,
119
+ blocks: selectedBlocks,
120
+ mode,
121
+ versions
122
+ };
123
+ const result = await build({
124
+ entity,
125
+ selectedBlockIds: selectedBlocks,
126
+ context
127
+ });
128
+ const outRoot = input.out ?? result.outRoot;
129
+ const state = await inspectTarget(outRoot);
130
+ if (input["dry-run"]) {
131
+ info(`Would write to: ${outRoot}`);
132
+ info("Tree:");
133
+ info(formatTree(result.files));
134
+ outro("Dry run complete.");
135
+ return { exitCode: 0, result: { outRoot, files: result.files.length } };
136
+ }
137
+ if (state.exists && !state.empty) {
138
+ if (input.force) {
139
+ warn(`--force: overwriting ${outRoot}`);
140
+ } else {
141
+ error(`Target "${outRoot}" is not empty. Use --force to overwrite.`);
142
+ return { exitCode: 1 };
143
+ }
144
+ }
145
+ await writeFiles({ outRoot, files: result.files, force: input.force });
146
+ ctx.ui?.success?.(`Scaffolded ${entityId} "${name}"`);
147
+ info(`Output: ${outRoot}`);
148
+ const entryPkgDir = entityId === "plugin" ? `${outRoot}/packages/${name}-entry` : outRoot;
149
+ const linked = await linkWithMarketplace(ctx, entryPkgDir);
150
+ if (linked === "ok") {
151
+ info("Registered in .kb/marketplace.lock");
152
+ } else if (linked === "no-shell") {
153
+ warn("Could not auto-register (no shell). Run manually:");
154
+ info(` kb marketplace plugins link ${entryPkgDir}`);
155
+ } else {
156
+ warn("Auto-register failed \u2014 register manually:");
157
+ info(` kb marketplace plugins link ${entryPkgDir}`);
158
+ }
159
+ info("Next steps:");
160
+ info(" pnpm install");
161
+ info(" pnpm -w build");
162
+ info(` pnpm kb ${name} hello # try it`);
163
+ info(` pnpm kb scaffold doctor --path ${dirname(outRoot)}`);
164
+ outro("Done.");
165
+ return {
166
+ exitCode: 0,
167
+ result: { outRoot, files: result.files.length }
168
+ };
169
+ }
170
+ async function linkWithMarketplace(ctx, entryPkgDir) {
171
+ const shell = ctx.api?.shell;
172
+ if (!shell?.exec) {
173
+ return "no-shell";
174
+ }
175
+ try {
176
+ const res = await shell.exec(
177
+ "kb",
178
+ ["marketplace", "plugins", "link", entryPkgDir],
179
+ { timeout: 6e4 }
180
+ );
181
+ return res.ok ? "ok" : "failed";
182
+ } catch {
183
+ return "failed";
184
+ }
185
+ }
186
+ var scaffold_default = defineCommand({
187
+ id: "scaffold:run",
188
+ description: "Scaffold <entity> <name> from blocks",
189
+ handler: {
190
+ execute: runDefault
191
+ }
192
+ });
193
+
194
+ export { scaffold_default as default };
195
+ //# sourceMappingURL=scaffold.js.map
196
+ //# sourceMappingURL=scaffold.js.map
@@ -0,0 +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 } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { createRequire } from 'node:module';\nimport { readFile } from 'node:fs/promises';\nimport {\n defineCommand,\n type PluginContextV3,\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 argv?: 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} 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] = await Promise.all([\n readPkg('@kb-labs/sdk/package.json', FALLBACK_VERSIONS.sdk),\n readPkg('@kb-labs/devkit/package.json', FALLBACK_VERSIONS.devkit),\n ]);\n return { sdk, devkit };\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 input: ScaffoldFlags,\n): Promise<ScaffoldResult> {\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 = ((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\nasync function linkWithMarketplace(\n ctx: PluginContextV3,\n entryPkgDir: string,\n): Promise<LinkOutcome> {\n const shell = ctx.api?.shell;\n if (!shell?.exec) {\n return 'no-shell';\n }\n try {\n const res = await shell.exec(\n 'kb',\n ['marketplace', 'plugins', 'link', entryPkgDir],\n { timeout: 60_000 },\n );\n return res.ok ? 'ok' : 'failed';\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"]}
@@ -0,0 +1,2 @@
1
+ export { default as manifest } from './manifest.js';
2
+ import '@kb-labs/perm-presets';
package/dist/index.js ADDED
@@ -0,0 +1,114 @@
1
+ import { combinePermissions, kbPlatformPreset } from '@kb-labs/sdk';
2
+
3
+ // src/manifest.ts
4
+ var permissions = combinePermissions().with(kbPlatformPreset).withFs({
5
+ mode: "readWrite",
6
+ allow: [
7
+ ".kb/plugins/**",
8
+ ".kb/marketplace.lock",
9
+ "plugins/**",
10
+ "adapters/**"
11
+ ]
12
+ }).withShell({
13
+ // Needed to call `kb marketplace plugins link` after scaffolding,
14
+ // so the generated plugin lands in .kb/marketplace.lock automatically.
15
+ allow: ["kb"]
16
+ }).withQuotas({ timeoutMs: 12e4, memoryMb: 256 }).build();
17
+ var manifest = {
18
+ schema: "kb.plugin/3",
19
+ id: "@kb-labs/scaffold",
20
+ version: "0.1.0",
21
+ display: {
22
+ name: "Scaffold",
23
+ description: "Generic entity scaffolder for KB Labs plugins, adapters, and friends.",
24
+ tags: ["scaffold", "generator", "dx"]
25
+ },
26
+ cli: {
27
+ groupMeta: [
28
+ { name: "scaffold", describe: "Scaffold KB Labs entities" }
29
+ ],
30
+ commands: [
31
+ {
32
+ id: "run",
33
+ group: "scaffold",
34
+ describe: "Scaffold <entity> <name> from blocks",
35
+ handler: "./commands/scaffold.js#default",
36
+ handlerPath: "./commands/scaffold.js",
37
+ flags: [
38
+ {
39
+ name: "blocks",
40
+ type: "string",
41
+ description: "Comma-separated block ids"
42
+ },
43
+ {
44
+ name: "yes",
45
+ alias: "y",
46
+ type: "boolean",
47
+ description: "Accept defaults and skip prompts"
48
+ },
49
+ {
50
+ name: "force",
51
+ type: "boolean",
52
+ description: "Overwrite non-empty target directory"
53
+ },
54
+ {
55
+ name: "dry-run",
56
+ type: "boolean",
57
+ description: "Print the tree that would be written and exit"
58
+ },
59
+ {
60
+ name: "out",
61
+ type: "string",
62
+ description: "Override the output directory"
63
+ },
64
+ {
65
+ name: "scope",
66
+ type: "string",
67
+ description: "npm scope for the generated package"
68
+ },
69
+ {
70
+ name: "mode",
71
+ type: "string",
72
+ description: 'Layout mode: "in-workspace" (workspace:* deps) or "standalone" (semver deps + pnpm-workspace.yaml)'
73
+ }
74
+ ],
75
+ examples: [
76
+ "kb scaffold run plugin my-plugin",
77
+ "kb scaffold run adapter my-llm --blocks base",
78
+ "kb scaffold run plugin ui --scope @acme --yes",
79
+ "kb scaffold run plugin demo --dry-run"
80
+ ]
81
+ },
82
+ {
83
+ id: "doctor",
84
+ group: "scaffold",
85
+ describe: "Scan user plugins for common issues",
86
+ handler: "./commands/doctor.js#default",
87
+ handlerPath: "./commands/doctor.js",
88
+ flags: [
89
+ {
90
+ name: "path",
91
+ type: "string",
92
+ description: "Path to scan (default: .kb/plugins)"
93
+ },
94
+ {
95
+ name: "json",
96
+ type: "boolean",
97
+ description: "Emit JSON instead of text"
98
+ }
99
+ ],
100
+ examples: [
101
+ "kb scaffold doctor",
102
+ "kb scaffold doctor --path ./plugins",
103
+ "kb scaffold doctor --json"
104
+ ]
105
+ }
106
+ ]
107
+ },
108
+ permissions
109
+ };
110
+ var manifest_default = manifest;
111
+
112
+ export { manifest_default as manifest };
113
+ //# sourceMappingURL=index.js.map
114
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/manifest.ts"],"names":[],"mappings":"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","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:\n 'Generic entity scaffolder for KB Labs plugins, adapters, and friends.',\n tags: ['scaffold', 'generator', 'dx'],\n },\n cli: {\n groupMeta: [\n { name: 'scaffold', describe: 'Scaffold KB Labs entities' },\n ],\n commands: [\n {\n id: 'run',\n group: 'scaffold',\n describe: 'Scaffold <entity> <name> from blocks',\n handler: './commands/scaffold.js#default',\n handlerPath: './commands/scaffold.js',\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 id: 'doctor',\n group: 'scaffold',\n describe: 'Scan user plugins for common issues',\n handler: './commands/doctor.js#default',\n handlerPath: './commands/doctor.js',\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"]}
@@ -0,0 +1,75 @@
1
+ import * as _kb_labs_perm_presets from '@kb-labs/perm-presets';
2
+
3
+ declare const manifest: {
4
+ readonly schema: "kb.plugin/3";
5
+ readonly id: "@kb-labs/scaffold";
6
+ readonly version: "0.1.0";
7
+ readonly display: {
8
+ readonly name: "Scaffold";
9
+ readonly description: "Generic entity scaffolder for KB Labs plugins, adapters, and friends.";
10
+ readonly tags: readonly ["scaffold", "generator", "dx"];
11
+ };
12
+ readonly cli: {
13
+ readonly groupMeta: readonly [{
14
+ readonly name: "scaffold";
15
+ readonly describe: "Scaffold KB Labs entities";
16
+ }];
17
+ readonly commands: readonly [{
18
+ readonly id: "run";
19
+ readonly group: "scaffold";
20
+ readonly describe: "Scaffold <entity> <name> from blocks";
21
+ readonly handler: "./commands/scaffold.js#default";
22
+ readonly handlerPath: "./commands/scaffold.js";
23
+ readonly flags: readonly [{
24
+ readonly name: "blocks";
25
+ readonly type: "string";
26
+ readonly description: "Comma-separated block ids";
27
+ }, {
28
+ readonly name: "yes";
29
+ readonly alias: "y";
30
+ readonly type: "boolean";
31
+ readonly description: "Accept defaults and skip prompts";
32
+ }, {
33
+ readonly name: "force";
34
+ readonly type: "boolean";
35
+ readonly description: "Overwrite non-empty target directory";
36
+ }, {
37
+ readonly name: "dry-run";
38
+ readonly type: "boolean";
39
+ readonly description: "Print the tree that would be written and exit";
40
+ }, {
41
+ readonly name: "out";
42
+ readonly type: "string";
43
+ readonly description: "Override the output directory";
44
+ }, {
45
+ readonly name: "scope";
46
+ readonly type: "string";
47
+ readonly description: "npm scope for the generated package";
48
+ }, {
49
+ readonly name: "mode";
50
+ readonly type: "string";
51
+ readonly description: "Layout mode: \"in-workspace\" (workspace:* deps) or \"standalone\" (semver deps + pnpm-workspace.yaml)";
52
+ }];
53
+ 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
+ }, {
55
+ readonly id: "doctor";
56
+ readonly group: "scaffold";
57
+ readonly describe: "Scan user plugins for common issues";
58
+ readonly handler: "./commands/doctor.js#default";
59
+ readonly handlerPath: "./commands/doctor.js";
60
+ readonly flags: readonly [{
61
+ readonly name: "path";
62
+ readonly type: "string";
63
+ readonly description: "Path to scan (default: .kb/plugins)";
64
+ }, {
65
+ readonly name: "json";
66
+ readonly type: "boolean";
67
+ readonly description: "Emit JSON instead of text";
68
+ }];
69
+ readonly examples: readonly ["kb scaffold doctor", "kb scaffold doctor --path ./plugins", "kb scaffold doctor --json"];
70
+ }];
71
+ };
72
+ readonly permissions: _kb_labs_perm_presets.RuntimePermissionSpec;
73
+ };
74
+
75
+ export { manifest as default };
@@ -0,0 +1,114 @@
1
+ import { combinePermissions, kbPlatformPreset } from '@kb-labs/sdk';
2
+
3
+ // src/manifest.ts
4
+ var permissions = combinePermissions().with(kbPlatformPreset).withFs({
5
+ mode: "readWrite",
6
+ allow: [
7
+ ".kb/plugins/**",
8
+ ".kb/marketplace.lock",
9
+ "plugins/**",
10
+ "adapters/**"
11
+ ]
12
+ }).withShell({
13
+ // Needed to call `kb marketplace plugins link` after scaffolding,
14
+ // so the generated plugin lands in .kb/marketplace.lock automatically.
15
+ allow: ["kb"]
16
+ }).withQuotas({ timeoutMs: 12e4, memoryMb: 256 }).build();
17
+ var manifest = {
18
+ schema: "kb.plugin/3",
19
+ id: "@kb-labs/scaffold",
20
+ version: "0.1.0",
21
+ display: {
22
+ name: "Scaffold",
23
+ description: "Generic entity scaffolder for KB Labs plugins, adapters, and friends.",
24
+ tags: ["scaffold", "generator", "dx"]
25
+ },
26
+ cli: {
27
+ groupMeta: [
28
+ { name: "scaffold", describe: "Scaffold KB Labs entities" }
29
+ ],
30
+ commands: [
31
+ {
32
+ id: "run",
33
+ group: "scaffold",
34
+ describe: "Scaffold <entity> <name> from blocks",
35
+ handler: "./commands/scaffold.js#default",
36
+ handlerPath: "./commands/scaffold.js",
37
+ flags: [
38
+ {
39
+ name: "blocks",
40
+ type: "string",
41
+ description: "Comma-separated block ids"
42
+ },
43
+ {
44
+ name: "yes",
45
+ alias: "y",
46
+ type: "boolean",
47
+ description: "Accept defaults and skip prompts"
48
+ },
49
+ {
50
+ name: "force",
51
+ type: "boolean",
52
+ description: "Overwrite non-empty target directory"
53
+ },
54
+ {
55
+ name: "dry-run",
56
+ type: "boolean",
57
+ description: "Print the tree that would be written and exit"
58
+ },
59
+ {
60
+ name: "out",
61
+ type: "string",
62
+ description: "Override the output directory"
63
+ },
64
+ {
65
+ name: "scope",
66
+ type: "string",
67
+ description: "npm scope for the generated package"
68
+ },
69
+ {
70
+ name: "mode",
71
+ type: "string",
72
+ description: 'Layout mode: "in-workspace" (workspace:* deps) or "standalone" (semver deps + pnpm-workspace.yaml)'
73
+ }
74
+ ],
75
+ examples: [
76
+ "kb scaffold run plugin my-plugin",
77
+ "kb scaffold run adapter my-llm --blocks base",
78
+ "kb scaffold run plugin ui --scope @acme --yes",
79
+ "kb scaffold run plugin demo --dry-run"
80
+ ]
81
+ },
82
+ {
83
+ id: "doctor",
84
+ group: "scaffold",
85
+ describe: "Scan user plugins for common issues",
86
+ handler: "./commands/doctor.js#default",
87
+ handlerPath: "./commands/doctor.js",
88
+ flags: [
89
+ {
90
+ name: "path",
91
+ type: "string",
92
+ description: "Path to scan (default: .kb/plugins)"
93
+ },
94
+ {
95
+ name: "json",
96
+ type: "boolean",
97
+ description: "Emit JSON instead of text"
98
+ }
99
+ ],
100
+ examples: [
101
+ "kb scaffold doctor",
102
+ "kb scaffold doctor --path ./plugins",
103
+ "kb scaffold doctor --json"
104
+ ]
105
+ }
106
+ ]
107
+ },
108
+ permissions
109
+ };
110
+ var manifest_default = manifest;
111
+
112
+ export { manifest_default as default };
113
+ //# sourceMappingURL=manifest.js.map
114
+ //# sourceMappingURL=manifest.js.map