@mrquake/quakecode-cli 0.64.3 → 0.64.6
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/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/assistant-message.js +1 -0
- package/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/dist/modes/interactive/components/session-tabs.d.ts +9 -0
- package/dist/modes/interactive/components/session-tabs.d.ts.map +1 -0
- package/dist/modes/interactive/components/session-tabs.js +43 -0
- package/dist/modes/interactive/components/session-tabs.js.map +1 -0
- package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/user-message.js +3 -2
- package/dist/modes/interactive/components/user-message.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +1 -3
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +66 -20
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/package.json +2 -2
|
@@ -42,6 +42,7 @@ import { ModelSelectorComponent } from "./components/model-selector.js";
|
|
|
42
42
|
import { OAuthSelectorComponent } from "./components/oauth-selector.js";
|
|
43
43
|
import { ScopedModelsSelectorComponent } from "./components/scoped-models-selector.js";
|
|
44
44
|
import { SessionSelectorComponent } from "./components/session-selector.js";
|
|
45
|
+
import { SessionTabsComponent } from "./components/session-tabs.js";
|
|
45
46
|
import { SettingsSelectorComponent } from "./components/settings-selector.js";
|
|
46
47
|
import { SkillInvocationMessageComponent } from "./components/skill-invocation-message.js";
|
|
47
48
|
import { ToolExecutionComponent } from "./components/tool-execution.js";
|
|
@@ -161,6 +162,8 @@ export class InteractiveMode {
|
|
|
161
162
|
this.defaultEditor = new CustomEditor(this.ui, getEditorTheme(), this.keybindings, {
|
|
162
163
|
paddingX: editorPaddingX,
|
|
163
164
|
autocompleteMaxVisible,
|
|
165
|
+
noBorders: true,
|
|
166
|
+
prompt: theme.bold(theme.fg("accent", "› ")),
|
|
164
167
|
});
|
|
165
168
|
this.editor = this.defaultEditor;
|
|
166
169
|
this.editorContainer = new Container();
|
|
@@ -291,17 +294,20 @@ export class InteractiveMode {
|
|
|
291
294
|
this.fdPath = fdPath;
|
|
292
295
|
// Add header container as first child
|
|
293
296
|
this.ui.addChild(this.headerContainer);
|
|
297
|
+
this.headerContainer.addChild(new SessionTabsComponent(() => this.getSessionTabLabel(), () => DISPLAY_NAME));
|
|
298
|
+
this.headerContainer.addChild(new Spacer(1));
|
|
294
299
|
// Add header with keybindings from config (unless silenced)
|
|
295
300
|
if (this.options.verbose || !this.settingsManager.getQuietStartup()) {
|
|
296
301
|
const currentModel = this.session.model?.id ?? "no model";
|
|
297
302
|
const cwd = this.sessionManager.getCwd();
|
|
298
303
|
const owner = os.userInfo().username;
|
|
299
304
|
const title = `${DISPLAY_NAME} v${this.version}`;
|
|
300
|
-
const leftInner =
|
|
301
|
-
const maxTotalWidth = Math.max(
|
|
305
|
+
const leftInner = 44;
|
|
306
|
+
const maxTotalWidth = Math.max(128, Math.min(this.ui.terminal.columns - 6, 172));
|
|
302
307
|
const rightInner = maxTotalWidth - leftInner - 7;
|
|
303
308
|
const totalWidth = leftInner + rightInner + 7;
|
|
304
309
|
const border = (s) => theme.fg("borderAccent", s);
|
|
310
|
+
const accent = (s) => theme.bold(theme.fg("accent", s));
|
|
305
311
|
const fit = (text, width) => {
|
|
306
312
|
let out = text;
|
|
307
313
|
while (visibleWidth(out) > width && out.length > 0) {
|
|
@@ -316,19 +322,28 @@ export class InteractiveMode {
|
|
|
316
322
|
return out + " ".repeat(remaining);
|
|
317
323
|
};
|
|
318
324
|
const row = (left, right) => `${border("│")} ${fit(left, leftInner)} ${border("│")} ${fit(right, rightInner)} ${border("│")}`;
|
|
319
|
-
const top =
|
|
325
|
+
const top = `╭── ${title} ${"─".repeat(Math.max(0, totalWidth - title.length - 5))}╮`;
|
|
320
326
|
const bottom = `╰${"─".repeat(totalWidth - 2)}╯`;
|
|
321
|
-
const
|
|
322
|
-
const
|
|
323
|
-
const
|
|
327
|
+
const logo1 = accent(" ██████╗ ██╗ ██╗ █████╗ ██╗ ██╗███████╗ ");
|
|
328
|
+
const logo2 = accent("██╔═══██╗██║ ██║██╔══██╗██║ ██╔╝██╔════╝ ");
|
|
329
|
+
const logo3 = accent("██║ ██║██║ ██║███████║█████╔╝ █████╗ ");
|
|
330
|
+
const logo4 = accent("██║▄▄ ██║██║ ██║██╔══██║██╔═██╗ ██╔══╝ ");
|
|
331
|
+
const logo5 = accent("╚██████╔╝╚██████╔╝██║ ██║██║ ██╗███████╗ ");
|
|
332
|
+
const logo6 = accent(" ╚══▀▀═╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝ ");
|
|
333
|
+
const quick = theme.fg("muted", "/login") + " · " + theme.fg("muted", "/model") + " · " + theme.fg("muted", "/resume") + " · " + theme.fg("muted", "/agents");
|
|
334
|
+
const tips = `${theme.bold("Quick start")} ${quick}`;
|
|
335
|
+
const status = `${theme.bold("Model")} ${theme.fg("borderAccent", currentModel)} · ${theme.bold("User")} ${owner}`;
|
|
336
|
+
const workspace = `${theme.bold("Workspace")} ${cwd}`;
|
|
337
|
+
const note = theme.fg("dim", "Built for terminal-native coding, sessions, tools, and fast iteration.");
|
|
324
338
|
const dashboard = [
|
|
325
339
|
border(top),
|
|
326
|
-
row(
|
|
327
|
-
row(
|
|
328
|
-
row(
|
|
329
|
-
row(
|
|
330
|
-
row(
|
|
331
|
-
row(
|
|
340
|
+
row(logo1, `${theme.bold("Welcome back")} ${owner}`),
|
|
341
|
+
row(logo2, tips),
|
|
342
|
+
row(logo3, "Run /init to generate AGENTS.md for this repo."),
|
|
343
|
+
row(logo4, "Use Tab for completion, Ctrl+R to resume, and /settings to tune Quake."),
|
|
344
|
+
row(logo5, status),
|
|
345
|
+
row(logo6, workspace),
|
|
346
|
+
row(theme.fg("dim", " "), note),
|
|
332
347
|
border(bottom),
|
|
333
348
|
].join("\n");
|
|
334
349
|
this.builtInHeader = new Text(dashboard, 1, 0);
|
|
@@ -402,17 +417,21 @@ export class InteractiveMode {
|
|
|
402
417
|
// Initialize available provider count for footer display
|
|
403
418
|
await this.updateAvailableProviderCount();
|
|
404
419
|
}
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
420
|
+
getSessionTabLabel() {
|
|
421
|
+
return this.sessionManager.getSessionName() || path.basename(this.sessionManager.getCwd()) || "new session";
|
|
422
|
+
}
|
|
408
423
|
updateTerminalTitle() {
|
|
409
|
-
const cwdBasename = path.basename(this.sessionManager.getCwd());
|
|
410
424
|
const sessionName = this.sessionManager.getSessionName();
|
|
411
|
-
|
|
412
|
-
|
|
425
|
+
const title = sessionName ? `${DISPLAY_NAME} - ${sessionName}` : DISPLAY_NAME;
|
|
426
|
+
// Add spinner if agent is thinking or working
|
|
427
|
+
const isActive = this.session.agent.state.isStreaming || this.session.agent.state.pendingToolCalls.size > 0;
|
|
428
|
+
if (isActive) {
|
|
429
|
+
const frames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
|
430
|
+
const frame = frames[Math.floor(Date.now() / 100) % frames.length];
|
|
431
|
+
this.ui.terminal.setTitle(`${frame} ${title}`);
|
|
413
432
|
}
|
|
414
433
|
else {
|
|
415
|
-
this.ui.terminal.setTitle(
|
|
434
|
+
this.ui.terminal.setTitle(title);
|
|
416
435
|
}
|
|
417
436
|
}
|
|
418
437
|
/**
|
|
@@ -439,6 +458,13 @@ export class InteractiveMode {
|
|
|
439
458
|
this.showWarning(warning);
|
|
440
459
|
}
|
|
441
460
|
});
|
|
461
|
+
// Start thinking/working animation loop for terminal title
|
|
462
|
+
setInterval(() => {
|
|
463
|
+
const state = this.session.agent.state;
|
|
464
|
+
if (state.isStreaming || state.pendingToolCalls.size > 0) {
|
|
465
|
+
this.updateTerminalTitle();
|
|
466
|
+
}
|
|
467
|
+
}, 100);
|
|
442
468
|
// Show startup warnings
|
|
443
469
|
const { migratedProviders, modelFallbackMessage, initialMessage, initialImages, initialMessages } = this.options;
|
|
444
470
|
if (migratedProviders && migratedProviders.length > 0) {
|
|
@@ -1885,7 +1911,27 @@ export class InteractiveMode {
|
|
|
1885
1911
|
this.loadingAnimation.stop();
|
|
1886
1912
|
}
|
|
1887
1913
|
this.statusContainer.clear();
|
|
1888
|
-
|
|
1914
|
+
// Create loading animation with "shimmer" effect support
|
|
1915
|
+
this.loadingAnimation = new Loader(this.ui, (spinner) => theme.fg("accent", spinner), (text) => {
|
|
1916
|
+
// Custom "shimmer" effect for the working message text
|
|
1917
|
+
const chars = text.split("");
|
|
1918
|
+
if (chars.length === 0)
|
|
1919
|
+
return "";
|
|
1920
|
+
const sweepSeconds = 2.0;
|
|
1921
|
+
const padding = 10;
|
|
1922
|
+
const period = chars.length + padding * 2;
|
|
1923
|
+
const posF = ((Date.now() / 1000) % sweepSeconds) / sweepSeconds * period;
|
|
1924
|
+
const pos = Math.floor(posF);
|
|
1925
|
+
const bandHalfWidth = 5;
|
|
1926
|
+
return chars.map((ch, i) => {
|
|
1927
|
+
const dist = Math.abs(i + padding - pos);
|
|
1928
|
+
if (dist <= bandHalfWidth) {
|
|
1929
|
+
// Glow effect: Bold + Accent color
|
|
1930
|
+
return theme.bold(theme.fg("accent", ch));
|
|
1931
|
+
}
|
|
1932
|
+
return theme.fg("muted", ch);
|
|
1933
|
+
}).join("");
|
|
1934
|
+
}, this.defaultWorkingMessage);
|
|
1889
1935
|
this.statusContainer.addChild(this.loadingAnimation);
|
|
1890
1936
|
// Apply any pending working message queued before loader existed
|
|
1891
1937
|
if (this.pendingWorkingMessage !== undefined) {
|