@fadhilp/stateql 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.
Files changed (2) hide show
  1. package/README.md +227 -127
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -1,20 +1,28 @@
1
1
  # StateQL
2
2
 
3
- StateQL is a stateful database CLI for AI agents and automation. It provides a
4
- safe interface for querying, changing, and inspecting databases while keeping
5
- results reusable and operations traceable across commands.
3
+ StateQL is a stateful database CLI and TypeScript library for AI agents and
4
+ automation. It provides a safe interface for querying, changing, and inspecting
5
+ SQLite, PostgreSQL, and MySQL databases while keeping results reusable and
6
+ operations traceable across commands.
7
+
8
+ StateQL is built around durable handles:
9
+
10
+ 1. Run a query and receive a result handle such as `q_1`.
11
+ 2. Reuse, filter, page, count, alias, or export that stored result without
12
+ rerunning the original SQL.
13
+ 3. Use operation, plan, and transaction handles to inspect and control writes.
6
14
 
7
15
  Requires Node.js 22.5 or newer.
8
16
 
9
17
  ## Quick start
10
18
 
19
+ Install the CLI:
20
+
11
21
  ```bash
12
22
  npm install -g @fadhilp/stateql
13
23
  ```
14
24
 
15
- Connect to an existing SQLite database, then run a filtered, parameterized
16
- query. Parameters keep values separate from SQL; `ORDER BY` makes paging
17
- stable, while `LIMIT` bounds work at the database.
25
+ Connect to an existing SQLite database and run a bounded, parameterized query:
18
26
 
19
27
  ```bash
20
28
  export STQL_SESSION=audit
@@ -27,14 +35,16 @@ stql query \
27
35
  --param 2026-01-01
28
36
  ```
29
37
 
30
- Example output:
38
+ Parameters keep values separate from SQL. `ORDER BY` makes paging stable, and
39
+ `LIMIT` bounds work at the database. The default `agent` output is compact,
40
+ one-line JSON:
31
41
 
32
42
  ```json
33
43
  {"ok":true,"handle":"q_1","rows":[{"id":7,"name":"Ada","email":"ada@example.com"},{"id":12,"name":"Grace","email":"grace@example.com"},{"id":18,"name":"Linus","email":"linus@kernel.org"}],"truncated":false,"cached":false,"total":3,"next_offset":null}
34
44
  ```
35
45
 
36
- `q_1` is a durable result handle. Filter its stored snapshot without querying
37
- the original database; the result becomes another durable handle:
46
+ `q_1` is a durable snapshot. Filter it locally without accessing the original
47
+ database:
38
48
 
39
49
  ```bash
40
50
  stql filter q_1 "email LIKE ?" --param "%@example.com"
@@ -44,8 +54,8 @@ stql filter q_1 "email LIKE ?" --param "%@example.com"
44
54
  {"ok":true,"handle":"q_2","rows":[{"id":7,"name":"Ada","email":"ada@example.com"},{"id":12,"name":"Grace","email":"grace@example.com"}],"truncated":false,"cached":false,"total":2,"next_offset":null}
45
55
  ```
46
56
 
47
- Give the derived result a readable alias, page through it, inspect its count,
48
- or export it—all without rerunning SQL:
57
+ The filtered snapshot receives its own handle. Give it a readable alias, page
58
+ through it, inspect its count, or export it without rerunning SQL:
49
59
 
50
60
  ```bash
51
61
  stql alias set example-users q_2
@@ -62,7 +72,22 @@ Example first page:
62
72
  ```
63
73
 
64
74
  Running the same normalized query with the same parameters reuses `q_1` while
65
- its cache is valid. Use `--cache bypass` when a fresh read is required.
75
+ its cache entry is valid. Use `--cache bypass` when a fresh read is required.
76
+
77
+ ## Connections and profiles
78
+
79
+ A connection accepts exactly one source: a direct target, `--env`, or
80
+ `--profile`.
81
+
82
+ ```bash
83
+ stql connect <sqlite-path|postgres-url|mysql-url> [--name NAME] [--read-write]
84
+ stql connect --env ENV [--name NAME] [--read-write]
85
+ stql connect --profile NAME
86
+ stql disconnect
87
+ stql status
88
+ ```
89
+
90
+ ### Environment-backed credentials
66
91
 
67
92
  PostgreSQL and MySQL credentials should come from environment variables. The
