oc-tweaks 0.11.2 → 0.11.3

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 (2) hide show
  1. package/dist/cli/init.js +136 -3
  2. package/package.json +1 -1
package/dist/cli/init.js CHANGED
@@ -2,8 +2,8 @@
2
2
  // @bun
3
3
 
4
4
  // src/cli/init.ts
5
- import { mkdir } from "fs/promises";
6
- import { dirname } from "path";
5
+ import { mkdir as mkdir2 } from "fs/promises";
6
+ import { dirname as dirname2 } from "path";
7
7
 
8
8
  // src/plugins/auto-memory/diag.ts
9
9
  import { statSync } from "node:fs";
@@ -103,6 +103,33 @@ function parseFrontmatter(raw) {
103
103
  };
104
104
  return { meta, body };
105
105
  }
106
+ function serializeFrontmatter(meta, body) {
107
+ const lines = ["---"];
108
+ if (meta.id)
109
+ lines.push(`id: ${meta.id}`);
110
+ lines.push(`scope: ${meta.scope}`);
111
+ if (meta.type)
112
+ lines.push(`type: ${meta.type}`);
113
+ if (meta.source)
114
+ lines.push(`source: ${meta.source}`);
115
+ if (meta.created_at)
116
+ lines.push(`created_at: ${meta.created_at}`);
117
+ if (meta.updated_at)
118
+ lines.push(`updated_at: ${meta.updated_at}`);
119
+ lines.push(`trusted_as_instruction: false`);
120
+ if (meta.summary !== undefined)
121
+ lines.push(`summary: "${meta.summary}"`);
122
+ if (meta.disabled !== undefined)
123
+ lines.push(`disabled: ${meta.disabled ? "true" : "false"}`);
124
+ if (meta.usage_count !== undefined)
125
+ lines.push(`usage_count: ${meta.usage_count}`);
126
+ if (meta.last_usage !== undefined)
127
+ lines.push(`last_usage: ${meta.last_usage}`);
128
+ lines.push("---");
129
+ lines.push(body);
130
+ return lines.join(`
131
+ `);
132
+ }
106
133
 
107
134
  // src/plugins/auto-memory/registry.ts
