ework-web 0.10.62 → 0.10.63
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 +1 -1
- package/src/coordination.ts +36 -0
- package/src/index.ts +11 -6
- package/src/webhooks.ts +1 -1
package/package.json
CHANGED
package/src/coordination.ts
CHANGED
|
@@ -118,3 +118,39 @@ export async function resolveDaemonEndpoint(daemonId: number): Promise<string |
|
|
|
118
118
|
return null;
|
|
119
119
|
}
|
|
120
120
|
}
|
|
121
|
+
|
|
122
|
+
export interface RunningSessionInfo {
|
|
123
|
+
issueNumber: string;
|
|
124
|
+
sessionId: string;
|
|
125
|
+
daemonId: number;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Query daemon DB for sessions with state='running' belonging to a specific project scope.
|
|
130
|
+
* Uses REAL daemon session state instead of the display-only ai_status field.
|
|
131
|
+
*/
|
|
132
|
+
export async function getRunningSessionsForProject(scopeKey: string): Promise<RunningSessionInfo[]> {
|
|
133
|
+
try {
|
|
134
|
+
const rows = await getDB().all<{
|
|
135
|
+
tracker_issue_id: string;
|
|
136
|
+
opencode_session_id: string;
|
|
137
|
+
daemon_id: number;
|
|
138
|
+
}>(
|
|
139
|
+
`SELECT i.tracker_issue_id, s.opencode_session_id, i.owner_daemon_id AS daemon_id
|
|
140
|
+
FROM {{d_op_sessions}} s
|
|
141
|
+
JOIN {{d_issues}} i ON i.uid = s.issue_id
|
|
142
|
+
WHERE s.state = 'running'
|
|
143
|
+
AND i.tracker_scope_key = ?
|
|
144
|
+
AND s.opencode_session_id IS NOT NULL`,
|
|
145
|
+
[scopeKey],
|
|
146
|
+
);
|
|
147
|
+
return rows.map((r) => ({
|
|
148
|
+
issueNumber: r.tracker_issue_id,
|
|
149
|
+
sessionId: r.opencode_session_id,
|
|
150
|
+
daemonId: r.daemon_id,
|
|
151
|
+
}));
|
|
152
|
+
} catch (e) {
|
|
153
|
+
log.info(`coordination: running-sessions query failed (${e instanceof Error ? e.message : String(e)})`);
|
|
154
|
+
return [];
|
|
155
|
+
}
|
|
156
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -6,7 +6,7 @@ import { homedir } from "os";
|
|
|
6
6
|
import { loadConfig, DB_OVERRIDABLE, parseOverride, resolveTtsBackend } from "./config";
|
|
7
7
|
import type { Config } from "./config";
|
|
8
8
|
import { setConfig, deleteConfig, getConfigAll, initDB, getDB } from "./db";
|
|
9
|
-
import { getActiveDaemons, listAllDaemons, getSessionDaemonMap, resolveDaemonEndpoint } from "./coordination";
|
|
9
|
+
import { getActiveDaemons, listAllDaemons, getSessionDaemonMap, resolveDaemonEndpoint, getRunningSessionsForProject } from "./coordination";
|
|
10
10
|
import { testMysqlConnection, migrateSqliteToMysql, writeMysqlEnv, migrateMysqlToSqlite, writeSqliteEnv, migrateDaemonSqliteToMysql, generateMysqlDDL } from "./db-admin";
|
|
11
11
|
import type { MysqlTargetOpts } from "./db-admin";
|
|
12
12
|
import { checkAuth, makeAuthCookieHeader, clearAuthCookieHeader, loginHTML, sanitizeNext, ensureBootstrapAdmin, ensureBootstrapSystem, isReservedSystemLogin } from "./auth";
|
|
@@ -1994,12 +1994,17 @@ async function handle(req: Request, url: URL, ip: string, ctx: { authed: boolean
|
|
|
1994
1994
|
return Response.redirect(`${back}?err=${encodeURIComponent("无权限")}`, 303);
|
|
1995
1995
|
}
|
|
1996
1996
|
const issues = await listIssues(project.id, { state: "all" });
|
|
1997
|
-
const
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
1997
|
+
const running = await getRunningSessionsForProject(`${owner}/${repo}`);
|
|
1998
|
+
const issueIds = new Set<number>();
|
|
1999
|
+
for (const r of running) {
|
|
2000
|
+
const it = issues.find((i) => String(i.number) === r.issueNumber);
|
|
2001
|
+
if (it) issueIds.add(it.id);
|
|
2001
2002
|
}
|
|
2002
|
-
|
|
2003
|
+
for (const id of issueIds) {
|
|
2004
|
+
await updateIssueAiStatus(id, "halted");
|
|
2005
|
+
void emitStatusChanged(project.id, id, "processing", "halted", ctx.user!.login, url.origin);
|
|
2006
|
+
}
|
|
2007
|
+
return Response.redirect(`${back}?ok=1&ok_msg=${encodeURIComponent(`已停止 ${issueIds.size} 个运行中AI会话`)}`, 303);
|
|
2003
2008
|
}
|
|
2004
2009
|
|
|
2005
2010
|
const settingsDispatchMatch = url.pathname.match(SETTINGS_DISPATCH_RE);
|
package/src/webhooks.ts
CHANGED
|
@@ -756,7 +756,7 @@ export async function emitStatusChanged(
|
|
|
756
756
|
const project = await getProjectById(projectId);
|
|
757
757
|
if (!project) return;
|
|
758
758
|
const issue = await getIssueById(issueId);
|
|
759
|
-
if (!issue) return;
|
|
759
|
+
if (!issue) { log.warn(`emitStatusChanged: issue ${issueId} not found (project=${projectId}) — silent skip prevented`); return; }
|
|
760
760
|
const commentCount = await countCommentsSafe(issueId);
|
|
761
761
|
const repo = buildRepository(project, origin);
|
|
762
762
|
const sender = buildUser(actor, origin);
|