ework-web 0.10.108 → 0.10.109

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ework-web",
3
- "version": "0.10.108",
3
+ "version": "0.10.109",
4
4
  "type": "module",
5
5
  "description": "ework-web — standalone multi-project issue tracker. Local SQLite-backed, no external API dependency. Bun + TypeScript + SSR HTML.",
6
6
  "license": "MIT",
package/src/index.ts CHANGED
@@ -402,7 +402,7 @@ const REPO_AI_RE = /^\/([^/]+)\/([^/]+)\/settings\/ai$/;
402
402
  const REPO_LABELS_RE = /^\/([^/]+)\/([^/]+)\/settings\/labels$/;
403
403
  const REPO_LABEL_ADD_RE = /^\/([^/]+)\/([^/]+)\/settings\/labels\/add$/;
404
404
  const REPO_LABEL_ACTION_RE = /^\/([^/]+)\/([^/]+)\/settings\/labels\/(\d+)\/(update|archive|unarchive|delete)$/;
405
- const REPO_ISSUE_HALT_RE = /^\/([^/]+)\/([^/]+)\/issues\/(\d+)\/(halt|resume|dispatch-off|dispatch-on)$/;
405
+ const REPO_ISSUE_HALT_RE = /^\/([^/]+)\/([^/]+)\/issues\/(\d+)\/(halt|resume|dispatch-off|dispatch-on|reset-session)$/;
406
406
  const REPO_ISSUE_MODEL_RE = /^\/([^/]+)\/([^/]+)\/issues\/(\d+)\/model$/;
407
407
  const REPO_ISSUE_RUNTIME_RE = /^\/([^/]+)\/([^/]+)\/issues\/(\d+)\/runtime$/;
408
408
  const REPO_ISSUE_STATUS_RE = /^\/([^/]+)\/([^/]+)\/issues\/(\d+)\/ai-status$/;
@@ -611,7 +611,8 @@ async function handle(req: Request, url: URL, ip: string, ctx: { authed: boolean
611
611
  const projectOff = cfgKv[`dispatchOff:${owner}/${repo}`] === "1";
612
612
  const aiStatus = issue?.ai_status ?? "";
613
613
  const issueOff = aiStatus === "dispatch_off" || aiStatus === "halted";
614
- return json({ dispatchOff: globalOff || projectOff || issueOff, aiStatus });
614
+ const sessionResetMs = Number(cfgKv[`sessionReset:${owner}/${repo}#${number}`]) || null;
615
+ return json({ dispatchOff: globalOff || projectOff || issueOff, aiStatus, sessionResetMs });
615
616
  }
616
617
  if (url.pathname === "/api/v1/wake-logins" && req.method === "GET") {
617
618
  const owner = url.searchParams.get("owner") ?? "";
@@ -1911,6 +1912,13 @@ async function handle(req: Request, url: URL, ip: string, ctx: { authed: boolean
1911
1912
  const issue = await getIssueWithMeta(project.id, number);
1912
1913
  if (!issue) return json({ error: "issue not found" }, 404);
1913
1914
  const statusMap: Record<string, string> = { halt: "halted", resume: "", "dispatch-off": "dispatch_off", "dispatch-on": "" };
1915
+ if (action === "reset-session") {
1916
+ if (!(await canAdminProject(project.id, ctx.user))) {
1917
+ return json({ error: "admin role required" }, 403);
1918
+ }
1919
+ await setConfig(`sessionReset:${owner}/${repo}#${number}`, String(Date.now()));
1920
+ return json({ ok: true, reset: true });
1921
+ }
1914
1922
  const newStatus = statusMap[action] ?? "";
1915
1923
  const oldStatus = issue.ai_status ?? "";
1916
1924
  await updateIssueAiStatus(issue.id, newStatus);
@@ -214,6 +214,9 @@ export function renderLayout(props: LayoutProps, inner: string, initialItems: st
214
214
  ? `<button type="button" class="action-btn dispatch-btn" data-action-href="${escapeAttr(repoIssuesHref)}/${props.issueNumber}/dispatch-on" title="允许自动接单">🔔 恢复接单</button>`
215
215
  : `<button type="button" class="action-btn dispatch-btn" data-action-href="${escapeAttr(repoIssuesHref)}/${props.issueNumber}/dispatch-off" data-action-confirm="设为不自动接单?" title="关闭此 issue 的自动接单">🔕 暂停接单</button>`
216
216
  : "";
217
+ const resetBtnHtml = showActions
218
+ ? `<button type="button" class="action-btn dispatch-btn" data-action-href="${escapeAttr(repoIssuesHref)}/${props.issueNumber}/reset-session" data-action-confirm="重置 AI 会话?下次触发将从全新会话开始(历史评论保留)" title="重置 AI 会话(下次触发开新会话)">🔄 重置会话</button>`
219
+ : "";
217
220
  const runtimeSelectHtml = props.runtimeSelect && showActions
218
221
  ? `<span class="model-select-wrap"><select class="model-select" id="issueRuntimeSelect" title="此 issue 的运行时(新会话生效)">
219
222
  <option value="" ${props.runtimeSelect.current === "" ? "selected" : ""}>默认运行时</option>
@@ -251,7 +254,7 @@ export function renderLayout(props: LayoutProps, inner: string, initialItems: st
251
254
  <div class="meta-status">
252
255
  <span class="state-badge ${stateClass}">${stateLabel}</span>
253
256
  ${aiBadgeHtml}
254
- ${(haltBtnHtml || dispatchBtnHtml || (props.customActions ?? []).length) ? `<span class="action-group">${haltBtnHtml}${dispatchBtnHtml}${runtimeSelectHtml}${modelSelectHtml}${(props.customActions ?? []).map((a) => {
257
+ ${(haltBtnHtml || dispatchBtnHtml || (props.customActions ?? []).length) ? `<span class="action-group">${haltBtnHtml}${dispatchBtnHtml}${resetBtnHtml}${runtimeSelectHtml}${modelSelectHtml}${(props.customActions ?? []).map((a) => {
255
258
  const attrs = [`data-action-href="${escapeAttr(a.href)}"`];
256
259
  if (a.method && a.method !== "POST") attrs.push(`data-action-method="${escapeAttr(a.method)}"`);
257
260
  if (a.confirm) attrs.push(`data-action-confirm="${escapeAttr(a.confirm)}"`);