rootr-cli 0.26.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.
@@ -94,6 +94,8 @@ export function registerPublicTools(server) {
94
94
  'PLAN_UPGRADE_REQUIRED; a password-locked page is always hidden and cannot be re-exposed until unlocked); ' +
95
95
  '`{"design": {"layout": "board", "skin": "paper"}}` changes how a published TABLE looks — it does not ' +
96
96
  'have to be a table (cards, gallery, list, board, timeline, calendar, chart, ranking). ' +
97
+ '`{"seoDescription": "...", "seoImage": "<attachment id>"}` sets the search-result description and link-preview ' +
98
+ 'image (search engines are pinged right away). ' +
97
99
  '`{"isPublic": true}` on a PAGE needs the Team plan (Free → 403 PLAN_UPGRADE_REQUIRED); closing it works on any plan. ' +
98
100
  'For DOCUMENT nodes use rootr_set_document_public instead — documents keep their own settings (skins, ' +
99
101
  'edit proposals) on the older path. Owner-level action (MANAGE): use an account key (PAT).',
@@ -106,6 +108,17 @@ export function registerPublicTools(server) {
106
108
  noIndex: z.boolean().optional(),
107
109
  expiresAt: z.string().nullable().optional().describe('ISO date, or null to clear'),
108
110
  password: z.string().nullable().optional().describe('null or "" removes the lock'),
111
+ seoDescription: z
112
+ .string()
113
+ .max(300)
114
+ .nullable()
115
+ .optional()
116
+ .describe('Search-result / link-preview description (~160 chars recommended). null or "" falls back to the opening text.'),
117
+ seoImage: z
118
+ .string()
119
+ .nullable()
120
+ .optional()
121
+ .describe('Link-preview cover image: an image attachment id from the same workspace (rootr_upload_attachment). null removes it.'),
109
122
  view: z.string().optional().describe('DATABASE only: view id the public page opens with'),
110
123
  design: DB_DESIGN_SCHEMA.optional().describe(
111
124
  'DATABASE only: how the public page presents the table. `layout` — table, cards, gallery, list, ' +
@@ -43,7 +43,7 @@ const ACCESS_HINT =
43
43
  'property needs `dimensions` (an embedding column agents fill with rootr_set_row_vectors). ' +
44
44
  'A phone/email/name property may carry `dedupe: true` (warn when the same person is entered again) with ' +
45
45
  '`dedupeShow: ["상태","메모","통화 기록"]` (fields of the existing row the warning shows — a relation shows its latest 5 rows) and ' +
46
- '`dedupeCarry: { label: "재등록", auto: true, exclude: ["접수일"], mark: { "재등록 여부": true, "구분": { map: { "A": "A(재등록)" }, else: "재등록" } } }` ' +
46
+ '`dedupeCarry: { label: "재등록", action: "carry"|"merge_into_old"|"merge_all"|"ask", sources: "all", columns: { "메모": { append: { sep: " / " } } }, exclude: ["접수일"], mark: { "재등록 여부": true, "구분": { map: { "A": "A(재등록)" }, else: "{value} (재등록)" } }, cases: [{ when: { within: { column: "접수일", days: 0 } }, action: "merge_all", mark: {} }, { action: "carry" }] }` ' +
47
47
  '(same entry came back: copy the earlier row into the new one — see rootr_update_column); any property may carry ' +
48
48
  '`validate: { kind: "pattern"|"range"|"date"|"birthdate", pattern?, flags?, negate?, min?, max?, message? }` (flags a wrong value on every new write, never blocks); ' +
49
49
  'a relation property may carry `relationFilter: [{ propId, op: "is"|"is_not_empty", values? }]` (which linked rows may be picked). ' +
@@ -236,6 +236,68 @@ export function registerWorkspaceTools(server) {
236
236
  },
237
237
  );
238
238
 
239
+ server.registerTool(
240
+ 'rootr_workspace_members',
241
+ {
242
+ title: 'List members of a Rootr workspace',
243
+ description:
244
+ 'List the members of a Rootr (루터) workspace — each with their user id, name, email, and role. Use the ' +
245
+ 'id to address rootr_message_member, or to pass as assigneeId/userId elsewhere.',
246
+ annotations: { readOnlyHint: true, destructiveHint: false },
247
+ inputSchema: {
248
+ workspace: z.string().optional().describe('Workspace id; defaults to ROOTR_WORKSPACE/config if omitted'),
249
+ },
250
+ },
251
+ async ({ workspace }) => {
252
+ try {
253
+ const ws = requireWorkspace(workspace);
254
+ const client = makeClient(ws);
255
+ const members = await client.listMembers(ws);
256
+ return jsonResult(
257
+ members.map((m) => ({
258
+ userId: m.userId ?? m.user?.id,
259
+ name: m.user?.name ?? '',
260
+ email: m.user?.email ?? '',
261
+ role: m.role,
262
+ })),
263
+ );
264
+ } catch (err) {
265
+ return errorResult(err);
266
+ }
267
+ },
268
+ );
269
+
270
+ server.registerTool(
271
+ 'rootr_message_member',
272
+ {
273
+ title: 'Send a direct message to a workspace member',
274
+ description:
275
+ 'Send a direct notification-style message to another member of a Rootr (루터) workspace — not tied to ' +
276
+ 'any document, issue, or comment. The message is posted as the person the ROOTR_API_KEY belongs to and ' +
277
+ 'shows up for the recipient in their Rootr notification bell (and by email). Use rootr_workspace_members ' +
278
+ 'first to find the recipient\'s userId.',
279
+ annotations: { readOnlyHint: false, destructiveHint: false },
280
+ inputSchema: {
281
+ userId: z.string().describe('User id of the workspace member to message (see rootr_workspace_members)'),
282
+ body: z.string().describe('Message text'),
283
+ workspace: z
284
+ .string()
285
+ .optional()
286
+ .describe('Workspace id; defaults to ROOTR_WORKSPACE/config if omitted'),
287
+ },
288
+ },
289
+ async ({ userId, body, workspace }) => {
290
+ try {
291
+ const ws = requireWorkspace(workspace);
292
+ const client = makeClient(ws);
293
+ await client.messageMember(ws, userId, body);
294
+ return textResult(`${userId} 에게 메시지를 보냈습니다.`);
295
+ } catch (err) {
296
+ return errorResult(err);
297
+ }
298
+ },
299
+ );
300
+
239
301
  server.registerTool(
240
302
  'rootr_scaffold_plan',
241
303
  {
package/lib/mcp.js CHANGED
@@ -25,6 +25,7 @@ import { registerSignedDocTools } from './mcp-tools/signed.js';
25
25
  import { registerFeedbackTools } from './mcp-tools/feedback.js';
26
26
  import { registerMemoryTools } from './mcp-tools/memory.js';
27
27
  import { registerDocMailTools } from './mcp-tools/doc-mail.js';
28
+ import { registerDomainTools } from './mcp-tools/domains.js';
28
29
  import { withDocMailSink, withRateLimitSink } from './context.js';
29
30
  import { makeClient } from './mcp-tools/shared.js';
30
31
  import { t as tr } from './i18n.js';
@@ -330,6 +331,7 @@ export function buildMcpServer({ name, version }) {
330
331
  registerFeedbackTools(server);
331
332
  registerMemoryTools(server);
332
333
  registerDocMailTools(server);
334
+ registerDomainTools(server);
333
335
 
334
336
  return server;
335
337
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rootr-cli",
3
- "version": "0.26.0",
3
+ "version": "0.29.0",
4
4
  "description": "Official Rootr CLI + MCP server — read, write, edit and search Rootr documents from the shell or from an AI agent.",
5
5
  "type": "module",
6
6
  "bin": {