oh-my-githubcopilot 1.4.1 → 1.8.0-alpha.021bf87

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 (123) hide show
  1. package/.claude-plugin/plugin.json +36 -6
  2. package/.mcp.json +17 -0
  3. package/AGENTS.md +78 -9
  4. package/CHANGELOG.md +216 -1
  5. package/README.de.md +112 -26
  6. package/README.es.md +115 -29
  7. package/README.fr.md +114 -28
  8. package/README.it.md +114 -28
  9. package/README.ja.md +112 -26
  10. package/README.ko.md +112 -26
  11. package/README.md +96 -95
  12. package/README.pt.md +116 -30
  13. package/README.ru.md +116 -30
  14. package/README.tr.md +115 -29
  15. package/README.vi.md +116 -30
  16. package/README.zh.md +112 -26
  17. package/agents/analyst.agent.md +27 -0
  18. package/agents/architect.agent.md +24 -0
  19. package/agents/code-reviewer.agent.md +24 -0
  20. package/agents/critic.agent.md +24 -0
  21. package/agents/debugger.agent.md +24 -0
  22. package/agents/designer.agent.md +24 -0
  23. package/agents/document-specialist.agent.md +24 -0
  24. package/agents/executor.agent.md +27 -0
  25. package/agents/explorer.agent.md +23 -0
  26. package/agents/git-master.agent.md +24 -0
  27. package/agents/orchestrator.agent.md +26 -0
  28. package/agents/planner.agent.md +24 -0
  29. package/agents/qa-tester.agent.md +24 -0
  30. package/agents/researcher.agent.md +18 -0
  31. package/agents/reviewer.agent.md +23 -0
  32. package/agents/scientist.agent.md +20 -0
  33. package/agents/security-reviewer.agent.md +20 -0
  34. package/agents/simplifier.agent.md +20 -0
  35. package/agents/test-engineer.agent.md +20 -0
  36. package/agents/tester.agent.md +20 -0
  37. package/agents/tracer.agent.md +24 -0
  38. package/agents/verifier.agent.md +19 -0
  39. package/agents/writer.agent.md +24 -0
  40. package/bin/omp-statusline.mjs +179 -0
  41. package/bin/omp-statusline.mjs.map +7 -0
  42. package/bin/omp-statusline.sh +21 -0
  43. package/bin/omp.mjs +709 -16
  44. package/bin/omp.mjs.map +4 -4
  45. package/dist/hooks/hud-emitter.mjs +268 -82
  46. package/dist/hooks/hud-emitter.mjs.map +4 -4
  47. package/dist/hooks/keyword-detector.mjs +100 -23
  48. package/dist/hooks/keyword-detector.mjs.map +2 -2
  49. package/dist/hooks/model-router.mjs +1 -1
  50. package/dist/hooks/model-router.mjs.map +1 -1
  51. package/dist/hooks/stop-continuation.mjs +1 -1
  52. package/dist/hooks/stop-continuation.mjs.map +1 -1
  53. package/dist/hooks/token-tracker.mjs +2 -1
  54. package/dist/hooks/token-tracker.mjs.map +2 -2
  55. package/dist/mcp/server.mjs +85 -53
  56. package/dist/mcp/server.mjs.map +4 -4
  57. package/dist/skills/setup.mjs +39 -27
  58. package/dist/skills/setup.mjs.map +4 -4
  59. package/hooks/hooks.json +39 -45
  60. package/package.json +9 -4
  61. package/plugin.json +71 -0
  62. package/skills/ai-slop-cleaner/SKILL.md +137 -0
  63. package/skills/autopilot/SKILL.md +6 -0
  64. package/skills/configure-notifications/SKILL.md +6 -0
  65. package/skills/deep-interview/SKILL.md +6 -0
  66. package/skills/doctor/SKILL.md +188 -0
  67. package/skills/ecomode/SKILL.md +6 -0
  68. package/skills/graph-context/SKILL.md +119 -0
  69. package/skills/graph-provider/SKILL.md +6 -0
  70. package/skills/graphify/SKILL.md +6 -0
  71. package/skills/graphwiki/SKILL.md +6 -0
  72. package/skills/hud/SKILL.md +6 -0
  73. package/skills/improve-codebase-architecture/SKILL.md +214 -0
  74. package/skills/interactive-menu/SKILL.md +102 -0
  75. package/skills/interview/SKILL.md +203 -0
  76. package/skills/learner/SKILL.md +6 -0
  77. package/skills/mcp-setup/SKILL.md +6 -0
  78. package/skills/note/SKILL.md +6 -0
  79. package/skills/notifications/SKILL.md +190 -0
  80. package/skills/omp-doctor/SKILL.md +146 -0
  81. package/skills/omp-plan/SKILL.md +219 -2
  82. package/skills/omp-reference/SKILL.md +174 -0
  83. package/skills/omp-setup/SKILL.md +15 -1
  84. package/skills/pipeline/SKILL.md +6 -0
  85. package/skills/psm/SKILL.md +6 -0
  86. package/skills/ralph/SKILL.md +6 -0
  87. package/skills/ralplan/SKILL.md +148 -0
  88. package/skills/release/SKILL.md +6 -0
  89. package/skills/research/SKILL.md +149 -0
  90. package/skills/session/SKILL.md +220 -0
  91. package/skills/setup/SKILL.md +6 -0
  92. package/skills/skillify/SKILL.md +66 -0
  93. package/skills/spending/SKILL.md +6 -0
  94. package/skills/swarm/SKILL.md +6 -0
  95. package/skills/swe-bench/SKILL.md +6 -0
  96. package/skills/tdd/SKILL.md +246 -0
  97. package/skills/team/SKILL.md +6 -0
  98. package/skills/trace/SKILL.md +6 -0
  99. package/skills/ultrawork/SKILL.md +6 -0
  100. package/skills/wiki/SKILL.md +6 -0
  101. package/src/agents/analyst.md +0 -103
  102. package/src/agents/architect.md +0 -169
  103. package/src/agents/code-reviewer.md +0 -135
  104. package/src/agents/critic.md +0 -196
  105. package/src/agents/debugger.md +0 -132
  106. package/src/agents/designer.md +0 -103
  107. package/src/agents/document-specialist.md +0 -111
  108. package/src/agents/executor.md +0 -120
  109. package/src/agents/explorer.md +0 -98
  110. package/src/agents/git-master.md +0 -92
  111. package/src/agents/orchestrator.md +0 -125
  112. package/src/agents/planner.md +0 -106
  113. package/src/agents/qa-tester.md +0 -129
  114. package/src/agents/researcher.md +0 -102
  115. package/src/agents/reviewer.md +0 -100
  116. package/src/agents/scientist.md +0 -150
  117. package/src/agents/security-reviewer.md +0 -132
  118. package/src/agents/simplifier.md +0 -109
  119. package/src/agents/test-engineer.md +0 -124
  120. package/src/agents/tester.md +0 -102
  121. package/src/agents/tracer.md +0 -160
  122. package/src/agents/verifier.md +0 -100
  123. package/src/agents/writer.md +0 -96
