aiquila-mcp 0.4.15 → 0.4.16

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.
@@ -1,6 +1,10 @@
1
1
  // SPDX-License-Identifier: MIT
2
2
  import { z } from 'zod';
3
3
  import { executeOCC } from '../../client/aiquila.js';
4
+ /** Effort levels `occ aiquila:configure` accepts; each model takes a subset. */
5
+ const EFFORTS = ['low', 'medium', 'high', 'xhigh', 'max'];
6
+ /** Thinking modes; 'auto' follows the model's own default. */
7
+ const THINKING_MODES = ['auto', 'on', 'off'];
4
8
  /**
5
9
  * AIquila Internal Tools
6
10
  * Provides configuration and testing for AIquila OCC commands
@@ -66,15 +70,31 @@ export const configureTool = {
66
70
  idempotentHint: true,
67
71
  openWorldHint: false,
68
72
  },
69
- description: 'Configure AIquila settings (API key, model, tokens, timeout)',
73
+ description: 'Configure AIquila settings (API key, model, tokens, timeout, effort and thinking for chat and background tasks)',
70
74
  inputSchema: z.object({
71
75
  apiKey: z.string().optional().describe('Anthropic API key'),
72
76
  model: z
73
77
  .string()
74
78
  .optional()
75
- .describe("Claude model to use (e.g., 'claude-fable-5', 'claude-opus-5', 'claude-sonnet-5')"),
79
+ .describe("Claude model to use (e.g., 'claude-fable-5-1', 'claude-opus-5-5', 'claude-opus-5', 'claude-sonnet-5')"),
76
80
  maxTokens: z.number().optional().describe('Maximum tokens for responses (default: 4096)'),
77
81
  timeout: z.number().optional().describe('Request timeout in seconds (default: 60)'),
82
+ effort: z
83
+ .enum(['', ...EFFORTS])
84
+ .optional()
85
+ .describe('Default effort level; empty string resets to the model default'),
86
+ thinking: z
87
+ .enum(THINKING_MODES)
88
+ .optional()
89
+ .describe("Default thinking: 'auto' follows the model (Fable, Opus 5.x and Sonnet 5 think on their own), 'on' or 'off'. Fable and Opus 5.5 always think."),
90
+ taskEffort: z
91
+ .enum(['', ...EFFORTS])
92
+ .optional()
93
+ .describe('Effort for Assistant tasks and coworkers; empty string uses the default effort'),
94
+ taskThinking: z
95
+ .enum(['', ...THINKING_MODES])
96
+ .optional()
97
+ .describe('Thinking for Assistant tasks and coworkers; empty string uses the default thinking'),
78
98
  }),
79
99
  handler: async (args) => {
80
100
  try {
@@ -91,6 +111,19 @@ export const configureTool = {
91
111
  if (args.timeout) {
92
112
  configArgs.push('--timeout', args.timeout.toString());
93
113
  }
114
+ // Empty strings are meaningful here (reset), so test for undefined.
115
+ if (args.effort !== undefined) {
116
+ configArgs.push('--effort', args.effort);
117
+ }
118
+ if (args.thinking !== undefined) {
119
+ configArgs.push('--thinking', args.thinking);
120
+ }
121
+ if (args.taskEffort !== undefined) {
122
+ configArgs.push('--task-effort', args.taskEffort);
123
+ }
124
+ if (args.taskThinking !== undefined) {
125
+ configArgs.push('--task-thinking', args.taskThinking);
126
+ }
94
127
  const output = await runOCC('aiquila:configure', configArgs);
95
128
  return {
96
129
  content: [
@@ -203,7 +203,7 @@ function collectAlarmMinutes(alarm, alarms) {
203
203
  /**
204
204
  * Parse calendar collections from a PROPFIND response.
205
205
  */
