open-agents-ai 0.187.467 → 0.187.469

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.
package/dist/index.js CHANGED
@@ -517859,6 +517859,15 @@ var init_agenticRunner = __esm({
517859
517859
  // a phase's worth of work without recording progress — and on the next
517860
517860
  // turn will replay the same plan. Surface a nudge before that happens.
517861
517861
  _writesSinceLastTodoWrite = 0;
517862
+ // REG-12: Progress gate (root-cause enforcement). When ≥6 file writes
517863
+ // have happened without a todo_write call, this latch flips ON. While
517864
+ // the latch is on, every tool call EXCEPT todo_write/todo_read/
517865
+ // task_complete/ask_user is intercepted with a synthetic '[PROGRESS GATE]'
517866
+ // result that forces the agent to update its plan before continuing.
517867
+ // Released when todo_write fires successfully. Without this, the agent
517868
+ // can re-emit the same plan a second time (plan-replay) and execute
517869
+ // duplicate work because PROGRESS NUDGE alone is informational.
517870
+ _progressGateActive = false;
517862
517871
  // REG-5: Rolling buffer of recent tool failures with their error output.
517863
517872
  // Surfaced before every LLM call so the agent can't ignore "I just ran this
517864
517873
  // and it errored". Detects same-fingerprint failure repetition and escalates
@@ -518592,41 +518601,98 @@ ${body}`;
518592
518601
  if (!output || typeof output !== "string")
518593
518602
  return null;
518594
518603
  const text = output;
518595
- const tail = text.slice(-3e3);
518596
- if (/\bTS\d{3,5}\b.*?: /m.test(tail) && /\berror\s+TS\d{3,5}\b/i.test(tail)) {
518604
+ const tail = text.slice(-4e3);
518605
+ if (/\berror\s+TS\d{3,5}\b/i.test(tail)) {
518597
518606
  const m2 = tail.match(/error\s+TS\d{3,5}[^\n]{0,200}/i);
518598
- return `TypeScript build error detected: ${(m2?.[0] ?? "").slice(0, 200)}`;
518607
+ return `Compile error: ${(m2?.[0] ?? "").slice(0, 240)}`;
518599
518608
  }
518600
- if (/\b(Failed to compile|Compilation failed|Build failed)\b/i.test(tail)) {
518601
- const m2 = tail.match(/(Failed to compile|Compilation failed|Build failed)[^\n]{0,300}/i);
518602
- return `Build failed: ${(m2?.[0] ?? "").slice(0, 200)}`;
518609
+ if (/\berror\[E\d+\]/i.test(tail)) {
518610
+ const m2 = tail.match(/error\[E\d+\][^\n]{0,200}/i);
518611
+ return `Compile error: ${(m2?.[0] ?? "").slice(0, 240)}`;
518603
518612
  }
518604
- if (/\bError:\s+Build failed\b/i.test(tail)) {
518605
- return "Next.js build failed (webpack/rspack errors)";
518613
+ if (/\berror\s+CS\d{3,5}\b/i.test(tail)) {
518614
+ const m2 = tail.match(/error\s+CS\d{3,5}[^\n]{0,200}/i);
518615
+ return `Compile error: ${(m2?.[0] ?? "").slice(0, 240)}`;
518606
518616
  }
518607
- if (/\b\d+\s+errors? found\b/i.test(tail) && /\b(error|failed)\b/i.test(tail)) {
518608
- const m2 = tail.match(/\d+\s+errors? found[^\n]{0,200}/i);
518609
- return `Build reported errors: ${(m2?.[0] ?? "").slice(0, 200)}`;
518617
+ if (/(^|\n)\S+:\d+:\d+:\s+error:/i.test(tail)) {
518618
+ const m2 = tail.match(/\S+:\d+:\d+:\s+error:[^\n]{0,200}/i);
518619
+ return `Compile error: ${(m2?.[0] ?? "").slice(0, 240)}`;
518620
+ }
518621
+ if (/\bundefined\s+reference\s+to\b|\bld:\s+error:/i.test(tail)) {
518622
+ const m2 = tail.match(/(undefined\s+reference\s+to|ld:\s+error:)[^\n]{0,200}/i);
518623
+ return `Linker error: ${(m2?.[0] ?? "").slice(0, 240)}`;
518624
+ }
518625
+ if (/\b(Failed to compile|Compilation failed|Build failed|BUILD\s+FAIL(ED|URE))\b/i.test(tail)) {
518626
+ const m2 = tail.match(/(Failed to compile|Compilation failed|Build failed|BUILD\s+FAIL(?:ED|URE))[^\n]{0,300}/i);
518627
+ return `Build failed: ${(m2?.[0] ?? "").slice(0, 240)}`;
518628
+ }
518629
+ if (/\b\d+\s+errors?\s+(found|generated)\b/i.test(tail)) {
518630
+ const m2 = tail.match(/\d+\s+errors?\s+(?:found|generated)[^\n]{0,200}/i);
518631
+ return `Build reported errors: ${(m2?.[0] ?? "").slice(0, 240)}`;
518610
518632
  }
518611
518633
  if (/\bnpm\s+ERR!|\bnpm error code\b/i.test(tail)) {
518612
518634
  const m2 = tail.match(/(npm\s+ERR!|npm error code)[^\n]{0,300}/i);
518613
- return `npm error: ${(m2?.[0] ?? "").slice(0, 200)}`;
518635
+ return `Package install error: ${(m2?.[0] ?? "").slice(0, 240)}`;
518636
+ }
518637
+ if (/\bERROR:\s+Could not (install|find|build)\b/i.test(tail)) {
518638
+ const m2 = tail.match(/ERROR:\s+Could not[^\n]{0,200}/i);
518639
+ return `Package install error: ${(m2?.[0] ?? "").slice(0, 240)}`;
518640
+ }
518641
+ if (/\b(E:\s+(Unable to|Could not)|apt-get:\s+error|dnf:\s+(?:Error|Failed)|pacman:\s+error)/i.test(tail)) {
518642
+ const m2 = tail.match(/(E:\s+|apt-get:\s+error|dnf:\s+|pacman:\s+error)[^\n]{0,200}/i);
518643
+ return `System package error: ${(m2?.[0] ?? "").slice(0, 240)}`;
518644
+ }
518645
+ if (/\bTests?:\s+\d+\s+failed\b/i.test(tail)) {
518646
+ const m2 = tail.match(/Tests?:[^\n]{0,200}/i);
518647
+ return `Test failures: ${(m2?.[0] ?? "").slice(0, 240)}`;
518648
+ }
518649
+ if (/^FAILED\s+\S+::/m.test(tail) || /=+\s*\d+\s+failed/i.test(tail)) {
518650
+ const m2 = tail.match(/(FAILED\s+\S+|=+\s*\d+\s+failed)[^\n]{0,200}/i);
518651
+ return `Test failures: ${(m2?.[0] ?? "").slice(0, 240)}`;
518652
+ }
518653
+ if (/\b\d+\s+failing\b/i.test(tail) && /\bpassing\b/i.test(tail)) {
518654
+ const m2 = tail.match(/\d+\s+failing[^\n]{0,200}/i);
518655
+ return `Test failures: ${(m2?.[0] ?? "").slice(0, 240)}`;
518656
+ }
518657
+ if (/^---\s+FAIL:/m.test(tail) || /^FAIL\t\S+/m.test(tail)) {
518658
+ const m2 = tail.match(/(---\s+FAIL:[^\n]{0,200}|FAIL\t\S+[^\n]{0,200})/i);
518659
+ return `Test failures: ${(m2?.[0] ?? "").slice(0, 240)}`;
518660
+ }
518661
+ if (/test\s+result:\s+FAILED/i.test(tail)) {
518662
+ const m2 = tail.match(/test\s+result:\s+FAILED[^\n]{0,200}/i);
518663
+ return `Test failures: ${(m2?.[0] ?? "").slice(0, 240)}`;
518664
+ }
518665
+ if (/\b\d+\s+failed\s+(of|out\s+of)\s+\d+\b/i.test(tail)) {
518666
+ const m2 = tail.match(/\d+\s+failed\s+(?:of|out\s+of)\s+\d+[^\n]{0,200}/i);
518667
+ return `Test failures: ${(m2?.[0] ?? "").slice(0, 240)}`;
518668
+ }
518669
+ if (/^Traceback \(most recent call last\):/m.test(tail) && /\w+(?:Error|Exception):\s/.test(tail)) {
518670
+ const m2 = tail.match(/\w+(?:Error|Exception):[^\n]{0,200}/);
518671
+ return `Runtime exception: ${(m2?.[0] ?? "").slice(0, 240)}`;
518614
518672
  }
518615
- if (/\bTests:\s+\d+\s+failed\b/i.test(tail) || /\b\d+\s+failed\b.*\bof\s+\d+\b/i.test(tail)) {
518616
- const m2 = tail.match(/Tests:[^\n]{0,200}|\d+\s+failed[^\n]{0,200}/i);
518617
- return `Test failures detected: ${(m2?.[0] ?? "").slice(0, 200)}`;
518673
+ if (/\b(UnhandledPromiseRejection|throw\s+new\s+\w+|Uncaught\s+\w+Error)\b/i.test(tail)) {
518674
+ const m2 = tail.match(/(UnhandledPromiseRejection|throw\s+new\s+\w+|Uncaught[^\n]{0,200})/i);
518675
+ return `Runtime exception: ${(m2?.[0] ?? "").slice(0, 240)}`;
518618
518676
  }
518619
- if (/^Traceback \(most recent call last\):/m.test(tail) && /\bError:|Exception:/m.test(tail)) {
518620
- const m2 = tail.match(/(\w+(?:Error|Exception)):[^\n]{0,200}/);
518621
- return `Python exception: ${(m2?.[0] ?? "").slice(0, 200)}`;
518677
+ if (/\b(Exception\s+in\s+thread|java\.\w+(?:Error|Exception):)/i.test(tail)) {
518678
+ const m2 = tail.match(/(Exception\s+in\s+thread[^\n]{0,200}|java\.\w+(?:Error|Exception):[^\n]{0,200})/i);
518679
+ return `Runtime exception: ${(m2?.[0] ?? "").slice(0, 240)}`;
518622
518680
  }
518623
- if (/\berror\[E\d+\]:/i.test(tail) || /\b(\.\/[\w./-]+):\d+:\d+:\s+error:/i.test(tail)) {
518624
- const m2 = tail.match(/error\[E\d+\][^\n]{0,200}|\.\/[\w./-]+:\d+:\d+:\s+error:[^\n]{0,200}/i);
518625
- return `Compiler error: ${(m2?.[0] ?? "").slice(0, 200)}`;
518681
+ if (/^[\w./:-]+:\d+:in\s+`[^']*':\s+/m.test(tail) && /\b\w+Error\b/.test(tail)) {
518682
+ const m2 = tail.match(/\b\w+Error[^\n]{0,200}/);
518683
+ return `Runtime exception: ${(m2?.[0] ?? "").slice(0, 240)}`;
518684
+ }
518685
+ if (/\bthread\s+'[^']*'\s+panicked\s+at/i.test(tail)) {
518686
+ const m2 = tail.match(/thread\s+'[^']*'\s+panicked\s+at[^\n]{0,200}/i);
518687
+ return `Runtime panic: ${(m2?.[0] ?? "").slice(0, 240)}`;
518626
518688
  }
518627
518689
  if (/^(fatal|FATAL|panic):\s/m.test(tail)) {
518628
518690
  const m2 = tail.match(/^(fatal|FATAL|panic):\s[^\n]{0,200}/m);
518629
- return `Fatal error: ${(m2?.[0] ?? "").slice(0, 200)}`;
518691
+ return `Fatal error: ${(m2?.[0] ?? "").slice(0, 240)}`;
518692
+ }
518693
+ if (/\b(Segmentation\s+fault|core\s+dumped|Abort(?:ed)?\s+\(core dumped\)|Killed)\b/i.test(tail)) {
518694
+ const m2 = tail.match(/(Segmentation\s+fault|core\s+dumped|Abort(?:ed)?\s+\(core dumped\)|Killed)[^\n]{0,80}/i);
518695
+ return `Process terminated abnormally: ${(m2?.[0] ?? "").slice(0, 240)}`;
518630
518696
  }
518631
518697
  return null;
518632
518698
  }
