rootr-cli 0.25.0 → 0.29.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 +53 -3
- package/README.md +62 -4
- package/bin/rootr.js +667 -13
- package/lib/client.js +131 -7
- package/lib/domain-billing.js +52 -0
- package/lib/mcp-tools/booking.js +11 -1
- package/lib/mcp-tools/databases.js +423 -10
- package/lib/mcp-tools/documents.js +17 -1
- package/lib/mcp-tools/domains.js +236 -0
- package/lib/mcp-tools/forms.js +20 -2
- package/lib/mcp-tools/pages.js +21 -4
- package/lib/mcp-tools/public.js +13 -0
- package/lib/mcp-tools/workspaces.js +71 -1
- package/lib/mcp.js +2 -0
- package/package.json +1 -1
package/README.ko.md
CHANGED
|
@@ -331,6 +331,33 @@ stdout 과 `--json` 출력은 그대로입니다. 끄려면 `ROOTR_MAIL_NOTICE=0
|
|
|
331
331
|
키마다 한 번 붙입니다. 웹훅 요청은 서명되어 있습니다 — `add` 때 한 번 보이는 비밀값으로
|
|
332
332
|
`X-Rootr-Signature: sha256=HMAC_SHA256(secret, 원문)` 을 확인하세요. 몸통에는 문서 내용이 없습니다(`apiUrl` 을 부르세요).
|
|
333
333
|
|
|
334
|
+
### 내 도메인 연결 (domain)
|
|
335
|
+
|
|
336
|
+
발행한 페이지(PAGE)를 내 도메인(`www.회사.co.kr`)에서 보통 홈페이지처럼 엽니다 — 첫 화면은 그 페이지, `/{하위}` 는
|
|
337
|
+
공개된 하위 페이지, 루터 서명은 붙지 않습니다. Team 플랜부터, 워크스페이스 관리자만 됩니다.
|
|
338
|
+
|
|
339
|
+
- **무료 주소** `이름.rootr.site` — 결제·DNS 없이 바로 열립니다(워크스페이스당 3개, 영어 소문자·숫자·하이픈 3~30자, `www`·`api`·`admin` 같은 이름과 `rootr` 가 들어간 이름은 예약).
|
|
340
|
+
- **내 도메인** — 1개당 월 $10, 연 결제 시 월 $8(연 $96). "도메인 연결" 애드온의 자리를 하나 씁니다. 자리가 없으면
|
|
341
|
+
`402`(결제 필요)와 함께 설정 › 결제 주소를 알려 줍니다. 애드온이 있는데 꽉 찼으면 `--confirm-charge` 로 1개를 더 삽니다(일할 계산).
|
|
342
|
+
해제하면 수량이 줄고(일할 환불), 마지막 하나면 이번 주기 끝에 애드온이 끝나도록 예약됩니다.
|
|
343
|
+
|
|
344
|
+
```bash
|
|
345
|
+
rootr domain detect www.회사.co.kr # DNS 를 어디서 관리하는지(가비아·카페24·Cloudflare…) + 단계 안내
|
|
346
|
+
rootr domain add www.회사.co.kr /홈페이지 # 등록 — 넣을 한 줄과 그 업체 화면 기준 단계가 나온다
|
|
347
|
+
rootr domain add --subdomain acme /홈페이지 # 무료 주소 acme.rootr.site — 바로 열린다
|
|
348
|
+
rootr domain available acme # 무료 주소 이름을 쓸 수 있는지
|
|
349
|
+
rootr domain check <id> # 지금 다시 확인(연결 전이면 exit 2)
|
|
350
|
+
rootr domain list # 종류·상태(DNS 확인 중 / 인증서 발급 중 / 연결됨 / 일시 중지) + 자리 사용
|
|
351
|
+
rootr domain rename <id> www.right.co.kr # 연결 전 도메인의 이름 바꾸기(결제 그대로, 새 id)
|
|
352
|
+
rootr domain remove <id> # 연결 해제(업체 DNS 의 CNAME 줄도 지우세요)
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
고객이 넣는 것은 **딱 한 줄**입니다: 타입 `CNAME`, 이름 `www`, 값 `connect.rootr.site`. 그다음 HTTPS 인증서는
|
|
356
|
+
루터가 알아서 발급하고 5분마다 다시 확인합니다 — 연결되면 등록한 사람에게 알림과 메일이 갑니다. 루트 도메인
|
|
357
|
+
(`회사.co.kr`)에는 CNAME 을 못 거는 곳이 많아 `www.` 으로 연결하고 루트는 포워딩합니다(업체별 방법이 안내에 나옵니다).
|
|
358
|
+
같은 주소를 **다른 워크스페이스가 전에 등록했던** 경우에만 소유 확인 줄(`TXT`, 이름 `_rootr-verify.www`)이 하나 더 필요합니다 —
|
|
359
|
+
남겨 둔 CNAME 으로 남의 도메인을 가로채지 못하게.
|
|
360
|
+
|
|
334
361
|
### 제보 보내기 (feedback)
|
|
335
362
|
|
|
336
363
|
```bash
|
|
@@ -378,7 +405,7 @@ rootr memory forget <id> # 폐기(--hard면 행 삭제)
|
|
|
378
405
|
|
|
379
406
|
## MCP 서버로 사용하기
|
|
380
407
|
|
|
381
|
-
`rootr mcp`는 stdio로 MCP(Model Context Protocol) 서버를 구동합니다. 제공 도구
|
|
408
|
+
`rootr mcp`는 stdio로 MCP(Model Context Protocol) 서버를 구동합니다. 제공 도구 214종:
|
|
382
409
|
|
|
383
410
|
노드를 가리키는 인자(`target`, `databaseId`, `spreadsheetId`, `formId`, `crmId`, `trackerId`,
|
|
384
411
|
`recordingId`, `presentationId`, `whiteboardId`, `logId`, `parentId` 등)는 **노드 id와 경로를 모두**
|
|
@@ -530,6 +557,10 @@ rootr db buttons <표> --file buttons.json # 목록 통째로 저장(남길 것
|
|
|
530
557
|
rootr db button-run <표> <버튼id> # 한 번 누르기 (--rows id,id 로 고른 행 지정)
|
|
531
558
|
rootr db automations <표> --file rules.json # 자동 규칙 — 사람이 안 눌러도 도는 것
|
|
532
559
|
rootr db view <표> <뷰> --scale year # 달력 보기를 주·달·해 중에서
|
|
560
|
+
rootr db view <표> <뷰> --density compact --freeze 1 # 촘촘한 줄 · 왼쪽 첫 칸 고정
|
|
561
|
+
rootr db column <표> 지원일 --time off --range off # 시간·기간 없이 날짜 하나만
|
|
562
|
+
rootr db column <표> 마감일 --overdue on # 지난 날짜를 빨갛게(기본은 꺼짐)
|
|
563
|
+
rootr db column <표> 특이사항 --wrap on --align center # 긴 글 줄바꿈 · 가운데 정렬
|
|
533
564
|
```
|
|
534
565
|
|
|
535
566
|
```json
|
|
@@ -839,6 +870,16 @@ rootr db view <표> <뷰> --scale year # 달력 보기를 주·달·해
|
|
|
839
870
|
| `rootr_remove_doc_mail_webhook` | 내 받은 문서 웹훅 지우기 |
|
|
840
871
|
| `rootr_test_doc_mail_webhook` | 시험 전송(doc_mail.test) 후 전달 결과 |
|
|
841
872
|
|
|
873
|
+
#### 내 도메인 연결 (워크스페이스 관리자, Team 플랜)
|
|
874
|
+
|
|
875
|
+
| 도구 | 설명 |
|
|
876
|
+
|---|---|
|
|
877
|
+
| `rootr_list_custom_domains` | 워크스페이스의 도메인 목록 — 종류(내 도메인·무료 주소)·상태·가리키는 페이지·넣을 DNS 줄·사이트 주소 + 자리 요약(`slots`) |
|
|
878
|
+
| `rootr_add_custom_domain` | 발행한 페이지를 내 도메인으로 연결 — 넣을 한 줄 + 이름서버로 짚은 업체(가비아·카페24·Cloudflare…)의 단계 안내(`instructions`). `subdomain` 이면 무료 주소(바로 열림), 자리가 꽉 찼으면 사람 동의 뒤 `confirmCharge: true` |
|
|
879
|
+
| `rootr_check_custom_domain` | 지금 다시 확인 — DNS·인증서 상태와 쉬운 말 사유 |
|
|
880
|
+
| `rootr_rename_custom_domain` | 연결 전 내 도메인의 이름 바꾸기(결제 자리는 새 이름으로 옮겨 감) |
|
|
881
|
+
| `rootr_remove_custom_domain` | 연결 해제(인증서 호스트도 바로 지움) |
|
|
882
|
+
|
|
842
883
|
문서함은 워크스페이스가 아니라 **사람(이메일)**에 붙습니다. 사람 없는 워크스페이스 키(원격 커넥터)는
|
|
843
884
|
그 키를 만든 구성원으로 동작합니다.
|
|
844
885
|
|
|
@@ -859,11 +900,20 @@ rootr db view <표> <뷰> --scale year # 달력 보기를 주·달·해
|
|
|
859
900
|
`rootr_append_page_blocks`, `rootr_update_page`, `rootr_update_page_block`,
|
|
860
901
|
`rootr_read_page_live_data`)로 저작합니다.
|
|
861
902
|
|
|
862
|
-
HTML을 짜는 것이 아니라 **정해진 블록
|
|
903
|
+
HTML을 짜는 것이 아니라 **정해진 블록 16종을 골라 쌓습니다** — `hero` `text`
|
|
863
904
|
`features` `gallery` `pricing` `testimonials` `faq` `timeline` `cta` `footer` +
|
|
864
905
|
표에서 값을 끌어오는 `liveStats` `liveTable` `liveChart` + 신청을 받는 `form` +
|
|
865
906
|
방문자가 시간을 잡는 `booking`(`{bookingNodeId, headline?, type?}` — 예약을 켜고 공개한 표의 노드 id) +
|
|
866
|
-
자유 블록 `custom`.
|
|
907
|
+
모션그래픽 동영상 `video` + 자유 블록 `custom`.
|
|
908
|
+
|
|
909
|
+
**같은 페이지 안 이동** — 버튼·링크의 `target`에 `{"kind":"block","blockId":"booking"}`을 주면 새 탭 없이
|
|
910
|
+
그 블록까지 부드럽게 내려갑니다(인스타그램 앱 안 브라우저에서 사람을 잃지 않는 광고 랜딩용). 가리킨 블록이
|
|
911
|
+
페이지에 없으면 400이라, 만들 때 그 블록에 `id`를 직접 붙여 둡니다. `text` 본문에서는 `[글](#블록id)`.
|
|
912
|
+
|
|
913
|
+
**동영상(Team 플랜)** — `hero.background`에 `{"kind":"video","attachmentId":"…","posterAttachmentId":"…"}`,
|
|
914
|
+
동영상 블록은 `{attachmentId, posterAttachmentId?, caption?, aspect?: "16:9"|"9:16"|"1:1"|"4:5", bleed?}`.
|
|
915
|
+
둘 다 소리 없이 자동 재생·반복·컨트롤 없음이고, 동작 줄이기를 켠 방문자에게는 포스터 그림만 보입니다.
|
|
916
|
+
히어로 동영상에는 `portraitAttachmentId`·`portraitPosterAttachmentId`(휴대폰 세로판)를 더할 수 있습니다 — 세로 화면은 그 판을, 아니면 기본판을 하나만 내려받습니다.
|
|
867
917
|
|
|
868
918
|
**랜딩 페이지**용으로 두 블록은 가운데 본문 기둥을 벗어나 화면 폭 전체를 쓸 수 있습니다.
|
|
869
919
|
`hero`에 `size: "screen"`을 주면 화면 한 장을 채우는 큰 제목(화면 폭 전체·화면 높이·큰 글자)이 되고,
|
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, **
|
|
14
|
+
- `rootr mcp` — stdio MCP server, **214 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
|
|
@@ -248,8 +256,14 @@ rootr form mapping /intake/request # which column each questi
|
|
|
248
256
|
rootr form mapping /intake/request --set '{"f_name":"p_title"}'
|
|
249
257
|
rootr form responses /intake/request --latest # --latest = newest one per person
|
|
250
258
|
rootr form response-edit <responseId> --values '{"Email":"a@b.com"}'
|
|
259
|
+
rootr form submit /intake/request --values '{"f_email":"a@b.com"}' \
|
|
260
|
+
--files '{"Portfolio":["a.pdf","b.png"]}' # uploads each file, then submits
|
|
251
261
|
```
|
|
252
262
|
|
|
263
|
+
A `file` question takes one file unless it has `"multiple": true` (add `"maxFiles": 5`
|
|
264
|
+
to cap it, default 10); then the answer is an array. `"allowImages": true` on a
|
|
265
|
+
`text`/`textarea` question lets respondents put images inside their answer.
|
|
266
|
+
|
|
253
267
|
Run `form mapping` right after pointing a form at a hand-built table. Answers reach the
|
|
254
268
|
table by matching the question name to the column name, so a question the table has no
|
|
255
269
|
column for is **dropped with no error anywhere** — this command is the only place that
|
|
@@ -286,6 +300,37 @@ rootr readreq /handbook/policy.md --users u1,u2 --due 2026-10-01T00:00:00Z --ack
|
|
|
286
300
|
rootr readreq /handbook/policy.md # who has read it, completion rate
|
|
287
301
|
```
|
|
288
302
|
|
|
303
|
+
### Custom domains (your own website address)
|
|
304
|
+
|
|
305
|
+
Open a published PAGE at your own domain (`www.customer.co.kr`) as a normal website — the root shows the
|
|
306
|
+
page, `/{child}` shows its published child pages, and there is no Rootr signature. Team plan and up,
|
|
307
|
+
workspace admins only.
|
|
308
|
+
|
|
309
|
+
- **Free address** `name.rootr.site` — live at once, no DNS and no payment (3 per workspace; lowercase a-z, 0-9 and
|
|
310
|
+
hyphen, 3–30 chars; names like `www`, `api`, `admin` and anything containing `rootr` are reserved).
|
|
311
|
+
- **Your own domain** — $10/month per domain, $8/month billed yearly ($96/year): one slot of the "Custom domain"
|
|
312
|
+
add-on. With no free slot the API answers `402` and points to Settings → Billing; when the add-on exists but is
|
|
313
|
+
full, `--confirm-charge` buys one more slot (prorated). Removing a domain lowers the quantity (prorated credit);
|
|
314
|
+
removing the last one schedules the add-on to end at the end of the billing period.
|
|
315
|
+
|
|
316
|
+
```bash
|
|
317
|
+
rootr domain detect www.customer.co.kr # where is the DNS managed (Gabia, Cafe24, Cloudflare…) + the steps
|
|
318
|
+
rootr domain add www.customer.co.kr /홈페이지 # register; prints the one DNS line and provider-specific steps
|
|
319
|
+
rootr domain add --subdomain acme /홈페이지 # free address acme.rootr.site — live immediately
|
|
320
|
+
rootr domain available acme # is acme.rootr.site free to take
|
|
321
|
+
rootr domain check <id> # re-check now (exit 2 until it is live)
|
|
322
|
+
rootr domain list # kind, status (waiting for DNS / issuing certificate / connected / paused) + slot usage
|
|
323
|
+
rootr domain rename <id> www.right.co.kr # fix the name of a not-yet-live domain (billing unchanged, new id)
|
|
324
|
+
rootr domain remove <id> # disconnect (then remove the CNAME at your provider)
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
The customer adds exactly **one** DNS line: `CNAME`, name `www`, value `connect.rootr.site`. Rootr then
|
|
328
|
+
issues the HTTPS certificate on its own and re-checks every 5 minutes; whoever registered the domain
|
|
329
|
+
gets a notification and an email when it goes live. A bare root domain (`customer.co.kr`) usually
|
|
330
|
+
cannot hold a CNAME — connect `www.` and forward the root to it (the guide shows how for your provider).
|
|
331
|
+
Only when the same name was registered before by a *different* workspace, one extra `TXT` line
|
|
332
|
+
(`_rootr-verify.www`) is required, so nobody can take over a domain whose CNAME was left behind.
|
|
333
|
+
|
|
289
334
|
### Signed documents and research notes
|
|
290
335
|
|
|
291
336
|
A signed document is a markdown document whose body **freezes the moment it is submitted**; the
|
|
@@ -444,7 +489,7 @@ is refused and says when the grace was used.
|
|
|
444
489
|
|
|
445
490
|
## MCP tools
|
|
446
491
|
|
|
447
|
-
`rootr mcp` speaks MCP over stdio.
|
|
492
|
+
`rootr mcp` speaks MCP over stdio. 214 tools:
|
|
448
493
|
|
|
449
494
|
| Group | Count | Tools |
|
|
450
495
|
|---|---|---|
|
|
@@ -470,6 +515,7 @@ is refused and says when the grace was used.
|
|
|
470
515
|
| Visitor booking & Google Calendar | 6 | turn a published table into a booking page, rules, open slots, connect / list / disconnect Google Calendar |
|
|
471
516
|
| Root-cause Q&A | 1 | ask the workspace knowledge graph, answer with citations |
|
|
472
517
|
| Feedback | 1 | send feedback to the Rootr team |
|
|
518
|
+
| Custom domains | 4 | list (with kind + slot usage), add (own domain: the one DNS line + click-by-click steps for the detected DNS provider; `subdomain` for a free name.rootr.site; `confirmCharge` after the person agrees to buy a slot), check now, remove |
|
|
473
519
|
|
|
474
520
|
Two gaps keep breathing room: `bufferMin` around bookings made through the table (CLI `--buffer`) and
|
|
475
521
|
`calendarBufferMin` around events already on the connected Google Calendar, e.g. travel time to an outside
|
|
@@ -506,11 +552,23 @@ signed-document, issue, CRM and LOG tools need `docs:read` / `docs:write`; `root
|
|
|
506
552
|
### Pages
|
|
507
553
|
|
|
508
554
|
A PAGE is **a screen for people outside the workspace** — an event announcement, a product page,
|
|
509
|
-
a sign-up. You do not write HTML: you stack **
|
|
555
|
+
a sign-up. You do not write HTML: you stack **16 predefined block types** — `hero`, `text`,
|
|
510
556
|
`features`, `gallery`, `pricing`, `testimonials`, `faq`, `timeline`, `cta`, `footer`, the
|
|
511
557
|
table-backed `liveStats`, `liveTable`, `liveChart`, the `form` block, the `booking` block
|
|
512
558
|
(a visitor scheduling calendar: `{bookingNodeId, headline?, type?}` — the node id of a published
|
|
513
|
-
table with visitor booking on) — plus the free-form `custom`.
|
|
559
|
+
table with visitor booking on), the `video` block (a looping motion-graphic clip) — plus the free-form `custom`.
|
|
560
|
+
|
|
561
|
+
**Same-page links.** A button or link `target` can be `{"kind":"block","blockId":"booking"}` — it
|
|
562
|
+
jumps to that block on the same page (smooth scroll, same tab; ideal for a hero "Book now" button
|
|
563
|
+
on an ad landing page opened in an in-app browser). The block must exist on the page (else 400),
|
|
564
|
+
so give it an explicit `id`. In a `text` block, `[label](#<blockId>)` does the same.
|
|
565
|
+
|
|
566
|
+
**Videos (Team plan).** `hero.background` can be `{"kind":"video","attachmentId":"…","posterAttachmentId":"…"}`
|
|
567
|
+
and the `video` block is `{attachmentId, posterAttachmentId?, caption?, aspect?: "16:9"|"9:16"|"1:1"|"4:5", bleed?}`.
|
|
568
|
+
Both autoplay muted and looped with no controls; the poster shows for reduced-motion visitors. A hero video can add
|
|
569
|
+
`portraitAttachmentId` / `portraitPosterAttachmentId` — a vertical cut that portrait phone screens play instead (only one file is downloaded). Upload the
|
|
570
|
+
mp4 with `POST /v1/attachments/upload?workspaceId=…&nodeId=<page>&mimeType=video/mp4` (body = bytes,
|
|
571
|
+
`Content-Type: application/octet-stream`).
|
|
514
572
|
|
|
515
573
|
For a **landing page**, two options let a block use the whole page width instead of the centred
|
|
516
574
|
text column: `hero` with `size: "screen"` is a full-screen hero (edge to edge, one viewport tall,
|