Skip to content

Commit e4ba5ae

Browse files
committed
feat: v1.0.0 — browser mode, deploy integration, wallet security, crash reporting
Browser Mode: - Rebuilt architecture: removed dual-engine (fetch + webview), webview-only now - Agent chat via Anthropic SDK with OAuth token from Claude CLI credentials - Inspector captures computed styles + attributes, integrated into chat - Unblocked localhost, fixed event handling, added error boundary - Back/forward disabled state, URL bar sync, webview security Deploy Integration (Vercel + Railway): - DeployService with Vercel REST API + Railway GraphQL API - Token-based auth via personal access tokens (stored encrypted) - Git remote parsing (SSH + HTTPS), auto-detect project matching - Deploy panel (center-panel) with connect, link, deployment list, redeploy - Git panel deploy status badge, sidebar icon, plugin registry Wallet Security: - Private key export rate-limited + confirmation dialog - Transaction timeout (60s), send confirmation step - Address validation via PublicKey, balance check before send - Keypair zeroing after use, agent spend limits (2 SOL/day) - Helius key validation before storing Grind Mode: - Grid state moved from useState to Zustand (survives mode switching) - Claude CLI check on cell activation, terminal kills awaited - xterm dispose guards Infrastructure: - Auto-update via electron-updater + GitHub Releases - DB integrity check on startup, WAL checkpoint on close - Crash reporting: main + renderer capture, Settings crash log viewer - Onboarding completion flag, path validation for filesystem IPC - Code signing config, macOS entitlements, CI/CD release automation - DB schema V11 (deploy_cache) + V12 (app_crashes)
1 parent 695a2f9 commit e4ba5ae

52 files changed

Lines changed: 4203 additions & 653 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/ci.yml

Lines changed: 28 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,8 @@ on:
66
pull_request:
77
branches: [main]
88

9-
concurrency:
10-
group: ${{ github.workflow }}-${{ github.ref }}
11-
cancel-in-progress: true
12-
139
jobs:
1410
typecheck:
15-
name: Typecheck
1611
runs-on: ubuntu-latest
1712
steps:
1813
- uses: actions/checkout@v4
@@ -27,7 +22,6 @@ jobs:
2722
- run: pnpm run typecheck
2823

2924
test:
30-
name: Test
3125
runs-on: ubuntu-latest
3226
steps:
3327
- uses: actions/checkout@v4
@@ -39,17 +33,32 @@ jobs:
3933
node-version: 22
4034
cache: pnpm
4135
- run: pnpm install --frozen-lockfile
42-
- run: pnpm run pretest
4336
- run: pnpm run test
4437

45-
build:
46-
name: Build
38+
build-windows:
39+
runs-on: windows-latest
40+
needs: [typecheck, test]
41+
steps:
42+
- uses: actions/checkout@v4
43+
- uses: pnpm/action-setup@v4
44+
with:
45+
version: 9
46+
- uses: actions/setup-node@v4
47+
with:
48+
node-version: 22
49+
cache: pnpm
50+
- run: pnpm install --frozen-lockfile
51+
- run: pnpm run build
52+
- run: pnpm run package
53+
- uses: actions/upload-artifact@v4
54+
with:
55+
name: windows-build
56+
path: release/**/*.exe
57+
if-no-files-found: warn
58+
59+
build-macos:
60+
runs-on: macos-latest
4761
needs: [typecheck, test]
48-
strategy:
49-
fail-fast: false
50-
matrix:
51-
os: [windows-latest, macos-latest]
52-
runs-on: ${{ matrix.os }}
5362
steps:
5463
- uses: actions/checkout@v4
5564
- uses: pnpm/action-setup@v4
@@ -61,15 +70,11 @@ jobs:
6170
cache: pnpm
6271
- run: pnpm install --frozen-lockfile
6372
- run: pnpm run build
64-
- name: Package
65-
run: pnpm run package
66-
env:
67-
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
73+
- run: pnpm run package
6874
- uses: actions/upload-artifact@v4
6975
with:
70-
name: daemon-${{ matrix.os }}
76+
name: macos-build
7177
path: |
72-
release/*.exe
73-
release/*.dmg
74-
release/*.AppImage
75-
retention-days: 7
78+
release/**/*.dmg
79+
release/**/*.zip
80+
if-no-files-found: warn

