@wrongstack/tools 0.274.0 → 0.275.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/audit.js +57 -19
- package/dist/audit.js.map +1 -1
- package/dist/bash.js +166 -83
- package/dist/bash.js.map +1 -1
- package/dist/builtin.js +503 -119
- package/dist/builtin.js.map +1 -1
- package/dist/circuit-breaker.js +1 -0
- package/dist/circuit-breaker.js.map +1 -1
- package/dist/edit.js +1 -1
- package/dist/edit.js.map +1 -1
- package/dist/exec.js +136 -38
- package/dist/exec.js.map +1 -1
- package/dist/fetch.js +9 -1
- package/dist/fetch.js.map +1 -1
- package/dist/format.js +57 -19
- package/dist/format.js.map +1 -1
- package/dist/index.d.ts +37 -1
- package/dist/index.js +514 -130
- package/dist/index.js.map +1 -1
- package/dist/install.js +65 -19
- package/dist/install.js.map +1 -1
- package/dist/lint.js +57 -19
- package/dist/lint.js.map +1 -1
- package/dist/pack.js +501 -118
- package/dist/pack.js.map +1 -1
- package/dist/process-registry.d.ts +30 -0
- package/dist/process-registry.js +57 -19
- package/dist/process-registry.js.map +1 -1
- package/dist/search.js.map +1 -1
- package/dist/test.js +57 -19
- package/dist/test.js.map +1 -1
- package/dist/typecheck.js +57 -19
- package/dist/typecheck.js.map +1 -1
- package/dist/write.js +2 -2
- package/dist/write.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as fs7 from 'node:fs/promises';
|
|
2
2
|
import * as Core from '@wrongstack/core';
|
|
3
|
-
import { toErrorMessage, atomicWrite, unifiedDiff, detectNewlineStyle, normalizeToLf, toStyle, compileGlob, expectDefined, buildChildEnv, isPrivateIPv4, isPrivateIPv6, loadPlan, setPlanItemStatus, savePlan, loadTasks, saveTasks, mutatePlan, clearPlan, getPlanTemplate, addPlanItem, deriveTodosFromPlanItem, removePlanItem, mutateTasks, formatTaskList, formatPlan, assessCommitSafety, recordPackageAction, detectPackageEcosystem, computeTaskItemProgress, wstackGlobalRoot, resolveWstackPaths, truncate } from '@wrongstack/core';
|
|
3
|
+
import { toErrorMessage, atomicWrite, unifiedDiff, detectNewlineStyle, normalizeToLf, toStyle, compileGlob, expectDefined, buildChildEnv, isPrivateIPv4, isPrivateIPv6, loadPlan, setPlanItemStatus, savePlan, loadTasks, saveTasks, mutatePlan, clearPlan, getPlanTemplate, addPlanItem, deriveTodosFromPlanItem, removePlanItem, mutateTasks, formatTaskList, formatPlan, assessCommitSafety, recordPackageAction, detectPackageEcosystem, getDesignKitLoader, isDesignStack, loadActiveKit, applyTokenOverrides, setActiveKit, recordKitChoice, recordOverrides, setDesignOverrides, materializeTokens, runDesignVerify, computeTaskItemProgress, wstackGlobalRoot, resolveWstackPaths, truncate } from '@wrongstack/core';
|
|
4
4
|
import * as path from 'node:path';
|
|
5
5
|
import { resolve, sep, dirname, join } from 'node:path';
|
|
6
6
|
import { spawn, execFileSync } from 'node:child_process';
|
|
@@ -375,7 +375,7 @@ var writeTool = {
|
|
|
375
375
|
if (existed) {
|
|
376
376
|
if (!ctx.hasRead(absPath)) {
|
|
377
377
|
prev = await fs7.readFile(absPath, "utf8");
|
|
378
|
-
ctx.recordRead(absPath, stat12.mtimeMs);
|
|
378
|
+
ctx.recordRead(absPath, stat12.mtimeMs, "write");
|
|
379
379
|
} else {
|
|
380
380
|
prev = await fs7.readFile(absPath, "utf8");
|
|
381
381
|
}
|
|
@@ -389,7 +389,7 @@ var writeTool = {
|
|
|
389
389
|
const diff = existed ? unifiedDiff(prev, input.content, { fromFile: input.path, toFile: input.path }) : `+++ ${input.path}
|
|
390
390
|
+ (new file, ${input.content.split("\n").length} lines)`;
|
|
391
391
|
const stat11 = await fs7.stat(absPath);
|
|
392
|
-
ctx.recordRead(absPath, stat11.mtimeMs);
|
|
392
|
+
ctx.recordRead(absPath, stat11.mtimeMs, "write");
|
|
393
393
|
ctx.session.recordFileChange({
|
|
394
394
|
path: absPath,
|
|
395
395
|
action: existed ? "modified" : "created",
|
|
@@ -486,7 +486,7 @@ var editTool = {
|
|
|
486
486
|
const newFile = toStyle(newFileLf, style);
|
|
487
487
|
await atomicWrite(absPath, newFile, { mode: updated.mode & 511 });
|
|
488
488
|
const written = await fs7.stat(absPath);
|
|
489
|
-
ctx.recordRead(absPath, written.mtimeMs);
|
|
489
|
+
ctx.recordRead(absPath, written.mtimeMs, "write");
|
|
490
490
|
ctx.session.recordFileChange({
|
|
491
491
|
path: absPath,
|
|
492
492
|
action: "modified",
|
|
@@ -1522,6 +1522,7 @@ var CircuitBreaker = class {
|
|
|
1522
1522
|
if (this.state === "open") return;
|
|
1523
1523
|
this.state = "open";
|
|
1524
1524
|
this.openedAt = Date.now();
|
|
1525
|
+
this.window = [];
|
|
1525
1526
|
try {
|
|
1526
1527
|
this.onTrip?.();
|
|
1527
1528
|
} catch {
|
|
@@ -1561,7 +1562,7 @@ var SENSITIVE_FLAG_PATTERNS = [
|
|
|
1561
1562
|
/--(?:token|password|passwd|pwd|secret|api[-_]?key|api[-_]?secret|auth|credential|private[-_]?key|access[-_]?key|github[-_]?token|gh[-_]?token|bearer|jwt|oauth|pin|pincode|passphrase|access[-_]?token)(?:[=\s,][^\s]*)?/gi,
|
|
1562
1563
|
// -f "value" style short flags
|
|
1563
1564
|
/(?<!\w)-t(?:\s+|\s*=\s*)[^\s,]+/,
|
|
1564
|
-
/(?<!\w)-
|
|
1565
|
+
/(?<!\w)-(?:p|password)(?:\s+|\s*=\s*)[^\s,]+/gi,
|
|
1565
1566
|
// env var–style secrets: TOKEN=x, API_KEY=y, etc.
|
|
1566
1567
|
/(?:TOKEN|API_KEY|API_SECRET|AUTH_TOKEN|GITHUB_TOKEN|GH_TOKEN|BEARER|JWT|OAUTH|CREDENTIAL|SECRET|PRIVATE_KEY|PASSWORD|PASSWD)\s*[=:]\s*[^\s,]+/gi,
|
|
1567
1568
|
// Generic high-entropy look: base64 strings >32 chars or hex strings >32 digits — but only
|
|
@@ -1622,12 +1623,35 @@ var ProcessRegistryImpl = class {
|
|
|
1622
1623
|
register(info) {
|
|
1623
1624
|
this.processes.set(info.pid, { ...info, killed: false, protected: info.protected ?? false });
|
|
1624
1625
|
}
|
|
1626
|
+
_isSafeSignalPid(pid) {
|
|
1627
|
+
return Number.isInteger(pid) && pid > 1 && pid !== process.pid && pid !== process.ppid;
|
|
1628
|
+
}
|
|
1629
|
+
_canSignalProcessGroup(p) {
|
|
1630
|
+
return os2.platform() !== "win32" && p.processGroupLeader === true && this._isSafeSignalPid(p.pid) && typeof p.child.pid === "number" && p.child.pid === p.pid;
|
|
1631
|
+
}
|
|
1632
|
+
_killChildDirect(p, signal) {
|
|
1633
|
+
try {
|
|
1634
|
+
p.child.kill(signal);
|
|
1635
|
+
} catch {
|
|
1636
|
+
}
|
|
1637
|
+
}
|
|
1638
|
+
_killPosix(p, signal) {
|
|
1639
|
+
if (this._canSignalProcessGroup(p)) {
|
|
1640
|
+
try {
|
|
1641
|
+
process.kill(-p.pid, signal);
|
|
1642
|
+
return;
|
|
1643
|
+
} catch {
|
|
1644
|
+
}
|
|
1645
|
+
}
|
|
1646
|
+
this._killChildDirect(p, signal);
|
|
1647
|
+
}
|
|
1625
1648
|
/** Unregister a process by PID. Called on 'close' / 'exit' events. */
|
|
1626
1649
|
unregister(pid) {
|
|
1627
1650
|
this.processes.delete(pid);
|
|
1628
1651
|
}
|
|
1629
1652
|
/** Get a single process by PID. */
|
|
1630
1653
|
get(pid) {
|
|
1654
|
+
this._pruneStale(pid);
|
|
1631
1655
|
return this.processes.get(pid);
|
|
1632
1656
|
}
|
|
1633
1657
|
/** Get all tracked processes. */
|
|
@@ -1791,13 +1815,14 @@ var ProcessRegistryImpl = class {
|
|
|
1791
1815
|
* Returns true if the process was found and kill was attempted.
|
|
1792
1816
|
*/
|
|
1793
1817
|
kill(pid, opts = {}) {
|
|
1818
|
+
this._pruneStale(pid);
|
|
1794
1819
|
const p = this.processes.get(pid);
|
|
1795
1820
|
if (!p) return false;
|
|
1796
1821
|
if (p.killed) return true;
|
|
1797
1822
|
if (p.protected) return false;
|
|
1798
1823
|
const { force = false, graceMs = DEFAULT_GRACE_MS } = opts;
|
|
1799
|
-
const
|
|
1800
|
-
if (
|
|
1824
|
+
const isWin4 = os2.platform() === "win32";
|
|
1825
|
+
if (isWin4) {
|
|
1801
1826
|
const liveRealChild = p.child.exitCode === null && typeof p.child.pid === "number";
|
|
1802
1827
|
if (liveRealChild && killWin32Tree(pid)) {
|
|
1803
1828
|
const fallback = setTimeout(() => {
|
|
@@ -1820,27 +1845,12 @@ var ProcessRegistryImpl = class {
|
|
|
1820
1845
|
}
|
|
1821
1846
|
try {
|
|
1822
1847
|
if (force) {
|
|
1823
|
-
|
|
1824
|
-
process.kill(-pid, "SIGKILL");
|
|
1825
|
-
} catch {
|
|
1826
|
-
p.child.kill("SIGKILL");
|
|
1827
|
-
}
|
|
1848
|
+
this._killPosix(p, "SIGKILL");
|
|
1828
1849
|
} else {
|
|
1829
|
-
|
|
1830
|
-
process.kill(-pid, "SIGTERM");
|
|
1831
|
-
} catch {
|
|
1832
|
-
p.child.kill("SIGTERM");
|
|
1833
|
-
}
|
|
1850
|
+
this._killPosix(p, "SIGTERM");
|
|
1834
1851
|
const timer = setTimeout(() => {
|
|
1835
1852
|
if (this.processes.has(pid) && !p.child.killed) {
|
|
1836
|
-
|
|
1837
|
-
process.kill(-pid, "SIGKILL");
|
|
1838
|
-
} catch {
|
|
1839
|
-
try {
|
|
1840
|
-
p.child.kill("SIGKILL");
|
|
1841
|
-
} catch {
|
|
1842
|
-
}
|
|
1843
|
-
}
|
|
1853
|
+
this._killPosix(p, "SIGKILL");
|
|
1844
1854
|
}
|
|
1845
1855
|
}, graceMs);
|
|
1846
1856
|
timer.unref?.();
|
|
@@ -1875,6 +1885,34 @@ var ProcessRegistryImpl = class {
|
|
|
1875
1885
|
}
|
|
1876
1886
|
return killed;
|
|
1877
1887
|
}
|
|
1888
|
+
/**
|
|
1889
|
+
* Check whether a tracked process entry is stale — the child has exited
|
|
1890
|
+
* (exitCode !== null) AND it's been in the registry long enough that the
|
|
1891
|
+
* OS may have reused the PID for a new, unrelated process.
|
|
1892
|
+
*
|
|
1893
|
+
* P3 #24 (before-release.md): on POSIX, PIDs are reused after process
|
|
1894
|
+
* exit. If a tracked process exits but its 'close' event hasn't fired yet
|
|
1895
|
+
* (or was missed), the registry still holds the entry. A new process
|
|
1896
|
+
* gets the same PID, and PID-based lookups (get, kill, shouldBlockKill)
|
|
1897
|
+
* may incorrectly protect or target the wrong process.
|
|
1898
|
+
*
|
|
1899
|
+
* The 60s threshold is conservative — the OS typically waits much longer
|
|
1900
|
+
* before reusing a PID, but we want to clean up before that becomes a risk.
|
|
1901
|
+
*/
|
|
1902
|
+
_isStaleEntry(entry) {
|
|
1903
|
+
return entry.child.exitCode !== null && Date.now() - entry.startedAt > 6e4;
|
|
1904
|
+
}
|
|
1905
|
+
/**
|
|
1906
|
+
* Remove a stale entry for a specific PID before any PID-based lookup.
|
|
1907
|
+
* This prevents PID reuse from causing the registry to act on a dead
|
|
1908
|
+
* process that has been replaced by a new one with the same PID.
|
|
1909
|
+
*/
|
|
1910
|
+
_pruneStale(pid) {
|
|
1911
|
+
const entry = this.processes.get(pid);
|
|
1912
|
+
if (entry && this._isStaleEntry(entry)) {
|
|
1913
|
+
this.processes.delete(pid);
|
|
1914
|
+
}
|
|
1915
|
+
}
|
|
1878
1916
|
};
|
|
1879
1917
|
var _registry;
|
|
1880
1918
|
function getProcessRegistry() {
|
|
@@ -2299,17 +2337,18 @@ function resetPersistentProcessRegistry() {
|
|
|
2299
2337
|
}
|
|
2300
2338
|
|
|
2301
2339
|
// src/bash-kill-guard.ts
|
|
2340
|
+
var isWin = os2.platform() === "win32";
|
|
2302
2341
|
function extractKillCommand(command) {
|
|
2303
2342
|
const normalized = command.replace(/\s+/g, " ").trim();
|
|
2304
2343
|
const shellCMatch = normalized.match(
|
|
2305
|
-
/^(
|
|
2344
|
+
/^(?:\S+(?:\s+\S+)?)?\s+-c\s+['"](.+?)['"]$/
|
|
2306
2345
|
);
|
|
2307
2346
|
if (shellCMatch?.[1]) {
|
|
2308
2347
|
const inner = shellCMatch[1].trim();
|
|
2309
2348
|
return isKillRelatedCommand(inner) ? inner : null;
|
|
2310
2349
|
}
|
|
2311
2350
|
const shellCUnquoted = normalized.match(
|
|
2312
|
-
/^(
|
|
2351
|
+
/^(?:\S+(?:\s+\S+)?)?\s+-c\s+(kill(?:\s+-[a-zA-Z]+)?(?:\s+\d+)+)$/
|
|
2313
2352
|
);
|
|
2314
2353
|
if (shellCUnquoted?.[1]) {
|
|
2315
2354
|
return shellCUnquoted[1];
|
|
@@ -2318,15 +2357,43 @@ function extractKillCommand(command) {
|
|
|
2318
2357
|
}
|
|
2319
2358
|
function isKillRelatedCommand(cmd) {
|
|
2320
2359
|
const normalized = cmd.toLowerCase().replace(/\s+/g, " ").trim();
|
|
2360
|
+
if (isWin) {
|
|
2361
|
+
if (/^taskkill\s/i.test(normalized)) return true;
|
|
2362
|
+
if (/^tskill\s/i.test(normalized)) return true;
|
|
2363
|
+
return false;
|
|
2364
|
+
}
|
|
2321
2365
|
if (/^kill(\s|$)/.test(normalized)) return true;
|
|
2322
2366
|
if (/^(pkill|killall|pgrep|skill)\s/.test(normalized)) return true;
|
|
2323
|
-
if (/^taskkill\s/i.test(normalized)) return true;
|
|
2324
|
-
if (/^tskill\s/i.test(normalized)) return true;
|
|
2325
2367
|
if (/^\/proc\/\d+\/(?:kill|fd)/.test(normalized)) return true;
|
|
2326
2368
|
return false;
|
|
2327
2369
|
}
|
|
2328
2370
|
function parseKillCommand(command) {
|
|
2329
2371
|
const normalized = command.replace(/\s+/g, " ").trim();
|
|
2372
|
+
if (isWin) {
|
|
2373
|
+
const taskkillMatch = normalized.match(/^taskkill\s+(?:\/[a-zA-Z]+\s+)*\/PID\s+(\d+)/i);
|
|
2374
|
+
if (taskkillMatch?.[1]) {
|
|
2375
|
+
const pidStr = taskkillMatch[1];
|
|
2376
|
+
return {
|
|
2377
|
+
pid: parseInt(pidStr, 10),
|
|
2378
|
+
signal: normalized.includes("/F") ? "FORCE" : "TERM",
|
|
2379
|
+
isGroupKill: false,
|
|
2380
|
+
isAllKill: false,
|
|
2381
|
+
originalCommand: command
|
|
2382
|
+
};
|
|
2383
|
+
}
|
|
2384
|
+
const tskillMatch = normalized.match(/^tskill\s+(\d+)/i);
|
|
2385
|
+
if (tskillMatch?.[1]) {
|
|
2386
|
+
const pidStr = tskillMatch[1];
|
|
2387
|
+
return {
|
|
2388
|
+
pid: parseInt(pidStr, 10),
|
|
2389
|
+
signal: "TERM",
|
|
2390
|
+
isGroupKill: false,
|
|
2391
|
+
isAllKill: false,
|
|
2392
|
+
originalCommand: command
|
|
2393
|
+
};
|
|
2394
|
+
}
|
|
2395
|
+
return null;
|
|
2396
|
+
}
|
|
2330
2397
|
const simpleMatch = normalized.match(/^kill\s+(?:(-[a-zA-Z]+)\s+)?(\d+|-?\d+)$/);
|
|
2331
2398
|
if (simpleMatch) {
|
|
2332
2399
|
const signal = simpleMatch[1] ?? "-TERM";
|
|
@@ -2370,28 +2437,6 @@ function parseKillCommand(command) {
|
|
|
2370
2437
|
if (pgrepMatch) {
|
|
2371
2438
|
return null;
|
|
2372
2439
|
}
|
|
2373
|
-
const taskkillMatch = normalized.match(/^taskkill\s+(?:\/[a-zA-Z]+\s+)*\/PID\s+(\d+)/i);
|
|
2374
|
-
if (taskkillMatch?.[1]) {
|
|
2375
|
-
const pidStr = taskkillMatch[1];
|
|
2376
|
-
return {
|
|
2377
|
-
pid: parseInt(pidStr, 10),
|
|
2378
|
-
signal: normalized.includes("/F") ? "FORCE" : "TERM",
|
|
2379
|
-
isGroupKill: false,
|
|
2380
|
-
isAllKill: false,
|
|
2381
|
-
originalCommand: command
|
|
2382
|
-
};
|
|
2383
|
-
}
|
|
2384
|
-
const tskillMatch = normalized.match(/^tskill\s+(\d+)/i);
|
|
2385
|
-
if (tskillMatch?.[1]) {
|
|
2386
|
-
const pidStr = tskillMatch[1];
|
|
2387
|
-
return {
|
|
2388
|
-
pid: parseInt(pidStr, 10),
|
|
2389
|
-
signal: "TERM",
|
|
2390
|
-
isGroupKill: false,
|
|
2391
|
-
isAllKill: false,
|
|
2392
|
-
originalCommand: command
|
|
2393
|
-
};
|
|
2394
|
-
}
|
|
2395
2440
|
return null;
|
|
2396
2441
|
}
|
|
2397
2442
|
async function getProtectedEntries() {
|
|
@@ -2468,7 +2513,7 @@ async function checkAndBlockKillCommand(command) {
|
|
|
2468
2513
|
}
|
|
2469
2514
|
return { blocked: false };
|
|
2470
2515
|
}
|
|
2471
|
-
function pickShell(
|
|
2516
|
+
function pickShell(platform5, command, env) {
|
|
2472
2517
|
const override = env.get("WRONGSTACK_SHELL")?.trim().toLowerCase();
|
|
2473
2518
|
if (override === "cmd" || override === "cmd.exe") return "cmd";
|
|
2474
2519
|
if (override === "powershell" || override === "powershell.exe") return "powershell";
|
|
@@ -2522,7 +2567,7 @@ function looksLikePowerShellExtended(command) {
|
|
|
2522
2567
|
}
|
|
2523
2568
|
function wrapPowerShellScript(command) {
|
|
2524
2569
|
const bootstrap = "[Console]::OutputEncoding = [System.Text.Encoding]::UTF8;$ConfirmPreference='None';$WhatIfPreference=$false";
|
|
2525
|
-
return
|
|
2570
|
+
return bootstrap + "\n$ErrorActionPreference='Stop'\n" + command + "\nif ($LASTEXITCODE -is [int]) { exit $LASTEXITCODE }";
|
|
2526
2571
|
}
|
|
2527
2572
|
var PS_VERB_RE = new RegExp(
|
|
2528
2573
|
// Boundaries: start-of-string, whitespace, `;`, `&`, `|`, `(`, `{`, `,`.
|
|
@@ -2712,10 +2757,10 @@ var bashTool = {
|
|
|
2712
2757
|
}));
|
|
2713
2758
|
}
|
|
2714
2759
|
const timeoutMs = Math.max(1, Math.min(input.timeout_ms ?? DEFAULT_TIMEOUT_MS, 6e5));
|
|
2715
|
-
const
|
|
2760
|
+
const isWin4 = os2.platform() === "win32";
|
|
2716
2761
|
let plan;
|
|
2717
2762
|
let winShellKind;
|
|
2718
|
-
if (
|
|
2763
|
+
if (isWin4) {
|
|
2719
2764
|
const shell2 = pickShell("win32", input.command, {
|
|
2720
2765
|
get: (k) => process.env[k]
|
|
2721
2766
|
});
|
|
@@ -2744,7 +2789,7 @@ var bashTool = {
|
|
|
2744
2789
|
const shell = plan.bin;
|
|
2745
2790
|
const args = plan.useStdin ? [...plan.argv] : [...plan.argv, input.command];
|
|
2746
2791
|
const env = buildChildEnv(ctx.session?.id);
|
|
2747
|
-
const detached = !
|
|
2792
|
+
const detached = !isWin4;
|
|
2748
2793
|
const startedAt = Date.now();
|
|
2749
2794
|
if (input.background) {
|
|
2750
2795
|
let buf2 = "";
|
|
@@ -2762,7 +2807,7 @@ var bashTool = {
|
|
|
2762
2807
|
// apply: the child gets a hidden console that grandchildren inherit.
|
|
2763
2808
|
// Windows children survive parent exit either way. POSIX keeps
|
|
2764
2809
|
// detached for the process-group kill semantics.
|
|
2765
|
-
detached: !
|
|
2810
|
+
detached: !isWin4,
|
|
2766
2811
|
windowsHide: true
|
|
2767
2812
|
});
|
|
2768
2813
|
if (plan.useStdin) {
|
|
@@ -2780,7 +2825,8 @@ var bashTool = {
|
|
|
2780
2825
|
command: redactCommand(input.command),
|
|
2781
2826
|
startedAt: Date.now(),
|
|
2782
2827
|
sessionId: ctx.session?.id,
|
|
2783
|
-
child: child2
|
|
2828
|
+
child: child2,
|
|
2829
|
+
processGroupLeader: detached && child2.pid === pid2
|
|
2784
2830
|
});
|
|
2785
2831
|
child2.on("close", () => registry.unregister(pid2));
|
|
2786
2832
|
}
|
|
@@ -2821,6 +2867,14 @@ var bashTool = {
|
|
|
2821
2867
|
pid: pid2
|
|
2822
2868
|
}
|
|
2823
2869
|
};
|
|
2870
|
+
ctx.recordSideEffect?.({
|
|
2871
|
+
toolUseId: `bash-bg-${Date.now()}`,
|
|
2872
|
+
toolName: "bash",
|
|
2873
|
+
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2874
|
+
input: { command: redactCommand(input.command), background: true },
|
|
2875
|
+
outcome: `launched (pid ${pid2 ?? "unknown"})`,
|
|
2876
|
+
risk: "shell"
|
|
2877
|
+
});
|
|
2824
2878
|
return;
|
|
2825
2879
|
}
|
|
2826
2880
|
const child = spawn(shell, args, {
|
|
@@ -2831,7 +2885,7 @@ var bashTool = {
|
|
|
2831
2885
|
stdio: [plan.useStdin ? "pipe" : "ignore", "pipe", "pipe"],
|
|
2832
2886
|
detached,
|
|
2833
2887
|
windowsHide: true,
|
|
2834
|
-
...
|
|
2888
|
+
...isWin4 ? {} : { signal: opts.signal }
|
|
2835
2889
|
});
|
|
2836
2890
|
if (plan.useStdin) {
|
|
2837
2891
|
try {
|
|
@@ -2848,7 +2902,8 @@ var bashTool = {
|
|
|
2848
2902
|
command: redactCommand(input.command),
|
|
2849
2903
|
startedAt: Date.now(),
|
|
2850
2904
|
sessionId: ctx.session?.id,
|
|
2851
|
-
child
|
|
2905
|
+
child,
|
|
2906
|
+
processGroupLeader: detached && child.pid === pid
|
|
2852
2907
|
});
|
|
2853
2908
|
}
|
|
2854
2909
|
let buf = "";
|
|
@@ -2857,7 +2912,7 @@ var bashTool = {
|
|
|
2857
2912
|
const timers = [];
|
|
2858
2913
|
const spool = createOutputSpool({ tool: "bash", thresholdBytes: MAX_OUTPUT });
|
|
2859
2914
|
function killWithTimeout(child2, timeoutMs2) {
|
|
2860
|
-
if (
|
|
2915
|
+
if (isWin4) {
|
|
2861
2916
|
if (typeof child2.pid === "number" && child2.exitCode === null && killWin32Tree(child2.pid)) {
|
|
2862
2917
|
const fallback = setTimeout(() => {
|
|
2863
2918
|
if (child2.exitCode === null) {
|
|
@@ -2877,34 +2932,22 @@ var bashTool = {
|
|
|
2877
2932
|
}
|
|
2878
2933
|
return;
|
|
2879
2934
|
}
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
|
|
2883
|
-
|
|
2884
|
-
} catch {
|
|
2885
|
-
child2.kill("SIGTERM");
|
|
2886
|
-
}
|
|
2887
|
-
} else {
|
|
2935
|
+
if (typeof child2.pid === "number") {
|
|
2936
|
+
registry.kill(child2.pid, { graceMs: timeoutMs2 });
|
|
2937
|
+
} else {
|
|
2938
|
+
try {
|
|
2888
2939
|
child2.kill("SIGTERM");
|
|
2940
|
+
} catch {
|
|
2889
2941
|
}
|
|
2890
|
-
|
|
2891
|
-
|
|
2892
|
-
const killTimer = setTimeout(() => {
|
|
2893
|
-
try {
|
|
2894
|
-
if (typeof child2.pid === "number") {
|
|
2895
|
-
try {
|
|
2896
|
-
process.kill(-child2.pid, "SIGKILL");
|
|
2897
|
-
} catch {
|
|
2898
|
-
child2.kill("SIGKILL");
|
|
2899
|
-
}
|
|
2900
|
-
} else {
|
|
2942
|
+
const killTimer = setTimeout(() => {
|
|
2943
|
+
try {
|
|
2901
2944
|
child2.kill("SIGKILL");
|
|
2945
|
+
} catch {
|
|
2902
2946
|
}
|
|
2903
|
-
}
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
killTimer.unref?.();
|
|
2947
|
+
}, timeoutMs2);
|
|
2948
|
+
timers.push(killTimer);
|
|
2949
|
+
killTimer.unref?.();
|
|
2950
|
+
}
|
|
2908
2951
|
}
|
|
2909
2952
|
const timer = setTimeout(() => {
|
|
2910
2953
|
timedOut = true;
|
|
@@ -2913,7 +2956,7 @@ var bashTool = {
|
|
|
2913
2956
|
timers.push(timer);
|
|
2914
2957
|
timer.unref?.();
|
|
2915
2958
|
const onAbort = () => killWithTimeout(child, 2e3);
|
|
2916
|
-
if (
|
|
2959
|
+
if (isWin4) {
|
|
2917
2960
|
if (opts.signal.aborted) onAbort();
|
|
2918
2961
|
else opts.signal.addEventListener("abort", onAbort, { once: true });
|
|
2919
2962
|
}
|
|
@@ -3001,6 +3044,14 @@ ${hint}` : ""),
|
|
|
3001
3044
|
timed_out: timedOut
|
|
3002
3045
|
}
|
|
3003
3046
|
};
|
|
3047
|
+
ctx.recordSideEffect?.({
|
|
3048
|
+
toolUseId: `bash-${Date.now()}`,
|
|
3049
|
+
toolName: "bash",
|
|
3050
|
+
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3051
|
+
input: { command: redactCommand(input.command) },
|
|
3052
|
+
outcome: timedOut ? `timed out (exit ${c.code})` : `exit ${c.code}`,
|
|
3053
|
+
risk: "shell"
|
|
3054
|
+
});
|
|
3004
3055
|
return;
|
|
3005
3056
|
}
|
|
3006
3057
|
const now2 = Date.now();
|
|
@@ -3012,7 +3063,7 @@ ${hint}` : ""),
|
|
|
3012
3063
|
} finally {
|
|
3013
3064
|
for (const t of timers) clearTimeout(t);
|
|
3014
3065
|
spool.finalize();
|
|
3015
|
-
if (
|
|
3066
|
+
if (isWin4) opts.signal.removeEventListener("abort", onAbort);
|
|
3016
3067
|
child.stdout?.off("data", onData);
|
|
3017
3068
|
child.stderr?.off("data", onData);
|
|
3018
3069
|
child.stdout?.destroy();
|
|
@@ -3022,6 +3073,38 @@ ${hint}` : ""),
|
|
|
3022
3073
|
else killWithTimeout(child, 2e3);
|
|
3023
3074
|
}
|
|
3024
3075
|
}
|
|
3076
|
+
},
|
|
3077
|
+
/**
|
|
3078
|
+
* Tool-level teardown fired by `ToolExecutor.runToolCleanup()` when the
|
|
3079
|
+
* tool's run is aborted/timeout'd. The generator's `finally` block above
|
|
3080
|
+
* already force-kills the direct child, but that only runs if the
|
|
3081
|
+
* executor closes the async iterator (via `iter.return()`). When the
|
|
3082
|
+
* executor tears down without iterating — or a re-entrant abort races
|
|
3083
|
+
* with the generator — a bash-spawned process tree can survive in the
|
|
3084
|
+
* ProcessRegistry with `killed === false`, continuing to write files,
|
|
3085
|
+
* consume CPU, or hold inherited stdio pipes open for the rest of the
|
|
3086
|
+
* session.
|
|
3087
|
+
*
|
|
3088
|
+
* This is the defensive layer the executor calls via `tool.cleanup()`
|
|
3089
|
+
* (see `types/tool.ts`): kill every bash-owned process still tracked
|
|
3090
|
+
* for this session that hasn't exited yet. `registry.kill()` already
|
|
3091
|
+
* handles process-group / taskkill tree-kill and the SIGTERM→SIGKILL
|
|
3092
|
+
* grace window, so this just scopes the registry's existing kill path
|
|
3093
|
+
* to "this session's runaway bash children". Idempotent — a process
|
|
3094
|
+
* that already exited is skipped by `kill()` (it returns false), and a
|
|
3095
|
+
* `protected` infrastructure process (dev server the user intentionally
|
|
3096
|
+
* backgrounded) is left alone by design.
|
|
3097
|
+
*/
|
|
3098
|
+
async cleanup(_input, ctx) {
|
|
3099
|
+
const registry = getProcessRegistry();
|
|
3100
|
+
const sessionId = ctx.session?.id;
|
|
3101
|
+
if (!sessionId) return;
|
|
3102
|
+
for (const entry of registry.bySession(sessionId)) {
|
|
3103
|
+
if (entry.name !== "bash") continue;
|
|
3104
|
+
if (entry.child.exitCode !== null) continue;
|
|
3105
|
+
if (entry.protected) continue;
|
|
3106
|
+
registry.kill(entry.pid, { force: true });
|
|
3107
|
+
}
|
|
3025
3108
|
}
|
|
3026
3109
|
};
|
|
3027
3110
|
|
|
@@ -3033,8 +3116,8 @@ function normalizeShell(value) {
|
|
|
3033
3116
|
if (v === "pwsh" || v === "pwsh.exe") return "pwsh";
|
|
3034
3117
|
return void 0;
|
|
3035
3118
|
}
|
|
3036
|
-
function resolveSessionShell(
|
|
3037
|
-
if (
|
|
3119
|
+
function resolveSessionShell(platform5, env, deps = {}) {
|
|
3120
|
+
if (platform5 !== "win32") return void 0;
|
|
3038
3121
|
const override = normalizeShell(env.get("WRONGSTACK_SHELL"));
|
|
3039
3122
|
if (override) return override;
|
|
3040
3123
|
const hasBinary = deps.hasBinary ?? ((bin) => resolveWin32Command(bin) !== bin);
|
|
@@ -3044,15 +3127,15 @@ function resolveSessionShell(platform4, env, deps = {}) {
|
|
|
3044
3127
|
}
|
|
3045
3128
|
function ensureSessionShell(opts = {}) {
|
|
3046
3129
|
const env = opts.env ?? process.env;
|
|
3047
|
-
const
|
|
3048
|
-
if (
|
|
3130
|
+
const platform5 = opts.platform ?? process.platform;
|
|
3131
|
+
if (platform5 !== "win32") return void 0;
|
|
3049
3132
|
const existing = normalizeShell(env["WRONGSTACK_SHELL"]);
|
|
3050
3133
|
if (existing) return existing;
|
|
3051
|
-
const chosen = resolveSessionShell(
|
|
3134
|
+
const chosen = resolveSessionShell(platform5, { get: (k) => env[k] }, { hasBinary: opts.hasBinary }) ?? "cmd";
|
|
3052
3135
|
env["WRONGSTACK_SHELL"] = chosen;
|
|
3053
3136
|
return chosen;
|
|
3054
3137
|
}
|
|
3055
|
-
var
|
|
3138
|
+
var isWin2 = process.platform === "win32";
|
|
3056
3139
|
var DEFAULT_ALLOWED_COMMANDS = /* @__PURE__ */ new Set([
|
|
3057
3140
|
// JS / TS toolchain
|
|
3058
3141
|
"node",
|
|
@@ -3062,12 +3145,25 @@ var DEFAULT_ALLOWED_COMMANDS = /* @__PURE__ */ new Set([
|
|
|
3062
3145
|
"npx",
|
|
3063
3146
|
"bun",
|
|
3064
3147
|
"deno",
|
|
3148
|
+
"corepack",
|
|
3065
3149
|
"tsc",
|
|
3150
|
+
"tsx",
|
|
3151
|
+
"ts-node",
|
|
3152
|
+
"vite",
|
|
3066
3153
|
"vitest",
|
|
3067
3154
|
"jest",
|
|
3068
3155
|
"biome",
|
|
3069
3156
|
"eslint",
|
|
3070
3157
|
"prettier",
|
|
3158
|
+
"turbo",
|
|
3159
|
+
"nx",
|
|
3160
|
+
"webpack",
|
|
3161
|
+
"rollup",
|
|
3162
|
+
"parcel",
|
|
3163
|
+
"next",
|
|
3164
|
+
"astro",
|
|
3165
|
+
"playwright",
|
|
3166
|
+
"cypress",
|
|
3071
3167
|
// version control
|
|
3072
3168
|
"git",
|
|
3073
3169
|
// Rust
|
|
@@ -3080,10 +3176,22 @@ var DEFAULT_ALLOWED_COMMANDS = /* @__PURE__ */ new Set([
|
|
|
3080
3176
|
"python3",
|
|
3081
3177
|
"pip",
|
|
3082
3178
|
"pip3",
|
|
3179
|
+
"pytest",
|
|
3180
|
+
"ruff",
|
|
3181
|
+
"mypy",
|
|
3182
|
+
"uv",
|
|
3183
|
+
"uvx",
|
|
3184
|
+
"poetry",
|
|
3185
|
+
"hatch",
|
|
3186
|
+
"tox",
|
|
3083
3187
|
// Ruby
|
|
3084
3188
|
"ruby",
|
|
3085
3189
|
"gem",
|
|
3086
3190
|
"bundle",
|
|
3191
|
+
// PHP
|
|
3192
|
+
"php",
|
|
3193
|
+
"composer",
|
|
3194
|
+
"phpunit",
|
|
3087
3195
|
// JVM
|
|
3088
3196
|
"java",
|
|
3089
3197
|
"javac",
|
|
@@ -3095,18 +3203,25 @@ var DEFAULT_ALLOWED_COMMANDS = /* @__PURE__ */ new Set([
|
|
|
3095
3203
|
// C / C++ / native build
|
|
3096
3204
|
"make",
|
|
3097
3205
|
"cmake",
|
|
3098
|
-
// containers / orchestration
|
|
3206
|
+
// containers / orchestration
|
|
3099
3207
|
"docker",
|
|
3208
|
+
"podman",
|
|
3100
3209
|
"kubectl",
|
|
3101
3210
|
// common POSIX file/text utilities
|
|
3211
|
+
"pwd",
|
|
3102
3212
|
"ls",
|
|
3103
3213
|
"cat",
|
|
3104
3214
|
"head",
|
|
3105
3215
|
"tail",
|
|
3106
3216
|
"wc",
|
|
3107
3217
|
"grep",
|
|
3218
|
+
"rg",
|
|
3108
3219
|
"find",
|
|
3109
3220
|
"echo",
|
|
3221
|
+
"sort",
|
|
3222
|
+
"uniq",
|
|
3223
|
+
"sed",
|
|
3224
|
+
"awk",
|
|
3110
3225
|
"mkdir",
|
|
3111
3226
|
"cp",
|
|
3112
3227
|
"mv",
|
|
@@ -3137,8 +3252,7 @@ var MAX_ARGS = 20;
|
|
|
3137
3252
|
var MAX_OUTPUT2 = 2e5;
|
|
3138
3253
|
var DEFAULT_TIMEOUT_MS2 = 3e4;
|
|
3139
3254
|
var BLOCKED_ARG_PATTERNS = {
|
|
3140
|
-
|
|
3141
|
-
python: [/-c$/, /^--command$/, /^-m$/, /^--module$/],
|
|
3255
|
+
python: [],
|
|
3142
3256
|
// git --exec=<cmd> runs arbitrary commands via upload-pack/receive-pack;
|
|
3143
3257
|
// -C <dir> changes working directory, bypassing cwd sandbox;
|
|
3144
3258
|
// -c/--config <k>=<v> injects config that runs commands
|
|
@@ -3154,15 +3268,10 @@ var BLOCKED_ARG_PATTERNS = {
|
|
|
3154
3268
|
/^--config=/,
|
|
3155
3269
|
/^--config-env=/
|
|
3156
3270
|
],
|
|
3157
|
-
|
|
3158
|
-
|
|
3159
|
-
|
|
3160
|
-
|
|
3161
|
-
// bun --preload is similar to node --require
|
|
3162
|
-
bun: [/^--preload$/, /^run$/, /^bunx$/, /^create$/, /^init$/],
|
|
3163
|
-
// docker build/run can create containers with host access;
|
|
3164
|
-
// only allow read-only commands (ps, images, version)
|
|
3165
|
-
docker: [/^build$/, /^run$/, /^exec$/, /^push$/, /^pull$/],
|
|
3271
|
+
node: [],
|
|
3272
|
+
go: [],
|
|
3273
|
+
bun: [],
|
|
3274
|
+
docker: [],
|
|
3166
3275
|
// find -exec/-ok/-execdir execute arbitrary commands
|
|
3167
3276
|
find: [/^-exec$/, /^-exec;$/, /^-ok$/, /^-ok;$/, /^-execdir$/, /^-execdir;$/, /^-exec=/, /^-ok=/, /^-execdir=/],
|
|
3168
3277
|
// rm -rf / is catastrophic — block absolute paths, home, dot-dirs,
|
|
@@ -3170,15 +3279,49 @@ var BLOCKED_ARG_PATTERNS = {
|
|
|
3170
3279
|
// `rm -rf ./src/*` expands to project files; `rm -rf ../../` escapes upward;
|
|
3171
3280
|
// `rm -rf /*` targets the filesystem root. All are blocked.
|
|
3172
3281
|
rm: [/^\//, /^~\//, /^~$/, /^\.$/, /^\.\.$/, /\*$/, /\/$/, /\/\*$/, /\.\//],
|
|
3173
|
-
// npm
|
|
3174
|
-
|
|
3175
|
-
|
|
3176
|
-
pnpm: [
|
|
3177
|
-
|
|
3178
|
-
|
|
3179
|
-
|
|
3282
|
+
// npm/pnpm subcommands are checked separately below. Matching every arg here
|
|
3283
|
+
// over-blocked normal dev flows such as `pnpm vitest run ...`.
|
|
3284
|
+
npm: [],
|
|
3285
|
+
pnpm: [],
|
|
3286
|
+
npx: []
|
|
3287
|
+
};
|
|
3288
|
+
var BLOCKED_SUBCOMMANDS = {
|
|
3289
|
+
docker: /* @__PURE__ */ new Set(["push"]),
|
|
3290
|
+
podman: /* @__PURE__ */ new Set(["push"]),
|
|
3291
|
+
npm: /* @__PURE__ */ new Set(["publish", "deploy"]),
|
|
3292
|
+
pnpm: /* @__PURE__ */ new Set(["publish", "deploy"]),
|
|
3293
|
+
yarn: /* @__PURE__ */ new Set(["publish"])
|
|
3294
|
+
};
|
|
3295
|
+
var BLOCKED_SUBCOMMAND_SEQUENCES = {
|
|
3296
|
+
yarn: [["npm", "publish"]]
|
|
3180
3297
|
};
|
|
3298
|
+
function firstSubcommand(args) {
|
|
3299
|
+
for (const arg of args) {
|
|
3300
|
+
if (arg === "--") return null;
|
|
3301
|
+
if (!arg.startsWith("-")) return arg;
|
|
3302
|
+
}
|
|
3303
|
+
return null;
|
|
3304
|
+
}
|
|
3305
|
+
function subcommandArgs(args) {
|
|
3306
|
+
const out = [];
|
|
3307
|
+
for (const arg of args) {
|
|
3308
|
+
if (arg === "--") break;
|
|
3309
|
+
if (!arg.startsWith("-")) out.push(arg);
|
|
3310
|
+
}
|
|
3311
|
+
return out;
|
|
3312
|
+
}
|
|
3181
3313
|
function validateArgs(cmd, args) {
|
|
3314
|
+
const blockedSubcommands = BLOCKED_SUBCOMMANDS[cmd];
|
|
3315
|
+
const subcommand = firstSubcommand(args);
|
|
3316
|
+
if (blockedSubcommands && subcommand && blockedSubcommands.has(subcommand)) {
|
|
3317
|
+
return `Blocked subcommand "${subcommand}" for command "${cmd}"`;
|
|
3318
|
+
}
|
|
3319
|
+
const blockedSequences = BLOCKED_SUBCOMMAND_SEQUENCES[cmd];
|
|
3320
|
+
if (blockedSequences) {
|
|
3321
|
+
const actual = subcommandArgs(args);
|
|
3322
|
+
const blocked2 = blockedSequences.find((seq) => seq.every((part, idx) => actual[idx] === part));
|
|
3323
|
+
if (blocked2) return `Blocked subcommand "${blocked2.join(" ")}" for command "${cmd}"`;
|
|
3324
|
+
}
|
|
3182
3325
|
const blocked = BLOCKED_ARG_PATTERNS[cmd];
|
|
3183
3326
|
if (!blocked) return null;
|
|
3184
3327
|
for (const arg of args) {
|
|
@@ -3305,7 +3448,7 @@ function runCommand(cmd, args, cwd, timeout, signal, sessionId) {
|
|
|
3305
3448
|
const startedAt = Date.now();
|
|
3306
3449
|
const spool = createOutputSpool({ tool: `exec-${cmd}`, thresholdBytes: MAX_OUTPUT2 });
|
|
3307
3450
|
const resolved = resolveWin32Command(cmd);
|
|
3308
|
-
const needsShell =
|
|
3451
|
+
const needsShell = isWin2 && (resolved.endsWith(".cmd") || resolved.endsWith(".bat"));
|
|
3309
3452
|
const spawnCmd = needsShell ? cmd : resolved;
|
|
3310
3453
|
if (needsShell) assertSafeWin32ShellArgs(args);
|
|
3311
3454
|
let child;
|
|
@@ -3315,7 +3458,7 @@ function runCommand(cmd, args, cwd, timeout, signal, sessionId) {
|
|
|
3315
3458
|
env: buildChildEnv(sessionId),
|
|
3316
3459
|
stdio: ["ignore", "pipe", "pipe"],
|
|
3317
3460
|
windowsHide: true,
|
|
3318
|
-
...
|
|
3461
|
+
...isWin2 ? {} : { signal },
|
|
3319
3462
|
...needsShell ? { shell: true, windowsVerbatimArguments: true } : {}
|
|
3320
3463
|
});
|
|
3321
3464
|
} catch (err) {
|
|
@@ -3335,7 +3478,7 @@ function runCommand(cmd, args, cwd, timeout, signal, sessionId) {
|
|
|
3335
3478
|
const isAbort = err && err.code === "ABORT_ERR";
|
|
3336
3479
|
const stderrText = isAbort ? `Aborted: ${err.message}` : err.message;
|
|
3337
3480
|
clearTimeout(timer);
|
|
3338
|
-
if (
|
|
3481
|
+
if (isWin2) signal.removeEventListener("abort", onAbort);
|
|
3339
3482
|
if (typeof pid === "number") registry.unregister(pid);
|
|
3340
3483
|
registry.afterCall(Date.now() - startedAt, true);
|
|
3341
3484
|
spool.finalize();
|
|
@@ -3365,7 +3508,7 @@ function runCommand(cmd, args, cwd, timeout, signal, sessionId) {
|
|
|
3365
3508
|
if (typeof pid === "number") registry.kill(pid, { force: true });
|
|
3366
3509
|
else child.kill("SIGTERM");
|
|
3367
3510
|
};
|
|
3368
|
-
if (
|
|
3511
|
+
if (isWin2) {
|
|
3369
3512
|
if (signal.aborted) onAbort();
|
|
3370
3513
|
else signal.addEventListener("abort", onAbort, { once: true });
|
|
3371
3514
|
}
|
|
@@ -3381,7 +3524,7 @@ function runCommand(cmd, args, cwd, timeout, signal, sessionId) {
|
|
|
3381
3524
|
});
|
|
3382
3525
|
child.on("close", (code) => {
|
|
3383
3526
|
clearTimeout(timer);
|
|
3384
|
-
if (
|
|
3527
|
+
if (isWin2) signal.removeEventListener("abort", onAbort);
|
|
3385
3528
|
if (typeof pid === "number") registry.unregister(pid);
|
|
3386
3529
|
const durationMs = Date.now() - startedAt;
|
|
3387
3530
|
const exitCode = killed ? 124 : code ?? 1;
|
|
@@ -3545,7 +3688,7 @@ var fetchTool = {
|
|
|
3545
3688
|
if (!final) throw new Error("fetch: stream ended without final event");
|
|
3546
3689
|
return final;
|
|
3547
3690
|
},
|
|
3548
|
-
async *executeStream(input,
|
|
3691
|
+
async *executeStream(input, ctx, opts) {
|
|
3549
3692
|
if (!input?.url) throw new Error("fetch: url is required");
|
|
3550
3693
|
const u = new URL(input.url);
|
|
3551
3694
|
if (u.protocol !== "https:" && u.protocol !== "http:") {
|
|
@@ -3617,6 +3760,14 @@ var fetchTool = {
|
|
|
3617
3760
|
url: res.url
|
|
3618
3761
|
}
|
|
3619
3762
|
};
|
|
3763
|
+
ctx.recordSideEffect?.({
|
|
3764
|
+
toolUseId: `fetch-${Date.now()}`,
|
|
3765
|
+
toolName: "fetch",
|
|
3766
|
+
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3767
|
+
input: { url: input.url, format: input.format },
|
|
3768
|
+
outcome: `HTTP ${res.status} (${ct})`,
|
|
3769
|
+
risk: "network"
|
|
3770
|
+
});
|
|
3620
3771
|
} finally {
|
|
3621
3772
|
clearTimeout(timer);
|
|
3622
3773
|
}
|
|
@@ -4724,8 +4875,8 @@ var jsonTool = {
|
|
|
4724
4875
|
};
|
|
4725
4876
|
}
|
|
4726
4877
|
};
|
|
4727
|
-
function query(data,
|
|
4728
|
-
const parts =
|
|
4878
|
+
function query(data, path22) {
|
|
4879
|
+
const parts = path22.replace(/\[(\d+)\]/g, ".$1").split(".").filter(Boolean);
|
|
4729
4880
|
let current = data;
|
|
4730
4881
|
for (const part of parts) {
|
|
4731
4882
|
if (current === null || current === void 0) return void 0;
|
|
@@ -5097,7 +5248,7 @@ async function walkDir(dir, depth, opts) {
|
|
|
5097
5248
|
}
|
|
5098
5249
|
}
|
|
5099
5250
|
}
|
|
5100
|
-
var
|
|
5251
|
+
var isWin3 = process.platform === "win32";
|
|
5101
5252
|
async function* spawnStream(opts) {
|
|
5102
5253
|
const max = opts.maxBytes ?? 2e5;
|
|
5103
5254
|
const flushAt = opts.flushBytes ?? 4 * 1024;
|
|
@@ -5108,7 +5259,7 @@ async function* spawnStream(opts) {
|
|
|
5108
5259
|
let error;
|
|
5109
5260
|
const spool = createOutputSpool({ tool: opts.cmd, thresholdBytes: max });
|
|
5110
5261
|
const resolved = resolveWin32Command(opts.cmd);
|
|
5111
|
-
const needsShell =
|
|
5262
|
+
const needsShell = isWin3 && (resolved.endsWith(".cmd") || resolved.endsWith(".bat"));
|
|
5112
5263
|
const cmd = needsShell ? opts.cmd : resolved;
|
|
5113
5264
|
if (needsShell) assertSafeWin32ShellArgs(opts.args);
|
|
5114
5265
|
const child = spawn(cmd, opts.args, {
|
|
@@ -5116,7 +5267,7 @@ async function* spawnStream(opts) {
|
|
|
5116
5267
|
env: buildChildEnv(),
|
|
5117
5268
|
stdio: ["ignore", "pipe", "pipe"],
|
|
5118
5269
|
windowsHide: true,
|
|
5119
|
-
...
|
|
5270
|
+
...isWin3 ? {} : { signal: opts.signal },
|
|
5120
5271
|
...needsShell ? { shell: true, windowsVerbatimArguments: true } : {}
|
|
5121
5272
|
});
|
|
5122
5273
|
const registry = getProcessRegistry();
|
|
@@ -5195,7 +5346,7 @@ async function* spawnStream(opts) {
|
|
|
5195
5346
|
queue.push({ kind: "close", data: "", code: 124 });
|
|
5196
5347
|
wake();
|
|
5197
5348
|
};
|
|
5198
|
-
if (
|
|
5349
|
+
if (isWin3) {
|
|
5199
5350
|
if (opts.signal.aborted) onAbort();
|
|
5200
5351
|
else opts.signal.addEventListener("abort", onAbort, { once: true });
|
|
5201
5352
|
}
|
|
@@ -5242,7 +5393,7 @@ async function* spawnStream(opts) {
|
|
|
5242
5393
|
};
|
|
5243
5394
|
} finally {
|
|
5244
5395
|
spool.finalize();
|
|
5245
|
-
if (
|
|
5396
|
+
if (isWin3) opts.signal.removeEventListener("abort", onAbort);
|
|
5246
5397
|
child.stdout?.off("data", onOut);
|
|
5247
5398
|
child.stderr?.off("data", onErr);
|
|
5248
5399
|
child.stdout?.destroy();
|
|
@@ -5828,6 +5979,14 @@ var installTool = {
|
|
|
5828
5979
|
}
|
|
5829
5980
|
}
|
|
5830
5981
|
}
|
|
5982
|
+
ctx.recordSideEffect?.({
|
|
5983
|
+
toolUseId: `install-${Date.now()}`,
|
|
5984
|
+
toolName: "install",
|
|
5985
|
+
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
5986
|
+
input: { packages: pkgList, cwd, dry_run: Boolean(input.dry_run) },
|
|
5987
|
+
outcome: output.dry_run ? "dry run" : result.exitCode === 0 ? `installed ${pkgList.length || "all"} packages` : `failed (exit ${result.exitCode})`,
|
|
5988
|
+
risk: "package"
|
|
5989
|
+
});
|
|
5831
5990
|
yield { type: "final", output };
|
|
5832
5991
|
}
|
|
5833
5992
|
};
|
|
@@ -6194,7 +6353,7 @@ async function dockerLogs(service, lines, filterRe, cwd, signal, since) {
|
|
|
6194
6353
|
}
|
|
6195
6354
|
var DOCKER_LOGS_TIMEOUT_MS = 3e3;
|
|
6196
6355
|
var MAX_TAIL_LINES = 1e5;
|
|
6197
|
-
async function fileLogs(
|
|
6356
|
+
async function fileLogs(path22, lines, filterRe, stream) {
|
|
6198
6357
|
const { createInterface } = await import('node:readline');
|
|
6199
6358
|
const { createReadStream } = await import('node:fs');
|
|
6200
6359
|
const entries = [];
|
|
@@ -6203,7 +6362,7 @@ async function fileLogs(path21, lines, filterRe, stream) {
|
|
|
6203
6362
|
let writeIdx = 0;
|
|
6204
6363
|
let totalLines = 0;
|
|
6205
6364
|
const rl = createInterface({
|
|
6206
|
-
input: createReadStream(
|
|
6365
|
+
input: createReadStream(path22),
|
|
6207
6366
|
crlfDelay: Number.POSITIVE_INFINITY
|
|
6208
6367
|
});
|
|
6209
6368
|
for await (const line of rl) {
|
|
@@ -6224,7 +6383,7 @@ async function fileLogs(path21, lines, filterRe, stream) {
|
|
|
6224
6383
|
if (parsed) entries.push(parsed);
|
|
6225
6384
|
}
|
|
6226
6385
|
return {
|
|
6227
|
-
source:
|
|
6386
|
+
source: path22,
|
|
6228
6387
|
entries,
|
|
6229
6388
|
total: entries.length,
|
|
6230
6389
|
truncated: totalLines > effLines,
|
|
@@ -6596,6 +6755,229 @@ function substituteVars(content, name, vars) {
|
|
|
6596
6755
|
}
|
|
6597
6756
|
return result;
|
|
6598
6757
|
}
|
|
6758
|
+
function normalizeOverrides(set) {
|
|
6759
|
+
const out = {};
|
|
6760
|
+
if (set && typeof set === "object") {
|
|
6761
|
+
for (const [k, v] of Object.entries(set)) {
|
|
6762
|
+
if (typeof v === "string") out[k] = v;
|
|
6763
|
+
}
|
|
6764
|
+
}
|
|
6765
|
+
return out;
|
|
6766
|
+
}
|
|
6767
|
+
var designTool = {
|
|
6768
|
+
name: "design",
|
|
6769
|
+
category: "Design",
|
|
6770
|
+
description: 'Browse, load, customize, and enforce curated frontend/mobile UI design kits. Use BEFORE writing UI code to commit to one coherent, modern, responsive, dark/light, accessible design. Actions: "list" (menu), "use" (load+pin a kit for a stack), "foundations" (baseline), "set" (override kit colors/tokens), "materialize" (write the tokens to a real theme file \u2014 CSS @theme/OKLCH or native), "verify" (scan UI files for off-palette colors).',
|
|
6771
|
+
usageHint: 'Flow: `design {action:"use", kit:"minimal-clarity", stack:"web"}` \u2192 optionally `design {action:"set", set:{primary:"oklch(62% 0.2 25)"}}` \u2192 `design {action:"materialize"}` to write tokens to disk \u2192 implement against them \u2192 `design {action:"verify"}`.',
|
|
6772
|
+
permission: "auto",
|
|
6773
|
+
mutating: false,
|
|
6774
|
+
capabilities: [],
|
|
6775
|
+
timeoutMs: 15e3,
|
|
6776
|
+
inputSchema: {
|
|
6777
|
+
type: "object",
|
|
6778
|
+
properties: {
|
|
6779
|
+
action: {
|
|
6780
|
+
type: "string",
|
|
6781
|
+
enum: ["list", "use", "foundations", "set", "materialize", "verify"],
|
|
6782
|
+
description: "list = menu; use = load+pin a kit; foundations = baseline; set = override colors/tokens; materialize = write tokens to a theme file; verify = scan UI for off-palette colors. Default: list."
|
|
6783
|
+
},
|
|
6784
|
+
kit: {
|
|
6785
|
+
type: "string",
|
|
6786
|
+
description: 'Kit id (required for "use"), e.g. "minimal-clarity", "neo-brutalist".'
|
|
6787
|
+
},
|
|
6788
|
+
stack: {
|
|
6789
|
+
type: "string",
|
|
6790
|
+
enum: ["web", "react-native", "flutter", "swiftui", "compose"],
|
|
6791
|
+
description: "Target stack \u2014 narrows guidance + materialize format. Default: web."
|
|
6792
|
+
},
|
|
6793
|
+
set: {
|
|
6794
|
+
type: "object",
|
|
6795
|
+
description: 'Token overrides for "set"/"use": { "primary": "oklch(\u2026)", "dark.bg": "#111" }. Bare key = both themes; "light."/"dark." prefix = that theme only. Empty value clears an override.',
|
|
6796
|
+
additionalProperties: { type: "string" }
|
|
6797
|
+
},
|
|
6798
|
+
out: {
|
|
6799
|
+
type: "string",
|
|
6800
|
+
description: "Materialize output path (project-relative). Defaults to a per-stack convention."
|
|
6801
|
+
},
|
|
6802
|
+
force: {
|
|
6803
|
+
type: "boolean",
|
|
6804
|
+
description: "Materialize: overwrite an existing file (default false \u2014 refuses to clobber)."
|
|
6805
|
+
},
|
|
6806
|
+
files: {
|
|
6807
|
+
type: "array",
|
|
6808
|
+
items: { type: "string" },
|
|
6809
|
+
description: "Verify: explicit project-relative files to scan. Default: a bounded UI-file walk."
|
|
6810
|
+
}
|
|
6811
|
+
},
|
|
6812
|
+
required: []
|
|
6813
|
+
},
|
|
6814
|
+
async execute(input, ctx) {
|
|
6815
|
+
const loader = getDesignKitLoader(ctx.projectRoot);
|
|
6816
|
+
const action = input.action ?? "list";
|
|
6817
|
+
const stack = input.stack && isDesignStack(input.stack) ? input.stack : void 0;
|
|
6818
|
+
if (action === "foundations") {
|
|
6819
|
+
const text = await loader.foundationsText(stack);
|
|
6820
|
+
return { action, stack, output: text || "No foundations document is installed." };
|
|
6821
|
+
}
|
|
6822
|
+
if (action === "use") {
|
|
6823
|
+
const kitId = input.kit?.trim();
|
|
6824
|
+
if (!kitId) {
|
|
6825
|
+
const menu2 = await loader.menuText();
|
|
6826
|
+
return { action, output: `No kit id provided.
|
|
6827
|
+
|
|
6828
|
+
${menu2}` };
|
|
6829
|
+
}
|
|
6830
|
+
const manifest = await loader.find(kitId);
|
|
6831
|
+
if (!manifest) {
|
|
6832
|
+
const menu2 = await loader.menuText();
|
|
6833
|
+
return { action, kit: kitId, output: `Kit "${kitId}" not found.
|
|
6834
|
+
|
|
6835
|
+
${menu2}` };
|
|
6836
|
+
}
|
|
6837
|
+
const resolvedStack = stack ?? manifest.stacks[0] ?? "web";
|
|
6838
|
+
const body = await loader.readBody(manifest.id, resolvedStack);
|
|
6839
|
+
const rawTokens = await loader.readTokens(manifest.id);
|
|
6840
|
+
const persisted = await loadActiveKit(ctx.projectRoot);
|
|
6841
|
+
const keepOverrides = persisted?.kit === manifest.id ? persisted.overrides ?? {} : {};
|
|
6842
|
+
const overrides = { ...keepOverrides, ...normalizeOverrides(input.set) };
|
|
6843
|
+
const tokens = rawTokens ? applyTokenOverrides(rawTokens, overrides) : rawTokens;
|
|
6844
|
+
setActiveKit(ctx, manifest.id, resolvedStack, overrides);
|
|
6845
|
+
await recordKitChoice(
|
|
6846
|
+
ctx.projectRoot,
|
|
6847
|
+
manifest.id,
|
|
6848
|
+
resolvedStack,
|
|
6849
|
+
"design-tool",
|
|
6850
|
+
(/* @__PURE__ */ new Date()).toISOString(),
|
|
6851
|
+
Object.keys(overrides).length ? overrides : void 0
|
|
6852
|
+
);
|
|
6853
|
+
const ovLine = Object.keys(overrides).length ? `
|
|
6854
|
+
Active color overrides: ${Object.entries(overrides).map(([k, v]) => `${k}=${v}`).join(", ")}
|
|
6855
|
+
` : "";
|
|
6856
|
+
const header = `# Active design kit: ${manifest.name} (${manifest.id}) \u2014 stack: ${resolvedStack}
|
|
6857
|
+
${manifest.aesthetic}
|
|
6858
|
+
${ovLine}
|
|
6859
|
+
Implement the UI faithfully to this spec. Keep light/dark, responsive, and WCAG AA.
|
|
6860
|
+
`;
|
|
6861
|
+
const tokenBlock = tokens ? `
|
|
6862
|
+
## Token snapshot (overrides applied)
|
|
6863
|
+
\`\`\`json
|
|
6864
|
+
${JSON.stringify(tokens, null, 2)}
|
|
6865
|
+
\`\`\`
|
|
6866
|
+
Tip: run \`design {action:"materialize"}\` to write these tokens to a real theme file.
|
|
6867
|
+
` : "";
|
|
6868
|
+
return {
|
|
6869
|
+
action,
|
|
6870
|
+
kit: manifest.id,
|
|
6871
|
+
stack: resolvedStack,
|
|
6872
|
+
output: `${header}${tokenBlock}
|
|
6873
|
+
${body}`
|
|
6874
|
+
};
|
|
6875
|
+
}
|
|
6876
|
+
if (action === "set") {
|
|
6877
|
+
const patch = normalizeOverrides(input.set);
|
|
6878
|
+
if (Object.keys(patch).length === 0) {
|
|
6879
|
+
return { action, output: 'No overrides given. Pass set:{ "primary": "oklch(\u2026)" }.' };
|
|
6880
|
+
}
|
|
6881
|
+
const merged = await recordOverrides(ctx.projectRoot, patch, (/* @__PURE__ */ new Date()).toISOString());
|
|
6882
|
+
if (!merged) {
|
|
6883
|
+
return {
|
|
6884
|
+
action,
|
|
6885
|
+
output: 'No active kit. Pick one first: `design {action:"use", kit:"<id>"}`.'
|
|
6886
|
+
};
|
|
6887
|
+
}
|
|
6888
|
+
setDesignOverrides(ctx, merged);
|
|
6889
|
+
return {
|
|
6890
|
+
action,
|
|
6891
|
+
output: `Overrides updated. Active overrides: ${Object.entries(merged).map(([k, v]) => `${k}=${v}`).join(", ")}
|
|
6892
|
+
These win over kit tokens. Run \`design {action:"materialize"}\` to write them to a theme file.`
|
|
6893
|
+
};
|
|
6894
|
+
}
|
|
6895
|
+
if (action === "materialize") {
|
|
6896
|
+
const active = await loadActiveKit(ctx.projectRoot);
|
|
6897
|
+
if (!active) {
|
|
6898
|
+
return {
|
|
6899
|
+
action,
|
|
6900
|
+
output: 'No active kit. Pick one first: `design {action:"use", kit:"<id>"}`.'
|
|
6901
|
+
};
|
|
6902
|
+
}
|
|
6903
|
+
const resolvedStack = stack ?? (active.stack && isDesignStack(active.stack) ? active.stack : "web");
|
|
6904
|
+
const rawTokens = await loader.readTokens(active.kit);
|
|
6905
|
+
if (!rawTokens) {
|
|
6906
|
+
return { action, kit: active.kit, output: `Kit "${active.kit}" has no tokens.json.` };
|
|
6907
|
+
}
|
|
6908
|
+
const tokens = applyTokenOverrides(rawTokens, active.overrides);
|
|
6909
|
+
const result = materializeTokens({
|
|
6910
|
+
tokens,
|
|
6911
|
+
stack: resolvedStack,
|
|
6912
|
+
kitId: active.kit,
|
|
6913
|
+
outPath: input.out
|
|
6914
|
+
});
|
|
6915
|
+
const abs = path.join(ctx.projectRoot, result.path);
|
|
6916
|
+
let exists = false;
|
|
6917
|
+
try {
|
|
6918
|
+
await fs7.access(abs);
|
|
6919
|
+
exists = true;
|
|
6920
|
+
} catch {
|
|
6921
|
+
}
|
|
6922
|
+
if (exists && !input.force) {
|
|
6923
|
+
return {
|
|
6924
|
+
action,
|
|
6925
|
+
kit: active.kit,
|
|
6926
|
+
stack: resolvedStack,
|
|
6927
|
+
path: result.path,
|
|
6928
|
+
output: `${result.path} already exists. Re-run with force:true to overwrite, or write this ${result.format} yourself:
|
|
6929
|
+
|
|
6930
|
+
\`\`\`
|
|
6931
|
+
${result.content}
|
|
6932
|
+
\`\`\``
|
|
6933
|
+
};
|
|
6934
|
+
}
|
|
6935
|
+
await fs7.mkdir(path.dirname(abs), { recursive: true });
|
|
6936
|
+
await fs7.writeFile(abs, result.content);
|
|
6937
|
+
return {
|
|
6938
|
+
action,
|
|
6939
|
+
kit: active.kit,
|
|
6940
|
+
stack: resolvedStack,
|
|
6941
|
+
path: result.path,
|
|
6942
|
+
output: `Wrote ${result.format} to ${result.path}. Import these tokens in your UI so the kit palette is the source of truth. ${exists ? "(overwrote existing file)" : ""}`
|
|
6943
|
+
};
|
|
6944
|
+
}
|
|
6945
|
+
if (action === "verify") {
|
|
6946
|
+
const active = await loadActiveKit(ctx.projectRoot);
|
|
6947
|
+
if (!active) {
|
|
6948
|
+
return {
|
|
6949
|
+
action,
|
|
6950
|
+
output: 'No active kit to verify against. Pick one: `design {action:"use", kit:"<id>"}`.'
|
|
6951
|
+
};
|
|
6952
|
+
}
|
|
6953
|
+
const rawTokens = await loader.readTokens(active.kit);
|
|
6954
|
+
if (!rawTokens) {
|
|
6955
|
+
return { action, kit: active.kit, output: `Kit "${active.kit}" has no tokens.json.` };
|
|
6956
|
+
}
|
|
6957
|
+
const tokens = applyTokenOverrides(rawTokens, active.overrides);
|
|
6958
|
+
const report = await runDesignVerify(ctx.projectRoot, tokens, input.files);
|
|
6959
|
+
const pct = Math.round(report.score * 100);
|
|
6960
|
+
const top = report.violations.slice(0, 25).map((v) => ` ${v.file}:${v.line} \u2014 ${v.reason}: ${v.snippet}`).join("\n");
|
|
6961
|
+
const summary = `Adherence: ${pct}% on-palette across ${report.filesScanned} file(s). ${report.violations.length} violation(s).` + (report.violations.length ? `
|
|
6962
|
+
${top}${report.violations.length > 25 ? `
|
|
6963
|
+
\u2026and ${report.violations.length - 25} more` : ""}
|
|
6964
|
+
|
|
6965
|
+
Replace off-palette colors with kit tokens (or the materialized CSS vars / token utilities).` : "\nNo off-palette colors found \u2014 UI adheres to the kit palette.");
|
|
6966
|
+
return {
|
|
6967
|
+
action,
|
|
6968
|
+
kit: active.kit,
|
|
6969
|
+
output: summary,
|
|
6970
|
+
score: report.score,
|
|
6971
|
+
violations: report.violations.length
|
|
6972
|
+
};
|
|
6973
|
+
}
|
|
6974
|
+
const menu = await loader.menuText();
|
|
6975
|
+
return {
|
|
6976
|
+
action: "list",
|
|
6977
|
+
output: (menu || "No design kits are installed.") + '\n\nLoad one with `design {action:"use", kit:"<id>", stack:"<stack>"}`.'
|
|
6978
|
+
};
|
|
6979
|
+
}
|
|
6980
|
+
};
|
|
6599
6981
|
|
|
6600
6982
|
// src/tool-search.ts
|
|
6601
6983
|
var toolSearchTool = {
|
|
@@ -11127,7 +11509,8 @@ var TIER2_TOOLS = [
|
|
|
11127
11509
|
planTool,
|
|
11128
11510
|
taskTool,
|
|
11129
11511
|
installTool,
|
|
11130
|
-
auditTool
|
|
11512
|
+
auditTool,
|
|
11513
|
+
designTool
|
|
11131
11514
|
];
|
|
11132
11515
|
var TIER3_TOOLS = [
|
|
11133
11516
|
outdatedTool,
|
|
@@ -11172,6 +11555,7 @@ var builtinTools = [
|
|
|
11172
11555
|
logsTool,
|
|
11173
11556
|
documentTool,
|
|
11174
11557
|
scaffoldTool,
|
|
11558
|
+
designTool,
|
|
11175
11559
|
toolSearchTool,
|
|
11176
11560
|
toolUseTool,
|
|
11177
11561
|
batchToolUseTool,
|
|
@@ -11345,6 +11729,6 @@ var TOOL_ICON_CONFIG = {
|
|
|
11345
11729
|
};
|
|
11346
11730
|
var FALLBACK_ICON = "fallback";
|
|
11347
11731
|
|
|
11348
|
-
export { CircuitBreaker, CircuitOpenError, FALLBACK_ICON, IndexCircuitBreaker, IndexTimeoutError, OPTIONAL_TOOLS, TIER1_TOOLS, TIER2_TOOLS, TIER3_TOOLS, TOOL_ICON_CONFIG, TOOL_ICON_MAP, _resetProcessRegistry, auditTool, bashTool, batchToolUseTool, builtinTools, builtinToolsPack, cancelPendingReindexes, codebaseIndexStats, codebaseIndexTool, codebaseSearchTool, codebaseStatsTool, configureExecPolicy, createGlobalPsSlashCommand, createModeTool, diffTool, documentTool, editTool, enqueueReindex, ensureSessionShell, execTool, fetchTool, forgetTool, formatGlobalStatus, formatInstanceList, formatInstanceSummary, formatTool, getExecAllowlist, getIndexState, getInstanceCount, getPersistentProcessRegistry, getProcessGuardian, getProcessRegistry, getToolIcon, gitTool, globTool, grepTool, indexCircuitBreaker, installTool, isExecCommandAllowed, isIndexReady, isIndexableFile, isIndexing, jsonTool, lintTool, listInstances, logsTool, normalizeShell, onIndexStateChange, outdatedTool, patchTool, planTool, readTool, relatedMemoryTool, rememberTool, replaceTool, resetExecPolicy, resetIndexCircuitBreaker, resetPersistentProcessRegistry, resolveSessionShell, runStartupIndex, scaffoldTool, searchCodebaseIndex, searchMemoryTool, searchTool, shutdownCodebaseIndexHost, startProcessGuardian, stopProcessGuardian, testTool, todoTool, toolHelpTool, toolSearchTool, toolUseTool, treeTool, typecheckTool, writeTool };
|
|
11732
|
+
export { CircuitBreaker, CircuitOpenError, FALLBACK_ICON, IndexCircuitBreaker, IndexTimeoutError, OPTIONAL_TOOLS, TIER1_TOOLS, TIER2_TOOLS, TIER3_TOOLS, TOOL_ICON_CONFIG, TOOL_ICON_MAP, _resetProcessRegistry, auditTool, bashTool, batchToolUseTool, builtinTools, builtinToolsPack, cancelPendingReindexes, codebaseIndexStats, codebaseIndexTool, codebaseSearchTool, codebaseStatsTool, configureExecPolicy, createGlobalPsSlashCommand, createModeTool, designTool, diffTool, documentTool, editTool, enqueueReindex, ensureSessionShell, execTool, fetchTool, forgetTool, formatGlobalStatus, formatInstanceList, formatInstanceSummary, formatTool, getExecAllowlist, getIndexState, getInstanceCount, getPersistentProcessRegistry, getProcessGuardian, getProcessRegistry, getToolIcon, gitTool, globTool, grepTool, indexCircuitBreaker, installTool, isExecCommandAllowed, isIndexReady, isIndexableFile, isIndexing, jsonTool, lintTool, listInstances, logsTool, normalizeShell, onIndexStateChange, outdatedTool, patchTool, planTool, readTool, relatedMemoryTool, rememberTool, replaceTool, resetExecPolicy, resetIndexCircuitBreaker, resetPersistentProcessRegistry, resolveSessionShell, runStartupIndex, scaffoldTool, searchCodebaseIndex, searchMemoryTool, searchTool, shutdownCodebaseIndexHost, startProcessGuardian, stopProcessGuardian, testTool, todoTool, toolHelpTool, toolSearchTool, toolUseTool, treeTool, typecheckTool, writeTool };
|
|
11349
11733
|
//# sourceMappingURL=index.js.map
|
|
11350
11734
|
//# sourceMappingURL=index.js.map
|