@@ -518683,6 +518749,7 @@ ${body}`;
518683
518749
  if (/(^|[^&\d])(>|>>)\s*\S/.test(cmd))
518684
518750
  return false;
518685
518751
  const MUTATE_BINS = [
518752
+ // POSIX file/process mutators
518686
518753
  "rm",
518687
518754
  "mv",
518688
518755
  "cp",
@@ -518690,56 +518757,158 @@ ${body}`;
518690
518757
  "rmdir",
518691
518758
  "chmod",
518692
518759
  "chown",
518760
+ "chgrp",
518693
518761
  "touch",
518694
518762
  "tee",
518695
518763
  "dd",
518696
518764
  "truncate",
518697
518765
  "ln",
518766
+ "install",
518698
518767
  "kill",
518699
518768
  "pkill",
518700
518769
  "killall",
518701
518770
  "reboot",
518702
518771
  "shutdown",
518772
+ "halt",
518773
+ "poweroff",
518703
518774
  "fakeroot",
518704
518775
  "sudo",
518776
+ "doas",
518705
518777
  "nohup",
518706
518778
  "setsid",
518779
+ "su",
518780
+ // Build orchestrators (always trigger compile/test side-effects)
518707
518781
  "make",
518782
+ "gmake",
518783
+ "ninja",
518708
518784
  "gradle",
