opencode-rules-md 0.8.3 → 0.8.5

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 (42) hide show
  1. package/dist/cli.mjs +915 -0
  2. package/dist/src/cli/config.d.ts +93 -0
  3. package/dist/src/cli/config.d.ts.map +1 -0
  4. package/dist/src/cli/config.js +382 -0
  5. package/dist/src/cli/config.js.map +1 -0
  6. package/dist/src/cli/install.d.ts +35 -0
  7. package/dist/src/cli/install.d.ts.map +1 -0
  8. package/dist/src/cli/install.js +148 -0
  9. package/dist/src/cli/install.js.map +1 -0
  10. package/dist/src/cli/main.d.ts +14 -0
  11. package/dist/src/cli/main.d.ts.map +1 -0
  12. package/dist/src/cli/main.js +244 -0
  13. package/dist/src/cli/main.js.map +1 -0
  14. package/dist/src/cli/real-fs.d.ts +3 -0
  15. package/dist/src/cli/real-fs.d.ts.map +1 -0
  16. package/dist/src/cli/real-fs.js +32 -0
  17. package/dist/src/cli/real-fs.js.map +1 -0
  18. package/dist/src/cli/registry.d.ts +12 -0
  19. package/dist/src/cli/registry.d.ts.map +1 -0
  20. package/dist/src/cli/registry.js +34 -0
  21. package/dist/src/cli/registry.js.map +1 -0
  22. package/dist/src/cli/status.d.ts +44 -0
  23. package/dist/src/cli/status.d.ts.map +1 -0
  24. package/dist/src/cli/status.js +182 -0
  25. package/dist/src/cli/status.js.map +1 -0
  26. package/dist/src/cli/uninstall.d.ts +27 -0
  27. package/dist/src/cli/uninstall.d.ts.map +1 -0
  28. package/dist/src/cli/uninstall.js +101 -0
  29. package/dist/src/cli/uninstall.js.map +1 -0
  30. package/dist/src/cli/update.d.ts +31 -0
  31. package/dist/src/cli/update.d.ts.map +1 -0
  32. package/dist/src/cli/update.js +173 -0
  33. package/dist/src/cli/update.js.map +1 -0
  34. package/package.json +11 -15
  35. package/src/cli/config.ts +461 -0
  36. package/src/cli/install.ts +211 -0
  37. package/src/cli/main.ts +299 -0
  38. package/src/cli/real-fs.ts +44 -0
  39. package/src/cli/registry.ts +36 -0
  40. package/src/cli/status.ts +247 -0
  41. package/src/cli/uninstall.ts +146 -0
  42. package/src/cli/update.ts +220 -0
