@sns-myagent/cli 0.3.7 → 0.3.9

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 (70) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/README.md +63 -24
  3. package/bin/snsagent.js +3 -41
  4. package/dist/cli.js +3267 -3288
  5. package/package.json +3 -3
  6. package/src/adapters/telegram/handler.ts +1 -1
  7. package/src/agents/ensemble.ts +3 -4
  8. package/src/agents/executor.ts +129 -0
  9. package/src/async/notifier.ts +1 -1
  10. package/src/cli/config-cli.ts +1 -1
  11. package/src/cli/entry.ts +2 -2
  12. package/src/cli/gallery-fixtures/misc.ts +3 -3
  13. package/src/cli/grep-cli.ts +3 -3
  14. package/src/cli/grievances-cli.ts +2 -2
  15. package/src/cli/index.ts +243 -24
  16. package/src/cli/plugin-cli.ts +5 -5
  17. package/src/cli/setup-cli.ts +3 -3
  18. package/src/cli/setup-model-picker.ts +1 -1
  19. package/src/cli/shell-cli.ts +1 -1
  20. package/src/cli/ssh-cli.ts +1 -1
  21. package/src/cli/stats-cli.ts +1 -1
  22. package/src/cli/tiny-models-cli.ts +3 -3
  23. package/src/cli/ttsr-cli.ts +2 -2
  24. package/src/cli/update-cli.ts +3 -3
  25. package/src/cli/usage-cli.ts +1 -1
  26. package/src/cli-commands.ts +6 -6
  27. package/src/commands/acp.ts +2 -2
  28. package/src/commands/chat.ts +3 -3
  29. package/src/commands/install.ts +5 -5
  30. package/src/commands/say.ts +4 -4
  31. package/src/commands/setup.ts +1 -1
  32. package/src/config/defaults.ts +5 -3
  33. package/src/config/schema.ts +8 -0
  34. package/src/config/settings-schema.ts +1 -1
  35. package/src/config/sns-config.ts +1 -1
  36. package/src/extensibility/plugins/loader.ts +1 -1
  37. package/src/extensibility/plugins/manager.ts +2 -2
  38. package/src/hindsight/client.ts +1 -1
  39. package/src/internal-urls/docs-index.generated.txt +2 -0
  40. package/src/main.ts +4 -0
  41. package/src/modes/acp/acp-agent.ts +3 -3
  42. package/src/modes/components/plugin-settings.ts +2 -2
  43. package/src/modes/components/welcome.ts +66 -160
  44. package/src/modes/interactive-mode.ts +2 -2
  45. package/src/modes/print-mode.ts +2 -2
  46. package/src/modes/setup-version.ts +1 -1
  47. package/src/modes/setup-wizard/scenes/byok-setup.ts +354 -0
  48. package/src/modes/setup-wizard/scenes/outro.ts +2 -2
  49. package/src/modes/setup-wizard/scenes/providers.ts +6 -5
  50. package/src/modes/setup-wizard/scenes/splash.ts +3 -3
  51. package/src/modes/setup-wizard/wizard-overlay.ts +2 -2
  52. package/src/modes/theme/dark.json +21 -20
  53. package/src/modes/theme/light.json +30 -29
  54. package/src/modes/utils/ui-helpers.ts +1 -1
  55. package/src/slash-commands/builtin-registry.ts +6 -3
  56. package/src/stt/recorder.ts +3 -3
  57. package/src/tts/player.ts +1 -1
  58. package/src/tts/tts-client.ts +1 -1
  59. package/src/tui/chat-blocks.ts +4 -4
  60. package/src/tui/chat-ui.ts +3 -3
  61. package/src/tui/code-cell.ts +3 -3
  62. package/src/tui/command-palette.ts +3 -3
  63. package/src/tui/splash.ts +12 -18
  64. package/src/ui/banner.ts +51 -66
  65. package/src/ui/chat-prompt.ts +2 -2
  66. package/src/ui/colors.ts +17 -14
  67. package/src/ui/error-display.ts +2 -2
  68. package/src/ui/gradient.ts +3 -3
  69. package/src/ui/memory-toast.ts +5 -5
  70. package/src/ui/status-bar.ts +1 -1
