@dadado/agent-kit-cli 4.2.4 → 4.4.1

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 +210 -30
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -897,6 +897,10 @@ var L0_ARTIFACTS = [
897
897
  source: ".cursor/commands/start-project.md",
898
898
  target: ".cursor/commands/start-project.md"
899
899
  },
900
+ {
901
+ source: ".cursor/commands/onboard.md",
902
+ target: ".cursor/commands/onboard.md"
903
+ },
900
904
  {
901
905
  source: ".cursor/commands/continue-plan.md",
902
906
  target: ".cursor/commands/continue-plan.md"
@@ -2163,6 +2167,27 @@ async function runScanner(rootDir) {
2163
2167
 
2164
2168
  // src/utils/prompts.ts
2165
2169
  import { cancel, confirm, isCancel, multiselect, select, text } from "@clack/prompts";
2170
+ var WORKSPACE_SKIN_MODE_DEFAULTS = {
2171
+ default: "autopilot",
2172
+ modes: {
2173
+ "continue-plan": "autopilot",
2174
+ "run-plan": "night-shift",
2175
+ "cli-run-plan": "ghost-runner"
2176
+ }
2177
+ };
2178
+ function workspaceSkinConfigFromChoice(choice) {
2179
+ if (choice.kind === "skip") return null;
2180
+ if (choice.kind === "mode-defaults")
2181
+ return { ...WORKSPACE_SKIN_MODE_DEFAULTS, modes: { ...WORKSPACE_SKIN_MODE_DEFAULTS.modes } };
2182
+ return {
2183
+ default: choice.id,
2184
+ modes: {
2185
+ "continue-plan": choice.id,
2186
+ "run-plan": choice.id,
2187
+ "cli-run-plan": choice.id
2188
+ }
2189
+ };
2190
+ }
2166
2191
  function ensureNotCancelled(value) {
2167
2192
  if (isCancel(value)) {
2168
2193
  cancel("Operation cancelled.");
@@ -2234,6 +2259,27 @@ async function askProjectManagement(existing = []) {
2234
2259
  })
2235
2260
  );
2236
2261
  }
2262
+ async function askWorkspaceSkin() {
2263
+ const value = ensureNotCancelled(
2264
+ await select({
2265
+ message: "Workspace skin for chat/CLI chrome? (optional)",
2266
+ initialValue: "mode-defaults",
2267
+ options: [
2268
+ {
2269
+ label: "Keep mode defaults (Autopilot/Night Shift/Ghost Runner per mode)",
2270
+ value: "mode-defaults"
2271
+ },
2272
+ { label: "Autopilot", value: "autopilot" },
2273
+ { label: "Night Shift", value: "night-shift" },
2274
+ { label: "Ghost Runner", value: "ghost-runner" },
2275
+ { label: "Skip for now", value: "skip" }
2276
+ ]
2277
+ })
2278
+ );
2279
+ if (value === "skip") return { kind: "skip" };
2280
+ if (value === "mode-defaults") return { kind: "mode-defaults" };
2281
+ return { kind: "skin", id: value };
2282
+ }
2237
2283
  async function runExistingProjectWizard(scan) {
2238
2284
  const ide = await askIdeAndPlan(scan.ide);
2239
2285
  const workflow = await askGitWorkflow(scan.git.workflow);
@@ -2244,6 +2290,7 @@ async function runExistingProjectWizard(scan) {
2244
2290
  initialValue: true
2245
2291
  })
2246
2292
  );
2293
+ const workspaceSkinChoice = await askWorkspaceSkin();
2247
2294
  return {
2248
2295
  rootDir: scan.rootDir,
2249
2296
  stack: scan.stack,
@@ -2261,7 +2308,8 @@ async function runExistingProjectWizard(scan) {
2261
2308
  "clean-code",
2262
2309
  "docs-repo",
2263
2310
  "ide-guide"
2264
- ]
2311
+ ],
2312
+ workspaceSkinChoice
2265
2313
  };
2266
2314
  }
2267
2315
  async function runGreenfieldWizard(scan) {
@@ -2320,6 +2368,7 @@ async function runGreenfieldWizard(scan) {
2320
2368
  initialValue: true
2321
2369
  })
2322
2370
  );
2371
+ const workspaceSkinChoice = await askWorkspaceSkin();
2323
2372
  return {
2324
2373
  rootDir: scan.rootDir,
2325
2374
  stack: {
@@ -2345,11 +2394,20 @@ async function runGreenfieldWizard(scan) {
2345
2394
  "clean-code",
2346
2395
  "docs-repo",
2347
2396
  "ide-guide"
2348
- ]
2397
+ ],
2398
+ workspaceSkinChoice
2349
2399
  };