518785
+ "gradlew",
518709
518786
  "mvn",
518787
+ "mvnw",
518788
+ "ant",
518789
+ "bazel",
518790
+ "buck",
518791
+ "buck2",
518792
+ "cmake",
518793
+ "meson",
518794
+ "scons",
518795
+ "rake",
518796
+ "leiningen",
518797
+ "lein",
518798
+ "sbt",
518799
+ "stack",
518800
+ // Configuration-management / orchestration
518710
518801
  "ansible",
518711
- "systemd-run"
518802
+ "ansible-playbook",
518803
+ "puppet",
518804
+ "chef-client",
518805
+ "salt",
518806
+ "salt-call",
518807
+ "systemd-run",
518808
+ "systemd-analyze",
518809
+ // System package managers
518810
+ "apt",
518811
+ "apt-get",
518812
+ "yum",
518813
+ "dnf",
518814
+ "rpm",
518815
+ "pacman",
518816
+ "zypper",
518817
+ "emerge",
518818
+ "snap",
518819
+ "flatpak",
518820
+ "brew",
518821
+ "port",
518822
+ "pkg",
518823
+ "apk",
518824
+ "choco",
518825
+ "scoop",
518826
+ "winget",
518827
+ // Helm / k8s-flavored
518828
+ "helm",
518829
+ "helmfile",
518830
+ "kustomize"
518712
518831
  ];
