@dadado/agent-kit-cli 6.1.1 → 6.3.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/dashboard/README.md +3 -1
- package/dashboard/dashboard-data.mjs +13 -2
- package/dashboard/dashboard.html +95 -2
- package/dashboard/lib/gate-exit-tickets.d.mts +45 -0
- package/dashboard/lib/gate-exit-tickets.mjs +233 -0
- package/dashboard/lib/semantic-model.d.mts +21 -0
- package/dashboard/lib/semantic-model.mjs +47 -0
- package/dist/{add-YTCDLPUS.js → add-VA2W7I6P.js} +3 -3
- package/dist/{chunk-VTOUQAVR.js → chunk-25J2SMJQ.js} +9 -1
- package/dist/{chunk-2FQX2O4I.js → chunk-6GYKOHIL.js} +2 -2
- package/dist/{chunk-DBPNGZNH.js → chunk-6KUSG7BJ.js} +15 -2
- package/dist/{chunk-C26I6HTO.js → chunk-C4Q77GGJ.js} +0 -1
- package/dist/{chunk-U5F6RJN4.js → chunk-GO3K752H.js} +4 -1
- package/dist/chunk-GUQYNUV4.js +61 -0
- package/dist/{chunk-ESNAFDYT.js → chunk-JEI6HACW.js} +44 -1
- package/dist/chunk-KVY425NM.js +519 -0
- package/dist/{chunk-WUWRGOUV.js → chunk-L5V3W3DY.js} +13 -1
- package/dist/chunk-MO63KZBP.js +516 -0
- package/dist/chunk-MUTTNRX4.js +53 -0
- package/dist/{chunk-PPKX55GI.js → chunk-NNKOWUWM.js} +1 -1
- package/dist/{chunk-DRND2KYV.js → chunk-OVOXRH5W.js} +1 -1
- package/dist/{chunk-GN4SAZF2.js → chunk-OWWFKGKS.js} +2 -2
- package/dist/chunk-QTBTKEXK.js +77 -0
- package/dist/{chunk-TMFOLRU2.js → chunk-SV2BR2LZ.js} +44 -9
- package/dist/{chunk-3DGTPONS.js → chunk-U26MRIWN.js} +1 -1
- package/dist/{chunk-BBVBYQJO.js → chunk-VQBI3JVS.js} +2 -2
- package/dist/{chunk-YP4OOK4T.js → chunk-WMVMBPCR.js} +2 -2
- package/dist/{chunk-OZYJUNAQ.js → chunk-YRFSTHR5.js} +29 -525
- package/dist/{chunk-3XKVQS2K.js → chunk-Z7ABX5QI.js} +13 -9
- package/dist/{chunk-DBXDV5O7.js → chunk-Z7RYIHHX.js} +90 -5
- package/dist/{contribute-A7NCWTUM.js → contribute-NLM2BN6Z.js} +4 -4
- package/dist/countdown-QXJD6TDB.js +479 -0
- package/dist/{diff-4MDU5SLE.js → diff-HHG4JEDE.js} +5 -5
- package/dist/{doctor-SS6Y2T6H.js → doctor-TWF2M3S3.js} +9 -9
- package/dist/ground-control-NMYYIVCV.js +434 -0
- package/dist/{handoff-MK5JG3J5.js → handoff-5AGE2D3T.js} +3 -2
- package/dist/{hook-D2WHBKRN.js → hook-VP7FHRSZ.js} +7 -6
- package/dist/index.js +30 -20
- package/dist/{init-GVVBA2BM.js → init-UOTV4ASJ.js} +12 -12
- package/dist/{install-R4HPI7VK.js → install-VCHPXQV3.js} +12 -12
- package/dist/{plan-index-V7T5MKL6.js → plan-index-BNLUU6T5.js} +3 -2
- package/dist/{run-3B26CVIL.js → run-R66G276Q.js} +58 -12
- package/dist/{run-plan-APTBO2OT.js → run-plan-24Z5K4P3.js} +12 -7
- package/dist/{scan-K6TQGV4S.js → scan-UX4HARMJ.js} +1 -1
- package/dist/{setup-global-AT4DD3MG.js → setup-global-M6LKGJHQ.js} +6 -6
- package/dist/{status-MPJHI5RP.js → status-5UKVIKOI.js} +8 -8
- package/dist/{update-P62637ZI.js → update-VQBGEUWS.js} +33 -43
- package/package.json +1 -1
package/dashboard/README.md
CHANGED
|
@@ -31,7 +31,9 @@ A host page can replace the copy-to-clipboard default by defining
|
|
|
31
31
|
every action is one `{ kind: "copy", text, subject, destination, toastMessage }` record. The web
|
|
32
32
|
dashboard keeps the copy-only default. Contract, CSP readiness counts and the innerHTML sink
|
|
33
33
|
audit: `docs/mission-control-embedding.md`. The snapshot shape is versioned by `dashboardDataVersion`
|
|
34
|
-
and published as `docs/contracts/mission-control-snapshot.schema.json`.
|
|
34
|
+
and published as `docs/contracts/mission-control-snapshot.schema.json`. The Flight Log lists pending
|
|
35
|
+
operator tickets (gate exits awaiting triage) read-only from `gateExit`
|
|
36
|
+
(`lib/gate-exit-tickets.mjs`, the no-fetch mirror of `agent-kit ground-control status`).
|
|
35
37
|
|
|
36
38
|
## Git tab and DevOps tab
|
|
37
39
|
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
import { execFileSync } from "node:child_process";
|
|
8
8
|
import { existsSync, mkdirSync, readdirSync, readFileSync, statSync, writeFileSync } from "node:fs";
|
|
9
9
|
import { dirname, join, resolve } from "node:path";
|
|
10
|
+
import { collectGateExitTickets } from "./lib/gate-exit-tickets.mjs";
|
|
10
11
|
import {
|
|
11
12
|
allowlistConfig,
|
|
12
13
|
MAX_STRING,
|
|
@@ -132,7 +133,7 @@ function redactTerminalOutput(text) {
|
|
|
132
133
|
|
|
133
134
|
const SNAPSHOT = {
|
|
134
135
|
_schema: {
|
|
135
|
-
version: "1.
|
|
136
|
+
version: "1.6.0",
|
|
136
137
|
description: "Mission Control dashboard data model",
|
|
137
138
|
fields: {
|
|
138
139
|
generatedAt: "ISO-8601 timestamp of snapshot generation",
|
|
@@ -151,6 +152,8 @@ const SNAPSHOT = {
|
|
|
151
152
|
"Active Cursor terminal sessions with metadata, output line count, and capped lastOutput",
|
|
152
153
|
runLogs:
|
|
153
154
|
"Newest headless agent-kit run / tick logs from <state root>/loop-logs (AGENT_KIT_STATE_ROOT: .cursor by default, or .agent-kit; no ~/.cursor dependency): format, session id, capped last agent text, result, LOOP_TICK_RESULT line, HITL gate ids and reply stamps (1.5.0)",
|
|
155
|
+
gateExit:
|
|
156
|
+
"Pending operator tickets (read-only, never fetches): {marker: absent|ok|invalid, base, tickets[] (stamp, headline, askId, labels, trigger, openedAt, url, branch, branchState unmerged|merged|none, inMarker), skipped[] (latest launcher skip records), truncated} from .cursor/context/gate-exit.json and gate-exit/<stamp> branches; same contract as agent-kit ground-control status (1.6.0)",
|
|
154
157
|
processes:
|
|
155
158
|
"Running process snapshots (node, serve.mjs, git operations) with elapsed time and a generated narration per process",
|
|
156
159
|
skills: "Available skills discovered in .cursor/skills/",
|
|
@@ -159,7 +162,7 @@ const SNAPSHOT = {
|
|
|
159
162
|
},
|
|
160
163
|
},
|
|
161
164
|
generatedAt: new Date().toISOString(),
|
|
162
|
-
dashboardDataVersion: "1.
|
|
165
|
+
dashboardDataVersion: "1.6.0",
|
|
163
166
|
plans: [],
|
|
164
167
|
system: {
|
|
165
168
|
repoRoot: ROOT,
|
|
@@ -171,6 +174,7 @@ const SNAPSHOT = {
|
|
|
171
174
|
git: {},
|
|
172
175
|
terminals: [],
|
|
173
176
|
runLogs: [],
|
|
177
|
+
gateExit: { marker: "absent", base: "staging", tickets: [], skipped: [], truncated: false },
|
|
174
178
|
processes: [],
|
|
175
179
|
skills: [],
|
|
176
180
|
health: { status: "ok", checks: [] },
|
|
@@ -779,6 +783,12 @@ if (withinSnapshotBudget(200)) {
|
|
|
779
783
|
SNAPSHOT.runLogs = collectRunLogs(ROOT, { redact: redactTerminalOutput });
|
|
780
784
|
}
|
|
781
785
|
|
|
786
|
+
// 7c. Pending operator tickets (gate exits): marker + gate-exit/<stamp> branches, read-only and
|
|
787
|
+
// without a fetch (the CLI's `ground-control status` fetches; a refresh must not).
|
|
788
|
+
if (withinSnapshotBudget(200)) {
|
|
789
|
+
SNAPSHOT.gateExit = collectGateExitTickets(ROOT, { redact: redactTerminalOutput });
|
|
790
|
+
}
|
|
791
|
+
|
|
782
792
|
// 8. Config
|
|
783
793
|
const configPath = join(ROOT, ".cursor", "context", "config.json");
|
|
784
794
|
if (existsSync(configPath)) {
|
|
@@ -1372,6 +1382,7 @@ function readPreviousInventory() {
|
|
|
1372
1382
|
flightLogLedger: collectFlightLogLedger(),
|
|
1373
1383
|
cadenceLedger: collectCadenceLedger(),
|
|
1374
1384
|
cadenceConfig: collectCadenceConfig(),
|
|
1385
|
+
gateExitTickets: SNAPSHOT.gateExit?.tickets || [],
|
|
1375
1386
|
});
|
|
1376
1387
|
persistMissionTimingLedger(missionControl.timingLedger);
|
|
1377
1388
|
persistFlightLogLedger(missionControl.flightLogLedger);
|
package/dashboard/dashboard.html
CHANGED
|
@@ -3397,6 +3397,23 @@ html[data-monitor-density="comfortable"] .live-activity-feed .monitor-row .monit
|
|
|
3397
3397
|
gap: 6px;
|
|
3398
3398
|
margin-bottom: 4px;
|
|
3399
3399
|
}
|
|
3400
|
+
/* Pending operator tickets lane (read-only; prompt chrome via flightLogKindClassName). */
|
|
3401
|
+
.flight-log-tickets {
|
|
3402
|
+
display: flex;
|
|
3403
|
+
flex-direction: column;
|
|
3404
|
+
gap: 6px;
|
|
3405
|
+
margin-bottom: 4px;
|
|
3406
|
+
}
|
|
3407
|
+
.flight-log-card-ticket {
|
|
3408
|
+
cursor: default;
|
|
3409
|
+
}
|
|
3410
|
+
.flight-log-card-code {
|
|
3411
|
+
margin-top: 6px;
|
|
3412
|
+
font-family: var(--mc-font-mono);
|
|
3413
|
+
font-size: 11px;
|
|
3414
|
+
color: var(--text-secondary);
|
|
3415
|
+
word-break: break-all;
|
|
3416
|
+
}
|
|
3400
3417
|
.flight-log-card {
|
|
3401
3418
|
display: block;
|
|
3402
3419
|
width: 100%;
|
|
@@ -6499,6 +6516,13 @@ function snapshotPrevData(d) {
|
|
|
6499
6516
|
quietOpenTriages: Array.isArray(d.missionControl.flightLog.quietOpenTriages)
|
|
6500
6517
|
? d.missionControl.flightLog.quietOpenTriages.map((i) => i?.id || i?.sourcePath || '')
|
|
6501
6518
|
: [],
|
|
6519
|
+
tickets: Array.isArray(d.missionControl.flightLog.tickets)
|
|
6520
|
+
? d.missionControl.flightLog.tickets.map((t) => ({
|
|
6521
|
+
stamp: t?.stamp || '',
|
|
6522
|
+
branchState: t?.branchState || '',
|
|
6523
|
+
text: t?.text || '',
|
|
6524
|
+
}))
|
|
6525
|
+
: [],
|
|
6502
6526
|
}
|
|
6503
6527
|
: null,
|
|
6504
6528
|
};
|
|
@@ -7445,6 +7469,52 @@ function renderFlightLogQuietOpenTriageCard(item, idx) {
|
|
|
7445
7469
|
`;
|
|
7446
7470
|
}
|
|
7447
7471
|
|
|
7472
|
+
/**
|
|
7473
|
+
* Pending operator ticket card (gate exit awaiting triage). Read-only: no button,
|
|
7474
|
+
* no handler; prompt chrome from flightLogKindClassName('prompt'). Triage stays in
|
|
7475
|
+
* the CLI (`agent-kit ground-control`) or the `ticket` Ask; the card shows the command.
|
|
7476
|
+
* @param {{ id?: string, stamp?: string, title?: string, text?: string, askId?: string|null, branch?: string|null, branchState?: string, url?: string|null, triage?: string, sourcePath?: string }} ticket
|
|
7477
|
+
* @param {number} idx
|
|
7478
|
+
*/
|
|
7479
|
+
function renderFlightLogTicketCard(ticket, idx) {
|
|
7480
|
+
const stamp = typeof ticket?.stamp === 'string' ? ticket.stamp.trim() : '';
|
|
7481
|
+
const text = typeof ticket?.text === 'string' ? ticket.text.trim() : '';
|
|
7482
|
+
if (!stamp || !text) return '';
|
|
7483
|
+
const title =
|
|
7484
|
+
typeof ticket?.title === 'string' && ticket.title.trim() ? ticket.title.trim() : 'Pending ticket';
|
|
7485
|
+
const state =
|
|
7486
|
+
ticket?.branchState === 'merged'
|
|
7487
|
+
? 'merged, ready to accept'
|
|
7488
|
+
: ticket?.branchState === 'unmerged'
|
|
7489
|
+
? 'awaiting merge'
|
|
7490
|
+
: 'no gate-exit branch';
|
|
7491
|
+
const metaBits = [];
|
|
7492
|
+
if (typeof ticket?.askId === 'string' && ticket.askId) metaBits.push(`Ask ${escapeHtml(ticket.askId)}`);
|
|
7493
|
+
metaBits.push(
|
|
7494
|
+
escapeHtml(typeof ticket?.branch === 'string' && ticket.branch ? `${ticket.branch} (${state})` : state),
|
|
7495
|
+
);
|
|
7496
|
+
if (typeof ticket?.url === 'string' && /^https?:\/\//.test(ticket.url)) metaBits.push(escapeHtml(ticket.url));
|
|
7497
|
+
const triage = typeof ticket?.triage === 'string' && ticket.triage.trim() ? ticket.triage.trim() : '';
|
|
7498
|
+
const aria = `${title} ${stamp}: ${text}`;
|
|
7499
|
+
const kindClass = flightLogKindClassName('prompt');
|
|
7500
|
+
return `
|
|
7501
|
+
<div class="flight-log-card flight-log-card-current flight-log-card-ticket ${kindClass}" role="listitem" tabindex="0" data-focus-key="flight-log-ticket-${idx}" data-flight-log-kind="prompt" data-ticket-stamp="${escapeAttr(stamp)}" aria-label="${escapeAttr(aria)}">
|
|
7502
|
+
<span class="flight-log-card-label">${escapeHtml(title)} · ${escapeHtml(stamp)}</span>
|
|
7503
|
+
<div class="flight-log-card-text">${escapeHtml(text)}</div>
|
|
7504
|
+
<div class="flight-log-card-meta">${metaBits.join(' · ')}</div>
|
|
7505
|
+
${triage ? `<div class="flight-log-card-code">${escapeHtml(triage)}</div>` : ''}
|
|
7506
|
+
</div>
|
|
7507
|
+
`;
|
|
7508
|
+
}
|
|
7509
|
+
|
|
7510
|
+
/** Pending ticket rows on the Flight Log (stamp + text required, as the card renders). */
|
|
7511
|
+
function flightLogTicketEntries(fl) {
|
|
7512
|
+
if (!fl || !Array.isArray(fl.tickets)) return [];
|
|
7513
|
+
return fl.tickets.filter(
|
|
7514
|
+
(t) => t && typeof t.stamp === 'string' && t.stamp.trim() && typeof t.text === 'string' && t.text.trim(),
|
|
7515
|
+
);
|
|
7516
|
+
}
|
|
7517
|
+
|
|
7448
7518
|
/**
|
|
7449
7519
|
* Resolve Live Gaps text for Flight Log render + fingerprint (same fallback chain).
|
|
7450
7520
|
* Prefer fl.current; with Plan:none, fall back to now.gaps then system.handoff.gaps.
|
|
@@ -7537,6 +7607,16 @@ function renderAttentionPanel(d, attentionChanged) {
|
|
|
7537
7607
|
.filter(Boolean)
|
|
7538
7608
|
.join('');
|
|
7539
7609
|
const hasOpenTriages = openTriageCards.length > 0;
|
|
7610
|
+
// Pending operator tickets render above every branch: a ticket never falls through to All clear.
|
|
7611
|
+
const tickets = flightLogTicketEntries(fl);
|
|
7612
|
+
const ticketCards = tickets
|
|
7613
|
+
.map((t, idx) => renderFlightLogTicketCard(t, idx))
|
|
7614
|
+
.filter(Boolean)
|
|
7615
|
+
.join('');
|
|
7616
|
+
const hasTickets = ticketCards.length > 0;
|
|
7617
|
+
const ticketsBlock = hasTickets
|
|
7618
|
+
? `<div class="flight-log-tickets" role="list" aria-label="Pending operator tickets (Ground Control)">${ticketCards}</div>`
|
|
7619
|
+
: '';
|
|
7540
7620
|
|
|
7541
7621
|
let body;
|
|
7542
7622
|
const hasCurrent = Boolean(current);
|
|
@@ -7546,6 +7626,8 @@ function renderAttentionPanel(d, attentionChanged) {
|
|
|
7546
7626
|
if (!hasCurrent && !hasPast && !hasWarnings) {
|
|
7547
7627
|
if (hasOpenTriages) {
|
|
7548
7628
|
body = `<div class="flight-log-stack" role="list" aria-label="Reviews awaiting triage">${openTriageCards}</div>`;
|
|
7629
|
+
} else if (hasTickets) {
|
|
7630
|
+
body = '';
|
|
7549
7631
|
} else {
|
|
7550
7632
|
body = renderEmptyStateCta({
|
|
7551
7633
|
headline: 'All clear',
|
|
@@ -7578,8 +7660,9 @@ function renderAttentionPanel(d, attentionChanged) {
|
|
|
7578
7660
|
</div>`;
|
|
7579
7661
|
body = `${warningsBlock}<div class="flight-log-stack" role="list">${currentCard}${pastCards}</div>`;
|
|
7580
7662
|
}
|
|
7663
|
+
body = `${ticketsBlock}${body}`;
|
|
7581
7664
|
|
|
7582
|
-
const
|
|
7665
|
+
const baseCountLabel = hasCurrent
|
|
7583
7666
|
? hasPast
|
|
7584
7667
|
? `1 · ${past.length} earlier${hasWarnings ? ` · ${warnings.length} warn` : ''}`
|
|
7585
7668
|
: hasWarnings
|
|
@@ -7592,6 +7675,12 @@ function renderAttentionPanel(d, attentionChanged) {
|
|
|
7592
7675
|
: hasOpenTriages
|
|
7593
7676
|
? `${quietOpenTriages.length} review`
|
|
7594
7677
|
: 'Clear';
|
|
7678
|
+
const ticketCountLabel = hasTickets ? `${tickets.length} ticket${tickets.length === 1 ? '' : 's'}` : '';
|
|
7679
|
+
const countLabel = !ticketCountLabel
|
|
7680
|
+
? baseCountLabel
|
|
7681
|
+
: baseCountLabel === 'Clear'
|
|
7682
|
+
? ticketCountLabel
|
|
7683
|
+
: `${ticketCountLabel} · ${baseCountLabel}`;
|
|
7595
7684
|
|
|
7596
7685
|
return `
|
|
7597
7686
|
<div class="card${attentionChanged ? ' card-flash' : ''}" id="attention-panel">
|
|
@@ -7695,9 +7784,13 @@ function flightLogFingerprint(d) {
|
|
|
7695
7784
|
)
|
|
7696
7785
|
.join('\n')
|
|
7697
7786
|
: '';
|
|
7787
|
+
// Pending tickets: stamp + merge state + headline, so a merge or a new note re-renders.
|
|
7788
|
+
const tickets = flightLogTicketEntries(fl)
|
|
7789
|
+
.map((t) => `${t.stamp}|${t.branchState || ''}|${t.text}`)
|
|
7790
|
+
.join('\n');
|
|
7698
7791
|
// Busy-outside-plan header chip must re-render the card on flip.
|
|
7699
7792
|
const busy = (d.missionControl?.now ?? d.now)?.busyOutsidePlan?.active === true;
|
|
7700
|
-
return `${current}\0${past}\0${warnings}\0${openTriages}\0${busy ? 'busy' : ''}`;
|
|
7793
|
+
return `${current}\0${past}\0${warnings}\0${openTriages}\0${tickets}\0${busy ? 'busy' : ''}`;
|
|
7701
7794
|
}
|
|
7702
7795
|
|
|
7703
7796
|
// Step progress bar: one segment per plan step (completed / current / remaining).
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/** Ambient types for dashboard/lib/gate-exit-tickets.mjs (consumed by CLI TypeScript). */
|
|
2
|
+
|
|
3
|
+
export const GATE_EXIT_BRANCH_PREFIX: "gate-exit/";
|
|
4
|
+
export const GATE_EXIT_MARKER_RELPATH: ".cursor/context/gate-exit.json";
|
|
5
|
+
export const GATE_EXIT_NOTE_DIR: ".cursor/gate-exit";
|
|
6
|
+
export const GATE_EXIT_DEFAULT_BASE: "staging";
|
|
7
|
+
export const GATE_EXIT_STAMP_RE: RegExp;
|
|
8
|
+
export const MAX_GATE_EXIT_TICKETS: 10;
|
|
9
|
+
export const MAX_GATE_EXIT_SKIPPED: 5;
|
|
10
|
+
export const MAX_GATE_EXIT_TEXT: 300;
|
|
11
|
+
|
|
12
|
+
export type GitRunner = (args: string[]) => { code: number; stdout: string };
|
|
13
|
+
|
|
14
|
+
export interface GateExitTicketRow {
|
|
15
|
+
stamp: string;
|
|
16
|
+
headline: string | null;
|
|
17
|
+
askId: string | null;
|
|
18
|
+
labels: string[];
|
|
19
|
+
trigger: "gate" | "stopped-by-operator" | "failure" | null;
|
|
20
|
+
openedAt: string | null;
|
|
21
|
+
url: string | null;
|
|
22
|
+
branch: string | null;
|
|
23
|
+
branchState: "unmerged" | "merged" | "none";
|
|
24
|
+
inMarker: boolean;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface GateExitTickets {
|
|
28
|
+
marker: "absent" | "ok" | "invalid";
|
|
29
|
+
base: string;
|
|
30
|
+
tickets: GateExitTicketRow[];
|
|
31
|
+
skipped: string[];
|
|
32
|
+
truncated: boolean;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function makeGitRunner(root: string, timeoutMs?: number): GitRunner;
|
|
36
|
+
export function readGateExitMarkerSync(
|
|
37
|
+
root: string,
|
|
38
|
+
):
|
|
39
|
+
| { kind: "absent" }
|
|
40
|
+
| { kind: "invalid" }
|
|
41
|
+
| { kind: "ok"; pending: Record<string, unknown>[]; skipped: string[] };
|
|
42
|
+
export function collectGateExitTickets(
|
|
43
|
+
root: string,
|
|
44
|
+
opts?: { git?: GitRunner; redact?: (s: string) => string; max?: number },
|
|
45
|
+
): GateExitTickets;
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pending operator tickets for Mission Control (ADR 2026-10-08
|
|
3
|
+
* countdown-coming-home-generic-lane point 3: "Mission Control shows pending
|
|
4
|
+
* tickets read-only in the Flight Log").
|
|
5
|
+
*
|
|
6
|
+
* Mirrors the read half of `groundControlStatus`
|
|
7
|
+
* (packages/cli/src/commands/ground-control.ts) on the same contract: the
|
|
8
|
+
* gitignored marker `.cursor/context/gate-exit.json`, `gate-exit/<UTC stamp>`
|
|
9
|
+
* branches, the note at `.cursor/gate-exit/<stamp>.md` (first line = ticket
|
|
10
|
+
* headline), and the same merged test (branch tip is an ancestor of the base,
|
|
11
|
+
* or the base holds the note blob byte for byte). A parity test pins this file
|
|
12
|
+
* to the CLI (packages/cli/src/dashboard/gate-exit-tickets.test.ts).
|
|
13
|
+
*
|
|
14
|
+
* Unlike `agent-kit ground-control status` this never fetches: the dashboard
|
|
15
|
+
* re-snapshots on every refresh, so it shows the last fetched state. It never
|
|
16
|
+
* writes, never throws, and costs one `git for-each-ref` when there is no
|
|
17
|
+
* marker and no gate-exit branch.
|
|
18
|
+
*/
|
|
19
|
+
import { execFileSync } from "node:child_process";
|
|
20
|
+
import { readFileSync } from "node:fs";
|
|
21
|
+
import { join } from "node:path";
|
|
22
|
+
|
|
23
|
+
export const GATE_EXIT_BRANCH_PREFIX = "gate-exit/";
|
|
24
|
+
export const GATE_EXIT_MARKER_RELPATH = ".cursor/context/gate-exit.json";
|
|
25
|
+
export const GATE_EXIT_NOTE_DIR = ".cursor/gate-exit";
|
|
26
|
+
export const GATE_EXIT_DEFAULT_BASE = "staging";
|
|
27
|
+
export const GATE_EXIT_STAMP_RE = /^\d{8}T\d{6}Z$/;
|
|
28
|
+
export const MAX_GATE_EXIT_TICKETS = 10;
|
|
29
|
+
export const MAX_GATE_EXIT_SKIPPED = 5;
|
|
30
|
+
export const MAX_GATE_EXIT_TEXT = 300;
|
|
31
|
+
|
|
32
|
+
const SAFE_REF_RE = /^[A-Za-z0-9][A-Za-z0-9._/-]*$/;
|
|
33
|
+
const TRIGGERS = new Set(["gate", "stopped-by-operator", "failure", "review"]);
|
|
34
|
+
|
|
35
|
+
const isRecord = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
36
|
+
|
|
37
|
+
function cap(text, max = MAX_GATE_EXIT_TEXT) {
|
|
38
|
+
const s = String(text ?? "").trim();
|
|
39
|
+
return s.length > max ? `${s.slice(0, max - 1)}…` : s;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function isSafeBaseRef(ref) {
|
|
43
|
+
return (
|
|
44
|
+
typeof ref === "string" &&
|
|
45
|
+
SAFE_REF_RE.test(ref) &&
|
|
46
|
+
!ref.includes("..") &&
|
|
47
|
+
!ref.endsWith("/") &&
|
|
48
|
+
!ref.endsWith(".lock")
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** Synchronous git runner: `{ code, stdout }`, never throws. */
|
|
53
|
+
export function makeGitRunner(root, timeoutMs = 5000) {
|
|
54
|
+
return (args) => {
|
|
55
|
+
try {
|
|
56
|
+
const stdout = execFileSync("git", args, {
|
|
57
|
+
cwd: root,
|
|
58
|
+
encoding: "utf-8",
|
|
59
|
+
timeout: timeoutMs,
|
|
60
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
61
|
+
});
|
|
62
|
+
return { code: 0, stdout };
|
|
63
|
+
} catch (err) {
|
|
64
|
+
const status = isRecord(err) && typeof err.status === "number" ? err.status : 1;
|
|
65
|
+
return { code: status || 1, stdout: "" };
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** Marker read with the CLI's validation (`readGateExitMarker`). */
|
|
71
|
+
export function readGateExitMarkerSync(root) {
|
|
72
|
+
let raw;
|
|
73
|
+
try {
|
|
74
|
+
raw = readFileSync(join(root, GATE_EXIT_MARKER_RELPATH), "utf8");
|
|
75
|
+
} catch (err) {
|
|
76
|
+
if (isRecord(err) && err.code === "ENOENT") return { kind: "absent" };
|
|
77
|
+
return { kind: "invalid" };
|
|
78
|
+
}
|
|
79
|
+
try {
|
|
80
|
+
const parsed = JSON.parse(raw);
|
|
81
|
+
if (!isRecord(parsed) || parsed.schema !== 1) return { kind: "invalid" };
|
|
82
|
+
if (!Array.isArray(parsed.pending) || !Array.isArray(parsed.skipped)) {
|
|
83
|
+
return { kind: "invalid" };
|
|
84
|
+
}
|
|
85
|
+
const pending = parsed.pending.filter(
|
|
86
|
+
(e) => isRecord(e) && typeof e.stamp === "string" && GATE_EXIT_STAMP_RE.test(e.stamp),
|
|
87
|
+
);
|
|
88
|
+
return { kind: "ok", pending, skipped: parsed.skipped.map(String) };
|
|
89
|
+
} catch {
|
|
90
|
+
return { kind: "invalid" };
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/** Base ref chain of `resolveGateExitRefs`: origin/<base>, origin/HEAD, local <base>, HEAD. */
|
|
95
|
+
function resolveBaseRef(git, hasOrigin, requested) {
|
|
96
|
+
let base = isSafeBaseRef(requested) ? requested : GATE_EXIT_DEFAULT_BASE;
|
|
97
|
+
const verify = (ref) => git(["rev-parse", "--verify", "--quiet", `${ref}^{commit}`]).code === 0;
|
|
98
|
+
if (hasOrigin) {
|
|
99
|
+
if (verify(`refs/remotes/origin/${base}`))
|
|
100
|
+
return { base, baseRef: `refs/remotes/origin/${base}` };
|
|
101
|
+
const head = git(["symbolic-ref", "--quiet", "--short", "refs/remotes/origin/HEAD"]);
|
|
102
|
+
const fallback = head.stdout.trim().replace(/^origin\//, "");
|
|
103
|
+
if (head.code === 0 && isSafeBaseRef(fallback)) {
|
|
104
|
+
base = fallback;
|
|
105
|
+
return { base, baseRef: `refs/remotes/origin/${fallback}` };
|
|
106
|
+
}
|
|
107
|
+
return { base, baseRef: "HEAD" };
|
|
108
|
+
}
|
|
109
|
+
if (verify(`refs/heads/${base}`)) return { base, baseRef: `refs/heads/${base}` };
|
|
110
|
+
return { base, baseRef: "HEAD" };
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function blobId(git, spec) {
|
|
114
|
+
const r = git(["rev-parse", "--verify", "--quiet", spec]);
|
|
115
|
+
const id = r.stdout.trim();
|
|
116
|
+
return r.code === 0 && id ? id : null;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function notePath(stamp) {
|
|
120
|
+
return `${GATE_EXIT_NOTE_DIR}/${stamp}.md`;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function isMerged(git, branchRef, baseRef, stamp) {
|
|
124
|
+
if (git(["merge-base", "--is-ancestor", branchRef, baseRef]).code === 0) return true;
|
|
125
|
+
const onBranch = blobId(git, `${branchRef}:${notePath(stamp)}`);
|
|
126
|
+
return onBranch !== null && onBranch === blobId(git, `${baseRef}:${notePath(stamp)}`);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function readHeadline(git, ref, stamp) {
|
|
130
|
+
const shown = git(["show", `${ref}:${notePath(stamp)}`]);
|
|
131
|
+
if (shown.code !== 0) return null;
|
|
132
|
+
const first = shown.stdout.split("\n")[0]?.trim() ?? "";
|
|
133
|
+
return first || null;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function stampOfBranch(short) {
|
|
137
|
+
const i = short.lastIndexOf(GATE_EXIT_BRANCH_PREFIX);
|
|
138
|
+
if (i < 0) return null;
|
|
139
|
+
const stamp = short.slice(i + GATE_EXIT_BRANCH_PREFIX.length);
|
|
140
|
+
return GATE_EXIT_STAMP_RE.test(stamp) ? stamp : null;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function shortRef(ref) {
|
|
144
|
+
return ref.replace(/^refs\/remotes\//, "").replace(/^refs\/heads\//, "");
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function emptyResult(marker, base = GATE_EXIT_DEFAULT_BASE) {
|
|
148
|
+
return { marker, base, tickets: [], skipped: [], truncated: false };
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Pending operator tickets: marker entries plus unmerged gate-exit branches
|
|
153
|
+
* (remote-tracking and local) with no entry. A merged branch with no entry is
|
|
154
|
+
* history and is hidden, as in `ground-control status`.
|
|
155
|
+
* @param {string} root
|
|
156
|
+
* @param {{ git?: (args: string[]) => { code: number, stdout: string }, redact?: (s: string) => string, max?: number }} [opts]
|
|
157
|
+
*/
|
|
158
|
+
export function collectGateExitTickets(root, opts = {}) {
|
|
159
|
+
const redact = typeof opts.redact === "function" ? opts.redact : (s) => s;
|
|
160
|
+
const max = Number.isInteger(opts.max) && opts.max > 0 ? opts.max : MAX_GATE_EXIT_TICKETS;
|
|
161
|
+
const git = opts.git ?? makeGitRunner(root);
|
|
162
|
+
const marker = readGateExitMarkerSync(root);
|
|
163
|
+
const entries = marker.kind === "ok" ? marker.pending : [];
|
|
164
|
+
const skipped =
|
|
165
|
+
marker.kind === "ok" ? marker.skipped.slice(-MAX_GATE_EXIT_SKIPPED).map((s) => cap(s, 80)) : [];
|
|
166
|
+
|
|
167
|
+
const listed = git([
|
|
168
|
+
"for-each-ref",
|
|
169
|
+
"--format=%(refname)",
|
|
170
|
+
`refs/remotes/origin/${GATE_EXIT_BRANCH_PREFIX}`,
|
|
171
|
+
`refs/heads/${GATE_EXIT_BRANCH_PREFIX}`,
|
|
172
|
+
]);
|
|
173
|
+
const branchRefs = listed.code === 0 ? listed.stdout.split("\n").filter((l) => l.trim()) : [];
|
|
174
|
+
if (entries.length === 0 && branchRefs.length === 0) {
|
|
175
|
+
return { ...emptyResult(marker.kind), skipped };
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const hasOrigin = git(["remote", "get-url", "origin"]).code === 0;
|
|
179
|
+
const defaultRefs = resolveBaseRef(git, hasOrigin, GATE_EXIT_DEFAULT_BASE);
|
|
180
|
+
// Same scopes as the CLI: with an origin, remote-tracking + local heads; without, local heads.
|
|
181
|
+
const remoteScope = `refs/remotes/origin/${GATE_EXIT_BRANCH_PREFIX}`;
|
|
182
|
+
const present = new Set(branchRefs);
|
|
183
|
+
const stamps = new Set(entries.map((e) => e.stamp));
|
|
184
|
+
for (const ref of branchRefs) {
|
|
185
|
+
if (!hasOrigin && ref.startsWith(remoteScope)) continue;
|
|
186
|
+
const stamp = stampOfBranch(shortRef(ref));
|
|
187
|
+
if (stamp) stamps.add(stamp);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
const tickets = [];
|
|
191
|
+
const ordered = [...stamps].sort();
|
|
192
|
+
for (const stamp of ordered) {
|
|
193
|
+
const entry = entries.find((e) => e.stamp === stamp);
|
|
194
|
+
const remote = `refs/remotes/origin/${GATE_EXIT_BRANCH_PREFIX}${stamp}`;
|
|
195
|
+
const local = `refs/heads/${GATE_EXIT_BRANCH_PREFIX}${stamp}`;
|
|
196
|
+
const branchRef = hasOrigin && present.has(remote) ? remote : present.has(local) ? local : null;
|
|
197
|
+
const refs =
|
|
198
|
+
entry && isSafeBaseRef(entry.base) && entry.base !== defaultRefs.base
|
|
199
|
+
? resolveBaseRef(git, hasOrigin, entry.base)
|
|
200
|
+
: defaultRefs;
|
|
201
|
+
let branchState = "none";
|
|
202
|
+
if (branchRef) {
|
|
203
|
+
branchState = isMerged(git, branchRef, refs.baseRef, stamp) ? "merged" : "unmerged";
|
|
204
|
+
}
|
|
205
|
+
if (!entry && branchState === "merged") continue;
|
|
206
|
+
const headline =
|
|
207
|
+
(branchRef ? readHeadline(git, branchRef, stamp) : null) ??
|
|
208
|
+
readHeadline(git, refs.baseRef, stamp);
|
|
209
|
+
const url = typeof entry?.url === "string" && /^https?:\/\//.test(entry.url) ? entry.url : null;
|
|
210
|
+
tickets.push({
|
|
211
|
+
stamp,
|
|
212
|
+
headline: headline ? cap(redact(headline)) : null,
|
|
213
|
+
askId: typeof entry?.askId === "string" ? cap(entry.askId, 64) : null,
|
|
214
|
+
labels: Array.isArray(entry?.labels)
|
|
215
|
+
? entry.labels.slice(0, 8).map((l) => cap(redact(String(l)), 80))
|
|
216
|
+
: [],
|
|
217
|
+
trigger: TRIGGERS.has(entry?.trigger) ? entry.trigger : null,
|
|
218
|
+
openedAt: typeof entry?.openedAt === "string" ? cap(entry.openedAt, 40) : null,
|
|
219
|
+
url: url ? cap(redact(url), 300) : null,
|
|
220
|
+
branch: branchRef ? shortRef(branchRef) : null,
|
|
221
|
+
branchState,
|
|
222
|
+
inMarker: Boolean(entry),
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
return {
|
|
227
|
+
marker: marker.kind,
|
|
228
|
+
base: defaultRefs.base,
|
|
229
|
+
tickets: tickets.slice(0, max),
|
|
230
|
+
skipped,
|
|
231
|
+
truncated: tickets.length > max,
|
|
232
|
+
};
|
|
233
|
+
}
|
|
@@ -32,3 +32,24 @@ export type HandoffMarkdown = {
|
|
|
32
32
|
};
|
|
33
33
|
|
|
34
34
|
export function parseHandoffMarkdown(content: string): HandoffMarkdown | null;
|
|
35
|
+
|
|
36
|
+
/** Flight Log pending operator tickets lane (read-only rows). */
|
|
37
|
+
export type FlightLogTicket = {
|
|
38
|
+
id: string;
|
|
39
|
+
stamp: string;
|
|
40
|
+
title: string;
|
|
41
|
+
text: string;
|
|
42
|
+
askId: string | null;
|
|
43
|
+
branch: string | null;
|
|
44
|
+
branchState: "unmerged" | "merged" | "none";
|
|
45
|
+
url: string | null;
|
|
46
|
+
triage: string;
|
|
47
|
+
sourcePath: string;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export const FLIGHT_LOG_TICKETS_CAP: 5;
|
|
51
|
+
|
|
52
|
+
export function buildFlightLogTickets(
|
|
53
|
+
tickets: Record<string, unknown>[] | null | undefined,
|
|
54
|
+
opts?: { cap?: number },
|
|
55
|
+
): FlightLogTicket[];
|
|
@@ -643,6 +643,51 @@ export function listFlightLogQuietOpenTriages(reportOrAttentionItems, opts = {})
|
|
|
643
643
|
return out;
|
|
644
644
|
}
|
|
645
645
|
|
|
646
|
+
/** Cap pending operator tickets on the Flight Log tickets lane. */
|
|
647
|
+
export const FLIGHT_LOG_TICKETS_CAP = 5;
|
|
648
|
+
|
|
649
|
+
/**
|
|
650
|
+
* Pending operator tickets for the Flight Log (read-only; prompt chrome).
|
|
651
|
+
* Input rows come from `collectGateExitTickets` (dashboard/lib/gate-exit-tickets.mjs,
|
|
652
|
+
* the read half of `agent-kit ground-control status`). No action: triage stays
|
|
653
|
+
* in the CLI (`ground-control accept|discard <stamp>`) or the `ticket` Ask.
|
|
654
|
+
* @param {object[]|null|undefined} tickets
|
|
655
|
+
* @param {{ cap?: number }} [opts]
|
|
656
|
+
* @returns {{ id: string, stamp: string, title: string, text: string, askId: string|null, branch: string|null, branchState: string, url: string|null, triage: string, sourcePath: string }[]}
|
|
657
|
+
*/
|
|
658
|
+
export function buildFlightLogTickets(tickets, opts = {}) {
|
|
659
|
+
const cap =
|
|
660
|
+
typeof opts.cap === "number" && opts.cap > 0 ? Math.floor(opts.cap) : FLIGHT_LOG_TICKETS_CAP;
|
|
661
|
+
if (!Array.isArray(tickets)) return [];
|
|
662
|
+
const out = [];
|
|
663
|
+
for (const t of tickets) {
|
|
664
|
+
if (!t || typeof t.stamp !== "string" || !/^\d{8}T\d{6}Z$/.test(t.stamp)) continue;
|
|
665
|
+
const headline =
|
|
666
|
+
typeof t.headline === "string" && t.headline.trim()
|
|
667
|
+
? t.headline.replace(/^#\s*/, "").trim()
|
|
668
|
+
: `Gate exit ${t.stamp} (note not readable)`;
|
|
669
|
+
const branchState =
|
|
670
|
+
t.branchState === "merged" || t.branchState === "unmerged" ? t.branchState : "none";
|
|
671
|
+
out.push({
|
|
672
|
+
id: `flight-log-ticket:${t.stamp}`,
|
|
673
|
+
stamp: t.stamp,
|
|
674
|
+
title: "Pending ticket",
|
|
675
|
+
text: truncateStr(headline, MAX_SEMANTIC_LABEL),
|
|
676
|
+
askId: typeof t.askId === "string" && t.askId ? t.askId : null,
|
|
677
|
+
branch: typeof t.branch === "string" && t.branch ? t.branch : null,
|
|
678
|
+
branchState,
|
|
679
|
+
url: typeof t.url === "string" && /^https?:\/\//.test(t.url) ? t.url : null,
|
|
680
|
+
triage:
|
|
681
|
+
branchState === "merged"
|
|
682
|
+
? `agent-kit ground-control accept ${t.stamp}`
|
|
683
|
+
: `agent-kit ground-control accept|discard ${t.stamp}`,
|
|
684
|
+
sourcePath: t.inMarker ? ".cursor/context/gate-exit.json" : t.branch || "gate-exit/",
|
|
685
|
+
});
|
|
686
|
+
if (out.length >= cap) break;
|
|
687
|
+
}
|
|
688
|
+
return out;
|
|
689
|
+
}
|
|
690
|
+
|
|
646
691
|
/** Relative path of the gitignored Field Report activity cadence ledger. */
|
|
647
692
|
export const FIELD_REPORT_CADENCE_LEDGER_REL = ".cursor/context/field-report-cadence.json";
|
|
648
693
|
|
|
@@ -3790,6 +3835,7 @@ export function buildMissionControlView({
|
|
|
3790
3835
|
flightLogLedger = null,
|
|
3791
3836
|
cadenceLedger = null,
|
|
3792
3837
|
cadenceConfig = null,
|
|
3838
|
+
gateExitTickets = [],
|
|
3793
3839
|
nowMs = Date.now(),
|
|
3794
3840
|
} = {}) {
|
|
3795
3841
|
const nowBase = buildCurrentExecution(plans, handoff);
|
|
@@ -3814,6 +3860,7 @@ export function buildMissionControlView({
|
|
|
3814
3860
|
},
|
|
3815
3861
|
);
|
|
3816
3862
|
flightLog.warnings = buildFlightLogWarnings(handoff);
|
|
3863
|
+
flightLog.tickets = buildFlightLogTickets(gateExitTickets);
|
|
3817
3864
|
const classifiedPlans = enrichPlans(plans, handoff);
|
|
3818
3865
|
const planEvents = formatPlanHandoffActivity({ now, handoff, plans });
|
|
3819
3866
|
const inventoryEvents = formatInventoryActivity(
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
import {
|
|
6
6
|
REGISTRY_CLI_ARGS,
|
|
7
7
|
resolveRegistryFromCli
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-U26MRIWN.js";
|
|
9
9
|
import {
|
|
10
10
|
logger
|
|
11
11
|
} from "./chunk-ZB43YMHW.js";
|
|
@@ -22,11 +22,11 @@ import {
|
|
|
22
22
|
resolveProtectedGlobs,
|
|
23
23
|
saveManifest,
|
|
24
24
|
upsertIdList
|
|
25
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-6KUSG7BJ.js";
|
|
26
26
|
import {
|
|
27
27
|
KIT_VERSION
|
|
28
28
|
} from "./chunk-7HDQEK6T.js";
|
|
29
|
-
import "./chunk-
|
|
29
|
+
import "./chunk-C4Q77GGJ.js";
|
|
30
30
|
import "./chunk-5B4DVO6C.js";
|
|
31
31
|
|
|
32
32
|
// src/commands/add.ts
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
loadRegistry,
|
|
5
5
|
packMemberFileTargets,
|
|
6
6
|
skillFileTargets
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-6KUSG7BJ.js";
|
|
8
8
|
|
|
9
9
|
// src/lifecycle/l0.ts
|
|
10
10
|
var L0_ARTIFACTS = [
|
|
@@ -59,6 +59,10 @@ var L0_ARTIFACTS = [
|
|
|
59
59
|
source: ".cursor/skills/core/hitl-gates/run-plan-all-queue.md",
|
|
60
60
|
target: ".cursor/skills/core/hitl-gates/run-plan-all-queue.md"
|
|
61
61
|
},
|
|
62
|
+
{
|
|
63
|
+
source: ".cursor/skills/core/hitl-gates/pending-ticket.md",
|
|
64
|
+
target: ".cursor/skills/core/hitl-gates/pending-ticket.md"
|
|
65
|
+
},
|
|
62
66
|
{
|
|
63
67
|
source: ".cursor/skills/core/qa/SKILL.md",
|
|
64
68
|
target: ".cursor/skills/core/qa/SKILL.md"
|
|
@@ -178,6 +182,10 @@ var L0_ARTIFACTS = [
|
|
|
178
182
|
source: ".cursor/commands/dogfood.md",
|
|
179
183
|
target: ".cursor/commands/dogfood.md"
|
|
180
184
|
},
|
|
185
|
+
{
|
|
186
|
+
source: ".cursor/commands/review-pack.md",
|
|
187
|
+
target: ".cursor/commands/review-pack.md"
|
|
188
|
+
},
|
|
181
189
|
// Factory-only: `.cursor/commands/public-issue-triage.md` and
|
|
182
190
|
// `.cursor/commands/public-inbound-radar.md` are intentionally omitted from
|
|
183
191
|
// L0 (and excluded from public-sync). See ADRs
|
|
@@ -6,13 +6,13 @@ import {
|
|
|
6
6
|
import {
|
|
7
7
|
diffAgainstRegistry,
|
|
8
8
|
summarizeDiff
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-VQBI3JVS.js";
|
|
10
10
|
import {
|
|
11
11
|
DEFAULT_REGISTRY_URL,
|
|
12
12
|
assertSafeRegistrySource,
|
|
13
13
|
loadAgentKitManifest,
|
|
14
14
|
resolveRegistryRoot
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-6KUSG7BJ.js";
|
|
16
16
|
import {
|
|
17
17
|
KIT_PACKAGE_SPEC,
|
|
18
18
|
KIT_VERSION
|