@lgcyaxi/oh-my-claude 1.0.1 → 1.1.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/index.js CHANGED
@@ -39,6 +39,10 @@ import {
39
39
  getMcpServerPath,
40
40
  getProviderDetails,
41
41
  getProvidersStatus,
42
+ getStatusLineScriptPath,
43
+ init_agent_generator,
44
+ init_agents,
45
+ init_installer,
42
46
  install,
43
47
  isMcpAgent,
44
48
  isProviderConfigured,
@@ -58,7 +62,10 @@ import {
58
62
  sisyphusAgent,
59
63
  taskAgents,
60
64
  uninstall
61
- } from "./index-5ars1tn4.js";
65
+ } from "./index-qrbfj4cd.js";
66
+
67
+ // src/index.ts
68
+ init_agents();
62
69
  // src/providers/deepseek.ts
63
70
  var DEEPSEEK_BASE_URL = "https://api.deepseek.com/anthropic";
64
71
  var DEEPSEEK_API_KEY_ENV = "DEEPSEEK_API_KEY";
@@ -80,6 +87,11 @@ function createMiniMaxClient() {
80
87
  return createAnthropicClientFromEnv("MiniMax", MINIMAX_BASE_URL, MINIMAX_API_KEY_ENV, "MiniMax-M2.1");
81
88
  }
82
89
  var minimaxClient = createMiniMaxClient();
