@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/README.md CHANGED
@@ -55,6 +55,8 @@ NO_COLOR=1 agent-kit
55
55
 
56
56
  Subcommands and `agent-kit --version` are unchanged. Chat-only HITL flows (`/start-project`, `/git-staging`, `/git-prod`, `/run-plan-all`, backlog CRUD) are not CLI commands.
57
57
 
58
+ On an interactive TTY, long-running commands (`init`, `install`, `doctor`, `update`, `run-plan` ticks) show an in-process ANSI spinner plus a rotating Mission Kit tip. Set `AGENT_KIT_REDUCED_MOTION=1` for static text on a capable TTY. Runtime dependencies stay `@clack/prompts`, `citty`, and `kolorist` (no `ora` / `figlet` / `chalk` / `ink`). Window titles for `agent-kit dashboard` and `agent-kit dashboard-broadcast` use the workspace basename, not the CLI package folder.
59
+
58
60
  ## Common commands
59
61
 
60
62
  | Command | Purpose |
@@ -5606,9 +5606,31 @@ function renderConfigSection(d) {
5606
5606
  <div class="config-row">
5607
5607
  <label for="config-epr-backend">Backend</label>
5608
5608
  <select id="config-epr-backend" name="eprBackend" data-focus-key="config-epr-backend">
5609
+ <option value="auto"${epr.backend === 'auto' ? ' selected' : ''}>auto</option>
5609
5610
  <option value="claude"${epr.backend === 'claude' || !epr.backend ? ' selected' : ''}>claude</option>
5611
+ <option value="cursor"${epr.backend === 'cursor' ? ' selected' : ''}>cursor</option>
5610
5612
  </select>
5611
- <span class="config-hint">claude is the only backend today.</span>
5613
+ <span class="config-hint">auto uses Claude when usable, else Cursor Agent. Pin claude or cursor to force one backend.</span>
5614
+ </div>
5615
+ <div class="config-row">
5616
+ <label for="config-epr-reviewerModel">Reviewer model</label>
5617
+ <input type="text" id="config-epr-reviewerModel" name="eprReviewerModel" value="${escapeAttr(epr.reviewerModel || 'haiku')}" maxlength="64" data-focus-key="config-epr-reviewerModel" />
5618
+ <span class="config-hint">Claude default haiku. Must differ from the implementer stamp (Auto/Auto refused).</span>
5619
+ </div>
5620
+ <div class="config-row">
5621
+ <label for="config-epr-advisorModel">Advisor model</label>
5622
+ <input type="text" id="config-epr-advisorModel" name="eprAdvisorModel" value="${escapeAttr(epr.advisorModel || 'opus')}" maxlength="64" data-focus-key="config-epr-advisorModel" />
5623
+ <span class="config-hint">Opus only when the monitor marks high severity or uncertainty.</span>
5624
+ </div>
5625
+ <div class="config-row">
5626
+ <label for="config-epr-waitSlice">Wait slice (seconds)</label>
5627
+ <input type="number" id="config-epr-waitSlice" name="eprWaitSlice" min="1" max="3600" step="1" value="${escapeAttr(String(epr.waitSliceSeconds || 90))}" data-focus-key="config-epr-waitSlice" />
5628
+ <span class="config-hint">Chat AwaitShell budget per session. Default 90.</span>
5629
+ </div>
5630
+ <div class="config-row">
5631
+ <label for="config-epr-waitTimeout">Wait timeout (seconds)</label>
5632
+ <input type="number" id="config-epr-waitTimeout" name="eprWaitTimeout" min="1" max="86400" step="1" value="${escapeAttr(String(epr.waitTimeoutSeconds || 900))}" data-focus-key="config-epr-waitTimeout" />
5633
+ <span class="config-hint">Total remaining budget across slices and CI. Default 900.</span>
5612
5634
  </div>
5613
5635
  <div class="config-row">
5614
5636
  <label for="config-epr-mode">Arming mode</label>
@@ -5680,6 +5702,18 @@ function collectMissionConfigPayload() {
5680
5702
  offerOnExhausted: !!document.getElementById('config-epr-offer')?.checked,
5681
5703
  autoRemediate: !!document.getElementById('config-epr-auto')?.checked,
5682
5704
  backend: document.getElementById('config-epr-backend')?.value || 'claude',
5705
+ reviewerModel: (document.getElementById('config-epr-reviewerModel')?.value || 'haiku').trim(),
5706
+ advisorModel: (document.getElementById('config-epr-advisorModel')?.value || 'opus').trim(),
5707
+ waitSliceSeconds: (() => {
5708
+ const raw = document.getElementById('config-epr-waitSlice')?.value;
5709
+ const n = Number.parseInt(String(raw || '90'), 10);
5710
+ return Number.isFinite(n) && n >= 1 ? n : 90;
5711
+ })(),
5712
+ waitTimeoutSeconds: (() => {
5713
+ const raw = document.getElementById('config-epr-waitTimeout')?.value;
5714
+ const n = Number.parseInt(String(raw || '900'), 10);
5715
+ return Number.isFinite(n) && n >= 1 ? n : 900;
5716
+ })(),
5683
5717
  mode: document.getElementById('config-epr-mode')?.value || 'paste',
5684
5718
  midBatchAudits: !!document.getElementById('config-epr-midBatch')?.checked,
5685
5719
  preflight: document.getElementById('config-epr-preflight')?.value || 'off',
@@ -445,7 +445,10 @@ export const CONFIG_PERSONA_IDS = Object.freeze(["autopilot", "night-shift", "gh
445
445
  export const CONFIG_PERSONA_MODES = Object.freeze(["continue-plan", "run-plan", "cli-run-plan"]);
446
446
 
447
447
  /** Allowed externalPlanReview.backend values. */
448
- export const CONFIG_REVIEW_BACKENDS = Object.freeze(["claude"]);
448
+ export const CONFIG_REVIEW_BACKENDS = Object.freeze(["auto", "claude", "cursor"]);
449
+
450
+ /** Named reviewer / advisor / implementer model id (no secrets). */
451
+ const REVIEW_MODEL_ID = /^[A-Za-z0-9._:+-]{1,64}$/;
449
452
 
450
453
  /** Allowed externalPlanReview.mode values (audits arming path). */
451
454
  export const CONFIG_REVIEW_MODES = Object.freeze(["paste", "autonomous"]);
@@ -591,6 +594,10 @@ export function validateConfigWriteBody(body) {
591
594
  const eprAllowed = new Set([
592
595
  "enabled",
593
596
  "backend",
597
+ "reviewerModel",
598
+ "advisorModel",
599
+ "waitSliceSeconds",
600
+ "waitTimeoutSeconds",
594
601
  "autoRemediate",
595
602
  "offerOnExhausted",
596
603
  "mode",
@@ -612,10 +619,45 @@ export function validateConfigWriteBody(body) {
612
619
  }
613
620
  if ("backend" in epr) {
614
621
  if (typeof epr.backend !== "string" || !CONFIG_REVIEW_BACKENDS.includes(epr.backend)) {
615
- return { ok: false, error: "externalPlanReview.backend must be a known backend" };
622
+ return { ok: false, error: "externalPlanReview.backend must be auto, claude, or cursor" };
616
623
  }
617
624
  eprPatch.backend = epr.backend;
618
625
  }
626
+ if ("reviewerModel" in epr) {
627
+ if (
628
+ typeof epr.reviewerModel !== "string" ||
629
+ !REVIEW_MODEL_ID.test(epr.reviewerModel.trim())
630
+ ) {
631
+ return { ok: false, error: "externalPlanReview.reviewerModel must be a model id" };
632
+ }
633
+ eprPatch.reviewerModel = epr.reviewerModel.trim();
634
+ }
635
+ if ("advisorModel" in epr) {
636
+ if (typeof epr.advisorModel !== "string" || !REVIEW_MODEL_ID.test(epr.advisorModel.trim())) {
637
+ return { ok: false, error: "externalPlanReview.advisorModel must be a model id" };
638
+ }
639
+ eprPatch.advisorModel = epr.advisorModel.trim();
640
+ }
641
+ if ("waitSliceSeconds" in epr) {
642
+ const n = epr.waitSliceSeconds;
643
+ if (typeof n !== "number" || !Number.isInteger(n) || n < 1 || n > 3600) {
644
+ return {
645
+ ok: false,
646
+ error: "externalPlanReview.waitSliceSeconds must be an integer 1..3600",
647
+ };
648
+ }
649
+ eprPatch.waitSliceSeconds = n;
650
+ }
651
+ if ("waitTimeoutSeconds" in epr) {
652
+ const n = epr.waitTimeoutSeconds;
653
+ if (typeof n !== "number" || !Number.isInteger(n) || n < 1 || n > 86400) {
654
+ return {
655
+ ok: false,
656
+ error: "externalPlanReview.waitTimeoutSeconds must be an integer 1..86400",
657
+ };
658
+ }
659
+ eprPatch.waitTimeoutSeconds = n;
660
+ }
619
661
  if ("autoRemediate" in epr) {
620
662
  if (typeof epr.autoRemediate !== "boolean") {
621
663
  return { ok: false, error: "externalPlanReview.autoRemediate must be boolean" };
@@ -847,6 +889,18 @@ export function allowlistConfig(raw) {
847
889
  if (typeof raw.externalPlanReview.preflight === "string") {
848
890
  epr.preflight = truncateStr(raw.externalPlanReview.preflight, 16);
849
891
  }
892
+ if (typeof raw.externalPlanReview.reviewerModel === "string") {
893
+ epr.reviewerModel = truncateStr(raw.externalPlanReview.reviewerModel, 64);
894
+ }
895
+ if (typeof raw.externalPlanReview.advisorModel === "string") {
896
+ epr.advisorModel = truncateStr(raw.externalPlanReview.advisorModel, 64);
897
+ }
898
+ if (typeof raw.externalPlanReview.waitSliceSeconds === "number") {
899
+ epr.waitSliceSeconds = raw.externalPlanReview.waitSliceSeconds;
900
+ }
901
+ if (typeof raw.externalPlanReview.waitTimeoutSeconds === "number") {
902
+ epr.waitTimeoutSeconds = raw.externalPlanReview.waitTimeoutSeconds;
903
+ }
850
904
  summary.externalPlanReview = epr;
851
905
  }
852
906
  if (raw.agentPersona && typeof raw.agentPersona === "object") {
@@ -9,7 +9,7 @@
9
9
 
10
10
  import { execFileSync, execSync, spawn } from "node:child_process";
11
11
  import { existsSync, openSync } from "node:fs";
12
- import { dirname, join } from "node:path";
12
+ import { basename, dirname, join } from "node:path";
13
13
  import { fileURLToPath } from "node:url";
14
14
  import {
15
15
  buildBroadcastShareUrl,
@@ -35,6 +35,7 @@ const __dirname = dirname(fileURLToPath(import.meta.url));
35
35
  const KIT_ROOT = join(__dirname, "..");
36
36
  /** Workspace snapshots / preference config. Defaults to KIT_ROOT. */
37
37
  const ROOT = resolveSnapshotRepoRoot(process.env, KIT_ROOT);
38
+ process.title = `Mission Control · ${basename(ROOT) || "workspace"}`;
38
39
  const SERVE = join(__dirname, "serve.mjs");
39
40
  const LOG = process.env.MISSION_CONTROL_LOG || "/tmp/mission-control-broadcast.log";
40
41
  const PORT = Number.parseInt(process.env.PORT || "3333", 10);
@@ -18,7 +18,7 @@
18
18
 
19
19
  import { execFileSync, execSync, spawn } from "node:child_process";
20
20
  import { existsSync, openSync } from "node:fs";
21
- import { dirname, join, resolve } from "node:path";
21
+ import { basename, dirname, join, resolve } from "node:path";
22
22
  import { fileURLToPath } from "node:url";
23
23
  import {
24
24
  REPO_ROOT_ENV,
@@ -34,6 +34,7 @@ import { openBrowser, readPreferredBrowserFromConfig } from "./lib/open-browser.
34
34
  const __dirname = dirname(fileURLToPath(import.meta.url));
35
35
  const KIT_ROOT = join(__dirname, "..");
36
36
  const ROOT = resolveSnapshotRepoRoot(process.env, KIT_ROOT);
37
+ process.title = `Mission Control · ${basename(ROOT) || "workspace"}`;
37
38
  const SERVE = join(__dirname, "serve.mjs");
38
39
  const HOST = process.env.HOST || "127.0.0.1";
39
40
  const DISPLAY_HOST = HOST === "0.0.0.0" ? "127.0.0.1" : HOST;