@eduwork/dsh-mail 0.1.2 → 0.2.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/CHANGELOG.en.md +11 -0
- package/CHANGELOG.md +11 -0
- package/README.md +4 -4
- package/README_EN.md +5 -5
- package/THIRD_PARTY_NOTICES.en.md +2 -0
- package/THIRD_PARTY_NOTICES.md +2 -0
- package/docs/EDUWORK-MIGRATION.en.md +2 -2
- package/docs/EDUWORK-MIGRATION.md +2 -2
- package/docs/architecture.en.md +3 -3
- package/docs/architecture.md +3 -3
- package/docs/compatibility.en.md +5 -6
- package/docs/compatibility.md +5 -6
- package/docs/getting-started.en.md +6 -6
- package/docs/getting-started.md +6 -6
- package/docs/security-model.en.md +4 -0
- package/docs/security-model.md +4 -0
- package/lib/client.js +167 -157
- package/lib/index.js +181 -37
- package/package.json +24 -16
package/lib/index.js
CHANGED
|
@@ -78,6 +78,43 @@ function pick(source, keys, forced) {
|
|
|
78
78
|
for (const key of keys) if (forced || source[key] !== void 0) result[key] = source[key];
|
|
79
79
|
return result;
|
|
80
80
|
}
|
|
81
|
+
/** Shared config references used by schema validators and plugin runtimes. */
|
|
82
|
+
const write = Symbol.for("cosmokit.volatile.write");
|
|
83
|
+
function snapshot(value, ancestors = /* @__PURE__ */ new Set()) {
|
|
84
|
+
if (typeof value === "function") throw new TypeError("volatile config cannot contain functions");
|
|
85
|
+
if (value === null || typeof value !== "object") return value;
|
|
86
|
+
if (ancestors.has(value)) throw new TypeError("volatile config cannot contain cycles");
|
|
87
|
+
ancestors.add(value);
|
|
88
|
+
try {
|
|
89
|
+
if (Array.isArray(value)) return Object.freeze(value.map((item) => snapshot(item, ancestors)));
|
|
90
|
+
if (Object.getPrototypeOf(value) !== Object.prototype && Object.getPrototypeOf(value) !== null) throw new TypeError("volatile config objects must be plain objects or arrays");
|
|
91
|
+
return Object.freeze(Object.fromEntries(Object.entries(value).map(([key, item]) => [key, snapshot(item, ancestors)])));
|
|
92
|
+
} finally {
|
|
93
|
+
ancestors.delete(value);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Create a detached reference containing an immutable copy of the supplied data.
|
|
98
|
+
* @param value - validated config data; class instances and functions are unsupported.
|
|
99
|
+
* @returns a reference whose value is updated only by its owning runtime.
|
|
100
|
+
*/
|
|
101
|
+
function createVolatile(value) {
|
|
102
|
+
let current = snapshot(value);
|
|
103
|
+
return Object.freeze({
|
|
104
|
+
get: () => current,
|
|
105
|
+
[write]: (value) => {
|
|
106
|
+
current = value;
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Identify references across ESM/CJS copies of the shared library.
|
|
112
|
+
* @param value - a parsed config value.
|
|
113
|
+
* @returns whether the value implements the shared reference protocol.
|
|
114
|
+
*/
|
|
115
|
+
function isVolatile(value) {
|
|
116
|
+
return typeof value === "object" && value !== null && write in value;
|
|
117
|
+
}
|
|
81
118
|
/** Test values using `instanceof` with a `toStringTag` fallback. */
|
|
82
119
|
function is(type, value) {
|
|
83
120
|
if (arguments.length === 1) return (value) => is(type, value);
|
|
@@ -158,26 +195,47 @@ function clone(source, refs = /* @__PURE__ */ new Map()) {
|
|
|
158
195
|
}
|
|
159
196
|
return result;
|
|
160
197
|
}
|
|
161
|
-
/**
|
|
198
|
+
/**
|
|
199
|
+
* Compare values recursively, treating two volatile references as equal regardless of value.
|
|
200
|
+
* Strict comparison distinguishes null/undefined, treats opaque objects by identity,
|
|
201
|
+
* compares URLs by normalized href, treats array holes as undefined, and considers distinct cyclic structures unequal.
|
|
202
|
+
* @param a - first value.
|
|
203
|
+
* @param b - second value.
|
|
204
|
+
* @param strict - whether to require strict data equality outside volatile references.
|
|
205
|
+
* @returns whether the values compare equal.
|
|
206
|
+
*/
|
|
162
207
|
function deepEqual(a, b, strict) {
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
208
|
+
const ancestors = /* @__PURE__ */ new Set();
|
|
209
|
+
function compare(a, b) {
|
|
210
|
+
if (a === b) return true;
|
|
211
|
+
if (isVolatile(a) || isVolatile(b)) return isVolatile(a) && isVolatile(b);
|
|
212
|
+
if (!strict && isNullable(a) && isNullable(b)) return true;
|
|
213
|
+
if (typeof a !== typeof b || typeof a !== "object" || !a || !b) return false;
|
|
214
|
+
if (ancestors.has(a)) return false;
|
|
215
|
+
function check(test, then) {
|
|
216
|
+
return test(a) ? test(b) ? then(a, b) : false : test(b) ? false : void 0;
|
|
217
|
+
}
|
|
218
|
+
ancestors.add(a);
|
|
219
|
+
try {
|
|
220
|
+
return check(Array.isArray, (a, b) => {
|
|
221
|
+
if (a.length !== b.length) return false;
|
|
222
|
+
for (let index = 0; index < a.length; index++) if (!compare(a[index], b[index])) return false;
|
|
223
|
+
return true;
|
|
224
|
+
}) ?? check(is("Date"), (a, b) => a.valueOf() === b.valueOf()) ?? check(is("URL"), (a, b) => a.href === b.href) ?? check(is("RegExp"), (a, b) => a.source === b.source && a.flags === b.flags) ?? check(isArrayBufferLike, (a, b) => {
|
|
225
|
+
if (a.byteLength !== b.byteLength) return false;
|
|
226
|
+
const viewA = new Uint8Array(a);
|
|
227
|
+
const viewB = new Uint8Array(b);
|
|
228
|
+
for (let i = 0; i < viewA.length; i++) if (viewA[i] !== viewB[i]) return false;
|
|
229
|
+
return true;
|
|
230
|
+
}) ?? ((!strict || [a, b].every((value) => Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null)) && Object.keys({
|
|
231
|
+
...a,
|
|
232
|
+
...b
|
|
233
|
+
}).every((key) => compare(a[key], b[key])));
|
|
234
|
+
} finally {
|
|
235
|
+
ancestors.delete(a);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
return compare(a, b);
|
|
181
239
|
}
|
|
182
240
|
/** Time constants plus parsing and formatting helpers. */
|
|
183
241
|
var Time;
|
|
@@ -426,6 +484,7 @@ Schema.prototype.pattern = function pattern(regexp) {
|
|
|
426
484
|
return schema;
|
|
427
485
|
};
|
|
428
486
|
Schema.prototype.simplify = function simplify(value) {
|
|
487
|
+
if (isVolatile(value)) value = value.get();
|
|
429
488
|
if (deepEqual(value, this.meta.default, this.type === "dict")) return null;
|
|
430
489
|
if (isNullable(value)) return value;
|
|
431
490
|
if (this.type === "object" || this.type === "dict") {
|
|
@@ -482,12 +541,49 @@ for (const key of [
|
|
|
482
541
|
};
|
|
483
542
|
return schema;
|
|
484
543
|
} });
|
|
544
|
+
Schema.prototype.volatile = function volatile() {
|
|
545
|
+
if (this.meta.volatile) throw new TypeError("volatile schema is already wrapped");
|
|
546
|
+
return this.extra("volatile", true);
|
|
547
|
+
};
|
|
485
548
|
const resolvers = {};
|
|
549
|
+
const checkedVolatile = Symbol("checked-volatile-schema");
|
|
550
|
+
function validateVolatileSchema(schema, path = [], blocked = false, seen = /* @__PURE__ */ new Map()) {
|
|
551
|
+
const states = seen.get(schema) ?? /* @__PURE__ */ new Set();
|
|
552
|
+
if (states.has(blocked)) return;
|
|
553
|
+
states.add(blocked);
|
|
554
|
+
seen.set(schema, states);
|
|
555
|
+
if (schema.meta?.volatile && blocked) throw new ValidationError("volatile fields require a fixed object path without an enclosing volatile field", { path });
|
|
556
|
+
const nested = blocked || !!schema.meta?.volatile;
|
|
557
|
+
if (schema.dict) for (const [key, child] of Object.entries(schema.dict)) validateVolatileSchema(child, [...path, key], nested, seen);
|
|
558
|
+
if (schema.sKey) validateVolatileSchema(schema.sKey, [...path, "<key>"], true, seen);
|
|
559
|
+
if (schema.inner && (schema.type !== "lazy" || schema.inner[kSchema])) validateVolatileSchema(schema.inner, [...path, "*"], true, seen);
|
|
560
|
+
if (schema.list) for (let index = 0; index < schema.list.length; index++) validateVolatileSchema(schema.list[index], [...path, String(index)], true, seen);
|
|
561
|
+
}
|
|
486
562
|
Schema.extend = function extend(type, resolve) {
|
|
487
563
|
resolvers[type] = resolve;
|
|
488
564
|
};
|
|
489
565
|
Schema.resolve = function resolve(data, schema, options = {}, strict = false) {
|
|
490
566
|
if (!schema) return [data];
|
|
567
|
+
if (!options[checkedVolatile]) {
|
|
568
|
+
validateVolatileSchema(schema, options.path);
|
|
569
|
+
options = {
|
|
570
|
+
...options,
|
|
571
|
+
[checkedVolatile]: true
|
|
572
|
+
};
|
|
573
|
+
}
|
|
574
|
+
if (schema.meta?.volatile) {
|
|
575
|
+
const inner = Schema(schema);
|
|
576
|
+
inner.meta = {
|
|
577
|
+
...schema.meta,
|
|
578
|
+
volatile: false
|
|
579
|
+
};
|
|
580
|
+
const [value, adapted] = Schema.resolve(data, inner, options, strict);
|
|
581
|
+
try {
|
|
582
|
+
return [createVolatile(value), adapted];
|
|
583
|
+
} catch (error) {
|
|
584
|
+
throw new ValidationError(error instanceof Error ? error.message : String(error), options);
|
|
585
|
+
}
|
|
586
|
+
}
|
|
491
587
|
if (options.ignore?.(data, schema)) return [data];
|
|
492
588
|
if (isNullable(data) && schema.type !== "lazy") {
|
|
493
589
|
if (schema.meta.required) throw new ValidationError(`missing required value`, options);
|
|
@@ -590,6 +686,7 @@ Schema.extend("lazy", (data, schema, options, strict) => {
|
|
|
590
686
|
...schema.meta,
|
|
591
687
|
...schema.inner.meta
|
|
592
688
|
};
|
|
689
|
+
validateVolatileSchema(schema.inner, options.path, true);
|
|
593
690
|
}
|
|
594
691
|
return Schema.resolve(data, schema.inner, options, strict);
|
|
595
692
|
});
|
|
@@ -689,7 +786,7 @@ function property(data, key, schema, options) {
|
|
|
689
786
|
} catch (e) {
|
|
690
787
|
if (!options?.autofix) throw e;
|
|
691
788
|
delete data[key];
|
|
692
|
-
return schema.meta.default;
|
|
789
|
+
return schema.meta.volatile ? createVolatile(schema.meta.default) : schema.meta.default;
|
|
693
790
|
}
|
|
694
791
|
}
|
|
695
792
|
Schema.extend("array", (data, { inner, meta }, options) => {
|
|
@@ -848,20 +945,21 @@ defineMethod("transform", [
|
|
|
848
945
|
const MailSettingsSchema = Schema.object({
|
|
849
946
|
readEnabled: Schema.boolean().default(DEFAULTS.readEnabled),
|
|
850
947
|
sendEnabled: Schema.boolean().default(DEFAULTS.sendEnabled),
|
|
851
|
-
email: Schema.string().default(DEFAULTS.email),
|
|
852
|
-
username: Schema.string().default(DEFAULTS.username),
|
|
853
|
-
fromName: Schema.string().default(DEFAULTS.fromName),
|
|
854
|
-
inboxFolder: Schema.string().default(DEFAULTS.inboxFolder),
|
|
855
|
-
imapHost: Schema.string().default(DEFAULTS.imapHost),
|
|
856
|
-
imapPort: Schema.number().default(DEFAULTS.imapPort),
|
|
948
|
+
email: Schema.string().pattern(/^[^\r\n\u0000]*$/u).default(DEFAULTS.email),
|
|
949
|
+
username: Schema.string().pattern(/^[^\r\n\u0000]*$/u).default(DEFAULTS.username),
|
|
950
|
+
fromName: Schema.string().pattern(/^[^\r\n\u0000]*$/u).default(DEFAULTS.fromName),
|
|
951
|
+
inboxFolder: Schema.string().pattern(/^[^\r\n\u0000]*$/u).default(DEFAULTS.inboxFolder),
|
|
952
|
+
imapHost: Schema.string().pattern(/^[^\r\n\u0000]*$/u).default(DEFAULTS.imapHost),
|
|
953
|
+
imapPort: Schema.number().step(1).min(1).max(65535).default(DEFAULTS.imapPort),
|
|
857
954
|
imapTls: Schema.union(["implicit", "starttls"]).default(DEFAULTS.imapTls),
|
|
858
|
-
smtpHost: Schema.string().default(DEFAULTS.smtpHost),
|
|
859
|
-
smtpPort: Schema.number().default(DEFAULTS.smtpPort),
|
|
955
|
+
smtpHost: Schema.string().pattern(/^[^\r\n\u0000]*$/u).default(DEFAULTS.smtpHost),
|
|
956
|
+
smtpPort: Schema.number().step(1).min(1).max(65535).default(DEFAULTS.smtpPort),
|
|
860
957
|
smtpTls: Schema.union(["implicit", "starttls"]).default(DEFAULTS.smtpTls),
|
|
861
|
-
maxBodyChars: Schema.number().default(DEFAULTS.maxBodyChars),
|
|
862
|
-
maxMessageBytes: Schema.number().default(DEFAULTS.maxMessageBytes),
|
|
863
|
-
maxAttachmentBytes: Schema.number().default(DEFAULTS.maxAttachmentBytes)
|
|
958
|
+
maxBodyChars: Schema.number().step(1).min(1e3).max(2e5).default(DEFAULTS.maxBodyChars),
|
|
959
|
+
maxMessageBytes: Schema.number().step(1).min(1048576).max(104857600).default(DEFAULTS.maxMessageBytes),
|
|
960
|
+
maxAttachmentBytes: Schema.number().step(1).min(1024).max(104857600).default(DEFAULTS.maxAttachmentBytes)
|
|
864
961
|
});
|
|
962
|
+
const Config = typeof Schema.string().volatile === "function" ? Schema.object(Object.fromEntries(Object.entries(MailSettingsSchema.dict).map(([key, field]) => [key, field.volatile()]))) : void 0;
|
|
865
963
|
function settingsBase(config = {}) {
|
|
866
964
|
const base = { ...DEFAULTS };
|
|
867
965
|
for (const key of Object.keys(DEFAULTS)) if (config[key] !== void 0) base[key] = config[key];
|
|
@@ -910,6 +1008,7 @@ const SEND_APPROVAL_REASON = "Send this email through the configured SMTP accoun
|
|
|
910
1008
|
* after the user has explicitly enabled sending in Mail assistant settings.
|
|
911
1009
|
*/
|
|
912
1010
|
function decideMailPermission(ctx, exec, next) {
|
|
1011
|
+
if (exec.name === TOOL_NAMES.attachment) return decideAttachmentWrite(ctx, exec, next);
|
|
913
1012
|
if (exec.name !== TOOL_NAMES.send) return next();
|
|
914
1013
|
const agent = exec.agent;
|
|
915
1014
|
if (agent === void 0) return Promise.resolve({
|
|
@@ -919,9 +1018,50 @@ function decideMailPermission(ctx, exec, next) {
|
|
|
919
1018
|
if (ctx.permissionPresets.current(agent.session) === "danger-full-access") return next();
|
|
920
1019
|
return Promise.resolve({
|
|
921
1020
|
kind: "ask",
|
|
922
|
-
reason: SEND_APPROVAL_REASON
|
|
1021
|
+
reason: SEND_APPROVAL_REASON,
|
|
1022
|
+
displayReason: {
|
|
1023
|
+
en: SEND_APPROVAL_REASON,
|
|
1024
|
+
zh: "允许通过已配置的 SMTP 账号发送这封邮件。请核对工具调用中显示的收件人、主题和附件。"
|
|
1025
|
+
}
|
|
923
1026
|
});
|
|
924
1027
|
}
|
|
1028
|
+
async function decideAttachmentWrite(ctx, exec, next) {
|
|
1029
|
+
if (!exec.agent) return {
|
|
1030
|
+
kind: "deny",
|
|
1031
|
+
reason: "Attachment downloads require an Agent-backed session"
|
|
1032
|
+
};
|
|
1033
|
+
if (!exec.agent.session.header?.cwd) return {
|
|
1034
|
+
kind: "deny",
|
|
1035
|
+
reason: "Attachment downloads require a session workspace"
|
|
1036
|
+
};
|
|
1037
|
+
const resolver = ctx.get?.("sandboxPolicy");
|
|
1038
|
+
const policy = resolver ? resolver.resolve({ session: exec.agent.session }) : { mode: ctx.permissionPresets.current(exec.agent.session) };
|
|
1039
|
+
if (policy?.mode === "danger-full-access") return next();
|
|
1040
|
+
if (policy?.mode === "workspace-write") {
|
|
1041
|
+
if (policy.workspaceRoot !== void 0) {
|
|
1042
|
+
const options = {
|
|
1043
|
+
cwd: exec.agent.session.header.cwd,
|
|
1044
|
+
signal: exec.signal
|
|
1045
|
+
};
|
|
1046
|
+
const root = await ctx.fs.resolve(".", options);
|
|
1047
|
+
const allowed = await ctx.fs.resolve(policy.workspaceRoot, options);
|
|
1048
|
+
if (!ctx.fs.contains(allowed, root)) return {
|
|
1049
|
+
kind: "deny",
|
|
1050
|
+
reason: "Attachment workspace is outside the allowed write root"
|
|
1051
|
+
};
|
|
1052
|
+
}
|
|
1053
|
+
return next();
|
|
1054
|
+
}
|
|
1055
|
+
const reason = "Save this mail attachment in the current workspace";
|
|
1056
|
+
return {
|
|
1057
|
+
kind: "ask",
|
|
1058
|
+
reason,
|
|
1059
|
+
displayReason: {
|
|
1060
|
+
en: reason,
|
|
1061
|
+
zh: "允许将这封邮件的附件保存到当前工作区"
|
|
1062
|
+
}
|
|
1063
|
+
};
|
|
1064
|
+
}
|
|
925
1065
|
Object.freeze({ SEND_APPROVAL_REASON });
|
|
926
1066
|
//#endregion
|
|
927
1067
|
//#region node_modules/pino-std-serializers/lib/err-helpers.js
|
|
@@ -101893,11 +102033,12 @@ async function readWorkspaceAttachments(ctx, paths, exec, maxBytes) {
|
|
|
101893
102033
|
if (!Array.isArray(paths) || paths.length > 10 || paths.some((path) => typeof path !== "string" || path.trim() === "")) throw new Error("attachments must be an array of at most 10 non-empty workspace paths");
|
|
101894
102034
|
const workspace = workspaceOf(exec);
|
|
101895
102035
|
const workspaceTarget = await ctx.fs.resolve(workspace, { signal: exec.signal });
|
|
102036
|
+
const cwd = ctx.get?.("workingDirectory")?.get(exec.agent.session) ?? workspace;
|
|
101896
102037
|
const attachments = [];
|
|
101897
102038
|
let total = 0;
|
|
101898
102039
|
for (const raw of paths) {
|
|
101899
102040
|
const target = await ctx.fs.resolve(raw.trim(), {
|
|
101900
|
-
cwd
|
|
102041
|
+
cwd,
|
|
101901
102042
|
signal: exec.signal
|
|
101902
102043
|
});
|
|
101903
102044
|
if (!ctx.fs.contains(workspaceTarget, target)) throw new Error(`Attachment is outside the session workspace: ${raw}`);
|
|
@@ -102412,14 +102553,16 @@ const inject = [
|
|
|
102412
102553
|
"permissionPresets"
|
|
102413
102554
|
];
|
|
102414
102555
|
function apply(ctx, config = {}) {
|
|
102415
|
-
const
|
|
102556
|
+
const native = typeof ctx.settings.register !== "function";
|
|
102557
|
+
const readLive = () => Object.fromEntries(Object.keys(DEFAULTS).map((key) => [key, config[key].get()]));
|
|
102558
|
+
const base = native ? readLive() : settingsBase(config);
|
|
102416
102559
|
validateSettings(base);
|
|
102417
|
-
const scope = ctx.settings.register(SETTINGS_NAMESPACE, MailSettingsSchema, {
|
|
102560
|
+
const scope = native ? { get: readLive } : ctx.settings.register(SETTINGS_NAMESPACE, MailSettingsSchema, {
|
|
102418
102561
|
base,
|
|
102419
102562
|
applies: "live",
|
|
102420
102563
|
validate: validateSettings
|
|
102421
102564
|
});
|
|
102422
|
-
const getSettings = () => currentSettings(ctx, scope, config);
|
|
102565
|
+
const getSettings = () => currentSettings(ctx, scope, native ? {} : config);
|
|
102423
102566
|
ctx.on("tools/pre-execute", (exec, next) => decideMailPermission(ctx, exec, next));
|
|
102424
102567
|
installTools(ctx, getSettings);
|
|
102425
102568
|
ctx.tools.guard((exec) => {
|
|
@@ -102453,9 +102596,10 @@ function apply(ctx, config = {}) {
|
|
|
102453
102596
|
var host_default = {
|
|
102454
102597
|
name,
|
|
102455
102598
|
inject,
|
|
102599
|
+
Config,
|
|
102456
102600
|
apply
|
|
102457
102601
|
};
|
|
102458
102602
|
//#endregion
|
|
102459
|
-
export { DEFAULTS, MailSettingsSchema, PASSWORD_REF_NAME, SETTINGS_NAMESPACE, TOOL_NAMES, apply, host_default as default, inject, name, validateSettings };
|
|
102603
|
+
export { Config, DEFAULTS, MailSettingsSchema, PASSWORD_REF_NAME, SETTINGS_NAMESPACE, TOOL_NAMES, apply, host_default as default, inject, name, validateSettings };
|
|
102460
102604
|
|
|
102461
102605
|
//# sourceMappingURL=index.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eduwork/dsh-mail",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "Standards-based IMAP/SMTP mail assistant for DeepSeek Harness with explicit read/send controls and approval-aware delivery",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"deepseek-harness",
|
|
@@ -50,7 +50,8 @@
|
|
|
50
50
|
"inject": [
|
|
51
51
|
"@deepseek-ai/dsh-api-remotes",
|
|
52
52
|
"@deepseek-ai/dsh-client-ui-renderer",
|
|
53
|
-
"@deepseek-ai/dsh-client-ui-settings"
|
|
53
|
+
"@deepseek-ai/dsh-client-ui-settings",
|
|
54
|
+
"@deepseek-ai/dsh-client-locale"
|
|
54
55
|
],
|
|
55
56
|
"platform": "web",
|
|
56
57
|
"immediately": true
|
|
@@ -78,7 +79,7 @@
|
|
|
78
79
|
"prepare": "npm run build"
|
|
79
80
|
},
|
|
80
81
|
"engines": {
|
|
81
|
-
"node": ">=
|
|
82
|
+
"node": ">=24.18.0"
|
|
82
83
|
},
|
|
83
84
|
"license": "MIT",
|
|
84
85
|
"publishConfig": {
|
|
@@ -86,22 +87,23 @@
|
|
|
86
87
|
},
|
|
87
88
|
"repository": {
|
|
88
89
|
"type": "git",
|
|
89
|
-
"url": "git+https://github.com/
|
|
90
|
+
"url": "git+https://github.com/ECNU/EduWork.git",
|
|
90
91
|
"directory": "packages/dsh-mail"
|
|
91
92
|
},
|
|
92
93
|
"bugs": {
|
|
93
|
-
"url": "https://github.com/
|
|
94
|
+
"url": "https://github.com/ECNU/EduWork/issues"
|
|
94
95
|
},
|
|
95
|
-
"homepage": "https://github.com/
|
|
96
|
+
"homepage": "https://github.com/ECNU/EduWork/tree/main/packages/dsh-mail#readme",
|
|
96
97
|
"peerDependencies": {
|
|
97
|
-
"@deepseek-ai/cordis": "4.0.
|
|
98
|
-
"@deepseek-ai/dsh-api-remotes": "0.
|
|
99
|
-
"@deepseek-ai/dsh-client-ui-renderer": "0.
|
|
100
|
-
"@deepseek-ai/dsh-client-ui-settings": "0.
|
|
101
|
-
"@deepseek-ai/dsh-credentials": "0.
|
|
102
|
-
"@deepseek-ai/dsh-permission-presets": "0.
|
|
103
|
-
"@deepseek-ai/dsh-tools": "0.
|
|
104
|
-
"react": "^18.2.0"
|
|
98
|
+
"@deepseek-ai/cordis": ">=4.0.5 <4.1.0",
|
|
99
|
+
"@deepseek-ai/dsh-api-remotes": ">=0.2.1-rc.2 <0.3.0-0",
|
|
100
|
+
"@deepseek-ai/dsh-client-ui-renderer": ">=0.2.1-rc.2 <0.3.0-0",
|
|
101
|
+
"@deepseek-ai/dsh-client-ui-settings": ">=0.2.1-rc.2 <0.3.0-0",
|
|
102
|
+
"@deepseek-ai/dsh-credentials": ">=0.2.1-rc.2 <0.3.0-0",
|
|
103
|
+
"@deepseek-ai/dsh-permission-presets": ">=0.2.1-rc.2 <0.3.0-0",
|
|
104
|
+
"@deepseek-ai/dsh-tools": ">=0.2.1-rc.2 <0.3.0-0",
|
|
105
|
+
"react": "^18.2.0",
|
|
106
|
+
"@deepseek-ai/dsh-client-locale": ">=0.2.1-rc.2 <0.3.0-0"
|
|
105
107
|
},
|
|
106
108
|
"peerDependenciesMeta": {
|
|
107
109
|
"@deepseek-ai/cordis": {
|
|
@@ -127,10 +129,13 @@
|
|
|
127
129
|
},
|
|
128
130
|
"react": {
|
|
129
131
|
"optional": true
|
|
132
|
+
},
|
|
133
|
+
"@deepseek-ai/dsh-client-locale": {
|
|
134
|
+
"optional": true
|
|
130
135
|
}
|
|
131
136
|
},
|
|
132
137
|
"devDependencies": {
|
|
133
|
-
"@deepseek-ai/schemastery": "3.18.
|
|
138
|
+
"@deepseek-ai/schemastery": "3.18.5",
|
|
134
139
|
"@types/node": "^26.0.0",
|
|
135
140
|
"@types/react": "^18.3.28",
|
|
136
141
|
"imapflow": "^1.7.0",
|
|
@@ -138,7 +143,10 @@
|
|
|
138
143
|
"nodemailer": "^9.1.0",
|
|
139
144
|
"react": "^18.3.1",
|
|
140
145
|
"tsdown": "0.22.14",
|
|
141
|
-
"typescript": "^5.9.3"
|
|
146
|
+
"typescript": "^5.9.3",
|
|
147
|
+
"@deepseek-ai/dsh": "0.2.1-rc.2",
|
|
148
|
+
"@deepseek-ai/cordis": "4.0.5",
|
|
149
|
+
"semver": "7.7.4"
|
|
142
150
|
},
|
|
143
151
|
"directories": {
|
|
144
152
|
"doc": "docs",
|