heyio 1.7.3 → 1.8.1
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/config.js +11 -2
- package/dist/copilot/agents.js +25 -15
- package/dist/copilot/specialist-runner.js +187 -0
- package/dist/copilot/squad-tools.js +89 -0
- package/dist/daemon.js +7 -1
- package/package.json +1 -1
- package/web-dist/assets/{AuditLogView-CQ0_fNNC.js → AuditLogView-DLCa71tX.js} +1 -1
- package/web-dist/assets/{ChatView-CMrGek2t.js → ChatView-C0O6zQs2.js} +1 -1
- package/web-dist/assets/{FeedView-CLT5n92b.js → FeedView-Dt45CAAc.js} +1 -1
- package/web-dist/assets/{HistoryView-ChVrABKZ.js → HistoryView-CwEb-6As.js} +1 -1
- package/web-dist/assets/{LoginView-BpyPueAJ.js → LoginView-CayeYaG7.js} +1 -1
- package/web-dist/assets/{McpView-NESAwdjb.js → McpView-psdsP_9e.js} +1 -1
- package/web-dist/assets/{SchedulesView-D2d4EW4s.js → SchedulesView-D7yxie2r.js} +1 -1
- package/web-dist/assets/{SettingsView-qrLa06kS.js → SettingsView-Dj0vNjoS.js} +1 -1
- package/web-dist/assets/{SkillsView-lRD1oRGj.js → SkillsView-Bviae2q4.js} +1 -1
- package/web-dist/assets/{SquadDetailView-CBAJi3oS.js → SquadDetailView-DuJSNNVn.js} +1 -1
- package/web-dist/assets/{SquadHealthView-CcfjWCOh.js → SquadHealthView-CSg65XVJ.js} +1 -1
- package/web-dist/assets/{SquadsView-BfI7gXGL.js → SquadsView-4g61WHtz.js} +1 -1
- package/web-dist/assets/{ToggleSwitch.vue_vue_type_script_setup_true_lang-CDuXZZzC.js → ToggleSwitch.vue_vue_type_script_setup_true_lang-CD4oN0Pq.js} +1 -1
- package/web-dist/assets/{UsageView-DE3mx0K2.js → UsageView-B1ufrvq3.js} +1 -1
- package/web-dist/assets/{WikiView-Cqn_mgy2.js → WikiView-CFYJ0l0o.js} +1 -1
- package/web-dist/assets/{api-47T1Y5gh.js → api-D4lBmidg.js} +1 -1
- package/web-dist/assets/{arrow-left-DjWS3Dza.js → arrow-left-DttNDi_y.js} +1 -1
- package/web-dist/assets/{git-branch-mIOb5xe9.js → git-branch-B_UsZh9H.js} +1 -1
- package/web-dist/assets/{index-BGcJLCmg.js → index-CC2SMx1A.js} +53 -58
- package/web-dist/assets/index-c_ZAglfK.css +1 -0
- package/web-dist/assets/{plus-bVg6pl4_.js → plus-CR62BmKR.js} +1 -1
- package/web-dist/assets/{save-Ca__Dc6q.js → save-C1H3nHZu.js} +1 -1
- package/web-dist/assets/{search-bl71fr1B.js → search-Re8udetv.js} +1 -1
- package/web-dist/assets/{trash-2-hQUV1Voi.js → trash-2-BPFYLMoU.js} +1 -1
- package/web-dist/assets/{triangle-alert-48e9MScx.js → triangle-alert-3JP6Iw8a.js} +1 -1
- package/web-dist/index.html +2 -2
- package/web-dist/assets/index-DquQZ4vP.css +0 -1
package/dist/config.js
CHANGED
|
@@ -26,10 +26,17 @@ const ConfigSchema = z.object({
|
|
|
26
26
|
tokenAlertThreshold: z.number().optional(),
|
|
27
27
|
});
|
|
28
28
|
let cachedConfig;
|
|
29
|
+
let configWarning;
|
|
30
|
+
/** Returns a warning message if config fell back to defaults on last load. */
|
|
31
|
+
export function getConfigWarning() {
|
|
32
|
+
return configWarning;
|
|
33
|
+
}
|
|
29
34
|
export function loadConfig() {
|
|
30
35
|
if (cachedConfig)
|
|
31
36
|
return cachedConfig;
|
|
32
37
|
if (!existsSync(PATHS.config)) {
|
|
38
|
+
configWarning = `Config file not found at ${PATHS.config} — using defaults. Run "io setup" or create the file manually.`;
|
|
39
|
+
console.warn(`[io] ⚠️ ${configWarning}`);
|
|
33
40
|
const defaults = ConfigSchema.parse({});
|
|
34
41
|
cachedConfig = defaults;
|
|
35
42
|
return defaults;
|
|
@@ -38,8 +45,9 @@ export function loadConfig() {
|
|
|
38
45
|
try {
|
|
39
46
|
raw = JSON.parse(readFileSync(PATHS.config, "utf-8"));
|
|
40
47
|
}
|
|
41
|
-
catch {
|
|
42
|
-
|
|
48
|
+
catch (err) {
|
|
49
|
+
configWarning = `Config file at ${PATHS.config} is corrupted or unreadable — using defaults. Please restore your config.`;
|
|
50
|
+
console.warn(`[io] ⚠️ ${configWarning}`);
|
|
43
51
|
const defaults = ConfigSchema.parse({});
|
|
44
52
|
cachedConfig = defaults;
|
|
45
53
|
return defaults;
|
|
@@ -50,6 +58,7 @@ export function loadConfig() {
|
|
|
50
58
|
delete raw.apiPort;
|
|
51
59
|
saveConfig(raw);
|
|
52
60
|
}
|
|
61
|
+
configWarning = undefined;
|
|
53
62
|
cachedConfig = ConfigSchema.parse(raw);
|
|
54
63
|
return cachedConfig;
|
|
55
64
|
}
|
package/dist/copilot/agents.js
CHANGED
|
@@ -9,7 +9,7 @@ import { attachTokenTracker } from "./token-tracker.js";
|
|
|
9
9
|
import { addAuditEntry } from "../store/audit-log.js";
|
|
10
10
|
import { addAgentEvent } from "../store/agent-events.js";
|
|
11
11
|
import { PATHS } from "../paths.js";
|
|
12
|
-
import { createSquadTools } from "./squad-tools.js";
|
|
12
|
+
import { createSquadTools, createLeadDelegationTools } from "./squad-tools.js";
|
|
13
13
|
import { loadSkillDirectories } from "./skills.js";
|
|
14
14
|
import { getMcpServersForSession } from "../mcp/registry.js";
|
|
15
15
|
import { buildAttachmentPathSummary, saveAttachmentsToDisk, toCopilotBlobAttachments } from "../chat/attachments.js";
|
|
@@ -120,14 +120,14 @@ export async function delegateTask(squadId, task, instanceId, attachments = [])
|
|
|
120
120
|
}
|
|
121
121
|
}
|
|
122
122
|
if (pageContents.length > 0) {
|
|
123
|
-
wikiKnowledge = `\n## ⚠️ MANDATORY SQUAD RULES & KNOWLEDGE\
|
|
123
|
+
wikiKnowledge = `\n## ⚠️ MANDATORY SQUAD RULES & KNOWLEDGE (from squad wiki)\n\nThese rules were written by the project owner specifically for this squad. You MUST follow them in ALL work — every task, every PR, every decision. Violating them is a critical failure.\n\nBefore starting any task, re-read these rules. Before submitting any PR or review, verify compliance.\n\n${pageContents.join("\n\n---\n\n")}\n`;
|
|
124
124
|
}
|
|
125
125
|
}
|
|
126
126
|
catch {
|
|
127
127
|
// Wiki not available — proceed without
|
|
128
128
|
}
|
|
129
129
|
const systemMessage = `# Squad Team Lead: ${lead.character_name}
|
|
130
|
-
|
|
130
|
+
|
|
131
131
|
## 🚨 CRITICAL SECURITY RULE — ABSOLUTE, NON-NEGOTIABLE 🚨
|
|
132
132
|
|
|
133
133
|
You must NEVER expose secrets, credentials, or sensitive values in ANY publicly visible location. This includes:
|
|
@@ -143,22 +143,29 @@ Violation of this rule is a HARD FAILURE — no exceptions, no workarounds, no "
|
|
|
143
143
|
|
|
144
144
|
## Identity & Role
|
|
145
145
|
|
|
146
|
-
You are ${lead.character_name}, the team lead for this squad. Your role is
|
|
146
|
+
You are ${lead.character_name}, the team lead for this squad. Your PRIMARY role is coordination and delegation — you break down tasks and route implementation work to specialists via the \`delegate_to_specialist\` or \`delegate_to_specialists_parallel\` tools.
|
|
147
|
+
|
|
148
|
+
## How Delegation Works
|
|
149
|
+
|
|
150
|
+
When you call \`delegate_to_specialist\`, a **real, independent AI agent session** is spawned for that specialist. They have:
|
|
151
|
+
- Their own full Copilot session with shell access, tools, and MCP servers
|
|
152
|
+
- The squad wiki rules (immutable — they MUST follow them too)
|
|
153
|
+
- Complete autonomy to implement their assigned sub-task
|
|
154
|
+
|
|
155
|
+
This means specialists work IN PARALLEL with you and with each other. Use \`delegate_to_specialists_parallel\` when multiple independent sub-tasks can run concurrently.
|
|
147
156
|
|
|
148
157
|
## Your Responsibilities:
|
|
149
158
|
1. Break down tasks into smaller pieces and delegate to specialists
|
|
150
159
|
2. Route work to the appropriate specialist based on their role
|
|
151
|
-
3.
|
|
152
|
-
4.
|
|
153
|
-
5.
|
|
154
|
-
|
|
155
|
-
## PROHIBITED — You must NEVER:
|
|
156
|
-
- Write, edit, or generate code directly
|
|
157
|
-
- Create or modify files in the repository
|
|
158
|
-
- Run build/test commands to fix code (only to verify status)
|
|
159
|
-
- Implement any part of a task yourself
|
|
160
|
+
3. Use \`delegate_to_specialists_parallel\` for independent sub-tasks (faster!)
|
|
161
|
+
4. Coordinate reviews and approvals after specialists complete work
|
|
162
|
+
5. Ensure quality gates are met
|
|
163
|
+
6. Report progress and blockers
|
|
160
164
|
|
|
161
|
-
|
|
165
|
+
## IMPORTANT — Prefer Delegation:
|
|
166
|
+
- For implementation work (writing code, running tests, creating PRs), ALWAYS delegate to the appropriate specialist
|
|
167
|
+
- You may perform coordination tasks directly: reading issues, checking CI status, posting comments, merging PRs
|
|
168
|
+
- If no suitable specialist exists for a sub-task, report that back — do NOT attempt implementation yourself
|
|
162
169
|
|
|
163
170
|
## Your Team:
|
|
164
171
|
${agentRoster}
|
|
@@ -170,6 +177,7 @@ ${agentRoster}
|
|
|
170
177
|
- Merge criteria: all veto-capable members have posted approving comments + CI passes + no conflicts
|
|
171
178
|
- When work is complete, ALWAYS notify the user via feed_post with a summary of what was done
|
|
172
179
|
- Consult the squad wiki (wiki_read, wiki_search) for additional context when needed
|
|
180
|
+
${wikiKnowledge}
|
|
173
181
|
${lead.persona ? `## Personality:\n${lead.persona}` : ""}
|
|
174
182
|
`;
|
|
175
183
|
let result;
|
|
@@ -180,12 +188,14 @@ ${lead.persona ? `## Personality:\n${lead.persona}` : ""}
|
|
|
180
188
|
const mcpServers = getMcpServersForSession();
|
|
181
189
|
// Resolve correct working directory for the squad's project
|
|
182
190
|
const workDir = await resolveSquadWorkingDirectory(squad, instanceId);
|
|
191
|
+
// Create lead-specific delegation tools (allows spawning real specialist sessions)
|
|
192
|
+
const leadTools = createLeadDelegationTools(squadId, squadSlug, squad, wikiKnowledge, workDir, taskRecord.id, instanceId);
|
|
183
193
|
const session = await client.createSession({
|
|
184
194
|
model,
|
|
185
195
|
streaming: true,
|
|
186
196
|
workingDirectory: workDir,
|
|
187
197
|
systemMessage: { content: systemMessage },
|
|
188
|
-
tools: squadTools,
|
|
198
|
+
tools: [...squadTools, ...leadTools],
|
|
189
199
|
skillDirectories: skillDirs,
|
|
190
200
|
mcpServers,
|
|
191
201
|
onPermissionRequest: approveAll,
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import { approveAll } from "@github/copilot-sdk";
|
|
2
|
+
import { getClient } from "./client.js";
|
|
3
|
+
import { selectModel, classifyComplexity } from "./model-router.js";
|
|
4
|
+
import { attachTokenTracker } from "./token-tracker.js";
|
|
5
|
+
import { createSquadTools } from "./squad-tools.js";
|
|
6
|
+
import { loadSkillDirectories } from "./skills.js";
|
|
7
|
+
import { getMcpServersForSession } from "../mcp/registry.js";
|
|
8
|
+
import { addAgentEvent } from "../store/agent-events.js";
|
|
9
|
+
import { addAuditEntry } from "../store/audit-log.js";
|
|
10
|
+
import { updateAgentStatus } from "../store/squads.js";
|
|
11
|
+
import { touchInstanceActivity } from "../store/instances.js";
|
|
12
|
+
/**
|
|
13
|
+
* Build the system message for a specialist agent session.
|
|
14
|
+
* Wiki knowledge is placed at the END for maximum LLM attention (recency bias).
|
|
15
|
+
*/
|
|
16
|
+
function buildSpecialistSystemMessage(agent, squad, wikiKnowledge, roster) {
|
|
17
|
+
return `# Squad Specialist: ${agent.character_name}
|
|
18
|
+
|
|
19
|
+
## 🚨 CRITICAL SECURITY RULE — ABSOLUTE, NON-NEGOTIABLE 🚨
|
|
20
|
+
|
|
21
|
+
You must NEVER expose secrets, credentials, or sensitive values in ANY publicly visible location. This includes:
|
|
22
|
+
- GitHub issues, pull requests, PR descriptions, comments, or commit messages
|
|
23
|
+
- Log output, error messages, or stack traces shared externally
|
|
24
|
+
- Wiki pages, feed items, or any content viewable by others
|
|
25
|
+
|
|
26
|
+
What counts as a secret: API keys, access tokens, passwords, connection strings, environment variable values, private config file contents, SSH keys, certificates, webhook URLs with tokens.
|
|
27
|
+
|
|
28
|
+
If you need to reference that a secret exists, use \`<REDACTED>\` or \`***\` as a placeholder. NEVER include the actual value.
|
|
29
|
+
|
|
30
|
+
Violation of this rule is a HARD FAILURE — no exceptions, no workarounds, no "just this once."
|
|
31
|
+
|
|
32
|
+
## Identity & Role
|
|
33
|
+
|
|
34
|
+
You are **${agent.character_name}**, a **${agent.role_title}** on the ${squad.name} squad.
|
|
35
|
+
You are an independent specialist — you execute implementation work within your domain of expertise.
|
|
36
|
+
|
|
37
|
+
## Your Responsibilities:
|
|
38
|
+
1. Execute the assigned sub-task fully and correctly
|
|
39
|
+
2. Write clean, tested, production-quality code
|
|
40
|
+
3. Follow project conventions and existing patterns
|
|
41
|
+
4. Commit work to the appropriate branch
|
|
42
|
+
5. Report completion or blockers clearly
|
|
43
|
+
|
|
44
|
+
## Your Team (for context):
|
|
45
|
+
${roster}
|
|
46
|
+
|
|
47
|
+
## Workflow Rules:
|
|
48
|
+
- Always use the gh CLI for GitHub interactions
|
|
49
|
+
- Use \`--comment\` with "LGTM" for approvals (not \`--approve\`)
|
|
50
|
+
- When your work is complete, provide a clear summary of what was done
|
|
51
|
+
- Consult the squad wiki (wiki_read) for additional context when needed
|
|
52
|
+
- Follow all squad rules from the wiki — they are non-negotiable
|
|
53
|
+
${wikiKnowledge}
|
|
54
|
+
${agent.persona ? `## Personality:\n${agent.persona}` : ""}
|
|
55
|
+
`;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Run a specialist agent session independently.
|
|
59
|
+
* Creates a full Copilot SDK session with tools, executes the task, returns the result.
|
|
60
|
+
*/
|
|
61
|
+
export async function runSpecialistSession(request) {
|
|
62
|
+
const { agent, squad, squadSlug, squadId, task, wikiKnowledge, workDir, instanceId, parentTaskId } = request;
|
|
63
|
+
// Select model based on task complexity
|
|
64
|
+
const tier = classifyComplexity(task);
|
|
65
|
+
const model = await selectModel(tier);
|
|
66
|
+
// Build roster for context
|
|
67
|
+
const { getAgentsForSquad } = await import("../store/squads.js");
|
|
68
|
+
const agents = getAgentsForSquad(squadId);
|
|
69
|
+
const roster = agents
|
|
70
|
+
.map((a) => `- ${a.character_name} (${a.role_title})${a.is_lead ? " [LEAD]" : ""}${a.is_qa ? " [QA]" : ""}${a.is_test ? " [TEST]" : ""}`)
|
|
71
|
+
.join("\n");
|
|
72
|
+
const systemMessage = buildSpecialistSystemMessage(agent, squad, wikiKnowledge, roster);
|
|
73
|
+
// Update agent status
|
|
74
|
+
updateAgentStatus(agent.id, "working");
|
|
75
|
+
// Touch instance activity
|
|
76
|
+
if (instanceId) {
|
|
77
|
+
touchInstanceActivity(instanceId);
|
|
78
|
+
}
|
|
79
|
+
// Audit: specialist task started
|
|
80
|
+
addAuditEntry("specialist_task_started", `Specialist task delegated to ${agent.character_name} (${agent.role_title})`, { task: task.slice(0, 500), model, parentTaskId }, { squad_id: squadId, agent_id: agent.id });
|
|
81
|
+
addAgentEvent(parentTaskId, "status", `Sub-task delegated to specialist ${agent.character_name} (${agent.role_title})`, {
|
|
82
|
+
agent: agent.character_name,
|
|
83
|
+
role: agent.role_title,
|
|
84
|
+
task: task.slice(0, 300),
|
|
85
|
+
});
|
|
86
|
+
const client = await getClient();
|
|
87
|
+
try {
|
|
88
|
+
// Load squad-scoped tools, skills, and MCP servers
|
|
89
|
+
const squadTools = createSquadTools(squadSlug, squadId, squad.repo_url);
|
|
90
|
+
const skillDirs = await loadSkillDirectories();
|
|
91
|
+
const mcpServers = getMcpServersForSession();
|
|
92
|
+
const session = await client.createSession({
|
|
93
|
+
model,
|
|
94
|
+
streaming: true,
|
|
95
|
+
workingDirectory: workDir,
|
|
96
|
+
systemMessage: { content: systemMessage },
|
|
97
|
+
tools: squadTools,
|
|
98
|
+
skillDirectories: skillDirs,
|
|
99
|
+
mcpServers,
|
|
100
|
+
onPermissionRequest: approveAll,
|
|
101
|
+
infiniteSessions: {
|
|
102
|
+
enabled: true,
|
|
103
|
+
backgroundCompactionThreshold: 0.8,
|
|
104
|
+
bufferExhaustionThreshold: 0.95,
|
|
105
|
+
},
|
|
106
|
+
});
|
|
107
|
+
const flushTokens = attachTokenTracker(session, {
|
|
108
|
+
squadId,
|
|
109
|
+
agentId: agent.id,
|
|
110
|
+
taskId: parentTaskId,
|
|
111
|
+
});
|
|
112
|
+
// Stream deltas and broadcast via SSE
|
|
113
|
+
let accumulatedMessage = "";
|
|
114
|
+
const { broadcast } = await import("../api/server.js");
|
|
115
|
+
const unsubscribeDelta = session.on("assistant.message_delta", (event) => {
|
|
116
|
+
const delta = event.data?.deltaContent ?? "";
|
|
117
|
+
if (delta) {
|
|
118
|
+
accumulatedMessage += delta;
|
|
119
|
+
broadcast("agent_event", {
|
|
120
|
+
taskId: parentTaskId,
|
|
121
|
+
agentName: agent.character_name,
|
|
122
|
+
type: "specialist_delta",
|
|
123
|
+
summary: accumulatedMessage,
|
|
124
|
+
payload: { delta, accumulated: accumulatedMessage },
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
let result;
|
|
129
|
+
try {
|
|
130
|
+
const response = await session.sendAndWait({ prompt: `You have been assigned the following sub-task by your team lead:\n\n${task}\n\nExecute this task fully. When done, provide a clear summary of what was accomplished.` }, 600_000);
|
|
131
|
+
result = response?.data?.content ?? "Task completed (no response content).";
|
|
132
|
+
}
|
|
133
|
+
finally {
|
|
134
|
+
unsubscribeDelta();
|
|
135
|
+
flushTokens();
|
|
136
|
+
await session.disconnect();
|
|
137
|
+
}
|
|
138
|
+
// Record completion
|
|
139
|
+
addAgentEvent(parentTaskId, "status", `Specialist ${agent.character_name} completed sub-task`, {
|
|
140
|
+
agent: agent.character_name,
|
|
141
|
+
role: agent.role_title,
|
|
142
|
+
result: result.slice(0, 500),
|
|
143
|
+
});
|
|
144
|
+
addAuditEntry("specialist_task_completed", `Specialist ${agent.character_name} completed task`, { result: result.slice(0, 500) }, { squad_id: squadId, agent_id: agent.id });
|
|
145
|
+
updateAgentStatus(agent.id, "idle");
|
|
146
|
+
return {
|
|
147
|
+
agentName: agent.character_name,
|
|
148
|
+
role: agent.role_title,
|
|
149
|
+
success: true,
|
|
150
|
+
result,
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
catch (err) {
|
|
154
|
+
const errMsg = err instanceof Error ? err.message : "Unknown error";
|
|
155
|
+
addAgentEvent(parentTaskId, "status", `Specialist ${agent.character_name} failed: ${errMsg}`, {
|
|
156
|
+
agent: agent.character_name,
|
|
157
|
+
error: errMsg,
|
|
158
|
+
});
|
|
159
|
+
addAuditEntry("specialist_task_failed", `Specialist ${agent.character_name} failed: ${errMsg.slice(0, 200)}`, { error: errMsg }, { squad_id: squadId, agent_id: agent.id });
|
|
160
|
+
updateAgentStatus(agent.id, "idle");
|
|
161
|
+
return {
|
|
162
|
+
agentName: agent.character_name,
|
|
163
|
+
role: agent.role_title,
|
|
164
|
+
success: false,
|
|
165
|
+
result: `Error: ${errMsg}`,
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Run multiple specialist sessions in parallel.
|
|
171
|
+
* Returns results in the same order as the input requests.
|
|
172
|
+
*/
|
|
173
|
+
export async function runSpecialistsParallel(requests) {
|
|
174
|
+
const results = await Promise.allSettled(requests.map(runSpecialistSession));
|
|
175
|
+
return results.map((r, i) => {
|
|
176
|
+
if (r.status === "fulfilled") {
|
|
177
|
+
return r.value;
|
|
178
|
+
}
|
|
179
|
+
return {
|
|
180
|
+
agentName: requests[i].agent.character_name,
|
|
181
|
+
role: requests[i].agent.role_title,
|
|
182
|
+
success: false,
|
|
183
|
+
result: `Session error: ${r.reason instanceof Error ? r.reason.message : "Unknown error"}`,
|
|
184
|
+
};
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
//# sourceMappingURL=specialist-runner.js.map
|
|
@@ -166,4 +166,93 @@ export function createSquadTools(squadSlug, squadId, repoUrl) {
|
|
|
166
166
|
}),
|
|
167
167
|
];
|
|
168
168
|
}
|
|
169
|
+
/**
|
|
170
|
+
* Additional tools available ONLY to team leads.
|
|
171
|
+
* Includes the delegate_to_specialist tool which spawns real parallel agent sessions.
|
|
172
|
+
*/
|
|
173
|
+
export function createLeadDelegationTools(squadId, squadSlug, squad, wikiKnowledge, workDir, parentTaskId, instanceId) {
|
|
174
|
+
return [
|
|
175
|
+
defineTool("delegate_to_specialist", {
|
|
176
|
+
description: "Delegate a sub-task to a specialist agent. This spawns an INDEPENDENT session for that agent — they will execute the work in parallel. Use this to assign implementation work to the right specialist based on their role. You can call this multiple times to delegate to multiple specialists in parallel.",
|
|
177
|
+
parameters: z.object({
|
|
178
|
+
agent_name: z.string().describe("Character name of the specialist to delegate to (from your team roster)"),
|
|
179
|
+
sub_task: z.string().describe("Detailed description of the sub-task. Be specific about what to implement, which files to touch, acceptance criteria, and branch to work on."),
|
|
180
|
+
}),
|
|
181
|
+
handler: async ({ agent_name, sub_task }) => {
|
|
182
|
+
const { getAgentsForSquad } = await import("../store/squads.js");
|
|
183
|
+
const agents = getAgentsForSquad(squadId);
|
|
184
|
+
const agent = agents.find((a) => a.character_name.toLowerCase() === agent_name.toLowerCase() && !a.is_lead);
|
|
185
|
+
if (!agent) {
|
|
186
|
+
const available = agents
|
|
187
|
+
.filter((a) => !a.is_lead)
|
|
188
|
+
.map((a) => `${a.character_name} (${a.role_title})`)
|
|
189
|
+
.join(", ");
|
|
190
|
+
return `Error: No specialist found with name "${agent_name}". Available specialists: ${available}`;
|
|
191
|
+
}
|
|
192
|
+
const { runSpecialistSession } = await import("./specialist-runner.js");
|
|
193
|
+
const result = await runSpecialistSession({
|
|
194
|
+
agent,
|
|
195
|
+
squad,
|
|
196
|
+
squadSlug,
|
|
197
|
+
squadId,
|
|
198
|
+
task: sub_task,
|
|
199
|
+
wikiKnowledge,
|
|
200
|
+
workDir,
|
|
201
|
+
instanceId,
|
|
202
|
+
parentTaskId,
|
|
203
|
+
});
|
|
204
|
+
if (result.success) {
|
|
205
|
+
return `✅ ${result.agentName} (${result.role}) completed the task:\n\n${result.result}`;
|
|
206
|
+
}
|
|
207
|
+
else {
|
|
208
|
+
return `❌ ${result.agentName} (${result.role}) failed:\n\n${result.result}`;
|
|
209
|
+
}
|
|
210
|
+
},
|
|
211
|
+
}),
|
|
212
|
+
defineTool("delegate_to_specialists_parallel", {
|
|
213
|
+
description: "Delegate multiple sub-tasks to different specialists IN PARALLEL. All tasks run concurrently and results are returned together. Use this when multiple independent sub-tasks can be worked on simultaneously by different specialists.",
|
|
214
|
+
parameters: z.object({
|
|
215
|
+
assignments: z.array(z.object({
|
|
216
|
+
agent_name: z.string().describe("Character name of the specialist"),
|
|
217
|
+
sub_task: z.string().describe("Detailed sub-task description"),
|
|
218
|
+
})).describe("Array of agent assignments to execute in parallel"),
|
|
219
|
+
}),
|
|
220
|
+
handler: async ({ assignments }) => {
|
|
221
|
+
const { getAgentsForSquad } = await import("../store/squads.js");
|
|
222
|
+
const { runSpecialistsParallel } = await import("./specialist-runner.js");
|
|
223
|
+
const agents = getAgentsForSquad(squadId);
|
|
224
|
+
const requests = [];
|
|
225
|
+
const errors = [];
|
|
226
|
+
for (const assignment of assignments) {
|
|
227
|
+
const agent = agents.find((a) => a.character_name.toLowerCase() === assignment.agent_name.toLowerCase() && !a.is_lead);
|
|
228
|
+
if (!agent) {
|
|
229
|
+
errors.push(`No specialist found: "${assignment.agent_name}"`);
|
|
230
|
+
continue;
|
|
231
|
+
}
|
|
232
|
+
requests.push({
|
|
233
|
+
agent,
|
|
234
|
+
squad,
|
|
235
|
+
squadSlug,
|
|
236
|
+
squadId,
|
|
237
|
+
task: assignment.sub_task,
|
|
238
|
+
wikiKnowledge,
|
|
239
|
+
workDir,
|
|
240
|
+
instanceId,
|
|
241
|
+
parentTaskId,
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
if (requests.length === 0) {
|
|
245
|
+
return `Error: No valid specialists matched. ${errors.join("; ")}`;
|
|
246
|
+
}
|
|
247
|
+
const results = await runSpecialistsParallel(requests);
|
|
248
|
+
const summaries = results.map((r) => {
|
|
249
|
+
const status = r.success ? "✅" : "❌";
|
|
250
|
+
return `${status} **${r.agentName}** (${r.role}):\n${r.result}`;
|
|
251
|
+
});
|
|
252
|
+
const preamble = errors.length > 0 ? `⚠️ Skipped: ${errors.join("; ")}\n\n` : "";
|
|
253
|
+
return `${preamble}## Parallel Results\n\n${summaries.join("\n\n---\n\n")}`;
|
|
254
|
+
},
|
|
255
|
+
}),
|
|
256
|
+
];
|
|
257
|
+
}
|
|
169
258
|
//# sourceMappingURL=squad-tools.js.map
|
package/dist/daemon.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { loadConfig } from "./config.js";
|
|
1
|
+
import { loadConfig, getConfigWarning } from "./config.js";
|
|
2
2
|
import { getDb, closeDb } from "./store/db.js";
|
|
3
3
|
import { PATHS } from "./paths.js";
|
|
4
4
|
import { mkdirSync, existsSync } from "node:fs";
|
|
@@ -43,6 +43,12 @@ export async function startDaemon(opts) {
|
|
|
43
43
|
console.log("[io] Watchdog active.");
|
|
44
44
|
}
|
|
45
45
|
console.log("[io] Daemon running. Press Ctrl+C to stop.");
|
|
46
|
+
// Notify user if config had to fall back to defaults
|
|
47
|
+
const configWarn = getConfigWarning();
|
|
48
|
+
if (configWarn) {
|
|
49
|
+
const { postFeedItem } = await import("./store/feed.js");
|
|
50
|
+
postFeedItem("system", "⚠️ Config Warning", configWarn);
|
|
51
|
+
}
|
|
46
52
|
// Graceful shutdown
|
|
47
53
|
let shuttingDown = false;
|
|
48
54
|
const shutdown = async () => {
|
package/package.json
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{r as W,u as X,E as Z,J as a,q as d,n as o,t as A,T as N,b as V,s as S,R as l,a5 as f,a0 as T,d as h,L as w,a1 as L,p as b,K as n,m as _,z as ee}from"./index-
|
|
1
|
+
import{r as W,u as X,E as Z,J as a,q as d,n as o,t as A,T as N,b as V,s as S,R as l,a5 as f,a0 as T,d as h,L as w,a1 as L,p as b,K as n,m as _,z as ee}from"./index-CC2SMx1A.js";import{b as F}from"./api-D4lBmidg.js";/**
|
|
2
2
|
* @license lucide-vue-next v0.474.0 - ISC
|
|
3
3
|
*
|
|
4
4
|
* This source code is licensed under the ISC license.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{u as H,W as O,a3 as z,E as U,J as a,q as r,n as o,T as t,t as w,p as m,d as T,L as A,R as d,w as g,M as X,f as W,P as Y,a5 as J,a1 as Q,o as f,S as R,j as G,z as b,K as v,m as B,v as Z,a2 as ee,_ as te,x as S,Q as se,I as E,F as I,l as ae,X as ne,y as $}from"./index-
|
|
1
|
+
import{u as H,W as O,a3 as z,E as U,J as a,q as r,n as o,T as t,t as w,p as m,d as T,L as A,R as d,w as g,M as X,f as W,P as Y,a5 as J,a1 as Q,o as f,S as R,j as G,z as b,K as v,m as B,v as Z,a2 as ee,_ as te,x as S,Q as se,I as E,F as I,l as ae,X as ne,y as $}from"./index-CC2SMx1A.js";const oe={class:"flex flex-col h-full"},re={key:0,class:"flex items-center justify-center h-full"},le={class:"text-center text-muted-foreground"},ie={key:0,class:"mb-2 space-y-2"},ce=["src","alt"],ue={class:"flex items-center gap-2 text-xs"},de={class:"truncate"},pe={class:"opacity-70"},fe={key:2,class:"text-muted-foreground"},me={key:3,class:"inline-block w-2 h-4 bg-current animate-pulse ml-1"},ve={key:0,class:"mb-2 space-y-2"},he={class:"flex flex-wrap gap-2"},ge={class:"max-w-[170px] truncate"},xe={class:"opacity-70"},_e=["onClick"],ye={class:"text-xs text-muted-foreground"},be={key:1,class:"text-xs text-destructive mb-2"},ke={class:"flex gap-2 items-end"},we=["disabled"],Te=["disabled"],Ce=H({__name:"ChatView",setup(Ae){const c=O(),h=v(""),p=v(""),x=v(),_=v(),i=v([]),y=v(!1),j=B(()=>i.value.reduce((e,n)=>e+n.size,0)),C=B(()=>!c.isStreaming&&(h.value.trim().length>0||i.value.length>0));async function D(e){if(!e||e.length===0)return;p.value="";const n=[];try{for(const u of Array.from(e))n.push(await Z(u))}catch(u){p.value=(u==null?void 0:u.message)??"Unable to read one or more files.";return}const s=[...i.value,...n],l=ee(s);if(!l.ok){p.value=l.error;return}i.value=s,_.value&&(_.value.value="")}function N(e){i.value.splice(e,1),p.value=""}function P(){var e;(e=_.value)==null||e.click()}function V(e){const n=e.target;D((n==null?void 0:n.files)??null)}async function M(){if(!C.value)return;const e=h.value.trim(),n=[...i.value],s=e||"Please review the attached file(s).";h.value="",i.value=[],p.value="",await c.sendMessage(s,n)}function k(){x.value&&(x.value.scrollTop=x.value.scrollHeight)}function F(e){e.key==="Enter"&&!e.shiftKey&&(e.preventDefault(),M())}function K(e){e.preventDefault(),y.value=!0}function L(e){e.preventDefault(),y.value=!1}async function q(e){var n;e.preventDefault(),y.value=!1,await D(((n=e.dataTransfer)==null?void 0:n.files)??null)}return z(()=>c.messages.map(e=>e.content),async()=>{await $(),k()},{deep:!0}),z(()=>c.messages.length,async()=>{await $(),k()}),U(()=>k()),(e,n)=>(a(),r("div",oe,[o("div",{ref_key:"messagesContainer",ref:x,class:"flex-1 overflow-y-auto p-4 space-y-4"},[t(c).messages.length===0?(a(),r("div",re,[o("div",le,[w(te,{size:56,class:"mx-auto mb-4"}),n[1]||(n[1]=o("p",{class:"text-lg font-medium"},"Welcome to IO",-1)),n[2]||(n[2]=o("p",{class:"text-sm mt-1"},"Send a message to get started.",-1))])])):m("",!0),(a(!0),r(T,null,A(t(c).messages,s=>(a(),r("div",{key:s.id,class:b(["flex",s.role==="user"?"justify-end":"justify-start"])},[o("div",{class:b(["max-w-[75%] rounded-lg px-4 py-2 text-sm",s.role==="user"?"bg-primary text-primary-foreground":"bg-muted text-foreground"])},[s.attachments.length>0?(a(),r("div",ie,[(a(!0),r(T,null,A(s.attachments,(l,u)=>(a(),r("div",{key:`${s.id}-${u}`,class:"rounded border border-border/50 p-2 bg-background/70 text-foreground"},[t(S)(l)?(a(),r("img",{key:0,src:t(se)(l),alt:l.name,class:"max-h-44 rounded mb-1 object-contain"},null,8,ce)):m("",!0),o("div",ue,[t(S)(l)?(a(),f(t(E),{key:0,class:"w-3.5 h-3.5"})):(a(),f(t(I),{key:1,class:"w-3.5 h-3.5"})),o("span",de,d(l.name),1),o("span",pe,d(t(g)(l.size)),1)])]))),128))])):m("",!0),s.content?(a(),f(ae,{key:1,content:s.content,class:b(s.role==="user"?"prose-invert":"")},null,8,["content","class"])):(a(),r("span",fe,"...")),s.streaming?(a(),r("div",me)):m("",!0)],2)],2))),128))],512),o("div",{class:b(["border-t border-border p-4",y.value?"bg-accent/40":""]),onDragover:K,onDragleave:L,onDrop:q},[o("input",{ref_key:"fileInput",ref:_,type:"file",multiple:"",class:"hidden",onChange:V},null,544),i.value.length>0?(a(),r("div",ve,[o("div",he,[(a(!0),r(T,null,A(i.value,(s,l)=>(a(),r("div",{key:`${s.name}-${l}`,class:"flex items-center gap-2 rounded border border-border px-2 py-1 text-xs bg-muted"},[t(S)(s)?(a(),f(t(E),{key:0,class:"w-3.5 h-3.5"})):(a(),f(t(I),{key:1,class:"w-3.5 h-3.5"})),o("span",ge,d(s.name),1),o("span",xe,d(t(g)(s.size)),1),o("button",{class:"hover:text-destructive",onClick:u=>N(l)},[w(t(ne),{class:"w-3.5 h-3.5"})],8,_e)]))),128))]),o("p",ye,d(t(g)(j.value))+" attached · Max per file "+d(t(g)(t(X)))+" · Max total "+d(t(g)(t(W))),1)])):m("",!0),p.value?(a(),r("p",be,d(p.value),1)):m("",!0),o("div",ke,[o("button",{class:"rounded-md border border-input p-2 hover:bg-accent disabled:opacity-50",disabled:t(c).isStreaming,onClick:P,title:"Attach files"},[w(t(Y),{class:"w-4 h-4"})],8,we),J(o("textarea",{"onUpdate:modelValue":n[0]||(n[0]=s=>h.value=s),onKeydown:F,placeholder:"Send a message...",rows:"1",class:"flex-1 resize-none rounded-md border border-input bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring min-h-[40px] max-h-[120px]"},null,544),[[Q,h.value]]),o("button",{onClick:M,disabled:!C.value,class:"rounded-md bg-primary text-primary-foreground p-2 hover:bg-primary/90 disabled:opacity-50 transition-colors"},[t(c).isStreaming?(a(),f(t(G),{key:1,class:"w-4 h-4"})):(a(),f(t(R),{key:0,class:"w-4 h-4"}))],8,Te)])],34)]))}});export{Ce as default};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{r as M,u as D,E as N,J as o,q as n,n as a,d as h,L as b,t as c,T as i,e as V,K as d,m as z,z as f,R as p,D as B,a7 as k,p as q,l as T}from"./index-
|
|
1
|
+
import{r as M,u as D,E as N,J as o,q as n,n as a,d as h,L as b,t as c,T as i,e as V,K as d,m as z,z as f,R as p,D as B,a7 as k,p as q,l as T}from"./index-CC2SMx1A.js";import{b as C,c as E,a as P}from"./api-D4lBmidg.js";import{g as R}from"./squad-colors-B8B_Y-lz.js";import{T as j}from"./trash-2-BPFYLMoU.js";/**
|
|
2
2
|
* @license lucide-vue-next v0.474.0 - ISC
|
|
3
3
|
*
|
|
4
4
|
* This source code is licensed under the ISC license.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{u as q,a3 as F,E as z,J as r,q as n,n as t,t as d,T as c,H as M,a5 as T,a1 as L,g as E,p as x,d as $,L as A,z as p,R as g,K as l,m as P,o as R,l as G}from"./index-
|
|
1
|
+
import{u as q,a3 as F,E as z,J as r,q as n,n as t,t as d,T as c,H as M,a5 as T,a1 as L,g as E,p as x,d as $,L as A,z as p,R as g,K as l,m as P,o as R,l as G}from"./index-CC2SMx1A.js";import{b as B,a as J}from"./api-D4lBmidg.js";import{S as K}from"./search-Re8udetv.js";import{A as Q}from"./arrow-left-DttNDi_y.js";import{T as I}from"./trash-2-BPFYLMoU.js";const O={class:"flex h-full"},W={class:"p-3 border-b border-border space-y-2"},X={class:"flex items-center gap-2"},Y={class:"relative"},Z={class:"flex gap-2"},ee={class:"flex-1"},te={class:"flex-1"},se={class:"flex-1 overflow-y-auto"},oe={key:0,class:"p-4 text-xs text-muted-foreground"},re={key:1,class:"flex flex-col items-center justify-center h-full p-6 text-center text-muted-foreground"},ne=["onClick"],ae={class:"flex-1 min-w-0"},le={class:"text-xs text-foreground line-clamp-2"},ie={class:"flex items-center gap-2 mt-1"},ue={class:"text-xs text-muted-foreground"},de={class:"text-xs text-muted-foreground"},ce=["onClick"],fe={key:2,class:"p-3 text-center"},ve={key:0,class:"flex-1 flex flex-col"},me={class:"flex items-center gap-2 px-4 py-2 border-b border-border"},xe={class:"text-sm font-medium text-muted-foreground"},pe={class:"flex-1 overflow-y-auto p-4 space-y-4"},ge={key:0,class:"text-center text-xs text-muted-foreground py-8"},he={class:"text-xs mt-1 opacity-60"},ye={key:1,class:"hidden md:flex flex-1 items-center justify-center text-muted-foreground"},be={class:"text-center"},_e=50,De=q({__name:"HistoryView",setup(we){const a=l([]),h=l(0),y=l(!0),f=l(""),v=l(""),m=l(""),u=l(null),b=l([]),_=l(!1),w=l(0);async function k(o=!0){y.value=!0;try{o&&(w.value=0,a.value=[]);const e=new URLSearchParams;f.value&&e.set("q",f.value),v.value&&e.set("from",v.value),m.value&&e.set("to",m.value+"T23:59:59"),e.set("limit",String(_e)),e.set("offset",String(w.value));const i=await B(`/history?${e.toString()}`);a.value=o?i.items:[...a.value,...i.items],h.value=i.total,w.value+=i.items.length}finally{y.value=!1}}async function j(o){u.value=o,_.value=!0;try{b.value=await B(`/history/${o}`)}finally{_.value=!1}}function D(){u.value=null,b.value=[]}async function H(o,e){e.stopPropagation(),confirm("Delete this conversation?")&&(await J(`/history/${o}`),a.value=a.value.filter(i=>i.id!==o),h.value=Math.max(0,h.value-1),u.value===o&&D())}function C(o){return new Date(o).toLocaleString(void 0,{year:"numeric",month:"short",day:"numeric",hour:"2-digit",minute:"2-digit"})}function N(o,e=100){return o.length>e?o.slice(0,e)+"…":o}const U=P(()=>a.value.length<h.value);let S=null;return F([f,v,m],()=>{S&&clearTimeout(S),S=setTimeout(()=>k(!0),300)}),z(()=>k(!0)),(o,e)=>{var i;return r(),n("div",O,[t("div",{class:p(["flex flex-col border-r border-border",u.value?"hidden md:flex w-80 shrink-0":"flex-1"])},[t("div",W,[t("div",X,[d(c(M),{class:"w-4 h-4 text-muted-foreground"}),e[4]||(e[4]=t("span",{class:"text-sm font-medium"},"Conversation History",-1))]),t("div",Y,[d(c(K),{class:"absolute left-2.5 top-2.5 w-3.5 h-3.5 text-muted-foreground"}),T(t("input",{"onUpdate:modelValue":e[0]||(e[0]=s=>f.value=s),placeholder:"Search conversations...",class:"w-full rounded-md border border-input bg-background pl-8 pr-3 py-2 text-xs focus:outline-none focus:ring-1 focus:ring-ring"},null,512),[[L,f.value]])]),t("div",Z,[t("div",ee,[e[5]||(e[5]=t("label",{class:"text-xs text-muted-foreground block mb-1"},"From",-1)),T(t("input",{"onUpdate:modelValue":e[1]||(e[1]=s=>v.value=s),type:"date",class:"w-full rounded-md border border-input bg-background px-2 py-1.5 text-xs focus:outline-none focus:ring-1 focus:ring-ring"},null,512),[[L,v.value]])]),t("div",te,[e[6]||(e[6]=t("label",{class:"text-xs text-muted-foreground block mb-1"},"To",-1)),T(t("input",{"onUpdate:modelValue":e[2]||(e[2]=s=>m.value=s),type:"date",class:"w-full rounded-md border border-input bg-background px-2 py-1.5 text-xs focus:outline-none focus:ring-1 focus:ring-ring"},null,512),[[L,m.value]])])])]),t("div",se,[y.value&&a.value.length===0?(r(),n("div",oe," Loading... ")):a.value.length===0?(r(),n("div",re,[d(c(E),{class:"w-10 h-10 mb-3 opacity-40"}),e[7]||(e[7]=t("p",{class:"text-sm"},"No conversations found.",-1)),e[8]||(e[8]=t("p",{class:"text-xs mt-1"},"Start chatting to build up your history.",-1))])):x("",!0),(r(!0),n($,null,A(a.value,s=>(r(),n("div",{key:s.id,class:p(["group flex items-start gap-2 px-3 py-3 border-b border-border cursor-pointer hover:bg-accent/50 transition-colors",u.value===s.id?"bg-accent":""]),onClick:V=>j(s.id)},[t("div",ae,[t("p",le,g(N(s.preview)),1),t("div",ie,[t("span",ue,g(C(s.updatedAt)),1),t("span",de,"· "+g(s.messageCount)+" msgs",1)])]),t("button",{class:"opacity-0 group-hover:opacity-100 p-1 rounded hover:bg-destructive/10 text-muted-foreground hover:text-destructive transition-all",title:"Delete",onClick:V=>H(s.id,V)},[d(c(I),{class:"w-3.5 h-3.5"})],8,ce)],10,ne))),128)),U.value?(r(),n("div",fe,[t("button",{class:"text-xs text-muted-foreground hover:text-foreground underline",onClick:e[3]||(e[3]=s=>k(!1))}," Load more ")])):x("",!0)])],2),u.value?(r(),n("div",ve,[t("div",me,[t("button",{class:"p-1.5 rounded hover:bg-accent text-muted-foreground",title:"Back",onClick:D},[d(c(Q),{class:"w-4 h-4"})]),t("span",xe,g(C(((i=a.value.find(s=>s.id===u.value))==null?void 0:i.startedAt)??"")),1)]),t("div",pe,[_.value?(r(),n("div",ge," Loading... ")):x("",!0),(r(!0),n($,null,A(b.value,s=>(r(),n("div",{key:s.id,class:p(["flex",s.role==="user"?"justify-end":"justify-start"])},[t("div",{class:p(["max-w-[75%] rounded-lg px-4 py-2 text-sm",s.role==="user"?"bg-blue-600 text-white":"bg-muted text-foreground"])},[s.content?(r(),R(G,{key:0,content:s.content,class:p(s.role==="user"?"prose-invert":"")},null,8,["content","class"])):x("",!0),t("p",he,g(C(s.createdAt)),1)],2)],2))),128))])])):u.value?x("",!0):(r(),n("div",ye,[t("div",be,[d(c(M),{class:"w-12 h-12 mx-auto mb-3 opacity-50"}),e[9]||(e[9]=t("p",null,"Select a conversation to view",-1))])]))])}}});export{De as default};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{u as b,V as v,J as u,q as i,n as t,t as y,a7 as w,a5 as m,a1 as p,R as c,p as V,T as f,K as d,_,Z as h}from"./index-
|
|
1
|
+
import{u as b,V as v,J as u,q as i,n as t,t as y,a7 as w,a5 as m,a1 as p,R as c,p as V,T as f,K as d,_,Z as h}from"./index-CC2SMx1A.js";const S={class:"min-h-screen flex items-center justify-center bg-background p-4"},k={class:"w-full max-w-sm space-y-8"},q={class:"text-center"},A={key:0,class:"text-sm text-destructive"},B=["disabled"],L=b({__name:"LoginView",setup(D){const o=v(),g=h(),r=d(""),n=d(""),s=d("");async function x(){s.value="";try{await o.login(r.value,n.value),g.push("/")}catch(l){s.value=l.message??"Login failed"}}return(l,e)=>(u(),i("div",S,[t("div",k,[t("div",q,[y(_,{size:56,class:"mx-auto mb-4"}),e[2]||(e[2]=t("h1",{class:"font-display text-4xl font-normal uppercase tracking-[0.18em] bg-gradient-brand bg-clip-text text-transparent"}," IO ",-1)),e[3]||(e[3]=t("p",{class:"text-sm text-muted-foreground mt-1"},"Sign in to your dashboard",-1))]),t("form",{onSubmit:w(x,["prevent"]),class:"space-y-4 bg-card border border-border rounded-lg p-6"},[t("div",null,[e[4]||(e[4]=t("label",{class:"text-sm font-medium text-muted-foreground",for:"email"},"Email",-1)),m(t("input",{id:"email","onUpdate:modelValue":e[0]||(e[0]=a=>r.value=a),type:"email",required:"",class:"mt-1 w-full rounded-md border border-border bg-input px-3 py-2 text-sm text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring",placeholder:"you@example.com"},null,512),[[p,r.value]])]),t("div",null,[e[5]||(e[5]=t("label",{class:"text-sm font-medium text-muted-foreground",for:"password"},"Password",-1)),m(t("input",{id:"password","onUpdate:modelValue":e[1]||(e[1]=a=>n.value=a),type:"password",required:"",class:"mt-1 w-full rounded-md border border-border bg-input px-3 py-2 text-sm text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring",placeholder:"••••••••"},null,512),[[p,n.value]])]),s.value?(u(),i("div",A,c(s.value),1)):V("",!0),t("button",{type:"submit",disabled:f(o).loading,class:"btn-gradient w-full py-2.5"},c(f(o).loading?"Signing in...":"Sign In"),9,B)],32),e[6]||(e[6]=t("p",{class:"text-center text-xs text-muted-foreground"}," Personal AI Assistant Daemon ",-1))])]))}});export{L as default};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{u as E,E as S,J as a,q as l,n as s,t as c,T as b,s as C,a5 as i,a1 as m,a0 as M,p as x,i as P,d as j,L as U,K as f,R as p}from"./index-
|
|
1
|
+
import{u as E,E as S,J as a,q as l,n as s,t as c,T as b,s as C,a5 as i,a1 as m,a0 as M,p as x,i as P,d as j,L as U,K as f,R as p}from"./index-CC2SMx1A.js";import{b as $,c as I,d as N,a as L}from"./api-D4lBmidg.js";import{_ as O}from"./ToggleSwitch.vue_vue_type_script_setup_true_lang-CD4oN0Pq.js";import{P as G}from"./plus-CR62BmKR.js";import{T as K}from"./trash-2-BPFYLMoU.js";const F={class:"p-6"},Y={class:"flex items-center justify-between mb-6"},B={key:0,class:"border border-border rounded-lg p-4 mb-6 space-y-3 bg-card"},h={class:"grid grid-cols-2 gap-3"},D={key:0},J={key:1},R={key:1,class:"text-muted-foreground"},q={key:2,class:"text-center py-12 text-muted-foreground"},W={key:3,class:"space-y-2"},z={class:"space-y-1"},H={class:"flex items-center gap-2"},Q={class:"font-medium text-sm"},X={class:"text-xs text-muted-foreground bg-secondary px-1.5 py-0.5 rounded"},Z={key:0,class:"text-xs text-muted-foreground"},ee={key:1,class:"text-xs text-muted-foreground"},te={key:2,class:"text-xs text-muted-foreground"},se={class:"flex items-center gap-3"},oe=["onClick"],ie=E({__name:"McpView",setup(ne){const u=f([]),g=f(!0),v=f(!1),o=f({name:"",type:"stdio",command:"",url:"",argsText:"",envText:""});S(async()=>{try{u.value=await $("/mcp")}finally{g.value=!1}});function k(n){return n.split(/\r?\n|,/).map(e=>e.trim()).filter(Boolean)}function w(n){const e={};try{const t=JSON.parse(n);if(t&&typeof t=="object"&&!Array.isArray(t)){for(const[d,r]of Object.entries(t))e[d]=String(r);return e}}catch{}for(const t of n.split(/\r?\n/)){const d=t.trim();if(!d||d.startsWith("#"))continue;const r=d.indexOf("=");if(r===-1)continue;const y=d.slice(0,r).trim(),A=d.slice(r+1).trim();y&&(e[y]=A)}return e}async function _(n){await N(`/mcp/${n.id}`,{enabled:!n.enabled}),n.enabled=!n.enabled}async function T(n){await L(`/mcp/${n}`),u.value=u.value.filter(e=>e.id!==n)}async function V(){const n={name:o.value.name,type:o.value.type,args:k(o.value.argsText),env:w(o.value.envText)};o.value.type==="stdio"?n.command=o.value.command:n.url=o.value.url;const e=await I("/mcp",n);u.value.push(e),v.value=!1,o.value={name:"",type:"stdio",command:"",url:"",argsText:"",envText:""}}return(n,e)=>(a(),l("div",F,[s("div",Y,[e[8]||(e[8]=s("div",null,[s("p",{class:"text-sm font-medium text-primary"},"MCP configuration"),s("h1",{class:"text-2xl font-bold"},"MCP Servers")],-1)),s("button",{onClick:e[0]||(e[0]=t=>v.value=!v.value),class:"btn-gradient inline-flex items-center gap-1"},[c(b(G),{class:"w-4 h-4"}),e[7]||(e[7]=C(" Add Server ",-1))])]),v.value?(a(),l("div",B,[s("div",h,[s("div",null,[e[9]||(e[9]=s("label",{class:"text-sm font-medium"},"Name",-1)),i(s("input",{"onUpdate:modelValue":e[1]||(e[1]=t=>o.value.name=t),class:"mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm"},null,512),[[m,o.value.name]])]),s("div",null,[e[11]||(e[11]=s("label",{class:"text-sm font-medium"},"Type",-1)),i(s("select",{"onUpdate:modelValue":e[2]||(e[2]=t=>o.value.type=t),class:"mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm"},[...e[10]||(e[10]=[s("option",{value:"stdio"},"stdio",-1),s("option",{value:"http"},"http",-1)])],512),[[M,o.value.type]])])]),o.value.type==="stdio"?(a(),l("div",D,[e[12]||(e[12]=s("label",{class:"text-sm font-medium"},"Command",-1)),i(s("input",{"onUpdate:modelValue":e[3]||(e[3]=t=>o.value.command=t),placeholder:"npx @my/mcp-server",class:"mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm"},null,512),[[m,o.value.command]])])):(a(),l("div",J,[e[13]||(e[13]=s("label",{class:"text-sm font-medium"},"URL",-1)),i(s("input",{"onUpdate:modelValue":e[4]||(e[4]=t=>o.value.url=t),placeholder:"https://...",class:"mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm"},null,512),[[m,o.value.url]])])),s("div",null,[e[14]||(e[14]=s("label",{class:"text-sm font-medium"},"Command args",-1)),i(s("textarea",{"onUpdate:modelValue":e[5]||(e[5]=t=>o.value.argsText=t),rows:"3",placeholder:"--stdio\n--figma-api-key=${FIGMA_API_KEY}",class:"mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm"},null,512),[[m,o.value.argsText]]),e[15]||(e[15]=s("p",{class:"mt-1 text-xs text-muted-foreground"},"Enter one arg per line or comma-separated.",-1))]),s("div",null,[e[16]||(e[16]=s("label",{class:"text-sm font-medium"},"Environment variables",-1)),i(s("textarea",{"onUpdate:modelValue":e[6]||(e[6]=t=>o.value.envText=t),rows:"4",placeholder:"FIGMA_API_KEY=${FIGMA_API_KEY}\nLOG_LEVEL=debug",class:"mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm font-mono"},null,512),[[m,o.value.envText]]),e[17]||(e[17]=s("p",{class:"mt-1 text-xs text-muted-foreground"},"Use KEY=value lines, or paste JSON. Values like ${FIGMA_API_KEY} are preserved.",-1))]),s("div",{class:"flex justify-end"},[s("button",{onClick:V,class:"btn-gradient"},"Save")])])):x("",!0),g.value?(a(),l("div",R,"Loading...")):u.value.length===0?(a(),l("div",q,[c(b(P),{class:"w-12 h-12 mx-auto mb-3 opacity-50"}),e[18]||(e[18]=s("p",null,"No MCP servers configured.",-1))])):(a(),l("div",W,[(a(!0),l(j,null,U(u.value,t=>{var d;return a(),l("div",{key:t.id,class:"flex items-center justify-between border border-border rounded-lg px-4 py-3 bg-card"},[s("div",z,[s("div",H,[s("span",Q,p(t.name),1),s("span",X,p(t.type),1)]),t.command||t.url?(a(),l("div",Z,p(t.command||t.url),1)):x("",!0),(d=t.args)!=null&&d.length?(a(),l("div",ee,"Args: "+p(t.args.join(", ")),1)):x("",!0),t.env&&Object.keys(t.env).length>0?(a(),l("div",te,"Env: "+p(Object.keys(t.env).join(", ")),1)):x("",!0)]),s("div",se,[c(O,{"model-value":t.enabled,"aria-label":`Toggle ${t.name}`,"onUpdate:modelValue":r=>_(t)},null,8,["model-value","aria-label","onUpdate:modelValue"]),s("button",{onClick:r=>T(t.id),class:"p-1.5 rounded hover:bg-destructive/10 text-muted-foreground hover:text-destructive"},[c(b(K),{class:"w-4 h-4"})],8,oe)])])}),128))]))]))}});export{ie as default};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{r as B,u as I,E as L,J as d,q as r,n as o,t as m,T as p,s as z,d as x,L as y,a5 as f,a0 as k,a1 as S,p as _,c as E,R as n,K as u,m as M,z as O,D as j}from"./index-
|
|
1
|
+
import{r as B,u as I,E as L,J as d,q as r,n as o,t as m,T as p,s as z,d as x,L as y,a5 as f,a0 as k,a1 as S,p as _,c as E,R as n,K as u,m as M,z as O,D as j}from"./index-CC2SMx1A.js";import{b as h,c as C,d as A,a as R}from"./api-D4lBmidg.js";import{g as F}from"./squad-colors-B8B_Y-lz.js";import{_ as G}from"./ToggleSwitch.vue_vue_type_script_setup_true_lang-CD4oN0Pq.js";import{P as J}from"./plus-CR62BmKR.js";import{T as K}from"./trash-2-BPFYLMoU.js";/**
|
|
2
2
|
* @license lucide-vue-next v0.474.0 - ISC
|
|
3
3
|
*
|
|
4
4
|
* This source code is licensed under the ISC license.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{u as w,E,J as d,q as s,n as t,R as g,d as x,L as U,a5 as o,a1 as n,a0 as M,$ as p,p as b,K as r,z as T}from"./index-
|
|
1
|
+
import{u as w,E,J as d,q as s,n as t,R as g,d as x,L as U,a5 as o,a1 as n,a0 as M,$ as p,p as b,K as r,z as T}from"./index-CC2SMx1A.js";import{b as V,d as S}from"./api-D4lBmidg.js";const z={class:"p-6"},A={class:"flex items-center justify-between mb-6"},B=["disabled"],N={key:0,class:"text-muted-foreground"},C={class:"flex gap-1 border-b border-border mb-6"},I=["onClick"],K={key:0,class:"space-y-4 max-w-lg"},D={class:"flex items-center gap-3"},L={key:1,class:"space-y-4 max-w-lg"},R={class:"flex items-center gap-3"},j={key:2,class:"space-y-4 max-w-lg"},q={key:3,class:"space-y-4 max-w-lg"},G={class:"flex items-center gap-3"},O={class:"flex items-center gap-3"},W=w({__name:"SettingsView",setup(P){const f=r(!0),i=r(!1),m=r(!1),u=r("general"),y=[{id:"general",label:"General"},{id:"telegram",label:"Telegram"},{id:"auth",label:"Auth"},{id:"advanced",label:"Advanced"}],a=r({defaultModel:"",port:3170,telegramEnabled:!1,telegramBotToken:"",authorizedUserId:null,supabaseUrl:"",supabaseAnonKey:"",authorizedEmail:"",backgroundNotifyMode:"meaningful",backgroundNotifyTelegram:!0,selfEditEnabled:!1,watchdogEnabled:!0});async function k(){f.value=!0;try{const v=await V("/settings");a.value=v}finally{f.value=!1}}async function c(){i.value=!0,m.value=!1;try{await S("/settings",a.value),m.value=!0,setTimeout(()=>m.value=!1,2e3)}finally{i.value=!1}}return E(k),(v,e)=>(d(),s("div",z,[t("div",A,[e[12]||(e[12]=t("h1",{class:"text-2xl font-bold"},"Settings",-1)),t("button",{onClick:c,disabled:i.value,class:"px-4 py-2 rounded-md bg-primary text-primary-foreground text-sm hover:bg-primary/90 disabled:opacity-50"},g(i.value?"Saving...":m.value?"Saved ✓":"Save"),9,B)]),f.value?(d(),s("div",N,"Loading...")):(d(),s(x,{key:1},[t("div",C,[(d(),s(x,null,U(y,l=>t("button",{key:l.id,onClick:$=>u.value=l.id,class:T(["px-4 py-2 text-sm font-medium border-b-2 transition-colors",u.value===l.id?"border-primary text-foreground":"border-transparent text-muted-foreground hover:text-foreground"])},g(l.label),11,I)),64))]),u.value==="general"?(d(),s("div",K,[t("div",null,[e[13]||(e[13]=t("label",{class:"text-sm font-medium"},"Default Model",-1)),o(t("input",{"onUpdate:modelValue":e[0]||(e[0]=l=>a.value.defaultModel=l),class:"mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm"},null,512),[[n,a.value.defaultModel]])]),t("div",null,[e[14]||(e[14]=t("label",{class:"text-sm font-medium"},"Port",-1)),o(t("input",{"onUpdate:modelValue":e[1]||(e[1]=l=>a.value.port=l),type:"number",class:"mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm"},null,512),[[n,a.value.port,void 0,{number:!0}]]),e[15]||(e[15]=t("p",{class:"text-xs text-muted-foreground mt-1"},"Requires restart to take effect",-1))]),t("div",null,[e[17]||(e[17]=t("label",{class:"text-sm font-medium"},"Background Notify Mode",-1)),o(t("select",{"onUpdate:modelValue":e[2]||(e[2]=l=>a.value.backgroundNotifyMode=l),class:"mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm"},[...e[16]||(e[16]=[t("option",{value:"all"},"All",-1),t("option",{value:"meaningful"},"Meaningful",-1),t("option",{value:"off"},"Off",-1)])],512),[[M,a.value.backgroundNotifyMode]])]),t("div",D,[o(t("input",{"onUpdate:modelValue":e[3]||(e[3]=l=>a.value.backgroundNotifyTelegram=l),type:"checkbox",id:"notifyTelegram",class:"rounded"},null,512),[[p,a.value.backgroundNotifyTelegram]]),e[18]||(e[18]=t("label",{for:"notifyTelegram",class:"text-sm font-medium"},"Send notifications via Telegram",-1))])])):b("",!0),u.value==="telegram"?(d(),s("div",L,[t("div",null,[e[19]||(e[19]=t("label",{class:"text-sm font-medium"},"Bot Token",-1)),o(t("input",{"onUpdate:modelValue":e[4]||(e[4]=l=>a.value.telegramBotToken=l),type:"password",placeholder:"Enter new token to update",class:"mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm"},null,512),[[n,a.value.telegramBotToken]])]),t("div",null,[e[20]||(e[20]=t("label",{class:"text-sm font-medium"},"Authorized User ID",-1)),o(t("input",{"onUpdate:modelValue":e[5]||(e[5]=l=>a.value.authorizedUserId=l),type:"number",placeholder:"123456789",class:"mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm"},null,512),[[n,a.value.authorizedUserId,void 0,{number:!0}]])]),t("div",R,[o(t("input",{"onUpdate:modelValue":e[6]||(e[6]=l=>a.value.telegramEnabled=l),type:"checkbox",id:"telegramEnabled",class:"rounded"},null,512),[[p,a.value.telegramEnabled]]),e[21]||(e[21]=t("label",{for:"telegramEnabled",class:"text-sm font-medium"},"Enable Telegram Bot",-1))])])):b("",!0),u.value==="auth"?(d(),s("div",j,[t("div",null,[e[22]||(e[22]=t("label",{class:"text-sm font-medium"},"Supabase URL",-1)),o(t("input",{"onUpdate:modelValue":e[7]||(e[7]=l=>a.value.supabaseUrl=l),placeholder:"https://your-project.supabase.co",class:"mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm"},null,512),[[n,a.value.supabaseUrl]])]),t("div",null,[e[23]||(e[23]=t("label",{class:"text-sm font-medium"},"Supabase Anon Key",-1)),o(t("input",{"onUpdate:modelValue":e[8]||(e[8]=l=>a.value.supabaseAnonKey=l),type:"password",placeholder:"Enter new key to update",class:"mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm"},null,512),[[n,a.value.supabaseAnonKey]])]),t("div",null,[e[24]||(e[24]=t("label",{class:"text-sm font-medium"},"Authorized Email",-1)),o(t("input",{"onUpdate:modelValue":e[9]||(e[9]=l=>a.value.authorizedEmail=l),type:"email",placeholder:"you@example.com",class:"mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm"},null,512),[[n,a.value.authorizedEmail]])])])):b("",!0),u.value==="advanced"?(d(),s("div",q,[t("div",G,[o(t("input",{"onUpdate:modelValue":e[10]||(e[10]=l=>a.value.selfEditEnabled=l),type:"checkbox",id:"selfEdit",class:"rounded"},null,512),[[p,a.value.selfEditEnabled]]),e[25]||(e[25]=t("div",null,[t("label",{for:"selfEdit",class:"text-sm font-medium"},"Self-Edit Mode"),t("p",{class:"text-xs text-muted-foreground"},"Allow IO to modify its own source code")],-1))]),t("div",O,[o(t("input",{"onUpdate:modelValue":e[11]||(e[11]=l=>a.value.watchdogEnabled=l),type:"checkbox",id:"watchdog",class:"rounded"},null,512),[[p,a.value.watchdogEnabled]]),e[26]||(e[26]=t("div",null,[t("label",{for:"watchdog",class:"text-sm font-medium"},"Watchdog"),t("p",{class:"text-xs text-muted-foreground"},"Monitor event loop and zombie instances")],-1))])])):b("",!0)],64))]))}});export{W as default};
|