@xrkseek/harness 0.6.8 → 0.6.10
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/node_modules/@xrkseek/server-face/dist/agent-member-pack.d.ts +96 -0
- package/node_modules/@xrkseek/server-face/dist/agent-member-pack.d.ts.map +1 -1
- package/node_modules/@xrkseek/server-face/dist/agent-member-pack.js +365 -9
- package/node_modules/@xrkseek/server-face/dist/agent-member-pack.js.map +1 -1
- package/node_modules/@xrkseek/server-face/dist/agent-roster-store.d.ts +8 -1
- package/node_modules/@xrkseek/server-face/dist/agent-roster-store.d.ts.map +1 -1
- package/node_modules/@xrkseek/server-face/dist/agent-roster-store.js +21 -1
- package/node_modules/@xrkseek/server-face/dist/agent-roster-store.js.map +1 -1
- package/node_modules/@xrkseek/server-face/dist/agent-roster-tools.d.ts +7 -2
- package/node_modules/@xrkseek/server-face/dist/agent-roster-tools.d.ts.map +1 -1
- package/node_modules/@xrkseek/server-face/dist/agent-roster-tools.js +655 -76
- package/node_modules/@xrkseek/server-face/dist/agent-roster-tools.js.map +1 -1
- package/node_modules/@xrkseek/server-face/dist/agent-team-roles.d.ts +9 -0
- package/node_modules/@xrkseek/server-face/dist/agent-team-roles.d.ts.map +1 -1
- package/node_modules/@xrkseek/server-face/dist/agent-team-roles.js +25 -2
- package/node_modules/@xrkseek/server-face/dist/agent-team-roles.js.map +1 -1
- package/node_modules/@xrkseek/server-face/dist/capture-member-playbook.d.ts +4 -0
- package/node_modules/@xrkseek/server-face/dist/capture-member-playbook.d.ts.map +1 -1
- package/node_modules/@xrkseek/server-face/dist/capture-member-playbook.js +28 -7
- package/node_modules/@xrkseek/server-face/dist/capture-member-playbook.js.map +1 -1
- package/node_modules/@xrkseek/server-face/dist/handlers/team.d.ts.map +1 -1
- package/node_modules/@xrkseek/server-face/dist/handlers/team.js +37 -3
- package/node_modules/@xrkseek/server-face/dist/handlers/team.js.map +1 -1
- package/node_modules/@xrkseek/server-face/dist/presets-catalog.d.ts.map +1 -1
- package/node_modules/@xrkseek/server-face/dist/presets-catalog.js +6 -3
- package/node_modules/@xrkseek/server-face/dist/presets-catalog.js.map +1 -1
- package/node_modules/@xrkseek/server-face/dist/runtime.d.ts.map +1 -1
- package/node_modules/@xrkseek/server-face/dist/runtime.js +7 -2
- package/node_modules/@xrkseek/server-face/dist/runtime.js.map +1 -1
- package/node_modules/@xrkseek/server-face/dist/session-capability.d.ts.map +1 -1
- package/node_modules/@xrkseek/server-face/dist/session-capability.js +30 -2
- package/node_modules/@xrkseek/server-face/dist/session-capability.js.map +1 -1
- package/node_modules/@xrkseek/server-face/dist/session-posture.d.ts.map +1 -1
- package/node_modules/@xrkseek/server-face/dist/session-posture.js +3 -1
- package/node_modules/@xrkseek/server-face/dist/session-posture.js.map +1 -1
- package/node_modules/@xrkseek/server-face/dist/session-tool-copy.d.ts +6 -1
- package/node_modules/@xrkseek/server-face/dist/session-tool-copy.d.ts.map +1 -1
- package/node_modules/@xrkseek/server-face/dist/session-tool-copy.js +10 -10
- package/node_modules/@xrkseek/server-face/dist/session-tool-copy.js.map +1 -1
- package/node_modules/@xrkseek/server-face/dist/session-tools.d.ts.map +1 -1
- package/node_modules/@xrkseek/server-face/dist/session-tools.js +5 -0
- package/node_modules/@xrkseek/server-face/dist/session-tools.js.map +1 -1
- package/node_modules/@xrkseek/server-face/dist/subagent-tools.d.ts.map +1 -1
- package/node_modules/@xrkseek/server-face/dist/subagent-tools.js +32 -3
- package/node_modules/@xrkseek/server-face/dist/subagent-tools.js.map +1 -1
- package/node_modules/@xrkseek/server-face/dist/xiangyang-skill-bodies/demand-translate.d.ts +1 -1
- package/node_modules/@xrkseek/server-face/dist/xiangyang-skill-bodies/demand-translate.d.ts.map +1 -1
- package/node_modules/@xrkseek/server-face/dist/xiangyang-skill-bodies/demand-translate.js +25 -7
- package/node_modules/@xrkseek/server-face/dist/xiangyang-skill-bodies/demand-translate.js.map +1 -1
- package/node_modules/@xrkseek/server-face/dist/xiangyang-skill-bodies/home-config.d.ts +1 -1
- package/node_modules/@xrkseek/server-face/dist/xiangyang-skill-bodies/home-config.d.ts.map +1 -1
- package/node_modules/@xrkseek/server-face/dist/xiangyang-skill-bodies/home-config.js +18 -5
- package/node_modules/@xrkseek/server-face/dist/xiangyang-skill-bodies/home-config.js.map +1 -1
- package/node_modules/@xrkseek/server-face/dist/xiangyang-skill-bodies/index.d.ts +1 -1
- package/node_modules/@xrkseek/server-face/dist/xiangyang-skill-bodies/index.js +1 -1
- package/node_modules/@xrkseek/server-face/dist/xiangyang-skill-bodies/skill-merge.d.ts +1 -1
- package/node_modules/@xrkseek/server-face/dist/xiangyang-skill-bodies/skill-merge.d.ts.map +1 -1
- package/node_modules/@xrkseek/server-face/dist/xiangyang-skill-bodies/skill-merge.js +12 -7
- package/node_modules/@xrkseek/server-face/dist/xiangyang-skill-bodies/skill-merge.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,19 +1,24 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Model-facing team_list /
|
|
3
|
-
*
|
|
2
|
+
* Model-facing team_list / save / import / ready / export / remove /
|
|
3
|
+
* team_self (child own surfaces). Packs under agent-rosters/packs/.
|
|
4
4
|
*/
|
|
5
|
+
import { writeFileSync } from "node:fs";
|
|
5
6
|
import path from "node:path";
|
|
6
7
|
import { readSessionEvents } from "@xrkseek/core-session";
|
|
7
8
|
import { isAttachmentError } from "@xrkseek/attachment";
|
|
8
9
|
import { canvasWorkspaceIdForSession } from "./canvas-tools.js";
|
|
9
10
|
import { isAgentTeamSpawnRole } from "./agent-team-roles.js";
|
|
10
|
-
import { GLOBAL_ROSTER_ID, memberIdProblem, catalogMemberWriteProblem, parseMemberToolPolicy, parseRosterScope, rosterPublicFields, } from "./agent-roster-store.js";
|
|
11
|
-
import { parseAgentMemberCard } from "./agent-member-card.js";
|
|
12
|
-
import { loadAgentMemberPack, loadAgentMemberPackBytes, materializeAgentMemberPack, notReadyPackHints, } from "./agent-member-pack.js";
|
|
13
|
-
import {
|
|
11
|
+
import { GLOBAL_ROSTER_ID, memberIdProblem, catalogMemberWriteProblem, parseMemberInject, parseMemberToolPolicy, parseRosterScope, rosterPublicFields, } from "./agent-roster-store.js";
|
|
12
|
+
import { parseAgentMemberCard, } from "./agent-member-card.js";
|
|
13
|
+
import { AGENT_MEMBER_PACK_LAYOUT, MEMBER_PACK_BRIEFCASE, buildAgentMemberPackZip, collectPackSkillFiles, collectPackWorkspaceFiles, listMemberPackInventory, loadAgentMemberPack, loadAgentMemberPackBytes, materializeAgentMemberPack, mergeIntoMemberPack, notReadyPackHints, syncMemberPackPlaybook, } from "./agent-member-pack.js";
|
|
14
|
+
import { withAdvancedPackPathGuidance } from "./capture-member-playbook.js";
|
|
14
15
|
import { resolveSessionCwd } from "./session-cwd.js";
|
|
15
16
|
import { referencedAttachmentIds } from "./session-attachment.js";
|
|
16
|
-
import {
|
|
17
|
+
import { dispatchFaceMethod } from "./dispatch.js";
|
|
18
|
+
import { liveRosterCatalog, rosterScopeVisibility, teamListDescription, } from "./session-tool-copy.js";
|
|
19
|
+
function teamPresent(title, kind, args = {}) {
|
|
20
|
+
return { card: "generic", title, kind, rawInput: args };
|
|
21
|
+
}
|
|
17
22
|
function missingMemberHint(runtime, canvasId, id, tool) {
|
|
18
23
|
const home = runtime.agentRoster.findHome(id);
|
|
19
24
|
if (!home) {
|
|
@@ -86,35 +91,204 @@ function enrichListedMember(runtime, canvasId, row) {
|
|
|
86
91
|
...rosterPublicFields(row),
|
|
87
92
|
visibility: rosterScopeVisibility(row.scope === "global" ? "global" : "workspace", rosterWs),
|
|
88
93
|
};
|
|
89
|
-
if (row.kind !== "advanced"
|
|
94
|
+
if (row.kind !== "advanced")
|
|
90
95
|
return pub;
|
|
91
|
-
|
|
96
|
+
const packOpts = {
|
|
97
|
+
rosterWorkspaceId: rosterWs,
|
|
98
|
+
memberId: row.id,
|
|
99
|
+
productHome: runtime.agentRoster.home,
|
|
100
|
+
};
|
|
101
|
+
const inventory = listMemberPackInventory(packOpts);
|
|
102
|
+
const base = {
|
|
92
103
|
...pub,
|
|
93
|
-
...
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
104
|
+
...(inventory
|
|
105
|
+
? {
|
|
106
|
+
packHome: inventory.packHome,
|
|
107
|
+
playbookPath: inventory.playbookPath,
|
|
108
|
+
...(inventory.envPrepPath
|
|
109
|
+
? { envPrepPath: inventory.envPrepPath }
|
|
110
|
+
: {}),
|
|
111
|
+
...(inventory.materialsPath
|
|
112
|
+
? {
|
|
113
|
+
materialsPath: inventory.materialsPath,
|
|
114
|
+
materialsTop: inventory.materialsTop,
|
|
115
|
+
}
|
|
116
|
+
: {}),
|
|
117
|
+
skills: inventory.skills,
|
|
118
|
+
briefcase: MEMBER_PACK_BRIEFCASE,
|
|
119
|
+
}
|
|
120
|
+
: {}),
|
|
121
|
+
};
|
|
122
|
+
if (row.ready)
|
|
123
|
+
return base;
|
|
124
|
+
return {
|
|
125
|
+
...base,
|
|
126
|
+
...notReadyPackHints(packOpts),
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
function resolveCwdPaths(runtime, sessionId, rows) {
|
|
130
|
+
const cwd = resolveSessionCwd(runtime, sessionId);
|
|
131
|
+
if (!Array.isArray(rows))
|
|
132
|
+
return [];
|
|
133
|
+
return rows
|
|
134
|
+
.filter((s) => typeof s === "string" && s.trim().length > 0)
|
|
135
|
+
.map((s) => path.isAbsolute(s.trim()) ? s.trim() : path.resolve(cwd, s.trim()));
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Mint an advanced pack member (playbook + optional skills/files/env).
|
|
139
|
+
* Shared by team_save — team_import only installs card=/pack=.
|
|
140
|
+
*/
|
|
141
|
+
function mintAdvancedMember(input) {
|
|
142
|
+
const { runtime, sessionId, canvasId, scope, name, playbook, } = input;
|
|
143
|
+
if (!name.trim() || !playbook.trim()) {
|
|
144
|
+
return {
|
|
145
|
+
ok: false,
|
|
146
|
+
content: "team_save: advanced needs name and playbook (from the real scenario)",
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
const toolsPolicy = parseMemberToolPolicy(input.tools);
|
|
150
|
+
if (input.tools !== undefined && input.tools !== null && !toolsPolicy) {
|
|
151
|
+
return {
|
|
152
|
+
ok: false,
|
|
153
|
+
content: 'team_save: tools needs { mode: "allow"|"deny", names: [...] }',
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
const card = {
|
|
157
|
+
name: name.trim(),
|
|
158
|
+
playbook: withAdvancedPackPathGuidance(playbook),
|
|
159
|
+
role: isAgentTeamSpawnRole(input.roleRaw) ? input.roleRaw : "worker",
|
|
160
|
+
...(input.brief?.trim() ? { brief: input.brief.trim() } : {}),
|
|
161
|
+
...(input.inject === "subagent" || input.inject === "minimal"
|
|
162
|
+
? { inject: input.inject }
|
|
163
|
+
: {}),
|
|
164
|
+
...(toolsPolicy ? { tools: toolsPolicy } : {}),
|
|
165
|
+
};
|
|
166
|
+
const skillPaths = resolveCwdPaths(runtime, sessionId, input.skills);
|
|
167
|
+
let skillsFiles;
|
|
168
|
+
if (skillPaths.length > 0) {
|
|
169
|
+
const bundled = collectPackSkillFiles(skillPaths);
|
|
170
|
+
if (!bundled.ok) {
|
|
171
|
+
return { ok: false, content: `team_save: ${bundled.error}` };
|
|
172
|
+
}
|
|
173
|
+
skillsFiles = bundled.files;
|
|
174
|
+
}
|
|
175
|
+
const filePaths = resolveCwdPaths(runtime, sessionId, input.files);
|
|
176
|
+
let workspaceFiles;
|
|
177
|
+
if (filePaths.length > 0) {
|
|
178
|
+
const bundled = collectPackWorkspaceFiles(filePaths);
|
|
179
|
+
if (!bundled.ok) {
|
|
180
|
+
return { ok: false, content: `team_save: ${bundled.error}` };
|
|
181
|
+
}
|
|
182
|
+
workspaceFiles = bundled.files;
|
|
183
|
+
}
|
|
184
|
+
const envPrep = input.envPrep?.trim() || undefined;
|
|
185
|
+
const zip = buildAgentMemberPackZip(card, {
|
|
186
|
+
...(skillsFiles && skillsFiles.size > 0 ? { skillsFiles } : {}),
|
|
187
|
+
...(workspaceFiles && workspaceFiles.size > 0 ? { workspaceFiles } : {}),
|
|
188
|
+
...(envPrep ? { envPrep } : {}),
|
|
189
|
+
});
|
|
190
|
+
const loaded = loadAgentMemberPackBytes(zip);
|
|
191
|
+
if (!loaded.ok) {
|
|
192
|
+
return { ok: false, content: `team_save: ${loaded.error}` };
|
|
193
|
+
}
|
|
194
|
+
const rosterWs = scope === "global" ? GLOBAL_ROSTER_ID : canvasId;
|
|
195
|
+
const member = runtime.agentRoster.upsertAtScope(canvasId, scope, {
|
|
196
|
+
...loaded.pack.card,
|
|
197
|
+
kind: "advanced",
|
|
198
|
+
ready: false,
|
|
199
|
+
...(input.id?.trim() ? { id: input.id.trim() } : {}),
|
|
200
|
+
});
|
|
201
|
+
if (!member) {
|
|
202
|
+
return { ok: false, content: "team_save: name and playbook required" };
|
|
203
|
+
}
|
|
204
|
+
const placed = materializeAgentMemberPack(loaded.pack, {
|
|
205
|
+
rosterWorkspaceId: rosterWs,
|
|
206
|
+
memberId: member.id,
|
|
207
|
+
productHome: runtime.agentRoster.home,
|
|
208
|
+
});
|
|
209
|
+
return {
|
|
210
|
+
ok: true,
|
|
211
|
+
content: JSON.stringify({
|
|
212
|
+
workspaceId: rosterWs,
|
|
213
|
+
scope,
|
|
214
|
+
visibility: rosterScopeVisibility(scope, rosterWs),
|
|
215
|
+
member,
|
|
216
|
+
source: "team_save",
|
|
217
|
+
kind: "advanced",
|
|
218
|
+
packDir: placed.packDir,
|
|
219
|
+
skillNames: placed.skillNames,
|
|
220
|
+
ready: false,
|
|
221
|
+
...(placed.envPrep
|
|
222
|
+
? {
|
|
223
|
+
envPrep: placed.envPrep,
|
|
224
|
+
envHint: "Review envPrep here (or hand zip to a friend). Then team_ready. Do not auto-run scripts.",
|
|
225
|
+
}
|
|
226
|
+
: {
|
|
227
|
+
envHint: "No env/SETUP.md — team_ready when configured; friend gets playbook (± skills).",
|
|
228
|
+
}),
|
|
229
|
+
next: "team_ready → subagent member_id",
|
|
230
|
+
layout: AGENT_MEMBER_PACK_LAYOUT,
|
|
231
|
+
pathHint: `Spawn keeps parent workspace cwd. ${MEMBER_PACK_BRIEFCASE} = pack_home (injected) — child may read/edit/copy into workspace. Share zip with relative paths under the pack tree.`,
|
|
232
|
+
shareHint: "Friend: team_export zip / UI import, or they team_import pack=… → follow envPrep with main session → team_ready. " +
|
|
233
|
+
"scope=global keeps it on every canvas team_list.",
|
|
97
234
|
}),
|
|
98
235
|
};
|
|
99
236
|
}
|
|
100
|
-
|
|
237
|
+
function patchExistingMember(runtime, canvasId, existing, patch) {
|
|
238
|
+
const name = (patch.name ?? existing.name).trim();
|
|
239
|
+
let playbook = (patch.playbook ?? existing.playbook).trim();
|
|
240
|
+
if (existing.kind === "advanced" && patch.playbook !== undefined) {
|
|
241
|
+
playbook = withAdvancedPackPathGuidance(playbook);
|
|
242
|
+
}
|
|
243
|
+
if (!name || !playbook)
|
|
244
|
+
return undefined;
|
|
245
|
+
const scope = existing.scope === "global" ? "global" : "workspace";
|
|
246
|
+
const inject = patch.inject ?? existing.inject;
|
|
247
|
+
const tools = patch.tools === undefined
|
|
248
|
+
? existing.tools
|
|
249
|
+
: patch.tools === null
|
|
250
|
+
? undefined
|
|
251
|
+
: patch.tools;
|
|
252
|
+
const member = runtime.agentRoster.upsertAtScope(canvasId, scope, {
|
|
253
|
+
id: existing.id,
|
|
254
|
+
name,
|
|
255
|
+
playbook,
|
|
256
|
+
role: isAgentTeamSpawnRole(existing.role) ? existing.role : "worker",
|
|
257
|
+
kind: existing.kind,
|
|
258
|
+
ready: existing.ready,
|
|
259
|
+
brief: patch.brief !== undefined ? patch.brief : existing.brief,
|
|
260
|
+
inject,
|
|
261
|
+
...(tools ? { tools } : patch.tools === null ? { tools: null } : {}),
|
|
262
|
+
appearance: existing.appearance,
|
|
263
|
+
});
|
|
264
|
+
if (!member)
|
|
265
|
+
return undefined;
|
|
266
|
+
if (existing.kind === "advanced") {
|
|
267
|
+
const rosterWs = scope === "global" ? GLOBAL_ROSTER_ID : canvasId;
|
|
268
|
+
syncMemberPackPlaybook({
|
|
269
|
+
rosterWorkspaceId: rosterWs,
|
|
270
|
+
memberId: member.id,
|
|
271
|
+
playbook: member.playbook,
|
|
272
|
+
productHome: runtime.agentRoster.home,
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
return runtime.agentRoster.get(canvasId, member.id);
|
|
276
|
+
}
|
|
277
|
+
/** Register team_list / team_save / team_import / team_ready / team_remove (or list + team_self). */
|
|
101
278
|
export function bindAgentRosterTools(tools, options) {
|
|
102
279
|
const { runtime, sessionId, listOnly = false } = options;
|
|
280
|
+
const selfMemberId = options.selfMemberId?.trim() || undefined;
|
|
103
281
|
const ws = () => canvasWorkspaceIdForSession(runtime, sessionId);
|
|
104
282
|
registerTool(tools, {
|
|
105
283
|
name: "team_list",
|
|
106
284
|
description: "List Agent Team members (干员) for this workspace + global.",
|
|
107
285
|
parameters: { type: "object", properties: {}, additionalProperties: false },
|
|
108
286
|
isConcurrencySafe: () => true,
|
|
109
|
-
presentCall: () => (
|
|
110
|
-
card: "generic",
|
|
111
|
-
title: "team_list",
|
|
112
|
-
kind: "search",
|
|
113
|
-
rawInput: {},
|
|
114
|
-
}),
|
|
287
|
+
presentCall: () => teamPresent("team_list", "search"),
|
|
115
288
|
dynamicSchema: () => ({
|
|
116
289
|
description: teamListDescription({
|
|
117
290
|
listOnly,
|
|
291
|
+
...(selfMemberId ? { selfRevise: true } : {}),
|
|
118
292
|
catalog: liveRosterCatalog(runtime, sessionId),
|
|
119
293
|
}),
|
|
120
294
|
}),
|
|
@@ -126,33 +300,139 @@ export function bindAgentRosterTools(tools, options) {
|
|
|
126
300
|
return { content: JSON.stringify({ workspaceId, members }) };
|
|
127
301
|
},
|
|
128
302
|
});
|
|
129
|
-
if (listOnly)
|
|
303
|
+
if (listOnly) {
|
|
304
|
+
if (selfMemberId) {
|
|
305
|
+
registerTool(tools, {
|
|
306
|
+
name: "team_self",
|
|
307
|
+
description: "Revise YOUR 干员 surfaces (this member_id): playbook, inject, tools, brief. " +
|
|
308
|
+
"Child tool/inject surface ≠ parent. Durable for next spawn. " +
|
|
309
|
+
"Cannot mint, import, export, or edit other members.",
|
|
310
|
+
parameters: {
|
|
311
|
+
type: "object",
|
|
312
|
+
properties: {
|
|
313
|
+
playbook: {
|
|
314
|
+
type: "string",
|
|
315
|
+
description: "Replacement playbook (max 20000). Omit to keep.",
|
|
316
|
+
},
|
|
317
|
+
brief: {
|
|
318
|
+
type: "string",
|
|
319
|
+
description: "Replacement duty line. Omit to keep.",
|
|
320
|
+
},
|
|
321
|
+
name: {
|
|
322
|
+
type: "string",
|
|
323
|
+
description: "Optional display-name tweak. Omit to keep.",
|
|
324
|
+
},
|
|
325
|
+
inject: {
|
|
326
|
+
type: "string",
|
|
327
|
+
description: "minimal (thin context) | subagent (keep project docs). Omit to keep.",
|
|
328
|
+
},
|
|
329
|
+
tools: {
|
|
330
|
+
type: "object",
|
|
331
|
+
properties: {
|
|
332
|
+
mode: { type: "string" },
|
|
333
|
+
names: { type: "array", items: { type: "string" } },
|
|
334
|
+
},
|
|
335
|
+
additionalProperties: false,
|
|
336
|
+
description: "allow|deny list on top of role. Pass null to clear.",
|
|
337
|
+
},
|
|
338
|
+
},
|
|
339
|
+
additionalProperties: false,
|
|
340
|
+
},
|
|
341
|
+
presentCall: (args) => teamPresent("team_self", "execute", args),
|
|
342
|
+
execute: async (args) => {
|
|
343
|
+
const a = readArgs(args);
|
|
344
|
+
const canvasId = ws();
|
|
345
|
+
const existing = runtime.agentRoster.get(canvasId, selfMemberId);
|
|
346
|
+
if (!existing || existing.catalog) {
|
|
347
|
+
return {
|
|
348
|
+
content: `team_self: member "${selfMemberId}" not editable here`,
|
|
349
|
+
isError: true,
|
|
350
|
+
};
|
|
351
|
+
}
|
|
352
|
+
const hasPlaybook = typeof a.playbook === "string";
|
|
353
|
+
const hasBrief = typeof a.brief === "string";
|
|
354
|
+
const hasName = typeof a.name === "string" && a.name.trim().length > 0;
|
|
355
|
+
const hasInject = a.inject === "minimal" || a.inject === "subagent";
|
|
356
|
+
const hasTools = a.tools !== undefined;
|
|
357
|
+
if (!hasPlaybook && !hasBrief && !hasName && !hasInject && !hasTools) {
|
|
358
|
+
return {
|
|
359
|
+
content: "team_self: pass playbook, brief, inject, and/or tools (optional name)",
|
|
360
|
+
isError: true,
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
const toolsPatch = a.tools === null
|
|
364
|
+
? null
|
|
365
|
+
: hasTools
|
|
366
|
+
? parseMemberToolPolicy(a.tools)
|
|
367
|
+
: undefined;
|
|
368
|
+
if (hasTools && a.tools !== null && !toolsPatch) {
|
|
369
|
+
return {
|
|
370
|
+
content: 'team_self: tools needs { mode: "allow"|"deny", names: [...] }',
|
|
371
|
+
isError: true,
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
const patched = patchExistingMember(runtime, canvasId, existing, {
|
|
375
|
+
...(hasName ? { name: String(a.name).trim() } : {}),
|
|
376
|
+
...(hasPlaybook ? { playbook: String(a.playbook) } : {}),
|
|
377
|
+
...(hasBrief ? { brief: String(a.brief) } : {}),
|
|
378
|
+
...(hasInject
|
|
379
|
+
? { inject: parseMemberInject(a.inject, existing.inject) }
|
|
380
|
+
: {}),
|
|
381
|
+
...(hasTools ? { tools: toolsPatch ?? null } : {}),
|
|
382
|
+
});
|
|
383
|
+
if (!patched) {
|
|
384
|
+
return { content: "team_self: name and playbook required", isError: true };
|
|
385
|
+
}
|
|
386
|
+
return {
|
|
387
|
+
content: JSON.stringify({
|
|
388
|
+
member: {
|
|
389
|
+
...enrichListedMember(runtime, canvasId, patched),
|
|
390
|
+
playbook: patched.playbook,
|
|
391
|
+
},
|
|
392
|
+
next: "next subagent member_id uses these surfaces; this turn already started",
|
|
393
|
+
}),
|
|
394
|
+
};
|
|
395
|
+
},
|
|
396
|
+
});
|
|
397
|
+
}
|
|
130
398
|
return;
|
|
399
|
+
}
|
|
131
400
|
registerTool(tools, {
|
|
132
401
|
name: "team_save",
|
|
133
|
-
description: "Mint
|
|
134
|
-
"
|
|
135
|
-
|
|
136
|
-
|
|
402
|
+
description: "Mint or revise a 干员 (template → skill xrk-delegate). " +
|
|
403
|
+
"Thin: name+playbook (+inject/tools). " +
|
|
404
|
+
`Advanced ${MEMBER_PACK_BRIEFCASE}: kind=advanced + skills/files/env_prep (playbook.md · skills/ · workspace/ · env/SETUP.md) → team_ready → team_export. ` +
|
|
405
|
+
"Revise any custom member with id= (omit unchanged fields); advanced may also merge skills/files/env_prep into 公文包. " +
|
|
406
|
+
"Install friend zip/json → team_import (not this).",
|
|
137
407
|
parameters: {
|
|
138
408
|
type: "object",
|
|
139
409
|
properties: {
|
|
140
410
|
id: {
|
|
141
411
|
type: "string",
|
|
142
|
-
description: "mem_
|
|
412
|
+
description: "Existing mem_… to revise (thin or advanced). Omit to mint. Pattern: mem_[A-Za-z0-9][A-Za-z0-9._-]*",
|
|
413
|
+
},
|
|
414
|
+
name: {
|
|
415
|
+
type: "string",
|
|
416
|
+
description: "Short label (e.g. PPT排版员). On revise, omit to keep.",
|
|
143
417
|
},
|
|
144
|
-
name: { type: "string" },
|
|
145
418
|
playbook: {
|
|
146
419
|
type: "string",
|
|
147
|
-
description: "
|
|
420
|
+
description: "Durable how-to. Prefer: Role; Steps; Constraints; Acceptance; for advanced also list what is in 公文包 (briefcase). " +
|
|
421
|
+
"On revise, omit to keep. Max 20000. Template: skill xrk-delegate.",
|
|
148
422
|
},
|
|
149
423
|
role: { type: "string" },
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
424
|
+
kind: {
|
|
425
|
+
type: "string",
|
|
426
|
+
description: "thin (default) | advanced. Also advanced when skills/files/env_prep set.",
|
|
427
|
+
},
|
|
428
|
+
brief: { type: "string", description: "One-line duty for team_list." },
|
|
429
|
+
scope: {
|
|
430
|
+
type: "string",
|
|
431
|
+
description: "global | workspace. Thin default workspace; advanced default global.",
|
|
432
|
+
},
|
|
153
433
|
inject: {
|
|
154
434
|
type: "string",
|
|
155
|
-
description: "minimal (default) | subagent",
|
|
435
|
+
description: "minimal (default) | subagent (keep project docs)",
|
|
156
436
|
},
|
|
157
437
|
tools: {
|
|
158
438
|
type: "object",
|
|
@@ -161,16 +441,26 @@ export function bindAgentRosterTools(tools, options) {
|
|
|
161
441
|
names: { type: "array", items: { type: "string" } },
|
|
162
442
|
},
|
|
163
443
|
additionalProperties: false,
|
|
444
|
+
description: "Child tool allow|deny on top of role.",
|
|
445
|
+
},
|
|
446
|
+
env_prep: {
|
|
447
|
+
type: "string",
|
|
448
|
+
description: `Advanced ${MEMBER_PACK_BRIEFCASE}: env/SETUP.md (links, installs). Never auto-run. Merge on id= revise.`,
|
|
449
|
+
},
|
|
450
|
+
skills: {
|
|
451
|
+
type: "array",
|
|
452
|
+
items: { type: "string" },
|
|
453
|
+
description: `Advanced: skill dirs → ${MEMBER_PACK_BRIEFCASE} skills/<id>/ (full tree incl. references/). Merge on id=.`,
|
|
454
|
+
},
|
|
455
|
+
files: {
|
|
456
|
+
type: "array",
|
|
457
|
+
items: { type: "string" },
|
|
458
|
+
description: `Advanced: paths → ${MEMBER_PACK_BRIEFCASE} workspace/ (materials; not session cwd). Merge on id=.`,
|
|
164
459
|
},
|
|
165
460
|
},
|
|
166
461
|
additionalProperties: false,
|
|
167
462
|
},
|
|
168
|
-
presentCall: (args) => (
|
|
169
|
-
card: "generic",
|
|
170
|
-
title: "team_save",
|
|
171
|
-
kind: "execute",
|
|
172
|
-
rawInput: args,
|
|
173
|
-
}),
|
|
463
|
+
presentCall: (args) => teamPresent("team_save", "execute", args),
|
|
174
464
|
execute: async (args) => {
|
|
175
465
|
const a = readArgs(args);
|
|
176
466
|
const idProblem = memberIdProblem(a.id);
|
|
@@ -179,14 +469,15 @@ export function bindAgentRosterTools(tools, options) {
|
|
|
179
469
|
const catalogProblem = catalogMemberWriteProblem(a.id);
|
|
180
470
|
if (catalogProblem)
|
|
181
471
|
return { content: `team_save: ${catalogProblem}`, isError: true };
|
|
182
|
-
const
|
|
183
|
-
|
|
184
|
-
: undefined;
|
|
185
|
-
const name = String(a.name ?? "").trim() || captured?.name || "";
|
|
186
|
-
const playbook = String(a.playbook ?? "").trim() || captured?.playbook || "";
|
|
472
|
+
const name = String(a.name ?? "").trim();
|
|
473
|
+
const playbook = String(a.playbook ?? "").trim();
|
|
187
474
|
const roleRaw = typeof a.role === "string" ? a.role : "worker";
|
|
188
475
|
const canvasId = ws();
|
|
189
|
-
const
|
|
476
|
+
const wantsAdvanced = a.kind === "advanced" ||
|
|
477
|
+
(typeof a.env_prep === "string" && a.env_prep.trim().length > 0) ||
|
|
478
|
+
(Array.isArray(a.skills) && a.skills.length > 0) ||
|
|
479
|
+
(Array.isArray(a.files) && a.files.length > 0);
|
|
480
|
+
const scope = parseRosterScope(a.scope ?? (wantsAdvanced ? "global" : "workspace"));
|
|
190
481
|
if (scope === undefined) {
|
|
191
482
|
return {
|
|
192
483
|
content: 'team_save: scope must be "workspace" or "global"',
|
|
@@ -195,13 +486,169 @@ export function bindAgentRosterTools(tools, options) {
|
|
|
195
486
|
}
|
|
196
487
|
if (typeof a.id === "string" && a.id.trim()) {
|
|
197
488
|
const existing = runtime.agentRoster.get(canvasId, a.id.trim());
|
|
198
|
-
if (existing
|
|
489
|
+
if (!existing) {
|
|
490
|
+
return {
|
|
491
|
+
content: missingMemberHint(runtime, canvasId, a.id.trim(), "team_save"),
|
|
492
|
+
isError: true,
|
|
493
|
+
};
|
|
494
|
+
}
|
|
495
|
+
const toolsPatch = a.tools === null
|
|
496
|
+
? null
|
|
497
|
+
: a.tools !== undefined
|
|
498
|
+
? parseMemberToolPolicy(a.tools)
|
|
499
|
+
: undefined;
|
|
500
|
+
if (a.tools !== undefined && a.tools !== null && !toolsPatch) {
|
|
199
501
|
return {
|
|
200
|
-
content:
|
|
201
|
-
"Prep with team_list envPrep, then team_ready (or import a new pack). Do not downgrade via team_save.",
|
|
502
|
+
content: 'team_save: tools needs { mode: "allow"|"deny", names: [...] }',
|
|
202
503
|
isError: true,
|
|
203
504
|
};
|
|
204
505
|
}
|
|
506
|
+
const hasName = name.length > 0;
|
|
507
|
+
const hasPlaybook = playbook.length > 0;
|
|
508
|
+
const hasSurface = hasName ||
|
|
509
|
+
hasPlaybook ||
|
|
510
|
+
typeof a.brief === "string" ||
|
|
511
|
+
a.inject === "minimal" ||
|
|
512
|
+
a.inject === "subagent" ||
|
|
513
|
+
a.tools !== undefined;
|
|
514
|
+
if (existing.kind === "advanced") {
|
|
515
|
+
const rosterWs = existing.scope === "global" ? GLOBAL_ROSTER_ID : canvasId;
|
|
516
|
+
const packOpts = {
|
|
517
|
+
rosterWorkspaceId: rosterWs,
|
|
518
|
+
memberId: existing.id,
|
|
519
|
+
productHome: runtime.agentRoster.home,
|
|
520
|
+
};
|
|
521
|
+
let inventory = listMemberPackInventory(packOpts);
|
|
522
|
+
const skillPaths = resolveCwdPaths(runtime, sessionId, a.skills);
|
|
523
|
+
const filePaths = resolveCwdPaths(runtime, sessionId, a.files);
|
|
524
|
+
const envPrep = typeof a.env_prep === "string" && a.env_prep.trim()
|
|
525
|
+
? a.env_prep.trim()
|
|
526
|
+
: undefined;
|
|
527
|
+
if (skillPaths.length > 0 || filePaths.length > 0 || envPrep) {
|
|
528
|
+
let skillsFiles;
|
|
529
|
+
if (skillPaths.length > 0) {
|
|
530
|
+
const bundled = collectPackSkillFiles(skillPaths);
|
|
531
|
+
if (!bundled.ok) {
|
|
532
|
+
return { content: `team_save: ${bundled.error}`, isError: true };
|
|
533
|
+
}
|
|
534
|
+
skillsFiles = bundled.files;
|
|
535
|
+
}
|
|
536
|
+
let workspaceFiles;
|
|
537
|
+
if (filePaths.length > 0) {
|
|
538
|
+
const bundled = collectPackWorkspaceFiles(filePaths);
|
|
539
|
+
if (!bundled.ok) {
|
|
540
|
+
return { content: `team_save: ${bundled.error}`, isError: true };
|
|
541
|
+
}
|
|
542
|
+
workspaceFiles = bundled.files;
|
|
543
|
+
}
|
|
544
|
+
const merged = mergeIntoMemberPack({
|
|
545
|
+
...packOpts,
|
|
546
|
+
...(skillsFiles ? { skillsFiles } : {}),
|
|
547
|
+
...(workspaceFiles ? { workspaceFiles } : {}),
|
|
548
|
+
...(envPrep ? { envPrep } : {}),
|
|
549
|
+
});
|
|
550
|
+
if (!merged.ok) {
|
|
551
|
+
return { content: `team_save: ${merged.error}`, isError: true };
|
|
552
|
+
}
|
|
553
|
+
inventory = merged.inventory;
|
|
554
|
+
}
|
|
555
|
+
let patched = existing;
|
|
556
|
+
if (hasSurface) {
|
|
557
|
+
const next = patchExistingMember(runtime, canvasId, existing, {
|
|
558
|
+
...(hasName ? { name } : {}),
|
|
559
|
+
...(hasPlaybook ? { playbook } : {}),
|
|
560
|
+
...(typeof a.brief === "string" ? { brief: a.brief } : {}),
|
|
561
|
+
...(a.inject === "minimal" || a.inject === "subagent"
|
|
562
|
+
? { inject: a.inject }
|
|
563
|
+
: {}),
|
|
564
|
+
...(a.tools !== undefined ? { tools: toolsPatch ?? null } : {}),
|
|
565
|
+
});
|
|
566
|
+
if (!next) {
|
|
567
|
+
return {
|
|
568
|
+
content: "team_save: name and playbook required",
|
|
569
|
+
isError: true,
|
|
570
|
+
};
|
|
571
|
+
}
|
|
572
|
+
patched = next;
|
|
573
|
+
}
|
|
574
|
+
else if (skillPaths.length === 0 &&
|
|
575
|
+
filePaths.length === 0 &&
|
|
576
|
+
!envPrep) {
|
|
577
|
+
return {
|
|
578
|
+
content: "team_save: pass playbook/brief/inject/tools and/or skills/files/env_prep to revise",
|
|
579
|
+
isError: true,
|
|
580
|
+
};
|
|
581
|
+
}
|
|
582
|
+
return {
|
|
583
|
+
content: JSON.stringify({
|
|
584
|
+
workspaceId: patched.scope === "global" ? "global" : canvasId,
|
|
585
|
+
member: {
|
|
586
|
+
...enrichListedMember(runtime, canvasId, patched),
|
|
587
|
+
playbook: patched.playbook,
|
|
588
|
+
},
|
|
589
|
+
kind: "advanced",
|
|
590
|
+
briefcase: MEMBER_PACK_BRIEFCASE,
|
|
591
|
+
...(inventory ? { inventory } : {}),
|
|
592
|
+
next: patched.ready
|
|
593
|
+
? "subagent member_id · team_export to share"
|
|
594
|
+
: "follow envPrep → team_ready → subagent member_id",
|
|
595
|
+
}),
|
|
596
|
+
};
|
|
597
|
+
}
|
|
598
|
+
// Thin revise (or upgrade path falls through to mint when wantsAdvanced).
|
|
599
|
+
if (!wantsAdvanced) {
|
|
600
|
+
if (!hasSurface) {
|
|
601
|
+
return {
|
|
602
|
+
content: "team_save: pass playbook/brief/inject/tools to revise thin",
|
|
603
|
+
isError: true,
|
|
604
|
+
};
|
|
605
|
+
}
|
|
606
|
+
const patched = patchExistingMember(runtime, canvasId, existing, {
|
|
607
|
+
...(hasName ? { name } : {}),
|
|
608
|
+
...(hasPlaybook ? { playbook } : {}),
|
|
609
|
+
...(typeof a.brief === "string" ? { brief: a.brief } : {}),
|
|
610
|
+
...(a.inject === "minimal" || a.inject === "subagent"
|
|
611
|
+
? { inject: a.inject }
|
|
612
|
+
: {}),
|
|
613
|
+
...(a.tools !== undefined ? { tools: toolsPatch ?? null } : {}),
|
|
614
|
+
});
|
|
615
|
+
if (!patched) {
|
|
616
|
+
return {
|
|
617
|
+
content: "team_save: name and playbook required",
|
|
618
|
+
isError: true,
|
|
619
|
+
};
|
|
620
|
+
}
|
|
621
|
+
return {
|
|
622
|
+
content: JSON.stringify({
|
|
623
|
+
workspaceId: patched.scope === "global" ? "global" : canvasId,
|
|
624
|
+
member: enrichListedMember(runtime, canvasId, patched),
|
|
625
|
+
kind: "thin",
|
|
626
|
+
next: "subagent member_id",
|
|
627
|
+
}),
|
|
628
|
+
};
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
if (wantsAdvanced) {
|
|
632
|
+
const minted = mintAdvancedMember({
|
|
633
|
+
runtime,
|
|
634
|
+
sessionId,
|
|
635
|
+
canvasId,
|
|
636
|
+
scope,
|
|
637
|
+
name,
|
|
638
|
+
playbook,
|
|
639
|
+
roleRaw,
|
|
640
|
+
...(typeof a.brief === "string" ? { brief: a.brief } : {}),
|
|
641
|
+
inject: a.inject,
|
|
642
|
+
tools: a.tools,
|
|
643
|
+
...(typeof a.env_prep === "string" ? { envPrep: a.env_prep } : {}),
|
|
644
|
+
skills: a.skills,
|
|
645
|
+
files: a.files,
|
|
646
|
+
...(typeof a.id === "string" ? { id: a.id } : {}),
|
|
647
|
+
});
|
|
648
|
+
return {
|
|
649
|
+
content: minted.content,
|
|
650
|
+
...(minted.ok ? {} : { isError: true }),
|
|
651
|
+
};
|
|
205
652
|
}
|
|
206
653
|
const toolsPolicy = parseMemberToolPolicy(a.tools);
|
|
207
654
|
const member = runtime.agentRoster.upsertAtScope(canvasId, scope, {
|
|
@@ -232,45 +679,48 @@ export function bindAgentRosterTools(tools, options) {
|
|
|
232
679
|
});
|
|
233
680
|
registerTool(tools, {
|
|
234
681
|
name: "team_import",
|
|
235
|
-
description:
|
|
682
|
+
description: "Install a friend-shared 干员: card= (thin JSON) or pack= (advanced zip/dir/attachment → 公文包/briefcase). " +
|
|
683
|
+
"Then follow envPrep with this main session → team_ready. Illegal pack: inspect/fix → re-import. " +
|
|
684
|
+
"After import you may team_save id= to edit playbook or merge skills/files. Mint new → team_save (not this).",
|
|
236
685
|
parameters: {
|
|
237
686
|
type: "object",
|
|
238
687
|
properties: {
|
|
239
688
|
card: {
|
|
240
689
|
type: "string",
|
|
241
|
-
description: "Thin JSON (kind xrk-agent-member). Omit when pack
|
|
690
|
+
description: "Thin JSON (kind xrk-agent-member). Omit when pack.",
|
|
242
691
|
},
|
|
243
692
|
pack: {
|
|
244
693
|
type: "string",
|
|
245
694
|
description: "Marked pack zip/dir path (cwd-relative OK) or upload id " +
|
|
246
|
-
"(attachment:sha256:… / sha256:…
|
|
695
|
+
"(attachment:sha256:… / sha256:…). Omit when card.",
|
|
247
696
|
},
|
|
248
697
|
scope: {
|
|
249
698
|
type: "string",
|
|
250
|
-
description: "global | workspace.
|
|
251
|
-
"Defaults: card→workspace, pack→global (pass workspace for project-only packs).",
|
|
699
|
+
description: "global | workspace. Defaults: card→workspace; pack→global (shareable).",
|
|
252
700
|
},
|
|
253
701
|
},
|
|
254
702
|
additionalProperties: false,
|
|
255
703
|
},
|
|
256
|
-
presentCall: (args) => (
|
|
257
|
-
card: "generic",
|
|
258
|
-
title: "team_import",
|
|
259
|
-
kind: "execute",
|
|
260
|
-
rawInput: args,
|
|
261
|
-
}),
|
|
704
|
+
presentCall: (args) => teamPresent("team_import", "execute", args),
|
|
262
705
|
execute: async (args) => {
|
|
263
706
|
const a = readArgs(args);
|
|
707
|
+
if (a.from_session === true) {
|
|
708
|
+
return {
|
|
709
|
+
content: "team_import: minting moved to team_save (kind=advanced + name/playbook/skills/files). " +
|
|
710
|
+
"team_import is only card= or pack= install.",
|
|
711
|
+
isError: true,
|
|
712
|
+
};
|
|
713
|
+
}
|
|
264
714
|
const hasCard = typeof a.card === "string" && a.card.trim().length > 0;
|
|
265
715
|
const hasPack = typeof a.pack === "string" && a.pack.trim().length > 0;
|
|
266
716
|
if (hasCard === hasPack) {
|
|
267
717
|
return {
|
|
268
|
-
content: "team_import: set exactly one of card (JSON) or pack (path|attachment
|
|
718
|
+
content: "team_import: set exactly one of card (JSON) or pack (path|attachment). " +
|
|
719
|
+
"Mint new → team_save.",
|
|
269
720
|
isError: true,
|
|
270
721
|
};
|
|
271
722
|
}
|
|
272
|
-
|
|
273
|
-
const scope = parseRosterScope(a.scope ?? (hasPack ? "global" : "workspace"));
|
|
723
|
+
const scope = parseRosterScope(a.scope ?? (hasCard ? "workspace" : "global"));
|
|
274
724
|
if (scope === undefined) {
|
|
275
725
|
return { content: 'team_import: scope must be "workspace" or "global"', isError: true };
|
|
276
726
|
}
|
|
@@ -299,8 +749,8 @@ export function bindAgentRosterTools(tools, options) {
|
|
|
299
749
|
}),
|
|
300
750
|
};
|
|
301
751
|
}
|
|
302
|
-
const
|
|
303
|
-
const loaded = await loadPackFromArg(runtime, sessionId,
|
|
752
|
+
const packLabel = String(a.pack);
|
|
753
|
+
const loaded = await loadPackFromArg(runtime, sessionId, packLabel);
|
|
304
754
|
if (!loaded.ok)
|
|
305
755
|
return { content: `team_import: ${loaded.error}`, isError: true };
|
|
306
756
|
const member = runtime.agentRoster.upsertAtScope(canvasId, scope, {
|
|
@@ -322,31 +772,37 @@ export function bindAgentRosterTools(tools, options) {
|
|
|
322
772
|
visibility,
|
|
323
773
|
member,
|
|
324
774
|
source: "pack",
|
|
325
|
-
pack:
|
|
775
|
+
pack: packLabel,
|
|
326
776
|
packDir: placed.packDir,
|
|
327
777
|
skillNames: placed.skillNames,
|
|
328
778
|
ready: false,
|
|
329
779
|
...(placed.envPrep
|
|
330
780
|
? {
|
|
331
781
|
envPrep: placed.envPrep,
|
|
332
|
-
envHint: "Review envPrep
|
|
782
|
+
envHint: "Review envPrep here (or hand zip to a friend). Then team_ready. Do not auto-run scripts.",
|
|
333
783
|
}
|
|
334
784
|
: {
|
|
335
|
-
envHint: "No env/SETUP.md —
|
|
785
|
+
envHint: "No env/SETUP.md — team_ready when configured; friend gets playbook (± skills).",
|
|
336
786
|
}),
|
|
337
|
-
next: "team_ready → subagent member_id
|
|
787
|
+
next: "team_ready → subagent member_id",
|
|
788
|
+
layout: AGENT_MEMBER_PACK_LAYOUT,
|
|
789
|
+
pathHint: `Spawn keeps parent workspace cwd. ${MEMBER_PACK_BRIEFCASE} = pack_home (injected) — child may read/edit/copy into workspace. Share zip with relative paths under the pack tree.`,
|
|
790
|
+
shareHint: "Friend: team_export zip / UI import, or they team_import pack=… → follow envPrep with main session → team_ready. " +
|
|
791
|
+
"scope=global keeps it on every canvas team_list.",
|
|
338
792
|
}),
|
|
339
793
|
};
|
|
340
794
|
},
|
|
341
795
|
});
|
|
342
796
|
registerTool(tools, {
|
|
343
797
|
name: "team_ready",
|
|
344
|
-
description: "Mark an advanced
|
|
345
|
-
"
|
|
798
|
+
description: "Mark an advanced 干员 ready after env prep. " +
|
|
799
|
+
"Triggers: team_list shows not-ready; UI zip import; user says 帮我就绪 / mark ready / prep done. " +
|
|
800
|
+
"Flow: team_list → read envPrep → help install if needed → team_ready id=. " +
|
|
801
|
+
"Thin members stay ready. Required before subagent member_id on advanced.",
|
|
346
802
|
parameters: {
|
|
347
803
|
type: "object",
|
|
348
804
|
properties: {
|
|
349
|
-
id: { type: "string", description: "mem_…
|
|
805
|
+
id: { type: "string", description: "mem_… from team_list (not-ready advanced)" },
|
|
350
806
|
ready: {
|
|
351
807
|
type: "boolean",
|
|
352
808
|
description: "Default true. Pass false to mark not-ready again.",
|
|
@@ -355,12 +811,7 @@ export function bindAgentRosterTools(tools, options) {
|
|
|
355
811
|
required: ["id"],
|
|
356
812
|
additionalProperties: false,
|
|
357
813
|
},
|
|
358
|
-
presentCall: (args) => (
|
|
359
|
-
card: "generic",
|
|
360
|
-
title: "team_ready",
|
|
361
|
-
kind: "execute",
|
|
362
|
-
rawInput: args,
|
|
363
|
-
}),
|
|
814
|
+
presentCall: (args) => teamPresent("team_ready", "execute", args),
|
|
364
815
|
execute: async (args) => {
|
|
365
816
|
const a = readArgs(args);
|
|
366
817
|
const id = String(a.id ?? "").trim();
|
|
@@ -380,5 +831,133 @@ export function bindAgentRosterTools(tools, options) {
|
|
|
380
831
|
};
|
|
381
832
|
},
|
|
382
833
|
});
|
|
834
|
+
registerTool(tools, {
|
|
835
|
+
name: "team_export",
|
|
836
|
+
description: "Export a custom 干员 for the user: thin→JSON, advanced→zip (公文包/briefcase: playbook+skills+references+workspace+env). " +
|
|
837
|
+
"Writes to dir= (default session cwd). Catalog mem_seed_* cannot export — mint a copy first. " +
|
|
838
|
+
"User said 导出/分享这个干员 / export member. UI Export is equivalent.",
|
|
839
|
+
parameters: {
|
|
840
|
+
type: "object",
|
|
841
|
+
properties: {
|
|
842
|
+
id: { type: "string", description: "mem_… from team_list (not catalog)" },
|
|
843
|
+
dir: {
|
|
844
|
+
type: "string",
|
|
845
|
+
description: "Output directory (cwd-relative or absolute). Default: session cwd.",
|
|
846
|
+
},
|
|
847
|
+
},
|
|
848
|
+
required: ["id"],
|
|
849
|
+
additionalProperties: false,
|
|
850
|
+
},
|
|
851
|
+
presentCall: (args) => teamPresent("team_export", "execute", args),
|
|
852
|
+
execute: async (args) => {
|
|
853
|
+
const a = readArgs(args);
|
|
854
|
+
const id = String(a.id ?? "").trim();
|
|
855
|
+
if (!id)
|
|
856
|
+
return { content: "team_export: id required", isError: true };
|
|
857
|
+
const exported = await dispatchFaceMethod(runtime, "team.export", `te-${Date.now()}`, {
|
|
858
|
+
sessionId,
|
|
859
|
+
id,
|
|
860
|
+
});
|
|
861
|
+
if (!exported.result.ok) {
|
|
862
|
+
const msg = typeof exported.result.error === "object" &&
|
|
863
|
+
exported.result.error &&
|
|
864
|
+
"message" in exported.result.error
|
|
865
|
+
? String(exported.result.error.message)
|
|
866
|
+
: "export failed";
|
|
867
|
+
return { content: `team_export: ${msg}`, isError: true };
|
|
868
|
+
}
|
|
869
|
+
const value = exported.result.value;
|
|
870
|
+
const cwd = resolveSessionCwd(runtime, sessionId);
|
|
871
|
+
const dirRaw = typeof a.dir === "string" ? a.dir.trim() : "";
|
|
872
|
+
const outDir = dirRaw
|
|
873
|
+
? path.isAbsolute(dirRaw)
|
|
874
|
+
? dirRaw
|
|
875
|
+
: path.resolve(cwd, dirRaw)
|
|
876
|
+
: cwd;
|
|
877
|
+
const outPath = path.join(outDir, value.fileName);
|
|
878
|
+
try {
|
|
879
|
+
if (value.format === "json" && typeof value.text === "string") {
|
|
880
|
+
writeFileSync(outPath, value.text, "utf8");
|
|
881
|
+
}
|
|
882
|
+
else if (value.format === "zip" && typeof value.base64 === "string") {
|
|
883
|
+
writeFileSync(outPath, Buffer.from(value.base64, "base64"));
|
|
884
|
+
}
|
|
885
|
+
else {
|
|
886
|
+
return { content: "team_export: empty payload", isError: true };
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
catch (err) {
|
|
890
|
+
return {
|
|
891
|
+
content: `team_export: write failed — ${err instanceof Error ? err.message : String(err)}`,
|
|
892
|
+
isError: true,
|
|
893
|
+
};
|
|
894
|
+
}
|
|
895
|
+
return {
|
|
896
|
+
content: JSON.stringify({
|
|
897
|
+
format: value.format,
|
|
898
|
+
path: outPath,
|
|
899
|
+
fileName: value.fileName,
|
|
900
|
+
...(value.packIncomplete
|
|
901
|
+
? { packIncomplete: true, hint: value.hint }
|
|
902
|
+
: {}),
|
|
903
|
+
next: value.format === "zip"
|
|
904
|
+
? "Hand zip → team_import pack= → follow envPrep → team_ready"
|
|
905
|
+
: "Hand JSON → team_import card= or UI import",
|
|
906
|
+
}),
|
|
907
|
+
};
|
|
908
|
+
},
|
|
909
|
+
});
|
|
910
|
+
registerTool(tools, {
|
|
911
|
+
name: "team_remove",
|
|
912
|
+
description: "Uninstall a custom 干员 (not catalog mem_seed_*). Like deleting a skill. " +
|
|
913
|
+
"Pass id from team_list; scope global|workspace must match where it lives.",
|
|
914
|
+
parameters: {
|
|
915
|
+
type: "object",
|
|
916
|
+
properties: {
|
|
917
|
+
id: { type: "string", description: "mem_… to delete" },
|
|
918
|
+
scope: {
|
|
919
|
+
type: "string",
|
|
920
|
+
description: "global | workspace — must match team_list scope for that id",
|
|
921
|
+
},
|
|
922
|
+
},
|
|
923
|
+
required: ["id", "scope"],
|
|
924
|
+
additionalProperties: false,
|
|
925
|
+
},
|
|
926
|
+
presentCall: (args) => teamPresent("team_remove", "execute", args),
|
|
927
|
+
execute: async (args) => {
|
|
928
|
+
const a = readArgs(args);
|
|
929
|
+
const id = String(a.id ?? "").trim();
|
|
930
|
+
if (!id)
|
|
931
|
+
return { content: "team_remove: id required", isError: true };
|
|
932
|
+
const catalogProblem = catalogMemberWriteProblem(id);
|
|
933
|
+
if (catalogProblem) {
|
|
934
|
+
return { content: `team_remove: ${catalogProblem}`, isError: true };
|
|
935
|
+
}
|
|
936
|
+
const scope = parseRosterScope(a.scope);
|
|
937
|
+
if (scope === undefined) {
|
|
938
|
+
return {
|
|
939
|
+
content: 'team_remove: scope must be "workspace" or "global"',
|
|
940
|
+
isError: true,
|
|
941
|
+
};
|
|
942
|
+
}
|
|
943
|
+
const canvasId = ws();
|
|
944
|
+
const rosterWs = scope === "global" ? GLOBAL_ROSTER_ID : canvasId;
|
|
945
|
+
const ok = runtime.agentRoster.remove(rosterWs, id);
|
|
946
|
+
if (!ok) {
|
|
947
|
+
return {
|
|
948
|
+
content: missingMemberHint(runtime, canvasId, id, "team_remove"),
|
|
949
|
+
isError: true,
|
|
950
|
+
};
|
|
951
|
+
}
|
|
952
|
+
return {
|
|
953
|
+
content: JSON.stringify({
|
|
954
|
+
workspaceId: rosterWs,
|
|
955
|
+
deleted: true,
|
|
956
|
+
id,
|
|
957
|
+
next: "gone from team_list; zip/JSON copies elsewhere are untouched",
|
|
958
|
+
}),
|
|
959
|
+
};
|
|
960
|
+
},
|
|
961
|
+
});
|
|
383
962
|
}
|
|
384
963
|
//# sourceMappingURL=agent-roster-tools.js.map
|