Commit Graph
1000 Commits
Author SHA1 Message Date
ruv 56a638190d fix(console): CLI launcher resolution and cold-start handling for settings writes (fixes #3914)
With the ruflo CLI option on npx, a confirmed action ran a cold online npx under the 90 s default and aborted with 'still running after 90000ms'. Resolve ruflo on PATH, a project-local bin or the cached npx copy first; give a cold download a 300 s limit and a first-run label; turn a timeout or ENOTCACHED into an error naming the fix. Console 0.40.1; ADR-407 update.

Co-Authored-By: RuFlo <ruv@ruv.net>
2026-10-08 15:25:08 -04:00
ruv aeaa51e99a feat(console): advisor checkpoints for mission loops (ADR-483)
Default-off Settings rows: a read-only claude -p consult (asked first, exact argv, turn budget, mission spend cap) before a plan locks, when the same check fails twice in a row, and before done; a third failure pauses the mission. Honest about not being the in-session advisor tool. Console 0.40.0.

Co-Authored-By: RuFlo <ruv@ruv.net>
2026-10-08 12:20:26 -04:00
ruv 817dcfe0e3 fix(console): manually entered text is never silently truncated (ADR-481)
The mission goal was cut at 500 characters and drawn on one clipped line; the host Input is one line and hides the rest. A live mirror
under every field shows all lines, views draw text in full with an explicit marker, limits are checked before sending with the exact
count, and every silent slice/plain cap on typed text is removed or made a counted refusal. console 0.39.1.

Co-Authored-By: RuFlo <ruv@ruv.net>
2026-10-07 18:20:32 -04:00
ruv 2a08b54a4c Merge origin/main into fix/console-input-truncation
Co-Authored-By: RuFlo <ruv@ruv.net>
2026-10-07 18:14:01 -04:00
ruv dd180a29ed test: stronger wrap checks 2026-10-07 18:10:29 -04:00
ruv 7483d28f3c test(console): full-text helpers and input classes (ADR-481)
Co-Authored-By: RuFlo <ruv@ruv.net>
2026-10-07 18:09:56 -04:00
ruv 5d3d145ac9 wip(console): inputs never cut: chokepoints raised, refusals counted (ADR-481)
Co-Authored-By: RuFlo <ruv@ruv.net>
2026-10-07 18:02:19 -04:00
ruv bf67d3e304 wip(console): full-text helpers, mission goal never truncated (ADR-481)
Co-Authored-By: RuFlo <ruv@ruv.net>
2026-10-07 17:44:12 -04:00
ruv b62b7d334c fix(console): keep the swarm ADR digest true to the active mission; verify's confirm names its git reads; real-pane ADRs test (ADR-480)
Co-Authored-By: RuFlo <ruv@ruv.net>
2026-10-07 17:16:11 -04:00
ruv aed428c43e feat(console,adr): ADR management registry, page and mission/loop/swarm integration (ADR-480)
Co-Authored-By: RuFlo <ruv@ruv.net>
2026-10-07 17:08:41 -04:00
ruv 578a1d3686 wip(console,swarm): ADR registry, page, mission/swarm integration (ADR-480)
Co-Authored-By: RuFlo <ruv@ruv.net>
2026-10-07 16:54:03 -04:00
ruv 7670a02849 docs(plugins): CHANGELOG.md for every plugin in the ADR-478 format, derived from git history
Co-Authored-By: RuFlo <ruv@ruv.net>
2026-10-07 14:37:29 -04:00
ruv 9cef4cb070 feat(console): What's new page under TOOLS, plugin changelog parser and marker (ADR-478), console 0.38.0
Co-Authored-By: RuFlo <ruv@ruv.net>
2026-10-07 14:37:28 -04:00
rUv 2ab3f99ff9 Merge pull request #3890 from ruvnet/release/3.55.0
release: 3.55.0
2026-10-07 10:31:41 -07:00
ruv b02e2247dc chore(release): 3.55.0 versions, leaf pins, lockfiles, plugin bumps, changelog
Pins mcp 3.1.0, plugin-agent-federation 1.0.1, security 3.0.2, shared 3.0.2 and
memory 3.0.1 (all published and registry-verified) in root, cli, pnpm and npm locks.

Co-Authored-By: RuFlo <ruv@ruv.net>
2026-10-07 13:14:22 -04:00
ruv 04ff98bb32 fix(mods): a toast needs no engine.create (bind at session.start too), a throwing clock falls back to the wall clock; update the cost ladder expectation in the v3 mods contract
Co-Authored-By: RuFlo <ruv@ruv.net>
2026-10-07 13:08:53 -04:00
ruv 24806b7e78 fix(mods): console toasts release held errors on a timer; settings section names toasts; ADR wording
Co-Authored-By: RuFlo <ruv@ruv.net>
2026-10-07 12:54:37 -04:00
ruv 146febd999 feat(mods): shared toast system with levels, dedupe, persistence and Settings (ADR-477)
One dependency-free policy (canonical in ruflo-mods, byte-identical copies in console,
swarm and protector, checked by scripts/sync-toast-policy.mjs and each smoke.sh): level
prefixes, one washed line of at most 120 characters, 60 s de-duplication, four toasts a
minute per source with errors held and counted, the person's all/important/off setting and
per-source mute (console Settings, mirrored to a file the others read), and a digest of
every toast kept for the console's Events page. All call sites migrated; new toasts for a
mission that finishes or fails and a swarm subagent that fails or a loop that is stuck.

Versions: console 0.37.0, swarm 0.3.4, protector 0.1.1, mods 0.3.16.

Co-Authored-By: RuFlo <ruv@ruv.net>
2026-10-07 12:50:30 -04:00
ruv 1175bc19c9 Merge origin/main into feat/mod-toasts 2026-10-07 12:40:10 -04:00
ruv a65be10ed4 feat(mods): shared toast policy and its call sites (ADR-477), work in progress
Co-Authored-By: RuFlo <ruv@ruv.net>
2026-10-07 12:40:10 -04:00
rUv a0ef9b8ed5 Merge pull request #3887 from ruvnet/feat/console-settings-order
feat(console): Settings: most important first (0.36.1)
2026-10-07 09:12:27 -07:00
rUv 7872e601aa Merge pull request #3559 from MAMDV/fix/plugins-prefer-installed-cli
fix(plugins): run the installed ruflo CLI before `npx @claude-flow/cli@latest` in cost-tracker, adr and metaharness (#3558)
2026-10-07 08:37:03 -07:00
ruv b461822280 fix(console): CONSOLE_VERSION follows the manifest (0.36.1)
Co-Authored-By: RuFlo <ruv@ruv.net>
2026-10-07 11:08:46 -04:00
ruv 5a0e5bff4a feat(console): Settings puts Claude control and spending first, folds ruflo config and plugin options to the end
Co-Authored-By: RuFlo <ruv@ruv.net>
2026-10-07 10:29:40 -04:00
rUv 211a94a27a Merge branch 'main' into fix/plugins-prefer-installed-cli 2026-10-07 07:03:25 -07:00
rUv 57a9755b0b Merge branch 'main' into claude/3633-fix 2026-10-07 07:03:22 -07:00
ruv 38c30b1120 chore(mods): ruflo-mods 0.3.15 so marketplace users receive the #3791-#3805 fixes
The fixes merged in #3873 without a version bump, so 'claude plugin update'
saw no new version.

Co-Authored-By: RuFlo <ruv@ruv.net>
2026-10-07 03:51:38 -04:00
rUv 610a2e1475 Merge pull request #3877 from ruvnet/feat/console-0.36
feat(console): 0.36.0 — Events and Timeline pages: history, sources, severity, query language, lanes, overlays
2026-10-06 23:44:14 -07:00
ruv 1ac200432c feat(console): 0.36.0 integration: eventsPersist option, shared whole-batch append argv, hostile-time hardening, init ignores console/
- plugin.json declares eventsPersist (default true); version 0.36.0 in plugin.json, version.ts, smoke.sh
- data/append-argv.ts: one dd argv (bs=1M iflag=fullblock) shared by the Events store and the autopilot journal; real-dd 8-writer test fails on the old argv
- history decoders and Events/Timeline displays use #3874's timeOf/countOf/isoOf, so a hostile time or count cannot throw
- cli init: .claude-flow/.gitignore template lists console/
- ADR-474 updated to the reviewed behaviour and the open low items

Co-Authored-By: RuFlo <ruv@ruv.net>
2026-10-07 02:19:20 -04:00
ruv 027e180c39 Merge verify/events-0.36 into feat/console-0.36
Conflict in views/manage.ts: #3874 (isoOf) edited eventsView, which the Events work moved to views/events.ts; the move wins and the isoOf clamp is applied at every Events/Timeline site instead.

Co-Authored-By: RuFlo <ruv@ruv.net>
2026-10-07 02:19:20 -04:00
rUv 7ee853ee34 Merge branch 'main' into fix/mods-3791-3805 2026-10-06 23:02:04 -07:00
ruv 7782ccbf60 fix(console): log Claude's refused request when the person's card is waiting; mission-auto why when not wired; document the local-read allowlist
Co-Authored-By: RuFlo <ruv@ruv.net>
2026-10-07 01:06:51 -04:00
ruv e5d887af43 test(ruflo-mods): the /clear rollup record keeps the ending session's rung, the next starts at OK (#3795)
Co-Authored-By: RuFlo <ruv@ruv.net>
2026-10-07 00:58:38 -04:00
ruv 6258d60127 fix(guard): decode $'...' escapes as bash does; adversarial and benign tables for the root-delete guard (#3791)
$'\x2f' and $'\x72m' name the root and rm without any expansion, and a
\' inside $'...' does not close the string. The scanner now decodes ANSI-C
escapes (octal, \x, \u/\U, \c, the single-letter set, NUL ends the string)
in all four copies, and the parity table gains wrapper, flag-spelling,
benign look-alike and documented-limit rows.

Co-Authored-By: RuFlo <ruv@ruv.net>
2026-10-07 00:58:38 -04:00
ruv 93b6870a1d fix(ruflo-mods): trust gate judges a glob or a negation by what it selects (#3801)
The scan reports hook patterns as written, so tool.*, prompt.*, agent.* or
!tool.describe hooked every risky event without matching a RISKY_EVENTS key.

Co-Authored-By: RuFlo <ruv@ruv.net>
2026-10-07 00:58:38 -04:00
Dragan Spiridonov 72c84437d4 fix(ruflo-mods): trust gate treats process.spawn, mcp.call/connect, session.send, config.set, prompt.submit and agent.spawn as risky; names a reload that gains risk (#3787, #3801)
refuse-risky admitted a user-tier mod that ran host commands through
$.process.spawn (process.run was listed) or through any MCP tool via
$.mcp.call, and one that steered every prompt (prompt.submit) or every
subagent (agent.spawn). Observe told the person "no risky calls or hooks".

The risk sets now cover every call in the engine's $ API that reaches
outside the session, and the two hooks from #3787. Observe-mode logging is
keyed on provenance plus the risk set, so a hot reload that gains a risky
call or hook is named again ("and every reload"), and the same risk is not
repeated.

(cherry picked from commit 566bfdc8a20409f763d312e1ae34bcd0fc6c0515)
2026-10-07 00:58:38 -04:00
Dragan Spiridonov 810fb0de48 test(ruflo-mods): pin registeredEvents to what register() hooks across every option combination (#3805)
Adversarial review follow-up: the list test only covered the conditions it
named, and the doc comment claimed smoke.sh guarded drift (it checks names,
not conditions). The matrix test calls register() with a recording on() for
256 option combinations and compares.

(cherry picked from commit d857b4d136)
2026-10-07 00:58:38 -04:00
Dragan Spiridonov fff705bb3a fix(ruflo-mods): capabilityProbe counts session.measure, agent.spawn and plugin.register only where the options hook them (#3805)
registeredEvents() listed them as always registered, so with default options
the probe counted session.measure as "fired" with no ruflo hook running and
listed agent.spawn as "never fired" although the mod never hooked it (and
plugin.register under modTrust: off).

(cherry picked from commit 3a146c08dc)
2026-10-07 00:58:38 -04:00
Dragan Spiridonov 8613d5bdfe fix(ruflo-mods): stand down for legacy CLI hooks route|post-edit settings and check the %USERPROFILE% helper (#3803)
Projects initialised before hook-handler.cjs (e.g. settings-generator at
d7212d25b wrote `npx claude-flow@v3alpha hooks route --task "$PROMPT"`) run
the CLI's own hooks command, which never reads RUFLO_MODS_OWNS. The mod saw
no classic route/post-edit there, owned both, and every prompt was routed
twice (the CLI still prints its block with the handshake set, verified on
3.52.0). A settings hook running claude-flow / @claude-flow/cli / ruflo
`hooks route|post-edit` now makes the mod stand down for that event.

On Windows the generated hook falls back to
%USERPROFILE%\.claude\helpers\hook-handler.cjs; helperHonours now checks it
beside the project root and $HOME.

(cherry picked from commit 4dec48e9f5)
2026-10-07 00:58:38 -04:00
Dragan Spiridonov c79f66e89f fix(ruflo-mods): keep main's Google-key and JWT matches when glued to a dash; no ^ at mid-line window starts (#3798)
Fourth review (differential vs main over 154k inputs): two secret shapes
main caught were missed after the earlier tightening - a Google key glued to
"-suffix" (the trailing lookahead rejected it; \b now also ends it) and a
JWT after a '-' (the new lookbehind; the rule now starts at the first eyJ
after a '-' or the run start, still once per run and linear). A later window
that starts mid-line gets a lead character so ^ cannot treat a benign
"system:" there as a role tag. Inbound and outbound now build the windows
once and pass them to scanWindows(). Two tests (each fails on the previous
head); corpus unchanged.

(cherry picked from commit 5e9cec209c)
2026-10-07 00:58:38 -04:00
Dragan Spiridonov 0e505ffcef fix(ruflo-mods): screen three readings so stripping or folding never glues a phrase to the word before it (#3798)
Third review: stripping every default-ignorable character and NFKC folding
joined what followed to the word before it, so a leading \b or lookbehind
failed: "x" + soft hyphen + "Ignore all previous instructions", a circled
digit before AKIA..., and a zero-width space before an SSN all passed, where
main caught them (129 of 1,093 sampled inputs).

windows() now screens three readings: the folded one, main's literal one
(only its original invisible set removed) and a spaced one (invisible
characters become spaces), each whitespace-collapsed and windowed, so cost
stays linear. The role-tag rule is back to main's \s* (linear after the
collapse; it caught "system\n:"), and the key rule accepts doubled or mixed
separators again (my--token=). One test pins seven of these cases; it fails
on the previous head.

(cherry picked from commit 000f677c36)
2026-10-07 00:58:38 -04:00
Dragan Spiridonov 6f88e5e9ae fix(ruflo-mods): screens stay linear on blank lines and repeated token starts; whitespace padding cannot straddle a window (#3798)
Second review: once the whole text is screened, two older rules that were
only ever run on a 20k prefix became the cost: `fake role tags` (^\s* with
m) is quadratic on runs of newlines (1 MB of "\n": 16.8 s) and `jwt` (\beyJ)
restarts at every '-' ("-eyJ" x 1 MB: 8.2 s). Unbounded \s in shell pipe,
key assignment and bearer also let padding carry a match across a window.

- bare() collapses each whitespace run to one space or newline before
  windowing (linear; screening only tests text, never returns it).
- jwt starts once per token run; the anchored role-tag half uses [ \t].
- key assignment accepts a CLI flag prefix again (--password=, --token=),
  which main caught.
Three tests pin these (1 MB of blank lines and "-eyJ" under 1.5 s, a pipe
padded with 1.1k-25k spaces at window boundaries, CLI flags); each fails on
the previous head.

(cherry picked from commit 2ffd534404)
2026-10-07 00:58:38 -04:00
Dragan Spiridonov e281da31a4 fix(ruflo-mods): key-assignment rule is linear and ends at the credential name; windows start at whitespace (#3798)
Adversarial review of the previous commit:
- the suffix group after the keyword backtracked against it: 1 MB of
  'token_' took 6.4 s through scan() (10 MB: 71 s), and with the 20k cap gone
  a peer controlled the input. The keyword must now end the name, optionally
  followed by _key / _access_key; 1 MB of 'token_' screens in milliseconds.
- the same group flagged config names that only start with a keyword
  (TOKEN_URL=, MAX_TOKENS=, session_token_ttl=, CREDENTIALS_FILE=); those
  pass again, and an all-digit value is no longer a credential.
- a later window began mid-word, so its lookbehind, \b and ^ saw a false
  start of text ('q' * 18976 + 'secret=...' was refused, unpadded it passes).
  Later windows now start after whitespace within 256 characters; the 1,024
  overlap still covers every rule.
Three tests pin these; each fails on the previous head.

(cherry picked from commit 60a5f05340)
2026-10-07 00:58:38 -04:00
Dragan Spiridonov 3a3f8c3a61 fix(ruflo-mods): screen the whole text, strip every default-ignorable character, catch more secret shapes (#3798)
The shared screen behind deliveryScreen, compactCarry and guidance safeText:

- scanned only the first 20,000 characters, so padding pushed an injection
  or a secret past it. It now scans the whole text in overlapping 20k
  windows (1k overlap, far longer than any rule spans): still linear.
- stripped a fixed list of invisible characters. It now strips every
  default-ignorable code point (soft hyphen, CGJ, Mongolian VS, variation
  selectors, bidi isolates, tags) plus C0/C1 and line/paragraph separators,
  then NFKC-folds fullwidth forms.
- missed GITHUB_TOKEN= / aws_secret_access_key = / "client_secret": (the
  keyword inside an _ or - separated name), PGP armored private keys, Google
  keys ending in '-', and Slack xapp- tokens.

delivery/screen.ts reuses the shared windows instead of its own copy of the
invisible set and the 20k slice. The 50/50 acceptance corpus is unchanged
(50/50 caught, 1/50 benign flagged, as before).

(cherry picked from commit b1cc41c887)
2026-10-07 00:58:38 -04:00
Dragan Spiridonov 42424201c6 fix(ruflo-mods): /resume also gives the next session its own rollup record; redraw after the budget reset (#3795)
Re-review follow-ups: the engine contract says the process also goes on
under another session after a resume (no session.start), so the rollup
resets on reason resume as on clear (new test). The cost reset stays on
clear only until /resume cost behaviour is measured live. The cost reset
now redraws the status line, which otherwise showed the old rung until the
next prompt.

(cherry picked from commit 927799ae24)
2026-10-07 00:58:38 -04:00
Dragan Spiridonov c486e0ec26 fix(ruflo-mods): reset per-session state on session.end(reason: clear), not session.start (#3795)
Adversarial review: the engine contract (2.1.289 types) says session.start
fires once per process or fresh load, "never /clear"; /clear is seen as
session.end with reason clear and no session.start follows. The previous
commit reset on session.start, so it never ran on a real /clear, and its
tests faked one with an `as never` cast.

- rollup: after writing the ending session's record, a clear resets the
  counters and the written flag, so the next session gets its own record.
- cost: a session.end matcher on reason clear restarts the ladder and the
  hard stop. Registered after the rollup, which records the rung first. Any
  other end reason keeps the hard stop (new test).
- tests replay the real sequence: session.end(clear), work, session.end.

Live (2.1.289, --plugin-dir, tmux): prompt, /clear, prompt, /exit now writes
two ledger records; main writes one.

(cherry picked from commit 3630744aea)
2026-10-07 00:58:38 -04:00
Dragan Spiridonov ffd882365e fix(ruflo-mods): rollup and budget start over at each session.start, so /clear gets its own session (#3795)
/clear ends a session and starts the next in the same process without
re-running register, so the process-scoped state carried over:

- sessionRollup set `written` once and never reset it, so every session after
  the first /clear went unrecorded (measured live on 2.1.289), and its
  counters accumulated. The rollup now resets on session.start and records
  routed/tightened as this session's share.
- the cost ladder kept the previous session's announced rung and HARD_STOP
  level, though the engine counts the new session's cost from zero
  ($0.07 -> $0.06 across /clear, measured live). The ladder and the hard stop
  now start over at session.start; within a session a rung is still told once.

The engine refuses a second matcher-less session.start, so the cost hook uses
the same match-everything surface matcher as the rollup hook.

(cherry picked from commit 0f9f1b99f2)
2026-10-07 00:58:38 -04:00
Dragan Spiridonov 061efa3b40 fix(ruflo-mods): the observation queue and a quoted path no longer read as "missing" (#3793)
Adversarial review follow-ups in the same class:
- flushObservations read and parsed in one try and applied isMissing to the
  parse error, so a corrupt queue quoting ENOENT was overwritten, against its
  own "corrupt bytes are never replaced". Read and parse are separate now.
- isMissing matched ENOENT anywhere in the message, including the quoted
  path (a project under .../ENOENT-x/). It now takes the path and ignores
  it; cachedFile and the queue pass theirs.

(cherry picked from commit 5044d007f3)
2026-10-07 00:58:38 -04:00
Dragan Spiridonov f661b83585 fix(ruflo-mods): a parse error that quotes "ENOENT" no longer reads as an absent projection (#3793)
cachedFile applied isMissing() to parse() exceptions as well as to the
fs.read rejection. JSON.parse and parseProjection both put the file's own
text in their message, so an enforced policy projection containing "ENOENT"
(torn JSON, a stray log line, version: "ENOENT") read as "no policy" and the
guard allowed what the rule denies. Only the read may say absent now; every
parse failure is an error, so the guard fails closed as ADR-450 T10 says.

(cherry picked from commit 5a0a5a4cf9)
2026-10-07 00:58:38 -04:00
Dragan Spiridonov 5ae95050c7 fix(guard): a quoted empty substitution leaves the word as bash does; # after it stays in the word (#3791)
Real-bash oracle (bwrap, read-only root, logging fake rm; positive controls
detected) over a 63,696-command differential between main and this branch:
- a substitution inside double quotes is now dropped from the word, as its
  empty output is, so "`true`"-rf reads as -rf; a placeholder is kept only
  when a # follows, so bash -c "`true`#x; rm -rf /" is still read as one
  word and caught;
- 1,260 commands main denies and this branch allows: 0 really delete
  (bash parses each differently than main assumed);
- of 1,500 sampled commands this branch allows with a root operand, the
  201 that really delete are all $(...) substitutions (stated follow-up, 189)
  or $- expansions inside sh -c (12); main misses every one too.
Three parity rows added (309 pass). All four copies alike; the generator's
String.raw source keeps no backtick in comments.

(cherry picked from commit 4f2ac8ba28)
2026-10-07 00:58:38 -04:00