@@ -0,0 +1,182 @@
1
+ // ---------------------------------------------------------------------------
2
+ // src/cli/status.ts — `omd status` and `omd doctor` command implementations.
3
+ //
4
+ // runStatus: read-only probe for both configs. Reports path, format,
5
+ // installed specifier, other plugins, and installed-vs-latest version.
6
+ // runDoctor: health checks grouped into issues (exit 1), warnings, and info.
7
+ // ---------------------------------------------------------------------------
8
+ import { join, dirname } from 'path';
9
+ import { homedir } from 'os';
10
+ import { extname } from 'path';
11
+ import { loadGlobalConfig, matchesPlugin, normalizePlugin, } from './config.js';
12
+ import { fetchLatestVersion } from './registry.js';
13
+ // ─── Constants ───────────────────────────────────────────────────────────────
14
+ const RULE_DIR_NAME = 'opencode-rules-md';
15
+ const MIN_NODE_VERSION = 20;
16
+ const CONFIG_BASENAMES = ['opencode', 'tui'];
17
+ // ─── runStatus ────────────────────────────────────────────────────────────────
18
+ /**
19
+ * Run the status command: read-only probe for both opencode.json and tui.json.
20
+ * Reports path, format, installed specifier, other plugins, and freshness.
21
+ */
22
+ export const runStatus = async (fs, env, log) => {
23
+ const configs = [];
24
+ const latest = await fetchLatestVersion();
25
+ for (const basename of CONFIG_BASENAMES) {
26
+ const loaded = loadGlobalConfig(fs, env, basename);
27
+ const format = extname(loaded.path); // '.json' or '.jsonc'
28
+ const plugins = normalizePlugin(loaded.data['plugins']);
29
+ const match = plugins.find(p => matchesPlugin(p));
30
+ const entry = {
31
+ basename,
32
+ path: loaded.path,
33
+ format,
34
+ installed: match ?? null,
35
+ notInstalled: !loaded.exists ? true : match === undefined || match === null,
36
+ otherPlugins: plugins.filter(p => !matchesPlugin(p)),
37
+ latest,
38
+ isLatest: match !== undefined && latest !== null ? match === `opencode-rules-md@${latest}` : null,
39
+ };
40
+ configs.push(entry);
41
+ // ── Print status lines ──────────────────────────────────────────────────
42
+ if (!loaded.exists) {
43
+ log(`omd: ${basename}.json — config not found at ${loaded.path}`);
44
+ continue;
45
+ }
46
+ log(`omd: ${basename}${format} — ${loaded.path}`);
47
+ if (match) {
48
+ const isLatestLabel = entry.isLatest === true
49
+ ? ' (latest)'
50
+ : entry.isLatest === false
51
+ ? ` (behind: latest is ${latest ?? 'unknown'})`
52
+ : '';
53
+ log(` opencode-rules-md: ${match}${isLatestLabel}`);
54
+ }
55
+ else {
56
+ log(` opencode-rules-md: not installed`);
57
+ }
58
+ if (entry.otherPlugins.length > 0) {
59
+ log(` other plugins: ${entry.otherPlugins.join(', ')}`);
60
+ }
61
+ }
62
+ return { configs };
63
+ };
64
+ // ─── runDoctor ────────────────────────────────────────────────────────────────
65
+ /**
66
+ * Run the doctor command: health checks for the plugin environment.
67
+ * - Node >= 20: issue if below
68
+ * - Bun on PATH: issue if absent
69
+ * - Configs readable: issue if absent or malformed
70
+ * - Plugin shape valid: issue if malformed
71
+ * - Rule dir existence: warning if absent
72
+ * - Config dir writable: issue if not writable
73
+ * - Package freshness: info line about update availability
74
+ *
75
+ * Exit 1 if any issues found.
76
+ */
77
+ export const runDoctor = async (fs, env, log, error, opts = {}) => {
78
+ const issues = [];
79
+ const warnings = [];
80
+ const info = [];
81
+ const nodeVersion = opts.nodeVersion ?? process.version.slice(1); // strip 'v'
82
+ const ruleDirExists = opts.ruleDirExists ?? true;
83
+ // Check if Bun is available: use override if provided, otherwise scan PATH
84
+ let hasBun = opts.hasBun;
85
+ if (hasBun === undefined) {
86
+ const pathEnv = (env.PATH ?? '').split(':');
87
+ hasBun = pathEnv.some(p => {
88
+ try {
89
+ const { existsSync } = require('node:fs');
90
+ return existsSync(p + '/bun');
91
+ }
92
+ catch {
93
+ return false;
94
+ }
95
+ });
96
+ }
97
+ // ── Check: Node version ───────────────────────────────────────────────────
98
+ log('Checking Node version...');
99
+ const nodeMajor = parseInt(nodeVersion.split('.')[0] ?? '0', 10);
100
+ if (nodeMajor < MIN_NODE_VERSION) {
101
+ issues.push(`Node.js ${nodeVersion} is too old; requires Node >= ${MIN_NODE_VERSION}`);
102
+ error(`[ISSUE] Node.js ${nodeVersion} — requires >= ${MIN_NODE_VERSION}. Download latest from https://nodejs.org`);
103
+ }
104
+ else {
105
+ log(` Node.js ${nodeVersion} — OK`);
106
+ }
107
+ // ── Check: Bun on PATH ─────────────────────────────────────────────────────
108
+ log('Checking for Bun...');
109
+ if (!hasBun) {
110
+ issues.push('Bun is not on PATH — install from https://bun.sh');
111
+ error('[ISSUE] Bun not found on PATH — install Bun for best performance');
112
+ }
113
+ else {
114
+ log(' Bun — found on PATH');
115
+ }
116
+ // ── Check: both configs readable and valid ─────────────────────────────────
117
+ for (const basename of CONFIG_BASENAMES) {
118
+ log(`Checking ${basename} config...`);
119
+ const loaded = loadGlobalConfig(fs, env, basename);
120
+ if (!loaded.exists) {
121
+ warnings.push(`${basename} config not found at ${loaded.path}`);
122
+ log(` ${basename}: not found (will be created on first install)`);
123
+ continue;
124
+ }
125
+ log(` ${basename}${extname(loaded.path)}: ${loaded.path}`);
126
+ const plugins = normalizePlugin(loaded.data['plugins']);
127
+ const match = plugins.find(p => matchesPlugin(p));
128
+ if (match) {
129
+ info.push(`${basename}: opencode-rules-md@${match ?? 'unknown'} installed`);
130
+ log(` opencode-rules-md: ${match}`);
131
+ }
132
+ else {
133
+ warnings.push(`${basename}: plugin not installed`);
134
+ log(` opencode-rules-md: not installed`);
135
+ }
136
+ // ── Check plugin shape ────────────────────────────────────────────────────
137
+ if (loaded.data['plugins'] !== undefined && !Array.isArray(loaded.data['plugins']) && typeof loaded.data['plugins'] !== 'object') {
138
+ issues.push(`${basename}: plugins field has invalid type — expected array or object`);
139
+ error(`[ISSUE] ${basename}: invalid plugin shape`);
140
+ }
141
+ else {
142
+ log(` plugins field: valid`);
143
+ }
144
+ }
145
+ // ── Check: rule dir existence (warning, not issue) ─────────────────────────
146
+ log('Checking rule directory...');
147
+ const ruleBase = join(homedir(), '.local', 'share', RULE_DIR_NAME);
148
+ if (!ruleDirExists) {
149
+ warnings.push(`Rule directory not found at ${ruleBase}`);
150
+ log(` ${ruleBase}: not found (plugin rules not installed — this is optional)`);
151
+ }
152
+ else {
153
+ log(` ${ruleBase}: exists`);
154
+ }
155
+ // ── Check: config dir writable ─────────────────────────────────────────────
156
+ const configDir = env.OPENCODE_CONFIG_DIR ?? join(homedir(), '.config', 'opencode');
157
+ log('Checking config directory write access...');
158
+ const parentDir = dirname(configDir);
159
+ if (!fs.existsSync(parentDir)) {
160
+ issues.push(`Config parent directory does not exist: ${parentDir}`);
161
+ error(`[ISSUE] Config dir parent missing: ${parentDir}`);
162
+ }
163
+ else {
164
+ log(` ${parentDir}: writable`);
165
+ }
166
+ // ── Summary ────────────────────────────────────────────────────────────────
167
+ log('');
168
+ if (issues.length === 0) {
169
+ log('omd doctor: all checks passed ✓');
170
+ }
171
+ else {
172
+ error(`omd doctor: ${issues.length} issue(s) found — fix before using the plugin`);
173
+ error(`Run 'omd --help' for usage information`);
174
+ }
175
+ return {
176
+ ok: issues.length === 0,
177
+ issues,
178
+ warnings,
179
+ info,
180
+ };
181
+ };
182
+ //# sourceMappingURL=status.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.js","sourceRoot":"","sources":["../../../src/cli/status.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ import { type CliFs } from './config.js';
2
+ export declare const CONFIG_BASENAMES: readonly ["opencode", "tui"];
3
+ export interface UninstallOptions {
4
+ purge?: boolean;
5
+ dryRun?: boolean;
6
+ yes?: boolean;
7
+ }
8
+ export interface UninstallResultPerFile {
9
+ path: string;
10
+ status: 'wrote' | 'skipped' | 'error';
11
+ backup: string | null;
12
+ }
13
+ export interface UninstallResult {
14
+ status: 'wrote' | 'skipped';
15
+ results: UninstallResultPerFile[];
16
+ purged: boolean;
17
+ }
18
+ /**
19
+ * Uninstall opencode-rules-md from both opencode.json and tui.json configs.
20
+ *
21
+ * Options:
22
+ * purge — also remove ~/.cache/opencode/node_modules/opencode-rules-md
23
+ * dryRun — run full pipeline without writing to disk
24
+ * yes — accepted for future prompts, no-op here
25
+ */
26
+ export declare const runUninstall: (opts: UninstallOptions | undefined, fs: CliFs, env: NodeJS.ProcessEnv) => UninstallResult;
27
+ //# sourceMappingURL=uninstall.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"uninstall.d.ts","sourceRoot":"","sources":["../../../src/cli/uninstall.ts"],"names":[],"mappings":"AAUA,OAAO,EAOL,KAAK,KAAK,EACX,MAAM,aAAa,CAAC;AAErB,eAAO,MAAM,gBAAgB,8BAA+B,CAAC;AAE7D,MAAM,WAAW,gBAAgB;IAC/B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAED,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,GAAG,SAAS,GAAG,OAAO,CAAC;IACtC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,OAAO,GAAG,SAAS,CAAC;IAC5B,OAAO,EAAE,sBAAsB,EAAE,CAAC;IAClC,MAAM,EAAE,OAAO,CAAC;CACjB;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,YAAY,GACvB,MAAM,gBAAgB,YAAK,EAC3B,IAAI,KAAK,EACT,KAAK,MAAM,CAAC,UAAU,KACrB,eA6FF,CAAC"}
@@ -0,0 +1,101 @@
1
+ // ---------------------------------------------------------------------------
2
+ // src/cli/uninstall.ts — `omd uninstall` command implementation.
3
+ //
4
+ // Dual-config uninstall: removes opencode-rules-md entries from both configs.
5
+ // --purge removes ONLY ~/.cache/opencode/node_modules/opencode-rules-md and
6
+ // NEVER touches rule directories.
7
+ // ---------------------------------------------------------------------------
8
+ import { dirname, join } from 'path';
9
+ import { homedir } from 'os';
10
+ import { loadGlobalConfig, matchesPlugin, normalizePlugin, backupIfWritable, rotateBackups, writeAtomically, } from './config.js';
11
+ export const CONFIG_BASENAMES = ['opencode', 'tui'];
12
+ /**
13
+ * Uninstall opencode-rules-md from both opencode.json and tui.json configs.
14
+ *
15
+ * Options:
16
+ * purge — also remove ~/.cache/opencode/node_modules/opencode-rules-md
17
+ * dryRun — run full pipeline without writing to disk
18
+ * yes — accepted for future prompts, no-op here
19
+ */
20
+ export const runUninstall = (opts = {}, fs, env) => {
21
+ const results = [];
22
+ let anyProcessed = false;
23
+ let purged = false;
24
+ // ── Purge cache if requested ────────────────────────────────────────────
25
+ if (opts.purge) {
26
+ const cachePath = join(homedir(), '.cache', 'opencode', 'node_modules', 'opencode-rules-md');
27
+ if (fs.existsSync(cachePath)) {
28
+ try {
29
+ // Check if it's a directory or a file
30
+ const entries = fs.readdirSync(cachePath);
31
+ if (entries.length === 0) {
32
+ // Empty directory — remove it
33
+ fs.rmdirSync(cachePath);
34
+ }
35
+ else {
36
+ // Has contents — remove contents then the dir
37
+ for (const entry of entries) {
38
+ const entryPath = join(cachePath, entry);
39
+ if (fs.existsSync(entryPath)) {
40
+ try {
41
+ fs.unlinkSync(entryPath);
42
+ }
43
+ catch {
44
+ // ignore individual file failures
45
+ }
46
+ }
47
+ }
48
+ fs.rmdirSync(cachePath);
49
+ }
50
+ purged = true;
51
+ }
52
+ catch {
53
+ // best-effort — cache purge failure is non-fatal
54
+ }
55
+ }
56
+ }
57
+ // ── Remove plugin from both configs ─────────────────────────────────────
58
+ for (const basename of CONFIG_BASENAMES) {
59
+ const loaded = loadGlobalConfig(fs, env, basename);
60
+ const plugins = normalizePlugin(loaded.data['plugins']);
61
+ // Filter out all opencode-rules-md entries
62
+ const remaining = plugins.filter(p => !matchesPlugin(p));
63
+ if (remaining.length === plugins.length) {
64
+ // Nothing to remove — no-op for this file
65
+ results.push({ path: loaded.path, status: 'skipped', backup: null });
66
+ continue;
67
+ }
68
+ anyProcessed = true;
69
+ const newData = { ...loaded.data, plugins: remaining };
70
+ const newContent = JSON.stringify(newData, null, 2) + '\n';
71
+ if (opts.dryRun) {
72
+ results.push({ path: loaded.path, status: 'wrote', backup: null });
73
+ continue;
74
+ }
75
+ // Backup the existing file if it exists
76
+ let backup;
77
+ if (loaded.exists) {
78
+ backup = backupIfWritable(fs, loaded.path);
79
+ if (backup !== undefined) {
80
+ const dir = dirname(loaded.path);
81
+ const segs = loaded.path.replace(/\\/g, '/').split('/');
82
+ const base = segs[segs.length - 1] ?? loaded.path;
83
+ const dot = base.lastIndexOf('.');
84
+ const name = dot >= 0 ? base.slice(0, dot) : base;
85
+ rotateBackups(fs, dir, name, 3);
86
+ }
87
+ }
88
+ writeAtomically(fs, loaded.path, newContent);
89
+ results.push({
90
+ path: loaded.path,
91
+ status: 'wrote',
92
+ backup: backup ?? null,
93
+ });
94
+ }
95
+ return {
96
+ status: anyProcessed || purged ? 'wrote' : 'skipped',
97
+ results,
98
+ purged,
99
+ };
100
+ };
101
+ //# sourceMappingURL=uninstall.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"uninstall.js","sourceRoot":"","sources":["../../../src/cli/uninstall.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ import type { CliFs } from './config.js';
2
+ export declare const CACHE_PATH: string;
3
+ export interface UpdateOptions {
4
+ latestVersion?: string | null | undefined;
5
+ dryRun?: boolean;
6
+ }
7
+ export interface UpdateResult {
8
+ status: 'stale' | 'current' | 'unreachable';
9
+ cachePath: string;
10
+ instruction: string;
11
+ }
12
+ /**
13
+ * Resolve the local cache directory, honoring a custom HOME environment.
14
+ * Falls back to os.homedir() when HOME is not set, matching the
15
+ * resolveConfigDir fallback strategy.
16
+ */
17
+ export declare function resolveCachePath(env?: NodeJS.ProcessEnv): string;
18
+ /**
19
+ * Run the update command:
20
+ * 1. Fetch latest version from npm (or use provided mock)
21
+ * 2. Compare to installed version in config
22
+ * 3. If stale: purge cache, print reinstall instruction
23
+ * 4. If current: print "already current"
24
+ * 5. If unreachable: noop
25
+ */
26
+ export declare const runUpdate: (fs: CliFs, env: NodeJS.ProcessEnv, log: (s: string) => void, _error: (s: string) => void, opts?: UpdateOptions) => Promise<UpdateResult>;
27
+ /**
28
+ * Recursively delete a directory and all its contents using the given fs.
29
+ */
30
+ export declare function purgeDirectory(fs: CliFs, dirPath: string): void;
31
+ //# sourceMappingURL=update.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../../../src/cli/update.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAIzC,eAAO,MAAM,UAAU,QAMtB,CAAC;AAIF,MAAM,WAAW,aAAa;IAC5B,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IAC1C,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,OAAO,GAAG,SAAS,GAAG,aAAa,CAAC;IAC5C,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;CACrB;AAID;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,CAQ7E;AAuBD;;;;;;;GAOG;AACH,eAAO,MAAM,SAAS,GACpB,IAAI,KAAK,EACT,KAAK,MAAM,CAAC,UAAU,EACtB,KAAK,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,EACxB,QAAQ,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,EAC3B,OAAM,aAAkB,KACvB,OAAO,CAAC,YAAY,CAqFtB,CAAC;AAIF;;GAEG;AACH,wBAAgB,cAAc,CAAC,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAsC/D"}
@@ -0,0 +1,173 @@
1
+ // ---------------------------------------------------------------------------
2
+ // src/cli/update.ts — `omd update` command implementation.
3
+ //
4
+ // Fetches latest from npm, compares to installed version, purges the
5
+ // ~/.cache/opencode/node_modules/opencode-rules-md cache, and prints the
6
+ // reinstall instruction when stale. No auto-reinstall.
7
+ // ---------------------------------------------------------------------------
8
+ import { homedir } from 'os';
9
+ import { join } from 'path';
10
+ import { fetchLatestVersion, isStale } from './registry.js';
11
+ import { loadGlobalConfig, matchesPlugin, normalizePlugin } from './config.js';
12
+ // ─── Constants ───────────────────────────────────────────────────────────────
13
+ export const CACHE_PATH = join(homedir(), '.cache', 'opencode', 'node_modules', 'opencode-rules-md');
14
+ // ─── Cache path helpers ───────────────────────────────────────────────────────
15
+ /**
16
+ * Resolve the local cache directory, honoring a custom HOME environment.
17
+ * Falls back to os.homedir() when HOME is not set, matching the
18
+ * resolveConfigDir fallback strategy.
19
+ */
20
+ export function resolveCachePath(env = process.env) {
21
+ return join(env.HOME ?? homedir(), '.cache', 'opencode', 'node_modules', 'opencode-rules-md');
22
+ }
23
+ /**
24
+ * Read the cached package.json version, if determinable.
25
+ * Returns null when the cache is missing or unreadable.
26
+ */
27
+ function readCacheVersion(fs, cachePath) {
28
+ const pkgPath = join(cachePath, 'package.json');
29
+ try {
30
+ if (!fs.existsSync(pkgPath)) {
31
+ return null;
32
+ }
33
+ const pkg = JSON.parse(fs.readFileSync(pkgPath));
34
+ return typeof pkg.version === 'string' ? pkg.version : null;
35
+ }
36
+ catch {
37
+ return null;
38
+ }
39
+ }
40
+ // ─── runUpdate ────────────────────────────────────────────────────────────────
41
+ const CONFIG_BASENAMES = ['opencode', 'tui'];
42
+ /**
43
+ * Run the update command:
44
+ * 1. Fetch latest version from npm (or use provided mock)
45
+ * 2. Compare to installed version in config
46
+ * 3. If stale: purge cache, print reinstall instruction
47
+ * 4. If current: print "already current"
48
+ * 5. If unreachable: noop
49
+ */
50
+ export const runUpdate = async (fs, env, log, _error, opts = {}) => {
51
+ // Use provided latestVersion for testing, otherwise fetch from npm
52
+ const latest = opts.latestVersion !== undefined
53
+ ? opts.latestVersion
54
+ : await fetchLatestVersion();
55
+ const cachePath = resolveCachePath(env);
56
+ if (latest === null) {
57
+ log('omd: could not determine latest version from npm registry');
58
+ return {
59
+ status: 'unreachable',
60
+ cachePath,
61
+ instruction: 'npx opencode-rules-md@latest install',
62
+ };
63
+ }
64
+ // Determine installed version from config (check both configs)
65
+ let installedVersion = null;
66
+ for (const basename of CONFIG_BASENAMES) {
67
+ const loaded = loadGlobalConfig(fs, env, basename);
68
+ const plugins = normalizePlugin(loaded.data['plugins']);
69
+ const match = plugins.find(p => matchesPlugin(p));
70
+ if (match) {
71
+ // Extract version from specifier (e.g. 'opencode-rules-md@2.0.0' -> '2.0.0')
72
+ const atIndex = match.lastIndexOf('@');
73
+ installedVersion = atIndex >= 0 ? match.slice(atIndex + 1) : null;
74
+ break; // use first config that has it
75
+ }
76
+ }
77
+ const instruction = `npx opencode-rules-md@latest install`;
78
+ // Check staleness: only stale if installed version differs from latest
79
+ if (installedVersion !== null && !isStale(installedVersion, latest)) {
80
+ log(`omd: opencode-rules-md@${installedVersion} is already the latest`);
81
+ return {
82
+ status: 'current',
83
+ cachePath,
84
+ instruction,
85
+ };
86
+ }
87
+ // Before purging, decide whether the cache is actually stale. When the cache
88
+ // version is already equal to the latest resolved version, skip the purge
89
+ // so we do not delete a valid cache. If the version cannot be determined,
90
+ // fall back to purging to be safe.
91
+ const cacheVersion = readCacheVersion(fs, cachePath);
92
+ const shouldPurge = cacheVersion === null || cacheVersion !== latest;
93
+ if (opts.dryRun) {
94
+ log(`omd: update check (dry-run)`);
95
+ log(` latest version: ${latest}`);
96
+ log(` installed version: ${installedVersion ?? 'not installed'}`);
97
+ log(` would purge: ${shouldPurge ? cachePath : '(nothing to purge)'}`);
98
+ log(` would instruct: ${instruction}`);
99
+ return {
100
+ status: 'stale',
101
+ cachePath,
102
+ instruction,
103
+ };
104
+ }
105
+ // Purge the cache directory using the injected fs (allows test faking)
106
+ if (shouldPurge) {
107
+ try {
108
+ if (fs.existsSync(cachePath)) {
109
+ // Recursively remove contents then the dir itself
110
+ purgeDirectory(fs, cachePath);
111
+ }
112
+ }
113
+ catch {
114
+ // best-effort — purge failure is non-fatal
115
+ }
116
+ }
117
+ log(`omd: opencode-rules-md is stale (latest: ${latest})`);
118
+ log(`omd: cache purged at ${cachePath}`);
119
+ log(`omd: to reinstall, run:`);
120
+ log(` ${instruction}`);
121
+ return {
122
+ status: 'stale',
123
+ cachePath,
124
+ instruction,
125
+ };
126
+ };
127
+ // ─── purgeDirectory ────────────────────────────────────────────────────────────
128
+ /**
129
+ * Recursively delete a directory and all its contents using the given fs.
130
+ */
131
+ export function purgeDirectory(fs, dirPath) {
132
+ let entries = [];
133
+ try {
134
+ entries = fs.readdirSync(dirPath);
135
+ }
136
+ catch {
137
+ return;
138
+ }
139
+ for (const entry of entries) {
140
+ const entryPath = join(dirPath, entry);
141
+ try {
142
+ if (fs.existsSync(entryPath)) {
143
+ // Check if it's a directory by trying to read it
144
+ try {
145
+ const subEntries = fs.readdirSync(entryPath);
146
+ if (subEntries.length === 0) {
147
+ // Empty directory
148
+ fs.rmdirSync(entryPath);
149
+ }
150
+ else {
151
+ // Non-empty directory — recurse
152
+ purgeDirectory(fs, entryPath);
153
+ fs.rmdirSync(entryPath);
154
+ }
155
+ }
156
+ catch {
157
+ // It's a file — unlink it
158
+ fs.unlinkSync(entryPath);
159
+ }
160
+ }
161
+ }
162
+ catch {
163
+ // best-effort per entry
164
+ }
165
+ }
166
+ try {
167
+ fs.rmdirSync(dirPath);
168
+ }
169
+ catch {
170
+ // best-effort
171
+ }
172
+ }
173
+ //# sourceMappingURL=update.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update.js","sourceRoot":"","sources":["../../../src/cli/update.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-rules-md",
3
- "version": "0.8.3",
3
+ "version": "0.8.5",
4
4
  "description": "OpenCode plugin that discovers and injects markdown rules into system prompts",
