kiro-kit 0.3.5 → 0.3.7

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 CHANGED
@@ -16,7 +16,7 @@
16
16
  npx kiro-kit init
17
17
  ```
18
18
 
19
- Pick from 6 curated presets, confirm, and your `.kiro/` workspace is ready. Agents, skills, commands, hooks, workflows, MCP servers, statusline, and spec templates — all configured and bundled in the install.
19
+ Pick from 6 curated presets with an interactive selector — arrow keys to move, Enter to select, Enter again to confirm. Your `.kiro/` workspace is ready with agents, skills, commands, hooks, MCP servers, Powers recommendations, and spec templates.
20
20
 
21
21
  ```bash
22
22
  # or install globally
@@ -70,6 +70,17 @@ Every preset ships **self-contained**: agents, skills, commands, cross-platform
70
70
  --json Machine-readable output (list, info)
71
71
  ```
72
72
 
73
+ ## CLI Experience
74
+
75
+ The `kiro-kit init` command features a polished terminal UI:
76
+
77
+ - Purple gradient ASCII logo (figlet Slant font)
78
+ - Interactive preset selector with arrow keys, Enter to select, Enter x2 to confirm
79
+ - Live selected count indicator
80
+ - Task progress list with spinners
81
+ - Success summary box with file counts and next steps
82
+ - Graceful fallback for CI/non-TTY environments
83
+
73
84
  ## Kiro Powers Integration
74
85
 
75
86
  Each preset recommends curated [Kiro Powers](https://kiro.dev/powers/) from the marketplace, organized by priority:
package/dist/index.js CHANGED
@@ -11899,13 +11899,20 @@ function loadTerminalLink() {
11899
11899
 
11900
11900
  // src/ui/theme.ts
11901
11901
  var DEFAULT_PALETTE = {
11902
- primary: "#a970ff",
11903
- secondary: "#8bd5ff",
11904
- muted: "#6f6a7c",
11905
- text: "#f4f1ff",
11906
- danger: "#ff5c8a",
11907
- success: "#22c55e",
11908
- warn: "#f5b042"
11902
+ primary: "#c084fc",
11903
+ // violet-400 — bright purple
11904
+ secondary: "#818cf8",
11905
+ // indigo-400 — purple-blue
11906
+ muted: "#7c6f9f",
11907
+ // muted purple-gray
11908
+ text: "#f5f3ff",
11909
+ // near-white with purple tint
11910
+ danger: "#f472b6",
11911
+ // pink-400
11912
+ success: "#34d399",
11913
+ // emerald-400
11914
+ warn: "#fbbf24"
11915
+ // amber-400
11909
11916
  };
11910
11917
  var HEX_REGEX = /^#[0-9a-fA-F]{6}$/;
11911
11918
  function validatePalette(palette) {
@@ -11993,7 +12000,7 @@ async function createTheme(capability, palette) {
11993
12000
  return `${label} (${url})`;
11994
12001
  };
11995
12002
  return {
11996
- logoGradient: [merged.primary, merged.secondary],
12003
+ logoGradient: [merged.primary, "#a78bfa", merged.secondary, "#f472b6"],
11997
12004
  heading: headingFn,
11998
12005
  command: commandFn,
11999
12006
  flag: flagFn,
@@ -12014,17 +12021,15 @@ function createLogoSync(capability, theme, figlet, gradient) {
12014
12021
  let line = text;
12015
12022
  if (version) line += ` v${version}`;
12016
12023
  line = theme.heading(line);
12017
- if (subtitle) {
12018
- line += `
12024
+ if (subtitle) line += `
12019
12025
  ${theme.muted(subtitle)}`;
12020
- }
12021
12026
  return line;
12022
12027
  }
