omkx 0.1.0 → 0.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.
Files changed (4) hide show
  1. package/README.md +41 -15
  2. package/bin/cli.mjs +286 -140
  3. package/install.sh +8 -1
  4. package/package.json +26 -6
package/README.md CHANGED
@@ -35,33 +35,56 @@ omkx provides a three-tier agent system where main agents orchestrate work and s
35
35
  ## Quick Start
36
36
 
37
37
  ```bash
38
- npx omkx@latest install
38
+ npx omkx@latest
39
39
  ```
40
40
 
41
- This installs all agents, prompts, hooks, skills, and configuration into your Kiro project's `.kiro/` directory.
41
+ Or for global install (available in all projects):
42
+
43
+ ```bash
44
+ npx omkx@latest --global
45
+ ```
46
+
47
+ This copies all agents, prompts, hooks, skills, steering files, and MCP configuration into `.kiro/` — either `./.kiro/` (local) or `~/.kiro/` (global). Then open your project in Kiro and the agents are available — `ctrl+p` for Prometheus (planner), `ctrl+a` for Atlas (plan executor), `ctrl+e` for Sisyphus (direct tasks).
42
48
 
43
49
  ---
44
50
 
45
51
  ## Installation
46
52
 
47
- ### Option 1: npx (Recommended)
53
+ Two ways:
54
+
55
+ **Option 1 — npx (no clone needed):**
48
56
 
49
57
  ```bash
50
- npx omkx@latest install
58
+ npx omkx@latest
51
59
  ```
52
60
 
53
- ### Option 2: Using the install script
61
+ Or for global install (available in all projects):
54
62
 
55
63
  ```bash
56
- curl -fsSL https://raw.githubusercontent.com/seyisulu/omkx/main/install.sh | bash
64
+ npx omkx@latest --global
57
65
  ```
58
66
 
59
- ### Option 3: Local development
67
+ **Option 2 from the repo:**
60
68
 
61
69
  ```bash
62
70
  git clone https://github.com/seyisulu/omkx.git
63
71
  cd omkx
64
- bash install.sh
72
+ ./install.sh # local install (current project only)
73
+ ./install.sh --global # global install (all projects)
74
+ ```
75
+
76
+ Both methods copy the `.kiro/` directory (agents, prompts, hooks, skills, steering files, MCP config) into either `./.kiro/` (local) or `~/.kiro/` (global). Then just open your project in Kiro and the agents are available — `ctrl+p` for Prometheus (planner), `ctrl+a` for Atlas (plan executor), `ctrl+e` for Sisyphus (direct tasks).
77
+
78
+ ### Updating later
79
+
80
+ ```bash
81
+ npx omkx@latest --update
82
+ ```
83
+
84
+ ### Uninstalling
85
+
86
+ ```bash
87
+ npx omkx@latest --uninstall
65
88
  ```
66
89
 
67
90
  ---
@@ -287,13 +310,16 @@ Update files in `.kiro/steering/omkx/` to change project conventions, plan forma
287
310
  ## Commands
288
311
 
289
312
  ```bash
290
- omkx install # Install omkx agents and configuration
291
- omkx install --force # Force reinstall
313
+ omkx # Install (local, current project only)
314
+ omkx --global # Install globally (all projects)
315
+ omkx --update # Update to the latest version
316
+ omkx --uninstall # Remove omkx
317
+ omkx install --force # Force reinstall
292
318
  omkx install --dir <path> # Install to specific directory
293
- omkx status # Show installation status
294
- omkx list # List all installed agents
295
- omkx plans # List execution plans
296
- omkx help # Show help
319
+ omkx status # Show installation status
320
+ omkx list # List all installed agents
321
+ omkx plans # List execution plans
322
+ omkx help # Show help
297
323
  ```
298
324
 
299
325
  ---
@@ -302,7 +328,7 @@ omkx help # Show help
302
328
 
303
329
  omkx is based on:
304
330
 