68
93
  variable must contain the complete connection URL, not only its password.
@@ -79,21 +104,45 @@ export SQLITE_DATABASE='sqlite:./app.sqlite'
79
104
  stql connect --env SQLITE_DATABASE --name local --read-only
80
105
  ```
81
106
 
82
- A connection accepts exactly one direct target, `--env`, or `--profile` source.
83
- For PostgreSQL, StateQL preserves strict TLS verification by normalizing
84
- `sslmode=prefer`, `require`, and `verify-ca` to `verify-full` before opening the
85
- adapter. Use `sslmode=verify-full` explicitly for clarity. Setting
86
- `uselibpqcompat=true` opts out and keeps libpq-compatible SSL semantics.
107
+ StateQL stores no PostgreSQL or MySQL password. Credential-bearing URLs must be
108
+ supplied through `--env`. SQLite paths remain persisted as connection metadata.
109
+
110
+ ### Local profiles
111
+
112
+ Profiles store connection targets, read-only policy, and environment-variable
113
+ names. Credential values are never stored. Profiles persist under `STQL_HOME`
114
+ with other StateQL metadata.
115
+
116
+ ```bash
117
+ stql profile add local ./app.sqlite --read-write
118
+ stql profile add production --env PROD_DATABASE_URL --read-only
119
+ stql profile list
120
+ stql profile show production
121
+ stql connect local
122
+ stql connect --profile production
123
+ ```
124
+
125
+ A bare connection target matching a profile name resolves to that profile;
126
+ otherwise it remains a path or database URL.
127
+
128
+ ### Driver notes
87
129
 
88
- MySQL uses positional `?` parameters. MariaDB compatibility is not currently
89
- claimed.
130
+ - **SQLite:** use a filesystem path for direct connections or `sqlite:` for an
131
+ environment-backed path.
132
+ - **PostgreSQL:** StateQL preserves strict TLS verification by normalizing
133
+ `sslmode=prefer`, `require`, and `verify-ca` to `verify-full` before opening
134
+ the adapter. Use `sslmode=verify-full` explicitly for clarity. Setting
135
+ `uselibpqcompat=true` opts out and keeps libpq-compatible SSL semantics.
136
+ - **MySQL:** uses positional `?` parameters. MariaDB compatibility is not
137
+ currently claimed.
90
138
 
91
- ## Commands
139
+ ## CLI reference
92
140
 
93
141
  ```text
94
142
  stql connect <sqlite-path|postgres-url|mysql-url> [--name NAME] [--read-write]
95
143
  stql connect --env ENV [--name NAME] [--read-write]
96
144
  stql connect --profile NAME
145
+ stql disconnect
97
146
  stql status
98
147
  stql profile add|list|show|remove
99
148
  stql session start|list|show|summary|close
