archbyte 0.3.1 → 0.3.3
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/bin/archbyte.js +4 -3
- package/dist/agents/providers/google.d.ts +1 -2
- package/dist/agents/providers/google.js +72 -74
- package/dist/cli/analyze.d.ts +2 -0
- package/dist/cli/analyze.js +7 -5
- package/dist/cli/auth.js +3 -2
- package/dist/cli/run.js +1 -0
- package/dist/cli/serve.js +3 -1
- package/dist/cli/setup.js +27 -10
- package/package.json +2 -2
package/bin/archbyte.js
CHANGED
|
@@ -36,9 +36,10 @@ program
|
|
|
36
36
|
.version(PKG_VERSION)
|
|
37
37
|
.addHelpText('after', `
|
|
38
38
|
Quick start:
|
|
39
|
-
|
|
40
|
-
$ archbyte
|
|
41
|
-
$ archbyte
|
|
39
|
+
1. Sign up at https://archbyte.heartbyte.io
|
|
40
|
+
2. $ archbyte login Sign in from the CLI
|
|
41
|
+
3. $ archbyte init Configure your model provider
|
|
42
|
+
4. $ archbyte run Analyze → generate → serve
|
|
42
43
|
|
|
43
44
|
https://archbyte.heartbyte.io
|
|
44
45
|
Support: archbyte@heartbyte.io
|
|
@@ -5,6 +5,5 @@ export declare class GoogleProvider implements LLMProvider {
|
|
|
5
5
|
constructor(apiKey: string);
|
|
6
6
|
chat(params: ChatParams): Promise<LLMResponse>;
|
|
7
7
|
stream(params: ChatParams): AsyncIterable<LLMChunk>;
|
|
8
|
-
private
|
|
9
|
-
private toGeminiFunctionDecl;
|
|
8
|
+
private toContents;
|
|
10
9
|
}
|
|
@@ -1,43 +1,47 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { GoogleGenAI } from "@google/genai";
|
|
2
2
|
export class GoogleProvider {
|
|
3
3
|
name = "google";
|
|
4
4
|
client;
|
|
5
5
|
constructor(apiKey) {
|
|
6
|
-
this.client = new
|
|
6
|
+
this.client = new GoogleGenAI({ apiKey });
|
|
7
7
|
}
|
|
8
8
|
async chat(params) {
|
|
9
|
-
const model =
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
9
|
+
const model = params.model ?? "gemini-2.5-pro";
|
|
10
|
+
const response = await this.client.models.generateContent({
|
|
11
|
+
model,
|
|
12
|
+
contents: this.toContents(params.messages),
|
|
13
|
+
config: {
|
|
14
|
+
systemInstruction: params.system,
|
|
15
|
+
maxOutputTokens: params.maxTokens ?? 8192,
|
|
16
|
+
...(params.tools?.length
|
|
17
|
+
? {
|
|
18
|
+
tools: [
|
|
19
|
+
{
|
|
20
|
+
functionDeclarations: params.tools.map((t) => ({
|
|
21
|
+
name: t.name,
|
|
22
|
+
description: t.description,
|
|
23
|
+
parameters: t.input_schema,
|
|
24
|
+
})),
|
|
25
|
+
},
|
|
26
|
+
],
|
|
27
|
+
}
|
|
28
|
+
: {}),
|
|
29
|
+
},
|
|
21
30
|
});
|
|
22
|
-
const contents = this.toGeminiContents(params.messages);
|
|
23
|
-
const result = await model.generateContent({ contents });
|
|
24
|
-
const response = result.response;
|
|
25
31
|
const content = [];
|
|
26
32
|
let hasToolCalls = false;
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
});
|
|
40
|
-
}
|
|
33
|
+
if (response.text) {
|
|
34
|
+
content.push({ type: "text", text: response.text });
|
|
35
|
+
}
|
|
36
|
+
if (response.functionCalls) {
|
|
37
|
+
for (const fc of response.functionCalls) {
|
|
38
|
+
hasToolCalls = true;
|
|
39
|
+
content.push({
|
|
40
|
+
type: "tool_use",
|
|
41
|
+
id: fc.id ?? `call_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`,
|
|
42
|
+
name: fc.name ?? "",
|
|
43
|
+
input: fc.args ?? {},
|
|
44
|
+
});
|
|
41
45
|
}
|
|
42
46
|
}
|
|
43
47
|
return {
|
|
@@ -50,44 +54,49 @@ export class GoogleProvider {
|
|
|
50
54
|
};
|
|
51
55
|
}
|
|
52
56
|
async *stream(params) {
|
|
53
|
-
const model =
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
if (part.text) {
|
|
72
|
-
yield { type: "text", text: part.text };
|
|
73
|
-
}
|
|
74
|
-
if (part.functionCall) {
|
|
75
|
-
yield {
|
|
76
|
-
type: "tool_use_start",
|
|
77
|
-
toolName: part.functionCall.name,
|
|
78
|
-
toolId: `call_${Date.now()}`,
|
|
79
|
-
};
|
|
80
|
-
yield {
|
|
81
|
-
type: "tool_use_input",
|
|
82
|
-
input: JSON.stringify(part.functionCall.args ?? {}),
|
|
83
|
-
};
|
|
57
|
+
const model = params.model ?? "gemini-2.5-pro";
|
|
58
|
+
const stream = await this.client.models.generateContentStream({
|
|
59
|
+
model,
|
|
60
|
+
contents: this.toContents(params.messages),
|
|
61
|
+
config: {
|
|
62
|
+
systemInstruction: params.system,
|
|
63
|
+
maxOutputTokens: params.maxTokens ?? 8192,
|
|
64
|
+
...(params.tools?.length
|
|
65
|
+
? {
|
|
66
|
+
tools: [
|
|
67
|
+
{
|
|
68
|
+
functionDeclarations: params.tools.map((t) => ({
|
|
69
|
+
name: t.name,
|
|
70
|
+
description: t.description,
|
|
71
|
+
parameters: t.input_schema,
|
|
72
|
+
})),
|
|
73
|
+
},
|
|
74
|
+
],
|
|
84
75
|
}
|
|
76
|
+
: {}),
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
for await (const chunk of stream) {
|
|
80
|
+
if (chunk.text) {
|
|
81
|
+
yield { type: "text", text: chunk.text };
|
|
82
|
+
}
|
|
83
|
+
if (chunk.functionCalls) {
|
|
84
|
+
for (const fc of chunk.functionCalls) {
|
|
85
|
+
yield {
|
|
86
|
+
type: "tool_use_start",
|
|
87
|
+
toolName: fc.name ?? "",
|
|
88
|
+
toolId: fc.id ?? `call_${Date.now()}`,
|
|
89
|
+
};
|
|
90
|
+
yield {
|
|
91
|
+
type: "tool_use_input",
|
|
92
|
+
input: JSON.stringify(fc.args ?? {}),
|
|
93
|
+
};
|
|
85
94
|
}
|
|
86
95
|
}
|
|
87
96
|
}
|
|
88
97
|
yield { type: "done" };
|
|
89
98
|
}
|
|
90
|
-
|
|
99
|
+
toContents(messages) {
|
|
91
100
|
return messages.map((m) => {
|
|
92
101
|
const parts = [];
|
|
93
102
|
if (typeof m.content === "string") {
|
|
@@ -122,15 +131,4 @@ export class GoogleProvider {
|
|
|
122
131
|
};
|
|
123
132
|
});
|
|
124
133
|
}
|
|
125
|
-
toGeminiFunctionDecl(tool) {
|
|
126
|
-
return {
|
|
127
|
-
name: tool.name,
|
|
128
|
-
description: tool.description,
|
|
129
|
-
parameters: {
|
|
130
|
-
type: SchemaType.OBJECT,
|
|
131
|
-
properties: (tool.input_schema.properties ?? {}),
|
|
132
|
-
required: tool.input_schema.required ?? [],
|
|
133
|
-
},
|
|
134
|
-
};
|
|
135
|
-
}
|
|
136
134
|
}
|
package/dist/cli/analyze.d.ts
CHANGED
|
@@ -9,6 +9,8 @@ interface AnalyzeOptions {
|
|
|
9
9
|
dryRun?: boolean;
|
|
10
10
|
force?: boolean;
|
|
11
11
|
dir?: string;
|
|
12
|
+
/** When true, skip "archbyte serve" in the Next steps (e.g. called from `archbyte run`) */
|
|
13
|
+
skipServeHint?: boolean;
|
|
12
14
|
}
|
|
13
15
|
export declare function handleAnalyze(options: AnalyzeOptions): Promise<void>;
|
|
14
16
|
/**
|
package/dist/cli/analyze.js
CHANGED
|
@@ -63,7 +63,7 @@ export async function handleAnalyze(options) {
|
|
|
63
63
|
progress.update(2, "Generating diagram...");
|
|
64
64
|
await autoGenerate(rootDir, options);
|
|
65
65
|
progress.done("Analysis complete");
|
|
66
|
-
printSummary(analysis, duration, "static");
|
|
66
|
+
printSummary(analysis, duration, "static", { skipServeHint: options.skipServeHint });
|
|
67
67
|
return;
|
|
68
68
|
}
|
|
69
69
|
// ─── Default mode: static context → LLM pipeline ───
|
|
@@ -248,7 +248,7 @@ export async function handleAnalyze(options) {
|
|
|
248
248
|
writeSpec(rootDir, fbSpec);
|
|
249
249
|
writeScanMetadata(rootDir, duration, "static-fallback");
|
|
250
250
|
await autoGenerate(rootDir, options);
|
|
251
|
-
printSummary(analysis, duration, "static");
|
|
251
|
+
printSummary(analysis, duration, "static", { skipServeHint: options.skipServeHint });
|
|
252
252
|
}
|
|
253
253
|
catch (fallbackErr) {
|
|
254
254
|
console.error(chalk.red(` Static fallback also failed: ${fallbackErr instanceof Error ? fallbackErr.message : String(fallbackErr)}`));
|
|
@@ -292,7 +292,7 @@ export async function handleAnalyze(options) {
|
|
|
292
292
|
agentCount: 5,
|
|
293
293
|
durationMs: duration,
|
|
294
294
|
});
|
|
295
|
-
printSummary(analysis, duration, "pipeline");
|
|
295
|
+
printSummary(analysis, duration, "pipeline", { skipServeHint: options.skipServeHint });
|
|
296
296
|
}
|
|
297
297
|
// ─── Shared helpers ───
|
|
298
298
|
function writeAnalysisStatus(rootDir, status, error) {
|
|
@@ -352,7 +352,7 @@ async function autoGenerate(rootDir, options) {
|
|
|
352
352
|
console.error(chalk.gray("You can run 'archbyte generate' manually."));
|
|
353
353
|
}
|
|
354
354
|
}
|
|
355
|
-
function printSummary(analysis, durationMs, mode) {
|
|
355
|
+
function printSummary(analysis, durationMs, mode, options) {
|
|
356
356
|
const components = analysis.components ?? [];
|
|
357
357
|
const connections = analysis.connections ?? [];
|
|
358
358
|
console.log();
|
|
@@ -363,7 +363,9 @@ function printSummary(analysis, durationMs, mode) {
|
|
|
363
363
|
console.log(chalk.gray(` Connections: ${connections.length}`));
|
|
364
364
|
console.log();
|
|
365
365
|
console.log(chalk.bold("Next"));
|
|
366
|
-
|
|
366
|
+
if (!options?.skipServeHint) {
|
|
367
|
+
console.log(` ${chalk.cyan("archbyte serve")} Open the interactive diagram`);
|
|
368
|
+
}
|
|
367
369
|
console.log(` ${chalk.cyan("archbyte validate")} Check architecture fitness rules ${chalk.yellow("[Pro]")}`);
|
|
368
370
|
console.log(` ${chalk.cyan("archbyte patrol")} Continuous architecture monitoring ${chalk.yellow("[Pro]")}`);
|
|
369
371
|
console.log();
|
package/dist/cli/auth.js
CHANGED
|
@@ -7,7 +7,9 @@ import { CONFIG_DIR, CREDENTIALS_PATH, API_BASE, CLI_CALLBACK_PORT, OAUTH_TIMEOU
|
|
|
7
7
|
export async function handleLogin(provider) {
|
|
8
8
|
console.log();
|
|
9
9
|
console.log(chalk.bold.cyan("ArchByte Login"));
|
|
10
|
-
console.log(
|
|
10
|
+
console.log();
|
|
11
|
+
console.log(chalk.gray(" Don't have an account yet? Sign up first:"));
|
|
12
|
+
console.log(` ${chalk.bold.cyan("https://archbyte.heartbyte.io")}`);
|
|
11
13
|
console.log();
|
|
12
14
|
const existing = loadCredentials();
|
|
13
15
|
if (existing && !isExpired(existing)) {
|
|
@@ -35,7 +37,6 @@ export async function handleLogin(provider) {
|
|
|
35
37
|
}
|
|
36
38
|
const selectedProvider = provider ?? "github";
|
|
37
39
|
console.log(chalk.gray(`Opening browser for ${selectedProvider} sign-in...`));
|
|
38
|
-
console.log(chalk.gray("Don't have an account? One will be created automatically."));
|
|
39
40
|
console.log();
|
|
40
41
|
try {
|
|
41
42
|
const credentials = await startOAuthFlow(selectedProvider);
|
package/dist/cli/run.js
CHANGED
package/dist/cli/serve.js
CHANGED
|
@@ -75,7 +75,9 @@ export async function handleServe(options) {
|
|
|
75
75
|
// Try to start, handle port conflicts interactively
|
|
76
76
|
while (true) {
|
|
77
77
|
try {
|
|
78
|
-
|
|
78
|
+
const url = `http://localhost:${port}`;
|
|
79
|
+
console.log();
|
|
80
|
+
console.log(chalk.bold.green(` ➜ ${chalk.underline(url)}`));
|
|
79
81
|
console.log();
|
|
80
82
|
await startServer({
|
|
81
83
|
name: projectName,
|
package/dist/cli/setup.js
CHANGED
|
@@ -143,10 +143,14 @@ async function validateProviderSilent(providerName, apiKey, model) {
|
|
|
143
143
|
return true;
|
|
144
144
|
}
|
|
145
145
|
catch (err) {
|
|
146
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
146
147
|
if (process.env.ARCHBYTE_DEBUG) {
|
|
147
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
148
148
|
console.log(chalk.red(`\n Validation error: ${msg}`));
|
|
149
149
|
}
|
|
150
|
+
// Quota/rate limit = key is valid, just exhausted
|
|
151
|
+
if (msg.includes("429") || msg.includes("RESOURCE_EXHAUSTED") || msg.includes("rate_limit") || msg.includes("quota")) {
|
|
152
|
+
return "quota";
|
|
153
|
+
}
|
|
150
154
|
return false;
|
|
151
155
|
}
|
|
152
156
|
}
|
|
@@ -308,12 +312,17 @@ export async function handleSetup() {
|
|
|
308
312
|
const validationModel = profiles[provider].model ?? resolveModel(provider, "fast");
|
|
309
313
|
// Validate provider with spinner
|
|
310
314
|
const s = spinner(`Validating credentials with ${validationModel}`);
|
|
311
|
-
let
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
+
let result = await validateProviderSilent(provider, apiKey, validationModel);
|
|
316
|
+
if (result === "quota") {
|
|
317
|
+
s.stop("valid (quota exceeded — key accepted)", "yellow");
|
|
318
|
+
}
|
|
319
|
+
else {
|
|
320
|
+
s.stop(result ? "valid" : "invalid", result ? "green" : "red");
|
|
321
|
+
}
|
|
322
|
+
// Retry loop on failure (not for quota — that means the key works)
|
|
323
|
+
if (result === false) {
|
|
315
324
|
let retries = 0;
|
|
316
|
-
while (
|
|
325
|
+
while (result === false && retries < 2) {
|
|
317
326
|
if (!await confirm(" Retry?"))
|
|
318
327
|
break;
|
|
319
328
|
retries++;
|
|
@@ -323,10 +332,15 @@ export async function handleSetup() {
|
|
|
323
332
|
console.log(chalk.green(` ✓ API key: ${maskKey(newKey)}`));
|
|
324
333
|
}
|
|
325
334
|
const s2 = spinner(`Validating credentials with ${validationModel}`);
|
|
326
|
-
|
|
327
|
-
|
|
335
|
+
result = await validateProviderSilent(provider, profiles[provider].apiKey, validationModel);
|
|
336
|
+
if (result === "quota") {
|
|
337
|
+
s2.stop("valid (quota exceeded — key accepted)", "yellow");
|
|
338
|
+
}
|
|
339
|
+
else {
|
|
340
|
+
s2.stop(result ? "valid" : "invalid", result ? "green" : "red");
|
|
341
|
+
}
|
|
328
342
|
}
|
|
329
|
-
if (
|
|
343
|
+
if (result === false) {
|
|
330
344
|
console.log(chalk.yellow(" Warning: credentials unverified. Saving anyway."));
|
|
331
345
|
}
|
|
332
346
|
}
|
|
@@ -393,7 +407,10 @@ export async function handleSetup() {
|
|
|
393
407
|
if (hasClaude || hasCodex) {
|
|
394
408
|
console.log(" " + chalk.cyan("archbyte mcp install") + " Use from your AI tool");
|
|
395
409
|
}
|
|
396
|
-
|
|
410
|
+
if (result === false) {
|
|
411
|
+
console.log(chalk.yellow(" Warning: credentials unverified. Saving anyway."));
|
|
412
|
+
console.log();
|
|
413
|
+
}
|
|
397
414
|
}
|
|
398
415
|
function writeArchbyteReadme(archbyteDir) {
|
|
399
416
|
const readmePath = path.join(archbyteDir, "README.md");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "archbyte",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.3",
|
|
4
4
|
"description": "ArchByte - See what agents build. As they build it.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"@anthropic-ai/sdk": "^0.74.0",
|
|
39
|
-
"@google/
|
|
39
|
+
"@google/genai": "^1.41.0",
|
|
40
40
|
"@modelcontextprotocol/sdk": "^1.26.0",
|
|
41
41
|
"chalk": "^5.3.0",
|
|
42
42
|
"chokidar": "^3.5.3",
|