myuru 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Wittlesus
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,105 @@
1
+ # MyUru
2
+
3
+ [![npm version](https://img.shields.io/npm/v/myuru.svg)](https://www.npmjs.com/package/myuru)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+
6
+ Multi-provider AI agent orchestrator. Coordinate Claude, GPT, and Gemini agents to build software in parallel.
7
+
8
+ ## Features
9
+
10
+ - **Multi-Provider**: Claude, OpenAI, Gemini
11
+ - **Council Mode**: Agents deliberate in a chatroom, then execute tasks together
12
+ - **Session Persistence**: Agents maintain context across invocations
13
+ - **Terminal Dashboard**: Real-time ANSI UI showing agent status
14
+ - **Tier System**: Free (2 sequential agents) / Pro (5 concurrent + config packs, $29 one-time)
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ npm install -g myuru
20
+ ```
21
+
22
+ ## Quick Start
23
+
24
+ Initialize a project:
25
+
26
+ ```bash
27
+ myuru init
28
+ ```
29
+
30
+ Run agents on a task:
31
+
32
+ ```bash
33
+ myuru run --task "Build a login page with JWT auth"
34
+ ```
35
+
36
+ Output:
37
+ ```
38
+ [Agent Architect] Designing authentication system...
39
+ [Agent Frontend] Building React login form...
40
+ [Agent Security] Implementing JWT validation...
41
+
42
+ Tasks completed: 3/3 | Status: SUCCESS
43
+ ```
44
+
45
+ Start a council discussion:
46
+
47
+ ```bash
48
+ myuru council \
49
+ --topic "Design auth system" \
50
+ --agents "Architect,Security,Frontend"
51
+ ```
52
+
53
+ Check task progress:
54
+
55
+ ```bash
56
+ myuru status
57
+ ```
58
+
59
+ ## Commands
60
+
61
+ | Command | Description |
62
+ |---------|-------------|
63
+ | `myuru init` | Initialize project with config |
64
+ | `myuru run --task "..."` | Run agents on a task |
65
+ | `myuru council --topic "..." --agents "..."` | Start council deliberation |
66
+ | `myuru status` | View task progress |
67
+
68
+ ## Configuration
69
+
70
+ Set environment variables:
71
+
72
+ ```bash
73
+ export OPENAI_API_KEY="sk-..."
74
+ export ANTHROPIC_API_KEY="sk-ant-..."
75
+ export GOOGLE_API_KEY="..."
76
+ ```
77
+
78
+ Create `.myuru.json`:
79
+
80
+ ```json
81
+ {
82
+ "tier": "free",
83
+ "providers": ["claude", "openai"],
84
+ "maxConcurrent": 2
85
+ }
86
+ ```
87
+
88
+ ## Pricing
89
+
90
+ **Free**: 2 sequential agents, basic reporting
91
+ **Pro**: 5 concurrent agents, config packs, priority support — $29 one-time
92
+
93
+ ## Requirements
94
+
95
+ - Node.js >= 18
96
+ - Claude CLI (for Claude provider)
97
+ - API keys for your chosen providers
98
+
99
+ ## License
100
+
101
+ MIT - See LICENSE file
102
+
103
+ ---
104
+
105
+ Built by Wittlesus | [GitHub](https://github.com/Wittlesus/myuru)
package/bin/myuru.js ADDED
@@ -0,0 +1,59 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { Command } = require('commander');
4
+ const path = require('path');
5
+ const pkg = require('../package.json');
6
+
7
+ const program = new Command();
8
+
9
+ program
10
+ .name('myuru')
11
+ .description('Multi-provider AI agent orchestrator')
12
+ .version(pkg.version);
13
+
14
+ program
15
+ .command('init')
16
+ .description('Initialize a MyUru project in the current directory')
17
+ .option('--template <name>', 'Config pack template to use', 'default')
18
+ .action(async (opts) => {
19
+ const { init } = require('../src/commands/init');
20
+ await init(opts);
21
+ });
22
+
23
+ program
24
+ .command('run')
25
+ .description('Run the orchestrator on the current project')
26
+ .option('-t, --task <description>', 'Single task to execute')
27
+ .option('-f, --file <path>', 'Task file (myuru.config.mjs or JSON)')
28
+ .option('--provider <name>', 'Single provider: claude, openai, gemini', 'claude')
29
+ .option('--model <name>', 'Model override')
30
+ .option('--agents <n>', 'Number of builder agents', '2')
31
+ .option('--pro', 'Enable Pro tier (concurrent execution, more agents)')
32
+ .option('--budget <usd>', 'Max budget in USD')
33
+ .option('--dry-run', 'Show what would run without executing')
34
+ .action(async (opts) => {
35
+ const { run } = require('../src/commands/run');
36
+ await run(opts);
37
+ });
38
+
39
+ program
40
+ .command('status')
41
+ .description('Show task progress and agent status')
42
+ .action(async () => {
43
+ const { status } = require('../src/commands/status');
44
+ await status();
45
+ });
46
+
47
+ program
48
+ .command('council')
49
+ .description('Start a council session — agents deliberate, then execute')
50
+ .option('--topic <text>', 'Topic for council discussion')
51
+ .option('--agents <names>', 'Comma-separated agent roles', 'Architect,Reviewer,Tester')
52
+ .option('--rounds <n>', 'Max deliberation rounds', '3')
53
+ .option('--execute', 'Auto-execute tasks after deliberation')
54
+ .action(async (opts) => {
55
+ const { council } = require('../src/commands/council');
56
+ await council(opts);
57
+ });
58
+
59
+ program.parse();
package/package.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "myuru",
3
+ "version": "0.1.0",
4
+ "description": "Multi-provider AI agent orchestrator. Coordinate Claude, GPT, and Gemini agents to build software in parallel.",
5
+ "main": "src/index.js",
6
+ "bin": {
7
+ "myuru": "./bin/myuru.js"
8
+ },
9
+ "scripts": {
10
+ "test": "node --test src/**/*.test.js",
11
+ "start": "node bin/myuru.js"
12
+ },
13
+ "keywords": [
14
+ "ai",
15
+ "orchestrator",
16
+ "multi-agent",
17
+ "multi-provider",
18
+ "claude",
19
+ "openai",
20
+ "gemini",
21
+ "coding-agent",
22
+ "automation",
23
+ "cli"
24
+ ],
25
+ "author": "Wittlesus",
26
+ "license": "MIT",
27
+ "repository": {
28
+ "type": "git",
29
+ "url": "https://github.com/Wittlesus/myuru"
30
+ },
31
+ "engines": {
32
+ "node": ">=18.0.0"
33
+ },
34
+ "dependencies": {
35
+ "commander": "^12.0.0"
36
+ }
37
+ }
@@ -0,0 +1,168 @@
1
+ const { spawn } = require("child_process");
2
+ const path = require("path");
3
+ const http = require("http");
4
+ const CouncilServer = require("../lib/council-server");
5
+ const { TierManager } = require("../lib/tiers");
6
+
7
+ async function council(opts) {
8
+ const topic = opts.topic;
9
+ if (!topic) {
10
+ console.error("No topic specified. Use --topic \"...\"");
11
+ process.exit(1);
12
+ }
13
+
14
+ const agentNames = (opts.agents || "Architect,Reviewer,Tester").split(",").map(a => a.trim());
15
+ const maxRounds = parseInt(opts.rounds) || 3;
16
+ const shouldExecute = opts.execute || false;
17
+
18
+ // Tier check
19
+ const tier = new TierManager("FREE");
20
+ try {
21
+ tier.enforceLimit(agentNames.length);
22
+ } catch (err) {
23
+ console.error(err.message);
24
+ process.exit(1);
25
+ }
26
+
27
+ console.log("MyUru Council");
28
+ console.log("─".repeat(50));
29
+ console.log(`Topic: ${topic}`);
30
+ console.log(`Agents: ${agentNames.join(", ")}`);
31
+ console.log(`Rounds: ${maxRounds}`);
32
+ console.log("");
33
+
34
+ // Start council server
35
+ const server = new CouncilServer();
36
+ const port = await server.start();
37
+ console.log(`Council server on port ${port}`);
38
+
39
+ // Configure session
40
+ server.config.agents = agentNames;
41
+ server.config.maxRounds = maxRounds;
42
+
43
+ const base = `http://localhost:${port}`;
44
+
45
+ // Default role prompts
46
+ const rolePrompts = {
47
+ Architect: "Focus on technical feasibility. Challenge complexity. Push for simplicity.",
48
+ Reviewer: "Focus on code quality and edge cases. Challenge assumptions.",
49
+ Tester: "Focus on testability. What could break? Push for test coverage.",
50
+ Revenue: "Focus on monetization. Challenge anything without revenue path.",
51
+ Growth: "Focus on user acquisition. How do users find this?",
52
+ Security: "Focus on security implications. What attack surfaces exist?",
53
+ };
54
+
55
+ // Spawn agents for deliberation
56
+ console.log("\n--- DELIBERATION ---\n");
57
+
58
+ const spawnAgent = (name) => {
59
+ const prompt = [
60
+ `You are "${name}" in a council discussion.`,
61
+ `TOPIC: ${topic}`,
62
+ `YOUR ROLE: ${name}. Stay in character. Be concise.`,
63
+ "CHATROOM PROTOCOL:",
64
+ `- Send message: curl -s -X POST ${base}/chat -H "Content-Type: application/json" -d '{"agent":"${name}","message":"YOUR MSG"}'`,
65
+ `- Read messages: curl -s "${base}/chat?since=-1"`,
66
+ `- Keep messages under 300 chars.`,
67
+ `- You have ${maxRounds} rounds. Each round: read, think, respond.`,
68
+ "- Reference other agents by name. Agree, disagree, challenge.",
69
+ "EFFICIENCY RULES:",
70
+ "- One message per round. No essays.",
71
+ "- Agree in 1 sentence + 1 new insight. Disagree in 2-3 sentences max.",
72
+ rolePrompts[name] || `You are ${name}. Contribute your perspective.`,
73
+ `START: Post opening position (2 sentences), then loop for ${maxRounds} rounds.`,
74
+ ].join("\n");
75
+
76
+ console.log(` Spawning ${name}...`);
77
+
78
+ const env = { ...process.env };
79
+ delete env.CLAUDECODE;
80
+
81
+ // Intentional spawn — core product functionality
82
+ const child = spawn("claude", ["--model", "haiku", "-p"], {
83
+ stdio: ["pipe", "pipe", "pipe"],
84
+ env,
85
+ shell: true,
86
+ });
87
+
88
+ child.stdin.write(prompt);
89
+ child.stdin.end();
90
+
91
+ let output = "";
92
+ child.stdout?.on("data", d => output += d.toString());
93
+ child.stderr?.on("data", d => output += d.toString());
94
+
95
+ return new Promise(resolve => {
96
+ child.on("close", code => {
97
+ console.log(` ${name} finished (exit ${code})`);
98
+ resolve({ name, code, output: output.substring(0, 500) });
99
+ });
100
+ child.on("error", () => {
101
+ resolve({ name, code: -1, output: "spawn error" });
102
+ });
103
+ });
104
+ };
105
+
106
+ const results = await Promise.all(agentNames.map(spawnAgent));
107
+
108
+ // Get transcript
109
+ const transcript = server.messages
110
+ .map(m => `[R${m.round}] **${m.agent}**: ${m.message}`)
111
+ .join("\n\n");
112
+
113
+ console.log(`\nDeliberation complete: ${server.messages.length} messages across ${server.currentRound} rounds.\n`);
114
+
115
+ if (transcript) {
116
+ console.log("--- TRANSCRIPT ---\n");
117
+ console.log(transcript.substring(0, 3000));
118
+ console.log("");
119
+ }
120
+
121
+ // Task extraction
122
+ if (shouldExecute && server.messages.length > 0) {
123
+ console.log("--- TASK EXTRACTION ---\n");
124
+
125
+ const extractPrompt = [
126
+ "Read this council debate and extract 3-6 concrete tasks.",
127
+ `Output a JSON array: [{id, title, description, assignee, priority}].`,
128
+ `Assignee must be one of: ${agentNames.join(", ")}.`,
129
+ "Only output the JSON array.",
130
+ "",
131
+ "TRANSCRIPT:",
132
+ transcript.substring(0, 4000),
133
+ ].join("\n");
134
+
135
+ const env = { ...process.env };
136
+ delete env.CLAUDECODE;
137
+
138
+ const taskOutput = await new Promise(resolve => {
139
+ const child = spawn("claude", ["--model", "haiku", "-p"], {
140
+ stdio: ["pipe", "pipe", "pipe"], env, shell: true,
141
+ });
142
+ child.stdin.write(extractPrompt);
143
+ child.stdin.end();
144
+ let out = "";
145
+ child.stdout?.on("data", d => out += d.toString());
146
+ child.stderr?.on("data", d => out += d.toString());
147
+ child.on("close", () => resolve(out));
148
+ });
149
+
150
+ let tasks = [];
151
+ try {
152
+ const jsonMatch = taskOutput.match(/\[[\s\S]*\]/);
153
+ tasks = jsonMatch ? JSON.parse(jsonMatch[0]) : [];
154
+ } catch {
155
+ console.log("Failed to parse tasks from output.");
156
+ }
157
+
158
+ if (tasks.length > 0) {
159
+ console.log(`Extracted ${tasks.length} tasks:`);
160
+ tasks.forEach(t => console.log(` [${t.assignee}] ${t.title}`));
161
+ }
162
+ }
163
+
164
+ await server.stop();
165
+ console.log("\nCouncil session complete.");
166
+ }
167
+
168
+ module.exports = { council };
@@ -0,0 +1,67 @@
1
+ const fs = require("fs");
2
+ const path = require("path");
3
+
4
+ async function init(opts) {
5
+ const cwd = process.cwd();
6
+ const configFile = path.join(cwd, "myuru.config.mjs");
7
+ const stateDir = path.join(cwd, ".myuru");
8
+
9
+ if (fs.existsSync(configFile)) {
10
+ console.log("myuru.config.mjs already exists in this directory.");
11
+ return;
12
+ }
13
+
14
+ // Create .myuru state directory
15
+ fs.mkdirSync(stateDir, { recursive: true });
16
+ fs.writeFileSync(path.join(stateDir, ".gitignore"), "*\n");
17
+
18
+ // Write default config
19
+ const template = opts.template || "default";
20
+ const config = getTemplate(template);
21
+ fs.writeFileSync(configFile, config);
22
+
23
+ console.log("Initialized MyUru project:");
24
+ console.log(` ${configFile}`);
25
+ console.log(` ${stateDir}/`);
26
+ console.log("");
27
+ console.log("Next: myuru run --task \"Build a login page\"");
28
+ }
29
+
30
+ function getTemplate(name) {
31
+ const templates = {
32
+ default: `// myuru.config.mjs — MyUru orchestrator configuration
33
+ export default {
34
+ // Provider: "claude", "openai", or "gemini" (coming soon)
35
+ provider: "claude",
36
+
37
+ // Model to use for execution
38
+ model: "sonnet",
39
+
40
+ // Number of builder agents
41
+ agents: 2,
42
+
43
+ // Agent roles and system prompts
44
+ roles: {
45
+ Builder: "You are a software engineer. Write clean, working code.",
46
+ Reviewer: "You review code for bugs, security issues, and quality.",
47
+ },
48
+
49
+ // Budget limit per run (USD)
50
+ budget: 5,
51
+
52
+ // Max turns per agent invocation
53
+ maxTurns: 10,
54
+ };
55
+ `,
56
+ minimal: `export default {
57
+ provider: "claude",
58
+ model: "sonnet",
59
+ agents: 1,
60
+ };
61
+ `,
62
+ };
63
+
64
+ return templates[name] || templates.default;
65
+ }
66
+
67
+ module.exports = { init };
@@ -0,0 +1,179 @@
1
+ const fs = require("fs");
2
+ const path = require("path");
3
+ const { createProvider } = require("../providers");
4
+ const AgentRunner = require("../lib/agent-runner");
5
+ const TaskDB = require("../lib/task-db");
6
+ const Dashboard = require("../lib/dashboard");
7
+ const { TierManager } = require("../lib/tiers");
8
+
9
+ async function run(opts) {
10
+ const cwd = process.cwd();
11
+ const stateDir = path.join(cwd, ".myuru");
12
+ fs.mkdirSync(stateDir, { recursive: true });
13
+
14
+ // Load config
15
+ let config = {};
16
+ const configFile = path.join(cwd, "myuru.config.mjs");
17
+ if (fs.existsSync(configFile)) {
18
+ try {
19
+ config = (await import(`file://${configFile.replace(/\\/g, "/")}`)).default;
20
+ } catch {}
21
+ }
22
+
23
+ // CLI overrides
24
+ const providerName = opts.provider || config.provider || "claude";
25
+ const model = opts.model || config.model || "sonnet";
26
+ const agentCount = parseInt(opts.agents) || config.agents || 2;
27
+ const budget = opts.budget || config.budget || "5";
28
+ const maxTurns = config.maxTurns || 10;
29
+ const isPro = opts.pro || false;
30
+
31
+ // Tier enforcement
32
+ const tier = new TierManager(isPro ? "PRO" : "FREE");
33
+ const tierInfo = tier.info();
34
+
35
+ console.log(`MyUru v0.1.0 | ${tierInfo.tier} tier | ${providerName}/${model}`);
36
+ console.log(`Agents: ${agentCount} | Execution: ${tierInfo.concurrency}`);
37
+ console.log("─".repeat(50));
38
+
39
+ try {
40
+ tier.enforceLimit(agentCount, isPro);
41
+ } catch (err) {
42
+ console.error(err.message);
43
+ process.exit(1);
44
+ }
45
+
46
+ // Resolve task
47
+ let task = opts.task;
48
+ if (!task && opts.file) {
49
+ task = fs.readFileSync(opts.file, "utf-8");
50
+ }
51
+ if (!task) {
52
+ console.error("No task specified. Use --task \"...\" or --file <path>");
53
+ process.exit(1);
54
+ }
55
+
56
+ if (opts.dryRun) {
57
+ console.log("\nDry run — would execute:");
58
+ console.log(` Task: ${task}`);
59
+ console.log(` Provider: ${providerName}/${model}`);
60
+ console.log(` Agents: ${agentCount}`);
61
+ console.log(` Budget: $${budget}`);
62
+ return;
63
+ }
64
+
65
+ // Create provider and DB
66
+ const provider = createProvider(providerName);
67
+ const db = new TaskDB(stateDir);
68
+
69
+ // Create task in DB
70
+ const taskId = `task-${Date.now()}`;
71
+ db.createTask({
72
+ id: taskId,
73
+ title: task.substring(0, 100),
74
+ description: task,
75
+ priority: 1,
76
+ createdBy: "user",
77
+ });
78
+
79
+ // Create agents
80
+ const agents = [];
81
+ const roles = config.roles || { Builder: "You are a software engineer. Write clean, working code." };
82
+ const roleNames = Object.keys(roles).slice(0, agentCount);
83
+
84
+ for (let i = 0; i < agentCount; i++) {
85
+ const roleName = roleNames[i % roleNames.length];
86
+ agents.push(new AgentRunner({
87
+ id: `${roleName}-${i}`,
88
+ model,
89
+ provider,
90
+ systemPrompt: roles[roleName] || `You are ${roleName}. Complete the task efficiently.`,
91
+ maxTurns,
92
+ budgetUsd: budget,
93
+ cwd,
94
+ stateless: true,
95
+ }));
96
+ }
97
+
98
+ // Dashboard
99
+ const dashboard = new Dashboard();
100
+ const startTime = Date.now();
101
+
102
+ dashboard.start(() => {
103
+ const elapsed = ((Date.now() - startTime) / 1000).toFixed(0);
104
+ const running = agents.filter(a => a.busy).length;
105
+ const done = agents.filter(a => a.invocationCount > 0 && !a.busy).length;
106
+ return [
107
+ `\x1b[36mMyUru\x1b[0m | ${providerName}/${model} | ${tierInfo.tier}`,
108
+ `Task: ${task.substring(0, 60)}`,
109
+ `Agents: ${running} running, ${done} done | ${elapsed}s elapsed`,
110
+ "─".repeat(dashboard.cols),
111
+ ];
112
+ });
113
+
114
+ // Execute
115
+ console.log(`\nExecuting with ${agentCount} agent(s)...\n`);
116
+
117
+ const runAgent = async (agent, idx) => {
118
+ const prompt = [
119
+ `PROJECT DIRECTORY: ${cwd}`,
120
+ `TASK: ${task}`,
121
+ "",
122
+ `You are agent ${idx + 1} of ${agentCount}.`,
123
+ agentCount > 1 ? `Focus on your part. Agent roles: ${roleNames.join(", ")}.` : "",
124
+ "",
125
+ "Complete the task. Be efficient. Ship working code.",
126
+ ].filter(Boolean).join("\n");
127
+
128
+ db.assignTask(taskId, agent.id);
129
+ db.startTask(taskId, agent.id);
130
+ dashboard.log(`[${agent.id}] Starting...`);
131
+
132
+ try {
133
+ const output = await agent.invoke(prompt, taskId);
134
+ dashboard.log(`[${agent.id}] Done (${output.length} chars)`);
135
+ return { agent: agent.id, success: true, output };
136
+ } catch (err) {
137
+ dashboard.log(`[${agent.id}] Failed: ${err.message}`);
138
+ return { agent: agent.id, success: false, error: err.message };
139
+ }
140
+ };
141
+
142
+ let results;
143
+ if (isPro && agentCount > 1) {
144
+ // Concurrent execution (PRO)
145
+ results = await Promise.all(agents.map((a, i) => runAgent(a, i)));
146
+ } else {
147
+ // Sequential execution (FREE)
148
+ results = [];
149
+ for (let i = 0; i < agents.length; i++) {
150
+ results.push(await runAgent(agents[i], i));
151
+ }
152
+ }
153
+
154
+ dashboard.stop();
155
+
156
+ // Summary
157
+ const successes = results.filter(r => r.success).length;
158
+ const failures = results.filter(r => !r.success).length;
159
+
160
+ if (successes > 0) {
161
+ db.completeTask(taskId, "orchestrator", `${successes} agents completed`);
162
+ } else {
163
+ db.failTask(taskId, "orchestrator", `All ${failures} agents failed`);
164
+ }
165
+
166
+ console.log("\nResults:");
167
+ console.log("─".repeat(50));
168
+ for (const r of results) {
169
+ const icon = r.success ? "OK" : "XX";
170
+ console.log(` [${icon}] ${r.agent}`);
171
+ if (r.output) console.log(` ${r.output.substring(0, 200)}`);
172
+ if (r.error) console.log(` Error: ${r.error}`);
173
+ }
174
+ console.log(`\n${successes} succeeded, ${failures} failed.`);
175
+
176
+ db.close();
177
+ }
178
+
179
+ module.exports = { run };
@@ -0,0 +1,49 @@
1
+ const fs = require("fs");
2
+ const path = require("path");
3
+ const TaskDB = require("../lib/task-db");
4
+
5
+ async function status() {
6
+ const stateDir = path.join(process.cwd(), ".myuru");
7
+
8
+ if (!fs.existsSync(stateDir)) {
9
+ console.log("No MyUru project found. Run: myuru init");
10
+ return;
11
+ }
12
+
13
+ const db = new TaskDB(stateDir);
14
+ const tasks = db.getAllTasks();
15
+ const stats = db.getTaskStats();
16
+
17
+ if (tasks.length === 0) {
18
+ console.log("No tasks yet. Run: myuru run --task \"...\"");
19
+ return;
20
+ }
21
+
22
+ console.log("MyUru Task Status");
23
+ console.log("─".repeat(60));
24
+
25
+ const statusIcons = {
26
+ pending: " ",
27
+ assigned: ">>",
28
+ in_progress: "**",
29
+ done: "OK",
30
+ failed: "XX",
31
+ };
32
+
33
+ for (const task of tasks) {
34
+ const icon = statusIcons[task.status] || "??";
35
+ const agent = task.assigned_to ? ` (${task.assigned_to})` : "";
36
+ console.log(` [${icon}] ${task.title}${agent}`);
37
+ if (task.result) {
38
+ console.log(` -> ${task.result.substring(0, 80)}`);
39
+ }
40
+ }
41
+
42
+ console.log("");
43
+ console.log("Summary:");
44
+ for (const s of stats) {
45
+ console.log(` ${s.status}: ${s.count}`);
46
+ }
47
+ }
48
+
49
+ module.exports = { status };