reffy-cli 1.4.2 → 1.7.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/README.md CHANGED
@@ -33,7 +33,8 @@ Command summary:
33
33
  - `reffy plan create`: generates proposal, task, design, and spec scaffolds from indexed Reffy artifacts.
34
34
  - `reffy plan validate|list|show|archive`: manages the planning lifecycle under `.reffy/reffyspec/`.
35
35
  - `reffy spec list|show`: inspects current spec state under `.reffy/reffyspec/`.
36
- - `reffy remote init|status|push|ls|cat`: links, publishes, and inspects a Paseo-backed remote `.reffy/` workspace.
36
+ - `reffy remote init|status|push|ls|cat|snapshot`: links, publishes, and inspects a Paseo-backed remote `.reffy/` workspace.
37
+ - `reffy remote workspace create|get` and `reffy remote project register|list`: control-plane operations against the workspace manager actor.
37
38
  - `reffy diagram render`: renders Mermaid diagrams as SVG or ASCII, including spec-aware generation from compatible `spec.md` files.
38
39
 
39
40
  Output modes:
@@ -65,83 +66,115 @@ reffy diagram render --input .reffy/reffyspec/specs/auth/spec.md --format ascii
65
66
  reffy diagram render --input .reffy/reffyspec/specs/auth/spec.md --format svg --output .reffy/artifacts/auth-spec.svg
66
67
  ```
67
68
 
68
- ## Remote Backend Helper
69
-
70
- Reffy includes a Paseo helper bridge at `scripts/reffy-remote-backend-demo.mjs`.
71
-
72
- The helper:
69
+ ## Remote Sync
73
70
 
74
- - loads `.env` automatically when present
75
- - reads `project_id` and `workspace_name` from `.reffy/manifest.json`
76
- - provisions or links a Paseo `reffyRemoteBackend` actor
77
- - imports the local `.reffy/` workspace
71
+ Reffy can publish the local `.reffy/` workspace to a Paseo-backed remote workspace and inspect it later with native CLI commands.
78
72
 
79
- Expected environment variables:
73
+ The Paseo remote splits into two actor surfaces:
80
74
 
81
- - `PASEO_ENDPOINT` - required unless already exported in the shell
82
- - `PASEO_POD_NAME` - optional existing pod override
83
- - `PASEO_ACTOR_ID` - optional existing actor override
75
+ - `reffyWorkspaceManager.v1` is the **control plane**. It owns workspace lifecycle (create / get) and project registration.
76
+ - `reffyRemoteBackend.v2` is the **storage plane**. One actor instance represents one shared `workspace_id` and accepts contributions keyed by `project_id`.
84
77
 
85
- Examples:
78
+ Reffy stores manager identity once per linkage file and the workspace backend identity per `workspace_id`.
86
79
 
87
- ```bash
88
- npm run remote:backend:demo
89
- reffy remote init --provision
90
- reffy remote push
91
- ```
80
+ The current remote flow is:
92
81
 
93
- ## Remote Sync
82
+ 1. Reffy reads `project_id` and `workspace_ids` from `.reffy/manifest.json`.
83
+ 2. You select one workspace projection to act on. Reffy infers the selection when `workspace_ids` has exactly one entry; otherwise pass `--workspace-id <id>`.
84
+ 3. Reffy connects to Paseo using `PASEO_ENDPOINT` or `--endpoint` and configured manager identity.
85
+ 4. `reffy remote init` resolves (or creates) the workspace through the manager, persists the workspace backend identity, and registers the local `project_id` for that workspace.
86
+ 5. `reffy remote push` registers the project if needed (idempotent on 409), then imports the full local `.reffy/` tree through `POST /workspace/projects/{project_id}/import` on the workspace backend actor with `replace_missing=true`.
87
+ 6. `reffy remote status|ls|cat|snapshot` inspects the selected workspace projection per project on the workspace backend actor.
94
88
 
95
- Reffy can publish the local `.reffy/` workspace to a Paseo-backed remote actor and inspect it later with native CLI commands.
89
+ ### Bearer-token authentication
96
90
 
97
- The current remote flow is:
91
+ Every Paseo request from the CLI carries `Authorization: Bearer ${PASEO_TOKEN}`. The token is the only thing that grants access — manager / workspace-backend identifiers in `.reffy/state/remote.json` are inert without it.
98
92
 
99
- 1. Reffy reads `project_id` and `workspace_name` from `.reffy/manifest.json`.
100
- 2. Reffy connects to Paseo using `PASEO_ENDPOINT` or `--endpoint`.
101
- 3. `reffy remote init --provision` creates a pod and actor when needed, then writes local linkage state to `.reffy/state/remote.json`.
102
- 4. `reffy remote push` publishes the local workspace to that linked actor with `replace_missing=true` by default, so remote reflects local.
103
- 5. `reffy remote status|ls|cat` inspects the linked remote workspace using the saved linkage state unless you override it.
93
+ Required env for any remote command:
104
94
 
105
- ### Minimal connection requirement
106
-
107
- For the fresh-provision path, the only required connection value is:
95
+ ```bash
96
+ PASEO_ENDPOINT="https://your-paseo-endpoint.example"
97
+ PASEO_TOKEN="<bearer token issued by manager provisioning>"
98
+ ```
108
99
 
109
- - `PASEO_ENDPOINT`
100
+ Both must be present; the CLI fails fast and names the missing variable before issuing any network call. Endpoint is **never** persisted to `remote.json`. The token is **never** persisted anywhere by the CLI.
110
101
 
111
- Example `.env`:
102
+ ### First-time provisioning
112
103
 
113
104
  ```bash
