llm-orchestrator 1.2.7 → 1.2.8

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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "llm-orchestrator",
3
3
  "description": "Write /task once — it plans the work, shards it across parallel subagents, gates every phase and verifies before claiming done. Claude Code, Codex, OpenCode, Kilo.",
4
- "version": "1.2.7",
4
+ "version": "1.2.8",
5
5
  "author": {
6
6
  "name": "Bogdan-Gabriel Torcescu",
7
7
  "url": "https://www.linkedin.com/in/bogdantorcescu/"
package/README.md CHANGED
@@ -365,8 +365,8 @@ more instructions:
365
365
  it, runs opened without a PlanShard count, runs that planned several shards but started no
366
366
  subagents, and runs still open.
367
367
  - Trivial is the narrow exception — a one-line change such as a typo or a version bump. A run
368
- declared trivial that then edits a second file, touches tests, or keeps working past eight calls
369
- (an investigation is not trivial) gets one reminder to reopen it as
368
+ declared trivial that then edits a second file, touches tests, queries a live source twice, or keeps
369
+ working past eight calls (an investigation is not trivial) gets one reminder to reopen it as
370
370
  a typed run, and counts as `trivial_overreach` in the audit. Trivial runs close at the end of the
371
371
  turn (`Stop` hook), so single-prompt sessions still reach the history. Typed runs stay open across
372
372
  turns and close when the session ends (`SessionEnd`), so an unclosed run is never lost.
package/lib/flow-gate.mjs CHANGED
@@ -52,6 +52,11 @@ export function overreachWorkNudgeFor(cli = 'llm-orchestrator', calls = 9) {
52
52
  return `This task was declared trivial, but it has now made ${calls} work calls — trivial is a one-line change, not an investigation. Reopen it as a typed run (\`${cli} run start --type <TYPE> --shards <n>\`) so it is classified, planned and verified like one.`;
53
53
  }
54
54
 
55
+ /** A run declared trivial that is querying live sources. */
56
+ export function overreachLiveNudgeFor(cli = 'llm-orchestrator', live = 2) {
57
+ return `This task was declared trivial, but it has now queried live sources ${live} times — an investigation over production evidence is not trivial. Reopen it as a typed run (\`${cli} run start --type INCIDENT|INVESTIGATION --shards <n>\`), where independent live sources are shards for collectors.`;
58
+ }
59
+
55
60
  // Edit-shaped tools, per harness. Only a short hash of each path is kept.
56
61
  const EDIT_TOOLS = new Set(['edit', 'write', 'multiedit', 'notebookedit', 'str_replace_based_edit_tool', 'apply_patch', 'patch']);
57
62
  const TEST_PATH = /(^|\/)(test|tests|__tests__|spec|specs)\/|[._-](test|spec)\.[a-z0-9]+$|(^|\/)test_[^/]+\.py$|_spec\.rb$/i;
@@ -122,6 +127,8 @@ export const INLINE_REASON = /^stateful:\s*\S/;
122
127
 
123
128
  // A: a trivial run is a one-line change, not an investigation.
124
129
  export const TRIVIAL_WORK_LIMIT = 8;
130
+ // Querying a live source more than once is an investigation, however few calls it takes.
131
+ export const TRIVIAL_LIVE_LIMIT = 2;
125
132
 
126
133
  // C: sources whose reads cost real time and live remotely — the reads that pay to fan out.
127
134
  const LIVE_SOURCE = /(^|[\s;&|(])(rtk\s+)?(ssh|scp|psql|mysql|mongosh|mongo|redis-cli|kubectl|docker\s+(exec|logs)|aws|gcloud|az|curl|wget|http|httpie)(\s|$)/;
@@ -428,20 +435,24 @@ export function decide(previous, event, now) {
428
435
  if (session.run) {
429
436
  const current = session.run;
430
437
  current.main_work_calls = (current.main_work_calls ?? 0) + 1;
438
+ // Live reads count on every run, trivial ones included — they are what fan-out is for.
439
+ if (event.live) current.live_calls = (current.live_calls ?? 0) + 1;
431
440
  if (current.trivial) {
432
441
  current.edited_files = [...new Set([...(current.edited_files ?? []), ...event.edits.map((entry) => entry.hash)])];
433
442
  current.touched_tests = Boolean(current.touched_tests) || event.edits.some((entry) => entry.test);
434
443
  const grewByEdits = current.edited_files.length >= 2 || current.touched_tests;
435
444
  const grewByWork = current.main_work_calls > TRIVIAL_WORK_LIMIT;
436
- if (!current.overreach_nudged && (grewByEdits || grewByWork)) {
445
+ const grewByLive = (current.live_calls ?? 0) >= TRIVIAL_LIVE_LIMIT;
446
+ if (!current.overreach_nudged && (grewByEdits || grewByWork || grewByLive)) {
437
447
  current.overreach_nudged = true;
438
448
  output = grewByEdits
439
449
  ? { additionalContext: overreachNudgeFor(undefined, current.edited_files.length), kind: 'overreach', files: current.edited_files.length }
440
- : { additionalContext: overreachWorkNudgeFor(undefined, current.main_work_calls), kind: 'overreach', calls: current.main_work_calls };
450
+ : grewByLive
451
+ ? { additionalContext: overreachLiveNudgeFor(undefined, current.live_calls), kind: 'overreach', live: current.live_calls }
452
+ : { additionalContext: overreachWorkNudgeFor(undefined, current.main_work_calls), kind: 'overreach', calls: current.main_work_calls };
441
453
  }
442
454
  return { session, output, history };
443
455
  }
444
- if (event.live) current.live_calls = (current.live_calls ?? 0) + 1;
445
456
  const evidence = EVIDENCE_TYPES.has(current.task_type);
446
457
  const step = (evidence ? EVIDENCE_CALLS_PER_SHARD : DISPATCH_CALLS_PER_SHARD) * (current.planned_shards ?? 0);
447
458
  const nudges = current.dispatch_nudges ?? (current.dispatch_nudged ? 1 : 0);
@@ -593,7 +604,8 @@ export async function handleHook({ payload, project, now = Date.now(), cli = 'll
593
604
  // decide() speaks in the default CLI spelling; the hook swaps in the runnable path.
594
605
  const text = result.output.kind === 'dispatch' ? dispatchNudgeFor(cli, result.output.planned, result.output.taskType)
595
606
  : result.output.kind === 'dispatch_followup' ? dispatchFollowupFor(cli, result.output.planned, result.output.taskType)
596
- : result.output.kind === 'overreach' ? (result.output.calls ? overreachWorkNudgeFor(cli, result.output.calls) : overreachNudgeFor(cli, result.output.files))
607
+ : result.output.kind === 'overreach' ? (result.output.live ? overreachLiveNudgeFor(cli, result.output.live)
608
+ : result.output.calls ? overreachWorkNudgeFor(cli, result.output.calls) : overreachNudgeFor(cli, result.output.files))
597
609
  : nudgeFor(cli);
598
610
  return { hookSpecificOutput: { hookEventName: 'PreToolUse', additionalContext: text } };
599
611
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "llm-orchestrator",
3
- "version": "1.2.7",
3
+ "version": "1.2.8",
4
4
  "description": "Write /task once — it plans the work, shards it across parallel subagents, gates every phase and verifies before claiming done. Claude Code, Codex, OpenCode, Kilo.",
5
5
  "type": "module",
6
6
  "engines": {