Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
daf2445
docs: add fresh Mach context spawn plan and design
Haknt Apr 17, 2026
c501dcf
spike(fresh-spawn): validate FD passing between processes via UDS
Haknt Apr 17, 2026
2ed094b
docs(plan): pivot to I/O forwarding after Task 3 spike finding
Haknt Apr 17, 2026
0912cce
feat(fresh-spawn): define UDS protocol schema
Haknt Apr 17, 2026
60670c0
refactor(fresh-spawn): derive default paths via os.homedir + path.join
Haknt Apr 17, 2026
3852bca
feat(fresh-spawn): token-based auth with 0600 file
Haknt Apr 17, 2026
1f397b8
feat(fresh-spawn): UDS spawn server skeleton
Haknt Apr 17, 2026
aff1c4a
feat(fresh-spawn): add idle timeout to server connections
Haknt Apr 17, 2026
83c3443
feat(fresh-spawn): spawn client for terminal-host and fresh-exec
Haknt Apr 17, 2026
b3bb92a
feat(fresh-spawn): add bidirectional stream frame schemas
Haknt Apr 17, 2026
2540799
feat(fresh-spawn): implement spawn-pty-subprocess streaming handler
Haknt Apr 17, 2026
465527c
feat(fresh-spawn): SpawnSession for streaming client
Haknt Apr 17, 2026
711bf76
fix(fresh-spawn): synthetic exit on disconnect + buffer cap + safe er…
Haknt Apr 17, 2026
d0f6f19
feat(terminal-host): spawn PTY subprocesses via fresh-spawn when avai…
Haknt Apr 17, 2026
b0a8001
feat(main): start fresh-spawn server on app lifecycle
Haknt Apr 17, 2026
dc8c213
feat(fresh-spawn): implement fresh-exec streaming handler
Haknt Apr 17, 2026
a26c9de
feat(fresh-spawn): fresh-exec helper binary
Haknt Apr 17, 2026
7dac3fa
feat(fresh-spawn): whitelist + zsh shell hook
Haknt Apr 17, 2026
caa0db6
feat(fresh-spawn): wire shell hook into managed zsh sessions
Haknt Apr 17, 2026
c63b6a8
fix(fresh-spawn): resolve pty-subprocess path at caller, not lifecycle
Haknt Apr 17, 2026
3f26757
refactor(fresh-spawn): host UDS server inside terminal-host daemon
Haknt Apr 19, 2026
b71e251
fix(daemon): ignore SIGTERM in addition to SIGHUP for full nohup sema…
Haknt Apr 19, 2026
6f31a4f
fix(fresh-spawn): address bot review feedback — security, crash safet…
Haknt Apr 19, 2026
1705f9c
fix(fresh-spawn): address follow-up bot review feedback
Haknt Apr 19, 2026
89c8699
fix(fresh-spawn): resolve asar.unpacked path for fresh-exec binary + …
Haknt Apr 19, 2026
82df365
fix(fresh-spawn): cap post-handshake NDJSON line at 1 MiB
Haknt Apr 22, 2026
a3a939f
fix(fresh-spawn): honor socket + stdin backpressure in PTY handler
Haknt Apr 22, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
294 changes: 294 additions & 0 deletions apps/desktop/docs/fresh-mach-context-design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,294 @@
# Superset Fresh Spawn — Design Document

**Tarih:** 2026-04-17
**Durum:** Draft
**Hedef:** macOS'ta stale Mach bootstrap context sorunu için Superset.sh çözümü — çalışan session'ları öldürmeden.

---

## 1. Problem Statement

### Tek Cümle
macOS'ta uzun-ömürlü `terminal-host` daemon fork ettiğinde, child process daemon'ın **stale bootstrap port**'unu miras alır; sonuç olarak Go binary'leri (`gh`, `terraform`, `kubectl`) TLS doğrulaması yapamaz:

```
tls: failed to verify certificate: x509: OSStatus -26276
```