114
- PASEO_ENDPOINT="https://your-paseo-endpoint.example"
105
+ PASEO_ENDPOINT="https://your-paseo-endpoint.example" reffy remote init --provision
115
106
  ```
116
107
 
117
- That is enough for:
108
+ `--provision` creates a fresh pod and `reffyWorkspaceManager.v1` actor. The manager mints a bearer token and the CLI prints it once with strong "save this now" guidance. Save it to your team secret store immediately — the CLI does not keep a copy.
109
+
110
+ After provisioning, export it for subsequent commands:
118
111
 
119
112
  ```bash
120
- reffy remote init --provision
113
+ export PASEO_TOKEN="<token from init output>"
114
+ reffy remote status
121
115
  ```
122
116
 
123
117
  Optional overrides:
124
118
 
125
- - `PASEO_POD_NAME` if you want to reuse an existing Paseo pod
126
- - `PASEO_ACTOR_ID` if you want to reuse an existing backend actor
119
+ - `PASEO_MANAGER_POD` and `PASEO_MANAGER_ACTOR` (or `--manager-pod` / `--manager-actor`) to reuse an existing manager actor instead of provisioning one.
120
+ - `--workspace-id <id>` when the manifest lists more than one `workspace_ids`.
121
+ - `--create` or `--resolve` to force-create or force-resolve the workspace through the manager during init. The default is "resolve when present, create when absent."
127
122
 
128
- Reffy does not require separate `REFFY_PROJECT_ID` or `REFFY_WORKSPACE_NAME` values for the normal case because those come from `.reffy/manifest.json`.
123
+ ### Joining an existing manager from another repo
124
+
125
+ Drop the team's shared values into the new repo's `.env`:
126
+
127
+ ```bash
128
+ PASEO_ENDPOINT="..."
129
+ PASEO_TOKEN="..."
130
+ PASEO_MANAGER_POD="..."
131
+ PASEO_MANAGER_ACTOR="..."
132
+ ```
133
+
134
+ Then `reffy remote init --workspace-id <id>` resolves the workspace through the manager and registers the local project. No `--provision`, no new token issuance.
129
135
 
130
136
  ### Saved remote linkage
131
137
 
132
- After `reffy remote init`, Reffy stores the local pointer to the linked backend actor in:
138
+ After `reffy remote init`, Reffy stores manager and workspace-backend identifiers in:
133
139
 
134
140
  - `.reffy/state/remote.json`
135
141
 
136
- That file contains the connection tuple Reffy uses to reach the backend:
142
+ ```json
143
+ {
144
+ "version": 4,
145
+ "provider": "paseo",
146
+ "manager": { "pod_name": "...", "actor_id": "..." },
147
+ "targets": {
148
+ "my-project": {
149
+ "workspace_backend": { "pod_name": "...", "actor_id": "..." },
150
+ "last_imported_at": "..."
151
+ },
152
+ "portfolio-alpha": {
153
+ "workspace_backend": { "pod_name": "...", "actor_id": "..." }
154
+ }
155
+ }
156
+ }
157
+ ```
158
+
159
+ Each `workspace_id` is its own backend actor. Manager identity is shared across workspaces in this linkage file.
160
+
161
+ The file deliberately does **not** contain the Paseo endpoint URL or the bearer token. Both are sourced from environment configuration on every command. Without `PASEO_TOKEN`, the identifiers in this file grant nothing.
162
+
163
+ If `workspace_backend` for a workspace is missing or stale, Reffy automatically resolves it through the manager and refreshes the linkage file before continuing.
137
164
 
138
- - `endpoint`
139
- - `pod_name`
140
- - `actor_id`
165
+ ### Control-plane subcommands
141
166
 
142
- This file is local runtime state. It is not part of the synced remote workspace and is intentionally excluded from `reffy remote push`.
167
+ ```bash
168
+ reffy remote workspace create <workspace-id> [--label "Pretty name"]
169
+ reffy remote workspace get <workspace-id>
170
+ reffy remote workspace delete <workspace-id> --yes
171
+ reffy remote project register [--workspace-id <id>] [--project-id <id>]
172
+ reffy remote project list [--workspace-id <id>]
173
+ ```
174
+
175
+ `workspace delete` is destructive (it removes the shared workspace and all of its contributions) and requires `--yes` to proceed. The CLI also drops the workspace entry from the local linkage file on success, and treats a `404` from the manager as an idempotent "already gone" outcome.
143
176
 
144
- The file can also record local sync metadata such as the last successful import timestamp. That metadata is for local diagnostics and does not become part of the remote workspace contract.
177
+ These talk directly to the manager actor and let you provision or inspect state without re-running `init`.
145
178
 
146
179
  ### Example flow
147
180
 
@@ -152,28 +185,28 @@ reffy remote status
152
185
  reffy remote push
153
186
  reffy remote ls
154
187
  reffy remote cat .reffy/manifest.json
188
+ reffy remote snapshot
155
189
  ```
