@markus-global/cli 0.7.1 → 0.7.2
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/commands/start.js +19 -1
- package/dist/commands/start.js.map +1 -1
- package/dist/markus.mjs +1156 -265
- package/dist/web-ui/assets/{browser-DlVfF39H.js → browser-D7voLlvI.js} +1 -1
- package/dist/web-ui/assets/index-BY8rA8ML.css +1 -0
- package/dist/web-ui/assets/index-WWZgMSA9.js +386 -0
- package/dist/web-ui/index.html +2 -2
- package/package.json +1 -1
- package/dist/web-ui/assets/index-BmAWk8NW.css +0 -1
- package/dist/web-ui/assets/index-DtpSP_xt.js +0 -386
package/dist/markus.mjs
CHANGED
|
@@ -4216,7 +4216,7 @@ function withJitter(baseMs, factor = 0.2) {
|
|
|
4216
4216
|
const jitter = baseMs * factor * (2 * Math.random() - 1);
|
|
4217
4217
|
return Math.max(0, Math.round(baseMs + jitter));
|
|
4218
4218
|
}
|
|
4219
|
-
var TASK_GET_NOTES_DEFAULT, TASK_GET_DELIVERABLES_DEFAULT, TASK_GET_STATUS_HISTORY_DEFAULT, REQUIREMENT_LIST_DEFAULT, ENTITY_COMMENTS_DEFAULT, PROMPT_TASK_NOTES_MAX, PROMPT_TASK_NOTE_CHARS, PROMPT_DEP_NOTES_MAX, PROMPT_DEP_NOTE_CHARS, PROMPT_DEP_DESC_CHARS, PROMPT_EXECUTION_ROUNDS_MAX, PROMPT_LOG_ENTRY_CHARS, PROMPT_RECENT_ERRORS_MAX, PROMPT_HUMAN_COMMENTS_MAX, REVIEWER_NOTES_MAX, SYSTEM_MY_TASKS_MAX, SYSTEM_TEAM_TASKS_MAX, SYSTEM_TASK_DESC_CHARS, PROMPT_PROJECT_DESC_CHARS, PROMPT_REQUIREMENT_DESC_CHARS, REVIEWER_FILE_LIST_MAX, DELIVERABLE_TITLE_CHARS, REVISION_REASON_CHARS, TASK_MAX_RETRIES, MAILBOX_ITEM_MAX_RETRIES, COMPLETION_MARKER, COMPLETION_MARKER_INSTRUCTION, TASK_MAX_NO_SUBMIT_RETRIES, TASK_RETRY_DELAYS_MS, PREEMPT_REQUEUE_DELAY_MS, SYSTEM_KNOWLEDGE_CHARS, SYSTEM_SOPS_CHARS, SYSTEM_LONGTERM_MEMORY_CHARS, MEMORY_MD_SECTION_MAX_CHARS, MEMORY_MD_TOTAL_MAX_CHARS, SYSTEM_LESSON_ENTRIES_MAX, SYSTEM_BEST_PRACTICE_ENTRIES_MAX, SYSTEM_DELIVERABLES_CHARS, SYSTEM_DAILY_LOG_CHARS, SYSTEM_DAILY_LOG_DAYS, SYSTEM_USER_PROFILE_CHARS, SYSTEM_CHAT_SESSIONS_MAX, HEARTBEAT_DAILY_LOG_CHARS, SYSTEM_PROJECT_DESC_CHARS, SYSTEM_DELIVERABLE_PREVIEW_CHARS, SYSTEM_MAILBOX_MERGED_CHARS, SYSTEM_MAILBOX_ITEM_PREVIEW_CHARS, TASK_LIST_PAGE_SIZE, TASK_LIST_PAGE_MAX, ARCHIVE_COMPLETED_AFTER_DAYS, ARCHIVE_TERMINAL_AFTER_DAYS, ARCHIVE_REQUIREMENT_AFTER_DAYS, ARCHIVE_SCAN_INTERVAL_MS, CHANNEL_CONTEXT_MESSAGES, MAILBOX_QUEUED_TTL_MS, MAILBOX_PROCESSING_TIMEOUT_MS, WATCHDOG_INTERVAL_MS, WATCHDOG_DRIFT_THRESHOLD_MS, TRIAGE_BACKLOG_THRESHOLD, TRIAGE_PROMPT_MAX_ITEMS, TRIAGE_MAX_TOKENS, TRIAGE_TEMPERATURE, TRIAGE_CONTEXT_MESSAGES_MAX, TRIAGE_CONTEXT_MSG_CHARS, TRIAGE_ITEM_CONTENT_CHARS, TRIAGE_STALE_INFO_TTL_MS, TRIAGE_STALE_DROP_TYPES, TRIAGE_MAX_TOOL_ITERATIONS, TRIAGE_ALLOWED_TOOLS, DELIBERATION_ALLOWED_TOOLS, WORKING_MEMORY_MAX_ENTRIES, WORKING_MEMORY_MAX_CHARS, SUBAGENT_TASK_PREVIEW_CHARS, SUBAGENT_THINKING_PREVIEW_CHARS, SUBAGENT_RESULT_PREVIEW_CHARS, SUBAGENT_LOG_ENTRY_CHARS, SUBAGENT_ERROR_PREVIEW_CHARS, SUBAGENT_MAX_PARALLEL, SUBAGENT_MAX_LLM_RETRIES, SUBAGENT_RETRY_BASE_MS, SHELL_TIMEOUT_DEFAULT_MS, SHELL_TIMEOUT_MAX_MS, SHELL_MAX_SESSIONS_PER_AGENT, SHELL_SESSION_IDLE_TIMEOUT_MS, SHELL_SESSION_MAX_OUTPUT_BYTES, APPROVAL_WAIT_TIMEOUT_MS, HEARTBEAT_MIN_INITIAL_DELAY_MS, HEARTBEAT_STARTUP_JITTER_MS, LLM_CIRCUIT_RESET_RATE_LIMIT_MS, LLM_MAX_CONCURRENT_PER_PROVIDER, LLM_CONCURRENCY_JITTER_BASE_MS;
|
|
4219
|
+
var TASK_GET_NOTES_DEFAULT, TASK_GET_DELIVERABLES_DEFAULT, TASK_GET_STATUS_HISTORY_DEFAULT, REQUIREMENT_LIST_DEFAULT, ENTITY_COMMENTS_DEFAULT, PROMPT_TASK_NOTES_MAX, PROMPT_TASK_NOTE_CHARS, PROMPT_DEP_NOTES_MAX, PROMPT_DEP_NOTE_CHARS, PROMPT_DEP_DESC_CHARS, PROMPT_EXECUTION_ROUNDS_MAX, PROMPT_LOG_ENTRY_CHARS, PROMPT_RECENT_ERRORS_MAX, PROMPT_HUMAN_COMMENTS_MAX, REVIEWER_NOTES_MAX, SYSTEM_MY_TASKS_MAX, SYSTEM_TEAM_TASKS_MAX, SYSTEM_TASK_DESC_CHARS, PROMPT_PROJECT_DESC_CHARS, PROMPT_REQUIREMENT_DESC_CHARS, REVIEWER_FILE_LIST_MAX, DELIVERABLE_TITLE_CHARS, REVISION_REASON_CHARS, TASK_MAX_RETRIES, MAILBOX_ITEM_MAX_RETRIES, COMPLETION_MARKER, COMPLETION_MARKER_INSTRUCTION, TASK_MAX_NO_SUBMIT_RETRIES, TASK_RETRY_DELAYS_MS, PREEMPT_REQUEUE_DELAY_MS, SYSTEM_KNOWLEDGE_CHARS, SYSTEM_SOPS_CHARS, SYSTEM_LONGTERM_MEMORY_CHARS, MEMORY_MD_SECTION_MAX_CHARS, MEMORY_MD_TOTAL_MAX_CHARS, SYSTEM_LESSON_ENTRIES_MAX, SYSTEM_BEST_PRACTICE_ENTRIES_MAX, SYSTEM_DELIVERABLES_CHARS, SYSTEM_DAILY_LOG_CHARS, SYSTEM_DAILY_LOG_DAYS, SYSTEM_USER_PROFILE_CHARS, SYSTEM_CHAT_SESSIONS_MAX, HEARTBEAT_DAILY_LOG_CHARS, SYSTEM_PROJECT_DESC_CHARS, SYSTEM_DELIVERABLE_PREVIEW_CHARS, SYSTEM_MAILBOX_MERGED_CHARS, SYSTEM_MAILBOX_ITEM_PREVIEW_CHARS, TASK_LIST_PAGE_SIZE, TASK_LIST_PAGE_MAX, ARCHIVE_COMPLETED_AFTER_DAYS, ARCHIVE_TERMINAL_AFTER_DAYS, ARCHIVE_REQUIREMENT_AFTER_DAYS, ARCHIVE_SCAN_INTERVAL_MS, CHANNEL_CONTEXT_MESSAGES, MAILBOX_QUEUED_TTL_MS, MAILBOX_COALESCE_WINDOW_MS, MAILBOX_PROCESSING_TIMEOUT_MS, WATCHDOG_INTERVAL_MS, WATCHDOG_DRIFT_THRESHOLD_MS, TRIAGE_BACKLOG_THRESHOLD, TRIAGE_PROMPT_MAX_ITEMS, TRIAGE_MAX_TOKENS, TRIAGE_TEMPERATURE, TRIAGE_CONTEXT_MESSAGES_MAX, TRIAGE_CONTEXT_MSG_CHARS, TRIAGE_ITEM_CONTENT_CHARS, TRIAGE_STALE_INFO_TTL_MS, TRIAGE_STALE_DROP_TYPES, TRIAGE_MAX_TOOL_ITERATIONS, TRIAGE_ALLOWED_TOOLS, DELIBERATION_ALLOWED_TOOLS, WORKING_MEMORY_MAX_ENTRIES, WORKING_MEMORY_MAX_CHARS, SUBAGENT_TASK_PREVIEW_CHARS, SUBAGENT_THINKING_PREVIEW_CHARS, SUBAGENT_RESULT_PREVIEW_CHARS, SUBAGENT_LOG_ENTRY_CHARS, SUBAGENT_ERROR_PREVIEW_CHARS, SUBAGENT_MAX_PARALLEL, SUBAGENT_MAX_LLM_RETRIES, SUBAGENT_RETRY_BASE_MS, SHELL_TIMEOUT_DEFAULT_MS, SHELL_TIMEOUT_MAX_MS, SHELL_MAX_SESSIONS_PER_AGENT, SHELL_SESSION_IDLE_TIMEOUT_MS, SHELL_SESSION_MAX_OUTPUT_BYTES, APPROVAL_WAIT_TIMEOUT_MS, HEARTBEAT_MIN_INITIAL_DELAY_MS, HEARTBEAT_STARTUP_JITTER_MS, LLM_CIRCUIT_RESET_RATE_LIMIT_MS, LLM_MAX_CONCURRENT_PER_PROVIDER, LLM_CONCURRENCY_JITTER_BASE_MS;
|
|
4220
4220
|
var init_limits = __esm({
|
|
4221
4221
|
"../shared/dist/limits.js"() {
|
|
4222
4222
|
"use strict";
|
|
@@ -4277,6 +4277,7 @@ var init_limits = __esm({
|
|
|
4277
4277
|
ARCHIVE_SCAN_INTERVAL_MS = 6 * 60 * 60 * 1e3;
|
|
4278
4278
|
CHANNEL_CONTEXT_MESSAGES = 40;
|
|
4279
4279
|
MAILBOX_QUEUED_TTL_MS = 3 * 24 * 60 * 60 * 1e3;
|
|
4280
|
+
MAILBOX_COALESCE_WINDOW_MS = 200;
|
|
4280
4281
|
MAILBOX_PROCESSING_TIMEOUT_MS = 10 * 60 * 1e3;
|
|
4281
4282
|
WATCHDOG_INTERVAL_MS = 3e4;
|
|
4282
4283
|
WATCHDOG_DRIFT_THRESHOLD_MS = 6e4;
|
|
@@ -4326,6 +4327,9 @@ var init_limits = __esm({
|
|
|
4326
4327
|
// Working memory
|
|
4327
4328
|
"update_working_memory",
|
|
4328
4329
|
"clear_working_memory",
|
|
4330
|
+
// Long-term memory (allows recording observations during deliberation)
|
|
4331
|
+
"memory_save",
|
|
4332
|
+
"memory_update_longterm",
|
|
4329
4333
|
// Inline action (lightweight communication)
|
|
4330
4334
|
"notify_user",
|
|
4331
4335
|
"task_comment",
|
|
@@ -4433,6 +4437,7 @@ __export(dist_exports, {
|
|
|
4433
4437
|
LLM_MAX_CONCURRENT_PER_PROVIDER: () => LLM_MAX_CONCURRENT_PER_PROVIDER,
|
|
4434
4438
|
Logger: () => Logger,
|
|
4435
4439
|
MAILBOX_CATEGORIES: () => MAILBOX_CATEGORIES,
|
|
4440
|
+
MAILBOX_COALESCE_WINDOW_MS: () => MAILBOX_COALESCE_WINDOW_MS,
|
|
4436
4441
|
MAILBOX_ITEM_MAX_RETRIES: () => MAILBOX_ITEM_MAX_RETRIES,
|
|
4437
4442
|
MAILBOX_PROCESSING_TIMEOUT_MS: () => MAILBOX_PROCESSING_TIMEOUT_MS,
|
|
4438
4443
|
MAILBOX_QUEUED_TTL_MS: () => MAILBOX_QUEUED_TTL_MS,
|
|
@@ -6700,8 +6705,9 @@ var init_context_engine = __esm({
|
|
|
6700
6705
|
stable.push("- `recall_activity` \u2014 query your own past execution logs by task or activity type. Use when you need to review what you did previously (e.g., to answer a follow-up question).");
|
|
6701
6706
|
stable.push("");
|
|
6702
6707
|
stable.push("**Communicating with other agents**:");
|
|
6703
|
-
stable.push("- `agent_send_message` \u2014 send a direct message to a peer agent. **
|
|
6704
|
-
stable.push("- A2A messaging is
|
|
6708
|
+
stable.push("- `agent_send_message` \u2014 send a direct message to a peer agent. **Always asynchronous**: the message enters their mailbox and you continue working without blocking.");
|
|
6709
|
+
stable.push("- A2A messaging is **non-blocking by design**. You send a message, the recipient processes it on their own schedule, and may reply via their own `agent_send_message`. Do NOT spin-wait or poll.");
|
|
6710
|
+
stable.push("- Use `conversation_id` to correlate multi-turn exchanges. Record what you asked in working memory (`update_working_memory`) so you recognize the reply when it arrives as a new mailbox item.");
|
|
6705
6711
|
stable.push("- For substantial work requests, create a `task_create` assigned to the target agent instead of asking via message.");
|
|
6706
6712
|
stable.push("- Do NOT use A2A messages for routine task status notifications \u2014 the system handles those automatically.");
|
|
6707
6713
|
}
|
|
@@ -7110,24 +7116,19 @@ ${ctx.mergedContent.slice(0, SYSTEM_MAILBOX_MERGED_CHARS)}`);
|
|
|
7110
7116
|
lines.push("If nothing needs attention, respond with exactly: HEARTBEAT_OK");
|
|
7111
7117
|
break;
|
|
7112
7118
|
case "a2a": {
|
|
7113
|
-
const waitForReply = extra?.a2aWaitForReply;
|
|
7114
7119
|
lines.push("You are in an **agent-to-agent (A2A) conversation**. This context is for COORDINATION, not for executing work.");
|
|
7115
7120
|
lines.push("");
|
|
7116
|
-
|
|
7117
|
-
|
|
7118
|
-
|
|
7119
|
-
|
|
7120
|
-
|
|
7121
|
-
|
|
7122
|
-
|
|
7123
|
-
|
|
7124
|
-
|
|
7125
|
-
|
|
7126
|
-
|
|
7127
|
-
lines.push("- The information changes your current work priorities");
|
|
7128
|
-
lines.push("- You have critical corrections to share");
|
|
7129
|
-
lines.push("Otherwise, absorb silently and continue your current work.");
|
|
7130
|
-
}
|
|
7121
|
+
lines.push("**Communication channel**: All A2A messaging is **asynchronous**. The sender is NOT blocking for your reply. Humans do NOT see this conversation.");
|
|
7122
|
+
lines.push("- To **reply to the sender**, use `agent_send_message` with the sender's agent ID and the same `conversation_id` (if present in the message as `[conversation:...]`).");
|
|
7123
|
+
lines.push("- To reach a **human**, use `notify_user`.");
|
|
7124
|
+
lines.push("- To reach a **different agent**, use `agent_send_message`.");
|
|
7125
|
+
lines.push("- If no response is needed, just process the information silently (e.g., update your state, create tasks, take notes).");
|
|
7126
|
+
lines.push("");
|
|
7127
|
+
lines.push("**A2A etiquette**: Only act if:");
|
|
7128
|
+
lines.push("- The message contains a direct question or request for you");
|
|
7129
|
+
lines.push("- The information changes your current work priorities");
|
|
7130
|
+
lines.push("- You have critical corrections to share");
|
|
7131
|
+
lines.push("Otherwise, absorb silently and continue your current work.");
|
|
7131
7132
|
lines.push("");
|
|
7132
7133
|
lines.push("**Communication rules:**");
|
|
7133
7134
|
lines.push("- Be concise and structured \u2014 your colleague needs actionable information");
|
|
@@ -8913,18 +8914,33 @@ var init_tool_selector = __esm({
|
|
|
8913
8914
|
});
|
|
8914
8915
|
pushUnique({
|
|
8915
8916
|
name: "complete_deliberation",
|
|
8916
|
-
description: "Finalize your mailbox deliberation. Declare which item to process next, which to defer/drop, and which you handled inline. Only available in deliberation mode.",
|
|
8917
|
+
description: "Finalize your mailbox deliberation. Declare which item(s) to process next, which to defer/drop, and which you handled inline. Supports batch processing: pass multiple IDs in process_item_ids to handle related items together in one session. Only available in deliberation mode.",
|
|
8917
8918
|
inputSchema: {
|
|
8918
8919
|
type: "object",
|
|
8919
8920
|
properties: {
|
|
8920
|
-
process_item_id: { type: "string", description: "ID of the mailbox item to process
|
|
8921
|
+
process_item_id: { type: "string", description: "ID of the primary mailbox item to process next. Required unless process_item_ids is provided." },
|
|
8922
|
+
process_item_ids: { type: "array", items: { type: "string" }, description: "Batch mode: IDs of multiple items to process together in one session. Use for related items (same channel, same topic). Overrides process_item_id when length > 1." },
|
|
8923
|
+
batch_context: { type: "string", description: "When using batch mode, optional synthesis/instruction for how to handle the batch together." },
|
|
8921
8924
|
defer_item_ids: { type: "array", items: { type: "string" }, description: "IDs of items to defer for later" },
|
|
8922
8925
|
drop_item_ids: { type: "array", items: { type: "string" }, description: "IDs of stale/redundant items to drop" },
|
|
8923
8926
|
inline_completed_ids: { type: "array", items: { type: "string" }, description: "IDs of items you already handled inline during this deliberation (e.g., sent a notification, posted a comment)" },
|
|
8924
8927
|
reasoning: { type: "string", description: "1-2 sentence explanation of your decision" },
|
|
8925
|
-
situational_awareness: { type: "string", description: "Your current understanding of the situation \u2014 injected into future prompts for continuity" }
|
|
8928
|
+
situational_awareness: { type: "string", description: "Your current understanding of the situation \u2014 injected into future prompts for continuity" },
|
|
8929
|
+
memory_updates: {
|
|
8930
|
+
type: "array",
|
|
8931
|
+
items: {
|
|
8932
|
+
type: "object",
|
|
8933
|
+
properties: {
|
|
8934
|
+
type: { type: "string", enum: ["working", "longterm"], description: "working = volatile per-session memory, longterm = persisted to MEMORY.md" },
|
|
8935
|
+
key: { type: "string", description: "Memory key/section name" },
|
|
8936
|
+
content: { type: "string", description: "Content to store" }
|
|
8937
|
+
},
|
|
8938
|
+
required: ["type", "key", "content"]
|
|
8939
|
+
},
|
|
8940
|
+
description: "Memory updates to apply after deliberation. Use to record observations, team decisions, or context for future cycles."
|
|
8941
|
+
}
|
|
8926
8942
|
},
|
|
8927
|
-
required: ["
|
|
8943
|
+
required: ["reasoning"]
|
|
8928
8944
|
}
|
|
8929
8945
|
});
|
|
8930
8946
|
pushUnique({
|
|
@@ -41899,14 +41915,14 @@ var require_turndown_cjs = __commonJS({
|
|
|
41899
41915
|
} else if (node.nodeType === 1) {
|
|
41900
41916
|
replacement = replacementForNode.call(self, node);
|
|
41901
41917
|
}
|
|
41902
|
-
return
|
|
41918
|
+
return join32(output, replacement);
|
|
41903
41919
|
}, "");
|
|
41904
41920
|
}
|
|
41905
41921
|
function postProcess(output) {
|
|
41906
41922
|
var self = this;
|
|
41907
41923
|
this.rules.forEach(function(rule) {
|
|
41908
41924
|
if (typeof rule.append === "function") {
|
|
41909
|
-
output =
|
|
41925
|
+
output = join32(output, rule.append(self.options));
|
|
41910
41926
|
}
|
|
41911
41927
|
});
|
|
41912
41928
|
return output.replace(/^[\t\r\n]+/, "").replace(/[\t\r\n\s]+$/, "");
|
|
@@ -41918,7 +41934,7 @@ var require_turndown_cjs = __commonJS({
|
|
|
41918
41934
|
if (whitespace2.leading || whitespace2.trailing) content = content.trim();
|
|
41919
41935
|
return whitespace2.leading + rule.replacement(content, node, this.options) + whitespace2.trailing;
|
|
41920
41936
|
}
|
|
41921
|
-
function
|
|
41937
|
+
function join32(output, replacement) {
|
|
41922
41938
|
var s1 = trimTrailingNewlines(output);
|
|
41923
41939
|
var s2 = trimLeadingNewlines(replacement);
|
|
41924
41940
|
var nls = Math.max(output.length - s1.length, replacement.length - s2.length);
|
|
@@ -42144,6 +42160,113 @@ async function searchSerper(query2, maxResults) {
|
|
|
42144
42160
|
date: r.date
|
|
42145
42161
|
}));
|
|
42146
42162
|
}
|
|
42163
|
+
async function searchTavily(query2, maxResults) {
|
|
42164
|
+
const apiKey = process.env["TAVILY_API_KEY"];
|
|
42165
|
+
if (!apiKey)
|
|
42166
|
+
throw new Error("TAVILY_API_KEY not configured");
|
|
42167
|
+
let res;
|
|
42168
|
+
try {
|
|
42169
|
+
res = await proxyFetch("https://api.tavily.com/search", {
|
|
42170
|
+
method: "POST",
|
|
42171
|
+
headers: { "Content-Type": "application/json" },
|
|
42172
|
+
body: JSON.stringify({
|
|
42173
|
+
api_key: apiKey,
|
|
42174
|
+
query: query2,
|
|
42175
|
+
max_results: maxResults,
|
|
42176
|
+
include_answer: false
|
|
42177
|
+
})
|
|
42178
|
+
});
|
|
42179
|
+
} catch (err) {
|
|
42180
|
+
throw new Error(`Network error: ${err instanceof Error ? err.message : String(err)}`);
|
|
42181
|
+
}
|
|
42182
|
+
if (!res.ok)
|
|
42183
|
+
throw new Error(`HTTP ${res.status} ${res.statusText}`);
|
|
42184
|
+
const data = await res.json();
|
|
42185
|
+
return (data.results ?? []).slice(0, maxResults).map((r) => ({
|
|
42186
|
+
title: r.title,
|
|
42187
|
+
url: r.url,
|
|
42188
|
+
snippet: r.content,
|
|
42189
|
+
date: r.published_date
|
|
42190
|
+
}));
|
|
42191
|
+
}
|
|
42192
|
+
async function searchBing(query2, maxResults) {
|
|
42193
|
+
const apiKey = process.env["BING_SEARCH_API_KEY"];
|
|
42194
|
+
if (!apiKey)
|
|
42195
|
+
throw new Error("BING_SEARCH_API_KEY not configured");
|
|
42196
|
+
const params = new URLSearchParams({ q: query2, count: String(maxResults), mkt: "en-US" });
|
|
42197
|
+
let res;
|
|
42198
|
+
try {
|
|
42199
|
+
res = await proxyFetch(`https://api.bing.microsoft.com/v7.0/search?${params}`, {
|
|
42200
|
+
headers: { "Ocp-Apim-Subscription-Key": apiKey }
|
|
42201
|
+
});
|
|
42202
|
+
} catch (err) {
|
|
42203
|
+
throw new Error(`Network error: ${err instanceof Error ? err.message : String(err)}`);
|
|
42204
|
+
}
|
|
42205
|
+
if (!res.ok)
|
|
42206
|
+
throw new Error(`HTTP ${res.status} ${res.statusText}`);
|
|
42207
|
+
const data = await res.json();
|
|
42208
|
+
return (data.webPages?.value ?? []).slice(0, maxResults).map((r) => ({
|
|
42209
|
+
title: r.name,
|
|
42210
|
+
url: r.url,
|
|
42211
|
+
snippet: r.snippet,
|
|
42212
|
+
date: r.dateLastCrawled
|
|
42213
|
+
}));
|
|
42214
|
+
}
|
|
42215
|
+
async function searchGoogle(query2, maxResults) {
|
|
42216
|
+
const apiKey = process.env["GOOGLE_SEARCH_API_KEY"];
|
|
42217
|
+
const cx = process.env["GOOGLE_SEARCH_CX"];
|
|
42218
|
+
if (!apiKey)
|
|
42219
|
+
throw new Error("GOOGLE_SEARCH_API_KEY not configured");
|
|
42220
|
+
if (!cx)
|
|
42221
|
+
throw new Error("GOOGLE_SEARCH_CX not configured");
|
|
42222
|
+
const params = new URLSearchParams({
|
|
42223
|
+
key: apiKey,
|
|
42224
|
+
cx,
|
|
42225
|
+
q: query2,
|
|
42226
|
+
num: String(Math.min(maxResults, 10))
|
|
42227
|
+
});
|
|
42228
|
+
let res;
|
|
42229
|
+
try {
|
|
42230
|
+
res = await proxyFetch(`https://www.googleapis.com/customsearch/v1?${params}`);
|
|
42231
|
+
} catch (err) {
|
|
42232
|
+
throw new Error(`Network error: ${err instanceof Error ? err.message : String(err)}`);
|
|
42233
|
+
}
|
|
42234
|
+
if (!res.ok)
|
|
42235
|
+
throw new Error(`HTTP ${res.status} ${res.statusText}`);
|
|
42236
|
+
const data = await res.json();
|
|
42237
|
+
return (data.items ?? []).slice(0, maxResults).map((r) => ({
|
|
42238
|
+
title: r.title,
|
|
42239
|
+
url: r.link,
|
|
42240
|
+
snippet: r.snippet,
|
|
42241
|
+
date: r.pagemap?.metatags?.[0]?.["article:published_time"]
|
|
42242
|
+
}));
|
|
42243
|
+
}
|
|
42244
|
+
async function searchSerpApi(query2, maxResults) {
|
|
42245
|
+
const apiKey = process.env["SERPAPI_API_KEY"];
|
|
42246
|
+
if (!apiKey)
|
|
42247
|
+
throw new Error("SERPAPI_API_KEY not configured");
|
|
42248
|
+
const params = new URLSearchParams({
|
|
42249
|
+
api_key: apiKey,
|
|
42250
|
+
q: query2,
|
|
42251
|
+
engine: "google",
|
|
42252
|
+
num: String(maxResults)
|
|
42253
|
+
});
|
|
42254
|
+
let res;
|
|
42255
|
+
try {
|
|
42256
|
+
res = await proxyFetch(`https://serpapi.com/search.json?${params}`);
|
|
42257
|
+
} catch (err) {
|
|
42258
|
+
throw new Error(`Network error: ${err instanceof Error ? err.message : String(err)}`);
|
|
42259
|
+
}
|
|
42260
|
+
if (!res.ok)
|
|
42261
|
+
throw new Error(`HTTP ${res.status} ${res.statusText}`);
|
|
42262
|
+
const data = await res.json();
|
|
42263
|
+
return (data.organic_results ?? []).slice(0, maxResults).map((r) => ({
|
|
42264
|
+
title: r.title,
|
|
42265
|
+
url: r.link,
|
|
42266
|
+
snippet: r.snippet,
|
|
42267
|
+
date: r.date
|
|
42268
|
+
}));
|
|
42269
|
+
}
|
|
42147
42270
|
async function searchBrave(query2, maxResults) {
|
|
42148
42271
|
const apiKey = process.env["BRAVE_SEARCH_API_KEY"];
|
|
42149
42272
|
if (!apiKey)
|
|
@@ -42171,6 +42294,38 @@ async function searchBrave(query2, maxResults) {
|
|
|
42171
42294
|
date: r.page_age
|
|
42172
42295
|
}));
|
|
42173
42296
|
}
|
|
42297
|
+
async function searchExa(query2, maxResults) {
|
|
42298
|
+
const apiKey = process.env["EXA_API_KEY"];
|
|
42299
|
+
if (!apiKey)
|
|
42300
|
+
throw new Error("EXA_API_KEY not configured");
|
|
42301
|
+
let res;
|
|
42302
|
+
try {
|
|
42303
|
+
res = await proxyFetch("https://api.exa.ai/search", {
|
|
42304
|
+
method: "POST",
|
|
42305
|
+
headers: {
|
|
42306
|
+
"x-api-key": apiKey,
|
|
42307
|
+
"Content-Type": "application/json"
|
|
42308
|
+
},
|
|
42309
|
+
body: JSON.stringify({
|
|
42310
|
+
query: query2,
|
|
42311
|
+
numResults: maxResults,
|
|
42312
|
+
type: "auto",
|
|
42313
|
+
contents: { text: { maxCharacters: 300 } }
|
|
42314
|
+
})
|
|
42315
|
+
});
|
|
42316
|
+
} catch (err) {
|
|
42317
|
+
throw new Error(`Network error: ${err instanceof Error ? err.message : String(err)}`);
|
|
42318
|
+
}
|
|
42319
|
+
if (!res.ok)
|
|
42320
|
+
throw new Error(`HTTP ${res.status} ${res.statusText}`);
|
|
42321
|
+
const data = await res.json();
|
|
42322
|
+
return (data.results ?? []).slice(0, maxResults).map((r) => ({
|
|
42323
|
+
title: r.title,
|
|
42324
|
+
url: r.url,
|
|
42325
|
+
snippet: r.text ?? "",
|
|
42326
|
+
date: r.publishedDate
|
|
42327
|
+
}));
|
|
42328
|
+
}
|
|
42174
42329
|
async function searchBocha(query2, maxResults) {
|
|
42175
42330
|
const apiKey = process.env["BOCHA_API_KEY"];
|
|
42176
42331
|
if (!apiKey)
|
|
@@ -42314,7 +42469,12 @@ var init_web_search = __esm({
|
|
|
42314
42469
|
const maxResults = args["maxResults"] ?? 8;
|
|
42315
42470
|
const backends = [
|
|
42316
42471
|
{ name: "Serper", fn: searchSerper },
|
|
42472
|
+
{ name: "Tavily", fn: searchTavily },
|
|
42473
|
+
{ name: "Bing", fn: searchBing },
|
|
42474
|
+
{ name: "Google", fn: searchGoogle },
|
|
42475
|
+
{ name: "SerpAPI", fn: searchSerpApi },
|
|
42317
42476
|
{ name: "Brave", fn: searchBrave },
|
|
42477
|
+
{ name: "Exa", fn: searchExa },
|
|
42318
42478
|
{ name: "Bocha", fn: searchBocha },
|
|
42319
42479
|
{ name: "DuckDuckGo", fn: searchDuckDuckGo }
|
|
42320
42480
|
];
|
|
@@ -43688,6 +43848,7 @@ var init_mailbox2 = __esm({
|
|
|
43688
43848
|
}
|
|
43689
43849
|
removed += this.mergeByEntity(_AgentMailbox.TASK_COMMENT_DEDUP_TYPES, (item) => item.payload.taskId ?? item.metadata?.taskId);
|
|
43690
43850
|
removed += this.mergeByEntity(_AgentMailbox.REQ_COMMENT_DEDUP_TYPES, (item) => item.payload.requirementId);
|
|
43851
|
+
removed += this.mergeByEntity(_AgentMailbox.CHANNEL_DEDUP_TYPES, (item) => item.payload.extra?.channelKey);
|
|
43691
43852
|
return removed;
|
|
43692
43853
|
}
|
|
43693
43854
|
/**
|
|
@@ -43823,6 +43984,9 @@ ${typeLabel}${item.payload.content}`;
|
|
|
43823
43984
|
static REQ_COMMENT_DEDUP_TYPES = /* @__PURE__ */ new Set([
|
|
43824
43985
|
"requirement_comment"
|
|
43825
43986
|
]);
|
|
43987
|
+
static CHANNEL_DEDUP_TYPES = /* @__PURE__ */ new Set([
|
|
43988
|
+
"a2a_message"
|
|
43989
|
+
]);
|
|
43826
43990
|
enqueue(sourceType, payload, options) {
|
|
43827
43991
|
const merged = this.tryMergeIntoExisting(sourceType, payload);
|
|
43828
43992
|
if (merged) {
|
|
@@ -44165,14 +44329,33 @@ ${typeLabel}${item.payload.content}`;
|
|
|
44165
44329
|
if (reqId) {
|
|
44166
44330
|
existing = this.queue.find((i) => i.status === "queued" && _AgentMailbox.REQ_COMMENT_DEDUP_TYPES.has(i.sourceType) && i.payload.requirementId === reqId);
|
|
44167
44331
|
}
|
|
44332
|
+
} else if (_AgentMailbox.CHANNEL_DEDUP_TYPES.has(sourceType)) {
|
|
44333
|
+
const channelKey = payload.extra?.channelKey;
|
|
44334
|
+
if (channelKey) {
|
|
44335
|
+
existing = this.queue.find((i) => i.status === "queued" && _AgentMailbox.CHANNEL_DEDUP_TYPES.has(i.sourceType) && i.payload.extra?.channelKey === channelKey);
|
|
44336
|
+
}
|
|
44168
44337
|
}
|
|
44169
44338
|
if (!existing)
|
|
44170
44339
|
return void 0;
|
|
44171
|
-
|
|
44340
|
+
if (_AgentMailbox.CHANNEL_DEDUP_TYPES.has(sourceType) && payload.extra?.channelKey) {
|
|
44341
|
+
const senderName = payload.extra?.senderName || "unknown";
|
|
44342
|
+
const newMsg = { senderId: payload.extra?.senderId, senderName, content: payload.content, timestamp: (/* @__PURE__ */ new Date()).toISOString() };
|
|
44343
|
+
if (!existing.payload.messages) {
|
|
44344
|
+
const existingSender = existing.payload.extra?.senderName || "unknown";
|
|
44345
|
+
existing.payload.messages = [{ senderId: existing.payload.extra?.senderId, senderName: existingSender, content: existing.payload.content, timestamp: existing.queuedAt }];
|
|
44346
|
+
}
|
|
44347
|
+
existing.payload.messages.push(newMsg);
|
|
44348
|
+
existing.payload.content += `
|
|
44349
|
+
|
|
44350
|
+
---
|
|
44351
|
+
[${senderName}]: ${payload.content}`;
|
|
44352
|
+
} else {
|
|
44353
|
+
existing.payload.content += `
|
|
44172
44354
|
|
|
44173
44355
|
---
|
|
44174
44356
|
|
|
44175
44357
|
${payload.content}`;
|
|
44358
|
+
}
|
|
44176
44359
|
existing.payload.summary += ` (+1)`;
|
|
44177
44360
|
this.persistence?.updateStatus(existing.id, "queued", existing);
|
|
44178
44361
|
log13.debug("Mailbox enqueue-time dedup: merged into existing item", {
|
|
@@ -44183,12 +44366,15 @@ ${payload.content}`;
|
|
|
44183
44366
|
return existing;
|
|
44184
44367
|
}
|
|
44185
44368
|
/**
|
|
44186
|
-
* Insert item into the queue maintaining priority
|
|
44369
|
+
* Insert item into the queue maintaining priority order.
|
|
44370
|
+
* Within the same priority, newer items go first (LIFO) so the most
|
|
44371
|
+
* recent message is processed before older ones — a user's latest
|
|
44372
|
+
* instruction may supersede earlier ones.
|
|
44187
44373
|
*/
|
|
44188
44374
|
insertSorted(item) {
|
|
44189
44375
|
let insertIdx = this.queue.length;
|
|
44190
44376
|
for (let i = 0; i < this.queue.length; i++) {
|
|
44191
|
-
if (this.queue[i].priority
|
|
44377
|
+
if (this.queue[i].priority >= item.priority) {
|
|
44192
44378
|
insertIdx = i;
|
|
44193
44379
|
break;
|
|
44194
44380
|
}
|
|
@@ -44240,6 +44426,8 @@ var init_attention = __esm({
|
|
|
44240
44426
|
lastTriageResult;
|
|
44241
44427
|
/** True while a full-session deliberation is in progress (suppresses yield points). */
|
|
44242
44428
|
isDeliberating = false;
|
|
44429
|
+
/** Set to true when a human_chat arrives during deliberation, causing early abort. */
|
|
44430
|
+
deliberationAbortSignal = false;
|
|
44243
44431
|
/** Tracks whether the last yield-point decision was 'cancel' vs 'preempt'. */
|
|
44244
44432
|
lastYieldDecision;
|
|
44245
44433
|
unsubscribeNewItem;
|
|
@@ -44340,7 +44528,7 @@ var init_attention = __esm({
|
|
|
44340
44528
|
});
|
|
44341
44529
|
this.launchLoop();
|
|
44342
44530
|
}
|
|
44343
|
-
if (this.running && !this.currentFocus && this.state === "idle") {
|
|
44531
|
+
if (this.running && !this.currentFocus && (this.state === "idle" || this.state === "deciding")) {
|
|
44344
44532
|
try {
|
|
44345
44533
|
const cleaned = this.mailbox.cleanStaleProcessing();
|
|
44346
44534
|
if (cleaned > 0) {
|
|
@@ -44408,6 +44596,9 @@ var init_attention = __esm({
|
|
|
44408
44596
|
try {
|
|
44409
44597
|
this.setState("deciding");
|
|
44410
44598
|
const isUserMessage = _AttentionController.USER_INTERACTION_TYPES.has(item.sourceType);
|
|
44599
|
+
if (!isUserMessage && MAILBOX_COALESCE_WINDOW_MS > 0 && this.mailbox.depth > 0) {
|
|
44600
|
+
await new Promise((r) => setTimeout(r, MAILBOX_COALESCE_WINDOW_MS));
|
|
44601
|
+
}
|
|
44411
44602
|
if (this.mailbox.depth > 0 && !isUserMessage) {
|
|
44412
44603
|
this.mailbox.putBack(item);
|
|
44413
44604
|
const purged = this.mailbox.purgeStaleItems();
|
|
@@ -44434,14 +44625,23 @@ var init_attention = __esm({
|
|
|
44434
44625
|
deliberationAttempted = true;
|
|
44435
44626
|
const allItems = [item, ...this.mailbox.getQueuedItems()];
|
|
44436
44627
|
this.isDeliberating = true;
|
|
44628
|
+
this.deliberationAbortSignal = false;
|
|
44437
44629
|
try {
|
|
44438
44630
|
const deliberationResult = await this.delegate.performDeliberation(item, allItems);
|
|
44439
|
-
if (
|
|
44631
|
+
if (this.deliberationAbortSignal) {
|
|
44632
|
+
log14.info("Deliberation aborted: human_chat arrived", { agentId: this.agentId });
|
|
44633
|
+
this.mailbox.putBack(item);
|
|
44634
|
+
const userItem = this.mailbox.dequeue();
|
|
44635
|
+
if (userItem) {
|
|
44636
|
+
item = userItem;
|
|
44637
|
+
}
|
|
44638
|
+
} else if (deliberationResult) {
|
|
44440
44639
|
triaged = true;
|
|
44441
44640
|
item = this.applyDeliberationResult(item, deliberationResult);
|
|
44442
44641
|
}
|
|
44443
44642
|
} finally {
|
|
44444
44643
|
this.isDeliberating = false;
|
|
44644
|
+
this.deliberationAbortSignal = false;
|
|
44445
44645
|
}
|
|
44446
44646
|
} else {
|
|
44447
44647
|
deliberationAttempted = true;
|
|
@@ -44515,10 +44715,14 @@ var init_attention = __esm({
|
|
|
44515
44715
|
this.lastYieldDecision = void 0;
|
|
44516
44716
|
this.processingStartedAt = Date.now();
|
|
44517
44717
|
this.delegate?.onFocusChanged(item);
|
|
44718
|
+
const batchItems = this.pendingBatchItems.length > 0 ? [...this.pendingBatchItems] : void 0;
|
|
44719
|
+
const batchContext = this.pendingBatchContext;
|
|
44720
|
+
this.pendingBatchItems = [];
|
|
44721
|
+
this.pendingBatchContext = void 0;
|
|
44518
44722
|
let reply = void 0;
|
|
44519
44723
|
let timedOut = false;
|
|
44520
44724
|
try {
|
|
44521
|
-
const processing = this.delegate?.processMailboxItem(item);
|
|
44725
|
+
const processing = this.delegate?.processMailboxItem(item, batchItems, batchContext);
|
|
44522
44726
|
const backstopMs = this.waitingForHumanApproval ? APPROVAL_WAIT_TIMEOUT_MS : MAILBOX_PROCESSING_TIMEOUT_MS;
|
|
44523
44727
|
const backstop = new Promise((resolve22) => setTimeout(() => resolve22(void 0), backstopMs));
|
|
44524
44728
|
const result = await Promise.race([
|
|
@@ -44608,6 +44812,16 @@ var init_attention = __esm({
|
|
|
44608
44812
|
});
|
|
44609
44813
|
this.mailbox.complete(item.id);
|
|
44610
44814
|
}
|
|
44815
|
+
if (batchItems && batchItems.length > 0) {
|
|
44816
|
+
const wasSuccessful = !timedOut && reply !== "[cancelled]" && reply !== "[preempted]" && this.lastYieldDecision !== "cancel" && this.lastYieldDecision !== "preempt";
|
|
44817
|
+
for (const bi of batchItems) {
|
|
44818
|
+
if (wasSuccessful) {
|
|
44819
|
+
this.mailbox.complete(bi.id);
|
|
44820
|
+
} else {
|
|
44821
|
+
this.mailbox.requeue(bi);
|
|
44822
|
+
}
|
|
44823
|
+
}
|
|
44824
|
+
}
|
|
44611
44825
|
this.currentFocus = void 0;
|
|
44612
44826
|
this.interruptSignal = false;
|
|
44613
44827
|
this.pendingInterruptItem = void 0;
|
|
@@ -44627,6 +44841,9 @@ var init_attention = __esm({
|
|
|
44627
44841
|
const peeked = this.mailbox.peek();
|
|
44628
44842
|
if (peeked) {
|
|
44629
44843
|
this.pendingInterruptItem = peeked;
|
|
44844
|
+
if (this.isDeliberating && _AttentionController.USER_INTERACTION_TYPES.has(peeked.sourceType)) {
|
|
44845
|
+
this.deliberationAbortSignal = true;
|
|
44846
|
+
}
|
|
44630
44847
|
const wouldPreempt = this.currentFocus ? this.heuristicDecision(this.currentFocus, peeked) === "preempt" : false;
|
|
44631
44848
|
if (wouldPreempt && this.criticalInterruptResolve) {
|
|
44632
44849
|
this.criticalInterruptResolve();
|
|
@@ -44661,6 +44878,10 @@ var init_attention = __esm({
|
|
|
44661
44878
|
clearLastYieldDecision() {
|
|
44662
44879
|
this.lastYieldDecision = void 0;
|
|
44663
44880
|
}
|
|
44881
|
+
/** True if a human_chat arrived during deliberation, signalling early abort. */
|
|
44882
|
+
get shouldAbortDeliberation() {
|
|
44883
|
+
return this.deliberationAbortSignal;
|
|
44884
|
+
}
|
|
44664
44885
|
/**
|
|
44665
44886
|
* Called from the Agent's tool loop at safe yield points (between LLM turns).
|
|
44666
44887
|
* If an interrupt signal is pending, evaluates whether to continue or switch.
|
|
@@ -44755,6 +44976,9 @@ var init_attention = __esm({
|
|
|
44755
44976
|
heuristicDecision(currentItem, newItem) {
|
|
44756
44977
|
const isNewUserInteraction = _AttentionController.USER_INTERACTION_TYPES.has(newItem.sourceType);
|
|
44757
44978
|
const isCurrentUserInteraction = _AttentionController.USER_INTERACTION_TYPES.has(currentItem.sourceType);
|
|
44979
|
+
if (newItem.sourceType === "human_chat" && currentItem.sourceType === "human_chat" && newItem.metadata?.senderId && newItem.metadata.senderId === currentItem.metadata?.senderId) {
|
|
44980
|
+
return "merge";
|
|
44981
|
+
}
|
|
44758
44982
|
if (isNewUserInteraction && !isCurrentUserInteraction) {
|
|
44759
44983
|
return "preempt";
|
|
44760
44984
|
}
|
|
@@ -45020,6 +45244,9 @@ var init_attention = __esm({
|
|
|
45020
45244
|
* Apply a DeliberationResult to the mailbox: handle inline completions, reorder, defer, drop.
|
|
45021
45245
|
* Returns the item to process next.
|
|
45022
45246
|
*/
|
|
45247
|
+
/** Batch items dequeued for the current processing cycle (set by applyDeliberationResult). */
|
|
45248
|
+
pendingBatchItems = [];
|
|
45249
|
+
pendingBatchContext;
|
|
45023
45250
|
applyDeliberationResult(currentItem, result) {
|
|
45024
45251
|
let item = currentItem;
|
|
45025
45252
|
const queueSnapshot = this.mailbox.getQueuedItems();
|
|
@@ -45035,12 +45262,13 @@ var init_attention = __esm({
|
|
|
45035
45262
|
return true;
|
|
45036
45263
|
return false;
|
|
45037
45264
|
};
|
|
45265
|
+
const effectiveProcessIds = result.processItemIds && result.processItemIds.length > 0 ? result.processItemIds : [result.processItemId];
|
|
45038
45266
|
for (const completedId of result.inlineCompletedIds) {
|
|
45039
45267
|
if (isProtected(completedId))
|
|
45040
45268
|
continue;
|
|
45041
45269
|
if (completedId === currentItem.id)
|
|
45042
45270
|
continue;
|
|
45043
|
-
if (completedId
|
|
45271
|
+
if (effectiveProcessIds.includes(completedId))
|
|
45044
45272
|
continue;
|
|
45045
45273
|
const completedItem = queueSnapshot.find((i) => i.id === completedId);
|
|
45046
45274
|
this.mailbox.complete(completedId);
|
|
@@ -45048,15 +45276,16 @@ var init_attention = __esm({
|
|
|
45048
45276
|
this.recordDecision("complete", completedItem, "Handled inline during deliberation");
|
|
45049
45277
|
}
|
|
45050
45278
|
}
|
|
45051
|
-
|
|
45279
|
+
const primaryId = effectiveProcessIds[0];
|
|
45280
|
+
if (primaryId !== item.id) {
|
|
45052
45281
|
this.mailbox.putBack(item);
|
|
45053
|
-
const chosen = this.mailbox.dequeueById(
|
|
45282
|
+
const chosen = this.mailbox.dequeueById(primaryId);
|
|
45054
45283
|
if (chosen) {
|
|
45055
45284
|
item = chosen;
|
|
45056
45285
|
} else {
|
|
45057
45286
|
log14.warn("Deliberation chose item that is no longer in queue, falling back to head", {
|
|
45058
45287
|
agentId: this.agentId,
|
|
45059
|
-
chosenId:
|
|
45288
|
+
chosenId: primaryId,
|
|
45060
45289
|
fallbackId: currentItem.id
|
|
45061
45290
|
});
|
|
45062
45291
|
const redequeued = this.mailbox.dequeueById(currentItem.id);
|
|
@@ -45064,6 +45293,19 @@ var init_attention = __esm({
|
|
|
45064
45293
|
item = redequeued;
|
|
45065
45294
|
}
|
|
45066
45295
|
}
|
|
45296
|
+
this.pendingBatchItems = [];
|
|
45297
|
+
this.pendingBatchContext = result.batchContext;
|
|
45298
|
+
if (effectiveProcessIds.length > 1) {
|
|
45299
|
+
for (let i = 1; i < effectiveProcessIds.length; i++) {
|
|
45300
|
+
const batchId = effectiveProcessIds[i];
|
|
45301
|
+
if (isProtected(batchId))
|
|
45302
|
+
continue;
|
|
45303
|
+
const batchItem = this.mailbox.dequeueById(batchId);
|
|
45304
|
+
if (batchItem) {
|
|
45305
|
+
this.pendingBatchItems.push(batchItem);
|
|
45306
|
+
}
|
|
45307
|
+
}
|
|
45308
|
+
}
|
|
45067
45309
|
for (const deferId of result.deferItemIds) {
|
|
45068
45310
|
if (isProtected(deferId))
|
|
45069
45311
|
continue;
|
|
@@ -45074,8 +45316,11 @@ var init_attention = __esm({
|
|
|
45074
45316
|
continue;
|
|
45075
45317
|
this.mailbox.drop(dropId);
|
|
45076
45318
|
}
|
|
45319
|
+
if (result.memoryUpdates && result.memoryUpdates.length > 0) {
|
|
45320
|
+
this.delegate?.applyMemoryUpdates?.(result.memoryUpdates);
|
|
45321
|
+
}
|
|
45077
45322
|
const triageEquivalent = {
|
|
45078
|
-
processItemId:
|
|
45323
|
+
processItemId: primaryId,
|
|
45079
45324
|
deferItemIds: result.deferItemIds,
|
|
45080
45325
|
dropItemIds: result.dropItemIds,
|
|
45081
45326
|
inlineCompletedIds: result.inlineCompletedIds,
|
|
@@ -45191,6 +45436,7 @@ var init_attention = __esm({
|
|
|
45191
45436
|
const queued = this.mailbox.getQueuedItems();
|
|
45192
45437
|
return {
|
|
45193
45438
|
attentionState: this.state,
|
|
45439
|
+
isDeliberating: this.isDeliberating || void 0,
|
|
45194
45440
|
currentFocus: this.currentFocus ? {
|
|
45195
45441
|
mailboxItemId: this.currentFocus.id,
|
|
45196
45442
|
type: this.currentFocus.sourceType,
|
|
@@ -46517,8 +46763,10 @@ var init_agent2 = __esm({
|
|
|
46517
46763
|
onActivityStartCb;
|
|
46518
46764
|
onActivityLogCb;
|
|
46519
46765
|
onActivityEndCb;
|
|
46766
|
+
browserCloseTabsHelper;
|
|
46520
46767
|
dynamicContextProviders = /* @__PURE__ */ new Map();
|
|
46521
46768
|
static MAX_ACTIVITY_LOG_ENTRIES = 200;
|
|
46769
|
+
static BROWSER_CLOSE_FOLLOWUP_MAX_ITER = 5;
|
|
46522
46770
|
static MAX_ACTIVITY_LOGS_KEPT = 10;
|
|
46523
46771
|
static MAX_CONCURRENT_TASKS = 1;
|
|
46524
46772
|
static MAX_CONSECUTIVE_FAILURES = 3;
|
|
@@ -46528,6 +46776,9 @@ var init_agent2 = __esm({
|
|
|
46528
46776
|
static NETWORK_RETRY_BASE_MS = 2e3;
|
|
46529
46777
|
static MEMORY_CONSOLIDATION_INTERVAL_MS = 4 * 60 * 60 * 1e3;
|
|
46530
46778
|
// 4 hours
|
|
46779
|
+
static MAX_CONCURRENT_DREAMS = 3;
|
|
46780
|
+
static dreamSemaphore = 0;
|
|
46781
|
+
static dreamQueue = [];
|
|
46531
46782
|
static DEFAULT_MAX_TOOL_ITERATIONS = 200;
|
|
46532
46783
|
static HEARTBEAT_MAX_TOOL_ITERATIONS = 30;
|
|
46533
46784
|
/** Maps background_exec session IDs to the originating session that spawned them */
|
|
@@ -46702,17 +46953,48 @@ ${notification.stdoutTail}`);
|
|
|
46702
46953
|
}
|
|
46703
46954
|
this.heartbeat.start(options?.initialHeartbeatDelayMs);
|
|
46704
46955
|
this.attentionController.start();
|
|
46705
|
-
this.
|
|
46706
|
-
this.consolidateMemory().catch((e) => log17.warn("Memory consolidation failed", { error: String(e) }));
|
|
46707
|
-
}, _Agent.MEMORY_CONSOLIDATION_INTERVAL_MS);
|
|
46956
|
+
this.scheduleConsolidationTimer();
|
|
46708
46957
|
this.eventBus.emit("agent:started", { agentId: this.id });
|
|
46709
46958
|
log17.info(`Agent started: ${this.config.name}`);
|
|
46710
46959
|
}
|
|
46960
|
+
consolidationInitialTimer;
|
|
46961
|
+
scheduleConsolidationTimer() {
|
|
46962
|
+
const jitter = Math.floor(Math.random() * _Agent.MEMORY_CONSOLIDATION_INTERVAL_MS);
|
|
46963
|
+
this.consolidationInitialTimer = setTimeout(() => {
|
|
46964
|
+
this.consolidationInitialTimer = void 0;
|
|
46965
|
+
this.consolidateMemory().catch((e) => log17.warn("Memory consolidation failed", { error: String(e) }));
|
|
46966
|
+
this.memoryConsolidationTimer = setInterval(() => {
|
|
46967
|
+
this.consolidateMemory().catch((e) => log17.warn("Memory consolidation failed", { error: String(e) }));
|
|
46968
|
+
}, _Agent.MEMORY_CONSOLIDATION_INTERVAL_MS);
|
|
46969
|
+
}, jitter);
|
|
46970
|
+
}
|
|
46971
|
+
static acquireDreamSlot() {
|
|
46972
|
+
if (_Agent.dreamSemaphore < _Agent.MAX_CONCURRENT_DREAMS) {
|
|
46973
|
+
_Agent.dreamSemaphore++;
|
|
46974
|
+
return Promise.resolve();
|
|
46975
|
+
}
|
|
46976
|
+
return new Promise((resolve22) => {
|
|
46977
|
+
_Agent.dreamQueue.push(() => {
|
|
46978
|
+
_Agent.dreamSemaphore++;
|
|
46979
|
+
resolve22();
|
|
46980
|
+
});
|
|
46981
|
+
});
|
|
46982
|
+
}
|
|
46983
|
+
static releaseDreamSlot() {
|
|
46984
|
+
_Agent.dreamSemaphore--;
|
|
46985
|
+
const next = _Agent.dreamQueue.shift();
|
|
46986
|
+
if (next)
|
|
46987
|
+
next();
|
|
46988
|
+
}
|
|
46711
46989
|
async stop() {
|
|
46712
46990
|
this.cancelActiveStream();
|
|
46713
46991
|
this.attentionController.stop();
|
|
46714
46992
|
this.heartbeat.stop();
|
|
46715
46993
|
this._bgCompletionUnsub?.();
|
|
46994
|
+
if (this.consolidationInitialTimer) {
|
|
46995
|
+
clearTimeout(this.consolidationInitialTimer);
|
|
46996
|
+
this.consolidationInitialTimer = void 0;
|
|
46997
|
+
}
|
|
46716
46998
|
if (this.memoryConsolidationTimer) {
|
|
46717
46999
|
clearInterval(this.memoryConsolidationTimer);
|
|
46718
47000
|
this.memoryConsolidationTimer = void 0;
|
|
@@ -46861,7 +47143,15 @@ ${notification.stdoutTail}`);
|
|
|
46861
47143
|
}
|
|
46862
47144
|
/** Get the current cognitive state of the agent. */
|
|
46863
47145
|
getMindState() {
|
|
46864
|
-
|
|
47146
|
+
const mind = this.attentionController.getMindState();
|
|
47147
|
+
if (mind.isDeliberating && this.state.currentActivity) {
|
|
47148
|
+
mind.deliberationActivity = {
|
|
47149
|
+
activityId: this.state.currentActivity.id,
|
|
47150
|
+
label: this.state.currentActivity.label,
|
|
47151
|
+
startedAt: this.state.currentActivity.startedAt
|
|
47152
|
+
};
|
|
47153
|
+
}
|
|
47154
|
+
return mind;
|
|
46865
47155
|
}
|
|
46866
47156
|
/** Get the raw mailbox instance (for persistence wiring). */
|
|
46867
47157
|
getMailbox() {
|
|
@@ -46894,8 +47184,8 @@ ${notification.stdoutTail}`);
|
|
|
46894
47184
|
*/
|
|
46895
47185
|
createAttentionDelegate() {
|
|
46896
47186
|
return {
|
|
46897
|
-
processMailboxItem: async (item) => {
|
|
46898
|
-
return this.processMailboxItemInternal(item);
|
|
47187
|
+
processMailboxItem: async (item, batchItems, batchContext) => {
|
|
47188
|
+
return this.processMailboxItemInternal(item, batchItems, batchContext);
|
|
46899
47189
|
},
|
|
46900
47190
|
onDecisionMade: (decision) => {
|
|
46901
47191
|
log17.debug("Attention decision", {
|
|
@@ -46943,6 +47233,15 @@ ${notification.stdoutTail}`);
|
|
|
46943
47233
|
if (!result)
|
|
46944
47234
|
return;
|
|
46945
47235
|
this.updateCognitionFromDeliberation(result);
|
|
47236
|
+
},
|
|
47237
|
+
applyMemoryUpdates: (updates) => {
|
|
47238
|
+
for (const u of updates) {
|
|
47239
|
+
if (u.type === "working") {
|
|
47240
|
+
this.updateWorkingMemory(u.key, u.content);
|
|
47241
|
+
} else if (u.type === "longterm") {
|
|
47242
|
+
this.memory.addLongTermMemory(u.key, u.content);
|
|
47243
|
+
}
|
|
47244
|
+
}
|
|
46946
47245
|
}
|
|
46947
47246
|
};
|
|
46948
47247
|
}
|
|
@@ -46950,9 +47249,31 @@ ${notification.stdoutTail}`);
|
|
|
46950
47249
|
* Route a mailbox item to the appropriate Agent processing method.
|
|
46951
47250
|
* Options like sessionId/images/scenario are forwarded from payload.extra
|
|
46952
47251
|
* when present, falling back to type-appropriate defaults.
|
|
47252
|
+
* When batchItems are provided (from deliberation batch processing), their
|
|
47253
|
+
* content is composed into the primary item's message for unified handling.
|
|
46953
47254
|
*/
|
|
46954
|
-
async processMailboxItemInternal(item) {
|
|
47255
|
+
async processMailboxItemInternal(item, batchItems, batchContext) {
|
|
46955
47256
|
this.processingMailboxItemId = item.id;
|
|
47257
|
+
if (batchItems && batchItems.length > 0) {
|
|
47258
|
+
const batchHeader = batchContext ? `[BATCH PROCESSING \u2014 ${batchItems.length + 1} items]
|
|
47259
|
+
${batchContext}
|
|
47260
|
+
|
|
47261
|
+
---
|
|
47262
|
+
|
|
47263
|
+
` : `[BATCH PROCESSING \u2014 ${batchItems.length + 1} items]
|
|
47264
|
+
Process the following items together and respond comprehensively.
|
|
47265
|
+
|
|
47266
|
+
---
|
|
47267
|
+
|
|
47268
|
+
`;
|
|
47269
|
+
const batchSuffix = batchItems.map((bi, idx) => `
|
|
47270
|
+
|
|
47271
|
+
---
|
|
47272
|
+
[Item ${idx + 2}] (${bi.sourceType}) ${bi.payload.summary}:
|
|
47273
|
+
${bi.payload.content}`).join("");
|
|
47274
|
+
item.payload.content = batchHeader + `[Item 1] (${item.sourceType}) ${item.payload.summary}:
|
|
47275
|
+
${item.payload.content}` + batchSuffix;
|
|
47276
|
+
}
|
|
46956
47277
|
if (item.sourceType === "human_chat" && item.metadata?.senderId) {
|
|
46957
47278
|
this.currentInteractingUserId = item.metadata.senderId;
|
|
46958
47279
|
}
|
|
@@ -47285,6 +47606,10 @@ ${notification.stdoutTail}`);
|
|
|
47285
47606
|
this.cancelActiveStream();
|
|
47286
47607
|
this.heartbeat.stop();
|
|
47287
47608
|
this.attentionController.stop();
|
|
47609
|
+
if (this.consolidationInitialTimer) {
|
|
47610
|
+
clearTimeout(this.consolidationInitialTimer);
|
|
47611
|
+
this.consolidationInitialTimer = void 0;
|
|
47612
|
+
}
|
|
47288
47613
|
if (this.memoryConsolidationTimer) {
|
|
47289
47614
|
clearInterval(this.memoryConsolidationTimer);
|
|
47290
47615
|
this.memoryConsolidationTimer = void 0;
|
|
@@ -47301,9 +47626,7 @@ ${notification.stdoutTail}`);
|
|
|
47301
47626
|
this.heartbeat.start();
|
|
47302
47627
|
this.attentionController.start();
|
|
47303
47628
|
if (!this.memoryConsolidationTimer) {
|
|
47304
|
-
this.
|
|
47305
|
-
this.consolidateMemory().catch((e) => log17.warn("Memory consolidation failed", { error: String(e) }));
|
|
47306
|
-
}, _Agent.MEMORY_CONSOLIDATION_INTERVAL_MS);
|
|
47629
|
+
this.scheduleConsolidationTimer();
|
|
47307
47630
|
}
|
|
47308
47631
|
this.setStatus(this.activeTasks.size > 0 ? "working" : "idle");
|
|
47309
47632
|
this.eventBus.emit("agent:resumed", { agentId: this.id });
|
|
@@ -47875,13 +48198,14 @@ ${conversationText}`
|
|
|
47875
48198
|
"2. **Gather context**: `recall_activity`, `task_get`, `memory_search` for background.",
|
|
47876
48199
|
"3. **Manage queue**: `defer_mailbox_item` to postpone, `drop_mailbox_item` to discard stale items.",
|
|
47877
48200
|
"4. **Handle inline**: `notify_user`, `task_comment`, `agent_send_message` for trivial replies. Mark as inline_completed.",
|
|
47878
|
-
"5. **Save awareness**: `update_working_memory` to record
|
|
48201
|
+
"5. **Save awareness**: `update_working_memory` or `memory_save` to record observations.",
|
|
47879
48202
|
"6. **Decide**: `complete_deliberation` with your final focus decision.",
|
|
47880
48203
|
"",
|
|
47881
48204
|
"## Guidelines",
|
|
47882
48205
|
"- Human messages (priority 0) always take precedence.",
|
|
47883
|
-
"- Items sharing a taskId/requirementId/channel \
|
|
48206
|
+
"- **Batch processing**: Items sharing a taskId/requirementId/channel can be processed together \u2014 pass multiple IDs in `process_item_ids` and provide `batch_context` to guide unified handling.",
|
|
47884
48207
|
"- Drop old informational items (heartbeats, status updates) aggressively.",
|
|
48208
|
+
"- **Memory updates**: Use `memory_updates` in `complete_deliberation` to record team decisions, observations, or context that should persist across cycles.",
|
|
47885
48209
|
"- Your working memory persists across processing cycles \u2014 use it for continuity.",
|
|
47886
48210
|
"",
|
|
47887
48211
|
"When ready, call `complete_deliberation`."
|
|
@@ -48097,6 +48421,105 @@ ${instructions}
|
|
|
48097
48421
|
this.onActivityLogCb = cbs.onLog;
|
|
48098
48422
|
this.onActivityEndCb = cbs.onEnd;
|
|
48099
48423
|
}
|
|
48424
|
+
setBrowserCloseTabsHelper(fn) {
|
|
48425
|
+
this.browserCloseTabsHelper = fn;
|
|
48426
|
+
}
|
|
48427
|
+
/**
|
|
48428
|
+
* At session end: inject a one-time [SYSTEM] reminder if the session used
|
|
48429
|
+
* the browser and still has owned tabs, then run a lightweight LLM turn so
|
|
48430
|
+
* the agent can call close_page.
|
|
48431
|
+
*/
|
|
48432
|
+
async finalizeBrowserSession(sessionId) {
|
|
48433
|
+
if (!this.browserCloseTabsHelper)
|
|
48434
|
+
return;
|
|
48435
|
+
const reminder = this.browserCloseTabsHelper(sessionId);
|
|
48436
|
+
if (!reminder)
|
|
48437
|
+
return;
|
|
48438
|
+
try {
|
|
48439
|
+
this.memory.appendMessage(sessionId, { role: "user", content: reminder });
|
|
48440
|
+
log17.debug("Injected browser close-tabs reminder", { agentId: this.id, sessionId });
|
|
48441
|
+
const allTools = this.buildToolDefinitions({});
|
|
48442
|
+
const browserTools = allTools.filter((t) => t.name.startsWith("chrome-devtools__") && (t.name.endsWith("__close_page") || t.name.endsWith("__list_pages") || t.name.endsWith("__select_page")));
|
|
48443
|
+
if (browserTools.length === 0)
|
|
48444
|
+
return;
|
|
48445
|
+
const { text: systemPrompt, segments: systemCacheSegments } = await this.contextEngine.buildSystemPrompt({
|
|
48446
|
+
agentId: this.id,
|
|
48447
|
+
agentName: this.config.name,
|
|
48448
|
+
role: this.role,
|
|
48449
|
+
orgContext: this.orgContext,
|
|
48450
|
+
contextMdPath: this.contextMdPath,
|
|
48451
|
+
memory: this.memory,
|
|
48452
|
+
scenario: "chat",
|
|
48453
|
+
...this.getTeamContextParams()
|
|
48454
|
+
});
|
|
48455
|
+
const useCompaction = this.llmRouter.isCompactionSupported(this.getEffectiveProvider());
|
|
48456
|
+
const prepareFollowUpMessages = () => this.contextEngine.prepareMessages({
|
|
48457
|
+
systemPrompt,
|
|
48458
|
+
sessionMessages: this.memory.getRecentMessages(sessionId, 50),
|
|
48459
|
+
memory: this.memory,
|
|
48460
|
+
sessionId,
|
|
48461
|
+
agentId: this.id,
|
|
48462
|
+
modelContextWindow: this.llmRouter.getModelContextWindow(this.getEffectiveProvider()),
|
|
48463
|
+
modelMaxOutput: this.llmRouter.getModelMaxOutput(this.getEffectiveProvider()),
|
|
48464
|
+
toolDefinitions: browserTools,
|
|
48465
|
+
systemCacheSegments
|
|
48466
|
+
});
|
|
48467
|
+
let iterations = 0;
|
|
48468
|
+
let preparedFollowUp = await prepareFollowUpMessages();
|
|
48469
|
+
let response = await this.withNetworkRetry(() => this.llmRouter.chat({
|
|
48470
|
+
messages: preparedFollowUp.messages,
|
|
48471
|
+
tools: browserTools,
|
|
48472
|
+
metadata: this.getLLMMetadata(sessionId),
|
|
48473
|
+
compaction: useCompaction,
|
|
48474
|
+
systemCacheSegments
|
|
48475
|
+
}, this.getEffectiveProvider()), "Browser close-tabs follow-up");
|
|
48476
|
+
while (response.finishReason === "tool_use" && response.toolCalls?.length && ++iterations <= _Agent.BROWSER_CLOSE_FOLLOWUP_MAX_ITER) {
|
|
48477
|
+
this.memory.appendMessage(sessionId, {
|
|
48478
|
+
role: "assistant",
|
|
48479
|
+
content: response.content,
|
|
48480
|
+
toolCalls: response.toolCalls,
|
|
48481
|
+
reasoningContent: response.reasoningContent
|
|
48482
|
+
});
|
|
48483
|
+
for (const tc of response.toolCalls) {
|
|
48484
|
+
try {
|
|
48485
|
+
let result = await this.executeTool(tc, void 0, sessionId);
|
|
48486
|
+
result = this.offloadLargeResult(tc.name, result);
|
|
48487
|
+
this.memory.appendMessage(sessionId, { role: "tool", content: result, toolCallId: tc.id });
|
|
48488
|
+
} catch (toolErr) {
|
|
48489
|
+
this.memory.appendMessage(sessionId, {
|
|
48490
|
+
role: "tool",
|
|
48491
|
+
content: `Error: ${String(toolErr)}`,
|
|
48492
|
+
toolCallId: tc.id
|
|
48493
|
+
});
|
|
48494
|
+
}
|
|
48495
|
+
}
|
|
48496
|
+
preparedFollowUp = await prepareFollowUpMessages();
|
|
48497
|
+
response = await this.withNetworkRetry(() => this.llmRouter.chat({
|
|
48498
|
+
messages: preparedFollowUp.messages,
|
|
48499
|
+
tools: browserTools,
|
|
48500
|
+
metadata: this.getLLMMetadata(sessionId),
|
|
48501
|
+
compaction: useCompaction,
|
|
48502
|
+
systemCacheSegments
|
|
48503
|
+
}, this.getEffectiveProvider()), "Browser close-tabs follow-up continuation");
|
|
48504
|
+
}
|
|
48505
|
+
if (response.toolCalls?.length) {
|
|
48506
|
+
this.memory.appendMessage(sessionId, {
|
|
48507
|
+
role: "assistant",
|
|
48508
|
+
content: response.content,
|
|
48509
|
+
toolCalls: response.toolCalls,
|
|
48510
|
+
reasoningContent: response.reasoningContent
|
|
48511
|
+
});
|
|
48512
|
+
} else if (response.content?.trim()) {
|
|
48513
|
+
this.memory.appendMessage(sessionId, {
|
|
48514
|
+
role: "assistant",
|
|
48515
|
+
content: sanitizeLLMReply(response.content),
|
|
48516
|
+
reasoningContent: response.reasoningContent
|
|
48517
|
+
});
|
|
48518
|
+
}
|
|
48519
|
+
} catch (err) {
|
|
48520
|
+
log17.warn("Browser close-tabs follow-up failed", { agentId: this.id, sessionId, error: String(err) });
|
|
48521
|
+
}
|
|
48522
|
+
}
|
|
48100
48523
|
// ─── Activity Tracking ───────────────────────────────────────────────────────
|
|
48101
48524
|
startActivity(type, label, extra) {
|
|
48102
48525
|
const id = `act-${this.id}-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`;
|
|
@@ -48870,6 +49293,8 @@ ${chatYield.item.payload.content}`;
|
|
|
48870
49293
|
});
|
|
48871
49294
|
log17.error("Failed to handle message", { error: String(error) });
|
|
48872
49295
|
throw error;
|
|
49296
|
+
} finally {
|
|
49297
|
+
await this.finalizeBrowserSession(sessionId);
|
|
48873
49298
|
}
|
|
48874
49299
|
}
|
|
48875
49300
|
async handleMessageStream(userMessage, onEvent, senderId, senderInfo, cancelToken, images, fileNames) {
|
|
@@ -49247,6 +49672,9 @@ ${streamYield.item.payload.content}`;
|
|
|
49247
49672
|
} finally {
|
|
49248
49673
|
if (cancelPollTimer)
|
|
49249
49674
|
clearInterval(cancelPollTimer);
|
|
49675
|
+
if (this.currentSessionId) {
|
|
49676
|
+
await this.finalizeBrowserSession(this.currentSessionId);
|
|
49677
|
+
}
|
|
49250
49678
|
}
|
|
49251
49679
|
}
|
|
49252
49680
|
/**
|
|
@@ -49800,6 +50228,7 @@ ${yieldResult.item.payload.content}`
|
|
|
49800
50228
|
this.activeTasks.delete(taskId2);
|
|
49801
50229
|
this.activeTaskGen.delete(taskId2);
|
|
49802
50230
|
this.pendingInjections.delete(sessionId);
|
|
50231
|
+
await this.finalizeBrowserSession(sessionId);
|
|
49803
50232
|
}
|
|
49804
50233
|
this.endActivity(taskActId);
|
|
49805
50234
|
this.notifyStateChange();
|
|
@@ -50014,6 +50443,7 @@ ${risYield.item.payload.content}`
|
|
|
50014
50443
|
this.endActivity(actId);
|
|
50015
50444
|
if (this.activeTasks.size === 0)
|
|
50016
50445
|
this.setStatus("idle");
|
|
50446
|
+
await this.finalizeBrowserSession(sessionId);
|
|
50017
50447
|
}
|
|
50018
50448
|
}
|
|
50019
50449
|
skillProficiency = /* @__PURE__ */ new Map();
|
|
@@ -50397,16 +50827,20 @@ ${body}${contextSuffix}`;
|
|
|
50397
50827
|
}
|
|
50398
50828
|
if (toolCall.name === "complete_deliberation") {
|
|
50399
50829
|
const processItemId = toolCall.arguments.process_item_id;
|
|
50400
|
-
|
|
50401
|
-
|
|
50830
|
+
const processItemIds = toolCall.arguments.process_item_ids;
|
|
50831
|
+
if (!processItemId && (!processItemIds || processItemIds.length === 0)) {
|
|
50832
|
+
return JSON.stringify({ status: "error", message: "process_item_id or process_item_ids is required" });
|
|
50402
50833
|
}
|
|
50403
50834
|
this.pendingDeliberationResult = {
|
|
50404
|
-
processItemId,
|
|
50835
|
+
processItemId: processItemId || processItemIds[0],
|
|
50836
|
+
processItemIds: processItemIds && processItemIds.length > 1 ? processItemIds : void 0,
|
|
50837
|
+
batchContext: toolCall.arguments.batch_context,
|
|
50405
50838
|
deferItemIds: toolCall.arguments.defer_item_ids ?? [],
|
|
50406
50839
|
dropItemIds: toolCall.arguments.drop_item_ids ?? [],
|
|
50407
50840
|
inlineCompletedIds: toolCall.arguments.inline_completed_ids ?? [],
|
|
50408
50841
|
reasoning: toolCall.arguments.reasoning ?? "",
|
|
50409
|
-
situationalAwareness: toolCall.arguments.situational_awareness
|
|
50842
|
+
situationalAwareness: toolCall.arguments.situational_awareness,
|
|
50843
|
+
memoryUpdates: toolCall.arguments.memory_updates
|
|
50410
50844
|
};
|
|
50411
50845
|
return JSON.stringify({ status: "ok", message: "Deliberation decision recorded. Proceeding to focused processing." });
|
|
50412
50846
|
}
|
|
@@ -50954,8 +51388,13 @@ ${todayLog.slice(0, HEARTBEAT_DAILY_LOG_CHARS)}
|
|
|
50954
51388
|
const dreamKey = entries2.length > 500 ? `${today}_${Math.floor(Date.now() / (6 * 36e5))}` : today;
|
|
50955
51389
|
if (entries2.length >= 50 && this.lastDreamDate !== dreamKey) {
|
|
50956
51390
|
this.lastDreamDate = dreamKey;
|
|
50957
|
-
await
|
|
50958
|
-
|
|
51391
|
+
await _Agent.acquireDreamSlot();
|
|
51392
|
+
try {
|
|
51393
|
+
await this.dreamConsolidateMemory(entries2);
|
|
51394
|
+
this.pruneMemoryMd();
|
|
51395
|
+
} finally {
|
|
51396
|
+
_Agent.releaseDreamSlot();
|
|
51397
|
+
}
|
|
50959
51398
|
}
|
|
50960
51399
|
log17.debug("Memory consolidation completed", { agentId: this.id });
|
|
50961
51400
|
} catch (error) {
|
|
@@ -51785,6 +52224,10 @@ var init_browser_session = __esm({
|
|
|
51785
52224
|
* route to the new process after reconnect.
|
|
51786
52225
|
*/
|
|
51787
52226
|
reconnectors = /* @__PURE__ */ new Map();
|
|
52227
|
+
/** ownerKeys where a browser tool succeeded (excluding close_page / list_pages). */
|
|
52228
|
+
browserUsedKeys = /* @__PURE__ */ new Set();
|
|
52229
|
+
/** ownerKeys that already received a session-end close-tabs reminder. */
|
|
52230
|
+
remindedKeys = /* @__PURE__ */ new Set();
|
|
51788
52231
|
_bringToFront = false;
|
|
51789
52232
|
_autoCloseTabs = true;
|
|
51790
52233
|
get bringToFront() {
|
|
@@ -51971,6 +52414,56 @@ var init_browser_session = __esm({
|
|
|
51971
52414
|
const ids = [...owned].join(", ");
|
|
51972
52415
|
return `Your owned tab IDs: [${ids}] (${owned.size} total). You can only operate on these.`;
|
|
51973
52416
|
}
|
|
52417
|
+
ownerKeyFor(agentId2, sessionId) {
|
|
52418
|
+
return sessionId ? `${agentId2}::${sessionId}` : agentId2;
|
|
52419
|
+
}
|
|
52420
|
+
isToolError(result) {
|
|
52421
|
+
if (this.isStalePageError(result))
|
|
52422
|
+
return true;
|
|
52423
|
+
if (result.startsWith("Cannot ") || result.startsWith("Failed to auto-create"))
|
|
52424
|
+
return true;
|
|
52425
|
+
try {
|
|
52426
|
+
const parsed = JSON.parse(result);
|
|
52427
|
+
if (parsed?.error)
|
|
52428
|
+
return true;
|
|
52429
|
+
} catch {
|
|
52430
|
+
}
|
|
52431
|
+
return false;
|
|
52432
|
+
}
|
|
52433
|
+
/** Mark that this session successfully used the browser (called from tool wrappers). */
|
|
52434
|
+
markBrowserUsed(ownerKey) {
|
|
52435
|
+
this.browserUsedKeys.add(ownerKey);
|
|
52436
|
+
}
|
|
52437
|
+
markBrowserUsedIfSuccess(ownerKey, result) {
|
|
52438
|
+
if (!this.isToolError(result)) {
|
|
52439
|
+
this.markBrowserUsed(ownerKey);
|
|
52440
|
+
}
|
|
52441
|
+
}
|
|
52442
|
+
/** Return owned tab IDs for an agent session (for reminder text). */
|
|
52443
|
+
getOwnedTabIds(agentId2, sessionId) {
|
|
52444
|
+
const ownerKey = this.ownerKeyFor(agentId2, sessionId);
|
|
52445
|
+
return [...this.getOwned(ownerKey)];
|
|
52446
|
+
}
|
|
52447
|
+
/**
|
|
52448
|
+
* Consume a one-time session-end reminder if the session used the browser,
|
|
52449
|
+
* has remaining owned tabs, and has not been reminded yet.
|
|
52450
|
+
*/
|
|
52451
|
+
consumeCloseTabsReminder(agentId2, sessionId) {
|
|
52452
|
+
const ownerKey = this.ownerKeyFor(agentId2, sessionId);
|
|
52453
|
+
if (!this.browserUsedKeys.has(ownerKey))
|
|
52454
|
+
return null;
|
|
52455
|
+
if (this.remindedKeys.has(ownerKey))
|
|
52456
|
+
return null;
|
|
52457
|
+
const owned = this.getOwned(ownerKey);
|
|
52458
|
+
if (owned.size === 0)
|
|
52459
|
+
return null;
|
|
52460
|
+
this.remindedKeys.add(ownerKey);
|
|
52461
|
+
const ids = [...owned].join(", ");
|
|
52462
|
+
return [
|
|
52463
|
+
"[SYSTEM] You used the browser in this session. Before finishing, close any tabs you no longer need with chrome-devtools__close_page.",
|
|
52464
|
+
`Your owned tab IDs: [${ids}] (${owned.size} total).`
|
|
52465
|
+
].join(" ");
|
|
52466
|
+
}
|
|
51974
52467
|
// ─── Public API ───────────────────────────────────────────────────────────
|
|
51975
52468
|
wrapToolHandlers(handlers, agentId2) {
|
|
51976
52469
|
const findHandler = (name) => handlers.find((h) => (h.name.split("__").pop() ?? h.name) === name);
|
|
@@ -52037,6 +52530,7 @@ var init_browser_session = __esm({
|
|
|
52037
52530
|
} else {
|
|
52038
52531
|
log19.warn(`new_page response contained no pages for ${ownerKey}`);
|
|
52039
52532
|
}
|
|
52533
|
+
this.markBrowserUsedIfSuccess(ownerKey, result);
|
|
52040
52534
|
}
|
|
52041
52535
|
return this.annotateResponse(result, ownerKey);
|
|
52042
52536
|
});
|
|
@@ -52095,6 +52589,7 @@ var init_browser_session = __esm({
|
|
|
52095
52589
|
this.currentPage.set(ownerKey, pageId);
|
|
52096
52590
|
this.lastActiveSession.set(agentId2, { ownerKey, pageId });
|
|
52097
52591
|
}
|
|
52592
|
+
this.markBrowserUsedIfSuccess(ownerKey, result);
|
|
52098
52593
|
return this.annotateResponse(result, ownerKey);
|
|
52099
52594
|
});
|
|
52100
52595
|
}
|
|
@@ -52164,6 +52659,7 @@ var init_browser_session = __esm({
|
|
|
52164
52659
|
return this.navigateAutoCreateLocked(agentId2, ownerKey, args, newPageHandler);
|
|
52165
52660
|
}
|
|
52166
52661
|
}
|
|
52662
|
+
this.markBrowserUsedIfSuccess(ownerKey, result);
|
|
52167
52663
|
return this.annotateResponse(result, ownerKey);
|
|
52168
52664
|
});
|
|
52169
52665
|
}
|
|
@@ -52209,6 +52705,7 @@ var init_browser_session = __esm({
|
|
|
52209
52705
|
log19.info(`Auto-created page ${newPage.id} (${newPage.url}) for ${ownerKey}`);
|
|
52210
52706
|
}
|
|
52211
52707
|
}
|
|
52708
|
+
this.markBrowserUsedIfSuccess(ownerKey, result);
|
|
52212
52709
|
return this.annotateResponse(result, ownerKey);
|
|
52213
52710
|
} catch (err) {
|
|
52214
52711
|
return JSON.stringify({ error: `Failed to auto-create new tab: ${err}` });
|
|
@@ -52250,6 +52747,7 @@ var init_browser_session = __esm({
|
|
|
52250
52747
|
return `The tab you were operating on was closed externally. ${this.ownedPagesSummary(ownerKey)} Call navigate_page or new_page to create a new tab, then retry.`;
|
|
52251
52748
|
}
|
|
52252
52749
|
}
|
|
52750
|
+
this.markBrowserUsedIfSuccess(ownerKey, result);
|
|
52253
52751
|
return this.annotateResponse(result, ownerKey);
|
|
52254
52752
|
});
|
|
52255
52753
|
}
|
|
@@ -52266,6 +52764,16 @@ var init_browser_session = __esm({
|
|
|
52266
52764
|
this.currentPage.delete(key2);
|
|
52267
52765
|
}
|
|
52268
52766
|
}
|
|
52767
|
+
for (const key2 of [...this.browserUsedKeys]) {
|
|
52768
|
+
if (key2 === agentId2 || key2.startsWith(prefix)) {
|
|
52769
|
+
this.browserUsedKeys.delete(key2);
|
|
52770
|
+
}
|
|
52771
|
+
}
|
|
52772
|
+
for (const key2 of [...this.remindedKeys]) {
|
|
52773
|
+
if (key2 === agentId2 || key2.startsWith(prefix)) {
|
|
52774
|
+
this.remindedKeys.delete(key2);
|
|
52775
|
+
}
|
|
52776
|
+
}
|
|
52269
52777
|
this.agentLocks.delete(agentId2);
|
|
52270
52778
|
this.selectPageHandlers.delete(agentId2);
|
|
52271
52779
|
this.listPageHandlers.delete(agentId2);
|
|
@@ -52320,7 +52828,7 @@ function createPackageTools(ctx) {
|
|
|
52320
52828
|
},
|
|
52321
52829
|
{
|
|
52322
52830
|
name: "package_install",
|
|
52323
|
-
description: 'Install a package into the live organization. type "agent": hire/install an agent (from a built-in role or a custom package). type "team": deploy a full team with all members, norms, and starter tasks. type "skill": install a skill package. Use package_list to see what is available.',
|
|
52831
|
+
description: 'Install a package into the live organization. type "agent": hire/install an agent (from a built-in role or a custom package). type "team": deploy a full team with all members, norms, and starter tasks. type "skill": install a skill package. Requires user approval. Use package_list to see what is available.',
|
|
52324
52832
|
inputSchema: {
|
|
52325
52833
|
type: "object",
|
|
52326
52834
|
properties: {
|
|
@@ -52350,6 +52858,15 @@ function createPackageTools(ctx) {
|
|
|
52350
52858
|
return JSON.stringify({ status: "error", error: "type is required and must be one of: agent, team, skill" });
|
|
52351
52859
|
if (!name)
|
|
52352
52860
|
return JSON.stringify({ status: "error", error: "name is required \u2014 use package_list to see available packages" });
|
|
52861
|
+
if (ctx.requestApproval) {
|
|
52862
|
+
const { approved, comment } = await ctx.requestApproval({
|
|
52863
|
+
toolName: "package_install",
|
|
52864
|
+
toolArgs: { type, name, agent_name: args["agent_name"] },
|
|
52865
|
+
reason: `Agent wants to install ${type} "${name}" into the organization`
|
|
52866
|
+
});
|
|
52867
|
+
if (!approved)
|
|
52868
|
+
return JSON.stringify({ status: "rejected", reason: comment || "User denied package installation" });
|
|
52869
|
+
}
|
|
52353
52870
|
if (type === "agent") {
|
|
52354
52871
|
try {
|
|
52355
52872
|
const result2 = await installArtifact(type, name);
|
|
@@ -52422,7 +52939,7 @@ function createPackageTools(ctx) {
|
|
|
52422
52939
|
},
|
|
52423
52940
|
{
|
|
52424
52941
|
name: "hub_install",
|
|
52425
|
-
description: "Download an item from Markus Hub and install it. Combines download, save as artifact, and install into a single step. For agents/teams: remember to onboard the new agent(s) after installation.",
|
|
52942
|
+
description: "Download an item from Markus Hub and install it. Combines download, save as artifact, and install into a single step. Requires user approval. For agents/teams: remember to onboard the new agent(s) after installation.",
|
|
52426
52943
|
inputSchema: {
|
|
52427
52944
|
type: "object",
|
|
52428
52945
|
properties: {
|
|
@@ -52438,6 +52955,15 @@ function createPackageTools(ctx) {
|
|
|
52438
52955
|
const itemId = args["item_id"]?.trim();
|
|
52439
52956
|
if (!itemId)
|
|
52440
52957
|
return JSON.stringify({ status: "error", error: "item_id is required \u2014 use hub_search to find available items first" });
|
|
52958
|
+
if (ctx.requestApproval) {
|
|
52959
|
+
const { approved, comment } = await ctx.requestApproval({
|
|
52960
|
+
toolName: "hub_install",
|
|
52961
|
+
toolArgs: { item_id: itemId },
|
|
52962
|
+
reason: `Agent wants to download and install Hub item "${itemId}" into the organization`
|
|
52963
|
+
});
|
|
52964
|
+
if (!approved)
|
|
52965
|
+
return JSON.stringify({ status: "rejected", reason: comment || "User denied Hub installation" });
|
|
52966
|
+
}
|
|
52441
52967
|
const result = await downloadAndInstall(itemId);
|
|
52442
52968
|
const isAgentOrTeam = result.type === "agent" || result.type === "team";
|
|
52443
52969
|
return JSON.stringify({
|
|
@@ -52653,11 +53179,10 @@ function createA2ATools(ctx) {
|
|
|
52653
53179
|
name: "agent_send_message",
|
|
52654
53180
|
description: [
|
|
52655
53181
|
"Send a message to another agent (colleague) in your organization.",
|
|
52656
|
-
"This tool is
|
|
52657
|
-
"
|
|
52658
|
-
"Use
|
|
52659
|
-
"
|
|
52660
|
-
'Use this for one-way announcements (e.g., "I submitted task X for review", status updates).',
|
|
53182
|
+
"This tool is ALWAYS asynchronous (fire-and-forget): the message enters the target agent's mailbox and you continue working.",
|
|
53183
|
+
"The recipient will process it on their own schedule and may reply via their own agent_send_message.",
|
|
53184
|
+
"Use conversation_id to correlate multi-turn exchanges \u2014 you and the recipient will both see this ID.",
|
|
53185
|
+
"Record what you asked in your working memory so you recognize the reply when it arrives.",
|
|
52661
53186
|
"IMPORTANT: Do NOT use this tool to request substantial work from another agent.",
|
|
52662
53187
|
"If you need another agent to perform multi-step work, file changes, or extended execution,",
|
|
52663
53188
|
"use requirement_propose + task_create instead \u2014 tasks provide tracking, review, and audit trail."
|
|
@@ -52667,9 +53192,13 @@ function createA2ATools(ctx) {
|
|
|
52667
53192
|
properties: {
|
|
52668
53193
|
agent_id: { type: "string", description: "The ID of the agent to message" },
|
|
52669
53194
|
message: { type: "string", description: "The message to send" },
|
|
53195
|
+
conversation_id: {
|
|
53196
|
+
type: "string",
|
|
53197
|
+
description: "Optional correlation ID for multi-turn exchanges. Auto-generated if omitted. Include this when replying to a previous message to maintain context."
|
|
53198
|
+
},
|
|
52670
53199
|
wait_for_reply: {
|
|
52671
53200
|
type: "boolean",
|
|
52672
|
-
description: "
|
|
53201
|
+
description: "[DEPRECATED \u2014 ignored] A2A is always async. Record your question in working memory and process the reply when it arrives."
|
|
52673
53202
|
}
|
|
52674
53203
|
},
|
|
52675
53204
|
required: ["agent_id", "message"]
|
|
@@ -52677,26 +53206,25 @@ function createA2ATools(ctx) {
|
|
|
52677
53206
|
async execute(args) {
|
|
52678
53207
|
const targetId = args["agent_id"];
|
|
52679
53208
|
const message = args["message"];
|
|
52680
|
-
const
|
|
53209
|
+
const conversationId = args["conversation_id"] || generateId("conv");
|
|
53210
|
+
const waitForReply = args["wait_for_reply"];
|
|
52681
53211
|
if (targetId === ctx.selfId) {
|
|
52682
53212
|
return JSON.stringify({ status: "error", error: "Cannot send a message to yourself" });
|
|
52683
53213
|
}
|
|
52684
53214
|
if (waitForReply) {
|
|
52685
|
-
log21.
|
|
52686
|
-
try {
|
|
52687
|
-
const reply = await ctx.sendMessage(targetId, message, ctx.selfId, ctx.selfName, 0, true);
|
|
52688
|
-
log21.info(`A2A reply received: ${targetId} \u2192 ${ctx.selfName}`, { replyLen: reply.length });
|
|
52689
|
-
return JSON.stringify({ status: "replied", from: targetId, reply });
|
|
52690
|
-
} catch (err) {
|
|
52691
|
-
log21.warn(`A2A sync message to ${targetId} failed`, { error: String(err) });
|
|
52692
|
-
return JSON.stringify({ status: "error", error: `Failed to get reply: ${String(err)}` });
|
|
52693
|
-
}
|
|
53215
|
+
log21.warn(`A2A wait_for_reply=true is deprecated and ignored (deadlock risk). Sending async. Sender: ${ctx.selfName} \u2192 ${targetId}`);
|
|
52694
53216
|
}
|
|
52695
|
-
|
|
52696
|
-
|
|
53217
|
+
const taggedMessage = `[conversation:${conversationId}]
|
|
53218
|
+
${message}`;
|
|
53219
|
+
log21.info(`A2A send (async): ${ctx.selfName} \u2192 ${targetId}`, { messageLen: message.length, conversationId });
|
|
53220
|
+
ctx.sendMessage(targetId, taggedMessage, ctx.selfId, ctx.selfName, void 0, false).catch((err) => {
|
|
52697
53221
|
log21.warn(`A2A async message to ${targetId} failed in background`, { error: String(err) });
|
|
52698
53222
|
});
|
|
52699
|
-
return JSON.stringify({
|
|
53223
|
+
return JSON.stringify({
|
|
53224
|
+
status: "dispatched",
|
|
53225
|
+
conversation_id: conversationId,
|
|
53226
|
+
message: "Message sent asynchronously. The agent will process it on their schedule. Record your question in working memory to recognize the reply."
|
|
53227
|
+
});
|
|
52700
53228
|
}
|
|
52701
53229
|
},
|
|
52702
53230
|
{
|
|
@@ -54255,35 +54783,62 @@ function createProjectTools(ctx) {
|
|
|
54255
54783
|
},
|
|
54256
54784
|
{
|
|
54257
54785
|
name: "get_project",
|
|
54258
|
-
description: "Get detailed information about a specific project including repositories, teams, and governance policy.",
|
|
54786
|
+
description: "Get detailed information about a specific project including repositories (with paths and branches), teams, and governance policy. Use project_id or omit to get your current project.",
|
|
54259
54787
|
inputSchema: {
|
|
54260
54788
|
type: "object",
|
|
54261
54789
|
properties: {
|
|
54262
54790
|
project_id: {
|
|
54263
54791
|
type: "string",
|
|
54264
|
-
description: "The project ID"
|
|
54792
|
+
description: "The project ID (omit to get current project if available)"
|
|
54265
54793
|
}
|
|
54266
|
-
}
|
|
54267
|
-
required: ["project_id"]
|
|
54794
|
+
}
|
|
54268
54795
|
},
|
|
54269
54796
|
async execute(args) {
|
|
54270
54797
|
try {
|
|
54271
54798
|
const projectId = args["project_id"];
|
|
54272
|
-
|
|
54273
|
-
|
|
54274
|
-
|
|
54275
|
-
|
|
54276
|
-
|
|
54277
|
-
|
|
54278
|
-
|
|
54279
|
-
|
|
54280
|
-
|
|
54281
|
-
|
|
54282
|
-
|
|
54283
|
-
|
|
54284
|
-
|
|
54285
|
-
|
|
54286
|
-
|
|
54799
|
+
if (projectId) {
|
|
54800
|
+
const project = ctx.projectService.getProject(projectId);
|
|
54801
|
+
if (!project)
|
|
54802
|
+
return JSON.stringify({ status: "error", error: "Project not found" });
|
|
54803
|
+
return JSON.stringify({
|
|
54804
|
+
status: "success",
|
|
54805
|
+
project: {
|
|
54806
|
+
id: project.id,
|
|
54807
|
+
name: project.name,
|
|
54808
|
+
description: project.description,
|
|
54809
|
+
status: project.status,
|
|
54810
|
+
repositories: (project.repositories ?? []).map((r) => ({
|
|
54811
|
+
path: r.localPath,
|
|
54812
|
+
branch: r.defaultBranch,
|
|
54813
|
+
role: r.role
|
|
54814
|
+
})),
|
|
54815
|
+
teamIds: project.teamIds ?? [],
|
|
54816
|
+
governancePolicy: project.governancePolicy ?? null
|
|
54817
|
+
}
|
|
54818
|
+
});
|
|
54819
|
+
}
|
|
54820
|
+
if (ctx.getProjectInfo) {
|
|
54821
|
+
const info4 = await ctx.getProjectInfo();
|
|
54822
|
+
if (!info4)
|
|
54823
|
+
return JSON.stringify({ status: "error", error: "No current project found" });
|
|
54824
|
+
return JSON.stringify({
|
|
54825
|
+
status: "success",
|
|
54826
|
+
project: {
|
|
54827
|
+
id: info4.id,
|
|
54828
|
+
name: info4.name,
|
|
54829
|
+
description: info4.description,
|
|
54830
|
+
status: info4.status,
|
|
54831
|
+
repositories: (info4.repositories ?? []).map((r) => ({
|
|
54832
|
+
path: r.localPath,
|
|
54833
|
+
branch: r.defaultBranch,
|
|
54834
|
+
role: r.role
|
|
54835
|
+
})),
|
|
54836
|
+
teamIds: info4.teamIds ?? [],
|
|
54837
|
+
governancePolicy: info4.governancePolicy ?? null
|
|
54838
|
+
}
|
|
54839
|
+
});
|
|
54840
|
+
}
|
|
54841
|
+
return JSON.stringify({ status: "error", error: "project_id is required" });
|
|
54287
54842
|
} catch (error) {
|
|
54288
54843
|
return JSON.stringify({ status: "error", error: String(error) });
|
|
54289
54844
|
}
|
|
@@ -54330,14 +54885,40 @@ function createProjectTools(ctx) {
|
|
|
54330
54885
|
...ctx.projectService?.updateProject ? [
|
|
54331
54886
|
{
|
|
54332
54887
|
name: "update_project",
|
|
54333
|
-
description: "Update an existing project
|
|
54888
|
+
description: "Update an existing project. Supports name, description, status, repositories, teamIds, and governancePolicy. Changing description alone executes directly; all other changes require user approval.",
|
|
54334
54889
|
inputSchema: {
|
|
54335
54890
|
type: "object",
|
|
54336
54891
|
properties: {
|
|
54337
54892
|
project_id: { type: "string", description: "The project ID to update" },
|
|
54338
54893
|
name: { type: "string", description: "New project name (optional)" },
|
|
54339
54894
|
description: { type: "string", description: "New description (optional)" },
|
|
54340
|
-
status: { type: "string", enum: ["active", "paused", "archived"], description: "New status (optional)" }
|
|
54895
|
+
status: { type: "string", enum: ["active", "paused", "archived"], description: "New status (optional)" },
|
|
54896
|
+
repositories: {
|
|
54897
|
+
type: "array",
|
|
54898
|
+
items: {
|
|
54899
|
+
type: "object",
|
|
54900
|
+
properties: {
|
|
54901
|
+
localPath: { type: "string", description: "Local filesystem path to the repository" },
|
|
54902
|
+
defaultBranch: { type: "string", description: "Default branch name (e.g. main)" },
|
|
54903
|
+
role: { type: "string", enum: ["primary", "secondary"], description: "Role of this repository" }
|
|
54904
|
+
},
|
|
54905
|
+
required: ["localPath", "defaultBranch", "role"]
|
|
54906
|
+
},
|
|
54907
|
+
description: "Full list of repositories (replaces existing). Requires approval."
|
|
54908
|
+
},
|
|
54909
|
+
team_ids: {
|
|
54910
|
+
type: "array",
|
|
54911
|
+
items: { type: "string" },
|
|
54912
|
+
description: "Team IDs to associate with this project. Requires approval."
|
|
54913
|
+
},
|
|
54914
|
+
governance_policy: {
|
|
54915
|
+
type: "object",
|
|
54916
|
+
properties: {
|
|
54917
|
+
enabled: { type: "boolean" },
|
|
54918
|
+
defaultTier: { type: "string" }
|
|
54919
|
+
},
|
|
54920
|
+
description: "Governance policy settings. Requires approval."
|
|
54921
|
+
}
|
|
54341
54922
|
},
|
|
54342
54923
|
required: ["project_id"]
|
|
54343
54924
|
},
|
|
@@ -54351,11 +54932,20 @@ function createProjectTools(ctx) {
|
|
|
54351
54932
|
data.description = args["description"];
|
|
54352
54933
|
if (args["status"])
|
|
54353
54934
|
data.status = args["status"];
|
|
54354
|
-
if (
|
|
54935
|
+
if (args["repositories"])
|
|
54936
|
+
data.repositories = args["repositories"];
|
|
54937
|
+
if (args["team_ids"])
|
|
54938
|
+
data.teamIds = args["team_ids"];
|
|
54939
|
+
if (args["governance_policy"])
|
|
54940
|
+
data.governancePolicy = args["governance_policy"];
|
|
54941
|
+
const APPROVAL_FIELDS = ["name", "status", "repositories", "teamIds", "governancePolicy"];
|
|
54942
|
+
const needsApproval = APPROVAL_FIELDS.some((f) => data[f] !== void 0);
|
|
54943
|
+
if (needsApproval && ctx.requestApproval) {
|
|
54944
|
+
const changedFields = Object.keys(data).filter((k) => k !== "description");
|
|
54355
54945
|
const { approved, comment } = await ctx.requestApproval({
|
|
54356
54946
|
toolName: "update_project",
|
|
54357
54947
|
toolArgs: { project_id: projectId, ...data },
|
|
54358
|
-
reason: `Agent wants to update project ${projectId}`
|
|
54948
|
+
reason: `Agent wants to update project ${projectId} (fields: ${changedFields.join(", ")})`
|
|
54359
54949
|
});
|
|
54360
54950
|
if (!approved)
|
|
54361
54951
|
return JSON.stringify({ status: "rejected", reason: comment || "User denied project update" });
|
|
@@ -54369,36 +54959,56 @@ function createProjectTools(ctx) {
|
|
|
54369
54959
|
}
|
|
54370
54960
|
] : []
|
|
54371
54961
|
] : [],
|
|
54372
|
-
...ctx.
|
|
54962
|
+
...ctx.projectService?.deleteProject ? [
|
|
54373
54963
|
{
|
|
54374
|
-
name: "
|
|
54375
|
-
description: "
|
|
54964
|
+
name: "delete_project",
|
|
54965
|
+
description: "Delete a project. This is a destructive operation that unlinks all tasks and requirements. Always requires user approval.",
|
|
54376
54966
|
inputSchema: {
|
|
54377
54967
|
type: "object",
|
|
54378
54968
|
properties: {
|
|
54379
|
-
project_id: {
|
|
54380
|
-
|
|
54381
|
-
|
|
54969
|
+
project_id: { type: "string", description: "The project ID to delete" },
|
|
54970
|
+
reason: { type: "string", description: "Why this project should be deleted" }
|
|
54971
|
+
},
|
|
54972
|
+
required: ["project_id", "reason"]
|
|
54973
|
+
},
|
|
54974
|
+
async execute(args) {
|
|
54975
|
+
try {
|
|
54976
|
+
const projectId = args["project_id"];
|
|
54977
|
+
const reason = args["reason"];
|
|
54978
|
+
if (ctx.requestApproval) {
|
|
54979
|
+
const { approved, comment } = await ctx.requestApproval({
|
|
54980
|
+
toolName: "delete_project",
|
|
54981
|
+
toolArgs: { project_id: projectId, reason },
|
|
54982
|
+
reason: `Agent wants to DELETE project ${projectId}: ${reason}`
|
|
54983
|
+
});
|
|
54984
|
+
if (!approved)
|
|
54985
|
+
return JSON.stringify({ status: "rejected", reason: comment || "User denied project deletion" });
|
|
54382
54986
|
}
|
|
54987
|
+
ctx.projectService.deleteProject(projectId);
|
|
54988
|
+
return JSON.stringify({ status: "success", deleted: projectId });
|
|
54989
|
+
} catch (error) {
|
|
54990
|
+
return JSON.stringify({ status: "error", error: String(error) });
|
|
54383
54991
|
}
|
|
54992
|
+
}
|
|
54993
|
+
}
|
|
54994
|
+
] : [],
|
|
54995
|
+
...ctx.getProjectStats ? [
|
|
54996
|
+
{
|
|
54997
|
+
name: "project_stats",
|
|
54998
|
+
description: "Get task and requirement statistics for a project: counts by status (completed, in_progress, blocked, etc.).",
|
|
54999
|
+
inputSchema: {
|
|
55000
|
+
type: "object",
|
|
55001
|
+
properties: {
|
|
55002
|
+
project_id: { type: "string", description: "The project ID" }
|
|
55003
|
+
},
|
|
55004
|
+
required: ["project_id"]
|
|
54384
55005
|
},
|
|
54385
55006
|
async execute(args) {
|
|
54386
55007
|
try {
|
|
54387
|
-
const
|
|
54388
|
-
if (!
|
|
54389
|
-
return JSON.stringify({ status: "error", error: "
|
|
54390
|
-
return JSON.stringify({
|
|
54391
|
-
status: "success",
|
|
54392
|
-
project: {
|
|
54393
|
-
id: info4.id,
|
|
54394
|
-
name: info4.name,
|
|
54395
|
-
description: info4.description,
|
|
54396
|
-
status: info4.status,
|
|
54397
|
-
repositories: info4.repositories?.map((r) => ({ path: r.localPath, branch: r.defaultBranch })),
|
|
54398
|
-
teamCount: info4.teamIds?.length ?? 0,
|
|
54399
|
-
governance: info4.governancePolicy?.enabled ? info4.governancePolicy.defaultTier : "none"
|
|
54400
|
-
}
|
|
54401
|
-
});
|
|
55008
|
+
const stats = await ctx.getProjectStats(args["project_id"]);
|
|
55009
|
+
if (!stats)
|
|
55010
|
+
return JSON.stringify({ status: "error", error: "Project not found" });
|
|
55011
|
+
return JSON.stringify({ status: "success", ...stats });
|
|
54402
55012
|
} catch (error) {
|
|
54403
55013
|
return JSON.stringify({ status: "error", error: String(error) });
|
|
54404
55014
|
}
|
|
@@ -57090,7 +57700,6 @@ var init_agent_manager = __esm({
|
|
|
57090
57700
|
userNotifier;
|
|
57091
57701
|
taskService;
|
|
57092
57702
|
projectService;
|
|
57093
|
-
knowledgeService;
|
|
57094
57703
|
deliverableService;
|
|
57095
57704
|
webUiBaseUrl;
|
|
57096
57705
|
semanticSearch;
|
|
@@ -57113,49 +57722,6 @@ var init_agent_manager = __esm({
|
|
|
57113
57722
|
teamUpdater;
|
|
57114
57723
|
agentConfigPersister;
|
|
57115
57724
|
groupChatHandlers;
|
|
57116
|
-
buildKnowledgeCallbacks(agentId2, orgId2) {
|
|
57117
|
-
if (!this.knowledgeService)
|
|
57118
|
-
return {};
|
|
57119
|
-
const ks = this.knowledgeService;
|
|
57120
|
-
return {
|
|
57121
|
-
knowledgeContribute: async (opts) => {
|
|
57122
|
-
const scopeId = opts.scope === "org" ? orgId2 : opts.scope === "project" ? orgId2 : agentId2;
|
|
57123
|
-
const entry = ks.contribute({
|
|
57124
|
-
scope: opts.scope,
|
|
57125
|
-
scopeId,
|
|
57126
|
-
category: opts.category,
|
|
57127
|
-
title: opts.title,
|
|
57128
|
-
content: opts.content,
|
|
57129
|
-
source: agentId2,
|
|
57130
|
-
importance: opts.importance,
|
|
57131
|
-
tags: opts.tags?.split(",").map((t) => t.trim()).filter(Boolean),
|
|
57132
|
-
supersedes: opts.supersedes
|
|
57133
|
-
});
|
|
57134
|
-
return { id: entry.id, status: entry.status, filePath: ks.getEntryFilePath?.(entry.id) };
|
|
57135
|
-
},
|
|
57136
|
-
knowledgeSearch: async (query2, scope, category, limit) => {
|
|
57137
|
-
const results = ks.search({ query: query2, scope, category, limit });
|
|
57138
|
-
return results.map((e) => ({
|
|
57139
|
-
id: e.id,
|
|
57140
|
-
title: e.title,
|
|
57141
|
-
category: e.category,
|
|
57142
|
-
content: e.content,
|
|
57143
|
-
importance: e.importance,
|
|
57144
|
-
filePath: ks.getEntryFilePath?.(e.id)
|
|
57145
|
-
}));
|
|
57146
|
-
},
|
|
57147
|
-
knowledgeBrowse: async (category, scope) => {
|
|
57148
|
-
return ks.browse({
|
|
57149
|
-
scope: scope ?? "project",
|
|
57150
|
-
scopeId: orgId2,
|
|
57151
|
-
category
|
|
57152
|
-
});
|
|
57153
|
-
},
|
|
57154
|
-
knowledgeFlagOutdated: async (id, reason) => {
|
|
57155
|
-
ks.flagOutdated(id, reason);
|
|
57156
|
-
}
|
|
57157
|
-
};
|
|
57158
|
-
}
|
|
57159
57725
|
buildDeliverableCallbacks(agentId2, projectId) {
|
|
57160
57726
|
if (!this.deliverableService)
|
|
57161
57727
|
return {};
|
|
@@ -57405,9 +57971,6 @@ Priority: ${delegation.priority}`, envelope.from, { name: envelope.from, role: "
|
|
|
57405
57971
|
setRequirementService(requirementService) {
|
|
57406
57972
|
this.requirementService = requirementService;
|
|
57407
57973
|
}
|
|
57408
|
-
setKnowledgeService(knowledgeService) {
|
|
57409
|
-
this.knowledgeService = knowledgeService;
|
|
57410
|
-
}
|
|
57411
57974
|
setDeliverableService(deliverableService) {
|
|
57412
57975
|
this.deliverableService = deliverableService;
|
|
57413
57976
|
}
|
|
@@ -57952,13 +58515,59 @@ Known issues: ${knownIssues}` : ""}`
|
|
|
57952
58515
|
}
|
|
57953
58516
|
if (this.projectService) {
|
|
57954
58517
|
const ah = this.approvalHandler;
|
|
58518
|
+
const ps = this.projectService;
|
|
58519
|
+
const ts = this.taskService;
|
|
58520
|
+
const rs = this.requirementService;
|
|
57955
58521
|
for (const tool of createProjectTools({
|
|
57956
58522
|
agentId: id,
|
|
57957
58523
|
orgId: config.orgId,
|
|
57958
58524
|
webUiBaseUrl: this.webUiBaseUrl,
|
|
57959
|
-
projectService:
|
|
58525
|
+
projectService: ps,
|
|
57960
58526
|
requestApproval: ah ? (req) => ah(id, req) : void 0,
|
|
57961
|
-
|
|
58527
|
+
getProjectInfo: async (projectId) => {
|
|
58528
|
+
let resolvedId = projectId;
|
|
58529
|
+
if (!resolvedId && config.teamId) {
|
|
58530
|
+
resolvedId = ps.listProjects(config.orgId).find((p) => p.teamIds.includes(config.teamId))?.id;
|
|
58531
|
+
}
|
|
58532
|
+
if (!resolvedId)
|
|
58533
|
+
return null;
|
|
58534
|
+
const project = ps.getProject(resolvedId);
|
|
58535
|
+
return project ?? null;
|
|
58536
|
+
},
|
|
58537
|
+
getProjectStats: ts ? async (projectId) => {
|
|
58538
|
+
const tasks = ts.listTasks({ orgId: config.orgId, projectId });
|
|
58539
|
+
const reqs = rs?.listRequirements?.({ projectId }) ?? [];
|
|
58540
|
+
const stats = {
|
|
58541
|
+
totalTasks: tasks.length,
|
|
58542
|
+
completed: 0,
|
|
58543
|
+
inProgress: 0,
|
|
58544
|
+
inReview: 0,
|
|
58545
|
+
blocked: 0,
|
|
58546
|
+
pending: 0,
|
|
58547
|
+
failed: 0,
|
|
58548
|
+
totalRequirements: reqs.length,
|
|
58549
|
+
completedRequirements: 0
|
|
58550
|
+
};
|
|
58551
|
+
for (const t of tasks) {
|
|
58552
|
+
if (t.status === "completed" || t.status === "accepted")
|
|
58553
|
+
stats.completed++;
|
|
58554
|
+
else if (t.status === "in_progress")
|
|
58555
|
+
stats.inProgress++;
|
|
58556
|
+
else if (t.status === "review" || t.status === "revision")
|
|
58557
|
+
stats.inReview++;
|
|
58558
|
+
else if (t.status === "blocked")
|
|
58559
|
+
stats.blocked++;
|
|
58560
|
+
else if (t.status === "failed")
|
|
58561
|
+
stats.failed++;
|
|
58562
|
+
else
|
|
58563
|
+
stats.pending++;
|
|
58564
|
+
}
|
|
58565
|
+
for (const r of reqs) {
|
|
58566
|
+
if (r.status === "completed")
|
|
58567
|
+
stats.completedRequirements++;
|
|
58568
|
+
}
|
|
58569
|
+
return stats;
|
|
58570
|
+
} : void 0,
|
|
57962
58571
|
...this.buildDeliverableCallbacks(id, config.orgId)
|
|
57963
58572
|
})) {
|
|
57964
58573
|
agent.registerTool(tool);
|
|
@@ -58014,6 +58623,7 @@ Known issues: ${knownIssues}` : ""}`
|
|
|
58014
58623
|
}
|
|
58015
58624
|
}
|
|
58016
58625
|
{
|
|
58626
|
+
const pkgAh = this.approvalHandler;
|
|
58017
58627
|
const packageTools = createPackageTools({
|
|
58018
58628
|
installArtifact: () => this.builderService ? (type, name) => this.builderService.installArtifact(type, name) : void 0,
|
|
58019
58629
|
listArtifacts: () => this.builderService ? (type) => this.builderService.listArtifacts(type) : void 0,
|
|
@@ -58036,7 +58646,8 @@ Known issues: ${knownIssues}` : ""}`
|
|
|
58036
58646
|
category: t.category ?? "general"
|
|
58037
58647
|
})) : void 0,
|
|
58038
58648
|
searchHub: () => this.hubClient ? (opts) => this.hubClient.search(opts) : void 0,
|
|
58039
|
-
downloadAndInstall: () => this.hubClient ? (itemId) => this.hubClient.downloadAndInstall(itemId) : void 0
|
|
58649
|
+
downloadAndInstall: () => this.hubClient ? (itemId) => this.hubClient.downloadAndInstall(itemId) : void 0,
|
|
58650
|
+
requestApproval: pkgAh ? (req) => pkgAh(id, req) : void 0
|
|
58040
58651
|
});
|
|
58041
58652
|
for (const tool of packageTools)
|
|
58042
58653
|
agent.registerTool(tool);
|
|
@@ -58081,6 +58692,7 @@ Known issues: ${knownIssues}` : ""}`
|
|
|
58081
58692
|
if (this.activityCallbacks) {
|
|
58082
58693
|
agent.setActivityCallbacks(this.activityCallbacks);
|
|
58083
58694
|
}
|
|
58695
|
+
agent.setBrowserCloseTabsHelper((sessionId) => this.browserSessionManager.consumeCloseTabsReminder(id, sessionId));
|
|
58084
58696
|
this.forwardAgentEvents(agent);
|
|
58085
58697
|
if (config.teamId) {
|
|
58086
58698
|
agent.setTeamDataDir(join12(homedir6(), ".markus", "teams", config.teamId));
|
|
@@ -58563,13 +59175,59 @@ Known issues: ${knownIssues}` : ""}`
|
|
|
58563
59175
|
}
|
|
58564
59176
|
if (this.projectService) {
|
|
58565
59177
|
const ah2 = this.approvalHandler;
|
|
59178
|
+
const ps2 = this.projectService;
|
|
59179
|
+
const ts2 = this.taskService;
|
|
59180
|
+
const rs2 = this.requirementService;
|
|
58566
59181
|
for (const tool of createProjectTools({
|
|
58567
59182
|
agentId: id,
|
|
58568
59183
|
orgId: config.orgId,
|
|
58569
59184
|
webUiBaseUrl: this.webUiBaseUrl,
|
|
58570
|
-
projectService:
|
|
59185
|
+
projectService: ps2,
|
|
58571
59186
|
requestApproval: ah2 ? (req) => ah2(id, req) : void 0,
|
|
58572
|
-
|
|
59187
|
+
getProjectInfo: async (projectId) => {
|
|
59188
|
+
let resolvedId2 = projectId;
|
|
59189
|
+
if (!resolvedId2 && config.teamId) {
|
|
59190
|
+
resolvedId2 = ps2.listProjects(config.orgId).find((p) => p.teamIds.includes(config.teamId))?.id;
|
|
59191
|
+
}
|
|
59192
|
+
if (!resolvedId2)
|
|
59193
|
+
return null;
|
|
59194
|
+
const project = ps2.getProject(resolvedId2);
|
|
59195
|
+
return project ?? null;
|
|
59196
|
+
},
|
|
59197
|
+
getProjectStats: ts2 ? async (projectId) => {
|
|
59198
|
+
const tasks = ts2.listTasks({ orgId: config.orgId, projectId });
|
|
59199
|
+
const reqs = rs2?.listRequirements?.({ projectId }) ?? [];
|
|
59200
|
+
const stats = {
|
|
59201
|
+
totalTasks: tasks.length,
|
|
59202
|
+
completed: 0,
|
|
59203
|
+
inProgress: 0,
|
|
59204
|
+
inReview: 0,
|
|
59205
|
+
blocked: 0,
|
|
59206
|
+
pending: 0,
|
|
59207
|
+
failed: 0,
|
|
59208
|
+
totalRequirements: reqs.length,
|
|
59209
|
+
completedRequirements: 0
|
|
59210
|
+
};
|
|
59211
|
+
for (const t of tasks) {
|
|
59212
|
+
if (t.status === "completed" || t.status === "accepted")
|
|
59213
|
+
stats.completed++;
|
|
59214
|
+
else if (t.status === "in_progress")
|
|
59215
|
+
stats.inProgress++;
|
|
59216
|
+
else if (t.status === "review" || t.status === "revision")
|
|
59217
|
+
stats.inReview++;
|
|
59218
|
+
else if (t.status === "blocked")
|
|
59219
|
+
stats.blocked++;
|
|
59220
|
+
else if (t.status === "failed")
|
|
59221
|
+
stats.failed++;
|
|
59222
|
+
else
|
|
59223
|
+
stats.pending++;
|
|
59224
|
+
}
|
|
59225
|
+
for (const r of reqs) {
|
|
59226
|
+
if (r.status === "completed")
|
|
59227
|
+
stats.completedRequirements++;
|
|
59228
|
+
}
|
|
59229
|
+
return stats;
|
|
59230
|
+
} : void 0,
|
|
58573
59231
|
...this.buildDeliverableCallbacks(id, config.orgId)
|
|
58574
59232
|
})) {
|
|
58575
59233
|
agent.registerTool(tool);
|
|
@@ -58624,6 +59282,7 @@ Known issues: ${knownIssues}` : ""}`
|
|
|
58624
59282
|
agent.registerTool(tool);
|
|
58625
59283
|
}
|
|
58626
59284
|
{
|
|
59285
|
+
const pkgAh2 = this.approvalHandler;
|
|
58627
59286
|
const packageTools = createPackageTools({
|
|
58628
59287
|
installArtifact: () => this.builderService ? (type, name) => this.builderService.installArtifact(type, name) : void 0,
|
|
58629
59288
|
listArtifacts: () => this.builderService ? (type) => this.builderService.listArtifacts(type) : void 0,
|
|
@@ -58646,7 +59305,8 @@ Known issues: ${knownIssues}` : ""}`
|
|
|
58646
59305
|
category: t.category ?? "general"
|
|
58647
59306
|
})) : void 0,
|
|
58648
59307
|
searchHub: () => this.hubClient ? (opts) => this.hubClient.search(opts) : void 0,
|
|
58649
|
-
downloadAndInstall: () => this.hubClient ? (itemId) => this.hubClient.downloadAndInstall(itemId) : void 0
|
|
59308
|
+
downloadAndInstall: () => this.hubClient ? (itemId) => this.hubClient.downloadAndInstall(itemId) : void 0,
|
|
59309
|
+
requestApproval: pkgAh2 ? (req) => pkgAh2(id, req) : void 0
|
|
58650
59310
|
});
|
|
58651
59311
|
for (const tool of packageTools)
|
|
58652
59312
|
agent.registerTool(tool);
|
|
@@ -58666,6 +59326,7 @@ Known issues: ${knownIssues}` : ""}`
|
|
|
58666
59326
|
if (this.activityCallbacks) {
|
|
58667
59327
|
agent.setActivityCallbacks(this.activityCallbacks);
|
|
58668
59328
|
}
|
|
59329
|
+
agent.setBrowserCloseTabsHelper((sessionId) => this.browserSessionManager.consumeCloseTabsReminder(id, sessionId));
|
|
58669
59330
|
this.forwardAgentEvents(agent);
|
|
58670
59331
|
if (config.teamId) {
|
|
58671
59332
|
agent.setTeamDataDir(join12(homedir6(), ".markus", "teams", config.teamId));
|
|
@@ -63672,7 +64333,7 @@ var init_tool_profiles = __esm({
|
|
|
63672
64333
|
"group:agent": ["spawn_subagent", "spawn_subagents"],
|
|
63673
64334
|
"group:tasks": ["task_create", "task_list", "task_get", "task_update", "task_note", "task_assign", "task_submit_review", "task_comment", "subtask_create", "subtask_complete", "subtask_list"],
|
|
63674
64335
|
"group:requirements": ["requirement_propose", "requirement_list", "requirement_get", "requirement_update", "requirement_update_status", "requirement_resubmit", "requirement_comment"],
|
|
63675
|
-
"group:project": ["list_projects", "get_project", "create_project", "update_project", "project_info", "deliverable_create", "deliverable_search", "deliverable_list", "deliverable_update"],
|
|
64336
|
+
"group:project": ["list_projects", "get_project", "create_project", "update_project", "delete_project", "project_info", "project_stats", "deliverable_create", "deliverable_search", "deliverable_list", "deliverable_update"],
|
|
63676
64337
|
"group:manager": ["team_list", "team_status", "delegate_message", "team_update", "agent_update", "task_check_duplicates", "task_cleanup_duplicates", "task_board_health"],
|
|
63677
64338
|
"group:packages": ["package_list", "package_install", "hub_search", "hub_install"]
|
|
63678
64339
|
};
|
|
@@ -65857,11 +66518,15 @@ var init_org_service = __esm({
|
|
|
65857
66518
|
pendingAgentStartIds = [];
|
|
65858
66519
|
roleLoader;
|
|
65859
66520
|
storage;
|
|
66521
|
+
deliverableService;
|
|
65860
66522
|
constructor(agentManager, roleLoader, storage) {
|
|
65861
66523
|
this.agentManager = agentManager;
|
|
65862
66524
|
this.roleLoader = roleLoader ?? new RoleLoader();
|
|
65863
66525
|
this.storage = storage;
|
|
65864
66526
|
}
|
|
66527
|
+
setDeliverableService(svc) {
|
|
66528
|
+
this.deliverableService = svc;
|
|
66529
|
+
}
|
|
65865
66530
|
// ─── Human User Management ───
|
|
65866
66531
|
addHumanUser(orgId2, name, role, opts) {
|
|
65867
66532
|
const org = this.orgs.get(orgId2);
|
|
@@ -66430,6 +67095,17 @@ var init_org_service = __esm({
|
|
|
66430
67095
|
if (this.isProtectedAgent(agentId2)) {
|
|
66431
67096
|
throw new Error("The Secretary agent is a protected system agent and cannot be deleted.");
|
|
66432
67097
|
}
|
|
67098
|
+
if (this.deliverableService) {
|
|
67099
|
+
const agentDir = join19(this.agentManager.getDataDir(), agentId2);
|
|
67100
|
+
const sharedDir = this.agentManager.getSharedDataDir();
|
|
67101
|
+
if (sharedDir) {
|
|
67102
|
+
try {
|
|
67103
|
+
await this.deliverableService.migrateAgentFiles(agentId2, agentDir, sharedDir);
|
|
67104
|
+
} catch (err) {
|
|
67105
|
+
log53.warn("Failed to migrate deliverable files before agent removal", { agentId: agentId2, error: String(err) });
|
|
67106
|
+
}
|
|
67107
|
+
}
|
|
67108
|
+
}
|
|
66433
67109
|
const agentInfo = this.agentManager.listAgents().find((a) => a.id === agentId2);
|
|
66434
67110
|
await this.agentManager.removeAgent(agentId2, { purgeFiles: opts?.purgeFiles });
|
|
66435
67111
|
for (const org of this.orgs.values()) {
|
|
@@ -82676,7 +83352,7 @@ ${cleanText}`,
|
|
|
82676
83352
|
});
|
|
82677
83353
|
return;
|
|
82678
83354
|
}
|
|
82679
|
-
if (path.match(/^\/api\/agents\/[^/]+\/(start|stop|daily-report|a2a|message)$/) && req.method === "POST") {
|
|
83355
|
+
if (path.match(/^\/api\/agents\/[^/]+\/(start|stop|pause|resume|cancel-processing|daily-report|a2a|message)$/) && req.method === "POST") {
|
|
82680
83356
|
const authUser = await this.requireAuth(req, res);
|
|
82681
83357
|
if (!authUser)
|
|
82682
83358
|
return;
|
|
@@ -82695,6 +83371,29 @@ ${cleanText}`,
|
|
|
82695
83371
|
this.json(res, 200, { status: "stopped" });
|
|
82696
83372
|
return;
|
|
82697
83373
|
}
|
|
83374
|
+
if (action === "pause") {
|
|
83375
|
+
const body = await this.readBody(req);
|
|
83376
|
+
const reason = body["reason"];
|
|
83377
|
+
const agent = this.orgService.getAgentManager().getAgent(agentId2);
|
|
83378
|
+
agent.pause(reason);
|
|
83379
|
+
this.ws.broadcastAgentUpdate(agentId2, "paused");
|
|
83380
|
+
this.json(res, 200, { status: "paused" });
|
|
83381
|
+
return;
|
|
83382
|
+
}
|
|
83383
|
+
if (action === "resume") {
|
|
83384
|
+
const agent = this.orgService.getAgentManager().getAgent(agentId2);
|
|
83385
|
+
agent.resume();
|
|
83386
|
+
const newStatus = agent.getState().status;
|
|
83387
|
+
this.ws.broadcastAgentUpdate(agentId2, newStatus);
|
|
83388
|
+
this.json(res, 200, { status: newStatus });
|
|
83389
|
+
return;
|
|
83390
|
+
}
|
|
83391
|
+
if (action === "cancel-processing") {
|
|
83392
|
+
const agent = this.orgService.getAgentManager().getAgent(agentId2);
|
|
83393
|
+
agent.cancelActiveStream();
|
|
83394
|
+
this.json(res, 200, { status: "cancelled" });
|
|
83395
|
+
return;
|
|
83396
|
+
}
|
|
82698
83397
|
if (action === "daily-report") {
|
|
82699
83398
|
const agent = this.orgService.getAgentManager().getAgent(agentId2);
|
|
82700
83399
|
const report = await agent.generateDailyReport();
|
|
@@ -83365,6 +84064,16 @@ ${cleanText}`,
|
|
|
83365
84064
|
this.json(res, 200, { results, total });
|
|
83366
84065
|
return;
|
|
83367
84066
|
}
|
|
84067
|
+
if (path === "/api/deliverables/health" && req.method === "GET") {
|
|
84068
|
+
if (!this.deliverableService) {
|
|
84069
|
+
this.json(res, 503, { error: "Deliverable service not available" });
|
|
84070
|
+
return;
|
|
84071
|
+
}
|
|
84072
|
+
const agentId2 = url.searchParams.get("agentId") ?? void 0;
|
|
84073
|
+
const missingIds = this.deliverableService.checkFileHealth(agentId2);
|
|
84074
|
+
this.json(res, 200, { missingFiles: missingIds });
|
|
84075
|
+
return;
|
|
84076
|
+
}
|
|
83368
84077
|
if (path === "/api/deliverables" && req.method === "POST") {
|
|
83369
84078
|
const authUser = await this.requireAuth(req, res);
|
|
83370
84079
|
if (!authUser)
|
|
@@ -85462,12 +86171,12 @@ EXPLANATION_END`;
|
|
|
85462
86171
|
const installedSkills = new Map((this.skillRegistry?.list() ?? []).map((s2) => [s2.name, s2]));
|
|
85463
86172
|
const rawManifests = /* @__PURE__ */ new Map();
|
|
85464
86173
|
try {
|
|
85465
|
-
const { readdirSync: readdirSync14, readFileSync: readFileSync28, existsSync:
|
|
86174
|
+
const { readdirSync: readdirSync14, readFileSync: readFileSync28, existsSync: existsSync39 } = await import("node:fs");
|
|
85466
86175
|
for (const entry of readdirSync14(builtinDir, { withFileTypes: true })) {
|
|
85467
86176
|
if (!entry.isDirectory())
|
|
85468
86177
|
continue;
|
|
85469
86178
|
const sjPath = resolve15(builtinDir, entry.name, "skill.json");
|
|
85470
|
-
if (
|
|
86179
|
+
if (existsSync39(sjPath)) {
|
|
85471
86180
|
try {
|
|
85472
86181
|
rawManifests.set(entry.name, JSON.parse(readFileSync28(sjPath, "utf-8")));
|
|
85473
86182
|
} catch {
|
|
@@ -87378,7 +88087,12 @@ data: ${JSON.stringify({ error: msg })}
|
|
|
87378
88087
|
const mask = (key2) => key2 ? "***" + key2.slice(-4) : "";
|
|
87379
88088
|
this.json(res, 200, {
|
|
87380
88089
|
serper: { configured: !!search.serperApiKey || !!process.env["SERPER_API_KEY"], preview: mask(search.serperApiKey || process.env["SERPER_API_KEY"]) },
|
|
88090
|
+
tavily: { configured: !!search.tavilyApiKey || !!process.env["TAVILY_API_KEY"], preview: mask(search.tavilyApiKey || process.env["TAVILY_API_KEY"]) },
|
|
88091
|
+
bing: { configured: !!search.bingApiKey || !!process.env["BING_SEARCH_API_KEY"], preview: mask(search.bingApiKey || process.env["BING_SEARCH_API_KEY"]) },
|
|
88092
|
+
google: { configured: !!(search.googleSearchApiKey && search.googleSearchCx) || !!(process.env["GOOGLE_SEARCH_API_KEY"] && process.env["GOOGLE_SEARCH_CX"]), preview: mask(search.googleSearchApiKey || process.env["GOOGLE_SEARCH_API_KEY"]) },
|
|
88093
|
+
serpapi: { configured: !!search.serpApiKey || !!process.env["SERPAPI_API_KEY"], preview: mask(search.serpApiKey || process.env["SERPAPI_API_KEY"]) },
|
|
87381
88094
|
brave: { configured: !!search.braveApiKey || !!process.env["BRAVE_SEARCH_API_KEY"], preview: mask(search.braveApiKey || process.env["BRAVE_SEARCH_API_KEY"]) },
|
|
88095
|
+
exa: { configured: !!search.exaApiKey || !!process.env["EXA_API_KEY"], preview: mask(search.exaApiKey || process.env["EXA_API_KEY"]) },
|
|
87382
88096
|
bocha: { configured: !!search.bochaApiKey || !!process.env["BOCHA_API_KEY"], preview: mask(search.bochaApiKey || process.env["BOCHA_API_KEY"]) }
|
|
87383
88097
|
});
|
|
87384
88098
|
return;
|
|
@@ -87396,6 +88110,41 @@ data: ${JSON.stringify({ error: msg })}
|
|
|
87396
88110
|
else
|
|
87397
88111
|
delete process.env["SERPER_API_KEY"];
|
|
87398
88112
|
}
|
|
88113
|
+
if (typeof body["tavilyApiKey"] === "string") {
|
|
88114
|
+
updates.tavilyApiKey = body["tavilyApiKey"] || void 0;
|
|
88115
|
+
if (body["tavilyApiKey"])
|
|
88116
|
+
process.env["TAVILY_API_KEY"] = body["tavilyApiKey"];
|
|
88117
|
+
else
|
|
88118
|
+
delete process.env["TAVILY_API_KEY"];
|
|
88119
|
+
}
|
|
88120
|
+
if (typeof body["bingApiKey"] === "string") {
|
|
88121
|
+
updates.bingApiKey = body["bingApiKey"] || void 0;
|
|
88122
|
+
if (body["bingApiKey"])
|
|
88123
|
+
process.env["BING_SEARCH_API_KEY"] = body["bingApiKey"];
|
|
88124
|
+
else
|
|
88125
|
+
delete process.env["BING_SEARCH_API_KEY"];
|
|
88126
|
+
}
|
|
88127
|
+
if (typeof body["googleSearchApiKey"] === "string") {
|
|
88128
|
+
updates.googleSearchApiKey = body["googleSearchApiKey"] || void 0;
|
|
88129
|
+
if (body["googleSearchApiKey"])
|
|
88130
|
+
process.env["GOOGLE_SEARCH_API_KEY"] = body["googleSearchApiKey"];
|
|
88131
|
+
else
|
|
88132
|
+
delete process.env["GOOGLE_SEARCH_API_KEY"];
|
|
88133
|
+
}
|
|
88134
|
+
if (typeof body["googleSearchCx"] === "string") {
|
|
88135
|
+
updates.googleSearchCx = body["googleSearchCx"] || void 0;
|
|
88136
|
+
if (body["googleSearchCx"])
|
|
88137
|
+
process.env["GOOGLE_SEARCH_CX"] = body["googleSearchCx"];
|
|
88138
|
+
else
|
|
88139
|
+
delete process.env["GOOGLE_SEARCH_CX"];
|
|
88140
|
+
}
|
|
88141
|
+
if (typeof body["serpApiKey"] === "string") {
|
|
88142
|
+
updates.serpApiKey = body["serpApiKey"] || void 0;
|
|
88143
|
+
if (body["serpApiKey"])
|
|
88144
|
+
process.env["SERPAPI_API_KEY"] = body["serpApiKey"];
|
|
88145
|
+
else
|
|
88146
|
+
delete process.env["SERPAPI_API_KEY"];
|
|
88147
|
+
}
|
|
87399
88148
|
if (typeof body["braveApiKey"] === "string") {
|
|
87400
88149
|
updates.braveApiKey = body["braveApiKey"] || void 0;
|
|
87401
88150
|
if (body["braveApiKey"])
|
|
@@ -87403,6 +88152,13 @@ data: ${JSON.stringify({ error: msg })}
|
|
|
87403
88152
|
else
|
|
87404
88153
|
delete process.env["BRAVE_SEARCH_API_KEY"];
|
|
87405
88154
|
}
|
|
88155
|
+
if (typeof body["exaApiKey"] === "string") {
|
|
88156
|
+
updates.exaApiKey = body["exaApiKey"] || void 0;
|
|
88157
|
+
if (body["exaApiKey"])
|
|
88158
|
+
process.env["EXA_API_KEY"] = body["exaApiKey"];
|
|
88159
|
+
else
|
|
88160
|
+
delete process.env["EXA_API_KEY"];
|
|
88161
|
+
}
|
|
87406
88162
|
if (typeof body["bochaApiKey"] === "string") {
|
|
87407
88163
|
updates.bochaApiKey = body["bochaApiKey"] || void 0;
|
|
87408
88164
|
if (body["bochaApiKey"])
|
|
@@ -87430,7 +88186,12 @@ data: ${JSON.stringify({ error: msg })}
|
|
|
87430
88186
|
const mask = (key2) => key2 ? "***" + key2.slice(-4) : "";
|
|
87431
88187
|
this.json(res, 200, {
|
|
87432
88188
|
serper: { configured: !!search.serperApiKey || !!process.env["SERPER_API_KEY"], preview: mask(search.serperApiKey || process.env["SERPER_API_KEY"]) },
|
|
88189
|
+
tavily: { configured: !!search.tavilyApiKey || !!process.env["TAVILY_API_KEY"], preview: mask(search.tavilyApiKey || process.env["TAVILY_API_KEY"]) },
|
|
88190
|
+
bing: { configured: !!search.bingApiKey || !!process.env["BING_SEARCH_API_KEY"], preview: mask(search.bingApiKey || process.env["BING_SEARCH_API_KEY"]) },
|
|
88191
|
+
google: { configured: !!(search.googleSearchApiKey && search.googleSearchCx) || !!(process.env["GOOGLE_SEARCH_API_KEY"] && process.env["GOOGLE_SEARCH_CX"]), preview: mask(search.googleSearchApiKey || process.env["GOOGLE_SEARCH_API_KEY"]) },
|
|
88192
|
+
serpapi: { configured: !!search.serpApiKey || !!process.env["SERPAPI_API_KEY"], preview: mask(search.serpApiKey || process.env["SERPAPI_API_KEY"]) },
|
|
87433
88193
|
brave: { configured: !!search.braveApiKey || !!process.env["BRAVE_SEARCH_API_KEY"], preview: mask(search.braveApiKey || process.env["BRAVE_SEARCH_API_KEY"]) },
|
|
88194
|
+
exa: { configured: !!search.exaApiKey || !!process.env["EXA_API_KEY"], preview: mask(search.exaApiKey || process.env["EXA_API_KEY"]) },
|
|
87434
88195
|
bocha: { configured: !!search.bochaApiKey || !!process.env["BOCHA_API_KEY"], preview: mask(search.bochaApiKey || process.env["BOCHA_API_KEY"]) }
|
|
87435
88196
|
});
|
|
87436
88197
|
return;
|
|
@@ -88696,7 +89457,7 @@ data: ${JSON.stringify({ error: msg })}
|
|
|
88696
89457
|
}
|
|
88697
89458
|
try {
|
|
88698
89459
|
const { resolve: resolve22, extname: extname2 } = await import("node:path");
|
|
88699
|
-
const { existsSync:
|
|
89460
|
+
const { existsSync: existsSync39, statSync: statSync7 } = await import("node:fs");
|
|
88700
89461
|
const { homedir: homedir22 } = await import("node:os");
|
|
88701
89462
|
const home = homedir22();
|
|
88702
89463
|
const results = {};
|
|
@@ -88708,7 +89469,7 @@ data: ${JSON.stringify({ error: msg })}
|
|
|
88708
89469
|
try {
|
|
88709
89470
|
const expanded = p.startsWith("~/") ? resolve22(home, p.slice(2)) : p === "~" ? home : p;
|
|
88710
89471
|
const resolved = resolve22(expanded);
|
|
88711
|
-
if (!
|
|
89472
|
+
if (!existsSync39(resolved)) {
|
|
88712
89473
|
results[p] = { exists: false, isFile: false, type: "unknown" };
|
|
88713
89474
|
continue;
|
|
88714
89475
|
}
|
|
@@ -88745,21 +89506,21 @@ data: ${JSON.stringify({ error: msg })}
|
|
|
88745
89506
|
}
|
|
88746
89507
|
try {
|
|
88747
89508
|
const { resolve: resolve22, extname: extname2 } = await import("node:path");
|
|
88748
|
-
const { readFileSync: readFileSync28, existsSync:
|
|
89509
|
+
const { readFileSync: readFileSync28, existsSync: existsSync39, statSync: statSync7 } = await import("node:fs");
|
|
88749
89510
|
const { homedir: homedir22 } = await import("node:os");
|
|
88750
89511
|
const home = homedir22();
|
|
88751
89512
|
const expanded = filePath.startsWith("~/") ? resolve22(home, filePath.slice(2)) : filePath === "~" ? home : filePath;
|
|
88752
89513
|
const resolved = resolve22(expanded);
|
|
88753
|
-
if (!
|
|
89514
|
+
if (!existsSync39(resolved)) {
|
|
88754
89515
|
this.json(res, 404, { error: "File not found" });
|
|
88755
89516
|
return;
|
|
88756
89517
|
}
|
|
88757
89518
|
const stat = statSync7(resolved);
|
|
88758
89519
|
if (stat.isDirectory()) {
|
|
88759
89520
|
const { readdirSync: readdirSync14 } = await import("node:fs");
|
|
88760
|
-
const { join:
|
|
89521
|
+
const { join: join32, extname: extDir } = await import("node:path");
|
|
88761
89522
|
const entries2 = readdirSync14(resolved, { withFileTypes: true }).filter((e) => !e.name.startsWith(".")).map((e) => {
|
|
88762
|
-
const full =
|
|
89523
|
+
const full = join32(resolved, e.name);
|
|
88763
89524
|
const isDir = e.isDirectory();
|
|
88764
89525
|
let size;
|
|
88765
89526
|
try {
|
|
@@ -88830,12 +89591,12 @@ data: ${JSON.stringify({ error: msg })}
|
|
|
88830
89591
|
}
|
|
88831
89592
|
try {
|
|
88832
89593
|
const { resolve: resolve22, extname: extname2 } = await import("node:path");
|
|
88833
|
-
const { readFileSync: readFileSync28, existsSync:
|
|
89594
|
+
const { readFileSync: readFileSync28, existsSync: existsSync39, statSync: statSync7 } = await import("node:fs");
|
|
88834
89595
|
const { homedir: homedir22 } = await import("node:os");
|
|
88835
89596
|
const home = homedir22();
|
|
88836
89597
|
const expanded = filePath.startsWith("~/") ? resolve22(home, filePath.slice(2)) : filePath === "~" ? home : filePath;
|
|
88837
89598
|
const resolved = resolve22(expanded);
|
|
88838
|
-
if (!
|
|
89599
|
+
if (!existsSync39(resolved) || !statSync7(resolved).isFile()) {
|
|
88839
89600
|
this.json(res, 404, { error: "Image not found" });
|
|
88840
89601
|
return;
|
|
88841
89602
|
}
|
|
@@ -88881,13 +89642,13 @@ data: ${JSON.stringify({ error: msg })}
|
|
|
88881
89642
|
}
|
|
88882
89643
|
try {
|
|
88883
89644
|
const { resolve: resolve22, dirname: dirname12 } = await import("node:path");
|
|
88884
|
-
const { existsSync:
|
|
89645
|
+
const { existsSync: existsSync39, statSync: statSync7 } = await import("node:fs");
|
|
88885
89646
|
const { exec: exec2 } = await import("node:child_process");
|
|
88886
89647
|
const { homedir: homedir22 } = await import("node:os");
|
|
88887
89648
|
const home = homedir22();
|
|
88888
89649
|
const expanded = filePath.startsWith("~/") ? resolve22(home, filePath.slice(2)) : filePath === "~" ? home : filePath;
|
|
88889
89650
|
const resolved = resolve22(expanded);
|
|
88890
|
-
if (!
|
|
89651
|
+
if (!existsSync39(resolved)) {
|
|
88891
89652
|
this.json(res, 404, { error: "Path not found" });
|
|
88892
89653
|
return;
|
|
88893
89654
|
}
|
|
@@ -89612,7 +90373,7 @@ data: ${JSON.stringify({ error: msg })}
|
|
|
89612
90373
|
exact("/api/agents", "GET", "POST"),
|
|
89613
90374
|
exact("/api/agents/role-updates", "GET"),
|
|
89614
90375
|
regex(/^\/api\/agents\/[^/]+\/sessions$/, "GET"),
|
|
89615
|
-
regex(/^\/api\/agents\/[^/]+\/(start|stop|daily-report|a2a|message)$/, "POST"),
|
|
90376
|
+
regex(/^\/api\/agents\/[^/]+\/(start|stop|pause|resume|cancel-processing|daily-report|a2a|message)$/, "POST"),
|
|
89616
90377
|
regex(/^\/api\/agents\/[^/]+$/, "GET", "DELETE"),
|
|
89617
90378
|
regex(/^\/api\/agents\/[^/]+\/mind$/, "GET"),
|
|
89618
90379
|
regex(/^\/api\/agents\/[^/]+\/mailbox$/, "GET"),
|
|
@@ -89695,6 +90456,7 @@ data: ${JSON.stringify({ error: msg })}
|
|
|
89695
90456
|
exact("/api/execution-logs", "GET"),
|
|
89696
90457
|
// ── Deliverables / Knowledge ─────────────────────────────────────────
|
|
89697
90458
|
exact("/api/deliverables", "GET", "POST"),
|
|
90459
|
+
exact("/api/deliverables/health", "GET"),
|
|
89698
90460
|
regex(/^\/api\/deliverables\/[^/]+$/, "GET", "PUT", "DELETE"),
|
|
89699
90461
|
exact("/api/knowledge", "POST"),
|
|
89700
90462
|
exact("/api/knowledge/search", "GET"),
|
|
@@ -92057,6 +92819,11 @@ var init_file_knowledge_store = __esm({
|
|
|
92057
92819
|
});
|
|
92058
92820
|
|
|
92059
92821
|
// ../org-manager/dist/deliverable-service.js
|
|
92822
|
+
import { existsSync as existsSync30, cpSync as cpSync3, mkdirSync as mkdirSync20 } from "node:fs";
|
|
92823
|
+
import { join as join25, basename } from "node:path";
|
|
92824
|
+
function isUrl(s2) {
|
|
92825
|
+
return /^https?:\/\//i.test(s2);
|
|
92826
|
+
}
|
|
92060
92827
|
var log68, DeliverableService;
|
|
92061
92828
|
var init_deliverable_service = __esm({
|
|
92062
92829
|
"../org-manager/dist/deliverable-service.js"() {
|
|
@@ -92103,6 +92870,8 @@ var init_deliverable_service = __esm({
|
|
|
92103
92870
|
patch.diffStats = opts.diffStats;
|
|
92104
92871
|
if (opts.testResults !== void 0)
|
|
92105
92872
|
patch.testResults = opts.testResults;
|
|
92873
|
+
if (opts.taskId && !existing.taskId)
|
|
92874
|
+
patch.taskId = opts.taskId;
|
|
92106
92875
|
const updated = await this.update(existing.id, patch);
|
|
92107
92876
|
log68.info("Deliverable upserted (updated existing)", { id: existing.id, reference: ref });
|
|
92108
92877
|
this.ws?.broadcastDeliverableUpdate(existing.id, "updated", {
|
|
@@ -92223,6 +92992,40 @@ var init_deliverable_service = __esm({
|
|
|
92223
92992
|
const d = this.cache.get(id);
|
|
92224
92993
|
if (!d)
|
|
92225
92994
|
return void 0;
|
|
92995
|
+
const arrEq = (a, b) => JSON.stringify(a) === JSON.stringify(b);
|
|
92996
|
+
const changed = [];
|
|
92997
|
+
if (data.type !== void 0 && data.type !== d.type)
|
|
92998
|
+
changed.push("type");
|
|
92999
|
+
if (data.title !== void 0 && data.title !== d.title)
|
|
93000
|
+
changed.push("title");
|
|
93001
|
+
if (data.summary !== void 0 && data.summary !== d.summary)
|
|
93002
|
+
changed.push("summary");
|
|
93003
|
+
if (data.reference !== void 0 && data.reference !== d.reference)
|
|
93004
|
+
changed.push("reference");
|
|
93005
|
+
if (data.format !== void 0 && data.format !== d.format)
|
|
93006
|
+
changed.push("format");
|
|
93007
|
+
if (data.tags !== void 0 && !arrEq(data.tags, d.tags))
|
|
93008
|
+
changed.push("tags");
|
|
93009
|
+
if (data.status !== void 0 && data.status !== d.status)
|
|
93010
|
+
changed.push("status");
|
|
93011
|
+
if (data.taskId !== void 0 && data.taskId !== d.taskId)
|
|
93012
|
+
changed.push("taskId");
|
|
93013
|
+
if (data.agentId !== void 0 && data.agentId !== d.agentId)
|
|
93014
|
+
changed.push("agentId");
|
|
93015
|
+
if (data.projectId !== void 0 && data.projectId !== d.projectId)
|
|
93016
|
+
changed.push("projectId");
|
|
93017
|
+
if (data.artifactType !== void 0 && data.artifactType !== d.artifactType)
|
|
93018
|
+
changed.push("artifactType");
|
|
93019
|
+
if (data.artifactData !== void 0 && !arrEq(data.artifactData, d.artifactData))
|
|
93020
|
+
changed.push("artifactData");
|
|
93021
|
+
if (data.diffStats !== void 0 && !arrEq(data.diffStats, d.diffStats))
|
|
93022
|
+
changed.push("diffStats");
|
|
93023
|
+
if (data.testResults !== void 0 && !arrEq(data.testResults, d.testResults))
|
|
93024
|
+
changed.push("testResults");
|
|
93025
|
+
if (changed.length === 0) {
|
|
93026
|
+
log68.debug("Deliverable update skipped (no-op)", { id });
|
|
93027
|
+
return d;
|
|
93028
|
+
}
|
|
92226
93029
|
const now3 = (/* @__PURE__ */ new Date()).toISOString();
|
|
92227
93030
|
if (data.type !== void 0)
|
|
92228
93031
|
d.type = data.type;
|
|
@@ -92238,6 +93041,12 @@ var init_deliverable_service = __esm({
|
|
|
92238
93041
|
d.tags = data.tags;
|
|
92239
93042
|
if (data.status !== void 0)
|
|
92240
93043
|
d.status = data.status;
|
|
93044
|
+
if (data.taskId !== void 0)
|
|
93045
|
+
d.taskId = data.taskId;
|
|
93046
|
+
if (data.agentId !== void 0)
|
|
93047
|
+
d.agentId = data.agentId;
|
|
93048
|
+
if (data.projectId !== void 0)
|
|
93049
|
+
d.projectId = data.projectId;
|
|
92241
93050
|
if (data.artifactType !== void 0)
|
|
92242
93051
|
d.artifactType = data.artifactType;
|
|
92243
93052
|
if (data.artifactData !== void 0)
|
|
@@ -92248,7 +93057,7 @@ var init_deliverable_service = __esm({
|
|
|
92248
93057
|
d.testResults = data.testResults;
|
|
92249
93058
|
d.updatedAt = now3;
|
|
92250
93059
|
await this.repo?.update(id, data);
|
|
92251
|
-
log68.info("Deliverable updated", { id, fields:
|
|
93060
|
+
log68.info("Deliverable updated", { id, fields: changed });
|
|
92252
93061
|
this.ws?.broadcastDeliverableUpdate(id, "updated", {
|
|
92253
93062
|
type: d.type,
|
|
92254
93063
|
title: d.title,
|
|
@@ -92331,6 +93140,58 @@ var init_deliverable_service = __esm({
|
|
|
92331
93140
|
}
|
|
92332
93141
|
return cleaned;
|
|
92333
93142
|
}
|
|
93143
|
+
/**
|
|
93144
|
+
* Migrate deliverable files from an agent's workspace to the shared directory
|
|
93145
|
+
* before the agent is deleted. Updates each deliverable's reference to point
|
|
93146
|
+
* at the new shared location.
|
|
93147
|
+
*/
|
|
93148
|
+
async migrateAgentFiles(agentId2, agentDir, sharedDataDir) {
|
|
93149
|
+
const deliverables = this.findByAgent(agentId2);
|
|
93150
|
+
if (deliverables.length === 0)
|
|
93151
|
+
return 0;
|
|
93152
|
+
const sharedDeliverables = join25(sharedDataDir, "deliverables");
|
|
93153
|
+
let migrated = 0;
|
|
93154
|
+
for (const d of deliverables) {
|
|
93155
|
+
if (!d.reference || isUrl(d.reference))
|
|
93156
|
+
continue;
|
|
93157
|
+
if (!d.reference.startsWith(agentDir + "/") && d.reference !== agentDir)
|
|
93158
|
+
continue;
|
|
93159
|
+
if (!existsSync30(d.reference))
|
|
93160
|
+
continue;
|
|
93161
|
+
try {
|
|
93162
|
+
const destDir = join25(sharedDeliverables, d.id);
|
|
93163
|
+
mkdirSync20(destDir, { recursive: true });
|
|
93164
|
+
const fileName = basename(d.reference);
|
|
93165
|
+
const destPath = join25(destDir, fileName);
|
|
93166
|
+
cpSync3(d.reference, destPath, { recursive: true });
|
|
93167
|
+
await this.update(d.id, { reference: destPath });
|
|
93168
|
+
migrated++;
|
|
93169
|
+
log68.info("Deliverable file migrated to shared", { id: d.id, from: d.reference, to: destPath });
|
|
93170
|
+
} catch (err) {
|
|
93171
|
+
log68.warn("Failed to migrate deliverable file", { id: d.id, reference: d.reference, error: String(err) });
|
|
93172
|
+
}
|
|
93173
|
+
}
|
|
93174
|
+
if (migrated > 0) {
|
|
93175
|
+
log68.info("Migrated agent deliverable files to shared directory", { agentId: agentId2, migrated, total: deliverables.length });
|
|
93176
|
+
}
|
|
93177
|
+
return migrated;
|
|
93178
|
+
}
|
|
93179
|
+
/**
|
|
93180
|
+
* Check file health for deliverables: returns IDs of deliverables whose
|
|
93181
|
+
* referenced files no longer exist on disk.
|
|
93182
|
+
*/
|
|
93183
|
+
checkFileHealth(agentId2) {
|
|
93184
|
+
const deliverables = agentId2 ? this.findByAgent(agentId2) : this.getAll();
|
|
93185
|
+
const missing = [];
|
|
93186
|
+
for (const d of deliverables) {
|
|
93187
|
+
if (!d.reference || isUrl(d.reference))
|
|
93188
|
+
continue;
|
|
93189
|
+
if (!existsSync30(d.reference)) {
|
|
93190
|
+
missing.push(d.id);
|
|
93191
|
+
}
|
|
93192
|
+
}
|
|
93193
|
+
return missing;
|
|
93194
|
+
}
|
|
92334
93195
|
/**
|
|
92335
93196
|
* One-time migration: scan existing tasks and create Deliverable entries
|
|
92336
93197
|
* for any task.deliverables that don't yet have a corresponding row.
|
|
@@ -93124,7 +93985,7 @@ var init_scheduled_task_runner = __esm({
|
|
|
93124
93985
|
// ../storage/dist/sqlite-storage.js
|
|
93125
93986
|
import { DatabaseSync } from "node:sqlite";
|
|
93126
93987
|
import { randomUUID } from "node:crypto";
|
|
93127
|
-
import { mkdirSync as
|
|
93988
|
+
import { mkdirSync as mkdirSync21 } from "node:fs";
|
|
93128
93989
|
import { dirname as dirname8 } from "node:path";
|
|
93129
93990
|
function generateId2(prefix = "") {
|
|
93130
93991
|
const uuid = randomUUID().replace(/-/g, "").slice(0, 16);
|
|
@@ -93145,7 +94006,7 @@ function toDate(v) {
|
|
|
93145
94006
|
function openSqlite(dbPath) {
|
|
93146
94007
|
if (_db)
|
|
93147
94008
|
return _db;
|
|
93148
|
-
|
|
94009
|
+
mkdirSync21(dirname8(dbPath), { recursive: true });
|
|
93149
94010
|
_db = new DatabaseSync(dbPath);
|
|
93150
94011
|
_db.exec("PRAGMA journal_mode = WAL");
|
|
93151
94012
|
_db.exec("PRAGMA foreign_keys = ON");
|
|
@@ -95573,6 +96434,18 @@ CREATE TABLE IF NOT EXISTS user_read_cursors (
|
|
|
95573
96434
|
sets.push("type = ?");
|
|
95574
96435
|
vals.push(patch.type);
|
|
95575
96436
|
}
|
|
96437
|
+
if (patch.taskId !== void 0) {
|
|
96438
|
+
sets.push("task_id = ?");
|
|
96439
|
+
vals.push(patch.taskId);
|
|
96440
|
+
}
|
|
96441
|
+
if (patch.agentId !== void 0) {
|
|
96442
|
+
sets.push("agent_id = ?");
|
|
96443
|
+
vals.push(patch.agentId);
|
|
96444
|
+
}
|
|
96445
|
+
if (patch.projectId !== void 0) {
|
|
96446
|
+
sets.push("project_id = ?");
|
|
96447
|
+
vals.push(patch.projectId);
|
|
96448
|
+
}
|
|
95576
96449
|
if (patch.artifactType !== void 0) {
|
|
95577
96450
|
sets.push("artifact_type = ?");
|
|
95578
96451
|
vals.push(patch.artifactType);
|
|
@@ -96343,16 +97216,16 @@ var init_dist5 = __esm({
|
|
|
96343
97216
|
|
|
96344
97217
|
// ../org-manager/dist/storage-bridge.js
|
|
96345
97218
|
import { homedir as homedir15 } from "node:os";
|
|
96346
|
-
import { join as
|
|
97219
|
+
import { join as join26 } from "node:path";
|
|
96347
97220
|
function resolveSqlitePath(url) {
|
|
96348
97221
|
if (url?.startsWith("sqlite:")) {
|
|
96349
97222
|
let p = url.slice("sqlite:".length);
|
|
96350
97223
|
if (p.startsWith("~/") || p === "~") {
|
|
96351
|
-
p =
|
|
97224
|
+
p = join26(homedir15(), p.slice(2));
|
|
96352
97225
|
}
|
|
96353
97226
|
return p;
|
|
96354
97227
|
}
|
|
96355
|
-
return
|
|
97228
|
+
return join26(homedir15(), ".markus", "data.db");
|
|
96356
97229
|
}
|
|
96357
97230
|
async function initStorage(databaseUrl) {
|
|
96358
97231
|
const url = databaseUrl ?? process.env["DATABASE_URL"];
|
|
@@ -96409,8 +97282,8 @@ var init_storage_bridge = __esm({
|
|
|
96409
97282
|
});
|
|
96410
97283
|
|
|
96411
97284
|
// ../org-manager/dist/file-storage-provider.js
|
|
96412
|
-
import { mkdirSync as
|
|
96413
|
-
import { join as
|
|
97285
|
+
import { mkdirSync as mkdirSync22, writeFileSync as writeFileSync18, unlinkSync as unlinkSync4, existsSync as existsSync31 } from "node:fs";
|
|
97286
|
+
import { join as join27, extname } from "node:path";
|
|
96414
97287
|
import { homedir as homedir16 } from "node:os";
|
|
96415
97288
|
function mimeToExt(mime) {
|
|
96416
97289
|
const map = {
|
|
@@ -96431,27 +97304,27 @@ var init_file_storage_provider = __esm({
|
|
|
96431
97304
|
LocalFileStorageProvider = class {
|
|
96432
97305
|
baseDir;
|
|
96433
97306
|
constructor(baseDir) {
|
|
96434
|
-
this.baseDir = baseDir ??
|
|
96435
|
-
|
|
97307
|
+
this.baseDir = baseDir ?? join27(homedir16(), ".markus", "uploads");
|
|
97308
|
+
mkdirSync22(this.baseDir, { recursive: true });
|
|
96436
97309
|
}
|
|
96437
97310
|
async upload(data, opts) {
|
|
96438
97311
|
const ext = extname(opts.name) || mimeToExt(opts.contentType);
|
|
96439
97312
|
const key2 = `${generateId("upl")}${ext}`;
|
|
96440
|
-
const subDir = opts.prefix ?
|
|
96441
|
-
|
|
96442
|
-
writeFileSync18(
|
|
97313
|
+
const subDir = opts.prefix ? join27(this.baseDir, opts.prefix) : this.baseDir;
|
|
97314
|
+
mkdirSync22(subDir, { recursive: true });
|
|
97315
|
+
writeFileSync18(join27(subDir, key2), data);
|
|
96443
97316
|
const urlPath = opts.prefix ? `/api/uploads/${opts.prefix}/${key2}` : `/api/uploads/${key2}`;
|
|
96444
97317
|
return { url: urlPath, key: opts.prefix ? `${opts.prefix}/${key2}` : key2 };
|
|
96445
97318
|
}
|
|
96446
97319
|
async delete(key2) {
|
|
96447
|
-
const filePath =
|
|
96448
|
-
if (
|
|
97320
|
+
const filePath = join27(this.baseDir, key2);
|
|
97321
|
+
if (existsSync31(filePath)) {
|
|
96449
97322
|
unlinkSync4(filePath);
|
|
96450
97323
|
}
|
|
96451
97324
|
}
|
|
96452
97325
|
/** Resolve a storage key to an absolute filesystem path (for serving). */
|
|
96453
97326
|
resolve(key2) {
|
|
96454
|
-
return
|
|
97327
|
+
return join27(this.baseDir, key2);
|
|
96455
97328
|
}
|
|
96456
97329
|
};
|
|
96457
97330
|
}
|
|
@@ -97181,17 +98054,17 @@ var init_dist7 = __esm({
|
|
|
97181
98054
|
});
|
|
97182
98055
|
|
|
97183
98056
|
// src/utils/logger.ts
|
|
97184
|
-
import { createWriteStream as createWriteStream2, existsSync as
|
|
97185
|
-
import { join as
|
|
98057
|
+
import { createWriteStream as createWriteStream2, existsSync as existsSync32, mkdirSync as mkdirSync23, appendFileSync as appendFileSync3 } from "node:fs";
|
|
98058
|
+
import { join as join28 } from "node:path";
|
|
97186
98059
|
import { homedir as homedir17 } from "node:os";
|
|
97187
98060
|
function ensureLogDir2() {
|
|
97188
|
-
if (!
|
|
97189
|
-
|
|
98061
|
+
if (!existsSync32(LOG_DIR2)) {
|
|
98062
|
+
mkdirSync23(LOG_DIR2, { recursive: true, mode: 493 });
|
|
97190
98063
|
}
|
|
97191
98064
|
}
|
|
97192
98065
|
function getStartupLogPath() {
|
|
97193
98066
|
const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
97194
|
-
return
|
|
98067
|
+
return join28(LOG_DIR2, `startup-${date}.log`);
|
|
97195
98068
|
}
|
|
97196
98069
|
function setSuppressConsole(suppress) {
|
|
97197
98070
|
_suppressConsole = suppress;
|
|
@@ -97246,7 +98119,7 @@ var LOG_DIR2, startupLogStream, startupLogPath, _suppressConsole, LEVEL_PREFIX;
|
|
|
97246
98119
|
var init_logger2 = __esm({
|
|
97247
98120
|
"src/utils/logger.ts"() {
|
|
97248
98121
|
"use strict";
|
|
97249
|
-
LOG_DIR2 =
|
|
98122
|
+
LOG_DIR2 = join28(homedir17(), ".markus", "logs");
|
|
97250
98123
|
startupLogStream = null;
|
|
97251
98124
|
startupLogPath = "";
|
|
97252
98125
|
_suppressConsole = false;
|
|
@@ -97303,8 +98176,8 @@ var init_browser = __esm({
|
|
|
97303
98176
|
|
|
97304
98177
|
// src/utils/startupProgress.ts
|
|
97305
98178
|
import { homedir as homedir18 } from "node:os";
|
|
97306
|
-
import { appendFileSync as appendFileSync4, existsSync as
|
|
97307
|
-
import { join as
|
|
98179
|
+
import { appendFileSync as appendFileSync4, existsSync as existsSync33, mkdirSync as mkdirSync24 } from "node:fs";
|
|
98180
|
+
import { join as join29 } from "node:path";
|
|
97308
98181
|
function clearScreen() {
|
|
97309
98182
|
return "\x1B[2J\x1B[H";
|
|
97310
98183
|
}
|
|
@@ -97466,8 +98339,8 @@ var init_startupProgress = __esm({
|
|
|
97466
98339
|
const line = `${ts} ${msg}
|
|
97467
98340
|
`;
|
|
97468
98341
|
try {
|
|
97469
|
-
const dir =
|
|
97470
|
-
if (!
|
|
98342
|
+
const dir = join29(homedir18(), ".markus", "logs");
|
|
98343
|
+
if (!existsSync33(dir)) mkdirSync24(dir, { recursive: true, mode: 493 });
|
|
97471
98344
|
appendFileSync4(this.logPath, line, { mode: 420 });
|
|
97472
98345
|
} catch {
|
|
97473
98346
|
}
|
|
@@ -97576,8 +98449,8 @@ var init_startupProgress = __esm({
|
|
|
97576
98449
|
});
|
|
97577
98450
|
|
|
97578
98451
|
// src/connector-service.ts
|
|
97579
|
-
import { resolve as resolve16, join as
|
|
97580
|
-
import { existsSync as
|
|
98452
|
+
import { resolve as resolve16, join as join30, dirname as dirname9 } from "node:path";
|
|
98453
|
+
import { existsSync as existsSync34, readFileSync as readFileSync23, writeFileSync as writeFileSync19, mkdirSync as mkdirSync25, readdirSync as readdirSync13, cpSync as cpSync4 } from "node:fs";
|
|
97581
98454
|
import { homedir as homedir19 } from "node:os";
|
|
97582
98455
|
import { execSync as execSync4 } from "node:child_process";
|
|
97583
98456
|
import { fileURLToPath as fileURLToPath5 } from "node:url";
|
|
@@ -97590,16 +98463,16 @@ function loadConnectors() {
|
|
|
97590
98463
|
loadFromDir(builtinDir, connectors);
|
|
97591
98464
|
const devDir = resolve16(process.cwd(), "packages", "cli", "connectors");
|
|
97592
98465
|
if (devDir !== builtinDir) loadFromDir(devDir, connectors);
|
|
97593
|
-
const userDir =
|
|
98466
|
+
const userDir = join30(homedir19(), ".markus", "connectors");
|
|
97594
98467
|
loadFromDir(userDir, connectors);
|
|
97595
98468
|
return [...connectors.values()].filter((c) => c.platform !== "_template");
|
|
97596
98469
|
}
|
|
97597
98470
|
function loadFromDir(dir, map) {
|
|
97598
|
-
if (!
|
|
98471
|
+
if (!existsSync34(dir)) return;
|
|
97599
98472
|
for (const file of readdirSync13(dir)) {
|
|
97600
98473
|
if (!file.endsWith(".json") || file.startsWith("_")) continue;
|
|
97601
98474
|
try {
|
|
97602
|
-
const raw = readFileSync23(
|
|
98475
|
+
const raw = readFileSync23(join30(dir, file), "utf-8");
|
|
97603
98476
|
const desc = JSON.parse(raw);
|
|
97604
98477
|
if (desc.platform) {
|
|
97605
98478
|
map.set(desc.platform, desc);
|
|
@@ -97624,7 +98497,7 @@ function scanInstalledPlatforms() {
|
|
|
97624
98497
|
};
|
|
97625
98498
|
for (const p of c.detection.configPaths) {
|
|
97626
98499
|
const expanded = expandHome(p);
|
|
97627
|
-
if (
|
|
98500
|
+
if (existsSync34(expanded)) {
|
|
97628
98501
|
result.installed = true;
|
|
97629
98502
|
result.configPath = expanded;
|
|
97630
98503
|
break;
|
|
@@ -97651,7 +98524,7 @@ function scanInstalledPlatforms() {
|
|
|
97651
98524
|
}
|
|
97652
98525
|
function readPlatformConfig(connector) {
|
|
97653
98526
|
const configPath = expandHome(connector.integration.configPath);
|
|
97654
|
-
if (!
|
|
98527
|
+
if (!existsSync34(configPath)) return null;
|
|
97655
98528
|
try {
|
|
97656
98529
|
const raw = readFileSync23(configPath, "utf-8");
|
|
97657
98530
|
if (connector.integration.configFormat === "json5") {
|
|
@@ -97666,11 +98539,11 @@ function readPlatformConfig(connector) {
|
|
|
97666
98539
|
function writePlatformConfig(connector, markusUrl, token) {
|
|
97667
98540
|
const configPath = expandHome(connector.integration.configPath);
|
|
97668
98541
|
const configDir = dirname9(configPath);
|
|
97669
|
-
if (!
|
|
97670
|
-
|
|
98542
|
+
if (!existsSync34(configDir)) {
|
|
98543
|
+
mkdirSync25(configDir, { recursive: true });
|
|
97671
98544
|
}
|
|
97672
98545
|
let config = {};
|
|
97673
|
-
if (
|
|
98546
|
+
if (existsSync34(configPath)) {
|
|
97674
98547
|
const existing = readPlatformConfig(connector);
|
|
97675
98548
|
if (existing) config = existing;
|
|
97676
98549
|
}
|
|
@@ -97691,24 +98564,24 @@ function installSkillTemplate(connector) {
|
|
|
97691
98564
|
const skillDir = expandHome(connector.integration.skillDir);
|
|
97692
98565
|
const templateName = connector.integration.skillTemplateName;
|
|
97693
98566
|
const candidates = [
|
|
97694
|
-
|
|
98567
|
+
join30(homedir19(), ".markus", "templates", templateName),
|
|
97695
98568
|
resolve16(process.cwd(), "templates", templateName),
|
|
97696
98569
|
resolve16(__dirname4, "..", "templates", templateName)
|
|
97697
98570
|
];
|
|
97698
98571
|
let sourceDir;
|
|
97699
98572
|
for (const c of candidates) {
|
|
97700
|
-
if (
|
|
98573
|
+
if (existsSync34(c)) {
|
|
97701
98574
|
sourceDir = c;
|
|
97702
98575
|
break;
|
|
97703
98576
|
}
|
|
97704
98577
|
}
|
|
97705
98578
|
if (!sourceDir) return false;
|
|
97706
|
-
const targetDir =
|
|
97707
|
-
if (!
|
|
97708
|
-
|
|
98579
|
+
const targetDir = join30(skillDir, templateName);
|
|
98580
|
+
if (!existsSync34(targetDir)) {
|
|
98581
|
+
mkdirSync25(targetDir, { recursive: true });
|
|
97709
98582
|
}
|
|
97710
98583
|
try {
|
|
97711
|
-
|
|
98584
|
+
cpSync4(sourceDir, targetDir, { recursive: true });
|
|
97712
98585
|
return true;
|
|
97713
98586
|
} catch {
|
|
97714
98587
|
return false;
|
|
@@ -97758,7 +98631,7 @@ __export(init_exports, {
|
|
|
97758
98631
|
registerInitCommand: () => registerInitCommand
|
|
97759
98632
|
});
|
|
97760
98633
|
import { resolve as resolve17 } from "node:path";
|
|
97761
|
-
import { readFileSync as readFileSync24, existsSync as
|
|
98634
|
+
import { readFileSync as readFileSync24, existsSync as existsSync35, cpSync as cpSync5 } from "node:fs";
|
|
97762
98635
|
import { homedir as homedir20 } from "node:os";
|
|
97763
98636
|
function registerInitCommand(program2) {
|
|
97764
98637
|
program2.command("init").description("Setup wizard: configure LLM provider, API keys, and server settings").option("--force", "Overwrite existing configuration").option("--non-interactive", "Run without prompts (use env vars or --import-from)").option("--provider <name>", "LLM provider (anthropic/openai/google/minimax/siliconflow/zai/deepseek/ollama)").option("--api-key <key>", "LLM API key").option("--port <port>", "API server port", "8056").option("--import-from <platform>", "Import LLM config from an installed agent platform (e.g. openclaw, hermes)").option("--auto-connect", "Auto-connect detected agent platforms after init").action(async (opts) => {
|
|
@@ -97774,7 +98647,7 @@ function registerInitCommand(program2) {
|
|
|
97774
98647
|
});
|
|
97775
98648
|
}
|
|
97776
98649
|
async function quickInit(options) {
|
|
97777
|
-
const { writeFileSync: writeFileSync21, mkdirSync:
|
|
98650
|
+
const { writeFileSync: writeFileSync21, mkdirSync: mkdirSync27 } = await import("node:fs");
|
|
97778
98651
|
const { join: pathJoin } = await import("node:path");
|
|
97779
98652
|
const readline4 = await import("node:readline");
|
|
97780
98653
|
const nonInteractive = options?.nonInteractive ?? false;
|
|
@@ -97795,7 +98668,7 @@ async function quickInit(options) {
|
|
|
97795
98668
|
\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518
|
|
97796
98669
|
`);
|
|
97797
98670
|
const configPath = getDefaultConfigPath();
|
|
97798
|
-
if (
|
|
98671
|
+
if (existsSync35(configPath) && !options?.force) {
|
|
97799
98672
|
if (nonInteractive) {
|
|
97800
98673
|
console.log(` Existing configuration found. Use --force to overwrite.`);
|
|
97801
98674
|
rl?.close();
|
|
@@ -97844,7 +98717,7 @@ async function quickInit(options) {
|
|
|
97844
98717
|
pathJoin(homedir20(), ".openclaw", "openclaw.json5")
|
|
97845
98718
|
];
|
|
97846
98719
|
for (const p of openclawCandidates) {
|
|
97847
|
-
if (
|
|
98720
|
+
if (existsSync35(p)) {
|
|
97848
98721
|
openclawPath = p;
|
|
97849
98722
|
break;
|
|
97850
98723
|
}
|
|
@@ -98048,15 +98921,15 @@ async function quickInit(options) {
|
|
|
98048
98921
|
}
|
|
98049
98922
|
const userTemplatesDir = pathJoin(homedir20(), ".markus", "templates");
|
|
98050
98923
|
const builtinTemplatesDir = resolveTemplatesDir("roles");
|
|
98051
|
-
if (builtinTemplatesDir &&
|
|
98924
|
+
if (builtinTemplatesDir && existsSync35(builtinTemplatesDir) && !existsSync35(userTemplatesDir)) {
|
|
98052
98925
|
const builtinRoot = resolve17(builtinTemplatesDir, "..");
|
|
98053
|
-
|
|
98054
|
-
|
|
98926
|
+
mkdirSync27(userTemplatesDir, { recursive: true });
|
|
98927
|
+
cpSync5(builtinRoot, userTemplatesDir, { recursive: true });
|
|
98055
98928
|
console.log(` Copied templates to ${userTemplatesDir}`);
|
|
98056
98929
|
}
|
|
98057
98930
|
const devRoleDir = pathJoin(userTemplatesDir || pathJoin(process.cwd(), "templates"), "roles", "developer");
|
|
98058
|
-
if (!
|
|
98059
|
-
|
|
98931
|
+
if (!existsSync35(devRoleDir)) {
|
|
98932
|
+
mkdirSync27(devRoleDir, { recursive: true });
|
|
98060
98933
|
writeFileSync21(
|
|
98061
98934
|
pathJoin(devRoleDir, "ROLE.md"),
|
|
98062
98935
|
[
|
|
@@ -98993,15 +99866,15 @@ var start_exports = {};
|
|
|
98993
99866
|
__export(start_exports, {
|
|
98994
99867
|
registerStartCommand: () => registerStartCommand
|
|
98995
99868
|
});
|
|
98996
|
-
import { resolve as resolve18, join as
|
|
98997
|
-
import { existsSync as
|
|
99869
|
+
import { resolve as resolve18, join as join31, dirname as dirname10 } from "node:path";
|
|
99870
|
+
import { existsSync as existsSync36, readFileSync as readFileSync25 } from "node:fs";
|
|
98998
99871
|
import { homedir as homedir21 } from "node:os";
|
|
98999
99872
|
function registerStartCommand(program2) {
|
|
99000
99873
|
program2.command("start").description("Start the Markus server (auto-initializes on first run)").option("--setup", "Force re-run the interactive setup wizard before starting").action(async (opts) => {
|
|
99001
99874
|
const globalOpts = program2.optsWithGlobals();
|
|
99002
99875
|
const configPath = globalOpts.config ?? getDefaultConfigPath();
|
|
99003
|
-
if (opts.setup || !
|
|
99004
|
-
if (!
|
|
99876
|
+
if (opts.setup || !existsSync36(configPath)) {
|
|
99877
|
+
if (!existsSync36(configPath)) {
|
|
99005
99878
|
console.log(" No configuration found \u2014 auto-configuring from environment...\n");
|
|
99006
99879
|
}
|
|
99007
99880
|
const { quickInit: quickInit2 } = await Promise.resolve().then(() => (init_init(), init_exports));
|
|
@@ -99130,8 +100003,8 @@ async function createServices(config) {
|
|
|
99130
100003
|
extraSkillDirs: skillDirs
|
|
99131
100004
|
});
|
|
99132
100005
|
const storage = await initStorage(config.database?.url);
|
|
99133
|
-
const markusDataDir =
|
|
99134
|
-
const sharedDataDir =
|
|
100006
|
+
const markusDataDir = join31(homedir21(), ".markus");
|
|
100007
|
+
const sharedDataDir = join31(markusDataDir, "shared");
|
|
99135
100008
|
const taskService = new TaskService();
|
|
99136
100009
|
taskService.setSharedDataDir(sharedDataDir);
|
|
99137
100010
|
if (storage) {
|
|
@@ -99163,7 +100036,7 @@ async function createServices(config) {
|
|
|
99163
100036
|
const agentManager = new AgentManager({
|
|
99164
100037
|
llmRouter,
|
|
99165
100038
|
roleLoader,
|
|
99166
|
-
dataDir:
|
|
100039
|
+
dataDir: join31(markusDataDir, "agents"),
|
|
99167
100040
|
sharedDataDir,
|
|
99168
100041
|
skillRegistry,
|
|
99169
100042
|
taskService,
|
|
@@ -99280,8 +100153,8 @@ async function startServer(config, values) {
|
|
|
99280
100153
|
const extraPaths = [];
|
|
99281
100154
|
const selfBinDir = dirname10(resolve18(process.argv[1] ?? ""));
|
|
99282
100155
|
if (selfBinDir && !currentPath.includes(selfBinDir)) extraPaths.push(selfBinDir);
|
|
99283
|
-
const cwdBin =
|
|
99284
|
-
if (
|
|
100156
|
+
const cwdBin = join31(process.cwd(), "node_modules", ".bin");
|
|
100157
|
+
if (existsSync36(cwdBin) && !currentPath.includes(cwdBin)) extraPaths.push(cwdBin);
|
|
99285
100158
|
if (extraPaths.length > 0) {
|
|
99286
100159
|
process.env["PATH"] = `${extraPaths.join(":")}:${currentPath}`;
|
|
99287
100160
|
}
|
|
@@ -99291,9 +100164,27 @@ async function startServer(config, values) {
|
|
|
99291
100164
|
if (config.integrations?.search?.serperApiKey && !process.env["SERPER_API_KEY"]) {
|
|
99292
100165
|
process.env["SERPER_API_KEY"] = config.integrations.search.serperApiKey;
|
|
99293
100166
|
}
|
|
100167
|
+
if (config.integrations?.search?.tavilyApiKey && !process.env["TAVILY_API_KEY"]) {
|
|
100168
|
+
process.env["TAVILY_API_KEY"] = config.integrations.search.tavilyApiKey;
|
|
100169
|
+
}
|
|
100170
|
+
if (config.integrations?.search?.bingApiKey && !process.env["BING_SEARCH_API_KEY"]) {
|
|
100171
|
+
process.env["BING_SEARCH_API_KEY"] = config.integrations.search.bingApiKey;
|
|
100172
|
+
}
|
|
100173
|
+
if (config.integrations?.search?.googleSearchApiKey && !process.env["GOOGLE_SEARCH_API_KEY"]) {
|
|
100174
|
+
process.env["GOOGLE_SEARCH_API_KEY"] = config.integrations.search.googleSearchApiKey;
|
|
100175
|
+
}
|
|
100176
|
+
if (config.integrations?.search?.googleSearchCx && !process.env["GOOGLE_SEARCH_CX"]) {
|
|
100177
|
+
process.env["GOOGLE_SEARCH_CX"] = config.integrations.search.googleSearchCx;
|
|
100178
|
+
}
|
|
100179
|
+
if (config.integrations?.search?.serpApiKey && !process.env["SERPAPI_API_KEY"]) {
|
|
100180
|
+
process.env["SERPAPI_API_KEY"] = config.integrations.search.serpApiKey;
|
|
100181
|
+
}
|
|
99294
100182
|
if (config.integrations?.search?.braveApiKey && !process.env["BRAVE_SEARCH_API_KEY"]) {
|
|
99295
100183
|
process.env["BRAVE_SEARCH_API_KEY"] = config.integrations.search.braveApiKey;
|
|
99296
100184
|
}
|
|
100185
|
+
if (config.integrations?.search?.exaApiKey && !process.env["EXA_API_KEY"]) {
|
|
100186
|
+
process.env["EXA_API_KEY"] = config.integrations.search.exaApiKey;
|
|
100187
|
+
}
|
|
99297
100188
|
if (config.integrations?.search?.bochaApiKey && !process.env["BOCHA_API_KEY"]) {
|
|
99298
100189
|
process.env["BOCHA_API_KEY"] = config.integrations.search.bochaApiKey;
|
|
99299
100190
|
}
|
|
@@ -99328,7 +100219,7 @@ async function startServer(config, values) {
|
|
|
99328
100219
|
projectService.setProjectRepo(storage.projectRepo);
|
|
99329
100220
|
}
|
|
99330
100221
|
await projectService.loadFromDB("default");
|
|
99331
|
-
const knowledgeStore = new FileKnowledgeStore(
|
|
100222
|
+
const knowledgeStore = new FileKnowledgeStore(join31(homedir21(), ".markus", "knowledge"));
|
|
99332
100223
|
const knowledgeService = new KnowledgeService(knowledgeStore);
|
|
99333
100224
|
const deliverableService = new DeliverableService(storage?.deliverableRepo);
|
|
99334
100225
|
await deliverableService.load();
|
|
@@ -99358,7 +100249,6 @@ async function startServer(config, values) {
|
|
|
99358
100249
|
requirementService.rebuildTaskLinks(taskService.listTasks());
|
|
99359
100250
|
agentManager.setRequirementService(requirementService);
|
|
99360
100251
|
agentManager.setProjectService(projectService);
|
|
99361
|
-
agentManager.setKnowledgeService(knowledgeService);
|
|
99362
100252
|
agentManager.setDeliverableService(deliverableService);
|
|
99363
100253
|
agentManager.setWebUiBaseUrl(`http://localhost:${apiPort}`);
|
|
99364
100254
|
requirementService.setAgentManager(agentManager);
|
|
@@ -99369,6 +100259,7 @@ async function startServer(config, values) {
|
|
|
99369
100259
|
apiServer.setDeliverableService(deliverableService);
|
|
99370
100260
|
apiServer.setRequirementService(requirementService);
|
|
99371
100261
|
taskService.setDeliverableService(deliverableService);
|
|
100262
|
+
orgService.setDeliverableService(deliverableService);
|
|
99372
100263
|
taskService.setProjectService(projectService);
|
|
99373
100264
|
taskService.setRequirementService(requirementService);
|
|
99374
100265
|
const archiveService = new ArchiveService(taskService, projectService);
|
|
@@ -99423,7 +100314,7 @@ async function startServer(config, values) {
|
|
|
99423
100314
|
const builderService = apiServer.getBuilderService();
|
|
99424
100315
|
if (builderService) {
|
|
99425
100316
|
const builtinTeamsDir = resolveTemplatesDir("teams");
|
|
99426
|
-
if (builtinTeamsDir &&
|
|
100317
|
+
if (builtinTeamsDir && existsSync36(builtinTeamsDir)) {
|
|
99427
100318
|
builderService.setBuiltinTeamTemplatesDir(builtinTeamsDir);
|
|
99428
100319
|
}
|
|
99429
100320
|
agentManager.setBuilderService(builderService);
|
|
@@ -99725,9 +100616,9 @@ ${reason}`;
|
|
|
99725
100616
|
apiServer.setGateway(gateway, gatewaySecret);
|
|
99726
100617
|
log87.info("External Agent Gateway enabled", { secret: gatewaySecret === "markus-gateway-default-secret-change-me" ? "(default)" : "(custom)" });
|
|
99727
100618
|
{
|
|
99728
|
-
const hubTokenPath =
|
|
100619
|
+
const hubTokenPath = join31(homedir21(), ".markus", "hub-token");
|
|
99729
100620
|
const createRemoteAgent = async () => {
|
|
99730
|
-
const token =
|
|
100621
|
+
const token = existsSync36(hubTokenPath) ? readFileSync25(hubTokenPath, "utf-8").trim() : void 0;
|
|
99731
100622
|
if (!token) return null;
|
|
99732
100623
|
const { RemoteAccessAgent: RemoteAccessAgent2 } = await Promise.resolve().then(() => (init_dist8(), dist_exports6));
|
|
99733
100624
|
return new RemoteAccessAgent2({
|
|
@@ -101115,8 +102006,8 @@ ${C3.BOLD}\u25C6 Summary${C3.RESET}
|
|
|
101115
102006
|
}
|
|
101116
102007
|
async function getDefaultConfigPath2() {
|
|
101117
102008
|
const { homedir: homedir22 } = await import("node:os");
|
|
101118
|
-
const { join:
|
|
101119
|
-
return
|
|
102009
|
+
const { join: join32 } = await import("node:path");
|
|
102010
|
+
return join32(homedir22(), ".markus", "markus.json");
|
|
101120
102011
|
}
|
|
101121
102012
|
function registerDoctorCommand(program2) {
|
|
101122
102013
|
program2.command("doctor").description("Diagnose Markus configuration issues and environment health").option("--fix", "Attempt to automatically fix issues").option("--verbose", "Show detailed output").action(async (opts) => {
|
|
@@ -101851,9 +102742,9 @@ ${C6.BOLD}\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u25
|
|
|
101851
102742
|
gateway.command("logs").description("Show recent gateway logs").option("--lines <n>", "Number of lines", "50").action(async (opts) => {
|
|
101852
102743
|
const lines = parseInt(opts.lines ?? "50", 10);
|
|
101853
102744
|
const { homedir: homedir22 } = await import("node:os");
|
|
101854
|
-
const { join:
|
|
102745
|
+
const { join: join32 } = await import("node:path");
|
|
101855
102746
|
const fs = await import("node:fs");
|
|
101856
|
-
const logPath =
|
|
102747
|
+
const logPath = join32(homedir22(), ".markus", "logs", "markus.log");
|
|
101857
102748
|
if (!fs.existsSync(logPath)) {
|
|
101858
102749
|
warn3("No log file found", logPath);
|
|
101859
102750
|
return;
|
|
@@ -103736,7 +104627,7 @@ var skill_exports = {};
|
|
|
103736
104627
|
__export(skill_exports, {
|
|
103737
104628
|
registerSkillCommands: () => registerSkillCommands
|
|
103738
104629
|
});
|
|
103739
|
-
import { writeFileSync as writeFileSync20, mkdirSync as
|
|
104630
|
+
import { writeFileSync as writeFileSync20, mkdirSync as mkdirSync26 } from "node:fs";
|
|
103740
104631
|
import { resolve as resolve19 } from "node:path";
|
|
103741
104632
|
function registerSkillCommands(program2) {
|
|
103742
104633
|
const root = program2.command("skill").description("Skills registry and local scaffold");
|
|
@@ -103826,7 +104717,7 @@ function registerSkillCommands(program2) {
|
|
|
103826
104717
|
const out = { json: !!g.json };
|
|
103827
104718
|
if (!opts.dir && !opts.name) fail("Specify --dir or --name");
|
|
103828
104719
|
const dir = resolve19(process.cwd(), opts.dir ?? opts.name);
|
|
103829
|
-
|
|
104720
|
+
mkdirSync26(dir, { recursive: true });
|
|
103830
104721
|
const skillName = opts.name ?? (opts.dir ? opts.dir.replace(/.*[/\\]/, "") : "my-skill");
|
|
103831
104722
|
const skillJson = {
|
|
103832
104723
|
name: skillName,
|
|
@@ -103868,13 +104759,13 @@ __export(system_exports, {
|
|
|
103868
104759
|
registerSystemCommands: () => registerSystemCommands
|
|
103869
104760
|
});
|
|
103870
104761
|
import { execSync as execSync6 } from "node:child_process";
|
|
103871
|
-
import { existsSync as
|
|
104762
|
+
import { existsSync as existsSync37, readFileSync as readFileSync26 } from "node:fs";
|
|
103872
104763
|
import { resolve as resolve20, dirname as dirname11 } from "node:path";
|
|
103873
104764
|
import { fileURLToPath as fileURLToPath6 } from "node:url";
|
|
103874
104765
|
function findMarkusRoot() {
|
|
103875
104766
|
let dir = dirname11(fileURLToPath6(import.meta.url));
|
|
103876
104767
|
for (let i = 0; i < 10; i++) {
|
|
103877
|
-
if (
|
|
104768
|
+
if (existsSync37(resolve20(dir, "package.json")) && existsSync37(resolve20(dir, "packages"))) return dir;
|
|
103878
104769
|
dir = dirname11(dir);
|
|
103879
104770
|
}
|
|
103880
104771
|
return null;
|
|
@@ -104021,7 +104912,7 @@ function registerSystemCommands(program2) {
|
|
|
104021
104912
|
}
|
|
104022
104913
|
}
|
|
104023
104914
|
try {
|
|
104024
|
-
const isGit =
|
|
104915
|
+
const isGit = existsSync37(resolve20(markusRoot, ".git"));
|
|
104025
104916
|
if (isGit) {
|
|
104026
104917
|
info4.gitBranch = execSync6("git rev-parse --abbrev-ref HEAD", { cwd: markusRoot, encoding: "utf-8" }).trim();
|
|
104027
104918
|
info4.gitCommit = execSync6("git rev-parse --short HEAD", { cwd: markusRoot, encoding: "utf-8" }).trim();
|
|
@@ -104060,7 +104951,7 @@ function registerSystemCommands(program2) {
|
|
|
104060
104951
|
fail("Cannot locate Markus installation directory");
|
|
104061
104952
|
return;
|
|
104062
104953
|
}
|
|
104063
|
-
if (!
|
|
104954
|
+
if (!existsSync37(resolve20(markusRoot, ".git"))) {
|
|
104064
104955
|
fail("Markus installation is not a git repository. Update manually.");
|
|
104065
104956
|
return;
|
|
104066
104957
|
}
|
|
@@ -104626,7 +105517,7 @@ var init_settings2 = __esm({
|
|
|
104626
105517
|
|
|
104627
105518
|
// src/index.ts
|
|
104628
105519
|
import { resolve as resolve21 } from "node:path";
|
|
104629
|
-
import { readFileSync as readFileSync27, existsSync as
|
|
105520
|
+
import { readFileSync as readFileSync27, existsSync as existsSync38 } from "node:fs";
|
|
104630
105521
|
import process2 from "node:process";
|
|
104631
105522
|
|
|
104632
105523
|
// ../../node_modules/.pnpm/commander@14.0.3/node_modules/commander/esm.mjs
|
|
@@ -104650,7 +105541,7 @@ var {
|
|
|
104650
105541
|
init_dist();
|
|
104651
105542
|
init_output();
|
|
104652
105543
|
var envPath = resolve21(process2.cwd(), ".env");
|
|
104653
|
-
if (
|
|
105544
|
+
if (existsSync38(envPath)) {
|
|
104654
105545
|
for (const line of readFileSync27(envPath, "utf-8").split("\n")) {
|
|
104655
105546
|
const trimmed = line.trim();
|
|
104656
105547
|
if (!trimmed || trimmed.startsWith("#")) continue;
|