@hasna/loops 0.4.2 → 0.4.4

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.
@@ -23,7 +23,7 @@ tokens, Postgres, or hosted infrastructure.
23
23
  client and runner contract, but tenant auth, account administration, and hosted
24
24
  infrastructure stay outside this package. The public package must not depend on
25
25
  private hosted packages or resource names. This release exposes status
26
- surfaces only; non-local claim/lease execution is follow-up work.
26
+ surfaces only.
27
27
 
28
28
  ## Mode Resolution
29
29
 
@@ -51,9 +51,18 @@ strings, and fragments are not returned in status output.
51
51
  loops mode
52
52
  loops --json mode
53
53
  loops self-hosted status
54
+ loops self-hosted migrate --dry-run
55
+ loops self-hosted push --dry-run
56
+ loops self-hosted pull --dry-run
57
+ loops self-hosted runner-register --runner-id <id> --machine-id <machine>
58
+ loops self-hosted runner-register --runner-id <id> --machine-id <machine> --apply
54
59
  loops cloud status
55
60
  loops-api status
56
61
  loops-runner status
62
+ loops export --file ./loops-export.json --dry-run
63
+ loops export --file ./loops-export.json
64
+ loops import ./loops-export.json
65
+ loops import ./loops-export.json --apply
57
66
  ```
58
67
 
59
68
  Human status output is intentionally compact:
@@ -89,9 +98,67 @@ platform host.
89
98
  plane. The current public package supports a bounded one-shot protocol:
90
99
  registration, claim polling, claim-token fenced heartbeat/finalization, and
91
100
  `loops-runner run-once` execution for non-workflow targets. Full fleet daemon
92
- mode, workflow target execution over the remote protocol, and import/export
93
- migration still need follow-up releases before `loops-runner` is advertised as
94
- a complete always-on worker.
101
+ mode and workflow target execution over the remote protocol still need
102
+ follow-up releases before `loops-runner` is advertised as a complete always-on
103
+ worker.
104
+
105
+ ## Migration And Sync
106
+
107
+ Local migration commands are available now:
108
+
109
+ ```bash
110
+ loops export --file ./loops-export.json
111
+ loops export --file ./loops-export.json --dry-run
112
+ loops import ./loops-export.json
113
+ loops import ./loops-export.json --apply
114
+ ```
115
+
116
+ `loops export` writes an id-preserving JSON bundle for the supported local
117
+ state: workflow specs, loop definitions, and terminal loop run history. The
118
+ bundle includes schema version, package version, row counts, row hashes, and
119
+ no-loss checks. Use `--dry-run` to preview the bundle without writing a file.
120
+ Inline command `env` values are treated as unsafe for export; the command
121
+ refuses to write a no-loss bundle unless the operator explicitly uses
122
+ `--allow-redacted`, which produces a non-importable redacted bundle.
123
+
124
+ `loops import` is a dry-run by default. It reports exact per-row actions:
125
+ `insert`, `update`, `skip`, `conflict`, and `blocked`. Applying an import
126
+ requires `--apply`; existing rows with the same id are updated only with
127
+ `--replace`. The CLI creates a local SQLite backup before a safe apply.
128
+
129
+ No-loss validation blocks unsupported or live state instead of silently
130
+ dropping it. The current migration bundle does not preserve workflow invocation
131
+ rows, workflow work items, workflow run/step/event history, or goal run history.
132
+ If those tables contain rows, the export/import plan is non-importable until a
133
+ later release adds full table-preserving migration. Active daemon leases,
134
+ running loop runs, running workflow runs/steps, and leased work items also
135
+ block migration; finish or stop that work first.
136
+
137
+ Self-hosted sync commands are preview-only today:
138
+
139
+ ```bash
140
+ loops self-hosted migrate --dry-run
141
+ loops self-hosted push --dry-run
142
+ loops self-hosted pull --dry-run
143
+ ```
144
+
145
+ They inspect local state, optionally inspect `LOOPS_API_URL`, and report the
146
+ rows that would need to move. Remote apply is intentionally blocked because the
147
+ current self-hosted API exposes normal loop CRUD and run listing, not
148
+ id-preserving workflow/loop/run import endpoints. A normal remote loop create
149
+ would generate new ids, so it is not a no-loss migration. Local SQLite remains
150
+ authoritative until a safe import is applied; in non-local modes it may remain
151
+ a cache, offline spool, and audit copy.
152
+
153
+ `loops self-hosted runner-register` is also preview-only unless `--apply` is
154
+ present. The dry run prints the runner id, machine id, labels, and
155
+ capabilities that would be posted, without exposing tokens.
156
+
157
+ Cross-machine rollout evidence should record: machine id/hostname, package
158
+ version, git/build version, command run, dry-run or apply mode, redacted API
159
+ URL, source and target store ids, backup path, bundle hash, schema version,
160
+ row counts, conflicts, blocked rows, runner registration id, daemon/runner
161
+ status, and timestamp.
95
162
 
96
163
  ## Machine Placement
97
164
 
@@ -120,7 +187,8 @@ Non-local execution needs these follow-up releases before it is live:
120
187
  - Long-running runner daemon mode with backoff, fleet observability, and
121
188
  durable machine registration records.
122
189
  - Workflow target execution over the remote protocol.
123
- - Import/export migration between local SQLite state and a control plane.
190
+ - Id-preserving self-hosted import endpoints for workflow specs, loop
191
+ definitions, run history, workflow history, work items, goals, and audit rows.
124
192
  - Hosted product integration outside the public package.
125
193
 
126
194
  ## Public Package Boundary
package/docs/USAGE.md CHANGED
@@ -19,7 +19,8 @@ defines `self_hosted` and `cloud` contracts for future non-local control
19
19
  planes:
20
20
 
21
21
  - `self_hosted`: user-operated `loops-api` control-plane contract; this
22
- release exposes API/runner status foundations only.
22
+ release exposes storage-backed API/runner foundations plus local migration
23
+ previews.
23
24
  - `cloud`: hosted control-plane contract; this release exposes client/runner
24
25
  status only, and requires `LOOPS_CLOUD_API_URL` plus `LOOPS_CLOUD_TOKEN` or
25
26
  `HASNA_LOOPS_CLOUD_TOKEN` before status can report ready.
@@ -30,11 +31,61 @@ Useful status commands:
30
31
  loops mode
31
32
  loops --json mode
32
33
  loops self-hosted status
34
+ loops self-hosted migrate --dry-run
35
+ loops self-hosted push --dry-run
36
+ loops self-hosted pull --dry-run
37
+ loops self-hosted runner-register --runner-id <id> --machine-id <machine>
38
+ loops self-hosted runner-register --runner-id <id> --machine-id <machine> --apply
33
39
  loops cloud status
34
40
  loops-api status
35
41
  loops-runner status
36
42
  ```
