@hmharness/cli 0.6.0 → 0.6.1

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 +77 -52
  2. package/package.json +7 -7
package/dist/tui.js CHANGED
@@ -932,12 +932,88 @@ export async function tui(yes, noWeb = false) {
932
932
  void notifyUpdate(home, current, (latest) => rt.addText(`↑ ${t.updateHint(latest)}`, 'dim'));
933
933
  }
934
934
  let history = [];
935
+ // Task queue: new submissions during a running task are queued (not
936
+ // rejected, not run concurrently — sequential execution preserves history
937
+ // integrity). Slash commands still run immediately (they're quick).
938
+ const taskQueue = [];
939
+ let taskRunning = false;
935
940
  rt.onSubmit(() => {
936
941
  const line = rt.consumeInput().trim();
937
942
  if (!line)
938
943
  return;
939
- void handleLine(line);
944
+ if (line.startsWith('/')) {
945
+ void handleLine(line);
946
+ return;
947
+ }
948
+ if (taskRunning) {
949
+ taskQueue.push(line);
950
+ rt.addText(`📋 queued: "${line.slice(0, 60)}${line.length > 60 ? '…' : ''}" (${taskQueue.length} waiting)`, 'dim');
951
+ return;
952
+ }
953
+ void executeTaskQueue(line);
940
954
  });
955
+ async function executeTaskQueue(firstTask) {
956
+ taskRunning = true;
957
+ let task = firstTask;
958
+ while (task) {
959
+ await runSingleTask(task);
960
+ task = taskQueue.shift();
961
+ if (task)
962
+ rt.addText(`▶ next queued: "${task.slice(0, 60)}${task.length > 60 ? '…' : ''}"`, 'dim');
963
+ }
964
+ taskRunning = false;
965
+ }
966
+ async function runSingleTask(line) {
967
+ rt.addUser(line);
968
+ rt.setBusy(true, t.running);
969
+ let appender = null;
970
+ let kind = null;
971
+ try {
972
+ const result = await runAgentTask({
973
+ task: line,
974
+ registry: reg,
975
+ cfg,
976
+ yes: autoApprove,
977
+ resumeMessages: history,
978
+ approvalAsk: (name, args) => rt.requestApproval(name, args),
979
+ events: {
980
+ onLine: (l) => { if (kind === 'reasoning')
981
+ rt.foldThinking(); appender = null; kind = null; rt.addText(l, 'dim'); },
982
+ onDelta: (k, chunk) => {
983
+ if (k !== kind) {
984
+ if (kind === 'reasoning')
985
+ rt.foldThinking();
986
+ appender = rt.startStream(k === 'reasoning' ? 'think' : 'say');
987
+ kind = k;
988
+ }
989
+ appender?.(chunk);
990
+ },
991
+ onToolCall: (name, args) => {
992
+ if (kind === 'reasoning')
993
+ rt.foldThinking();
994
+ appender = null;
995
+ kind = null;
996
+ const brief = name === 'run_command' && typeof args.command === 'string'
997
+ ? args.command
998
+ : JSON.stringify(args);
999
+ rt.addText(`${YELLOW('●')} ${CYAN(name)} ${DIM(brief.replace(/\s+/g, ' ').slice(0, 90))}`);
1000
+ },
1001
+ onToolResult: (name, output, isError) => {
1002
+ const dot = isError ? RED('✗') : GREEN('•');
1003
+ const first = output.split('\n').find((l) => l.trim()) ?? '';
1004
+ rt.addText(` ${dot} ${DIM('⎿ ' + first.trim().slice(0, 100))}`);
1005
+ },
1006
+ },
1007
+ });
1008
+ rt.setBusy(false);
1009
+ rt.setStatus(`↑${result.usage.promptTokens} ↓${result.usage.completionTokens} tok · ${result.turns} turns · ${result.toolUses} tools`);
1010
+ history = [...history, { role: 'user', content: line }, ...result.messages.slice(history.length + 2)];
1011
+ }
1012
+ catch (err) {
1013
+ rt.setBusy(false);
1014
+ rt.addText(String(err), 'err');
1015
+ }
1016
+ }
941
1017
  async function handleLine(line) {
942
1018
  if (line === '/exit' || line === '/quit') {
943
1019
  rt.destroy();
@@ -1176,57 +1252,6 @@ export async function tui(yes, noWeb = false) {
1176
1252
  }
1177
1253
  return;
1178
1254
  }
1179
- rt.addUser(line);
1180
- rt.setBusy(true, t.running);
1181
- let appender = null;
1182
- let kind = null;
1183
- try {
1184
- const result = await runAgentTask({
1185
- task: line,
1186
- registry: reg,
1187
- cfg,
1188
- yes: autoApprove,
1189
- resumeMessages: history,
1190
- approvalAsk: (name, args) => rt.requestApproval(name, args),
1191
- events: {
1192
- onLine: (l) => { if (kind === 'reasoning')
1193
- rt.foldThinking(); appender = null; kind = null; rt.addText(l, 'dim'); },
1194
- onDelta: (k, chunk) => {
1195
- if (k !== kind) {
1196
- if (kind === 'reasoning')
1197
- rt.foldThinking(); // collapse before the next phase
1198
- appender = rt.startStream(k === 'reasoning' ? 'think' : 'say');
1199
- kind = k;
1200
- }
1201
- appender?.(chunk);
1202
- },
1203
- onToolCall: (name, args) => {
1204
- if (kind === 'reasoning')
1205
- rt.foldThinking();
1206
- appender = null;
1207
- kind = null;
1208
- // fold the args to their essence: for run_command the command
1209
- // string itself, otherwise a short JSON tail
1210
- const brief = name === 'run_command' && typeof args.command === 'string'
1211
- ? args.command
1212
- : JSON.stringify(args);
1213
- rt.addText(`${YELLOW('●')} ${CYAN(name)} ${DIM(brief.replace(/\s+/g, ' ').slice(0, 90))}`);
1214
- },
1215
- onToolResult: (name, output, isError) => {
1216
- const dot = isError ? RED('✗') : GREEN('•');
1217
- const first = output.split('\n').find((l) => l.trim()) ?? '';
1218
- rt.addText(` ${dot} ${DIM('⎿ ' + first.trim().slice(0, 100))}`);
1219
- },
1220
- },
1221
- });
1222
- rt.setBusy(false);
1223
- rt.setStatus(`↑${result.usage.promptTokens} ↓${result.usage.completionTokens} tok · ${result.turns} turns · ${result.toolUses} tools`);
1224
- history = [...history, { role: 'user', content: line }, ...result.messages.slice(history.length + 2)];
1225
- }
1226
- catch (err) {
1227
- rt.setBusy(false);
1228
- rt.addText(String(err), 'err');
1229
- }
1230
1255
  }
1231
1256
  await rt.waitExit();
1232
1257
  rt.destroy();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hmharness/cli",
3
- "version": "0.6.0",
3
+ "version": "0.6.1",
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.0",
47
- "@hmharness/evolution": "0.6.0",
48
- "@hmharness/domain-harmony": "0.6.0",
49
- "@hmharness/domain-ops": "0.6.0",
50
- "@hmharness/agent": "0.6.0",
51
- "@hmharness/web": "0.6.0"
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"
52
52
  }
53
53
  }