@agentuity/coder-tui 3.0.0-alpha.6 → 3.0.0-beta.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/dist/agentuity-cli.d.ts +12 -0
- package/dist/agentuity-cli.d.ts.map +1 -0
- package/dist/agentuity-cli.js +178 -0
- package/dist/agentuity-cli.js.map +1 -0
- package/dist/aigateway.d.ts +4 -0
- package/dist/aigateway.d.ts.map +1 -0
- package/dist/aigateway.js +178 -0
- package/dist/aigateway.js.map +1 -0
- package/dist/footer.d.ts +3 -2
- package/dist/footer.d.ts.map +1 -1
- package/dist/footer.js +50 -16
- package/dist/footer.js.map +1 -1
- package/dist/hub-overlay-state.d.ts.map +1 -1
- package/dist/hub-overlay-state.js +3 -1
- package/dist/hub-overlay-state.js.map +1 -1
- package/dist/hub-overlay.d.ts.map +1 -1
- package/dist/hub-overlay.js +12 -3
- package/dist/hub-overlay.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +53 -30
- package/dist/index.js.map +1 -1
- package/dist/local-init-filter.d.ts +5 -0
- package/dist/local-init-filter.d.ts.map +1 -0
- package/dist/local-init-filter.js +40 -0
- package/dist/local-init-filter.js.map +1 -0
- package/dist/protocol.d.ts +2 -0
- package/dist/protocol.d.ts.map +1 -1
- package/dist/remote-session.d.ts.map +1 -1
- package/dist/remote-session.js +12 -6
- package/dist/remote-session.js.map +1 -1
- package/dist/renderers.d.ts.map +1 -1
- package/dist/renderers.js +53 -1
- package/dist/renderers.js.map +1 -1
- package/dist/startup-logo.d.ts +3 -0
- package/dist/startup-logo.d.ts.map +1 -0
- package/dist/startup-logo.js +212 -0
- package/dist/startup-logo.js.map +1 -0
- package/dist/subagent-tool-selection.d.ts +3 -0
- package/dist/subagent-tool-selection.d.ts.map +1 -0
- package/dist/subagent-tool-selection.js +22 -0
- package/dist/subagent-tool-selection.js.map +1 -0
- package/package.json +6 -6
- package/src/agentuity-cli.ts +225 -0
- package/src/aigateway.ts +256 -0
- package/src/footer.ts +62 -15
- package/src/hub-overlay-state.ts +4 -1
- package/src/hub-overlay.ts +14 -3
- package/src/index.ts +59 -32
- package/src/local-init-filter.ts +54 -0
- package/src/protocol.ts +2 -0
- package/src/remote-session.ts +12 -6
- package/src/renderers.ts +61 -1
- package/src/startup-logo.ts +255 -0
- package/src/subagent-tool-selection.ts +33 -0
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
import type { ExtensionAPI, ExtensionContext, Theme } from '@mariozechner/pi-coding-agent';
|
|
2
|
+
|
|
3
|
+
type TuiRenderer = {
|
|
4
|
+
requestRender(): void;
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
type LogoCell = {
|
|
8
|
+
ri: number;
|
|
9
|
+
ci: number;
|
|
10
|
+
sr: number;
|
|
11
|
+
sc: number;
|
|
12
|
+
delay: number;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const LOGO = [
|
|
16
|
+
' ## ',
|
|
17
|
+
' #### ',
|
|
18
|
+
' ###### ',
|
|
19
|
+
' ########## ',
|
|
20
|
+
' ##### ##### ',
|
|
21
|
+
' ##### ##### ',
|
|
22
|
+
' ##### ##### ',
|
|
23
|
+
' ##### ##### ',
|
|
24
|
+
' ##### ##### ',
|
|
25
|
+
' ############################# ',
|
|
26
|
+
' ############################## ',
|
|
27
|
+
' ',
|
|
28
|
+
' ',
|
|
29
|
+
' ##################################### ',
|
|
30
|
+
'######################################## ',
|
|
31
|
+
' ##### ##### ',
|
|
32
|
+
' ##### ##### ',
|
|
33
|
+
' ##### ##### ',
|
|
34
|
+
' ##### ##### ',
|
|
35
|
+
' ############################################ ',
|
|
36
|
+
'############################################## ',
|
|
37
|
+
];
|
|
38
|
+
|
|
39
|
+
const ASSEMBLE_FRAMES = 30;
|
|
40
|
+
const SHIMMER_FRAMES = 56;
|
|
41
|
+
const PULSE_FRAMES = 40;
|
|
42
|
+
const FRAME_INTERVAL_MS = 35;
|
|
43
|
+
const CHARS = '░▒▓█#@%&*+=-:.';
|
|
44
|
+
const TITLE = 'Agentuity Coder';
|
|
45
|
+
const SANDBOX_ID_ENV = 'AGENTUITY_SANDBOX_ID';
|
|
46
|
+
|
|
47
|
+
const LOGO_ROWS = LOGO.length;
|
|
48
|
+
const LOGO_COLS = LOGO[0]?.length ?? 0;
|
|
49
|
+
const CELLS = LOGO.flatMap((row, ri) =>
|
|
50
|
+
[...row].flatMap((ch, ci) => (ch === '#' ? [{ ri, ci }] : []))
|
|
51
|
+
);
|
|
52
|
+
const TOTAL_FRAMES = ASSEMBLE_FRAMES + SHIMMER_FRAMES + PULSE_FRAMES;
|
|
53
|
+
const TITLE_OFFSET = 3;
|
|
54
|
+
|
|
55
|
+
function mulberry32(seed: number): () => number {
|
|
56
|
+
return () => {
|
|
57
|
+
seed += 0x6d2b79f5;
|
|
58
|
+
let value = seed;
|
|
59
|
+
value = Math.imul(value ^ (value >>> 15), value | 1);
|
|
60
|
+
value ^= value + Math.imul(value ^ (value >>> 7), value | 61);
|
|
61
|
+
return ((value ^ (value >>> 14)) >>> 0) / 4294967296;
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function center(line: string, width: number): string {
|
|
66
|
+
if (width <= LOGO_COLS) return line;
|
|
67
|
+
const padding = Math.max(0, Math.floor((width - LOGO_COLS) / 2));
|
|
68
|
+
return `${' '.repeat(padding)}${line}`;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function centerText(line: string, width: number): string {
|
|
72
|
+
const padding = Math.max(0, Math.floor((width - line.length) / 2) - TITLE_OFFSET);
|
|
73
|
+
return `${' '.repeat(padding)}${line}`;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function randomChar(rand: () => number): string {
|
|
77
|
+
return CHARS[Math.floor(rand() * CHARS.length)] ?? '#';
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function makeParticles(seed: number): LogoCell[] {
|
|
81
|
+
const rand = mulberry32(seed);
|
|
82
|
+
return CELLS.map((cell) => ({
|
|
83
|
+
...cell,
|
|
84
|
+
sr: Math.floor(rand() * LOGO_ROWS),
|
|
85
|
+
sc: Math.floor(rand() * LOGO_COLS),
|
|
86
|
+
delay: rand() * 0.6,
|
|
87
|
+
}));
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function makeGrid(): string[][] {
|
|
91
|
+
return LOGO.map((row) => [...row].map(() => ' '));
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function phaseForFrame(
|
|
95
|
+
frame: number
|
|
96
|
+
):
|
|
97
|
+
| { type: 'assemble'; frame: number }
|
|
98
|
+
| { type: 'shimmer'; frame: number }
|
|
99
|
+
| { type: 'pulse'; frame: number }
|
|
100
|
+
| { type: 'final' } {
|
|
101
|
+
if (frame < ASSEMBLE_FRAMES) return { type: 'assemble', frame };
|
|
102
|
+
if (frame < ASSEMBLE_FRAMES + SHIMMER_FRAMES) {
|
|
103
|
+
return { type: 'shimmer', frame: frame - ASSEMBLE_FRAMES };
|
|
104
|
+
}
|
|
105
|
+
if (frame < TOTAL_FRAMES) {
|
|
106
|
+
return { type: 'pulse', frame: frame - ASSEMBLE_FRAMES - SHIMMER_FRAMES };
|
|
107
|
+
}
|
|
108
|
+
return { type: 'final' };
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
class StartupLogoHeader {
|
|
112
|
+
#frame = 0;
|
|
113
|
+
#timer: ReturnType<typeof setInterval> | null = null;
|
|
114
|
+
readonly #particles = makeParticles(Date.now());
|
|
115
|
+
|
|
116
|
+
constructor(
|
|
117
|
+
private readonly tui: TuiRenderer,
|
|
118
|
+
private readonly theme: Theme
|
|
119
|
+
) {
|
|
120
|
+
this.#timer = setInterval(() => {
|
|
121
|
+
this.#frame++;
|
|
122
|
+
if (this.#frame >= TOTAL_FRAMES) this.#stop();
|
|
123
|
+
this.tui.requestRender();
|
|
124
|
+
}, FRAME_INTERVAL_MS);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
render(width: number): string[] {
|
|
128
|
+
const grid = this.#renderGrid();
|
|
129
|
+
return [
|
|
130
|
+
'',
|
|
131
|
+
...grid.map((row) => center(row.join(''), width)),
|
|
132
|
+
'',
|
|
133
|
+
this.#renderTitle(width),
|
|
134
|
+
'',
|
|
135
|
+
];
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
invalidate(): void {
|
|
139
|
+
this.tui.requestRender();
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
dispose(): void {
|
|
143
|
+
this.#stop();
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
#renderGrid(): string[][] {
|
|
147
|
+
const phase = phaseForFrame(this.#frame);
|
|
148
|
+
if (phase.type === 'assemble') return this.#renderAssemble(phase.frame);
|
|
149
|
+
if (phase.type === 'shimmer') return this.#renderShimmer(phase.frame);
|
|
150
|
+
if (phase.type === 'pulse') return this.#renderPulse(phase.frame);
|
|
151
|
+
return this.#renderFinal();
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
#renderAssemble(frame: number): string[][] {
|
|
155
|
+
const rand = mulberry32(frame + 1);
|
|
156
|
+
const grid = makeGrid();
|
|
157
|
+
const t = frame / Math.max(1, ASSEMBLE_FRAMES - 1);
|
|
158
|
+
|
|
159
|
+
for (const particle of this.#particles) {
|
|
160
|
+
const pt = Math.max(0, (t - particle.delay) / (1 - particle.delay));
|
|
161
|
+
const eased = 1 - (1 - Math.min(pt, 1)) ** 3;
|
|
162
|
+
const ri = Math.round(particle.sr + (particle.ri - particle.sr) * eased);
|
|
163
|
+
const ci = Math.round(particle.sc + (particle.ci - particle.sc) * eased);
|
|
164
|
+
|
|
165
|
+
if (pt >= 1) {
|
|
166
|
+
grid[particle.ri]![particle.ci] = this.#cyan('#');
|
|
167
|
+
} else if (ri >= 0 && ri < LOGO_ROWS && ci >= 0 && ci < LOGO_COLS) {
|
|
168
|
+
grid[ri]![ci] = this.#dim(randomChar(rand));
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return grid;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
#renderShimmer(frame: number): string[][] {
|
|
176
|
+
const wave = (frame / SHIMMER_FRAMES) * (LOGO_ROWS + LOGO_COLS) * 1.5;
|
|
177
|
+
return LOGO.map((row, ri) =>
|
|
178
|
+
[...row].map((ch, ci) => {
|
|
179
|
+
if (ch !== '#') return ' ';
|
|
180
|
+
const dist = Math.abs(ri + ci * 0.5 - wave);
|
|
181
|
+
if (dist < 1.5) return this.#brightCyan('█');
|
|
182
|
+
if (dist < 3.5) return this.#cyan('#');
|
|
183
|
+
if (dist < 5) return this.#dim('#');
|
|
184
|
+
return this.#cyan('#');
|
|
185
|
+
})
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
#renderPulse(frame: number): string[][] {
|
|
190
|
+
const step = frame % 20;
|
|
191
|
+
const t = step / 20;
|
|
192
|
+
const bright = t < 0.5 ? t * 2 : (1 - t) * 2;
|
|
193
|
+
|
|
194
|
+
return LOGO.map((row) =>
|
|
195
|
+
[...row].map((ch) => {
|
|
196
|
+
if (ch !== '#') return ' ';
|
|
197
|
+
if (bright > 0.5) return this.#brightCyan('#');
|
|
198
|
+
if (bright > 0.2) return this.#cyan('#');
|
|
199
|
+
return this.#dim('#');
|
|
200
|
+
})
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
#renderFinal(): string[][] {
|
|
205
|
+
return LOGO.map((row) => [...row].map((ch) => (ch === '#' ? this.#cyan('#') : ' ')));
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
#renderTitle(width: number): string {
|
|
209
|
+
if (this.#frame < ASSEMBLE_FRAMES) return '';
|
|
210
|
+
|
|
211
|
+
const titleFrame = Math.min(this.#frame - ASSEMBLE_FRAMES, SHIMMER_FRAMES);
|
|
212
|
+
const visibleChars = Math.min(
|
|
213
|
+
TITLE.length,
|
|
214
|
+
Math.floor((titleFrame / Math.max(1, SHIMMER_FRAMES - 1)) * TITLE.length)
|
|
215
|
+
);
|
|
216
|
+
const title = TITLE.slice(0, visibleChars);
|
|
217
|
+
|
|
218
|
+
if (this.#frame >= ASSEMBLE_FRAMES + SHIMMER_FRAMES) {
|
|
219
|
+
return this.#brightCyan(centerText(TITLE, width));
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
return this.#cyan(centerText(title, width));
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
#cyan(text: string): string {
|
|
226
|
+
return `\x1b[36m${text}\x1b[0m`;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
#brightCyan(text: string): string {
|
|
230
|
+
return `\x1b[96m${text}\x1b[0m`;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
#dim(text: string): string {
|
|
234
|
+
return this.theme.fg('dim', this.theme.fg('accent', text));
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
#stop(): void {
|
|
238
|
+
if (!this.#timer) return;
|
|
239
|
+
clearInterval(this.#timer);
|
|
240
|
+
this.#timer = null;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
function installStartupLogo(ctx: ExtensionContext): void {
|
|
245
|
+
if (!ctx.hasUI) return;
|
|
246
|
+
ctx.ui.setHeader((tui, theme) => new StartupLogoHeader(tui, theme));
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
export function setupStartupLogo(pi: ExtensionAPI): void {
|
|
250
|
+
if (process.env[SANDBOX_ID_ENV]) return;
|
|
251
|
+
|
|
252
|
+
pi.on('session_start', async (_event, ctx) => {
|
|
253
|
+
installStartupLogo(ctx);
|
|
254
|
+
});
|
|
255
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { AgentDefinition } from './protocol.ts';
|
|
2
|
+
|
|
3
|
+
const READ_ONLY_TOOL_NAMES = ['read', 'grep', 'find', 'ls'] as const;
|
|
4
|
+
const CODING_TOOL_NAMES = ['read', 'bash', 'edit', 'write'] as const;
|
|
5
|
+
|
|
6
|
+
function normalizeToolName(name: string): string {
|
|
7
|
+
return name.trim().toLowerCase();
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function selectSubAgentToolNames(agentConfig: AgentDefinition): string[] {
|
|
11
|
+
const declared = new Set(
|
|
12
|
+
(agentConfig.tools ?? [])
|
|
13
|
+
.filter((name): name is string => typeof name === 'string' && name.trim().length > 0)
|
|
14
|
+
.map(normalizeToolName)
|
|
15
|
+
);
|
|
16
|
+
const needsBash = declared.has('bash');
|
|
17
|
+
const baseToolNames =
|
|
18
|
+
agentConfig.readOnly && !needsBash ? READ_ONLY_TOOL_NAMES : CODING_TOOL_NAMES;
|
|
19
|
+
const allowLegacyFallback =
|
|
20
|
+
agentConfig.strictToolSelection !== true && agentConfig.source === 'builtin';
|
|
21
|
+
|
|
22
|
+
if (declared.size === 0) {
|
|
23
|
+
return allowLegacyFallback ? [...baseToolNames] : [];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const filtered = baseToolNames.filter((toolName) => declared.has(toolName));
|
|
27
|
+
|
|
28
|
+
if (filtered.length > 0) {
|
|
29
|
+
return filtered;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return allowLegacyFallback ? [...baseToolNames] : [];
|
|
33
|
+
}
|