@wrongstack/tools 0.5.6 → 0.6.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/dist/bash.d.ts +2 -1
- package/dist/bash.js +361 -3
- package/dist/bash.js.map +1 -1
- package/dist/builtin.js +408 -12
- package/dist/builtin.js.map +1 -1
- package/dist/circuit-breaker.d.ts +111 -0
- package/dist/circuit-breaker.js +150 -0
- package/dist/circuit-breaker.js.map +1 -0
- package/dist/exec.js +355 -4
- package/dist/exec.js.map +1 -1
- package/dist/fetch.js.map +1 -1
- package/dist/grep.js +9 -4
- package/dist/grep.js.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.js +412 -13
- package/dist/index.js.map +1 -1
- package/dist/logs.js +9 -4
- package/dist/logs.js.map +1 -1
- package/dist/pack.js +408 -12
- package/dist/pack.js.map +1 -1
- package/dist/process-registry.d.ts +112 -0
- package/dist/process-registry.js +327 -0
- package/dist/process-registry.js.map +1 -0
- package/dist/replace.js +9 -4
- package/dist/replace.js.map +1 -1
- package/dist/scaffold.js +2 -1
- package/dist/scaffold.js.map +1 -1
- package/package.json +10 -2
package/dist/scaffold.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/_util.ts","../src/scaffold.ts"],"names":["path2"],"mappings":";;;;AAGO,SAAS,WAAA,CAAY,OAAe,GAAA,EAAsB;AAC/D,EAAA,OAAY,IAAA,CAAA,UAAA,CAAW,KAAK,CAAA,GAAS,IAAA,CAAA,SAAA,CAAU,KAAK,CAAA,GAAS,IAAA,CAAA,OAAA,CAAQ,GAAA,CAAI,GAAA,EAAK,KAAK,CAAA;AACrF;AAEO,SAAS,gBAAA,CAAiB,SAAiB,GAAA,EAAsB;AACtE,EAAA,MAAM,IAAA,GAAY,IAAA,CAAA,OAAA,CAAQ,GAAA,CAAI,WAAW,CAAA;AACzC,EAAA,MAAM,MAAA,GAAc,aAAQ,OAAO,CAAA;AACnC,EAAA,MAAM,GAAA,GAAW,IAAA,CAAA,QAAA,CAAS,IAAA,EAAM,MAAM,CAAA;AACtC,EAAA,IAAI,IAAI,UAAA,CAAW,IAAI,CAAA,IAAU,IAAA,CAAA,UAAA,CAAW,GAAG,CAAA,EAAG;AAChD,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,MAAA,EAAS,OAAO,CAAA,2BAAA,EAA8B,IAAI,CAAA,CAAA,CAAG,CAAA;AAAA,EACvE;AACA,EAAA,OAAO,MAAA;AACT;AAEO,SAAS,WAAA,CAAY,OAAe,GAAA,EAAsB;AAC/D,EAAA,OAAO,gBAAA,CAAiB,WAAA,CAAY,KAAA,EAAO,GAAG,GAAG,GAAG,CAAA;AACtD;;;ACGA,IAAM,kBAAA,GAA6F;AAAA,EACjG,aAAA,EAAe;AAAA,IACb,WAAA,EAAa,4BAAA;AAAA,IACb,KAAA,EAAO;AAAA,MACL,gBAAgB,IAAA,CAAK,SAAA;AAAA,QACnB;AAAA,UACE,IAAA,EAAM,UAAA;AAAA,UACN,OAAA,EAAS,OAAA;AAAA,UACT,IAAA,EAAM,QAAA;AAAA,UACN,IAAA,EAAM,iBAAA;AAAA,UACN,OAAA,EAAS,EAAE,KAAA,EAAO,KAAA,EAAO,MAAM,YAAA,EAAa;AAAA,UAC5C,eAAA,EAAiB,EAAE,UAAA,EAAY,QAAA;AAAS,SAC1C;AAAA,QACA,IAAA;AAAA,QACA;AAAA,OACF;AAAA,MACA,iBAAiB,IAAA,CAAK,SAAA;AAAA,QACpB;AAAA,UACE,iBAAiB,EAAE,MAAA,EAAQ,UAAU,MAAA,EAAQ,QAAA,EAAU,QAAQ,IAAA,EAAK;AAAA,UACpE,OAAA,EAAS,CAAC,KAAK;AAAA,SACjB;AAAA,QACA,IAAA;AAAA,QACA;AAAA,OACF;AAAA,MACA,cAAA,EAAgB,CAAA;AAAA;AAAA;AAAA,CAAA;AAAA,MAChB,mBAAA,EAAqB,CAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACvB,GACF;AAAA,EACA,UAAA,EAAY;AAAA,IACV,WAAA,EAAa,wBAAA;AAAA,IACb,KAAA,EAAO;AAAA,MACL,gBAAgB,IAAA,CAAK,SAAA;AAAA,QACnB;AAAA,UACE,IAAA,EAAM,UAAA;AAAA,UACN,OAAA,EAAS,OAAA;AAAA,UACT,IAAA,EAAM,QAAA;AAAA,UACN,GAAA,EAAK,EAAE,UAAA,EAAY,gBAAA,EAAiB;AAAA,UACpC,OAAA,EAAS,EAAE,KAAA,EAAO,KAAA,EAAO,OAAO,oBAAA;AAAqB,SACvD;AAAA,QACA,IAAA;AAAA,QACA;AAAA,OACF;AAAA,MACA,cAAA,EAAgB,CAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAClB,GACF;AAAA,EACA,iBAAA,EAAmB;AAAA,IACjB,WAAA,EAAa,iCAAA;AAAA,IACb,KAAA,EAAO;AAAA,MACL,cAAA,EAAgB,CAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAAA;AAAA,MAChB,mBAAA,EAAqB,CAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACvB;AAEJ,CAAA;AAEO,IAAM,YAAA,GAAoD;AAAA,EAC/D,IAAA,EAAM,UAAA;AAAA,EACN,QAAA,EAAU,SAAA;AAAA,EACV,WAAA,EACE,wGAAA;AAAA,EACF,SAAA,EACE,uHAAA;AAAA,EACF,UAAA,EAAY,SAAA;AAAA,EACZ,QAAA,EAAU,IAAA;AAAA,EACV,SAAA,EAAW,GAAA;AAAA,EACX,WAAA,EAAa;AAAA,IACX,IAAA,EAAM,QAAA;AAAA,IACN,UAAA,EAAY;AAAA,MACV,QAAA,EAAU;AAAA,QACR,IAAA,EAAM,QAAA;AAAA,QACN,WAAA,EACE;AAAA,OACJ;AAAA,MACA,IAAA,EAAM;AAAA,QACJ,IAAA,EAAM,QAAA;AAAA,QACN,WAAA,EAAa;AAAA,OACf;AAAA,MACA,GAAA,EAAK,EAAE,IAAA,EAAM,QAAA,EAAU,aAAa,kCAAA,EAAmC;AAAA,MACvE,IAAA,EAAM;AAAA,QACJ,IAAA,EAAM,QAAA;AAAA,QACN,oBAAA,EAAsB,EAAE,IAAA,EAAM,QAAA,EAAS;AAAA,QACvC,WAAA,EAAa;AAAA,OACf;AAAA,MACA,OAAA,EAAS;AAAA,QACP,IAAA,EAAM,SAAA;AAAA,QACN,WAAA,EAAa;AAAA;AACf,KACF;AAAA,IACA,QAAA,EAAU,CAAC,UAAA,EAAY,MAAM;AAAA,GAC/B;AAAA,EACA,MAAM,OAAA,CAAQ,KAAA,EAAO,GAAA,EAAK;AACxB,IAAA,MAAM,GAAA,GAAM,MAAM,GAAA,GAAM,WAAA,CAAY,MAAM,GAAA,EAAK,GAAG,IAAI,GAAA,CAAI,GAAA;AAC1D,IAAA,MAAM,OAAO,KAAA,CAAM,IAAA;AACnB,IAAA,MAAM,IAAA,GAAO,EAAE,IAAA,EAAM,GAAG,MAAM,IAAA,EAAK;AAEnC,IAAA,MAAM,OAAA,GAAU,kBAAA,CAAmB,KAAA,CAAM,QAAQ,CAAA;AACjD,IAAA,IAAI,OAAA,EAAS;AACX,MAAA,OAAO,MAAM,aAAA,CAAc,IAAA,EAAM,OAAA,CAAQ,KAAA,EAAO,KAAK,GAAA,EAAK,KAAA,CAAM,OAAA,IAAW,KAAA,EAAO,IAAI,CAAA;AAAA,IACxF;AAEA,IAAA,OAAO;AAAA,MACL,UAAU,KAAA,CAAM,QAAA;AAAA,MAChB,IAAA;AAAA,MACA,aAAA,EAAe,CAAA;AAAA,MACf,OAAO,EAAC;AAAA,MACR,OAAA,EAAS,MAAM,OAAA,IAAW,KAAA;AAAA,MAC1B,MAAA,EAAQ,CAAA,UAAA,EAAa,KAAA,CAAM,QAAQ,CAAA,wBAAA,EAA2B,MAAA,CAAO,IAAA,CAAK,kBAAkB,CAAA,CAAE,IAAA,CAAK,IAAI,CAAC,CAAA;AAAA,KAC1G;AAAA,EACF;AACF;AAEA,eAAe,cACb,IAAA,EACA,aAAA,EACA,GAAA,EACA,GAAA,EACA,QACA,IAAA,EACyB;AACzB,EAAA,MAAM,QAAkB,EAAC;AACzB,EAAA,IAAI,YAAA,GAAe,CAAA;AAEnB,EAAA,KAAA,MAAW,CAAC,QAAA,EAAU,OAAO,KAAK,MAAA,CAAO,OAAA,CAAQ,aAAa,CAAA,EAAG;AAC/D,IAAA,MAAM,YAAA,GAAe,cAAA,CAAe,QAAA,EAAU,IAAA,EAAM,IAAI,CAAA;AACxD,IAAA,MAAM,UAAA,GAAkBA,IAAA,CAAA,IAAA,CAAK,GAAA,EAAK,YAAY,CAAA;AAE9C,IAAA,MAAM,IAAA,GAAYA,IAAA,CAAA,OAAA,CAAQ,GAAA,CAAI,WAAW,CAAA;AACzC,IAAA,MAAM,MAAA,GAAcA,aAAQ,UAAU,CAAA;AACtC,IAAA,MAAM,GAAA,GAAWA,IAAA,CAAA,QAAA,CAAS,IAAA,EAAM,MAAM,CAAA;AACtC,IAAA,IAAI,IAAI,UAAA,CAAW,IAAI,CAAA,IAAUA,IAAA,CAAA,UAAA,CAAW,GAAG,CAAA,EAAG;AAChD,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,0BAAA,EAA6B,YAAY,CAAA,2BAAA,CAA6B,CAAA;AAAA,IACxF;AACA,IAAA,MAAM,QAAA,GAAW,MAAA;AAEjB,IAAA,IAAI,CAAC,MAAA,EAAQ;AACX,MAAA,MAAS,SAAWA,IAAA,CAAA,OAAA,CAAQ,QAAQ,GAAG,EAAE,SAAA,EAAW,MAAM,CAAA;AAC1D,MAAA,MAAS,aAAU,QAAA,EAAU,cAAA,CAAe,SAAS,IAAA,EAAM,IAAI,GAAG,MAAM,CAAA;AAAA,IAC1E;AACA,IAAA,KAAA,CAAM,KAAK,YAAY,CAAA;AACvB,IAAA,YAAA,EAAA;AAAA,EACF;AAEA,EAAA,OAAO;AAAA,IACL,QAAA,EAAU,UAAA;AAAA,IACV,IAAA;AAAA,IACA,aAAA,EAAe,YAAA;AAAA,IACf,KAAA;AAAA,IACA,OAAA,EAAS,MAAA;AAAA,IACT,QAAQ,MAAA,GACJ,CAAA,aAAA,EAAgB,YAAY,CAAA,QAAA,EAAW,MAAM,IAAA,CAAK,IAAI,CAAC,CAAA,CAAA,GACvD,WAAW,YAAY,CAAA,QAAA,EAAW,KAAA,CAAM,IAAA,CAAK,IAAI,CAAC,CAAA;AAAA,GACxD;AACF;AAEA,SAAS,cAAA,CAAe,OAAA,EAAiB,IAAA,EAAc,IAAA,EAAsC;AAC3F,EAAA,IAAI,MAAA,GAAS,OAAA;AACb,EAAA,MAAA,GAAS,MAAA,CAAO,QAAQ,eAAA,EAAiB,IAAA,CAAK,aAAY,CAAE,OAAA,CAAQ,MAAA,EAAQ,GAAG,CAAC,CAAA;AAChF,EAAA,MAAA,GAAS,MAAA,CAAO,OAAA;AAAA,IACd,eAAA;AAAA,IACA,IAAA,CAAK,QAAQ,uBAAA,EAAyB,CAAC,GAAG,CAAA,KAAM,CAAA,CAAE,aAAa;AAAA,GACjE;AACA,EAAA,KAAA,MAAW,CAAC,CAAA,EAAG,CAAC,KAAK,MAAA,CAAO,OAAA,CAAQ,IAAI,CAAA,EAAG;AACzC,IAAA,MAAA,GAAS,MAAA,CAAO,QAAQ,IAAI,MAAA,CAAO,SAAS,CAAC,CAAA,MAAA,CAAA,EAAU,GAAG,CAAA,EAAG,CAAC,CAAA;AAAA,EAChE;AACA,EAAA,OAAO,MAAA;AACT","file":"scaffold.js","sourcesContent":["import * as path from 'node:path';\nimport type { Context } from '@wrongstack/core';\n\nexport function resolvePath(input: string, ctx: Context): string {\n return path.isAbsolute(input) ? path.normalize(input) : path.resolve(ctx.cwd, input);\n}\n\nexport function ensureInsideRoot(absPath: string, ctx: Context): string {\n const root = path.resolve(ctx.projectRoot);\n const target = path.resolve(absPath);\n const rel = path.relative(root, target);\n if (rel.startsWith('..') || path.isAbsolute(rel)) {\n throw new Error(`Path \"${absPath}\" is outside project root \"${root}\"`);\n }\n return target;\n}\n\nexport function safeResolve(input: string, ctx: Context): string {\n return ensureInsideRoot(resolvePath(input, ctx), ctx);\n}\n\nexport function truncateMiddle(s: string, max: number): string {\n if (Buffer.byteLength(s, 'utf8') <= max) return s;\n const half = Math.floor(max / 2);\n return (\n s.slice(0, half) +\n `\\n…[truncated ${Buffer.byteLength(s, 'utf8') - max} bytes from middle]…\\n` +\n s.slice(-half)\n );\n}\n\nexport function isBinaryBuffer(buf: Buffer): boolean {\n const len = Math.min(buf.length, 8192);\n for (let i = 0; i < len; i++) {\n if (buf[i] === 0) return true;\n }\n return false;\n}\n","import * as fs from 'node:fs/promises';\r\nimport * as path from 'node:path';\r\nimport type { Tool } from '@wrongstack/core';\r\nimport { safeResolve } from './_util.js';\r\n\r\ninterface ScaffoldInput {\r\n template: string;\r\n name: string;\r\n cwd?: string;\r\n vars?: Record<string, string>;\r\n dry_run?: boolean;\r\n}\r\n\r\ninterface ScaffoldOutput {\r\n template: string;\r\n name: string;\r\n files_created: number;\r\n files: string[];\r\n dry_run: boolean;\r\n output: string;\r\n}\r\n\r\nconst BUILT_IN_TEMPLATES: Record<string, { description: string; files: Record<string, string> }> = {\r\n 'npm-package': {\r\n description: 'Basic npm package with ESM',\r\n files: {\r\n 'package.json': JSON.stringify(\r\n {\r\n name: '{{name}}',\r\n version: '0.1.1',\r\n type: 'module',\r\n main: './dist/index.js',\r\n scripts: { build: 'tsc', test: 'vitest run' },\r\n devDependencies: { typescript: '^5.0.0' },\r\n },\r\n null,\r\n 2,\r\n ),\r\n 'tsconfig.json': JSON.stringify(\r\n {\r\n compilerOptions: { target: 'ES2022', module: 'ESNext', strict: true },\r\n include: ['src'],\r\n },\r\n null,\r\n 2,\r\n ),\r\n 'src/index.ts': `export function hello() {\\n return 'Hello from {{name}}';\\n}\\n`,\r\n 'src/index.test.ts': `import { hello } from './index';\\nimport { describe, it, expect } from 'vitest';\\n\\ndescribe('hello', () => {\\n it('returns greeting', () => {\\n expect(hello()).toBe('Hello from {{name}}');\\n });\\n});\\n`,\r\n },\r\n },\r\n 'cli-tool': {\r\n description: 'CLI tool with argparse',\r\n files: {\r\n 'package.json': JSON.stringify(\r\n {\r\n name: '{{name}}',\r\n version: '0.1.1',\r\n type: 'module',\r\n bin: { '{{name}}': './src/index.js' },\r\n scripts: { build: 'tsc', start: 'node dist/index.js' },\r\n },\r\n null,\r\n 2,\r\n ),\r\n 'src/index.ts': `#!/usr/bin/env node\\n\\nasync function main() {\\n console.log('Hello from {{name}}');\\n}\\n\\nmain();\\n`,\r\n },\r\n },\r\n 'react-component': {\r\n description: 'React component with TypeScript',\r\n files: {\r\n '{{name}}.tsx': `interface {{Name}}Props {\\n className?: string;\\n}\\n\\nexport function {{Name}}({ className }: {{Name}}Props) {\\n return (\\n <div className={className}>\\n {{Name}} Component\\n </div>\\n );\\n}\\n`,\r\n '{{name}}.test.tsx': `import { render, screen } from '@testing-library/react';\\nimport { {{Name}} } from './{{Name}}';\\n\\ndescribe('{{Name}}', () => {\\n it('renders', () => {\\n render(<{{Name}} />);\\n expect(screen.getByText('{{Name}} Component')).toBeInTheDocument();\\n });\\n});\\n`,\r\n },\r\n },\r\n};\r\n\r\nexport const scaffoldTool: Tool<ScaffoldInput, ScaffoldOutput> = {\r\n name: 'scaffold',\r\n category: 'Project',\r\n description:\r\n 'Generate boilerplate code from built-in templates or paths. Creates package.json, source files, tests.',\r\n usageHint:\r\n 'Set `template` (npm-package, cli-tool, react-component) and `name`. `vars` for template variables. `dry_run` preview.',\r\n permission: 'confirm',\r\n mutating: true,\r\n timeoutMs: 30_000,\r\n inputSchema: {\r\n type: 'object',\r\n properties: {\r\n template: {\r\n type: 'string',\r\n description:\r\n 'Template name (npm-package, cli-tool, react-component) or path to template directory',\r\n },\r\n name: {\r\n type: 'string',\r\n description: 'Project/component name (used in generated files)',\r\n },\r\n cwd: { type: 'string', description: 'Working directory (default: cwd)' },\r\n vars: {\r\n type: 'object',\r\n additionalProperties: { type: 'string' },\r\n description: 'Template variables for custom templates',\r\n },\r\n dry_run: {\r\n type: 'boolean',\r\n description: 'Preview generated files without creating (default: false)',\r\n },\r\n },\r\n required: ['template', 'name'],\r\n },\r\n async execute(input, ctx) {\r\n const cwd = input.cwd ? safeResolve(input.cwd, ctx) : ctx.cwd;\r\n const name = input.name;\r\n const vars = { name, ...input.vars };\r\n\r\n const builtIn = BUILT_IN_TEMPLATES[input.template];\r\n if (builtIn) {\r\n return await handleBuiltIn(name, builtIn.files, cwd, ctx, input.dry_run ?? false, vars);\r\n }\r\n\r\n return {\r\n template: input.template,\r\n name,\r\n files_created: 0,\r\n files: [],\r\n dry_run: input.dry_run ?? false,\r\n output: `Template \"${input.template}\" not found. Available: ${Object.keys(BUILT_IN_TEMPLATES).join(', ')}`,\r\n };\r\n },\r\n};\r\n\r\nasync function handleBuiltIn(\r\n name: string,\r\n templateFiles: Record<string, string>,\r\n cwd: string,\r\n ctx: Parameters<Tool['execute']>[1],\r\n dryRun: boolean,\r\n vars: Record<string, string>,\r\n): Promise<ScaffoldOutput> {\r\n const files: string[] = [];\r\n let filesCreated = 0;\r\n\r\n for (const [filePath, content] of Object.entries(templateFiles)) {\r\n const resolvedPath = substituteVars(filePath, name, vars);\r\n const joinedPath = path.join(cwd, resolvedPath);\r\n // Ensure generated files cannot escape the project root via template variable injection (e.g. name containing \"../\")\r\n const root = path.resolve(ctx.projectRoot);\r\n const target = path.resolve(joinedPath);\r\n const rel = path.relative(root, target);\r\n if (rel.startsWith('..') || path.isAbsolute(rel)) {\r\n throw new Error(`scaffold: generated path \"${resolvedPath}\" would escape project root`);\r\n }\r\n const fullPath = target;\r\n\r\n if (!dryRun) {\r\n await fs.mkdir(path.dirname(fullPath), { recursive: true });\r\n await fs.writeFile(fullPath, substituteVars(content, name, vars), 'utf8');\r\n }\r\n files.push(resolvedPath);\r\n filesCreated++;\r\n }\r\n\r\n return {\r\n template: 'built-in',\r\n name,\r\n files_created: filesCreated,\r\n files,\r\n dry_run: dryRun,\r\n output: dryRun\r\n ? `Would create ${filesCreated} files: ${files.join(', ')}`\r\n : `Created ${filesCreated} files: ${files.join(', ')}`,\r\n };\r\n}\r\n\r\nfunction substituteVars(content: string, name: string, vars: Record<string, string>): string {\r\n let result = content;\r\n result = result.replace(/\\{\\{name\\}\\}/g, name.toLowerCase().replace(/\\s+/g, '-'));\r\n result = result.replace(\r\n /\\{\\{Name\\}\\}/g,\r\n name.replace(/(?:^|[-_\\s]+)([a-z])/g, (_, c) => c.toUpperCase()),\r\n );\r\n for (const [k, v] of Object.entries(vars)) {\r\n result = result.replace(new RegExp(`\\\\{\\\\{${k}\\\\}\\\\}`, 'g'), v);\r\n }\r\n return result;\r\n}\r\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/_util.ts","../src/scaffold.ts"],"names":["path2"],"mappings":"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","file":"scaffold.js","sourcesContent":["import * as path from 'node:path';\nimport type { Context } from '@wrongstack/core';\n\nexport function resolvePath(input: string, ctx: Context): string {\n return path.isAbsolute(input) ? path.normalize(input) : path.resolve(ctx.cwd, input);\n}\n\nexport function ensureInsideRoot(absPath: string, ctx: Context): string {\n const root = path.resolve(ctx.projectRoot);\n const target = path.resolve(absPath);\n const rel = path.relative(root, target);\n if (rel.startsWith('..') || path.isAbsolute(rel)) {\n throw new Error(`Path \"${absPath}\" is outside project root \"${root}\"`);\n }\n return target;\n}\n\nexport function safeResolve(input: string, ctx: Context): string {\n return ensureInsideRoot(resolvePath(input, ctx), ctx);\n}\n\nexport function truncateMiddle(s: string, max: number): string {\n if (Buffer.byteLength(s, 'utf8') <= max) return s;\n const half = Math.floor(max / 2);\n return (\n s.slice(0, half) +\n `\\n…[truncated ${Buffer.byteLength(s, 'utf8') - max} bytes from middle]…\\n` +\n s.slice(-half)\n );\n}\n\nexport function isBinaryBuffer(buf: Buffer): boolean {\n const len = Math.min(buf.length, 8192);\n for (let i = 0; i < len; i++) {\n if (buf[i] === 0) return true;\n }\n return false;\n}\n","import * as fs from 'node:fs/promises';\r\nimport * as path from 'node:path';\r\nimport type { Tool } from '@wrongstack/core';\r\nimport { atomicWrite } from '@wrongstack/core';\r\nimport { safeResolve } from './_util.js';\r\n\r\ninterface ScaffoldInput {\r\n template: string;\r\n name: string;\r\n cwd?: string;\r\n vars?: Record<string, string>;\r\n dry_run?: boolean;\r\n}\r\n\r\ninterface ScaffoldOutput {\r\n template: string;\r\n name: string;\r\n files_created: number;\r\n files: string[];\r\n dry_run: boolean;\r\n output: string;\r\n}\r\n\r\nconst BUILT_IN_TEMPLATES: Record<string, { description: string; files: Record<string, string> }> = {\r\n 'npm-package': {\r\n description: 'Basic npm package with ESM',\r\n files: {\r\n 'package.json': JSON.stringify(\r\n {\r\n name: '{{name}}',\r\n version: '0.1.1',\r\n type: 'module',\r\n main: './dist/index.js',\r\n scripts: { build: 'tsc', test: 'vitest run' },\r\n devDependencies: { typescript: '^5.0.0' },\r\n },\r\n null,\r\n 2,\r\n ),\r\n 'tsconfig.json': JSON.stringify(\r\n {\r\n compilerOptions: { target: 'ES2022', module: 'ESNext', strict: true },\r\n include: ['src'],\r\n },\r\n null,\r\n 2,\r\n ),\r\n 'src/index.ts': `export function hello() {\\n return 'Hello from {{name}}';\\n}\\n`,\r\n 'src/index.test.ts': `import { hello } from './index';\\nimport { describe, it, expect } from 'vitest';\\n\\ndescribe('hello', () => {\\n it('returns greeting', () => {\\n expect(hello()).toBe('Hello from {{name}}');\\n });\\n});\\n`,\r\n },\r\n },\r\n 'cli-tool': {\r\n description: 'CLI tool with argparse',\r\n files: {\r\n 'package.json': JSON.stringify(\r\n {\r\n name: '{{name}}',\r\n version: '0.1.1',\r\n type: 'module',\r\n bin: { '{{name}}': './src/index.js' },\r\n scripts: { build: 'tsc', start: 'node dist/index.js' },\r\n },\r\n null,\r\n 2,\r\n ),\r\n 'src/index.ts': `#!/usr/bin/env node\\n\\nasync function main() {\\n console.log('Hello from {{name}}');\\n}\\n\\nmain();\\n`,\r\n },\r\n },\r\n 'react-component': {\r\n description: 'React component with TypeScript',\r\n files: {\r\n '{{name}}.tsx': `interface {{Name}}Props {\\n className?: string;\\n}\\n\\nexport function {{Name}}({ className }: {{Name}}Props) {\\n return (\\n <div className={className}>\\n {{Name}} Component\\n </div>\\n );\\n}\\n`,\r\n '{{name}}.test.tsx': `import { render, screen } from '@testing-library/react';\\nimport { {{Name}} } from './{{Name}}';\\n\\ndescribe('{{Name}}', () => {\\n it('renders', () => {\\n render(<{{Name}} />);\\n expect(screen.getByText('{{Name}} Component')).toBeInTheDocument();\\n });\\n});\\n`,\r\n },\r\n },\r\n};\r\n\r\nexport const scaffoldTool: Tool<ScaffoldInput, ScaffoldOutput> = {\r\n name: 'scaffold',\r\n category: 'Project',\r\n description:\r\n 'Generate boilerplate code from built-in templates or paths. Creates package.json, source files, tests.',\r\n usageHint:\r\n 'Set `template` (npm-package, cli-tool, react-component) and `name`. `vars` for template variables. `dry_run` preview.',\r\n permission: 'confirm',\r\n mutating: true,\r\n timeoutMs: 30_000,\r\n inputSchema: {\r\n type: 'object',\r\n properties: {\r\n template: {\r\n type: 'string',\r\n description:\r\n 'Template name (npm-package, cli-tool, react-component) or path to template directory',\r\n },\r\n name: {\r\n type: 'string',\r\n description: 'Project/component name (used in generated files)',\r\n },\r\n cwd: { type: 'string', description: 'Working directory (default: cwd)' },\r\n vars: {\r\n type: 'object',\r\n additionalProperties: { type: 'string' },\r\n description: 'Template variables for custom templates',\r\n },\r\n dry_run: {\r\n type: 'boolean',\r\n description: 'Preview generated files without creating (default: false)',\r\n },\r\n },\r\n required: ['template', 'name'],\r\n },\r\n async execute(input, ctx) {\r\n const cwd = input.cwd ? safeResolve(input.cwd, ctx) : ctx.cwd;\r\n const name = input.name;\r\n const vars = { name, ...input.vars };\r\n\r\n const builtIn = BUILT_IN_TEMPLATES[input.template];\r\n if (builtIn) {\r\n return await handleBuiltIn(name, builtIn.files, cwd, ctx, input.dry_run ?? false, vars);\r\n }\r\n\r\n return {\r\n template: input.template,\r\n name,\r\n files_created: 0,\r\n files: [],\r\n dry_run: input.dry_run ?? false,\r\n output: `Template \"${input.template}\" not found. Available: ${Object.keys(BUILT_IN_TEMPLATES).join(', ')}`,\r\n };\r\n },\r\n};\r\n\r\nasync function handleBuiltIn(\r\n name: string,\r\n templateFiles: Record<string, string>,\r\n cwd: string,\r\n ctx: Parameters<Tool['execute']>[1],\r\n dryRun: boolean,\r\n vars: Record<string, string>,\r\n): Promise<ScaffoldOutput> {\r\n const files: string[] = [];\r\n let filesCreated = 0;\r\n\r\n for (const [filePath, content] of Object.entries(templateFiles)) {\r\n const resolvedPath = substituteVars(filePath, name, vars);\r\n const joinedPath = path.join(cwd, resolvedPath);\r\n // Ensure generated files cannot escape the project root via template variable injection (e.g. name containing \"../\")\r\n const root = path.resolve(ctx.projectRoot);\r\n const target = path.resolve(joinedPath);\r\n const rel = path.relative(root, target);\r\n if (rel.startsWith('..') || path.isAbsolute(rel)) {\r\n throw new Error(`scaffold: generated path \"${resolvedPath}\" would escape project root`);\r\n }\r\n const fullPath = target;\r\n\r\n if (!dryRun) {\r\n await fs.mkdir(path.dirname(fullPath), { recursive: true });\r\n // atomicWrite: scaffolded files land in the user's tracked tree.\r\n // A torn write here would commit a corrupt file to their repo.\r\n await atomicWrite(fullPath, substituteVars(content, name, vars));\r\n }\r\n files.push(resolvedPath);\r\n filesCreated++;\r\n }\r\n\r\n return {\r\n template: 'built-in',\r\n name,\r\n files_created: filesCreated,\r\n files,\r\n dry_run: dryRun,\r\n output: dryRun\r\n ? `Would create ${filesCreated} files: ${files.join(', ')}`\r\n : `Created ${filesCreated} files: ${files.join(', ')}`,\r\n };\r\n}\r\n\r\nfunction substituteVars(content: string, name: string, vars: Record<string, string>): string {\r\n let result = content;\r\n result = result.replace(/\\{\\{name\\}\\}/g, name.toLowerCase().replace(/\\s+/g, '-'));\r\n result = result.replace(\r\n /\\{\\{Name\\}\\}/g,\r\n name.replace(/(?:^|[-_\\s]+)([a-z])/g, (_, c) => c.toUpperCase()),\r\n );\r\n for (const [k, v] of Object.entries(vars)) {\r\n result = result.replace(new RegExp(`\\\\{\\\\{${k}\\\\}\\\\}`, 'g'), v);\r\n }\r\n return result;\r\n}\r\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wrongstack/tools",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "WrongStack built-in tools: read/write/edit, bash/exec, grep/glob, git, fetch, test, lint, and more.",
|
|
6
6
|
"repository": {
|
|
@@ -155,13 +155,21 @@
|
|
|
155
155
|
"./mode": {
|
|
156
156
|
"types": "./dist/mode.d.ts",
|
|
157
157
|
"import": "./dist/mode.js"
|
|
158
|
+
},
|
|
159
|
+
"./process-registry": {
|
|
160
|
+
"types": "./dist/process-registry.d.ts",
|
|
161
|
+
"import": "./dist/process-registry.js"
|
|
162
|
+
},
|
|
163
|
+
"./circuit-breaker": {
|
|
164
|
+
"types": "./dist/circuit-breaker.d.ts",
|
|
165
|
+
"import": "./dist/circuit-breaker.js"
|
|
158
166
|
}
|
|
159
167
|
},
|
|
160
168
|
"files": [
|
|
161
169
|
"dist"
|
|
162
170
|
],
|
|
163
171
|
"dependencies": {
|
|
164
|
-
"@wrongstack/core": "0.
|
|
172
|
+
"@wrongstack/core": "0.6.0"
|
|
165
173
|
},
|
|
166
174
|
"devDependencies": {
|
|
167
175
|
"@types/node": "^22.19.19",
|