108
135
  var SKIP_PATTERNS = [
@@ -281,6 +308,90 @@ function formatDiagReport(report) {
281
308
  }
282
309
  if (false) {}
283
310
 
311
+ // src/plugins/auto-memory/migrate.ts
312
+ import { mkdir, open, readdir, readFile, rename, unlink } from "node:fs/promises";
313
+ import { dirname, join as join3, resolve } from "node:path";
314
+ function detectScope(absRoot, override) {
315
+ if (override)
316
+ return override;
317
+ return absRoot.includes(`.opencode${"/"}memory`) || absRoot.includes(`.opencode${"\\"}memory`) ? "project" : "global";
318
+ }
319
+ function slugifyFilename(filename) {
320
+ return filename.replace(/\.md$/i, "").toLowerCase().replace(/[\s_]+/g, "-");
321
+ }
322
+ async function atomicWrite(absPath, content) {
323
+ const tmpfile = `${absPath}.tmp.${Date.now()}-${Math.random().toString(36).slice(2)}`;
324
+ let tmpfileCreated = false;
325
+ try {
326
+ await mkdir(dirname(absPath), { recursive: true });
327
+ const handle = await open(tmpfile, "w");
328
+ try {
329
+ await handle.writeFile(content, "utf8");
330
+ await handle.sync();
331
+ } finally {
332
+ await handle.close();
333
+ }
334
+ tmpfileCreated = true;
335
+ await rename(tmpfile, absPath);
336
+ tmpfileCreated = false;
337
+ } finally {
338
+ if (tmpfileCreated) {
339
+ await unlink(tmpfile).catch(() => {});
340
+ }
341
+ }
342
+ }
343
+ async function migrate(opts) {
344
+ const absRoot = resolve(opts.root);
345
+ const scope = detectScope(absRoot, opts.scope);
346
+ const result = { migrated: [], skipped: [], errored: [] };
347
+ let filenames;
348
+ try {
349
+ filenames = await readdir(absRoot);
350
+ } catch {
351
+ return result;
352
+ }
353
+ for (const filename of filenames) {
354
+ if (!filename.endsWith(".md"))
355
+ continue;
356
+ const absPath = join3(absRoot, filename);
357
+ let raw;
358
+ try {
359
+ raw = await readFile(absPath, "utf8");
360
+ } catch (err) {
361
+ console.error(`[migrate] error reading ${filename}: ${err.message}`);
362
+ result.errored.push(filename);
363
+ continue;
364
+ }
365
+ const stripped = raw.startsWith("\uFEFF") ? raw.slice(1) : raw;
366
+ if (stripped.startsWith("---")) {
367
+ console.log(`[migrate] skip (has frontmatter): ${filename}`);
368
+ result.skipped.push(filename);
369
+ continue;
370
+ }
371
+ const now = new Date().toISOString();
372
+ const meta = {
373
+ id: slugifyFilename(filename),
374
+ scope,
375
+ type: "note",
376
+ source: "migrate",
377
+ created_at: now,
378
+ updated_at: now,
379
+ trusted_as_instruction: false
380
+ };
381
+ const newContent = serializeFrontmatter(meta, raw);
382
+ try {
383
+ await atomicWrite(absPath, newContent);
384
+ console.log(`[migrate] migrated: ${filename}`);
385
+ result.migrated.push(filename);
386
+ } catch (err) {
387
+ console.error(`[migrate] error writing ${filename}: ${err.message}`);
388
+ result.errored.push(filename);
389
+ }
390
+ }
391
+ return result;
392
+ }
393
+ if (false) {}
394
+
284
395
  // src/cli/init.ts
285
396
  var DEFAULT_CONFIG = {
286
397
  notify: { enabled: true },
@@ -298,7 +409,7 @@ async function initConfig() {
298
409
  return { created: false, path: configPath };
299
410
  }
300
411
  const json = JSON.stringify(DEFAULT_CONFIG, null, 2);
301
- await mkdir(dirname(configPath), { recursive: true });
412
+ await mkdir2(dirname2(configPath), { recursive: true });
302
413
  await Bun.write(configPath, json + `
303
414
  `);
304
415
  return { created: true, path: configPath };
@@ -310,6 +421,9 @@ function parseCliArgs(argv) {
310
421
  if (args[0] === "memory" && args[1] === "diag") {
311
422
  return { command: "memory-diag", opts: parseDiagOpts(args.slice(2)) };
312
423
  }
424
+ if (args[0] === "memory" && args[1] === "migrate") {
425
+ return { command: "memory-migrate", opts: parseMigrateOpts(args.slice(2)) };
426
+ }
313
427
  return { command: "init" };
314
428
  }
315
429
  function parseDiagOpts(args) {
@@ -325,12 +439,31 @@ function parseDiagOpts(args) {
325
439
  }
326
440
  return opts;
327
441
  }
442
+ function parseMigrateOpts(args) {
443
+ const opts = { root: "" };
444
+ for (let i = 0;i < args.length; i++) {
445
+ const arg = args[i];
446
+ if (arg === "--root" && args[i + 1])
447
+ opts.root = args[++i];
448
+ else if (arg === "--scope" && args[i + 1]) {
449
+ const scope = args[++i];
450
+ if (scope === "global" || scope === "project")
451
+ opts.scope = scope;
452
+ }
453
+ }
454
+ return opts;
455
+ }
328
456
  var isMain = typeof Bun !== "undefined" && Bun.main === import.meta.path;
329
457
  if (isMain) {
330
458
  const parsed = parseCliArgs(process.argv.slice(2));
331
459
  if (parsed.command === "memory-diag") {
332
460
  const report = await runDiag(parsed.opts);
333
461
  console.log(formatDiagReport(report));
462
+ } else if (parsed.command === "memory-migrate") {
463
+ if (!parsed.opts.root)
464
+ throw new Error("--root <dir> is required");
465
+ const result = await migrate(parsed.opts);
466
+ console.log(`Summary: migrated=${result.migrated.length}, skipped=${result.skipped.length}, errored=${result.errored.length}`);
334
467
  } else {
335
468
  const result = await initConfig();
336
469
  if (result.created) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oc-tweaks",
3
- "version": "0.11.2",
3
+ "version": "0.11.3",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": "./dist/index.js"