@kendoo.agentdesk/agentdesk 0.9.5 → 0.9.7

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.
@@ -1,166 +0,0 @@
1
- // Per-agent prompt generator for sub-agent architecture
2
-
3
- import { generateContext } from "./detect.mjs";
4
-
5
- const PHASE_INSTRUCTIONS = {
6
- intake: {
7
- Jane: `You are leading the intake for this task. Your job:
8
- 1. Understand the task requirements from the description and/or tracker.
9
- 2. Check for existing branches: \`git branch -a | grep <task-id>\`
10
- 3. Check for existing PRs: \`gh pr list --search <task-id> --json number,title,state\`
11
- 4. Explore the codebase briefly to understand what we're working with.
12
- 5. Summarize: what needs to be done, what already exists, and what the starting point is.
13
- 6. Recommend which phase to start from (BRAINSTORM for new work, EXECUTION if branch exists).
14
-
15
- IMPORTANT: At the end of your intake summary, you MUST provide a short title for this session on its own line in this exact format:
16
- SESSION_TITLE: <4-8 word title>
17
- Example: SESSION_TITLE: Fix checkout total calculation
18
- This title will be displayed in the dashboard navbar, so keep it short and descriptive.`,
19
- },
20
-
21
- brainstorm: {
22
- _default: (agent) => `Share your perspective on this task from your role as ${agent.role}.
23
- Focus on: ${agent.brainstorm?.focus || "your area of expertise"}.
24
- Use [${agent.brainstorm?.tag || "SAY"}] tag.
25
- Be specific. If you disagree with anything in the conversation so far, use [ARGUE] and explain why.
26
- If you agree, still add value — don't just say "I agree."`,
27
- },
28
-
29
- planning: {
30
- _default: (agent) => `Present your plan for this task from your role as ${agent.role}.
31
- Your expected output: ${agent.planning || "Your role-specific plan."}
32
- Be concrete — name files, approaches, specific concerns.`,
33
- },
34
-
35
- "planning-review": {
36
- _default: () => `Review all the plans presented by the team.
37
- If you see problems, conflicts, or missing considerations, use [ARGUE] and explain.
38
- If everything looks good, acknowledge with [AGREE] and note why.`,
39
- },
40
-
41
- execution: {
42
- _default: (agent) => {
43
- if (!agent.execution) return "This task has no execution step for your role. Skip this phase.";
44
- return `Complete your execution tasks:
45
- ${agent.execution.tasks.map((t, i) => `${i + 1}. ${t}`).join("\n")}
46
-
47
- Work carefully. Use tools as needed. Narrate what you're doing.`;
48
- },
49
- },
50
-
51
- "execution-review": {
52
- _default: (agent) => `Review the changes made so far.
53
- From your perspective as ${agent.role}:
54
- ${agent.groundRules || "Review for issues in your area of expertise."}
55
- If you find issues, describe them specifically with file paths and line numbers.
56
- If everything looks good, confirm with [AGREE].`,
57
- },
58
-
59
- review: {
60
- _default: (agent) => `The session is wrapping up. Provide your final notes:
61
- - Any remaining concerns?
62
- - Anything the team should watch out for?
63
- - Overall assessment from your perspective as ${agent.role}.
64
- Keep it brief.`,
65
- Jane: `The session is wrapping up. Provide the final summary:
66
- 1. What was accomplished
67
- 2. Any remaining concerns from the team
68
- 3. What the next steps should be
69
- Keep it concise.`,
70
- },
71
- };
72
-
73
- export function buildAgentPrompt(agent, { phase, task, project, conversation, inboxUrl, sessionUrl }) {
74
- const parts = [];
75
-
76
- // Identity
77
- parts.push(`You are ${agent.name}, ${agent.role} on a software development team.`);
78
- parts.push("");
79
-
80
- // Role
81
- parts.push("## Your Role");
82
- parts.push(agent.description);
83
- if (agent.groundRules) parts.push(`\nGround rules: ${agent.groundRules}`);
84
- if (agent.codePrinciple) parts.push(`\nCode principle: ${agent.codePrinciple}`);
85
- parts.push("");
86
-
87
- // Communication
88
- parts.push("## Communication");
89
- parts.push(`Prefix your output with your badge: ${agent.badge}`);
90
- parts.push("Use these tags in your messages:");
91
- parts.push("- [SAY] — Normal statements, announcements, questions");
92
- parts.push("- [THINK] — Internal reasoning, analysis");
93
- parts.push("- [ACT] — When using tools or taking actions");
94
- parts.push("- [ARGUE] — When you disagree or see problems");
95
- parts.push("- [AGREE] — When you agree (but still add value)");
96
- parts.push("");
97
-
98
- // Task
99
- parts.push("## Task");
100
- parts.push(`Task ID: ${task.id}`);
101
- if (task.link) parts.push(`Task link: ${task.link}`);
102
- if (task.description) parts.push(`\nDescription: ${task.description}`);
103
- parts.push("");
104
-
105
- // Project context
106
- if (project) {
107
- const context = generateContext(project);
108
- parts.push("## Project Context");
109
- parts.push(context);
110
- parts.push("");
111
- }
112
-
113
- // Conversation so far
114
- if (conversation && conversation.length > 0) {
115
- parts.push("## Conversation So Far");
116
- for (const msg of conversation) {
117
- if (msg.type === "phase") {
118
- parts.push(`\n--- ${msg.phase} ---\n`);
119
- } else if (msg.agent && msg.message) {
120
- parts.push(`${msg.agent} [${msg.tag || "SAY"}]: ${msg.message}`);
121
- }
122
- }
123
- parts.push("");
124
- }
125
-
126
- // Phase instructions
127
- parts.push(`## Current Phase: ${phase.toUpperCase()}`);
128
- const phaseConfig = PHASE_INSTRUCTIONS[phase] || {};
129
- const agentInstr = phaseConfig[agent.name] || (phaseConfig._default ? phaseConfig._default(agent) : "Contribute from your area of expertise.");
130
- parts.push(agentInstr);
131
- parts.push("");
132
-
133
- // Inbox (Jane only)
134
- if (agent.name === "Jane" && inboxUrl) {
135
- parts.push("## User Messages");
136
- parts.push(`Before starting, check for user messages: \`curl -s ${inboxUrl}\``);
137
- parts.push("If the response is not empty ([]), read the messages and incorporate the user's input.");
138
- parts.push("");
139
- }
140
-
141
- // Session URL
142
- if (sessionUrl) {
143
- parts.push(`Session: ${sessionUrl}`);
144
- }
145
-
146
- // Time
147
- const now = new Date();
148
- parts.push(`\nCurrent date/time: ${now.toLocaleDateString("en-US", { weekday: "long", year: "numeric", month: "long", day: "numeric" })} ${now.toLocaleTimeString("en-US", { hour: "2-digit", minute: "2-digit" })}`);
149
-
150
- return parts.join("\n");
151
- }
152
-
153
- // Get tool list for an agent
154
- const AGENT_TOOLS = {
155
- Jane: ["Bash", "Read"],
156
- Dennis: ["Bash", "Read", "Edit", "Write", "Glob", "Grep"],
157
- Sam: ["Read", "Glob", "Grep"],
158
- Bart: ["Bash", "Read", "Glob", "Grep"],
159
- Vera: ["Bash", "Read", "Edit", "Write", "Glob", "Grep"],
160
- Luna: ["Read", "Glob"],
161
- Mark: ["Read", "Glob"],
162
- };
163
-
164
- export function getAgentTools(agentName) {
165
- return AGENT_TOOLS[agentName] || ["Bash", "Read", "Edit", "Write", "Glob", "Grep"];
166
- }
@@ -1,148 +0,0 @@
1
- // Spawns a single Claude process for one agent and parses its output
2
-
3
- import { spawn } from "child_process";
4
- import { createInterface } from "readline";
5
-
6
- export async function runAgent(agentName, {
7
- prompt,
8
- allowedTools = ["Bash", "Read", "Edit", "Write", "Glob", "Grep"],
9
- cwd,
10
- env,
11
- onMessage,
12
- onToolUse,
13
- onToolResult,
14
- }) {
15
- const messages = [];
16
- const toolUses = [];
17
- let rawOutput = "";
18
- let inputTokens = 0;
19
- let outputTokens = 0;
20
- let steps = 0;
21
- let hadArgue = false;
22
-
23
- const child = spawn(
24
- "claude",
25
- [
26
- "-p", prompt,
27
- "--allowedTools", allowedTools.join(","),
28
- "--verbose",
29
- "--output-format", "stream-json",
30
- ],
31
- {
32
- stdio: ["pipe", "pipe", "inherit"],
33
- shell: false,
34
- env: env || process.env,
35
- cwd,
36
- }
37
- );
38
-
39
- child.stdin.end();
40
-
41
- const rl = createInterface({ input: child.stdout });
42
-
43
- for await (const line of rl) {
44
- try {
45
- const event = JSON.parse(line);
46
-
47
- // Track tokens
48
- if (event.usage) {
49
- if (event.usage.input_tokens) inputTokens = Math.max(inputTokens, event.usage.input_tokens);
50
- if (event.usage.output_tokens) outputTokens += (event.usage.output_tokens_delta || 0);
51
- }
52
- if (event.message?.usage) {
53
- if (event.message.usage.input_tokens) inputTokens = Math.max(inputTokens, event.message.usage.input_tokens);
54
- if (event.message.usage.output_tokens) outputTokens = Math.max(outputTokens, event.message.usage.output_tokens);
55
- }
56
-
57
- // Text output
58
- if (event.type === "assistant" && event.message?.content) {
59
- for (const block of event.message.content) {
60
- if (block.type === "text" && block.text.trim()) {
61
- const text = block.text.trim();
62
- rawOutput += text + "\n";
63
-
64
- // Detect tags
65
- let tag = "SAY";
66
- if (/\[ARGUE\]/i.test(text)) { tag = "ARGUE"; hadArgue = true; }
67
- else if (/\[AGREE\]/i.test(text)) tag = "AGREE";
68
- else if (/\[THINK\]/i.test(text)) tag = "THINK";
69
- else if (/\[ACT\]/i.test(text)) tag = "ACT";
70
-
71
- const cleanMsg = text.replace(/\[(SAY|ACT|THINK|AGREE|ARGUE)\]\s*/gi, "").replace(/\*+/g, "");
72
- const msg = { agent: agentName, tag, message: cleanMsg };
73
- messages.push(msg);
74
- onMessage?.(msg);
75
- }
76
- }
77
- }
78
-
79
- // Tool use
80
- if (event.type === "tool_use") {
81
- const name = event.name || event.tool_name;
82
- steps++;
83
-
84
- let description = "Running command...";
85
- if (name === "Bash") {
86
- const cmd = event.input?.command || "";
87
- if (cmd.includes("curl") && cmd.includes("linear")) description = "Calling Linear API...";
88
- else if (cmd.includes("curl")) description = "Making API request...";
89
- else {
90
- const shortCmd = cmd.length > 80 ? cmd.slice(0, 80) + "..." : cmd;
91
- description = `$ ${shortCmd}`;
92
- }
93
- } else if (name === "Read") {
94
- const shortPath = (event.input?.file_path || "").split("/").slice(-3).join("/");
95
- description = `Reading ${shortPath}`;
96
- } else if (name === "Edit" || name === "Write") {
97
- const shortPath = (event.input?.file_path || "").split("/").slice(-3).join("/");
98
- description = `${name === "Edit" ? "Editing" : "Writing"} ${shortPath}`;
99
- } else if (name === "Glob" || name === "Grep") {
100
- description = `Searching ${event.input?.pattern || ""}`;
101
- }
102
-
103
- const use = { agent: agentName, tool: name, description };
104
- toolUses.push(use);
105
- onToolUse?.(use);
106
- }
107
-
108
- // Tool result
109
- if (event.type === "tool_result") {
110
- const output = event.content || event.output;
111
- let text = "";
112
- if (typeof output === "string") text = output.trim();
113
- else if (Array.isArray(output)) {
114
- text = output.filter(b => b.type === "text").map(b => b.text.trim()).join("\n");
115
- }
116
- const hasError = text && (text.toLowerCase().includes("error") || text.toLowerCase().includes("failed"));
117
- const summary = text?.length > 300 ? `Done (${text.length} chars)` : text || "Done";
118
- onToolResult?.({ success: !hasError, summary });
119
- }
120
-
121
- // Final result
122
- if (event.type === "result") {
123
- if (event.usage) {
124
- if (event.usage.input_tokens) inputTokens = Math.max(inputTokens, event.usage.input_tokens);
125
- if (event.usage.output_tokens) outputTokens = Math.max(outputTokens, event.usage.output_tokens);
126
- }
127
- }
128
- } catch {
129
- // skip non-JSON
130
- }
131
- }
132
-
133
- const exitCode = await new Promise(resolve => {
134
- child.on("close", (code) => resolve(code || 0));
135
- });
136
-
137
- return {
138
- agent: agentName,
139
- messages,
140
- toolUses,
141
- rawOutput,
142
- inputTokens,
143
- outputTokens,
144
- steps,
145
- hadArgue,
146
- exitCode,
147
- };
148
- }