bkper 5.7.2 → 5.8.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 +25 -0
- package/lib/agent/bundle/agent-entry.js +110 -103
- package/lib/agent/context-resources.d.ts +44 -0
- package/lib/agent/context-resources.d.ts.map +1 -0
- package/lib/agent/context-resources.js +110 -0
- package/lib/agent/context-resources.js.map +1 -0
- package/lib/agent/interactive/run-agent-mode.d.ts +2 -0
- package/lib/agent/interactive/run-agent-mode.d.ts.map +1 -1
- package/lib/agent/interactive/run-agent-mode.js +22 -3
- package/lib/agent/interactive/run-agent-mode.js.map +1 -1
- package/lib/agent/startup-maintenance.d.ts +13 -2
- package/lib/agent/startup-maintenance.d.ts.map +1 -1
- package/lib/agent/startup-maintenance.js +35 -8
- package/lib/agent/startup-maintenance.js.map +1 -1
- package/lib/cli.js +3 -0
- package/lib/cli.js.map +1 -1
- package/lib/commands/agent-command.d.ts +9 -1
- package/lib/commands/agent-command.d.ts.map +1 -1
- package/lib/commands/agent-command.js +45 -4
- package/lib/commands/agent-command.js.map +1 -1
- package/lib/commands/apps/dev.d.ts.map +1 -1
- package/lib/commands/apps/dev.js +5 -4
- package/lib/commands/apps/dev.js.map +1 -1
- package/lib/commands/apps/git/credentials.d.ts +1 -0
- package/lib/commands/apps/git/credentials.d.ts.map +1 -1
- package/lib/commands/apps/git/credentials.js +1 -1
- package/lib/commands/apps/git/credentials.js.map +1 -1
- package/lib/commands/context/book-context.d.ts +20 -0
- package/lib/commands/context/book-context.d.ts.map +1 -0
- package/lib/commands/context/book-context.js +40 -0
- package/lib/commands/context/book-context.js.map +1 -0
- package/lib/commands/context/domain-context.d.ts +21 -0
- package/lib/commands/context/domain-context.d.ts.map +1 -0
- package/lib/commands/context/domain-context.js +39 -0
- package/lib/commands/context/domain-context.js.map +1 -0
- package/lib/commands/context/git-credential.d.ts +17 -0
- package/lib/commands/context/git-credential.d.ts.map +1 -0
- package/lib/commands/context/git-credential.js +121 -0
- package/lib/commands/context/git-credential.js.map +1 -0
- package/lib/commands/context/platform-context.d.ts +42 -0
- package/lib/commands/context/platform-context.d.ts.map +1 -0
- package/lib/commands/context/platform-context.js +84 -0
- package/lib/commands/context/platform-context.js.map +1 -0
- package/lib/commands/context/register.d.ts +4 -0
- package/lib/commands/context/register.d.ts.map +1 -0
- package/lib/commands/context/register.js +79 -0
- package/lib/commands/context/register.js.map +1 -0
- package/lib/commands/context/user-context.d.ts +36 -0
- package/lib/commands/context/user-context.d.ts.map +1 -0
- package/lib/commands/context/user-context.js +125 -0
- package/lib/commands/context/user-context.js.map +1 -0
- package/lib/dev/auth-middleware.d.ts +11 -1
- package/lib/dev/auth-middleware.d.ts.map +1 -1
- package/lib/dev/auth-middleware.js +16 -1
- package/lib/dev/auth-middleware.js.map +1 -1
- package/lib/dev/local-outbound.d.ts +7 -0
- package/lib/dev/local-outbound.d.ts.map +1 -1
- package/lib/dev/local-outbound.js +26 -12
- package/lib/dev/local-outbound.js.map +1 -1
- package/lib/dev/managed-sandbox.d.ts +11 -0
- package/lib/dev/managed-sandbox.d.ts.map +1 -0
- package/lib/dev/managed-sandbox.js +13 -0
- package/lib/dev/managed-sandbox.js.map +1 -0
- package/lib/dev/tunnel.d.ts +5 -0
- package/lib/dev/tunnel.d.ts.map +1 -1
- package/lib/dev/tunnel.js +15 -0
- package/lib/dev/tunnel.js.map +1 -1
- package/lib/docs/api/managed-agent.md +133 -1
- package/lib/docs/cli/app-management.md +3 -1
- package/lib/docs/cli/data-management.md +14 -1
- package/lib/docs/sdk/bkper-api-types.md +1 -0
- package/package.json +1 -1
|
@@ -104,7 +104,7 @@ the totals you checked.
|
|
|
104
104
|
```
|
|
105
105
|
|
|
106
106
|
- Instructions can be up to 16,000 characters.
|
|
107
|
-
- A fork keeps its parent's instructions unless the create request sets new ones.
|
|
107
|
+
- A fork keeps its parent's instructions unless the create request sets new ones. Continuing someone else's session never takes theirs.
|
|
108
108
|
- Sessions keep the text they were given. Updating your client changes only the sessions it creates or patches.
|
|
109
109
|
|
|
110
110
|
## Who the agent acts as
|
|
@@ -121,6 +121,8 @@ The workspace (sessions, files, and sandbox) depends on who calls. Bkper sets th
|
|
|
121
121
|
|
|
122
122
|
Book changes made in an app's workspace are attributed to that app, with its name and logo.
|
|
123
123
|
|
|
124
|
+
A workspace's sessions are private to its user, unless the user [shares one](#share-a-session) from their own workspace.
|
|
125
|
+
|
|
124
126
|
- **Personal tools**: use each person's own token, so each person sees only their Books.
|
|
125
127
|
- **Shared channel bots**: everyone in the channel acts with the bot's account. Use a dedicated Bkper account, shared only on the Books the channel needs, with the lowest permission that does the job.
|
|
126
128
|
- **Read-only bots**: instructions are guidance, not enforcement. To guarantee read-only behavior, share the Books with the bot's account as View only.
|
|
@@ -181,6 +183,8 @@ Create a session with `parent` to continue from a point in another session:
|
|
|
181
183
|
|
|
182
184
|
A fork copies the conversation only, not workspace files or Book changes.
|
|
183
185
|
|
|
186
|
+
`parent` may also name a session someone else shares with the user, to [continue it](#continue-a-shared-session) as their own.
|
|
187
|
+
|
|
184
188
|
## Observe progress
|
|
185
189
|
|
|
186
190
|
`GET /v1/sessions/{sessionId}/stream` sends server-sent events over an authenticated `fetch`. Browsers' `EventSource` cannot send the token.
|
|
@@ -193,6 +197,68 @@ A fork copies the conversation only, not workspace files or Book changes.
|
|
|
193
197
|
|
|
194
198
|
`GET /v1/sessions/stream` streams the user's session list in the same way, for clients that show sessions created elsewhere.
|
|
195
199
|
|
|
200
|
+
## Share a session
|
|
201
|
+
|
|
202
|
+
A user can share a session read-only, so colleagues and Book collaborators can follow it live, learn from it, or help. Only the user's own workspace shares: an app's workspace cannot share its sessions or read others'.
|
|
203
|
+
|
|
204
|
+
Turn sharing on or off with `PATCH /v1/sessions/{sessionId}` and `{ "shared": true }` or `false`. Sessions are not shared by default.
|
|
205
|
+
|
|
206
|
+
| Session | Shared with |
|
|
207
|
+
| --- | --- |
|
|
208
|
+
| Started outside a Book | Everyone in the owner's hosted domain |
|
|
209
|
+
| Started in a Book | Everyone in the owner's hosted domain, and everyone who can view that Book, also outside the domain |
|
|
210
|
+
|
|
211
|
+
- A session's Book is its first input's `bookContext`, shown as `bookId`. It is fixed once set.
|
|
212
|
+
- The domain is the account's hosted domain as Bkper verified it, never an email address. Without one, a session outside a Book cannot be shared: 409 `share_unavailable`.
|
|
213
|
+
- To share a session started in a Book, the user must view that Book: 409 `book_access_required`.
|
|
214
|
+
- Viewing a Book means the `OWNER`, `EDITOR`, `POSTER`, or `VIEWER` permission; not `RECORDER`.
|
|
215
|
+
- Readers are checked on every request and stream connection, never remembered. Turning sharing off ends their streams at once; copies and exports already made stay with whoever has them.
|
|
216
|
+
- When the user can no longer view the session's Book, it leaves that Book: its Book list drops it, and readers outside the user's domain lose it. The domain's audience stays. It returns when the user can view the Book again and sends a message or turns sharing on.
|
|
217
|
+
- The user's own list shows `shared: true` on the sessions they share.
|
|
218
|
+
|
|
219
|
+
### Read a shared session
|
|
220
|
+
|
|
221
|
+
Readers use the session routes with the shared session's ID: the session, now with `owner.name`, its entries, stream, published files, and [export](#export-a-session). They download its files through `GET /v1/sessions/{sessionId}/files/{fileId}` and `…/content`: files its history shows, published in it or attached to its messages, under the same retention. `/v1/files/{fileId}` serves only the user's own files.
|
|
222
|
+
|
|
223
|
+
Readers cannot rename, archive, share, send to, stop, or compact someone else's session: those requests return 404, as for any session that is not theirs.
|
|
224
|
+
|
|
225
|
+
### Find shared sessions
|
|
226
|
+
|
|
227
|
+
`GET /v1/shared` lists sessions other people share with the user, newest updated first, with their title, owner's name, `updatedAt`, and `bookId`:
|
|
228
|
+
|
|
229
|
+
- without parameters, those shared with the user's hosted domain (none without one);
|
|
230
|
+
- with `?book={bookId}`, those started in that Book, when the user can view it (403 `book_access_required`). People outside the owner's domain find a Book's shared sessions this way.
|
|
231
|
+
|
|
232
|
+
`GET /v1/shared/stream` sends the first page as `snapshot` events after every change, like the session-list stream. Archived sessions leave these lists, but stay readable while shared.
|
|
233
|
+
|
|
234
|
+
### Continue a shared session
|
|
235
|
+
|
|
236
|
+
Create a session with `parent` naming the shared session, as for a [fork](#forks):
|
|
237
|
+
|
|
238
|
+
| To | `parent` |
|
|
239
|
+
| --- | --- |
|
|
240
|
+
| Reply at the end | The latest finished reply, `position: "at"` |
|
|
241
|
+
| Continue from a reply | That reply, `position: "at"` |
|
|
242
|
+
| Edit a message | That user message, `position: "before"`, with the edited text as `input` |
|
|
243
|
+
|
|
244
|
+
- The new session is the user's own, in their own workspace, and runs with their own access.
|
|
245
|
+
- It holds a copy of the history up to that point, titled like the original, and is marked `continuedFrom`, with the original's owner.
|
|
246
|
+
- It never takes the original's instructions: send your own `instructions`, as for a new session.
|
|
247
|
+
- Files are not copied: the history names them, and the user can upload them again.
|
|
248
|
+
- The original is unchanged, and its owner is not notified.
|
|
249
|
+
- A session not shared with the user is 404 `parent_not_found`.
|
|
250
|
+
|
|
251
|
+
## Export a session
|
|
252
|
+
|
|
253
|
+
`GET /v1/sessions/{sessionId}/export` downloads a session as one JSON file, for support or another agent to read:
|
|
254
|
+
|
|
255
|
+
- the session, with its model, thinking level and instructions;
|
|
256
|
+
- every entry in full, oldest first, including history inherited from a fork or copied from a shared session;
|
|
257
|
+
- the session's files, as metadata without their contents;
|
|
258
|
+
- each input's Agent and sandbox CLI versions.
|
|
259
|
+
|
|
260
|
+
`format` and `contractVersion` say which objects it holds. Whoever can read the session can export it, including those it is [shared with](#share-a-session). An export is a record of the session, not a way to resume it elsewhere.
|
|
261
|
+
|
|
196
262
|
## Files
|
|
197
263
|
|
|
198
264
|
Files go both ways as the same `File` resource. `origin` tells them apart:
|
|
@@ -332,6 +398,48 @@ export async function reply(event: SlackEvent): Promise<string> {
|
|
|
332
398
|
|
|
333
399
|
Acknowledge each Slack event at once and post the reply when `reply` returns: Slack expects an answer within three seconds, and an agent run usually takes longer.
|
|
334
400
|
|
|
401
|
+
## Connected services
|
|
402
|
+
|
|
403
|
+
A user can connect other services, such as GitHub or Intercom, once: requests the agent sends to their hosts then carry the user's token, added outside the agent's workspace. The agent never sees the token.
|
|
404
|
+
|
|
405
|
+
```bash
|
|
406
|
+
curl --fail-with-body -X PUT https://agent.bkper.app/v1/services/github \
|
|
407
|
+
-H "Authorization: Bearer ${BKPER_TOKEN}" \
|
|
408
|
+
-H "Content-Type: application/json" \
|
|
409
|
+
--data '{
|
|
410
|
+
"name": "GitHub",
|
|
411
|
+
"targets": [{ "host": "api.github.com", "scheme": "bearer" }],
|
|
412
|
+
"secret": "<token>"
|
|
413
|
+
}'
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
- `PUT /v1/services/{serviceId}` connects (201) or replaces (200) the whole service, token included. The ID is yours: lowercase letters, digits and hyphens.
|
|
417
|
+
- `GET /v1/services` lists them; `DELETE /v1/services/{serviceId}` disconnects one (204), at once.
|
|
418
|
+
- The token is write-only: never returned, logged, or shown to the agent. Choose its permissions in the service: the agent can do whatever the token allows.
|
|
419
|
+
- Each host belongs to one service: 409 `host_in_use` names the service that holds it.
|
|
420
|
+
- Only calls with the user's own token manage services. Through an app or channel bot these routes are 404.
|
|
421
|
+
|
|
422
|
+
Google APIs take a service account instead of a token: send its JSON key file as the secret, `google` targets on `*.googleapis.com` hosts, and the scopes to make access tokens for. Access tokens are made and renewed outside the agent's workspace; the response carries the account's `clientEmail`, to share Drive files or an Analytics property with. Change the APIs or scopes by sending the whole service again, key included.
|
|
423
|
+
|
|
424
|
+
```json
|
|
425
|
+
{
|
|
426
|
+
"name": "Google",
|
|
427
|
+
"targets": [{ "host": "analyticsdata.googleapis.com", "scheme": "google" }],
|
|
428
|
+
"google": { "scopes": ["https://www.googleapis.com/auth/analytics.readonly"] },
|
|
429
|
+
"secret": "<the key file's JSON>"
|
|
430
|
+
}
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
In the agent's workspace, Google's client libraries find credentials through `GOOGLE_APPLICATION_CREDENTIALS`, a placeholder key that grants nothing, and must use their REST transport (such as `{ fallback: true }`): gRPC does not leave the workspace.
|
|
434
|
+
|
|
435
|
+
### Domain services
|
|
436
|
+
|
|
437
|
+
A domain's admin can connect a service for everyone in the domain, with the same requests under `/v1/domain/services`. The agent of every member then uses it, unless the member connected their own service for the same host, which comes first. A domain's token works for everyone in the domain and any app they authorize: choose its permissions as narrowly as you can.
|
|
438
|
+
|
|
439
|
+
- `GET /v1/domain/services` lists the caller's domain's services, for any member; without a domain, the list is empty.
|
|
440
|
+
- `PUT` and `DELETE /v1/domain/services/{serviceId}` are only for the domain's admin (403 `domain_admin_required`). The services belong to the domain, not the admin who connected them.
|
|
441
|
+
- Each host belongs to one service within the domain; a member's own services are apart. Through an app or channel bot these routes are 404.
|
|
442
|
+
|
|
335
443
|
## Limits
|
|
336
444
|
|
|
337
445
|
| Limit | Value |
|
|
@@ -346,6 +454,7 @@ Acknowledge each Slack event at once and post the reply when `reply` returns: Sl
|
|
|
346
454
|
| `bookContext.query` | 4,000 characters |
|
|
347
455
|
| `attributes` | 16 names, 16000 characters in total |
|
|
348
456
|
| List page | 50 sessions, entries, or files |
|
|
457
|
+
| Connected services | 20 per user and 20 per domain, 10 hosts each, tokens and keys up to 8192 characters, 20 Google scopes |
|
|
349
458
|
|
|
350
459
|
## Errors
|
|
351
460
|
|
|
@@ -354,15 +463,21 @@ Errors are `{ "error": { "code", "type", "message" } }`. Branch on `code`.
|
|
|
354
463
|
| Status | `code` | Meaning |
|
|
355
464
|
| --- | --- | --- |
|
|
356
465
|
| 400 | `invalid_request`, `unknown_model`, `unknown_thinking_level` | A field is invalid or unknown |
|
|
466
|
+
| 400 | `host_not_allowed` | A connected service names a host that has its own route, such as Bkper's or Google's token endpoint |
|
|
357
467
|
| 401 | `unauthorized`, `authentication_failed` | The token is missing, invalid, or expired |
|
|
358
468
|
| 403 | `agent_beta_required` | The account cannot use the agent, such as one without an email address |
|
|
359
469
|
| 403 | `origin_forbidden` | A browser on another website sent a write |
|
|
470
|
+
| 403 | `book_access_required` | The user cannot view the Book whose shared sessions they asked for |
|
|
471
|
+
| 403 | `domain_admin_required` | Only the domain's admin changes its services |
|
|
360
472
|
| 404 | `not_found`, `parent_not_found`, `file_not_found` | No such resource for this user |
|
|
361
473
|
| 405 | `method_not_allowed` | The path does not support the method |
|
|
362
474
|
| 409 | `idempotency_conflict` | The key was used with different content |
|
|
363
475
|
| 409 | `invalid_fork_point` | The fork point is not a finished reply or a user message |
|
|
364
476
|
| 409 | `input_running` | The input is already running and cannot be withdrawn |
|
|
365
477
|
| 409 | `file_quota_exceeded` | The user's upload quota is full |
|
|
478
|
+
| 409 | `share_unavailable` | The session cannot be shared: an app's workspace, or outside a Book without a hosted domain |
|
|
479
|
+
| 409 | `book_access_required` | The user cannot view the Book the session was started in |
|
|
480
|
+
| 409 | `host_in_use`, `service_limit` | Another service holds the host, or the user (or domain) has 20 services |
|
|
366
481
|
| 410 | `file_gone` | The file's stored copy was deleted |
|
|
367
482
|
| 411 | `length_required` | An upload has no `Content-Length` |
|
|
368
483
|
| 413 | `request_too_large`, `file_too_large` | The JSON body exceeds 64 KiB, or the upload 25 MiB |
|
|
@@ -391,6 +506,7 @@ Each operation has its own page. The machine-readable contract is [openapi.json]
|
|
|
391
506
|
- [`GET /v1/sessions/{sessionId}/entries` — List history entries](https://bkper.com/docs/api/managed-agent/operations/listentries.md)
|
|
392
507
|
- [`GET /v1/sessions/{sessionId}/entries/{entryId}` — Get a full entry](https://bkper.com/docs/api/managed-agent/operations/getentry.md)
|
|
393
508
|
- [`POST /v1/sessions/{sessionId}/compact` — Compact earlier context](https://bkper.com/docs/api/managed-agent/operations/compactsession.md)
|
|
509
|
+
- [`GET /v1/sessions/{sessionId}/export` — Export a session](https://bkper.com/docs/api/managed-agent/operations/exportsession.md)
|
|
394
510
|
|
|
395
511
|
### Inputs
|
|
396
512
|
|
|
@@ -404,13 +520,29 @@ Each operation has its own page. The machine-readable contract is [openapi.json]
|
|
|
404
520
|
- [`GET /v1/sessions/stream` — Observe the session list](https://bkper.com/docs/api/managed-agent/operations/observesessions.md)
|
|
405
521
|
- [`GET /v1/sessions/{sessionId}/stream` — Observe a session](https://bkper.com/docs/api/managed-agent/operations/observesession.md)
|
|
406
522
|
|
|
523
|
+
### Shared
|
|
524
|
+
|
|
525
|
+
- [`GET /v1/shared` — List sessions shared with me](https://bkper.com/docs/api/managed-agent/operations/listshared.md)
|
|
526
|
+
- [`GET /v1/shared/stream` — Observe sessions shared with me](https://bkper.com/docs/api/managed-agent/operations/observeshared.md)
|
|
527
|
+
|
|
407
528
|
### Files
|
|
408
529
|
|
|
409
530
|
- [`GET /v1/sessions/{sessionId}/files` — List published files](https://bkper.com/docs/api/managed-agent/operations/listfiles.md)
|
|
531
|
+
- [`GET /v1/sessions/{sessionId}/files/{fileId}` — Get a session's file](https://bkper.com/docs/api/managed-agent/operations/getsessionfile.md)
|
|
532
|
+
- [`GET /v1/sessions/{sessionId}/files/{fileId}/content` — Download a session's file](https://bkper.com/docs/api/managed-agent/operations/downloadsessionfile.md)
|
|
410
533
|
- [`POST /v1/files` — Upload a file](https://bkper.com/docs/api/managed-agent/operations/uploadfile.md)
|
|
411
534
|
- [`GET /v1/files/{fileId}` — Get file metadata](https://bkper.com/docs/api/managed-agent/operations/getfile.md)
|
|
412
535
|
- [`GET /v1/files/{fileId}/content` — Download a file](https://bkper.com/docs/api/managed-agent/operations/downloadfile.md)
|
|
413
536
|
|
|
537
|
+
### Services
|
|
538
|
+
|
|
539
|
+
- [`GET /v1/services` — List connected services](https://bkper.com/docs/api/managed-agent/operations/listservices.md)
|
|
540
|
+
- [`PUT /v1/services/{serviceId}` — Connect or replace a service](https://bkper.com/docs/api/managed-agent/operations/putservice.md)
|
|
541
|
+
- [`DELETE /v1/services/{serviceId}` — Disconnect a service](https://bkper.com/docs/api/managed-agent/operations/deleteservice.md)
|
|
542
|
+
- [`GET /v1/domain/services` — List domain services](https://bkper.com/docs/api/managed-agent/operations/listdomainservices.md)
|
|
543
|
+
- [`PUT /v1/domain/services/{serviceId}` — Connect or replace a domain service](https://bkper.com/docs/api/managed-agent/operations/putdomainservice.md)
|
|
544
|
+
- [`DELETE /v1/domain/services/{serviceId}` — Disconnect a domain service](https://bkper.com/docs/api/managed-agent/operations/deletedomainservice.md)
|
|
545
|
+
|
|
414
546
|
### Models
|
|
415
547
|
|
|
416
548
|
- [`GET /v1/models` — List models](https://bkper.com/docs/api/managed-agent/operations/listmodels.md)
|
|
@@ -88,7 +88,7 @@ Verify:
|
|
|
88
88
|
|
|
89
89
|
- Server worker responds: `curl http://localhost:8787/health` (or the port you configured)
|
|
90
90
|
- Client dev server is reachable if running separately
|
|
91
|
-
- If the app declares `events`, the events tunnel URL is printed in terminal and registered in Bkper as `webhookUrlDev`
|
|
91
|
+
- If the app declares `events`, the events tunnel URL is printed in terminal and registered in Bkper as `webhookUrlDev` (not in Bkper's managed agent sandbox: there, test events on a deployed preview)
|
|
92
92
|
- If the worker fails to start, fix before writing code
|
|
93
93
|
|
|
94
94
|
### 3. Build
|
|
@@ -199,6 +199,8 @@ bkper app status <appId>
|
|
|
199
199
|
|
|
200
200
|
> **Note:** `bkper app dev` runs one local Worker runtime — Miniflare, file watching, and an optional Cloudflare tunnel to `/events` when the app subscribes to events. Miniflare is loaded from the app project's `devDependencies` so each app can keep its local Workers simulator aligned with its own code. The Vite client dev server is configured in the project's `vite.config.ts` and run separately. The project template composes both via `npm run dev` using `concurrently`. Open the printed `Open app` URL in your browser; the `Worker/API` URL is for `/api`, `/health`, `/openapi.json`, and events. If your Vite server uses a port other than `5173`, pass that port with `--cp, --client-port` so the local `ASSETS` binding can reach it. If needed, install Miniflare in the app root with `bun add -d miniflare` or `npm install -D miniflare`.
|
|
201
201
|
|
|
202
|
+
> **Managed agent sandbox:** in Bkper's managed agent sandbox, `bkper app dev` needs no `bkper auth login`. The Worker's calls to the Bkper API and Bkper AI go out without the CLI's credentials (the sandbox adds its owner's), Bkper API calls go to the sandbox's own Bkper environment, and the client's `/auth/refresh` gets a placeholder token the sandbox replaces. The events tunnel is skipped there, since it cannot connect; test events on a deployed preview (`bkper app deploy --preview`).
|
|
203
|
+
|
|
202
204
|
---
|
|
203
205
|
|
|
204
206
|
## Clone managed source
|
|
@@ -154,9 +154,22 @@ bkper group delete "Cash" -b abc123
|
|
|
154
154
|
|
|
155
155
|
When setting up a full Book or starter chart of accounts, prefer a hierarchical group structure by default.
|
|
156
156
|
|
|
157
|
+
Give the Book one root group per report it needs, named in the Book's language. Each root holds accounts of one time basis — `ASSET`/`LIABILITY` (position at a date) or `INCOMING`/`OUTGOING` (activity over a period) — and each report has a single root. For a financial Book, that means a **Balance Sheet root** and a **P&L root**:
|
|
158
|
+
|
|
159
|
+
```
|
|
160
|
+
Balance Sheet
|
|
161
|
+
├── Assets ──────► ASSET accounts
|
|
162
|
+
└── Liabilities ─► LIABILITY accounts
|
|
163
|
+
Profit & Loss
|
|
164
|
+
├── Revenue ─────► INCOMING accounts
|
|
165
|
+
└── Expenses ────► OUTGOING accounts
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
Add other root groups (by project, branch, etc.) only when the user asks for them.
|
|
169
|
+
|
|
157
170
|
Create top-level groups first, then child groups with `--parent`, then accounts with `--groups`.
|
|
158
171
|
|
|
159
|
-
Verify the resulting group hierarchy and account memberships before reporting success.
|
|
172
|
+
Verify the resulting group hierarchy and account memberships before reporting success, including that each report has its root and every account sits under one.
|
|
160
173
|
|
|
161
174
|
Avoid using the same name for a Group and an Account in the same Book.
|
|
162
175
|
|
|
@@ -538,6 +538,7 @@ More information at the [Bkper Developer Documentation](https://bkper.com/docs/#
|
|
|
538
538
|
- `billingEnabled?`: `boolean` — True if billing is enabled for the user
|
|
539
539
|
- `daysLeftInTrial?`: `number` — How many days left in trial
|
|
540
540
|
- `domain?`: `bkper.Domain`
|
|
541
|
+
- `domainAdmin?`: `boolean` — True if the user is the admin of their domain
|
|
541
542
|
- `email?`: `string` — The user email
|
|
542
543
|
- `free?`: `boolean` — True if user is in the free plan
|
|
543
544
|
- `fullName?`: `string` — The user full name
|