@zaclinley/dsh-mailharbor 0.22.1 → 0.23.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 +29 -0
- package/README.zh.md +17 -17
- package/lib/client.js +1508 -1004
- package/lib/client.js.map +4 -4
- package/lib/index.js +222 -40
- package/lib/index.js.map +3 -3
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -1609,6 +1609,20 @@ var MailDatabase = class {
|
|
|
1609
1609
|
return 0;
|
|
1610
1610
|
}
|
|
1611
1611
|
}
|
|
1612
|
+
/** Recover To/Cc from raw headers when the stored summary is empty. */
|
|
1613
|
+
recipientsFromRaw(raw) {
|
|
1614
|
+
const text2 = Buffer.from(raw.subarray(0, Math.min(raw.byteLength, 3e5))).toString("utf8");
|
|
1615
|
+
const separator = text2.search(/\r?\n\r?\n/);
|
|
1616
|
+
const head = (separator >= 0 ? text2.slice(0, separator) : text2).replace(/\r?\n[ \t]+/g, " ");
|
|
1617
|
+
const value = (name2) => {
|
|
1618
|
+
const match = new RegExp(`^${name2}:\\s*(.*)$`, "im").exec(head);
|
|
1619
|
+
return match === null ? "" : String(match[1] ?? "");
|
|
1620
|
+
};
|
|
1621
|
+
const to = parseAddressList(
|
|
1622
|
+
value("to") || value("delivered-to") || value("x-original-to") || value("apparently-to")
|
|
1623
|
+
);
|
|
1624
|
+
return { to, cc: parseAddressList(value("cc")) };
|
|
1625
|
+
}
|
|
1612
1626
|
get(localId) {
|
|
1613
1627
|
const db = this.open();
|
|
1614
1628
|
const row = db.prepare(
|
|
@@ -1642,6 +1656,19 @@ var MailDatabase = class {
|
|
|
1642
1656
|
size: Number(item.size ?? 0)
|
|
1643
1657
|
}));
|
|
1644
1658
|
const max = this.options.maxBodyChars ?? 4e5;
|
|
1659
|
+
let to = parseAddressList(String(row.to_addr ?? ""));
|
|
1660
|
+
let cc = parseAddressList(String(row.cc ?? ""));
|
|
1661
|
+
if (to.length === 0) {
|
|
1662
|
+
try {
|
|
1663
|
+
const raw = db.prepare("SELECT raw_eml FROM emails WHERE id = ?").get(localId)?.raw_eml;
|
|
1664
|
+
if (raw instanceof Uint8Array) {
|
|
1665
|
+
const recovered = this.recipientsFromRaw(raw);
|
|
1666
|
+
to = recovered.to;
|
|
1667
|
+
if (cc.length === 0) cc = recovered.cc;
|
|
1668
|
+
}
|
|
1669
|
+
} catch {
|
|
1670
|
+
}
|
|
1671
|
+
}
|
|
1645
1672
|
const bodyText2 = String(row.body_text ?? "");
|
|
1646
1673
|
const inlineImages = wantsInline ? rows.filter(
|
|
1647
1674
|
(item) => String(item.content_type ?? "").toLowerCase().startsWith("image/")
|
|
@@ -1653,7 +1680,8 @@ var MailDatabase = class {
|
|
|
1653
1680
|
})).filter((item) => item.data !== void 0) : [];
|
|
1654
1681
|
return {
|
|
1655
1682
|
...rowToSummary(row),
|
|
1656
|
-
|
|
1683
|
+
to,
|
|
1684
|
+
cc,
|
|
1657
1685
|
replyTo: [],
|
|
1658
1686
|
text: truncate(bodyText2, max),
|
|
1659
1687
|
html: bodyHtml === "" ? null : truncate(inlineCidImages(bodyHtml, inlineImages), max * 2),
|
|
@@ -2923,7 +2951,16 @@ var ProjectStore = class {
|
|
|
2923
2951
|
parsed = null;
|
|
2924
2952
|
}
|
|
2925
2953
|
const projects = parsed !== null && typeof parsed === "object" && Array.isArray(parsed.projects) ? parsed.projects : [];
|
|
2926
|
-
this.cache = {
|
|
2954
|
+
this.cache = {
|
|
2955
|
+
version: 2,
|
|
2956
|
+
projects: projects.filter(isProject).map((project) => ({
|
|
2957
|
+
...project,
|
|
2958
|
+
status: project.status ?? "active",
|
|
2959
|
+
notes: Array.isArray(project.notes) ? project.notes : [],
|
|
2960
|
+
milestones: Array.isArray(project.milestones) ? project.milestones : [],
|
|
2961
|
+
sessionIds: Array.isArray(project.sessionIds) ? project.sessionIds : project.sessionId === "" ? [] : [project.sessionId]
|
|
2962
|
+
}))
|
|
2963
|
+
};
|
|
2927
2964
|
return this.cache;
|
|
2928
2965
|
}
|
|
2929
2966
|
flush() {
|
|
@@ -2978,6 +3015,48 @@ var ProjectStore = class {
|
|
|
2978
3015
|
this.flush();
|
|
2979
3016
|
return project;
|
|
2980
3017
|
}
|
|
3018
|
+
addNote(id, body, createdAt) {
|
|
3019
|
+
const project = this.get(id);
|
|
3020
|
+
if (project === void 0) return void 0;
|
|
3021
|
+
const note = {
|
|
3022
|
+
id: `note_${randomUUID2().slice(0, 8)}`,
|
|
3023
|
+
body,
|
|
3024
|
+
createdAt,
|
|
3025
|
+
taskIds: []
|
|
3026
|
+
};
|
|
3027
|
+
project.notes.unshift(note);
|
|
3028
|
+
project.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
3029
|
+
this.flush();
|
|
3030
|
+
return project;
|
|
3031
|
+
}
|
|
3032
|
+
updateNote(id, noteId, body, createdAt) {
|
|
3033
|
+
const project = this.get(id);
|
|
3034
|
+
const note = project?.notes.find((item) => item.id === noteId);
|
|
3035
|
+
if (project === void 0 || note === void 0) return void 0;
|
|
3036
|
+
note.body = body;
|
|
3037
|
+
note.createdAt = createdAt;
|
|
3038
|
+
note.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
3039
|
+
project.updatedAt = note.updatedAt;
|
|
3040
|
+
this.flush();
|
|
3041
|
+
return project;
|
|
3042
|
+
}
|
|
3043
|
+
removeNote(id, noteId) {
|
|
3044
|
+
const project = this.get(id);
|
|
3045
|
+
if (project === void 0) return void 0;
|
|
3046
|
+
project.notes = project.notes.filter((item) => item.id !== noteId);
|
|
3047
|
+
project.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
3048
|
+
this.flush();
|
|
3049
|
+
return project;
|
|
3050
|
+
}
|
|
3051
|
+
linkNoteTasks(id, noteId, taskIds) {
|
|
3052
|
+
const project = this.get(id);
|
|
3053
|
+
const note = project?.notes.find((item) => item.id === noteId);
|
|
3054
|
+
if (project === void 0 || note === void 0) return void 0;
|
|
3055
|
+
note.taskIds = [.../* @__PURE__ */ new Set([...note.taskIds, ...taskIds])];
|
|
3056
|
+
project.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
3057
|
+
this.flush();
|
|
3058
|
+
return project;
|
|
3059
|
+
}
|
|
2981
3060
|
remove(id) {
|
|
2982
3061
|
const data = this.load();
|
|
2983
3062
|
const index = data.projects.findIndex((project) => project.id === id);
|
|
@@ -3038,35 +3117,17 @@ async function createProject(options) {
|
|
|
3038
3117
|
} else {
|
|
3039
3118
|
warnings.push("\u5F53\u524D DSH \u7EC4\u5408\u6CA1\u6709 workspaceRegistry\uFF0C\u9879\u76EE\u76EE\u5F55\u5DF2\u521B\u5EFA\u4F46\u6CA1\u6709\u6CE8\u518C\u5230\u4FA7\u680F");
|
|
3040
3119
|
}
|
|
3041
|
-
|
|
3042
|
-
if (options.sessions !== void 0) {
|
|
3043
|
-
try {
|
|
3044
|
-
sessionId = randomUUID2();
|
|
3045
|
-
const session = options.sessions.create(sessionId, { meta: { cwd: path } });
|
|
3046
|
-
session.append(
|
|
3047
|
-
"user/message",
|
|
3048
|
-
{
|
|
3049
|
-
role: "user",
|
|
3050
|
-
content: [{ type: "text", text: `\u6211\u521B\u5EFA\u4E86\u4E00\u4E2A\u90AE\u4EF6\u9879\u76EE\u300C${name2}\u300D\u3002
|
|
3051
|
-
|
|
3052
|
-
${brief}` }],
|
|
3053
|
-
source: { kind: "user" }
|
|
3054
|
-
},
|
|
3055
|
-
{ surfaceOp: "append" }
|
|
3056
|
-
);
|
|
3057
|
-
} catch (error) {
|
|
3058
|
-
warnings.push(`\u4F1A\u8BDD\u521B\u5EFA\u5931\u8D25\uFF1A${error instanceof Error ? error.message : String(error)}`);
|
|
3059
|
-
sessionId = "";
|
|
3060
|
-
}
|
|
3061
|
-
} else {
|
|
3062
|
-
warnings.push("\u5F53\u524D DSH \u7EC4\u5408\u6CA1\u6709 sessions \u670D\u52A1\uFF0C\u672A\u521B\u5EFA\u9879\u76EE\u4F1A\u8BDD");
|
|
3063
|
-
}
|
|
3120
|
+
const sessionId = "";
|
|
3064
3121
|
const project = {
|
|
3065
3122
|
id,
|
|
3066
3123
|
name: name2,
|
|
3124
|
+
status: "active",
|
|
3125
|
+
notes: [],
|
|
3126
|
+
milestones: [],
|
|
3067
3127
|
path,
|
|
3068
3128
|
workspaceId,
|
|
3069
3129
|
sessionId,
|
|
3130
|
+
sessionIds: sessionId === "" ? [] : [sessionId],
|
|
3070
3131
|
accountIds: [input.accountId],
|
|
3071
3132
|
messages: input.message === void 0 ? [] : [input.message],
|
|
3072
3133
|
threads: input.thread === void 0 ? [] : [input.thread],
|
|
@@ -3124,7 +3185,7 @@ ${conversation.trim()}
|
|
|
3124
3185
|
}
|
|
3125
3186
|
|
|
3126
3187
|
// src/host/version.ts
|
|
3127
|
-
var VERSION = "0.
|
|
3188
|
+
var VERSION = "0.23.0";
|
|
3128
3189
|
|
|
3129
3190
|
// src/host/api.ts
|
|
3130
3191
|
init_smtp();
|
|
@@ -3949,10 +4010,12 @@ function buildRouter(runtime) {
|
|
|
3949
4010
|
title: String(payload.title ?? ""),
|
|
3950
4011
|
notes: typeof payload.notes === "string" ? payload.notes : "",
|
|
3951
4012
|
due: typeof payload.due === "string" ? payload.due : "",
|
|
3952
|
-
status: typeof payload.status === "string" ? payload.status : "
|
|
4013
|
+
status: typeof payload.status === "string" ? payload.status : "TODO",
|
|
3953
4014
|
priority: Number(payload.priority ?? 0),
|
|
3954
4015
|
owner: typeof payload.owner === "string" ? payload.owner : "",
|
|
3955
4016
|
projectId: typeof payload.projectId === "string" ? payload.projectId : null,
|
|
4017
|
+
parentId: typeof payload.parentId === "string" && payload.parentId !== "" ? payload.parentId : null,
|
|
4018
|
+
waitingOn: typeof payload.waitingOn === "string" ? payload.waitingOn : "",
|
|
3956
4019
|
messageKey: typeof payload.messageKey === "string" ? payload.messageKey : "",
|
|
3957
4020
|
messageSubject: typeof payload.messageSubject === "string" ? payload.messageSubject : ""
|
|
3958
4021
|
});
|
|
@@ -3967,7 +4030,9 @@ function buildRouter(runtime) {
|
|
|
3967
4030
|
...typeof payload.status === "string" ? { status: payload.status } : {},
|
|
3968
4031
|
...typeof payload.priority === "number" ? { priority: payload.priority } : {},
|
|
3969
4032
|
...typeof payload.owner === "string" ? { owner: payload.owner } : {},
|
|
3970
|
-
...payload.projectId === null || typeof payload.projectId === "string" ? { projectId: payload.projectId } : {}
|
|
4033
|
+
...payload.projectId === null || typeof payload.projectId === "string" ? { projectId: payload.projectId } : {},
|
|
4034
|
+
...payload.parentId === null || typeof payload.parentId === "string" ? { parentId: payload.parentId } : {},
|
|
4035
|
+
...typeof payload.waitingOn === "string" ? { waitingOn: payload.waitingOn } : {}
|
|
3971
4036
|
});
|
|
3972
4037
|
return { task: taskView(task) };
|
|
3973
4038
|
});
|
|
@@ -4023,8 +4088,10 @@ function buildRouter(runtime) {
|
|
|
4023
4088
|
for (const task of runtime.tasks().list({ accountId: account.id })) {
|
|
4024
4089
|
const projectId = task.projectId ?? "";
|
|
4025
4090
|
if (projectId === "") continue;
|
|
4026
|
-
const entry = counts.get(projectId) ?? { total: 0, done: 0 };
|
|
4091
|
+
const entry = counts.get(projectId) ?? { total: 0, todo: 0, waiting: 0, done: 0 };
|
|
4027
4092
|
entry.total += 1;
|
|
4093
|
+
if (task.status === "TODO" || task.status === "IN-PROCESS") entry.todo += 1;
|
|
4094
|
+
if (task.status === "WAITING") entry.waiting += 1;
|
|
4028
4095
|
if (task.status === "COMPLETED") entry.done += 1;
|
|
4029
4096
|
counts.set(projectId, entry);
|
|
4030
4097
|
}
|
|
@@ -4032,7 +4099,13 @@ function buildRouter(runtime) {
|
|
|
4032
4099
|
return {
|
|
4033
4100
|
items: runtime.projects().list().map((project) => {
|
|
4034
4101
|
const stat = counts.get(project.id);
|
|
4035
|
-
return {
|
|
4102
|
+
return {
|
|
4103
|
+
...projectView(project),
|
|
4104
|
+
taskTotal: stat?.total ?? 0,
|
|
4105
|
+
taskTodo: stat?.todo ?? 0,
|
|
4106
|
+
taskWaiting: stat?.waiting ?? 0,
|
|
4107
|
+
taskDone: stat?.done ?? 0
|
|
4108
|
+
};
|
|
4036
4109
|
})
|
|
4037
4110
|
};
|
|
4038
4111
|
});
|
|
@@ -4082,12 +4155,78 @@ function buildRouter(runtime) {
|
|
|
4082
4155
|
});
|
|
4083
4156
|
router.patch("/projects/:id", async ({ params, body }) => {
|
|
4084
4157
|
const payload = await body();
|
|
4085
|
-
const
|
|
4086
|
-
if (
|
|
4087
|
-
|
|
4158
|
+
const patch = {};
|
|
4159
|
+
if (typeof payload.name === "string") {
|
|
4160
|
+
const name2 = payload.name.trim();
|
|
4161
|
+
if (name2 === "") throw new HttpError(400, "\u9879\u76EE\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A");
|
|
4162
|
+
patch.name = name2;
|
|
4163
|
+
}
|
|
4164
|
+
if (typeof payload.status === "string") {
|
|
4165
|
+
const allowed = ["active", "paused", "done", "archived"];
|
|
4166
|
+
if (!allowed.includes(payload.status)) throw new HttpError(400, "\u9879\u76EE\u72B6\u6001\u4E0D\u6B63\u786E");
|
|
4167
|
+
patch.status = payload.status;
|
|
4168
|
+
}
|
|
4169
|
+
const project = runtime.projects().update(String(params.id ?? ""), patch);
|
|
4170
|
+
if (project === void 0) throw new HttpError(404, "\u9879\u76EE\u4E0D\u5B58\u5728");
|
|
4171
|
+
return { project: projectView(project) };
|
|
4172
|
+
});
|
|
4173
|
+
router.post("/projects/:id/notes", async ({ params, body }) => {
|
|
4174
|
+
const payload = await body();
|
|
4175
|
+
const project = runtime.projects().get(String(params.id ?? ""));
|
|
4176
|
+
if (project === void 0) throw new HttpError(404, "\u9879\u76EE\u4E0D\u5B58\u5728");
|
|
4177
|
+
const text2 = String(payload.body ?? "").trim();
|
|
4178
|
+
if (text2 === "") throw new HttpError(400, "\u8BB0\u5F55\u5185\u5BB9\u4E0D\u80FD\u4E3A\u7A7A");
|
|
4179
|
+
const createdAt = typeof payload.createdAt === "string" && payload.createdAt !== "" ? payload.createdAt : (/* @__PURE__ */ new Date()).toISOString();
|
|
4180
|
+
const updated = runtime.projects().addNote(project.id, text2, createdAt);
|
|
4181
|
+
return { project: updated === void 0 ? null : projectView(updated) };
|
|
4182
|
+
});
|
|
4183
|
+
router.patch("/projects/:id/notes/:noteId", async ({ params, body }) => {
|
|
4184
|
+
const payload = await body();
|
|
4185
|
+
const project = runtime.projects().get(String(params.id ?? ""));
|
|
4088
4186
|
if (project === void 0) throw new HttpError(404, "\u9879\u76EE\u4E0D\u5B58\u5728");
|
|
4187
|
+
const text2 = String(payload.body ?? "").trim();
|
|
4188
|
+
if (text2 === "") throw new HttpError(400, "\u8BB0\u5F55\u5185\u5BB9\u4E0D\u80FD\u4E3A\u7A7A");
|
|
4189
|
+
const createdAt = typeof payload.createdAt === "string" && payload.createdAt !== "" ? payload.createdAt : (/* @__PURE__ */ new Date()).toISOString();
|
|
4190
|
+
const updated = runtime.projects().updateNote(project.id, String(params.noteId ?? ""), text2, createdAt);
|
|
4191
|
+
if (updated === void 0) throw new HttpError(404, "\u8BB0\u5F55\u4E0D\u5B58\u5728");
|
|
4192
|
+
return { project: projectView(updated) };
|
|
4193
|
+
});
|
|
4194
|
+
router.delete("/projects/:id/notes/:noteId", ({ params }) => {
|
|
4195
|
+
const project = runtime.projects().removeNote(String(params.id ?? ""), String(params.noteId ?? ""));
|
|
4196
|
+
if (project === void 0) throw new HttpError(404, "\u8BB0\u5F55\u4E0D\u5B58\u5728");
|
|
4089
4197
|
return { project: projectView(project) };
|
|
4090
4198
|
});
|
|
4199
|
+
router.post("/projects/:id/notes/convert", async ({ params, body }) => {
|
|
4200
|
+
const payload = await body();
|
|
4201
|
+
const project = runtime.projects().get(String(params.id ?? ""));
|
|
4202
|
+
if (project === void 0) throw new HttpError(404, "\u9879\u76EE\u4E0D\u5B58\u5728");
|
|
4203
|
+
const noteIds = Array.isArray(payload.noteIds) ? payload.noteIds.filter((id) => typeof id === "string") : [];
|
|
4204
|
+
if (noteIds.length === 0) throw new HttpError(400, "\u8BF7\u9009\u62E9\u8981\u8F6C\u6362\u7684\u8BB0\u5F55");
|
|
4205
|
+
const accountId = typeof payload.accountId === "string" && payload.accountId !== "" ? payload.accountId : project.accountIds[0] ?? "";
|
|
4206
|
+
if (accountId === "") throw new HttpError(400, "\u9879\u76EE\u6CA1\u6709\u5173\u8054\u8D26\u53F7");
|
|
4207
|
+
const created = [];
|
|
4208
|
+
for (const noteId of noteIds) {
|
|
4209
|
+
const note = project.notes.find((item) => item.id === noteId);
|
|
4210
|
+
if (note === void 0) continue;
|
|
4211
|
+
const first = note.body.split("\n").map((line2) => line2.trim()).find((line2) => line2 !== "") ?? "\u9879\u76EE\u8BB0\u5F55";
|
|
4212
|
+
const title = first.replace(/^#+\s*/, "").slice(0, 120);
|
|
4213
|
+
const task = runtime.tasks().create({
|
|
4214
|
+
accountId,
|
|
4215
|
+
title,
|
|
4216
|
+
notes: `\u6765\u81EA\u9879\u76EE\u8BB0\u5F55 ${note.createdAt.slice(0, 10)}
|
|
4217
|
+
|
|
4218
|
+
${note.body}`,
|
|
4219
|
+
status: "TODO",
|
|
4220
|
+
projectId: project.id
|
|
4221
|
+
});
|
|
4222
|
+
runtime.projects().linkNoteTasks(project.id, note.id, [task.id]);
|
|
4223
|
+
created.push(taskView(task));
|
|
4224
|
+
}
|
|
4225
|
+
return {
|
|
4226
|
+
tasks: created,
|
|
4227
|
+
project: projectView(runtime.projects().get(project.id) ?? project)
|
|
4228
|
+
};
|
|
4229
|
+
});
|
|
4091
4230
|
router.delete("/projects/:id", async ({ params, url }) => {
|
|
4092
4231
|
const id = String(params.id ?? "");
|
|
4093
4232
|
const project = runtime.projects().get(id);
|
|
@@ -4337,10 +4476,12 @@ function taskView(task) {
|
|
|
4337
4476
|
id: task.id,
|
|
4338
4477
|
accountId: task.accountId,
|
|
4339
4478
|
projectId: task.projectId,
|
|
4479
|
+
parentId: task.parentId,
|
|
4340
4480
|
title: task.title,
|
|
4341
4481
|
notes: task.notes,
|
|
4342
4482
|
due: task.due,
|
|
4343
4483
|
status: task.status,
|
|
4484
|
+
waitingOn: task.waitingOn,
|
|
4344
4485
|
priority: task.priority,
|
|
4345
4486
|
owner: task.owner,
|
|
4346
4487
|
messageKey: task.messageKey,
|
|
@@ -4355,9 +4496,13 @@ function projectView(project) {
|
|
|
4355
4496
|
return {
|
|
4356
4497
|
id: project.id,
|
|
4357
4498
|
name: project.name,
|
|
4499
|
+
status: project.status,
|
|
4500
|
+
notes: project.notes.map((note) => ({ ...note, taskIds: [...note.taskIds] })),
|
|
4501
|
+
milestones: project.milestones.map((milestone) => ({ ...milestone })),
|
|
4358
4502
|
path: project.path,
|
|
4359
4503
|
workspaceId: project.workspaceId,
|
|
4360
4504
|
sessionId: project.sessionId,
|
|
4505
|
+
sessionIds: [...project.sessionIds],
|
|
4361
4506
|
accountIds: [...project.accountIds],
|
|
4362
4507
|
messages: project.messages.map((message) => ({ ...message })),
|
|
4363
4508
|
threads: project.threads.map((thread) => ({ ...thread })),
|
|
@@ -5011,7 +5156,7 @@ import { randomUUID as randomUUID5 } from "node:crypto";
|
|
|
5011
5156
|
import { mkdirSync as mkdirSync9 } from "node:fs";
|
|
5012
5157
|
import { dirname as dirname5 } from "node:path";
|
|
5013
5158
|
import { DatabaseSync as DatabaseSync5 } from "node:sqlite";
|
|
5014
|
-
var STATUSES = /* @__PURE__ */ new Set(["
|
|
5159
|
+
var STATUSES = /* @__PURE__ */ new Set(["TODO", "IN-PROCESS", "WAITING", "COMPLETED", "CANCELLED"]);
|
|
5015
5160
|
function now() {
|
|
5016
5161
|
return (/* @__PURE__ */ new Date()).toISOString();
|
|
5017
5162
|
}
|
|
@@ -5021,6 +5166,8 @@ function rowToTask(row) {
|
|
|
5021
5166
|
id: String(row.id),
|
|
5022
5167
|
accountId: String(row.account_id),
|
|
5023
5168
|
projectId: row.project_id === null || row.project_id === void 0 ? null : String(row.project_id),
|
|
5169
|
+
parentId: row.parent_id === null || row.parent_id === void 0 ? null : String(row.parent_id),
|
|
5170
|
+
waitingOn: String(row.waiting_on ?? ""),
|
|
5024
5171
|
calendarHref: row.calendar_href === null || row.calendar_href === void 0 ? null : String(row.calendar_href),
|
|
5025
5172
|
href: row.href === null || row.href === void 0 ? null : String(row.href),
|
|
5026
5173
|
etag: row.etag === null || row.etag === void 0 ? null : String(row.etag),
|
|
@@ -5041,8 +5188,9 @@ function rowToTask(row) {
|
|
|
5041
5188
|
};
|
|
5042
5189
|
}
|
|
5043
5190
|
function statusOf(value) {
|
|
5044
|
-
const text2 = String(value ?? "
|
|
5045
|
-
|
|
5191
|
+
const text2 = String(value ?? "TODO").toUpperCase();
|
|
5192
|
+
if (text2 === "NEEDS-ACTION") return "TODO";
|
|
5193
|
+
return STATUSES.has(text2) ? text2 : "TODO";
|
|
5046
5194
|
}
|
|
5047
5195
|
var TaskStore = class {
|
|
5048
5196
|
file;
|
|
@@ -5067,6 +5215,8 @@ var TaskStore = class {
|
|
|
5067
5215
|
id TEXT PRIMARY KEY,
|
|
5068
5216
|
account_id TEXT NOT NULL,
|
|
5069
5217
|
project_id TEXT,
|
|
5218
|
+
parent_id TEXT,
|
|
5219
|
+
waiting_on TEXT,
|
|
5070
5220
|
calendar_href TEXT,
|
|
5071
5221
|
href TEXT,
|
|
5072
5222
|
etag TEXT,
|
|
@@ -5096,6 +5246,14 @@ var TaskStore = class {
|
|
|
5096
5246
|
error TEXT
|
|
5097
5247
|
);
|
|
5098
5248
|
`);
|
|
5249
|
+
const columns = db.prepare("PRAGMA table_info(tasks)").all();
|
|
5250
|
+
if (!columns.some((column) => column.name === "parent_id")) {
|
|
5251
|
+
db.exec("ALTER TABLE tasks ADD COLUMN parent_id TEXT");
|
|
5252
|
+
}
|
|
5253
|
+
if (!columns.some((column) => column.name === "waiting_on")) {
|
|
5254
|
+
db.exec("ALTER TABLE tasks ADD COLUMN waiting_on TEXT");
|
|
5255
|
+
}
|
|
5256
|
+
db.exec("UPDATE tasks SET status = 'TODO' WHERE status = 'NEEDS-ACTION'");
|
|
5099
5257
|
this.db = db;
|
|
5100
5258
|
return db;
|
|
5101
5259
|
}
|
|
@@ -5135,16 +5293,26 @@ var TaskStore = class {
|
|
|
5135
5293
|
if (title === "") throw new Error("\u4EFB\u52A1\u6807\u9898\u4E0D\u80FD\u4E3A\u7A7A");
|
|
5136
5294
|
if (title.length > 300) throw new Error("\u4EFB\u52A1\u6807\u9898\u8FC7\u957F");
|
|
5137
5295
|
const status = statusOf(input.status);
|
|
5296
|
+
if (status === "WAITING" && String(input.waitingOn ?? "").trim() === "") {
|
|
5297
|
+
throw new Error("\u7B49\u5F85\u4E2D\u4EFB\u52A1\u9700\u8981\u586B\u5199\u7B49\u8C01/\u7B49\u4EC0\u4E48");
|
|
5298
|
+
}
|
|
5299
|
+
if (input.parentId !== void 0 && input.parentId !== null) {
|
|
5300
|
+
const parent = this.get(input.parentId);
|
|
5301
|
+
if (parent === void 0) throw new Error("\u7236\u4EFB\u52A1\u4E0D\u5B58\u5728");
|
|
5302
|
+
if (parent.parentId !== null) throw new Error("\u5B50\u4EFB\u52A1\u4E0B\u4E0D\u80FD\u518D\u5EFA\u5B50\u4EFB\u52A1");
|
|
5303
|
+
}
|
|
5138
5304
|
const id = `task_${randomUUID5()}`;
|
|
5139
5305
|
const stamp3 = now();
|
|
5140
5306
|
this.open().prepare(
|
|
5141
|
-
`INSERT INTO tasks (id, account_id, project_id, uid, title, notes, due, status,
|
|
5142
|
-
message_key, message_subject, completed_at, dirty, deleted, created_at, updated_at)
|
|
5143
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, 0, ?, ?)`
|
|
5307
|
+
`INSERT INTO tasks (id, account_id, project_id, parent_id, waiting_on, uid, title, notes, due, status,
|
|
5308
|
+
priority, owner, message_key, message_subject, completed_at, dirty, deleted, created_at, updated_at)
|
|
5309
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, 0, ?, ?)`
|
|
5144
5310
|
).run(
|
|
5145
5311
|
id,
|
|
5146
5312
|
input.accountId,
|
|
5147
5313
|
input.projectId ?? null,
|
|
5314
|
+
input.parentId ?? null,
|
|
5315
|
+
String(input.waitingOn ?? ""),
|
|
5148
5316
|
`${randomUUID5()}@dsh-mailharbor`,
|
|
5149
5317
|
title,
|
|
5150
5318
|
String(input.notes ?? ""),
|
|
@@ -5173,15 +5341,27 @@ var TaskStore = class {
|
|
|
5173
5341
|
priority: fields.priority === void 0 ? current.priority : Number(fields.priority),
|
|
5174
5342
|
owner: fields.owner === void 0 ? current.owner : String(fields.owner ?? ""),
|
|
5175
5343
|
projectId: fields.projectId === void 0 ? current.projectId : fields.projectId,
|
|
5344
|
+
parentId: fields.parentId === void 0 ? current.parentId : fields.parentId,
|
|
5345
|
+
waitingOn: fields.waitingOn === void 0 ? current.waitingOn : String(fields.waitingOn ?? ""),
|
|
5176
5346
|
messageKey: fields.messageKey === void 0 ? current.messageKey : String(fields.messageKey),
|
|
5177
5347
|
messageSubject: fields.messageSubject === void 0 ? current.messageSubject : String(fields.messageSubject)
|
|
5178
5348
|
};
|
|
5179
5349
|
if (next.title === "") throw new Error("\u4EFB\u52A1\u6807\u9898\u4E0D\u80FD\u4E3A\u7A7A");
|
|
5350
|
+
if (next.status === "WAITING" && next.waitingOn.trim() === "") {
|
|
5351
|
+
throw new Error("\u7B49\u5F85\u4E2D\u4EFB\u52A1\u9700\u8981\u586B\u5199\u7B49\u8C01/\u7B49\u4EC0\u4E48");
|
|
5352
|
+
}
|
|
5353
|
+
if (next.parentId !== null) {
|
|
5354
|
+
if (next.parentId === id) throw new Error("\u4EFB\u52A1\u4E0D\u80FD\u4F5C\u4E3A\u81EA\u5DF1\u7684\u5B50\u4EFB\u52A1");
|
|
5355
|
+
const parent = this.get(next.parentId);
|
|
5356
|
+
if (parent === void 0) throw new Error("\u7236\u4EFB\u52A1\u4E0D\u5B58\u5728");
|
|
5357
|
+
if (parent.parentId !== null) throw new Error("\u5B50\u4EFB\u52A1\u4E0B\u4E0D\u80FD\u518D\u5EFA\u5B50\u4EFB\u52A1");
|
|
5358
|
+
}
|
|
5180
5359
|
const stamp3 = now();
|
|
5181
5360
|
const completedAt = next.status === "COMPLETED" ? current.completedAt ?? stamp3 : null;
|
|
5182
5361
|
this.open().prepare(
|
|
5183
5362
|
`UPDATE tasks SET title = ?, notes = ?, due = ?, status = ?, priority = ?, owner = ?, project_id = ?,
|
|
5184
|
-
|
|
5363
|
+
parent_id = ?, waiting_on = ?, message_key = ?, message_subject = ?, completed_at = ?,
|
|
5364
|
+
dirty = 1, updated_at = ? WHERE id = ?`
|
|
5185
5365
|
).run(
|
|
5186
5366
|
next.title,
|
|
5187
5367
|
next.notes,
|
|
@@ -5190,6 +5370,8 @@ var TaskStore = class {
|
|
|
5190
5370
|
Math.max(0, Math.min(9, Number(next.priority) || 0)),
|
|
5191
5371
|
next.owner,
|
|
5192
5372
|
next.projectId,
|
|
5373
|
+
next.parentId,
|
|
5374
|
+
next.waitingOn,
|
|
5193
5375
|
next.messageKey,
|
|
5194
5376
|
next.messageSubject,
|
|
5195
5377
|
completedAt,
|