305
- - **[oh-my-openagent](https://github.com/code-yeongyu/oh-my-openagent)** — The original TypeScript multi-agent system developed by seyisulu. Agent personalities, workflows, and delegation patterns are adapted from this project.
331
+ - **[oh-my-openagent](https://github.com/code-yeongyu/oh-my-openagent)** — The original TypeScript multi-agent system developed by code-yeongyu. Agent personalities, workflows, and delegation patterns are adapted from this project.
306
332
  - **[oh-my-kiro](https://github.com/NachoFLizaur/oh-my-kiro)** — The Kiro IDE agent format and conventions that omkx follows.
307
333
 
308
334
  ### Agent Name Origins
package/bin/cli.mjs CHANGED
@@ -1,12 +1,21 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import { readFileSync, existsSync } from 'fs';
4
- import { resolve, dirname } from 'path';
5
- import { fileURLToPath } from 'url';
6
- import { execSync } from 'child_process';
3
+ import {
4
+ readFileSync,
5
+ existsSync,
6
+ cpSync,
7
+ mkdirSync,
8
+ writeFileSync,
9
+ rmSync,
10
+ rmdirSync,
11
+ } from "fs";
12
+ import { resolve, dirname } from "path";
13
+ import { fileURLToPath } from "url";
14
+ import { execSync } from "child_process";
15
+ import { homedir } from "os";
7
16
 
8
17
  const __dirname = dirname(fileURLToPath(import.meta.url));
9
- const PKG_ROOT = resolve(__dirname, '..');
18
+ const PKG_ROOT = resolve(__dirname, "..");
10
19
 
11
20
  // ─── Help ────────────────────────────────────────────────────────────────
12
21
 
@@ -17,22 +26,27 @@ function showHelp() {
17
26
  ║ Multi-Agent Orchestration for Kiro ║
18
27
  ╚══════════════════════════════════════════════════════════╝
19
28
 
20
- Usage: omkx <command> [options]
29
+ Usage: omkx [command] [options]
21
30
 
22
31
  Commands:
23
- install Install omkx agents and configuration
32
+ (default) Install omkx agents and configuration
24
33
  status Show installation status
25
34
  list List installed agents
26
35
  plans List execution plans
27
36
  help Show this help
28
37
 
29
- Installation:
30
- npx omkx@latest install Install to current directory
31
- omkx install --force Force reinstall
32
- omkx install --dir <path> Install to specific directory
38
+ Flags:
39
+ --global Install/uninstall globally (~/.kiro) instead of locally (./.kiro)
40
+ --update Update to the latest version (force reinstall)
41
+ --uninstall Remove omkx from the target directory
42
+ --force Force reinstall
43
+ --dir <path> Target directory (default: current directory)
33
44
 
34
45
  Examples:
35
- omkx install Install omkx in current directory
46
+ npx omkx@latest Install in current project
47
+ npx omkx@latest --global Install globally (all projects)
48
+ npx omkx@latest --update Update to the latest version
49
+ npx omkx@latest --uninstall Remove omkx
36
50
  omkx status Check what's installed
37
51
  omkx list List all agents
38
52
  omkx plans List plans from .kiro/plans/
@@ -51,10 +65,12 @@ Repository: https://github.com/seyisulu/omkx
51
65
 
52
66
  function getVersion() {
53
67
  try {
54
- const pkg = JSON.parse(readFileSync(resolve(PKG_ROOT, 'package.json'), 'utf8'));
68
+ const pkg = JSON.parse(
69
+ readFileSync(resolve(PKG_ROOT, "package.json"), "utf8"),
70
+ );
55
71
  return pkg.version;
56
72
  } catch {
57
- return '0.1.0';
73
+ return "0.1.0";
58
74
  }
59
75
  }
60
76
 
@@ -62,153 +78,171 @@ function getVersion() {
62
78
 
63
79
  const MANIFEST = {
64
80
  agents: [
65
- 'prometheus.json',
66
- 'atlas.json',
67
- 'sisyphus.json',
68
- 'ghost-explorer.json',
69
- 'ghost-metis.json',
70
- 'ghost-momus.json',
71
- 'ghost-oracle.json',
72
- 'ghost-librarian.json',
73
- 'ghost-junior.json',
74
- 'ghost-looker.json',
81
+ "prometheus.json",
82
+ "atlas.json",
83
+ "sisyphus.json",
84
+ "ghost-explorer.json",
85
+ "ghost-metis.json",
86
+ "ghost-momus.json",
87
+ "ghost-oracle.json",
88
+ "ghost-librarian.json",
89
+ "ghost-junior.json",
90
+ "ghost-looker.json",
75
91
  ],
76
92
  prompts: [
77
- 'prometheus.md',
78
- 'atlas.md',
79
- 'sisyphus.md',
80
- 'ghost-explorer.md',
81
- 'ghost-metis.md',
82
- 'ghost-momus.md',
83
- 'ghost-oracle.md',
84
- 'ghost-librarian.md',
85
- 'ghost-junior.md',
86
- 'ghost-looker.md',
93
+ "prometheus.md",
94
+ "atlas.md",
95
+ "sisyphus.md",
96
+ "ghost-explorer.md",
97
+ "ghost-metis.md",
98
+ "ghost-momus.md",
99
+ "ghost-oracle.md",
100
+ "ghost-librarian.md",
101
+ "ghost-junior.md",
102
+ "ghost-looker.md",
87
103
  ],
88
104
  hooks: [
89
- 'agent-spawn.sh',
90
- 'pre-tool-use.sh',
91
- 'prometheus-read-guard.sh',
92
- 'prometheus-write-guard.sh',
105
+ "agent-spawn.sh",
106
+ "pre-tool-use.sh",
107
+ "prometheus-read-guard.sh",
108
+ "prometheus-write-guard.sh",
93
109
  ],
94
110
  steering: [
95
- 'product.md',
96
- 'conventions.md',
97
- 'plan-format.md',
98
- 'architecture.md',
111
+ "product.md",
112
+ "conventions.md",
113
+ "plan-format.md",
114
+ "architecture.md",
99
115
  ],
100
116
  skills: [
101
- 'git-operations',
102
- 'code-review',
103
- 'frontend-ux',
104
- 'debugging',
105
- 'programming',
106
- ],
107
- settings: [
108
- 'mcp.json',
117
+ "git-operations",
118
+ "code-review",
119
+ "frontend-ux",
120
+ "debugging",
121
+ "programming",
109
122
  ],
123
+ settings: ["mcp.json"],
110
124
  };
111
125
 
112
126
  function install(targetDir, force = false) {
113
- const kiroDir = resolve(targetDir, '.kiro');
127
+ const kiroDir = resolve(targetDir, ".kiro");
128
+ const isGlobal = resolve(targetDir) === homedir();
129
+ const scope = isGlobal ? "globally" : "locally";
114
130
 
115
131
  // Check if already installed
116
- const manifestMarker = resolve(kiroDir, 'agents', 'prometheus.json');
132
+ const manifestMarker = resolve(kiroDir, "agents", "prometheus.json");
117
133
  if (existsSync(manifestMarker) && !force) {
118
- console.log('✅ omkx is already installed.');
119
- console.log(' Use --force to reinstall.');
134
+ console.log(`✅ omkx is already installed ${scope} (${kiroDir}).`);
135
+ console.log(" Use --force or --update to reinstall.");
120
136
  return;
121
137
  }
122
138
 
123
- console.log(`📦 Installing omkx to ${targetDir}...\n`);
139
+ console.log(`📦 Installing omkx ${scope} to ${kiroDir}...\n`);
124
140
 
125
141
  // Copy .kiro directory
126
- copyDir(resolve(PKG_ROOT, '.kiro'), kiroDir);
142
+ copyDir(resolve(PKG_ROOT, ".kiro"), kiroDir);
127
143
 
128
144
  // Make hooks executable
129
- const hooksDir = resolve(kiroDir, 'hooks');
145
+ const hooksDir = resolve(kiroDir, "hooks");
130
146
  try {
131
- execSync(`chmod +x ${hooksDir}/*.sh`, { stdio: 'pipe' });
147
+ execSync(`chmod +x ${hooksDir}/*.sh`, { stdio: "pipe" });
132
148
  } catch {
133
149
  // Ignore if no hooks dir
134
150
  }
135
151
 
136
152
  // Create empty dirs with gitkeep
137
- ensureDir(resolve(kiroDir, 'plans'));
138
- ensureDir(resolve(kiroDir, 'notepads'));
139
- touchIfMissing(resolve(kiroDir, 'plans', '.gitkeep'));
140
- touchIfMissing(resolve(kiroDir, 'notepads', '.gitkeep'));
141
-
142
- console.log('');
143
- console.log('✅ omkx installed successfully!');
144
- console.log('');
145
- console.log('📂 Installed structure:');
153
+ ensureDir(resolve(kiroDir, "plans"));
154
+ ensureDir(resolve(kiroDir, "notepads"));
155
+ touchIfMissing(resolve(kiroDir, "plans", ".gitkeep"));
156
+ touchIfMissing(resolve(kiroDir, "notepads", ".gitkeep"));
157
+
158
+ console.log("");
159
+ console.log("✅ omkx installed successfully!");
160
+ console.log("");
161
+ console.log("📂 Installed structure:");
146
162
  console.log(` .kiro/agents/ → ${MANIFEST.agents.length} agents`);
147
163
  console.log(` .kiro/prompts/ → ${MANIFEST.prompts.length} prompts`);
148
164
  console.log(` .kiro/hooks/ → ${MANIFEST.hooks.length} hooks`);
149
165
  console.log(` .kiro/skills/ → ${MANIFEST.skills.length} skills`);
150
- console.log(` .kiro/steering/omkx/ → ${MANIFEST.steering.length} steering files`);
166
+ console.log(
167
+ ` .kiro/steering/omkx/ → ${MANIFEST.steering.length} steering files`,
168
+ );
151
169
  console.log(` .kiro/settings/ → ${MANIFEST.settings.length} settings`);
152
170
  console.log(` .kiro/plans/ → Execution plans`);
153
171
  console.log(` .kiro/notepads/ → Agent notepads`);
154
- console.log('');
155
- console.log('⌨️ Keyboard Shortcuts in Kiro:');
156
- console.log(' ctrl+p → Prometheus (Planner)');
157
- console.log(' ctrl+a → Atlas (Plan Executor)');
158
- console.log(' ctrl+e → Sisyphus (Direct Executor)');
159
- console.log('');
160
- console.log('📖 Read .kiro/steering/omkx/product.md for full documentation.');
172
+ console.log("");
173
+ console.log("⌨️ Keyboard Shortcuts in Kiro:");
174
+ console.log(" ctrl+p → Prometheus (Planner)");
175
+ console.log(" ctrl+a → Atlas (Plan Executor)");
176
+ console.log(" ctrl+e → Sisyphus (Direct Executor)");
177
+ console.log("");
178
+ console.log("📖 Read .kiro/steering/omkx/product.md for full documentation.");
161
179
  }
162
180
 
163
181
  // ─── Status ───────────────────────────────────────────────────────────────
164
182
 
165
183
  function status(targetDir) {
166
- const kiroDir = resolve(targetDir, '.kiro');
167
- const manifestMarker = resolve(kiroDir, 'agents', 'prometheus.json');
184
+ const kiroDir = resolve(targetDir, ".kiro");
185
+ const manifestMarker = resolve(kiroDir, "agents", "prometheus.json");
168
186
 
169
- console.log('🔍 omkx Status\n');
187
+ console.log("🔍 omkx Status\n");
170
188
 
171
189
  if (!existsSync(manifestMarker)) {
172
- console.log('❌ omkx is NOT installed.');
173
- console.log(' Run: npx omkx install');
190
+ console.log("❌ omkx is NOT installed.");
191
+ console.log(" Run: npx omkx install");
174
192
  return;
175
193
  }
176
194
 
177
- console.log('✅ omkx is installed.\n');
195
+ console.log("✅ omkx is installed.\n");
178
196
 
179
197
  // Count agents
180
- const agentsDir = resolve(kiroDir, 'agents');
198
+ const agentsDir = resolve(kiroDir, "agents");
181
199
  let agentCount = 0;
182
200
  if (existsSync(agentsDir)) {
183
- agentCount = MANIFEST.agents.filter(a => existsSync(resolve(agentsDir, a))).length;
201
+ agentCount = MANIFEST.agents.filter((a) =>
202
+ existsSync(resolve(agentsDir, a)),
203
+ ).length;
184
204
  }
185
205
  console.log(` Agents: ${agentCount}/${MANIFEST.agents.length}`);
186
206
 
187
207
  // Count prompts
188
- const promptsDir = resolve(kiroDir, 'prompts');
208
+ const promptsDir = resolve(kiroDir, "prompts");
189
209
  let promptCount = 0;
190
210
  if (existsSync(promptsDir)) {
191
- promptCount = MANIFEST.prompts.filter(p => existsSync(resolve(promptsDir, p))).length;
211
+ promptCount = MANIFEST.prompts.filter((p) =>
212
+ existsSync(resolve(promptsDir, p)),
213
+ ).length;
192
214
  }
193
215
  console.log(` Prompts: ${promptCount}/${MANIFEST.prompts.length}`);
194
216
 
195
217
  // Count plans
196
- const plansDir = resolve(kiroDir, 'plans');
218
+ const plansDir = resolve(kiroDir, "plans");
197
219
  let planCount = 0;
198
220
  if (existsSync(plansDir)) {
199
221
  try {
200
- planCount = execSync(`ls -1 ${plansDir}/*.md 2>/dev/null | wc -l`, { stdio: 'pipe' }).toString().trim();
201
- } catch { planCount = 0; }
222
+ planCount = execSync(`ls -1 ${plansDir}/*.md 2>/dev/null | wc -l`, {
223
+ stdio: "pipe",
224
+ })
225
+ .toString()
226
+ .trim();
227
+ } catch {
228
+ planCount = 0;
229
+ }
202
230
  }
203
231
  console.log(` Plans: ${planCount}`);
204
232
 
205
233
  // Count notepads
206
- const notepadsDir = resolve(kiroDir, 'notepads');
234
+ const notepadsDir = resolve(kiroDir, "notepads");
207
235
  let notepadCount = 0;
208
236
  if (existsSync(notepadsDir)) {
209
237
  try {
210
- notepadCount = execSync(`ls -1d ${notepadsDir}/*/ 2>/dev/null | wc -l`, { stdio: 'pipe' }).toString().trim();
211
- } catch { notepadCount = 0; }
238
+ notepadCount = execSync(`ls -1d ${notepadsDir}/*/ 2>/dev/null | wc -l`, {
239
+ stdio: "pipe",
240
+ })
241
+ .toString()
242
+ .trim();
243
+ } catch {
244
+ notepadCount = 0;
245
+ }
212
246
  }
213
247
  console.log(` Notepads: ${notepadCount}`);
214
248
  }
@@ -216,45 +250,51 @@ function status(targetDir) {
216
250
  // ─── List ──────────────────────────────────────────────────────────────────
217
251
 
218
252
  function list(targetDir) {
219
- const kiroDir = resolve(targetDir, '.kiro');
220
- const agentsDir = resolve(kiroDir, 'agents');
253
+ const kiroDir = resolve(targetDir, ".kiro");
254
+ const agentsDir = resolve(kiroDir, "agents");
221
255
 
222
- console.log('🤖 omkx Agents\n');
256
+ console.log("🤖 omkx Agents\n");
223
257
 
224
258
  if (!existsSync(agentsDir)) {
225
- console.log('❌ No agents found. Run: npx omkx install');
259
+ console.log("❌ No agents found. Run: npx omkx install");
226
260
  return;
227
261
  }
228
262
 
229
- console.log('Main Agents:');
230
- const mainAgents = ['prometheus', 'atlas', 'sisyphus'];
231
- const shortcuts = { prometheus: 'ctrl+p', atlas: 'ctrl+a', sisyphus: 'ctrl+e' };
263
+ console.log("Main Agents:");
264
+ const mainAgents = ["prometheus", "atlas", "sisyphus"];
265
+ const shortcuts = {
266
+ prometheus: "ctrl+p",
267
+ atlas: "ctrl+a",
268
+ sisyphus: "ctrl+e",
269
+ };
232
270
  const descriptions = {
233
- prometheus: 'Planner — creates execution plans',
234
- atlas: 'Plan Executor — orchestrates plan execution',
235
- sisyphus: 'Direct Executor — handles ad-hoc tasks',
271
+ prometheus: "Planner — creates execution plans",
272
+ atlas: "Plan Executor — orchestrates plan execution",
273
+ sisyphus: "Direct Executor — handles ad-hoc tasks",
236
274
  };
237
275
 
238
276
  for (const name of mainAgents) {
239
277
  const file = resolve(agentsDir, `${name}.json`);
240
- const installed = existsSync(file) ? '' : '';
241
- console.log(` ${installed} ${name.padEnd(16)} ${shortcuts[name].padEnd(8)} ${descriptions[name]}`);
278
+ const installed = existsSync(file) ? "" : "";
279
+ console.log(
280
+ ` ${installed} ${name.padEnd(16)} ${shortcuts[name].padEnd(8)} ${descriptions[name]}`,
281
+ );
242
282
  }
243
283
 
244
- console.log('\nSubagents:');
284
+ console.log("\nSubagents:");
245
285
  const subAgents = [
246
- { name: 'ghost-oracle', desc: 'Strategic technical advisor' },
247
- { name: 'ghost-metis', desc: 'Pre-planning analyst' },
248
- { name: 'ghost-momus', desc: 'Plan validator' },
249
- { name: 'ghost-librarian', desc: 'Research specialist' },
250
- { name: 'ghost-explorer', desc: 'Codebase explorer' },
251
- { name: 'ghost-junior', desc: 'Implementation specialist' },
252
- { name: 'ghost-looker', desc: 'Media analyst' },
286
+ { name: "ghost-oracle", desc: "Strategic technical advisor" },
287
+ { name: "ghost-metis", desc: "Pre-planning analyst" },
288
+ { name: "ghost-momus", desc: "Plan validator" },
289
+ { name: "ghost-librarian", desc: "Research specialist" },
290
+ { name: "ghost-explorer", desc: "Codebase explorer" },
291
+ { name: "ghost-junior", desc: "Implementation specialist" },
292
+ { name: "ghost-looker", desc: "Media analyst" },
253
293
  ];
254
294
 
255
295
  for (const agent of subAgents) {
256
296
  const file = resolve(agentsDir, `${agent.name}.json`);
257
- const installed = existsSync(file) ? '' : '';
297
+ const installed = existsSync(file) ? "" : "";
258
298
  console.log(` ${installed} ${agent.name.padEnd(20)} ${agent.desc}`);
259
299
  }
260
300
  }
@@ -262,43 +302,111 @@ function list(targetDir) {
262
302
  // ─── Plans ─────────────────────────────────────────────────────────────────
263
303
 
264
304
  function plans(targetDir) {
265
- const plansDir = resolve(targetDir, '.kiro', 'plans');
305
+ const plansDir = resolve(targetDir, ".kiro", "plans");
266
306
 
267
- console.log('📐 Execution Plans\n');
307
+ console.log("📐 Execution Plans\n");
268
308
 
269
309
  if (!existsSync(plansDir)) {
270
- console.log('No plans directory found. Create plans with Prometheus (ctrl+p).');
310
+ console.log(
311
+ "No plans directory found. Create plans with Prometheus (ctrl+p).",
312
+ );
271
313
  return;
272
314
  }
273
315
 
274
316
  try {
275
- const output = execSync(`ls -1t ${plansDir}/*.md 2>/dev/null`, { stdio: 'pipe' }).toString().trim();
317
+ const output = execSync(`ls -1t ${plansDir}/*.md 2>/dev/null`, {
318
+ stdio: "pipe",
319
+ })
320
+ .toString()
321
+ .trim();
276
322
  if (!output) {
277
- console.log('No plans found. Create plans with Prometheus (ctrl+p).');
323
+ console.log("No plans found. Create plans with Prometheus (ctrl+p).");
278
324
  return;
279
325
  }
280
- const planFiles = output.split('\n');
326
+ const planFiles = output.split("\n");
281
327
  for (const plan of planFiles) {
282
- const name = plan.split('/').pop();
328
+ const name = plan.split("/").pop();
283
329
  // Try to extract title from first line
284
330
  try {
285
- const firstLine = execSync(`head -1 "${plan}"`, { stdio: 'pipe' }).toString().trim();
286
- const title = firstLine.replace(/^#\s*(Plan:\s*)?/, '');
331
+ const firstLine = execSync(`head -1 "${plan}"`, { stdio: "pipe" })
332
+ .toString()
333
+ .trim();
334
+ const title = firstLine.replace(/^#\s*(Plan:\s*)?/, "");
287
335
  console.log(` 📄 ${name}`);
288
336
  console.log(` ${title}`);
289
337
  } catch {
290
338
  console.log(` 📄 ${name}`);
291
339
  }
292
- console.log('');
340
+ console.log("");
293
341
  }
294
342
  } catch {
295
- console.log('No plans found.');
343
+ console.log("No plans found.");
296
344
  }
297
345
  }
298
346
 
299
- // ─── Utilities ─────────────────────────────────────────────────────────────
347
+ // ─── Uninstall ────────────────────────────────────────────────────────────
348
+
349
+ function uninstall(targetDir) {
350
+ const kiroDir = resolve(targetDir, ".kiro");
351
+ const isGlobal = resolve(targetDir) === homedir();
352
+ const scope = isGlobal ? "global" : "local";
353
+ const manifestMarker = resolve(kiroDir, "agents", "prometheus.json");
354
+
355
+ console.log("🗑️ Uninstalling omkx...\n");
356
+
357
+ if (!existsSync(manifestMarker)) {
358
+ console.log(`❌ omkx is not installed ${scope} (${kiroDir}).`);
359
+ return;
360
+ }
361
+
362
+ // Remove all omkx-managed directories and files
363
+ const targets = [
364
+ "agents",
365
+ "prompts",
366
+ "hooks",
367
+ "skills",
368
+ "settings/mcp.json",
369
+ "steering/omkx",
370
+ ];
371
+
372
+ const removed = [];
373
+ for (const t of targets) {
374
+ const path = resolve(kiroDir, t);
375
+ if (existsSync(path)) {
376
+ rmSync(path, { recursive: true, force: true });
377
+ removed.push(t);
378
+ }
379
+ }
380
+
381
+ // Clean up now-empty parent dirs (steering/, settings/)
382
+ for (const dir of ["steering", "settings"]) {
383
+ const path = resolve(kiroDir, dir);
384
+ try {
385
+ rmdirSync(path);
386
+ removed.push(`${dir}/`);
387
+ } catch {
388
+ // Not empty or doesn't exist — leave it alone
389
+ }
390
+ }
391
+
392
+ // Try to remove .kiro itself if entirely empty.
393
+ // If plans/ or notepads/ still has user content, .kiro is kept.
394
+ let kiroRemoved = false;
395
+ try {
396
+ rmdirSync(kiroDir);
397
+ kiroRemoved = true;
398
+ } catch {
399
+ // User still has plans/notepads — preserve them
400
+ }
401
+
402
+ console.log(`✅ omkx removed ${scope} from ${kiroDir}`);
403
+ console.log(` Removed: ${removed.join(", ")}`);
404
+ if (!kiroRemoved) {
405
+ console.log(` Kept: ${kiroDir}/plans/, ${kiroDir}/notepads/ (your data)`);
406
+ }
407
+ }
300
408
 
301
- import { cpSync, mkdirSync, writeFileSync } from 'fs';
409
+ // ─── Utilities ─────────────────────────────────────────────────────────────
302
410
 
303
411
  function copyDir(src, dest) {
304
412
  cpSync(src, dest, { recursive: true });
@@ -310,7 +418,7 @@ function ensureDir(dir) {
310
418
 
311
419
  function touchIfMissing(file) {
312
420
  if (!existsSync(file)) {
313
- writeFileSync(file, '');
421
+ writeFileSync(file, "");
314
422
  }
315
423
  }
316
424
 
@@ -318,36 +426,74 @@ function touchIfMissing(file) {
318
426
 
319
427
  function main() {
320
428
  const args = process.argv.slice(2);
321
- const command = args[0] || 'help';
322
429
 
323
430
  let targetDir = process.cwd();
324
431
  let force = false;
325
-
326
- // Parse flags
327
- for (let i = 1; i < args.length; i++) {
328
- if (args[i] === '--dir' && args[i + 1]) {
329
- targetDir = resolve(args[++i]);
330
- } else if (args[i] === '--force') {
432
+ let global = false;
433
+ let doUpdate = false;
434
+ let doUninstall = false;
435
+ let command = null;
436
+
437
+ // Parse all args flags can appear anywhere.
438
+ for (let i = 0; i < args.length; i++) {
439
+ const arg = args[i];
440
+ if (arg === "--global" || arg === "-g") {
441
+ global = true;
442
+ } else if (arg === "--force" || arg === "-f") {
331
443
  force = true;
444
+ } else if (arg === "--update") {
445
+ doUpdate = true;
446
+ } else if (arg === "--uninstall") {
447
+ doUninstall = true;
448
+ } else if (arg === "--dir" && args[i + 1]) {
449
+ targetDir = resolve(args[++i]);
450
+ } else if (arg === "--help" || arg === "-h") {
451
+ showHelp();
452
+ return;
453
+ } else if (!arg.startsWith("-")) {
454
+ // First non-flag arg is the command (install/status/list/plans/help)
455
+ if (!command) command = arg;
456
+ } else {
457
+ console.log(`Unknown option: ${arg}`);
458
+ console.log('Run "omkx help" for usage information.');
459
+ process.exit(1);
332
460
  }
333
461
  }
334
462
 
463
+ // --global targets the user's home directory (~/.kiro)
464
+ if (global) {
465
+ targetDir = homedir();
466
+ }
467
+
468
+ // --uninstall removes omkx from the target directory
469
+ if (doUninstall) {
470
+ uninstall(targetDir);
471
+ return;
472
+ }
473
+
474
+ // --update reinstalls with force (useful with npx to pull latest)
475
+ if (doUpdate) {
476
+ install(targetDir, true);
477
+ return;
478
+ }
479
+
480
+ // Default command is install (so bare `npx omkx@latest` installs)
481
+ command = command || "install";
482
+
335
483
  switch (command) {
336
- case 'install':
484
+ case "install":
337
485
  install(targetDir, force);
338
486
  break;
339
- case 'status':
487
+ case "status":
340
488
  status(targetDir);
341
489
  break;
342
- case 'list':
490
+ case "list":
343
491
  list(targetDir);
344
492
  break;
345
- case 'plans':
493
+ case "plans":
346
494
  plans(targetDir);
347
495
  break;
348
- case 'help':
349
- case '--help':
350
- case '-h':
496
+ case "help":
351
497
  showHelp();
352
498
  break;
353
499
  default:
package/install.sh CHANGED
@@ -1,21 +1,28 @@
1
1
  #!/bin/bash
2
2
  # omkx — Install Script
3
3
  # Installs omkx multi-agent orchestration into the current Kiro project
4
- # Usage: bash install.sh [--force] [--dir <path>]
4
+ # Usage: bash install.sh [--force] [--global] [--dir <path>]
5
5
 
6
6
  set -e
7
7
 
8
8
  FORCE=false
9
+ GLOBAL=false
9
10
  TARGET_DIR="$(pwd)"
10
11
 
11
12
  while [[ $# -gt 0 ]]; do
12
13
  case "$1" in
13
14
  --force) FORCE=true; shift ;;
15
+ --global) GLOBAL=true; shift ;;
14
16
  --dir) TARGET_DIR="$2"; shift 2 ;;
15
17
  *) echo "Unknown option: $1"; exit 1 ;;
16
18
  esac
17
19
  done
18
20
 
21
+ # --global installs to ~/.kiro so agents are available in all projects
22
+ if [ "$GLOBAL" = true ]; then
23
+ TARGET_DIR="$HOME"
24
+ fi
25
+
19
26
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
20
27
  KIRO_DIR="$TARGET_DIR/.kiro"
21
28
 
package/package.json CHANGED
@@ -1,14 +1,34 @@
1
1
  {
2
2
  "name": "omkx",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Multi-agent orchestration for Kiro — agents from oh-my-openagent adapted for the Kiro IDE",
5
- "bin": { "omkx": "bin/cli.mjs" },
6
- "files": ["bin/", ".kiro/", "install.sh"],
5
+ "bin": {
6
+ "omkx": "bin/cli.mjs"
7
+ },
8
+ "files": [
9
+ "bin/",
10
+ ".kiro/",
11
+ "install.sh"
12
+ ],
7
13
  "type": "module",
8
- "keywords": ["kiro", "kiro-cli", "kiro-agents", "ai", "agents", "multi-agent", "orchestration", "oh-my-openagent"],
14
+ "keywords": [
15
+ "kiro",
16
+ "kiro-cli",
17
+ "kiro-agents",
18
+ "ai",
19
+ "agents",
20
+ "multi-agent",
21
+ "orchestration",
22
+ "oh-my-openagent"
23
+ ],
9
24
  "author": "seyisulu",
10
25
  "license": "MIT",
11
- "repository": { "type": "git", "url": "git+https://github.com/seyisulu/omkx.git" },
26
+ "repository": {
27
+ "type": "git",
28
+ "url": "git+https://github.com/seyisulu/omkx.git"
29
+ },
12
30
  "homepage": "https://github.com/seyisulu/omkx#readme",
13
- "engines": { "node": ">=18.0.0" }
31
+ "engines": {
32
+ "node": ">=18.0.0"
33
+ }
14
34
  }