Commit Graph
6 Commits
Author SHA1 Message Date
dsh-slopo agent 5ff10eaefd Background only the warm-up, and use the framework's own parameter name
The tool backgrounded EVERY long action and exposed an inverted `foreground`
flag. dsh-tool-bash does neither: its parameter is `run_in_background`, it
defaults to foreground, and the model opts in. That difference is what made a
finished job go uncollected.

The evidence, from this session's own log: the only slopo job that ever ran was
slopo-1, and the agent KILLED it — `kill()` sets `reported = true`, which
suppresses the completion notice by design, because a caller who asked to stop
something does not want to be told it stopped. The agent then worked around the
tool entirely and re-ran slopo through bash, which is where the six notices in
that session came from. Nothing was broken; the tool was asking the caller to
depend on a best-effort signal.

So the query actions return their report directly. Only `prepare` — index plus
embed, the genuinely long and watchable step, and the one the user asked to be
able to watch — backgrounds by default. Any action can still be backgrounded
with `run_in_background: true`.

The render now names the collect call explicitly (`job_output` for that id, with
`wait: true` when blocked on it) instead of the vaguer "read the job output when
it settles", so a caller that is not woken still has an unambiguous next step.

I checked the waiter path while I was in there: a timed-out `wait` decrements
`waiters` in a `finally`, so it does not leak and does not suppress the notice.
That was my first hypothesis and it is wrong — worth recording, since it was the
plausible one.
2026-09-22 13:30:55 +01:00
dsh-slopo agent 2d7a7d1e73 Make the settings card behave like the other plugin cards
It rendered as a flat, always-open block with no header. The framework's card
chrome is a disclosure: the tab renders every card into a <ul>, each card's root
is an <li>, its header is its own <button> that discloses the controls in place,
it starts collapsed, the header marks it when it holds unsaved edits, and a save
that lands folds it back up.

Three things were wrong and only one of them was cosmetic:

  * the root was a <div> inside the tab's <ul>, so the list and card styling
    never reached it
  * there was no header button, so no disclosure and no aria-expanded
  * nothing marked unsaved edits, and nothing collapsed after a save

`PluginCard` is not importable — it lives in that package's client bundle, and
the client purity gate forbids cross-plugin value imports — so the behaviour is
reproduced rather than borrowed, with inline styles for the same reason.

The collapse-on-save originally lived in an effect watching a `saving` flag, which
is how the shipped card does it because its form state comes from a controller.
This card awaits its own writes, so it already knows the save landed; collapsing
directly in the success path is simpler and is what the tests can actually reach.
A failed save still keeps the card open with its drafts.

Tests cover the disclosure itself: the root element, collapsed-by-default, the
header's aria-expanded and label, that staged edits survive collapsing, and that
a landed save folds the card up.
2026-09-22 13:26:29 +01:00
dsh-slopo agent 6b9d91b436 Document what gets indexed, with the measured numbers 2026-09-22 13:23:49 +01:00
dsh-slopo agent 534efa8b50 Document the settings card and the status pre-flight
Including the part that matters operationally: a client half's bytes are
snapshotted at activation, so the card only appears after the profile restarts.
Without it the namespace still works — settings.yaml and the `configure` action —
there is simply no form drawn.
2026-09-22 07:22:03 +01:00
dsh-slopo agent e758a723e2 Fix: the tool substituted the deployment sandbox default for the session's
dsh-bash-sandbox is the composed ctx.shell, and its resolve() stamps
`request.sandboxPolicy ?? ctx.sandboxPolicy.resolve()`. Omitting the policy
therefore does NOT mean "unconfined" -- it silently substitutes the DEPLOYMENT
default (`DSH_PERMISSION_MODE ?? 'workspace-write'`) for the session's preset.
On a host with no sandbox runner that confines a danger-full-access session and
fails with SandboxUnavailableError before slopo is ever reached, which is
exactly what happened: the tool was unusable while bash worked.

Resolve the calling session's policy the way dsh-tool-bash does, and pass it on
every call. A confining executor with no ctx.sandboxPolicy is now refused
outright rather than guessed at.

That fix exposes a second problem worth naming. Slopo's state lives under
$DSH_HOME, which is outside the workspace root a workspace-write sandbox permits
writing to, so under that preset nothing would work. The tool now refuses before
running and names both ways out -- run under danger-full-access, or set stateDir
to a directory inside the workspace -- instead of letting a write fail halfway
through an embed.

Five tests pin this: the session's policy is resolved exactly once and travels
with the session, a missing policy service is refused, state outside the sandbox
is refused before any execution, state inside it proceeds, and status/configure
never touch the shell at all.
2026-09-22 07:12:03 +01:00
dsh-slopo agent a8e577ae38 Document dsh-slopo, including the traps that cost real time
The provider prefix is not cosmetic: the openai/ prefix makes LiteLLM apply
OpenAI parameter validation to any model behind it, and slopo always passes
dimensions, so a local OpenAI-compatible server needs its own prefix.

Five settings are frozen into the database at first index, so changing the
embedding model means re-embedding everything. And a review cannot bootstrap the
database at all, because agent-review opens the index read-only.
2026-09-22 06:11:17 +01:00