Scaffold prompd ai command (Phase 1)#11
Conversation
Adds the five-verb CLI surface for the on-device Prompd AI runtime: install / uninstall / start / stop / status. All verbs are wired through commander with --model and --yes flags where applicable. Only `status` is fully functional in this PR — it reads the catalog and daemon.lock, checks for a live PID, clears stale locks, and prints installed-models + running state. The other four verbs print a "Phase 1 scaffolding — not yet implemented" message with their parsed flags. Supporting lib modules at src/lib/ai/: - paths.ts: resolves ~/.prompd/ai/ and its subdirs - types.ts: ModelEntry, Catalog, DaemonLock, DaemonStatus - catalog.ts: load/save, findModel, getDefaultModel (default-first fallback) - daemon.ts: readLock, clearLock, isPidAlive, getStatus with stale-lock cleanup Tests cover catalog round-trip, default-model resolution, corrupt-file handling, not-running status, and stale-lock cleanup on dead PIDs (8 tests). See docs/PROMPD-AI-PLAN.md in prompd-app for the full plan. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c22f5a666f
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| } catch { | ||
| return false; |
There was a problem hiding this comment.
Treat EPERM as alive in PID liveness checks
isPidAlive currently maps every process.kill(pid, 0) exception to “dead”, but Node throws EPERM when a process exists but the current user cannot signal it. In that case getStatus will incorrectly clear daemon.lock and report “Not running”, which can happen when the daemon is started under a different user/context (e.g., sudo/service account) while the same home directory is reused.
Useful? React with 👍 / 👎.
| if (!raw || raw.version !== 1 || !Array.isArray(raw.models)) { | ||
| return { version: 1, models: [] }; | ||
| } | ||
| return raw as Catalog; |
There was a problem hiding this comment.
Validate model entries before accepting catalog JSON
loadCatalog only checks that models is an array, so partially corrupt data like {"version":1,"models":[null]} is treated as valid. The ai status renderer then dereferences each entry (m.isDefault / m.name) and crashes on null entries, which breaks the intended “graceful handling” path for corrupted catalog files.
Useful? React with 👍 / 👎.
Summary
First PR in the Prompd AI local-runtime workstream. Wires up the
prompd aicommand with all five verbs (install / uninstall / start / stop / status) plus supporting lib modules, but only implements the non-destructive read path.What's in this PR
New command: typescript/src/commands/ai.ts — top-level
aiwith five subcommands, flag parsing (--model,-y/--yes) wired up via commander.New lib modules at typescript/src/lib/ai/:
paths.ts— resolves~/.prompd/ai/and subdirstypes.ts—ModelEntry,Catalog,DaemonLock,DaemonStatuscatalog.ts— load/save,findModel,getDefaultModel(explicit-default → first-installed fallback)daemon.ts—readLock,clearLock,isPidAlive,getStatuswith stale-lock cleanupBehavior in this PR:
prompd ai --help— clean output, all 5 verbs listedprompd ai status— fully functional; reads catalog + lock file, clears stale locks, prints running state and installed-models listprompd ai install / uninstall / start / stop— print "Phase 1 scaffolding — not yet implemented" with their parsed flags echoed backTests: 8 new tests covering catalog round-trip, default-model resolution, corrupt-file handling, not-running status, and stale-lock cleanup on dead PIDs. Full suite passes (21 suites, 339 pass, 5 skipped).
Why this shape
Small, reviewable PR. Commits the command surface (names, flags, help text) and proves the plumbing without making the big llama-server bundling decision. Follow-ups will fill in
install(downloader + manifest),start(llama-server spawn + lock write), etc.Why
prompd aiChosen in Prompd/prompd-app#46. The AIDEN / AI Fox codenames were dropped — Aiden-space is crowded in the AI-assistant market and
prompd aiis intuitive in--helpoutput + trademark-collision-proof.Plan
Full plan in prompd-app/docs/PROMPD-AI-PLAN.md.
Test plan
npm run buildsucceedsnpx jestpasses (21 suites, 339 tests)node ./bin/prompd.js ai --helprenders cleanlynode ./bin/prompd.js ai statusreports "Not running" and "(none)" on a fresh machinenode ./bin/prompd.js ai install --model gemma-4-e4b-q4 -yechoes the parsed flagsGenerated with Claude Code