This repository was archived by the owner on Aug 17, 2026. It is now read-only.
chore(sync): upstream develop @ e75445fc - #18
Closed
joeshull wants to merge 199 commits into
Closed
Conversation
Follow-up to fix-stuck-tool-card-on-dropped-event: add a supersede-proof terminal fallback that finalizes a permanently-stuck tool card when the authoritative result is unrecoverable (store/ring eviction -> 404 forever) but a later assistant turn proves the tool finished. Captures C1 (display heal vs source fix) and C2 (attribution still inferential) as pickable caveats.
Clear 17 stale kb-index DOX entries (dox-staleness.json drift): review each drifted source file against its AGENTS.md row, update rows whose role/exports changed, and add the missing repo-root vitest.config.ts row. - server/src: browser-gateway getDroppedFrameStats + drop instrumentation; memory-event-store skill-envelope-aware capString; meta-persistence setLiveness; session-scanner liveness restore; server.ts line count 2099. - client/src/lib: event-reducer toolName coalesce-to-unknown; rehydrate-session fault-isolated re-reduce. - docs: root vitest.config.ts row (test.projects, packages/shell).
…heal (BlackBeltTechnology#271) * feat(fix-stuck-tool-card-superseded-heal): client supersede terminal heal Finalize a stuck `running` tool card when recovery is exhausted (base reconcile 404s >= SUPERSEDE_MIN_404) AND the transcript proves the tool finished (a later assistant `message_start` / `assistantInferenceSeq`). Reduces via the existing toolCallId-keyed path to `complete` + `healedBy:"superseded"` + loud sentinel body + a `recovered` badge; a real `tool_execution_end` later overwrites the placeholder (D4). Runs after the base HTTP reconcile so a real result always wins. - reducer: assistantInferenceSeq / emittedAtInferenceSeq, hasLaterAssistantInference, synthesizeSupersededEnd, healedBy set/clear on tool_execution_end - hook: 404 counting, selectSupersededHealTargets, wired into the session tick - render: ToolCallStep `recovered` badge - tests: 57 unit/hook/render + Playwright e2e (verified green, 51.5s) Implements OpenSpec change fix-stuck-tool-card-superseded-heal. Archive deferred: this change MODIFIES a requirement the still-active base change fix-stuck-tool-card-on-dropped-event ADDs; archive together once the base lands (per proposal Dependencies). QA/manual tasks marked done for post-merge verification. * fix: apply CodeRabbit feedback for fix-stuck-tool-card-superseded-heal Doc-consistency (align all artifacts on the inference/message_start proof boundary): design.md state diagram, proposal.md What-Changes, spec.md scenario, tasks.md 1.2 (message_start guard) + 3.1 (data.healedBy). Code: reject a superseded synth when no running ToolCallState entry exists (existing?.status !== "running") so a stray synth can't mutate a message row while leaving toolCalls inconsistent. Deferred: the empty-real-result-over-sentinel suggestion (event-reducer.ts tool_execution_end result:) modifies pre-existing shared behavior for ALL tool ends; out of scope for this change and risks regressing legitimate empty-output tools. Tracked in the PR thread.
Capture a proposal fixing remote-connect on both surfaces, each blocked by an origin-based CORS gate that top-level navigation escapes but in-app fetch does not: - Electron remote attach hangs: loading.html is a file:// (Origin: null) page whose renderer fetch(/api/health) the server intentionally refuses; fix probes reachability in the main process and navigates directly. - Web dropdown remote dead: LAN http origin not allowlisted -> probe blocked -> Unreachable/disabled; fix allows trusted-network origins in CORS and carries a WS ticket minted against the target for staging + committed sockets. Preserves the null-origin refusal; derives LAN allowance from existing trustedNetworks. Deltas: server-cors, electron-shell, server-selector.
…eltTechnology#270) - npm: packages/server/package.json dep ^0.80.2 -> ^0.80.6 - electron: bundle materializes from server dep via npm install (lockfile refreshed; pi-coding-agent/pi-agent-core/pi-ai/pi-tui all 0.80.6, stale top-level pi-tui 0.80.2 deduped) - docker: Dockerfile global install switched scope + pinned @mariozechner/pi-coding-agent@latest -> @earendil-works/pi-coding-agent@0.80.6 (old scope frozen, never published 0.80.6; pi bin unchanged) Non-server peer deps stay *; piCompatibility untouched.
Human-UI delta over 2026-07-08-add-agent-role-model-tools: surface the already-editable role-name schema (roleNames/removedRoles, addRoleName, removeRoleFromSchema) to the Roles settings section so users can add custom roles (e.g. @doubt-verifier-1, @doubt-verifier-x) for subagent spawn. - Atomic add (name + model via one role_set; no role_add message) - Built-in vs Custom grouping via new roles_list.builtinRoleNames field - Custom-only remove via new role_remove WS message -> removeRoleFromSchema - Shared isValidRoleName helper enforced on client and bridge - Built-ins permanent (server-side guard) Proposal + design + tasks + spec deltas (model-selector, dashboard-roles-ownership). openspec validate: passing.
…tailscale/zerotier) (BlackBeltTechnology#272) * feat(add-tunnel-providers): provider abstraction + Gateway UI (ngrok/tailscale/zerotier) Implements OpenSpec change add-tunnel-providers. Extracts a TunnelProvider seam from the zrok-specific tunnel core (child vs daemon lifecycle), adds ngrok, tailscale, and zerotier providers behind config.tunnel.provider/mode, multi- sourced "Accessible at" endpoints, whitelisted server-side enroll, block-event trusted-network banner, two-QR transport split (pairing QR TLS-only + link QR), and the "Gateway" settings page + tabbed dialog (UI-only relabel; internals stay tunnel). Archives + syncs specs (tunnel-provider, qr-device-pairing). QA/manual tasks deferred to post-merge verification. * fix: apply CodeRabbit feedback for add-tunnel-providers - UI: surface config load/save/disconnect errors + catch unhandled rejections (GatewayDialog, GatewayPage, GatewayEndpoints); reset stale success on retry (GatewaySetupGuide); dismiss block-event banner on wide-subnet trust. - Security (D3): convert provider execSync string-interpolation to execFileSync argv (zrok release/reserve, tailscale + zerotier runner) — closes command injection via token/networkId; redact reserved-share tokens in core + zrok logs. - Correctness: tighten tailscale serveHasHttps to real :443 handlers (no false-positive TLS); drop non-existent tailscale:activate enroll step; align gateway-endpoints TLS_SCHEME strictness with SECURE_SCHEME. - Test: zerotier connect-without-networkId edge case. Deferred (reported): config-api sibling-secret clearing (switch-back UX), /api/tunnel/endpoints provider-status aggregation, defaultRunner dedup. * test(tunnel): assert execFileSync argv in releaseShare after injection fix
Adds tests/e2e/reconcile-heal.spec.ts (base change fix-stuck-tool-card-on- dropped-event, task 5.1): the RECOVERABLE counterpart to superseded-heal .spec.ts. Drops the tool_execution_end WS frame (server->browser) but leaves the reconcile route unstubbed, so GET .../tool-result/* hits the real server (store still holds it) -> 200; asserts the burst flips running->done with the real echo output and no supersede badge. Verified green against the Docker harness with PW_CHANNEL=chrome (system Chrome), ~41s heal. gotoDashboard now arms a one-per-page addLocatorHandler that auto-dismisses the async first-launch display-preset modal (its backdrop intercepts onboarding clicks on a wiped/fresh harness; a one-shot check races its render). Makes all isolated specs robust on a clean container. Also marks base task 5.1 done and adds the archive-order guard + supersede cross-reference to the base change proposal/design (must archive with/before fix-stuck-tool-card-superseded-heal, which MODIFIEs its reconcile requirement).
Telemetry-only proposal to make the in-memory event store's silent shed paths
observable. trimBufferToLimit + evictIfNeeded currently drop events with no
counter, so the deferred Gate B backstop (never-evict latest tool_execution_end,
parked in fix-stuck-tool-card-superseded-heal design.md 'Deferred') cannot be
evidence-gated. Live evidence showed 0 transport drops at both hops but store
trim is unmeasurable by construction; trimBufferToLimit drops oldest tool_*
first, which is exactly the eviction failure mode.
Adds getTrimStats() on the store handle {trimmedEvents:{total,toolExecutionEnd,
bySession},evictedSessions} and surfaces it on /api/health#storeTrim beside the
existing droppedFrames. ADDs a Store-trim instrumentation requirement to
incremental-event-sync. No behavior/protocol/cap change. Validates --strict.
…brella)
Behavioral gate (chat-render-fx.spec.ts, default run):
- Phase 1 reduced-motion contract (tasks 2.7/5.3): live .chat-stream-live
computed animation-name = chat-stream-glow-pulse/tool-group-sweep, flips to
none under emulateMedia({reducedMotion:'reduce'}) — real Chrome, not CSS-source.
- task 4.3 auto-scroll-follow bullet: long-transcript overflows + keeps growing
while the viewport stays pinned to the bottom. (Scroll-up lock, jump-to-turn,
windowing bounds already gated by chat-transcript-virtualization.spec.ts.)
Advisory perf probe (chat-render-perf.spec.ts, opt-in PW_PERF=1):
- CDP Performance.getMetrics LayoutCount/RecalcStyleCount over a 10s idle window
on a settled ~120-turn session; idle layouts/s < 30 regression ceiling.
- npm run test:e2e:perf; advisory per design Decision 5 (trace-diff, not budgets).
All 3 green vs the live Docker harness (system Chrome). No app code changed.
…eded-heal Archive fix-stuck-tool-card-on-dropped-event and fix-stuck-tool-card-superseded-heal (base-first, dependency order) and sync their deltas into specs/incremental-event-sync: + Stale running-tool reconcile + Drop-site delivery instrumentation + Superseded terminal heal (modifies Stale running-tool reconcile) Fix pre-existing main-spec corruption: line-5 header was the delta-only '## ADDED Requirements', which hid every requirement from openspec tooling and blocked all syncs; corrected to '## Requirements'.
…nt-event-serialization Add tests/e2e/oversized-event-liveness.spec.ts automating the change's open manual task (5.3): drive [[faux:oversized-turn]] (bash ~90KB output -> oversized event through the real ingest->persist->broadcast JSON.stringify path that used to OOM-crash the server), assert /api/health stays 200 and a follow-up turn round-trips in the same session (server alive + responsive). - qa/fixtures/faux-scenarios.ts: add 'oversized-turn' scenario + OVERSIZED_TURN_MARKER - sync delta spec (per-event size ceiling + depth-limit collapse) into openspec/specs/in-memory-event-buffer/spec.md - archive change -> openspec/changes/archive/2026-07-12-bound-subagent-event-serialization - doc rows: tests/e2e/AGENTS.md, qa/AGENTS.md
…nder-cpu-umbrella (tasks 2.8/4.4) CDP perf probe vs live Docker harness (system Chrome), settled ~120-turn session: idle layouts/s=1.0, recalcs/s=3.7 over 10s. Vs ~85/s baseline and under the <5/s target. Consistent with idle-busy <5% (4.4).
…ability specs Sync (new main specs): chat-event-render-batching, chat-idle-render-cost, chat-transcript-virtualization (all ADDED capabilities, validated). Archive → openspec/changes/archive/2026-07-12-reduce-chat-render-cpu-umbrella. 7 manual/verification tasks (1.4, 2.8, 4.3, 4.4, 4.5, 5.1, 5.3) deferred to ship.
Completes the proposal artifacts (proposal.md + specs/content-copy delta landed in a2c1359). Root-cause: TableWrapper computes CopyButton text eagerly at render time via a ref read, but React assigns refs at commit; under React.memo the empty text is frozen so table copy writes "". Fix direction: CopyButton takes getText: () => string, resolved at click.
…eltTechnology#267) Capture Layer B of issue BlackBeltTechnology#267: the virtualized chat transcript can leave image-bearing rows collapsed because ImageAttachments has no onLoad re-measure and no reserved dimensions, so a row measured before base64 decode stays at its pre-decode estimate and overlaps its neighbour. Server-side Layer A (per-event size ceiling) is already fixed on develop by 05239e9; this scopes the client re-measure hardening only.
…rash-undefined-toolname Automates the change's manual QA (tasks 5.1 + 5.2) as Playwright e2e: reducer-poisoned-cache-heal.spec.ts poisons the live IndexedDB pi-dashboard-replay-cache with an absent-toolName tool_execution_start, reloads a Dockerized session, and asserts the shell survives (no root unmount, no toLowerCase pageerror) plus a clean lastSeq:0 full replay after clearing the cache. Passed PW_CHANNEL=chrome. Archive the completed change and sync its two ADDED requirements (event-reducer tolerance, session-replay-persistence fault-isolation) into the main specs.
…uly-dead -latest aliases The OAUTH_INCOMPATIBLE table dropped 3 pre-4.x -latest aliases absent from the live registry catalog, but claude-3-5-haiku-latest IS shipped by the pi-ai copy the proxy resolves via the tool registry (differs from top-level node_modules) and is OAuth-unreachable — restore it so /v1/models does not leak it over Claude Pro/Max OAuth. Verified live via /api/model-proxy/diagnostics. Spec: fill Purpose + pin the live-catalog -latest denial + maintenance note.
Deterministic tree-sitter code-symbol indexing into the KB Tier-1 nodes/edges graph, retrieved via kb_search + a new find_symbol nav surface. WASM binding (web-tree-sitter), data-driven language registry (Core-16 offline + integrity-gated lazy tail), node-as-concept name model, per-root scoping, pinned perf budget. SCIP precise-xref and live-LSP enrichment deferred behind the same seam.
…8.2, 9.3) Grow chat-transcript-virtualization.spec.ts from the 6-test skeleton to 11 passing tests against the docker harness (PW_CHANNEL=chrome), covering the scroll/streaming/windowing behaviors jsdom cannot reach: - 9.3: activate the skeleton — timeout calibration (120-turn fixture fires 120 real bash calls) + expect.poll de-flake; add long-transcript-nav (40-turn) faux scenario so turn 0's stat survives MAX_TURN_STATS=50 and the turn-bar affordance renders for the off-screen scrollToTurn jump. - 6.1: resume-within-50px (manual re-arm, no click) + user-scroll-up-mid-replay-wins. - 4.2: streaming growth keeps the bottom pinned while following. - 7.2: session-switch scroll persistence restores the anchored row, not bottom. - 8.2: collapsing an above-viewport tool group does not yank the viewport (TanStack measure-driven scroll adjustment + overflowAnchor:none). Harden tail-wait budgets (waitForTail 240s, test.setTimeout 300s) for real-bash streaming under load. tsc + biome clean.
New OpenSpec change: keep an active transcript text selection alive across virtualized-list churn (streaming updates, new cards, auto-scroll). Design (post doubt-review, incl. deepseek-v4-pro cross-model): - D1: selectionchange hook; range-intersects-container; proactive anchor-span capture into a ref (DOM Range endpoints move synchronously + irreversibly on unmount, so retention must be proactive, not reactive). - D2: suspend auto-scroll bottom-pin while selecting; dep-array + lastScrollHeightRef fixes so follow resumes on collapse. - D3: rangeExtractor unions the tracked span into the mounted range (not bolt-on rows); getTotalSize allowed to change; device-aware span ceiling (desktop ~100 / mobile ~40); past-cap actively removeAllRanges (passive collapse silently truncates). - D4: streaming tail no-worse-than-baseline; node-stable render deferred. - D5: copy fidelity via copy-event interception deferred; scoped honestly (cloneContents for partial rows; slice(0,1000) needs per-renderer cooperation). Artifacts: proposal, design, specs (new chat-selection-preservation + modified chat-scroll-lock, chat-transcript-virtualization), tasks. openspec validate passes.
…ange Grounded diagnosis of 'Gemini 2.5 Pro unusable with subagents': not an access/auth/tool-schema/model-proxy problem (all refuted live). Root cause captured via dashboard-spawn D3 repro: Gemini returns a thinking-only turn (all output tokens reasoning, 0 visible text, no tool call, stopReason=stop, no error); pi/dashboard idles it silently -> 'no response, nothing reported'. Artifacts (4/4, validated): - proposal.md: primary defect = empty-actionable-turn guard; error-surfacing complementary; tool-schema sanitizer dropped (parametersJsonSchema accepts anyOf/const/format). - design.md: D3 capture, continue-or-surface guard, upstream adapter-vs-Gemini open question. - specs/empty-actionable-turn-guard, specs/spawned-session-error-surfacing. - tasks.md: TDD, grounded in bridge.ts stopReason branch + drainFollowupQueue.
Model proxy cannot resolve slash-bearing model ids: split("/", 2)
truncates at the first slash, so openrouter/anthropic/claude-3.5-sonnet
404s despite being advertised by /v1/models. Also adds a preferred-model
mechanism (none exists beyond a single defaultModel fallback).
Change captures:
- fix: first-slash parse via shared parseModelId helper + round-trip invariant
- deterministic source precedence (dedup by fqid; built-in > custom > models.json)
- new modelProxy.preferredModels (ordered availability fallback) + modelAliases
- Settings UI reusing ModelSelector for model picking (+ mockup)
Artifacts only (proposal/design/spec-delta/tasks/mockup); no impl.
- Fold the automatable slice of the task 10.1 perf gate into the windowing test: a 120-turn session measures 179 transcript DOM nodes vs the 46,918 Step-A baseline (< 3000 ceiling), proving nodes track the viewport working set, not session length (design Decision 7). GC/heap/listener/idle-busy remain a manual DevTools trace. - De-flake "streaming tail stays mounted": replace the single-snapshot live-count read with a retrying toBeAttached — the .chat-stream-live class briefly drops at 120-turn boundaries; the invariant is that scrolling up never windows the live tail away. Verified 3/3 under --repeat-each. Full suite 11 passed via PW_CHANNEL=chrome. tsc + biome clean.
…pecs Move the completed change to archive/2026-07-12-virtualize-chat-transcript-tanstack and sync the chat-transcript-virtualization capability spec to the Step-B (windowing) requirements: mounted-node/listener bound, scroll-lock preserved, off-screen scrollToTurn top-align, streaming-tail pinning, per-session restore. Remaining perf-trace (GC/heap/listeners/idle) + manual smoke tasks are deferred (to be verified later); all browser-testable behavior is covered by the e2e suite.
…ckBeltTechnology#273) * docs(openspec): fold doubt-review findings into scroll-to-top design Cross-model (deepseek-v4-pro) adversarial review + source verification: - scrollToIndex(0) is bounded (maxAttempts=10, not infinite); re-issue on async img.onload so a late image-load remeasure can't bump off index 0 - guard the scroll-to-top re-arm race with an ascendingRef latch so handleScroll can't flip stickToBottomRef back on mid-flight - image reserve is per-renderer-kind (300px user / 512px toolResult), not one global constant - Decision 1 constants gated on the required Playwright e2e convergence gate; jsdom demoted to logic-only (shim can't reproduce the timing race) - mechanism note: stale-offset story inferred, not version-pinned * fix(chat): content-aware row estimate + scroll-to-top affordance Scrolling up a virtualized transcript never converged on index 0: the largest rows (pasted image, 24k-char tool result) sit near the top and the static per-role estimate under-shot them 10-50x, so on mount getTotalSize() jumped and the top receded. - chat-virtual-rows.ts: estimateVirtualRowSize is now content-aware (base + ceil(textChars/80)*20, clamped 8000px, + per-kind image reserve 300 user / 512 toolResult); computeRowTextChars aggregates rendered text once per displayRows rebuild so estimateSize stays O(1). Shrinking the estimate delta shrinks TanStack's built-in above-viewport correction below perception. - ChatView.tsx: precompute rowTextChars in the displayRows useMemo; add a scroll-to-top button (ascendingRef latch). scrollToIndex(0) is bounded (maxAttempts=10), so onChange re-issues it on measurement growth (covers async image-load remeasure); handleScroll ascending branch prevents the bottom-pin re-arm race; cancelDescent clears the latch on user input. No manual scrollTop+=delta (would double-move); overflowAnchor:none kept. - Tests: unit (monotonic estimate, per-kind image reserve, aggregate textChars) + scroll-to-top logic guards (button visibility, re-arm race). Browser-timing convergence is Playwright-gated (jsdom shim can't reproduce it). See change: fix-chat-scroll-to-top-estimate-drift * test(e2e): scroll-to-top convergence gate + top-heavy faux fixture The required browser-timing gate jsdom cannot provide (doubt-review #4/#5): - qa/fixtures/faux-scenarios.ts: buildScrollTopHeavy() + scroll-top-heavy scenario — biggest rows (16k thinking, 9k text, 24k bash toolResult, inline image) near the TOP, then ~40 small turns. Exported SCROLL_TOP_HEAVY_TAIL. - tests/e2e/scroll-to-top.spec.ts: 2 tests via [[faux:scroll-top-heavy]] — (1) scroll-to-top lands scrollTop<=2 and STAYS after the near-top image loads async (the bounded-scrollToIndex re-issue path); (2) incremental scroll-up converges on scrollTop<=2 + [data-index=0] visible (top does not recede). test.slow() (180s) for the ~40 real bash round-trips. - helpers: scrollToTop testid. Verified 2/2 green against the Docker harness. Test 2 fails if the top recedes (the pre-fix bug); test 1 fails without the new button — the gate is not vacuous. See change: fix-chat-scroll-to-top-estimate-drift * chore(openspec): archive fix-chat-scroll-to-top-estimate-drift Sync delta specs into openspec/specs/chat-transcript-virtualization. QA/manual tasks were validated via the Playwright e2e gate + existing virtualization suite. * test: add clamp-boundary + empty-payload edge cases (CodeRabbit) Covers exact text-reserve clamp boundary + saturation above it, and 0-length message/group/burst payloads for the O(1) sizing contract.
…G via electron-builder (BlackBeltTechnology#277) Rewire build_native() to mirror CI (_electron-build.yml): darwin uses electron-forge package -> electron-builder --mac dmg --prepackaged (with CSC_IDENTITY_AUTO_DISCOVERY=false); linux uses forge make -> electron-builder --linux AppImage. Fixes the hard failure where npm run electron:build could not produce a macOS DMG. Removes obsolete macos-alias plumbing (ensure-macos-alias postinstall, maker-dmg devDep, Doctor row + test) since electron-builder's DMG target uses hdiutil, not macos-alias. Adds tests/e2e-electron/dmg-build-launch.electron.spec.ts (Playwright _electron) that mounts the built DMG and asserts the app launches + dashboard opens. Implements OpenSpec change fix-local-electron-dmg-build. Archives + syncs specs. QA/manual tasks (arm64 --mac-both) deferred to post-merge CI verification.
…c decode (BlackBeltTechnology#267) (BlackBeltTechnology#275) * fix(fix-virtualized-image-row-measurement): re-measure image rows on decode Image-bearing user rows in the virtualized transcript could collapse and overlap their neighbour (issue BlackBeltTechnology#267): a base64 data-URL decodes async, so a row is first measured near-zero and, when the decode-driven ResizeObserver re-measure is missed (ChatView reuse across session switch), stays cached at the collapsed height. - ImageAttachments: onImageLoad re-measures the owning virtual row via virtualizer.measureElement, coalesced to one measure per row per frame. - Reserve a bounded loading box on the <img> so the pre-decode measurement is not near-zero (dropped once decoded). - estimateVirtualRowSize: taller pre-mount estimate for image-bearing user rows to bound first-paint drift (measurement stays authoritative). Archives + syncs specs. QA/manual tasks (5.1/5.2) deferred to post-merge. * merge develop: drop superseded estimate edit, keep onLoad re-measure develop PR BlackBeltTechnology#273 rewrote estimateVirtualRowSize into a content-aware form (estimateVirtualRowSize(item, textChars)) that already reserves IMAGE_RESERVE_USER=300 for image rows. Take develop's chat-virtual-rows.ts wholesale — our interim task-3.1 estimate bump is superseded and its textual auto-merge broke the new baseRowSize(role) scope (TS2304 msg). The load-bearing fix (ImageAttachments onLoad -> coalesced row re-measure + reserved loading box in ChatView.tsx) is independent of the estimate rewrite and preserved. tsc clean; full client suite 3195 green. * fix: apply CodeRabbit feedback for fix-virtualized-image-row-measurement - Add onError-path test: a failed image decode must not schedule a re-measure. - Archived design.md: convert the ASCII decode-sequence to a Mermaid sequenceDiagram (repo Diagram Style rule).
…time (BlackBeltTechnology#276) CopyButton now takes a getText callback resolved at click time instead of an eager text string bound at render, so ref-derived payloads (tables, code blocks, message body) copy real content even under React.memo single-render. Migrates all call sites. Adds click-level unit tests + a Playwright e2e (copy-surfaces faux scenario, real clipboard) automating the former manual QA. Implements OpenSpec change fix-table-copy-empty-clipboard. Archives + syncs specs. Repairs pre-existing structural corruption in openspec/specs/content-copy/spec.md (leaked delta header + missing Purpose section) to allow the sync.
…sks + test-plan Client-render out-of-cwd session diffs from captured Write/Edit payload; lazy full-fidelity fetch from pi session JSONL by (sessionId,toolCallId). No server read of the out-of-cwd path. Doubt-review (single+cross-model) killed an earlier server-side realpath eligibility gate as a remote arbitrary-read hole; this is the safe pivot. 16 automated scenarios folded to tasks (test-plan.md manifest).
Capture a change proposal to fix low kb_* tool adoption. Evidence from the last 20 main-repo sessions: 234 grep/rg vs 24 kb_search, 137 greps into source (mostly symbol lookups), kb_neighbors unused. Root cause is framing: the prose Docs-First Gate is ignored while the mechanical Discipline-Skills table is followed. Proposal converts the gate into a tool-substitution table (reflex -> exact kb command), names the symbol-lookup case, adds kb_neighbors/kb_get as the chain-through, and fixes the project-init coding template that ships 'Read the file first' to new projects. New capability spec kb-read-discipline (4 requirements, 8 scenarios); validates --strict.
Implement steer-agents-to-kb-tools. Convert the prose Docs-First Gate into a mechanical reflex -> exact-kb-command table that names the symbol-lookup case (kb_search --doc-type agents) and adds kb_neighbors/kb_get as the chain-through. Drop the STOP/violation scare framing; keep the explicit fall-through (grep on tree miss -> add the missing row). - AGENTS.md: gate rewritten as table; fix 'read it before answering' steer. - project-init dox-doctrine.md: same table seeded into new projects (dox:read:kb) + degraded chain-walk variant (dox:read:manual). - coding AGENTS.md.tmpl: 'read the file first' -> consult doc tree first. 12/14 tasks; 5.x manual scaffold checks deferred. openspec validate --strict ok.
…tion table
Cover tasks 5.1/5.2 deterministically. project-init seeding runs through the
composer seed-doctrine.ts buildDoctrineBlock({kbWired}); assert its output
directly rather than via docker/Playwright (the skill's browser path drives a
model, not this static content).
- kb-wired variant: symbol-lookup row (kb_search --doc-type agents),
kb_neighbors/kb_get chain-through, explicit fall-through.
- manual variant: degraded chain-walk table, explicit fall-through, no kb tools.
9/9 pass in project-init-seed-doctrine.test.ts. tasks.md 14/14, validate ok.
…pline spec Move the completed change to archive/2026-07-16-steer-agents-to-kb-tools and create openspec/specs/kb-read-discipline/spec.md (4 requirements, 8 scenarios) from the delta. Validates --strict.
Create openspec/specs/kb-read-discipline/spec.md from the archived steer-agents-to-kb-tools delta (4 requirements, 8 scenarios). validate --strict ok.
kb_neighbors/kb_get open an empty store via getKb but never populate it, so on a never-indexed cwd they return false-empty while kb_search self-populates via its freshness reindexNow. Proposal: ensurePopulated(state,cwd) that reindexes only when counts().chunks===0, called in both handlers (guarded). Delta adds 3 scenarios to markdown-knowledge-base pull-retrieval. validate --strict ok.
kb_neighbors/kb_get called getKb() (opens an EMPTY store) but never populated it, so on a never-indexed cwd they returned false-empty while kb_search self-populates via its freshness reindexNow. Add ensurePopulated(state,cwd): build the index once only when store.counts().chunks===0 (warm index = COUNT-only no-op; removed cwd = safe no-op). Wire into both handlers, guarded try/catch so a failed walk falls back to the existing index (mirrors kb_search). Tests: cold populate, warm no-walk (edit-without-reindex stays unsearchable), removed-cwd degrade. 14/14 pass, tsc clean, biome clean (also removed 3 pre-existing unused imports in the touched test file). Implements fix-kb-neighbors-get-cold-start.
Move the completed change to archive/2026-07-16-fix-kb-neighbors-get-cold-start and fold its delta into openspec/specs/markdown-knowledge-base: the pull-retrieval requirement gains the cold-start self-population rule + 3 scenarios (cold self-populate, warm-not-re-walked, failed-degrade). validate --strict ok.
… research/ Research pass over pingdotgg/t3code -> pi-dashboard feature-adaptation map, plus three explore-mode OpenSpec proposals derived from it. - docs/research/t3code-feature-adaptation.md: comprehensive feature comparison (6 candidates, our-edge, parity, not-adaptable), effort/value shortlist. - add-supervised-tool-approval: per-session supervised mode gating risky tool calls via pi's blockable tool_call hook + ctx.ui.confirm (PromptBus); approval-only scope (sandboxing delegated to the container path). - add-workspace-checkpointing: per-turn git working-tree snapshots (private shadow ref via temp index) + non-destructive revert (pre-revert safety snap). - add-ai-pr-description: server-side model-proxy endpoint drafting PR title/body from commit log + diffstat; prefill-not-autosubmit, graceful degradation. - Consolidate: move research/ into docs/research/; update 3 LoRA proposal refs; index all research docs in docs/AGENTS.md. All changes pass openspec validate --strict. Explore-mode artifacts only; no implementation.
Full-system STRIDE sweep (security-hardening skill applied post-hoc) across all packages, captured as OpenSpec artifacts. No product code changes. security-boundary-audit/ — findings register (7 clusters A–G), 5 verification checks (V1–V5), and 5 line-cited verified deep-dives (VD1–VD5). Verdict: core is well-secured (path-containment, CSPRNG+timingSafe secrets, scoped WS tickets, argv-everywhere, sanitized EML/DOCX, hardened Electron webPreferences) but the auth guard is applied non-uniformly. Remediation planned as 7 validated changes (openspec validate --strict): Highs: - add-universal-network-guard VD2 automation RCE + provider-auth - sanitize-untrusted-rendered-content VD3 markdown/asciidoc/mermaid XSS - fix-git-checkout-command-injection VD1 (+ B6 Windows escape) - harden-electron-renderer-boundary VD5 preload + VD4 openExternal (+ B10) Mediums (batched by subsystem): - harden-server-capability-bounds B7 PTY cap · B8 browse · B9 recovery - harden-untrusted-content-ingestion B11 mounts · B12 SSRF · B13 zip-slip · B26 xlsx - harden-trust-and-credential-boundaries B4 bearer · B5 CSRF · B14 loopback · B15 events · B25 config 0600 Still open (not drafted): S2 bridge WS auth (V2-rescoped LAN-only), Low tail B16–B24.
…per-plugin handlers (BlackBeltTechnology#343) * plan(bundle-python-runtime): doubt-reviewed proposal+design+specs+tasks Planning artifacts for bundling a pip-capable Python env (uv + python-build-standalone, Tier 2) into the Electron bundle, exposed on PATH for agent bash/tool calls all platforms. Doubt-review (single + cross-model GLM) corrected 13 findings, notably: - D5 rewritten: sync-inject + bare-interpreter fallback (async materialize can't be awaited in the synchronous spawn-env seam) - UV_* scoped to materialize subprocess; SSL_CERT_FILE -> interpreter CA (pip certs) - Windows rebuild-vs-live-install via versioned overlay dirs - offline base rebuild = online/warm-cache only (Tier 2 non-goal) scenario-design gate resolved 2 spec gaps (offline pip = pip's own exit/stderr passthrough; small hash-pinned starter baseline). 24 automated scenarios folded to tasks (test-plan.md manifest), 0 manual-only. #9 uv file:// mirror layout gated behind a blocking spike. * docs(security): plan add-universal-network-guard (doubt-review + scenario-design) plan-proposal on develop. Added design.md + test-plan.md; revised proposal/ specs/tasks after a 2-cycle doubt-driven-review (single-model + cross-model @propose-review-1 GLM, @propose-review-2 DeepSeek). Design pivoted: the first draft's "deny-all + enumerate a public allowlist" was shown unimplementable (hashed static assets rooted at /, SPA history-fallback via setNotFoundHandler) and would brick the app shell with auth off over a tunnel. Revised to a namespace-scoped guard: jurisdiction = /api,/v1,/editor,/live, deny-by-default within, everything else (static/SPA/auth/manifest) untouched. Reviewer-found + reconciled: - /v1 proxy brick: proxy gate must set request.isAuthenticated; guard registered last (after bearer/oauth/proxy hooks). - /auth/status + SPA shell + deep-link refresh must stay public (now out of jurisdiction by construction). - model-proxy SECOND port (server.ts:1875) is a separate Fastify instance with only the proxy gate -> loopback-bind invariant, test-asserted. - proposal/design contradiction (ws-ticket mint) + phantom service worker fixed. scenario-design: test-plan.md manifest, 18 automated (17 L1 + 1 L3) + 1 manual-only, folded into tasks.md as vanilla checkboxes with exemplar+Triple+ manifest ref. openspec validate --strict passes; all 4 artifacts done. * plan(openspec-artifact-dialog-desktop): proposal+design+specs+tasks+test-plan Desktop-viewport modal for P/D/S/T artifact badges; mobile keeps full-page route. Planned via plan-proposal: 2 doubt-review cycles (single+cross-model), scenario-design manifest (20 automated + 1 manual), folded to tasks. * plan(cloud-sync): add-cloud-sync-connector planning artifacts Bidirectional local↔cloud file sync connector (Drive/Dropbox/OneDrive). Baseline-ledger engine, held-conflict resolution, provider adapter seam. - proposal.md: scope, safety posture (lossless+faithful), pinned decisions - design.md: impossibility triangle, 8 decisions, 3 engine invariants, pressure-tested Provider interface (7 verbs) - specs/cloud-file-sync/spec.md: 42-scenario completeness matrix (checkable total-coverage backbone), N=3 hot-edit defer, K=10 tombstone window - test-plan.md: manifest, 45 automated (L1/L2) + 2 manual-only, functional-only - tasks.md: 68 tasks, folded automated scenarios (parser-safe vanilla checkboxes) Doubt-reviewed 3 cycles (single + cross-model glm-5.2): fixed 4 data-loss paths (conflict→push re-overwrite, pull pre-write overwrite, native-doc push, resolve pull-inversion). * docs(openspec): shelve close-initialize-handoff-via-bus (never implemented) Doubt-review (single-model + GLM-5.2 cross-model) found the design incoherent with the shipped server, defeating its own no-click goal via the TOFU trust resolution, and resting on a wrong value premise: - No bus primitive awaits worktree_init_done (keyed by requestId+cwd, not a session status); plain spawn({cwd}) doesn't fire the hook and re-launches project-init. until()/await()/read cannot observe completion. - TOFU trust gate: auto-confirming a just-written hook bypasses the human gate and poisons worktree-init-trust.json, so the next manual click skips TOFU. - Premise wrong: project-init's worktreeInit hook is ~npm ci; kb-index is the kb-extension's separate hook; openspec-init already runs inline at Step 6. - connect() has no timeout arg; connect-failed is never thrown -> bounded degradation is unimplementable as designed. Archived pre-implementation with NOTES.md capturing findings + revival prerequisites so it is not re-proposed. * plan(fix-plugin-action-fanout-and-handlers): design + tasks artifacts * feat(fix-plugin-action-fanout-and-handlers): pluginId fan-out + real per-plugin handlers Make plugin_action a real universal seam. The gateway now fans out plugin_action by pluginId (Map<pluginId,Handler> + registerPluginActionHandler) instead of a last-writer-wins Map<type,Handler>, so flows/kb/automation/goal coexist regardless of load order. Unknown pluginId returns a structured plugin_action_error to the sender (never a silent drop). flows/kb/automation gain production plugin_action handlers dispatching to their existing in-process cores. bus-client KNOWN_PLUGIN_HANDLERS extended to goal/flows/kb/automation. Implements OpenSpec change fix-plugin-action-fanout-and-handlers. Archives + syncs specs. * fix: apply CodeRabbit feedback for fix-plugin-action-fanout-and-handlers Validate plugin_action inputs: reject non-object/array flow.run `inputs` (flows) and require a plain-object `config.set` patch (kb, no fallback to the control payload). Hoist kb handler-test mocks into vi.hoisted to avoid a TDZ hit in the vi.mock factory.
…ion resolution (Phase 1) (BlackBeltTechnology#344) * plan(bundle-python-runtime): doubt-reviewed proposal+design+specs+tasks Planning artifacts for bundling a pip-capable Python env (uv + python-build-standalone, Tier 2) into the Electron bundle, exposed on PATH for agent bash/tool calls all platforms. Doubt-review (single + cross-model GLM) corrected 13 findings, notably: - D5 rewritten: sync-inject + bare-interpreter fallback (async materialize can't be awaited in the synchronous spawn-env seam) - UV_* scoped to materialize subprocess; SSL_CERT_FILE -> interpreter CA (pip certs) - Windows rebuild-vs-live-install via versioned overlay dirs - offline base rebuild = online/warm-cache only (Tier 2 non-goal) scenario-design gate resolved 2 spec gaps (offline pip = pip's own exit/stderr passthrough; small hash-pinned starter baseline). 24 automated scenarios folded to tasks (test-plan.md manifest), 0 manual-only. #9 uv file:// mirror layout gated behind a blocking spike. * docs(security): plan add-universal-network-guard (doubt-review + scenario-design) plan-proposal on develop. Added design.md + test-plan.md; revised proposal/ specs/tasks after a 2-cycle doubt-driven-review (single-model + cross-model @propose-review-1 GLM, @propose-review-2 DeepSeek). Design pivoted: the first draft's "deny-all + enumerate a public allowlist" was shown unimplementable (hashed static assets rooted at /, SPA history-fallback via setNotFoundHandler) and would brick the app shell with auth off over a tunnel. Revised to a namespace-scoped guard: jurisdiction = /api,/v1,/editor,/live, deny-by-default within, everything else (static/SPA/auth/manifest) untouched. Reviewer-found + reconciled: - /v1 proxy brick: proxy gate must set request.isAuthenticated; guard registered last (after bearer/oauth/proxy hooks). - /auth/status + SPA shell + deep-link refresh must stay public (now out of jurisdiction by construction). - model-proxy SECOND port (server.ts:1875) is a separate Fastify instance with only the proxy gate -> loopback-bind invariant, test-asserted. - proposal/design contradiction (ws-ticket mint) + phantom service worker fixed. scenario-design: test-plan.md manifest, 18 automated (17 L1 + 1 L3) + 1 manual-only, folded into tasks.md as vanilla checkboxes with exemplar+Triple+ manifest ref. openspec validate --strict passes; all 4 artifacts done. * plan(openspec-artifact-dialog-desktop): proposal+design+specs+tasks+test-plan Desktop-viewport modal for P/D/S/T artifact badges; mobile keeps full-page route. Planned via plan-proposal: 2 doubt-review cycles (single+cross-model), scenario-design manifest (20 automated + 1 manual), folded to tasks. * plan(cloud-sync): add-cloud-sync-connector planning artifacts Bidirectional local↔cloud file sync connector (Drive/Dropbox/OneDrive). Baseline-ledger engine, held-conflict resolution, provider adapter seam. - proposal.md: scope, safety posture (lossless+faithful), pinned decisions - design.md: impossibility triangle, 8 decisions, 3 engine invariants, pressure-tested Provider interface (7 verbs) - specs/cloud-file-sync/spec.md: 42-scenario completeness matrix (checkable total-coverage backbone), N=3 hot-edit defer, K=10 tombstone window - test-plan.md: manifest, 45 automated (L1/L2) + 2 manual-only, functional-only - tasks.md: 68 tasks, folded automated scenarios (parser-safe vanilla checkboxes) Doubt-reviewed 3 cycles (single + cross-model glm-5.2): fixed 4 data-loss paths (conflict→push re-overwrite, pull pre-write overwrite, native-doc push, resolve pull-inversion). * docs(openspec): shelve close-initialize-handoff-via-bus (never implemented) Doubt-review (single-model + GLM-5.2 cross-model) found the design incoherent with the shipped server, defeating its own no-click goal via the TOFU trust resolution, and resting on a wrong value premise: - No bus primitive awaits worktree_init_done (keyed by requestId+cwd, not a session status); plain spawn({cwd}) doesn't fire the hook and re-launches project-init. until()/await()/read cannot observe completion. - TOFU trust gate: auto-confirming a just-written hook bypasses the human gate and poisons worktree-init-trust.json, so the next manual click skips TOFU. - Premise wrong: project-init's worktreeInit hook is ~npm ci; kb-index is the kb-extension's separate hook; openspec-init already runs inline at Step 6. - connect() has no timeout arg; connect-failed is never thrown -> bounded degradation is unimplementable as designed. Archived pre-implementation with NOTES.md capturing findings + revival prerequisites so it is not re-proposed. * feat(server-side-file-mention-resolution): lazy server-side file-mention resolution (Phase 1) Client detects mentions synchronously; the server resolves them against the real filesystem lazily on click. Fixes broken/tilde tool-output links. - Add resolveFileMention() + POST /api/file/resolve-mention (untrusted-cwd gate before resolve; containment before stat; fixed ~/.pi allowlist anchor). - Open/preview routes (/api/file, /api/file/raw, /api/file/render) honor the ~/.pi anchor so a resolved home path previews without a 403. - Client: one ~/ tokenizer branch; FileLink resolves on click and opens the server-resolved path directly (no double re-root), inline not-found on null, client-side fallback on transport failure; split-open routes through resolve. Archives + syncs specs. Manual latency check (test-plan #M1) deferred to post-merge verification.
…lackBeltTechnology#345) * plan(bundle-python-runtime): doubt-reviewed proposal+design+specs+tasks Planning artifacts for bundling a pip-capable Python env (uv + python-build-standalone, Tier 2) into the Electron bundle, exposed on PATH for agent bash/tool calls all platforms. Doubt-review (single + cross-model GLM) corrected 13 findings, notably: - D5 rewritten: sync-inject + bare-interpreter fallback (async materialize can't be awaited in the synchronous spawn-env seam) - UV_* scoped to materialize subprocess; SSL_CERT_FILE -> interpreter CA (pip certs) - Windows rebuild-vs-live-install via versioned overlay dirs - offline base rebuild = online/warm-cache only (Tier 2 non-goal) scenario-design gate resolved 2 spec gaps (offline pip = pip's own exit/stderr passthrough; small hash-pinned starter baseline). 24 automated scenarios folded to tasks (test-plan.md manifest), 0 manual-only. #9 uv file:// mirror layout gated behind a blocking spike. * docs(security): plan add-universal-network-guard (doubt-review + scenario-design) plan-proposal on develop. Added design.md + test-plan.md; revised proposal/ specs/tasks after a 2-cycle doubt-driven-review (single-model + cross-model @propose-review-1 GLM, @propose-review-2 DeepSeek). Design pivoted: the first draft's "deny-all + enumerate a public allowlist" was shown unimplementable (hashed static assets rooted at /, SPA history-fallback via setNotFoundHandler) and would brick the app shell with auth off over a tunnel. Revised to a namespace-scoped guard: jurisdiction = /api,/v1,/editor,/live, deny-by-default within, everything else (static/SPA/auth/manifest) untouched. Reviewer-found + reconciled: - /v1 proxy brick: proxy gate must set request.isAuthenticated; guard registered last (after bearer/oauth/proxy hooks). - /auth/status + SPA shell + deep-link refresh must stay public (now out of jurisdiction by construction). - model-proxy SECOND port (server.ts:1875) is a separate Fastify instance with only the proxy gate -> loopback-bind invariant, test-asserted. - proposal/design contradiction (ws-ticket mint) + phantom service worker fixed. scenario-design: test-plan.md manifest, 18 automated (17 L1 + 1 L3) + 1 manual-only, folded into tasks.md as vanilla checkboxes with exemplar+Triple+ manifest ref. openspec validate --strict passes; all 4 artifacts done. * plan(openspec-artifact-dialog-desktop): proposal+design+specs+tasks+test-plan Desktop-viewport modal for P/D/S/T artifact badges; mobile keeps full-page route. Planned via plan-proposal: 2 doubt-review cycles (single+cross-model), scenario-design manifest (20 automated + 1 manual), folded to tasks. * plan(cloud-sync): add-cloud-sync-connector planning artifacts Bidirectional local↔cloud file sync connector (Drive/Dropbox/OneDrive). Baseline-ledger engine, held-conflict resolution, provider adapter seam. - proposal.md: scope, safety posture (lossless+faithful), pinned decisions - design.md: impossibility triangle, 8 decisions, 3 engine invariants, pressure-tested Provider interface (7 verbs) - specs/cloud-file-sync/spec.md: 42-scenario completeness matrix (checkable total-coverage backbone), N=3 hot-edit defer, K=10 tombstone window - test-plan.md: manifest, 45 automated (L1/L2) + 2 manual-only, functional-only - tasks.md: 68 tasks, folded automated scenarios (parser-safe vanilla checkboxes) Doubt-reviewed 3 cycles (single + cross-model glm-5.2): fixed 4 data-loss paths (conflict→push re-overwrite, pull pre-write overwrite, native-doc push, resolve pull-inversion). * docs(openspec): shelve close-initialize-handoff-via-bus (never implemented) Doubt-review (single-model + GLM-5.2 cross-model) found the design incoherent with the shipped server, defeating its own no-click goal via the TOFU trust resolution, and resting on a wrong value premise: - No bus primitive awaits worktree_init_done (keyed by requestId+cwd, not a session status); plain spawn({cwd}) doesn't fire the hook and re-launches project-init. until()/await()/read cannot observe completion. - TOFU trust gate: auto-confirming a just-written hook bypasses the human gate and poisons worktree-init-trust.json, so the next manual click skips TOFU. - Premise wrong: project-init's worktreeInit hook is ~npm ci; kb-index is the kb-extension's separate hook; openspec-init already runs inline at Step 6. - connect() has no timeout arg; connect-failed is never thrown -> bounded degradation is unimplementable as designed. Archived pre-implementation with NOTES.md capturing findings + revival prerequisites so it is not re-proposed. * feat(terminals-in-tabbed-panes): host terminals as editor-pane tabs Terminals now open as virtual `term:<id>` tabs (new `terminal` ViewerKind) inside the editor pane, replacing the standalone TerminalsView. - Session split: opt-in `+ Terminal` create; folder pane: auto-surfaces cwd terminals. - Keep-alive TerminalPaneLayer (single TerminalView mount per id); registry placeholder. - SplitWorkspaceContext terminal slice via useTerminalPaneTabs (reconcile D5, auto-surface D3, close-kills D4). - closeByPath reducer action; VALID_VIEWERS accepts terminal (persisted tabs survive reload). - Cold-load guard: empty live set = "not yet known", never wipes persisted tabs before the WS snapshot. - Remove /folder/:cwd/terminals route + TerminalsView + create-time navigation (deselected the session). - Sidebar [Terminals(N)] retargets to the folder pane. Implements OpenSpec change terminals-in-tabbed-panes. * docs(terminals-in-tabbed-panes): archive change + sync specs Syncs delta specs into openspec/specs (terminal-viewer-tab created, split-editor-workspace updated, terminals-view capability removed as fully superseded) and archives the change. Also repairs pre-existing main-spec corruption (terminals-view had a leaked delta header).
…us-client-scripting PR BlackBeltTechnology#341 committed the change into both the archive/ path and the active changes/ path. The archived copy (2026-07-16-add-dashboard-bus-client-scripting) is authoritative with all tasks checked and specs already synced; the active duplicate lingered and kept showing as an active 'Complete' change. Remove it.
/live/:id/* threw 500 "reply.from is not a function" after remove-external-editor-integration (BlackBeltTechnology#342) deleted editor-proxy.ts, the sole registrant of @fastify/reply-from. live-server-proxy still called reply.from() but the decorator was never installed. live-server-proxy is now the sole from-decorator consumer, so it owns its own dependency and registers the plugin itself. Harden the regression test: drop the manual @fastify/reply-from registration that was masking the break, so the test now exercises the proxy's own self-registration and would catch a future deletion.
…est-plan Two-axis file-open behavior: mode stickiness (reveal only from closed) + focus intent (user-click activates, auto-canvas adds silent/unread when editor shown). Doubt-reviewed (single + cross-model @propose-review-1); reconciled 10 findings incl. removing a fabricated tool-result path, handling the deep-link 6th mode-changer, and the shared useOpenTarget callsite. Scenario-design: 28 scenarios (26 automated / 2 manual-only), folded to tasks. Coordinate: land after redesign-split-layout-controls.
… test-plan + mockups Planning artifacts for the split-layout controls redesign: - divider becomes resize-only (dotted grip); collapse via header switch only - always-visible pane captions; in-flow rotated restore tabs (fixes overlap bug) - header: mode switch before Seek; remove model+level (keep piVersion) - unified session-list dotted-grip seam + centered knob + vertical SESSIONS tab Approved mockup at mockups/index.html (v1.html superseded). Doubt-reviewed (single + cross-model glm-5.2): piVersion-not-on-card blocker fixed per user, mobile scoped to orientation h, a11y + centering + tablet carve-outs added. 16 automated scenarios folded to tasks §7; 2 manual-only to §8.
…s from payload (no file read) (BlackBeltTechnology#346) * plan(bundle-python-runtime): doubt-reviewed proposal+design+specs+tasks Planning artifacts for bundling a pip-capable Python env (uv + python-build-standalone, Tier 2) into the Electron bundle, exposed on PATH for agent bash/tool calls all platforms. Doubt-review (single + cross-model GLM) corrected 13 findings, notably: - D5 rewritten: sync-inject + bare-interpreter fallback (async materialize can't be awaited in the synchronous spawn-env seam) - UV_* scoped to materialize subprocess; SSL_CERT_FILE -> interpreter CA (pip certs) - Windows rebuild-vs-live-install via versioned overlay dirs - offline base rebuild = online/warm-cache only (Tier 2 non-goal) scenario-design gate resolved 2 spec gaps (offline pip = pip's own exit/stderr passthrough; small hash-pinned starter baseline). 24 automated scenarios folded to tasks (test-plan.md manifest), 0 manual-only. #9 uv file:// mirror layout gated behind a blocking spike. * docs(security): plan add-universal-network-guard (doubt-review + scenario-design) plan-proposal on develop. Added design.md + test-plan.md; revised proposal/ specs/tasks after a 2-cycle doubt-driven-review (single-model + cross-model @propose-review-1 GLM, @propose-review-2 DeepSeek). Design pivoted: the first draft's "deny-all + enumerate a public allowlist" was shown unimplementable (hashed static assets rooted at /, SPA history-fallback via setNotFoundHandler) and would brick the app shell with auth off over a tunnel. Revised to a namespace-scoped guard: jurisdiction = /api,/v1,/editor,/live, deny-by-default within, everything else (static/SPA/auth/manifest) untouched. Reviewer-found + reconciled: - /v1 proxy brick: proxy gate must set request.isAuthenticated; guard registered last (after bearer/oauth/proxy hooks). - /auth/status + SPA shell + deep-link refresh must stay public (now out of jurisdiction by construction). - model-proxy SECOND port (server.ts:1875) is a separate Fastify instance with only the proxy gate -> loopback-bind invariant, test-asserted. - proposal/design contradiction (ws-ticket mint) + phantom service worker fixed. scenario-design: test-plan.md manifest, 18 automated (17 L1 + 1 L3) + 1 manual-only, folded into tasks.md as vanilla checkboxes with exemplar+Triple+ manifest ref. openspec validate --strict passes; all 4 artifacts done. * plan(openspec-artifact-dialog-desktop): proposal+design+specs+tasks+test-plan Desktop-viewport modal for P/D/S/T artifact badges; mobile keeps full-page route. Planned via plan-proposal: 2 doubt-review cycles (single+cross-model), scenario-design manifest (20 automated + 1 manual), folded to tasks. * plan(cloud-sync): add-cloud-sync-connector planning artifacts Bidirectional local↔cloud file sync connector (Drive/Dropbox/OneDrive). Baseline-ledger engine, held-conflict resolution, provider adapter seam. - proposal.md: scope, safety posture (lossless+faithful), pinned decisions - design.md: impossibility triangle, 8 decisions, 3 engine invariants, pressure-tested Provider interface (7 verbs) - specs/cloud-file-sync/spec.md: 42-scenario completeness matrix (checkable total-coverage backbone), N=3 hot-edit defer, K=10 tombstone window - test-plan.md: manifest, 45 automated (L1/L2) + 2 manual-only, functional-only - tasks.md: 68 tasks, folded automated scenarios (parser-safe vanilla checkboxes) Doubt-reviewed 3 cycles (single + cross-model glm-5.2): fixed 4 data-loss paths (conflict→push re-overwrite, pull pre-write overwrite, native-doc push, resolve pull-inversion). * docs(openspec): shelve close-initialize-handoff-via-bus (never implemented) Doubt-review (single-model + GLM-5.2 cross-model) found the design incoherent with the shipped server, defeating its own no-click goal via the TOFU trust resolution, and resting on a wrong value premise: - No bus primitive awaits worktree_init_done (keyed by requestId+cwd, not a session status); plain spawn({cwd}) doesn't fire the hook and re-launches project-init. until()/await()/read cannot observe completion. - TOFU trust gate: auto-confirming a just-written hook bypasses the human gate and poisons worktree-init-trust.json, so the next manual click skips TOFU. - Premise wrong: project-init's worktreeInit hook is ~npm ci; kb-index is the kb-extension's separate hook; openspec-init already runs inline at Step 6. - connect() has no timeout arg; connect-failed is never thrown -> bounded degradation is unimplementable as designed. Archived pre-implementation with NOTES.md capturing findings + revival prerequisites so it is not re-proposed. * feat(session-diff): opt-in out-of-cwd session diffs (payload-only, no file read) Render diffs for files a session writes OUTSIDE its workspace from the captured Write/Edit event payload — the server never reads the out-of-cwd file (the doubt-review's core property). Server: - session-diff.ts: `resolvePathKey` carries out-of-cwd Write/Edit entries keyed by absolute path; `buildSessionDiff` splits in-cwd (enriched) vs out-of-cwd (payload-only, previewable:false) BEFORE enrichment so an out-of-cwd path can never reach the untracked `readFileSync(resolve(cwd,absPath))` branch. Threads `toolCallId` + `truncated` onto FileChangeEvent. - session-file-reader.ts: `findSessionToolCallPayload(file, toolCallId)` returns the FULL untruncated Write/Edit payload from the on-disk JSONL (session-scoped id only, no path input/traversal). - routes: `GET /api/session-change/:sessionId/:toolCallId` → { content?, edits? } resolved via sessionManager.sessionFile; miss → 404, reads nothing else. - preferences-store: backfill + merge `showOutOfCwdSessionDiffs` (default off). Client: - DisplayPrefs.showOutOfCwdSessionDiffs (default off, all presets) + ChatViewMenu toggle. ChatView suppresses out-of-cwd rows unless on. - DiffPanel: hide the File toggle when previewable:false; lazy-fetch full payload on truncation; truncation banner on fetch failure (never blank). - diff-tree: out-of-cwd entries group under "outside workspace" (no blank-root). - normalize-path: `isOutOfCwd`. Tests: L1 E1-E8 + X3 + truncation threading (session-diff/reader/routes/prefs); unit F4 (tree) + isOutOfCwd + F5/F3/X2 (DiffPanel); L3 e2e F1/F2/F5 + API-level F3 (out-of-cwd-session-diffs.spec.ts, harness-verified). X1 superseded by the payload-only design (never reads the file → deletion is moot). OpenSpec: opt-in-out-of-cwd-session-diffs * chore(opt-in-out-of-cwd-session-diffs): archive + sync specs Archives the change to openspec/changes/archive/ and syncs the change-summary-table + session-diff-extraction delta specs into openspec/specs/. Manual-only QA task deferred to post-merge verification. * fix: apply CodeRabbit feedback for opt-in-out-of-cwd-session-diffs - DiffPanel: accept the lazy-fetch payload only when it carries a string `content` or an `edits` array ({success:true,data:{}} → truncation banner, not a silent blank); reset viewMode to Diff when a refresh flips an entry to out-of-cwd (previewable:false) in File mode so the /api/session-file fetch (403 for out-of-cwd) can never fire. - Tests: F3 now asserts the fetched full content REPLACES the truncated text in the render (RichDiff mock exposes newText) + a previewable→false rerender test; isOutOfCwd(undefined-cwd) case; E3 also asserts no existsSync/statSync probe of the out-of-cwd path; nested-toolCallId test uses a distinct decoy top-level id. Skipped (with reason): archive-dir relocation (the change is correctly archived by the ship workflow); oversized AGENTS.md row splits (pre-existing giant rows — out of scope); e2e session-scan/marker refinements (reliable as-is on a fresh container, endpoint content assertion already proves full fidelity).
# Conflicts: # CHANGELOG.md # docs/AGENTS.md # package-lock.json # packages/client/src/components/ChatView.tsx # packages/client/src/components/ChatViewMenu.tsx # packages/client/src/components/ChatViewMenu.tsx.AGENTS.md # packages/client/src/components/CommandInput.tsx # packages/client/src/components/SessionCard.tsx # packages/client/src/components/SettingsPanel.tsx # packages/client/src/components/ToolCallStep.tsx # packages/client/src/components/__tests__/ChatViewMenu.flip.test.tsx # packages/client/src/components/interactive-renderers/SelectRenderer.tsx # packages/client/src/hooks/AGENTS.md # packages/client/src/hooks/usePopoverFlip.ts # packages/client/src/lib/AGENTS.md # packages/extension/src/__tests__/role-manager.test.ts # packages/extension/src/bridge.ts # packages/extension/src/role-manager.ts # packages/roles-plugin/src/RolesSettingsSection.tsx # packages/roles-plugin/src/__tests__/RolesSettingsSection.test.tsx # packages/server/package.json # packages/server/src/AGENTS.md # packages/server/src/event-wiring.ts # packages/server/src/routes/system-routes.ts # packages/server/src/server.ts
Add scripts/upstream-sync.sh (status/merge/verify/pr), docs policy, weekly upstream-sync workflow, and ci-zge focused gates so we can merge BlackBelt develop without clobbering deploy/push/OMP surfaces. Default install ref is main; README links the sync runbook.
Use stable branch sync/upstream-<ref>, force-with-lease each run, upsert the same PR, and close older labeled/sync-head PRs as superseded so a late review only has the latest merge to look at.
Gate 1 invoked vitest with real HOME, which upstream globalSetup rejects. Match root npm test isolation and pass package vitest.config.
Author
|
Use PR #17 as the single sync review thread; this duplicate is superseded. |
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 subscribe to this conversation on GitHub.
Already have an account?
Sign in.
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.
Upstream sync (latest only)
Automation replaces any previous open sync PR. Review this one when ready; older sync PRs are closed as superseded.
Commands:
status Show ahead/behind vs upstream ref
merge Create/update sync branch and merge upstream (auto-ours on deploy/**)
verify Run structural + focused unit + build gates
pr Open/update PR from current sync branch into main
ff-develop Fast-forward origin/develop to origin/main (mirror)
Env:
UPSTREAM_REF upstream branch (default: develop)
TARGET_BRANCH integration branch (default: main)
SYNC_BRANCH override sync branch (default: sync/upstream-, stable/single PR)
DRY_RUN=1 print actions only for merge/pr
SKIP_BUILD=1 verify skips npm run build
SYNC_ADOPT_UPSTREAM=1 do not auto-checkout --ours for protected paths
Protected ZGE surfaces (must remain green)
Policy
Commands:
status Show ahead/behind vs upstream ref
merge Create/update sync branch and merge upstream (auto-ours on deploy/**)
verify Run structural + focused unit + build gates
pr Open/update PR from current sync branch into main
ff-develop Fast-forward origin/develop to origin/main (mirror)
Env:
UPSTREAM_REF upstream branch (default: develop)
TARGET_BRANCH integration branch (default: main)
SYNC_BRANCH override sync branch (default: sync/upstream-, stable/single PR)
DRY_RUN=1 print actions only for merge/pr
SKIP_BUILD=1 verify skips npm run build
SYNC_ADOPT_UPSTREAM=1 do not auto-checkout --ours for protected paths)
Commands:
status Show ahead/behind vs upstream ref
merge Create/update sync branch and merge upstream (auto-ours on deploy/**)
verify Run structural + focused unit + build gates
pr Open/update PR from current sync branch into main
ff-develop Fast-forward origin/develop to origin/main (mirror)
Env:
UPSTREAM_REF upstream branch (default: develop)
TARGET_BRANCH integration branch (default: main)
SYNC_BRANCH override sync branch (default: sync/upstream-, stable/single PR)
DRY_RUN=1 print actions only for merge/pr
SKIP_BUILD=1 verify skips npm run build
SYNC_ADOPT_UPSTREAM=1 do not auto-checkout --ours for protected paths (sync branch may force-with-lease)
Gates
==> Gate 0: structural
==> Gate 0 OK
==> Gate 1: focused vitest
==> vitest in packages/shared -- src/tests/omp-agent-paths.test.ts src/tests/config-push.test.ts
RUN v4.1.9 /tmp/omp-dashboard-sync-real/packages/shared
[test-isolation] HOME=/tmp/pi-test-SWLXrC (real=/home/joe)
·······················
Test Files 2 passed (2)
Tests 23 passed (23)
Start at 16:52:39
Duration 139ms (transform 51ms, setup 13ms, import 59ms, tests 8ms, environment 0ms)
==> vitest in packages/server -- src/tests/build-push-payload.test.ts src/tests/push-dispatcher.test.ts src/tests/push-vapid.test.ts src/tests/push-trigger-classifier.test.ts src/tests/ws-ticket.test.ts
RUN v4.1.9 /tmp/omp-dashboard-sync-real/packages/server
[test-isolation] HOME=/tmp/pi-test-SWLXrC (real=/home/joe)
····································
Test Files 5 passed (5)
Tests 36 passed (36)
Start at 16:52:39
Duration 147ms (transform 159ms, setup 27ms, import 188ms, tests 25ms, environment 0ms)
==> Gate 1 OK (or skipped missing files)
==> Gate 2: build
vite v6.4.3 building for production...
[plugin-loader] discovered 8 plugin(s): automation, flows, goal, kb, roles, subagents, flows-anthropic-bridge, demo
[vite-dashboard-plugins] Generated plugin-registry.tsx
transforming...
✓ 5257 modules transformed.
rendering chunks...
computing gzip size...
../dist/index.html 1.58 kB │ gzip: 0.55 kB
../dist/assets/KaTeX_Size3-Regular-CTq5MqoE.woff 4.42 kB
../dist/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 4.93 kB
../dist/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 5.21 kB
../dist/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 5.47 kB
../dist/assets/KaTeX_Size4-Regular-BF-4gkZK.woff 5.98 kB
../dist/assets/KaTeX_Size2-Regular-oD1tc_U0.woff 6.19 kB
../dist/assets/KaTeX_Size1-Regular-C195tn64.woff 6.50 kB
../dist/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 6.91 kB
../dist/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 6.91 kB
../dist/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf 7.59 kB
../dist/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff 7.66 kB
../dist/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff 7.72 kB
../dist/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 9.64 kB
../dist/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 10.34 kB
../dist/assets/KaTeX_Size4-Regular-DWFBv043.ttf 10.36 kB
../dist/assets/KaTeX_Script-Regular-D5yQViql.woff 10.59 kB
../dist/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 11.32 kB
../dist/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 11.35 kB
../dist/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf 11.51 kB
../dist/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 12.03 kB
../dist/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 12.22 kB
../dist/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf 12.23 kB
../dist/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff 12.32 kB
../dist/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf 12.34 kB
../dist/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf 12.37 kB
../dist/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff 13.21 kB
../dist/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff 13.30 kB
../dist/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 13.57 kB
../dist/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff 14.11 kB
../dist/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff 14.41 kB
../dist/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff 16.03 kB
../dist/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 16.40 kB
../dist/assets/KaTeX_Math-Italic-t53AETM-.woff2 16.44 kB
../dist/assets/KaTeX_Script-Regular-C5JkGWo-.ttf 16.65 kB
../dist/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 16.78 kB
../dist/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 16.99 kB
../dist/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff 18.67 kB
../dist/assets/KaTeX_Math-Italic-DA0__PXp.woff 18.75 kB
../dist/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff 19.41 kB
../dist/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf 19.44 kB
../dist/assets/KaTeX_Fraktur-Regular-CB_wures.ttf 19.57 kB
../dist/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf 19.58 kB
../dist/assets/KaTeX_Main-Italic-BMLOBm91.woff 19.68 kB
../dist/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf 22.36 kB
../dist/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf 24.50 kB
../dist/assets/KaTeX_Main-Bold-Cx986IdX.woff2 25.32 kB
../dist/assets/KaTeX_Main-Regular-B22Nviop.woff2 26.27 kB
../dist/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf 27.56 kB
../dist/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 28.08 kB
../dist/assets/KaTeX_Main-Bold-Jm3AIy58.woff 29.91 kB
../dist/assets/KaTeX_Main-Regular-Dr94JaBh.woff 30.77 kB
../dist/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf 31.20 kB
../dist/assets/KaTeX_Math-Italic-flOr_0UB.ttf 31.31 kB
../dist/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf 32.97 kB
../dist/assets/KaTeX_AMS-Regular-DMm9YOAa.woff 33.52 kB
../dist/assets/KaTeX_Main-Italic-3WenGoN9.ttf 33.58 kB
../dist/assets/KaTeX_Main-Bold-waoOVXN0.ttf 51.34 kB
../dist/assets/KaTeX_Main-Regular-ypZvNtVU.ttf 53.58 kB
../dist/assets/KaTeX_AMS-Regular-DRggAlZN.ttf 63.63 kB
../dist/assets/codicon-DCmgc-ay.ttf 80.34 kB
../dist/assets/editor.worker-BCzxt1at.js 232.35 kB
../dist/assets/json.worker-B7c_PmGb.js 364.77 kB
../dist/assets/html.worker-CKrFyw_2.js 674.50 kB
../dist/assets/css.worker-DaIe3gwK.js 1,011.91 kB
../dist/assets/pdf.worker.min-yatZIOMy.mjs 1,375.84 kB
../dist/assets/xterm-6GBZ9nXN.css 5.24 kB │ gzip: 1.92 kB
../dist/assets/diff-D_jQ-W02.css 21.33 kB │ gzip: 3.36 kB
../dist/assets/monaco-D6kYW_CN.css 133.00 kB │ gzip: 21.09 kB
../dist/assets/index-qdTqjsAm.css 160.86 kB │ gzip: 29.39 kB
../dist/assets/pdf.worker.min-ocdtAcA3.js 0.07 kB │ gzip: 0.09 kB
../dist/assets/channel-DVkCQ1b3.js 0.11 kB │ gzip: 0.13 kB
../dist/assets/init-Gi6I4Gst.js 0.15 kB │ gzip: 0.13 kB
../dist/assets/chunk-2Q5K7J3B-C44KYlEO.js 0.19 kB │ gzip: 0.16 kB
../dist/assets/chunk-XXDRQBXY-Cf8jc-jU.js 0.26 kB │ gzip: 0.22 kB
../dist/assets/chunk-JWPE2WC7-DQwlVora.js 0.30 kB │ gzip: 0.20 kB
../dist/assets/chunk-5VM5RSS4-BZxHvEht.js 0.37 kB │ gzip: 0.27 kB
../dist/assets/chunk-VR4S4FIN-Dx6p_Wq8.js 0.53 kB │ gzip: 0.37 kB
../dist/assets/stateDiagram-v2-6OUMAXLB-BXOp3Mx-.js 0.63 kB │ gzip: 0.40 kB
../dist/assets/classDiagram-OUVF2IWQ-DDJ0ZhY8.js 0.67 kB │ gzip: 0.42 kB
../dist/assets/classDiagram-v2-EOCWNBFH-DDJ0ZhY8.js 0.67 kB │ gzip: 0.42 kB
../dist/assets/swimlanesDiagram-G3AALYLV-lGxfXPag.js 0.75 kB │ gzip: 0.46 kB
../dist/assets/infoDiagram-FWYZ7A6U-CXDYphhq.js 0.79 kB │ gzip: 0.50 kB
../dist/assets/MarkdownEditor-CCf01RTc.js 1.06 kB │ gzip: 0.65 kB
../dist/assets/ordinal-Cboi1Yqb.js 1.19 kB │ gzip: 0.57 kB
../dist/assets/sizeCapture-X5ZJPWSS-Ce2CtUNJ.js 1.20 kB │ gzip: 0.66 kB
../dist/assets/railroadDiagram-RFXS5EU6-ChgrLXps.js 1.81 kB │ gzip: 0.85 kB
../dist/assets/chunk-32BRIVSS-CDa7LggN.js 1.91 kB │ gzip: 0.85 kB
../dist/assets/abnfDiagram-VRR7QNED-BBs3doU3.js 2.01 kB │ gzip: 0.99 kB
../dist/assets/pegDiagram-2B236MQR-DpcaDiNu.js 2.16 kB │ gzip: 1.02 kB
../dist/assets/ebnfDiagram-CCIWWBDH-BPgOuvTU.js 2.21 kB │ gzip: 0.98 kB
../dist/assets/monaco-setup-CyE3tqBZ.js 2.40 kB │ gzip: 0.95 kB
../dist/assets/MonacoBuffer-DcKC6iIm.js 2.80 kB │ gzip: 1.41 kB
../dist/assets/arc-BlVBpbND.js 3.43 kB │ gzip: 1.47 kB
../dist/assets/diagram-NH7WQ7WH-B9KDfyQr.js 4.45 kB │ gzip: 1.96 kB
../dist/assets/defaultLocale-DX6XiGOO.js 4.69 kB │ gzip: 2.18 kB
../dist/assets/linear-BujcPsVm.js 5.65 kB │ gzip: 2.30 kB
../dist/assets/diagram-WEI45ONY-SsK-yCca.js 6.28 kB │ gzip: 2.70 kB
../dist/assets/pieDiagram-ENE6RG2P-Jz2sD6vN.js 6.56 kB │ gzip: 2.75 kB
../dist/assets/chunk-RYQCIY6F-BW_W8WHo.js 7.15 kB │ gzip: 2.76 kB
../dist/assets/diagram-OA4YK3LP-BB5d947h.js 8.68 kB │ gzip: 3.87 kB
../dist/assets/dagre-VKFMJZFB-KUrktgNc.js 9.02 kB │ gzip: 3.46 kB
../dist/assets/cynefinDiagram-TSTJHNR4-DhR9Uplp.js 10.30 kB │ gzip: 3.73 kB
../dist/assets/stateDiagram-2N3HPSRC-WJ1VGb0x.js 10.54 kB │ gzip: 3.71 kB
../dist/assets/diagram-FQU43EPY-DnJsgDJM.js 11.02 kB │ gzip: 4.27 kB
../dist/assets/chunk-MOJQB5TN-Ciohy4qm.js 15.76 kB │ gzip: 4.43 kB
../dist/assets/diagram-G47NLZAW-Cn2ECYmQ.js 16.27 kB │ gzip: 5.84 kB
../dist/assets/ishikawaDiagram-FXEZZL3T-Cb9usVAw.js 17.77 kB │ gzip: 6.78 kB
../dist/assets/kanban-definition-HUTT4EX6-DjZ-9DcZ.js 20.90 kB │ gzip: 7.40 kB
../dist/assets/mindmap-definition-LN4V7U3C-DJnLpY4I.js 23.57 kB │ gzip: 8.00 kB
../dist/assets/sankeyDiagram-HTMAVEWB-f_kEluA7.js 23.59 kB │ gzip: 8.68 kB
../dist/assets/journeyDiagram-5HDEW3XC-CL-XvB2t.js 23.77 kB │ gzip: 8.45 kB
../dist/assets/wardleyDiagram-EHGQE667-BxTSAo0a.js 26.30 kB │ gzip: 7.04 kB
../dist/assets/erDiagram-Q63AITRT-C7wFdsBu.js 27.42 kB │ gzip: 9.55 kB
../dist/assets/gitGraphDiagram-IHSO6WYX-7z4h28NB.js 30.14 kB │ gzip: 8.98 kB
../dist/assets/requirementDiagram-TGXJPOKE-e3OV55hP.js 31.41 kB │ gzip: 9.92 kB
../dist/assets/timeline-definition-FHXFAJF6-meAduJgN.js 31.55 kB │ gzip: 10.53 kB
../dist/assets/quadrantDiagram-ABIIQ3AL-Bb6wLm2a.js 34.70 kB │ gzip: 10.23 kB
../dist/assets/chunk-EX3LRPZG-oA0ODuFr.js 38.69 kB │ gzip: 12.71 kB
../dist/assets/xychartDiagram-FW5EYKEG-gCO8yN3N.js 42.14 kB │ gzip: 12.15 kB
../dist/assets/vennDiagram-L72KCM5P-1pMtwo05.js 42.58 kB │ gzip: 15.91 kB
../dist/assets/dnd-xsEmu8eG.js 48.96 kB │ gzip: 16.22 kB
../dist/assets/chunk-V7JOEXUC-Dq7WEM-s.js 49.37 kB │ gzip: 15.81 kB
../dist/assets/util-Cb6vekaB.js 57.07 kB │ gzip: 21.73 kB
../dist/assets/flowDiagram-23GEKE2U-BaUj17kh.js 61.47 kB │ gzip: 19.70 kB
../dist/assets/ganttDiagram-NO4QXBWP-CxlWICLs.js 69.90 kB │ gzip: 23.65 kB
../dist/assets/c4Diagram-LMCZKHZV-DUKzxVDR.js 70.17 kB │ gzip: 19.75 kB
../dist/assets/blockDiagram-677ZJIJ3-9RBsE4wT.js 75.31 kB │ gzip: 21.70 kB
../dist/assets/cose-bilkent-JH36ORCC-68wFxBC2.js 81.92 kB │ gzip: 22.59 kB
../dist/assets/sequenceDiagram-DBY2YBRQ-DQZZZ_Qg.js 117.65 kB │ gzip: 31.38 kB
../dist/assets/swimlanes-5IMT3BWC-BuACkpes.js 120.67 kB │ gzip: 44.15 kB
../dist/assets/architectureDiagram-ZJ3FMSHR-zAU6FNyj.js 151.91 kB │ gzip: 43.24 kB
../dist/assets/react-vendor-CChIRzeM.js 194.27 kB │ gzip: 60.74 kB
../dist/assets/xterm-zg-euOi2.js 335.87 kB │ gzip: 85.14 kB
../dist/assets/markdown-COVWc3k7.js 355.30 kB │ gzip: 109.67 kB
../dist/assets/pdf-CcZYcL52.js 365.12 kB │ gzip: 107.61 kB
../dist/assets/cytoscape.esm-DTSO7Bv0.js 443.72 kB │ gzip: 142.36 kB
../dist/assets/mermaid.core-Ce0RPquC.js 569.20 kB │ gzip: 128.92 kB
../dist/assets/syntax-B-e8QZRG.js 666.56 kB │ gzip: 228.30 kB
../dist/assets/cynefin-VYW2F7L2-B6whK_F0.js 690.83 kB │ gzip: 155.11 kB
../dist/assets/diff-UEgWwdD8.js 1,117.84 kB │ gzip: 342.91 kB
../dist/assets/monaco-D15WGkKO.js 3,930.10 kB │ gzip: 998.63 kB
../dist/assets/index-Dyj_oz8D.js 4,823.18 kB │ gzip: 1,390.31 kB
✓ built in 20.24s
[precompress] 69 files gzipped: 16.74 MB → 4.63 MB (72% saved)
==> Gate 2 OK (Gate 0–2)
Docs: