rootr-cli 0.24.0 → 0.26.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.ko.md CHANGED
@@ -307,20 +307,30 @@ rootr sign ledger # 워크스페이스 원장 전체 재계산
307
307
 
308
308
  ### 문서 보내기 · 문서함 (send · mail)
309
309
 
310
- 폴더만 빼고 어떤 노드든 이메일 1~20명에게 **보낼 때의 복사본**으로 보낼 수 있습니다. 담기는 내용은
311
- 공개 페이지와 같아서 사람·첨부·관계 칸은 나가지 않습니다. 받는 사람은 메일 링크로 **루터 계정 없이**
312
- 열고, 그 이메일에 루터 계정이 있거나 나중에 가입하면 받은 문서함에도 그대로 있습니다. 보낸 뒤 원본을
313
- 고치거나 지워도 받은 문서는 그대로입니다. 보내려면 그 노드에 쓰기(WRITE) 권한이 있어야 합니다(공유와 같은 문턱).
310
+ 어떤 노드든(폴더 포함) 이메일 1~20명에게 보낼 수 있습니다. **복사본이 아니라 원본 그 문서**를 그 이메일에
311
+ 열어 주는 것입니다 — `--access read`(보기, 기본) · `comment`(댓글) · `write`(편집). 받는 사람은 언제나 최신
312
+ 내용을 보고, 편집을 받았으면 원본을 직접 고칩니다. 그 이메일(인증된)의 루터 계정은 우리 워크스페이스 구성원이
313
+ 아니어도 문서함에서 그 문서만 엽니다(트리·구성원·검색은 안 보임). 계정이 없으면 메일 링크에서 받은 이메일을
314
+ 넣어야 읽기 전용으로 보입니다. 보내려면 그 노드에 구성원으로서 쓰기(WRITE) 권한이 있어야 하고(공유와 같은
315
+ 문턱), 내 권한까지만 줄 수 있습니다.
314
316
 
315
317
  ```bash
316
- rootr send "/보고서/3분기 실적" --to partner@example.com,cfo@example.com --message "말씀드린 자료입니다"
318
+ rootr send "/보고서/3분기 실적" --to partner@example.com,cfo@example.com --access comment --message "말씀드린 자료입니다"
317
319
  rootr mail # 받은 문서 (안 읽은 수 함께)
318
- rootr mail sent # 보낸 문서 — 읽었는지, 메일 실패
319
- rootr mail show <id> # 열기 (문서는 마크다운 본문, 그 밖은 --json 으로 전부)
320
- rootr mail revoke <id> # 회수 — 받는 쪽에서 본문이 안 보이고 링크는 410
320
+ rootr mail sent # 보낸 문서 — 권한·읽었는지·메일 실패
321
+ rootr mail show <id> # 지금 내용 (문서는 마크다운 본문, 그 밖은 --json 으로 전부, 폴더 안은 --node <아래 id>)
322
+ rootr mail access <id> write # 받는 사람 권한 바꾸기
323
+ rootr mail revoke <id> # 회수 — 받는 사람이 바로 못 열고 링크는 410
321
324
  rootr mail hide <id> # 내 문서함에서만 지우기
325
+ rootr mail webhook add https://example.com/hooks/rootr # 내 계정 웹훅: doc_mail.received / revoked / read
326
+ rootr mail webhook list | rm <id> | test <id>
322
327
  ```
323
328
 
329
+ 다른 명령을 쓰고 나면 새로 받은 문서가 있을 때 stderr 로 한 줄이 나옵니다(`📬 받은 문서 2건 — … · rootr mail`).
330
+ stdout 과 `--json` 출력은 그대로입니다. 끄려면 `ROOTR_MAIL_NOTICE=0`. MCP 서버는 같은 소식을 아무 도구 응답 끝에
331
+ 키마다 한 번 붙입니다. 웹훅 요청은 서명되어 있습니다 — `add` 때 한 번 보이는 비밀값으로
332
+ `X-Rootr-Signature: sha256=HMAC_SHA256(secret, 원문)` 을 확인하세요. 몸통에는 문서 내용이 없습니다(`apiUrl` 을 부르세요).
333
+
324
334
  ### 제보 보내기 (feedback)
