swarmlancer-cli 0.2.0 → 0.2.1

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/agent.js CHANGED
@@ -21,7 +21,7 @@ function resetIdleTimer(limits, log) {
21
21
  if (idleTimer)
22
22
  clearTimeout(idleTimer);
23
23
  idleTimer = setTimeout(() => {
24
- log(colors.yellow(`⏱ Auto-stopping: idle for ${limits.autoStopIdleMinutes} minutes`));
24
+ log(colors.lime(`⏱ Auto-stopping: idle for ${limits.autoStopIdleMinutes} minutes`));
25
25
  stopAgent();
26
26
  }, limits.autoStopIdleMinutes * 60 * 1000);
27
27
  }
@@ -35,7 +35,7 @@ function resetIdleTimer(limits, log) {
35
35
  export function startAgent(limits = DEFAULT_LIMITS, agentId, agentName, log = console.log) {
36
36
  const config = getConfig();
37
37
  if (!config.token) {
38
- log(colors.red("Not logged in. Run: swarmlancer login"));
38
+ log(colors.lime("Not logged in. Run: swarmlancer login"));
39
39
  return;
40
40
  }
41
41
  resetCounters();
@@ -44,7 +44,7 @@ export function startAgent(limits = DEFAULT_LIMITS, agentId, agentName, log = co
44
44
  // Log limits
45
45
  log(colors.gray(`Limits: ${limits.maxConcurrentConversations} concurrent, ${limits.maxMessagesPerConversation} msgs/convo, ${limits.cooldownSeconds}s cooldown, ${limits.maxConversationsPerSession} max/session, ${limits.autoStopIdleMinutes}m idle`));
46
46
  function connect() {
47
- log(colors.cyan(`Connecting to ${wsUrl}...`));
47
+ log(colors.lime(`Connecting to ${wsUrl}...`));
48
48
  const ws = new WebSocket(wsUrl);
49
49
  activeWs = ws;
50
50
  // Start idle timer
@@ -56,7 +56,7 @@ export function startAgent(limits = DEFAULT_LIMITS, agentId, agentName, log = co
56
56
  const msg = JSON.parse(raw.toString());
57
57
  switch (msg.type) {
58
58
  case "authenticated":
59
- log(colors.green("Agent online"));
59
+ log(colors.lime("Agent online"));
60
60
  log("");
61
61
  log(colors.gray("Waiting for conversations..."));
62
62
  ws.send(JSON.stringify({ type: "get_online_users" }));
@@ -64,7 +64,7 @@ export function startAgent(limits = DEFAULT_LIMITS, agentId, agentName, log = co
64
64
  case "online_users": {
65
65
  const users = msg.users;
66
66
  if (users.length > 0) {
67
- log(colors.cyan(`📡 Online: ${users.map((u) => `${u.displayName} (@${u.githubUsername})`).join(", ")}`));
67
+ log(colors.lime(`📡 Online: ${users.map((u) => `${u.displayName} (@${u.githubUsername})`).join(", ")}`));
68
68
  }
69
69
  else {
70
70
  log(colors.gray("No other agents online right now."));
@@ -78,7 +78,7 @@ export function startAgent(limits = DEFAULT_LIMITS, agentId, agentName, log = co
78
78
  // Check concurrent conversation limit
79
79
  if (!activeConversations.has(conversationId) &&
80
80
  activeConversations.size >= limits.maxConcurrentConversations) {
81
- log(colors.yellow(`⚠ Skipping: ${limits.maxConcurrentConversations} concurrent conversations active`));
81
+ log(colors.lime(`⚠ Skipping: ${limits.maxConcurrentConversations} concurrent conversations active`));
82
82
  ws.send(JSON.stringify({
83
83
  type: "inference_error",
84
84
  requestId,
@@ -89,7 +89,7 @@ export function startAgent(limits = DEFAULT_LIMITS, agentId, agentName, log = co
89
89
  // Check session total limit
90
90
  if (!activeConversations.has(conversationId) &&
91
91
  totalConversations >= limits.maxConversationsPerSession) {
92
- log(colors.yellow(`⚠ Session limit reached (${limits.maxConversationsPerSession} conversations). Stopping.`));
92
+ log(colors.lime(`⚠ Session limit reached (${limits.maxConversationsPerSession} conversations). Stopping.`));
93
93
  stopAgent();
94
94
  break;
95
95
  }
@@ -99,7 +99,7 @@ export function startAgent(limits = DEFAULT_LIMITS, agentId, agentName, log = co
99
99
  const elapsed = (Date.now() - lastConversationTime) / 1000;
100
100
  if (lastConversationTime > 0 && elapsed < limits.cooldownSeconds) {
101
101
  const wait = Math.ceil(limits.cooldownSeconds - elapsed);
102
- log(colors.yellow(`⚠ Cooldown: ${wait}s remaining`));
102
+ log(colors.lime(`⚠ Cooldown: ${wait}s remaining`));
103
103
  ws.send(JSON.stringify({
104
104
  type: "inference_error",
105
105
  requestId,
@@ -119,7 +119,7 @@ export function startAgent(limits = DEFAULT_LIMITS, agentId, agentName, log = co
119
119
  const msgCount = (conversationMessageCounts.get(conversationId) ?? 0) + 1;
120
120
  conversationMessageCounts.set(conversationId, msgCount);
121
121
  if (msgCount > limits.maxMessagesPerConversation) {
122
- log(colors.yellow(`⚠ Conversation ${conversationId.slice(0, 8)} hit ${limits.maxMessagesPerConversation} message limit`));
122
+ log(colors.lime(`⚠ Conversation ${conversationId.slice(0, 8)} hit ${limits.maxMessagesPerConversation} message limit`));
123
123
  activeConversations.delete(conversationId);
124
124
  ws.send(JSON.stringify({
125
125
  type: "inference_response",
@@ -128,7 +128,7 @@ export function startAgent(limits = DEFAULT_LIMITS, agentId, agentName, log = co
128
128
  }));
129
129
  break;
130
130
  }
131
- log(colors.yellow(`💬 [${conversationId.slice(0, 8)}] msg ${msgCount}/${limits.maxMessagesPerConversation} (${activeConversations.size}/${limits.maxConcurrentConversations} active, ${totalConversations}/${limits.maxConversationsPerSession} total)`));
131
+ log(colors.lime(`💬 [${conversationId.slice(0, 8)}] msg ${msgCount}/${limits.maxMessagesPerConversation} (${activeConversations.size}/${limits.maxConcurrentConversations} active, ${totalConversations}/${limits.maxConversationsPerSession} total)`));
132
132
  try {
133
133
  let response = await runInference(systemPrompt, messages);
134
134
  // Enforce response length limit
@@ -137,7 +137,7 @@ export function startAgent(limits = DEFAULT_LIMITS, agentId, agentName, log = co
137
137
  log(colors.gray(` (truncated to ${limits.maxResponseLength} chars)`));
138
138
  }
139
139
  const preview = response.length > 80 ? response.slice(0, 80) + "..." : response;
140
- log(colors.green(`✓ Response: ${preview}`));
140
+ log(colors.lime(`✓ Response: ${preview}`));
141
141
  ws.send(JSON.stringify({
142
142
  type: "inference_response",
143
143
  requestId,
@@ -146,7 +146,7 @@ export function startAgent(limits = DEFAULT_LIMITS, agentId, agentName, log = co
146
146
  }
147
147
  catch (err) {
148
148
  const errorMsg = err instanceof Error ? err.message : "Unknown error";
149
- log(colors.red(`✗ Inference failed: ${errorMsg}`));
149
+ log(colors.lime(`✗ Inference failed: ${errorMsg}`));
150
150
  ws.send(JSON.stringify({
151
151
  type: "inference_error",
152
152
  requestId,
@@ -157,7 +157,7 @@ export function startAgent(limits = DEFAULT_LIMITS, agentId, agentName, log = co
157
157
  }
158
158
  case "conversation_started": {
159
159
  const { conversationId, withUser } = msg;
160
- log(colors.brightGreen(`🤝 Conversation started with ${withUser.displayName} (@${withUser.githubUsername})`));
160
+ log(colors.lime(`🤝 Conversation started with ${withUser.displayName} (@${withUser.githubUsername})`));
161
161
  resetIdleTimer(limits, log);
162
162
  break;
163
163
  }
@@ -169,18 +169,18 @@ export function startAgent(limits = DEFAULT_LIMITS, agentId, agentName, log = co
169
169
  break;
170
170
  }
171
171
  case "error":
172
- log(colors.red(`Server error: ${msg.message}`));
172
+ log(colors.lime(`Server error: ${msg.message}`));
173
173
  break;
174
174
  }
175
175
  });
176
176
  ws.on("close", () => {
177
177
  if (alive) {
178
- log(colors.yellow("Disconnected. Reconnecting in 5s..."));
178
+ log(colors.lime("Disconnected. Reconnecting in 5s..."));
179
179
  reconnectTimer = setTimeout(connect, 5000);
180
180
  }
181
181
  });
182
182
  ws.on("error", (err) => {
183
- log(colors.red(`WebSocket error: ${err.message}`));
183
+ log(colors.lime(`WebSocket error: ${err.message}`));
184
184
  });
185
185
  }
186
186
  connect();
package/dist/app.js CHANGED
@@ -388,15 +388,15 @@ async function runAgentSession() {
388
388
  screen.setStatus("waiting for conversations...");
389
389
  }
390
390
  else {
391
- log(colors.cyan(`📡 Found ${candidates.length} candidates, screening...`));
391
+ log(colors.lime(`📡 Found ${candidates.length} candidates, screening...`));
392
392
  screen.setStatus(`screening ${candidates.length} profiles...`);
393
393
  const results = await screenProfiles(candidates, agent.instructions, sessionGoal, discovery.matchThreshold, discovery.maxScreenPerSession, (screened, total, result) => {
394
394
  const icon = result.score >= discovery.matchThreshold
395
- ? colors.green("✓")
395
+ ? colors.lime("✓")
396
396
  : colors.gray("⊘");
397
397
  const name = `@${result.profile.githubUsername}`;
398
398
  const scoreStr = result.score >= discovery.matchThreshold
399
- ? colors.green(`${result.score}/10`)
399
+ ? colors.lime(`${result.score}/10`)
400
400
  : colors.gray(`${result.score}/10`);
401
401
  log(` ${icon} ${name} ${scoreStr} — ${colors.gray(result.reason)}`);
402
402
  screen.setStatus(`screening ${screened}/${total}...`);
@@ -404,10 +404,10 @@ async function runAgentSession() {
404
404
  const matches = results.filter((r) => r.score >= discovery.matchThreshold);
405
405
  log("");
406
406
  if (matches.length === 0) {
407
- log(colors.yellow("No strong matches found. Waiting for incoming conversations..."));
407
+ log(colors.lime("No strong matches found. Waiting for incoming conversations..."));
408
408
  }
409
409
  else {
410
- log(colors.green(`Found ${matches.length} match${matches.length === 1 ? "" : "es"}. Starting conversations...`));
410
+ log(colors.lime(`Found ${matches.length} match${matches.length === 1 ? "" : "es"}. Starting conversations...`));
411
411
  log("");
412
412
  // Initiate conversations with matches
413
413
  for (const match of matches) {
@@ -415,7 +415,7 @@ async function runAgentSession() {
415
415
  log(colors.gray(` ⊘ @${match.profile.githubUsername} is offline, skipping`));
416
416
  continue;
417
417
  }
418
- log(colors.cyan(` 🤝 Reaching out to @${match.profile.githubUsername} (${match.score}/10: ${match.reason})`));
418
+ log(colors.lime(` 🤝 Reaching out to @${match.profile.githubUsername} (${match.score}/10: ${match.reason})`));
419
419
  // Send start_conversation via WebSocket
420
420
  sendToServer({
421
421
  type: "start_conversation",
@@ -431,7 +431,7 @@ async function runAgentSession() {
431
431
  }
432
432
  }
433
433
  catch (err) {
434
- log(colors.red(`Discovery failed: ${err instanceof Error ? err.message : err}`));
434
+ log(colors.lime(`Discovery failed: ${err instanceof Error ? err.message : err}`));
435
435
  screen.setStatus("waiting for conversations...");
436
436
  }
437
437
  return done;
@@ -28,20 +28,19 @@ export class AgentConfigScreen {
28
28
  this.container.addChild(new Text(truncateToWidth(theme.border("─".repeat(60)), 60), 0, 0));
29
29
  this.container.addChild(new Spacer(1));
30
30
  const items = [
31
- { value: "edit-name", label: "Rename agent", description: `Currently: ${agent.name}` },
32
- { value: "edit-instructions", label: "Edit instructions", description: "How your agent behaves" },
33
- { value: "edit-discovery", label: "Discovery settings", description: "Keywords, match threshold, filters" },
34
- { value: "edit-limits", label: "Agent limits", description: "Max conversations, cooldown, auto-stop" },
35
- { value: "edit-model", label: "Change model", description: `Currently: ${modelStr}` },
36
- { value: "delete", label: "Delete agent", description: "Remove this agent permanently" },
37
- { value: "back", label: "← Back", description: "" },
31
+ { value: "edit-name", label: "Rename", description: agent.name },
32
+ { value: "edit-instructions", label: "Instructions", description: "How your agent behaves" },
33
+ { value: "edit-discovery", label: "Discovery", description: "Keywords, match threshold, filters" },
34
+ { value: "edit-limits", label: "Limits", description: "Max conversations, cooldown, auto-stop" },
35
+ { value: "edit-model", label: "Model", description: modelStr },
36
+ { value: "delete", label: "Delete", description: "" },
38
37
  ];
39
38
  this.selectList = new SelectList(items, items.length, {
40
39
  selectedPrefix: (t) => theme.accent(t),
41
40
  selectedText: (t) => theme.accent(t),
42
41
  description: (t) => colors.gray(t),
43
42
  scrollInfo: (t) => colors.gray(t),
44
- noMatch: (t) => colors.yellow(t),
43
+ noMatch: (t) => colors.gray(t),
45
44
  });
46
45
  this.selectList.onSelect = (item) => {
47
46
  this.onAction?.(item.value);
@@ -1,13 +1,13 @@
1
1
  import { Editor, matchesKey, Key, truncateToWidth, } from "@mariozechner/pi-tui";
2
2
  import { colors, theme } from "../theme.js";
3
3
  const EDITOR_THEME = {
4
- borderColor: (s) => colors.cyan(s),
4
+ borderColor: (s) => colors.lime(s),
5
5
  selectList: {
6
- selectedPrefix: (t) => colors.cyan(t),
7
- selectedText: (t) => colors.cyan(t),
6
+ selectedPrefix: (t) => colors.lime(t),
7
+ selectedText: (t) => colors.lime(t),
8
8
  description: (t) => colors.gray(t),
9
9
  scrollInfo: (t) => colors.gray(t),
10
- noMatch: (t) => colors.yellow(t),
10
+ noMatch: (t) => colors.gray(t),
11
11
  },
12
12
  };
13
13
  export class AgentEditorScreen {
@@ -43,17 +43,22 @@ export class AgentEditorScreen {
43
43
  return this.cachedLines;
44
44
  const lines = [];
45
45
  lines.push(truncateToWidth(theme.border("─".repeat(width)), width));
46
- lines.push(truncateToWidth(` ${theme.title("Edit Agent Instructions")} ${colors.gray("~/.swarmlancer/agent.md")}`, width));
47
- lines.push(truncateToWidth(colors.gray(" This controls how your agent behaves in conversations."), width));
46
+ lines.push(truncateToWidth(` ${theme.title("Instructions")}`, width));
48
47
  lines.push(truncateToWidth(theme.border("─".repeat(width)), width));
49
- lines.push("");
50
- // Editor takes most of the space
51
- for (const line of this.editor.render(width)) {
48
+ // Editor takes most of the space — pad with empty lines to double the height
49
+ const editorLines = this.editor.render(width);
50
+ for (const line of editorLines) {
52
51
  lines.push(line);
53
52
  }
54
- lines.push("");
53
+ // Add padding lines to give the editor more vertical space
54
+ const termHeight = this.tui.terminal?.rows ?? 40;
55
+ const usedLines = lines.length + 3; // +3 for footer
56
+ const remaining = Math.max(0, termHeight - usedLines);
57
+ for (let i = 0; i < remaining; i++) {
58
+ lines.push("");
59
+ }
55
60
  lines.push(truncateToWidth(theme.border("─".repeat(width)), width));
56
- lines.push(truncateToWidth(colors.gray(" shift+enter new line • ctrl+s save • esc cancel"), width));
61
+ lines.push(truncateToWidth(colors.gray(" ctrl+s save • esc cancel"), width));
57
62
  this.cachedLines = lines;
58
63
  return lines;
59
64
  }
@@ -12,7 +12,7 @@ export class AgentListScreen {
12
12
  this.container = new Container();
13
13
  this.container.addChild(new Spacer(1));
14
14
  this.container.addChild(new Text(truncateToWidth(theme.border("─".repeat(60)), 60), 0, 0));
15
- this.container.addChild(new Text(theme.title(" Manage Agents"), 1, 0));
15
+ this.container.addChild(new Text(theme.title(" Agents"), 1, 0));
16
16
  this.container.addChild(new Text(colors.gray(" Each agent has its own instructions, model, discovery & limits."), 1, 0));
17
17
  this.container.addChild(new Text(truncateToWidth(theme.border("─".repeat(60)), 60), 0, 0));
18
18
  this.container.addChild(new Spacer(1));
@@ -20,14 +20,11 @@ export class AgentListScreen {
20
20
  // Create new agent always at top
21
21
  items.push({
22
22
  value: "__create__",
23
- label: "+ Create new agent",
23
+ label: "+ Create new",
24
24
  description: "",
25
25
  });
26
26
  // Existing agents
27
27
  for (const agent of agents) {
28
- const modelStr = agent.modelPattern
29
- ? colors.gray(` (${agent.modelPattern})`)
30
- : "";
31
28
  const instrPreview = agent.instructions.length > 0
32
29
  ? `${agent.instructions.slice(0, 50).replace(/\n/g, " ").trim()}…`
33
30
  : "(no instructions)";
@@ -43,7 +40,7 @@ export class AgentListScreen {
43
40
  selectedText: (t) => theme.accent(t),
44
41
  description: (t) => colors.gray(t),
45
42
  scrollInfo: (t) => colors.gray(t),
46
- noMatch: (t) => colors.yellow(t),
43
+ noMatch: (t) => colors.gray(t),
47
44
  });
48
45
  this.selectList.onSelect = (item) => {
49
46
  if (item.value === "__create__") {
@@ -25,7 +25,7 @@ export class AgentPickerScreen {
25
25
  selectedText: (t) => theme.accent(t),
26
26
  description: (t) => colors.gray(t),
27
27
  scrollInfo: (t) => colors.gray(t),
28
- noMatch: (t) => colors.yellow(t),
28
+ noMatch: (t) => colors.gray(t),
29
29
  });
30
30
  this.selectList.onSelect = (item) => {
31
31
  const agent = agents.find((a) => a.id === item.value);
@@ -45,9 +45,9 @@ export class AgentRunningScreen {
45
45
  // Header
46
46
  lines.push(theme.border("─".repeat(width)));
47
47
  const modelInfo = `${this.model.provider}/${this.model.id}`;
48
- lines.push(truncateToWidth(` ${theme.title("⚡ AGENT ONLINE")} ${colors.cyan(this.agentName)} ${colors.gray("model:")} ${colors.green(modelInfo)}`, width));
48
+ lines.push(truncateToWidth(` ${theme.title("⚡ AGENT ONLINE")} ${colors.lime(this.agentName)} ${colors.gray("model:")} ${colors.lime(modelInfo)}`, width));
49
49
  if (this.sessionGoal) {
50
- lines.push(truncateToWidth(` ${colors.gray("goal:")} ${colors.cyan(this.sessionGoal)}`, width));
50
+ lines.push(truncateToWidth(` ${colors.gray("goal:")} ${colors.lime(this.sessionGoal)}`, width));
51
51
  }
52
52
  lines.push(theme.border("─".repeat(width)));
53
53
  lines.push("");
@@ -1,10 +1,10 @@
1
1
  import { Container, Text, Spacer } from "@mariozechner/pi-tui";
2
2
  import { colors } from "../theme.js";
3
- // "LET THE SWARM BEGIN" — figlet Mini font, 70 chars wide, single horizontal block
4
3
  const BANNER_ART = [
5
- ` _ ___ ___ _ __ _ _ _ __ ___`,
6
- ` | |_ | | |_| |_ (_ \\ / /\\ |_) |\\/| |_) |_ /__ | |\\ |`,
7
- ` |_ |_ | | | | |_ __) \\/\\/ /--\\ | \\ | | |_) |_ \\_| _|_ | \\|`,
4
+ ` _______ ________ _______ ______ _______ _____ _______ _______ ______ _______ ______`,
5
+ ` | __| | | | _ | __ \\ | | |_| _ | | | | ___| __ \\`,
6
+ ` |__ | | | | | < | | | | ---| ___| <`,
7
+ ` |_______|________|___|___|___|__|__|_|__|_______|___|___|__|____|______|_______|___|__|`,
8
8
  ];
9
9
  export class BannerComponent extends Container {
10
10
  constructor() {
@@ -15,9 +15,10 @@ export class BannerComponent extends Container {
15
15
  this.clear();
16
16
  this.addChild(new Spacer(1));
17
17
  for (const line of BANNER_ART) {
18
- this.addChild(new Text(colors.bold(colors.lime(line)), 1, 0));
18
+ this.addChild(new Text(colors.limeBold(line), 1, 0));
19
19
  }
20
- this.addChild(new Text(colors.gray(" swarmlancer.com — let the swarm begin"), 1, 0));
20
+ this.addChild(new Spacer(0));
21
+ this.addChild(new Text(colors.gray(" Let the Swarm Begin"), 1, 0));
21
22
  this.addChild(new Spacer(1));
22
23
  }
23
24
  invalidate() {
@@ -3,9 +3,9 @@ import { colors, theme } from "../theme.js";
3
3
  import { StatusPanel } from "./status-panel.js";
4
4
  import { BannerComponent } from "./banner.js";
5
5
  const MENU_ITEMS = [
6
- { value: "start", label: "Start agent", description: "Pick an agent → set goal → discover → connect" },
7
- { value: "agents", label: "Manage agents", description: "Create, edit, or delete agents" },
8
- { value: "quit", label: "Quit", description: "Exit swarmlancer" },
6
+ { value: "start", label: "Start", description: "Pick an agent → set goal → discover → connect" },
7
+ { value: "agents", label: "Agents", description: "Create, edit, or delete agents" },
8
+ { value: "quit", label: "Exit", description: "" },
9
9
  ];
10
10
  export class DashboardScreen {
11
11
  container;
@@ -22,15 +22,12 @@ export class DashboardScreen {
22
22
  this.statusPanel = new StatusPanel(status);
23
23
  this.container.addChild(this.statusPanel);
24
24
  this.container.addChild(new Spacer(1));
25
- // Menu
26
- this.container.addChild(new Text(colors.bold(" What do you want to do?"), 1, 0));
27
- this.container.addChild(new Spacer(1));
28
25
  this.selectList = new SelectList(MENU_ITEMS, MENU_ITEMS.length, {
29
26
  selectedPrefix: (t) => theme.accent(t),
30
27
  selectedText: (t) => theme.accent(t),
31
28
  description: (t) => colors.gray(t),
32
29
  scrollInfo: (t) => colors.gray(t),
33
- noMatch: (t) => colors.yellow(t),
30
+ noMatch: (t) => colors.gray(t),
34
31
  });
35
32
  this.selectList.onSelect = (item) => {
36
33
  this.onAction?.(item.value);
@@ -146,14 +146,14 @@ export class DiscoverySettingsScreen {
146
146
  const pct = ((value - (f.min ?? 0)) / ((f.max ?? 100) - (f.min ?? 0)));
147
147
  const barW = 16;
148
148
  const filled = Math.round(pct * barW);
149
- const bar = colors.cyan("█".repeat(filled)) + colors.gray("░".repeat(barW - filled));
149
+ const bar = colors.lime("█".repeat(filled)) + colors.gray("░".repeat(barW - filled));
150
150
  const valStr = `${value}${f.suffix ?? ""}`;
151
151
  lines.push(truncateToWidth(`${prefix}${label}`, width));
152
- lines.push(truncateToWidth(` ${colors.gray("◀")} ${bar} ${colors.gray("▶")} ${isActive ? colors.brightCyan(valStr) : colors.gray(valStr)}`, width));
152
+ lines.push(truncateToWidth(` ${colors.gray("◀")} ${bar} ${colors.gray("▶")} ${isActive ? colors.lime(valStr) : colors.gray(valStr)}`, width));
153
153
  }
154
154
  else if (f.type === "boolean") {
155
155
  const value = this.settings[f.key];
156
- const valStr = value ? colors.green("ON") : colors.red("OFF");
156
+ const valStr = value ? colors.lime("ON") : colors.gray("OFF");
157
157
  lines.push(truncateToWidth(`${prefix}${label} ${colors.gray("◀")} ${valStr} ${colors.gray("▶")}`, width));
158
158
  }
159
159
  else if (f.type === "keywords") {
@@ -8,7 +8,7 @@ export declare class MessageScreen implements Component {
8
8
  private container;
9
9
  private tui;
10
10
  onClose?: () => void;
11
- constructor(tui: TUI, title: string, lines: string[], style?: "info" | "error" | "success");
11
+ constructor(tui: TUI, title: string, lines: string[], _style?: "info" | "error" | "success");
12
12
  handleInput(_data: string): void;
13
13
  render(width: number): string[];
14
14
  invalidate(): void;
@@ -8,17 +8,12 @@ export class MessageScreen {
8
8
  container;
9
9
  tui;
10
10
  onClose;
11
- constructor(tui, title, lines, style = "info") {
11
+ constructor(tui, title, lines, _style = "info") {
12
12
  this.tui = tui;
13
13
  this.container = new Container();
14
- const colorFn = style === "error"
15
- ? colors.red
16
- : style === "success"
17
- ? colors.green
18
- : colors.cyan;
19
14
  this.container.addChild(new Spacer(1));
20
15
  this.container.addChild(new Text(theme.border("─".repeat(50)), 0, 0));
21
- this.container.addChild(new Text(colorFn(colors.bold(` ${title}`)), 1, 0));
16
+ this.container.addChild(new Text(colors.bold(colors.lime(` ${title}`)), 1, 0));
22
17
  this.container.addChild(new Spacer(1));
23
18
  for (const line of lines) {
24
19
  this.container.addChild(new Text(` ${line}`, 0, 0));
@@ -23,7 +23,7 @@ export class ModelPickerScreen {
23
23
  selectedText: (t) => theme.accent(t),
24
24
  description: (t) => colors.gray(t),
25
25
  scrollInfo: (t) => colors.gray(t),
26
- noMatch: (t) => colors.yellow(t),
26
+ noMatch: (t) => colors.gray(t),
27
27
  });
28
28
  this.selectList.onSelect = (item) => {
29
29
  const model = models.find((m) => m.id === item.value);
@@ -1,13 +1,13 @@
1
1
  import { Editor, matchesKey, Key, truncateToWidth, } from "@mariozechner/pi-tui";
2
2
  import { colors, theme } from "../theme.js";
3
3
  const EDITOR_THEME = {
4
- borderColor: (s) => colors.cyan(s),
4
+ borderColor: (s) => colors.lime(s),
5
5
  selectList: {
6
- selectedPrefix: (t) => colors.cyan(t),
7
- selectedText: (t) => colors.cyan(t),
6
+ selectedPrefix: (t) => colors.lime(t),
7
+ selectedText: (t) => colors.lime(t),
8
8
  description: (t) => colors.gray(t),
9
9
  scrollInfo: (t) => colors.gray(t),
10
- noMatch: (t) => colors.yellow(t),
10
+ noMatch: (t) => colors.gray(t),
11
11
  },
12
12
  };
13
13
  export class NameEditorScreen {
@@ -1,13 +1,13 @@
1
1
  import { Editor, matchesKey, Key, truncateToWidth, } from "@mariozechner/pi-tui";
2
2
  import { colors, theme } from "../theme.js";
3
3
  const EDITOR_THEME = {
4
- borderColor: (s) => colors.cyan(s),
4
+ borderColor: (s) => colors.lime(s),
5
5
  selectList: {
6
- selectedPrefix: (t) => colors.cyan(t),
7
- selectedText: (t) => colors.cyan(t),
6
+ selectedPrefix: (t) => colors.lime(t),
7
+ selectedText: (t) => colors.lime(t),
8
8
  description: (t) => colors.gray(t),
9
9
  scrollInfo: (t) => colors.gray(t),
10
- noMatch: (t) => colors.yellow(t),
10
+ noMatch: (t) => colors.gray(t),
11
11
  },
12
12
  };
13
13
  export class SessionGoalScreen {
@@ -107,9 +107,9 @@ export class SettingsScreen {
107
107
  const pct = (value - s.min) / (s.max - s.min);
108
108
  const barWidth = 20;
109
109
  const filled = Math.round(pct * barWidth);
110
- const bar = colors.cyan("█".repeat(filled)) + colors.gray("░".repeat(barWidth - filled));
110
+ const bar = colors.lime("█".repeat(filled)) + colors.gray("░".repeat(barWidth - filled));
111
111
  lines.push(truncateToWidth(`${prefix}${label}`, width));
112
- lines.push(truncateToWidth(` ${colors.gray("◀")} ${bar} ${colors.gray("▶")} ${isActive ? colors.brightCyan(valueStr) : colors.gray(valueStr)}`, width));
112
+ lines.push(truncateToWidth(` ${colors.gray("◀")} ${bar} ${colors.gray("▶")} ${isActive ? colors.lime(valueStr) : colors.gray(valueStr)}`, width));
113
113
  if (isActive) {
114
114
  lines.push(truncateToWidth(` ${colors.gray(s.description)}`, width));
115
115
  }
@@ -39,7 +39,7 @@ export class SetupWizardScreen {
39
39
  selectedText: (t) => theme.accent(t),
40
40
  description: (t) => colors.gray(t),
41
41
  scrollInfo: (t) => colors.gray(t),
42
- noMatch: (t) => colors.yellow(t),
42
+ noMatch: (t) => colors.gray(t),
43
43
  });
44
44
  this.promptList.onSelect = (item) => {
45
45
  this.promptActive = false;
@@ -81,20 +81,20 @@ export class SetupWizardScreen {
81
81
  line = colors.gray(step.label);
82
82
  break;
83
83
  case "running":
84
- icon = colors.cyan("◉");
85
- line = colors.cyan(step.label + "...");
84
+ icon = colors.lime("◉");
85
+ line = colors.lime(step.label + "...");
86
86
  break;
87
87
  case "done":
88
- icon = colors.green("✓");
89
- line = colors.green(step.label);
88
+ icon = colors.lime("✓");
89
+ line = colors.lime(step.label);
90
90
  break;
91
91
  case "failed":
92
- icon = colors.red("✗");
93
- line = colors.red(step.label);
92
+ icon = colors.lime("✗");
93
+ line = colors.lime(step.label);
94
94
  break;
95
95
  case "skipped":
96
- icon = colors.yellow("⊘");
97
- line = colors.yellow(step.label);
96
+ icon = colors.gray("⊘");
97
+ line = colors.gray(step.label);
98
98
  break;
99
99
  }
100
100
  lines.push(truncateToWidth(` ${icon} ${line}`, width));
@@ -14,7 +14,7 @@ export class StatusPanel extends Container {
14
14
  rebuild() {
15
15
  this.clear();
16
16
  const line = (label, value, ok) => {
17
- const icon = ok ? colors.green("✓") : colors.red("✗");
17
+ const icon = ok ? colors.lime("✓") : colors.gray("✗");
18
18
  const labelStr = colors.gray(label.padEnd(10));
19
19
  return ` ${icon} ${labelStr} ${value}`;
20
20
  };
@@ -24,7 +24,7 @@ export class StatusPanel extends Container {
24
24
  ? `${this.info.model.provider}/${this.info.model.id}`
25
25
  : "(not detected)", !!this.info.model), 0, 0));
26
26
  const agentStr = this.info.agentCount === 0
27
- ? "none — create one in Manage agents"
27
+ ? "none — create one in Agents"
28
28
  : `${this.info.agentCount} agent${this.info.agentCount === 1 ? "" : "s"}`;
29
29
  this.addChild(new Text(line("Agents", agentStr, this.info.agentCount > 0), 0, 0));
30
30
  this.addChild(new Text(line("Server", this.info.serverUrl, true), 0, 0));
package/dist/theme.d.ts CHANGED
@@ -3,24 +3,13 @@ export declare const colors: {
3
3
  bold: (s: string) => string;
4
4
  dim: (s: string) => string;
5
5
  italic: (s: string) => string;
6
- cyan: (s: string) => string;
7
- green: (s: string) => string;
8
- red: (s: string) => string;
9
- yellow: (s: string) => string;
10
- magenta: (s: string) => string;
11
- blue: (s: string) => string;
12
6
  white: (s: string) => string;
13
7
  gray: (s: string) => string;
14
- brightCyan: (s: string) => string;
15
- brightGreen: (s: string) => string;
16
- brightYellow: (s: string) => string;
17
8
  brightWhite: (s: string) => string;
18
9
  lime: (s: string) => string;
19
10
  limeBold: (s: string) => string;
20
11
  bgLime: (s: string) => string;
21
12
  bgGray: (s: string) => string;
22
- bgCyan: (s: string) => string;
23
- bgBlue: (s: string) => string;
24
13
  inverse: (s: string) => string;
25
14
  };
26
15
  export declare const theme: {
package/dist/theme.js CHANGED
@@ -11,46 +11,34 @@ export const colors = {
11
11
  bold: (s) => `${ESC}1m${s}${ESC}22m`,
12
12
  dim: (s) => `${ESC}2m${s}${ESC}22m`,
13
13
  italic: (s) => `${ESC}3m${s}${ESC}23m`,
14
- // Named colors
15
- cyan: (s) => `${ESC}36m${s}${ESC}39m`,
16
- green: (s) => `${ESC}32m${s}${ESC}39m`,
17
- red: (s) => `${ESC}31m${s}${ESC}39m`,
18
- yellow: (s) => `${ESC}33m${s}${ESC}39m`,
19
- magenta: (s) => `${ESC}35m${s}${ESC}39m`,
20
- blue: (s) => `${ESC}34m${s}${ESC}39m`,
14
+ // Named colors — kept for internal use but UI uses only lime
21
15
  white: (s) => `${ESC}37m${s}${ESC}39m`,
22
16
  gray: (s) => `${ESC}90m${s}${ESC}39m`,
23
- // Bright
24
- brightCyan: (s) => `${ESC}96m${s}${ESC}39m`,
25
- brightGreen: (s) => `${ESC}92m${s}${ESC}39m`,
26
- brightYellow: (s) => `${ESC}93m${s}${ESC}39m`,
27
17
  brightWhite: (s) => `${ESC}97m${s}${ESC}39m`,
28
- // Logo lime green — #C8F135
18
+ // Logo lime green — #C8F135 — THE accent color
29
19
  lime: (s) => `${LIME_FG}${s}${ESC}39m`,
30
20
  limeBold: (s) => `${LIME_FG}${ESC}1m${s}${ESC}22m${ESC}39m`,
31
21
  bgLime: (s) => `${LIME_BG}${DARK_FG}${s}${RESET}`,
32
22
  // Background
33
23
  bgGray: (s) => `${ESC}48;5;236m${s}${ESC}49m`,
34
- bgCyan: (s) => `${ESC}46m${s}${ESC}49m`,
35
- bgBlue: (s) => `${ESC}44m${s}${ESC}49m`,
36
24
  // Inverse
37
25
  inverse: (s) => `${ESC}7m${s}${ESC}27m`,
38
26
  };
39
- // Semantic aliases — accent is now the logo lime green
27
+ // Semantic aliases — everything colorful is lime
40
28
  export const theme = {
41
29
  accent: colors.lime,
42
- success: colors.green,
43
- error: colors.red,
44
- warning: colors.yellow,
30
+ success: colors.lime,
31
+ error: colors.lime,
32
+ warning: colors.lime,
45
33
  muted: colors.gray,
46
34
  highlight: colors.limeBold,
47
35
  border: colors.lime,
48
36
  title: (s) => colors.bold(colors.lime(s)),
49
37
  subtitle: (s) => colors.bold(colors.white(s)),
50
38
  status: {
51
- ok: (s) => colors.green(`✓ ${s}`),
52
- fail: (s) => colors.red(`✗ ${s}`),
53
- warn: (s) => colors.yellow(`⚠ ${s}`),
39
+ ok: (s) => colors.lime(`✓ ${s}`),
40
+ fail: (s) => colors.lime(`✗ ${s}`),
41
+ warn: (s) => colors.lime(`⚠ ${s}`),
54
42
  info: (s) => colors.lime(`▸ ${s}`),
55
43
  },
56
44
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "swarmlancer-cli",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "Swarmlancer CLI — let the swarm begin. Connect your AI agent to a network of other agents.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",