oh-aicoding-tool 0.1.8 → 0.1.9

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/bin/cli.js +103 -21
  2. package/package.json +1 -1
package/bin/cli.js CHANGED
@@ -4,9 +4,11 @@ import path from "node:path";
4
4
  import { spawnSync } from "node:child_process";
5
5
  import { createRequire } from "node:module";
6
6
  import { createInterface } from "node:readline/promises";
7
+ import { fileURLToPath } from "node:url";
7
8
 
8
- const require = createRequire(import.meta.url);
9
-
9
+ const require = createRequire(import.meta.url);
10
+ const packageJsonPath = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..", "package.json");
11
+
10
12
  const colorEnabled = process.stdout.isTTY && process.env.NO_COLOR !== "1";
11
13
  const ansi = (code) => (colorEnabled ? `\x1b[${code}m` : "");
12
14
  const rgb = (r, g, b) => (colorEnabled ? `\x1b[38;2;${r};${g};${b}m` : "");
@@ -46,16 +48,22 @@ function renderHeader(subtitle = "Interactive setup") {
46
48
  console.log(`${paint("Space", t.gold)} toggle ${paint("Enter", t.gold)} continue ${paint("Up/Down", t.gold)} move ${paint("q", t.gold)} exit`);
47
49
  }
48
50
 
49
- function printHelp() {
50
- console.log("oh-aicoding-tool");
51
- console.log("");
52
- console.log("Usage:");
53
- console.log(" oh-aicoding-tool");
54
- console.log(" oh-aicoding-tool langfuse [setup|check] [target]");
55
- console.log(" oh-aicoding-tool report install opencode [--email user@company.com]");
56
- console.log(" oh-aicoding-tool report install claude");
57
- console.log(" oh-aicoding-tool report install both");
58
- }
51
+ function printHelp() {
52
+ console.log("oh-aicoding-tool");
53
+ console.log("");
54
+ console.log("Usage:");
55
+ console.log(" oh-aicoding-tool");
56
+ console.log(" oh-aicoding-tool --version");
57
+ console.log(" oh-aicoding-tool debug-keys");
58
+ console.log(" oh-aicoding-tool langfuse [setup|check] [target]");
59
+ console.log(" oh-aicoding-tool report install opencode [--email user@company.com]");
60
+ console.log(" oh-aicoding-tool report install claude");
61
+ console.log(" oh-aicoding-tool report install both");
62
+ }
63
+
64
+ function readOwnPackage() {
65
+ return JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
66
+ }
59
67
 
