@rse/ase 0.9.34 → 0.9.36
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/dst/ase-service.js +4 -0
- package/dst/ase-setup.js +11 -9
- package/dst/ase-skills.js +69 -17
- package/package.json +7 -7
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/.codex-plugin/plugin.json +1 -1
- package/plugin/.github/plugin/plugin.json +1 -1
- package/plugin/agents/ase-code-analyze.md +262 -0
- package/plugin/meta/ase-dialog.md +10 -171
- package/plugin/package.json +5 -5
- package/plugin/skills/ase-arch-analyze/SKILL.md +5 -4
- package/plugin/skills/ase-arch-discover/SKILL.md +34 -19
- package/plugin/skills/ase-arch-discover/help.md +28 -3
- package/plugin/skills/ase-code-analyze/SKILL.md +58 -217
- package/plugin/skills/ase-code-explain/SKILL.md +5 -5
- package/plugin/skills/ase-code-insight/SKILL.md +5 -5
- package/plugin/skills/ase-code-lint/SKILL.md +30 -13
- package/plugin/skills/ase-code-resolve/SKILL.md +5 -5
- package/plugin/skills/ase-docs-proofread/SKILL.md +28 -14
- package/plugin/skills/ase-meta-chat/SKILL.md +4 -4
- package/plugin/skills/ase-meta-diff/SKILL.md +3 -3
- package/plugin/skills/ase-meta-quorum/SKILL.md +6 -5
- package/plugin/skills/ase-meta-review/SKILL.md +5 -6
- package/plugin/skills/ase-meta-search/SKILL.md +7 -4
- package/dst/ase-hello.js +0 -23
package/dst/ase-service.js
CHANGED
|
@@ -295,6 +295,10 @@ export default class ServiceCommand {
|
|
|
295
295
|
const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: undefined });
|
|
296
296
|
const mcp = buildMcpServer();
|
|
297
297
|
request.raw.res.on("close", () => {
|
|
298
|
+
/* "h.abandon" (see below) bypasses "onPreResponse",
|
|
299
|
+
so undo the "onRequest" accounting here instead */
|
|
300
|
+
inFlight = Math.max(0, inFlight - 1);
|
|
301
|
+
lastActivity = Date.now();
|
|
298
302
|
transport.close().catch(() => { });
|
|
299
303
|
mcp.close().catch(() => { });
|
|
300
304
|
});
|
package/dst/ase-setup.js
CHANGED
|
@@ -163,7 +163,7 @@ export default class SetupCommand {
|
|
|
163
163
|
`installing ASE ${spec.label} plugin (origin: ${dev ? "local" : "remote/bundled"})`);
|
|
164
164
|
const pkgdir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
165
165
|
const source = dev ? path.resolve(pkgdir, "..") : pkgdir;
|
|
166
|
-
const scopeArgs = tool === "claude" ? ["--scope", scope] : [];
|
|
166
|
+
const scopeArgs = tool === "claude" && scope !== "user" ? ["--scope", scope] : [];
|
|
167
167
|
await this.run(spec.cli, ["plugin", "marketplace", "add", source, ...scopeArgs]);
|
|
168
168
|
await this.run(spec.cli, ["plugin", spec.pInstall, "ase@ase", ...scopeArgs], { retries: 3 });
|
|
169
169
|
return 0;
|
|
@@ -174,7 +174,7 @@ export default class SetupCommand {
|
|
|
174
174
|
const spec = toolSpecs[tool];
|
|
175
175
|
await this.ensureTool("npm");
|
|
176
176
|
await this.ensureTool(spec.cli);
|
|
177
|
-
const scopeArgs = tool === "claude" ? ["--scope", scope] : [];
|
|
177
|
+
const scopeArgs = tool === "claude" && scope !== "user" ? ["--scope", scope] : [];
|
|
178
178
|
/* best-effort stop of background service */
|
|
179
179
|
this.log.write("info", `setup: update${dev ? "[dev]" : ""}: ` +
|
|
180
180
|
"stopping potentially running ASE service");
|
|
@@ -230,8 +230,9 @@ export default class SetupCommand {
|
|
|
230
230
|
this.log.write("info", `setup: enable: enabling ASE ${spec.label} plugin`);
|
|
231
231
|
/* the GitHub Copilot CLI and OpenAI Codex CLI have no "plugin
|
|
232
232
|
enable" subcommand, so (re-)install the plugin instead */
|
|
233
|
+
const scopeArgs = scope !== "user" ? ["--scope", scope] : [];
|
|
233
234
|
const args = tool === "claude" ?
|
|
234
|
-
["plugin", "enable", "ase@ase",
|
|
235
|
+
["plugin", "enable", "ase@ase", ...scopeArgs] :
|
|
235
236
|
["plugin", spec.pInstall, "ase@ase"];
|
|
236
237
|
await this.run(spec.cli, args, { retries: tool === "claude" ? 1 : 3 });
|
|
237
238
|
return 0;
|
|
@@ -244,8 +245,9 @@ export default class SetupCommand {
|
|
|
244
245
|
this.log.write("info", `setup: disable: disabling ASE ${spec.label} plugin`);
|
|
245
246
|
/* the GitHub Copilot CLI and OpenAI Codex CLI have no "plugin
|
|
246
247
|
disable" subcommand, so uninstall the plugin instead */
|
|
248
|
+
const scopeArgs = scope !== "user" ? ["--scope", scope] : [];
|
|
247
249
|
const args = tool === "claude" ?
|
|
248
|
-
["plugin", "disable", "ase@ase",
|
|
250
|
+
["plugin", "disable", "ase@ase", ...scopeArgs] :
|
|
249
251
|
["plugin", spec.pRemove, "ase@ase"];
|
|
250
252
|
await this.run(spec.cli, args, { retries: tool === "claude" ? 1 : 3 });
|
|
251
253
|
return 0;
|
|
@@ -256,7 +258,7 @@ export default class SetupCommand {
|
|
|
256
258
|
const spec = toolSpecs[tool];
|
|
257
259
|
await this.ensureTool("npm");
|
|
258
260
|
await this.ensureTool(spec.cli);
|
|
259
|
-
const scopeArgs = tool === "claude" ? ["--scope", scope] : [];
|
|
261
|
+
const scopeArgs = tool === "claude" && scope !== "user" ? ["--scope", scope] : [];
|
|
260
262
|
/* best-effort stop of background service */
|
|
261
263
|
this.log.write("info", `setup: uninstall${dev ? "[dev]" : ""}: ` +
|
|
262
264
|
"stopping potentially running ASE service");
|
|
@@ -376,7 +378,8 @@ export default class SetupCommand {
|
|
|
376
378
|
async mcpAdd(tool, name, env, transport, scope) {
|
|
377
379
|
const args = ["mcp", "add"];
|
|
378
380
|
if (tool === "claude") {
|
|
379
|
-
|
|
381
|
+
if (scope !== "user")
|
|
382
|
+
args.push("--scope", scope);
|
|
380
383
|
args.push("--transport", transport.type);
|
|
381
384
|
if (transport.type === "stdio") {
|
|
382
385
|
for (const [key, val] of Object.entries(env))
|
|
@@ -429,9 +432,8 @@ export default class SetupCommand {
|
|
|
429
432
|
/* unregister an MCP server from the tool; the per-tool command line
|
|
430
433
|
differs between Anthropic Claude Code CLI, GitHub Copilot CLI, and OpenAI Codex CLI */
|
|
431
434
|
async mcpRemove(tool, name, scope) {
|
|
432
|
-
const
|
|
433
|
-
|
|
434
|
-
["mcp", "remove", name];
|
|
435
|
+
const scopeArgs = tool === "claude" && scope !== "user" ? ["--scope", scope] : [];
|
|
436
|
+
const args = ["mcp", "remove", ...scopeArgs, name];
|
|
435
437
|
await this.run(toolSpecs[tool].cli, args, { ignoreError: `MCP server "${name}" not registered` });
|
|
436
438
|
}
|
|
437
439
|
/* build a chat-model MCP handler from the per-model direct and
|
package/dst/ase-skills.js
CHANGED
|
@@ -37,17 +37,19 @@ export class Skills {
|
|
|
37
37
|
const time = pkg.time ?? {};
|
|
38
38
|
const verEntry = version !== "" ? pkg.versions?.[version] : undefined;
|
|
39
39
|
let repository = "";
|
|
40
|
+
let deps = "N.A.";
|
|
40
41
|
if (verEntry !== undefined) {
|
|
41
42
|
const r = verEntry.repository;
|
|
42
43
|
if (typeof r === "string")
|
|
43
44
|
repository = r;
|
|
44
45
|
else if (r !== undefined && typeof r.url === "string")
|
|
45
46
|
repository = r.url;
|
|
47
|
+
deps = Object.keys(verEntry.dependencies ?? {}).length;
|
|
46
48
|
}
|
|
47
|
-
return { version, time, repository };
|
|
49
|
+
return { version, time, repository, deps };
|
|
48
50
|
}
|
|
49
51
|
catch {
|
|
50
|
-
return { version: "", time: {}, repository: "" };
|
|
52
|
+
return { version: "", time: {}, repository: "", deps: "N.A." };
|
|
51
53
|
}
|
|
52
54
|
}
|
|
53
55
|
/* fetch GitHub stars given a repository URL (or empty string) */
|
|
@@ -83,7 +85,7 @@ export class Skills {
|
|
|
83
85
|
static async fetchMavenInfo(coord) {
|
|
84
86
|
const [groupId, artifactId] = coord.split(":", 2);
|
|
85
87
|
if (groupId === undefined || artifactId === undefined || groupId === "" || artifactId === "")
|
|
86
|
-
return { version: "", created: "", updated: "", repository: "" };
|
|
88
|
+
return { version: "", created: "", updated: "", repository: "", deps: "N.A." };
|
|
87
89
|
try {
|
|
88
90
|
const latest = await Skills.httpLimit(() => ofetch("https://search.maven.org/solrsearch/select" +
|
|
89
91
|
`?q=g:%22${encodeURIComponent(groupId)}%22+AND+a:%22${encodeURIComponent(artifactId)}%22` +
|
|
@@ -113,6 +115,7 @@ export class Skills {
|
|
|
113
115
|
}
|
|
114
116
|
const created = typeof firstTs === "number" ? new Date(firstTs).toISOString() : updated;
|
|
115
117
|
let repository = "";
|
|
118
|
+
let deps = "N.A.";
|
|
116
119
|
if (version !== "") {
|
|
117
120
|
try {
|
|
118
121
|
const pom = await Skills.httpLimit(() => ofetch(`https://repo1.maven.org/maven2/${groupId.replace(/\./g, "/")}` +
|
|
@@ -126,16 +129,31 @@ export class Skills {
|
|
|
126
129
|
if (url !== null)
|
|
127
130
|
repository = url[1];
|
|
128
131
|
}
|
|
132
|
+
/* count the `<dependency>` entries of the direct
|
|
133
|
+
`<dependencies>` block, skipping `test`/`provided`
|
|
134
|
+
scopes; a `<dependencyManagement>` block is ignored
|
|
135
|
+
as it only declares versions, not real dependencies */
|
|
136
|
+
const managed = /<dependencyManagement>[\s\S]*?<\/dependencyManagement>/gi;
|
|
137
|
+
const stripped = pom.replace(managed, "");
|
|
138
|
+
const depRe = /<dependency>([\s\S]*?)<\/dependency>/gi;
|
|
139
|
+
let count = 0;
|
|
140
|
+
let dep;
|
|
141
|
+
while ((dep = depRe.exec(stripped)) !== null) {
|
|
142
|
+
const scope = /<scope>\s*([^<\s]+)\s*<\/scope>/i.exec(dep[1]);
|
|
143
|
+
if (scope === null || (scope[1] !== "test" && scope[1] !== "provided"))
|
|
144
|
+
count++;
|
|
145
|
+
}
|
|
146
|
+
deps = count;
|
|
129
147
|
}
|
|
130
148
|
}
|
|
131
149
|
catch {
|
|
132
150
|
repository = "";
|
|
133
151
|
}
|
|
134
152
|
}
|
|
135
|
-
return { version, created, updated, repository };
|
|
153
|
+
return { version, created, updated, repository, deps };
|
|
136
154
|
}
|
|
137
155
|
catch {
|
|
138
|
-
return { version: "", created: "", updated: "", repository: "" };
|
|
156
|
+
return { version: "", created: "", updated: "", repository: "", deps: "N.A." };
|
|
139
157
|
}
|
|
140
158
|
}
|
|
141
159
|
/* fetch the "Used By" count from `mvnrepository.com` as a downloads proxy
|
|
@@ -180,7 +198,7 @@ export class Skills {
|
|
|
180
198
|
- "JavaScript"/"TypeScript": NPM registry (pacote) + GitHub stars + npm-downloads
|
|
181
199
|
- "Java"/"Kotlin": Maven Central + GitHub stars + mvnrepository.com "Used By"
|
|
182
200
|
- "Unknown": not supported -- return empty result */
|
|
183
|
-
static async info(stack, components) {
|
|
201
|
+
static async info(stack, components, staleMonths = 18, smallScope = false) {
|
|
184
202
|
if (stack === "JavaScript" || stack === "TypeScript") {
|
|
185
203
|
/* per package: kick off packument and downloads in parallel,
|
|
186
204
|
then stars as soon as the packument resolves; across packages
|
|
@@ -194,7 +212,7 @@ export class Skills {
|
|
|
194
212
|
]);
|
|
195
213
|
const created = p.time.created ?? "";
|
|
196
214
|
const updated = p.version !== "" ? (p.time[p.version] ?? "") : "";
|
|
197
|
-
const rank = Skills.computeRank(downloads, stars, created, updated);
|
|
215
|
+
const rank = Skills.computeRank(downloads, stars, created, updated, p.deps, staleMonths, smallScope);
|
|
198
216
|
return {
|
|
199
217
|
name,
|
|
200
218
|
version: p.version,
|
|
@@ -203,6 +221,7 @@ export class Skills {
|
|
|
203
221
|
repository: p.repository,
|
|
204
222
|
stars,
|
|
205
223
|
downloads,
|
|
224
|
+
deps: p.deps,
|
|
206
225
|
rank
|
|
207
226
|
};
|
|
208
227
|
}));
|
|
@@ -222,7 +241,7 @@ export class Skills {
|
|
|
222
241
|
const [i, downloads, stars] = await Promise.all([
|
|
223
242
|
infoPromise, downloadsPromise, starsPromise
|
|
224
243
|
]);
|
|
225
|
-
const rank = Skills.computeRank(downloads, stars, i.created, i.updated);
|
|
244
|
+
const rank = Skills.computeRank(downloads, stars, i.created, i.updated, i.deps, staleMonths, smallScope);
|
|
226
245
|
return {
|
|
227
246
|
name,
|
|
228
247
|
version: i.version,
|
|
@@ -231,6 +250,7 @@ export class Skills {
|
|
|
231
250
|
repository: i.repository,
|
|
232
251
|
stars,
|
|
233
252
|
downloads,
|
|
253
|
+
deps: i.deps,
|
|
234
254
|
rank
|
|
235
255
|
};
|
|
236
256
|
}));
|
|
@@ -253,7 +273,7 @@ export class Skills {
|
|
|
253
273
|
is structurally unavailable, e.g. Maven Central exposes no
|
|
254
274
|
per-artifact download counts) is likewise treated as neutral `1`, so
|
|
255
275
|
such stacks can still be ranked by the remaining metrics. */
|
|
256
|
-
static computeRank(downloads, stars, created, updated) {
|
|
276
|
+
static computeRank(downloads, stars, created, updated, deps, staleMonths, smallScope) {
|
|
257
277
|
const d = typeof downloads === "number" ? downloads + 1 : 1;
|
|
258
278
|
const s = typeof stars === "number" ? stars + 1 : 1;
|
|
259
279
|
const cMs = created !== "" ? Date.parse(created) : NaN;
|
|
@@ -277,7 +297,31 @@ export class Skills {
|
|
|
277
297
|
entry rankable without rewarding the missing date. */
|
|
278
298
|
const lifespan = (!Number.isNaN(cMs) && !Number.isNaN(uMs)) ? Math.max(0, uMs - cMs) : 1;
|
|
279
299
|
const recentness = !Number.isNaN(uMs) ? Math.exp(-Math.max(0, (now - uMs) / msPerDay) / halfLife) : 0.5;
|
|
280
|
-
|
|
300
|
+
let rank = d * s * lifespan * recentness;
|
|
301
|
+
/* hard, caller-tunable staleness penalty on top of the soft
|
|
302
|
+
`recentness` decay: unlike the smooth exp-decay above, this is a
|
|
303
|
+
two-tier *cliff* keyed off the `staleMonths` threshold. Past the
|
|
304
|
+
first tier (`staleMonths`) the rank is cut to `0.3x`, past the
|
|
305
|
+
second tier (`2 x staleMonths`, i.e. long abandoned) to `0.1x`.
|
|
306
|
+
A component below the first tier -- or one whose `updated` date
|
|
307
|
+
is unknown -- is left unpenalized. */
|
|
308
|
+
if (!Number.isNaN(uMs)) {
|
|
309
|
+
const ageMonths = (now - uMs) / msPerDay / 30;
|
|
310
|
+
if (ageMonths > 2 * staleMonths)
|
|
311
|
+
rank *= 0.1;
|
|
312
|
+
else if (ageMonths > staleMonths)
|
|
313
|
+
rank *= 0.3;
|
|
314
|
+
}
|
|
315
|
+
/* small-scope dependency-weight penalty: for a narrow, self-
|
|
316
|
+
contained need, dragging in a heavy dependency tree is usually
|
|
317
|
+
the wrong call, so each real component is demoted in proportion
|
|
318
|
+
to its own number of *direct* dependencies (`1 / (1 + deps)`).
|
|
319
|
+
A zero-dep component is left unpenalized; an unknown `deps` count
|
|
320
|
+
(`"N.A."`) is treated neutrally. This only applies when the
|
|
321
|
+
caller flags the need as small-scope. */
|
|
322
|
+
if (smallScope && typeof deps === "number")
|
|
323
|
+
rank *= 1 / (1 + deps);
|
|
324
|
+
return rank;
|
|
281
325
|
}
|
|
282
326
|
/* compute the per-alternative product-sum (rating) row from a
|
|
283
327
|
weighted decision matrix. Each input row has the shape
|
|
@@ -318,20 +362,28 @@ export class SkillsMCP {
|
|
|
318
362
|
"version + earliest/latest release timestamps from the Maven Central Solr " +
|
|
319
363
|
"search endpoint, the SCM/project URL from the latest POM at `repo1.maven.org`, " +
|
|
320
364
|
"GitHub stars (if applicable), and the \"Used By\" count from `mvnrepository.com` " +
|
|
321
|
-
"as the `downloads` proxy.
|
|
322
|
-
"
|
|
323
|
-
"
|
|
324
|
-
"
|
|
325
|
-
"
|
|
365
|
+
"as the `downloads` proxy. The number of *direct* dependencies is read as `deps` " +
|
|
366
|
+
"(from the packument version entry for NPM, or the latest POM's `<dependencies>` " +
|
|
367
|
+
"block for Maven). Returns a JSON `text` array of " +
|
|
368
|
+
"`{ name, version, created, updated, repository, stars, downloads, deps, rank }` " +
|
|
369
|
+
"objects, sorted in descending order by `rank`. The `rank` applies a two-tier hard " +
|
|
370
|
+
"staleness penalty keyed off `staleMonths` (0.3x past the threshold, 0.1x past twice " +
|
|
371
|
+
"it) and, when `smallScope` is set, a dependency-weight penalty of `1/(1+deps)` so " +
|
|
372
|
+
"dependency-heavy components sink. Failures of individual side calls are isolated " +
|
|
373
|
+
"and reported as `\"N.A.\"` or empty string so every entry has the full shape.",
|
|
326
374
|
inputSchema: {
|
|
327
375
|
stack: z.string()
|
|
328
376
|
.describe("Technology stack: \"JavaScript\", \"TypeScript\", \"Java\", \"Kotlin\", or \"Unknown\""),
|
|
329
377
|
components: z.array(z.string())
|
|
330
|
-
.describe("List of package names (NPM) or Maven coordinates `groupId:artifactId` (Java/Kotlin)")
|
|
378
|
+
.describe("List of package names (NPM) or Maven coordinates `groupId:artifactId` (Java/Kotlin)"),
|
|
379
|
+
staleMonths: z.number().optional()
|
|
380
|
+
.describe("Staleness threshold in months (default 18); a release older than this is rank-penalized"),
|
|
381
|
+
smallScope: z.boolean().optional()
|
|
382
|
+
.describe("If true, penalize each component by its direct-dependency count (small-scope need)")
|
|
331
383
|
}
|
|
332
384
|
}, async (args) => {
|
|
333
385
|
try {
|
|
334
|
-
const result = await Skills.info(args.stack, args.components);
|
|
386
|
+
const result = await Skills.info(args.stack, args.components, args.staleMonths, args.smallScope);
|
|
335
387
|
return {
|
|
336
388
|
content: [{ type: "text", text: JSON.stringify(result) }]
|
|
337
389
|
};
|
package/package.json
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
"homepage": "http://github.com/rse/ase",
|
|
7
7
|
"repository": { "url": "git+https://github.com/rse/ase.git", "type": "git" },
|
|
8
8
|
"bugs": { "url": "http://github.com/rse/ase/issues" },
|
|
9
|
-
"version": "0.9.
|
|
9
|
+
"version": "0.9.36",
|
|
10
10
|
"license": "Apache-2.0",
|
|
11
11
|
"author": {
|
|
12
12
|
"name": "Dr. Ralf S. Engelschall",
|
|
@@ -18,8 +18,8 @@
|
|
|
18
18
|
"devDependencies": {
|
|
19
19
|
"eslint": "9.39.4",
|
|
20
20
|
"@eslint/js": "9.39.4",
|
|
21
|
-
"@typescript-eslint/parser": "8.62.
|
|
22
|
-
"@typescript-eslint/eslint-plugin": "8.62.
|
|
21
|
+
"@typescript-eslint/parser": "8.62.1",
|
|
22
|
+
"@typescript-eslint/eslint-plugin": "8.62.1",
|
|
23
23
|
"eslint-plugin-promise": "7.3.0",
|
|
24
24
|
"eslint-plugin-import": "2.32.0",
|
|
25
25
|
"neostandard": "0.13.0",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"nodemon": "3.1.14",
|
|
31
31
|
"shx": "0.4.0",
|
|
32
32
|
|
|
33
|
-
"@types/node": "26.0
|
|
33
|
+
"@types/node": "26.1.0",
|
|
34
34
|
"@types/luxon": "3.7.2",
|
|
35
35
|
"@types/which": "3.0.4",
|
|
36
36
|
"@types/update-notifier": "6.0.8",
|
|
@@ -42,9 +42,9 @@
|
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
44
|
"commander": "15.0.0",
|
|
45
|
-
"@dotenvx/dotenvx": "1.
|
|
45
|
+
"@dotenvx/dotenvx": "2.1.4",
|
|
46
46
|
"yaml": "2.9.0",
|
|
47
|
-
"valibot": "1.4.
|
|
47
|
+
"valibot": "1.4.2",
|
|
48
48
|
"execa": "9.6.1",
|
|
49
49
|
"mkdirp": "3.0.1",
|
|
50
50
|
"@hapi/hapi": "21.4.9",
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
"write-file-atomic": "8.0.0",
|
|
64
64
|
"pacote": "22.0.0",
|
|
65
65
|
"ofetch": "1.5.1",
|
|
66
|
-
"picomatch": "4.0.
|
|
66
|
+
"picomatch": "4.0.5"
|
|
67
67
|
},
|
|
68
68
|
"engines": {
|
|
69
69
|
"npm": ">=10.0.0",
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ase-code-analyze
|
|
3
|
+
description: "Analysis Investigation"
|
|
4
|
+
effort: high
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
Your role is an experienced, *expert-level software developer*.
|
|
8
|
+
|
|
9
|
+
Your objective is to *analyze* source code for *problems* under a
|
|
10
|
+
single *analysis lens* - read-only, *without* applying any changes.
|
|
11
|
+
|
|
12
|
+
Workflow
|
|
13
|
+
--------
|
|
14
|
+
|
|
15
|
+
1. Set the requested context: <context>$ARGUMENTS</context>.
|
|
16
|
+
The *first* whitespace-separated token of <context/> is the
|
|
17
|
+
*analysis lens* <lens/> (one of `logic`, `performance`, or
|
|
18
|
+
`security`). The *remaining* tokens are the source code files
|
|
19
|
+
to analyze.
|
|
20
|
+
|
|
21
|
+
2. Use the `Read` tool to read all source code files referenced by
|
|
22
|
+
<context/>, plus all *related* source code files needed to really
|
|
23
|
+
comprehend the context.
|
|
24
|
+
|
|
25
|
+
3. *Determine* the *target programming language* and apply all
|
|
26
|
+
subsequent checks according to its *idiomatic conventions* and *best
|
|
27
|
+
practices*.
|
|
28
|
+
|
|
29
|
+
4. Set <problems/> to empty.
|
|
30
|
+
Then check the read source code for problems under the analysis
|
|
31
|
+
lens <lens/>:
|
|
32
|
+
|
|
33
|
+
- If <lens/> is `logic`:
|
|
34
|
+
|
|
35
|
+
Focus on problems in the *logic* and *semantics* and the related
|
|
36
|
+
*control flow* only - and do *not* investigate performance,
|
|
37
|
+
efficiency, or security problems.
|
|
38
|
+
|
|
39
|
+
Analysis Hints (not exhaustive, just indicators):
|
|
40
|
+
- incorrect conditionals and boolean logic
|
|
41
|
+
- off-by-one and boundary errors
|
|
42
|
+
- operator misuse
|
|
43
|
+
- mishandled edge cases
|
|
44
|
+
- broken or missing error handling
|
|
45
|
+
- incorrect async/await/promise handling
|
|
46
|
+
- control-flow defects (unreachable code, missing breaks, wrong early returns)
|
|
47
|
+
- state-mutation bugs
|
|
48
|
+
- incorrect default values
|
|
49
|
+
- null/undefined mishandling
|
|
50
|
+
- type-coercion bugs
|
|
51
|
+
- faulty parsing or merge/override semantics
|
|
52
|
+
- race conditions and unsynchronized shared state
|
|
53
|
+
- resource leaks (unclosed files, handles, connections)
|
|
54
|
+
- inverted or swapped function arguments
|
|
55
|
+
- incorrect loop termination or accumulator initialization
|
|
56
|
+
- shadowed or reassigned variables changing intent
|
|
57
|
+
- incomplete switch/case or enum coverage
|
|
58
|
+
- silent exception swallowing
|
|
59
|
+
- floating-point comparison and rounding errors
|
|
60
|
+
- integer overflow/underflow or truncating division
|
|
61
|
+
- sign and modulo errors with negative operands
|
|
62
|
+
- reference vs. value semantics (aliasing, shared mutable defaults)
|
|
63
|
+
- incorrect short-circuit evaluation or operator precedence
|
|
64
|
+
- logical vs. bitwise operator confusion
|
|
65
|
+
- negation mistakes in compound predicates
|
|
66
|
+
- wrong comparison operator (`==` instead of `===`, `<` vs. `<=`, etc)
|
|
67
|
+
- inverted condition or swapped if/else branches
|
|
68
|
+
- dead or duplicated conditional branches
|
|
69
|
+
- fall-through where a break or return was intended
|
|
70
|
+
- missing or misplaced base case in recursion (non-termination)
|
|
71
|
+
- mutation of a collection while iterating over it
|
|
72
|
+
- incorrect index, key, or bounds when accessing collections
|
|
73
|
+
- empty-collection or single-element edge cases unhandled
|
|
74
|
+
- wrong order of operations in initialization or teardown
|
|
75
|
+
- missing cleanup on early return, break, or exception path
|
|
76
|
+
- double-free, use-after-free, or double-close of resources
|
|
77
|
+
- incorrect time-zone, date arithmetic, or unit conversions
|
|
78
|
+
- stale cache or memoization not invalidated on change
|
|
79
|
+
- incorrect deep vs. shallow copy semantics
|
|
80
|
+
- partial or non-atomic updates leaving inconsistent state
|
|
81
|
+
- ignored or unchecked return values and status codes
|
|
82
|
+
- error code vs. exception path mismatch
|
|
83
|
+
- catching too broad an exception masking real failures
|
|
84
|
+
- re-throwing without preserving the original cause
|
|
85
|
+
- incorrect equality, hashing, or ordering for custom types
|
|
86
|
+
- regex anchoring, greediness, or escaping mistakes
|
|
87
|
+
- string encoding, normalization, or case-folding errors
|
|
88
|
+
- missing `await` causing unhandled or dropped promises
|
|
89
|
+
- incorrect promise concurrency (`all` vs. `allSettled`, races)
|
|
90
|
+
- callback invoked zero times, twice, or out of order
|
|
91
|
+
- unguarded re-entrancy or recursive lock acquisition
|
|
92
|
+
- incorrect guard ordering allowing invalid states through
|
|
93
|
+
- assumptions about iteration order of maps/sets/objects
|
|
94
|
+
- [...]
|
|
95
|
+
|
|
96
|
+
- If <lens/> is `performance`:
|
|
97
|
+
|
|
98
|
+
Focus on *performance* and *efficiency* only - and do *not*
|
|
99
|
+
investigate logic, semantics, control flow, or security
|
|
100
|
+
problems.
|
|
101
|
+
|
|
102
|
+
Analysis Hints (not exhaustive, just indicators):
|
|
103
|
+
- high algorithmic complexity
|
|
104
|
+
- needless resource allocations/copies
|
|
105
|
+
- redundant recomputation
|
|
106
|
+
- many I/O and query round-trips
|
|
107
|
+
- concurrency bottlenecks
|
|
108
|
+
- mismatched data structures
|
|
109
|
+
- N+1 query patterns (1 parent query, N child queries)
|
|
110
|
+
- missing caching/memoization of stable results
|
|
111
|
+
- blocking/synchronous calls on hot paths
|
|
112
|
+
- unbounded growth (memory leaks, ever-growing collections)
|
|
113
|
+
- inefficient string building/concatenation in loops
|
|
114
|
+
- premature or repeated serialization/parsing
|
|
115
|
+
- lack of batching/pagination for bulk operations
|
|
116
|
+
- excessive logging or instrumentation overhead
|
|
117
|
+
- chatty network protocols (no connection pooling/keep-alive)
|
|
118
|
+
- lock contention and overly coarse-grained locking
|
|
119
|
+
- eager/over-fetching of data that is never used
|
|
120
|
+
- missing database indexes
|
|
121
|
+
- repeated regex (re)compilation in hot paths
|
|
122
|
+
- busy-waiting/polling instead of event-driven waits
|
|
123
|
+
- transferring uncompressed or overly verbose payloads
|
|
124
|
+
- missing short-circuit evaluation in expensive conditions
|
|
125
|
+
- recomputing invariants inside loops (loop-invariant code)
|
|
126
|
+
- suboptimal batch sizes (too small = overhead, too large = latency)
|
|
127
|
+
- inefficient algorithms for sorting/searching already-ordered data
|
|
128
|
+
- redundant validation/sanitization of trusted internal data
|
|
129
|
+
- missing connection/resource reuse (open-close per operation)
|
|
130
|
+
- [...]
|
|
131
|
+
|
|
132
|
+
- If <lens/> is `security`:
|
|
133
|
+
|
|
134
|
+
Focus on *security* only - and do *not* investigate logic,
|
|
135
|
+
semantics, performance, or efficiency problems.
|
|
136
|
+
|
|
137
|
+
Analysis Hints (not exhaustive, just indicators):
|
|
138
|
+
- unsafe data deserialization
|
|
139
|
+
- missing input data validation/sanitization
|
|
140
|
+
- broken authentication/authorization
|
|
141
|
+
- sensitive-data exposure
|
|
142
|
+
- path traversal
|
|
143
|
+
- unsafe cryptography
|
|
144
|
+
- hard-coded secrets
|
|
145
|
+
- vulnerable dependencies
|
|
146
|
+
- injection flaws
|
|
147
|
+
- cross-site scripting (XSS) and output-encoding gaps
|
|
148
|
+
- cross-site request forgery (CSRF) and missing anti-forgery tokens
|
|
149
|
+
- insecure direct object references (IDOR)
|
|
150
|
+
- server-side request forgery (SSRF)
|
|
151
|
+
- insecure or missing transport encryption (TLS)
|
|
152
|
+
- weak session management (fixation, predictable tokens)
|
|
153
|
+
- missing rate limiting/anti-automation controls
|
|
154
|
+
- overly permissive CORS or file permissions
|
|
155
|
+
- verbose error messages leaking internals
|
|
156
|
+
- unsafe randomness for security-sensitive values
|
|
157
|
+
- mass assignment / over-binding of request parameters
|
|
158
|
+
- security misconfiguration (default credentials, debug modes, exposed admin endpoints)
|
|
159
|
+
- missing or misconfigured security headers (CSP, HSTS, X-Frame-Options)
|
|
160
|
+
- improper certificate/hostname validation (TLS verification disabled)
|
|
161
|
+
- insufficient logging and monitoring of security events
|
|
162
|
+
- race conditions / TOCTOU (time-of-check to time-of-use) flaws
|
|
163
|
+
- integer overflow/underflow and buffer overflows
|
|
164
|
+
- use-after-free and memory-safety violations
|
|
165
|
+
- privilege escalation through improper privilege dropping
|
|
166
|
+
- insecure file upload handling (unrestricted type/size, executable storage)
|
|
167
|
+
- unsafe handling of untrusted regular expressions (ReDoS)
|
|
168
|
+
- caching of sensitive data in shared or client-side caches
|
|
169
|
+
- secrets or sensitive data leaking into logs, traces, or telemetry
|
|
170
|
+
- insecure default-deny failures (fail-open instead of fail-closed)
|
|
171
|
+
- missing integrity verification (unsigned updates, no subresource integrity)
|
|
172
|
+
- excessive data exposure in API responses (returning more fields than needed)
|
|
173
|
+
- improper resource cleanup leading to exhaustion (connection/file-descriptor leaks)
|
|
174
|
+
- business-logic flaws (bypassable workflows, negative quantities, replay)
|
|
175
|
+
- [...]
|
|
176
|
+
|
|
177
|
+
Be practically relevant - focus on *practically relevant* cases
|
|
178
|
+
only and especially do *not* investigate theoretical or fictive
|
|
179
|
+
cases.
|
|
180
|
+
|
|
181
|
+
Be problem-focused - report the *problem only* and do *not*
|
|
182
|
+
already investigate any possible *solution* or apply any *change*.
|
|
183
|
+
|
|
184
|
+
Be conservative - only report clear, well-grounded problems.
|
|
185
|
+
Think twice to avoid *false positives*.
|
|
186
|
+
|
|
187
|
+
Be focused - only report problems which were found in the source
|
|
188
|
+
files referenced by <context/>. Ignore problems which are located
|
|
189
|
+
in related source files which were just read to better comprehend
|
|
190
|
+
the <context/>.
|
|
191
|
+
|
|
192
|
+
For *each* found problem:
|
|
193
|
+
|
|
194
|
+
1. Set <file/> to the *relative* filename path of the source file
|
|
195
|
+
in which the problem is located.
|
|
196
|
+
|
|
197
|
+
2. Set <line/> to the numeric 1-based line number in <file/> which
|
|
198
|
+
is most relevant to the problem.
|
|
199
|
+
|
|
200
|
+
3. Set <severity/> to the string `LOW`, `MEDIUM`, `HIGH`, or
|
|
201
|
+
`ACCEPTED`, ranked by the estimated *impact* of the problem.
|
|
202
|
+
Use `ACCEPTED` when the problem is a deliberate, justified
|
|
203
|
+
trade-off that should remain on record.
|
|
204
|
+
|
|
205
|
+
4. Set <description/> to an *ultra brief* but still as *precise*
|
|
206
|
+
as possible Markdown-formatted problem description. In it,
|
|
207
|
+
highlight *code* as <template>`<code/>`</template> and *key
|
|
208
|
+
aspects* as <template>*<aspect/>*</template>, and add inline
|
|
209
|
+
*references* to the related code positions in the form of either
|
|
210
|
+
<template>(`<filename/>:<line-number/>`)</template>,
|
|
211
|
+
<template>(`<filename/>:<line-number/>-<line-number/>`)</template> or
|
|
212
|
+
<template>(`<filename/>#<function-or-method/>`)</template>.
|
|
213
|
+
|
|
214
|
+
5. Set <title/> to an ultra-compressed <description/>: a concise,
|
|
215
|
+
short, single sentence. Keep one inline reference to the code
|
|
216
|
+
position which is most relevant to the problem.
|
|
217
|
+
|
|
218
|
+
6. If <lens/> is `performance`:
|
|
219
|
+
|
|
220
|
+
Set <evidence/> to ground the finding by citing either the
|
|
221
|
+
inferred *Big-O* time/space complexity (e.g. `O(n²)` reducible
|
|
222
|
+
to `O(n)`) with the exact driving loop or recursion, or the
|
|
223
|
+
matched performance *anti-pattern* (e.g. N+1 query,
|
|
224
|
+
sync-in-loop, repeated recompute, string concat in loop), with
|
|
225
|
+
an inline code reference.
|
|
226
|
+
|
|
227
|
+
Set <trade-off/> to state the *cost* of the optimization (e.g.
|
|
228
|
+
readability, additional memory for speed, added complexity), so
|
|
229
|
+
the user can make an informed decision; use *none* if there is
|
|
230
|
+
no meaningful trade-off.
|
|
231
|
+
|
|
232
|
+
Otherwise (for the other lenses), set both <evidence/> and
|
|
233
|
+
<trade-off/> to empty strings.
|
|
234
|
+
|
|
235
|
+
7. If <problems/> is not empty, set
|
|
236
|
+
<problems><problems/>,</problems> (append a comma).
|
|
237
|
+
Then append the following <template/> to <problems/>:
|
|
238
|
+
|
|
239
|
+
<template>
|
|
240
|
+
{
|
|
241
|
+
"file": <file/>,
|
|
242
|
+
"line": <line/>,
|
|
243
|
+
"severity": <severity/>,
|
|
244
|
+
"title": <title/>,
|
|
245
|
+
"description": <description/>,
|
|
246
|
+
"evidence": <evidence/>,
|
|
247
|
+
"trade-off": <trade-off/>
|
|
248
|
+
}
|
|
249
|
+
</template>
|
|
250
|
+
|
|
251
|
+
5. Return *exclusively* a single fenced JSON block (no prose,
|
|
252
|
+
no preamble, no summary) of the following shape:
|
|
253
|
+
|
|
254
|
+
```json
|
|
255
|
+
[
|
|
256
|
+
<problems/>
|
|
257
|
+
]
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
6. You *MUST* *NOT* propose, apply, or render any code
|
|
261
|
+
changes yourself.
|
|
262
|
+
|