@@ -1,5 +1,5 @@
1
1
  import { padding, truncateToWidth, visibleWidth } from "@oh-my-pi/pi-tui";
2
- import { gradientLogo, PI_LOGO } from "../../components/welcome";
2
+ import { gradientLogo, SNS_LOGO } from "../../components/welcome";
3
3
  import { theme } from "../../theme/theme";
4
4
  import { renderStarfield, SETUP_TICK_MS } from "./splash";
5
5
 
@@ -21,7 +21,7 @@ export function renderSetupOutro(width: number, height: number, elapsedMs: numbe
21
21
  const frame = Math.floor(elapsedMs / SETUP_TICK_MS);
22
22
  const lines = renderStarfield(width, height, frame + 1000);
23
23
  const progress = Math.max(0, Math.min(1, elapsedMs / SETUP_OUTRO_MS));
24
- const logo = gradientLogo(PI_LOGO, progress * 1.2, { pos: (progress * 2) % 1, strength: 1 - progress });
24
+ const logo = gradientLogo(SNS_LOGO, progress * 1.2, { pos: (progress * 2) % 1, strength: 1 - progress });
25
25
  const title = theme.bold(theme.fg("success", `${theme.status.success} Setup saved`));
26
26
  const subtitle = theme.fg("muted", "Handing off to the normal CLI…");
27
27
  const sweepWidth = Math.max(1, Math.min(width - 8, Math.floor((width - 8) * progress)));
@@ -1,18 +1,19 @@
1
1
  import { type SgrMouseEvent, TabBar } from "@oh-my-pi/pi-tui";
2
2
  import { getTabBarTheme } from "../../shared";
3
+ import { ByokSetupTab } from "./byok-setup";
3
4
  import { SignInTab } from "./sign-in";
4
5
  import type { SetupScene, SetupSceneController, SetupSceneHost, SetupTab } from "./types";
5
6
  import { WebSearchTab } from "./web-search";
6
7
 
7
8
  /**
8
9
  * Tabbed "Set up your providers" scene. Composes independent panels (model
9
- * sign-in, web search) behind a {@link TabBar}; the active panel owns
10
- * rendering and input, while modal panels (e.g. an in-flight OAuth login)
11
- * temporarily suppress tab switching.
10
+ * sign-in, BYOK quick-connect, web search) behind a {@link TabBar}; the active
11
+ * panel owns rendering and input, while modal panels (e.g. an in-flight OAuth
12
+ * login) temporarily suppress tab switching.
12
13
  */
13
14
  class ProvidersSceneController implements SetupSceneController {
14
15
  title = "Set up your providers";
15
- subtitle = "Sign in and pick a web search provider. Press Esc when you're done.";
16
+ subtitle = "Sign in, bring your own key, or pick a web search provider. Press Esc when you're done.";
16
17
 
17
18
  #tabs: SetupTab[];
18
19
  #tabBar: TabBar;
@@ -20,7 +21,7 @@ class ProvidersSceneController implements SetupSceneController {
20
21
  #tabRowCount = 1;
21
22
 
22
23
  constructor(host: SetupSceneHost) {
23
- this.#tabs = [new SignInTab(host), new WebSearchTab(host)];
24
+ this.#tabs = [new ByokSetupTab(host), new SignInTab(host), new WebSearchTab(host)];
24
25
  this.#tabBar = new TabBar(
25
26
  "Providers",
26
27
  this.#tabs.map(tab => ({ id: tab.id, label: tab.label })),
@@ -1,12 +1,12 @@
1
1
  import { padding, truncateToWidth, visibleWidth } from "@oh-my-pi/pi-tui";
2
- import { gradientEscape, gradientLogo, PI_LOGO, type ShineConfig } from "../../components/welcome";
2
+ import { gradientEscape, gradientLogo, SNS_LOGO, type ShineConfig } from "../../components/welcome";
3
3
  import { theme } from "../../theme/theme";
4
4
 
5
5
  export const SETUP_SPLASH_MS = 2600;
6
6
  export const SETUP_TICK_MS = 33;
7
7
 
8
8
  /** Brand mark at 2x: every glyph doubled horizontally, every row doubled vertically. */
9
- const LARGE_LOGO = PI_LOGO.flatMap(line => {
9
+ const LARGE_LOGO = SNS_LOGO.flatMap(line => {
10
10
  let wide = "";
11
11
  for (const char of line) {
12
12
  wide += char === " " ? " " : `${char}${char}`;
@@ -188,7 +188,7 @@ export function renderSetupSplash(width: number, height: number, elapsedMs: numb
188
188
 
189
189
  /** Centered fallback for windows too small to hold the full scene. */
190
190
  function renderCompactSplash(width: number, height: number, phase: number, shine: ShineConfig): string[] {
191
- const art = height >= 14 ? LARGE_LOGO : PI_LOGO;
191
+ const art = height >= 14 ? LARGE_LOGO : SNS_LOGO;
192
192
  const content = [...gradientLogo(art, phase, shine), "", theme.bold("S n s A g e n t")];
193
193
  const start = Math.max(0, Math.floor((height - content.length) / 2));
194
194
  const lines: string[] = [];
@@ -8,7 +8,7 @@ import {
8
8
  visibleWidth,
9
9
  } from "@oh-my-pi/pi-tui";
10
10
  import { APP_NAME } from "@oh-my-pi/pi-utils";
11
- import { gradientLogo, PI_LOGO } from "../components/welcome";
11
+ import { gradientLogo, SNS_LOGO } from "../components/welcome";
12
12
  import { theme } from "../theme/theme";
13
13
  import type { InteractiveModeContext } from "../types";
14
14
  import { renderSetupOutro, SETUP_OUTRO_MS } from "./scenes/outro";
@@ -200,7 +200,7 @@ export class SetupWizardComponent implements Component, OverlayFocusOwner {
200
200
  const title = this.#activeScene?.title ?? scene?.title ?? "Setup";
201
201
  const subtitle = this.#activeScene?.subtitle;
202
202
  const contentWidth = Math.max(MIN_CONTENT_WIDTH, width - SCENE_MARGIN_X * 2);
203
- const logo = gradientLogo(PI_LOGO, 0);
203
+ const logo = gradientLogo(SNS_LOGO, 0);
204
204
  const header = [
205
205
  "",
206
206
  ...logo.map(line => centerLine(line, width)),
@@ -1,18 +1,19 @@
1
1
  {
2
- "$schema": "https://raw.githubusercontent.com/can1357/oh-my-pi/main/packages/coding-agent/theme-schema.json",
2
+ "$schema": "sns-agent",
3
3
  "name": "dark",
4
4
  "vars": {
5
- "cyan": "#0088fa",
6
- "blue": "#178fb9",
5
+ "orange": "#F97316",
6
+ "orangeDeep": "#EA580C",
7
+ "orangeLight": "#FB923C",
7
8
  "green": "#89d281",
8
9
  "red": "#fc3a4b",
9
10
  "yellow": "#e4c00f",
10
11
  "gray": "#777d88",
11
12
  "dimGray": "#5f6673",
12
13
  "darkGray": "#3d424a",
13
- "accent": "#febc38",
14
- "selectedBg": "#31363f",
15
- "userMsgBg": "#221d1a",
14
+ "accent": "#F97316",
15
+ "selectedBg": "#2a1d12",
16
+ "userMsgBg": "#1a1410",
16
17
  "toolPendingBg": "#1d2129",
17
18
  "toolSuccessBg": "#161a1f",
18
19
  "toolErrorBg": "#291d1d",
@@ -20,8 +21,8 @@
20
21
  },
21
22
  "colors": {
22
23
  "accent": "accent",
23
- "border": "blue",
24
- "borderAccent": "cyan",
24
+ "border": "orange",
25
+ "borderAccent": "orange",
25
26
  "borderMuted": "darkGray",
26
27
  "success": "green",
27
28
  "error": "red",
@@ -35,14 +36,14 @@
35
36
  "userMessageText": "",
36
37
  "customMessageBg": "customMsgBg",
37
38
  "customMessageText": "",
38
- "customMessageLabel": "#b281d6",
39
+ "customMessageLabel": "#FB923C",
39
40
  "toolPendingBg": "toolPendingBg",
40
41
  "toolSuccessBg": "toolSuccessBg",
41
42
  "toolErrorBg": "toolErrorBg",
42
43
  "toolTitle": "",
43
44
  "toolOutput": "gray",
44
- "mdHeading": "#febc38",
45
- "mdLink": "#0088fa",
45
+ "mdHeading": "#F97316",
46
+ "mdLink": "#FB923C",
46
47
  "mdLinkUrl": "dimGray",
47
48
  "mdCode": "#e5c1ff",
48
49
  "mdCodeBlock": "#9CDCFE",
@@ -54,7 +55,7 @@
54
55
  "toolDiffAdded": "green",
55
56
  "toolDiffRemoved": "red",
56
57
  "toolDiffContext": "gray",
57
- "link": "#0088fa",
58
+ "link": "#FB923C",
58
59
  "syntaxComment": "#6A9955",
59
60
  "syntaxKeyword": "#569CD6",
60
61
  "syntaxFunction": "#DCDCAA",
@@ -66,19 +67,19 @@
66
67
  "syntaxPunctuation": "#D4D4D4",
67
68
  "thinkingOff": "darkGray",
68
69
  "thinkingMinimal": "dimGray",
69
- "thinkingLow": "#178fb9",
70
- "thinkingMedium": "#0088fa",
71
- "thinkingHigh": "#b281d6",
72
- "thinkingXhigh": "#e5c1ff",
73
- "bashMode": "cyan",
70
+ "thinkingLow": "#EA580C",
71
+ "thinkingMedium": "#F97316",
72
+ "thinkingHigh": "#FB923C",
73
+ "thinkingXhigh": "#FDBA74",
74
+ "bashMode": "orange",
74
75
  "statusLineBg": "#121212",
75
76
  "statusLineSep": 244,
76
- "statusLineModel": "#d787af",
77
- "statusLinePath": "#00afaf",
77
+ "statusLineModel": "#FB923C",
78
+ "statusLinePath": "#F97316",
78
79
  "statusLineGitClean": "#5faf5f",
79
80
  "statusLineGitDirty": "#d7af5f",
80
81
  "statusLineContext": "#8787af",
81
- "statusLineSpend": "#5fafaf",
82
+ "statusLineSpend": "#FB923C",
82
83
  "statusLineStaged": 70,
83
84
  "statusLineDirty": 178,
84
85
  "statusLineUntracked": 39,
@@ -1,26 +1,27 @@
1
1
  {
2
- "$schema": "https://raw.githubusercontent.com/can1357/oh-my-pi/main/packages/coding-agent/theme-schema.json",
2
+ "$schema": "sns-agent",
3
3
  "name": "light",
4
4
  "vars": {
5
- "teal": "#5a8080",
6
- "blue": "#547da7",
5
+ "orange": "#EA580C",
6
+ "orangeDeep": "#C2410C",
7
+ "orangeLight": "#F97316",
7
8
  "green": "#588458",
8
9
  "red": "#aa5555",
9
10
  "yellow": "#9a7326",
10
11
  "mediumGray": "#6c6c6c",
11
12
  "dimGray": "#767676",
12
13
  "lightGray": "#b0b0b0",
13
- "selectedBg": "#d0d0e0",
14
- "userMsgBg": "#e8e8e8",
15
- "toolPendingBg": "#e8e8f0",
16
- "toolSuccessBg": "#e8f0e8",
17
- "toolErrorBg": "#f0e8e8",
18
- "customMsgBg": "#ede7f6"
14
+ "selectedBg": "#fdf0e6",
15
+ "userMsgBg": "#faf5f0",
16
+ "toolPendingBg": "#f0f0f0",
17
+ "toolSuccessBg": "#f0f8f0",
18
+ "toolErrorBg": "#f8f0f0",
19
+ "customMsgBg": "#fff5eb"
19
20
  },
20
21
  "colors": {
21
- "accent": "teal",
22
- "border": "blue",
23
- "borderAccent": "teal",
22
+ "accent": "orange",
23
+ "border": "orange",
24
+ "borderAccent": "orange",
24
25
  "borderMuted": "lightGray",
25
26
  "success": "green",
26
27
  "error": "red",
@@ -34,22 +35,22 @@
34
35
  "userMessageText": "",
35
36
  "customMessageBg": "customMsgBg",
36
37
  "customMessageText": "",
37
- "customMessageLabel": "#7e57c2",
38
+ "customMessageLabel": "#C2410C",
38
39
  "toolPendingBg": "toolPendingBg",
39
40
  "toolSuccessBg": "toolSuccessBg",
40
41
  "toolErrorBg": "toolErrorBg",
41
42
  "toolTitle": "",
42
43
  "toolOutput": "mediumGray",
43
- "mdHeading": "yellow",
44
- "mdLink": "blue",
44
+ "mdHeading": "orange",
45
+ "mdLink": "orangeLight",
45
46
  "mdLinkUrl": "dimGray",
46
- "mdCode": "teal",
47
+ "mdCode": "orangeDeep",
47
48
  "mdCodeBlock": "green",
48
49
  "mdCodeBlockBorder": "mediumGray",
49
50
  "mdQuote": "mediumGray",
50
51
  "mdQuoteBorder": "mediumGray",
51
52
  "mdHr": "mediumGray",
52
- "mdListBullet": "green",
53
+ "mdListBullet": "orange",
53
54
  "toolDiffAdded": "green",
54
55
  "toolDiffRemoved": "red",
55
56
  "toolDiffContext": "mediumGray",
@@ -64,30 +65,30 @@
64
65
  "syntaxPunctuation": "#000000",
65
66
  "thinkingOff": "lightGray",
66
67
  "thinkingMinimal": "#767676",
67
- "thinkingLow": "blue",
68
- "thinkingMedium": "teal",
69
- "thinkingHigh": "#875f87",
70
- "thinkingXhigh": "#8b008b",
71
- "bashMode": "green",
72
- "statusLineBg": "#e0e0e0",
68
+ "thinkingLow": "orangeDeep",
69
+ "thinkingMedium": "orange",
70
+ "thinkingHigh": "orangeLight",
71
+ "thinkingXhigh": "#FDBA74",
72
+ "bashMode": "orange",
73
+ "statusLineBg": "#f0f0f0",
73
74
  "statusLineSep": "#808080",
74
- "statusLineModel": "#875f87",
75
- "statusLinePath": "#005f87",
75
+ "statusLineModel": "#EA580C",
76
+ "statusLinePath": "#C2410C",
76
77
  "statusLineGitClean": "#005f00",
77
78
  "statusLineGitDirty": "#af5f00",
78
79
  "statusLineContext": "#5f5f87",
79
- "statusLineSpend": "#005f5f",
80
+ "statusLineSpend": "#EA580C",
80
81
  "statusLineStaged": 28,
81
82
  "statusLineDirty": 136,
82
83
  "statusLineUntracked": 31,
83
84
  "statusLineOutput": 133,
84
85
  "statusLineCost": 133,
85
- "statusLineSubagents": "teal",
86
+ "statusLineSubagents": "orange",
86
87
  "pythonMode": "yellow"
87
88
  },
88
89
  "export": {
89
- "pageBg": "#f8f8f8",
90
+ "pageBg": "#faf8f5",
90
91
  "cardBg": "#ffffff",
91
- "infoBg": "#fffae6"
92
+ "infoBg": "#fff5eb"
92
93
  }
93
94
  }
@@ -569,7 +569,7 @@ export class UiHelpers {
569
569
  theme.bold(theme.fg("warning", "Update Available")) +
570
570
  "\n" +
571
571
  theme.fg("muted", `New version ${newVersion} is available. Run: `) +
572
- theme.fg("accent", "omp update"),
572
+ theme.fg("accent", "snsagent update"),
573
573
  1,
574
574
  0,
575
575
  ),
@@ -214,14 +214,17 @@ const BUILTIN_SLASH_COMMAND_REGISTRY: ReadonlyArray<SlashCommandSpec> = [
214
214
  aliases: ["providers"],
215
215
  description: "Open provider setup",
216
216
  allowArgs: true,
217
- subcommands: [{ name: "providers", description: "Configure sign-in and web search providers" }],
217
+ subcommands: [
218
+ { name: "providers", description: "Configure sign-in and web search providers" },
219
+ { name: "byok", description: "Add custom AI provider (Base URL + API Key)" },
220
+ ],
218
221
  handleTui: async (command, runtime) => {
219
222
  const args = command.args.trim().toLowerCase();
220
- const opensProviders = args === "" || args === "providers";
223
+ const opensProviders = args === "" || args === "providers" || args === "byok";
221
224
  if (opensProviders) {
222
225
  await runtime.ctx.showProviderSetup();
223
226
  } else {
224
- runtime.ctx.showWarning(`Usage: /${command.name} [providers]`);
227
+ runtime.ctx.showWarning(`Usage: /${command.name} [providers|byok]`);
225
228
  }
226
229
  runtime.ctx.editor.setText("");
227
230
  },
@@ -355,7 +355,7 @@ async function startRecordingWithRecorder(recorder: ResolvedRecorder, outputPath
355
355
  export async function startRecording(outputPath: string): Promise<RecordingHandle> {
356
356
  const recorders = detectRecorders();
357
357
  if (recorders.length === 0) {
358
- throw new Error("No audio recorder available — run `omp setup speech`");
358
+ throw new Error("No audio recorder available — run `snsagent setup speech`");
359
359
  }
360
360
 
361
361
  const failures: string[] = [];
@@ -372,7 +372,7 @@ export async function startRecording(outputPath: string): Promise<RecordingHandl
372
372
  });
373
373
  }
374
374
  }
375
- throw new Error(`No audio recorder could start — run \`omp setup speech\`.\n${failures.join("\n")}`);
375
+ throw new Error(`No audio recorder could start — run \`snsagent setup speech\`.\n${failures.join("\n")}`);
376
376
  }
377
377
 
378
378
  /**
@@ -515,7 +515,7 @@ export async function startStreamingRecording(
515
515
  ): Promise<StreamingRecordingHandle | null> {
516
516
  const recorders = detectRecorders();
517
517
  if (recorders.length === 0) {
518
- throw new Error("No audio recorder available — run `omp setup speech`");
518
+ throw new Error("No audio recorder available — run `snsagent setup speech`");
519
519
  }
520
520
  const streamingRecorders = recorders.filter(recorder => recorder.tool !== "powershell");
521
521
  if (streamingRecorders.length === 0) return null;
package/src/tts/player.ts CHANGED
@@ -93,7 +93,7 @@ export async function playAudioFile(filePath: string, options: PlayAudioOptions
93
93
  if (commands.length === 0) {
94
94
  throw new Error(
95
95
  "No audio player available. Install PulseAudio (paplay) or ALSA (aplay), " +
96
- "or run `omp setup speech` to download a bundled ffmpeg.",
96
+ "or run `snsagent setup speech` to download a bundled ffmpeg.",
97
97
  );
98
98
  }
99
99
 
@@ -379,7 +379,7 @@ export class TtsClient {
379
379
 
380
380
  /**
381
381
  * The TTS subprocess is spawned `unref`'d so an idle worker never blocks
382
- * process exit. A short-lived CLI command (`omp say`) awaiting a request would
382
+ * process exit. A short-lived CLI command (`snsagent say`) awaiting a request would
383
383
  * otherwise let the event loop drain and exit before the audio arrives, so we
384
384
  * `ref` the worker exactly while at least one request is pending.
385
385
  */
@@ -16,7 +16,7 @@ const ROLE_LABEL: Record<MessageRole, string> = {
16
16
  error: "error",
17
17
  };
18
18
 
19
- const BULLET = chalk.cyan("●");
19
+ const BULLET = chalk.hex("#F97316")("●");
20
20
 
21
21
  export interface ChatBlockOptions {
22
22
  role: MessageRole;
@@ -73,7 +73,7 @@ export function renderChatBlock(opts: ChatBlockOptions): string {
73
73
  const parts: string[] = [header, ...indented];
74
74
 
75
75
  if (opts.streaming) {
76
- parts.push(` ${chalk.dim("│")} ${chalk.cyan("…")} ${chalk.dim("thinking")}`);
76
+ parts.push(` ${chalk.dim("│")} ${chalk.hex("#F97316")("…")} ${chalk.dim("thinking")}`);
77
77
  }
78
78
 
79
79
  return parts.join("\n");
@@ -99,7 +99,7 @@ export function renderToolBlock(
99
99
  status: "running" | "done" | "error",
100
100
  detail?: string,
101
101
  ): string {
102
- const icon = status === "running" ? chalk.cyan("●") : status === "done" ? chalk.green("●") : chalk.red("●");
102
+ const icon = status === "running" ? chalk.hex("#F97316")("●") : status === "done" ? chalk.green("●") : chalk.red("●");
103
103
  const label = ` ${icon} tool:${toolName} `;
104
104
  const detailText = detail ? chalk.dim(` ${detail}`) : "";
105
105
  return label + detailText;
@@ -107,5 +107,5 @@ export function renderToolBlock(
107
107
 
108
108
  /** Session header — single line. */
109
109
  export function renderSessionHeader(model: string, version: string): string {
110
- return ` ${chalk.cyan.bold("MY")} ${chalk.bold("snsagent")} ${chalk.dim(`v${version}`)} ${chalk.dim("·")} ${chalk.cyan(model)}\n`;
110
+ return ` ${chalk.hex("#F97316")("SNS")} ${chalk.bold("snsagent")} ${chalk.dim(`v${version}`)} ${chalk.dim("·")} ${chalk.hex("#F97316")(model)}\n`;
111
111
  }
@@ -98,7 +98,7 @@ const BUILTIN_COMMANDS: SlashCommand[] = [
98
98
  description: "Show available commands",
99
99
  handler: (_args, ctx) => {
100
100
  const lines = BUILTIN_COMMANDS.map(
101
- c => ` ${chalk.cyan(c.name.padEnd(14))}${chalk.dim(c.description)}`
101
+ c => ` ${chalk.hex("#F97316")(c.name.padEnd(14))}${chalk.dim(c.description)}`
102
102
  ).join("\n");
103
103
  ctx.print(renderChatBlock({
104
104
  role: "system",
@@ -176,7 +176,7 @@ export async function runChatSession(config: ChatSessionConfig): Promise<void> {
176
176
 
177
177
  // Readline loop
178
178
  while (true) {
179
- const promptStr = chalk.cyan("you") + chalk.dim(" › ");
179
+ const promptStr = chalk.hex("#F97316")("you") + chalk.dim(" › ");
180
180
  let line: string;
181
181
  try {
182
182
  const rl = createInterface({ input: stdin, output: stdout });
@@ -224,7 +224,7 @@ export async function runChatSession(config: ChatSessionConfig): Promise<void> {
224
224
  const spinner = ora({
225
225
  text: chalk.dim("thinking..."),
226
226
  spinner: "dots",
227
- color: "cyan",
227
+ color: "yellow",
228
228
  }).start();
229
229
 
230
230
  try {
@@ -247,15 +247,15 @@ export function renderCollapsibleOutput(
247
247
  // Collapsed: just header + hint
248
248
  const lineCount = content.split("\n").length;
249
249
  const hint = chalk.dim(` (${lineCount} lines, click to expand)`);
250
- lines.push(` ${chalk.cyan("▸")} ${chalk.bold(label)}${hint}`);
250
+ lines.push(` ${chalk.hex("#F97316")("▸")} ${chalk.bold(label)}${hint}`);
251
251
  return lines;
252
252
  }
253
253
 
254
254
  // Expanded: bordered block
255
- const accent = chalk.cyan;
255
+ const accent = chalk.hex("#F97316");
256
256
 
257
257
  // Expanded: bordered block
258
- const accentFn = (s: string) => chalk.cyan(s);
258
+ const accentFn = (s: string) => chalk.hex("#F97316")(s);
259
259
 
260
260
  // Header
261
261
  const headerText = ` ${label} `;
@@ -47,7 +47,7 @@ export function renderCommandPalette(opts: CommandPaletteOptions): string {
47
47
  const lines: string[] = [];
48
48
 
49
49
  // Search line
50
- lines.push(` ${chalk.cyan("?")} ${query}${chalk.dim(" (↑↓ navigate · Enter select · Esc cancel)")}`);
50
+ lines.push(` ${chalk.hex("#F97316")("?")} ${query}${chalk.dim(" (↑↓ navigate · Enter select · Esc cancel)")}`);
51
51
  lines.push("");
52
52
 
53
53
  if (filtered.length === 0) {
@@ -55,8 +55,8 @@ export function renderCommandPalette(opts: CommandPaletteOptions): string {
55
55
  } else {
56
56
  filtered.forEach((cmd, idx) => {
57
57
  const isActive = idx === highlighted;
58
- const prefix = isActive ? chalk.cyan("●") : " ";
59
- const name = isActive ? chalk.cyan.bold(cmd.name) : chalk.cyan(cmd.name);
58
+ const prefix = isActive ? chalk.hex("#F97316")("●") : " ";
59
+ const name = isActive ? chalk.hex("#F97316").bold(cmd.name) : chalk.hex("#F97316")(cmd.name);
60
60
  const desc = chalk.dim(cmd.description);
61
61
  const cat = chalk.dim(` [${cmd.category}]`);
62
62
  const shortcut = cmd.shortcut ? chalk.dim(` ${cmd.shortcut}`) : "";
package/src/tui/splash.ts CHANGED
@@ -1,7 +1,6 @@
1
1
  /**
2
- * SNS-MyAgent splash — flat list, no boxes.
3
- * Single line brand + `●` prefixed info rows. No rounded borders, no
4
- * gradient, no separator boxes. Reads like a status line.
2
+ * SNS Agent splash — clean, minimal, no boxes.
3
+ * Orange accent dot + flat info rows. Zero OMP/Pi Agent visual language.
5
4
  */
6
5
  import chalk from "chalk";
7
6
  import { readFileSync } from "node:fs";
@@ -48,31 +47,26 @@ export interface SplashInfo {
48
47
  nodeVersion?: string;
49
48
  }
50
49
 
51
- /**
52
- * One-line prefix used throughout the TUI.
53
- * `●` = present, default text. No rounded boxes.
54
- */
55
- const BULLET = chalk.cyan("●");
50
+ const DOT = chalk.hex("#F97316")("●");
56
51
 
57
52
  export function renderSplash(info: SplashInfo = {}): string {
58
53
  const ver = readVersion();
59
54
  const lines: string[] = [];
60
55
 
61
- // Brand line: MY · snsagent · v0.3.6
62
- lines.push(` ${chalk.cyan.bold("MY")} ${chalk.bold("snsagent")} ${chalk.dim(`v${ver}`)}`);
63
- lines.push(` ${chalk.dim("coding agent CLI")}`);
56
+ // Brand orange dot + bold name + dim version
57
+ lines.push(` ${DOT} ${chalk.bold("SNS")} ${chalk.dim(`v${ver}`)}`);
64
58
  lines.push("");
65
59
 
66
- // Status lines — flat, one per line, ● prefix
67
- const row = (label: string, value: string) => ` ${BULLET} ${chalk.dim(label.padEnd(13))}${value}`;
60
+ // Status rows
61
+ const row = (label: string, value: string) =>
62
+ ` ${chalk.dim("·")} ${chalk.dim(label.padEnd(12))}${value}`;
68
63
  if (info.model) lines.push(row("model", `${info.provider ?? "unknown"}/${info.model}`));
69
64
  if (info.cwd) lines.push(row("dir", info.cwd));
70
65
  if (info.platform) lines.push(row("platform", info.platform));
71
- lines.push(row("version", ver));
72
66
 
73
- // Hints
67
+ // Footer
74
68
  lines.push("");
75
- lines.push(` ${chalk.dim("type to chat · /exit to quit")}`);
69
+ lines.push(` ${chalk.dim("chat to configure · /help for commands")}`);
76
70
 
77
71
  return lines.join("\n") + "\n";
78
72
  }
@@ -80,7 +74,7 @@ export function renderSplash(info: SplashInfo = {}): string {
80
74
  export function renderInlineHeader(info: SplashInfo = {}): string {
81
75
  const ver = readVersion();
82
76
  const model = info.model
83
- ? chalk.cyan(`${info.provider ?? "?"}/${info.model}`)
77
+ ? chalk.hex("#F97316")(`${info.provider ?? "?"}/${info.model}`)
84
78
  : chalk.dim("no model");
85
- return ` ${chalk.cyan.bold("MY")} ${chalk.bold("snsagent")} ${chalk.dim(`v${ver}`)} ${chalk.dim("·")} ${model}\n`;
79
+ return ` ${DOT} ${chalk.bold("SNS")} ${chalk.dim(`v${ver}`)} ${chalk.dim("·")} ${model}\n`;
86
80
  }