@mrciphersmith/keryx 0.2.50 → 0.2.52
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/cli.js +463 -36
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -17055,7 +17055,7 @@ function renderWrapUpMemoryEntry(input2) {
|
|
|
17055
17055
|
|
|
17056
17056
|
Version: 0.1.0
|
|
17057
17057
|
Type: task-note
|
|
17058
|
-
Status:
|
|
17058
|
+
Status: accepted
|
|
17059
17059
|
Confidence: medium
|
|
17060
17060
|
|
|
17061
17061
|
## Summary
|
|
@@ -17155,7 +17155,7 @@ function renderWrapUpDecisionPage(input2) {
|
|
|
17155
17155
|
|
|
17156
17156
|
Version: 0.1.0
|
|
17157
17157
|
Type: decision
|
|
17158
|
-
Status:
|
|
17158
|
+
Status: accepted
|
|
17159
17159
|
|
|
17160
17160
|
## Summary
|
|
17161
17161
|
|
|
@@ -33709,6 +33709,21 @@ function renderMcpClientSnippet(projectRoot) {
|
|
|
33709
33709
|
return `${JSON.stringify({ mcpServers: { [MCP_SERVER_NAME]: mcpServerEntry(projectRoot) } }, null, 2)}
|
|
33710
33710
|
`;
|
|
33711
33711
|
}
|
|
33712
|
+
async function mcpClientStatus(projectRoot, ids = mcpRuntimeIds()) {
|
|
33713
|
+
const absoluteProjectRoot = path40.resolve(projectRoot);
|
|
33714
|
+
const { runtimes } = resolveMcpRuntimes(ids);
|
|
33715
|
+
const statuses = [];
|
|
33716
|
+
for (const runtime of runtimes) {
|
|
33717
|
+
const file = runtime.settingsPath(absoluteProjectRoot);
|
|
33718
|
+
if (file === null) {
|
|
33719
|
+
statuses.push({ id: runtime.id, filePath: null, connected: false });
|
|
33720
|
+
continue;
|
|
33721
|
+
}
|
|
33722
|
+
const settings = await readSettings2(file);
|
|
33723
|
+
statuses.push({ id: runtime.id, filePath: file, connected: runtime.hasManaged(settings) });
|
|
33724
|
+
}
|
|
33725
|
+
return statuses;
|
|
33726
|
+
}
|
|
33712
33727
|
async function readSettings2(file) {
|
|
33713
33728
|
if (!await pathExists(file)) {
|
|
33714
33729
|
return {};
|
|
@@ -33752,7 +33767,7 @@ function buildMcpModuleEntry() {
|
|
|
33752
33767
|
expose: {
|
|
33753
33768
|
tools: true,
|
|
33754
33769
|
resources: true,
|
|
33755
|
-
modules: ["gdgraph", "gdctx", "security", "flow", "memory", "health", "testing", "wiki", "standard", "sac"]
|
|
33770
|
+
modules: ["gdgraph", "gdctx", "security", "flow", "memory", "health", "testing", "wiki", "standard", "sac", "gdskills"]
|
|
33756
33771
|
}
|
|
33757
33772
|
};
|
|
33758
33773
|
}
|
|
@@ -47120,6 +47135,8 @@ init_workspace_service();
|
|
|
47120
47135
|
var HARNESS_PROVIDER_OPTIONS = [
|
|
47121
47136
|
"fake",
|
|
47122
47137
|
"anthropic",
|
|
47138
|
+
"openai",
|
|
47139
|
+
"gemini",
|
|
47123
47140
|
"ollama",
|
|
47124
47141
|
...OPENAI_COMPAT_PROVIDERS.map((provider) => provider.name)
|
|
47125
47142
|
];
|
|
@@ -47285,6 +47302,20 @@ async function harnessCommand(args2, deps) {
|
|
|
47285
47302
|
return;
|
|
47286
47303
|
}
|
|
47287
47304
|
}
|
|
47305
|
+
if (provider === "openai") {
|
|
47306
|
+
const apiKey = env.OPENAI_API_KEY;
|
|
47307
|
+
if (apiKey === undefined || apiKey.length === 0) {
|
|
47308
|
+
console.log("OPENAI_API_KEY is not set: the openai provider is required to have a credential and fails closed (no network was contacted).");
|
|
47309
|
+
return;
|
|
47310
|
+
}
|
|
47311
|
+
}
|
|
47312
|
+
if (provider === "gemini") {
|
|
47313
|
+
const apiKey = env.GEMINI_API_KEY !== undefined && env.GEMINI_API_KEY.length > 0 ? env.GEMINI_API_KEY : env.GOOGLE_API_KEY;
|
|
47314
|
+
if (apiKey === undefined || apiKey.length === 0) {
|
|
47315
|
+
console.log("GEMINI_API_KEY (or GOOGLE_API_KEY) is not set: the gemini provider is required to have a credential and fails closed (no network was contacted).");
|
|
47316
|
+
return;
|
|
47317
|
+
}
|
|
47318
|
+
}
|
|
47288
47319
|
const providerPort = makeProvider(provider, model, {
|
|
47289
47320
|
fetch: fetchImpl,
|
|
47290
47321
|
env,
|
|
@@ -52920,7 +52951,7 @@ import { spawnSync as spawnSync2 } from "child_process";
|
|
|
52920
52951
|
// package.json
|
|
52921
52952
|
var package_default = {
|
|
52922
52953
|
name: "@mrciphersmith/keryx",
|
|
52923
|
-
version: "0.2.
|
|
52954
|
+
version: "0.2.52",
|
|
52924
52955
|
description: "Version-controlled project context for AI coding agents: code graph, architecture wiki, project memory, relevant tests, quality signals, and task flows.",
|
|
52925
52956
|
private: false,
|
|
52926
52957
|
publishConfig: {
|
|
@@ -53808,16 +53839,15 @@ var MODAL_PANEL_MARGIN = 1;
|
|
|
53808
53839
|
var MODAL_PANEL_CHROME_X = 4;
|
|
53809
53840
|
var MODAL_PANEL_MIN_WIDTH = 72;
|
|
53810
53841
|
var MODAL_PANEL_MIN_HEIGHT = 18;
|
|
53811
|
-
var
|
|
53812
|
-
var MODAL_PANEL_TARGET_HEIGHT = 28;
|
|
53842
|
+
var MODAL_PANEL_SIZE_RATIO = 0.95;
|
|
53813
53843
|
var MODAL_CHROME_ROWS = 5;
|
|
53814
53844
|
var MODAL_PANEL_WIDTH = MODAL_PANEL_MIN_WIDTH;
|
|
53815
53845
|
var MODAL_PANEL_HEIGHT = MODAL_PANEL_MIN_HEIGHT;
|
|
53816
53846
|
var MODAL_PANEL_INNER_WIDTH = MODAL_PANEL_MIN_WIDTH - MODAL_PANEL_CHROME_X;
|
|
53817
53847
|
function resolveModalPanelSize(cols, rows) {
|
|
53818
53848
|
return {
|
|
53819
|
-
width: Math.
|
|
53820
|
-
height: Math.
|
|
53849
|
+
width: Math.max(MODAL_PANEL_MIN_WIDTH, Math.round(cols * MODAL_PANEL_SIZE_RATIO)),
|
|
53850
|
+
height: Math.max(MODAL_PANEL_MIN_HEIGHT, Math.round(rows * MODAL_PANEL_SIZE_RATIO))
|
|
53821
53851
|
};
|
|
53822
53852
|
}
|
|
53823
53853
|
function modalBodyRows(panelHeight) {
|
|
@@ -54231,6 +54261,7 @@ async function computeLifecycleFlags(cwd, now = () => new Date) {
|
|
|
54231
54261
|
}
|
|
54232
54262
|
|
|
54233
54263
|
// src/sac/catch-up.ts
|
|
54264
|
+
init_proposal_evidence();
|
|
54234
54265
|
async function buildCatchUp(input2) {
|
|
54235
54266
|
const [proposals, sessionCategories, lifecycleFlagsAll] = await Promise.all([
|
|
54236
54267
|
collectProposals(input2.cwd, input2.workspaceId),
|
|
@@ -54250,8 +54281,20 @@ async function collectProposals(cwd, workspaceId) {
|
|
|
54250
54281
|
const scoped = workspaceId === undefined ? groups : groups.filter((group) => group.workspace.id === workspaceId);
|
|
54251
54282
|
const flattened = scoped.flatMap((group) => group.proposals.map((proposal) => ({ group, proposal })));
|
|
54252
54283
|
return Promise.all(flattened.map(async ({ group, proposal }) => {
|
|
54253
|
-
const fresh = await
|
|
54254
|
-
|
|
54284
|
+
const [fresh, note2] = await Promise.all([
|
|
54285
|
+
proposalService.isEvidenceFresh(proposal, actor),
|
|
54286
|
+
readSidecarNote(cwd, group.workspace.id, proposal.id)
|
|
54287
|
+
]);
|
|
54288
|
+
return {
|
|
54289
|
+
type: "proposal",
|
|
54290
|
+
workspaceId: group.workspace.id,
|
|
54291
|
+
proposalId: proposal.id,
|
|
54292
|
+
fresh,
|
|
54293
|
+
kind: proposal.kind,
|
|
54294
|
+
author: proposal.author,
|
|
54295
|
+
createdAt: proposal.createdAt,
|
|
54296
|
+
note: note2
|
|
54297
|
+
};
|
|
54255
54298
|
}));
|
|
54256
54299
|
}
|
|
54257
54300
|
async function classifySession(session) {
|
|
@@ -54822,7 +54865,7 @@ function openFlows(otui, chrome, options) {
|
|
|
54822
54865
|
|
|
54823
54866
|
// src/tui/busy-dispatch.ts
|
|
54824
54867
|
function classifyBusyDispatch(params) {
|
|
54825
|
-
const { line, commandName, isSessionInfo, isFlows, isWorkspace, isReview } = params;
|
|
54868
|
+
const { line, commandName, isSessionInfo, isFlows, isWorkspace, isReview, isMcp } = params;
|
|
54826
54869
|
if (commandName === "/exit")
|
|
54827
54870
|
return "exit";
|
|
54828
54871
|
if (commandName === "/help")
|
|
@@ -54841,7 +54884,7 @@ function classifyBusyDispatch(params) {
|
|
|
54841
54884
|
return "copy";
|
|
54842
54885
|
if (commandName === "/mode")
|
|
54843
54886
|
return "mode";
|
|
54844
|
-
const isBusyReadonlyCommand = isSessionInfo || isFlows || isWorkspace || isReview;
|
|
54887
|
+
const isBusyReadonlyCommand = isSessionInfo || isFlows || isWorkspace || isReview || isMcp;
|
|
54845
54888
|
if (isBusyReadonlyCommand && isSessionInfo)
|
|
54846
54889
|
return "session-info";
|
|
54847
54890
|
if (isBusyReadonlyCommand && isFlows)
|
|
@@ -54850,6 +54893,8 @@ function classifyBusyDispatch(params) {
|
|
|
54850
54893
|
return "workspace";
|
|
54851
54894
|
if (isBusyReadonlyCommand && isReview)
|
|
54852
54895
|
return "review";
|
|
54896
|
+
if (isBusyReadonlyCommand && isMcp)
|
|
54897
|
+
return "mcp";
|
|
54853
54898
|
if (commandName !== undefined || line.startsWith("/"))
|
|
54854
54899
|
return "deferred";
|
|
54855
54900
|
return "not-a-command";
|
|
@@ -55109,7 +55154,8 @@ function openWorkspace(otui, chrome, options) {
|
|
|
55109
55154
|
var REVIEW_COMMAND = "/review";
|
|
55110
55155
|
var REVIEW_FOOTER = [
|
|
55111
55156
|
{ key: "[/]", label: "item" },
|
|
55112
|
-
{ key: "a y", label: "accept" },
|
|
55157
|
+
{ key: "a y", label: "accept proposal" },
|
|
55158
|
+
{ key: "d y", label: "decline proposal" },
|
|
55113
55159
|
{ key: "\u2191/\u2193", label: "scroll" },
|
|
55114
55160
|
{ key: "\u2190/\u2192", label: "tabs" },
|
|
55115
55161
|
{ key: "esc", label: "close" }
|
|
@@ -55127,7 +55173,7 @@ var TYPE_LABEL = {
|
|
|
55127
55173
|
function summarizeReviewItem(item) {
|
|
55128
55174
|
switch (item.type) {
|
|
55129
55175
|
case "proposal":
|
|
55130
|
-
return `${item.proposalId} in ${item.workspaceId}${item.fresh ? "" : " (stale)"}`;
|
|
55176
|
+
return `${item.kind} ${item.proposalId} in ${item.workspaceId}${item.fresh ? "" : " (stale)"}`;
|
|
55131
55177
|
case "blocked":
|
|
55132
55178
|
return `${item.sessionId} \u2014 ${item.terminalState.reason}`;
|
|
55133
55179
|
case "unbound-candidate":
|
|
@@ -55151,9 +55197,13 @@ function describeReviewItem(item) {
|
|
|
55151
55197
|
return [
|
|
55152
55198
|
`Proposal ${item.proposalId}`,
|
|
55153
55199
|
`Workspace ${item.workspaceId}`,
|
|
55200
|
+
`Kind ${item.kind}`,
|
|
55201
|
+
`Author ${item.author}`,
|
|
55202
|
+
`Created ${item.createdAt}`,
|
|
55154
55203
|
`Evidence ${item.fresh ? "fresh" : "stale \u2014 evidence has drifted since this proposal was created; re-run wrap-up before deciding"}`,
|
|
55204
|
+
...item.note !== undefined ? ["", `Note ${item.note}`] : [],
|
|
55155
55205
|
"",
|
|
55156
|
-
`
|
|
55206
|
+
`Dismiss (archive with no decision) from a terminal: keryx workspace review ${item.workspaceId} ${item.proposalId} --decision dismissed`
|
|
55157
55207
|
];
|
|
55158
55208
|
case "blocked":
|
|
55159
55209
|
return [
|
|
@@ -55206,25 +55256,37 @@ function describeGroupOutcome(g) {
|
|
|
55206
55256
|
}
|
|
55207
55257
|
}
|
|
55208
55258
|
}
|
|
55259
|
+
var DECISION_VERB = { accept: "Accept", decline: "Decline" };
|
|
55260
|
+
var DECISION_ING = { accept: "Accepting", decline: "Declining" };
|
|
55261
|
+
var DECISION_DONE = { accept: "Accepted", decline: "Declined" };
|
|
55262
|
+
var DECISION_COMMAND = {
|
|
55263
|
+
accept: "running `keryx workspace confirm-review` then `keryx workspace review`",
|
|
55264
|
+
decline: "running `keryx workspace review --decision rejected`"
|
|
55265
|
+
};
|
|
55209
55266
|
function formatReviewDetailLines(item, status) {
|
|
55210
55267
|
if (item === undefined) {
|
|
55211
55268
|
return ["No item selected.", "", "Press Enter (or click a row) on the Review tab to view one."];
|
|
55212
55269
|
}
|
|
55213
55270
|
const lines = describeReviewItem(item);
|
|
55214
55271
|
if (item.type !== "proposal") {
|
|
55272
|
+
if (status.kind === "unavailable") {
|
|
55273
|
+
return [...lines, "", `[${status.decision === "accept" ? "a" : "d"}] does nothing here \u2014 accept/decline only apply to a pending proposal, not to this item.`];
|
|
55274
|
+
}
|
|
55215
55275
|
return lines;
|
|
55216
55276
|
}
|
|
55217
55277
|
const withAction = [...lines, ""];
|
|
55218
55278
|
if (status.kind === "armed") {
|
|
55219
|
-
withAction.push(
|
|
55279
|
+
withAction.push(`Press [y] to CONFIRM ${status.decision}, any other key cancels.`);
|
|
55220
55280
|
} else if (status.kind === "running") {
|
|
55221
|
-
withAction.push(
|
|
55281
|
+
withAction.push(`${DECISION_ING[status.decision]}\u2026 ${DECISION_COMMAND[status.decision]}.`);
|
|
55222
55282
|
} else if (status.kind === "done" && status.outcome.ok) {
|
|
55223
|
-
withAction.push(
|
|
55283
|
+
withAction.push(`\u2713 ${DECISION_DONE[status.decision]}.`);
|
|
55224
55284
|
} else if (status.kind === "done" && !status.outcome.ok) {
|
|
55225
|
-
withAction.push(`\u2717
|
|
55285
|
+
withAction.push(`\u2717 ${DECISION_VERB[status.decision]} failed: ${status.outcome.message}`);
|
|
55286
|
+
} else if (status.kind === "unavailable") {
|
|
55287
|
+
withAction.push(`[${status.decision === "accept" ? "a" : "d"}] does nothing \u2014 no ${status.decision} handler is configured for this modal.`);
|
|
55226
55288
|
} else {
|
|
55227
|
-
withAction.push("[a] Accept this proposal");
|
|
55289
|
+
withAction.push("[a] Accept this proposal [d] Decline this proposal");
|
|
55228
55290
|
}
|
|
55229
55291
|
return withAction;
|
|
55230
55292
|
}
|
|
@@ -55321,17 +55383,19 @@ function presentReview(openModal2, otui, chrome, options) {
|
|
|
55321
55383
|
status = { kind: "idle" };
|
|
55322
55384
|
paintSelection();
|
|
55323
55385
|
};
|
|
55324
|
-
const
|
|
55386
|
+
const handlerFor = (decision) => decision === "accept" ? options.acceptProposal : options.declineProposal;
|
|
55387
|
+
const runDecision = (decision) => {
|
|
55325
55388
|
const item = items[selected];
|
|
55326
|
-
|
|
55389
|
+
const run = handlerFor(decision);
|
|
55390
|
+
if (item === undefined || item.type !== "proposal" || run === undefined) {
|
|
55327
55391
|
return;
|
|
55328
55392
|
}
|
|
55329
|
-
status = { kind: "running" };
|
|
55393
|
+
status = { kind: "running", decision };
|
|
55330
55394
|
paintSelection();
|
|
55331
|
-
|
|
55332
|
-
status = { kind: "done", outcome };
|
|
55395
|
+
run(item).then((outcome) => {
|
|
55396
|
+
status = { kind: "done", decision, outcome };
|
|
55333
55397
|
if (outcome.ok) {
|
|
55334
|
-
options.
|
|
55398
|
+
options.onResolved?.(item);
|
|
55335
55399
|
}
|
|
55336
55400
|
paintSelection();
|
|
55337
55401
|
});
|
|
@@ -55371,7 +55435,7 @@ function presentReview(openModal2, otui, chrome, options) {
|
|
|
55371
55435
|
const onDetail = handle.activeTab() === "detail";
|
|
55372
55436
|
if (onDetail && status.kind === "armed") {
|
|
55373
55437
|
if (token === "y") {
|
|
55374
|
-
|
|
55438
|
+
runDecision(status.decision);
|
|
55375
55439
|
} else {
|
|
55376
55440
|
status = { kind: "idle" };
|
|
55377
55441
|
paintSelection();
|
|
@@ -55390,8 +55454,9 @@ function presentReview(openModal2, otui, chrome, options) {
|
|
|
55390
55454
|
handle.setTab("detail");
|
|
55391
55455
|
return;
|
|
55392
55456
|
}
|
|
55393
|
-
if (onDetail && token === "a"
|
|
55394
|
-
|
|
55457
|
+
if (onDetail && (token === "a" || token === "d") && status.kind !== "running") {
|
|
55458
|
+
const decision = token === "a" ? "accept" : "decline";
|
|
55459
|
+
status = items[selected]?.type === "proposal" && handlerFor(decision) !== undefined ? { kind: "armed", decision } : { kind: "unavailable", decision };
|
|
55395
55460
|
paintSelection();
|
|
55396
55461
|
return;
|
|
55397
55462
|
}
|
|
@@ -55455,6 +55520,285 @@ async function acceptProposalViaShell(run, workspaceId, proposalId) {
|
|
|
55455
55520
|
}
|
|
55456
55521
|
return { ok: true };
|
|
55457
55522
|
}
|
|
55523
|
+
async function declineProposalViaShell(run, workspaceId, proposalId) {
|
|
55524
|
+
const decline = await run(`keryx workspace review ${shQuote(workspaceId)} ${shQuote(proposalId)} --decision rejected`);
|
|
55525
|
+
if (decline.isError) {
|
|
55526
|
+
return { ok: false, message: decline.output };
|
|
55527
|
+
}
|
|
55528
|
+
return { ok: true };
|
|
55529
|
+
}
|
|
55530
|
+
|
|
55531
|
+
// src/tui/mcp-inspector.ts
|
|
55532
|
+
var MCP_INSPECTOR_FOOTER = [
|
|
55533
|
+
{ key: "\u2191/\u2193", label: "select" },
|
|
55534
|
+
{ key: "click", label: "row: select/act" },
|
|
55535
|
+
{ key: "c/d", label: "connect/disconnect" },
|
|
55536
|
+
{ key: "y", label: "confirm" },
|
|
55537
|
+
{ key: "\u2190/\u2192", label: "tabs" },
|
|
55538
|
+
{ key: "esc", label: "close" }
|
|
55539
|
+
];
|
|
55540
|
+
var MCP_TOOLS_COMMAND = "/mcp";
|
|
55541
|
+
function isMcpToolsCommand(line) {
|
|
55542
|
+
const token = line.trim().split(/\s+/)[0] ?? "";
|
|
55543
|
+
return token === MCP_TOOLS_COMMAND;
|
|
55544
|
+
}
|
|
55545
|
+
var RUNTIME_LABELS = {
|
|
55546
|
+
cursor: "Cursor",
|
|
55547
|
+
claude: "Claude Code",
|
|
55548
|
+
opencode: "opencode",
|
|
55549
|
+
vscode: "VS Code",
|
|
55550
|
+
generic: "Generic (manual)"
|
|
55551
|
+
};
|
|
55552
|
+
function runtimeLabel(id) {
|
|
55553
|
+
return RUNTIME_LABELS[id] ?? id;
|
|
55554
|
+
}
|
|
55555
|
+
function formatToolRowLine(tool) {
|
|
55556
|
+
const risk = (tool.risk ?? "read").padEnd(6);
|
|
55557
|
+
const name = tool.name.padEnd(28);
|
|
55558
|
+
return `${name} ${risk} ${tool.description ?? ""}`.trimEnd();
|
|
55559
|
+
}
|
|
55560
|
+
function isActionable(id) {
|
|
55561
|
+
return id !== "generic";
|
|
55562
|
+
}
|
|
55563
|
+
function formatMcpRowLine(runtime, isSelected, status) {
|
|
55564
|
+
const mark = isSelected ? ">" : " ";
|
|
55565
|
+
const label = runtimeLabel(runtime.id).padEnd(20);
|
|
55566
|
+
const statusText = runtime.connected ? "\u25CF connected" : "\u25CB not connected";
|
|
55567
|
+
let action = "";
|
|
55568
|
+
if (!isActionable(runtime.id)) {
|
|
55569
|
+
action = " (copy snippet manually)";
|
|
55570
|
+
} else if (status.kind === "armed" && status.target.id === runtime.id) {
|
|
55571
|
+
action = ` [click again or press y to ${status.target.action}]`;
|
|
55572
|
+
} else if (status.kind === "running" && status.target.id === runtime.id) {
|
|
55573
|
+
action = ` ${status.target.action === "connect" ? "connecting\u2026" : "disconnecting\u2026"}`;
|
|
55574
|
+
} else if (status.kind === "done" && status.target.id === runtime.id) {
|
|
55575
|
+
action = status.outcome.ok ? " \u2713 done" : ` \u2717 ${status.outcome.message}`;
|
|
55576
|
+
} else {
|
|
55577
|
+
action = runtime.connected ? " [d] disconnect" : " [c] connect";
|
|
55578
|
+
}
|
|
55579
|
+
return `${mark} ${label} ${statusText}${action}`;
|
|
55580
|
+
}
|
|
55581
|
+
function asRowTarget(body) {
|
|
55582
|
+
const parent = body;
|
|
55583
|
+
if (parent.add === undefined || parent.getChildren === undefined || parent.remove === undefined) {
|
|
55584
|
+
return;
|
|
55585
|
+
}
|
|
55586
|
+
return {
|
|
55587
|
+
add: parent.add.bind(parent),
|
|
55588
|
+
getChildren: parent.getChildren.bind(parent),
|
|
55589
|
+
remove: parent.remove.bind(parent)
|
|
55590
|
+
};
|
|
55591
|
+
}
|
|
55592
|
+
function presentMcpTools(openModal2, otui, chrome, options) {
|
|
55593
|
+
const runtimes = options.runtimes.map((r) => ({ ...r }));
|
|
55594
|
+
let mcpSelected = 0;
|
|
55595
|
+
let toolsScroll = 0;
|
|
55596
|
+
let mcpScroll = 0;
|
|
55597
|
+
let status = { kind: "idle" };
|
|
55598
|
+
let toolsBody;
|
|
55599
|
+
let mcpBody;
|
|
55600
|
+
let rowCtor;
|
|
55601
|
+
let activeRenderer;
|
|
55602
|
+
let unsubscribeKey;
|
|
55603
|
+
const rendererHint = options.renderer ?? chrome?.renderer;
|
|
55604
|
+
const bodyRows = options.visibleRows ?? (typeof rendererHint?.width === "number" && typeof rendererHint.height === "number" ? modalBodyRows(resolveModalPanelSize(rendererHint.width, rendererHint.height).height) : 13);
|
|
55605
|
+
const paintToolsRows = () => {
|
|
55606
|
+
if (toolsBody === undefined || rowCtor === undefined) {
|
|
55607
|
+
return;
|
|
55608
|
+
}
|
|
55609
|
+
clearTranscriptChildren(toolsBody);
|
|
55610
|
+
if (options.tools.length === 0) {
|
|
55611
|
+
toolsBody.add(new rowCtor(activeRenderer, { id: "mcp-tools-empty", content: "No tools available." }));
|
|
55612
|
+
return;
|
|
55613
|
+
}
|
|
55614
|
+
const start = clampScroll3(toolsScroll, options.tools.length, bodyRows);
|
|
55615
|
+
for (const [i, tool] of options.tools.slice(start, start + bodyRows).entries()) {
|
|
55616
|
+
toolsBody.add(new rowCtor(activeRenderer, { id: `mcp-tool-row-${start + i}`, content: formatToolRowLine(tool) }));
|
|
55617
|
+
}
|
|
55618
|
+
};
|
|
55619
|
+
const paintMcpRows = () => {
|
|
55620
|
+
if (mcpBody === undefined || rowCtor === undefined) {
|
|
55621
|
+
return;
|
|
55622
|
+
}
|
|
55623
|
+
clearTranscriptChildren(mcpBody);
|
|
55624
|
+
if (runtimes.length === 0) {
|
|
55625
|
+
mcpBody.add(new rowCtor(activeRenderer, { id: "mcp-mcp-empty", content: "No MCP client runtimes registered." }));
|
|
55626
|
+
return;
|
|
55627
|
+
}
|
|
55628
|
+
const start = clampScroll3(mcpScroll, runtimes.length, bodyRows);
|
|
55629
|
+
for (const [i, runtime] of runtimes.slice(start, start + bodyRows).entries()) {
|
|
55630
|
+
const index = start + i;
|
|
55631
|
+
mcpBody.add(new rowCtor(activeRenderer, {
|
|
55632
|
+
id: `mcp-row-${runtime.id}`,
|
|
55633
|
+
content: formatMcpRowLine(runtime, index === mcpSelected, status),
|
|
55634
|
+
onMouseDown: () => handleRowClick(runtime.id, index)
|
|
55635
|
+
}));
|
|
55636
|
+
}
|
|
55637
|
+
};
|
|
55638
|
+
const paint = () => {
|
|
55639
|
+
toolsScroll = clampScroll3(toolsScroll, options.tools.length, bodyRows);
|
|
55640
|
+
mcpScroll = scrollToReveal3(mcpSelected, mcpScroll, bodyRows);
|
|
55641
|
+
mcpScroll = clampScroll3(mcpScroll, runtimes.length, bodyRows);
|
|
55642
|
+
paintToolsRows();
|
|
55643
|
+
paintMcpRows();
|
|
55644
|
+
};
|
|
55645
|
+
const moveMcpSelection = (next) => {
|
|
55646
|
+
if (runtimes.length === 0) {
|
|
55647
|
+
return;
|
|
55648
|
+
}
|
|
55649
|
+
const clamped = Math.min(runtimes.length - 1, Math.max(0, next));
|
|
55650
|
+
if (clamped === mcpSelected) {
|
|
55651
|
+
return;
|
|
55652
|
+
}
|
|
55653
|
+
mcpSelected = clamped;
|
|
55654
|
+
status = { kind: "idle" };
|
|
55655
|
+
paint();
|
|
55656
|
+
};
|
|
55657
|
+
const runAction = () => {
|
|
55658
|
+
if (status.kind !== "armed") {
|
|
55659
|
+
return;
|
|
55660
|
+
}
|
|
55661
|
+
const target = status.target;
|
|
55662
|
+
status = { kind: "running", target };
|
|
55663
|
+
paint();
|
|
55664
|
+
const fn = target.action === "connect" ? options.connect : options.disconnect;
|
|
55665
|
+
fn(target.id).then((outcome) => {
|
|
55666
|
+
status = { kind: "done", target, outcome };
|
|
55667
|
+
if (outcome.ok) {
|
|
55668
|
+
const row = runtimes.find((r) => r.id === target.id);
|
|
55669
|
+
if (row !== undefined) {
|
|
55670
|
+
row.connected = target.action === "connect";
|
|
55671
|
+
}
|
|
55672
|
+
}
|
|
55673
|
+
options.onStatusChange?.(runtimes);
|
|
55674
|
+
paint();
|
|
55675
|
+
});
|
|
55676
|
+
};
|
|
55677
|
+
const armFor = (id) => {
|
|
55678
|
+
const index = runtimes.findIndex((r) => r.id === id);
|
|
55679
|
+
const row = runtimes[index];
|
|
55680
|
+
if (index < 0 || row === undefined || !isActionable(row.id) || status.kind === "running") {
|
|
55681
|
+
return;
|
|
55682
|
+
}
|
|
55683
|
+
mcpSelected = index;
|
|
55684
|
+
status = { kind: "armed", target: { id: row.id, action: row.connected ? "disconnect" : "connect" } };
|
|
55685
|
+
paint();
|
|
55686
|
+
};
|
|
55687
|
+
const handleRowClick = (id, index) => {
|
|
55688
|
+
if (status.kind === "armed" && status.target.id === id) {
|
|
55689
|
+
runAction();
|
|
55690
|
+
return;
|
|
55691
|
+
}
|
|
55692
|
+
if (status.kind === "running") {
|
|
55693
|
+
return;
|
|
55694
|
+
}
|
|
55695
|
+
if (!isActionable(id)) {
|
|
55696
|
+
if (index !== mcpSelected) {
|
|
55697
|
+
mcpSelected = index;
|
|
55698
|
+
status = { kind: "idle" };
|
|
55699
|
+
paint();
|
|
55700
|
+
}
|
|
55701
|
+
return;
|
|
55702
|
+
}
|
|
55703
|
+
armFor(id);
|
|
55704
|
+
};
|
|
55705
|
+
const handle = openModal2(otui, chrome, {
|
|
55706
|
+
title: "Tools & MCP",
|
|
55707
|
+
tabs: [
|
|
55708
|
+
{ id: "tools", label: "Tools" },
|
|
55709
|
+
{ id: "mcp", label: "MCP" }
|
|
55710
|
+
],
|
|
55711
|
+
initialTab: "tools",
|
|
55712
|
+
footer: MCP_INSPECTOR_FOOTER,
|
|
55713
|
+
renderTab: (tabId, body, ctx) => {
|
|
55714
|
+
const renderer = options.renderer ?? chrome?.renderer;
|
|
55715
|
+
const ctor = otui.TextRenderable;
|
|
55716
|
+
const target = asRowTarget(body);
|
|
55717
|
+
if (target === undefined || ctor === undefined) {
|
|
55718
|
+
return;
|
|
55719
|
+
}
|
|
55720
|
+
rowCtor = ctor;
|
|
55721
|
+
activeRenderer = renderer;
|
|
55722
|
+
if (tabId === "tools") {
|
|
55723
|
+
toolsBody = target;
|
|
55724
|
+
toolsScroll = clampScroll3(toolsScroll, options.tools.length, bodyRows);
|
|
55725
|
+
paintToolsRows();
|
|
55726
|
+
return;
|
|
55727
|
+
}
|
|
55728
|
+
mcpBody = target;
|
|
55729
|
+
mcpScroll = scrollToReveal3(mcpSelected, mcpScroll, bodyRows);
|
|
55730
|
+
paintMcpRows();
|
|
55731
|
+
},
|
|
55732
|
+
onClose: () => {
|
|
55733
|
+
unsubscribeKey?.();
|
|
55734
|
+
}
|
|
55735
|
+
});
|
|
55736
|
+
if (handle === undefined) {
|
|
55737
|
+
return;
|
|
55738
|
+
}
|
|
55739
|
+
if (options.onKeypress !== undefined) {
|
|
55740
|
+
unsubscribeKey = options.onKeypress((key) => {
|
|
55741
|
+
const token = key.name || key.sequence;
|
|
55742
|
+
const onMcp = handle.activeTab() === "mcp";
|
|
55743
|
+
if (onMcp && status.kind === "armed") {
|
|
55744
|
+
if (token === "y") {
|
|
55745
|
+
runAction();
|
|
55746
|
+
} else {
|
|
55747
|
+
status = { kind: "idle" };
|
|
55748
|
+
paint();
|
|
55749
|
+
}
|
|
55750
|
+
return;
|
|
55751
|
+
}
|
|
55752
|
+
if (onMcp && token === "c") {
|
|
55753
|
+
const row = runtimes[mcpSelected];
|
|
55754
|
+
if (row !== undefined && isActionable(row.id) && !row.connected && status.kind !== "running") {
|
|
55755
|
+
status = { kind: "armed", target: { id: row.id, action: "connect" } };
|
|
55756
|
+
paint();
|
|
55757
|
+
}
|
|
55758
|
+
return;
|
|
55759
|
+
}
|
|
55760
|
+
if (onMcp && token === "d") {
|
|
55761
|
+
const row = runtimes[mcpSelected];
|
|
55762
|
+
if (row !== undefined && isActionable(row.id) && row.connected && status.kind !== "running") {
|
|
55763
|
+
status = { kind: "armed", target: { id: row.id, action: "disconnect" } };
|
|
55764
|
+
paint();
|
|
55765
|
+
}
|
|
55766
|
+
return;
|
|
55767
|
+
}
|
|
55768
|
+
if (token === "up" || token === "k") {
|
|
55769
|
+
if (onMcp) {
|
|
55770
|
+
moveMcpSelection(mcpSelected - 1);
|
|
55771
|
+
} else {
|
|
55772
|
+
toolsScroll = clampScroll3(toolsScroll - 1, options.tools.length, bodyRows);
|
|
55773
|
+
paint();
|
|
55774
|
+
}
|
|
55775
|
+
return;
|
|
55776
|
+
}
|
|
55777
|
+
if (token === "down" || token === "j") {
|
|
55778
|
+
if (onMcp) {
|
|
55779
|
+
moveMcpSelection(mcpSelected + 1);
|
|
55780
|
+
} else {
|
|
55781
|
+
toolsScroll = clampScroll3(toolsScroll + 1, options.tools.length, bodyRows);
|
|
55782
|
+
paint();
|
|
55783
|
+
}
|
|
55784
|
+
return;
|
|
55785
|
+
}
|
|
55786
|
+
if (token === "pageup" || token === "pagedown") {
|
|
55787
|
+
const step = token === "pageup" ? -bodyRows : bodyRows;
|
|
55788
|
+
if (onMcp) {
|
|
55789
|
+
mcpScroll = clampScroll3(mcpScroll + step, runtimes.length, bodyRows);
|
|
55790
|
+
} else {
|
|
55791
|
+
toolsScroll = clampScroll3(toolsScroll + step, options.tools.length, bodyRows);
|
|
55792
|
+
}
|
|
55793
|
+
paint();
|
|
55794
|
+
}
|
|
55795
|
+
});
|
|
55796
|
+
}
|
|
55797
|
+
return handle;
|
|
55798
|
+
}
|
|
55799
|
+
function openMcpTools(otui, chrome, options) {
|
|
55800
|
+
return presentMcpTools((hostOtui, hostChrome, input2) => openModal(hostOtui, hostChrome, input2), otui, chrome, options);
|
|
55801
|
+
}
|
|
55458
55802
|
|
|
55459
55803
|
// src/tui/tui-shell.ts
|
|
55460
55804
|
init_slate();
|
|
@@ -55825,6 +56169,11 @@ var AGENT_SLASH_COMMANDS = [
|
|
|
55825
56169
|
description: "Show project-wide items needing review (proposals, blocked sessions)",
|
|
55826
56170
|
modes: AGENT_ONLY
|
|
55827
56171
|
},
|
|
56172
|
+
{
|
|
56173
|
+
name: "/mcp",
|
|
56174
|
+
description: "Show available tools and MCP client connect status",
|
|
56175
|
+
modes: AGENT_ONLY
|
|
56176
|
+
},
|
|
55828
56177
|
{
|
|
55829
56178
|
name: "/compact",
|
|
55830
56179
|
description: "Compact model context \u2014 /compact [focus] (archive kept)",
|
|
@@ -56403,6 +56752,10 @@ function onKeypress2(r, handler) {
|
|
|
56403
56752
|
return () => r._internalKeyInput.offInternal("keypress", handler);
|
|
56404
56753
|
}
|
|
56405
56754
|
function showComposerChoice(otui, r, dock, request) {
|
|
56755
|
+
if (dock.visible === true) {
|
|
56756
|
+
request.onBusy?.();
|
|
56757
|
+
return Promise.resolve(request.cancelId);
|
|
56758
|
+
}
|
|
56406
56759
|
return new Promise((resolve3) => {
|
|
56407
56760
|
const options = request.options.map((o) => ({
|
|
56408
56761
|
...o,
|
|
@@ -60626,7 +60979,13 @@ async function launchTuiAgentShell(opts) {
|
|
|
60626
60979
|
const sbContext = new otui.TextRenderable(r, { id: "sb-ctx-v", content: otui.t`${otui.dim("0 tokens")}` });
|
|
60627
60980
|
sidebar.add(sbContext);
|
|
60628
60981
|
sidebar.add(new otui.TextRenderable(r, { id: "sb-tools-k", content: otui.t`${otui.dim("Tools")}`, marginTop: 1 }));
|
|
60629
|
-
sidebar.add(new otui.TextRenderable(r, {
|
|
60982
|
+
sidebar.add(new otui.TextRenderable(r, {
|
|
60983
|
+
id: "sb-tools-v",
|
|
60984
|
+
content: otui.t`${otui.dim(`${deps.tools.length} available`)}`,
|
|
60985
|
+
onMouseDown: () => {
|
|
60986
|
+
showTools();
|
|
60987
|
+
}
|
|
60988
|
+
}));
|
|
60630
60989
|
sidebar.add(new otui.TextRenderable(r, { id: "sb-status-k", content: otui.t`${otui.dim("Status")}`, marginTop: 1 }));
|
|
60631
60990
|
const sbWorkers = new otui.TextRenderable(r, {
|
|
60632
60991
|
id: "sb-status-v",
|
|
@@ -61401,7 +61760,8 @@ Staying in the current session.
|
|
|
61401
61760
|
openReview(otui, chrome, {
|
|
61402
61761
|
items,
|
|
61403
61762
|
acceptProposal: (item) => acceptProposalViaShell(makeCommandRunner(cwd), item.workspaceId, item.proposalId),
|
|
61404
|
-
|
|
61763
|
+
declineProposal: (item) => declineProposalViaShell(makeCommandRunner(cwd), item.workspaceId, item.proposalId),
|
|
61764
|
+
onResolved: () => {
|
|
61405
61765
|
refreshReviewSidebar();
|
|
61406
61766
|
},
|
|
61407
61767
|
renderer: r,
|
|
@@ -61409,6 +61769,38 @@ Staying in the current session.
|
|
|
61409
61769
|
});
|
|
61410
61770
|
})();
|
|
61411
61771
|
};
|
|
61772
|
+
const showTools = () => {
|
|
61773
|
+
(async () => {
|
|
61774
|
+
const cwd = inspectorCwd();
|
|
61775
|
+
const runtimes = await mcpClientStatus(cwd, mcpRuntimeIds());
|
|
61776
|
+
openMcpTools(otui, chrome, {
|
|
61777
|
+
tools: deps.tools.map((t) => t.definition),
|
|
61778
|
+
runtimes,
|
|
61779
|
+
connect: async (id) => {
|
|
61780
|
+
try {
|
|
61781
|
+
const report = await installMcpClient(cwd, [id]);
|
|
61782
|
+
const outcome = report.outcomes[0];
|
|
61783
|
+
if (outcome !== undefined && outcome.errors.length > 0) {
|
|
61784
|
+
return { ok: false, message: outcome.errors.join("; ") };
|
|
61785
|
+
}
|
|
61786
|
+
return { ok: true };
|
|
61787
|
+
} catch (error2) {
|
|
61788
|
+
return { ok: false, message: error2 instanceof Error ? error2.message : String(error2) };
|
|
61789
|
+
}
|
|
61790
|
+
},
|
|
61791
|
+
disconnect: async (id) => {
|
|
61792
|
+
try {
|
|
61793
|
+
await uninstallMcpClient(cwd, [id]);
|
|
61794
|
+
return { ok: true };
|
|
61795
|
+
} catch (error2) {
|
|
61796
|
+
return { ok: false, message: error2 instanceof Error ? error2.message : String(error2) };
|
|
61797
|
+
}
|
|
61798
|
+
},
|
|
61799
|
+
renderer: r,
|
|
61800
|
+
...inspectorKeys
|
|
61801
|
+
});
|
|
61802
|
+
})();
|
|
61803
|
+
};
|
|
61412
61804
|
const runModeCommand = (line) => {
|
|
61413
61805
|
const modeArgs = line.trim().split(/\s+/).slice(1).filter((p) => p.length > 0);
|
|
61414
61806
|
const wanted = modeArgs[0] ?? "";
|
|
@@ -61416,6 +61808,7 @@ Staying in the current session.
|
|
|
61416
61808
|
const applyMode = async (next) => {
|
|
61417
61809
|
if (next === "auto") {
|
|
61418
61810
|
chrome.hideMenu();
|
|
61811
|
+
let blockedByOpenDialog = false;
|
|
61419
61812
|
const confirmId = await chrome.withOverlay(() => showComposerChoice(otui, r, chrome.dock, {
|
|
61420
61813
|
title: "Switch to auto mode?",
|
|
61421
61814
|
subtitle: "Skips confirmation for EVERY action, including destructive commands. Only credential-touching commands still ask.",
|
|
@@ -61423,9 +61816,16 @@ Staying in the current session.
|
|
|
61423
61816
|
options: [
|
|
61424
61817
|
{ id: "confirm", label: "Confirm", description: "I understand the risk" },
|
|
61425
61818
|
{ id: "cancel", label: "Cancel", description: "Keep the current mode", recommended: true }
|
|
61426
|
-
]
|
|
61819
|
+
],
|
|
61820
|
+
onBusy: () => {
|
|
61821
|
+
blockedByOpenDialog = true;
|
|
61822
|
+
chrome.showToast("Answer the open approval first, then retry /mode.");
|
|
61823
|
+
}
|
|
61427
61824
|
}));
|
|
61428
61825
|
input2.focus();
|
|
61826
|
+
if (blockedByOpenDialog) {
|
|
61827
|
+
return;
|
|
61828
|
+
}
|
|
61429
61829
|
if (confirmId !== "confirm") {
|
|
61430
61830
|
chrome.showToast("Cancelled \u2014 mode unchanged.");
|
|
61431
61831
|
return;
|
|
@@ -61455,6 +61855,7 @@ Staying in the current session.
|
|
|
61455
61855
|
const stored = getProjectPermissionMode(sessionCwd);
|
|
61456
61856
|
chrome.hideMenu();
|
|
61457
61857
|
(async () => {
|
|
61858
|
+
let blockedByOpenDialog = false;
|
|
61458
61859
|
const id = await chrome.withOverlay(() => showComposerChoice(otui, r, chrome.dock, {
|
|
61459
61860
|
title: `Permission mode (current: ${permissionMode})`,
|
|
61460
61861
|
subtitle: stored !== undefined ? `Project default: ${stored}` : "No project default set.",
|
|
@@ -61464,9 +61865,16 @@ Staying in the current session.
|
|
|
61464
61865
|
label: m,
|
|
61465
61866
|
description: MODE_PICKER_DESCRIPTIONS[m],
|
|
61466
61867
|
recommended: m === permissionMode
|
|
61467
|
-
}))
|
|
61868
|
+
})),
|
|
61869
|
+
onBusy: () => {
|
|
61870
|
+
blockedByOpenDialog = true;
|
|
61871
|
+
chrome.showToast("Answer the open approval first, then retry /mode.");
|
|
61872
|
+
}
|
|
61468
61873
|
}));
|
|
61469
61874
|
input2.focus();
|
|
61875
|
+
if (blockedByOpenDialog) {
|
|
61876
|
+
return;
|
|
61877
|
+
}
|
|
61470
61878
|
if (isPermissionMode(id) && id !== permissionMode) {
|
|
61471
61879
|
await applyMode(id);
|
|
61472
61880
|
}
|
|
@@ -61864,7 +62272,8 @@ Staying in the current session.
|
|
|
61864
62272
|
isSessionInfo: isSessionInfoCommand(line),
|
|
61865
62273
|
isFlows: isFlowsCommand(line),
|
|
61866
62274
|
isWorkspace: isWorkspaceCommand(line),
|
|
61867
|
-
isReview: isReviewCommand(line)
|
|
62275
|
+
isReview: isReviewCommand(line),
|
|
62276
|
+
isMcp: isMcpToolsCommand(line)
|
|
61868
62277
|
});
|
|
61869
62278
|
switch (decision) {
|
|
61870
62279
|
case "exit": {
|
|
@@ -61972,6 +62381,10 @@ Staying in the current session.
|
|
|
61972
62381
|
showReview();
|
|
61973
62382
|
return;
|
|
61974
62383
|
}
|
|
62384
|
+
case "mcp": {
|
|
62385
|
+
showTools();
|
|
62386
|
+
return;
|
|
62387
|
+
}
|
|
61975
62388
|
case "deferred": {
|
|
61976
62389
|
transcript.add(new otui.TextRenderable(r, {
|
|
61977
62390
|
id: `c${uid++}`,
|
|
@@ -61995,6 +62408,7 @@ Staying in the current session.
|
|
|
61995
62408
|
return;
|
|
61996
62409
|
}
|
|
61997
62410
|
(async () => {
|
|
62411
|
+
let blockedByOpenDialog = false;
|
|
61998
62412
|
const chosen = await showComposerChoice(otui, r, chrome.dock, {
|
|
61999
62413
|
title: "Main agent is busy",
|
|
62000
62414
|
subtitle: line,
|
|
@@ -62002,8 +62416,17 @@ Staying in the current session.
|
|
|
62002
62416
|
{ id: "main", label: "Main queue", description: "queue for the main agent; remove/edit/force later", recommended: true },
|
|
62003
62417
|
{ id: "side", label: "Side-1", description: "read-only answer, outside main history (as before)" }
|
|
62004
62418
|
],
|
|
62005
|
-
cancelId: "side"
|
|
62419
|
+
cancelId: "side",
|
|
62420
|
+
onBusy: () => {
|
|
62421
|
+
blockedByOpenDialog = true;
|
|
62422
|
+
chrome.showToast("Answer the open approval first, then resend.");
|
|
62423
|
+
}
|
|
62006
62424
|
});
|
|
62425
|
+
if (blockedByOpenDialog) {
|
|
62426
|
+
input2.value = line;
|
|
62427
|
+
input2.focus();
|
|
62428
|
+
return;
|
|
62429
|
+
}
|
|
62007
62430
|
if (chosen === "main") {
|
|
62008
62431
|
const id = `mq${mainQueueSeq++}`;
|
|
62009
62432
|
mainQueue.push({ id, question: line, displayQuestion: displayLine });
|
|
@@ -62182,6 +62605,10 @@ Staying in the current session.
|
|
|
62182
62605
|
showReview();
|
|
62183
62606
|
return;
|
|
62184
62607
|
}
|
|
62608
|
+
if (isMcpToolsCommand(command.name)) {
|
|
62609
|
+
showTools();
|
|
62610
|
+
return;
|
|
62611
|
+
}
|
|
62185
62612
|
if (command.name === "/copy") {
|
|
62186
62613
|
const target = newestBlock();
|
|
62187
62614
|
if (target === undefined || !copyBlock(target.id)) {
|
|
@@ -70868,7 +71295,7 @@ keryx workspace list-proposals [<workspace-id>]`);
|
|
|
70868
71295
|
}
|
|
70869
71296
|
function renderCatchUp(report, includeLifecycleFlags = true) {
|
|
70870
71297
|
const sections = [];
|
|
70871
|
-
sections.push(renderSection("Pending proposals", report.proposals, (item) => `- Accept, reject, or dismiss proposal ${item.proposalId} in workspace ${item.workspaceId}? ` + `Recommendation: ${item.fresh ? "evidence is fresh \u2014 review now (`keryx workspace review " + item.workspaceId + " " + item.proposalId + " --decision <accepted|rejected|dismissed>`)" : "evidence has drifted since this proposal was created \u2014 treat as stale, re-run wrap-up before deciding"}.`));
|
|
71298
|
+
sections.push(renderSection("Pending proposals", report.proposals, (item) => `- Accept, reject, or dismiss ${item.kind} proposal ${item.proposalId} in workspace ${item.workspaceId}` + `${item.note !== undefined ? `: "${item.note}"` : ""}? ` + `Recommendation: ${item.fresh ? "evidence is fresh \u2014 review now (`keryx workspace review " + item.workspaceId + " " + item.proposalId + " --decision <accepted|rejected|dismissed>`)" : "evidence has drifted since this proposal was created \u2014 treat as stale, re-run wrap-up before deciding"}.`));
|
|
70872
71299
|
sections.push(renderSection("Blocked sessions (stopped unattended)", report.blocked, (item) => `- Session ${item.sessionId} stopped unattended (${item.terminalState.reason}) at ${item.terminalState.occurredAt}. Resume it, or archive and move on? ` + `Recommendation: \`keryx shell -r ${item.sessionId}\` to resume and unblock it.`));
|
|
70873
71300
|
sections.push(renderSection("Unbound candidates (wrap-up ran, no workspace bound)", report.unboundCandidates, (item) => `- Session ${item.sessionId} produced untriaged seeds with no workspace bound (${item.summary}). Bind to a workspace and propose, or discard? ` + `Recommendation: pick a workspace, then \`keryx workspace propose <workspace-id> --kind <kind> --session ${item.sessionId}\` (evidence: ${item.evidencePath}).`));
|
|
70874
71301
|
sections.push(renderSection("Unknown (no resolution recorded)", report.unknown, (item) => `- Session ${item.sessionId} was last seen ${item.lastSeenAt} with no proposal, terminal state, or unbound-candidate artifact recorded. Investigate, or ignore? ` + `Recommendation: \`keryx sessions list\` / \`keryx shell -r ${item.sessionId}\` to see what happened.`));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mrciphersmith/keryx",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.52",
|
|
4
4
|
"description": "Version-controlled project context for AI coding agents: code graph, architecture wiki, project memory, relevant tests, quality signals, and task flows.",
|
|
5
5
|
"private": false,
|
|
6
6
|
"publishConfig": {
|