@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.
@@ -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", "--scope", scope] :
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", "--scope", scope] :
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
- args.push("--scope", scope);
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 args = tool === "claude" ?
433
- ["mcp", "remove", "--scope", scope, name] :
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
- return d * s * lifespan * recentness;
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. Returns a JSON `text` array of " +
322
- "`{ name, version, created, updated, repository, stars, downloads, rank }` " +
323
- "objects, sorted in descending order by `rank`. Failures of individual side " +
324
- "calls are isolated and reported as `\"N.A.\"` or empty string so every entry " +
325
- "has the full shape.",
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.34",
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.0",
22
- "@typescript-eslint/eslint-plugin": "8.62.0",
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.1",
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.75.1",
45
+ "@dotenvx/dotenvx": "2.1.4",
46
46
  "yaml": "2.9.0",
47
- "valibot": "1.4.1",
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.4"
66
+ "picomatch": "4.0.5"
67
67
  },
68
68
  "engines": {
69
69
  "npm": ">=10.0.0",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ase",
3
- "version": "0.9.34",
3
+ "version": "0.9.36",
4
4
  "description": "Agentic Software Engineering (ASE)",
5
5
  "keywords": [ "agentic", "software", "engineering" ],
6
6
  "homepage": "https://ase.tools",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ase",
3
- "version": "0.9.34",
3
+ "version": "0.9.36",
4
4
  "description": "Agentic Software Engineering (ASE)",
5
5
  "keywords": [ "agentic", "software", "engineering" ],
6
6
  "homepage": "https://ase.tools",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ase",
3
- "version": "0.9.34",
3
+ "version": "0.9.36",
4
4
  "description": "Agentic Software Engineering (ASE)",
5
5
  "keywords": [ "agentic", "software", "engineering" ],
6
6
  "homepage": "https://ase.tools",
@@ -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
+