tide-commander 1.64.1 → 1.65.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/dist/assets/{BossLogsModal-B72_7BHt.js → BossLogsModal-U4mcLIP3.js} +1 -1
- package/dist/assets/{BossSpawnModal-I2gd6Haa.js → BossSpawnModal-CiFvgaQ1.js} +1 -1
- package/dist/assets/{ControlsModal-C6N5J1b9.js → ControlsModal-Bz4EQ0ii.js} +1 -1
- package/dist/assets/{DockerLogsModal-Sbka63uD.js → DockerLogsModal-CSMh4uRZ.js} +1 -1
- package/dist/assets/{EmbeddedEditor-CWXIFbqO.js → EmbeddedEditor-ecjZKKkD.js} +1 -1
- package/dist/assets/{GmailOAuthSetup-BD7iFY_z.js → GmailOAuthSetup-pFwSGVxa.js} +1 -1
- package/dist/assets/{GoogleOAuthSetup-BFA7pkjF.js → GoogleOAuthSetup-CPvUA9JE.js} +1 -1
- package/dist/assets/{IframeModal-CSNQoKQp.js → IframeModal-DcTPyjLy.js} +1 -1
- package/dist/assets/{IntegrationsPanel-CxIlAfwM.js → IntegrationsPanel-DHdp8HO-.js} +2 -2
- package/dist/assets/{LogViewerModal-oR_MJdlg.js → LogViewerModal-QWGgGmiP.js} +1 -1
- package/dist/assets/{MonitoringModal-DQgasofL.js → MonitoringModal-C8cfJlg5.js} +1 -1
- package/dist/assets/{PM2LogsModal-BUuealrs.js → PM2LogsModal-uUu_bTeC.js} +1 -1
- package/dist/assets/{RestoreArchivedAreaModal-Cw_fsm0f.js → RestoreArchivedAreaModal-C-Zxn6n6.js} +1 -1
- package/dist/assets/{Scene2DCanvas-Ct8tkxrX.js → Scene2DCanvas-0uRu2G4V.js} +1 -1
- package/dist/assets/{SceneManager-ksMw6QzO.js → SceneManager-xyitf6BI.js} +1 -1
- package/dist/assets/{SkillsPanel-CIKjBsqK.js → SkillsPanel-Bgcx1OI3.js} +1 -1
- package/dist/assets/SpawnModal-CS3BMuY9.js +1 -0
- package/dist/assets/{SubordinateAssignmentModal-fBH0D-n0.js → SubordinateAssignmentModal-DNWrbv9p.js} +1 -1
- package/dist/assets/{TriggerManagerPanel-DQaewpQE.js → TriggerManagerPanel-D-pLDqne.js} +1 -1
- package/dist/assets/{WorkflowEditorPanel-BbQPfsAP.js → WorkflowEditorPanel-Cu7zjFdE.js} +1 -1
- package/dist/assets/{index-IKCoEdSk.js → index-2BVW4z0_.js} +1 -1
- package/dist/assets/{index-B9GgZYql.js → index-CWyxpmuL.js} +1 -1
- package/dist/assets/{index-3YGJoOHV.js → index-CZl-6UH7.js} +1 -1
- package/dist/assets/{index-ecMsTrrV.js → index-DEfCPZTr.js} +3 -3
- package/dist/assets/{index-BVOPPyiD.js → index-DM70jqOd.js} +1 -1
- package/dist/assets/{index-XGJvKAEa.js → index-Dd0cfrn9.js} +1 -1
- package/dist/assets/{index-CqU-Wd9O.js → index-Yy2LrlI7.js} +2 -2
- package/dist/assets/{index-BB5wf97o.js → index-cGfzMto2.js} +1 -1
- package/dist/assets/main-4iQEaD98.css +1 -0
- package/dist/assets/{main-KYv9Wb4s.js → main-BNhrjJHj.js} +82 -82
- package/dist/assets/{web-CTASmenh.js → web-BnX_BsjB.js} +1 -1
- package/dist/assets/{web-BlD_xY8D.js → web-CyBgxhK2.js} +1 -1
- package/dist/index.html +2 -2
- package/dist/src/packages/server/claude/runner.js +9 -6
- package/dist/src/packages/server/claude/session-loader.js +15 -0
- package/dist/src/packages/server/data/builtin-skills/agent-tracking.js +7 -7
- package/dist/src/packages/server/data/builtin-skills/boss-instructions.js +14 -1
- package/dist/src/packages/server/data/builtin-skills/task-label.js +10 -10
- package/dist/src/packages/server/routes/agents.js +39 -0
- package/dist/src/packages/server/services/runtime-command-execution.js +2 -1
- package/dist/src/packages/server/services/runtime-watchdog.js +2 -1
- package/dist/src/packages/server/websocket/handlers/boss-response-handler.js +48 -4
- package/package.json +1 -1
- package/dist/assets/SpawnModal-ClEPoXzz.js +0 -1
- package/dist/assets/main-DpE84tMP.css +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{bI as a}from"./main-BNhrjJHj.js";import{ImpactStyle as i,NotificationType as r}from"./index-Yy2LrlI7.js";import"./vendor-react--Eh9ivFN.js";import"./vendor-three-Chj50gSY.js";class h extends a{constructor(){super(...arguments),this.selectionStarted=!1}async impact(t){const e=this.patternForImpact(t==null?void 0:t.style);this.vibrateWithPattern(e)}async notification(t){const e=this.patternForNotification(t==null?void 0:t.type);this.vibrateWithPattern(e)}async vibrate(t){const e=(t==null?void 0:t.duration)||300;this.vibrateWithPattern([e])}async selectionStart(){this.selectionStarted=!0}async selectionChanged(){this.selectionStarted&&this.vibrateWithPattern([70])}async selectionEnd(){this.selectionStarted=!1}patternForImpact(t=i.Heavy){return t===i.Medium?[43]:t===i.Light?[20]:[61]}patternForNotification(t=r.Success){return t===r.Warning?[30,40,30,50,60]:t===r.Error?[27,45,50]:[35,65,21]}vibrateWithPattern(t){if(navigator.vibrate)navigator.vibrate(t);else throw this.unavailable("Browser does not support the vibrate API")}}export{h as HapticsWeb};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{bI as s}from"./main-BNhrjJHj.js";import"./vendor-react--Eh9ivFN.js";import"./vendor-three-Chj50gSY.js";class l extends s{constructor(){super(...arguments),this.pending=[],this.deliveredNotifications=[],this.hasNotificationSupport=()=>{if(!("Notification"in window)||!Notification.requestPermission)return!1;if(Notification.permission!=="granted")try{new Notification("")}catch(i){if(i instanceof Error&&i.name==="TypeError")return!1}return!0}}async getDeliveredNotifications(){const i=[];for(const t of this.deliveredNotifications){const e={title:t.title,id:parseInt(t.tag),body:t.body};i.push(e)}return{notifications:i}}async removeDeliveredNotifications(i){for(const t of i.notifications){const e=this.deliveredNotifications.find(n=>n.tag===String(t.id));e==null||e.close(),this.deliveredNotifications=this.deliveredNotifications.filter(()=>!e)}}async removeAllDeliveredNotifications(){for(const i of this.deliveredNotifications)i.close();this.deliveredNotifications=[]}async createChannel(){throw this.unimplemented("Not implemented on web.")}async deleteChannel(){throw this.unimplemented("Not implemented on web.")}async listChannels(){throw this.unimplemented("Not implemented on web.")}async schedule(i){if(!this.hasNotificationSupport())throw this.unavailable("Notifications not supported in this browser.");for(const t of i.notifications)this.sendNotification(t);return{notifications:i.notifications.map(t=>({id:t.id}))}}async getPending(){return{notifications:this.pending}}async registerActionTypes(){throw this.unimplemented("Not implemented on web.")}async cancel(i){this.pending=this.pending.filter(t=>!i.notifications.find(e=>e.id===t.id))}async areEnabled(){const{display:i}=await this.checkPermissions();return{value:i==="granted"}}async changeExactNotificationSetting(){throw this.unimplemented("Not implemented on web.")}async checkExactNotificationSetting(){throw this.unimplemented("Not implemented on web.")}async requestPermissions(){if(!this.hasNotificationSupport())throw this.unavailable("Notifications not supported in this browser.");return{display:this.transformNotificationPermission(await Notification.requestPermission())}}async checkPermissions(){if(!this.hasNotificationSupport())throw this.unavailable("Notifications not supported in this browser.");return{display:this.transformNotificationPermission(Notification.permission)}}transformNotificationPermission(i){switch(i){case"granted":return"granted";case"denied":return"denied";default:return"prompt"}}sendPending(){var i;const t=[],e=new Date().getTime();for(const n of this.pending)!((i=n.schedule)===null||i===void 0)&&i.at&&n.schedule.at.getTime()<=e&&(this.buildNotification(n),t.push(n));this.pending=this.pending.filter(n=>!t.find(o=>o===n))}sendNotification(i){var t;if(!((t=i.schedule)===null||t===void 0)&&t.at){const e=i.schedule.at.getTime()-new Date().getTime();this.pending.push(i),setTimeout(()=>{this.sendPending()},e);return}this.buildNotification(i)}buildNotification(i){const t=new Notification(i.title,{body:i.body,tag:String(i.id)});return t.addEventListener("click",this.onClick.bind(this,i),!1),t.addEventListener("show",this.onShow.bind(this,i),!1),t.addEventListener("close",()=>{this.deliveredNotifications=this.deliveredNotifications.filter(()=>!this)},!1),this.deliveredNotifications.push(t),t}onClick(i){const t={actionId:"tap",notification:i};this.notifyListeners("localNotificationActionPerformed",t)}onShow(i){this.notifyListeners("localNotificationReceived",i)}}export{l as LocalNotificationsWeb};
|
package/dist/index.html
CHANGED
|
@@ -22,10 +22,10 @@
|
|
|
22
22
|
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16x16.png" />
|
|
23
23
|
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png" />
|
|
24
24
|
<title>Tide Commander</title>
|
|
25
|
-
<script type="module" crossorigin src="/assets/main-
|
|
25
|
+
<script type="module" crossorigin src="/assets/main-BNhrjJHj.js"></script>
|
|
26
26
|
<link rel="modulepreload" crossorigin href="/assets/vendor-react--Eh9ivFN.js">
|
|
27
27
|
<link rel="modulepreload" crossorigin href="/assets/vendor-three-Chj50gSY.js">
|
|
28
|
-
<link rel="stylesheet" crossorigin href="/assets/main-
|
|
28
|
+
<link rel="stylesheet" crossorigin href="/assets/main-4iQEaD98.css">
|
|
29
29
|
</head>
|
|
30
30
|
<body>
|
|
31
31
|
<div id="app"></div>
|
|
@@ -404,10 +404,11 @@ export class ClaudeRunner {
|
|
|
404
404
|
getActiveProcessCount() {
|
|
405
405
|
return this.activeProcesses.size;
|
|
406
406
|
}
|
|
407
|
-
async stop(agentId) {
|
|
408
|
-
//
|
|
409
|
-
//
|
|
410
|
-
|
|
407
|
+
async stop(agentId, clearQueue = true) {
|
|
408
|
+
// Only clear queued messages on explicit user-initiated stops.
|
|
409
|
+
// Respawns (watchdog, auto-restart) should preserve the queue so
|
|
410
|
+
// messages sent while the agent was processing are not lost.
|
|
411
|
+
if (clearQueue && this.messageQueue.has(agentId)) {
|
|
411
412
|
const count = this.messageQueue.get(agentId).length;
|
|
412
413
|
this.messageQueue.delete(agentId);
|
|
413
414
|
if (count > 0) {
|
|
@@ -416,7 +417,7 @@ export class ClaudeRunner {
|
|
|
416
417
|
}
|
|
417
418
|
await this.lifecycle.stop(agentId);
|
|
418
419
|
}
|
|
419
|
-
async stopAll(killProcesses = true) {
|
|
420
|
+
async stopAll(killProcesses = true, clearQueue = true) {
|
|
420
421
|
if (this.persistTimer) {
|
|
421
422
|
clearInterval(this.persistTimer);
|
|
422
423
|
this.persistTimer = null;
|
|
@@ -425,7 +426,9 @@ export class ClaudeRunner {
|
|
|
425
426
|
clearInterval(this.watchdogTimer);
|
|
426
427
|
this.watchdogTimer = null;
|
|
427
428
|
}
|
|
428
|
-
|
|
429
|
+
if (clearQueue) {
|
|
430
|
+
this.messageQueue.clear();
|
|
431
|
+
}
|
|
429
432
|
await this.lifecycle.stopAll(killProcesses);
|
|
430
433
|
}
|
|
431
434
|
isRunning(agentId) {
|
|
@@ -443,6 +443,21 @@ async function waitForFileStable(filePath, maxWaitMs = 500) {
|
|
|
443
443
|
}
|
|
444
444
|
}
|
|
445
445
|
function parseClaudeEntryMessages(entry, messages, toolUseIdToName) {
|
|
446
|
+
// Messages typed while a turn is in flight are persisted as
|
|
447
|
+
// attachment.queued_command rather than a top-level user entry, so emit
|
|
448
|
+
// them as user messages to keep history chronologically intact.
|
|
449
|
+
if (entry.type === 'attachment' && entry.attachment?.type === 'queued_command') {
|
|
450
|
+
const prompt = entry.attachment.prompt;
|
|
451
|
+
if (typeof prompt === 'string' && prompt.trim()) {
|
|
452
|
+
messages.push({
|
|
453
|
+
type: 'user',
|
|
454
|
+
content: prompt,
|
|
455
|
+
timestamp: entry.timestamp,
|
|
456
|
+
uuid: entry.uuid ?? `${entry.timestamp}-queued-user`,
|
|
457
|
+
});
|
|
458
|
+
}
|
|
459
|
+
return;
|
|
460
|
+
}
|
|
446
461
|
if (entry.type === 'user' && entry.message?.content) {
|
|
447
462
|
if (Array.isArray(entry.message.content)) {
|
|
448
463
|
for (const block of entry.message.content) {
|
|
@@ -6,7 +6,7 @@ export const agentTracking = {
|
|
|
6
6
|
assignedAgentClasses: ['*'],
|
|
7
7
|
content: `# Agent Tracking Status (MANDATORY)
|
|
8
8
|
|
|
9
|
-
**Every turn MUST end with a tracking-status PATCH curl as your final tool call. No exceptions — not for tiny replies, not for questions, not for refusals. Skipping it leaves the user's board stuck on stale \`
|
|
9
|
+
**Every turn MUST end with a tracking-status PATCH curl as your final tool call. No exceptions — not for tiny replies, not for questions, not for refusals. Skipping it leaves the user's board stuck on stale \`thinking\` or \`working\`.**
|
|
10
10
|
|
|
11
11
|
## When to Call
|
|
12
12
|
- After finishing ANY reply (one-word answers included)
|
|
@@ -23,7 +23,7 @@ export const agentTracking = {
|
|
|
23
23
|
\`\`\`
|
|
24
24
|
|
|
25
25
|
## Statuses
|
|
26
|
-
- \`
|
|
26
|
+
- \`thinking\` — the "thinking" state, set AUTOMATICALLY at the start of each turn by the Task Label skill. You normally do NOT set this yourself; the combined opening PATCH (taskLabel + trackingStatus:'thinking') covers it. The UI shows an animated typing-dots indicator while in this state.
|
|
27
27
|
- \`working\` — longer-running work in progress; set this mid-turn if you want to clear the typing-dots indicator before you're fully done (e.g. a long build, a tight loop of edits). Optional.
|
|
28
28
|
- \`need-review\` — finished work awaiting user review (describe what)
|
|
29
29
|
- \`blocked\` — cannot proceed (say WHO/WHAT blocks you)
|
|
@@ -31,18 +31,18 @@ export const agentTracking = {
|
|
|
31
31
|
- \`waiting-subordinates\` — boss agent waiting on delegated work
|
|
32
32
|
|
|
33
33
|
## Status Lifecycle Within a Turn
|
|
34
|
-
1. **Start of turn:** the Task Label skill sets \`
|
|
35
|
-
2. **During the turn:** the \`
|
|
36
|
-
3. **End of turn:** send the final tracking PATCH with the outcome status (\`need-review\`, \`blocked\`, \`can-clear-context\`, or \`waiting-subordinates\`). This replaces \`
|
|
34
|
+
1. **Start of turn:** the Task Label skill sets \`thinking\` (typing dots visible).
|
|
35
|
+
2. **During the turn:** the \`thinking\` state persists until you replace it. You MAY optionally PATCH to \`working\` once you start doing real work (reads/edits/bash) if the turn is long — this swaps typing dots for the cyan working indicator.
|
|
36
|
+
3. **End of turn:** send the final tracking PATCH with the outcome status (\`need-review\`, \`blocked\`, \`can-clear-context\`, or \`waiting-subordinates\`). This replaces \`thinking\`/\`working\` with the final state.
|
|
37
37
|
|
|
38
38
|
## Rules
|
|
39
39
|
- Detail ≤ 80 chars
|
|
40
40
|
- Tracking curl is the VERY LAST tool call — all user-facing text comes BEFORE it, nothing after
|
|
41
41
|
- Don't pick \`can-clear-context\` if anything still needs user confirmation — use \`need-review\`
|
|
42
|
-
- Do NOT manually set \`
|
|
42
|
+
- Do NOT manually set \`thinking\` outside the opening PATCH from the Task Label skill — it's only for turn-start.
|
|
43
43
|
|
|
44
44
|
## Final Check Before Ending a Turn
|
|
45
45
|
1. Have I sent the PATCH this turn? If not — send now.
|
|
46
46
|
2. Is it my last tool call with no output after? If not — fix order.
|
|
47
|
-
3. Have I replaced the opening \`
|
|
47
|
+
3. Have I replaced the opening \`thinking\` status with a meaningful final status? If not — do it now.`,
|
|
48
48
|
};
|
|
@@ -411,8 +411,21 @@ You can ONLY spawn new agents when the user EXPLICITLY requests it.
|
|
|
411
411
|
|
|
412
412
|
### Spawn Block Format (ONLY when user explicitly requests):
|
|
413
413
|
\\\`\\\`\\\`spawn
|
|
414
|
-
[{
|
|
414
|
+
[{
|
|
415
|
+
"name": "<Agent Name>",
|
|
416
|
+
"class": "<agent class slug>",
|
|
417
|
+
"cwd": "<optional working directory>",
|
|
418
|
+
"model": "<optional: claude-opus-4-7 | claude-sonnet-4-6 | claude-haiku-4-5 | etc.>",
|
|
419
|
+
"effort": "<optional: low | medium | high | xHigh | max>",
|
|
420
|
+
"initialSkillIds": ["<optional skill-id-1>", "<skill-id-2>"],
|
|
421
|
+
"provider": "<optional: claude | codex | opencode>",
|
|
422
|
+
"customInstructions": "<optional extra system prompt for this agent>",
|
|
423
|
+
"codexModel": "<optional: only when provider='codex'>",
|
|
424
|
+
"opencodeModel": "<optional: only when provider='opencode'>"
|
|
425
|
+
}]
|
|
415
426
|
\\\`\\\`\\\`
|
|
416
427
|
|
|
428
|
+
**ALL fields except \`name\` and \`class\` are OPTIONAL.** Omit any field to use defaults (provider=claude, default model for the provider, agent class default skills, no custom instructions, cwd=boss's cwd).
|
|
429
|
+
|
|
417
430
|
Valid classes: Any registered agent class in the system, including built-in classes (scout, builder, debugger, architect, warrior, support) and custom classes. Use the class slug (e.g. "growey", "espeon", "charming"). If the user requests a specific class, use that class name exactly as they specify it.`,
|
|
418
431
|
};
|
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
export const taskLabel = {
|
|
2
2
|
slug: 'task-label',
|
|
3
3
|
name: 'Task Label',
|
|
4
|
-
description: 'Generate a brief task label and mark
|
|
4
|
+
description: 'Generate a brief task label and mark thinking status at the start of every turn',
|
|
5
5
|
allowedTools: ['Bash(curl:*)'],
|
|
6
6
|
assignedAgentClasses: ['*'],
|
|
7
|
-
content: `# Task Label +
|
|
7
|
+
content: `# Task Label + Thinking Status (MANDATORY - Execute FIRST)
|
|
8
8
|
|
|
9
|
-
**IMPORTANT: Every new turn begins with a single PATCH that (a) sets a brief task label and (b) flips your tracking status to \`
|
|
9
|
+
**IMPORTANT: Every new turn begins with a single PATCH that (a) sets a brief task label and (b) flips your tracking status to \`thinking\`. This makes the UI show a typing indicator while you plan/think before any real work happens.**
|
|
10
10
|
|
|
11
11
|
## Steps (do this FIRST before anything else):
|
|
12
12
|
1. Read the user's request
|
|
13
13
|
2. Generate a 1-5 word summary of the task (e.g., "Fix auth bug", "Add dark mode", "Refactor API calls", "Update tests")
|
|
14
|
-
3. Call the API to set BOTH your task label AND
|
|
14
|
+
3. Call the API to set BOTH your task label AND thinking status in one PATCH:
|
|
15
15
|
|
|
16
16
|
\`PATCH /api/agents/YOUR_AGENT_ID\`
|
|
17
17
|
|
|
18
18
|
**Body (combined):**
|
|
19
19
|
\`\`\`json
|
|
20
|
-
{"taskLabel":"YOUR 1-5 WORD LABEL","trackingStatus":"
|
|
20
|
+
{"taskLabel":"YOUR 1-5 WORD LABEL","trackingStatus":"thinking","trackingStatusDetail":"Short sentence describing what you're about to do"}
|
|
21
21
|
\`\`\`
|
|
22
22
|
|
|
23
23
|
4. Then proceed with the actual task
|
|
@@ -28,15 +28,15 @@ export const taskLabel = {
|
|
|
28
28
|
- Be specific but concise (e.g., "Fix login redirect" not "Work on stuff")
|
|
29
29
|
- \`trackingStatusDetail\` ≤ 80 chars — a tiny preview of the plan, shown under the typing dots
|
|
30
30
|
|
|
31
|
-
## Why \`
|
|
32
|
-
\`
|
|
31
|
+
## Why \`thinking\`?
|
|
32
|
+
\`thinking\` is the "thinking" status. It renders a typing-dots indicator in the tracking board so the user knows you've received their request and are forming a plan. It will be replaced automatically by your normal end-of-turn tracking PATCH (see the Agent Tracking skill), which sets the final status (\`need-review\`, \`blocked\`, \`can-clear-context\`, etc.).
|
|
33
33
|
|
|
34
34
|
## CRITICAL: Execution Order
|
|
35
35
|
|
|
36
36
|
YOUR VERY FIRST TOOL CALL, before ANY other tool — no Read, no Grep, no Glob, no Bash, no Agent, no TodoWrite, no WebSearch, NOTHING — MUST be the combined PATCH above. This is non-negotiable and has zero exceptions.
|
|
37
37
|
|
|
38
38
|
### Pre-flight checklist (run mentally before your first response):
|
|
39
|
-
- (a) Have I sent the combined taskLabel +
|
|
39
|
+
- (a) Have I sent the combined taskLabel + thinking PATCH yet for this task?
|
|
40
40
|
- (b) If NO — the ONLY acceptable first action is that PATCH curl. Stop. Do that first.
|
|
41
41
|
- (c) If YES — proceed with normal work.
|
|
42
42
|
|
|
@@ -51,7 +51,7 @@ Grep("somePattern") ← VIOLATION
|
|
|
51
51
|
# WRONG: Planning before labeling
|
|
52
52
|
TodoWrite([...]) ← VIOLATION
|
|
53
53
|
|
|
54
|
-
# WRONG: Two separate PATCHes (one for label, one for
|
|
54
|
+
# WRONG: Two separate PATCHes (one for label, one for thinking)
|
|
55
55
|
PATCH taskLabel only → PATCH trackingStatus only ← VIOLATION (combine them)
|
|
56
56
|
|
|
57
57
|
# WRONG: Batching the label PATCH with other tool calls
|
|
@@ -63,7 +63,7 @@ PATCH taskLabel + Grep + Read ← VIOLATION
|
|
|
63
63
|
# First turn: ONLY the combined PATCH, nothing else
|
|
64
64
|
curl -s -X PATCH http://localhost:5174/api/agents/YOUR_AGENT_ID \\
|
|
65
65
|
-H "Content-Type: application/json" -H "X-Auth-Token: abcd" \\
|
|
66
|
-
-d '{"taskLabel":"Fix login redirect","trackingStatus":"
|
|
66
|
+
-d '{"taskLabel":"Fix login redirect","trackingStatus":"thinking","trackingStatusDetail":"Tracing the bad redirect on mobile Safari"}'
|
|
67
67
|
|
|
68
68
|
# Second turn onward: proceed with all actual work (Read, Grep, etc.)
|
|
69
69
|
\`\`\`
|
|
@@ -15,6 +15,7 @@ import { getAllCustomClasses } from '../services/custom-class-service.js';
|
|
|
15
15
|
import { createLogger } from '../utils/logger.js';
|
|
16
16
|
import { buildCustomAgentConfig } from '../websocket/handlers/command-handler.js';
|
|
17
17
|
import { clearDelegation, getBossForSubordinate } from '../websocket/handlers/boss-response-handler.js';
|
|
18
|
+
import { OpencodeBackend } from '../opencode/backend.js';
|
|
18
19
|
import { getSystemPrompt, setSystemPrompt, clearSystemPrompt, isEchoPromptEnabled, setEchoPromptEnabled, getCodexBinaryPath, setCodexBinaryPath, isTmuxModeEnabled, setTmuxModeEnabled } from '../services/system-prompt-service.js';
|
|
19
20
|
const log = createLogger('Routes');
|
|
20
21
|
const router = Router();
|
|
@@ -66,6 +67,44 @@ function runCommandWithTimeout(command, args, timeoutMs, cwd) {
|
|
|
66
67
|
});
|
|
67
68
|
});
|
|
68
69
|
}
|
|
70
|
+
let opencodeModelsCache = null;
|
|
71
|
+
const OPENCODE_MODELS_TTL_MS = 60 * 60 * 1000; // 1 hour
|
|
72
|
+
router.get('/opencode/models', async (req, res) => {
|
|
73
|
+
const refresh = req.query.refresh === 'true' || req.query.refresh === '1';
|
|
74
|
+
const now = Date.now();
|
|
75
|
+
if (!refresh && opencodeModelsCache && now - opencodeModelsCache.fetchedAt < OPENCODE_MODELS_TTL_MS) {
|
|
76
|
+
res.json({
|
|
77
|
+
models: opencodeModelsCache.models,
|
|
78
|
+
source: opencodeModelsCache.source,
|
|
79
|
+
cached: true,
|
|
80
|
+
fetchedAt: opencodeModelsCache.fetchedAt,
|
|
81
|
+
});
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
try {
|
|
85
|
+
const opencodeExe = new OpencodeBackend().getExecutablePath();
|
|
86
|
+
const args = refresh ? ['models', '--refresh'] : ['models'];
|
|
87
|
+
const result = await runCommandWithTimeout(opencodeExe, args, 15000);
|
|
88
|
+
const models = result.output
|
|
89
|
+
.split('\n')
|
|
90
|
+
.map((line) => line.trim())
|
|
91
|
+
.filter((line) => line.length > 0 && line.includes('/'));
|
|
92
|
+
if (models.length === 0) {
|
|
93
|
+
res.status(502).json({
|
|
94
|
+
error: 'opencode CLI returned no models',
|
|
95
|
+
stderr: result.errorOutput || undefined,
|
|
96
|
+
exitCode: result.exitCode,
|
|
97
|
+
});
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
opencodeModelsCache = { models, fetchedAt: now, source: 'cli' };
|
|
101
|
+
res.json({ models, source: 'cli', cached: false, fetchedAt: now });
|
|
102
|
+
}
|
|
103
|
+
catch (err) {
|
|
104
|
+
log.error(' opencode models fetch failed:', err);
|
|
105
|
+
res.status(500).json({ error: err?.message || 'Failed to run opencode CLI' });
|
|
106
|
+
}
|
|
107
|
+
});
|
|
69
108
|
// GET /api/agents/claude-sessions - List all Claude Code sessions
|
|
70
109
|
// NOTE: This must be defined BEFORE /:id routes to prevent being interpreted as an ID
|
|
71
110
|
router.get('/claude-sessions', async (req, res) => {
|
|
@@ -111,7 +111,8 @@ export function createRuntimeCommandExecution(deps) {
|
|
|
111
111
|
}
|
|
112
112
|
else {
|
|
113
113
|
log.log(`[sendCommand] Agent ${agentId} (${agent.provider}): backend does not support stdin, stopping current process to respawn with resume`);
|
|
114
|
-
|
|
114
|
+
// Preserve queued messages — they will be drained after the new process completes its turn
|
|
115
|
+
await runner.stop(agentId, false);
|
|
115
116
|
}
|
|
116
117
|
}
|
|
117
118
|
else if (!processRunning) {
|
|
@@ -41,7 +41,8 @@ export function startStdinWatchdog(options) {
|
|
|
41
41
|
}
|
|
42
42
|
if (runner && !runner.hasRecentActivity(agentId, STDIN_ACTIVITY_TIMEOUT_MS)) {
|
|
43
43
|
log.warn(`[STDIN-WATCHDOG] Agent ${agentId}: No activity after stdin message, respawning process...`);
|
|
44
|
-
|
|
44
|
+
// Preserve queued messages — they will be drained after the respawned process completes its turn
|
|
45
|
+
await runner.stop(agentId, false);
|
|
45
46
|
try {
|
|
46
47
|
await onRespawn(agentId, command, systemPrompt, customAgent);
|
|
47
48
|
log.log(`[STDIN-WATCHDOG] Agent ${agentId}: Successfully respawned process`);
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
* Parses delegation, spawn, work-plan, and analysis-request blocks from boss agent responses
|
|
4
4
|
*/
|
|
5
5
|
import { BUILT_IN_AGENT_CLASSES } from '../../../shared/agent-types.js';
|
|
6
|
-
import { agentService, runtimeService, bossService, workPlanService } from '../../services/index.js';
|
|
7
|
-
import { getAllCustomClasses } from '../../services/custom-class-service.js';
|
|
6
|
+
import { agentService, runtimeService, bossService, workPlanService, skillService } from '../../services/index.js';
|
|
7
|
+
import { getAllCustomClasses, getClassDefaultSkillIds } from '../../services/custom-class-service.js';
|
|
8
8
|
import { logger, getCommanderBaseUrl } from '../../utils/index.js';
|
|
9
9
|
import { getLastBossCommand, buildCustomAgentConfig } from './command-handler.js';
|
|
10
10
|
const log = logger.ws;
|
|
@@ -308,7 +308,7 @@ export async function parseBossSpawn(bossId, bossName, resultText, broadcast, se
|
|
|
308
308
|
const customClassIds = getAllCustomClasses().map(c => c.id);
|
|
309
309
|
const validClasses = [...builtInClassIds, ...customClassIds];
|
|
310
310
|
for (const spawnRequest of spawns) {
|
|
311
|
-
const { name, class: agentClass, cwd } = spawnRequest;
|
|
311
|
+
const { name, class: agentClass, cwd, model, codexModel, opencodeModel, effort, initialSkillIds, provider, customInstructions, codexConfig, permissionMode, } = spawnRequest;
|
|
312
312
|
if (!name || !agentClass) {
|
|
313
313
|
log.error(` Spawn request missing required fields (name, class):`, spawnRequest);
|
|
314
314
|
continue;
|
|
@@ -317,10 +317,54 @@ export async function parseBossSpawn(bossId, bossName, resultText, broadcast, se
|
|
|
317
317
|
log.error(` Invalid agent class "${agentClass}". Must be one of: ${validClasses.join(', ')}`);
|
|
318
318
|
continue;
|
|
319
319
|
}
|
|
320
|
+
let safeProvider;
|
|
321
|
+
if (provider !== undefined) {
|
|
322
|
+
if (provider === 'claude' || provider === 'codex' || provider === 'opencode') {
|
|
323
|
+
safeProvider = provider;
|
|
324
|
+
}
|
|
325
|
+
else {
|
|
326
|
+
log.warn(` Spawn: invalid provider "${provider}" — falling back to default. Allowed: claude, codex, opencode.`);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
let safeEffort;
|
|
330
|
+
if (effort !== undefined) {
|
|
331
|
+
if (effort === 'low' || effort === 'medium' || effort === 'high' || effort === 'xHigh' || effort === 'max') {
|
|
332
|
+
safeEffort = effort;
|
|
333
|
+
}
|
|
334
|
+
else {
|
|
335
|
+
log.warn(` Spawn: invalid effort "${effort}" — ignoring. Allowed: low, medium, high, xHigh, max.`);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
let safeSkillIds;
|
|
339
|
+
if (initialSkillIds !== undefined) {
|
|
340
|
+
if (Array.isArray(initialSkillIds) && initialSkillIds.every(s => typeof s === 'string')) {
|
|
341
|
+
safeSkillIds = initialSkillIds;
|
|
342
|
+
}
|
|
343
|
+
else {
|
|
344
|
+
log.warn(` Spawn: initialSkillIds must be an array of strings — ignoring.`);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
320
347
|
const agentCwd = cwd || bossCwd;
|
|
321
348
|
log.log(` Boss ${bossName} spawning new ${agentClass} agent: "${name}" in ${agentCwd}`);
|
|
322
349
|
try {
|
|
323
|
-
const newAgent = await agentService.createAgent(name, agentClass, agentCwd
|
|
350
|
+
const newAgent = await agentService.createAgent(name, agentClass, agentCwd, undefined, // position
|
|
351
|
+
undefined, // sessionId
|
|
352
|
+
undefined, // useChrome
|
|
353
|
+
permissionMode ?? 'bypass', safeSkillIds, undefined, // isBoss
|
|
354
|
+
model, codexModel, typeof customInstructions === 'string' ? customInstructions : undefined, safeProvider, codexConfig, safeEffort, opencodeModel);
|
|
355
|
+
// Assign initial skills (mirrors agent-handler behavior). Combine
|
|
356
|
+
// explicitly requested skills with the class's default skills.
|
|
357
|
+
const requestedSkills = safeSkillIds ?? [];
|
|
358
|
+
const classDefaultSkills = getClassDefaultSkillIds(newAgent.class);
|
|
359
|
+
const allSkillIds = [...new Set([...requestedSkills, ...classDefaultSkills])];
|
|
360
|
+
for (const skillId of allSkillIds) {
|
|
361
|
+
try {
|
|
362
|
+
skillService.assignSkillToAgent(skillId, newAgent.id);
|
|
363
|
+
}
|
|
364
|
+
catch (skillErr) {
|
|
365
|
+
log.warn(` Failed to assign skill "${skillId}" to ${newAgent.name}: ${skillErr}`);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
324
368
|
const currentSubordinates = bossService.getSubordinates(bossId).map(a => a.id);
|
|
325
369
|
const newSubordinates = [...currentSubordinates, newAgent.id];
|
|
326
370
|
bossService.assignSubordinates(bossId, newSubordinates);
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{u as Ve,$ as Ze,a0 as es,a1 as ss,a2 as as,r as t,a3 as ye,S as ne,a4 as te,A as Ae,l as le,a5 as ns,s as S,h as ts,j as s,a6 as ls,G as De,a7 as x,a8 as os,a9 as oe,I as ie,aa as T,ab as K,ac as ce,ad as is,ae as cs}from"./main-KYv9Wb4s.js";import"./vendor-react--Eh9ivFN.js";import"./vendor-three-Chj50gSY.js";function Ee(r,g){const b=g.filter(C=>!r.has(C));return b.length===0?`${g[Math.floor(Math.random()*g.length)]}-${Date.now()%1e3}`:b[Math.floor(Math.random()*b.length)]}function ms({isOpen:r,onClose:g,onSpawnStart:b,onSpawnEnd:C,spawnPosition:Ie,spawnAreaId:N}){const{t:a}=Ve(["terminal","common"]),P=Ze(),p=es(),re=ss(),H=re.length>0?re:as,[m,v]=t.useState(""),[M,F]=t.useState(()=>ye(ne.LAST_CWD)),[i,k]=t.useState("scout"),[de,E]=t.useState(!1),[Le,R]=t.useState(!1),[pe,J]=t.useState(!1),[me,ue]=t.useState(""),[y,Y]=t.useState([]),[A,U]=t.useState(null),[_e,he]=t.useState(!1),[I,we]=t.useState(""),[h,$e]=t.useState(""),[z,Te]=t.useState(!1),[q,Pe]=t.useState("bypass"),[o,X]=t.useState("claude"),[j,L]=t.useState({fullAuto:!0,sandbox:"workspace-write",approvalMode:"on-request",search:!1}),[xe,Q]=t.useState(new Set),[V,fe]=t.useState("opus[1m]"),[Z,ge]=t.useState("xHigh"),[ee,Fe]=t.useState("gpt-5.3-codex"),[se,Re]=t.useState("minimax/MiniMax-M1-80k"),[je,Ue]=t.useState(""),[D,ze]=t.useState(""),O=t.useRef(null),Ne=t.useRef(!1),_=t.useCallback(()=>{window.__spawnModalAreaContext=null},[]),w=t.useMemo(()=>P.filter(e=>e.enabled),[P]),qe=["full-notifications","streaming-exec","task-label","report-task-to-boss","agent-tracking","send-message-to-agent"];t.useEffect(()=>{if(r&&!Ne.current){if(w.length>0){const l=w.filter(c=>qe.includes(c.slug)).map(c=>c.id);l.length>0&&Q(new Set(l))}const n=ye(ne.DEFAULT_AGENT_CLASS);if(n==="random"){const c=[...Object.keys(is),...p.map(u=>u.id)];k(c[Math.floor(Math.random()*c.length)])}else k(n||"scout")}Ne.current=r},[r,w,p]);const ve=t.useMemo(()=>{if(!D.trim())return w;const e=D.toLowerCase();return w.filter(n=>n.name.toLowerCase().includes(e)||n.description.toLowerCase().includes(e)||n.slug.toLowerCase().includes(e))},[w,D]),Oe=t.useCallback(e=>{Q(n=>{const l=new Set(n);return l.has(e)?l.delete(e):l.add(e),l})},[]);t.useMemo(()=>w.filter(e=>e.assignedAgentClasses.includes(i)),[w,i]);const We=t.useMemo(()=>{var n;const e=p.find(l=>l.id===i);return(n=e==null?void 0:e.defaultSkillIds)!=null&&n.length?P.filter(l=>e.defaultSkillIds.includes(l.id)):[]},[p,i,P]),Se=t.useMemo(()=>{if(!I.trim())return y;const e=I.toLowerCase();return y.filter(n=>n.sessionId.toLowerCase().includes(e)||n.projectPath.toLowerCase().includes(e)||n.firstMessage&&n.firstMessage.toLowerCase().includes(e))},[y,I]),W=t.useMemo(()=>{if(!h.trim())return p;const e=h.toLowerCase();return p.filter(n=>n.name.toLowerCase().includes(e)||n.description.toLowerCase().includes(e)||n.id.toLowerCase().includes(e))},[p,h]),G=t.useMemo(()=>{if(!h.trim())return te;const e=h.toLowerCase();return te.filter(n=>{const l=Ae[n.id];return n.name.toLowerCase().includes(e)||n.id.toLowerCase().includes(e)||l.description.toLowerCase().includes(e)})},[h]);t.useEffect(()=>{if(!r||!h.trim())return;const e=[...W.map(n=>n.id),...G.map(n=>n.id)];e.length===1&&e[0]!==i&&k(e[0])},[r,h,W,G,i]);const d=t.useMemo(()=>p.find(e=>e.id===i),[p,i]),Ge=t.useMemo(()=>{if(d!=null&&d.model)return d.model},[d]),Be=t.useMemo(()=>{if(d!=null&&d.customModelPath)return le(`/api/custom-models/${d.id}`)},[d]),Ke=d==null?void 0:d.modelScale,He=t.useMemo(()=>d?"scout":i,[i,d]),B=t.useCallback(async e=>{he(!0);try{const n=e?le(`/api/agents/claude-sessions?cwd=${encodeURIComponent(e)}`):le("/api/agents/claude-sessions"),c=await(await ns(n)).json();Y(c.sessions||[])}catch(n){console.error("Failed to fetch sessions:",n),Y([])}finally{he(!1)}},[]);t.useEffect(()=>{r?B(M||void 0):(Y([]),U(null),we(""))},[r,B]),t.useEffect(()=>{if(!r)return;const e=setTimeout(()=>{B(M||void 0),U(null)},300);return()=>clearTimeout(e)},[M,r,B]),t.useEffect(()=>{if(!r||!N)return;const e=S.getState().areas.get(N);if(e!=null&&e.directories&&e.directories.length>0){F(e.directories[0]);return}const n=Array.from(S.getState().agents.values()).filter(f=>{var $;return(($=S.getAreaForAgent(f.id))==null?void 0:$.id)===N&&f.cwd});if(n.length===0)return;const l=new Map;for(const f of n)l.set(f.cwd,(l.get(f.cwd)||0)+1);let c="",u=0;for(const[f,$]of l)$>u&&(c=f,u=$);c&&F(c)},[r,N]),t.useEffect(()=>{if(r){const e=new Set(Array.from(S.getState().agents.values()).map(u=>u.name)),n=Ee(e,H),l=p.find(u=>u.id===i),c=l?`${l.name} ${n}`:n;v(c),O.current&&(O.current.focus(),O.current.select())}},[r,H]),t.useEffect(()=>{if(!r)return;const e=p.find(n=>n.id===i);if(e){const n=p.find(l=>m.startsWith(l.name+" "));if(n){const l=m.substring(n.name.length+1);v(`${e.name} ${l}`)}else v(`${e.name} ${m}`)}else{const n=p.find(l=>m.startsWith(l.name+" "));if(n){const l=m.substring(n.name.length+1);v(l)}}},[i]),t.useEffect(()=>{i==="boss"&&fe("claude-opus-4-7")},[i]);const Je=()=>{var c;console.log("[SpawnModal] handleSpawn called"),R(!1);const e=A&&((c=y.find(u=>u.sessionId===A))==null?void 0:c.projectPath)||M;if(console.log("[SpawnModal] Effective CWD:",e),console.log("[SpawnModal] Agent name:",m),console.log("[SpawnModal] Agent class:",i),console.log("[SpawnModal] Permission mode:",q),console.log("[SpawnModal] Provider:",o),console.log("[SpawnModal] Use Chrome:",z),console.log("[SpawnModal] Session ID:",A||"none"),!e.trim()){console.error("[SpawnModal] Empty CWD, showing error"),R(!0);return}if(!m.trim()){console.log("[SpawnModal] Empty name, regenerating");const u=new Set(Array.from(S.getState().agents.values()).map(f=>f.name));v(Ee(u,H));return}cs(ne.LAST_CWD,e),E(!0),b();const n=Array.from(xe),l=je.trim()||void 0;console.log("[SpawnModal] Calling store.spawnAgent with:",{name:m.trim(),class:i,cwd:e.trim(),sessionId:A||void 0,useChrome:o==="claude"?z:!1,permissionMode:q,provider:o,codexConfig:o==="codex"?j:void 0,codexModel:o==="codex"?ee:void 0,opencodeModel:o==="opencode"?se:void 0,initialSkillIds:n,model:o==="claude"?V:void 0,customInstructions:l?`${l.length} chars`:void 0,spawnAreaId:N||void 0}),window.__spawnModalAreaContext=N?{areaId:N}:null,S.spawnAgent(m.trim(),i,e.trim(),Ie||void 0,A||void 0,o==="claude"?z:!1,q,n,o,o==="codex"?j:void 0,o==="codex"?ee:void 0,o==="claude"?V:void 0,l,o==="claude"?Z:void 0,o==="opencode"?se:void 0)},be=()=>{console.log("[SpawnModal] Agent creation successful"),E(!1),v(""),Q(new Set),_(),C(),g()},Ce=()=>{console.error("[SpawnModal] Agent creation failed"),E(!1),R(!0),_(),C()},Me=e=>{console.log("[SpawnModal] Directory not found:",e),E(!1),ue(e),J(!0),C()},ke=()=>{J(!1),E(!0),b(),S.createDirectoryAndSpawn(me,m.trim(),i)},ae=()=>{J(!1),ue(""),_()};t.useEffect(()=>(window.__spawnModalSuccess=be,window.__spawnModalError=Ce,window.__spawnModalDirNotFound=Me,()=>{_(),delete window.__spawnModalSuccess,delete window.__spawnModalError,delete window.__spawnModalDirNotFound}),[m,i,be,Ce,Me,_]);const{handleMouseDown:Ye,handleClick:Xe}=ts(g),Qe=e=>{e.key==="Escape"&&g()};return!r&&!pe?null:pe?s.jsx("div",{className:"modal-overlay visible",onClick:ae,onKeyDown:e=>{e.key==="Escape"&&ae(),e.key==="Enter"&&ke()},children:s.jsxs("div",{className:"modal confirm-modal",onClick:e=>e.stopPropagation(),children:[s.jsx("div",{className:"modal-header",children:a("terminal:spawn.directoryNotFound")}),s.jsxs("div",{className:"modal-body confirm-modal-body",children:[s.jsx("p",{children:a("terminal:spawn.directoryNotExist")}),s.jsx("code",{className:"confirm-modal-path",children:me}),s.jsx("p",{children:a("terminal:spawn.wouldYouCreate")})]}),s.jsxs("div",{className:"modal-footer",children:[s.jsx("button",{className:"btn btn-secondary",onClick:ae,children:a("common:buttons.cancel")}),s.jsx("button",{className:"btn btn-primary",onClick:ke,autoFocus:!0,children:a("terminal:spawn.createDirectory")})]})]})}):s.jsx("div",{className:`modal-overlay ${r?"visible":""}`,onMouseDown:Ye,onClick:Xe,onKeyDown:Qe,children:s.jsxs("div",{className:"modal spawn-modal",children:[s.jsx("div",{className:"modal-header",children:a("terminal:spawn.deployTitle")}),s.jsxs("div",{className:"modal-body spawn-modal-body",children:[s.jsxs("div",{className:"spawn-top-section",children:[s.jsx("div",{className:"spawn-preview-compact",children:s.jsx(ls,{agentClass:He,modelFile:Ge,customModelUrl:Be,modelScale:Ke,width:100,height:120})}),s.jsxs("div",{className:"spawn-class-section",children:[s.jsx("div",{className:"spawn-class-label",children:a("terminal:spawn.agentClass")}),p.length+te.length>6&&s.jsx("input",{type:"text",className:"spawn-input class-search-input",placeholder:a("terminal:spawn.filterClasses"),value:h,onChange:e=>$e(e.target.value)}),s.jsxs("div",{className:"class-selector-inline",children:[W.map(e=>s.jsxs("button",{className:`class-chip ${i===e.id?"selected":""}`,onClick:()=>k(e.id),title:e.description,children:[s.jsx(De,{classId:e.id,size:18,className:"class-chip-icon"}),s.jsx("span",{className:"class-chip-name",children:e.name})]},e.id)),G.map(e=>{const n=Ae[e.id];return s.jsxs("button",{className:`class-chip ${i===e.id?"selected":""}`,onClick:()=>k(e.id),title:n.description,children:[s.jsx(De,{classId:e.id,size:18,className:"class-chip-icon"}),s.jsx("span",{className:"class-chip-name",children:e.name})]},e.id)}),h&&W.length===0&&G.length===0&&s.jsx("div",{className:"class-search-empty",children:a("terminal:spawn.noClassesMatch",{query:h})})]})]})]}),s.jsxs("div",{className:"spawn-form-section",children:[s.jsxs("div",{className:"spawn-form-row",children:[s.jsxs("div",{className:"spawn-field",children:[s.jsx("label",{className:"spawn-label",children:a("common:labels.name")}),s.jsx("input",{ref:O,type:"text",className:"spawn-input",placeholder:a("terminal:spawn.agentNamePlaceholder"),value:m,onChange:e=>v(e.target.value)})]}),s.jsxs("div",{className:"spawn-field spawn-field-wide",children:[s.jsxs("label",{className:"spawn-label",children:[a("terminal:spawn.workingDir"),s.jsx(x,{text:a("terminal:spawn.helpWorkingDir"),title:a("terminal:spawn.workingDir"),position:"top",size:"sm"})]}),s.jsx(os,{value:M,onChange:e=>{F(e),R(!1)},placeholder:a("terminal:spawn.workingDirPlaceholder"),className:`spawn-input ${Le?"error":""}`,directoriesOnly:!0})]})]}),s.jsxs("div",{className:"spawn-form-row",children:[s.jsxs("div",{className:"spawn-field",children:[s.jsxs("label",{className:"spawn-label",children:[a("terminal:spawn.selectRuntime"),s.jsx(x,{text:a("terminal:spawn.helpRuntime"),title:a("terminal:spawn.runtimeTitle"),position:"top",size:"sm"})]}),s.jsxs("div",{className:"spawn-select-row",children:[s.jsxs("button",{className:`spawn-select-btn ${o==="claude"?"selected":""}`,onClick:()=>X("claude"),title:a("terminal:spawn.useClaudeCli"),children:[s.jsx("img",{src:"/assets/claude.ico",alt:"Claude",className:"spawn-provider-icon"}),s.jsx("span",{children:"Claude"})]}),s.jsxs("button",{className:`spawn-select-btn ${o==="codex"?"selected":""}`,onClick:()=>X("codex"),title:a("terminal:spawn.useCodexCli"),children:[s.jsx("img",{src:"/assets/codex.ico",alt:"Codex",className:"spawn-provider-icon"}),s.jsx("span",{children:"Codex"})]}),s.jsxs("button",{className:`spawn-select-btn spawn-select-btn--opencode ${o==="opencode"?"selected":""}`,onClick:()=>X("opencode"),title:"Use OpenCode CLI (multi-provider)",children:[s.jsx("img",{src:"/assets/opencode.svg",alt:"OpenCode",className:"spawn-provider-icon"}),s.jsx("span",{children:"OpenCode"})]})]})]}),s.jsxs("div",{className:"spawn-field",children:[s.jsxs("label",{className:"spawn-label",children:[a("common:labels.permissions"),s.jsx(x,{text:a("terminal:spawn.helpPermission"),title:a("terminal:spawn.permissionMode"),position:"top",size:"sm"})]}),s.jsx("div",{className:"spawn-select-row",children:Object.keys(oe).map(e=>s.jsxs("button",{className:`spawn-select-btn ${q===e?"selected":""}`,onClick:()=>Pe(e),title:oe[e].description,children:[s.jsx("span",{children:s.jsx(ie,{name:e==="bypass"?"bolt":"lock",size:12})}),s.jsx("span",{children:oe[e].label})]},e))})]})]}),s.jsx("div",{className:"spawn-form-row",children:s.jsxs("div",{className:"spawn-field",children:[s.jsxs("label",{className:"spawn-label",children:[a("common:labels.model"),s.jsx(x,{text:a("terminal:spawn.helpModel"),title:a("terminal:spawn.modelTitle"),position:"top",size:"sm"})]}),o==="claude"?s.jsx("div",{className:"spawn-select-row spawn-select-row--wrap",children:Object.keys(T).filter(e=>!T[e].deprecated).map(e=>s.jsxs("button",{className:`spawn-select-btn ${V===e?"selected":""}`,onClick:()=>fe(e),title:T[e].description,children:[s.jsx("span",{children:T[e].icon}),s.jsx("span",{children:T[e].label})]},e))}):o==="codex"?s.jsx("div",{className:"spawn-select-row spawn-select-row--codex-models",children:Object.keys(K).map(e=>s.jsxs("button",{className:`spawn-select-btn ${ee===e?"selected":""}`,onClick:()=>Fe(e),title:K[e].description,children:[s.jsx("span",{children:K[e].icon}),s.jsx("span",{children:K[e].label})]},e))}):o==="opencode"?s.jsx("input",{type:"text",className:"spawn-input",value:se,onChange:e=>Re(e.target.value),placeholder:"provider/model (e.g., minimax/MiniMax-M1-80k)"}):s.jsx("div",{className:"spawn-inline-hint",children:a("terminal:spawn.chooseCodexModel")})]})}),s.jsxs("div",{className:"spawn-form-row",children:[o==="claude"&&s.jsxs("div",{className:"spawn-field",children:[s.jsx("label",{className:"spawn-label",children:"Effort"}),s.jsxs("div",{className:"spawn-select-row spawn-select-row--effort",children:[s.jsx("button",{className:`spawn-select-btn spawn-select-btn--compact ${Z===void 0?"selected":""}`,onClick:()=>ge(void 0),title:"Use default effort level",children:s.jsx("span",{children:"Default"})}),Object.keys(ce).map(e=>s.jsx("button",{className:`spawn-select-btn spawn-select-btn--compact ${Z===e?"selected":""}`,onClick:()=>ge(e),title:ce[e].description,children:s.jsx("span",{children:ce[e].label})},e))]})]}),s.jsxs("div",{className:"spawn-field",children:[s.jsx("label",{className:"spawn-label",children:a("terminal:spawn.browser")}),s.jsxs("label",{className:"spawn-checkbox",children:[s.jsx("input",{type:"checkbox",checked:z,onChange:e=>Te(e.target.checked),disabled:o!=="claude"}),s.jsxs("span",{children:[s.jsx(ie,{name:"globe",size:12})," ",a("terminal:spawn.chromeBrowser")]}),s.jsx(x,{text:a(o==="claude"?"terminal:spawn.helpChrome":"terminal:spawn.helpChromeDisabled"),title:a("terminal:spawn.chromeBrowser"),position:"top",size:"sm"})]})]})]}),o==="codex"&&s.jsxs("div",{className:"codex-config-section",children:[s.jsx("div",{className:"codex-config-title",children:a("terminal:spawn.codex.configuration")}),s.jsxs("div",{className:"codex-config-options",children:[s.jsxs("div",{className:"codex-option-group",children:[s.jsxs("label",{className:"spawn-checkbox",children:[s.jsx("input",{type:"checkbox",checked:j.fullAuto!==!1,onChange:e=>L(n=>({...n,fullAuto:e.target.checked}))}),s.jsx("span",{children:a("terminal:spawn.codex.fullAuto")}),s.jsx(x,{text:a("terminal:spawn.helpFullAuto"),title:a("terminal:spawn.fullAutoTitle"),position:"top",size:"sm"})]}),s.jsxs("label",{className:"spawn-checkbox",children:[s.jsx("input",{type:"checkbox",checked:!!j.search,onChange:e=>L(n=>({...n,search:e.target.checked}))}),s.jsx("span",{children:a("terminal:spawn.codex.search")}),s.jsx(x,{text:a("terminal:spawn.helpSearch"),title:a("terminal:spawn.searchTitle"),position:"top",size:"sm"})]})]}),j.fullAuto===!1&&s.jsxs("div",{className:"codex-option-group",children:[s.jsx("div",{className:"codex-option-header",children:a("terminal:spawn.codex.restrictions")}),s.jsxs("select",{className:"spawn-input codex-select",value:j.sandbox||"workspace-write",onChange:e=>L(n=>({...n,sandbox:e.target.value})),children:[s.jsxs("option",{value:"read-only",children:["📖 ",a("terminal:spawn.codex.sandboxReadOnly")]}),s.jsxs("option",{value:"workspace-write",children:["✏️ ",a("terminal:spawn.codex.sandboxWorkspaceWrite")]}),s.jsxs("option",{value:"danger-full-access",children:["⚡ ",a("terminal:spawn.codex.sandboxDangerFullAccess")]})]}),s.jsxs("select",{className:"spawn-input codex-select",value:j.approvalMode||"on-request",onChange:e=>L(n=>({...n,approvalMode:e.target.value})),children:[s.jsxs("option",{value:"untrusted",children:["🔒 ",a("terminal:spawn.codex.approvalsUntrusted")]}),s.jsxs("option",{value:"on-failure",children:["⚠️ ",a("terminal:spawn.codex.approvalsOnFailure")]}),s.jsxs("option",{value:"on-request",children:["🤔 ",a("terminal:spawn.codex.approvalsOnRequest")]}),s.jsxs("option",{value:"never",children:["✅ ",a("terminal:spawn.codex.approvalsNever")]})]})]}),s.jsxs("div",{className:"codex-option-group",children:[s.jsx("div",{className:"codex-option-header",children:a("terminal:spawn.codex.profile")}),s.jsx("input",{type:"text",className:"spawn-input codex-profile-input",placeholder:a("terminal:spawn.codex.profilePlaceholder"),value:j.profile||"",onChange:e=>L(n=>({...n,profile:e.target.value||void 0}))})]})]})]}),w.length>0&&s.jsxs("div",{className:"spawn-skills-section",children:[s.jsxs("label",{className:"spawn-label",children:[a("terminal:spawn.skills")," ",s.jsxs("span",{className:"spawn-label-hint",children:["(",a("common:labels.optional"),")"]}),s.jsx(x,{text:a("terminal:spawn.helpSkills"),title:a("terminal:spawn.skillsTitle"),position:"top",size:"sm"})]}),w.length>6&&s.jsx("input",{type:"text",className:"spawn-input skill-search-input",placeholder:a("terminal:spawn.filterSkills"),value:D,onChange:e=>ze(e.target.value)}),s.jsxs("div",{className:"spawn-skills-inline",children:[ve.map(e=>{const n=xe.has(e.id);return We.some(c=>c.id===e.id)?null:s.jsxs("button",{className:`spawn-skill-chip ${n?"selected":""}`,onClick:()=>Oe(e.id),title:e.description,children:[n&&s.jsx("span",{className:"spawn-skill-check",children:s.jsx(ie,{name:"check",size:10})}),s.jsx("span",{children:e.name}),e.builtin&&s.jsx("span",{className:"spawn-skill-builtin",children:"TC"})]},e.id)}),D&&ve.length===0&&s.jsx("div",{className:"skill-search-empty",children:a("terminal:spawn.noSkillsMatch",{query:D})})]})]}),s.jsxs("div",{className:"spawn-custom-instructions-section",children:[s.jsxs("label",{className:"spawn-label",children:[a("terminal:spawn.customInstructions")," ",s.jsxs("span",{className:"spawn-label-hint",children:["(",a("common:labels.optional"),")"]}),s.jsx(x,{text:a("terminal:spawn.helpCustomInstructions"),title:a("terminal:spawn.customInstructions"),position:"top",size:"sm"})]}),s.jsx("textarea",{className:"spawn-input spawn-textarea",placeholder:a("terminal:spawn.customInstructionsPlaceholder"),value:je,onChange:e=>Ue(e.target.value),rows:3})]}),s.jsxs("div",{className:"spawn-sessions-section",children:[s.jsxs("label",{className:"spawn-label",children:[a("terminal:spawn.linkSession")," ",s.jsxs("span",{className:"spawn-label-hint",children:["(",a("common:labels.optional"),")"]}),s.jsx(x,{text:a("terminal:spawn.helpLinkSession"),title:a("terminal:spawn.linkSessionTitle"),position:"top",size:"sm"})]}),y.length>0&&s.jsx("input",{type:"text",className:"spawn-input session-search-input",placeholder:a("terminal:spawn.searchSessions"),value:I,onChange:e=>we(e.target.value)}),s.jsx("div",{className:"sessions-list",children:_e?s.jsx("div",{className:"sessions-loading",children:a("terminal:spawn.loadingSessions")}):y.length===0?s.jsx("div",{className:"sessions-empty",children:a("terminal:spawn.noSessions")}):Se.length===0?s.jsx("div",{className:"sessions-empty",children:a("terminal:spawn.noSessionsMatch",{query:I})}):Se.map(e=>{const n=A===e.sessionId,l=Date.now()-new Date(e.lastModified).getTime(),c=l<6e4?a("common:time.justNow"):l<36e5?a("common:time.minutesAgo",{count:Math.floor(l/6e4)}):l<864e5?a("common:time.hoursAgo",{count:Math.floor(l/36e5)}):a("common:time.daysAgo",{count:Math.floor(l/864e5)});return s.jsxs("div",{className:`session-item ${n?"selected":""}`,onClick:()=>{n?U(null):(U(e.sessionId),F(e.projectPath))},children:[s.jsxs("div",{className:"session-item-header",children:[s.jsx("span",{className:"session-item-path",children:e.projectPath}),s.jsx("span",{className:"session-item-age",children:c})]}),s.jsx("div",{className:"session-item-preview",children:e.firstMessage||a("terminal:spawn.messagesCount",{count:e.messageCount})})]},e.sessionId)})})]})]})]}),s.jsxs("div",{className:"modal-footer",children:[s.jsx("button",{className:"btn btn-secondary",onClick:g,children:a("common:buttons.cancel")}),s.jsx("button",{className:"btn btn-primary",onClick:Je,disabled:de,children:a(de?"common:buttons.deploying":"common:buttons2.deploy")})]})]})})}export{ms as SpawnModal};
|