@crouton-kit/humanloop 0.4.8 → 0.4.9

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.
@@ -42,6 +42,7 @@ export declare class InboxController {
42
42
  private claim;
43
43
  private suspended;
44
44
  private submittingDir;
45
+ private cancelConfirmation;
45
46
  private stdinListener;
46
47
  private cols;
47
48
  private rows;
@@ -64,6 +65,7 @@ export declare class InboxController {
64
65
  resize(cols?: number, rows?: number): void;
65
66
  render(): string[];
66
67
  handleKey(input: string, key: Key): void;
68
+ private cancelFromInbox;
67
69
  activate(): void;
68
70
  /** Claim the review, hand the whole popup TTY to the native editor, then
69
71
  * converge to the on-disk outcome when it exits. Draft/final ownership stays
@@ -12,7 +12,7 @@ import { inboxLayout } from './layout.js';
12
12
  import { scanInbox } from './scan.js';
13
13
  import { inboxActivityPath, inboxRootsDirectory, inboxStateDirectory, listInboxRoots, registeredInboxRoot } from './registry.js';
14
14
  import { claimTicket, heartbeatClaim, releaseClaim } from './claim.js';
15
- import { completeDeck, readTicketResult, ticketRoot } from './tickets.js';
15
+ import { cancelTicket, completeDeck, readTicketResult, ticketRoot } from './tickets.js';
16
16
  import { clearProgress, deckPath, progressPath, readJson, responsePath, reviewPath, runHandler, visualsDir } from './convention.js';
17
17
  import { DeckAdapter } from './deck-adapter.js';
18
18
  import { validateDeck } from './deck-schema.js';
@@ -48,6 +48,7 @@ export class InboxController {
48
48
  claim;
49
49
  suspended = false;
50
50
  submittingDir;
51
+ cancelConfirmation;
51
52
  stdinListener;
52
53
  cols;
53
54
  rows;
@@ -166,6 +167,29 @@ export class InboxController {
166
167
  this.repaint();
167
168
  return;
168
169
  }
170
+ if (this.cancelConfirmation !== undefined) {
171
+ if (input === 'y' || input === 'Y') {
172
+ const dir = this.cancelConfirmation.dir;
173
+ this.cancelConfirmation = undefined;
174
+ this.status = 'canceling…';
175
+ void this.cancelFromInbox(dir);
176
+ }
177
+ else if (input === 'n' || input === 'N' || key.escape) {
178
+ this.cancelConfirmation = undefined;
179
+ this.status = undefined;
180
+ }
181
+ this.repaint();
182
+ return;
183
+ }
184
+ if (input === 'x' || input === 'X') {
185
+ const selected = this.items[this.selectedIndex];
186
+ if (selected !== undefined) {
187
+ this.cancelConfirmation = { dir: selected.dir, title: selected.title };
188
+ this.status = undefined;
189
+ }
190
+ this.repaint();
191
+ return;
192
+ }
169
193
  if (key.escape || input === 'q') {
170
194
  this.close();
171
195
  return;
@@ -187,6 +211,21 @@ export class InboxController {
187
211
  this.activate();
188
212
  this.repaint();
189
213
  }
214
+ async cancelFromInbox(dir) {
215
+ this.submittingDir = dir;
216
+ try {
217
+ const result = await cancelTicket(dir, { reason: 'Canceled from the inbox.', actor: 'human' });
218
+ this.status = result.status === 'canceled' ? 'canceled' : 'ticket already resolved';
219
+ }
220
+ catch (error) {
221
+ this.status = error instanceof Error ? error.message : String(error);
222
+ }
223
+ finally {
224
+ this.submittingDir = undefined;
225
+ this.rescan();
226
+ this.repaint();
227
+ }
228
+ }
190
229
  activate() {
191
230
  const item = this.items[this.selectedIndex];
192
231
  if (item === undefined)
@@ -687,8 +726,8 @@ export class InboxController {
687
726
  return this.previewViewport(this.passiveDetailLines(width), width, rows);
688
727
  const focusHint = this.focusAvailable(selected.dir) ? ` ${DIM}g${RESET} chat` : '';
689
728
  const footer = selected.kind === 'deck'
690
- ? [` ${DIM}Enter${RESET} opens the full ticket ${DIM}u/d${RESET} scroll ${DIM}j/k${RESET} select`, ` ${DIM}Active ask:${RESET} c comment u/d scroll w browser${focusHint} ${DIM}q${RESET} close`]
691
- : [` ${DIM}Enter${RESET} opens the full review ${DIM}u/d${RESET} scroll ${DIM}j/k${RESET} select`, ` ${focusHint} ${DIM}q${RESET} close`];
729
+ ? [` ${DIM}Enter${RESET} opens the full ticket ${DIM}u/d${RESET} scroll ${DIM}j/k${RESET} select ${DIM}x${RESET} cancel`, ` ${DIM}Active ask:${RESET} c comment u/d scroll w browser${focusHint} ${DIM}q${RESET} close`]
730
+ : [` ${DIM}Enter${RESET} opens the full review ${DIM}u/d${RESET} scroll ${DIM}j/k${RESET} select ${DIM}x${RESET} cancel`, ` ${focusHint} ${DIM}q${RESET} close`];
692
731
  return [...this.previewViewport(this.passiveDetailLines(width), width, Math.max(0, rows - footer.length)), ...footer.map((line) => clipLine(line, width))];
693
732
  }
694
733
  focusAvailable(dir) {
@@ -791,12 +830,15 @@ export class InboxController {
791
830
  return out.map((line) => clipLine(line, width));
792
831
  }
793
832
  withStatus(lines) {
794
- if (this.status === undefined || this.rows < 1)
833
+ const status = this.cancelConfirmation === undefined
834
+ ? this.status
835
+ : `cancel “${this.cancelConfirmation.title}”? y yes · n/Esc no`;
836
+ if (status === undefined || this.rows < 1)
795
837
  return lines;
796
838
  const next = [...lines];
797
839
  while (next.length < this.rows)
798
840
  next.push('');
799
- next[this.rows - 1] = `${YELLOW}${this.status}${RESET}`;
841
+ next[this.rows - 1] = `${YELLOW}${status}${RESET}`;
800
842
  return next;
801
843
  }
802
844
  repaint(clear = false) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crouton-kit/humanloop",
3
- "version": "0.4.8",
3
+ "version": "0.4.9",
4
4
  "description": "Human-in-the-loop decision TUI — agents write questions, humans answer them",
5
5
  "engines": {
6
6
  "node": ">=22.19.0"