@edgehero/pi-dispatch 4.3.1 → 5.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +84 -3
- package/README.md +21 -7
- package/deploy/console.service +52 -0
- package/deploy/docker-compose.yml +3 -1
- package/deploy/pi-dispatch-valkey.container +4 -2
- package/deploy/sandbox-gateway.service +23 -0
- package/deploy/worker-env-wrapper.cmd +6 -0
- package/deploy/worker-env-wrapper.sh +10 -1
- package/package.json +118 -19
- package/src/agent-snapshot.mjs +49 -0
- package/src/answerer-runtime.mjs +194 -0
- package/src/answerer.mjs +178 -0
- package/src/approval-policy.mjs +76 -0
- package/src/approval-runtime.mjs +188 -0
- package/src/approval-session.mjs +137 -0
- package/src/approval-state.mjs +170 -0
- package/src/auth-cli.mjs +86 -0
- package/src/auth-connections.mjs +145 -0
- package/src/auth-policy.mjs +32 -0
- package/src/auth-store.mjs +97 -0
- package/src/azure-host.mjs +66 -4
- package/src/azure-prompt.mjs +5 -4
- package/src/backend-conformance.mjs +34 -2
- package/src/backend-local.mjs +103 -34
- package/src/backend-openshell.mjs +1540 -0
- package/src/backend-podman.mjs +63 -2
- package/src/backend-registry.mjs +61 -4
- package/src/backends.mjs +395 -6
- package/src/bullmq-internals.mjs +208 -0
- package/src/canary-cli.mjs +28 -0
- package/src/canary-lock.mjs +41 -0
- package/src/canary-runtime.mjs +237 -0
- package/src/canary.mjs +53 -0
- package/src/cancel-cli.mjs +47 -34
- package/src/cancel-state.mjs +213 -15
- package/src/capabilities.mjs +36 -1
- package/src/capacity-cli.mjs +28 -8
- package/src/capacity-records.mjs +75 -16
- package/src/capacity.mjs +65 -0
- package/src/chat-cli.mjs +288 -0
- package/src/chat-fork.mjs +547 -0
- package/src/chat-mode.mjs +156 -0
- package/src/chat-view.mjs +720 -0
- package/src/checkpoint-paths.mjs +113 -0
- package/src/cli.mjs +136 -41
- package/src/comment-tables.mjs +322 -0
- package/src/community-auth-adapters.mjs +87 -0
- package/src/community-auth-helper.mjs +76 -0
- package/src/community-auth-metadata.mjs +6 -0
- package/src/community-auth-output-pins.mjs +38 -0
- package/src/community-auth-patches.mjs +168 -0
- package/src/community-auth-pins.mjs +38 -0
- package/src/config.mjs +190 -29
- package/src/connection.mjs +83 -7
- package/src/console-answer.mjs +113 -0
- package/src/console-audit.mjs +604 -0
- package/src/console-bootstrap.mjs +325 -0
- package/src/console-client.mjs +848 -0
- package/src/console-devices.mjs +372 -0
- package/src/console-install.mjs +239 -0
- package/src/console-open.mjs +99 -0
- package/src/console-probe.mjs +106 -0
- package/src/console-tokens.mjs +459 -0
- package/src/container-names.mjs +51 -0
- package/src/container-spec.mjs +20 -1
- package/src/cpu-reserve.mjs +4 -1
- package/src/defer-reasons.mjs +200 -0
- package/src/defer-write.mjs +208 -0
- package/src/deployment-venue.mjs +23 -6
- package/src/docker-run.mjs +11 -0
- package/src/doctor-bundles.mjs +130 -0
- package/src/doctor-model-proposals.mjs +109 -0
- package/src/doctor-openshell.mjs +238 -0
- package/src/doctor-results.mjs +602 -0
- package/src/doctor-spawner.mjs +215 -0
- package/src/doctor.mjs +1657 -196
- package/src/dollar-budget.mjs +212 -3
- package/src/endpoint-status.mjs +100 -0
- package/src/env-allowlist.mjs +96 -6
- package/src/env-file.mjs +6 -4
- package/src/envelope.mjs +5 -3
- package/src/file-expect.mjs +47 -0
- package/src/forgejo-host.mjs +42 -5
- package/src/forgejo-prompt.mjs +5 -4
- package/src/forges.mjs +33 -3
- package/src/fork-job.mjs +58 -0
- package/src/fork-policy.mjs +23 -0
- package/src/fork-store.mjs +338 -0
- package/src/get-token.mjs +1 -1
- package/src/git-dirty.mjs +119 -14
- package/src/git-hardening.mjs +85 -0
- package/src/github-host.mjs +31 -6
- package/src/github-prompt.mjs +7 -16
- package/src/gitlab-host.mjs +42 -3
- package/src/gitlab-prompt.mjs +5 -4
- package/src/held-document.mjs +23 -0
- package/src/held-replies.mjs +325 -0
- package/src/held-settle.mjs +266 -0
- package/src/hook-runs.mjs +188 -0
- package/src/host-budget.mjs +8 -5
- package/src/host-clone.mjs +72 -0
- package/src/host-loads.mjs +557 -0
- package/src/host-registry.mjs +66 -6
- package/src/host-telemetry.mjs +92 -0
- package/src/http-body.mjs +78 -0
- package/src/image-preflight.mjs +156 -13
- package/src/import-pi.mjs +60 -172
- package/src/inbox-relay.mjs +482 -0
- package/src/inbox-settle.mjs +196 -0
- package/src/index.mjs +734 -129
- package/src/init.mjs +35 -5
- package/src/job-data-version.mjs +75 -0
- package/src/job-id.mjs +30 -15
- package/src/job-layout.mjs +22 -0
- package/src/job-size.mjs +16 -0
- package/src/live-jobs.mjs +14 -6
- package/src/live-probes.mjs +6 -2
- package/src/live-transcript.mjs +872 -0
- package/src/loaded-record.mjs +609 -0
- package/src/mcp-config.mjs +4 -2
- package/src/mcp-preflight.mjs +36 -5
- package/src/model-attempts.mjs +84 -0
- package/src/model-catalog.mjs +83 -0
- package/src/model-cooldowns.mjs +22 -0
- package/src/model-failover-protocol.mjs +11 -0
- package/src/model-failover.mjs +134 -0
- package/src/model-observation.mjs +50 -0
- package/src/model-proposal-protocol.mjs +21 -0
- package/src/model-proposals.mjs +75 -0
- package/src/model-ref.mjs +67 -10
- package/src/model-roles-file.mjs +24 -0
- package/src/model-roles.mjs +73 -0
- package/src/model-status.mjs +34 -0
- package/src/models-json.mjs +12 -2
- package/src/money.mjs +1 -1
- package/src/oauth-openai.mjs +121 -0
- package/src/older-state.mjs +249 -0
- package/src/on-failure.mjs +17 -13
- package/src/open-browser.mjs +31 -2
- package/src/opener-cli.mjs +135 -0
- package/src/opener-protocol.mjs +27 -0
- package/src/opener-terminal.mjs +128 -0
- package/src/openshell-cli.mjs +155 -0
- package/src/openshell-policy.mjs +163 -0
- package/src/outbox.mjs +14 -0
- package/src/output-cap.mjs +1 -0
- package/src/package-canary-record.mjs +26 -0
- package/src/package-canary.mjs +135 -0
- package/src/package-names.mjs +9 -0
- package/src/package-stage.mjs +418 -0
- package/src/packages.mjs +24 -16
- package/src/parked.mjs +2 -1
- package/src/pause-windows.mjs +136 -17
- package/src/podman-stack.mjs +40 -14
- package/src/portfolio-snapshot.mjs +26 -7
- package/src/prepare-github.mjs +41 -77
- package/src/prepare-local.mjs +32 -2
- package/src/prepare.mjs +45 -11
- package/src/private-store-boundary.mjs +70 -0
- package/src/processor.mjs +1550 -173
- package/src/projects.mjs +23 -0
- package/src/prompt-fence.mjs +18 -0
- package/src/provider-key.mjs +7 -0
- package/src/provider-steering.mjs +1 -0
- package/src/question-context.mjs +35 -0
- package/src/question-group-runtime.mjs +91 -0
- package/src/question-groups.mjs +171 -0
- package/src/queue.mjs +264 -55
- package/src/reason-catalog.mjs +448 -0
- package/src/receiver-status.mjs +230 -0
- package/src/record-reason.mjs +37 -0
- package/src/recovery-queue.mjs +566 -0
- package/src/redact-secrets.mjs +219 -0
- package/src/reserve-estimate.mjs +101 -0
- package/src/reserved-env.mjs +36 -1
- package/src/retention.mjs +67 -0
- package/src/run-budget-ledger.mjs +283 -0
- package/src/run-checkpoint.mjs +627 -0
- package/src/run-container.mjs +749 -33
- package/src/run-history.mjs +791 -45
- package/src/run-mirror.mjs +75 -7
- package/src/run-progress.mjs +751 -0
- package/src/runtime-observations.mjs +3 -1
- package/src/runtime-settings.mjs +272 -37
- package/src/sandbox-cli.mjs +78 -2
- package/src/sandbox-deployment.mjs +51 -0
- package/src/sandbox-gateway-protocol.mjs +378 -0
- package/src/sandbox-hosts.mjs +100 -0
- package/src/sandbox-inventory.mjs +83 -0
- package/src/sandbox-policy.mjs +225 -0
- package/src/sandbox-prepare-requests.mjs +145 -0
- package/src/sandbox-prepare.mjs +285 -0
- package/src/sandbox-refs.mjs +70 -0
- package/src/sandbox-session-monitor.mjs +4 -0
- package/src/sandbox-session-watch.mjs +124 -0
- package/src/sandbox-sessions.mjs +161 -0
- package/src/sandbox-store.mjs +63 -6
- package/src/sandbox-workspace-guard.mjs +39 -0
- package/src/sandbox.mjs +27 -200
- package/src/scheduler-stall-guard.mjs +14 -8
- package/src/schedules.mjs +19 -6
- package/src/secret-bundles.mjs +245 -0
- package/src/secret-profiles.mjs +103 -3
- package/src/secrets.mjs +19 -9
- package/src/service-env.mjs +38 -5
- package/src/service.mjs +638 -106
- package/src/session-key.mjs +60 -0
- package/src/session-store.mjs +168 -10
- package/src/setup-contract.mjs +40 -0
- package/src/setup-egress.mjs +113 -0
- package/src/setup-host-entry.mjs +36 -0
- package/src/setup-host.mjs +242 -0
- package/src/setup-lock.mjs +41 -0
- package/src/size-records.mjs +15 -3
- package/src/start.mjs +1353 -135
- package/src/status-comment.mjs +415 -0
- package/src/stderr-transcript.mjs +318 -0
- package/src/steer-ack.mjs +122 -0
- package/src/steer-cli.mjs +213 -0
- package/src/steer-framing.mjs +185 -0
- package/src/steer-inbox.mjs +693 -0
- package/src/store-version.mjs +139 -0
- package/src/subscription-config.mjs +56 -0
- package/src/subscription-limits.mjs +3 -0
- package/src/subscription-quota.mjs +259 -0
- package/src/subscription-runtime.mjs +123 -0
- package/src/subscription-status.mjs +42 -0
- package/src/subscription-wait.mjs +11 -0
- package/src/subscriptions.mjs +7 -1
- package/src/thinking-level.mjs +19 -0
- package/src/touch-outbox.mjs +61 -0
- package/src/touch-state.mjs +133 -0
- package/src/triggers-file.mjs +299 -39
- package/src/triggers.mjs +780 -38
- package/src/trust-paths.mjs +171 -0
- package/src/up.mjs +402 -53
- package/src/updates-cli.mjs +61 -0
- package/src/updates-look.mjs +127 -0
- package/src/updates-reconcile.mjs +182 -0
- package/src/updates-subscription-adapters.mjs +8 -0
- package/src/updates.mjs +252 -0
- package/src/valkey-auth.mjs +32 -9
- package/src/valkey-endpoint.mjs +14 -4
- package/src/wait-for.mjs +1 -1
- package/src/wait-state.mjs +62 -3
- package/src/watch-board.mjs +38 -0
- package/src/watch-closer.mjs +1 -1
- package/src/watch-contract.mjs +102 -0
- package/src/watch-decision.mjs +78 -0
- package/src/watch-drainer.mjs +14 -0
- package/src/watch-issue-adapter.mjs +44 -0
- package/src/watch-issue.mjs +111 -0
- package/src/watch-record.mjs +10 -0
- package/src/watch-runtime.mjs +167 -0
- package/src/watch-store.mjs +183 -0
- package/src/watch-trace.mjs +34 -0
- package/src/workspace-checkpoint.mjs +1750 -0
- package/src/zero-touch-fixes.mjs +99 -0
- package/src/zero-touch.mjs +225 -0
- package/src/repeat-slot.mjs +0 -13
package/.env.example
CHANGED
|
@@ -26,15 +26,23 @@
|
|
|
26
26
|
# OpenAI: OPENAI_API_KEY Google: GEMINI_API_KEY Groq: GROQ_API_KEY ... etc.
|
|
27
27
|
# You can LEAVE THIS BLANK if you are already logged into pi: when the env has no key, the worker reads the
|
|
28
28
|
# API key from ~/.pi/agent/auth.json (host-side) and env-injects it -- on by default, nothing to set.
|
|
29
|
-
# API-key
|
|
29
|
+
# Stored pi logins remain API-key only. For host-owned subscription authentication use docs/subscription-auth.md.
|
|
30
30
|
ANTHROPIC_API_KEY=
|
|
31
31
|
# uncomment to force env-only (fail loudly on a missing env key instead of using your pi login)
|
|
32
32
|
# PI_AUTH_FROM_PI=0
|
|
33
|
+
# Explicit subscription bindings own their providers, with no API-key fallback.
|
|
34
|
+
# PI_AUTH_CONNECTIONS_FILE=/absolute/path/auth-connections.json
|
|
35
|
+
# Host-private credentials, never under the global overlay or job/sandbox directories.
|
|
36
|
+
# PI_AUTH_STORE_DIR=/absolute/private/path/subscription-auth
|
|
33
37
|
|
|
34
38
|
# --- Which provider/model to run by default (override per job with --provider / --model) ---
|
|
39
|
+
# A provider id: 1 to 64 letters, digits, dots, dashes and underscores, starting with a letter or digit.
|
|
40
|
+
# Leave it out for the default; a value outside this shape, or an empty one, stops the worker at boot.
|
|
35
41
|
PI_PROVIDER=anthropic
|
|
36
42
|
# Name an exact model version (claude-sonnet-5-5, or a dated id such as claude-sonnet-4-5-20250929); an alias
|
|
37
43
|
# that moves to a newer model can change cost.
|
|
44
|
+
# A model id: 1 to 64 letters, digits and . _ - : / @, starting with a letter or digit (or one ~ or @ then
|
|
45
|
+
# one), no spaces. Case is kept. A value outside this shape, or an empty one, stops the worker at boot.
|
|
38
46
|
PI_MODEL=claude-sonnet-5-5
|
|
39
47
|
# optional: the only models a job may call, comma-separated provider/model (at most 16). A trigger's own
|
|
40
48
|
# run.models replaces this list for its jobs. The default model must be on it, or every job that uses the
|
|
@@ -161,8 +169,24 @@ PI_JOB_IMAGE=pi-job:latest
|
|
|
161
169
|
# PI_LOGS_DIR=
|
|
162
170
|
# default 0; set 1 to ALSO write raw container output to logs/<jobId>.log -- PII-bearing (issue/comment text), host-only (never mounted into the container), off by default (opt-in)
|
|
163
171
|
# PI_CAPTURE_JOB_LOGS=
|
|
172
|
+
# default on; set 0 to stop publishing each running job's transcript to Valkey (issue #643), where the console and the /dispatch panel on any host read it live
|
|
173
|
+
# What leaves the host is the transcript only (never the raw log), redacted of this job's own secrets and known token shapes, capped at 2,000 entries per job, and removed 24h after the run ends (7 days if a worker dies mid-run)
|
|
174
|
+
# PII: it carries issue text and tool output, so anyone who can read this Valkey (and every console operator) can read it; a secret the agent re-encodes is not caught. Any value but 0, 1 or empty refuses to boot
|
|
175
|
+
# PI_LIVE_TRANSCRIPTS=
|
|
176
|
+
# default on; set 0 to stop reading each running job's progress from its transcript (issue #644): turn, steps, failed steps and the tool running, to Valkey for the console and the /dispatch panel, plus a summary of integers in the run record
|
|
177
|
+
# A trigger with run.progress also reports named phases (shown to console operators only, redacted); one with run.statusComment gets a forge comment edited as it runs (numbers only, never model text)
|
|
178
|
+
# Independent of PI_LIVE_TRANSCRIPTS: with that at 0 and this on, no transcript text is published. 0 also stops the record field and the status comment. Any value but 0, 1 or empty refuses to boot
|
|
179
|
+
# PI_RUN_PROGRESS=
|
|
164
180
|
# default 30; prunes logs older than N days at boot AND on the retention timer below; 0 = keep forever
|
|
165
181
|
# PI_LOG_RETENTION_DAYS=
|
|
182
|
+
# default: PI_LOG_RETENTION_DAYS's value; prunes the console audit trail's month files (console-audit/ in PI_LOGS_DIR) older than N days, at boot and on the retention timer below; 0 = keep forever
|
|
183
|
+
# Its own setting so that shortening the run history for privacy does not shorten the security trail. The newest month file is never pruned (it holds the chain's head)
|
|
184
|
+
# Read by the worker, which runs the sweep (the console never prunes); set the same value on every host that shares PI_LOGS_DIR, where the shortest one wins. A value that is not a non-negative integer refuses to boot
|
|
185
|
+
# A worker from before this setting that shares PI_LOGS_DIR prunes console-audit/ by PI_LOG_RETENTION_DAYS, so upgrade every host before relying on a longer audit retention
|
|
186
|
+
# PI_CONSOLE_AUDIT_RETENTION_DAYS=
|
|
187
|
+
# default 5000; how many runs the shared run index keeps (the run mirror in Valkey that a worker with PI_WORKER_NAME writes, read by the console, the /dispatch panel and capacity); an integer 1000-20000, anything else refuses to boot
|
|
188
|
+
# Set the same value on every host: each worker trims the shared index to its own setting, so in a fleet the lowest one wins, and a worker from before this setting trims at 5000. Each trim is recorded, so a report shows the cut, never idle time
|
|
189
|
+
# PI_RUN_MIRROR_MAX_RUNS=
|
|
166
190
|
# default 24; how often the three retention sweeps (logs, sandboxes, sessions) re-run while the worker is up
|
|
167
191
|
# The sandbox one covers two things since issue #337: the retained directories, and the pi-sandbox-<id>-net network of a run whose directory is already gone
|
|
168
192
|
# 0 = BOOT-ONLY, which is what every version before this one did: a worker that never restarts never re-sweeps, so a configured window described nothing
|
|
@@ -170,10 +194,26 @@ PI_JOB_IMAGE=pi-job:latest
|
|
|
170
194
|
# The window is a FLOOR, not a ceiling: a file dies on the first sweep AFTER its window closes, so the real ceiling is its window plus this interval (up to 48h for a sandbox at both defaults)
|
|
171
195
|
# Refused above 168 (one week): setInterval clamps a longer delay to 1ms, and a sweep slower than a week is 0 with extra steps
|
|
172
196
|
# PI_SWEEP_INTERVAL_HOURS=
|
|
197
|
+
# default 24; how often the worker runs `pi-dispatch doctor --publish` itself (the first run a minute after boot), so the console and the /dispatch panel show each host's checks (issue #712)
|
|
198
|
+
# What is published to Valkey is each check's level, and for a warning or a failure its label and fix with paths and URLs cut to <path> and scheme://host and secret-named values and known token shapes redacted; kept 7 days per host
|
|
199
|
+
# A doctor you run by hand publishes the same way (pass --no-publish to skip it). 0 = the worker runs no doctor of its own; refused above 168 (one week)
|
|
200
|
+
# PI_DOCTOR_INTERVAL_HOURS=
|
|
201
|
+
# 1 = this host looks once a day for a newer pi and newer staged extensions, for the console's Updates page. Off by default.
|
|
202
|
+
# It reads registry.npmjs.org and this project's public check runs on api.github.com, from the worker host and never from a job.
|
|
203
|
+
# It sends the names of your staged packages to that registry, and changes nothing: trying or adopting a version is always a person.
|
|
204
|
+
# PI_UPDATES_LOOK=
|
|
205
|
+
# a proxy for the look's requests, with no direct fallback (http or https URL). Unset, the look connects directly.
|
|
206
|
+
# PI_UPDATES_PROXY=
|
|
207
|
+
# a registry to ask instead of registry.npmjs.org, such as a private mirror, so that private package names stay inside.
|
|
208
|
+
# PI_UPDATES_REGISTRY=
|
|
173
209
|
# where a finished run's directory is kept so you can re-open it (default: <PI_JOBS_DIR>/sandboxes, mode 0700)
|
|
174
210
|
# `pi-dispatch sandbox <jobId>` starts a fresh container from the same image with the same workspace and NO credentials (docs/sandbox.md)
|
|
175
211
|
# A retained directory holds the run's clone plus its prompt.md/event.json -- so issue text. Host-only; never mounted into a job
|
|
176
212
|
# PI_SANDBOX_DIR=
|
|
213
|
+
# Operator-only Fleet terminal mappings; the console defaults to <deployment>/sandbox-hosts.json
|
|
214
|
+
# PI_SANDBOX_HOSTS_FILE=
|
|
215
|
+
# Optional browser gateway enrollment, hand-owned and off when absent. See docs/sandbox-gateway.md.
|
|
216
|
+
# PI_SANDBOX_GATEWAYS_FILE=sandbox-gateways.json
|
|
177
217
|
# default 24. NOTE: 0 means OFF here -- nothing is retained and cleanup deletes as it always did
|
|
178
218
|
# This is the OPPOSITE of PI_LOG_RETENTION_DAYS/PI_SESSIONS_TTL_DAYS, where 0 means keep forever
|
|
179
219
|
# There is deliberately no keep-forever value: one repo clone per run with no ceiling is a disk bomb. Use --pin for the one run worth keeping
|
|
@@ -212,6 +252,10 @@ PI_JOB_IMAGE=pi-job:latest
|
|
|
212
252
|
# That source is your whole gh login: full-scope and non-expiring, and a transcript is a FILE -- any command that echoed an auth header persists it
|
|
213
253
|
# Prefer GITHUB_AUTH_SOURCE=app or a short-expiry fine-grained PAT. Set exactly 1 to accept the trade explicitly (SECURITY.md, docs/sessions.md)
|
|
214
254
|
# PI_SESSIONS_ALLOW_GH_SOURCE=
|
|
255
|
+
# default <PI_SESSIONS_DIR>/.checkpoints; where workspace checkpoints of durable runs live, unset with no PI_SESSIONS_DIR = nowhere
|
|
256
|
+
# A checkpoint holds a job's workspace, so the same rules as transcripts apply: mode 0700, owned by the worker, never under a temp dir
|
|
257
|
+
# It must not be PI_SESSIONS_DIR itself, contain it, or sit inside one of its session folders: the worker refuses that at start
|
|
258
|
+
# PI_CHECKPOINTS_DIR=
|
|
215
259
|
# ABSOLUTE path to the unified triggers.json, read by BOTH worker and receiver (a relative path resolves against the service's WorkingDirectory).
|
|
216
260
|
# Unset = cron disabled for the worker; the receiver falls back to ./triggers.json in the folder it starts from (what `pi-dispatch init` scaffolds)
|
|
217
261
|
# and refuses to start when neither exists (it holds the label/comment/pull_request trigger config)
|
|
@@ -248,8 +292,6 @@ PI_JOB_IMAGE=pi-job:latest
|
|
|
248
292
|
# (default: <your pi agent dir>/pi-dispatch-deployment.json). Read by the ADMIN EXTENSION only; the worker and receiver never look at it.
|
|
249
293
|
# Your own environment still wins key by key, so this points the panel at a deployment, it does not override one
|
|
250
294
|
# PI_DISPATCH_DEPLOYMENT_FILE=
|
|
251
|
-
# where `/dispatch insights` writes its HTML artifact (default: <OS temp dir>/pi-dispatch-<your uid>/graph). Admin extension only. See docs/insights.md
|
|
252
|
-
# PI_GRAPH_DIR=
|
|
253
295
|
|
|
254
296
|
# --- Reuse your existing pi setup in every job (see docs/global-pi-overlay.md) ---
|
|
255
297
|
# dir with your host pi setup (models.json/skills/APPEND_SYSTEM.md), mounted /opt/pi-global:ro into every job, layered UNDER each repo's .pi/. Unset = off. Stage it with: pi-dispatch import-pi
|
|
@@ -286,6 +328,13 @@ PI_JOB_IMAGE=pi-job:latest
|
|
|
286
328
|
# PI_SECRET_RESOLVER_ROOTS=
|
|
287
329
|
# default 10000, per reference. Sits before a paid container and is multiplied by the reference count, so tighter than doctor's 30s.
|
|
288
330
|
# PI_SECRET_RESOLVE_TIMEOUT_MS=
|
|
331
|
+
# Project secret bundles (docs/secrets.md Recipe D, issue #704): a project's whole environment, granted ONCE in
|
|
332
|
+
# triggers.json ("secretBundles": { "shop": { "profile": "shop-env", "ref": "shop", "project": "shop" } }). The worker
|
|
333
|
+
# runs YOUR script once per job start, on the HOST, and it prints every variable of that environment.
|
|
334
|
+
# name:/absolute/path:format, comma separated; format is dotenv (strict NAME=value lines) or json (one object of strings),
|
|
335
|
+
# required, never guessed. A plain file needs no manager: `exec cat "/etc/pi-dispatch/bundles/$1.env"` with :dotenv.
|
|
336
|
+
# Same exit codes as above. Bounded by PI_SECRET_RESOLVER_ROOTS for panel-declared ones. Unset = no bundle resolves here.
|
|
337
|
+
# PI_SECRET_BUNDLES=
|
|
289
338
|
|
|
290
339
|
# --- Holding a job until something else happens (docs/wait-for.md, issue #230) ---
|
|
291
340
|
# A trigger may carry "waitFor": [{ "after": "2026-09-01T09:00:00Z" }, { "profile": "jira" }]. The job is
|
|
@@ -345,6 +394,16 @@ PI_SCHEDULER_STALL_MAX=2
|
|
|
345
394
|
# `pi-dispatch doctor` prints enforced quietly, asserted as a warning naming who asserts it, and absent as a failure.
|
|
346
395
|
# Env-only, deliberately: a bound that can be widened from the surface it bounds is not a bound.
|
|
347
396
|
# PI_BACKEND_FLOOR=
|
|
397
|
+
# openshell (an NVIDIA OpenShell sandbox per job, docs/backends.md) is blessable since issue #684: name it in PI_BACKENDS.
|
|
398
|
+
# While PI_BACKENDS names it the worker reads these two at boot (a bad value refuses the boot), refuses PI_EGRESS=0, and
|
|
399
|
+
# refuses an openshell CLI or gateway not at the tested release; `pi-dispatch doctor --openshell` checks the host first.
|
|
400
|
+
# openshell-bind is the same venue in bind mode (issue #686): the job's directories bind-mounted, which brings back folder
|
|
401
|
+
# and cron-folder jobs, /inbox steering and run.recover. Opt-in: the gateway's gateway.toml must allow driver config and
|
|
402
|
+
# bind mounts (docs/backends.md, "Bind mode"), docker driver only. It shares the two settings below; name it in PI_BACKENDS.
|
|
403
|
+
# the gateway's compute driver, docker (default) or podman, whose store the job image is read from
|
|
404
|
+
# PI_OPENSHELL_ENGINE=
|
|
405
|
+
# a registered gateway's name (`openshell gateway list`); unset uses the CLI's active gateway
|
|
406
|
+
# PI_OPENSHELL_GATEWAY=
|
|
348
407
|
|
|
349
408
|
# --- Egress policy: what a job container may reach on the network (docs/egress.md) ---
|
|
350
409
|
# ON by default. Every job runs on its own --internal Docker network whose only other member is an allowlist
|
|
@@ -509,6 +568,28 @@ AZURE_WEBHOOK_SECRET=
|
|
|
509
568
|
# Required only when AZURE_WEBHOOK_MODE=header.
|
|
510
569
|
AZURE_WEBHOOK_HEADER=
|
|
511
570
|
|
|
571
|
+
# --- The operator console, a web page served by `pi-dispatch-console serve` (docs/console.md, issue #640) ---
|
|
572
|
+
# Nothing listens until you run serve, and serve refuses to start before `pi-dispatch-console token add --name <you> --role operator`.
|
|
573
|
+
# default 127.0.0.1:4790. Also [::1]:<port> or unix:/abs/path (a 0600 socket in a folder only you can open, which no job can reach).
|
|
574
|
+
# IP literals only: a hostname could resolve somewhere you did not mean.
|
|
575
|
+
# The /dispatch panel reads it too: `/dispatch insights` and the `i` key print the console's insights page at this address (docs/insights.md).
|
|
576
|
+
# PI_CONSOLE_LISTEN=
|
|
577
|
+
# default console-tokens.json, relative to this folder. Hashes only, mode 0600, yours; serve refuses anything looser.
|
|
578
|
+
# PI_CONSOLE_TOKENS_FILE=
|
|
579
|
+
# default none. Extra Host names the console answers to, comma separated; any port is accepted, so an ssh -L tunnel needs nothing here.
|
|
580
|
+
# host.docker.internal and the other container gateway names are refused: they are how a job would reach the console.
|
|
581
|
+
# PI_CONSOLE_ALLOWED_HOSTS=
|
|
582
|
+
# default off. 1 answers every write 403 and leaves reads and sign-in on -- for a console you only want to look at.
|
|
583
|
+
# PI_CONSOLE_READ_ONLY=
|
|
584
|
+
# default off. 1 allows a non-loopback IP in PI_CONSOLE_LISTEN, and doctor warns every time: the console has no TLS, use ssh -L instead.
|
|
585
|
+
# PI_CONSOLE_BIND_PUBLIC=
|
|
586
|
+
# default 60, 5 to 1440. Minutes without a request before a session ends.
|
|
587
|
+
# PI_CONSOLE_IDLE_MINUTES=
|
|
588
|
+
# default 12, 1 to 168. Hours after sign-in before a session ends however busy, so a forgotten tab does not stay signed in.
|
|
589
|
+
# PI_CONSOLE_MAX_HOURS=
|
|
590
|
+
# default 4, 1 to 32. Live streams one token may hold across its sign-ins, so no one can hold every connection.
|
|
591
|
+
# PI_CONSOLE_MAX_STREAMS=
|
|
592
|
+
|
|
512
593
|
# --- What is deliberately NOT a key in this file --- issue #282
|
|
513
594
|
# The rule, and it is checked by a test (worker/test/env-docs.test.mjs): every environment variable this
|
|
514
595
|
# project's loaders read is either a key above, or named here with the reason it cannot be one. A variable
|
package/README.md
CHANGED
|
@@ -2,13 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
The worker and the `pi-dispatch` command line tool of
|
|
4
4
|
**[pi-dispatch](https://github.com/edgehero/pi-dispatch)**, which runs the
|
|
5
|
-
[pi](https://github.com/earendil-works/pi) coding agent
|
|
5
|
+
[pi](https://github.com/earendil-works/pi) coding agent for you in the background, in a sealed box for each job, up to the spending limit
|
|
6
|
+
you set, and shows it all on one web page. Most people want the
|
|
7
|
+
[main README](https://github.com/edgehero/pi-dispatch#readme) first: it explains why and how to use it.
|
|
6
8
|
|
|
7
9
|
The worker takes jobs from a durable queue (Valkey with BullMQ). Before anything is spent it checks every
|
|
8
10
|
cap that applies: job counts and a daily token count for the whole deployment, job counts per repo, folder
|
|
9
11
|
or project, and dollars per day, week or month for the deployment and per repo, folder, project or model,
|
|
10
12
|
plus each project's share of the budget split. It then starts one locked down container per job (Docker or
|
|
11
|
-
Podman), holds the job to its own dollar cap when one is set, gives the agent the job, records what it did
|
|
13
|
+
Podman), holds the job to its own dollar cap when one is set, gives the agent the job, records what it loaded, what it did
|
|
12
14
|
and what it cost, and removes the container. Jobs come from the command line, from cron triggers, or from
|
|
13
15
|
forge events that the
|
|
14
16
|
[receiver](https://www.npmjs.com/package/@edgehero/pi-dispatch-receiver) queues.
|
|
@@ -27,6 +29,10 @@ npx @edgehero/pi-dispatch worker # run jobs
|
|
|
27
29
|
npx @edgehero/pi-dispatch run ./my-project --task "add type hints" --flow tidy
|
|
28
30
|
```
|
|
29
31
|
|
|
32
|
+
On the NVIDIA OpenShell venue (`PI_BACKENDS=openshell` in `.env`), `up` also checks its gateway, offers to start
|
|
33
|
+
and register it (it never installs OpenShell), and puts the job image into the gateway's engine
|
|
34
|
+
([backends](https://github.com/edgehero/pi-dispatch/blob/main/docs/backends.md#the-openshell-venue)).
|
|
35
|
+
|
|
30
36
|
A local job edits your folder **in place**, and there is no undo, so commit first. The worker refuses a
|
|
31
37
|
folder with uncommitted changes unless you pass `--force`. The folder must be the root of a git repository
|
|
32
38
|
with at least one commit, and `run` refuses any other folder before it queues anything.
|
|
@@ -37,15 +43,23 @@ with at least one commit, and `run` refuses any other folder before it queues an
|
|
|
37
43
|
|---|---|
|
|
38
44
|
| `init` | write `.env` and the config files into this folder (never overwrites) |
|
|
39
45
|
| `up` | one pass that asks before each container action: image, Valkey, egress proxy, `init`, `doctor` |
|
|
40
|
-
| `
|
|
46
|
+
| `console` | get into the web console: starts its service if it stopped, then opens your browser signed in |
|
|
47
|
+
| `doctor [--fix] [--live] [--openshell] [--secrets] [--no-publish]` | check the whole setup; `--live` reads the isolation guarantees back from real containers; each run publishes its checks (paths, URLs and secret values cut out) for the console and the panel, unless `--no-publish` |
|
|
41
48
|
| `worker` | run jobs from the queue |
|
|
42
49
|
| `run <folder> --task "..."` | queue one job against a local folder |
|
|
43
50
|
| `run --trigger <id>` | fire one cron trigger from the triggers file now, once, as its schedule would |
|
|
44
|
-
| `status`, `pause`, `resume`, `cancel <jobId>` |
|
|
45
|
-
| `
|
|
51
|
+
| `status`, `pause`, `resume`, `cancel <jobId>` | control the running worker from any terminal |
|
|
52
|
+
| `steer <jobId> "..."` | send a running job a message, which the agent reads between its steps (`--later` once it would otherwise stop) |
|
|
53
|
+
| `capacity` | how busy each host was over the last day, week or thirty days, read from the run records |
|
|
54
|
+
| `service render\|install\|uninstall\|status\|start\|stop\|restart` | run the worker (or `--receiver`, or `--console` for the operator console) as a service (user level on macOS and Linux, nssm on Windows) |
|
|
46
55
|
| `setup github` | create a GitHub App in one browser click |
|
|
56
|
+
| `auth` | manage host owned subscription authentication: `status`, `login`, `logout`, `usage`, `trial` |
|
|
57
|
+
| `canary` | replay up to three retained jobs on another model in disposable workspaces, under one experiment cap |
|
|
58
|
+
| `updates` | which pi and which extensions jobs run, what is newer, and adopting it |
|
|
59
|
+
| `opener install` | register `pi-dispatch-open`, so the console can open a sandbox in your own terminal |
|
|
47
60
|
| `import-pi` | stage your own pi setup (models, skills, persona) for every job, without credentials |
|
|
48
|
-
| `
|
|
61
|
+
| `chat <jobId \| url \| key>` | follow and steer a running job, answer a parked one, or fork a finished one into your own pi (`--fork-as-job` to run it as a job), through the operator console |
|
|
62
|
+
| `sandbox <jobId>` | reopen a finished run's workspace in a fresh container with no credentials; `--list`, `--attach` and `--new` to see, return to or prepare one |
|
|
49
63
|
| `egress render` | write `model-endpoints.conf` from `model-endpoints.json`, then print the command that reloads the egress proxy |
|
|
50
64
|
|
|
51
65
|
Before you rely on it, read [`SECURITY.md`](https://github.com/edgehero/pi-dispatch/blob/main/SECURITY.md).
|
|
@@ -54,5 +68,5 @@ guardrails that tell it not to leak them are prompt text. The default GitHub sou
|
|
|
54
68
|
whole login, full scope and never expiring. pi-dispatch never merges anything, but the job's token can,
|
|
55
69
|
so branch protection on your default branch is the real control.
|
|
56
70
|
|
|
57
|
-
The full guide, with triggers, providers, the
|
|
71
|
+
The full guide, with the console, triggers, providers, the panel and every forge, is the
|
|
58
72
|
[main README](https://github.com/edgehero/pi-dispatch#readme). MIT licensed.
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# UNTESTED EXAMPLE (DES-OPERATOR-CONSOLE) -- a starting point, not a shipped, verified unit. Adapt it.
|
|
2
|
+
#
|
|
3
|
+
# The operator console (`pi-dispatch-console serve`, issue #640) as a service, so it keeps running after the terminal
|
|
4
|
+
# that started it closes (issue #708). `pi-dispatch service install --console` renders this file for THIS host: the
|
|
5
|
+
# node, the console package's own entry (admin/dist/console.mjs of @edgehero/pi-dispatch-admin, wherever npm put it)
|
|
6
|
+
# and the deployment folder are substituted, so prefer that to adapting it by hand.
|
|
7
|
+
#
|
|
8
|
+
# The console listens on PI_CONSOLE_LISTEN (default 127.0.0.1:4790, loopback only) and reads its tokens file
|
|
9
|
+
# (PI_CONSOLE_TOKENS_FILE, default console-tokens.json in the deployment folder). It never needs Docker or Podman, so
|
|
10
|
+
# this unit is ordered after nothing but the network and has no Quadlet companion. Reach it from another machine
|
|
11
|
+
# with ssh -L, never by binding a public address: it speaks plain HTTP (docs/console.md).
|
|
12
|
+
#
|
|
13
|
+
# NO EnvironmentFile= on purpose: `serve --deployment` reads the deployment's `.env` itself, takes only its own
|
|
14
|
+
# PI_CONSOLE_* keys and the Valkey keys it needs from it, and refuses a `.env` another account can change. Loading the
|
|
15
|
+
# whole file into the process environment would hand it every worker secret (the provider key, the forge token) and
|
|
16
|
+
# would make each of those keys read as this shell's, which wins over the file and skips that trust check.
|
|
17
|
+
# WorkingDirectory / User / node path below are PLACEHOLDERS: set them to wherever your deployment folder is and
|
|
18
|
+
# whoever owns it (the tokens file must be owned by that account, mode 0600, or serve refuses).
|
|
19
|
+
|
|
20
|
+
[Unit]
|
|
21
|
+
Description=pi-dispatch operator console (the web console over the queue, runs and spend; loopback by default)
|
|
22
|
+
# For a system unit. In a --user unit these two are inert (the user manager has no network-online.target), which is
|
|
23
|
+
# harmless: the console binds loopback or a socket, and its Valkey reads retry on their own.
|
|
24
|
+
After=network-online.target
|
|
25
|
+
Wants=network-online.target
|
|
26
|
+
# Crash-loop bound, as the worker and receiver units carry it: at most StartLimitBurst restarts within
|
|
27
|
+
# StartLimitIntervalSec, then systemd stops trying. Pairs with Restart=on-failure below.
|
|
28
|
+
StartLimitIntervalSec=60
|
|
29
|
+
StartLimitBurst=5
|
|
30
|
+
|
|
31
|
+
[Service]
|
|
32
|
+
Type=simple
|
|
33
|
+
User=pi
|
|
34
|
+
WorkingDirectory=/opt/pi-dispatch
|
|
35
|
+
ExecStart=/usr/bin/node /usr/lib/node_modules/@edgehero/pi-dispatch-admin/dist/console.mjs serve --deployment /opt/pi-dispatch
|
|
36
|
+
Restart=on-failure
|
|
37
|
+
RestartSec=5
|
|
38
|
+
# Exit 2 is the console's refusal: no tokens file, no operator token in it, an unusable PI_CONSOLE_LISTEN, or the
|
|
39
|
+
# single-instance lock held by another console of this deployment. The next start reads the same files and fails
|
|
40
|
+
# the same way, so it is never restarted; add a token (`pi-dispatch-console token add`) or fix the setting, then
|
|
41
|
+
# start the unit again.
|
|
42
|
+
# A crash leaves the lock (<PI_LOGS_DIR>/console-audit/.console.lock) behind holding a dead pid, which the next start
|
|
43
|
+
# takes over. But if that pid has since been reused by another process (or by another account's, which reads as
|
|
44
|
+
# alive), every start refuses with exit 2 and the unit stays stopped: when the pid the refusal names is not a console,
|
|
45
|
+
# remove the lock file and start the unit again.
|
|
46
|
+
RestartPreventExitStatus=2
|
|
47
|
+
# serve handles SIGTERM: it ends the open streams, closes the listener and releases the lock, then exits.
|
|
48
|
+
KillSignal=SIGTERM
|
|
49
|
+
TimeoutStopSec=30
|
|
50
|
+
|
|
51
|
+
[Install]
|
|
52
|
+
WantedBy=multi-user.target
|
|
@@ -30,7 +30,9 @@
|
|
|
30
30
|
|
|
31
31
|
services:
|
|
32
32
|
valkey:
|
|
33
|
-
|
|
33
|
+
# Pinned to a minor, never a floating major (issue #761): VALKEY_IMAGE in worker/src/valkey-auth.mjs says why, and a
|
|
34
|
+
# test holds this line to it.
|
|
35
|
+
image: valkey/valkey:8.1
|
|
34
36
|
# The password (issue #468), from the deployment's .env through `--env-file .env`, into the container's ENVIRONMENT
|
|
35
37
|
# and never onto a command line: the image's PID 1 is tini, which keeps its whole argv for the life of the container,
|
|
36
38
|
# readable by every account on the host in /proc (measured). Empty or unset starts Valkey without one, as before.
|
|
@@ -10,13 +10,15 @@
|
|
|
10
10
|
# (measured on Podman 5.8.1: with linger on it came up 25 s after a reboot with nobody logged in).
|
|
11
11
|
#
|
|
12
12
|
# Fully qualified image names throughout: under short-name enforcement a unit cannot answer the prompt a short
|
|
13
|
-
# name raises, so `valkey/valkey:8` could fail to start where Docker quietly assumed docker.io.
|
|
13
|
+
# name raises, so `valkey/valkey:8.1` could fail to start where Docker quietly assumed docker.io. Pinned to a minor,
|
|
14
|
+
# never a floating major (issue #761): VALKEY_IMAGE in worker/src/valkey-auth.mjs says why, and a test holds the
|
|
15
|
+
# Image= line to it. A changed line restarts Valkey when `service install --force` writes it; the volume is kept.
|
|
14
16
|
|
|
15
17
|
[Unit]
|
|
16
18
|
Description=pi-dispatch Valkey (the job queue; rootless Podman, Quadlet)
|
|
17
19
|
|
|
18
20
|
[Container]
|
|
19
|
-
Image=docker.io/valkey/valkey:8
|
|
21
|
+
Image=docker.io/valkey/valkey:8.1
|
|
20
22
|
ContainerName=pi-dispatch-valkey
|
|
21
23
|
# EXPLICIT, see pi-dispatch-valkey.network for why a container here must never rely on the default network.
|
|
22
24
|
Network=pi-dispatch-valkey.network
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Optional example, installed by hand only. See docs/sandbox-gateway.md (#754).
|
|
2
|
+
# Run as the account owning the sandbox runtime, never add privileges for the gateway.
|
|
3
|
+
# No EnvironmentFile: the program reads only its explicit deployment key allowlist.
|
|
4
|
+
[Unit]
|
|
5
|
+
Description=pi-dispatch sandbox browser gateway
|
|
6
|
+
After=network-online.target
|
|
7
|
+
Wants=network-online.target
|
|
8
|
+
StartLimitIntervalSec=60
|
|
9
|
+
StartLimitBurst=5
|
|
10
|
+
|
|
11
|
+
[Service]
|
|
12
|
+
Type=simple
|
|
13
|
+
User=pi
|
|
14
|
+
WorkingDirectory=/opt/pi-dispatch
|
|
15
|
+
ExecStart=/usr/bin/node /usr/lib/node_modules/@edgehero/pi-dispatch-sandbox-gateway/dist/cli.mjs --config /opt/pi-dispatch/sandbox-gateway.json
|
|
16
|
+
Restart=on-failure
|
|
17
|
+
RestartSec=5
|
|
18
|
+
NoNewPrivileges=yes
|
|
19
|
+
KillSignal=SIGTERM
|
|
20
|
+
TimeoutStopSec=30
|
|
21
|
+
|
|
22
|
+
[Install]
|
|
23
|
+
WantedBy=multi-user.target
|
|
@@ -54,6 +54,10 @@ REM number. So after the load the wrapper re-asserts its own: ENV_SETUP and PI_E
|
|
|
54
54
|
REM %PI_ENV_SETUP%, which cmd expands when it READS this parenthesized block, before its first line runs
|
|
55
55
|
REM (`set /?`, the reason delayed expansion exists), so the value is the unit's and no .env line reaches it;
|
|
56
56
|
REM and ERRORLEVEL cleared just before the command runs. RC is assigned after the command, before it is read.
|
|
57
|
+
REM PI_WRAPPER_NO_DOTENV=1 (issue #708): the command reads the deployment's .env ITSELF and takes only the keys it
|
|
58
|
+
REM owns (the operator console, `serve --deployment`), so .env is neither loaded nor required here; see
|
|
59
|
+
REM worker-env-wrapper.sh for why. Read before the load, from the service's own environment, and cleared after it.
|
|
60
|
+
if "%PI_WRAPPER_NO_DOTENV%"=="1" goto wrapper_env_loaded
|
|
57
61
|
if exist ".env" (
|
|
58
62
|
for /f "usebackq eol=# tokens=1,* delims==" %%A in (".env") do set "%%A=%%B"
|
|
59
63
|
set "ENV_SETUP=%PI_ENV_SETUP%"
|
|
@@ -65,6 +69,8 @@ if exist ".env" (
|
|
|
65
69
|
)
|
|
66
70
|
echo worker-env-wrapper: no .env in "%CD%" -- the environment comes from "%ENV_SETUP%" ^(PI_ENV_SETUP^) 1>&2
|
|
67
71
|
)
|
|
72
|
+
:wrapper_env_loaded
|
|
73
|
+
set "PI_WRAPPER_NO_DOTENV="
|
|
68
74
|
|
|
69
75
|
REM AFTER .env, deliberately: the manager is the newer source of truth, so a stale key left in the file
|
|
70
76
|
REM loses instead of silently shadowing the managed one (mirrors the .sh twin). A missing or failing
|
|
@@ -77,7 +77,15 @@ trap wrapper_stopped_early TERM INT
|
|
|
77
77
|
# until the `shift` below.
|
|
78
78
|
set -- "${PI_ENV_SETUP:-}" "$@"
|
|
79
79
|
|
|
80
|
-
|
|
80
|
+
# PI_WRAPPER_NO_DOTENV=1 (issue #708) is set by the unit for a command that reads the deployment's .env ITSELF and
|
|
81
|
+
# takes only the keys it owns: the operator console (`serve --deployment`), which also refuses a .env another account
|
|
82
|
+
# can change. Sourcing the whole file here would hand that process every worker secret and make each key read as its
|
|
83
|
+
# own shell's, which wins over the file and skips that check. So ./.env is not sourced and not required. Tested
|
|
84
|
+
# before the load, from the unit's environment, so no .env line can set it; PI_ENV_SETUP is honoured exactly as
|
|
85
|
+
# without it (an operator who configured a script asked for it). Unset after, so the command never sees it.
|
|
86
|
+
if [ "${PI_WRAPPER_NO_DOTENV:-}" = "1" ]; then
|
|
87
|
+
:
|
|
88
|
+
elif [ -f ./.env ]; then
|
|
81
89
|
set -a; . ./.env; set +a
|
|
82
90
|
elif [ -z "$1" ]; then
|
|
83
91
|
echo "worker-env-wrapper: .env not found in $PWD -- this wrapper must be started in the deployment folder (the unit's WorkingDirectory / nssm AppDirectory); it no longer guesses a location from its own path" >&2
|
|
@@ -90,6 +98,7 @@ fi
|
|
|
90
98
|
# AFTER THE LOAD, every variable this wrapper reads is assigned, so no assignment line of ./.env
|
|
91
99
|
# reaches one. The worker sees the unit's PI_ENV_SETUP too, never one the file set (the setup script,
|
|
92
100
|
# which is unit configuration, may still set its own).
|
|
101
|
+
unset PI_WRAPPER_NO_DOTENV
|
|
93
102
|
env_setup=$1
|
|
94
103
|
shift
|
|
95
104
|
if [ -n "$env_setup" ]; then
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@edgehero/pi-dispatch",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "5.1.0",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"description": "The pi-dispatch worker and CLI:
|
|
5
|
+
"description": "The pi-dispatch worker and CLI: go from one AI coding agent to many in the background, running the pi coding agent as a self-hosted service, one locked down Docker or Podman container per job, with spend caps checked before anything is spent, plus init, up, doctor and service install.",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"pi",
|
|
8
8
|
"pi-coding-agent",
|
|
@@ -41,11 +41,47 @@
|
|
|
41
41
|
"pi-dispatch": "src/cli.mjs"
|
|
42
42
|
},
|
|
43
43
|
"exports": {
|
|
44
|
+
"./receiver-status": "./src/receiver-status.mjs",
|
|
45
|
+
"./setup-contract": "./src/setup-contract.mjs",
|
|
46
|
+
"./auth-policy": "./src/auth-policy.mjs",
|
|
47
|
+
"./setup-host-entry": "./src/setup-host-entry.mjs",
|
|
48
|
+
"./setup-lock": "./src/setup-lock.mjs",
|
|
49
|
+
"./provider-key": "./src/provider-key.mjs",
|
|
44
50
|
".": "./src/index.mjs",
|
|
45
51
|
"./config": "./src/config.mjs",
|
|
46
52
|
"./exit-code": "./src/exit-code.mjs",
|
|
47
53
|
"./entry": "./src/entry.mjs",
|
|
48
54
|
"./git-hardening": "./src/git-hardening.mjs",
|
|
55
|
+
"./http-body": "./src/http-body.mjs",
|
|
56
|
+
"./console-tokens": "./src/console-tokens.mjs",
|
|
57
|
+
"./console-devices": "./src/console-devices.mjs",
|
|
58
|
+
"./console-probe": "./src/console-probe.mjs",
|
|
59
|
+
"./console-audit": "./src/console-audit.mjs",
|
|
60
|
+
"./console-answer": "./src/console-answer.mjs",
|
|
61
|
+
"./steer-inbox": "./src/steer-inbox.mjs",
|
|
62
|
+
"./steer-framing": "./src/steer-framing.mjs",
|
|
63
|
+
"./inbox-relay": "./src/inbox-relay.mjs",
|
|
64
|
+
"./held-replies": "./src/held-replies.mjs",
|
|
65
|
+
"./live-transcript": "./src/live-transcript.mjs",
|
|
66
|
+
"./run-progress": "./src/run-progress.mjs",
|
|
67
|
+
"./reserve-estimate": "./src/reserve-estimate.mjs",
|
|
68
|
+
"./endpoint-status": "./src/endpoint-status.mjs",
|
|
69
|
+
"./model-endpoints": "./src/model-endpoints.mjs",
|
|
70
|
+
"./egress-allowlist": "./src/egress-allowlist.mjs",
|
|
71
|
+
"./egress": "./src/egress.mjs",
|
|
72
|
+
"./openshell-policy": "./src/openshell-policy.mjs",
|
|
73
|
+
"./model-catalog": "./src/model-catalog.mjs",
|
|
74
|
+
"./output-cap": "./src/output-cap.mjs",
|
|
75
|
+
"./model-roles": "./src/model-roles.mjs",
|
|
76
|
+
"./model-status": "./src/model-status.mjs",
|
|
77
|
+
"./model-observation": "./src/model-observation.mjs",
|
|
78
|
+
"./model-cooldowns": "./src/model-cooldowns.mjs",
|
|
79
|
+
"./model-proposal-protocol": "./src/model-proposal-protocol.mjs",
|
|
80
|
+
"./model-ref": "./src/model-ref.mjs",
|
|
81
|
+
"./model-failover-protocol": "./src/model-failover-protocol.mjs",
|
|
82
|
+
"./model-failover": "./src/model-failover.mjs",
|
|
83
|
+
"./model-attempts": "./src/model-attempts.mjs",
|
|
84
|
+
"./schedules": "./src/schedules.mjs",
|
|
49
85
|
"./env-file": "./src/env-file.mjs",
|
|
50
86
|
"./service-env": "./src/service-env.mjs",
|
|
51
87
|
"./podman-stack": "./src/podman-stack.mjs",
|
|
@@ -56,28 +92,41 @@
|
|
|
56
92
|
"./queue": "./src/queue.mjs",
|
|
57
93
|
"./capabilities": "./src/capabilities.mjs",
|
|
58
94
|
"./parked": "./src/parked.mjs",
|
|
95
|
+
"./approval-policy": "./src/approval-policy.mjs",
|
|
96
|
+
"./approval-state": "./src/approval-state.mjs",
|
|
59
97
|
"./connection": "./src/connection.mjs",
|
|
60
98
|
"./valkey-auth": "./src/valkey-auth.mjs",
|
|
61
99
|
"./job-id": "./src/job-id.mjs",
|
|
62
100
|
"./forges": "./src/forges.mjs",
|
|
101
|
+
"./fleet-lease": "./src/fleet-lease.mjs",
|
|
63
102
|
"./backend-local": "./src/backend-local.mjs",
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
103
|
+
"./container-names": "./src/container-names.mjs",
|
|
104
|
+
"./backends": "./src/backends.mjs",
|
|
105
|
+
"./backend-registry": "./src/backend-registry.mjs",
|
|
106
|
+
"./container-spec": "./src/container-spec.mjs",
|
|
107
|
+
"./job-size": "./src/job-size.mjs",
|
|
108
|
+
"./size-suggest": "./src/size-suggest.mjs",
|
|
109
|
+
"./capacity": "./src/capacity.mjs",
|
|
110
|
+
"./capacity-records": "./src/capacity-records.mjs",
|
|
111
|
+
"./touch-state": "./src/touch-state.mjs",
|
|
112
|
+
"./touch-outbox": "./src/touch-outbox.mjs",
|
|
113
|
+
"./zero-touch": "./src/zero-touch.mjs",
|
|
114
|
+
"./capacity-cli": "./src/capacity-cli.mjs",
|
|
115
|
+
"./live-jobs": "./src/live-jobs.mjs",
|
|
116
|
+
"./host-telemetry": "./src/host-telemetry.mjs",
|
|
117
|
+
"./size-records": "./src/size-records.mjs",
|
|
118
|
+
"./host-budget": "./src/host-budget.mjs",
|
|
119
|
+
"./backend-conformance": "./src/backend-conformance.mjs",
|
|
120
|
+
"./live-probes": "./src/live-probes.mjs",
|
|
121
|
+
"./triggers": "./src/triggers.mjs",
|
|
78
122
|
"./mcp-config": "./src/mcp-config.mjs",
|
|
123
|
+
"./mcp-preflight": "./src/mcp-preflight.mjs",
|
|
79
124
|
"./triggers-file": "./src/triggers-file.mjs",
|
|
125
|
+
"./file-expect": "./src/file-expect.mjs",
|
|
80
126
|
"./packages": "./src/packages.mjs",
|
|
127
|
+
"./updates": "./src/updates.mjs",
|
|
128
|
+
"./package-canary-record": "./src/package-canary-record.mjs",
|
|
129
|
+
"./updates-subscription-adapters": "./src/updates-subscription-adapters.mjs",
|
|
81
130
|
"./pause-windows": "./src/pause-windows.mjs",
|
|
82
131
|
"./scoped-limits": "./src/scoped-limits.mjs",
|
|
83
132
|
"./projects": "./src/projects.mjs",
|
|
@@ -88,6 +137,10 @@
|
|
|
88
137
|
"./wait-state": "./src/wait-state.mjs",
|
|
89
138
|
"./cancel-state": "./src/cancel-state.mjs",
|
|
90
139
|
"./host-registry": "./src/host-registry.mjs",
|
|
140
|
+
"./hook-runs": "./src/hook-runs.mjs",
|
|
141
|
+
"./doctor-results": "./src/doctor-results.mjs",
|
|
142
|
+
"./host-loads": "./src/host-loads.mjs",
|
|
143
|
+
"./loaded-record": "./src/loaded-record.mjs",
|
|
91
144
|
"./identity": "./src/identity.mjs",
|
|
92
145
|
"./gitlab-identity": "./src/gitlab-identity.mjs",
|
|
93
146
|
"./forgejo-identity": "./src/forgejo-identity.mjs",
|
|
@@ -95,17 +148,57 @@
|
|
|
95
148
|
"./get-token": "./src/get-token.mjs",
|
|
96
149
|
"./octokit-log": "./src/octokit-log.mjs",
|
|
97
150
|
"./runtime-settings": "./src/runtime-settings.mjs",
|
|
151
|
+
"./secret-profiles": "./src/secret-profiles.mjs",
|
|
98
152
|
"./run-history": "./src/run-history.mjs",
|
|
153
|
+
"./reason-catalog": "./src/reason-catalog.mjs",
|
|
99
154
|
"./run-mirror": "./src/run-mirror.mjs",
|
|
155
|
+
"./run-budget-ledger": "./src/run-budget-ledger.mjs",
|
|
156
|
+
"./recovery-queue": "./src/recovery-queue.mjs",
|
|
157
|
+
"./run-checkpoint": "./src/run-checkpoint.mjs",
|
|
158
|
+
"./session-key": "./src/session-key.mjs",
|
|
159
|
+
"./fork-store": "./src/fork-store.mjs",
|
|
160
|
+
"./fork-policy": "./src/fork-policy.mjs",
|
|
161
|
+
"./fork-job": "./src/fork-job.mjs",
|
|
162
|
+
"./chat-mode": "./src/chat-mode.mjs",
|
|
163
|
+
"./chat-fork": "./src/chat-fork.mjs",
|
|
164
|
+
"./console-client": "./src/console-client.mjs",
|
|
165
|
+
"./workspace-checkpoint": "./src/workspace-checkpoint.mjs",
|
|
100
166
|
"./sandbox": "./src/sandbox.mjs",
|
|
167
|
+
"./sandbox-policy": "./src/sandbox-policy.mjs",
|
|
168
|
+
"./openshell-cli": "./src/openshell-cli.mjs",
|
|
101
169
|
"./sandbox-store": "./src/sandbox-store.mjs",
|
|
170
|
+
"./sandbox-gateway-protocol": "./src/sandbox-gateway-protocol.mjs",
|
|
171
|
+
"./opener-protocol": "./src/opener-protocol.mjs",
|
|
172
|
+
"./sandbox-hosts": "./src/sandbox-hosts.mjs",
|
|
173
|
+
"./sandbox-prepare": "./src/sandbox-prepare.mjs",
|
|
174
|
+
"./sandbox-prepare-requests": "./src/sandbox-prepare-requests.mjs",
|
|
175
|
+
"./sandbox-inventory": "./src/sandbox-inventory.mjs",
|
|
176
|
+
"./sandbox-sessions": "./src/sandbox-sessions.mjs",
|
|
177
|
+
"./sandbox-session-watch": "./src/sandbox-session-watch.mjs",
|
|
102
178
|
"./subscriptions": "./src/subscriptions.mjs",
|
|
179
|
+
"./subscription-status": "./src/subscription-status.mjs",
|
|
103
180
|
"./budget": "./src/budget.mjs",
|
|
104
181
|
"./pricing": "./src/pricing.mjs",
|
|
105
182
|
"./money": "./src/money.mjs",
|
|
106
183
|
"./dollar-budget": "./src/dollar-budget.mjs",
|
|
107
184
|
"./scheduler-stall-guard": "./src/scheduler-stall-guard.mjs",
|
|
108
|
-
"./watch-closer": "./src/watch-closer.mjs"
|
|
185
|
+
"./watch-closer": "./src/watch-closer.mjs",
|
|
186
|
+
"./defer-reasons": "./src/defer-reasons.mjs",
|
|
187
|
+
"./bullmq-internals": "./src/bullmq-internals.mjs",
|
|
188
|
+
"./store-version": "./src/store-version.mjs",
|
|
189
|
+
"./job-data-version": "./src/job-data-version.mjs",
|
|
190
|
+
"./retention": "./src/retention.mjs",
|
|
191
|
+
"./record-reason": "./src/record-reason.mjs",
|
|
192
|
+
"./watch-contract": "./src/watch-contract.mjs",
|
|
193
|
+
"./watch-store": "./src/watch-store.mjs",
|
|
194
|
+
"./watch-decision": "./src/watch-decision.mjs",
|
|
195
|
+
"./watch-board": "./src/watch-board.mjs",
|
|
196
|
+
"./watch-trace": "./src/watch-trace.mjs",
|
|
197
|
+
"./answerer": "./src/answerer.mjs",
|
|
198
|
+
"./answerer-runtime": "./src/answerer-runtime.mjs",
|
|
199
|
+
"./question-groups": "./src/question-groups.mjs",
|
|
200
|
+
"./question-group-runtime": "./src/question-group-runtime.mjs",
|
|
201
|
+
"./zero-touch-fixes": "./src/zero-touch-fixes.mjs"
|
|
109
202
|
},
|
|
110
203
|
"engines": {
|
|
111
204
|
"node": ">=22.19.0"
|
|
@@ -115,10 +208,16 @@
|
|
|
115
208
|
"start": "node src/cli.mjs worker"
|
|
116
209
|
},
|
|
117
210
|
"dependencies": {
|
|
118
|
-
"@earendil-works/pi-ai": "1.2
|
|
211
|
+
"@earendil-works/pi-ai": "1.5.2",
|
|
212
|
+
"@earendil-works/pi-tui": "1.5.2",
|
|
119
213
|
"@octokit/auth-app": "8.2.0",
|
|
120
214
|
"@octokit/rest": "22.0.1",
|
|
121
215
|
"bullmq": "5.80.4",
|
|
122
|
-
"ioredis": "5.11.1"
|
|
216
|
+
"ioredis": "5.11.1",
|
|
217
|
+
"jiti": "2.7.0",
|
|
218
|
+
"jose": "6.2.14",
|
|
219
|
+
"proper-lockfile": "4.1.2",
|
|
220
|
+
"undici": "8.10.2",
|
|
221
|
+
"yaml": "2.9.0"
|
|
123
222
|
}
|
|
124
223
|
}
|