rootr-cli 0.8.0 → 0.9.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.md +42 -4
- package/bin/rootr.js +375 -1
- package/lib/client.js +147 -12
- package/lib/mcp-tools/databases.js +346 -25
- package/lib/mcp-tools/documents.js +230 -3
- package/lib/mcp-tools/forms.js +87 -2
- package/lib/mcp-tools/misc.js +40 -0
- package/lib/mcp-tools/workspaces.js +8 -1
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -348,6 +348,55 @@ export class RootrClient {
|
|
|
348
348
|
});
|
|
349
349
|
}
|
|
350
350
|
|
|
351
|
+
// ── DB-PERM-001 / DB-WATCH — 표에 거는 자물쇠와 알림 규칙 ──────────────
|
|
352
|
+
//
|
|
353
|
+
// 노션에 없는 것들이라, 에이전트가 표를 만들어 놓고도 "지원서는 서로 못 보게" 같은
|
|
354
|
+
// 요구를 못 들어주는 일이 있었다. 만들 수 있으면 잠글 수도 있어야 한다.
|
|
355
|
+
|
|
356
|
+
async getDatabasePermissions(databaseId) {
|
|
357
|
+
return this.request(`/databases/${encodeURIComponent(databaseId)}/permissions`);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
async setDatabasePermissions(databaseId, permissions) {
|
|
361
|
+
return this.request(`/databases/${encodeURIComponent(databaseId)}/permissions`, {
|
|
362
|
+
method: 'PATCH',
|
|
363
|
+
body: permissions,
|
|
364
|
+
});
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
async getDatabaseNotifications(databaseId) {
|
|
368
|
+
return this.request(`/databases/${encodeURIComponent(databaseId)}/notifications`);
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
async setDatabaseNotifications(databaseId, watchers) {
|
|
372
|
+
return this.request(`/databases/${encodeURIComponent(databaseId)}/notifications`, {
|
|
373
|
+
method: 'PUT',
|
|
374
|
+
body: { watchers },
|
|
375
|
+
});
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
// ── PUBLIC-DOCS — 발행한 문서에 올라온 변경 제안 ────────────────────────
|
|
379
|
+
|
|
380
|
+
async listDocumentCommits(documentId, status = 'OPEN') {
|
|
381
|
+
return this.request(
|
|
382
|
+
`/documents/${encodeURIComponent(documentId)}/commits?status=${encodeURIComponent(status)}`,
|
|
383
|
+
);
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
async mergeDocumentCommit(documentId, commitId, force = false) {
|
|
387
|
+
return this.request(
|
|
388
|
+
`/documents/${encodeURIComponent(documentId)}/commits/${encodeURIComponent(commitId)}/merge`,
|
|
389
|
+
{ method: 'POST', body: force ? { force: true } : {} },
|
|
390
|
+
);
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
async rejectDocumentCommit(documentId, commitId, reason) {
|
|
394
|
+
return this.request(
|
|
395
|
+
`/documents/${encodeURIComponent(documentId)}/commits/${encodeURIComponent(commitId)}/reject`,
|
|
396
|
+
{ method: 'POST', body: reason ? { reason } : {} },
|
|
397
|
+
);
|
|
398
|
+
}
|
|
399
|
+
|
|
351
400
|
async getDocumentPublicStatus(documentId) {
|
|
352
401
|
return this.request(`/documents/${encodeURIComponent(documentId)}/public-status`);
|
|
353
402
|
}
|
|
@@ -602,6 +651,25 @@ export class RootrClient {
|
|
|
602
651
|
});
|
|
603
652
|
}
|
|
604
653
|
|
|
654
|
+
/**
|
|
655
|
+
* 뷰를 하나 **덧붙인다**(기존 뷰는 그대로). 표를 만들 때만 뷰를 정할 수 있어서,
|
|
656
|
+
* 노션에서 뷰가 넷인 표를 옮기면 하나밖에 못 두던 문제를 푼다.
|
|
657
|
+
*/
|
|
658
|
+
async createDatabaseView(databaseId, { name, type, groupBy, dateProp, endDateProp } = {}) {
|
|
659
|
+
return this.request(`/databases/${encodeURIComponent(databaseId)}/views`, {
|
|
660
|
+
method: 'POST',
|
|
661
|
+
body: { name, type, groupBy, dateProp, endDateProp },
|
|
662
|
+
});
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
/** 뷰 하나를 지운다. 마지막 하나는 못 지운다. 행 값은 안 지워진다. */
|
|
666
|
+
async deleteDatabaseView(databaseId, viewId) {
|
|
667
|
+
return this.request(
|
|
668
|
+
`/databases/${encodeURIComponent(databaseId)}/views/${encodeURIComponent(viewId)}`,
|
|
669
|
+
{ method: 'DELETE' },
|
|
670
|
+
);
|
|
671
|
+
}
|
|
672
|
+
|
|
605
673
|
/**
|
|
606
674
|
* 뷰 하나만 고친다(이름·감출 컬럼·그룹 기준). PATCH /databases/:id 는 views 배열을
|
|
607
675
|
* 통째로 갈아끼워서 빠뜨린 뷰가 사라지는데, 여기서는 서버가 그 뷰만 병합한다.
|
|
@@ -618,25 +686,29 @@ export class RootrClient {
|
|
|
618
686
|
return this.request(`/databases/${encodeURIComponent(databaseId)}`);
|
|
619
687
|
}
|
|
620
688
|
|
|
621
|
-
/**
|
|
622
|
-
|
|
623
|
-
|
|
689
|
+
/**
|
|
690
|
+
* All rows of a database, in position order. Returns the raw rows array.
|
|
691
|
+
* DB-BODY — `withBody` 를 주면 행마다 상세 내용(본문 메모)까지 함께 온다.
|
|
692
|
+
*/
|
|
693
|
+
async listRows(databaseId, { withBody = false } = {}) {
|
|
694
|
+
const query = withBody ? '?body=1' : '';
|
|
695
|
+
const data = await this.request(`/databases/${encodeURIComponent(databaseId)}/rows${query}`);
|
|
624
696
|
if (Array.isArray(data)) return data;
|
|
625
697
|
if (data && Array.isArray(data.rows)) return data.rows;
|
|
626
698
|
return [];
|
|
627
699
|
}
|
|
628
700
|
|
|
629
|
-
async createRow(databaseId, { values, position } = {}) {
|
|
701
|
+
async createRow(databaseId, { values, position, body } = {}) {
|
|
630
702
|
return this.request(`/databases/${encodeURIComponent(databaseId)}/rows`, {
|
|
631
703
|
method: 'POST',
|
|
632
|
-
body: { values, position },
|
|
704
|
+
body: { values, position, body },
|
|
633
705
|
});
|
|
634
706
|
}
|
|
635
707
|
|
|
636
|
-
async updateRow(databaseId, rowId, { values, position } = {}) {
|
|
708
|
+
async updateRow(databaseId, rowId, { values, position, body } = {}) {
|
|
637
709
|
return this.request(
|
|
638
710
|
`/databases/${encodeURIComponent(databaseId)}/rows/${encodeURIComponent(rowId)}`,
|
|
639
|
-
{ method: 'PATCH', body: { values, position } },
|
|
711
|
+
{ method: 'PATCH', body: { values, position, body } },
|
|
640
712
|
);
|
|
641
713
|
}
|
|
642
714
|
|
|
@@ -651,10 +723,11 @@ export class RootrClient {
|
|
|
651
723
|
// PATCH /databases/:id replaces the whole properties array, so rebuilding it
|
|
652
724
|
// client-side drops any column left out. These merge server-side instead.
|
|
653
725
|
|
|
654
|
-
async addColumn(databaseId, { name, type, options } = {}) {
|
|
726
|
+
async addColumn(databaseId, { name, type, options, relationDatabaseId, formula, rollup, prefix } = {}) {
|
|
655
727
|
return this.request(`/databases/${encodeURIComponent(databaseId)}/columns`, {
|
|
656
728
|
method: 'POST',
|
|
657
|
-
|
|
729
|
+
// 계산 칸(수식·롤업·번호)은 설정이 곧 그 칸이라 같이 보내야 한다.
|
|
730
|
+
body: { name, type, options, relationDatabaseId, formula, rollup, prefix },
|
|
658
731
|
});
|
|
659
732
|
}
|
|
660
733
|
|
|
@@ -1132,13 +1205,75 @@ export class RootrClient {
|
|
|
1132
1205
|
});
|
|
1133
1206
|
}
|
|
1134
1207
|
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1208
|
+
// ── 문서·폴더 접근 권한(공개범위) ────────────────────────────────
|
|
1209
|
+
// 화면의 "공개범위"·"권한" 창이 하는 일을 그대로 연다. 관리 권한이 있는
|
|
1210
|
+
// 사람만 부를 수 있고, 없으면 서버가 403으로 막는다.
|
|
1211
|
+
|
|
1212
|
+
/** 이 노드의 공개범위와 직접·상속 권한을 함께 읽는다. */
|
|
1213
|
+
async getNodeAccess(nodeId) {
|
|
1214
|
+
return this.request(`/nodes/${encodeURIComponent(nodeId)}/permissions`);
|
|
1215
|
+
}
|
|
1216
|
+
|
|
1217
|
+
/** 공개범위를 정한다. null이면 상위 폴더/워크스페이스 기본값을 따른다. */
|
|
1218
|
+
async setNodeVisibility(nodeId, visibility) {
|
|
1219
|
+
return this.request(`/nodes/${encodeURIComponent(nodeId)}/visibility`, {
|
|
1220
|
+
method: 'POST',
|
|
1221
|
+
body: { visibility: visibility ?? null },
|
|
1222
|
+
});
|
|
1223
|
+
}
|
|
1224
|
+
|
|
1225
|
+
/** 특정 사람/그룹에게 이 노드의 권한을 준다(이미 있으면 등급만 바뀐다). */
|
|
1226
|
+
async grantNodePermission(nodeId, { subjectType = 'USER', subjectId, level }) {
|
|
1227
|
+
return this.request(`/nodes/${encodeURIComponent(nodeId)}/permissions`, {
|
|
1228
|
+
method: 'POST',
|
|
1229
|
+
body: { subjectType, subjectId, level },
|
|
1230
|
+
});
|
|
1231
|
+
}
|
|
1232
|
+
|
|
1233
|
+
/** 준 권한을 거둔다. */
|
|
1234
|
+
async revokeNodePermission(nodeId, { subjectType = 'USER', subjectId }) {
|
|
1235
|
+
return this.request(`/nodes/${encodeURIComponent(nodeId)}/permissions`, {
|
|
1236
|
+
method: 'DELETE',
|
|
1237
|
+
body: { subjectType, subjectId },
|
|
1238
|
+
});
|
|
1239
|
+
}
|
|
1240
|
+
|
|
1241
|
+
/**
|
|
1242
|
+
* Submitted responses, most recent first.
|
|
1243
|
+
* `latestPerRespondent`이면 같은 사람이 여러 번 낸 것 중 마지막 것만 남긴다
|
|
1244
|
+
* (누가 냈는지 모르는 익명 제출은 합치지 않는다 — 합칠 근거가 없다).
|
|
1245
|
+
*/
|
|
1246
|
+
async listFormResponses(formId, { latestPerRespondent } = {}) {
|
|
1247
|
+
const qs = latestPerRespondent ? '?latestPerRespondent=true' : '';
|
|
1248
|
+
const data = await this.request(`/forms/${encodeURIComponent(formId)}/responses${qs}`);
|
|
1138
1249
|
if (data && Array.isArray(data.responses)) return data.responses;
|
|
1139
1250
|
return [];
|
|
1140
1251
|
}
|
|
1141
1252
|
|
|
1253
|
+
/**
|
|
1254
|
+
* 응답 모을 곳을 새로 만들어 연결한다. 'database'면 폼 질문 그대로 칸이 생기고,
|
|
1255
|
+
* 'spreadsheet'면 응답이 깔리는 시트가 한 장 생긴다. 미리 만들어 둘 필요가 없다.
|
|
1256
|
+
*/
|
|
1257
|
+
async createFormCollector(formId, target) {
|
|
1258
|
+
return this.request(`/forms/${encodeURIComponent(formId)}/collect`, {
|
|
1259
|
+
method: 'POST',
|
|
1260
|
+
body: { target },
|
|
1261
|
+
});
|
|
1262
|
+
}
|
|
1263
|
+
|
|
1264
|
+
/** 이미 낸 응답의 내용을 고친다(폼의 검사 규칙을 그대로 다시 통과해야 한다). */
|
|
1265
|
+
async updateFormResponse(responseId, values) {
|
|
1266
|
+
return this.request(`/form-responses/${encodeURIComponent(responseId)}`, {
|
|
1267
|
+
method: 'PATCH',
|
|
1268
|
+
body: { values },
|
|
1269
|
+
});
|
|
1270
|
+
}
|
|
1271
|
+
|
|
1272
|
+
/** 응답 한 건을 지운다. */
|
|
1273
|
+
async deleteFormResponse(responseId) {
|
|
1274
|
+
return this.request(`/form-responses/${encodeURIComponent(responseId)}`, { method: 'DELETE' });
|
|
1275
|
+
}
|
|
1276
|
+
|
|
1142
1277
|
async createFormResponse(formId, values) {
|
|
1143
1278
|
return this.request(`/forms/${encodeURIComponent(formId)}/responses`, {
|
|
1144
1279
|
method: 'POST',
|