Repository navigation
Conversation
Every documents and wiki CLI gets the same commands, options and answers from cli-core instead of copying drive-cli's. `@wirecat/cli-core/documents/cli` has one builder per group, over ports the CLI supplies (its store, lock, principal, provider source and item shapes); `addDocumentCommands` mounts them all: - folders add|list|remove (the CLI adds its own `browse`, outside the contract) - sync, status - documents list|show|export, then the CLI's live subcommands on the group - search, catalog import|show|list|search|tree|tags - documents context, tags, relationships, notes, memories, facts, identities - mirrors add|list|remove|status|sync|watch `words` names the CLI and its provider: `--keep local|<remote>|both` maps the CLI's word to the engine's `remote`, identities are `<remote>-id`/`<remote>_id`, and a partial sync's issue names the CLI's store provider rather than a hard-coded google-drive. Entity names are neutral and the same everywhere: document (views imported, catalog), document_tag, document_relationship, document_identity, selected_folder, mirror. `catalog tree` now reads each folder's children by parent, page by page, with no total cap; it used to read the first 10 000 entries of the account. `@wirecat/cli-core/documents/testing`: documentSourceContract for an adapter, documentCommandsContract for a CLI's mounted commands, fakeDocumentSource. The kit's test runs both over a reference CLI on a temporary store. The module lives in src/cli/documents/: Biome forbids src/documents/ (the domain) from importing commands, the store or services. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
catalog tree reads only what it shows: each shown entry's children come
from catalog.list({ parent }), 1 000 a page, and the branches cut at
--depth are checked 200 parents at a time. Any entry with children can be
a root or a branch, so a page with sub-pages works. An entry in two
folders is shown once in full and marked repeated elsewhere. Over 10 000
entries it answers catalog.tree-limit, which says to narrow the folder or
the depth.
document_identity has one schema in every CLI: remote_id, provider, a
fixed role list and person. The mirrors sync description is a word of the
CLI. listing.too-large, which mirrors watch recovers from, and
catalog.tree-limit are core reasons; sync.partial names no provider. Every
builder honours a global --dry-run.
The contract kit checks more: the source contract takes isDocument and a
change in the feed and calls bytes; the commands contract parses answers,
checks ids, each path's effects and that no shared contract is overridden.
The kit's own test runs a broken CLI, a page-tree source and mirrors sync
through to the engine.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
leemour
force-pushed
the
feat/documents-commands
branch
from
November 14, 2026 12:24
2d777bd to
99259fd
Compare
Since #2949 a command's own --yes takes the value the root took, and the root gate guard refuses a read of --yes off the root by a command that declares its own. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Task
Lane L2 of notion-cli (C4): one shared
documentscommand group in cli-core, so every documents or wiki CLI (drive, notion, …) gets the same commands over the existing documents services.Why
drive-cli built folders, sync, status, documents, search, catalog, tags, relationships, notes, memories, facts, identities and mirrors on its own. notion-cli needs the same commands. Copying them would make two CLIs that drift apart. A CLI now passes its ports, its provider name and its word for the remote side, and gets the whole tree.
What
@wirecat/cli-core/documents/cli:addDocumentCommands(program, { words, output, folders, sync, documents, search, catalog, knowledge, mirrors? })mounts the group (src/cli/documents/index.ts:69).addDocumentFolderCommands,addDocumentSyncCommands,addLocalDocumentCommands,addDocumentSearchCommand,addDocumentCatalogCommands,addDocumentKnowledgeCommands,addDocumentMirrorCommands. A CLI can add its own subcommands todocumentsand its own groups.DocumentWords(src/cli/documents/words.ts:8) holds the app, the provider, the place, the remote word for--keep local|<remote>|bothand the<remote>-idof identities, plus optional text overrides.document,selected_folder,mirror,document_tag,note,document_relationship,document_identity(remote_id,provider,roleofownerorlast-editor,person). The family audit'ssame-entity-schemasees one schema.honoursDryRun(sharedCommand(…)), asaddCalendarCommandsandaddCrmCommandsare.catalog treereads only what it shows (src/cli/documents/catalog.ts,catalogTreeandcatalogSource):catalog.list({ parent }), 1 000 a page;--depthare checked 200 parents at a time (oneparent:a OR parent:b …query), not one by one;file) works;repeatedat its other place;catalog.tree-limit: "name a smaller FOLDER or lower --depth".--depth 1in a 12 000-entry account takes 6.6 s. Asking about each cut branch alone took 32 s. The store'sparentfilter scans the account's catalog (no index), so each read costs the whole account. See follow-ups.catalog.unavailable|not-found|depth-invalid|cycle|tree-limit,mirror.none|not-found|not-folder,export.exists,listing.too-large.failureContextaccepts an app's copy with the same code (drive@main still lists them), and refuses one with another code. No CLI in the family lists one under another code.sync.partialnames no provider.mirrors watchrestarts the change feed onlisting.too-largefrom the connection'schanges. That is now documented onDocumentMirrorConnection.changesand in DOCUMENTS.md for notion. Themirrors syncdescription iswords.text.mirrorsSync.@wirecat/cli-core/documents/testing:documentSourceContract:isDocumentfor pages that are folders and documents at once,changeto put a real change in the feed, andbytesis called.documentCommandsContract: parses answers and checks ids, checks each shared path's effects against a table, and checks that the CLI overrides no shared contract.mirrors sync --keep <remote>now reaches the engine withkeep: "remote".Placement. The module lives in
src/cli/documents/, notsrc/documents/cli/. Biome forbidssrc/documents/**(the domain layer) from importing commands, the store or services, and these commands need all three.Not spread into shared code (drive breaks the handbook here, see the drive PR): its own profile lock, its own policy and
--read-only, and its own MCP server.Testing
pnpm lint,typecheck,docs:check: ok. Tests ofsrc/errors,src/cli/documents,src/documents,src/services/documents, the store catalog and the dry-run guard: 835 passed. The full suite runs in CI.catalog.tree-limitthrough the CLI, a cut branch with an odd id, the page-tree source, the change feed, a broken CLI refused by the contract, and--keep boxreaching the engine asremote.commands --jsondiff against drive@main changes only the entity names and the identity fields.contracts:check(help.snap),test:matrix(0 missing),lint,lint:commandsanddocs:checkpass. In the familycli-dev audit, drive's rows and the 24 blocking findings are identical to the baseline before this change.Follow-ups (lane L1)
Rebased on #2938, #2941 and #2944.
catalog.list({ parent })andparent:queries scan every entry withjson_each(src/store/sqlite/catalog.ts). With an index, a tree of 1 000 entries in a big account would take milliseconds, not seconds.catalog.getandcatalog.list({ parent })take a bare id and add.md, but the entries they return carry<id>.md. So every caller strips.mdbefore asking again. The service could accept both forms.identitiesneeds a provider hook for people (people,linkPerson). drive passes its Google owners. The services could offer it.🤖 Generated with Claude Code