518713
518832
  const mutateBinsRe = new RegExp(`\\b(${MUTATE_BINS.join("|")})\\b`, "i");
518714
518833
  if (mutateBinsRe.test(cmd))
518715
518834
  return false;
518716
518835
  if (/\bsed\s+(-i|--in-place)\b/.test(cmd))
518717
518836
  return false;
518718
- if (/\bsystemctl\s+(?!status\b|show\b|is-)/i.test(cmd))
518837
+ if (/\bsystemctl\s+(?!status\b|show\b|is-|cat\b|list-|get-)/i.test(cmd))
518719
518838
  return false;
518720
518839
  if (/\bservice\s+\S+\s+(?!status\b)/i.test(cmd))
518721
518840
  return false;
518722
518841
  if (/\bcrontab\s+-(e|d|r)\b/.test(cmd))
518723
518842
  return false;
518724
- if (/\bnpm\s+(install|uninstall|update|run|test|exec|publish|init|link|unlink|version|cache\s+clean|ci|audit\s+fix)\b/i.test(cmd))
518725
- return false;
518726
- if (/\bpnpm\s+(install|update|add|remove|run|test|exec|publish|init|link|unlink|version)\b/i.test(cmd))
518843
+ if (/\bnpm\s+(install|i\b|uninstall|un\b|update|up\b|run\s|test\b|exec|publish|init|link|unlink|version|cache\s+clean|ci\b|audit\s+fix|prune|rebuild|adduser|login|logout|deprecate)\b/i.test(cmd))
518727
518844
  return false;
518728
- if (/\byarn\s+(install|add|remove|upgrade|run|test|exec|publish|init|link|unlink|version)\b/i.test(cmd))
518845
+ if (/\bpnpm\s+(install|i\b|update|up\b|add|remove|rm\b|run\s|test\b|exec|publish|init|link|unlink|version|prune|rebuild)\b/i.test(cmd))
518729
518846
  return false;
518730
- if (/\bpip\s+(install|uninstall|wheel)\b/i.test(cmd))
518847
+ if (/\byarn\s+(install|add|remove|upgrade|run\s|test\b|exec|publish|init|link|unlink|version)\b/i.test(cmd))
518731
518848
  return false;
518732
518849
  if (/\bnpx\b/.test(cmd))
518733
518850
  return false;
518734
- if (/\bcargo\s+(build|run|test|update|publish|install|uninstall|fmt|fix)\b/i.test(cmd))
518851
+ if (/\bpip3?\s+(install|uninstall|wheel|download)\b/i.test(cmd))
518852
+ return false;
518853
+ if (/\bpipenv\s+(install|uninstall|run|update|sync)\b/i.test(cmd))
518854
+ return false;
518855
+ if (/\bpoetry\s+(add|install|run|update|remove|build|publish|init|new|export|lock)\b/i.test(cmd))
518856
+ return false;
518857
+ if (/\bconda\s+(install|remove|update|create|env\s+(create|update|remove))\b/i.test(cmd))
518858
+ return false;
518859
+ if (/\buv\s+(add|remove|sync|install|run|build|publish|pip\s+install)\b/i.test(cmd))
518860
+ return false;
518861
+ if (/\bbundle\s+(install|update|exec|add|remove|init)\b/i.test(cmd))
518862
+ return false;
518863
+ if (/\bgem\s+(install|uninstall|update|build|push|owner)\b/i.test(cmd))
518864
+ return false;
518865
+ if (/\bcpan\b|\bcpanm\b|\bperl\s+-MCPAN\b/i.test(cmd))
518866
+ return false;
518867
+ if (/\bcomposer\s+(install|update|require|remove|create-project|dump-autoload|run-script)\b/i.test(cmd))
518868
+ return false;
518869
+ if (/\bdotnet\s+(build|run|test|publish|pack|restore|add|remove|new|tool\s+install)\b/i.test(cmd))
518735
518870
  return false;
