@renseiai/agentfactory-cli 0.8.17 → 0.8.19
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/src/code.d.ts
CHANGED
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
* get-repo-map Get PageRank-ranked repository file map
|
|
14
14
|
* search-code <query> BM25/hybrid code search
|
|
15
15
|
* check-duplicate Check content for duplicates
|
|
16
|
+
* find-type-usages <name> Find all switch/case, mapping, and usage sites for a type
|
|
17
|
+
* validate-cross-deps Check cross-package imports have package.json entries
|
|
16
18
|
* help Show this help message
|
|
17
19
|
*
|
|
18
20
|
* Environment:
|
package/dist/src/code.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"code.d.ts","sourceRoot":"","sources":["../../src/code.ts"],"names":[],"mappings":";AACA
|
|
1
|
+
{"version":3,"file":"code.d.ts","sourceRoot":"","sources":["../../src/code.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;;;;;;;GAqBG"}
|
package/dist/src/code.js
CHANGED
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
* get-repo-map Get PageRank-ranked repository file map
|
|
14
14
|
* search-code <query> BM25/hybrid code search
|
|
15
15
|
* check-duplicate Check content for duplicates
|
|
16
|
+
* find-type-usages <name> Find all switch/case, mapping, and usage sites for a type
|
|
17
|
+
* validate-cross-deps Check cross-package imports have package.json entries
|
|
16
18
|
* help Show this help message
|
|
17
19
|
*
|
|
18
20
|
* Environment:
|
|
@@ -55,6 +57,12 @@ Options (check-duplicate):
|
|
|
55
57
|
--content <string> Content to check (inline)
|
|
56
58
|
--content-file <path> Path to file containing content to check
|
|
57
59
|
|
|
60
|
+
Options (find-type-usages):
|
|
61
|
+
--max-results <N> Maximum results (default: 50)
|
|
62
|
+
|
|
63
|
+
Options (validate-cross-deps):
|
|
64
|
+
[path] Optional directory/file to scope the check
|
|
65
|
+
|
|
58
66
|
Index:
|
|
59
67
|
First invocation builds the index from source files (~5-10s).
|
|
60
68
|
Subsequent calls reuse the persisted index from .agentfactory/code-index/.
|
|
@@ -66,6 +74,9 @@ Examples:
|
|
|
66
74
|
af-code search-code "incremental indexer" --language typescript
|
|
67
75
|
af-code check-duplicate --content "function hello() { return 'world' }"
|
|
68
76
|
af-code check-duplicate --content-file /tmp/snippet.ts
|
|
77
|
+
af-code find-type-usages "AgentWorkType"
|
|
78
|
+
af-code validate-cross-deps
|
|
79
|
+
af-code validate-cross-deps packages/linear
|
|
69
80
|
`);
|
|
70
81
|
}
|
|
71
82
|
async function main() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"code-intelligence-runner.d.ts","sourceRoot":"","sources":["../../../src/lib/code-intelligence-runner.ts"],"names":[],"mappings":"AAkBA,MAAM,WAAW,4BAA4B;IAC3C,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,OAAO,CAAC,CAAA;IACjD,cAAc,EAAE,MAAM,EAAE,CAAA;IACxB,GAAG,EAAE,MAAM,CAAA;CACZ;AAED,MAAM,WAAW,4BAA4B;IAC3C,MAAM,EAAE,OAAO,CAAA;CAChB;AAID,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG;IAC7C,OAAO,EAAE,MAAM,GAAG,SAAS,CAAA;IAC3B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,OAAO,CAAC,CAAA;IACjD,cAAc,EAAE,MAAM,EAAE,CAAA;CACzB,CAwBA;
|
|
1
|
+
{"version":3,"file":"code-intelligence-runner.d.ts","sourceRoot":"","sources":["../../../src/lib/code-intelligence-runner.ts"],"names":[],"mappings":"AAkBA,MAAM,WAAW,4BAA4B;IAC3C,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,OAAO,CAAC,CAAA;IACjD,cAAc,EAAE,MAAM,EAAE,CAAA;IACxB,GAAG,EAAE,MAAM,CAAA;CACZ;AAED,MAAM,WAAW,4BAA4B;IAC3C,MAAM,EAAE,OAAO,CAAA;CAChB;AAID,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG;IAC7C,OAAO,EAAE,MAAM,GAAG,SAAS,CAAA;IAC3B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,OAAO,CAAC,CAAA;IACjD,cAAc,EAAE,MAAM,EAAE,CAAA;CACzB,CAwBA;AA+gBD,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,4BAA4B,GACnC,OAAO,CAAC,4BAA4B,CAAC,CAuBvC"}
|
|
@@ -171,8 +171,290 @@ async function checkDuplicate(config, engines) {
|
|
|
171
171
|
const result = await engines.dedupPipeline.check(content);
|
|
172
172
|
return result;
|
|
173
173
|
}
|
|
174
|
+
async function findTypeUsages(config) {
|
|
175
|
+
const typeName = config.positionalArgs[0];
|
|
176
|
+
if (!typeName)
|
|
177
|
+
throw new Error('Usage: af-code find-type-usages <TypeName>');
|
|
178
|
+
const maxResults = config.args['max-results'] ? Number(config.args['max-results']) : 50;
|
|
179
|
+
const files = await discoverSourceFiles(config.cwd);
|
|
180
|
+
const usages = [];
|
|
181
|
+
// Patterns that indicate exhaustive switch/case, mapping objects, or type references
|
|
182
|
+
const switchPattern = new RegExp(`switch\\s*\\(`, 'g');
|
|
183
|
+
const casePattern = new RegExp(`case\\s+['"]`, 'g');
|
|
184
|
+
const importPattern = new RegExp(`\\b${escapeRegex(typeName)}\\b`, 'g');
|
|
185
|
+
const mappingPattern = new RegExp(`(?:Record<\\s*${escapeRegex(typeName)}|:\\s*\\{\\s*\\[\\w+\\s+in\\s+${escapeRegex(typeName)}\\]|satisfies\\s+Record<\\s*${escapeRegex(typeName)})`, 'g');
|
|
186
|
+
for (const [filePath, content] of files) {
|
|
187
|
+
if (!content.includes(typeName))
|
|
188
|
+
continue;
|
|
189
|
+
const lines = content.split('\n');
|
|
190
|
+
for (let i = 0; i < lines.length; i++) {
|
|
191
|
+
const line = lines[i];
|
|
192
|
+
// Check for import of the type
|
|
193
|
+
if (line.match(/\bimport\b/) && line.includes(typeName)) {
|
|
194
|
+
usages.push({ filePath, line: i + 1, context: line.trim(), kind: 'import' });
|
|
195
|
+
continue;
|
|
196
|
+
}
|
|
197
|
+
// Check for switch statements — look for switch keyword near the type name usage
|
|
198
|
+
if (switchPattern.test(line)) {
|
|
199
|
+
// Scan surrounding lines for the type name
|
|
200
|
+
const windowStart = Math.max(0, i - 2);
|
|
201
|
+
const windowEnd = Math.min(lines.length - 1, i + 5);
|
|
202
|
+
const window = lines.slice(windowStart, windowEnd + 1).join('\n');
|
|
203
|
+
if (window.includes(typeName) || hasRelatedCases(lines, i, typeName)) {
|
|
204
|
+
usages.push({ filePath, line: i + 1, context: line.trim(), kind: 'switch_case' });
|
|
205
|
+
}
|
|
206
|
+
switchPattern.lastIndex = 0;
|
|
207
|
+
}
|
|
208
|
+
// Check for Record<TypeName, ...> or mapping objects
|
|
209
|
+
if (mappingPattern.test(line)) {
|
|
210
|
+
usages.push({ filePath, line: i + 1, context: line.trim(), kind: 'mapping_object' });
|
|
211
|
+
mappingPattern.lastIndex = 0;
|
|
212
|
+
}
|
|
213
|
+
// Check for exhaustive checks (assertNever, default: throw, etc.)
|
|
214
|
+
if ((line.includes('assertNever') || line.includes('exhaustive')) &&
|
|
215
|
+
content.includes(typeName)) {
|
|
216
|
+
usages.push({ filePath, line: i + 1, context: line.trim(), kind: 'exhaustive_check' });
|
|
217
|
+
}
|
|
218
|
+
// Check for type definition/reference (union type definitions, extends, etc.)
|
|
219
|
+
if ((line.includes(`type ${typeName}`) ||
|
|
220
|
+
line.includes(`interface ${typeName}`) ||
|
|
221
|
+
line.match(new RegExp(`:\\s*${escapeRegex(typeName)}\\b`))) &&
|
|
222
|
+
!line.match(/\bimport\b/)) {
|
|
223
|
+
usages.push({ filePath, line: i + 1, context: line.trim(), kind: 'type_reference' });
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
// Deduplicate and sort: switch_case and mapping_object first (most actionable)
|
|
228
|
+
const kindPriority = {
|
|
229
|
+
switch_case: 0,
|
|
230
|
+
mapping_object: 1,
|
|
231
|
+
exhaustive_check: 2,
|
|
232
|
+
type_reference: 3,
|
|
233
|
+
import: 4,
|
|
234
|
+
};
|
|
235
|
+
usages.sort((a, b) => (kindPriority[a.kind] ?? 5) - (kindPriority[b.kind] ?? 5));
|
|
236
|
+
return {
|
|
237
|
+
typeName,
|
|
238
|
+
totalUsages: usages.length,
|
|
239
|
+
usages: usages.slice(0, maxResults),
|
|
240
|
+
switchStatements: usages.filter(u => u.kind === 'switch_case').length,
|
|
241
|
+
mappingObjects: usages.filter(u => u.kind === 'mapping_object').length,
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
/** Check if a switch block's case statements relate to a union type */
|
|
245
|
+
function hasRelatedCases(lines, switchLine, _typeName) {
|
|
246
|
+
// Scan forward from the switch line looking for string literal cases
|
|
247
|
+
for (let j = switchLine; j < Math.min(lines.length, switchLine + 50); j++) {
|
|
248
|
+
if (lines[j].includes('case \'') || lines[j].includes('case "')) {
|
|
249
|
+
return true; // Has string literal cases, likely a discriminated union switch
|
|
250
|
+
}
|
|
251
|
+
if (lines[j].match(/^\s*\}/))
|
|
252
|
+
break; // End of block
|
|
253
|
+
}
|
|
254
|
+
return false;
|
|
255
|
+
}
|
|
256
|
+
function escapeRegex(str) {
|
|
257
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Determine whether a line contains a real import statement (not one inside
|
|
261
|
+
* a comment, string literal, template literal, or test assertion).
|
|
262
|
+
*
|
|
263
|
+
* The caller must maintain the parse state across lines.
|
|
264
|
+
*/
|
|
265
|
+
function isRealImportLine(line, state) {
|
|
266
|
+
const trimmed = line.trim();
|
|
267
|
+
// Track block comment boundaries
|
|
268
|
+
if (state.inBlockComment) {
|
|
269
|
+
if (trimmed.includes('*/')) {
|
|
270
|
+
return { real: false, state: { ...state, inBlockComment: false } };
|
|
271
|
+
}
|
|
272
|
+
return { real: false, state };
|
|
273
|
+
}
|
|
274
|
+
if (trimmed.startsWith('/*')) {
|
|
275
|
+
const closesOnSameLine = trimmed.includes('*/');
|
|
276
|
+
return { real: false, state: { ...state, inBlockComment: !closesOnSameLine } };
|
|
277
|
+
}
|
|
278
|
+
// Track template literal boundaries (backtick strings spanning multiple lines)
|
|
279
|
+
// Count unescaped backticks to toggle state
|
|
280
|
+
if (state.inTemplateLiteral) {
|
|
281
|
+
const backtickCount = countUnescapedBackticks(line);
|
|
282
|
+
if (backtickCount % 2 === 1) {
|
|
283
|
+
// Odd number of backticks — template literal ends on this line
|
|
284
|
+
return { real: false, state: { ...state, inTemplateLiteral: false } };
|
|
285
|
+
}
|
|
286
|
+
return { real: false, state };
|
|
287
|
+
}
|
|
288
|
+
// Single-line comments and JSDoc continuation lines
|
|
289
|
+
if (trimmed.startsWith('//') || trimmed.startsWith('*'))
|
|
290
|
+
return { real: false, state };
|
|
291
|
+
// Check if this line opens a template literal that doesn't close on the same line
|
|
292
|
+
const backticks = countUnescapedBackticks(line);
|
|
293
|
+
if (backticks % 2 === 1) {
|
|
294
|
+
// Odd backticks — a template literal opens and doesn't close on this line.
|
|
295
|
+
// The import on this line (if any) could be before or after the backtick.
|
|
296
|
+
// If the import keyword appears after a backtick, it's template content.
|
|
297
|
+
const importIdx = line.search(/\b(import|export)\s/);
|
|
298
|
+
const firstBacktick = line.indexOf('`');
|
|
299
|
+
if (importIdx >= 0 && firstBacktick >= 0 && importIdx > firstBacktick) {
|
|
300
|
+
// Import appears inside the template literal
|
|
301
|
+
return { real: false, state: { ...state, inTemplateLiteral: true } };
|
|
302
|
+
}
|
|
303
|
+
// Import appears before the backtick — real import, but template opens
|
|
304
|
+
if (importIdx >= 0 && (firstBacktick < 0 || importIdx < firstBacktick)) {
|
|
305
|
+
return { real: true, state: { ...state, inTemplateLiteral: true } };
|
|
306
|
+
}
|
|
307
|
+
return { real: false, state: { ...state, inTemplateLiteral: true } };
|
|
308
|
+
}
|
|
309
|
+
// Real import/export/require statements start at the beginning of the line
|
|
310
|
+
if (/^\s*(import|export)\s/.test(line))
|
|
311
|
+
return { real: true, state };
|
|
312
|
+
// Dynamic require: `const x = require('pkg')`
|
|
313
|
+
if (/\brequire\s*\(/.test(line)) {
|
|
314
|
+
const reqIdx = line.indexOf('require');
|
|
315
|
+
const beforeReq = line.slice(0, reqIdx);
|
|
316
|
+
if (beforeReq.includes('`') || beforeReq.includes("'require") || beforeReq.includes('"require')) {
|
|
317
|
+
return { real: false, state };
|
|
318
|
+
}
|
|
319
|
+
return { real: true, state };
|
|
320
|
+
}
|
|
321
|
+
return { real: false, state };
|
|
322
|
+
}
|
|
323
|
+
/** Count unescaped backticks in a line */
|
|
324
|
+
function countUnescapedBackticks(line) {
|
|
325
|
+
let count = 0;
|
|
326
|
+
for (let i = 0; i < line.length; i++) {
|
|
327
|
+
if (line[i] === '`' && (i === 0 || line[i - 1] !== '\\')) {
|
|
328
|
+
count++;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
return count;
|
|
332
|
+
}
|
|
333
|
+
async function validateCrossDeps(config) {
|
|
334
|
+
const targetPath = config.positionalArgs[0]; // Optional: specific file or directory
|
|
335
|
+
const files = await discoverSourceFiles(config.cwd);
|
|
336
|
+
// 1. Build a map of workspace packages by reading all package.json files
|
|
337
|
+
const workspacePackages = new Map();
|
|
338
|
+
await discoverWorkspacePackages(config.cwd, workspacePackages);
|
|
339
|
+
// 2. Map file paths to their owning workspace package
|
|
340
|
+
function findOwningPackage(filePath) {
|
|
341
|
+
let bestMatch = null;
|
|
342
|
+
for (const [dir, pkg] of workspacePackages) {
|
|
343
|
+
if (filePath.startsWith(dir + '/') || filePath === dir) {
|
|
344
|
+
if (!bestMatch || dir.length > bestMatch.key.length) {
|
|
345
|
+
bestMatch = { key: dir, pkg };
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
return bestMatch?.pkg;
|
|
350
|
+
}
|
|
351
|
+
const missingDeps = [];
|
|
352
|
+
// 3. Check each file for cross-package imports
|
|
353
|
+
for (const [filePath, content] of files) {
|
|
354
|
+
if (targetPath && !filePath.startsWith(targetPath))
|
|
355
|
+
continue;
|
|
356
|
+
const owningPkg = findOwningPackage(filePath);
|
|
357
|
+
if (!owningPkg)
|
|
358
|
+
continue;
|
|
359
|
+
const lines = content.split('\n');
|
|
360
|
+
let parseState = { inBlockComment: false, inTemplateLiteral: false };
|
|
361
|
+
for (let i = 0; i < lines.length; i++) {
|
|
362
|
+
const line = lines[i];
|
|
363
|
+
// Skip comments, string literals, and template content
|
|
364
|
+
const classification = isRealImportLine(line, parseState);
|
|
365
|
+
parseState = classification.state;
|
|
366
|
+
if (!classification.real)
|
|
367
|
+
continue;
|
|
368
|
+
// Match import/require of workspace packages
|
|
369
|
+
const importMatch = line.match(/(?:from\s+['"]|require\s*\(\s*['"]|import\s+['"])(@[^'"\/]+\/[^'"\/]+|[^.'"\/@][^'"\/]*)/);
|
|
370
|
+
if (!importMatch)
|
|
371
|
+
continue;
|
|
372
|
+
const importedPkg = importMatch[1];
|
|
373
|
+
// Check if this is a workspace package
|
|
374
|
+
const isWorkspacePkg = [...workspacePackages.values()].some(wp => wp.name === importedPkg);
|
|
375
|
+
if (!isWorkspacePkg)
|
|
376
|
+
continue;
|
|
377
|
+
// Check if it's declared in package.json
|
|
378
|
+
if (!owningPkg.deps.has(importedPkg)) {
|
|
379
|
+
missingDeps.push({
|
|
380
|
+
importingFile: filePath,
|
|
381
|
+
importedPackage: importedPkg,
|
|
382
|
+
packageJsonPath: join(owningPkg.dir, 'package.json'),
|
|
383
|
+
line: i + 1,
|
|
384
|
+
});
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
// Deduplicate by (packageJsonPath, importedPackage)
|
|
389
|
+
const seen = new Set();
|
|
390
|
+
const uniqueMissing = missingDeps.filter(d => {
|
|
391
|
+
const key = `${d.packageJsonPath}:${d.importedPackage}`;
|
|
392
|
+
if (seen.has(key))
|
|
393
|
+
return false;
|
|
394
|
+
seen.add(key);
|
|
395
|
+
return true;
|
|
396
|
+
});
|
|
397
|
+
return {
|
|
398
|
+
valid: uniqueMissing.length === 0,
|
|
399
|
+
missingDeps: uniqueMissing,
|
|
400
|
+
packagesChecked: workspacePackages.size,
|
|
401
|
+
filesChecked: targetPath
|
|
402
|
+
? [...files.keys()].filter(f => f.startsWith(targetPath)).length
|
|
403
|
+
: files.size,
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
async function discoverWorkspacePackages(cwd, result) {
|
|
407
|
+
// Find all package.json files in the workspace (skip node_modules, dist)
|
|
408
|
+
async function walk(dir, depth) {
|
|
409
|
+
if (depth > 5)
|
|
410
|
+
return;
|
|
411
|
+
let entries;
|
|
412
|
+
try {
|
|
413
|
+
entries = await readdir(dir, { withFileTypes: true });
|
|
414
|
+
}
|
|
415
|
+
catch {
|
|
416
|
+
return;
|
|
417
|
+
}
|
|
418
|
+
for (const entry of entries) {
|
|
419
|
+
if (IGNORE_DIRS.has(entry.name))
|
|
420
|
+
continue;
|
|
421
|
+
const fullPath = join(dir, entry.name);
|
|
422
|
+
if (entry.isDirectory()) {
|
|
423
|
+
await walk(fullPath, depth + 1);
|
|
424
|
+
}
|
|
425
|
+
else if (entry.name === 'package.json') {
|
|
426
|
+
try {
|
|
427
|
+
const content = JSON.parse(await readFile(fullPath, 'utf-8'));
|
|
428
|
+
if (content.name) {
|
|
429
|
+
const allDeps = new Set([
|
|
430
|
+
...Object.keys(content.dependencies ?? {}),
|
|
431
|
+
...Object.keys(content.devDependencies ?? {}),
|
|
432
|
+
...Object.keys(content.peerDependencies ?? {}),
|
|
433
|
+
]);
|
|
434
|
+
result.set(relative(cwd, dir), {
|
|
435
|
+
name: content.name,
|
|
436
|
+
dir: relative(cwd, dir),
|
|
437
|
+
deps: allDeps,
|
|
438
|
+
});
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
catch {
|
|
442
|
+
// Skip malformed package.json
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
await walk(cwd, 0);
|
|
448
|
+
}
|
|
174
449
|
// ── Main runner ─────────────────────────────────────────────────────────────
|
|
175
450
|
export async function runCodeIntelligence(config) {
|
|
451
|
+
// Commands that don't need the full index
|
|
452
|
+
switch (config.command) {
|
|
453
|
+
case 'find-type-usages':
|
|
454
|
+
return { output: await findTypeUsages(config) };
|
|
455
|
+
case 'validate-cross-deps':
|
|
456
|
+
return { output: await validateCrossDeps(config) };
|
|
457
|
+
}
|
|
176
458
|
const engines = await initializeIndex(config.cwd);
|
|
177
459
|
switch (config.command) {
|
|
178
460
|
case 'search-symbols':
|
|
@@ -184,6 +466,6 @@ export async function runCodeIntelligence(config) {
|
|
|
184
466
|
case 'check-duplicate':
|
|
185
467
|
return { output: await checkDuplicate(config, engines) };
|
|
186
468
|
default:
|
|
187
|
-
throw new Error(`Unknown command: ${config.command}. Available: search-symbols, get-repo-map, search-code, check-duplicate`);
|
|
469
|
+
throw new Error(`Unknown command: ${config.command}. Available: search-symbols, get-repo-map, search-code, check-duplicate, find-type-usages, validate-cross-deps`);
|
|
188
470
|
}
|
|
189
471
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@renseiai/agentfactory-cli",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.19",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "CLI tools for AgentFactory — local orchestrator, remote worker, queue admin",
|
|
6
6
|
"author": "Rensei AI (https://rensei.ai)",
|
|
@@ -126,12 +126,12 @@
|
|
|
126
126
|
],
|
|
127
127
|
"dependencies": {
|
|
128
128
|
"dotenv": "^17.2.3",
|
|
129
|
-
"@renseiai/
|
|
130
|
-
"@renseiai/
|
|
131
|
-
"@renseiai/agentfactory
|
|
129
|
+
"@renseiai/plugin-linear": "0.8.19",
|
|
130
|
+
"@renseiai/agentfactory-server": "0.8.19",
|
|
131
|
+
"@renseiai/agentfactory": "0.8.19"
|
|
132
132
|
},
|
|
133
133
|
"optionalDependencies": {
|
|
134
|
-
"@renseiai/agentfactory-code-intelligence": "0.8.
|
|
134
|
+
"@renseiai/agentfactory-code-intelligence": "0.8.19"
|
|
135
135
|
},
|
|
136
136
|
"devDependencies": {
|
|
137
137
|
"@types/node": "^22.5.4",
|