@evandu/super-pi 0.1.162 → 0.1.163
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/agents/super-pi-task/core.ts +1 -1
- package/agents/super-pi-task/index.ts +1 -1
- package/dist/client/.super-pi-client-sources.json +5 -5
- package/dist/client/assets/{CodeMirrorEditor-Ch1Ipz3r.js → CodeMirrorEditor-DEkvKQts.js} +2 -2
- package/dist/client/assets/{dist-opu-Ndfn.js → dist-B-8UFI-6.js} +1 -1
- package/dist/client/assets/{dist-B0NwzG2K.js → dist-BtNbcR8w.js} +1 -1
- package/dist/client/assets/{dist-L0PobKDk.js → dist-C2Uv2gLb.js} +1 -1
- package/dist/client/assets/{dist-D5kM2io7.js → dist-C2mmiivD.js} +1 -1
- package/dist/client/assets/{dist-MIa-fDZ9.js → dist-CNrwgb43.js} +1 -1
- package/dist/client/assets/{dist-BGN6sRpP.js → dist-CSiW1PcF.js} +1 -1
- package/dist/client/assets/{dist-Cp0He9AW.js → dist-CVljZ_cT.js} +1 -1
- package/dist/client/assets/{dist-EWYaYkiN.js → dist-CbFClRtF.js} +1 -1
- package/dist/client/assets/{dist-BucgltXJ.js → dist-ChSDUOFD.js} +1 -1
- package/dist/client/assets/{dist-BAxkLl0w.js → dist-CipOPceB.js} +1 -1
- package/dist/client/assets/{dist-Chs1uuQX.js → dist-D5doZ1C8.js} +1 -1
- package/dist/client/assets/{dist-phbezeQa.js → dist-D5nqZFe3.js} +1 -1
- package/dist/client/assets/{dist-C_rEORol.js → dist-DC-1StQ4.js} +1 -1
- package/dist/client/assets/{dist-BelPaaJY.js → dist-DYahm0uS.js} +1 -1
- package/dist/client/assets/{dist-PaqaOBBw.js → dist-Dgkmmss0.js} +1 -1
- package/dist/client/assets/{dist-CmFGh26v.js → dist-DpVnCvxg.js} +1 -1
- package/dist/client/assets/{dist-BofmoyAA.js → dist-DwUj9On7.js} +1 -1
- package/dist/client/assets/{dist-B_k2ubHz.js → dist-DywKNYXP.js} +1 -1
- package/dist/client/assets/{dist-COh20l57.js → dist-FPDQhYJa.js} +1 -1
- package/dist/client/assets/{dist-DsvKYPCw.js → dist-GFhYndkm.js} +1 -1
- package/dist/client/assets/{dist-sV52WV4g.js → dist-OOixZci6.js} +1 -1
- package/dist/client/assets/{dist-CZfh2TpC.js → dist-a40vvieq.js} +1 -1
- package/dist/client/assets/{index-PN2dNRnQ.js → index-CLV7t20O.js} +10 -10
- package/dist/client/assets/{index-unAm6EaY.css → index-Wtlj0s4R.css} +1 -1
- package/dist/client/index.html +2 -2
- package/dist/server/application/project-service.d.ts +5 -1
- package/dist/server/application/project-service.js +98 -1
- package/dist/server/types.d.ts +33 -0
- package/package.json +1 -1
package/dist/client/index.html
CHANGED
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
<link rel="alternate icon" href="/favicon.ico" />
|
|
9
9
|
<link rel="apple-touch-icon" href="/favicon.svg" />
|
|
10
10
|
<title>Super Pi</title>
|
|
11
|
-
<script type="module" crossorigin src="/assets/index-
|
|
12
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
11
|
+
<script type="module" crossorigin src="/assets/index-CLV7t20O.js"></script>
|
|
12
|
+
<link rel="stylesheet" crossorigin href="/assets/index-Wtlj0s4R.css">
|
|
13
13
|
</head>
|
|
14
14
|
<body>
|
|
15
15
|
<div id="root"></div>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Store } from "../store.js";
|
|
2
|
-
import type { Project, ProjectEscalation, ProjectMode, ProjectReport, ProjectRisk, ProjectTask, SessionProfile } from "../types.js";
|
|
2
|
+
import type { Project, ProjectEscalation, ProjectMode, ProjectReport, ProjectRisk, ProjectSummary, ProjectTask, SessionProfile } from "../types.js";
|
|
3
3
|
import type { SessionOrchestratorService } from "./session-orchestrator-service.js";
|
|
4
4
|
export declare const profile: (value: unknown, label: string) => SessionProfile | undefined;
|
|
5
5
|
export declare const mergeProfile: (taskProfile?: SessionProfile, projectDefault?: SessionProfile) => SessionProfile | undefined;
|
|
@@ -95,6 +95,10 @@ export declare class ProjectService {
|
|
|
95
95
|
private reconcile;
|
|
96
96
|
private resources;
|
|
97
97
|
list(workspaceId?: string): Project[];
|
|
98
|
+
headline(p: Project): string;
|
|
99
|
+
private isActorRelated;
|
|
100
|
+
private projectSummary;
|
|
101
|
+
listForActor(workspaceId: string, actor: string): ProjectSummary[];
|
|
98
102
|
get(id: string, workspaceId?: string): Project;
|
|
99
103
|
/**
|
|
100
104
|
* THE PROJECT AS A REPORT A HUMAN CAN READ.
|
|
@@ -331,6 +331,16 @@ export class ProjectService {
|
|
|
331
331
|
}
|
|
332
332
|
}
|
|
333
333
|
const coordinatorIds = new Set([p.ownerConversationId, ...p.tasks.filter((t) => t.role === "leader").map((t) => t.ownerConversationId)].filter(Boolean));
|
|
334
|
+
/* THE MEMORY TREE OF THE PROJECT, AND OF EVERY SESSION IN IT.
|
|
335
|
+
*
|
|
336
|
+
* Since 0.1.161 a project opens its OWN memory tree: the leader session is the root of it and
|
|
337
|
+
* the workers inherit it, so the project's memories never mix with the Boss's chat. That is
|
|
338
|
+
* invisible from the outside - the client draws a tree of sessions and cannot tell which
|
|
339
|
+
* memories are behind it. So the server says it outright: the tree each session belongs to,
|
|
340
|
+
* and whether that tree is the project's own ("project") or the one it shares with the
|
|
341
|
+
* initiator's conversation ("shared"). The leader is the root of the project's tree, so it is
|
|
342
|
+
* "project" by the same rule as everybody else - there is no special case for it. */
|
|
343
|
+
const projectTreeId = p.ownerConversationId ? this.store.conversation(p.ownerConversationId)?.treeId : undefined;
|
|
334
344
|
const sessions = state.conversations.filter((c) => c.workspaceId === p.workspaceId && members.has(c.id)).map((c) => ({
|
|
335
345
|
id: c.id, title: c.title, status: c.status, tokens: tokens(c.usage), contextPercent: c.contextUsage?.percent,
|
|
336
346
|
// THE TREE SKELETON. The client draws the agents of a project as a tree, and the only
|
|
@@ -338,6 +348,10 @@ export class ProjectService {
|
|
|
338
348
|
// verbatim (including the undefined case, which means "this session has no parent in
|
|
339
349
|
// this collection" - i.e. it is a root of the tree).
|
|
340
350
|
parentConversationId: c.parentConversationId,
|
|
351
|
+
// WHOSE MEMORY THIS SESSION WORKS FROM. The project's own tree is the one the leader
|
|
352
|
+
// opened; anything else is a session that still shares the initiator's chat memory.
|
|
353
|
+
memoryTreeId: c.treeId,
|
|
354
|
+
memoryScope: projectTreeId && c.treeId === projectTreeId ? "project" : "shared",
|
|
341
355
|
role: c.id === p.ownerConversationId ? "项目负责人" : coordinatorIds.has(c.id) ? "分支 Leader" : p.tasks.some((t) => t.reviewerConversationId === c.id) ? "独立复核" : "执行者",
|
|
342
356
|
}));
|
|
343
357
|
const runs = state.subagentRuns.filter((r) => members.has(r.conversationId));
|
|
@@ -348,12 +362,92 @@ export class ProjectService {
|
|
|
348
362
|
const leaderIsWorker = lightweight(p) && p.ownerConversationId !== undefined;
|
|
349
363
|
return { tokens: sessions.reduce((sum, s) => sum + s.tokens, 0) + runs.reduce((sum, r) => sum + tokens(r.usage), 0),
|
|
350
364
|
usageKnown: sessions.length > 0 && sessions.every((s) => Boolean(this.store.conversation(s.id)?.usage)) && runs.every((r) => Boolean(r.usage)),
|
|
351
|
-
activeWorkers: sessions.filter((s) => (!coordinatorIds.has(s.id) || (leaderIsWorker && s.id === p.ownerConversationId)) && busy(s.status)).length + runs.filter((r) => r.status === "running").length,
|
|
365
|
+
activeWorkers: sessions.filter((s) => (!coordinatorIds.has(s.id) || (leaderIsWorker && s.id === p.ownerConversationId)) && busy(s.status)).length + runs.filter((r) => r.status === "running").length,
|
|
366
|
+
// THE PROJECT'S OWN MEMORY TREE, named once so the client does not have to infer it from
|
|
367
|
+
// the sessions. Absent only when the project has no leader session yet.
|
|
368
|
+
memoryTreeId: projectTreeId, sessions };
|
|
352
369
|
}
|
|
353
370
|
list(workspaceId) {
|
|
354
371
|
const scope = this.workspace(workspaceId);
|
|
355
372
|
return this.store.projects().filter((p) => p.workspaceId === scope).map((p) => this.projectView(p));
|
|
356
373
|
}
|
|
374
|
+
headline(p) {
|
|
375
|
+
const total = p.tasks.length;
|
|
376
|
+
const completed = p.tasks.filter((t) => t.status === "completed").length;
|
|
377
|
+
if (p.status === "completed") {
|
|
378
|
+
return total > 0 ? `项目已完成(${completed}/${total} 任务已验收)` : "项目已完成";
|
|
379
|
+
}
|
|
380
|
+
if (p.status === "cancelled")
|
|
381
|
+
return "项目已取消";
|
|
382
|
+
if (p.status === "failed")
|
|
383
|
+
return "项目失败";
|
|
384
|
+
const openEscalation = (p.escalations ?? []).find((e) => e.status === "open");
|
|
385
|
+
if (openEscalation) {
|
|
386
|
+
return p.status === "awaiting_approval"
|
|
387
|
+
? `等待审批:${openEscalation.reason}`
|
|
388
|
+
: `项目已阻塞:${openEscalation.reason}`;
|
|
389
|
+
}
|
|
390
|
+
const blockedTask = p.tasks.find((t) => t.status === "blocked");
|
|
391
|
+
if (blockedTask) {
|
|
392
|
+
const reason = blockedTask.blockedReason ? `(${blockedTask.blockedReason})` : "";
|
|
393
|
+
return `项目已阻塞:${blockedTask.title}${reason}`;
|
|
394
|
+
}
|
|
395
|
+
const inProgressTask = p.tasks.find((t) => t.status === "in_progress");
|
|
396
|
+
if (inProgressTask) {
|
|
397
|
+
return `${completed}/${total} 任务完成,正在执行${inProgressTask.title}`;
|
|
398
|
+
}
|
|
399
|
+
const reviewTask = p.tasks.find((t) => t.status === "awaiting_review");
|
|
400
|
+
if (reviewTask) {
|
|
401
|
+
return `${completed}/${total} 任务完成,正在复核${reviewTask.title}`;
|
|
402
|
+
}
|
|
403
|
+
const readyTask = p.tasks.find((t) => t.status === "ready");
|
|
404
|
+
if (readyTask) {
|
|
405
|
+
return `${completed}/${total} 任务完成,待派发${readyTask.title}`;
|
|
406
|
+
}
|
|
407
|
+
if (total > 0) {
|
|
408
|
+
return `${completed}/${total} 任务完成,等待前置依赖`;
|
|
409
|
+
}
|
|
410
|
+
return "项目规划中,尚未拆解任务";
|
|
411
|
+
}
|
|
412
|
+
isActorRelated(p, actor) {
|
|
413
|
+
if (!actor)
|
|
414
|
+
return false;
|
|
415
|
+
if (actor === p.initiatorConversationId)
|
|
416
|
+
return true;
|
|
417
|
+
if (actor === p.ownerConversationId)
|
|
418
|
+
return true;
|
|
419
|
+
if (p.tasks?.some((t) => t.ownerConversationId === actor || t.reviewerConversationId === actor))
|
|
420
|
+
return true;
|
|
421
|
+
if (this.projectForSession(actor)?.id === p.id)
|
|
422
|
+
return true;
|
|
423
|
+
return false;
|
|
424
|
+
}
|
|
425
|
+
projectSummary(p) {
|
|
426
|
+
const resources = this.resources(p);
|
|
427
|
+
return {
|
|
428
|
+
id: p.id,
|
|
429
|
+
name: p.title,
|
|
430
|
+
status: p.status,
|
|
431
|
+
mode: p.mode ?? "standard",
|
|
432
|
+
headline: this.headline(p),
|
|
433
|
+
tasks: {
|
|
434
|
+
total: p.tasks.length,
|
|
435
|
+
completed: p.tasks.filter((t) => t.status === "completed").length,
|
|
436
|
+
inProgress: p.tasks.filter((t) => t.status === "in_progress").length,
|
|
437
|
+
blocked: p.tasks.filter((t) => t.status === "blocked").length,
|
|
438
|
+
},
|
|
439
|
+
activeWorkers: resources.activeWorkers,
|
|
440
|
+
tokens: resources.tokens,
|
|
441
|
+
updatedAt: p.updatedAt,
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
listForActor(workspaceId, actor) {
|
|
445
|
+
const scope = this.workspace(workspaceId);
|
|
446
|
+
return this.store.projects()
|
|
447
|
+
.filter((p) => p.workspaceId === scope && this.isActorRelated(p, actor))
|
|
448
|
+
.sort((a, b) => b.updatedAt.localeCompare(a.updatedAt))
|
|
449
|
+
.map((p) => this.projectSummary(p));
|
|
450
|
+
}
|
|
357
451
|
get(id, workspaceId) {
|
|
358
452
|
return this.projectView(this.raw(id, workspaceId));
|
|
359
453
|
}
|
|
@@ -1219,6 +1313,9 @@ export class ProjectService {
|
|
|
1219
1313
|
await this.registerTopLevelTasks(project.id, plan, workspaceId, actor);
|
|
1220
1314
|
return this.get(project.id, workspaceId);
|
|
1221
1315
|
}
|
|
1316
|
+
if (body.action === "list") {
|
|
1317
|
+
return this.listForActor(workspaceId, actor);
|
|
1318
|
+
}
|
|
1222
1319
|
const id = text(body.projectId, "projectId");
|
|
1223
1320
|
const p = this.get(id, workspaceId);
|
|
1224
1321
|
this.member(p, actor);
|
package/dist/server/types.d.ts
CHANGED
|
@@ -1033,10 +1033,25 @@ export type Project = {
|
|
|
1033
1033
|
* and any orphan left behind by an older layout). Without it the panel can only show a row
|
|
1034
1034
|
* per session, and the hierarchy - who reported to whom - stays invisible.
|
|
1035
1035
|
*/
|
|
1036
|
+
/**
|
|
1037
|
+
* The project's live sessions, with the tree skeleton and the memory scope attached.
|
|
1038
|
+
*
|
|
1039
|
+
* `parentConversationId` is what lets the client draw a TREE rather than a flat list: a
|
|
1040
|
+
* session whose parent is not in this collection is a ROOT of the tree (the project leader,
|
|
1041
|
+
* and any orphan left behind by an older layout). Without it the panel can only show a row
|
|
1042
|
+
* per session, and the hierarchy - who reported to whom - stays invisible.
|
|
1043
|
+
*
|
|
1044
|
+
* `memoryScope` says whose memory a session works from: "project" for the sessions that live
|
|
1045
|
+
* in the PROJECT'S OWN memory tree (the leader, and every worker that inherited it), "shared"
|
|
1046
|
+
* for a session that still reads the initiator's chat memory. The panel shows it as a small
|
|
1047
|
+
* mark on every agent, because a reader who cannot tell the two apart cannot tell what a
|
|
1048
|
+
* session remembers.
|
|
1049
|
+
*/
|
|
1036
1050
|
resources?: {
|
|
1037
1051
|
tokens: number;
|
|
1038
1052
|
usageKnown: boolean;
|
|
1039
1053
|
activeWorkers: number;
|
|
1054
|
+
memoryTreeId?: string;
|
|
1040
1055
|
sessions: {
|
|
1041
1056
|
id: string;
|
|
1042
1057
|
title: string;
|
|
@@ -1045,6 +1060,8 @@ export type Project = {
|
|
|
1045
1060
|
tokens: number;
|
|
1046
1061
|
contextPercent?: number | null;
|
|
1047
1062
|
parentConversationId?: string;
|
|
1063
|
+
memoryTreeId?: string;
|
|
1064
|
+
memoryScope?: "project" | "shared";
|
|
1048
1065
|
}[];
|
|
1049
1066
|
};
|
|
1050
1067
|
/**
|
|
@@ -1063,6 +1080,22 @@ export type Project = {
|
|
|
1063
1080
|
updatedAt: string;
|
|
1064
1081
|
closedAt?: string;
|
|
1065
1082
|
};
|
|
1083
|
+
export type ProjectSummary = {
|
|
1084
|
+
id: string;
|
|
1085
|
+
name: string;
|
|
1086
|
+
status: string;
|
|
1087
|
+
mode: "standard" | "lightweight";
|
|
1088
|
+
headline: string;
|
|
1089
|
+
tasks: {
|
|
1090
|
+
total: number;
|
|
1091
|
+
completed: number;
|
|
1092
|
+
inProgress: number;
|
|
1093
|
+
blocked: number;
|
|
1094
|
+
};
|
|
1095
|
+
activeWorkers: number;
|
|
1096
|
+
tokens: number;
|
|
1097
|
+
updatedAt: string;
|
|
1098
|
+
};
|
|
1066
1099
|
export type AppState = {
|
|
1067
1100
|
modelFilterRules?: ModelFilterRule[];
|
|
1068
1101
|
defaultModel?: ModelSelection;
|