518736
- if (/\bgo\s+(build|run|test|get|install)\b/i.test(cmd))
518871
+ if (/\bcargo\s+(build|run|test|bench|update|publish|install|uninstall|fmt|fix|clippy\s+--fix|new|init|add|remove|generate-lockfile)\b/i.test(cmd))
518737
518872
  return false;
518738
- if (/\bdocker\s+(build|run|push|pull|exec|kill|stop|rm|rmi|tag)\b/i.test(cmd))
518873
+ if (/\bgo\s+(build|run|test|get|install|generate|mod\s+(tidy|download|init|edit|vendor)|work\s+)\b/i.test(cmd))
518739
518874
  return false;
518740
- if (/\bkubectl\s+(apply|delete|create|edit|patch|scale|rollout|exec)\b/i.test(cmd))
518875
+ if (/\bdocker\s+(build|run|push|pull|exec|kill|stop|rm|rmi|tag|create|cp|commit|save|load|import|export|network\s+create|volume\s+create|compose\s+(up|down|build|run|exec|restart))\b/i.test(cmd))
518741
518876
  return false;
518742
- if (/\bterraform\s+(apply|destroy|init|plan|import)\b/i.test(cmd))
518877
+ if (/\bpodman\s+(build|run|push|pull|exec|kill|stop|rm|rmi|tag|create|commit)\b/i.test(cmd))
518878
+ return false;
518879
+ if (/\bkubectl\s+(apply|delete|create|edit|patch|scale|rollout|exec|cp|drain|cordon|uncordon|taint|label|annotate|set\s)\b/i.test(cmd))
518880
+ return false;
518881
+ if (/\bterraform\s+(apply|destroy|init|plan|import|taint|untaint|workspace\s+(new|delete)|state\s+(rm|mv|push|replace-provider))\b/i.test(cmd))
518882
+ return false;
518883
+ if (/\bpulumi\s+(up|destroy|new|stack\s+(rm|init)|config\s+set|policy\s+enable|import)\b/i.test(cmd))
518884
+ return false;
518885
+ if (/\baws\s+(?:\S+\s+)+(create|delete|put|update|run|start|stop|terminate|attach|detach|cp|sync|mv)\b/i.test(cmd))
518886
+ return false;
518887
+ if (/\bgcloud\s+(?:\S+\s+)+(create|delete|update|deploy|apply|set|enable|disable|attach|detach|reset|move|sign-in|sign-out)\b/i.test(cmd))
518888
+ return false;
518889
+ if (/\baz\s+(?:\S+\s+)+(create|delete|update|deploy|set|attach|detach|reset|move)\b/i.test(cmd))
518890
+ return false;
518891
+ if (/\beslint\s+[^|;&]*--fix\b/i.test(cmd))
518892
+ return false;
518893
+ if (/\bprettier\s+[^|;&]*--write\b/i.test(cmd))
518894
+ return false;
518895
+ if (/\bblack\s+(?!--check\b)/i.test(cmd))
518896
+ return false;
518897
+ if (/\bisort\s+(?!--check\b|--diff\b)/i.test(cmd))
518898
+ return false;
518899
+ if (/\bruff\s+(?:format\b|check\s+[^|;&]*--fix\b)/i.test(cmd))
518900
+ return false;
518901
+ if (/\bgofmt\s+-w\b/i.test(cmd))
518902
+ return false;
518903
+ if (/\brustfmt\s+(?!--check\b)/i.test(cmd))
518904
+ return false;
518905
+ if (/\b(node|python\d?|ruby|perl|bash|sh|zsh|dash|fish)\s+-(e|c)\b/.test(cmd))
518906
+ return false;
518907
+ if (/\bcurl\s+[^|]*\|\s*(bash|sh|zsh|fish|python\d?|ruby|node|perl)\b/i.test(cmd))
518908
+ return false;
518909
+ if (/\bgit\s+(add|commit|push|pull|fetch|clone|init|checkout|switch|restore|reset|rm|mv|merge|rebase|cherry-pick|revert|stash|apply|am|tag(?:\s+\S)?|notes|worktree\s+(add|remove)|gc|prune|repack|filter-branch|filter-repo|reflog\s+(delete|expire)|update-ref|update-index|symbolic-ref|hash-object\s+-w)\b/i.test(cmd))
518910
+ return false;
518911
+ if (/\bollama\s+(pull|push|run|create|rm|cp|serve)\b/i.test(cmd))
518743
518912
  return false;
