@wrongstack/tools 0.8.4 → 0.8.6
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/builtin.js +166 -64
- package/dist/builtin.js.map +1 -1
- package/dist/codebase-index/index.js +14 -6
- package/dist/codebase-index/index.js.map +1 -1
- package/dist/exec.js +14 -2
- package/dist/exec.js.map +1 -1
- package/dist/fetch.js +48 -3
- package/dist/fetch.js.map +1 -1
- package/dist/git.js +38 -13
- package/dist/git.js.map +1 -1
- package/dist/index.js +166 -64
- package/dist/index.js.map +1 -1
- package/dist/logs.js +22 -11
- package/dist/logs.js.map +1 -1
- package/dist/pack.js +166 -64
- package/dist/pack.js.map +1 -1
- package/dist/replace.js +2 -1
- package/dist/replace.js.map +1 -1
- package/package.json +3 -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 { buildChildEnv } from '@wrongstack/core';\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 | 'worktree';\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 /** worktree action: list, add, remove, prune */\n worktreeAction?: 'list' | 'add' | 'remove' | 'prune';\n /** path for worktree add/remove (e.g. \"../wt-feature-xyz\") */\n worktreePath?: string;\n /** create new branch when adding worktree */\n newBranch?: boolean;\n /** force operation (e.g. worktree remove --force) */\n force?: boolean;\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, worktree.',\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 'worktree',\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 worktreeAction: {\n type: 'string',\n enum: ['list', 'add', 'remove', 'prune'],\n description: 'Worktree action: list, add, remove, prune',\n },\n worktreePath: {\n type: 'string',\n description: 'Path for worktree add/remove (e.g. \"../wt-feature-xyz\")',\n },\n newBranch: {\n type: 'boolean',\n description: 'Create new branch when adding worktree',\n },\n force: {\n type: 'boolean',\n description: 'Force operation (e.g. worktree remove --force)',\n },\n },\n required: ['command'],\n },\n async execute(input, ctx, opts) {\n if (!input?.command) throw new Error('git: command is required');\n\n if (input.command === 'commit' && !input.message) {\n return {\n command: 'commit',\n stdout: '',\n stderr: 'git commit requires a message (-m flag)',\n exitCode: 1,\n truncated: false,\n };\n }\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 // Validate branch name: reject names starting with '-' (flag injection).\n return input.branch\n ? ['branch', ...(input.branch.startsWith('-') ? [] : [input.branch])]\n : ['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 case 'worktree':\n switch (input.worktreeAction) {\n case 'list':\n return ['worktree', 'list'];\n case 'add':\n return [\n 'worktree',\n 'add',\n ...(input.newBranch ? ['-b'] : []),\n ...(input.branch ? [input.branch] : []),\n input.worktreePath ?? '',\n ].filter(Boolean);\n case 'remove':\n return [\n 'worktree',\n 'remove',\n ...(input.force ? ['--force'] : []),\n input.worktreePath ?? '',\n ].filter(Boolean);\n case 'prune':\n return ['worktree', 'prune'];\n default:\n return ['worktree', 'list'];\n }\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 env: buildChildEnv(),\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":["resolve"],"mappings":"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","file":"git.js","sourcesContent":["import { spawn } from 'node:child_process';\nimport { statSync } from 'node:fs';\nimport { dirname, resolve, sep } from 'node:path';\nimport { buildChildEnv } from '@wrongstack/core';\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 | 'worktree';\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 /** worktree action: list, add, remove, prune */\n worktreeAction?: 'list' | 'add' | 'remove' | 'prune';\n /** path for worktree add/remove (e.g. \"../wt-feature-xyz\") */\n worktreePath?: string;\n /** create new branch when adding worktree */\n newBranch?: boolean;\n /** force operation (e.g. worktree remove --force) */\n force?: boolean;\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, worktree.',\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 'worktree',\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 worktreeAction: {\n type: 'string',\n enum: ['list', 'add', 'remove', 'prune'],\n description: 'Worktree action: list, add, remove, prune',\n },\n worktreePath: {\n type: 'string',\n description: 'Path for worktree add/remove (e.g. \"../wt-feature-xyz\")',\n },\n newBranch: {\n type: 'boolean',\n description: 'Create new branch when adding worktree',\n },\n force: {\n type: 'boolean',\n description: 'Force operation (e.g. worktree remove --force)',\n },\n },\n required: ['command'],\n },\n async execute(input, ctx, opts) {\n if (!input?.command) throw new Error('git: command is required');\n\n if (input.command === 'commit' && !input.message) {\n return {\n command: 'commit',\n stdout: '',\n stderr: 'git commit requires a message (-m flag)',\n exitCode: 1,\n truncated: false,\n };\n }\n\n // Validate worktree paths/branches before touching the filesystem: reject\n // flag injection and any path that escapes the project root.\n if (input.command === 'worktree') {\n const guard = validateWorktreeInput(input, ctx.projectRoot);\n if (guard) return guard;\n }\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\n/**\n * Reject worktree inputs that could inject git flags or escape the project\n * root. Returns a `GitOutput` describing the rejection, or `null` if safe.\n */\nfunction validateWorktreeInput(input: GitInput, projectRoot: string): GitOutput | null {\n const reject = (stderr: string): GitOutput => ({\n command: 'worktree',\n stdout: '',\n stderr,\n exitCode: 1,\n truncated: false,\n });\n\n // Flag injection: a leading '-' would be parsed as a git option.\n if (input.branch?.startsWith('-')) return reject(`unsafe branch name: ${input.branch}`);\n if (input.worktreePath?.startsWith('-')) {\n return reject(`unsafe worktree path: ${input.worktreePath}`);\n }\n\n // Path escape: add/remove targets must resolve inside the project root.\n if (\n (input.worktreeAction === 'add' || input.worktreeAction === 'remove') &&\n input.worktreePath\n ) {\n const root = resolve(projectRoot);\n const abs = resolve(root, input.worktreePath);\n if (abs !== root && !abs.startsWith(root + sep)) {\n return reject(`unsafe worktree path (escapes project root): ${input.worktreePath}`);\n }\n }\n\n return null;\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 // A normal repo has a `.git` directory; a linked worktree has a `.git`\n // *file* (gitlink pointing at the main repo). Accept both so the tool\n // operates inside a worktree when a subagent's cwd is a worktree dir.\n if (stat.isDirectory() || stat.isFile()) 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 // Validate branch name: reject names starting with '-' (flag injection).\n return input.branch\n ? ['branch', ...(input.branch.startsWith('-') ? [] : [input.branch])]\n : ['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 case 'worktree':\n switch (input.worktreeAction) {\n case 'list':\n return ['worktree', 'list'];\n case 'add': {\n // git worktree add [-b <new-branch>] <path> [<commit-ish>]\n // The path comes BEFORE the branch/commit-ish. With --newBranch the\n // branch is the name to create (`-b <branch> <path>`); without it the\n // branch is an existing branch/commit to check out (`<path> <branch>`).\n if (!input.worktreePath) return ['worktree', 'list'];\n const add = ['worktree', 'add'];\n if (input.newBranch && input.branch) add.push('-b', input.branch);\n add.push(input.worktreePath);\n if (!input.newBranch && input.branch) add.push(input.branch);\n return add;\n }\n case 'remove':\n return [\n 'worktree',\n 'remove',\n ...(input.force ? ['--force'] : []),\n input.worktreePath ?? '',\n ].filter(Boolean);\n case 'prune':\n return ['worktree', 'prune'];\n default:\n return ['worktree', 'list'];\n }\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 env: buildChildEnv(),\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/index.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import * as fs4 from 'node:fs/promises';
|
|
2
2
|
import { stat } from 'node:fs/promises';
|
|
3
3
|
import * as path from 'node:path';
|
|
4
|
-
import { dirname } from 'node:path';
|
|
4
|
+
import { resolve, sep, dirname } from 'node:path';
|
|
5
5
|
import { atomicWrite, unifiedDiff, detectNewlineStyle, normalizeToLf, toStyle, compileGlob, buildChildEnv, stripAnsi, loadPlan, emptyPlan, clearPlan, savePlan, getPlanTemplate, addPlanItem, deriveTodosFromPlanItem, removePlanItem, setPlanItemStatus, formatPlan } from '@wrongstack/core';
|
|
6
|
-
import { spawn,
|
|
6
|
+
import { spawn, execFileSync, spawnSync } from 'node:child_process';
|
|
7
7
|
import * as os from 'node:os';
|
|
8
8
|
import * as dns from 'node:dns/promises';
|
|
9
9
|
import * as net from 'node:net';
|
|
10
|
+
import { Agent } from 'undici';
|
|
10
11
|
import * as fs13 from 'node:fs';
|
|
11
12
|
import { statSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
12
13
|
import { createRequire } from 'node:module';
|
|
@@ -371,6 +372,7 @@ var replaceTool = {
|
|
|
371
372
|
const dryRun = input.dry_run ?? false;
|
|
372
373
|
const filesInput = Array.isArray(input.files) ? input.files.join(",") : input.files;
|
|
373
374
|
const fileList = await resolveFiles(filesInput, ctx, globRe);
|
|
375
|
+
const realRoot = await fs4.realpath(ctx.projectRoot).catch(() => ctx.projectRoot);
|
|
374
376
|
const results = [];
|
|
375
377
|
let totalReplacements = 0;
|
|
376
378
|
for (const absPath of fileList) {
|
|
@@ -386,7 +388,7 @@ var replaceTool = {
|
|
|
386
388
|
} catch {
|
|
387
389
|
continue;
|
|
388
390
|
}
|
|
389
|
-
const rel = path.relative(
|
|
391
|
+
const rel = path.relative(realRoot, realPath);
|
|
390
392
|
if (rel.startsWith("..") || path.isAbsolute(rel)) continue;
|
|
391
393
|
const stat11 = await fs4.stat(realPath).catch(() => null);
|
|
392
394
|
if (!stat11 || !stat11.isFile()) continue;
|
|
@@ -464,13 +466,13 @@ async function globFiles(pattern, base, extraGlob) {
|
|
|
464
466
|
return await globNative(pattern, base, extraGlob);
|
|
465
467
|
}
|
|
466
468
|
function checkRg() {
|
|
467
|
-
return new Promise((
|
|
469
|
+
return new Promise((resolve7) => {
|
|
468
470
|
try {
|
|
469
471
|
const p = spawn("rg", ["--version"], { env: buildChildEnv(), stdio: "ignore" });
|
|
470
|
-
p.on("error", () =>
|
|
471
|
-
p.on("close", (code) =>
|
|
472
|
+
p.on("error", () => resolve7(false));
|
|
473
|
+
p.on("close", (code) => resolve7(code === 0));
|
|
472
474
|
} catch {
|
|
473
|
-
|
|
475
|
+
resolve7(false);
|
|
474
476
|
}
|
|
475
477
|
});
|
|
476
478
|
}
|
|
@@ -482,10 +484,10 @@ function spawnRgFind(pattern, base) {
|
|
|
482
484
|
buf += chunk.toString();
|
|
483
485
|
});
|
|
484
486
|
return {
|
|
485
|
-
promise: new Promise((
|
|
487
|
+
promise: new Promise((resolve7, reject) => {
|
|
486
488
|
child.on("error", reject);
|
|
487
489
|
child.on("close", () => {
|
|
488
|
-
|
|
490
|
+
resolve7(buf.split("\n").filter(Boolean));
|
|
489
491
|
});
|
|
490
492
|
})
|
|
491
493
|
};
|
|
@@ -654,13 +656,13 @@ var grepTool = {
|
|
|
654
656
|
}
|
|
655
657
|
};
|
|
656
658
|
async function detectRg(signal) {
|
|
657
|
-
return new Promise((
|
|
659
|
+
return new Promise((resolve7) => {
|
|
658
660
|
try {
|
|
659
661
|
const p = spawn("rg", ["--version"], { env: buildChildEnv(), stdio: "ignore", signal });
|
|
660
|
-
p.on("error", () =>
|
|
661
|
-
p.on("close", (code) =>
|
|
662
|
+
p.on("error", () => resolve7(false));
|
|
663
|
+
p.on("close", (code) => resolve7(code === 0));
|
|
662
664
|
} catch {
|
|
663
|
-
|
|
665
|
+
resolve7(false);
|
|
664
666
|
}
|
|
665
667
|
});
|
|
666
668
|
}
|
|
@@ -1371,10 +1373,10 @@ var bashTool = {
|
|
|
1371
1373
|
queue.push(c);
|
|
1372
1374
|
}
|
|
1373
1375
|
};
|
|
1374
|
-
const next = () => new Promise((
|
|
1376
|
+
const next = () => new Promise((resolve7) => {
|
|
1375
1377
|
const c = queue.shift();
|
|
1376
|
-
if (c)
|
|
1377
|
-
else resolveNext =
|
|
1378
|
+
if (c) resolve7(c);
|
|
1379
|
+
else resolveNext = resolve7;
|
|
1378
1380
|
});
|
|
1379
1381
|
let lastFlush = Date.now();
|
|
1380
1382
|
const flush = () => {
|
|
@@ -1488,8 +1490,20 @@ var BLOCKED_ARG_PATTERNS = {
|
|
|
1488
1490
|
// python -c/--command executes arbitrary code; python -m runs modules
|
|
1489
1491
|
python: [/-c$/, /^--command$/, /^-m$/, /^--module$/],
|
|
1490
1492
|
// git --exec=<cmd> runs arbitrary commands via upload-pack/receive-pack;
|
|
1491
|
-
// -C <dir> changes working directory, bypassing cwd sandbox
|
|
1492
|
-
|
|
1493
|
+
// -C <dir> changes working directory, bypassing cwd sandbox;
|
|
1494
|
+
// -c/--config <k>=<v> injects config that runs commands
|
|
1495
|
+
// (e.g. core.sshCommand, core.pager, http.proxy, alias.x=!cmd).
|
|
1496
|
+
git: [
|
|
1497
|
+
/^--exec=/,
|
|
1498
|
+
/^--upload-pack=/,
|
|
1499
|
+
/^--receive-pack=/,
|
|
1500
|
+
/^-C$/,
|
|
1501
|
+
/^-c$/,
|
|
1502
|
+
/^--config$/,
|
|
1503
|
+
/^-c=/,
|
|
1504
|
+
/^--config=/,
|
|
1505
|
+
/^--config-env=/
|
|
1506
|
+
],
|
|
1493
1507
|
// node -r/--require preloads arbitrary modules; --eval executes code
|
|
1494
1508
|
node: [/^-r$/, /^--require$/, /^-e$/, /^--eval$/, /^--prof-process$/],
|
|
1495
1509
|
// go run could execute arbitrary .go files; -ldflags could inject build-time code
|
|
@@ -1612,7 +1626,7 @@ var execTool = {
|
|
|
1612
1626
|
}
|
|
1613
1627
|
};
|
|
1614
1628
|
function runCommand(cmd, args, cwd, timeout, signal, sessionId) {
|
|
1615
|
-
return new Promise((
|
|
1629
|
+
return new Promise((resolve7) => {
|
|
1616
1630
|
let stdout = "";
|
|
1617
1631
|
let stderr = "";
|
|
1618
1632
|
let killed = false;
|
|
@@ -1646,7 +1660,7 @@ function runCommand(cmd, args, cwd, timeout, signal, sessionId) {
|
|
|
1646
1660
|
const durationMs = Date.now() - startedAt;
|
|
1647
1661
|
const exitCode = killed ? 124 : code ?? 1;
|
|
1648
1662
|
registry.afterCall(durationMs, exitCode !== 0);
|
|
1649
|
-
|
|
1663
|
+
resolve7({
|
|
1650
1664
|
command: cmd,
|
|
1651
1665
|
args,
|
|
1652
1666
|
stdout: stdout.slice(0, MAX_OUTPUT2),
|
|
@@ -1660,7 +1674,7 @@ function runCommand(cmd, args, cwd, timeout, signal, sessionId) {
|
|
|
1660
1674
|
clearTimeout(timer);
|
|
1661
1675
|
if (typeof pid === "number") registry.unregister(pid);
|
|
1662
1676
|
registry.afterCall(Date.now() - startedAt, true);
|
|
1663
|
-
|
|
1677
|
+
resolve7({
|
|
1664
1678
|
command: cmd,
|
|
1665
1679
|
args,
|
|
1666
1680
|
stdout: stdout.slice(0, MAX_OUTPUT2),
|
|
@@ -1675,6 +1689,48 @@ function runCommand(cmd, args, cwd, timeout, signal, sessionId) {
|
|
|
1675
1689
|
var MAX_BYTES2 = 131072;
|
|
1676
1690
|
var TIMEOUT_MS2 = 2e4;
|
|
1677
1691
|
var ALLOW_PRIVATE = process.env["WRONGSTACK_FETCH_ALLOW_PRIVATE"] === "1";
|
|
1692
|
+
function guardedLookup(hostname, options, callback) {
|
|
1693
|
+
dns.lookup(hostname, { all: true }).then((records) => {
|
|
1694
|
+
const family = options?.family;
|
|
1695
|
+
const byFamily = family === 4 || family === 6 ? records.filter((r) => r.family === family) : records;
|
|
1696
|
+
const list = byFamily.length > 0 ? byFamily : records;
|
|
1697
|
+
if (!ALLOW_PRIVATE) {
|
|
1698
|
+
for (const r of list) {
|
|
1699
|
+
const bad = r.family === 4 ? isPrivateIPv4(r.address) : isPrivateIPv6(r.address);
|
|
1700
|
+
if (bad) {
|
|
1701
|
+
callback(
|
|
1702
|
+
Object.assign(new Error(`fetch: resolved to private address ${r.address}`), {
|
|
1703
|
+
code: "EAI_FAIL"
|
|
1704
|
+
})
|
|
1705
|
+
);
|
|
1706
|
+
return;
|
|
1707
|
+
}
|
|
1708
|
+
}
|
|
1709
|
+
}
|
|
1710
|
+
if (options?.all) {
|
|
1711
|
+
callback(
|
|
1712
|
+
null,
|
|
1713
|
+
list.map((r) => ({ address: r.address, family: r.family }))
|
|
1714
|
+
);
|
|
1715
|
+
return;
|
|
1716
|
+
}
|
|
1717
|
+
const first = list[0];
|
|
1718
|
+
if (!first) {
|
|
1719
|
+
callback(
|
|
1720
|
+
Object.assign(new Error(`fetch: no address for ${hostname}`), { code: "ENOTFOUND" })
|
|
1721
|
+
);
|
|
1722
|
+
return;
|
|
1723
|
+
}
|
|
1724
|
+
callback(null, first.address, first.family);
|
|
1725
|
+
}).catch((err) => callback(err));
|
|
1726
|
+
}
|
|
1727
|
+
var pinnedAgent;
|
|
1728
|
+
function getPinnedDispatcher() {
|
|
1729
|
+
if (!pinnedAgent) {
|
|
1730
|
+
pinnedAgent = new Agent({ connect: { lookup: guardedLookup } });
|
|
1731
|
+
}
|
|
1732
|
+
return pinnedAgent;
|
|
1733
|
+
}
|
|
1678
1734
|
async function fetchWithRedirectLimit(url, maxRedirects, signal) {
|
|
1679
1735
|
const headers = {
|
|
1680
1736
|
"user-agent": "WrongStack/1.0 (+https://wrongstack.com)",
|
|
@@ -1691,11 +1747,13 @@ async function fetchWithRedirectLimit(url, maxRedirects, signal) {
|
|
|
1691
1747
|
throw new Error("fetch: redirect to http:// blocked (HTTPS required by default)");
|
|
1692
1748
|
}
|
|
1693
1749
|
await assertNotPrivate(parsed.hostname);
|
|
1694
|
-
const
|
|
1750
|
+
const init = {
|
|
1695
1751
|
redirect: "manual",
|
|
1696
1752
|
signal,
|
|
1697
|
-
headers
|
|
1698
|
-
|
|
1753
|
+
headers,
|
|
1754
|
+
dispatcher: getPinnedDispatcher()
|
|
1755
|
+
};
|
|
1756
|
+
const res = await fetch(currentUrl, init);
|
|
1699
1757
|
if (res.status < 300 || res.status > 399) {
|
|
1700
1758
|
return res;
|
|
1701
1759
|
}
|
|
@@ -2440,6 +2498,10 @@ var gitTool = {
|
|
|
2440
2498
|
truncated: false
|
|
2441
2499
|
};
|
|
2442
2500
|
}
|
|
2501
|
+
if (input.command === "worktree") {
|
|
2502
|
+
const guard = validateWorktreeInput(input, ctx.projectRoot);
|
|
2503
|
+
if (guard) return guard;
|
|
2504
|
+
}
|
|
2443
2505
|
const gitDir = findGitDir(ctx.cwd, ctx.projectRoot);
|
|
2444
2506
|
if (!gitDir) {
|
|
2445
2507
|
return {
|
|
@@ -2454,13 +2516,34 @@ var gitTool = {
|
|
|
2454
2516
|
return await runGit(args, gitDir, opts.signal);
|
|
2455
2517
|
}
|
|
2456
2518
|
};
|
|
2519
|
+
function validateWorktreeInput(input, projectRoot) {
|
|
2520
|
+
const reject = (stderr) => ({
|
|
2521
|
+
command: "worktree",
|
|
2522
|
+
stdout: "",
|
|
2523
|
+
stderr,
|
|
2524
|
+
exitCode: 1,
|
|
2525
|
+
truncated: false
|
|
2526
|
+
});
|
|
2527
|
+
if (input.branch?.startsWith("-")) return reject(`unsafe branch name: ${input.branch}`);
|
|
2528
|
+
if (input.worktreePath?.startsWith("-")) {
|
|
2529
|
+
return reject(`unsafe worktree path: ${input.worktreePath}`);
|
|
2530
|
+
}
|
|
2531
|
+
if ((input.worktreeAction === "add" || input.worktreeAction === "remove") && input.worktreePath) {
|
|
2532
|
+
const root = resolve(projectRoot);
|
|
2533
|
+
const abs = resolve(root, input.worktreePath);
|
|
2534
|
+
if (abs !== root && !abs.startsWith(root + sep)) {
|
|
2535
|
+
return reject(`unsafe worktree path (escapes project root): ${input.worktreePath}`);
|
|
2536
|
+
}
|
|
2537
|
+
}
|
|
2538
|
+
return null;
|
|
2539
|
+
}
|
|
2457
2540
|
function findGitDir(cwd, projectRoot) {
|
|
2458
2541
|
const root = projectRoot;
|
|
2459
2542
|
let dir = cwd;
|
|
2460
2543
|
for (let i = 0; i < 20; i++) {
|
|
2461
2544
|
try {
|
|
2462
2545
|
const stat11 = statSync(`${dir}/.git`);
|
|
2463
|
-
if (stat11.isDirectory()) return dir;
|
|
2546
|
+
if (stat11.isDirectory() || stat11.isFile()) return dir;
|
|
2464
2547
|
} catch {
|
|
2465
2548
|
}
|
|
2466
2549
|
if (dir === root) break;
|
|
@@ -2516,14 +2599,14 @@ function buildArgs(input) {
|
|
|
2516
2599
|
switch (input.worktreeAction) {
|
|
2517
2600
|
case "list":
|
|
2518
2601
|
return ["worktree", "list"];
|
|
2519
|
-
case "add":
|
|
2520
|
-
return [
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2602
|
+
case "add": {
|
|
2603
|
+
if (!input.worktreePath) return ["worktree", "list"];
|
|
2604
|
+
const add = ["worktree", "add"];
|
|
2605
|
+
if (input.newBranch && input.branch) add.push("-b", input.branch);
|
|
2606
|
+
add.push(input.worktreePath);
|
|
2607
|
+
if (!input.newBranch && input.branch) add.push(input.branch);
|
|
2608
|
+
return add;
|
|
2609
|
+
}
|
|
2527
2610
|
case "remove":
|
|
2528
2611
|
return [
|
|
2529
2612
|
"worktree",
|
|
@@ -2541,7 +2624,7 @@ function buildArgs(input) {
|
|
|
2541
2624
|
}
|
|
2542
2625
|
}
|
|
2543
2626
|
function runGit(args, cwd, signal) {
|
|
2544
|
-
return new Promise((
|
|
2627
|
+
return new Promise((resolve7) => {
|
|
2545
2628
|
let stdout = "";
|
|
2546
2629
|
let stderr = "";
|
|
2547
2630
|
const child = spawn("git", args, {
|
|
@@ -2561,7 +2644,7 @@ function runGit(args, cwd, signal) {
|
|
|
2561
2644
|
}
|
|
2562
2645
|
});
|
|
2563
2646
|
child.on("error", (err) => {
|
|
2564
|
-
|
|
2647
|
+
resolve7({
|
|
2565
2648
|
command: args[0],
|
|
2566
2649
|
stdout,
|
|
2567
2650
|
stderr: err.message,
|
|
@@ -2570,7 +2653,7 @@ function runGit(args, cwd, signal) {
|
|
|
2570
2653
|
});
|
|
2571
2654
|
});
|
|
2572
2655
|
child.on("close", (code) => {
|
|
2573
|
-
|
|
2656
|
+
resolve7({
|
|
2574
2657
|
command: args[0],
|
|
2575
2658
|
stdout: stdout.slice(0, MAX_OUTPUT3),
|
|
2576
2659
|
stderr: stderr.slice(0, MAX_OUTPUT3),
|
|
@@ -2666,7 +2749,7 @@ function stripPathComponents(p, strip) {
|
|
|
2666
2749
|
return parts.slice(strip).join("/");
|
|
2667
2750
|
}
|
|
2668
2751
|
function runPatch(args, cwd, signal) {
|
|
2669
|
-
return new Promise((
|
|
2752
|
+
return new Promise((resolve7) => {
|
|
2670
2753
|
let stdout = "";
|
|
2671
2754
|
let stderr = "";
|
|
2672
2755
|
const env = { ...buildChildEnv(), LANG: "C", LC_ALL: "C" };
|
|
@@ -2677,8 +2760,8 @@ function runPatch(args, cwd, signal) {
|
|
|
2677
2760
|
child.stderr?.on("data", (c) => {
|
|
2678
2761
|
stderr += c.toString();
|
|
2679
2762
|
});
|
|
2680
|
-
child.on("close", (code) =>
|
|
2681
|
-
child.on("error", (e) =>
|
|
2763
|
+
child.on("close", (code) => resolve7({ exitCode: code ?? 1, stdout, stderr }));
|
|
2764
|
+
child.on("error", (e) => resolve7({ exitCode: 1, stdout: "", stderr: e.message }));
|
|
2682
2765
|
});
|
|
2683
2766
|
}
|
|
2684
2767
|
function extractPatchedFiles(output) {
|
|
@@ -2880,7 +2963,7 @@ function findGitDir2(cwd) {
|
|
|
2880
2963
|
return null;
|
|
2881
2964
|
}
|
|
2882
2965
|
function runGit2(args, cwd, signal) {
|
|
2883
|
-
return new Promise((
|
|
2966
|
+
return new Promise((resolve7) => {
|
|
2884
2967
|
let stdout = "";
|
|
2885
2968
|
let stderr = "";
|
|
2886
2969
|
const child = spawn("git", args, { cwd, signal, env: buildChildEnv(), stdio: ["ignore", "pipe", "pipe"] });
|
|
@@ -2890,8 +2973,8 @@ function runGit2(args, cwd, signal) {
|
|
|
2890
2973
|
child.stderr?.on("data", (c) => {
|
|
2891
2974
|
stderr += c.toString();
|
|
2892
2975
|
});
|
|
2893
|
-
child.on("close", (code) =>
|
|
2894
|
-
child.on("error", (e) =>
|
|
2976
|
+
child.on("close", (code) => resolve7({ stdout, stderr, exitCode: code ?? 0 }));
|
|
2977
|
+
child.on("error", (e) => resolve7({ stdout: "", stderr: e.message, exitCode: 1 }));
|
|
2895
2978
|
});
|
|
2896
2979
|
}
|
|
2897
2980
|
async function fileDiff(input, ctx, signal) {
|
|
@@ -3142,8 +3225,8 @@ async function* spawnStream(opts) {
|
|
|
3142
3225
|
let spawnFailed = false;
|
|
3143
3226
|
for (; ; ) {
|
|
3144
3227
|
while (queue.length === 0) {
|
|
3145
|
-
await new Promise((
|
|
3146
|
-
waiter =
|
|
3228
|
+
await new Promise((resolve7) => {
|
|
3229
|
+
waiter = resolve7;
|
|
3147
3230
|
});
|
|
3148
3231
|
}
|
|
3149
3232
|
const chunk = queue.shift();
|
|
@@ -3862,7 +3945,7 @@ async function detectManager2(cwd) {
|
|
|
3862
3945
|
return "npm";
|
|
3863
3946
|
}
|
|
3864
3947
|
function runOutdated(manager, args, cwd, signal) {
|
|
3865
|
-
return new Promise((
|
|
3948
|
+
return new Promise((resolve7) => {
|
|
3866
3949
|
let stdout = "";
|
|
3867
3950
|
let stderr = "";
|
|
3868
3951
|
const MAX = 1e5;
|
|
@@ -3875,10 +3958,10 @@ function runOutdated(manager, args, cwd, signal) {
|
|
|
3875
3958
|
});
|
|
3876
3959
|
child.on("close", (code) => {
|
|
3877
3960
|
const result = parseOutdatedOutput(stdout, code ?? 0);
|
|
3878
|
-
|
|
3961
|
+
resolve7(result);
|
|
3879
3962
|
});
|
|
3880
3963
|
child.on("error", (e) => {
|
|
3881
|
-
|
|
3964
|
+
resolve7({
|
|
3882
3965
|
exit_code: 1,
|
|
3883
3966
|
packages: [],
|
|
3884
3967
|
total: 0,
|
|
@@ -4002,21 +4085,39 @@ async function dockerLogs(service, lines, filterRe, cwd, signal, since) {
|
|
|
4002
4085
|
};
|
|
4003
4086
|
}
|
|
4004
4087
|
args.push("--timestamps", service);
|
|
4005
|
-
return new Promise((
|
|
4088
|
+
return new Promise((resolve7) => {
|
|
4006
4089
|
let stdout = "";
|
|
4007
4090
|
let stderr = "";
|
|
4008
4091
|
const MAX = 2e5;
|
|
4092
|
+
let settled = false;
|
|
4093
|
+
const empty = () => ({
|
|
4094
|
+
source: `docker:${service}`,
|
|
4095
|
+
entries: [],
|
|
4096
|
+
total: 0,
|
|
4097
|
+
truncated: false,
|
|
4098
|
+
stream_mode: false
|
|
4099
|
+
});
|
|
4100
|
+
const finish = (result) => {
|
|
4101
|
+
if (settled) return;
|
|
4102
|
+
settled = true;
|
|
4103
|
+
clearTimeout(timer);
|
|
4104
|
+
resolve7(result);
|
|
4105
|
+
};
|
|
4009
4106
|
const child = spawn("docker", args, { cwd, signal, env: buildChildEnv(), stdio: ["ignore", "pipe", "pipe"] });
|
|
4107
|
+
const timer = setTimeout(() => {
|
|
4108
|
+
child.kill("SIGTERM");
|
|
4109
|
+
finish(empty());
|
|
4110
|
+
}, DOCKER_LOGS_TIMEOUT_MS);
|
|
4010
4111
|
child.stdout?.on("data", (c) => {
|
|
4011
4112
|
if (stdout.length < MAX) stdout += c.toString();
|
|
4012
4113
|
});
|
|
4013
4114
|
child.stderr?.on("data", (c) => {
|
|
4014
4115
|
if (stderr.length < MAX) stderr += c.toString();
|
|
4015
4116
|
});
|
|
4016
|
-
child.on("close", (
|
|
4117
|
+
child.on("close", () => {
|
|
4017
4118
|
const output = stdout + stderr;
|
|
4018
4119
|
const entries = parseLogLines(output, filterRe);
|
|
4019
|
-
|
|
4120
|
+
finish({
|
|
4020
4121
|
source: `docker:${service}`,
|
|
4021
4122
|
entries,
|
|
4022
4123
|
total: entries.length,
|
|
@@ -4024,17 +4125,10 @@ async function dockerLogs(service, lines, filterRe, cwd, signal, since) {
|
|
|
4024
4125
|
stream_mode: false
|
|
4025
4126
|
});
|
|
4026
4127
|
});
|
|
4027
|
-
child.on("error", (
|
|
4028
|
-
resolve6({
|
|
4029
|
-
source: `docker:${service}`,
|
|
4030
|
-
entries: [],
|
|
4031
|
-
total: 0,
|
|
4032
|
-
truncated: false,
|
|
4033
|
-
stream_mode: false
|
|
4034
|
-
});
|
|
4035
|
-
});
|
|
4128
|
+
child.on("error", () => finish(empty()));
|
|
4036
4129
|
});
|
|
4037
4130
|
}
|
|
4131
|
+
var DOCKER_LOGS_TIMEOUT_MS = 3e3;
|
|
4038
4132
|
var MAX_TAIL_LINES = 1e5;
|
|
4039
4133
|
async function fileLogs(path18, lines, filterRe, stream) {
|
|
4040
4134
|
const { createInterface } = await import('node:readline');
|
|
@@ -5747,7 +5841,7 @@ function syncGoParse(filePath, content, lang) {
|
|
|
5747
5841
|
mkdirSync(tmpDir, { recursive: true });
|
|
5748
5842
|
const scriptPath = path.join(tmpDir, "parse.go");
|
|
5749
5843
|
writeFileSync(scriptPath, GO_PARSE_SCRIPT, "utf8");
|
|
5750
|
-
const stdout =
|
|
5844
|
+
const stdout = execFileSync("go", ["run", scriptPath], {
|
|
5751
5845
|
input: content,
|
|
5752
5846
|
timeout: 15e3,
|
|
5753
5847
|
encoding: "utf8",
|
|
@@ -5993,7 +6087,7 @@ function syncPyParse(filePath, lang) {
|
|
|
5993
6087
|
mkdirSync(tmpDir, { recursive: true });
|
|
5994
6088
|
const scriptPath = path.join(tmpDir, "parse.py");
|
|
5995
6089
|
writeFileSync(scriptPath, PY_PARSE_SCRIPT, "utf8");
|
|
5996
|
-
const stdout =
|
|
6090
|
+
const stdout = execFileSync("python", [scriptPath, filePath], {
|
|
5997
6091
|
timeout: 15e3,
|
|
5998
6092
|
encoding: "utf8",
|
|
5999
6093
|
windowsHide: true
|
|
@@ -6031,11 +6125,19 @@ function parseSymbols4(opts) {
|
|
|
6031
6125
|
}
|
|
6032
6126
|
function checkNativeParser() {
|
|
6033
6127
|
try {
|
|
6034
|
-
|
|
6128
|
+
execFileSync("rustc", ["--version"], { stdio: "pipe" });
|
|
6035
6129
|
const toolsDir = path.join(process.cwd(), "tools");
|
|
6036
6130
|
try {
|
|
6037
|
-
|
|
6038
|
-
"cargo
|
|
6131
|
+
execFileSync(
|
|
6132
|
+
"cargo",
|
|
6133
|
+
[
|
|
6134
|
+
"metadata",
|
|
6135
|
+
"--no-deps",
|
|
6136
|
+
"--format-version",
|
|
6137
|
+
"1",
|
|
6138
|
+
"--manifest-path",
|
|
6139
|
+
path.join(toolsDir, "Cargo.toml")
|
|
6140
|
+
],
|
|
6039
6141
|
{ stdio: "pipe" }
|
|
6040
6142
|
);
|
|
6041
6143
|
return true;
|