@book.dev/sdk 1.76.2 → 2.1.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/dist/ai.d.ts CHANGED
@@ -31,7 +31,7 @@ export type AiEffort = 'low' | 'med' | 'high';
31
31
  * claude all set up at once and switch between them per agent run. */
32
32
  export interface AiProviderSettings {
33
33
  /** Model identifier: a GGUF filename (llama), an MLX model id (mlx), a served
34
- * model name (openai), or a Claude model id (e.g. `claude-sonnet-4-6`). */
34
+ * model name (openai), or a Claude model id (e.g. `claude-opus-4-8`). */
35
35
  model?: string;
36
36
  /** Base URL for `mlx` / `openai` / `claude`. Defaults: mlx
37
37
  * http://127.0.0.1:8080, openai http://127.0.0.1:11434, claude
@@ -271,13 +271,18 @@ export type AgentChatEvent = {
271
271
  result: string;
272
272
  }
273
273
  /**
274
- * The agent is asking to apply its edits DIRECTLY (without the review pane).
275
- * The UI shows an allow/keep-reviewing prompt; granting it makes subsequent
276
- * edits in this conversation apply immediately (see {@link apply}).
274
+ * The agent is asking for a sticky, per-conversation permission. `kind`
275
+ * distinguishes them (default `direct_edits` for back-compat):
276
+ * - `direct_edits` — apply its edits DIRECTLY (without the review pane);
277
+ * granting makes subsequent edits apply immediately (see {@link apply}).
278
+ * - `external_tools` — call EXTERNAL MCP tools (`mcp__*`), which send inputs
279
+ * off the workspace; granting lets the agent use them for this conversation.
280
+ * The UI shows an allow / keep-reviewing prompt either way.
277
281
  */
278
282
  | {
279
283
  type: 'permission_request';
280
284
  summary: string;
285
+ kind?: 'direct_edits' | 'external_tools';
281
286
  }
282
287
  /** The agent is asking the user a multi-step interview; answers return as the
283
288
  * user's next message. */
@@ -346,6 +351,105 @@ export interface AgentChatOptions {
346
351
  * via an {@link AgentChatEvent.apply} event instead of becoming review
347
352
  * suggestions. Sticky for the conversation once granted. */
348
353
  allowDirectEdits?: boolean;
354
+ /** When true (the user consented), the agent may call EXTERNAL MCP tools
355
+ * (`mcp__*`) without pausing. Sticky for the conversation; the first external
356
+ * call otherwise emits a `permission_request` with `kind:'external_tools'`. */
357
+ allowExternalTools?: boolean;
358
+ /** When true, an external MCP tool was already used earlier in this conversation
359
+ * — the client re-sends it (set once it sees any `mcp__*` tool event) so taint
360
+ * (edits routed through review) stays sticky for the rest of the conversation,
361
+ * not just the run that made the external call. */
362
+ externalToolsUsed?: boolean;
363
+ }
364
+ /**
365
+ * How the in-app agent reaches an external MCP server:
366
+ * - `stdio` — spawn a local child process and speak MCP over its stdio. This is
367
+ * host **command execution** (the child runs as the server user and can reach
368
+ * loopback services the identity layer trusts as the machine owner), so it is
369
+ * permitted ONLY on a desktop / UNCLAIMED instance. On a claimed multi-user
370
+ * instance the server rejects a `stdio` registration and the UI hides it.
371
+ * - `http` — a remote (or loopback) Streamable-HTTP MCP endpoint, authed with a
372
+ * static bearer token. The only transport offered on a claimed instance.
373
+ */
374
+ export type McpTransport = 'stdio' | 'http';
375
+ /**
376
+ * One registered external MCP server. Admin-managed (see {@link McpClientConfig});
377
+ * connections are pooled server-side and its tools are merged into an agent run
378
+ * namespaced `mcp__<id>__<tool>` (so `id` forbids underscores — the delimiter).
379
+ */
380
+ export interface McpServerConfig {
381
+ /** Stable slug, `^[a-z0-9][a-z0-9-]{0,31}$` (NO underscores — the namespace
382
+ * delimiter). Unique within {@link McpClientConfig.servers}. */
383
+ id: string;
384
+ /** Optional display name (defaults to {@link id}). */
385
+ name?: string;
386
+ /** Per-server enable. Default false — a registered server does nothing until
387
+ * explicitly enabled (and the global {@link McpClientConfig.enabled} is on). */
388
+ enabled: boolean;
389
+ transport: McpTransport;
390
+ /** The executable to spawn (stdio). */
391
+ command?: string;
392
+ /** Arguments for {@link command} (stdio). NEVER carries the auth token. */
393
+ args?: string[];
394
+ /** Extra environment for the child (stdio). Overlaid on a MINIMAL default env
395
+ * (never the server's own `process.env`); the auth token is injected under
396
+ * {@link authEnvVar}, not here. */
397
+ env?: Record<string, string>;
398
+ /** Env var name the auth token is injected under (stdio). Default `MCP_AUTH_TOKEN`. */
399
+ authEnvVar?: string;
400
+ /** The Streamable-HTTP MCP endpoint (http). */
401
+ url?: string;
402
+ /** Extra request headers (http). The auth token is sent as `Authorization:
403
+ * Bearer <token>`, NOT here. */
404
+ headers?: Record<string, string>;
405
+ /**
406
+ * The static bearer token (http) or injected secret (stdio). **Write-only
407
+ * across the wire** — the server never returns it. Same three-way contract as
408
+ * {@link AiProviderSettings.apiKey}:
409
+ * • omitted / empty string → PRESERVE the stored token;
410
+ * • a non-empty string → set a new token;
411
+ * • explicit `null` → CLEAR the stored token.
412
+ */
413
+ authToken?: string | null;
414
+ /** Response-only signal: the server holds a non-empty token for this server.
415
+ * Set by `GET /api/ai/mcp` in place of the redacted {@link authToken}. */
416
+ authTokenSet?: boolean;
417
+ /** Per-call timeout for this server's tools, ms. Default 30000, clamped
418
+ * 1000..120000. */
419
+ timeoutMs?: number;
420
+ }
421
+ /**
422
+ * The workspace's external-tool (MCP client) configuration, persisted server-side
423
+ * under the `ai.mcp` settings key. Admin-managed. OFF and empty by default —
424
+ * nothing connects until an admin adds a server, enables it, and flips the global
425
+ * switch. A deployment env kill-switch (`OPENBOOK_MCP_CLIENTS=0`) hard-disables
426
+ * the whole subsystem regardless.
427
+ */
428
+ export interface McpClientConfig {
429
+ /** Global kill-switch. Default false — with it off no server connects, even an
430
+ * individually-enabled one. */
431
+ enabled: boolean;
432
+ servers: McpServerConfig[];
433
+ }
434
+ /**
435
+ * `GET /api/ai/mcp` (admin only): the redacted config (every {@link
436
+ * McpServerConfig.authToken} stripped, {@link McpServerConfig.authTokenSet}
437
+ * flagged) plus `stdioAllowed` — whether this instance's trust level permits the
438
+ * `stdio` transport (true on a desktop / unclaimed instance, false once claimed).
439
+ * The UI hides the stdio option when false; the PUT route enforces the same rule.
440
+ */
441
+ export interface McpConfigResponse {
442
+ config: McpClientConfig;
443
+ stdioAllowed: boolean;
444
+ }
445
+ /** Result of `POST /api/ai/mcp/test` (admin only): a connect + list-tools dry-run
446
+ * against one server config. Never returns secrets. */
447
+ export interface McpTestResult {
448
+ ok: boolean;
449
+ /** Tool names discovered on a successful connect. */
450
+ tools?: string[];
451
+ /** A human-readable failure reason (error class / message), never headers/env. */
452
+ error?: string;
349
453
  }
350
454
  /**
351
455
  * A user-authored prompt/recipe skill: markdown instructions the agent can
package/dist/authorize.js CHANGED
@@ -32,12 +32,15 @@ export function isEmailAuthoritative(principal, config) {
32
32
  * satisfy an `account.book.pub`-scoped email grant.
33
33
  */
34
34
  function matchAcl(principal, acl, ctx) {
35
- const isJws = principal.verifiedVia === 'jws';
35
+ // A **subject** entry matches a `jws` OR a `pat` principal with that subject: an
36
+ // agent PAT (AGENT-6) rides the exact subject-keyed grants its bound user has. An
37
+ // **email** entry stays jws-only (a PAT carries no persona email — see below).
38
+ const subjectEligible = principal.verifiedVia === 'jws' || principal.verifiedVia === 'pat';
36
39
  let best = null;
37
40
  for (const entry of acl) {
38
41
  let matches = false;
39
42
  if (entry.subject) {
40
- matches = isJws && entry.subject === principal.subject;
43
+ matches = subjectEligible && entry.subject === principal.subject;
41
44
  }
42
45
  else if (entry.email) {
43
46
  matches =
@@ -62,8 +65,9 @@ function scopeAllowsRead(principal, ctx, guestBlocked) {
62
65
  // guest when `guestAccess='off'` (rule 6 / footnote ¹).
63
66
  return !guestBlocked;
64
67
  case 'authenticated':
65
- // Any signed-in (jws) user; guests denied (N8).
66
- return principal.verifiedVia === 'jws';
68
+ // Any signed-in (jws) user, or an agent PAT bound to one (AGENT-6); guests
69
+ // denied (N8).
70
+ return principal.verifiedVia === 'jws' || principal.verifiedVia === 'pat';
67
71
  case 'members':
68
72
  // Only active roster members — an active row resolves to a non-null role.
69
73
  // A signed-in non-member or invited/suspended persona (role null) gets
@@ -94,13 +98,20 @@ export function authorize(principal, page, ctx) {
94
98
  const { config } = ctx;
95
99
  const isLocal = principal.verifiedVia === 'local';
96
100
  const isJws = principal.verifiedVia === 'jws';
101
+ // An agent PAT (AGENT-6) rides the SUBJECT-keyed rungs its bound user would —
102
+ // owner-content (rule 2), subject-ACL (rule 3), authenticated-read (rule 5), and
103
+ // the unclaimed rule-0 short-circuit — but is NEVER a roster member (rule 4:
104
+ // `ctx.role` is jws-only via `resolveMemberRole`, so a PAT can't ride the
105
+ // admin/viewer rung) and carries no persona email (no email-ACL). Its write
106
+ // ceiling is additionally enforced out-of-band by the HTTP scope-gate.
107
+ const isPat = principal.verifiedVia === 'pat';
97
108
  // Rule 0 — unclaimed instance: legacy short-circuit, preserving today's
98
109
  // loopback behaviour exactly. Roster/scope/ACL don't exist until claimed; the
99
110
  // in-process (`local`) and any `jws` caller always read+write (truth-table
100
111
  // footer), everyone else is judged by the guest gate. Reachable only on
101
112
  // loopback (the §2.6 exposure invariant — a claim is required before exposure).
102
113
  if (config.ownerSubject === undefined) {
103
- const privileged = isJws || isLocal;
114
+ const privileged = isJws || isLocal || isPat;
104
115
  return {
105
116
  canRead: config.guestAccess !== 'off' || privileged,
106
117
  canWrite: config.guestAccess === 'write' || privileged,
@@ -108,7 +119,7 @@ export function authorize(principal, page, ctx) {
108
119
  };
109
120
  }
110
121
  // ── Claimed instance ──────────────────────────────────────────────────────
111
- const isOwner = isJws && principal.subject === config.ownerSubject; // rule 2
122
+ const isOwner = (isJws || isPat) && principal.subject === config.ownerSubject; // rule 2
112
123
  const aclMatch = matchAcl(principal, page.acl, ctx); // rule 3
113
124
  const isAdmin = ctx.role === 'admin'; // rule 4
114
125
  const isViewer = ctx.role === 'viewer'; // rule 4
@@ -120,7 +131,7 @@ export function authorize(principal, page, ctx) {
120
131
  // past the `guestAccess='off'` floor onto a `public` page either (defence in
121
132
  // depth behind the middleware, which already rejects such principals at the gate
122
133
  // on an identity-enabled instance).
123
- const guestBlocked = !isJws && !isLocal && config.guestAccess === 'off';
134
+ const guestBlocked = !isJws && !isLocal && !isPat && config.guestAccess === 'off';
124
135
  const scopeRead = scopeAllowsRead(principal, ctx, guestBlocked); // rule 5
125
136
  // WRITE — only rules 1/2/3(write)/4(admin) ever grant it. `viewer` is locked,
126
137
  // jws-non-members and guests are read-only on a claimed instance.
@@ -1 +1 @@
1
- {"version":3,"file":"authorize.js","sourceRoot":"","sources":["../src/authorize.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"authorize.js","sourceRoot":"","sources":["../src/authorize.ts"],"names":[],"mappings":"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"}
package/dist/backup.d.ts CHANGED
@@ -12,7 +12,7 @@
12
12
  import type { StoredPage } from './types';
13
13
  import type { StoredDatabase } from './database';
14
14
  export declare const BACKUP_VERSION = 1;
15
- export interface SpaceBackup {
15
+ export interface LibraryBackup {
16
16
  version: number;
17
17
  exportedAt: string;
18
18
  pages: StoredPage[];
@@ -3,7 +3,7 @@ import type { StoredDatabase } from './database';
3
3
  /**
4
4
  * Whole-space → folder-of-files serialisation, shared by every "dump my books
5
5
  * to a folder" surface: the desktop's native folder export and the web app's
6
- * File System Access export both call {@link spaceToBookFiles}, and the layout
6
+ * File System Access export both call {@link libraryToBookFiles}, and the layout
7
7
  * is byte-compatible with the server's on-disk {@link BookMirror} (OB-134) so a
8
8
  * folder written by one can be re-imported by the other.
9
9
  *
@@ -19,33 +19,49 @@ export interface BookFolderFile {
19
19
  path: string;
20
20
  contents: string;
21
21
  }
22
- /** Everything in a space, as returned by `DataClient.exportSpace`. */
23
- export interface SpaceSnapshot {
22
+ /** Everything in a space, as returned by `DataClient.exportLibrary`. */
23
+ export interface LibrarySnapshot {
24
24
  pages: StoredPage[];
25
25
  databases: StoredDatabase[];
26
26
  }
27
- /** Lossless structured sidecar, parsed back by {@link parseBookFolder}. */
28
- export declare const SPACE_BUNDLE_FILE = "openbook.space.json";
27
+ /**
28
+ * Lossless structured sidecar filename that NEW exports write, parsed back by
29
+ * {@link parseBookFolder}. Renamed from the legacy `openbook.space.json`
30
+ * (LIB-4): the writer emits only this, while the reader also accepts
31
+ * {@link LEGACY_SPACE_BUNDLE_FILE} so folders exported before the rename still
32
+ * re-import losslessly.
33
+ */
34
+ export declare const SPACE_BUNDLE_FILE = "openbook.library.json";
35
+ /**
36
+ * The pre-LIB-4 sidecar filename. READ-ONLY back-compat: {@link parseBookFolder}
37
+ * falls back to it so already-exported book folders keep importing. The writer
38
+ * never emits it.
39
+ */
40
+ export declare const LEGACY_SPACE_BUNDLE_FILE = "openbook.space.json";
29
41
  /**
30
42
  * The whole-space **source-island** payload embedded in a standalone *site* HTML
31
- * export: the full {@link SpaceSnapshot} (pages + databases + nesting via each
43
+ * export: the full {@link LibrarySnapshot} (pages + databases + nesting via each
32
44
  * page's `parentId`/`databaseId`) plus the root id shown first. Same structure as
33
45
  * {@link SPACE_BUNDLE_FILE}, so a site export re-imports with structure intact.
34
46
  */
35
- export interface SpaceIsland {
47
+ export interface LibraryIsland {
36
48
  version: 1;
37
49
  rootId: string;
38
- space: SpaceSnapshot;
50
+ space: LibrarySnapshot;
39
51
  }
40
52
  /** Wrap a whole-space bundle as its source-island `<script>` (versioned, escaped). */
41
- export declare function spaceIslandScript(rootId: string, space: SpaceSnapshot, opts?: {
53
+ export declare function libraryIslandScript(rootId: string, space: LibrarySnapshot, opts?: {
42
54
  attrs?: string;
43
55
  indent?: string;
44
56
  }): string;
45
- /** Read a site export's space island back, or `null` when absent/corrupt. */
46
- export declare function readSpaceIsland(html: string): SpaceIsland | null;
47
- /** Options for {@link spaceToBookFiles}. */
48
- export interface SpaceToBookFilesOptions {
57
+ /**
58
+ * Read a site export's space island back, or `null` when absent/corrupt.
59
+ * Dual-read: prefer the new `library` key, fall back to the legacy `space` key
60
+ * so bundles published before LIB-4 still import.
61
+ */
62
+ export declare function readLibraryIsland(html: string): LibraryIsland | null;
63
+ /** Options for {@link libraryToBookFiles}. */
64
+ export interface LibraryToBookFilesOptions {
49
65
  /** Include the lossless {@link SPACE_BUNDLE_FILE} sidecar. Default true. */
50
66
  includeBundle?: boolean;
51
67
  /**
@@ -63,14 +79,15 @@ export interface SpaceToBookFilesOptions {
63
79
  * Serialise a space to its on-disk files. By default includes the lossless
64
80
  * {@link SPACE_BUNDLE_FILE}; pass `includeBundle: false` for the human-readable
65
81
  * HTML files only. Pass `runtime` (the viewer bundle source) to make the folder
66
- * self-hydrating — see {@link SpaceToBookFilesOptions.runtime}.
82
+ * self-hydrating — see {@link LibraryToBookFilesOptions.runtime}.
67
83
  */
68
- export declare function spaceToBookFiles(snapshot: SpaceSnapshot, opts?: SpaceToBookFilesOptions): BookFolderFile[];
84
+ export declare function libraryToBookFiles(snapshot: LibrarySnapshot, opts?: LibraryToBookFilesOptions): BookFolderFile[];
69
85
  /**
70
- * Reconstruct a space from a folder's files. Prefers the lossless
71
- * {@link SPACE_BUNDLE_FILE} when present; otherwise falls back to parsing the
72
- * `.html` files into a flat list of pages (no databases, no nesting — the most
73
- * a human-readable folder can recover). Returns `null` if nothing parseable was
74
- * found, so the caller can surface "not an OpenBook folder".
86
+ * Reconstruct a space from a folder's files. Prefers the lossless structured
87
+ * sidecar ({@link SPACE_BUNDLE_FILE}, or the legacy {@link LEGACY_SPACE_BUNDLE_FILE}
88
+ * for folders exported before LIB-4) when present; otherwise falls back to
89
+ * parsing the `.html` files into a flat list of pages (no databases, no nesting
90
+ * — the most a human-readable folder can recover). Returns `null` if nothing
91
+ * parseable was found, so the caller can surface "not an OpenBook folder".
75
92
  */
76
- export declare function parseBookFolder(files: BookFolderFile[]): SpaceSnapshot | null;
93
+ export declare function parseBookFolder(files: BookFolderFile[]): LibrarySnapshot | null;
@@ -1,22 +1,40 @@
1
1
  import { pageToBookHtml, bookHtmlToPage, slugify, BOOK_RUNTIME_FILE } from './bookfile';
2
2
  import { islandScript, readIsland } from './island';
3
- /** Lossless structured sidecar, parsed back by {@link parseBookFolder}. */
4
- export const SPACE_BUNDLE_FILE = 'openbook.space.json';
3
+ /**
4
+ * Lossless structured sidecar filename that NEW exports write, parsed back by
5
+ * {@link parseBookFolder}. Renamed from the legacy `openbook.space.json`
6
+ * (LIB-4): the writer emits only this, while the reader also accepts
7
+ * {@link LEGACY_SPACE_BUNDLE_FILE} so folders exported before the rename still
8
+ * re-import losslessly.
9
+ */
10
+ export const SPACE_BUNDLE_FILE = 'openbook.library.json';
11
+ /**
12
+ * The pre-LIB-4 sidecar filename. READ-ONLY back-compat: {@link parseBookFolder}
13
+ * falls back to it so already-exported book folders keep importing. The writer
14
+ * never emits it.
15
+ */
16
+ export const LEGACY_SPACE_BUNDLE_FILE = 'openbook.space.json';
5
17
  /** Wrap a whole-space bundle as its source-island `<script>` (versioned, escaped). */
6
- export function spaceIslandScript(rootId, space, opts = {}) {
7
- return islandScript({ version: 1, rootId, space }, opts);
18
+ export function libraryIslandScript(rootId, space, opts = {}) {
19
+ // Writer emits ONLY the new `library` key; the reader dual-reads for back-compat.
20
+ return islandScript({ version: 1, rootId, library: space }, opts);
8
21
  }
9
- /** Read a site export's space island back, or `null` when absent/corrupt. */
10
- export function readSpaceIsland(html) {
22
+ /**
23
+ * Read a site export's space island back, or `null` when absent/corrupt.
24
+ * Dual-read: prefer the new `library` key, fall back to the legacy `space` key
25
+ * so bundles published before LIB-4 still import.
26
+ */
27
+ export function readLibraryIsland(html) {
11
28
  const parsed = readIsland(html);
12
- if (!parsed || !parsed.space || !Array.isArray(parsed.space.pages))
29
+ const bundle = parsed?.library ?? parsed?.space;
30
+ if (!bundle || !Array.isArray(bundle.pages))
13
31
  return null;
14
32
  return {
15
33
  version: 1,
16
- rootId: parsed.rootId ?? '',
34
+ rootId: parsed?.rootId ?? '',
17
35
  space: {
18
- pages: parsed.space.pages,
19
- databases: Array.isArray(parsed.space.databases) ? parsed.space.databases : [],
36
+ pages: bundle.pages,
37
+ databases: Array.isArray(bundle.databases) ? bundle.databases : [],
20
38
  },
21
39
  };
22
40
  }
@@ -47,9 +65,9 @@ function rootOf(page, byId, dbHost) {
47
65
  * Serialise a space to its on-disk files. By default includes the lossless
48
66
  * {@link SPACE_BUNDLE_FILE}; pass `includeBundle: false` for the human-readable
49
67
  * HTML files only. Pass `runtime` (the viewer bundle source) to make the folder
50
- * self-hydrating — see {@link SpaceToBookFilesOptions.runtime}.
68
+ * self-hydrating — see {@link LibraryToBookFilesOptions.runtime}.
51
69
  */
52
- export function spaceToBookFiles(snapshot, opts = {}) {
70
+ export function libraryToBookFiles(snapshot, opts = {}) {
53
71
  const { pages, databases } = snapshot;
54
72
  const byId = new Map(pages.map((p) => [p.id, p]));
55
73
  const dbHost = new Map(databases.map((d) => [d.id, d.pageId]));
@@ -73,15 +91,21 @@ export function spaceToBookFiles(snapshot, opts = {}) {
73
91
  }
74
92
  return files;
75
93
  }
94
+ /** Match a sidecar file by basename — the new name first, then the legacy one. */
95
+ const isSpaceBundleFile = (path) => path === SPACE_BUNDLE_FILE ||
96
+ path.endsWith(`/${SPACE_BUNDLE_FILE}`) ||
97
+ path === LEGACY_SPACE_BUNDLE_FILE ||
98
+ path.endsWith(`/${LEGACY_SPACE_BUNDLE_FILE}`);
76
99
  /**
77
- * Reconstruct a space from a folder's files. Prefers the lossless
78
- * {@link SPACE_BUNDLE_FILE} when present; otherwise falls back to parsing the
79
- * `.html` files into a flat list of pages (no databases, no nesting — the most
80
- * a human-readable folder can recover). Returns `null` if nothing parseable was
81
- * found, so the caller can surface "not an OpenBook folder".
100
+ * Reconstruct a space from a folder's files. Prefers the lossless structured
101
+ * sidecar ({@link SPACE_BUNDLE_FILE}, or the legacy {@link LEGACY_SPACE_BUNDLE_FILE}
102
+ * for folders exported before LIB-4) when present; otherwise falls back to
103
+ * parsing the `.html` files into a flat list of pages (no databases, no nesting
104
+ * — the most a human-readable folder can recover). Returns `null` if nothing
105
+ * parseable was found, so the caller can surface "not an OpenBook folder".
82
106
  */
83
107
  export function parseBookFolder(files) {
84
- const bundle = files.find((f) => f.path === SPACE_BUNDLE_FILE || f.path.endsWith(`/${SPACE_BUNDLE_FILE}`));
108
+ const bundle = files.find((f) => isSpaceBundleFile(f.path));
85
109
  if (bundle) {
86
110
  try {
87
111
  const parsed = JSON.parse(bundle.contents);
@@ -1 +1 @@
1
- {"version":3,"file":"bookFolder.js","sourceRoot":"","sources":["../src/bookFolder.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"bookFolder.js","sourceRoot":"","sources":["../src/bookFolder.ts"],"names":[],"mappings":"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"}
@@ -121,7 +121,7 @@ export interface BookHtmlOptions {
121
121
  * Reference the folder's shared viewer runtime (`_openbook/viewer.js`) so the
122
122
  * file, opened directly in a browser, hydrates into the interactive locked
123
123
  * viewer. Pass true ONLY when the writer also ships the bundle into the folder
124
- * (sdk `spaceToBookFiles({runtime})` / server `BookMirror` with `runtimeBundle`)
124
+ * (sdk `libraryToBookFiles({runtime})` / server `BookMirror` with `runtimeBundle`)
125
125
  * — a reference without the bundle degrades gracefully (static article), but
126
126
  * writers keep the invariant anyway. Emitters MUST agree on this flag for the
127
127
  * SDK/server byte-compatibility contract to hold.
package/dist/client.d.ts CHANGED
@@ -1,8 +1,9 @@
1
1
  import { type CompactResult } from './routes';
2
2
  import type { PluginPackage, StoredPlugin } from './plugins';
3
- import type { AgentChatEvent, AgentChatMessage, AgentChatOptions, AiConfig, AiPricingResponse, AiPricingTable, AiUsageResponse, AiSearchResponse, AiSkill, AiStatus, AiTasksResponse } from './ai';
3
+ import type { AgentChatEvent, AgentChatMessage, AgentChatOptions, AiConfig, AiPricingResponse, AiPricingTable, AiUsageResponse, AiSearchResponse, AiSkill, AiStatus, AiTasksResponse, McpClientConfig, McpConfigResponse, McpServerConfig, McpTestResult } from './ai';
4
4
  import type { AclLevel, Member, MemberRole, MemberStatus, PageAcl, PageInput, PageMeta, PageVisibility, StoredPage } from './types';
5
5
  import type { InstanceConfig, InstanceInfo, StoredEdit } from './provenance';
6
+ import type { AgentTokenMeta, AgentTokenScope } from './identity';
6
7
  import type { BackupCadence, BackupConfig, BackupStatus, ImportRequest, ImportResult } from './backup';
7
8
  import type { DatabaseInput, DatabaseRow, DatabaseUpdate, RowInput, RowUpdate, StoredDatabase } from './database';
8
9
  import type { CommentInput, StoredComment, StoredSuggestion, SuggestionInput, SuggestionStatus, SuggestionUpdate } from './suggestions';
@@ -13,6 +14,23 @@ export interface PageSubscription {
13
14
  /** The page was deleted. */
14
15
  onDeleted?: (id: string) => void;
15
16
  }
17
+ /** Input to {@link DataClient.createAgentToken}. `scope` defaults to `read`;
18
+ * `expiresInDays` defaults to 90 server-side, and `null` mints a no-expiry token. */
19
+ export interface CreateAgentTokenInput {
20
+ name: string;
21
+ scope?: AgentTokenScope;
22
+ expiresInDays?: number | null;
23
+ }
24
+ /** The one-time create response: the plaintext `token` (shown ONCE) + its meta. */
25
+ export interface CreatedAgentToken {
26
+ token: string;
27
+ meta: AgentTokenMeta;
28
+ }
29
+ /** The agent-token management view: the dark `agentApi` on/off state + the list. */
30
+ export interface AgentTokenList {
31
+ enabled: boolean;
32
+ tokens: AgentTokenMeta[];
33
+ }
16
34
  /**
17
35
  * Storage-agnostic data access used by the document UI.
18
36
  *
@@ -90,6 +108,16 @@ export interface DataClient {
90
108
  setAiUsageRetention(days: number): Promise<{
91
109
  days: number;
92
110
  }>;
111
+ /** Read the external-tools (MCP client) config (admin only): redacted config +
112
+ * whether the stdio transport is permitted on this instance. */
113
+ getMcpConfig(): Promise<McpConfigResponse>;
114
+ /** Save the external-tools (MCP client) config (admin only). Auth tokens are
115
+ * write-only (omit/blank preserves, a value sets, `null` clears). Returns the
116
+ * redacted result. */
117
+ putMcpConfig(config: McpClientConfig): Promise<McpConfigResponse>;
118
+ /** Dry-run one MCP server config (admin only): connect + list tools; never
119
+ * returns secrets. */
120
+ testMcpServer(server: McpServerConfig): Promise<McpTestResult>;
93
121
  listPlugins(): Promise<StoredPlugin[]>;
94
122
  installPlugin(pkg: PluginPackage): Promise<StoredPlugin>;
95
123
  setPluginEnabled(id: string, enabled: boolean): Promise<StoredPlugin>;
@@ -101,12 +129,12 @@ export interface DataClient {
101
129
  */
102
130
  deletePage(id: string): Promise<boolean>;
103
131
  /** Export the whole space: every live page (full data) + every database. */
104
- exportSpace(): Promise<{
132
+ exportLibrary(): Promise<{
105
133
  pages: StoredPage[];
106
134
  databases: StoredDatabase[];
107
135
  }>;
108
136
  /** Restore a (client-selected) set of pages/databases; see {@link ImportRequest}. */
109
- importSpace(req: ImportRequest): Promise<ImportResult>;
137
+ importLibrary(req: ImportRequest): Promise<ImportResult>;
110
138
  /** List the trash (most-recently-deleted first). */
111
139
  listTrash(): Promise<PageMeta[]>;
112
140
  /** Restore a trashed page, or `null` if it isn't in the trash. */
@@ -269,6 +297,17 @@ export interface DataClient {
269
297
  }): Promise<Member>;
270
298
  /** Revoke a roster row by id. `true` if one was removed. */
271
299
  removeMember(id: string): Promise<boolean>;
300
+ /** List minted agent tokens (redacted) plus the dark `agentApi` on/off state. */
301
+ listAgentTokens(): Promise<AgentTokenList>;
302
+ /** Toggle the dark `agentApi` setting on/off. Returns the new state. */
303
+ setAgentApiEnabled(enabled: boolean): Promise<{
304
+ enabled: boolean;
305
+ }>;
306
+ /** Mint a token (requires `agentApi` enabled). The plaintext `token` comes back
307
+ * exactly ONCE — store it now; only its hash is kept server-side. */
308
+ createAgentToken(input: CreateAgentTokenInput): Promise<CreatedAgentToken>;
309
+ /** Revoke a token by id. `true` if one was removed. */
310
+ revokeAgentToken(id: string): Promise<boolean>;
272
311
  /** Scheduled-backup policy + per-cadence status. */
273
312
  getBackupStatus(): Promise<BackupStatus>;
274
313
  /** Update the backup policy (enable, cadences, retention, folder). Owner-only. */
@@ -404,11 +443,11 @@ export declare class HttpDataClient implements DataClient {
404
443
  orderedIds: string[];
405
444
  }): Promise<StoredPage>;
406
445
  deletePage(id: string): Promise<boolean>;
407
- exportSpace(): Promise<{
446
+ exportLibrary(): Promise<{
408
447
  pages: StoredPage[];
409
448
  databases: StoredDatabase[];
410
449
  }>;
411
- importSpace(req: ImportRequest): Promise<ImportResult>;
450
+ importLibrary(req: ImportRequest): Promise<ImportResult>;
412
451
  listTrash(): Promise<PageMeta[]>;
413
452
  restorePage(id: string): Promise<StoredPage | null>;
414
453
  purgePage(id: string): Promise<boolean>;
@@ -501,6 +540,12 @@ export declare class HttpDataClient implements DataClient {
501
540
  }): Promise<Member>;
502
541
  /** Revoke a roster row by id. `true` if one was removed. */
503
542
  removeMember(id: string): Promise<boolean>;
543
+ listAgentTokens(): Promise<AgentTokenList>;
544
+ setAgentApiEnabled(enabled: boolean): Promise<{
545
+ enabled: boolean;
546
+ }>;
547
+ createAgentToken(input: CreateAgentTokenInput): Promise<CreatedAgentToken>;
548
+ revokeAgentToken(id: string): Promise<boolean>;
504
549
  /** A page's stored visibility scope (raw — `inherit` not yet resolved), or
505
550
  * `null` if the page does not exist. Gated on read of the page. */
506
551
  getPageVisibility(pageId: string): Promise<PageVisibility | null>;
@@ -554,6 +599,9 @@ export declare class HttpDataClient implements DataClient {
554
599
  aiDeleteSkill(name: string): Promise<boolean>;
555
600
  getAiPricing(): Promise<AiPricingResponse>;
556
601
  setAiPricing(override: AiPricingTable): Promise<AiPricingResponse>;
602
+ getMcpConfig(): Promise<McpConfigResponse>;
603
+ putMcpConfig(config: McpClientConfig): Promise<McpConfigResponse>;
604
+ testMcpServer(server: McpServerConfig): Promise<McpTestResult>;
557
605
  getAiUsage(): Promise<AiUsageResponse>;
558
606
  setAiUsageRetention(days: number): Promise<{
559
607
  days: number;