### Kök Sebep
- Go stdlib `crypto/x509` macOS'ta `Security.framework → trustd` → Mach IPC yolu kullanır
- Bu çağrı process'in bootstrap port'u üzerinden lookup yapar
- Bootstrap port process doğduğunda parent'tan **snapshot olarak miras alınır**; runtime'da değiştirilemez
- `terminal-host` daemon uzun süredir çalışıyorsa (Fast User Switch, sistem crash sonrası) bootstrap port stale olur
- Child'lar stale port'u inherit eder, `trustd`'ye ulaşamaz

### Somut Vaka
[superset-sh/superset#2570](https://github.com/superset-sh/superset/issues/2570)

### Mevcut Çözümler ve Kusurları

| Yaklaşım | Çalışır mı? | Kusur |
|----------|-------------|-------|
| [PR #2571](https://github.com/superset-sh/superset/pull/2571): Her startup'ta daemon restart | ✅ | Çalışan session'ları öldürür (dev server, build) |
| `launchctl bsexec` | ❌ | macOS 10.7'den beri security context'i doğru kopyalamıyor |
| `task_set_special_port` runtime swap | ❌ | Lion+ XPC cache'i kırıyor, deprecated |
| `posix_spawnattr_setspecialport_np` | ✅ (teorik) | Mach port transfer infrastructure'ı çok karmaşık, native C gerekir |

---

## 2. Çözüm: Spawn'ı Electron Main'e Delegate Et

### Anahtar İçgörü

**Electron main process her Superset açılışında yeniden doğar.** Bu demektir ki:
- Her Superset açılışında Electron main **fresh Mach bootstrap context** alır
- Bu context çağdaş, canlı kullanıcı oturumunun kimliğini taşır
- Fresh Electron main'den spawn edilen her child **fresh context inherit eder**

O zaman: pty-subprocess'leri terminal-host yerine Electron main doğursun. Terminal-host sadece sessionları yönetsin, fork yapmasın.

### Mimari

**Önce (stale chain):**
```
terminal-host (STALE ctx)
↓ fork/exec
pty-subprocess (STALE ctx inherit)
↓ fork
zsh (STALE)
↓ exec
gh ❌
```

**Sonra (fresh chain):**
```
Electron main (FRESH ctx — her restart'ta yenilenir)
↓ IPC-triggered spawn
pty-subprocess (FRESH ctx ✅)
│ stdin/stdout FD'leri UDS üzerinden pass edilir
terminal-host (STALE ctx — ama fork etmiyor!)
│ sadece I/O forwarding yapar, ChildProcess referansı tutar
zsh (FRESH)
↓ exec
gh ✅
```

### Yeni Terminal Akışı

```
1. Kullanıcı "yeni terminal" → Electron renderer
2. Electron renderer → terminal-host "bana session aç"
3. terminal-host → Electron main UDS (spawn-server): "pty-subprocess spawn et"
4. Electron main: fresh child_process.spawn(pty-subprocess.js)
- Child fresh context alır
5. Electron main: child'ın stdin/stdout/stderr FD'lerini UDS üzerinden SCM_RIGHTS ile terminal-host'a pass eder
6. terminal-host: FD'leri alır, Session class'ına bağlar, I/O akışı başlar
7. Kullanıcıya "session hazır"
```

### Eski Terminal Akışı (Shell Wrapper ile)

Eski session'ların içindeki zsh stale. Onları düzeltemeyiz. Ama zsh'in içindeki **komutları** fresh context'te çalıştırabiliriz.

```
1. Kullanıcı eski terminalde: gh auth login
2. zsh preexec hook devreye girer
3. Hook: gh whitelist'te → komutu yakalar
4. Hook: komutu `fresh-exec gh auth login` ile replace eder
5. fresh-exec → Electron main UDS: "bu komutu fresh ctx'te çalıştır"
6. Electron main: fresh child_process.spawn(gh, [auth, login], { stdio: "pipe" })
- gh fresh context alır, trustd'ye ulaşır
7. Electron main: gh'nin stdin/stdout/stderr'ını fresh-exec'e UDS üzerinden pipe'lar
8. fresh-exec: kendi TTY'sine (eski terminal) yönlendirir
9. gh çalışır ✅
```

### Neden Çalışır?

**Fork inheritance kritik:** Mach bootstrap port **fork anında snapshot** olarak geçer. Electron main fresh'se, ondan fork edilen her şey fresh. Terminal-host'un stale olması önemli değil — o artık fork etmiyor, sadece FD'ler üzerinden I/O yönetiyor.

**Elektron kapalıyken?** Fallback: terminal-host yine eski stale spawn yapar. Degradation, crash değil.

Comment on lines +39 to +115
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot Apr 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Update the design doc to match the implemented architecture.

This still describes Electron-main-owned spawning plus SCM_RIGHTS FD passing, but the PR implements daemon-hosted fresh-spawn with NDJSON I/O forwarding and explicitly rejected FD passing. Please refresh the diagrams, terminal flow, fallback notes, and protocol section so the doc does not preserve the obsolete design.

Also applies to: 160-208

🧰 Tools
🪛 LanguageTool

[grammar] ~95-~95: Ensure spelling is correct
Context: ...ession'ların içindeki zsh stale. Onları düzeltemeyiz. Ama zsh'in içindeki komutları fres...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)

🪛 markdownlint-cli2 (0.22.0)

[warning] 53-53: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


[warning] 64-64: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


[warning] 82-82: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


[warning] 97-97: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/desktop/docs/fresh-mach-context-design.md` around lines 39 - 115, Update
the design doc to reflect the implemented architecture: replace the "Electron
main (FRESH ctx)" spawn model and SCM_RIGHTS FD-passing flow with the actual
"daemon-hosted fresh-spawn" design that uses NDJSON I/O forwarding and
explicitly rejects FD passing; update all diagrams (formerly showing "Electron
main → spawn-server", "pty-subprocess", "terminal-host", "fresh-exec") and the
terminal flows to show daemon as the spawner, show NDJSON streams instead of
SCM_RIGHTS FD transfer, adjust the fallback note to describe daemon vs.
terminal-host behavior, and revise the protocol section to document NDJSON I/O
framing and the deliberate rejection of SCM_RIGHTS/FD passing (also apply the
same edits to the later section referenced in the comment).

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Noted — the design doc will be refreshed in a follow-up doc pass. The 'Post-Spike Architecture Update' section at the top of the plan (apps/desktop/plans/20260417-1500-fresh-mach-context-spawn.md) already documents the pivot away from SCM_RIGHTS; I'll propagate the same into fresh-mach-context-design.md to avoid stale guidance for future readers.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Haknt, understood — thanks for the context. The plan file serving as the interim source of truth for the pivot makes sense. Would you like me to open a GitHub issue to track the fresh-mach-context-design.md refresh so it doesn't get lost across PRs?


🧠 Learnings used
Learnt from: Haknt
Repo: superset-sh/superset PR: 3575
File: apps/desktop/src/main/terminal-host/index.ts:787-805
Timestamp: 2026-04-19T14:17:37.090Z
Learning: In `apps/desktop/src/main/terminal-host/index.ts` (superset-sh/superset desktop app), the fresh-spawn UDS server is intentionally hosted inside the long-lived terminal-host daemon rather than in the Electron main process. The daemon is spawned exactly once by Electron main at first launch (inheriting a fresh macOS Mach bootstrap context at that moment), then survives Electron quit via `detached: true` + `unref()` + SIGHUP/SIGTERM suppression (added in PR `#3574`). On subsequent Electron restarts, the main process re-attaches to the existing daemon via the pid-file liveness check rather than spawning a new one. This means the daemon's Mach context is established once (fresh) and never becomes stale through normal operation; all PTY children of the spawn server inherit that same clean context for the daemon's entire lifetime. Do not flag this placement as a stale-context bug.

Learnt from: Haknt
Repo: superset-sh/superset PR: 3575
File: apps/desktop/src/main/fresh-spawn/spawn-client.ts:40-42
Timestamp: 2026-04-19T14:17:34.111Z
Learning: In `apps/desktop/src/main/fresh-spawn/spawn-client.ts`, `sendSpawnRequest` is a single-shot probe utility (used for health checks and tests). It intentionally destroys the socket after reading the first handshake response (`SpawnResponse`). The actual production streaming path for spawned PTYs goes through `openSpawnSession` in `apps/desktop/src/main/fresh-spawn/spawn-session.ts`, which keeps the UDS socket open after the handshake and exposes a full bidirectional `SpawnSession` EventEmitter. Do not flag `sendSpawnRequest` for closing the socket prematurely — this is intentional design.

Learnt from: CR
Repo: superset-sh/superset PR: 0
File: apps/desktop/CLAUDE.md:0-0
Timestamp: 2025-11-24T21:32:21.725Z
Learning: Applies to apps/desktop/**/AGENTS.md : Document agent responsibilities, capabilities, and interaction patterns in AGENTS.md

Learnt from: CR
Repo: superset-sh/superset PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-18T22:44:26.758Z
Learning: Applies to **/*_PLAN.md : Place implementation plans in `plans/` (cross-cutting) or `apps/<app>/plans/` (app-scoped); move shipped plans to `plans/done/`. Place architecture/reference docs in `<app>/docs/`. Never create `*_PLAN.md` at an app root or inside `src/`.

---

## 3. Bileşenler

### 3.1 Superset Fork — Değişecek Dosyalar

#### 3.1.1 Electron Main: Spawn Server

**Yeni dosya:** `apps/desktop/src/main/fresh-spawn/spawn-server.ts`

Unix Domain Socket server. İki RPC destekler:

1. **`spawn-pty-subprocess`**: pty-subprocess.js'i fresh spawn et, FD'leri client'a pass et
2. **`fresh-exec`**: Arbitrary komut fresh spawn et (shell wrapper tarafından çağrılır)

Socket konumu: `~/.superset/fresh-spawn.sock`
Token-based auth: `~/.superset/fresh-spawn.token`

**Değişim:** `apps/desktop/src/main/index.ts` — startup'ta spawn-server'ı başlat, shutdown'da kapat.

#### 3.1.2 Terminal-Host: Spawn Client

**Yeni dosya:** `apps/desktop/src/main/terminal-host/fresh-spawn-client.ts`

Spawn-server'a bağlanır, FD'ler alır, `net.Socket` + synthetic `ChildProcess` oluşturur (node-pty uyumlu).

**Değişim:** `apps/desktop/src/main/terminal-host/session.ts:268` — `spawnProcess`'i yeni bir `spawnViaFreshClient()` fonksiyonu ile değiştir. Fallback: spawn-client fail ederse eski stale spawn.

#### 3.1.3 Shell Wrapper

**Yeni dosyalar:**
- `apps/desktop/resources/shell-hooks/zsh-fresh-exec.zsh`
- `apps/desktop/resources/shell-hooks/bash-fresh-exec.sh` (v1.1)

**Değişim:** Shell wrapper sistemi (`apps/desktop/src/main/terminal-host/shell-wrappers.ts`) — kullanıcının `.zshrc`'sine source satırı ekler ya da ZDOTDIR pattern'iyle rcfile inject eder.

#### 3.1.4 fresh-exec Helper Binary

**Yeni dosya:** `apps/desktop/src/main/fresh-spawn/fresh-exec.ts`

Küçük Node.js script, Electron main UDS'ine client olarak bağlanır. stdin/stdout/stderr'ı proxy eder.

Build output: `/Applications/Superset.app/Contents/Resources/app.asar.unpacked/bin/fresh-exec`

### 3.2 FD Passing over UDS

Node.js'in built-in IPC (`child.send(msg, handle)`) sadece fork edilmiş child'lar arasında çalışır. Bağımsız process'ler arası FD passing için `SCM_RIGHTS` gerekir.

**Seçenek 1: Mevcut npm package**
- `node-unix-socket` — `sendmsg`/`recvmsg` SCM_RIGHTS desteği var
- `pass-fds` — daha küçük, sadece FD passing
- Risk: Dependency ekler, ama proven

**Seçenek 2: Minimal inline native addon**
- ~50 satır C, sadece 2 fonksiyon: `sendFdsOverUds()`, `recvFdsOverUds()`
- Build node-gyp ile
- Tam kontrol

**Tercih:** Seçenek 1 denenecek (`node-unix-socket`). Çalışmazsa Seçenek 2.
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot Apr 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: The newly added design doc contains stale architecture guidance (SCM_RIGHTS/node-unix-socket FD passing) that conflicts with the documented post-spike implementation direction (UDS NDJSON I/O forwarding), creating actionable maintenance risk.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/desktop/docs/fresh-mach-context-design.md, line 174:

<comment>The newly added design doc contains stale architecture guidance (SCM_RIGHTS/node-unix-socket FD passing) that conflicts with the documented post-spike implementation direction (UDS NDJSON I/O forwarding), creating actionable maintenance risk.</comment>

<file context>
@@ -0,0 +1,294 @@
+- Build node-gyp ile
+- Tam kontrol
+
+**Tercih:** Seçenek 1 denenecek (`node-unix-socket`). Çalışmazsa Seçenek 2.
+
+### 3.3 Protocol
</file context>
Fix with Cubic

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as the coderabbitai comment on this file: the design doc will be refreshed in a follow-up doc-only PR; the plan doc's 'Post-Spike Architecture Update' section already documents the NDJSON I/O-forwarding pivot.


### 3.3 Protocol

UDS mesaj formatı (length-prefixed JSON + FD'ler SCM_RIGHTS ile):

```typescript
// Client → Server
type SpawnRequest =
| {
type: "spawn-pty-subprocess";
token: string;
env: Record<string, string>;
}
| {
type: "fresh-exec";
token: string;
command: string;
args: string[];
cwd: string;
env: Record<string, string>;
ttyName: string; // e.g., "/dev/ttys003"
};

// Server → Client
type SpawnResponse = {
type: "ok";
pid: number;
// Accompanied by 3 FDs via SCM_RIGHTS: stdin, stdout, stderr
} | {
type: "error";
message: string;
code: string;
};
```

---

## 4. Failure Modes & Fallbacks

| Senaryo | Davranış |
|---------|----------|
| Non-macOS platform | Spawn-server başlamaz, terminal-host fallback'e düşer (eski davranış) |
| Electron main kapalı, daemon standalone | UDS bağlantısı fail → stale spawn + `console.warn` |
| UDS socket dosyası yok | Timeout (500ms) → stale spawn + warn |
| Token dosyası invalid | Auth fail → stale spawn |
| FD passing exception | Stale spawn + warn + metric log |
| Kullanıcı `~/.zshrc`'sine el yapımı mod yaptı | Source satırı idempotent, ikinci kez eklemez |
| fresh-exec helper binary yok | Whitelist komut normal çalışır (stale) + warn banner |

**Prensip:** Superset hiçbir senaryoda çökmez. En kötü senaryo: mevcut stale davranış.

---

## 5. Test Stratejisi

### Unit Tests
- `spawn-server.test.ts`: Mock UDS client, spawn request → FD yanıtı doğru mu
- `fresh-spawn-client.test.ts`: Mock UDS server, received FD'ler ChildProcess-like obje yaratıyor mu
- `shell-wrappers.test.ts`: ZDOTDIR inject mekanizması temiz mi

### Integration Tests (macOS only)
- Manuel FastUserSwitch simulasyon script: `sudo killall -USR1 launchd` gibi bir proxy
- `launchctl procinfo <pid>` ile bootstrap port namespace kontrolü
- `security list-keychains` fresh child'da OK, stale'de EPERM

### E2E Test (Manual, local Superset build)
```
Setup:
- Local Superset build+install
- Terminal 1: "python3 -m http.server 9999" başlat (long-running)
- Taint the daemon: launchctl kickstart -k system/com.apple.trustd (veya sistem crash simulate)
- Superset'i kapat-aç

Verify:
1. Terminal 1 hâlâ yaşıyor mu? [python3 server hâlâ hizmet veriyor mu?] → PASS
2. Terminal 2 (yeni): gh auth status → fresh spawn path → PASS
3. Terminal 1'de: gh auth status → shell wrapper → fresh-exec → PASS
4. Fallback: fresh-spawn.sock'u sil, yeni terminal aç, stale spawn'a düşmeli, warn basmalı
```

### CI
- macOS 14 + 15 GitHub Actions runner
- Unit + integration testler
- E2E testler skip (user-interactive, not automatable)

---

## 6. PR Stratejisi

- **PR başlığı:** `fix(desktop): spawn PTY subprocesses via Electron main to avoid stale Mach context on macOS`
- **Approach:** PR #2571'i REPLACE ediyoruz, kapatılmasını öneriyoruz
- **Issue #2570 comment:** Yaklaşımı özetle, link ver
- **PR body:** Problem + PR #2571'in sorunu + yeni yaklaşım + E2E sonuçları + fallback garantileri
- **Commit organization:**
1. `feat(main): add fresh-spawn UDS server`
2. `feat(terminal-host): delegate pty-subprocess spawn to Electron main`
3. `feat(terminal-host): shell wrappers for fresh-exec whitelist`
4. `feat(fresh-exec): client binary for shell wrapper integration`
5. `test: e2e fresh-spawn scenarios`
6. `docs: explain Mach context problem and fresh-spawn architecture`

---

## 7. Open Questions

- [ ] FD passing npm package güvenilir mi? → Spike olarak ilk task'ta test
- [ ] Kullanıcı kendi `.zshrc`'sinde `precmd`/`preexec` kullanıyorsa sıralama sorunu? → Append behavior + test
- [ ] `fresh-exec`'e gönderilen env hangi env olmalı? Eski terminalin mi, fresh process'in mi? → Mix: kullanıcı env'i + fresh bootstrap
- [ ] Whitelist kullanıcı tarafından editlenebilmeli mi? Settings'e eklensin mi? → v1'de hardcode, v1.1'de UI

---

## 8. Kaynaklar

- [posix_spawn(2) - Apple](https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/posix_spawn.2.html)
- [Bootstrap Contexts - Apple](https://developer.apple.com/library/archive/documentation/Darwin/Conceptual/KernelProgramming/contexts/contexts.html)
- [superset-sh/superset#2570](https://github.com/superset-sh/superset/issues/2570)
- [superset-sh/superset#2571](https://github.com/superset-sh/superset/pull/2571) (replace)
- [mobile-shell/mosh#249](https://github.com/mobile-shell/mosh/issues/249) (benzer problem, mosh'ta çözülmedi)
- [node-unix-socket](https://www.npmjs.com/package/node-unix-socket) — potansiyel FD passing lib
6 changes: 6 additions & 0 deletions apps/desktop/electron-builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,12 @@ const config: Configuration = {
"**/resources/sounds/**/*",
// Tray icon must be unpacked so Electron Tray can load it
"**/resources/tray/**/*",
// Shell hook must be unpacked so zsh can `source` it at runtime
// (zsh's built-in `source` is not asar-aware).
"**/resources/shell-hooks/**/*",
// fresh-exec helper binary is invoked from inside a stale-context
// zsh shell via its absolute path, so it must live outside asar.
"**/dist/main/fresh-exec.js",
],

// Extra resources placed outside asar archive (accessible via process.resourcesPath)
Expand Down
5 changes: 5 additions & 0 deletions apps/desktop/electron.vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,11 @@ export default defineConfig({
"git-task-worker": resolve("src/main/git-task-worker.ts"),
// Workspace service - local HTTP/tRPC server per org
"host-service": resolve("src/main/host-service/index.ts"),
// fresh-exec helper — invoked from stale zsh sessions to re-run
// whitelisted commands in Electron main's fresh Mach context.
// Emitted as a sibling to index.js so the shell hook can resolve
// it via __dirname-relative paths.
"fresh-exec": resolve("src/main/fresh-spawn/fresh-exec.ts"),
},
output: {
dir: resolve(devPath, "main"),
Expand Down
1 change: 1 addition & 0 deletions apps/desktop/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@
"nanoid": "^5.1.6",
"node-addon-api": "^7.1.0",
"node-pty": "1.1.0",
"node-unix-socket": "^0.2.7",
"os-locale": "^6.0.2",
"pidtree": "^0.6.0",
"pidusage": "^4.0.1",
Expand Down
Loading