Commit Graph

1285 Commits

Author SHA1 Message Date
Mohamed Boudra
059d543c97 refactor(server/tests): clear 146 type-aware lint errors in session tests (T1.a) (#753)
Replace `as unknown as SessionOptions["X"]` call-site casts with typed stub
helpers from a new `test-utils/session-stubs.ts` module. Unsafe assertions
are now contained to that single infrastructure file, keeping all call sites
in the two fully-fixed test files clean.

Files fully fixed (typeAware: true → 0 errors):
- session.workspaces.test.ts: 119 → 0
- session.test.ts: 27 → 0

Helpers added in session-stubs.ts:
- asSessionLogger / asAgentManager / asAgentStorage / asDownloadTokenStore /
  asPushTokenStore / asChatService / asScheduleService / asLoopService /
  asCheckoutDiffManager / asDaemonConfigStore / asTerminalManager /
  asGitHubService / asWorkspaceGitService / asScriptRouteStore /
  asWorkspaceScriptRuntimeStore
- asSessionInternals<T> for private session access
- filterByType / findByType message helpers
- createProviderSnapshotManagerStub returning typed spy refs
2026-05-05 19:58:56 +07:00
Mohamed Boudra
eb16829f51 refactor(server/tests): replace unsafe type assertions with Reflect + Zod (T1.b partial) (#752)
Cluster T1.b — first wave of no-unsafe-type-assertion fixes across agent
provider and MCP test files. Clears all type-aware lint errors in 6 files;
remaining 4 files (class-mock patterns) deferred to T1.b2.
2026-05-05 19:58:56 +07:00
Mohamed Boudra
b1d3867da9 refactor(server): parse daemon/ws/wire test responses with Zod (T1.c typeaware sweep) (#750)
Fixes all reachable typescript-eslint(no-unsafe-type-assertion) errors
in the four in-scope test files by:
- Adding Zod schemas (WireEnvelopeSchema, BinaryFrameSchema,
  RuntimeMetricsLogSchema) and helpers (parseSentEnvelope, parseSentFrame,
  assertStr) to parse wire frames instead of casting JSON.parse() results
- Replacing `JSON.parse(x) as { ... }` with Zod-validated helpers
- Replacing `mock.sent[N] as string` / `String(mock.sent[N])` with assertStr()
- Replacing `frame as Uint8Array` with direct type annotation (Buffer extends Uint8Array)
- Replacing `session.args.onMessage as (() => void) | undefined` with typeof
  function guard and direct invocation
- Replacing `metricsCall![0] as RuntimeMetricsLog` with RuntimeMetricsLogSchema.parse()

Remaining `as unknown as SomeClass` patterns in constructor mocks and
`client as unknown as { ... }` internal-access patterns are out of scope:
they require extracting interfaces from concrete classes (AgentManager,
AgentStorage, FileBackedChatService, etc.) with private members, or
refactoring the client API to expose internal methods — neither is safe
to do in a test-only sweep.
2026-05-05 19:58:56 +07:00
Mohamed Boudra
006a79ed01 refactor(app/relay): parse test responses with Zod (T1.d typeaware sweep) (#749)
Replace unsafe type assertions with Zod schema parsing:
- app/utils/project-config-form.test.ts: Use PaseoConfigRawSchema.parse()
  instead of 'as unknown as PaseoConfigRaw' (~10 errors fixed)
- server/daemon-e2e/relay-transport.e2e.test.ts: Use ConnectionOfferSchema
  and WSOutboundMessageSchema.parse() instead of inline type casts (~8 errors fixed)

Deferred to follow-up cluster (architectural decisions needed):
- host-runtime.test.ts: FakeDaemonClient mock needs proper interface
  implementation (requires source file changes)
- cloudflare-adapter.test.ts: WebSocket/DurableObjectState mocks need
  design review (external Cloudflare types)

Target rule: typescript-eslint(no-unsafe-type-assertion)
Errors cleared: 18/76 in cluster (61 deferred)
2026-05-05 19:58:56 +07:00
Mohamed Boudra
75247efbd5 refactor(agent-providers): fix type-aware lint errors in diagnostic-utils and generic-acp-agent (#705)
* refactor(agent-providers): add type guards and fix type-aware lint errors in diagnostic-utils, generic-acp-agent, and tool-call-detail-primitives

* fix(server): defer PTY onExit to allow pending data events to fire

On Linux, node-pty's onExit callback can arrive before the last buffered
PTY data chunk is delivered via onData. Wrapping finish() in setImmediate
gives libuv's I/O poll phase a chance to flush remaining PTY reads before
the promise resolves, preventing tail bytes from being silently dropped.

Fixes a flaky worktree-bootstrap test that reliably reproduced on Linux CI.

* unslop: remove dead guard, fix import order, trim comment

- generic-acp-agent: remove isNonEmptyStringArray and its guard; the
  constructor parameter is already typed [string, ...string[]] so the
  check can never fire
- provider-registry: move isNonEmptyStringArray below the import block
  instead of between two import groups
- worktree: condense 3-line comment to one line per project convention
2026-05-05 19:58:55 +07:00
Mohamed Boudra
c8274ba88a refactor(claude-agent): replace unsafe type assertions with type guards (#707)
Adds isObjectRecord, isUnknownArray, isChildProcessWithStreams, and
isImageMimeType type predicates to eliminate all no-unsafe-type-assertion
violations surfaced by typeAware lint mode. Fixes floating promise, adds
throw after exhaustive switch, and widens readCompactionMetadata to accept
unknown so callers need no casts.
2026-05-05 19:58:16 +07:00
Mohamed Boudra
8b54d27cbc refactor(server): add getErrorMessage helper and fix error-related type-aware lint errors (#704)
* refactor(server): add getErrorMessage helper and fix error-related type-aware lint errors in session.ts

* fix build: correct parseClientCapabilities type handling
2026-05-05 19:57:35 +07:00
Mohamed Boudra
d359bffed5 refactor(agent-providers): add toObjectRecord helper and fix type-aware lint errors in codex and claude agents (#699) 2026-05-05 19:57:35 +07:00
Mohamed Boudra
b2c88e4312 refactor(speech): add ONNX type augmentation and fix type-aware lint errors (#701) 2026-05-05 19:56:52 +07:00
Mohamed Boudra
ab9f07dd8a fix(app): make e2e setup an auto fixture so first-of-spec tests get setup (#702)
* fix(app): make e2e setup an auto fixture so it runs for the first test of every spec

The fixtures.ts beforeEach was declared at the top level of a non-test
fixture file. Playwright sometimes skipped it for the first test of a
subsequent spec when multiple specs ran in the same worker — that test
hit page.evaluate without the seed nonce or daemon registry in
localStorage and failed (then passed on retry, masking the bug behind
retries: 1). Reproduced locally by running sidebar-workspace then
startup-loading: the first startup-loading test got no fixture setup
and threw "Expected e2e seed nonce".

Move the setup into an `auto: true` fixture, the canonical Playwright
pattern for running setup for every test in a workspace. The afterEach
console-attachment is folded into the same fixture's teardown.

* refactor(server): simplify nullish handling in workspace-git-metadata

Drop the explicit `null` arg in `deriveProjectSlug(input.cwd, null)` —
the second parameter already defaults to `null`. Inline the
`repoName && repoName.length > 0` check in `parseGitHubRepoNameFromRemote`
since `pop()` on a non-empty array returns a non-empty string here, and
`|| null` covers the empty-string case directly.
2026-05-05 19:56:52 +07:00
Mohamed Boudra
400934f19c schedule: add paseo schedule update to edit schedules in place (#694)
* schedule: add `paseo schedule update` to edit schedules in place

Editing a schedule today requires delete+recreate, losing run history
and the schedule id. This adds an additive RPC and CLI command that
patches name, prompt, cadence, new-agent target fields, max-runs, and
expires-in without touching runs or in-flight executions. nextRunAt is
recomputed only when the cadence actually changes.

* schedule(cli): share cadence flag parser between create and update

Both paths were turning --every/--cron into a ScheduleCadence with
near-identical code. Extract `parseCadenceFromFlags` so the literals
and the exclusivity check live in one place; create wraps it to
require a value, update lets it stay optional.
2026-05-05 19:56:52 +07:00
Mohamed Boudra
82cf11aaae fix(server): derive non-GitHub project display names from remote owner/repo (#697)
Reconciliation overwrote correctly-set project display names with the
directory name for non-GitHub remotes (e.g. gitlab.com/acme/app), because
buildWorkspaceGitMetadataFromSnapshot only handled GitHub URLs while the
registry-model layer used the more general deriveProjectGroupingKey path.
Reuse that path here so both layers agree on the owner/repo display name.
2026-05-05 19:56:52 +07:00
Mohamed Boudra
84d822450e refactor(server): remove unnecessary String() conversions from type-aware lint fixes (#695) 2026-05-05 19:56:52 +07:00
Mohamed Boudra
cccccca18e refactor(server): remove redundant null from unknown union types (#693) 2026-05-05 19:56:52 +07:00
Mohamed Boudra
946152d820 refactor(server): replace JSON.parse type assertions with Zod validation (#691)
Replace unsafe 'JSON.parse(content) as Type' patterns with proper Zod schema
validation. This fixes type-aware lint errors and provides runtime safety.

- pid-lock.ts: Add pidLockInfoSchema and parsePidLockInfo helper
- package-version.ts: Add packageJsonSchema and parsePackageJson helper
- relay-transport.ts: Add isRecord type guard to avoid unsafe type assertion
2026-05-05 19:56:51 +07:00
Mathias Kurz
44d13919d7 Feat/open projects config to any (#681)
* feat(server): derive owner/repo display name for any remote host

Generalize deriveProjectGroupingName so any remote:<host>/<segments...>
project key returns the last two path segments (owner/repo) instead of
just the trailing segment. Path-fallback for non-remote keys is unchanged.

Brings GitLab, Gitea, Bitbucket, and self-hosted remotes to parity with
the prior github.com-only behavior — no separate special-case needed.

* feat(app): show projects from any git remote in Projects settings

Remove the isSupportedProjectKey filter so workspaces with non-GitHub
remotes (GitLab, Gitea, Bitbucket, self-hosted, ssh-style) appear in the
Projects list and route to the project settings screen. The daemon RPCs,
config schema, and registry were already host-agnostic; this lifts a
client-side filter that hid them.

Also remove the now-vestigial hiddenUnsupportedRemoteCount field from
ProjectSummary, BuildProjectsResult, and UseProjectsResult — once the
filter is gone, the count is always zero and the field is dead state.
This is an internal app-package type, not a wire schema, so deletion is
safe.

* chore(app): simplify Projects empty state to "No projects yet"

Drop the "Non-GitHub remote projects aren't supported yet" empty-state
branch — it can no longer fire now that any git remote is shown. The
empty state is unconditional now.

* test(app): cover non-GitHub remote in projects-settings e2e

Add a fixture that creates a temp git repo with origin pointing at a
gitlab.com URL and exercises the same paseo.json read/edit/save flow
already covered for local repos. Verifies the project surfaces with the
"acme/app" display name and that the round-trip persists correctly.

Extracted the remote-setup branch in createTempGitRepo into a small
configureRemote helper to keep the main function under the cyclomatic
complexity limit.

---------

Co-authored-by: Mathias Kurz <mkurz@stamus-networks.com>
2026-05-05 19:56:51 +07:00
Mohamed Boudra
2b6d7d4ec2 schedule: fire --every now by default, add run-once for cron-style triggers (#689)
Interval schedules used to wait the full interval before their first run, which
made `--every 1d` feel broken for fresh schedules. Now `--every` fires
immediately on creation; `--cron` keeps waiting for the next slot. `--no-run-now`
and `--run-now` override the defaults, and the parser rejects redundant combos.

Adds `paseo schedule run-once <id>` to manually trigger a single run without
advancing cadence or recomputing completion. The new `runOnCreate` field and
`schedule/run-once` RPC are additive on the WebSocket schema.
2026-05-05 19:56:51 +07:00
Mohamed Boudra
f11aea3223 mcp(create_agent): validate mode and refuse silent cross-provider inheritance (#688)
The MCP create_agent tool inherited the parent agent's mode regardless of
provider, so a Claude parent in bypassPermissions spawning an opencode
child would feed an invalid mode to opencode and the new agent would die
in error state. The fix:

- Add an optional mode field to the agent-to-agent input schema.
- Validate any explicit mode against the target provider's available
  modes; throw with the list when invalid.
- Inherit the caller's mode only when both sides use the same provider;
  otherwise refuse with a helpful error listing the target's modes.
2026-05-05 19:56:51 +07:00
Mohamed Boudra
e22b497a08 voice: quieter thinking tone, log cleanup, and small ui polish
- Add scripts/lower-thinking-tone.mjs to scale the thinking-tone PCM
  amplitude in-place; apply it at 0.1 so the cue is a soft indicator
  instead of triggering the VAD via mic feedback.
- Drop the "Received first voice_audio_chunk" log that re-fires every
  summary window because the chunk counter is reset.
- Match Spoke message icon and label sizing to the standard tool-call
  badge.
- Append a spoken-input instruction so voice replies route through the
  speak tool.
2026-05-05 19:56:51 +07:00
Mohamed Boudra
91865ba66e Switch voice turn controller to streaming transcription 2026-05-05 19:56:51 +07:00
Mohamed Boudra
4d31cd4013 fix(opencode): forward provider retries instead of swallowing them
OpenCode subproviders (e.g. opencode/kimi-k2.6 on OpenCode Zen) emit
session.status:retry events with messages like "Internal server error"
when the upstream provider returns 5xx. opencode itself retries
indefinitely with backoff and never emits a terminal event for these.

Previously the adapter only surfaced retry messages on a small allowlist
of "fatal" tokens (insufficient balance, invalid api key, etc.) and
silently dropped everything else. The agent appeared hung from the
user's perspective — no message, no spinner update, nothing — until the
upstream eventually recovered or the user manually interrupted.

Forward every session.status:retry as a non-terminal timeline error
item so the user can see what opencode is doing, mirroring opencode's
own TUI. Drop the fatal-token allowlist: classifying which retries are
"really" terminal is opencode's job, and synthesizing turn_failed for
ones we guess at is misleading anyway because opencode keeps spending
upstream while we tell the user the agent is done.

Also a small design pass on the timeline error rendering:
- drop the redundant "Agent error" prefix (the message is descriptive)
- drop the colored box background (visual weight too high for a retry)
- align the icon vertically to the first text line (height+center)
- make the message text selectable so users can copy errors
2026-05-05 19:56:51 +07:00
Mohamed Boudra
0775f59a6f Add --mode to schedule and loop CLI, default background runs to unattended mode
Plumb --mode/--verify-mode through paseo schedule create and paseo loop run.
Mark each provider's unattended mode (claude bypassPermissions, codex/opencode
full-access, copilot autopilot) so loop and schedule services pick it by
default when no explicit modeId is given.
2026-05-05 19:56:26 +07:00
Mohamed Boudra
4cd9e76bd2 Remove unnecessary type assertions across codebase
Add oxlint-tsgolint and configure typescript/no-unnecessary-type-assertion
to flag redundant `!` and `as Foo` casts. Type-aware mode is left off by
default to keep `npm run lint` fast; the rule sits configured for when we
turn type-aware on intentionally. Auto-fix removed ~283 redundant casts;
two manual touch-ups: a real tsgolint false positive in split-container.tsx
and a stale ChildProcess import after a double-cast collapsed.
2026-05-05 19:56:26 +07:00
Mohamed Boudra
78fe3e4df3 Drop subagent task notifications from parent timeline
Subagent task_notification system messages arrive without
parent_tool_use_id but with tool_use_id pointing at the parent's Task
call, so they slip past the sidechain router and render as top-level
"Task Notification" rows in the parent's timeline. Skip them when the
referenced tool_use is a Task call; parent-level background bash
notifications still flow through.
2026-05-05 19:56:26 +07:00
Mohamed Boudra
1e5e17f000 chore(release): cut 0.1.69 2026-05-05 19:40:12 +07:00
Mohamed Boudra
fd4e26ca9b Align script TypeScript lib with server build 2026-05-05 18:54:29 +07:00
Somasundaram Ayyappan
f89e5604d2 fix: normalize Claude AskUserQuestion answers (#755) (#760)
Translate Paseo's header-keyed AskUserQuestion answers into the full question-text keys Claude expects before resolving question permissions.

Also preserve the original question payload when UI callbacks return an answers-only updatedInput, and lock the behavior down with provider-flow regression coverage in claude-agent tests.
2026-05-05 19:50:34 +08:00
Mohamed Boudra
ca3e55813e Keep daemon worker supervision explicit 2026-05-05 18:48:07 +07:00
Mohamed Boudra
3fad128d02 Restart daemon worker crashes in production 2026-05-05 18:42:21 +07:00
Mohamed Boudra
0cb9da17cd Daemon hardening epic 2026-05-05 18:21:10 +07:00
Mohamed Boudra
84478a2dba chore(release): cut 0.1.68 2026-05-05 16:46:10 +07:00
Mohamed Boudra
15a2e3bdcb chore(release): cut 0.1.67 2026-05-04 01:43:24 +07:00
Mohamed Boudra
cf1f849b68 Update MCP create_agent test to match async branch auto-name
7c85341a moved first-agent branch auto-naming out of the worktree
service (sync slugify) into the workflow layer (async LLM call).
The MCP test stubs createPaseoWorktree, bypassing the workflow,
so the placeholder mnemonic branch is never renamed at this layer.
Replace the obsolete sync-slugify outcome assertion with a
placeholder-presence check; the auto-name logic itself is covered
in worktree-branch-name-generator.test.ts.
2026-05-04 00:31:33 +07:00
Mohamed Boudra
12fcfe53eb Make structured response generation ephemeral end-to-end
Plumbs persistSession through the structured response pipeline so
metadata, branch name, commit message, and PR text generators no
longer leave provider-side artifacts behind:

- Codex: passes ephemeral: true on thread/start (no rollout file)
- OpenCode: deletes the session via session.delete on close
- Claude: forwards persistSession: false to the SDK query

Adds a real-credentials e2e test per provider that asserts the
generated title is applied AND no persistence artifact is produced
(rollout for Codex, project JSONL for Claude, leftover session for
OpenCode).
2026-05-04 00:10:50 +07:00
Mohamed Boudra
7c85341a42 Fix worktree creation and archive flow
Server: drop the synchronous branch-name generator dep, use the
worktree slug as the initial branch, and move first-agent branch
auto-naming to an async post-creation step backed by a structured
LLM call. Guards against renaming when the placeholder branch has
already been changed.

App: make workspace and worktree archive optimistic, rolling back
the local hide if the daemon call fails, and suppress incoming
workspace upserts while an archive is pending.
2026-05-03 23:22:54 +07:00
Mohamed Boudra
221b6665a0 chore(release): cut 0.1.66 2026-05-03 20:48:53 +07:00
Mohamed Boudra
0aa4868b31 Fix terminal DSR replies 2026-05-03 19:24:30 +07:00
Mohamed Boudra
38c1b08433 chore(release): cut 0.1.65 2026-05-03 17:20:28 +07:00
Mohamed Boudra
2faacc59f1 chore(release): cut 0.1.65-beta.5 2026-05-03 13:58:46 +07:00
Mohamed Boudra
65cfe4bda4 Reduce agent timeline focus catch-up 2026-05-03 13:57:48 +07:00
Mohamed Boudra
fa20f313d3 Simplify workspace reconnect gating 2026-05-03 13:50:20 +07:00
Mohamed Boudra
b2247450f9 Fix terminal snapshot flushing 2026-05-03 13:25:19 +07:00
Mohamed Boudra
d89ecae615 fix(server): clean up OpenCode process trees
Spawn the shared OpenCode server in its own POSIX process group and terminate provider child process trees with graceful timeout escalation before forcing SIGKILL. Reuse the same helper for Codex app-server cleanup so process-tree behavior is covered consistently across providers.

Add cross-platform unit coverage for macOS/Linux process groups, Windows taskkill cleanup, and timeout escalation. Add the process-tree test to the Windows-critical CI allowlist; Linux full server tests already include it.

Refs #227
2026-05-02 21:44:59 +07:00
Mohamed Boudra
d06e3e9494 chore(release): cut 0.1.65-beta.4 2026-05-02 20:41:37 +07:00
Mohamed Boudra
b7802ae271 chore(release): prep 0.1.65-beta.4 changelog
Update CHANGELOG.md in place per beta policy and add a compat note on the
`sub_agent.actions` field flagging it as drop-on-cleanup once clients
<= 0.1.65-beta.3 are out of the field.
2026-05-02 20:40:41 +07:00
Mohamed Boudra
d53d601043 refactor(server): inline client capability parsing
With capability negotiation in place, the consumer-side tolerance pattern is unnecessary. Drop the dead readDeclaredClientCapabilities helper, inline the parsing in ClientCapabilities.fromHello, delete a tautological assertion in the relay reconnect test, and document the compatibility rules in architecture.md.
2026-05-02 20:30:25 +07:00
Mohamed Boudra
ca318f29cf feat(client): advertise reasoning merge capability 2026-05-02 20:30:25 +07:00
Mohamed Boudra
ee1c7e6956 test(server): pin wire compatibility regressions 2026-05-02 20:30:25 +07:00
Mohamed Boudra
e3e1c08525 fix(server): restore wire compatibility for old clients 2026-05-02 20:30:25 +07:00
Mohamed Boudra
906205f97a Add browser pane element picker (#670)
* feat: add browser pane element picker

Port the browser pane from PR #198 and route picked elements through workspace attachments so the context follows every agent composer in a workspace.

Co-authored-by: Jason Kneen <jason.kneen@bouncingfish.com>

* docs: document electron platform overlays

* fix: harden browser pane navigation

* fix: polish browser tab interactions

* fix: route browser pane focus shortcuts

---------

Co-authored-by: Jason Kneen <jason.kneen@bouncingfish.com>
2026-05-02 19:28:40 +08:00