12023
12028
  function render(opts) {
12024
- const text = opts.text ?? "kiro-kit";
12025
- const font = opts.font ?? "ANSI Shadow";
12029
+ const font = opts.font ?? "Slant";
12026
12030
  const subtitle = opts.subtitle ?? "";
12027
12031
  const version = opts.version ?? "";
12032
+ const text = opts.text ?? "kiro-kit";
12028
12033
  if (capability.columns < 60 || !capability.unicode || figlet === null) {
12029
12034
  return renderCompact(opts);
12030
12035
  }
@@ -12049,9 +12054,7 @@ ${theme.muted(subtitle)}`;
12049
12054
  }
12050
12055
  if (subtitle || version) {
12051
12056
  let tagline = subtitle;
12052
- if (version) {
12053
- tagline += (subtitle ? " " : "") + `v${version}`;
12054
- }
12057
+ if (version) tagline += (subtitle ? " " : "") + `v${version}`;
12055
12058
  body += `
12056
12059
  ${theme.muted(tagline)}`;
12057
12060
  }
@@ -12070,11 +12073,16 @@ async function createLogo(capability, theme) {
12070
12073
 
12071
12074
  // src/ui/ThemedBox.ts
12072
12075
  var VARIANT_HEX = {
12073
- info: "#a970ff",
12074
- tip: "#8bd5ff",
12075
- success: "#22c55e",
12076
- warn: "#f5b042",
12077
- error: "#ff5c8a"
12076
+ info: "#c084fc",
12077
+ // violet-400
12078
+ tip: "#818cf8",
12079
+ // indigo-400
12080
+ success: "#34d399",
12081
+ // emerald-400
12082
+ warn: "#fbbf24",
12083
+ // amber-400
12084
+ error: "#f472b6"
12085
+ // pink-400
12078
12086
  };
12079
12087
  function drawAsciiBox(content, title, width, padding, colorBorder) {
12080
12088
  const innerWidth = width - 2;
@@ -12190,55 +12198,60 @@ async function createInitScreens(ctx) {
12190
12198
  createThemedBox(capability, theme)
12191
12199
  ]);
12192
12200
  function welcome(data) {
12201
+ const cols = capability.columns ?? 80;
12193
12202
  const logoStr = logo.render({
12194
12203
  text: "kiro-kit",
12195
- font: "ANSI Shadow",
12204
+ font: "Slant",
12196
12205
  version: data.cliVersion,
12197
12206
  subtitle: "Engineer-grade Kiro presets"
12198
12207
  });
12199
12208
  process.stdout.write(logoStr + "\n");
12200
- process.stdout.write("\n");
12201
- const tipBox = box.render(data.tipText, {
12202
- title: "Did you know?",
12203
- variant: "tip"
12204
- });
12205
- process.stdout.write(tipBox + "\n");
12206
- process.stdout.write("\n");
12207
- process.stdout.write(theme.heading("Available commands:") + "\n");
12209
+ const sep = capability.color ? "\x1B[38;2;124;111;159m" + "\u2500".repeat(Math.min(cols - 2, 72)) + "\x1B[0m" : "\u2500".repeat(Math.min(cols - 2, 72));
12210
+ process.stdout.write(sep + "\n\n");
12211
+ process.stdout.write(theme.heading("Commands") + "\n");
12212
+ const icons = {
12213
+ init: "\u25B6",
12214
+ add: "+",
12215
+ list: "\u2261",
12216
+ doctor: "\u2665"
12217
+ };
12208
12218
  for (const cmd of data.commands) {
12209
- const paddedName = theme.command(cmd.name.padEnd(20));
12219
+ const icon = capability.color ? "\x1B[38;2;192;132;252m" + (icons[cmd.name] ?? "\u25CF") + "\x1B[0m" : icons[cmd.name] ?? "-";
12220
+ const paddedName = theme.command(cmd.name.padEnd(10));
12210
12221
  const desc = theme.muted(cmd.description);
12211
- process.stdout.write(` ${paddedName}${desc}
12222
+ process.stdout.write(` ${icon} ${paddedName} ${desc}
12212
12223
  `);
12213
12224
  }
12214
12225
  process.stdout.write("\n");
12215
12226
  }
