rootr-cli 0.2.1 → 0.4.1
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/LICENSE +21 -0
- package/README.md +101 -4
- package/bin/rootr.js +109 -3
- package/lib/client.js +531 -1
- package/lib/config.js +30 -1
- package/lib/context.js +38 -0
- package/lib/mcp-tools/ask.js +1 -0
- package/lib/mcp-tools/attachments.js +111 -0
- package/lib/mcp-tools/crm.js +725 -0
- package/lib/mcp-tools/databases.js +25 -14
- package/lib/mcp-tools/documents.js +164 -3
- package/lib/mcp-tools/forms.js +215 -0
- package/lib/mcp-tools/issues.js +13 -4
- package/lib/mcp-tools/logs.js +16 -6
- package/lib/mcp-tools/misc.js +2 -0
- package/lib/mcp-tools/presentations.js +25 -9
- package/lib/mcp-tools/recordings.js +433 -0
- package/lib/mcp-tools/shared.js +44 -3
- package/lib/mcp-tools/spreadsheets.js +231 -0
- package/lib/mcp-tools/webhooks.js +6 -2
- package/lib/mcp-tools/whiteboards.js +169 -0
- package/lib/mcp-tools/workspaces.js +148 -5
- package/lib/mcp.js +98 -5
- package/package.json +22 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Rootr
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -3,12 +3,22 @@
|
|
|
3
3
|
Rootr(마크다운 지식협업 SaaS) 공식 CLI + MCP 서버. 에이전트나 사람이 Rootr 문서를
|
|
4
4
|
로컬 파일처럼 읽고/쓰고/검색할 수 있게 해줍니다.
|
|
5
5
|
|
|
6
|
-
- `rootr` CLI: `ls`, `read`, `write`, `append`, `edit`, `search`, `ws`, `ask`, `config`
|
|
7
|
-
- `rootr mcp`: stdio 기반 MCP 서버 (Claude Code / Claude Desktop 등에 등록해서 사용), 도구
|
|
8
|
-
—
|
|
6
|
+
- `rootr` CLI: `ls`, `read`, `write`, `append`, `edit`, `search`, `rm`, `attach`, `ws`, `ask`, `config`
|
|
7
|
+
- `rootr mcp`: stdio 기반 MCP 서버 (Claude Code / Claude Desktop 등에 등록해서 사용), 도구 90종+
|
|
8
|
+
— 문서·워크스페이스/스캐폴딩·LOG 데이터스토어·RCA ask·이슈·웹훅·첨부파일에 더해
|
|
9
|
+
스프레드시트/화이트보드/폼/프레젠테이션/녹음/CRM/데이터베이스까지. 정확한 목록은 MCP `tools/list`로 확인하세요.
|
|
9
10
|
|
|
10
11
|
순수 Node.js ESM, 빌드 과정 없음. Node 18 이상 필요(내장 `fetch` 사용).
|
|
11
12
|
|
|
13
|
+
## 링크
|
|
14
|
+
|
|
15
|
+
- 소스: https://github.com/gwmage/rootr-cli
|
|
16
|
+
- npm: https://www.npmjs.com/package/rootr-cli
|
|
17
|
+
- 원격 커넥터(설치 없이 바로 연결): `https://rootr.io/mcp` — Claude Code/Desktop 등에서
|
|
18
|
+
로컬 CLI 설치 없이 원격 MCP 엔드포인트로 바로 연결할 수 있습니다. 로컬 CLI(`rootr mcp`)와
|
|
19
|
+
기능은 동일하며, 자체 인프라에 CLI를 두고 싶을 때만 이 저장소를 설치하면 됩니다.
|
|
20
|
+
- 라이선스: MIT (`LICENSE` 참고)
|
|
21
|
+
|
|
12
22
|
## 설치
|
|
13
23
|
|
|
14
24
|
이 저장소 안에서 바로 실행하거나, 전역 설치할 수 있습니다.
|
|
@@ -130,6 +140,18 @@ rootr search "배포 절차"
|
|
|
130
140
|
|
|
131
141
|
출력: `path — snippet` 목록.
|
|
132
142
|
|
|
143
|
+
### 문서 삭제 (휴지통으로)
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
rootr rm /notes/todo.md # 확인 후 삭제
|
|
147
|
+
rootr rm /notes/todo.md --yes # 확인 없이 (스크립트용)
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
휴지통으로 옮기는 **복구 가능한** 삭제입니다. 앱의 휴지통에서 되돌릴 수 있고,
|
|
151
|
+
30일이 지나면 자동으로 완전 삭제됩니다. `--yes` 없이 실행하면 확인을 묻습니다
|
|
152
|
+
(파이프/CI처럼 입력이 없는 환경에서는 "아니오"로 처리되어 안전합니다).
|
|
153
|
+
`docs:write` 스코프가 필요합니다.
|
|
154
|
+
|
|
133
155
|
### 워크스페이스 목록
|
|
134
156
|
|
|
135
157
|
```bash
|
|
@@ -138,6 +160,38 @@ rootr ws
|
|
|
138
160
|
|
|
139
161
|
출력: `id\tname` 목록 (계정 키면 소속된 전체 워크스페이스, 워크스페이스 키면 그 워크스페이스만).
|
|
140
162
|
|
|
163
|
+
### 워크스페이스 여러 개 쓰기 (키 등록 + 전환)
|
|
164
|
+
|
|
165
|
+
워크스페이스마다 키가 다르면 한 번만 등록해 두세요:
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
rootr config --add-key rootr_xxx --label "영업팀"
|
|
169
|
+
rootr config # 등록된 키 목록 확인
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
이후 MCP에서 `rootr_use_workspace` 도구로 **이름이나 id**를 주면 활성 워크스페이스가
|
|
173
|
+
바뀌고, 그 워크스페이스를 담당하는 키가 자동으로 선택·기억됩니다. 계정 키(PAT)를 쓰면
|
|
174
|
+
소속된 어느 워크스페이스로든 바로 전환됩니다.
|
|
175
|
+
|
|
176
|
+
> 원격 커넥터(`https://rootr.io/mcp`)는 승인할 때 고른 워크스페이스 하나에만 연결됩니다.
|
|
177
|
+
> 다른 워크스페이스가 필요하면 그 워크스페이스로 커넥터를 새로 발급하세요.
|
|
178
|
+
|
|
179
|
+
### 사용량 한도
|
|
180
|
+
|
|
181
|
+
프로그램(API 키·MCP) 호출 중 **조회 계열**(`docs:read`/`graph:read`/`ask`)에만 한도가 있습니다.
|
|
182
|
+
쓰기·업로드는 제한하지 않습니다.
|
|
183
|
+
|
|
184
|
+
| 플랜 | 한도 |
|
|
185
|
+
| --- | --- |
|
|
186
|
+
| Free | **하루 180회** (KST 자정 리셋) |
|
|
187
|
+
| Team | 시간당 5,000회 |
|
|
188
|
+
| Business | 시간당 50,000회 |
|
|
189
|
+
| Platform | 무제한 |
|
|
190
|
+
|
|
191
|
+
한도의 80%를 쓰면 MCP 도구 응답 끝에 남은 횟수 안내가 붙고, 다 쓰면 429와 함께
|
|
192
|
+
업그레이드 링크가 담긴 안내가 나옵니다. 응답 헤더로도 확인할 수 있습니다
|
|
193
|
+
(`X-RateLimit-Remaining`, `X-RateLimit-Reset`, `X-RateLimit-Window`).
|
|
194
|
+
|
|
141
195
|
### RCA 질의응답 (ask)
|
|
142
196
|
|
|
143
197
|
```bash
|
|
@@ -150,7 +204,14 @@ rootr ask "왜 결제 실패가 늘었지?" --workspace ws_123
|
|
|
150
204
|
|
|
151
205
|
## MCP 서버로 사용하기
|
|
152
206
|
|
|
153
|
-
`rootr mcp`는 stdio로 MCP(Model Context Protocol) 서버를 구동합니다. 제공 도구
|
|
207
|
+
`rootr mcp`는 stdio로 MCP(Model Context Protocol) 서버를 구동합니다. 제공 도구 29종:
|
|
208
|
+
|
|
209
|
+
노드를 가리키는 인자(`target`, `databaseId`, `spreadsheetId`, `formId`, `crmId`, `trackerId`,
|
|
210
|
+
`recordingId`, `presentationId`, `whiteboardId`, `logId`, `parentId` 등)는 **노드 id와 경로를 모두**
|
|
211
|
+
받습니다 — CLI와 같은 규칙으로 `/`로 시작하면 경로로 해석합니다.
|
|
212
|
+
즉 `rootr_add_row`에 `databaseId: "/제작 공정/칸반"`을 그대로 넘길 수 있어,
|
|
213
|
+
경로만 아는 에이전트가 uuid를 찾아 헤맬 필요가 없습니다.
|
|
214
|
+
`rootr_list`·`rootr_search` 출력도 각 줄 끝에 `[노드 id]`를 함께 표시합니다.
|
|
154
215
|
|
|
155
216
|
#### 문서 (workspace 키, docs:read/docs:write)
|
|
156
217
|
|
|
@@ -167,6 +228,16 @@ rootr ask "왜 결제 실패가 늘었지?" --workspace ws_123
|
|
|
167
228
|
`rootr_write`는 정말 전체를 다시 쓸 때만 (가능하면 `ifMatch`와 함께) 쓰도록
|
|
168
229
|
각 도구 설명에 명시되어 있습니다.
|
|
169
230
|
|
|
231
|
+
#### 첨부파일 (workspace 키, docs:write)
|
|
232
|
+
|
|
233
|
+
| 도구 | 설명 |
|
|
234
|
+
|---|---|
|
|
235
|
+
| `rootr_upload_attachment` | 로컬 파일(`filePath`) 또는 base64(`base64Data`)를 업로드하고 `{id, url, markdown}` 반환 |
|
|
236
|
+
| `rootr_attach_image_to_document` | 위 업로드 + 지정 문서에 `rootr_append`로 바로 삽입 (가장 흔한 용법) |
|
|
237
|
+
|
|
238
|
+
`url`은 `/attachments/{id}/raw` — 로그인 없이 렌더되는 공개 경로라 published(`/p/`) 문서에도
|
|
239
|
+
그대로 쓸 수 있습니다. CLI에서는 `rootr attach <file> [--doc <path|id>] [--heading "## X"] [--alt <text>]`.
|
|
240
|
+
|
|
170
241
|
#### 워크스페이스 / 스캐폴딩
|
|
171
242
|
|
|
172
243
|
| 도구 | 필요 스코프 | 설명 |
|
|
@@ -218,6 +289,32 @@ rootr ask "왜 결제 실패가 늘었지?" --workspace ws_123
|
|
|
218
289
|
| `rootr_document_versions` | 문서 버전 히스토리 조회 |
|
|
219
290
|
| `rootr_delete_node` | 노드를 휴지통으로 이동(복구 가능) |
|
|
220
291
|
|
|
292
|
+
#### 프레젠테이션 (현재 REST 전용 — 전용 MCP 도구는 예정)
|
|
293
|
+
|
|
294
|
+
프레젠테이션(PRESENTATION) 노드는 아직 전용 MCP 도구가 없고, **같은 API 키로 REST를
|
|
295
|
+
직접 호출**해 저작합니다 (`x-api-key` 헤더, `docs:write`):
|
|
296
|
+
|
|
297
|
+
```bash
|
|
298
|
+
# 덱 생성 (슬라이드 포함 가능)
|
|
299
|
+
curl -X POST "$BASE/workspaces/$WS/presentations" -H "x-api-key: $KEY" \
|
|
300
|
+
-H 'Content-Type: application/json' \
|
|
301
|
+
-d '{"name":"제안서","slides":[{"id":"SLD-001","kind":"cover","title":"..."}]}'
|
|
302
|
+
|
|
303
|
+
# 슬라이드 부분 수정(머지) / 추가 / 순서 변경
|
|
304
|
+
curl -X PATCH "$BASE/presentations/$ID/slides/SLD-001" -H "x-api-key: $KEY" \
|
|
305
|
+
-H 'Content-Type: application/json' -d '{"slide":{"notes":"발표 대본"}}'
|
|
306
|
+
curl -X POST "$BASE/presentations/$ID/slides" -d '{"slides":[...]}' ...
|
|
307
|
+
curl -X POST "$BASE/presentations/$ID/reorder" -d '{"order":["SLD-002","SLD-001"]}' ...
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
**고품질 덱을 만들 때는 슬라이드 `html` 필드에 1280×720 완결 HTML을 직접 구워
|
|
311
|
+
넣는 방식을 권장**합니다 — 뷰어가 기본 템플릿 대신 그대로 렌더합니다(완전 자유
|
|
312
|
+
디자인). 필수 규칙(외부 요청 차단이라 전부 인라인, 이미지=data URI 내장, 폰트
|
|
313
|
+
폴백 스택, `<span class="pn">`=페이지번호, 그래프용 텍스트(title/blocks/notes/alt)
|
|
314
|
+
병행 유지)은 **`/llms.txt`의 "Presentations" 섹션**에 정리돼 있습니다 — 저작 전에
|
|
315
|
+
꼭 읽어보세요. AI 이미지 생성은 `POST /v1/workspaces/:ws/images/generate`(AI
|
|
316
|
+
크레딧 차감)를 사용합니다.
|
|
317
|
+
|
|
221
318
|
모든 도구 설명은 영어(에이전트가 소비하는 스키마)로 작성되어 있고, JSON을 반환하는
|
|
222
319
|
도구는 보기 좋게 들여쓴 JSON 텍스트로 응답합니다. `workspace` 인자를 받는 도구는
|
|
223
320
|
생략 시 `ROOTR_WORKSPACE`/설정파일의 기본 워크스페이스를 사용하며, 그것도 없으면
|
package/bin/rootr.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { readFileSync } from 'node:fs';
|
|
3
3
|
import { fileURLToPath } from 'node:url';
|
|
4
|
-
import { dirname, join } from 'node:path';
|
|
4
|
+
import { dirname, join, basename, extname } from 'node:path';
|
|
5
5
|
|
|
6
|
-
import { loadConfig, saveConfig, maskKey, CONFIG_PATH, DEFAULT_BASE_URL } from '../lib/config.js';
|
|
6
|
+
import { loadConfig, saveConfig, maskKey, upsertKey, CONFIG_PATH, DEFAULT_BASE_URL } from '../lib/config.js';
|
|
7
7
|
import { RootrClient, RootrApiError } from '../lib/client.js';
|
|
8
8
|
import { resolveTarget, requireResolved } from '../lib/resolve.js';
|
|
9
9
|
|
|
@@ -19,10 +19,13 @@ const USAGE = `Rootr CLI v${pkg.version}
|
|
|
19
19
|
rootr append <path|id> [<text>] [--heading "## X"] [--file <f>] 문서 끝(또는 헤딩 아래)에 안전하게 추가
|
|
20
20
|
rootr edit <path|id> --find <text> --replace <text> [--all] 본문 내 텍스트 치환
|
|
21
21
|
rootr search <query> 워크스페이스 검색
|
|
22
|
+
rootr rm <path|id> [--yes] 문서/폴더를 휴지통으로 이동 (복구 가능)
|
|
23
|
+
rootr attach <file> [--doc <path|id>] [--heading "## X"] [--alt <text>] 파일 업로드(+문서에 삽입)
|
|
22
24
|
rootr ws 내 워크스페이스 목록 (id\tname)
|
|
23
25
|
rootr ask <question> [--workspace <w>] GraphRAG 질의응답 (RCA), 인용 포함 출력
|
|
24
26
|
rootr config [--api-key <k>] [--workspace <w>] [--base-url <u>] 설정 조회/저장
|
|
25
|
-
rootr
|
|
27
|
+
rootr config --add-key <k> [--label <name>] [--workspace <w>] 워크스페이스별 키 추가 등록
|
|
28
|
+
rootr mcp MCP stdio 서버 구동 (도구 90종+ — README 참고)
|
|
26
29
|
rootr --help 도움말
|
|
27
30
|
rootr --version 버전 출력
|
|
28
31
|
|
|
@@ -215,6 +218,89 @@ async function cmdSearch(args) {
|
|
|
215
218
|
}
|
|
216
219
|
}
|
|
217
220
|
|
|
221
|
+
async function cmdRm(args) {
|
|
222
|
+
const target = args._[0];
|
|
223
|
+
if (!target) throw new Error('사용법: rootr rm <path|id> [--yes]');
|
|
224
|
+
|
|
225
|
+
const client = makeClient();
|
|
226
|
+
const resolved = await resolveTarget(client, target);
|
|
227
|
+
const id = requireResolved(resolved);
|
|
228
|
+
|
|
229
|
+
// Deleting is recoverable (trash), but it still removes the node from every
|
|
230
|
+
// teammate's tree — confirm unless the caller opted out for scripting.
|
|
231
|
+
if (!args.yes) {
|
|
232
|
+
const label = resolved.path || resolved.name || id;
|
|
233
|
+
const ok = await confirmPrompt(`"${label}" 을(를) 휴지통으로 옮깁니다. 계속할까요? [y/N] `);
|
|
234
|
+
if (!ok) {
|
|
235
|
+
console.log('취소했습니다.');
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
await client.deleteNode(id);
|
|
241
|
+
console.log(`휴지통으로 옮겼습니다: ${resolved.path || id}`);
|
|
242
|
+
console.log('복구하려면 앱의 휴지통에서 되돌리세요 (30일 뒤 자동 삭제).');
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/** Minimal y/N prompt. Non-interactive stdin (pipes, CI) answers "no". */
|
|
246
|
+
function confirmPrompt(question) {
|
|
247
|
+
if (!process.stdin.isTTY) return Promise.resolve(false);
|
|
248
|
+
return new Promise((resolve) => {
|
|
249
|
+
process.stdout.write(question);
|
|
250
|
+
process.stdin.setEncoding('utf8');
|
|
251
|
+
process.stdin.once('data', (data) => {
|
|
252
|
+
process.stdin.pause();
|
|
253
|
+
resolve(/^y(es)?$/i.test(String(data).trim()));
|
|
254
|
+
});
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
const MIME_BY_EXT = {
|
|
259
|
+
'.png': 'image/png',
|
|
260
|
+
'.jpg': 'image/jpeg',
|
|
261
|
+
'.jpeg': 'image/jpeg',
|
|
262
|
+
'.gif': 'image/gif',
|
|
263
|
+
'.webp': 'image/webp',
|
|
264
|
+
'.svg': 'image/svg+xml',
|
|
265
|
+
'.pdf': 'application/pdf',
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
async function cmdAttach(args) {
|
|
269
|
+
const filePath = args._[0];
|
|
270
|
+
if (!filePath) throw new Error('사용법: rootr attach <file> [--doc <path|id>] [--heading "## X"] [--alt <text>]');
|
|
271
|
+
|
|
272
|
+
const cfg = loadConfig();
|
|
273
|
+
const workspace = args.workspace || cfg.workspace;
|
|
274
|
+
if (!workspace) {
|
|
275
|
+
throw new RootrApiError('워크스페이스가 설정되지 않았습니다.', {
|
|
276
|
+
hint: '--workspace <id>로 넘기거나 rootr config --workspace <id> 또는 ROOTR_WORKSPACE 환경변수를 지정하세요.',
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
const client = new RootrClient({ ...cfg, workspace });
|
|
281
|
+
const data = readFileSync(filePath);
|
|
282
|
+
const filename = basename(filePath);
|
|
283
|
+
const mimeType = args.mime || MIME_BY_EXT[extname(filePath).toLowerCase()] || 'application/octet-stream';
|
|
284
|
+
|
|
285
|
+
let nodeId;
|
|
286
|
+
if (typeof args.doc === 'string') {
|
|
287
|
+
const resolved = await resolveTarget(client, args.doc);
|
|
288
|
+
nodeId = requireResolved(resolved);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
const { id } = await client.uploadAttachment(workspace, { filename, mimeType, nodeId, data });
|
|
292
|
+
const url = client.attachmentRawUrl(id);
|
|
293
|
+
const markdown = ``;
|
|
294
|
+
|
|
295
|
+
if (nodeId) {
|
|
296
|
+
const result = await client.appendDocument(nodeId, { content: markdown, underHeading: args.heading });
|
|
297
|
+
console.error(`uploaded ${filename} (id ${id}) and appended to ${args.doc} (etag ${result.etag || 'n/a'})`);
|
|
298
|
+
} else {
|
|
299
|
+
console.error(`uploaded ${filename} (id ${id})`);
|
|
300
|
+
}
|
|
301
|
+
console.log(markdown);
|
|
302
|
+
}
|
|
303
|
+
|
|
218
304
|
async function cmdWs() {
|
|
219
305
|
const client = makeClient();
|
|
220
306
|
const workspaces = await client.listWorkspaces();
|
|
@@ -248,6 +334,19 @@ async function cmdAsk(args) {
|
|
|
248
334
|
}
|
|
249
335
|
|
|
250
336
|
async function cmdConfig(args) {
|
|
337
|
+
// Registering an extra credential is its own action — several keys can live
|
|
338
|
+
// side by side, each bound to the workspace it can reach, so `rootr mcp` (and
|
|
339
|
+
// the rootr_use_workspace tool) can switch workspaces without reconfiguring.
|
|
340
|
+
if (typeof args['add-key'] === 'string') {
|
|
341
|
+
const keys = upsertKey({
|
|
342
|
+
apiKey: args['add-key'],
|
|
343
|
+
workspace: typeof args.workspace === 'string' ? args.workspace : undefined,
|
|
344
|
+
label: typeof args.label === 'string' ? args.label : undefined,
|
|
345
|
+
});
|
|
346
|
+
console.log(`키를 등록했습니다 (총 ${keys.length}개): ${CONFIG_PATH}`);
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
|
|
251
350
|
const hasAny = args['api-key'] || args.workspace || args['base-url'];
|
|
252
351
|
if (!hasAny) {
|
|
253
352
|
const cfg = loadConfig();
|
|
@@ -255,6 +354,9 @@ async function cmdConfig(args) {
|
|
|
255
354
|
console.log(`apiKey: ${maskKey(cfg.apiKey)}`);
|
|
256
355
|
console.log(`workspace: ${cfg.workspace || '(not set)'}`);
|
|
257
356
|
console.log(`baseUrl: ${cfg.baseUrl || DEFAULT_BASE_URL}`);
|
|
357
|
+
for (const k of cfg.keys || []) {
|
|
358
|
+
console.log(` + ${maskKey(k.apiKey)} ${k.workspace || '(any)'} ${k.label || ''}`);
|
|
359
|
+
}
|
|
258
360
|
return;
|
|
259
361
|
}
|
|
260
362
|
|
|
@@ -301,6 +403,10 @@ async function main() {
|
|
|
301
403
|
return cmdEdit(args);
|
|
302
404
|
case 'search':
|
|
303
405
|
return cmdSearch(args);
|
|
406
|
+
case 'attach':
|
|
407
|
+
return cmdAttach(args);
|
|
408
|
+
case 'rm':
|
|
409
|
+
return cmdRm(args);
|
|
304
410
|
case 'ws':
|
|
305
411
|
return cmdWs(args);
|
|
306
412
|
case 'ask':
|