archbyte 0.1.0
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/README.md +282 -0
- package/bin/archbyte.js +213 -0
- package/dist/agents/core/component-detector.d.ts +2 -0
- package/dist/agents/core/component-detector.js +57 -0
- package/dist/agents/core/connection-mapper.d.ts +2 -0
- package/dist/agents/core/connection-mapper.js +77 -0
- package/dist/agents/core/doc-parser.d.ts +2 -0
- package/dist/agents/core/doc-parser.js +64 -0
- package/dist/agents/core/env-detector.d.ts +2 -0
- package/dist/agents/core/env-detector.js +51 -0
- package/dist/agents/core/event-detector.d.ts +2 -0
- package/dist/agents/core/event-detector.js +59 -0
- package/dist/agents/core/infra-analyzer.d.ts +2 -0
- package/dist/agents/core/infra-analyzer.js +72 -0
- package/dist/agents/core/structure-scanner.d.ts +2 -0
- package/dist/agents/core/structure-scanner.js +55 -0
- package/dist/agents/core/validator.d.ts +2 -0
- package/dist/agents/core/validator.js +74 -0
- package/dist/agents/index.d.ts +24 -0
- package/dist/agents/index.js +73 -0
- package/dist/agents/llm/index.d.ts +8 -0
- package/dist/agents/llm/index.js +185 -0
- package/dist/agents/llm/prompt-builder.d.ts +3 -0
- package/dist/agents/llm/prompt-builder.js +251 -0
- package/dist/agents/llm/response-parser.d.ts +6 -0
- package/dist/agents/llm/response-parser.js +174 -0
- package/dist/agents/llm/types.d.ts +31 -0
- package/dist/agents/llm/types.js +2 -0
- package/dist/agents/pipeline/agents/component-identifier.d.ts +3 -0
- package/dist/agents/pipeline/agents/component-identifier.js +102 -0
- package/dist/agents/pipeline/agents/connection-mapper.d.ts +3 -0
- package/dist/agents/pipeline/agents/connection-mapper.js +126 -0
- package/dist/agents/pipeline/agents/flow-detector.d.ts +3 -0
- package/dist/agents/pipeline/agents/flow-detector.js +101 -0
- package/dist/agents/pipeline/agents/service-describer.d.ts +3 -0
- package/dist/agents/pipeline/agents/service-describer.js +100 -0
- package/dist/agents/pipeline/agents/validator.d.ts +3 -0
- package/dist/agents/pipeline/agents/validator.js +102 -0
- package/dist/agents/pipeline/index.d.ts +13 -0
- package/dist/agents/pipeline/index.js +128 -0
- package/dist/agents/pipeline/merger.d.ts +7 -0
- package/dist/agents/pipeline/merger.js +212 -0
- package/dist/agents/pipeline/response-parser.d.ts +5 -0
- package/dist/agents/pipeline/response-parser.js +43 -0
- package/dist/agents/pipeline/types.d.ts +92 -0
- package/dist/agents/pipeline/types.js +3 -0
- package/dist/agents/prompt-data.d.ts +1 -0
- package/dist/agents/prompt-data.js +15 -0
- package/dist/agents/prompts-encode.d.ts +9 -0
- package/dist/agents/prompts-encode.js +26 -0
- package/dist/agents/prompts.d.ts +12 -0
- package/dist/agents/prompts.js +30 -0
- package/dist/agents/providers/anthropic.d.ts +10 -0
- package/dist/agents/providers/anthropic.js +117 -0
- package/dist/agents/providers/google.d.ts +10 -0
- package/dist/agents/providers/google.js +136 -0
- package/dist/agents/providers/ollama.d.ts +9 -0
- package/dist/agents/providers/ollama.js +162 -0
- package/dist/agents/providers/openai.d.ts +9 -0
- package/dist/agents/providers/openai.js +142 -0
- package/dist/agents/providers/router.d.ts +7 -0
- package/dist/agents/providers/router.js +55 -0
- package/dist/agents/runtime/orchestrator.d.ts +34 -0
- package/dist/agents/runtime/orchestrator.js +193 -0
- package/dist/agents/runtime/registry.d.ts +23 -0
- package/dist/agents/runtime/registry.js +56 -0
- package/dist/agents/runtime/types.d.ts +117 -0
- package/dist/agents/runtime/types.js +29 -0
- package/dist/agents/static/code-sampler.d.ts +3 -0
- package/dist/agents/static/code-sampler.js +153 -0
- package/dist/agents/static/component-detector.d.ts +3 -0
- package/dist/agents/static/component-detector.js +404 -0
- package/dist/agents/static/connection-mapper.d.ts +3 -0
- package/dist/agents/static/connection-mapper.js +280 -0
- package/dist/agents/static/doc-parser.d.ts +3 -0
- package/dist/agents/static/doc-parser.js +358 -0
- package/dist/agents/static/env-detector.d.ts +3 -0
- package/dist/agents/static/env-detector.js +73 -0
- package/dist/agents/static/event-detector.d.ts +3 -0
- package/dist/agents/static/event-detector.js +70 -0
- package/dist/agents/static/file-tree-collector.d.ts +3 -0
- package/dist/agents/static/file-tree-collector.js +51 -0
- package/dist/agents/static/index.d.ts +19 -0
- package/dist/agents/static/index.js +307 -0
- package/dist/agents/static/infra-analyzer.d.ts +3 -0
- package/dist/agents/static/infra-analyzer.js +208 -0
- package/dist/agents/static/structure-scanner.d.ts +3 -0
- package/dist/agents/static/structure-scanner.js +195 -0
- package/dist/agents/static/types.d.ts +165 -0
- package/dist/agents/static/types.js +2 -0
- package/dist/agents/static/utils.d.ts +21 -0
- package/dist/agents/static/utils.js +146 -0
- package/dist/agents/static/validator.d.ts +2 -0
- package/dist/agents/static/validator.js +75 -0
- package/dist/agents/tools/claude-code.d.ts +38 -0
- package/dist/agents/tools/claude-code.js +129 -0
- package/dist/agents/tools/local-fs.d.ts +12 -0
- package/dist/agents/tools/local-fs.js +112 -0
- package/dist/agents/tools/tool-definitions.d.ts +6 -0
- package/dist/agents/tools/tool-definitions.js +66 -0
- package/dist/cli/analyze.d.ts +27 -0
- package/dist/cli/analyze.js +586 -0
- package/dist/cli/auth.d.ts +46 -0
- package/dist/cli/auth.js +397 -0
- package/dist/cli/config.d.ts +11 -0
- package/dist/cli/config.js +177 -0
- package/dist/cli/diff.d.ts +10 -0
- package/dist/cli/diff.js +144 -0
- package/dist/cli/export.d.ts +10 -0
- package/dist/cli/export.js +321 -0
- package/dist/cli/gate.d.ts +13 -0
- package/dist/cli/gate.js +131 -0
- package/dist/cli/generate.d.ts +10 -0
- package/dist/cli/generate.js +213 -0
- package/dist/cli/license-gate.d.ts +27 -0
- package/dist/cli/license-gate.js +121 -0
- package/dist/cli/patrol.d.ts +15 -0
- package/dist/cli/patrol.js +212 -0
- package/dist/cli/run.d.ts +11 -0
- package/dist/cli/run.js +24 -0
- package/dist/cli/serve.d.ts +9 -0
- package/dist/cli/serve.js +65 -0
- package/dist/cli/setup.d.ts +1 -0
- package/dist/cli/setup.js +233 -0
- package/dist/cli/shared.d.ts +68 -0
- package/dist/cli/shared.js +275 -0
- package/dist/cli/stats.d.ts +9 -0
- package/dist/cli/stats.js +158 -0
- package/dist/cli/ui.d.ts +18 -0
- package/dist/cli/ui.js +144 -0
- package/dist/cli/validate.d.ts +54 -0
- package/dist/cli/validate.js +315 -0
- package/dist/cli/workflow.d.ts +10 -0
- package/dist/cli/workflow.js +594 -0
- package/dist/server/src/generator/index.d.ts +123 -0
- package/dist/server/src/generator/index.js +254 -0
- package/dist/server/src/index.d.ts +8 -0
- package/dist/server/src/index.js +1311 -0
- package/package.json +62 -0
- package/ui/dist/assets/index-B66Til39.js +70 -0
- package/ui/dist/assets/index-BE2OWbzu.css +1 -0
- package/ui/dist/index.html +14 -0
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
// Pipeline Agent — Component Identifier
|
|
2
|
+
// Parallel, fast tier: identifies all architecturally significant components
|
|
3
|
+
import { extractJSON } from "../response-parser.js";
|
|
4
|
+
import { getPrompt } from "../../prompts.js";
|
|
5
|
+
import "../../prompt-data.js";
|
|
6
|
+
function formatFileTree(ctx) {
|
|
7
|
+
// Show directories + key files only (not all 1000+ files) to stay within context limits
|
|
8
|
+
const lines = [];
|
|
9
|
+
const MAX_LINES = 300;
|
|
10
|
+
function walk(entries, indent) {
|
|
11
|
+
for (const e of entries) {
|
|
12
|
+
if (lines.length >= MAX_LINES)
|
|
13
|
+
return;
|
|
14
|
+
if (e.type === "directory") {
|
|
15
|
+
const fileCount = e.children?.filter((c) => c.type === "file").length ?? 0;
|
|
16
|
+
const dirCount = e.children?.filter((c) => c.type === "directory").length ?? 0;
|
|
17
|
+
lines.push(`${" ".repeat(indent)}${e.path}/ (${fileCount} files, ${dirCount} dirs)`);
|
|
18
|
+
if (e.children)
|
|
19
|
+
walk(e.children, indent + 1);
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
// Only show key files at top level or config-like files
|
|
23
|
+
if (indent <= 1 || isKeyFile(e.path)) {
|
|
24
|
+
lines.push(`${" ".repeat(indent)}${e.path}`);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
walk(ctx.fileTree.tree, 0);
|
|
30
|
+
if (lines.length >= MAX_LINES)
|
|
31
|
+
lines.push("... (truncated)");
|
|
32
|
+
return lines.join("\n");
|
|
33
|
+
}
|
|
34
|
+
function isKeyFile(path) {
|
|
35
|
+
const name = path.split("/").pop() ?? "";
|
|
36
|
+
return /^(package\.json|Cargo\.toml|go\.mod|pyproject\.toml|Dockerfile|docker-compose|compose|Makefile|README|tsconfig|index\.(ts|js)|main\.(ts|js|py|go|rs)|app\.(ts|js|py)|server\.(ts|js))/i.test(name);
|
|
37
|
+
}
|
|
38
|
+
function formatConfigs(ctx) {
|
|
39
|
+
return ctx.codeSamples.configFiles
|
|
40
|
+
.map((cf) => `--- ${cf.path} ---\n${cf.content}`)
|
|
41
|
+
.join("\n\n");
|
|
42
|
+
}
|
|
43
|
+
export const componentIdentifier = {
|
|
44
|
+
id: "component-identifier",
|
|
45
|
+
name: "Component Identifier",
|
|
46
|
+
modelTier: "fast",
|
|
47
|
+
phase: "parallel",
|
|
48
|
+
buildPrompt(ctx) {
|
|
49
|
+
const system = getPrompt("pipeline/component-identifier");
|
|
50
|
+
const fileTree = formatFileTree(ctx);
|
|
51
|
+
const configs = formatConfigs(ctx);
|
|
52
|
+
const structureInfo = [
|
|
53
|
+
`Project: ${ctx.structure.projectName || "(unknown)"}`,
|
|
54
|
+
`Language: ${ctx.structure.language}`,
|
|
55
|
+
`Languages: ${ctx.structure.languages.join(", ") || "none detected"}`,
|
|
56
|
+
`Framework: ${ctx.structure.framework ?? "none"}`,
|
|
57
|
+
`Monorepo: ${ctx.structure.isMonorepo} ${ctx.structure.monorepoTool ? `(${ctx.structure.monorepoTool})` : ""}`,
|
|
58
|
+
`Build: ${ctx.structure.buildSystem ?? "none"}`,
|
|
59
|
+
`Entry points: ${ctx.structure.entryPoints.join(", ") || "none"}`,
|
|
60
|
+
].join("\n");
|
|
61
|
+
const docNotes = ctx.docs.architectureNotes.length > 0
|
|
62
|
+
? `\n\nArchitecture notes from docs:\n${ctx.docs.architectureNotes.join("\n")}`
|
|
63
|
+
: "";
|
|
64
|
+
const dockerInfo = ctx.infra.docker.composeFile
|
|
65
|
+
? `\n\nDocker Compose services:\n${ctx.infra.docker.services.map((s) => `- ${s.name}${s.image ? ` (image: ${s.image})` : ""}${s.buildContext ? ` (build: ${s.buildContext})` : ""}${s.dependsOn?.length ? ` depends_on: ${s.dependsOn.join(", ")}` : ""}`).join("\n")}`
|
|
66
|
+
: "";
|
|
67
|
+
const user = `Analyze this project and identify ALL architecturally significant components.
|
|
68
|
+
|
|
69
|
+
${structureInfo}
|
|
70
|
+
${docNotes}
|
|
71
|
+
${dockerInfo}
|
|
72
|
+
|
|
73
|
+
## File Tree (depth 3, ${ctx.fileTree.totalFiles} files, ${ctx.fileTree.totalDirs} dirs)
|
|
74
|
+
${fileTree}
|
|
75
|
+
|
|
76
|
+
## Configuration Files
|
|
77
|
+
${configs}`;
|
|
78
|
+
return { system, user };
|
|
79
|
+
},
|
|
80
|
+
parseResponse(raw) {
|
|
81
|
+
const parsed = extractJSON(raw);
|
|
82
|
+
if (!parsed || !Array.isArray(parsed.components))
|
|
83
|
+
return null;
|
|
84
|
+
const components = [];
|
|
85
|
+
for (const c of parsed.components) {
|
|
86
|
+
if (typeof c !== "object" || !c)
|
|
87
|
+
continue;
|
|
88
|
+
if (typeof c.id !== "string" || typeof c.name !== "string")
|
|
89
|
+
continue;
|
|
90
|
+
components.push({
|
|
91
|
+
id: c.id,
|
|
92
|
+
name: c.name,
|
|
93
|
+
type: typeof c.type === "string" ? c.type : "service",
|
|
94
|
+
layer: typeof c.layer === "string" ? c.layer : "application",
|
|
95
|
+
path: typeof c.path === "string" ? c.path : "",
|
|
96
|
+
description: typeof c.description === "string" ? c.description : "",
|
|
97
|
+
technologies: Array.isArray(c.technologies) ? c.technologies.filter((t) => typeof t === "string") : [],
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
return components.length > 0 ? { components } : null;
|
|
101
|
+
},
|
|
102
|
+
};
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
// Pipeline Agent — Connection Mapper
|
|
2
|
+
// Sequential, standard tier: maps ALL connections between components
|
|
3
|
+
import { extractJSON } from "../response-parser.js";
|
|
4
|
+
import { getPrompt } from "../../prompts.js";
|
|
5
|
+
import "../../prompt-data.js";
|
|
6
|
+
export const connectionMapper = {
|
|
7
|
+
id: "connection-mapper",
|
|
8
|
+
name: "Connection Mapper",
|
|
9
|
+
modelTier: "standard",
|
|
10
|
+
phase: "sequential",
|
|
11
|
+
buildPrompt(ctx, priorResults) {
|
|
12
|
+
const system = getPrompt("pipeline/connection-mapper");
|
|
13
|
+
const parts = [];
|
|
14
|
+
// Components from Phase 1
|
|
15
|
+
const components = priorResults?.["component-identifier"];
|
|
16
|
+
if (components?.components) {
|
|
17
|
+
parts.push("## Components (use these exact IDs)");
|
|
18
|
+
for (const c of components.components) {
|
|
19
|
+
parts.push(`- ${c.id}: ${c.name} (type=${c.type}, path=${c.path}, tech=[${(c.technologies || []).join(", ")}])`);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
// Databases and external services from Phase 1
|
|
23
|
+
const services = priorResults?.["service-describer"];
|
|
24
|
+
if (services?.databases?.length) {
|
|
25
|
+
parts.push("\n## Databases");
|
|
26
|
+
for (const db of services.databases) {
|
|
27
|
+
parts.push(`- ${db.id}: ${db.name} (${db.type})`);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
if (services?.externalServices?.length) {
|
|
31
|
+
parts.push("\n## External Services");
|
|
32
|
+
for (const svc of services.externalServices) {
|
|
33
|
+
parts.push(`- ${svc.id}: ${svc.name} (${svc.type})`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
// Event connections from Phase 1
|
|
37
|
+
const flows = priorResults?.["flow-detector"];
|
|
38
|
+
if (flows?.eventConnections?.length) {
|
|
39
|
+
parts.push("\n## Detected Event Patterns");
|
|
40
|
+
for (const ec of flows.eventConnections) {
|
|
41
|
+
parts.push(`- ${ec.publisher} → ${ec.subscriber} via ${ec.channel} (${ec.technology})`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
if (flows?.apiRoutes?.length) {
|
|
45
|
+
parts.push("\n## Detected API Routes");
|
|
46
|
+
for (const ar of flows.apiRoutes.slice(0, 30)) {
|
|
47
|
+
parts.push(`- ${ar.method} ${ar.path} (${ar.handlerFile})`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
// Import map
|
|
51
|
+
const importEntries = Object.entries(ctx.codeSamples.importMap);
|
|
52
|
+
if (importEntries.length > 0) {
|
|
53
|
+
parts.push(`\n## Import Graph (${importEntries.length} files)`);
|
|
54
|
+
// Summarize by directory to keep it concise
|
|
55
|
+
const dirImports = {};
|
|
56
|
+
for (const [file, imports] of importEntries) {
|
|
57
|
+
const dir = file.includes("/") ? file.substring(0, file.lastIndexOf("/")) : ".";
|
|
58
|
+
if (!dirImports[dir])
|
|
59
|
+
dirImports[dir] = new Set();
|
|
60
|
+
for (const imp of imports) {
|
|
61
|
+
if (imp.startsWith(".") || imp.startsWith("/"))
|
|
62
|
+
continue; // skip relative
|
|
63
|
+
dirImports[dir].add(imp);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
for (const [dir, imports] of Object.entries(dirImports)) {
|
|
67
|
+
if (imports.size > 0) {
|
|
68
|
+
parts.push(` ${dir}/: imports [${[...imports].slice(0, 10).join(", ")}]`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
// Docker depends_on
|
|
73
|
+
if (ctx.infra.docker.composeFile) {
|
|
74
|
+
const deps = ctx.infra.docker.services
|
|
75
|
+
.filter((s) => s.dependsOn?.length)
|
|
76
|
+
.map((s) => `${s.name} → ${s.dependsOn.join(", ")}`);
|
|
77
|
+
if (deps.length > 0) {
|
|
78
|
+
parts.push(`\n## Docker depends_on\n${deps.join("\n")}`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
// Kubernetes resources
|
|
82
|
+
if (ctx.infra.kubernetes.resources.length > 0) {
|
|
83
|
+
parts.push("\n## Kubernetes Resources");
|
|
84
|
+
for (const r of ctx.infra.kubernetes.resources) {
|
|
85
|
+
parts.push(`- ${r.kind}: ${r.name}${r.namespace ? ` (ns=${r.namespace})` : ""}`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return { system, user: parts.join("\n") };
|
|
89
|
+
},
|
|
90
|
+
parseResponse(raw) {
|
|
91
|
+
const parsed = extractJSON(raw);
|
|
92
|
+
if (!parsed)
|
|
93
|
+
return null;
|
|
94
|
+
const result = {
|
|
95
|
+
connections: [],
|
|
96
|
+
flows: [],
|
|
97
|
+
};
|
|
98
|
+
if (Array.isArray(parsed.connections)) {
|
|
99
|
+
for (const c of parsed.connections) {
|
|
100
|
+
if (typeof c === "object" && c &&
|
|
101
|
+
typeof c.from === "string" && typeof c.to === "string" &&
|
|
102
|
+
c.from !== c.to) {
|
|
103
|
+
result.connections.push({
|
|
104
|
+
from: c.from,
|
|
105
|
+
to: c.to,
|
|
106
|
+
type: typeof c.type === "string" ? c.type : "import",
|
|
107
|
+
description: typeof c.description === "string" ? c.description : "",
|
|
108
|
+
async: typeof c.async === "boolean" ? c.async : false,
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
if (Array.isArray(parsed.flows)) {
|
|
114
|
+
for (const f of parsed.flows) {
|
|
115
|
+
if (typeof f === "object" && f && typeof f.name === "string") {
|
|
116
|
+
result.flows.push({
|
|
117
|
+
name: f.name,
|
|
118
|
+
description: typeof f.description === "string" ? f.description : "",
|
|
119
|
+
steps: Array.isArray(f.steps) ? f.steps.filter((s) => typeof s === "string") : [],
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return result;
|
|
125
|
+
},
|
|
126
|
+
};
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
// Pipeline Agent — Flow Detector
|
|
2
|
+
// Parallel, fast tier: identifies event-driven patterns and API routes
|
|
3
|
+
import { extractJSON } from "../response-parser.js";
|
|
4
|
+
import { getPrompt } from "../../prompts.js";
|
|
5
|
+
import "../../prompt-data.js";
|
|
6
|
+
export const flowDetector = {
|
|
7
|
+
id: "flow-detector",
|
|
8
|
+
name: "Flow Detector",
|
|
9
|
+
modelTier: "fast",
|
|
10
|
+
phase: "parallel",
|
|
11
|
+
buildPrompt(ctx) {
|
|
12
|
+
const system = getPrompt("pipeline/flow-detector");
|
|
13
|
+
const parts = [];
|
|
14
|
+
// Event patterns from static scanner
|
|
15
|
+
if (ctx.events.hasEDA) {
|
|
16
|
+
parts.push("Event-driven patterns detected:");
|
|
17
|
+
for (const p of ctx.events.patterns) {
|
|
18
|
+
parts.push(` Technology: ${p.technology} (dep: ${p.dependency})`);
|
|
19
|
+
}
|
|
20
|
+
parts.push("\nEvent occurrences in code:");
|
|
21
|
+
for (const e of ctx.events.events.slice(0, 30)) {
|
|
22
|
+
parts.push(` [${e.type}] ${e.file}: ${e.pattern}`);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
parts.push("No event-driven patterns detected by static scanner.");
|
|
27
|
+
}
|
|
28
|
+
// API endpoints from docs
|
|
29
|
+
if (ctx.docs.apiEndpoints.length > 0) {
|
|
30
|
+
parts.push(`\nAPI endpoints from docs (${ctx.docs.apiEndpoints.length}):`);
|
|
31
|
+
for (const ep of ctx.docs.apiEndpoints.slice(0, 20)) {
|
|
32
|
+
parts.push(` ${ep.method} ${ep.path} — ${ep.description}`);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
// Route file samples
|
|
36
|
+
const routeSamples = ctx.codeSamples.samples.filter((s) => s.category === "route-file");
|
|
37
|
+
if (routeSamples.length > 0) {
|
|
38
|
+
parts.push("\nRoute file excerpts:");
|
|
39
|
+
for (const s of routeSamples.slice(0, 5)) {
|
|
40
|
+
parts.push(`\n--- ${s.path} ---\n${s.excerpt}`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
// Entry points for context
|
|
44
|
+
const entrySamples = ctx.codeSamples.samples.filter((s) => s.category === "entry-point");
|
|
45
|
+
if (entrySamples.length > 0) {
|
|
46
|
+
parts.push("\nEntry point excerpts:");
|
|
47
|
+
for (const s of entrySamples.slice(0, 3)) {
|
|
48
|
+
parts.push(`\n--- ${s.path} ---\n${s.excerpt}`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
// Docker info for queue/broker identification
|
|
52
|
+
if (ctx.infra.docker.composeFile) {
|
|
53
|
+
const queueServices = ctx.infra.docker.services.filter((s) => {
|
|
54
|
+
const img = (s.image ?? "").toLowerCase();
|
|
55
|
+
return img.includes("rabbit") || img.includes("kafka") || img.includes("redis") ||
|
|
56
|
+
img.includes("nats") || img.includes("pulsar");
|
|
57
|
+
});
|
|
58
|
+
if (queueServices.length > 0) {
|
|
59
|
+
parts.push("\nMessage broker/queue Docker services:");
|
|
60
|
+
for (const s of queueServices) {
|
|
61
|
+
parts.push(` ${s.name} (image: ${s.image})`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return { system, user: parts.join("\n") };
|
|
66
|
+
},
|
|
67
|
+
parseResponse(raw) {
|
|
68
|
+
const parsed = extractJSON(raw);
|
|
69
|
+
if (!parsed)
|
|
70
|
+
return null;
|
|
71
|
+
const result = {
|
|
72
|
+
eventConnections: [],
|
|
73
|
+
apiRoutes: [],
|
|
74
|
+
};
|
|
75
|
+
if (Array.isArray(parsed.eventConnections)) {
|
|
76
|
+
for (const ec of parsed.eventConnections) {
|
|
77
|
+
if (typeof ec === "object" && ec &&
|
|
78
|
+
typeof ec.publisher === "string" && typeof ec.subscriber === "string") {
|
|
79
|
+
result.eventConnections.push({
|
|
80
|
+
publisher: ec.publisher,
|
|
81
|
+
subscriber: ec.subscriber,
|
|
82
|
+
channel: typeof ec.channel === "string" ? ec.channel : "",
|
|
83
|
+
technology: typeof ec.technology === "string" ? ec.technology : "unknown",
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
if (Array.isArray(parsed.apiRoutes)) {
|
|
89
|
+
for (const ar of parsed.apiRoutes) {
|
|
90
|
+
if (typeof ar === "object" && ar && typeof ar.path === "string") {
|
|
91
|
+
result.apiRoutes.push({
|
|
92
|
+
path: ar.path,
|
|
93
|
+
method: typeof ar.method === "string" ? ar.method : "GET",
|
|
94
|
+
handlerFile: typeof ar.handlerFile === "string" ? ar.handlerFile : "",
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return result;
|
|
100
|
+
},
|
|
101
|
+
};
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
// Pipeline Agent — Service Describer
|
|
2
|
+
// Parallel, fast tier: identifies project description, primary language, databases, external services
|
|
3
|
+
import { extractJSON } from "../response-parser.js";
|
|
4
|
+
import { getPrompt } from "../../prompts.js";
|
|
5
|
+
import "../../prompt-data.js";
|
|
6
|
+
export const serviceDescriber = {
|
|
7
|
+
id: "service-describer",
|
|
8
|
+
name: "Service Describer",
|
|
9
|
+
modelTier: "fast",
|
|
10
|
+
phase: "parallel",
|
|
11
|
+
buildPrompt(ctx) {
|
|
12
|
+
const system = getPrompt("pipeline/service-describer");
|
|
13
|
+
const parts = [];
|
|
14
|
+
// Structure info
|
|
15
|
+
parts.push(`Project: ${ctx.structure.projectName || "(unknown)"}`);
|
|
16
|
+
parts.push(`Detected language: ${ctx.structure.language}`);
|
|
17
|
+
parts.push(`Languages: ${ctx.structure.languages.join(", ") || "none"}`);
|
|
18
|
+
parts.push(`Framework: ${ctx.structure.framework ?? "none"}`);
|
|
19
|
+
// Docs
|
|
20
|
+
if (ctx.docs.projectDescription) {
|
|
21
|
+
parts.push(`\nFrom docs: ${ctx.docs.projectDescription}`);
|
|
22
|
+
}
|
|
23
|
+
if (ctx.docs.externalDependencies.length > 0) {
|
|
24
|
+
parts.push(`\nExternal dependencies mentioned: ${ctx.docs.externalDependencies.join(", ")}`);
|
|
25
|
+
}
|
|
26
|
+
// Docker services
|
|
27
|
+
if (ctx.infra.docker.composeFile) {
|
|
28
|
+
const svcInfo = ctx.infra.docker.services.map((s) => {
|
|
29
|
+
const details = [s.name];
|
|
30
|
+
if (s.image)
|
|
31
|
+
details.push(`image=${s.image}`);
|
|
32
|
+
if (s.ports?.length)
|
|
33
|
+
details.push(`ports=${s.ports.join(",")}`);
|
|
34
|
+
if (s.environment) {
|
|
35
|
+
const envKeys = Object.keys(s.environment).join(", ");
|
|
36
|
+
details.push(`env=[${envKeys}]`);
|
|
37
|
+
}
|
|
38
|
+
return details.join(" ");
|
|
39
|
+
});
|
|
40
|
+
parts.push(`\nDocker services:\n${svcInfo.join("\n")}`);
|
|
41
|
+
}
|
|
42
|
+
// Env vars
|
|
43
|
+
if (ctx.envs.environments.length > 0) {
|
|
44
|
+
for (const env of ctx.envs.environments) {
|
|
45
|
+
parts.push(`\nEnv file "${env.name}" variables: ${env.variables.join(", ")}`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
// Code samples (entry points)
|
|
49
|
+
const entrySamples = ctx.codeSamples.samples.filter((s) => s.category === "entry-point");
|
|
50
|
+
if (entrySamples.length > 0) {
|
|
51
|
+
parts.push("\nEntry point excerpts:");
|
|
52
|
+
for (const s of entrySamples.slice(0, 5)) {
|
|
53
|
+
parts.push(`\n--- ${s.path} ---\n${s.excerpt}`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
// Cloud info
|
|
57
|
+
if (ctx.infra.cloud.provider) {
|
|
58
|
+
parts.push(`\nCloud: ${ctx.infra.cloud.provider}, services: ${ctx.infra.cloud.services.join(", ")}`);
|
|
59
|
+
}
|
|
60
|
+
return { system, user: parts.join("\n") };
|
|
61
|
+
},
|
|
62
|
+
parseResponse(raw) {
|
|
63
|
+
const parsed = extractJSON(raw);
|
|
64
|
+
if (!parsed)
|
|
65
|
+
return null;
|
|
66
|
+
const result = {
|
|
67
|
+
projectDescription: typeof parsed.projectDescription === "string" ? parsed.projectDescription : "",
|
|
68
|
+
primaryLanguage: typeof parsed.primaryLanguage === "string" ? parsed.primaryLanguage : "",
|
|
69
|
+
databases: [],
|
|
70
|
+
externalServices: [],
|
|
71
|
+
};
|
|
72
|
+
if (Array.isArray(parsed.databases)) {
|
|
73
|
+
for (const db of parsed.databases) {
|
|
74
|
+
if (typeof db === "object" && db && typeof db.id === "string" && typeof db.name === "string") {
|
|
75
|
+
result.databases.push({
|
|
76
|
+
id: db.id,
|
|
77
|
+
name: db.name,
|
|
78
|
+
type: typeof db.type === "string" ? db.type : "unknown",
|
|
79
|
+
description: typeof db.description === "string" ? db.description : "",
|
|
80
|
+
usedBy: Array.isArray(db.usedBy) ? db.usedBy.filter((x) => typeof x === "string") : [],
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
if (Array.isArray(parsed.externalServices)) {
|
|
86
|
+
for (const svc of parsed.externalServices) {
|
|
87
|
+
if (typeof svc === "object" && svc && typeof svc.id === "string" && typeof svc.name === "string") {
|
|
88
|
+
result.externalServices.push({
|
|
89
|
+
id: svc.id,
|
|
90
|
+
name: svc.name,
|
|
91
|
+
type: typeof svc.type === "string" ? svc.type : "unknown",
|
|
92
|
+
description: typeof svc.description === "string" ? svc.description : "",
|
|
93
|
+
usedBy: Array.isArray(svc.usedBy) ? svc.usedBy.filter((x) => typeof x === "string") : [],
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return result;
|
|
99
|
+
},
|
|
100
|
+
};
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
// Pipeline Agent — Validator
|
|
2
|
+
// Sequential, fast tier: validates complete analysis, suggests corrections
|
|
3
|
+
import { extractJSON } from "../response-parser.js";
|
|
4
|
+
import { getPrompt } from "../../prompts.js";
|
|
5
|
+
import "../../prompt-data.js";
|
|
6
|
+
export const validator = {
|
|
7
|
+
id: "validator",
|
|
8
|
+
name: "Validator",
|
|
9
|
+
modelTier: "fast",
|
|
10
|
+
phase: "sequential",
|
|
11
|
+
buildPrompt(ctx, priorResults) {
|
|
12
|
+
const system = getPrompt("pipeline/validator");
|
|
13
|
+
const parts = [];
|
|
14
|
+
// Components
|
|
15
|
+
const components = priorResults?.["component-identifier"];
|
|
16
|
+
if (components?.components) {
|
|
17
|
+
parts.push("## Components");
|
|
18
|
+
for (const c of components.components) {
|
|
19
|
+
parts.push(`- ${c.id}: ${c.name} (type=${c.type}, layer=${c.layer}, path=${c.path})`);
|
|
20
|
+
parts.push(` description: ${c.description || "(none)"}`);
|
|
21
|
+
parts.push(` tech: [${(c.technologies || []).join(", ")}]`);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
// Services
|
|
25
|
+
const services = priorResults?.["service-describer"];
|
|
26
|
+
if (services?.databases?.length) {
|
|
27
|
+
parts.push("\n## Databases");
|
|
28
|
+
for (const db of services.databases) {
|
|
29
|
+
parts.push(`- ${db.id}: ${db.name} (${db.type}) — ${db.description}`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
if (services?.externalServices?.length) {
|
|
33
|
+
parts.push("\n## External Services");
|
|
34
|
+
for (const svc of services.externalServices) {
|
|
35
|
+
parts.push(`- ${svc.id}: ${svc.name} (${svc.type}) — ${svc.description}`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
// Connections
|
|
39
|
+
const connections = priorResults?.["connection-mapper"];
|
|
40
|
+
if (connections?.connections) {
|
|
41
|
+
parts.push("\n## Connections");
|
|
42
|
+
for (const c of connections.connections) {
|
|
43
|
+
parts.push(`- ${c.from} → ${c.to} (${c.type}) ${c.async ? "[async]" : ""}: ${c.description}`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
// Structure context for validation
|
|
47
|
+
parts.push(`\n## Project Context`);
|
|
48
|
+
parts.push(`Language: ${ctx.structure.language}`);
|
|
49
|
+
parts.push(`Framework: ${ctx.structure.framework ?? "none"}`);
|
|
50
|
+
parts.push(`Monorepo: ${ctx.structure.isMonorepo}`);
|
|
51
|
+
if (ctx.docs.projectDescription) {
|
|
52
|
+
parts.push(`Description: ${ctx.docs.projectDescription}`);
|
|
53
|
+
}
|
|
54
|
+
return { system, user: parts.join("\n") };
|
|
55
|
+
},
|
|
56
|
+
parseResponse(raw) {
|
|
57
|
+
const parsed = extractJSON(raw);
|
|
58
|
+
if (!parsed)
|
|
59
|
+
return null;
|
|
60
|
+
const result = {
|
|
61
|
+
componentTypeCorrections: {},
|
|
62
|
+
componentDescriptions: {},
|
|
63
|
+
addedConnections: [],
|
|
64
|
+
removedConnectionKeys: [],
|
|
65
|
+
confidence: typeof parsed.confidence === "number" ? parsed.confidence : 0.7,
|
|
66
|
+
issues: Array.isArray(parsed.issues) ? parsed.issues.filter((i) => typeof i === "string") : [],
|
|
67
|
+
};
|
|
68
|
+
if (parsed.componentTypeCorrections && typeof parsed.componentTypeCorrections === "object") {
|
|
69
|
+
for (const [id, type] of Object.entries(parsed.componentTypeCorrections)) {
|
|
70
|
+
if (typeof type === "string") {
|
|
71
|
+
result.componentTypeCorrections[id] = type;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
if (parsed.componentDescriptions && typeof parsed.componentDescriptions === "object") {
|
|
76
|
+
for (const [id, desc] of Object.entries(parsed.componentDescriptions)) {
|
|
77
|
+
if (typeof desc === "string" && desc.length > 0) {
|
|
78
|
+
result.componentDescriptions[id] = desc;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
if (Array.isArray(parsed.addedConnections)) {
|
|
83
|
+
for (const c of parsed.addedConnections) {
|
|
84
|
+
if (typeof c === "object" && c &&
|
|
85
|
+
typeof c.from === "string" && typeof c.to === "string" &&
|
|
86
|
+
c.from !== c.to) {
|
|
87
|
+
result.addedConnections.push({
|
|
88
|
+
from: c.from,
|
|
89
|
+
to: c.to,
|
|
90
|
+
type: typeof c.type === "string" ? c.type : "import",
|
|
91
|
+
description: typeof c.description === "string" ? c.description : "",
|
|
92
|
+
async: typeof c.async === "boolean" ? c.async : false,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
if (Array.isArray(parsed.removedConnectionKeys)) {
|
|
98
|
+
result.removedConnectionKeys = parsed.removedConnectionKeys.filter((k) => typeof k === "string");
|
|
99
|
+
}
|
|
100
|
+
return result;
|
|
101
|
+
},
|
|
102
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { StaticContext } from "../static/types.js";
|
|
2
|
+
import type { StaticAnalysisResult } from "../static/types.js";
|
|
3
|
+
import type { LLMProvider, ArchByteConfig } from "../runtime/types.js";
|
|
4
|
+
/**
|
|
5
|
+
* Run the multi-agent pipeline: 3 parallel fast agents → 2 sequential agents.
|
|
6
|
+
* Each agent gets a single chat() call with pre-collected static context.
|
|
7
|
+
*/
|
|
8
|
+
export declare function runPipeline(ctx: StaticContext, provider: LLMProvider, config: ArchByteConfig, onProgress?: (msg: string) => void): Promise<StaticAnalysisResult & {
|
|
9
|
+
tokenUsage?: {
|
|
10
|
+
input: number;
|
|
11
|
+
output: number;
|
|
12
|
+
};
|
|
13
|
+
}>;
|