archbyte 0.4.2 → 0.5.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/README.md +9 -25
- package/bin/archbyte.js +6 -41
- package/dist/agents/static/component-detector.js +71 -107
- package/dist/agents/static/connection-mapper.js +24 -25
- package/dist/agents/static/deep-drill.d.ts +72 -0
- package/dist/agents/static/deep-drill.js +388 -0
- package/dist/agents/static/doc-parser.js +73 -48
- package/dist/agents/static/env-detector.js +3 -6
- package/dist/agents/static/event-detector.js +20 -26
- package/dist/agents/static/infra-analyzer.js +15 -1
- package/dist/agents/static/structure-scanner.js +56 -57
- package/dist/agents/static/taxonomy.d.ts +19 -0
- package/dist/agents/static/taxonomy.js +147 -0
- package/dist/agents/tools/local-fs.js +5 -2
- package/dist/cli/analyze.js +49 -27
- package/dist/cli/license-gate.js +47 -19
- package/dist/cli/run.js +117 -1
- package/dist/cli/setup.d.ts +6 -1
- package/dist/cli/setup.js +35 -16
- package/dist/cli/shared.d.ts +0 -11
- package/dist/cli/shared.js +0 -61
- package/dist/cli/workflow.js +8 -15
- package/dist/server/src/index.js +276 -168
- package/package.json +2 -2
- package/templates/archbyte.yaml +28 -7
- package/ui/dist/assets/index-BQouokNH.css +1 -0
- package/ui/dist/assets/index-QllGSFhe.js +72 -0
- package/ui/dist/index.html +2 -2
- package/dist/cli/arch-diff.d.ts +0 -38
- package/dist/cli/arch-diff.js +0 -61
- package/dist/cli/diff.d.ts +0 -10
- package/dist/cli/diff.js +0 -144
- package/dist/cli/patrol.d.ts +0 -18
- package/dist/cli/patrol.js +0 -596
- package/dist/cli/validate.d.ts +0 -53
- package/dist/cli/validate.js +0 -299
- package/ui/dist/assets/index-DDCNauh7.css +0 -1
- package/ui/dist/assets/index-DO4t5Xu1.js +0 -72
package/dist/cli/run.js
CHANGED
|
@@ -1,8 +1,124 @@
|
|
|
1
|
+
import * as fs from "fs";
|
|
2
|
+
import * as path from "path";
|
|
3
|
+
import chalk from "chalk";
|
|
1
4
|
import { handleAnalyze } from "./analyze.js";
|
|
2
5
|
import { handleServe } from "./serve.js";
|
|
3
|
-
import { DEFAULT_PORT } from "./constants.js";
|
|
6
|
+
import { DEFAULT_PORT, CONFIG_PATH } from "./constants.js";
|
|
7
|
+
import { loadCredentials } from "./auth.js";
|
|
8
|
+
import { resolveConfig } from "./config.js";
|
|
9
|
+
import { requireLicense } from "./license-gate.js";
|
|
10
|
+
import { isTTY } from "./utils.js";
|
|
11
|
+
/**
|
|
12
|
+
* Check if the user has explicitly configured a provider via `archbyte init`.
|
|
13
|
+
* This reads the raw config file — unlike resolveConfig() which auto-detects
|
|
14
|
+
* Claude Code on PATH, env vars, etc. We want to trigger setup only when
|
|
15
|
+
* the user hasn't gone through init yet.
|
|
16
|
+
*/
|
|
17
|
+
function hasExplicitConfig() {
|
|
18
|
+
try {
|
|
19
|
+
if (!fs.existsSync(CONFIG_PATH))
|
|
20
|
+
return false;
|
|
21
|
+
const config = JSON.parse(fs.readFileSync(CONFIG_PATH, "utf-8"));
|
|
22
|
+
return !!config.provider;
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
4
28
|
export async function handleRun(options) {
|
|
5
29
|
const port = options.port || DEFAULT_PORT;
|
|
30
|
+
const isStaticOnly = options.static || options.skipLlm;
|
|
31
|
+
// ─── First-run onboarding: login + provider setup ───
|
|
32
|
+
const creds = loadCredentials();
|
|
33
|
+
const needsLogin = !creds;
|
|
34
|
+
const needsSetup = !hasExplicitConfig() && !isStaticOnly && !options.provider;
|
|
35
|
+
if (needsLogin || needsSetup) {
|
|
36
|
+
const dim = chalk.gray;
|
|
37
|
+
const sep = dim(" ───");
|
|
38
|
+
console.log();
|
|
39
|
+
console.log(chalk.bold.cyan(" Welcome to ArchByte"));
|
|
40
|
+
console.log(dim(" Visual observability for agentic development."));
|
|
41
|
+
console.log(dim(" Understand what your agents are building, in real time."));
|
|
42
|
+
console.log();
|
|
43
|
+
console.log(sep);
|
|
44
|
+
console.log();
|
|
45
|
+
console.log(dim(" Docs ") + chalk.cyan("https://archbyte.heartbyte.io/setup"));
|
|
46
|
+
console.log(dim(" Website ") + chalk.cyan("https://archbyte.heartbyte.io"));
|
|
47
|
+
console.log();
|
|
48
|
+
console.log(sep);
|
|
49
|
+
console.log();
|
|
50
|
+
console.log(dim(" Let's get you set up. This takes about 30 seconds."));
|
|
51
|
+
console.log();
|
|
52
|
+
// Step 1: Login
|
|
53
|
+
if (needsLogin) {
|
|
54
|
+
const { handleLogin } = await import("./auth.js");
|
|
55
|
+
await handleLogin();
|
|
56
|
+
if (!loadCredentials()) {
|
|
57
|
+
console.error(chalk.red("Login required. Run `archbyte login` to try again."));
|
|
58
|
+
process.exit(1);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
// Step 2: Provider setup
|
|
62
|
+
if (needsSetup) {
|
|
63
|
+
const { handleSetup } = await import("./setup.js");
|
|
64
|
+
await handleSetup({ calledFromRun: true });
|
|
65
|
+
}
|
|
66
|
+
// Show config summary and pause before scanning
|
|
67
|
+
const resolvedConfig = resolveConfig();
|
|
68
|
+
const resolvedCreds = loadCredentials();
|
|
69
|
+
const rootDir = options.dir ? path.resolve(options.dir) : process.cwd();
|
|
70
|
+
console.log(sep);
|
|
71
|
+
console.log();
|
|
72
|
+
console.log(" " + chalk.bold("Ready to scan"));
|
|
73
|
+
console.log();
|
|
74
|
+
if (resolvedCreds) {
|
|
75
|
+
console.log(dim(" Account ") + chalk.white(resolvedCreds.email));
|
|
76
|
+
}
|
|
77
|
+
if (resolvedConfig) {
|
|
78
|
+
const providerLabel = resolvedConfig.provider === "claude-sdk"
|
|
79
|
+
? "Claude Code (SDK)"
|
|
80
|
+
: resolvedConfig.provider;
|
|
81
|
+
console.log(dim(" Provider ") + chalk.white(providerLabel));
|
|
82
|
+
if (resolvedConfig.model) {
|
|
83
|
+
console.log(dim(" Model ") + chalk.white(resolvedConfig.model));
|
|
84
|
+
}
|
|
85
|
+
if (resolvedConfig.provider !== "claude-sdk") {
|
|
86
|
+
console.log(dim(" API key ") + (resolvedConfig.apiKey ? chalk.green("configured") : chalk.yellow("not set")));
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
console.log(dim(" Project ") + chalk.white(path.basename(rootDir)));
|
|
90
|
+
console.log(dim(" Directory ") + chalk.white(rootDir));
|
|
91
|
+
console.log();
|
|
92
|
+
// Pause — let the user absorb the config before scanning
|
|
93
|
+
if (isTTY()) {
|
|
94
|
+
await new Promise((resolve) => {
|
|
95
|
+
process.stdout.write(dim(" Press Enter to start analysis (q to quit)..."));
|
|
96
|
+
const stdin = process.stdin;
|
|
97
|
+
stdin.setRawMode(true);
|
|
98
|
+
stdin.resume();
|
|
99
|
+
stdin.setEncoding("utf8");
|
|
100
|
+
const onData = (data) => {
|
|
101
|
+
if (data === "\r" || data === "\n" || data === " ") {
|
|
102
|
+
stdin.setRawMode(false);
|
|
103
|
+
stdin.pause();
|
|
104
|
+
stdin.removeListener("data", onData);
|
|
105
|
+
process.stdout.write("\n\n");
|
|
106
|
+
resolve();
|
|
107
|
+
}
|
|
108
|
+
else if (data === "q" || data === "Q" || data === "\u0003" || data === "\u001b") {
|
|
109
|
+
stdin.setRawMode(false);
|
|
110
|
+
stdin.pause();
|
|
111
|
+
stdin.removeListener("data", onData);
|
|
112
|
+
process.stdout.write("\n");
|
|
113
|
+
process.exit(0);
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
stdin.on("data", onData);
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
// License/usage check (creds guaranteed to exist after onboarding)
|
|
121
|
+
await requireLicense("analyze");
|
|
6
122
|
// 1. Analyze (includes auto-generate)
|
|
7
123
|
await handleAnalyze({
|
|
8
124
|
verbose: options.verbose,
|
package/dist/cli/setup.d.ts
CHANGED
|
@@ -1 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
interface SetupOptions {
|
|
2
|
+
/** When true, skip "archbyte run" in next steps (called from `archbyte run`) */
|
|
3
|
+
calledFromRun?: boolean;
|
|
4
|
+
}
|
|
5
|
+
export declare function handleSetup(opts?: SetupOptions): Promise<void>;
|
|
6
|
+
export {};
|
package/dist/cli/setup.js
CHANGED
|
@@ -207,7 +207,8 @@ async function validateProviderSilent(providerName, apiKey, model) {
|
|
|
207
207
|
function getProfiles(config) {
|
|
208
208
|
return config.profiles ?? {};
|
|
209
209
|
}
|
|
210
|
-
export async function handleSetup() {
|
|
210
|
+
export async function handleSetup(opts) {
|
|
211
|
+
const calledFromRun = opts?.calledFromRun ?? false;
|
|
211
212
|
console.log();
|
|
212
213
|
console.log(chalk.bold.cyan("ArchByte Setup"));
|
|
213
214
|
console.log(chalk.gray("Configure your model provider and API key.\n"));
|
|
@@ -300,12 +301,20 @@ export async function handleSetup() {
|
|
|
300
301
|
console.log();
|
|
301
302
|
console.log(sep);
|
|
302
303
|
console.log();
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
304
|
+
if (calledFromRun) {
|
|
305
|
+
console.log(dim(" Continuing to scan your codebase..."));
|
|
306
|
+
console.log();
|
|
307
|
+
}
|
|
308
|
+
else {
|
|
309
|
+
console.log(" " + chalk.bold("Next steps"));
|
|
310
|
+
console.log();
|
|
311
|
+
console.log(" " + chalk.cyan("archbyte run") + " Analyze your codebase");
|
|
312
|
+
console.log(" " + chalk.cyan("archbyte status") + " Check account and usage");
|
|
313
|
+
console.log(" " + chalk.cyan("archbyte --help") + " See all commands");
|
|
314
|
+
console.log();
|
|
315
|
+
console.log(dim(" Run from your project root, or use --dir <path> to specify the directory."));
|
|
316
|
+
console.log();
|
|
317
|
+
}
|
|
309
318
|
return;
|
|
310
319
|
}
|
|
311
320
|
if (choice === "codex") {
|
|
@@ -588,18 +597,28 @@ export async function handleSetup() {
|
|
|
588
597
|
console.log();
|
|
589
598
|
console.log(sep);
|
|
590
599
|
console.log();
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
600
|
+
if (calledFromRun) {
|
|
601
|
+
if (result === false) {
|
|
602
|
+
console.log(chalk.yellow(" Warning: credentials unverified. Saving anyway."));
|
|
603
|
+
console.log();
|
|
604
|
+
}
|
|
605
|
+
console.log(dim(" Continuing to scan your codebase..."));
|
|
606
|
+
console.log();
|
|
595
607
|
}
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
608
|
+
else {
|
|
609
|
+
console.log(" " + chalk.bold("Next steps"));
|
|
610
|
+
console.log();
|
|
611
|
+
console.log(" " + chalk.cyan("archbyte run") + " Analyze your codebase");
|
|
612
|
+
console.log(" " + chalk.cyan("archbyte status") + " Check account and usage");
|
|
613
|
+
console.log(" " + chalk.cyan("archbyte --help") + " See all commands");
|
|
614
|
+
console.log();
|
|
615
|
+
console.log(dim(" Run from your project root, or use --dir <path> to specify the directory."));
|
|
616
|
+
if (result === false) {
|
|
617
|
+
console.log();
|
|
618
|
+
console.log(chalk.yellow(" Warning: credentials unverified. Saving anyway."));
|
|
619
|
+
}
|
|
599
620
|
console.log();
|
|
600
|
-
console.log(chalk.yellow(" Warning: credentials unverified. Saving anyway."));
|
|
601
621
|
}
|
|
602
|
-
console.log();
|
|
603
622
|
}
|
|
604
623
|
function writeArchbyteReadme(archbyteDir) {
|
|
605
624
|
const readmePath = path.join(archbyteDir, "README.md");
|
package/dist/cli/shared.d.ts
CHANGED
|
@@ -64,16 +64,5 @@ export declare function parseRulesFromYaml(content: string): RuleConfig;
|
|
|
64
64
|
* level: error
|
|
65
65
|
*/
|
|
66
66
|
export declare function parseCustomRulesFromYaml(content: string): CustomRule[];
|
|
67
|
-
/**
|
|
68
|
-
* Parse the patrol.ignore list from archbyte.yaml.
|
|
69
|
-
* Returns user-defined glob patterns for watch mode to ignore.
|
|
70
|
-
*
|
|
71
|
-
* patrol:
|
|
72
|
-
* ignore:
|
|
73
|
-
* - "docs/"
|
|
74
|
-
* - "*.md"
|
|
75
|
-
* - "build/"
|
|
76
|
-
*/
|
|
77
|
-
export declare function loadPatrolIgnore(configPath?: string): string[];
|
|
78
67
|
export declare function getRuleLevel(config: RuleConfig, rule: keyof RuleConfig, defaultLevel: RuleLevel): RuleLevel;
|
|
79
68
|
export declare function getThreshold(config: RuleConfig, rule: "max-connections", defaultVal: number): number;
|
package/dist/cli/shared.js
CHANGED
|
@@ -259,67 +259,6 @@ export function parseCustomRulesFromYaml(content) {
|
|
|
259
259
|
flushItem();
|
|
260
260
|
return rules;
|
|
261
261
|
}
|
|
262
|
-
/**
|
|
263
|
-
* Parse the patrol.ignore list from archbyte.yaml.
|
|
264
|
-
* Returns user-defined glob patterns for watch mode to ignore.
|
|
265
|
-
*
|
|
266
|
-
* patrol:
|
|
267
|
-
* ignore:
|
|
268
|
-
* - "docs/"
|
|
269
|
-
* - "*.md"
|
|
270
|
-
* - "build/"
|
|
271
|
-
*/
|
|
272
|
-
export function loadPatrolIgnore(configPath) {
|
|
273
|
-
const rootDir = process.cwd();
|
|
274
|
-
const yamlPath = configPath
|
|
275
|
-
? path.resolve(rootDir, configPath)
|
|
276
|
-
: path.join(rootDir, ".archbyte", "archbyte.yaml");
|
|
277
|
-
if (!fs.existsSync(yamlPath))
|
|
278
|
-
return [];
|
|
279
|
-
try {
|
|
280
|
-
const lines = fs.readFileSync(yamlPath, "utf-8").split("\n");
|
|
281
|
-
const patterns = [];
|
|
282
|
-
let inPatrol = false;
|
|
283
|
-
let inIgnore = false;
|
|
284
|
-
for (const line of lines) {
|
|
285
|
-
const trimmed = line.trimEnd();
|
|
286
|
-
if (/^patrol:\s*$/.test(trimmed)) {
|
|
287
|
-
inPatrol = true;
|
|
288
|
-
continue;
|
|
289
|
-
}
|
|
290
|
-
// Another top-level section ends patrol
|
|
291
|
-
if (inPatrol && /^\S/.test(trimmed) && !trimmed.startsWith("#")) {
|
|
292
|
-
inPatrol = false;
|
|
293
|
-
inIgnore = false;
|
|
294
|
-
continue;
|
|
295
|
-
}
|
|
296
|
-
if (!inPatrol)
|
|
297
|
-
continue;
|
|
298
|
-
if (trimmed === "" || trimmed.trim().startsWith("#"))
|
|
299
|
-
continue;
|
|
300
|
-
if (/^ {2}ignore:\s*$/.test(trimmed)) {
|
|
301
|
-
inIgnore = true;
|
|
302
|
-
continue;
|
|
303
|
-
}
|
|
304
|
-
// Another patrol sub-key ends ignore
|
|
305
|
-
if (inIgnore && /^ {2}\S/.test(trimmed) && !/^ {2}ignore:/.test(trimmed)) {
|
|
306
|
-
inIgnore = false;
|
|
307
|
-
continue;
|
|
308
|
-
}
|
|
309
|
-
if (!inIgnore)
|
|
310
|
-
continue;
|
|
311
|
-
// List item: " - pattern"
|
|
312
|
-
const itemMatch = trimmed.match(/^ {4}-\s+"?([^"]+)"?\s*$/);
|
|
313
|
-
if (itemMatch) {
|
|
314
|
-
patterns.push(itemMatch[1].trim());
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
return patterns;
|
|
318
|
-
}
|
|
319
|
-
catch {
|
|
320
|
-
return [];
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
262
|
export function getRuleLevel(config, rule, defaultLevel) {
|
|
324
263
|
const entry = config[rule];
|
|
325
264
|
if (!entry)
|
package/dist/cli/workflow.js
CHANGED
|
@@ -8,7 +8,7 @@ const BUILTIN_WORKFLOWS = [
|
|
|
8
8
|
{
|
|
9
9
|
id: "full-analysis",
|
|
10
10
|
name: "Full Analysis Pipeline",
|
|
11
|
-
description: "Complete architecture pipeline: analyze, generate,
|
|
11
|
+
description: "Complete architecture pipeline: analyze, generate, audit, and report",
|
|
12
12
|
steps: [
|
|
13
13
|
{
|
|
14
14
|
id: "generate",
|
|
@@ -17,13 +17,6 @@ const BUILTIN_WORKFLOWS = [
|
|
|
17
17
|
needs: [],
|
|
18
18
|
description: "Generate architecture diagram from analysis JSON",
|
|
19
19
|
},
|
|
20
|
-
{
|
|
21
|
-
id: "validate",
|
|
22
|
-
name: "Validate Architecture",
|
|
23
|
-
command: "archbyte validate",
|
|
24
|
-
needs: ["generate"],
|
|
25
|
-
description: "Run fitness function rules against the architecture",
|
|
26
|
-
},
|
|
27
20
|
{
|
|
28
21
|
id: "stats",
|
|
29
22
|
name: "Architecture Stats",
|
|
@@ -34,23 +27,23 @@ const BUILTIN_WORKFLOWS = [
|
|
|
34
27
|
{
|
|
35
28
|
id: "export",
|
|
36
29
|
name: "Export Mermaid",
|
|
37
|
-
command: "archbyte export --format mermaid",
|
|
30
|
+
command: "archbyte export --format mermaid --output .archbyte/architecture.mmd",
|
|
38
31
|
needs: ["generate"],
|
|
39
|
-
description: "Export architecture as Mermaid diagram",
|
|
32
|
+
description: "Export architecture as Mermaid diagram to .archbyte/architecture.mmd",
|
|
40
33
|
},
|
|
41
34
|
],
|
|
42
35
|
},
|
|
43
36
|
{
|
|
44
37
|
id: "ci-check",
|
|
45
38
|
name: "CI Architecture Check",
|
|
46
|
-
description: "Lightweight CI pipeline:
|
|
39
|
+
description: "Lightweight CI pipeline: audit architecture health",
|
|
47
40
|
steps: [
|
|
48
41
|
{
|
|
49
|
-
id: "
|
|
50
|
-
name: "
|
|
51
|
-
command: "archbyte
|
|
42
|
+
id: "stats",
|
|
43
|
+
name: "Stats",
|
|
44
|
+
command: "archbyte stats --ci",
|
|
52
45
|
needs: [],
|
|
53
|
-
description: "Run
|
|
46
|
+
description: "Run architecture stats in CI mode",
|
|
54
47
|
},
|
|
55
48
|
],
|
|
56
49
|
},
|