156
190
 
157
- `reffy remote status` is the primary diagnostic command for this flow. It reports:
191
+ `reffy remote status` reports:
158
192
 
159
- - the saved linkage being used
160
- - the local manifest identity
161
- - the remote workspace identity
162
- - remote document counts when reachable
193
+ - the saved manager and workspace backend linkage for the selected workspace id
194
+ - the local manifest identity (source `project_id` and selected `workspace_id`)
195
+ - the remote workspace identity (`workspace.workspace_id`, `source.actor_type`, `source.version`)
196
+ - remote document counts and registered project counts when available
163
197
 
164
198
  `reffy remote push` reports:
165
199
 
200
+ - whether the project was newly registered or already registered
166
201
  - local document count
167
- - imported count
168
- - created count
169
- - updated count
170
- - deleted count
202
+ - imported / created / updated / deleted counts
203
+ - last imported timestamp
171
204
 
172
205
  That makes the default prune/import behavior auditable without dropping to direct backend API calls.
173
206
 
174
207
  ## Manifest Contract
175
208
 
176
- Reffy keeps workspace metadata in `.reffy/manifest.json`. New managed manifests include both core timestamps and workspace identity:
209
+ Reffy keeps workspace metadata in `.reffy/manifest.json`. New managed manifests separate stable source identity (`project_id`) from plural workspace membership (`workspace_ids`):
177
210
 
178
211
  ```json
179
212
  {
@@ -181,12 +214,21 @@ Reffy keeps workspace metadata in `.reffy/manifest.json`. New managed manifests
181
214
  "created_at": "2026-04-18T00:00:00.000Z",
182
215
  "updated_at": "2026-04-18T00:00:00.000Z",
183
216
  "project_id": "my-project",
184
- "workspace_name": "my-project",
217
+ "workspace_ids": ["my-project"],
185
218
  "artifacts": []
186
219
  }
187
220
  ```
188
221
 
189
- Older v1 manifests without `project_id` and `workspace_name` still validate. Running `reffy init` migrates managed manifests by adding those fields with deterministic defaults derived from the repository name.
222
+ A single `.reffy/` tree can belong to more than one planning workspace:
223
+
224
+ ```json
225
+ {
226
+ "project_id": "my-project",
227
+ "workspace_ids": ["my-project", "portfolio-alpha", "nuveris-cross-project-planning"]
228
+ }
229
+ ```
230
+
231
+ Running `reffy init` populates `project_id` and `workspace_ids` with deterministic defaults derived from the repository name for any managed manifest that is missing them.
190
232
 
191
233
  ## Using Reffy With ReffySpec
192
234