@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.
Files changed (2) hide show
  1. package/dist/tui.js +46 -0
  2. 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.1",
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.1",
47
- "@hmharness/evolution": "0.6.1",
48
- "@hmharness/domain-harmony": "0.6.1",
49
- "@hmharness/domain-ops": "0.6.1",
50
- "@hmharness/agent": "0.6.1",
51
- "@hmharness/web": "0.6.1"
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
  }