.github/workflows/release.yml

Lines changed: 102 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,51 @@ permissions:
99
contents: write
1010

1111
jobs:
12-
release:
13-
name: Build & Release
14-
strategy:
15-
fail-fast: false
16-
matrix:
17-
include:
18-
- os: windows-latest
19-
artifact: '*.exe'
20-
- os: macos-latest
21-
artifact: '*.dmg'
22-
runs-on: ${{ matrix.os }}
12+
release-windows:
13+
runs-on: windows-latest
14+
env:
15+
CSC_LINK: ${{ secrets.CSC_LINK }}
16+
CSC_KEY_PASSWORD: ${{ secrets.CSC_KEY_PASSWORD }}
2317
steps:
2418
- uses: actions/checkout@v4
19+
with:
20+
fetch-depth: 0
21+
- uses: pnpm/action-setup@v4
22+
with:
23+
version: 9
24+
- uses: actions/setup-node@v4
25+
with:
26+
node-version: 22
27+
cache: pnpm
28+
- run: pnpm install --frozen-lockfile
29+
- run: pnpm run build
30+
- run: pnpm run package
31+
- name: Generate checksums
32+
shell: pwsh
33+
run: |
34+
Get-ChildItem -Path release -Recurse -Include *.exe | ForEach-Object {
35+
$hash = (Get-FileHash $_.FullName -Algorithm SHA256).Hash.ToLower()
36+
"$hash $($_.Name)" | Out-File -Append -FilePath release/checksums-windows.txt
37+
}
38+
- uses: actions/upload-artifact@v4
39+
with:
40+
name: windows-release
41+
path: |
42+
release/**/*.exe
43+
release/checksums-windows.txt
44+
45+
release-macos:
46+
runs-on: macos-latest
47+
env:
48+
CSC_LINK: ${{ secrets.CSC_LINK }}
49+
CSC_KEY_PASSWORD: ${{ secrets.CSC_KEY_PASSWORD }}
50+
APPLE_ID: ${{ secrets.APPLE_ID }}
51+
APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}
52+
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
53+
steps:
54+
- uses: actions/checkout@v4
55+
with:
56+
fetch-depth: 0
2557
- uses: pnpm/action-setup@v4
2658
with:
2759
version: 9
@@ -30,20 +62,66 @@ jobs:
3062
node-version: 22
3163
cache: pnpm
3264
- run: pnpm install --frozen-lockfile
33-
- run: pnpm run typecheck
34-
- run: pnpm run pretest
35-
- run: pnpm run test
3665
- run: pnpm run build
37-
- name: Package
38-
run: pnpm run package
39-
env:
40-
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
41-
- name: Upload release assets
66+
- name: Package with optional notarization
67+
run: |
68+
if [ -n "$APPLE_ID" ] && [ -n "$APPLE_APP_SPECIFIC_PASSWORD" ] && [ -n "$APPLE_TEAM_ID" ]; then
69+
echo "Notarization secrets found, enabling notarize"
70+
npx json -I -f electron-builder.json -e 'this.mac.notarize=true'
71+
fi
72+
pnpm run package
73+
- name: Generate checksums
74+
run: |
75+
cd release
76+
find . -name "*.dmg" -o -name "*.zip" | while read f; do
77+
shasum -a 256 "$f" >> checksums-macos.txt
78+
done
79+
- uses: actions/upload-artifact@v4
80+
with:
81+
name: macos-release
82+
path: |
83+
release/**/*.dmg
84+
release/**/*.zip
85+
release/checksums-macos.txt
86+
87+
publish:
88+
runs-on: ubuntu-latest
89+
needs: [release-windows, release-macos]
90+
steps:
91+
- uses: actions/checkout@v4
92+
with:
93+
fetch-depth: 0
94+
- uses: actions/download-artifact@v4
95+
with:
96+
name: windows-release
97+
path: artifacts/windows
98+
- uses: actions/download-artifact@v4
99+
with:
100+
name: macos-release
101+
path: artifacts/macos
102+
- name: Generate changelog
103+
id: changelog
104+
run: |
105+
PREV_TAG=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || git rev-list --max-parents=0 HEAD)
106+
echo "## Changes" > changelog.md
107+
echo "" >> changelog.md
108+
git log --pretty=format:"- %s (%h)" "$PREV_TAG"..HEAD >> changelog.md
109+
echo "" >> changelog.md
110+
echo "" >> changelog.md
111+
echo "## Checksums" >> changelog.md
112+
echo '```' >> changelog.md
113+
cat artifacts/windows/checksums-windows.txt 2>/dev/null >> changelog.md || true
114+
cat artifacts/macos/checksums-macos.txt 2>/dev/null >> changelog.md || true
115+
echo '```' >> changelog.md
116+
- name: Create GitHub Release
42117
uses: softprops/action-gh-release@v2
43118
with:
119+
body_path: changelog.md
120+
draft: false
121+
prerelease: ${{ contains(github.ref, '-beta') || contains(github.ref, '-alpha') || contains(github.ref, '-rc') }}
44122
files: |
45-
release/*.exe
46-
release/*.dmg
47-
release/*.AppImage
48-
draft: true
49-
generate_release_notes: true
123+
artifacts/windows/**/*.exe
124+
artifacts/macos/**/*.dmg
125+
artifacts/macos/**/*.zip
126+
artifacts/windows/checksums-windows.txt
127+
artifacts/macos/checksums-macos.txt

