@stofone/dsh-agent-roster 1.1.0 → 1.2.0
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/CHANGELOG.md +19 -0
- package/README.md +7 -1
- package/README.zh.md +9 -1
- package/client.js +156 -1
- package/index.js +2 -0
- package/locale/en.json +20 -1
- package/locale/zh.json +20 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,25 @@
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [1.2.0] - 2026-11-03
|
|
8
|
+
|
|
9
|
+
### Create a team from the row you are looking at
|
|
10
|
+
|
|
11
|
+
Creating a team used to require expanding the roster, finding the captain panel and pressing *apply*. The
|
|
12
|
+
one action the product is named after was the hardest thing to find, and a roster without a `captain` block
|
|
13
|
+
offered no path at all.
|
|
14
|
+
|
|
15
|
+
Every roster row now carries **Create team**. It opens a small dialog: team name (defaults to the roster id),
|
|
16
|
+
a choice between a new session and an existing one — new is the default, because quick creation must not
|
|
17
|
+
hijack the conversation you are in — and a one-line summary of what will be built (`N members · captain model`).
|
|
18
|
+
Submitting queues the same build prompt as *apply*; the toast names the session it landed in.
|
|
19
|
+
|
|
20
|
+
The boundary is unchanged, and the dialog says so on its face: the plugin never writes team state. It
|
|
21
|
+
prepares a session (selects the captain model when the archive declares one, queues the prompt), and that
|
|
22
|
+
session calls `agent_teams_create` / `agent_teams_add_member` / `roster_verify`. A roster without a captain
|
|
23
|
+
block can still create a team; it just will not switch the model, and the dialog says that instead of failing
|
|
24
|
+
silently.
|
|
25
|
+
|
|
7
26
|
## [1.1.0] - 2026-11-03
|
|
8
27
|
|
|
9
28
|
### The library reads as spaces, not groups
|
package/README.md
CHANGED
|
@@ -383,6 +383,12 @@ The **apply** action is the one write the panel offers here: it switches the cho
|
|
|
383
383
|
declared model and queues a prompt that calls `agent_teams_create`, `agent_teams_add_member` per
|
|
384
384
|
member and finally `roster_verify`. Creating the team stays with the runtime.
|
|
385
385
|
|
|
386
|
+
Since 1.2.0 the roster row itself carries **Create team**, so this no longer hides behind an
|
|
387
|
+
expanded card. It defaults to a *new* session — quick creation must not hijack the conversation
|
|
388
|
+
you are in — lets you rename the team, switches the captain model when the archive declares one,
|
|
389
|
+
and queues the same build prompt. The plugin still writes no team state: the row action prepares a
|
|
390
|
+
session, the session does the creating.
|
|
391
|
+
|
|
386
392
|
## Sidebar panel
|
|
387
393
|
|
|
388
394
|
The roster list is a **ledger, not a wall of cards**: one row per roster — a 3px state edge (lit only when something is wrong, quiet when it is fine), a monospace id column, the title with a one-line description, right-aligned counts (members / errors / warnings / deployment), and a quiet pair of actions (edit, expand). Duplicate, copy-create and delete moved into the expanded area, which turns 105 buttons across 21 rosters into 42. Below 860px the tag pool becomes a top row and the metadata wraps. Expansions never build their own scroll box: the panel root is the only scroller, so an expanded section grows as tall as its content instead of showing "just a few rows".
|
|
@@ -524,7 +530,7 @@ test/ unit tests
|
|
|
524
530
|
|
|
525
531
|
Verified on this machine:
|
|
526
532
|
|
|
527
|
-
- `npm test` —
|
|
533
|
+
- `npm test` — 315/315 passing (format, parse, validate, registry, paths, bridge, verify buckets, digests and provenance, roster diff, capability requirements and the capability gate, library organization, registry schema, lossless JSON, write plan/apply, all routes, panel snapshot and hints, dictionary consistency, tool contracts, client loader contract, library snapshot, config view, package manifest, declared fields and captain block, schema/constant alignment, the v2 role/roster/compiled layers and their schema alignment, v1→v2 migration, run records feeding the plan, remote registry and one-click install).
|
|
528
534
|
- `npm run smoke` — `apply()` registers all six tools through a real `defineTool` from a DSH bundle; `roster_list` / `roster_show` / `roster_create` / `roster_verify` / `roster_diff` execute, every output survives `lossless` checks, `path` overrides are honored, effect disposal runs cleanly. The same command then loads `client.js` against a stubbed module table and asserts the three slot registrations, style injection and effect disposal.
|
|
529
535
|
- CLI: `validate --dir examples` returns exit 0 over both example libraries.
|
|
530
536
|
- Installed into a real profile with the plugin manager (`plugin_manager install_bundle` against this directory → `link:` dependency + bundle entry); the profile re-reads the linked files on restart.
|
package/README.zh.md
CHANGED
|
@@ -370,6 +370,14 @@ node bin/cli.mjs compile --roster examples-orchestration/rosters/core-review \
|
|
|
370
370
|
设置页显示每个 profile 里实际部署的 provider / model,每份带 captain 段的档案按字段报
|
|
371
371
|
「一致 / 不一致 / 未声明 / 无法核对」。读不到部署配置时是「无法核对」,永远不会写成“通过”。
|
|
372
372
|
|
|
373
|
+
面板在这里唯一会写的一步是**应用**:把选中的会话切到声明的模型,再排入一条提示词,
|
|
374
|
+
让它依次调用 `agent_teams_create`、逐成员 `agent_teams_add_member`,最后 `roster_verify`。
|
|
375
|
+
建团队本身仍由运行时完成。
|
|
376
|
+
|
|
377
|
+
1.2.0 起,档案行上直接有**创建团队**,不必先展开卡片:默认开**新会话**(快速建团不该劫持
|
|
378
|
+
你正在聊的这个),可改团队名,档案声明了队长模型就一并切换,然后排入同样的建团提示词。
|
|
379
|
+
插件仍然不写团队状态——行上的按钮只负责把一个会话准备好,动手创建的是那个会话。
|
|
380
|
+
|
|
373
381
|
**应用**是这块唯一会写入的动作:把选中会话切到声明里的模型,并排入一段提示词,让它依次调用
|
|
374
382
|
`agent_teams_create`、逐成员 `agent_teams_add_member`,最后 `roster_verify` 核对。
|
|
375
383
|
团队仍由运行时创建,插件不代劳。
|
|
@@ -505,7 +513,7 @@ test/ 单测
|
|
|
505
513
|
|
|
506
514
|
本机已验证:
|
|
507
515
|
|
|
508
|
-
- `npm test` ——
|
|
516
|
+
- `npm test` —— 315/315 通过(格式、解析、校验、扫描、路径、桥接、核对四桶、摘要与溯源、档案差异、能力要求与能力闸门、档案库组织、索引 schema、无损 JSON、写入计划与执行、六条路由、快照与提示、两本词典一致、工具契约、客户端加载器契约、包清单、配置视图、样式 token 约束、声明层字段与队长段、schema 与常量对齐、v2 角色/组装/编译三层及其 schema 对齐、v1→v2 迁移、执行回执并入施工图)。
|
|
509
517
|
- `npm run smoke` —— 用真实 DSH bundle 的 `defineTool` 注册六个工具,逐个调用:输出全部通过无损校验、`path` 覆盖生效、释放干净;同一条命令随后用桩模块表加载 `client.js`,断言三处槽位注册、样式只注入一次、effect 可回收。
|
|
510
518
|
- CLI:`validate --dir examples` 对两座示例库退出码 0。
|
|
511
519
|
- 用插件管理器真的装进了本机 profile(`plugin_manager install_bundle` 指向本仓库 → `link:` 依赖 + bundle 条目),重启后按链接读取本仓库文件。
|
package/client.js
CHANGED
|
@@ -660,13 +660,147 @@ window.__ModuleLoader__.load({
|
|
|
660
660
|
);
|
|
661
661
|
}
|
|
662
662
|
|
|
663
|
+
/**
|
|
664
|
+
* 从档案创建团队:挑一个队长会话,把建团提示排进去。
|
|
665
|
+
*
|
|
666
|
+
* 为什么不是“插件直接建”:团队只能由队长会话里的 `agent_teams_create` 建,插件没有这个权限。
|
|
667
|
+
* 所以这个对话框做的是端到端的前半段——把成员、队长模型、建团步骤一次交给一个会话,
|
|
668
|
+
* 后半段(建队、加成员、核对)在那个会话里发生;结果回团队页签与 `roster_verify` 看。
|
|
669
|
+
*/
|
|
670
|
+
function TeamCreateDialog({ roster, sessions, onClose, onToast, onCreated }) {
|
|
671
|
+
useTranslation();
|
|
672
|
+
// 默认新会话:快速建团不该劫持用户正在聊的这个。
|
|
673
|
+
const [mode, setMode] = useState("new");
|
|
674
|
+
const [sessionId, setSessionId] = useState(sessions[0]?.sessionId ?? "");
|
|
675
|
+
const [cwd, setCwd] = useState(roster.rootDir ?? "");
|
|
676
|
+
const [teamName, setTeamName] = useState(roster.id);
|
|
677
|
+
const [busy, setBusy] = useState(false);
|
|
678
|
+
const [error, setError] = useState(null);
|
|
679
|
+
const captain = roster.captain ?? null;
|
|
680
|
+
const declaredModel =
|
|
681
|
+
captain !== null && captain.provider !== undefined && captain.model !== undefined && captain.provider !== "" && captain.model !== ""
|
|
682
|
+
? `${captain.provider}/${captain.model}`
|
|
683
|
+
: null;
|
|
684
|
+
const canSubmit = !busy && (mode === "new" || sessionId !== "");
|
|
685
|
+
|
|
686
|
+
async function submit() {
|
|
687
|
+
if (!canSubmit) return;
|
|
688
|
+
setBusy(true);
|
|
689
|
+
setError(null);
|
|
690
|
+
try {
|
|
691
|
+
const payload = { rosterId: roster.id, teamName: teamName.trim(), mode };
|
|
692
|
+
if (mode === "existing") payload.sessionId = sessionId;
|
|
693
|
+
else if (cwd.trim() !== "") payload.cwd = cwd.trim();
|
|
694
|
+
const response = await readJson(APPLY_ROUTE, {
|
|
695
|
+
method: "POST",
|
|
696
|
+
headers: { "content-type": "application/json" },
|
|
697
|
+
body: JSON.stringify(payload),
|
|
698
|
+
});
|
|
699
|
+
if (!response.ok || response.body?.ok !== true) {
|
|
700
|
+
setError(response.body?.code ?? response.body?.error?.code ?? String(response.status));
|
|
701
|
+
return;
|
|
702
|
+
}
|
|
703
|
+
onToast(t("teamCreate.queued", { session: response.body.sessionId }));
|
|
704
|
+
onCreated?.(response.body.sessionId);
|
|
705
|
+
onClose();
|
|
706
|
+
} catch {
|
|
707
|
+
setError("network");
|
|
708
|
+
} finally {
|
|
709
|
+
setBusy(false);
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
return h(
|
|
714
|
+
Modal,
|
|
715
|
+
{
|
|
716
|
+
title: t("teamCreate.title", { roster: roster.id }),
|
|
717
|
+
onClose,
|
|
718
|
+
footer: h(
|
|
719
|
+
"div",
|
|
720
|
+
{ className: "rstr-modal-foot-actions" },
|
|
721
|
+
h("button", { type: "button", className: "rstr-btn", onClick: onClose }, t("teamCreate.cancel")),
|
|
722
|
+
h(
|
|
723
|
+
"button",
|
|
724
|
+
{ type: "button", className: "rstr-btn rstr-btn-primary", disabled: !canSubmit, onClick: submit },
|
|
725
|
+
busy ? t("teamCreate.creating") : t("teamCreate.submit"),
|
|
726
|
+
),
|
|
727
|
+
),
|
|
728
|
+
},
|
|
729
|
+
h("p", { className: "rstr-hint" }, t("teamCreate.hint")),
|
|
730
|
+
h(
|
|
731
|
+
Field,
|
|
732
|
+
{ label: t("teamCreate.teamName") },
|
|
733
|
+
h("input", {
|
|
734
|
+
className: "rstr-input",
|
|
735
|
+
value: teamName,
|
|
736
|
+
onChange: (event) => setTeamName(event.target.value),
|
|
737
|
+
placeholder: roster.id,
|
|
738
|
+
}),
|
|
739
|
+
),
|
|
740
|
+
h(
|
|
741
|
+
Field,
|
|
742
|
+
{ label: t("teamCreate.target") },
|
|
743
|
+
h(
|
|
744
|
+
"div",
|
|
745
|
+
{ className: "rstr-segmented" },
|
|
746
|
+
h(
|
|
747
|
+
"button",
|
|
748
|
+
{ type: "button", className: mode === "new" ? "rstr-seg rstr-seg-on" : "rstr-seg", onClick: () => setMode("new") },
|
|
749
|
+
t("teamCreate.newSession"),
|
|
750
|
+
),
|
|
751
|
+
h(
|
|
752
|
+
"button",
|
|
753
|
+
{
|
|
754
|
+
type: "button",
|
|
755
|
+
className: mode === "existing" ? "rstr-seg rstr-seg-on" : "rstr-seg",
|
|
756
|
+
onClick: () => setMode("existing"),
|
|
757
|
+
},
|
|
758
|
+
t("teamCreate.existingSession"),
|
|
759
|
+
),
|
|
760
|
+
),
|
|
761
|
+
mode === "existing"
|
|
762
|
+
? h(
|
|
763
|
+
"select",
|
|
764
|
+
{ className: "rstr-select", value: sessionId, onChange: (event) => setSessionId(event.target.value) },
|
|
765
|
+
sessions.length === 0
|
|
766
|
+
? h("option", { value: "" }, t("teamCreate.noSessions"))
|
|
767
|
+
: sessions.map((session) =>
|
|
768
|
+
h(
|
|
769
|
+
"option",
|
|
770
|
+
{ key: session.sessionId, value: session.sessionId },
|
|
771
|
+
`${session.sessionId.slice(0, 12)} · ${session.cwd || "?"}${
|
|
772
|
+
session.model === null ? "" : ` · ${session.model.model}`
|
|
773
|
+
}`,
|
|
774
|
+
),
|
|
775
|
+
),
|
|
776
|
+
)
|
|
777
|
+
: h("input", {
|
|
778
|
+
className: "rstr-input",
|
|
779
|
+
placeholder: t("teamCreate.cwdPlaceholder"),
|
|
780
|
+
value: cwd,
|
|
781
|
+
onChange: (event) => setCwd(event.target.value),
|
|
782
|
+
}),
|
|
783
|
+
),
|
|
784
|
+
h(
|
|
785
|
+
"p",
|
|
786
|
+
{ className: "rstr-hint" },
|
|
787
|
+
t("teamCreate.summary", {
|
|
788
|
+
count: roster.members.length,
|
|
789
|
+
model: declaredModel ?? t("teamCreate.noModel"),
|
|
790
|
+
}),
|
|
791
|
+
),
|
|
792
|
+
captain === null ? h("p", { className: "rstr-hint" }, t("teamCreate.noCaptain")) : null,
|
|
793
|
+
error !== null ? h("p", { className: "rstr-bad rstr-small" }, t("teamCreate.failed", { code: error })) : null,
|
|
794
|
+
);
|
|
795
|
+
}
|
|
796
|
+
|
|
663
797
|
/**
|
|
664
798
|
* 一行 = 一份档案。
|
|
665
799
|
*
|
|
666
800
|
* 名册是列表不是画廊:id 立在第一列当"脊",状态长在左沿,操作平时只露两个入口。
|
|
667
801
|
* 复制/建队/删除这些低频且危险的动作收进展开区——否则 21 份档案就是 105 个按钮。
|
|
668
802
|
*/
|
|
669
|
-
function RosterCard({ roster, deployment, captainReport, sessions, onToast, onEdit, onDuplicate, onDelete, onCopy }) {
|
|
803
|
+
function RosterCard({ roster, deployment, captainReport, sessions, onToast, onEdit, onDuplicate, onDelete, onCopy, onCreateTeam }) {
|
|
670
804
|
const [open, setOpen] = useState(false);
|
|
671
805
|
const diagnostics = roster.diagnostics ?? [];
|
|
672
806
|
const errors = diagnostics.filter((item) => item?.severity === "error").length;
|
|
@@ -717,6 +851,11 @@ window.__ModuleLoader__.load({
|
|
|
717
851
|
h(
|
|
718
852
|
"div",
|
|
719
853
|
{ className: "rstr-row-actions" },
|
|
854
|
+
h(
|
|
855
|
+
"button",
|
|
856
|
+
{ type: "button", className: "rstr-btn rstr-btn-sm", onClick: () => onCreateTeam(roster) },
|
|
857
|
+
t("roster.createTeam"),
|
|
858
|
+
),
|
|
720
859
|
h("button", { type: "button", className: "rstr-btn rstr-btn-sm rstr-btn-quiet", onClick: () => onEdit(roster) }, t("roster.edit")),
|
|
721
860
|
h(
|
|
722
861
|
"button",
|
|
@@ -1609,6 +1748,7 @@ window.__ModuleLoader__.load({
|
|
|
1609
1748
|
const [editor, setEditor] = useState(null);
|
|
1610
1749
|
const [importing, setImporting] = useState(false);
|
|
1611
1750
|
const [removing, setRemoving] = useState(null);
|
|
1751
|
+
const [creatingTeam, setCreatingTeam] = useState(null);
|
|
1612
1752
|
const [toast, setToast] = useState(null);
|
|
1613
1753
|
|
|
1614
1754
|
useEffect(() => {
|
|
@@ -1936,6 +2076,7 @@ window.__ModuleLoader__.load({
|
|
|
1936
2076
|
onDuplicate: () => setEditor({ roster, rootDir: roster.rootDir, duplicate: true }),
|
|
1937
2077
|
onDelete: () => setRemoving(roster),
|
|
1938
2078
|
onCopy: copyPayload,
|
|
2079
|
+
onCreateTeam: (target) => setCreatingTeam(target),
|
|
1939
2080
|
}),
|
|
1940
2081
|
),
|
|
1941
2082
|
),
|
|
@@ -2030,6 +2171,18 @@ window.__ModuleLoader__.load({
|
|
|
2030
2171
|
},
|
|
2031
2172
|
})
|
|
2032
2173
|
: null,
|
|
2174
|
+
creatingTeam !== null
|
|
2175
|
+
? h(TeamCreateDialog, {
|
|
2176
|
+
roster: creatingTeam,
|
|
2177
|
+
sessions: snapshot?.sessions?.sessions ?? [],
|
|
2178
|
+
onClose: () => setCreatingTeam(null),
|
|
2179
|
+
onToast: setToast,
|
|
2180
|
+
onCreated: () => {
|
|
2181
|
+
setCreatingTeam(null);
|
|
2182
|
+
library.reload();
|
|
2183
|
+
},
|
|
2184
|
+
})
|
|
2185
|
+
: null,
|
|
2033
2186
|
removing !== null
|
|
2034
2187
|
? h(DeleteDialog, {
|
|
2035
2188
|
roster: removing,
|
|
@@ -2908,6 +3061,8 @@ window.__ModuleLoader__.load({
|
|
|
2908
3061
|
.rstr-apply { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
|
|
2909
3062
|
.rstr-segmented { display: inline-flex; border: 1px solid var(--dsw-alias-border-l3); }
|
|
2910
3063
|
.rstr-seg { border: none; background: transparent; padding: 5px 12px; font-size: 12px; font-family: inherit; cursor: pointer; color: var(--dsw-alias-label-secondary); }
|
|
3064
|
+
/* 对话框里的二选一开关:字段列默认拉伸,这里收回内容宽度,别让它长得像第二个输入框。 */
|
|
3065
|
+
.rstr-field > .rstr-segmented { align-self: flex-start; }
|
|
2911
3066
|
.rstr-seg:hover { background: var(--dsw-alias-interactive-bg-hover); }
|
|
2912
3067
|
.rstr-seg-on { background: color-mix(in srgb, var(--dsw-alias-state-business-primary) 10%, transparent); color: var(--dsw-alias-label-primary); font-weight: 600; }
|
|
2913
3068
|
|
package/index.js
CHANGED
|
@@ -441,6 +441,8 @@ export function apply(ctx, config) {
|
|
|
441
441
|
mode: input.mode === "new" ? "new" : "existing",
|
|
442
442
|
sessionId: typeof input.sessionId === "string" ? input.sessionId : "",
|
|
443
443
|
cwd: typeof input.cwd === "string" ? input.cwd : "",
|
|
444
|
+
// 团队名只进提示词,不写任何团队状态;超长按 120 截断,与档案标题同量级。
|
|
445
|
+
teamName: typeof input.teamName === "string" ? input.teamName.trim().slice(0, 120) : "",
|
|
444
446
|
});
|
|
445
447
|
const status = result.ok ? 200 : result.code === "session-controller-unavailable" ? 503 : 400;
|
|
446
448
|
sendJson(res, status, result);
|
package/locale/en.json
CHANGED
|
@@ -86,7 +86,8 @@
|
|
|
86
86
|
"showMembers": "Show members",
|
|
87
87
|
"hideMembers": "Hide members",
|
|
88
88
|
"warnings": "{count} warnings",
|
|
89
|
-
"deployedDrifted": "In {teams} ({count} drifted)"
|
|
89
|
+
"deployedDrifted": "In {teams} ({count} drifted)",
|
|
90
|
+
"createTeam": "Create team"
|
|
90
91
|
},
|
|
91
92
|
"member": {
|
|
92
93
|
"prompt": "Prompt",
|
|
@@ -323,5 +324,23 @@
|
|
|
323
324
|
"pulledSpace": "Space pulled: {files} files written, {skipped} skipped",
|
|
324
325
|
"facts": "{count} rosters · {installed} here",
|
|
325
326
|
"here": "Already here"
|
|
327
|
+
},
|
|
328
|
+
"teamCreate": {
|
|
329
|
+
"title": "Create a team from {roster}",
|
|
330
|
+
"hint": "The plugin never writes team state: it queues a build prompt into the captain session, which then calls agent_teams_create and adds each member.",
|
|
331
|
+
"teamName": "Team name",
|
|
332
|
+
"target": "Captain session",
|
|
333
|
+
"newSession": "New session",
|
|
334
|
+
"existingSession": "Existing session",
|
|
335
|
+
"noSessions": "No session available",
|
|
336
|
+
"cwdPlaceholder": "Working directory (empty = current workspace)",
|
|
337
|
+
"summary": "{count} members · captain model {model}",
|
|
338
|
+
"noModel": "not declared, the session keeps its model",
|
|
339
|
+
"noCaptain": "This roster has no captain block: it can still build a team, but the captain model is not switched.",
|
|
340
|
+
"submit": "Create",
|
|
341
|
+
"creating": "Queueing…",
|
|
342
|
+
"cancel": "Cancel",
|
|
343
|
+
"queued": "Queued into session {session} — that session will build the team.",
|
|
344
|
+
"failed": "Could not queue ({code})"
|
|
326
345
|
}
|
|
327
346
|
}
|
package/locale/zh.json
CHANGED
|
@@ -86,7 +86,8 @@
|
|
|
86
86
|
"showMembers": "展开成员",
|
|
87
87
|
"hideMembers": "收起成员",
|
|
88
88
|
"warnings": "{count} 条提醒",
|
|
89
|
-
"deployedDrifted": "在 {teams}({count} 处不一致)"
|
|
89
|
+
"deployedDrifted": "在 {teams}({count} 处不一致)",
|
|
90
|
+
"createTeam": "创建团队"
|
|
90
91
|
},
|
|
91
92
|
"member": {
|
|
92
93
|
"prompt": "人设",
|
|
@@ -323,5 +324,23 @@
|
|
|
323
324
|
"pulledSpace": "空间已拉取:写入 {files} 个文件,跳过 {skipped} 个",
|
|
324
325
|
"facts": "{count} 份 · 已装 {installed}",
|
|
325
326
|
"here": "已在本机"
|
|
327
|
+
},
|
|
328
|
+
"teamCreate": {
|
|
329
|
+
"title": "从 {roster} 创建团队",
|
|
330
|
+
"hint": "插件不写团队状态:它只把建团提示排进队长会话,由那个会话调用 agent_teams_create 并逐个加成员。",
|
|
331
|
+
"teamName": "团队名",
|
|
332
|
+
"target": "队长会话",
|
|
333
|
+
"newSession": "新会话",
|
|
334
|
+
"existingSession": "已有会话",
|
|
335
|
+
"noSessions": "没有可选的会话",
|
|
336
|
+
"cwdPlaceholder": "工作目录(留空用当前工作区)",
|
|
337
|
+
"summary": "将建 {count} 名成员 · 队长模型 {model}",
|
|
338
|
+
"noModel": "未声明,沿用会话当前模型",
|
|
339
|
+
"noCaptain": "这份档案没有 captain 段:仍可建团,但不会切换队长模型。",
|
|
340
|
+
"submit": "创建",
|
|
341
|
+
"creating": "排队中…",
|
|
342
|
+
"cancel": "取消",
|
|
343
|
+
"queued": "已排入会话 {session}——那个会话会开始建队。",
|
|
344
|
+
"failed": "排队失败({code})"
|
|
326
345
|
}
|
|
327
346
|
}
|
package/package.json
CHANGED