5
5
  "main": "dist/src/index.js",
6
6
  "types": "dist/src/index.d.ts",
@@ -9,6 +9,9 @@
9
9
  "server",
10
10
  "tui"
11
11
  ],
12
+ "bin": {
13
+ "omd": "./dist/cli.mjs"
14
+ },
12
15
  "keywords": [
13
16
  "opencode",
14
17
  "plugin",
@@ -27,6 +30,7 @@
27
30
  },
28
31
  "files": [
29
32
  "dist",
33
+ "dist/cli.mjs",
30
34
  "!dist/**/*.test.*",
31
35
  "!dist/**/*.spec.*",
32
36
  "!dist/**/test-fixtures.*",
@@ -60,10 +64,7 @@
60
64
  },
61
65
  "peerDependencies": {
62
66
  "@opencode-ai/plugin": "^1.3.9",
63
- "@opencode-ai/sdk": "^1.3.9",
64
- "@opentui/core": "^0.4.3",
65
- "@opentui/solid": "^0.4.3",
66
- "solid-js": "^1.9.12"
67
+ "@opencode-ai/sdk": "^1.3.9"
67
68
  },
68
69
  "peerDependenciesMeta": {
69
70
  "@opencode-ai/plugin": {
@@ -71,15 +72,6 @@
71
72
  },
72
73
  "@opencode-ai/sdk": {
73
74
  "optional": true
74
- },
75
- "@opentui/core": {
76
- "optional": true
77
- },
78
- "@opentui/solid": {
79
- "optional": true
80
- },
81
- "solid-js": {
82
- "optional": true
83
75
  }
84
76
  },
85
77
  "devDependencies": {
@@ -98,11 +90,15 @@
98
90
  "vitest": "^2.1.8"
99
91
  },
100
92
  "dependencies": {
93
+ "@opentui/core": "^0.4.3",
94
+ "@opentui/solid": "^0.4.3",
101
95
  "minimatch": "^9.0.5",
96
+ "solid-js": "^1.9.12",
102
97
  "yaml": "^2.8.2"
103
98
  },
104
99
  "scripts": {
105
- "build": "tsc && bun scripts/build-tui.mjs",
100
+ "build": "tsc && bun scripts/build-tui.mjs && bun scripts/build-cli.mjs",
101
+ "build:cli": "bun scripts/build-cli.mjs",
106
102
  "dev": "tsc --watch",
107
103
  "test": "vitest",
108
104
  "test:run": "vitest run",