package/bin/omp.mjs CHANGED
@@ -1,23 +1,690 @@
1
1
  #!/usr/bin/env node
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __esm = (fn, res) => function __init() {
5
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
6
+ };
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+
12
+ // src/hud/renderer.mts
13
+ function formatAge(startedAt) {
14
+ const elapsed = Date.now() - startedAt;
15
+ const mins = Math.floor(elapsed / 6e4);
16
+ if (mins < 60) return `${mins}m`;
17
+ const hours = Math.floor(mins / 60);
18
+ const remainingMins = mins % 60;
19
+ return `${hours}h${remainingMins}m`;
20
+ }
21
+ function formatTokens(tokens) {
22
+ if (tokens >= 1e6) return `${(tokens / 1e6).toFixed(1)}M`;
23
+ if (tokens >= 1e3) return `${(tokens / 1e3).toFixed(1)}k`;
24
+ return `${tokens}`;
25
+ }
26
+ function ctxColor(pct) {
27
+ if (pct < 60) return "\x1B[32m";
28
+ if (pct < 85) return "\x1B[33m";
29
+ return "\x1B[31m";
30
+ }
31
+ function reset() {
32
+ return "\x1B[0m";
33
+ }
34
+ function renderAnsi(state) {
35
+ const age = formatAge(state.startedAt);
36
+ const tokens = formatTokens(state.tokensUsed);
37
+ const ctx = state.contextPct;
38
+ const mode = state.activeMode || "-";
39
+ const model = state.activeModel || "sonnet";
40
+ const icon = STATUS_ICONS[state.status] || "\u25CF";
41
+ const ctxClr = ctxColor(ctx);
42
+ const ctxStr = `${ctxClr}ctx:${ctx}%${reset()}`;
43
+ const tokenStr = `tok:~${tokens}/${state.tokensTotal}`;
44
+ const modeStr = mode === "-" ? "-" : `\x1B[36m${mode}${reset()}`;
45
+ const reqWarning = state.warningActive ? " !!" : "";
46
+ const reqStr = `req:${state.premiumRequests ?? 0}/${state.premiumRequestsTotal ?? 1500}${reqWarning}`;
47
+ return `[OMP v${state.version}] ${modeStr} | ${model} | ${ctxStr} | ${tokenStr} | ${reqStr} | ${age} | tools:${state.toolsUsed?.size || 0}/${state.toolsTotal ?? 13} | skills:${state.skillsUsed?.size || 0}/${state.skillsTotal ?? 25} | agents:${state.cumulativeAgentsUsed}/${state.agentsTotal ?? 23} | ${icon} ${state.status}`;
48
+ }
49
+ function renderPlain(state) {
50
+ const age = formatAge(state.startedAt);
51
+ const tokens = formatTokens(state.tokensUsed);
52
+ const ctx = state.contextPct;
53
+ const mode = state.activeMode || "-";
54
+ const model = state.activeModel || "sonnet";
55
+ const reqWarningPlain = state.warningActive ? " !!" : "";
56
+ const reqStrPlain = `req:${state.premiumRequests ?? 0}/${state.premiumRequestsTotal ?? 1500}${reqWarningPlain}`;
57
+ return `[OMP v${state.version}] ${mode} | ${model} | ctx:${ctx}% | tok:~${tokens}/${state.tokensTotal} | ${reqStrPlain} | ${age} | tools:${state.toolsUsed?.size || 0}/${state.toolsTotal ?? 13} | skills:${state.skillsUsed?.size || 0}/${state.skillsTotal ?? 25} | agents:${state.cumulativeAgentsUsed}/${state.agentsTotal ?? 23} | ${state.status}`;
58
+ }
59
+ var STATUS_ICONS;
60
+ var init_renderer = __esm({
61
+ "src/hud/renderer.mts"() {
62
+ "use strict";
63
+ STATUS_ICONS = {
64
+ idle: "\u25CB",
65
+ running: "\u25CF",
66
+ waiting: "\u25F7",
67
+ complete: "\u2713",
68
+ error: "\u2717",
69
+ eco: "\u26A1"
70
+ };
71
+ }
72
+ });
73
+
74
+ // src/hud/statusline.mts
75
+ import { mkdirSync, readFileSync, renameSync, writeFileSync } from "fs";
76
+ import { homedir as homedir2 } from "os";
77
+ import { dirname as dirname2, join as join2 } from "path";
78
+ import { fileURLToPath } from "url";
79
+ function getStatuslinePaths(home = process.env["HOME"] || homedir2()) {
80
+ const ompDir = join2(home, ".omp");
81
+ const hudDir = join2(ompDir, "hud");
82
+ return {
83
+ legacyLinePath: join2(ompDir, "hud.line"),
84
+ hudDir,
85
+ statusJsonPath: join2(hudDir, "status.json"),
86
+ displayPath: join2(hudDir, "display.txt"),
87
+ tmuxSegmentPath: join2(hudDir, "tmux-segment.sh")
88
+ };
89
+ }
90
+ function ensureParent(filePath) {
91
+ mkdirSync(dirname2(filePath), { recursive: true });
92
+ }
93
+ function writeAtomic(filePath, content, mode) {
94
+ ensureParent(filePath);
95
+ const tempPath = `${filePath}.tmp`;
96
+ writeFileSync(tempPath, content, mode === void 0 ? "utf-8" : { encoding: "utf-8", mode });
97
+ renameSync(tempPath, filePath);
98
+ }
99
+ function normalizeStringArray(value) {
100
+ if (!Array.isArray(value)) return [];
101
+ return value.filter((item) => typeof item === "string");
102
+ }
103
+ function serializeHudState(state) {
104
+ return {
105
+ ...state,
106
+ toolsUsed: Array.from(state.toolsUsed),
107
+ skillsUsed: Array.from(state.skillsUsed)
108
+ };
109
+ }
110
+ function deserializeHudState(raw) {
111
+ if (!raw || typeof raw !== "object") return null;
112
+ const value = raw;
113
+ const toolsUsed = new Set(normalizeStringArray(value.toolsUsed));
114
+ const skillsUsed = new Set(normalizeStringArray(value.skillsUsed));
115
+ const agentsActive = normalizeStringArray(value.agentsActive);
116
+ const status = typeof value.status === "string" ? value.status : "idle";
117
+ return {
118
+ sessionId: typeof value.sessionId === "string" ? value.sessionId : "default",
119
+ activeMode: typeof value.activeMode === "string" ? value.activeMode : null,
120
+ activeModel: typeof value.activeModel === "string" ? value.activeModel : "sonnet",
121
+ contextPct: typeof value.contextPct === "number" ? value.contextPct : 0,
122
+ tokensUsed: typeof value.tokensUsed === "number" ? value.tokensUsed : 0,
123
+ tokensTotal: typeof value.tokensTotal === "number" ? value.tokensTotal : DEFAULT_TOKEN_BUDGET,
124
+ agentsActive,
125
+ lastAgent: typeof value.lastAgent === "string" ? value.lastAgent : agentsActive.at(-1) ?? "-",
126
+ lastOutput: typeof value.lastOutput === "string" ? value.lastOutput : "",
127
+ taskProgress: typeof value.taskProgress === "number" ? value.taskProgress : 0,
128
+ startedAt: typeof value.startedAt === "number" ? value.startedAt : Date.now(),
129
+ updatedAt: typeof value.updatedAt === "number" ? value.updatedAt : Date.now(),
130
+ version: typeof value.version === "string" ? value.version : DEFAULT_VERSION,
131
+ status,
132
+ sessionDurationMs: typeof value.sessionDurationMs === "number" ? value.sessionDurationMs : 0,
133
+ cumulativeAgentsUsed: typeof value.cumulativeAgentsUsed === "number" ? value.cumulativeAgentsUsed : agentsActive.length,
134
+ toolsUsed,
135
+ skillsUsed,
136
+ toolsTotal: typeof value.toolsTotal === "number" ? value.toolsTotal : 13,
137
+ skillsTotal: typeof value.skillsTotal === "number" ? value.skillsTotal : 25,
138
+ agentsTotal: typeof value.agentsTotal === "number" ? value.agentsTotal : 23,
139
+ premiumRequests: typeof value.premiumRequests === "number" ? value.premiumRequests : 0,
140
+ premiumRequestsTotal: typeof value.premiumRequestsTotal === "number" ? value.premiumRequestsTotal : DEFAULT_PREMIUM_REQUESTS_TOTAL,
141
+ warningActive: typeof value.warningActive === "boolean" ? value.warningActive : false
142
+ };
143
+ }
144
+ function buildHudState(snapshot, now = Date.now()) {
145
+ const startedAt = snapshot.started_at ?? now;
146
+ const updatedAt = snapshot.updated_at ?? now;
147
+ const toolsUsed = new Set(normalizeStringArray(snapshot.tools_used));
148
+ const skillsUsed = new Set(normalizeStringArray(snapshot.skills_used));
149
+ const agentsActive = normalizeStringArray(snapshot.agents_used);
150
+ return {
151
+ sessionId: snapshot.session_id ?? "default",
152
+ activeMode: snapshot.active_mode ?? null,
153
+ activeModel: snapshot.model ?? "sonnet",
154
+ contextPct: snapshot.context_pct ?? 0,
155
+ tokensUsed: snapshot.tokens_estimated ?? 0,
156
+ tokensTotal: snapshot.token_budget ?? DEFAULT_TOKEN_BUDGET,
157
+ agentsActive,
158
+ lastAgent: agentsActive.at(-1) ?? "-",
159
+ lastOutput: snapshot.last_output ?? "",
160
+ taskProgress: snapshot.task_progress ?? 0,
161
+ startedAt,
162
+ updatedAt,
163
+ version: snapshot.version ?? DEFAULT_VERSION,
164
+ status: snapshot.status ?? "idle",
165
+ sessionDurationMs: Math.max(0, updatedAt - startedAt),
166
+ cumulativeAgentsUsed: agentsActive.length,
167
+ toolsUsed,
168
+ skillsUsed,
169
+ toolsTotal: 13,
170
+ skillsTotal: 25,
171
+ agentsTotal: 23,
172
+ premiumRequests: snapshot.premium_requests ?? 0,
173
+ premiumRequestsTotal: snapshot.premium_requests_total ?? DEFAULT_PREMIUM_REQUESTS_TOTAL,
174
+ warningActive: snapshot.warning_active ?? false
175
+ };
176
+ }
177
+ function writeHudArtifacts(snapshot, paths = getStatuslinePaths()) {
178
+ const state = buildHudState(snapshot);
179
+ const line = renderPlain(state);
180
+ const serializedState = `${JSON.stringify(serializeHudState(state), null, 2)}
181
+ `;
182
+ writeAtomic(paths.statusJsonPath, serializedState);
183
+ writeAtomic(paths.displayPath, `${line}
184
+ `);
185
+ writeAtomic(paths.tmuxSegmentPath, `${line}
186
+ `, 493);
187
+ writeAtomic(paths.legacyLinePath, `${line}
188
+ `);
189
+ return { line, state, paths };
190
+ }
191
+ function readStatusline(paths = getStatuslinePaths()) {
192
+ try {
193
+ const line = readFileSync(paths.displayPath, "utf-8").trim();
194
+ if (line) return line;
195
+ } catch {
196
+ }
197
+ try {
198
+ const parsed = JSON.parse(readFileSync(paths.statusJsonPath, "utf-8"));
199
+ const state = deserializeHudState(parsed);
200
+ if (state) return renderPlain(state);
201
+ } catch {
202
+ }
203
+ try {
204
+ const line = readFileSync(paths.legacyLinePath, "utf-8").trim();
205
+ if (line) return line;
206
+ } catch {
207
+ }
208
+ return DEFAULT_STATUSLINE;
209
+ }
210
+ var DEFAULT_VERSION, DEFAULT_STATUSLINE, DEFAULT_TOKEN_BUDGET, DEFAULT_PREMIUM_REQUESTS_TOTAL;
211
+ var init_statusline = __esm({
212
+ "src/hud/statusline.mts"() {
213
+ "use strict";
214
+ init_renderer();
215
+ DEFAULT_VERSION = "0.0.0";
216
+ DEFAULT_STATUSLINE = "OMP | hud: no active session";
217
+ DEFAULT_TOKEN_BUDGET = 2e5;
218
+ DEFAULT_PREMIUM_REQUESTS_TOTAL = 1500;
219
+ if (process.argv[1] === fileURLToPath(import.meta.url)) {
220
+ console.log(readStatusline());
221
+ }
222
+ }
223
+ });
224
+
225
+ // src/hud/watch.mts
226
+ var watch_exports = {};
227
+ __export(watch_exports, {
228
+ runHudWatch: () => runHudWatch
229
+ });
230
+ import { readFileSync as readFileSync2 } from "fs";
231
+ import { homedir as homedir3 } from "os";
232
+ import { join as join3 } from "path";
233
+ function readSnapshot() {
234
+ try {
235
+ const raw = readFileSync2(STATE_PATH, "utf-8");
236
+ const parsed = JSON.parse(raw);
237
+ return parsed;
238
+ } catch {
239
+ return null;
240
+ }
241
+ }
242
+ function tick(paths = getStatuslinePaths()) {
243
+ const snapshot = readSnapshot();
244
+ if (!snapshot) return;
245
+ const now = Date.now();
246
+ const state = buildHudState(snapshot, now);
247
+ writeHudArtifacts(snapshot, paths);
248
+ process.stdout.write("\x1B[2J\x1B[H" + renderAnsi(state) + "\x1B[K\n\x1B[J");
249
+ }
250
+ function runHudWatch() {
251
+ const intervalMs = Math.max(
252
+ 500,
253
+ parseInt(process.env["OMP_HUD_INTERVAL"] ?? "", 10) || DEFAULT_INTERVAL_MS
254
+ );
255
+ const paths = getStatuslinePaths();
256
+ process.stdout.write("\x1B[?25l");
257
+ try {
258
+ tick(paths);
259
+ } catch {
260
+ }
261
+ const timer = setInterval(() => {
262
+ try {
263
+ tick(paths);
264
+ } catch {
265
+ }
266
+ }, intervalMs);
267
+ const stop = () => {
268
+ clearInterval(timer);
269
+ process.stdout.write("\x1B[?25h\x1B[2J\x1B[H");
270
+ process.exit(0);
271
+ };
272
+ process.on("SIGINT", stop);
273
+ process.on("SIGTERM", stop);
274
+ }
275
+ var DEFAULT_INTERVAL_MS, STATE_PATH;
276
+ var init_watch = __esm({
277
+ "src/hud/watch.mts"() {
278
+ "use strict";
279
+ init_statusline();
280
+ init_renderer();
281
+ DEFAULT_INTERVAL_MS = 2e3;
282
+ STATE_PATH = join3(homedir3(), ".omp", "state", "session.json");
283
+ }
284
+ });
285
+
286
+ // src/hooks/keyword-detector.mts
287
+ var keyword_detector_exports = {};
288
+ __export(keyword_detector_exports, {
289
+ processHook: () => processHook
290
+ });
291
+ function detectKeyword(prompt) {
292
+ const trimmed = prompt.trimStart();
293
+ for (const [keyword, skillId] of KEYWORD_ENTRIES) {
294
+ if (trimmed.startsWith(keyword)) {
295
+ return {
296
+ keyword,
297
+ skillId,
298
+ position: 0
299
+ };
300
+ }
301
+ }
302
+ const slashPattern = /^\/((?:omp:)?[a-zA-Z][a-zA-Z0-9-]*)\b/;
303
+ const slashMatch = trimmed.match(slashPattern);
304
+ if (slashMatch) {
305
+ const cmd = slashMatch[1].toLowerCase();
306
+ const skillId = KEYWORD_MAP[`/${cmd}`] ?? KEYWORD_MAP[`${cmd}:`];
307
+ if (skillId) {
308
+ return {
309
+ keyword: slashMatch[0],
310
+ skillId,
311
+ position: 0
312
+ };
313
+ }
314
+ }
315
+ const longNamespacePattern = /^\/?oh-my-githubcopilot:([a-zA-Z][a-zA-Z0-9-]*)\b/i;
316
+ const longNamespaceMatch = trimmed.match(longNamespacePattern);
317
+ if (longNamespaceMatch) {
318
+ const cmd = longNamespaceMatch[1].toLowerCase();
319
+ const skillId = KEYWORD_MAP[`/omp:${cmd}`] ?? KEYWORD_MAP[`/${cmd}`] ?? KEYWORD_MAP[`${cmd}:`];
320
+ if (skillId) {
321
+ return {
322
+ keyword: longNamespaceMatch[0],
323
+ skillId,
324
+ position: 0
325
+ };
326
+ }
327
+ }
328
+ return null;
329
+ }
330
+ function getCanonicalCommand(skillId) {
331
+ return CANONICAL_COMMAND_MAP[skillId] ?? `/omp:${skillId}`;
332
+ }
333
+ function processHook(input) {
334
+ const start = Date.now();
335
+ const log = [];
336
+ try {
337
+ if (input.hook_type !== "UserPromptSubmitted") {
338
+ return {
339
+ status: "skip",
340
+ latencyMs: Date.now() - start,
341
+ mutations: [],
342
+ log: ["Not a UserPromptSubmitted hook"]
343
+ };
344
+ }
345
+ const match = detectKeyword(input.prompt);
346
+ if (!match) {
347
+ return {
348
+ status: "ok",
349
+ latencyMs: Date.now() - start,
350
+ mutations: [],
351
+ log: []
352
+ };
353
+ }
354
+ const taskPart = input.prompt.slice(match.position + match.keyword.length).trim();
355
+ const rewritten = `${getCanonicalCommand(match.skillId)}${taskPart ? ` ${taskPart}` : ""}`;
356
+ log.push(`Keyword detected: "${match.keyword}" \u2192 skill: ${match.skillId}`);
357
+ log.push(`Rewritten: "${rewritten}"`);
358
+ return {
359
+ status: "ok",
360
+ latencyMs: Date.now() - start,
361
+ modifiedPrompt: rewritten,
362
+ mutations: [
363
+ { type: "set_mode", mode: match.skillId },
364
+ { type: "log", level: "info", message: `Skill activated: ${match.skillId}` }
365
+ ],
366
+ log
367
+ };
368
+ } catch (err) {
369
+ return {
370
+ status: "error",
371
+ latencyMs: Date.now() - start,
372
+ mutations: [],
373
+ log: [`Error: ${err}`]
374
+ };
375
+ }
376
+ }
377
+ async function readStdin() {
378
+ const chunks = [];
379
+ for await (const chunk of process.stdin) {
380
+ chunks.push(chunk);
381
+ }
382
+ return chunks.join("");
383
+ }
384
+ var KEYWORD_MAP, KEYWORD_ENTRIES, CANONICAL_COMMAND_MAP;
385
+ var init_keyword_detector = __esm({
386
+ async "src/hooks/keyword-detector.mts"() {
387
+ "use strict";
388
+ KEYWORD_MAP = {
389
+ "autopilot:": "autopilot",
390
+ "/autopilot": "autopilot",
391
+ "/omp:autopilot": "autopilot",
392
+ "ralph:": "ralph",
393
+ "/ralph": "ralph",
394
+ "/omp:ralph": "ralph",
395
+ "ulw:": "ultrawork",
396
+ "ultrawork:": "ultrawork",
397
+ "/ulw": "ultrawork",
398
+ "/ultrawork": "ultrawork",
399
+ "/omp:ulw": "ultrawork",
400
+ "/omp:ultrawork": "ultrawork",
401
+ "team:": "team",
402
+ "/team": "team",
403
+ "/omp:team": "team",
404
+ "eco:": "ecomode",
405
+ "ecomode:": "ecomode",
406
+ "/eco": "ecomode",
407
+ "/ecomode": "ecomode",
408
+ "/omp:eco": "ecomode",
409
+ "/omp:ecomode": "ecomode",
410
+ "swarm:": "swarm",
411
+ "/swarm": "swarm",
412
+ "/omp:swarm": "swarm",
413
+ "pipeline:": "pipeline",
414
+ "/pipeline": "pipeline",
415
+ "/omp:pipeline": "pipeline",
416
+ "deep interview:": "deep-interview",
417
+ "/deep-interview": "deep-interview",
418
+ "/omp:deep-interview": "deep-interview",
419
+ "plan:": "omp-plan",
420
+ "/plan": "omp-plan",
421
+ "/omp-plan": "omp-plan",
422
+ "/omp:plan": "omp-plan",
423
+ "setup:": "omp-setup",
424
+ "/setup": "omp-setup",
425
+ "/omp-setup": "omp-setup",
426
+ "/omp:setup": "omp-setup",
427
+ "mcp:": "mcp-setup",
428
+ "mcp-setup:": "mcp-setup",
429
+ "/mcp": "mcp-setup",
430
+ "/mcp-setup": "mcp-setup",
431
+ "/omp:mcp-setup": "mcp-setup",
432
+ "/hud": "hud",
433
+ "hud:": "hud",
434
+ "/omp:hud": "hud",
435
+ "/wiki": "wiki",
436
+ "wiki:": "wiki",
437
+ "/omp:wiki": "wiki",
438
+ "/learner": "learner",
439
+ "learner:": "learner",
440
+ "/omp:learner": "learner",
441
+ "/note": "note",
442
+ "note:": "note",
443
+ "/omp:note": "note",
444
+ "/trace": "trace",
445
+ "trace:": "trace",
446
+ "/omp:trace": "trace",
447
+ "/release": "release",
448
+ "release:": "release",
449
+ "/omp:release": "release",
450
+ "/configure-notifications": "configure-notifications",
451
+ "configure-notifications:": "configure-notifications",
452
+ "/omp:configure-notifications": "configure-notifications",
453
+ "/psm": "psm",
454
+ "psm:": "psm",
455
+ "/omp:psm": "psm",
456
+ "/swe-bench": "swe-bench",
457
+ "swe-bench:": "swe-bench",
458
+ "/omp:swe-bench": "swe-bench",
459
+ "graphify:": "graphify",
460
+ "graph build": "graphify",
461
+ "build graph": "graphify",
462
+ "graphwiki:": "graphwiki",
463
+ "graph:": "graph-provider",
464
+ "spending:": "spending",
465
+ "/graphify": "graphify",
466
+ "/omp:graphify": "graphify",
467
+ "/graphwiki": "graphwiki",
468
+ "/omp:graphwiki": "graphwiki",
469
+ "/graph-provider": "graph-provider",
470
+ "/omp:graph-provider": "graph-provider",
471
+ "/spending": "spending",
472
+ "/omp:spending": "spending",
473
+ "--consensus": "omp-plan",
474
+ "/omp:omp-doctor": "omp-doctor",
475
+ "/omp:ralplan": "ralplan",
476
+ "/omp:research": "research",
477
+ "doctor:": "doctor",
478
+ "/doctor": "doctor",
479
+ "/omp:doctor": "doctor",
480
+ "interview:": "interview",
481
+ "/interview": "interview",
482
+ "/omp:interview": "interview",
483
+ "notifications:": "notifications",
484
+ "/notifications": "notifications",
485
+ "/omp:notifications": "notifications",
486
+ "session:": "session",
487
+ "/session": "session",
488
+ "/omp:session": "session"
489
+ };
490
+ KEYWORD_ENTRIES = Object.entries(KEYWORD_MAP).sort(([a], [b]) => b.length - a.length);
491
+ CANONICAL_COMMAND_MAP = {
492
+ "omp-plan": "/omp:plan",
493
+ "omp-setup": "/setup",
494
+ "mcp-setup": "/mcp"
495
+ };
496
+ if (process.argv[1]?.endsWith("keyword-detector.mjs") || process.argv[1]?.endsWith("keyword-detector.mts")) {
497
+ const input = JSON.parse(await readStdin());
498
+ const output = processHook(input);
499
+ console.log(JSON.stringify(output));
500
+ }
501
+ }
502
+ });
2
503
 
