dsh-plugin-t-expert 0.3.6 → 0.3.25
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/README.md +101 -276
- package/data/.t-team-snapshot.json +10 -0
- package/data/experts/engineering/engineering-security-engineer.md +303 -0
- package/data/experts/engineering/engineering-threat-detection-engineer.md +553 -0
- package/data/experts/finance/finance-financial-forecaster.md +213 -0
- package/data/experts/hr/hr-recruiter.md +232 -0
- package/data/experts/marketing/marketing-search-growth-orchestrator.md +372 -0
- package/data/experts/specialized/specialized-pricing-optimizer.md +254 -0
- package/data/experts/support/support-recruitment-specialist.md +508 -0
- package/data/source.json +2 -2
- package/data/t-team.config.json +826 -1126
- package/data/teams.json +486 -672
- package/data/teams.resolved.json +743 -1109
- package/data/zh/COVERAGE.json +4 -4
- package/data/zh/company/chief-of-staff.md +278 -0
- package/data/zh/descriptions.json +21 -14
- package/data/zh/divisions.json +3 -3
- package/data/zh/engineering/engineering-security-engineer.md +303 -0
- package/data/zh/engineering/engineering-threat-detection-engineer.md +553 -0
- package/data/zh/finance/finance-financial-forecaster.md +213 -0
- package/data/zh/hr/hr-recruiter.md +232 -0
- package/data/zh/manual.json +4 -4
- package/data/zh/marketing/marketing-aeo-foundations.md +489 -219
- package/data/zh/marketing/marketing-ai-citation-strategist.md +692 -140
- package/data/zh/marketing/marketing-bilibili-strategist.md +194 -0
- package/data/zh/marketing/marketing-search-growth-orchestrator.md +372 -0
- package/data/zh/marketing/marketing-seo-specialist.md +427 -245
- package/data/zh/names.json +21 -14
- package/data/zh/specialized/recruitment-specialist.md +490 -31
- package/data/zh/specialized/specialized-french-consulting-market.md +173 -28
- package/data/zh/specialized/specialized-korean-business-navigator.md +198 -29
- package/data/zh/specialized/specialized-pricing-optimizer.md +254 -0
- package/data/zh/support/support-recruitment-specialist.md +508 -0
- package/lib/catalog.js +3 -3
- package/lib/client.js +450 -93
- package/lib/index.js +198 -14
- package/lib/remote-schemas.js +26 -1
- package/lib/remote.js +65 -5
- package/lib/schedule.js +14 -1
- package/lib/skill.js +21 -5
- package/lib/teams/state.js +9 -0
- package/package.json +4 -3
- package/vendor/third-party-licenses/README.md +2 -2
- package/data/zh/marketing/marketing-bilibili-content-strategist.md +0 -40
- package/data/zh/specialized/specialized-chief-of-staff.md +0 -40
- package/skills/t-expert-manager/SKILL.md +0 -125
- package/skills/t-expert-manager/references/ops-reference.md +0 -100
- /package/data/experts/{specialized/specialized-chief-of-staff.md → company/chief-of-staff.md} +0 -0
- /package/data/experts/engineering/{engineering-china-network-engineer.md → engineering-network-engineer-china.md} +0 -0
- /package/data/experts/marketing/{marketing-bilibili-content-strategist.md → marketing-bilibili-strategist.md} +0 -0
- /package/data/experts/marketing/{marketing-china-ecommerce-operator.md → marketing-ecommerce-operator.md} +0 -0
- /package/data/experts/marketing/{marketing-wechat-official-account.md → marketing-wechat-operator.md} +0 -0
- /package/data/experts/marketing/{marketing-xiaohongshu-specialist.md → marketing-xiaohongshu-operator.md} +0 -0
- /package/data/experts/{engineering/engineering-prompt-engineer.md → specialized/prompt-engineer.md} +0 -0
- /package/data/zh/engineering/{engineering-china-network-engineer.md → engineering-network-engineer-china.md} +0 -0
- /package/data/zh/manual-bodies/engineering/{engineering-china-network-engineer.md → engineering-network-engineer-china.md} +0 -0
- /package/data/zh/marketing/{marketing-china-ecommerce-operator.md → marketing-ecommerce-operator.md} +0 -0
- /package/data/zh/marketing/{marketing-wechat-official-account.md → marketing-wechat-operator.md} +0 -0
- /package/data/zh/marketing/{marketing-xiaohongshu-specialist.md → marketing-xiaohongshu-operator.md} +0 -0
- /package/data/zh/{engineering/engineering-prompt-engineer.md → specialized/prompt-engineer.md} +0 -0
package/lib/client.js
CHANGED
|
@@ -19925,6 +19925,14 @@ var teamSchema = external_exports.object({
|
|
|
19925
19925
|
teamId: external_exports.string(),
|
|
19926
19926
|
name: external_exports.string(),
|
|
19927
19927
|
workspace: external_exports.string(),
|
|
19928
|
+
// 2026-09-15:teamId 是团队名 slug 化的结果,**跨工作区会重名**,客户端把 workspacePath
|
|
19929
|
+
// 回传给 stop/deleteTeam 才能精确定位(strict schema 不声明就会被剥掉)。
|
|
19930
|
+
// 两个字段都 `.optional()` 是**兼容闸门**:客户端产物热重载,host 可能是旧的(不返回它们)——
|
|
19931
|
+
// 那时必需字段会让 `teamsSnapshotSchema.parse` 直接失败、列表**整片空白**。可选之后退化为
|
|
19932
|
+
// 「按 halted 判定按钮 + 按 teamId 全量遍历」的旧行为,而不是白屏。
|
|
19933
|
+
workspacePath: external_exports.string().optional(),
|
|
19934
|
+
/** 队长会话此刻是否在运行:客户端据此决定按钮叫「停止」还是「归档」。 */
|
|
19935
|
+
captainActive: external_exports.boolean().optional(),
|
|
19928
19936
|
captainSessionId: external_exports.string(),
|
|
19929
19937
|
phase: external_exports.string(),
|
|
19930
19938
|
halted: external_exports.boolean(),
|
|
@@ -19940,7 +19948,16 @@ var startResultSchema = external_exports.object({
|
|
|
19940
19948
|
var stopResultSchema = external_exports.object({
|
|
19941
19949
|
teamName: external_exports.string(),
|
|
19942
19950
|
cancelledTasks: external_exports.number(),
|
|
19943
|
-
alreadyHalted: external_exports.boolean()
|
|
19951
|
+
alreadyHalted: external_exports.boolean(),
|
|
19952
|
+
// 2026-09-15 起,「停止」在队长会话已结束(或团队早已 halted)时改为**归档**:
|
|
19953
|
+
// 这个字段让面板知道该报「已停止」还是「已归档」。
|
|
19954
|
+
archived: external_exports.boolean()
|
|
19955
|
+
});
|
|
19956
|
+
var deleteTeamResultSchema = external_exports.object({
|
|
19957
|
+
teamName: external_exports.string(),
|
|
19958
|
+
deleted: external_exports.boolean(),
|
|
19959
|
+
// 删掉的是归档里那份(而不是还挂在「运行中」的那份)
|
|
19960
|
+
wasArchived: external_exports.boolean()
|
|
19944
19961
|
});
|
|
19945
19962
|
var squadInputSchema = external_exports.object({
|
|
19946
19963
|
key: external_exports.string().min(1).max(64),
|
|
@@ -19978,7 +19995,8 @@ var scheduleSnapshotSchema = external_exports.object({
|
|
|
19978
19995
|
/** 正在执行中的事项 id(面板据此显示「执行中…」)。 */
|
|
19979
19996
|
running: external_exports.array(external_exports.string()),
|
|
19980
19997
|
capabilities: external_exports.object({ agents: external_exports.boolean(), presets: external_exports.boolean() }),
|
|
19981
|
-
|
|
19998
|
+
/** 可选工作区(下拉选项);path 是目录,面板显示给用户看落地位置。 */
|
|
19999
|
+
workspaces: external_exports.array(external_exports.object({ id: external_exports.string(), title: external_exports.string(), path: external_exports.string().optional() }))
|
|
19982
20000
|
});
|
|
19983
20001
|
var scheduleInputSchema = external_exports.object({
|
|
19984
20002
|
title: external_exports.string().min(1).max(200),
|
|
@@ -19991,10 +20009,13 @@ var scheduleInputSchema = external_exports.object({
|
|
|
19991
20009
|
var schedulePatchSchema = scheduleInputSchema.partial();
|
|
19992
20010
|
var schedulePreviewSchema = external_exports.object({ fires: external_exports.array(external_exports.string()) });
|
|
19993
20011
|
var scheduleArmedSchema = external_exports.object({ armed: external_exports.boolean() });
|
|
20012
|
+
var scheduleWorkspaceSchema = external_exports.object({
|
|
20013
|
+
workspace: external_exports.object({ id: external_exports.string(), title: external_exports.string(), path: external_exports.string() })
|
|
20014
|
+
});
|
|
19994
20015
|
|
|
19995
20016
|
// src/client.jsx
|
|
19996
20017
|
var NS = "t-team";
|
|
19997
|
-
var CLIENT_BUILD_VERSION = "0.3.
|
|
20018
|
+
var CLIENT_BUILD_VERSION = "0.3.25";
|
|
19998
20019
|
var uiPrefs = { showTaskBadge: true, showScheduleButton: true };
|
|
19999
20020
|
var uiPrefsListeners = /* @__PURE__ */ new Set();
|
|
20000
20021
|
function setUiPrefs(next) {
|
|
@@ -20187,6 +20208,16 @@ var zh = {
|
|
|
20187
20208
|
"teams.stopConfirm": "\u505C\u6B62\u56E2\u961F\u300C{name}\u300D\uFF1F\u672A\u5B8C\u6210\u7684\u4EFB\u52A1\u4F1A\u88AB\u53D6\u6D88\uFF0C\u5DF2\u4EA4\u4ED8\u7ED3\u679C\u4FDD\u7559\u3002",
|
|
20188
20209
|
"teams.stopping": "\u505C\u6B62\u4E2D\u2026",
|
|
20189
20210
|
"teams.stopped": "\u5DF2\u505C\u6B62 {name}\uFF08\u53D6\u6D88 {count} \u9879\u4EFB\u52A1\uFF09",
|
|
20211
|
+
// 已停止、或队长会话已结束的团队:按钮改为「归档」——它本来就已经不干活了,
|
|
20212
|
+
// 唯一还想要的动作是把它从「运行中」列表里清掉(任务记录进「看归档」)。
|
|
20213
|
+
"teams.archive": "\u5F52\u6863",
|
|
20214
|
+
"teams.archiveConfirm": "\u5F52\u6863\u56E2\u961F\u300C{name}\u300D\uFF1F\u5B83\u4F1A\u4ECE\u300C\u8FD0\u884C\u4E2D\u300D\u79FB\u5230\u300C\u770B\u5F52\u6863\u300D\uFF0C\u4EFB\u52A1\u8BB0\u5F55\u4FDD\u7559\u3002",
|
|
20215
|
+
"teams.archiving": "\u5F52\u6863\u4E2D\u2026",
|
|
20216
|
+
"teams.archivedNote": "\u5DF2\u5F52\u6863 {name}",
|
|
20217
|
+
"teams.remove": "\u5220\u9664",
|
|
20218
|
+
"teams.removeConfirm": "\u5220\u9664\u56E2\u961F\u300C{name}\u300D\uFF1F\u56E2\u961F\u72B6\u6001\u4E0E\u4EFB\u52A1\u8BB0\u5F55\u4F1A\u88AB\u6C38\u4E45\u5220\u9664\uFF0C\u65E0\u6CD5\u6062\u590D\u3002",
|
|
20219
|
+
"teams.removing": "\u5220\u9664\u4E2D\u2026",
|
|
20220
|
+
"teams.removed": "\u5DF2\u5220\u9664 {name}",
|
|
20190
20221
|
"teams.refresh": "\u5237\u65B0",
|
|
20191
20222
|
"teams.tasks": "{done}/{total} \u4EFB\u52A1",
|
|
20192
20223
|
"teams.members": "{count} \u540D\u6210\u5458",
|
|
@@ -20238,6 +20269,11 @@ var zh = {
|
|
|
20238
20269
|
"sched.workspace": "\u5DE5\u4F5C\u533A",
|
|
20239
20270
|
"sched.workspaceNone": "\u4E0D\u7ED1\u5B9A\u5DE5\u4F5C\u533A\uFF08\u9ED8\u8BA4\u76EE\u5F55\uFF09",
|
|
20240
20271
|
"sched.workspaceHint": "\u6267\u884C\u65F6\u4F1A\u5728\u8FD9\u4E2A\u5DE5\u4F5C\u533A\u4E0B\u65B0\u5EFA\u4F1A\u8BDD\uFF0C\u5E76\u663E\u793A\u5728\u5DE5\u4F5C\u533A\u5206\u7EC4\u91CC\u3002",
|
|
20272
|
+
"sched.workspacePath": "\u76EE\u5F55\uFF1A{path}",
|
|
20273
|
+
"sched.workspaceCustom": "\uFF0B \u81EA\u5B9A\u4E49\u76EE\u5F55\u2026",
|
|
20274
|
+
"sched.workspaceCustomPlaceholder": "\u7EDD\u5BF9\u8DEF\u5F84\uFF0C\u4F8B\u5982 /Users/\u4F60/tasks",
|
|
20275
|
+
"sched.workspaceCustomHint": "\u76EE\u5F55\u4E0D\u5B58\u5728\u65F6\u4F1A\u81EA\u52A8\u521B\u5EFA\uFF0C\u5E76\u6CE8\u518C\u6210\u4E00\u4E2A\u5DE5\u4F5C\u533A\u3002",
|
|
20276
|
+
"sched.workspaceCustomEmpty": "\u8BF7\u5148\u586B\u5199\u81EA\u5B9A\u4E49\u76EE\u5F55\u7684\u7EDD\u5BF9\u8DEF\u5F84\u3002",
|
|
20241
20277
|
"sched.cronLabel": "cron \u5B9A\u65F6\u5668",
|
|
20242
20278
|
"sched.cronHint": "\u4E94\u6BB5 croner \u8868\u8FBE\u5F0F\uFF08\u5206 \u65F6 \u65E5 \u6708 \u5468\uFF09\uFF0C\u4F8B\u5982 \u201C0 9 * * *\u201D \u8868\u793A\u6BCF\u5929 09:00\u3002",
|
|
20243
20279
|
"sched.cronHourly": "\u6BCF\u5C0F\u65F6",
|
|
@@ -20443,6 +20479,14 @@ var en = {
|
|
|
20443
20479
|
"teams.stopConfirm": 'Stop team "{name}"? Unfinished tasks are cancelled; delivered results are kept.',
|
|
20444
20480
|
"teams.stopping": "Stopping\u2026",
|
|
20445
20481
|
"teams.stopped": "Stopped {name} ({count} tasks cancelled)",
|
|
20482
|
+
"teams.archive": "Archive",
|
|
20483
|
+
"teams.archiveConfirm": 'Archive team "{name}"? It moves from active to archived; task records are kept.',
|
|
20484
|
+
"teams.archiving": "Archiving\u2026",
|
|
20485
|
+
"teams.archivedNote": "Archived {name}",
|
|
20486
|
+
"teams.remove": "Delete",
|
|
20487
|
+
"teams.removeConfirm": 'Delete team "{name}"? Its state and task records are permanently removed; this cannot be undone.',
|
|
20488
|
+
"teams.removing": "Deleting\u2026",
|
|
20489
|
+
"teams.removed": "Deleted {name}",
|
|
20446
20490
|
"teams.refresh": "Refresh",
|
|
20447
20491
|
"teams.tasks": "{done}/{total} tasks",
|
|
20448
20492
|
"teams.members": "{count} members",
|
|
@@ -20494,6 +20538,11 @@ var en = {
|
|
|
20494
20538
|
"sched.workspace": "Workspace",
|
|
20495
20539
|
"sched.workspaceNone": "None (default directory)",
|
|
20496
20540
|
"sched.workspaceHint": "Each run starts a new session in this workspace; sessions appear grouped under it in the sidebar.",
|
|
20541
|
+
"sched.workspacePath": "Directory: {path}",
|
|
20542
|
+
"sched.workspaceCustom": "+ Custom directory\u2026",
|
|
20543
|
+
"sched.workspaceCustomPlaceholder": "Absolute path, e.g. /Users/you/tasks",
|
|
20544
|
+
"sched.workspaceCustomHint": "The directory is created when missing, then registered as a workspace.",
|
|
20545
|
+
"sched.workspaceCustomEmpty": "Enter an absolute path for the custom directory first.",
|
|
20497
20546
|
"sched.cronLabel": "Cron schedule",
|
|
20498
20547
|
"sched.cronHint": 'Five-field cron expression (minute hour day month weekday), e.g. "0 9 * * *" runs daily at 09:00.',
|
|
20499
20548
|
"sched.cronHourly": "Hourly",
|
|
@@ -20631,6 +20680,9 @@ var CSS = `
|
|
|
20631
20680
|
.t-team-chip:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}
|
|
20632
20681
|
.t-team-chip:disabled{opacity:.5;cursor:default}
|
|
20633
20682
|
.t-team-chip[data-active="true"]{background:var(--dsw-alias-button-ghost-active-fill);border-color:var(--dsw-alias-button-ghost-active-border);color:var(--dsw-alias-label-primary);font-weight:600}
|
|
20683
|
+
/* \u7834\u574F\u6027\u52A8\u4F5C\uFF08\u5220\u9664\u56E2\u961F\uFF09\uFF1A\u5E38\u6001\u5C31\u5E26\u4E0A\u9519\u8BEF\u8272\uFF0C\u522B\u7B49 hover \u624D\u63D0\u793A\u3002 */
|
|
20684
|
+
.t-team-chip[data-tone="error"]{color:var(--dsw-alias-state-error-primary);border-color:color-mix(in srgb,var(--dsw-alias-state-error-primary) 40%,transparent)}
|
|
20685
|
+
.t-team-chip[data-tone="error"]:hover{background:color-mix(in srgb,var(--dsw-alias-state-error-primary) 12%,transparent);color:var(--dsw-alias-state-error-primary)}
|
|
20634
20686
|
.t-team-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(250px,1fr));gap:10px 12px}
|
|
20635
20687
|
.t-team-group{margin-top:6px}
|
|
20636
20688
|
.t-team-division{font-size:12px;font-weight:600;color:var(--dsw-alias-label-secondary);margin:2px 0 6px}
|
|
@@ -20808,18 +20860,23 @@ button:has(.t-team-schedule-glyph):hover{background:var(--dsw-alias-button-float
|
|
|
20808
20860
|
.t-team-sched-nextList{list-style:none;margin:0;padding:0;display:flex;flex-wrap:wrap;gap:6px}
|
|
20809
20861
|
.t-team-sched-nextList li{font-size:12px;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l2);border-radius:6px;padding:2px 8px;font-variant-numeric:tabular-nums}
|
|
20810
20862
|
/* \u63D0\u793A\u8BCD\u8F93\u5165\u533A\uFF1A\u6846\u5185\u7B2C\u4E00\u884C\u662F\u4E13\u5BB6\u82AF\u7247\uFF08\u6807\u7B7E\u89C2\u611F\uFF0C\u4E0E\u5BF9\u8BDD\u8F93\u5165\u6846\u4E00\u81F4\uFF09\uFF0C\u4E0B\u9762\u662F\u6B63\u6587 */
|
|
20811
|
-
.t-team-sched-promptbox{box-sizing:border-box;display:flex;flex-direction:column;
|
|
20863
|
+
.t-team-sched-promptbox{box-sizing:border-box;display:flex;flex-direction:column;padding:8px 10px;border-radius:8px;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);transition:border-color .16s}
|
|
20812
20864
|
.t-team-sched-promptbox:focus-within{border-color:var(--dsw-alias-brand-primary, var(--dsw-alias-label-primary))}
|
|
20813
|
-
|
|
20814
|
-
|
|
20865
|
+
/* \u82AF\u7247\u89C2\u611F\u5BF9\u9F50\u5BF9\u8BDD\u8F93\u5165\u6846\u91CC\u7684\u5F15\u7528\u82AF\u7247\uFF1A\u6D45\u7070\u5E95\u3001\u5706\u89D2\u77E9\u5F62\uFF08\u4E0D\u662F\u5168\u80F6\u56CA\uFF09\u3001\u84DD\u8272\u6587\u5B57\u3001
|
|
20866
|
+
* \u5DE6\u4FA7\u4E00\u4E2A\u5706\u5F62\u7EBF\u6761\u5C0F\u56FE\u6807\uFF1B\xD7 \u5E73\u65F6\u4E0D\u663E\u793A\uFF0C\u60AC\u505C\u624D\u6D6E\u51FA\u6765\uFF08\u622A\u56FE\u91CC\u5C31\u662F\u6CA1\u6709 \xD7 \u7684\u6837\u5B50\uFF09\u3002 */
|
|
20867
|
+
.t-team-sched-chip{box-sizing:border-box;display:inline-flex;align-items:center;gap:3px;max-width:100%;margin:0 2px;padding:0 4px;border:1px solid transparent;border-radius:6px;background:color-mix(in srgb, var(--dsw-alias-label-primary) 10%, transparent);color:var(--dsw-alias-brand-primary, #1677ff);font-size:12px;line-height:18px;vertical-align:middle;user-select:none}
|
|
20868
|
+
/* \u60AC\u505C\u7ED9\u4E00\u5708\u6DE1\u63CF\u8FB9\uFF1A\u8BA9"\u9F20\u6807\u5728\u8FD9\u679A\u82AF\u7247\u4E0A"\u8FD9\u4EF6\u4E8B\u6709\u786E\u5B9A\u7684\u89C6\u89C9\u53CD\u9988\uFF08\u522B\u9760\u6D4F\u89C8\u5668\u9ED8\u8BA4\uFF09\u3002 */
|
|
20869
|
+
.t-team-sched-chip:hover{border-color:color-mix(in srgb, var(--dsw-alias-brand-primary, #1677ff) 35%, transparent)}
|
|
20870
|
+
.t-team-sched-chip-icon{flex:none;display:block}
|
|
20815
20871
|
.t-team-sched-chip-name{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
20816
|
-
.t-team-sched-chip-remove{padding:0
|
|
20817
|
-
.t-team-sched-chip-remove:hover
|
|
20818
|
-
|
|
20819
|
-
|
|
20820
|
-
* \
|
|
20821
|
-
.t-team-sched-field .t-team-sched-prompt-input{box-sizing:border-box;width:100%;min-height:72px;padding:0;border:0;border-radius:0;background:transparent;color:var(--dsw-alias-label-primary);font:inherit;font-size:13px;resize:
|
|
20872
|
+
.t-team-sched-chip-remove{padding:0 1px;border:0;background:transparent;color:inherit;font:inherit;font-size:12px;line-height:1;cursor:pointer;opacity:.6;transition:opacity .12s}
|
|
20873
|
+
.t-team-sched-chip-remove:hover{opacity:1}
|
|
20874
|
+
/* \u63D0\u793A\u8BCD\u7F16\u8F91\u533A\uFF1Acontenteditable \u7684\u5BCC\u6587\u672C\u6D41\uFF08\u7EAF\u6587\u5B57 + \u82AF\u7247\uFF09\uFF0C\u82AF\u7247\u56E0\u6B64\u80FD\u63D2\u5728\u6B63\u6587\u4EFB\u610F\u4F4D\u7F6E\u3002
|
|
20875
|
+
* \u26A0\uFE0F \u7C7B\u540D\u5FC5\u987B\u5E26 .t-team-sched-field \u524D\u7F00\uFF1A\u5426\u5219\u7279\u5F02\u6027\u4F4E\u4E8E\u901A\u7528\u7684 ".t-team-sched-field textarea"
|
|
20876
|
+
* \u90A3\u7C7B\u89C4\u5219\uFF0C\u7F16\u8F91\u533A\u4F1A\u81EA\u5E26\u4E00\u5708\u8FB9\u6846\uFF08\u8E29\u8FC7\uFF1A\u6846\u91CC\u5957\u6846\uFF09\u3002 */
|
|
20877
|
+
.t-team-sched-field .t-team-sched-prompt-input{box-sizing:border-box;width:100%;min-height:72px;max-height:320px;overflow-y:auto;padding:0;border:0;border-radius:0;background:transparent;color:var(--dsw-alias-label-primary);font:inherit;font-size:13px;line-height:22px;white-space:pre-wrap;word-break:break-word;cursor:text;resize:none}
|
|
20822
20878
|
.t-team-sched-field .t-team-sched-prompt-input:focus{outline:none;border:0}
|
|
20879
|
+
.t-team-sched-field .t-team-sched-prompt-input[data-empty="true"]::before{content:attr(data-placeholder);color:var(--dsw-alias-label-tertiary);pointer-events:none}
|
|
20823
20880
|
/* \u63D0\u793A\u8BCD\u6846\u4E0B\u65B9\u7684\u300CT\u4E13\u5BB6\u300D\u6311\u9009\u5668\uFF1A\u6309\u94AE + \u53EA\u542B\u4E13\u5BB6\u5217\u8868\u7684\u6D6E\u5C42\uFF08\u7C7B\u540D\u72EC\u7ACB\uFF0C\u907F\u514D\u4E0E\u65E2\u6709\u7C7B\u4E92\u76F8\u8986\u76D6\uFF09 */
|
|
20824
20881
|
.t-team-expert-pick{position:relative;display:flex;align-items:center;gap:8px;margin-top:2px}
|
|
20825
20882
|
.t-team-expert-pick-hint{font-size:12px;color:var(--dsw-alias-label-secondary)}
|
|
@@ -20878,6 +20935,9 @@ var TYPERT_REMOTE = {
|
|
|
20878
20935
|
direct("runScheduleItem", [
|
|
20879
20936
|
{ name: "id", wire: "id", source: "json", codec: { mode: "strict", typeSymbol: "string", schema: external_exports.string().min(1).max(128) } }
|
|
20880
20937
|
], "TTeamSchedule", scheduleSnapshotSchema),
|
|
20938
|
+
direct("ensureScheduleWorkspace", [
|
|
20939
|
+
{ name: "path", wire: "path", source: "json", codec: { mode: "strict", typeSymbol: "string", schema: external_exports.string().max(1024) } }
|
|
20940
|
+
], "TTeamScheduleWorkspace", scheduleWorkspaceSchema),
|
|
20881
20941
|
direct("previewSchedule", [
|
|
20882
20942
|
{ name: "cron", wire: "cron", source: "json", codec: { mode: "strict", typeSymbol: "string", schema: external_exports.string().min(1).max(120) } }
|
|
20883
20943
|
], "TTeamSchedulePreview", schedulePreviewSchema),
|
|
@@ -20893,9 +20953,16 @@ var TYPERT_REMOTE = {
|
|
|
20893
20953
|
direct("getTeams", [
|
|
20894
20954
|
{ name: "archived", wire: "archived", source: "json", codec: { mode: "strict", typeSymbol: "boolean", schema: external_exports.boolean() } }
|
|
20895
20955
|
], "TTeamTeams", teamsSnapshotSchema),
|
|
20956
|
+
// workspacePath 标 acceptsUndefined:host 若是旧版(快照里没这个字段),这里就是 undefined,
|
|
20957
|
+
// 请求里不带该键,宿主退回全量遍历;不带标记会在 gateway 侧被判 arguments-invalid。
|
|
20896
20958
|
direct("stopTeam", [
|
|
20897
|
-
{ name: "teamId", wire: "teamId", source: "json", codec: { mode: "strict", typeSymbol: "string", schema: external_exports.string().min(1).max(128) } }
|
|
20959
|
+
{ name: "teamId", wire: "teamId", source: "json", codec: { mode: "strict", typeSymbol: "string", schema: external_exports.string().min(1).max(128) } },
|
|
20960
|
+
{ name: "workspacePath", wire: "workspacePath", source: "json", acceptsUndefined: true, codec: { mode: "strict", typeSymbol: "string", schema: external_exports.string().max(1024) } }
|
|
20898
20961
|
], "TTeamStopResult", stopResultSchema),
|
|
20962
|
+
direct("deleteTeam", [
|
|
20963
|
+
{ name: "teamId", wire: "teamId", source: "json", codec: { mode: "strict", typeSymbol: "string", schema: external_exports.string().min(1).max(128) } },
|
|
20964
|
+
{ name: "workspacePath", wire: "workspacePath", source: "json", acceptsUndefined: true, codec: { mode: "strict", typeSymbol: "string", schema: external_exports.string().max(1024) } }
|
|
20965
|
+
], "TTeamDeleteResult", deleteTeamResultSchema),
|
|
20899
20966
|
direct("createExpert", [
|
|
20900
20967
|
{ name: "expert", wire: "expert", source: "json", codec: { mode: "strict", typeSymbol: "TTeamCustomExpertInput", schema: customExpertInputSchema } }
|
|
20901
20968
|
], "TTeamCatalog", catalogSnapshotSchema),
|
|
@@ -20941,11 +21008,7 @@ function onCatalogLoaded(listener) {
|
|
|
20941
21008
|
catalogListeners.add(listener);
|
|
20942
21009
|
return () => catalogListeners.delete(listener);
|
|
20943
21010
|
}
|
|
20944
|
-
|
|
20945
|
-
const cached2 = catalogCache.get(remote);
|
|
20946
|
-
if (cached2 !== void 0 && !force) return cached2;
|
|
20947
|
-
const next = unwrap(await remote.getCatalog(), "getCatalog");
|
|
20948
|
-
next.enabledSet = new Set(next.enabled);
|
|
21011
|
+
function publishCatalog(remote, next) {
|
|
20949
21012
|
catalogCache.set(remote, next);
|
|
20950
21013
|
for (const listener of catalogListeners) {
|
|
20951
21014
|
try {
|
|
@@ -20956,6 +21019,13 @@ async function refresh(remote, force = false) {
|
|
|
20956
21019
|
}
|
|
20957
21020
|
return next;
|
|
20958
21021
|
}
|
|
21022
|
+
async function refresh(remote, force = false) {
|
|
21023
|
+
const cached2 = catalogCache.get(remote);
|
|
21024
|
+
if (cached2 !== void 0 && !force) return cached2;
|
|
21025
|
+
const next = unwrap(await remote.getCatalog(), "getCatalog");
|
|
21026
|
+
next.enabledSet = new Set(next.enabled);
|
|
21027
|
+
return publishCatalog(remote, next);
|
|
21028
|
+
}
|
|
20959
21029
|
function displayName(expert, active) {
|
|
20960
21030
|
return active === "en" ? expert.nameEn || expert.name : expert.name || expert.nameEn;
|
|
20961
21031
|
}
|
|
@@ -20965,25 +21035,50 @@ function displayDescription(expert, active) {
|
|
|
20965
21035
|
function divisionLabel(expert, active) {
|
|
20966
21036
|
return active === "en" ? expert.divisionEn || expert.division : expert.divisionZh || expert.division;
|
|
20967
21037
|
}
|
|
20968
|
-
function
|
|
20969
|
-
|
|
20970
|
-
|
|
20971
|
-
for (
|
|
20972
|
-
|
|
20973
|
-
for (const
|
|
20974
|
-
|
|
20975
|
-
|
|
20976
|
-
|
|
20977
|
-
if (matched === void 0 || name.length > matched.name.length) {
|
|
20978
|
-
matched = { name, display: displayName(expert, active) };
|
|
20979
|
-
}
|
|
21038
|
+
function matchExpertAtHead(text, experts, active) {
|
|
21039
|
+
if (!text.startsWith("@")) return void 0;
|
|
21040
|
+
let matched;
|
|
21041
|
+
for (const expert of experts ?? []) {
|
|
21042
|
+
const names = [displayName(expert, active), expert?.name, expert?.nameEn, expert?.slug].filter((name) => typeof name === "string" && name !== "");
|
|
21043
|
+
for (const name of names) {
|
|
21044
|
+
if (!text.startsWith(`@${name}`)) continue;
|
|
21045
|
+
if (matched === void 0 || name.length > matched.name.length) {
|
|
21046
|
+
matched = { name, display: displayName(expert, active) };
|
|
20980
21047
|
}
|
|
20981
21048
|
}
|
|
20982
|
-
if (matched === void 0) break;
|
|
20983
|
-
rest = rest.slice(matched.name.length + 2);
|
|
20984
|
-
if (!mentions.includes(matched.display)) mentions.push(matched.display);
|
|
20985
21049
|
}
|
|
20986
|
-
return
|
|
21050
|
+
return matched;
|
|
21051
|
+
}
|
|
21052
|
+
function tokenizePrompt(text, experts, active) {
|
|
21053
|
+
const raw = String(text ?? "");
|
|
21054
|
+
const tokens = [];
|
|
21055
|
+
let buffer = "";
|
|
21056
|
+
let rest = raw;
|
|
21057
|
+
const flush = () => {
|
|
21058
|
+
if (buffer === "") return;
|
|
21059
|
+
tokens.push({ type: "text", text: buffer });
|
|
21060
|
+
buffer = "";
|
|
21061
|
+
};
|
|
21062
|
+
while (rest !== "") {
|
|
21063
|
+
const hit = rest.startsWith("@") ? matchExpertAtHead(rest, experts, active) : void 0;
|
|
21064
|
+
if (hit === void 0) {
|
|
21065
|
+
buffer += rest[0];
|
|
21066
|
+
rest = rest.slice(1);
|
|
21067
|
+
continue;
|
|
21068
|
+
}
|
|
21069
|
+
flush();
|
|
21070
|
+
tokens.push({ type: "expert", name: hit.display });
|
|
21071
|
+
rest = rest.slice(hit.name.length + 1);
|
|
21072
|
+
}
|
|
21073
|
+
flush();
|
|
21074
|
+
return tokens;
|
|
21075
|
+
}
|
|
21076
|
+
function collectExpertMentions(text, experts, active) {
|
|
21077
|
+
const names = [];
|
|
21078
|
+
for (const token of tokenizePrompt(text, experts, active)) {
|
|
21079
|
+
if (token.type === "expert" && !names.includes(token.name)) names.push(token.name);
|
|
21080
|
+
}
|
|
21081
|
+
return names;
|
|
20987
21082
|
}
|
|
20988
21083
|
function matchExpert(expert, active, query) {
|
|
20989
21084
|
if (query === "") return true;
|
|
@@ -21021,6 +21116,7 @@ var SectionBoundary = class extends import_react.default.Component {
|
|
|
21021
21116
|
return this.props.children;
|
|
21022
21117
|
}
|
|
21023
21118
|
};
|
|
21119
|
+
var CUSTOM_WORKSPACE = "__custom__";
|
|
21024
21120
|
var SCHEDULE_PANEL_KEY = `${NS}-schedule`;
|
|
21025
21121
|
var SCHEDULE_PRESET_LABELS = {
|
|
21026
21122
|
hourly: "sched.presetHourly",
|
|
@@ -21187,13 +21283,220 @@ function CronPicker({ t, remote, value, onChange, disabled }) {
|
|
|
21187
21283
|
), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-sched-sum" }, hint === "" ? summary : hint), fires.length > 0 && /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-sched-next" }, /* @__PURE__ */ import_react.default.createElement("span", { className: "t-team-sched-nextLabel" }, t("sched.nextRuns", { n: fires.length })), /* @__PURE__ */ import_react.default.createElement("ul", { className: "t-team-sched-nextList" }, fires.map((iso, index) => /* @__PURE__ */ import_react.default.createElement("li", { key: index }, new Date(iso).toLocaleString(void 0, { weekday: "short", month: "numeric", day: "numeric", hour: "2-digit", minute: "2-digit" }))))));
|
|
21188
21284
|
}
|
|
21189
21285
|
function emptyScheduleForm() {
|
|
21190
|
-
return { editingId: null, title: "", prompt: "", cron: "", enabled: true, workspaceId: "" };
|
|
21286
|
+
return { editingId: null, title: "", prompt: "", cron: "", enabled: true, workspaceId: "", customDir: "" };
|
|
21191
21287
|
}
|
|
21192
21288
|
function scheduleLastRun(t, item) {
|
|
21193
21289
|
if (!item.lastRunAt) return t("sched.neverRun");
|
|
21194
21290
|
const time3 = new Date(item.lastRunAt).toLocaleString();
|
|
21195
21291
|
return item.lastRunError === void 0 ? time3 : `${time3}\uFF08${t("sched.failed")}: ${item.lastRunError}\uFF09`;
|
|
21196
21292
|
}
|
|
21293
|
+
function PromptEditor({ editorRef, t, active, experts, value, disabled, onChange }) {
|
|
21294
|
+
const boxRef = import_react.default.useRef(null);
|
|
21295
|
+
const lastWritten = import_react.default.useRef(null);
|
|
21296
|
+
const savedRange = import_react.default.useRef(null);
|
|
21297
|
+
const buildChipIcon = () => {
|
|
21298
|
+
const NS2 = "http://www.w3.org/2000/svg";
|
|
21299
|
+
const svg = document.createElementNS(NS2, "svg");
|
|
21300
|
+
svg.setAttribute("class", "t-team-sched-chip-icon");
|
|
21301
|
+
svg.setAttribute("viewBox", "0 0 16 16");
|
|
21302
|
+
svg.setAttribute("width", "13");
|
|
21303
|
+
svg.setAttribute("height", "13");
|
|
21304
|
+
svg.setAttribute("fill", "none");
|
|
21305
|
+
svg.setAttribute("stroke", "currentColor");
|
|
21306
|
+
svg.setAttribute("stroke-width", "1.4");
|
|
21307
|
+
svg.setAttribute("stroke-linecap", "round");
|
|
21308
|
+
svg.setAttribute("aria-hidden", "true");
|
|
21309
|
+
const circle = document.createElementNS(NS2, "circle");
|
|
21310
|
+
circle.setAttribute("cx", "8");
|
|
21311
|
+
circle.setAttribute("cy", "8");
|
|
21312
|
+
circle.setAttribute("r", "6");
|
|
21313
|
+
const line1 = document.createElementNS(NS2, "line");
|
|
21314
|
+
line1.setAttribute("x1", "5.4");
|
|
21315
|
+
line1.setAttribute("y1", "6.6");
|
|
21316
|
+
line1.setAttribute("x2", "10.6");
|
|
21317
|
+
line1.setAttribute("y2", "6.6");
|
|
21318
|
+
const line2 = document.createElementNS(NS2, "line");
|
|
21319
|
+
line2.setAttribute("x1", "5.4");
|
|
21320
|
+
line2.setAttribute("y1", "9.4");
|
|
21321
|
+
line2.setAttribute("x2", "9");
|
|
21322
|
+
line2.setAttribute("y2", "9.4");
|
|
21323
|
+
svg.append(circle, line1, line2);
|
|
21324
|
+
return svg;
|
|
21325
|
+
};
|
|
21326
|
+
const buildChip = (name) => {
|
|
21327
|
+
const chip = document.createElement("span");
|
|
21328
|
+
chip.className = "t-team-sched-chip";
|
|
21329
|
+
chip.contentEditable = "false";
|
|
21330
|
+
chip.dataset.expert = name;
|
|
21331
|
+
const label = document.createElement("span");
|
|
21332
|
+
label.className = "t-team-sched-chip-name";
|
|
21333
|
+
label.textContent = name;
|
|
21334
|
+
const remove = document.createElement("button");
|
|
21335
|
+
remove.type = "button";
|
|
21336
|
+
remove.className = "t-team-sched-chip-remove";
|
|
21337
|
+
remove.dataset.remove = name;
|
|
21338
|
+
remove.textContent = "\xD7";
|
|
21339
|
+
remove.title = t("sched.expertRemove", { name });
|
|
21340
|
+
chip.append(buildChipIcon(), label, remove);
|
|
21341
|
+
return chip;
|
|
21342
|
+
};
|
|
21343
|
+
const serialize = () => {
|
|
21344
|
+
const box = boxRef.current;
|
|
21345
|
+
if (box === null) return "";
|
|
21346
|
+
let out = "";
|
|
21347
|
+
for (const node2 of box.childNodes) {
|
|
21348
|
+
if (node2.nodeType === 3) {
|
|
21349
|
+
out += node2.textContent ?? "";
|
|
21350
|
+
continue;
|
|
21351
|
+
}
|
|
21352
|
+
if (node2.nodeType !== 1) continue;
|
|
21353
|
+
const el = (
|
|
21354
|
+
/** @type {HTMLElement} */
|
|
21355
|
+
node2
|
|
21356
|
+
);
|
|
21357
|
+
if (el.dataset?.expert !== void 0) {
|
|
21358
|
+
out += `@${el.dataset.expert}`;
|
|
21359
|
+
continue;
|
|
21360
|
+
}
|
|
21361
|
+
if (el.tagName === "BR") {
|
|
21362
|
+
out += "\n";
|
|
21363
|
+
continue;
|
|
21364
|
+
}
|
|
21365
|
+
out += el.textContent ?? "";
|
|
21366
|
+
}
|
|
21367
|
+
return out;
|
|
21368
|
+
};
|
|
21369
|
+
const refreshEmpty = () => {
|
|
21370
|
+
const box = boxRef.current;
|
|
21371
|
+
if (box !== null) box.dataset.empty = box.textContent === "" ? "true" : "false";
|
|
21372
|
+
};
|
|
21373
|
+
const pushOut = () => {
|
|
21374
|
+
const text = serialize();
|
|
21375
|
+
lastWritten.current = text;
|
|
21376
|
+
refreshEmpty();
|
|
21377
|
+
onChange(text);
|
|
21378
|
+
};
|
|
21379
|
+
const rebuild = () => {
|
|
21380
|
+
const box = boxRef.current;
|
|
21381
|
+
if (box === null) return;
|
|
21382
|
+
box.textContent = "";
|
|
21383
|
+
for (const token of tokenizePrompt(value, experts, active)) {
|
|
21384
|
+
box.append(token.type === "text" ? document.createTextNode(token.text ?? "") : buildChip(token.name ?? ""));
|
|
21385
|
+
}
|
|
21386
|
+
refreshEmpty();
|
|
21387
|
+
};
|
|
21388
|
+
const removeExpert = (name) => {
|
|
21389
|
+
const box = boxRef.current;
|
|
21390
|
+
if (box === null) return;
|
|
21391
|
+
for (const el of box.querySelectorAll("[data-expert]")) {
|
|
21392
|
+
if (
|
|
21393
|
+
/** @type {HTMLElement} */
|
|
21394
|
+
el.dataset.expert === name
|
|
21395
|
+
) {
|
|
21396
|
+
el.remove();
|
|
21397
|
+
break;
|
|
21398
|
+
}
|
|
21399
|
+
}
|
|
21400
|
+
pushOut();
|
|
21401
|
+
};
|
|
21402
|
+
const insertExpert = (name) => {
|
|
21403
|
+
const box = boxRef.current;
|
|
21404
|
+
if (box === null || disabled) return;
|
|
21405
|
+
const chip = buildChip(name);
|
|
21406
|
+
const space = document.createTextNode(" ");
|
|
21407
|
+
box.focus();
|
|
21408
|
+
const selection = window.getSelection();
|
|
21409
|
+
if (selection !== null && savedRange.current !== null && box.contains(savedRange.current.commonAncestorContainer)) {
|
|
21410
|
+
selection.removeAllRanges();
|
|
21411
|
+
selection.addRange(savedRange.current);
|
|
21412
|
+
}
|
|
21413
|
+
const inside = selection !== null && selection.rangeCount > 0 && box.contains(selection.anchorNode);
|
|
21414
|
+
if (inside) {
|
|
21415
|
+
const range = selection.getRangeAt(0);
|
|
21416
|
+
range.deleteContents();
|
|
21417
|
+
range.insertNode(chip);
|
|
21418
|
+
chip.after(space);
|
|
21419
|
+
range.setStartAfter(space);
|
|
21420
|
+
range.collapse(true);
|
|
21421
|
+
selection.removeAllRanges();
|
|
21422
|
+
selection.addRange(range);
|
|
21423
|
+
savedRange.current = range.cloneRange();
|
|
21424
|
+
} else {
|
|
21425
|
+
box.append(chip, space);
|
|
21426
|
+
}
|
|
21427
|
+
pushOut();
|
|
21428
|
+
};
|
|
21429
|
+
import_react.default.useEffect(() => {
|
|
21430
|
+
if (editorRef === void 0) return void 0;
|
|
21431
|
+
editorRef.current = { insertExpert, removeExpert, focus: () => boxRef.current?.focus() };
|
|
21432
|
+
return () => {
|
|
21433
|
+
editorRef.current = null;
|
|
21434
|
+
};
|
|
21435
|
+
});
|
|
21436
|
+
import_react.default.useEffect(() => {
|
|
21437
|
+
if (lastWritten.current === value) return;
|
|
21438
|
+
rebuild();
|
|
21439
|
+
}, [value, experts, active]);
|
|
21440
|
+
import_react.default.useEffect(() => {
|
|
21441
|
+
const onSelectionChange = () => {
|
|
21442
|
+
const box = boxRef.current;
|
|
21443
|
+
if (box === null) return;
|
|
21444
|
+
const selection = window.getSelection();
|
|
21445
|
+
if (selection === null || selection.rangeCount === 0) return;
|
|
21446
|
+
const range = selection.getRangeAt(0);
|
|
21447
|
+
if (box.contains(range.commonAncestorContainer)) savedRange.current = range.cloneRange();
|
|
21448
|
+
};
|
|
21449
|
+
document.addEventListener("selectionchange", onSelectionChange);
|
|
21450
|
+
return () => document.removeEventListener("selectionchange", onSelectionChange);
|
|
21451
|
+
}, []);
|
|
21452
|
+
const onPaste = (event) => {
|
|
21453
|
+
const text = event.clipboardData?.getData("text/plain") ?? "";
|
|
21454
|
+
if (text === "") return;
|
|
21455
|
+
event.preventDefault();
|
|
21456
|
+
const selection = window.getSelection();
|
|
21457
|
+
if (selection === null || selection.rangeCount === 0) return;
|
|
21458
|
+
const range = selection.getRangeAt(0);
|
|
21459
|
+
range.deleteContents();
|
|
21460
|
+
const node2 = document.createTextNode(text);
|
|
21461
|
+
range.insertNode(node2);
|
|
21462
|
+
range.setStartAfter(node2);
|
|
21463
|
+
range.collapse(true);
|
|
21464
|
+
selection.removeAllRanges();
|
|
21465
|
+
selection.addRange(range);
|
|
21466
|
+
pushOut();
|
|
21467
|
+
};
|
|
21468
|
+
return /* @__PURE__ */ import_react.default.createElement(
|
|
21469
|
+
"div",
|
|
21470
|
+
{
|
|
21471
|
+
ref: boxRef,
|
|
21472
|
+
className: "t-team-sched-prompt-input",
|
|
21473
|
+
contentEditable: !disabled,
|
|
21474
|
+
suppressContentEditableWarning: true,
|
|
21475
|
+
role: "textbox",
|
|
21476
|
+
"aria-multiline": "true",
|
|
21477
|
+
"aria-label": t("sched.promptLabel"),
|
|
21478
|
+
"data-placeholder": t("sched.promptPlaceholder"),
|
|
21479
|
+
"data-empty": "true",
|
|
21480
|
+
onInput: () => {
|
|
21481
|
+
if (!disabled) pushOut();
|
|
21482
|
+
},
|
|
21483
|
+
onPaste,
|
|
21484
|
+
onBlur: () => {
|
|
21485
|
+
if (!disabled) pushOut();
|
|
21486
|
+
},
|
|
21487
|
+
onMouseDownCapture: (event) => {
|
|
21488
|
+
const target = (
|
|
21489
|
+
/** @type {HTMLElement} */
|
|
21490
|
+
event.target
|
|
21491
|
+
);
|
|
21492
|
+
const name = target?.dataset?.remove;
|
|
21493
|
+
if (name === void 0 || disabled) return;
|
|
21494
|
+
event.preventDefault();
|
|
21495
|
+
removeExpert(name);
|
|
21496
|
+
}
|
|
21497
|
+
}
|
|
21498
|
+
);
|
|
21499
|
+
}
|
|
21197
21500
|
function ExpertPicker({ t, active, experts, disabled, selected, onPick }) {
|
|
21198
21501
|
const [open2, setOpen] = import_react.default.useState(false);
|
|
21199
21502
|
const [query, setQuery] = import_react.default.useState("");
|
|
@@ -21277,6 +21580,7 @@ function ExpertPicker({ t, active, experts, disabled, selected, onPick }) {
|
|
|
21277
21580
|
"data-picked": picked.includes(displayName(expert, active)),
|
|
21278
21581
|
className: "t-team-expert-pick-item",
|
|
21279
21582
|
onMouseEnter: () => setIndex(position),
|
|
21583
|
+
onMouseDown: (event) => event.preventDefault(),
|
|
21280
21584
|
onClick: () => pick2(expert)
|
|
21281
21585
|
},
|
|
21282
21586
|
/* @__PURE__ */ import_react.default.createElement("span", { className: "t-team-expert-pick-name" }, picked.includes(displayName(expert, active)) ? "\u2713 " : "", expert.emoji, " ", displayName(expert, active)),
|
|
@@ -21293,6 +21597,8 @@ function SchedulePanel({ t, ctx: hostCtx, remote, getActive }) {
|
|
|
21293
21597
|
const [historyId, setHistoryId] = import_react.default.useState(null);
|
|
21294
21598
|
const [runningId, setRunningId] = import_react.default.useState(null);
|
|
21295
21599
|
const [experts, setExperts] = import_react.default.useState([]);
|
|
21600
|
+
const promptEditorRef = import_react.default.useRef(null);
|
|
21601
|
+
const [extraWorkspaces, setExtraWorkspaces] = import_react.default.useState([]);
|
|
21296
21602
|
const layout = () => hostCtx?.get?.("layout") ?? hostCtx?.layout;
|
|
21297
21603
|
const backToConversation = () => layout()?.selectPanel?.(null);
|
|
21298
21604
|
const load = import_react.default.useCallback(async () => {
|
|
@@ -21311,17 +21617,23 @@ function SchedulePanel({ t, ctx: hostCtx, remote, getActive }) {
|
|
|
21311
21617
|
}, [load]);
|
|
21312
21618
|
import_react.default.useEffect(() => {
|
|
21313
21619
|
let alive = true;
|
|
21620
|
+
const sync = () => {
|
|
21621
|
+
const current = snapshotOf(remote);
|
|
21622
|
+
if (current === void 0 || !alive) return;
|
|
21623
|
+
setExperts(current.experts.filter((expert) => expert.conflict !== true && current.enabledSet.has(expert.slug)));
|
|
21624
|
+
};
|
|
21625
|
+
const stop = onCatalogLoaded(sync);
|
|
21314
21626
|
void (async () => {
|
|
21315
21627
|
try {
|
|
21316
|
-
|
|
21317
|
-
|
|
21318
|
-
setExperts(catalogSnapshot.experts.filter((expert) => expert.conflict !== true && catalogSnapshot.enabledSet.has(expert.slug)));
|
|
21628
|
+
await refresh(remote);
|
|
21629
|
+
sync();
|
|
21319
21630
|
} catch (cause) {
|
|
21320
21631
|
console.warn("[t-team] \u5B9A\u65F6\u4EFB\u52A1\uFF1A\u8BFB\u53D6\u4E13\u5BB6\u540D\u518C\u5931\u8D25\uFF0C\u300CT\u4E13\u5BB6\u300D\u6311\u9009\u5668\u6682\u4E0D\u53EF\u7528\uFF1A", cause);
|
|
21321
21632
|
}
|
|
21322
21633
|
})();
|
|
21323
21634
|
return () => {
|
|
21324
21635
|
alive = false;
|
|
21636
|
+
stop();
|
|
21325
21637
|
};
|
|
21326
21638
|
}, [remote]);
|
|
21327
21639
|
const active = getActive();
|
|
@@ -21334,13 +21646,28 @@ function SchedulePanel({ t, ctx: hostCtx, remote, getActive }) {
|
|
|
21334
21646
|
setError("");
|
|
21335
21647
|
};
|
|
21336
21648
|
function fillExpert(expert) {
|
|
21649
|
+
const editor = promptEditorRef.current;
|
|
21650
|
+
if (editor === null) return;
|
|
21337
21651
|
const name = displayName(expert, active);
|
|
21338
|
-
|
|
21339
|
-
|
|
21340
|
-
|
|
21341
|
-
|
|
21342
|
-
|
|
21343
|
-
|
|
21652
|
+
if (mentioned.includes(name)) editor.removeExpert(name);
|
|
21653
|
+
else editor.insertExpert(name);
|
|
21654
|
+
}
|
|
21655
|
+
function rememberWorkspace(workspace) {
|
|
21656
|
+
if (workspace === void 0 || workspace === null) return "";
|
|
21657
|
+
setExtraWorkspaces((current) => current.some((item) => item.id === workspace.id) ? current : [...current, workspace]);
|
|
21658
|
+
return workspace.id;
|
|
21659
|
+
}
|
|
21660
|
+
async function openNewForm() {
|
|
21661
|
+
setBusy(true);
|
|
21662
|
+
let workspaceId = "";
|
|
21663
|
+
try {
|
|
21664
|
+
workspaceId = rememberWorkspace(unwrap(await remote.ensureScheduleWorkspace(""), "ensureScheduleWorkspace")?.workspace);
|
|
21665
|
+
} catch (cause) {
|
|
21666
|
+
setError(errorText(cause));
|
|
21667
|
+
} finally {
|
|
21668
|
+
setBusy(false);
|
|
21669
|
+
}
|
|
21670
|
+
setForm({ ...emptyScheduleForm(), workspaceId });
|
|
21344
21671
|
}
|
|
21345
21672
|
async function submitForm() {
|
|
21346
21673
|
if (form === null || busy) return;
|
|
@@ -21350,13 +21677,22 @@ function SchedulePanel({ t, ctx: hostCtx, remote, getActive }) {
|
|
|
21350
21677
|
}
|
|
21351
21678
|
setBusy(true);
|
|
21352
21679
|
try {
|
|
21680
|
+
let workspaceId = form.workspaceId;
|
|
21681
|
+
if (workspaceId === CUSTOM_WORKSPACE) {
|
|
21682
|
+
const dir = form.customDir.trim();
|
|
21683
|
+
if (dir === "") {
|
|
21684
|
+
window.alert(t("sched.workspaceCustomEmpty"));
|
|
21685
|
+
return;
|
|
21686
|
+
}
|
|
21687
|
+
workspaceId = rememberWorkspace(unwrap(await remote.ensureScheduleWorkspace(dir), "ensureScheduleWorkspace")?.workspace);
|
|
21688
|
+
}
|
|
21353
21689
|
const payload = {
|
|
21354
21690
|
title: form.title.trim(),
|
|
21355
21691
|
prompt: form.prompt,
|
|
21356
21692
|
cron: form.cron.trim(),
|
|
21357
21693
|
enabled: form.enabled,
|
|
21358
21694
|
// 空串 = 不绑定工作区(显式解绑也走这个值,宿主认得)。
|
|
21359
|
-
workspaceId:
|
|
21695
|
+
workspaceId: workspaceId === void 0 || workspaceId === null ? "" : workspaceId
|
|
21360
21696
|
};
|
|
21361
21697
|
const next = form.editingId === null ? unwrap(await remote.createScheduleItem(payload), "createScheduleItem") : unwrap(await remote.updateScheduleItem(form.editingId, payload), "updateScheduleItem");
|
|
21362
21698
|
applySnapshot(next);
|
|
@@ -21390,7 +21726,11 @@ function SchedulePanel({ t, ctx: hostCtx, remote, getActive }) {
|
|
|
21390
21726
|
}
|
|
21391
21727
|
const items = snapshot?.items ?? [];
|
|
21392
21728
|
const workspaces = snapshot?.workspaces ?? [];
|
|
21393
|
-
const
|
|
21729
|
+
const allWorkspaces = [...workspaces];
|
|
21730
|
+
for (const workspace of extraWorkspaces) {
|
|
21731
|
+
if (!allWorkspaces.some((item) => item.id === workspace.id)) allWorkspaces.push(workspace);
|
|
21732
|
+
}
|
|
21733
|
+
const workspaceTitle = (id) => allWorkspaces.find((workspace) => workspace.id === id)?.title ?? id;
|
|
21394
21734
|
const rowMeta = (item) => {
|
|
21395
21735
|
const parts = [];
|
|
21396
21736
|
if (item.workspaceId !== void 0) parts.push(`${t("sched.workspace")}: ${workspaceTitle(item.workspaceId)}`);
|
|
@@ -21399,23 +21739,8 @@ function SchedulePanel({ t, ctx: hostCtx, remote, getActive }) {
|
|
|
21399
21739
|
return parts.join(" \xB7 ");
|
|
21400
21740
|
};
|
|
21401
21741
|
const disabled = busy || loading || !showButton;
|
|
21402
|
-
const
|
|
21403
|
-
const
|
|
21404
|
-
const promptBody = parsedPrompt.body;
|
|
21405
|
-
function setPromptBody(nextBody) {
|
|
21406
|
-
setForm((current) => {
|
|
21407
|
-
if (current === null) return current;
|
|
21408
|
-
const { mentions } = splitExpertMentions(current.prompt, experts, active);
|
|
21409
|
-
return { ...current, prompt: `${mentions.map((item) => `@${item} `).join("")}${nextBody}` };
|
|
21410
|
-
});
|
|
21411
|
-
}
|
|
21412
|
-
function removeExpert(name) {
|
|
21413
|
-
setForm((current) => {
|
|
21414
|
-
if (current === null) return current;
|
|
21415
|
-
const { mentions, body } = splitExpertMentions(current.prompt, experts, active);
|
|
21416
|
-
return { ...current, prompt: `${mentions.filter((item) => item !== name).map((item) => `@${item} `).join("")}${body}` };
|
|
21417
|
-
});
|
|
21418
|
-
}
|
|
21742
|
+
const mentioned = form === null ? [] : collectExpertMentions(form.prompt, experts, active);
|
|
21743
|
+
const selectedWorkspacePath = form === null ? "" : allWorkspaces.find((workspace) => workspace.id === form.workspaceId)?.path ?? "";
|
|
21419
21744
|
return /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-sched" }, /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-sched-head" }, /* @__PURE__ */ import_react.default.createElement("div", null, /* @__PURE__ */ import_react.default.createElement("h2", { className: "t-team-sched-title" }, t("sched.title")), /* @__PURE__ */ import_react.default.createElement("p", { className: "t-team-sched-intro" }, t("sched.intro"))), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-sched-actions" }, /* @__PURE__ */ import_react.default.createElement("button", { type: "button", className: "t-team-sched-btn", disabled: loading, onClick: () => void load() }, t("sched.refresh")), /* @__PURE__ */ import_react.default.createElement("button", { type: "button", className: "t-team-sched-btn", onClick: backToConversation }, t("sched.back")))), !showButton && /* @__PURE__ */ import_react.default.createElement("p", { className: "t-team-sched-note" }, t("sched.off")), snapshot !== null && snapshot.capabilities.agents !== true && /* @__PURE__ */ import_react.default.createElement("p", { className: "t-team-sched-note" }, t("sched.noAgents")), error62 !== "" && /* @__PURE__ */ import_react.default.createElement("p", { className: "t-team-sched-error", role: "alert" }, t("sched.error"), " ", error62, /* @__PURE__ */ import_react.default.createElement("button", { type: "button", className: "t-team-sched-btn", onClick: () => void load() }, t("sched.retry"))), loading && /* @__PURE__ */ import_react.default.createElement("p", { className: "t-team-sched-intro" }, t("sched.loading")), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-sched-body" }, !loading && items.length === 0 && error62 === "" && /* @__PURE__ */ import_react.default.createElement("p", { className: "t-team-sched-intro" }, t("sched.empty")), /* @__PURE__ */ import_react.default.createElement("ul", { className: "t-team-sched-list" }, items.map((item) => /* @__PURE__ */ import_react.default.createElement("li", { key: item.id, className: "t-team-sched-row" }, /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-sched-rowMain" }, /* @__PURE__ */ import_react.default.createElement("span", { className: "t-team-sched-rowTitle" }, item.title), /* @__PURE__ */ import_react.default.createElement("span", { className: "t-team-sched-rowCron" }, item.cron), /* @__PURE__ */ import_react.default.createElement("span", { className: "t-team-sched-rowMeta" }, rowMeta(item)), item.runs.length > 0 && /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement(
|
|
21420
21745
|
"button",
|
|
21421
21746
|
{
|
|
@@ -21446,11 +21771,12 @@ function SchedulePanel({ t, ctx: hostCtx, remote, getActive }) {
|
|
|
21446
21771
|
prompt: item.prompt,
|
|
21447
21772
|
cron: item.cron,
|
|
21448
21773
|
enabled: item.enabled === true,
|
|
21449
|
-
workspaceId: item.workspaceId ?? ""
|
|
21774
|
+
workspaceId: item.workspaceId ?? "",
|
|
21775
|
+
customDir: ""
|
|
21450
21776
|
})
|
|
21451
21777
|
},
|
|
21452
21778
|
t("sched.edit")
|
|
21453
|
-
), /* @__PURE__ */ import_react.default.createElement("button", { type: "button", className: "t-team-sched-btn t-team-sched-btn-danger", disabled, onClick: () => void removeItem(item.id) }, t("sched.delete")))))), form === null ? /* @__PURE__ */ import_react.default.createElement("button", { type: "button", className: "t-team-sched-btn t-team-sched-btn-primary", disabled, onClick: () =>
|
|
21779
|
+
), /* @__PURE__ */ import_react.default.createElement("button", { type: "button", className: "t-team-sched-btn t-team-sched-btn-danger", disabled, onClick: () => void removeItem(item.id) }, t("sched.delete")))))), form === null ? /* @__PURE__ */ import_react.default.createElement("button", { type: "button", className: "t-team-sched-btn t-team-sched-btn-primary", disabled, onClick: () => void openNewForm() }, t("sched.new")) : /* @__PURE__ */ import_react.default.createElement(
|
|
21454
21780
|
"form",
|
|
21455
21781
|
{
|
|
21456
21782
|
className: "t-team-sched-form",
|
|
@@ -21469,26 +21795,16 @@ function SchedulePanel({ t, ctx: hostCtx, remote, getActive }) {
|
|
|
21469
21795
|
onChange: (event) => setForm({ ...form, title: event.target.value })
|
|
21470
21796
|
}
|
|
21471
21797
|
)),
|
|
21472
|
-
/* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-sched-field" }, /* @__PURE__ */ import_react.default.createElement("span", null, t("sched.promptLabel")), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-sched-promptbox" },
|
|
21473
|
-
|
|
21798
|
+
/* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-sched-field" }, /* @__PURE__ */ import_react.default.createElement("span", null, t("sched.promptLabel")), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-sched-promptbox" }, /* @__PURE__ */ import_react.default.createElement(
|
|
21799
|
+
PromptEditor,
|
|
21474
21800
|
{
|
|
21475
|
-
|
|
21476
|
-
|
|
21477
|
-
|
|
21478
|
-
|
|
21479
|
-
|
|
21480
|
-
onClick: () => removeExpert(name)
|
|
21481
|
-
},
|
|
21482
|
-
"\xD7"
|
|
21483
|
-
)))), /* @__PURE__ */ import_react.default.createElement(
|
|
21484
|
-
"textarea",
|
|
21485
|
-
{
|
|
21486
|
-
className: "t-team-sched-prompt-input",
|
|
21487
|
-
value: promptBody,
|
|
21488
|
-
rows: 4,
|
|
21801
|
+
editorRef: promptEditorRef,
|
|
21802
|
+
t,
|
|
21803
|
+
active,
|
|
21804
|
+
experts,
|
|
21805
|
+
value: form.prompt,
|
|
21489
21806
|
disabled: busy,
|
|
21490
|
-
|
|
21491
|
-
onChange: (event) => setPromptBody(event.target.value)
|
|
21807
|
+
onChange: (prompt) => setForm((current) => current === null ? current : { ...current, prompt })
|
|
21492
21808
|
}
|
|
21493
21809
|
)), /* @__PURE__ */ import_react.default.createElement(
|
|
21494
21810
|
ExpertPicker,
|
|
@@ -21502,7 +21818,7 @@ function SchedulePanel({ t, ctx: hostCtx, remote, getActive }) {
|
|
|
21502
21818
|
}
|
|
21503
21819
|
), mentioned.length > 0 && /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-expert-pick-hint" }, mentioned.length === 1 ? t("sched.expertInvokeHint", { name: mentioned[0] }) : t("sched.expertInvokeManyHint", { names: mentioned.join(t("sched.listSep")) }))),
|
|
21504
21820
|
/* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-sched-field" }, /* @__PURE__ */ import_react.default.createElement("span", null, t("sched.cronLabel")), /* @__PURE__ */ import_react.default.createElement(CronPicker, { t, remote, value: form.cron, disabled: busy, onChange: (cron) => setForm((current) => current === null ? current : { ...current, cron }) }), /* @__PURE__ */ import_react.default.createElement("small", { className: "t-team-sched-hint" }, t("sched.cronHint"))),
|
|
21505
|
-
|
|
21821
|
+
/* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-sched-field" }, /* @__PURE__ */ import_react.default.createElement("span", null, t("sched.workspace")), /* @__PURE__ */ import_react.default.createElement(
|
|
21506
21822
|
"select",
|
|
21507
21823
|
{
|
|
21508
21824
|
value: form.workspaceId,
|
|
@@ -21510,8 +21826,18 @@ function SchedulePanel({ t, ctx: hostCtx, remote, getActive }) {
|
|
|
21510
21826
|
onChange: (event) => setForm({ ...form, workspaceId: event.target.value })
|
|
21511
21827
|
},
|
|
21512
21828
|
/* @__PURE__ */ import_react.default.createElement("option", { value: "" }, t("sched.workspaceNone")),
|
|
21513
|
-
|
|
21514
|
-
|
|
21829
|
+
allWorkspaces.map((workspace) => /* @__PURE__ */ import_react.default.createElement("option", { key: workspace.id, value: workspace.id }, workspace.title)),
|
|
21830
|
+
form.workspaceId !== "" && form.workspaceId !== CUSTOM_WORKSPACE && !allWorkspaces.some((workspace) => workspace.id === form.workspaceId) && /* @__PURE__ */ import_react.default.createElement("option", { value: form.workspaceId }, form.workspaceId),
|
|
21831
|
+
/* @__PURE__ */ import_react.default.createElement("option", { value: CUSTOM_WORKSPACE }, t("sched.workspaceCustom"))
|
|
21832
|
+
), form.workspaceId === CUSTOM_WORKSPACE ? /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement(
|
|
21833
|
+
"input",
|
|
21834
|
+
{
|
|
21835
|
+
value: form.customDir,
|
|
21836
|
+
disabled: busy,
|
|
21837
|
+
placeholder: t("sched.workspaceCustomPlaceholder"),
|
|
21838
|
+
onChange: (event) => setForm({ ...form, customDir: event.target.value })
|
|
21839
|
+
}
|
|
21840
|
+
), /* @__PURE__ */ import_react.default.createElement("small", { className: "t-team-sched-hint" }, t("sched.workspaceCustomHint"))) : /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement("small", { className: "t-team-sched-hint" }, t("sched.workspaceHint")), selectedWorkspacePath !== "" && /* @__PURE__ */ import_react.default.createElement("small", { className: "t-team-sched-hint" }, t("sched.workspacePath", { path: selectedWorkspacePath })))),
|
|
21515
21841
|
/* @__PURE__ */ import_react.default.createElement("label", { className: "t-team-sched-checkbox" }, /* @__PURE__ */ import_react.default.createElement(
|
|
21516
21842
|
"input",
|
|
21517
21843
|
{
|
|
@@ -21741,7 +22067,7 @@ function SettingsPanel({ t, ctx, remote, getActive, refreshCatalog, initialTab,
|
|
|
21741
22067
|
setSnapshot({ ...snapshot, enabled: list });
|
|
21742
22068
|
try {
|
|
21743
22069
|
const state = unwrap(await remote.setEnabled(list, snapshot.revision), "setEnabled");
|
|
21744
|
-
|
|
22070
|
+
publishCatalog(remote, { ...snapshot, enabled: state.enabled, enabledSet: new Set(state.enabled), revision: state.revision });
|
|
21745
22071
|
setSnapshot({ ...snapshot, enabled: state.enabled, revision: state.revision });
|
|
21746
22072
|
setError("");
|
|
21747
22073
|
} catch (cause) {
|
|
@@ -21828,7 +22154,7 @@ function SettingsPanel({ t, ctx, remote, getActive, refreshCatalog, initialTab,
|
|
|
21828
22154
|
onClick: () => void setShowScheduleButton(!showScheduleButton)
|
|
21829
22155
|
},
|
|
21830
22156
|
/* @__PURE__ */ import_react.default.createElement("span", { className: "t-team-switch-knob" })
|
|
21831
|
-
)), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-setting-hint" }, t("settings.showScheduleButtonHint"))), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-tabs", role: "tablist" }, [["experts", "tab.experts"], ["categories", "tab.categories"], ["roster", "tab.roster"]].map(([key, label]) => /* @__PURE__ */ import_react.default.createElement(
|
|
22157
|
+
)), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-setting-hint" }, t("settings.showScheduleButtonHint"))), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-tabs", role: "tablist" }, [["experts", "tab.experts"], ["categories", "tab.categories"], ["roster", "tab.roster"], ["teams", "tab.teams"]].map(([key, label]) => /* @__PURE__ */ import_react.default.createElement(
|
|
21832
22158
|
"button",
|
|
21833
22159
|
{
|
|
21834
22160
|
className: "t-team-tab",
|
|
@@ -21840,7 +22166,7 @@ function SettingsPanel({ t, ctx, remote, getActive, refreshCatalog, initialTab,
|
|
|
21840
22166
|
onClick: () => setTab(key)
|
|
21841
22167
|
},
|
|
21842
22168
|
t(label)
|
|
21843
|
-
))), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-tabbody", hidden: tab !== "categories" }, /* @__PURE__ */ import_react.default.createElement(SectionBoundary, { t, reloadKey: tab }, /* @__PURE__ */ import_react.default.createElement(CategoriesTab, { t, remote, categories, onChanged: () => reload(true) }))), tab === "roster" && /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-tabbody" }, /* @__PURE__ */ import_react.default.createElement(SectionBoundary, { t, reloadKey: tab }, /* @__PURE__ */ import_react.default.createElement("div", null, /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-section-head" }, t("roster.squads")), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-note" }, t("roster.squadsHint"))), /* @__PURE__ */ import_react.default.createElement(SquadsTab, { t, remote, initialData: squadsPreview, initialDraft: draftPreview }), /* @__PURE__ */ import_react.default.createElement("div", null, /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-section-head" }, t("roster.teams")), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-note" }, t("roster.teamsHint"))), /* @__PURE__ */ import_react.default.createElement(TeamsTab, { t, remote, initialTeams: teamsPreview }))), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-tabbody", hidden: tab !== "experts" }, /* @__PURE__ */ import_react.default.createElement(SectionBoundary, { t, reloadKey: tab }, /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-note" }, t("roster.expertsHint")), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-bar" }, /* @__PURE__ */ import_react.default.createElement(
|
|
22169
|
+
))), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-tabbody", hidden: tab !== "categories" }, /* @__PURE__ */ import_react.default.createElement(SectionBoundary, { t, reloadKey: tab }, /* @__PURE__ */ import_react.default.createElement(CategoriesTab, { t, remote, categories, onChanged: () => reload(true) }))), tab === "roster" && /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-tabbody" }, /* @__PURE__ */ import_react.default.createElement(SectionBoundary, { t, reloadKey: tab }, /* @__PURE__ */ import_react.default.createElement("div", null, /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-section-head" }, t("roster.squads")), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-note" }, t("roster.squadsHint"))), /* @__PURE__ */ import_react.default.createElement(SquadsTab, { t, remote, initialData: squadsPreview, initialDraft: draftPreview }))), tab === "teams" && /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-tabbody" }, /* @__PURE__ */ import_react.default.createElement(SectionBoundary, { t, reloadKey: tab }, /* @__PURE__ */ import_react.default.createElement("div", null, /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-section-head" }, t("roster.teams")), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-note" }, t("roster.teamsHint"))), /* @__PURE__ */ import_react.default.createElement(TeamsTab, { t, remote, initialTeams: teamsPreview }))), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-tabbody", hidden: tab !== "experts" }, /* @__PURE__ */ import_react.default.createElement(SectionBoundary, { t, reloadKey: tab }, /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-note" }, t("roster.expertsHint")), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-bar" }, /* @__PURE__ */ import_react.default.createElement(
|
|
21844
22170
|
"input",
|
|
21845
22171
|
{
|
|
21846
22172
|
className: "t-team-input",
|
|
@@ -22747,6 +23073,7 @@ function TeamsTab({ t, remote, initialTeams, compact }) {
|
|
|
22747
23073
|
const [state, setState] = import_react.default.useState({ teams: initialTeams ?? null, error: "" });
|
|
22748
23074
|
const [archived, setArchived] = import_react.default.useState(false);
|
|
22749
23075
|
const [busyId, setBusyId] = import_react.default.useState("");
|
|
23076
|
+
const [removingId, setRemovingId] = import_react.default.useState("");
|
|
22750
23077
|
const [note, setNote] = import_react.default.useState("");
|
|
22751
23078
|
const load = import_react.default.useCallback(async (wantArchived) => {
|
|
22752
23079
|
setState((current) => ({ teams: current.teams, error: "" }));
|
|
@@ -22769,12 +23096,13 @@ function TeamsTab({ t, remote, initialTeams, compact }) {
|
|
|
22769
23096
|
}));
|
|
22770
23097
|
}
|
|
22771
23098
|
async function stop(team) {
|
|
22772
|
-
|
|
23099
|
+
const archiving = team.halted === true || team.captainActive === false;
|
|
23100
|
+
if (!window.confirm(t(archiving ? "teams.archiveConfirm" : "teams.stopConfirm", { name: team.name }))) return;
|
|
22773
23101
|
setBusyId(team.teamId);
|
|
22774
23102
|
setNote("");
|
|
22775
23103
|
try {
|
|
22776
|
-
const result = unwrap(await remote.stopTeam(team.teamId), "stopTeam");
|
|
22777
|
-
setNote(t("teams.stopped", { name: result?.teamName ?? team.name, count: result?.cancelledTasks ?? 0 }));
|
|
23104
|
+
const result = unwrap(await remote.stopTeam(team.teamId, team.workspacePath), "stopTeam");
|
|
23105
|
+
setNote(result?.archived === true ? t("teams.archivedNote", { name: result?.teamName ?? team.name }) : t("teams.stopped", { name: result?.teamName ?? team.name, count: result?.cancelledTasks ?? 0 }));
|
|
22778
23106
|
await load(archived);
|
|
22779
23107
|
} catch (cause) {
|
|
22780
23108
|
setState({ teams: state.teams, error: cause instanceof Error ? cause.message : String(cause) });
|
|
@@ -22782,14 +23110,43 @@ function TeamsTab({ t, remote, initialTeams, compact }) {
|
|
|
22782
23110
|
setBusyId("");
|
|
22783
23111
|
}
|
|
22784
23112
|
}
|
|
23113
|
+
async function remove(team) {
|
|
23114
|
+
if (!window.confirm(t("teams.removeConfirm", { name: team.name }))) return;
|
|
23115
|
+
setRemovingId(team.teamId);
|
|
23116
|
+
setNote("");
|
|
23117
|
+
try {
|
|
23118
|
+
const result = unwrap(await remote.deleteTeam(team.teamId, team.workspacePath), "deleteTeam");
|
|
23119
|
+
setNote(t("teams.removed", { name: result?.teamName ?? team.name }));
|
|
23120
|
+
await load(archived);
|
|
23121
|
+
} catch (cause) {
|
|
23122
|
+
setState({ teams: state.teams, error: cause instanceof Error ? cause.message : String(cause) });
|
|
23123
|
+
} finally {
|
|
23124
|
+
setRemovingId("");
|
|
23125
|
+
}
|
|
23126
|
+
}
|
|
22785
23127
|
const teams = state.teams;
|
|
22786
23128
|
return /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-tabbody" }, /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-row" }, compact !== true && /* @__PURE__ */ import_react.default.createElement("button", { className: "t-team-chip", type: "button", onClick: () => setArchived((value) => !value) }, archived ? t("teams.showActive") : t("teams.showArchived")), /* @__PURE__ */ import_react.default.createElement("button", { className: "t-team-chip", type: "button", onClick: () => void load(archived) }, t("teams.refresh")), /* @__PURE__ */ import_react.default.createElement("button", { className: "t-team-chip", type: "button", onClick: () => openPanel((teams ?? [])[0]) }, t("teams.openPanel"))), note !== "" && /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-ok" }, note), state.error !== "" && /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-error" }, state.error), teams === null && /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-meta" }, t("teams.loading")), teams !== null && teams.length === 0 && /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-meta" }, archived ? t("teams.emptyArchived") : t("teams.empty")), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-teams" }, (teams ?? []).map((team) => {
|
|
22787
23129
|
const taskList = Array.isArray(team?.tasks) ? team.tasks : [];
|
|
22788
23130
|
const memberList = Array.isArray(team?.members) ? team.members : [];
|
|
22789
23131
|
const done = taskList.filter((task) => task?.status === "completed").length;
|
|
22790
23132
|
const working = memberList.filter((member) => member?.activity === "working").length;
|
|
23133
|
+
const archivable = team.halted === true || team.captainActive === false;
|
|
22791
23134
|
const phase = team.halted === true ? t("teams.halted") : archived ? t("teams.archived") : team.phase === "staged" ? t("teams.staged") : t("teams.running");
|
|
22792
|
-
return
|
|
23135
|
+
return (
|
|
23136
|
+
// key 必须带上工作区:teamId 跨工作区会重名,只用 teamId 会让两行共用同一个 key
|
|
23137
|
+
// (同列表内渲染状态互相串)。
|
|
23138
|
+
/* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-team", key: `${team.workspacePath ?? ""}:${team.teamId}` }, /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-team-head" }, /* @__PURE__ */ import_react.default.createElement("span", { className: "t-team-team-name", title: `${team.name} \xB7 ${team.teamId}` }, team.name), /* @__PURE__ */ import_react.default.createElement("span", { className: "t-team-badge", "data-tone": team.halted === true ? "error" : team.phase === "staged" ? "warn" : void 0 }, phase)), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-team-meta" }, /* @__PURE__ */ import_react.default.createElement("span", null, t("teams.members", { count: memberList.length })), /* @__PURE__ */ import_react.default.createElement("span", null, working > 0 ? `${t("teams.working", { count: working })} \xB7 ` : "", t("teams.tasks", { done, total: taskList.length })), /* @__PURE__ */ import_react.default.createElement("span", null, team.workspace)), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-row" }, memberList.slice(0, 8).map((member) => /* @__PURE__ */ import_react.default.createElement("span", { className: "t-team-member-chip", key: member.name, "data-unknown": member.activity === "unknown" }, member.name))), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-row" }, /* @__PURE__ */ import_react.default.createElement("button", { className: "t-team-chip", type: "button", onClick: () => openPanel(team) }, t("teams.openPanel")), !archived && /* @__PURE__ */ import_react.default.createElement("button", { className: "t-team-chip", type: "button", disabled: busyId === team.teamId || removingId === team.teamId, onClick: () => void stop(team) }, busyId === team.teamId ? archivable ? t("teams.archiving") : t("teams.stopping") : archivable ? t("teams.archive") : t("teams.stop")), /* @__PURE__ */ import_react.default.createElement(
|
|
23139
|
+
"button",
|
|
23140
|
+
{
|
|
23141
|
+
className: "t-team-chip",
|
|
23142
|
+
type: "button",
|
|
23143
|
+
"data-tone": "error",
|
|
23144
|
+
disabled: removingId === team.teamId || busyId === team.teamId,
|
|
23145
|
+
onClick: () => void remove(team)
|
|
23146
|
+
},
|
|
23147
|
+
removingId === team.teamId ? t("teams.removing") : t("teams.remove")
|
|
23148
|
+
)))
|
|
23149
|
+
);
|
|
22793
23150
|
})));
|
|
22794
23151
|
}
|
|
22795
23152
|
function resolveInputTarget(ctx, sessionId) {
|