@stll/folio-cli 0.0.1-placeholder.0 → 0.1.1
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 +298 -0
- package/dist/bin.d.ts +1 -0
- package/dist/bin.js +30 -0
- package/dist/cli.d.ts +25 -0
- package/dist/cli.js +440 -0
- package/dist/document.d.ts +43 -0
- package/dist/document.js +127 -0
- package/dist/errors.d.ts +67 -0
- package/dist/errors.js +92 -0
- package/dist/execute-read.d.ts +64 -0
- package/dist/execute-read.js +220 -0
- package/dist/execute-write.d.ts +36 -0
- package/dist/execute-write.js +449 -0
- package/dist/flags.d.ts +38 -0
- package/dist/flags.js +102 -0
- package/dist/journal.d.ts +82 -0
- package/dist/journal.js +212 -0
- package/dist/lock.d.ts +55 -0
- package/dist/lock.js +157 -0
- package/dist/mcp.d.ts +28 -0
- package/dist/mcp.js +310 -0
- package/dist/output-file.d.ts +14 -0
- package/dist/output-file.js +60 -0
- package/dist/output.d.ts +33 -0
- package/dist/output.js +77 -0
- package/dist/package-parts.d.ts +24 -0
- package/dist/package-parts.js +172 -0
- package/dist/package.js +4 -0
- package/dist/preview-commands.d.ts +8 -0
- package/dist/preview-commands.js +226 -0
- package/dist/provenance.d.ts +17 -0
- package/dist/provenance.js +53 -0
- package/dist/registry.d.ts +69 -0
- package/dist/registry.js +255 -0
- package/dist/render.d.ts +35 -0
- package/dist/render.js +120 -0
- package/dist/roots.d.ts +21 -0
- package/dist/roots.js +57 -0
- package/dist/serve.d.ts +17 -0
- package/dist/serve.js +234 -0
- package/dist/sidecar.d.ts +52 -0
- package/dist/sidecar.js +156 -0
- package/dist/transaction.d.ts +55 -0
- package/dist/transaction.js +218 -0
- package/package.json +85 -3
package/README.md
ADDED
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
# @stll/folio-cli
|
|
2
|
+
|
|
3
|
+
`folio`: a command line for reading and reviewing `.docx` files on disk. It
|
|
4
|
+
runs the [`@stll/folio-agents`](https://www.npmjs.com/package/@stll/folio-agents)
|
|
5
|
+
tools over local files, so a script, a person at a terminal, and an agent see
|
|
6
|
+
the same blocks, ids, and results.
|
|
7
|
+
|
|
8
|
+
Part of [stella](https://github.com/stella/stella), an open-source legal workspace.
|
|
9
|
+
|
|
10
|
+
## Install
|
|
11
|
+
|
|
12
|
+
```sh
|
|
13
|
+
bun add -g @stll/folio-cli # or: npm install -g @stll/folio-cli
|
|
14
|
+
folio --help
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Node.js 22 or later.
|
|
18
|
+
|
|
19
|
+
## Reading
|
|
20
|
+
|
|
21
|
+
| Command | Tool | Prints |
|
|
22
|
+
| ---------- | ---------------------- | ------------------------------------------------------ |
|
|
23
|
+
| `read` | `read_document` | Body blocks with ids, text, and `blockTextHash`, paged |
|
|
24
|
+
| `outline` | `get_document_outline` | Heading outline with section handles |
|
|
25
|
+
| `section` | `read_section` | One section's blocks, by handle |
|
|
26
|
+
| `stories` | `list_stories` | Header, footer, footnote, and endnote story handles |
|
|
27
|
+
| `story` | `read_story` | One story's text, by handle |
|
|
28
|
+
| `find` | `find_text` | Exact matches with range handles and context |
|
|
29
|
+
| `comments` | `read_comments` | Comment threads with replies and resolved state |
|
|
30
|
+
| `changes` | `read_changes` | Pending tracked changes |
|
|
31
|
+
|
|
32
|
+
```sh
|
|
33
|
+
folio read contract.docx --max-blocks 50
|
|
34
|
+
folio find contract.docx --query "Termination" --whole-word
|
|
35
|
+
# the handle is copied from `folio outline`
|
|
36
|
+
folio section contract.docx --handle '{"type":"headingSection","story":"main","headingBlockId":"1A2B3C4D","headingTextHash":"h5f3a9c","headingLevel":1}'
|
|
37
|
+
folio comments contract.docx --filter open --output text
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Each command's flags are generated from its tool's input schema: a property
|
|
41
|
+
`matchCase` is `--match-case`; objects and arrays take JSON. `--input` passes
|
|
42
|
+
the whole argument object as JSON (inline, `@args.json`, or `-` for stdin), and
|
|
43
|
+
flags given with it override its fields. `folio <command> --help` lists them.
|
|
44
|
+
|
|
45
|
+
Reading never writes: not the file, not identifiers, not a cache.
|
|
46
|
+
|
|
47
|
+
## Changing a document
|
|
48
|
+
|
|
49
|
+
| Command | Tool | Does |
|
|
50
|
+
| --------- | ------------------- | ------------------------------------------------------------ |
|
|
51
|
+
| `suggest` | `suggest_changes` | Applies a batch of edit operations as tracked changes |
|
|
52
|
+
| `comment` | `add_comment` | Comments on a block, optionally quoting text in it |
|
|
53
|
+
| `reply` | `reply_comment` | Replies to a comment thread |
|
|
54
|
+
| `resolve` | `resolve_comment` | Resolves or reopens a comment thread |
|
|
55
|
+
| `accept` | `resolve_changes` | Accepts tracked changes: `--id <id>` (repeatable) or `--all` |
|
|
56
|
+
| `reject` | `resolve_changes` | Rejects tracked changes: `--id <id>` (repeatable) or `--all` |
|
|
57
|
+
| `compare` | `compare_documents` | Diffs two files; with `-o`, writes their redline |
|
|
58
|
+
|
|
59
|
+
```sh
|
|
60
|
+
folio suggest contract.docx --input @ops.json --in-place --expect-version 9f2c…
|
|
61
|
+
folio comment contract.docx --block-id 1A2B3C4D --text "Confirm the rate." -o reviewed.docx --expect-version 9f2c…
|
|
62
|
+
folio accept contract.docx --all --in-place --expect-version 51ab…
|
|
63
|
+
folio compare signed.docx draft.docx -o redline.docx --expect-version 07de…
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
`suggest --input` takes the operation batch: `{ "operations": [...] }`, or the
|
|
67
|
+
bare array. The operation types and fields are those of `suggest_changes` in
|
|
68
|
+
`@stll/folio-agents` (`folio suggest --help` lists them); every operation's
|
|
69
|
+
targets come from a read of the same `fileVersion`. Edits are tracked changes;
|
|
70
|
+
`--direct` edits the text instead and must be asked for.
|
|
71
|
+
|
|
72
|
+
Every change commits, so there is no separate save:
|
|
73
|
+
|
|
74
|
+
- **Destination.** Exactly one of `--in-place` or `-o <path>`, and only a
|
|
75
|
+
`.docx` whose name does not start with a dot and that is not inside a
|
|
76
|
+
`.folio` directory (`invalid_destination`). `-o` never modifies the input
|
|
77
|
+
and refuses a path that is the input (or, for `compare`, the revised file)
|
|
78
|
+
under another name: symlinks and hard links are resolved and files are
|
|
79
|
+
compared by device and inode. `-o` refuses an existing file unless
|
|
80
|
+
`--overwrite` is given with `--expect-destination-version <fileVersion>`
|
|
81
|
+
of the file being replaced.
|
|
82
|
+
- **Preconditions.** A change needs `--expect-version <fileVersion>` from the
|
|
83
|
+
read it was based on, and refuses (`stale_version`, exit 10) a file that
|
|
84
|
+
changed since; `--no-expect-version` skips the check and must be given
|
|
85
|
+
explicitly. Under the write lease the file is hashed again right before
|
|
86
|
+
the commit, so a change made during the edit is refused too. A batch lands whole
|
|
87
|
+
or not at all: a stale target (`stale_target`, exit 10), an ambiguous `find`
|
|
88
|
+
(`ambiguous_target`, exit 2), or any other refused operation writes nothing,
|
|
89
|
+
with the per-operation reasons in `error.details`.
|
|
90
|
+
- **Atomic write.** The new package is staged beside the destination, checked
|
|
91
|
+
(it reopens, every changed XML part is well formed, every relationship id a
|
|
92
|
+
changed part uses resolves, every internal target a changed `.rels` part
|
|
93
|
+
names exists), flushed to disk, and renamed over the destination. Whatever
|
|
94
|
+
a write replaces (in place, or with `--overwrite`) is first copied to
|
|
95
|
+
`.folio/backups/<document name>/<fileVersion>.docx`, flushed with its
|
|
96
|
+
directory; the newest 20 per document are kept. A file with more than one
|
|
97
|
+
hard link is not written in place.
|
|
98
|
+
- **Minimal saves.** A change is written by patching the edited paragraphs
|
|
99
|
+
into the original package, leaving every other part's content as it was.
|
|
100
|
+
When that is not possible (a paragraph added or removed, styles or section
|
|
101
|
+
properties changed) the command refuses with `repack_required` rather than
|
|
102
|
+
silently rewriting the whole package; `--allow-repack` permits it. The
|
|
103
|
+
receipt reports `saveStrategy` (`selective`, `full-repack` with a
|
|
104
|
+
`repackReason`, or `redline`) and `changedParts`. The promise is part
|
|
105
|
+
content, not identical ZIP bytes.
|
|
106
|
+
- **Write lease.** A write holds `.<name>.docx.folio-lock` beside the file
|
|
107
|
+
(pid, host, expiry, and a random token), created complete or not at all.
|
|
108
|
+
Another holder, such as an editor session, makes a write fail with
|
|
109
|
+
`locked` (exit 10) unless `--force`. Just before journaling and again
|
|
110
|
+
before the rename, a write checks that the lock still carries its token, so
|
|
111
|
+
a writer whose lease was taken over stops without writing. Reads ignore the
|
|
112
|
+
lease. A lease whose process has exited, or that expired, is replaced; a
|
|
113
|
+
lock that cannot be parsed counts as held until it is older than a lease.
|
|
114
|
+
- **Sidecar files.** The lock, the stage, the journal, and backups are never
|
|
115
|
+
read or written through a symlink or a file with more than one hard link
|
|
116
|
+
(`unsafe_path`, exit 8). `.folio` and its subdirectories are created with
|
|
117
|
+
mode 0700; an existing `.folio` that is a symlink or not a directory is
|
|
118
|
+
refused, not followed.
|
|
119
|
+
- **Author and time.** The author is `--author`, else `FOLIO_AUTHOR`, else git
|
|
120
|
+
`user.name`; with none, the command refuses. Every revision, comment, and
|
|
121
|
+
reply of one transaction carries one UTC timestamp, `--date` to fix it for
|
|
122
|
+
reproducible output. (`compare` stamps its redline with the current time.)
|
|
123
|
+
|
|
124
|
+
### Journal, retries, and recovery
|
|
125
|
+
|
|
126
|
+
Each committed transaction appends a line to `.folio/journal.jsonl` beside the
|
|
127
|
+
destination (or `--journal <path>`): its `txId`, `fromVersion`, `toVersion`,
|
|
128
|
+
author, time, the operations, their receipts, and the command's receipt.
|
|
129
|
+
|
|
130
|
+
`--tx-id <key>` makes a change idempotent: running a committed transaction
|
|
131
|
+
again returns its original receipt with `status: "replayed"` and writes
|
|
132
|
+
nothing; reusing the key for a different request is refused
|
|
133
|
+
(`transaction_conflict`).
|
|
134
|
+
|
|
135
|
+
The journal line is written after the staged package validates and before the
|
|
136
|
+
rename. If a process dies between the two, the next write to that file
|
|
137
|
+
completes the rename only when the line names that file, the stage is a
|
|
138
|
+
regular single-link file holding the recorded version, it still parses as a
|
|
139
|
+
package, and the file is still what the transaction replaced; any other stage
|
|
140
|
+
is discarded (unlinked, never followed). Recovery is reported under
|
|
141
|
+
`recovered`, and the write's own version check runs against the file as
|
|
142
|
+
recovery left it.
|
|
143
|
+
|
|
144
|
+
### Known limits
|
|
145
|
+
|
|
146
|
+
A process on the same machine that can rename directories inside the
|
|
147
|
+
document's directory while a write runs can still race it: names are
|
|
148
|
+
resolved, then re-checked (the handle's device and inode against the checked
|
|
149
|
+
path, and the directory's real path just before the rename), but not held
|
|
150
|
+
open across the whole transaction. The tool caller cannot exploit this; it
|
|
151
|
+
matters only against another local actor with write access to the
|
|
152
|
+
directory.
|
|
153
|
+
|
|
154
|
+
## Rendering and preview
|
|
155
|
+
|
|
156
|
+
```sh
|
|
157
|
+
folio render contract.docx -o contract.pdf
|
|
158
|
+
folio render contract.docx -o page-3.png --page 3
|
|
159
|
+
folio serve contract.docx
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
`folio render` lays the document out with folio's own layout engine and
|
|
163
|
+
paints it with folio's painters, with no word processor involved: `.pdf` from
|
|
164
|
+
the PDF backend (every page, or `--page n`), `.html` from the DOM backend,
|
|
165
|
+
and `.png` by screenshotting that page in headless Chromium (page 1 unless
|
|
166
|
+
`--page`, `--scale` pixels per CSS pixel, default 2). Text is measured and
|
|
167
|
+
painted with the metric-compatible `@fontsource` faces the CLI installs. PNG
|
|
168
|
+
needs `playwright-core` and its Chromium, which the CLI does not install:
|
|
169
|
+
|
|
170
|
+
```sh
|
|
171
|
+
npm install playwright-core && npx playwright-core install chromium
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
`-o` refuses an existing file unless `--overwrite`; the document is never
|
|
175
|
+
changed.
|
|
176
|
+
|
|
177
|
+
`folio serve` prints a URL and serves a read-only preview of the document on
|
|
178
|
+
`127.0.0.1` until interrupted. The page re-renders when the file's version
|
|
179
|
+
changes: it watches the file and its `.folio/journal.jsonl`, so a change from
|
|
180
|
+
`folio suggest`, the MCP server, or any other program appears on its own. The
|
|
181
|
+
URL carries a random token; requests without it, with a `Host` other than
|
|
182
|
+
the loopback address, or with a method other than GET are refused. The server
|
|
183
|
+
never writes, not even a lock.
|
|
184
|
+
|
|
185
|
+
## Output
|
|
186
|
+
|
|
187
|
+
Every command prints one envelope:
|
|
188
|
+
|
|
189
|
+
```json
|
|
190
|
+
{ "ok": true, "data": { "path": "/abs/contract.docx", "fileVersion": "9f2c…", "result": {} } }
|
|
191
|
+
{ "ok": false, "error": { "code": "stale_version", "message": "…", "hint": "Re-read the document…" } }
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
`--output json` (the default when stdout is not a terminal) prints the
|
|
195
|
+
envelope on stdout for success and failure alike. `--output text` (the default
|
|
196
|
+
on a terminal) prints a readable rendering, and failures as `error:` and
|
|
197
|
+
`hint:` lines on stderr.
|
|
198
|
+
|
|
199
|
+
| Exit | Meaning |
|
|
200
|
+
| ---- | -------------------------------------------------------------------------- |
|
|
201
|
+
| 0 | success |
|
|
202
|
+
| 1 | unexpected internal error |
|
|
203
|
+
| 2 | usage, input, or refused-operation error |
|
|
204
|
+
| 6 | file, change, or comment not found |
|
|
205
|
+
| 8 | path outside the allowed roots, or unsafe to write through |
|
|
206
|
+
| 10 | conflict with current state (stale version, lock held, destination exists) |
|
|
207
|
+
|
|
208
|
+
## Versions and identifiers
|
|
209
|
+
|
|
210
|
+
`fileVersion` is the lowercase hex SHA-256 of the file's bytes.
|
|
211
|
+
`--expect-version <sha256>` refuses the command (exit 10, `stale_version`)
|
|
212
|
+
unless the file still has that version.
|
|
213
|
+
|
|
214
|
+
A block id is the paragraph's own `w14:paraId` when it has one
|
|
215
|
+
(`blockIdSource: "package"`). A paragraph without one gets an id derived from
|
|
216
|
+
its text and position (`blockIdSource: "synthetic"`): stable across reads of
|
|
217
|
+
the same bytes, but valid only for the `fileVersion` it was read at.
|
|
218
|
+
|
|
219
|
+
`read` pages with `--max-blocks`; a page that stops early carries
|
|
220
|
+
`nextCursor`, which `--cursor` continues. A cursor is bound to the version it
|
|
221
|
+
was issued for, so a cursor from before an edit is refused rather than
|
|
222
|
+
continuing on different content.
|
|
223
|
+
|
|
224
|
+
Offsets in range handles (`startOffset`, `endOffset`) are UTF-16 code-unit
|
|
225
|
+
indices into the block `text` that `read` returns, the indexing JavaScript
|
|
226
|
+
strings use. A consumer that counts Unicode code points converts with
|
|
227
|
+
`Array.from(text.slice(0, offset)).length`.
|
|
228
|
+
|
|
229
|
+
## MCP server
|
|
230
|
+
|
|
231
|
+
`folio mcp` serves the same tools over the Model Context Protocol on stdio:
|
|
232
|
+
the protocol owns stdout, diagnostics go to stderr.
|
|
233
|
+
|
|
234
|
+
```sh
|
|
235
|
+
folio mcp --root ~/contracts --author "Jane Doe"
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
Claude Code, in a project's `.mcp.json`:
|
|
239
|
+
|
|
240
|
+
```json
|
|
241
|
+
{
|
|
242
|
+
"mcpServers": {
|
|
243
|
+
"folio": {
|
|
244
|
+
"command": "npx",
|
|
245
|
+
"args": ["-y", "@stll/folio-cli", "mcp", "--root", "."],
|
|
246
|
+
"env": { "FOLIO_AUTHOR": "Jane Doe" }
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
Codex, in `~/.codex/config.toml`:
|
|
253
|
+
|
|
254
|
+
```toml
|
|
255
|
+
[mcp_servers.folio]
|
|
256
|
+
command = "npx"
|
|
257
|
+
args = ["-y", "@stll/folio-cli", "mcp", "--root", "/path/to/contracts"]
|
|
258
|
+
env = { FOLIO_AUTHOR = "Jane Doe" }
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
Tools: `read_document`, `get_document_outline`, `read_section`,
|
|
262
|
+
`list_stories`, `read_story`, `find_text`, `read_comments`, `read_changes`,
|
|
263
|
+
`suggest_changes`, `add_comment`, `reply_comment`, `resolve_comment`,
|
|
264
|
+
`resolve_changes`, and `compare_documents`. Each takes its folio-agents
|
|
265
|
+
arguments plus a file envelope:
|
|
266
|
+
|
|
267
|
+
| Field | Meaning |
|
|
268
|
+
| ---------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
|
|
269
|
+
| `path` | The `.docx`, absolute or relative to the first root |
|
|
270
|
+
| `fileVersion` | Required on every change (including `compare_documents` with a `destination`): the version the caller read; optional on reads |
|
|
271
|
+
| `destination` | Write the result to this `.docx` instead of changing `path` in place (not a dotfile, not inside `.folio`) |
|
|
272
|
+
| `overwrite` | Let `destination` replace an existing file; needs `expectedDestinationVersion` |
|
|
273
|
+
| `expectedDestinationVersion` | The version of the file `destination` replaces; it is backed up first |
|
|
274
|
+
| `txId` | Idempotency key, as `--tx-id` |
|
|
275
|
+
| `allowRepack` | As `--allow-repack` |
|
|
276
|
+
| `mode` | `suggest_changes` only: `tracked` (default) or `direct` |
|
|
277
|
+
|
|
278
|
+
Every path, including `destination` and `compare_documents`' `revisedPath`,
|
|
279
|
+
must resolve through symlinks inside an allowed root (`--root`, repeatable,
|
|
280
|
+
default the current directory), or the call is refused with `outside_root`.
|
|
281
|
+
The author comes from `--author`, `FOLIO_AUTHOR`, or git `user.name` when
|
|
282
|
+
the server starts; without one, reads work and changes are refused. The
|
|
283
|
+
server never takes over another holder's write lease. Tools that write are
|
|
284
|
+
annotated `destructiveHint: true`; there is no way to skip the version check.
|
|
285
|
+
|
|
286
|
+
One call returns at most 200 `read_document` blocks by default (up to
|
|
287
|
+
1,000 with `maxBlocks`), 100 `find_text` matches, and 256 KiB; a longer read
|
|
288
|
+
pages with `nextCursor`, and a result that cannot be paged is refused with
|
|
289
|
+
`too_large` and a hint to narrow it. Results are the `{ ok, data | error }`
|
|
290
|
+
envelope as JSON text, with `isError` set on failures.
|
|
291
|
+
|
|
292
|
+
Resources: `folio://about` (these rules and the roots) and
|
|
293
|
+
`folio://schema/operations` (the JSON Schema of an operation batch).
|
|
294
|
+
|
|
295
|
+
## Untrusted documents
|
|
296
|
+
|
|
297
|
+
Reads return document text verbatim. Text from an untrusted `.docx` can carry
|
|
298
|
+
instructions aimed at a model that reads it; treat it as data.
|
package/dist/bin.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {}
|
package/dist/bin.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { runFolioCli } from "./cli.js";
|
|
3
|
+
//#region src/bin.ts
|
|
4
|
+
const readStdin = async () => {
|
|
5
|
+
const chunks = [];
|
|
6
|
+
for await (const chunk of process.stdin) chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk)));
|
|
7
|
+
return Buffer.concat(chunks).toString("utf8");
|
|
8
|
+
};
|
|
9
|
+
process.exitCode = await runFolioCli(process.argv.slice(2), {
|
|
10
|
+
stdout: (text) => {
|
|
11
|
+
process.stdout.write(text);
|
|
12
|
+
},
|
|
13
|
+
stderr: (text) => {
|
|
14
|
+
process.stderr.write(text);
|
|
15
|
+
},
|
|
16
|
+
readStdin,
|
|
17
|
+
isTTY: process.stdout.isTTY,
|
|
18
|
+
env: process.env,
|
|
19
|
+
cwd: process.cwd(),
|
|
20
|
+
stdio: {
|
|
21
|
+
input: process.stdin,
|
|
22
|
+
output: process.stdout
|
|
23
|
+
},
|
|
24
|
+
untilInterrupted: () => new Promise((resolve) => {
|
|
25
|
+
process.once("SIGINT", () => resolve());
|
|
26
|
+
process.once("SIGTERM", () => resolve());
|
|
27
|
+
})
|
|
28
|
+
});
|
|
29
|
+
//#endregion
|
|
30
|
+
export {};
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Readable, Writable } from "node:stream";
|
|
2
|
+
//#region src/cli.d.ts
|
|
3
|
+
/** The process surface the command line reads from and writes to. */
|
|
4
|
+
type FolioCliIo = {
|
|
5
|
+
stdout: (text: string) => void;
|
|
6
|
+
stderr: (text: string) => void;
|
|
7
|
+
readStdin: () => Promise<string>;
|
|
8
|
+
/** Whether stdout is a terminal; picks the default output format. */
|
|
9
|
+
isTTY: boolean;
|
|
10
|
+
/** Environment for `FOLIO_AUTHOR`. */
|
|
11
|
+
env: Readonly<Record<string, string | undefined>>;
|
|
12
|
+
/** Directory whose git `user.name` is the last author fallback, and the default MCP root. */
|
|
13
|
+
cwd: string;
|
|
14
|
+
/** Byte streams `folio mcp` speaks the protocol over; absent, it refuses to start. */
|
|
15
|
+
stdio?: {
|
|
16
|
+
input: Readable;
|
|
17
|
+
output: Writable;
|
|
18
|
+
};
|
|
19
|
+
/** Resolves when the process is asked to stop; `folio serve` runs until then. */
|
|
20
|
+
untilInterrupted?: () => Promise<void>;
|
|
21
|
+
};
|
|
22
|
+
/** Run `folio` with the given arguments (without the executable); resolves to the exit code. */
|
|
23
|
+
declare const runFolioCli: (argv: readonly string[], io: FolioCliIo) => Promise<number>;
|
|
24
|
+
//#endregion
|
|
25
|
+
export { FolioCliIo, runFolioCli };
|