325
335
 
326
336
  ```bash
@@ -368,7 +378,7 @@ rootr memory forget <id> # 폐기(--hard면 행 삭제)
368
378
 
369
379
  ## MCP 서버로 사용하기
370
380
 
371
- `rootr mcp`는 stdio로 MCP(Model Context Protocol) 서버를 구동합니다. 제공 도구 197종:
381
+ `rootr mcp`는 stdio로 MCP(Model Context Protocol) 서버를 구동합니다. 제공 도구 202종:
372
382
 
373
383
  노드를 가리키는 인자(`target`, `databaseId`, `spreadsheetId`, `formId`, `crmId`, `trackerId`,
374
384
  `recordingId`, `presentationId`, `whiteboardId`, `logId`, `parentId` 등)는 **노드 id와 경로를 모두**
@@ -520,6 +530,10 @@ rootr db buttons <표> --file buttons.json # 목록 통째로 저장(남길 것
520
530
  rootr db button-run <표> <버튼id> # 한 번 누르기 (--rows id,id 로 고른 행 지정)
521
531
  rootr db automations <표> --file rules.json # 자동 규칙 — 사람이 안 눌러도 도는 것
522
532
  rootr db view <표> <뷰> --scale year # 달력 보기를 주·달·해 중에서
533
+ rootr db view <표> <뷰> --density compact --freeze 1 # 촘촘한 줄 · 왼쪽 첫 칸 고정
534
+ rootr db column <표> 지원일 --time off --range off # 시간·기간 없이 날짜 하나만
535
+ rootr db column <표> 마감일 --overdue on # 지난 날짜를 빨갛게(기본은 꺼짐)
536
+ rootr db column <표> 특이사항 --wrap on --align center # 긴 글 줄바꿈 · 가운데 정렬
523
537
  ```
524
538
 
