@wrongstack/tools 0.305.1 → 0.306.2
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/_shell-pick.d.ts +4 -5
- package/dist/_util.d.ts +22 -5
- package/dist/audit.d.ts +0 -1
- package/dist/audit.js +135 -46
- package/dist/bash.js +61 -37
- package/dist/browser/index.js +29 -9
- package/dist/browser/types.d.ts +7 -1
- package/dist/builtin.js +1294 -726
- package/dist/codebase-index/codebase-search-tool.d.ts +5 -0
- package/dist/codebase-index/index.js +223 -152
- package/dist/codebase-index/project-server.js +10 -11
- package/dist/diff.d.ts +5 -0
- package/dist/diff.js +78 -12
- package/dist/document.js +18 -6
- package/dist/edit.js +69 -16
- package/dist/exec.js +44 -22
- package/dist/fetch.js +13 -1
- package/dist/format.d.ts +4 -2
- package/dist/format.js +81 -31
- package/dist/glob.js +12 -4
- package/dist/grep.d.ts +2 -0
- package/dist/grep.js +15 -4
- package/dist/index.js +1359 -762
- package/dist/install.js +96 -37
- package/dist/kanban-tool-types.d.ts +6 -1
- package/dist/kanban.js +60 -0
- package/dist/languages/index.js +28 -13
- package/dist/lint.js +28 -13
- package/dist/logs.d.ts +0 -1
- package/dist/logs.js +44 -13
- package/dist/memory.d.ts +8 -0
- package/dist/memory.js +23 -3
- package/dist/mode.d.ts +1 -1
- package/dist/mode.js +3 -0
- package/dist/next-steps.d.ts +2 -3
- package/dist/next-steps.js +3 -3
- package/dist/outdated.d.ts +0 -3
- package/dist/outdated.js +89 -48
- package/dist/pack.js +1294 -726
- package/dist/plan.js +91 -3
- package/dist/process-registry.d.ts +8 -2
- package/dist/process-registry.js +28 -13
- package/dist/ps-slash.js +22 -12
- package/dist/read.js +10 -3
- package/dist/replace.d.ts +4 -0
- package/dist/replace.js +104 -7
- package/dist/search.d.ts +6 -0
- package/dist/search.js +47 -26
- package/dist/session-kanban.js +3 -1
- package/dist/skill.d.ts +6 -0
- package/dist/skill.js +9 -10
- package/dist/task.js +81 -2
- package/dist/test.js +28 -13
- package/dist/todo.js +79 -2
- package/dist/tool-icons.js +4 -2
- package/dist/tool-summary.d.ts +1 -1
- package/dist/tool-summary.js +76 -1
- package/dist/tool-tier.js +1294 -726
- package/dist/tree.js +9 -10
- package/dist/typecheck.d.ts +0 -2
- package/dist/typecheck.js +98 -31
- package/dist/write.js +58 -10
- package/package.json +4 -4
package/dist/memory.d.ts
CHANGED
|
@@ -16,10 +16,18 @@ interface RememberOutput {
|
|
|
16
16
|
interface ForgetInput {
|
|
17
17
|
query: string;
|
|
18
18
|
scope?: MemoryScope | undefined;
|
|
19
|
+
/** Preview: list what WOULD be deleted without deleting anything. */
|
|
20
|
+
dry_run?: boolean | undefined;
|
|
19
21
|
}
|
|
20
22
|
interface ForgetOutput {
|
|
21
23
|
removed: number;
|
|
22
24
|
scope: MemoryScope;
|
|
25
|
+
/** True when this was a preview run — nothing was deleted. */
|
|
26
|
+
dryRun?: boolean | undefined;
|
|
27
|
+
/** dry_run only: texts of the entries the query matches (capped at 20). */
|
|
28
|
+
matches?: string[] | undefined;
|
|
29
|
+
/** dry_run only: total number of matching entries (may exceed matches.length). */
|
|
30
|
+
matched?: number | undefined;
|
|
23
31
|
}
|
|
24
32
|
export declare function rememberTool(memory: MemoryStore): Tool<RememberInput, RememberOutput>;
|
|
25
33
|
export declare function forgetTool(memory: MemoryStore): Tool<ForgetInput, ForgetOutput>;
|
package/dist/memory.js
CHANGED
|
@@ -62,17 +62,25 @@ function forgetTool(memory) {
|
|
|
62
62
|
return {
|
|
63
63
|
name: "forget",
|
|
64
64
|
category: "Session",
|
|
65
|
-
description: "Remove memory entries that contain the given substring (case-insensitive). Use with caution.",
|
|
66
|
-
usageHint: "This permanently deletes matching memories in the chosen scope.\n- Provide a reasonably specific `query` to avoid deleting unrelated memories.\n- Always double-check before calling with broad queries.\n- Use `remember` + `forget` together to maintain clean long-term memory.",
|
|
65
|
+
description: "Remove memory entries that contain the given substring (case-insensitive). Use with caution. Pass `dry_run: true` to preview the matching entries (capped at 20) without deleting anything.",
|
|
66
|
+
usageHint: "This permanently deletes matching memories in the chosen scope.\n- Provide a reasonably specific `query` to avoid deleting unrelated memories.\n- Always double-check before calling with broad queries \u2014 `dry_run: true` previews the matches without deleting.\n- Use `remember` + `forget` together to maintain clean long-term memory.",
|
|
67
67
|
permission: "confirm",
|
|
68
|
+
// WS-046: gives permission decisions something to key on — the substring
|
|
69
|
+
// being forgotten.
|
|
70
|
+
subjectKey: "query",
|
|
68
71
|
mutating: true,
|
|
69
72
|
timeoutMs: 2e3,
|
|
70
73
|
capabilities: ["memory.delete"],
|
|
74
|
+
icon: "settings",
|
|
71
75
|
inputSchema: {
|
|
72
76
|
type: "object",
|
|
73
77
|
properties: {
|
|
74
78
|
query: { type: "string" },
|
|
75
|
-
scope: { type: "string", enum: ["project-agents", "project-memory", "user-memory"] }
|
|
79
|
+
scope: { type: "string", enum: ["project-agents", "project-memory", "user-memory"] },
|
|
80
|
+
dry_run: {
|
|
81
|
+
type: "boolean",
|
|
82
|
+
description: "When true, return the matched entries (capped at 20) WITHOUT deleting them. Default false."
|
|
83
|
+
}
|
|
76
84
|
},
|
|
77
85
|
required: ["query"]
|
|
78
86
|
},
|
|
@@ -84,6 +92,18 @@ function forgetTool(memory) {
|
|
|
84
92
|
});
|
|
85
93
|
}
|
|
86
94
|
const scope = input.scope ?? "project-memory";
|
|
95
|
+
if (input.dry_run) {
|
|
96
|
+
const entries = await memory.list(scope);
|
|
97
|
+
const needle = input.query.toLowerCase();
|
|
98
|
+
const matching = entries.filter((entry) => entry.text.toLowerCase().includes(needle));
|
|
99
|
+
return {
|
|
100
|
+
removed: 0,
|
|
101
|
+
scope,
|
|
102
|
+
dryRun: true,
|
|
103
|
+
matched: matching.length,
|
|
104
|
+
matches: matching.slice(0, 20).map((entry) => entry.text)
|
|
105
|
+
};
|
|
106
|
+
}
|
|
87
107
|
const removed = await memory.forget(input.query, scope);
|
|
88
108
|
return { removed, scope };
|
|
89
109
|
}
|
package/dist/mode.d.ts
CHANGED
package/dist/mode.js
CHANGED
|
@@ -12,6 +12,9 @@ function createModeTool(modeStore) {
|
|
|
12
12
|
description: "Manage agent operating modes. Modes change the agent's behavior, personality, and system prompt for different workflows (e.g. coding, security review, planning).",
|
|
13
13
|
usageHint: "POWERFUL BEHAVIOR CONTROL TOOL:\n\n- Use `list` to see available modes.\n- Use `set <modeId>` to switch the agent into a specific role/mode.\n- Use `get` to check current mode.\n- Use `clear` to return to default behavior.\nSwitching modes is very effective for specialized tasks. The mode change affects how the agent reasons and which guidelines it follows.",
|
|
14
14
|
permission: "confirm",
|
|
15
|
+
// WS-046: gives permission decisions something to key on — the mode being
|
|
16
|
+
// activated. Permission semantics are unchanged.
|
|
17
|
+
subjectKey: "mode",
|
|
15
18
|
mutating: true,
|
|
16
19
|
timeoutMs: 5e3,
|
|
17
20
|
capabilities: ["session.mode"],
|
package/dist/next-steps.d.ts
CHANGED
|
@@ -73,12 +73,11 @@ export declare function isFinalTurnStopReason(stopReason: string | undefined): b
|
|
|
73
73
|
* Parse canonical "<nextsteps>" blocks from assistant output (or raw numbered lines).
|
|
74
74
|
*
|
|
75
75
|
* @param content — raw assistant message text or subagent output
|
|
76
|
-
* @param
|
|
77
|
-
* @param requireHeading — when true, a canonical XML tag must precede the item list.
|
|
76
|
+
* @param requireHeading — when true (default), a canonical XML tag must precede the item list.
|
|
78
77
|
* when false, numbered/bullet items are parsed from anywhere in text
|
|
79
78
|
* (used by /suggest subagent output which has no heading).
|
|
80
79
|
*/
|
|
81
|
-
export declare function parseNextSteps(content: string,
|
|
80
|
+
export declare function parseNextSteps(content: string, requireHeading?: boolean): ParseNextStepsResult;
|
|
82
81
|
/**
|
|
83
82
|
* Strip <nextsteps>...</nextsteps> blocks from subagent output text.
|
|
84
83
|
* Subagent results should not contain suggestion blocks — those belong to
|
package/dist/next-steps.js
CHANGED
|
@@ -5,9 +5,9 @@ function isFinalTurnStopReason(stopReason) {
|
|
|
5
5
|
var NEXT_STEPS_TAG_RE = /<nextsteps\b[^>]*>\s*\n+/i;
|
|
6
6
|
var ITEM_RE = /^(?:(\d+)[.)]\s*|[-*•]\s*)(.+?)(\s+auto="true")?$/;
|
|
7
7
|
var MAX_STEPS = 6;
|
|
8
|
-
function parseNextSteps(content,
|
|
8
|
+
function parseNextSteps(content, requireHeading = true) {
|
|
9
9
|
if (requireHeading) {
|
|
10
|
-
return parseWithHeading(content
|
|
10
|
+
return parseWithHeading(content);
|
|
11
11
|
}
|
|
12
12
|
return parseRawNumbered(content);
|
|
13
13
|
}
|
|
@@ -44,7 +44,7 @@ function parseRawNumbered(content) {
|
|
|
44
44
|
autoTexts: steps.filter((s) => s.auto).map((s) => s.text)
|
|
45
45
|
};
|
|
46
46
|
}
|
|
47
|
-
function parseWithHeading(content
|
|
47
|
+
function parseWithHeading(content) {
|
|
48
48
|
const headingMatch = NEXT_STEPS_TAG_RE.exec(content);
|
|
49
49
|
if (!headingMatch) {
|
|
50
50
|
return { steps: [], texts: [], stripped: content, autoTexts: [] };
|
package/dist/outdated.d.ts
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
import type { Tool } from '@wrongstack/core/types';
|
|
2
2
|
interface OutdatedInput {
|
|
3
3
|
cwd?: string | undefined;
|
|
4
|
-
format?: 'list' | 'table' | undefined;
|
|
5
|
-
include_deprecated?: boolean | undefined;
|
|
6
|
-
check?: string | string[] | undefined;
|
|
7
4
|
}
|
|
8
5
|
interface OutdatedPackage {
|
|
9
6
|
name: string;
|
package/dist/outdated.js
CHANGED
|
@@ -17,19 +17,48 @@ var __export = (target, all) => {
|
|
|
17
17
|
import * as fsp from "node:fs/promises";
|
|
18
18
|
import * as path from "node:path";
|
|
19
19
|
import * as Core from "@wrongstack/core/utils";
|
|
20
|
-
async function detectPackageManager(cwd) {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
20
|
+
async function detectPackageManager(cwd, stopAt) {
|
|
21
|
+
let dir = path.resolve(cwd);
|
|
22
|
+
const stop = stopAt ? path.resolve(stopAt) : dir;
|
|
23
|
+
for (; ; ) {
|
|
24
|
+
const found = await detectPackageManagerInDir(dir);
|
|
25
|
+
if (found) return found;
|
|
26
|
+
if (dir === stop) break;
|
|
27
|
+
const parent = path.dirname(dir);
|
|
28
|
+
const relParent = path.relative(stop, parent);
|
|
29
|
+
if (parent === dir || relParent.startsWith("..") || path.isAbsolute(relParent)) break;
|
|
30
|
+
dir = parent;
|
|
26
31
|
}
|
|
32
|
+
return "npm";
|
|
33
|
+
}
|
|
34
|
+
async function detectPackageManagerInDir(dir) {
|
|
35
|
+
const fs6 = await import("node:fs/promises");
|
|
27
36
|
try {
|
|
28
|
-
await
|
|
29
|
-
|
|
37
|
+
const raw = await fs6.readFile(path.join(dir, "package.json"), "utf8");
|
|
38
|
+
const declared = JSON.parse(raw).packageManager;
|
|
39
|
+
if (typeof declared === "string") {
|
|
40
|
+
const name = declared.split("@")[0] ?? "";
|
|
41
|
+
if (name === "pnpm" || name === "yarn") return name;
|
|
42
|
+
if (name === "npm" || name === "bun") return "npm";
|
|
43
|
+
}
|
|
30
44
|
} catch {
|
|
31
45
|
}
|
|
32
|
-
|
|
46
|
+
const lockfiles = [
|
|
47
|
+
["pnpm-lock.yaml", "pnpm"],
|
|
48
|
+
["yarn.lock", "yarn"],
|
|
49
|
+
["bun.lockb", "npm"],
|
|
50
|
+
["bun.lock", "npm"],
|
|
51
|
+
["package-lock.json", "npm"],
|
|
52
|
+
["npm-shrinkwrap.json", "npm"]
|
|
53
|
+
];
|
|
54
|
+
for (const [file, manager] of lockfiles) {
|
|
55
|
+
try {
|
|
56
|
+
await fs6.stat(`${dir}/${file}`);
|
|
57
|
+
return manager;
|
|
58
|
+
} catch {
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return null;
|
|
33
62
|
}
|
|
34
63
|
function resolvePath(input, ctx) {
|
|
35
64
|
return path.isAbsolute(input) ? path.normalize(input) : path.resolve(ctx.workingDir ?? ctx.cwd, input);
|
|
@@ -2719,8 +2748,11 @@ var init_redact_command = __esm({
|
|
|
2719
2748
|
/--(?: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,
|
|
2720
2749
|
// -t short flag (token): attached (-tVALUE), separated (-t VALUE), or -t=VALUE.
|
|
2721
2750
|
// (?<![-\w]) anchors to a token start so we don't match the `-t` inside `--token`.
|
|
2751
|
+
// The value must be token-like (>= 8 chars) so ordinary combined flags such
|
|
2752
|
+
// as `tar -tf` / `ssh -tt` are not eaten. Global flag: EVERY occurrence is
|
|
2753
|
+
// redacted, not just the first.
|
|
2722
2754
|
// NOTE: synced with @wrongstack/core observability/redact-command.ts.
|
|
2723
|
-
/(?<![-\w])-t(?:[=\s]+)?[^\s,-]
|
|
2755
|
+
/(?<![-\w])-t(?:[=\s]+)?[^\s,-]{8,}/g,
|
|
2724
2756
|
// -p|-password|-a (redis auth) short flags: attached + separated + =value.
|
|
2725
2757
|
// Same token-start anchor; over-redaction is an accepted tradeoff for a
|
|
2726
2758
|
// redaction function. Synced with core copy.
|
|
@@ -2728,8 +2760,9 @@ var init_redact_command = __esm({
|
|
|
2728
2760
|
// env var–style secrets: TOKEN=x, API_KEY=y, etc.
|
|
2729
2761
|
/(?:TOKEN|API_KEY|API_SECRET|AUTH_TOKEN|GITHUB_TOKEN|GH_TOKEN|BEARER|JWT|OAUTH|CREDENTIAL|SECRET|PRIVATE_KEY|PASSWORD|PASSWD)\s*[=:]\s*[^\s,]+/gi,
|
|
2730
2762
|
// Generic high-entropy look: base64 strings >32 chars or hex strings >32 digits — but only
|
|
2731
|
-
// when preceded by a flag name (e.g. --github-token=EyJ...).
|
|
2732
|
-
|
|
2763
|
+
// when preceded by a flag name (e.g. --github-token=EyJ...). Global flag so
|
|
2764
|
+
// every such flag in the command line is redacted, not just the first.
|
|
2765
|
+
/--\w*(?:token|key|secret|password|passwd|auth|credential)\w*[=\s,][A-Za-z0-9+/=]{32,}/g
|
|
2733
2766
|
];
|
|
2734
2767
|
}
|
|
2735
2768
|
});
|
|
@@ -2815,11 +2848,15 @@ var init_process_registry = __esm({
|
|
|
2815
2848
|
return Number.isInteger(pid) && pid > 1 && pid !== process.pid && pid !== process.ppid;
|
|
2816
2849
|
}
|
|
2817
2850
|
_canSignalProcessGroup(p) {
|
|
2818
|
-
return os.platform() !== "win32" && p.processGroupLeader === true && this._isSafeSignalPid(p.pid) && typeof p.child.pid === "number" && p.child.pid === p.pid;
|
|
2851
|
+
return os.platform() !== "win32" && p.processGroupLeader === true && this._isSafeSignalPid(p.pid) && p.child !== null && typeof p.child.pid === "number" && p.child.pid === p.pid;
|
|
2819
2852
|
}
|
|
2820
2853
|
_killChildDirect(p, signal) {
|
|
2821
2854
|
try {
|
|
2822
|
-
p.child
|
|
2855
|
+
if (p.child) {
|
|
2856
|
+
p.child.kill(signal);
|
|
2857
|
+
return;
|
|
2858
|
+
}
|
|
2859
|
+
if (this._isSafeSignalPid(p.pid)) process.kill(p.pid, signal);
|
|
2823
2860
|
} catch {
|
|
2824
2861
|
}
|
|
2825
2862
|
}
|
|
@@ -3017,15 +3054,15 @@ var init_process_registry = __esm({
|
|
|
3017
3054
|
this._pruneStale(pid);
|
|
3018
3055
|
const p = this.processes.get(pid);
|
|
3019
3056
|
if (!p) return false;
|
|
3020
|
-
if (p.killed) return true;
|
|
3057
|
+
if (p.killed && opts.force !== true) return true;
|
|
3021
3058
|
if (p.protected && opts.includeProtected !== true) return false;
|
|
3022
3059
|
if (opts.preserveBackground && p.background) return false;
|
|
3023
3060
|
const { force = false, graceMs = DEFAULT_GRACE_MS } = opts;
|
|
3024
3061
|
const isWin2 = os.platform() === "win32";
|
|
3025
3062
|
if (isWin2) {
|
|
3026
|
-
const liveRealChild = p.child.exitCode === null && typeof p.child.pid === "number";
|
|
3063
|
+
const liveRealChild = p.child === null || p.child.exitCode === null && typeof p.child.pid === "number";
|
|
3027
3064
|
const directFallback = () => {
|
|
3028
|
-
if (p.child.exitCode === null) {
|
|
3065
|
+
if (p.child && p.child.exitCode === null) {
|
|
3029
3066
|
try {
|
|
3030
3067
|
p.child.kill("SIGKILL");
|
|
3031
3068
|
} catch {
|
|
@@ -3037,10 +3074,7 @@ var init_process_registry = __esm({
|
|
|
3037
3074
|
onSettled: directFallback
|
|
3038
3075
|
})) {
|
|
3039
3076
|
} else {
|
|
3040
|
-
|
|
3041
|
-
p.child.kill(force ? "SIGKILL" : "SIGTERM");
|
|
3042
|
-
} catch {
|
|
3043
|
-
}
|
|
3077
|
+
this._killChildDirect(p, force ? "SIGKILL" : "SIGTERM");
|
|
3044
3078
|
}
|
|
3045
3079
|
p.killed = true;
|
|
3046
3080
|
return true;
|
|
@@ -3051,7 +3085,7 @@ var init_process_registry = __esm({
|
|
|
3051
3085
|
} else {
|
|
3052
3086
|
this._killPosix(p, "SIGTERM");
|
|
3053
3087
|
const timer = setTimeout(() => {
|
|
3054
|
-
if (this.processes.has(pid) && !p.child
|
|
3088
|
+
if (this.processes.has(pid) && !p.child?.killed) {
|
|
3055
3089
|
this._killPosix(p, "SIGKILL");
|
|
3056
3090
|
}
|
|
3057
3091
|
}, graceMs);
|
|
@@ -3106,6 +3140,16 @@ var init_process_registry = __esm({
|
|
|
3106
3140
|
* before reusing a PID, but we want to clean up before that becomes a risk.
|
|
3107
3141
|
*/
|
|
3108
3142
|
_isStaleEntry(entry) {
|
|
3143
|
+
if (entry.child === null) {
|
|
3144
|
+
if (Date.now() - entry.startedAt <= 6e4) return false;
|
|
3145
|
+
if (os.platform() === "win32") return false;
|
|
3146
|
+
try {
|
|
3147
|
+
process.kill(entry.pid, 0);
|
|
3148
|
+
return false;
|
|
3149
|
+
} catch (err) {
|
|
3150
|
+
return err.code !== "EPERM";
|
|
3151
|
+
}
|
|
3152
|
+
}
|
|
3109
3153
|
return entry.child.exitCode !== null && Date.now() - entry.startedAt > 6e4;
|
|
3110
3154
|
}
|
|
3111
3155
|
/**
|
|
@@ -4972,25 +5016,12 @@ var outdatedTool = {
|
|
|
4972
5016
|
inputSchema: {
|
|
4973
5017
|
type: "object",
|
|
4974
5018
|
properties: {
|
|
4975
|
-
cwd: { type: "string", description: "Working directory (default: cwd)" }
|
|
4976
|
-
format: {
|
|
4977
|
-
type: "string",
|
|
4978
|
-
enum: ["list", "table"],
|
|
4979
|
-
description: "Output format (default: list)"
|
|
4980
|
-
},
|
|
4981
|
-
include_deprecated: {
|
|
4982
|
-
type: "boolean",
|
|
4983
|
-
description: "Include deprecated packages (default: false)"
|
|
4984
|
-
},
|
|
4985
|
-
check: {
|
|
4986
|
-
type: "string",
|
|
4987
|
-
description: "Specific package(s) to check (comma-separated)"
|
|
4988
|
-
}
|
|
5019
|
+
cwd: { type: "string", description: "Working directory (default: cwd)" }
|
|
4989
5020
|
}
|
|
4990
5021
|
},
|
|
4991
5022
|
async execute(input, ctx, opts) {
|
|
4992
5023
|
const cwd = input.cwd ? safeResolve(input.cwd, ctx) : ctx.cwd;
|
|
4993
|
-
const manager = await detectPackageManager(cwd);
|
|
5024
|
+
const manager = await detectPackageManager(cwd, ctx.projectRoot);
|
|
4994
5025
|
if (manager === "npm") {
|
|
4995
5026
|
try {
|
|
4996
5027
|
const { detectNonJsEcosystem: detectNonJsEcosystem2 } = await Promise.resolve().then(() => (init_legacy_bridge(), legacy_bridge_exports));
|
|
@@ -5043,8 +5074,6 @@ var outdatedTool = {
|
|
|
5043
5074
|
}
|
|
5044
5075
|
}
|
|
5045
5076
|
const args = ["outdated", "--json"];
|
|
5046
|
-
if (input.format === "table") args.push("--table");
|
|
5047
|
-
if (input.include_deprecated) args.push("--include", "deprecated");
|
|
5048
5077
|
return runOutdated(manager, args, cwd, opts.signal);
|
|
5049
5078
|
}
|
|
5050
5079
|
};
|
|
@@ -5098,27 +5127,39 @@ function parseOutdatedOutput(json, exitCode) {
|
|
|
5098
5127
|
truncated: false
|
|
5099
5128
|
};
|
|
5100
5129
|
}
|
|
5130
|
+
const truncated = json.length >= 1e5 || Buffer.byteLength(json, "utf8") > COMMAND_OUTPUT_MAX_BYTES;
|
|
5131
|
+
let parsedOk = false;
|
|
5101
5132
|
try {
|
|
5102
5133
|
const data = JSON.parse(json);
|
|
5134
|
+
parsedOk = true;
|
|
5103
5135
|
for (const name of Object.keys(data)) {
|
|
5104
|
-
const info = data[name];
|
|
5136
|
+
const info = data[name] ?? {};
|
|
5137
|
+
const str = (v) => typeof v === "string" ? v : void 0;
|
|
5105
5138
|
packages.push({
|
|
5106
5139
|
name,
|
|
5107
|
-
current: info
|
|
5108
|
-
latest: info
|
|
5109
|
-
wanted: info
|
|
5110
|
-
|
|
5111
|
-
|
|
5140
|
+
current: str(info["current"]) ?? "unknown",
|
|
5141
|
+
latest: str(info["latest"]) ?? "unknown",
|
|
5142
|
+
wanted: str(info["wanted"]) ?? "unknown",
|
|
5143
|
+
// npm calls it `type`; pnpm calls it `dependencyType`.
|
|
5144
|
+
type: str(info["type"]) ?? str(info["dependencyType"]) ?? "unknown",
|
|
5145
|
+
location: str(info["location"]) ?? name
|
|
5112
5146
|
});
|
|
5113
5147
|
}
|
|
5114
5148
|
} catch {
|
|
5149
|
+
}
|
|
5150
|
+
const outdatedFound = parsedOk && exitCode === 1;
|
|
5151
|
+
let output = normalizeCommandOutput(json);
|
|
5152
|
+
if (outdatedFound) {
|
|
5153
|
+
output = `${output}
|
|
5154
|
+
|
|
5155
|
+
Note: exit code 1 from \`outdated\` means outdated packages were found (expected); treated as success.`;
|
|
5115
5156
|
}
|
|
5116
5157
|
return {
|
|
5117
|
-
exit_code: exitCode,
|
|
5158
|
+
exit_code: outdatedFound ? 0 : exitCode,
|
|
5118
5159
|
packages,
|
|
5119
5160
|
total: packages.length,
|
|
5120
|
-
output
|
|
5121
|
-
truncated
|
|
5161
|
+
output,
|
|
5162
|
+
truncated
|
|
5122
5163
|
};
|
|
5123
5164
|
}
|
|
5124
5165
|
export {
|