@tt-a1i/hive 1.6.0 → 1.7.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 +14 -0
- package/README.en.md +2 -1
- package/README.md +2 -1
- package/dist/src/cli/team.js +2 -2
- package/dist/src/server/agent-run-bootstrap.d.ts +6 -1
- package/dist/src/server/agent-run-bootstrap.js +5 -2
- package/dist/src/server/agent-run-starter.js +15 -1
- package/dist/src/server/agent-startup-instructions.js +1 -1
- package/dist/src/server/command-preset-defaults.js +12 -0
- package/dist/src/server/hive-team-guidance.js +4 -4
- package/dist/src/server/post-start-input-writer.js +2 -2
- package/dist/src/server/preset-launch-support.js +2 -1
- package/dist/src/server/session-capture.d.ts +6 -0
- package/dist/src/server/session-capture.js +32 -0
- package/dist/src/server/sqlite-schema-v22.d.ts +2 -0
- package/dist/src/server/sqlite-schema-v22.js +27 -0
- package/dist/src/server/sqlite-schema.d.ts +1 -1
- package/dist/src/server/sqlite-schema.js +6 -1
- package/dist/src/server/workflow-cli-policy.d.ts +1 -1
- package/dist/src/server/workflow-cli-policy.js +1 -1
- package/dist/src/server/workflow-runner.js +1 -1
- package/dist/src/shared/types.d.ts +2 -2
- package/package.json +1 -1
- package/web/dist/assets/{AddWorkerDialog-CGbaxu0T.js → AddWorkerDialog-BRUxpa3f.js} +2 -2
- package/web/dist/assets/{AddWorkspaceDialog-CNgExu6b.js → AddWorkspaceDialog-D56x5JCb.js} +1 -1
- package/web/dist/assets/{FirstRunWizard-DxGApUNc.js → FirstRunWizard-BFVaMIsE.js} +1 -1
- package/web/dist/assets/{MarketplaceDrawer-Bk6cpukn.js → MarketplaceDrawer-DeEZ35dN.js} +1 -1
- package/web/dist/assets/{WhatsNewDialog-CSGzk-2U.js → WhatsNewDialog-CHkZeINH.js} +1 -1
- package/web/dist/assets/{WorkerModal-i2F3n3nZ.js → WorkerModal-BBCuMLIa.js} +1 -1
- package/web/dist/assets/{WorkspaceTaskDrawer-C_Ta_K13.js → WorkspaceTaskDrawer-CpZHAcj1.js} +1 -1
- package/web/dist/assets/{WorkspaceTerminalPanels-VdDxtrQF.js → WorkspaceTerminalPanels-7If2mDyp.js} +1 -1
- package/web/dist/assets/{index-CAgGM6nb.js → index-CxNL0O-C.js} +5 -7
- package/web/dist/cli-icons/hermes.png +0 -0
- package/web/dist/index.html +1 -1
- package/web/dist/sw.js +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
All notable user-facing changes will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## 1.7.0 - 2026-06-05
|
|
6
|
+
|
|
7
|
+
Hermes joins the roster.
|
|
8
|
+
|
|
9
|
+
- Adds Hermes as a fifth built-in CLI agent preset alongside Claude Code,
|
|
10
|
+
Codex, OpenCode, and Gemini: available as an Orchestrator or Worker, in
|
|
11
|
+
`team spawn --cli hermes`, and in the workflow CLI allowlist.
|
|
12
|
+
- Hermes runs YOLO via `--yolo` and resumes sessions via
|
|
13
|
+
`--resume <session_id>`; crash recovery (Layer A) captures its session id
|
|
14
|
+
from the CLI's own startup output through a new stdout-based capture
|
|
15
|
+
source.
|
|
16
|
+
- Existing installs pick the preset up automatically via a database
|
|
17
|
+
migration — no manual setup beyond having `hermes` on your PATH.
|
|
18
|
+
|
|
5
19
|
## 1.6.0 - 2026-06-02
|
|
6
20
|
|
|
7
21
|
Orchestrator controls, worker visibility, and protocol-trust fixes.
|
package/README.en.md
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
</p>
|
|
10
10
|
|
|
11
11
|
**Hive is a browser-native workbench where a team of agents works together — one orchestrates, the rest execute, all on your laptop.** The orchestrator
|
|
12
|
-
is a real `claude` / `codex` / `opencode` / `gemini` process — not you, and
|
|
12
|
+
is a real `claude` / `codex` / `opencode` / `gemini` / `hermes` process — not you, and
|
|
13
13
|
not a script — and so are the workers it dispatches to. Every agent runs as
|
|
14
14
|
a real PTY on your machine, talks through a small `team` protocol that Hive
|
|
15
15
|
injects into each agent's shell, and shares a markdown task graph at
|
|
@@ -176,6 +176,7 @@ Three details matter:
|
|
|
176
176
|
| Codex | `codex` | `--dangerously-bypass-approvals-and-sandbox` | `resume <session_id>` |
|
|
177
177
|
| OpenCode | `opencode` | Config-driven in `~/.config/opencode/opencode.json` | `--session <session_id>` |
|
|
178
178
|
| Gemini | `gemini` | `--yolo` | `--resume <session_id>` |
|
|
179
|
+
| Hermes | `hermes` | `--yolo` | `--resume <session_id>` |
|
|
179
180
|
| Custom | Any executable | User configured | User configured |
|
|
180
181
|
|
|
181
182
|
Hive does not install these CLIs for you. Install and authenticate them in the
|
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
<img src="./assets/hive-hero.png" alt="Hive 本机多 agent 协作工作台" />
|
|
9
9
|
</p>
|
|
10
10
|
|
|
11
|
-
**Hive 是浏览器里的 Agent 协作工作台——一群 Agent 在你本机各自开工,一个当 Orchestrator 派活、归总进展,其余各司其职。** Orchestrator 本身就是一个真实的 `claude` / `codex` / `opencode` / `gemini` 进程——不是你、也不是脚本——它派单的 Worker 同样是真 CLI agent。所有 agent 都是本机真实的 PTY 进程,通过 Hive 注入到 shell 里的小型 `team` 协议互相通信,共享 `<workspace>/.hive/tasks.md` 这份 markdown 任务图。
|
|
11
|
+
**Hive 是浏览器里的 Agent 协作工作台——一群 Agent 在你本机各自开工,一个当 Orchestrator 派活、归总进展,其余各司其职。** Orchestrator 本身就是一个真实的 `claude` / `codex` / `opencode` / `gemini` / `hermes` 进程——不是你、也不是脚本——它派单的 Worker 同样是真 CLI agent。所有 agent 都是本机真实的 PTY 进程,通过 Hive 注入到 shell 里的小型 `team` 协议互相通信,共享 `<workspace>/.hive/tasks.md` 这份 markdown 任务图。
|
|
12
12
|
|
|
13
13
|
写代码、做调研、起草文档、做翻译——凡是能拆给一群人协作的脑力活,都可以让一群 Agent 合伙干。
|
|
14
14
|
|
|
@@ -126,6 +126,7 @@ Workspace 任务图:
|
|
|
126
126
|
| Codex | `codex` | `--dangerously-bypass-approvals-and-sandbox` | `resume <session_id>` |
|
|
127
127
|
| OpenCode | `opencode` | 由 `~/.config/opencode/opencode.json` 配置 | `--session <session_id>` |
|
|
128
128
|
| Gemini | `gemini` | `--yolo` | `--resume <session_id>` |
|
|
129
|
+
| Hermes | `hermes` | `--yolo` | `--resume <session_id>` |
|
|
129
130
|
| 自定义 | 任意可执行文件 | 自己配 | 自己配 |
|
|
130
131
|
|
|
131
132
|
Hive 不替你安装这些 CLI。请在启动 Hive 的同一个 shell 环境里先装好、登录好。
|
package/dist/src/cli/team.js
CHANGED
|
@@ -11,7 +11,7 @@ const TEAM_USAGE = [
|
|
|
11
11
|
' team list',
|
|
12
12
|
' team next (tasks in .hive/tasks.md that are unblocked now — those whose [needs: #n] deps are all done)',
|
|
13
13
|
' team send <worker-name> "<task>"',
|
|
14
|
-
' team spawn <role> [--name <name>] [--cli <claude|codex|opencode|gemini>] [--ephemeral]',
|
|
14
|
+
' team spawn <role> [--name <name>] [--cli <claude|codex|opencode|gemini|hermes>] [--ephemeral]',
|
|
15
15
|
' team dismiss <worker-name>',
|
|
16
16
|
" team workflow run --stdin [--args '<JSON>'] (script from stdin — for multi-line scripts)",
|
|
17
17
|
' team workflow run --inline "<source>" [--args \'<JSON>\']',
|
|
@@ -291,7 +291,7 @@ export const runTeamCommand = async (argv) => {
|
|
|
291
291
|
if (command === 'spawn') {
|
|
292
292
|
const role = args[0];
|
|
293
293
|
if (!role || role.startsWith('--')) {
|
|
294
|
-
throw new Error('Usage: team spawn <role> [--name <name>] [--cli <claude|codex|opencode|gemini>] [--ephemeral]\n' +
|
|
294
|
+
throw new Error('Usage: team spawn <role> [--name <name>] [--cli <claude|codex|opencode|gemini|hermes>] [--ephemeral]\n' +
|
|
295
295
|
' Default: persistent member (lives until you `team dismiss` it).\n' +
|
|
296
296
|
' --ephemeral: auto-dismiss after the next dispatch report (one-shot worker).');
|
|
297
297
|
}
|
|
@@ -60,6 +60,10 @@ export declare const buildAgentRunBootstrap: (workspace: WorkspaceSummary, agent
|
|
|
60
60
|
};
|
|
61
61
|
knownSessionIds: Set<string>;
|
|
62
62
|
root: string;
|
|
63
|
+
} | {
|
|
64
|
+
knownSessionIds: Set<string>;
|
|
65
|
+
env?: never;
|
|
66
|
+
root?: never;
|
|
63
67
|
} | undefined;
|
|
64
68
|
startConfig: AgentLaunchConfigInput;
|
|
65
69
|
startEnv: {
|
|
@@ -69,8 +73,9 @@ export declare const buildAgentRunBootstrap: (workspace: WorkspaceSummary, agent
|
|
|
69
73
|
HIVE_AGENT_TOKEN: string;
|
|
70
74
|
};
|
|
71
75
|
};
|
|
72
|
-
export declare const startAgentRunCapture: ({ agentId, sessionCaptureSnapshot, sessionStore, startConfig, workspace, }: {
|
|
76
|
+
export declare const startAgentRunCapture: ({ agentId, getRunOutput, sessionCaptureSnapshot, sessionStore, startConfig, workspace, }: {
|
|
73
77
|
agentId: string;
|
|
78
|
+
getRunOutput?: () => string | null;
|
|
74
79
|
sessionCaptureSnapshot: SessionCaptureSnapshot | undefined;
|
|
75
80
|
sessionStore: AgentSessionStorePort;
|
|
76
81
|
startConfig: AgentLaunchConfigInput;
|
|
@@ -84,10 +84,13 @@ export const buildAgentRunBootstrap = (workspace, agentId, config, sessionStore,
|
|
|
84
84
|
},
|
|
85
85
|
};
|
|
86
86
|
};
|
|
87
|
-
export const startAgentRunCapture = ({ agentId, sessionCaptureSnapshot, sessionStore, startConfig, workspace, }) => {
|
|
87
|
+
export const startAgentRunCapture = ({ agentId, getRunOutput, sessionCaptureSnapshot, sessionStore, startConfig, workspace, }) => {
|
|
88
88
|
if (!sessionCaptureSnapshot || !startConfig.sessionIdCapture)
|
|
89
89
|
return;
|
|
90
|
-
|
|
90
|
+
const captureSnapshot = startConfig.sessionIdCapture.source === 'stdout_regex' && getRunOutput
|
|
91
|
+
? { ...sessionCaptureSnapshot, getOutput: getRunOutput }
|
|
92
|
+
: sessionCaptureSnapshot;
|
|
93
|
+
void captureSessionIdForCapture(workspace.path, startConfig.sessionIdCapture, captureSnapshot, (sessionId) => {
|
|
91
94
|
sessionStore.setLastSessionId(workspace.id, agentId, sessionId);
|
|
92
95
|
}, SESSION_CAPTURE_TIMEOUT_MS);
|
|
93
96
|
};
|
|
@@ -85,7 +85,21 @@ export const createAgentRunStarter = ({ agentManager, registry, onAgentExit, sto
|
|
|
85
85
|
registry.clearPendingExitCode(run.runId);
|
|
86
86
|
return liveRun;
|
|
87
87
|
}
|
|
88
|
-
startAgentRunCapture({
|
|
88
|
+
startAgentRunCapture({
|
|
89
|
+
agentId,
|
|
90
|
+
getRunOutput: () => {
|
|
91
|
+
try {
|
|
92
|
+
return agentManager.getRun(run.runId).output;
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
sessionCaptureSnapshot,
|
|
99
|
+
sessionStore,
|
|
100
|
+
startConfig,
|
|
101
|
+
workspace,
|
|
102
|
+
});
|
|
89
103
|
const postStartWriter = createPostStartInputWriter(agentManager, startConfig.interactiveCommand ?? startConfig.command);
|
|
90
104
|
queueMicrotask(() => {
|
|
91
105
|
try {
|
|
@@ -19,7 +19,7 @@ export const buildAgentStartupInstructions = ({ agent, workspace, flags = FEATUR
|
|
|
19
19
|
'',
|
|
20
20
|
];
|
|
21
21
|
if (agent.role === 'orchestrator') {
|
|
22
|
-
lines.push('Your responsibilities:', '- Respond to the user directly; clarify the goal and break it into dispatchable tasks', `- Maintain ${TASKS_RELATIVE_PATH}`, '- Dispatch by worker name and drive the next step from each report', '', 'Available team commands:', '- team list', '- team send "<worker-name>" "<task>"', '- team spawn <role> [--name <n>] [--cli claude|codex|opencode|gemini] [--ephemeral]', '- team cancel --dispatch <id> "<reason>"', ...(workflowsEnabled
|
|
22
|
+
lines.push('Your responsibilities:', '- Respond to the user directly; clarify the goal and break it into dispatchable tasks', `- Maintain ${TASKS_RELATIVE_PATH}`, '- Dispatch by worker name and drive the next step from each report', '', 'Available team commands:', '- team list', '- team send "<worker-name>" "<task>"', '- team spawn <role> [--name <n>] [--cli claude|codex|opencode|gemini|hermes] [--ephemeral]', '- team cancel --dispatch <id> "<reason>"', ...(workflowsEnabled
|
|
23
23
|
? [
|
|
24
24
|
'- team workflow run --stdin (fan-out / staged work — see .hive/PROTOCOL.md for the DSL)',
|
|
25
25
|
]
|
|
@@ -2,6 +2,7 @@ import { CLAUDE_DEFAULT_YOLO_ARGS } from './claude-command-defaults.js';
|
|
|
2
2
|
const CODEX_DEFAULT_YOLO_ARGS = ['--dangerously-bypass-approvals-and-sandbox'];
|
|
3
3
|
const OPENCODE_DEFAULT_YOLO_ARGS = [];
|
|
4
4
|
const GEMINI_DEFAULT_YOLO_ARGS = ['--yolo'];
|
|
5
|
+
const HERMES_DEFAULT_YOLO_ARGS = ['--yolo'];
|
|
5
6
|
export const BUILTIN_COMMAND_PRESETS = [
|
|
6
7
|
{
|
|
7
8
|
command: 'claude',
|
|
@@ -47,5 +48,16 @@ export const BUILTIN_COMMAND_PRESETS = [
|
|
|
47
48
|
},
|
|
48
49
|
yoloArgsTemplate: GEMINI_DEFAULT_YOLO_ARGS,
|
|
49
50
|
},
|
|
51
|
+
{
|
|
52
|
+
command: 'hermes',
|
|
53
|
+
displayName: 'Hermes',
|
|
54
|
+
id: 'hermes',
|
|
55
|
+
resumeArgsTemplate: '--resume {session_id}',
|
|
56
|
+
sessionIdCapture: {
|
|
57
|
+
pattern: String.raw `Session:\s*([A-Za-z0-9_-]+)`,
|
|
58
|
+
source: 'stdout_regex',
|
|
59
|
+
},
|
|
60
|
+
yoloArgsTemplate: HERMES_DEFAULT_YOLO_ARGS,
|
|
61
|
+
},
|
|
50
62
|
];
|
|
51
63
|
export const getBuiltinCommandPreset = (id) => BUILTIN_COMMAND_PRESETS.find((preset) => preset.id === id);
|
|
@@ -20,7 +20,7 @@ import { DEFAULT_WORKFLOW_CLI_POLICY } from './workflow-cli-policy.js';
|
|
|
20
20
|
export const buildOrchestratorReminderTail = ({ workflowsEnabled }) => {
|
|
21
21
|
const body = 'You are the Hive Orchestrator. Reply with one of: ' +
|
|
22
22
|
'(a) `team send "<worker-name>" "<task>"` to dispatch — run `team list` first if the roster may have changed since your last view (Hive does not push membership changes; stale names fail). ' +
|
|
23
|
-
'If no worker fits or the roster is empty, `team spawn <role> [--cli claude|codex|opencode|gemini]` to create one (add `--ephemeral` for a one-shot), then dispatch; do not ask the user to add workers. ' +
|
|
23
|
+
'If no worker fits or the roster is empty, `team spawn <role> [--cli claude|codex|opencode|gemini|hermes]` to create one (add `--ephemeral` for a one-shot), then dispatch; do not ask the user to add workers. ' +
|
|
24
24
|
'(b) `team cancel --dispatch <id> "<reason>"` to close an obsolete dispatch. ' +
|
|
25
25
|
(workflowsEnabled
|
|
26
26
|
? '(c) `team workflow run --stdin` to fan out across 3+ workers or run a staged review→fix — never a loop of `team send` (no barrier, no UI group, no stop button). (d) plain text to the user. '
|
|
@@ -53,7 +53,7 @@ const CORE_ORCHESTRATOR_RULES = [
|
|
|
53
53
|
'Small, low-risk tasks you can finish in a couple of minutes: do them yourself; do not dispatch for the sake of form. Reach for `team send` when the work needs parallelism, long execution, independent review/test, a dedicated role, or the user explicitly asked for a worker.',
|
|
54
54
|
'If exactly one worker is available, dispatch to it directly with `team send <worker-name> "<task>"` — do not bounce the choice back to the user.',
|
|
55
55
|
'When the user says "have a worker do X", dispatch it with `team send <worker-name> "<task>"`.',
|
|
56
|
-
'If the roster is empty or lacks the role the task needs, build the team yourself: `team spawn <role> [--name <n>] [--cli claude|codex|opencode|gemini]`, then immediately dispatch. Do not stop to ask the user to add members — that call is yours.',
|
|
56
|
+
'If the roster is empty or lacks the role the task needs, build the team yourself: `team spawn <role> [--name <n>] [--cli claude|codex|opencode|gemini|hermes]`, then immediately dispatch. Do not stop to ask the user to add members — that call is yours.',
|
|
57
57
|
'`team spawn` is PERSISTENT by default (a normal member that stays in the workspace); add `--ephemeral` for a one-shot worker that auto-dismisses after its first `team report`. Rule of thumb: will you reuse this role in the next 10 minutes? Yes → persistent; no → `--ephemeral`.',
|
|
58
58
|
'When the user cancels or changes direction on an open dispatch, close it explicitly with `team cancel --dispatch <id> "<reason>"` — do not just say "cancel" in prose.',
|
|
59
59
|
'Each `team send` opens a SEPARATE dispatch with its own pending count and its own required report — it is not a way to tack context onto a dispatch already in flight. Send the same worker twice and it owes you TWO reports; one report closes only one dispatch (the one its `--dispatch <id>` names, or the oldest open one if the flag is omitted), so the other stays open and the worker is pinned on `working`. To change or extend an in-flight task, `team cancel --dispatch <id> "<reason>"` the stale dispatch and re-send the whole task, or wait for the worker to report and dispatch the follow-up after.',
|
|
@@ -121,7 +121,7 @@ Host functions injected into the script: \`agent(prompt, opts)\`,
|
|
|
121
121
|
\`parallel(thunks)\`, \`pipeline(items, ...stages)\`, \`phase(title)\`,
|
|
122
122
|
\`log(msg)\`, plus the \`args\` global.
|
|
123
123
|
|
|
124
|
-
\`agent(prompt, opts)\` opts: \`{ agentType?: "coder"|"reviewer"|"tester"|"custom"|<custom-role-name>, cli?: "claude"|"codex"|"opencode"|"gemini", model?: string, outputSchema?: object, label?: string, timeoutMs?: number }\` — other fields are silently ignored. \`agentType\` also accepts the name of a workspace custom role template (case-insensitive); a typo throws rather than silently falling back to coder. \`model\` is passed through to the worker launch config (\`--model <id>\`), so a 100-way fan-out can use a cheap model and the synthesizer a strong one. \`outputSchema\` makes \`agent()\` resolve to a parsed object instead of a string: the worker is told to end its report with a fenced \`\`\`json block whose keys match the schema. On a parse miss it falls back to \`{ text: "<raw report>" }\`, so ALWAYS treat a missing field as the SAFE default (never assume success). The worker auto-dismisses when its \`agent()\` call resolves — you never dismiss it.
|
|
124
|
+
\`agent(prompt, opts)\` opts: \`{ agentType?: "coder"|"reviewer"|"tester"|"custom"|<custom-role-name>, cli?: "claude"|"codex"|"opencode"|"gemini"|"hermes", model?: string, outputSchema?: object, label?: string, timeoutMs?: number }\` — other fields are silently ignored. \`agentType\` also accepts the name of a workspace custom role template (case-insensitive); a typo throws rather than silently falling back to coder. \`model\` is passed through to the worker launch config (\`--model <id>\`), so a 100-way fan-out can use a cheap model and the synthesizer a strong one. \`outputSchema\` makes \`agent()\` resolve to a parsed object instead of a string: the worker is told to end its report with a fenced \`\`\`json block whose keys match the schema. On a parse miss it falls back to \`{ text: "<raw report>" }\`, so ALWAYS treat a missing field as the SAFE default (never assume success). The worker auto-dismisses when its \`agent()\` call resolves — you never dismiss it.
|
|
125
125
|
|
|
126
126
|
\`parallel()\` takes an array of THUNKS (\`() => agent(...)\`), NOT already-started promises: \`parallel([agent(...), agent(...)])\` degrades to unordered concurrency counted as a single step (a no-op grouping), because the promises already started at construction time. \`pipeline(items, ...stages)\` stages are also functions, shape \`(prev, item, i) => agent(...)\`.
|
|
127
127
|
|
|
@@ -253,7 +253,7 @@ export const buildProtocolDoc = (cliPolicy = DEFAULT_WORKFLOW_CLI_POLICY, flags
|
|
|
253
253
|
'',
|
|
254
254
|
'- `team list` — show workspace members and their status',
|
|
255
255
|
'- `team send "<worker-name>" "<task>"` — dispatch to a worker by name (never id)',
|
|
256
|
-
'- `team spawn <role> [--name <name>] [--cli claude|codex|opencode|gemini]` — create a PERSISTENT member when none fits (or when the roster is empty)',
|
|
256
|
+
'- `team spawn <role> [--name <name>] [--cli claude|codex|opencode|gemini|hermes]` — create a PERSISTENT member when none fits (or when the roster is empty)',
|
|
257
257
|
'- `team spawn <role> --ephemeral [other-flags]` — create a one-shot worker that auto-dismisses after its first `team report`',
|
|
258
258
|
'- `team dismiss <worker-name>` — remove an ephemeral worker you spawned',
|
|
259
259
|
'- `team cancel --dispatch <id> "<reason>"` — cancel an obsolete open dispatch',
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { normalizeExecutableToken } from './startup-command-parser.js';
|
|
2
|
-
const INTERACTIVE_COMMANDS = new Set(['claude', 'codex', 'gemini', 'opencode']);
|
|
2
|
+
const INTERACTIVE_COMMANDS = new Set(['claude', 'codex', 'gemini', 'hermes', 'opencode']);
|
|
3
3
|
const READY_CHECK_INTERVAL_MS = 50;
|
|
4
4
|
const READY_TIMEOUT_MS = 3000;
|
|
5
5
|
const MIN_SUBMIT_AFTER_PASTE_DELAY_MS = 600;
|
|
@@ -19,7 +19,7 @@ const CODEX_PASTE_ACK_TIMEOUT_MS = 10000;
|
|
|
19
19
|
// timeout before Enter is sent.
|
|
20
20
|
const CODEX_PASTE_ACK_MIN_CHARS = 2000;
|
|
21
21
|
const CODEX_SUBMIT_RETRY_DELAY_MS = 500;
|
|
22
|
-
const COMMANDS_WITH_BRACKETED_PASTE = new Set(['claude', 'codex', 'opencode']);
|
|
22
|
+
const COMMANDS_WITH_BRACKETED_PASTE = new Set(['claude', 'codex', 'hermes', 'opencode']);
|
|
23
23
|
const COMMANDS_WAITING_FOR_PASTE_ACK = new Set(['claude', 'codex']);
|
|
24
24
|
const BRACKETED_PASTE_END = '\u001b[201~';
|
|
25
25
|
const PASTE_ACK_PATTERN = /(?:^|[\r\n])\s*(?:[❯›]\s*)?\[(?:Pasted text #\d+[^\]]*|Pasted Content [\d,]+ chars)\]/u;
|
|
@@ -63,7 +63,8 @@ const shouldVerifySessionBeforeResume = (capture) => {
|
|
|
63
63
|
const supportsPresetResume = (capture) => capture?.source === 'claude_project_jsonl_dir' ||
|
|
64
64
|
capture?.source === 'codex_session_jsonl_dir' ||
|
|
65
65
|
capture?.source === 'gemini_session_json_dir' ||
|
|
66
|
-
capture?.source === 'opencode_session_db'
|
|
66
|
+
capture?.source === 'opencode_session_db' ||
|
|
67
|
+
capture?.source === 'stdout_regex';
|
|
67
68
|
export const withPresetResumeArgs = (config, preset, lastSessionId, cwd, discriminator, onInvalidSessionId) => {
|
|
68
69
|
const launchConfig = normalizeCodexNodeEntrypoint(config, preset);
|
|
69
70
|
let nextConfig = withPresetYoloArgs(launchConfig, preset);
|
|
@@ -21,6 +21,7 @@ export interface SessionCaptureSnapshot {
|
|
|
21
21
|
discriminator?: {
|
|
22
22
|
contentIncludes: string | readonly string[];
|
|
23
23
|
};
|
|
24
|
+
getOutput?: () => string | null;
|
|
24
25
|
knownSessionIds: Set<string>;
|
|
25
26
|
env?: Record<string, string>;
|
|
26
27
|
root?: string;
|
|
@@ -65,7 +66,12 @@ export declare const snapshotSessionIdsForCapture: (cwd: string, capture: Sessio
|
|
|
65
66
|
};
|
|
66
67
|
knownSessionIds: Set<string>;
|
|
67
68
|
root: string;
|
|
69
|
+
} | {
|
|
70
|
+
knownSessionIds: Set<string>;
|
|
71
|
+
env?: never;
|
|
72
|
+
root?: never;
|
|
68
73
|
} | undefined;
|
|
69
74
|
export declare const getSessionCaptureEnvironment: (snapshot: SessionCaptureSnapshot | undefined) => Record<string, string>;
|
|
70
75
|
export declare const captureSessionIdForCapture: (cwd: string, capture: SessionIdCaptureConfig, snapshot: SessionCaptureSnapshot, onCapture: (sessionId: string) => void, timeoutMs?: number, intervalMs?: number) => Promise<void>;
|
|
71
76
|
export declare const doesCapturedSessionExist: (cwd: string, capture: SessionIdCaptureConfig, sessionId: string, discriminator?: SessionCaptureSnapshot["discriminator"]) => boolean;
|
|
77
|
+
export declare const captureStdoutRegexSessionId: (pattern: string, getOutput: (() => string | null) | undefined, knownSessionIds: Set<string>, onCapture: (sessionId: string) => void, timeoutMs?: number, intervalMs?: number) => Promise<void>;
|
|
@@ -57,6 +57,11 @@ export const snapshotSessionIdsForCapture = (cwd, capture, discriminator) => {
|
|
|
57
57
|
root: dbPath,
|
|
58
58
|
};
|
|
59
59
|
}
|
|
60
|
+
if (capture.source === 'stdout_regex') {
|
|
61
|
+
return {
|
|
62
|
+
knownSessionIds: new Set(),
|
|
63
|
+
};
|
|
64
|
+
}
|
|
60
65
|
return undefined;
|
|
61
66
|
};
|
|
62
67
|
export const getSessionCaptureEnvironment = (snapshot) => snapshot?.env ?? {};
|
|
@@ -73,6 +78,9 @@ export const captureSessionIdForCapture = async (cwd, capture, snapshot, onCaptu
|
|
|
73
78
|
if (capture.source === 'opencode_session_db') {
|
|
74
79
|
await captureOpenCodeSessionId(cwd, snapshot.knownSessionIds, onCapture, timeoutMs, intervalMs, snapshot.root);
|
|
75
80
|
}
|
|
81
|
+
if (capture.source === 'stdout_regex') {
|
|
82
|
+
await captureStdoutRegexSessionId(capture.pattern, snapshot.getOutput, snapshot.knownSessionIds, onCapture, timeoutMs, intervalMs);
|
|
83
|
+
}
|
|
76
84
|
};
|
|
77
85
|
export const doesCapturedSessionExist = (cwd, capture, sessionId, discriminator) => {
|
|
78
86
|
if (capture.source === 'claude_project_jsonl_dir') {
|
|
@@ -89,3 +97,27 @@ export const doesCapturedSessionExist = (cwd, capture, sessionId, discriminator)
|
|
|
89
97
|
}
|
|
90
98
|
return false;
|
|
91
99
|
};
|
|
100
|
+
const compileCaptureRegex = (pattern) => {
|
|
101
|
+
try {
|
|
102
|
+
return new RegExp(pattern, 'u');
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
export const captureStdoutRegexSessionId = async (pattern, getOutput, knownSessionIds, onCapture, timeoutMs = 5000, intervalMs = 100) => {
|
|
109
|
+
const regex = compileCaptureRegex(pattern);
|
|
110
|
+
if (!regex || !getOutput)
|
|
111
|
+
return;
|
|
112
|
+
const deadline = Date.now() + timeoutMs;
|
|
113
|
+
while (Date.now() <= deadline) {
|
|
114
|
+
const output = getOutput();
|
|
115
|
+
const match = output ? regex.exec(output) : null;
|
|
116
|
+
const sessionId = match?.[1];
|
|
117
|
+
if (sessionId && !knownSessionIds.has(sessionId)) {
|
|
118
|
+
onCapture(sessionId);
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
await new Promise((resolve) => setTimeout(resolve, intervalMs));
|
|
122
|
+
}
|
|
123
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
const HERMES_SESSION_ID_CAPTURE = {
|
|
2
|
+
pattern: String.raw `Session:\s*([A-Za-z0-9_-]+)`,
|
|
3
|
+
source: 'stdout_regex',
|
|
4
|
+
};
|
|
5
|
+
const HERMES_YOLO_ARGS = ['--yolo'];
|
|
6
|
+
export const applySchemaVersion22 = (db) => {
|
|
7
|
+
const hasCommandPresets = db
|
|
8
|
+
.prepare("SELECT name FROM sqlite_master WHERE type = 'table' AND name = 'command_presets'")
|
|
9
|
+
.get();
|
|
10
|
+
if (!hasCommandPresets)
|
|
11
|
+
return;
|
|
12
|
+
const now = Date.now();
|
|
13
|
+
db.prepare(`INSERT INTO command_presets (
|
|
14
|
+
id, display_name, command, args, env, resume_args_template, session_id_capture,
|
|
15
|
+
yolo_args_template, is_builtin, created_at, updated_at
|
|
16
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, 1, ?, ?)
|
|
17
|
+
ON CONFLICT(id) DO UPDATE SET
|
|
18
|
+
display_name = excluded.display_name,
|
|
19
|
+
command = excluded.command,
|
|
20
|
+
args = excluded.args,
|
|
21
|
+
env = excluded.env,
|
|
22
|
+
resume_args_template = excluded.resume_args_template,
|
|
23
|
+
session_id_capture = excluded.session_id_capture,
|
|
24
|
+
yolo_args_template = excluded.yolo_args_template,
|
|
25
|
+
updated_at = excluded.updated_at
|
|
26
|
+
WHERE command_presets.is_builtin = 1`).run('hermes', 'Hermes', 'hermes', '[]', '{}', '--resume {session_id}', JSON.stringify(HERMES_SESSION_ID_CAPTURE), JSON.stringify(HERMES_YOLO_ARGS), now, now);
|
|
27
|
+
};
|
|
@@ -14,7 +14,8 @@ import { applySchemaVersion18 } from './sqlite-schema-v18.js';
|
|
|
14
14
|
import { applySchemaVersion19 } from './sqlite-schema-v19.js';
|
|
15
15
|
import { applySchemaVersion20 } from './sqlite-schema-v20.js';
|
|
16
16
|
import { applySchemaVersion21 } from './sqlite-schema-v21.js';
|
|
17
|
-
|
|
17
|
+
import { applySchemaVersion22 } from './sqlite-schema-v22.js';
|
|
18
|
+
export const CURRENT_SCHEMA_VERSION = 22;
|
|
18
19
|
// Idempotent column-add helper. SQLite doesn't have `ALTER TABLE … ADD COLUMN
|
|
19
20
|
// IF NOT EXISTS`, so PRAGMA-check first. Safe to call on every init; required
|
|
20
21
|
// for foreign-built DBs where the version-gated migration is skipped.
|
|
@@ -312,4 +313,8 @@ export const initializeRuntimeDatabase = (db) => {
|
|
|
312
313
|
applySchemaVersion21(db);
|
|
313
314
|
db.prepare('INSERT INTO schema_version (version, applied_at) VALUES (?, ?)').run(21, Date.now());
|
|
314
315
|
}
|
|
316
|
+
if (!appliedVersions.has(22)) {
|
|
317
|
+
applySchemaVersion22(db);
|
|
318
|
+
db.prepare('INSERT INTO schema_version (version, applied_at) VALUES (?, ?)').run(22, Date.now());
|
|
319
|
+
}
|
|
315
320
|
};
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
*/
|
|
15
15
|
/** Canonical CLI set — mirrors the built-in command preset ids
|
|
16
16
|
* (see command-preset-defaults.ts). The allowlist is a subset of these. */
|
|
17
|
-
export declare const CANONICAL_WORKFLOW_CLIS: readonly ["claude", "codex", "opencode", "gemini"];
|
|
17
|
+
export declare const CANONICAL_WORKFLOW_CLIS: readonly ["claude", "codex", "opencode", "gemini", "hermes"];
|
|
18
18
|
export type WorkflowCli = (typeof CANONICAL_WORKFLOW_CLIS)[number];
|
|
19
19
|
export declare const WORKFLOW_CLI_POLICY_KEY = "workflow.cli-policy";
|
|
20
20
|
export interface WorkflowCliPolicy {
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
*/
|
|
15
15
|
/** Canonical CLI set — mirrors the built-in command preset ids
|
|
16
16
|
* (see command-preset-defaults.ts). The allowlist is a subset of these. */
|
|
17
|
-
export const CANONICAL_WORKFLOW_CLIS = ['claude', 'codex', 'opencode', 'gemini'];
|
|
17
|
+
export const CANONICAL_WORKFLOW_CLIS = ['claude', 'codex', 'opencode', 'gemini', 'hermes'];
|
|
18
18
|
export const WORKFLOW_CLI_POLICY_KEY = 'workflow.cli-policy';
|
|
19
19
|
export const DEFAULT_WORKFLOW_CLI_POLICY = {
|
|
20
20
|
default: 'claude',
|
|
@@ -19,7 +19,7 @@ const isBuiltInWorkerRole = (value) => BUILT_IN_WORKER_ROLES.has(value);
|
|
|
19
19
|
const buildModelArgs = (_cli, model) => {
|
|
20
20
|
if (!model?.trim())
|
|
21
21
|
return [];
|
|
22
|
-
/* All
|
|
22
|
+
/* All supported CLIs (claude / codex / opencode / gemini / hermes) accept
|
|
23
23
|
`--model <id>` as a positional flag. Keeping the mapping centralised
|
|
24
24
|
here so future CLI quirks (e.g. opencode wanting `-m` instead) can
|
|
25
25
|
be patched without touching the runner body. */
|
|
@@ -27,13 +27,13 @@ export interface TeamListItem {
|
|
|
27
27
|
status: AgentStatus;
|
|
28
28
|
pendingTaskCount: number;
|
|
29
29
|
/**
|
|
30
|
-
* Last raw line printed to the worker's PTY.
|
|
30
|
+
* Last raw line printed to the worker's PTY. Kept as non-authoritative UI context only —
|
|
31
31
|
* not a worker reply. Real replies arrive as [Hive 系统消息] entries on orchestrator stdin.
|
|
32
32
|
*/
|
|
33
33
|
lastPtyLine?: string;
|
|
34
34
|
/**
|
|
35
35
|
* Built-in command preset this worker was launched with (`claude` / `codex` /
|
|
36
|
-
* `opencode` / `gemini`). Drives the worker card's CLI logo (§6.4). Undefined
|
|
36
|
+
* `opencode` / `gemini` / `hermes`). Drives the worker card's CLI logo (§6.4). Undefined
|
|
37
37
|
* when the worker was created without picking a preset, or when the launch
|
|
38
38
|
* config row references a custom command — in that case the UI falls back to
|
|
39
39
|
* the role-letter avatar.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tt-a1i/hive",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.7.0",
|
|
4
4
|
"description": "Browser-native hive-mind for CLI coding agents — Claude Code, Codex, Gemini, and OpenCode collaborate as real PTY processes via a team protocol.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"packageManager": "pnpm@10.30.3",
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/MarketplaceDrawer-
|
|
2
|
-
import{c as W,j as e,u as j,r as c,e as z,k as M,n as X,A as Y,B as Z,F as R,G as ee,H as te,a as ae,P as re,O as se,C as ne,b as le,D as oe,d as ie,_ as de}from"./index-CAgGM6nb.js";const ce=[["path",{d:"M12 7v6",key:"lw1j43"}],["path",{d:"M15 10H9",key:"o6yqo3"}],["path",{d:"M17 3a2 2 0 0 1 2 2v15a1 1 0 0 1-1.496.868l-4.512-2.578a2 2 0 0 0-1.984 0l-4.512 2.578A1 1 0 0 1 5 20V5a2 2 0 0 1 2-2z",key:"oz39mx"}]],ue=W("bookmark-plus",ce);const xe=[["rect",{width:"12",height:"12",x:"2",y:"10",rx:"2",ry:"2",key:"6agr2n"}],["path",{d:"m17.92 14 3.5-3.5a2.24 2.24 0 0 0 0-3l-5-4.92a2.24 2.24 0 0 0-3 0L10 6",key:"1o487t"}],["path",{d:"M6 18h.01",key:"uhywen"}],["path",{d:"M10 14h.01",key:"ssrbsk"}],["path",{d:"M15 6h.01",key:"cblpky"}],["path",{d:"M18 9h.01",key:"2061c0"}]],me=W("dices",xe);const pe=[["path",{d:"m21 21-4.34-4.34",key:"14j7rj"}],["circle",{cx:"11",cy:"11",r:"8",key:"4ej97u"}]],he=W("search",pe);const fe=[["path",{d:"m7 11 2-2-2-2",key:"1lz0vl"}],["path",{d:"M11 13h4",key:"1p7l4v"}],["rect",{width:"18",height:"18",x:"3",y:"3",rx:"2",ry:"2",key:"1m3agn"}]],be=W("square-terminal",fe);const ge=[["path",{d:"M15 21v-5a1 1 0 0 0-1-1h-4a1 1 0 0 0-1 1v5",key:"slp6dd"}],["path",{d:"M17.774 10.31a1.12 1.12 0 0 0-1.549 0 2.5 2.5 0 0 1-3.451 0 1.12 1.12 0 0 0-1.548 0 2.5 2.5 0 0 1-3.452 0 1.12 1.12 0 0 0-1.549 0 2.5 2.5 0 0 1-3.77-3.248l2.889-4.184A2 2 0 0 1 7 2h10a2 2 0 0 1 1.653.873l2.895 4.192a2.5 2.5 0 0 1-3.774 3.244",key:"o0xfot"}],["path",{d:"M4 10.95V19a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-8.05",key:"wn3emo"}]],ke=W("store",ge),ve=[{value:"coder"},{value:"reviewer"},{value:"tester"},{value:"custom",dashed:!0}],F=t=>`role.${t}`,C=({children:t})=>e.jsx("span",{className:"text-sm font-medium text-sec",children:t}),je=({active:t,spec:a,onSelect:l})=>{const{t:n}=j();return e.jsxs("button",{type:"button",onClick:l,"aria-pressed":t,"data-testid":`role-card-${a.value}`,className:`selectable-card${a.dashed?" selectable-card--dashed":""} flex items-center gap-3 px-3 py-2`,children:[e.jsx(R,{role:a.value,size:20}),e.jsx("span",{className:"flex-1 text-left text-base font-medium text-pri",children:n(F(a.value))}),t?e.jsx(M,{size:14,className:"shrink-0 text-accent","aria-hidden":!0}):null]})},ye=({onRoleChange:t,workerRole:a})=>{const{t:l}=j();return e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsx(C,{children:l("addWorker.role")}),e.jsx("div",{className:"grid grid-cols-2 gap-2",children:ve.map(n=>e.jsx(je,{active:a===n.value,spec:n,onSelect:()=>t(n.value)},n.value))})]})},Ne=({customTemplates:t,disabledReason:a,onDeleteTemplate:l,onSelect:n,selectedTemplateId:i})=>{const{t:o}=j(),[f,x]=c.useState(!1),[m,u]=c.useState(""),[b,k]=c.useState(null),y=c.useRef(null),g=c.useMemo(()=>t.find(r=>r.id===i)??null,[t,i]),v=c.useMemo(()=>{const r=m.trim().toLowerCase();return r?t.filter(s=>s.name.toLowerCase().includes(r)||s.description.toLowerCase().includes(r)):t},[t,m]);return c.useEffect(()=>{if(!f)return;const r=h=>{h.key==="Escape"&&x(!1)},s=h=>{const w=y.current;w&&!w.contains(h.target)&&x(!1)};return document.addEventListener("keydown",r),document.addEventListener("pointerdown",s),()=>{document.removeEventListener("keydown",r),document.removeEventListener("pointerdown",s)}},[f]),e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsx(C,{children:o("addWorker.template")}),e.jsxs("div",{ref:y,className:"relative",children:[e.jsxs("button",{type:"button","aria-haspopup":"listbox","aria-expanded":f,"data-testid":"role-template-picker-trigger",onClick:()=>x(r=>!r),className:"flex w-full items-center justify-between gap-2 rounded border px-3 py-2 text-left text-sm transition-colors hover:bg-3",style:{borderColor:"var(--border)",background:"var(--bg-1)"},children:[e.jsx("span",{className:"min-w-0 flex-1 truncate text-pri",children:g?g.name:o("addWorker.templatePickPlaceholder")}),e.jsx(z,{size:14,className:"shrink-0 text-ter","aria-hidden":!0})]}),f?e.jsxs("div",{role:"listbox","aria-label":o("addWorker.template"),"data-testid":"role-template-picker-menu",className:"elev-2 absolute left-0 right-0 top-full z-30 mt-1 flex max-h-72 flex-col overflow-hidden rounded border",style:{background:"var(--bg-elevated)",borderColor:"var(--border-bright)"},children:[e.jsxs("div",{className:"flex items-center gap-2 border-b px-2 py-1.5",style:{borderColor:"var(--border)"},children:[e.jsx(he,{size:14,className:"text-ter","aria-hidden":!0}),e.jsx("input",{value:m,onChange:r=>u(r.currentTarget.value),placeholder:o("addWorker.templateSearchPlaceholder"),"data-testid":"role-template-search-input",className:"w-full bg-transparent text-sm text-pri outline-none placeholder:text-ter",spellCheck:!1})]}),e.jsx("div",{className:"flex-1 overflow-y-auto py-1",children:t.length===0?e.jsx("div",{"data-testid":"role-template-empty-state",className:"px-3 py-3 text-center text-sm text-ter",children:o("addWorker.templateEmpty")}):v.length===0?e.jsx("div",{className:"px-3 py-3 text-center text-sm text-ter",children:o("addWorker.templateNoMatch")}):v.map(r=>{const s=r.id===i;return e.jsxs("div",{className:"relative",children:[e.jsxs("button",{type:"button",role:"option","aria-selected":s,"data-testid":`role-template-option-${r.id}`,onClick:()=>{n(r.id),x(!1),u("")},className:"flex w-full items-center gap-2 px-3 py-1.5 pr-9 text-left text-sm text-pri hover:bg-3",style:s?{background:"var(--bg-3)"}:void 0,children:[e.jsx("span",{className:"min-w-0 flex-1 truncate",children:r.name}),s?e.jsx(M,{size:14,className:"shrink-0 text-accent","aria-hidden":!0}):null]}),e.jsx("button",{type:"button","aria-label":o("addWorker.templateDeleteAria",{name:r.name}),"data-testid":`role-template-delete-${r.id}`,disabled:!!a,title:a??void 0,onClick:h=>{h.preventDefault(),h.stopPropagation(),!a&&k(r)},className:"absolute right-1 top-1/2 flex h-6 w-6 -translate-y-1/2 items-center justify-center rounded text-ter transition-colors hover:bg-3 hover:text-pri",children:e.jsx(X,{size:14,"aria-hidden":!0})})]},r.id)})}),i!==null?e.jsx("button",{type:"button","data-testid":"role-template-clear",onClick:()=>{n(null),x(!1),u("")},className:"border-t px-3 py-1.5 text-left text-sm text-ter transition-colors hover:bg-3 hover:text-pri",style:{borderColor:"var(--border)"},children:o("addWorker.templateClear")}):null]}):null]}),e.jsx(Y,{open:b!==null,onOpenChange:r=>{r||k(null)},title:o("addWorker.templateDeleteTitle"),description:b?o("addWorker.templateDeleteConfirm",{name:b.name}):"",confirmLabel:o("addWorker.templateDeleteConfirmLabel"),confirmKind:"danger",onConfirm:()=>{if(!b||a)return;const r=b.id;k(null),l(r)}})]})},Ce=({canSaveAsTemplate:t,modified:a,onChange:l,onReset:n,onSaveAsTemplate:i,roleDescription:o,templateBusy:f,workerRole:x,writeDisabledReason:m})=>{const{t:u}=j(),[b,k]=c.useState(!1),[y,g]=c.useState(!1),[v,r]=c.useState("");return c.useEffect(()=>{(x==="custom"||a)&&k(!0)},[a,x]),c.useEffect(()=>{t||(g(!1),r(""))},[t]),e.jsxs("details",{open:b,onToggle:s=>k(s.currentTarget.open),className:"group flex flex-col gap-2",children:[e.jsxs("summary",{className:"flex cursor-pointer select-none items-center justify-between gap-2 list-none",children:[e.jsxs("span",{className:"flex items-center gap-1.5",children:[e.jsx(z,{size:12,"aria-hidden":!0,className:"-rotate-90 text-ter transition-transform duration-150 group-open:rotate-0"}),e.jsx(C,{children:u("addWorker.roleInstructions")}),a?e.jsxs("span",{className:"text-sm text-ter",children:["· ",u("addWorker.modifiedFrom",{role:u(F(x))})]}):null]}),e.jsxs("div",{className:"flex items-center gap-1",children:[t&&!y?e.jsxs("button",{type:"button","data-testid":"role-template-save",disabled:!!m,title:m??void 0,onClick:s=>{s.preventDefault(),s.stopPropagation(),g(!0)},className:"flex items-center gap-1 rounded px-2 py-0.5 text-xs font-medium transition-colors hover:opacity-80 disabled:cursor-not-allowed disabled:opacity-50",style:{color:"var(--accent)",background:"color-mix(in oklab, var(--accent) 14%, transparent)"},children:[e.jsx(ue,{size:12,"aria-hidden":!0}),u("addWorker.saveAsTemplate")]}):null,a?e.jsxs("button",{type:"button",className:"flex items-center gap-1 rounded px-1.5 py-0.5 text-xs text-ter transition-colors hover:bg-3 hover:text-sec",onClick:s=>{s.preventDefault(),s.stopPropagation(),n()},children:[e.jsx(Z,{size:12,"aria-hidden":!0}),u("addWorker.reset")]}):null]})]}),e.jsx("textarea",{"aria-label":"Role instructions",id:"add-worker-role-instructions",value:o,rows:5,onChange:s=>l(s.currentTarget.value),placeholder:x==="custom"?u("addWorker.customPlaceholder"):void 0,title:u("addWorker.roleInstructionsTitle"),className:"input mono resize-y text-sm",style:{minHeight:150},"data-testid":"role-instructions-textarea"}),t&&y?e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("input",{autoFocus:!0,value:v,onChange:s=>r(s.currentTarget.value),placeholder:u("addWorker.templateNamePlaceholder"),"data-testid":"role-template-save-name",className:"input flex-1 text-sm"}),e.jsx("button",{type:"button",disabled:f||!v.trim()||!!m,title:m??void 0,"data-testid":"role-template-save-confirm",onClick:async()=>{if(m)return;const s=v.trim();if(s)try{await i(s),g(!1),r("")}catch{}},className:"icon-btn icon-btn--primary text-xs",children:u("addWorker.templateSaveConfirm")}),e.jsx("button",{type:"button","data-testid":"role-template-save-cancel",onClick:()=>{g(!1),r("")},className:"icon-btn text-xs",children:u("common.cancel")})]}):null]})},D=({active:t,command:a,displayName:l,logoPresetId:n,notFound:i=!1,testId:o,onSelect:f})=>{const{t:x}=j(),m=e.jsx("span",{className:"inline-flex h-5 w-5 shrink-0 items-center justify-center rounded border border-border bg-surface-1 text-ter","data-testid":`${o}-generic-icon`,"aria-hidden":!0,children:e.jsx(be,{size:13})});return e.jsxs("button",{type:"button",onClick:f,"aria-pressed":t,"data-testid":o,className:"selectable-card flex items-center justify-between gap-3 px-3 py-2",children:[e.jsxs("span",{className:"flex min-w-0 items-center gap-3",children:[e.jsx(ee,{commandPresetId:n,fallback:m,size:22}),e.jsxs("span",{className:"flex min-w-0 flex-col items-start gap-0.5",children:[e.jsx("span",{className:"truncate text-base font-medium text-pri",children:l}),e.jsxs("span",{className:"mono truncate text-xs text-ter",children:[a,i?` · ${x("addWorker.agentNotFound")}`:""]})]})]}),t?e.jsx(M,{size:14,className:"shrink-0 text-accent","aria-hidden":!0}):null]})},We=({active:t,preset:a,onSelect:l})=>e.jsx(D,{active:t,command:a.command,displayName:a.displayName,logoPresetId:a.id,notFound:a.available===!1,testId:`agent-radio-${a.id}`,onSelect:l}),we=({commandPresetId:t,commandPresets:a,onPresetChange:l})=>e.jsx(Se,{commandPresetId:t,commandPresets:a,onPresetChange:l}),Se=({commandPresetId:t,commandPresets:a,onPresetChange:l})=>{const{t:n}=j();return e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsx(C,{children:n("addWorker.agentCli")}),a.length===0?e.jsx("div",{className:"text-sm text-ter",children:n("addWorker.loadingPresets")}):e.jsxs("div",{className:"grid grid-cols-2 gap-2",children:[a.map(i=>e.jsx(We,{active:t===i.id,preset:i,onSelect:()=>l(i.id)},i.id)),e.jsx(D,{active:t==="",command:n("addWorker.genericCommand"),displayName:n("addWorker.genericAgent"),testId:"agent-radio-generic",onSelect:()=>l("")})]})]})},ze=({onChange:t,value:a})=>{const{t:l}=j(),n=a.trim();return e.jsxs("details",{className:"group flex flex-col gap-2",children:[e.jsx("summary",{className:"flex cursor-pointer select-none items-center justify-between gap-2 list-none",children:e.jsxs("span",{className:"flex min-w-0 items-center gap-1.5",children:[e.jsx(z,{size:12,"aria-hidden":!0,className:"-rotate-90 shrink-0 text-ter transition-transform duration-150 group-open:rotate-0"}),e.jsx(C,{children:l("addWorker.startupCommand")}),n?e.jsxs("span",{className:"truncate text-sm text-ter",children:["· ",l("addWorker.startupOverrides")]}):null]})}),e.jsxs("div",{className:"flex flex-col gap-2 rounded border bg-2 p-3",style:{borderColor:"var(--border)"},children:[e.jsx("input",{"aria-label":"Startup command",value:a,onChange:i=>t(i.currentTarget.value),placeholder:"qwen --model qwen3-coder",className:"input mono text-sm",spellCheck:!1}),e.jsx("p",{className:"text-sm leading-5 text-ter",children:l("addWorker.startupHelp",{example:"claude --resume <session-id>"})})]})]})},Me=c.lazy(()=>de(()=>import("./MarketplaceDrawer-Bk6cpukn.js"),__vite__mapDeps([0,1,2])).then(t=>({default:t.MarketplaceDrawer}))),_e=({commandPresets:t,commandPresetId:a,creating:l=!1,customTemplates:n,onApplyMarketplaceImport:i,onClose:o,onDeleteTemplate:f,onNameChange:x,onPresetChange:m,onRandomName:u,onRoleDescriptionChange:b,onRoleDescriptionReset:k,onRoleChange:y,onSaveAsTemplate:g,onStartupCommandChange:v,onSubmit:r,onTemplateChange:s,roleDescription:h,roleDescriptionDefault:w,selectedTemplateId:_,startupCommand:P,templateBusy:I,workerName:A,workerRole:S,writeDisabledReason:N})=>{const{t:d}=j(),L=te(),[B,O]=c.useState(!1),[q,H]=c.useState(!1),K=c.useMemo(()=>new Set(n.map(p=>p.name)),[n]),V=p=>{i(p),L.show({kind:"success",message:d("marketplace.imported",{name:p.name})})},G=p=>{p||o()},Q=h!==w,E=t.find(p=>p.id===a),$=P.trim(),J=()=>N||(A.trim()?!a&&!$?d("addWorker.pickCliOrStartup"):E?.available===!1&&!$?d("addWorker.unavailable",{name:E.displayName}):h.trim()?null:d("addWorker.emptyInstructions"):d("addWorker.enterName")),U=p=>{const T=J();if(T){p.preventDefault(),L.show({kind:"warning",message:T});return}r(p)};return e.jsxs(ae,{open:!0,onOpenChange:G,children:[e.jsxs(re,{children:[e.jsx(se,{"data-testid":"add-worker-overlay",className:"app-overlay fixed inset-0 z-40"}),e.jsx("div",{className:"pointer-events-none fixed inset-0 z-50 grid place-items-center p-4",children:e.jsx(ne,{"data-testid":"add-worker-content",className:"dialog-scale-pop elev-2 pointer-events-auto flex max-h-[calc(100vh-32px)] w-[560px] max-w-full flex-col rounded-lg border",style:{background:"var(--bg-elevated)",borderColor:"var(--border-bright)"},children:e.jsxs("form",{onSubmit:U,"aria-label":d("addWorker.title"),className:"flex flex-col",children:[e.jsxs("div",{className:"flex shrink-0 flex-col gap-0.5 border-b px-5 py-4",style:{borderColor:"var(--border)"},children:[e.jsx(le,{className:"text-lg font-semibold text-pri",children:d("addWorker.title")}),e.jsx(oe,{className:"text-sm text-ter",children:d("addWorker.description",{command:"team send"})})]}),e.jsxs("div",{className:"flex flex-col gap-4 overflow-y-auto px-5 py-4",children:[e.jsxs("label",{className:"flex flex-col gap-2",children:[e.jsxs("div",{className:"flex items-baseline justify-between gap-2",children:[e.jsx(C,{children:d("addWorker.name")}),e.jsx(ie,{label:d("addWorker.randomTooltip"),children:e.jsxs("button",{type:"button","aria-label":d("addWorker.randomAria"),className:"flex cursor-pointer items-center gap-1 rounded px-1.5 py-0.5 text-xs text-ter transition-colors hover:bg-3 hover:text-sec",onClick:u,"data-testid":"random-worker-name",children:[e.jsx(me,{size:12,"aria-hidden":!0}),d("addWorker.random")]})})]}),e.jsx("input",{autoFocus:!0,value:A,onChange:p=>x(p.target.value),placeholder:d("addWorker.namePlaceholder"),className:"input"})]}),e.jsx(ye,{workerRole:S,onRoleChange:y}),e.jsxs("button",{type:"button",onClick:()=>{H(!0),O(!0)},"data-testid":"open-marketplace",className:"marketplace-browse-btn flex cursor-pointer items-center gap-2 self-start rounded-md border px-3 py-1.5 text-xs text-sec outline-none transition-colors focus-visible:ring-2",style:{background:"var(--bg-0)",borderColor:"var(--border-bright)","--tw-ring-color":"color-mix(in oklab, var(--accent) 45%, transparent)"},children:[e.jsx(ke,{size:14,"aria-hidden":!0}),d("marketplace.openFromAddWorker")]}),S==="custom"?e.jsx(Ne,{customTemplates:n,disabledReason:N,onDeleteTemplate:f,onSelect:s,selectedTemplateId:_}):null,e.jsx(Ce,{canSaveAsTemplate:S==="custom"&&!_&&h.trim().length>0,modified:Q,onChange:b,onReset:k,onSaveAsTemplate:g,roleDescription:h,templateBusy:I,workerRole:S,writeDisabledReason:N}),e.jsx(we,{commandPresetId:a,commandPresets:t,onPresetChange:m}),e.jsx(ze,{value:P,onChange:v})]}),e.jsxs("div",{className:"flex shrink-0 items-center justify-end gap-2 border-t px-5 py-3",style:{borderColor:"var(--border)",background:"var(--bg-2)"},children:[e.jsx("button",{type:"button",onClick:o,className:"icon-btn","data-testid":"add-worker-cancel",children:d("addWorker.cancel")}),e.jsx("button",{type:"submit",disabled:l||!!N,title:N??void 0,className:"icon-btn icon-btn--primary","data-testid":"add-worker-submit",children:d(l?"addWorker.creating":"addWorker.create")})]})]})})})]}),q?e.jsx(c.Suspense,{fallback:null,children:e.jsx(Me,{open:B,onClose:()=>O(!1),onImport:V,importedNames:K})}):null]})},Ae=Object.freeze(Object.defineProperty({__proto__:null,AddWorkerDialog:_e},Symbol.toStringTag,{value:"Module"}));export{Ae as A,he as S};
|
|
1
|
+
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/MarketplaceDrawer-DeEZ35dN.js","assets/index-CxNL0O-C.js","assets/index-5zh61jMg.css"])))=>i.map(i=>d[i]);
|
|
2
|
+
import{c as W,j as e,u as j,r as c,e as z,k as M,n as X,A as Y,B as Z,F as R,G as ee,H as te,a as ae,P as re,O as se,C as ne,b as le,D as oe,d as ie,_ as de}from"./index-CxNL0O-C.js";const ce=[["path",{d:"M12 7v6",key:"lw1j43"}],["path",{d:"M15 10H9",key:"o6yqo3"}],["path",{d:"M17 3a2 2 0 0 1 2 2v15a1 1 0 0 1-1.496.868l-4.512-2.578a2 2 0 0 0-1.984 0l-4.512 2.578A1 1 0 0 1 5 20V5a2 2 0 0 1 2-2z",key:"oz39mx"}]],ue=W("bookmark-plus",ce);const xe=[["rect",{width:"12",height:"12",x:"2",y:"10",rx:"2",ry:"2",key:"6agr2n"}],["path",{d:"m17.92 14 3.5-3.5a2.24 2.24 0 0 0 0-3l-5-4.92a2.24 2.24 0 0 0-3 0L10 6",key:"1o487t"}],["path",{d:"M6 18h.01",key:"uhywen"}],["path",{d:"M10 14h.01",key:"ssrbsk"}],["path",{d:"M15 6h.01",key:"cblpky"}],["path",{d:"M18 9h.01",key:"2061c0"}]],me=W("dices",xe);const pe=[["path",{d:"m21 21-4.34-4.34",key:"14j7rj"}],["circle",{cx:"11",cy:"11",r:"8",key:"4ej97u"}]],he=W("search",pe);const fe=[["path",{d:"m7 11 2-2-2-2",key:"1lz0vl"}],["path",{d:"M11 13h4",key:"1p7l4v"}],["rect",{width:"18",height:"18",x:"3",y:"3",rx:"2",ry:"2",key:"1m3agn"}]],be=W("square-terminal",fe);const ge=[["path",{d:"M15 21v-5a1 1 0 0 0-1-1h-4a1 1 0 0 0-1 1v5",key:"slp6dd"}],["path",{d:"M17.774 10.31a1.12 1.12 0 0 0-1.549 0 2.5 2.5 0 0 1-3.451 0 1.12 1.12 0 0 0-1.548 0 2.5 2.5 0 0 1-3.452 0 1.12 1.12 0 0 0-1.549 0 2.5 2.5 0 0 1-3.77-3.248l2.889-4.184A2 2 0 0 1 7 2h10a2 2 0 0 1 1.653.873l2.895 4.192a2.5 2.5 0 0 1-3.774 3.244",key:"o0xfot"}],["path",{d:"M4 10.95V19a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-8.05",key:"wn3emo"}]],ke=W("store",ge),ve=[{value:"coder"},{value:"reviewer"},{value:"tester"},{value:"custom",dashed:!0}],F=t=>`role.${t}`,C=({children:t})=>e.jsx("span",{className:"text-sm font-medium text-sec",children:t}),je=({active:t,spec:a,onSelect:l})=>{const{t:n}=j();return e.jsxs("button",{type:"button",onClick:l,"aria-pressed":t,"data-testid":`role-card-${a.value}`,className:`selectable-card${a.dashed?" selectable-card--dashed":""} flex items-center gap-3 px-3 py-2`,children:[e.jsx(R,{role:a.value,size:20}),e.jsx("span",{className:"flex-1 text-left text-base font-medium text-pri",children:n(F(a.value))}),t?e.jsx(M,{size:14,className:"shrink-0 text-accent","aria-hidden":!0}):null]})},ye=({onRoleChange:t,workerRole:a})=>{const{t:l}=j();return e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsx(C,{children:l("addWorker.role")}),e.jsx("div",{className:"grid grid-cols-2 gap-2",children:ve.map(n=>e.jsx(je,{active:a===n.value,spec:n,onSelect:()=>t(n.value)},n.value))})]})},Ne=({customTemplates:t,disabledReason:a,onDeleteTemplate:l,onSelect:n,selectedTemplateId:i})=>{const{t:o}=j(),[f,x]=c.useState(!1),[m,u]=c.useState(""),[b,k]=c.useState(null),y=c.useRef(null),g=c.useMemo(()=>t.find(r=>r.id===i)??null,[t,i]),v=c.useMemo(()=>{const r=m.trim().toLowerCase();return r?t.filter(s=>s.name.toLowerCase().includes(r)||s.description.toLowerCase().includes(r)):t},[t,m]);return c.useEffect(()=>{if(!f)return;const r=h=>{h.key==="Escape"&&x(!1)},s=h=>{const w=y.current;w&&!w.contains(h.target)&&x(!1)};return document.addEventListener("keydown",r),document.addEventListener("pointerdown",s),()=>{document.removeEventListener("keydown",r),document.removeEventListener("pointerdown",s)}},[f]),e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsx(C,{children:o("addWorker.template")}),e.jsxs("div",{ref:y,className:"relative",children:[e.jsxs("button",{type:"button","aria-haspopup":"listbox","aria-expanded":f,"data-testid":"role-template-picker-trigger",onClick:()=>x(r=>!r),className:"flex w-full items-center justify-between gap-2 rounded border px-3 py-2 text-left text-sm transition-colors hover:bg-3",style:{borderColor:"var(--border)",background:"var(--bg-1)"},children:[e.jsx("span",{className:"min-w-0 flex-1 truncate text-pri",children:g?g.name:o("addWorker.templatePickPlaceholder")}),e.jsx(z,{size:14,className:"shrink-0 text-ter","aria-hidden":!0})]}),f?e.jsxs("div",{role:"listbox","aria-label":o("addWorker.template"),"data-testid":"role-template-picker-menu",className:"elev-2 absolute left-0 right-0 top-full z-30 mt-1 flex max-h-72 flex-col overflow-hidden rounded border",style:{background:"var(--bg-elevated)",borderColor:"var(--border-bright)"},children:[e.jsxs("div",{className:"flex items-center gap-2 border-b px-2 py-1.5",style:{borderColor:"var(--border)"},children:[e.jsx(he,{size:14,className:"text-ter","aria-hidden":!0}),e.jsx("input",{value:m,onChange:r=>u(r.currentTarget.value),placeholder:o("addWorker.templateSearchPlaceholder"),"data-testid":"role-template-search-input",className:"w-full bg-transparent text-sm text-pri outline-none placeholder:text-ter",spellCheck:!1})]}),e.jsx("div",{className:"flex-1 overflow-y-auto py-1",children:t.length===0?e.jsx("div",{"data-testid":"role-template-empty-state",className:"px-3 py-3 text-center text-sm text-ter",children:o("addWorker.templateEmpty")}):v.length===0?e.jsx("div",{className:"px-3 py-3 text-center text-sm text-ter",children:o("addWorker.templateNoMatch")}):v.map(r=>{const s=r.id===i;return e.jsxs("div",{className:"relative",children:[e.jsxs("button",{type:"button",role:"option","aria-selected":s,"data-testid":`role-template-option-${r.id}`,onClick:()=>{n(r.id),x(!1),u("")},className:"flex w-full items-center gap-2 px-3 py-1.5 pr-9 text-left text-sm text-pri hover:bg-3",style:s?{background:"var(--bg-3)"}:void 0,children:[e.jsx("span",{className:"min-w-0 flex-1 truncate",children:r.name}),s?e.jsx(M,{size:14,className:"shrink-0 text-accent","aria-hidden":!0}):null]}),e.jsx("button",{type:"button","aria-label":o("addWorker.templateDeleteAria",{name:r.name}),"data-testid":`role-template-delete-${r.id}`,disabled:!!a,title:a??void 0,onClick:h=>{h.preventDefault(),h.stopPropagation(),!a&&k(r)},className:"absolute right-1 top-1/2 flex h-6 w-6 -translate-y-1/2 items-center justify-center rounded text-ter transition-colors hover:bg-3 hover:text-pri",children:e.jsx(X,{size:14,"aria-hidden":!0})})]},r.id)})}),i!==null?e.jsx("button",{type:"button","data-testid":"role-template-clear",onClick:()=>{n(null),x(!1),u("")},className:"border-t px-3 py-1.5 text-left text-sm text-ter transition-colors hover:bg-3 hover:text-pri",style:{borderColor:"var(--border)"},children:o("addWorker.templateClear")}):null]}):null]}),e.jsx(Y,{open:b!==null,onOpenChange:r=>{r||k(null)},title:o("addWorker.templateDeleteTitle"),description:b?o("addWorker.templateDeleteConfirm",{name:b.name}):"",confirmLabel:o("addWorker.templateDeleteConfirmLabel"),confirmKind:"danger",onConfirm:()=>{if(!b||a)return;const r=b.id;k(null),l(r)}})]})},Ce=({canSaveAsTemplate:t,modified:a,onChange:l,onReset:n,onSaveAsTemplate:i,roleDescription:o,templateBusy:f,workerRole:x,writeDisabledReason:m})=>{const{t:u}=j(),[b,k]=c.useState(!1),[y,g]=c.useState(!1),[v,r]=c.useState("");return c.useEffect(()=>{(x==="custom"||a)&&k(!0)},[a,x]),c.useEffect(()=>{t||(g(!1),r(""))},[t]),e.jsxs("details",{open:b,onToggle:s=>k(s.currentTarget.open),className:"group flex flex-col gap-2",children:[e.jsxs("summary",{className:"flex cursor-pointer select-none items-center justify-between gap-2 list-none",children:[e.jsxs("span",{className:"flex items-center gap-1.5",children:[e.jsx(z,{size:12,"aria-hidden":!0,className:"-rotate-90 text-ter transition-transform duration-150 group-open:rotate-0"}),e.jsx(C,{children:u("addWorker.roleInstructions")}),a?e.jsxs("span",{className:"text-sm text-ter",children:["· ",u("addWorker.modifiedFrom",{role:u(F(x))})]}):null]}),e.jsxs("div",{className:"flex items-center gap-1",children:[t&&!y?e.jsxs("button",{type:"button","data-testid":"role-template-save",disabled:!!m,title:m??void 0,onClick:s=>{s.preventDefault(),s.stopPropagation(),g(!0)},className:"flex items-center gap-1 rounded px-2 py-0.5 text-xs font-medium transition-colors hover:opacity-80 disabled:cursor-not-allowed disabled:opacity-50",style:{color:"var(--accent)",background:"color-mix(in oklab, var(--accent) 14%, transparent)"},children:[e.jsx(ue,{size:12,"aria-hidden":!0}),u("addWorker.saveAsTemplate")]}):null,a?e.jsxs("button",{type:"button",className:"flex items-center gap-1 rounded px-1.5 py-0.5 text-xs text-ter transition-colors hover:bg-3 hover:text-sec",onClick:s=>{s.preventDefault(),s.stopPropagation(),n()},children:[e.jsx(Z,{size:12,"aria-hidden":!0}),u("addWorker.reset")]}):null]})]}),e.jsx("textarea",{"aria-label":"Role instructions",id:"add-worker-role-instructions",value:o,rows:5,onChange:s=>l(s.currentTarget.value),placeholder:x==="custom"?u("addWorker.customPlaceholder"):void 0,title:u("addWorker.roleInstructionsTitle"),className:"input mono resize-y text-sm",style:{minHeight:150},"data-testid":"role-instructions-textarea"}),t&&y?e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("input",{autoFocus:!0,value:v,onChange:s=>r(s.currentTarget.value),placeholder:u("addWorker.templateNamePlaceholder"),"data-testid":"role-template-save-name",className:"input flex-1 text-sm"}),e.jsx("button",{type:"button",disabled:f||!v.trim()||!!m,title:m??void 0,"data-testid":"role-template-save-confirm",onClick:async()=>{if(m)return;const s=v.trim();if(s)try{await i(s),g(!1),r("")}catch{}},className:"icon-btn icon-btn--primary text-xs",children:u("addWorker.templateSaveConfirm")}),e.jsx("button",{type:"button","data-testid":"role-template-save-cancel",onClick:()=>{g(!1),r("")},className:"icon-btn text-xs",children:u("common.cancel")})]}):null]})},D=({active:t,command:a,displayName:l,logoPresetId:n,notFound:i=!1,testId:o,onSelect:f})=>{const{t:x}=j(),m=e.jsx("span",{className:"inline-flex h-5 w-5 shrink-0 items-center justify-center rounded border border-border bg-surface-1 text-ter","data-testid":`${o}-generic-icon`,"aria-hidden":!0,children:e.jsx(be,{size:13})});return e.jsxs("button",{type:"button",onClick:f,"aria-pressed":t,"data-testid":o,className:"selectable-card flex items-center justify-between gap-3 px-3 py-2",children:[e.jsxs("span",{className:"flex min-w-0 items-center gap-3",children:[e.jsx(ee,{commandPresetId:n,fallback:m,size:22}),e.jsxs("span",{className:"flex min-w-0 flex-col items-start gap-0.5",children:[e.jsx("span",{className:"truncate text-base font-medium text-pri",children:l}),e.jsxs("span",{className:"mono truncate text-xs text-ter",children:[a,i?` · ${x("addWorker.agentNotFound")}`:""]})]})]}),t?e.jsx(M,{size:14,className:"shrink-0 text-accent","aria-hidden":!0}):null]})},We=({active:t,preset:a,onSelect:l})=>e.jsx(D,{active:t,command:a.command,displayName:a.displayName,logoPresetId:a.id,notFound:a.available===!1,testId:`agent-radio-${a.id}`,onSelect:l}),we=({commandPresetId:t,commandPresets:a,onPresetChange:l})=>e.jsx(Se,{commandPresetId:t,commandPresets:a,onPresetChange:l}),Se=({commandPresetId:t,commandPresets:a,onPresetChange:l})=>{const{t:n}=j();return e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsx(C,{children:n("addWorker.agentCli")}),a.length===0?e.jsx("div",{className:"text-sm text-ter",children:n("addWorker.loadingPresets")}):e.jsxs("div",{className:"grid grid-cols-2 gap-2",children:[a.map(i=>e.jsx(We,{active:t===i.id,preset:i,onSelect:()=>l(i.id)},i.id)),e.jsx(D,{active:t==="",command:n("addWorker.genericCommand"),displayName:n("addWorker.genericAgent"),testId:"agent-radio-generic",onSelect:()=>l("")})]})]})},ze=({onChange:t,value:a})=>{const{t:l}=j(),n=a.trim();return e.jsxs("details",{className:"group flex flex-col gap-2",children:[e.jsx("summary",{className:"flex cursor-pointer select-none items-center justify-between gap-2 list-none",children:e.jsxs("span",{className:"flex min-w-0 items-center gap-1.5",children:[e.jsx(z,{size:12,"aria-hidden":!0,className:"-rotate-90 shrink-0 text-ter transition-transform duration-150 group-open:rotate-0"}),e.jsx(C,{children:l("addWorker.startupCommand")}),n?e.jsxs("span",{className:"truncate text-sm text-ter",children:["· ",l("addWorker.startupOverrides")]}):null]})}),e.jsxs("div",{className:"flex flex-col gap-2 rounded border bg-2 p-3",style:{borderColor:"var(--border)"},children:[e.jsx("input",{"aria-label":"Startup command",value:a,onChange:i=>t(i.currentTarget.value),placeholder:"qwen --model qwen3-coder",className:"input mono text-sm",spellCheck:!1}),e.jsx("p",{className:"text-sm leading-5 text-ter",children:l("addWorker.startupHelp",{example:"claude --resume <session-id>"})})]})]})},Me=c.lazy(()=>de(()=>import("./MarketplaceDrawer-DeEZ35dN.js"),__vite__mapDeps([0,1,2])).then(t=>({default:t.MarketplaceDrawer}))),_e=({commandPresets:t,commandPresetId:a,creating:l=!1,customTemplates:n,onApplyMarketplaceImport:i,onClose:o,onDeleteTemplate:f,onNameChange:x,onPresetChange:m,onRandomName:u,onRoleDescriptionChange:b,onRoleDescriptionReset:k,onRoleChange:y,onSaveAsTemplate:g,onStartupCommandChange:v,onSubmit:r,onTemplateChange:s,roleDescription:h,roleDescriptionDefault:w,selectedTemplateId:_,startupCommand:P,templateBusy:I,workerName:A,workerRole:S,writeDisabledReason:N})=>{const{t:d}=j(),L=te(),[B,O]=c.useState(!1),[q,H]=c.useState(!1),K=c.useMemo(()=>new Set(n.map(p=>p.name)),[n]),V=p=>{i(p),L.show({kind:"success",message:d("marketplace.imported",{name:p.name})})},G=p=>{p||o()},Q=h!==w,E=t.find(p=>p.id===a),$=P.trim(),J=()=>N||(A.trim()?!a&&!$?d("addWorker.pickCliOrStartup"):E?.available===!1&&!$?d("addWorker.unavailable",{name:E.displayName}):h.trim()?null:d("addWorker.emptyInstructions"):d("addWorker.enterName")),U=p=>{const T=J();if(T){p.preventDefault(),L.show({kind:"warning",message:T});return}r(p)};return e.jsxs(ae,{open:!0,onOpenChange:G,children:[e.jsxs(re,{children:[e.jsx(se,{"data-testid":"add-worker-overlay",className:"app-overlay fixed inset-0 z-40"}),e.jsx("div",{className:"pointer-events-none fixed inset-0 z-50 grid place-items-center p-4",children:e.jsx(ne,{"data-testid":"add-worker-content",className:"dialog-scale-pop elev-2 pointer-events-auto flex max-h-[calc(100vh-32px)] w-[560px] max-w-full flex-col rounded-lg border",style:{background:"var(--bg-elevated)",borderColor:"var(--border-bright)"},children:e.jsxs("form",{onSubmit:U,"aria-label":d("addWorker.title"),className:"flex flex-col",children:[e.jsxs("div",{className:"flex shrink-0 flex-col gap-0.5 border-b px-5 py-4",style:{borderColor:"var(--border)"},children:[e.jsx(le,{className:"text-lg font-semibold text-pri",children:d("addWorker.title")}),e.jsx(oe,{className:"text-sm text-ter",children:d("addWorker.description",{command:"team send"})})]}),e.jsxs("div",{className:"flex flex-col gap-4 overflow-y-auto px-5 py-4",children:[e.jsxs("label",{className:"flex flex-col gap-2",children:[e.jsxs("div",{className:"flex items-baseline justify-between gap-2",children:[e.jsx(C,{children:d("addWorker.name")}),e.jsx(ie,{label:d("addWorker.randomTooltip"),children:e.jsxs("button",{type:"button","aria-label":d("addWorker.randomAria"),className:"flex cursor-pointer items-center gap-1 rounded px-1.5 py-0.5 text-xs text-ter transition-colors hover:bg-3 hover:text-sec",onClick:u,"data-testid":"random-worker-name",children:[e.jsx(me,{size:12,"aria-hidden":!0}),d("addWorker.random")]})})]}),e.jsx("input",{autoFocus:!0,value:A,onChange:p=>x(p.target.value),placeholder:d("addWorker.namePlaceholder"),className:"input"})]}),e.jsx(ye,{workerRole:S,onRoleChange:y}),e.jsxs("button",{type:"button",onClick:()=>{H(!0),O(!0)},"data-testid":"open-marketplace",className:"marketplace-browse-btn flex cursor-pointer items-center gap-2 self-start rounded-md border px-3 py-1.5 text-xs text-sec outline-none transition-colors focus-visible:ring-2",style:{background:"var(--bg-0)",borderColor:"var(--border-bright)","--tw-ring-color":"color-mix(in oklab, var(--accent) 45%, transparent)"},children:[e.jsx(ke,{size:14,"aria-hidden":!0}),d("marketplace.openFromAddWorker")]}),S==="custom"?e.jsx(Ne,{customTemplates:n,disabledReason:N,onDeleteTemplate:f,onSelect:s,selectedTemplateId:_}):null,e.jsx(Ce,{canSaveAsTemplate:S==="custom"&&!_&&h.trim().length>0,modified:Q,onChange:b,onReset:k,onSaveAsTemplate:g,roleDescription:h,templateBusy:I,workerRole:S,writeDisabledReason:N}),e.jsx(we,{commandPresetId:a,commandPresets:t,onPresetChange:m}),e.jsx(ze,{value:P,onChange:v})]}),e.jsxs("div",{className:"flex shrink-0 items-center justify-end gap-2 border-t px-5 py-3",style:{borderColor:"var(--border)",background:"var(--bg-2)"},children:[e.jsx("button",{type:"button",onClick:o,className:"icon-btn","data-testid":"add-worker-cancel",children:d("addWorker.cancel")}),e.jsx("button",{type:"submit",disabled:l||!!N,title:N??void 0,className:"icon-btn icon-btn--primary","data-testid":"add-worker-submit",children:d(l?"addWorker.creating":"addWorker.create")})]})]})})})]}),q?e.jsx(c.Suspense,{fallback:null,children:e.jsx(Me,{open:B,onClose:()=>O(!1),onImport:V,importedNames:K})}):null]})},Ae=Object.freeze(Object.defineProperty({__proto__:null,AddWorkerDialog:_e},Symbol.toStringTag,{value:"Module"}));export{Ae as A,he as S};
|