Promote v1.0.0 to production#351
Closed
mrubens wants to merge 69 commits into
Closed
Conversation
* Move environment setup into regular task * Fix onboarding setup task handoff * ui * Improve onboarding environment handoff * Fix onboarding rebase fallout * Remove stale setup bootstrap helper * Guide users to their first task after setup * env creation task UX * Fix onboarding completion footer validation
* feat: add local docker sandbox toggle * fix: place local docker toggle in provider section * fix: preserve sandbox exclusions * fix: preserve provider exclusions in launch lookup * test: cover sandbox exclusion preservation --------- Co-authored-by: Roomote <roomote@roomote.dev>
* copy tweak * Skip sandbox setup for env configured providers * copy/logo * ui * Update communication connection onboarding * ui * Fix Teams onboarding copy lint * Fix onboarding lint warnings * Remove unused onboarding wordmark * fixes * Add Teams advanced setup config toggle * Fix stale PR test expectations * Resolve compute setup rebase conflict * Address Teams setup feedback
Co-authored-by: Matt Rubens <2600+mrubens@users.noreply.github.com>
* Add shared communication provider factories Hoist the ad-hoc Teams/Telegram adapter construction into shared runtime-credential factories in @roomote/sdk/server: - New createTelegramCommunicationProviderFromRuntimeCredentials (resolves the bot token from env or settings-UI values) replacing five duplicated resolve-check-construct blocks across the API handlers, bullmq jobs, and comms settings. - createTeamsCommunicationProviderFromRuntimeCredentials now accepts extra provider options (graphTokenProvider, serviceUrl) so the Teams delegated-Graph path uses the shared factory too. Behavior note: PR-review Telegram notifications previously read the bot token from process env only; via the shared factory they now also honor a token saved from the comms settings UI, matching every other Telegram outbound path. Groundwork for routing automations through the provider-agnostic communication adapters. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Fix test mocks for the shared Telegram provider factory Two api test files not covered by the first pass mocked @roomote/sdk/server (or its module graph) without the new factory: slack-reaction-add now stubs it, and submitAutomationWorkItems mocks the automation-work-items telegram module like its teams sibling so the sdk server barrel stays out of the test module graph. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* Add generic communication adapter dispatch getCommunicationProviderAdapter(provider) in @roomote/sdk/server resolves a ready CommunicationProviderAdapter for slack/teams/telegram from the deployment's runtime credentials, or null when the provider is not connected. Slack gets its missing adapter factory (active installation -> SlackNotifier -> SlackCommunicationProvider); Teams and Telegram reuse the shared factories. First consumer: the PR-review notification job now posts through the adapter dispatch instead of a hand-rolled per-provider switch over SlackNotifier and the provider classes. Per-route input nuances (Teams serviceUrl/markdown, Telegram plain text) stay in a small input builder. Groundwork for the automation channel waterfall: destination resolution lands with the automation target model next. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Fix formatting Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* Make Slack MCP setup a non-blocking suggestion instead of an interrupt
When a Slack message links to a service whose MCP integration is not set
up (Zero, Linear, Vercel, ...), Roomote previously refused to start the
task: the mention path posted a blocking Configure / "Nah, keep going"
prompt, and the channel auto-start path returned a bare "Task was not
started because X still needs Slack MCP setup." line with no way to
proceed.
The task now always starts. Detection still runs, but its result is
surfaced as a small context-block reply in the thread ("That looks like
a Zero link... link your Zero account if you want me to be able to use
it") posted after the task launches, with the manager-channel
notification preserved. Detection or posting failures never affect the
launch.
This removes the now-unused interrupt machinery: the Redis pending
interrupt state and nonce-claim script, the mcp_setup_configure /
mcp_setup_ignore interactive handlers, the resume-after-setup flow, and
the pending-interrupt follow-up eligibility in message entry.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Refine MCP setup suggestion placement from review findings
Post the mention-path suggestion only after routing decides a task flow
is proceeding, so it never appears above a pure Q&A platform answer.
Skip the suggestion when a follow-up reuses an active run so repeated
links don't stack identical nudges, and drop "so I'll work without it"
from the copy since the confirmation flow can still be cancelled.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* Surface-scope automation tracked messages and add button parity Two pieces of comms groundwork so automations can post to Teams and Telegram without corrupting the Slack feedback loop: - Automation tracked-message reads/writes now carry an explicit TrackedMessageSurface instead of a hardcoded 'slack': the upsert takes a surface, and every lookup filters on it so rows from different surfaces can never collide on a shared dedupe key. All current callers pass 'slack'; no behavior change. - Generic message buttons now render on every adapter. Slack turns link buttons into a Block Kit actions block (wrapping the text body in a section so it stays visible); Teams degrades them to trailing links (markdown links or label: url lines) since there is no validated outbound card renderer; Telegram already rendered inline keyboards. Callback-only buttons are dropped on Slack/Teams because no generic interaction handler exists. The thread-feedback reply harvest still reads the persisted Slack conversation log; non-Slack threads resolve with empty feedback until those surfaces get an equivalent reply source (noted inline). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Fix formatting Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* Scope Zero MCP link detection to product surfaces The Zero catalog entry matched any URL on zero.xyz or withzero.ai, so casual mentions of the marketing homepage (e.g. "grab the favicon from zero.xyz") triggered MCP setup suggestions in Slack. Following the Vercel entry's pattern, Zero now matches only its product surfaces: capability pages (/c/<id>), the service directory (/browse), the wallet/profile page, and the mcp.zero.xyz connector host. withzero.ai is dropped entirely — it is a bare landing page with no linkable product resources. Adds the first direct tests for extractUrlsFromSlackText and matchSlackMcpSetupService, covering the Zero split and existing service matching. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Keep Zero homepage links triggering the setup suggestion The bare zero.xyz / withzero.ai homepage is a strong enough "about Zero" signal now that detection only produces a non-blocking hint; deep marketing pages (/faq, /security, /getlisted, ...) stay excluded. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Revert accidentally committed local Caddyfile dev patch Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Matt Rubens <2600+mrubens@users.noreply.github.com>
* Add surface-generic post_to_channel agent tool Teams- and Telegram-launched tasks previously had no way to post a standalone message: post_to_slack_channel is Slack-only and send_chat_reply only replies into the originating thread. - The channel_post MCP endpoint now dispatches by the task's communication provider (mirroring thread_reply's maybeSendCommunicationThreadReply): Teams and Telegram tasks post through their provider adapter, everything else keeps the existing Slack path byte-for-byte. - Cross-surface posts are restricted to the conversation the task was launched from — Teams and Telegram have no channel-membership model equivalent to Slack's isAppInChannel, and that conversation is the only one whose Teams serviceUrl the task holds. Telegram posts default into the task's own topic. - New post_to_channel worker tool, registered only for Teams/Telegram chat contexts (Slack tasks keep post_to_slack_channel), passing opaque conversation ids through without Slack channel-name normalization. Added to the Slack-posting basenames so subagents cannot bypass the parent-only posting restriction. reply_to_thread needs no new tool: send_chat_reply already dispatches by surface via the thread_reply endpoint. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Address review: raw channel ids for communication dispatch - parseChannelPostRequestBody no longer Slack-normalizes the channel; normalization moved after the communication-provider dispatch so Teams conversation ids keep their case (Slack normalization lowercases, which broke own-conversation matching for realistic Teams ids). Dispatch tests now use an uppercase-bearing Teams id. - post_to_slack_channel is no longer registered for Teams/Telegram chat contexts; post_to_channel is the single channel-post tool there, so opaque ids can't be fed into Slack normalization. - Missing Teams serviceUrl now returns a distinct 503 instead of the misleading wrong-conversation 403. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* feat: add 7d product PR funnel to daily instance report Ship aggregate opened/open/closed/merged counts plus median time-to-merge for product-authored PRs in the anonymous daily stats payload, using local task_pull_requests (and pull_request_facts for durations) only. * fix: make instance-report PR cohort tests isolation-safe Stop asserting absolute pullRequests7d totals against the shared test DB. Scope the integration case to this fixture's repository so parallel suite data cannot flake the product-opened funnel expectations. * fix: harden product PR funnel stats against review feedback - Derive workflow exclusions from SOURCE_CONTROL_AUTOMATION_WORKFLOWS - Case-insensitive history/facts name matching (plus repositoryId paths) - Keep report tests fixture-scoped so shared DB suites stay isolation-safe --------- Co-authored-by: Roomote <roomote@roomote.dev>
…y when PRs close (#288) * [Improve] Move Working on footer to OOB Slack posts and notify on PR close Keep the sticky Working on footer on the latest Slack message for review and PR status updates, and post a closed-PR status with heavy_multiplication_x. * [Fix] Address PR #288 review: ADO closed notify, share footer helpers Notify Azure DevOps abandoned PRs like other providers, dedupe sticky footer helpers into packages/slack for MCP, drop always-true terminal guards, and use reply-only sticky footers on terminal PR status posts. --------- Co-authored-by: Matt Rubens <2600+mrubens@users.noreply.github.com>
* Add automation target model and capability declarations Groundwork for automations reporting to non-Slack surfaces: - AutomationTarget unions gain teams/teams_channel alongside the existing slack/telegram/sentry kinds. - Every triggerable automation descriptor now declares which comms surfaces and source-control providers its shipped runner supports today (dependabot_triage and ci_failure_triage stay GitHub-only by design; suggester and sentry_triage are already SCM-agnostic). Settings gating and the automations page read these as the source of truth, expanding per-automation as runners generalize. - upsertAutomation gains managedTargetKinds: a settings save now only replaces the target kinds it owns and preserves the rest, so the Slack-channel settings writer can no longer clobber teams/telegram targets configured through other paths. All settings-update sites declare their managed kinds. No behavior change for existing Slack/sentry configurations. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Address review: manage target kinds in the starter-automation writer syncManagerStarterAutomations also writes suggester/announcer targets; it now declares managedTargetKinds so it cannot clobber non-Slack targets either. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Roomote <roomote@roomote.dev>
…ult (#278) * Simplify Azure DevOps setup to organization and PAT by default Hide advanced ADO fields behind a setup toggle, keep Settings complete, and fall back ADO tenant resolution to the shared Microsoft tenant. * Add Azure DevOps authentication modes * ui * ui * Align Azure DevOps setup with Teams flow * Clarify Azure DevOps auth labels * Improve Azure DevOps setup guidance * ui * Show onboarding completion in live tasks * More tweaks * More ui * Fix Azure DevOps onboarding tests * Remove unused ADO auth type export --------- Co-authored-by: Roomote <roomote@roomote.dev> Co-authored-by: Bruno Bergher <bruno@roocode.com>
SlackSetupExperience's intro screen owns the step action buttons, and it is skipped when the Slack config is already saved (savedSatisfied). But StepAuthEnvVars's providerOwnsActions check was missing the matching !savedSatisfied clause, so revisiting the auth step with saved Slack credentials rendered the value form with no action button at all, stranding the user on the page. Align providerOwnsActions with the intro guard and add a regression test for the saved-Slack revisit path. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
…faces (#300) Co-authored-by: Matt Rubens <2600+mrubens@users.noreply.github.com>
Keeps develop's package.json and CHANGELOG aligned after the main-only 0.4.2 Slack setup hotfix so the next release does not reuse the v0.4.2 tag. Co-authored-by: Roomote <roomote@users.noreply.github.com>
* Route triage and audit automations to any comms destination Sentry triage, Dependabot triage, and the security/code-quality auditors can now report to Teams or Telegram, not just Slack. Core design: instead of teaching runners about adapters, the resolved destination is stamped onto the scan task's communication payload fields, so the surface-generic worker tools (send_chat_reply, post_to_channel) and the own-conversation posting restriction all apply unchanged. Slack destinations stay byte-identical (no stamping). - New destination module: resolveAutomationRuntimeDestination extends the db waterfall (own target -> Slack manager channel) with a primary-conversation tail for Slack-less deployments (most recently active Teams conversation, then the Telegram primary chat); the tail is skipped when Slack is connected so the "configure a manager channel" nudge survives. listConnectedCommunicationProviders gates deployment eligibility. Teams destinations resolve their Bot Framework serviceUrl from teamsInstallations at launch. - scheduled-triage-runner and merged-pr-audit-runner resolve destinations, stamp payload fields, and keep Slack-only side effects (debug posts, workspace timezone) guarded on an actual Slack token. - Scan prompts are surface-correct: channel tag, posting tool name, and surface wording parameterized per destination. - ci_failure_triage explicitly skips non-Slack destinations for now (its prompt and webhook announcements are still Slack-shaped). - Manual "Run now" and settings validation accept a resolved destination on any provider the automation's descriptor supports; registry declarations flip to slack/teams/telegram for the four generalized automations. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Address review: destination-surface feedback lookups, skip reason - Thread-feedback loaders take the destination surface (default slack) and the runners pass it, so Teams/Telegram feedback context flows as soon as those surfaces track automation threads. - Stale 'No active Slack installation' skip reason now reads 'No connected communication provider'. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
The merged-PR announcer's enumeration already reads the provider-neutral taskPullRequests table, which every source-control provider's webhooks populate; only its eligibility gate forced a GitHub installation. The gate now requires any active repository, the manual-trigger requirement drops the github token for the neutral repository check, and the registry declares support for all source-control providers. The security/code-quality auditors and conflict resolver stay GitHub-only by declaration: the auditors read pullRequestFacts, which only the GitHub sync writes, and conflict resolution needs a list-open-PRs primitive no provider package has yet — both are real per-provider workstreams, not gate changes. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Roomote <roomote@roomote.dev>
* Sync merged-PR facts from all source-control providers The security and code-quality auditors read pullRequestFacts, which only the GitHub sync wrote — so they silently audited GitHub alone. A new provider-neutral sync (gitlab/gitea/ado/bitbucket) reuses the shared facts store extracted from the GitHub writer: provider-scoped active-repo selection with the same repo budget, least-recently-synced ordering and cooldowns, bounded merged-PR backfill plus incremental updated-after passes via the extended list primitive, and webhook fact upserts on terminal merge/close events in each provider's handler. The GitHub sync is now scoped to github repositories so the two syncs cannot contend over budget or cursor rows. Per-provider timestamp realities documented in code: ADO substitutes closedDate, Bitbucket has no merge timestamp (updated_on fallback with a warning), GitLab merge webhooks carry no author until the next pass. The audit runner gates on any active repository, prompts drop their GitHub assumptions, and both auditors declare all source-control providers — the automations-page badges update accordingly. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Address review: repository-identity scoping and cursor tie-breaker - Webhook fact upserts scope the repository lookup by the event's host (derived from the PR URL), with NULL-host legacy rows still matching, so same-name repositories on different self-managed hosts no longer cross-write facts and cursors. - The audit manifest dedupes by repository id + PR number instead of fullName + number, keeping same-name cross-provider PRs distinct. - Scan pagination orders and tie-breaks on the facts row primary key; cursors carry both new and legacy fields so rollbacks read them, and old-format cursors resume timestamp-inclusive (possible one-time re-audit at the boundary, never a skip). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Address review: partition audit launches by source-control provider The merged-PR manifest now launches one audit task per provider partition, stamping sourceControlProvider on non-GitHub payloads so the provider-bound pull-request tools accept their PRs. All-GitHub manifests keep today's single launch with a byte-identical payload. Partitions exactly tile the scan page, so the page cursor advances only after every partition launches; a partition failure leaves the cursor untouched (at most a one-time duplicate audit, never a skip). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Address review: host-aware audit partitioning with ambiguity guard Audit launches now partition by (provider, host). Entries whose (provider, fullName) matches more than one active repository row are excluded from every manifest with a logged warning — the pull-request tools resolve by provider and name alone, so auditing them could hit the wrong host; threading host identity through the payload and tool resolution is marked as the follow-up. The page cursor still tiles exactly and advances past deliberately skipped entries. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…rovider (#331) Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Full provider coverage now renders no badge — the absence of a warning is the signal. Limited automations keep an explicit boundary badge: "GitHub only", "Slack only", or the supported-provider list suffixed with "only" (e.g. conflict resolution, which has no Gitea/Bitbucket conflict signal). Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Matt Rubens <2600+mrubens@users.noreply.github.com>
* Improve source control provider setup guidance * Add directional setup step transitions * fix gitea base URL normalization * ui details * Animate pre-sign-in setup steps * Match setup transition timing * normalize gitea URLs when saving config * ui * feat(gitlab): add deployment OAuth connection * feat(gitea): make OAuth the primary source-control connection * test(gitlab): update OAuth API expectations * feat(setup): show Gitea OAuth redirect instructions * Remove GitLab PAT deployment fallback * feat(setup): authorize Gitea after saving credentials * docs(setup): clarify Gitea OAuth instructions * gitlab oauth fixes * sync fix * Automatically sync repositories during onboarding * invoke * fix GitLab webhook setup after OAuth sync * fix GitLab OAuth API authentication * chore(web): clean up setup lint exports * default gitea url * fix gitea oauth webhook registration * invoke * fix(source-control): resolve CI test and CodeQL findings * fix gitea comment setup guidance * fix gitea oauth callback setup * address source control oauth review feedback * fix: address remaining source control review feedback * fix: avoid polynomial URL normalization regexes --------- Co-authored-by: Roomote <roomote@roomote.dev> Co-authored-by: Bruno Bergher <bruno@roocode.com>
* Compute manager stats across all source-control providers The weekly digest was computed exclusively from GitHub's analytics API. Non-GitHub repositories now contribute via the provider-neutral list primitives (open + merged-in-window per repo), mapped through a pure per-provider normalizer; the GitHub path is unchanged. The authored-vs-reviewed classification joins task PRs with provider- qualified keys, fixing a latent same-name cross-provider collision. Honest degradations, marked in the digest rather than fabricated: the LOC line is labeled "(GitHub PRs only)" when non-GitHub PRs are counted (no bulk additions/deletions API elsewhere), closed-without- merge PRs are not counted off-GitHub, and rows without timestamps are dropped. Eligibility requires any active repository; the GitHub actor is only needed for the GitHub data path. manager_stats declares all source-control providers — with exception- only badges, its "GitHub only" pill disappears, leaving only the inherently-GitHub Dependabot and CI-failure triage automations. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Address review: truncation logging, merge-race dedup, provider-scoped repo counts Provider list warnings are logged per repo instead of silently dropped; dedup prefers the merged summary when a PR merges between the concurrent open and merged reads; most-active-repo counts are keyed by provider-qualified identity. Per product direction, outbound digest copy carries no scope qualifiers: the LOC line renders only when it covers every counted PR and is omitted otherwise, and repo labels stay bare names. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Address review: deterministic tie-break for same-name repo counts Equal-count same-name repos across providers now tie-break on the provider-qualified key instead of input order. The digest deliberately keeps bare repository names: outbound message copy carries no provider qualifiers by product direction; the settings-page capability badges own that story. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Roomote <roomote@roomote.dev>
…#333) * Make environment setup completion observable to the task Repository setup commands run in the background for environment tasks, but nothing told the agent (or the platform) when they finished: - Write <workspace>/.roomote/setup-status.json with live per-command state (pending/running/succeeded/failed) and mirror each command's stdout/stderr to .roomote/setup-logs/<repo>/<command>.log - Fix the sandbox instruction that unconditionally claimed setup commands "were already executed"; in background mode it now points the agent at the status file and logs instead - Inject an in-session notification via the harness when background setup settles while the task is actively running - Track the real setup lifecycle on task_runs (environment_setup_state / environment_setup_completed_at), written when setup settles rather than when the blocking phase returns, and record one task-run phase event per repository command * Update workspace test assertions for new command lifecycle callbacks * Defer environment-setup notification until the runtime task has started executeStartNewTask flips the phase to running before the StartNewTask command carrying the initial prompt reaches the harness, so a fast-settling background setup could inject its notification into that window and replace the initial user prompt as the session's first message. Buffer the settled outcome and deliver it only after the runtime emits taskStarted. * Address review feedback on setup status file - Replace a literal NUL byte in commandKey with the \u0000 escape so Git stops treating setup-status.ts as a binary blob - Fold background Docker project warnings into the setup status file so it cannot report a clean 'completed' when Docker setup failed * Always create setup-status.json for environment workspaces The sandbox instruction and the settle notification point the agent at .roomote/setup-status.json, but Docker-only or command-less environments never created it. Initialize the writer for every environment workspace and finalize it even when there are no repository commands to run, so the file's existence is an invariant the agent can rely on. * Track duplicate command names as separate setup-status entries The environment schema allows repeated command names within a repo, but the (repository, name) map kept only the first entry, so later duplicates vanished from the published plan and their callbacks overwrote the first entry's lifecycle. Each key now maps to all matching entries in plan order; since commands run sequentially per repository, callbacks target the earliest entry still in the expected state, and duplicate log files get an occurrence suffix. --------- Co-authored-by: Matt Rubens <2600+mrubens@users.noreply.github.com>
…ogs panel (#337) * Stream Docker project logs to a well-known file and surface them in the Logs panel Docker projects had no standard log: Compose startup output went only to the worker's startup logger and container logs lived inside dockerd. Now: - The worker writes each project's Compose startup output, failure diagnostics, and a detached 'docker compose logs --follow' stream to /tmp/roomote-docker-projects/<compose-project>.log, created up front so the Logs panel's tail -f finds it immediately - toComposeProjectName / getDockerProjectLogFilePath move to @roomote/types so the web app derives identical paths - The Logs sidebar lists one entry per configured docker_project * Redact project values from Docker failure output in project logs error.message from a failed compose up carries Compose stderr, which can echo substituted project env values or build args. Redact it (alongside the already-redacted diagnostics) before appending to the project log file and before rethrowing, so neither the Logs panel nor downstream warnings expose sensitive values. * Log redacted message instead of raw error for optional Docker failures The caught Error's cause chain still holds the original Compose error with unredacted stderr, and the startup logger serializes causes into harness.log, which the Logs panel exposes. Log the redacted message on both the user and debug channels instead. --------- Co-authored-by: Matt Rubens <2600+mrubens@users.noreply.github.com>
* Resolve repositories host-aware via payload sourceControlHost Merged-PR audits skipped every repository whose (provider, fullName) was active on more than one host, because launched tasks resolved repositories by (provider, fullName) alone and could hit the wrong self-managed instance. Task payloads can now carry an optional sourceControlHost, stamped by the merged-PR audit runner (per provider/host partition) and the conflict scanner's provider-neutral path. resolveRepositoryRow narrows by that host, preferring exact matches and falling back to legacy rows without a recorded host; without a payload host, a multi-host identity now fails loudly instead of resolving arbitrarily. The audit manifest skip narrows to legacy entries whose repository row has no recorded host; those self-heal once the host backfill reaches them. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Address review: host-scope conflict-scan dedup and PR linkage An active resolution run recorded for a same-name PR on another host no longer suppresses a host-pinned launch: hasActiveResolutionRun and findActiveGitHubBranchWork scope their lookups by the repository host (NULL-host legacy rows still match), and the provider-neutral conflict scan stamps the host into prLinkage so the task association itself is host-scoped. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Address review: gate legacy branch fallback on linkage host An unstamped legacy payload no longer suppresses a host-scoped branch lookup when the task's own pull-request linkage records a different host: the linkage pins the task to another instance, so the NULL-host payload tolerance applies only when no conflicting linkage host is known. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Address review: stamp sourceControlHost in webhook review launches GitLab/Gitea/ADO/Bitbucket webhook handlers already resolve the concrete repository row before enqueueing review tasks; stamping its host into the launch payload lets those tasks resolve repositories host-aware instead of failing the new multi-host ambiguity check. Null-host legacy rows omit the field, matching the audit runner and conflict scan. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Address review: host-scope webhook automation target lookup get*AutomationTargets selected the repository row by externalRepoId-or-fullName alone; numeric project ids and full names collide across self-managed instances, so a webhook could select the other host's row and pin its review launch to the wrong host. The handlers now derive the instance host from the webhook's own URLs (shared toHostFromUrl, moved from pull-request-fact-sync) and the helpers pick the row host-first with the legacy NULL-host fallback, matching resolveRepositoryRow's tiering. A webhook whose host matches no row resolves to none rather than another instance's repository. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* Fix ReDoS-prone link regex in Slack markdown converter
The markdown link pattern used a quantified alternation whose first
branch was itself unbounded ((?:[^()]+|\([^()]*\))+), a shape prone to
catastrophic backtracking on inputs like a long run of open parens
after "[label](". Matching one character per iteration ([^()]) removes
the ambiguity while still supporting link targets with one level of
balanced parentheses.
Adds a test for balanced parens in the URL and a regression guard that
converts a pathological 50k-paren input within a strict time budget.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Make the link label capture linear as well
The label part ([^\]]+) was still quadratic on malformed input such as
a long run of "[" with no closing bracket: the unanchored global match
retried at every "[" and rescanned the remaining suffix for a "]".
Excluding "[" from the label class makes failed attempts non-overlapping
with subsequent start positions, so matching stays linear.
Flagged by CodeQL (js/polynomial-redos) and PR review on the previous
commit. Adds regression guards for "[".repeat(50_000) and
"[a".repeat(50_000).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…nner verification loop (#340) * Feed environment setup ground truth into the verification loop The environment-setup workflow already launches a verification task and revises the environment when verification fails, but both ends of that loop ran blind to the setup ground truth #333 introduced: - The verification task's prompt told it to "be patient" instead of reading .roomote/setup-status.json, so it could judge the environment before background setup settled or fail to name the broken command. - The task summary the setup agent polls (manage_tasks get_summary) did not surface environmentSetupState, so setup failures only reached the fix loop when the verification agent happened to describe them. Expose environmentSetupState through the summary API and render it as an Environment Setup line in get_summary, and update the skill so the verification prompt consults setup-status.json / setup-logs and the monitoring steps treat a failed or completed-with-warnings line as direct, fixable evidence. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Verify environments with the proof runner instead of re-provisioning The environment-setup fix loop iterated by relaunching a full environment-backed verification task per config revision, so every retry paid provisioning time and inherited compute failure modes unrelated to the config under test. Give environment-setup tasks the hidden proof-runner subagent in brief-supplied-target mode (they discover the app URL mid-task, so no target exists to bake at config-generation time; detection keys off the $environment-setup prompt invocation via the new isEnvironmentSetupTaskPrompt helper). The skill now iterates in-workspace: after loopback validation and on every install/start-affecting revision it delegates a one-item proof brief to the proof runner and treats the Blocked verdict, observed port state, and visible browser errors as the fix-loop evidence. The spawned environment-backed task becomes the single final end-to-end confirmation, and its prompt now relays its own proof runner's verdict and screenshot URLs instead of judging the page itself. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Update browser containment policy test for delegated proof-runner wording Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Prefer brief-targeted proof runner for env-setup tasks with an environment An environment-setup task launched against an existing environment carries that environment's initialUrl, but that URL is the thing under revision — baking it would pin the proof runner to a possibly stale surface and make it reject the freshly validated target the setup workflow needs to verify. Addresses the roomote review finding on run-task.ts. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Matt Rubens <2600+mrubens@users.noreply.github.com>
Co-authored-by: Matt Rubens <2600+mrubens@users.noreply.github.com>
* [Feat] Show environment setup logs in the task Logs tab * [Chore] Stop exporting unused SetupStatusResult type * [Fix] Infer getSetupStatus result type for worker declarations * [Improve] Drop repo name from setup log dropdown labels * [Improve] Disambiguate setup log labels only on name collisions * [Fix] Keep setup log dropdown labels unique when repos or commands collide * [Improve] Keep setup log disambiguation intentionally light --------- Co-authored-by: Matt Rubens <2600+mrubens@users.noreply.github.com>
* Release Roomote 1.0.0 Bump the product version to 1.0.0 and record the public 1.0 changelog. * [Improve] Lead Roomote 1.0 notes with headline features Reorder and reword the 1.0.0 changelog so Docker projects, multi-SCM automations, setup-flow rework, and Code Mode appear first. --------- Co-authored-by: Matt Rubens <2600+mrubens@users.noreply.github.com>
Contributor
|
No new code issues found; 7 previously reported issues remain. See task
Reviewed 690cb87 |
Contributor
|
Fixed all 7 open review checklist items from the Roomote review summary on a new branch off Covered:
Review threads on this promote PR remain unresolved because the fixes land on |
8 tasks
Merged
7 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Promote v1.0.0
Frozen at
48046b5dd4671c26319e480af8881d2b63cb240a— the commit where1.0.0was versioned. Commits merged todevelopafter that point ship in the next release.v1.0.0and triggers the existing GHCRv*image publish (latestchannel).release/v1.0.0branch can be deleted after this PR merges.Changelog
1.0.0 (2026-07-15)
Major changes
Minor changes
Patch changes