@batalabs/virlow-mcp-core 3.123.0 → 3.125.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/dist/cjs/notes.d.ts +25 -0
- package/dist/cjs/notes.js +19 -0
- package/dist/cjs/todos.d.ts +28 -2
- package/dist/cjs/todos.js +175 -41
- package/dist/notes.d.ts +25 -0
- package/dist/notes.d.ts.map +1 -1
- package/dist/notes.js +19 -0
- package/dist/notes.js.map +1 -1
- package/dist/todos.d.ts +28 -2
- package/dist/todos.d.ts.map +1 -1
- package/dist/todos.js +175 -41
- package/dist/todos.js.map +1 -1
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +19 -10
- package/dist/tools.js.map +1 -1
- package/package.json +3 -3
package/dist/cjs/notes.d.ts
CHANGED
|
@@ -8,6 +8,24 @@ import { WorkspaceKeyring } from './keyring.js';
|
|
|
8
8
|
* `truncated` tells the caller when the account holds more than this. Also
|
|
9
9
|
* bounds listVisibleRows(), which backs mention-matching and backlinks(). */
|
|
10
10
|
export declare const SEARCH_SCAN_CAP = 500;
|
|
11
|
+
/**
|
|
12
|
+
* An Exposure plus a fingerprint of the folder list it was computed from.
|
|
13
|
+
*
|
|
14
|
+
* The fingerprint is what tells the paged row cache whether the rows it holds
|
|
15
|
+
* were filtered under the same folder settings the current call is asking
|
|
16
|
+
* about. It rides on the exposure object so it can never be paired with the
|
|
17
|
+
* wrong one: an instance field would be overwritten by any concurrent call
|
|
18
|
+
* that reached listFolders() second.
|
|
19
|
+
*/
|
|
20
|
+
/** What the to-do tools need to know about folders. See NotesService.todoScope. */
|
|
21
|
+
export interface TodoScope {
|
|
22
|
+
/** Whether the connector may see what is in this folder. */
|
|
23
|
+
allows(folderId: string): boolean;
|
|
24
|
+
/** The shared workspace a folder belongs to; null for a personal one. */
|
|
25
|
+
workspaceOf(folderId: string | null): string | null;
|
|
26
|
+
/** The folder's name as the person sees it. */
|
|
27
|
+
folderName(folderId: string): Promise<string>;
|
|
28
|
+
}
|
|
11
29
|
/** One property a setProperties() call actually changed, said the way the
|
|
12
30
|
* caller asked for it: the definition's name, and option names rather than
|
|
13
31
|
* the option ids stored in the note. A caller that had to read ids back to
|
|
@@ -290,6 +308,13 @@ export declare class NotesService {
|
|
|
290
308
|
}>;
|
|
291
309
|
withheld: number;
|
|
292
310
|
}>;
|
|
311
|
+
/**
|
|
312
|
+
* Where shared to-dos may come from, for the to-do tools: a shared list
|
|
313
|
+
* lives in its workspace's root folder, so it is open exactly when that
|
|
314
|
+
* folder is (the same rule as the workspace's notes), and is read and
|
|
315
|
+
* written under the workspace key. Computed fresh for each call.
|
|
316
|
+
*/
|
|
317
|
+
todoScope(): Promise<TodoScope>;
|
|
293
318
|
/** Folder exposure for this request. Not cached across calls: the user can
|
|
294
319
|
* flip the switch in the app at any moment and the next tool call must
|
|
295
320
|
* respect it. */
|
package/dist/cjs/notes.js
CHANGED
|
@@ -849,6 +849,25 @@ class NotesService {
|
|
|
849
849
|
}
|
|
850
850
|
return { folders, notes, withheld };
|
|
851
851
|
}
|
|
852
|
+
/**
|
|
853
|
+
* Where shared to-dos may come from, for the to-do tools: a shared list
|
|
854
|
+
* lives in its workspace's root folder, so it is open exactly when that
|
|
855
|
+
* folder is (the same rule as the workspace's notes), and is read and
|
|
856
|
+
* written under the workspace key. Computed fresh for each call.
|
|
857
|
+
*/
|
|
858
|
+
async todoScope() {
|
|
859
|
+
const { folders } = await this.api.listFolders();
|
|
860
|
+
const exposure = await this.exposureOf(folders);
|
|
861
|
+
const byId = new Map(folders.map((f) => [f.id, f]));
|
|
862
|
+
return {
|
|
863
|
+
allows: (folderId) => exposure.allows(folderId),
|
|
864
|
+
workspaceOf: (folderId) => exposure.workspaceOf(folderId),
|
|
865
|
+
folderName: async (folderId) => {
|
|
866
|
+
const folder = byId.get(folderId);
|
|
867
|
+
return folder ? this.folderName(this.vault.session.key, folder) : 'Shared workspace';
|
|
868
|
+
},
|
|
869
|
+
};
|
|
870
|
+
}
|
|
852
871
|
/** Folder exposure for this request. Not cached across calls: the user can
|
|
853
872
|
* flip the switch in the app at any moment and the next tool call must
|
|
854
873
|
* respect it. */
|
package/dist/cjs/todos.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { VirlowApi } from './api.js';
|
|
2
|
+
import type { WorkspaceKeyring } from './keyring.js';
|
|
3
|
+
import type { TodoScope } from './notes.js';
|
|
2
4
|
import { type Repeat, type Task, type TodoList } from './todo-format.js';
|
|
3
|
-
import type
|
|
5
|
+
import { type Vault } from './vault.js';
|
|
4
6
|
export interface ListTodosArgs {
|
|
5
7
|
list?: string;
|
|
6
8
|
include_completed?: boolean;
|
|
@@ -39,20 +41,36 @@ export interface CreateTodoListArgs {
|
|
|
39
41
|
interface Loaded {
|
|
40
42
|
tasks: Task[];
|
|
41
43
|
lists: TodoList[];
|
|
44
|
+
/** Each shared list's workspace name, by list id. */
|
|
45
|
+
sharedIn: Map<string, string>;
|
|
46
|
+
/** The key version each shared row is under, by id. */
|
|
47
|
+
versions: Map<string, number>;
|
|
48
|
+
}
|
|
49
|
+
/** What reading and writing shared to-dos needs; without it only the person's own are seen. */
|
|
50
|
+
export interface SharedTodos {
|
|
51
|
+
scope: () => Promise<TodoScope>;
|
|
52
|
+
keyring: WorkspaceKeyring;
|
|
42
53
|
}
|
|
43
54
|
export declare class TodoService {
|
|
44
55
|
private readonly api;
|
|
45
56
|
private readonly vault;
|
|
46
57
|
/** The clock, for "today" and reminder checks. Tests pass a fixed one. */
|
|
47
58
|
private readonly now;
|
|
59
|
+
private readonly shared;
|
|
48
60
|
constructor(api: VirlowApi, vault: Vault,
|
|
49
61
|
/** The clock, for "today" and reminder checks. Tests pass a fixed one. */
|
|
50
|
-
now?: () => Date);
|
|
62
|
+
now?: () => Date, shared?: SharedTodos | null);
|
|
51
63
|
private today;
|
|
52
64
|
/** The key, or the vault's own "ask the user to unlock" error. */
|
|
53
65
|
private key;
|
|
54
66
|
private fetchAll;
|
|
55
67
|
private decrypt;
|
|
68
|
+
/**
|
|
69
|
+
* The key a row is under, or null to leave it out: a shared row whose
|
|
70
|
+
* workspace folder is not open to AI, or whose key does not open. A lock
|
|
71
|
+
* is not a row to skip; it propagates.
|
|
72
|
+
*/
|
|
73
|
+
private keyForRow;
|
|
56
74
|
load(): Promise<Loaded>;
|
|
57
75
|
/** A list by id or name (case-insensitive). Never guesses between two
|
|
58
76
|
* lists with one name, and never makes one up. */
|
|
@@ -66,7 +84,15 @@ export declare class TodoService {
|
|
|
66
84
|
private validDay;
|
|
67
85
|
private validRemind;
|
|
68
86
|
private encrypted;
|
|
87
|
+
/**
|
|
88
|
+
* Seals a task's text and details for where it lives: the account key for
|
|
89
|
+
* the person's own, the workspace's current key (never older than the row
|
|
90
|
+
* already is) for a shared one, with that version sent along.
|
|
91
|
+
*/
|
|
92
|
+
private seal;
|
|
69
93
|
private createTask;
|
|
94
|
+
/** My Day, Important and reminders are each person's own, so a shared task never carries them. */
|
|
95
|
+
private refusePersonal;
|
|
70
96
|
private channels;
|
|
71
97
|
/** Cancels the task's pending reminders. */
|
|
72
98
|
private clearReminders;
|
package/dist/cjs/todos.js
CHANGED
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.TodoService = void 0;
|
|
4
4
|
const virlow_crypto_1 = require("@batalabs/virlow-crypto");
|
|
5
|
+
const exposure_js_1 = require("./exposure.js");
|
|
5
6
|
const todo_format_js_1 = require("./todo-format.js");
|
|
7
|
+
const vault_js_1 = require("./vault.js");
|
|
6
8
|
/**
|
|
7
9
|
* The to-do list over the API, for the MCP tools.
|
|
8
10
|
*
|
|
@@ -14,6 +16,13 @@ const todo_format_js_1 = require("./todo-format.js");
|
|
|
14
16
|
*
|
|
15
17
|
* Nothing is cached: a to-do list is small, and the apps change it all the
|
|
16
18
|
* time, so every call reads the current state.
|
|
19
|
+
*
|
|
20
|
+
* A list shared with a workspace lives in the workspace's root folder, under
|
|
21
|
+
* the workspace key, with its tasks beside it. It is seen exactly when that
|
|
22
|
+
* folder is open to AI (the rule for the workspace's notes), and read and
|
|
23
|
+
* written with the workspace key. My Day, Important and reminders are each
|
|
24
|
+
* person's own, so they are never set on a shared task; moving a list or
|
|
25
|
+
* task in or out of a workspace is left to the apps.
|
|
17
26
|
*/
|
|
18
27
|
/** Smart list names as a tool takes them. */
|
|
19
28
|
const SMART_ALIASES = {
|
|
@@ -31,12 +40,14 @@ class TodoService {
|
|
|
31
40
|
api;
|
|
32
41
|
vault;
|
|
33
42
|
now;
|
|
43
|
+
shared;
|
|
34
44
|
constructor(api, vault,
|
|
35
45
|
/** The clock, for "today" and reminder checks. Tests pass a fixed one. */
|
|
36
|
-
now = () => new Date()) {
|
|
46
|
+
now = () => new Date(), shared = null) {
|
|
37
47
|
this.api = api;
|
|
38
48
|
this.vault = vault;
|
|
39
49
|
this.now = now;
|
|
50
|
+
this.shared = shared;
|
|
40
51
|
}
|
|
41
52
|
today() {
|
|
42
53
|
return (0, todo_format_js_1.dayKey)(this.now());
|
|
@@ -69,32 +80,85 @@ class TodoService {
|
|
|
69
80
|
return null;
|
|
70
81
|
}
|
|
71
82
|
}
|
|
83
|
+
/**
|
|
84
|
+
* The key a row is under, or null to leave it out: a shared row whose
|
|
85
|
+
* workspace folder is not open to AI, or whose key does not open. A lock
|
|
86
|
+
* is not a row to skip; it propagates.
|
|
87
|
+
*/
|
|
88
|
+
async keyForRow(accountKey, row, scope) {
|
|
89
|
+
if (!(0, exposure_js_1.isSharedNote)(row))
|
|
90
|
+
return { key: accountKey, workspaceId: null };
|
|
91
|
+
if (!this.shared || !scope || !row.folderId || !scope.allows(row.folderId))
|
|
92
|
+
return null;
|
|
93
|
+
const workspaceId = scope.workspaceOf(row.folderId);
|
|
94
|
+
// The row's own folder field and the folder list must agree on its
|
|
95
|
+
// workspace, as for notes; one that does not is not opened.
|
|
96
|
+
const sent = row.folder?.workspaceId;
|
|
97
|
+
if (!workspaceId || (sent !== undefined && sent !== workspaceId))
|
|
98
|
+
return null;
|
|
99
|
+
try {
|
|
100
|
+
return { key: await this.shared.keyring.forRead(accountKey, row.keyVersion, workspaceId), workspaceId };
|
|
101
|
+
}
|
|
102
|
+
catch (err) {
|
|
103
|
+
if (err instanceof vault_js_1.LockedError)
|
|
104
|
+
throw err;
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
72
108
|
async load() {
|
|
73
|
-
const
|
|
74
|
-
const [taskRows, listRows] = await Promise.all([
|
|
109
|
+
const accountKey = this.key();
|
|
110
|
+
const [taskRows, listRows, scope] = await Promise.all([
|
|
111
|
+
this.fetchAll(todo_format_js_1.TODO_NOTE_TYPE),
|
|
112
|
+
this.fetchAll(todo_format_js_1.TODO_LIST_NOTE_TYPE),
|
|
113
|
+
this.shared ? this.shared.scope() : Promise.resolve(null),
|
|
114
|
+
]);
|
|
115
|
+
const versions = new Map();
|
|
116
|
+
const open = async (row) => {
|
|
117
|
+
const found = await this.keyForRow(accountKey, row, scope);
|
|
118
|
+
if (!found)
|
|
119
|
+
return null;
|
|
120
|
+
const opened = await this.decrypt(found.key, row);
|
|
121
|
+
if (!opened)
|
|
122
|
+
return null;
|
|
123
|
+
if (found.workspaceId)
|
|
124
|
+
versions.set(row.id, row.keyVersion);
|
|
125
|
+
return { opened, workspaceId: found.workspaceId, folderId: found.workspaceId ? row.folderId : null };
|
|
126
|
+
};
|
|
75
127
|
const tasks = [];
|
|
76
128
|
for (const row of taskRows) {
|
|
77
|
-
const
|
|
78
|
-
if (!
|
|
129
|
+
const got = await open(row);
|
|
130
|
+
if (!got)
|
|
79
131
|
continue;
|
|
80
132
|
tasks.push({
|
|
81
133
|
id: row.id,
|
|
82
|
-
title: opened.title,
|
|
83
|
-
details: (0, todo_format_js_1.parseDetails)(opened.content),
|
|
134
|
+
title: got.opened.title,
|
|
135
|
+
details: (0, todo_format_js_1.parseDetails)(got.opened.content),
|
|
84
136
|
done: row.archived === true,
|
|
85
137
|
createdAt: row.createdAt,
|
|
86
138
|
updatedAt: row.updatedAt,
|
|
139
|
+
folderId: got.folderId,
|
|
140
|
+
workspaceId: got.workspaceId,
|
|
87
141
|
});
|
|
88
142
|
}
|
|
89
143
|
const lists = [];
|
|
144
|
+
const sharedIn = new Map();
|
|
90
145
|
for (const row of listRows) {
|
|
91
|
-
const
|
|
92
|
-
if (!
|
|
146
|
+
const got = await open(row);
|
|
147
|
+
if (!got)
|
|
93
148
|
continue;
|
|
94
|
-
lists.push({
|
|
149
|
+
lists.push({
|
|
150
|
+
id: row.id,
|
|
151
|
+
name: got.opened.title,
|
|
152
|
+
meta: (0, todo_format_js_1.parseListMeta)(got.opened.content),
|
|
153
|
+
createdAt: row.createdAt,
|
|
154
|
+
folderId: got.folderId,
|
|
155
|
+
workspaceId: got.workspaceId,
|
|
156
|
+
});
|
|
157
|
+
if (got.folderId && scope)
|
|
158
|
+
sharedIn.set(row.id, await scope.folderName(got.folderId));
|
|
95
159
|
}
|
|
96
160
|
lists.sort((a, b) => a.createdAt.localeCompare(b.createdAt));
|
|
97
|
-
return { tasks, lists };
|
|
161
|
+
return { tasks, lists, sharedIn, versions };
|
|
98
162
|
}
|
|
99
163
|
/** A list by id or name (case-insensitive). Never guesses between two
|
|
100
164
|
* lists with one name, and never makes one up. */
|
|
@@ -121,15 +185,19 @@ class TodoService {
|
|
|
121
185
|
return smart;
|
|
122
186
|
return (0, todo_format_js_1.listKey)(this.resolveList(lists, ref).id);
|
|
123
187
|
}
|
|
124
|
-
listName(lists, id) {
|
|
188
|
+
listName(lists, id, sharedIn) {
|
|
125
189
|
if (id === null)
|
|
126
190
|
return 'Tasks';
|
|
127
|
-
|
|
191
|
+
const list = lists.find((l) => l.id === id);
|
|
192
|
+
if (!list)
|
|
193
|
+
return 'Tasks';
|
|
194
|
+
const where = sharedIn?.get(list.id);
|
|
195
|
+
return where ? `${list.name} (shared in ${where})` : list.name;
|
|
128
196
|
}
|
|
129
|
-
describe(task, lists) {
|
|
197
|
+
describe(task, lists, sharedIn) {
|
|
130
198
|
const d = task.details;
|
|
131
199
|
const today = this.today();
|
|
132
|
-
const parts = [`list: ${this.listName(lists, d.list)}`];
|
|
200
|
+
const parts = [`list: ${this.listName(lists, d.list, sharedIn)}`];
|
|
133
201
|
if (d.due)
|
|
134
202
|
parts.push(`due ${d.due}${!task.done && d.due < today ? ' (overdue)' : ''}`);
|
|
135
203
|
if (d.myDay === today)
|
|
@@ -155,7 +223,7 @@ class TodoService {
|
|
|
155
223
|
return lines.join('\n');
|
|
156
224
|
}
|
|
157
225
|
async listTodos(args) {
|
|
158
|
-
const { tasks, lists } = await this.load();
|
|
226
|
+
const { tasks, lists, sharedIn } = await this.load();
|
|
159
227
|
const today = this.today();
|
|
160
228
|
const scope = this.scopeOf(lists, args.list);
|
|
161
229
|
const query = args.query?.trim().toLowerCase();
|
|
@@ -171,27 +239,33 @@ class TodoService {
|
|
|
171
239
|
.sort((a, b) => (b.details.completedAt ?? b.updatedAt).localeCompare(a.details.completedAt ?? a.updatedAt))
|
|
172
240
|
: [];
|
|
173
241
|
const shown = [...open.filter(matches), ...done.filter(matches)];
|
|
174
|
-
const where = scope ? this.scopeName(lists, scope) : 'every list';
|
|
242
|
+
const where = scope ? this.scopeName(lists, scope, sharedIn) : 'every list';
|
|
175
243
|
if (shown.length === 0) {
|
|
176
244
|
return query
|
|
177
245
|
? `No to-dos in ${where} match "${args.query}".`
|
|
178
246
|
: `No ${args.include_completed ? '' : 'open '}to-dos in ${where}.`;
|
|
179
247
|
}
|
|
180
248
|
const head = `${open.filter(matches).length} open${args.include_completed ? `, ${done.filter(matches).length} completed` : ''} in ${where} (today is ${today}):`;
|
|
181
|
-
return [head, ...shown.map((t) => this.describe(t, lists))].join('\n');
|
|
249
|
+
return [head, ...shown.map((t) => this.describe(t, lists, sharedIn))].join('\n');
|
|
182
250
|
}
|
|
183
|
-
scopeName(lists, scope) {
|
|
251
|
+
scopeName(lists, scope, sharedIn) {
|
|
184
252
|
const smart = todo_format_js_1.SMART_LISTS.find((s) => s.id === scope);
|
|
185
253
|
if (smart)
|
|
186
254
|
return smart.label;
|
|
187
|
-
return this.listName(lists, scope.slice(5));
|
|
255
|
+
return this.listName(lists, scope.slice(5), sharedIn);
|
|
188
256
|
}
|
|
189
257
|
async listLists() {
|
|
190
|
-
const { tasks, lists } = await this.load();
|
|
258
|
+
const { tasks, lists, sharedIn } = await this.load();
|
|
191
259
|
const today = this.today();
|
|
192
260
|
const lines = todo_format_js_1.SMART_LISTS.map((s) => `- ${s.label} (${s.id === 'myday' ? 'my_day' : s.id}): ${(0, todo_format_js_1.openTasks)(tasks, s.id, today).length} open`);
|
|
193
|
-
lines.push(...lists.map((l) =>
|
|
194
|
-
|
|
261
|
+
lines.push(...lists.map((l) => {
|
|
262
|
+
const where = sharedIn.get(l.id);
|
|
263
|
+
return `- ${l.meta.emoji ? `${l.meta.emoji} ` : ''}${l.name} (id: ${l.id}${where ? `, shared in ${where}` : ''}): ${(0, todo_format_js_1.openTasks)(tasks, (0, todo_format_js_1.listKey)(l.id), today).length} open`;
|
|
264
|
+
}));
|
|
265
|
+
const note = sharedIn.size
|
|
266
|
+
? ' A shared list is seen by everyone in its workspace; My Day, Important and reminders stay personal and are not set on its tasks.'
|
|
267
|
+
: '';
|
|
268
|
+
return [`Smart lists, then the person's lists (today is ${today}):${note}`, ...lines].join('\n');
|
|
195
269
|
}
|
|
196
270
|
// MARK: Writing
|
|
197
271
|
validDay(value, field) {
|
|
@@ -208,14 +282,40 @@ class TodoService {
|
|
|
208
282
|
throw new Error(`remind_at must be in the future, got ${value}.`);
|
|
209
283
|
return at;
|
|
210
284
|
}
|
|
211
|
-
async encrypted(title, content) {
|
|
212
|
-
const key = this.key();
|
|
285
|
+
async encrypted(title, content, key = this.key()) {
|
|
213
286
|
const salt = (0, virlow_crypto_1.bytesToBase64)(crypto.getRandomValues(new Uint8Array(32)));
|
|
214
287
|
const { encryptedTitle, encryptedContent, iv } = await (0, virlow_crypto_1.encryptNoteFields)(key, title, content);
|
|
215
288
|
return { title: '[ENCRYPTED]', content: '[ENCRYPTED]', encryptedTitle, encryptedContent, iv, salt };
|
|
216
289
|
}
|
|
217
|
-
|
|
218
|
-
|
|
290
|
+
/**
|
|
291
|
+
* Seals a task's text and details for where it lives: the account key for
|
|
292
|
+
* the person's own, the workspace's current key (never older than the row
|
|
293
|
+
* already is) for a shared one, with that version sent along.
|
|
294
|
+
*/
|
|
295
|
+
async seal(text, details, workspaceId, atLeast = null) {
|
|
296
|
+
if (!workspaceId)
|
|
297
|
+
return this.encrypted(text, (0, todo_format_js_1.serializeDetails)(details));
|
|
298
|
+
if (!this.shared)
|
|
299
|
+
throw new Error('This to-do is in a shared workspace, which this connection cannot write to.');
|
|
300
|
+
const choice = await this.shared.keyring.forWrite(this.key(), workspaceId, { atLeast });
|
|
301
|
+
if (choice.keyVersion === null)
|
|
302
|
+
throw new Error('A shared to-do needs its workspace key.');
|
|
303
|
+
return { ...(await this.encrypted(text, (0, todo_format_js_1.serializeDetails)(details), choice.key)), keyVersion: choice.keyVersion };
|
|
304
|
+
}
|
|
305
|
+
async createTask(text, details, where = { folderId: null, workspaceId: null }) {
|
|
306
|
+
return this.api.createNote({
|
|
307
|
+
...(await this.seal(text, details, where.workspaceId)),
|
|
308
|
+
type: todo_format_js_1.TODO_NOTE_TYPE,
|
|
309
|
+
folderId: where.workspaceId ? where.folderId : null,
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
/** My Day, Important and reminders are each person's own, so a shared task never carries them. */
|
|
313
|
+
refusePersonal(list, sharedIn, asked) {
|
|
314
|
+
if (asked.length === 0)
|
|
315
|
+
return;
|
|
316
|
+
const where = sharedIn.get(list.id) ?? 'a shared workspace';
|
|
317
|
+
throw new Error(`"${list.name}" is shared in ${where}, and ${asked.join(', ')} ${asked.length > 1 ? 'are' : 'is'} personal, ` +
|
|
318
|
+
'so it is not set on a shared task. Leave it out, or use one of the person\'s own lists.');
|
|
219
319
|
}
|
|
220
320
|
async channels() {
|
|
221
321
|
try {
|
|
@@ -246,11 +346,19 @@ class TodoService {
|
|
|
246
346
|
throw new Error(`repeat must be one of ${todo_format_js_1.REPEATS.join(', ')}.`);
|
|
247
347
|
}
|
|
248
348
|
const remindAt = args.remind_at !== undefined ? this.validRemind(args.remind_at) : null;
|
|
249
|
-
const { lists } = await this.load();
|
|
349
|
+
const { lists, sharedIn } = await this.load();
|
|
250
350
|
const today = this.today();
|
|
251
351
|
const details = (0, todo_format_js_1.parseDetails)('');
|
|
252
|
-
|
|
253
|
-
|
|
352
|
+
const list = args.list !== undefined && args.list.trim() !== '' ? this.resolveList(lists, args.list) : null;
|
|
353
|
+
if (list)
|
|
354
|
+
details.list = list.id;
|
|
355
|
+
if (list?.workspaceId) {
|
|
356
|
+
this.refusePersonal(list, sharedIn, [
|
|
357
|
+
...(args.my_day ? ['My Day'] : []),
|
|
358
|
+
...(args.important ? ['Important'] : []),
|
|
359
|
+
...(remindAt ? ['a reminder'] : []),
|
|
360
|
+
]);
|
|
361
|
+
}
|
|
254
362
|
if (args.due !== undefined)
|
|
255
363
|
details.due = this.validDay(args.due, 'due');
|
|
256
364
|
if (args.my_day)
|
|
@@ -268,17 +376,32 @@ class TodoService {
|
|
|
268
376
|
}
|
|
269
377
|
if (remindAt)
|
|
270
378
|
details.remindAt = remindAt.toISOString();
|
|
271
|
-
const
|
|
379
|
+
const where = { folderId: list?.folderId ?? null, workspaceId: list?.workspaceId ?? null };
|
|
380
|
+
const row = await this.createTask(text, details, where);
|
|
272
381
|
if (remindAt)
|
|
273
382
|
await this.createReminder(row.id, remindAt);
|
|
274
|
-
const task = { id: row.id, title: text, details, done: false, createdAt: row.createdAt, updatedAt: row.updatedAt };
|
|
275
|
-
return `Added to-do (id: ${row.id}).\n${this.describe(task, lists)}`;
|
|
383
|
+
const task = { id: row.id, title: text, details, done: false, createdAt: row.createdAt, updatedAt: row.updatedAt, ...where };
|
|
384
|
+
return `Added to-do (id: ${row.id}).\n${this.describe(task, lists, sharedIn)}`;
|
|
276
385
|
}
|
|
277
386
|
async updateTodo(args) {
|
|
278
|
-
const { tasks, lists } = await this.load();
|
|
387
|
+
const { tasks, lists, sharedIn, versions } = await this.load();
|
|
279
388
|
const task = tasks.find((t) => t.id === args.id);
|
|
280
389
|
if (!task)
|
|
281
390
|
throw new Error(`No to-do with id ${args.id}. Call list_todos to find it.`);
|
|
391
|
+
const workspaceId = task.workspaceId ?? null;
|
|
392
|
+
if (workspaceId) {
|
|
393
|
+
const list = lists.find((l) => l.id === task.details.list) ?? {
|
|
394
|
+
id: '',
|
|
395
|
+
name: 'This to-do',
|
|
396
|
+
meta: (0, todo_format_js_1.parseListMeta)(''),
|
|
397
|
+
createdAt: task.createdAt,
|
|
398
|
+
};
|
|
399
|
+
this.refusePersonal(list, sharedIn, [
|
|
400
|
+
...(args.my_day ? ['My Day'] : []),
|
|
401
|
+
...(args.important ? ['Important'] : []),
|
|
402
|
+
...(args.remind_at ? ['a reminder'] : []),
|
|
403
|
+
]);
|
|
404
|
+
}
|
|
282
405
|
const today = this.today();
|
|
283
406
|
const details = { ...task.details, steps: task.details.steps.map((s) => ({ ...s })) };
|
|
284
407
|
let text = task.title;
|
|
@@ -295,8 +418,17 @@ class TodoService {
|
|
|
295
418
|
details.important = args.important;
|
|
296
419
|
if (args.note !== undefined)
|
|
297
420
|
details.note = args.note;
|
|
298
|
-
if (args.list !== undefined)
|
|
299
|
-
|
|
421
|
+
if (args.list !== undefined) {
|
|
422
|
+
const target = args.list === null || args.list.trim() === '' ? null : this.resolveList(lists, args.list);
|
|
423
|
+
// A task stays on its side of a workspace: crossing changes its key
|
|
424
|
+
// and who can see it, which the apps do with the whole list.
|
|
425
|
+
if ((target?.workspaceId ?? null) !== workspaceId) {
|
|
426
|
+
throw new Error(workspaceId
|
|
427
|
+
? 'This to-do is in a shared list. It can move to another list in the same workspace, not to the person\'s own lists.'
|
|
428
|
+
: 'A to-do moves into a shared list only with its whole list, from the Virlow app (Share on the list).');
|
|
429
|
+
}
|
|
430
|
+
details.list = target?.id ?? null;
|
|
431
|
+
}
|
|
300
432
|
if (args.repeat !== undefined) {
|
|
301
433
|
if (args.repeat !== null && !todo_format_js_1.REPEATS.includes(args.repeat))
|
|
302
434
|
throw new Error(`repeat must be one of ${todo_format_js_1.REPEATS.join(', ')}.`);
|
|
@@ -330,11 +462,12 @@ class TodoService {
|
|
|
330
462
|
if (reopening)
|
|
331
463
|
details.completedAt = null;
|
|
332
464
|
const done = completing ? true : reopening ? false : task.done;
|
|
333
|
-
const body = await this.
|
|
465
|
+
const body = await this.seal(text, details, workspaceId, versions.get(task.id) ?? null);
|
|
334
466
|
if (completing || reopening)
|
|
335
467
|
body.archived = done;
|
|
336
468
|
await this.api.updateNote(task.id, body);
|
|
337
|
-
|
|
469
|
+
// A shared task has no reminders to change.
|
|
470
|
+
if (remindAt !== undefined && !workspaceId) {
|
|
338
471
|
await this.clearReminders(task.id);
|
|
339
472
|
if (remindAt)
|
|
340
473
|
await this.createReminder(task.id, remindAt);
|
|
@@ -342,20 +475,21 @@ class TodoService {
|
|
|
342
475
|
const lines = [];
|
|
343
476
|
if (completing) {
|
|
344
477
|
// A done task needs no reminder.
|
|
345
|
-
|
|
478
|
+
if (!workspaceId)
|
|
479
|
+
await this.clearReminders(task.id);
|
|
346
480
|
const next = (0, todo_format_js_1.nextRepeat)({ ...task, title: text, details }, today);
|
|
347
481
|
if (next) {
|
|
348
482
|
const at = next.remindAt ? new Date(next.remindAt) : null;
|
|
349
483
|
const future = at !== null && at.getTime() > this.now().getTime();
|
|
350
484
|
const nextDetails = { ...next, remindAt: future ? next.remindAt : null };
|
|
351
|
-
const row = await this.createTask(text, nextDetails);
|
|
485
|
+
const row = await this.createTask(text, nextDetails, { folderId: task.folderId ?? null, workspaceId });
|
|
352
486
|
if (future)
|
|
353
487
|
await this.createReminder(row.id, at);
|
|
354
488
|
lines.push(`It repeats ${next.repeat}: the next one (id: ${row.id}) is due ${next.due}.`);
|
|
355
489
|
}
|
|
356
490
|
}
|
|
357
491
|
const updated = { ...task, title: text, details, done };
|
|
358
|
-
return [`Updated to-do.`, this.describe(updated, lists), ...lines].join('\n');
|
|
492
|
+
return [`Updated to-do.`, this.describe(updated, lists, sharedIn), ...lines].join('\n');
|
|
359
493
|
}
|
|
360
494
|
async createList(args) {
|
|
361
495
|
const name = args.name?.trim();
|
package/dist/notes.d.ts
CHANGED
|
@@ -8,6 +8,24 @@ import { WorkspaceKeyring } from './keyring.js';
|
|
|
8
8
|
* `truncated` tells the caller when the account holds more than this. Also
|
|
9
9
|
* bounds listVisibleRows(), which backs mention-matching and backlinks(). */
|
|
10
10
|
export declare const SEARCH_SCAN_CAP = 500;
|
|
11
|
+
/**
|
|
12
|
+
* An Exposure plus a fingerprint of the folder list it was computed from.
|
|
13
|
+
*
|
|
14
|
+
* The fingerprint is what tells the paged row cache whether the rows it holds
|
|
15
|
+
* were filtered under the same folder settings the current call is asking
|
|
16
|
+
* about. It rides on the exposure object so it can never be paired with the
|
|
17
|
+
* wrong one: an instance field would be overwritten by any concurrent call
|
|
18
|
+
* that reached listFolders() second.
|
|
19
|
+
*/
|
|
20
|
+
/** What the to-do tools need to know about folders. See NotesService.todoScope. */
|
|
21
|
+
export interface TodoScope {
|
|
22
|
+
/** Whether the connector may see what is in this folder. */
|
|
23
|
+
allows(folderId: string): boolean;
|
|
24
|
+
/** The shared workspace a folder belongs to; null for a personal one. */
|
|
25
|
+
workspaceOf(folderId: string | null): string | null;
|
|
26
|
+
/** The folder's name as the person sees it. */
|
|
27
|
+
folderName(folderId: string): Promise<string>;
|
|
28
|
+
}
|
|
11
29
|
/** One property a setProperties() call actually changed, said the way the
|
|
12
30
|
* caller asked for it: the definition's name, and option names rather than
|
|
13
31
|
* the option ids stored in the note. A caller that had to read ids back to
|
|
@@ -290,6 +308,13 @@ export declare class NotesService {
|
|
|
290
308
|
}>;
|
|
291
309
|
withheld: number;
|
|
292
310
|
}>;
|
|
311
|
+
/**
|
|
312
|
+
* Where shared to-dos may come from, for the to-do tools: a shared list
|
|
313
|
+
* lives in its workspace's root folder, so it is open exactly when that
|
|
314
|
+
* folder is (the same rule as the workspace's notes), and is read and
|
|
315
|
+
* written under the workspace key. Computed fresh for each call.
|
|
316
|
+
*/
|
|
317
|
+
todoScope(): Promise<TodoScope>;
|
|
293
318
|
/** Folder exposure for this request. Not cached across calls: the user can
|
|
294
319
|
* flip the switch in the app at any moment and the next tool call must
|
|
295
320
|
* respect it. */
|
package/dist/notes.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"notes.d.ts","sourceRoot":"","sources":["../src/notes.ts"],"names":[],"mappings":"AAQA,OAAO,EAAkD,KAAK,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC9F,OAAO,EAgBL,KAAK,UAAU,EACf,KAAK,WAAW,EAChB,KAAK,cAAc,EAEnB,KAAK,QAAQ,EACb,KAAK,SAAS,EACf,MAAM,YAAY,CAAC;AAEpB,OAAO,KAAK,EAAiC,SAAS,EAAE,MAAM,UAAU,CAAC;AAEzE,OAAO,EAAe,KAAK,KAAK,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EAEL,gBAAgB,EAIjB,MAAM,cAAc,CAAC;AAEtB;;;6EAG6E;AAC7E,eAAO,MAAM,eAAe,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"notes.d.ts","sourceRoot":"","sources":["../src/notes.ts"],"names":[],"mappings":"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"}
|
package/dist/notes.js
CHANGED
|
@@ -846,6 +846,25 @@ export class NotesService {
|
|
|
846
846
|
}
|
|
847
847
|
return { folders, notes, withheld };
|
|
848
848
|
}
|
|
849
|
+
/**
|
|
850
|
+
* Where shared to-dos may come from, for the to-do tools: a shared list
|
|
851
|
+
* lives in its workspace's root folder, so it is open exactly when that
|
|
852
|
+
* folder is (the same rule as the workspace's notes), and is read and
|
|
853
|
+
* written under the workspace key. Computed fresh for each call.
|
|
854
|
+
*/
|
|
855
|
+
async todoScope() {
|
|
856
|
+
const { folders } = await this.api.listFolders();
|
|
857
|
+
const exposure = await this.exposureOf(folders);
|
|
858
|
+
const byId = new Map(folders.map((f) => [f.id, f]));
|
|
859
|
+
return {
|
|
860
|
+
allows: (folderId) => exposure.allows(folderId),
|
|
861
|
+
workspaceOf: (folderId) => exposure.workspaceOf(folderId),
|
|
862
|
+
folderName: async (folderId) => {
|
|
863
|
+
const folder = byId.get(folderId);
|
|
864
|
+
return folder ? this.folderName(this.vault.session.key, folder) : 'Shared workspace';
|
|
865
|
+
},
|
|
866
|
+
};
|
|
867
|
+
}
|
|
849
868
|
/** Folder exposure for this request. Not cached across calls: the user can
|
|
850
869
|
* flip the switch in the app at any moment and the next tool call must
|
|
851
870
|
* respect it. */
|