kadai 0.5.0 → 0.8.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/README.md +15 -2
- package/dist/cli.js +355 -227
- package/dist/exports/ink.js +3 -0
- package/dist/exports/jsx-dev-runtime.js +3 -0
- package/dist/exports/jsx-runtime.js +3 -0
- package/dist/exports/react.js +7 -0
- package/dist/exports/ui.js +3 -0
- package/dist/types.js +1 -0
- package/package.json +10 -1
package/README.md
CHANGED
|
@@ -7,12 +7,25 @@
|
|
|
7
7
|
3. Share them with your team in the repo.
|
|
8
8
|
4. Automatically make them discoverable by AI.
|
|
9
9
|
|
|
10
|
+
## Prerequisites
|
|
11
|
+
|
|
12
|
+
kadai requires [Bun](https://bun.sh) as its runtime.
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
# macOS / Linux
|
|
16
|
+
curl -fsSL https://bun.sh/install | bash
|
|
17
|
+
|
|
18
|
+
# Homebrew
|
|
19
|
+
brew install oven-sh/bun/bun
|
|
20
|
+
|
|
21
|
+
# Windows
|
|
22
|
+
powershell -c "irm bun.sh/install.ps1 | iex"
|
|
23
|
+
```
|
|
24
|
+
|
|
10
25
|
## Getting Started
|
|
11
26
|
|
|
12
27
|
```bash
|
|
13
28
|
bunx kadai
|
|
14
|
-
# OR
|
|
15
|
-
npx kadai
|
|
16
29
|
```
|
|
17
30
|
|
|
18
31
|
On first run, kadai creates a `.kadai/` directory with a sample action and config file. Run it again to open the interactive menu.
|
package/dist/cli.js
CHANGED
|
@@ -29,14 +29,67 @@ var __export = (target, all) => {
|
|
|
29
29
|
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
30
30
|
var __require = import.meta.require;
|
|
31
31
|
|
|
32
|
+
// src/core/shared-deps.ts
|
|
33
|
+
import { existsSync, mkdirSync, symlinkSync, unlinkSync } from "fs";
|
|
34
|
+
import { dirname, join } from "path";
|
|
35
|
+
function registerSharedDeps() {
|
|
36
|
+
const escaped = SHARED_DEPS.map((d) => d.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"));
|
|
37
|
+
const filter = new RegExp(`^(${escaped.join("|")})(/.*)?$`);
|
|
38
|
+
Bun.plugin({
|
|
39
|
+
name: "kadai-shared-deps",
|
|
40
|
+
setup(build) {
|
|
41
|
+
build.onResolve({ filter }, (args) => {
|
|
42
|
+
try {
|
|
43
|
+
return { path: __require.resolve(args.path) };
|
|
44
|
+
} catch {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
function ensureKadaiResolvable(projectNodeModules) {
|
|
52
|
+
const link = join(projectNodeModules, "kadai");
|
|
53
|
+
if (existsSync(link))
|
|
54
|
+
return null;
|
|
55
|
+
const kadaiRoot = dirname(import.meta.dir);
|
|
56
|
+
if (!existsSync(join(kadaiRoot, "package.json")))
|
|
57
|
+
return null;
|
|
58
|
+
try {
|
|
59
|
+
if (!existsSync(projectNodeModules)) {
|
|
60
|
+
mkdirSync(projectNodeModules, { recursive: true });
|
|
61
|
+
}
|
|
62
|
+
symlinkSync(kadaiRoot, link);
|
|
63
|
+
} catch {
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
let cleaned = false;
|
|
67
|
+
const cleanup = () => {
|
|
68
|
+
if (cleaned)
|
|
69
|
+
return;
|
|
70
|
+
cleaned = true;
|
|
71
|
+
try {
|
|
72
|
+
unlinkSync(link);
|
|
73
|
+
} catch {}
|
|
74
|
+
};
|
|
75
|
+
process.on("exit", cleanup);
|
|
76
|
+
process.on("SIGTERM", cleanup);
|
|
77
|
+
process.on("SIGINT", cleanup);
|
|
78
|
+
return cleanup;
|
|
79
|
+
}
|
|
80
|
+
var SHARED_DEPS;
|
|
81
|
+
var init_shared_deps = __esm(() => {
|
|
82
|
+
SHARED_DEPS = ["ink", "react", "@inkjs/ui"];
|
|
83
|
+
});
|
|
84
|
+
|
|
32
85
|
// src/core/config.ts
|
|
33
86
|
var exports_config = {};
|
|
34
87
|
__export(exports_config, {
|
|
35
88
|
loadConfig: () => loadConfig
|
|
36
89
|
});
|
|
37
|
-
import { join } from "path";
|
|
90
|
+
import { join as join2 } from "path";
|
|
38
91
|
async function loadConfig(kadaiDir) {
|
|
39
|
-
const configPath =
|
|
92
|
+
const configPath = join2(kadaiDir, "config.ts");
|
|
40
93
|
const configFile = Bun.file(configPath);
|
|
41
94
|
if (!await configFile.exists()) {
|
|
42
95
|
return { ...DEFAULT_CONFIG };
|
|
@@ -150,7 +203,7 @@ var init_metadata = __esm(() => {
|
|
|
150
203
|
|
|
151
204
|
// src/core/loader.ts
|
|
152
205
|
import { readdir } from "fs/promises";
|
|
153
|
-
import { join as
|
|
206
|
+
import { join as join3 } from "path";
|
|
154
207
|
async function readShebang(filePath) {
|
|
155
208
|
try {
|
|
156
209
|
const head = await Bun.file(filePath).slice(0, 256).text();
|
|
@@ -192,7 +245,7 @@ async function getGitAddedDates(dir) {
|
|
|
192
245
|
if (/^\d+$/.test(trimmed)) {
|
|
193
246
|
currentTimestamp = Number.parseInt(trimmed, 10) * 1000;
|
|
194
247
|
} else {
|
|
195
|
-
const absPath =
|
|
248
|
+
const absPath = join3(repoRoot, trimmed);
|
|
196
249
|
dates.set(absPath, currentTimestamp);
|
|
197
250
|
}
|
|
198
251
|
}
|
|
@@ -218,7 +271,7 @@ async function scanDirectory(baseDir, currentDir, category, actions, depth, gitD
|
|
|
218
271
|
for (const entry of entries) {
|
|
219
272
|
if (entry.name.startsWith("_") || entry.name.startsWith("."))
|
|
220
273
|
continue;
|
|
221
|
-
const fullPath =
|
|
274
|
+
const fullPath = join3(currentDir, entry.name);
|
|
222
275
|
if (entry.isDirectory()) {
|
|
223
276
|
await scanDirectory(baseDir, fullPath, [...category, entry.name], actions, depth + 1, gitDates, origin);
|
|
224
277
|
} else if (entry.isFile()) {
|
|
@@ -247,15 +300,15 @@ async function scanDirectory(baseDir, currentDir, category, actions, depth, gitD
|
|
|
247
300
|
function findZcliDir(cwd) {
|
|
248
301
|
let dir = cwd;
|
|
249
302
|
while (true) {
|
|
250
|
-
const candidate =
|
|
251
|
-
if (Bun.file(
|
|
303
|
+
const candidate = join3(dir, ".kadai");
|
|
304
|
+
if (Bun.file(join3(candidate, "actions")).name) {
|
|
252
305
|
try {
|
|
253
306
|
const stat = __require("fs").statSync(candidate);
|
|
254
307
|
if (stat.isDirectory())
|
|
255
308
|
return candidate;
|
|
256
309
|
} catch {}
|
|
257
310
|
}
|
|
258
|
-
const parent =
|
|
311
|
+
const parent = join3(dir, "..");
|
|
259
312
|
if (parent === dir)
|
|
260
313
|
break;
|
|
261
314
|
dir = parent;
|
|
@@ -276,9 +329,24 @@ var init_loader = __esm(() => {
|
|
|
276
329
|
]);
|
|
277
330
|
});
|
|
278
331
|
|
|
332
|
+
// src/core/last-action.ts
|
|
333
|
+
import { join as join4 } from "path";
|
|
334
|
+
async function saveLastAction(kadaiDir, actionId) {
|
|
335
|
+
await Bun.write(join4(kadaiDir, LAST_ACTION_FILE), actionId);
|
|
336
|
+
}
|
|
337
|
+
async function loadLastAction(kadaiDir) {
|
|
338
|
+
const file = Bun.file(join4(kadaiDir, LAST_ACTION_FILE));
|
|
339
|
+
if (!await file.exists())
|
|
340
|
+
return null;
|
|
341
|
+
const content = (await file.text()).trim();
|
|
342
|
+
return content || null;
|
|
343
|
+
}
|
|
344
|
+
var LAST_ACTION_FILE = ".last-action";
|
|
345
|
+
var init_last_action = () => {};
|
|
346
|
+
|
|
279
347
|
// src/core/fetchers/github.ts
|
|
280
348
|
import { mkdir, rm } from "fs/promises";
|
|
281
|
-
import { join as
|
|
349
|
+
import { join as join5 } from "path";
|
|
282
350
|
async function fetchGithubPlugin(source, destDir) {
|
|
283
351
|
const ref = source.ref ?? "main";
|
|
284
352
|
const repoUrl = `https://github.com/${source.github}.git`;
|
|
@@ -296,7 +364,7 @@ async function fetchGithubPlugin(source, destDir) {
|
|
|
296
364
|
});
|
|
297
365
|
const sha = (await new Response(shaProc.stdout).text()).trim();
|
|
298
366
|
await shaProc.exited;
|
|
299
|
-
await rm(
|
|
367
|
+
await rm(join5(destDir, ".git"), { recursive: true, force: true });
|
|
300
368
|
return { resolvedVersion: sha };
|
|
301
369
|
}
|
|
302
370
|
async function checkGithubUpdate(source, currentSha) {
|
|
@@ -321,29 +389,25 @@ async function checkGithubUpdate(source, currentSha) {
|
|
|
321
389
|
}
|
|
322
390
|
var init_github = () => {};
|
|
323
391
|
|
|
324
|
-
// src/core/
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
const withoutPrerelease = v.replace(/^v/, "").split("-")[0] ?? "";
|
|
329
|
-
const clean = withoutPrerelease.split("+")[0] ?? "";
|
|
330
|
-
const parts = clean.split(".");
|
|
331
|
-
if (parts.length !== 3)
|
|
392
|
+
// src/core/semver.ts
|
|
393
|
+
function parseSemver(version) {
|
|
394
|
+
const match = version.match(/^(\d+)\.(\d+)\.(\d+)/);
|
|
395
|
+
if (!match)
|
|
332
396
|
return null;
|
|
333
|
-
|
|
334
|
-
if (nums.some((n) => Number.isNaN(n)))
|
|
335
|
-
return null;
|
|
336
|
-
return nums;
|
|
397
|
+
return [Number(match[1]), Number(match[2]), Number(match[3])];
|
|
337
398
|
}
|
|
338
399
|
function compareSemver(a, b) {
|
|
339
400
|
for (let i = 0;i < 3; i++) {
|
|
340
|
-
const
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
return av - bv;
|
|
401
|
+
const diff = a[i] - b[i];
|
|
402
|
+
if (diff !== 0)
|
|
403
|
+
return diff;
|
|
344
404
|
}
|
|
345
405
|
return 0;
|
|
346
406
|
}
|
|
407
|
+
|
|
408
|
+
// src/core/fetchers/npm.ts
|
|
409
|
+
import { mkdir as mkdir2, unlink } from "fs/promises";
|
|
410
|
+
import { join as join6 } from "path";
|
|
347
411
|
function satisfies(version, range) {
|
|
348
412
|
if (range === "*" || range === "x")
|
|
349
413
|
return true;
|
|
@@ -417,7 +481,7 @@ async function fetchNpmPlugin(source, destDir) {
|
|
|
417
481
|
}
|
|
418
482
|
await mkdir2(destDir, { recursive: true });
|
|
419
483
|
const tarball = await tarballRes.arrayBuffer();
|
|
420
|
-
const tarballPath =
|
|
484
|
+
const tarballPath = join6(destDir, ".plugin.tgz");
|
|
421
485
|
await Bun.write(tarballPath, tarball);
|
|
422
486
|
const proc = Bun.spawn(["tar", "xzf", tarballPath, "--strip-components=1"], {
|
|
423
487
|
cwd: destDir,
|
|
@@ -457,9 +521,9 @@ var init_which = __esm(() => {
|
|
|
457
521
|
});
|
|
458
522
|
|
|
459
523
|
// src/core/pm.ts
|
|
460
|
-
import { join as
|
|
524
|
+
import { join as join7 } from "path";
|
|
461
525
|
async function resolvePM(dir) {
|
|
462
|
-
const pkgJsonPath =
|
|
526
|
+
const pkgJsonPath = join7(dir, "package.json");
|
|
463
527
|
try {
|
|
464
528
|
const file = Bun.file(pkgJsonPath);
|
|
465
529
|
if (await file.exists()) {
|
|
@@ -489,13 +553,13 @@ var init_pm = __esm(() => {
|
|
|
489
553
|
});
|
|
490
554
|
|
|
491
555
|
// src/core/plugins.ts
|
|
492
|
-
import { existsSync } from "fs";
|
|
556
|
+
import { existsSync as existsSync2 } from "fs";
|
|
493
557
|
import { mkdir as mkdir3, rm as rm2 } from "fs/promises";
|
|
494
|
-
import { isAbsolute, join as
|
|
558
|
+
import { isAbsolute, join as join8, resolve } from "path";
|
|
495
559
|
async function ensurePluginCacheDir(kadaiDir) {
|
|
496
|
-
const cacheDir =
|
|
560
|
+
const cacheDir = join8(kadaiDir, ".cache", "plugins");
|
|
497
561
|
await mkdir3(cacheDir, { recursive: true });
|
|
498
|
-
const gitignorePath =
|
|
562
|
+
const gitignorePath = join8(kadaiDir, ".cache", ".gitignore");
|
|
499
563
|
const gitignoreFile = Bun.file(gitignorePath);
|
|
500
564
|
if (!await gitignoreFile.exists()) {
|
|
501
565
|
await Bun.write(gitignorePath, `*
|
|
@@ -522,7 +586,7 @@ function pluginDisplayName(source) {
|
|
|
522
586
|
}
|
|
523
587
|
async function readPluginMeta(cacheDir) {
|
|
524
588
|
try {
|
|
525
|
-
const file = Bun.file(
|
|
589
|
+
const file = Bun.file(join8(cacheDir, ".plugin-meta.json"));
|
|
526
590
|
if (!await file.exists())
|
|
527
591
|
return null;
|
|
528
592
|
return await file.json();
|
|
@@ -531,18 +595,18 @@ async function readPluginMeta(cacheDir) {
|
|
|
531
595
|
}
|
|
532
596
|
}
|
|
533
597
|
async function writePluginMeta(cacheDir, meta) {
|
|
534
|
-
await Bun.write(
|
|
598
|
+
await Bun.write(join8(cacheDir, ".plugin-meta.json"), JSON.stringify(meta, null, 2));
|
|
535
599
|
}
|
|
536
600
|
async function loadCachedPlugins(kadaiDir, plugins) {
|
|
537
601
|
const allActions = [];
|
|
538
|
-
const cacheBase =
|
|
602
|
+
const cacheBase = join8(kadaiDir, ".cache", "plugins");
|
|
539
603
|
for (const source of plugins) {
|
|
540
604
|
if ("path" in source)
|
|
541
605
|
continue;
|
|
542
606
|
const key = cacheKeyFor(source);
|
|
543
|
-
const pluginCacheDir =
|
|
544
|
-
const actionsDir =
|
|
545
|
-
if (!
|
|
607
|
+
const pluginCacheDir = join8(cacheBase, key);
|
|
608
|
+
const actionsDir = join8(pluginCacheDir, "actions");
|
|
609
|
+
if (!existsSync2(actionsDir))
|
|
546
610
|
continue;
|
|
547
611
|
const name = pluginDisplayName(source);
|
|
548
612
|
const origin = { type: "plugin", pluginName: name };
|
|
@@ -556,8 +620,8 @@ async function loadCachedPlugins(kadaiDir, plugins) {
|
|
|
556
620
|
return allActions;
|
|
557
621
|
}
|
|
558
622
|
async function installPluginDeps(pluginDir) {
|
|
559
|
-
const pkgJsonPath =
|
|
560
|
-
if (!
|
|
623
|
+
const pkgJsonPath = join8(pluginDir, "package.json");
|
|
624
|
+
if (!existsSync2(pkgJsonPath))
|
|
561
625
|
return;
|
|
562
626
|
const pm = await resolvePM(pluginDir);
|
|
563
627
|
const proc = Bun.spawn(pm.install, {
|
|
@@ -574,7 +638,7 @@ async function installPluginDeps(pluginDir) {
|
|
|
574
638
|
async function syncPlugin(kadaiDir, source) {
|
|
575
639
|
const cacheBase = await ensurePluginCacheDir(kadaiDir);
|
|
576
640
|
const key = cacheKeyFor(source);
|
|
577
|
-
const pluginCacheDir =
|
|
641
|
+
const pluginCacheDir = join8(cacheBase, key);
|
|
578
642
|
const meta = await readPluginMeta(pluginCacheDir);
|
|
579
643
|
if (meta) {
|
|
580
644
|
let needsUpdate = false;
|
|
@@ -624,8 +688,8 @@ async function syncPlugins(kadaiDir, plugins, callbacks) {
|
|
|
624
688
|
}
|
|
625
689
|
async function loadPathPlugin(kadaiDir, source) {
|
|
626
690
|
const pluginRoot = isAbsolute(source.path) ? source.path : resolve(kadaiDir, source.path);
|
|
627
|
-
const actionsDir =
|
|
628
|
-
if (!
|
|
691
|
+
const actionsDir = join8(pluginRoot, "actions");
|
|
692
|
+
if (!existsSync2(actionsDir))
|
|
629
693
|
return [];
|
|
630
694
|
const name = source.path;
|
|
631
695
|
const origin = { type: "plugin", pluginName: name };
|
|
@@ -640,8 +704,8 @@ async function loadUserGlobalActions() {
|
|
|
640
704
|
const homeDir = process.env.HOME ?? process.env.USERPROFILE ?? "";
|
|
641
705
|
if (!homeDir)
|
|
642
706
|
return [];
|
|
643
|
-
const actionsDir =
|
|
644
|
-
if (!
|
|
707
|
+
const actionsDir = join8(homeDir, ".kadai", "actions");
|
|
708
|
+
if (!existsSync2(actionsDir))
|
|
645
709
|
return [];
|
|
646
710
|
const origin = { type: "plugin", pluginName: "~" };
|
|
647
711
|
const actions = await loadActions(actionsDir, origin);
|
|
@@ -729,13 +793,14 @@ var exports_commands = {};
|
|
|
729
793
|
__export(exports_commands, {
|
|
730
794
|
handleSync: () => handleSync,
|
|
731
795
|
handleRun: () => handleRun,
|
|
796
|
+
handleRerun: () => handleRerun,
|
|
732
797
|
handleList: () => handleList
|
|
733
798
|
});
|
|
734
|
-
import { join as
|
|
799
|
+
import { join as join9 } from "path";
|
|
735
800
|
async function handleList(options) {
|
|
736
801
|
const { kadaiDir, all } = options;
|
|
737
802
|
const config = await loadConfig(kadaiDir);
|
|
738
|
-
const actionsDir =
|
|
803
|
+
const actionsDir = join9(kadaiDir, config.actionsDir ?? "actions");
|
|
739
804
|
let actions = await loadActions(actionsDir);
|
|
740
805
|
const globalActions = await loadUserGlobalActions();
|
|
741
806
|
actions = [...actions, ...globalActions];
|
|
@@ -768,7 +833,7 @@ async function handleList(options) {
|
|
|
768
833
|
async function handleRun(options) {
|
|
769
834
|
const { kadaiDir, actionId, cwd } = options;
|
|
770
835
|
const config = await loadConfig(kadaiDir);
|
|
771
|
-
const actionsDir =
|
|
836
|
+
const actionsDir = join9(kadaiDir, config.actionsDir ?? "actions");
|
|
772
837
|
let actions = await loadActions(actionsDir);
|
|
773
838
|
const globalActions = await loadUserGlobalActions();
|
|
774
839
|
actions = [...actions, ...globalActions];
|
|
@@ -788,7 +853,9 @@ async function handleRun(options) {
|
|
|
788
853
|
`);
|
|
789
854
|
process.exit(1);
|
|
790
855
|
}
|
|
856
|
+
await saveLastAction(kadaiDir, actionId);
|
|
791
857
|
if (action.runtime === "ink") {
|
|
858
|
+
const cleanupKadai = ensureKadaiResolvable(join9(cwd, "node_modules"));
|
|
792
859
|
const mod = await import(action.filePath);
|
|
793
860
|
if (typeof mod.default !== "function") {
|
|
794
861
|
process.stderr.write(`Error: "${action.filePath}" does not export a default function component
|
|
@@ -806,6 +873,7 @@ async function handleRun(options) {
|
|
|
806
873
|
}));
|
|
807
874
|
await instance.waitUntilExit();
|
|
808
875
|
cleanupFullscreen?.();
|
|
876
|
+
cleanupKadai?.();
|
|
809
877
|
process.exit(0);
|
|
810
878
|
}
|
|
811
879
|
const cmd = resolveCommand(action);
|
|
@@ -829,6 +897,16 @@ async function handleRun(options) {
|
|
|
829
897
|
const exitCode = await proc.exited;
|
|
830
898
|
process.exit(exitCode);
|
|
831
899
|
}
|
|
900
|
+
async function handleRerun(options) {
|
|
901
|
+
const { kadaiDir, cwd } = options;
|
|
902
|
+
const actionId = await loadLastAction(kadaiDir);
|
|
903
|
+
if (!actionId) {
|
|
904
|
+
process.stderr.write(`No last action found. Run an action first before using --rerun.
|
|
905
|
+
`);
|
|
906
|
+
process.exit(1);
|
|
907
|
+
}
|
|
908
|
+
return handleRun({ kadaiDir, actionId, cwd });
|
|
909
|
+
}
|
|
832
910
|
async function handleSync(options) {
|
|
833
911
|
const { kadaiDir } = options;
|
|
834
912
|
const config = await loadConfig(kadaiDir);
|
|
@@ -875,6 +953,8 @@ All plugins synced.
|
|
|
875
953
|
var init_commands = __esm(() => {
|
|
876
954
|
init_config();
|
|
877
955
|
init_loader();
|
|
956
|
+
init_last_action();
|
|
957
|
+
init_shared_deps();
|
|
878
958
|
init_plugins();
|
|
879
959
|
init_runner();
|
|
880
960
|
});
|
|
@@ -883,11 +963,20 @@ var init_commands = __esm(() => {
|
|
|
883
963
|
var require_package = __commonJS((exports, module) => {
|
|
884
964
|
module.exports = {
|
|
885
965
|
name: "kadai",
|
|
886
|
-
version: "0.
|
|
966
|
+
version: "0.8.0",
|
|
887
967
|
type: "module",
|
|
888
968
|
bin: {
|
|
889
969
|
kadai: "./dist/cli.js"
|
|
890
970
|
},
|
|
971
|
+
exports: {
|
|
972
|
+
".": "./dist/cli.js",
|
|
973
|
+
"./types": "./dist/types.js",
|
|
974
|
+
"./ink": "./dist/exports/ink.js",
|
|
975
|
+
"./ui": "./dist/exports/ui.js",
|
|
976
|
+
"./react": "./dist/exports/react.js",
|
|
977
|
+
"./react/jsx-runtime": "./dist/exports/jsx-runtime.js",
|
|
978
|
+
"./react/jsx-dev-runtime": "./dist/exports/jsx-dev-runtime.js"
|
|
979
|
+
},
|
|
891
980
|
scripts: {
|
|
892
981
|
build: "bun build.ts",
|
|
893
982
|
check: "tsc --noEmit && biome check ./src ./test",
|
|
@@ -924,7 +1013,7 @@ __export(exports_mcp, {
|
|
|
924
1013
|
ensureMcpConfig: () => ensureMcpConfig,
|
|
925
1014
|
actionIdToToolName: () => actionIdToToolName
|
|
926
1015
|
});
|
|
927
|
-
import { join as
|
|
1016
|
+
import { join as join10, resolve as resolve2 } from "path";
|
|
928
1017
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
929
1018
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
930
1019
|
function resolveInvocationCommand() {
|
|
@@ -951,40 +1040,35 @@ function buildToolDescription(action) {
|
|
|
951
1040
|
return parts.join(" ");
|
|
952
1041
|
}
|
|
953
1042
|
async function ensureMcpConfig(projectRoot) {
|
|
954
|
-
const mcpJsonPath =
|
|
1043
|
+
const mcpJsonPath = join10(projectRoot, ".mcp.json");
|
|
955
1044
|
const mcpFile = Bun.file(mcpJsonPath);
|
|
956
1045
|
const kadaiEntry = resolveInvocationCommand();
|
|
957
1046
|
if (await mcpFile.exists()) {
|
|
958
1047
|
const existing = await mcpFile.json();
|
|
959
1048
|
if (existing.mcpServers?.kadai) {
|
|
960
|
-
|
|
961
|
-
`);
|
|
962
|
-
return;
|
|
1049
|
+
return false;
|
|
963
1050
|
}
|
|
964
1051
|
existing.mcpServers = existing.mcpServers ?? {};
|
|
965
1052
|
existing.mcpServers.kadai = kadaiEntry;
|
|
966
1053
|
await Bun.write(mcpJsonPath, `${JSON.stringify(existing, null, 2)}
|
|
967
1054
|
`);
|
|
968
|
-
|
|
969
|
-
`);
|
|
970
|
-
} else {
|
|
971
|
-
const config = {
|
|
972
|
-
mcpServers: {
|
|
973
|
-
kadai: kadaiEntry
|
|
974
|
-
}
|
|
975
|
-
};
|
|
976
|
-
await Bun.write(mcpJsonPath, `${JSON.stringify(config, null, 2)}
|
|
977
|
-
`);
|
|
978
|
-
process.stderr.write(`Created .mcp.json with kadai MCP server config
|
|
979
|
-
`);
|
|
1055
|
+
return true;
|
|
980
1056
|
}
|
|
1057
|
+
const config = {
|
|
1058
|
+
mcpServers: {
|
|
1059
|
+
kadai: kadaiEntry
|
|
1060
|
+
}
|
|
1061
|
+
};
|
|
1062
|
+
await Bun.write(mcpJsonPath, `${JSON.stringify(config, null, 2)}
|
|
1063
|
+
`);
|
|
1064
|
+
return true;
|
|
981
1065
|
}
|
|
982
1066
|
async function startMcpServer(kadaiDir, cwd) {
|
|
983
1067
|
let visibleActions = [];
|
|
984
1068
|
let config = {};
|
|
985
1069
|
if (kadaiDir) {
|
|
986
1070
|
config = await loadConfig(kadaiDir);
|
|
987
|
-
const actionsDir =
|
|
1071
|
+
const actionsDir = join10(kadaiDir, config.actionsDir ?? "actions");
|
|
988
1072
|
let allActions = await loadActions(actionsDir);
|
|
989
1073
|
const globalActions = await loadUserGlobalActions();
|
|
990
1074
|
allActions = [...allActions, ...globalActions];
|
|
@@ -1051,6 +1135,173 @@ var init_mcp = __esm(() => {
|
|
|
1051
1135
|
init_runner();
|
|
1052
1136
|
});
|
|
1053
1137
|
|
|
1138
|
+
// src/core/init-wizard.ts
|
|
1139
|
+
var exports_init_wizard = {};
|
|
1140
|
+
__export(exports_init_wizard, {
|
|
1141
|
+
writeInitFiles: () => writeInitFiles,
|
|
1142
|
+
generateConfigFile: () => generateConfigFile,
|
|
1143
|
+
ensureClaudeIntegration: () => ensureClaudeIntegration
|
|
1144
|
+
});
|
|
1145
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync2 } from "fs";
|
|
1146
|
+
import { join as join11 } from "path";
|
|
1147
|
+
function generateConfigFile() {
|
|
1148
|
+
const lines = [' // actionsDir: "actions",', " // env: {},"];
|
|
1149
|
+
return `export default {
|
|
1150
|
+
${lines.join(`
|
|
1151
|
+
`)}
|
|
1152
|
+
};
|
|
1153
|
+
`;
|
|
1154
|
+
}
|
|
1155
|
+
async function writeInitFiles(cwd) {
|
|
1156
|
+
const kadaiDir = join11(cwd, ".kadai");
|
|
1157
|
+
const actionsDir = join11(kadaiDir, "actions");
|
|
1158
|
+
mkdirSync2(actionsDir, { recursive: true });
|
|
1159
|
+
const sampleAction = join11(actionsDir, "hello.sh");
|
|
1160
|
+
const sampleFile = Bun.file(sampleAction);
|
|
1161
|
+
let sampleCreated = false;
|
|
1162
|
+
if (!await sampleFile.exists()) {
|
|
1163
|
+
await Bun.write(sampleAction, `#!/bin/bash
|
|
1164
|
+
# kadai:name Hello World
|
|
1165
|
+
# kadai:emoji \uD83D\uDC4B
|
|
1166
|
+
# kadai:description A sample action \u2014 edit or delete this file
|
|
1167
|
+
|
|
1168
|
+
echo "Hello from kadai!"
|
|
1169
|
+
echo "Add your own scripts to .kadai/actions/ to get started."
|
|
1170
|
+
`);
|
|
1171
|
+
sampleCreated = true;
|
|
1172
|
+
}
|
|
1173
|
+
const gitignorePath = join11(kadaiDir, ".gitignore");
|
|
1174
|
+
if (!await Bun.file(gitignorePath).exists()) {
|
|
1175
|
+
await Bun.write(gitignorePath, `.last-action
|
|
1176
|
+
`);
|
|
1177
|
+
}
|
|
1178
|
+
const configContent = generateConfigFile();
|
|
1179
|
+
const configPath = join11(kadaiDir, "config.ts");
|
|
1180
|
+
await Bun.write(configPath, configContent);
|
|
1181
|
+
const integration = await ensureClaudeIntegration(cwd);
|
|
1182
|
+
return { sampleCreated, skillCreated: integration.skillCreated };
|
|
1183
|
+
}
|
|
1184
|
+
async function ensureClaudeIntegration(projectRoot) {
|
|
1185
|
+
const hasClaudeDir = existsSync3(join11(projectRoot, ".claude"));
|
|
1186
|
+
const hasClaudeMd = existsSync3(join11(projectRoot, "CLAUDE.md"));
|
|
1187
|
+
if (!hasClaudeDir && !hasClaudeMd) {
|
|
1188
|
+
return { skillCreated: false, mcpConfigured: false };
|
|
1189
|
+
}
|
|
1190
|
+
const skillCreated = await ensureSkillFile(projectRoot);
|
|
1191
|
+
const mcpConfigured = await ensureMcpJsonEntry(projectRoot);
|
|
1192
|
+
return { skillCreated, mcpConfigured };
|
|
1193
|
+
}
|
|
1194
|
+
async function ensureSkillFile(projectRoot) {
|
|
1195
|
+
const skillDir = join11(projectRoot, ".claude", "skills", "kadai");
|
|
1196
|
+
const skillPath = join11(skillDir, "SKILL.md");
|
|
1197
|
+
if (await Bun.file(skillPath).exists()) {
|
|
1198
|
+
return false;
|
|
1199
|
+
}
|
|
1200
|
+
mkdirSync2(skillDir, { recursive: true });
|
|
1201
|
+
await Bun.write(skillPath, generateSkillFile());
|
|
1202
|
+
return true;
|
|
1203
|
+
}
|
|
1204
|
+
async function ensureMcpJsonEntry(projectRoot) {
|
|
1205
|
+
const { ensureMcpConfig: ensureMcpConfig2 } = await Promise.resolve().then(() => (init_mcp(), exports_mcp));
|
|
1206
|
+
return await ensureMcpConfig2(projectRoot);
|
|
1207
|
+
}
|
|
1208
|
+
function generateSkillFile() {
|
|
1209
|
+
return `---
|
|
1210
|
+
name: kadai
|
|
1211
|
+
description: >-
|
|
1212
|
+
kadai is a script runner for this project. Discover available actions with
|
|
1213
|
+
kadai list --json, and run them with kadai run <action-id>.
|
|
1214
|
+
user-invocable: false
|
|
1215
|
+
---
|
|
1216
|
+
|
|
1217
|
+
# kadai \u2014 Project Script Runner
|
|
1218
|
+
|
|
1219
|
+
kadai manages and runs project-specific shell scripts stored in \`.kadai/actions/\`.
|
|
1220
|
+
|
|
1221
|
+
## Discovering Actions
|
|
1222
|
+
|
|
1223
|
+
\`\`\`bash
|
|
1224
|
+
kadai list --json
|
|
1225
|
+
\`\`\`
|
|
1226
|
+
|
|
1227
|
+
Returns a JSON array of available actions:
|
|
1228
|
+
|
|
1229
|
+
\`\`\`json
|
|
1230
|
+
[
|
|
1231
|
+
{
|
|
1232
|
+
"id": "database/reset",
|
|
1233
|
+
"name": "Reset Database",
|
|
1234
|
+
"emoji": "\uD83D\uDDD1\uFE0F",
|
|
1235
|
+
"description": "Drop and recreate the dev database",
|
|
1236
|
+
"category": ["database"],
|
|
1237
|
+
"runtime": "bash",
|
|
1238
|
+
"confirm": true
|
|
1239
|
+
}
|
|
1240
|
+
]
|
|
1241
|
+
\`\`\`
|
|
1242
|
+
|
|
1243
|
+
Use \`--all\` to include hidden actions: \`kadai list --json --all\`
|
|
1244
|
+
|
|
1245
|
+
Always use \`kadai list --json\` for the current set of actions \u2014 do not hardcode action lists.
|
|
1246
|
+
|
|
1247
|
+
## Running Actions
|
|
1248
|
+
|
|
1249
|
+
\`\`\`bash
|
|
1250
|
+
kadai run <action-id>
|
|
1251
|
+
\`\`\`
|
|
1252
|
+
|
|
1253
|
+
Runs the action and streams stdout/stderr directly. The process exits with the action's exit code.
|
|
1254
|
+
Confirmation prompts are automatically skipped in non-TTY environments.
|
|
1255
|
+
|
|
1256
|
+
### Examples
|
|
1257
|
+
|
|
1258
|
+
\`\`\`bash
|
|
1259
|
+
kadai run hello
|
|
1260
|
+
kadai run database/reset
|
|
1261
|
+
\`\`\`
|
|
1262
|
+
|
|
1263
|
+
## Creating Actions
|
|
1264
|
+
|
|
1265
|
+
Create a script file in \`.kadai/actions/\`. Supported extensions: \`.sh\`, \`.bash\`, \`.ts\`, \`.js\`, \`.mjs\`, \`.py\`, \`.tsx\`.
|
|
1266
|
+
|
|
1267
|
+
Add metadata as comments in the first 20 lines using \`# kadai:<key> <value>\` (for shell/python) or \`// kadai:<key> <value>\` (for JS/TS):
|
|
1268
|
+
|
|
1269
|
+
\`\`\`bash
|
|
1270
|
+
#!/bin/bash
|
|
1271
|
+
# kadai:name Deploy Staging
|
|
1272
|
+
# kadai:emoji \uD83D\uDE80
|
|
1273
|
+
# kadai:description Deploy the app to the staging environment
|
|
1274
|
+
# kadai:confirm true
|
|
1275
|
+
|
|
1276
|
+
echo "Deploying..."
|
|
1277
|
+
\`\`\`
|
|
1278
|
+
|
|
1279
|
+
Available metadata keys:
|
|
1280
|
+
|
|
1281
|
+
| Key | Description |
|
|
1282
|
+
|---------------|---------------------------------------------|
|
|
1283
|
+
| \`name\` | Display name in menus |
|
|
1284
|
+
| \`emoji\` | Emoji prefix |
|
|
1285
|
+
| \`description\` | Short description |
|
|
1286
|
+
| \`confirm\` | Require confirmation before running (true/false) |
|
|
1287
|
+
| \`hidden\` | Hide from default listing (true/false) |
|
|
1288
|
+
| \`fullscreen\` | Use alternate screen buffer for ink actions (true/false) |
|
|
1289
|
+
|
|
1290
|
+
If \`name\` is omitted, it is inferred from the filename (e.g. \`deploy-staging.sh\` \u2192 "Deploy Staging").
|
|
1291
|
+
|
|
1292
|
+
Organize actions into categories using subdirectories:
|
|
1293
|
+
|
|
1294
|
+
\`\`\`
|
|
1295
|
+
.kadai/actions/
|
|
1296
|
+
hello.sh \u2192 id: "hello"
|
|
1297
|
+
database/
|
|
1298
|
+
migrate.sh \u2192 id: "database/migrate"
|
|
1299
|
+
reset.ts \u2192 id: "database/reset"
|
|
1300
|
+
\`\`\`
|
|
1301
|
+
`;
|
|
1302
|
+
}
|
|
1303
|
+
var init_init_wizard = () => {};
|
|
1304
|
+
|
|
1054
1305
|
// src/components/Breadcrumbs.tsx
|
|
1055
1306
|
import { Box, Text } from "ink";
|
|
1056
1307
|
import { jsxDEV } from "react/jsx-dev-runtime";
|
|
@@ -1087,6 +1338,7 @@ var init_FullscreenProvider = () => {};
|
|
|
1087
1338
|
|
|
1088
1339
|
// src/components/InkActionRenderer.tsx
|
|
1089
1340
|
import { Box as Box2, Text as Text2 } from "ink";
|
|
1341
|
+
import { join as join12 } from "path";
|
|
1090
1342
|
import React, { useEffect, useState } from "react";
|
|
1091
1343
|
import { jsxDEV as jsxDEV3 } from "react/jsx-dev-runtime";
|
|
1092
1344
|
function InkActionRenderer({
|
|
@@ -1100,6 +1352,7 @@ function InkActionRenderer({
|
|
|
1100
1352
|
let cancelled = false;
|
|
1101
1353
|
(async () => {
|
|
1102
1354
|
try {
|
|
1355
|
+
ensureKadaiResolvable(join12(cwd, "node_modules"));
|
|
1103
1356
|
const mod = await import(action.filePath);
|
|
1104
1357
|
if (cancelled)
|
|
1105
1358
|
return;
|
|
@@ -1162,6 +1415,7 @@ function InkActionRenderer({
|
|
|
1162
1415
|
}
|
|
1163
1416
|
var InkActionErrorBoundary;
|
|
1164
1417
|
var init_InkActionRenderer = __esm(() => {
|
|
1418
|
+
init_shared_deps();
|
|
1165
1419
|
InkActionErrorBoundary = class InkActionErrorBoundary extends React.Component {
|
|
1166
1420
|
constructor(props) {
|
|
1167
1421
|
super(props);
|
|
@@ -1212,7 +1466,7 @@ function StatusBar() {
|
|
|
1212
1466
|
var init_StatusBar = () => {};
|
|
1213
1467
|
|
|
1214
1468
|
// src/hooks/useActions.ts
|
|
1215
|
-
import { join as
|
|
1469
|
+
import { join as join13 } from "path";
|
|
1216
1470
|
import { useEffect as useEffect2, useRef, useState as useState2 } from "react";
|
|
1217
1471
|
function useActions({ kadaiDir }) {
|
|
1218
1472
|
const [actions, setActions] = useState2([]);
|
|
@@ -1225,7 +1479,7 @@ function useActions({ kadaiDir }) {
|
|
|
1225
1479
|
(async () => {
|
|
1226
1480
|
const cfg = await loadConfig(kadaiDir);
|
|
1227
1481
|
setConfig(cfg);
|
|
1228
|
-
const actionsDir =
|
|
1482
|
+
const actionsDir = join13(kadaiDir, cfg.actionsDir ?? "actions");
|
|
1229
1483
|
const localActions = await loadActions(actionsDir);
|
|
1230
1484
|
let allActions = [...localActions];
|
|
1231
1485
|
const globalActions = await loadUserGlobalActions();
|
|
@@ -2267,6 +2521,7 @@ function MenuList({
|
|
|
2267
2521
|
}
|
|
2268
2522
|
const selected = i === selectedIndex;
|
|
2269
2523
|
return /* @__PURE__ */ jsxDEV5(Box4, {
|
|
2524
|
+
width: "100%",
|
|
2270
2525
|
children: [
|
|
2271
2526
|
/* @__PURE__ */ jsxDEV5(Text4, {
|
|
2272
2527
|
color: selected ? "cyan" : undefined,
|
|
@@ -2288,14 +2543,13 @@ function MenuList({
|
|
|
2288
2543
|
dimColor: true,
|
|
2289
2544
|
children: " \u27F3"
|
|
2290
2545
|
}, undefined, false, undefined, this),
|
|
2546
|
+
/* @__PURE__ */ jsxDEV5(Box4, {
|
|
2547
|
+
flexGrow: 1
|
|
2548
|
+
}, undefined, false, undefined, this),
|
|
2291
2549
|
item.description && /* @__PURE__ */ jsxDEV5(Text4, {
|
|
2292
2550
|
dimColor: true,
|
|
2293
|
-
children:
|
|
2294
|
-
|
|
2295
|
-
item.description,
|
|
2296
|
-
")"
|
|
2297
|
-
]
|
|
2298
|
-
}, undefined, true, undefined, this)
|
|
2551
|
+
children: item.description
|
|
2552
|
+
}, undefined, false, undefined, this)
|
|
2299
2553
|
]
|
|
2300
2554
|
}, `${i}-${item.value}`, true, undefined, this);
|
|
2301
2555
|
})
|
|
@@ -2548,153 +2802,8 @@ var init_app = __esm(() => {
|
|
|
2548
2802
|
SEVEN_DAYS_MS = 7 * 24 * 60 * 60 * 1000;
|
|
2549
2803
|
});
|
|
2550
2804
|
|
|
2551
|
-
// src/
|
|
2552
|
-
|
|
2553
|
-
__export(exports_init_wizard, {
|
|
2554
|
-
writeInitFiles: () => writeInitFiles,
|
|
2555
|
-
generateConfigFile: () => generateConfigFile
|
|
2556
|
-
});
|
|
2557
|
-
import { existsSync as existsSync2, mkdirSync } from "fs";
|
|
2558
|
-
import { join as join10 } from "path";
|
|
2559
|
-
function generateConfigFile() {
|
|
2560
|
-
const lines = [' // actionsDir: "actions",', " // env: {},"];
|
|
2561
|
-
return `export default {
|
|
2562
|
-
${lines.join(`
|
|
2563
|
-
`)}
|
|
2564
|
-
};
|
|
2565
|
-
`;
|
|
2566
|
-
}
|
|
2567
|
-
async function writeInitFiles(cwd) {
|
|
2568
|
-
const kadaiDir = join10(cwd, ".kadai");
|
|
2569
|
-
const actionsDir = join10(kadaiDir, "actions");
|
|
2570
|
-
mkdirSync(actionsDir, { recursive: true });
|
|
2571
|
-
const sampleAction = join10(actionsDir, "hello.sh");
|
|
2572
|
-
const sampleFile = Bun.file(sampleAction);
|
|
2573
|
-
let sampleCreated = false;
|
|
2574
|
-
if (!await sampleFile.exists()) {
|
|
2575
|
-
await Bun.write(sampleAction, `#!/bin/bash
|
|
2576
|
-
# kadai:name Hello World
|
|
2577
|
-
# kadai:emoji \uD83D\uDC4B
|
|
2578
|
-
# kadai:description A sample action \u2014 edit or delete this file
|
|
2579
|
-
|
|
2580
|
-
echo "Hello from kadai!"
|
|
2581
|
-
echo "Add your own scripts to .kadai/actions/ to get started."
|
|
2582
|
-
`);
|
|
2583
|
-
sampleCreated = true;
|
|
2584
|
-
}
|
|
2585
|
-
const configContent = generateConfigFile();
|
|
2586
|
-
const configPath = join10(kadaiDir, "config.ts");
|
|
2587
|
-
await Bun.write(configPath, configContent);
|
|
2588
|
-
let skillCreated = false;
|
|
2589
|
-
const hasClaudeDir = existsSync2(join10(cwd, ".claude"));
|
|
2590
|
-
const hasClaudeMd = existsSync2(join10(cwd, "CLAUDE.md"));
|
|
2591
|
-
if (hasClaudeDir || hasClaudeMd) {
|
|
2592
|
-
const skillDir = join10(cwd, ".claude", "skills", "kadai");
|
|
2593
|
-
const skillPath = join10(skillDir, "SKILL.md");
|
|
2594
|
-
if (!await Bun.file(skillPath).exists()) {
|
|
2595
|
-
mkdirSync(skillDir, { recursive: true });
|
|
2596
|
-
await Bun.write(skillPath, generateSkillFile());
|
|
2597
|
-
skillCreated = true;
|
|
2598
|
-
}
|
|
2599
|
-
}
|
|
2600
|
-
return { sampleCreated, skillCreated };
|
|
2601
|
-
}
|
|
2602
|
-
function generateSkillFile() {
|
|
2603
|
-
return `---
|
|
2604
|
-
name: kadai
|
|
2605
|
-
description: >-
|
|
2606
|
-
kadai is a script runner for this project. Discover available actions with
|
|
2607
|
-
kadai list --json, and run them with kadai run <action-id>.
|
|
2608
|
-
user-invocable: false
|
|
2609
|
-
---
|
|
2610
|
-
|
|
2611
|
-
# kadai \u2014 Project Script Runner
|
|
2612
|
-
|
|
2613
|
-
kadai manages and runs project-specific shell scripts stored in \`.kadai/actions/\`.
|
|
2614
|
-
|
|
2615
|
-
## Discovering Actions
|
|
2616
|
-
|
|
2617
|
-
\`\`\`bash
|
|
2618
|
-
kadai list --json
|
|
2619
|
-
\`\`\`
|
|
2620
|
-
|
|
2621
|
-
Returns a JSON array of available actions:
|
|
2622
|
-
|
|
2623
|
-
\`\`\`json
|
|
2624
|
-
[
|
|
2625
|
-
{
|
|
2626
|
-
"id": "database/reset",
|
|
2627
|
-
"name": "Reset Database",
|
|
2628
|
-
"emoji": "\uD83D\uDDD1\uFE0F",
|
|
2629
|
-
"description": "Drop and recreate the dev database",
|
|
2630
|
-
"category": ["database"],
|
|
2631
|
-
"runtime": "bash",
|
|
2632
|
-
"confirm": true
|
|
2633
|
-
}
|
|
2634
|
-
]
|
|
2635
|
-
\`\`\`
|
|
2636
|
-
|
|
2637
|
-
Use \`--all\` to include hidden actions: \`kadai list --json --all\`
|
|
2638
|
-
|
|
2639
|
-
Always use \`kadai list --json\` for the current set of actions \u2014 do not hardcode action lists.
|
|
2640
|
-
|
|
2641
|
-
## Running Actions
|
|
2642
|
-
|
|
2643
|
-
\`\`\`bash
|
|
2644
|
-
kadai run <action-id>
|
|
2645
|
-
\`\`\`
|
|
2646
|
-
|
|
2647
|
-
Runs the action and streams stdout/stderr directly. The process exits with the action's exit code.
|
|
2648
|
-
Confirmation prompts are automatically skipped in non-TTY environments.
|
|
2649
|
-
|
|
2650
|
-
### Examples
|
|
2651
|
-
|
|
2652
|
-
\`\`\`bash
|
|
2653
|
-
kadai run hello
|
|
2654
|
-
kadai run database/reset
|
|
2655
|
-
\`\`\`
|
|
2656
|
-
|
|
2657
|
-
## Creating Actions
|
|
2658
|
-
|
|
2659
|
-
Create a script file in \`.kadai/actions/\`. Supported extensions: \`.sh\`, \`.bash\`, \`.ts\`, \`.js\`, \`.mjs\`, \`.py\`, \`.tsx\`.
|
|
2660
|
-
|
|
2661
|
-
Add metadata as comments in the first 20 lines using \`# kadai:<key> <value>\` (for shell/python) or \`// kadai:<key> <value>\` (for JS/TS):
|
|
2662
|
-
|
|
2663
|
-
\`\`\`bash
|
|
2664
|
-
#!/bin/bash
|
|
2665
|
-
# kadai:name Deploy Staging
|
|
2666
|
-
# kadai:emoji \uD83D\uDE80
|
|
2667
|
-
# kadai:description Deploy the app to the staging environment
|
|
2668
|
-
# kadai:confirm true
|
|
2669
|
-
|
|
2670
|
-
echo "Deploying..."
|
|
2671
|
-
\`\`\`
|
|
2672
|
-
|
|
2673
|
-
Available metadata keys:
|
|
2674
|
-
|
|
2675
|
-
| Key | Description |
|
|
2676
|
-
|---------------|---------------------------------------------|
|
|
2677
|
-
| \`name\` | Display name in menus |
|
|
2678
|
-
| \`emoji\` | Emoji prefix |
|
|
2679
|
-
| \`description\` | Short description |
|
|
2680
|
-
| \`confirm\` | Require confirmation before running (true/false) |
|
|
2681
|
-
| \`hidden\` | Hide from default listing (true/false) |
|
|
2682
|
-
| \`fullscreen\` | Use alternate screen buffer for ink actions (true/false) |
|
|
2683
|
-
|
|
2684
|
-
If \`name\` is omitted, it is inferred from the filename (e.g. \`deploy-staging.sh\` \u2192 "Deploy Staging").
|
|
2685
|
-
|
|
2686
|
-
Organize actions into categories using subdirectories:
|
|
2687
|
-
|
|
2688
|
-
\`\`\`
|
|
2689
|
-
.kadai/actions/
|
|
2690
|
-
hello.sh \u2192 id: "hello"
|
|
2691
|
-
database/
|
|
2692
|
-
migrate.sh \u2192 id: "database/migrate"
|
|
2693
|
-
reset.ts \u2192 id: "database/reset"
|
|
2694
|
-
\`\`\`
|
|
2695
|
-
`;
|
|
2696
|
-
}
|
|
2697
|
-
var init_init_wizard = () => {};
|
|
2805
|
+
// src/cli.tsx
|
|
2806
|
+
init_shared_deps();
|
|
2698
2807
|
|
|
2699
2808
|
// src/core/args.ts
|
|
2700
2809
|
function parseArgs(argv) {
|
|
@@ -2705,6 +2814,9 @@ function parseArgs(argv) {
|
|
|
2705
2814
|
if (command === "--version" || command === "-v") {
|
|
2706
2815
|
return { type: "version" };
|
|
2707
2816
|
}
|
|
2817
|
+
if (command === "--rerun" || command === "-r") {
|
|
2818
|
+
return { type: "rerun" };
|
|
2819
|
+
}
|
|
2708
2820
|
switch (command) {
|
|
2709
2821
|
case "list": {
|
|
2710
2822
|
if (!argv.includes("--json")) {
|
|
@@ -2730,7 +2842,7 @@ function parseArgs(argv) {
|
|
|
2730
2842
|
default:
|
|
2731
2843
|
return {
|
|
2732
2844
|
type: "error",
|
|
2733
|
-
message: `Unknown command: ${command}. Available commands: list, run, sync, mcp, --version`
|
|
2845
|
+
message: `Unknown command: ${command}. Available commands: list, run, sync, mcp, --version, --rerun`
|
|
2734
2846
|
};
|
|
2735
2847
|
}
|
|
2736
2848
|
}
|
|
@@ -2738,6 +2850,8 @@ function parseArgs(argv) {
|
|
|
2738
2850
|
// src/cli.tsx
|
|
2739
2851
|
init_commands();
|
|
2740
2852
|
init_loader();
|
|
2853
|
+
init_last_action();
|
|
2854
|
+
registerSharedDeps();
|
|
2741
2855
|
var cwd = process.cwd();
|
|
2742
2856
|
var parsed = parseArgs(process.argv.slice(2));
|
|
2743
2857
|
if (parsed.type === "error") {
|
|
@@ -2758,17 +2872,22 @@ if (parsed.type === "mcp") {
|
|
|
2758
2872
|
await startMcpServer2(kadaiDir, cwd);
|
|
2759
2873
|
await new Promise(() => {});
|
|
2760
2874
|
}
|
|
2761
|
-
if (parsed.type === "list" || parsed.type === "run" || parsed.type === "sync") {
|
|
2875
|
+
if (parsed.type === "list" || parsed.type === "run" || parsed.type === "sync" || parsed.type === "rerun") {
|
|
2762
2876
|
const kadaiDir = findZcliDir(cwd);
|
|
2763
2877
|
if (!kadaiDir) {
|
|
2764
2878
|
process.stderr.write(`Error: No .kadai directory found. Run kadai to initialize.
|
|
2765
2879
|
`);
|
|
2766
2880
|
process.exit(1);
|
|
2767
2881
|
}
|
|
2882
|
+
const { dirname: dirname2 } = await import("path");
|
|
2883
|
+
const { ensureClaudeIntegration: ensureClaudeIntegration2 } = await Promise.resolve().then(() => (init_init_wizard(), exports_init_wizard));
|
|
2884
|
+
await ensureClaudeIntegration2(dirname2(kadaiDir));
|
|
2768
2885
|
if (parsed.type === "list") {
|
|
2769
2886
|
await handleList({ kadaiDir, all: parsed.all });
|
|
2770
2887
|
} else if (parsed.type === "run") {
|
|
2771
2888
|
await handleRun({ kadaiDir, actionId: parsed.actionId, cwd });
|
|
2889
|
+
} else if (parsed.type === "rerun") {
|
|
2890
|
+
await handleRerun({ kadaiDir, cwd });
|
|
2772
2891
|
} else {
|
|
2773
2892
|
const { handleSync: handleSync2 } = await Promise.resolve().then(() => (init_commands(), exports_commands));
|
|
2774
2893
|
await handleSync2({ kadaiDir });
|
|
@@ -2794,12 +2913,20 @@ if (!kadaiDir) {
|
|
|
2794
2913
|
console.log(" Created .kadai/config.ts");
|
|
2795
2914
|
if (result.sampleCreated)
|
|
2796
2915
|
console.log(" Created .kadai/actions/hello.sh");
|
|
2797
|
-
if (result.skillCreated)
|
|
2798
|
-
console.log(" Created .claude/skills/kadai/SKILL.md");
|
|
2799
2916
|
console.log(`
|
|
2800
2917
|
Done! Run kadai again to get started.`);
|
|
2801
2918
|
process.exit(0);
|
|
2802
2919
|
}
|
|
2920
|
+
{
|
|
2921
|
+
const { dirname: dirname2 } = await import("path");
|
|
2922
|
+
const { ensureClaudeIntegration: ensureClaudeIntegration2 } = await Promise.resolve().then(() => (init_init_wizard(), exports_init_wizard));
|
|
2923
|
+
const projectRoot = dirname2(kadaiDir);
|
|
2924
|
+
const ensured = await ensureClaudeIntegration2(projectRoot);
|
|
2925
|
+
if (ensured.skillCreated)
|
|
2926
|
+
console.log("Created .claude/skills/kadai/SKILL.md");
|
|
2927
|
+
if (ensured.mcpConfigured)
|
|
2928
|
+
console.log("Configured kadai in .mcp.json");
|
|
2929
|
+
}
|
|
2803
2930
|
function createStdinStream() {
|
|
2804
2931
|
if (process.stdin.isTTY) {
|
|
2805
2932
|
return process.stdin;
|
|
@@ -2881,6 +3008,7 @@ await instance.waitUntilExit();
|
|
|
2881
3008
|
if (!selectedAction)
|
|
2882
3009
|
process.exit(0);
|
|
2883
3010
|
var action = selectedAction;
|
|
3011
|
+
await saveLastAction(kadaiDir, action.id);
|
|
2884
3012
|
var config = await loadConfig2(kadaiDir);
|
|
2885
3013
|
var cmd = resolveCommand2(action);
|
|
2886
3014
|
var env = {
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
// @bun
|
package/package.json
CHANGED
|
@@ -1,10 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kadai",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"kadai": "./dist/cli.js"
|
|
7
7
|
},
|
|
8
|
+
"exports": {
|
|
9
|
+
".": "./dist/cli.js",
|
|
10
|
+
"./types": "./dist/types.js",
|
|
11
|
+
"./ink": "./dist/exports/ink.js",
|
|
12
|
+
"./ui": "./dist/exports/ui.js",
|
|
13
|
+
"./react": "./dist/exports/react.js",
|
|
14
|
+
"./react/jsx-runtime": "./dist/exports/jsx-runtime.js",
|
|
15
|
+
"./react/jsx-dev-runtime": "./dist/exports/jsx-dev-runtime.js"
|
|
16
|
+
},
|
|
8
17
|
"scripts": {
|
|
9
18
|
"build": "bun build.ts",
|
|
10
19
|
"check": "tsc --noEmit && biome check ./src ./test",
|