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.
- package/dist/index.js +123 -6
- 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
|
|
5
|
+
import { readFileSync as readFileSync3 } from "fs";
|
|
6
6
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
7
|
-
import { dirname as
|
|
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
|
|
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 =
|
|
188
|
-
var pkg = JSON.parse(
|
|
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();
|