@smart-tinker/kayla 0.1.4 → 0.1.5

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
@@ -61,8 +61,30 @@ async function main(argv) {
61
61
  const username = node_os_1.default.userInfo().username;
62
62
  const paths = (0, setup_1.computeDefaultSetupPaths)(home);
63
63
  (0, setup_1.ensureXdgDirs)(paths);
64
+ const isTty = Boolean(process.stdin.isTTY && process.stdout.isTTY);
65
+ // If config exists and we're in a TTY, allow the user to overwrite it (default: No).
66
+ if (node_fs_1.default.existsSync(paths.configPath) && isTty) {
67
+ const answer = (await (0, tty_1.readLine)({
68
+ input: process.stdin,
69
+ output: process.stdout,
70
+ prompt: `Config file exists: ${paths.configPath}. Overwrite? (y/N): `
71
+ })).trim().toLowerCase();
72
+ const yes = answer === "y" || answer === "yes";
73
+ if (yes) {
74
+ const p = createPrompt();
75
+ try {
76
+ // Overwrite is explicitly interactive: do not silently take env values.
77
+ const inputs = await (0, setup_1.promptBootstrapInputs)(p.prompt);
78
+ const cfg = (0, setup_1.buildConfigFromBootstrapInputs)(paths, inputs);
79
+ (0, setup_1.overwriteConfigWithBackup)(paths.configPath, cfg);
80
+ }
81
+ finally {
82
+ p.close();
83
+ }
84
+ }
85
+ }
86
+ // First-time setup: create config if missing.
64
87
  if (!node_fs_1.default.existsSync(paths.configPath)) {
65
- const isTty = Boolean(process.stdin.isTTY && process.stdout.isTTY);
66
88
  const p = isTty ? createPrompt() : null;
67
89
  try {
68
90
  const res = await (0, setup_1.bootstrapConfig)(paths, process.env, { isTty, prompt: p?.prompt });
@@ -15,6 +15,8 @@ exports.promptBootstrapInputs = promptBootstrapInputs;
15
15
  exports.nonInteractiveSetupError = nonInteractiveSetupError;
16
16
  exports.bootstrapConfig = bootstrapConfig;
17
17
  exports.writeConfigIfMissing = writeConfigIfMissing;
18
+ exports.backupFileInPlace = backupFileInPlace;
19
+ exports.overwriteConfigWithBackup = overwriteConfigWithBackup;
18
20
  exports.ensureConfigValidOrThrow = ensureConfigValidOrThrow;
19
21
  exports.computeUnitEnvPath = computeUnitEnvPath;
20
22
  exports.ensurePathHasLocalBin = ensurePathHasLocalBin;
@@ -206,6 +208,29 @@ function writeConfigIfMissing(configPath, cfg) {
206
208
  node_fs_1.default.writeFileSync(configPath, raw, { mode: 0o600 });
207
209
  return { created: true };
208
210
  }
211
+ function backupFileInPlace(p, suffix) {
212
+ const dir = node_path_1.default.dirname(p);
213
+ const base = node_path_1.default.basename(p);
214
+ const backupPath = node_path_1.default.join(dir, `${base}.bak.${suffix}`);
215
+ node_fs_1.default.copyFileSync(p, backupPath);
216
+ try {
217
+ node_fs_1.default.chmodSync(backupPath, 0o600);
218
+ }
219
+ catch {
220
+ // best-effort
221
+ }
222
+ return backupPath;
223
+ }
224
+ function overwriteConfigWithBackup(configPath, cfg, now = new Date()) {
225
+ if (!node_fs_1.default.existsSync(configPath))
226
+ throw new Error(`Missing config file: ${configPath}`);
227
+ const pad2 = (n) => String(n).padStart(2, "0");
228
+ const suffix = `${now.getFullYear()}${pad2(now.getMonth() + 1)}${pad2(now.getDate())}-${pad2(now.getHours())}${pad2(now.getMinutes())}${pad2(now.getSeconds())}`;
229
+ // Backup first so we don't lose the old config if writing fails later.
230
+ backupFileInPlace(configPath, suffix);
231
+ const raw = yaml_1.default.stringify(cfg);
232
+ node_fs_1.default.writeFileSync(configPath, raw, { mode: 0o600 });
233
+ }
209
234
  function ensureConfigValidOrThrow(configPath) {
210
235
  if (!node_fs_1.default.existsSync(configPath))
211
236
  throw new Error(`Missing config file: ${configPath}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@smart-tinker/kayla",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "description": "Telegram -> Claude Code CLI orchestrator (Z.AI backend configured in Claude Code).",
5
5
  "license": "MIT",
6
6
  "repository": {