astrabot 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 +411 -0
- package/ai/ai.config.ts +27 -0
- package/ai/auto-retry.ts +117 -0
- package/ai/config-loader.ts +132 -0
- package/ai/index.ts +4 -0
- package/ai/retry-prompt.ts +30 -0
- package/bin/astra +2 -0
- package/core/retry/error-classifier.ts +208 -0
- package/core/retry/index.ts +29 -0
- package/core/retry/retry-config.ts +142 -0
- package/core/retry/retry-engine.ts +215 -0
- package/game/index.html +573 -0
- package/game/neon-breaker.html +1037 -0
- package/index.ts +140 -0
- package/modes/agent/action-tracker.ts +47 -0
- package/modes/agent/agent-tools.ts +338 -0
- package/modes/agent/approval.ts +184 -0
- package/modes/agent/diff-view.ts +34 -0
- package/modes/agent/orchestrator.ts +234 -0
- package/modes/agent/tool-executor.ts +993 -0
- package/modes/agent/types.ts +68 -0
- package/modes/ask/orchestrator.ts +230 -0
- package/modes/auto.ts +88 -0
- package/modes/cli.ts +43 -0
- package/modes/multi/agent-pool-manager.ts +337 -0
- package/modes/multi/examples.ts +441 -0
- package/modes/multi/message-broker.ts +179 -0
- package/modes/multi/multi-agent-orchestrator.ts +891 -0
- package/modes/multi/orchestrator.ts +414 -0
- package/modes/multi/types.ts +245 -0
- package/modes/multi/workflow-builder.ts +569 -0
- package/modes/plan/orchestrator.ts +198 -0
- package/modes/plan/planner.ts +121 -0
- package/modes/plan/selection.ts +43 -0
- package/modes/plan/types.ts +13 -0
- package/modes/plan/web-tools.ts +132 -0
- package/modes/setup.ts +210 -0
- package/package.json +62 -0
- package/session/index.ts +45 -0
- package/session/session-context.ts +188 -0
- package/session/session-manager.ts +374 -0
- package/session/session-tools.ts +109 -0
- package/session/store.ts +278 -0
- package/tsconfig.json +30 -0
- package/tui/spinner.ts +182 -0
- package/tui/terminal-md.ts +17 -0
- package/tui/wakeup.ts +231 -0
package/tui/wakeup.ts
ADDED
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
import { select, isCancel, confirm } from "@clack/prompts";
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
import figlet from "figlet";
|
|
4
|
+
import { runCliMode } from "../modes/cli";
|
|
5
|
+
import { getResumableSession, formatSessionLine } from "../session";
|
|
6
|
+
import { withSpinner } from "./spinner"; // Custom high-fidelity spinner
|
|
7
|
+
|
|
8
|
+
const BANNER_FONT = "ANSI Shadow";
|
|
9
|
+
|
|
10
|
+
// ── Clean & Minimal Color Palette ─────────────────────────────────────────
|
|
11
|
+
const C = {
|
|
12
|
+
brand: chalk.bold.hex("#a78bfa"), // Vibrant clean violet
|
|
13
|
+
text: chalk.hex("#f3f4f6"), // Off-white for high readability
|
|
14
|
+
dim: chalk.hex("#6b7280"), // Subtle gray for secondary metadata
|
|
15
|
+
success: chalk.bold.hex("#34d399"), // Emerald green accent
|
|
16
|
+
warning: chalk.bold.hex("#fbbf24"), // Amber yellow for attention items
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Interpolates between two hex colors by a factor t ∈ [0, 1].
|
|
21
|
+
*/
|
|
22
|
+
function lerpHex(from: string, to: string, t: number): string {
|
|
23
|
+
const f = from.replace("#", "");
|
|
24
|
+
const t2 = to.replace("#", "");
|
|
25
|
+
const r = Math.round(parseInt(f.slice(0, 2), 16) + (parseInt(t2.slice(0, 2), 16) - parseInt(f.slice(0, 2), 16)) * t);
|
|
26
|
+
const g = Math.round(parseInt(f.slice(2, 4), 16) + (parseInt(t2.slice(2, 4), 16) - parseInt(f.slice(2, 4), 16)) * t);
|
|
27
|
+
const b = Math.round(parseInt(f.slice(4, 6), 16) + (parseInt(t2.slice(4, 6), 16) - parseInt(f.slice(4, 6), 16)) * t);
|
|
28
|
+
return `#${r.toString(16).padStart(2, "0")}${g.toString(16).padStart(2, "0")}${b.toString(16).padStart(2, "0")}`;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// ── Star Field ──────────────────────────────────────────────────────────────
|
|
32
|
+
// Each star has a stable position and an independent phase offset so they
|
|
33
|
+
// twinkle asynchronously. Layout seeded deterministically — same every run.
|
|
34
|
+
type Star = { col: number; row: number; phaseOffset: number; speed: number };
|
|
35
|
+
|
|
36
|
+
const STAR_GLYPHS = ["·", "·", "+", "✦", "✧", "✦", "★"];
|
|
37
|
+
const STAR_COLORS = ["#3b2f6e", "#4c3a8a", "#7c5cbf", "#a78bfa", "#c4b0fd", "#e0d4ff"];
|
|
38
|
+
|
|
39
|
+
function buildStarField(lineCount: number): Star[] {
|
|
40
|
+
// Seeded LCG — stable positions across every frame / run
|
|
41
|
+
let seed = 0xdeadbeef;
|
|
42
|
+
const rand = () => {
|
|
43
|
+
seed ^= seed << 13;
|
|
44
|
+
seed ^= seed >> 17;
|
|
45
|
+
seed ^= seed << 5;
|
|
46
|
+
return (seed >>> 0) / 0xffffffff;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const stars: Star[] = [];
|
|
50
|
+
const density = 3; // stars per banner row
|
|
51
|
+
for (let row = 0; row < lineCount; row++) {
|
|
52
|
+
for (let i = 0; i < density; i++) {
|
|
53
|
+
stars.push({
|
|
54
|
+
row,
|
|
55
|
+
col: Math.floor(rand() * 38) + 2, // spread across ~38 cols
|
|
56
|
+
phaseOffset: rand() * Math.PI * 2, // independent twinkle start
|
|
57
|
+
speed: 0.6 + rand() * 1.2, // each star at its own rate
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return stars;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Renders one star glyph at the current animation time.
|
|
66
|
+
*/
|
|
67
|
+
function renderStar(star: Star, time: number): string {
|
|
68
|
+
const brightness = 0.5 + 0.5 * Math.sin(time * star.speed + star.phaseOffset);
|
|
69
|
+
const glyphIdx = Math.floor(brightness * (STAR_GLYPHS.length - 1));
|
|
70
|
+
const colorIdx = Math.floor(brightness * (STAR_COLORS.length - 1));
|
|
71
|
+
return chalk.hex(STAR_COLORS[colorIdx]!)(STAR_GLYPHS[glyphIdx]);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Returns one sidebar string per banner line — a fixed-width column of stars
|
|
76
|
+
* placed at stable positions, each pulsing independently.
|
|
77
|
+
*/
|
|
78
|
+
function buildStarSidebar(stars: Star[], lineCount: number, time: number): string[] {
|
|
79
|
+
const WIDTH = 42;
|
|
80
|
+
// Build per-row character arrays; stars overwrite their slot with a chalk string
|
|
81
|
+
const rows: (string)[][] = Array.from({ length: lineCount }, () => Array(WIDTH).fill(" "));
|
|
82
|
+
for (const star of stars) {
|
|
83
|
+
if (star.row < lineCount && star.col < WIDTH) {
|
|
84
|
+
rows[star.row]![star.col] = renderStar(star, time);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return rows.map((cols) => cols.join(""));
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Pre-built star field — initialised once, reused every frame
|
|
91
|
+
let _starField: Star[] | null = null;
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Prints the banner at a specific breath phase (0 = dim, 1 = full brightness),
|
|
95
|
+
* with a twinkling star field to the right. Clears the screen each frame.
|
|
96
|
+
*/
|
|
97
|
+
function drawBanner(ascii: string, phase: number, time: number): void {
|
|
98
|
+
const color = lerpHex("#2e1f5e", "#a78bfa", phase);
|
|
99
|
+
const lines = ascii.split("\n").filter((l) => l.trim().length > 0);
|
|
100
|
+
|
|
101
|
+
if (!_starField) _starField = buildStarField(lines.length);
|
|
102
|
+
const sidebar = buildStarSidebar(_starField, lines.length, time);
|
|
103
|
+
|
|
104
|
+
console.clear();
|
|
105
|
+
console.log();
|
|
106
|
+
lines.forEach((line, i) => {
|
|
107
|
+
console.log(` ${chalk.bold.hex(color)(line)} ${sidebar[i]}`);
|
|
108
|
+
});
|
|
109
|
+
console.log(
|
|
110
|
+
`\n ${C.success("●")} ${C.text("ASTRA")} ${C.dim("│")} ${C.dim("AI-native development companion")}`
|
|
111
|
+
);
|
|
112
|
+
console.log(` ${C.dim(" Version 0.1.0 — Environment Ready")}\n`);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Plays one full inhale→exhale breath cycle on the banner (with live star
|
|
117
|
+
* twinkling throughout), then leaves it rendered at full brightness.
|
|
118
|
+
*/
|
|
119
|
+
export async function printBanner(ascii: string): Promise<void> {
|
|
120
|
+
const DURATION_MS = 1600;
|
|
121
|
+
const FPS = 28;
|
|
122
|
+
const INTERVAL = Math.round(1000 / FPS);
|
|
123
|
+
const steps = Math.round(DURATION_MS / INTERVAL);
|
|
124
|
+
const startTime = Date.now();
|
|
125
|
+
|
|
126
|
+
await new Promise<void>((resolve) => {
|
|
127
|
+
let step = 0;
|
|
128
|
+
const timer = setInterval(() => {
|
|
129
|
+
if (step > steps) {
|
|
130
|
+
clearInterval(timer);
|
|
131
|
+
// Final frame: guaranteed full brightness
|
|
132
|
+
drawBanner(ascii, 1, (Date.now() - startTime) / 1000);
|
|
133
|
+
resolve();
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
// Cosine curve: 1 → 0 → 1 (bright → dim → bright)
|
|
137
|
+
const phase = 0.5 + 0.5 * Math.cos((step / steps) * 2 * Math.PI);
|
|
138
|
+
const time = (Date.now() - startTime) / 1000;
|
|
139
|
+
drawBanner(ascii, phase, time);
|
|
140
|
+
step++;
|
|
141
|
+
}, INTERVAL);
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Standard initialization workflow wrapped in the custom loader framework
|
|
147
|
+
*/
|
|
148
|
+
async function initializeSystem(): Promise<string> {
|
|
149
|
+
return await withSpinner(
|
|
150
|
+
{
|
|
151
|
+
message: "Initializing Astra development workspace...",
|
|
152
|
+
doneMessage: "Workspace initialized successfully.",
|
|
153
|
+
failMessage: "Initialization failed. Falling back to default canvas.",
|
|
154
|
+
},
|
|
155
|
+
async (ctx) => {
|
|
156
|
+
// Light natural pacing overhead to ensure the UI feels responsive
|
|
157
|
+
await new Promise((resolve) => setTimeout(resolve, 400));
|
|
158
|
+
ctx.updateMetric("Loading configuration");
|
|
159
|
+
|
|
160
|
+
let ascii = "";
|
|
161
|
+
try {
|
|
162
|
+
ascii = figlet.textSync("astra", { font: BANNER_FONT });
|
|
163
|
+
} catch {
|
|
164
|
+
ascii = figlet.textSync("astra", { font: "Standard" });
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
await new Promise((resolve) => setTimeout(resolve, 300));
|
|
168
|
+
ctx.updateMetric("Ready");
|
|
169
|
+
return ascii;
|
|
170
|
+
}
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
export async function runWakeup() {
|
|
175
|
+
console.clear();
|
|
176
|
+
|
|
177
|
+
// Boot up sequence displaying your metric-enhanced loader
|
|
178
|
+
const ascii = await initializeSystem();
|
|
179
|
+
|
|
180
|
+
while (true) {
|
|
181
|
+
console.clear();
|
|
182
|
+
await printBanner(ascii);
|
|
183
|
+
|
|
184
|
+
// Check for resumable session states
|
|
185
|
+
const recent = getResumableSession(process.cwd());
|
|
186
|
+
if (recent && recent.status === "interrupted") {
|
|
187
|
+
console.log(
|
|
188
|
+
` ${C.warning("⏸ Previous session was interrupted:")} ${C.text(recent.lastGoal.slice(0, 60))}...`
|
|
189
|
+
);
|
|
190
|
+
console.log(` ${C.dim(formatSessionLine(recent))}\n`);
|
|
191
|
+
|
|
192
|
+
const resume = await confirm({
|
|
193
|
+
message: "Would you like to resume this session?",
|
|
194
|
+
initialValue: true,
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
if (!isCancel(resume) && resume) {
|
|
198
|
+
(globalThis as any).__ASTRA_RESUME_SESSION__ = recent.id;
|
|
199
|
+
console.log(C.dim(" Re-attaching to pipeline context..."));
|
|
200
|
+
await runCliMode();
|
|
201
|
+
continue;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// Clean, structured interactive select layout
|
|
206
|
+
const mode = await select({
|
|
207
|
+
message: "Select an execution mode to proceed:",
|
|
208
|
+
options: [
|
|
209
|
+
{ value: "cli", label: "Interactive CLI Mode" },
|
|
210
|
+
//{ value: "telegram", label: "Telegram Gateway Interface" },
|
|
211
|
+
{ value: "exit", label: "Exit Application" }
|
|
212
|
+
]
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
if (isCancel(mode) || mode === "exit") {
|
|
216
|
+
console.log(C.dim("\n Session closed. Goodbye.\n"));
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
if (mode === "cli") {
|
|
221
|
+
console.log(C.dim(" Launching local environment CLI..."));
|
|
222
|
+
await runCliMode();
|
|
223
|
+
continue;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
if (mode === "telegram") {
|
|
227
|
+
console.log(C.dim(" Connecting to Telegram services..."));
|
|
228
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|