lokuma-cli 1.0.3 → 1.2.0

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/dist/index.js +123 -6
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -2,13 +2,14 @@
2
2
 
3
3
  // src/index.ts
4
4
  import { Command } from "commander";
5
- import { readFileSync as readFileSync2 } from "fs";
5
+ import { readFileSync as readFileSync3 } from "fs";
6
6
  import { fileURLToPath as fileURLToPath2 } from "url";
7
- import { dirname as dirname2, join as join2 } from "path";
7
+ import { dirname as dirname3, join as join3 } from "path";
8
8
 
9
9
  // src/commands/init.ts
10
10
  import { mkdir, writeFile, access } from "node:fs/promises";
11
11
  import { dirname, join } from "node:path";
12
+ import { homedir } from "node:os";
12
13
  import { readFileSync } from "node:fs";
13
14
  import { fileURLToPath } from "node:url";
14
15
  import chalk from "chalk";
@@ -31,6 +32,7 @@ var AI_TYPES = [
31
32
  "continue",
32
33
  "codebuddy",
33
34
  "droid",
35
+ "openclaw",
34
36
  "all"
35
37
  ];
36
38
  var AI_DISPLAY_NAMES = {
@@ -48,6 +50,7 @@ var AI_DISPLAY_NAMES = {
48
50
  continue: "Continue",
49
51
  codebuddy: "CodeBuddy",
50
52
  droid: "Droid (Factory)",
53
+ openclaw: "OpenClaw",
51
54
  all: "All assistants"
52
55
  };
53
56
  var AI_SKILL_PATHS = {
@@ -64,7 +67,9 @@ var AI_SKILL_PATHS = {
64
67
  opencode: { root: ".opencode", skillMd: ".opencode/OPENCODE.md", scriptPy: ".opencode/lokuma/scripts/search.py" },
65
68
  continue: { root: ".continue", skillMd: ".continue/lokuma/SKILL.md", scriptPy: ".continue/lokuma/scripts/search.py" },
66
69
  codebuddy: { root: ".codebuddy", skillMd: ".codebuddy/lokuma/SKILL.md", scriptPy: ".codebuddy/lokuma/scripts/search.py" },
67
- droid: { root: ".factory", skillMd: ".factory/skills/lokuma/SKILL.md", scriptPy: ".factory/skills/lokuma/scripts/search.py" }
70
+ droid: { root: ".factory", skillMd: ".factory/skills/lokuma/SKILL.md", scriptPy: ".factory/skills/lokuma/scripts/search.py" },
71
+ // OpenClaw installs to a fixed absolute path (not relative to cwd)
72
+ openclaw: { root: "~/.openclaw/workspace/skills/lokuma", skillMd: "~/.openclaw/workspace/skills/lokuma/SKILL.md", scriptPy: "~/.openclaw/workspace/skills/lokuma/scripts/search.py" }
68
73
  };
69
74
 
70
75
  // src/commands/init.ts
@@ -72,6 +77,10 @@ import { createRequire } from "node:module";
72
77
  var _require = createRequire(import.meta.url);
73
78
  var _pkgDir = dirname(dirname(fileURLToPath(import.meta.url)));
74
79
  var SEARCH_PY = readFileSync(join(_pkgDir, "assets", "search.py"), "utf-8");
80
+ function resolvePath(p) {
81
+ if (p.startsWith("~/")) return join(homedir(), p.slice(2));
82
+ return p;
83
+ }
75
84
  function buildSkillMd(scriptPath) {
76
85
  return `---
77
86
  name: lokuma
@@ -150,7 +159,11 @@ async function initCommand(options) {
150
159
  const installed = [];
151
160
  try {
152
161
  for (const t of targets) {
153
- const paths = AI_SKILL_PATHS[t];
162
+ const rawPaths = AI_SKILL_PATHS[t];
163
+ const paths = {
164
+ skillMd: resolvePath(rawPaths.skillMd),
165
+ scriptPy: resolvePath(rawPaths.scriptPy)
166
+ };
154
167
  if (!options.force && await exists(paths.skillMd)) {
155
168
  spinner.warn(`${AI_DISPLAY_NAMES[t]}: already installed (use --force to overwrite)`);
156
169
  spinner.start();
@@ -182,10 +195,110 @@ async function initCommand(options) {
182
195
  }
183
196
  }
184
197
 
198
+ // src/commands/auth.ts
199
+ import { writeFileSync, readFileSync as readFileSync2, existsSync, mkdirSync } from "node:fs";
200
+ import { dirname as dirname2, join as join2 } from "node:path";
201
+ import { createInterface } from "node:readline";
202
+ import chalk2 from "chalk";
203
+ function detectShellRc() {
204
+ const shell = process.env.SHELL ?? "";
205
+ const home = process.env.HOME ?? "";
206
+ if (shell.includes("zsh")) return join2(home, ".zshrc");
207
+ if (shell.includes("bash")) return process.platform === "darwin" ? join2(home, ".bash_profile") : join2(home, ".bashrc");
208
+ return join2(home, ".profile");
209
+ }
210
+ function persistKey(key) {
211
+ const rc = detectShellRc();
212
+ let content = existsSync(rc) ? readFileSync2(rc, "utf-8") : "";
213
+ content = content.replace(/\n?# Lokuma API key\nexport LOKUMA_API_KEY=.*\n?/g, "");
214
+ content += `
215
+ # Lokuma API key
216
+ export LOKUMA_API_KEY="${key}"
217
+ `;
218
+ writeFileSync(rc, content, "utf-8");
219
+ const envFile = join2(process.env.HOME ?? "", ".lokuma");
220
+ mkdirSync(dirname2(envFile), { recursive: true });
221
+ writeFileSync(envFile, `LOKUMA_API_KEY=${key}
222
+ `, "utf-8");
223
+ return rc;
224
+ }
225
+ async function prompt(question, hidden = false) {
226
+ return new Promise((resolve) => {
227
+ const rl = createInterface({
228
+ input: process.stdin,
229
+ output: hidden ? void 0 : process.stdout,
230
+ terminal: hidden
231
+ });
232
+ if (hidden) {
233
+ process.stdout.write(question);
234
+ process.stdin.setRawMode?.(true);
235
+ let input = "";
236
+ process.stdin.resume();
237
+ process.stdin.setEncoding("utf-8");
238
+ process.stdin.on("data", (char) => {
239
+ if (char === "\n" || char === "\r" || char === "") {
240
+ process.stdin.setRawMode?.(false);
241
+ process.stdout.write("\n");
242
+ rl.close();
243
+ resolve(input);
244
+ } else if (char === "") {
245
+ process.exit(0);
246
+ } else if (char === "\x7F") {
247
+ input = input.slice(0, -1);
248
+ } else {
249
+ input += char;
250
+ }
251
+ });
252
+ } else {
253
+ rl.question(question, (answer) => {
254
+ rl.close();
255
+ resolve(answer.trim());
256
+ });
257
+ }
258
+ });
259
+ }
260
+ async function authLoginCommand() {
261
+ console.log();
262
+ console.log(chalk2.bold(" Lokuma \u2014 API Key Setup"));
263
+ console.log(chalk2.dim(" Get your key at https://lokuma.ai"));
264
+ console.log();
265
+ const existing = process.env.LOKUMA_API_KEY;
266
+ if (existing) {
267
+ const masked = existing.slice(0, 10) + "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022";
268
+ console.log(chalk2.dim(` Current key: ${masked}`));
269
+ const overwrite = await prompt(" Overwrite? (y/N): ");
270
+ if (overwrite.toLowerCase() !== "y") {
271
+ console.log(chalk2.dim(" Keeping existing key."));
272
+ console.log();
273
+ return;
274
+ }
275
+ }
276
+ const key = await prompt(" Paste your API key: ", true);
277
+ if (!key) {
278
+ console.log(chalk2.yellow(" No key entered. Exiting."));
279
+ console.log();
280
+ return;
281
+ }
282
+ if (!key.startsWith("lokuma_")) {
283
+ console.log(chalk2.red(" \u2717 Invalid key format (should start with lokuma_)"));
284
+ console.log(chalk2.dim(" Visit https://lokuma.ai to get a valid key."));
285
+ console.log();
286
+ process.exit(1);
287
+ }
288
+ const rc = persistKey(key);
289
+ console.log();
290
+ console.log(chalk2.green(" \u2713 API key saved!"));
291
+ console.log(chalk2.dim(` Written to: ${rc}`));
292
+ console.log();
293
+ console.log(chalk2.dim(" Reload your shell to apply:"));
294
+ console.log(chalk2.cyan(` source ${rc}`));
295
+ console.log();
296
+ }
297
+
185
298
  // src/index.ts
186
299
  var __filename = fileURLToPath2(import.meta.url);
187
- var __dirname = dirname2(__filename);
188
- var pkg = JSON.parse(readFileSync2(join2(__dirname, "../package.json"), "utf-8"));
300
+ var __dirname = dirname3(__filename);
301
+ var pkg = JSON.parse(readFileSync3(join3(__dirname, "../package.json"), "utf-8"));
189
302
  var program = new Command();
190
303
  program.name("lokuma").description("Install Lokuma design intelligence skill for AI coding assistants").version(pkg.version);
191
304
  program.command("init").description("Install Lokuma skill to current project").option("-a, --ai <type>", `AI assistant type (${AI_TYPES.join(", ")})`).option("-f, --force", "Overwrite existing files").action(async (options) => {
@@ -199,4 +312,8 @@ program.command("init").description("Install Lokuma skill to current project").o
199
312
  force: options.force
200
313
  });
201
314
  });
315
+ var auth = program.command("auth").description("Manage authentication");
316
+ auth.command("login").description("Set or update your Lokuma API key").action(async () => {
317
+ await authLoginCommand();
318
+ });
202
319
  program.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lokuma-cli",
3
- "version": "1.0.3",
3
+ "version": "1.2.0",
4
4
  "description": "CLI to install Lokuma design intelligence skill for AI coding assistants",
5
5
  "type": "module",
6
6
  "bin": {