@wrongstack/tools 0.2.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/audit.js +1 -0
- package/dist/audit.js.map +1 -1
- package/dist/bash.js +1 -0
- package/dist/bash.js.map +1 -1
- package/dist/batch-tool-use.js +1 -0
- package/dist/batch-tool-use.js.map +1 -1
- package/dist/builtin.js +48 -1
- package/dist/builtin.js.map +1 -1
- package/dist/diff.js +1 -0
- package/dist/diff.js.map +1 -1
- package/dist/document.js +1 -0
- package/dist/document.js.map +1 -1
- package/dist/edit.js +1 -0
- package/dist/edit.js.map +1 -1
- package/dist/exec.js +1 -0
- package/dist/exec.js.map +1 -1
- package/dist/fetch.js +1 -0
- package/dist/fetch.js.map +1 -1
- package/dist/format.js +1 -0
- package/dist/format.js.map +1 -1
- package/dist/git.js +1 -0
- package/dist/git.js.map +1 -1
- package/dist/glob.js +1 -0
- package/dist/glob.js.map +1 -1
- package/dist/grep.js +18 -1
- package/dist/grep.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +59 -2
- package/dist/index.js.map +1 -1
- package/dist/install.js +1 -0
- package/dist/install.js.map +1 -1
- package/dist/json.js +1 -0
- package/dist/json.js.map +1 -1
- package/dist/lint.js +1 -0
- package/dist/lint.js.map +1 -1
- package/dist/logs.js +1 -0
- package/dist/logs.js.map +1 -1
- package/dist/memory.js +2 -0
- package/dist/memory.js.map +1 -1
- package/dist/mode.js +1 -0
- package/dist/mode.js.map +1 -1
- package/dist/outdated.js +1 -0
- package/dist/outdated.js.map +1 -1
- package/dist/pack.d.ts +9 -0
- package/dist/pack.js +4216 -0
- package/dist/pack.js.map +1 -0
- package/dist/patch.js +1 -0
- package/dist/patch.js.map +1 -1
- package/dist/read.js +1 -0
- package/dist/read.js.map +1 -1
- package/dist/replace.js +1 -0
- package/dist/replace.js.map +1 -1
- package/dist/scaffold.js +1 -0
- package/dist/scaffold.js.map +1 -1
- package/dist/search.js +1 -0
- package/dist/search.js.map +1 -1
- package/dist/test.js +1 -0
- package/dist/test.js.map +1 -1
- package/dist/todo.js +1 -0
- package/dist/todo.js.map +1 -1
- package/dist/tool-help.js +1 -0
- package/dist/tool-help.js.map +1 -1
- package/dist/tool-search.js +1 -0
- package/dist/tool-search.js.map +1 -1
- package/dist/tool-use.js +1 -0
- package/dist/tool-use.js.map +1 -1
- package/dist/tree.js +1 -0
- package/dist/tree.js.map +1 -1
- package/dist/typecheck.js +1 -0
- package/dist/typecheck.js.map +1 -1
- package/dist/write.js +1 -0
- package/dist/write.js.map +1 -1
- package/package.json +6 -2
package/dist/git.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/git.ts"],"names":[],"mappings":"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","file":"git.js","sourcesContent":["import { spawn } from 'node:child_process';\nimport { statSync } from 'node:fs';\nimport { dirname } from 'node:path';\nimport type { Tool } from '@wrongstack/core';\n\ntype GitSubcommand =\n | 'status'\n | 'log'\n | 'diff'\n | 'commit'\n | 'branch'\n | 'checkout'\n | 'stash'\n | 'push'\n | 'pull'\n | 'fetch'\n | 'reset';\n\ninterface GitInput {\n command: GitSubcommand;\n files?: string | string[];\n dry_run?: boolean;\n /** commit message for `commit` subcommand */\n message?: string;\n /** branch name for `checkout` / `branch` */\n branch?: string;\n /** pass --graph, --oneline, --stat for `log` */\n format?: 'short' | 'oneline' | 'stat' | 'graph';\n /** limit for `log` */\n limit?: number;\n}\n\ninterface GitOutput {\n command: GitSubcommand;\n stdout: string;\n stderr: string;\n exitCode: number;\n truncated: boolean;\n}\n\nconst TIMEOUT_MS = 30_000;\nconst MAX_OUTPUT = 100_000;\n\nexport const gitTool: Tool<GitInput, GitOutput> = {\n name: 'git',\n description:\n 'Run git commands. Wraps common operations: status, log, diff, commit, branch, checkout, stash, push, pull, fetch, reset.',\n usageHint:\n 'Prefer built-in subcommands over raw args. `command` is required. `message` for commits. `branch` for checkout/branch. `files` for status/diff. `format` for log.',\n permission: 'confirm',\n // Conservative: any of these may mutate. The non-mutating commands\n // (status/log/diff/branch/fetch) are still gated on `permission: 'confirm'`\n // and `MUTATING_SUBCOMMANDS` is consulted at runtime for per-call checks.\n mutating: true,\n timeoutMs: TIMEOUT_MS,\n inputSchema: {\n type: 'object',\n properties: {\n command: {\n type: 'string',\n enum: [\n 'status',\n 'log',\n 'diff',\n 'commit',\n 'branch',\n 'checkout',\n 'stash',\n 'push',\n 'pull',\n 'fetch',\n 'reset',\n ],\n description: 'Git subcommand',\n },\n files: {\n type: 'string',\n description:\n 'File(s) for status/diff: single path, comma-separated list, or \"**/*.ts\" glob',\n },\n message: { type: 'string', description: 'Commit message (required for commit)' },\n branch: { type: 'string', description: 'Branch name for checkout/branch' },\n format: {\n type: 'string',\n enum: ['short', 'oneline', 'stat', 'graph'],\n description: 'Log format (default: short)',\n },\n limit: { type: 'integer', description: 'Limit for log (default: 20)' },\n dry_run: { type: 'boolean', description: 'For commit: show what would be committed' },\n },\n required: ['command'],\n },\n async execute(input, ctx, opts) {\n if (!input?.command) throw new Error('git: command is required');\n\n // Bound the search at projectRoot so a non-git project doesn't drift\n // into a parent repo (e.g. ~/repos/.git) and operate on the wrong tree.\n const gitDir = findGitDir(ctx.cwd, ctx.projectRoot);\n if (!gitDir) {\n return {\n command: input.command,\n stdout: '',\n stderr: 'Not in a git repository (within project root)',\n exitCode: 128,\n truncated: false,\n };\n }\n\n const args = buildArgs(input);\n return await runGit(args, gitDir, opts.signal);\n },\n};\n\nfunction findGitDir(cwd: string, projectRoot: string): string | null {\n const root = projectRoot;\n let dir = cwd;\n for (let i = 0; i < 20; i++) {\n try {\n const stat = statSync(`${dir}/.git`);\n if (stat.isDirectory()) return dir;\n } catch {\n // continue\n }\n if (dir === root) break;\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n return null;\n}\n\nfunction buildArgs(input: GitInput): string[] {\n const limit = input.limit ?? 20;\n const files = input.files\n ? (Array.isArray(input.files) ? input.files : input.files.split(','))\n .map((s: string) => s.trim())\n .filter(Boolean)\n : [];\n\n switch (input.command) {\n case 'status':\n return ['status', ...(files.length ? ['--', ...files] : [])];\n case 'log':\n return [\n 'log',\n `--max-count=${limit}`,\n ...(input.format === 'oneline' ? ['--oneline'] : []),\n ...(input.format === 'stat' ? ['--stat'] : []),\n ...(input.format === 'graph' ? ['--oneline', '--graph', '--decorate'] : []),\n ...(input.format === 'short' || !input.format ? [] : []),\n ];\n case 'diff':\n return ['diff', '--no-color', ...(files.length ? ['--', ...files] : [])];\n case 'commit':\n return [\n 'commit',\n ...(input.dry_run ? ['--dry-run', '--porcelain'] : []),\n ...(input.message ? ['-m', input.message] : []),\n ...(files.length ? ['--', ...files] : []),\n ];\n case 'branch':\n return input.branch ? ['branch', input.branch] : ['branch'];\n case 'checkout':\n return [\n 'checkout',\n ...(input.branch ? [input.branch] : []),\n ...(files.length ? ['--', ...files] : []),\n ];\n case 'stash':\n return input.message ? ['stash', 'push', '-m', input.message] : ['stash', 'push'];\n case 'push':\n return ['push'];\n case 'pull':\n return ['pull'];\n case 'fetch':\n return ['fetch', ...(input.branch ? [input.branch] : ['--all'])];\n case 'reset':\n return ['reset'];\n default:\n return [input.command];\n }\n}\n\nfunction runGit(args: string[], cwd: string, signal: AbortSignal): Promise<GitOutput> {\n return new Promise((resolve) => {\n let stdout = '';\n let stderr = '';\n\n const child = spawn('git', args, {\n cwd,\n signal,\n stdio: ['ignore', 'pipe', 'pipe'],\n });\n\n child.stdout?.on('data', (chunk: Buffer) => {\n if (stdout.length < MAX_OUTPUT) {\n stdout += chunk.toString();\n }\n });\n\n child.stderr?.on('data', (chunk: Buffer) => {\n if (stderr.length < MAX_OUTPUT) {\n stderr += chunk.toString();\n }\n });\n\n child.on('error', (err) => {\n resolve({\n command: args[0] as GitSubcommand,\n stdout,\n stderr: err.message,\n exitCode: 1,\n truncated: stdout.length >= MAX_OUTPUT,\n });\n });\n\n child.on('close', (code) => {\n resolve({\n command: args[0] as GitSubcommand,\n stdout: stdout.slice(0, MAX_OUTPUT),\n stderr: stderr.slice(0, MAX_OUTPUT),\n exitCode: code ?? 1,\n truncated: stdout.length >= MAX_OUTPUT || stderr.length >= MAX_OUTPUT,\n });\n });\n });\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/git.ts"],"names":[],"mappings":"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","file":"git.js","sourcesContent":["import { spawn } from 'node:child_process';\nimport { statSync } from 'node:fs';\nimport { dirname } from 'node:path';\nimport type { Tool } from '@wrongstack/core';\n\ntype GitSubcommand =\n | 'status'\n | 'log'\n | 'diff'\n | 'commit'\n | 'branch'\n | 'checkout'\n | 'stash'\n | 'push'\n | 'pull'\n | 'fetch'\n | 'reset';\n\ninterface GitInput {\n command: GitSubcommand;\n files?: string | string[];\n dry_run?: boolean;\n /** commit message for `commit` subcommand */\n message?: string;\n /** branch name for `checkout` / `branch` */\n branch?: string;\n /** pass --graph, --oneline, --stat for `log` */\n format?: 'short' | 'oneline' | 'stat' | 'graph';\n /** limit for `log` */\n limit?: number;\n}\n\ninterface GitOutput {\n command: GitSubcommand;\n stdout: string;\n stderr: string;\n exitCode: number;\n truncated: boolean;\n}\n\nconst TIMEOUT_MS = 30_000;\nconst MAX_OUTPUT = 100_000;\n\nexport const gitTool: Tool<GitInput, GitOutput> = {\n name: 'git',\n category: 'Git',\n description:\n 'Run git commands. Wraps common operations: status, log, diff, commit, branch, checkout, stash, push, pull, fetch, reset.',\n usageHint:\n 'Prefer built-in subcommands over raw args. `command` is required. `message` for commits. `branch` for checkout/branch. `files` for status/diff. `format` for log.',\n permission: 'confirm',\n // Conservative: any of these may mutate. The non-mutating commands\n // (status/log/diff/branch/fetch) are still gated on `permission: 'confirm'`\n // and `MUTATING_SUBCOMMANDS` is consulted at runtime for per-call checks.\n mutating: true,\n timeoutMs: TIMEOUT_MS,\n inputSchema: {\n type: 'object',\n properties: {\n command: {\n type: 'string',\n enum: [\n 'status',\n 'log',\n 'diff',\n 'commit',\n 'branch',\n 'checkout',\n 'stash',\n 'push',\n 'pull',\n 'fetch',\n 'reset',\n ],\n description: 'Git subcommand',\n },\n files: {\n type: 'string',\n description:\n 'File(s) for status/diff: single path, comma-separated list, or \"**/*.ts\" glob',\n },\n message: { type: 'string', description: 'Commit message (required for commit)' },\n branch: { type: 'string', description: 'Branch name for checkout/branch' },\n format: {\n type: 'string',\n enum: ['short', 'oneline', 'stat', 'graph'],\n description: 'Log format (default: short)',\n },\n limit: { type: 'integer', description: 'Limit for log (default: 20)' },\n dry_run: { type: 'boolean', description: 'For commit: show what would be committed' },\n },\n required: ['command'],\n },\n async execute(input, ctx, opts) {\n if (!input?.command) throw new Error('git: command is required');\n\n // Bound the search at projectRoot so a non-git project doesn't drift\n // into a parent repo (e.g. ~/repos/.git) and operate on the wrong tree.\n const gitDir = findGitDir(ctx.cwd, ctx.projectRoot);\n if (!gitDir) {\n return {\n command: input.command,\n stdout: '',\n stderr: 'Not in a git repository (within project root)',\n exitCode: 128,\n truncated: false,\n };\n }\n\n const args = buildArgs(input);\n return await runGit(args, gitDir, opts.signal);\n },\n};\n\nfunction findGitDir(cwd: string, projectRoot: string): string | null {\n const root = projectRoot;\n let dir = cwd;\n for (let i = 0; i < 20; i++) {\n try {\n const stat = statSync(`${dir}/.git`);\n if (stat.isDirectory()) return dir;\n } catch {\n // continue\n }\n if (dir === root) break;\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n return null;\n}\n\nfunction buildArgs(input: GitInput): string[] {\n const limit = input.limit ?? 20;\n const files = input.files\n ? (Array.isArray(input.files) ? input.files : input.files.split(','))\n .map((s: string) => s.trim())\n .filter(Boolean)\n : [];\n\n switch (input.command) {\n case 'status':\n return ['status', ...(files.length ? ['--', ...files] : [])];\n case 'log':\n return [\n 'log',\n `--max-count=${limit}`,\n ...(input.format === 'oneline' ? ['--oneline'] : []),\n ...(input.format === 'stat' ? ['--stat'] : []),\n ...(input.format === 'graph' ? ['--oneline', '--graph', '--decorate'] : []),\n ...(input.format === 'short' || !input.format ? [] : []),\n ];\n case 'diff':\n return ['diff', '--no-color', ...(files.length ? ['--', ...files] : [])];\n case 'commit':\n return [\n 'commit',\n ...(input.dry_run ? ['--dry-run', '--porcelain'] : []),\n ...(input.message ? ['-m', input.message] : []),\n ...(files.length ? ['--', ...files] : []),\n ];\n case 'branch':\n return input.branch ? ['branch', input.branch] : ['branch'];\n case 'checkout':\n return [\n 'checkout',\n ...(input.branch ? [input.branch] : []),\n ...(files.length ? ['--', ...files] : []),\n ];\n case 'stash':\n return input.message ? ['stash', 'push', '-m', input.message] : ['stash', 'push'];\n case 'push':\n return ['push'];\n case 'pull':\n return ['pull'];\n case 'fetch':\n return ['fetch', ...(input.branch ? [input.branch] : ['--all'])];\n case 'reset':\n return ['reset'];\n default:\n return [input.command];\n }\n}\n\nfunction runGit(args: string[], cwd: string, signal: AbortSignal): Promise<GitOutput> {\n return new Promise((resolve) => {\n let stdout = '';\n let stderr = '';\n\n const child = spawn('git', args, {\n cwd,\n signal,\n stdio: ['ignore', 'pipe', 'pipe'],\n });\n\n child.stdout?.on('data', (chunk: Buffer) => {\n if (stdout.length < MAX_OUTPUT) {\n stdout += chunk.toString();\n }\n });\n\n child.stderr?.on('data', (chunk: Buffer) => {\n if (stderr.length < MAX_OUTPUT) {\n stderr += chunk.toString();\n }\n });\n\n child.on('error', (err) => {\n resolve({\n command: args[0] as GitSubcommand,\n stdout,\n stderr: err.message,\n exitCode: 1,\n truncated: stdout.length >= MAX_OUTPUT,\n });\n });\n\n child.on('close', (code) => {\n resolve({\n command: args[0] as GitSubcommand,\n stdout: stdout.slice(0, MAX_OUTPUT),\n stderr: stderr.slice(0, MAX_OUTPUT),\n exitCode: code ?? 1,\n truncated: stdout.length >= MAX_OUTPUT || stderr.length >= MAX_OUTPUT,\n });\n });\n });\n}\n"]}
|
package/dist/glob.js
CHANGED
|
@@ -23,6 +23,7 @@ function safeResolve(input, ctx) {
|
|
|
23
23
|
var DEFAULT_IGNORE = ["node_modules", ".git", "dist", "build", ".next", "coverage", ".turbo"];
|
|
24
24
|
var globTool = {
|
|
25
25
|
name: "glob",
|
|
26
|
+
category: "Filesystem",
|
|
26
27
|
description: "Find files matching a glob pattern. Returns paths sorted by mtime (newest first).",
|
|
27
28
|
usageHint: "Examples: `**/*.ts`, `src/**/*.test.ts`, `*.json`. Common dirs (node_modules, .git, dist) are ignored by default. Returns up to 1000 paths.",
|
|
28
29
|
permission: "auto",
|
package/dist/glob.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/_util.ts","../src/glob.ts"],"names":["path2"],"mappings":"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","file":"glob.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';\nimport * as path from 'node:path';\nimport { compileGlob } from '@wrongstack/core';\nimport type { Tool } from '@wrongstack/core';\nimport { safeResolve } from './_util.js';\n\ninterface GlobInput {\n pattern: string;\n path?: string;\n limit?: number;\n}\n\ninterface GlobOutput {\n files: string[];\n truncated: boolean;\n}\n\nconst DEFAULT_IGNORE = ['node_modules', '.git', 'dist', 'build', '.next', 'coverage', '.turbo'];\n\nexport const globTool: Tool<GlobInput, GlobOutput> = {\n name: 'glob',\n description: 'Find files matching a glob pattern. Returns paths sorted by mtime (newest first).',\n usageHint:\n 'Examples: `**/*.ts`, `src/**/*.test.ts`, `*.json`. Common dirs (node_modules, .git, dist) are ignored by default. Returns up to 1000 paths.',\n permission: 'auto',\n mutating: false,\n maxOutputBytes: 65_536,\n timeoutMs: 5_000,\n inputSchema: {\n type: 'object',\n properties: {\n pattern: { type: 'string' },\n path: { type: 'string', description: 'Base directory (defaults to cwd)' },\n limit: { type: 'integer' },\n },\n required: ['pattern'],\n },\n async execute(input, ctx) {\n if (!input?.pattern) throw new Error('glob: pattern is required');\n const base = input.path ? safeResolve(input.path, ctx) : ctx.cwd;\n const limit = Math.max(1, Math.min(input.limit ?? 1000, 5000));\n\n const ignored = await readGitignore(base);\n const re = compileGlob(input.pattern);\n\n const results: { rel: string; mtime: number }[] = [];\n let truncated = false;\n const walk = async (dir: string, relPrefix: string): Promise<void> => {\n if (results.length >= limit) {\n truncated = true;\n return;\n }\n let entries: import('node:fs').Dirent[];\n try {\n entries = await fs.readdir(dir, { withFileTypes: true });\n } catch {\n return;\n }\n for (const e of entries) {\n const name = e.name;\n if (DEFAULT_IGNORE.includes(name)) continue;\n if (ignored.includes(name)) continue;\n const rel = relPrefix ? `${relPrefix}/${name}` : name;\n const full = path.join(dir, name);\n if (e.isDirectory()) {\n await walk(full, rel);\n if (truncated) return;\n } else if (e.isFile()) {\n if (re.test(rel) || re.test(name)) {\n try {\n const st = await fs.stat(full);\n results.push({ rel: full, mtime: st.mtimeMs });\n if (results.length >= limit) {\n truncated = true;\n return;\n }\n } catch {\n // skip stat error\n }\n }\n }\n }\n };\n await walk(base, '');\n results.sort((a, b) => b.mtime - a.mtime);\n return { files: results.map((r) => r.rel), truncated };\n },\n};\n\nasync function readGitignore(dir: string): Promise<string[]> {\n try {\n const raw = await fs.readFile(path.join(dir, '.gitignore'), 'utf8');\n return raw\n .split('\\n')\n .map((l) => l.trim())\n .filter((l) => l && !l.startsWith('#'));\n } catch {\n return [];\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/_util.ts","../src/glob.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;;;ACFA,IAAM,cAAA,GAAiB,CAAC,cAAA,EAAgB,MAAA,EAAQ,QAAQ,OAAA,EAAS,OAAA,EAAS,YAAY,QAAQ,CAAA;AAEvF,IAAM,QAAA,GAAwC;AAAA,EACnD,IAAA,EAAM,MAAA;AAAA,EACN,QAAA,EAAU,YAAA;AAAA,EACV,WAAA,EAAa,mFAAA;AAAA,EACb,SAAA,EACE,6IAAA;AAAA,EACF,UAAA,EAAY,MAAA;AAAA,EACZ,QAAA,EAAU,KAAA;AAAA,EACV,cAAA,EAAgB,KAAA;AAAA,EAChB,SAAA,EAAW,GAAA;AAAA,EACX,WAAA,EAAa;AAAA,IACX,IAAA,EAAM,QAAA;AAAA,IACN,UAAA,EAAY;AAAA,MACV,OAAA,EAAS,EAAE,IAAA,EAAM,QAAA,EAAS;AAAA,MAC1B,IAAA,EAAM,EAAE,IAAA,EAAM,QAAA,EAAU,aAAa,kCAAA,EAAmC;AAAA,MACxE,KAAA,EAAO,EAAE,IAAA,EAAM,SAAA;AAAU,KAC3B;AAAA,IACA,QAAA,EAAU,CAAC,SAAS;AAAA,GACtB;AAAA,EACA,MAAM,OAAA,CAAQ,KAAA,EAAO,GAAA,EAAK;AACxB,IAAA,IAAI,CAAC,KAAA,EAAO,OAAA,EAAS,MAAM,IAAI,MAAM,2BAA2B,CAAA;AAChE,IAAA,MAAM,IAAA,GAAO,MAAM,IAAA,GAAO,WAAA,CAAY,MAAM,IAAA,EAAM,GAAG,IAAI,GAAA,CAAI,GAAA;AAC7D,IAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,IAAA,CAAK,IAAI,KAAA,CAAM,KAAA,IAAS,GAAA,EAAM,GAAI,CAAC,CAAA;AAE7D,IAAA,MAAM,OAAA,GAAU,MAAM,aAAA,CAAc,IAAI,CAAA;AACxC,IAAA,MAAM,EAAA,GAAK,WAAA,CAAY,KAAA,CAAM,OAAO,CAAA;AAEpC,IAAA,MAAM,UAA4C,EAAC;AACnD,IAAA,IAAI,SAAA,GAAY,KAAA;AAChB,IAAA,MAAM,IAAA,GAAO,OAAO,GAAA,EAAa,SAAA,KAAqC;AACpE,MAAA,IAAI,OAAA,CAAQ,UAAU,KAAA,EAAO;AAC3B,QAAA,SAAA,GAAY,IAAA;AACZ,QAAA;AAAA,MACF;AACA,MAAA,IAAI,OAAA;AACJ,MAAA,IAAI;AACF,QAAA,OAAA,GAAU,MAAS,EAAA,CAAA,OAAA,CAAQ,GAAA,EAAK,EAAE,aAAA,EAAe,MAAM,CAAA;AAAA,MACzD,CAAA,CAAA,MAAQ;AACN,QAAA;AAAA,MACF;AACA,MAAA,KAAA,MAAW,KAAK,OAAA,EAAS;AACvB,QAAA,MAAM,OAAO,CAAA,CAAE,IAAA;AACf,QAAA,IAAI,cAAA,CAAe,QAAA,CAAS,IAAI,CAAA,EAAG;AACnC,QAAA,IAAI,OAAA,CAAQ,QAAA,CAAS,IAAI,CAAA,EAAG;AAC5B,QAAA,MAAM,MAAM,SAAA,GAAY,CAAA,EAAG,SAAS,CAAA,CAAA,EAAI,IAAI,CAAA,CAAA,GAAK,IAAA;AACjD,QAAA,MAAM,IAAA,GAAYA,IAAA,CAAA,IAAA,CAAK,GAAA,EAAK,IAAI,CAAA;AAChC,QAAA,IAAI,CAAA,CAAE,aAAY,EAAG;AACnB,UAAA,MAAM,IAAA,CAAK,MAAM,GAAG,CAAA;AACpB,UAAA,IAAI,SAAA,EAAW;AAAA,QACjB,CAAA,MAAA,IAAW,CAAA,CAAE,MAAA,EAAO,EAAG;AACrB,UAAA,IAAI,GAAG,IAAA,CAAK,GAAG,KAAK,EAAA,CAAG,IAAA,CAAK,IAAI,CAAA,EAAG;AACjC,YAAA,IAAI;AACF,cAAA,MAAM,EAAA,GAAK,MAAS,EAAA,CAAA,IAAA,CAAK,IAAI,CAAA;AAC7B,cAAA,OAAA,CAAQ,KAAK,EAAE,GAAA,EAAK,MAAM,KAAA,EAAO,EAAA,CAAG,SAAS,CAAA;AAC7C,cAAA,IAAI,OAAA,CAAQ,UAAU,KAAA,EAAO;AAC3B,gBAAA,SAAA,GAAY,IAAA;AACZ,gBAAA;AAAA,cACF;AAAA,YACF,CAAA,CAAA,MAAQ;AAAA,YAER;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF,CAAA;AACA,IAAA,MAAM,IAAA,CAAK,MAAM,EAAE,CAAA;AACnB,IAAA,OAAA,CAAQ,KAAK,CAAC,CAAA,EAAG,MAAM,CAAA,CAAE,KAAA,GAAQ,EAAE,KAAK,CAAA;AACxC,IAAA,OAAO,EAAE,OAAO,OAAA,CAAQ,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,GAAG,CAAA,EAAG,SAAA,EAAU;AAAA,EACvD;AACF;AAEA,eAAe,cAAc,GAAA,EAAgC;AAC3D,EAAA,IAAI;AACF,IAAA,MAAM,MAAM,MAAS,EAAA,CAAA,QAAA,CAAcA,UAAK,GAAA,EAAK,YAAY,GAAG,MAAM,CAAA;AAClE,IAAA,OAAO,IACJ,KAAA,CAAM,IAAI,EACV,GAAA,CAAI,CAAC,MAAM,CAAA,CAAE,IAAA,EAAM,CAAA,CACnB,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,IAAK,CAAC,CAAA,CAAE,UAAA,CAAW,GAAG,CAAC,CAAA;AAAA,EAC1C,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,EAAC;AAAA,EACV;AACF","file":"glob.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';\nimport * as path from 'node:path';\nimport { compileGlob } from '@wrongstack/core';\nimport type { Tool } from '@wrongstack/core';\nimport { safeResolve } from './_util.js';\n\ninterface GlobInput {\n pattern: string;\n path?: string;\n limit?: number;\n}\n\ninterface GlobOutput {\n files: string[];\n truncated: boolean;\n}\n\nconst DEFAULT_IGNORE = ['node_modules', '.git', 'dist', 'build', '.next', 'coverage', '.turbo'];\n\nexport const globTool: Tool<GlobInput, GlobOutput> = {\n name: 'glob',\n category: 'Filesystem',\n description: 'Find files matching a glob pattern. Returns paths sorted by mtime (newest first).',\n usageHint:\n 'Examples: `**/*.ts`, `src/**/*.test.ts`, `*.json`. Common dirs (node_modules, .git, dist) are ignored by default. Returns up to 1000 paths.',\n permission: 'auto',\n mutating: false,\n maxOutputBytes: 65_536,\n timeoutMs: 5_000,\n inputSchema: {\n type: 'object',\n properties: {\n pattern: { type: 'string' },\n path: { type: 'string', description: 'Base directory (defaults to cwd)' },\n limit: { type: 'integer' },\n },\n required: ['pattern'],\n },\n async execute(input, ctx) {\n if (!input?.pattern) throw new Error('glob: pattern is required');\n const base = input.path ? safeResolve(input.path, ctx) : ctx.cwd;\n const limit = Math.max(1, Math.min(input.limit ?? 1000, 5000));\n\n const ignored = await readGitignore(base);\n const re = compileGlob(input.pattern);\n\n const results: { rel: string; mtime: number }[] = [];\n let truncated = false;\n const walk = async (dir: string, relPrefix: string): Promise<void> => {\n if (results.length >= limit) {\n truncated = true;\n return;\n }\n let entries: import('node:fs').Dirent[];\n try {\n entries = await fs.readdir(dir, { withFileTypes: true });\n } catch {\n return;\n }\n for (const e of entries) {\n const name = e.name;\n if (DEFAULT_IGNORE.includes(name)) continue;\n if (ignored.includes(name)) continue;\n const rel = relPrefix ? `${relPrefix}/${name}` : name;\n const full = path.join(dir, name);\n if (e.isDirectory()) {\n await walk(full, rel);\n if (truncated) return;\n } else if (e.isFile()) {\n if (re.test(rel) || re.test(name)) {\n try {\n const st = await fs.stat(full);\n results.push({ rel: full, mtime: st.mtimeMs });\n if (results.length >= limit) {\n truncated = true;\n return;\n }\n } catch {\n // skip stat error\n }\n }\n }\n }\n };\n await walk(base, '');\n results.sort((a, b) => b.mtime - a.mtime);\n return { files: results.map((r) => r.rel), truncated };\n },\n};\n\nasync function readGitignore(dir: string): Promise<string[]> {\n try {\n const raw = await fs.readFile(path.join(dir, '.gitignore'), 'utf8');\n return raw\n .split('\\n')\n .map((l) => l.trim())\n .filter((l) => l && !l.startsWith('#'));\n } catch {\n return [];\n }\n}\n"]}
|
package/dist/grep.js
CHANGED
|
@@ -71,6 +71,7 @@ function isBinaryBuffer(buf) {
|
|
|
71
71
|
var DEFAULT_IGNORE = ["node_modules", ".git", "dist", "build", ".next", "coverage"];
|
|
72
72
|
var grepTool = {
|
|
73
73
|
name: "grep",
|
|
74
|
+
category: "Search",
|
|
74
75
|
description: "Search file contents with a regex. Uses ripgrep when available.",
|
|
75
76
|
usageHint: 'Pattern is regex. Use `output_mode: "content"` for matched lines, `"files_with_matches"` for paths, `"count"` for tallies. `glob` filters files (e.g. `*.ts`).',
|
|
76
77
|
permission: "auto",
|
|
@@ -103,6 +104,10 @@ var grepTool = {
|
|
|
103
104
|
const base = input.path ? safeResolve(input.path, ctx) : ctx.cwd;
|
|
104
105
|
const mode = input.output_mode ?? "content";
|
|
105
106
|
const limit = Math.max(1, Math.min(input.limit ?? 200, 2e3));
|
|
107
|
+
const validation = compileUserRegex(input.pattern, input.case_insensitive ? "i" : "");
|
|
108
|
+
if (!validation.ok) {
|
|
109
|
+
throw new Error(`grep: ${validation.reason}`);
|
|
110
|
+
}
|
|
106
111
|
const rgAvailable = await detectRg(opts.signal);
|
|
107
112
|
if (rgAvailable) {
|
|
108
113
|
try {
|
|
@@ -136,11 +141,15 @@ async function* runRgStream(input, base, mode, limit, signal) {
|
|
|
136
141
|
args.push("-n");
|
|
137
142
|
if (input.context_lines) args.push("-C", String(input.context_lines));
|
|
138
143
|
}
|
|
144
|
+
for (const ignored of DEFAULT_IGNORE) {
|
|
145
|
+
args.push("--glob", `!${ignored}/**`, "--glob", `!**/${ignored}/**`);
|
|
146
|
+
}
|
|
139
147
|
if (input.glob) args.push("--glob", input.glob);
|
|
140
148
|
args.push("--", input.pattern, base);
|
|
141
149
|
const matches = [];
|
|
142
150
|
let buf = "";
|
|
143
151
|
let totalLines = 0;
|
|
152
|
+
let totalCount = 0;
|
|
144
153
|
let batchSinceFlush = 0;
|
|
145
154
|
const FLUSH_AT = 16;
|
|
146
155
|
const MAX_BUF_BYTES = 1e6;
|
|
@@ -197,6 +206,7 @@ async function* runRgStream(input, base, mode, limit, signal) {
|
|
|
197
206
|
for (const line of ready.split("\n")) {
|
|
198
207
|
if (!line) continue;
|
|
199
208
|
totalLines++;
|
|
209
|
+
if (mode === "count") totalCount += parseRgCountLine(line);
|
|
200
210
|
if (matches.length < limit) {
|
|
201
211
|
matches.push(line);
|
|
202
212
|
pendingBatch.push(line);
|
|
@@ -217,6 +227,7 @@ async function* runRgStream(input, base, mode, limit, signal) {
|
|
|
217
227
|
for (const line of buf.split("\n")) {
|
|
218
228
|
if (!line) continue;
|
|
219
229
|
totalLines++;
|
|
230
|
+
if (mode === "count") totalCount += parseRgCountLine(line);
|
|
220
231
|
if (matches.length < limit) {
|
|
221
232
|
matches.push(line);
|
|
222
233
|
pendingBatch.push(line);
|
|
@@ -235,12 +246,18 @@ async function* runRgStream(input, base, mode, limit, signal) {
|
|
|
235
246
|
type: "final",
|
|
236
247
|
output: {
|
|
237
248
|
matches,
|
|
238
|
-
count: totalLines,
|
|
249
|
+
count: mode === "count" ? totalCount : totalLines,
|
|
239
250
|
truncated: totalLines > limit || bufOverflow,
|
|
240
251
|
used: "rg"
|
|
241
252
|
}
|
|
242
253
|
};
|
|
243
254
|
}
|
|
255
|
+
function parseRgCountLine(line) {
|
|
256
|
+
const idx = line.lastIndexOf(":");
|
|
257
|
+
if (idx === -1) return 0;
|
|
258
|
+
const n = Number.parseInt(line.slice(idx + 1), 10);
|
|
259
|
+
return Number.isFinite(n) ? n : 0;
|
|
260
|
+
}
|
|
244
261
|
async function runNative(input, base, mode, limit, signal) {
|
|
245
262
|
const flags = input.case_insensitive ? "i" : "";
|
|
246
263
|
const compiled = compileUserRegex(input.pattern, flags);
|
package/dist/grep.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/_regex.ts","../src/_util.ts","../src/grep.ts"],"names":["resolve","path2","stat"],"mappings":"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","file":"grep.js","sourcesContent":["/**\n * Compile a user-supplied regex with conservative bounds against ReDoS.\n *\n * Node's regex engine (V8) is backtracking-based and cannot interrupt a\n * synchronous match — a pattern like `(a+)+$` against a sufficiently long\n * line will pin a worker for seconds. The executor's outer `timeoutMs` only\n * fires between async boundaries, so a long regex eval inside a sync loop\n * is uninterruptible.\n *\n * We can't fully prevent ReDoS without an alternative engine (re2-wasm), but\n * we can sharply limit the blast radius:\n *\n * 1. Cap pattern length — practically all legitimate user patterns are\n * under 256 characters. A 4 KB pattern is almost certainly malicious\n * or a copy-paste accident.\n * 2. Reject patterns containing the most obvious super-linear structures.\n * This is a coarse filter (false-positives are likely; we accept that\n * for hostile-input contexts).\n *\n * Callers should additionally bound the *subject* length (e.g. by capping\n * line size before matching).\n */\n\nconst MAX_PATTERN_LEN = 512;\n\n// Heuristics for catastrophic-backtracking constructs. Not exhaustive; bias\n// toward false-positives in tools that accept LLM-generated input.\nconst DANGEROUS_PATTERNS: ReadonlyArray<RegExp> = [\n /(\\([^)]*[+*][^)]*\\))[+*]/, // (a+)+, (.*)+, etc — nested quantifier on a group with internal quantifier\n /(\\(\\?:[^)]*[+*][^)]*\\))[+*]/, // same, with non-capturing group\n];\n\nexport interface CompileResult {\n ok: true;\n regex: RegExp;\n}\n\nexport interface CompileFail {\n ok: false;\n reason: string;\n}\n\nexport function compileUserRegex(pattern: string, flags: string): CompileResult | CompileFail {\n if (typeof pattern !== 'string') {\n return { ok: false, reason: 'pattern must be a string' };\n }\n if (pattern.length === 0) {\n return { ok: false, reason: 'pattern is empty' };\n }\n if (pattern.length > MAX_PATTERN_LEN) {\n return { ok: false, reason: `pattern exceeds ${MAX_PATTERN_LEN} characters` };\n }\n for (const rx of DANGEROUS_PATTERNS) {\n if (rx.test(pattern)) {\n return {\n ok: false,\n reason:\n 'pattern looks vulnerable to catastrophic backtracking — rewrite without nested quantifiers',\n };\n }\n }\n try {\n return { ok: true, regex: new RegExp(pattern, flags) };\n } catch (err) {\n return {\n ok: false,\n reason: err instanceof Error ? err.message : 'invalid regex',\n };\n }\n}\n\n/**\n * Truncate a subject line to a safe length for synchronous regex eval.\n * The cap is conservative; tools that need exact-line matching against very\n * long lines should use ripgrep externally rather than the native walker.\n */\nexport const MAX_SUBJECT_LEN = 64 * 1024;\n\nexport function capSubject(line: string): string {\n return line.length > MAX_SUBJECT_LEN ? line.slice(0, MAX_SUBJECT_LEN) : line;\n}\n","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 { spawn } from 'node:child_process';\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport type { Tool, ToolStreamEvent } from '@wrongstack/core';\nimport { compileGlob } from '@wrongstack/core';\nimport { capSubject, compileUserRegex } from './_regex.js';\nimport { isBinaryBuffer, safeResolve } from './_util.js';\n\ninterface GrepInput {\n pattern: string;\n path?: string;\n glob?: string;\n output_mode?: 'content' | 'files_with_matches' | 'count';\n context_lines?: number;\n case_insensitive?: boolean;\n limit?: number;\n}\n\ninterface GrepOutput {\n matches: string[];\n count: number;\n truncated: boolean;\n used: 'rg' | 'native';\n}\n\nconst DEFAULT_IGNORE = ['node_modules', '.git', 'dist', 'build', '.next', 'coverage'];\n\nexport const grepTool: Tool<GrepInput, GrepOutput> = {\n name: 'grep',\n description: 'Search file contents with a regex. Uses ripgrep when available.',\n usageHint:\n 'Pattern is regex. Use `output_mode: \"content\"` for matched lines, `\"files_with_matches\"` for paths, `\"count\"` for tallies. `glob` filters files (e.g. `*.ts`).',\n permission: 'auto',\n mutating: false,\n maxOutputBytes: 131_072,\n timeoutMs: 10_000,\n inputSchema: {\n type: 'object',\n properties: {\n pattern: { type: 'string' },\n path: { type: 'string' },\n glob: { type: 'string' },\n output_mode: { type: 'string', enum: ['content', 'files_with_matches', 'count'] },\n context_lines: { type: 'integer' },\n case_insensitive: { type: 'boolean' },\n limit: { type: 'integer' },\n },\n required: ['pattern'],\n },\n async execute(input, ctx, opts) {\n let final: GrepOutput | undefined;\n for await (const ev of grepTool.executeStream!(input, ctx, opts)) {\n if (ev.type === 'final') final = ev.output;\n }\n if (!final) throw new Error('grep: stream ended without final event');\n return final;\n },\n async *executeStream(input, ctx, opts): AsyncGenerator<ToolStreamEvent<GrepOutput>> {\n if (!input?.pattern) throw new Error('grep: pattern is required');\n const base = input.path ? safeResolve(input.path, ctx) : ctx.cwd;\n const mode = input.output_mode ?? 'content';\n const limit = Math.max(1, Math.min(input.limit ?? 200, 2000));\n\n const rgAvailable = await detectRg(opts.signal);\n if (rgAvailable) {\n try {\n yield* runRgStream(input, base, mode, limit, opts.signal);\n return;\n } catch {\n // fall through to native\n }\n }\n yield { type: 'log', text: 'Falling back to native grep…' };\n const out = await runNative(input, base, mode, limit, opts.signal);\n yield { type: 'final', output: out };\n },\n};\n\nasync function detectRg(signal: AbortSignal): Promise<boolean> {\n return new Promise((resolve) => {\n try {\n const p = spawn('rg', ['--version'], { stdio: 'ignore', signal });\n p.on('error', () => resolve(false));\n p.on('close', (code) => resolve(code === 0));\n } catch {\n resolve(false);\n }\n });\n}\n\nasync function* runRgStream(\n input: GrepInput,\n base: string,\n mode: 'content' | 'files_with_matches' | 'count',\n limit: number,\n signal: AbortSignal,\n): AsyncGenerator<ToolStreamEvent<GrepOutput>> {\n const args: string[] = ['--no-heading'];\n if (input.case_insensitive) args.push('-i');\n if (mode === 'files_with_matches') args.push('-l');\n if (mode === 'count') args.push('-c');\n if (mode === 'content') {\n args.push('-n');\n if (input.context_lines) args.push('-C', String(input.context_lines));\n }\n if (input.glob) args.push('--glob', input.glob);\n args.push('--', input.pattern, base);\n\n const matches: string[] = [];\n let buf = '';\n let totalLines = 0;\n let batchSinceFlush = 0;\n const FLUSH_AT = 16; // yield a partial_output every 16 matches\n // Cap on the in-progress line buffer. Without this, a single huge \"line\"\n // (e.g. a file with no newlines under a symlink) plus a fast producer\n // would let `buf` grow unbounded. 1 MB comfortably holds any realistic\n // grep hit; beyond that we kill the child and surface a truncation.\n const MAX_BUF_BYTES = 1_000_000;\n let bufOverflow = false;\n\n const child = spawn('rg', args, { signal, stdio: ['ignore', 'pipe', 'pipe'] });\n\n type Chunk = { kind: 'out' | 'close' | 'error'; data: string };\n const queue: Chunk[] = [];\n let waiter: (() => void) | undefined;\n const wake = () => {\n if (waiter) {\n const w = waiter;\n waiter = undefined;\n w();\n }\n };\n child.stdout?.on('data', (c) => {\n queue.push({ kind: 'out', data: c.toString() });\n wake();\n });\n child.on('error', (e) => {\n queue.push({ kind: 'error', data: e.message });\n wake();\n });\n child.on('close', () => {\n queue.push({ kind: 'close', data: '' });\n wake();\n });\n\n let pendingBatch: string[] = [];\n let errored = false;\n for (;;) {\n while (queue.length === 0) {\n await new Promise<void>((r) => {\n waiter = r;\n });\n }\n const c = queue.shift()!;\n if (c.kind === 'error') {\n errored = true;\n continue;\n }\n if (c.kind === 'close') break;\n buf += c.data;\n // Guard against a pathological producer (e.g. matching a huge binary\n // without newlines) pinning memory. Kill the child and mark the result\n // truncated; whatever we already captured stays intact.\n if (buf.length > MAX_BUF_BYTES && !bufOverflow) {\n bufOverflow = true;\n buf = buf.slice(-MAX_BUF_BYTES);\n try {\n child.kill('SIGTERM');\n } catch {\n /* ignore */\n }\n }\n const idx = buf.lastIndexOf('\\n');\n if (idx === -1) continue;\n const ready = buf.slice(0, idx);\n buf = buf.slice(idx + 1);\n for (const line of ready.split('\\n')) {\n if (!line) continue;\n totalLines++;\n if (matches.length < limit) {\n matches.push(line);\n pendingBatch.push(line);\n batchSinceFlush++;\n }\n }\n if (batchSinceFlush >= FLUSH_AT) {\n yield {\n type: 'partial_output',\n text: pendingBatch.join('\\n'),\n data: { matches_so_far: matches.length },\n };\n pendingBatch = [];\n batchSinceFlush = 0;\n }\n }\n\n if (buf.trim()) {\n for (const line of buf.split('\\n')) {\n if (!line) continue;\n totalLines++;\n if (matches.length < limit) {\n matches.push(line);\n pendingBatch.push(line);\n }\n }\n }\n if (pendingBatch.length > 0) {\n yield {\n type: 'partial_output',\n text: pendingBatch.join('\\n'),\n data: { matches_so_far: matches.length },\n };\n }\n if (errored) throw new Error('rg: spawn error');\n\n yield {\n type: 'final',\n output: {\n matches,\n count: totalLines,\n truncated: totalLines > limit || bufOverflow,\n used: 'rg',\n },\n };\n}\n\nasync function runNative(\n input: GrepInput,\n base: string,\n mode: 'content' | 'files_with_matches' | 'count',\n limit: number,\n signal: AbortSignal,\n): Promise<GrepOutput> {\n const flags = input.case_insensitive ? 'i' : '';\n const compiled = compileUserRegex(input.pattern, flags);\n if (!compiled.ok) {\n throw new Error(`grep: ${compiled.reason}`);\n }\n const re = compiled.regex;\n const globRe = input.glob ? compileGlob(input.glob) : null;\n const matches: string[] = [];\n const fileMatches = new Map<string, number>();\n let total = 0;\n let stopped = false;\n\n const walk = async (dir: string): Promise<void> => {\n if (stopped || signal.aborted) return;\n let entries: import('node:fs').Dirent[];\n try {\n entries = await fs.readdir(dir, { withFileTypes: true });\n } catch {\n return;\n }\n for (const e of entries) {\n if (stopped) return;\n if (DEFAULT_IGNORE.includes(e.name)) continue;\n // Skip symlinks entirely. fs.Dirent.isDirectory/isFile return the\n // symlink's TYPE without resolving, but following the link into\n // arbitrary places (e.g. ~/.ssh) is the security concern. Tools\n // that genuinely need to traverse symlinks should opt in explicitly.\n if (e.isSymbolicLink()) continue;\n const full = path.join(dir, e.name);\n if (e.isDirectory()) {\n await walk(full);\n } else if (e.isFile()) {\n if (globRe && !globRe.test(e.name) && !globRe.test(full)) continue;\n if (globRe) globRe.lastIndex = 0;\n try {\n const stat = await fs.stat(full);\n if (stat.size > 1_000_000) continue;\n const head = await fs.readFile(full);\n if (isBinaryBuffer(head)) continue;\n const text = head.toString('utf8');\n const lines = text.split(/\\r?\\n/);\n let fileHits = 0;\n for (let i = 0; i < lines.length; i++) {\n const ln = capSubject(lines[i] ?? '');\n re.lastIndex = 0;\n if (re.test(ln)) {\n fileHits++;\n total++;\n if (mode === 'content' && matches.length < limit) {\n matches.push(`${full}:${i + 1}:${ln}`);\n }\n }\n }\n if (fileHits > 0) {\n fileMatches.set(full, fileHits);\n if (mode === 'files_with_matches' && matches.length < limit) {\n matches.push(full);\n }\n if (mode === 'count' && matches.length < limit) {\n matches.push(`${full}:${fileHits}`);\n }\n }\n if (matches.length >= limit) stopped = true;\n } catch {\n // skip read errors\n }\n }\n }\n };\n await walk(base);\n\n return {\n matches,\n count: total,\n truncated: stopped,\n used: 'native',\n };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/_regex.ts","../src/_util.ts","../src/grep.ts"],"names":["resolve","path2","stat"],"mappings":"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","file":"grep.js","sourcesContent":["/**\n * Compile a user-supplied regex with conservative bounds against ReDoS.\n *\n * Node's regex engine (V8) is backtracking-based and cannot interrupt a\n * synchronous match — a pattern like `(a+)+$` against a sufficiently long\n * line will pin a worker for seconds. The executor's outer `timeoutMs` only\n * fires between async boundaries, so a long regex eval inside a sync loop\n * is uninterruptible.\n *\n * We can't fully prevent ReDoS without an alternative engine (re2-wasm), but\n * we can sharply limit the blast radius:\n *\n * 1. Cap pattern length — practically all legitimate user patterns are\n * under 256 characters. A 4 KB pattern is almost certainly malicious\n * or a copy-paste accident.\n * 2. Reject patterns containing the most obvious super-linear structures.\n * This is a coarse filter (false-positives are likely; we accept that\n * for hostile-input contexts).\n *\n * Callers should additionally bound the *subject* length (e.g. by capping\n * line size before matching).\n */\n\nconst MAX_PATTERN_LEN = 512;\n\n// Heuristics for catastrophic-backtracking constructs. Not exhaustive; bias\n// toward false-positives in tools that accept LLM-generated input.\nconst DANGEROUS_PATTERNS: ReadonlyArray<RegExp> = [\n /(\\([^)]*[+*][^)]*\\))[+*]/, // (a+)+, (.*)+, etc — nested quantifier on a group with internal quantifier\n /(\\(\\?:[^)]*[+*][^)]*\\))[+*]/, // same, with non-capturing group\n];\n\nexport interface CompileResult {\n ok: true;\n regex: RegExp;\n}\n\nexport interface CompileFail {\n ok: false;\n reason: string;\n}\n\nexport function compileUserRegex(pattern: string, flags: string): CompileResult | CompileFail {\n if (typeof pattern !== 'string') {\n return { ok: false, reason: 'pattern must be a string' };\n }\n if (pattern.length === 0) {\n return { ok: false, reason: 'pattern is empty' };\n }\n if (pattern.length > MAX_PATTERN_LEN) {\n return { ok: false, reason: `pattern exceeds ${MAX_PATTERN_LEN} characters` };\n }\n for (const rx of DANGEROUS_PATTERNS) {\n if (rx.test(pattern)) {\n return {\n ok: false,\n reason:\n 'pattern looks vulnerable to catastrophic backtracking — rewrite without nested quantifiers',\n };\n }\n }\n try {\n return { ok: true, regex: new RegExp(pattern, flags) };\n } catch (err) {\n return {\n ok: false,\n reason: err instanceof Error ? err.message : 'invalid regex',\n };\n }\n}\n\n/**\n * Truncate a subject line to a safe length for synchronous regex eval.\n * The cap is conservative; tools that need exact-line matching against very\n * long lines should use ripgrep externally rather than the native walker.\n */\nexport const MAX_SUBJECT_LEN = 64 * 1024;\n\nexport function capSubject(line: string): string {\n return line.length > MAX_SUBJECT_LEN ? line.slice(0, MAX_SUBJECT_LEN) : line;\n}\n","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 { spawn } from 'node:child_process';\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport type { Tool, ToolStreamEvent } from '@wrongstack/core';\nimport { compileGlob } from '@wrongstack/core';\nimport { capSubject, compileUserRegex } from './_regex.js';\nimport { isBinaryBuffer, safeResolve } from './_util.js';\n\ninterface GrepInput {\n pattern: string;\n path?: string;\n glob?: string;\n output_mode?: 'content' | 'files_with_matches' | 'count';\n context_lines?: number;\n case_insensitive?: boolean;\n limit?: number;\n}\n\ninterface GrepOutput {\n matches: string[];\n count: number;\n truncated: boolean;\n used: 'rg' | 'native';\n}\n\nconst DEFAULT_IGNORE = ['node_modules', '.git', 'dist', 'build', '.next', 'coverage'];\n\nexport const grepTool: Tool<GrepInput, GrepOutput> = {\n name: 'grep',\n category: 'Search',\n description: 'Search file contents with a regex. Uses ripgrep when available.',\n usageHint:\n 'Pattern is regex. Use `output_mode: \"content\"` for matched lines, `\"files_with_matches\"` for paths, `\"count\"` for tallies. `glob` filters files (e.g. `*.ts`).',\n permission: 'auto',\n mutating: false,\n maxOutputBytes: 131_072,\n timeoutMs: 10_000,\n inputSchema: {\n type: 'object',\n properties: {\n pattern: { type: 'string' },\n path: { type: 'string' },\n glob: { type: 'string' },\n output_mode: { type: 'string', enum: ['content', 'files_with_matches', 'count'] },\n context_lines: { type: 'integer' },\n case_insensitive: { type: 'boolean' },\n limit: { type: 'integer' },\n },\n required: ['pattern'],\n },\n async execute(input, ctx, opts) {\n let final: GrepOutput | undefined;\n for await (const ev of grepTool.executeStream!(input, ctx, opts)) {\n if (ev.type === 'final') final = ev.output;\n }\n if (!final) throw new Error('grep: stream ended without final event');\n return final;\n },\n async *executeStream(input, ctx, opts): AsyncGenerator<ToolStreamEvent<GrepOutput>> {\n if (!input?.pattern) throw new Error('grep: pattern is required');\n const base = input.path ? safeResolve(input.path, ctx) : ctx.cwd;\n const mode = input.output_mode ?? 'content';\n const limit = Math.max(1, Math.min(input.limit ?? 200, 2000));\n const validation = compileUserRegex(input.pattern, input.case_insensitive ? 'i' : '');\n if (!validation.ok) {\n throw new Error(`grep: ${validation.reason}`);\n }\n\n const rgAvailable = await detectRg(opts.signal);\n if (rgAvailable) {\n try {\n yield* runRgStream(input, base, mode, limit, opts.signal);\n return;\n } catch {\n // fall through to native\n }\n }\n yield { type: 'log', text: 'Falling back to native grep…' };\n const out = await runNative(input, base, mode, limit, opts.signal);\n yield { type: 'final', output: out };\n },\n};\n\nasync function detectRg(signal: AbortSignal): Promise<boolean> {\n return new Promise((resolve) => {\n try {\n const p = spawn('rg', ['--version'], { stdio: 'ignore', signal });\n p.on('error', () => resolve(false));\n p.on('close', (code) => resolve(code === 0));\n } catch {\n resolve(false);\n }\n });\n}\n\nasync function* runRgStream(\n input: GrepInput,\n base: string,\n mode: 'content' | 'files_with_matches' | 'count',\n limit: number,\n signal: AbortSignal,\n): AsyncGenerator<ToolStreamEvent<GrepOutput>> {\n const args: string[] = ['--no-heading'];\n if (input.case_insensitive) args.push('-i');\n if (mode === 'files_with_matches') args.push('-l');\n if (mode === 'count') args.push('-c');\n if (mode === 'content') {\n args.push('-n');\n if (input.context_lines) args.push('-C', String(input.context_lines));\n }\n for (const ignored of DEFAULT_IGNORE) {\n args.push('--glob', `!${ignored}/**`, '--glob', `!**/${ignored}/**`);\n }\n if (input.glob) args.push('--glob', input.glob);\n args.push('--', input.pattern, base);\n\n const matches: string[] = [];\n let buf = '';\n let totalLines = 0;\n let totalCount = 0;\n let batchSinceFlush = 0;\n const FLUSH_AT = 16; // yield a partial_output every 16 matches\n // Cap on the in-progress line buffer. Without this, a single huge \"line\"\n // (e.g. a file with no newlines under a symlink) plus a fast producer\n // would let `buf` grow unbounded. 1 MB comfortably holds any realistic\n // grep hit; beyond that we kill the child and surface a truncation.\n const MAX_BUF_BYTES = 1_000_000;\n let bufOverflow = false;\n\n const child = spawn('rg', args, { signal, stdio: ['ignore', 'pipe', 'pipe'] });\n\n type Chunk = { kind: 'out' | 'close' | 'error'; data: string };\n const queue: Chunk[] = [];\n let waiter: (() => void) | undefined;\n const wake = () => {\n if (waiter) {\n const w = waiter;\n waiter = undefined;\n w();\n }\n };\n child.stdout?.on('data', (c) => {\n queue.push({ kind: 'out', data: c.toString() });\n wake();\n });\n child.on('error', (e) => {\n queue.push({ kind: 'error', data: e.message });\n wake();\n });\n child.on('close', () => {\n queue.push({ kind: 'close', data: '' });\n wake();\n });\n\n let pendingBatch: string[] = [];\n let errored = false;\n for (;;) {\n while (queue.length === 0) {\n await new Promise<void>((r) => {\n waiter = r;\n });\n }\n const c = queue.shift()!;\n if (c.kind === 'error') {\n errored = true;\n continue;\n }\n if (c.kind === 'close') break;\n buf += c.data;\n // Guard against a pathological producer (e.g. matching a huge binary\n // without newlines) pinning memory. Kill the child and mark the result\n // truncated; whatever we already captured stays intact.\n if (buf.length > MAX_BUF_BYTES && !bufOverflow) {\n bufOverflow = true;\n buf = buf.slice(-MAX_BUF_BYTES);\n try {\n child.kill('SIGTERM');\n } catch {\n /* ignore */\n }\n }\n const idx = buf.lastIndexOf('\\n');\n if (idx === -1) continue;\n const ready = buf.slice(0, idx);\n buf = buf.slice(idx + 1);\n for (const line of ready.split('\\n')) {\n if (!line) continue;\n totalLines++;\n if (mode === 'count') totalCount += parseRgCountLine(line);\n if (matches.length < limit) {\n matches.push(line);\n pendingBatch.push(line);\n batchSinceFlush++;\n }\n }\n if (batchSinceFlush >= FLUSH_AT) {\n yield {\n type: 'partial_output',\n text: pendingBatch.join('\\n'),\n data: { matches_so_far: matches.length },\n };\n pendingBatch = [];\n batchSinceFlush = 0;\n }\n }\n\n if (buf.trim()) {\n for (const line of buf.split('\\n')) {\n if (!line) continue;\n totalLines++;\n if (mode === 'count') totalCount += parseRgCountLine(line);\n if (matches.length < limit) {\n matches.push(line);\n pendingBatch.push(line);\n }\n }\n }\n if (pendingBatch.length > 0) {\n yield {\n type: 'partial_output',\n text: pendingBatch.join('\\n'),\n data: { matches_so_far: matches.length },\n };\n }\n if (errored) throw new Error('rg: spawn error');\n\n yield {\n type: 'final',\n output: {\n matches,\n count: mode === 'count' ? totalCount : totalLines,\n truncated: totalLines > limit || bufOverflow,\n used: 'rg',\n },\n };\n}\n\nfunction parseRgCountLine(line: string): number {\n const idx = line.lastIndexOf(':');\n if (idx === -1) return 0;\n const n = Number.parseInt(line.slice(idx + 1), 10);\n return Number.isFinite(n) ? n : 0;\n}\n\nasync function runNative(\n input: GrepInput,\n base: string,\n mode: 'content' | 'files_with_matches' | 'count',\n limit: number,\n signal: AbortSignal,\n): Promise<GrepOutput> {\n const flags = input.case_insensitive ? 'i' : '';\n const compiled = compileUserRegex(input.pattern, flags);\n if (!compiled.ok) {\n throw new Error(`grep: ${compiled.reason}`);\n }\n const re = compiled.regex;\n const globRe = input.glob ? compileGlob(input.glob) : null;\n const matches: string[] = [];\n const fileMatches = new Map<string, number>();\n let total = 0;\n let stopped = false;\n\n const walk = async (dir: string): Promise<void> => {\n if (stopped || signal.aborted) return;\n let entries: import('node:fs').Dirent[];\n try {\n entries = await fs.readdir(dir, { withFileTypes: true });\n } catch {\n return;\n }\n for (const e of entries) {\n if (stopped) return;\n if (DEFAULT_IGNORE.includes(e.name)) continue;\n // Skip symlinks entirely. fs.Dirent.isDirectory/isFile return the\n // symlink's TYPE without resolving, but following the link into\n // arbitrary places (e.g. ~/.ssh) is the security concern. Tools\n // that genuinely need to traverse symlinks should opt in explicitly.\n if (e.isSymbolicLink()) continue;\n const full = path.join(dir, e.name);\n if (e.isDirectory()) {\n await walk(full);\n } else if (e.isFile()) {\n if (globRe && !globRe.test(e.name) && !globRe.test(full)) continue;\n if (globRe) globRe.lastIndex = 0;\n try {\n const stat = await fs.stat(full);\n if (stat.size > 1_000_000) continue;\n const head = await fs.readFile(full);\n if (isBinaryBuffer(head)) continue;\n const text = head.toString('utf8');\n const lines = text.split(/\\r?\\n/);\n let fileHits = 0;\n for (let i = 0; i < lines.length; i++) {\n const ln = capSubject(lines[i] ?? '');\n re.lastIndex = 0;\n if (re.test(ln)) {\n fileHits++;\n total++;\n if (mode === 'content' && matches.length < limit) {\n matches.push(`${full}:${i + 1}:${ln}`);\n }\n }\n }\n if (fileHits > 0) {\n fileMatches.set(full, fileHits);\n if (mode === 'files_with_matches' && matches.length < limit) {\n matches.push(full);\n }\n if (mode === 'count' && matches.length < limit) {\n matches.push(`${full}:${fileHits}`);\n }\n }\n if (matches.length >= limit) stopped = true;\n } catch {\n // skip read errors\n }\n }\n }\n };\n await walk(base);\n\n return {\n matches,\n count: total,\n truncated: stopped,\n used: 'native',\n };\n}\n"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -32,6 +32,7 @@ export { toolHelpTool } from './tool-help.js';
|
|
|
32
32
|
export { forgetTool, rememberTool } from './memory.js';
|
|
33
33
|
export { createModeTool } from './mode.js';
|
|
34
34
|
export { builtinTools } from './builtin.js';
|
|
35
|
+
export { builtinToolsPack } from './pack.js';
|
|
35
36
|
|
|
36
37
|
/**
|
|
37
38
|
* `planTool` — the LLM-callable counterpart to the `/plan` slash command.
|