@markus-global/cli 0.4.22 → 0.4.23
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/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +8 -0
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/start.d.ts.map +1 -1
- package/dist/commands/start.js +16 -0
- package/dist/commands/start.js.map +1 -1
- package/dist/markus.mjs +939 -241
- package/dist/web-ui/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
- package/dist/web-ui/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
- package/dist/web-ui/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
- package/dist/web-ui/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
- package/dist/web-ui/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
- package/dist/web-ui/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
- package/dist/web-ui/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
- package/dist/web-ui/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
- package/dist/web-ui/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
- package/dist/web-ui/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
- package/dist/web-ui/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
- package/dist/web-ui/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
- package/dist/web-ui/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
- package/dist/web-ui/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
- package/dist/web-ui/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
- package/dist/web-ui/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
- package/dist/web-ui/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
- package/dist/web-ui/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
- package/dist/web-ui/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
- package/dist/web-ui/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
- package/dist/web-ui/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
- package/dist/web-ui/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
- package/dist/web-ui/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
- package/dist/web-ui/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
- package/dist/web-ui/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
- package/dist/web-ui/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
- package/dist/web-ui/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
- package/dist/web-ui/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
- package/dist/web-ui/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
- package/dist/web-ui/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
- package/dist/web-ui/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
- package/dist/web-ui/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
- package/dist/web-ui/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
- package/dist/web-ui/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
- package/dist/web-ui/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
- package/dist/web-ui/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
- package/dist/web-ui/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
- package/dist/web-ui/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
- package/dist/web-ui/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
- package/dist/web-ui/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
- package/dist/web-ui/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
- package/dist/web-ui/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
- package/dist/web-ui/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
- package/dist/web-ui/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
- package/dist/web-ui/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
- package/dist/web-ui/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
- package/dist/web-ui/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
- package/dist/web-ui/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
- package/dist/web-ui/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
- package/dist/web-ui/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
- package/dist/web-ui/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
- package/dist/web-ui/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
- package/dist/web-ui/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
- package/dist/web-ui/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
- package/dist/web-ui/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
- package/dist/web-ui/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
- package/dist/web-ui/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
- package/dist/web-ui/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
- package/dist/web-ui/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
- package/dist/web-ui/assets/index-FxtMolbG.js +343 -0
- package/dist/web-ui/assets/index-jBDtl4o2.css +1 -0
- package/dist/web-ui/index.html +2 -2
- package/package.json +1 -1
- package/templates/roles/org-manager/HEARTBEAT.md +8 -0
- package/templates/roles/secretary/HEARTBEAT.md +8 -0
- package/templates/skills/agent-building/SKILL.md +14 -5
- package/templates/skills/team-building/SKILL.md +22 -5
- package/dist/web-ui/assets/index-DEkXd9d7.css +0 -1
- package/dist/web-ui/assets/index-HAWGXtTM.js +0 -66
package/dist/markus.mjs
CHANGED
|
@@ -41155,13 +41155,41 @@ var init_web_fetch = __esm({
|
|
|
41155
41155
|
});
|
|
41156
41156
|
|
|
41157
41157
|
// ../core/dist/tools/web-search.js
|
|
41158
|
+
async function resolveProxyDispatcher() {
|
|
41159
|
+
if (_dispatcher !== false)
|
|
41160
|
+
return _dispatcher || void 0;
|
|
41161
|
+
const proxyUrl = process.env["HTTPS_PROXY"] || process.env["HTTP_PROXY"] || process.env["https_proxy"] || process.env["http_proxy"];
|
|
41162
|
+
if (!proxyUrl) {
|
|
41163
|
+
_dispatcher = void 0;
|
|
41164
|
+
return void 0;
|
|
41165
|
+
}
|
|
41166
|
+
try {
|
|
41167
|
+
const load = new Function("id", "return import(id)");
|
|
41168
|
+
const { ProxyAgent } = await load("undici");
|
|
41169
|
+
_dispatcher = new ProxyAgent(proxyUrl);
|
|
41170
|
+
} catch {
|
|
41171
|
+
_dispatcher = void 0;
|
|
41172
|
+
}
|
|
41173
|
+
return _dispatcher || void 0;
|
|
41174
|
+
}
|
|
41175
|
+
async function proxyFetch(url, init) {
|
|
41176
|
+
const dispatcher = await resolveProxyDispatcher();
|
|
41177
|
+
const signal = init?.signal ?? AbortSignal.timeout(SEARCH_TIMEOUT_MS);
|
|
41178
|
+
const opts = { ...init, signal };
|
|
41179
|
+
if (dispatcher)
|
|
41180
|
+
opts["dispatcher"] = dispatcher;
|
|
41181
|
+
return fetch(url, opts);
|
|
41182
|
+
}
|
|
41183
|
+
function hasProxy() {
|
|
41184
|
+
return !!(process.env["HTTPS_PROXY"] || process.env["HTTP_PROXY"] || process.env["https_proxy"] || process.env["http_proxy"]);
|
|
41185
|
+
}
|
|
41158
41186
|
async function searchSerper(query2, maxResults) {
|
|
41159
41187
|
const apiKey = process.env["SERPER_API_KEY"];
|
|
41160
41188
|
if (!apiKey)
|
|
41161
41189
|
throw new Error("SERPER_API_KEY not configured");
|
|
41162
41190
|
let res;
|
|
41163
41191
|
try {
|
|
41164
|
-
res = await
|
|
41192
|
+
res = await proxyFetch("https://google.serper.dev/search", {
|
|
41165
41193
|
method: "POST",
|
|
41166
41194
|
headers: {
|
|
41167
41195
|
"X-API-KEY": apiKey,
|
|
@@ -41189,7 +41217,7 @@ async function searchBrave(query2, maxResults) {
|
|
|
41189
41217
|
const params = new URLSearchParams({ q: query2, count: String(maxResults) });
|
|
41190
41218
|
let res;
|
|
41191
41219
|
try {
|
|
41192
|
-
res = await
|
|
41220
|
+
res = await proxyFetch(`https://api.search.brave.com/res/v1/web/search?${params}`, {
|
|
41193
41221
|
headers: {
|
|
41194
41222
|
"Accept": "application/json",
|
|
41195
41223
|
"Accept-Encoding": "gzip",
|
|
@@ -41209,23 +41237,28 @@ async function searchBrave(query2, maxResults) {
|
|
|
41209
41237
|
date: r.page_age
|
|
41210
41238
|
}));
|
|
41211
41239
|
}
|
|
41212
|
-
async function
|
|
41240
|
+
async function searchDuckDuckGo(query2, maxResults) {
|
|
41213
41241
|
const encoded = encodeURIComponent(query2);
|
|
41214
|
-
let
|
|
41215
|
-
|
|
41216
|
-
|
|
41217
|
-
|
|
41218
|
-
"User-Agent":
|
|
41242
|
+
let lastError;
|
|
41243
|
+
for (const base of DDG_ENDPOINTS) {
|
|
41244
|
+
try {
|
|
41245
|
+
const res = await proxyFetch(`${base}?q=${encoded}`, {
|
|
41246
|
+
headers: { "User-Agent": DDG_UA }
|
|
41247
|
+
});
|
|
41248
|
+
if (!res.ok) {
|
|
41249
|
+
lastError = new Error(`HTTP ${res.status} ${res.statusText}`);
|
|
41250
|
+
continue;
|
|
41219
41251
|
}
|
|
41220
|
-
|
|
41221
|
-
|
|
41222
|
-
|
|
41223
|
-
|
|
41224
|
-
|
|
41225
|
-
|
|
41252
|
+
const html = await res.text();
|
|
41253
|
+
const results = base.includes("lite") ? parseDDGLite(html, maxResults) : parseDDGHtml(html, maxResults);
|
|
41254
|
+
if (results.length > 0)
|
|
41255
|
+
return results;
|
|
41256
|
+
lastError = new Error(`Parsed 0 results from ${base}`);
|
|
41257
|
+
} catch (err) {
|
|
41258
|
+
lastError = err instanceof Error ? err : new Error(String(err));
|
|
41259
|
+
}
|
|
41226
41260
|
}
|
|
41227
|
-
|
|
41228
|
-
return parseDDGLite(html, maxResults);
|
|
41261
|
+
throw new Error(`Network error: ${lastError?.message ?? "all DuckDuckGo endpoints failed"}`);
|
|
41229
41262
|
}
|
|
41230
41263
|
function parseDDGLite(html, max) {
|
|
41231
41264
|
const results = [];
|
|
@@ -41264,21 +41297,7 @@ function parseDDGLite(html, max) {
|
|
|
41264
41297
|
}
|
|
41265
41298
|
return results;
|
|
41266
41299
|
}
|
|
41267
|
-
|
|
41268
|
-
const encoded = encodeURIComponent(query2);
|
|
41269
|
-
let res;
|
|
41270
|
-
try {
|
|
41271
|
-
res = await fetch(`https://html.duckduckgo.com/html/?q=${encoded}`, {
|
|
41272
|
-
headers: {
|
|
41273
|
-
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
|
|
41274
|
-
}
|
|
41275
|
-
});
|
|
41276
|
-
} catch (err) {
|
|
41277
|
-
throw new Error(`Network error: ${err instanceof Error ? err.message : String(err)}`);
|
|
41278
|
-
}
|
|
41279
|
-
if (!res.ok)
|
|
41280
|
-
throw new Error(`HTTP ${res.status} ${res.statusText}`);
|
|
41281
|
-
const html = await res.text();
|
|
41300
|
+
function parseDDGHtml(html, maxResults) {
|
|
41282
41301
|
const results = [];
|
|
41283
41302
|
const linkRegex = /<a[^>]+class="result__a"[^>]*href="([^"]*)"[^>]*>([\s\S]*?)<\/a>/g;
|
|
41284
41303
|
const snippetRegex = /<a[^>]+class="result__snippet"[^>]*>([\s\S]*?)<\/a>/g;
|
|
@@ -41306,10 +41325,12 @@ async function searchDuckDuckGoHtml(query2, maxResults) {
|
|
|
41306
41325
|
function stripHtml(html) {
|
|
41307
41326
|
return html.replace(/<[^>]*>/g, "").replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, '"').replace(/'/g, "'").replace(/'/g, "'").replace(/ /g, " ").replace(/\s+/g, " ").trim();
|
|
41308
41327
|
}
|
|
41309
|
-
var WebSearchTool;
|
|
41328
|
+
var SEARCH_TIMEOUT_MS, _dispatcher, WebSearchTool, DDG_UA, DDG_ENDPOINTS;
|
|
41310
41329
|
var init_web_search = __esm({
|
|
41311
41330
|
"../core/dist/tools/web-search.js"() {
|
|
41312
41331
|
"use strict";
|
|
41332
|
+
SEARCH_TIMEOUT_MS = 15e3;
|
|
41333
|
+
_dispatcher = false;
|
|
41313
41334
|
WebSearchTool = {
|
|
41314
41335
|
name: "web_search",
|
|
41315
41336
|
description: "Search the web for real-time information. Returns search result titles, snippets, and URLs. Use this when you need up-to-date information that might not be in your training data.",
|
|
@@ -41333,7 +41354,7 @@ var init_web_search = __esm({
|
|
|
41333
41354
|
const backends = [
|
|
41334
41355
|
{ name: "Serper", fn: searchSerper },
|
|
41335
41356
|
{ name: "Brave", fn: searchBrave },
|
|
41336
|
-
{ name: "DuckDuckGo", fn:
|
|
41357
|
+
{ name: "DuckDuckGo", fn: searchDuckDuckGo }
|
|
41337
41358
|
];
|
|
41338
41359
|
const errors = [];
|
|
41339
41360
|
for (const { name, fn } of backends) {
|
|
@@ -41348,13 +41369,27 @@ var init_web_search = __esm({
|
|
|
41348
41369
|
errors.push({ backend: name, error: message });
|
|
41349
41370
|
}
|
|
41350
41371
|
}
|
|
41372
|
+
const hasNetworkErr = errors.some((e) => e.error.includes("Network error") || e.error.includes("timed out"));
|
|
41373
|
+
const hints = [];
|
|
41374
|
+
if (hasNetworkErr && !hasProxy()) {
|
|
41375
|
+
hints.push("All network requests failed and no HTTP proxy is configured. If you are behind a firewall or in a restricted network, set HTTPS_PROXY (e.g. export HTTPS_PROXY=http://127.0.0.1:7890).");
|
|
41376
|
+
}
|
|
41377
|
+
if (hasNetworkErr && hasProxy()) {
|
|
41378
|
+
hints.push(`HTTP proxy is configured (${process.env["HTTPS_PROXY"] || process.env["HTTP_PROXY"] || process.env["https_proxy"] || process.env["http_proxy"]}), but network requests still failed. Verify the proxy is reachable and allows outbound HTTPS.`);
|
|
41379
|
+
}
|
|
41351
41380
|
return JSON.stringify({
|
|
41352
41381
|
status: "error",
|
|
41353
41382
|
error: "All search backends failed.",
|
|
41354
|
-
details: errors
|
|
41383
|
+
details: errors,
|
|
41384
|
+
...hints.length > 0 ? { hints } : {}
|
|
41355
41385
|
});
|
|
41356
41386
|
}
|
|
41357
41387
|
};
|
|
41388
|
+
DDG_UA = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36";
|
|
41389
|
+
DDG_ENDPOINTS = [
|
|
41390
|
+
"https://lite.duckduckgo.com/lite/",
|
|
41391
|
+
"https://html.duckduckgo.com/html/"
|
|
41392
|
+
];
|
|
41358
41393
|
}
|
|
41359
41394
|
});
|
|
41360
41395
|
|
|
@@ -42917,6 +42952,18 @@ ${typeLabel}${item.payload.content}`;
|
|
|
42917
42952
|
this.persistence?.updateStatus(item.id, "deferred", { deferredUntil: until });
|
|
42918
42953
|
return item;
|
|
42919
42954
|
}
|
|
42955
|
+
/**
|
|
42956
|
+
* Defer an item that has already been dequeued (not in the queue).
|
|
42957
|
+
* Used when processing is interrupted (preempted) and the item should
|
|
42958
|
+
* be resumed later. Only updates persistence — does NOT re-insert
|
|
42959
|
+
* into the in-memory queue (resurfaceDue handles that on the next idle cycle).
|
|
42960
|
+
*/
|
|
42961
|
+
deferDequeued(item, until) {
|
|
42962
|
+
item.status = "deferred";
|
|
42963
|
+
item.deferredUntil = until;
|
|
42964
|
+
item.startedAt = void 0;
|
|
42965
|
+
this.persistence?.updateStatus(item.id, "deferred", { deferredUntil: until });
|
|
42966
|
+
}
|
|
42920
42967
|
/**
|
|
42921
42968
|
* Mark an item as merged into another item.
|
|
42922
42969
|
*/
|
|
@@ -43158,7 +43205,7 @@ function detectAbnormalCompletion(reply, item) {
|
|
|
43158
43205
|
const registry = MAILBOX_TYPE_REGISTRY[item.sourceType];
|
|
43159
43206
|
if (!registry?.invokesLLM)
|
|
43160
43207
|
return void 0;
|
|
43161
|
-
if (reply === "[preempted]")
|
|
43208
|
+
if (reply === "[preempted]" || reply === "[cancelled]")
|
|
43162
43209
|
return void 0;
|
|
43163
43210
|
const isUserFacing = item.sourceType === "human_chat" || item.sourceType === "a2a_message";
|
|
43164
43211
|
if (isUserFacing)
|
|
@@ -43195,6 +43242,8 @@ var init_attention = __esm({
|
|
|
43195
43242
|
triageToolHandlers;
|
|
43196
43243
|
triageChatFn;
|
|
43197
43244
|
lastTriageResult;
|
|
43245
|
+
/** Tracks whether the last yield-point decision was 'cancel' vs 'preempt'. */
|
|
43246
|
+
lastYieldDecision;
|
|
43198
43247
|
unsubscribeNewItem;
|
|
43199
43248
|
decisions = [];
|
|
43200
43249
|
watchdogTimer;
|
|
@@ -43391,6 +43440,7 @@ var init_attention = __esm({
|
|
|
43391
43440
|
this.interruptSignal = false;
|
|
43392
43441
|
this.pendingInterruptItem = void 0;
|
|
43393
43442
|
this.criticalInterruptResolve = void 0;
|
|
43443
|
+
this.lastYieldDecision = void 0;
|
|
43394
43444
|
this.processingStartedAt = Date.now();
|
|
43395
43445
|
this.delegate?.onFocusChanged(item);
|
|
43396
43446
|
let reply = void 0;
|
|
@@ -43425,6 +43475,27 @@ var init_attention = __esm({
|
|
|
43425
43475
|
this.processingStartedAt = void 0;
|
|
43426
43476
|
if (timedOut) {
|
|
43427
43477
|
this.mailbox.requeue(item);
|
|
43478
|
+
} else if (reply === "[cancelled]" || this.lastYieldDecision === "cancel") {
|
|
43479
|
+
log14.info("Item cancelled \u2014 dropping permanently", {
|
|
43480
|
+
agentId: this.agentId,
|
|
43481
|
+
itemId: item.id,
|
|
43482
|
+
type: item.sourceType
|
|
43483
|
+
});
|
|
43484
|
+
this.mailbox.complete(item.id);
|
|
43485
|
+
} else if (reply === "[preempted]" || this.lastYieldDecision === "preempt") {
|
|
43486
|
+
log14.info("Item preempted (paused) \u2014 deferring for later resumption", {
|
|
43487
|
+
agentId: this.agentId,
|
|
43488
|
+
itemId: item.id,
|
|
43489
|
+
type: item.sourceType
|
|
43490
|
+
});
|
|
43491
|
+
this.mailbox.deferDequeued(item);
|
|
43492
|
+
} else if (!this.running) {
|
|
43493
|
+
log14.info("Agent stopped during processing \u2014 requeueing item", {
|
|
43494
|
+
agentId: this.agentId,
|
|
43495
|
+
itemId: item.id,
|
|
43496
|
+
type: item.sourceType
|
|
43497
|
+
});
|
|
43498
|
+
this.mailbox.requeue(item);
|
|
43428
43499
|
} else {
|
|
43429
43500
|
const abnormalReason = detectAbnormalCompletion(reply, item);
|
|
43430
43501
|
const retries = item.retryCount ?? 0;
|
|
@@ -43500,7 +43571,8 @@ var init_attention = __esm({
|
|
|
43500
43571
|
*
|
|
43501
43572
|
* Returns the decision type so the caller knows what to do:
|
|
43502
43573
|
* - 'continue' → keep working on current task
|
|
43503
|
-
* - 'preempt' → caller should save state and return;
|
|
43574
|
+
* - 'preempt' → caller should save state and return '[preempted]'; item is deferred for later resumption
|
|
43575
|
+
* - 'cancel' → caller should abort and return '[cancelled]'; item is permanently dropped
|
|
43504
43576
|
* - 'merge' → item was absorbed into current work (caller may inject into session)
|
|
43505
43577
|
*/
|
|
43506
43578
|
async checkYieldPoint() {
|
|
@@ -43533,8 +43605,13 @@ var init_attention = __esm({
|
|
|
43533
43605
|
return { decision: "defer", item: newItem, reasoning };
|
|
43534
43606
|
}
|
|
43535
43607
|
if (decisionType === "preempt") {
|
|
43608
|
+
this.lastYieldDecision = "preempt";
|
|
43536
43609
|
return { decision: "preempt", item: newItem, reasoning };
|
|
43537
43610
|
}
|
|
43611
|
+
if (decisionType === "cancel") {
|
|
43612
|
+
this.lastYieldDecision = "cancel";
|
|
43613
|
+
return { decision: "cancel", item: newItem, reasoning };
|
|
43614
|
+
}
|
|
43538
43615
|
return { decision: "continue", reasoning };
|
|
43539
43616
|
}
|
|
43540
43617
|
/**
|
|
@@ -43617,7 +43694,7 @@ var init_attention = __esm({
|
|
|
43617
43694
|
try {
|
|
43618
43695
|
const prompt = this.buildJudgePrompt(currentItem, newItem);
|
|
43619
43696
|
const llmDecision = await this.llmJudge(prompt);
|
|
43620
|
-
const validDecisions = ["continue", "preempt", "merge", "defer"];
|
|
43697
|
+
const validDecisions = ["continue", "preempt", "cancel", "merge", "defer"];
|
|
43621
43698
|
if (validDecisions.includes(llmDecision))
|
|
43622
43699
|
return llmDecision;
|
|
43623
43700
|
} catch (err) {
|
|
@@ -43632,17 +43709,29 @@ var init_attention = __esm({
|
|
|
43632
43709
|
const recentDecs = this.decisions.slice(-5).map((d) => `- ${d.decisionType}: ${d.reasoning}`).join("\n");
|
|
43633
43710
|
const queuedItems = this.mailbox.getQueuedItems();
|
|
43634
43711
|
const queueSection = queuedItems.length > 0 ? queuedItems.map((i) => ` - [${i.sourceType}] p${i.priority}: "${i.payload.summary}"`).join("\n") : " (empty)";
|
|
43712
|
+
const currentContent = currentItem.payload.content?.slice(0, 500) ?? "";
|
|
43713
|
+
const newContent = newItem.payload.content?.slice(0, 800) ?? "";
|
|
43635
43714
|
return [
|
|
43636
|
-
"You are deciding
|
|
43637
|
-
"
|
|
43715
|
+
"You are deciding whether to INTERRUPT your current work to handle a new incoming message.",
|
|
43716
|
+
"",
|
|
43717
|
+
"RULES (in priority order):",
|
|
43718
|
+
"1. Human messages (human_chat) ALWAYS preempt non-human work \u2014 users are top priority.",
|
|
43719
|
+
'2. If the new message explicitly CANCELS or REVOKES the current work (e.g. "cancel that task",',
|
|
43720
|
+
` "don't publish this anymore", "delete the draft"), choose cancel \u2014 current work is permanently abandoned.`,
|
|
43721
|
+
'3. If the new message asks to PAUSE or DELAY current work (e.g. "hold off for now",',
|
|
43722
|
+
' "wait before deploying", "pause that"), choose preempt \u2014 current work is saved and can be resumed later.',
|
|
43723
|
+
"4. If the new message is about the SAME task/topic as current work and adds info, consider merge.",
|
|
43724
|
+
"5. If the new message is lower priority and unrelated, continue current work.",
|
|
43638
43725
|
"",
|
|
43639
43726
|
`CURRENT FOCUS: [${currentItem.sourceType}] priority=${currentItem.priority}`,
|
|
43640
|
-
` "${currentItem.payload.summary}"`,
|
|
43727
|
+
` Summary: "${currentItem.payload.summary}"`,
|
|
43641
43728
|
` Task: ${currentItem.payload.taskId ?? "none"}`,
|
|
43729
|
+
currentContent ? ` Content preview: ${currentContent}` : "",
|
|
43642
43730
|
"",
|
|
43643
43731
|
`NEW ITEM: [${newItem.sourceType}] priority=${newItem.priority}`,
|
|
43644
|
-
` "${newItem.payload.summary}"`,
|
|
43732
|
+
` Summary: "${newItem.payload.summary}"`,
|
|
43645
43733
|
` Task: ${newItem.payload.taskId ?? "none"}`,
|
|
43734
|
+
newContent ? ` Content: ${newContent}` : "",
|
|
43646
43735
|
"",
|
|
43647
43736
|
`FULL QUEUE (${this.mailbox.depth} items):`,
|
|
43648
43737
|
queueSection,
|
|
@@ -43650,7 +43739,14 @@ var init_attention = __esm({
|
|
|
43650
43739
|
"RECENT DECISIONS:",
|
|
43651
43740
|
recentDecs || "(none)",
|
|
43652
43741
|
"",
|
|
43653
|
-
"
|
|
43742
|
+
"DECISIONS:",
|
|
43743
|
+
"- preempt: PAUSE current work (session saved for later resumption) and handle the new item",
|
|
43744
|
+
"- cancel: PERMANENTLY STOP current work (session dropped, will NOT be resumed) and handle the new item",
|
|
43745
|
+
"- merge: Inject new item into current session as additional context (no interruption)",
|
|
43746
|
+
"- defer: Put the new item aside for later (no interruption)",
|
|
43747
|
+
"- continue: Ignore the new item for now, keep working",
|
|
43748
|
+
"",
|
|
43749
|
+
"Choose exactly one: continue | preempt | cancel | merge | defer",
|
|
43654
43750
|
"Reply with ONLY the decision word, nothing else."
|
|
43655
43751
|
].join("\n");
|
|
43656
43752
|
}
|
|
@@ -45272,6 +45368,7 @@ ${notification.stdoutTail}`);
|
|
|
45272
45368
|
log17.info(`Agent started: ${this.config.name}`);
|
|
45273
45369
|
}
|
|
45274
45370
|
async stop() {
|
|
45371
|
+
this.cancelActiveStream();
|
|
45275
45372
|
this.attentionController.stop();
|
|
45276
45373
|
this.heartbeat.stop();
|
|
45277
45374
|
this._bgCompletionUnsub?.();
|
|
@@ -45473,7 +45570,7 @@ ${notification.stdoutTail}`);
|
|
|
45473
45570
|
}
|
|
45474
45571
|
},
|
|
45475
45572
|
evaluateInterrupt: async (currentItem, newItem) => {
|
|
45476
|
-
return this.attentionController.
|
|
45573
|
+
return this.attentionController.evaluateWithLLMFallback(currentItem, newItem);
|
|
45477
45574
|
},
|
|
45478
45575
|
getTriageContext: async () => {
|
|
45479
45576
|
const messages = this.currentSessionId ? this.memory.getRecentMessages(this.currentSessionId, TRIAGE_CONTEXT_MESSAGES_MAX * 2).filter((m) => m.role === "user" || m.role === "assistant").slice(-TRIAGE_CONTEXT_MESSAGES_MAX).map((m) => ({ role: m.role, content: typeof m.content === "string" ? m.content.slice(0, TRIAGE_CONTEXT_MSG_CHARS) : String(m.content).slice(0, TRIAGE_CONTEXT_MSG_CHARS) })) : [];
|
|
@@ -45569,7 +45666,7 @@ ${notification.stdoutTail}`);
|
|
|
45569
45666
|
case "requirement_update": {
|
|
45570
45667
|
if (extra.actionRequired) {
|
|
45571
45668
|
const reqId = item.payload.requirementId ?? "unknown";
|
|
45572
|
-
const reply = await this.handleMessage(item.payload.content + markerSuffix, item.metadata?.senderId, senderInfo, buildHandleOpts({ sessionId: `
|
|
45669
|
+
const reply = await this.handleMessage(item.payload.content + markerSuffix, item.metadata?.senderId, senderInfo, buildHandleOpts({ sessionId: `requirement_${reqId}_${ts}`, scenario: "requirement_action" }));
|
|
45573
45670
|
resolveResponse(reply);
|
|
45574
45671
|
return reply;
|
|
45575
45672
|
}
|
|
@@ -45803,6 +45900,7 @@ ${notification.stdoutTail}`);
|
|
|
45803
45900
|
if (this.state.status === "offline")
|
|
45804
45901
|
return;
|
|
45805
45902
|
this.pauseReason = reason;
|
|
45903
|
+
this.cancelActiveStream();
|
|
45806
45904
|
this.heartbeat.stop();
|
|
45807
45905
|
this.attentionController.stop();
|
|
45808
45906
|
if (this.memoryConsolidationTimer) {
|
|
@@ -46633,10 +46731,11 @@ ${report}`);
|
|
|
46633
46731
|
if (!this.state.currentActivity) {
|
|
46634
46732
|
let actType = "chat";
|
|
46635
46733
|
let actLabel;
|
|
46734
|
+
const peerName = senderInfo?.name || senderId || void 0;
|
|
46636
46735
|
switch (scenario) {
|
|
46637
46736
|
case "a2a":
|
|
46638
46737
|
actType = "a2a";
|
|
46639
|
-
actLabel = `Chat from ${
|
|
46738
|
+
actLabel = peerName ? `Chat from ${peerName}` : "Agent Message";
|
|
46640
46739
|
break;
|
|
46641
46740
|
case "heartbeat":
|
|
46642
46741
|
actType = "internal";
|
|
@@ -46644,14 +46743,14 @@ ${report}`);
|
|
|
46644
46743
|
break;
|
|
46645
46744
|
case "comment_response":
|
|
46646
46745
|
actType = "chat";
|
|
46647
|
-
actLabel = `Comment reply to ${
|
|
46746
|
+
actLabel = peerName ? `Comment reply to ${peerName}` : "Comment Reply";
|
|
46648
46747
|
break;
|
|
46649
46748
|
case "review":
|
|
46650
46749
|
actType = "internal";
|
|
46651
|
-
actLabel = `Reviewing task from ${
|
|
46750
|
+
actLabel = peerName ? `Reviewing task from ${peerName}` : "Task Review";
|
|
46652
46751
|
break;
|
|
46653
46752
|
default:
|
|
46654
|
-
actLabel = `Chat with ${
|
|
46753
|
+
actLabel = peerName ? `Chat with ${peerName}` : "Human Chat";
|
|
46655
46754
|
break;
|
|
46656
46755
|
}
|
|
46657
46756
|
chatActivityId = this.startActivity(actType, actLabel);
|
|
@@ -46894,13 +46993,14 @@ ${block}
|
|
|
46894
46993
|
}
|
|
46895
46994
|
}
|
|
46896
46995
|
const chatYield = await this.checkAttentionYieldPoint();
|
|
46897
|
-
if (chatYield.decision === "preempt" && isPreemptable) {
|
|
46898
|
-
|
|
46996
|
+
if ((chatYield.decision === "preempt" || chatYield.decision === "cancel") && isPreemptable) {
|
|
46997
|
+
const marker = chatYield.decision === "cancel" ? "[cancelled]" : "[preempted]";
|
|
46998
|
+
log17.info(`handleMessage ${chatYield.decision} by higher-priority item`, {
|
|
46899
46999
|
agentId: this.id,
|
|
46900
47000
|
scenario,
|
|
46901
47001
|
preemptedBy: chatYield.item?.sourceType
|
|
46902
47002
|
});
|
|
46903
|
-
return
|
|
47003
|
+
return marker;
|
|
46904
47004
|
}
|
|
46905
47005
|
if (chatYield.decision === "merge" && chatYield.item) {
|
|
46906
47006
|
const mergeMsg = `[LIVE UPDATE] ${chatYield.item.payload.summary}
|
|
@@ -47081,6 +47181,7 @@ ${chatYield.item.payload.content}`;
|
|
|
47081
47181
|
this.checkDailyTokenBudget();
|
|
47082
47182
|
const llmStart = Date.now();
|
|
47083
47183
|
let response = await this.withNetworkRetry(() => this.llmRouter.chatStream({ messages, tools: llmTools.length > 0 ? llmTools : void 0, metadata: this.getLLMMetadata(this.currentSessionId), compaction: useCompaction }, wrappedOnEvent, this.getEffectiveProvider(), abortController.signal), "Stream LLM call");
|
|
47184
|
+
streamMarkerDelta.flush();
|
|
47084
47185
|
const tokensThisCall = response.usage.inputTokens + response.usage.outputTokens;
|
|
47085
47186
|
this.updateTokensUsed(tokensThisCall);
|
|
47086
47187
|
this.calibrateTokenCounter(response.usage.inputTokens);
|
|
@@ -47231,6 +47332,7 @@ ${chatYield.item.payload.content}`;
|
|
|
47231
47332
|
}
|
|
47232
47333
|
const llmStart2 = Date.now();
|
|
47233
47334
|
response = await this.withNetworkRetry(() => this.llmRouter.chatStream({ messages: updatedMessages, tools: llmTools.length > 0 ? llmTools : void 0, metadata: this.getLLMMetadata(this.currentSessionId), compaction: useCompaction }, wrappedOnEvent, this.getEffectiveProvider(), abortController.signal), "Stream LLM continuation");
|
|
47335
|
+
streamMarkerDelta.flush();
|
|
47234
47336
|
const tokens2 = response.usage.inputTokens + response.usage.outputTokens;
|
|
47235
47337
|
this.updateTokensUsed(tokens2);
|
|
47236
47338
|
this.calibrateTokenCounter(response.usage.inputTokens);
|
|
@@ -47637,14 +47739,16 @@ ${chatYield.item.payload.content}`;
|
|
|
47637
47739
|
}
|
|
47638
47740
|
this.flushPendingInjections(sessionId);
|
|
47639
47741
|
const yieldResult = await this.checkAttentionYieldPoint();
|
|
47640
|
-
if (yieldResult.decision === "preempt") {
|
|
47641
|
-
|
|
47742
|
+
if (yieldResult.decision === "preempt" || yieldResult.decision === "cancel") {
|
|
47743
|
+
const statusLabel = yieldResult.decision === "cancel" ? "cancelled" : "preempted";
|
|
47744
|
+
emit("status", statusLabel, {
|
|
47642
47745
|
reason: yieldResult.reasoning,
|
|
47643
47746
|
preemptedBy: yieldResult.item?.sourceType
|
|
47644
47747
|
});
|
|
47645
|
-
log17.info(
|
|
47748
|
+
log17.info(`Task ${statusLabel} by higher-priority mailbox item`, {
|
|
47646
47749
|
taskId: taskId2,
|
|
47647
47750
|
agentId: this.id,
|
|
47751
|
+
decision: yieldResult.decision,
|
|
47648
47752
|
preemptedBy: yieldResult.item?.sourceType,
|
|
47649
47753
|
reasoning: yieldResult.reasoning?.slice(0, 120)
|
|
47650
47754
|
});
|
|
@@ -50359,6 +50463,67 @@ function createA2ATools(ctx) {
|
|
|
50359
50463
|
return JSON.stringify({ status: "error", error: String(err) });
|
|
50360
50464
|
}
|
|
50361
50465
|
}
|
|
50466
|
+
}] : [],
|
|
50467
|
+
...ctx.getChannelMessages ? [{
|
|
50468
|
+
name: "recall_context",
|
|
50469
|
+
description: [
|
|
50470
|
+
"Recall historical context you may need to respond effectively.",
|
|
50471
|
+
"Use this BEFORE responding when the provided context is insufficient.",
|
|
50472
|
+
"",
|
|
50473
|
+
"Supported scopes:",
|
|
50474
|
+
'\u2022 "channel" \u2014 Read chat messages from a group chat or DM channel. Requires channel_key.',
|
|
50475
|
+
" Use when you joined a discussion late, were @mentioned, or need to understand prior conversation.",
|
|
50476
|
+
"",
|
|
50477
|
+
"For other context types, use these existing tools instead:",
|
|
50478
|
+
"\u2022 task_get \u2014 Full task details including all comments (scope=task context)",
|
|
50479
|
+
"\u2022 requirement_get \u2014 Full requirement details including all comments (scope=requirement context)",
|
|
50480
|
+
"\u2022 recall_activity \u2014 Your own execution history, activity logs, and past work (scope=your activities)",
|
|
50481
|
+
"\u2022 memory_search \u2014 Your saved memories and notes (scope=personal knowledge)"
|
|
50482
|
+
].join("\n"),
|
|
50483
|
+
inputSchema: {
|
|
50484
|
+
type: "object",
|
|
50485
|
+
properties: {
|
|
50486
|
+
scope: {
|
|
50487
|
+
type: "string",
|
|
50488
|
+
enum: ["channel"],
|
|
50489
|
+
description: 'Type of context to recall. Currently: "channel" for chat/group messages.'
|
|
50490
|
+
},
|
|
50491
|
+
channel_key: {
|
|
50492
|
+
type: "string",
|
|
50493
|
+
description: 'Required when scope="channel". The channel key (e.g., "group:<teamId>" for team chats, "dm:<id1>_<id2>" for DMs).'
|
|
50494
|
+
},
|
|
50495
|
+
limit: { type: "number", description: "Number of items to fetch (default 30, max 50)." },
|
|
50496
|
+
before: { type: "string", description: "ISO timestamp \u2014 fetch items older than this for pagination. Omit for most recent." }
|
|
50497
|
+
},
|
|
50498
|
+
required: ["scope"]
|
|
50499
|
+
},
|
|
50500
|
+
async execute(args) {
|
|
50501
|
+
const scope = args["scope"];
|
|
50502
|
+
if (scope === "channel") {
|
|
50503
|
+
const channelKey = args["channel_key"];
|
|
50504
|
+
if (!channelKey) {
|
|
50505
|
+
return JSON.stringify({ status: "error", error: 'channel_key is required when scope="channel"' });
|
|
50506
|
+
}
|
|
50507
|
+
const limit = Math.min(args["limit"] ?? 30, 50);
|
|
50508
|
+
const before2 = args["before"];
|
|
50509
|
+
try {
|
|
50510
|
+
const result = await ctx.getChannelMessages(channelKey, limit, before2);
|
|
50511
|
+
const formatted = result.messages.map((m) => `[${m.createdAt}] ${m.senderType === "agent" ? `[agent] ${m.senderName}` : `[human] ${m.senderName}`}: ${m.text.slice(0, 500)}`);
|
|
50512
|
+
return JSON.stringify({
|
|
50513
|
+
messages: formatted,
|
|
50514
|
+
count: result.messages.length,
|
|
50515
|
+
hasMore: result.hasMore,
|
|
50516
|
+
oldestTimestamp: result.messages[0]?.createdAt
|
|
50517
|
+
});
|
|
50518
|
+
} catch (err) {
|
|
50519
|
+
return JSON.stringify({ status: "error", error: String(err) });
|
|
50520
|
+
}
|
|
50521
|
+
}
|
|
50522
|
+
return JSON.stringify({
|
|
50523
|
+
status: "error",
|
|
50524
|
+
error: `Unknown scope: "${scope}". Use "channel" for chat messages, or use task_get / requirement_get / recall_activity for other context.`
|
|
50525
|
+
});
|
|
50526
|
+
}
|
|
50362
50527
|
}] : []
|
|
50363
50528
|
];
|
|
50364
50529
|
}
|
|
@@ -52875,7 +53040,7 @@ var init_dist3 = __esm({
|
|
|
52875
53040
|
|
|
52876
53041
|
// ../core/dist/agent-manager.js
|
|
52877
53042
|
import { join as join13 } from "node:path";
|
|
52878
|
-
import { mkdirSync as mkdirSync12, readFileSync as readFileSync13, existsSync as existsSync18, copyFileSync, rmSync, readdirSync as readdirSync4 } from "node:fs";
|
|
53043
|
+
import { mkdirSync as mkdirSync12, readFileSync as readFileSync13, existsSync as existsSync18, copyFileSync, rmSync, readdirSync as readdirSync4, writeFileSync as writeFileSync11 } from "node:fs";
|
|
52879
53044
|
import { homedir as homedir6 } from "node:os";
|
|
52880
53045
|
function resolveCurrentTaskId(agentObj, ts, agentId2) {
|
|
52881
53046
|
const activeTasks = agentObj?.getActiveTasks?.() ?? [];
|
|
@@ -53271,6 +53436,17 @@ You are ${request.name}.`,
|
|
|
53271
53436
|
}
|
|
53272
53437
|
}
|
|
53273
53438
|
}
|
|
53439
|
+
const heartbeatPath = join13(agentRoleDir, "HEARTBEAT.md");
|
|
53440
|
+
if (!existsSync18(heartbeatPath)) {
|
|
53441
|
+
writeFileSync11(heartbeatPath, [
|
|
53442
|
+
"# Heartbeat Checklist",
|
|
53443
|
+
"",
|
|
53444
|
+
"- [ ] Check mailbox for new messages and respond to urgent items",
|
|
53445
|
+
"- [ ] Review assigned tasks \u2014 update progress, unblock if possible",
|
|
53446
|
+
"- [ ] Check team announcements for new information",
|
|
53447
|
+
"- [ ] Scan recent channel messages for anything requiring attention"
|
|
53448
|
+
].join("\n"), "utf-8");
|
|
53449
|
+
}
|
|
53274
53450
|
const config = {
|
|
53275
53451
|
id,
|
|
53276
53452
|
name: request.name,
|
|
@@ -53436,7 +53612,8 @@ You are ${request.name}.`,
|
|
|
53436
53612
|
...this.groupChatHandlers ? {
|
|
53437
53613
|
sendGroupMessage: this.groupChatHandlers.sendGroupMessage,
|
|
53438
53614
|
createGroupChat: (name, memberIds) => this.groupChatHandlers.createGroupChat(name, id, config.name, memberIds),
|
|
53439
|
-
listGroupChats: this.groupChatHandlers.listGroupChats
|
|
53615
|
+
listGroupChats: this.groupChatHandlers.listGroupChats,
|
|
53616
|
+
getChannelMessages: this.groupChatHandlers.getChannelMessages
|
|
53440
53617
|
} : {}
|
|
53441
53618
|
};
|
|
53442
53619
|
for (const tool of createA2ATools(a2aContext))
|
|
@@ -54009,7 +54186,8 @@ You are ${row.name}.`,
|
|
|
54009
54186
|
...this.groupChatHandlers ? {
|
|
54010
54187
|
sendGroupMessage: this.groupChatHandlers.sendGroupMessage,
|
|
54011
54188
|
createGroupChat: (name, memberIds) => this.groupChatHandlers.createGroupChat(name, id, config.name, memberIds),
|
|
54012
|
-
listGroupChats: this.groupChatHandlers.listGroupChats
|
|
54189
|
+
listGroupChats: this.groupChatHandlers.listGroupChats,
|
|
54190
|
+
getChannelMessages: this.groupChatHandlers.getChannelMessages
|
|
54013
54191
|
} : {}
|
|
54014
54192
|
};
|
|
54015
54193
|
for (const tool of createA2ATools(a2aCtx))
|
|
@@ -55946,7 +56124,7 @@ var init_ollama = __esm({
|
|
|
55946
56124
|
});
|
|
55947
56125
|
|
|
55948
56126
|
// ../core/dist/llm/auth-profiles.js
|
|
55949
|
-
import { readFileSync as readFileSync14, writeFileSync as
|
|
56127
|
+
import { readFileSync as readFileSync14, writeFileSync as writeFileSync12, mkdirSync as mkdirSync13, existsSync as existsSync19, unlinkSync as unlinkSync2 } from "node:fs";
|
|
55950
56128
|
import { join as join14 } from "node:path";
|
|
55951
56129
|
import { homedir as homedir7 } from "node:os";
|
|
55952
56130
|
var log34, AuthProfileStore;
|
|
@@ -55977,7 +56155,7 @@ var init_auth_profiles = __esm({
|
|
|
55977
56155
|
}
|
|
55978
56156
|
}
|
|
55979
56157
|
write(data) {
|
|
55980
|
-
|
|
56158
|
+
writeFileSync12(this.filePath, JSON.stringify(data, null, 2) + "\n", { mode: 384 });
|
|
55981
56159
|
}
|
|
55982
56160
|
/**
|
|
55983
56161
|
* Acquire a simple filesystem lock for atomic profile updates (token refresh).
|
|
@@ -55986,7 +56164,7 @@ var init_auth_profiles = __esm({
|
|
|
55986
56164
|
acquireLock() {
|
|
55987
56165
|
const lockContent = `${process.pid}-${Date.now()}`;
|
|
55988
56166
|
try {
|
|
55989
|
-
|
|
56167
|
+
writeFileSync12(this.lockPath, lockContent, { flag: "wx" });
|
|
55990
56168
|
return () => {
|
|
55991
56169
|
try {
|
|
55992
56170
|
unlinkSync2(this.lockPath);
|
|
@@ -55998,7 +56176,7 @@ var init_auth_profiles = __esm({
|
|
|
55998
56176
|
const existing = readFileSync14(this.lockPath, "utf-8");
|
|
55999
56177
|
const ts = Number(existing.split("-").pop());
|
|
56000
56178
|
if (Date.now() - ts > 3e4) {
|
|
56001
|
-
|
|
56179
|
+
writeFileSync12(this.lockPath, lockContent, { mode: 384 });
|
|
56002
56180
|
return () => {
|
|
56003
56181
|
try {
|
|
56004
56182
|
unlinkSync2(this.lockPath);
|
|
@@ -59348,7 +59526,7 @@ var init_dist4 = __esm({
|
|
|
59348
59526
|
});
|
|
59349
59527
|
|
|
59350
59528
|
// ../org-manager/dist/org-service.js
|
|
59351
|
-
import { mkdirSync as mkdirSync15, writeFileSync as
|
|
59529
|
+
import { mkdirSync as mkdirSync15, writeFileSync as writeFileSync13, existsSync as existsSync23, rmSync as rmSync2 } from "node:fs";
|
|
59352
59530
|
import { join as join19 } from "node:path";
|
|
59353
59531
|
import { homedir as homedir10 } from "node:os";
|
|
59354
59532
|
var log50, OrganizationService;
|
|
@@ -59482,15 +59660,15 @@ var init_org_service = __esm({
|
|
|
59482
59660
|
mkdirSync15(dir, { recursive: true });
|
|
59483
59661
|
const annPath = join19(dir, "ANNOUNCEMENT.md");
|
|
59484
59662
|
if (announcements) {
|
|
59485
|
-
|
|
59663
|
+
writeFileSync13(annPath, announcements, "utf-8");
|
|
59486
59664
|
} else if (!existsSync23(annPath)) {
|
|
59487
|
-
|
|
59665
|
+
writeFileSync13(annPath, "", "utf-8");
|
|
59488
59666
|
}
|
|
59489
59667
|
const normsPath = join19(dir, "NORMS.md");
|
|
59490
59668
|
if (norms) {
|
|
59491
|
-
|
|
59669
|
+
writeFileSync13(normsPath, norms, "utf-8");
|
|
59492
59670
|
} else if (!existsSync23(normsPath)) {
|
|
59493
|
-
|
|
59671
|
+
writeFileSync13(normsPath, "", "utf-8");
|
|
59494
59672
|
}
|
|
59495
59673
|
}
|
|
59496
59674
|
async createTeam(orgId2, name, description) {
|
|
@@ -60226,7 +60404,7 @@ var init_org_service = __esm({
|
|
|
60226
60404
|
});
|
|
60227
60405
|
|
|
60228
60406
|
// ../org-manager/dist/task-service.js
|
|
60229
|
-
import { mkdirSync as mkdirSync16, writeFileSync as
|
|
60407
|
+
import { mkdirSync as mkdirSync16, writeFileSync as writeFileSync14, readFileSync as readFileSync18, existsSync as existsSync24, cpSync } from "node:fs";
|
|
60230
60408
|
import { join as join20, resolve as resolve12 } from "node:path";
|
|
60231
60409
|
import { homedir as homedir11 } from "node:os";
|
|
60232
60410
|
function formatLocalTimestamp(d = /* @__PURE__ */ new Date()) {
|
|
@@ -60579,7 +60757,7 @@ var init_task_service = __esm({
|
|
|
60579
60757
|
mkdirSync16(join20(dir, "knowledge"), { recursive: true });
|
|
60580
60758
|
const userMdPath = join20(dir, "USER.md");
|
|
60581
60759
|
if (!existsSync24(userMdPath)) {
|
|
60582
|
-
|
|
60760
|
+
writeFileSync14(userMdPath, [
|
|
60583
60761
|
"# About the Owner",
|
|
60584
60762
|
"",
|
|
60585
60763
|
"- Name:",
|
|
@@ -62645,7 +62823,7 @@ Action: ${guidance}` : ""
|
|
|
62645
62823
|
testResults: d.testResults
|
|
62646
62824
|
}))
|
|
62647
62825
|
};
|
|
62648
|
-
|
|
62826
|
+
writeFileSync14(join20(taskSharedDir, "manifest.json"), JSON.stringify(manifest, null, 2));
|
|
62649
62827
|
for (const d of deliverables) {
|
|
62650
62828
|
if (d.type === "file" && d.reference) {
|
|
62651
62829
|
const src = resolve12(d.reference);
|
|
@@ -62660,7 +62838,7 @@ Action: ${guidance}` : ""
|
|
|
62660
62838
|
}
|
|
62661
62839
|
if (d.type === "file" && d.summary && !existsSync24(d.reference)) {
|
|
62662
62840
|
const safeName = d.reference.replace(/[^a-zA-Z0-9._-]/g, "_").slice(0, 80);
|
|
62663
|
-
|
|
62841
|
+
writeFileSync14(join20(taskSharedDir, `${safeName}.md`), d.summary);
|
|
62664
62842
|
}
|
|
62665
62843
|
}
|
|
62666
62844
|
log51.info("Deliverables published to shared workspace", { taskId: task.id, dir: taskSharedDir });
|
|
@@ -63486,7 +63664,7 @@ ${task.description}`;
|
|
|
63486
63664
|
|
|
63487
63665
|
// ../org-manager/dist/builder-service.js
|
|
63488
63666
|
import { join as join21 } from "node:path";
|
|
63489
|
-
import { readdirSync as readdirSync8, readFileSync as readFileSync19, existsSync as existsSync25, writeFileSync as
|
|
63667
|
+
import { readdirSync as readdirSync8, readFileSync as readFileSync19, existsSync as existsSync25, writeFileSync as writeFileSync15, mkdirSync as mkdirSync17, copyFileSync as copyFileSync2, statSync as statSync4, cpSync as cpSync2 } from "node:fs";
|
|
63490
63668
|
import { homedir as homedir12 } from "node:os";
|
|
63491
63669
|
var log52, FS_HELPER, BuilderService;
|
|
63492
63670
|
var init_builder_service = __esm({
|
|
@@ -63592,7 +63770,7 @@ var init_builder_service = __esm({
|
|
|
63592
63770
|
copyFileSync2(srcFile, join21(agentRoleDir, fname));
|
|
63593
63771
|
}
|
|
63594
63772
|
}
|
|
63595
|
-
|
|
63773
|
+
writeFileSync15(join21(agentRoleDir, ".role-origin.json"), JSON.stringify({ customRole: true, source: "builder-artifact", artifact: artifactName, artifactType: "agent" }));
|
|
63596
63774
|
agent.reloadRole();
|
|
63597
63775
|
await agentManager.startAgent(agent.id);
|
|
63598
63776
|
return {
|
|
@@ -63654,7 +63832,7 @@ var init_builder_service = __esm({
|
|
|
63654
63832
|
}
|
|
63655
63833
|
}
|
|
63656
63834
|
}
|
|
63657
|
-
|
|
63835
|
+
writeFileSync15(join21(agentRoleDir, ".role-origin.json"), JSON.stringify({ customRole: true, source: "builder-artifact", artifact: artifactName, artifactType: "team" }));
|
|
63658
63836
|
agent.reloadRole();
|
|
63659
63837
|
if (memberRole === "manager") {
|
|
63660
63838
|
await this.orgService.updateTeam(team.id, { managerId: agent.id, managerType: "agent" });
|
|
@@ -64369,23 +64547,6 @@ var init_sse_handler = __esm({
|
|
|
64369
64547
|
this.sseBuffer.sendProgress(this.processedTokens, this.totalTokens, `\u5DE5\u5177\u6267\u884C\u5B8C\u6210: ${event.tool}`);
|
|
64370
64548
|
}
|
|
64371
64549
|
} else if (event.type === "message_end") {
|
|
64372
|
-
const now2 = (/* @__PURE__ */ new Date()).toISOString();
|
|
64373
|
-
let turnThinking;
|
|
64374
|
-
if (this.thinkingBuf) {
|
|
64375
|
-
this.sseBuffer.send({ type: "thinking_commit", thinking: this.thinkingBuf, createdAt: now2 });
|
|
64376
|
-
turnThinking = this.thinkingBuf;
|
|
64377
|
-
this.thinkingBuf = "";
|
|
64378
|
-
}
|
|
64379
|
-
if (this.textBuf) {
|
|
64380
|
-
this.sseBuffer.send({ type: "text_commit", text: this.textBuf, createdAt: now2 });
|
|
64381
|
-
const seg2 = { type: "text", content: this.textBuf, createdAt: now2 };
|
|
64382
|
-
if (turnThinking)
|
|
64383
|
-
seg2.thinking = turnThinking;
|
|
64384
|
-
this.msgSegments.push(seg2);
|
|
64385
|
-
this.textBuf = "";
|
|
64386
|
-
} else if (turnThinking) {
|
|
64387
|
-
this.msgSegments.push({ type: "text", content: "", thinking: turnThinking, createdAt: now2 });
|
|
64388
|
-
}
|
|
64389
64550
|
if (event.usage?.outputTokens) {
|
|
64390
64551
|
this.totalTokens = Math.max(this.totalTokens, event.usage.outputTokens);
|
|
64391
64552
|
this.processedTokens = event.usage.outputTokens;
|
|
@@ -64459,7 +64620,7 @@ var init_sse_handler = __esm({
|
|
|
64459
64620
|
|
|
64460
64621
|
// ../org-manager/dist/skill-service.js
|
|
64461
64622
|
import { join as join22, resolve as resolve13 } from "node:path";
|
|
64462
|
-
import { existsSync as existsSync26, writeFileSync as
|
|
64623
|
+
import { existsSync as existsSync26, writeFileSync as writeFileSync16, mkdirSync as mkdirSync18, readFileSync as readFileSync20, readdirSync as readdirSync9, copyFileSync as copyFileSync3 } from "node:fs";
|
|
64463
64624
|
import { homedir as homedir13 } from "node:os";
|
|
64464
64625
|
import { execSync as execSync2 } from "node:child_process";
|
|
64465
64626
|
async function searchSkillHub(query2) {
|
|
@@ -64610,7 +64771,7 @@ async function installSkill(request, skillRegistry) {
|
|
|
64610
64771
|
if (zipResp.ok) {
|
|
64611
64772
|
const tmpZip = join22(skillsDir, `_tmp_${safeName}.zip`);
|
|
64612
64773
|
const buffer = Buffer.from(await zipResp.arrayBuffer());
|
|
64613
|
-
|
|
64774
|
+
writeFileSync16(tmpZip, buffer);
|
|
64614
64775
|
mkdirSync18(targetDir, { recursive: true });
|
|
64615
64776
|
try {
|
|
64616
64777
|
execSync2(`unzip -o "${tmpZip}" -d "${targetDir}"`, { timeout: 3e4 });
|
|
@@ -64636,7 +64797,7 @@ async function installSkill(request, skillRegistry) {
|
|
|
64636
64797
|
const mdResp = await fetch(skillMdUrl, { signal: AbortSignal.timeout(15e3) });
|
|
64637
64798
|
if (mdResp.ok) {
|
|
64638
64799
|
mkdirSync18(targetDir, { recursive: true });
|
|
64639
|
-
|
|
64800
|
+
writeFileSync16(join22(targetDir, "SKILL.md"), await mdResp.text(), "utf-8");
|
|
64640
64801
|
installed = true;
|
|
64641
64802
|
installMethod = "github-skillmd";
|
|
64642
64803
|
}
|
|
@@ -64650,7 +64811,7 @@ async function installSkill(request, skillRegistry) {
|
|
|
64650
64811
|
const mdResp = await fetch(rootMd, { signal: AbortSignal.timeout(15e3) });
|
|
64651
64812
|
if (mdResp.ok) {
|
|
64652
64813
|
mkdirSync18(targetDir, { recursive: true });
|
|
64653
|
-
|
|
64814
|
+
writeFileSync16(join22(targetDir, "SKILL.md"), await mdResp.text(), "utf-8");
|
|
64654
64815
|
installed = true;
|
|
64655
64816
|
installMethod = "github-root-skillmd";
|
|
64656
64817
|
}
|
|
@@ -64666,7 +64827,7 @@ async function installSkill(request, skillRegistry) {
|
|
|
64666
64827
|
if (zipResp.ok) {
|
|
64667
64828
|
const tmpZip = join22(skillsDir, `_tmp_${safeName}.zip`);
|
|
64668
64829
|
const buffer = Buffer.from(await zipResp.arrayBuffer());
|
|
64669
|
-
|
|
64830
|
+
writeFileSync16(tmpZip, buffer);
|
|
64670
64831
|
mkdirSync18(targetDir, { recursive: true });
|
|
64671
64832
|
try {
|
|
64672
64833
|
execSync2(`unzip -o "${tmpZip}" -d "${targetDir}"`, { timeout: 3e4 });
|
|
@@ -64698,13 +64859,13 @@ async function installSkill(request, skillRegistry) {
|
|
|
64698
64859
|
};
|
|
64699
64860
|
const manifest = buildManifest("skill", raw);
|
|
64700
64861
|
manifest.source = skillSource;
|
|
64701
|
-
|
|
64862
|
+
writeFileSync16(skillMfPath, JSON.stringify(manifest, null, 2), "utf-8");
|
|
64702
64863
|
} else {
|
|
64703
64864
|
try {
|
|
64704
64865
|
const mf = JSON.parse(readFileSync20(skillMfPath, "utf-8"));
|
|
64705
64866
|
if (!mf.source) {
|
|
64706
64867
|
mf.source = skillSource;
|
|
64707
|
-
|
|
64868
|
+
writeFileSync16(skillMfPath, JSON.stringify(mf, null, 2), "utf-8");
|
|
64708
64869
|
}
|
|
64709
64870
|
} catch {
|
|
64710
64871
|
}
|
|
@@ -64738,7 +64899,7 @@ var init_skill_service = __esm({
|
|
|
64738
64899
|
// ../org-manager/dist/api-server.js
|
|
64739
64900
|
import { createServer as createServer2 } from "node:http";
|
|
64740
64901
|
import { join as join23, resolve as resolve14, dirname as dirname6 } from "node:path";
|
|
64741
|
-
import { readdirSync as readdirSync10, readFileSync as readFileSync21, existsSync as existsSync27, writeFileSync as
|
|
64902
|
+
import { readdirSync as readdirSync10, readFileSync as readFileSync21, existsSync as existsSync27, writeFileSync as writeFileSync17, mkdirSync as mkdirSync19, rmSync as rmSync3, statSync as statSync5 } from "node:fs";
|
|
64742
64903
|
import { homedir as homedir14 } from "node:os";
|
|
64743
64904
|
import { execSync as execSync3 } from "node:child_process";
|
|
64744
64905
|
async function signToken(payload, secret) {
|
|
@@ -64828,7 +64989,7 @@ var init_api_server = __esm({
|
|
|
64828
64989
|
init_skill_service();
|
|
64829
64990
|
log57 = createLogger("api-server");
|
|
64830
64991
|
PBKDF2_ITERATIONS = 1e4;
|
|
64831
|
-
APIServer = class {
|
|
64992
|
+
APIServer = class _APIServer {
|
|
64832
64993
|
orgService;
|
|
64833
64994
|
taskService;
|
|
64834
64995
|
port;
|
|
@@ -64853,7 +65014,7 @@ var init_api_server = __esm({
|
|
|
64853
65014
|
builderService;
|
|
64854
65015
|
workflowEngine;
|
|
64855
65016
|
teamTemplateRegistry;
|
|
64856
|
-
|
|
65017
|
+
// Custom group chats are now persisted in SQLite via storage.groupChatRepo
|
|
64857
65018
|
constructor(orgService, taskService, port = 8056) {
|
|
64858
65019
|
this.orgService = orgService;
|
|
64859
65020
|
this.taskService = taskService;
|
|
@@ -64868,15 +65029,18 @@ var init_api_server = __esm({
|
|
|
64868
65029
|
am.setGroupChatHandlers({
|
|
64869
65030
|
sendGroupMessage: async (channelKey, message, senderId, senderName) => {
|
|
64870
65031
|
const cleanText = stripInternalBlocks(message);
|
|
65032
|
+
const orgId2 = "default";
|
|
65033
|
+
let persistedMsgId;
|
|
64871
65034
|
if (this.storage) {
|
|
64872
|
-
await this.storage.channelMessageRepo.append({
|
|
64873
|
-
orgId:
|
|
65035
|
+
const saved = await this.storage.channelMessageRepo.append({
|
|
65036
|
+
orgId: orgId2,
|
|
64874
65037
|
channel: channelKey,
|
|
64875
65038
|
senderId,
|
|
64876
65039
|
senderType: "agent",
|
|
64877
65040
|
senderName,
|
|
64878
65041
|
text: cleanText
|
|
64879
65042
|
});
|
|
65043
|
+
persistedMsgId = saved.id;
|
|
64880
65044
|
}
|
|
64881
65045
|
this.ws.broadcast({
|
|
64882
65046
|
type: "chat:message",
|
|
@@ -64889,41 +65053,81 @@ var init_api_server = __esm({
|
|
|
64889
65053
|
},
|
|
64890
65054
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
64891
65055
|
});
|
|
64892
|
-
|
|
64893
|
-
if (
|
|
64894
|
-
|
|
64895
|
-
|
|
64896
|
-
|
|
64897
|
-
|
|
64898
|
-
|
|
64899
|
-
|
|
64900
|
-
|
|
64901
|
-
|
|
64902
|
-
|
|
64903
|
-
|
|
64904
|
-
|
|
65056
|
+
let allAgentIds = [];
|
|
65057
|
+
if (channelKey.startsWith("group:custom:") && this.storage?.groupChatRepo) {
|
|
65058
|
+
allAgentIds = this.storage.groupChatRepo.getAgentMemberIds(channelKey);
|
|
65059
|
+
} else if (channelKey.startsWith("group:")) {
|
|
65060
|
+
const teamId = channelKey.replace(/^group:/, "");
|
|
65061
|
+
const team = this.orgService.getTeam(teamId);
|
|
65062
|
+
allAgentIds = team?.memberAgentIds ?? [];
|
|
65063
|
+
}
|
|
65064
|
+
const peerAgentIds = allAgentIds.filter((id) => id !== senderId);
|
|
65065
|
+
if (peerAgentIds.length > 0) {
|
|
65066
|
+
const agentManager = this.orgService.getAgentManager();
|
|
65067
|
+
const nameMap = this.buildAgentNameMap(allAgentIds, agentManager);
|
|
65068
|
+
const mentionedNames = this.parseAgentMentions(cleanText, [...nameMap.keys()]);
|
|
65069
|
+
const filteredMentions = mentionedNames.filter((n) => {
|
|
65070
|
+
const id = nameMap.get(n);
|
|
65071
|
+
return id && id !== senderId;
|
|
65072
|
+
});
|
|
65073
|
+
if (filteredMentions.length > 0) {
|
|
65074
|
+
let channelContext = [];
|
|
65075
|
+
if (this.storage) {
|
|
65076
|
+
try {
|
|
65077
|
+
const recent = await this.storage.channelMessageRepo.getMessages(channelKey, 20);
|
|
65078
|
+
channelContext = (recent.messages ?? []).map((m) => ({
|
|
65079
|
+
role: m.senderType === "agent" ? "assistant" : "user",
|
|
65080
|
+
content: m.senderType === "agent" ? stripInternalBlocks(m.text) : `[${m.senderName}]: ${m.text}`
|
|
65081
|
+
}));
|
|
65082
|
+
} catch {
|
|
65083
|
+
}
|
|
65084
|
+
}
|
|
65085
|
+
const roundId = `round_${Date.now()}`;
|
|
65086
|
+
const respondedAgents = /* @__PURE__ */ new Set([senderId]);
|
|
65087
|
+
void this.triggerAgentToAgentChain(filteredMentions, nameMap, senderName, senderId, cleanText, persistedMsgId, channelKey, orgId2, agentManager, allAgentIds.length, { roundId, depth: 1, respondedAgents, allAgentIds });
|
|
65088
|
+
} else {
|
|
65089
|
+
for (const peerId of peerAgentIds) {
|
|
65090
|
+
try {
|
|
65091
|
+
agentManager.getAgent(peerId).enqueueToMailbox("a2a_message", {
|
|
65092
|
+
summary: `Group chat message from ${senderName}`,
|
|
65093
|
+
content: `[Group chat message from ${senderName}]:
|
|
65094
|
+
${cleanText}`,
|
|
65095
|
+
extra: { senderId, senderName, channelKey }
|
|
65096
|
+
}, {
|
|
65097
|
+
metadata: { senderId, senderName, senderRole: "agent" }
|
|
65098
|
+
});
|
|
65099
|
+
} catch {
|
|
65100
|
+
}
|
|
64905
65101
|
}
|
|
64906
65102
|
}
|
|
64907
65103
|
}
|
|
64908
65104
|
return "Message sent to group chat";
|
|
64909
65105
|
},
|
|
64910
65106
|
createGroupChat: async (name, creatorId, creatorName, memberIds) => {
|
|
64911
|
-
|
|
64912
|
-
|
|
64913
|
-
|
|
64914
|
-
|
|
64915
|
-
|
|
64916
|
-
|
|
64917
|
-
|
|
64918
|
-
|
|
64919
|
-
|
|
64920
|
-
|
|
64921
|
-
|
|
64922
|
-
|
|
64923
|
-
|
|
64924
|
-
|
|
64925
|
-
|
|
64926
|
-
|
|
65107
|
+
if (this.storage?.groupChatRepo) {
|
|
65108
|
+
const members = memberIds.map((id) => {
|
|
65109
|
+
try {
|
|
65110
|
+
const agentInfo = this.orgService.getAgentManager().getAgent(id);
|
|
65111
|
+
return { id, type: "agent", name: agentInfo?.config?.name ?? id };
|
|
65112
|
+
} catch {
|
|
65113
|
+
return { id, type: "agent", name: id };
|
|
65114
|
+
}
|
|
65115
|
+
});
|
|
65116
|
+
const gc = this.storage.groupChatRepo.create({
|
|
65117
|
+
orgId: "default",
|
|
65118
|
+
name,
|
|
65119
|
+
creatorId,
|
|
65120
|
+
creatorName,
|
|
65121
|
+
members
|
|
65122
|
+
});
|
|
65123
|
+
this.ws.broadcast({
|
|
65124
|
+
type: "chat:group_created",
|
|
65125
|
+
payload: { chatId: gc.channelKey, name, creatorId, creatorName },
|
|
65126
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
65127
|
+
});
|
|
65128
|
+
return { id: gc.channelKey, name };
|
|
65129
|
+
}
|
|
65130
|
+
return { id: `group:custom:${Date.now().toString(36)}`, name };
|
|
64927
65131
|
},
|
|
64928
65132
|
listGroupChats: async () => {
|
|
64929
65133
|
const teams = this.orgService.listTeamsWithMembers("default");
|
|
@@ -64933,13 +65137,27 @@ var init_api_server = __esm({
|
|
|
64933
65137
|
type: "team",
|
|
64934
65138
|
channelKey: `group:${t.id}`
|
|
64935
65139
|
}));
|
|
64936
|
-
const customChats = this.
|
|
64937
|
-
id: c.
|
|
65140
|
+
const customChats = this.storage?.groupChatRepo ? this.storage.groupChatRepo.list("default").map((c) => ({
|
|
65141
|
+
id: c.channelKey,
|
|
64938
65142
|
name: c.name,
|
|
64939
65143
|
type: "custom",
|
|
64940
|
-
channelKey: c.
|
|
64941
|
-
}));
|
|
65144
|
+
channelKey: c.channelKey
|
|
65145
|
+
})) : [];
|
|
64942
65146
|
return [...teamChats, ...customChats];
|
|
65147
|
+
},
|
|
65148
|
+
getChannelMessages: async (channelKey, limit, before2) => {
|
|
65149
|
+
if (!this.storage)
|
|
65150
|
+
return { messages: [], hasMore: false };
|
|
65151
|
+
const result = this.storage.channelMessageRepo.getMessages(channelKey, limit, before2);
|
|
65152
|
+
return {
|
|
65153
|
+
messages: result.messages.map((m) => ({
|
|
65154
|
+
senderName: m.senderName,
|
|
65155
|
+
senderType: m.senderType,
|
|
65156
|
+
text: stripInternalBlocks(m.text),
|
|
65157
|
+
createdAt: m.createdAt instanceof Date ? m.createdAt.toISOString() : String(m.createdAt)
|
|
65158
|
+
})),
|
|
65159
|
+
hasMore: result.hasMore
|
|
65160
|
+
};
|
|
64943
65161
|
}
|
|
64944
65162
|
});
|
|
64945
65163
|
}
|
|
@@ -65005,10 +65223,10 @@ var init_api_server = __esm({
|
|
|
65005
65223
|
for (const [fname, content] of Object.entries(data.files)) {
|
|
65006
65224
|
const filePath = join23(artDir, fname);
|
|
65007
65225
|
mkdirSync19(dirname6(filePath), { recursive: true });
|
|
65008
|
-
|
|
65226
|
+
writeFileSync17(filePath, content, "utf-8");
|
|
65009
65227
|
}
|
|
65010
65228
|
} else if (data.config) {
|
|
65011
|
-
|
|
65229
|
+
writeFileSync17(join23(artDir, manifestFilename(mode)), JSON.stringify(data.config, null, 2), "utf-8");
|
|
65012
65230
|
}
|
|
65013
65231
|
return self.builderService.installArtifact(mode, slug);
|
|
65014
65232
|
}
|
|
@@ -65239,48 +65457,167 @@ var init_api_server = __esm({
|
|
|
65239
65457
|
log57.warn("Failed to persist chat turn", { error: String(err) });
|
|
65240
65458
|
}
|
|
65241
65459
|
}
|
|
65460
|
+
// ── Agent-to-agent reply storm prevention ───────────────────────────────────
|
|
65461
|
+
static A2A_MAX_DEPTH = 3;
|
|
65462
|
+
static A2A_COOLDOWN_MS = 3e4;
|
|
65463
|
+
/** Per-channel cooldown tracker: channel → agentId → last reply timestamp */
|
|
65464
|
+
a2aCooldowns = /* @__PURE__ */ new Map();
|
|
65465
|
+
/** Extract @mentions from agent reply text. Returns agent names found.
|
|
65466
|
+
* Handles multi-word names (e.g. "Ryan 莱恩") by checking known names after each @ sign.
|
|
65467
|
+
* Also matches partial names: "@Sofia" matches "Sofia 索菲亚" if "Sofia" is a token in the name. */
|
|
65468
|
+
parseAgentMentions(text, knownAgentNames) {
|
|
65469
|
+
const mentioned = /* @__PURE__ */ new Set();
|
|
65470
|
+
const sorted = [...knownAgentNames].sort((a, b) => b.length - a.length);
|
|
65471
|
+
const tokenToName = /* @__PURE__ */ new Map();
|
|
65472
|
+
for (const name of sorted) {
|
|
65473
|
+
for (const token of name.split(/\s+/)) {
|
|
65474
|
+
if (token.length >= 2) {
|
|
65475
|
+
const key2 = token.toLowerCase();
|
|
65476
|
+
if (!tokenToName.has(key2))
|
|
65477
|
+
tokenToName.set(key2, name);
|
|
65478
|
+
}
|
|
65479
|
+
}
|
|
65480
|
+
}
|
|
65481
|
+
let idx = 0;
|
|
65482
|
+
while (idx < text.length) {
|
|
65483
|
+
const atPos = text.indexOf("@", idx);
|
|
65484
|
+
if (atPos < 0)
|
|
65485
|
+
break;
|
|
65486
|
+
if (text[atPos + 1] === "[") {
|
|
65487
|
+
const close = text.indexOf("]", atPos + 2);
|
|
65488
|
+
if (close > atPos + 2) {
|
|
65489
|
+
const bracketed = text.slice(atPos + 2, close);
|
|
65490
|
+
const match = sorted.find((n) => n.toLowerCase() === bracketed.toLowerCase());
|
|
65491
|
+
if (match)
|
|
65492
|
+
mentioned.add(match);
|
|
65493
|
+
idx = close + 1;
|
|
65494
|
+
continue;
|
|
65495
|
+
}
|
|
65496
|
+
}
|
|
65497
|
+
const after2 = text.slice(atPos + 1);
|
|
65498
|
+
const afterLower = after2.toLowerCase();
|
|
65499
|
+
const fullMatch = sorted.find((n) => afterLower.startsWith(n.toLowerCase()));
|
|
65500
|
+
if (fullMatch) {
|
|
65501
|
+
mentioned.add(fullMatch);
|
|
65502
|
+
idx = atPos + 1 + fullMatch.length;
|
|
65503
|
+
continue;
|
|
65504
|
+
}
|
|
65505
|
+
const tokenMatch = after2.match(/^(\S+)/);
|
|
65506
|
+
if (tokenMatch) {
|
|
65507
|
+
const token = tokenMatch[1].toLowerCase().replace(/[,,。!?!?;;::、()()[\]【】]+$/, "");
|
|
65508
|
+
const resolved = tokenToName.get(token);
|
|
65509
|
+
if (resolved) {
|
|
65510
|
+
mentioned.add(resolved);
|
|
65511
|
+
idx = atPos + 1 + tokenMatch[1].length;
|
|
65512
|
+
continue;
|
|
65513
|
+
}
|
|
65514
|
+
}
|
|
65515
|
+
idx = atPos + 1;
|
|
65516
|
+
}
|
|
65517
|
+
return [...mentioned];
|
|
65518
|
+
}
|
|
65519
|
+
/** Build name→id lookup for agents in a channel */
|
|
65520
|
+
buildAgentNameMap(agentIds, agentManager) {
|
|
65521
|
+
const map = /* @__PURE__ */ new Map();
|
|
65522
|
+
for (const id of agentIds) {
|
|
65523
|
+
try {
|
|
65524
|
+
map.set(agentManager.getAgent(id).config.name, id);
|
|
65525
|
+
} catch {
|
|
65526
|
+
}
|
|
65527
|
+
}
|
|
65528
|
+
return map;
|
|
65529
|
+
}
|
|
65242
65530
|
/**
|
|
65243
65531
|
* Process a single agent's reply in a group chat broadcast.
|
|
65244
65532
|
* Each agent decides independently whether to respond.
|
|
65245
65533
|
* Replies are persisted and broadcast via WebSocket.
|
|
65534
|
+
* If the agent @mentions other agents, a chain reply is triggered (with storm prevention).
|
|
65246
65535
|
*/
|
|
65247
|
-
async processGroupChatReply(agentId2, userMessage, senderId, senderInfo, channel, orgId2, channelContext, agentManager, teamSize) {
|
|
65536
|
+
async processGroupChatReply(agentId2, userMessage, senderId, senderInfo, channel, orgId2, channelContext, agentManager, teamSize, opts, chainCtx) {
|
|
65248
65537
|
try {
|
|
65249
65538
|
const agent = agentManager.getAgent(agentId2);
|
|
65250
65539
|
const agentName = agent.config.name;
|
|
65251
|
-
const
|
|
65252
|
-
|
|
65253
|
-
|
|
65254
|
-
|
|
65255
|
-
|
|
65256
|
-
|
|
65257
|
-
|
|
65258
|
-
|
|
65259
|
-
|
|
65260
|
-
|
|
65261
|
-
|
|
65262
|
-
|
|
65540
|
+
const isA2A = !!chainCtx && chainCtx.depth > 0;
|
|
65541
|
+
const hasReplyTarget = !!opts?.replyToAgentName;
|
|
65542
|
+
const hasMentions = !!opts?.mentionedNames?.length;
|
|
65543
|
+
const isTargeted = hasReplyTarget || hasMentions;
|
|
65544
|
+
const targetNames = /* @__PURE__ */ new Set();
|
|
65545
|
+
if (opts?.replyToAgentName)
|
|
65546
|
+
targetNames.add(opts.replyToAgentName);
|
|
65547
|
+
if (opts?.mentionedNames)
|
|
65548
|
+
opts.mentionedNames.forEach((n) => targetNames.add(n));
|
|
65549
|
+
const thisAgentIsTarget = targetNames.has(agentName);
|
|
65550
|
+
const prefixLines = [
|
|
65551
|
+
`[GROUP CHAT \u2014 ${teamSize} team members | You are: ${agentName}]`,
|
|
65263
65552
|
""
|
|
65264
|
-
]
|
|
65553
|
+
];
|
|
65554
|
+
if (isA2A) {
|
|
65555
|
+
prefixLines.push(`[AGENT COLLABORATION] This message is from a fellow agent (${opts?.replyToAgentName ?? "teammate"}), not from the user.`);
|
|
65556
|
+
prefixLines.push("You were @mentioned because your expertise is needed. Respond concisely to the specific request.");
|
|
65557
|
+
prefixLines.push("You may @mention another agent if (and ONLY if) you genuinely need their specific expertise to answer.");
|
|
65558
|
+
prefixLines.push("Do NOT @mention agents just to be polite or to pass the conversation along.");
|
|
65559
|
+
prefixLines.push("");
|
|
65560
|
+
}
|
|
65561
|
+
if (isTargeted && !isA2A) {
|
|
65562
|
+
if (hasReplyTarget) {
|
|
65563
|
+
prefixLines.push(`[REPLY] The user is replying to ${opts.replyToAgentName}'s message: "${(opts.replyToText ?? "").slice(0, 200)}"`);
|
|
65564
|
+
}
|
|
65565
|
+
if (hasMentions) {
|
|
65566
|
+
prefixLines.push(`[MENTIONED] The user @mentioned: ${opts.mentionedNames.join(", ")}`);
|
|
65567
|
+
}
|
|
65568
|
+
prefixLines.push("");
|
|
65569
|
+
if (thisAgentIsTarget) {
|
|
65570
|
+
prefixLines.push(">>> You are the target of this message. You SHOULD respond. <<<");
|
|
65571
|
+
} else {
|
|
65572
|
+
prefixLines.push(">>> STOP. This message is NOT for you. The user is talking to " + [...targetNames].join(", ") + ", not you.");
|
|
65573
|
+
prefixLines.push("You MUST respond with exactly: [NO_RESPONSE]");
|
|
65574
|
+
prefixLines.push('The ONLY exception: you are directly contradicted by a factual error. Offering opinions, agreement, "me too", or generic help does NOT count. <<<');
|
|
65575
|
+
}
|
|
65576
|
+
} else if (!isA2A) {
|
|
65577
|
+
prefixLines.push("This is an open group message (no specific @mention or reply target).");
|
|
65578
|
+
}
|
|
65579
|
+
prefixLines.push("");
|
|
65580
|
+
prefixLines.push("Rules for ALL group chat messages:");
|
|
65581
|
+
prefixLines.push("1. Check channel history \u2014 if another agent already answered, do NOT repeat.");
|
|
65582
|
+
prefixLines.push("2. Only respond if your specific role/expertise is directly relevant.");
|
|
65583
|
+
prefixLines.push("3. Be concise \u2014 short, actionable responses only.");
|
|
65584
|
+
if (agent.config.agentRole === "manager") {
|
|
65585
|
+
prefixLines.push("4. When assigning work to agents, you MUST use `task_create` to formalize each assignment as a tracked task. Verbal delegation without a task is NOT allowed \u2014 oral promises are meaningless without task tracking. Every commitment must have a corresponding task.");
|
|
65586
|
+
} else {
|
|
65587
|
+
prefixLines.push("4. When you accept a work assignment, verify a task has been created for it (`task_list`). If the coordinator did not create one, remind them or create it yourself with the correct `assigned_agent_id`. Do NOT make promises without task tracking.");
|
|
65588
|
+
}
|
|
65589
|
+
prefixLines.push("5. DEFAULT IS SILENCE. When in doubt, respond with exactly: [NO_RESPONSE]");
|
|
65590
|
+
prefixLines.push('6. If the provided context is insufficient, use `recall_context` (scope="channel") to fetch earlier messages before responding. For task/requirement details use `task_get`/`requirement_get`. Do NOT guess about prior discussion.');
|
|
65591
|
+
if (isTargeted && !thisAgentIsTarget && !isA2A) {
|
|
65592
|
+
prefixLines.push("7. REMINDER: This message is directed at " + [...targetNames].join(", ") + ". You are " + agentName + ". Respond ONLY with [NO_RESPONSE].");
|
|
65593
|
+
}
|
|
65594
|
+
prefixLines.push("---", "");
|
|
65595
|
+
const groupChatPrefix = prefixLines.join("\n");
|
|
65265
65596
|
const toolEvents = [];
|
|
65266
65597
|
const reply = await agent.sendMessage(groupChatPrefix + userMessage, senderId, senderInfo, {
|
|
65267
|
-
sourceType: "human_chat",
|
|
65598
|
+
sourceType: isA2A ? "a2a_message" : "human_chat",
|
|
65599
|
+
scenario: isA2A ? "a2a" : void 0,
|
|
65268
65600
|
channelContext,
|
|
65269
65601
|
toolEventCollector: toolEvents
|
|
65270
65602
|
});
|
|
65271
|
-
if (!reply || reply.trim()
|
|
65603
|
+
if (!reply || !reply.trim() || reply.includes("[NO_RESPONSE]")) {
|
|
65272
65604
|
return;
|
|
65273
65605
|
}
|
|
65274
|
-
const { thinking, clean:
|
|
65275
|
-
|
|
65606
|
+
const { thinking, clean: rawClean } = extractThinkBlocks(reply);
|
|
65607
|
+
const cleanReply = rawClean.replace(/\[NO_RESPONSE\]/gi, "").trim();
|
|
65608
|
+
if (!cleanReply)
|
|
65276
65609
|
return;
|
|
65277
65610
|
const metadata = {};
|
|
65278
65611
|
if (thinking.length > 0)
|
|
65279
65612
|
metadata["thinking"] = thinking;
|
|
65280
65613
|
if (toolEvents.length > 0)
|
|
65281
65614
|
metadata["toolCalls"] = toolEvents;
|
|
65615
|
+
if (isA2A && opts?.replyToAgentName) {
|
|
65616
|
+
metadata["replyToAgent"] = opts.replyToAgentName;
|
|
65617
|
+
}
|
|
65618
|
+
let persistedMsgId;
|
|
65282
65619
|
if (this.storage) {
|
|
65283
|
-
await this.storage.channelMessageRepo.append({
|
|
65620
|
+
const saved = await this.storage.channelMessageRepo.append({
|
|
65284
65621
|
orgId: orgId2,
|
|
65285
65622
|
channel,
|
|
65286
65623
|
senderId: agentId2,
|
|
@@ -65288,8 +65625,10 @@ var init_api_server = __esm({
|
|
|
65288
65625
|
senderName: agentName,
|
|
65289
65626
|
text: cleanReply,
|
|
65290
65627
|
mentions: [],
|
|
65291
|
-
metadata: Object.keys(metadata).length > 0 ? metadata : void 0
|
|
65628
|
+
metadata: Object.keys(metadata).length > 0 ? metadata : void 0,
|
|
65629
|
+
replyToId: isA2A ? opts?.replyToMsgId : void 0
|
|
65292
65630
|
});
|
|
65631
|
+
persistedMsgId = saved.id;
|
|
65293
65632
|
}
|
|
65294
65633
|
this.ws.broadcast({
|
|
65295
65634
|
type: "chat:message",
|
|
@@ -65299,10 +65638,29 @@ var init_api_server = __esm({
|
|
|
65299
65638
|
senderType: "agent",
|
|
65300
65639
|
senderName: agentName,
|
|
65301
65640
|
text: cleanReply,
|
|
65302
|
-
metadata: Object.keys(metadata).length > 0 ? metadata : void 0
|
|
65641
|
+
metadata: Object.keys(metadata).length > 0 ? metadata : void 0,
|
|
65642
|
+
...isA2A ? {
|
|
65643
|
+
replyToId: opts?.replyToMsgId,
|
|
65644
|
+
replyToSender: opts?.replyToAgentName,
|
|
65645
|
+
replyToText: (opts?.replyToText ?? "").slice(0, 120)
|
|
65646
|
+
} : {}
|
|
65303
65647
|
},
|
|
65304
65648
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
65305
65649
|
});
|
|
65650
|
+
const allAgentIds = chainCtx?.allAgentIds ?? [];
|
|
65651
|
+
if (allAgentIds.length > 0) {
|
|
65652
|
+
const nameMap = this.buildAgentNameMap(allAgentIds, agentManager);
|
|
65653
|
+
const mentionedNames = this.parseAgentMentions(cleanReply, [...nameMap.keys()]);
|
|
65654
|
+
const filteredMentions = mentionedNames.filter((n) => n !== agentName);
|
|
65655
|
+
log57.info("A2A mention scan", { agentName, mentionedNames, filteredMentions, depth: chainCtx?.depth ?? 0 });
|
|
65656
|
+
if (filteredMentions.length > 0) {
|
|
65657
|
+
const depth = (chainCtx?.depth ?? 0) + 1;
|
|
65658
|
+
const roundId = chainCtx?.roundId ?? `round_${Date.now()}`;
|
|
65659
|
+
const responded = chainCtx?.respondedAgents ?? /* @__PURE__ */ new Set();
|
|
65660
|
+
responded.add(agentId2);
|
|
65661
|
+
void this.triggerAgentToAgentChain(filteredMentions, nameMap, agentName, agentId2, cleanReply, persistedMsgId, channel, orgId2, agentManager, teamSize, { roundId, depth, respondedAgents: responded, allAgentIds });
|
|
65662
|
+
}
|
|
65663
|
+
}
|
|
65306
65664
|
} catch (err) {
|
|
65307
65665
|
log57.warn("Group chat agent reply failed", { agentId: agentId2, error: String(err) });
|
|
65308
65666
|
if (this.storage) {
|
|
@@ -65322,6 +65680,56 @@ var init_api_server = __esm({
|
|
|
65322
65680
|
}
|
|
65323
65681
|
}
|
|
65324
65682
|
}
|
|
65683
|
+
/**
|
|
65684
|
+
* Trigger agent-to-agent chain replies with 3-layer storm prevention:
|
|
65685
|
+
* 1. Depth limit (max 3 hops)
|
|
65686
|
+
* 2. Per-round dedup (each agent responds at most once per conversation round)
|
|
65687
|
+
* 3. Cooldown window (same agent won't be triggered twice within 30s on same channel)
|
|
65688
|
+
*/
|
|
65689
|
+
async triggerAgentToAgentChain(mentionedNames, nameMap, fromAgentName, fromAgentId, fromText, fromMsgId, channel, orgId2, agentManager, teamSize, chainCtx) {
|
|
65690
|
+
if (chainCtx.depth > _APIServer.A2A_MAX_DEPTH) {
|
|
65691
|
+
log57.info("A2A chain depth limit reached", { channel, depth: chainCtx.depth, roundId: chainCtx.roundId });
|
|
65692
|
+
return;
|
|
65693
|
+
}
|
|
65694
|
+
const now2 = Date.now();
|
|
65695
|
+
if (!this.a2aCooldowns.has(channel)) {
|
|
65696
|
+
this.a2aCooldowns.set(channel, /* @__PURE__ */ new Map());
|
|
65697
|
+
}
|
|
65698
|
+
const channelCooldowns = this.a2aCooldowns.get(channel);
|
|
65699
|
+
let channelContext = [];
|
|
65700
|
+
if (this.storage) {
|
|
65701
|
+
try {
|
|
65702
|
+
const recent = await this.storage.channelMessageRepo.getMessages(channel, 20);
|
|
65703
|
+
channelContext = (recent.messages ?? []).map((m) => ({
|
|
65704
|
+
role: m.senderType === "agent" ? "assistant" : "user",
|
|
65705
|
+
content: m.senderType === "agent" ? stripInternalBlocks(m.text) : `[${m.senderName}]: ${m.text}`
|
|
65706
|
+
}));
|
|
65707
|
+
} catch {
|
|
65708
|
+
}
|
|
65709
|
+
}
|
|
65710
|
+
for (const targetName of mentionedNames) {
|
|
65711
|
+
const targetId = nameMap.get(targetName);
|
|
65712
|
+
if (!targetId)
|
|
65713
|
+
continue;
|
|
65714
|
+
if (chainCtx.respondedAgents.has(targetId)) {
|
|
65715
|
+
log57.info("A2A skipping (already responded this round)", { targetName, roundId: chainCtx.roundId });
|
|
65716
|
+
continue;
|
|
65717
|
+
}
|
|
65718
|
+
const lastReply = channelCooldowns.get(targetId) ?? 0;
|
|
65719
|
+
if (now2 - lastReply < _APIServer.A2A_COOLDOWN_MS) {
|
|
65720
|
+
log57.info("A2A skipping (cooldown)", { targetName, channel, cooldownRemaining: _APIServer.A2A_COOLDOWN_MS - (now2 - lastReply) });
|
|
65721
|
+
continue;
|
|
65722
|
+
}
|
|
65723
|
+
channelCooldowns.set(targetId, now2);
|
|
65724
|
+
const a2aMessage = `[From @${fromAgentName}]: ${fromText}`;
|
|
65725
|
+
void this.processGroupChatReply(targetId, a2aMessage, fromAgentId, { name: fromAgentName, role: "agent" }, channel, orgId2, channelContext, agentManager, teamSize, {
|
|
65726
|
+
mentionedNames: [targetName],
|
|
65727
|
+
replyToAgentName: fromAgentName,
|
|
65728
|
+
replyToText: fromText.slice(0, 200),
|
|
65729
|
+
replyToMsgId: fromMsgId
|
|
65730
|
+
}, chainCtx);
|
|
65731
|
+
}
|
|
65732
|
+
}
|
|
65325
65733
|
/** Persist the user message first (before LLM), returns session id for subsequent assistant persistence.
|
|
65326
65734
|
* When sessionId is provided, appends to that session; when null/undefined, creates a new session. */
|
|
65327
65735
|
async persistUserMessage(agentId2, userMessage, senderId, images, sessionId) {
|
|
@@ -65577,7 +65985,7 @@ var init_api_server = __esm({
|
|
|
65577
65985
|
const avatarDir = join23(homedir14(), ".markus", "avatars");
|
|
65578
65986
|
mkdirSync19(avatarDir, { recursive: true });
|
|
65579
65987
|
const filename = `${targetType}_${targetId}.${ext}`;
|
|
65580
|
-
|
|
65988
|
+
writeFileSync17(join23(avatarDir, filename), buf);
|
|
65581
65989
|
const avatarUrl = `/api/avatars/${filename}`;
|
|
65582
65990
|
if (targetType === "user" && this.storage) {
|
|
65583
65991
|
this.storage.userRepo.updateAvatarUrl(targetId, avatarUrl);
|
|
@@ -65654,6 +66062,7 @@ var init_api_server = __esm({
|
|
|
65654
66062
|
const senderName = body["senderName"] ?? "You";
|
|
65655
66063
|
const mentions = body["mentions"] ?? [];
|
|
65656
66064
|
const targetAgentId = body["targetAgentId"];
|
|
66065
|
+
const replyToId = body["replyToId"];
|
|
65657
66066
|
const orgId2 = body["orgId"] ?? "default";
|
|
65658
66067
|
let userMsg;
|
|
65659
66068
|
if (this.storage) {
|
|
@@ -65664,7 +66073,8 @@ var init_api_server = __esm({
|
|
|
65664
66073
|
senderType: "human",
|
|
65665
66074
|
senderName,
|
|
65666
66075
|
text,
|
|
65667
|
-
mentions
|
|
66076
|
+
mentions,
|
|
66077
|
+
replyToId
|
|
65668
66078
|
});
|
|
65669
66079
|
}
|
|
65670
66080
|
const humanOnly = body["humanOnly"] === true;
|
|
@@ -65682,21 +66092,50 @@ var init_api_server = __esm({
|
|
|
65682
66092
|
return [];
|
|
65683
66093
|
}
|
|
65684
66094
|
};
|
|
65685
|
-
|
|
65686
|
-
|
|
65687
|
-
|
|
65688
|
-
|
|
66095
|
+
let replyToAgentName;
|
|
66096
|
+
let replyToText;
|
|
66097
|
+
if (replyToId && this.storage) {
|
|
66098
|
+
try {
|
|
66099
|
+
const original = this.storage.channelMessageRepo.getMessageById(replyToId);
|
|
66100
|
+
if (original) {
|
|
66101
|
+
replyToAgentName = original.senderName;
|
|
66102
|
+
replyToText = original.text.slice(0, 200);
|
|
66103
|
+
}
|
|
66104
|
+
} catch {
|
|
66105
|
+
}
|
|
66106
|
+
}
|
|
66107
|
+
const enrichedUserMsg = userMsg ? {
|
|
66108
|
+
...userMsg,
|
|
66109
|
+
...replyToAgentName ? { replyToSender: replyToAgentName, replyToText } : {}
|
|
66110
|
+
} : null;
|
|
66111
|
+
if (!isHumanChannel && channel.startsWith("group:")) {
|
|
66112
|
+
let allAgentIds;
|
|
66113
|
+
if (channel.startsWith("group:custom:")) {
|
|
66114
|
+
allAgentIds = this.storage?.groupChatRepo?.getAgentMemberIds(channel) ?? [];
|
|
66115
|
+
} else {
|
|
66116
|
+
const teamId = channel.replace(/^group:/, "");
|
|
66117
|
+
const team = this.orgService.getTeam(teamId);
|
|
66118
|
+
allAgentIds = team?.memberAgentIds ?? [];
|
|
66119
|
+
}
|
|
65689
66120
|
if (allAgentIds.length === 0) {
|
|
65690
|
-
this.json(res, 200, { userMessage:
|
|
66121
|
+
this.json(res, 200, { userMessage: enrichedUserMsg, agentMessage: null });
|
|
65691
66122
|
return;
|
|
65692
66123
|
}
|
|
65693
66124
|
const channelContext2 = await buildChannelContext();
|
|
65694
66125
|
const senderInfo2 = this.orgService.resolveHumanIdentity(senderId);
|
|
65695
66126
|
const agentManager = this.orgService.getAgentManager();
|
|
66127
|
+
const broadcastOpts = {
|
|
66128
|
+
mentionedNames: mentions.length > 0 ? mentions : void 0,
|
|
66129
|
+
replyToAgentName,
|
|
66130
|
+
replyToText
|
|
66131
|
+
};
|
|
66132
|
+
const roundId = `round_${Date.now()}`;
|
|
66133
|
+
const respondedAgents = /* @__PURE__ */ new Set();
|
|
66134
|
+
const chainCtx = { roundId, depth: 0, respondedAgents, allAgentIds };
|
|
65696
66135
|
for (const agentId2 of allAgentIds) {
|
|
65697
|
-
void this.processGroupChatReply(agentId2, text, senderId, senderInfo2, channel, orgId2, channelContext2, agentManager, allAgentIds.length);
|
|
66136
|
+
void this.processGroupChatReply(agentId2, text, senderId, senderInfo2, channel, orgId2, channelContext2, agentManager, allAgentIds.length, broadcastOpts, chainCtx);
|
|
65698
66137
|
}
|
|
65699
|
-
this.json(res, 200, { userMessage:
|
|
66138
|
+
this.json(res, 200, { userMessage: enrichedUserMsg, agentMessage: null });
|
|
65700
66139
|
return;
|
|
65701
66140
|
}
|
|
65702
66141
|
let routedAgentId = null;
|
|
@@ -65710,7 +66149,7 @@ var init_api_server = __esm({
|
|
|
65710
66149
|
}
|
|
65711
66150
|
}
|
|
65712
66151
|
if (!routedAgentId) {
|
|
65713
|
-
this.json(res, 200, { userMessage:
|
|
66152
|
+
this.json(res, 200, { userMessage: enrichedUserMsg, agentMessage: null });
|
|
65714
66153
|
return;
|
|
65715
66154
|
}
|
|
65716
66155
|
const agent = this.orgService.getAgentManager().getAgent(routedAgentId);
|
|
@@ -65753,7 +66192,7 @@ var init_api_server = __esm({
|
|
|
65753
66192
|
}
|
|
65754
66193
|
const statusCode = raw.includes("402") ? 402 : raw.includes("401") ? 401 : raw.includes("429") ? 429 : 502;
|
|
65755
66194
|
this.json(res, statusCode, {
|
|
65756
|
-
userMessage:
|
|
66195
|
+
userMessage: enrichedUserMsg,
|
|
65757
66196
|
agentMessage: errorMsg ?? null,
|
|
65758
66197
|
error: detail2
|
|
65759
66198
|
});
|
|
@@ -65780,7 +66219,7 @@ var init_api_server = __esm({
|
|
|
65780
66219
|
void this.persistChatTurn(routedAgentId, text, reply, senderId);
|
|
65781
66220
|
}
|
|
65782
66221
|
this.json(res, 200, {
|
|
65783
|
-
userMessage:
|
|
66222
|
+
userMessage: enrichedUserMsg,
|
|
65784
66223
|
agentMessage: agentMsg ?? {
|
|
65785
66224
|
id: `tmp_${Date.now()}`,
|
|
65786
66225
|
channel,
|
|
@@ -65980,7 +66419,7 @@ var init_api_server = __esm({
|
|
|
65980
66419
|
if (path === "/api/group-chats" && req.method === "GET") {
|
|
65981
66420
|
const orgId2 = url.searchParams.get("orgId") ?? "default";
|
|
65982
66421
|
const teams = this.orgService.listTeamsWithMembers(orgId2);
|
|
65983
|
-
const
|
|
66422
|
+
const teamChats = teams.map((t) => ({
|
|
65984
66423
|
id: `group:${t.id}`,
|
|
65985
66424
|
name: t.name,
|
|
65986
66425
|
type: "team",
|
|
@@ -65988,21 +66427,16 @@ var init_api_server = __esm({
|
|
|
65988
66427
|
memberCount: t.members.length,
|
|
65989
66428
|
channelKey: `group:${t.id}`
|
|
65990
66429
|
}));
|
|
65991
|
-
const customChats = this.
|
|
65992
|
-
|
|
65993
|
-
|
|
65994
|
-
|
|
65995
|
-
|
|
65996
|
-
|
|
65997
|
-
|
|
65998
|
-
|
|
65999
|
-
|
|
66000
|
-
|
|
66001
|
-
memberCount: c.memberIds?.length ?? 0,
|
|
66002
|
-
channelKey: c.id
|
|
66003
|
-
}))
|
|
66004
|
-
]
|
|
66005
|
-
});
|
|
66430
|
+
const customChats = this.storage?.groupChatRepo ? this.storage.groupChatRepo.list(orgId2).map((c) => ({
|
|
66431
|
+
id: c.id,
|
|
66432
|
+
name: c.name,
|
|
66433
|
+
type: "custom",
|
|
66434
|
+
creatorId: c.creatorId,
|
|
66435
|
+
creatorName: c.creatorName,
|
|
66436
|
+
memberCount: c.memberCount,
|
|
66437
|
+
channelKey: c.channelKey
|
|
66438
|
+
})) : [];
|
|
66439
|
+
this.json(res, 200, { chats: [...teamChats, ...customChats] });
|
|
66006
66440
|
return;
|
|
66007
66441
|
}
|
|
66008
66442
|
if (path === "/api/group-chats" && req.method === "POST") {
|
|
@@ -66012,31 +66446,129 @@ var init_api_server = __esm({
|
|
|
66012
66446
|
const creatorId = body["creatorId"];
|
|
66013
66447
|
const creatorName = body["creatorName"];
|
|
66014
66448
|
const memberIds = body["memberIds"];
|
|
66449
|
+
const memberTypes = body["memberTypes"];
|
|
66450
|
+
const memberNames = body["memberNames"];
|
|
66015
66451
|
if (!name) {
|
|
66016
66452
|
this.json(res, 400, { error: "name is required" });
|
|
66017
66453
|
return;
|
|
66018
66454
|
}
|
|
66019
|
-
|
|
66020
|
-
|
|
66021
|
-
|
|
66022
|
-
|
|
66023
|
-
|
|
66024
|
-
|
|
66025
|
-
|
|
66026
|
-
|
|
66027
|
-
|
|
66028
|
-
|
|
66029
|
-
|
|
66455
|
+
if (!this.storage?.groupChatRepo) {
|
|
66456
|
+
this.json(res, 500, { error: "Storage not initialized" });
|
|
66457
|
+
return;
|
|
66458
|
+
}
|
|
66459
|
+
const members = (memberIds ?? []).map((id) => {
|
|
66460
|
+
const mType = memberTypes?.[id] ?? "agent";
|
|
66461
|
+
let mName = memberNames?.[id] ?? id;
|
|
66462
|
+
if (mType === "agent") {
|
|
66463
|
+
try {
|
|
66464
|
+
mName = this.orgService.getAgentManager().getAgent(id)?.config?.name ?? mName;
|
|
66465
|
+
} catch {
|
|
66466
|
+
}
|
|
66467
|
+
}
|
|
66468
|
+
return { id, type: mType, name: mName };
|
|
66469
|
+
});
|
|
66470
|
+
const gc = this.storage.groupChatRepo.create({ orgId: orgId2, name, creatorId, creatorName, members });
|
|
66030
66471
|
this.ws?.broadcast({
|
|
66031
66472
|
type: "chat:group_created",
|
|
66032
|
-
payload: { chatId, name, creatorId, creatorName },
|
|
66473
|
+
payload: { chatId: gc.channelKey, name, creatorId, creatorName },
|
|
66033
66474
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
66034
66475
|
});
|
|
66035
66476
|
this.json(res, 201, {
|
|
66036
|
-
chat: {
|
|
66477
|
+
chat: {
|
|
66478
|
+
id: gc.id,
|
|
66479
|
+
name: gc.name,
|
|
66480
|
+
type: "custom",
|
|
66481
|
+
creatorId: gc.creatorId,
|
|
66482
|
+
creatorName: gc.creatorName,
|
|
66483
|
+
channelKey: gc.channelKey,
|
|
66484
|
+
memberCount: gc.members.length,
|
|
66485
|
+
members: gc.members.map((m) => ({ id: m.memberId, name: m.memberName, type: m.memberType }))
|
|
66486
|
+
}
|
|
66037
66487
|
});
|
|
66038
66488
|
return;
|
|
66039
66489
|
}
|
|
66490
|
+
if (path.match(/^\/api\/group-chats\/[^/]+$/) && req.method === "GET") {
|
|
66491
|
+
const gcId = path.split("/").pop();
|
|
66492
|
+
if (!this.storage?.groupChatRepo) {
|
|
66493
|
+
this.json(res, 500, { error: "Storage not initialized" });
|
|
66494
|
+
return;
|
|
66495
|
+
}
|
|
66496
|
+
const gc = this.storage.groupChatRepo.getById(gcId);
|
|
66497
|
+
if (!gc) {
|
|
66498
|
+
this.json(res, 404, { error: "Group chat not found" });
|
|
66499
|
+
return;
|
|
66500
|
+
}
|
|
66501
|
+
this.json(res, 200, {
|
|
66502
|
+
chat: {
|
|
66503
|
+
id: gc.id,
|
|
66504
|
+
name: gc.name,
|
|
66505
|
+
type: "custom",
|
|
66506
|
+
channelKey: gc.channelKey,
|
|
66507
|
+
creatorId: gc.creatorId,
|
|
66508
|
+
creatorName: gc.creatorName,
|
|
66509
|
+
members: gc.members.map((m) => ({ id: m.memberId, name: m.memberName, type: m.memberType }))
|
|
66510
|
+
}
|
|
66511
|
+
});
|
|
66512
|
+
return;
|
|
66513
|
+
}
|
|
66514
|
+
if (path.match(/^\/api\/group-chats\/[^/]+$/) && req.method === "PATCH") {
|
|
66515
|
+
const gcId = path.split("/").pop();
|
|
66516
|
+
if (!this.storage?.groupChatRepo) {
|
|
66517
|
+
this.json(res, 500, { error: "Storage not initialized" });
|
|
66518
|
+
return;
|
|
66519
|
+
}
|
|
66520
|
+
const body = await this.readBody(req);
|
|
66521
|
+
const newName = body["name"];
|
|
66522
|
+
if (newName)
|
|
66523
|
+
this.storage.groupChatRepo.updateName(gcId, newName);
|
|
66524
|
+
this.json(res, 200, { ok: true });
|
|
66525
|
+
return;
|
|
66526
|
+
}
|
|
66527
|
+
if (path.match(/^\/api\/group-chats\/[^/]+$/) && req.method === "DELETE") {
|
|
66528
|
+
const gcId = path.split("/").pop();
|
|
66529
|
+
if (!this.storage?.groupChatRepo) {
|
|
66530
|
+
this.json(res, 500, { error: "Storage not initialized" });
|
|
66531
|
+
return;
|
|
66532
|
+
}
|
|
66533
|
+
this.storage.groupChatRepo.delete(gcId);
|
|
66534
|
+
this.ws?.broadcast({ type: "chat:group_deleted", payload: { chatId: gcId }, timestamp: (/* @__PURE__ */ new Date()).toISOString() });
|
|
66535
|
+
this.json(res, 200, { ok: true });
|
|
66536
|
+
return;
|
|
66537
|
+
}
|
|
66538
|
+
if (path.match(/^\/api\/group-chats\/[^/]+\/members$/) && req.method === "POST") {
|
|
66539
|
+
const gcId = path.split("/")[3];
|
|
66540
|
+
if (!this.storage?.groupChatRepo) {
|
|
66541
|
+
this.json(res, 500, { error: "Storage not initialized" });
|
|
66542
|
+
return;
|
|
66543
|
+
}
|
|
66544
|
+
const body = await this.readBody(req);
|
|
66545
|
+
const memberId = body["memberId"];
|
|
66546
|
+
const memberType = body["memberType"] ?? "agent";
|
|
66547
|
+
let memberName = body["memberName"] ?? memberId;
|
|
66548
|
+
if (memberType === "agent") {
|
|
66549
|
+
try {
|
|
66550
|
+
memberName = this.orgService.getAgentManager().getAgent(memberId)?.config?.name ?? memberName;
|
|
66551
|
+
} catch {
|
|
66552
|
+
}
|
|
66553
|
+
}
|
|
66554
|
+
this.storage.groupChatRepo.addMember(gcId, memberId, memberType, memberName);
|
|
66555
|
+
this.ws?.broadcast({ type: "chat:group_updated", payload: { chatId: gcId }, timestamp: (/* @__PURE__ */ new Date()).toISOString() });
|
|
66556
|
+
this.json(res, 200, { ok: true });
|
|
66557
|
+
return;
|
|
66558
|
+
}
|
|
66559
|
+
if (path.match(/^\/api\/group-chats\/[^/]+\/members\/[^/]+$/) && req.method === "DELETE") {
|
|
66560
|
+
const parts = path.split("/");
|
|
66561
|
+
const gcId = parts[3];
|
|
66562
|
+
const memberId = parts[5];
|
|
66563
|
+
if (!this.storage?.groupChatRepo) {
|
|
66564
|
+
this.json(res, 500, { error: "Storage not initialized" });
|
|
66565
|
+
return;
|
|
66566
|
+
}
|
|
66567
|
+
this.storage.groupChatRepo.removeMember(gcId, memberId);
|
|
66568
|
+
this.ws?.broadcast({ type: "chat:group_updated", payload: { chatId: gcId }, timestamp: (/* @__PURE__ */ new Date()).toISOString() });
|
|
66569
|
+
this.json(res, 200, { ok: true });
|
|
66570
|
+
return;
|
|
66571
|
+
}
|
|
66040
66572
|
if (path === "/api/teams" && req.method === "GET") {
|
|
66041
66573
|
const orgId2 = url.searchParams.get("orgId") ?? "default";
|
|
66042
66574
|
const teams = this.orgService.listTeamsWithMembers(orgId2);
|
|
@@ -66271,7 +66803,7 @@ var init_api_server = __esm({
|
|
|
66271
66803
|
const content = body["content"];
|
|
66272
66804
|
const dir = this.orgService.getTeamDataDir(teamId);
|
|
66273
66805
|
mkdirSync19(dir, { recursive: true });
|
|
66274
|
-
|
|
66806
|
+
writeFileSync17(join23(dir, filename), content ?? "", "utf-8");
|
|
66275
66807
|
this.json(res, 200, { ok: true });
|
|
66276
66808
|
return;
|
|
66277
66809
|
}
|
|
@@ -67116,7 +67648,7 @@ var init_api_server = __esm({
|
|
|
67116
67648
|
}
|
|
67117
67649
|
const body = await this.readBody(req);
|
|
67118
67650
|
const content = body["content"] ?? "";
|
|
67119
|
-
|
|
67651
|
+
writeFileSync17(join23(roleDir, filename), content, "utf-8");
|
|
67120
67652
|
this.json(res, 200, { ok: true });
|
|
67121
67653
|
} catch {
|
|
67122
67654
|
this.json(res, 404, { error: `Agent not found: ${agentId2}` });
|
|
@@ -68455,7 +68987,7 @@ EXPLANATION_END`;
|
|
|
68455
68987
|
const mfName = manifestFilename(pkgType);
|
|
68456
68988
|
const artDir = join23(homedir14(), ".markus", "builder-artifacts", typeDir, manifest.name);
|
|
68457
68989
|
mkdirSync19(artDir, { recursive: true });
|
|
68458
|
-
|
|
68990
|
+
writeFileSync17(join23(artDir, mfName), JSON.stringify(manifest, null, 2), "utf-8");
|
|
68459
68991
|
const artFiles = artifact.files;
|
|
68460
68992
|
if (artFiles) {
|
|
68461
68993
|
for (const [fn, c] of Object.entries(artFiles)) {
|
|
@@ -68463,18 +68995,18 @@ EXPLANATION_END`;
|
|
|
68463
68995
|
continue;
|
|
68464
68996
|
const filePath = join23(artDir, fn);
|
|
68465
68997
|
mkdirSync19(dirname6(filePath), { recursive: true });
|
|
68466
|
-
|
|
68998
|
+
writeFileSync17(filePath, c, "utf-8");
|
|
68467
68999
|
}
|
|
68468
69000
|
}
|
|
68469
69001
|
if (mode === "team") {
|
|
68470
69002
|
const fileSet = new Set(artFiles ? Object.keys(artFiles) : []);
|
|
68471
69003
|
const announcement = artifact.announcement;
|
|
68472
69004
|
if (announcement && !fileSet.has("ANNOUNCEMENT.md")) {
|
|
68473
|
-
|
|
69005
|
+
writeFileSync17(join23(artDir, "ANNOUNCEMENT.md"), announcement, "utf-8");
|
|
68474
69006
|
}
|
|
68475
69007
|
const norms = artifact.norms;
|
|
68476
69008
|
if (norms && !fileSet.has("NORMS.md")) {
|
|
68477
|
-
|
|
69009
|
+
writeFileSync17(join23(artDir, "NORMS.md"), norms, "utf-8");
|
|
68478
69010
|
}
|
|
68479
69011
|
const rawMembers = Array.isArray(artifact.team?.members) ? artifact.team.members : Array.isArray(artifact.members) ? artifact.members : [];
|
|
68480
69012
|
for (const m of rawMembers) {
|
|
@@ -68486,15 +69018,15 @@ EXPLANATION_END`;
|
|
|
68486
69018
|
const contextContent = m.contextContent || m.context_md;
|
|
68487
69019
|
if (roleContent && !fileSet.has(`members/${slug}/ROLE.md`)) {
|
|
68488
69020
|
mkdirSync19(memberDir, { recursive: true });
|
|
68489
|
-
|
|
69021
|
+
writeFileSync17(join23(memberDir, "ROLE.md"), roleContent, "utf-8");
|
|
68490
69022
|
}
|
|
68491
69023
|
if (policiesContent && !fileSet.has(`members/${slug}/POLICIES.md`)) {
|
|
68492
69024
|
mkdirSync19(memberDir, { recursive: true });
|
|
68493
|
-
|
|
69025
|
+
writeFileSync17(join23(memberDir, "POLICIES.md"), policiesContent, "utf-8");
|
|
68494
69026
|
}
|
|
68495
69027
|
if (contextContent && !fileSet.has(`members/${slug}/CONTEXT.md`)) {
|
|
68496
69028
|
mkdirSync19(memberDir, { recursive: true });
|
|
68497
|
-
|
|
69029
|
+
writeFileSync17(join23(memberDir, "CONTEXT.md"), contextContent, "utf-8");
|
|
68498
69030
|
}
|
|
68499
69031
|
}
|
|
68500
69032
|
const memberFiles = artifact.memberFiles;
|
|
@@ -68503,7 +69035,7 @@ EXPLANATION_END`;
|
|
|
68503
69035
|
const memberDir = join23(artDir, "members", slug);
|
|
68504
69036
|
mkdirSync19(memberDir, { recursive: true });
|
|
68505
69037
|
for (const [fn, c] of Object.entries(files))
|
|
68506
|
-
|
|
69038
|
+
writeFileSync17(join23(memberDir, fn), c, "utf-8");
|
|
68507
69039
|
}
|
|
68508
69040
|
}
|
|
68509
69041
|
}
|
|
@@ -68541,7 +69073,7 @@ EXPLANATION_END`;
|
|
|
68541
69073
|
for (const [fn, content] of Object.entries(files)) {
|
|
68542
69074
|
const filePath = join23(artDir, fn);
|
|
68543
69075
|
mkdirSync19(dirname6(filePath), { recursive: true });
|
|
68544
|
-
|
|
69076
|
+
writeFileSync17(filePath, content, "utf-8");
|
|
68545
69077
|
}
|
|
68546
69078
|
if (source) {
|
|
68547
69079
|
const mfName = manifestFilename(type);
|
|
@@ -68550,7 +69082,7 @@ EXPLANATION_END`;
|
|
|
68550
69082
|
try {
|
|
68551
69083
|
const mf = JSON.parse(readFileSync21(mfPath, "utf-8"));
|
|
68552
69084
|
mf.source = source;
|
|
68553
|
-
|
|
69085
|
+
writeFileSync17(mfPath, JSON.stringify(mf, null, 2), "utf-8");
|
|
68554
69086
|
} catch {
|
|
68555
69087
|
}
|
|
68556
69088
|
}
|
|
@@ -69351,7 +69883,7 @@ EXPLANATION_END`;
|
|
|
69351
69883
|
try {
|
|
69352
69884
|
if (token) {
|
|
69353
69885
|
mkdirSync19(join23(homedir14(), ".markus"), { recursive: true });
|
|
69354
|
-
|
|
69886
|
+
writeFileSync17(tokenPath, token, "utf-8");
|
|
69355
69887
|
} else if (existsSync27(tokenPath)) {
|
|
69356
69888
|
rmSync3(tokenPath);
|
|
69357
69889
|
}
|
|
@@ -72643,11 +73175,13 @@ var init_requirement_service = __esm({
|
|
|
72643
73175
|
req.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
72644
73176
|
}
|
|
72645
73177
|
/**
|
|
72646
|
-
* Check if all tasks for a requirement are done.
|
|
73178
|
+
* Check if all tasks for a requirement are done. Instead of auto-completing,
|
|
73179
|
+
* notify the creator agent so they can review results and decide whether to
|
|
73180
|
+
* complete the requirement or create additional tasks.
|
|
72647
73181
|
*/
|
|
72648
73182
|
checkCompletion(requirementId2, taskStatuses) {
|
|
72649
73183
|
const req = this.requirements.get(requirementId2);
|
|
72650
|
-
if (!req || req.status === "completed")
|
|
73184
|
+
if (!req || req.status === "completed" || req.status === "cancelled")
|
|
72651
73185
|
return false;
|
|
72652
73186
|
if (req.taskIds.length === 0)
|
|
72653
73187
|
return false;
|
|
@@ -72655,14 +73189,28 @@ var init_requirement_service = __esm({
|
|
|
72655
73189
|
const status = taskStatuses.get(tid);
|
|
72656
73190
|
return status === "completed" || status === "cancelled" || status === "archived";
|
|
72657
73191
|
});
|
|
72658
|
-
if (allDone) {
|
|
72659
|
-
|
|
72660
|
-
|
|
72661
|
-
|
|
72662
|
-
|
|
73192
|
+
if (allDone && req.createdBy && this.agentManager) {
|
|
73193
|
+
try {
|
|
73194
|
+
const agent = this.agentManager.getAgent(req.createdBy);
|
|
73195
|
+
if (agent) {
|
|
73196
|
+
agent.enqueueToMailbox("requirement_update", {
|
|
73197
|
+
summary: `All tasks for requirement "${req.title}" are done \u2014 review needed`,
|
|
73198
|
+
content: [
|
|
73199
|
+
`[REQUIREMENT REVIEW NEEDED] All linked tasks for "${req.title}" (ID: ${requirementId2}) have reached terminal state.`,
|
|
73200
|
+
"",
|
|
73201
|
+
"Please review the results and decide:",
|
|
73202
|
+
`1. If the requirement is fully satisfied, complete it: requirement_update_status(requirement_id="${requirementId2}", status="completed")`,
|
|
73203
|
+
`2. If more work is needed, create additional tasks with task_create(requirement_id="${requirementId2}", ...)`
|
|
73204
|
+
].join("\n"),
|
|
73205
|
+
requirementId: requirementId2,
|
|
73206
|
+
extra: { actionRequired: true }
|
|
73207
|
+
}, {
|
|
73208
|
+
priority: 2,
|
|
73209
|
+
metadata: { senderName: "System", senderRole: "manager" }
|
|
73210
|
+
});
|
|
73211
|
+
}
|
|
73212
|
+
} catch {
|
|
72663
73213
|
}
|
|
72664
|
-
this.broadcast("requirement:completed", req);
|
|
72665
|
-
log62.info("Requirement completed", { id: requirementId2 });
|
|
72666
73214
|
return true;
|
|
72667
73215
|
}
|
|
72668
73216
|
return false;
|
|
@@ -72806,14 +73354,13 @@ var init_requirement_service = __esm({
|
|
|
72806
73354
|
parts.push("2. Abandon this requirement if the feedback indicates it is not needed");
|
|
72807
73355
|
}
|
|
72808
73356
|
const agent = this.agentManager.getAgent(creatorId);
|
|
72809
|
-
const isRejection = decision === "rejected";
|
|
72810
73357
|
agent.enqueueToMailbox("requirement_update", {
|
|
72811
73358
|
summary: `Requirement "${req.title}" ${decision}`,
|
|
72812
73359
|
content: parts.join("\n"),
|
|
72813
73360
|
requirementId: req.id,
|
|
72814
|
-
extra:
|
|
73361
|
+
extra: { actionRequired: true }
|
|
72815
73362
|
}, {
|
|
72816
|
-
priority:
|
|
73363
|
+
priority: 1,
|
|
72817
73364
|
metadata: { senderName: "System", senderRole: "manager" }
|
|
72818
73365
|
});
|
|
72819
73366
|
log62.info("Notified creator agent about requirement decision", {
|
|
@@ -73031,7 +73578,7 @@ var init_knowledge_service = __esm({
|
|
|
73031
73578
|
});
|
|
73032
73579
|
|
|
73033
73580
|
// ../org-manager/dist/file-knowledge-store.js
|
|
73034
|
-
import { readFileSync as readFileSync22, writeFileSync as
|
|
73581
|
+
import { readFileSync as readFileSync22, writeFileSync as writeFileSync18, existsSync as existsSync28, mkdirSync as mkdirSync20, readdirSync as readdirSync11, unlinkSync as unlinkSync3 } from "node:fs";
|
|
73035
73582
|
import { join as join24 } from "node:path";
|
|
73036
73583
|
function readdirSafe(dir) {
|
|
73037
73584
|
try {
|
|
@@ -73087,12 +73634,12 @@ var init_file_knowledge_store = __esm({
|
|
|
73087
73634
|
saveEntry(entry) {
|
|
73088
73635
|
const dir = this.scopeDir(entry.scope, entry.scopeId);
|
|
73089
73636
|
mkdirSync20(dir, { recursive: true });
|
|
73090
|
-
|
|
73637
|
+
writeFileSync18(join24(dir, `${entry.id}.json`), JSON.stringify(entry, null, 2));
|
|
73091
73638
|
}
|
|
73092
73639
|
saveIndex(scope, scopeId, entries2) {
|
|
73093
73640
|
const dir = this.scopeDir(scope, scopeId);
|
|
73094
73641
|
mkdirSync20(dir, { recursive: true });
|
|
73095
|
-
|
|
73642
|
+
writeFileSync18(join24(dir, "_index.json"), JSON.stringify(entries2, null, 2));
|
|
73096
73643
|
}
|
|
73097
73644
|
removeEntryFile(entry) {
|
|
73098
73645
|
const p = join24(this.scopeDir(entry.scope, entry.scopeId), `${entry.id}.json`);
|
|
@@ -74130,7 +74677,8 @@ function openSqlite(dbPath) {
|
|
|
74130
74677
|
{ table: "chat_sessions", column: "is_main", sql: "ALTER TABLE chat_sessions ADD COLUMN is_main INTEGER NOT NULL DEFAULT 0" },
|
|
74131
74678
|
{ table: "mailbox_items", column: "retry_count", sql: "ALTER TABLE mailbox_items ADD COLUMN retry_count INTEGER NOT NULL DEFAULT 0" },
|
|
74132
74679
|
{ table: "users", column: "avatar_url", sql: "ALTER TABLE users ADD COLUMN avatar_url TEXT" },
|
|
74133
|
-
{ table: "agents", column: "avatar_url", sql: "ALTER TABLE agents ADD COLUMN avatar_url TEXT" }
|
|
74680
|
+
{ table: "agents", column: "avatar_url", sql: "ALTER TABLE agents ADD COLUMN avatar_url TEXT" },
|
|
74681
|
+
{ table: "channel_messages", column: "reply_to_id", sql: "ALTER TABLE channel_messages ADD COLUMN reply_to_id TEXT" }
|
|
74134
74682
|
];
|
|
74135
74683
|
for (const m of migrations) {
|
|
74136
74684
|
const cols = _db.prepare(`PRAGMA table_info(${m.table})`).all();
|
|
@@ -74187,7 +74735,7 @@ function migrateToExecutionStreamLogs(db) {
|
|
|
74187
74735
|
log71.info(`Migration: copied ${actLogCount} agent_activity_logs to execution_stream_logs`);
|
|
74188
74736
|
}
|
|
74189
74737
|
}
|
|
74190
|
-
var log71, SCHEMA_SQL, _db, SqliteOrgRepo, SqliteAgentRepo, SqliteTaskRepo, SqliteRequirementRepo, SqliteProjectRepo, SqliteTaskLogRepo, SqliteTaskCommentRepo, SqliteRequirementCommentRepo, SqliteMessageRepo, SqliteChatSessionRepo, SqliteChannelMessageRepo, SqliteUserRepo, SqliteTeamRepo, SqliteMarketplaceTemplateRepo, SqliteMarketplaceSkillRepo, SqliteMarketplaceRatingRepo, SqliteAgentKnowledgeRepo, SqliteExternalAgentRepo, SqliteDeliverableRepo, SqliteActivityRepo, SqliteExecutionStreamRepo, SqliteMailboxRepo, SqliteDecisionRepo, SqliteNotificationRepo, SqliteApprovalRepo;
|
|
74738
|
+
var log71, SCHEMA_SQL, _db, SqliteOrgRepo, SqliteAgentRepo, SqliteTaskRepo, SqliteRequirementRepo, SqliteProjectRepo, SqliteTaskLogRepo, SqliteTaskCommentRepo, SqliteRequirementCommentRepo, SqliteMessageRepo, SqliteChatSessionRepo, SqliteChannelMessageRepo, SqliteUserRepo, SqliteTeamRepo, SqliteMarketplaceTemplateRepo, SqliteMarketplaceSkillRepo, SqliteMarketplaceRatingRepo, SqliteAgentKnowledgeRepo, SqliteExternalAgentRepo, SqliteDeliverableRepo, SqliteActivityRepo, SqliteExecutionStreamRepo, SqliteMailboxRepo, SqliteDecisionRepo, SqliteNotificationRepo, SqliteApprovalRepo, SqliteGroupChatRepo;
|
|
74191
74739
|
var init_sqlite_storage = __esm({
|
|
74192
74740
|
"../storage/dist/sqlite-storage.js"() {
|
|
74193
74741
|
"use strict";
|
|
@@ -74325,6 +74873,7 @@ CREATE TABLE IF NOT EXISTS channel_messages (
|
|
|
74325
74873
|
text TEXT NOT NULL,
|
|
74326
74874
|
mentions TEXT NOT NULL DEFAULT '[]',
|
|
74327
74875
|
metadata TEXT DEFAULT '{}',
|
|
74876
|
+
reply_to_id TEXT,
|
|
74328
74877
|
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
74329
74878
|
);
|
|
74330
74879
|
CREATE INDEX IF NOT EXISTS idx_channel_messages_channel ON channel_messages(channel, created_at);
|
|
@@ -74685,6 +75234,26 @@ CREATE TABLE IF NOT EXISTS approvals (
|
|
|
74685
75234
|
selected_option TEXT
|
|
74686
75235
|
);
|
|
74687
75236
|
CREATE INDEX IF NOT EXISTS idx_approvals_status ON approvals(status, requested_at DESC);
|
|
75237
|
+
|
|
75238
|
+
CREATE TABLE IF NOT EXISTS group_chats (
|
|
75239
|
+
id TEXT PRIMARY KEY,
|
|
75240
|
+
org_id TEXT NOT NULL DEFAULT 'default',
|
|
75241
|
+
name TEXT NOT NULL,
|
|
75242
|
+
channel_key TEXT NOT NULL UNIQUE,
|
|
75243
|
+
creator_id TEXT NOT NULL,
|
|
75244
|
+
creator_name TEXT NOT NULL,
|
|
75245
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
75246
|
+
);
|
|
75247
|
+
|
|
75248
|
+
CREATE TABLE IF NOT EXISTS group_chat_members (
|
|
75249
|
+
group_chat_id TEXT NOT NULL REFERENCES group_chats(id) ON DELETE CASCADE,
|
|
75250
|
+
member_id TEXT NOT NULL,
|
|
75251
|
+
member_type TEXT NOT NULL CHECK(member_type IN ('human', 'agent')),
|
|
75252
|
+
member_name TEXT NOT NULL,
|
|
75253
|
+
added_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
75254
|
+
PRIMARY KEY (group_chat_id, member_id)
|
|
75255
|
+
);
|
|
75256
|
+
CREATE INDEX IF NOT EXISTS idx_group_chat_members_group ON group_chat_members(group_chat_id);
|
|
74688
75257
|
`;
|
|
74689
75258
|
_db = null;
|
|
74690
75259
|
SqliteOrgRepo = class {
|
|
@@ -75553,7 +76122,7 @@ CREATE INDEX IF NOT EXISTS idx_approvals_status ON approvals(status, requested_a
|
|
|
75553
76122
|
async append(data) {
|
|
75554
76123
|
const id = generateId2("chm");
|
|
75555
76124
|
const ts = now();
|
|
75556
|
-
this.db.prepare("INSERT INTO channel_messages (id, org_id, channel, sender_id, sender_type, sender_name, text, mentions, metadata, created_at) VALUES (
|
|
76125
|
+
this.db.prepare("INSERT INTO channel_messages (id, org_id, channel, sender_id, sender_type, sender_name, text, mentions, metadata, reply_to_id, created_at) VALUES (?,?,?,?,?,?,?,?,?,?,?)").run(id, data.orgId, data.channel, data.senderId, data.senderType, data.senderName, data.text, toJson(data.mentions ?? []), toJson(data.metadata ?? {}), data.replyToId ?? null, ts);
|
|
75557
76126
|
return {
|
|
75558
76127
|
id,
|
|
75559
76128
|
orgId: data.orgId,
|
|
@@ -75564,17 +76133,20 @@ CREATE INDEX IF NOT EXISTS idx_approvals_status ON approvals(status, requested_a
|
|
|
75564
76133
|
text: data.text,
|
|
75565
76134
|
mentions: data.mentions ?? [],
|
|
75566
76135
|
metadata: data.metadata ?? null,
|
|
76136
|
+
replyToId: data.replyToId,
|
|
75567
76137
|
createdAt: new Date(ts)
|
|
75568
76138
|
};
|
|
75569
76139
|
}
|
|
75570
76140
|
getMessages(channel, limit = 50, before2) {
|
|
75571
|
-
let q =
|
|
76141
|
+
let q = `SELECT m.*, r.sender_name AS reply_to_sender, SUBSTR(r.text, 1, 120) AS reply_to_text
|
|
76142
|
+
FROM channel_messages m LEFT JOIN channel_messages r ON m.reply_to_id = r.id
|
|
76143
|
+
WHERE m.channel = ?`;
|
|
75572
76144
|
const vals = [channel];
|
|
75573
76145
|
if (before2) {
|
|
75574
|
-
q += " AND created_at < ?";
|
|
76146
|
+
q += " AND m.created_at < ?";
|
|
75575
76147
|
vals.push(before2);
|
|
75576
76148
|
}
|
|
75577
|
-
q += " ORDER BY created_at DESC LIMIT ?";
|
|
76149
|
+
q += " ORDER BY m.created_at DESC LIMIT ?";
|
|
75578
76150
|
vals.push(limit + 1);
|
|
75579
76151
|
const rows = this.db.prepare(q).all(...vals).map((r) => ({
|
|
75580
76152
|
id: r["id"],
|
|
@@ -75586,11 +76158,26 @@ CREATE INDEX IF NOT EXISTS idx_approvals_status ON approvals(status, requested_a
|
|
|
75586
76158
|
text: r["text"],
|
|
75587
76159
|
mentions: fromJson(r["mentions"]),
|
|
75588
76160
|
metadata: fromJson(r["metadata"]),
|
|
76161
|
+
replyToId: r["reply_to_id"] ?? void 0,
|
|
76162
|
+
replyToSender: r["reply_to_sender"] ?? void 0,
|
|
76163
|
+
replyToText: r["reply_to_text"] ?? void 0,
|
|
75589
76164
|
createdAt: toDate(r["created_at"])
|
|
75590
76165
|
}));
|
|
75591
76166
|
const hasMore = rows.length > limit;
|
|
75592
76167
|
return { messages: rows.slice(0, limit).reverse(), hasMore };
|
|
75593
76168
|
}
|
|
76169
|
+
getMessageById(id) {
|
|
76170
|
+
const r = this.db.prepare("SELECT * FROM channel_messages WHERE id = ?").get(id);
|
|
76171
|
+
if (!r)
|
|
76172
|
+
return void 0;
|
|
76173
|
+
return {
|
|
76174
|
+
id: r["id"],
|
|
76175
|
+
senderName: r["sender_name"],
|
|
76176
|
+
senderType: r["sender_type"],
|
|
76177
|
+
senderId: r["sender_id"],
|
|
76178
|
+
text: r["text"]
|
|
76179
|
+
};
|
|
76180
|
+
}
|
|
75594
76181
|
};
|
|
75595
76182
|
SqliteUserRepo = class {
|
|
75596
76183
|
db;
|
|
@@ -76708,6 +77295,96 @@ CREATE INDEX IF NOT EXISTS idx_approvals_status ON approvals(status, requested_a
|
|
|
76708
77295
|
};
|
|
76709
77296
|
}
|
|
76710
77297
|
};
|
|
77298
|
+
SqliteGroupChatRepo = class {
|
|
77299
|
+
db;
|
|
77300
|
+
constructor(db) {
|
|
77301
|
+
this.db = db;
|
|
77302
|
+
}
|
|
77303
|
+
create(data) {
|
|
77304
|
+
const id = generateId2("gc");
|
|
77305
|
+
const channelKey = `group:custom:${id}`;
|
|
77306
|
+
const ts = now();
|
|
77307
|
+
this.db.prepare("INSERT INTO group_chats (id, org_id, name, channel_key, creator_id, creator_name, created_at) VALUES (?,?,?,?,?,?,?)").run(id, data.orgId, data.name, channelKey, data.creatorId, data.creatorName, ts);
|
|
77308
|
+
const insertMember = this.db.prepare("INSERT OR IGNORE INTO group_chat_members (group_chat_id, member_id, member_type, member_name, added_at) VALUES (?,?,?,?,?)");
|
|
77309
|
+
const members = [];
|
|
77310
|
+
for (const m of data.members) {
|
|
77311
|
+
insertMember.run(id, m.id, m.type, m.name, ts);
|
|
77312
|
+
members.push({ groupChatId: id, memberId: m.id, memberType: m.type, memberName: m.name, addedAt: new Date(ts) });
|
|
77313
|
+
}
|
|
77314
|
+
return {
|
|
77315
|
+
id,
|
|
77316
|
+
orgId: data.orgId,
|
|
77317
|
+
name: data.name,
|
|
77318
|
+
channelKey,
|
|
77319
|
+
creatorId: data.creatorId,
|
|
77320
|
+
creatorName: data.creatorName,
|
|
77321
|
+
createdAt: new Date(ts),
|
|
77322
|
+
members
|
|
77323
|
+
};
|
|
77324
|
+
}
|
|
77325
|
+
list(orgId2) {
|
|
77326
|
+
const rows = this.db.prepare(`SELECT g.*, (SELECT COUNT(*) FROM group_chat_members WHERE group_chat_id = g.id) AS member_count
|
|
77327
|
+
FROM group_chats g WHERE g.org_id = ? ORDER BY g.created_at DESC`).all(orgId2);
|
|
77328
|
+
return rows.map((r) => ({
|
|
77329
|
+
...this.mapRow(r),
|
|
77330
|
+
memberCount: r["member_count"]
|
|
77331
|
+
}));
|
|
77332
|
+
}
|
|
77333
|
+
getById(id) {
|
|
77334
|
+
const r = this.db.prepare("SELECT * FROM group_chats WHERE id = ?").get(id);
|
|
77335
|
+
if (!r)
|
|
77336
|
+
return void 0;
|
|
77337
|
+
const members = this.getMembers(id);
|
|
77338
|
+
return { ...this.mapRow(r), members };
|
|
77339
|
+
}
|
|
77340
|
+
getByChannelKey(channelKey) {
|
|
77341
|
+
const r = this.db.prepare("SELECT * FROM group_chats WHERE channel_key = ?").get(channelKey);
|
|
77342
|
+
if (!r)
|
|
77343
|
+
return void 0;
|
|
77344
|
+
const gc = this.mapRow(r);
|
|
77345
|
+
return { ...gc, members: this.getMembers(gc.id) };
|
|
77346
|
+
}
|
|
77347
|
+
getMembers(groupChatId) {
|
|
77348
|
+
const rows = this.db.prepare("SELECT * FROM group_chat_members WHERE group_chat_id = ?").all(groupChatId);
|
|
77349
|
+
return rows.map((r) => ({
|
|
77350
|
+
groupChatId: r["group_chat_id"],
|
|
77351
|
+
memberId: r["member_id"],
|
|
77352
|
+
memberType: r["member_type"],
|
|
77353
|
+
memberName: r["member_name"],
|
|
77354
|
+
addedAt: toDate(r["added_at"])
|
|
77355
|
+
}));
|
|
77356
|
+
}
|
|
77357
|
+
getAgentMemberIds(channelKey) {
|
|
77358
|
+
const gc = this.db.prepare("SELECT id FROM group_chats WHERE channel_key = ?").get(channelKey);
|
|
77359
|
+
if (!gc)
|
|
77360
|
+
return [];
|
|
77361
|
+
const rows = this.db.prepare("SELECT member_id FROM group_chat_members WHERE group_chat_id = ? AND member_type = 'agent'").all(gc.id);
|
|
77362
|
+
return rows.map((r) => r.member_id);
|
|
77363
|
+
}
|
|
77364
|
+
addMember(groupChatId, memberId, memberType, memberName) {
|
|
77365
|
+
this.db.prepare("INSERT OR IGNORE INTO group_chat_members (group_chat_id, member_id, member_type, member_name, added_at) VALUES (?,?,?,?,?)").run(groupChatId, memberId, memberType, memberName, now());
|
|
77366
|
+
}
|
|
77367
|
+
removeMember(groupChatId, memberId) {
|
|
77368
|
+
this.db.prepare("DELETE FROM group_chat_members WHERE group_chat_id = ? AND member_id = ?").run(groupChatId, memberId);
|
|
77369
|
+
}
|
|
77370
|
+
updateName(id, name) {
|
|
77371
|
+
this.db.prepare("UPDATE group_chats SET name = ? WHERE id = ?").run(name, id);
|
|
77372
|
+
}
|
|
77373
|
+
delete(id) {
|
|
77374
|
+
this.db.prepare("DELETE FROM group_chats WHERE id = ?").run(id);
|
|
77375
|
+
}
|
|
77376
|
+
mapRow(r) {
|
|
77377
|
+
return {
|
|
77378
|
+
id: r["id"],
|
|
77379
|
+
orgId: r["org_id"],
|
|
77380
|
+
name: r["name"],
|
|
77381
|
+
channelKey: r["channel_key"],
|
|
77382
|
+
creatorId: r["creator_id"],
|
|
77383
|
+
creatorName: r["creator_name"],
|
|
77384
|
+
createdAt: toDate(r["created_at"])
|
|
77385
|
+
};
|
|
77386
|
+
}
|
|
77387
|
+
};
|
|
76711
77388
|
}
|
|
76712
77389
|
});
|
|
76713
77390
|
|
|
@@ -76724,6 +77401,7 @@ __export(dist_exports3, {
|
|
|
76724
77401
|
SqliteDeliverableRepo: () => SqliteDeliverableRepo,
|
|
76725
77402
|
SqliteExecutionStreamRepo: () => SqliteExecutionStreamRepo,
|
|
76726
77403
|
SqliteExternalAgentRepo: () => SqliteExternalAgentRepo,
|
|
77404
|
+
SqliteGroupChatRepo: () => SqliteGroupChatRepo,
|
|
76727
77405
|
SqliteMailboxRepo: () => SqliteMailboxRepo,
|
|
76728
77406
|
SqliteMarketplaceRatingRepo: () => SqliteMarketplaceRatingRepo,
|
|
76729
77407
|
SqliteMarketplaceSkillRepo: () => SqliteMarketplaceSkillRepo,
|
|
@@ -76793,7 +77471,8 @@ async function initSqliteStorage(url) {
|
|
|
76793
77471
|
mailboxRepo: new storage.SqliteMailboxRepo(db),
|
|
76794
77472
|
decisionRepo: new storage.SqliteDecisionRepo(db),
|
|
76795
77473
|
notificationRepo: new storage.SqliteNotificationRepo(db),
|
|
76796
|
-
approvalRepo: new storage.SqliteApprovalRepo(db)
|
|
77474
|
+
approvalRepo: new storage.SqliteApprovalRepo(db),
|
|
77475
|
+
groupChatRepo: new storage.SqliteGroupChatRepo(db)
|
|
76797
77476
|
};
|
|
76798
77477
|
log72.info("SQLite storage initialized", { path: dbPath });
|
|
76799
77478
|
return bridge;
|
|
@@ -77885,7 +78564,7 @@ var init_startupProgress = __esm({
|
|
|
77885
78564
|
|
|
77886
78565
|
// src/connector-service.ts
|
|
77887
78566
|
import { resolve as resolve15, join as join28, dirname as dirname8 } from "node:path";
|
|
77888
|
-
import { existsSync as existsSync31, readFileSync as readFileSync23, writeFileSync as
|
|
78567
|
+
import { existsSync as existsSync31, readFileSync as readFileSync23, writeFileSync as writeFileSync19, mkdirSync as mkdirSync24, readdirSync as readdirSync12, cpSync as cpSync3 } from "node:fs";
|
|
77889
78568
|
import { homedir as homedir18 } from "node:os";
|
|
77890
78569
|
import { execSync as execSync4 } from "node:child_process";
|
|
77891
78570
|
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
@@ -77986,7 +78665,7 @@ function writePlatformConfig(connector, markusUrl, token) {
|
|
|
77986
78665
|
setNestedField(config, connector.integration.tokenField, token);
|
|
77987
78666
|
try {
|
|
77988
78667
|
const content = JSON.stringify(config, null, 2);
|
|
77989
|
-
|
|
78668
|
+
writeFileSync19(configPath, content, "utf-8");
|
|
77990
78669
|
return true;
|
|
77991
78670
|
} catch {
|
|
77992
78671
|
return false;
|
|
@@ -78082,7 +78761,7 @@ function registerInitCommand(program2) {
|
|
|
78082
78761
|
});
|
|
78083
78762
|
}
|
|
78084
78763
|
async function quickInit(options) {
|
|
78085
|
-
const { writeFileSync:
|
|
78764
|
+
const { writeFileSync: writeFileSync21, mkdirSync: mkdirSync26 } = await import("node:fs");
|
|
78086
78765
|
const { join: pathJoin } = await import("node:path");
|
|
78087
78766
|
const readline4 = await import("node:readline");
|
|
78088
78767
|
const nonInteractive = options?.nonInteractive ?? false;
|
|
@@ -78361,7 +79040,7 @@ async function quickInit(options) {
|
|
|
78361
79040
|
const devRoleDir = pathJoin(userTemplatesDir || pathJoin(process.cwd(), "templates"), "roles", "developer");
|
|
78362
79041
|
if (!existsSync32(devRoleDir)) {
|
|
78363
79042
|
mkdirSync26(devRoleDir, { recursive: true });
|
|
78364
|
-
|
|
79043
|
+
writeFileSync21(
|
|
78365
79044
|
pathJoin(devRoleDir, "ROLE.md"),
|
|
78366
79045
|
[
|
|
78367
79046
|
"---",
|
|
@@ -79269,6 +79948,19 @@ ${reason}`;
|
|
|
79269
79948
|
}, triageProvider);
|
|
79270
79949
|
return response.content;
|
|
79271
79950
|
});
|
|
79951
|
+
agent.getAttentionController().setLLMJudge(async (prompt) => {
|
|
79952
|
+
const response = await llmRouter.chat({
|
|
79953
|
+
messages: [
|
|
79954
|
+
{ role: "system", content: 'You are an attention interrupt judge. Decide whether to interrupt current work for a new incoming message. Reply with ONLY one word: continue, preempt, cancel, merge, or defer. Use "preempt" to pause (resume later) and "cancel" to permanently stop current work.' },
|
|
79955
|
+
{ role: "user", content: prompt }
|
|
79956
|
+
],
|
|
79957
|
+
temperature: 0.1,
|
|
79958
|
+
maxTokens: 32
|
|
79959
|
+
}, triageProvider);
|
|
79960
|
+
const raw = response.content.trim().toLowerCase();
|
|
79961
|
+
const valid = ["continue", "preempt", "cancel", "merge", "defer"];
|
|
79962
|
+
return valid.includes(raw) ? raw : "continue";
|
|
79963
|
+
});
|
|
79272
79964
|
agent.getAttentionController().setTriageChatFn(async (messages, tools) => {
|
|
79273
79965
|
const llmTools = tools?.map((t) => ({
|
|
79274
79966
|
name: t.name,
|
|
@@ -80295,6 +80987,12 @@ ${C3.BOLD}${C3.CYAN}\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
|
80295
80987
|
checkWarn("Skills directory not found", `${skillsDir} \u2014 run: markus skill install <name>`);
|
|
80296
80988
|
}
|
|
80297
80989
|
section("Network");
|
|
80990
|
+
const proxyUrl = process.env["HTTPS_PROXY"] || process.env["HTTP_PROXY"] || process.env["https_proxy"] || process.env["http_proxy"];
|
|
80991
|
+
if (proxyUrl) {
|
|
80992
|
+
checkOk("HTTP proxy configured", proxyUrl);
|
|
80993
|
+
} else {
|
|
80994
|
+
checkWarn("HTTP proxy", "not configured \u2014 if behind firewall, set HTTPS_PROXY env var");
|
|
80995
|
+
}
|
|
80298
80996
|
try {
|
|
80299
80997
|
const res = await fetch("https://api.anthropic.com/.well-known/ready", {
|
|
80300
80998
|
method: "HEAD",
|
|
@@ -82976,7 +83674,7 @@ var skill_exports = {};
|
|
|
82976
83674
|
__export(skill_exports, {
|
|
82977
83675
|
registerSkillCommands: () => registerSkillCommands
|
|
82978
83676
|
});
|
|
82979
|
-
import { writeFileSync as
|
|
83677
|
+
import { writeFileSync as writeFileSync20, mkdirSync as mkdirSync25 } from "node:fs";
|
|
82980
83678
|
import { resolve as resolve18 } from "node:path";
|
|
82981
83679
|
function registerSkillCommands(program2) {
|
|
82982
83680
|
const root = program2.command("skill").description("Skills registry and local scaffold");
|
|
@@ -83084,8 +83782,8 @@ Describe what this skill does for agents.
|
|
|
83084
83782
|
## Tools / behavior
|
|
83085
83783
|
|
|
83086
83784
|
`;
|
|
83087
|
-
|
|
83088
|
-
|
|
83785
|
+
writeFileSync20(resolve18(dir, "skill.json"), JSON.stringify(skillJson, null, 2) + "\n");
|
|
83786
|
+
writeFileSync20(resolve18(dir, "SKILL.md"), skillMd);
|
|
83089
83787
|
if (out.json) {
|
|
83090
83788
|
console.log(JSON.stringify({ dir, files: ["skill.json", "SKILL.md"] }, null, 2));
|
|
83091
83789
|
} else {
|