build/README.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Build Configuration
2+
3+
## Code Signing (Optional)
4+
5+
### Windows
6+
Set `CSC_LINK` to the path/base64 of your .pfx certificate and `CSC_KEY_PASSWORD` to the password.
7+
8+
### macOS
9+
Set `CSC_LINK` to the path/base64 of your .p12 certificate, `CSC_KEY_PASSWORD`, and for notarization: `APPLE_ID`, `APPLE_APP_SPECIFIC_PASSWORD`, `APPLE_TEAM_ID`.
10+
11+
### GitHub Actions
12+
Add these as repository secrets. The release workflow will use them automatically.
13+
Without signing secrets, builds are unsigned (fine for development).

build/entitlements.mac.plist

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+
<plist version="1.0">
4+
<dict>
5+
<key>com.apple.security.cs.allow-jit</key>
6+
<true/>
7+
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
8+
<true/>
9+
<key>com.apple.security.cs.allow-dyld-environment-variables</key>
10+
<true/>
11+
<key>com.apple.security.network.client</key>
12+
<true/>
13+
<key>com.apple.security.files.user-selected.read-write</key>
14+
<true/>
15+
</dict>
16+
</plist>

electron-builder.json

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"productName": "DAEMON",
55
"asar": true,
66
"directories": {
7-
"output": "release"
7+
"output": "release/${version}"
88
},
99
"files": [
1010
"dist-electron",
@@ -13,13 +13,24 @@
1313
],
1414
"asarUnpack": [
1515
"node_modules/better-sqlite3/**",
16-
"node_modules/node-pty/**",
17-
"node_modules/node-pty/build/**"
16+
"node_modules/node-pty/**"
17+
],
18+
"publish": [
19+
{
20+
"provider": "github",
21+
"owner": "nullxnothing",
22+
"repo": "daemon"
23+
}
1824
],
1925
"mac": {
20-
"target": "dmg",
26+
"target": ["dmg", "zip"],
2127
"category": "public.app-category.developer-tools",
22-
"artifactName": "${productName}_${version}.${ext}"
28+
"artifactName": "${productName}-${version}-${arch}.${ext}",
29+
"hardenedRuntime": true,
30+
"gatekeeperAssess": false,
31+
"entitlements": "build/entitlements.mac.plist",
32+
"entitlementsInherit": "build/entitlements.mac.plist",
33+
"notarize": false
2334
},
2435
"win": {
2536
"target": [
@@ -28,12 +39,20 @@
2839
"arch": ["x64"]
2940
}
3041
],
31-
"artifactName": "${productName}_${version}.${ext}"
42+
"artifactName": "${productName}-${version}-setup.${ext}",
43+
"signingHashAlgorithms": ["sha256"]
3244
},
3345
"nsis": {
3446
"oneClick": false,
3547
"perMachine": false,
3648
"allowToChangeInstallationDirectory": true,
37-
"deleteAppDataOnUninstall": false
49+
"deleteAppDataOnUninstall": false,
50+
"createDesktopShortcut": true,
51+
"createStartMenuShortcut": true
52+
},
53+
"linux": {
54+
"target": ["AppImage"],
55+
"category": "Development",
56+
"artifactName": "${productName}-${version}.${ext}"
3857
}
3958
}

