feat(terminal): embedded web terminal — sub-project #1/4 (spec→plan→Sprint 175) - #16
Merged
Conversation
… kayıp 722 satır afc2638'den iç-kanonik anchor geri getirildi (Sprint 149-200 master roadmap, 20 Beta GA gate, debt envanteri, risk matrisi, rekabet/pazarlama, anchor kuralları). Sprint 172 doc-reorg (1c8cef2) docs/vision/roadmap.md'ye damıtırken ~210 satır düşmüştü. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Yeni ⚡ 2026-05-19 bölümü: Brain/Deckent stabil; Sprint 152-174 olgunlaşma; 1 Haziran 2026 = OSS Public Beta (Sprint Mode); post-beta ark (AEGIS 175-200 + vertical) - §4 Master Roadmap / §5 20-Gate / §6 Debt → 🕓 HISTORICAL banner (içerik kanıt olarak korundu) - Header Last update + reconciliation note güncellendi Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…m A) deckent init artık eksik ön-koşulları (claude/codex/gemini CLI, tmux) tespit edip onaylı kurar — blueprint §3.4 "auto-install" gerçeği. ADR-062. - NEW src/core/provisioner.ts: planInstall/installTool/provisionMissing/ resolveProvisionMode/collectMissingTools; OS-aware, ADR-006 shell-free spawn, PROVISIONER_BIN_WHITELIST, no silent sudo (23 test, RED→GREEN) - init.ts: --yes / --no-install + per-tool consent prompt + post-install re-verify - doctor.ts + doctor-format.ts: getProviderInstallHint → provisioner tek-kaynak (legacy format korundu, 0 test regresyonu) - mcp/tools/init.ts: installMissing opt-in paritesi (MCP interaktif consent yok) - ADR-062 (numara DB+FS doğrulandı; 049-059 TaskType ailesine ayrık) Tests: provisioner 23 + doctor 252 + init 211 PASS, tsc 0 error, lint:adr OK Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Brainstormed design for VSCode-like embedded web terminal: full PTY (node-pty) + ws + xterm.js, multi-tab claude/gemini/codex/deckent/shell, localhost-default + zero-config token, tmux-like reattach, transparent DB audit. 4-part decomposition; #1 only. ADR-010 amendment + new ADR required. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Companion constraint checklist for the upcoming dashboard reorg so the embedded web terminal integrates painlessly later. Adds process gate: joint current-state analysis + verified-processes-only plan + run systematic-debugging before finalizing the implementation plan. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Kırık dashboard onarıldı — kullanıcı tarafında çalışır web uygulaması. - NEW dashboard-dir.ts: bundled dashboard resolver (dist/dashboard, kurulu-paket güvenli). Eski bug: web/serve staticDir'i <projectRoot>/src/dashboard/dist'e bakıyordu + serve hiç geçmiyordu (2 test bu bug'ı encode ediyordu → doğru kontrata güncellendi) - NEW chat-handler.ts: gerçek /api/chat (status/help/guidance) — 404 stub kapandı - web.ts/serve.ts: getDashboardStaticDir() wire; server.ts: POST /api/chat route - NEW scripts/build-dashboard.mjs: dayanıklı build (src/dashboard deps oto-kur + --emptyOutDir) — yayınlanan paket artık boş dist/dashboard ile çıkmaz (build canlı doğrulandı: dist/dashboard/index.html + assets üretildi) - npx-first: README quick start/requirements/installation + blueprint §3.4/§12 doc-honesty (gerçek durum + Sprint 175 repair notu) Tests: 666 PASS (provisioner+doctor+init+server+serve+web+chat+dashboard-dir), tsc 0 error. dist/ gitignored — npm files+prepublishOnly üretir. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Gerçek amblem (1024px pixel-art devre-kartı kraken) kanonik konumlara kondu:
- docs/assets/logo.png (README üstü, ortalı)
- src/dashboard/public/{logo,favicon}.png + index.html favicon link +
Layout.tsx sidebar header'da logo (pixelated render)
- docs/.vitepress/public/{logo,favicon}.png + config.ts logo/favicon → png
Dashboard build doğrulandı: logo/favicon dist/dashboard/'a düşüyor. ADR-021
(Kraken Brand Identity) artık grafik amblemle somut.
Not: favicon = full 1024px png (~1.4MB) — imagemagick/sharp yok, ADR-010
minimal-dep gereği image-tooling eklenmedi; küçük favicon post-beta optimize.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Windows PowerShell System.Drawing ile 1024px → 64x64 RGBA yeniden boyutlandırıldı (şeffaflık korundu), aynı isim (favicon.png). Logo (logo.png) tam çözünürlükte kalır. Dashboard build doğrulandı. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Gate #1 joint analysis (Alperen-approved). Adds §1c verified facts: ADR-010 real path + extend existing Sprint-172 Amendment; frontend auth gap (systematic-debugging target); WS auth via verifyBearerToken primitive; absent upgrade handler; config type-surface debt; self-mod sequential mandatory; branch strategy. §8/§5 aligned. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…isions Phase 1 root cause: dashboard works only via DECKENT_API_AUTH_DISABLED=1 (no browser auth path for header-less transports; B-022 flagged). Decisions: terminal WS auth independent+stricter than global bypass; token via localhost page-inject → WS subprotocol; serve.ts CLI surface. + VSCode dock-panel UX; enterprise AuthProvider/SessionBackend/tenantId seams (design now, implement #3). Decomposition preserved. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bite-sized TDD plan from verified §1c/§1d ground truth. Wave 0 deps/ADR/ config/types → 1 backend core → 2 wiring → 3 frontend dock+xterm → 4 e2e/docs/verify. Self-modifying sequential. Self-review included. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ential wave Plan→DIRECTIVES (self-modifying dogfood, sequential). Plan binding contract 905087d. opus=code/sonnet=doc per project rule. Security invariant (auth bypass-independence + raw-output-never-persist) = auto NO_GO. Build/run = Alperen only. Sprint NOT started — awaiting user approval. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
systematic-debugging Phase 1+4.5: 5-sprint loop root cause = auto-debt- injection (sprint-planner.ts:197-216) producing empty-scope CRITICAL tasks; workers cannot resolve a bookkeeping artifact; re-injection 4 sprints (170→174) was the 3+ failed identical-mode fixes pattern. Original 170-001 code verified in repo (tmux.ts:61-70, commit 5ffbf3e). Structural cause already fixed (Sprint 138 T-13 Docker HB Core Fix). Non-destructive DB upsert: status active→resolved, metadata.resolution attached (1020 char honest closure). Unblocks Sprint 175 dry-run: 21→20 tasks, dependency IDs realigned (W0.1=175-001, off-by-one fixed). Architectural follow-up (empty-scope auto-inject) deferred to sub-project #2 per Alperen 2026-05-20. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…cts) Caught during Sprint 175 prep, deferred to #2 per Alperen 2026-05-20: (1) auto-debt-injection empty-scope bug — sprint-planner.ts:197-216, 4-sprint loop root cause for debt-170-001-fix; (2) re-plan orphan cleanup — .tasks/task-{id}-*.json from prior iteration not unlinked (today's finding: orphan task-175-021.json hand-removed). .tasks/ is gitignored — orphan removal not in git history; spec §1d backlog is the durable record. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Observed during Sprint 175 EXECUTE (user reported terminal warning). Three call-sites pass args array WITH shell:true on all platforms: - src/core/plugin-hooks.ts:395, :577 - src/orchestra/baseline-tracker.ts:85 Node DEP0190 + ADR-006 violation + already flagged by authority-enforcer.ts:464-481 (lint, not runtime-enforced). Deferred to sub-project #2 per Alperen 2026-05-20. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sprint-175 audit (W1.3/175-007-xfix) used a SQLite URI shared-cache
trick (`file:audit-idem-XXX?mode=memory&cache=shared`) to share an
in-memory DB between two MemoryStore handles for the idempotent-
migration regression test. better-sqlite3 requires `{ uri: true }`
to honor URI syntax — the option is missing from MemoryStore's
constructor AND from @types/better-sqlite3, so the entire URI string
was written to disk as a literal filename (~100KB SQLite DB per run).
22 phantom files (2.2MB) had accumulated at repo root. Fixed by
refactoring the test to use a real tmpdir() path with explicit
rmSync cleanup (incl. -wal/-shm sidecars from WAL mode). Production
code unchanged. Added .gitignore guard against accidental regression.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Wave 0 of the Embedded Web Terminal (Sprint 175, sub-project #1/4): - node-pty ^1.0.0 + ws ^8.18.0 runtime deps - ADR-010 Sprint-172 Amendment extended with both deps → ADR-062 - ADR-062 (Embedded Web Terminal) accepted; 062-vs-062 collision with Workstream A's consent-based-provisioning resolved by renaming the latter to 063-* (README ADR index regenerated) - TerminalConfig added to DeckentConfig type (no bolt-on intersection pattern — proper field) with secure defaults (localhost-default, shell-allowed, conservative caps) - src/api/terminal/types.ts — 7 shared exports incl. tenantId enterprise seam baked in from day one Plan: docs/superpowers/plans/2026-05-19-embedded-web-terminal.md W0 Spec: docs/superpowers/specs/2026-05-19-embedded-web-terminal-design.md Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Wave 1 of the Embedded Web Terminal (Sprint 175, sub-project #1/4): - LocalTokenAuthProvider: SHA-256 + timingSafeEqual constant-time compare; DELIBERATELY ignores DECKENT_API_AUTH_DISABLED — terminal auth is independent of and stricter than the global API bypass (spec §1c.2, aligns with Sprint-171 B-022 hardening). RCE endpoint must NEVER inherit a dev convenience. - SessionBackend interface + LocalPtyBackend impl (node-pty spawn). The interface is the enterprise seam: future remote / k8s pod-exec impls ship in sub-project #3 without call-site changes. - TerminalAudit: low-volume structured events to memory.db (audit type, tenant_id column, decay_exempt). Raw PTY output is NEVER passed in. memory-store.ts schema: additive ALTER TABLE for tenant_id (idempotent PRAGMA-guarded migration); memory-types.ts adds 'audit' EntryType. - PtySessionManager: Map<sessionId,PtySession>, bounded ring buffer (scrollbackBytes), attach/detach ≠ kill (tmux-like), explicit kill, idle reaper via idleTimeoutMs (deckent kind exempt for long sprints). Tests: 4/4 auth-provider (incl. bypass-independence), 1/1 session-backend (real bash spawn), 4/4 session-manager (ring bound, detach≠kill, maxSessions, reaper deckent-exempt). All TDD RED→GREEN. Plan: docs/superpowers/plans/2026-05-19-embedded-web-terminal.md W1 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Wave 2 of the Embedded Web Terminal (Sprint 175, sub-project #1/4): - attachTerminalGateway: registers server.on('upgrade') for /api/terminal/ws, extracts token from Sec-WebSocket-Protocol (deckent.<token> — browsers cannot set Authorization on WebSocket, spec §1c.2), verifies via AuthProvider.verify() BEFORE any pty spawn, then bridges socket ↔ session-manager. JSON protocol: attach/input/resize ↑, output/exit ↓. Backpressure: pause sending when ws.bufferedAmount > 1MB. Reattach replays bounded ring buffer then live-streams. - src/api/server.ts: GET/POST /api/terminal/sessions + DELETE /:id (Bearer middleware reused for HTTP control); terminal auto-token (randomUUID) generated even when API auth is disabled; localhost-only bootstrap injection of window.__DECKENT_TERMINAL_TOKEN__ into served index.html (127.0.0.1 / ::1 only — remote callers must supply token explicitly). - src/cli/commands/serve.ts: --host <addr> + --no-terminal flags. Refuses to enable the terminal on a non-localhost bind without an explicit token. Tests: 2/2 ws-gateway (reject-before-spawn + accept+replay), 5/5 server-routes (CRUD + localhost-only inject + terminal-disabled path), 3/3 serve-terminal CLI options. Plan: docs/superpowers/plans/2026-05-19-embedded-web-terminal.md W2 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Wave 3 of the Embedded Web Terminal (Sprint 175, sub-project #1/4): - @xterm/xterm ^5.5.0 + @xterm/addon-fit ^0.10.0 as dashboard devDeps (ADR-010 unaffected — frontend devDep, not runtime). - src/dashboard/src/lib/terminal-api.ts: getBootstrapToken (reads window.__DECKENT_TERMINAL_TOKEN__ injected by server.ts for localhost callers only) + sessions CRUD fetch helpers. - useTerminalSocket: WS hook with Sec-WebSocket-Protocol deckent.<token>, auto-reconnect with exponential backoff (5-retry cap), reattach by sessionId on every reconnect (tmux-like UX). - TerminalView: xterm.js + FitAddon, ResizeObserver-driven fit + WS resize protocol, term.onData → socket.send, dispose cleanup. - TerminalTabs + TerminalPanel: multi-tab state with 5 quick-launch kinds (claude / gemini / codex / deckent / shell), close + switch. - DockPanel: VSCode-like resizable + collapsible bottom dock; Layout.tsx hosts <DockPanel><TerminalPanel/></DockPanel> OUTSIDE the React Router Outlet so terminal sessions persist across page navigation. - ConfigPage: new 'Terminal' category surfacing all 5 TerminalConfig fields (enabled, allowShellKind, maxSessions, idleTimeoutMs, scrollbackBytes); EN + TR i18n labels. Tests: 15/15 dashboard terminal suite (terminal-api 2, useTerminalSocket 6, DockPanel 3, TerminalView 2, TerminalPanel 2) — all PASS. Plan: docs/superpowers/plans/2026-05-19-embedded-web-terminal.md W3 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Wave 4 of the Embedded Web Terminal (Sprint 175, sub-project #1/4): - e2e-reattach.test.ts: real http server + real ws + real node-pty + full PtySessionManager + ws-gateway stack. Phase: ws1 attach → input → disconnect → (while detached) mgr.write MARKER_ONE + MARKER_TWO → ws2 reattach by sessionId → assert BOTH markers replayed from ring buffer before live stream resumes. Validates the tmux-like client- disconnect-survives invariant. Runtime ~960ms in CI. - docs/guide/terminal.md (EN canonical): what it is, security model (localhost-default, token auto-inject, bypass-independent auth, remote = explicit --host + token + user-managed TLS), audit timeline, reattach semantics + explicit server-restart boundary, config keys, ws subprotocol contract, sub-project roadmap. - docs/guide/terminal-tr.md: TR parallel (project rule: TR docs are never removed; full parity maintained). Plan: docs/superpowers/plans/2026-05-19-embedded-web-terminal.md W4 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sprint-175 Wave 2 (T2.3) added --host / --no-terminal flags but serve.ts still called createHttpServer(root, port, staticDir) with the positional signature — terminalBackend was never passed, so server.ts' `if (terminalBackend)` guard at line 877 stayed false: - terminalToken not minted - window.__DECKENT_TERMINAL_TOKEN__ not injected into served index.html - attachTerminalGateway never called (no /api/terminal/ws upgrade handler) - GET /api/terminal/sessions 401'd via the generic Bearer middleware - Terminal panel rendered visually but had no live channel Wire it: import LocalPtyBackend, instantiate when isLocalhost && !--no-terminal, pass via options object to createHttpServer. Server signature already supported it (HttpServerOptions.terminalBackend, line 784 of server.ts); only the CLI hand-off was missing. Verified: tsc clean, dist/cli/commands/serve.js now imports LocalPtyBackend and threads terminalBackend through. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sprint-175 Wave 3 (T3.1) plumbed window.__DECKENT_TERMINAL_TOKEN__
into the SPA and used it on the WebSocket subprotocol — but the HTTP
fetch helpers (createSession / listSessions / killSession) sent the
request WITHOUT any Authorization header. The terminal HTTP block at
src/api/server.ts:919 reads token from req.headers['authorization']
('Bearer …') and rejects every empty-header call with 401, by design
(bypass-independence — spec §1c.2).
Symptom: dashboard panel opened, +shell clicked, all calls 401:
POST /api/terminal/sessions → 401
GET /api/terminal/sessions → 401
DELETE /api/terminal/sessions/:id → 401
Fix: terminal-api.ts now reads the bootstrap token via getBootstrapToken()
and attaches 'Authorization: Bearer <token>' to every terminal HTTP call.
Build smoke: dashboard bundle hash flipped (index-MoZ7g0zT.js →
index-D-n_0X2r.js), Authorization Bearer present in minified output.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ical docs Sub-project #1/4 (Embedded Web Terminal) shipped 2026-05-19→2026-05-20, operationally smoke-confirmed by Alperen. Update reader-facing docs to reflect the delivery honestly + the four-part path ahead. - README + README-TR: new Highlights bullet (top), link to terminal guide - VISION + VISION-TR: extend 'Where we are now' / 'Where we are going' with the embedded terminal as the first concrete step toward agentic- OS workflows + the 3 deferred sub-projects (#2 self-security, #3 multi-tenant/k8s, #4 enterprise integrations) with the seams (AuthProvider / SessionBackend / tenantId) called out - docs/release/roadmap.md: new 'Phase 3.6: Embedded Web Terminal' before Phase 3.5, with delivered checklist + sub-project #2-4 backlog - docs/release/beta-tracker.md + -tr.md: Last-updated header refreshed (2026-05-14→2026-05-20); new 'Sprint 175 — Embedded Web Terminal' section with metrics (46/46 tests, build/pack clean), honest debt (node-pty linux-x64 prebuild, DECKENT_API_AUTH_DISABLED=1 dashboard precondition), process learnings (two durable feedback memories) - docs/ROADMAP-GOD-LEVEL.md: new ⚡ 2026-05-20 section at the top, full Sprint 175 record + sub-project backlog table + Sprint 176+ priorities - docs/adr/README.md: regenerated index (already had ADR-062/063 after collision rename earlier) No exaggeration: smoke confirmed, but DECKENT_API_AUTH_DISABLED=1 is still required for dashboard data calls (frontend general API auth plumbing is sub-project #2/#3 scope) and node-pty linux-x64 prebuild needs the optionalDep fix in Sprint 176. Recorded as honest debt. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
175-006 left a tech-debt: node-pty@^1.1.0 ships no linux-x64 prebuild and falls back to node-gyp rebuild (needs python3/build-essential). On OSS GA installs this breaks `npm install` for users without C++ toolchain. @lydell/node-pty is a thin drop-in fork that distributes prebuilt binaries via npm-native optionalDependencies (6 platforms: linux/darwin/win32 × x64/arm64). Same API surface (`pty.spawn(...)`), one-line import change. Result: tests/api/terminal/session-backend.test.ts (skipped on linux-x64 in Sprint 175) now PASSES, e2e reattach still green, tsc --noEmit clean. Closes debt-175-006 (env build-tooling dependency). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Three deferred fixes from Sprint 175 implementation that were missing from the wave commits: 1. sprint-docs-updater.ts — add `terminal:` block to the fallback config used when projects haven't customized .deckent/config.json, so the ConfigPage Terminal category (W3.6) has live values on first run. 2. dashboard-page.test.ts — CATEGORIES count assertion 13 → 14 to match the Terminal category added by W3.6. 3. dashboard-build-smoke.test.ts — adapt to build:dashboard now delegating to scripts/build-dashboard.mjs (script wrapper, not a raw vite call). Verifies wrapper script content matches the expected dashboard path. All 493 dashboard tests pass; tsc --noEmit clean. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Auto-regenerated bookkeeping from Sprint 175 (embedded web terminal, sub-project #1/4). No semantic changes — these are outputs of brain/ auditor scans + sprint-docs-updater hooks. - .brain/exports/{summary,memory,debt}.md: ADR-062 added to active decisions, Sprint 175 learnings recorded, debt-175-006 closed by follow-up commit (now resolved via @lydell/node-pty swap). - .claude/.codex/.cursor/.gemini/rules/{brain,auditor,worker-default}.md: ADR list regenerated to include ADR-062 (Embedded Web Terminal). - .deckent/agents/*/agent.json + skills/*/manifest.json: routing stats (totalUses/successRate) updated by sprint-router outcome tracking. - .deckent/features-manifest.json: Sprint 175 feature counts refreshed. - docs/CHANGELOG.md, docs/SPRINT-LOG.md: Sprint 175 milestone appended. - docs/audits/sprint-139/dead-code-report.md: minor stat resync. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Preserve work artifacts from the three sprints that culminated in the embedded web terminal (Sprint 175 ships sub-project #1/4): - .brain/archive/DIRECTIVES-sprint-{173,174,175}.md: original sprint goal text + per-task scope. Memory V2 stores parsed content in memory.db, but the verbatim markdown is useful for git-history grep ("which sprint introduced X?") and for review of brain's planning decisions. - docs/audits/sprint-{173,174,175}/load-test-report.md: read-only audit outputs captured during each sprint's EVALUATE phase. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…d files
Branch carried 70+ runtime/debris files that gitignore patterns didn't
fully cover, plus several files that became gitignored long ago but
remained tracked (gitignore is retroactive only). One-time cleanup:
New ignores:
- .brain/ERRORS.md, .brain/PROJECT-IDENTITY.md (deprecated per ADR-046),
.brain/directives-backup/
- .deckent/sprint-*-panic-*.json, sprint-*-*-result.json, sprint-*-
subagent-prompts/, sprint-*-merge-runbook.sh, sprint-*-worktree-
setup.sh, sprint-*-dispatch-locks.json, evaluations/
- src/dashboard/tsconfig.tsbuildinfo
- .claude/settings.local.json
- .npm-cache/, vitest-out.txt, kendimenot.md
Untracked (git rm --cached, file remains on disk):
- .brain/{ERRORS,MEMORY,RETRO}.md
- .deckent/{config,project-stack}.json
- src/dashboard/tsconfig.tsbuildinfo
- .claude/settings.local.json
- .deckent/archive/metrics/metrics-sprint-164.jsonl.gz (already-deleted)
These files regenerate on first sprint run, so removing from index
doesn't break workflow; it just stops the per-sprint diff noise.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ems) The §1d backlog had 3 items captured during Sprint 175 prep; the post-implementation review surfaced 3 more (4–6) plus a self-security procedure scope section for the #2 spec phase. All references checked against current source (npm run lint:link clean): 4. Schema-gate coverage enforcement gap — coverage_threshold auto-lowers when avg <70%, so the gate moves with reality instead of holding the bar. Needs hard-floor vs aspirational split. 5. WorkerCard/DashboardPage pre-existing TS errors — TS2345 i18n contravariance, suppressed because root `lint` doesn't recurse into src/dashboard/tsconfig.json. Wire the dashboard tsc into root lint. 6. `doctor` DECISIONS.md obsolete check — Memory V2 (Sprint 143) moved this to memory.db; doctor still hard-requires .brain/DECISIONS.md. Cascade fossils across constants.ts, debt-manager.ts, sprint-docs- helpers.ts, authority-enforcer.ts catalogued. Self-security scope section (sub-project #2): prompt guard, command guard, outbound rate-limit, mutual-TLS hook on AuthProvider, self-audit- of-audit. To be ADR'd in the #2 spec phase. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Six independent build-blockers surfaced when PR #16 triggered the docs workflow for the first time (main never had a passing docs build). Pre-existing root causes, none introduced by Sprint 175: 1. docs/launch/blog-devto-launch.md — YAML frontmatter `description:` contained an unquoted second colon ("...one hard-won insight: multi- agent..."), parsed as an incomplete explicit mapping pair. Quoted. 2. docs/.vitepress/config.ts — srcExclude expanded to skip developer- only directories (superpowers/, audits/, launch/, governance/) that contain TS generics (`trace<T>`), placeholder syntax (`<PID>`, `<noreply@anthropic.com>`), and other patterns VitePress's Vue compiler interprets as unclosed HTML elements. reference/ was re-included now that placeholders inside it are escaped (see #3). 3. scripts/gen-reference-docs.mjs — tableCell() now HTML-entity-escapes bare-word placeholders like `<sprint-id>`, `<command>`, `<id>` in auto-generated reference tables. Regen propagated to cli.md and mcp-tools.md. Real HTML tags in source (`<br/>`, `<sub>`) won't match this anchored single-token pattern. 4. src/mcp/tools/audit.ts — `.deckent/<sprint-id>-gate.json` in the description rewritten as `.deckent/{sprintId}-gate.json` so the auto-gen output doesn't ship the breaking placeholder. 5. docs/adr/030 + docs/reference/managed-docs.md — `{{path.to.value}}` template placeholders in prose escaped as `{{…}}` so Vue's interpolation parser leaves them alone. (Code blocks like JSON examples are safe — VitePress treats fenced code as raw.) 6. docs/reference/security.md + docs/guide/docker-backend.md — two dead-link callouts fixed: `[ADR Index](../adr/)` → `(../adr/README)` (vitepress directory links don't fall back to README), and the architecture-overview cross-link replaced with a GitHub URL (the architecture/ dir stays in srcExclude due to its TS generics). Verification: `cd docs && npx vitepress build` completes clean. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Six pre-existing test failures surfaced by PR #16 CI dogfood (all present on main, none introduced by Sprint 175). Each test asserted an obsolete contract — the production code was updated in an earlier sprint but the matching test was not. CLI suite (3 fails): - tests/cli/commands/serve-overhaul.test.ts:128 — `createHttpServer` signature became `(root, opts)` in Sprint 175 W2.3 (commit 1a69b68) to wire host + terminalBackend. Updated to match opts-object shape. - tests/cli/serve.test.ts (2 cases — default & custom port) — same signature change; also the listen-on banner now uses 127.0.0.1 (explicit-bind security default) instead of "localhost". Security suite (2 fails): - tests/security/shell-injection.test.ts (2 cases) — Sprint 170 P0-3 (Tmux Prompt Filename TaskId-Aware) renamed `.prompt-{rand}.txt` to `.prompt-{taskId}-{rand}.txt`. Updated both assertions to include the taskId prefix. Monitor suite (1 fail): - tests/monitor/alert-emitter.test.ts:112 — "provider parity" asserted `^paths:` frontmatter on `.codex/.gemini/.cursor` rules, but src/core/rule-generator.ts:77-113 intentionally emits the `paths:` hint only for Claude (the other three loaders don't honour it). Test relaxed to assert the AUTO-START marker — the actual parity invariant. Verified locally: tests/cli/, tests/security/, tests/monitor/ now green; full vitest suites pass (Core 4728, MCP+API 2500, Dashboard 493). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two CI infrastructure fixes for PR #16: 1. .github/workflows/dashboard-build.yml — Node 18 dropped from the build matrix. Tailwind 4 ships `@tailwindcss/oxide` as a per-platform optionalDependency; npm CLI bug #4828 fails to resolve it on Node 18 in CI runners (the cache layout differs). Tailwind 4 officially supports Node 20+. engines.node remains >=18 for the library — only the dashboard build needs 20+. The Node 18 row also masked test- build smoke failures on otherwise-green matrices. 2. .secrets-baseline — regenerated with `--build-baseline` after the Sprint 171 doc reorg moved audit fixtures from `.audit/sprint-167/` to `docs/audits/sprint-167/`. All 8 unallowlisted hits are confirmed-safe: - 6 audit-report fixtures (Sprint 167 T6, Sprint 171 security) that document detection patterns by quoting the literal regex. - 2 false positives in docs/adr/README.md — the OPENAI_KEY pattern matches the substring `sk-detection-...` inside the ADR-039 filename slug ("self-modifying-task-detection-..."), not a key. Verified: `node scripts/security/secret-baseline.mjs` exits 0. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
8 tasks
…TS + Current Sprint 175 PR #16 CI dogfood surfaced 230+ test failures across the entire matrix. Root cause was not Sprint 175 work — it was systemic CI rot. ## Why now | Node | Status (May 2026) | We were testing? | |------|---------------------|---------------------| | v18 (Hydrogen) | EOL Apr 2025 — 1+ year dead | ❌ Yes (wasted) | | v20 (Iron) | EOL Mar 2026 — 2 months dead | ❌ Yes (wasted) | | v22 (Jod) | Maintenance EOL May 2026 — this month | ❌ Yes (wasted) | | **v24 (Krypton)** | **Active LTS (until May 2027) — production target** | ❌ NO (untested) | | v26 | Current (latest) | ❌ NO (untested) | The matrix burned three slots on dead-or-dying releases while never touching Active LTS or Current. better-sqlite3 v12.10.0 (released May 12, 2026) explicitly removed Node 20/23 prebuilds and added Node 26 — so the old matrix was guaranteed to fail post-12.10.0 anyway. ## Changes - All 7 workflows (`ci.yml`, `dashboard-build.yml`, `cross-platform-e2e.yml`, `docs.yml`, `publish.yml`, `release.yml`, `secret-scan.yml`): - Matrix `[18.x, 20.x, 22.x]` → `[24.x, 26.x]` (test-core, test-orchestra, test-cli, test-remaining, dashboard build) - Fixed `'22.x'` / `'20'` → `'24.x'` / `'24'` (typecheck, security, test-docs-scripts, test-dashboard, test-windows, coverage, build, docs, publish, release, secret-scan, cross-platform-e2e) - Dashboard artifact upload condition: `matrix.node-version == '22.x'` → `'24.x'` so the LTS run ships the artifact. - `package.json`: - `engines.node`: `>=18.0.0` → `>=24.0.0`. Breaking-change-by-design for OSS GA — Node 18/20/22 users get a clear error instead of a runtime crash later (npm shows `engineStrict` warning at install time). - `better-sqlite3`: `^12.9.0` → `^12.10.0` (Node 26 prebuilds, Node 20/23 cleanup). Verified locally: 12.10.0 ships prebuilds for the new matrix; no native compile required at install time. - New script `ci:rebuild-native: npm rebuild better-sqlite3 --ignore- scripts=false`. Required because `.npmrc` sets `ignore-scripts=true` (Sprint 167 H3 supply-chain hardening); `npm ci` honours that and skips better-sqlite3's `prebuild-install || node-gyp rebuild`, so the native binding never lands without an explicit rebuild step. Targeted to the one package that needs it — the .npmrc guard for every other dependency stays intact. - All 7 workflows: new step `npm run ci:rebuild-native` after `npm ci`. Five-second cost per job; without it the binding is missing and 200+ tests collapse on `Database` instantiation. - `src/cli/entry.ts`: runtime Node guard `< 18` → `< 24`. Error message updated to mention Active LTS. - 7 test files realigned: - `tests/github/ci-workflow.test.ts`, `tests/github/workflows/ci.test.ts`, `tests/github/workflows/release.test.ts` — workflow assertions against the new matrix and fixed versions. - `tests/cli/bin-entry-validation.test.ts`, `tests/cli/npx-compat.test.ts` — engines.node and entry.ts guard assertions. - `tests/core/nervous-enabled-integration.test.ts` — `.deckent/config. json` dogfood-only assertion now skipped when the file is absent (PR #16 made the config gitignored). ## Local verification (Node 24.15.0, the current Active LTS) | Gate | Result | |------|--------| | Non-orchestra suites | 475 files, **10,625 pass**, 23 skip, **0 fail** | | Orchestra suite | 205 files, **4,416 pass**, 11 skip, **0 fail** | | Dashboard suite | 23 files, **493 pass**, **0 fail** | | `tsc --noEmit` | clean | | `npm run build` | dist/cli/{index,entry}.js, dist/mcp/server.js, dist/index.js all present with shebang | | VitePress build | complete | | `secret-baseline.mjs` | 0 unallowlisted secrets | Total: **15,534 tests pass, 0 fail**. ## Baseline note This PR is based on `docs/embedded-web-terminal-spec` (PR #16). PR #16's test/vitepress/secret-baseline fixes are inherited; once PR #16 merges to main, this PR's base becomes main automatically with no conflict. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
AlbSar
added a commit
that referenced
this pull request
May 20, 2026
Six independent build-blockers surfaced when PR #16 triggered the docs workflow for the first time (main never had a passing docs build). Pre-existing root causes, none introduced by Sprint 175: 1. docs/launch/blog-devto-launch.md — YAML frontmatter `description:` contained an unquoted second colon ("...one hard-won insight: multi- agent..."), parsed as an incomplete explicit mapping pair. Quoted. 2. docs/.vitepress/config.ts — srcExclude expanded to skip developer- only directories (superpowers/, audits/, launch/, governance/) that contain TS generics (`trace<T>`), placeholder syntax (`<PID>`, `<noreply@anthropic.com>`), and other patterns VitePress's Vue compiler interprets as unclosed HTML elements. reference/ was re-included now that placeholders inside it are escaped (see #3). 3. scripts/gen-reference-docs.mjs — tableCell() now HTML-entity-escapes bare-word placeholders like `<sprint-id>`, `<command>`, `<id>` in auto-generated reference tables. Regen propagated to cli.md and mcp-tools.md. Real HTML tags in source (`<br/>`, `<sub>`) won't match this anchored single-token pattern. 4. src/mcp/tools/audit.ts — `.deckent/<sprint-id>-gate.json` in the description rewritten as `.deckent/{sprintId}-gate.json` so the auto-gen output doesn't ship the breaking placeholder. 5. docs/adr/030 + docs/reference/managed-docs.md — `{{path.to.value}}` template placeholders in prose escaped as `{{…}}` so Vue's interpolation parser leaves them alone. (Code blocks like JSON examples are safe — VitePress treats fenced code as raw.) 6. docs/reference/security.md + docs/guide/docker-backend.md — two dead-link callouts fixed: `[ADR Index](../adr/)` → `(../adr/README)` (vitepress directory links don't fall back to README), and the architecture-overview cross-link replaced with a GitHub URL (the architecture/ dir stays in srcExclude due to its TS generics). Verification: `cd docs && npx vitepress build` completes clean. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
AlbSar
added a commit
that referenced
this pull request
May 20, 2026
Six pre-existing test failures surfaced by PR #16 CI dogfood (all present on main, none introduced by Sprint 175). Each test asserted an obsolete contract — the production code was updated in an earlier sprint but the matching test was not. CLI suite (3 fails): - tests/cli/commands/serve-overhaul.test.ts:128 — `createHttpServer` signature became `(root, opts)` in Sprint 175 W2.3 (commit 1a69b68) to wire host + terminalBackend. Updated to match opts-object shape. - tests/cli/serve.test.ts (2 cases — default & custom port) — same signature change; also the listen-on banner now uses 127.0.0.1 (explicit-bind security default) instead of "localhost". Security suite (2 fails): - tests/security/shell-injection.test.ts (2 cases) — Sprint 170 P0-3 (Tmux Prompt Filename TaskId-Aware) renamed `.prompt-{rand}.txt` to `.prompt-{taskId}-{rand}.txt`. Updated both assertions to include the taskId prefix. Monitor suite (1 fail): - tests/monitor/alert-emitter.test.ts:112 — "provider parity" asserted `^paths:` frontmatter on `.codex/.gemini/.cursor` rules, but src/core/rule-generator.ts:77-113 intentionally emits the `paths:` hint only for Claude (the other three loaders don't honour it). Test relaxed to assert the AUTO-START marker — the actual parity invariant. Verified locally: tests/cli/, tests/security/, tests/monitor/ now green; full vitest suites pass (Core 4728, MCP+API 2500, Dashboard 493). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
AlbSar
added a commit
that referenced
this pull request
May 20, 2026
Two CI infrastructure fixes for PR #16: 1. .github/workflows/dashboard-build.yml — Node 18 dropped from the build matrix. Tailwind 4 ships `@tailwindcss/oxide` as a per-platform optionalDependency; npm CLI bug #4828 fails to resolve it on Node 18 in CI runners (the cache layout differs). Tailwind 4 officially supports Node 20+. engines.node remains >=18 for the library — only the dashboard build needs 20+. The Node 18 row also masked test- build smoke failures on otherwise-green matrices. 2. .secrets-baseline — regenerated with `--build-baseline` after the Sprint 171 doc reorg moved audit fixtures from `.audit/sprint-167/` to `docs/audits/sprint-167/`. All 8 unallowlisted hits are confirmed-safe: - 6 audit-report fixtures (Sprint 167 T6, Sprint 171 security) that document detection patterns by quoting the literal regex. - 2 false positives in docs/adr/README.md — the OPENAI_KEY pattern matches the substring `sk-detection-...` inside the ADR-039 filename slug ("self-modifying-task-detection-..."), not a key. Verified: `node scripts/security/secret-baseline.mjs` exits 0. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
AlbSar
added a commit
that referenced
this pull request
May 20, 2026
PR #16 main merge surfaced 3 test failures that all pass locally on the same Node 24.15.0 runtime — pure CI environment divergence. Captured in sub-project #2 backlog as item #7 (lokal-CI gap) with concrete fix candidates (mock hygiene, process.kill semantics, vitest --retry tag). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
AlbSar
added a commit
that referenced
this pull request
May 20, 2026
…rity Sprint 176 spec — 12 task, 5 wave, June 1 2026 beta-blocker: A. Planner state-hygiene (W1-W3, 7 task): 1. Auto-debt empty-scope (sprint-planner.ts:197-216) 2. Re-plan orphan task file cleanup 3. DEP0190 shell:true (3 call-site) 4. Coverage hard-floor / aspirational split 5. Dashboard TS errors + root lint wire 6. doctor DECISIONS.md obsolete + 5-file cascade 7. CI-only test flakes (lokal-CI divergence) B. Self-security guards (W4-W5, 5 task — interceptor pattern, 5 new files): 8. Prompt guard (input pattern matcher) 9. Command guard (shell-kind deny-list, remote-only) 10. Outbound rate-limit (daily tenant-scoped quota) 11. mTLS hook (AuthProvider interface extension) 12. Self-audit-of-audit (HMAC append-only chain + verify CLI) Five non-negotiable security invariants (I1-I5): - I1 no silent drop, I2 no raw payload in audit, I3 default-deny on host≠127.0.0.1, I4 append-only audit + HMAC tamper detect, I5 tenant-scope isolation (audit + quota + guard state). Locked decisions: single sprint #176, structured planning, sequential self-modifying dispatch (Sprint 175 pattern), Brain manuel wave gates (ADR-047), non-destructive memory.db ALTER, GO_WITH_TECH_DEBT acceptable verdict (≤2 GWT, W1-W3≥5 DONE, W4≥2 DONE). Predecessor: PR #16 (sub-project #1, terminal, merged 2026-05-20). Successor: sub-project #3 (multi-tenant + k8s + mTLS impl, post-beta). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
AlbSar
added a commit
that referenced
this pull request
May 20, 2026
…rift Sprint 176 worker on task 176-001 produced a 3 KB NO_GO refuse note documenting auto-debt-injection empty-scope failure — a live reproduction of spec §1d.1, the exact bug W1-1 fixes. On SIGTERM the brain-honest- gate mechanism stub-overwrote the result file to 364 bytes erasing the forensic notes. This document restores the original notes from the conversation transcript + records the two concurrent dogfood bugs that triggered the kill: (1) config.json template-regen losing spawn_backend (cascade from PR #16 git rm --cached); (2) nervous_system.directives_protection auto_restore rolling DIRECTIVES.md back to Sprint 175 after cleanup. Cross-referenced in sub-project #2 plan Task 1 — to be cited in the regression fixture for sprint-planner debt injection. Open question captured for sub-project #2 backlog #8 (nervous_system baseline-update hook on deckent_set_directives success). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Ships sub-project #1/4 of the embedded web terminal initiative: a VSCode-style dockable terminal inside the deckent dashboard with interactive
claude/gemini/codex/deckent/shellPTY sessions,wstransport, tmux-style reattach, and a hard security boundary that is independent of (and stricter than) the global API auth bypass.26 commits / 145 files / +7,082 / −1,561.
What's in this PR
Spec & Plan (commits
03ff09c..905087d)docs/superpowers/specs/2026-05-19-embedded-web-terminal-design.md— design with §1c verified Step-A, §1c.2 auth root-cause, §1d VSCode dock + enterprise seamsdocs/superpowers/plans/2026-05-19-embedded-web-terminal.md— 5-wave TDD plan (binding per-task contract)docs/adr/062-embedded-web-terminal.md) accepted + ADR-010 amendment forws&@lydell/node-ptySprint 175 Implementation — 5 sequential waves
84b16406b8e554c496d88,1a69b6888e51e3,4664cf6ffb67b7Follow-up fixes (post Sprint 175 dogfood)
742af849— plug SQLite URI phantom-file leak in audit.test.ts89bc7d5b— record milestone across canonical docs110c24c2— swapnode-pty→@lydell/node-ptyfor zero-compile install (closes debt-175-006: linux-x64 prebuild gap)713ba9bf— Sprint 175 follow-up: terminal config fallback + dashboard test syncac3af194— refresh runtime regen + ADR-062 propagation4b5cec7b— archive directives + audit outputs (sprints 173–175)eb683b44— gitignore: drop sprint runtime debris + untrack already-ignored filesSecurity invariant (non-negotiable)
The terminal's WS auth is independent of
DECKENT_API_AUTH_DISABLEDand stricter than the global API path. Token is delivered via WebSocket subprotocol (not Authorization header), and auth happens before any PTY spawn (4401 close on bad token → no shell, no audit, no resource leak). Raw PTY output is never persisted —TerminalAuditrecords structured events only (action + tenant_id + kind, no bytes).Tests proving both rails:
tests/api/terminal/auth-provider.test.ts— 4 cases incl.DECKENT_API_AUTH_DISABLED=1with bad token → still rejectedtests/api/terminal/ws-gateway.test.ts— bad subprotocol token → close before bridge, no spawntests/api/terminal/audit.test.ts— assertion that audit content never contains raw PTY bytesEnterprise seams (interfaces only — #3 implements)
Per spec §1d, the protocol surface is multi-tenant-ready but the only concrete impl is
local:AuthProviderinterface +LocalTokenAuthProvider(SHA-256 + timingSafeEqual)SessionBackendinterface +LocalPtyBackend(remote / k8s pod-exec deferred to ci: Bump actions/setup-node from 4 to 6 #3)tenantIdfield in every type from day oneSmoke test ✅ (Alperen, 2026-05-20 evening)
Live confirmation: claude / gemini / shell tabs spawn, type-through works, ANSI rendering correct, detach→reattach replays buffer, idle reaper exempts deckent sessions, multi-tab in DockPanel toggle/resize functional.
Roadmap — what's next
This is #1/4. Subsequent sub-projects (each its own spec→plan→sprint):
shell:trueviolations, schema-gate coverage enforcement, WorkerCard/DashboardPage pre-existing TS errors, doctor DECISIONS.md obsolete check)AuthProvider/SessionBackendreal impls land)Server-restart session persistence (disk-backed) is backlog for post-#1.
Test plan
npm installclean on linux-x64 (was failing pre-@lydell/node-ptyswap)npm run lint(tsc --noEmit) exit 0npm run lint:adrexit 0 (ADR-062 valid)npx vitest run tests/api/terminal/— all PASS (auth-provider, session-backend, audit, session-manager, ws-gateway, server-routes, e2e-reattach)npm run test:dashboard— 493/493 PASS (incl. new terminal panel/view/tabs/dock + ConfigPage Terminal category)npm run build:all && deckent serve→ dashboard at http://127.0.0.1:7777 → open dock → spawn each of (claude, gemini, codex, deckent, shell), type, detach, reattachnpm pack --dry-runclean (deps include@lydell/node-pty+ws; no internal state files)🤖 Generated with Claude Code