oh-aicoding-tool 0.1.6 → 0.1.7
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/bin/cli.js +52 -72
- package/package.json +2 -2
package/bin/cli.js
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import fs from "node:fs";
|
|
3
|
-
import path from "node:path";
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import { createInterface } from "node:readline/promises";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { spawnSync } from "node:child_process";
|
|
5
|
+
import { createRequire } from "node:module";
|
|
6
|
+
import { createInterface } from "node:readline/promises";
|
|
8
7
|
|
|
9
8
|
const require = createRequire(import.meta.url);
|
|
10
9
|
|
|
@@ -87,43 +86,6 @@ function emailIsValid(value) {
|
|
|
87
86
|
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(String(value || "").trim());
|
|
88
87
|
}
|
|
89
88
|
|
|
90
|
-
function keySeq(raw, key = {}) {
|
|
91
|
-
return String(key.sequence ?? raw ?? "");
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
function isCtrlC(raw, key = {}) {
|
|
95
|
-
return Boolean(key.ctrl && key.name === "c") || keySeq(raw, key) === "\x03";
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
function isEscape(raw, key = {}) {
|
|
99
|
-
const seq = keySeq(raw, key);
|
|
100
|
-
return key.name === "escape" || seq === "\x1b";
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
function isUpKey(raw, key = {}) {
|
|
104
|
-
const seq = keySeq(raw, key);
|
|
105
|
-
return key.name === "up" || seq === "\x1b[A" || seq === "\x1bOA";
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
function isDownKey(raw, key = {}) {
|
|
109
|
-
const seq = keySeq(raw, key);
|
|
110
|
-
return key.name === "down" || seq === "\x1b[B" || seq === "\x1bOB";
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
function isEnterKey(raw, key = {}) {
|
|
114
|
-
const seq = keySeq(raw, key);
|
|
115
|
-
return key.name === "return" || key.name === "enter" || seq === "\r" || seq === "\n";
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
function isSpaceKey(raw, key = {}) {
|
|
119
|
-
return key.name === "space" || keySeq(raw, key) === " ";
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
function numberKey(raw, key = {}) {
|
|
123
|
-
const seq = keySeq(raw, key);
|
|
124
|
-
return /^[1-9]$/.test(seq) ? Number.parseInt(seq, 10) : Number.NaN;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
89
|
function renderMultiChoice(title, choices, index, selected, subtitle) {
|
|
128
90
|
renderHeader(subtitle);
|
|
129
91
|
console.log("");
|
|
@@ -139,21 +101,39 @@ function renderMultiChoice(title, choices, index, selected, subtitle) {
|
|
|
139
101
|
if (choice.description) console.log(` ${paint(choice.description, focused ? t.blue : t.muted)}`);
|
|
140
102
|
if (idx < choices.length - 1) console.log("");
|
|
141
103
|
});
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function rawKeySeq(raw) {
|
|
107
|
+
if (Buffer.isBuffer(raw)) return raw.toString("latin1");
|
|
108
|
+
return String(raw ?? "");
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function parseRawKey(raw) {
|
|
112
|
+
const seq = rawKeySeq(raw);
|
|
113
|
+
if (seq === "\x03") return { name: "ctrl-c", sequence: seq };
|
|
114
|
+
if (seq === "\x1b[A" || seq === "\x1bOA" || seq === "\x00H" || seq === "\xe0H") return { name: "up", sequence: seq };
|
|
115
|
+
if (seq === "\x1b[B" || seq === "\x1bOB" || seq === "\x00P" || seq === "\xe0P") return { name: "down", sequence: seq };
|
|
116
|
+
if (seq === "\r" || seq === "\n" || seq === "\r\n") return { name: "enter", sequence: seq };
|
|
117
|
+
if (seq === " ") return { name: "space", sequence: seq };
|
|
118
|
+
if (seq === "\x1b") return { name: "escape", sequence: seq };
|
|
119
|
+
if (/^[1-9]$/.test(seq)) return { name: "number", number: Number.parseInt(seq, 10), sequence: seq };
|
|
120
|
+
if (seq.length === 1) return { name: seq.toLowerCase(), sequence: seq };
|
|
121
|
+
return { name: "", sequence: seq };
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
async function askMultiChoice(rl, title, choices, subtitle) {
|
|
145
125
|
if (process.stdin.isTTY && process.stdout.isTTY) {
|
|
146
126
|
rl.pause();
|
|
147
127
|
return await new Promise((resolve) => {
|
|
148
128
|
let index = 0;
|
|
149
129
|
const selected = new Set(choices.filter((choice) => choice.selected).map((choice) => choice.value));
|
|
150
130
|
const stdin = process.stdin;
|
|
151
|
-
|
|
152
|
-
function cleanup(value) {
|
|
153
|
-
stdin.off("
|
|
154
|
-
if (stdin.isTTY) stdin.setRawMode(false);
|
|
155
|
-
stdin.pause();
|
|
156
|
-
rl.resume();
|
|
131
|
+
|
|
132
|
+
function cleanup(value) {
|
|
133
|
+
stdin.off("data", onData);
|
|
134
|
+
if (stdin.isTTY) stdin.setRawMode(false);
|
|
135
|
+
stdin.pause();
|
|
136
|
+
rl.resume();
|
|
157
137
|
clearScreen();
|
|
158
138
|
resolve(value);
|
|
159
139
|
}
|
|
@@ -162,37 +142,37 @@ async function askMultiChoice(rl, title, choices, subtitle) {
|
|
|
162
142
|
const value = choices[index].value;
|
|
163
143
|
if (selected.has(value)) selected.delete(value);
|
|
164
144
|
else selected.add(value);
|
|
165
|
-
renderMultiChoice(title, choices, index, selected, subtitle);
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
function
|
|
169
|
-
|
|
170
|
-
if (
|
|
145
|
+
renderMultiChoice(title, choices, index, selected, subtitle);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function onData(raw) {
|
|
149
|
+
const key = parseRawKey(raw);
|
|
150
|
+
if (key.name === "ctrl-c") return cleanup([]);
|
|
151
|
+
if (key.name === "up") {
|
|
171
152
|
index = (index - 1 + choices.length) % choices.length;
|
|
172
153
|
renderMultiChoice(title, choices, index, selected, subtitle);
|
|
173
154
|
return;
|
|
174
155
|
}
|
|
175
|
-
if (
|
|
156
|
+
if (key.name === "down") {
|
|
176
157
|
index = (index + 1) % choices.length;
|
|
177
158
|
renderMultiChoice(title, choices, index, selected, subtitle);
|
|
178
159
|
return;
|
|
179
160
|
}
|
|
180
|
-
if (
|
|
181
|
-
if (
|
|
182
|
-
if (
|
|
183
|
-
const number =
|
|
161
|
+
if (key.name === "q" || key.name === "escape") return cleanup([]);
|
|
162
|
+
if (key.name === "space") return toggle();
|
|
163
|
+
if (key.name === "enter") return cleanup([...selected]);
|
|
164
|
+
const number = key.name === "number" ? key.number : Number.NaN;
|
|
184
165
|
if (Number.isInteger(number) && choices[number - 1]) {
|
|
185
166
|
index = number - 1;
|
|
186
167
|
toggle();
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
stdin.
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
});
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (stdin.isTTY) stdin.setRawMode(true);
|
|
172
|
+
stdin.on("data", onData);
|
|
173
|
+
stdin.resume();
|
|
174
|
+
renderMultiChoice(title, choices, index, selected, subtitle);
|
|
175
|
+
});
|
|
196
176
|
}
|
|
197
177
|
|
|
198
178
|
choices.forEach((choice, index) => console.log(` ${index + 1}. ${choice.label}`));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "oh-aicoding-tool",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.7",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "Interactive installer for AI coding tools: Langfuse tracing and oh-ai-report.",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
],
|
|
26
26
|
"license": "UNLICENSED",
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"oh-langfuse": "^0.1.
|
|
28
|
+
"oh-langfuse": "^0.1.10",
|
|
29
29
|
"oh-aireport": "^0.1.1"
|
|
30
30
|
}
|
|
31
31
|
}
|