@wrongstack/tools 0.313.0 → 0.316.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_edit-match.d.ts +3 -2
- package/dist/_output-spool.d.ts +4 -3
- package/dist/_shell-pick.d.ts +2 -1
- package/dist/_spawn-stream.d.ts +2 -1
- package/dist/_syntax-check.d.ts +2 -1
- package/dist/audit.js +10 -4055
- package/dist/bash-kill-guard.d.ts +3 -6
- package/dist/bash.js +9 -2308
- package/dist/batch-tool-use.js +2 -187
- package/dist/browser/index.js +25 -1339
- package/dist/browser/network-guard-proxy.d.ts +2 -1
- package/dist/builtin.js +69 -33949
- package/dist/chunk-22B7GE5T.js +260 -0
- package/dist/chunk-2VSZC6QM.js +113 -0
- package/dist/chunk-3PVYQFRQ.js +472 -0
- package/dist/chunk-42BHI7TN.js +337 -0
- package/dist/chunk-4BHUSMNL.js +104 -0
- package/dist/chunk-4I4LWFOO.js +431 -0
- package/dist/chunk-4UESMQDP.js +122 -0
- package/dist/chunk-553IQUMO.js +478 -0
- package/dist/chunk-5H4GSJAI.js +223 -0
- package/dist/chunk-6RNIFLG4.js +305 -0
- package/dist/chunk-7EY5DCRO.js +434 -0
- package/dist/chunk-A6BRWIXN.js +317 -0
- package/dist/chunk-AHHDWNXC.js +200 -0
- package/dist/chunk-BSLVR56S.js +199 -0
- package/dist/chunk-BTSFTGIL.js +7 -0
- package/dist/chunk-D33S4RQG.js +222 -0
- package/dist/chunk-DA4KNE2H.js +4412 -0
- package/dist/chunk-DR7JOQTC.js +520 -0
- package/dist/chunk-EEOFQDT6.js +898 -0
- package/dist/chunk-EJWSCQ6D.js +137 -0
- package/dist/chunk-EMRGN4KM.js +170 -0
- package/dist/chunk-FQZOHLG3.js +89 -0
- package/dist/chunk-GOIZNNOA.js +221 -0
- package/dist/chunk-HFXSNKCV.js +196 -0
- package/dist/chunk-HYX2TZ7O.js +1272 -0
- package/dist/chunk-I64BS3VC.js +15 -0
- package/dist/chunk-IVWV2UM6.js +955 -0
- package/dist/chunk-IXMNTNW5.js +238 -0
- package/dist/chunk-IYK7XGDZ.js +892 -0
- package/dist/chunk-J5SKD6LN.js +235 -0
- package/dist/chunk-JNNVRHMV.js +2111 -0
- package/dist/chunk-JOHXDF3D.js +295 -0
- package/dist/chunk-JRJJX3L5.js +424 -0
- package/dist/chunk-K3WNSHUF.js +1371 -0
- package/dist/chunk-L25CVUVR.js +2830 -0
- package/dist/chunk-LIJQMYYX.js +59 -0
- package/dist/chunk-LWKUTMD5.js +197 -0
- package/dist/chunk-MQX2KXVW.js +54 -0
- package/dist/chunk-MZZN7VCD.js +359 -0
- package/dist/chunk-NBDZMMG2.js +169 -0
- package/dist/chunk-NKJW5GFO.js +366 -0
- package/dist/chunk-NKNOBUBU.js +522 -0
- package/dist/chunk-O4MBV4AX.js +134 -0
- package/dist/chunk-OUBDL3WH.js +3515 -0
- package/dist/chunk-PQKK5JH7.js +101 -0
- package/dist/chunk-PY2IOS7C.js +1000 -0
- package/dist/chunk-Q5JPPCZC.js +12 -0
- package/dist/chunk-QBV725YG.js +128 -0
- package/dist/chunk-QZQSPUBF.js +315 -0
- package/dist/chunk-RGISBZBD.js +231 -0
- package/dist/chunk-RJZQWEMS.js +84 -0
- package/dist/chunk-RXISBFR5.js +315 -0
- package/dist/chunk-S5CCLZL3.js +99 -0
- package/dist/chunk-SDLVH5RZ.js +178 -0
- package/dist/chunk-T2F4S7U4.js +1723 -0
- package/dist/chunk-TEBQ4VPZ.js +163 -0
- package/dist/chunk-U4D5S3VQ.js +21 -0
- package/dist/chunk-U4VAATKP.js +193 -0
- package/dist/chunk-UCYQTZ7F.js +113 -0
- package/dist/chunk-UKU2ZX4C.js +203 -0
- package/dist/chunk-UNSKG6DC.js +159 -0
- package/dist/chunk-V43EQ6VR.js +68 -0
- package/dist/chunk-VB3MJGCV.js +610 -0
- package/dist/chunk-VFKPWSOX.js +154 -0
- package/dist/chunk-VJNHFZ7J.js +190 -0
- package/dist/chunk-VXECAJJ7.js +1091 -0
- package/dist/chunk-WHIIIREL.js +223 -0
- package/dist/chunk-Z6DAKQ3U.js +1 -0
- package/dist/chunk-ZJQ4IGXK.js +474 -0
- package/dist/chunk-ZLTFLC25.js +385 -0
- package/dist/circuit-breaker.js +3 -191
- package/dist/codebase-index/ast-invariant-engine.d.ts +5 -4
- package/dist/codebase-index/binary-frame.d.ts +0 -2
- package/dist/codebase-index/bm25.d.ts +1 -1
- package/dist/codebase-index/circuit-breaker.d.ts +2 -1
- package/dist/codebase-index/codebase-ast-replace-tool.d.ts +3 -2
- package/dist/codebase-index/codebase-impact-analysis-tool.d.ts +4 -3
- package/dist/codebase-index/codebase-invariant-check-tool.d.ts +3 -2
- package/dist/codebase-index/codebase-repo-map-tool.d.ts +3 -2
- package/dist/codebase-index/codebase-skeleton-tool.d.ts +3 -2
- package/dist/codebase-index/codebase-targeted-test-tool.d.ts +3 -2
- package/dist/codebase-index/content-hash.d.ts +0 -2
- package/dist/codebase-index/import-extractor.d.ts +0 -13
- package/dist/codebase-index/index-service.d.ts +1 -1
- package/dist/codebase-index/index.js +84 -13688
- package/dist/codebase-index/languages.d.ts +2 -1
- package/dist/codebase-index/module-roots.d.ts +3 -2
- package/dist/codebase-index/parser-batch.d.ts +0 -5
- package/dist/codebase-index/parser-dispatch.d.ts +2 -1
- package/dist/codebase-index/parser-output.d.ts +4 -3
- package/dist/codebase-index/parser-worker-pool.d.ts +0 -2
- package/dist/codebase-index/parser-worker-script.d.ts +1 -16
- package/dist/codebase-index/parser-worker-script.js +8 -3995
- package/dist/codebase-index/project-server-client-state.d.ts +2 -2
- package/dist/codebase-index/project-server-endpoint.d.ts +0 -15
- package/dist/codebase-index/project-server.js +60 -8548
- package/dist/codebase-index/tree-sitter/visitor.d.ts +2 -1
- package/dist/codebase-index/tree-sitter-parser.d.ts +0 -2
- package/dist/codebase-index/ts-parser.d.ts +1 -1
- package/dist/codebase-index/vector-search.d.ts +2 -1
- package/dist/codebase-index/wal-maintenance.d.ts +3 -2
- package/dist/codebase-index/worker.js +20 -8416
- package/dist/codebase-index/writer-admin.d.ts +0 -1
- package/dist/codebase-index/writer-search.d.ts +0 -9
- package/dist/design.js +2 -299
- package/dist/diff.js +4 -256
- package/dist/document.js +4 -222
- package/dist/e2e.js +5 -476
- package/dist/edit.js +14 -10200
- package/dist/exec.js +16 -3131
- package/dist/fetch.js +8 -398
- package/dist/format.js +10 -3750
- package/dist/generic-parser-VUXDIAOZ.js +13 -0
- package/dist/git.js +4 -380
- package/dist/glob.js +6 -280
- package/dist/go-parser-JXYKJHRC.js +469 -0
- package/dist/grep.js +7 -604
- package/dist/index.js +318 -35387
- package/dist/install.js +10 -4091
- package/dist/json-parser-IBHZ4BZC.js +213 -0
- package/dist/json.js +4 -665
- package/dist/kanban-contract-actions.d.ts +1 -1
- package/dist/kanban-detail-actions.d.ts +2 -1
- package/dist/kanban-presence.d.ts +2 -1
- package/dist/kanban-serializer.d.ts +0 -8
- package/dist/kanban-split-task-handler.d.ts +2 -2
- package/dist/kanban-tool-types.d.ts +2 -1
- package/dist/kanban.js +3 -2096
- package/dist/languages/diagnostics.d.ts +2 -1
- package/dist/languages/index.js +23 -4664
- package/dist/languages/legacy-bridge.d.ts +3 -2
- package/dist/languages/types.d.ts +2 -1
- package/dist/legacy-bridge-7M6QLUQN.js +18 -0
- package/dist/lint.js +10 -3706
- package/dist/logs.js +4 -287
- package/dist/memory.js +6 -215
- package/dist/mode.js +3 -99
- package/dist/outdated.js +4 -5170
- package/dist/pack.js +65 -33897
- package/dist/parser-dispatch-QH4XPGG6.js +14 -0
- package/dist/patch.js +13 -9935
- package/dist/plan.js +5 -3286
- package/dist/process-registry.js +8 -651
- package/dist/ps-slash.js +12 -1439
- package/dist/pwsh.d.ts +0 -1
- package/dist/py-parser-IS4HKYMF.js +16 -0
- package/dist/read.js +13 -9816
- package/dist/replace.js +15 -10014
- package/dist/rs-parser-XHUUO2KZ.js +81 -0
- package/dist/scaffold.js +4 -253
- package/dist/search.js +5 -585
- package/dist/session-kanban-sync.d.ts +0 -6
- package/dist/session-kanban.js +30 -972
- package/dist/skill.js +2 -215
- package/dist/spawn-background.d.ts +1 -1
- package/dist/task.js +5 -3410
- package/dist/test.js +10 -3773
- package/dist/todo.js +4 -2891
- package/dist/tool-help.js +3 -123
- package/dist/tool-search.js +3 -79
- package/dist/tool-tier.js +68 -33984
- package/dist/tool-use.js +2 -93
- package/dist/tree-sitter-parser-AIERW3YI.js +15 -0
- package/dist/tree.js +4 -288
- package/dist/ts-parser-RCTYKSVI.js +232 -0
- package/dist/typecheck.js +10 -3753
- package/dist/win32.js +6 -60
- package/dist/write.js +14 -9882
- package/dist/yaml-parser-4SAXV3PL.js +157 -0
- package/package.json +5 -5
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import {
|
|
2
|
+
tryLegacyCodeOperation
|
|
3
|
+
} from "./chunk-PQKK5JH7.js";
|
|
4
|
+
import {
|
|
5
|
+
spawnStream
|
|
6
|
+
} from "./chunk-22B7GE5T.js";
|
|
7
|
+
import {
|
|
8
|
+
detectPackageManager,
|
|
9
|
+
normalizeCommandOutput,
|
|
10
|
+
safeResolveReal
|
|
11
|
+
} from "./chunk-D33S4RQG.js";
|
|
12
|
+
|
|
13
|
+
// src/typecheck.ts
|
|
14
|
+
import * as path from "node:path";
|
|
15
|
+
var typecheckTool = {
|
|
16
|
+
name: "typecheck",
|
|
17
|
+
category: "Code Quality",
|
|
18
|
+
description: "Run the project's TypeScript type checker (`tsc --noEmit` or equivalent). Essential for verifying type safety before making changes or committing.",
|
|
19
|
+
usageHint: "ALWAYS RUN BEFORE CONSIDERING WORK COMPLETE:\n\n- Use this to catch type errors early.\n- In monorepos, `all: true` will check every package.\n- This is one of the most important quality gates in this project.\nNever claim a task is done without a clean typecheck (unless the user explicitly says otherwise).",
|
|
20
|
+
permission: "confirm",
|
|
21
|
+
mutating: false,
|
|
22
|
+
timeoutMs: 12e4,
|
|
23
|
+
capabilities: ["shell.restricted"],
|
|
24
|
+
icon: "code",
|
|
25
|
+
inputSchema: {
|
|
26
|
+
type: "object",
|
|
27
|
+
properties: {
|
|
28
|
+
project: { type: "string", description: "Path to tsconfig.json (default: auto-detect)" },
|
|
29
|
+
cwd: { type: "string", description: "Working directory (default: cwd)" },
|
|
30
|
+
strict: {
|
|
31
|
+
type: "boolean",
|
|
32
|
+
description: "Add --strict flag for maximum type checking (default: false)"
|
|
33
|
+
},
|
|
34
|
+
all: {
|
|
35
|
+
type: "boolean",
|
|
36
|
+
description: "Type-check all workspace packages (pnpm workspaces run `pnpm -r exec tsc --noEmit`; other setups run a single `tsc --noEmit` at cwd) (default: false)"
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
async execute(input, ctx, opts) {
|
|
41
|
+
let final;
|
|
42
|
+
const executeStream = typecheckTool.executeStream;
|
|
43
|
+
if (!executeStream) throw new Error("typecheckTool: stream execution unavailable");
|
|
44
|
+
for await (const ev of executeStream(input, ctx, opts)) {
|
|
45
|
+
if (ev.type === "final") final = ev.output;
|
|
46
|
+
}
|
|
47
|
+
if (!final) throw new Error("typecheck: stream ended without final event");
|
|
48
|
+
return final;
|
|
49
|
+
},
|
|
50
|
+
async *executeStream(input, ctx, opts) {
|
|
51
|
+
const cwd = input.cwd ? await safeResolveReal(input.cwd, ctx) : ctx.cwd;
|
|
52
|
+
const bridge = await tryLegacyCodeOperation("semantic", {
|
|
53
|
+
cwd,
|
|
54
|
+
projectRoot: ctx.projectRoot,
|
|
55
|
+
signal: opts.signal
|
|
56
|
+
});
|
|
57
|
+
if (bridge?.run) {
|
|
58
|
+
const run = bridge.run;
|
|
59
|
+
yield {
|
|
60
|
+
type: "final",
|
|
61
|
+
output: {
|
|
62
|
+
project: `${bridge.language} workspace`,
|
|
63
|
+
exit_code: run.exitCode ?? 0,
|
|
64
|
+
errors: run.summary.errors,
|
|
65
|
+
warnings: run.summary.warnings,
|
|
66
|
+
output: normalizeCommandOutput(run.output || run.error || ""),
|
|
67
|
+
truncated: run.truncated
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
let cmd;
|
|
73
|
+
let cmdArgs;
|
|
74
|
+
let project;
|
|
75
|
+
if (input.all) {
|
|
76
|
+
project = "workspace";
|
|
77
|
+
const tscArgs = ["--noEmit"];
|
|
78
|
+
if (input.strict) tscArgs.push("--strict");
|
|
79
|
+
const manager = await detectPackageManager(cwd, ctx.projectRoot);
|
|
80
|
+
if (manager === "pnpm") {
|
|
81
|
+
cmd = "pnpm";
|
|
82
|
+
cmdArgs = ["-r", "--no-bail", "exec", "tsc", ...tscArgs];
|
|
83
|
+
} else {
|
|
84
|
+
cmd = "npx";
|
|
85
|
+
cmdArgs = ["tsc", ...tscArgs];
|
|
86
|
+
}
|
|
87
|
+
} else {
|
|
88
|
+
const tsconfig = input.project ? await safeResolveReal(input.project, ctx) : await findTsConfig(cwd);
|
|
89
|
+
const tscArgs = ["--noEmit"];
|
|
90
|
+
if (input.strict) tscArgs.push("--strict");
|
|
91
|
+
if (tsconfig) tscArgs.push("--project", tsconfig);
|
|
92
|
+
project = tsconfig ?? "default";
|
|
93
|
+
cmd = "npx";
|
|
94
|
+
cmdArgs = ["tsc", ...tscArgs];
|
|
95
|
+
}
|
|
96
|
+
yield { type: "log", text: `${cmd} ${cmdArgs.join(" ")}`, data: { project } };
|
|
97
|
+
const result = yield* spawnStream({
|
|
98
|
+
cmd,
|
|
99
|
+
args: cmdArgs,
|
|
100
|
+
cwd,
|
|
101
|
+
signal: opts.signal,
|
|
102
|
+
maxBytes: 2e5
|
|
103
|
+
});
|
|
104
|
+
const combined = `${result.stdout}
|
|
105
|
+
${result.stderr}`;
|
|
106
|
+
const errors = [...combined.matchAll(/^.*\berror TS\d+:/gm)].length;
|
|
107
|
+
const warnings = [...combined.matchAll(/^.*\bwarning TS\d+:/gm)].length;
|
|
108
|
+
yield {
|
|
109
|
+
type: "final",
|
|
110
|
+
output: {
|
|
111
|
+
project,
|
|
112
|
+
exit_code: result.exitCode,
|
|
113
|
+
errors,
|
|
114
|
+
warnings,
|
|
115
|
+
output: normalizeCommandOutput(result.stdout || result.stderr || result.error || ""),
|
|
116
|
+
truncated: result.truncated
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
async function findTsConfig(cwd) {
|
|
122
|
+
const { stat } = await import("node:fs/promises");
|
|
123
|
+
const candidates = ["tsconfig.json", "tsconfig.base.json"];
|
|
124
|
+
for (const f of candidates) {
|
|
125
|
+
try {
|
|
126
|
+
const s = await stat(path.join(cwd, f));
|
|
127
|
+
if (s.isFile()) return path.join(cwd, f);
|
|
128
|
+
} catch {
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return null;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export {
|
|
135
|
+
typecheckTool
|
|
136
|
+
};
|
|
137
|
+
//# sourceMappingURL=chunk-EJWSCQ6D.js.map
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ensureInsideRoot,
|
|
3
|
+
safeResolveReal
|
|
4
|
+
} from "./chunk-D33S4RQG.js";
|
|
5
|
+
|
|
6
|
+
// src/document.ts
|
|
7
|
+
import * as fs from "node:fs/promises";
|
|
8
|
+
import * as path from "node:path";
|
|
9
|
+
var documentTool = {
|
|
10
|
+
name: "document",
|
|
11
|
+
category: "Project",
|
|
12
|
+
description: "DEPRECATED \u2014 read-only preview stub that lists undocumented symbols as `skipped` candidates. It never writes files and does not generate real docstrings. If the auto-doc plugin is enabled, use its `auto_doc` tool (with `dry_run: true` to preview) instead.",
|
|
13
|
+
usageHint: "Deprecated: this tool only lists undocumented symbols with placeholder comments \u2014 it does not generate real JSDoc/TSDoc and writes nothing. When the auto-doc plugin is enabled, prefer its `auto_doc` tool (`dry_run: true` for previewing, without it for writing).",
|
|
14
|
+
permission: "auto",
|
|
15
|
+
mutating: false,
|
|
16
|
+
timeoutMs: 3e4,
|
|
17
|
+
capabilities: ["fs.read"],
|
|
18
|
+
icon: "document",
|
|
19
|
+
inputSchema: {
|
|
20
|
+
type: "object",
|
|
21
|
+
properties: {
|
|
22
|
+
target: {
|
|
23
|
+
type: "string",
|
|
24
|
+
enum: ["file", "function", "class", "type", "all"],
|
|
25
|
+
description: "What to document"
|
|
26
|
+
},
|
|
27
|
+
path: {
|
|
28
|
+
type: "string",
|
|
29
|
+
description: "Specific file path to document"
|
|
30
|
+
},
|
|
31
|
+
files: {
|
|
32
|
+
type: "string",
|
|
33
|
+
description: "File(s) to process: single path, comma-separated list, or glob"
|
|
34
|
+
},
|
|
35
|
+
style: {
|
|
36
|
+
type: "string",
|
|
37
|
+
enum: ["jsdoc", "tsdoc", "block"],
|
|
38
|
+
description: "Documentation style (default: jsdoc)"
|
|
39
|
+
},
|
|
40
|
+
cwd: { type: "string", description: "Working directory (default: cwd)" }
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
async execute(input, ctx) {
|
|
44
|
+
const cwd = input.cwd ? await safeResolveReal(input.cwd, ctx) : ctx.cwd;
|
|
45
|
+
const style = input.style ?? "jsdoc";
|
|
46
|
+
const results = [];
|
|
47
|
+
let filesProcessed = 0;
|
|
48
|
+
let itemsDocumented = 0;
|
|
49
|
+
const fileList = input.files ? await resolveFiles(
|
|
50
|
+
Array.isArray(input.files) ? input.files.join(",") : input.files,
|
|
51
|
+
cwd,
|
|
52
|
+
ctx
|
|
53
|
+
) : input.path ? [await safeResolveReal(input.path, ctx)] : [];
|
|
54
|
+
for (const absPath of fileList) {
|
|
55
|
+
try {
|
|
56
|
+
const content = await fs.readFile(absPath, "utf8");
|
|
57
|
+
filesProcessed++;
|
|
58
|
+
const processed = processFile(
|
|
59
|
+
content,
|
|
60
|
+
absPath,
|
|
61
|
+
style,
|
|
62
|
+
input.overwrite ?? false,
|
|
63
|
+
input.target ?? "all"
|
|
64
|
+
);
|
|
65
|
+
results.push(...processed);
|
|
66
|
+
itemsDocumented += processed.filter((r) => r.status === "documented").length;
|
|
67
|
+
} catch (e) {
|
|
68
|
+
results.push({
|
|
69
|
+
path: absPath,
|
|
70
|
+
name: absPath.split("/").pop() ?? absPath,
|
|
71
|
+
signature: "",
|
|
72
|
+
docstring: "",
|
|
73
|
+
status: "error",
|
|
74
|
+
error: e instanceof Error ? e.message : String(e)
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return {
|
|
79
|
+
files_processed: filesProcessed,
|
|
80
|
+
items_documented: itemsDocumented,
|
|
81
|
+
results,
|
|
82
|
+
style
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
async function resolveFiles(filesInput, cwd, ctx) {
|
|
87
|
+
const files = filesInput.split(",");
|
|
88
|
+
const resolved = [];
|
|
89
|
+
for (const f of files) {
|
|
90
|
+
const entry = f.trim();
|
|
91
|
+
if (!entry) continue;
|
|
92
|
+
let absPath;
|
|
93
|
+
try {
|
|
94
|
+
absPath = ensureInsideRoot(path.resolve(cwd, entry), ctx);
|
|
95
|
+
} catch {
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
try {
|
|
99
|
+
const stat2 = await fs.stat(absPath);
|
|
100
|
+
if (stat2.isFile()) resolved.push(absPath);
|
|
101
|
+
} catch {
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return resolved;
|
|
105
|
+
}
|
|
106
|
+
function processFile(content, absPath, _style, _overwrite, target) {
|
|
107
|
+
const results = [];
|
|
108
|
+
const functionRegex = /(?:async\s+)?function\s+(\w+)\s*\(([^)]*)\)/g;
|
|
109
|
+
const arrowRegex = /(?:const|let|var)\s+(\w+)\s*=\s*(?:async\s+)?\(([^)]*)\)\s*=>/g;
|
|
110
|
+
const classRegex = /class\s+(\w+)/g;
|
|
111
|
+
const typeRegex = /(?:type|interface)\s+(\w+)\s*[=<]/g;
|
|
112
|
+
const allMatches = [];
|
|
113
|
+
if (target === "all" || target === "function") {
|
|
114
|
+
for (const m of content.matchAll(functionRegex)) {
|
|
115
|
+
if (!m[1]) continue;
|
|
116
|
+
allMatches.push({
|
|
117
|
+
name: m[1],
|
|
118
|
+
sig: m[2] ?? "",
|
|
119
|
+
type: "function",
|
|
120
|
+
line: content.slice(0, m.index).split("\n").length
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
for (const m of content.matchAll(arrowRegex)) {
|
|
124
|
+
if (!m[1]) continue;
|
|
125
|
+
allMatches.push({
|
|
126
|
+
name: m[1],
|
|
127
|
+
sig: m[2] ?? "",
|
|
128
|
+
type: "arrow",
|
|
129
|
+
line: content.slice(0, m.index).split("\n").length
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
if (target === "all" || target === "class") {
|
|
134
|
+
for (const m of content.matchAll(classRegex)) {
|
|
135
|
+
if (!m[1]) continue;
|
|
136
|
+
allMatches.push({
|
|
137
|
+
name: m[1],
|
|
138
|
+
sig: "",
|
|
139
|
+
type: "class",
|
|
140
|
+
line: content.slice(0, m.index).split("\n").length
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
if (target === "all" || target === "type") {
|
|
145
|
+
for (const m of content.matchAll(typeRegex)) {
|
|
146
|
+
if (!m[1]) continue;
|
|
147
|
+
allMatches.push({
|
|
148
|
+
name: m[1],
|
|
149
|
+
sig: m[0] ?? "",
|
|
150
|
+
type: "type",
|
|
151
|
+
line: content.slice(0, m.index).split("\n").length
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
for (const m of allMatches) {
|
|
156
|
+
results.push({
|
|
157
|
+
path: absPath,
|
|
158
|
+
name: m.name,
|
|
159
|
+
signature: m.sig,
|
|
160
|
+
docstring: `/** ${m.name} - documented at line ${m.line} */`,
|
|
161
|
+
status: "skipped"
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
return results;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export {
|
|
168
|
+
documentTool
|
|
169
|
+
};
|
|
170
|
+
//# sourceMappingURL=chunk-EMRGN4KM.js.map
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
// src/_syntax-check.ts
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
var TS_LIKE = /* @__PURE__ */ new Set([".ts", ".tsx", ".mts", ".cts", ".js", ".jsx", ".mjs", ".cjs"]);
|
|
4
|
+
var MAX_CHECK_CHARS = 15e5;
|
|
5
|
+
var MAX_ERRORS = 5;
|
|
6
|
+
var tsLoad = null;
|
|
7
|
+
function loadTypescript() {
|
|
8
|
+
tsLoad ??= import("@typescript/typescript6").then(
|
|
9
|
+
(m) => m.default ?? m,
|
|
10
|
+
() => null
|
|
11
|
+
);
|
|
12
|
+
return tsLoad;
|
|
13
|
+
}
|
|
14
|
+
async function checkSyntax(filePath, content, previousContent) {
|
|
15
|
+
const errors = await parseErrors(filePath, content);
|
|
16
|
+
if (errors === void 0) return void 0;
|
|
17
|
+
if (errors.length === 0) return { errors, preExisting: false };
|
|
18
|
+
let preExisting = false;
|
|
19
|
+
if (previousContent !== void 0) {
|
|
20
|
+
const prevErrors = await parseErrors(filePath, previousContent);
|
|
21
|
+
preExisting = prevErrors !== void 0 && prevErrors.length > 0;
|
|
22
|
+
}
|
|
23
|
+
return { errors, preExisting };
|
|
24
|
+
}
|
|
25
|
+
function isJsoncFile(filePath) {
|
|
26
|
+
const base = path.basename(filePath).toLowerCase();
|
|
27
|
+
if (base.endsWith(".jsonc")) return true;
|
|
28
|
+
if (/^(tsconfig|jsconfig)([.-].*)?\.json$/.test(base)) return true;
|
|
29
|
+
const dir = path.basename(path.dirname(filePath)).toLowerCase();
|
|
30
|
+
return dir === ".vscode";
|
|
31
|
+
}
|
|
32
|
+
async function parseErrors(filePath, content) {
|
|
33
|
+
if (content.length > MAX_CHECK_CHARS) return void 0;
|
|
34
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
35
|
+
if (ext === ".json" || ext === ".jsonc") {
|
|
36
|
+
try {
|
|
37
|
+
JSON.parse(content);
|
|
38
|
+
return [];
|
|
39
|
+
} catch (err) {
|
|
40
|
+
if (isJsoncFile(filePath)) {
|
|
41
|
+
const ts2 = await loadTypescript();
|
|
42
|
+
if (ts2) {
|
|
43
|
+
const jsonc = ts2.parseConfigFileTextToJson(filePath, content);
|
|
44
|
+
if (!jsonc.error) return [];
|
|
45
|
+
return [formatDiag(ts2, jsonc.error, content)];
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return [`JSON parse error: ${err.message}`];
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
if (!TS_LIKE.has(ext)) return void 0;
|
|
52
|
+
const ts = await loadTypescript();
|
|
53
|
+
if (!ts) return void 0;
|
|
54
|
+
const scriptKind = ext === ".tsx" ? ts.ScriptKind.TSX : ext === ".ts" || ext === ".mts" || ext === ".cts" ? ts.ScriptKind.TS : (
|
|
55
|
+
// Plain JS may legitimately contain JSX; the JSX grammar is a
|
|
56
|
+
// superset for untyped code, so parsing .js/.jsx as JSX avoids
|
|
57
|
+
// false positives on React files.
|
|
58
|
+
ts.ScriptKind.JSX
|
|
59
|
+
);
|
|
60
|
+
const sourceFile = ts.createSourceFile(
|
|
61
|
+
path.basename(filePath),
|
|
62
|
+
content,
|
|
63
|
+
ts.ScriptTarget.Latest,
|
|
64
|
+
/* setParentNodes */
|
|
65
|
+
false,
|
|
66
|
+
scriptKind
|
|
67
|
+
);
|
|
68
|
+
const diags = sourceFile.parseDiagnostics ?? [];
|
|
69
|
+
return diags.slice(0, MAX_ERRORS).map((d) => formatDiag(ts, d, content, sourceFile));
|
|
70
|
+
}
|
|
71
|
+
function formatDiag(ts, diag, content, sourceFile) {
|
|
72
|
+
const message = ts.flattenDiagnosticMessageText(diag.messageText, " ");
|
|
73
|
+
if (diag.start === void 0) return message;
|
|
74
|
+
let line;
|
|
75
|
+
if (sourceFile) {
|
|
76
|
+
line = sourceFile.getLineAndCharacterOfPosition(diag.start).line + 1;
|
|
77
|
+
} else {
|
|
78
|
+
line = 1;
|
|
79
|
+
for (let i = 0; i < diag.start && i < content.length; i++) {
|
|
80
|
+
if (content.charCodeAt(i) === 10) line++;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return `line ${line}: ${message}`;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export {
|
|
87
|
+
checkSyntax
|
|
88
|
+
};
|
|
89
|
+
//# sourceMappingURL=chunk-FQZOHLG3.js.map
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
// src/skill.ts
|
|
2
|
+
import * as fs from "node:fs/promises";
|
|
3
|
+
import * as path from "node:path";
|
|
4
|
+
import {
|
|
5
|
+
missingRequiredRuntimeTools,
|
|
6
|
+
missingRuntimeCapabilities,
|
|
7
|
+
runtimeToolReferencesFromText
|
|
8
|
+
} from "@wrongstack/core/agent-catalog";
|
|
9
|
+
import { SKILL_LIMITS, stripFrontmatter } from "@wrongstack/core/skills";
|
|
10
|
+
import { ToolValidationError } from "@wrongstack/core/types";
|
|
11
|
+
var MAX_BODY_CHARS = SKILL_LIMITS.MAX_SKILL_BODY_CHARS;
|
|
12
|
+
var MAX_RESOURCE_CHARS = SKILL_LIMITS.MAX_RESOURCE_CHARS;
|
|
13
|
+
var MAX_LISTED_RESOURCES = SKILL_LIMITS.MAX_LISTED_RESOURCES;
|
|
14
|
+
var SKIP_DIRS = /* @__PURE__ */ new Set(["node_modules", ".git", "dist", "build"]);
|
|
15
|
+
function makeSkillTool(skillLoader) {
|
|
16
|
+
return {
|
|
17
|
+
name: "skill",
|
|
18
|
+
category: "Skills",
|
|
19
|
+
description: "Load a skill's instructions or a bundled resource on demand (agentskills.io progressive disclosure). With only `name`: returns the SKILL.md body + a list of bundled resource files. With `name` + `resource` (a relative path like `references/REF.md` or `scripts/extract.py`): returns that file content. Prefer this over the read tool for skill files \u2014 it reaches foreign skills outside the project root.",
|
|
20
|
+
usageHint: 'Load a skill body or one of its bundled resources (progressive disclosure).\n\nWHEN TO USE:\n- A task matches a skill trigger \u2192 load the body: skill({ name })\n- You need a reference/template/script bundled with the skill \u2192 skill({ name, resource: "references/REF.md" })\n\nThe body call lists every bundled resource; load the ones you need. Run scripts via bash using the returned abs path.',
|
|
21
|
+
permission: "auto",
|
|
22
|
+
mutating: false,
|
|
23
|
+
capabilities: ["fs.read"],
|
|
24
|
+
icon: "document",
|
|
25
|
+
timeoutMs: 5e3,
|
|
26
|
+
inputSchema: {
|
|
27
|
+
type: "object",
|
|
28
|
+
properties: {
|
|
29
|
+
name: {
|
|
30
|
+
type: "string",
|
|
31
|
+
description: "Exact skill name (as shown in the available-skills list)."
|
|
32
|
+
},
|
|
33
|
+
resource: {
|
|
34
|
+
type: "string",
|
|
35
|
+
description: "Optional relative path of a bundled resource to load (e.g. references/REF.md, scripts/extract.py, assets/template.html). Omit to list resources."
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
required: ["name"]
|
|
39
|
+
},
|
|
40
|
+
async execute(input, ctx) {
|
|
41
|
+
const name = input?.name?.trim();
|
|
42
|
+
if (!name) {
|
|
43
|
+
throw new ToolValidationError({ message: "skill: name is required", field: "name" });
|
|
44
|
+
}
|
|
45
|
+
const manifest = await skillLoader.find(name);
|
|
46
|
+
if (!manifest) {
|
|
47
|
+
throw new ToolValidationError({
|
|
48
|
+
message: `skill "${name}" not found \u2014 use /skill to list available skills`,
|
|
49
|
+
field: "name"
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
const availableToolNames = (ctx?.catalogTools ?? ctx?.tools ?? []).map((tool) => tool.name);
|
|
53
|
+
const missingCapabilities = missingRuntimeCapabilities(
|
|
54
|
+
manifest.requiredCapabilities,
|
|
55
|
+
availableToolNames
|
|
56
|
+
);
|
|
57
|
+
const missingTools = missingRequiredRuntimeTools(manifest.requiredTools, availableToolNames);
|
|
58
|
+
if (missingCapabilities.length > 0 || missingTools.length > 0) {
|
|
59
|
+
throw new ToolValidationError({
|
|
60
|
+
message: `skill "${name}" is unavailable in this runtime; ` + [
|
|
61
|
+
missingCapabilities.length > 0 ? `missing capabilities: ${missingCapabilities.join(", ")}` : "",
|
|
62
|
+
missingTools.length > 0 ? `missing tools: ${missingTools.join(", ")}` : ""
|
|
63
|
+
].filter(Boolean).join("; "),
|
|
64
|
+
field: "name"
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
const dir = path.dirname(manifest.path);
|
|
68
|
+
let loadedResource;
|
|
69
|
+
if (input.resource?.trim()) {
|
|
70
|
+
loadedResource = await loadResource(dir, input.resource.trim());
|
|
71
|
+
}
|
|
72
|
+
const raw = await skillLoader.readBody(name);
|
|
73
|
+
const missingBodyTools = missingRequiredRuntimeTools(
|
|
74
|
+
runtimeToolReferencesFromText(raw),
|
|
75
|
+
availableToolNames
|
|
76
|
+
);
|
|
77
|
+
const warning = missingBodyTools.length > 0 ? `Warning: skill "${name}" references tools not registered in this runtime: ${missingBodyTools.join(", ")}. Steps that call them may be unavailable.` : void 0;
|
|
78
|
+
const body = stripFrontmatter(raw).trim().slice(0, MAX_BODY_CHARS);
|
|
79
|
+
const resources = loadedResource ? [] : await listResources(dir);
|
|
80
|
+
try {
|
|
81
|
+
await ctx?.session?.append({
|
|
82
|
+
type: "skill_activated",
|
|
83
|
+
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
84
|
+
skillName: manifest.name
|
|
85
|
+
});
|
|
86
|
+
} catch {
|
|
87
|
+
}
|
|
88
|
+
return {
|
|
89
|
+
name: manifest.name,
|
|
90
|
+
description: manifest.description,
|
|
91
|
+
body,
|
|
92
|
+
resources,
|
|
93
|
+
dir,
|
|
94
|
+
loadedResource,
|
|
95
|
+
warning
|
|
96
|
+
};
|
|
97
|
+
},
|
|
98
|
+
serialize(output) {
|
|
99
|
+
const warningLine = output.warning ? `
|
|
100
|
+
|
|
101
|
+
${output.warning}` : "";
|
|
102
|
+
if (output.loadedResource) {
|
|
103
|
+
const lr = output.loadedResource;
|
|
104
|
+
const note = lr.truncated ? ` (truncated to ${lr.content.length} chars of ${lr.bytes} B)` : "";
|
|
105
|
+
return `# Resource: ${output.name}/${lr.rel}
|
|
106
|
+
(abs path: ${lr.absPath})${note}
|
|
107
|
+
|
|
108
|
+
${lr.content}${warningLine}`;
|
|
109
|
+
}
|
|
110
|
+
const head = `# Skill: ${output.name}
|
|
111
|
+
${output.description}
|
|
112
|
+
|
|
113
|
+
${output.body}`;
|
|
114
|
+
if (output.resources.length === 0) return `${head}${warningLine}`;
|
|
115
|
+
const listing = output.resources.map((r) => `- ${r.path} (${r.bytes} B)`).join("\n");
|
|
116
|
+
return `${head}
|
|
117
|
+
|
|
118
|
+
## Bundled resources (load on demand)
|
|
119
|
+
Load any with: \`skill({ name: "${output.name}", resource: "<path>" })\`. Run scripts via bash using their abs path under ${output.dir}.
|
|
120
|
+
${listing}${warningLine}`;
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
async function loadResource(skillDir, rel) {
|
|
125
|
+
const norm = rel.replace(/\\/g, "/");
|
|
126
|
+
if (path.isAbsolute(rel) || norm.split("/").some((seg) => seg === "..")) {
|
|
127
|
+
throw new ToolValidationError({
|
|
128
|
+
message: `skill: invalid resource path "${rel}"`,
|
|
129
|
+
field: "resource"
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
const absPath = path.resolve(skillDir, rel);
|
|
133
|
+
const root = path.resolve(skillDir);
|
|
134
|
+
if (absPath !== root && !absPath.startsWith(root + path.sep)) {
|
|
135
|
+
throw new ToolValidationError({
|
|
136
|
+
message: `skill: resource "${rel}" escapes the skill directory`,
|
|
137
|
+
field: "resource"
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
let realPath;
|
|
141
|
+
let realRoot;
|
|
142
|
+
try {
|
|
143
|
+
realRoot = await fs.realpath(root);
|
|
144
|
+
realPath = await fs.realpath(absPath);
|
|
145
|
+
} catch {
|
|
146
|
+
throw new ToolValidationError({
|
|
147
|
+
message: `skill: resource "${rel}" not readable`,
|
|
148
|
+
field: "resource"
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
if (realPath !== realRoot && !realPath.startsWith(realRoot + path.sep)) {
|
|
152
|
+
throw new ToolValidationError({
|
|
153
|
+
message: `skill: resource "${rel}" resolves outside the skill directory`,
|
|
154
|
+
field: "resource"
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
let buf;
|
|
158
|
+
try {
|
|
159
|
+
buf = await fs.readFile(realPath);
|
|
160
|
+
} catch {
|
|
161
|
+
throw new ToolValidationError({
|
|
162
|
+
message: `skill: resource "${rel}" not readable`,
|
|
163
|
+
field: "resource"
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
const raw = buf.toString("utf8");
|
|
167
|
+
const truncated = raw.length > MAX_RESOURCE_CHARS;
|
|
168
|
+
return {
|
|
169
|
+
rel: norm,
|
|
170
|
+
// The canonical path — the one actually opened, and the one a follow-up
|
|
171
|
+
// `bash` invocation should use.
|
|
172
|
+
absPath: realPath,
|
|
173
|
+
content: truncated ? raw.slice(0, MAX_RESOURCE_CHARS) : raw,
|
|
174
|
+
bytes: buf.length,
|
|
175
|
+
truncated
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
async function listResources(skillDir) {
|
|
179
|
+
const out = [];
|
|
180
|
+
await walk(skillDir, skillDir, out);
|
|
181
|
+
out.sort((a, b) => a.path.localeCompare(b.path));
|
|
182
|
+
return out.slice(0, MAX_LISTED_RESOURCES);
|
|
183
|
+
}
|
|
184
|
+
async function walk(root, dir, out) {
|
|
185
|
+
if (out.length >= MAX_LISTED_RESOURCES) return;
|
|
186
|
+
let entries;
|
|
187
|
+
try {
|
|
188
|
+
entries = await fs.readdir(dir, { withFileTypes: true });
|
|
189
|
+
} catch {
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
for (const e of entries) {
|
|
193
|
+
if (out.length >= MAX_LISTED_RESOURCES) return;
|
|
194
|
+
const fullPath = path.join(dir, e.name);
|
|
195
|
+
let isDir = e.isDirectory();
|
|
196
|
+
if (e.isSymbolicLink()) {
|
|
197
|
+
try {
|
|
198
|
+
isDir = (await fs.stat(fullPath)).isDirectory();
|
|
199
|
+
} catch {
|
|
200
|
+
continue;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
if (isDir) {
|
|
204
|
+
if (SKIP_DIRS.has(e.name) || e.name.startsWith(".")) continue;
|
|
205
|
+
await walk(root, fullPath, out);
|
|
206
|
+
} else if (e.isFile()) {
|
|
207
|
+
if (e.name === "SKILL.md" || e.name === "SKILL.save.md") continue;
|
|
208
|
+
try {
|
|
209
|
+
const stat2 = await fs.stat(fullPath);
|
|
210
|
+
const rel = path.relative(root, fullPath).split(path.sep).join("/");
|
|
211
|
+
out.push({ path: rel, bytes: stat2.size });
|
|
212
|
+
} catch {
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
export {
|
|
219
|
+
makeSkillTool
|
|
220
|
+
};
|
|
221
|
+
//# sourceMappingURL=chunk-GOIZNNOA.js.map
|