@hasna/loops 0.4.26 → 0.4.28
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/CHANGELOG.md +121 -0
- package/README.md +6 -0
- package/dist/api/index.js +689 -20
- package/dist/cli/index.js +509 -85
- package/dist/daemon/index.js +118 -11
- package/dist/index.js +525 -64
- package/dist/lib/executor.d.ts +9 -0
- package/dist/lib/migration.d.ts +66 -0
- package/dist/lib/mode.js +3 -3
- package/dist/lib/route/fields.d.ts +8 -0
- package/dist/lib/storage/index.js +197 -7
- package/dist/lib/storage/postgres-loop-storage.d.ts +2 -2
- package/dist/lib/storage/postgres-schema.js +3 -0
- package/dist/lib/storage/postgres.js +3 -0
- package/dist/lib/storage/sqlite.js +83 -3
- package/dist/lib/store/index.d.ts +3 -0
- package/dist/lib/store.d.ts +77 -0
- package/dist/lib/store.js +89 -4
- package/dist/mcp/index.js +118 -11
- package/dist/runner/index.js +35 -8
- package/dist/sdk/http.d.ts +153 -1
- package/dist/sdk/http.js +78 -1
- package/dist/sdk/index.js +411 -60
- package/dist/serve/index.js +919 -60
- package/dist/types.d.ts +11 -0
- package/docs/DEPLOYMENT_MODES.md +6 -0
- package/docs/USAGE.md +11 -8
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -42,6 +42,127 @@ unless noted.
|
|
|
42
42
|
execution over the runner protocol, and id-preserving remote import remain
|
|
43
43
|
follow-up work.
|
|
44
44
|
|
|
45
|
+
## 0.4.18 (2026-07-07/08)
|
|
46
|
+
|
|
47
|
+
Drain reliability: kill the todos-task redispatch "black hole" family, then the
|
|
48
|
+
merge-lane routing wedge and the schema-lockout class behind it. One artifact
|
|
49
|
+
consolidates the whole independently-reviewed family: #82 (dead-letter at the
|
|
50
|
+
cap + attempt refunds + requeue reset + worktree self-heal), #88 (per-task
|
|
51
|
+
repository routing + candidate-window memory), #89 (schema-compat soft-open +
|
|
52
|
+
gate-death ceiling), plus the previously unpublished 0.4.15–0.4.17 ride-alongs
|
|
53
|
+
documented below.
|
|
54
|
+
|
|
55
|
+
### Fixed
|
|
56
|
+
|
|
57
|
+
- **Merge-lane wedge — the task's own repository wins over a group-root
|
|
58
|
+
`--project-path`:** commit 8ab2664 made the router-level `--project-path` win
|
|
59
|
+
unconditionally in todos-task drains, so multi-repo routers that pass it as a
|
|
60
|
+
concurrency group root (a non-repository directory such as the operator's
|
|
61
|
+
home) sent every task to the group root and skipped it (`worktreeMode=required
|
|
62
|
+
but projectPath is not an existing git repository`), zeroing merge dispatch
|
|
63
|
+
fleet-wide. A drain
|
|
64
|
+
now routes each task to its own first *usable* repository path (explicit
|
|
65
|
+
`project_path`, metadata, the description's `Repository:` line, then
|
|
66
|
+
`working_dir` — first that is a real git repo, probed once per path per tick);
|
|
67
|
+
the router-level `--project-path` remains the rescue fallback for tasks whose
|
|
68
|
+
recorded path is stale or broken (8ab2664's original intent). Registry drains
|
|
69
|
+
are unchanged (the scanned source project still wins; task-controlled fields
|
|
70
|
+
cannot redirect a route).
|
|
71
|
+
- **Route-disallowed tasks no longer burn the candidate window:** tasks bearing
|
|
72
|
+
`no-auto`/`blocked`/`manual`-class tags can never route, but each occupied one
|
|
73
|
+
of the bounded candidate rows every tick just to be rejected by eligibility —
|
|
74
|
+
enough marked tasks starved a drain into `considered=N created=0` forever.
|
|
75
|
+
They are now held out of the window before slicing (unless the drain's own
|
|
76
|
+
`--tags` explicitly selects that tag) and counted as `excludedDisallowedTag`
|
|
77
|
+
in drain reports, so the exclusion is auditable.
|
|
78
|
+
- **Deterministic gate deaths are bounded by a secondary ceiling:** gate deaths
|
|
79
|
+
(runs that fail at worktree prep or a fast triage/planner gate before any real
|
|
80
|
+
work) refund their redispatch attempt — correct for transient faults, but a
|
|
81
|
+
deterministic fault would retry forever at the backoff floor. Work items now
|
|
82
|
+
count consecutive gate deaths (`gate_deaths`, additive migration
|
|
83
|
+
`0011_work_item_gate_deaths`, no schema `user_version` bump); at the ceiling
|
|
84
|
+
(20) the item is dead-lettered — visible in drain reports — instead of
|
|
85
|
+
spinning, and the bounded route re-admission will not requeue it. A
|
|
86
|
+
productive failure or an `exit 75` tempfail (runs that reached the worker)
|
|
87
|
+
resets the streak; `loops routes requeue` (default attempts reset) re-arms
|
|
88
|
+
the full ceiling. Known gap (review finding N1; fix queued for the next
|
|
89
|
+
patch): a non-closing SUCCESS does not yet reset the streak — bounded and
|
|
90
|
+
safe (it errs toward a recoverable early dead-letter, and the redispatch cap
|
|
91
|
+
independently bounds chronically non-closing successes).
|
|
92
|
+
- **Redispatch cap no longer a silent black hole** (the original #82 core: a
|
|
93
|
+
still-actionable task whose runs kept finishing without closing it was
|
|
94
|
+
deduped forever once its attempt count reached the cap): when a todos-task
|
|
95
|
+
work item reaches `MAX_TODOS_TASK_ROUTE_REDISPATCHES` (8) it is transitioned
|
|
96
|
+
to a visible `dead_letter` state instead of being deduped forever with no
|
|
97
|
+
signal. Drain reports gain a `deadLettered` count (and the deduped result
|
|
98
|
+
carries `deadLettered: true` + the reason), so a capped task is surfaced and
|
|
99
|
+
an operator can requeue it rather than the drain silently reporting
|
|
100
|
+
`created=0`.
|
|
101
|
+
- **Gate deaths no longer count toward the cap:** a run that dies before doing
|
|
102
|
+
real work — worktree preparation failure, or a fast (`<60s`) `triage`/`planner`
|
|
103
|
+
gate failure — has its attempt refunded by `finalizeWorkflowRun`, so an infra
|
|
104
|
+
fault cannot dead-letter a task that never reached its worker.
|
|
105
|
+
- **`exit(75)` tempfail is requeueable, not dedupe-bait:** a step that exits 75
|
|
106
|
+
(`EX_TEMPFAIL`, "retry later") drops its work item back to `queued` with the
|
|
107
|
+
attempt refunded, so the "retry next tick" contract fires instead of leaving a
|
|
108
|
+
terminal row that counts toward the cap.
|
|
109
|
+
- **`loops routes requeue` resets attempts by default:** an operator unwedge is
|
|
110
|
+
now durable rather than one-shot (a capped item no longer re-caps after a
|
|
111
|
+
single further terminal run). `--keep-attempts` preserves the count for the
|
|
112
|
+
cautious path; the bounded route-path re-admission still preserves attempts so
|
|
113
|
+
the cap keeps working.
|
|
114
|
+
- **Executor self-heals a stale worktree registration:** on git's "missing but
|
|
115
|
+
already registered worktree" error, `ensureLocalWorktree` (and the remote
|
|
116
|
+
worktree-prep script) now runs `git worktree prune` and retries the add exactly
|
|
117
|
+
once — git's own prescribed remedy — before failing honestly. This removes the
|
|
118
|
+
single biggest burner of the redispatch cap at its source.
|
|
119
|
+
|
|
120
|
+
### Changed
|
|
121
|
+
|
|
122
|
+
- **Newer-schema databases soft-open when the delta is non-breaking:** an older
|
|
123
|
+
binary used to refuse ANY database with a newer `PRAGMA user_version` — during
|
|
124
|
+
the 2026-07-07 schema-8 lockout that bricked the whole CLI fleet over purely
|
|
125
|
+
additive migrations. The database now carries a compatibility floor
|
|
126
|
+
(`schema_compat.min_compatible_user_version`, raised only by BREAKING
|
|
127
|
+
migrations; additive ones leave it untouched): a binary opens any newer
|
|
128
|
+
database whose floor it meets, preserves the newer `user_version` stamp
|
|
129
|
+
(never downgrades it), and refuses only on a known-breaking delta or when the
|
|
130
|
+
floor row is absent (pre-contract/unblessed databases stay conservative).
|
|
131
|
+
|
|
132
|
+
## 0.4.15 – 0.4.17 (2026-07-06/07 — unpublished; first shipped with 0.4.18)
|
|
133
|
+
|
|
134
|
+
These three versions were committed to `main` with version bumps but never
|
|
135
|
+
published to npm individually; the 0.4.18 release is the first registry artifact
|
|
136
|
+
that carries them. Consolidated here so the published history stays honest.
|
|
137
|
+
|
|
138
|
+
### Added
|
|
139
|
+
|
|
140
|
+
- **0.4.15** — self-hosted client mode: the CLI routes loop reads/writes to the
|
|
141
|
+
hosted `/v1` API when `self_hosted` mode is configured (#74).
|
|
142
|
+
- **0.4.16** — id-preserving bulk import endpoint (`POST /v1/import`) for
|
|
143
|
+
self-hosted backfill, plus `loops self-hosted push --apply` in the CLI (#76).
|
|
144
|
+
- **0.4.17** — `GET /v1/loops/count` and `GET /v1/runs/count` endpoints (#77).
|
|
145
|
+
- Run receipt contract: run receipts table + API surface for verifiable run
|
|
146
|
+
evidence (`migrations/0005_run_receipts.sql` mirror).
|
|
147
|
+
|
|
148
|
+
### Changed
|
|
149
|
+
|
|
150
|
+
- **SQLite schema `user_version` 7 → 8** via ledger migrations
|
|
151
|
+
`0009_run_receipts` and `0010_work_item_machine_id` (additive; applied
|
|
152
|
+
automatically on first open). NOTE: binaries older than this range refuse to
|
|
153
|
+
open a migrated database ("schema version 8 is newer than this binary
|
|
154
|
+
supports"), so downgrading below 0.4.15 after opening a database with this
|
|
155
|
+
release requires restoring a pre-upgrade backup. A version-tolerance softening
|
|
156
|
+
(open unless a known-breaking delta) is planned follow-up work.
|
|
157
|
+
- Launch-gated route drains: `--launch-gate`/`--launch-gate-blocker` hold a
|
|
158
|
+
drain closed until named blocker tasks are completed.
|
|
159
|
+
|
|
160
|
+
### Fixed
|
|
161
|
+
|
|
162
|
+
- codewith agent JSON output parsing (#17).
|
|
163
|
+
- PR handoff: no-remote fallback repaired and handoff artifact errors scrubbed
|
|
164
|
+
from templates.
|
|
165
|
+
|
|
45
166
|
## 0.4.14 (2026-07-06)
|
|
46
167
|
|
|
47
168
|
Self-hosted control-plane service brought to the full Hasna standard: all four
|
package/README.md
CHANGED
|
@@ -85,6 +85,12 @@ HASNA_LOOPS_DATABASE_URL=... loops-serve migrate --dry-run
|
|
|
85
85
|
loops-runner status
|
|
86
86
|
```
|
|
87
87
|
|
|
88
|
+
`loops self-hosted push` is safe by default: imported workflows are archived and
|
|
89
|
+
imported loops are paused with `nextRunAt`/`retryScheduledFor` cleared. Even
|
|
90
|
+
without `--replace`, the control-plane import boundary may rewrite existing
|
|
91
|
+
same-id workflows/loops into that disabled representation; use explicit
|
|
92
|
+
preserve flags only for an intentional activation.
|
|
93
|
+
|
|
88
94
|
See [Deployment Modes](docs/DEPLOYMENT_MODES.md) for the full package boundary
|
|
89
95
|
and machine-placement contract.
|
|
90
96
|
|