feat: /dispatch setup — first-run wizard, deployment pointer, and detection (issue #92) - #93
Merged
Merged
Conversation
…ource of truth (issue #92) materialize.mjs imported nothing and kept a keep-in-sync copy; the admin's setup wizard is about to become a third reader. A traversal-choke charset duplicated three ways drifts exactly where it must not — one export, two imports, one vector-pin test. Signed-off-by: Rob Boerman <robboerman@live.nl>
… elsewhere (issue #92) INT-DEPLOYMENT-POINTER-CONTRACT: <agent dir>/pi-dispatch-deployment.json (override PI_DISPATCH_DEPLOYMENT_FILE), an allowlisted absolute-paths-only env map layered UNDER the operator's env once at extension load. Env wins key by key; the worker and receiver never read it; PI_DISPATCH_RUN_ROOTS and credential-shaped keys in the file have no effect by construction -- the pointer resolves paths, never grants capabilities. A broken or newer file degrades to exactly the pre-pointer behavior with a one-line surfaced notice, never a throw (the recorded reconciliation of fail-loud-on-newer with the read-model's never-throw doctrine). Reapply (post-wizard-write) updates only keys the pointer itself set and never unsets -- a half-typed hand edit cannot yank paths from a live panel. resolvePaths stays env-only and untouched; 12 new tests, admin suite 306/306. Signed-off-by: Rob Boerman <robboerman@live.nl>
…ce-ever nudge (issue #92) - bare /dispatch now detects where the deployment is: valid pointer or explicit env -> panel exactly as before; cwd scaffold or a reachable queue -> panel plus one hint; nothing anywhere AND queue unreachable -> the offer. An exported VALKEY_URL is probed, never trusted -- a dead URL still reaches the offer, and an ops outage on a configured deployment keeps the banner, never the wizard - /dispatch setup: dialogs-first, overlay-per-handoff (the tui suspend handle exists only inside a ctx.ui.custom factory; dialogs cannot run under a capturing overlay; stdin belongs to the attached child) -- pick a deploy dir, consented npm install of @edgehero/pi-dispatch@RUNTIME_VERSION under import-pi's spawn doctrine (no path in argv, --ignore-scripts, post-install version assertion that stops the wizard loudly), hand the terminal to pi-dispatch up (its own y/N gates ARE the host-mutation consents; --yes is forwarded to nothing), optional user-level service install, pointer written with the JSON shown verbatim then reapplied in-process, provider key printed never written, optional setup github hand-off, optional first trigger for the repo the session sits in (folder pre-filled, flow picked from its .pi/skills via the shared SKILL_NAME_RE, the in-place-edit warning printed, and the ai-trigger: allow line PRINTED for the operator to commit -- the wizard never writes repo files), then the panel - session_start nudge: reason startup only, hasUI only, sync-only checks, a marker file makes it once-ever, notify-only - every step individually declinable; declines continue converge-style; headless refuses; USED_API unchanged (spawns via node:child_process) Specs: new DES-FIRST-RUN-SETUP-WIZARD (incl. the recorded rejections); REQ-ADMIN-VIA-PI-EXTENSION amended (setup, the detection tree, the nudge, declined-offer acceptance); REQ-DEPLOYMENT-BOOTSTRAP scope carve-in (the wizard is a driver, not a power); Revision History rows in design.md + requirements.md; DES-TRIGGER-OUTSIDE-PI, DES-CLI-SURFACE, CONST-BUDGET-BEFORE-TOKENS unchanged, checked. operate-pi-dispatch SKILL.md gains the setup chapter (operator-typed only; the model asks the operator to type it). README first-run story; cli/init next-steps mention the wizard. Signed-off-by: Rob Boerman <robboerman@live.nl>
birhantprkc
pushed a commit
to birhantprkc/pi-dispatch
that referenced
this pull request
Aug 6, 2026
The first-run wizard (issue edgehero#92, PRs edgehero#93 + edgehero#94): admin 0.4.0 ships /dispatch setup, the deployment pointer, the no-deployment detection, and the once-ever startup nudge. worker 0.1.1 ships the SKILL_NAME_RE export and the setup cross-references in the CLI help; RUNTIME_VERSION follows it (the anti-drift test makes the pair atomic). Both READMEs compacted. Signed-off-by: Rob Boerman <robboerman@live.nl>
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.
Closes #92. The final UX on top of the #80–#82 ladder: an operator whose only install is
pi install npm:@edgehero/pi-dispatch-admintypes/dispatchin a repo, and the console takes them from nothing to a working deployment — with a consent per action — then lands in the panel.Three commits:
1 — worker:
SKILL_NAME_REexported from flow-gateThe traversal-choke charset was duplicated in
materialize.mjswith a keep-in-sync comment, and the wizard becomes a third reader. One export, two imports, one vector-pin test.2 — the deployment pointer (
INT-DEPLOYMENT-POINTER-CONTRACT)~/.pi/agent/pi-dispatch-deployment.json(overridePI_DISPATCH_DEPLOYMENT_FILE): an allowlisted, absolute-paths-only env map layered under the operator's env once at extension load — env wins key by key, the worker/receiver never read it, andPI_DISPATCH_RUN_ROOTSor credential-shaped keys in the file have no effect by construction (a pointer that widened the AI-run allowlist would be a second, unreviewed door to a gated capability). A broken or newer file degrades to exactly the pre-pointer behavior with a one-line surfaced notice — never a throw; the contract records this as the deliberate reconciliation of fail-loud-on-newer with the read-model's never-throw doctrine.resolvePathsstays env-only and untouched. This is what makes a wizard-built deployment visible to/dispatchfrom any directory — and it replaces the README's "hand-mirror five env vars into your pi session" paragraph.3 — the wizard, detection, and the nudge
/dispatch(cheapest-first): valid pointer or explicit env ⇒ panel exactly as before; cwd scaffold quadruple or a reachable queue ⇒ panel plus one hint; nothing anywhere and the queue unreachable ⇒ the offer. An exportedVALKEY_URLis probed, never trusted — a dead URL still reaches the offer, and an ops outage on a configured deployment keeps today's banner, never a wizard prompt. Missing logs/settings dirs prove nothing (lazy OS-temp defaults) and are never consulted./dispatch setup— dialogs-first, overlay-per-handoff (pi'stuisuspend handle exists only inside actx.ui.customfactory; dialogs can't run under a capturing overlay; stdin belongs to the attached child): deploy dir (default~/pi-dispatch, never the repo) → consentednpm install @edgehero/pi-dispatch@0.1.0under import-pi's spawn doctrine (barenpm, win32npm.cmd+shell:trueonly there, no filesystem path in argv,--ignore-scripts, post-install version assertion that stops the wizard loudly) → the terminal handed topi-dispatch up, whose own y/N gates are the host-mutation consents (--yesis forwarded to nothing) → optional user-levelservice install→ the pointer written with its JSON shown verbatim, then re-applied in-process so the panel opens against it without restarting pi → provider key printed, never written → optionalsetup githubhand-off → optional first trigger for the repo the session sits in: folder pre-filled, flow picked from that repo's.pi/skills/through the sharedSKILL_NAME_RE, the in-place-edit warning printed, and theai-trigger: allowline printed for the operator to commit — the wizard never writes into a repo. Then the panel.session_startnudge:reason: "startup"only,hasUIonly, sync-only checks (no queue probe at startup), marker-file latch, notify-only.USED_APIis unchanged (spawns vianode:child_process);RUNTIME_VERSIONis pinned to the worker's version by an anti-drift test so release bumps stay atomic.Specs
New
DES-FIRST-RUN-SETUP-WIZARD(with the recorded rejections: long-lived wizard overlay, clone reuse, detached worker, credential dialogs, auto-writing the repo's opt-in — two keys stay two keys) andINT-DEPLOYMENT-POINTER-CONTRACT;REQ-ADMIN-VIA-PI-EXTENSIONamended (setup is operator-typed only — deliberately no model-callable tool; the skill's new chapter tells the model to ask the operator to type it);REQ-DEPLOYMENT-BOOTSTRAPScope carve-in (the wizard is a driver, not a power). Revision History rows in interfaces/design/requirements;DES-TRIGGER-OUTSIDE-PI(bootstraps, never hosts),DES-CLI-SURFACE,CONST-BUDGET-BEFORE-TOKENS(no wizard path spends — setup ends at the panel, not at a job) — unchanged, checked.Tests
Full suite: 1843 tests, 1827 pass, 0 fail, 16 pre-existing skips (+46 over main: 31 wizard, 12 pointer, wiring/pinned-api/flow-gate additions). Admin bundle rebuilt and smoke-loaded (both new modules inlined; factory registers
resources_discover+session_start). CI greps clean.