@hydra-acp/cli 0.1.43 → 0.1.44
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 +211 -1
- package/dist/index.js +42 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -4106,12 +4106,42 @@ function mapPromptReceived(u) {
|
|
|
4106
4106
|
}
|
|
4107
4107
|
return { kind: "user-text", text: promptText };
|
|
4108
4108
|
}
|
|
4109
|
+
function isExitPlanModeTool(name) {
|
|
4110
|
+
if (!name) {
|
|
4111
|
+
return false;
|
|
4112
|
+
}
|
|
4113
|
+
const normalised = name.toLowerCase().replace(/[_\s-]/g, "");
|
|
4114
|
+
return normalised === "exitplanmode";
|
|
4115
|
+
}
|
|
4116
|
+
function readExitPlanMarkdown(u) {
|
|
4117
|
+
const rawInput = u.rawInput;
|
|
4118
|
+
if (!rawInput || typeof rawInput !== "object" || Array.isArray(rawInput)) {
|
|
4119
|
+
return null;
|
|
4120
|
+
}
|
|
4121
|
+
const plan = rawInput.plan;
|
|
4122
|
+
if (typeof plan !== "string" || plan.length === 0) {
|
|
4123
|
+
return null;
|
|
4124
|
+
}
|
|
4125
|
+
return sanitizeWireText(plan);
|
|
4126
|
+
}
|
|
4109
4127
|
function mapToolCall(u) {
|
|
4110
4128
|
const toolCallId = readString(u, "toolCallId") ?? readString(u, "id");
|
|
4111
4129
|
if (!toolCallId) {
|
|
4112
4130
|
return null;
|
|
4113
4131
|
}
|
|
4114
4132
|
const rawTitle = readString(u, "title") ?? readString(u, "name") ?? readString(u, "label") ?? "tool call";
|
|
4133
|
+
const toolName = readString(u, "name") ?? readString(u, "title");
|
|
4134
|
+
if (isExitPlanModeTool(toolName)) {
|
|
4135
|
+
const plan = readExitPlanMarkdown(u);
|
|
4136
|
+
if (plan !== null) {
|
|
4137
|
+
const status2 = readString(u, "status");
|
|
4138
|
+
const event2 = { kind: "exit-plan-mode", toolCallId, plan };
|
|
4139
|
+
if (status2 !== void 0) {
|
|
4140
|
+
event2.status = status2;
|
|
4141
|
+
}
|
|
4142
|
+
return event2;
|
|
4143
|
+
}
|
|
4144
|
+
}
|
|
4115
4145
|
const title = sanitizeSingleLine(rawTitle);
|
|
4116
4146
|
const status = readString(u, "status");
|
|
4117
4147
|
const rawKind = readString(u, "kind");
|
|
@@ -4136,6 +4166,18 @@ function mapToolCallUpdate(u) {
|
|
|
4136
4166
|
if (!meaningful) {
|
|
4137
4167
|
return null;
|
|
4138
4168
|
}
|
|
4169
|
+
const toolName = readString(u, "name") ?? rawTitle;
|
|
4170
|
+
if (isExitPlanModeTool(toolName)) {
|
|
4171
|
+
const event2 = { kind: "exit-plan-mode", toolCallId };
|
|
4172
|
+
const plan = readExitPlanMarkdown(u);
|
|
4173
|
+
if (plan !== null) {
|
|
4174
|
+
event2.plan = plan;
|
|
4175
|
+
}
|
|
4176
|
+
if (status !== void 0) {
|
|
4177
|
+
event2.status = status;
|
|
4178
|
+
}
|
|
4179
|
+
return event2;
|
|
4180
|
+
}
|
|
4139
4181
|
const event = { kind: "tool-call-update", toolCallId };
|
|
4140
4182
|
if (title !== void 0) {
|
|
4141
4183
|
event.title = title;
|
|
@@ -6600,6 +6642,8 @@ function emergencyTerminalReset() {
|
|
|
6600
6642
|
// SGR mouse mode off
|
|
6601
6643
|
"\x1B[?1015l",
|
|
6602
6644
|
// urxvt mouse mode off
|
|
6645
|
+
"\x1B[=0;0w",
|
|
6646
|
+
// MasterBandit selective mouse reporting off
|
|
6603
6647
|
"\x1B[?2004l",
|
|
6604
6648
|
// bracketed paste off
|
|
6605
6649
|
"\x1B[>4;0m",
|
|
@@ -6846,6 +6890,13 @@ var init_screen = __esm({
|
|
|
6846
6890
|
onProcessExit = null;
|
|
6847
6891
|
onProcessSignal = null;
|
|
6848
6892
|
onProcessUncaught = null;
|
|
6893
|
+
// Selective Mouse Reporting (MasterBandit `CSI = w` / `CSI ? w`). Probed
|
|
6894
|
+
// on start() when mouseEnabled is false — terminals that support it let
|
|
6895
|
+
// us receive wheel-up/down without claiming the mouse for clicks (so the
|
|
6896
|
+
// host terminal still does native text selection on click+drag).
|
|
6897
|
+
selectiveMouseSupported = false;
|
|
6898
|
+
selectiveMouseProbing = false;
|
|
6899
|
+
selectiveMouseProbeTimer = null;
|
|
6849
6900
|
// Last OSC 9;4 state we wrote (3 = indeterminate, 0 = remove). Used to
|
|
6850
6901
|
// suppress redundant writes when setBanner runs but `status` didn't
|
|
6851
6902
|
// actually change, and to re-emit on start() if a picker round-trip
|
|
@@ -6904,6 +6955,7 @@ var init_screen = __esm({
|
|
|
6904
6955
|
}
|
|
6905
6956
|
this.term.on("resize", this.resizeHandler);
|
|
6906
6957
|
this.installBracketedPaste();
|
|
6958
|
+
this.installSelectiveMouseReporting();
|
|
6907
6959
|
this.installEmergencyCleanup();
|
|
6908
6960
|
this.lastProgressState = 0;
|
|
6909
6961
|
this.writeProgressIndicator(this.banner.status === "busy" ? 3 : 0);
|
|
@@ -6930,6 +6982,7 @@ var init_screen = __esm({
|
|
|
6930
6982
|
clearTimeout(this.throttledRepaintTimer);
|
|
6931
6983
|
this.throttledRepaintTimer = null;
|
|
6932
6984
|
}
|
|
6985
|
+
this.uninstallSelectiveMouseReporting();
|
|
6933
6986
|
this.uninstallBracketedPaste();
|
|
6934
6987
|
this.uninstallEmergencyCleanup();
|
|
6935
6988
|
this.term.off("key", this.keyHandler);
|
|
@@ -6983,6 +7036,34 @@ var init_screen = __esm({
|
|
|
6983
7036
|
this.pasteActive = false;
|
|
6984
7037
|
this.pasteBuffer = "";
|
|
6985
7038
|
}
|
|
7039
|
+
// Probe for MasterBandit's Selective Mouse Reporting protocol. Sent
|
|
7040
|
+
// unconditionally on terminals that don't recognise it (silently
|
|
7041
|
+
// ignored). A supporting terminal replies with `\x1b[?<b>;<e> w` —
|
|
7042
|
+
// matched in handleRawStdin, which then enables wheel-only reporting.
|
|
7043
|
+
// Skipped when mouseEnabled is true: full mouse capture is already on
|
|
7044
|
+
// via terminal-kit and selective would just be dormant per spec.
|
|
7045
|
+
installSelectiveMouseReporting() {
|
|
7046
|
+
if (this.mouseEnabled || this.selectiveMouseProbing || this.selectiveMouseSupported) {
|
|
7047
|
+
return;
|
|
7048
|
+
}
|
|
7049
|
+
this.selectiveMouseProbing = true;
|
|
7050
|
+
process.stdout.write("\x1B[?w");
|
|
7051
|
+
this.selectiveMouseProbeTimer = setTimeout(() => {
|
|
7052
|
+
this.selectiveMouseProbing = false;
|
|
7053
|
+
this.selectiveMouseProbeTimer = null;
|
|
7054
|
+
}, 250);
|
|
7055
|
+
}
|
|
7056
|
+
uninstallSelectiveMouseReporting() {
|
|
7057
|
+
if (this.selectiveMouseProbeTimer) {
|
|
7058
|
+
clearTimeout(this.selectiveMouseProbeTimer);
|
|
7059
|
+
this.selectiveMouseProbeTimer = null;
|
|
7060
|
+
}
|
|
7061
|
+
this.selectiveMouseProbing = false;
|
|
7062
|
+
if (this.selectiveMouseSupported) {
|
|
7063
|
+
process.stdout.write("\x1B[=0;0w");
|
|
7064
|
+
this.selectiveMouseSupported = false;
|
|
7065
|
+
}
|
|
7066
|
+
}
|
|
6986
7067
|
installEmergencyCleanup() {
|
|
6987
7068
|
if (this.emergencyCleanupInstalled) {
|
|
6988
7069
|
return;
|
|
@@ -7025,8 +7106,57 @@ uncaught: ${err.stack ?? err.message}
|
|
|
7025
7106
|
this.onProcessUncaught = null;
|
|
7026
7107
|
}
|
|
7027
7108
|
}
|
|
7109
|
+
// Strip Selective Mouse Reporting sequences from a stdin chunk and
|
|
7110
|
+
// dispatch them. Returns the chunk with recognised sequences removed
|
|
7111
|
+
// so the remaining text can flow through the existing key/paste
|
|
7112
|
+
// pipeline. Matches:
|
|
7113
|
+
// - `\x1b[?<b>;<e> w` probe reply (any digits, mandatory ' w' suffix)
|
|
7114
|
+
// - `\x1b[<64;<col>;<row>M` wheel-up press
|
|
7115
|
+
// - `\x1b[<65;<col>;<row>M` wheel-down press
|
|
7116
|
+
consumeSelectiveMouseSequences(text) {
|
|
7117
|
+
if (!text.includes("\x1B[")) {
|
|
7118
|
+
return text;
|
|
7119
|
+
}
|
|
7120
|
+
if (this.selectiveMouseProbing) {
|
|
7121
|
+
const probeRe = /\x1b\[\?(\d+);(\d+) w/;
|
|
7122
|
+
const m2 = probeRe.exec(text);
|
|
7123
|
+
if (m2) {
|
|
7124
|
+
this.selectiveMouseProbing = false;
|
|
7125
|
+
if (this.selectiveMouseProbeTimer) {
|
|
7126
|
+
clearTimeout(this.selectiveMouseProbeTimer);
|
|
7127
|
+
this.selectiveMouseProbeTimer = null;
|
|
7128
|
+
}
|
|
7129
|
+
this.selectiveMouseSupported = true;
|
|
7130
|
+
process.stdout.write("\x1B[=24;1w");
|
|
7131
|
+
text = text.slice(0, m2.index) + text.slice(m2.index + m2[0].length);
|
|
7132
|
+
}
|
|
7133
|
+
}
|
|
7134
|
+
if (!this.selectiveMouseSupported) {
|
|
7135
|
+
return text;
|
|
7136
|
+
}
|
|
7137
|
+
const wheelRe = /\x1b\[<(64|65);\d+;\d+M/g;
|
|
7138
|
+
let out = "";
|
|
7139
|
+
let lastEnd = 0;
|
|
7140
|
+
let m;
|
|
7141
|
+
while ((m = wheelRe.exec(text)) !== null) {
|
|
7142
|
+
out += text.slice(lastEnd, m.index);
|
|
7143
|
+
const code = m[1];
|
|
7144
|
+
if (code === "64") {
|
|
7145
|
+
this.scrollBy(3);
|
|
7146
|
+
} else {
|
|
7147
|
+
this.scrollBy(-3);
|
|
7148
|
+
}
|
|
7149
|
+
lastEnd = m.index + m[0].length;
|
|
7150
|
+
}
|
|
7151
|
+
out += text.slice(lastEnd);
|
|
7152
|
+
return out;
|
|
7153
|
+
}
|
|
7028
7154
|
handleRawStdin(chunk) {
|
|
7029
|
-
|
|
7155
|
+
let text = chunk.toString("binary");
|
|
7156
|
+
text = this.consumeSelectiveMouseSequences(text);
|
|
7157
|
+
if (text.length === 0) {
|
|
7158
|
+
return;
|
|
7159
|
+
}
|
|
7030
7160
|
if (this.pasteActive) {
|
|
7031
7161
|
this.handleRawStdinSegment(text);
|
|
7032
7162
|
return;
|
|
@@ -10783,6 +10913,8 @@ function formatEvent(event) {
|
|
|
10783
10913
|
case "tool-call":
|
|
10784
10914
|
case "tool-call-update":
|
|
10785
10915
|
return [];
|
|
10916
|
+
case "exit-plan-mode":
|
|
10917
|
+
return [];
|
|
10786
10918
|
case "plan":
|
|
10787
10919
|
return formatPlan(event);
|
|
10788
10920
|
case "mode-changed":
|
|
@@ -11105,6 +11237,62 @@ function toolIconStyle(status) {
|
|
|
11105
11237
|
return "tool-status-running";
|
|
11106
11238
|
}
|
|
11107
11239
|
}
|
|
11240
|
+
function formatExitPlanMode(state) {
|
|
11241
|
+
const lines = [
|
|
11242
|
+
{
|
|
11243
|
+
prefix: "\u25A3 ",
|
|
11244
|
+
prefixStyle: "plan",
|
|
11245
|
+
body: "Plan",
|
|
11246
|
+
bodyStyle: "plan"
|
|
11247
|
+
}
|
|
11248
|
+
];
|
|
11249
|
+
lines.push(...parseAgentMarkdown(state.plan));
|
|
11250
|
+
const status = state.status;
|
|
11251
|
+
if (status !== void 0) {
|
|
11252
|
+
const footer = exitPlanFooter(status);
|
|
11253
|
+
if (footer !== null) {
|
|
11254
|
+
lines.push(footer);
|
|
11255
|
+
}
|
|
11256
|
+
}
|
|
11257
|
+
return lines;
|
|
11258
|
+
}
|
|
11259
|
+
function exitPlanFooter(status) {
|
|
11260
|
+
switch (status) {
|
|
11261
|
+
case "completed":
|
|
11262
|
+
case "succeeded":
|
|
11263
|
+
case "ok":
|
|
11264
|
+
return {
|
|
11265
|
+
prefix: " ",
|
|
11266
|
+
body: "\u2713 Approved",
|
|
11267
|
+
bodyStyle: "tool-status-ok"
|
|
11268
|
+
};
|
|
11269
|
+
case "failed":
|
|
11270
|
+
case "error":
|
|
11271
|
+
case "rejected":
|
|
11272
|
+
return {
|
|
11273
|
+
prefix: " ",
|
|
11274
|
+
body: "\u2717 Rejected",
|
|
11275
|
+
bodyStyle: "tool-status-fail"
|
|
11276
|
+
};
|
|
11277
|
+
case "cancelled":
|
|
11278
|
+
return {
|
|
11279
|
+
prefix: " ",
|
|
11280
|
+
body: "\u229D Cancelled",
|
|
11281
|
+
bodyStyle: "tool-status-cancelled"
|
|
11282
|
+
};
|
|
11283
|
+
case "pending":
|
|
11284
|
+
case "in_progress":
|
|
11285
|
+
case "running":
|
|
11286
|
+
case "updated":
|
|
11287
|
+
return {
|
|
11288
|
+
prefix: " ",
|
|
11289
|
+
body: "awaiting approval\u2026",
|
|
11290
|
+
bodyStyle: "dim"
|
|
11291
|
+
};
|
|
11292
|
+
default:
|
|
11293
|
+
return null;
|
|
11294
|
+
}
|
|
11295
|
+
}
|
|
11108
11296
|
function formatPlan(event) {
|
|
11109
11297
|
const stopped = event.stopped === true;
|
|
11110
11298
|
const amended = event.amended === true;
|
|
@@ -12664,6 +12852,7 @@ async function runSession(term, config, target, opts, exitHint, viewPrefs) {
|
|
|
12664
12852
|
return true;
|
|
12665
12853
|
case "/clear":
|
|
12666
12854
|
toolStates.clear();
|
|
12855
|
+
exitPlanStates.clear();
|
|
12667
12856
|
toolCallOrder.length = 0;
|
|
12668
12857
|
toolsBlockStartedAt = null;
|
|
12669
12858
|
toolsBlockEndedAt = null;
|
|
@@ -12878,6 +13067,7 @@ async function runSession(term, config, target, opts, exitHint, viewPrefs) {
|
|
|
12878
13067
|
}
|
|
12879
13068
|
};
|
|
12880
13069
|
const toolStates = /* @__PURE__ */ new Map();
|
|
13070
|
+
const exitPlanStates = /* @__PURE__ */ new Map();
|
|
12881
13071
|
const toolCallOrder = [];
|
|
12882
13072
|
let toolsExpanded = false;
|
|
12883
13073
|
let toolsBlockStartedAt = null;
|
|
@@ -13067,6 +13257,7 @@ async function runSession(term, config, target, opts, exitHint, viewPrefs) {
|
|
|
13067
13257
|
screen.clearKey("plan");
|
|
13068
13258
|
lastPlanEvent = null;
|
|
13069
13259
|
toolStates.clear();
|
|
13260
|
+
exitPlanStates.clear();
|
|
13070
13261
|
toolCallOrder.length = 0;
|
|
13071
13262
|
toolsExpanded = false;
|
|
13072
13263
|
toolsBlockEndedAt = null;
|
|
@@ -13083,6 +13274,23 @@ async function runSession(term, config, target, opts, exitHint, viewPrefs) {
|
|
|
13083
13274
|
screen.appendStreaming(event.text, "\xB7 ", "thought", "thought");
|
|
13084
13275
|
return;
|
|
13085
13276
|
}
|
|
13277
|
+
if (event.kind === "exit-plan-mode") {
|
|
13278
|
+
closeAgentText();
|
|
13279
|
+
const existing = exitPlanStates.get(event.toolCallId);
|
|
13280
|
+
const merged = {
|
|
13281
|
+
plan: event.plan ?? existing?.plan ?? "",
|
|
13282
|
+
status: event.status ?? existing?.status
|
|
13283
|
+
};
|
|
13284
|
+
exitPlanStates.set(event.toolCallId, merged);
|
|
13285
|
+
if (merged.plan.length === 0) {
|
|
13286
|
+
return;
|
|
13287
|
+
}
|
|
13288
|
+
const lines = formatExitPlanMode(merged);
|
|
13289
|
+
if (lines.length > 0) {
|
|
13290
|
+
screen.upsertLines(event.toolCallId, lines);
|
|
13291
|
+
}
|
|
13292
|
+
return;
|
|
13293
|
+
}
|
|
13086
13294
|
if (event.kind === "tool-call") {
|
|
13087
13295
|
closeAgentText();
|
|
13088
13296
|
recordToolCall(event.toolCallId, event.title, event.status, void 0);
|
|
@@ -13154,6 +13362,7 @@ async function runSession(term, config, target, opts, exitHint, viewPrefs) {
|
|
|
13154
13362
|
]);
|
|
13155
13363
|
}
|
|
13156
13364
|
toolStates.clear();
|
|
13365
|
+
exitPlanStates.clear();
|
|
13157
13366
|
toolCallOrder.length = 0;
|
|
13158
13367
|
toolsBlockStartedAt = null;
|
|
13159
13368
|
toolsBlockEndedAt = null;
|
|
@@ -13210,6 +13419,7 @@ async function runSession(term, config, target, opts, exitHint, viewPrefs) {
|
|
|
13210
13419
|
renderToolsBlock();
|
|
13211
13420
|
screen.clearKey("tools");
|
|
13212
13421
|
toolStates.clear();
|
|
13422
|
+
exitPlanStates.clear();
|
|
13213
13423
|
toolCallOrder.length = 0;
|
|
13214
13424
|
toolsBlockStartedAt = null;
|
|
13215
13425
|
toolsBlockEndedAt = null;
|
package/dist/index.js
CHANGED
|
@@ -6965,12 +6965,42 @@ function mapPromptReceived(u) {
|
|
|
6965
6965
|
}
|
|
6966
6966
|
return { kind: "user-text", text: promptText };
|
|
6967
6967
|
}
|
|
6968
|
+
function isExitPlanModeTool(name) {
|
|
6969
|
+
if (!name) {
|
|
6970
|
+
return false;
|
|
6971
|
+
}
|
|
6972
|
+
const normalised = name.toLowerCase().replace(/[_\s-]/g, "");
|
|
6973
|
+
return normalised === "exitplanmode";
|
|
6974
|
+
}
|
|
6975
|
+
function readExitPlanMarkdown(u) {
|
|
6976
|
+
const rawInput = u.rawInput;
|
|
6977
|
+
if (!rawInput || typeof rawInput !== "object" || Array.isArray(rawInput)) {
|
|
6978
|
+
return null;
|
|
6979
|
+
}
|
|
6980
|
+
const plan = rawInput.plan;
|
|
6981
|
+
if (typeof plan !== "string" || plan.length === 0) {
|
|
6982
|
+
return null;
|
|
6983
|
+
}
|
|
6984
|
+
return sanitizeWireText(plan);
|
|
6985
|
+
}
|
|
6968
6986
|
function mapToolCall(u) {
|
|
6969
6987
|
const toolCallId = readString(u, "toolCallId") ?? readString(u, "id");
|
|
6970
6988
|
if (!toolCallId) {
|
|
6971
6989
|
return null;
|
|
6972
6990
|
}
|
|
6973
6991
|
const rawTitle = readString(u, "title") ?? readString(u, "name") ?? readString(u, "label") ?? "tool call";
|
|
6992
|
+
const toolName = readString(u, "name") ?? readString(u, "title");
|
|
6993
|
+
if (isExitPlanModeTool(toolName)) {
|
|
6994
|
+
const plan = readExitPlanMarkdown(u);
|
|
6995
|
+
if (plan !== null) {
|
|
6996
|
+
const status2 = readString(u, "status");
|
|
6997
|
+
const event2 = { kind: "exit-plan-mode", toolCallId, plan };
|
|
6998
|
+
if (status2 !== void 0) {
|
|
6999
|
+
event2.status = status2;
|
|
7000
|
+
}
|
|
7001
|
+
return event2;
|
|
7002
|
+
}
|
|
7003
|
+
}
|
|
6974
7004
|
const title = sanitizeSingleLine(rawTitle);
|
|
6975
7005
|
const status = readString(u, "status");
|
|
6976
7006
|
const rawKind = readString(u, "kind");
|
|
@@ -6995,6 +7025,18 @@ function mapToolCallUpdate(u) {
|
|
|
6995
7025
|
if (!meaningful) {
|
|
6996
7026
|
return null;
|
|
6997
7027
|
}
|
|
7028
|
+
const toolName = readString(u, "name") ?? rawTitle;
|
|
7029
|
+
if (isExitPlanModeTool(toolName)) {
|
|
7030
|
+
const event2 = { kind: "exit-plan-mode", toolCallId };
|
|
7031
|
+
const plan = readExitPlanMarkdown(u);
|
|
7032
|
+
if (plan !== null) {
|
|
7033
|
+
event2.plan = plan;
|
|
7034
|
+
}
|
|
7035
|
+
if (status !== void 0) {
|
|
7036
|
+
event2.status = status;
|
|
7037
|
+
}
|
|
7038
|
+
return event2;
|
|
7039
|
+
}
|
|
6998
7040
|
const event = { kind: "tool-call-update", toolCallId };
|
|
6999
7041
|
if (title !== void 0) {
|
|
7000
7042
|
event.title = title;
|