@dadado/agent-kit-cli 5.5.0 → 5.7.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.
@@ -1173,6 +1173,45 @@ body.mc-fullscreen .top-tabs-row {
1173
1173
  color: var(--text-secondary);
1174
1174
  margin: 12px 0 6px;
1175
1175
  }
1176
+ .git-graph-title:first-child { margin-top: 0; }
1177
+
1178
+ /* ===== DevOps ===== */
1179
+ /* Row visual language mirrors .git-flow-row (state dot + lane + meta) so the
1180
+ * new tab reads as the same product, not a second component vocabulary. */
1181
+ .devops-row {
1182
+ display: flex;
1183
+ align-items: center;
1184
+ gap: 10px;
1185
+ font-size: 12px;
1186
+ padding: 8px 10px;
1187
+ border: 1px solid var(--border);
1188
+ border-radius: 8px;
1189
+ background: var(--bg-card);
1190
+ flex-wrap: wrap;
1191
+ margin-bottom: 6px;
1192
+ }
1193
+ .devops-row:last-child { margin-bottom: 0; }
1194
+ .devops-name {
1195
+ font-weight: 600;
1196
+ color: var(--text-primary);
1197
+ flex-shrink: 0;
1198
+ }
1199
+ .devops-meta {
1200
+ color: var(--text-secondary);
1201
+ flex: 1;
1202
+ min-width: 0;
1203
+ }
1204
+ .devops-time {
1205
+ color: var(--text-muted);
1206
+ font-family: var(--mc-font-mono);
1207
+ font-size: 11px;
1208
+ flex-shrink: 0;
1209
+ }
1210
+ .devops-note {
1211
+ font-size: 11px;
1212
+ color: var(--text-muted);
1213
+ margin: 0 0 8px;
1214
+ }
1176
1215
  .git-hygiene {
1177
1216
  display: flex;
1178
1217
  align-items: flex-start;
@@ -3644,6 +3683,10 @@ html[data-monitor-density="comfortable"] .live-activity-feed .monitor-row .monit
3644
3683
  Git
3645
3684
  <span class="dot dot-gray" id="navGitDot" aria-hidden="true"></span>
3646
3685
  </a>
3686
+ <a class="top-tab nav-more-item" role="menuitem" href="#" data-section="devops" tabindex="0" onclick="return showSection('devops')" aria-label="DevOps section">
3687
+ DevOps
3688
+ <span class="dot dot-gray" id="navDevopsDot" aria-hidden="true"></span>
3689
+ </a>
3647
3690
  <a class="top-tab nav-more-item" role="menuitem" href="#" data-section="memory" tabindex="0" onclick="return showSection('memory')" aria-label="Memory section">
3648
3691
  Memory
3649
3692
  </a>
@@ -3819,6 +3862,7 @@ const SECTION_IDS = [
3819
3862
  'commands',
3820
3863
  'health',
3821
3864
  'git',
3865
+ 'devops',
3822
3866
  'memory',
3823
3867
  'terminals',
3824
3868
  'processes',
@@ -5430,6 +5474,199 @@ function renderGitGraphCard(git) {
5430
5474
  `;
5431
5475
  }
5432
5476
 
5477
+ /** Cap for the visual tree row count (mirrors MAX_GIT_GRAPH_LINES server-side cap, further
5478
+ * bounded here so the stepper stays a glance, not a scroll well). */
5479
+ const MAX_GIT_VISUAL_TREE_ROWS = 12;
5480
+
5481
+ /**
5482
+ * Parse `git log --graph --oneline --decorate` lines into flattened commit
5483
+ * entries. Connector-only lines (`|`, `/`, `\`, whitespace between lanes)
5484
+ * carry no commit and are skipped — see the plan's "Phase 0 lane-flattening
5485
+ * interpretation" note: this trades true branch-lane geometry (still fully
5486
+ * present in the kept markdown block) for one row per commit.
5487
+ */
5488
+ function parseGitGraphCommits(lines) {
5489
+ const commits = [];
5490
+ for (const line of Array.isArray(lines) ? lines : []) {
5491
+ const m = /\*\s*([0-9a-f]{4,40})\s+(?:\(([^)]*)\)\s*)?(.*)$/.exec(line);
5492
+ if (!m) continue;
5493
+ const decoration = (m[2] || '').trim();
5494
+ commits.push({
5495
+ hash: m[1],
5496
+ decoration,
5497
+ subject: (m[3] || '').trim(),
5498
+ isHead: /\bHEAD\b/.test(decoration),
5499
+ isPromoted: /\borigin\/(main|staging)\b/.test(decoration),
5500
+ });
5501
+ }
5502
+ return commits;
5503
+ }
5504
+
5505
+ /**
5506
+ * Visual companion to the markdown git-graph block: reuses the exact
5507
+ * .now-stepper/.now-step/.now-step-marker timeline primitive (state-colored
5508
+ * markers + connecting line) with one row per parsed commit. Dot/marker
5509
+ * semantics stay locked to the existing Now-panel vocabulary: current/blue =
5510
+ * HEAD, done/green = already promoted to origin/main or origin/staging,
5511
+ * neutral = neither. Degrades to a compact empty-state when the graph has no
5512
+ * parseable commit line (e.g. a shallow clone) while a branch still exists.
5513
+ */
5514
+ function renderGitVisualTree(git) {
5515
+ const commits = parseGitGraphCommits(git?.graph);
5516
+ if (!commits.length) {
5517
+ if (!git?.branch) return '';
5518
+ return renderEmptyStateCta({
5519
+ headline: 'No visual tree yet',
5520
+ support: 'The commit graph had no parseable commit line to render.',
5521
+ compact: true,
5522
+ className: 'git-visual-tree-empty',
5523
+ });
5524
+ }
5525
+ const shown = commits.slice(0, MAX_GIT_VISUAL_TREE_ROWS);
5526
+ const rows = shown
5527
+ .map((c) => {
5528
+ const stateClass = c.isHead ? ' now-step-current' : c.isPromoted ? ' now-step-done' : '';
5529
+ const marker = c.isHead ? '●' : c.isPromoted ? '✓' : '○';
5530
+ const label = c.decoration ? escapeHtml(c.decoration) : 'Commit';
5531
+ const text = `<span class="now-todo-id">${escapeHtml(c.hash)}</span>${c.subject ? ` — ${escapeHtml(c.subject)}` : ''}`;
5532
+ return `
5533
+ <li class="now-step${stateClass}">
5534
+ <span class="now-step-marker" aria-hidden="true">${marker}</span>
5535
+ <div class="now-step-body">
5536
+ <span class="now-step-label">${label}</span>
5537
+ <div class="now-step-text">${text}</div>
5538
+ </div>
5539
+ </li>
5540
+ `;
5541
+ })
5542
+ .join('');
5543
+ return `
5544
+ <div class="git-graph-title">Visual tree (${shown.length} of ${commits.length} commit${commits.length !== 1 ? 's' : ''})</div>
5545
+ <ol class="now-stepper git-visual-tree" aria-label="Visual commit tree: state-colored markers by promotion status">
5546
+ ${rows}
5547
+ </ol>
5548
+ `;
5549
+ }
5550
+
5551
+ /** `in_progress` / `timed_out` -> `In progress` / `Timed out`. */
5552
+ function humanizeRunStatus(s) {
5553
+ const raw = String(s || '').trim();
5554
+ if (!raw) return 'Unknown';
5555
+ return raw
5556
+ .split('_')
5557
+ .map((w) => (w ? w[0].toUpperCase() + w.slice(1) : w))
5558
+ .join(' ');
5559
+ }
5560
+
5561
+ /** Dot tone for one `gh run list` row: in-flight states read yellow; a
5562
+ * completed run reads by conclusion (green/red/yellow), never decorative. */
5563
+ function pipelineRunTone(run) {
5564
+ if (run.status !== 'completed') return 'yellow';
5565
+ if (run.conclusion === 'success') return 'green';
5566
+ if (['failure', 'cancelled', 'timed_out'].includes(run.conclusion)) return 'red';
5567
+ return 'yellow';
5568
+ }
5569
+
5570
+ /**
5571
+ * CI/CD pipeline card (Phase 2): recent `gh run list` rows, honest empty-state
5572
+ * when the collector didn't produce runs. Display only, no CTA — a
5573
+ * workflow-run URL has no named paste destination in the copy-only
5574
+ * convention (ADR 2026-07-25), so this card ships without one rather than
5575
+ * inventing a destination.
5576
+ *
5577
+ * Empty-state copy is keyed off `pipeline.reason` rather than one blanket
5578
+ * message: live measurement (2026-08-24, mc-git-tab-devops-pipeline-timeout
5579
+ * residuals) found the dominant real case is the shared snapshot budget
5580
+ * running out before `gh` is even attempted ('budget'), not gh being
5581
+ * missing/unauthenticated — the old unconditional "gh is unavailable or not
5582
+ * authenticated" copy misattributed that case and pointed the operator at
5583
+ * the wrong fix.
5584
+ */
5585
+ function renderDevopsPipelineCard(devops) {
5586
+ const pipeline = devops?.pipeline || null;
5587
+ if (!pipeline?.available) {
5588
+ const support = pipeline?.reason === 'budget'
5589
+ ? 'This snapshot ran out of time before checking recent workflow runs — refresh to retry.'
5590
+ : 'Recent workflow runs could not be read this snapshot (gh may be missing, unauthenticated, or the call timed out).';
5591
+ return renderEmptyStateCta({
5592
+ headline: 'No pipeline signal',
5593
+ support,
5594
+ compact: true,
5595
+ className: 'devops-pipeline-empty',
5596
+ });
5597
+ }
5598
+ const runs = pipeline.runs || [];
5599
+ if (!runs.length) {
5600
+ return renderEmptyStateCta({
5601
+ headline: 'No recent runs',
5602
+ support: 'No GitHub Actions workflow runs found for this repository.',
5603
+ compact: true,
5604
+ className: 'devops-pipeline-empty',
5605
+ });
5606
+ }
5607
+ const rows = runs
5608
+ .map((r) => {
5609
+ const tone = pipelineRunTone(r);
5610
+ const label = humanizeRunStatus(r.status === 'completed' ? r.conclusion || 'unknown' : r.status);
5611
+ return `
5612
+ <div class="devops-row">
5613
+ <span class="dot dot-${tone}" aria-hidden="true"></span>
5614
+ <span class="devops-name">${escapeHtml(r.workflow || 'Workflow')}</span>
5615
+ <span class="devops-meta">${escapeHtml(label)} · ${escapeHtml(r.branch || '—')} · ${escapeHtml(r.event || '—')}</span>
5616
+ <span class="devops-time">${escapeHtml(fmtDate(r.createdAt))}</span>
5617
+ </div>
5618
+ `;
5619
+ })
5620
+ .join('');
5621
+ return rows;
5622
+ }
5623
+
5624
+ /**
5625
+ * Deploy-activity card (Phase 3, best-effort, honest): a "what shipped
5626
+ * recently" proxy from `v*` git tags and the latest non-Unreleased CHANGELOG
5627
+ * entry. Deliberately not a live infra/hosting poll — no fabricated service
5628
+ * tiles for sources this dashboard does not actually reach.
5629
+ */
5630
+ function renderDevopsDeployCard(devops) {
5631
+ const deploy = devops?.deploy || null;
5632
+ const tags = deploy?.tags || [];
5633
+ const changelog = deploy?.changelog || null;
5634
+ if (!tags.length && !changelog) {
5635
+ return renderEmptyStateCta({
5636
+ headline: 'No deploy signal yet',
5637
+ support: 'No git release tags (v*) or a parseable CHANGELOG release entry were found. This section reflects what shipped, from tags and CHANGELOG only — it does not poll live infra or hosting.',
5638
+ compact: true,
5639
+ className: 'devops-deploy-empty',
5640
+ });
5641
+ }
5642
+ const changelogRow = changelog
5643
+ ? `
5644
+ <div class="devops-row">
5645
+ <span class="dot dot-green" aria-hidden="true"></span>
5646
+ <span class="devops-name">CHANGELOG ${escapeHtml(changelog.version)}</span>
5647
+ <span class="devops-meta">${escapeHtml((changelog.items || []).join(' · ') || 'Release notes')}</span>
5648
+ <span class="devops-time">${escapeHtml(changelog.date || '—')}</span>
5649
+ </div>
5650
+ `
5651
+ : '';
5652
+ const tagRows = tags
5653
+ .map(
5654
+ (t) => `
5655
+ <div class="devops-row">
5656
+ <span class="dot dot-gray" aria-hidden="true"></span>
5657
+ <span class="devops-name">${escapeHtml(t.name)}</span>
5658
+ <span class="devops-meta">git tag</span>
5659
+ <span class="devops-time">${escapeHtml(t.date || '—')}</span>
5660
+ </div>
5661
+ `,
5662
+ )
5663
+ .join('');
5664
+ return `
5665
+ <div class="devops-note">Best-effort "what shipped recently" from git tags + CHANGELOG — not a live infra/deploy poll.</div>
5666
+ ${changelogRow}${tagRows}
5667
+ `;
5668
+ }
5669
+
5433
5670
  /** Staging hygiene: untracked plan-monitor WIP (add-by-name only; ADR 2026-07-29 R14). */
5434
5671
  function renderGitHygieneHint(git) {
5435
5672
  const wip = git?.hygiene?.monitorWip || [];
@@ -6788,7 +7025,7 @@ function nowMetaIconSvg(kind, opts) {
6788
7025
  * features >= 1 unit. Detail that cannot meet the floor is drawn filled
6789
7026
  * (fill="currentColor" stroke="none"), never as a sub-stroke stroked shape.
6790
7027
  * Static path markup only; never concatenate untrusted text into the SVG.
6791
- * @param {'current-mission'|'monitor'|'field-report'|'checklist'|'more-sections'|'overview'|'plans'|'activity'|'agents'|'skills'|'skins'|'commands'|'health'|'git'|'memory'|'terminals'|'processes'|'config'} kind
7028
+ * @param {'current-mission'|'monitor'|'field-report'|'checklist'|'more-sections'|'overview'|'plans'|'activity'|'agents'|'skills'|'skins'|'commands'|'health'|'git'|'devops'|'memory'|'terminals'|'processes'|'config'} kind
6792
7029
  * @param {{ decorative?: boolean }} [opts] decorative true (default): aria-hidden next to a visible label.
6793
7030
  * decorative false: role=img + aria-label + title for icon-only controls (e.g. more-sections).
6794
7031
  */
@@ -6810,6 +7047,7 @@ function spaceIconSvg(kind, opts) {
6810
7047
  commands: 'Commands',
6811
7048
  health: 'Health',
6812
7049
  git: 'Git',
7050
+ devops: 'DevOps',
6813
7051
  memory: 'Memory',
6814
7052
  terminals: 'Terminals',
6815
7053
  processes: 'Processes',
@@ -6877,6 +7115,12 @@ function spaceIconSvg(kind, opts) {
6877
7115
  '<path d="M10.5 4.5v7a2 2 0 01-2 2h-2"/>' +
6878
7116
  '<path d="M6.5 11.5a2 2 0 100-4 2 2 0 000 4z"/>' +
6879
7117
  '<path d="M10.5 6.5v2"/>',
7118
+ // Linked nodes (devops) — two pipeline-stage circles joined by a short
7119
+ // link; distinct from the Git branch glyph and from the Skills gear.
7120
+ devops:
7121
+ '<circle cx="5" cy="8" r="2.25"/>' +
7122
+ '<circle cx="11" cy="8" r="2.25"/>' +
7123
+ '<path d="M7.25 8h1.5"/>',
6880
7124
  // Chip (memory) — two internal lines 3 units apart; a third line would drop clearance below the stroke floor
6881
7125
  memory:
6882
7126
  '<path d="M4.5 2.5h7a1 1 0 011 1v9a1 1 0 01-1 1h-7a1 1 0 01-1-1v-9a1 1 0 011-1z"/>' +
@@ -7779,6 +8023,24 @@ function renderUnsafe() {
7779
8023
  gitDot.className = 'dot dot-green';
7780
8024
  }
7781
8025
 
8026
+ // DevOps nav dot: state of the most recent pipeline run only (gray = no
8027
+ // signal / gh unavailable, green = latest run succeeded, yellow = latest
8028
+ // run in progress or non-success conclusion other than a hard failure,
8029
+ // red = latest run failed/cancelled/timed out).
8030
+ const devopsDot = document.getElementById('navDevopsDot');
8031
+ const latestRun = (d.devops?.pipeline?.runs || [])[0] || null;
8032
+ if (!latestRun) {
8033
+ devopsDot.className = 'dot dot-gray';
8034
+ } else if (latestRun.status !== 'completed') {
8035
+ devopsDot.className = 'dot dot-yellow';
8036
+ } else if (latestRun.conclusion === 'success') {
8037
+ devopsDot.className = 'dot dot-green';
8038
+ } else if (['failure', 'cancelled', 'timed_out'].includes(latestRun.conclusion)) {
8039
+ devopsDot.className = 'dot dot-red';
8040
+ } else {
8041
+ devopsDot.className = 'dot dot-yellow';
8042
+ }
8043
+
7782
8044
  // Terminals / processes nav items carry count badges only (no decorative dots).
7783
8045
 
7784
8046
  // Build full HTML string once
@@ -8169,11 +8431,33 @@ function renderUnsafe() {
8169
8431
  </div>
8170
8432
  </div>
8171
8433
  ${renderGitGraphCard(d.git)}
8434
+ ${renderGitVisualTree(d.git)}
8172
8435
  ${d.git?.dirty ? renderGitFileList(d.git) : ''}
8173
8436
  </div>
8174
8437
  </div>
8175
8438
  `);
8176
8439
 
8440
+ // ===== DevOps =====
8441
+ // Distinct scope from Processes (local-process-only): CI/CD pipeline status
8442
+ // + a best-effort, honestly-scoped deploy-activity proxy. No fabricated
8443
+ // "service health" widgets for infra this dashboard does not actually poll.
8444
+ const devopsPipelineRuns = d.devops?.pipeline?.runs || [];
8445
+ const devopsRunCount = devopsPipelineRuns.length;
8446
+ parts.push(`
8447
+ <div class="content-section" id="section-devops">
8448
+ <div class="section-title">
8449
+ DevOps
8450
+ <span class="section-subtitle">${devopsRunCount} pipeline run${devopsRunCount !== 1 ? 's' : ''}</span>
8451
+ </div>
8452
+ <div class="card">
8453
+ <div class="git-graph-title">CI/CD pipeline</div>
8454
+ ${renderDevopsPipelineCard(d.devops)}
8455
+ <div class="git-graph-title">Deploy activity</div>
8456
+ ${renderDevopsDeployCard(d.devops)}
8457
+ </div>
8458
+ </div>
8459
+ `);
8460
+
8177
8461
  // ===== Memory =====
8178
8462
  const recentDecisions = d.memory?.recentDecisions || [];
8179
8463
  const recentErrors = d.memory?.recentErrors || [];
@@ -0,0 +1,23 @@
1
+ /** Ambient types for dashboard/lib/live-refresh.mjs (consumed by CLI TypeScript). */
2
+
3
+ export const WATCH_DEBOUNCE_MS: 400;
4
+ export const PERIODIC_REFRESH_MS: 15000;
5
+ export const SSE_SILENCE_MS: 20000;
6
+ export const SNAPSHOT_REPO_SOURCE_RELS: readonly string[];
7
+
8
+ export function projectSlugFromRoot(root: string): string;
9
+ export function resolveAgentTranscriptsWatchPath(root: string, home?: string): string;
10
+ export function resolveWatchPaths(root: string, dashboardDir: string): string[];
11
+ export function watchCoversPath(watchAbs: string, targetAbs: string): boolean;
12
+ export function isCoveredByWatchPaths(watchAbsPaths: string[], targetAbs: string): boolean;
13
+ export function createTrailingDebounce(
14
+ fn: () => void,
15
+ ms: number,
16
+ timers?: {
17
+ setTimeout?: typeof setTimeout;
18
+ clearTimeout?: typeof clearTimeout;
19
+ now?: () => number;
20
+ maxWait?: number;
21
+ },
22
+ ): () => void;
23
+ export function isSseSilent(lastEventAt: number, now: number, silenceMs?: number): boolean;
@@ -24,10 +24,17 @@ export const MONITOR_FEED_CAP = 20;
24
24
  /** Cap agent_step rows emitted per active plan for the denser Crew feed. */
25
25
  export const MONITOR_AGENT_STEP_EMIT_CAP = 12;
26
26
 
27
- /** Cap subagent-run rows emitted per snapshot (fs scan bounds live in dashboard-data.mjs). */
28
- export const MONITOR_SUBAGENT_EMIT_CAP = 8;
29
- /** Cap plan_review pointer rows emitted per snapshot. */
30
- export const MONITOR_PLAN_REVIEW_EMIT_CAP = 4;
27
+ /**
28
+ * Cap subagent-run and plan_review pointer rows emitted per snapshot (fs scan
29
+ * bounds for the former live in dashboard-data.mjs). Halved from 8/4 (C-G3,
30
+ * plan-monitor-crew-monitor-compact-labels-realtime-activity-2026-08-05.md):
31
+ * at full caps the two kinds sat ahead of `plan_progress` in mergeActivity's
32
+ * priority concat and could claim 12 of MONITOR_FEED_CAP's 20 slots during a
33
+ * busy run-plan-all batch, squeezing out plan-progress rows. 4/2 leaves more
34
+ * headroom without reordering the merge itself.
35
+ */
36
+ export const MONITOR_SUBAGENT_EMIT_CAP = 4;
37
+ export const MONITOR_PLAN_REVIEW_EMIT_CAP = 2;
31
38
 
32
39
  /**
33
40
  * Monitor hero curated subset over the semantic activity stream.
@@ -2511,7 +2518,7 @@ export function formatPlanReviewActivity(
2511
2518
  label: truncateStr(visible, MAX_SEMANTIC_LABEL),
2512
2519
  labelFull: visible,
2513
2520
  sourcePath: report.path || null,
2514
- refs: { plan: report.reviewedPlanFile || null, report: report.file, triaged },
2521
+ refs: { plan: planRef, report: report.file, triaged },
2515
2522
  });
2516
2523
  }
2517
2524
  return events;
Binary file
@@ -0,0 +1,18 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="1280" height="640" viewBox="0 0 1280 640" fill="none">
2
+ <!-- GitHub repository social preview (1280x640, 2:1). Plate fill is Mission
3
+ Control bg-primary #0b0e14, matching the marketplace logo spec
4
+ (dashboard/logo-marketplace.svg). Artwork is the same Cursor-skin
5
+ stroke helmet from dashboard/logo-cursor.svg, centered. Manual upload
6
+ step: docs/github-about.md "Social preview". -->
7
+ <rect width="1280" height="640" fill="#0b0e14"/>
8
+ <g transform="translate(471 84) scale(15)">
9
+ <path d="M9.61,22.1c-4.45-1.22-7.48-4.71-8.17-9.63v-2.47c0-5.39,4.37-9.75,9.75-9.75h0c5.39,0,9.75,4.37,9.75,9.75,0,.62.04,1.85,0,2.47-.34,4.86-3.54,8.41-8.2,9.63-.49.13-2.63.13-3.13,0Z" stroke="#e4e4e4" stroke-width=".5" stroke-miterlimit="10" fill="none"/>
10
+ <path d="M18.42,9.54c-.38,3.74-1.81,8.07-7.22,8.07s-6.66-4.49-7.22-8.07v-.19c0-3.47,3.23-6.28,7.22-6.28s7.22,2.81,7.22,6.28v.19Z" stroke="#e4e4e4" stroke-width=".5" stroke-miterlimit="10" fill="none"/>
11
+ <path d="M13.59,6.08c1.18.76,1.99,1.85,2.2,3.16.07.43.07.86,0,1.28s-.19.84-.37,1.25" stroke="#e4e4e4" stroke-width=".5" stroke-linecap="round" fill="none"/>
12
+ <g>
13
+ <line x1=".25" y1="7.9" x2=".25" y2="13.68" stroke="#e4e4e4" stroke-width=".5" stroke-linecap="round"/>
14
+ <line x1="22.13" y1="7.9" x2="22.13" y2="13.68" stroke="#e4e4e4" stroke-width=".5" stroke-linecap="round"/>
15
+ </g>
16
+ </g>
17
+ <text x="640" y="530" text-anchor="middle" font-family="-apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif" font-size="46" font-weight="600" fill="#e2e8f0">Mission Kit</text>
18
+ </svg>