525
539
  ```json
@@ -651,7 +665,7 @@ rootr db view <표> <뷰> --scale year # 달력 보기를 주·달·해
651
665
 
652
666
  | 도구 | 설명 |
653
667
  |---|---|
654
- | `rootr_publish_node` | **아무 노드나** 공개 — 문서·표·폼·시트·화이트보드·덱, 하위까지 |
668
+ | `rootr_publish_node` | **아무 노드나** 공개 — 문서·표·폼·시트·화이트보드·덱·페이지, 하위까지. **페이지(PAGE)는 Team 플랜부터**(무료는 403 `PLAN_UPGRADE_REQUIRED`, 하위 포함 시 페이지는 건너뛰고 개수를 알려 줌) |
655
669
  | `rootr_set_node_public` | 이미 공개한 것의 설정 변경(하위 포함 여부·검색 노출·만료) |
656
670
  | `rootr_node_public_status` | 지금 공개돼 있는지, 주소는 무엇인지 |
657
671
  | `rootr_publish_document` | 문서 전용 발행(구형 — 새로 짤 때는 `rootr_publish_node`) |
@@ -819,10 +833,15 @@ rootr db view <표> <뷰> --scale year # 달력 보기를 주·달·해
819
833
 
820
834
  | 도구 | 설명 |
821
835
  |---|---|
822
- | `rootr_send_document` | 노드 하나를 이메일 1~20명에게 보낼 때의 복사본으로 보내기 (계정 없어도 메일 링크로 열림) |
823
- | `rootr_list_doc_mail` | 내 문서함 — `box`: inbox(받은, 기본) / sent(보낸), 안 읽은 수 함께 |
824
- | `rootr_read_doc_mail` | 한 통 열기 — 본문(`payload`), 받은 것은 읽음 처리, 회수된 것은 본문 없음 |
825
- | `rootr_revoke_doc_mail` | 보낸 문서 회수 (보낸 사람만) |
836
+ | `rootr_send_document` | 노드 하나를 이메일 1~20명에게 보내기 — 복사본이 아니라 원본을 `access`(read 보기·comment 댓글·write 편집)만큼 열어 줌 |
837
+ | `rootr_list_doc_mail` | 내 문서함 — `box`: inbox(받은, 기본) / sent(보낸), 안 읽은 수·권한·원본 상태 함께 |
838
+ | `rootr_read_doc_mail` | 한 통 열기 — 원본의 지금 내용(읽기 전용)·권한·원본 주소, 폴더면 `node` 로 아래 것, 받은 것은 읽음 처리 |
839
+ | `rootr_set_doc_mail_access` | 보낸 문서의 받는 사람 권한 바꾸기 (보낸 사람만, 내 권한까지) |
840
+ | `rootr_revoke_doc_mail` | 보낸 문서 회수 — 받는 사람이 바로 못 연다 (보낸 사람만) |
841
+ | `rootr_add_doc_mail_webhook` | 내 계정 받은 문서 웹훅 만들기 — doc_mail.received·revoked·read, HMAC 서명, 비밀값은 한 번만 |
842
+ | `rootr_list_doc_mail_webhooks` | 내 받은 문서 웹훅 목록(마지막 전달 상태) |
843
+ | `rootr_remove_doc_mail_webhook` | 내 받은 문서 웹훅 지우기 |
844
+ | `rootr_test_doc_mail_webhook` | 시험 전송(doc_mail.test) 후 전달 결과 |
826
845
 
827
846
  문서함은 워크스페이스가 아니라 **사람(이메일)**에 붙습니다. 사람 없는 워크스페이스 키(원격 커넥터)는
828
847
  그 키를 만든 구성원으로 동작합니다.
@@ -844,11 +863,20 @@ rootr db view <표> <뷰> --scale year # 달력 보기를 주·달·해
844
863
  `rootr_append_page_blocks`, `rootr_update_page`, `rootr_update_page_block`,
845
864
  `rootr_read_page_live_data`)로 저작합니다.
846
865
 
847
- HTML을 짜는 것이 아니라 **정해진 블록 15종을 골라 쌓습니다** — `hero` `text`
866
+ HTML을 짜는 것이 아니라 **정해진 블록 16종을 골라 쌓습니다** — `hero` `text`
848
867
  `features` `gallery` `pricing` `testimonials` `faq` `timeline` `cta` `footer` +
849
868
  표에서 값을 끌어오는 `liveStats` `liveTable` `liveChart` + 신청을 받는 `form` +
850
869
  방문자가 시간을 잡는 `booking`(`{bookingNodeId, headline?, type?}` — 예약을 켜고 공개한 표의 노드 id) +
851
- 자유 블록 `custom`.
870
+ 모션그래픽 동영상 `video` + 자유 블록 `custom`.
871
+
872
+ **같은 페이지 안 이동** — 버튼·링크의 `target`에 `{"kind":"block","blockId":"booking"}`을 주면 새 탭 없이
873
+ 그 블록까지 부드럽게 내려갑니다(인스타그램 앱 안 브라우저에서 사람을 잃지 않는 광고 랜딩용). 가리킨 블록이
874
+ 페이지에 없으면 400이라, 만들 때 그 블록에 `id`를 직접 붙여 둡니다. `text` 본문에서는 `[글](#블록id)`.
875
+
876
+ **동영상(Team 플랜)** — `hero.background`에 `{"kind":"video","attachmentId":"…","posterAttachmentId":"…"}`,
877
+ 동영상 블록은 `{attachmentId, posterAttachmentId?, caption?, aspect?: "16:9"|"9:16"|"1:1"|"4:5", bleed?}`.
878
+ 둘 다 소리 없이 자동 재생·반복·컨트롤 없음이고, 동작 줄이기를 켠 방문자에게는 포스터 그림만 보입니다.
879
+ 히어로 동영상에는 `portraitAttachmentId`·`portraitPosterAttachmentId`(휴대폰 세로판)를 더할 수 있습니다 — 세로 화면은 그 판을, 아니면 기본판을 하나만 내려받습니다.
852
880
 
853
881
  **랜딩 페이지**용으로 두 블록은 가운데 본문 기둥을 벗어나 화면 폭 전체를 쓸 수 있습니다.
854
882
  `hero`에 `size: "screen"`을 주면 화면 한 장을 채우는 큰 제목(화면 폭 전체·화면 높이·큰 글자)이 되고,
@@ -899,6 +927,10 @@ DATABASE·SPREADSHEET·LOG 노드이고, 칸은 **이름**으로 가리킵니다
899
927
  페이지에서 조용히 빠집니다(일부러 그렇습니다).
900
928
 
901
929
  공개는 여느 노드와 같습니다: `POST /v1/nodes/:id/publish` → `rootr.io/p/{slug}`.
930
+ 단 **페이지를 웹에 게시하는 것은 Team 플랜부터**입니다 — 무료 워크스페이스는 403 `PLAN_UPGRADE_REQUIRED`
931
+ (아무것도 바뀌지 않음). 무료에서도 페이지를 만들고 편집하고 워크스페이스 안에서 보는 것은 그대로 됩니다.
932
+ Team 에서 공개한 뒤 무료로 내려가면 공개 설정은 남아 있지만 방문자에게는 "게시되어 있지 않습니다" 화면이
933
+ 나가고, 다시 Team 으로 올리면 같은 주소가 다시 발행하지 않아도 열립니다.
902
934
 
903
935
  #### 프레젠테이션
904
936
 
package/README.md CHANGED
@@ -11,7 +11,7 @@ citations back to the exact paragraph.
11
11
  *(한국어 문서: [README.ko.md](https://github.com/gwmage/rootr-cli/blob/main/README.ko.md))*
12
12
 
13
13
  - `rootr` CLI — documents, databases, forms, signed documents, publishing, permissions, memory
14
- - `rootr mcp` — stdio MCP server, **197 tools** (see [MCP tools](#mcp-tools))
14
+ - `rootr mcp` — stdio MCP server, **202 tools** (see [MCP tools](#mcp-tools))
15
15
 
16
16
  Plain Node.js ESM, no build step. Node 18+ (uses the built-in `fetch`).
17
17
 
@@ -201,10 +201,18 @@ rootr db rows-rm /projects/tasks --ids r1,r2 --yes
201
201
  rootr db duplicates /hr/applicants --row r9 # same person (dedupe column) + latest linked history
202
202
  rootr db merge /hr/applicants r9 --into r1 # merge a duplicate into the existing row
203
203
  rootr db keep-duplicate /hr/applicants r9 --from r1 # keep as a new row, link both
204
+ rootr db rename-col /hr/applicants "대처-클레임" "대처-청소 후 사진 제출" --dry # what follows a rename (formulas, {col} templates, rollups, forms, pages); drop --dry to rename
205
+ rootr db carry-over /hr/applicants r9 # re-application: copy the latest earlier row into r9 (earlier row untouched)
206
+ rootr db column-set /hr/applicants Phone --json '{"dedupe":true,"dedupeCarry":{"auto":true,"exclude":["Applied on"],"mark":{"Re-applied":true}}}'
207
+ rootr db column-set /hr/applicants Phone --json '{"validate":{"kind":"mobile_kr","mode":"block"}}' # also date · birthdate · range, mode warn
208
+ rootr db rule-violations /hr/applicants # existing values that break a validate rule (nothing changed)
204
209
  rootr db history /hr/applicants --row r1 # who changed what, when, how
205
210
  rootr db restore /hr/applicants --at 2026-10-15T09:00:00+09:00 --yes # rows + columns/views back to that time
206
211
  rootr db view /projects/tasks Calendar --scale month # views: table, board, calendar, timeline
207
212
  rootr db view /hr/applicants Board --cards "Interview date,Phone" # fields shown on board cards
213
+ rootr db view /hr/applicants Table --density compact --freeze 1 # compact rows, keep the first column fixed
214
+ rootr db column /hr/applicants "Applied on" --overdue off --time off --range off # plain single date, no red
215
+ rootr db column /hr/applicants Notes --wrap on --align center # wrap long text, center it
208
216
  rootr db lock /projects/tasks --schema managers --rows own --locked "Approved,Score"
209
217
  rootr db notify /projects/tasks --file rules.json # notification rules
210
218
  rootr db buttons /projects/tasks --file buttons.json # buttons that do work when pressed
@@ -269,7 +277,15 @@ rootr publish /handbook --status # is it public, at what URL, chi
269
277
  rootr publish /projects/tasks --layout board --skin paper # 9 layouts × 6 skins
270
278
  rootr publish /handbook/policy.md --comments --expires 2026-12-31T00:00:00Z
271
279
  rootr publish /handbook --off
280
+ ```
281
+
282
+ Every node type publishes on the Free plan **except PAGE** (the block-built web page): publishing a
283
+ page to the web needs the **Team plan**. On Free, `rootr publish <page>` fails with
284
+ `PLAN_UPGRADE_REQUIRED` and nothing changes; `--children` skips pages underneath and says how many.
285
+ A page published on Team stays saved if the workspace later drops to Free — visitors see a
286
+ "not published" screen until it is upgraded again, and `--status` says so.
272
287
 
288
+ ```bash
273
289
  rootr access /handbook --private # or --public / --inherit
274
290
  rootr access /handbook --grant <userId> --level WRITE
275
291
  rootr access /handbook --revoke <userId>
@@ -329,21 +345,32 @@ regulations require both the original and the trace of the change to remain visi
329
345
 
330
346
  ### Sending a document to someone (mailbox)
331
347
 
332
- Any node except a folder can be emailed to 1–20 addresses as a **copy taken at send time** — the
333
- same content a public page shows, so person / attachment / relation columns never go out. The
334
- recipient opens it from the email link **without a Rootr account**; if that address has (or later
335
- gets) a Rootr account, it is also in their inbox. Editing or deleting the original afterwards does
336
- not change what they received. Sending needs WRITE on the node, the same bar as sharing.
348
+ Any node — a folder too — can be sent to 1–20 email addresses. It is **not a copy**: the address
349
+ gets access to the **original** at `--access read` (view, default) · `comment` · `write` (edit), so
350
+ they always see the latest version and, with `write`, edit the original itself. A Rootr account on
351
+ that (verified) email opens it from its inbox even if it is not in your workspace — it sees that
352
+ node only, never your tree, members or search. Without an account the email link asks for the
353
+ address and then shows it read-only. Sending needs WRITE on the node as a member (the same bar as
354
+ sharing); you can give at most your own level.
337
355
 
338
356
  ```bash
339
- rootr send "/reports/Q3 numbers" --to partner@example.com,cfo@example.com --message "As discussed"
357
+ rootr send "/reports/Q3 numbers" --to partner@example.com,cfo@example.com --access comment --message "As discussed"
340
358
  rootr mail # received (with the unread count)
341
- rootr mail sent # what you sent — read or not, email failures
342
- rootr mail show <id> # open it (a document prints its markdown; --json for any type)
343
- rootr mail revoke <id> # withdraw: the recipient no longer sees the content, the link answers 410
359
+ rootr mail sent # what you sent — access, read or not, email failures
360
+ rootr mail show <id> # the current content (a document prints its markdown; --json for any type; --node <child> inside a folder)
361
+ rootr mail access <id> write # change what the recipient can do
362
+ rootr mail revoke <id> # withdraw: the recipient loses access at once, the link answers 410
344
363
  rootr mail hide <id> # remove from your own mailbox only
364
+ rootr mail webhook add https://example.com/hooks/rootr # your own webhook: doc_mail.received / revoked / read
365
+ rootr mail webhook list | rm <id> | test <id>
345
366
  ```
346
367
 
368
+ After any other command, newly received documents print one line to stderr
369
+ (`📬 2 new documents received — … · rootr mail`); stdout and `--json` stay clean. Turn it off with
370
+ `ROOTR_MAIL_NOTICE=0`. The MCP server appends the same news to the end of any tool result, once
371
+ per key. Webhook requests are signed: verify `X-Rootr-Signature: sha256=HMAC_SHA256(secret, raw body)`
372
+ with the secret shown once at `add`. The body never contains the document — GET its `apiUrl`.
373
+
347
374
  ### Team memory
348
375
 
349
376
  ```bash
@@ -425,7 +452,7 @@ is refused and says when the grace was used.
425
452
 
426
453
  ## MCP tools
427
454
 
428
- `rootr mcp` speaks MCP over stdio. 197 tools:
455
+ `rootr mcp` speaks MCP over stdio. 202 tools:
429
456
 
430
457
  | Group | Count | Tools |
431
458
  |---|---|---|
@@ -487,11 +514,23 @@ signed-document, issue, CRM and LOG tools need `docs:read` / `docs:write`; `root
487
514
  ### Pages
488
515
 
489
516
  A PAGE is **a screen for people outside the workspace** — an event announcement, a product page,
490
- a sign-up. You do not write HTML: you stack **15 predefined block types** — `hero`, `text`,
517
+ a sign-up. You do not write HTML: you stack **16 predefined block types** — `hero`, `text`,
491
518
  `features`, `gallery`, `pricing`, `testimonials`, `faq`, `timeline`, `cta`, `footer`, the
492
519
  table-backed `liveStats`, `liveTable`, `liveChart`, the `form` block, the `booking` block
493
520
  (a visitor scheduling calendar: `{bookingNodeId, headline?, type?}` — the node id of a published
494
- table with visitor booking on) — plus the free-form `custom`.
521
+ table with visitor booking on), the `video` block (a looping motion-graphic clip) — plus the free-form `custom`.
522
+
523
+ **Same-page links.** A button or link `target` can be `{"kind":"block","blockId":"booking"}` — it
524
+ jumps to that block on the same page (smooth scroll, same tab; ideal for a hero "Book now" button
525
+ on an ad landing page opened in an in-app browser). The block must exist on the page (else 400),
526
+ so give it an explicit `id`. In a `text` block, `[label](#<blockId>)` does the same.
527
+
528
+ **Videos (Team plan).** `hero.background` can be `{"kind":"video","attachmentId":"…","posterAttachmentId":"…"}`
529
+ and the `video` block is `{attachmentId, posterAttachmentId?, caption?, aspect?: "16:9"|"9:16"|"1:1"|"4:5", bleed?}`.
530
+ Both autoplay muted and looped with no controls; the poster shows for reduced-motion visitors. A hero video can add
531
+ `portraitAttachmentId` / `portraitPosterAttachmentId` — a vertical cut that portrait phone screens play instead (only one file is downloaded). Upload the
532
+ mp4 with `POST /v1/attachments/upload?workspaceId=…&nodeId=<page>&mimeType=video/mp4` (body = bytes,
533
+ `Content-Type: application/octet-stream`).
495
534
 
496
535
  For a **landing page**, two options let a block use the whole page width instead of the centred
497
536
  text column: `hero` with `size: "screen"` is a full-screen hero (edge to edge, one viewport tall,
@@ -543,7 +582,8 @@ takes `width: half | third | twoThirds` so a page becomes a **live dashboard**
543
582
  published separately. Tables and forms that live under a PRIVATE subtree are silently dropped
544
583
  from a public page, on purpose.
545
584
 
546
- Publishing works like any other node: `POST /v1/nodes/:id/publish` → `rootr.io/p/{slug}`.
585
+ Publishing works like any other node: `POST /v1/nodes/:id/publish` → `rootr.io/p/{slug}` —
586
+ **Team plan and up** for pages (Free → `403 PLAN_UPGRADE_REQUIRED`; pages still work inside the workspace).
547
587
 
548
588
  ### Embedding a table inside a document
549
589