206
- function parseCalendars(responseXml) {
206
+ export function parseCalendars(responseXml) {
207
207
  const calendars = [];
208
208
  const responseBlocks = responseXml.match(/<d:response>[\s\S]*?<\/d:response>/g);
209
209
  if (!responseBlocks)
@@ -3,6 +3,7 @@ import { z } from 'zod';
3
3
  import { decodeXmlEntities, encodeXmlEntities, fetchCalDAV, nsTagContent, } from '../../client/caldav.js';
4
4
  import { escapeICalValue } from '../dav-utils.js';
5
5
  import { getNextcloudConfig } from '../types.js';
6
+ import { parseCalendars } from './calendar.js';
6
7
  // ---------------------------------------------------------------------------
7
8
  // iCalendar helpers
8
9
  // ---------------------------------------------------------------------------
@@ -221,6 +222,33 @@ function formatTask(task) {
221
222
  line += `\n UID: ${task.uid}`;
222
223
  return line;
223
224
  }
225
+ /**
226
+ * Format a task list (VTODO-capable calendar) for human-readable display.
227
+ * `calendarName` is the URL slug the other task tools expect.
228
+ */
229
+ function formatTaskList(cal, detailed = false) {
230
+ const slug = cal.url.split('/').filter(Boolean).pop() ?? '';
231
+ let line = decodeXmlEntities(cal.displayName);
232
+ if (cal.color)
233
+ line += ` [${cal.color}]`;
234
+ if (!cal.enabled)
235
+ line += ' (disabled)';
236
+ line += `\n calendarName: ${slug}`;
237
+ line += `\n URL: ${cal.url}`;
238
+ if (detailed) {
239
+ const parts = [];
240
+ if (cal.supportsEvents)
241
+ parts.push('events');
242
+ if (cal.supportsTasks)
243
+ parts.push('tasks');
244
+ if (cal.supportsJournals)
245
+ parts.push('journals');
246
+ line += `\n Supports: ${parts.join(', ')}`;
247
+ if (cal.ctag)
248
+ line += `\n CTag: ${decodeXmlEntities(cal.ctag)}`;
249
+ }
250
+ return line;
251
+ }
224
252
  // ---------------------------------------------------------------------------
225
253
  // CalDAV helpers
226
254
  // ---------------------------------------------------------------------------
@@ -285,36 +313,67 @@ export const listTaskListsTool = {
285
313
  idempotentHint: true,
286
314
  openWorldHint: false,
287
315
  },
288
- description: 'List all task lists in Nextcloud Tasks',
289
- inputSchema: z.object({}),
290
- handler: async () => {
291
- const config = getNextcloudConfig();
292
- const calDavUrl = `${config.url}/remote.php/dav/calendars/${config.user}/`;
293
- const propfindBody = `<?xml version="1.0" encoding="UTF-8"?>
294
- <d:propfind xmlns:d="DAV:" xmlns:cs="http://calendarserver.org/ns/" xmlns:c="urn:ietf:params:xml:ns:caldav">
316
+ description: "List all task lists in Nextcloud Tasks (calendars that support tasks). Returns each list's display name, color, URL and calendarName (the value to pass to the other task tools). Set detailed for supported component types and the CTag.",
317
+ inputSchema: z.object({
318
+ detailed: z
319
+ .boolean()
320
+ .optional()
321
+ .describe('Also include the component types each list supports (events, tasks, journals) and its CTag sync token (default false)'),
322
+ }),
323
+ handler: async (args = {}) => {
324
+ try {
325
+ const config = getNextcloudConfig();
326
+ const calDavUrl = `${config.url}/remote.php/dav/calendars/${config.user}/`;
327
+ const propfindBody = `<?xml version="1.0" encoding="UTF-8"?>
328
+ <d:propfind xmlns:d="DAV:" xmlns:cs="http://calendarserver.org/ns/" xmlns:c="urn:ietf:params:xml:ns:caldav" xmlns:x1="http://apple.com/ns/ical/" xmlns:x2="http://owncloud.org/ns">
295
329
  <d:prop>
296
330
  <d:resourcetype />
297
331
  <d:displayname />
298
332
  <cs:getctag />
333
+ <x1:calendar-color />
334
+ <x1:calendar-order />
335
+ <x2:calendar-enabled />
299
336
  <c:supported-calendar-component-set />
300
337
  </d:prop>
301
338
  </d:propfind>`;
302
- const response = await fetchCalDAV(calDavUrl, {
303
- method: 'PROPFIND',
304
- body: propfindBody,
305
- headers: {
306
- Depth: '1',
307
- },
308
- });
309
- const responseText = await response.text();
310
- return {
311
- content: [
312
- {
313
- type: 'text',
314
- text: responseText,
315
- },
316
- ],
317
- };
339
+ const response = await fetchCalDAV(calDavUrl, {
340
+ method: 'PROPFIND',
341
+ body: propfindBody,
342
+ headers: { Depth: '1' },
343
+ });
344
+ if (!response.ok) {
345
+ const errorText = await response.text();
346
+ throw new Error(`CalDAV PROPFIND failed: ${response.status} - ${errorText}`);
347
+ }
348
+ const taskLists = parseCalendars(await response.text())
349
+ .filter((cal) => cal.supportsTasks)
350
+ .sort((a, b) => (a.order ?? Infinity) - (b.order ?? Infinity));
351
+ if (taskLists.length === 0) {
352
+ return {
353
+ content: [{ type: 'text', text: 'No task lists found.' }],
354
+ };
355
+ }
356
+ const formatted = taskLists.map((cal) => formatTaskList(cal, args.detailed)).join('\n\n');
357
+ return {
358
+ content: [
359
+ {
360
+ type: 'text',
361
+ text: `Task lists (${taskLists.length} found):\n\n${formatted}`,
362
+ },
363
+ ],
364
+ };
365
+ }
366
+ catch (error) {
367
+ return {
368
+ content: [
369
+ {
370
+ type: 'text',
371
+ text: `Error listing task lists: ${error instanceof Error ? error.message : String(error)}`,
372
+ },
373
+ ],
374
+ isError: true,
375
+ };
376
+ }
318
377
  },
319
378
  };
320
379
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aiquila-mcp",
3
- "version": "0.4.15",
3
+ "version": "0.4.16",
4
4
  "description": "Nextcloud MCP server — 342 tools: files, calendar, contacts, mail, Talk, Deck, photos, maps, notes, fediverse",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",