2350
2400
  }
2351
2401
 
2352
2402
  // src/commands/init.ts
2403
+ async function mergeWorkspaceSkinConfig(rootDir, workspaceSkin) {
2404
+ const contextDir = path23.join(rootDir, ".cursor", "context");
2405
+ const configPath = path23.join(contextDir, "config.json");
2406
+ await ensureDir(contextDir);
2407
+ const existing = await readJson(configPath) ?? {};
2408
+ await writeJson(configPath, { ...existing, workspaceSkin });
2409
+ return configPath;
2410
+ }
2353
2411
  var initCommand = defineCommand5({
2354
2412
  meta: {
2355
2413
  name: "init",
@@ -2370,9 +2428,15 @@ var initCommand = defineCommand5({
2370
2428
  scan.isGreenfield ? "Empty repo detected (greenfield)." : "Existing project detected."
2371
2429
  );
2372
2430
  const profile = scan.isGreenfield ? await runGreenfieldWizard(scan) : await runExistingProjectWizard(scan);
2431
+ const { workspaceSkinChoice, ...profileToSave } = profile;
2373
2432
  const configPath = path23.join(scan.rootDir, ".cursor", "agent-kit.config.json");
2374
- await writeJson(configPath, profile);
2433
+ await writeJson(configPath, profileToSave);
2375
2434
  logger.success(`Profile saved in ${configPath}`);
2435
+ const skinConfig = workspaceSkinChoice !== void 0 ? workspaceSkinConfigFromChoice(workspaceSkinChoice) : null;
2436
+ if (skinConfig) {
2437
+ const contextConfigPath = await mergeWorkspaceSkinConfig(scan.rootDir, skinConfig);
2438
+ logger.success(`Workspace skin saved in ${contextConfigPath}`);
2439
+ }
2376
2440
  await generateFromProfile(profile);
2377
2441
  try {
2378
2442
  const registry = await resolveRegistryRoot({ cwd: scan.rootDir });
@@ -2395,7 +2459,7 @@ var initCommand = defineCommand5({
2395
2459
  }
2396
2460
  console.log("\nNext:");
2397
2461
  console.log(` Open this folder in Cursor: ${scan.rootDir}`);
2398
- console.log(" Run /start-project in chat");
2462
+ console.log(" Run /onboard in chat; then /start-project when you have a goal");
2399
2463
  console.log(" Optional: agent-kit status");
2400
2464
  outro("Setup completed.");
2401
2465
  }
@@ -2450,7 +2514,7 @@ function parsePackList(raw) {
2450
2514
  function printInstallNextSteps(projectRoot) {
2451
2515
  console.log("\nNext:");
2452
2516
  console.log(` Open this folder in Cursor: ${projectRoot}`);
2453
- console.log(" Run /start-project in chat");
2517
+ console.log(" Run /onboard in chat; then /start-project when you have a goal");
2454
2518
  console.log(" Optional: agent-kit status");
2455
2519
  }
2456
2520
  var installCommand = defineCommand6({
@@ -2517,7 +2581,7 @@ var installCommand = defineCommand6({
2517
2581
  });
2518
2582
 
2519
2583
  // src/commands/run-plan.ts
2520
- import path28 from "path";
2584
+ import path29 from "path";
2521
2585
  import { defineCommand as defineCommand7 } from "citty";
2522
2586
 
2523
2587
  // src/plan-loop/backends.ts
@@ -2603,7 +2667,7 @@ function listBackendIds() {
2603
2667
 
2604
2668
  // src/plan-loop/run-loop.ts
2605
2669
  import { mkdir as mkdir4, readFile as readFile10, rm, unlink } from "fs/promises";
2606
- import path27 from "path";
2670
+ import path28 from "path";
2607
2671
 
2608
2672
  // src/plan-loop/external-review.ts
2609
2673
  import { spawn as spawn3 } from "child_process";
@@ -2767,6 +2831,101 @@ function formatSentinelLine(sentinel) {
2767
2831
  return "";
2768
2832
  }
2769
2833
 
2834
+ // src/plan-loop/skin-banners.ts
2835
+ import path27 from "path";
2836
+ import {
2837
+ blue,
2838
+ cyan as cyan2,
2839
+ gray,
2840
+ green as green2,
2841
+ lightGray,
2842
+ lightGreen,
2843
+ magenta,
2844
+ red as red2,
2845
+ white,
2846
+ yellow as yellow2
2847
+ } from "kolorist";
2848
+ var CLI_RUN_PLAN_MODE = "cli-run-plan";
2849
+ var DEFAULT_CLI_SKIN_ID = "ghost-runner";
2850
+ var COLORS = {
2851
+ white,
2852
+ gray,
2853
+ green: green2,
2854
+ cyan: cyan2,
2855
+ magenta,
2856
+ yellow: yellow2,
2857
+ red: red2,
2858
+ blue,
2859
+ "light-green": lightGreen,
2860
+ lightgreen: lightGreen,
2861
+ "light-gray": lightGray,
2862
+ lightgray: lightGray
2863
+ };
2864
+ function resolveColor(name, fallback) {
2865
+ if (!name) return fallback;
2866
+ return COLORS[name.toLowerCase()] ?? fallback;
2867
+ }
2868
+ async function resolveCliSkinId(root) {
2869
+ try {
2870
+ const cfg = await readJson(
2871
+ path27.join(root, ".cursor", "context", "config.json")
2872
+ );
2873
+ const id = cfg?.workspaceSkin?.modes?.[CLI_RUN_PLAN_MODE];
2874
+ if (typeof id === "string" && id.trim()) return id.trim();
2875
+ } catch {
2876
+ }
2877
+ return DEFAULT_CLI_SKIN_ID;
2878
+ }
2879
+ async function loadSkinPack(root, skinId) {
2880
+ try {
2881
+ const skinPath = path27.join(root, "registry", "skins", "core", skinId, "skin.json");
2882
+ const pack = await readJson(skinPath);
2883
+ if (!pack || typeof pack.id !== "string") return null;
2884
+ return pack;
2885
+ } catch {
2886
+ return null;
2887
+ }
2888
+ }
2889
+ async function loadCliRunPlanSkin(root) {
2890
+ const id = await resolveCliSkinId(root);
2891
+ return loadSkinPack(root, id);
2892
+ }
2893
+ function createSkinBannerPrinter(skin) {
2894
+ if (!skin?.cliBanners) return null;
2895
+ const banners = skin.cliBanners;
2896
+ if (!banners.tickStart && !banners.tickEnd && !banners.phaseComplete) return null;
2897
+ const primary = resolveColor(skin.ansiPalette?.primary, white);
2898
+ const secondary = resolveColor(skin.ansiPalette?.secondary, gray);
2899
+ const accent = resolveColor(skin.ansiPalette?.accent, green2);
2900
+ return {
2901
+ tickStart(detail) {
2902
+ if (banners.tickStart) {
2903
+ console.log(`${accent(banners.tickStart)} ${primary(detail)}`);
2904
+ } else {
2905
+ console.log(primary(detail));
2906
+ }
2907
+ },
2908
+ tickEnd(detail) {
2909
+ if (!banners.tickEnd) return;
2910
+ const line = detail ? `${banners.tickEnd} ${detail}` : banners.tickEnd;
2911
+ console.log(secondary(line));
2912
+ },
2913
+ phaseComplete(detail) {
2914
+ if (!banners.phaseComplete) return;
2915
+ const line = detail ? `${banners.phaseComplete} ${detail}` : banners.phaseComplete;
2916
+ console.log(accent(line));
2917
+ },
2918
+ sleep(seconds) {
2919
+ console.log(secondary(`sleep ${seconds}s`));
2920
+ },
2921
+ stop(reason) {
2922
+ if (banners.tickEnd) {
2923
+ console.log(secondary(`${banners.tickEnd} ${reason}`));
2924
+ }
2925
+ }
2926
+ };
2927
+ }
2928
+
2770
2929
  // src/plan-loop/run-loop.ts
2771
2930
  var TICK_PROMPT = '/run-plan - single tick from the headless runner (agent-kit run-plan). Read .cursor/HANDOFF.md and the active plan in .cursor/plans/. Mark the next to-do as in_progress in the frontmatter, execute ONLY that to-do, mark completed and update HANDOFF. If there is a commitable diff: run /git-staging without asking for confirmation. NEVER /git-prod. Do NOT re-arm an internal Loop skill - the external runner starts the next agent. End the response with exactly one line: "LOOP_TICK_RESULT: continue" if implementable to-dos remain, or "LOOP_TICK_RESULT: stop - <reason>" (plan exhausted, external blocker, or human decision needed).';
2772
2931
  function stamp() {
@@ -2778,9 +2937,9 @@ function sleep(ms) {
2778
2937
  return new Promise((r) => setTimeout(r, ms));
2779
2938
  }
2780
2939
  async function runPlanLoop(opts) {
2781
- const plansDir = path27.join(opts.root, ".cursor", "plans");
2782
- const stopFile = path27.join(opts.root, ".cursor", "loop.stop");
2783
- const logDir = path27.join(opts.root, ".cursor", "loop-logs");
2940
+ const plansDir = path28.join(opts.root, ".cursor", "plans");
2941
+ const stopFile = path28.join(opts.root, ".cursor", "loop.stop");
2942
+ const logDir = path28.join(opts.root, ".cursor", "loop-logs");
2784
2943
  const planPath = await findActivePlanFile(plansDir);
2785
2944
  if (!planPath) {
2786
2945
  logger.error("No active plan in .cursor/plans/");
@@ -2799,9 +2958,14 @@ async function runPlanLoop(opts) {
2799
2958
  };
2800
2959
  process.on("SIGINT", onSigInt);
2801
2960
  try {
2802
- console.log(`Active plan: ${path27.basename(planPath)}`);
2961
+ const skin = await loadCliRunPlanSkin(opts.root);
2962
+ const banners = createSkinBannerPrinter(skin);
2963
+ console.log(`Active plan: ${path28.basename(planPath)}`);
2803
2964
  console.log(`Pending to-dos: ${await pending()} | max ticks: ${opts.maxTicks}`);
2804
2965
  console.log(`Backend: ${opts.backend.id}`);
2966
+ if (skin) {
2967
+ console.log(`CLI skin: ${skin.displayName ?? skin.id}`);
2968
+ }
2805
2969
  if (opts.dryRun) {
2806
2970
  console.log("--dry-run: no agent will be started. Tick prompt:");
2807
2971
  console.log(TICK_PROMPT);
@@ -2818,11 +2982,15 @@ async function runPlanLoop(opts) {
2818
2982
  while (true) {
2819
2983
  tick += 1;
2820
2984
  if (tick > opts.maxTicks) {
2821
- console.log(`Budget of ${opts.maxTicks} ticks reached - stopping. Run again to continue.`);
2985
+ const msg = `Budget of ${opts.maxTicks} ticks reached - stopping. Run again to continue.`;
2986
+ if (banners) banners.stop(msg);
2987
+ else console.log(msg);
2822
2988
  break;
2823
2989
  }
2824
2990
  if (await fileExists(stopFile)) {
2825
- console.log(`Stop file found (${stopFile}) - stopping.`);
2991
+ const msg = `Stop file found (${stopFile}) - stopping.`;
2992
+ if (banners) banners.stop(msg);
2993
+ else console.log(msg);
2826
2994
  try {
2827
2995
  await rm(stopFile, { force: true });
2828
2996
  } catch {
@@ -2835,10 +3003,12 @@ async function runPlanLoop(opts) {
2835
3003
  planExhausted = true;
2836
3004
  break;
2837
3005
  }
2838
- const logPath = path27.join(logDir, `tick-${stamp()}.log`);
2839
- const relLog = path27.relative(opts.root, logPath);
3006
+ const logPath = path28.join(logDir, `tick-${stamp()}.log`);
3007
+ const relLog = path28.relative(opts.root, logPath);
2840
3008
  console.log("");
2841
- console.log(`=== tick ${tick}/${opts.maxTicks} - pending: ${before} - log: ${relLog} ===`);
3009
+ const tickLine = `=== tick ${tick}/${opts.maxTicks} - pending: ${before} - log: ${relLog} ===`;
3010
+ if (banners) banners.tickStart(tickLine);
3011
+ else console.log(tickLine);
2842
3012
  let agentExit = 0;
2843
3013
  try {
2844
3014
  const result = await opts.backend.run({
@@ -2855,21 +3025,28 @@ async function runPlanLoop(opts) {
2855
3025
  try {
2856
3026
  const logText = await readFile10(logPath, "utf8");
2857
3027
  if (logText.includes("Too many MCP tools")) {
2858
- console.log(
2859
- "Too many MCP tools for the headless model - disable servers (cursor-agent mcp disable <id>) and run again."
2860
- );
3028
+ const msg = "Too many MCP tools for the headless model - disable servers (cursor-agent mcp disable <id>) and run again.";
3029
+ if (banners) banners.stop(msg);
3030
+ else console.log(msg);
2861
3031
  break;
2862
3032
  }
2863
3033
  } catch {
2864
3034
  }
2865
3035
  if (agentExit !== 0) {
2866
- console.log(
2867
- `${opts.backend.id} exited with code ${agentExit} - stopping. See log: ${logPath}`
2868
- );
3036
+ const msg = `${opts.backend.id} exited with code ${agentExit} - stopping. See log: ${logPath}`;
3037
+ if (banners) {
3038
+ banners.tickEnd(`exit ${agentExit}`);
3039
+ banners.stop(msg);
3040
+ } else {
3041
+ console.log(msg);
3042
+ }
2869
3043
  break;
2870
3044
  }
2871
3045
  const sentinel = await parseSentinelFromLogFile(logPath);
2872
3046
  const after = await pending();
3047
+ if (banners) {
3048
+ banners.tickEnd(`pending: ${after}`);
3049
+ }
2873
3050
  if (sentinel.kind === "continue") {
2874
3051
  } else if (sentinel.kind === "stop") {
2875
3052
  console.log(`Agent requested stop: ${formatSentinelLine(sentinel)}`);
@@ -2883,9 +3060,9 @@ async function runPlanLoop(opts) {
2883
3060
  `warn: tick without sentinel, but progress (${before} -> ${after}) - continuing.`
2884
3061
  );
2885
3062
  } else {
2886
- console.log(
2887
- `Tick without sentinel and no progress (${before} -> ${after}) - stopping for safety.`
2888
- );
3063
+ const msg = `Tick without sentinel and no progress (${before} -> ${after}) - stopping for safety.`;
3064
+ if (banners) banners.stop(msg);
3065
+ else console.log(msg);
2889
3066
  break;
2890
3067
  }
2891
3068
  if (after === 0) {
@@ -2894,13 +3071,16 @@ async function runPlanLoop(opts) {
2894
3071
  break;
2895
3072
  }
2896
3073
  if (opts.sleepSeconds > 0) {
3074
+ if (banners) banners.sleep(opts.sleepSeconds);
2897
3075
  await sleep(opts.sleepSeconds * 1e3);
2898
3076
  }
2899
3077
  }
2900
3078
  const pendingNow = await pending();
2901
3079
  console.log("");
3080
+ const finishDetail = `after ${tick} tick(s); pending: ${pendingNow}`;
3081
+ if (banners) banners.phaseComplete(finishDetail);
2902
3082
  console.log(
2903
- `Loop finished after ${tick} tick(s). Pending now: ${pendingNow}. Logs in ${path27.relative(opts.root, logDir)}/`
3083
+ `Loop finished after ${tick} tick(s). Pending now: ${pendingNow}. Logs in ${path28.relative(opts.root, logDir)}/`
2904
3084
  );
2905
3085
  if (planExhausted || shouldArmExternalPlanReview({ pending: pendingNow, stopReason })) {
2906
3086
  await armExternalPlanReview(opts.root);
@@ -2971,7 +3151,7 @@ var runPlanCommand = defineCommand7({
2971
3151
  return;
2972
3152
  }
2973
3153
  const code = await runPlanLoop({
2974
- root: path28.resolve(args.cwd),
3154
+ root: path29.resolve(args.cwd),
2975
3155
  maxTicks,
2976
3156
  sleepSeconds,
2977
3157
  model: args.model ? String(args.model) : void 0,
@@ -3005,7 +3185,7 @@ var scanCommand = defineCommand8({
3005
3185
  });
3006
3186
 
3007
3187
  // src/commands/status.ts
3008
- import path29 from "path";
3188
+ import path30 from "path";
3009
3189
  import { defineCommand as defineCommand9 } from "citty";
3010
3190
  var statusCommand = defineCommand9({
3011
3191
  meta: {
@@ -3025,7 +3205,7 @@ var statusCommand = defineCommand9({
3025
3205
  },
3026
3206
  async run({ args }) {
3027
3207
  const manifest = await loadAgentKitManifest(args.cwd);
3028
- const profilePath = path29.join(args.cwd, ".cursor", "agent-kit.config.json");
3208
+ const profilePath = path30.join(args.cwd, ".cursor", "agent-kit.config.json");
3029
3209
  const profile = await readJson(profilePath);
3030
3210
  if (args.json) {
3031
3211
  console.log(
@@ -3115,7 +3295,7 @@ var updateCommand = defineCommand10({
3115
3295
  var main = defineCommand11({
3116
3296
  meta: {
3117
3297
  name: "agent-kit",
3118
- description: "Developer bootstrapper for AI-assisted IDEs"
3298
+ description: "HITL framework for AI-assisted IDEs"
3119
3299
  },
3120
3300
  subCommands: {
3121
3301
  init: initCommand,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@dadado/agent-kit-cli",
3
- "version": "4.2.4",
4
- "description": "Agent Kit CLI — bootstraps AI-assisted IDEs with project-aware rules, skills, and context management",
3
+ "version": "4.4.1",
4
+ "description": "Agent Kit CLI: HITL framework install and tooling for AI-assisted IDEs (rules, skills, plan/handoff, context).",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "agent-kit": "./dist/index.js"