diff --git a/.github/workflows/release-validation.yml b/.github/workflows/release-validation.yml
new file mode 100644
index 0000000..bea2b4e
--- /dev/null
+++ b/.github/workflows/release-validation.yml
@@ -0,0 +1,77 @@
+name: Release validation
+
+on:
+ pull_request:
+ branches: [main]
+
+permissions:
+ contents: read
+
+concurrency:
+ group: release-validation-${{ github.event.pull_request.number }}
+ cancel-in-progress: true
+
+jobs:
+ tests:
+ name: Tests and types (${{ matrix.os }})
+ runs-on: ${{ matrix.os }}
+ timeout-minutes: 15
+ strategy:
+ fail-fast: false
+ matrix:
+ os: [ubuntu-latest, windows-latest]
+ steps:
+ - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5
+ with:
+ persist-credentials: false
+ fetch-depth: 0
+ - uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5
+ with:
+ node-version: '24'
+ cache: npm
+ - name: Install locked dependencies without lifecycle scripts
+ run: npm ci --ignore-scripts --no-audit --no-fund
+ - name: Full automated suite
+ run: npm test
+ - name: TypeScript
+ run: npm run typecheck
+ - name: Lockfile and source whitespace
+ shell: bash
+ env:
+ BASE_SHA: ${{ github.event.pull_request.base.sha }}
+ run: |
+ git diff --exit-code -- package.json package-lock.json
+ git diff --check "$BASE_SHA" HEAD
+
+ package:
+ name: Build and package (Ubuntu)
+ runs-on: ubuntu-latest
+ timeout-minutes: 15
+ env:
+ BB_TELEMETRY: 'false'
+ steps:
+ - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5
+ with:
+ persist-credentials: false
+ - uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5
+ with:
+ node-version: '24'
+ cache: npm
+ - name: Install locked project dependencies
+ run: npm ci --ignore-scripts --no-audit --no-fund
+ - name: Prepare separate official BB 0.46.0 build tools
+ shell: bash
+ run: |
+ npm install --prefix "$RUNNER_TEMP/bb-tools" --ignore-scripts --no-audit --no-fund bb-app@0.46.0
+ cd "$RUNNER_TEMP/bb-tools"
+ npm rebuild better-sqlite3
+ - name: Official full plugin production build
+ shell: bash
+ env:
+ BB_DATA_DIR: ${{ runner.temp }}/agent-board-build-data
+ BB_SERVER_URL: http://127.0.0.1:50886
+ run: node "$RUNNER_TEMP/bb-tools/node_modules/bb-app/dist/bb.js" plugin build
+ - name: Inspect actual release package and metadata
+ run: npm run verify:package
+ - name: Ensure build/install did not alter locked source
+ run: git diff --exit-code -- package.json package-lock.json
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2bdc1fa..2784396 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,34 @@
# Changelog
+## 0.7.0 — prepared 2026-10-12 (unpublished)
+
+- Show the latest observed public activity and distinguish recent from quiet
+ reporting, without changing task status or the indeterminate activity strips.
+- Add structured completion outcome/result/failure sections, explicitly labeled
+ agent-reported verification and access to the original bounded output preview.
+- Filter and group the bounded dashboard by project, repository, provider and
+ status. Project metadata lookup is optional, bounded and credential-safe.
+- Separate transport connection, refresh/change timestamps and watcher health.
+ Contain watcher callback/publication errors and surface degraded monitoring.
+- Reduce empty Needs attention to a compact line; actionable items remain visible.
+- Add bundled What's New highlights with per-version local dismissal and a
+ persistent Release notes control. No telemetry or remote release fetching.
+- Retain explicit result/check labels before truncating the original output preview.
+- Qualify cached watcher health when disconnected, a refresh fails or becomes overdue.
+- Keep terminal duration unknown when the source supplies no completion timing.
+- Bound package contents to runtime source, assets and user documentation;
+ exclude tests, validation helpers, reports and temporary evidence from npm packs.
+- Make public-SDK test paths portable to Windows and use a serial Vitest thread
+ pool for reliable startup on the development laptop.
+
+- Add Node 24 Ubuntu/Windows PR tests/typecheck and an Ubuntu official build/package gate.
+- Patch Hono, Undici and source-map-js development dependencies; the updated graph audits clean.
+- Prebundle the large icon data dependency in Vitest without relaxing hook limits or mocking the UI.
+
+No storage migration or settings reset is required. BB >=0.40 and SDK >=0.4.21
+remain declared; BB 0.46.0 is recommended. See [upgrade notes](docs/upgrade-0.7.0.md)
+and [release convention](docs/release-convention.md). Version 0.7.0 is prepared on the PR branch and is not published.
+
## 0.6.1 — first public beta
- Fix managed Git installation when BB omits development dependencies: keep the
@@ -7,7 +36,7 @@
- 0.6.0 remained an unpublished release candidate.
Dates are omitted because these milestones were local development commits.
-0.6.0 is the first planned public beta.
+0.6.1 is the first public beta; 0.6.0 remained unpublished.
## 0.6.0
- Optional Ollama Fleet public observability integration.
diff --git a/PLUGIN_OVERVIEW.md b/PLUGIN_OVERVIEW.md
index eab8927..3a0c5e7 100644
--- a/PLUGIN_OVERVIEW.md
+++ b/PLUGIN_OVERVIEW.md
@@ -5,9 +5,19 @@ completion. Open a thread's Agent Board action for automatic single-agent focus
or a multi-agent Kanban view. Inspect the bounded execution timeline to see
public operational updates, actual models, and tools as sources report them.
+See how recently an agent reported public activity. Quiet reporting keeps the
+source's task status intact. Review completion outcomes, results, failures and
+explicitly agent-reported checks, then open the original thread or timeline for
+details. Filter and group visible work by project, repository, provider or status.
+Needs Attention stays visible across filters. Connection, refresh and watcher
+health help you distinguish an observation problem from quiet execution.
+
+What's New shows bundled version highlights. Dismiss an announcement once and
+reopen its notes from the dashboard whenever needed.
+
## Requirements
-Requires BB. Ollama Fleet 0.6.0 or newer and Redteam's public observability RPC
+Requires BB 0.40 or newer; BB 0.46.0 is recommended. Ollama Fleet 0.6.0 or newer and Redteam's public observability RPC
are optional integrations. Missing integrations leave native BB observation
available. Mobile layouts and reduced-motion preferences are supported.
Hidden reasoning is excluded. System/push notifications are unavailable in
diff --git a/README.md b/README.md
index 353cf01..fbbe221 100644
--- a/README.md
+++ b/README.md
@@ -30,6 +30,11 @@ focus and the global dashboard offer other views of the same bounded state.
- **Multi-Agent Kanban:** live state for concurrent agents and workers.
- **Needs Attention:** structured waiting/failure states and persistent dismissal.
- **Execution Timeline:** bounded operational events, loaded when opened.
+- **Activity freshness:** recent or quiet public reporting without inferring a stall.
+- **Completion summaries:** outcomes, results, failures and agent-reported checks.
+- **Filters and grouping:** project, repository, provider and status over visible work.
+- **Monitoring health:** connection, successful refresh and watcher status.
+- **What's New:** version highlights with persistent dismissal and later viewing.
- Native BB threads, workflows, delegations, models and tools.
- Optional Ollama Fleet and Redteam observation.
- Mobile layouts, keyboard controls, and reduced-motion support.
@@ -64,6 +69,7 @@ bb plugin install .
Neither Fleet nor Redteam is required. Declared compatibility is BB >=0.40 and
SDK >=0.4.21; the development SDK is pinned to 0.4.34. See the honest
[compatibility matrix](RELEASE_AUDIT.md), including historical runtime evidence.
+For the prepared, unpublished 0.7.0 source, see [compatibility and upgrade notes](docs/upgrade-0.7.0.md).
## Usage
@@ -144,6 +150,13 @@ This is a bounded latest view, not a persistent history database.
## Development
+The prepared, unpublished 0.7.0 source is documented in [vnext launch/testing](docs/vnext-testing.md),
+[design](docs/vnext-design.md) and [release convention](docs/release-convention.md).
+Use a separate BB data directory and ports for development; keep your stable
+installation untouched. `0.7.0` on this PR branch is not a published release.
+See [dependency assessment](docs/dependency-security-0.7.0.md) and the PR
+Release validation checks before approving a merge.
+
```sh
npm ci
npm test
diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
index d003375..9cae090 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -1,3 +1,49 @@
+# Agent Board v0.7.0 — prepared release notes
+
+Version **0.7.0** is prepared on the development PR branch, unpublished and
+awaiting final merge review. No public tag, release, marketplace update or
+installed stable-plugin update has occurred.
+
+Agent Board gives you a clearer view of live agent work and completed outcomes.
+
+- **Activity freshness:** see the age of the latest public activity and whether
+ reporting is recent or quiet. Long tasks keep their authoritative status and
+ the existing animated activity bars.
+- **Completion outcomes:** review results, failures and explicitly agent-reported
+ checks in separate sections. Open the original thread or bounded timeline for details.
+- **Filters and grouping:** organize visible work by project, repository, provider
+ or status. Needs Attention and operational counts remain visible across filters.
+- **Monitoring health:** distinguish transport connection, snapshot refresh and
+ source-watcher health. Cached watcher status is qualified when it cannot be confirmed.
+- **What's New:** read bundled version highlights, persist dismissal for that
+ version, and reopen its notes from the dashboard. Empty Needs Attention is compact.
+
+Reliability fixes preserve explicit result/check metadata before output truncation,
+qualify cached health during disconnects and failed/overdue refreshes, and avoid
+inventing elapsed duration for terminal tasks without completion timing.
+
+Release hardening adds hosted Node 24 Linux/Windows tests and typecheck, an
+Ubuntu official BB build/package gate, and fixed development Hono/Undici/source-map-js
+patches. See [dependency assessment](docs/dependency-security-0.7.0.md).
+
+Existing settings and attention dismissals are preserved. No manual data migration
+or configuration change is required. BB >=0.40 and public SDK >=0.4.21 remain
+declared; BB **0.46.0 is recommended**. Optional Fleet >=0.6.0 and a Redteam
+runtime exposing the public observability contract remain optional.
+
+BB installs tracking `^0.6.1` do not include 0.7.0. After publication, users must
+select the new marketplace release or change their Git selector to `^0.7.0`.
+Pinned tags/commits remain pinned. See [compatibility and upgrade notes](docs/upgrade-0.7.0.md).
+
+Filters cover the bounded visible snapshot. Quiet reporting does not prove a
+stall, and reported checks are not independent test evidence. Release notes in
+the UI are bundled highlights; GitHub hosts the full release notes. There are
+no new push notifications, automatic-install promises or Phase 2 features.
+
+Candidate checks, coverage provenance and remaining limits are recorded in
+[the validation summary](docs/validation-0.7.0.md). Detailed machine-specific
+reports and live screenshots remain local development evidence.
+
# Agent Board v0.6.1
First public beta: live execution observability for BB.
diff --git a/components/board/activity-freshness.tsx b/components/board/activity-freshness.tsx
new file mode 100644
index 0000000..abf45e2
--- /dev/null
+++ b/components/board/activity-freshness.tsx
@@ -0,0 +1,11 @@
+import type { BoardCard } from "@/contract/rpc";
+import { activityFreshness } from "@/lib/dashboard-view";
+import { formatElapsed } from "@/lib/board-model";
+
+export function ActivityFreshness({ card, now }: { card: BoardCard; now: number }) {
+ const freshness = activityFreshness(card, now);
+ return
;
+}
diff --git a/contract/rpc.ts b/contract/rpc.ts
index 13a3119..030830f 100644
--- a/contract/rpc.ts
+++ b/contract/rpc.ts
@@ -123,8 +123,13 @@ export const boardCardSchema = z.object({
/** Task preview where the source exposes one (workflow promptPreview). */
promptPreview: z.string().nullable(),
activity: boardActivitySchema.nullable(),
+ /** Most recent public activity; never the snapshot fetch time. */
+ lastActivityAt: z.number().nullable().optional(),
/** Compact final-output preview (truncated server-side). */
outputPreview: z.string().nullable(),
+ /** Explicit agent-reported labels, retained before output preview truncation. */
+ completionResult: z.string().max(240).nullable().optional(),
+ reportedVerification: z.array(z.string().max(240)).max(4).optional(),
/**
* Latest user-visible assistant-authored text (bounded excerpt). Strictly
* conversational: never reasoning, tool/command output, or user/system
@@ -219,6 +224,8 @@ export const globalExecutionSchema = z.object({
card: boardCardSchema,
projectId: z.string().nullable(),
delegatedWorkers: z.array(boardCardSchema).max(4).optional(),
+ projectName: z.string().nullable().optional(),
+ repository: z.string().nullable().optional(),
delegatedWorkerCount: z.number().int().nonnegative().optional(),
activeDelegatedWorkerCount: z.number().int().nonnegative().optional(),
childCount: z.number().int().nonnegative(),
@@ -353,6 +360,13 @@ export const globalDashboardCountsSchema = z.object({
export type GlobalDashboardCounts = z.infer;
const globalDashboardSnapshotSchema = z.object({
+ monitoring: z.object({
+ status: z.enum(["watching", "degraded", "unavailable", "disposed"]),
+ startedAt: z.number(),
+ lastEventAt: z.number().nullable(),
+ lastPublishedAt: z.number().nullable(),
+ lastErrorAt: z.number().nullable(),
+ }).optional(),
active: z.array(globalExecutionSchema),
attention: z.array(attentionItemSchema),
recent: z.array(globalExecutionSchema),
@@ -382,6 +396,14 @@ export const boardChangedPayloadSchema = z.object({
});
export const rpcContract = {
+ release_announcement: {
+ input: z.object({}),
+ output: z.object({ version: z.string(), title: z.string(), highlights: z.array(z.string()), dismissed: z.boolean() }),
+ },
+ dismiss_release_announcement: {
+ input: z.object({ version: z.string().min(1).max(80) }),
+ output: z.object({ dismissed: z.boolean() }),
+ },
/**
* Normalized board for one root thread and its publicly visible
* descendants/workflows. `fresh: true` bypasses the short-lived
diff --git a/docs/architecture.md b/docs/architecture.md
index 122fb38..bca105b 100644
--- a/docs/architecture.md
+++ b/docs/architecture.md
@@ -14,7 +14,7 @@ Agent Board is a generic BB execution-observability plugin with two complementar
The mode is derived from the normalized snapshot by a pure view model (`lib/focus-model.ts`); no source-specific logic lives in the UI. The board is derived from authoritative sources on demand. It stores no duplicate board state and never renders reasoning/thinking events, fabricated progress percentages, or raw tool output.
-The global page uses the stable public `app.slots.navPanel` surface and `useBbNavigate().toThread(...)`. `lib/global-model.ts` collapses normalized source cards into independent logical executions, derives attention only from explicit structured metadata, and removes resolved conditions automatically. It does not inspect assistant prose. Stale/no-activity warnings are intentionally omitted because current timestamps cannot prove a stall reliably.
+The global page uses the stable public `app.slots.navPanel` surface and `useBbNavigate().toThread(...)`. `lib/global-model.ts` collapses normalized source cards into independent logical executions, derives attention only from explicit structured metadata, and removes resolved conditions automatically. It does not inspect assistant prose to infer attention. Phase 1 adds public-activity age and recent/quiet reporting labels; these never prove a stall or change execution status. Completion verification is explicitly agent-reported. See [the vnext design](vnext-design.md).
## Sources
diff --git a/docs/dependency-security-0.7.0.md b/docs/dependency-security-0.7.0.md
new file mode 100644
index 0000000..b991e48
--- /dev/null
+++ b/docs/dependency-security-0.7.0.md
@@ -0,0 +1,73 @@
+# Development dependency assessment for 0.7.0
+
+Assessed 12 October 2026. GitHub's eight default-branch alerts were mapped to the
+actual lockfile and code paths. No affected Hono/Undici/source-map-js module was
+present in the plugin's generated backend source map. These packages are
+development dependencies, not declared production dependencies. That distinction
+does not exempt build/test tooling from malicious inputs or supply-chain risk.
+
+## Dependency paths and narrow updates
+
+- Direct development Hono **4.13.5 → 4.13.7**. The SDK 0.4.34 testing host uses
+ that root optional peer; its compatible `^4.11.9` peer requirement is satisfied.
+ The root minimum becomes `^4.13.7` without upgrading the SDK.
+- `jsdom@30.0.1 → undici` **8.10.1 → 8.10.2**, pinned by a transitive override.
+ jsdom's existing `^8.9.0` range accepts this patch.
+- `jsdom → css-tree → source-map-js` and
+ `vitest → vite → postcss → source-map-js` **1.2.1 → 1.2.2**, pinned by a
+ transitive override. Existing transitive ranges accept this patch.
+
+Only those three resolved package versions changed. Production dependencies,
+BB runtime/build version 0.46.0, SDK pin 0.4.34, Node major 24 and declared BB/SDK
+compatibility floors were retained. No major upgrade or forced audit fix was used.
+Locked root engine metadata was reconciled with the existing package declarations:
+BB >=0.40 and SDK >=0.4.21. Unrelated Linux libc metadata was retained.
+
+## Original eight GitHub alerts
+
+Every row retains its original alert; no alerts were merged or dismissed. Fixed
+means the PR lockfile selects a patched version, not that an exploit was reproduced
+or that GitHub's default-branch alert is closed before merge.
+
+| Alert / advisory | Severity | Affected range / first fixed | Mechanism and current reachability | Action / status |
+| --- | --- | --- | --- | --- |
+| #12 [GHSA-hxh3-vqpv-xpqv](https://github.com/advisories/GHSA-hxh3-vqpv-xpqv), CVE-2026-93981 | Medium | Hono <4.13.7 / 4.13.7 | Unescaped strings in Hono JSX server boundaries/root can cause XSS. Agent Board uses React; its fake SDK HTTP routes return JSON and do not use Hono JSX/SSR. No current shipped/harness exploit path established. | Defensive patch to 4.13.7; fixed in PR lock. |
+| #11 [GHSA-pmjh-fq2x-6v4x](https://github.com/advisories/GHSA-pmjh-fq2x-6v4x), CVE-2026-18149 | Medium | Undici >=8.0.0 <8.10.2 / 8.10.2 | A malicious retried response can leave a body pending. Current harness does not configure RetryHandler/retry interception. | Defensive patch to 8.10.2; fixed in PR lock. |
+| #10 [GHSA-2gqq-gqf2-x968](https://github.com/advisories/GHSA-2gqq-gqf2-x968), CVE-2026-84947 | Low | Undici >=8.0.0 <8.10.2 / 8.10.2 | Oversized chunked responses can be truncated by the dump interceptor. No dump interceptor is configured. | Same patch; fixed in PR lock. |
+| #9 [GHSA-2jfj-6hjv-fm6j](https://github.com/advisories/GHSA-2jfj-6hjv-fm6j), CVE-2026-84933 | Medium | Undici >=8.0.0 <8.10.2 / 8.10.2 | Shared cache can replay Set-Cookie across users. No shared cache interceptor is configured. | Same patch; fixed in PR lock. |
+| #6 [GHSA-r53p-7pc4-xj5r](https://github.com/advisories/GHSA-r53p-7pc4-xj5r), CVE-2026-18540 | Low | Undici >=8.0.0 <8.10.2 / 8.10.2 | Retried bytes forwarded with old framing can split downstream responses. No retry interceptor or downstream HTTP proxy is configured. | Same patch; fixed in PR lock. |
+| #5 [GHSA-w293-vg96-wgc3](https://github.com/advisories/GHSA-w293-vg96-wgc3), CVE-2026-84961 | High | Undici >=8.0.0 <8.10.2 / 8.10.2 | BalancedPool drops function-valued custom TLS checks. The current jsdom dispatcher uses the default Agent, not BalancedPool/custom TLS callbacks. | Same patch; fixed in PR lock. |
+| #4 [GHSA-8436-99hf-9mmv](https://github.com/advisories/GHSA-8436-99hf-9mmv), CVE-2026-85008 | Low | Undici >=8.0.0 <8.10.2 / 8.10.2 | A cache interceptor can suppress/replay state-changing HTTP requests. No cache interceptor is configured. | Same patch; fixed in PR lock. |
+| #2 [GHSA-vp8m-p9jh-q5pm](https://github.com/advisories/GHSA-vp8m-p9jh-q5pm), CVE-2026-85152 | High | Undici >=8.10.0 <8.10.2 / 8.10.2 | Shared originless cache/deduplication keys permit cross-origin poisoning. No such interceptor is configured; default Agent carries request origin. | Same patch; fixed in PR lock. |
+
+Static triage classified these eight supplied application claims as not actionable
+in the current inspected plugin/harness paths, rather than confirming them from
+package presence alone. All received cheap compatible preventive patches anyway.
+Future use of these features or untrusted network input would require reassessment.
+
+## Additional npm audit evidence
+
+`npm audit` also identified
+[GHSA-68fv-2mgg-jv7q / CVE-2026-93749](https://github.com/advisories/GHSA-68fv-2mgg-jv7q)
+in source-map-js >=1.0.0 <1.2.2 (high). An indexed source map with extreme section
+offsets can synchronously block the event loop. Its build/test dependency path is
+real; a complete attacker-controlled-map path in this project was not established.
+This was a potential build-time exposure requiring review, not a confirmed shipped
+plugin DoS. The 1.2.2 override removes the vulnerable version without relying on
+risk acceptance.
+
+The same Undici patch also covers npm's additional WebSocket decompression,
+subprotocol, unclean-close and HTTP decompression advisories
+([GHSA-3wwx-pv8p-q78v](https://github.com/advisories/GHSA-3wwx-pv8p-q78v),
+[GHSA-rfgv-xxqx-mfg5](https://github.com/advisories/GHSA-rfgv-xxqx-mfg5),
+[GHSA-rx4f-c7p8-82vq](https://github.com/advisories/GHSA-rx4f-c7p8-82vq),
+[GHSA-3xpg-4rpp-hhhm](https://github.com/advisories/GHSA-3xpg-4rpp-hhhm)).
+These concern malicious network responses in build/test libraries; no production
+Undici dependency or claimed runtime exploit was introduced. After locked install,
+`npm audit --json` returned exit 0 with zero reported vulnerabilities.
+
+No exploit PoC, exhaustive security scan or independent Node/BB host dependency
+audit is claimed. Hosted CI uses disposable GitHub runners, read-only permissions,
+no repository secrets, no persisted checkout credentials, no `pull_request_target`
+execution and no uploaded runtime artifacts. GitHub alerts on unchanged main can
+remain open until merge/reindexing; this task does not change their status.
diff --git a/docs/marketplace-0.7.0-proposal.md b/docs/marketplace-0.7.0-proposal.md
new file mode 100644
index 0000000..26011d1
--- /dev/null
+++ b/docs/marketplace-0.7.0-proposal.md
@@ -0,0 +1,30 @@
+# Marketplace update proposal — not submitted
+
+Current reviewed entry: `get-bb/marketplace/entries/agent-board.json`, source
+range `^0.6.1`. Preserve its id, source URL, category, author, icon and existing
+reviewed synthetic screenshot. After 0.7.0 publication, propose:
+
+```json
+{
+ "description": "Follow live BB agent activity, freshness, completion outcomes and monitoring health. Filter and group visible work by project, repository, provider or status. Optional Ollama Fleet and Redteam add worker visibility. Requires BB 0.40+; BB 0.46.0 recommended.",
+ "source": {
+ "git": {
+ "url": "https://github.com/aaronphifer/bb-plugin-agent-board.git",
+ "range": "^0.7.0"
+ }
+ }
+}
+```
+
+This is a fragment describing edits to the existing entry, not a standalone
+marketplace manifest. Copy the updated `PLUGIN_OVERVIEW.md` into
+`overview/agent-board.md`. Compatibility remains in package engines; do not add
+unsupported compatibility/version fields to the marketplace entry. Do not use
+live validation screenshots containing private task details as listing media.
+
+Existing installs retain their stored source range. Tell `^0.6.1` users to
+select/reinstall the new marketplace release or use the `^0.7.0` Git command in
+the upgrade notes. Do not ask them to uninstall, which would delete preferences.
+Publishing only a `v0.7.0` tag will not move their existing 0.6.x selector.
+
+No marketplace repository edits, PRs, submissions or announcements were made.
diff --git a/docs/release-convention.md b/docs/release-convention.md
new file mode 100644
index 0000000..1f409a1
--- /dev/null
+++ b/docs/release-convention.md
@@ -0,0 +1,26 @@
+# Release notes convention
+
+This work is unreleased. `0.7.0` is prepared on the development PR branch after
+the RC hardening/CI gates passed. It is not a public tag, release, marketplace or
+production update. The changelog preparation date is not a publication date.
+
+For each approved release:
+
+1. Finalize the `Unreleased` section of CHANGELOG.md, with user-facing changes,
+ relevant fixes, compatibility and known limitations. Move it to a versioned
+ section with the actual release date; keep earlier sections intact.
+2. Set package.json and the lockfile root to the same version. `lib/releases.ts`
+ imports that package version and provides the bundled announcement title and
+ highlights. Do not include unverified test claims in those highlights.
+3. Put the complete human-facing notes in RELEASE_NOTES.md, led by the new
+ version. Keep previous notes below it. Link compatibility/testing evidence.
+4. Use GitHub release title `Agent Board vX.Y.Z`, tag `vX.Y.Z`, and copy the
+ finalized release notes into its body. Keep pre-release builds marked as
+ pre-releases. A repository tag/release or marketplace change requires the
+ maintainer's explicit approval; this convention grants none.
+
+The UI reads only bundled notes, never GitHub or the marketplace. Dismissal is
+stored in plugin KV for the exact version (latest 20 dismissed versions), so
+reloads retain dismissal, upgrades show new notes, and a recent downgrade
+retains its old dismissal. Release notes can be opened later from the dashboard.
+Storage failures are shown, not silently treated as saved.
diff --git a/docs/upgrade-0.7.0.md b/docs/upgrade-0.7.0.md
new file mode 100644
index 0000000..7f3b62b
--- /dev/null
+++ b/docs/upgrade-0.7.0.md
@@ -0,0 +1,72 @@
+# Agent Board 0.7.0 compatibility and upgrade notes
+
+The current PR source is **0.7.0**, prepared but unpublished. Do not install it
+over a stable installation as part of release review. The public 0.6.1 tag remains
+the existing released installation until a separately approved publication.
+
+## Compatibility
+
+The package declares BB `>=0.40` and public Plugin SDK `>=0.4.21`.
+BB **0.46.0** is the recommended runtime, also the latest published `bb-app`
+version checked during this review on 12 October 2026. The development/test SDK
+remains pinned to **0.4.34**. The BB 0.40.0 builder stamps SDK 0.4.21; the
+BB 0.46.0 builder stamps SDK 0.6.37. These are different roles: the development
+pin supplies types/test harnesses, while BB builds and supplies runtime shims.
+The SDK and production dependencies are unchanged; development Hono, Undici and
+source-map-js received compatible patch fixes. No BB/SDK compatibility range was
+narrowed. See [dependency assessment](dependency-security-0.7.0.md).
+
+Phase 1 adds one BB SDK read, `projects.get`, using `name` and `gitRemoteUrl`.
+Both fields and that method exist in SDK 0.4.21. Project lookup is optional,
+bounded, cached and failure-tolerant. New announcement RPCs use existing plugin
+RPC and KV storage APIs. Existing realtime, navigation and lifecycle APIs are
+reused. No new permission/capability declaration, migration, provider access
+or external service is required.
+
+A disposable BB 0.40.0 runtime built, installed and served the preview.
+Candidate checks are detailed in the [validation summary](validation-0.7.0.md). A source-only
+typecheck against SDK 0.4.21 reports eight references to the newer optional queue
+`waitingOn` field; the unchanged 0.6.1 source reports the same eight errors.
+Those accesses already tolerate an absent field at runtime. New Phase 1 API
+uses pass that static comparison. This is not a claim that the full development
+suite runs on the oldest SDK harness.
+
+BB 0.40.0 could not refresh today's community catalog because it accepts at
+most 256 entries. Direct local plugin installation and RPC smoke work; use
+BB 0.46.0 for current marketplace discovery. Fresh Linux graphical-browser and
+physical-device checks remain limited. The RC subsequently passed Windows
+automated/build and browser/live-provider validation; prior Linux live-provider
+coverage applies to the same reviewed runtime source. See the validation summary
+for the distinction between fresh and historical checks.
+
+Fleet >=0.6.0 is optional. Redteam is optional and must actually expose
+`observability_snapshot` schema version 1; a version number alone is not enough.
+The installed local Redteam 0.7.2 does not expose it and correctly remains unavailable.
+
+## Existing users
+
+Agent Board keeps the same plugin identity (`agent-board`). Existing settings
+and attention-dismissal storage are retained; no manual migration or reset is
+needed. The new release-dismissal preference is separate and version-specific.
+The current announcement appears when upgrading from 0.6.1 or skipping earlier
+releases. Missing/malformed dismissal storage shows the announcement again;
+storage read/write failures are surfaced. Only the latest 20 dismissed versions
+are retained. Bundled notes can be reopened after dismissal.
+
+After final approval and publication only:
+
+```sh
+bb plugin install git:https://github.com/aaronphifer/bb-plugin-agent-board.git@^0.7.0
+```
+
+Reinstalling the same identity through BB replaces its source while retaining
+plugin preferences; do not remove/uninstall first, because removal deletes
+plugin storage. Exact tag/commit installations stay pinned. `^0.6.1` permits
+0.6.x but excludes 0.7.0. Changing the marketplace entry to `^0.7.0` affects new
+selections, not the selector already stored by an existing installation.
+
+BB checks managed Git/npm installations for compatible updates and presents
+them for an explicit update action. Path/builtin sources are pinned. Stable
+semver ranges exclude prereleases unless the range explicitly names one.
+Agent Board's What's New appears after installing a new version; it does not
+discover remote releases, send push notifications or install updates itself.
diff --git a/docs/validation-0.7.0.md b/docs/validation-0.7.0.md
new file mode 100644
index 0000000..e0124f5
--- /dev/null
+++ b/docs/validation-0.7.0.md
@@ -0,0 +1,65 @@
+# Agent Board 0.7.0 validation summary
+
+Version 0.7.0 is prepared on the PR branch and is unpublished. These checks support development review, not
+stable-release, marketplace or automatic-install approval. Detailed host-specific
+reports, logs, synchronization manifests and live screenshots are retained
+locally and excluded from the public commit.
+
+## Stable preparation and CI
+
+Release hardening patched the development Hono/Undici/source-map-js graph, which
+returned zero npm audit findings. The development SDK/BB runtime/production
+dependencies and animated activity source remain unchanged. A measured 100-second
+Windows cold icon import was addressed by prebundling its real data-only module
+without changing the 20-second hook limit or adding retries.
+
+The [hardening CI run](https://github.com/aaronphifer/bb-plugin-agent-board/actions/runs/38289933214)
+passed all three hosted jobs before stable promotion: Ubuntu and Windows full tests/
+typecheck, and Ubuntu BB 0.46.0 full build plus actual package inspection. Stable
+version tests/build/package checks run again before push and through the same
+workflow on the new head. Inspect PR checks for their current result; historical
+RC checks alone do not validate newly patched dependencies.
+
+See [dependency assessment](dependency-security-0.7.0.md) and [testing](vnext-testing.md).
+
+## Historical RC source and checks (12 October 2026)
+
+At the RC review, before public-documentation cleanup, 134 source inventory hashes matched between
+Windows and Pop!_OS. Public cleanup only changes documentation and one launcher's
+missing-tools help message; plugin implementation, tests, animation, dependencies,
+version and compatibility declarations remain the reviewed candidate.
+
+| Coverage | Result and provenance |
+| --- | --- |
+| Windows full suite | 468 tests / 24 files passed. The first cold-import timeout was followed by an unchanged passing full rerun. |
+| Windows adapter regression | 109 Fleet/Redteam tests / 6 files passed; a subset of the full suite. |
+| Windows focused checks | 37 announcement, dashboard, JSON and public-SDK tests / 4 files passed; a subset of the full suite. |
+| Windows typecheck / official build | Passed, BB 0.46.0 builder. Fresh frontend/backend metadata both identify the candidate. |
+| Pop!_OS RC review | Independently passed 468 tests / 24 files, 109 adapter tests, typecheck and official build. |
+| Minimum/current Linux runtime | BB 0.40.0 and 0.46.0 built, directly installed and served the RC in disposable hosts; RPC/app-asset/announcement smoke passed. |
+| Production-only Linux install | Clean runtime dependency/source build and installation passed without the development SDK. |
+| Actual Windows providers | Codex created and ran three Python unittests; Grok completed harmless delay/review tasks and explicitly reported tests not run. A controlled invalid-model failure appeared correctly. |
+| Actual Linux providers | Earlier Linux validation ran Codex/Grok tasks and host recovery on the preview. Linux RC build/install/RPC smoke was checked separately. New inference tasks were not rerun in the independent Linux RC review. |
+| Windows UI/storage | Monitoring health, saved attention preservation, version dismissal/reload/reopening, filtering/grouping, completion provenance, active animation, Open/Timeline and desktop/narrow rendering passed. |
+| Package inspection | Fresh 68-file Windows package: correct plugin/version metadata, required runtime assets, unchanged dependencies and no test/runtime/credential data. |
+
+Windows native BB worked in the inspected environment. This is empirical evidence,
+not a claim of general native Windows host support. Codex's Windows sandbox
+startup failures required scoped one-time approvals for the disposable fixture;
+no authentication, persistent permissions or networking settings were changed.
+
+The SDK 0.4.34 development pin differs from the builder SDK. A source-only
+typecheck against the declared 0.4.21 floor finds eight existing optional queue
+`waitingOn` typing errors, also present in unchanged 0.6.1. New Phase 1 SDK use
+is present at that floor and optional at runtime. This does not claim the full
+development harness runs against the oldest SDK package.
+
+Nonempty live Fleet/Redteam coverage remains limited. Optional Redteam needs the
+public schema-version-1 observability RPC; a version number alone is insufficient.
+BB 0.40.0's community-catalog entry cap limits current marketplace discovery,
+while direct installation works. Physical-device and fresh Linux graphical
+browser coverage remain separate. Existing bounded-history and agent-reported
+verification limits still apply.
+
+See [testing instructions](vnext-testing.md), [compatibility/upgrade notes](upgrade-0.7.0.md),
+[release notes](../RELEASE_NOTES.md) and [release procedure](release-convention.md).
diff --git a/docs/vnext-design.md b/docs/vnext-design.md
new file mode 100644
index 0000000..981b987
--- /dev/null
+++ b/docs/vnext-design.md
@@ -0,0 +1,40 @@
+# Phase 1 design (unreleased)
+
+Base: main, 92efdcdf89b838713dac7ebc9fc2eaef9e4b8860, plugin 0.6.1.
+Development branch: feature/agent-board-vnext. This is an unpublished
+release preparation. Stable installation and publication require separate approval.
+
+Reuse the public SDK collectors, normalized cards, bounded caches, lifecycle
+watcher, optional Fleet/Redteam adapters and React hooks. Codex/Grok observation
+is mediated by BB threads/providers; there are no provider session-file watchers.
+Preserve LiveStrip, its CSS, reduced motion, source privacy and collection caps.
+
+Add pure dashboard derivation for freshness, filters/grouping and completion
+sections. Freshness uses source activity timestamps rather than fetch times or
+thread updatedAt (which can include cosmetic changes). Old observations mean
+quiet reporting, never failed/stalled work. Verification extracted from labeled
+output remains agent-reported, not independently verified. Full output remains
+accessible in BB through Open; the plugin keeps its bounded sanitized preview.
+
+Enrich global executions with project names/git remotes using bounded public
+projects.get calls for observed project IDs. Missing metadata is explicit and
+must not prevent native observation. Filter only the already bounded snapshot;
+the page states that matching sessions outside that window are not searched.
+Attention stays visible independently of execution filters.
+
+Separate transport connection, successful snapshot refresh and server watcher
+health. Record timestamps and generic error categories only. Quiet connections
+are not errors. Catch asynchronous watcher errors and failed publication instead
+of leaking rejected promises; expose degradation in the snapshot.
+
+Add a small version-keyed release dismissal store using plugin KV and bundled
+release highlights. Use the package version as the single version source. A
+release-notes control remains available after dismissal; storage failures stay
+visible. No network, account, telemetry or external release fetching.
+
+Automated validation uses the official SDK fake server/app hosts, synthetic
+data, separate dependencies and isolated storage. Real provider checks use a
+verified separate BB data directory and loopback ports; never install a preview
+into the production host. See [testing](vnext-testing.md) and
+[candidate validation](validation-0.7.0.md).
+No Lattice runtime integration or future orchestration/analytics is added.
diff --git a/docs/vnext-testing.md b/docs/vnext-testing.md
new file mode 100644
index 0000000..7b09b62
--- /dev/null
+++ b/docs/vnext-testing.md
@@ -0,0 +1,144 @@
+# Development launch and verification
+
+Use Node.js 24 and an isolated BB host. Version `0.7.0` is prepared on the PR
+branch and is unpublished. See [candidate validation](validation-0.7.0.md) for
+cross-platform results and their limits. Never install a review build over the
+stable plugin, share its data directory, or copy its credentials into a test host.
+
+## Pull request CI
+
+The `Release validation` workflow runs for PRs targeting `main`, using official
+GitHub-hosted Ubuntu and Windows runners with Node 24. Both run locked installation,
+the full suite and typecheck. Ubuntu additionally prepares separate pinned BB
+0.46.0 tools, runs the official full production build and `npm run verify:package`.
+The inspector checks the actual tar archive, required assets, version metadata
+and private/runtime-data exclusions. It leaves its temporary package outside Git.
+
+Permissions are `contents: read`; official Actions are pinned to commit revisions
+and checkout credentials are not persisted. No secrets, self-hosted runners,
+`pull_request_target`, release/tag jobs or sensitive artifact uploads are used.
+Test failures remain failures: there are no unconditional retries or blanket
+timeout increases. A clean local Windows install took 100 seconds importing the
+large icon barrel and exceeded the existing 20-second app-hook limit. Vitest now
+prebundles that data-only dependency once; real icon exports, app code and hook
+limits are preserved. Fresh hosted timings validate this harness change.
+See [dependency assessment](dependency-security-0.7.0.md).
+
+## Automated checks
+
+From the candidate checkout:
+
+```sh
+npm ci --ignore-scripts --no-audit --no-fund
+npm test
+npm run typecheck
+```
+
+The suite uses the public SDK fake hosts, synthetic fixtures and isolated
+storage. Vitest uses a serial thread pool for reliable Windows startup. A cold
+import timeout has been observed: record the failed run, investigate it and
+rerun unchanged checks; do not count a timeout as a pass. The development SDK
+pin is 0.4.34. The official BB 0.46.0 builder stamps SDK 0.6.37; these serve
+different roles and a build notice does not authorize upgrading the pin.
+
+## Guarded Windows helpers
+
+The helpers intentionally require this disposable workspace layout:
+
+```text
+/outputs/agent-board-vnext/ candidate checkout
+/work/bb-build-tools/ isolated official BB tools
+/work/bb-validation-windows-data/ test data; preserve across restarts
+```
+
+Prepare tools outside the checkout, from ``:
+
+```powershell
+npm install --prefix work\bb-build-tools --ignore-scripts --no-audit --no-fund bb-app@0.46.0
+```
+
+Use an environment with working native SQLite dependencies. The native Windows
+host was exercised successfully during this review; that is empirical coverage,
+not a general platform-support promise. Prefer the supported Linux/WSL host
+where available; do not change system networking or authentication to make a
+validation environment work.
+
+From the candidate checkout, build and start in one terminal:
+
+```powershell
+$env:BB_CLI=''
+.\scripts\build-dev.ps1
+.\scripts\validation-host.ps1 start
+```
+
+After the test host is healthy, in a second terminal in the same checkout:
+
+```powershell
+$env:BB_CLI=''
+.\scripts\validation-host.ps1 install
+.\scripts\validation-host.ps1 status
+```
+
+Open and choose Agent Board. Server/daemon ports are
+49986/49987; telemetry and in-app updates are disabled for this host. Install
+and stop verify the launcher marker, executable path, URL and process identity.
+The build helper uses separate build data and restores the caller's environment.
+
+After all disposable tasks finish:
+
+```powershell
+$env:BB_CLI=''
+.\scripts\validation-host.ps1 stop
+```
+
+Keep the test data. Do not uninstall to test an upgrade: replacing the same
+plugin identity preserves preferences, while uninstalling deletes them.
+
+## Guarded Linux helper
+
+`scripts/linux-validation-host.sh` uses only
+`$HOME/.local/share/agent-board-vnext-validation/`, loopback ports 50886/50887,
+and the source checkout containing the script. It refuses occupied start ports
+and verifies the launcher identity before install/stop. Prepare its dedicated
+`node24/` directory with an official Node 24 distribution verified against the
+vendor checksums; keep it separate from system and production runtimes.
+
+```bash
+runtime="$HOME/.local/share/agent-board-vnext-validation"
+npm install --prefix "$runtime/bb-tools" --ignore-scripts --no-audit --no-fund bb-app@0.46.0
+(cd "$runtime/bb-tools" && npm rebuild better-sqlite3)
+bash scripts/linux-validation-host.sh build
+bash scripts/linux-validation-host.sh start
+```
+
+In another terminal, from the candidate checkout:
+
+```bash
+bash scripts/linux-validation-host.sh install
+bash scripts/linux-validation-host.sh status
+```
+
+Open . Stop only that test host after tasks finish:
+
+```bash
+bash scripts/linux-validation-host.sh stop
+```
+
+The older `scripts/dev-host.sh` is a workspace-layout-specific WSL helper using
+`/work/bb-linux-tools`, `/work/bb-wsl-data` and ports
+49886/49887. It does not share selectors with the native Windows or Linux
+validation hosts. Inspect selectors and prerequisites before using any helper.
+
+## Acceptance checks
+
+Use a disposable project for real provider work. Verify connected transport,
+refresh/watch health, project/repository/provider/status filters and grouping,
+attention preservation, completed results with explicit verification provenance,
+controlled failure states, Open/Timeline navigation, active animation and
+version-scoped announcement dismissal/reload/reopening. Test a narrow viewport
+as well as desktop and reset temporary viewport overrides afterward.
+
+Agent-reported checks are not independent test evidence. Quiet reporting does
+not prove a stall. Optional Fleet/Redteam fixtures do not replace nonempty live
+adapter coverage. Save detailed local logs/screenshots in ignored `evidence/`;
+do not publish private task text, paths, databases or credentials.
diff --git a/hooks/useGlobalDashboard.ts b/hooks/useGlobalDashboard.ts
index 20bb78b..e9defb7 100644
--- a/hooks/useGlobalDashboard.ts
+++ b/hooks/useGlobalDashboard.ts
@@ -1,6 +1,6 @@
// Global dashboard data hook. Core thread events drive immediate refreshes;
// one slow bounded discovery check catches unrelated optional-plugin work.
-import { useCallback, useEffect, useMemo, useRef, useState } from "react";
+import { useCallback, useEffect, useRef, useState } from "react";
import { useRealtime, useRealtimeConnectionState, useRpc } from "@get-bb/plugin-sdk/app";
import {
BOARD_CHANGED_CHANNEL,
@@ -25,6 +25,8 @@ export function useGlobalDashboard() {
const [refreshing, setRefreshing] = useState(false);
const [error, setError] = useState(null);
const [tick, setTick] = useState(0);
+ const [lastSignalAt, setLastSignalAt] = useState(null);
+ const [lastRefreshAt, setLastRefreshAt] = useState(null);
const snapshotRef = useRef(null);
const inflight = useRef(false);
/**
@@ -52,6 +54,7 @@ export function useGlobalDashboard() {
if (id !== requestId.current) return;
snapshotRef.current = result;
setSnapshot(result);
+ setLastRefreshAt(Date.now());
setError(null);
},
(cause: unknown) => {
@@ -79,7 +82,7 @@ export function useGlobalDashboard() {
}, [refetch]);
useRealtime(BOARD_CHANGED_CHANNEL, (payload) => {
- if (isForGlobalDashboard(payload)) refetch();
+ if (isForGlobalDashboard(payload)) { setLastSignalAt(Date.now()); refetch(); }
});
const connectionState = useRealtimeConnectionState();
@@ -129,19 +132,10 @@ export function useGlobalDashboard() {
return () => clearInterval(timer);
}, [refetch]);
- const hasLive = useMemo(
- () => snapshot?.active.some((execution) =>
- execution.card.status === "running" ||
- execution.card.status === "starting" ||
- execution.card.status === "waiting",
- ) ?? false,
- [snapshot],
- );
useEffect(() => {
- if (!hasLive) return;
const timer = setInterval(() => setTick((value) => value + 1), 1_000);
return () => clearInterval(timer);
- }, [hasLive]);
+ }, []);
return {
snapshot,
@@ -153,5 +147,7 @@ export function useGlobalDashboard() {
dismissAttention,
clearDismissedAttentions,
connectionState,
+ lastSignalAt,
+ lastRefreshAt,
};
}
diff --git a/lib/bb-source.ts b/lib/bb-source.ts
index 019a951..c7e812a 100644
--- a/lib/bb-source.ts
+++ b/lib/bb-source.ts
@@ -15,6 +15,7 @@
// presentation labels, outputs.
// - Statuses are mapped losslessly enough to drive column placement.
import type { BbPluginApi } from "@get-bb/plugin-sdk";
+import { reportedCompletion } from "./dashboard-view";
import type {
BoardActivity,
BoardActivityFeed,
@@ -206,6 +207,20 @@ export function latestPublicUpdate(rows: readonly TimelineRow[]): string | null
return publicUpdatePreview(last.text);
}
+/** Work and public assistant timestamps; excludes reasoning/user/cosmetic events. */
+export function latestPublicActivityAt(rows: readonly TimelineRow[]): number | null {
+ const times: number[] = [];
+ for (const row of flattenRows(rows)) {
+ if (row.kind === "work" && !("presentation" in row && row.presentation?.suppress === true)) {
+ times.push(("completedAt" in row ? row.completedAt : null) ?? row.startedAt);
+ } else if (row.kind === "conversation" && "role" in row && row.role === "assistant") {
+ times.push(row.createdAt);
+ }
+ }
+ const valid = times.filter(at => Number.isFinite(at) && at >= 0);
+ return valid.length ? Math.max(...valid) : null;
+}
+
/** Compact human label for a work kind (recent-activity rows). */
export function workKindLabel(workKind: string): string {
switch (workKind) {
@@ -499,6 +514,8 @@ export function normalizeThread(
phaseTitle: null,
promptPreview: null,
activity: latestActivity(facts.timeline.rows),
+ lastActivityAt: latestPublicActivityAt(facts.timeline.rows),
+ ...reportedCompletion(facts.output ?? delegation?.output),
outputPreview:
previewText(facts.output ?? delegation?.output ?? null, BOARD_LIMITS.outputPreviewChars) ??
null,
diff --git a/lib/board-model.ts b/lib/board-model.ts
index a43005c..51b29cc 100644
--- a/lib/board-model.ts
+++ b/lib/board-model.ts
@@ -203,7 +203,8 @@ export function formatElapsed(ms: number): string {
/**
* Live elapsed for a card between authoritative snapshots: use durationMs
- * when the work finished, otherwise clock from startedAt against `now`.
+ * when the work finished, otherwise clock live work from startedAt against `now`.
+ * Terminal work without an authoritative end time has unknown duration.
*/
export function cardElapsedMs(card: BoardCard, now: number): number | null {
if (card.durationMs !== null && card.durationMs !== undefined) return card.durationMs;
@@ -211,5 +212,6 @@ export function cardElapsedMs(card: BoardCard, now: number): number | null {
if (card.completedAt !== null && card.completedAt !== undefined) {
return Math.max(0, card.completedAt - card.startedAt);
}
+ if (["completed", "failed", "interrupted", "skipped"].includes(card.status)) return null;
return Math.max(0, now - card.startedAt);
}
diff --git a/lib/collect.ts b/lib/collect.ts
index bbcc8f4..124b1d2 100644
--- a/lib/collect.ts
+++ b/lib/collect.ts
@@ -10,7 +10,7 @@
// say so instead of lying by omission.
import type { BbPluginApi } from "@get-bb/plugin-sdk";
import type { BoardCard, ExecutionTimeline, ExecutionTimelineInput, GlobalDashboardSnapshot } from "../contract/rpc";
-import { BOARD_LIMITS, columnForStatus, countCards, previewText } from "./board-model";
+import { BOARD_LIMITS, columnForStatus, countCards, previewText, redactOperationalText } from "./board-model";
import {
activityFromEvents,
normalizeThread,
@@ -37,6 +37,19 @@ import {
import { FleetSource, scopedFleetCards, addFleetGroups, fleetTimelineEvents, fleetActive } from "./fleet-source";
import { normalizeBbTimeline } from "./timeline-model";
+/** Remote label only, stripped of credentials/query/fragment; never a link. */
+export function safeRepositoryLabel(remote: string | null | undefined): string | null {
+ if (!remote) return null;
+ try {
+ const url = new URL(remote);
+ if (!["https:", "http:", "ssh:", "git:"].includes(url.protocol)) return null;
+ return previewText(redactOperationalText(`${url.host}${url.pathname.replace(/\.git$/, "")}`), 240);
+ } catch {
+ const scp = /^(?:[^@\s]+@)?([\w.-]+):([\w./-]+?)(?:\.git)?$/.exec(remote);
+ return scp ? previewText(redactOperationalText(`${scp[1]}/${scp[2]}`), 240) : null;
+ }
+}
+
/** Output of board_snapshot (shape matches contract/rpc.ts). */
export interface BoardSnapshot {
root: ReturnType;
@@ -64,6 +77,8 @@ interface CacheEntry {
at: number;
value: V;
}
+type ProjectMetadata = { name: string | null; repository: string | null };
+export const PROJECT_METADATA_TIMEOUT_MS = 750;
export class BoardCollector {
private readonly sdk: Sdk;
@@ -74,6 +89,8 @@ export class BoardCollector {
private readonly outputCache = new Map>();
private readonly modelCache = new Map>();
private providersCache: CacheEntry