oh-my-githubcopilot 1.5.7 → 1.8.0-alpha.afa30a7
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/.claude-plugin/plugin.json +27 -5
- package/AGENTS.md +78 -9
- package/CHANGELOG.md +92 -0
- package/README.de.md +112 -26
- package/README.es.md +115 -29
- package/README.fr.md +114 -28
- package/README.it.md +114 -28
- package/README.ja.md +112 -26
- package/README.ko.md +112 -26
- package/README.md +96 -175
- package/README.pt.md +116 -30
- package/README.ru.md +116 -30
- package/README.tr.md +115 -29
- package/README.vi.md +116 -30
- package/README.zh.md +112 -26
- package/bin/omp.mjs +423 -19
- package/bin/omp.mjs.map +4 -4
- package/dist/hooks/keyword-detector.mjs +18 -3
- package/dist/hooks/keyword-detector.mjs.map +2 -2
- package/dist/mcp/server.mjs +28 -12
- package/dist/mcp/server.mjs.map +2 -2
- package/hooks/hooks.json +1 -1
- package/package.json +5 -4
- package/plugin.json +27 -5
- package/skills/ai-slop-cleaner/SKILL.md +137 -0
- package/skills/doctor/SKILL.md +188 -0
- package/skills/graph-context/SKILL.md +119 -0
- package/skills/improve-codebase-architecture/SKILL.md +214 -0
- package/skills/interactive-menu/SKILL.md +102 -0
- package/skills/interview/SKILL.md +203 -0
- package/skills/notifications/SKILL.md +190 -0
- package/skills/omp-doctor/SKILL.md +146 -0
- package/skills/omp-plan/SKILL.md +215 -4
- package/skills/omp-reference/SKILL.md +174 -0
- package/skills/ralplan/SKILL.md +148 -0
- package/skills/research/SKILL.md +149 -0
- package/skills/session/SKILL.md +220 -0
- package/skills/skillify/SKILL.md +66 -0
- package/skills/tdd/SKILL.md +246 -0
package/bin/omp.mjs
CHANGED
|
@@ -73,22 +73,22 @@ var init_renderer = __esm({
|
|
|
73
73
|
|
|
74
74
|
// src/hud/statusline.mts
|
|
75
75
|
import { mkdirSync, readFileSync, renameSync, writeFileSync } from "fs";
|
|
76
|
-
import { homedir } from "os";
|
|
77
|
-
import { dirname, join } from "path";
|
|
76
|
+
import { homedir as homedir2 } from "os";
|
|
77
|
+
import { dirname as dirname2, join as join2 } from "path";
|
|
78
78
|
import { fileURLToPath } from "url";
|
|
79
|
-
function getStatuslinePaths(home = process.env["HOME"] ||
|
|
80
|
-
const ompDir =
|
|
81
|
-
const hudDir =
|
|
79
|
+
function getStatuslinePaths(home = process.env["HOME"] || homedir2()) {
|
|
80
|
+
const ompDir = join2(home, ".omp");
|
|
81
|
+
const hudDir = join2(ompDir, "hud");
|
|
82
82
|
return {
|
|
83
|
-
legacyLinePath:
|
|
83
|
+
legacyLinePath: join2(ompDir, "hud.line"),
|
|
84
84
|
hudDir,
|
|
85
|
-
statusJsonPath:
|
|
86
|
-
displayPath:
|
|
87
|
-
tmuxSegmentPath:
|
|
85
|
+
statusJsonPath: join2(hudDir, "status.json"),
|
|
86
|
+
displayPath: join2(hudDir, "display.txt"),
|
|
87
|
+
tmuxSegmentPath: join2(hudDir, "tmux-segment.sh")
|
|
88
88
|
};
|
|
89
89
|
}
|
|
90
90
|
function ensureParent(filePath) {
|
|
91
|
-
mkdirSync(
|
|
91
|
+
mkdirSync(dirname2(filePath), { recursive: true });
|
|
92
92
|
}
|
|
93
93
|
function writeAtomic(filePath, content, mode) {
|
|
94
94
|
ensureParent(filePath);
|
|
@@ -228,8 +228,8 @@ __export(watch_exports, {
|
|
|
228
228
|
runHudWatch: () => runHudWatch
|
|
229
229
|
});
|
|
230
230
|
import { readFileSync as readFileSync2 } from "fs";
|
|
231
|
-
import { homedir as
|
|
232
|
-
import { join as
|
|
231
|
+
import { homedir as homedir3 } from "os";
|
|
232
|
+
import { join as join3 } from "path";
|
|
233
233
|
function readSnapshot() {
|
|
234
234
|
try {
|
|
235
235
|
const raw = readFileSync2(STATE_PATH, "utf-8");
|
|
@@ -279,13 +279,376 @@ var init_watch = __esm({
|
|
|
279
279
|
init_statusline();
|
|
280
280
|
init_renderer();
|
|
281
281
|
DEFAULT_INTERVAL_MS = 2e3;
|
|
282
|
-
STATE_PATH =
|
|
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
|
+
}
|
|
283
501
|
}
|
|
284
502
|
});
|
|
285
503
|
|
|
286
504
|
// src/index.mts
|
|
287
505
|
import { parseArgs } from "util";
|
|
288
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
|
|
289
652
|
var _require = createRequire(import.meta.url);
|
|
290
653
|
var { version: PKG_VERSION, name: PKG_NAME } = _require("../package.json");
|
|
291
654
|
var { positionals, values: flags } = parseArgs({
|
|
@@ -298,8 +661,23 @@ var { positionals, values: flags } = parseArgs({
|
|
|
298
661
|
allowPositionals: true
|
|
299
662
|
});
|
|
300
663
|
var subcommand = positionals[0] || "hud";
|
|
664
|
+
var resolvedSubcommand = flags.version && !positionals[0] ? "version" : subcommand;
|
|
301
665
|
async function main() {
|
|
302
|
-
|
|
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) {
|
|
303
681
|
case "hud":
|
|
304
682
|
if (flags.watch) {
|
|
305
683
|
const { runHudWatch: runHudWatch2 } = await Promise.resolve().then(() => (init_watch(), watch_exports));
|
|
@@ -317,18 +695,25 @@ async function main() {
|
|
|
317
695
|
case "bench":
|
|
318
696
|
await runBench(positionals.slice(1));
|
|
319
697
|
break;
|
|
698
|
+
case "hook":
|
|
699
|
+
await runHook(positionals.slice(1));
|
|
700
|
+
break;
|
|
320
701
|
default:
|
|
321
|
-
console.error(`Unknown subcommand: ${
|
|
322
|
-
|
|
702
|
+
console.error(`Unknown subcommand: ${resolvedSubcommand}`);
|
|
703
|
+
printUsage(true);
|
|
323
704
|
process.exit(1);
|
|
324
705
|
}
|
|
325
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
|
+
}
|
|
326
711
|
async function printHud() {
|
|
327
712
|
try {
|
|
328
713
|
const { readFileSync: readFileSync3 } = await import("fs");
|
|
329
|
-
const { join:
|
|
330
|
-
const { homedir:
|
|
331
|
-
const hudPath =
|
|
714
|
+
const { join: join4 } = await import("path");
|
|
715
|
+
const { homedir: homedir4 } = await import("os");
|
|
716
|
+
const hudPath = join4(homedir4(), ".omp", "hud.line");
|
|
332
717
|
const line = readFileSync3(hudPath, "utf-8").trim();
|
|
333
718
|
console.log(line);
|
|
334
719
|
} catch {
|
|
@@ -342,6 +727,25 @@ async function runPsm(_args) {
|
|
|
342
727
|
console.log(" /omp:psm switch <name> Switch to session");
|
|
343
728
|
console.log(" /omp:psm destroy <name> Destroy session");
|
|
344
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("");
|
|
748
|
+
}
|
|
345
749
|
async function runBench(_args) {
|
|
346
750
|
console.log("SWE-bench requires Node.js subprocess with Python evaluation harness.");
|
|
347
751
|
console.log("Usage: /omp:swe-bench --suite lite --compare baseline");
|