@zaclinley/dsh-mailharbor 0.23.0 → 0.25.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/CHANGELOG.md +23 -0
- package/README.zh.md +17 -17
- package/lib/client.js +305 -5
- package/lib/client.js.map +3 -3
- package/lib/index.js +172 -3
- package/lib/index.js.map +3 -3
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -2542,6 +2542,16 @@ var TASK_SYSTEM = `\u4F60\u662F\u4EFB\u52A1\u63D0\u53D6\u52A9\u624B\u3002\u4ECE\
|
|
|
2542
2542
|
- \u622A\u6B62\u65F6\u95F4\u80FD\u786E\u5B9A\u624D\u586B\uFF0C\u5426\u5219\u7559\u7A7A
|
|
2543
2543
|
- \u6CA1\u6709\u53EF\u6267\u884C\u4E8B\u9879\u65F6\u8F93\u51FA []
|
|
2544
2544
|
- \u4E0D\u8981\u7F16\u9020\u90AE\u4EF6\u91CC\u6CA1\u6709\u7684\u4FE1\u606F`;
|
|
2545
|
+
var PROJECT_TASK_SYSTEM = `\u4F60\u662F\u9879\u76EE\u4EFB\u52A1\u62C6\u89E3\u52A9\u624B\u3002\u6839\u636E\u9879\u76EE\u8BB0\u5F55\u3001\u672A\u5B8C\u6210\u4EFB\u52A1\u548C\u90AE\u4EF6\u6458\u8981\uFF0C\u63D0\u51FA\u9700\u8981\u7528\u6237\u8DDF\u8FDB\u7684\u5177\u4F53\u4E8B\u9879\u3002
|
|
2546
|
+
|
|
2547
|
+
\u53EA\u8F93\u51FA\u4E00\u4E2A JSON \u6570\u7EC4\uFF0C\u4E0D\u8981\u8F93\u51FA\u89E3\u91CA\u3001Markdown \u6216\u4EE3\u7801\u5757\u6807\u8BB0\u3002\u6BCF\u4E2A\u5143\u7D20\uFF1A
|
|
2548
|
+
{"title": "\u4EFB\u52A1\u6807\u9898\uFF08\u52A8\u8BCD\u5F00\u5934\uFF0C\u5C3D\u91CF\u5177\u4F53\uFF09", "due": "YYYY-MM-DD \u6216\u7A7A\u5B57\u7B26\u4E32", "priority": 0 \u5230 9 \u7684\u6574\u6570, "owner": "\u76F8\u5173\u8054\u7CFB\u4EBA\u6216\u7A7A\u5B57\u7B26\u4E32", "notes": "\u4E00\u53E5\u4F9D\u636E"}
|
|
2549
|
+
|
|
2550
|
+
\u89C4\u5219\uFF1A
|
|
2551
|
+
- \u53EA\u63D0\u51FA\u6750\u6599\u91CC\u660E\u786E\u8981\u6C42\u3001\u6216\u660E\u663E\u9700\u8981\u8DDF\u8FDB\u7684\u4E8B\u9879
|
|
2552
|
+
- \u4E0D\u8981\u91CD\u590D\u5DF2\u7ECF\u5B58\u5728\u7684\u4EFB\u52A1
|
|
2553
|
+
- \u622A\u6B62\u65F6\u95F4\u4E0D\u786E\u5B9A\u5C31\u7559\u7A7A
|
|
2554
|
+
- \u6CA1\u6709\u53EF\u6267\u884C\u4E8B\u9879\u65F6\u8F93\u51FA []`;
|
|
2545
2555
|
var STYLE_SYSTEM = `\u4F60\u662F\u5199\u4F5C\u98CE\u683C\u5206\u6790\u5E08\u3002\u9605\u8BFB\u7528\u6237\u6700\u8FD1\u53D1\u51FA\u7684\u90AE\u4EF6\uFF0C\u7528\u7B80\u4F53\u4E2D\u6587\u5199\u4E00\u6BB5 150-300 \u5B57\u7684\u5199\u4F5C\u98CE\u683C\u6863\u6848\uFF0C\u8986\u76D6\uFF1A
|
|
2546
2556
|
\u5E38\u7528\u79F0\u547C\u3001\u5F00\u5934\u65B9\u5F0F\u3001\u7ED3\u5C3E\u4E0E\u7F72\u540D\u3001\u8BED\u6C14\uFF08\u6B63\u5F0F/\u4EB2\u5207/\u76F4\u63A5\uFF09\u3001\u53E5\u5B50\u957F\u77ED\u3001\u5E38\u7528\u8868\u8FBE\u6216\u53E3\u5934\u7985\u3002
|
|
2547
2557
|
\u53EA\u8F93\u51FA\u6863\u6848\u6B63\u6587\uFF0C\u4E0D\u8981\u8F93\u51FA\u6807\u9898\u3001\u5217\u8868\u7B26\u53F7\u6216\u5206\u6790\u8FC7\u7A0B\u3002`;
|
|
@@ -2752,6 +2762,11 @@ ${clip(item, 4e3)}`).join("\n\n");
|
|
|
2752
2762
|
const text2 = await this.complete(TASK_SYSTEM, contextOf(message), signal);
|
|
2753
2763
|
return parseTaskJson(text2);
|
|
2754
2764
|
}
|
|
2765
|
+
/** Propose tasks for a project from its notes, open tasks and mail summary. */
|
|
2766
|
+
async proposeProjectTasks(context, signal) {
|
|
2767
|
+
const text2 = await this.complete(PROJECT_TASK_SYSTEM, clip(context, 3e4), signal);
|
|
2768
|
+
return parseTaskJson(text2);
|
|
2769
|
+
}
|
|
2755
2770
|
/** Compose-body assistance: draft from points, polish, or shorten. */
|
|
2756
2771
|
async compose(account, options, signal) {
|
|
2757
2772
|
const style = this.style(account)?.profile ?? "";
|
|
@@ -2958,6 +2973,7 @@ var ProjectStore = class {
|
|
|
2958
2973
|
status: project.status ?? "active",
|
|
2959
2974
|
notes: Array.isArray(project.notes) ? project.notes : [],
|
|
2960
2975
|
milestones: Array.isArray(project.milestones) ? project.milestones : [],
|
|
2976
|
+
activity: Array.isArray(project.activity) ? project.activity : [],
|
|
2961
2977
|
sessionIds: Array.isArray(project.sessionIds) ? project.sessionIds : project.sessionId === "" ? [] : [project.sessionId]
|
|
2962
2978
|
}))
|
|
2963
2979
|
};
|
|
@@ -3057,6 +3073,47 @@ var ProjectStore = class {
|
|
|
3057
3073
|
this.flush();
|
|
3058
3074
|
return project;
|
|
3059
3075
|
}
|
|
3076
|
+
addMilestone(id, title, due) {
|
|
3077
|
+
const project = this.get(id);
|
|
3078
|
+
if (project === void 0) return void 0;
|
|
3079
|
+
project.milestones.push({
|
|
3080
|
+
id: `ms_${randomUUID2().slice(0, 8)}`,
|
|
3081
|
+
title,
|
|
3082
|
+
due,
|
|
3083
|
+
done: false
|
|
3084
|
+
});
|
|
3085
|
+
project.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
3086
|
+
this.flush();
|
|
3087
|
+
return project;
|
|
3088
|
+
}
|
|
3089
|
+
updateMilestone(id, milestoneId, patch) {
|
|
3090
|
+
const project = this.get(id);
|
|
3091
|
+
const milestone = project?.milestones.find((item) => item.id === milestoneId);
|
|
3092
|
+
if (project === void 0 || milestone === void 0) return void 0;
|
|
3093
|
+
if (patch.title !== void 0) milestone.title = patch.title;
|
|
3094
|
+
if (patch.due !== void 0) milestone.due = patch.due;
|
|
3095
|
+
if (patch.done !== void 0) milestone.done = patch.done;
|
|
3096
|
+
project.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
3097
|
+
this.flush();
|
|
3098
|
+
return project;
|
|
3099
|
+
}
|
|
3100
|
+
removeMilestone(id, milestoneId) {
|
|
3101
|
+
const project = this.get(id);
|
|
3102
|
+
if (project === void 0) return void 0;
|
|
3103
|
+
project.milestones = project.milestones.filter((item) => item.id !== milestoneId);
|
|
3104
|
+
project.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
3105
|
+
this.flush();
|
|
3106
|
+
return project;
|
|
3107
|
+
}
|
|
3108
|
+
addActivity(id, text2, at = (/* @__PURE__ */ new Date()).toISOString()) {
|
|
3109
|
+
const project = this.get(id);
|
|
3110
|
+
if (project === void 0) return void 0;
|
|
3111
|
+
project.activity.unshift({ id: `act_${randomUUID2().slice(0, 8)}`, at, text: text2 });
|
|
3112
|
+
if (project.activity.length > 100) project.activity.length = 100;
|
|
3113
|
+
project.updatedAt = at;
|
|
3114
|
+
this.flush();
|
|
3115
|
+
return project;
|
|
3116
|
+
}
|
|
3060
3117
|
remove(id) {
|
|
3061
3118
|
const data = this.load();
|
|
3062
3119
|
const index = data.projects.findIndex((project) => project.id === id);
|
|
@@ -3124,6 +3181,7 @@ async function createProject(options) {
|
|
|
3124
3181
|
status: "active",
|
|
3125
3182
|
notes: [],
|
|
3126
3183
|
milestones: [],
|
|
3184
|
+
activity: [],
|
|
3127
3185
|
path,
|
|
3128
3186
|
workspaceId,
|
|
3129
3187
|
sessionId,
|
|
@@ -3185,7 +3243,7 @@ ${conversation.trim()}
|
|
|
3185
3243
|
}
|
|
3186
3244
|
|
|
3187
3245
|
// src/host/version.ts
|
|
3188
|
-
var VERSION = "0.
|
|
3246
|
+
var VERSION = "0.25.0";
|
|
3189
3247
|
|
|
3190
3248
|
// src/host/api.ts
|
|
3191
3249
|
init_smtp();
|
|
@@ -4058,6 +4116,32 @@ function buildRouter(runtime) {
|
|
|
4058
4116
|
throw aiHttpError(error);
|
|
4059
4117
|
}
|
|
4060
4118
|
});
|
|
4119
|
+
router.post("/ai/propose/tasks", async ({ body }) => {
|
|
4120
|
+
const payload = await body();
|
|
4121
|
+
const account = accountFromPayload(runtime, payload);
|
|
4122
|
+
const projectId = typeof payload.projectId === "string" ? payload.projectId : "";
|
|
4123
|
+
const project = projectId === "" ? void 0 : runtime.projects().get(projectId);
|
|
4124
|
+
if (projectId !== "" && project === void 0) throw new HttpError(404, "\u9879\u76EE\u4E0D\u5B58\u5728");
|
|
4125
|
+
const notes = Array.isArray(payload.noteIds) ? payload.noteIds.map((id) => project?.notes.find((note) => note.id === id)).filter((note) => note !== void 0) : project?.notes.slice(0, 30) ?? [];
|
|
4126
|
+
const text2 = typeof payload.text === "string" ? payload.text : "";
|
|
4127
|
+
if (notes.length === 0 && text2.trim() === "") throw new HttpError(400, "\u6CA1\u6709\u53EF\u5206\u6790\u7684\u8BB0\u5F55");
|
|
4128
|
+
const tasks = project === void 0 ? [] : runtime.tasks().list({ accountId: account.id, projectId: project.id });
|
|
4129
|
+
const context = [
|
|
4130
|
+
project === void 0 ? "" : `\u9879\u76EE\uFF1A${project.name}\uFF08${project.status}\uFF09`,
|
|
4131
|
+
notes.length === 0 ? "" : `\u9879\u76EE\u8BB0\u5F55\uFF1A
|
|
4132
|
+
${notes.map((note) => `- ${note.createdAt.slice(0, 10)} ${note.body}`).join("\n")}`,
|
|
4133
|
+
tasks.length === 0 ? "" : `\u5DF2\u6709\u4EFB\u52A1\uFF1A
|
|
4134
|
+
${tasks.map((task) => `- ${task.title}`).join("\n")}`,
|
|
4135
|
+
text2.trim() === "" ? "" : `\u8865\u5145\u5185\u5BB9\uFF1A
|
|
4136
|
+
${text2}`
|
|
4137
|
+
].filter((line2) => line2 !== "").join("\n\n");
|
|
4138
|
+
try {
|
|
4139
|
+
const suggestions = await runtime.ai().proposeProjectTasks(context);
|
|
4140
|
+
return { suggestions };
|
|
4141
|
+
} catch (error) {
|
|
4142
|
+
throw aiHttpError(error);
|
|
4143
|
+
}
|
|
4144
|
+
});
|
|
4061
4145
|
router.post("/projects/:id/attachment", async ({ params, body }) => {
|
|
4062
4146
|
const payload = await body();
|
|
4063
4147
|
const account = accountFromPayload(runtime, payload);
|
|
@@ -4168,7 +4252,87 @@ function buildRouter(runtime) {
|
|
|
4168
4252
|
}
|
|
4169
4253
|
const project = runtime.projects().update(String(params.id ?? ""), patch);
|
|
4170
4254
|
if (project === void 0) throw new HttpError(404, "\u9879\u76EE\u4E0D\u5B58\u5728");
|
|
4171
|
-
|
|
4255
|
+
if (typeof patch.status === "string") {
|
|
4256
|
+
const labels = {
|
|
4257
|
+
active: "\u8FDB\u884C\u4E2D",
|
|
4258
|
+
paused: "\u6682\u505C",
|
|
4259
|
+
done: "\u5DF2\u5B8C\u6210",
|
|
4260
|
+
archived: "\u5DF2\u5F52\u6863"
|
|
4261
|
+
};
|
|
4262
|
+
runtime.projects().addActivity(project.id, `\u9879\u76EE\u72B6\u6001\u6539\u4E3A\u300C${labels[patch.status] ?? patch.status}\u300D`);
|
|
4263
|
+
}
|
|
4264
|
+
return { project: projectView(runtime.projects().get(project.id) ?? project) };
|
|
4265
|
+
});
|
|
4266
|
+
router.post("/projects/:id/milestones", async ({ params, body }) => {
|
|
4267
|
+
const payload = await body();
|
|
4268
|
+
const project = runtime.projects().get(String(params.id ?? ""));
|
|
4269
|
+
if (project === void 0) throw new HttpError(404, "\u9879\u76EE\u4E0D\u5B58\u5728");
|
|
4270
|
+
const title = String(payload.title ?? "").trim();
|
|
4271
|
+
if (title === "") throw new HttpError(400, "\u91CC\u7A0B\u7891\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A");
|
|
4272
|
+
const updated = runtime.projects().addMilestone(project.id, title, typeof payload.due === "string" ? payload.due : "");
|
|
4273
|
+
if (updated === void 0) throw new HttpError(404, "\u9879\u76EE\u4E0D\u5B58\u5728");
|
|
4274
|
+
runtime.projects().addActivity(project.id, `\u65B0\u589E\u91CC\u7A0B\u7891\u300C${title}\u300D`);
|
|
4275
|
+
return { project: projectView(runtime.projects().get(project.id) ?? updated) };
|
|
4276
|
+
});
|
|
4277
|
+
router.patch("/projects/:id/milestones/:milestoneId", async ({ params, body }) => {
|
|
4278
|
+
const payload = await body();
|
|
4279
|
+
const project = runtime.projects().get(String(params.id ?? ""));
|
|
4280
|
+
if (project === void 0) throw new HttpError(404, "\u9879\u76EE\u4E0D\u5B58\u5728");
|
|
4281
|
+
const milestone = project.milestones.find((item) => item.id === String(params.milestoneId ?? ""));
|
|
4282
|
+
if (milestone === void 0) throw new HttpError(404, "\u91CC\u7A0B\u7891\u4E0D\u5B58\u5728");
|
|
4283
|
+
const patch = {};
|
|
4284
|
+
if (typeof payload.title === "string") patch.title = payload.title.trim();
|
|
4285
|
+
if (typeof payload.due === "string") patch.due = payload.due;
|
|
4286
|
+
if (typeof payload.done === "boolean") patch.done = payload.done;
|
|
4287
|
+
const updated = runtime.projects().updateMilestone(project.id, milestone.id, patch);
|
|
4288
|
+
if (updated === void 0) throw new HttpError(404, "\u91CC\u7A0B\u7891\u4E0D\u5B58\u5728");
|
|
4289
|
+
if (patch.done !== void 0) {
|
|
4290
|
+
runtime.projects().addActivity(
|
|
4291
|
+
project.id,
|
|
4292
|
+
`\u91CC\u7A0B\u7891\u300C${patch.title ?? milestone.title}\u300D${patch.done ? "\u5DF2\u5B8C\u6210" : "\u91CD\u65B0\u6253\u5F00"}`
|
|
4293
|
+
);
|
|
4294
|
+
}
|
|
4295
|
+
return { project: projectView(runtime.projects().get(project.id) ?? updated) };
|
|
4296
|
+
});
|
|
4297
|
+
router.delete("/projects/:id/milestones/:milestoneId", ({ params }) => {
|
|
4298
|
+
const project = runtime.projects().get(String(params.id ?? ""));
|
|
4299
|
+
if (project === void 0) throw new HttpError(404, "\u9879\u76EE\u4E0D\u5B58\u5728");
|
|
4300
|
+
const milestone = project.milestones.find((item) => item.id === String(params.milestoneId ?? ""));
|
|
4301
|
+
const updated = runtime.projects().removeMilestone(project.id, String(params.milestoneId ?? ""));
|
|
4302
|
+
if (updated === void 0) throw new HttpError(404, "\u91CC\u7A0B\u7891\u4E0D\u5B58\u5728");
|
|
4303
|
+
runtime.projects().addActivity(project.id, `\u5220\u9664\u91CC\u7A0B\u7891\u300C${milestone?.title ?? ""}\u300D`);
|
|
4304
|
+
return { project: projectView(runtime.projects().get(project.id) ?? updated) };
|
|
4305
|
+
});
|
|
4306
|
+
router.post("/projects/:id/session", async ({ params, body }) => {
|
|
4307
|
+
const payload = await body();
|
|
4308
|
+
const project = runtime.projects().get(String(params.id ?? ""));
|
|
4309
|
+
if (project === void 0) throw new HttpError(404, "\u9879\u76EE\u4E0D\u5B58\u5728");
|
|
4310
|
+
if (runtime.sessions === void 0) throw new HttpError(400, "\u5F53\u524D DSH \u7EC4\u5408\u6CA1\u6709\u4F1A\u8BDD\u670D\u52A1");
|
|
4311
|
+
const purpose = typeof payload.purpose === "string" ? payload.purpose : "";
|
|
4312
|
+
const sessionId = randomUUID3();
|
|
4313
|
+
const session = runtime.sessions.create(sessionId, { meta: { cwd: project.path } });
|
|
4314
|
+
const notes = project.notes.slice(0, 20).map((note) => `- ${note.createdAt.slice(0, 10)} ${note.body}`).join("\n");
|
|
4315
|
+
const accountId = project.accountIds[0];
|
|
4316
|
+
const tasks = accountId === void 0 ? [] : runtime.tasks().list({ accountId, projectId: project.id }).filter((task) => task.status !== "COMPLETED" && task.status !== "CANCELLED").map(
|
|
4317
|
+
(task) => `- [${task.status}] ${task.title}${task.waitingOn === "" ? "" : `\uFF08\u7B49\u5F85\uFF1A${task.waitingOn}\uFF09`}`
|
|
4318
|
+
).join("\n");
|
|
4319
|
+
const context = [
|
|
4320
|
+
`\u9879\u76EE\uFF1A${project.name}\uFF08${project.status}\uFF09`,
|
|
4321
|
+
purpose === "" ? "" : `\u8FD9\u6B21\u4F1A\u8BDD\u7684\u76EE\u7684\uFF1A${purpose}`,
|
|
4322
|
+
notes === "" ? "" : `\u6700\u8FD1\u8BB0\u5F55\uFF1A
|
|
4323
|
+
${notes}`,
|
|
4324
|
+
tasks === "" ? "" : `\u672A\u5B8C\u6210\u4EFB\u52A1\uFF1A
|
|
4325
|
+
${tasks}`,
|
|
4326
|
+
"\u8BF7\u57FA\u4E8E\u4EE5\u4E0A\u4E0A\u4E0B\u6587\u534F\u52A9\u6574\u7406\u8D44\u6599\u6216\u5904\u7406\u6587\u4EF6\uFF1B\u9700\u8981\u521B\u5EFA\u4EFB\u52A1\u65F6\u5148\u7ED9\u51FA\u63D0\u8BAE\uFF0C\u7B49\u6211\u786E\u8BA4\u3002"
|
|
4327
|
+
].filter((line2) => line2 !== "").join("\n\n");
|
|
4328
|
+
session.append(
|
|
4329
|
+
"user/message",
|
|
4330
|
+
{ role: "user", content: [{ type: "text", text: context }], source: { kind: "user" } },
|
|
4331
|
+
{ surfaceOp: "append" }
|
|
4332
|
+
);
|
|
4333
|
+
runtime.projects().update(project.id, { sessionIds: [...project.sessionIds, sessionId] });
|
|
4334
|
+
runtime.projects().addActivity(project.id, "\u521B\u5EFA\u9879\u76EE\u4F1A\u8BDD");
|
|
4335
|
+
return { sessionId, project: projectView(runtime.projects().get(project.id) ?? project) };
|
|
4172
4336
|
});
|
|
4173
4337
|
router.post("/projects/:id/notes", async ({ params, body }) => {
|
|
4174
4338
|
const payload = await body();
|
|
@@ -4178,7 +4342,10 @@ function buildRouter(runtime) {
|
|
|
4178
4342
|
if (text2 === "") throw new HttpError(400, "\u8BB0\u5F55\u5185\u5BB9\u4E0D\u80FD\u4E3A\u7A7A");
|
|
4179
4343
|
const createdAt = typeof payload.createdAt === "string" && payload.createdAt !== "" ? payload.createdAt : (/* @__PURE__ */ new Date()).toISOString();
|
|
4180
4344
|
const updated = runtime.projects().addNote(project.id, text2, createdAt);
|
|
4181
|
-
|
|
4345
|
+
runtime.projects().addActivity(project.id, "\u65B0\u589E\u4E00\u6761\u9879\u76EE\u8BB0\u5F55");
|
|
4346
|
+
return {
|
|
4347
|
+
project: updated === void 0 ? null : projectView(runtime.projects().get(project.id) ?? updated)
|
|
4348
|
+
};
|
|
4182
4349
|
});
|
|
4183
4350
|
router.patch("/projects/:id/notes/:noteId", async ({ params, body }) => {
|
|
4184
4351
|
const payload = await body();
|
|
@@ -4222,6 +4389,7 @@ ${note.body}`,
|
|
|
4222
4389
|
runtime.projects().linkNoteTasks(project.id, note.id, [task.id]);
|
|
4223
4390
|
created.push(taskView(task));
|
|
4224
4391
|
}
|
|
4392
|
+
runtime.projects().addActivity(project.id, `\u5C06 ${String(created.length)} \u6761\u8BB0\u5F55\u8F6C\u4E3A\u4EFB\u52A1`);
|
|
4225
4393
|
return {
|
|
4226
4394
|
tasks: created,
|
|
4227
4395
|
project: projectView(runtime.projects().get(project.id) ?? project)
|
|
@@ -4499,6 +4667,7 @@ function projectView(project) {
|
|
|
4499
4667
|
status: project.status,
|
|
4500
4668
|
notes: project.notes.map((note) => ({ ...note, taskIds: [...note.taskIds] })),
|
|
4501
4669
|
milestones: project.milestones.map((milestone) => ({ ...milestone })),
|
|
4670
|
+
activity: project.activity.map((event) => ({ ...event })),
|
|
4502
4671
|
path: project.path,
|
|
4503
4672
|
workspaceId: project.workspaceId,
|
|
4504
4673
|
sessionId: project.sessionId,
|