codeimpact 0.3.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +432 -59
- package/dist/index.js.map +3 -3
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -11109,7 +11109,7 @@ var init_token_budget = __esm({
|
|
|
11109
11109
|
});
|
|
11110
11110
|
|
|
11111
11111
|
// src/core/agents/generator.ts
|
|
11112
|
-
import { mkdirSync as mkdirSync17 } from "fs";
|
|
11112
|
+
import { existsSync as existsSync32, readFileSync as readFileSync26, mkdirSync as mkdirSync17 } from "fs";
|
|
11113
11113
|
import { join as join33 } from "path";
|
|
11114
11114
|
function generateProjectFiles(input) {
|
|
11115
11115
|
const { projectPath, intelligence, technologies, features, index } = input;
|
|
@@ -11118,7 +11118,7 @@ function generateProjectFiles(input) {
|
|
|
11118
11118
|
const result = { filesWritten: [], filesSkipped: [] };
|
|
11119
11119
|
mkdirSync17(paths.projectDir, { recursive: true });
|
|
11120
11120
|
const skillPath = join33(paths.projectDir, "SKILL.md");
|
|
11121
|
-
writeMarkedFile2(skillPath, renderProjectSkill(intelligence, technologies, config2), config2, result, "project_skill");
|
|
11121
|
+
writeMarkedFile2(skillPath, renderProjectSkill(intelligence, technologies, config2, projectPath), config2, result, "project_skill");
|
|
11122
11122
|
const convPath = join33(paths.projectDir, "CONVENTIONS.md");
|
|
11123
11123
|
writeMarkedFile2(convPath, renderConventions(intelligence, config2), config2, result, "project_conventions");
|
|
11124
11124
|
const archPath = join33(paths.projectDir, "ARCHITECTURE.md");
|
|
@@ -11139,7 +11139,7 @@ function generateFeatureFiles(input) {
|
|
|
11139
11139
|
}
|
|
11140
11140
|
return result;
|
|
11141
11141
|
}
|
|
11142
|
-
function renderProjectSkill(intel, technologies, config2) {
|
|
11142
|
+
function renderProjectSkill(intel, technologies, config2, projectPath) {
|
|
11143
11143
|
const frontmatter = [
|
|
11144
11144
|
"---",
|
|
11145
11145
|
"name: project-overview",
|
|
@@ -11156,9 +11156,13 @@ function renderProjectSkill(intel, technologies, config2) {
|
|
|
11156
11156
|
const lines = [];
|
|
11157
11157
|
lines.push("## Tech Stack");
|
|
11158
11158
|
if (technologies.length > 0) {
|
|
11159
|
-
const
|
|
11160
|
-
|
|
11161
|
-
|
|
11159
|
+
const directDeps = filterDirectDependencies(technologies, projectPath);
|
|
11160
|
+
if (directDeps.length > 0) {
|
|
11161
|
+
for (const tech of directDeps.slice(0, 20)) {
|
|
11162
|
+
lines.push(`- ${tech.name} ${tech.version}`);
|
|
11163
|
+
}
|
|
11164
|
+
} else {
|
|
11165
|
+
lines.push(`- Languages: ${intel.codebase.languages.join(", ")}`);
|
|
11162
11166
|
}
|
|
11163
11167
|
} else {
|
|
11164
11168
|
lines.push(`- Languages: ${intel.codebase.languages.join(", ")}`);
|
|
@@ -11186,7 +11190,9 @@ function renderProjectSkill(intel, technologies, config2) {
|
|
|
11186
11190
|
}
|
|
11187
11191
|
} else {
|
|
11188
11192
|
for (const dir of intel.codebase.keyDirectories) {
|
|
11189
|
-
|
|
11193
|
+
const dirName = dir.split("/").pop() || dir;
|
|
11194
|
+
const purpose = inferDirPurpose(dirName);
|
|
11195
|
+
lines.push(`| ${dir}/ | ${purpose} |`);
|
|
11190
11196
|
}
|
|
11191
11197
|
}
|
|
11192
11198
|
lines.push("");
|
|
@@ -11335,46 +11341,15 @@ function renderFeatureSkill(feature, technologies, config2) {
|
|
|
11335
11341
|
lines.push("");
|
|
11336
11342
|
}
|
|
11337
11343
|
lines.push("## Rules");
|
|
11338
|
-
|
|
11339
|
-
|
|
11340
|
-
|
|
11341
|
-
lines.push("- Use Router() for modular route definitions");
|
|
11342
|
-
lines.push("- Always register error handler middleware last");
|
|
11343
|
-
} else if (tech.name === "better-sqlite3") {
|
|
11344
|
-
lines.push("- Use db.prepare().all() for SELECT, db.prepare().run() for INSERT/UPDATE/DELETE");
|
|
11345
|
-
lines.push("- better-sqlite3 is synchronous \u2014 do NOT use async/await");
|
|
11346
|
-
} else if (tech.name === "stripe") {
|
|
11347
|
-
lines.push("- Always verify webhook signatures before processing events");
|
|
11348
|
-
lines.push("- Use idempotency keys for payment creation");
|
|
11349
|
-
} else if (tech.name === "jsonwebtoken") {
|
|
11350
|
-
lines.push("- Always verify tokens before trusting decoded data");
|
|
11351
|
-
lines.push("- Set explicit expiration times on all tokens");
|
|
11352
|
-
} else {
|
|
11353
|
-
lines.push(`- Follow ${tech.name} v${tech.version} API conventions`);
|
|
11354
|
-
}
|
|
11355
|
-
}
|
|
11356
|
-
} else {
|
|
11357
|
-
lines.push("- Follow project coding conventions for this feature");
|
|
11344
|
+
const rules = deriveRules(feature, technologies);
|
|
11345
|
+
for (const rule of rules) {
|
|
11346
|
+
lines.push(`- ${rule}`);
|
|
11358
11347
|
}
|
|
11359
11348
|
lines.push("");
|
|
11360
11349
|
lines.push("## Pitfalls");
|
|
11361
|
-
|
|
11362
|
-
|
|
11363
|
-
|
|
11364
|
-
lines.push("- Forgetting to call next() in middleware causes request to hang");
|
|
11365
|
-
} else if (tech.name === "better-sqlite3") {
|
|
11366
|
-
lines.push("- db.exec() returns nothing \u2014 using it for SELECT gives undefined");
|
|
11367
|
-
} else if (tech.name === "stripe") {
|
|
11368
|
-
lines.push("- Stripe webhook events may arrive out of order \u2014 handle idempotently");
|
|
11369
|
-
} else if (tech.name === "jsonwebtoken") {
|
|
11370
|
-
lines.push("- Using jwt.decode() without verify() is a security vulnerability");
|
|
11371
|
-
}
|
|
11372
|
-
}
|
|
11373
|
-
if (technologies.every((t) => !["express", "better-sqlite3", "stripe", "jsonwebtoken"].includes(t.name))) {
|
|
11374
|
-
lines.push("- Check research docs for version-specific breaking changes");
|
|
11375
|
-
}
|
|
11376
|
-
} else {
|
|
11377
|
-
lines.push("- Check for null/undefined before property access on external data");
|
|
11350
|
+
const pitfalls = derivePitfalls(feature, technologies);
|
|
11351
|
+
for (const pitfall of pitfalls) {
|
|
11352
|
+
lines.push(`- ${pitfall}`);
|
|
11378
11353
|
}
|
|
11379
11354
|
lines.push("");
|
|
11380
11355
|
return { frontmatter, autoContent: lines.join("\n") };
|
|
@@ -11424,15 +11399,296 @@ function parseAutoContentSections(autoContent) {
|
|
|
11424
11399
|
}
|
|
11425
11400
|
return sections;
|
|
11426
11401
|
}
|
|
11402
|
+
function inferDirPurpose(dirName) {
|
|
11403
|
+
const purposes = {
|
|
11404
|
+
core: "Core business logic and domain modules",
|
|
11405
|
+
server: "Server, transports, and request handling",
|
|
11406
|
+
storage: "Database access and persistence",
|
|
11407
|
+
indexing: "Code indexing and symbol extraction",
|
|
11408
|
+
api: "API routes and handlers",
|
|
11409
|
+
auth: "Authentication and authorization",
|
|
11410
|
+
billing: "Payment processing",
|
|
11411
|
+
test: "Tests and evaluation harness",
|
|
11412
|
+
doc: "Documentation",
|
|
11413
|
+
knowledge: "AI knowledge system",
|
|
11414
|
+
cli: "Command-line interface",
|
|
11415
|
+
base: "Base configuration and fixtures",
|
|
11416
|
+
src: "Application source code",
|
|
11417
|
+
lib: "Shared utilities"
|
|
11418
|
+
};
|
|
11419
|
+
return purposes[dirName.toLowerCase()] || `${dirName} module`;
|
|
11420
|
+
}
|
|
11421
|
+
function deriveRules(feature, technologies) {
|
|
11422
|
+
const rules = [];
|
|
11423
|
+
for (const tech of technologies) {
|
|
11424
|
+
const knowledge = TECH_KNOWLEDGE[tech.name];
|
|
11425
|
+
if (knowledge) {
|
|
11426
|
+
rules.push(...knowledge.rules);
|
|
11427
|
+
}
|
|
11428
|
+
}
|
|
11429
|
+
if (rules.length === 0) {
|
|
11430
|
+
const featureRules = getFeatureNameRules(feature.name);
|
|
11431
|
+
rules.push(...featureRules);
|
|
11432
|
+
}
|
|
11433
|
+
if (feature.paths.length > 0) {
|
|
11434
|
+
const scope = feature.paths[0]?.replace("/**", "") || "";
|
|
11435
|
+
rules.push(`Changes here should not import from other feature directories \u2014 keep ${scope} self-contained`);
|
|
11436
|
+
}
|
|
11437
|
+
return rules;
|
|
11438
|
+
}
|
|
11439
|
+
function derivePitfalls(feature, technologies) {
|
|
11440
|
+
const pitfalls = [];
|
|
11441
|
+
for (const tech of technologies) {
|
|
11442
|
+
const knowledge = TECH_KNOWLEDGE[tech.name];
|
|
11443
|
+
if (knowledge) {
|
|
11444
|
+
pitfalls.push(...knowledge.pitfalls);
|
|
11445
|
+
}
|
|
11446
|
+
}
|
|
11447
|
+
if (pitfalls.length === 0) {
|
|
11448
|
+
const featurePitfalls = getFeatureNamePitfalls(feature.name);
|
|
11449
|
+
pitfalls.push(...featurePitfalls);
|
|
11450
|
+
}
|
|
11451
|
+
return pitfalls;
|
|
11452
|
+
}
|
|
11453
|
+
function getFeatureNameRules(name) {
|
|
11454
|
+
const rules = {
|
|
11455
|
+
server: [
|
|
11456
|
+
"All tool/resource handlers must validate inputs before processing",
|
|
11457
|
+
"Return structured error responses \u2014 never throw raw errors to clients"
|
|
11458
|
+
],
|
|
11459
|
+
storage: [
|
|
11460
|
+
"All database access should go through this module \u2014 no direct imports elsewhere",
|
|
11461
|
+
"Use transactions for multi-step operations to ensure consistency"
|
|
11462
|
+
],
|
|
11463
|
+
indexing: [
|
|
11464
|
+
"Index operations should be idempotent \u2014 reindexing same file produces same result",
|
|
11465
|
+
"Handle parse errors gracefully \u2014 a broken file should not crash the indexer"
|
|
11466
|
+
],
|
|
11467
|
+
core: [
|
|
11468
|
+
"Core modules should have no side effects on import",
|
|
11469
|
+
"Export types alongside functions for downstream consumers"
|
|
11470
|
+
],
|
|
11471
|
+
test: [
|
|
11472
|
+
"Tests should be deterministic \u2014 no reliance on external services or timing",
|
|
11473
|
+
"Clean up temporary files and directories in afterEach/afterAll hooks"
|
|
11474
|
+
],
|
|
11475
|
+
knowledge: [
|
|
11476
|
+
"Skill files must follow the agentskills.io SKILL.md format",
|
|
11477
|
+
"Generated content must use marker comments to preserve manual edits"
|
|
11478
|
+
],
|
|
11479
|
+
doc: [
|
|
11480
|
+
"Generated docs must be kept in sync with source code changes",
|
|
11481
|
+
"Use relative paths for internal links"
|
|
11482
|
+
],
|
|
11483
|
+
auth: [
|
|
11484
|
+
"Never store plain-text passwords \u2014 use bcrypt or argon2",
|
|
11485
|
+
"Validate and sanitize all user inputs before processing"
|
|
11486
|
+
],
|
|
11487
|
+
api: [
|
|
11488
|
+
"All endpoints must validate request bodies/params before processing",
|
|
11489
|
+
"Return consistent error response shapes across all endpoints"
|
|
11490
|
+
]
|
|
11491
|
+
};
|
|
11492
|
+
return rules[name] || [
|
|
11493
|
+
"Follow existing patterns in this module for consistency",
|
|
11494
|
+
"Export public API from index.ts \u2014 keep internal helpers unexported"
|
|
11495
|
+
];
|
|
11496
|
+
}
|
|
11497
|
+
function getFeatureNamePitfalls(name) {
|
|
11498
|
+
const pitfalls = {
|
|
11499
|
+
server: [
|
|
11500
|
+
"Unhandled promise rejections in handlers crash the process \u2014 always catch async errors",
|
|
11501
|
+
"Adding middleware order matters \u2014 auth before route handlers"
|
|
11502
|
+
],
|
|
11503
|
+
storage: [
|
|
11504
|
+
"Forgetting to close database connections leaks file handles",
|
|
11505
|
+
"Concurrent writes without transactions may cause data corruption"
|
|
11506
|
+
],
|
|
11507
|
+
indexing: [
|
|
11508
|
+
"Large files can cause out-of-memory \u2014 set size limits on parsed content",
|
|
11509
|
+
"File paths must be normalized (forward slashes) for cross-platform compatibility"
|
|
11510
|
+
],
|
|
11511
|
+
core: [
|
|
11512
|
+
"Circular imports between core modules cause runtime errors \u2014 check dependency direction",
|
|
11513
|
+
"Changing public API signatures breaks downstream consumers"
|
|
11514
|
+
],
|
|
11515
|
+
test: [
|
|
11516
|
+
"Tests sharing mutable state between runs cause flaky failures",
|
|
11517
|
+
"Temp directories not cleaned up fill disk over repeated test runs"
|
|
11518
|
+
]
|
|
11519
|
+
};
|
|
11520
|
+
return pitfalls[name] || [
|
|
11521
|
+
"Check for null/undefined before property access on external data",
|
|
11522
|
+
"Changing exports may break other modules that depend on this feature"
|
|
11523
|
+
];
|
|
11524
|
+
}
|
|
11427
11525
|
function capitalize(str) {
|
|
11428
11526
|
return str.charAt(0).toUpperCase() + str.slice(1).replace(/-/g, " ");
|
|
11429
11527
|
}
|
|
11528
|
+
function filterDirectDependencies(technologies, projectPath) {
|
|
11529
|
+
const directNames = /* @__PURE__ */ new Set();
|
|
11530
|
+
for (const tech of technologies) {
|
|
11531
|
+
if (tech.source === "package.json") {
|
|
11532
|
+
directNames.add(tech.name);
|
|
11533
|
+
}
|
|
11534
|
+
}
|
|
11535
|
+
if (directNames.size === 0) {
|
|
11536
|
+
const searchPaths = [
|
|
11537
|
+
projectPath ? join33(projectPath, "package.json") : "",
|
|
11538
|
+
join33(process.cwd(), "package.json")
|
|
11539
|
+
].filter(Boolean);
|
|
11540
|
+
for (const p of searchPaths) {
|
|
11541
|
+
try {
|
|
11542
|
+
if (existsSync32(p)) {
|
|
11543
|
+
const pkg = JSON.parse(readFileSync26(p, "utf-8"));
|
|
11544
|
+
for (const d of Object.keys(pkg.dependencies || {})) directNames.add(d);
|
|
11545
|
+
for (const d of Object.keys(pkg.devDependencies || {})) directNames.add(d);
|
|
11546
|
+
break;
|
|
11547
|
+
}
|
|
11548
|
+
} catch {
|
|
11549
|
+
}
|
|
11550
|
+
}
|
|
11551
|
+
}
|
|
11552
|
+
const skipPatterns = [
|
|
11553
|
+
/^@types\//,
|
|
11554
|
+
/^@esbuild\//,
|
|
11555
|
+
/^@rollup\//,
|
|
11556
|
+
/^@swc\//,
|
|
11557
|
+
/^@parcel\//,
|
|
11558
|
+
/^@biomejs\//
|
|
11559
|
+
];
|
|
11560
|
+
if (directNames.size > 0) {
|
|
11561
|
+
return technologies.filter((t) => directNames.has(t.name)).filter((t) => !skipPatterns.some((p) => p.test(t.name)));
|
|
11562
|
+
}
|
|
11563
|
+
return technologies.filter((t) => !skipPatterns.some((p) => p.test(t.name))).slice(0, 20);
|
|
11564
|
+
}
|
|
11565
|
+
var TECH_KNOWLEDGE;
|
|
11430
11566
|
var init_generator = __esm({
|
|
11431
11567
|
"src/core/agents/generator.ts"() {
|
|
11432
11568
|
"use strict";
|
|
11433
11569
|
init_workspace2();
|
|
11434
11570
|
init_marker_writer();
|
|
11435
11571
|
init_token_budget();
|
|
11572
|
+
TECH_KNOWLEDGE = {
|
|
11573
|
+
"express": {
|
|
11574
|
+
rules: [
|
|
11575
|
+
"Use Router() for modular route definitions",
|
|
11576
|
+
"Always register error handler middleware last (4 args: err, req, res, next)"
|
|
11577
|
+
],
|
|
11578
|
+
pitfalls: [
|
|
11579
|
+
"Forgetting to call next() in middleware causes request to hang",
|
|
11580
|
+
"Async errors in handlers need explicit try/catch or express-async-errors"
|
|
11581
|
+
]
|
|
11582
|
+
},
|
|
11583
|
+
"hono": {
|
|
11584
|
+
rules: [
|
|
11585
|
+
"Use app.route() for modular route grouping",
|
|
11586
|
+
"Return c.json() or c.text() \u2014 do not use res.send()"
|
|
11587
|
+
],
|
|
11588
|
+
pitfalls: [
|
|
11589
|
+
"Hono middleware must call next() or return a Response \u2014 skipping both hangs the request"
|
|
11590
|
+
]
|
|
11591
|
+
},
|
|
11592
|
+
"better-sqlite3": {
|
|
11593
|
+
rules: [
|
|
11594
|
+
"Use db.prepare().all() for SELECT, db.prepare().run() for INSERT/UPDATE/DELETE",
|
|
11595
|
+
"better-sqlite3 is synchronous \u2014 do NOT use async/await with db calls",
|
|
11596
|
+
"All database access should go through a single module"
|
|
11597
|
+
],
|
|
11598
|
+
pitfalls: [
|
|
11599
|
+
"db.exec() returns nothing \u2014 using it for SELECT gives undefined",
|
|
11600
|
+
'WAL mode must be set once after opening: db.pragma("journal_mode = WAL")'
|
|
11601
|
+
]
|
|
11602
|
+
},
|
|
11603
|
+
"stripe": {
|
|
11604
|
+
rules: [
|
|
11605
|
+
"Always verify webhook signatures before processing events",
|
|
11606
|
+
"Use idempotency keys for payment creation to prevent double-charges"
|
|
11607
|
+
],
|
|
11608
|
+
pitfalls: [
|
|
11609
|
+
"Stripe webhook events may arrive out of order \u2014 handle idempotently",
|
|
11610
|
+
"stripe.webhooks.constructEvent() throws on invalid signature \u2014 wrap in try/catch"
|
|
11611
|
+
]
|
|
11612
|
+
},
|
|
11613
|
+
"jsonwebtoken": {
|
|
11614
|
+
rules: [
|
|
11615
|
+
"Always use jwt.verify() \u2014 never trust jwt.decode() alone",
|
|
11616
|
+
"Set explicit expiration (expiresIn) on all tokens"
|
|
11617
|
+
],
|
|
11618
|
+
pitfalls: [
|
|
11619
|
+
"Using jwt.decode() without verify() is a security vulnerability",
|
|
11620
|
+
'The "none" algorithm attack \u2014 always specify algorithms: ["HS256"]'
|
|
11621
|
+
]
|
|
11622
|
+
},
|
|
11623
|
+
"@modelcontextprotocol/sdk": {
|
|
11624
|
+
rules: [
|
|
11625
|
+
"Use server.tool() to register MCP tools with zod schema validation",
|
|
11626
|
+
"All tool handlers must return { content: [...] } response objects"
|
|
11627
|
+
],
|
|
11628
|
+
pitfalls: [
|
|
11629
|
+
"Tool names must be unique across the server \u2014 duplicates silently overwrite",
|
|
11630
|
+
"Forgetting to call server.connect(transport) means no requests are handled"
|
|
11631
|
+
]
|
|
11632
|
+
},
|
|
11633
|
+
"prisma": {
|
|
11634
|
+
rules: [
|
|
11635
|
+
"Run npx prisma generate after schema changes",
|
|
11636
|
+
"Use transactions for multi-table operations: prisma.$transaction()"
|
|
11637
|
+
],
|
|
11638
|
+
pitfalls: [
|
|
11639
|
+
"Forgetting prisma generate after schema change causes type mismatches at runtime",
|
|
11640
|
+
"N+1 queries \u2014 use include/select to eagerly load relations"
|
|
11641
|
+
]
|
|
11642
|
+
},
|
|
11643
|
+
"zod": {
|
|
11644
|
+
rules: [
|
|
11645
|
+
"Define schemas once, derive TypeScript types with z.infer<typeof schema>",
|
|
11646
|
+
"Use .safeParse() in handlers for graceful error handling"
|
|
11647
|
+
],
|
|
11648
|
+
pitfalls: [
|
|
11649
|
+
".parse() throws on invalid data \u2014 use .safeParse() in request handlers"
|
|
11650
|
+
]
|
|
11651
|
+
},
|
|
11652
|
+
"vitest": {
|
|
11653
|
+
rules: [
|
|
11654
|
+
"Use describe/it/expect patterns for test organization",
|
|
11655
|
+
"Use vi.mock() for module mocking, vi.fn() for function stubs"
|
|
11656
|
+
],
|
|
11657
|
+
pitfalls: [
|
|
11658
|
+
"vi.mock() is hoisted to top of file \u2014 cannot access variables from outer scope"
|
|
11659
|
+
]
|
|
11660
|
+
},
|
|
11661
|
+
"web-tree-sitter": {
|
|
11662
|
+
rules: [
|
|
11663
|
+
"Initialize Parser with await Parser.init() before use",
|
|
11664
|
+
"Load language WASM files with Parser.Language.load()"
|
|
11665
|
+
],
|
|
11666
|
+
pitfalls: [
|
|
11667
|
+
"Parser.init() must complete before any parsing \u2014 race condition if not awaited",
|
|
11668
|
+
"WASM files must be bundled/copied to dist \u2014 not resolved from node_modules at runtime"
|
|
11669
|
+
]
|
|
11670
|
+
},
|
|
11671
|
+
"@xenova/transformers": {
|
|
11672
|
+
rules: [
|
|
11673
|
+
"Use pipeline() for high-level tasks, AutoModel for custom inference",
|
|
11674
|
+
"Cache downloaded models by setting env.cacheDir"
|
|
11675
|
+
],
|
|
11676
|
+
pitfalls: [
|
|
11677
|
+
"First model load downloads weights (~100MB+) \u2014 cache for subsequent runs",
|
|
11678
|
+
"ONNX runtime may fail on some architectures \u2014 test on target platform"
|
|
11679
|
+
]
|
|
11680
|
+
},
|
|
11681
|
+
"chokidar": {
|
|
11682
|
+
rules: [
|
|
11683
|
+
"Use chokidar.watch() with ignored patterns to skip node_modules",
|
|
11684
|
+
'Handle both "add" and "change" events for file watching'
|
|
11685
|
+
],
|
|
11686
|
+
pitfalls: [
|
|
11687
|
+
"Not closing watcher on process exit leaks file handles",
|
|
11688
|
+
"Rapid file changes may fire multiple events \u2014 debounce handlers"
|
|
11689
|
+
]
|
|
11690
|
+
}
|
|
11691
|
+
};
|
|
11436
11692
|
}
|
|
11437
11693
|
});
|
|
11438
11694
|
|
|
@@ -11842,7 +12098,7 @@ var init_lifecycle = __esm({
|
|
|
11842
12098
|
});
|
|
11843
12099
|
|
|
11844
12100
|
// src/core/agents/orchestrator.ts
|
|
11845
|
-
import { existsSync as existsSync34, readdirSync as readdirSync12 } from "fs";
|
|
12101
|
+
import { existsSync as existsSync34, readFileSync as readFileSync27, readdirSync as readdirSync12 } from "fs";
|
|
11846
12102
|
import { join as join35, relative as relative9 } from "path";
|
|
11847
12103
|
function agentsInit(projectPath) {
|
|
11848
12104
|
const paths = initAgentWorkspace(projectPath);
|
|
@@ -11877,11 +12133,13 @@ async function agentsGenerate(options) {
|
|
|
11877
12133
|
result.technologies = technologies.length;
|
|
11878
12134
|
const importGraph = options.importGraph || /* @__PURE__ */ new Map();
|
|
11879
12135
|
const indexedFiles = options.indexedFiles || getIndexedFilesFromFS(projectPath);
|
|
12136
|
+
const fileTechMap = buildFileTechMap(projectPath, indexedFiles, technologies);
|
|
11880
12137
|
const featureInput = {
|
|
11881
12138
|
projectPath,
|
|
11882
12139
|
config: config2.feature_detection,
|
|
11883
12140
|
importGraph,
|
|
11884
|
-
indexedFiles
|
|
12141
|
+
indexedFiles,
|
|
12142
|
+
fileTechMap
|
|
11885
12143
|
};
|
|
11886
12144
|
const features = detectFeatures(featureInput);
|
|
11887
12145
|
result.features = features.length;
|
|
@@ -12099,30 +12357,55 @@ function filterTopTechnologies(technologies) {
|
|
|
12099
12357
|
return technologies.filter((t) => !skipPatterns.some((p) => p.test(t.name))).filter((t) => t.source.includes("lock") || t.source === "package.json").slice(0, 20);
|
|
12100
12358
|
}
|
|
12101
12359
|
function createMinimalIntelligence(projectPath, technologies, features) {
|
|
12360
|
+
const sourceFiles = getIndexedFilesFromFS(projectPath);
|
|
12361
|
+
const codeFiles = sourceFiles.filter(
|
|
12362
|
+
(f) => /\.(ts|tsx|js|jsx|py|go|rs|java|rb|php|cs|cpp|c|h)$/.test(f) && !f.includes("node_modules") && !f.includes("dist")
|
|
12363
|
+
);
|
|
12364
|
+
let totalLines = 0;
|
|
12365
|
+
for (const f of codeFiles.slice(0, 500)) {
|
|
12366
|
+
try {
|
|
12367
|
+
const content = readFileSync27(join35(projectPath, f), "utf-8");
|
|
12368
|
+
totalLines += content.split("\n").length;
|
|
12369
|
+
} catch {
|
|
12370
|
+
}
|
|
12371
|
+
}
|
|
12372
|
+
const extCounts = /* @__PURE__ */ new Map();
|
|
12373
|
+
for (const f of codeFiles) {
|
|
12374
|
+
const ext = f.split(".").pop() || "";
|
|
12375
|
+
const lang = extToLanguage(ext);
|
|
12376
|
+
if (lang) extCounts.set(lang, (extCounts.get(lang) || 0) + 1);
|
|
12377
|
+
}
|
|
12378
|
+
const languages = [...extCounts.entries()].sort((a, b) => b[1] - a[1]).map(([lang]) => lang);
|
|
12379
|
+
const layers = features.map((f) => ({
|
|
12380
|
+
name: f.name.charAt(0).toUpperCase() + f.name.slice(1),
|
|
12381
|
+
directory: f.paths[0]?.replace("/**", "") || f.name,
|
|
12382
|
+
purpose: inferLayerPurpose(f.name),
|
|
12383
|
+
fileCount: f.fileCount
|
|
12384
|
+
}));
|
|
12385
|
+
const testFramework = detectTestFramework(projectPath);
|
|
12102
12386
|
return {
|
|
12103
12387
|
collectedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
12104
12388
|
codebase: {
|
|
12105
|
-
fileCount:
|
|
12106
|
-
totalLines
|
|
12107
|
-
languages:
|
|
12108
|
-
if (t.source.includes("package")) return "typescript";
|
|
12109
|
-
if (t.source.includes("Cargo")) return "rust";
|
|
12110
|
-
if (t.source.includes("go.")) return "go";
|
|
12111
|
-
if (t.source.includes("requirements") || t.source.includes("pyproject")) return "python";
|
|
12112
|
-
return "unknown";
|
|
12113
|
-
}))],
|
|
12389
|
+
fileCount: codeFiles.length,
|
|
12390
|
+
totalLines,
|
|
12391
|
+
languages: languages.length > 0 ? languages : ["typescript"],
|
|
12114
12392
|
keyDirectories: features.map((f) => f.paths[0]?.replace("/**", "") || ""),
|
|
12115
12393
|
symbolCount: 0,
|
|
12116
12394
|
description: "",
|
|
12117
12395
|
architectureNotes: ""
|
|
12118
12396
|
},
|
|
12119
|
-
architecture:
|
|
12397
|
+
architecture: {
|
|
12398
|
+
layers,
|
|
12399
|
+
dataFlow: inferDataFlow(features),
|
|
12400
|
+
keyComponents: [],
|
|
12401
|
+
functionStats: { total: 0, exported: 0 }
|
|
12402
|
+
},
|
|
12120
12403
|
dependencyHotspots: [],
|
|
12121
12404
|
patterns: [],
|
|
12122
12405
|
decisions: [],
|
|
12123
12406
|
riskFiles: [],
|
|
12124
12407
|
deadCode: null,
|
|
12125
|
-
tests: { framework:
|
|
12408
|
+
tests: { framework: testFramework, testCount: 0, coverageGaps: [], uncoveredFunctions: [] },
|
|
12126
12409
|
recentBugs: [],
|
|
12127
12410
|
changeHotspots: [],
|
|
12128
12411
|
activeFeature: null,
|
|
@@ -12134,6 +12417,96 @@ function createMinimalIntelligence(projectPath, technologies, features) {
|
|
|
12134
12417
|
}))
|
|
12135
12418
|
};
|
|
12136
12419
|
}
|
|
12420
|
+
function buildFileTechMap(projectPath, indexedFiles, technologies) {
|
|
12421
|
+
const techNames = new Set(technologies.map((t) => t.name));
|
|
12422
|
+
const fileTechMap = /* @__PURE__ */ new Map();
|
|
12423
|
+
const sourceFiles = indexedFiles.filter(
|
|
12424
|
+
(f) => /\.(ts|tsx|js|jsx)$/.test(f) && !f.includes("node_modules") && !f.includes("dist")
|
|
12425
|
+
);
|
|
12426
|
+
for (const file2 of sourceFiles.slice(0, 300)) {
|
|
12427
|
+
try {
|
|
12428
|
+
const content = readFileSync27(join35(projectPath, file2), "utf-8");
|
|
12429
|
+
const techs = /* @__PURE__ */ new Set();
|
|
12430
|
+
const importRegex = /(?:from\s+['"]|require\s*\(\s*['"])([^./'"@][^'"]*|@[^/'"]+\/[^'"]+)/g;
|
|
12431
|
+
let match;
|
|
12432
|
+
while ((match = importRegex.exec(content)) !== null) {
|
|
12433
|
+
const pkg = match[1] || "";
|
|
12434
|
+
const normalized = pkg.startsWith("@") ? pkg.split("/").slice(0, 2).join("/") : pkg.split("/")[0] || "";
|
|
12435
|
+
if (normalized && techNames.has(normalized)) {
|
|
12436
|
+
techs.add(normalized);
|
|
12437
|
+
}
|
|
12438
|
+
}
|
|
12439
|
+
if (techs.size > 0) {
|
|
12440
|
+
fileTechMap.set(file2, [...techs]);
|
|
12441
|
+
}
|
|
12442
|
+
} catch {
|
|
12443
|
+
}
|
|
12444
|
+
}
|
|
12445
|
+
return fileTechMap;
|
|
12446
|
+
}
|
|
12447
|
+
function extToLanguage(ext) {
|
|
12448
|
+
const map2 = {
|
|
12449
|
+
ts: "typescript",
|
|
12450
|
+
tsx: "typescript",
|
|
12451
|
+
js: "javascript",
|
|
12452
|
+
jsx: "javascript",
|
|
12453
|
+
py: "python",
|
|
12454
|
+
go: "go",
|
|
12455
|
+
rs: "rust",
|
|
12456
|
+
java: "java",
|
|
12457
|
+
rb: "ruby",
|
|
12458
|
+
php: "php",
|
|
12459
|
+
cs: "c#",
|
|
12460
|
+
cpp: "c++",
|
|
12461
|
+
c: "c",
|
|
12462
|
+
h: "c"
|
|
12463
|
+
};
|
|
12464
|
+
return map2[ext] || null;
|
|
12465
|
+
}
|
|
12466
|
+
function inferLayerPurpose(featureName) {
|
|
12467
|
+
const purposes = {
|
|
12468
|
+
core: "Core business logic and domain modules",
|
|
12469
|
+
server: "MCP server, transports, and request handling",
|
|
12470
|
+
storage: "Database access and persistence layer",
|
|
12471
|
+
indexing: "Code indexing, parsing, and symbol extraction",
|
|
12472
|
+
api: "API routes, handlers, and middleware",
|
|
12473
|
+
auth: "Authentication and authorization",
|
|
12474
|
+
billing: "Payment processing and subscription management",
|
|
12475
|
+
test: "Test fixtures, harness, and evaluation scenarios",
|
|
12476
|
+
doc: "Documentation generation and management",
|
|
12477
|
+
knowledge: "AI knowledge system and skill management",
|
|
12478
|
+
cli: "Command-line interface",
|
|
12479
|
+
base: "Base configuration and shared utilities"
|
|
12480
|
+
};
|
|
12481
|
+
return purposes[featureName] || `${featureName} module`;
|
|
12482
|
+
}
|
|
12483
|
+
function inferDataFlow(features) {
|
|
12484
|
+
const names = features.map((f) => f.name);
|
|
12485
|
+
const flow = [];
|
|
12486
|
+
if (names.includes("server") || names.includes("api")) flow.push("Request");
|
|
12487
|
+
if (names.includes("server")) flow.push("Server");
|
|
12488
|
+
if (names.includes("api")) flow.push("API");
|
|
12489
|
+
if (names.includes("core")) flow.push("Core");
|
|
12490
|
+
if (names.includes("storage")) flow.push("Storage");
|
|
12491
|
+
if (names.includes("indexing")) flow.push("Indexer");
|
|
12492
|
+
return flow.length >= 2 ? flow : [];
|
|
12493
|
+
}
|
|
12494
|
+
function detectTestFramework(projectPath) {
|
|
12495
|
+
const pkgPath = join35(projectPath, "package.json");
|
|
12496
|
+
if (existsSync34(pkgPath)) {
|
|
12497
|
+
try {
|
|
12498
|
+
const pkg = JSON.parse(readFileSync27(pkgPath, "utf-8"));
|
|
12499
|
+
const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
12500
|
+
if (allDeps["vitest"]) return "vitest";
|
|
12501
|
+
if (allDeps["jest"]) return "jest";
|
|
12502
|
+
if (allDeps["mocha"]) return "mocha";
|
|
12503
|
+
if (allDeps["tap"]) return "tap";
|
|
12504
|
+
if (pkg.scripts?.test?.includes("--test")) return "node:test";
|
|
12505
|
+
} catch {
|
|
12506
|
+
}
|
|
12507
|
+
}
|
|
12508
|
+
return "unknown";
|
|
12509
|
+
}
|
|
12137
12510
|
var init_orchestrator = __esm({
|
|
12138
12511
|
"src/core/agents/orchestrator.ts"() {
|
|
12139
12512
|
"use strict";
|
|
@@ -12153,7 +12526,7 @@ var init_orchestrator = __esm({
|
|
|
12153
12526
|
|
|
12154
12527
|
// src/core/agents/migration.ts
|
|
12155
12528
|
import { existsSync as existsSync35, readFileSync as readFileSync28, writeFileSync as writeFileSync20, mkdirSync as mkdirSync18, cpSync, readdirSync as readdirSync13 } from "fs";
|
|
12156
|
-
import { join as join36, relative as relative10, dirname as
|
|
12529
|
+
import { join as join36, relative as relative10, dirname as dirname15 } from "path";
|
|
12157
12530
|
function migrateKnowledge(options) {
|
|
12158
12531
|
const { projectPath, dryRun = false, backup = false } = options;
|
|
12159
12532
|
const result = {
|
|
@@ -12195,7 +12568,7 @@ function migrateKnowledge(options) {
|
|
|
12195
12568
|
continue;
|
|
12196
12569
|
}
|
|
12197
12570
|
if (!dryRun) {
|
|
12198
|
-
mkdirSync18(
|
|
12571
|
+
mkdirSync18(dirname15(targetPath), { recursive: true });
|
|
12199
12572
|
cpSync(skillFile, targetPath);
|
|
12200
12573
|
}
|
|
12201
12574
|
result.migrated.push({
|