fix: fix some displays and features
This commit is contained in:
@ -23,12 +23,15 @@ import type {
|
||||
LayoutTree,
|
||||
Project,
|
||||
ProfileAvailability,
|
||||
Skill,
|
||||
SkillScope,
|
||||
Template,
|
||||
Unsubscribe,
|
||||
} from "@/domain";
|
||||
import type {
|
||||
AgentGateway,
|
||||
CreateAgentInput,
|
||||
CreateSkillInput,
|
||||
CreateTemplateInput,
|
||||
Gateways,
|
||||
GitGateway,
|
||||
@ -38,6 +41,7 @@ import type {
|
||||
ProjectGateway,
|
||||
ReattachResult,
|
||||
RemoteGateway,
|
||||
SkillGateway,
|
||||
SystemGateway,
|
||||
TemplateGateway,
|
||||
TerminalGateway,
|
||||
@ -191,6 +195,7 @@ export class MockAgentGateway implements AgentGateway {
|
||||
profileId: input.profileId,
|
||||
origin: { type: "scratch" },
|
||||
synchronized: false,
|
||||
skills: [],
|
||||
};
|
||||
list.push(agent);
|
||||
this.contexts.set(
|
||||
@ -282,6 +287,18 @@ export class MockAgentGateway implements AgentGateway {
|
||||
return this.getAgents(projectId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces an agent's assigned skills in-place.
|
||||
* Used by `MockSkillGateway.assignSkill` / `unassignSkill` so both gateways
|
||||
* share the same in-memory store.
|
||||
*/
|
||||
_setSkills(projectId: string, agentId: string, skills: Agent["skills"]): void {
|
||||
const list = this.getAgents(projectId);
|
||||
const idx = list.findIndex((a) => a.id === agentId);
|
||||
if (idx === -1) return;
|
||||
list[idx] = { ...list[idx], skills };
|
||||
}
|
||||
|
||||
async launchAgent(
|
||||
projectId: string,
|
||||
agentId: string,
|
||||
@ -931,6 +948,7 @@ export class MockTemplateGateway implements TemplateGateway {
|
||||
syncedTemplateVersion: template.version,
|
||||
},
|
||||
synchronized,
|
||||
skills: [],
|
||||
};
|
||||
|
||||
this.agentGateway._insertAgent(projectId, agent, template.contentMd);
|
||||
@ -990,6 +1008,130 @@ export class MockTemplateGateway implements TemplateGateway {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stateful in-memory skill gateway (L12).
|
||||
*
|
||||
* Skills are keyed by `${scope}` (project scope is further partitioned by
|
||||
* `projectId`, mirroring the disjoint on-disk roots). Assignment mutates the
|
||||
* agent record held by the injected {@link MockAgentGateway}, so both gateways
|
||||
* share one store — exactly like {@link MockTemplateGateway}.
|
||||
*/
|
||||
export class MockSkillGateway implements SkillGateway {
|
||||
// Global skills are project-independent; project skills live under their id.
|
||||
private global: Skill[] = [];
|
||||
private byProject = new Map<string, Skill[]>();
|
||||
private seq = 0;
|
||||
|
||||
constructor(private readonly agentGateway: MockAgentGateway) {}
|
||||
|
||||
private bucket(projectId: string, scope: SkillScope): Skill[] {
|
||||
if (scope === "global") return this.global;
|
||||
let list = this.byProject.get(projectId);
|
||||
if (!list) {
|
||||
list = [];
|
||||
this.byProject.set(projectId, list);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
async listSkills(projectId: string, scope: SkillScope): Promise<Skill[]> {
|
||||
return structuredClone(this.bucket(projectId, scope));
|
||||
}
|
||||
|
||||
async createSkill(input: CreateSkillInput): Promise<Skill> {
|
||||
this.seq += 1;
|
||||
const skill: Skill = {
|
||||
id: `mock-skill-${this.seq}`,
|
||||
name: input.name,
|
||||
contentMd: input.content,
|
||||
scope: input.scope,
|
||||
};
|
||||
this.bucket(input.projectId, input.scope).push(skill);
|
||||
return structuredClone(skill);
|
||||
}
|
||||
|
||||
async updateSkill(
|
||||
projectId: string,
|
||||
scope: SkillScope,
|
||||
skillId: string,
|
||||
content: string,
|
||||
): Promise<Skill> {
|
||||
const list = this.bucket(projectId, scope);
|
||||
const idx = list.findIndex((s) => s.id === skillId);
|
||||
if (idx === -1) {
|
||||
const err: GatewayError = {
|
||||
code: "NOT_FOUND",
|
||||
message: `skill ${skillId} not found`,
|
||||
};
|
||||
throw err;
|
||||
}
|
||||
list[idx] = { ...list[idx], contentMd: content };
|
||||
return structuredClone(list[idx]);
|
||||
}
|
||||
|
||||
async deleteSkill(
|
||||
projectId: string,
|
||||
scope: SkillScope,
|
||||
skillId: string,
|
||||
): Promise<void> {
|
||||
const list = this.bucket(projectId, scope);
|
||||
const idx = list.findIndex((s) => s.id === skillId);
|
||||
if (idx === -1) {
|
||||
const err: GatewayError = {
|
||||
code: "NOT_FOUND",
|
||||
message: `skill ${skillId} not found`,
|
||||
};
|
||||
throw err;
|
||||
}
|
||||
list.splice(idx, 1);
|
||||
}
|
||||
|
||||
async assignSkill(
|
||||
projectId: string,
|
||||
agentId: string,
|
||||
skillId: string,
|
||||
scope: SkillScope,
|
||||
): Promise<void> {
|
||||
const agent = this.agentGateway
|
||||
._rawAgents(projectId)
|
||||
.find((a) => a.id === agentId);
|
||||
if (!agent) {
|
||||
const err: GatewayError = {
|
||||
code: "NOT_FOUND",
|
||||
message: `agent ${agentId} not found in project ${projectId}`,
|
||||
};
|
||||
throw err;
|
||||
}
|
||||
if (agent.skills.some((s) => s.skillId === skillId)) return; // idempotent
|
||||
this.agentGateway._setSkills(projectId, agentId, [
|
||||
...agent.skills,
|
||||
{ skillId, scope },
|
||||
]);
|
||||
}
|
||||
|
||||
async unassignSkill(
|
||||
projectId: string,
|
||||
agentId: string,
|
||||
skillId: string,
|
||||
): Promise<void> {
|
||||
const agent = this.agentGateway
|
||||
._rawAgents(projectId)
|
||||
.find((a) => a.id === agentId);
|
||||
if (!agent) {
|
||||
const err: GatewayError = {
|
||||
code: "NOT_FOUND",
|
||||
message: `agent ${agentId} not found in project ${projectId}`,
|
||||
};
|
||||
throw err;
|
||||
}
|
||||
this.agentGateway._setSkills(
|
||||
projectId,
|
||||
agentId,
|
||||
agent.skills.filter((s) => s.skillId !== skillId),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/** Builds the full set of mock gateways. */
|
||||
export function createMockGateways(): Gateways {
|
||||
const agentGateway = new MockAgentGateway();
|
||||
@ -1003,6 +1145,7 @@ export function createMockGateways(): Gateways {
|
||||
remote: new MockRemoteGateway(),
|
||||
profile: new MockProfileGateway(),
|
||||
template: new MockTemplateGateway(agentGateway),
|
||||
skill: new MockSkillGateway(agentGateway),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user