@dadado/agent-kit-cli 5.0.0 → 5.1.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 CHANGED
@@ -72,8 +72,11 @@ var KNOWN_SHIPPED_OVERLAY_HASHES = /* @__PURE__ */ new Set([
72
72
  "004d98f557942677264d053dcd8335f2bbcf19c5591123ec16a7a2697cb88932",
73
73
  "05ee6ecde4215e33ace0ee152ffbf2cd885d2bd4b032900f0f0bb001d350ef0f",
74
74
  "082bdbc584be3f3d8aa6e9d7b9f4e076450f3ff48f9147a1deb557e31475036b",
75
+ "09850afc201eccb3e700cb934400d49c9cbe7510d4a546ee84ee519771a8200e",
75
76
  "0b5fe4729c3c68654434837630d775b847c082418f25b0b2c581700fe84b797a",
76
77
  "1106b279558b6a20f87951102f172a680976f3e6530855d5dad083e1f89b9ba3",
78
+ "12bed56b332406477cf546d9e8360d3cab129bd82a638bea356726d00a6847a3",
79
+ "13f6a0711a2fcadcc7f1b751772448517ce4871cdef6a0269fc26dad51ebe26d",
77
80
  "15566765ec95dad3bc3160f20ac910e01a13471df536e6d990f4b263700784a9",
78
81
  "1681e6cf7b80a67cd999b94b8b6e16eb8caed0e11b32905848ba733da956e902",
79
82
  "17818e47e06349ee35c1d8e1cc16e8bcbbbcc89c664014e9096e1f08c8567807",
@@ -83,6 +86,7 @@ var KNOWN_SHIPPED_OVERLAY_HASHES = /* @__PURE__ */ new Set([
83
86
  "1c5c1af87951367ad04bb6fa5b1d6ebaaefbc0ee95989b624cabf406a1869907",
84
87
  "1ded5c7b7eefc355fc1d17feb65ec472e35ed96076e47ce95f7bff5c1b84746c",
85
88
  "1e58e0d4f2e8459b95a40d1b1e72c5c85a87230cbde945840a84073fe3a20422",
89
+ "2280e3ca96129ab2de8a85a301df7c2b15ffaa6204b734ed3b1f303e0055c41d",
86
90
  "285668d08f1b15d96286d27e29cc4a67e126e097fb8a940bdde33ccf25bd2bcd",
87
91
  "2acdb148b07f3a4872b896da419af796fd3fefaace7ac79cdee0aab447004a83",
88
92
  "2cd7fc018a384b0188737259ecf593ce25b4b75cc38b3e410063ac91745894b9",
@@ -95,6 +99,7 @@ var KNOWN_SHIPPED_OVERLAY_HASHES = /* @__PURE__ */ new Set([
95
99
  "46a1dd4a07a2190ab9fb09abc05a3962277209f8e0c28033bb41450301474c86",
96
100
  "48a0d55e21132a305946b195db7f6b75da78d44a1d32166fb0c69bef4a5ffbe2",
97
101
  "4b62a46c74e5fa6a80283f21e8e6711958fbcd577051dc73ff4050643a031475",
102
+ "4ba6e319ac79455a7d2713674f64fabbc9cd401b5d26b1c0edbd19c27a52297e",
98
103
  "4bf23acbc9bd4e0f8468e61f4970e182600b72d9025d29e81ddbd83cb7b1710a",
99
104
  "4c5167d0ebde685f266dce32c516a7c43876e0520647b93f07f2e2147e6a7b2f",
100
105
  "4dc4efcd1b43c643d3889fb349df8d4964d0867c3a67eb67e2ec168fbb70fc75",
@@ -113,11 +118,16 @@ var KNOWN_SHIPPED_OVERLAY_HASHES = /* @__PURE__ */ new Set([
113
118
  "6994595e3a62edb6c518006a6bece6848c7077977c041439cf7c822b89304a14",
114
119
  "6a42e76fc038ca69ddad18541b8df161770c58980fefaf9e5e80d87407074bec",
115
120
  "6a9af9e8a95dbb279347166c43dcee245ca673f9687841086b49911c54944c26",
121
+ "99fdd85310e658a1c1b0e8f92257493409c28c3d693f24deeaa665861788e1e4",
122
+ // public registry SoT n8n-workflows/SKILL.md (em dash description)
116
123
  "6b66ed7747ea2d19cb457f5af656e3c07f9f563f7f32b3951fa4ae5f27f0ac46",
117
124
  "6dede0588274f5b44d833bcc696ec4776eb978ed24a20efdcc9c38caf3df1576",
118
125
  "71991a10972b8b956cae93c88517e31741c95e351814082df65e44f813590210",
126
+ "75ae3018a70ed838428c0e63e8b6901ac05bf1f1cf1845faa6f73c3940d22e4a",
119
127
  "75e591bfde61ca1ca3ca1303cc9bc487197af2f713c68f346a46e94ca9432fd5",
120
128
  "76ae85bbc336c6f435d9653e8f254ae49774b4ebaecf7335697115933eb8797c",
129
+ "76c4361e70a73276771e841e2c939253b4124d690a0fd25aff2a3ac636d8f4b0",
130
+ // mission-kit-comms/SKILL.md
121
131
  "79878f0f6f59d1a0b65d94011c0cafe7b6f8e03e89f568aa638b8ba7a2c34076",
122
132
  "8108b202c829627c3c2df33575016ebe942df42acf4f1cc393900be3b82b402c",
123
133
  "819b7bd3ba9e8bf12dcd4f81a76c98e48261b34c397f339b36d36eb364d9c3f4",
@@ -126,6 +136,7 @@ var KNOWN_SHIPPED_OVERLAY_HASHES = /* @__PURE__ */ new Set([
126
136
  "8a11c80b0fbf6c4aabf60eec05b8cca7dccf5bca472787a8afa3028fd8fbedfa",
127
137
  "8b25659727063013e8bf6d7925f815b2630c2919b21e6fdac354362bf122bfab",
128
138
  "8c7edbacc74b1431fbecb04c9857c0e7a9cb1578fc6ca6367be888dbcec3c98f",
139
+ "8d8d60e929ebf717eed3c1a29ee0de7c71ae917d125eb1b220a77220597281ed",
129
140
  "8ffc181bb152c68a3353309bfdc87c42bdb925b98675cdba959c0cdb90b2adea",
130
141
  "91ce0c933e3c8ee81927b8224f944ec5ce5445098a2ad154773092e3541dbf69",
131
142
  "9309af07a0a99a56143386b3ddd2a35fae29378fba3f6b4c9297a5d1c02a9724",
@@ -137,6 +148,7 @@ var KNOWN_SHIPPED_OVERLAY_HASHES = /* @__PURE__ */ new Set([
137
148
  "9ccf52fe53c6fa4d731650ab4928ce50e201fa34f3e174fee70e3d29867fef2a",
138
149
  "9d905aca0123f3018c81c579217104f1749d8da802f3837b2407fbad8f2d803f",
139
150
  "9e324c52c1a9d1ceee738bccf47da92910aca9f7a5a21cc41738d9573c414830",
151
+ "9eb457654167df562481637b25ecd91f0ff3c9282ba79409089d644d3b09b926",
140
152
  "a013a6a476160183d6457ff6c1c51ec228bdca359b11eb15cd9b7fc177a705db",
141
153
  "a08d04f8efa121ad498f96873778c22630c9172c07c216839e348cd0bb7c2292",
142
154
  "a7cd7058bcb6fbd962c37317fa16893bc86a270d0164af5a0e6f3f026aa408ad",
@@ -145,6 +157,8 @@ var KNOWN_SHIPPED_OVERLAY_HASHES = /* @__PURE__ */ new Set([
145
157
  "b5c7a10df90d209be07159b7ff9bfa24e869538a0b6026bb5ce79e1cdd5b2528",
146
158
  "bd9fd1efacbd132c5dafc12cd0cf2b651a2b1fab7b2d7a9ba4a3e44128097f48",
147
159
  "be964ff33a40280e13ce6071fb3e30ce87c374527efbb74c25c9d4534084a634",
160
+ "c245035b539e41e822fab8c74fcde3b18c45f4b9f26f1c8583fc9e7254249698",
161
+ "c794accc6668d74a739c982c1b63985a8be4be08afe3766214ab1e08d25ea95c",
148
162
  "c96d522be440fbb638dbe953cebf1bb31185c431ac2e14446369cfb7d155a951",
149
163
  "cf2bd11891b934484171fa705f470de284e3874402e1e487750735dbc7692857",
150
164
  "d0e3bf82efbe32c09761689802ffea7838046dbdd4803b88ead5ec3dfc7efb7e",
@@ -174,11 +188,13 @@ var KNOWN_SHIPPED_OVERLAY_HASHES = /* @__PURE__ */ new Set([
174
188
  "f061432a2606049717c0cbf098ef07b1da4df2b136c4cb9cdaa7ea44c876bcd6",
175
189
  "f061d36a1180293519fbb560bbf659c621bd90885e995fca6eaf2eda9e418a50",
176
190
  "f28731a82f4b394a5765fdefe2d1b667810831f6dcea400ca62bc66e1d65371c",
191
+ "f43a5484e39aca4e6af86e7f8d2941773cdc1c960838ad88ae3540c49a1097df",
177
192
  "f46c108457e4fe12953dca75b409e06fca9cb264baffabe0c0d04c89af471e56",
178
193
  "f6bc17efa746680a44bbc49be67ac3f924d9c306c6d937f9959c57a1d3c5b9af",
179
194
  "f981764422d468567b5aff31148dc659aeee22cb13dc0ecd873d737deaf07372",
180
195
  "fa306a0cdb0f40c817e32164cd03b946564a02b4b7f7c3f4f0b9513096584d28",
181
- "fa5cf460eb314437081f7cea30dc8041c0bd6fc3f560a74bc2d7be1bf07384b0"
196
+ "fa5cf460eb314437081f7cea30dc8041c0bd6fc3f560a74bc2d7be1bf07384b0",
197
+ "fc39ec6d8a22498697f968ffc0fe5f717bed97afd68f922c76a80ed1f10d6579"
182
198
  ]);
183
199
 
184
200
  // src/lifecycle/paths.ts
@@ -2270,7 +2286,7 @@ var KIT_ROOT_ENV_KEYS = Object.freeze(["MISSION_CONTROL_KIT_ROOT", "AGENT_KIT_HO
2270
2286
  var CONTEXT_CONFIG_REL = ".cursor/context/config.json";
2271
2287
  var CONFIG_PERSONA_IDS = Object.freeze(["autopilot", "night-shift", "ghost-runner"]);
2272
2288
  var CONFIG_PERSONA_MODES = Object.freeze(["continue-plan", "run-plan", "cli-run-plan"]);
2273
- var CONFIG_REVIEW_BACKENDS = Object.freeze(["claude"]);
2289
+ var CONFIG_REVIEW_BACKENDS = Object.freeze(["auto", "claude", "cursor"]);
2274
2290
  var CONFIG_REVIEW_MODES = Object.freeze(["paste", "autonomous"]);
2275
2291
  var CONFIG_REVIEW_PREFLIGHT = Object.freeze(["off", "warn", "block"]);
2276
2292
  function resolveContextConfigPath(repoRoot, fsHooks = {}) {
@@ -2367,6 +2383,14 @@ function applyDashboardOpenEnv(env, opts) {
2367
2383
  }
2368
2384
  return next;
2369
2385
  }
2386
+ function dashboardSpawnEnv(env, snapshotRoot, opts) {
2387
+ const root = path11.resolve(snapshotRoot);
2388
+ return applyDashboardOpenEnv({ ...env, MISSION_CONTROL_REPO_ROOT: root }, { ...opts, cwd: root });
2389
+ }
2390
+ function dashboardProcessTitle(snapshotRoot) {
2391
+ const base = path11.basename(path11.resolve(snapshotRoot)) || "workspace";
2392
+ return `Mission Control \xB7 ${base}`;
2393
+ }
2370
2394
  function bundledDashboardCandidates(filename, moduleUrl = import.meta.url) {
2371
2395
  const here = path11.dirname(fileURLToPath(moduleUrl));
2372
2396
  return [
@@ -2501,10 +2525,11 @@ var dashboardCommand = defineCommand4({
2501
2525
  process.exitCode = 1;
2502
2526
  return;
2503
2527
  }
2504
- const env = applyDashboardOpenEnv(
2505
- { ...process.env, MISSION_CONTROL_REPO_ROOT: snapshotRoot },
2506
- { noOpen: Boolean(args["no-open"]), browser: args.browser, cwd: snapshotRoot }
2507
- );
2528
+ const env = dashboardSpawnEnv({ ...process.env }, snapshotRoot, {
2529
+ noOpen: Boolean(args["no-open"]),
2530
+ browser: args.browser
2531
+ });
2532
+ process.title = dashboardProcessTitle(snapshotRoot);
2508
2533
  const code = await runStartScript(startPath, env);
2509
2534
  if (code !== 0) process.exitCode = code;
2510
2535
  }
@@ -2601,10 +2626,11 @@ var dashboardBroadcastCommand = defineCommand5({
2601
2626
  return;
2602
2627
  }
2603
2628
  const snapshotRoot = resolveDashboardSnapshotRoot(args.cwd);
2604
- const env = applyDashboardOpenEnv(
2605
- { ...process.env },
2606
- { noOpen: Boolean(args["no-open"]), browser: args.browser, cwd: snapshotRoot }
2607
- );
2629
+ const env = dashboardSpawnEnv({ ...process.env }, snapshotRoot, {
2630
+ noOpen: Boolean(args["no-open"]),
2631
+ browser: args.browser
2632
+ });
2633
+ process.title = dashboardProcessTitle(snapshotRoot);
2608
2634
  const code = await runStartScript2(startPath, env);
2609
2635
  if (code !== 0) process.exitCode = code;
2610
2636
  }
@@ -4115,6 +4141,169 @@ async function writeReadinessSnapshot(rootDir, report) {
4115
4141
  return snapshotPath;
4116
4142
  }
4117
4143
 
4144
+ // src/welcome/visual-kit.ts
4145
+ import { cyan as cyan2, gray, options as koloristOptions } from "kolorist";
4146
+ var HELMET_OUTLINE = "#e2e8f0";
4147
+ var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
4148
+ var SPACE_MARKS = {
4149
+ star: "\u2726",
4150
+ tick: "\xB7",
4151
+ diamond: "\u2727",
4152
+ visor: "( )"
4153
+ };
4154
+ var KIT_TIPS = [
4155
+ "Try agent-kit doctor for repository readiness.",
4156
+ "HITL gates stay in Cursor slash commands.",
4157
+ "/run-plan never promotes to production.",
4158
+ "Mission Control is the dashboard, not the CLI name.",
4159
+ "NO_COLOR and CI keep this output static.",
4160
+ "agent-kit --help groups SETUP, MISSION, DASHBOARD, INTEGRITY."
4161
+ ];
4162
+ function shouldUseWelcomeColor(opts = {}) {
4163
+ if (opts.color === false) return false;
4164
+ if (process.env.NO_COLOR) return false;
4165
+ if (process.env.NODE_DISABLE_COLORS) return false;
4166
+ if (process.env.FORCE_COLOR === "0") return false;
4167
+ if (process.env.CI != null && process.env.CI !== "") return false;
4168
+ if (opts.color === true) return true;
4169
+ const tty = opts.stdoutIsTTY ?? Boolean(process.stdout.isTTY);
4170
+ return tty;
4171
+ }
4172
+ function shouldUseVisualMotion(opts = {}) {
4173
+ if (process.env.AGENT_KIT_REDUCED_MOTION === "1") return false;
4174
+ return shouldUseWelcomeColor(opts);
4175
+ }
4176
+ function spinnerFrame(index) {
4177
+ const n = SPINNER_FRAMES.length;
4178
+ return SPINNER_FRAMES[(index % n + n) % n] ?? SPINNER_FRAMES[0];
4179
+ }
4180
+ function tipAt(index) {
4181
+ const n = KIT_TIPS.length;
4182
+ return KIT_TIPS[(index % n + n) % n] ?? KIT_TIPS[0];
4183
+ }
4184
+ function wrapNarrow(text, columns) {
4185
+ const width = Math.max(8, Number.isFinite(columns) ? Math.floor(columns) : 80);
4186
+ const words = text.trim().split(/\s+/).filter(Boolean);
4187
+ if (words.length === 0) return "";
4188
+ const lines = [];
4189
+ let current = "";
4190
+ for (const word of words) {
4191
+ if (word.length > width) {
4192
+ if (current) {
4193
+ lines.push(current);
4194
+ current = "";
4195
+ }
4196
+ for (let i = 0; i < word.length; i += width) {
4197
+ const chunk = word.slice(i, i + width);
4198
+ if (i + width >= word.length) current = chunk;
4199
+ else lines.push(chunk);
4200
+ }
4201
+ continue;
4202
+ }
4203
+ const next = current ? `${current} ${word}` : word;
4204
+ if (next.length > width) {
4205
+ lines.push(current);
4206
+ current = word;
4207
+ } else {
4208
+ current = next;
4209
+ }
4210
+ }
4211
+ if (current) lines.push(current);
4212
+ return lines.join("\n");
4213
+ }
4214
+ function renderProgressLine(opts) {
4215
+ const motion = opts.motion ?? shouldUseVisualMotion();
4216
+ const color = opts.color ?? shouldUseWelcomeColor();
4217
+ const mark = motion ? spinnerFrame(opts.frameIndex) : SPACE_MARKS.tick;
4218
+ const tip = tipAt(opts.tipIndex);
4219
+ const label = opts.label?.trim() ?? "";
4220
+ const raw = label ? `${mark} ${label} ${SPACE_MARKS.star} ${tip}` : `${mark} ${tip}`;
4221
+ const cols = opts.columns ?? process.stdout.columns ?? 80;
4222
+ const wrapped = wrapNarrow(raw, cols);
4223
+ if (!color) return wrapped;
4224
+ const prevEnabled = koloristOptions.enabled;
4225
+ koloristOptions.enabled = true;
4226
+ try {
4227
+ return wrapped.split("\n").map((line, i) => i === 0 ? cyan2(line) : gray(line)).join("\n");
4228
+ } finally {
4229
+ koloristOptions.enabled = prevEnabled;
4230
+ }
4231
+ }
4232
+ var TtySpinner = class {
4233
+ timer = null;
4234
+ frame = 0;
4235
+ startedAt = 0;
4236
+ label = "";
4237
+ write;
4238
+ columns;
4239
+ motion;
4240
+ color;
4241
+ intervalMs;
4242
+ now;
4243
+ constructor(opts = {}) {
4244
+ this.write = opts.write ?? ((chunk) => process.stdout.write(chunk));
4245
+ this.columns = opts.columns ?? (() => process.stdout.columns ?? 80);
4246
+ this.motion = opts.motion ?? shouldUseVisualMotion();
4247
+ this.color = opts.color ?? shouldUseWelcomeColor();
4248
+ this.intervalMs = opts.intervalMs ?? 80;
4249
+ this.now = opts.now ?? (() => Date.now());
4250
+ }
4251
+ start(label = "") {
4252
+ this.stop();
4253
+ this.label = label;
4254
+ this.frame = 0;
4255
+ this.startedAt = this.now();
4256
+ this.paint(false);
4257
+ if (!this.motion) return;
4258
+ this.timer = setInterval(() => {
4259
+ this.frame += 1;
4260
+ this.paint(true);
4261
+ }, this.intervalMs);
4262
+ this.timer.unref?.();
4263
+ }
4264
+ stop(finalLine) {
4265
+ if (this.timer) {
4266
+ clearInterval(this.timer);
4267
+ this.timer = null;
4268
+ }
4269
+ if (this.motion) this.write("\r\x1B[K");
4270
+ if (finalLine) this.write(`${finalLine}
4271
+ `);
4272
+ }
4273
+ paint(overwrite) {
4274
+ const elapsed = this.now() - this.startedAt;
4275
+ const tipIndex = Math.floor(elapsed / 4e3);
4276
+ const line = renderProgressLine({
4277
+ frameIndex: this.frame,
4278
+ tipIndex,
4279
+ columns: this.columns(),
4280
+ label: this.label,
4281
+ motion: this.motion,
4282
+ color: this.color
4283
+ }).split("\n")[0] ?? "";
4284
+ if (overwrite && this.motion) this.write(`\r\x1B[K${line}`);
4285
+ else if (this.motion) this.write(line);
4286
+ else this.write(`${line}
4287
+ `);
4288
+ }
4289
+ };
4290
+ async function withCliProgress(label, fn, opts) {
4291
+ const motion = opts?.motion ?? shouldUseVisualMotion();
4292
+ if (!motion) {
4293
+ return fn();
4294
+ }
4295
+ const spinner = new TtySpinner({ ...opts, motion: true });
4296
+ spinner.start(label);
4297
+ try {
4298
+ const result = await fn();
4299
+ spinner.stop();
4300
+ return result;
4301
+ } catch (err) {
4302
+ spinner.stop();
4303
+ throw err;
4304
+ }
4305
+ }
4306
+
4118
4307
  // src/commands/doctor.ts
4119
4308
  async function runDoctor(cwd, options = {}) {
4120
4309
  const rootDir = path24.resolve(cwd);
@@ -4188,7 +4377,8 @@ var doctorCommand = defineCommand7({
4188
4377
  }
4189
4378
  },
4190
4379
  async run({ args }) {
4191
- const result = await runDoctor(args.cwd, { fixSafe: args["fix-safe"] });
4380
+ const run = () => runDoctor(args.cwd, { fixSafe: args["fix-safe"] });
4381
+ const result = args.json ? await run() : await withCliProgress("doctor", run);
4192
4382
  if (args.json) {
4193
4383
  console.log(JSON.stringify(result, null, 2));
4194
4384
  return;
@@ -5340,16 +5530,83 @@ function classifyInstallError(err) {
5340
5530
  }
5341
5531
 
5342
5532
  // src/commands/install.ts
5343
- import path32 from "path";
5533
+ import path33 from "path";
5344
5534
  import { defineCommand as defineCommand11 } from "citty";
5345
5535
 
5346
5536
  // src/generator/personalization.ts
5347
- import { readFile as readFile15, writeFile as writeFile8 } from "fs/promises";
5348
- import path30 from "path";
5537
+ import { readFile as readFile15, writeFile as writeFile9 } from "fs/promises";
5538
+ import path31 from "path";
5349
5539
 
5350
- // src/generator/vscode.ts
5540
+ // src/generator/claude-kit-load.ts
5351
5541
  import { writeFile as writeFile7 } from "fs/promises";
5352
5542
  import path29 from "path";
5543
+ var CLAUDE_MD_REL = "CLAUDE.md";
5544
+ var AGENT_KIT_COMMAND_REL = ".claude/commands/agent-kit.md";
5545
+ function renderClaudeMd() {
5546
+ return `# Agent Kit (Claude Code)
5547
+
5548
+ This repository uses Agent Kit / Mission Control. Before rediscovering the tree, read the shared sources of truth (paths below are pointers; do not treat this file as a second rulebook).
5549
+
5550
+ ## Read first
5551
+
5552
+ 1. \`AGENTS.md\` - cross-IDE contract
5553
+ 2. \`.cursor/project-context.md\` - verified repository facts (derived; prefer code, tests, SHAs when docs conflict)
5554
+ 3. \`.cursor/HANDOFF.md\` - if present: active plan, next to-do, queue fields
5555
+ 4. \`.cursor/commands/\` - slash catalog (Cursor). Follow the same HITL contracts here.
5556
+
5557
+ Mid-session refresh: \`/agent-kit\`.
5558
+
5559
+ ## HITL
5560
+
5561
+ Cursor Ask questions is not available in this CLI. When a command requires a choice, list the same labels as a numbered list and wait. Skip or cancel means stop. Never \`/git-prod\` without an explicit operator yes.
5562
+
5563
+ ## Non-goals
5564
+
5565
+ - Not Action A7 (Windsurf / VS Code generator parity)
5566
+ - Not Claude external plan-review audits (\`/plan-external-review\`)
5567
+ - Not \`--backend claude\` plan-loop ticks
5568
+ - Not a copy of Cursor \`sessionStart\` / other IDE hooks
5569
+ `;
5570
+ }
5571
+ function renderAgentKitCommand() {
5572
+ return `---
5573
+ description: Load Agent Kit session context (HANDOFF, project-context, commands). Manual refresh only.
5574
+ disable-model-invocation: true
5575
+ ---
5576
+
5577
+ Read these files if they exist, then summarize the active plan, next to-do, and any Gaps. Do not scan the whole repository first.
5578
+
5579
+ 1. \`AGENTS.md\`
5580
+ 2. \`.cursor/project-context.md\`
5581
+ 3. \`.cursor/HANDOFF.md\`
5582
+ 4. The plan file named in HANDOFF \`- **Plan:**\` under \`.cursor/plans/\`
5583
+
5584
+ If HANDOFF is missing, say so and point at \`/agent-kit-onboard\` or \`/start-project\` rather than inventing a plan.
5585
+
5586
+ HITL: numbered-list fallback for Ask questions labels. Never \`/git-prod\` from this skill.
5587
+
5588
+ Non-goals: not audits / \`/plan-external-review\`, not \`--backend claude\` ticks, not A7, not Cursor hook clones.
5589
+ `;
5590
+ }
5591
+ async function writeUnlessExists(rootDir, relativePath, content) {
5592
+ const target = path29.join(rootDir, relativePath);
5593
+ if (await fileExists(target)) {
5594
+ return { relativePath, status: "skipped-customized" };
5595
+ }
5596
+ await ensureDir(path29.dirname(target));
5597
+ await writeFile7(target, content, "utf8");
5598
+ return { relativePath, status: "applied" };
5599
+ }
5600
+ async function generateClaudeKitLoadArtifacts(rootDir) {
5601
+ return Promise.all([
5602
+ writeUnlessExists(rootDir, CLAUDE_MD_REL, renderClaudeMd()),
5603
+ writeUnlessExists(rootDir, AGENT_KIT_COMMAND_REL, renderAgentKitCommand())
5604
+ ]);
5605
+ }
5606
+
5607
+ // src/generator/vscode.ts
5608
+ import { writeFile as writeFile8 } from "fs/promises";
5609
+ import path30 from "path";
5353
5610
 
5354
5611
  // src/generator/platform.ts
5355
5612
  function gitProviderLabel(profile) {
@@ -5373,14 +5630,14 @@ function prTerminology(profile) {
5373
5630
  // src/generator/vscode.ts
5374
5631
  async function generateVSCodeArtifacts(profile) {
5375
5632
  const results = [];
5376
- const vscodeDir = path29.join(profile.rootDir, ".vscode");
5377
- const githubDir = path29.join(profile.rootDir, ".github");
5633
+ const vscodeDir = path30.join(profile.rootDir, ".vscode");
5634
+ const githubDir = path30.join(profile.rootDir, ".github");
5378
5635
  await Promise.all([ensureDir(vscodeDir), ensureDir(githubDir)]);
5379
- const settingsPath = path29.join(vscodeDir, "settings.json");
5636
+ const settingsPath = path30.join(vscodeDir, "settings.json");
5380
5637
  if (await fileExists(settingsPath)) {
5381
5638
  results.push({ relativePath: ".vscode/settings.json", status: "skipped-customized" });
5382
5639
  } else {
5383
- await writeFile7(
5640
+ await writeFile8(
5384
5641
  settingsPath,
5385
5642
  `${JSON.stringify(
5386
5643
  {
@@ -5400,11 +5657,11 @@ async function generateVSCodeArtifacts(profile) {
5400
5657
  }
5401
5658
  const provider = gitProviderLabel(profile);
5402
5659
  const prTerm = prTerminology(profile);
5403
- const copilotPath = path29.join(githubDir, "copilot-instructions.md");
5660
+ const copilotPath = path30.join(githubDir, "copilot-instructions.md");
5404
5661
  if (await fileExists(copilotPath)) {
5405
5662
  results.push({ relativePath: ".github/copilot-instructions.md", status: "skipped-customized" });
5406
5663
  } else {
5407
- await writeFile7(
5664
+ await writeFile8(
5408
5665
  copilotPath,
5409
5666
  `# Copilot Instructions
5410
5667
 
@@ -5418,14 +5675,14 @@ async function generateVSCodeArtifacts(profile) {
5418
5675
  results.push({ relativePath: ".github/copilot-instructions.md", status: "applied" });
5419
5676
  }
5420
5677
  if (profile.ide.plan === "vscode-pro") {
5421
- const securityPath = path29.join(vscodeDir, "security-review.agent.md");
5678
+ const securityPath = path30.join(vscodeDir, "security-review.agent.md");
5422
5679
  if (await fileExists(securityPath)) {
5423
5680
  results.push({
5424
5681
  relativePath: ".vscode/security-review.agent.md",
5425
5682
  status: "skipped-customized"
5426
5683
  });
5427
5684
  } else {
5428
- await writeFile7(
5685
+ await writeFile8(
5429
5686
  securityPath,
5430
5687
  "# Security Review Agent\n\nSpecialized mode for security review.\n",
5431
5688
  "utf8"
@@ -5597,7 +5854,7 @@ function renderProjectContext(profile) {
5597
5854
  `;
5598
5855
  }
5599
5856
  async function createOwnedFile(rootDir, relativePath, content, evidence) {
5600
- const target = path30.join(rootDir, relativePath);
5857
+ const target = path31.join(rootDir, relativePath);
5601
5858
  if (await fileExists(target)) {
5602
5859
  return {
5603
5860
  kind: "file",
@@ -5607,8 +5864,8 @@ async function createOwnedFile(rootDir, relativePath, content, evidence) {
5607
5864
  evidence
5608
5865
  };
5609
5866
  }
5610
- await ensureDir(path30.dirname(target));
5611
- await writeFile8(target, content, "utf8");
5867
+ await ensureDir(path31.dirname(target));
5868
+ await writeFile9(target, content, "utf8");
5612
5869
  return {
5613
5870
  kind: "file",
5614
5871
  id: relativePath,
@@ -5624,7 +5881,7 @@ async function packTargets(registryRoot, packId) {
5624
5881
  async function existingTargets(projectRoot, targets) {
5625
5882
  const checks = await Promise.all(
5626
5883
  targets.map(
5627
- async (target) => await fileExists(path30.join(projectRoot, target)) ? target : null
5884
+ async (target) => await fileExists(path31.join(projectRoot, target)) ? target : null
5628
5885
  )
5629
5886
  );
5630
5887
  return checks.filter((target) => target !== null);
@@ -5646,14 +5903,14 @@ async function applyPersonalization(input) {
5646
5903
  componentResults.push({ ...item, status: "unavailable" });
5647
5904
  continue;
5648
5905
  }
5649
- const target = path30.posix.join(
5906
+ const target = path31.posix.join(
5650
5907
  ".cursor",
5651
5908
  "skills",
5652
5909
  skill.path.includes("/core/") ? "core" : "community",
5653
5910
  skill.id,
5654
5911
  "SKILL.md"
5655
5912
  );
5656
- if (await fileExists(path30.join(input.rootDir, target))) {
5913
+ if (await fileExists(path31.join(input.rootDir, target))) {
5657
5914
  componentResults.push({ ...item, status: "skipped-customized", path: target });
5658
5915
  protectedPaths.add(target);
5659
5916
  continue;
@@ -5701,6 +5958,17 @@ async function applyPersonalization(input) {
5701
5958
  ]);
5702
5959
  protectedPaths.add(CONTEXT_PATH);
5703
5960
  protectedPaths.add(AGENTS_PATH);
5961
+ const claudeResults = await generateClaudeKitLoadArtifacts(input.rootDir);
5962
+ const claudeItems = claudeResults.map((artifact) => {
5963
+ protectedPaths.add(artifact.relativePath);
5964
+ return {
5965
+ kind: "file",
5966
+ id: artifact.relativePath,
5967
+ path: artifact.relativePath,
5968
+ status: artifact.status,
5969
+ evidence: profileEvidence
5970
+ };
5971
+ });
5704
5972
  const ideDetection = await detectIde(input.rootDir);
5705
5973
  if (ideDetection.ide === "vscode" || ideDetection.ide === "other") {
5706
5974
  const git = {
@@ -5748,10 +6016,10 @@ async function applyPersonalization(input) {
5748
6016
  contractVersion: PERSONALIZATION_CONTRACT_VERSION,
5749
6017
  generatorVersion: input.generatorVersion,
5750
6018
  repositoryFingerprint: input.report.repositoryFingerprint,
5751
- items: [...fileResults, ...componentResults],
6019
+ items: [...fileResults, ...claudeItems, ...componentResults],
5752
6020
  protectedPaths: [...protectedPaths].sort()
5753
6021
  };
5754
- await writeJson(path30.join(input.rootDir, RESULT_PATH), result);
6022
+ await writeJson(path31.join(input.rootDir, RESULT_PATH), result);
5755
6023
  return {
5756
6024
  result,
5757
6025
  manifest: {
@@ -5769,7 +6037,7 @@ async function applyPersonalization(input) {
5769
6037
  };
5770
6038
  }
5771
6039
  async function readRepositoryProfile(rootDir) {
5772
- const target = path30.join(rootDir, ".cursor/agent-kit.config.json");
6040
+ const target = path31.join(rootDir, ".cursor/agent-kit.config.json");
5773
6041
  if (!await fileExists(target)) return null;
5774
6042
  return JSON.parse(await readFile15(target, "utf8"));
5775
6043
  }
@@ -5777,16 +6045,16 @@ async function readRepositoryProfile(rootDir) {
5777
6045
  // src/lifecycle/onboard-migration.ts
5778
6046
  import { createHash as createHash4 } from "crypto";
5779
6047
  import { readFile as readFile16, unlink } from "fs/promises";
5780
- import path31 from "path";
6048
+ import path32 from "path";
5781
6049
  var LEGACY_ONBOARD_PATH = ".cursor/commands/onboard.md";
5782
6050
  var NAMESPACED_ONBOARD_PATH = ".cursor/commands/agent-kit-onboard.md";
5783
6051
  var MANAGED_LEGACY_HASHES = /* @__PURE__ */ new Set([
5784
6052
  "b274a68941813f19b185893cb7c5561dff027f53270890029992f208e24992fe"
5785
6053
  ]);
5786
6054
  async function migrateLegacyOnboardCommand(projectRoot, managedHashes = MANAGED_LEGACY_HASHES) {
5787
- const legacyPath = path31.join(projectRoot, LEGACY_ONBOARD_PATH);
6055
+ const legacyPath = path32.join(projectRoot, LEGACY_ONBOARD_PATH);
5788
6056
  if (!await fileExists(legacyPath)) return "absent";
5789
- const namespacedPath = path31.join(projectRoot, NAMESPACED_ONBOARD_PATH);
6057
+ const namespacedPath = path32.join(projectRoot, NAMESPACED_ONBOARD_PATH);
5790
6058
  if (!await fileExists(namespacedPath)) return "preserved-customized";
5791
6059
  const content = await readFile16(legacyPath);
5792
6060
  const hash = createHash4("sha256").update(content).digest("hex");
@@ -5861,7 +6129,7 @@ function printReadinessNarrative(result) {
5861
6129
  );
5862
6130
  }
5863
6131
  async function performInstall(options) {
5864
- const projectRoot = path32.resolve(options.cwd);
6132
+ const projectRoot = path33.resolve(options.cwd);
5865
6133
  const packs = parsePackList(options.pack);
5866
6134
  const existing = await loadAgentKitManifest(projectRoot);
5867
6135
  const registry = await resolveRegistryFromCli({
@@ -5979,15 +6247,18 @@ var installCommand = defineCommand11({
5979
6247
  }
5980
6248
  }
5981
6249
  try {
5982
- const result = await performInstall({
5983
- cwd: projectRoot,
5984
- profile: args.profile,
5985
- pack: args.pack,
5986
- registry: args.registry,
5987
- url: args.url,
5988
- ref: args.ref,
5989
- refresh: args.refresh
5990
- });
6250
+ const result = await withCliProgress(
6251
+ "install",
6252
+ () => performInstall({
6253
+ cwd: projectRoot,
6254
+ profile: args.profile,
6255
+ pack: args.pack,
6256
+ registry: args.registry,
6257
+ url: args.url,
6258
+ ref: args.ref,
6259
+ refresh: args.refresh
6260
+ })
6261
+ );
5991
6262
  logApplyStats(result.stats);
5992
6263
  logger.success(`Manifest written: ${result.manifestPath}`);
5993
6264
  logger.success("Readiness snapshot written: .cursor/context/readiness.json");
@@ -6028,7 +6299,7 @@ var initCommand = defineCommand12({
6028
6299
  }
6029
6300
  logger.info("init now uses the canonical install and readiness workflow.");
6030
6301
  try {
6031
- const result = await runInitCompatibility(args.cwd);
6302
+ const result = await withCliProgress("init", () => runInitCompatibility(args.cwd));
6032
6303
  const pending = result.readiness.pendingActions.length;
6033
6304
  logger.success(`L0 and readiness prepared in ${result.projectRoot}`);
6034
6305
  const nextStep = pending > 0 ? "Next: run /agent-kit-onboard in Cursor to resolve the first pending action." : "Next: run /start-project in Cursor when you have a deliverable.";
@@ -6049,13 +6320,13 @@ ${hint.recovery}
6049
6320
  });
6050
6321
 
6051
6322
  // src/commands/monitors.ts
6052
- import path34 from "path";
6323
+ import path35 from "path";
6053
6324
  import { defineCommand as defineCommand13 } from "citty";
6054
6325
 
6055
6326
  // src/invariants/monitors-untriaged.ts
6056
6327
  import { execFile as execFile5 } from "child_process";
6057
6328
  import { readFile as readFile17, readdir as readdir5, stat as stat3 } from "fs/promises";
6058
- import path33 from "path";
6329
+ import path34 from "path";
6059
6330
  import { promisify as promisify5 } from "util";
6060
6331
 
6061
6332
  // src/invariants/triage-heading.ts
@@ -6096,7 +6367,7 @@ async function gitFreshMonitorNames(rootDir) {
6096
6367
  for (const line of stdout.split("\n")) {
6097
6368
  if (!line.trim()) continue;
6098
6369
  const file = line.slice(3).trim().replace(/^.* -> /, "");
6099
- const base = path33.basename(file);
6370
+ const base = path34.basename(file);
6100
6371
  if (base.startsWith("plan-monitor-") && base.endsWith(".md")) {
6101
6372
  names.add(base);
6102
6373
  }
@@ -6119,13 +6390,13 @@ function monitorSlugFromName(fileName) {
6119
6390
  return fileName.replace(/^plan-monitor-/, "").replace(/\.md$/, "").toLowerCase();
6120
6391
  }
6121
6392
  async function selectUntriagedMonitors(rootDir) {
6122
- const root = path33.resolve(rootDir);
6123
- const memoryDir = path33.join(root, ".cursor", "memory");
6393
+ const root = path34.resolve(rootDir);
6394
+ const memoryDir = path34.join(root, ".cursor", "memory");
6124
6395
  const allNames = await listMonitorFiles(memoryDir);
6125
6396
  const selectionOrder = ["git-fresh", "handoff-aligned", "untriaged-scan"];
6126
6397
  const byName = /* @__PURE__ */ new Map();
6127
6398
  for (const name of allNames) {
6128
- const abs = path33.join(memoryDir, name);
6399
+ const abs = path34.join(memoryDir, name);
6129
6400
  try {
6130
6401
  const [content, st] = await Promise.all([readFile17(abs, "utf8"), stat3(abs)]);
6131
6402
  byName.set(name, { content, mtimeMs: st.mtimeMs });
@@ -6140,7 +6411,7 @@ async function selectUntriagedMonitors(rootDir) {
6140
6411
  const gitFreshSet = [...gitFresh].filter(untriaged).sort();
6141
6412
  let handoff = "";
6142
6413
  try {
6143
- handoff = await readFile17(path33.join(root, ".cursor", "HANDOFF.md"), "utf8");
6414
+ handoff = await readFile17(path34.join(root, ".cursor", "HANDOFF.md"), "utf8");
6144
6415
  } catch {
6145
6416
  handoff = "";
6146
6417
  }
@@ -6160,8 +6431,8 @@ async function selectUntriagedMonitors(rootDir) {
6160
6431
  const row = byName.get(name);
6161
6432
  if (!row) continue;
6162
6433
  entries.push({
6163
- path: path33.join(memoryDir, name),
6164
- relativePath: path33.relative(root, path33.join(memoryDir, name)).split(path33.sep).join("/"),
6434
+ path: path34.join(memoryDir, name),
6435
+ relativePath: path34.relative(root, path34.join(memoryDir, name)).split(path34.sep).join("/"),
6165
6436
  mtimeMs: row.mtimeMs,
6166
6437
  hasTriageHeading: false,
6167
6438
  hasOpenGaps: hasOpenGaps(row.content),
@@ -6207,7 +6478,7 @@ var monitorsCommand = defineCommand13({
6207
6478
  process.exitCode = 2;
6208
6479
  return;
6209
6480
  }
6210
- const result = await selectUntriagedMonitors(path34.resolve(args.cwd));
6481
+ const result = await selectUntriagedMonitors(path35.resolve(args.cwd));
6211
6482
  if (args.json) {
6212
6483
  console.log(JSON.stringify(result, null, 2));
6213
6484
  return;
@@ -6223,7 +6494,7 @@ var monitorsCommand = defineCommand13({
6223
6494
  });
6224
6495
 
6225
6496
  // src/commands/run-plan.ts
6226
- import path39 from "path";
6497
+ import path40 from "path";
6227
6498
  import { defineCommand as defineCommand14 } from "citty";
6228
6499
 
6229
6500
  // src/plan-loop/backends.ts
@@ -6309,13 +6580,13 @@ function listBackendIds() {
6309
6580
 
6310
6581
  // src/plan-loop/run-loop.ts
6311
6582
  import { mkdir as mkdir6, readFile as readFile20, rm as rm2, unlink as unlink2 } from "fs/promises";
6312
- import path38 from "path";
6583
+ import path39 from "path";
6313
6584
 
6314
6585
  // src/plan-loop/external-review.ts
6315
6586
  import { spawn as spawn7 } from "child_process";
6316
- import path35 from "path";
6317
- var CANONICAL_REL = path35.join(".cursor", "scripts", "plan-external-review.sh");
6318
- var FALLBACK_REL = path35.join("scripts", "plan-external-review.sh");
6587
+ import path36 from "path";
6588
+ var CANONICAL_REL = path36.join(".cursor", "scripts", "plan-external-review.sh");
6589
+ var FALLBACK_REL = path36.join("scripts", "plan-external-review.sh");
6319
6590
  function isPlanExhaustedReason(reason) {
6320
6591
  const r = reason.trim().toLowerCase();
6321
6592
  if (!r) return false;
@@ -6337,8 +6608,8 @@ async function armExternalPlanReview(root, options = {}) {
6337
6608
  const existsFn = options.existsFn ?? fileExists;
6338
6609
  const log = options.log ?? ((line) => console.log(line));
6339
6610
  const force = options.force === true;
6340
- const canonicalPath = path35.join(root, CANONICAL_REL);
6341
- const fallbackPath = path35.join(root, FALLBACK_REL);
6611
+ const canonicalPath = path36.join(root, CANONICAL_REL);
6612
+ const fallbackPath = path36.join(root, FALLBACK_REL);
6342
6613
  let scriptPath = null;
6343
6614
  let scriptRel = CANONICAL_REL;
6344
6615
  if (await existsFn(canonicalPath)) {
@@ -6391,11 +6662,11 @@ async function armExternalPlanReview(root, options = {}) {
6391
6662
  }
6392
6663
 
6393
6664
  // src/plan-loop/persona-banners.ts
6394
- import path36 from "path";
6665
+ import path37 from "path";
6395
6666
  import {
6396
6667
  blue,
6397
- cyan as cyan2,
6398
- gray,
6668
+ cyan as cyan3,
6669
+ gray as gray2,
6399
6670
  green as green2,
6400
6671
  lightGray,
6401
6672
  lightGreen,
@@ -6408,9 +6679,9 @@ var CLI_RUN_PLAN_MODE = "cli-run-plan";
6408
6679
  var DEFAULT_CLI_PERSONA_ID = "ghost-runner";
6409
6680
  var COLORS = {
6410
6681
  white,
6411
- gray,
6682
+ gray: gray2,
6412
6683
  green: green2,
6413
- cyan: cyan2,
6684
+ cyan: cyan3,
6414
6685
  magenta,
6415
6686
  yellow: yellow2,
6416
6687
  red: red2,
@@ -6427,7 +6698,7 @@ function resolveColor(name, fallback) {
6427
6698
  async function resolveCliPersonaId(root) {
6428
6699
  try {
6429
6700
  const cfg = await readJson(
6430
- path36.join(root, ".cursor", "context", "config.json")
6701
+ path37.join(root, ".cursor", "context", "config.json")
6431
6702
  );
6432
6703
  const modes = cfg?.agentPersona?.modes ?? cfg?.workspaceSkin?.modes;
6433
6704
  const id = modes?.[CLI_RUN_PLAN_MODE];
@@ -6438,7 +6709,7 @@ async function resolveCliPersonaId(root) {
6438
6709
  }
6439
6710
  async function loadPersonaPack(root, personaId) {
6440
6711
  try {
6441
- const personaPath = path36.join(root, "registry", "personas", "core", personaId, "persona.json");
6712
+ const personaPath = path37.join(root, "registry", "personas", "core", personaId, "persona.json");
6442
6713
  const pack = await readJson(personaPath);
6443
6714
  if (!pack || typeof pack.id !== "string") return null;
6444
6715
  return pack;
@@ -6455,7 +6726,7 @@ function createPersonaBannerPrinter(persona) {
6455
6726
  const banners = persona.cliBanners;
6456
6727
  if (!banners.tickStart && !banners.tickEnd && !banners.phaseComplete) return null;
6457
6728
  const primary = resolveColor(persona.ansiPalette?.primary, white);
6458
- const secondary = resolveColor(persona.ansiPalette?.secondary, gray);
6729
+ const secondary = resolveColor(persona.ansiPalette?.secondary, gray2);
6459
6730
  const accent = resolveColor(persona.ansiPalette?.accent, green2);
6460
6731
  return {
6461
6732
  tickStart(detail) {
@@ -6488,7 +6759,7 @@ function createPersonaBannerPrinter(persona) {
6488
6759
 
6489
6760
  // src/plan-loop/plan-state.ts
6490
6761
  import { readFile as readFile18, readdir as readdir6 } from "fs/promises";
6491
- import path37 from "path";
6762
+ import path38 from "path";
6492
6763
  function countPendingTodos(raw) {
6493
6764
  const lines = raw.split(/\r?\n/);
6494
6765
  let inFront = 0;
@@ -6516,7 +6787,7 @@ function countPendingTodos(raw) {
6516
6787
  async function findActivePlanFile(plansDir) {
6517
6788
  if (!await fileExists(plansDir)) return null;
6518
6789
  const files = (await readdir6(plansDir)).filter((f) => f.endsWith(".plan.md")).sort();
6519
- return files[0] ? path37.join(plansDir, files[0]) : null;
6790
+ return files[0] ? path38.join(plansDir, files[0]) : null;
6520
6791
  }
6521
6792
  async function readPlan(planPath) {
6522
6793
  return readFile18(planPath, "utf8");
@@ -6593,9 +6864,9 @@ function sleep(ms) {
6593
6864
  return new Promise((r) => setTimeout(r, ms));
6594
6865
  }
6595
6866
  async function runPlanLoop(opts) {
6596
- const plansDir = path38.join(opts.root, ".cursor", "plans");
6597
- const stopFile = path38.join(opts.root, ".cursor", "loop.stop");
6598
- const logDir = path38.join(opts.root, ".cursor", "loop-logs");
6867
+ const plansDir = path39.join(opts.root, ".cursor", "plans");
6868
+ const stopFile = path39.join(opts.root, ".cursor", "loop.stop");
6869
+ const logDir = path39.join(opts.root, ".cursor", "loop-logs");
6599
6870
  const planPath = await findActivePlanFile(plansDir);
6600
6871
  if (!planPath) {
6601
6872
  logger.error("No active plan in .cursor/plans/");
@@ -6616,7 +6887,7 @@ async function runPlanLoop(opts) {
6616
6887
  try {
6617
6888
  const persona = await loadCliRunPlanPersona(opts.root);
6618
6889
  const banners = createPersonaBannerPrinter(persona);
6619
- console.log(`Active plan: ${path38.basename(planPath)}`);
6890
+ console.log(`Active plan: ${path39.basename(planPath)}`);
6620
6891
  console.log(`Pending to-dos: ${await pending()} | max ticks: ${opts.maxTicks}`);
6621
6892
  console.log(`Backend: ${opts.backend.id}`);
6622
6893
  if (persona) {
@@ -6659,20 +6930,23 @@ async function runPlanLoop(opts) {
6659
6930
  planExhausted = true;
6660
6931
  break;
6661
6932
  }
6662
- const logPath = path38.join(logDir, `tick-${stamp()}.log`);
6663
- const relLog = path38.relative(opts.root, logPath);
6933
+ const logPath = path39.join(logDir, `tick-${stamp()}.log`);
6934
+ const relLog = path39.relative(opts.root, logPath);
6664
6935
  console.log("");
6665
6936
  const tickLine = `=== tick ${tick}/${opts.maxTicks} - pending: ${before} - log: ${relLog} ===`;
6666
6937
  if (banners) banners.tickStart(tickLine);
6667
6938
  else console.log(tickLine);
6668
6939
  let agentExit = 0;
6669
6940
  try {
6670
- const result = await opts.backend.run({
6671
- workspace: opts.root,
6672
- prompt: TICK_PROMPT,
6673
- model: opts.model,
6674
- logPath
6675
- });
6941
+ const result = await withCliProgress(
6942
+ `tick ${tick}`,
6943
+ () => opts.backend.run({
6944
+ workspace: opts.root,
6945
+ prompt: TICK_PROMPT,
6946
+ model: opts.model,
6947
+ logPath
6948
+ })
6949
+ );
6676
6950
  agentExit = result.exitCode;
6677
6951
  } catch (err) {
6678
6952
  logger.error(String(err));
@@ -6728,7 +7002,7 @@ async function runPlanLoop(opts) {
6728
7002
  }
6729
7003
  if (opts.sleepSeconds > 0) {
6730
7004
  if (banners) banners.sleep(opts.sleepSeconds);
6731
- await sleep(opts.sleepSeconds * 1e3);
7005
+ await withCliProgress(`sleep ${opts.sleepSeconds}s`, () => sleep(opts.sleepSeconds * 1e3));
6732
7006
  }
6733
7007
  }
6734
7008
  const pendingNow = await pending();
@@ -6736,7 +7010,7 @@ async function runPlanLoop(opts) {
6736
7010
  const finishDetail = `after ${tick} tick(s); pending: ${pendingNow}`;
6737
7011
  if (banners) banners.phaseComplete(finishDetail);
6738
7012
  console.log(
6739
- `Loop finished after ${tick} tick(s). Pending now: ${pendingNow}. Logs in ${path38.relative(opts.root, logDir)}/`
7013
+ `Loop finished after ${tick} tick(s). Pending now: ${pendingNow}. Logs in ${path39.relative(opts.root, logDir)}/`
6740
7014
  );
6741
7015
  if (planExhausted || shouldArmExternalPlanReview({ pending: pendingNow, stopReason })) {
6742
7016
  await armExternalPlanReview(opts.root);
@@ -6807,7 +7081,7 @@ var runPlanCommand = defineCommand14({
6807
7081
  return;
6808
7082
  }
6809
7083
  const code = await runPlanLoop({
6810
- root: path39.resolve(args.cwd),
7084
+ root: path40.resolve(args.cwd),
6811
7085
  maxTicks,
6812
7086
  sleepSeconds,
6813
7087
  model: args.model ? String(args.model) : void 0,
@@ -6841,7 +7115,7 @@ var scanCommand = defineCommand15({
6841
7115
  });
6842
7116
 
6843
7117
  // src/commands/status.ts
6844
- import path40 from "path";
7118
+ import path41 from "path";
6845
7119
  import { defineCommand as defineCommand16 } from "citty";
6846
7120
  function profileStatus(profile) {
6847
7121
  if (!profile) return { origin: "none", evidence: [], profile: null };
@@ -6872,11 +7146,11 @@ var statusCommand = defineCommand16({
6872
7146
  }
6873
7147
  },
6874
7148
  async run({ args }) {
6875
- const rootDir = path40.resolve(args.cwd);
7149
+ const rootDir = path41.resolve(args.cwd);
6876
7150
  const [manifest, rawProfile, scan] = await Promise.all([
6877
7151
  loadAgentKitManifest(rootDir),
6878
7152
  readJson(
6879
- path40.join(rootDir, ".cursor", "agent-kit.config.json")
7153
+ path41.join(rootDir, ".cursor", "agent-kit.config.json")
6880
7154
  ),
6881
7155
  runScanner(rootDir)
6882
7156
  ]);
@@ -6935,7 +7209,7 @@ import { defineCommand as defineCommand17 } from "citty";
6935
7209
 
6936
7210
  // src/lifecycle/check-updates.ts
6937
7211
  import { execFile as execFile6 } from "child_process";
6938
- import path41 from "path";
7212
+ import path42 from "path";
6939
7213
  import { promisify as promisify6 } from "util";
6940
7214
  var execFileAsync5 = promisify6(execFile6);
6941
7215
  var SEMVER_CORE = /^v?(\d+)\.(\d+)\.(\d+)(?:[-+].*)?$/i;
@@ -7026,11 +7300,11 @@ function intervalElapsed2(lastCheckedAt, intervalDays) {
7026
7300
  return Date.now() - last >= ms;
7027
7301
  }
7028
7302
  async function loadContextConfig2(cwd) {
7029
- const configPath = path41.join(cwd, ".cursor", "context", "config.json");
7303
+ const configPath = path42.join(cwd, ".cursor", "context", "config.json");
7030
7304
  return readJson(configPath);
7031
7305
  }
7032
7306
  async function stampLastCheckedAt(cwd) {
7033
- const configPath = path41.join(cwd, ".cursor", "context", "config.json");
7307
+ const configPath = path42.join(cwd, ".cursor", "context", "config.json");
7034
7308
  const existing = await loadContextConfig2(cwd) ?? {};
7035
7309
  const prev = existing.updateCheck && typeof existing.updateCheck === "object" ? { ...existing.updateCheck } : {};
7036
7310
  existing.updateCheck = {
@@ -7040,6 +7314,117 @@ async function stampLastCheckedAt(cwd) {
7040
7314
  };
7041
7315
  await writeJson(configPath, existing);
7042
7316
  }
7317
+ async function readLocalKitVersion(registryRoot) {
7318
+ for (const rel of ["packages/cli/package.json", "package.json"]) {
7319
+ const data = await readJson(path42.join(registryRoot, rel));
7320
+ if (data && typeof data.version === "string" && data.version.length > 0) {
7321
+ return data.version;
7322
+ }
7323
+ }
7324
+ return null;
7325
+ }
7326
+ async function checkAgainstLocalRegistry(cwd, manifest, options) {
7327
+ const registryPath = options.registryPath;
7328
+ if (!registryPath) {
7329
+ throw new Error("checkAgainstLocalRegistry requires registryPath");
7330
+ }
7331
+ let resolved;
7332
+ try {
7333
+ resolved = await resolveRegistryRoot({ cwd, registryPath });
7334
+ } catch (err) {
7335
+ const msg = err instanceof Error ? err.message : String(err);
7336
+ return {
7337
+ status: "error",
7338
+ installedVersion: manifest.version,
7339
+ latestVersion: null,
7340
+ registryUrl: path42.resolve(registryPath),
7341
+ registryRef: "local",
7342
+ applyRecommended: false,
7343
+ message: `Failed to resolve --registry: ${msg}`
7344
+ };
7345
+ }
7346
+ const registryUrl = resolved.root;
7347
+ const registryRef = "local";
7348
+ try {
7349
+ let latest;
7350
+ if (options.latestVersion !== void 0) {
7351
+ latest = options.latestVersion;
7352
+ } else {
7353
+ const raw = await readLocalKitVersion(resolved.root);
7354
+ latest = raw ? normalizeSemver(raw) : null;
7355
+ }
7356
+ const summary = summarizeDiff(await diffAgainstRegistry(resolved.root, cwd, manifest));
7357
+ const hasFileDrift = summary.drift > 0 || summary["missing-local"] > 0;
7358
+ const installed = normalizeSemver(manifest.version);
7359
+ if (!installed) {
7360
+ return {
7361
+ status: "error",
7362
+ installedVersion: manifest.version,
7363
+ latestVersion: latest,
7364
+ registryUrl,
7365
+ registryRef,
7366
+ applyRecommended: false,
7367
+ message: `Installed version "${manifest.version}" is not valid semver.`
7368
+ };
7369
+ }
7370
+ if (!latest) {
7371
+ return {
7372
+ status: "error",
7373
+ installedVersion: installed,
7374
+ latestVersion: null,
7375
+ registryUrl,
7376
+ registryRef,
7377
+ applyRecommended: false,
7378
+ message: "No semver found in the local --registry checkout (packages/cli/package.json or package.json)."
7379
+ };
7380
+ }
7381
+ const cmp = compareSemver(installed, latest);
7382
+ if (hasFileDrift) {
7383
+ return {
7384
+ status: "update-available",
7385
+ installedVersion: installed,
7386
+ latestVersion: latest,
7387
+ registryUrl,
7388
+ registryRef,
7389
+ applyRecommended: false,
7390
+ message: `Local registry has drift vs this install (drift=${summary.drift}, missing-local=${summary["missing-local"]}; source v${latest}). Run /update --registry <path> (Ask confirm) to apply; never silent.`
7391
+ };
7392
+ }
7393
+ if (cmp === 0) {
7394
+ return {
7395
+ status: "up-to-date",
7396
+ installedVersion: installed,
7397
+ latestVersion: latest,
7398
+ registryUrl,
7399
+ registryRef,
7400
+ applyRecommended: false,
7401
+ message: `Installed v${installed} matches local registry v${latest}.`
7402
+ };
7403
+ }
7404
+ if (cmp < 0) {
7405
+ return {
7406
+ status: "update-available",
7407
+ installedVersion: installed,
7408
+ latestVersion: latest,
7409
+ registryUrl,
7410
+ registryRef,
7411
+ applyRecommended: false,
7412
+ message: `Update available from local registry: v${installed} \u2192 v${latest}. Run /update --registry <path> (Ask confirm) to apply; never silent.`
7413
+ };
7414
+ }
7415
+ return {
7416
+ status: "ahead-of-public",
7417
+ installedVersion: installed,
7418
+ latestVersion: latest,
7419
+ registryUrl,
7420
+ registryRef,
7421
+ applyRecommended: false,
7422
+ message: `Installed v${installed} is ahead of local registry v${latest}.`
7423
+ };
7424
+ } finally {
7425
+ await resolved.unlock?.();
7426
+ }
7427
+ }
7043
7428
  async function checkForUpdates(cwd, options = {}) {
7044
7429
  const manifest = await loadAgentKitManifest(cwd);
7045
7430
  if (!manifest) {
@@ -7053,7 +7438,10 @@ async function checkForUpdates(cwd, options = {}) {
7053
7438
  message: "No .cursor/agent-kit.json \u2014 run agent-kit install first."
7054
7439
  };
7055
7440
  }
7056
- const registryUrl = manifest.registry?.url ?? null;
7441
+ if (options.registryPath) {
7442
+ return checkAgainstLocalRegistry(cwd, manifest, options);
7443
+ }
7444
+ const registryUrl = options.publicRegistryUrl ?? manifest.registry?.url ?? null;
7057
7445
  const registryRef = manifest.registry?.ref ?? null;
7058
7446
  if (isFactoryOrDevRegistry(registryUrl, registryRef)) {
7059
7447
  return {
@@ -7183,7 +7571,7 @@ var updateCommand = defineCommand17({
7183
7571
  },
7184
7572
  check: {
7185
7573
  type: "boolean",
7186
- description: "Check-only: compare installed version to latest public tag; never apply L0 writes",
7574
+ description: "Check-only: compare installed version to the resolved registry (public tags, or --registry local checkout); never apply L0 writes",
7187
7575
  default: false
7188
7576
  },
7189
7577
  json: {
@@ -7224,7 +7612,8 @@ var updateCommand = defineCommand17({
7224
7612
  const result = await checkForUpdates(args.cwd, {
7225
7613
  respectPrefs: Boolean(args["respect-prefs"]),
7226
7614
  stamp: Boolean(args.stamp),
7227
- publicRegistryUrl: typeof args.url === "string" && args.url ? args.url : void 0
7615
+ publicRegistryUrl: typeof args.url === "string" && args.url ? args.url : void 0,
7616
+ registryPath: typeof args.registry === "string" && args.registry ? args.registry : void 0
7228
7617
  });
7229
7618
  if (args.json) {
7230
7619
  console.log(JSON.stringify(result, null, 2));
@@ -7287,7 +7676,10 @@ var updateCommand = defineCommand17({
7287
7676
  await seedManagedHashLedger(projectRoot);
7288
7677
  logger.info("Seeded managed-hash ledger from current local overlay files.");
7289
7678
  }
7290
- const stats = await syncFromManifest(registry.root, projectRoot, next);
7679
+ const stats = await withCliProgress(
7680
+ "update",
7681
+ () => syncFromManifest(registry.root, projectRoot, next)
7682
+ );
7291
7683
  await saveManifest(projectRoot, next);
7292
7684
  logApplyStats(stats);
7293
7685
  logger.success("Update complete (L3 protected paths left untouched).");
@@ -7299,7 +7691,7 @@ var updateCommand = defineCommand17({
7299
7691
 
7300
7692
  // src/commands/validate.ts
7301
7693
  import { readFile as readFile21 } from "fs/promises";
7302
- import path42 from "path";
7694
+ import path43 from "path";
7303
7695
  import { defineCommand as defineCommand18 } from "citty";
7304
7696
 
7305
7697
  // src/invariants/plan-schema.ts
@@ -7346,7 +7738,7 @@ function validatePlanFrontmatterText(text) {
7346
7738
  // src/commands/validate.ts
7347
7739
  async function resolveEditedPath(cwd, explicit) {
7348
7740
  if (explicit) {
7349
- const filePath2 = path42.resolve(cwd, explicit);
7741
+ const filePath2 = path43.resolve(cwd, explicit);
7350
7742
  try {
7351
7743
  return { filePath: filePath2, content: await readFile21(filePath2, "utf8") };
7352
7744
  } catch {
@@ -7356,7 +7748,7 @@ async function resolveEditedPath(cwd, explicit) {
7356
7748
  const payload = await readStdinJson();
7357
7749
  const rel = typeof payload.file_path === "string" && payload.file_path || typeof payload.path === "string" && payload.path || typeof payload.file === "string" && payload.file || "";
7358
7750
  if (!rel) return null;
7359
- const filePath = path42.isAbsolute(rel) ? rel : path42.resolve(cwd, rel);
7751
+ const filePath = path43.isAbsolute(rel) ? rel : path43.resolve(cwd, rel);
7360
7752
  try {
7361
7753
  return { filePath, content: await readFile21(filePath, "utf8") };
7362
7754
  } catch {
@@ -7386,7 +7778,7 @@ var validateCommand = defineCommand18({
7386
7778
  async run({ args }) {
7387
7779
  const cwd = typeof args.cwd === "string" ? args.cwd : process.cwd();
7388
7780
  const fileArg = typeof args.file === "string" ? args.file : void 0;
7389
- const filePath = fileArg ? path42.resolve(cwd, fileArg) : path42.join(path42.resolve(cwd), ".cursor", "HANDOFF.md");
7781
+ const filePath = fileArg ? path43.resolve(cwd, fileArg) : path43.join(path43.resolve(cwd), ".cursor", "HANDOFF.md");
7390
7782
  let content = "";
7391
7783
  try {
7392
7784
  content = await readFile21(filePath, "utf8");
@@ -7413,7 +7805,7 @@ var validateCommand = defineCommand18({
7413
7805
  process.exitCode = 2;
7414
7806
  return;
7415
7807
  }
7416
- const filePath = path42.resolve(cwd, fileArg);
7808
+ const filePath = path43.resolve(cwd, fileArg);
7417
7809
  let content = "";
7418
7810
  try {
7419
7811
  content = await readFile21(filePath, "utf8");
@@ -7435,7 +7827,7 @@ var validateCommand = defineCommand18({
7435
7827
  },
7436
7828
  async run({ args }) {
7437
7829
  const cwd = typeof args.cwd === "string" ? args.cwd : process.cwd();
7438
- const resolved = await resolveEditedPath(path42.resolve(cwd));
7830
+ const resolved = await resolveEditedPath(path43.resolve(cwd));
7439
7831
  if (!resolved) {
7440
7832
  console.log(JSON.stringify({}));
7441
7833
  return;
@@ -7478,19 +7870,18 @@ var validateCommand = defineCommand18({
7478
7870
  });
7479
7871
 
7480
7872
  // src/welcome/help-groups.ts
7481
- import { bold, gray as gray3, underline } from "kolorist";
7873
+ import { bold, gray as gray4, underline } from "kolorist";
7482
7874
 
7483
7875
  // src/welcome/screen.ts
7484
7876
  import {
7485
7877
  blue as blue2,
7486
- cyan as cyan3,
7487
- gray as gray2,
7488
- options as koloristOptions,
7878
+ cyan as cyan4,
7879
+ gray as gray3,
7880
+ options as koloristOptions2,
7489
7881
  lightCyan,
7490
7882
  trueColor,
7491
7883
  white as white2
7492
7884
  } from "kolorist";
7493
- var HELMET_OUTLINE = "#e2e8f0";
7494
7885
  var KOLORIST_TRUECOLOR = 3;
7495
7886
  var HELMET_ASCII = [
7496
7887
  " ____",
@@ -7515,30 +7906,20 @@ function outlineAnsi(line) {
7515
7906
  return trueColor(r, g, b)(line);
7516
7907
  }
7517
7908
  function withKoloristColor(fn) {
7518
- const prevEnabled = koloristOptions.enabled;
7519
- const prevLevel = koloristOptions.supportLevel;
7520
- koloristOptions.enabled = true;
7521
- koloristOptions.supportLevel = KOLORIST_TRUECOLOR;
7909
+ const prevEnabled = koloristOptions2.enabled;
7910
+ const prevLevel = koloristOptions2.supportLevel;
7911
+ koloristOptions2.enabled = true;
7912
+ koloristOptions2.supportLevel = KOLORIST_TRUECOLOR;
7522
7913
  try {
7523
7914
  return fn();
7524
7915
  } finally {
7525
- koloristOptions.enabled = prevEnabled;
7526
- koloristOptions.supportLevel = prevLevel;
7916
+ koloristOptions2.enabled = prevEnabled;
7917
+ koloristOptions2.supportLevel = prevLevel;
7527
7918
  }
7528
7919
  }
7529
7920
  function hasCliSubcommand(rawArgs) {
7530
7921
  return Boolean(rawArgs?.some((arg) => !arg.startsWith("-")));
7531
7922
  }
7532
- function shouldUseWelcomeColor(opts = {}) {
7533
- if (opts.color === false) return false;
7534
- if (process.env.NO_COLOR) return false;
7535
- if (process.env.NODE_DISABLE_COLORS) return false;
7536
- if (process.env.FORCE_COLOR === "0") return false;
7537
- if (process.env.CI != null && process.env.CI !== "") return false;
7538
- if (opts.color === true) return true;
7539
- const tty = opts.stdoutIsTTY ?? Boolean(process.stdout.isTTY);
7540
- return tty;
7541
- }
7542
7923
  function renderHelmetAscii(color) {
7543
7924
  if (!color) return HELMET_ASCII.join("\n");
7544
7925
  return withKoloristColor(
@@ -7560,8 +7941,8 @@ function renderWelcomeScreen(opts = {}) {
7560
7941
  const version = opts.version ?? KIT_VERSION;
7561
7942
  const color = shouldUseWelcomeColor(opts);
7562
7943
  const title = color ? white2("Mission Kit") : "Mission Kit";
7563
- const product = color ? cyan3("agent-kit") : "agent-kit";
7564
- const muted = (s) => color ? gray2(s) : s;
7944
+ const product = color ? cyan4("agent-kit") : "agent-kit";
7945
+ const muted = (s) => color ? gray3(s) : s;
7565
7946
  const lines = [
7566
7947
  renderHelmetAscii(color),
7567
7948
  "",
@@ -7573,13 +7954,18 @@ function renderWelcomeScreen(opts = {}) {
7573
7954
  const width = Math.max(...WELCOME_UTILITY_HINTS.map(({ cmd }) => cmd.length));
7574
7955
  return WELCOME_UTILITY_HINTS.map(({ cmd, hint }) => {
7575
7956
  const pad = " ".repeat(width - cmd.length + 2);
7576
- const left = color ? cyan3(` ${cmd}`) : ` ${cmd}`;
7957
+ const left = color ? cyan4(` ${cmd}`) : ` ${cmd}`;
7577
7958
  return `${left}${pad}${muted(hint)}`;
7578
7959
  });
7579
7960
  })(),
7580
7961
  "",
7581
7962
  muted(
7582
7963
  "Chat HITL (start-project, git-staging/prod, run-plan-all) stays in Cursor slash commands."
7964
+ ),
7965
+ muted(
7966
+ `${shouldUseVisualMotion(opts) ? SPACE_MARKS.star : SPACE_MARKS.tick} ${tipAt(
7967
+ [...version].reduce((n, c) => n + c.charCodeAt(0), 0)
7968
+ )}`
7583
7969
  )
7584
7970
  ];
7585
7971
  return `${lines.join("\n")}
@@ -7630,7 +8016,7 @@ async function resolveSubMeta(subCommands) {
7630
8016
  async function renderGroupedRootHelp(cmd) {
7631
8017
  const color = shouldUseWelcomeColor();
7632
8018
  const u = (s) => color ? underline(bold(s)) : s;
7633
- const g = (s) => color ? gray3(s) : s;
8019
+ const g = (s) => color ? gray4(s) : s;
7634
8020
  const meta = await resolveCommandMeta(cmd.meta);
7635
8021
  const name = meta?.name ?? "agent-kit";
7636
8022
  const version = meta?.version ?? KIT_VERSION;
@@ -7660,11 +8046,14 @@ async function renderGroupedRootHelp(cmd) {
7660
8046
  }
7661
8047
  lines.push("");
7662
8048
  }
8049
+ const tipMark = shouldUseVisualMotion() ? SPACE_MARKS.star : SPACE_MARKS.tick;
8050
+ const tip = tipAt([...version].reduce((n, c) => n + c.charCodeAt(0), 0));
7663
8051
  lines.push(
7664
8052
  g(`Use \`${name} <command> --help\` for more information about a command.`),
7665
8053
  g(
7666
8054
  "Chat-only HITL (start-project, backlog, git-staging/prod, run-plan-all) is not a CLI surface."
7667
8055
  ),
8056
+ g(`${tipMark} ${tip}`),
7668
8057
  ""
7669
8058
  );
7670
8059
  return lines.join("\n");