tgo-wiki 0.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/CHANGELOG.md +32 -0
- package/README.md +255 -0
- package/docs/mcp-usage.md +631 -0
- package/docs/v0-acceptance.md +105 -0
- package/docs/v0-delivery-checklist.md +57 -0
- package/docs/v1-acceptance.md +39 -0
- package/docs/v2-acceptance.md +165 -0
- package/package.json +69 -0
- package/packages/core/src/config/config-loader.ts +109 -0
- package/packages/core/src/config/defaults.ts +74 -0
- package/packages/core/src/config/workspace-resolver.ts +40 -0
- package/packages/core/src/documents/command-document-parser.ts +206 -0
- package/packages/core/src/documents/document-id.ts +26 -0
- package/packages/core/src/documents/document-parser-registry.ts +126 -0
- package/packages/core/src/documents/document-service.ts +656 -0
- package/packages/core/src/documents/document-store.ts +132 -0
- package/packages/core/src/documents/document-types.ts +33 -0
- package/packages/core/src/documents/pdf-text-parser.ts +35 -0
- package/packages/core/src/documents/text-markdown-parser.ts +50 -0
- package/packages/core/src/errors.ts +46 -0
- package/packages/core/src/git/git-service.ts +68 -0
- package/packages/core/src/index.ts +38 -0
- package/packages/core/src/markdown/markdown-scanner.ts +90 -0
- package/packages/core/src/permissions/permission-service.ts +50 -0
- package/packages/core/src/publish/publish-service.ts +142 -0
- package/packages/core/src/result.ts +13 -0
- package/packages/core/src/services/session-workflow-service.ts +493 -0
- package/packages/core/src/services/wiki-service.ts +119 -0
- package/packages/core/src/services/workspace-service.ts +223 -0
- package/packages/core/src/session/session-id.ts +14 -0
- package/packages/core/src/session/session-service.ts +77 -0
- package/packages/core/src/session/session-store.ts +91 -0
- package/packages/core/src/session/session-types.ts +17 -0
- package/packages/core/src/sources/source-id.ts +19 -0
- package/packages/core/src/sources/source-paths.ts +15 -0
- package/packages/core/src/sources/source-service.ts +416 -0
- package/packages/core/src/sources/source-types.ts +77 -0
- package/packages/core/src/sources/source-validator.ts +132 -0
- package/packages/core/src/sources/source-writer.ts +419 -0
- package/packages/core/src/validation/frontmatter-validator.ts +128 -0
- package/packages/core/src/validation/link-validator.ts +55 -0
- package/packages/core/src/validation/path-validator.ts +65 -0
- package/packages/core/src/validation/source-reference-validator.ts +191 -0
- package/packages/core/src/validation/validation-service.ts +106 -0
- package/packages/core/src/vfs/vfs-command-parser.ts +69 -0
- package/packages/core/src/vfs/vfs-service.ts +498 -0
- package/packages/core/src/web/html-to-markdown.ts +144 -0
- package/packages/core/src/web/static-web-fetcher.ts +537 -0
- package/packages/core/src/web/web-id.ts +26 -0
- package/packages/core/src/web/web-ingestion-service.ts +335 -0
- package/packages/core/src/web/web-paths.ts +6 -0
- package/packages/core/src/web/web-types.ts +33 -0
- package/packages/server/src/cli.ts +56 -0
- package/packages/server/src/context.ts +7 -0
- package/packages/server/src/index.ts +2 -0
- package/packages/server/src/mcp-server.ts +111 -0
- package/packages/server/src/schemas/documents.ts +17 -0
- package/packages/server/src/schemas/read.ts +16 -0
- package/packages/server/src/schemas/session.ts +31 -0
- package/packages/server/src/schemas/sources.ts +12 -0
- package/packages/server/src/schemas/web.ts +23 -0
- package/packages/server/src/tools/document-tools.ts +46 -0
- package/packages/server/src/tools/publish-tools.ts +33 -0
- package/packages/server/src/tools/read-tools.ts +52 -0
- package/packages/server/src/tools/response.ts +24 -0
- package/packages/server/src/tools/session-tools.ts +100 -0
- package/packages/server/src/tools/source-tools.ts +32 -0
- package/packages/server/src/tools/web-tools.ts +26 -0
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# Agent Wiki v0 Acceptance Gate
|
|
2
|
+
|
|
3
|
+
Date: 2026-06-11
|
|
4
|
+
|
|
5
|
+
## Purpose
|
|
6
|
+
|
|
7
|
+
This document defines the local acceptance gate for the v0 MCP-first Agent Wiki slice. Run this gate before treating v0 as ready for handoff, release, or follow-on feature work.
|
|
8
|
+
|
|
9
|
+
v0 is now historical scope. For the current v2 release gate, use [v2-acceptance.md](./v2-acceptance.md), which extends the v1 document ingestion, source read, and fast-forward publish baseline with web ingestion.
|
|
10
|
+
|
|
11
|
+
The gate is intentionally black-box at the outer edge: the dedicated black-box package starts the public CLI and talks to the MCP server over stdio JSON-RPC. It must not import `@tgo-wiki/core`, `@tgo-wiki/server`, or internal service modules.
|
|
12
|
+
|
|
13
|
+
## Required Commands
|
|
14
|
+
|
|
15
|
+
For historical v0 verification, run from the repository root:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
bun install
|
|
19
|
+
bun run verify:v0
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Acceptance requires every command to exit with code 0.
|
|
23
|
+
|
|
24
|
+
At the time of v0 delivery, `bun run release:check` was the single local release-readiness gate and expanded to:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
bun run verify:v0 && bun run smoke:pack && bun pm pack --dry-run
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
`bun run verify:v0` runs the full local v0 gate:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
bun run check && bun run test:blackbox
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
`bun run check` runs the default unit and integration test suite for `packages/core` and `packages/server`, then runs `tsc --noEmit`.
|
|
37
|
+
|
|
38
|
+
`bun run test:blackbox` runs the independent `packages/blackbox-tests` package. This suite is explicit by design and is not part of the default `bun run test` command.
|
|
39
|
+
|
|
40
|
+
`bun run smoke:pack` creates a tarball with `bun pm pack`, installs that tarball into a temporary consumer project, and exercises the installed `tgo-wiki` bin for CLI init/status plus MCP `initialize` and `tools/list`.
|
|
41
|
+
|
|
42
|
+
`bun run smoke:cli` runs the same CLI/MCP flow through a faster `file:` install. It is useful during local development, while `smoke:pack` is the release-readiness gate.
|
|
43
|
+
|
|
44
|
+
The GitHub Actions workflow at `.github/workflows/v0-acceptance.yml` runs `bun run check`, `bun run test:blackbox`, and `bun run smoke:pack` as separate jobs.
|
|
45
|
+
|
|
46
|
+
## Historical v0 Black-Box Coverage
|
|
47
|
+
|
|
48
|
+
The black-box package must verify these public behaviors through `packages/server/src/cli.ts` only:
|
|
49
|
+
|
|
50
|
+
- `tgo-wiki init --workspace <path>` creates a usable local workspace.
|
|
51
|
+
- `tgo-wiki status --workspace <path>` reports the stable branch, clean status, and session count.
|
|
52
|
+
- MCP `initialize` and `tools/list` expose exactly the v0 tool surface.
|
|
53
|
+
- `wiki_read` reads stable Markdown content.
|
|
54
|
+
- `vfs_exec` executes allowed read-only VFS commands.
|
|
55
|
+
- A writer can complete the session flow:
|
|
56
|
+
- `wiki_session_start`
|
|
57
|
+
- `wiki_session_patch`
|
|
58
|
+
- `wiki_session_validate`
|
|
59
|
+
- `wiki_session_diff`
|
|
60
|
+
- `wiki_session_commit`
|
|
61
|
+
- A committed session branch does not mutate stable content.
|
|
62
|
+
- A reader receives permission errors for every writer-only session tool.
|
|
63
|
+
- Read tools reject unsupported refs and path traversal attempts.
|
|
64
|
+
- Session patch rejects unsafe paths and unified patch payloads.
|
|
65
|
+
- Invalid Markdown produces validation errors and cannot be committed.
|
|
66
|
+
- Empty session commits return a typed tool error.
|
|
67
|
+
|
|
68
|
+
## v0 Scope Guard
|
|
69
|
+
|
|
70
|
+
The following tools are intentionally out of scope for v0 and must not appear in `tools/list`:
|
|
71
|
+
|
|
72
|
+
- `wiki_publish_session`
|
|
73
|
+
- `wiki_rollback`
|
|
74
|
+
- `wiki_search`
|
|
75
|
+
- document ingestion tools
|
|
76
|
+
- web ingestion tools
|
|
77
|
+
- QA or semantic search tools
|
|
78
|
+
|
|
79
|
+
`publisher` and `admin` roles may exist as higher-privilege roles for the implemented read/write tools, but v0 must not expose publish or rollback behavior.
|
|
80
|
+
|
|
81
|
+
v1 historically superseded this guard by adding document ingestion, source read tools, and `wiki_publish_session`. v2 is the current release gate and adds web ingestion; see [v2-acceptance.md](./v2-acceptance.md) for the active public behavior list.
|
|
82
|
+
|
|
83
|
+
## Manual Spot Check
|
|
84
|
+
|
|
85
|
+
Use this only when changing CLI startup, MCP transport, or packaging:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
workspace="$(mktemp -d)"
|
|
89
|
+
bun packages/server/src/cli.ts init --workspace "$workspace"
|
|
90
|
+
bun packages/server/src/cli.ts status --workspace "$workspace"
|
|
91
|
+
bun packages/server/src/cli.ts mcp --workspace "$workspace" --role reader
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
For MCP manual checks, send `initialize`, `notifications/initialized`, and `tools/list` messages over stdio JSON-RPC. Prefer the automated black-box package for repeatable verification.
|
|
95
|
+
|
|
96
|
+
## Failure Policy
|
|
97
|
+
|
|
98
|
+
If any command in the required gate fails:
|
|
99
|
+
|
|
100
|
+
1. Do not merge or hand off the change.
|
|
101
|
+
2. Identify whether the failure is in unit/integration tests, type checking, or black-box behavior.
|
|
102
|
+
3. Fix the smallest root cause.
|
|
103
|
+
4. Re-run the full required command set from this document.
|
|
104
|
+
|
|
105
|
+
Black-box failures should be treated as public contract failures unless investigation proves the test is asserting behavior outside v0 scope.
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Agent Wiki v0 Delivery Checklist
|
|
2
|
+
|
|
3
|
+
Date: 2026-06-12
|
|
4
|
+
|
|
5
|
+
## v0 Scope
|
|
6
|
+
|
|
7
|
+
This checklist summarizes the historical v0 handoff and delivery state for the MCP-first v0 slice.
|
|
8
|
+
|
|
9
|
+
v0 is historical scope. v1 superseded and extended it with document ingestion, source reads, and fast-forward publish. v2 is the current release gate and adds web ingestion; use [v2-acceptance.md](./v2-acceptance.md) for current acceptance.
|
|
10
|
+
|
|
11
|
+
Implemented:
|
|
12
|
+
|
|
13
|
+
- Local wiki workspace initialization and status inspection.
|
|
14
|
+
- MCP stdio server startup for reader and writer roles.
|
|
15
|
+
- Stable wiki reads through `wiki_read`, `wiki_channel_status`, and read-only `vfs_exec`.
|
|
16
|
+
- Isolated writer sessions with start, full-content patch, validate, diff, and commit.
|
|
17
|
+
- Reader/writer permission enforcement.
|
|
18
|
+
- Markdown validation for frontmatter, H1, path safety, and links.
|
|
19
|
+
- Public black-box coverage through CLI and MCP stdio JSON-RPC.
|
|
20
|
+
- Packed tarball smoke coverage for the installed `tgo-wiki` bin.
|
|
21
|
+
|
|
22
|
+
Deferred:
|
|
23
|
+
|
|
24
|
+
- `publish/rollback` behavior and tools.
|
|
25
|
+
- Search, QA, document ingestion, and web ingestion.
|
|
26
|
+
- Remote git, pull request integration, and web UI.
|
|
27
|
+
|
|
28
|
+
## Required Verification
|
|
29
|
+
|
|
30
|
+
For the current release gate, run:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
bun install --frozen-lockfile
|
|
34
|
+
bun run release:check
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
For v0 delivery, `bun run release:check` ran:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
bun run verify:v0 && bun run smoke:pack && bun pm pack --dry-run
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
The release gate must report:
|
|
44
|
+
|
|
45
|
+
- default unit/integration tests passing;
|
|
46
|
+
- independent black-box tests passing;
|
|
47
|
+
- packed tarball smoke passing through the installed `.bin/tgo-wiki`;
|
|
48
|
+
- pack dry-run listing the expected narrow file set.
|
|
49
|
+
|
|
50
|
+
## Handoff Notes
|
|
51
|
+
|
|
52
|
+
- Use `docs/mcp-usage.md` for MCP client setup and tool examples.
|
|
53
|
+
- Use `docs/v2-acceptance.md` as the current release acceptance policy.
|
|
54
|
+
- Use `docs/v1-acceptance.md` as the historical v1 acceptance policy.
|
|
55
|
+
- Use `docs/v0-acceptance.md` as the historical v0 acceptance policy.
|
|
56
|
+
- Use `CHANGELOG.md` as the release-note draft source.
|
|
57
|
+
- Keep v0 publish/rollback deferral notes historical; v1 adds ff-only session publish while rollback remains deferred.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Agent Wiki v1 Acceptance Gate
|
|
2
|
+
|
|
3
|
+
Date: 2026-06-13
|
|
4
|
+
|
|
5
|
+
## Purpose
|
|
6
|
+
|
|
7
|
+
This document defines the historical v1 release acceptance gate for Agent Wiki. For the current v2 release gate, use [v2-acceptance.md](./v2-acceptance.md). v1 adds document ingestion on top of the v0 local git, worktree, session, validation, commit, and MCP surface.
|
|
8
|
+
|
|
9
|
+
The gate verifies that agents can upload raw document blobs into workspace state, parse those documents into git-tracked source files inside an isolated session worktree, cite those sources from wiki page frontmatter, commit the combined wiki/source changes, and fast-forward publish the clean committed session to stable with the appropriate role.
|
|
10
|
+
|
|
11
|
+
The v1.1 slice supports direct ingestion for `application/pdf`, `text/markdown`, `text/x-markdown`, and `text/plain`.
|
|
12
|
+
|
|
13
|
+
## Required Commands
|
|
14
|
+
|
|
15
|
+
Run from the repository root:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
bun install --frozen-lockfile
|
|
19
|
+
bun run release:check
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Acceptance requires every command to exit with code 0.
|
|
23
|
+
|
|
24
|
+
## Required Public Behaviors
|
|
25
|
+
|
|
26
|
+
- `wiki_publish_session` fast-forwards stable for committed clean sessions.
|
|
27
|
+
- `document_upload` stores raw blobs under workspace state, not git.
|
|
28
|
+
- `document_upload` accepts PDF, Markdown, and plain text documents.
|
|
29
|
+
- `document_parse` writes `sources/<document_id>/raw.md` and `metadata.json` into the session worktree.
|
|
30
|
+
- `document_parse` preserves Markdown uploads as raw Markdown and wraps plain text uploads in readable Markdown.
|
|
31
|
+
- Workspace config can enable command-backed parsers with explicit supported MIME types.
|
|
32
|
+
- Command parser stdout is written as source raw Markdown; command failures return `parse_failed`.
|
|
33
|
+
- `source_list` and `source_read` read stable and session refs.
|
|
34
|
+
- `wiki_session_patch` rejects `sources/**` with `source_write_denied`.
|
|
35
|
+
- `wiki_session_validate` accepts wiki pages with valid `sources` frontmatter and rejects missing source IDs.
|
|
36
|
+
- `wiki_session_commit` commits both wiki pages and source files.
|
|
37
|
+
- Reader can read sources but cannot upload or parse documents.
|
|
38
|
+
- Writer can upload and parse but cannot publish.
|
|
39
|
+
- Publisher and admin can publish.
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
# Agent Wiki v2 Acceptance Gate
|
|
2
|
+
|
|
3
|
+
Date: 2026-06-13
|
|
4
|
+
|
|
5
|
+
## Purpose
|
|
6
|
+
|
|
7
|
+
This document defines the current release acceptance gate for Agent Wiki v2. v2 adds static web ingestion on top of the v1 local git, worktree, session, validation, source, commit, and publish surface.
|
|
8
|
+
|
|
9
|
+
The gate verifies that agents can fetch one HTML page into an isolated session, read the generated source, cite the returned source id from wiki page frontmatter, validate and commit the combined wiki/source changes, fast-forward publish the clean committed session to stable, and read the published source from stable.
|
|
10
|
+
|
|
11
|
+
## Required Commands
|
|
12
|
+
|
|
13
|
+
Run from the repository root:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
bun install --frozen-lockfile
|
|
17
|
+
bun run release:check
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Acceptance requires every command to exit with code 0.
|
|
21
|
+
|
|
22
|
+
## Required Public Behaviors
|
|
23
|
+
|
|
24
|
+
- `web_fetch` is available to publisher and admin roles only.
|
|
25
|
+
- `web_fetch` fetches exactly one absolute public `http:` or `https:` URL with the static fetcher.
|
|
26
|
+
- `web_fetch` rejects private, loopback, link-local, multicast, and reserved network targets by default, including redirects to those targets. Workspace config may explicitly allow private hosts with `web.allowedPrivateHosts`.
|
|
27
|
+
- `web_fetch` stores the original HTML blob outside git under `state/web/blobs/sha256/<sha256>`.
|
|
28
|
+
- `web_fetch` writes `sources/<source_id>/raw.md` and `sources/<source_id>/metadata.json` into the session worktree.
|
|
29
|
+
- `web_fetch` returns `source_id`, `version`, `raw_markdown_path`, `metadata_path`, `html_blob_sha256`, `status`, optional `title`, and `warnings`.
|
|
30
|
+
- Existing source APIs expose the generated raw Markdown and metadata. `source_read` still accepts `document_id`; pass the returned web `source_id` as that value.
|
|
31
|
+
- `source_list` and `source_read` read web sources from stable and session refs.
|
|
32
|
+
- `wiki_session_patch` can cite the returned source id in page `sources` frontmatter.
|
|
33
|
+
- `wiki_session_validate` accepts valid web source citations and rejects missing source IDs.
|
|
34
|
+
- `wiki_session_commit` commits wiki pages and generated source files together.
|
|
35
|
+
- `wiki_publish_session` fast-forwards stable for committed clean sessions.
|
|
36
|
+
- Reader and writer roles can read permitted sources but cannot call `web_fetch`.
|
|
37
|
+
|
|
38
|
+
## Required Flow
|
|
39
|
+
|
|
40
|
+
Start the MCP server with `--role publisher` or `--role admin`, then initialize MCP.
|
|
41
|
+
|
|
42
|
+
```text
|
|
43
|
+
wiki_session_start
|
|
44
|
+
web_fetch
|
|
45
|
+
source_read with ref = session_id
|
|
46
|
+
wiki_session_patch with frontmatter.sources citing returned source_id
|
|
47
|
+
wiki_session_validate
|
|
48
|
+
wiki_session_diff
|
|
49
|
+
wiki_session_commit
|
|
50
|
+
wiki_publish_session as publisher/admin
|
|
51
|
+
source_read from stable
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
For separated duties, a writer can start the session, patch, validate, diff, and commit. A publisher or admin performs `web_fetch` and the final publish step.
|
|
55
|
+
|
|
56
|
+
## `web_fetch` Example
|
|
57
|
+
|
|
58
|
+
Input:
|
|
59
|
+
|
|
60
|
+
```json
|
|
61
|
+
{
|
|
62
|
+
"session_id": "SESSION_ID",
|
|
63
|
+
"url": "https://example.com/docs"
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Result:
|
|
68
|
+
|
|
69
|
+
```json
|
|
70
|
+
{
|
|
71
|
+
"source_id": "web_20260613_ab12cd34ef567890",
|
|
72
|
+
"version": 1,
|
|
73
|
+
"raw_markdown_path": "sources/web_20260613_ab12cd34ef567890/raw.md",
|
|
74
|
+
"metadata_path": "sources/web_20260613_ab12cd34ef567890/metadata.json",
|
|
75
|
+
"html_blob_sha256": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
|
|
76
|
+
"status": "fetched",
|
|
77
|
+
"title": "Example Docs",
|
|
78
|
+
"warnings": []
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
The original HTML bytes for this result are stored outside git at:
|
|
83
|
+
|
|
84
|
+
```text
|
|
85
|
+
state/web/blobs/sha256/0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
The session worktree receives:
|
|
89
|
+
|
|
90
|
+
```text
|
|
91
|
+
sources/web_20260613_ab12cd34ef567890/raw.md
|
|
92
|
+
sources/web_20260613_ab12cd34ef567890/metadata.json
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Source Read Example
|
|
96
|
+
|
|
97
|
+
Use the returned `source_id` as `document_id` when reading through the existing source API:
|
|
98
|
+
|
|
99
|
+
```json
|
|
100
|
+
{
|
|
101
|
+
"document_id": "web_20260613_ab12cd34ef567890",
|
|
102
|
+
"ref": "SESSION_ID"
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Result shape:
|
|
107
|
+
|
|
108
|
+
```json
|
|
109
|
+
{
|
|
110
|
+
"document_id": "web_20260613_ab12cd34ef567890",
|
|
111
|
+
"ref": "SESSION_ID",
|
|
112
|
+
"metadata": {
|
|
113
|
+
"documentId": "web_20260613_ab12cd34ef567890",
|
|
114
|
+
"version": 1,
|
|
115
|
+
"sourceType": "web",
|
|
116
|
+
"url": "https://example.com/docs",
|
|
117
|
+
"finalUrl": "https://example.com/docs",
|
|
118
|
+
"title": "Example Docs",
|
|
119
|
+
"contentType": "text/html; charset=utf-8",
|
|
120
|
+
"statusCode": 200,
|
|
121
|
+
"htmlBlobSha256": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
|
|
122
|
+
"rawMarkdownPath": "sources/web_20260613_ab12cd34ef567890/raw.md",
|
|
123
|
+
"fetcher": {
|
|
124
|
+
"name": "static-fetch",
|
|
125
|
+
"version": "1.0.0"
|
|
126
|
+
},
|
|
127
|
+
"fetchMetadata": {
|
|
128
|
+
"htmlBytes": 1234,
|
|
129
|
+
"markdownBytes": 567
|
|
130
|
+
},
|
|
131
|
+
"status": "fetched"
|
|
132
|
+
},
|
|
133
|
+
"raw_markdown": "# Example Docs\n\n> Source web page: https://example.com/docs\n> Final URL: https://example.com/docs\n> Fetched at: 2026-06-13T00:00:00.000Z\n> Fetcher: static-fetch\n\n..."
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
## Wiki Citation Example
|
|
138
|
+
|
|
139
|
+
Patch a normal wiki page with frontmatter that cites the fetched source:
|
|
140
|
+
|
|
141
|
+
```markdown
|
|
142
|
+
---
|
|
143
|
+
title: "Example Docs"
|
|
144
|
+
summary: "Notes derived from the fetched web source."
|
|
145
|
+
tags: ["web", "imported"]
|
|
146
|
+
updated: "2026-06-13"
|
|
147
|
+
sources:
|
|
148
|
+
- web_20260613_ab12cd34ef567890
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
# Example Docs
|
|
152
|
+
|
|
153
|
+
The published page content should cite the fetched source id in frontmatter.
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## Stable Read Requirement
|
|
157
|
+
|
|
158
|
+
After `wiki_session_commit` and `wiki_publish_session`, `source_read` with `ref: "stable"` must return the same source metadata and raw Markdown for the web source:
|
|
159
|
+
|
|
160
|
+
```json
|
|
161
|
+
{
|
|
162
|
+
"document_id": "web_20260613_ab12cd34ef567890",
|
|
163
|
+
"ref": "stable"
|
|
164
|
+
}
|
|
165
|
+
```
|
package/package.json
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "tgo-wiki",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Local git-backed Agent Wiki MCP server and CLI.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"homepage": "https://github.com/tgoai/tgo-wiki#readme",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/tgoai/tgo-wiki.git"
|
|
10
|
+
},
|
|
11
|
+
"bugs": {
|
|
12
|
+
"url": "https://github.com/tgoai/tgo-wiki/issues"
|
|
13
|
+
},
|
|
14
|
+
"keywords": [
|
|
15
|
+
"agent",
|
|
16
|
+
"bun",
|
|
17
|
+
"cli",
|
|
18
|
+
"knowledge-base",
|
|
19
|
+
"mcp",
|
|
20
|
+
"wiki"
|
|
21
|
+
],
|
|
22
|
+
"engines": {
|
|
23
|
+
"bun": ">=1.3.0"
|
|
24
|
+
},
|
|
25
|
+
"workspaces": [
|
|
26
|
+
"packages/*"
|
|
27
|
+
],
|
|
28
|
+
"bin": {
|
|
29
|
+
"tgo-wiki": "./packages/server/src/cli.ts"
|
|
30
|
+
},
|
|
31
|
+
"files": [
|
|
32
|
+
"packages/core/src/**/*.ts",
|
|
33
|
+
"packages/server/src/**/*.ts",
|
|
34
|
+
"!packages/**/*.test.ts",
|
|
35
|
+
"README.md",
|
|
36
|
+
"CHANGELOG.md",
|
|
37
|
+
"docs/mcp-usage.md",
|
|
38
|
+
"docs/v2-acceptance.md",
|
|
39
|
+
"docs/v1-acceptance.md",
|
|
40
|
+
"docs/v0-acceptance.md",
|
|
41
|
+
"docs/v0-delivery-checklist.md"
|
|
42
|
+
],
|
|
43
|
+
"scripts": {
|
|
44
|
+
"test": "bun test packages/core/src packages/server/src",
|
|
45
|
+
"test:blackbox": "bun test packages/blackbox-tests/src",
|
|
46
|
+
"typecheck": "tsc --noEmit",
|
|
47
|
+
"check": "bun run test && tsc --noEmit",
|
|
48
|
+
"verify:v0": "bun run check && bun run test:blackbox",
|
|
49
|
+
"verify:v1": "bun run check && bun run test:blackbox",
|
|
50
|
+
"verify:v2": "bun run check && bun run test:blackbox",
|
|
51
|
+
"example:mcp": "bun examples/mcp-stdio-client.ts",
|
|
52
|
+
"smoke:cli": "bun scripts/smoke-cli.ts",
|
|
53
|
+
"smoke:pack": "bun scripts/smoke-cli.ts --source pack",
|
|
54
|
+
"release:check": "bun run verify:v2 && bun run smoke:pack && bun pm pack --dry-run",
|
|
55
|
+
"prepublishOnly": "bun run release:check"
|
|
56
|
+
},
|
|
57
|
+
"dependencies": {
|
|
58
|
+
"@cfworker/json-schema": "^4.1.1",
|
|
59
|
+
"@modelcontextprotocol/server": "^2.0.0-alpha.2",
|
|
60
|
+
"gray-matter": "^4.0.3",
|
|
61
|
+
"pdf-parse": "^2.4.5",
|
|
62
|
+
"zod": "^4.4.3"
|
|
63
|
+
},
|
|
64
|
+
"devDependencies": {
|
|
65
|
+
"@types/node": "^25.9.3",
|
|
66
|
+
"bun-types": "^1.3.14",
|
|
67
|
+
"typescript": "^6.0.3"
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { defaultConfig, type DocumentParserConfig, type WikiConfig } from "./defaults.js";
|
|
4
|
+
import type { WorkspacePaths } from "./workspace-resolver.js";
|
|
5
|
+
import { WikiError } from "../errors.js";
|
|
6
|
+
|
|
7
|
+
type ParsedWikiConfig = Partial<Omit<WikiConfig, "documents">> & {
|
|
8
|
+
documents?: Partial<Omit<WikiConfig["documents"], "parsers">> & {
|
|
9
|
+
parsers?: Record<string, DocumentParserConfig>;
|
|
10
|
+
};
|
|
11
|
+
web?: Partial<WikiConfig["web"]>;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export async function loadConfig(paths: WorkspacePaths): Promise<WikiConfig> {
|
|
15
|
+
const configPath = path.join(paths.statePath, "config.json");
|
|
16
|
+
|
|
17
|
+
try {
|
|
18
|
+
const raw = await readFile(configPath, "utf8");
|
|
19
|
+
const parsed = JSON.parse(raw) as ParsedWikiConfig;
|
|
20
|
+
assertOptionalConfigObject("web", parsed.web);
|
|
21
|
+
|
|
22
|
+
const merged = {
|
|
23
|
+
...defaultConfig,
|
|
24
|
+
...parsed,
|
|
25
|
+
channels: {
|
|
26
|
+
...defaultConfig.channels,
|
|
27
|
+
...parsed.channels,
|
|
28
|
+
stable: {
|
|
29
|
+
...defaultConfig.channels.stable,
|
|
30
|
+
...parsed.channels?.stable
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
vfs: {
|
|
34
|
+
...defaultConfig.vfs,
|
|
35
|
+
...parsed.vfs
|
|
36
|
+
},
|
|
37
|
+
validation: {
|
|
38
|
+
...defaultConfig.validation,
|
|
39
|
+
...parsed.validation
|
|
40
|
+
},
|
|
41
|
+
documents: {
|
|
42
|
+
...defaultConfig.documents,
|
|
43
|
+
...parsed.documents,
|
|
44
|
+
parsers: mergeParserConfigs(defaultConfig.documents.parsers, parsed.documents?.parsers)
|
|
45
|
+
},
|
|
46
|
+
web: {
|
|
47
|
+
...defaultConfig.web,
|
|
48
|
+
...parsed.web
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
validateConfig(merged);
|
|
53
|
+
return merged;
|
|
54
|
+
} catch (error) {
|
|
55
|
+
if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") {
|
|
56
|
+
return defaultConfig;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
throw error;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function mergeParserConfigs(
|
|
64
|
+
defaultParsers: Record<string, DocumentParserConfig>,
|
|
65
|
+
configuredParsers: Record<string, DocumentParserConfig> = {}
|
|
66
|
+
): Record<string, DocumentParserConfig> {
|
|
67
|
+
const merged = { ...defaultParsers };
|
|
68
|
+
|
|
69
|
+
for (const [parserName, configuredParser] of Object.entries(configuredParsers)) {
|
|
70
|
+
merged[parserName] = {
|
|
71
|
+
...defaultParsers[parserName],
|
|
72
|
+
...configuredParser
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return merged;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function validateConfig(config: WikiConfig): void {
|
|
80
|
+
assertPositiveInteger("web.requestTimeoutMs", config.web.requestTimeoutMs, 120000);
|
|
81
|
+
assertPositiveInteger("web.maxResponseBytes", config.web.maxResponseBytes, 52428800);
|
|
82
|
+
|
|
83
|
+
if (
|
|
84
|
+
!Array.isArray(config.web.allowedPrivateHosts) ||
|
|
85
|
+
config.web.allowedPrivateHosts.some(host => typeof host !== "string" || host.trim().length === 0)
|
|
86
|
+
) {
|
|
87
|
+
throw new WikiError("validation_failed", "web.allowedPrivateHosts must be an array of non-empty host strings");
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function assertOptionalConfigObject(fieldName: string, value: unknown): void {
|
|
92
|
+
if (value === undefined) {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
97
|
+
throw new WikiError("validation_failed", `${fieldName} must be an object`);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function assertPositiveInteger(fieldName: string, value: unknown, max: number): void {
|
|
102
|
+
if (!Number.isSafeInteger(value) || typeof value !== "number" || value <= 0) {
|
|
103
|
+
throw new WikiError("validation_failed", `${fieldName} must be a positive integer`);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (value > max) {
|
|
107
|
+
throw new WikiError("validation_failed", `${fieldName} must be <= ${max}`);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
export type WikiConfig = {
|
|
2
|
+
version: 1;
|
|
3
|
+
wikiRoot: string;
|
|
4
|
+
stableBranch: string;
|
|
5
|
+
repoManagementBranch: string;
|
|
6
|
+
sessionBranchPrefix: string;
|
|
7
|
+
channels: {
|
|
8
|
+
stable: {
|
|
9
|
+
branch: string;
|
|
10
|
+
worktree: string;
|
|
11
|
+
};
|
|
12
|
+
};
|
|
13
|
+
vfs: {
|
|
14
|
+
allowedCommands: string[];
|
|
15
|
+
};
|
|
16
|
+
validation: {
|
|
17
|
+
requireH1: boolean;
|
|
18
|
+
requireExistingInternalLinks: boolean;
|
|
19
|
+
};
|
|
20
|
+
documents: {
|
|
21
|
+
defaultParser: string;
|
|
22
|
+
parsers: Record<string, DocumentParserConfig>;
|
|
23
|
+
};
|
|
24
|
+
web: {
|
|
25
|
+
requestTimeoutMs: number;
|
|
26
|
+
maxResponseBytes: number;
|
|
27
|
+
allowedPrivateHosts: string[];
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export type DocumentParserConfig = {
|
|
32
|
+
enabled: boolean;
|
|
33
|
+
command?: string;
|
|
34
|
+
supportedMimeTypes?: string[];
|
|
35
|
+
version?: string;
|
|
36
|
+
timeoutMs?: number;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export const defaultConfig: WikiConfig = {
|
|
40
|
+
version: 1,
|
|
41
|
+
wikiRoot: "wiki",
|
|
42
|
+
stableBranch: "wiki/stable",
|
|
43
|
+
repoManagementBranch: "wiki/repo",
|
|
44
|
+
sessionBranchPrefix: "wiki/session/",
|
|
45
|
+
channels: {
|
|
46
|
+
stable: {
|
|
47
|
+
branch: "wiki/stable",
|
|
48
|
+
worktree: "worktrees/stable"
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
vfs: {
|
|
52
|
+
allowedCommands: ["pwd", "ls", "find", "cat", "grep", "head", "tail", "wc", "tree"]
|
|
53
|
+
},
|
|
54
|
+
validation: {
|
|
55
|
+
requireH1: true,
|
|
56
|
+
requireExistingInternalLinks: true
|
|
57
|
+
},
|
|
58
|
+
documents: {
|
|
59
|
+
defaultParser: "pdf-text",
|
|
60
|
+
parsers: {
|
|
61
|
+
"pdf-text": {
|
|
62
|
+
enabled: true
|
|
63
|
+
},
|
|
64
|
+
"text-markdown": {
|
|
65
|
+
enabled: true
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
web: {
|
|
70
|
+
requestTimeoutMs: 15000,
|
|
71
|
+
maxResponseBytes: 5242880,
|
|
72
|
+
allowedPrivateHosts: []
|
|
73
|
+
}
|
|
74
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
|
|
3
|
+
export type WorkspacePaths = {
|
|
4
|
+
workspaceRoot: string;
|
|
5
|
+
repoPath: string;
|
|
6
|
+
statePath: string;
|
|
7
|
+
sessionsStatePath: string;
|
|
8
|
+
documentsStatePath: string;
|
|
9
|
+
documentBlobsPath: string;
|
|
10
|
+
webStatePath: string;
|
|
11
|
+
webBlobsPath: string;
|
|
12
|
+
pendingDocumentsPath: string;
|
|
13
|
+
worktreesPath: string;
|
|
14
|
+
stableWorktreePath: string;
|
|
15
|
+
sessionsWorktreePath: string;
|
|
16
|
+
wikiRootName: "wiki";
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export function resolveWorkspacePaths(workspaceRoot: string): WorkspacePaths {
|
|
20
|
+
const root = path.resolve(workspaceRoot);
|
|
21
|
+
const statePath = path.join(root, "state");
|
|
22
|
+
const documentsStatePath = path.join(statePath, "documents");
|
|
23
|
+
const worktreesPath = path.join(root, "worktrees");
|
|
24
|
+
|
|
25
|
+
return {
|
|
26
|
+
workspaceRoot: root,
|
|
27
|
+
repoPath: path.join(root, "repo"),
|
|
28
|
+
statePath,
|
|
29
|
+
sessionsStatePath: path.join(statePath, "sessions"),
|
|
30
|
+
documentsStatePath,
|
|
31
|
+
documentBlobsPath: path.join(documentsStatePath, "blobs", "sha256"),
|
|
32
|
+
webStatePath: path.join(statePath, "web"),
|
|
33
|
+
webBlobsPath: path.join(statePath, "web", "blobs", "sha256"),
|
|
34
|
+
pendingDocumentsPath: path.join(documentsStatePath, "pending"),
|
|
35
|
+
worktreesPath,
|
|
36
|
+
stableWorktreePath: path.join(worktreesPath, "stable"),
|
|
37
|
+
sessionsWorktreePath: path.join(worktreesPath, "sessions"),
|
|
38
|
+
wikiRootName: "wiki"
|
|
39
|
+
};
|
|
40
|
+
}
|