90
+ // src/generators/index.ts
91
+ init_agent_generator();
92
+
93
+ // src/index.ts
94
+ init_installer();
83
95
  export {
84
96
  zhipuClient,
85
97
  uninstall,
@@ -103,6 +115,7 @@ export {
103
115
  isProviderConfigured,
104
116
  isMcpAgent,
105
117
  install,
118
+ getStatusLineScriptPath,
106
119
  getProvidersStatus,
107
120
  getProviderDetails,
108
121
  getMcpServerPath,
@@ -18573,10 +18573,65 @@ function getAgent(name) {
18573
18573
  }
18574
18574
 
18575
18575
  // src/mcp/background-agent-server/task-manager.ts
18576
+ import { writeFileSync, mkdirSync, existsSync as existsSync2 } from "node:fs";
18577
+ import { join as join2, dirname } from "node:path";
18578
+ import { homedir as homedir2 } from "node:os";
18579
+
18580
+ // src/mcp/background-agent-server/concurrency.ts
18581
+ var activeCounts = new Map;
18582
+ var queues = new Map;
18583
+ function getConcurrencyLimit(provider) {
18584
+ const config2 = loadConfig();
18585
+ const perProvider = config2.concurrency.per_provider?.[provider];
18586
+ if (perProvider !== undefined) {
18587
+ return perProvider;
18588
+ }
18589
+ return config2.concurrency.default;
18590
+ }
18591
+ function getActiveCount(provider) {
18592
+ return activeCounts.get(provider) ?? 0;
18593
+ }
18594
+ function getConcurrencyStatus() {
18595
+ const config2 = loadConfig();
18596
+ const status = {};
18597
+ const providers = Object.keys(config2.providers);
18598
+ for (const provider of providers) {
18599
+ status[provider] = {
18600
+ active: getActiveCount(provider),
18601
+ limit: getConcurrencyLimit(provider),
18602
+ queued: queues.get(provider)?.length ?? 0
18603
+ };
18604
+ }
18605
+ return status;
18606
+ }
18607
+
18608
+ // src/mcp/background-agent-server/task-manager.ts
18609
+ var STATUS_FILE_PATH = join2(homedir2(), ".claude", "oh-my-claude", "status.json");
18576
18610
  var tasks = new Map;
18577
18611
  function generateTaskId() {
18578
18612
  return `task_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
18579
18613
  }
18614
+ function updateStatusFile() {
18615
+ try {
18616
+ const dir = dirname(STATUS_FILE_PATH);
18617
+ if (!existsSync2(dir)) {
18618
+ mkdirSync(dir, { recursive: true });
18619
+ }
18620
+ const activeTasks = Array.from(tasks.values()).filter((t) => t.status === "running" || t.status === "pending").map((t) => ({
18621
+ agent: t.agentName || t.categoryName || "unknown",
18622
+ startedAt: t.startedAt || t.createdAt
18623
+ }));
18624
+ const providers = getConcurrencyStatus();
18625
+ const status = {
18626
+ activeTasks,
18627
+ providers,
18628
+ updatedAt: new Date().toISOString()
18629
+ };
18630
+ writeFileSync(STATUS_FILE_PATH, JSON.stringify(status, null, 2));
18631
+ } catch (error2) {
18632
+ console.error("Failed to update status file:", error2);
18633
+ }
18634
+ }
18580
18635
  async function launchTask(options) {
18581
18636
  const { agentName, categoryName, prompt, systemPrompt } = options;
18582
18637
  if (!agentName && !categoryName) {
@@ -18599,6 +18654,7 @@ async function launchTask(options) {
18599
18654
  createdAt: Date.now()
18600
18655
  };
18601
18656
  tasks.set(taskId, task);
18657
+ updateStatusFile();
18602
18658
  runTask(task, finalSystemPrompt).catch((error2) => {
18603
18659
  console.error(`Task ${taskId} failed:`, error2);
18604
18660
  });
@@ -18608,6 +18664,7 @@ async function runTask(task, systemPrompt) {
18608
18664
  task.status = "running";
18609
18665
  task.startedAt = Date.now();
18610
18666
  tasks.set(task.id, task);
18667
+ updateStatusFile();
18611
18668
  try {
18612
18669
  const messages = [];
18613
18670
  if (systemPrompt) {
@@ -18633,6 +18690,7 @@ async function runTask(task, systemPrompt) {
18633
18690
  task.result = result;
18634
18691
  task.completedAt = Date.now();
18635
18692
  tasks.set(task.id, task);
18693
+ updateStatusFile();
18636
18694
  } catch (error2) {
18637
18695
  if (error2 instanceof FallbackRequiredError) {
18638
18696
  task.status = "fallback_required";
@@ -18649,6 +18707,7 @@ async function runTask(task, systemPrompt) {
18649
18707
  }
18650
18708
  task.completedAt = Date.now();
18651
18709
  tasks.set(task.id, task);
18710
+ updateStatusFile();
18652
18711
  }
18653
18712
  }
18654
18713
  function pollTask(taskId) {
@@ -18672,6 +18731,7 @@ function cancelTask(taskId) {
18672
18731
  task.status = "cancelled";
18673
18732
  task.completedAt = Date.now();
18674
18733
  tasks.set(taskId, task);
18734
+ updateStatusFile();
18675
18735
  return true;
18676
18736
  }
18677
18737
  return false;
@@ -18686,6 +18746,9 @@ function cancelAllTasks() {
18686
18746
  cancelled++;
18687
18747
  }
18688
18748
  }
18749
+ if (cancelled > 0) {
18750
+ updateStatusFile();
18751
+ }
18689
18752
  return cancelled;
18690
18753
  }
18691
18754
  function listTasks(options) {
@@ -18711,34 +18774,6 @@ function cleanupTasks(maxAgeMs = 30 * 60 * 1000) {
18711
18774
  return cleaned;
18712
18775
  }
18713
18776
 
18714
- // src/mcp/background-agent-server/concurrency.ts
18715
- var activeCounts = new Map;
18716
- var queues = new Map;
18717
- function getConcurrencyLimit(provider) {
18718
- const config2 = loadConfig();
18719
- const perProvider = config2.concurrency.per_provider?.[provider];
18720
- if (perProvider !== undefined) {
18721
- return perProvider;
18722
- }
18723
- return config2.concurrency.default;
18724
- }
18725
- function getActiveCount(provider) {
18726
- return activeCounts.get(provider) ?? 0;
18727
- }
18728
- function getConcurrencyStatus() {
18729
- const config2 = loadConfig();
18730
- const status = {};
18731
- const providers = Object.keys(config2.providers);
18732
- for (const provider of providers) {
18733
- status[provider] = {
18734
- active: getActiveCount(provider),
18735
- limit: getConcurrencyLimit(provider),
18736
- queued: queues.get(provider)?.length ?? 0
18737
- };
18738
- }
18739
- return status;
18740
- }
18741
-
18742
18777
  // src/mcp/background-agent-server/server.ts
18743
18778
  var tools = [
18744
18779
  {
@@ -19032,6 +19067,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
19032
19067
  async function main() {
19033
19068
  const transport = new StdioServerTransport;
19034
19069
  await server.connect(transport);
19070
+ updateStatusFile();
19035
19071
  console.error("oh-my-claude Background Agent MCP Server running");
19036
19072
  }
19037
19073
  main().catch((error2) => {
@@ -0,0 +1,146 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/statusline/statusline.ts
4
+ import { readFileSync, existsSync } from "node:fs";
5
+ import { join } from "node:path";
6
+ import { homedir } from "node:os";
7
+
8
+ // src/statusline/formatter.ts
9
+ var AGENT_ABBREV = {
10
+ oracle: "Oracle",
11
+ librarian: "Lib",
12
+ explore: "Exp",
13
+ "frontend-ui-ux": "UI",
14
+ "document-writer": "Doc"
15
+ };
16
+ var TASK_AGENT_ABBREV = {
17
+ Scout: "Scout",
18
+ Planner: "Plan",
19
+ General: "Gen",
20
+ Guide: "Guide",
21
+ Bash: "Bash"
22
+ };
23
+ var PROVIDER_ABBREV = {
24
+ deepseek: "DS",
25
+ zhipu: "ZP",
26
+ minimax: "MM",
27
+ openrouter: "OR"
28
+ };
29
+ function formatDuration(seconds) {
30
+ if (seconds < 60) {
31
+ return `${Math.floor(seconds)}s`;
32
+ }
33
+ const minutes = Math.floor(seconds / 60);
34
+ return `${minutes}m`;
35
+ }
36
+ function getAgentAbbrev(agent) {
37
+ if (agent.startsWith("@")) {
38
+ const taskAgent = agent.slice(1);
39
+ return `@${TASK_AGENT_ABBREV[taskAgent] || taskAgent.slice(0, 4)}`;
40
+ }
41
+ return AGENT_ABBREV[agent.toLowerCase()] || agent.slice(0, 4);
42
+ }
43
+ function getProviderAbbrev(provider) {
44
+ return PROVIDER_ABBREV[provider.toLowerCase()] || provider.slice(0, 2).toUpperCase();
45
+ }
46
+ function formatStatusLine(data) {
47
+ const parts = ["omc"];
48
+ const now = Date.now();
49
+ if (data.activeTasks.length > 0) {
50
+ const tasksToShow = data.activeTasks.slice(0, 3);
51
+ for (const task of tasksToShow) {
52
+ const durationSec = Math.floor((now - task.startedAt) / 1000);
53
+ const agentName = getAgentAbbrev(task.agent);
54
+ const duration = formatDuration(durationSec);
55
+ parts.push(`[${agentName}: ${duration}]`);
56
+ }
57
+ if (data.activeTasks.length > 3) {
58
+ parts.push(`+${data.activeTasks.length - 3}`);
59
+ }
60
+ }
61
+ const providerParts = [];
62
+ const providersToShow = ["deepseek", "zhipu", "minimax"];
63
+ for (const provider of providersToShow) {
64
+ const status = data.providers[provider];
65
+ if (status && (status.active > 0 || data.activeTasks.length > 0)) {
66
+ const abbrev = getProviderAbbrev(provider);
67
+ providerParts.push(`${abbrev}: ${status.active}/${status.limit}`);
68
+ }
69
+ }
70
+ if (providerParts.length > 0) {
71
+ parts.push("|");
72
+ parts.push(...providerParts);
73
+ }
74
+ return parts.join(" ");
75
+ }
76
+ function formatEmptyStatusLine() {
77
+ return "omc ready";
78
+ }
79
+ function formatIdleStatusLine(providers) {
80
+ const parts = ["omc ready"];
81
+ const providerParts = [];
82
+ const providersToShow = ["deepseek", "zhipu", "minimax"];
83
+ for (const provider of providersToShow) {
84
+ const status = providers[provider];
85
+ if (status && status.limit > 0) {
86
+ const abbrev = getProviderAbbrev(provider);
87
+ providerParts.push(`${abbrev}: ${status.limit}`);
88
+ }
89
+ }
90
+ if (providerParts.length > 0) {
91
+ parts.push("|");
92
+ parts.push(...providerParts);
93
+ }
94
+ return parts.join(" ");
95
+ }
96
+
97
+ // src/statusline/statusline.ts
98
+ var STATUS_FILE_PATH = join(homedir(), ".claude", "oh-my-claude", "status.json");
99
+ var TIMEOUT_MS = 100;
100
+ function readStatusFile() {
101
+ try {
102
+ if (!existsSync(STATUS_FILE_PATH)) {
103
+ return null;
104
+ }
105
+ const content = readFileSync(STATUS_FILE_PATH, "utf-8");
106
+ const data = JSON.parse(content);
107
+ if (!data || typeof data !== "object") {
108
+ return null;
109
+ }
110
+ if (data.updatedAt) {
111
+ const updatedAt = new Date(data.updatedAt).getTime();
112
+ const age = Date.now() - updatedAt;
113
+ if (age > 5 * 60 * 1000) {
114
+ return null;
115
+ }
116
+ }
117
+ return data;
118
+ } catch {
119
+ return null;
120
+ }
121
+ }
122
+ async function main() {
123
+ const timeoutId = setTimeout(() => {
124
+ console.log(formatEmptyStatusLine());
125
+ process.exit(0);
126
+ }, TIMEOUT_MS);
127
+ try {
128
+ let _input = "";
129
+ try {
130
+ _input = readFileSync(0, "utf-8");
131
+ } catch {}
132
+ const statusData = readStatusFile();
133
+ if (!statusData) {
134
+ console.log(formatEmptyStatusLine());
135
+ } else if (statusData.activeTasks.length === 0) {
136
+ console.log(formatIdleStatusLine(statusData.providers));
137
+ } else {
138
+ console.log(formatStatusLine(statusData));
139
+ }
140
+ } catch {
141
+ console.log(formatEmptyStatusLine());
142
+ } finally {
143
+ clearTimeout(timeoutId);
144
+ }
145
+ }
146
+ main();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lgcyaxi/oh-my-claude",
3
- "version": "1.0.1",
3
+ "version": "1.1.1",
4
4
  "description": "Multi-agent orchestration plugin for Claude Code with multi-provider support",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -11,8 +11,9 @@
11
11
  "scripts": {
12
12
  "build": "bun build src/index.ts src/cli.ts --outdir dist --target node --splitting",
13
13
  "build:mcp": "bun build src/mcp/background-agent-server/server.ts --outdir dist/mcp --target node",
14
- "build:hooks": "bun build src/hooks/comment-checker.ts src/hooks/todo-continuation.ts --outdir dist/hooks --target node",
15
- "build:all": "bun run build && bun run build:mcp && bun run build:hooks",
14
+ "build:hooks": "bun build src/hooks/comment-checker.ts src/hooks/todo-continuation.ts src/hooks/task-notification.ts src/hooks/task-tracker.ts --outdir dist/hooks --target node",
15
+ "build:statusline": "bun build src/statusline/statusline.ts --outdir dist/statusline --target node",
16
+ "build:all": "bun run build && bun run build:mcp && bun run build:hooks && bun run build:statusline",
16
17
  "typecheck": "tsc --noEmit",
17
18
  "test": "bun test",
18
19
  "dev": "bun run --watch src/index.ts",
package/src/cli.ts CHANGED
@@ -19,7 +19,7 @@ import { loadConfig } from "./config";
19
19
  program
20
20
  .name("oh-my-claude")
21
21
  .description("Multi-agent orchestration plugin for Claude Code")
22
- .version("1.0.1");
22
+ .version("1.1.1");
23
23
 
24
24
  // Install command
25
25
  program
@@ -206,6 +206,7 @@ program
206
206
  console.log(` ${status.components.agents ? ok("Agent files generated") : fail("Agent files generated")}`);
207
207
  console.log(` ${status.components.hooks ? ok("Hooks configured") : fail("Hooks configured")}`);
208
208
  console.log(` ${status.components.mcp ? ok("MCP server configured") : fail("MCP server configured")}`);
209
+ console.log(` ${status.components.statusLine ? ok("StatusLine configured") : warn("StatusLine not configured")}`);
209
210
  console.log(` ${status.components.config ? ok("Configuration file exists") : fail("Configuration file exists")}`);
210
211
 
211
212
 
@@ -243,11 +244,13 @@ program
243
244
  "omc-explore",
244
245
  "omc-plan",
245
246
  "omc-start-work",
247
+ "omc-status",
246
248
  // Quick action commands
247
249
  "omcx-commit",
248
250
  "omcx-implement",
249
251
  "omcx-refactor",
250
252
  "omcx-docs",
253
+ "omcx-issue",
251
254
  ];
252
255
  console.log(` ${subheader("Agent commands (omc-):")}`);
253
256
  for (const cmd of expectedCommands.filter(c => c.startsWith("omc-"))) {
@@ -291,12 +294,43 @@ program
291
294
  // Hooks detail
292
295
  console.log(`\n${header("Hooks (detailed):")}`);
293
296
  const hooksDir = join(homedir(), ".claude", "oh-my-claude", "hooks");
294
- const expectedHooks = ["comment-checker.js", "todo-continuation.js"];
297
+ const expectedHooks = ["comment-checker.js", "todo-continuation.js", "task-notification.js"];
295
298
  for (const hook of expectedHooks) {
296
299
  const hookPath = join(hooksDir, hook);
297
300
  const exists = existsSync(hookPath);
298
301
  console.log(` ${exists ? ok(hook) : fail(hook)}`);
299
302
  }
303
+
304
+ // StatusLine detail
305
+ console.log(`\n${header("StatusLine (detailed):")}`);
306
+ const statusLineDir = join(homedir(), ".claude", "oh-my-claude", "dist", "statusline");
307
+ const statusLineScript = join(statusLineDir, "statusline.js");
308
+ const statusFileExists = existsSync(statusLineScript);
309
+ console.log(` ${statusFileExists ? ok("statusline.js installed") : fail("statusline.js not installed")}`);
310
+
311
+ try {
312
+ const settingsPath = join(homedir(), ".claude", "settings.json");
313
+ if (existsSync(settingsPath)) {
314
+ const settings = JSON.parse(require("node:fs").readFileSync(settingsPath, "utf-8"));
315
+ if (settings.statusLine) {
316
+ const cmd = settings.statusLine.command || "";
317
+ const isOurs = cmd.includes("oh-my-claude");
318
+ const isWrapper = cmd.includes("statusline-wrapper");
319
+ console.log(` ${ok("StatusLine configured in settings.json")}`);
320
+ if (isWrapper) {
321
+ console.log(` Mode: ${c.yellow}Merged (wrapper)${c.reset}`);
322
+ } else if (isOurs) {
323
+ console.log(` Mode: ${c.green}Direct${c.reset}`);
324
+ } else {
325
+ console.log(` Mode: ${c.cyan}External${c.reset}`);
326
+ }
327
+ } else {
328
+ console.log(` ${warn("StatusLine not configured in settings.json")}`);
329
+ }
330
+ }
331
+ } catch {
332
+ console.log(` ${fail("Failed to read settings.json")}`);
333
+ }
300
334
  }
301
335
 
302
336
  // Check providers
@@ -487,6 +521,106 @@ program
487
521
  }
488
522
  });
489
523
 
524
+ // StatusLine command
525
+ program
526
+ .command("statusline")
527
+ .description("Manage statusline integration")
528
+ .option("--enable", "Enable statusline")
529
+ .option("--disable", "Disable statusline")
530
+ .option("--status", "Show current statusline configuration")
531
+ .action((options) => {
532
+ const { readFileSync, existsSync } = require("node:fs");
533
+ const { join } = require("node:path");
534
+ const { homedir } = require("node:os");
535
+
536
+ // Color helpers
537
+ const useColor = process.stdout.isTTY;
538
+ const c = {
539
+ reset: useColor ? "\x1b[0m" : "",
540
+ bold: useColor ? "\x1b[1m" : "",
541
+ dim: useColor ? "\x1b[2m" : "",
542
+ green: useColor ? "\x1b[32m" : "",
543
+ red: useColor ? "\x1b[31m" : "",
544
+ yellow: useColor ? "\x1b[33m" : "",
545
+ cyan: useColor ? "\x1b[36m" : "",
546
+ };
547
+
548
+ const ok = (text: string) => `${c.green}+${c.reset} ${text}`;
549
+ const fail = (text: string) => `${c.red}x${c.reset} ${text}`;
550
+ const warn = (text: string) => `${c.yellow}!${c.reset} ${text}`;
551
+
552
+ const settingsPath = join(homedir(), ".claude", "settings.json");
553
+
554
+ if (options.status || (!options.enable && !options.disable)) {
555
+ // Show status
556
+ console.log(`${c.bold}StatusLine Status${c.reset}\n`);
557
+
558
+ if (!existsSync(settingsPath)) {
559
+ console.log(fail("settings.json not found"));
560
+ process.exit(1);
561
+ }
562
+
563
+ try {
564
+ const settings = JSON.parse(readFileSync(settingsPath, "utf-8"));
565
+
566
+ if (!settings.statusLine) {
567
+ console.log(fail("StatusLine not configured"));
568
+ console.log(`\nRun ${c.cyan}oh-my-claude statusline --enable${c.reset} to enable.`);
569
+ } else {
570
+ const cmd = settings.statusLine.command || "";
571
+ const isOurs = cmd.includes("oh-my-claude");
572
+ const isWrapper = cmd.includes("statusline-wrapper");
573
+
574
+ console.log(ok("StatusLine configured"));
575
+ console.log(` Command: ${c.dim}${cmd}${c.reset}`);
576
+
577
+ if (isWrapper) {
578
+ console.log(` Mode: ${c.yellow}Merged (wrapper)${c.reset}`);
579
+ } else if (isOurs) {
580
+ console.log(` Mode: ${c.green}Direct${c.reset}`);
581
+ } else {
582
+ console.log(` Mode: ${c.cyan}External${c.reset}`);
583
+ }
584
+ }
585
+ } catch (error) {
586
+ console.log(fail(`Failed to read settings: ${error}`));
587
+ process.exit(1);
588
+ }
589
+ } else if (options.enable) {
590
+ // Enable statusline
591
+ const { installStatusLine } = require("./installer/settings-merger");
592
+ const { getStatusLineScriptPath } = require("./installer");
593
+
594
+ try {
595
+ const result = installStatusLine(getStatusLineScriptPath());
596
+ if (result.installed) {
597
+ console.log(ok("StatusLine enabled"));
598
+ if (result.wrapperCreated) {
599
+ console.log(warn("Wrapper created to merge with existing statusLine"));
600
+ }
601
+ }
602
+ } catch (error) {
603
+ console.log(fail(`Failed to enable statusline: ${error}`));
604
+ process.exit(1);
605
+ }
606
+ } else if (options.disable) {
607
+ // Disable statusline
608
+ const { uninstallStatusLine } = require("./installer/settings-merger");
609
+
610
+ try {
611
+ const result = uninstallStatusLine();
612
+ if (result) {
613
+ console.log(ok("StatusLine disabled"));
614
+ } else {
615
+ console.log(warn("StatusLine was not configured"));
616
+ }
617
+ } catch (error) {
618
+ console.log(fail(`Failed to disable statusline: ${error}`));
619
+ process.exit(1);
620
+ }
621
+ }
622
+ });
623
+
490
624
  // Setup MCP command
491
625
  program
492
626
  .command("setup-mcp")
@@ -18,6 +18,7 @@ export const agentCommands = [
18
18
  "omc-explore",
19
19
  "omc-plan",
20
20
  "omc-start-work",
21
+ "omc-status",
21
22
  ] as const;
22
23
 
23
24
  // Quick action commands (omcx- prefix)
@@ -26,10 +27,16 @@ export const actionCommands = [
26
27
  "omcx-implement",
27
28
  "omcx-refactor",
28
29
  "omcx-docs",
30
+ "omcx-issue",
31
+ ] as const;
32
+
33
+ // Special mode commands
34
+ export const modeCommands = [
35
+ "ulw", // Ultrawork mode - work until done
29
36
  ] as const;
30
37
 
31
38
  // All commands
32
- export const commands = [...agentCommands, ...actionCommands] as const;
39
+ export const commands = [...agentCommands, ...actionCommands, ...modeCommands] as const;
33
40
 
34
41
  export type CommandName = typeof commands[number];
35
42
 
@@ -0,0 +1,71 @@
1
+ # /omc-status
2
+
3
+ Display status dashboard for oh-my-claude MCP background agents.
4
+
5
+ ## Instructions
6
+
7
+ The user wants to see the current status of MCP background agents. Display a formatted ASCII dashboard showing:
8
+
9
+ 1. **Active Tasks** - Currently running background tasks
10
+ 2. **Provider Concurrency** - Usage bars for each provider
11
+ 3. **Recent Tasks** - Last 5 completed/failed tasks
12
+
13
+ **Step 1: Get system status**
14
+
15
+ ```
16
+ Use mcp__oh-my-claude-background__get_status to get:
17
+ - Provider configuration (which have API keys)
18
+ - Concurrency limits per provider
19
+ - Current active task counts
20
+ ```
21
+
22
+ **Step 2: Get task list**
23
+
24
+ ```
25
+ Use mcp__oh-my-claude-background__list_tasks with:
26
+ - limit: 20
27
+ (Gets recent tasks including running, completed, failed, fallback_required)
28
+ ```
29
+
30
+ **Step 3: Display dashboard**
31
+
32
+ Format the output as an ASCII dashboard:
33
+
34
+ ```
35
+ oh-my-claude Status Dashboard
36
+ ==============================
37
+
38
+ ACTIVE TASKS (count)
39
+ [agent] task_id... Provider [progress] status duration
40
+
41
+ PROVIDER CONCURRENCY
42
+ Provider: [bar] active/limit active, queued queued
43
+
44
+ RECENT TASKS (last 5)
45
+ [status] task_id agent time_ago
46
+ ```
47
+
48
+ **ASCII Progress Bar Helper:**
49
+
50
+ For concurrency bars, use:
51
+ - Full blocks: active tasks
52
+ - Empty blocks: remaining capacity
53
+ - 10 character width total
54
+
55
+ ```
56
+ Example: 4/10 active -> "4/10 active"
57
+ ```
58
+
59
+ **Status indicators:**
60
+ - `running` - Task is executing
61
+ - `completed` - Task finished successfully
62
+ - `failed` - Task encountered an error
63
+ - `fallback_required` - Provider API key not configured
64
+
65
+ **If no tasks:**
66
+ Display a message that no background tasks have been run yet, and suggest using `/omc-oracle` or other agent commands.
67
+
68
+ **If MCP server not available:**
69
+ Display an error message suggesting to run `oh-my-claude doctor` to check configuration.
70
+
71
+ Now gather the status and display the dashboard.