feat: land native mobile foundation
This commit is contained in:
@@ -9,6 +9,7 @@ build/
|
||||
.next/
|
||||
coverage/
|
||||
*.tsbuildinfo
|
||||
.gradle-user/
|
||||
|
||||
# env/secrets
|
||||
.env
|
||||
@@ -25,6 +26,9 @@ uploads/
|
||||
*.db-wal
|
||||
logs/
|
||||
|
||||
# local agent/audit workspace
|
||||
.dev/
|
||||
|
||||
# OS/editor
|
||||
.DS_Store
|
||||
.vscode/
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
# Changelog
|
||||
|
||||
All notable Hermes Mobile source changes are recorded here. Entries are added during the same work loop as their implementation; release artifacts are only listed after source commit, checks, and APK upload are verified.
|
||||
|
||||
## Unreleased
|
||||
|
||||
### Added
|
||||
- Added native Android chat, workspace, settings, local defaults, companion health, and file editing surfaces for the beta client.
|
||||
- Added `PROJECT_PLAN.md` as the project-controlled milestone plan.
|
||||
|
||||
### Changed
|
||||
- Updated companion `/api/chat` to call `hermes chat -Q --source tool -q <prompt>`, sanitize CLI banners/help/control output, truncate large mobile replies, and return structured failures.
|
||||
- Reconciled `docs/ROADMAP.md` to the current native Android beta state.
|
||||
- Ignored `.gradle-user/` and `.dev/` alongside existing generated build artifacts.
|
||||
|
||||
### Fixed
|
||||
- Fixed companion/mobile lint issues from missing Node globals and an unused React settings value.
|
||||
|
||||
### Verification
|
||||
- `git diff --check` — passed
|
||||
- `npm run typecheck --workspace @hermes-mobile/companion` — passed
|
||||
- `npm run lint --workspace @hermes-mobile/companion` — passed
|
||||
- `npm run build --workspace @hermes-mobile/companion` — passed
|
||||
- `npm run typecheck` — passed
|
||||
- `npm run lint` — passed
|
||||
- `npm run build` — passed
|
||||
- `GRADLE_USER_HOME=/root/hermes-mobile/.gradle-user ./gradlew :app:assembleDebug` from `apps/mobile/android` — blocked before compilation: network socket creation is not permitted while downloading Gradle 8.11.1
|
||||
|
||||
## Release history
|
||||
|
||||
_No versioned APK releases yet._
|
||||
|
||||
## Entry format
|
||||
|
||||
```markdown
|
||||
## [v0.1.0-beta.1] - YYYY-MM-DD
|
||||
|
||||
### Added
|
||||
- Concise user-visible change.
|
||||
|
||||
### Changed
|
||||
- Concise refinement or architectural change.
|
||||
|
||||
### Fixed
|
||||
- Concise defect fix.
|
||||
|
||||
### Verification
|
||||
- `command` — passed
|
||||
|
||||
### APK
|
||||
- `hermes-mobile-v0.1.0-beta.1.apk` — Telegram release topic message <id>
|
||||
```
|
||||
+113
@@ -0,0 +1,113 @@
|
||||
# Hermes Mobile — Delivery Plan
|
||||
|
||||
> **Operational contract:** Codex must read this file before each work loop. Work exactly one coherent milestone at a time. Move completed items to the completed section in the same commit that implements them. Add a concise entry to `CHANGELOG.md` in the same commit. Never mark work complete without running its listed verification.
|
||||
|
||||
## Product guardrails
|
||||
|
||||
- Native Android client for upstream Hermes Agent: **Kotlin + Jetpack Compose**.
|
||||
- Material 3 base, deliberately customized through a reusable design system.
|
||||
- Thin client: Hermes remains the authority for auth, sessions, streaming, tool semantics, and backend behavior.
|
||||
- No WebView-first app, no cloned Hermes backend, no embedded credentials.
|
||||
- Adaptive, accessible, compact-but-readable UI: phone, tablet, light/dark, font scaling, IME/keyboard, long code/output must remain safe.
|
||||
- Keep DTO/transport, domain/UI models, repositories, view models/state, and composables separated.
|
||||
- Never commit APKs, build outputs, credentials, or generated local environment files.
|
||||
|
||||
## Release policy
|
||||
|
||||
- Start artifacts at `v0.1.0-beta.1`.
|
||||
- Patch: compatible fixes/polish. Minor: a coherent feature milestone. Major: stable `v1.0.0+` only.
|
||||
- A release requires a pushed source commit, passing relevant checks, a versioned APK artifact, and a Telegram release post.
|
||||
|
||||
---
|
||||
|
||||
## Now — finish the foundation already in progress
|
||||
|
||||
- [ ] **F1 — Compose design system extraction**
|
||||
- Extract tokens for color, spacing, typography, shape, elevation, motion, and semantic status colors.
|
||||
- Implement light/dark themes with readable contrast; eliminate default-sample styling.
|
||||
- Split oversized UI into clear design, feature, and reusable component packages.
|
||||
- Add Compose previews: small phone, normal phone, tablet width, light, dark.
|
||||
- Verification: Android compile/build plus visual preview review.
|
||||
|
||||
- [ ] **F2 — Polished fake-data chat proving ground**
|
||||
- Session rail/list, conversation screen, context controls, keyboard-safe composer, send/cancel/retry behavior.
|
||||
- Render assistant/user/system/error/streaming messages from UI models.
|
||||
- Add markdown-friendly surfaces, selectable long text, code blocks with horizontal scroll + copy, compact expandable tool results.
|
||||
- Cover empty/loading/reconnecting/error states without clipped/overlapping content.
|
||||
- Verification: focused UI tests where practical; Android debug build.
|
||||
|
||||
## Beta path — upstream-connected MVP
|
||||
|
||||
- [ ] **B1 — Transport/domain contracts**
|
||||
- Define transport DTOs and a repository interface for server profiles, authentication, sessions, messages, stream events, tool results, and artifacts.
|
||||
- Map DTOs to stable UI models; fake repository powers previews/tests.
|
||||
- Keep the existing companion as an optional adapter only; do not change upstream Hermes semantics.
|
||||
- Verification: unit tests for mapping/state reducers; build/typecheck.
|
||||
|
||||
- [ ] **B2 — Connection and authentication UX**
|
||||
- Server connection screen with validation, health, auth/session configuration, offline/unauthorized/retry states.
|
||||
- Store sensitive values using Android-appropriate secure storage; never log secrets.
|
||||
- Verification: connection-state tests and manual unhappy-path walkthrough.
|
||||
|
||||
- [ ] **B3 — Session list and durable chat state**
|
||||
- Fetch/list/search/select/create sessions through repository contracts.
|
||||
- Restore selected session and protect against duplicate sends / lost drafts.
|
||||
- Verification: fake-repository UI tests; companion/integration checks where available.
|
||||
|
||||
- [ ] **B4 — Streaming, reconnects, and resilient long-running work**
|
||||
- Stream event reducer: token deltas, tool lifecycle, final/error/cancel, reconnect/backoff.
|
||||
- Preserve partial output and make recovery obvious and safe.
|
||||
- Verification: deterministic fake stream tests and real upstream-compatible exercise.
|
||||
|
||||
- [ ] **B5 — Tool, artifact, and output experience**
|
||||
- Compact tool cards with lifecycle/status, expandable output, copy/share/save affordances.
|
||||
- Safe rendering for large logs and code; no unbounded nested scroll failures.
|
||||
- Artifact/file handoff only where upstream capability is actually supported.
|
||||
- Verification: large-output and rotation/resume checks.
|
||||
|
||||
## Beta hardening and release
|
||||
|
||||
- [ ] **R1 — Adaptive/accessibility quality pass**
|
||||
- Small phone, normal phone, tablet/two-pane behavior; portrait/landscape.
|
||||
- Font scaling, TalkBack semantics, contrast, touch targets, reduced motion, IME behavior.
|
||||
- Verification: emulator/device matrix evidence documented in `docs/ROADMAP.md`.
|
||||
|
||||
- [ ] **R2 — Beta packaging and install guide**
|
||||
- Version `v0.1.0-beta.1`, reproducible debug/beta APK build, install/run guide, known limitations.
|
||||
- Publish source commit, APK, release notes, and verification result.
|
||||
- Verification: clean install on a real device or emulator plus full required checks.
|
||||
|
||||
## V2 backlog
|
||||
|
||||
- [ ] Multiple server profiles and fast switching.
|
||||
- [ ] Rich file/artifact workflows based on upstream capability.
|
||||
- [ ] Notifications for task completion.
|
||||
- [ ] Mature tablet/two-pane session + optional terminal/log pane.
|
||||
- [ ] Offline cache/search and diagnostic export with privacy controls.
|
||||
|
||||
---
|
||||
|
||||
## Completed
|
||||
|
||||
_Move finished items here with date, commit, and verification. Keep this section factual; do not claim unverified work._
|
||||
|
||||
- [x] **F0 — Audit and safely land existing work** — 2026-07-24, commit `da79d48` (`feat: land native mobile foundation`).
|
||||
- Reviewed existing Android and companion edits; preserved the native Android chat/workspace/settings work and companion chat hardening.
|
||||
- Confirmed generated build outputs are ignored and added ignores for `.gradle-user/` and `.dev/`.
|
||||
- Reconciled `docs/ROADMAP.md` to the actual native Android beta state and remaining validation gaps.
|
||||
- Verification: `git diff --check` passed; `npm run typecheck --workspace @hermes-mobile/companion` passed; `npm run lint --workspace @hermes-mobile/companion` passed; `npm run build --workspace @hermes-mobile/companion` passed; `npm run typecheck` passed; `npm run lint` passed; `npm run build` passed.
|
||||
- Android debug build attempted with `GRADLE_USER_HOME=/root/hermes-mobile/.gradle-user ./gradlew :app:assembleDebug` from `apps/mobile/android`; blocked before compilation because network socket creation is not permitted while downloading Gradle 8.11.1.
|
||||
|
||||
## Work-loop checklist
|
||||
|
||||
Before coding:
|
||||
1. Read `PROJECT_PLAN.md`, `CHANGELOG.md`, `docs/ROADMAP.md`, git status, and the prior commit.
|
||||
2. Choose the single highest-value unchecked item or a narrowly scoped sub-item.
|
||||
3. Inspect existing implementation before rewriting it.
|
||||
|
||||
Before committing:
|
||||
1. Run relevant checks; record exact pass/fail scope in the changelog.
|
||||
2. Update this plan: check the completed item, move it into **Completed**, and leave the next executable item unchecked.
|
||||
3. Add a concise `CHANGELOG.md` entry under **Unreleased**.
|
||||
4. Commit using Conventional Commits and push `origin/main`.
|
||||
5. Do not claim a release without an uploaded, verified versioned APK.
|
||||
@@ -1,3 +1,4 @@
|
||||
import { Buffer } from 'node:buffer';
|
||||
import { timingSafeEqual } from 'node:crypto';
|
||||
import type { FastifyInstance, FastifyRequest } from 'fastify';
|
||||
import { authValidateResponseSchema } from '@hermes-mobile/shared';
|
||||
|
||||
@@ -5,33 +5,123 @@ import { toSafeAbsolutePath } from '../config/paths.js';
|
||||
import { getHermesHealth } from '../system/hermesHealth.js';
|
||||
import { runProcess } from '../system/processes.js';
|
||||
|
||||
const ansiPattern = new RegExp(`${String.fromCharCode(27)}\\[[;?0-9]*[ -/]*[@-~]`, 'g');
|
||||
|
||||
export async function registerChatRoutes(app: FastifyInstance, config: CompanionConfig): Promise<void> {
|
||||
app.post('/api/chat', async (request, reply) => {
|
||||
const body = chatRequestSchema.parse(request.body);
|
||||
const body = chatRequestSchema.safeParse(request.body);
|
||||
if (!body.success) {
|
||||
return reply.code(400).send(
|
||||
chatResponseSchema.parse({
|
||||
reply: 'Chat prompt is required.',
|
||||
exitCode: null,
|
||||
stderr: undefined,
|
||||
hermesAvailable: false,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
const hermesHealth = await getHermesHealth();
|
||||
|
||||
if (!hermesHealth.cliAvailable) {
|
||||
return chatResponseSchema.parse({
|
||||
return reply.send(
|
||||
chatResponseSchema.parse({
|
||||
reply: 'Hermes CLI was not found on this machine. Install Hermes or make sure `hermes` is on PATH, then retry.',
|
||||
exitCode: null,
|
||||
stderr: undefined,
|
||||
hermesAvailable: false,
|
||||
});
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
const result = await runProcess(hermesHealth.cliPath ?? 'hermes', [], {
|
||||
const result = await runProcess(hermesHealth.cliPath ?? 'hermes', ['chat', '-Q', '--source', 'tool', '-q', body.data.prompt], {
|
||||
cwd: toSafeAbsolutePath(config.workspaceRoot),
|
||||
timeoutMs: 30000,
|
||||
input: body.prompt,
|
||||
timeoutMs: 120000,
|
||||
});
|
||||
|
||||
return reply.code(result.exitCode === 0 || result.exitCode === null ? 200 : 502).send(
|
||||
const cleanStdout = sanitizeHermesOutput(result.stdout);
|
||||
const cleanStderr = sanitizeHermesOutput(result.stderr);
|
||||
const openedHelp = looksLikeTopLevelHermesHelp(result.stdout) || looksLikeTopLevelHermesHelp(result.stderr);
|
||||
const spawnFailed = result.exitCode === null && cleanStderr.length > 0 && cleanStdout.length === 0;
|
||||
const failed = result.timedOut || openedHelp || spawnFailed || (result.exitCode !== 0 && result.exitCode !== null);
|
||||
const fallback = openedHelp
|
||||
? 'Hermes opened its CLI help instead of running the prompt. Restart the companion server so it uses the updated chat command.'
|
||||
: failed
|
||||
? `Hermes did not finish successfully${result.exitCode === null ? '' : ` (exit ${result.exitCode})`}.${result.timedOut ? ' The request timed out.' : ''}`
|
||||
: 'Hermes finished without output.';
|
||||
const responseText = (openedHelp ? '' : cleanStdout) || (openedHelp ? '' : cleanStderr) || fallback;
|
||||
|
||||
return reply.code(failed ? (result.timedOut ? 504 : 502) : 200).send(
|
||||
chatResponseSchema.parse({
|
||||
reply: result.stdout.trim() || result.stderr.trim() || 'Hermes finished without output.',
|
||||
reply: truncateForMobile(responseText),
|
||||
exitCode: result.exitCode,
|
||||
stderr: result.stderr || undefined,
|
||||
stderr: cleanStderr ? truncateForMobile(cleanStderr) : undefined,
|
||||
hermesAvailable: true,
|
||||
}),
|
||||
);
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : 'Chat request failed.';
|
||||
return reply.send(
|
||||
chatResponseSchema.parse({
|
||||
reply: sanitizeHermesOutput(message) || 'Chat request failed.',
|
||||
exitCode: null,
|
||||
stderr: undefined,
|
||||
hermesAvailable: true,
|
||||
}),
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function sanitizeHermesOutput(text: string): string {
|
||||
return text
|
||||
.replace(ansiPattern, '')
|
||||
.replace(/\r/g, '')
|
||||
.split('\n')
|
||||
.filter((line) => !isBannerOrHelpLine(line))
|
||||
.join('\n')
|
||||
.replace(/\n{3,}/g, '\n\n')
|
||||
.trim();
|
||||
}
|
||||
|
||||
function isBannerOrHelpLine(line: string): boolean {
|
||||
const trimmed = line.trim();
|
||||
if (!trimmed) return false;
|
||||
if (/session_id\s*:/i.test(trimmed)) return true;
|
||||
if (/[\u2500-\u257F]/u.test(trimmed)) return true;
|
||||
if (/^[+\-_|/\\()[\]{}<>\s*]+$/.test(trimmed) && trimmed.length > 8) return true;
|
||||
if (/^(usage:|positional arguments:|options:|examples:|for more help on a command:|hermes <command> --help)/i.test(trimmed)) return true;
|
||||
if (/^\{chat,model,gateway,setup,whatsapp,login,logout,auth,status,cron,webhook,doctor,config,pairing,skills,plugins,honcho,tools,mcp,sessions,insights,claw,version,update,uninstall,acp,profile,completion\}/i.test(trimmed)) return true;
|
||||
if (/^(chat|model|gateway|setup|whatsapp|login|logout|auth|status|cron|webhook|doctor|config|pairing|skills|plugins|honcho|tools|mcp|sessions|insights|claw|version|update|uninstall|acp|profile|completion)\s{2,}/i.test(trimmed)) return true;
|
||||
if (/^hermes\s+(chat|setup|gateway|status|doctor|model|config|sessions|update|uninstall)\b/i.test(trimmed)) return true;
|
||||
if (/^(Hermes|⚕ Hermes)\b.*(Agent|CLI|v?\d)/i.test(trimmed)) return true;
|
||||
if (/^Hermes Agent - AI assistant with tool-calling capabilities$/i.test(trimmed)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
function looksLikeTopLevelHermesHelp(text: string): boolean {
|
||||
const clean = text.replace(ansiPattern, '');
|
||||
return /usage:\s+hermes\b/i.test(clean) && /Hermes Agent - AI assistant with tool-calling capabilities/i.test(clean);
|
||||
}
|
||||
|
||||
function selfCheckSanitizer(): void {
|
||||
const sample = [
|
||||
'\u001B[36m╭─ ⚕ Hermes v1.2.3 ─╮\u001B[0m',
|
||||
'│ session_id: abc123 │',
|
||||
'╰────────────────────╯',
|
||||
'',
|
||||
'Final answer line.',
|
||||
].join('\n');
|
||||
if (sanitizeHermesOutput(sample) !== 'Final answer line.') {
|
||||
throw new Error('Hermes output sanitizer self-check failed.');
|
||||
}
|
||||
}
|
||||
|
||||
selfCheckSanitizer();
|
||||
|
||||
function truncateForMobile(text: string): string {
|
||||
const maxChars = 24000;
|
||||
if (text.length <= maxChars) return text;
|
||||
return `${text.slice(0, maxChars)}\n\n[Output truncated]`;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { Buffer } from 'node:buffer';
|
||||
import { mkdir, readFile, readdir, stat, writeFile } from 'node:fs/promises';
|
||||
import { basename, dirname, join } from 'node:path';
|
||||
import type { FastifyInstance } from 'fastify';
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { spawn } from 'node:child_process';
|
||||
import { clearTimeout, setTimeout } from 'node:timers';
|
||||
|
||||
export type RunProcessResult = {
|
||||
stdout: string;
|
||||
|
||||
+815
-215
File diff suppressed because it is too large
Load Diff
@@ -4,7 +4,7 @@ import { useCompanion } from '../../api/CompanionContext.js';
|
||||
import { CompanionClient, DEFAULT_COMPANION_URL } from '../../api/companionClient.js';
|
||||
|
||||
export function SettingsScreen() {
|
||||
const { client, settings, updateSettings } = useCompanion();
|
||||
const { settings, updateSettings } = useCompanion();
|
||||
const [baseUrl, setBaseUrl] = useState(settings.baseUrl);
|
||||
const [accessKey, setAccessKey] = useState(settings.accessKey);
|
||||
const [status, setStatus] = useState('Run companion setup, paste the access key, then test the connection.');
|
||||
|
||||
+28
-130
@@ -1,136 +1,34 @@
|
||||
# Roadmap
|
||||
# Hermes Mobile Beta Roadmap
|
||||
|
||||
## Phase 0 — Planning Scaffold
|
||||
## Current Milestone: Native Android Beta Chat and Connection UX
|
||||
|
||||
Status: completed.
|
||||
Status: in progress, close to beta validation. F0 source landing is complete; Android debug build validation remains environment-blocked.
|
||||
|
||||
Deliverables:
|
||||
- Repo created
|
||||
- Product plan
|
||||
- Architecture plan
|
||||
- Design direction
|
||||
- Install strategy
|
||||
- Project structure
|
||||
Done:
|
||||
- Native Kotlin/Compose Android shell replaces the web-first mobile path for the beta surface.
|
||||
- Companion settings flow stores companion URL and access key locally, validates bearer auth, and surfaces health errors in-app.
|
||||
- Chat UI supports conversation list/thread navigation, native composer, busy state, selectable replies, error bubbles, and new-chat reset.
|
||||
- Companion `/api/chat` invokes Hermes through the CLI with `hermes chat -Q --source tool -q <prompt>`.
|
||||
- Companion chat responses sanitize terminal banners/help/control output, truncate large replies for mobile, report CLI availability, and return structured failure responses.
|
||||
- Workspace utilities remain native: command runner, health view, file browsing, read, and write.
|
||||
- Local build artifacts, Android transient build output, `.gradle-user/`, and `.dev/` are ignored.
|
||||
- Companion and workspace TypeScript typecheck, build, and lint pass as of 2026-07-24.
|
||||
|
||||
## Phase 1 — Skeleton
|
||||
Remaining for beta:
|
||||
- Validate Android debug build in an environment where Gradle can fetch or reuse the Gradle 8.11.1 distribution. On 2026-07-24, `GRADLE_USER_HOME=/root/hermes-mobile/.gradle-user ./gradlew :app:assembleDebug` failed before compilation because network socket creation is blocked while downloading `https://services.gradle.org/distributions/gradle-8.11.1-all.zip`.
|
||||
- Exercise a real paired device against a running companion and authenticated Hermes CLI.
|
||||
- Exercise upstream-compatible transport/auth/session/streaming behavior end to end: bearer auth, health, chat request/response, session continuity expectations, streamed/final output handling, and failure recovery.
|
||||
- Add or run focused Android UI validation for chat/settings flows on small and large screens.
|
||||
- Confirm adaptive accessibility: font scaling, TalkBack labels, contrast, keyboard/IME behavior, and reduced-motion tolerance.
|
||||
- Document beta install/run steps after the native build is verified.
|
||||
|
||||
Goal: empty but runnable monorepo.
|
||||
## Beta Release Criteria
|
||||
|
||||
Status: in progress.
|
||||
|
||||
Deliverables:
|
||||
- pnpm workspace
|
||||
- `apps/mobile` Vite React app with Capacitor Android target and PWA fallback
|
||||
- `apps/companion` Fastify server
|
||||
- shared TypeScript package for event/API schemas
|
||||
- basic app shell with bottom nav
|
||||
- `/api/health`
|
||||
- local dev scripts
|
||||
|
||||
## Phase 2 — Basic Hermes Prompting
|
||||
|
||||
Goal: phone can send text prompt and receive final answer.
|
||||
|
||||
Deliverables:
|
||||
- pairing/auth MVP
|
||||
- Settings connect flow
|
||||
- task creation endpoint
|
||||
- Hermes CLI/API adapter MVP
|
||||
- Ask screen sends prompt
|
||||
- response display
|
||||
- task history in SQLite
|
||||
|
||||
## Phase 3 — Realtime Activity + Tool Timeline
|
||||
|
||||
Goal: see Hermes work live.
|
||||
|
||||
Deliverables:
|
||||
- event bus
|
||||
- WebSocket/SSE stream
|
||||
- tool timeline UI
|
||||
- Python worker adapter using AIAgent callbacks if needed
|
||||
- coarse/fine tool event mapping
|
||||
|
||||
## Phase 4 — Uploads + Voice
|
||||
|
||||
Goal: prompt with files and voice notes.
|
||||
|
||||
Deliverables:
|
||||
- multipart upload endpoint
|
||||
- upload tray UI
|
||||
- image/archive/pdf metadata
|
||||
- voice recorder UI
|
||||
- local STT or Hermes STT bridge
|
||||
- attach files to task prompt
|
||||
|
||||
## Phase 5 — Notifications
|
||||
|
||||
Goal: close phone and get told when done.
|
||||
|
||||
Deliverables:
|
||||
- Native Android push path or ntfy/Web Push fallback
|
||||
- PWA service worker fallback
|
||||
- notification provider abstraction
|
||||
- notification permission onboarding
|
||||
- completion/failure/approval notifications
|
||||
|
||||
## Phase 6 — Cron + Approvals
|
||||
|
||||
Goal: mobile control plane.
|
||||
|
||||
Deliverables:
|
||||
- cron list/run/pause/resume/remove
|
||||
- cron output viewer
|
||||
- approval queue UI
|
||||
- companion approval API
|
||||
- Hermes approval integration strategy
|
||||
|
||||
## Phase 7 — Installer + Release
|
||||
|
||||
Goal: one-liner install.
|
||||
|
||||
Deliverables:
|
||||
- production build
|
||||
- install.sh
|
||||
- systemd service
|
||||
- update/uninstall modes
|
||||
- release artifact
|
||||
- pairing URL output
|
||||
|
||||
## Phase 8 — Android Polish
|
||||
|
||||
Goal: feels native.
|
||||
|
||||
Deliverables:
|
||||
- refined Happy-inspired UI
|
||||
- animations/microinteractions
|
||||
- Capacitor Android build pipeline
|
||||
- adaptive icons/splash
|
||||
- native status/navigation bars
|
||||
- share target
|
||||
- haptics
|
||||
- offline shell polish
|
||||
- APK release/signing flow
|
||||
|
||||
## Phase 9 — Deep Hermes Integration
|
||||
|
||||
Goal: full Hermes-native experience.
|
||||
|
||||
Deliverables:
|
||||
- structured event stream from Hermes core or stable Python adapter
|
||||
- richer session browsing
|
||||
- generated file detection
|
||||
- background process control
|
||||
- subagent visualization
|
||||
- memory/skills dashboards possibly
|
||||
|
||||
## Open Feature Ideas
|
||||
|
||||
- Quick action tiles: “Check homelab”, “Run DV status”, “Start coding task”.
|
||||
- Voice-to-voice mode.
|
||||
- Per-task model/toolset selection.
|
||||
- “Watch mode” for long-running coding tasks.
|
||||
- Home Assistant widgets/actions.
|
||||
- Secure notification actions: approve/deny from notification.
|
||||
- Android native share target.
|
||||
- QR pairing from terminal output.
|
||||
- Native Kotlin/Compose Android app is the shipped beta client.
|
||||
- No WebView, Capacitor runtime dependency, fake backend, embedded secrets, or new external infrastructure is introduced for beta.
|
||||
- Companion transport and auth are upstream-compatible and exercised against the real Hermes CLI.
|
||||
- Chat/session/streaming behavior is exercised with Hermes, including success, CLI unavailable, timeout, non-zero exit, and malformed response cases.
|
||||
- Settings connection flow is reliable: save, validate, health, Hermes test, offline/unauthorized states, and recovery are clear.
|
||||
- Adaptive accessibility passes on target Android devices or emulators.
|
||||
- Required checks pass: `./gradlew :app:assembleDebug` from `apps/mobile/android`, companion typecheck/build, and relevant lint.
|
||||
- Release notes clearly list remaining known beta limitations.
|
||||
|
||||
@@ -28,4 +28,17 @@ export default [
|
||||
...tseslint.configs.recommended.rules,
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['apps/mobile/src/**/*.{ts,tsx}'],
|
||||
languageOptions: {
|
||||
globals: {
|
||||
document: 'readonly',
|
||||
fetch: 'readonly',
|
||||
HTMLFormElement: 'readonly',
|
||||
localStorage: 'readonly',
|
||||
RequestInit: 'readonly',
|
||||
URL: 'readonly',
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
Reference in New Issue
Block a user