@multiclawcli/dashboard 0.7.0 → 0.8.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 +50 -6
  2. package/package.json +2 -2
package/dist/tui.js CHANGED
@@ -52,7 +52,7 @@ var COMMANDS = [
52
52
  { name: "clear", description: "Clear the focused agent's log", availability: "always" },
53
53
  {
54
54
  name: "history",
55
- description: "Browse finished turns",
55
+ description: "Browse finished turns, or continue one",
56
56
  availability: "always"
57
57
  },
58
58
  {
@@ -1484,7 +1484,7 @@ function HistoryOverlay({
1484
1484
  ] })
1485
1485
  ] }, turn.turn);
1486
1486
  }) }),
1487
- /* @__PURE__ */ jsx2(Box2, { marginTop: 1, children: /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: `\u2191\u2193 select \xB7 enter open \xB7 esc close${range}` }) })
1487
+ /* @__PURE__ */ jsx2(Box2, { marginTop: 1, children: /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: `\u2191\u2193 select \xB7 enter open \xB7 c continue \xB7 esc close${range}` }) })
1488
1488
  ] });
1489
1489
  }
1490
1490
 
@@ -2158,6 +2158,20 @@ function pickTurn(state, raw, whenEmpty) {
2158
2158
  if (!target.record.requirement) return { error: `turn ${target.record.turn} has no requirement` };
2159
2159
  return { record: target.record, requirement: target.record.requirement };
2160
2160
  }
