@edgehero/pi-dispatch-admin 1.4.0 → 1.6.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@edgehero/pi-dispatch-admin",
3
- "version": "1.4.0",
3
+ "version": "1.6.0",
4
4
  "description": "Operator console (a pi extension) + skill for pi-dispatch: run the pi coding agent as a self-hosted service. A /dispatch TUI for the queue, spend caps, run history, editable GitHub, GitLab, Forgejo and Azure DevOps triggers (cron/label/comment/PR/MR/work item), and scheduled pause windows — plus AI-operable, human-confirmed controls. Runs against a live pi-dispatch deployment.",
5
5
  "keywords": [
6
6
  "pi-package",
@@ -41,6 +41,18 @@ dialog before it takes effect**:
41
41
  (per folder/repo "quiet hours": runs for a scope are deferred between certain times and auto-resume after;
42
42
  `dispatch_pauses` lists them with their index). `dispatch_pause_edit` is a partial change — pass the index
43
43
  plus only the fields to alter. Deferring never drops a job and costs no budget.
44
+ - `dispatch_waits` — list the jobs the worker is HOLDING on a trigger's `run.waitFor` condition: job id,
45
+ an id-only target, the operator's own words for what it waits on, and how long it has waited. Different
46
+ from the queue's `delayed` count, which also mixes cron next-occurrences, retry backoff and quiet hours.
47
+ - `dispatch_wait_cancel` — remove a held job so it never runs (confirm-gated). It is the only lever that
48
+ reaches one: a held job has spent nothing, so no budget cap will ever refuse it, and deleting the trigger
49
+ does not reach a job already enqueued.
50
+ - `dispatch_limit_add` / `dispatch_limit_edit` / `dispatch_limit_delete` — manage scoped limits (per
51
+ repo/folder budget caps and concurrency: `day`/`week`/`month` job-count caps refuse a job pre-spend with
52
+ reason `scope-cap`, never retried; `concurrent` defers the excess, never drops it; `dispatch_limits`
53
+ lists them with their index and used counts). `dispatch_limit_edit` is a partial change — pass the index
54
+ plus only the fields to alter. Scopes match exactly (a repo `owner/name` or an ABSOLUTE folder path, no
55
+ globs).
44
56
 
45
57
  Use them like this:
46
58
 
@@ -235,3 +247,50 @@ If you are asked why a GitLab trigger did not fire, the usual answers in order:
235
247
  2. **No label was added by that event.** GitLab has no `labeled` action; the trigger fires on the labels
236
248
  an event *added*, so editing an already-labelled issue does nothing. This is deliberate.
237
249
  3. **The action word belongs to the other forge.** See above.
250
+
251
+ ## Held jobs — what `waitFor` looks like from here
252
+
253
+ A trigger may carry `run.waitFor`, and a job whose conditions have not cleared is **held**: deferred, with
254
+ no budget slot reserved, no kill timer armed, no retry attempt consumed, and no run record written. It runs
255
+ exactly once when every condition clears.
256
+
257
+ What that means when you are asked about a job that "has not run":
258
+
259
+ - **Look at `dispatch_waits` before the queue counts.** A held job is not `waiting` and not `active`. It is
260
+ in the delayed set, which also holds every cron trigger's next occurrence, so the panel's `delayed` number
261
+ is not an answer to "what is stuck".
262
+ - **A held job has cost nothing yet.** Do not reason about it against the spend caps: they count container
263
+ starts, and this job has started none. The bounds that apply to it are its own (`PI_WAIT_MAX_MS`,
264
+ `PI_WAIT_MAX_CHECKS`), and when one is reached the job terminates with a run record naming the reason.
265
+ - **The terminal reasons say what to do.** `wait-refused` means the operator's check reported the condition
266
+ will never clear. `wait-unanswerable` means the check could not answer repeatedly, which usually means the
267
+ script is broken rather than the condition slow. `wait-expired` means a bound was reached.
268
+ `wait-skew` / `wait-unreadable` mean two services in the deployment disagree about the field and one needs
269
+ upgrading or restarting.
270
+ - **Cancelling is an operator decision.** `dispatch_wait_cancel` needs a confirm, writes no run record (the
271
+ job never ran), and cannot be undone: the delivery is gone, and a webhook does not resend itself.
272
+
273
+ ## Scoped limits — and the folder mutex you cannot turn off
274
+
275
+ `scoped-limits.json` holds per-scope bounds beside the deployment-global ones: `day`/`week`/`month` cap
276
+ how many jobs a repo or folder may run per window (refused pre-spend, reason `scope-cap`, never retried,
277
+ the scope's own counter still counts the refusal), and `concurrent` caps how many run at once (the excess
278
+ is deferred to the delayed set and runs when a slot frees — never dropped, no budget spent while waiting).
279
+ Edits apply live: the worker hot-reloads the file and keeps the last good version on a bad edit.
280
+
281
+ Separate from all of that, **local jobs carry a built-in one-job-per-folder mutex: at most one job per
282
+ folder at a time, always on, with NO configuration, NO tool, and NO panel key.** If an operator asks to
283
+ disable it, say plainly that there is no switch, deliberately: two agents editing one working tree race
284
+ each other with no gate and no undo, and an off switch's only use is re-opening that race. A `concurrent`
285
+ value on a folder scope can never raise the mutex's one-at-a-time (the lower bound always wins).
286
+
287
+ Three more things to say when asked:
288
+
289
+ - **A `scope-cap` refusal is final for that window.** The counter is not resettable from any tool; the
290
+ window rolls over on its own (day/week/month, UTC). Raising the cap via `dispatch_limit_edit` takes
291
+ effect at the next job.
292
+ - **Deferrals are visible only as the queue's delayed count** (the panel's status line shows it when it
293
+ is nonzero). That count also includes cron next-occurrences and retry backoff — a nonzero number is
294
+ normal on any deployment with schedules.
295
+ - **Per-scope in-flight is not displayed anywhere.** The panel and `dispatch_limits` show `concurrent` as
296
+ configuration only; the live count lives inside the worker process and no reader can see it.