@smart-tinker/kayla 0.1.1 → 0.1.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.
package/dist/cli.js CHANGED
@@ -8,11 +8,11 @@ const node_os_1 = __importDefault(require("node:os"));
8
8
  const node_path_1 = __importDefault(require("node:path"));
9
9
  const node_fs_1 = __importDefault(require("node:fs"));
10
10
  const node_child_process_1 = require("node:child_process");
11
- const promises_1 = __importDefault(require("node:readline/promises"));
12
11
  const storage_1 = require("./core/storage");
13
12
  const service_1 = require("./service");
14
13
  const setup_1 = require("./core/setup");
15
14
  const doctor_1 = require("./core/doctor");
15
+ const tty_1 = require("./core/tty");
16
16
  function usage() {
17
17
  return [
18
18
  "Usage:",
@@ -29,26 +29,22 @@ function fail(msg, code = 1) {
29
29
  process.exit(code);
30
30
  }
31
31
  function createPrompt() {
32
- const rl = promises_1.default.createInterface({ input: process.stdin, output: process.stdout, terminal: true });
33
- const askText = async (message) => rl.question(message);
34
- const askSecret = async (message) => {
35
- // Best-effort: hide user input for secrets while still showing the prompt.
36
- process.stdout.write(message);
37
- const anyRl = rl;
38
- const prev = anyRl._writeToOutput;
39
- anyRl._writeToOutput = () => { };
40
- try {
41
- const ans = await rl.question("");
42
- process.stdout.write("\n");
43
- return ans;
44
- }
45
- finally {
46
- anyRl._writeToOutput = prev;
47
- }
48
- };
49
32
  return {
50
- prompt: async (q) => (q.kind === "secret" ? askSecret(q.message) : askText(q.message)),
51
- close: () => rl.close()
33
+ prompt: async (q) => {
34
+ if (q.kind === "secret") {
35
+ return (0, tty_1.readMaskedLine)({
36
+ input: process.stdin,
37
+ output: process.stdout,
38
+ prompt: q.message,
39
+ maskChar: "*",
40
+ setRawMode: (on) => process.stdin.setRawMode?.(on)
41
+ });
42
+ }
43
+ return (0, tty_1.readLine)({ input: process.stdin, output: process.stdout, prompt: q.message });
44
+ },
45
+ close: () => {
46
+ // no-op; we don't allocate a readline interface
47
+ }
52
48
  };
53
49
  }
54
50
  async function main(argv) {
@@ -21,6 +21,9 @@ function buildClaudeArgs(cfg, prompt, chatSettings) {
21
21
  const args = [];
22
22
  args.push("-c", "-p");
23
23
  const outputFormat = cfg.claude.streaming ? "stream-json" : "json";
24
+ // Claude Code CLI requires --verbose for --output-format=stream-json.
25
+ if (outputFormat === "stream-json")
26
+ args.push("--verbose");
24
27
  args.push("--output-format", outputFormat);
25
28
  // Chat-level overrides (optional).
26
29
  const tools = chatSettings?.tools ?? cfg.claude.tools;
@@ -41,6 +44,8 @@ function buildClaudeArgs(cfg, prompt, chatSettings) {
41
44
  const agentsJson = node_fs_1.default.readFileSync(cfg.claude.agents_file, "utf8");
42
45
  args.push("--agents", agentsJson);
43
46
  }
47
+ // `--tools <tools...>` is variadic in Claude Code CLI. Use `--` to ensure the prompt isn't consumed as a tool.
48
+ args.push("--");
44
49
  args.push(prompt);
45
50
  return args;
46
51
  }
@@ -0,0 +1,114 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.readLine = readLine;
4
+ exports.readMaskedLine = readMaskedLine;
5
+ async function readLine(opts) {
6
+ opts.output.write(opts.prompt);
7
+ return new Promise((resolve, reject) => {
8
+ let buf = "";
9
+ const onData = (chunk) => {
10
+ const s = Buffer.isBuffer(chunk) ? chunk.toString("utf8") : chunk;
11
+ buf += s;
12
+ const nl = buf.indexOf("\n");
13
+ const cr = buf.indexOf("\r");
14
+ const idx = nl >= 0 && cr >= 0 ? Math.min(nl, cr) : Math.max(nl, cr);
15
+ if (idx >= 0) {
16
+ cleanup();
17
+ const line = buf.slice(0, idx);
18
+ resolve(line);
19
+ }
20
+ };
21
+ const onError = (err) => {
22
+ cleanup();
23
+ reject(err instanceof Error ? err : new Error(String(err)));
24
+ };
25
+ const onEnd = () => {
26
+ cleanup();
27
+ resolve(buf.replace(/[\r\n]+$/, ""));
28
+ };
29
+ const cleanup = () => {
30
+ opts.input.off("data", onData);
31
+ opts.input.off("error", onError);
32
+ opts.input.off("end", onEnd);
33
+ };
34
+ opts.input.on("data", onData);
35
+ opts.input.on("error", onError);
36
+ opts.input.on("end", onEnd);
37
+ opts.input.resume?.();
38
+ });
39
+ }
40
+ async function readMaskedLine(opts) {
41
+ const maskChar = opts.maskChar ?? "*";
42
+ opts.output.write(opts.prompt);
43
+ try {
44
+ opts.setRawMode?.(true);
45
+ }
46
+ catch {
47
+ // ignore: not a TTY / no raw mode support
48
+ }
49
+ return new Promise((resolve, reject) => {
50
+ let value = "";
51
+ let done = false;
52
+ const finish = () => {
53
+ if (done)
54
+ return;
55
+ done = true;
56
+ cleanup();
57
+ try {
58
+ opts.setRawMode?.(false);
59
+ }
60
+ catch {
61
+ // ignore
62
+ }
63
+ resolve(value);
64
+ };
65
+ const fail = (err) => {
66
+ if (done)
67
+ return;
68
+ done = true;
69
+ cleanup();
70
+ try {
71
+ opts.setRawMode?.(false);
72
+ }
73
+ catch {
74
+ // ignore
75
+ }
76
+ reject(err instanceof Error ? err : new Error(String(err)));
77
+ };
78
+ const onData = (chunk) => {
79
+ const s = Buffer.isBuffer(chunk) ? chunk.toString("utf8") : chunk;
80
+ for (const ch of s) {
81
+ // Ctrl-C
82
+ if (ch === "\u0003")
83
+ return fail(new Error("Canceled"));
84
+ // Enter
85
+ if (ch === "\r" || ch === "\n") {
86
+ opts.output.write("\n");
87
+ return finish();
88
+ }
89
+ // Backspace (DEL or BS)
90
+ if (ch === "\u007f" || ch === "\b") {
91
+ if (value.length > 0) {
92
+ value = value.slice(0, -1);
93
+ // Erase one masked char.
94
+ opts.output.write("\b \b");
95
+ }
96
+ continue;
97
+ }
98
+ value += ch;
99
+ opts.output.write(maskChar);
100
+ }
101
+ };
102
+ const onError = (err) => fail(err);
103
+ const onEnd = () => finish();
104
+ const cleanup = () => {
105
+ opts.input.off("data", onData);
106
+ opts.input.off("error", onError);
107
+ opts.input.off("end", onEnd);
108
+ };
109
+ opts.input.on("data", onData);
110
+ opts.input.on("error", onError);
111
+ opts.input.on("end", onEnd);
112
+ opts.input.resume?.();
113
+ });
114
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@smart-tinker/kayla",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "Telegram -> Claude Code CLI orchestrator (Z.AI backend configured in Claude Code).",
5
5
  "license": "MIT",
6
6
  "repository": {