2161
+ function turnSessions(turn) {
2162
+ const sessions = {};
2163
+ for (const agent of Object.values(turn.agents)) {
2164
+ if (agent.sessionId) sessions[agent.id] = agent.sessionId;
2165
+ }
2166
+ return sessions;
2167
+ }
2168
+ function continuationResume(continuation, live) {
2169
+ if (!continuation) return void 0;
2170
+ const sessions = Object.fromEntries(
2171
+ Object.entries(continuation.sessions).filter(([id]) => !live?.has(id))
2172
+ );
2173
+ return Object.keys(sessions).length > 0 ? { sessions } : void 0;
2174
+ }
2161
2175
  function StatusLine({
2162
2176
  state,
2163
2177
  running,
@@ -2244,6 +2258,7 @@ function App({ config, onTurnStart, sessions: providedSessions, onCleanupReady }
2244
2258
  const abortRef = useRef(null);
2245
2259
  const sessionsRef = useRef(null);
2246
2260
  if (!sessionsRef.current) sessionsRef.current = providedSessions ?? new AgentSessionManager();
2261
+ const continuationRef = useRef(null);
2247
2262
  const activeTurnRef = useRef(null);
2248
2263
  const reporterErrorRef = useRef(null);
2249
2264
  const closingRef = useRef(false);
@@ -2381,6 +2396,9 @@ function App({ config, onTurnStart, sessions: providedSessions, onCleanupReady }
2381
2396
  if (closingRef.current || busyRef.current) return;
2382
2397
  busyRef.current = true;
2383
2398
  setRunning(true);
2399
+ const continuation = opts?.newTask ? null : continuationRef.current;
2400
+ continuationRef.current = null;
2401
+ const resume = opts?.resume ?? continuationResume(continuation, sessionsRef.current);
2384
2402
  if (opts?.newTask) {
2385
2403
  try {
2386
2404
  await sessionsRef.current?.reset();
@@ -2430,8 +2448,9 @@ function App({ config, onTurnStart, sessions: providedSessions, onCleanupReady }
2430
2448
  logDir,
2431
2449
  permissions: !config.permissions || config.permissions.mode === "ask" ? { mode: "ask", onRequest: requestPermission } : config.permissions,
2432
2450
  questions: config.questions?.onRequest ? config.questions : { onRequest: requestQuestion },
2433
- // Only a retry carries this; a normal turn lets the leader route.
2434
- ...opts?.resume ? { resume: opts.resume } : {}
2451
+ // A retry names the agents to redo; a continued conversation carries only
2452
+ // sessions and still lets the leader route. Both arrive here.
2453
+ ...resume ? { resume } : {}
2435
2454
  };
2436
2455
  const controller = new AbortController();
2437
2456
  abortRef.current = controller;
@@ -3026,6 +3045,21 @@ function App({ config, onTurnStart, sessions: providedSessions, onCleanupReady }
3026
3045
  setHistoryOpen(false);
3027
3046
  return;
3028
3047
  }
3048
+ if (char === "c") {
3049
+ const target = historyTurns[historyIndex];
3050
+ const sessions = turnSessions(target);
3051
+ const count = Object.keys(sessions).length;
3052
+ if (count === 0) {
3053
+ setNotice(`turn ${target.turn} has no agent sessions to continue`);
3054
+ return;
3055
+ }
3056
+ continuationRef.current = { turn: target.turn, sessions };
3057
+ setHistoryOpen(false);
3058
+ setNotice(
3059
+ `continuing turn ${target.turn} \u2014 ${count} ${count === 1 ? "session" : "sessions"} \xB7 type your next instruction`
3060
+ );
3061
+ return;
3062
+ }
3029
3063
  return;
3030
3064
  }
3031
3065
  if (key.ctrl && char === "d") {
@@ -3046,11 +3080,21 @@ function App({ config, onTurnStart, sessions: providedSessions, onCleanupReady }
3046
3080
  return;
3047
3081
  }
3048
3082
  const formFront = front?.kind === "question" && !isCommandLine(line.text) ? front : void 0;
3049
- if (key.tab && formFront === void 0) {
3083
+ if (key.tab && formFront === void 0 && !paletteOpen) {
3050
3084
  dispatch({ type: "focus:cycle", delta: key.shift ? -1 : 1 });
3051
3085
  return;
3052
3086
  }
3053
3087
  if (paletteOpen) {
3088
+ if (key.tab) {
3089
+ if (arg) {
3090
+ const completed = `/${arg.command.name} ${allRows[selected].key} `;
3091
+ setLine({ text: completed, cursor: completed.length });
3092
+ } else {
3093
+ const completed = `/${matches[selected].name} `;
3094
+ setLine({ text: completed, cursor: completed.length });
3095
+ }
3096
+ return;
3097
+ }
3054
3098
  if (key.upArrow) {
3055
3099
  setMenuCursor({ query: paletteKey, index: (menuIndex - 1 + paletteTotal) % paletteTotal });
3056
3100
  return;
@@ -3264,7 +3308,7 @@ function App({ config, onTurnStart, sessions: providedSessions, onCleanupReady }
3264
3308
  const handlerRef = useRef(handleKey);
3265
3309
  handlerRef.current = handleKey;
3266
3310
  useInput((char, key) => handlerRef.current(char, key));
3267
- const keys = helpOpen ? "esc close" : historyOpen ? "\u2191\u2193 select \xB7 enter open \xB7 esc close" : argOpen ? `\u2191\u2193 select \xB7 enter ${arg?.command.name} \xB7 esc close` : menuOpen ? "\u2191\u2193 select \xB7 enter run \xB7 esc close" : running ? interactions.length > 0 ? layout.interactionRows === 0 ? (
3311
+ const keys = helpOpen ? "esc close" : historyOpen ? "\u2191\u2193 select \xB7 enter open \xB7 esc close" : argOpen ? `\u2191\u2193 select \xB7 tab complete \xB7 enter ${arg?.command.name} \xB7 esc close` : menuOpen ? "\u2191\u2193 select \xB7 tab complete \xB7 enter run \xB7 esc close" : running ? interactions.length > 0 ? layout.interactionRows === 0 ? (
3268
3312
  // Too short to dock the bar, so the commands are the only way in.
3269
3313
  "decide with /approve 1 \xB7 /deny \xB7 /respond"
3270
3314
  ) : interactions[0].kind === "question" ? "tab field \xB7 \u2191\u2193 pick \xB7 enter next \xB7 /dismiss" : menu.released ? "/approve 1 and /deny still reach it" : "\u2191\u2193 or 1-9 choose \xB7 enter confirm \xB7 esc to type" : "enter queues \xB7 ctrl+c cancel" : state.view ? "esc live \xB7 tab agent \xB7 ? help" : state.reply ? "enter sends \xB7 / commands \xB7 ? help" : "tab switch \xB7 / commands \xB7 ? help";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@multiclawcli/dashboard",
3
- "version": "0.7.0",
3
+ "version": "0.8.1",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  "./tui": {
@@ -25,7 +25,7 @@
25
25
  "access": "public"
26
26
  },
27
27
  "dependencies": {
28
- "@multiclawcli/core": "0.7.0",
28
+ "@multiclawcli/core": "0.8.1",
29
29
  "ink": "^8.0.0",
30
30
  "react": "^19.3.1",
31
31
  "string-width": "^8.3.0"