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.
Files changed (38) hide show
  1. package/README.md +9 -25
  2. package/bin/archbyte.js +6 -41
  3. package/dist/agents/static/component-detector.js +71 -107
  4. package/dist/agents/static/connection-mapper.js +24 -25
  5. package/dist/agents/static/deep-drill.d.ts +72 -0
  6. package/dist/agents/static/deep-drill.js +388 -0
  7. package/dist/agents/static/doc-parser.js +73 -48
  8. package/dist/agents/static/env-detector.js +3 -6
  9. package/dist/agents/static/event-detector.js +20 -26
  10. package/dist/agents/static/infra-analyzer.js +15 -1
  11. package/dist/agents/static/structure-scanner.js +56 -57
  12. package/dist/agents/static/taxonomy.d.ts +19 -0
  13. package/dist/agents/static/taxonomy.js +147 -0
  14. package/dist/agents/tools/local-fs.js +5 -2
  15. package/dist/cli/analyze.js +49 -27
  16. package/dist/cli/license-gate.js +47 -19
  17. package/dist/cli/run.js +117 -1
  18. package/dist/cli/setup.d.ts +6 -1
  19. package/dist/cli/setup.js +35 -16
  20. package/dist/cli/shared.d.ts +0 -11
  21. package/dist/cli/shared.js +0 -61
  22. package/dist/cli/workflow.js +8 -15
  23. package/dist/server/src/index.js +276 -168
  24. package/package.json +2 -2
  25. package/templates/archbyte.yaml +28 -7
  26. package/ui/dist/assets/index-BQouokNH.css +1 -0
  27. package/ui/dist/assets/index-QllGSFhe.js +72 -0
  28. package/ui/dist/index.html +2 -2
  29. package/dist/cli/arch-diff.d.ts +0 -38
  30. package/dist/cli/arch-diff.js +0 -61
  31. package/dist/cli/diff.d.ts +0 -10
  32. package/dist/cli/diff.js +0 -144
  33. package/dist/cli/patrol.d.ts +0 -18
  34. package/dist/cli/patrol.js +0 -596
  35. package/dist/cli/validate.d.ts +0 -53
  36. package/dist/cli/validate.js +0 -299
  37. package/ui/dist/assets/index-DDCNauh7.css +0 -1
  38. 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,
@@ -1 +1,6 @@
1
- export declare function handleSetup(): Promise<void>;
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
- console.log(" " + chalk.bold("Next steps"));
304
- console.log();
305
- console.log(" " + chalk.cyan("archbyte run") + " Analyze your codebase");
306
- console.log(" " + chalk.cyan("archbyte status") + " Check account and usage");
307
- console.log(" " + chalk.cyan("archbyte --help") + " See all commands");
308
- console.log();
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
- console.log(" " + chalk.bold("Next steps"));
592
- console.log();
593
- console.log(" " + chalk.cyan("archbyte run") + " Analyze your codebase");
594
- if (hasClaude || hasCodex) {
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
- console.log(" " + chalk.cyan("archbyte status") + " Check account and usage");
597
- console.log(" " + chalk.cyan("archbyte --help") + " See all commands");
598
- if (result === false) {
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");
@@ -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;
@@ -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)
@@ -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, validate, and report",
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: validate and diff against baseline",
39
+ description: "Lightweight CI pipeline: audit architecture health",
47
40
  steps: [
48
41
  {
49
- id: "validate",
50
- name: "Validate",
51
- command: "archbyte validate --ci",
42
+ id: "stats",
43
+ name: "Stats",
44
+ command: "archbyte stats --ci",
52
45
  needs: [],
53
- description: "Run validation in CI mode (JSON output, exit code on failure)",
46
+ description: "Run architecture stats in CI mode",
54
47
  },
55
48
  ],
56
49
  },