12216
12227
  function summary(data) {
12217
12228
  const lines = [];
12229
+ const check = capability.color ? "\x1B[38;2;52;211;153m\u2714\x1B[0m" : "[ok]";
12230
+ const bullet = capability.color ? "\x1B[38;2;192;132;252m\u2022\x1B[0m" : "-";
12218
12231
  lines.push(
12219
- `${theme.success(String(data.filesWritten))} files written, ${theme.muted(String(data.filesSkipped))} skipped`
12232
+ `${check} ${theme.success(String(data.filesWritten))} files written` + (data.filesSkipped > 0 ? `, ${theme.muted(String(data.filesSkipped) + " skipped")}` : "")
12220
12233
  );
12221
- lines.push(`Presets: ${theme.command(data.presets.join(", "))}`);
12234
+ lines.push(`${bullet} Presets: ${theme.command(data.presets.join(", "))}`);
12222
12235
  if (data.setupGuidePath !== void 0) {
12223
12236
  const safePath = sanitizePath(data.setupGuidePath);
12224
- lines.push(`Setup guide: ${theme.pathStyle(safePath)}`);
12237
+ lines.push(`${bullet} Setup guide: ${theme.pathStyle(safePath)}`);
12225
12238
  }
12226
12239
  if (data.envExamplePath !== void 0) {
12227
12240
  const safePath = sanitizePath(data.envExamplePath);
12228
- lines.push(`Env template: ${theme.pathStyle(safePath)}`);
12241
+ lines.push(`${bullet} Env template: ${theme.pathStyle(safePath)}`);
12229
12242
  }
12230
12243
  if (data.nextSteps.length > 0) {
12231
12244
  lines.push("");
12232
12245
  lines.push(theme.heading("Next steps:"));
12233
12246
  for (const step of data.nextSteps) {
12234
- lines.push(` ${theme.muted("\u2022")} ${step}`);
12247
+ lines.push(` ${bullet} ${step}`);
12235
12248
  }
12236
12249
  }
12237
12250
  lines.push("");
12238
- lines.push(theme.link("Docs", data.docsUrl));
12251
+ lines.push(` ${theme.muted("Docs:")} ${theme.link("github.com/ihatesea69/kiro-kit", data.docsUrl)}`);
12239
12252
  const content = lines.join("\n");
12240
12253
  const successBox = box.render(content, {
12241
- title: "Done!",
12254
+ title: " Done! ",
12242
12255
  variant: "success"
12243
12256
  });
12244
12257
  process.stdout.write("\n" + successBox + "\n");
@@ -12274,10 +12287,72 @@ async function createPrompt(capability, theme) {
12274
12287
  if (!process.stdin.readable) {
12275
12288
  return [];
12276
12289
  }
12290
+ let rawModeWorks = false;
12291
+ try {
12292
+ process.stdin.setRawMode(true);
12293
+ process.stdin.setRawMode(false);
12294
+ rawModeWorks = true;
12295
+ } catch {
12296
+ rawModeWorks = false;
12297
+ }
12298
+ if (rawModeWorks) {
12299
+ return multiPickRaw(items);
12300
+ } else {
12301
+ return multiPickLineMode(items);
12302
+ }
12303
+ }
12304
+ async function multiPickLineMode(items) {
12305
+ return new Promise((resolve2, reject) => {
12306
+ process.stdout.write("\n? Select presets to install (enter numbers separated by commas):\n\n");
12307
+ items.forEach((item, i) => {
12308
+ const num = String(i + 1).padStart(2);
12309
+ const name = item.name.padEnd(12);
12310
+ process.stdout.write(` ${num}. ${name} - ${item.description}
12311
+ `);
12312
+ });
12313
+ process.stdout.write("\nExample: 1,3 or 1-3 or all\n");
12314
+ process.stdout.write("Choice: ");
12315
+ const rl = readline2.createInterface({
12316
+ input: process.stdin,
12317
+ output: process.stdout,
12318
+ terminal: false
12319
+ });
12320
+ rl.once("line", (answer) => {
12321
+ rl.close();
12322
+ const a = answer.trim().toLowerCase();
12323
+ if (a === "all" || a === "a") {
12324
+ resolve2(items.map((item) => item.name));
12325
+ return;
12326
+ }
12327
+ const indices = /* @__PURE__ */ new Set();
12328
+ for (const part of a.split(",")) {
12329
+ const range = part.trim().split("-");
12330
+ if (range.length === 2) {
12331
+ const start = parseInt(range[0], 10);
12332
+ const end = parseInt(range[1], 10);
12333
+ if (!isNaN(start) && !isNaN(end)) {
12334
+ for (let i = start; i <= end; i++) indices.add(i - 1);
12335
+ }
12336
+ } else {
12337
+ const n = parseInt(part.trim(), 10);
12338
+ if (!isNaN(n)) indices.add(n - 1);
12339
+ }
12340
+ }
12341
+ const selected = [...indices].filter((i) => i >= 0 && i < items.length).map((i) => items[i].name);
12342
+ resolve2(selected);
12343
+ });
12344
+ rl.on("SIGINT", () => {
12345
+ rl.close();
12346
+ reject(new Error("SIGINT"));
12347
+ });
12348
+ });
12349
+ }
12350
+ async function multiPickRaw(items) {
12277
12351
  return new Promise((resolve2, reject) => {
12278
12352
  const selected = /* @__PURE__ */ new Set();
12279
12353
  let cursor = 0;
12280
12354
  let lineCount = 0;
12355
+ let lastEnterCursor = -1;
12281
12356
  const cols = process.stdout.columns ?? 80;
12282
12357
  const maxDescWidth = Math.max(0, cols - 23);
12283
12358
  const render = () => {
@@ -12286,8 +12361,14 @@ async function createPrompt(capability, theme) {
12286
12361
  }
12287
12362
  const lines = [];
12288
12363
  const heading = capability.color ? theme.heading("? Select presets to install:") : "? Select presets to install:";
12289
- const hint = capability.color ? theme.muted(" (Space to select, <a> toggle all, Enter to confirm)") : " (Space to select, <a> toggle all, Enter to confirm)";
12364
+ const hint = capability.color ? theme.muted(" (Up/Down: move Enter: select A: all Enter x2: confirm)") : " (Up/Down: move Enter: select A: all Enter x2: confirm)";
12290
12365
  lines.push(heading + hint);
12366
+ if (selected.size > 0) {
12367
+ const countLine = capability.color ? " " + theme.success(`${selected.size} selected`) + theme.muted(" \u2014 press Enter again to confirm") : ` ${selected.size} selected \u2014 press Enter again to confirm`;
12368
+ lines.push(countLine);
12369
+ } else {
12370
+ lines.push(capability.color ? theme.muted(" No presets selected yet") : " No presets selected yet");
12371
+ }
12291
12372
  for (let i = 0; i < items.length; i++) {
12292
12373
  const marker = cursor === i ? capability.color ? theme.command(">") : ">" : " ";
12293
12374
  const check = selected.has(i) ? capability.color ? "\x1B[32m[x]\x1B[0m" : "[x]" : "[ ]";
@@ -12324,11 +12405,13 @@ async function createPrompt(capability, theme) {
12324
12405
  const handleArrow = (seq) => {
12325
12406
  if (seq === "\x1B[A" || seq === "\x1BOA") {
12326
12407
  cursor = (cursor - 1 + items.length) % items.length;
12408
+ lastEnterCursor = -1;
12327
12409
  render();
12328
12410
  return true;
12329
12411
  }
12330
12412
  if (seq === "\x1B[B" || seq === "\x1BOB") {
12331
12413
  cursor = (cursor + 1) % items.length;
12414
+ lastEnterCursor = -1;
12332
12415
  render();
12333
12416
  return true;
12334
12417
  }
@@ -12361,14 +12444,25 @@ async function createPrompt(capability, theme) {
12361
12444
  return;
12362
12445
  }
12363
12446
  if (key === "\r" || key === "\n" || key === "\r\n") {
12364
- cleanup();
12365
- process.stdout.write("\n");
12366
- resolve2([...selected].map((i) => items[i].name));
12447
+ if (lastEnterCursor === cursor && selected.size > 0) {
12448
+ cleanup();
12449
+ process.stdout.write("\n");
12450
+ resolve2([...selected].map((i) => items[i].name));
12451
+ return;
12452
+ }
12453
+ if (selected.has(cursor)) {
12454
+ selected.delete(cursor);
12455
+ } else {
12456
+ selected.add(cursor);
12457
+ }
12458
+ lastEnterCursor = cursor;
12459
+ render();
12367
12460
  return;
12368
12461
  }
12369
12462
  if (key === " ") {
12370
12463
  if (selected.has(cursor)) selected.delete(cursor);
12371
12464
  else selected.add(cursor);
12465
+ lastEnterCursor = -1;
12372
12466
  render();
12373
12467
  return;
12374
12468
  }