@hmharness/cli 0.6.1 → 0.6.3
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/tui.js +46 -0
- package/package.json +7 -7
package/dist/tui.js
CHANGED
|
@@ -935,8 +935,10 @@ export async function tui(yes, noWeb = false) {
|
|
|
935
935
|
// Task queue: new submissions during a running task are queued (not
|
|
936
936
|
// rejected, not run concurrently — sequential execution preserves history
|
|
937
937
|
// integrity). Slash commands still run immediately (they're quick).
|
|
938
|
+
// `!` prefix inserts at FRONT (urgent). Esc interrupts the running task.
|
|
938
939
|
const taskQueue = [];
|
|
939
940
|
let taskRunning = false;
|
|
941
|
+
let currentAbort = null;
|
|
940
942
|
rt.onSubmit(() => {
|
|
941
943
|
const line = rt.consumeInput().trim();
|
|
942
944
|
if (!line)
|
|
@@ -945,6 +947,20 @@ export async function tui(yes, noWeb = false) {
|
|
|
945
947
|
void handleLine(line);
|
|
946
948
|
return;
|
|
947
949
|
}
|
|
950
|
+
if (line.startsWith('!')) {
|
|
951
|
+
// urgent: strip the ! and insert at front of queue (or run immediately)
|
|
952
|
+
const urgent = line.slice(1).trim();
|
|
953
|
+
if (!urgent)
|
|
954
|
+
return;
|
|
955
|
+
if (taskRunning) {
|
|
956
|
+
taskQueue.unshift(urgent);
|
|
957
|
+
rt.addText(`⚡ inserted at front: "${urgent.slice(0, 60)}${urgent.length > 60 ? '…' : ''}" (runs next)`, 'dim');
|
|
958
|
+
currentAbort?.abort(); // interrupt current to run the urgent task
|
|
959
|
+
return;
|
|
960
|
+
}
|
|
961
|
+
void executeTaskQueue(urgent);
|
|
962
|
+
return;
|
|
963
|
+
}
|
|
948
964
|
if (taskRunning) {
|
|
949
965
|
taskQueue.push(line);
|
|
950
966
|
rt.addText(`📋 queued: "${line.slice(0, 60)}${line.length > 60 ? '…' : ''}" (${taskQueue.length} waiting)`, 'dim');
|
|
@@ -966,6 +982,7 @@ export async function tui(yes, noWeb = false) {
|
|
|
966
982
|
async function runSingleTask(line) {
|
|
967
983
|
rt.addUser(line);
|
|
968
984
|
rt.setBusy(true, t.running);
|
|
985
|
+
currentAbort = new AbortController();
|
|
969
986
|
let appender = null;
|
|
970
987
|
let kind = null;
|
|
971
988
|
try {
|
|
@@ -975,6 +992,7 @@ export async function tui(yes, noWeb = false) {
|
|
|
975
992
|
cfg,
|
|
976
993
|
yes: autoApprove,
|
|
977
994
|
resumeMessages: history,
|
|
995
|
+
signal: currentAbort.signal,
|
|
978
996
|
approvalAsk: (name, args) => rt.requestApproval(name, args),
|
|
979
997
|
events: {
|
|
980
998
|
onLine: (l) => { if (kind === 'reasoning')
|
|
@@ -1013,6 +1031,9 @@ export async function tui(yes, noWeb = false) {
|
|
|
1013
1031
|
rt.setBusy(false);
|
|
1014
1032
|
rt.addText(String(err), 'err');
|
|
1015
1033
|
}
|
|
1034
|
+
finally {
|
|
1035
|
+
currentAbort = null;
|
|
1036
|
+
}
|
|
1016
1037
|
}
|
|
1017
1038
|
async function handleLine(line) {
|
|
1018
1039
|
if (line === '/exit' || line === '/quit') {
|
|
@@ -1021,6 +1042,31 @@ export async function tui(yes, noWeb = false) {
|
|
|
1021
1042
|
c.close();
|
|
1022
1043
|
process.exit(0);
|
|
1023
1044
|
}
|
|
1045
|
+
if (line === '/queue' || line.startsWith('/queue ')) {
|
|
1046
|
+
const sub = line.slice(7).trim();
|
|
1047
|
+
if (sub === 'clear') {
|
|
1048
|
+
const n = taskQueue.length;
|
|
1049
|
+
taskQueue.length = 0;
|
|
1050
|
+
rt.addText(n > 0 ? 'cleared ' + n + ' queued task(s)' : 'queue was already empty', 'dim');
|
|
1051
|
+
return;
|
|
1052
|
+
}
|
|
1053
|
+
if (sub === 'skip' || sub === 'interrupt') {
|
|
1054
|
+
if (!taskRunning) {
|
|
1055
|
+
rt.addText('no task is running', 'dim');
|
|
1056
|
+
return;
|
|
1057
|
+
}
|
|
1058
|
+
currentAbort?.abort();
|
|
1059
|
+
rt.addText('interrupting current task (finishes in-flight tool calls)...', 'dim');
|
|
1060
|
+
return;
|
|
1061
|
+
}
|
|
1062
|
+
// bare /queue: show status
|
|
1063
|
+
const status = taskRunning ? 'running' : 'idle';
|
|
1064
|
+
const queueList = taskQueue.length > 0
|
|
1065
|
+
? taskQueue.map((task, i) => ' ' + (i + 1) + '. ' + task.slice(0, 70)).join('\n')
|
|
1066
|
+
: ' (empty)';
|
|
1067
|
+
rt.addText('queue: ' + status + ' | ' + taskQueue.length + ' waiting\n' + queueList + '\n\ncommands: /queue clear, /queue skip, !<task> to insert at front', 'dim');
|
|
1068
|
+
return;
|
|
1069
|
+
}
|
|
1024
1070
|
if (line === '?' || line === '/help') {
|
|
1025
1071
|
rt.addText(COMMANDS.map((c) => ' ' + c.name.padEnd(11) + ' ' + String(t[c.key])).join('\n'), 'dim');
|
|
1026
1072
|
return;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hmharness/cli",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.3",
|
|
4
4
|
"description": "hmharness command line: one-shot tasks, an interactive REPL, a fullscreen TUI, the web frontend, and direct tool invocation.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/main.js",
|
|
@@ -43,11 +43,11 @@
|
|
|
43
43
|
"build": "tsc -p tsconfig.build.json"
|
|
44
44
|
},
|
|
45
45
|
"dependencies": {
|
|
46
|
-
"@hmharness/kernel": "0.6.
|
|
47
|
-
"@hmharness/evolution": "0.6.
|
|
48
|
-
"@hmharness/domain-harmony": "0.6.
|
|
49
|
-
"@hmharness/domain-ops": "0.6.
|
|
50
|
-
"@hmharness/agent": "0.6.
|
|
51
|
-
"@hmharness/web": "0.6.
|
|
46
|
+
"@hmharness/kernel": "0.6.3",
|
|
47
|
+
"@hmharness/evolution": "0.6.3",
|
|
48
|
+
"@hmharness/domain-harmony": "0.6.3",
|
|
49
|
+
"@hmharness/domain-ops": "0.6.3",
|
|
50
|
+
"@hmharness/agent": "0.6.3",
|
|
51
|
+
"@hmharness/web": "0.6.3"
|
|
52
52
|
}
|
|
53
53
|
}
|