@nevermorelove/ompp 0.2.0 → 0.2.2

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/README.md CHANGED
@@ -63,7 +63,7 @@ inside an installed package. The first `ompp create` makes the folder for you.
63
63
 
64
64
  A new mode is `ompp create <name>` (or plain `mkdir` plus files). No manifest,
65
65
  no code. The wrapper reads the folder, so it never needs to change when you
66
- add modes. `modes/general` in the repo is a working example.
66
+ add modes.
67
67
 
68
68
  ## Precedence
69
69
 
package/ompp.js CHANGED
@@ -278,88 +278,43 @@ function createMode(name) {
278
278
  return 0;
279
279
  }
280
280
 
281
- function pickInteractive(modes) {
282
- return new Promise((resolve, reject) => {
283
- const stdin = process.stdin;
284
- let idx = 0;
285
- let settled = false;
286
-
287
- const finish = (value) => {
288
- if (settled) return;
289
- settled = true;
290
- stdin.removeListener("data", onData);
291
- stdin.setRawMode(false);
292
- process.stdout.write("\u001b[?25h"); // show cursor
293
- if (value === null) reject(new Error("mode selection cancelled"));
294
- else resolve(value);
295
- };
296
-
297
- const render = (first) => {
298
- if (!first) process.stdout.write(`\u001b[${modes.length}A`);
299
- const body = modes
300
- .map((m, i) => (i === idx ? "> " + m : " " + m))
301
- .map((l) => "\u001b[2K" + l)
302
- .join("\n");
303
- process.stdout.write("\u001b[?25l" + body + "\n");
304
- };
305
-
306
- function onData(buf) {
307
- // A single read can carry several keys (arrow + Enter glued together,
308
- // a paste). Walk key by key instead of matching the whole chunk.
309
- const s = buf.toString();
310
- let i = 0;
311
- while (i < s.length) {
312
- const ch = s[i];
313
- if (ch === "\u001b") {
314
- const seq = s.slice(i);
315
- if (seq.startsWith("\u001b[A") || seq.startsWith("\u001b[B") ||
316
- seq.startsWith("\u001b[C") || seq.startsWith("\u001b[D")) {
317
- if (seq.startsWith("\u001b[A")) {
318
- idx = (idx - 1 + modes.length) % modes.length;
319
- render(false);
320
- } else if (seq.startsWith("\u001b[B")) {
321
- idx = (idx + 1) % modes.length;
322
- render(false);
323
- } // C/D: left/right, ignore
324
- i += 3;
325
- continue;
326
- }
327
- if (seq.length === 1) {
328
- // Bare escape with nothing after it in this chunk: cancel.
329
- finish(null);
330
- process.exit(0);
331
- }
332
- i++; // unknown or split sequence, skip the escape byte
333
- continue;
334
- }
335
- if (ch === "\r" || ch === "\n") return finish(modes[idx]);
336
- if (ch === "\u0003") {
337
- // Ctrl+C: restore the terminal and bail like a shell would.
338
- finish(null);
339
- process.exit(130);
340
- }
341
- if (ch === "q") {
342
- finish(null);
343
- process.exit(0);
344
- }
345
- if (ch === "j") {
346
- idx = (idx + 1) % modes.length;
347
- render(false);
348
- }
349
- if (ch === "k") {
350
- idx = (idx - 1 + modes.length) % modes.length;
351
- render(false);
352
- }
353
- i++;
354
- }
355
- }
281
+ async function pickMode(modeNames) {
282
+ const { select, isCancel, cancel } = require("@clack/prompts");
283
+ const chosen = await select({
284
+ message: "Pick a mode",
285
+ options: modeNames.map((name) => ({ value: name, label: name })),
286
+ });
287
+ if (isCancel(chosen)) {
288
+ cancel("Cancelled");
289
+ process.exit(130);
290
+ }
291
+ return chosen;
292
+ }
356
293
 
357
- stdin.setRawMode(true);
358
- stdin.resume();
359
- render(true);
294
+ // Non-TTY stdin: clack needs an interactive terminal, so numbered input.
295
+ function pickModePiped(modeNames) {
296
+ return new Promise((resolve, reject) => {
297
+ const readline = require("readline");
298
+ const rl = readline.createInterface({ input: process.stdin });
299
+ process.stdout.write("Select a mode:\n");
300
+ modeNames.forEach((m, i) => process.stdout.write(` ${i + 1}. ${m}\n`));
301
+ process.stdout.write(`Choice [1-${modeNames.length}]: `);
302
+ let done = false;
303
+ rl.once("line", (line) => {
304
+ done = true;
305
+ rl.close();
306
+ const n = parseInt(line.trim(), 10);
307
+ if (n >= 1 && n <= modeNames.length) resolve(modeNames[n - 1]);
308
+ else reject(new Error(`"${line.trim()}" is not a valid choice`));
309
+ });
310
+ rl.once("close", () => {
311
+ if (!done) reject(new Error("no mode selected"));
312
+ });
360
313
  });
361
314
  }
362
315
 
316
+
317
+
363
318
  async function main() {
364
319
  const argv = process.argv.slice(2);
365
320
 
@@ -371,7 +326,7 @@ async function main() {
371
326
  const { modes, skipped } = discoverModes();
372
327
  if (!modes.length) {
373
328
  console.error(
374
- `[ompp] no modes found. Run "ompp create <name>" to make one.`,
329
+ `You have no modes yet. Create one with "ompp create <name>".`,
375
330
  );
376
331
  for (const s of SOURCES) console.error(`[ompp] looked in: ${s}`);
377
332
  return 1;
@@ -405,7 +360,7 @@ async function main() {
405
360
  }
406
361
  if (!modes.length) {
407
362
  console.error(
408
- `[ompp] no modes found. Run "ompp create <name>" to make one.`,
363
+ `You have no modes yet. Create one with "ompp create <name>".`,
409
364
  );
410
365
  for (const s of SOURCES) console.error(`[ompp] looked in: ${s}`);
411
366
  return 1;
@@ -427,13 +382,10 @@ async function main() {
427
382
  }
428
383
  } else {
429
384
  try {
430
- mode = process.stdin.isTTY
431
- ? await pickInteractive(modeNames).then((n) =>
432
- modes.find((m) => m.name === n),
433
- )
434
- : await pickByNumber(modeNames).then((n) =>
435
- modes.find((m) => m.name === n),
436
- );
385
+ const name = process.stdin.isTTY
386
+ ? await pickMode(modeNames)
387
+ : await pickModePiped(modeNames);
388
+ mode = modes.find((m) => m.name === name);
437
389
  } catch (err) {
438
390
  console.error(`[ompp] ${err.message}`);
439
391
  return 1;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nevermorelove/ompp",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "Mode presets for the omp coding agent: one folder per mode, zero config code.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -24,5 +24,8 @@
24
24
  "cli"
25
25
  ],
26
26
  "author": "ForeverInLaw",
27
- "license": "MIT"
27
+ "license": "MIT",
28
+ "dependencies": {
29
+ "@clack/prompts": "^1.8.1"
30
+ }
28
31
  }
@@ -1,3 +0,0 @@
1
- # General
2
-
3
- Answer directly and briefly. No preamble, no restating the question.
@@ -1,8 +0,0 @@
1
- modelRoles:
2
- default: crusoe/zai-org/GLM-5.3:max
3
- defaultThinkingLevel: high
4
- skills:
5
- includeSkills:
6
- - unslop
7
- - tdd
8
- - diagnosing-bugs