37
43
 
44
+ ## Migration And Sync
45
+
46
+ Export a supported local bundle:
47
+
48
+ ```bash
49
+ loops export --file ./loops-export.json
50
+ loops export --file ./loops-export.json --dry-run
51
+ ```
52
+
53
+ Preview and apply it into another local store:
54
+
55
+ ```bash
56
+ loops import ./loops-export.json
57
+ loops import ./loops-export.json --apply
58
+ ```
59
+
60
+ `loops import` is dry-run by default and prints row actions (`insert`,
61
+ `update`, `skip`, `conflict`, `blocked`) with hashes and reasons. `--apply`
62
+ creates a SQLite backup first. Existing ids are not overwritten unless
63
+ `--replace` is used and the dry-run has no conflicts or blockers.
64
+
65
+ No-loss export/import currently preserves workflow specs, loop definitions, and
66
+ terminal loop run history. It intentionally blocks when unsupported durable
67
+ tables contain rows (workflow invocations/work items, workflow run/step/event
68
+ history, goal history) or when active runtime ownership exists (active daemon
69
+ leases, running runs, leased work items). Inline command env values are not
70
+ exported as secrets; bundles with redacted env values require
71
+ `--allow-redacted` and are marked non-importable.
72
+
73
+ Self-hosted sync commands are preview-only until the control-plane API exposes
74
+ id-preserving import endpoints:
75
+
76
+ ```bash
77
+ loops self-hosted migrate --dry-run
78
+ loops self-hosted push --dry-run
79
+ loops self-hosted pull --dry-run
80
+ ```
81
+
82
+ The preview may inspect `LOOPS_API_URL`/`HASNA_LOOPS_API_URL`, but it refuses
83
+ remote apply because normal loop CRUD would generate new ids. Use
84
+ `loops self-hosted runner-register` to verify runner registration against an
85
+ API, then use `loops-runner run-once` for the current bounded non-workflow
86
+ claim/execute/finalize protocol.
87
+ Runner registration is preview-only unless `--apply` is present.
88
+
38
89
  ## Install
39
90
 
40
91
  **OpenLoops requires the [Bun](https://bun.sh) runtime (`bun >= 1.0`).** The
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hasna/loops",
3
- "version": "0.4.2",
3
+ "version": "0.4.4",
4
4
  "description": "Persistent local loop and workflow runner for deterministic commands and headless AI coding agents",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -74,7 +74,7 @@
74
74
  "prepare": "test -d dist || bun run build",
75
75
  "dev:cli": "bun run src/cli/index.ts",
76
76
  "dev:daemon": "bun run src/daemon/index.ts",
77
- "prepublishOnly": "bun run build && bun run test:boundary"
77
+ "prepublishOnly": "bun run build && bun run typecheck && bun test && bun run test:boundary"
78
78
  },
79
79
  "keywords": [
80
80
  "loops",