60
68
  function packageBinScript(packageName, preferredBin) {
61
69
  const pkgPath = require.resolve(`${packageName}/package.json`);
@@ -110,10 +118,20 @@ function rawKeySeq(raw) {
110
118
 
111
119
  function readKeyFromBuffer(buffer) {
112
120
  if (!buffer) return { pending: true, rest: "" };
113
- if (buffer === "\x1b" || buffer === "\x1b[" || buffer === "\x1bO" || buffer === "\x00" || buffer === "\xe0") {
121
+ if (buffer === "\x1b" || buffer === "\x00" || buffer === "\xe0" || /^\x1b\[[0-9;?]*$/.test(buffer) || buffer === "\x1bO") {
114
122
  return { pending: true, rest: buffer };
115
123
  }
116
124
 
125
+ const csi = buffer.match(/^\x1b\[[0-9;?]*([A-Za-z~])/);
126
+ if (csi?.[1] === "A") return { key: { name: "up", sequence: csi[0] }, rest: buffer.slice(csi[0].length) };
127
+ if (csi?.[1] === "B") return { key: { name: "down", sequence: csi[0] }, rest: buffer.slice(csi[0].length) };
128
+ if (csi) return { key: { name: "", sequence: csi[0] }, rest: buffer.slice(csi[0].length) };
129
+
130
+ const ss3 = buffer.match(/^\x1bO([A-Za-z])/);
131
+ if (ss3?.[1] === "A") return { key: { name: "up", sequence: ss3[0] }, rest: buffer.slice(ss3[0].length) };
132
+ if (ss3?.[1] === "B") return { key: { name: "down", sequence: ss3[0] }, rest: buffer.slice(ss3[0].length) };
133
+ if (ss3) return { key: { name: "", sequence: ss3[0] }, rest: buffer.slice(ss3[0].length) };
134
+
117
135
  const three = buffer.slice(0, 3);
118
136
  if (three === "\x1b[A" || three === "\x1bOA") return { key: { name: "up", sequence: three }, rest: buffer.slice(3) };
119
137
  if (three === "\x1b[B" || three === "\x1bOB") return { key: { name: "down", sequence: three }, rest: buffer.slice(3) };
@@ -132,6 +150,65 @@ function readKeyFromBuffer(buffer) {
132
150
  return { key: { name: seq.toLowerCase(), sequence: seq }, rest: buffer.slice(1) };
133
151
  }
134
152
 
153
+ function showControlChars(value) {
154
+ return value
155
+ .replaceAll("\x1b", "\\x1b")
156
+ .replaceAll("\x00", "\\x00")
157
+ .replaceAll("\xe0", "\\xe0")
158
+ .replaceAll("\r", "\\r")
159
+ .replaceAll("\n", "\\n")
160
+ .replaceAll("\x03", "\\x03");
161
+ }
162
+
163
+ function keyHex(value) {
164
+ return [...Buffer.from(value, "latin1")].map((byte) => byte.toString(16).padStart(2, "0")).join(" ");
165
+ }
166
+
167
+ async function debugKeys() {
168
+ const pkg = readOwnPackage();
169
+ console.log(`oh-aicoding-tool ${pkg.version}`);
170
+ console.log(`node ${process.version} ${process.platform} ${process.arch}`);
171
+ console.log(`stdin.isTTY=${process.stdin.isTTY} stdout.isTTY=${process.stdout.isTTY} rawMode=${process.stdin.isRaw}`);
172
+ console.log(`TERM=${process.env.TERM || ""} WT_SESSION=${process.env.WT_SESSION || ""} TERM_PROGRAM=${process.env.TERM_PROGRAM || ""}`);
173
+ console.log("Press Up, Down, Space, Enter, then q to exit this debug view.");
174
+
175
+ if (!process.stdin.isTTY) return 1;
176
+
177
+ return await new Promise((resolve) => {
178
+ let keyBuffer = "";
179
+ const stdin = process.stdin;
180
+
181
+ function cleanup(code) {
182
+ stdin.off("data", onData);
183
+ if (stdin.isTTY) stdin.setRawMode(false);
184
+ stdin.pause();
185
+ resolve(code);
186
+ }
187
+
188
+ function onData(raw) {
189
+ const seq = rawKeySeq(raw);
190
+ console.log(`raw hex=[${keyHex(seq)}] text=${showControlChars(seq)}`);
191
+ keyBuffer += seq;
192
+ while (keyBuffer) {
193
+ const result = readKeyFromBuffer(keyBuffer);
194
+ if (result.pending) {
195
+ console.log(`pending buffer hex=[${keyHex(result.rest)}] text=${showControlChars(result.rest)}`);
196
+ keyBuffer = result.rest;
197
+ return;
198
+ }
199
+ keyBuffer = result.rest;
200
+ const key = result.key;
201
+ console.log(`parsed name=${key.name || "<unknown>"} sequence=${showControlChars(key.sequence || "")}`);
202
+ if (key.name === "q" || key.name === "ctrl-c") return cleanup(0);
203
+ }
204
+ }
205
+
206
+ stdin.setRawMode(true);
207
+ stdin.on("data", onData);
208
+ stdin.resume();
209
+ });
210
+ }
211
+
135
212
  async function askMultiChoice(rl, title, choices, subtitle) {
136
213
  if (process.stdin.isTTY && process.stdout.isTTY) {
137
214
  rl.pause();
@@ -273,14 +350,19 @@ async function interactive() {
273
350
  }
274
351
  }
275
352
 
276
- async function main() {
277
- const argv = process.argv.slice(2);
278
- const [cmd, ...rest] = argv;
279
- if (cmd === "--help" || cmd === "-h" || cmd === "help") {
280
- printHelp();
281
- return 0;
282
- }
283
- if (!cmd) return await interactive();
353
+ async function main() {
354
+ const argv = process.argv.slice(2);
355
+ const [cmd, ...rest] = argv;
356
+ if (cmd === "--version" || cmd === "-v" || cmd === "version") {
357
+ console.log(readOwnPackage().version);
358
+ return 0;
359
+ }
360
+ if (cmd === "--help" || cmd === "-h" || cmd === "help") {
361
+ printHelp();
362
+ return 0;
363
+ }
364
+ if (cmd === "debug-keys") return await debugKeys();
365
+ if (!cmd) return await interactive();
284
366
  if (cmd === "langfuse") return runPackageBin("oh-langfuse", "oh-langfuse", rest);
285
367
  if (cmd === "report") return runPackageBin("oh-aireport", "oh-aireport", rest);
286
368
  if (cmd === "setup" || cmd === "check") return runPackageBin("oh-langfuse", "oh-langfuse", argv);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oh-aicoding-tool",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "Interactive installer for AI coding tools: Langfuse tracing and oh-ai-report.",