@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/install.js
CHANGED
|
@@ -269,6 +269,7 @@ var CircuitBreaker = class {
|
|
|
269
269
|
if (this.state === "open") return;
|
|
270
270
|
this.state = "open";
|
|
271
271
|
this.openedAt = Date.now();
|
|
272
|
+
this.window = [];
|
|
272
273
|
try {
|
|
273
274
|
this.onTrip?.();
|
|
274
275
|
} catch {
|
|
@@ -308,7 +309,7 @@ var SENSITIVE_FLAG_PATTERNS = [
|
|
|
308
309
|
/--(?: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,
|
|
309
310
|
// -f "value" style short flags
|
|
310
311
|
/(?<!\w)-t(?:\s+|\s*=\s*)[^\s,]+/,
|
|
311
|
-
/(?<!\w)-
|
|
312
|
+
/(?<!\w)-(?:p|password)(?:\s+|\s*=\s*)[^\s,]+/gi,
|
|
312
313
|
// env var–style secrets: TOKEN=x, API_KEY=y, etc.
|
|
313
314
|
/(?:TOKEN|API_KEY|API_SECRET|AUTH_TOKEN|GITHUB_TOKEN|GH_TOKEN|BEARER|JWT|OAUTH|CREDENTIAL|SECRET|PRIVATE_KEY|PASSWORD|PASSWD)\s*[=:]\s*[^\s,]+/gi,
|
|
314
315
|
// Generic high-entropy look: base64 strings >32 chars or hex strings >32 digits — but only
|
|
@@ -369,12 +370,35 @@ var ProcessRegistryImpl = class {
|
|
|
369
370
|
register(info) {
|
|
370
371
|
this.processes.set(info.pid, { ...info, killed: false, protected: info.protected ?? false });
|
|
371
372
|
}
|
|
373
|
+
_isSafeSignalPid(pid) {
|
|
374
|
+
return Number.isInteger(pid) && pid > 1 && pid !== process.pid && pid !== process.ppid;
|
|
375
|
+
}
|
|
376
|
+
_canSignalProcessGroup(p) {
|
|
377
|
+
return os.platform() !== "win32" && p.processGroupLeader === true && this._isSafeSignalPid(p.pid) && typeof p.child.pid === "number" && p.child.pid === p.pid;
|
|
378
|
+
}
|
|
379
|
+
_killChildDirect(p, signal) {
|
|
380
|
+
try {
|
|
381
|
+
p.child.kill(signal);
|
|
382
|
+
} catch {
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
_killPosix(p, signal) {
|
|
386
|
+
if (this._canSignalProcessGroup(p)) {
|
|
387
|
+
try {
|
|
388
|
+
process.kill(-p.pid, signal);
|
|
389
|
+
return;
|
|
390
|
+
} catch {
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
this._killChildDirect(p, signal);
|
|
394
|
+
}
|
|
372
395
|
/** Unregister a process by PID. Called on 'close' / 'exit' events. */
|
|
373
396
|
unregister(pid) {
|
|
374
397
|
this.processes.delete(pid);
|
|
375
398
|
}
|
|
376
399
|
/** Get a single process by PID. */
|
|
377
400
|
get(pid) {
|
|
401
|
+
this._pruneStale(pid);
|
|
378
402
|
return this.processes.get(pid);
|
|
379
403
|
}
|
|
380
404
|
/** Get all tracked processes. */
|
|
@@ -538,6 +562,7 @@ var ProcessRegistryImpl = class {
|
|
|
538
562
|
* Returns true if the process was found and kill was attempted.
|
|
539
563
|
*/
|
|
540
564
|
kill(pid, opts = {}) {
|
|
565
|
+
this._pruneStale(pid);
|
|
541
566
|
const p = this.processes.get(pid);
|
|
542
567
|
if (!p) return false;
|
|
543
568
|
if (p.killed) return true;
|
|
@@ -567,27 +592,12 @@ var ProcessRegistryImpl = class {
|
|
|
567
592
|
}
|
|
568
593
|
try {
|
|
569
594
|
if (force) {
|
|
570
|
-
|
|
571
|
-
process.kill(-pid, "SIGKILL");
|
|
572
|
-
} catch {
|
|
573
|
-
p.child.kill("SIGKILL");
|
|
574
|
-
}
|
|
595
|
+
this._killPosix(p, "SIGKILL");
|
|
575
596
|
} else {
|
|
576
|
-
|
|
577
|
-
process.kill(-pid, "SIGTERM");
|
|
578
|
-
} catch {
|
|
579
|
-
p.child.kill("SIGTERM");
|
|
580
|
-
}
|
|
597
|
+
this._killPosix(p, "SIGTERM");
|
|
581
598
|
const timer = setTimeout(() => {
|
|
582
599
|
if (this.processes.has(pid) && !p.child.killed) {
|
|
583
|
-
|
|
584
|
-
process.kill(-pid, "SIGKILL");
|
|
585
|
-
} catch {
|
|
586
|
-
try {
|
|
587
|
-
p.child.kill("SIGKILL");
|
|
588
|
-
} catch {
|
|
589
|
-
}
|
|
590
|
-
}
|
|
600
|
+
this._killPosix(p, "SIGKILL");
|
|
591
601
|
}
|
|
592
602
|
}, graceMs);
|
|
593
603
|
timer.unref?.();
|
|
@@ -622,6 +632,34 @@ var ProcessRegistryImpl = class {
|
|
|
622
632
|
}
|
|
623
633
|
return killed;
|
|
624
634
|
}
|
|
635
|
+
/**
|
|
636
|
+
* Check whether a tracked process entry is stale — the child has exited
|
|
637
|
+
* (exitCode !== null) AND it's been in the registry long enough that the
|
|
638
|
+
* OS may have reused the PID for a new, unrelated process.
|
|
639
|
+
*
|
|
640
|
+
* P3 #24 (before-release.md): on POSIX, PIDs are reused after process
|
|
641
|
+
* exit. If a tracked process exits but its 'close' event hasn't fired yet
|
|
642
|
+
* (or was missed), the registry still holds the entry. A new process
|
|
643
|
+
* gets the same PID, and PID-based lookups (get, kill, shouldBlockKill)
|
|
644
|
+
* may incorrectly protect or target the wrong process.
|
|
645
|
+
*
|
|
646
|
+
* The 60s threshold is conservative — the OS typically waits much longer
|
|
647
|
+
* before reusing a PID, but we want to clean up before that becomes a risk.
|
|
648
|
+
*/
|
|
649
|
+
_isStaleEntry(entry) {
|
|
650
|
+
return entry.child.exitCode !== null && Date.now() - entry.startedAt > 6e4;
|
|
651
|
+
}
|
|
652
|
+
/**
|
|
653
|
+
* Remove a stale entry for a specific PID before any PID-based lookup.
|
|
654
|
+
* This prevents PID reuse from causing the registry to act on a dead
|
|
655
|
+
* process that has been replaced by a new one with the same PID.
|
|
656
|
+
*/
|
|
657
|
+
_pruneStale(pid) {
|
|
658
|
+
const entry = this.processes.get(pid);
|
|
659
|
+
if (entry && this._isStaleEntry(entry)) {
|
|
660
|
+
this.processes.delete(pid);
|
|
661
|
+
}
|
|
662
|
+
}
|
|
625
663
|
};
|
|
626
664
|
var _registry;
|
|
627
665
|
function getProcessRegistry() {
|
|
@@ -1055,6 +1093,14 @@ var installTool = {
|
|
|
1055
1093
|
}
|
|
1056
1094
|
}
|
|
1057
1095
|
}
|
|
1096
|
+
ctx.recordSideEffect?.({
|
|
1097
|
+
toolUseId: `install-${Date.now()}`,
|
|
1098
|
+
toolName: "install",
|
|
1099
|
+
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1100
|
+
input: { packages: pkgList, cwd, dry_run: Boolean(input.dry_run) },
|
|
1101
|
+
outcome: output.dry_run ? "dry run" : result.exitCode === 0 ? `installed ${pkgList.length || "all"} packages` : `failed (exit ${result.exitCode})`,
|
|
1102
|
+
risk: "package"
|
|
1103
|
+
});
|
|
1058
1104
|
yield { type: "final", output };
|
|
1059
1105
|
}
|
|
1060
1106
|
};
|