3
504
  // src/index.mts
4
505
  import { parseArgs } from "util";
5
506
  import { createRequire } from "module";
507
+
508
+ // src/cli/update.mts
509
+ import { spawnSync } from "child_process";
510
+ import { mkdir, readFile, writeFile } from "fs/promises";
511
+ import { homedir } from "os";
512
+ import { dirname, join } from "path";
513
+ import { createInterface } from "node:readline/promises";
514
+ var CHECK_INTERVAL_MS = 12 * 60 * 60 * 1e3;
515
+ var PROMPTABLE_SUBCOMMANDS = /* @__PURE__ */ new Set(["hud", "psm", "bench"]);
516
+ var DISABLED_AUTO_UPDATE_VALUES = /* @__PURE__ */ new Set(["0", "false", "no", "off"]);
517
+ var ENABLED_DISABLE_FLAG_VALUES = /* @__PURE__ */ new Set(["1", "true", "yes", "on"]);
518
+ function parseSemver(version) {
519
+ const match = version.trim().match(/^v?(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?$/);
520
+ if (!match) return null;
521
+ return {
522
+ major: Number(match[1]),
523
+ minor: Number(match[2]),
524
+ patch: Number(match[3]),
525
+ prerelease: match[4] ?? null
526
+ };
527
+ }
528
+ function isNewerVersion(current, latest) {
529
+ const currentVersion = parseSemver(current);
530
+ const latestVersion = parseSemver(latest);
531
+ if (!currentVersion || !latestVersion) return false;
532
+ if (latestVersion.major !== currentVersion.major) return latestVersion.major > currentVersion.major;
533
+ if (latestVersion.minor !== currentVersion.minor) return latestVersion.minor > currentVersion.minor;
534
+ if (latestVersion.patch !== currentVersion.patch) return latestVersion.patch > currentVersion.patch;
535
+ if (currentVersion.prerelease && !latestVersion.prerelease) return true;
536
+ return false;
537
+ }
538
+ function shouldCheckForUpdates(nowMs, state, intervalMs = CHECK_INTERVAL_MS) {
539
+ if (!state?.last_checked_at) return true;
540
+ const lastCheckedAt = Date.parse(state.last_checked_at);
541
+ if (!Number.isFinite(lastCheckedAt)) return true;
542
+ return nowMs - lastCheckedAt >= intervalMs;
543
+ }
544
+ function isAutoUpdateDisabled(env = process.env) {
545
+ const autoUpdate = env["OMP_AUTO_UPDATE"]?.trim().toLowerCase();
546
+ if (autoUpdate && DISABLED_AUTO_UPDATE_VALUES.has(autoUpdate)) return true;
547
+ const disableCheck = env["OMP_DISABLE_UPDATE_CHECK"]?.trim().toLowerCase();
548
+ if (disableCheck && ENABLED_DISABLE_FLAG_VALUES.has(disableCheck)) return true;
549
+ return false;
550
+ }
551
+ function shouldSkipUpdatePrompt(subcommand2, flags2 = {}) {
552
+ if (flags2.help || flags2.version) return true;
553
+ return !PROMPTABLE_SUBCOMMANDS.has(subcommand2);
554
+ }
555
+ function updateStatePath(homeDir) {
556
+ return join(homeDir, ".omp", "state", "update-check.json");
557
+ }
558
+ async function readCachedUpdateState(statePath) {
559
+ try {
560
+ const raw = await readFile(statePath, "utf-8");
561
+ return JSON.parse(raw);
562
+ } catch {
563
+ return null;
564
+ }
565
+ }
566
+ async function writeCachedUpdateState(statePath, state) {
567
+ await mkdir(dirname(statePath), { recursive: true });
568
+ await writeFile(statePath, JSON.stringify(state, null, 2), "utf-8");
569
+ }
570
+ async function fetchLatestVersionFromNpm(packageName, timeoutMs = 3500) {
571
+ const controller = new AbortController();
572
+ const timeout = setTimeout(() => controller.abort(), timeoutMs);
573
+ try {
574
+ const url = `https://registry.npmjs.org/${encodeURIComponent(packageName)}/latest`;
575
+ const response = await fetch(url, { signal: controller.signal });
576
+ if (!response.ok) return null;
577
+ const payload = await response.json();
578
+ return typeof payload.version === "string" ? payload.version : null;
579
+ } catch {
580
+ return null;
581
+ } finally {
582
+ clearTimeout(timeout);
583
+ }
584
+ }
585
+ function runNpmGlobalUpdate(packageName, cwd) {
586
+ const result = spawnSync("npm", ["install", "-g", `${packageName}@latest`], {
587
+ encoding: "utf-8",
588
+ stdio: ["ignore", "ignore", "pipe"],
589
+ timeout: 12e4,
590
+ windowsHide: true,
591
+ cwd
592
+ });
593
+ if (result.error) return { ok: false, stderr: result.error.message };
594
+ if (result.status !== 0) {
595
+ return { ok: false, stderr: (result.stderr || "").trim() || `npm exited ${result.status}` };
596
+ }
597
+ return { ok: true, stderr: "" };
598
+ }
599
+ async function askYesNo(question) {
600
+ if (!process.stdin.isTTY || !process.stdout.isTTY) return false;
601
+ const readline = createInterface({ input: process.stdin, output: process.stdout });
602
+ try {
603
+ const answer = (await readline.question(question)).trim().toLowerCase();
604
+ return answer === "" || answer === "y" || answer === "yes";
605
+ } finally {
606
+ readline.close();
607
+ }
608
+ }
609
+ var defaultDependencies = {
610
+ nowMs: () => Date.now(),
611
+ readUpdateState: readCachedUpdateState,
612
+ writeUpdateState: writeCachedUpdateState,
613
+ fetchLatestVersion: fetchLatestVersionFromNpm,
614
+ askYesNo,
615
+ runGlobalUpdate: runNpmGlobalUpdate
616
+ };
617
+ async function maybeCheckAndPromptUpdate(context, dependencies = {}) {
618
+ const updateDependencies = {
619
+ ...defaultDependencies,
620
+ ...dependencies
621
+ };
622
+ try {
623
+ if (isAutoUpdateDisabled()) return;
624
+ if (!process.stdin.isTTY || !process.stdout.isTTY) return;
625
+ if (shouldSkipUpdatePrompt(context.subcommand, context.flags)) return;
626
+ const statePath = updateStatePath(process.env["HOME"] || homedir());
627
+ const now = updateDependencies.nowMs();
628
+ const state = await updateDependencies.readUpdateState(statePath);
629
+ if (!shouldCheckForUpdates(now, state)) return;
630
+ const latestVersion = await updateDependencies.fetchLatestVersion(context.packageName);
631
+ await updateDependencies.writeUpdateState(statePath, {
632
+ last_checked_at: new Date(now).toISOString(),
633
+ last_seen_latest: latestVersion || state?.last_seen_latest
634
+ });
635
+ if (!latestVersion || !isNewerVersion(context.currentVersion, latestVersion)) return;
636
+ const approved = await updateDependencies.askYesNo(
637
+ `[omp] Update available: v${context.currentVersion} \u2192 v${latestVersion}. Update now? [Y/n] `
638
+ );
639
+ if (!approved) return;
640
+ console.log(`[omp] Running: npm install -g ${context.packageName}@latest`);
641
+ const result = updateDependencies.runGlobalUpdate(context.packageName, context.cwd);
642
+ if (result.ok) {
643
+ console.log(`[omp] Updated to v${latestVersion}. Restart this shell to load the new CLI.`);
644
+ } else {
645
+ console.log(`[omp] Update failed. Run manually: npm install -g ${context.packageName}@latest`);
646
+ }
647
+ } catch {
648
+ }
649
+ }
650
+
651
+ // src/index.mts
6
652
  var _require = createRequire(import.meta.url);
7
653
  var { version: PKG_VERSION, name: PKG_NAME } = _require("../package.json");
8
- var { positionals } = parseArgs({
654
+ var { positionals, values: flags } = parseArgs({
9
655
  args: process.argv.slice(2),
10
656
  options: {
11
657
  help: { type: "boolean", default: false },
12
- version: { type: "boolean", default: false }
658
+ version: { type: "boolean", default: false },
659
+ watch: { type: "boolean", default: false }
13
660
  },
14
661
  allowPositionals: true
15
662
  });
16
663
  var subcommand = positionals[0] || "hud";
664
+ var resolvedSubcommand = flags.version && !positionals[0] ? "version" : subcommand;
17
665
  async function main() {
18
- switch (subcommand) {
666
+ if (flags.help) {
667
+ printUsage();
668
+ return;
669
+ }
670
+ await maybeCheckAndPromptUpdate({
671
+ cwd: process.cwd(),
672
+ packageName: PKG_NAME,
673
+ currentVersion: PKG_VERSION,
674
+ subcommand: resolvedSubcommand,
675
+ flags: {
676
+ help: flags.help,
677
+ version: flags.version
678
+ }
679
+ });
680
+ switch (resolvedSubcommand) {
19
681
  case "hud":
20
- await printHud();
682
+ if (flags.watch) {
683
+ const { runHudWatch: runHudWatch2 } = await Promise.resolve().then(() => (init_watch(), watch_exports));
684
+ runHudWatch2();
685
+ } else {
686
+ await printHud();
687
+ }
21
688
  break;
22
689
  case "version":
23
690
  console.log(`${PKG_NAME} v${PKG_VERSION}`);
@@ -28,19 +695,26 @@ async function main() {
28
695
  case "bench":
29
696
  await runBench(positionals.slice(1));
30
697
  break;
698
+ case "hook":
699
+ await runHook(positionals.slice(1));
700
+ break;
31
701
  default:
32
- console.error(`Unknown subcommand: ${subcommand}`);
33
- console.error("Usage: omp [hud|version|psm|bench]");
702
+ console.error(`Unknown subcommand: ${resolvedSubcommand}`);
703
+ printUsage(true);
34
704
  process.exit(1);
35
705
  }
36
706
  }
707
+ function printUsage(stderr = false) {
708
+ const output = stderr ? console.error : console.log;
709
+ output("Usage: omp [hud|version|psm|bench|hook] [--watch]");
710
+ }
37
711
  async function printHud() {
38
712
  try {
39
- const { readFileSync } = await import("fs");
40
- const { join } = await import("path");
41
- const { homedir } = await import("os");
42
- const hudPath = join(homedir(), ".omp", "hud.line");
43
- const line = readFileSync(hudPath, "utf-8").trim();
713
+ const { readFileSync: readFileSync3 } = await import("fs");
714
+ const { join: join4 } = await import("path");
715
+ const { homedir: homedir4 } = await import("os");
716
+ const hudPath = join4(homedir4(), ".omp", "hud.line");
717
+ const line = readFileSync3(hudPath, "utf-8").trim();
44
718
  console.log(line);
45
719
  } catch {
46
720
  console.log(`OMP v${PKG_VERSION} | hud: no active session`);
@@ -48,14 +722,33 @@ async function printHud() {
48
722
  }
49
723
  async function runPsm(_args) {
50
724
  console.log("PSM commands:");
51
- console.log(" /oh-my-githubcopilot:psm create <name> Create isolated worktree session");
52
- console.log(" /oh-my-githubcopilot:psm list List active sessions");
53
- console.log(" /oh-my-githubcopilot:psm switch <name> Switch to session");
54
- console.log(" /oh-my-githubcopilot:psm destroy <name> Destroy session");
725
+ console.log(" /omp:psm create <name> Create isolated worktree session");
726
+ console.log(" /omp:psm list List active sessions");
727
+ console.log(" /omp:psm switch <name> Switch to session");
728
+ console.log(" /omp:psm destroy <name> Destroy session");
729
+ }
730
+ async function runHook(args) {
731
+ const hookId = args[0];
732
+ if (hookId !== "keyword-detector") {
733
+ console.error("Usage: omp hook keyword-detector");
734
+ process.exit(1);
735
+ }
736
+ const { processHook: processHook2 } = await init_keyword_detector().then(() => keyword_detector_exports);
737
+ const inputText = await readStdin2();
738
+ const input = JSON.parse(inputText || "{}");
739
+ const output = processHook2(input);
740
+ console.log(JSON.stringify(output));
741
+ }
742
+ async function readStdin2() {
743
+ const chunks = [];
744
+ for await (const chunk of process.stdin) {
745
+ chunks.push(String(chunk));
746
+ }
747
+ return chunks.join("");
55
748
  }
56
749
  async function runBench(_args) {
57
750
  console.log("SWE-bench requires Node.js subprocess with Python evaluation harness.");
58
- console.log("Usage: /oh-my-githubcopilot:swe-bench --suite lite --compare baseline");
751
+ console.log("Usage: /omp:swe-bench --suite lite --compare baseline");
59
752
  }
60
753
  main().catch((err) => {
61
754
  console.error(err);