agentsys 5.8.5 → 5.8.6
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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +13 -0
- package/lib/binary/version.js +1 -1
- package/lib/index.js +2 -0
- package/lib/package.json +2 -0
- package/lib/repo-intel/index.js +21 -0
- package/lib/repo-intel/queries.js +451 -0
- package/package.json +1 -1
- package/site/content.json +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agentsys",
|
|
3
3
|
"description": "19 specialized plugins for AI workflow automation - task orchestration, PR workflow, slop detection, code review, drift detection, enhancement analysis, documentation sync, unified static analysis, perf investigations, topic research, agent config linting, cross-tool AI consultation, structured AI debate, workflow pattern learning, codebase onboarding, and contributor guidance",
|
|
4
|
-
"version": "5.8.
|
|
4
|
+
"version": "5.8.6",
|
|
5
5
|
"owner": {
|
|
6
6
|
"name": "Avi Fenesh",
|
|
7
7
|
"url": "https://github.com/avifenesh"
|
package/CHANGELOG.md
CHANGED
|
@@ -9,6 +9,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
9
9
|
|
|
10
10
|
## [Unreleased]
|
|
11
11
|
|
|
12
|
+
## [5.8.6] - 2026-04-23
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
- **`@agentsys/lib`'s `repoIntel.queries` module** - typed wrappers over every `agent-analyzer repo-intel query <type>` subcommand (28 functions). Consumer plugins can now call `require('@agentsys/lib').repoIntel.queries.hotspots(cwd, { limit: 20 })` instead of constructing raw CLI argv themselves. Functions returned in JSON match the binary's output shape per query.
|
|
16
|
+
- **4 new graph-derived query wrappers** for the analyzer-graph crate landed in agent-analyzer v0.4.0:
|
|
17
|
+
- `communities(cwd)` - lists Louvain-discovered file clusters (the natural feature areas, independent of directory layout)
|
|
18
|
+
- `boundaries(cwd, { limit })` - files bridging multiple communities by betweenness centrality (architectural seams - highest-leverage files for refactoring)
|
|
19
|
+
- `areaOf(cwd, file)` - which community a file belongs to
|
|
20
|
+
- `communityHealth(cwd, id)` - composite per-community roll-up (size, total/recent changes, bug-fix rate, AI ratio, stale-owner count)
|
|
21
|
+
|
|
22
|
+
### Changed
|
|
23
|
+
- **`ANALYZER_MIN_VERSION` bumped 0.3.0 -> 0.4.0** to match agent-analyzer v0.4.0 which adds the graph subcommands. Older binaries get auto-upgraded on first call by `lib/binary.ensureBinary()`.
|
|
24
|
+
|
|
12
25
|
## [5.8.5] - 2026-04-23
|
|
13
26
|
|
|
14
27
|
### Fixed
|
package/lib/binary/version.js
CHANGED
package/lib/index.js
CHANGED
|
@@ -30,6 +30,7 @@ const perf = require('./perf');
|
|
|
30
30
|
const collectors = require('./collectors');
|
|
31
31
|
const discoveryModule = require('./discovery');
|
|
32
32
|
const binary = require('./binary');
|
|
33
|
+
const repoIntel = require('./repo-intel');
|
|
33
34
|
|
|
34
35
|
/**
|
|
35
36
|
* Platform detection and verification utilities
|
|
@@ -255,6 +256,7 @@ module.exports = {
|
|
|
255
256
|
collectors,
|
|
256
257
|
discovery,
|
|
257
258
|
binary,
|
|
259
|
+
repoIntel,
|
|
258
260
|
|
|
259
261
|
// Direct module access for backward compatibility
|
|
260
262
|
detectPlatform,
|
package/lib/package.json
CHANGED
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
"./discovery": "./discovery/index.js",
|
|
14
14
|
"./enhance": "./enhance/index.js",
|
|
15
15
|
"./perf": "./perf/index.js",
|
|
16
|
+
"./repo-intel": "./repo-intel/index.js",
|
|
17
|
+
"./repo-intel/queries": "./repo-intel/queries.js",
|
|
16
18
|
"./repo-map": "./repo-map/index.js",
|
|
17
19
|
"./collectors/codebase": "./collectors/codebase.js",
|
|
18
20
|
"./collectors/docs-patterns": "./collectors/docs-patterns.js",
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Repo intel module - typed wrappers over agent-analyzer's repo-intel
|
|
3
|
+
* subcommands. Consumers can import via:
|
|
4
|
+
*
|
|
5
|
+
* const { repoIntel } = require('@agentsys/lib');
|
|
6
|
+
* const hot = repoIntel.queries.hotspots(cwd, { limit: 20 });
|
|
7
|
+
* const communities = repoIntel.queries.communities(cwd);
|
|
8
|
+
*
|
|
9
|
+
* The Rust binary is downloaded lazily on first call by lib/binary; this
|
|
10
|
+
* module just constructs the right argv and parses the JSON output.
|
|
11
|
+
*
|
|
12
|
+
* @module lib/repo-intel
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
'use strict';
|
|
16
|
+
|
|
17
|
+
const queries = require('./queries');
|
|
18
|
+
|
|
19
|
+
module.exports = {
|
|
20
|
+
queries,
|
|
21
|
+
};
|
|
@@ -0,0 +1,451 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Repo intel query functions
|
|
3
|
+
*
|
|
4
|
+
* Typed wrappers over `agent-analyzer repo-intel query <type>` subcommands.
|
|
5
|
+
* Consumer plugins can call these instead of constructing CLI args by hand:
|
|
6
|
+
*
|
|
7
|
+
* const { repoIntel } = require('@agentsys/lib');
|
|
8
|
+
* const hot = repoIntel.queries.hotspots(cwd, { limit: 20 });
|
|
9
|
+
*
|
|
10
|
+
* Each function resolves the cached `repo-intel.json` via the platform
|
|
11
|
+
* state-dir helper and shells out to the binary downloaded by lib/binary.
|
|
12
|
+
*
|
|
13
|
+
* @module lib/repo-intel/queries
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
'use strict';
|
|
17
|
+
|
|
18
|
+
const fs = require('fs');
|
|
19
|
+
const path = require('path');
|
|
20
|
+
const binary = require('../binary');
|
|
21
|
+
const { getStateDirPath } = require('../platform/state-dir');
|
|
22
|
+
|
|
23
|
+
const MAP_FILENAME = 'repo-intel.json';
|
|
24
|
+
|
|
25
|
+
// Conservative bound on a single CLI argument length. Windows cmd-line max
|
|
26
|
+
// is ~32 KB total; modern Linux/macOS typically allow ~128 KB. We throw an
|
|
27
|
+
// actionable error rather than letting `execFileSync` fail with a cryptic
|
|
28
|
+
// E2BIG/ENAMETOOLONG, which would otherwise look like a binary crash to
|
|
29
|
+
// the caller.
|
|
30
|
+
const MAX_FILES_ARG_LEN = 30000;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Absolute path to the cached repo-intel artifact for `basePath`.
|
|
34
|
+
*
|
|
35
|
+
* @param {string} basePath
|
|
36
|
+
* @returns {string}
|
|
37
|
+
*/
|
|
38
|
+
function mapFilePath(basePath) {
|
|
39
|
+
return path.join(getStateDirPath(basePath), MAP_FILENAME);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Error thrown when the cached repo-intel artifact is missing.
|
|
44
|
+
* Distinguished by a `.code = 'REPO_INTEL_MISSING'` field so callers can
|
|
45
|
+
* choose between auto-init, fallback, or surfacing the message.
|
|
46
|
+
*/
|
|
47
|
+
class RepoIntelMissingError extends Error {
|
|
48
|
+
constructor(mapFile) {
|
|
49
|
+
super(
|
|
50
|
+
`repo-intel artifact not found at ${mapFile}. Run ` +
|
|
51
|
+
'`agent-analyzer repo-intel init <path>` (or `/repo-intel init` ' +
|
|
52
|
+
'in a CC plugin) first to create it.'
|
|
53
|
+
);
|
|
54
|
+
this.name = 'RepoIntelMissingError';
|
|
55
|
+
this.code = 'REPO_INTEL_MISSING';
|
|
56
|
+
this.mapFile = mapFile;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Run a binary query and return the parsed JSON result.
|
|
62
|
+
*
|
|
63
|
+
* @param {string} basePath - Repository root
|
|
64
|
+
* @param {string[]} queryArgs - Arguments after `repo-intel query`
|
|
65
|
+
* @returns {Object|Array} Parsed query result
|
|
66
|
+
* @throws {RepoIntelMissingError} If the cached artifact is missing.
|
|
67
|
+
* @throws {Error} If the binary fails or returns non-JSON output (with
|
|
68
|
+
* the failing query and an output preview included in the message).
|
|
69
|
+
*/
|
|
70
|
+
function runQuery(basePath, queryArgs) {
|
|
71
|
+
const mapFile = mapFilePath(basePath);
|
|
72
|
+
|
|
73
|
+
// Surface a clear "run init first" message instead of letting the binary
|
|
74
|
+
// exit non-zero with a low-level "no such file" error that would bubble
|
|
75
|
+
// up unannotated through `binary.runAnalyzer`.
|
|
76
|
+
if (!fs.existsSync(mapFile)) {
|
|
77
|
+
throw new RepoIntelMissingError(mapFile);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const args = ['repo-intel', 'query', ...queryArgs, '--map-file', mapFile, basePath];
|
|
81
|
+
|
|
82
|
+
let output;
|
|
83
|
+
try {
|
|
84
|
+
output = binary.runAnalyzer(args);
|
|
85
|
+
} catch (err) {
|
|
86
|
+
// Wrap so the caller learns which query failed without having to dig
|
|
87
|
+
// through the CLI argv. The original error stays as `cause`.
|
|
88
|
+
const wrapped = new Error(
|
|
89
|
+
`repo-intel query failed (${queryArgs.join(' ')}): ${err.message}`
|
|
90
|
+
);
|
|
91
|
+
wrapped.cause = err;
|
|
92
|
+
throw wrapped;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
try {
|
|
96
|
+
return JSON.parse(output);
|
|
97
|
+
} catch (err) {
|
|
98
|
+
const preview = output && output.length > 0 ? output.slice(0, 200) : '<empty>';
|
|
99
|
+
const wrapped = new Error(
|
|
100
|
+
`repo-intel query returned non-JSON output (${queryArgs.join(' ')}): ${preview}`
|
|
101
|
+
);
|
|
102
|
+
wrapped.cause = err;
|
|
103
|
+
throw wrapped;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// ─── Activity ───────────────────────────────────────────────────────────────
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Return files sorted by recency-weighted change score.
|
|
111
|
+
*
|
|
112
|
+
* @param {string} basePath
|
|
113
|
+
* @param {Object} [options={}]
|
|
114
|
+
* @param {number} [options.limit] - Maximum number of results
|
|
115
|
+
*/
|
|
116
|
+
function hotspots(basePath, options = {}) {
|
|
117
|
+
const args = ['hotspots'];
|
|
118
|
+
if (options.limit) args.push('--top', String(options.limit));
|
|
119
|
+
return runQuery(basePath, args);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Return least-changed files (no recent activity).
|
|
124
|
+
*/
|
|
125
|
+
function coldspots(basePath, options = {}) {
|
|
126
|
+
const args = ['coldspots'];
|
|
127
|
+
if (options.limit) args.push('--top', String(options.limit));
|
|
128
|
+
return runQuery(basePath, args);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Return change history for a specific file.
|
|
133
|
+
*/
|
|
134
|
+
function fileHistory(basePath, file) {
|
|
135
|
+
return runQuery(basePath, ['file-history', file]);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// ─── Quality ────────────────────────────────────────────────────────────────
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Return files with highest bug-fix density.
|
|
142
|
+
*/
|
|
143
|
+
function bugspots(basePath, options = {}) {
|
|
144
|
+
const args = ['bugspots'];
|
|
145
|
+
if (options.limit) args.push('--top', String(options.limit));
|
|
146
|
+
return runQuery(basePath, args);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Return hot source files with no co-changing test file.
|
|
151
|
+
*/
|
|
152
|
+
function testGaps(basePath, options = {}) {
|
|
153
|
+
const args = ['test-gaps'];
|
|
154
|
+
if (options.limit) args.push('--top', String(options.limit));
|
|
155
|
+
if (options.minChanges) args.push('--min-changes', String(options.minChanges));
|
|
156
|
+
return runQuery(basePath, args);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Score changed files by composite risk.
|
|
161
|
+
*
|
|
162
|
+
* Validates the joined file argument fits within the platform's argv length
|
|
163
|
+
* cap before shelling out (Windows is the tight constraint at ~32 KB).
|
|
164
|
+
* Callers with very large diffs should batch.
|
|
165
|
+
*
|
|
166
|
+
* @param {string} basePath
|
|
167
|
+
* @param {string[]} files - List of changed file paths
|
|
168
|
+
* @throws {TypeError} If `files` is not an array of strings.
|
|
169
|
+
* @throws {RangeError} If the joined argument exceeds {@link MAX_FILES_ARG_LEN}.
|
|
170
|
+
*/
|
|
171
|
+
function diffRisk(basePath, files) {
|
|
172
|
+
if (!Array.isArray(files) || !files.every((f) => typeof f === 'string')) {
|
|
173
|
+
throw new TypeError('diffRisk: `files` must be an array of strings');
|
|
174
|
+
}
|
|
175
|
+
const joined = files.join(',');
|
|
176
|
+
if (joined.length > MAX_FILES_ARG_LEN) {
|
|
177
|
+
throw new RangeError(
|
|
178
|
+
`diffRisk: joined file argument is ${joined.length} chars, ` +
|
|
179
|
+
`exceeds platform-safe limit of ${MAX_FILES_ARG_LEN}. ` +
|
|
180
|
+
`Split the request into batches (~500 paths each is typically safe).`
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
return runQuery(basePath, ['diff-risk', '--files', joined]);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Files ranked by hotspot × (1 + bug_rate) × (1 + complexity/30). Requires
|
|
188
|
+
* Phase 2 AST data; falls back to git-only when unavailable.
|
|
189
|
+
*/
|
|
190
|
+
function painspots(basePath, options = {}) {
|
|
191
|
+
const args = ['painspots'];
|
|
192
|
+
if (options.limit) args.push('--top', String(options.limit));
|
|
193
|
+
return runQuery(basePath, args);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// ─── People ─────────────────────────────────────────────────────────────────
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Return ownership breakdown for a file or directory.
|
|
200
|
+
*/
|
|
201
|
+
function ownership(basePath, file) {
|
|
202
|
+
return runQuery(basePath, ['ownership', file]);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Return contributors sorted by commit count.
|
|
207
|
+
*/
|
|
208
|
+
function contributors(basePath, options = {}) {
|
|
209
|
+
const args = ['contributors'];
|
|
210
|
+
if (options.limit) args.push('--top', String(options.limit));
|
|
211
|
+
return runQuery(basePath, args);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Detailed bus factor with critical owners and at-risk areas.
|
|
216
|
+
*/
|
|
217
|
+
function busFactor(basePath, options = {}) {
|
|
218
|
+
const args = ['bus-factor'];
|
|
219
|
+
if (options.adjustForAi) args.push('--adjust-for-ai');
|
|
220
|
+
return runQuery(basePath, args);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// ─── Coupling ───────────────────────────────────────────────────────────────
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Files that frequently change together with `file`.
|
|
227
|
+
*/
|
|
228
|
+
function coupling(basePath, file) {
|
|
229
|
+
return runQuery(basePath, ['coupling', file]);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// ─── Standards ──────────────────────────────────────────────────────────────
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Project norms (commit conventions, etc.) detected from git history.
|
|
236
|
+
*/
|
|
237
|
+
function norms(basePath) {
|
|
238
|
+
return runQuery(basePath, ['norms']);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Commit message style + prefixes + scope usage.
|
|
243
|
+
*/
|
|
244
|
+
function conventions(basePath) {
|
|
245
|
+
return runQuery(basePath, ['conventions']);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// ─── Health ─────────────────────────────────────────────────────────────────
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Directory-level health overview.
|
|
252
|
+
*/
|
|
253
|
+
function areas(basePath) {
|
|
254
|
+
return runQuery(basePath, ['areas']);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Repository-wide health summary.
|
|
259
|
+
*/
|
|
260
|
+
function health(basePath) {
|
|
261
|
+
return runQuery(basePath, ['health']);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Release cadence and tag history.
|
|
266
|
+
*/
|
|
267
|
+
function releaseInfo(basePath) {
|
|
268
|
+
return runQuery(basePath, ['release-info']);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// ─── AI detection ───────────────────────────────────────────────────────────
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* AI vs human contribution ratio.
|
|
275
|
+
*/
|
|
276
|
+
function aiRatio(basePath, options = {}) {
|
|
277
|
+
const args = ['ai-ratio'];
|
|
278
|
+
if (options.pathFilter) args.push('--path-filter', options.pathFilter);
|
|
279
|
+
return runQuery(basePath, args);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Files with recent AI-authored changes.
|
|
284
|
+
*/
|
|
285
|
+
function recentAi(basePath, options = {}) {
|
|
286
|
+
const args = ['recent-ai'];
|
|
287
|
+
if (options.limit) args.push('--top', String(options.limit));
|
|
288
|
+
return runQuery(basePath, args);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// ─── Contributor guidance ───────────────────────────────────────────────────
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Newcomer-oriented repo summary (tech stack, key areas, pain points).
|
|
295
|
+
*/
|
|
296
|
+
function onboard(basePath) {
|
|
297
|
+
return runQuery(basePath, ['onboard']);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Contribution guidance: good-first areas, test gaps, doc drift, bugspots.
|
|
302
|
+
*/
|
|
303
|
+
function canIHelp(basePath) {
|
|
304
|
+
return runQuery(basePath, ['can-i-help']);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// ─── Documentation ──────────────────────────────────────────────────────────
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Doc files with low code coupling (likely stale).
|
|
311
|
+
*/
|
|
312
|
+
function docDrift(basePath, options = {}) {
|
|
313
|
+
const args = ['doc-drift'];
|
|
314
|
+
if (options.limit) args.push('--top', String(options.limit));
|
|
315
|
+
return runQuery(basePath, args);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Doc files with stale references to source symbols. Requires Phase 4
|
|
320
|
+
* sync-check data.
|
|
321
|
+
*/
|
|
322
|
+
function staleDocs(basePath, options = {}) {
|
|
323
|
+
const args = ['stale-docs'];
|
|
324
|
+
if (options.limit) args.push('--top', String(options.limit));
|
|
325
|
+
return runQuery(basePath, args);
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// ─── AST symbols ────────────────────────────────────────────────────────────
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* AST symbols (exports, imports, definitions) for a specific file. Requires
|
|
332
|
+
* Phase 2 AST data.
|
|
333
|
+
*/
|
|
334
|
+
function symbols(basePath, file) {
|
|
335
|
+
return runQuery(basePath, ['symbols', file]);
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* Files that import a given symbol (reverse dependency lookup). Requires
|
|
340
|
+
* Phase 2 AST data.
|
|
341
|
+
*/
|
|
342
|
+
function dependents(basePath, symbol, file) {
|
|
343
|
+
const args = ['dependents', symbol];
|
|
344
|
+
if (file) args.push('--file', file);
|
|
345
|
+
return runQuery(basePath, args);
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// ─── Phase 5: Graph-derived (analyzer-graph crate) ──────────────────────────
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* Communities discovered by Louvain modularity over the co-change graph.
|
|
352
|
+
* Returns clusters of files that consistently change together - the natural
|
|
353
|
+
* feature areas, independent of directory layout. Requires agent-analyzer
|
|
354
|
+
* v0.4.0+.
|
|
355
|
+
*
|
|
356
|
+
* @param {string} basePath
|
|
357
|
+
* @returns {Array<{id: number, size: number, files: string[]}>}
|
|
358
|
+
*/
|
|
359
|
+
function communities(basePath) {
|
|
360
|
+
return runQuery(basePath, ['communities']);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* Files bridging multiple communities (high betweenness centrality). These
|
|
365
|
+
* are the architectural seams - the highest-leverage files for refactoring
|
|
366
|
+
* decisions. Requires agent-analyzer v0.4.0+.
|
|
367
|
+
*
|
|
368
|
+
* @param {string} basePath
|
|
369
|
+
* @param {Object} [options={}]
|
|
370
|
+
* @param {number} [options.limit] - Maximum number of results
|
|
371
|
+
* @returns {Array<{path: string, betweenness: number, community: number|null}>}
|
|
372
|
+
*/
|
|
373
|
+
function boundaries(basePath, options = {}) {
|
|
374
|
+
const args = ['boundaries'];
|
|
375
|
+
if (options.limit) args.push('--top', String(options.limit));
|
|
376
|
+
return runQuery(basePath, args);
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
/**
|
|
380
|
+
* Look up which community a given file belongs to. Requires agent-analyzer
|
|
381
|
+
* v0.4.0+.
|
|
382
|
+
*
|
|
383
|
+
* @param {string} basePath
|
|
384
|
+
* @param {string} file - File path (relative to repo root)
|
|
385
|
+
* @returns {{file: string, community: number|null, size: number|null}}
|
|
386
|
+
*/
|
|
387
|
+
function areaOf(basePath, file) {
|
|
388
|
+
return runQuery(basePath, ['area-of', file]);
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
/**
|
|
392
|
+
* Composite per-community health: total/recent changes, bug-fix rate,
|
|
393
|
+
* AI ratio, stale-owner count. Use to identify communities under stress
|
|
394
|
+
* (high bug rate or stale ownership). Requires agent-analyzer v0.4.0+.
|
|
395
|
+
*
|
|
396
|
+
* @param {string} basePath
|
|
397
|
+
* @param {number} id - Community id (from `communities()`)
|
|
398
|
+
* @returns {Object|null}
|
|
399
|
+
*/
|
|
400
|
+
function communityHealth(basePath, id) {
|
|
401
|
+
if (!Number.isInteger(id) || id < 0) {
|
|
402
|
+
throw new TypeError(
|
|
403
|
+
`communityHealth: \`id\` must be a non-negative integer, got: ${id} (${typeof id})`
|
|
404
|
+
);
|
|
405
|
+
}
|
|
406
|
+
return runQuery(basePath, ['community-health', String(id)]);
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
module.exports = {
|
|
410
|
+
// Errors
|
|
411
|
+
RepoIntelMissingError,
|
|
412
|
+
// Activity
|
|
413
|
+
hotspots,
|
|
414
|
+
coldspots,
|
|
415
|
+
fileHistory,
|
|
416
|
+
// Quality
|
|
417
|
+
bugspots,
|
|
418
|
+
testGaps,
|
|
419
|
+
diffRisk,
|
|
420
|
+
painspots,
|
|
421
|
+
// People
|
|
422
|
+
ownership,
|
|
423
|
+
contributors,
|
|
424
|
+
busFactor,
|
|
425
|
+
// Coupling
|
|
426
|
+
coupling,
|
|
427
|
+
// Standards
|
|
428
|
+
norms,
|
|
429
|
+
conventions,
|
|
430
|
+
// Health
|
|
431
|
+
areas,
|
|
432
|
+
health,
|
|
433
|
+
releaseInfo,
|
|
434
|
+
// AI detection
|
|
435
|
+
aiRatio,
|
|
436
|
+
recentAi,
|
|
437
|
+
// Contributor guidance
|
|
438
|
+
onboard,
|
|
439
|
+
canIHelp,
|
|
440
|
+
// Documentation
|
|
441
|
+
docDrift,
|
|
442
|
+
staleDocs,
|
|
443
|
+
// AST symbols
|
|
444
|
+
symbols,
|
|
445
|
+
dependents,
|
|
446
|
+
// Phase 5: graph-derived
|
|
447
|
+
communities,
|
|
448
|
+
boundaries,
|
|
449
|
+
areaOf,
|
|
450
|
+
communityHealth,
|
|
451
|
+
};
|
package/package.json
CHANGED
package/site/content.json
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"url": "https://agent-sh.github.io/agentsys",
|
|
6
6
|
"repo": "https://github.com/agent-sh/agentsys",
|
|
7
7
|
"npm": "https://www.npmjs.com/package/agentsys",
|
|
8
|
-
"version": "5.8.
|
|
8
|
+
"version": "5.8.6",
|
|
9
9
|
"author": "Avi Fenesh",
|
|
10
10
|
"author_url": "https://github.com/avifenesh"
|
|
11
11
|
},
|