518744
518913
  const READ_ONLY_BINS = /* @__PURE__ */ new Set([
518745
518914
  "cd",
@@ -518749,79 +518918,128 @@ ${body}`;
518749
518918
  "fgrep",
518750
518919
  "rg",
518751
518920
  "ag",
518921
+ "ack",
518752
518922
  "cat",
518753
518923
  "head",
518754
518924
  "tail",
518755
518925
  "less",
518756
518926
  "more",
518927
+ "bat",
518928
+ "tac",
518757
518929
  "ls",
518758
518930
  "ll",
518759
518931
  "la",
518932
+ "tree",
518760
518933
  "find",
518761
- // ALLOWED only if no -delete/-exec mutating action — pre-filtered above
518934
+ "fd",
518935
+ // mutating actions pre-filtered above
518762
518936
  "wc",
518763
518937
  "awk",
518764
518938
  "gawk",
518939
+ "mawk",
518940
+ "nawk",
518765
518941
  "sort",
518766
518942
  "uniq",
518943
+ "shuf",
518767
518944
  "tr",
518768
518945
  "cut",
518769
518946
  "paste",
518770
518947
  "join",
518771
518948
  "comm",
518949
+ "column",
518950
+ "expand",
518951
+ "unexpand",
518772
518952
  "diff",
518773
518953
  "cmp",
518954
+ "patch",
518955
+ // patch with -R or no-args could be mutating; --dry-run only is read
518774
518956
  "echo",
518775
518957
  "printf",
518776
518958
  "pwd",
518777
518959
  "which",
518778
518960
  "type",
518779
518961
  "command",
518780
- "node",
518781
- "python",
518782
- "python3",
518783
- "ruby",
518784
- "perl",
518962
+ "whereis",
518785
518963
  "git",
518786
- // git log/show/diff/status are read; but git add/commit/push/pull are writes — pre-filtered above
518964
+ // pre-filtered above for mutating subcommands
518787
518965
  "ollama",
518788
- // ollama show/list are read; ollama pull/run/create are writes — pre-filtered above
518966
+ // pre-filtered above
518789
518967
  "cargo",
518790
- // pre-filtered above for build/run/etc.
518791
518968
  "go",
518792
- // pre-filtered above for build/run/etc.
518969
+ "rustc",
518970
+ // bin-only forms are read; mutating subcommands pre-filtered
518793
518971
  "stat",
518794
518972
  "file",
518795
518973
  "du",
518796
518974
  "df",
518975
+ "lsof",
518976
+ "fuser",
518797
518977
  "date",
518798
518978
  "uname",
518799
518979
  "id",
518800
518980
  "whoami",
518801
518981
  "hostname",
518802
518982
  "uptime",
518983
+ "tty",
518803
518984
  "env",
518804
518985
  "printenv",
518986
+ "set",
518805
518987
  "test",
518806
518988
  "[",
518807
518989
  "true",
518808
518990
  "false",
518991
+ "yes",
518992
+ "seq",
518809
518993
  "tsc",
518810
518994
  "eslint",
518811
518995
  "prettier",
518812
- // these emit but mostly read
518813
- "head",
518814
- "tail",
518996
+ "ruff",
518997
+ "black",
518998
+ "isort",
518999
+ "rustfmt",
519000
+ "gofmt",
519001
+ // Linters/formatters: mutating modes pre-filtered above (--fix/--write/-w/-i),
519002
+ // so reaching here means we have a check-only invocation.
518815
519003
  "jq",
518816
519004
  "yq",
518817
519005
  "xq",
519006
+ "tomlq",
519007
+ "fx",
518818
519008
  "base64",
518819
519009
  "md5sum",
518820
519010
  "sha256sum",
518821
519011
  "sha1sum",
519012
+ "sha512sum",
518822
519013
  "tldr",
518823
519014
  "man",
518824
- "info"
519015
+ "info",
519016
+ "help",
519017
+ "pip",
519018
+ "pip3",
519019
+ "pipenv",
519020
+ "poetry",
519021
+ "uv",
519022
+ "conda",
519023
+ // pre-filtered above for mutating subcommands
519024
+ "npm",
519025
+ "pnpm",
519026
+ "yarn",
519027
+ // pre-filtered above
519028
+ "kubectl",
519029
+ "terraform",
519030
+ "pulumi",
519031
+ "aws",
519032
+ "gcloud",
519033
+ "az",
519034
+ // pre-filtered above
519035
+ "docker",
519036
+ "podman",
519037
+ // pre-filtered above
519038
+ "composer",
519039
+ "dotnet",
519040
+ "bundle",
519041
+ "gem"
519042
+ // pre-filtered above
518825
519043
  ]);
518826
519044
  if (/\bfind\b[\s\S]*?(-delete|-exec\s+(rm|mv|cp|chmod|chown|sed\s+-i)|--?ok\s+(rm|mv))/i.test(cmd))
518827
519045
  return false;
@@ -518830,11 +519048,42 @@ ${body}`;
518830
519048
  const segments = cmd.split(/(?:\|\||&&|;)/).map((s2) => s2.trim()).filter(Boolean);
518831
519049
  if (segments.length === 0)
518832
519050
  return false;
519051
+ const SAFE_INTERP_FLAGS = /^(?:--version|--help|-V|-v|-h|--vers|version)$/;
519052
+ const INTERPRETER_BINS = /* @__PURE__ */ new Set([
519053
+ "node",
519054
+ "python",
519055
+ "python2",
519056
+ "python3",
519057
+ "ruby",
519058
+ "perl",
519059
+ "php",
519060
+ "lua",
519061
+ "bash",
519062
+ "sh",
519063
+ "zsh",
519064
+ "dash",
519065
+ "fish",
519066
+ "ksh",
519067
+ "tcsh",
519068
+ "java",
519069
+ "kotlin",
519070
+ "scala",
519071
+ "groovy"
519072
+ ]);
518833
519073
  for (const seg of segments) {
518834
519074
  const stripped = seg.replace(/^cd\s+\S+\s*$/i, "true").replace(/^!/, "");
518835
- const firstTok = stripped.split(/\s+/)[0]?.replace(/^.*\//, "") || "";
519075
+ const tokens = stripped.split(/\s+/).filter(Boolean);
519076
+ const firstTok = (tokens[0] ?? "").replace(/^.*\//, "");
518836
519077
  if (!firstTok)
518837
519078
  continue;
519079
+ if (INTERPRETER_BINS.has(firstTok)) {
519080
+ const restToks = tokens.slice(1);
519081
+ if (restToks.length === 0)
519082
+ return false;
519083
+ if (!restToks.every((t2) => SAFE_INTERP_FLAGS.test(t2)))
519084
+ return false;
519085
+ continue;
519086
+ }
518838
519087
  if (!READ_ONLY_BINS.has(firstTok))
518839
519088
  return false;
518840
519089
  }
@@ -518843,10 +519092,11 @@ ${body}`;
518843
519092
  /**
518844
519093
  * REG-5: Render the recent-failures block so the agent SEES its own error
518845
519094
  * output before deciding what to do next. Detects same-fingerprint failure
518846
- * repetition and escalates the warning. Without this, the agent runs
518847
- * `npx next build`, gets a 200-line TypeScript error, ignores the specific
518848
- * error and blindly retries with `npm install --force`. Caching the failure
518849
- * + injecting it pre-LLM forces the model to confront what actually broke.
519095
+ * repetition and escalates the warning. Without this, the agent runs a
519096
+ * build/test/install command, gets a long error stream from the
519097
+ * underlying compiler/runner, ignores the specific error, and blindly
519098
+ * retries with a different flag combination. Caching the failure +
519099
+ * injecting it pre-LLM forces the model to confront what actually broke.
518850
519100
  */
518851
519101
  _renderRecentFailuresBlock(turn) {
518852
519102
  const fails = this._recentFailures;
@@ -520429,6 +520679,8 @@ ${memoryLines.join("\n")}`
520429
520679
  for (const [tool2, budget] of Object.entries(toolBudgets)) {
520430
520680
  toolCallBudget.set(tool2, budget);
520431
520681
  }
520682
+ this._writesSinceLastTodoWrite = 0;
520683
+ this._progressGateActive = false;
520432
520684
  this.emit({
520433
520685
  type: "status",
520434
520686
  content: `Tool budgets reset for new phase (${Object.keys(toolBudgets).length} tools)`,
@@ -520436,6 +520688,55 @@ ${memoryLines.join("\n")}`
520436
520688
  });
520437
520689
  }
520438
520690
  }
520691
+ const PROGRESS_GATE_BYPASS_TOOLS = /* @__PURE__ */ new Set([
520692
+ "todo_write",
520693
+ "todo_read",
520694
+ "task_complete",
520695
+ "ask_user",
520696
+ "phase_recall"
520697
+ // useful for the agent to consult prior phase state before updating
520698
+ ]);
520699
+ if (this._progressGateActive && !PROGRESS_GATE_BYPASS_TOOLS.has(tc.name)) {
520700
+ this.emit({
520701
+ type: "tool_call",
520702
+ toolName: tc.name,
520703
+ toolArgs: tc.arguments,
520704
+ turn,
520705
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
520706
+ });
520707
+ const recentWrites = [];
520708
+ for (const [path8, info] of this._worldFacts.files) {
520709
+ if ((info.writeCount ?? 0) > 0 && (info.lastWriteTurn ?? -1) >= 0 && turn - (info.lastWriteTurn ?? 0) <= 8) {
520710
+ recentWrites.push({ path: path8, turn: info.lastWriteTurn ?? 0 });
520711
+ }
520712
+ }
520713
+ recentWrites.sort((a2, b) => b.turn - a2.turn);
520714
+ const showWrites = recentWrites.slice(0, 16);
520715
+ const gateMsg = [
520716
+ `[PROGRESS GATE — call todo_write FIRST before any other tool]`,
520717
+ ``,
520718
+ `You have completed ${this._writesSinceLastTodoWrite} file modification${this._writesSinceLastTodoWrite === 1 ? "" : "s"} since your last todo_write call.`,
520719
+ `The next tool call MUST be todo_write to mark progress. This is enforced — non-todo tool calls are intercepted until plan state is updated.`,
520720
+ ``,
520721
+ `Recent file modifications (use these to decide what's done):`,
520722
+ ...showWrites.map((w) => ` • ${w.path} (turn ${w.turn})`),
520723
+ recentWrites.length > showWrites.length ? ` • ... +${recentWrites.length - showWrites.length} more` : "",
520724
+ ``,
520725
+ `Required action: call todo_write with the updated todo array — mark anything completed that these writes satisfy, advance the next item to in_progress, keep the rest pending.`,
520726
+ `After todo_write succeeds, this gate releases and you can continue normal work.`,
520727
+ ``,
520728
+ `Why this exists: without the explicit progress update, your next turn will see the same in_progress todo, re-plan the same work, and re-emit identical tool calls (the "plan replay" failure mode that causes byte-identical writes to appear twice).`
520729
+ ].filter(Boolean).join("\n");
520730
+ this.emit({
520731
+ type: "tool_result",
520732
+ toolName: tc.name,
520733
+ success: false,
520734
+ content: gateMsg.slice(0, 120),
520735
+ turn,
520736
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
520737
+ });
520738
+ return { tc, output: gateMsg };
520739
+ }
520439
520740
  const _argsKeyForBudget = `${tc.name}:${argsKey}`;
520440
520741
  const _isCachedHit = recentToolResults.has(_argsKeyForBudget);
520441
520742
  const budgetRemaining = toolCallBudget.get(tc.name);
@@ -520654,10 +520955,26 @@ ${cachedEntry2.result.slice(0, 500)}` : `[BLOCKED — the observer confirmed thi
520654
520955
  writeCount: (prev?.writeCount ?? 0) + 1
520655
520956
  });
520656
520957
  this._writesSinceLastTodoWrite++;
520958
+ if (this._writesSinceLastTodoWrite >= 6 && !this._progressGateActive) {
520959
+ this._progressGateActive = true;
520960
+ this.emit({
520961
+ type: "status",
520962
+ content: `Progress gate engaged at ${this._writesSinceLastTodoWrite} writes without todo_write — non-todo tools will be blocked until plan is updated`,
520963
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
520964
+ });
520965
+ }
520657
520966
  }
520658
520967
  }
520659
520968
  if (tc.name === "todo_write" && result.success) {
520969
+ if (this._progressGateActive) {
520970
+ this.emit({
520971
+ type: "status",
520972
+ content: "Progress gate released — todo_write acknowledged",
520973
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
520974
+ });
520975
+ }
520660
520976
  this._writesSinceLastTodoWrite = 0;
520977
+ this._progressGateActive = false;
520661
520978
  }
520662
520979
  if (tc.name === "file_read") {
520663
520980
  const p2 = String(tc.arguments?.["path"] ?? tc.arguments?.["file"] ?? "");
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "open-agents-ai",
3
- "version": "0.187.467",
3
+ "version": "0.187.469",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "open-agents-ai",
9
- "version": "0.187.467",
9
+ "version": "0.187.469",
10
10
  "hasInstallScript": true,
11
11
  "license": "CC-BY-NC-4.0",
12
12
  "dependencies": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-agents-ai",
3
- "version": "0.187.467",
3
+ "version": "0.187.469",
4
4
  "description": "AI coding agent powered by open-source models (Ollama/vLLM) — interactive TUI with agentic tool-calling loop",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",