@zhin.js/plugin-calendar 0.1.1 → 0.1.2
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/CHANGELOG.md +14 -0
- package/lib/caldav.d.ts +4 -4
- package/lib/caldav.d.ts.map +1 -1
- package/lib/caldav.js +74 -9
- package/lib/caldav.js.map +1 -1
- package/lib/chat-auth.d.ts.map +1 -1
- package/lib/chat-auth.js +16 -2
- package/lib/chat-auth.js.map +1 -1
- package/package.json +9 -17
- package/plugin.js +2 -3
- package/skills/calendar-scheduling/tools/create_event/index.js +7 -7
- package/skills/calendar-scheduling/tools/create_event/index.ts +10 -7
- package/src/caldav.ts +74 -9
- package/src/chat-auth.ts +18 -2
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# @zhin.js/plugin-calendar
|
|
2
|
+
|
|
3
|
+
## 0.1.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- a3a7b53: Authorize Google / Outlook calendars from chat: master-only `calendar auth|status|logout` commands, OAuth callback route on the zhin HTTP host, refresh tokens stored in the plugin database (env `refresh_token` stays as fallback), clear re-auth prompts and a one-time notification on `invalid_grant`. The auth CLI ships as the optional `zhin-calendar-auth` bin.
|
|
8
|
+
- a3a7b53: Add `@zhin.js/plugin-calendar` with CalDAV / Google / Microsoft backends and Agent tools `list_events`, `find_free_time`, `create_event` plus skill `calendar-scheduling`.
|
|
9
|
+
- a3a7b53: Google/Microsoft calendar OAuth refresh_token flow, token manager, and auth CLI.
|
|
10
|
+
- Updated dependencies [4778587]
|
|
11
|
+
- Updated dependencies [681abf3]
|
|
12
|
+
- @zhin.js/host-http@1.1.5
|
|
13
|
+
- @zhin.js/skill@1.1.5
|
|
14
|
+
- @zhin.js/tool@1.1.5
|
package/lib/caldav.d.ts
CHANGED
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Minimal CalDAV client (RFC 4791) for listing and creating VEVENTs.
|
|
3
|
-
* Works with iCloud, Fastmail and Nextcloud calendars.
|
|
4
|
-
*/
|
|
5
1
|
import type { CalendarEvent, CalendarProvider } from "./types.js";
|
|
6
2
|
export interface CalDavOptions {
|
|
7
3
|
readonly calendarUrl: string;
|
|
@@ -11,6 +7,10 @@ export interface CalDavOptions {
|
|
|
11
7
|
readonly fetchImpl?: typeof fetch;
|
|
12
8
|
}
|
|
13
9
|
declare function escapeXml(value: string): string;
|
|
10
|
+
/** Returns the text content of every `<href>` element (any namespace prefix). */
|
|
11
|
+
export declare function extractHrefs(xml: string): string[];
|
|
12
|
+
/** Returns the body between each BEGIN:VEVENT / END:VEVENT pair. */
|
|
13
|
+
export declare function extractVeventBlocks(text: string): string[];
|
|
14
14
|
/** Parses VEVENT components from a CalDAV multistatus response. */
|
|
15
15
|
export declare function parseCalDavEvents(xml: string, timezone: string): CalendarEvent[];
|
|
16
16
|
export declare function createCalDavProvider(options: CalDavOptions): CalendarProvider;
|
package/lib/caldav.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"caldav.d.ts","sourceRoot":"","sources":["../src/caldav.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"caldav.d.ts","sourceRoot":"","sources":["../src/caldav.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACV,aAAa,EACb,gBAAgB,EAEjB,MAAM,YAAY,CAAC;AAGpB,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;CACnC;AAMD,iBAAS,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAMxC;AAuCD,iFAAiF;AACjF,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CA4BlD;AAkBD,oEAAoE;AACpE,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAmB1D;AAED,mEAAmE;AACnE,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,MAAM,GACf,aAAa,EAAE,CAwBjB;AAgCD,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,aAAa,GAAG,gBAAgB,CA8D7E;AAED,OAAO,EAAE,SAAS,EAAE,CAAC"}
|
package/lib/caldav.js
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal CalDAV client (RFC 4791) for listing and creating VEVENTs.
|
|
3
|
+
* Works with iCloud, Fastmail and Nextcloud calendars.
|
|
4
|
+
*/
|
|
5
|
+
import { randomUUID } from "node:crypto";
|
|
1
6
|
import { formatInZone } from "./time.js";
|
|
2
7
|
function basicAuth(username, password) {
|
|
3
8
|
return `Basic ${Buffer.from(`${username}:${password}`).toString("base64")}`;
|
|
@@ -40,15 +45,77 @@ function extractField(block, name) {
|
|
|
40
45
|
? match[1].trim().replace(/\\n/g, "\n").replace(/\\,/g, ",")
|
|
41
46
|
: undefined;
|
|
42
47
|
}
|
|
48
|
+
/** Returns the text content of every `<href>` element (any namespace prefix). */
|
|
49
|
+
export function extractHrefs(xml) {
|
|
50
|
+
const hrefs = [];
|
|
51
|
+
let cursor = 0;
|
|
52
|
+
while (cursor < xml.length) {
|
|
53
|
+
const tagStart = xml.indexOf("<", cursor);
|
|
54
|
+
if (tagStart === -1) {
|
|
55
|
+
break;
|
|
56
|
+
}
|
|
57
|
+
const tagEnd = xml.indexOf(">", tagStart);
|
|
58
|
+
if (tagEnd === -1) {
|
|
59
|
+
break;
|
|
60
|
+
}
|
|
61
|
+
const tagName = readTagName(xml.slice(tagStart + 1, tagEnd));
|
|
62
|
+
cursor = tagEnd + 1;
|
|
63
|
+
if (localName(tagName) !== "href") {
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
const closingStart = xml.indexOf("</", cursor);
|
|
67
|
+
if (closingStart === -1) {
|
|
68
|
+
break;
|
|
69
|
+
}
|
|
70
|
+
const value = xml.slice(cursor, closingStart).trim();
|
|
71
|
+
if (value) {
|
|
72
|
+
hrefs.push(value);
|
|
73
|
+
}
|
|
74
|
+
cursor = closingStart;
|
|
75
|
+
}
|
|
76
|
+
return hrefs;
|
|
77
|
+
}
|
|
78
|
+
function readTagName(tagContent) {
|
|
79
|
+
if (tagContent.startsWith("/") || tagContent.startsWith("?")) {
|
|
80
|
+
return "";
|
|
81
|
+
}
|
|
82
|
+
let end = 0;
|
|
83
|
+
while (end < tagContent.length && !/[\s/]/.test(tagContent[end])) {
|
|
84
|
+
end += 1;
|
|
85
|
+
}
|
|
86
|
+
return tagContent.slice(0, end);
|
|
87
|
+
}
|
|
88
|
+
function localName(tagName) {
|
|
89
|
+
const colonIndex = tagName.lastIndexOf(":");
|
|
90
|
+
return tagName.slice(colonIndex + 1).toLowerCase();
|
|
91
|
+
}
|
|
92
|
+
/** Returns the body between each BEGIN:VEVENT / END:VEVENT pair. */
|
|
93
|
+
export function extractVeventBlocks(text) {
|
|
94
|
+
const beginMarker = "BEGIN:VEVENT";
|
|
95
|
+
const endMarker = "END:VEVENT";
|
|
96
|
+
const blocks = [];
|
|
97
|
+
let cursor = 0;
|
|
98
|
+
while (cursor < text.length) {
|
|
99
|
+
const begin = text.indexOf(beginMarker, cursor);
|
|
100
|
+
if (begin === -1) {
|
|
101
|
+
break;
|
|
102
|
+
}
|
|
103
|
+
const bodyStart = begin + beginMarker.length;
|
|
104
|
+
const end = text.indexOf(endMarker, bodyStart);
|
|
105
|
+
if (end === -1) {
|
|
106
|
+
break;
|
|
107
|
+
}
|
|
108
|
+
blocks.push(text.slice(bodyStart, end));
|
|
109
|
+
cursor = end + endMarker.length;
|
|
110
|
+
}
|
|
111
|
+
return blocks;
|
|
112
|
+
}
|
|
43
113
|
/** Parses VEVENT components from a CalDAV multistatus response. */
|
|
44
114
|
export function parseCalDavEvents(xml, timezone) {
|
|
45
115
|
const events = [];
|
|
46
|
-
const hrefs =
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
const calendars = [...xml.matchAll(/BEGIN:VEVENT([\s\S]*?)END:VEVENT/g)];
|
|
50
|
-
calendars.forEach((match, index) => {
|
|
51
|
-
const block = match[1];
|
|
116
|
+
const hrefs = extractHrefs(xml);
|
|
117
|
+
const blocks = extractVeventBlocks(xml);
|
|
118
|
+
blocks.forEach((block, index) => {
|
|
52
119
|
const uid = extractField(block, "UID") ?? hrefs[index] ?? `event-${index}`;
|
|
53
120
|
const summary = extractField(block, "SUMMARY") ?? "(无标题)";
|
|
54
121
|
const startRaw = extractField(block, "DTSTART");
|
|
@@ -134,9 +201,7 @@ export function createCalDavProvider(options) {
|
|
|
134
201
|
return parseCalDavEvents(await response.text(), options.timezone);
|
|
135
202
|
},
|
|
136
203
|
async createEvent(input, signal) {
|
|
137
|
-
const uid = `${
|
|
138
|
-
.toString(36)
|
|
139
|
-
.slice(2, 10)}@zhin`;
|
|
204
|
+
const uid = `${randomUUID()}@zhin`;
|
|
140
205
|
const url = new URL(`${uid}.ics`, base).toString();
|
|
141
206
|
const response = await fetchImpl(url, {
|
|
142
207
|
method: "PUT",
|
package/lib/caldav.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"caldav.js","sourceRoot":"","sources":["../src/caldav.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"caldav.js","sourceRoot":"","sources":["../src/caldav.ts"],"names":[],"mappings":"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"}
|
package/lib/chat-auth.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chat-auth.d.ts","sourceRoot":"","sources":["../src/chat-auth.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,KAAK,EACV,uBAAuB,EACvB,eAAe,EAChB,MAAM,uBAAuB,CAAC;AAS/B,OAAO,EAEL,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,EACvB,MAAM,oBAAoB,CAAC;AAE5B,eAAO,MAAM,2BAA2B,6BAA6B,CAAC;AAEtE,eAAO,MAAM,eAAe,EAAE,SAAS,iBAAiB,EAGvD,CAAC;AAEF,MAAM,MAAM,gBAAgB,CAAC,MAAM,IAAI,CACrC,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,KACT,OAAO,CAAC,IAAI,CAAC,CAAC;AAEnB,MAAM,WAAW,0BAA0B,CAAC,MAAM;IAChD,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC;IAChC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,iBAAiB,EAAE,iBAAiB,CAAC,CAAC,CAAC;IACzE,QAAQ,CAAC,WAAW,EAAE,uBAAuB,GAAG,SAAS,CAAC;IAC1D,QAAQ,CAAC,MAAM,EAAE,gBAAgB,CAAC,MAAM,CAAC,GAAG,SAAS,CAAC;IACtD,kFAAkF;IAClF,QAAQ,CAAC,kBAAkB,EAAE,MAAM,MAAM,GAAG,SAAS,CAAC;IACtD,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IAClC,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAaD,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,OAAO,GACb,iBAAiB,GAAG,SAAS,CAW/B;
|
|
1
|
+
{"version":3,"file":"chat-auth.d.ts","sourceRoot":"","sources":["../src/chat-auth.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,KAAK,EACV,uBAAuB,EACvB,eAAe,EAChB,MAAM,uBAAuB,CAAC;AAS/B,OAAO,EAEL,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,EACvB,MAAM,oBAAoB,CAAC;AAE5B,eAAO,MAAM,2BAA2B,6BAA6B,CAAC;AAEtE,eAAO,MAAM,eAAe,EAAE,SAAS,iBAAiB,EAGvD,CAAC;AAEF,MAAM,MAAM,gBAAgB,CAAC,MAAM,IAAI,CACrC,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,KACT,OAAO,CAAC,IAAI,CAAC,CAAC;AAEnB,MAAM,WAAW,0BAA0B,CAAC,MAAM;IAChD,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC;IAChC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,iBAAiB,EAAE,iBAAiB,CAAC,CAAC,CAAC;IACzE,QAAQ,CAAC,WAAW,EAAE,uBAAuB,GAAG,SAAS,CAAC;IAC1D,QAAQ,CAAC,MAAM,EAAE,gBAAgB,CAAC,MAAM,CAAC,GAAG,SAAS,CAAC;IACtD,kFAAkF;IAClF,QAAQ,CAAC,kBAAkB,EAAE,MAAM,MAAM,GAAG,SAAS,CAAC;IACtD,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IAClC,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAaD,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,OAAO,GACb,iBAAiB,GAAG,SAAS,CAW/B;AAkBD,gFAAgF;AAChF,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,MAAM,GACnB,MAAM,CAIR;AAED,uEAAuE;AACvE,wBAAgB,sBAAsB,CAAC,OAAO,EAAE;IAC9C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB,GAAG,MAAM,CAMT;AAED,qBAAa,mBAAmB,CAAC,MAAM;;gBASzB,OAAO,EAAE,0BAA0B,CAAC,MAAM,CAAC;IAUvD,qEAAqE;IAC/D,kBAAkB,CACtB,QAAQ,EAAE,iBAAiB,EAC3B,SAAS,EAAE,eAAe,CAAC,MAAM,CAAC,GACjC,OAAO,CAAC,MAAM,CAAC;IA0ClB,wDAAwD;IAClD,cAAc,CAAC,YAAY,EAAE,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC;IAwE5E,iCAAiC;IAC3B,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC;IAQvC,sEAAsE;IAChE,MAAM,CAAC,QAAQ,EAAE,iBAAiB,GAAG,OAAO,CAAC,MAAM,CAAC;IAU1D,2EAA2E;IACrE,uBAAuB,CAC3B,QAAQ,EAAE,iBAAiB,EAC3B,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,IAAI,CAAC;CAwEjB"}
|
package/lib/chat-auth.js
CHANGED
|
@@ -23,10 +23,24 @@ export function parseOAuthProvider(value) {
|
|
|
23
23
|
}
|
|
24
24
|
return undefined;
|
|
25
25
|
}
|
|
26
|
+
function trimTrailingSlashes(value) {
|
|
27
|
+
let end = value.length;
|
|
28
|
+
while (end > 0 && value[end - 1] === "/") {
|
|
29
|
+
end -= 1;
|
|
30
|
+
}
|
|
31
|
+
return value.slice(0, end);
|
|
32
|
+
}
|
|
33
|
+
function trimLeadingSlashes(value) {
|
|
34
|
+
let start = 0;
|
|
35
|
+
while (start < value.length && value[start] === "/") {
|
|
36
|
+
start += 1;
|
|
37
|
+
}
|
|
38
|
+
return value.slice(start);
|
|
39
|
+
}
|
|
26
40
|
/** Joins a base URL and the callback path, tolerating extra/missing slashes. */
|
|
27
41
|
export function buildRedirectUri(baseUrl, callbackPath) {
|
|
28
|
-
const trimmedBase = baseUrl.trim()
|
|
29
|
-
const normalizedPath = `/${callbackPath.trim()
|
|
42
|
+
const trimmedBase = trimTrailingSlashes(baseUrl.trim());
|
|
43
|
+
const normalizedPath = `/${trimLeadingSlashes(callbackPath.trim())}`;
|
|
30
44
|
return `${trimmedBase}${normalizedPath}`;
|
|
31
45
|
}
|
|
32
46
|
/** Turns a listening address into a browser-reachable local origin. */
|
package/lib/chat-auth.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chat-auth.js","sourceRoot":"","sources":["../src/chat-auth.ts"],"names":[],"mappings":"AAUA,OAAO,EACL,iBAAiB,EACjB,gBAAgB,EAChB,cAAc,EACd,yBAAyB,GAC1B,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAChF,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EACL,cAAc,GAGf,MAAM,oBAAoB,CAAC;AAE5B,MAAM,CAAC,MAAM,2BAA2B,GAAG,0BAA0B,CAAC;AAEtE,MAAM,CAAC,MAAM,eAAe,GAAiC;IAC3D,QAAQ;IACR,WAAW;CACZ,CAAC;AA6BF,MAAM,qBAAqB,GAAsC;IAC/D,MAAM,EAAE,WAAW;IACnB,SAAS,EAAE,YAAY;CACxB,CAAC;AAEF,MAAM,UAAU,kBAAkB,CAChC,KAAc;IAEd,MAAM,UAAU,GAAG,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC;SACnC,IAAI,EAAE;SACN,WAAW,EAAE,CAAC;IACjB,IAAI,UAAU,KAAK,QAAQ,EAAE,CAAC;QAC5B,OAAO,QAAQ,CAAC;IAClB,CAAC;IACD,IAAI,UAAU,KAAK,WAAW,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;QAC3D,OAAO,WAAW,CAAC;IACrB,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,
|
|
1
|
+
{"version":3,"file":"chat-auth.js","sourceRoot":"","sources":["../src/chat-auth.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zhin.js/plugin-calendar",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "CalDAV / Google / Microsoft calendar tools for Zhin Agent",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./lib/index.js",
|
|
@@ -39,35 +39,27 @@
|
|
|
39
39
|
"url": "https://github.com/lc-cn"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@zhin.js/host-http": "1.1.
|
|
43
|
-
"@zhin.js/
|
|
42
|
+
"@zhin.js/host-http": "1.1.5",
|
|
43
|
+
"@zhin.js/skill": "1.1.5",
|
|
44
|
+
"@zhin.js/im-contract": "1.1.3",
|
|
45
|
+
"@zhin.js/tool": "1.1.5"
|
|
44
46
|
},
|
|
45
47
|
"devDependencies": {
|
|
46
48
|
"typescript": "^6.0.3",
|
|
47
49
|
"vitest": "^4.1.10",
|
|
48
50
|
"zod": "^4.4.3",
|
|
49
|
-
"@zhin.js/command": "1.1.
|
|
50
|
-
"
|
|
51
|
-
"@zhin.js/tool": "1.1.4",
|
|
52
|
-
"zhin.js": "1.1.7"
|
|
51
|
+
"@zhin.js/command": "1.1.6",
|
|
52
|
+
"zhin.js": "1.1.8"
|
|
53
53
|
},
|
|
54
54
|
"peerDependencies": {
|
|
55
55
|
"zod": "^4.0.0",
|
|
56
|
-
"@zhin.js/
|
|
57
|
-
"
|
|
58
|
-
"@zhin.js/tool": "^1.1.4",
|
|
59
|
-
"zhin.js": "^1.1.7"
|
|
56
|
+
"@zhin.js/command": "^1.1.6",
|
|
57
|
+
"zhin.js": "^1.1.8"
|
|
60
58
|
},
|
|
61
59
|
"peerDependenciesMeta": {
|
|
62
60
|
"@zhin.js/command": {
|
|
63
61
|
"optional": true
|
|
64
62
|
},
|
|
65
|
-
"@zhin.js/skill": {
|
|
66
|
-
"optional": true
|
|
67
|
-
},
|
|
68
|
-
"@zhin.js/tool": {
|
|
69
|
-
"optional": true
|
|
70
|
-
},
|
|
71
63
|
"zod": {
|
|
72
64
|
"optional": true
|
|
73
65
|
}
|
package/plugin.js
CHANGED
|
@@ -41,12 +41,11 @@ export default definePlugin({
|
|
|
41
41
|
}
|
|
42
42
|
return buildRedirectUri(localOriginFromAddress(address), callbackPath);
|
|
43
43
|
};
|
|
44
|
-
let auth;
|
|
45
44
|
const managers = createOAuthTokenManagers(config, {
|
|
46
45
|
credentials,
|
|
47
|
-
onAuthorizationLost: (provider, message) => auth
|
|
46
|
+
onAuthorizationLost: (provider, message) => auth.notifyAuthorizationLost(provider, message),
|
|
48
47
|
});
|
|
49
|
-
auth = new CalendarAuthService({
|
|
48
|
+
const auth = new CalendarAuthService({
|
|
50
49
|
config,
|
|
51
50
|
managers,
|
|
52
51
|
credentials,
|
|
@@ -18,19 +18,19 @@ export default defineAgentTool({
|
|
|
18
18
|
description: z.string().max(2000).optional(),
|
|
19
19
|
all_day: z.boolean().optional(),
|
|
20
20
|
}),
|
|
21
|
-
async execute(
|
|
21
|
+
async execute({ title, start, end, location, description, all_day }, context) {
|
|
22
22
|
return runCalendarTool(async () => {
|
|
23
23
|
const runtime = context.use(calendarRuntimeToken);
|
|
24
24
|
if (!runtime.provider)
|
|
25
25
|
return "日历未启用:请先配置 provider 与凭据";
|
|
26
26
|
const timezone = runtime.config.timezone;
|
|
27
27
|
const event = await runtime.provider.createEvent({
|
|
28
|
-
title
|
|
29
|
-
start: parseDateTimeInZone(
|
|
30
|
-
end: parseDateTimeInZone(
|
|
31
|
-
location
|
|
32
|
-
description
|
|
33
|
-
all_day
|
|
28
|
+
title,
|
|
29
|
+
start: parseDateTimeInZone(start, timezone),
|
|
30
|
+
end: parseDateTimeInZone(end, timezone),
|
|
31
|
+
location,
|
|
32
|
+
description,
|
|
33
|
+
all_day,
|
|
34
34
|
}, context.signal);
|
|
35
35
|
return `已创建事件 [${event.id}]\n${event.title}\n${event.start} → ${event.end}(${timezone})`;
|
|
36
36
|
});
|
|
@@ -19,19 +19,22 @@ export default defineAgentTool({
|
|
|
19
19
|
description: z.string().max(2000).optional(),
|
|
20
20
|
all_day: z.boolean().optional(),
|
|
21
21
|
}),
|
|
22
|
-
async execute(
|
|
22
|
+
async execute(
|
|
23
|
+
{ title, start, end, location, description, all_day },
|
|
24
|
+
context
|
|
25
|
+
) {
|
|
23
26
|
return runCalendarTool(async () => {
|
|
24
27
|
const runtime = context.use(calendarRuntimeToken);
|
|
25
28
|
if (!runtime.provider) return "日历未启用:请先配置 provider 与凭据";
|
|
26
29
|
const timezone = runtime.config.timezone;
|
|
27
30
|
const event = await runtime.provider.createEvent(
|
|
28
31
|
{
|
|
29
|
-
title
|
|
30
|
-
start: parseDateTimeInZone(
|
|
31
|
-
end: parseDateTimeInZone(
|
|
32
|
-
location
|
|
33
|
-
description
|
|
34
|
-
all_day
|
|
32
|
+
title,
|
|
33
|
+
start: parseDateTimeInZone(start, timezone),
|
|
34
|
+
end: parseDateTimeInZone(end, timezone),
|
|
35
|
+
location,
|
|
36
|
+
description,
|
|
37
|
+
all_day,
|
|
35
38
|
},
|
|
36
39
|
context.signal
|
|
37
40
|
);
|
package/src/caldav.ts
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* Minimal CalDAV client (RFC 4791) for listing and creating VEVENTs.
|
|
3
3
|
* Works with iCloud, Fastmail and Nextcloud calendars.
|
|
4
4
|
*/
|
|
5
|
+
import { randomUUID } from "node:crypto";
|
|
5
6
|
import type {
|
|
6
7
|
CalendarEvent,
|
|
7
8
|
CalendarProvider,
|
|
@@ -66,18 +67,84 @@ function extractField(block: string, name: string): string | undefined {
|
|
|
66
67
|
: undefined;
|
|
67
68
|
}
|
|
68
69
|
|
|
70
|
+
/** Returns the text content of every `<href>` element (any namespace prefix). */
|
|
71
|
+
export function extractHrefs(xml: string): string[] {
|
|
72
|
+
const hrefs: string[] = [];
|
|
73
|
+
let cursor = 0;
|
|
74
|
+
while (cursor < xml.length) {
|
|
75
|
+
const tagStart = xml.indexOf("<", cursor);
|
|
76
|
+
if (tagStart === -1) {
|
|
77
|
+
break;
|
|
78
|
+
}
|
|
79
|
+
const tagEnd = xml.indexOf(">", tagStart);
|
|
80
|
+
if (tagEnd === -1) {
|
|
81
|
+
break;
|
|
82
|
+
}
|
|
83
|
+
const tagName = readTagName(xml.slice(tagStart + 1, tagEnd));
|
|
84
|
+
cursor = tagEnd + 1;
|
|
85
|
+
if (localName(tagName) !== "href") {
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
const closingStart = xml.indexOf("</", cursor);
|
|
89
|
+
if (closingStart === -1) {
|
|
90
|
+
break;
|
|
91
|
+
}
|
|
92
|
+
const value = xml.slice(cursor, closingStart).trim();
|
|
93
|
+
if (value) {
|
|
94
|
+
hrefs.push(value);
|
|
95
|
+
}
|
|
96
|
+
cursor = closingStart;
|
|
97
|
+
}
|
|
98
|
+
return hrefs;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function readTagName(tagContent: string): string {
|
|
102
|
+
if (tagContent.startsWith("/") || tagContent.startsWith("?")) {
|
|
103
|
+
return "";
|
|
104
|
+
}
|
|
105
|
+
let end = 0;
|
|
106
|
+
while (end < tagContent.length && !/[\s/]/.test(tagContent[end]!)) {
|
|
107
|
+
end += 1;
|
|
108
|
+
}
|
|
109
|
+
return tagContent.slice(0, end);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function localName(tagName: string): string {
|
|
113
|
+
const colonIndex = tagName.lastIndexOf(":");
|
|
114
|
+
return tagName.slice(colonIndex + 1).toLowerCase();
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/** Returns the body between each BEGIN:VEVENT / END:VEVENT pair. */
|
|
118
|
+
export function extractVeventBlocks(text: string): string[] {
|
|
119
|
+
const beginMarker = "BEGIN:VEVENT";
|
|
120
|
+
const endMarker = "END:VEVENT";
|
|
121
|
+
const blocks: string[] = [];
|
|
122
|
+
let cursor = 0;
|
|
123
|
+
while (cursor < text.length) {
|
|
124
|
+
const begin = text.indexOf(beginMarker, cursor);
|
|
125
|
+
if (begin === -1) {
|
|
126
|
+
break;
|
|
127
|
+
}
|
|
128
|
+
const bodyStart = begin + beginMarker.length;
|
|
129
|
+
const end = text.indexOf(endMarker, bodyStart);
|
|
130
|
+
if (end === -1) {
|
|
131
|
+
break;
|
|
132
|
+
}
|
|
133
|
+
blocks.push(text.slice(bodyStart, end));
|
|
134
|
+
cursor = end + endMarker.length;
|
|
135
|
+
}
|
|
136
|
+
return blocks;
|
|
137
|
+
}
|
|
138
|
+
|
|
69
139
|
/** Parses VEVENT components from a CalDAV multistatus response. */
|
|
70
140
|
export function parseCalDavEvents(
|
|
71
141
|
xml: string,
|
|
72
142
|
timezone: string
|
|
73
143
|
): CalendarEvent[] {
|
|
74
144
|
const events: CalendarEvent[] = [];
|
|
75
|
-
const hrefs =
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
const calendars = [...xml.matchAll(/BEGIN:VEVENT([\s\S]*?)END:VEVENT/g)];
|
|
79
|
-
calendars.forEach((match, index) => {
|
|
80
|
-
const block = match[1]!;
|
|
145
|
+
const hrefs = extractHrefs(xml);
|
|
146
|
+
const blocks = extractVeventBlocks(xml);
|
|
147
|
+
blocks.forEach((block, index) => {
|
|
81
148
|
const uid = extractField(block, "UID") ?? hrefs[index] ?? `event-${index}`;
|
|
82
149
|
const summary = extractField(block, "SUMMARY") ?? "(无标题)";
|
|
83
150
|
const startRaw = extractField(block, "DTSTART");
|
|
@@ -165,9 +232,7 @@ export function createCalDavProvider(options: CalDavOptions): CalendarProvider {
|
|
|
165
232
|
return parseCalDavEvents(await response.text(), options.timezone);
|
|
166
233
|
},
|
|
167
234
|
async createEvent(input, signal) {
|
|
168
|
-
const uid = `${
|
|
169
|
-
.toString(36)
|
|
170
|
-
.slice(2, 10)}@zhin`;
|
|
235
|
+
const uid = `${randomUUID()}@zhin`;
|
|
171
236
|
const url = new URL(`${uid}.ics`, base).toString();
|
|
172
237
|
const response = await fetchImpl(url, {
|
|
173
238
|
method: "PUT",
|
package/src/chat-auth.ts
CHANGED
|
@@ -76,13 +76,29 @@ export function parseOAuthProvider(
|
|
|
76
76
|
return undefined;
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
+
function trimTrailingSlashes(value: string): string {
|
|
80
|
+
let end = value.length;
|
|
81
|
+
while (end > 0 && value[end - 1] === "/") {
|
|
82
|
+
end -= 1;
|
|
83
|
+
}
|
|
84
|
+
return value.slice(0, end);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function trimLeadingSlashes(value: string): string {
|
|
88
|
+
let start = 0;
|
|
89
|
+
while (start < value.length && value[start] === "/") {
|
|
90
|
+
start += 1;
|
|
91
|
+
}
|
|
92
|
+
return value.slice(start);
|
|
93
|
+
}
|
|
94
|
+
|
|
79
95
|
/** Joins a base URL and the callback path, tolerating extra/missing slashes. */
|
|
80
96
|
export function buildRedirectUri(
|
|
81
97
|
baseUrl: string,
|
|
82
98
|
callbackPath: string
|
|
83
99
|
): string {
|
|
84
|
-
const trimmedBase = baseUrl.trim()
|
|
85
|
-
const normalizedPath = `/${callbackPath.trim()
|
|
100
|
+
const trimmedBase = trimTrailingSlashes(baseUrl.trim());
|
|
101
|
+
const normalizedPath = `/${trimLeadingSlashes(callbackPath.trim())}`;
|
|
86
102
|
return `${trimmedBase}${normalizedPath}`;
|
|
87
103
|
}
|
|
88
104
|
|