@@ -103,6 +152,7 @@ stql exec <sql> [--params JSON | --param VALUE...] [--idempotency-key KEY] [--re
103
152
  [--allow-unbounded] [--allow-destructive]
104
153
  stql show|count|columns <result-handle>
105
154
  stql rows <result-handle> [--offset N] [--limit N]
155
+ stql alias set <name> <result-handle>
106
156
  stql export <result-handle> --output FILE [--format json|jsonl|csv]
107
157
  stql inspect schema|table|columns|indexes|constraints [table]
108
158
  stql transaction begin|status|commit|rollback [--isolation LEVEL]
@@ -115,56 +165,128 @@ stql batch [commands.json|commands.jsonl|-] [--continue-on-error]
115
165
  stql pipe [--continue-on-error]
116
166
  ```
117
167
 
118
- Database commands accept `--timeout-ms N`; default is 30,000 ms. `Ctrl+C`
119
- cancels active work. SQLite runs in a killable child process so long synchronous
120
- statements cannot block StateQL's event loop. PostgreSQL uses server-side
121
- `statement_timeout` plus client deadlines. MySQL deadlines destroy the active
122
- connection. A timed-out write may return `OUTCOME_UNKNOWN` when commit status
123
- cannot be proven.
168
+ ### SQL parameters
124
169
 
125
- ## Output modes
170
+ For shell-safe positional parameters, repeat `--param`. JSON scalars become
171
+ their native types; other values remain strings.
126
172
 
127
- CLI output defaults to compact, one-line `agent` JSON. Successes flatten useful
128
- data and expose the primary durable ID as `handle`; errors retain their complete
129
- error object. Empty warnings and tracing metadata are omitted.
173
+ ```powershell
174
+ stql exec "INSERT INTO users (name, status) VALUES (?, ?)" `
175
+ --param Ada --param trial
176
+ ```
177
+
178
+ Use `--params JSON` for a JSON array or named parameters. Use
179
+ `--params-file FILE` when JSON is awkward to quote; `--params-file -` reads
180
+ JSON from standard input.
181
+
182
+ ### Output modes
183
+
184
+ CLI output defaults to compact, one-line `agent` JSON. Successful responses
185
+ flatten useful data and expose the primary durable ID as `handle`. Errors retain
186
+ their complete error object. Empty warnings and tracing metadata are omitted.
130
187
 
131
188
  ```json
132
189
  {"ok":false,"error":{"code":"UNBOUNDED_MUTATION","message":"Mutation has no WHERE clause.","retryable":false,"executed":false,"override_flag":"--allow-unbounded"}}
133
190
  ```
134
191
 
135
- Use `--output json` for the original pretty, verbose envelope, or
136
- `--output jsonl` for that envelope on one line. `--output text` prints a short
137
- human status; `--output silent` prints only a successful handle. Set
138
- `STQL_OUTPUT` to choose a mode globally. For `export`, `--output` names the
139
- file, so use `STQL_OUTPUT` to choose its response mode. Library responses keep
140
- the full envelope regardless of CLI mode.
192
+ Other modes are:
141
193
 
142
- For shell-safe positional parameters, repeat `--param`. JSON scalars become
143
- their native types; other values remain strings.
194
+ - `--output json`: original pretty, verbose envelope.
195
+ - `--output jsonl`: verbose envelope on one line.
196
+ - `--output text`: short human-readable status.
197
+ - `--output silent`: only a successful handle.
144
198
 
145
- ```powershell
146
- stql exec "INSERT INTO users (name, status) VALUES (?, ?)" `
147
- --param Ada --param trial
148
- ```
199
+ Set `STQL_OUTPUT` to choose a mode globally. For `export`, `--output` names the
200
+ file, so use `STQL_OUTPUT` to choose the command's response mode. Library
201
+ responses always keep the full envelope.
202
+
203
+ ### Deadlines and cancellation
204
+
205
+ Database commands accept `--timeout-ms N`; the default is 30,000 ms. `Ctrl+C`
206
+ cancels active work.
207
+
208
+ - SQLite runs in a killable child process so long synchronous statements cannot
209
+ block StateQL's event loop.
210
+ - PostgreSQL combines server-side `statement_timeout` with client deadlines.
211
+ - MySQL deadlines destroy the active connection.
212
+
213
+ A timed-out write may return `OUTCOME_UNKNOWN` when its commit status cannot be
214
+ proven.
215
+
216
+ ## Durable state and result reuse
217
+
218
+ State metadata lives under `STQL_HOME`, or the platform data directory when
219
+ unset. StateQL keeps connections, sessions, handles, aliases, cache entries,
220
+ plans, transactions, history, and receipts available across CLI invocations.
221
+
222
+ ### Sessions and actors
223
+
224
+ Set `STQL_SESSION` to select a named session and `STQL_ACTOR` to select an
225
+ attached actor. A session is a shared workspace: attached actors reuse its
226
+ connection, handles, aliases, cache, and state version. Plans and staged
227
+ transactions remain owned by the actor that created them.
228
+
229
+ Callers that omit `actor` keep the legacy behavior where the actor ID is the
230
+ session name.
149
231
 
150
- Use `--params-file FILE` for arrays or named parameters that are awkward to
151
- quote. `--params-file -` reads JSON from standard input.
232
+ ### Result lifetime and limits
152
233
 
153
- ## Local profiles
234
+ SQLite result rows are materialized locally for durable access. Read cache
235
+ entries expire after five minutes, and materialized handles expire after 24
236
+ hours. Expired results and plans are deleted the next time StateQL opens.
154
237
 
155
- Profiles persist under `STQL_HOME` with other StateQL metadata.
238
+ Queries exceeding 10,000 rows or 16 MiB of serialized row data fail before
239
+ persistence. Narrow the `WHERE` clause, add `LIMIT`, or select fewer columns.
240
+ These caps bound persisted materialization; the independent deadline bounds
241
+ execution time.
242
+
243
+ Command history keeps the latest 10,000 entries per session. SQLite cache reuse
244
+ also checks the database file signature. PostgreSQL and MySQL cache reuse is
245
+ labeled `ttl_based` and is never authoritative.
246
+
247
+ ### Local filtering
248
+
249
+ `filter` evaluates one scalar SQLite predicate against a stored result. It
250
+ preserves source order, state metadata, and expiry, and never accesses the
251
+ original database.
252
+
253
+ Use parameters for values. Subqueries, query-shaping clauses, and
254
+ non-allowlisted functions are rejected. Common deterministic functions such as
255
+ `lower`, `upper`, `length`, and `coalesce` are supported.
256
+
257
+ ## Write safety
258
+
259
+ Destructive and unbounded operations require `--allow-destructive` and
260
+ `--allow-unbounded`, respectively. The flags are independent.
261
+
262
+ `plan` validates and stores a write for later application. A plan persists only
263
+ the flags explicitly supplied when it is created; `apply` never adds
264
+ authorization.
265
+
266
+ Use an idempotency key to protect retryable writes from duplicate execution:
156
267
 
157
268
  ```bash
158
- stql profile add local ./app.sqlite --read-write
159
- stql profile add production --env PROD_DATABASE_URL --read-only
160
- stql profile list
161
- stql connect local
162
- stql connect --profile production
269
+ stql exec "UPDATE jobs SET claimed = 1 WHERE id = ?" \
270
+ --param 42 \
271
+ --idempotency-key claim-job-42
163
272
  ```
164
273
 
165
- A bare connection target matching a profile name resolves to that profile;
166
- otherwise it remains a path or database URL. Profiles store targets, read-only
167
- policy, and environment-variable names. Credential values are never stored.
274
+ If a write starts but StateQL cannot safely record its final outcome, it returns
275
+ `OUTCOME_UNKNOWN` and blocks automatic replay. Inspect database state before
276
+ using `--replay`. Interrupted commits remain fail-closed; stale `committing`
277
+ records become `outcome_unknown` after five minutes.
278
+
279
+ ### Transactions
280
+
281
+ Transactions are staged in local state so they survive CLI invocations, then
282
+ executed atomically on commit. While a transaction is active, StateQL rejects
283
+ database reads, plans, connection changes, and disconnects. Commit or roll back
284
+ first.
285
+
286
+ SQLite supports `serializable`. PostgreSQL and MySQL also support
287
+ `repeatable read`, `read committed`, and `read uncommitted`. Server reads run
288
+ inside database-enforced read-only transactions. MySQL staged transactions
289
+ reject DDL because MySQL implicitly commits those statements.
168
290
 
169
291
  ## Batch and pipes
170
292
 
@@ -173,6 +295,8 @@ policy, and environment-variable names. Credential values are never stored.
173
295
  the first error unless `--continue-on-error` is set. Output defaults to one
174
296
  compact `agent` JSON object per line.
175
297
 
298
+ Pipe commands directly:
299
+
176
300
  ```bash
177
301
  printf '%s\n' \
178
302
  '{"command":"query","sql":"SELECT id, email FROM users ORDER BY id","as":"users"}' \
@@ -181,6 +305,8 @@ printf '%s\n' \
181
305
  stql pipe
182
306
  ```
183
307
 
308
+ Or save a JSON array as `commands.json`:
309
+
184
310
  ```json
185
311
  [
186
312
  {
@@ -197,55 +323,21 @@ printf '%s\n' \
197
323
  ]
198
324
  ```
199
325
 
200
- Run the array with `stql batch commands.json`. Batch fields use snake case;
201
- supported command names match CLI paths, such as `filter`,
202
- `transaction.begin`, `session.summary`, `alias.set`, `plan`, and `apply`.
203
- Batch filters use `where` for the predicate and may assign the derived result
204
- with `as`. Database commands may set `timeout_ms`; otherwise they use the
205
- 30-second default.
206
-
207
- State metadata lives under `STQL_HOME`, or the platform data directory when
208
- unset. Set `STQL_SESSION` to select a named session and `STQL_ACTOR` to select
209
- an attached actor for CLI invocations. A session is a shared workspace:
210
- attached actors reuse its connection, handles, aliases, cache, and
211
- state version, while plans and staged transactions remain owned by their
212
- creating actor. Callers that omit `actor` keep the legacy behavior where the
213
- actor ID is the session name.
214
-
215
- Read cache entries expire after five minutes; materialized handles expire after
216
- 24 hours. Expired results and plans are deleted when StateQL next opens. Queries
217
- exceeding 10,000 rows or 16 MiB of serialized row data fail before persistence;
218
- add a narrower `WHERE` clause, `LIMIT`, or smaller column selection. These caps
219
- bound persisted materialization, while the independent deadline bounds execution
220
- time. Command history keeps the latest 10,000 entries per session. SQLite cache reuse also checks
221
- the database file signature; PostgreSQL and MySQL reuse is labeled `ttl_based`,
222
- never authoritative. Transactions are staged in local state so they survive CLI
223
- invocations, then executed atomically on commit. Database reads, plans,
224
- connection changes, and disconnects are rejected while a transaction is active;
225
- commit or roll back first. SQLite supports `serializable`;
226
- PostgreSQL and MySQL also support `repeatable read`, `read committed`, and
227
- `read uncommitted`. Server reads run inside database-enforced read-only
228
- transactions. MySQL staged transactions reject DDL because MySQL implicitly
229
- commits those statements.
326
+ ```bash
327
+ stql batch commands.json
328
+ ```
230
329
 
231
- StateQL stores no PostgreSQL or MySQL password. Credential-bearing URLs must be
232
- supplied through `--env`. SQLite result rows are materialized locally for
233
- durable access.
234
- `filter` evaluates one scalar SQLite predicate against those stored rows, keeps
235
- source order, state metadata, and expiry, and never accesses the original
236
- database. Use parameters for values. Subqueries, query-shaping clauses, and
237
- non-allowlisted functions are rejected; common deterministic functions such as
238
- `lower`, `upper`, `length`, and `coalesce` are supported.
330
+ Batch fields use snake case. Supported command names match CLI paths, such as
331
+ `filter`, `transaction.begin`, `session.summary`, `alias.set`, `plan`, and
332
+ `apply`. Batch filters use `where` for the predicate and may assign the derived
333
+ result with `as`. Database commands may set `timeout_ms`; otherwise they use the
334
+ 30-second default.
239
335
 
240
- Destructive and unbounded operations require their respective flags
241
- independently. Plans persist only flags explicitly supplied when the plan is
242
- created; `apply` never adds authorization. If a database write starts but its
243
- final outcome cannot be recorded safely, StateQL returns `OUTCOME_UNKNOWN` and
244
- blocks automatic replay. Inspect database state before using `--replay`.
245
- Interrupted commits remain fail-closed; stale `committing` records become
246
- `outcome_unknown` after five minutes.
336
+ ## TypeScript library
247
337
 
248
- ## Library
338
+ The package exports the same stateful operations for programmatic use. Library
339
+ responses retain the full response envelope regardless of the configured CLI
340
+ output mode.
249
341
 
250
342
  ```ts
251
343
  import { StateQL } from "@fadhilp/stateql";
@@ -256,11 +348,13 @@ const stateql = StateQL.forActor({
256
348
  timeoutMs: 30_000,
257
349
  maxResultBytes: 16 * 1024 * 1024,
258
350
  });
351
+
259
352
  const controller = new AbortController();
260
353
  const response = await stateql.query("SELECT * FROM users", {
261
354
  signal: controller.signal,
262
355
  timeoutMs: 5_000,
263
356
  });
357
+
264
358
  if (response.ok) {
265
359
  const handle = (response.data as { result_id: string }).result_id;
266
360
  await stateql.filter(handle, "email LIKE ?", {
@@ -269,6 +363,19 @@ if (response.ok) {
269
363
  }
270
364
  ```
271
365
 
366
+ ### Actor workspaces
367
+
368
+ `StateQL.forActor(...)` resolves the actor's attached session directly from
369
+ StateQL storage, avoiding a duplicate actor-to-session mapping in integrations.
370
+ On first use, it creates a legacy-compatible session named after the actor. Use
371
+ `new StateQL({ session, actor })` when the session is already known.
372
+
373
+ Membership is managed only through the library API, not batch commands:
374
+ `linkActor(session, actorId)`, `unlinkActor(session, actorId)`,
375
+ `listActors(session)`, and `resolveActor(actorId)`. An existing member must link
376
+ an actor before that actor opens an existing workspace. Integrations should ask
377
+ for user confirmation before changing membership or the shared connection.
378
+
272
379
  ### Harness credential resolution
273
380
 
274
381
  Library integrations can resolve a profile's credential reference through a
@@ -292,6 +399,7 @@ async function resolveCredential(
292
399
  access: request.access,
293
400
  signal: request.signal,
294
401
  });
402
+
295
403
  if (approved.denied) throw new CredentialResolutionError("denied");
296
404
  return approved.value;
297
405
  }
@@ -302,39 +410,31 @@ const stateql = StateQL.forActor({
302
410
  });
303
411
  ```
304
412
 
305
- When no custom resolver is configured, StateQL continues to read references
306
- from `process.env`. A configured resolver is authoritative: returning
307
- `undefined` produces `CREDENTIAL_UNAVAILABLE` and never falls back to the
308
- process environment. Resolvers may throw `CredentialResolutionError` with
309
- `denied`, `cancelled`, `timeout`, or `unavailable` to produce controlled,
310
- secret-free failures. Unknown resolver errors are replaced with a generic
413
+ When no custom resolver is configured, StateQL reads references from
414
+ `process.env`. A configured resolver is authoritative: returning `undefined`
415
+ produces `CREDENTIAL_UNAVAILABLE` and never falls back to the process
416
+ environment. Resolvers may throw `CredentialResolutionError` with `denied`,
417
+ `cancelled`, `timeout`, or `unavailable` to produce controlled, secret-free
418
+ failures. Unknown resolver errors are replaced with a generic
311
419
  `CREDENTIAL_RESOLUTION_FAILED` response.
312
420
 
313
421
  StateQL calls the resolver only immediately before database access, after SQL
314
- safety and duplicate checks. Requests contain actor/session identity, the
422
+ safety and duplicate checks. Requests contain actor and session identity, the
315
423
  operation's effective read/write access, an abort signal, and sanitized
316
- connection metadata. Returned values must be complete PostgreSQL/MySQL URLs or
317
- explicit `sqlite:` sources. StateQL validates the source and its stored driver
318
- before adapter construction, and normalizes SQLite paths. Credential-bearing
319
- PostgreSQL and MySQL URLs are redacted before connection
320
- metadata is persisted and never enter history, snapshots, cache keys, or
321
- responses. SQLite paths remain persisted connection metadata, as they are for
322
- direct SQLite connections. Harnesses remain responsible for approval policy,
323
- binding lifetime, revocation, and keeping values out of their own logs and
324
- model-visible data.
424
+ connection metadata.
425
+
426
+ Returned values must be complete PostgreSQL or MySQL URLs, or explicit
427
+ `sqlite:` sources. StateQL validates the source and its stored driver before
428
+ adapter construction and normalizes SQLite paths. Credential-bearing
429
+ PostgreSQL and MySQL URLs are redacted before connection metadata is persisted
430
+ and never enter history, snapshots, cache keys, or responses. SQLite paths
431
+ remain persisted connection metadata, as they are for direct SQLite
432
+ connections.
433
+
434
+ Harnesses remain responsible for approval policy, binding lifetime, revocation,
435
+ and keeping values out of their own logs and model-visible data.
325
436
 
326
437
  For writes, credential resolution happens after StateQL atomically reserves the
327
438
  operation for duplicate protection. A resolution failure keeps a non-executed
328
439
  `failed` audit record, does not consume the idempotency key, and permits a safe
329
440
  retry.
330
-
331
- `StateQL.forActor(...)` resolves the actor's attached session directly from
332
- StateQL storage, avoiding a duplicate actor-to-session mapping in integrations.
333
- On first use, it creates a legacy-compatible session named after the actor.
334
- Use `new StateQL({ session, actor })` when the session is already known.
335
-
336
- Membership is managed only through the library API, not batch commands:
337
- `linkActor(session, actorId)`, `unlinkActor(session, actorId)`,
338
- `listActors(session)`, and `resolveActor(actorId)`. An existing member must link
339
- an actor before that actor opens an existing workspace. Integrations should ask
340
- for user confirmation before changing membership or the shared connection.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fadhilp/stateql",
3
- "version": "0.4.2",
3
+ "version": "0.4.4",
4
4
  "description": "Stateful, agent-oriented database CLI for safe result reuse",
5
5
  "repository": {
6
6
  "type": "git",