@crouton-kit/humanloop 0.3.12 → 0.3.13

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/cli.js +35 -13
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -558,19 +558,20 @@ function parseValidationErrors(e) {
558
558
  const reviewCmd = program.command('review').description('Markdown document review with anchored comments.');
559
559
  reviewCmd
560
560
  .command('open')
561
- .description('Kickoff: spawn the read-only editor review and return immediately.\n' +
561
+ .description('Open a read-only editor review and BLOCK until the human submits.\n' +
562
562
  '\n' +
563
563
  'stdin { file: string (required, .md), output?: string|null,\n' +
564
564
  ' editor?: string|null, tmux?: bool=true }\n' +
565
- 'stdout { job_id: string, output: string (absolute), follow_up: string }\n' +
565
+ 'stdout { job_id: string, output: string (absolute),\n' +
566
+ ' status: "done"|"failed"|"canceled", result?: FeedbackResult }\n' +
566
567
  '\n' +
567
- 'Effects: spawns nvim/vim read-only DETACHED in a tmux pane when tmux=true\n' +
568
- ' and $TMUX set; returns before the human starts. Writes\n' +
568
+ 'Effects: spawns nvim/vim read-only in a tmux pane when tmux=true and $TMUX\n' +
569
+ ' set, then blocks until the human finishes and submits. Writes\n' +
569
570
  ' <dir>/review.vim, <dir>/feedback.json (on finish), <dir>/job.log.\n' +
570
571
  ' autosaves feedback JSON; the open pane live-reloads the source on\n' +
571
572
  ' disk edits. The review is open-ended (a human may take many\n' +
572
- ' minutes) — collect via `hl job result` with wait:true, run\n' +
573
- ' backgrounded so the call does not block on the human.\n')
573
+ ' minutes) — if you want to keep working, run this BACKGROUNDED; your\n' +
574
+ ' harness notifies you when it returns with the result.\n')
574
575
  .helpOption('-h, --help', 'Show help')
575
576
  .action(async () => {
576
577
  const input = parseStdinJson();
@@ -613,12 +614,32 @@ reviewCmd
613
614
  appendJobLog(jobDir, { level: 'error', event: 'job_failed', message: `tmux spawn failed: ${msg}` });
614
615
  emitError({ error: 'internal', message: `tmux spawn failed: ${msg}`, next: 'Check that $TMUX is set. Or pass tmux:false.' });
615
616
  }
616
- process.stdout.write(JSON.stringify({
617
- job_id: jobId,
618
- output,
619
- follow_up: `Call hl job result with stdin {"job_id":"${jobId}","wait":true} to block until the human finishes the review. They may take many minutes — run this backgrounded; you will be notified on completion.`,
620
- }) + '\n');
621
- process.exit(0);
617
+ // BLOCK until the human submits (or the job ends). The review is
618
+ // open-ended — a human may take many minutes — so callers that want to
619
+ // keep working should background this invocation; their harness notifies
620
+ // them when it returns. Poll the shared job dir for feedback.json the
621
+ // same way `hl job result --wait` does.
622
+ await new Promise((resolvePromise) => {
623
+ const poll = setInterval(() => {
624
+ const fp = join(jobDir, 'feedback.json');
625
+ if (existsSync(fp)) {
626
+ const result = tryParseJson(readFileSync(fp, 'utf8'));
627
+ if (result !== null) {
628
+ clearInterval(poll);
629
+ process.stdout.write(JSON.stringify({ job_id: jobId, output, status: 'done', result }) + '\n');
630
+ process.exit(0);
631
+ }
632
+ }
633
+ const state = detectJobState(jobDir);
634
+ if (state === 'failed' || state === 'canceled') {
635
+ clearInterval(poll);
636
+ process.stdout.write(JSON.stringify({ job_id: jobId, output, status: state }) + '\n');
637
+ process.exit(state === 'canceled' ? 0 : 1);
638
+ }
639
+ }, 200);
640
+ void resolvePromise;
641
+ });
642
+ return;
622
643
  }
623
644
  // In-process path: the detached child (this pane is its TTY), or a degraded
624
645
  // top-level call with no tmux. launchReview blocks until the editor exits.
@@ -634,7 +655,8 @@ reviewCmd
634
655
  process.stdout.write(JSON.stringify({
635
656
  job_id: jobId,
636
657
  output,
637
- follow_up: `Call hl job result with stdin {"job_id":"${jobId}","wait":true} to retrieve the feedback.`,
658
+ status: 'done',
659
+ result,
638
660
  ...(input.dir ? {} : { _note: 'No tmux: launchReview blocked synchronously. Result is already available.' }),
639
661
  }) + '\n');
640
662
  process.exit(0);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crouton-kit/humanloop",
3
- "version": "0.3.12",
3
+ "version": "0.3.13",
4
4
  "description": "Human-in-the-loop decision TUI — agents write questions, humans answer them",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",