electron/config/constants.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,6 @@ export const API_ENDPOINTS = {
3535
GOOGLE_OAUTH_TOKEN: 'https://oauth2.googleapis.com/token',
3636
GOOGLE_OAUTH_AUTH: 'https://accounts.google.com/o/oauth2/v2/auth',
3737
GMAIL_API_BASE: 'https://gmail.googleapis.com/gmail/v1/users/me',
38+
VERCEL_API: 'https://api.vercel.com',
39+
RAILWAY_API: 'https://backboard.railway.com/graphql/v2',
3840
} as const

electron/db/db.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import Database from 'better-sqlite3'
22
import path from 'node:path'
3+
import fs from 'node:fs'
34
import { app } from 'electron'
45
import { runMigrations } from './migrations'
56

@@ -15,13 +16,27 @@ export function getDb(): Database.Database {
1516
_db.pragma('foreign_keys = ON')
1617
_db.pragma('busy_timeout = 5000')
1718

19+
// Integrity check before migrations — detect corruption early
20+
const integrity = _db.pragma('integrity_check') as Array<{ integrity_check: string }>
21+
if (integrity[0]?.integrity_check !== 'ok') {
22+
const backupPath = dbPath + '.corrupted.' + Date.now()
23+
fs.copyFileSync(dbPath, backupPath)
24+
_db.close()
25+
_db = null
26+
fs.unlinkSync(dbPath)
27+
throw new Error(`Database corruption detected. Backup saved to ${backupPath}. Restarting with fresh database.`)
28+
}
29+
1830
runMigrations(_db)
1931

2032
return _db
2133
}
2234

2335
export function closeDb() {
2436
if (_db) {
37+
try {
38+
_db.pragma('wal_checkpoint(TRUNCATE)')
39+
} catch { /* checkpoint is best-effort */ }
2540
_db.close()
2641
_db = null
2742
}

electron/db/migrations.ts

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type Database from 'better-sqlite3'
2-
import { SCHEMA_V1, SCHEMA_V2, SCHEMA_V3, SCHEMA_V4, SCHEMA_V5, SCHEMA_V6, SCHEMA_V7, SCHEMA_V8, SCHEMA_V9 } from './schema'
2+
import { SCHEMA_V1, SCHEMA_V2, SCHEMA_V3, SCHEMA_V4, SCHEMA_V5, SCHEMA_V6, SCHEMA_V7, SCHEMA_V8, SCHEMA_V9, SCHEMA_V10, SCHEMA_V11, SCHEMA_V12 } from './schema'
33

44
export function runMigrations(db: Database.Database) {
55
db.exec(`
@@ -90,6 +90,30 @@ export function runMigrations(db: Database.Database) {
9090
})()
9191
}
9292

93+
if (currentVersion < 10) {
94+
db.transaction(() => {
95+
const stmts = SCHEMA_V10.split(';').map((s) => s.trim()).filter(Boolean)
96+
for (const stmt of stmts) {
97+
try { db.exec(stmt) } catch { /* column/index may already exist */ }
98+
}
99+
db.prepare('INSERT INTO _migrations (version) VALUES (?)').run(10)
100+
})()
101+
}
102+
103+
if (currentVersion < 11) {
104+
db.transaction(() => {
105+
db.exec(SCHEMA_V11)
106+
db.prepare('INSERT INTO _migrations (version) VALUES (?)').run(11)
107+
})()
108+
}
109+
110+
if (currentVersion < 12) {
111+
db.transaction(() => {
112+
db.exec(SCHEMA_V12)
113+
db.prepare('INSERT INTO _migrations (version) VALUES (?)').run(12)
114+
})()
115+
}
116+
93117
// Ensure built-in tools exist (idempotent — handles upgrades where table exists but seed was missed)
94118
try {
95119
const hasRecovery = db.prepare("SELECT id FROM tools WHERE id = 'builtin-wallet-recovery'").get()

0 commit comments

Comments
 (0)