@markus-global/cli 0.7.14 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/start.d.ts.map +1 -1
- package/dist/commands/start.js +34 -5
- package/dist/commands/start.js.map +1 -1
- package/dist/markus.mjs +1468 -449
- package/dist/web-ui/assets/{browser-CfOM0wgq.js → browser-B9TjqCIp.js} +1 -1
- package/dist/web-ui/assets/index-C4k3rmLZ.js +711 -0
- package/dist/web-ui/assets/index-DNRsw-vh.css +1 -0
- package/dist/web-ui/index.html +2 -2
- package/package.json +1 -1
- package/dist/web-ui/assets/index-C5W6KtWx.js +0 -709
- package/dist/web-ui/assets/index-dhoLUZDf.css +0 -1
package/dist/markus.mjs
CHANGED
|
@@ -3791,6 +3791,34 @@ var init_model_catalog = __esm({
|
|
|
3791
3791
|
}
|
|
3792
3792
|
});
|
|
3793
3793
|
|
|
3794
|
+
// ../shared/dist/types/license.js
|
|
3795
|
+
var PLAN_LIMITS, ENTERPRISE_FEATURES;
|
|
3796
|
+
var init_license = __esm({
|
|
3797
|
+
"../shared/dist/types/license.js"() {
|
|
3798
|
+
"use strict";
|
|
3799
|
+
PLAN_LIMITS = {
|
|
3800
|
+
free: {
|
|
3801
|
+
maxTeams: 1,
|
|
3802
|
+
maxToolCallsPerDay: 500,
|
|
3803
|
+
maxUsers: 1
|
|
3804
|
+
},
|
|
3805
|
+
enterprise: {
|
|
3806
|
+
maxTeams: -1,
|
|
3807
|
+
maxToolCallsPerDay: -1,
|
|
3808
|
+
maxUsers: -1
|
|
3809
|
+
}
|
|
3810
|
+
};
|
|
3811
|
+
ENTERPRISE_FEATURES = [
|
|
3812
|
+
"multi_user",
|
|
3813
|
+
"unlimited_teams",
|
|
3814
|
+
"unlimited_tools",
|
|
3815
|
+
"sso",
|
|
3816
|
+
"audit_enhanced",
|
|
3817
|
+
"multi_instance"
|
|
3818
|
+
];
|
|
3819
|
+
}
|
|
3820
|
+
});
|
|
3821
|
+
|
|
3794
3822
|
// ../shared/dist/utils/config.js
|
|
3795
3823
|
import { readFileSync, writeFileSync, mkdirSync, existsSync } from "node:fs";
|
|
3796
3824
|
import { resolve, join } from "node:path";
|
|
@@ -4515,6 +4543,7 @@ __export(dist_exports, {
|
|
|
4515
4543
|
CognitiveDepth: () => CognitiveDepth,
|
|
4516
4544
|
DELIBERATION_ALLOWED_TOOLS: () => DELIBERATION_ALLOWED_TOOLS,
|
|
4517
4545
|
DELIVERABLE_TITLE_CHARS: () => DELIVERABLE_TITLE_CHARS,
|
|
4546
|
+
ENTERPRISE_FEATURES: () => ENTERPRISE_FEATURES,
|
|
4518
4547
|
ENTITY_COMMENTS_DEFAULT: () => ENTITY_COMMENTS_DEFAULT,
|
|
4519
4548
|
HEARTBEAT_DAILY_LOG_CHARS: () => HEARTBEAT_DAILY_LOG_CHARS,
|
|
4520
4549
|
HEARTBEAT_MIN_INITIAL_DELAY_MS: () => HEARTBEAT_MIN_INITIAL_DELAY_MS,
|
|
@@ -4533,6 +4562,7 @@ __export(dist_exports, {
|
|
|
4533
4562
|
MEMORY_MD_SECTION_MAX_CHARS: () => MEMORY_MD_SECTION_MAX_CHARS,
|
|
4534
4563
|
MEMORY_MD_TOTAL_MAX_CHARS: () => MEMORY_MD_TOTAL_MAX_CHARS,
|
|
4535
4564
|
MailboxPriorityLevel: () => MailboxPriorityLevel,
|
|
4565
|
+
PLAN_LIMITS: () => PLAN_LIMITS,
|
|
4536
4566
|
PREEMPT_REQUEUE_DELAY_MS: () => PREEMPT_REQUEUE_DELAY_MS,
|
|
4537
4567
|
PRIORITY_LABELS: () => PRIORITY_LABELS,
|
|
4538
4568
|
PROMPT_DEP_DESC_CHARS: () => PROMPT_DEP_DESC_CHARS,
|
|
@@ -4653,6 +4683,7 @@ var init_dist = __esm({
|
|
|
4653
4683
|
init_mailbox();
|
|
4654
4684
|
init_cognitive();
|
|
4655
4685
|
init_model_catalog();
|
|
4686
|
+
init_license();
|
|
4656
4687
|
init_config();
|
|
4657
4688
|
init_logger();
|
|
4658
4689
|
init_id();
|
|
@@ -41975,14 +42006,14 @@ var require_turndown_cjs = __commonJS({
|
|
|
41975
42006
|
} else if (node.nodeType === 1) {
|
|
41976
42007
|
replacement = replacementForNode.call(self, node);
|
|
41977
42008
|
}
|
|
41978
|
-
return
|
|
42009
|
+
return join35(output, replacement);
|
|
41979
42010
|
}, "");
|
|
41980
42011
|
}
|
|
41981
42012
|
function postProcess(output) {
|
|
41982
42013
|
var self = this;
|
|
41983
42014
|
this.rules.forEach(function(rule) {
|
|
41984
42015
|
if (typeof rule.append === "function") {
|
|
41985
|
-
output =
|
|
42016
|
+
output = join35(output, rule.append(self.options));
|
|
41986
42017
|
}
|
|
41987
42018
|
});
|
|
41988
42019
|
return output.replace(/^[\t\r\n]+/, "").replace(/[\t\r\n\s]+$/, "");
|
|
@@ -41994,7 +42025,7 @@ var require_turndown_cjs = __commonJS({
|
|
|
41994
42025
|
if (whitespace2.leading || whitespace2.trailing) content = content.trim();
|
|
41995
42026
|
return whitespace2.leading + rule.replacement(content, node, this.options) + whitespace2.trailing;
|
|
41996
42027
|
}
|
|
41997
|
-
function
|
|
42028
|
+
function join35(output, replacement) {
|
|
41998
42029
|
var s1 = trimTrailingNewlines(output);
|
|
41999
42030
|
var s2 = trimLeadingNewlines(replacement);
|
|
42000
42031
|
var nls = Math.max(output.length - s1.length, replacement.length - s2.length);
|
|
@@ -46805,6 +46836,7 @@ var init_agent2 = __esm({
|
|
|
46805
46836
|
auditCallback;
|
|
46806
46837
|
escalationCallback;
|
|
46807
46838
|
approvalCallback;
|
|
46839
|
+
toolCallLimitChecker;
|
|
46808
46840
|
tasksFetcher;
|
|
46809
46841
|
consecutiveFailures = 0;
|
|
46810
46842
|
metricsCollector;
|
|
@@ -48591,6 +48623,9 @@ ${instructions}
|
|
|
48591
48623
|
setEscalationCallback(cb) {
|
|
48592
48624
|
this.escalationCallback = cb;
|
|
48593
48625
|
}
|
|
48626
|
+
setToolCallLimitChecker(cb) {
|
|
48627
|
+
this.toolCallLimitChecker = cb;
|
|
48628
|
+
}
|
|
48594
48629
|
setStateChangeCallback(cb) {
|
|
48595
48630
|
this.stateChangeCallback = cb;
|
|
48596
48631
|
}
|
|
@@ -48738,16 +48773,16 @@ ${instructions}
|
|
|
48738
48773
|
const toolNames = /* @__PURE__ */ new Set();
|
|
48739
48774
|
const errors = [];
|
|
48740
48775
|
let lastText = "";
|
|
48741
|
-
for (const
|
|
48742
|
-
if (
|
|
48743
|
-
const name =
|
|
48776
|
+
for (const log91 of logs) {
|
|
48777
|
+
if (log91.type === "tool_start") {
|
|
48778
|
+
const name = log91.metadata?.toolName ?? "";
|
|
48744
48779
|
if (name)
|
|
48745
48780
|
toolNames.add(name);
|
|
48746
48781
|
}
|
|
48747
|
-
if (
|
|
48748
|
-
errors.push(
|
|
48749
|
-
if (
|
|
48750
|
-
lastText =
|
|
48782
|
+
if (log91.type === "error")
|
|
48783
|
+
errors.push(log91.content.slice(0, 100));
|
|
48784
|
+
if (log91.type === "text")
|
|
48785
|
+
lastText = log91.content.slice(0, 200);
|
|
48751
48786
|
}
|
|
48752
48787
|
const parts = [];
|
|
48753
48788
|
if (toolNames.size > 0)
|
|
@@ -51138,6 +51173,15 @@ ${body}${contextSuffix}`;
|
|
|
51138
51173
|
error: beforeResult.reason ?? "Blocked by tool hook"
|
|
51139
51174
|
});
|
|
51140
51175
|
}
|
|
51176
|
+
if (this.toolCallLimitChecker) {
|
|
51177
|
+
const limitResult = this.toolCallLimitChecker();
|
|
51178
|
+
if (!limitResult.allowed) {
|
|
51179
|
+
return JSON.stringify({
|
|
51180
|
+
status: "denied",
|
|
51181
|
+
error: limitResult.reason ?? "Tool call limit reached"
|
|
51182
|
+
});
|
|
51183
|
+
}
|
|
51184
|
+
}
|
|
51141
51185
|
const baseArgs = beforeResult.modifiedArgs ?? toolCall.arguments;
|
|
51142
51186
|
const effectiveArgs = sessionId ? { ...baseArgs, _browserSessionId: sessionId } : baseArgs;
|
|
51143
51187
|
let lastError;
|
|
@@ -57929,6 +57973,7 @@ var init_agent_manager = __esm({
|
|
|
57929
57973
|
agentAuditCallback;
|
|
57930
57974
|
escalationHandler;
|
|
57931
57975
|
approvalHandler;
|
|
57976
|
+
toolCallLimitChecker;
|
|
57932
57977
|
stateChangeHandler;
|
|
57933
57978
|
/** Grace timers for releasing scoped MCP processes after agent goes idle */
|
|
57934
57979
|
mcpReleaseTimers = /* @__PURE__ */ new Map();
|
|
@@ -58910,6 +58955,9 @@ Known issues: ${knownIssues}` : ""}`
|
|
|
58910
58955
|
const ah = this.approvalHandler;
|
|
58911
58956
|
agent.setApprovalCallback(async (req) => ah(id, req));
|
|
58912
58957
|
}
|
|
58958
|
+
if (this.toolCallLimitChecker) {
|
|
58959
|
+
agent.setToolCallLimitChecker(this.toolCallLimitChecker);
|
|
58960
|
+
}
|
|
58913
58961
|
agent.setStateChangeCallback(this.buildStateChangeCallback());
|
|
58914
58962
|
if (this.activityCallbacks) {
|
|
58915
58963
|
agent.setActivityCallbacks(this.activityCallbacks);
|
|
@@ -59544,6 +59592,9 @@ Known issues: ${knownIssues}` : ""}`
|
|
|
59544
59592
|
const ah = this.approvalHandler;
|
|
59545
59593
|
agent.setApprovalCallback(async (req) => ah(id, req));
|
|
59546
59594
|
}
|
|
59595
|
+
if (this.toolCallLimitChecker) {
|
|
59596
|
+
agent.setToolCallLimitChecker(this.toolCallLimitChecker);
|
|
59597
|
+
}
|
|
59547
59598
|
agent.setStateChangeCallback(this.buildStateChangeCallback());
|
|
59548
59599
|
if (this.activityCallbacks) {
|
|
59549
59600
|
agent.setActivityCallbacks(this.activityCallbacks);
|
|
@@ -59690,6 +59741,12 @@ Known issues: ${knownIssues}` : ""}`
|
|
|
59690
59741
|
agent.setApprovalCallback(async (req) => handler4(id, req));
|
|
59691
59742
|
}
|
|
59692
59743
|
}
|
|
59744
|
+
setToolCallLimitChecker(checker) {
|
|
59745
|
+
this.toolCallLimitChecker = checker;
|
|
59746
|
+
for (const [, agent] of this.agents) {
|
|
59747
|
+
agent.setToolCallLimitChecker(checker);
|
|
59748
|
+
}
|
|
59749
|
+
}
|
|
59693
59750
|
/**
|
|
59694
59751
|
* Build the combined state-change callback for an agent. Handles:
|
|
59695
59752
|
* 1. MCP scoped-process lifecycle (release on idle, cancel release on working)
|
|
@@ -63957,7 +64014,7 @@ var init_external_gateway = __esm({
|
|
|
63957
64014
|
return rows.length;
|
|
63958
64015
|
}
|
|
63959
64016
|
async register(request) {
|
|
63960
|
-
const { externalAgentId, agentName, orgId: orgId2, capabilities = [], platform:
|
|
64017
|
+
const { externalAgentId, agentName, orgId: orgId2, capabilities = [], platform: platform5, platformConfig, agentCardUrl, openClawConfig } = request;
|
|
63961
64018
|
if (!externalAgentId || !agentName || !orgId2) {
|
|
63962
64019
|
throw new GatewayError("Missing required fields: externalAgentId, agentName, orgId", 400);
|
|
63963
64020
|
}
|
|
@@ -63984,7 +64041,7 @@ var init_external_gateway = __esm({
|
|
|
63984
64041
|
agentName,
|
|
63985
64042
|
orgId: orgId2,
|
|
63986
64043
|
capabilities,
|
|
63987
|
-
platform:
|
|
64044
|
+
platform: platform5 ?? (openClawConfig ? "openclaw" : void 0),
|
|
63988
64045
|
platformConfig: platformConfig ?? openClawConfig,
|
|
63989
64046
|
agentCardUrl,
|
|
63990
64047
|
openClawConfig,
|
|
@@ -76781,8 +76838,8 @@ var require_CronFileParser = __commonJS({
|
|
|
76781
76838
|
* @throws If file cannot be read
|
|
76782
76839
|
*/
|
|
76783
76840
|
static parseFileSync(filePath) {
|
|
76784
|
-
const { readFileSync:
|
|
76785
|
-
const data =
|
|
76841
|
+
const { readFileSync: readFileSync31 } = __require("fs");
|
|
76842
|
+
const data = readFileSync31(filePath, "utf8");
|
|
76786
76843
|
return _CronFileParser.#parseContent(data);
|
|
76787
76844
|
}
|
|
76788
76845
|
/**
|
|
@@ -82111,6 +82168,8 @@ var init_api_server = __esm({
|
|
|
82111
82168
|
hitlService;
|
|
82112
82169
|
billingService;
|
|
82113
82170
|
auditService;
|
|
82171
|
+
licenseService;
|
|
82172
|
+
telemetryService;
|
|
82114
82173
|
storage;
|
|
82115
82174
|
llmRouter;
|
|
82116
82175
|
markusConfigPath;
|
|
@@ -82130,7 +82189,40 @@ var init_api_server = __esm({
|
|
|
82130
82189
|
remoteAgent;
|
|
82131
82190
|
remoteAgentFactory;
|
|
82132
82191
|
modelCatalog;
|
|
82133
|
-
|
|
82192
|
+
/** Aggregate today's tool calls from all agents' persisted metrics (the single source of truth) */
|
|
82193
|
+
getToolCallsTodayFromAgents() {
|
|
82194
|
+
try {
|
|
82195
|
+
const agentManager = this.orgService.getAgentManager();
|
|
82196
|
+
const allAgents = agentManager.listAgents();
|
|
82197
|
+
let total = 0;
|
|
82198
|
+
for (const a of allAgents) {
|
|
82199
|
+
try {
|
|
82200
|
+
const agent = agentManager.getAgent(a.id);
|
|
82201
|
+
total += agent.getUsageStats().toolCallsToday;
|
|
82202
|
+
} catch {
|
|
82203
|
+
}
|
|
82204
|
+
}
|
|
82205
|
+
return total;
|
|
82206
|
+
} catch {
|
|
82207
|
+
return 0;
|
|
82208
|
+
}
|
|
82209
|
+
}
|
|
82210
|
+
/** fetch that follows redirects while preserving the Authorization header */
|
|
82211
|
+
async hubFetch(url, init) {
|
|
82212
|
+
let currentUrl = url;
|
|
82213
|
+
for (let i = 0; i < 3; i++) {
|
|
82214
|
+
const res = await fetch(currentUrl, { ...init, redirect: "manual" });
|
|
82215
|
+
if (res.status >= 300 && res.status < 400) {
|
|
82216
|
+
const location = res.headers.get("location");
|
|
82217
|
+
if (!location)
|
|
82218
|
+
return res;
|
|
82219
|
+
currentUrl = new URL(location, currentUrl).href;
|
|
82220
|
+
continue;
|
|
82221
|
+
}
|
|
82222
|
+
return res;
|
|
82223
|
+
}
|
|
82224
|
+
return fetch(currentUrl, init);
|
|
82225
|
+
}
|
|
82134
82226
|
constructor(orgService, taskService, port = 8056) {
|
|
82135
82227
|
this.orgService = orgService;
|
|
82136
82228
|
this.taskService = taskService;
|
|
@@ -82339,7 +82431,7 @@ ${cleanText}`,
|
|
|
82339
82431
|
const headers = { "Content-Type": "application/json" };
|
|
82340
82432
|
if (token)
|
|
82341
82433
|
headers["Authorization"] = `Bearer ${token}`;
|
|
82342
|
-
const res = await
|
|
82434
|
+
const res = await self.hubFetch(`${hubUrl}/api/items${qs ? `?${qs}` : ""}`, { headers });
|
|
82343
82435
|
if (!res.ok)
|
|
82344
82436
|
throw new Error(`Hub search failed: ${res.status}`);
|
|
82345
82437
|
const data = await res.json();
|
|
@@ -82359,7 +82451,7 @@ ${cleanText}`,
|
|
|
82359
82451
|
if (!token)
|
|
82360
82452
|
throw new Error("Hub token not configured. Please login to Markus Hub first.");
|
|
82361
82453
|
const headers = { "Content-Type": "application/json", "Authorization": `Bearer ${token}` };
|
|
82362
|
-
const res = await
|
|
82454
|
+
const res = await self.hubFetch(`${hubUrl}/api/items/${itemId}/download`, { method: "POST", headers });
|
|
82363
82455
|
if (!res.ok)
|
|
82364
82456
|
throw new Error(`Hub download failed: ${res.status}`);
|
|
82365
82457
|
const data = await res.json();
|
|
@@ -82393,6 +82485,12 @@ ${cleanText}`,
|
|
|
82393
82485
|
setBillingService(service) {
|
|
82394
82486
|
this.billingService = service;
|
|
82395
82487
|
}
|
|
82488
|
+
setLicenseService(service) {
|
|
82489
|
+
this.licenseService = service;
|
|
82490
|
+
}
|
|
82491
|
+
setTelemetryService(service) {
|
|
82492
|
+
this.telemetryService = service;
|
|
82493
|
+
}
|
|
82396
82494
|
setAuditService(service) {
|
|
82397
82495
|
this.auditService = service;
|
|
82398
82496
|
}
|
|
@@ -83145,12 +83243,18 @@ ${cleanText}`,
|
|
|
83145
83243
|
}
|
|
83146
83244
|
if (path === "/api/auth/status" && req.method === "GET") {
|
|
83147
83245
|
if (!this.storage || !this.authEnabled) {
|
|
83148
|
-
this.json(res, 200, { initialized: true });
|
|
83246
|
+
this.json(res, 200, { initialized: true, hasOwner: true, hasMultipleUsers: false });
|
|
83149
83247
|
return;
|
|
83150
83248
|
}
|
|
83151
83249
|
const allUsers = await this.storage.userRepo.listByOrg("default");
|
|
83152
|
-
const
|
|
83153
|
-
|
|
83250
|
+
const realUsers = allUsers.filter((u) => (u.passwordHash || u.hubUserId) && u.email !== "admin@markus.local");
|
|
83251
|
+
const hasOwner = realUsers.some((u) => u.role === "owner");
|
|
83252
|
+
const hasMultipleUsers = realUsers.length > 1;
|
|
83253
|
+
this.json(res, 200, {
|
|
83254
|
+
initialized: realUsers.length > 0,
|
|
83255
|
+
hasOwner,
|
|
83256
|
+
hasMultipleUsers
|
|
83257
|
+
});
|
|
83154
83258
|
return;
|
|
83155
83259
|
}
|
|
83156
83260
|
if (path === "/api/auth/init" && req.method === "POST") {
|
|
@@ -83252,6 +83356,135 @@ ${cleanText}`,
|
|
|
83252
83356
|
});
|
|
83253
83357
|
return;
|
|
83254
83358
|
}
|
|
83359
|
+
if (path === "/api/auth/hub-login" && req.method === "POST") {
|
|
83360
|
+
if (!this.storage) {
|
|
83361
|
+
this.json(res, 503, { error: "Storage not available" });
|
|
83362
|
+
return;
|
|
83363
|
+
}
|
|
83364
|
+
const body = await this.readBody(req);
|
|
83365
|
+
const hubToken = body["hubToken"];
|
|
83366
|
+
const hubUser = body["hubUser"];
|
|
83367
|
+
if (!hubToken || !hubUser?.id) {
|
|
83368
|
+
this.json(res, 400, { error: "hubToken and hubUser are required" });
|
|
83369
|
+
return;
|
|
83370
|
+
}
|
|
83371
|
+
let verifiedUser = null;
|
|
83372
|
+
try {
|
|
83373
|
+
const verifyRes = await this.hubFetch(`${this.hubUrl}/api/auth/me`, {
|
|
83374
|
+
headers: { "Authorization": `Bearer ${hubToken}` }
|
|
83375
|
+
});
|
|
83376
|
+
if (verifyRes.ok) {
|
|
83377
|
+
const verifyData = await verifyRes.json();
|
|
83378
|
+
if (verifyData.user && verifyData.user.id === hubUser.id) {
|
|
83379
|
+
verifiedUser = verifyData.user;
|
|
83380
|
+
} else {
|
|
83381
|
+
log61.warn("Hub token user mismatch", { expected: hubUser.id, got: verifyData.user?.id });
|
|
83382
|
+
}
|
|
83383
|
+
} else {
|
|
83384
|
+
log61.warn("Hub /api/auth/me returned non-OK", { status: verifyRes.status, hubUrl: this.hubUrl });
|
|
83385
|
+
}
|
|
83386
|
+
} catch (e) {
|
|
83387
|
+
log61.warn("Hub token verification failed, proceeding with client-supplied data", { error: e.message, hubUrl: this.hubUrl });
|
|
83388
|
+
}
|
|
83389
|
+
if (!verifiedUser) {
|
|
83390
|
+
verifiedUser = { id: hubUser.id, username: hubUser.username, email: hubUser.email, displayName: hubUser.displayName, avatarUrl: hubUser.avatarUrl };
|
|
83391
|
+
}
|
|
83392
|
+
const rawEmail = (verifiedUser.email ?? hubUser.email ?? "").trim().toLowerCase();
|
|
83393
|
+
const email = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(rawEmail) ? rawEmail : "";
|
|
83394
|
+
const name = verifiedUser.displayName || verifiedUser.username || hubUser.displayName || hubUser.username || email && email.split("@")[0] || "User";
|
|
83395
|
+
const avatarUrl = verifiedUser.avatarUrl ?? hubUser.avatarUrl ?? null;
|
|
83396
|
+
let userRow = this.storage.userRepo.findByHubUserId(hubUser.id);
|
|
83397
|
+
let isFirstLogin = false;
|
|
83398
|
+
if (!userRow && email) {
|
|
83399
|
+
userRow = this.storage.userRepo.findByEmail(email);
|
|
83400
|
+
if (userRow) {
|
|
83401
|
+
this.storage.userRepo.updateHubUserId(userRow.id, hubUser.id, hubUser.username);
|
|
83402
|
+
if (avatarUrl && !userRow.avatarUrl) {
|
|
83403
|
+
this.storage.userRepo.updateAvatarUrl(userRow.id, avatarUrl);
|
|
83404
|
+
}
|
|
83405
|
+
}
|
|
83406
|
+
}
|
|
83407
|
+
if (!userRow) {
|
|
83408
|
+
const allUsers = await this.storage.userRepo.listByOrg("default");
|
|
83409
|
+
const placeholder = allUsers.find((u) => u.role === "owner" && u.email === "admin@markus.local");
|
|
83410
|
+
const hasRealOwner = allUsers.some((u) => u.role === "owner" && (u.passwordHash || u.hubUserId) && u.email !== "admin@markus.local");
|
|
83411
|
+
if (placeholder && !hasRealOwner) {
|
|
83412
|
+
this.storage.userRepo.updateProfile(placeholder.id, { name, email: email || void 0, avatarUrl });
|
|
83413
|
+
this.storage.userRepo.updateHubUserId(placeholder.id, hubUser.id, hubUser.username);
|
|
83414
|
+
userRow = this.storage.userRepo.findById(placeholder.id);
|
|
83415
|
+
isFirstLogin = true;
|
|
83416
|
+
} else if (!hasRealOwner) {
|
|
83417
|
+
const userId2 = userId();
|
|
83418
|
+
this.storage.userRepo.create({
|
|
83419
|
+
id: userId2,
|
|
83420
|
+
orgId: "default",
|
|
83421
|
+
name,
|
|
83422
|
+
email: email || void 0,
|
|
83423
|
+
role: "owner",
|
|
83424
|
+
hubUserId: hubUser.id,
|
|
83425
|
+
avatarUrl: avatarUrl ?? void 0
|
|
83426
|
+
});
|
|
83427
|
+
this.storage.userRepo.updateHubUserId(userId2, hubUser.id, hubUser.username);
|
|
83428
|
+
userRow = this.storage.userRepo.findById(userId2);
|
|
83429
|
+
isFirstLogin = true;
|
|
83430
|
+
} else {
|
|
83431
|
+
const realOwners = allUsers.filter((u) => u.role === "owner" && (u.passwordHash || u.hubUserId) && u.email !== "admin@markus.local");
|
|
83432
|
+
if (realOwners.length === 1 && !realOwners[0].hubUserId) {
|
|
83433
|
+
const existingOwner = realOwners[0];
|
|
83434
|
+
this.storage.userRepo.updateProfile(existingOwner.id, { name: existingOwner.name, email: email || existingOwner.email, avatarUrl: avatarUrl ?? existingOwner.avatarUrl });
|
|
83435
|
+
this.storage.userRepo.updateHubUserId(existingOwner.id, hubUser.id, hubUser.username);
|
|
83436
|
+
userRow = this.storage.userRepo.findById(existingOwner.id);
|
|
83437
|
+
log61.info("Hub login: adopted existing owner", { ownerId: existingOwner.id, hubUserId: hubUser.id });
|
|
83438
|
+
} else {
|
|
83439
|
+
this.json(res, 403, { error: "This instance already has an owner. Multi-user requires Enterprise license." });
|
|
83440
|
+
return;
|
|
83441
|
+
}
|
|
83442
|
+
}
|
|
83443
|
+
}
|
|
83444
|
+
if (!userRow) {
|
|
83445
|
+
this.json(res, 500, { error: "Failed to create user" });
|
|
83446
|
+
return;
|
|
83447
|
+
}
|
|
83448
|
+
const hubUsername = verifiedUser.username || hubUser.username;
|
|
83449
|
+
if (hubUsername) {
|
|
83450
|
+
this.storage.userRepo.updateHubUserId(userRow.id, hubUser.id, hubUsername);
|
|
83451
|
+
}
|
|
83452
|
+
const profileUpdates = {};
|
|
83453
|
+
if (name && name !== userRow.name)
|
|
83454
|
+
profileUpdates.name = name;
|
|
83455
|
+
if (email && email !== userRow.email)
|
|
83456
|
+
profileUpdates.email = email;
|
|
83457
|
+
if (avatarUrl && avatarUrl !== userRow.avatarUrl)
|
|
83458
|
+
profileUpdates.avatarUrl = avatarUrl;
|
|
83459
|
+
if (Object.keys(profileUpdates).length > 0) {
|
|
83460
|
+
this.storage.userRepo.updateProfile(userRow.id, profileUpdates);
|
|
83461
|
+
userRow = this.storage.userRepo.findById(userRow.id);
|
|
83462
|
+
}
|
|
83463
|
+
this.orgService.syncHumanIdentity(userRow.id, "default", userRow.name, userRow.role, userRow.email ?? void 0);
|
|
83464
|
+
try {
|
|
83465
|
+
const tokenPath = join24(homedir15(), ".markus", "hub-token");
|
|
83466
|
+
mkdirSync19(dirname8(tokenPath), { recursive: true });
|
|
83467
|
+
writeFileSync17(tokenPath, hubToken, "utf-8");
|
|
83468
|
+
} catch {
|
|
83469
|
+
}
|
|
83470
|
+
const finalUser = userRow;
|
|
83471
|
+
await this.storage.userRepo.updateLastLogin(finalUser.id);
|
|
83472
|
+
const exp = Math.floor(Date.now() / 1e3) + 7 * 24 * 3600;
|
|
83473
|
+
const token = await signToken({ userId: finalUser.id, orgId: "default", role: finalUser.role, exp }, this.jwtSecret);
|
|
83474
|
+
res.setHeader("Set-Cookie", `markus_token=${token}; HttpOnly; SameSite=Strict; Path=/; Max-Age=${7 * 24 * 3600}`);
|
|
83475
|
+
this.json(res, 200, {
|
|
83476
|
+
user: {
|
|
83477
|
+
id: finalUser.id,
|
|
83478
|
+
name: finalUser.name,
|
|
83479
|
+
email: finalUser.email,
|
|
83480
|
+
role: finalUser.role,
|
|
83481
|
+
orgId: finalUser.orgId,
|
|
83482
|
+
avatarUrl: finalUser.avatarUrl ?? void 0
|
|
83483
|
+
},
|
|
83484
|
+
needsOnboarding: isFirstLogin
|
|
83485
|
+
});
|
|
83486
|
+
return;
|
|
83487
|
+
}
|
|
83255
83488
|
if (path === "/api/auth/logout" && req.method === "POST") {
|
|
83256
83489
|
res.setHeader("Set-Cookie", "markus_token=; HttpOnly; SameSite=Strict; Path=/; Max-Age=0");
|
|
83257
83490
|
this.json(res, 200, { ok: true });
|
|
@@ -84340,6 +84573,16 @@ ${cleanText}`,
|
|
|
84340
84573
|
this.json(res, 400, { error: "name is required" });
|
|
84341
84574
|
return;
|
|
84342
84575
|
}
|
|
84576
|
+
if (this.licenseService) {
|
|
84577
|
+
const limits = this.licenseService.getLimits();
|
|
84578
|
+
if (limits.maxTeams > 0) {
|
|
84579
|
+
const existingTeams = await this.orgService.listTeams(orgId2);
|
|
84580
|
+
if (existingTeams.length >= limits.maxTeams) {
|
|
84581
|
+
this.json(res, 403, { error: `Team limit reached (${limits.maxTeams}). Upgrade to Enterprise for unlimited teams.` });
|
|
84582
|
+
return;
|
|
84583
|
+
}
|
|
84584
|
+
}
|
|
84585
|
+
}
|
|
84343
84586
|
const team = await this.orgService.createTeam(orgId2, name, body["description"]);
|
|
84344
84587
|
this.ws?.broadcast({
|
|
84345
84588
|
type: "chat:group_created",
|
|
@@ -86470,6 +86713,16 @@ EXPLANATION_END`;
|
|
|
86470
86713
|
const authUser = await this.requireAuth(req, res);
|
|
86471
86714
|
if (!authUser)
|
|
86472
86715
|
return;
|
|
86716
|
+
if (this.licenseService && this.storage) {
|
|
86717
|
+
const limits = this.licenseService.getLimits();
|
|
86718
|
+
if (limits.maxUsers > 0) {
|
|
86719
|
+
const existingCount = this.storage.userRepo.countByOrg("default");
|
|
86720
|
+
if (existingCount >= limits.maxUsers) {
|
|
86721
|
+
this.json(res, 403, { error: `User limit reached (${limits.maxUsers}). Upgrade to Enterprise for multi-user support.` });
|
|
86722
|
+
return;
|
|
86723
|
+
}
|
|
86724
|
+
}
|
|
86725
|
+
}
|
|
86473
86726
|
const body = await this.readBody(req);
|
|
86474
86727
|
const orgId2 = body["orgId"] ?? "default";
|
|
86475
86728
|
const name = body["name"];
|
|
@@ -86750,14 +87003,14 @@ EXPLANATION_END`;
|
|
|
86750
87003
|
const installedSkills = new Map((this.skillRegistry?.list() ?? []).map((s2) => [s2.name, s2]));
|
|
86751
87004
|
const rawManifests = /* @__PURE__ */ new Map();
|
|
86752
87005
|
try {
|
|
86753
|
-
const { readdirSync: readdirSync14, readFileSync:
|
|
87006
|
+
const { readdirSync: readdirSync14, readFileSync: readFileSync31, existsSync: existsSync42 } = await import("node:fs");
|
|
86754
87007
|
for (const entry of readdirSync14(builtinDir, { withFileTypes: true })) {
|
|
86755
87008
|
if (!entry.isDirectory())
|
|
86756
87009
|
continue;
|
|
86757
87010
|
const sjPath = resolve15(builtinDir, entry.name, "skill.json");
|
|
86758
|
-
if (
|
|
87011
|
+
if (existsSync42(sjPath)) {
|
|
86759
87012
|
try {
|
|
86760
|
-
rawManifests.set(entry.name, JSON.parse(
|
|
87013
|
+
rawManifests.set(entry.name, JSON.parse(readFileSync31(sjPath, "utf-8")));
|
|
86761
87014
|
} catch {
|
|
86762
87015
|
}
|
|
86763
87016
|
}
|
|
@@ -87184,6 +87437,16 @@ EXPLANATION_END`;
|
|
|
87184
87437
|
this.json(res, 500, { error: "BuilderService not initialized" });
|
|
87185
87438
|
return;
|
|
87186
87439
|
}
|
|
87440
|
+
if (type === "team" && this.licenseService) {
|
|
87441
|
+
const limits = this.licenseService.getLimits();
|
|
87442
|
+
if (limits.maxTeams > 0) {
|
|
87443
|
+
const existingTeams = await this.orgService.listTeams("default");
|
|
87444
|
+
if (existingTeams.length >= limits.maxTeams) {
|
|
87445
|
+
this.json(res, 403, { error: `Team limit reached (${limits.maxTeams}). Upgrade to Enterprise for unlimited teams.` });
|
|
87446
|
+
return;
|
|
87447
|
+
}
|
|
87448
|
+
}
|
|
87449
|
+
}
|
|
87187
87450
|
try {
|
|
87188
87451
|
const result = await this.builderService.installArtifact(type, name);
|
|
87189
87452
|
this.json(res, 201, result);
|
|
@@ -88199,11 +88462,11 @@ EXPLANATION_END`;
|
|
|
88199
88462
|
}
|
|
88200
88463
|
if (path === "/api/templates/teams" && req.method === "GET") {
|
|
88201
88464
|
try {
|
|
88202
|
-
const { readdirSync: readdirSync14, readFileSync:
|
|
88465
|
+
const { readdirSync: readdirSync14, readFileSync: readFileSync31 } = await import("node:fs");
|
|
88203
88466
|
const { resolve: resolve21 } = await import("node:path");
|
|
88204
88467
|
const teamsDir = resolve21(process.cwd(), "templates", "teams");
|
|
88205
88468
|
const files = readdirSync14(teamsDir).filter((f) => f.endsWith(".json"));
|
|
88206
|
-
const teams = files.map((f) => JSON.parse(
|
|
88469
|
+
const teams = files.map((f) => JSON.parse(readFileSync31(resolve21(teamsDir, f), "utf-8")));
|
|
88207
88470
|
this.json(res, 200, { templates: teams });
|
|
88208
88471
|
} catch {
|
|
88209
88472
|
this.json(res, 200, { templates: [] });
|
|
@@ -88244,6 +88507,183 @@ EXPLANATION_END`;
|
|
|
88244
88507
|
this.json(res, 200, { usage });
|
|
88245
88508
|
return;
|
|
88246
88509
|
}
|
|
88510
|
+
if (path === "/api/license" && req.method === "GET") {
|
|
88511
|
+
const raw = this.licenseService ? this.licenseService.getInfo() : { plan: "free", features: [], limits: { maxTeams: 1, maxToolCallsPerDay: 500, maxUsers: 1 } };
|
|
88512
|
+
const info2 = { ...raw };
|
|
88513
|
+
const authUser = await this.getAuthUser(req);
|
|
88514
|
+
if (authUser && this.storage) {
|
|
88515
|
+
const userRow = this.storage.userRepo.findById(authUser.userId);
|
|
88516
|
+
if (userRow) {
|
|
88517
|
+
if (userRow.hubUserId)
|
|
88518
|
+
info2.hubUserId = userRow.hubUserId;
|
|
88519
|
+
info2.username = userRow.hubUsername || userRow.name || void 0;
|
|
88520
|
+
}
|
|
88521
|
+
}
|
|
88522
|
+
try {
|
|
88523
|
+
const defaultOrg = this.orgService.getDefaultOrganization();
|
|
88524
|
+
const orgId2 = defaultOrg?.id ?? "default";
|
|
88525
|
+
const teams = this.orgService.listTeams(orgId2);
|
|
88526
|
+
const humans = this.orgService.listHumanUsers(orgId2);
|
|
88527
|
+
const todayToolCalls = this.getToolCallsTodayFromAgents();
|
|
88528
|
+
info2.usage = { teams: teams.length, toolCallsToday: todayToolCalls, users: humans.length };
|
|
88529
|
+
} catch {
|
|
88530
|
+
}
|
|
88531
|
+
const hubToken = this.readHubToken();
|
|
88532
|
+
if (hubToken) {
|
|
88533
|
+
try {
|
|
88534
|
+
const meRes = await this.hubFetch(`${this.hubUrl}/api/auth/me`, {
|
|
88535
|
+
headers: { "Authorization": `Bearer ${hubToken}` }
|
|
88536
|
+
});
|
|
88537
|
+
if (meRes.ok) {
|
|
88538
|
+
const meData = await meRes.json();
|
|
88539
|
+
if (meData.defaultOrg) {
|
|
88540
|
+
info2.defaultOrg = meData.defaultOrg;
|
|
88541
|
+
if (!info2.orgId)
|
|
88542
|
+
info2.orgId = meData.defaultOrg.id;
|
|
88543
|
+
if (!info2.orgName)
|
|
88544
|
+
info2.orgName = meData.defaultOrg.name;
|
|
88545
|
+
}
|
|
88546
|
+
if (meData.user?.id && !info2.hubUserId)
|
|
88547
|
+
info2.hubUserId = meData.user.id;
|
|
88548
|
+
}
|
|
88549
|
+
} catch {
|
|
88550
|
+
}
|
|
88551
|
+
}
|
|
88552
|
+
this.json(res, 200, info2);
|
|
88553
|
+
return;
|
|
88554
|
+
}
|
|
88555
|
+
if (path === "/api/license/refresh" && req.method === "POST") {
|
|
88556
|
+
if (!this.licenseService) {
|
|
88557
|
+
this.json(res, 503, { error: "License service not available" });
|
|
88558
|
+
return;
|
|
88559
|
+
}
|
|
88560
|
+
const raw = await this.licenseService.revalidate();
|
|
88561
|
+
if (this.billingService)
|
|
88562
|
+
this.billingService.setOrgPlan("default", this.licenseService.getPlan());
|
|
88563
|
+
const info2 = { ...raw };
|
|
88564
|
+
const authUser = await this.getAuthUser(req);
|
|
88565
|
+
if (authUser && this.storage) {
|
|
88566
|
+
const userRow = this.storage.userRepo.findById(authUser.userId);
|
|
88567
|
+
if (userRow) {
|
|
88568
|
+
if (userRow.hubUserId)
|
|
88569
|
+
info2.hubUserId = userRow.hubUserId;
|
|
88570
|
+
info2.username = userRow.hubUsername || userRow.name || void 0;
|
|
88571
|
+
}
|
|
88572
|
+
}
|
|
88573
|
+
try {
|
|
88574
|
+
const defaultOrg = this.orgService.getDefaultOrganization();
|
|
88575
|
+
const orgId2 = defaultOrg?.id ?? "default";
|
|
88576
|
+
const teams = this.orgService.listTeams(orgId2);
|
|
88577
|
+
const humans = this.orgService.listHumanUsers(orgId2);
|
|
88578
|
+
const todayToolCalls = this.getToolCallsTodayFromAgents();
|
|
88579
|
+
info2.usage = { teams: teams.length, toolCallsToday: todayToolCalls, users: humans.length };
|
|
88580
|
+
} catch {
|
|
88581
|
+
}
|
|
88582
|
+
const hubToken = this.readHubToken();
|
|
88583
|
+
if (hubToken) {
|
|
88584
|
+
try {
|
|
88585
|
+
const meRes = await this.hubFetch(`${this.hubUrl}/api/auth/me`, {
|
|
88586
|
+
headers: { "Authorization": `Bearer ${hubToken}` }
|
|
88587
|
+
});
|
|
88588
|
+
if (meRes.ok) {
|
|
88589
|
+
const meData = await meRes.json();
|
|
88590
|
+
if (meData.defaultOrg) {
|
|
88591
|
+
info2.defaultOrg = meData.defaultOrg;
|
|
88592
|
+
if (!info2.orgId)
|
|
88593
|
+
info2.orgId = meData.defaultOrg.id;
|
|
88594
|
+
if (!info2.orgName)
|
|
88595
|
+
info2.orgName = meData.defaultOrg.name;
|
|
88596
|
+
}
|
|
88597
|
+
if (meData.user?.id && !info2.hubUserId)
|
|
88598
|
+
info2.hubUserId = meData.user.id;
|
|
88599
|
+
}
|
|
88600
|
+
} catch {
|
|
88601
|
+
}
|
|
88602
|
+
}
|
|
88603
|
+
this.json(res, 200, info2);
|
|
88604
|
+
return;
|
|
88605
|
+
}
|
|
88606
|
+
if (path === "/api/license/activate" && req.method === "POST") {
|
|
88607
|
+
const authUser = await this.requireAuth(req, res);
|
|
88608
|
+
if (!authUser)
|
|
88609
|
+
return;
|
|
88610
|
+
if (!this.licenseService) {
|
|
88611
|
+
this.json(res, 503, { error: "License service not available" });
|
|
88612
|
+
return;
|
|
88613
|
+
}
|
|
88614
|
+
const body = await this.readBody(req);
|
|
88615
|
+
const licenseKey = body["licenseKey"];
|
|
88616
|
+
if (!licenseKey) {
|
|
88617
|
+
this.json(res, 400, { error: "licenseKey is required" });
|
|
88618
|
+
return;
|
|
88619
|
+
}
|
|
88620
|
+
const result = await this.licenseService.activateLicense(licenseKey);
|
|
88621
|
+
if (result.success && this.billingService)
|
|
88622
|
+
this.billingService.setOrgPlan("default", this.licenseService.getPlan());
|
|
88623
|
+
this.json(res, result.success ? 200 : 400, result);
|
|
88624
|
+
return;
|
|
88625
|
+
}
|
|
88626
|
+
if (path === "/api/license/trial" && req.method === "POST") {
|
|
88627
|
+
const authUser = await this.requireAuth(req, res);
|
|
88628
|
+
if (!authUser)
|
|
88629
|
+
return;
|
|
88630
|
+
if (!this.licenseService) {
|
|
88631
|
+
this.json(res, 503, { error: "License service not available" });
|
|
88632
|
+
return;
|
|
88633
|
+
}
|
|
88634
|
+
const result = await this.licenseService.activateTrial();
|
|
88635
|
+
if (result.success && this.billingService)
|
|
88636
|
+
this.billingService.setOrgPlan("default", this.licenseService.getPlan());
|
|
88637
|
+
this.json(res, result.success ? 200 : 400, result);
|
|
88638
|
+
return;
|
|
88639
|
+
}
|
|
88640
|
+
if (path === "/api/license/import" && req.method === "POST") {
|
|
88641
|
+
const authUser = await this.requireAuth(req, res);
|
|
88642
|
+
if (!authUser)
|
|
88643
|
+
return;
|
|
88644
|
+
if (!this.licenseService) {
|
|
88645
|
+
this.json(res, 503, { error: "License service not available" });
|
|
88646
|
+
return;
|
|
88647
|
+
}
|
|
88648
|
+
const body = await this.readBody(req);
|
|
88649
|
+
const fileContent = body["fileContent"];
|
|
88650
|
+
if (!fileContent) {
|
|
88651
|
+
this.json(res, 400, { error: "fileContent is required" });
|
|
88652
|
+
return;
|
|
88653
|
+
}
|
|
88654
|
+
const result = this.licenseService.importOfflineLicense(fileContent);
|
|
88655
|
+
if (result.success && this.billingService)
|
|
88656
|
+
this.billingService.setOrgPlan("default", this.licenseService.getPlan());
|
|
88657
|
+
this.json(res, result.success ? 200 : 400, result);
|
|
88658
|
+
return;
|
|
88659
|
+
}
|
|
88660
|
+
if (path === "/api/license/deactivate" && req.method === "POST") {
|
|
88661
|
+
const authUser = await this.requireAuth(req, res);
|
|
88662
|
+
if (!authUser)
|
|
88663
|
+
return;
|
|
88664
|
+
if (!this.licenseService) {
|
|
88665
|
+
this.json(res, 503, { error: "License service not available" });
|
|
88666
|
+
return;
|
|
88667
|
+
}
|
|
88668
|
+
await this.licenseService.deactivate();
|
|
88669
|
+
if (this.billingService)
|
|
88670
|
+
this.billingService.setOrgPlan("default", this.licenseService.getPlan());
|
|
88671
|
+
this.json(res, 200, { ok: true });
|
|
88672
|
+
return;
|
|
88673
|
+
}
|
|
88674
|
+
if (path === "/api/settings/telemetry" && req.method === "POST") {
|
|
88675
|
+
const body = await this.readBody(req);
|
|
88676
|
+
const enabled = body["enabled"];
|
|
88677
|
+
if (this.telemetryService && typeof enabled === "boolean") {
|
|
88678
|
+
this.telemetryService.setEnabled(enabled);
|
|
88679
|
+
}
|
|
88680
|
+
this.json(res, 200, { ok: true });
|
|
88681
|
+
return;
|
|
88682
|
+
}
|
|
88683
|
+
if (path === "/api/settings/telemetry" && req.method === "GET") {
|
|
88684
|
+
this.json(res, 200, { enabled: this.telemetryService?.isEnabled() ?? false });
|
|
88685
|
+
return;
|
|
88686
|
+
}
|
|
88247
88687
|
if (path === "/api/hub/publish" && req.method === "POST") {
|
|
88248
88688
|
const authUser = await this.requireAuth(req, res);
|
|
88249
88689
|
if (!authUser)
|
|
@@ -88291,8 +88731,16 @@ EXPLANATION_END`;
|
|
|
88291
88731
|
else
|
|
88292
88732
|
proxyHeaders["Content-Type"] = req.headers["content-type"];
|
|
88293
88733
|
const authHeader = req.headers["authorization"];
|
|
88294
|
-
if (authHeader)
|
|
88734
|
+
if (authHeader) {
|
|
88295
88735
|
proxyHeaders["Authorization"] = authHeader;
|
|
88736
|
+
} else {
|
|
88737
|
+
const storedToken = this.readHubToken();
|
|
88738
|
+
if (storedToken)
|
|
88739
|
+
proxyHeaders["Authorization"] = `Bearer ${storedToken}`;
|
|
88740
|
+
}
|
|
88741
|
+
if (req.headers["accept-language"]) {
|
|
88742
|
+
proxyHeaders["Accept-Language"] = req.headers["accept-language"];
|
|
88743
|
+
}
|
|
88296
88744
|
try {
|
|
88297
88745
|
let body;
|
|
88298
88746
|
if (req.method === "POST" || req.method === "PUT" || req.method === "PATCH") {
|
|
@@ -88377,6 +88825,10 @@ EXPLANATION_END`;
|
|
|
88377
88825
|
}
|
|
88378
88826
|
this.remoteAgent.start().catch(() => {
|
|
88379
88827
|
});
|
|
88828
|
+
try {
|
|
88829
|
+
saveConfig({ remote: { enabled: true } }, this.markusConfigPath);
|
|
88830
|
+
} catch {
|
|
88831
|
+
}
|
|
88380
88832
|
this.json(res, 200, { ok: true, status: this.remoteAgent.getStatus() });
|
|
88381
88833
|
return;
|
|
88382
88834
|
}
|
|
@@ -88384,6 +88836,10 @@ EXPLANATION_END`;
|
|
|
88384
88836
|
if (this.remoteAgent) {
|
|
88385
88837
|
await this.remoteAgent.stop();
|
|
88386
88838
|
}
|
|
88839
|
+
try {
|
|
88840
|
+
saveConfig({ remote: { enabled: false } }, this.markusConfigPath);
|
|
88841
|
+
} catch {
|
|
88842
|
+
}
|
|
88387
88843
|
this.json(res, 200, { ok: true });
|
|
88388
88844
|
return;
|
|
88389
88845
|
}
|
|
@@ -88661,7 +89117,7 @@ EXPLANATION_END`;
|
|
|
88661
89117
|
const { fileURLToPath: fileURLToPath8 } = await import("node:url");
|
|
88662
89118
|
const { dirname: dn, resolve: rslv, join: jn } = await import("node:path");
|
|
88663
89119
|
const { execSync: execSync7 } = await import("node:child_process");
|
|
88664
|
-
const { existsSync: ex, readFileSync:
|
|
89120
|
+
const { existsSync: ex, readFileSync: readFileSync31, statSync: statSync8 } = await import("node:fs");
|
|
88665
89121
|
const thisDir = dn(fileURLToPath8(import.meta.url));
|
|
88666
89122
|
const zipCandidates = [
|
|
88667
89123
|
jn(rslv(thisDir, "..", "..", "chrome-extension"), "dist", "markus-browser-extension.zip"),
|
|
@@ -88690,7 +89146,7 @@ EXPLANATION_END`;
|
|
|
88690
89146
|
this.json(res, 404, { error: "Extension zip not found." });
|
|
88691
89147
|
return;
|
|
88692
89148
|
}
|
|
88693
|
-
const data =
|
|
89149
|
+
const data = readFileSync31(zipPath);
|
|
88694
89150
|
res.writeHead(200, {
|
|
88695
89151
|
"Content-Type": "application/zip",
|
|
88696
89152
|
"Content-Disposition": 'attachment; filename="markus-browser-extension.zip"',
|
|
@@ -88708,11 +89164,11 @@ EXPLANATION_END`;
|
|
|
88708
89164
|
return;
|
|
88709
89165
|
try {
|
|
88710
89166
|
const { exec: execCb2 } = await import("node:child_process");
|
|
88711
|
-
const
|
|
88712
|
-
if (
|
|
89167
|
+
const platform5 = process.platform;
|
|
89168
|
+
if (platform5 === "darwin") {
|
|
88713
89169
|
execCb2('open -a "Google Chrome" "chrome://extensions"', () => {
|
|
88714
89170
|
});
|
|
88715
|
-
} else if (
|
|
89171
|
+
} else if (platform5 === "win32") {
|
|
88716
89172
|
execCb2('start "" "chrome://extensions"', () => {
|
|
88717
89173
|
});
|
|
88718
89174
|
} else {
|
|
@@ -89791,11 +90247,11 @@ data: ${JSON.stringify({ error: msg })}
|
|
|
89791
90247
|
const { configPath, preview } = body;
|
|
89792
90248
|
const { existsSync: fsExists, readFileSync: fsRead } = await import("node:fs");
|
|
89793
90249
|
const { join: pathJoin } = await import("node:path");
|
|
89794
|
-
const { homedir:
|
|
90250
|
+
const { homedir: homedir25 } = await import("node:os");
|
|
89795
90251
|
const possiblePaths = [
|
|
89796
90252
|
configPath,
|
|
89797
|
-
pathJoin(
|
|
89798
|
-
pathJoin(
|
|
90253
|
+
pathJoin(homedir25(), ".openclaw", "openclaw.json"),
|
|
90254
|
+
pathJoin(homedir25(), ".openclaw", "openclaw.json5")
|
|
89799
90255
|
].filter(Boolean);
|
|
89800
90256
|
let found = "";
|
|
89801
90257
|
let rawContent = "";
|
|
@@ -90014,10 +90470,10 @@ data: ${JSON.stringify({ error: msg })}
|
|
|
90014
90470
|
this.json(res, 400, { error: "Invalid or non-existent path" });
|
|
90015
90471
|
return;
|
|
90016
90472
|
}
|
|
90017
|
-
const
|
|
90018
|
-
if (
|
|
90473
|
+
const platform5 = process.platform;
|
|
90474
|
+
if (platform5 === "darwin")
|
|
90019
90475
|
execSync3(`open ${JSON.stringify(dirPath)}`);
|
|
90020
|
-
else if (
|
|
90476
|
+
else if (platform5 === "win32")
|
|
90021
90477
|
execSync3(`explorer ${JSON.stringify(dirPath)}`);
|
|
90022
90478
|
else
|
|
90023
90479
|
execSync3(`xdg-open ${JSON.stringify(dirPath)}`);
|
|
@@ -90169,9 +90625,9 @@ data: ${JSON.stringify({ error: msg })}
|
|
|
90169
90625
|
}
|
|
90170
90626
|
try {
|
|
90171
90627
|
const { resolve: resolve21, extname: extname2 } = await import("node:path");
|
|
90172
|
-
const { existsSync:
|
|
90173
|
-
const { homedir:
|
|
90174
|
-
const home =
|
|
90628
|
+
const { existsSync: existsSync42, statSync: statSync8 } = await import("node:fs");
|
|
90629
|
+
const { homedir: homedir25 } = await import("node:os");
|
|
90630
|
+
const home = homedir25();
|
|
90175
90631
|
const results = {};
|
|
90176
90632
|
const mdExts = [".md", ".markdown"];
|
|
90177
90633
|
const htmlExts = [".html", ".htm"];
|
|
@@ -90181,7 +90637,7 @@ data: ${JSON.stringify({ error: msg })}
|
|
|
90181
90637
|
try {
|
|
90182
90638
|
const expanded = p.startsWith("~/") ? resolve21(home, p.slice(2)) : p === "~" ? home : p;
|
|
90183
90639
|
const resolved = resolve21(expanded);
|
|
90184
|
-
if (!
|
|
90640
|
+
if (!existsSync42(resolved)) {
|
|
90185
90641
|
results[p] = { exists: false, isFile: false, type: "unknown" };
|
|
90186
90642
|
continue;
|
|
90187
90643
|
}
|
|
@@ -90218,21 +90674,21 @@ data: ${JSON.stringify({ error: msg })}
|
|
|
90218
90674
|
}
|
|
90219
90675
|
try {
|
|
90220
90676
|
const { resolve: resolve21, extname: extname2 } = await import("node:path");
|
|
90221
|
-
const { readFileSync:
|
|
90222
|
-
const { homedir:
|
|
90223
|
-
const home =
|
|
90677
|
+
const { readFileSync: readFileSync31, existsSync: existsSync42, statSync: statSync8 } = await import("node:fs");
|
|
90678
|
+
const { homedir: homedir25 } = await import("node:os");
|
|
90679
|
+
const home = homedir25();
|
|
90224
90680
|
const expanded = filePath.startsWith("~/") ? resolve21(home, filePath.slice(2)) : filePath === "~" ? home : filePath;
|
|
90225
90681
|
const resolved = resolve21(expanded);
|
|
90226
|
-
if (!
|
|
90682
|
+
if (!existsSync42(resolved)) {
|
|
90227
90683
|
this.json(res, 404, { error: "File not found" });
|
|
90228
90684
|
return;
|
|
90229
90685
|
}
|
|
90230
90686
|
const stat = statSync8(resolved);
|
|
90231
90687
|
if (stat.isDirectory()) {
|
|
90232
90688
|
const { readdirSync: readdirSync14 } = await import("node:fs");
|
|
90233
|
-
const { join:
|
|
90689
|
+
const { join: join35, extname: extDir } = await import("node:path");
|
|
90234
90690
|
const entries2 = readdirSync14(resolved, { withFileTypes: true }).filter((e) => !e.name.startsWith(".")).map((e) => {
|
|
90235
|
-
const full =
|
|
90691
|
+
const full = join35(resolved, e.name);
|
|
90236
90692
|
const isDir = e.isDirectory();
|
|
90237
90693
|
let size;
|
|
90238
90694
|
try {
|
|
@@ -90261,7 +90717,7 @@ data: ${JSON.stringify({ error: msg })}
|
|
|
90261
90717
|
const ext = extname2(resolved).toLowerCase();
|
|
90262
90718
|
const imageExts = [".png", ".jpg", ".jpeg", ".gif", ".webp", ".svg"];
|
|
90263
90719
|
if (imageExts.includes(ext)) {
|
|
90264
|
-
const data =
|
|
90720
|
+
const data = readFileSync31(resolved);
|
|
90265
90721
|
const mimeMap = { ".png": "image/png", ".jpg": "image/jpeg", ".jpeg": "image/jpeg", ".gif": "image/gif", ".webp": "image/webp", ".svg": "image/svg+xml" };
|
|
90266
90722
|
this.json(res, 200, {
|
|
90267
90723
|
type: "image",
|
|
@@ -90270,7 +90726,7 @@ data: ${JSON.stringify({ error: msg })}
|
|
|
90270
90726
|
content: data.toString("base64")
|
|
90271
90727
|
});
|
|
90272
90728
|
} else {
|
|
90273
|
-
const content =
|
|
90729
|
+
const content = readFileSync31(resolved, "utf-8");
|
|
90274
90730
|
const mdExts = [".md", ".markdown"];
|
|
90275
90731
|
const htmlExts = [".html", ".htm"];
|
|
90276
90732
|
const jsonExts = [".json"];
|
|
@@ -90303,12 +90759,12 @@ data: ${JSON.stringify({ error: msg })}
|
|
|
90303
90759
|
}
|
|
90304
90760
|
try {
|
|
90305
90761
|
const { resolve: resolve21, extname: extname2 } = await import("node:path");
|
|
90306
|
-
const { readFileSync:
|
|
90307
|
-
const { homedir:
|
|
90308
|
-
const home =
|
|
90762
|
+
const { readFileSync: readFileSync31, existsSync: existsSync42, statSync: statSync8 } = await import("node:fs");
|
|
90763
|
+
const { homedir: homedir25 } = await import("node:os");
|
|
90764
|
+
const home = homedir25();
|
|
90309
90765
|
const expanded = filePath.startsWith("~/") ? resolve21(home, filePath.slice(2)) : filePath === "~" ? home : filePath;
|
|
90310
90766
|
const resolved = resolve21(expanded);
|
|
90311
|
-
if (!
|
|
90767
|
+
if (!existsSync42(resolved) || !statSync8(resolved).isFile()) {
|
|
90312
90768
|
this.json(res, 404, { error: "Image not found" });
|
|
90313
90769
|
return;
|
|
90314
90770
|
}
|
|
@@ -90333,7 +90789,7 @@ data: ${JSON.stringify({ error: msg })}
|
|
|
90333
90789
|
this.json(res, 400, { error: "Not an image file" });
|
|
90334
90790
|
return;
|
|
90335
90791
|
}
|
|
90336
|
-
const data =
|
|
90792
|
+
const data = readFileSync31(resolved);
|
|
90337
90793
|
res.writeHead(200, {
|
|
90338
90794
|
"Content-Type": mime,
|
|
90339
90795
|
"Content-Length": data.length,
|
|
@@ -90353,26 +90809,26 @@ data: ${JSON.stringify({ error: msg })}
|
|
|
90353
90809
|
return;
|
|
90354
90810
|
}
|
|
90355
90811
|
try {
|
|
90356
|
-
const { resolve: resolve21, dirname:
|
|
90357
|
-
const { existsSync:
|
|
90812
|
+
const { resolve: resolve21, dirname: dirname15 } = await import("node:path");
|
|
90813
|
+
const { existsSync: existsSync42, statSync: statSync8 } = await import("node:fs");
|
|
90358
90814
|
const { exec: exec2 } = await import("node:child_process");
|
|
90359
|
-
const { homedir:
|
|
90360
|
-
const home =
|
|
90815
|
+
const { homedir: homedir25 } = await import("node:os");
|
|
90816
|
+
const home = homedir25();
|
|
90361
90817
|
const expanded = filePath.startsWith("~/") ? resolve21(home, filePath.slice(2)) : filePath === "~" ? home : filePath;
|
|
90362
90818
|
const resolved = resolve21(expanded);
|
|
90363
|
-
if (!
|
|
90819
|
+
if (!existsSync42(resolved)) {
|
|
90364
90820
|
this.json(res, 404, { error: "Path not found" });
|
|
90365
90821
|
return;
|
|
90366
90822
|
}
|
|
90367
90823
|
const isDir = statSync8(resolved).isDirectory();
|
|
90368
|
-
const
|
|
90824
|
+
const platform5 = process.platform;
|
|
90369
90825
|
let cmd;
|
|
90370
|
-
if (
|
|
90826
|
+
if (platform5 === "darwin") {
|
|
90371
90827
|
cmd = isDir ? `open "${resolved}"` : `open -R "${resolved}"`;
|
|
90372
|
-
} else if (
|
|
90828
|
+
} else if (platform5 === "win32") {
|
|
90373
90829
|
cmd = isDir ? `explorer "${resolved}"` : `explorer /select,"${resolved}"`;
|
|
90374
90830
|
} else {
|
|
90375
|
-
cmd = `xdg-open "${isDir ? resolved :
|
|
90831
|
+
cmd = `xdg-open "${isDir ? resolved : dirname15(resolved)}"`;
|
|
90376
90832
|
}
|
|
90377
90833
|
exec2(cmd, (err) => {
|
|
90378
90834
|
if (err) {
|
|
@@ -91069,6 +91525,7 @@ data: ${JSON.stringify({ error: msg })}
|
|
|
91069
91525
|
return [
|
|
91070
91526
|
// ── Auth ─────────────────────────────────────────────────────────────
|
|
91071
91527
|
exact("/api/auth/login", "POST"),
|
|
91528
|
+
exact("/api/auth/hub-login", "POST"),
|
|
91072
91529
|
exact("/api/auth/logout", "POST"),
|
|
91073
91530
|
exact("/api/auth/me", "GET"),
|
|
91074
91531
|
exact("/api/auth/change-password", "POST"),
|
|
@@ -91228,6 +91685,13 @@ data: ${JSON.stringify({ error: msg })}
|
|
|
91228
91685
|
exact("/api/models/validate-key", "POST"),
|
|
91229
91686
|
regex(/^\/api\/models\/live\/[^/]+$/, "GET"),
|
|
91230
91687
|
// ── Settings ─────────────────────────────────────────────────────────
|
|
91688
|
+
exact("/api/license", "GET"),
|
|
91689
|
+
exact("/api/license/refresh", "POST"),
|
|
91690
|
+
exact("/api/license/activate", "POST"),
|
|
91691
|
+
exact("/api/license/trial", "POST"),
|
|
91692
|
+
exact("/api/license/import", "POST"),
|
|
91693
|
+
exact("/api/license/deactivate", "POST"),
|
|
91694
|
+
exact("/api/settings/telemetry", "GET", "POST"),
|
|
91231
91695
|
exact("/api/settings/hub", "GET"),
|
|
91232
91696
|
exact("/api/settings/hub-token", "POST"),
|
|
91233
91697
|
exact("/api/settings/llm", "GET", "POST"),
|
|
@@ -92376,17 +92840,10 @@ var init_billing_service = __esm({
|
|
|
92376
92840
|
DEFAULT_PLANS = {
|
|
92377
92841
|
free: {
|
|
92378
92842
|
maxAgents: -1,
|
|
92379
|
-
maxTokensPerMonth:
|
|
92380
|
-
maxToolCallsPerDay:
|
|
92381
|
-
maxMessagesPerDay:
|
|
92382
|
-
maxStorageBytes:
|
|
92383
|
-
},
|
|
92384
|
-
pro: {
|
|
92385
|
-
maxAgents: 20,
|
|
92386
|
-
maxTokensPerMonth: 5e6,
|
|
92387
|
-
maxToolCallsPerDay: 5e3,
|
|
92388
|
-
maxMessagesPerDay: 2e3,
|
|
92389
|
-
maxStorageBytes: 5 * 1024 * 1024 * 1024
|
|
92843
|
+
maxTokensPerMonth: -1,
|
|
92844
|
+
maxToolCallsPerDay: 500,
|
|
92845
|
+
maxMessagesPerDay: -1,
|
|
92846
|
+
maxStorageBytes: -1
|
|
92390
92847
|
},
|
|
92391
92848
|
enterprise: {
|
|
92392
92849
|
maxAgents: -1,
|
|
@@ -92402,6 +92859,10 @@ var init_billing_service = __esm({
|
|
|
92402
92859
|
apiKeys = /* @__PURE__ */ new Map();
|
|
92403
92860
|
apiKeysByKey = /* @__PURE__ */ new Map();
|
|
92404
92861
|
orgPlans = /* @__PURE__ */ new Map();
|
|
92862
|
+
toolCallsTodayProvider;
|
|
92863
|
+
setToolCallsTodayProvider(fn) {
|
|
92864
|
+
this.toolCallsTodayProvider = fn;
|
|
92865
|
+
}
|
|
92405
92866
|
setOrgPlan(orgId2, tier) {
|
|
92406
92867
|
const plan = {
|
|
92407
92868
|
orgId: orgId2,
|
|
@@ -92477,8 +92938,7 @@ var init_billing_service = __esm({
|
|
|
92477
92938
|
}
|
|
92478
92939
|
}
|
|
92479
92940
|
if (type === "tool_call") {
|
|
92480
|
-
const
|
|
92481
|
-
const todayCount = todayRecords.reduce((s2, r) => s2 + r.amount, 0);
|
|
92941
|
+
const todayCount = this.toolCallsTodayProvider ? this.toolCallsTodayProvider() : this.records.filter((r) => r.orgId === orgId2 && r.type === "tool_call" && r.timestamp.startsWith(today)).reduce((s2, r) => s2 + r.amount, 0);
|
|
92482
92942
|
if (plan.limits.maxToolCallsPerDay > 0 && todayCount + additionalAmount > plan.limits.maxToolCallsPerDay) {
|
|
92483
92943
|
return {
|
|
92484
92944
|
allowed: false,
|
|
@@ -92606,13 +93066,523 @@ var init_billing_service = __esm({
|
|
|
92606
93066
|
}
|
|
92607
93067
|
});
|
|
92608
93068
|
|
|
93069
|
+
// ../org-manager/dist/license-service.js
|
|
93070
|
+
import { readFileSync as readFileSync23, writeFileSync as writeFileSync18, existsSync as existsSync30, mkdirSync as mkdirSync20 } from "node:fs";
|
|
93071
|
+
import { join as join25, dirname as dirname9 } from "node:path";
|
|
93072
|
+
import { homedir as homedir16 } from "node:os";
|
|
93073
|
+
import { randomUUID, createVerify } from "node:crypto";
|
|
93074
|
+
async function hubFetch(url, init, maxRedirects = 3) {
|
|
93075
|
+
let currentUrl = url;
|
|
93076
|
+
for (let i = 0; i <= maxRedirects; i++) {
|
|
93077
|
+
const res = await fetch(currentUrl, { ...init, redirect: "manual" });
|
|
93078
|
+
if (res.status >= 300 && res.status < 400) {
|
|
93079
|
+
const location = res.headers.get("location");
|
|
93080
|
+
if (!location)
|
|
93081
|
+
break;
|
|
93082
|
+
currentUrl = new URL(location, currentUrl).href;
|
|
93083
|
+
continue;
|
|
93084
|
+
}
|
|
93085
|
+
return res;
|
|
93086
|
+
}
|
|
93087
|
+
return fetch(currentUrl, init);
|
|
93088
|
+
}
|
|
93089
|
+
var log64, LICENSE_FILE, HEARTBEAT_INTERVAL_MS, HUB_LICENSE_PUBLIC_KEY, LicenseService;
|
|
93090
|
+
var init_license_service = __esm({
|
|
93091
|
+
"../org-manager/dist/license-service.js"() {
|
|
93092
|
+
"use strict";
|
|
93093
|
+
init_dist();
|
|
93094
|
+
log64 = createLogger("license");
|
|
93095
|
+
LICENSE_FILE = join25(homedir16(), ".markus", "license.json");
|
|
93096
|
+
HEARTBEAT_INTERVAL_MS = 4 * 60 * 60 * 1e3;
|
|
93097
|
+
HUB_LICENSE_PUBLIC_KEY = `-----BEGIN PUBLIC KEY-----
|
|
93098
|
+
MCowBQYDK2VwAyEAPlaceholderPublicKeyForOfflineLicenseVerification00=
|
|
93099
|
+
-----END PUBLIC KEY-----`;
|
|
93100
|
+
LicenseService = class {
|
|
93101
|
+
license;
|
|
93102
|
+
hubUrl;
|
|
93103
|
+
heartbeatTimer = null;
|
|
93104
|
+
constructor(hubUrl = "https://markus.global") {
|
|
93105
|
+
this.hubUrl = hubUrl;
|
|
93106
|
+
this.license = this.loadLicense();
|
|
93107
|
+
this.startHeartbeat();
|
|
93108
|
+
}
|
|
93109
|
+
loadLicense() {
|
|
93110
|
+
try {
|
|
93111
|
+
if (existsSync30(LICENSE_FILE)) {
|
|
93112
|
+
const data = JSON.parse(readFileSync23(LICENSE_FILE, "utf-8"));
|
|
93113
|
+
if (data && data.plan && data.instanceId) {
|
|
93114
|
+
return data;
|
|
93115
|
+
}
|
|
93116
|
+
}
|
|
93117
|
+
} catch (e) {
|
|
93118
|
+
log64.warn("Failed to load license file, using defaults");
|
|
93119
|
+
}
|
|
93120
|
+
const defaultLicense = {
|
|
93121
|
+
plan: "free",
|
|
93122
|
+
features: [],
|
|
93123
|
+
limits: { ...PLAN_LIMITS.free },
|
|
93124
|
+
instanceId: randomUUID()
|
|
93125
|
+
};
|
|
93126
|
+
this.saveLicense(defaultLicense);
|
|
93127
|
+
return defaultLicense;
|
|
93128
|
+
}
|
|
93129
|
+
saveLicense(license) {
|
|
93130
|
+
try {
|
|
93131
|
+
mkdirSync20(dirname9(LICENSE_FILE), { recursive: true });
|
|
93132
|
+
writeFileSync18(LICENSE_FILE, JSON.stringify(license, null, 2), "utf-8");
|
|
93133
|
+
} catch (e) {
|
|
93134
|
+
log64.warn("Failed to save license file");
|
|
93135
|
+
}
|
|
93136
|
+
}
|
|
93137
|
+
startHeartbeat() {
|
|
93138
|
+
if (this.heartbeatTimer)
|
|
93139
|
+
clearInterval(this.heartbeatTimer);
|
|
93140
|
+
this.heartbeatTimer = setInterval(() => {
|
|
93141
|
+
void this.sendHeartbeat();
|
|
93142
|
+
}, HEARTBEAT_INTERVAL_MS);
|
|
93143
|
+
setTimeout(() => void this.sendHeartbeat(), 3e4);
|
|
93144
|
+
}
|
|
93145
|
+
async sendHeartbeat() {
|
|
93146
|
+
if (!this.license.licenseKey)
|
|
93147
|
+
return;
|
|
93148
|
+
const hubToken = this.readHubToken();
|
|
93149
|
+
if (!hubToken)
|
|
93150
|
+
return;
|
|
93151
|
+
try {
|
|
93152
|
+
const res = await hubFetch(`${this.hubUrl}/api/licenses/heartbeat`, {
|
|
93153
|
+
method: "POST",
|
|
93154
|
+
headers: {
|
|
93155
|
+
"Content-Type": "application/json",
|
|
93156
|
+
"Authorization": `Bearer ${hubToken}`
|
|
93157
|
+
},
|
|
93158
|
+
body: JSON.stringify({
|
|
93159
|
+
licenseKey: this.license.licenseKey,
|
|
93160
|
+
instanceId: this.license.instanceId
|
|
93161
|
+
})
|
|
93162
|
+
});
|
|
93163
|
+
if (res.ok) {
|
|
93164
|
+
const data = await res.json();
|
|
93165
|
+
if (data.valid) {
|
|
93166
|
+
this.license.lastValidated = (/* @__PURE__ */ new Date()).toISOString();
|
|
93167
|
+
this.license.plan = data.plan;
|
|
93168
|
+
this.license.validUntil = data.validUntil;
|
|
93169
|
+
this.license.limits = { ...PLAN_LIMITS[data.plan] };
|
|
93170
|
+
this.license.features = data.plan === "enterprise" ? [...ENTERPRISE_FEATURES] : [];
|
|
93171
|
+
if (data.orgId)
|
|
93172
|
+
this.license.orgId = data.orgId;
|
|
93173
|
+
if (data.orgName)
|
|
93174
|
+
this.license.orgName = data.orgName;
|
|
93175
|
+
if (data.maxSeats !== null && data.maxSeats !== void 0)
|
|
93176
|
+
this.license.maxSeats = data.maxSeats;
|
|
93177
|
+
if (data.usedSeats !== null && data.usedSeats !== void 0)
|
|
93178
|
+
this.license.usedSeats = data.usedSeats;
|
|
93179
|
+
this.saveLicense(this.license);
|
|
93180
|
+
} else {
|
|
93181
|
+
log64.warn("License heartbeat returned invalid \u2014 reverting to free");
|
|
93182
|
+
this.revertToFree();
|
|
93183
|
+
}
|
|
93184
|
+
} else if (res.status === 403 || res.status === 404) {
|
|
93185
|
+
log64.warn("License heartbeat rejected \u2014 reverting to free");
|
|
93186
|
+
this.revertToFree();
|
|
93187
|
+
}
|
|
93188
|
+
} catch {
|
|
93189
|
+
log64.debug("License heartbeat failed (network issue) \u2014 using cached state");
|
|
93190
|
+
}
|
|
93191
|
+
}
|
|
93192
|
+
revertToFree() {
|
|
93193
|
+
this.license.plan = "free";
|
|
93194
|
+
this.license.licenseKey = void 0;
|
|
93195
|
+
this.license.validUntil = void 0;
|
|
93196
|
+
this.license.isTrial = void 0;
|
|
93197
|
+
this.license.isOffline = void 0;
|
|
93198
|
+
this.license.features = [];
|
|
93199
|
+
this.license.limits = { ...PLAN_LIMITS.free };
|
|
93200
|
+
this.license.orgId = void 0;
|
|
93201
|
+
this.license.orgName = void 0;
|
|
93202
|
+
this.license.maxSeats = void 0;
|
|
93203
|
+
this.license.usedSeats = void 0;
|
|
93204
|
+
this.saveLicense(this.license);
|
|
93205
|
+
}
|
|
93206
|
+
readHubToken() {
|
|
93207
|
+
try {
|
|
93208
|
+
const tokenPath = join25(homedir16(), ".markus", "hub-token");
|
|
93209
|
+
return existsSync30(tokenPath) ? readFileSync23(tokenPath, "utf-8").trim() : void 0;
|
|
93210
|
+
} catch {
|
|
93211
|
+
return void 0;
|
|
93212
|
+
}
|
|
93213
|
+
}
|
|
93214
|
+
// ─── Public API ────────────────────────────────────────────────────────
|
|
93215
|
+
getPlan() {
|
|
93216
|
+
if (this.license.validUntil && new Date(this.license.validUntil) < /* @__PURE__ */ new Date()) {
|
|
93217
|
+
if (this.license.plan !== "free") {
|
|
93218
|
+
log64.info("License expired \u2014 reverting to free");
|
|
93219
|
+
this.revertToFree();
|
|
93220
|
+
}
|
|
93221
|
+
}
|
|
93222
|
+
return this.license.plan;
|
|
93223
|
+
}
|
|
93224
|
+
getLimits() {
|
|
93225
|
+
this.getPlan();
|
|
93226
|
+
return { ...this.license.limits };
|
|
93227
|
+
}
|
|
93228
|
+
getFeatures() {
|
|
93229
|
+
this.getPlan();
|
|
93230
|
+
return [...this.license.features];
|
|
93231
|
+
}
|
|
93232
|
+
canUse(feature) {
|
|
93233
|
+
this.getPlan();
|
|
93234
|
+
if (this.license.plan === "enterprise")
|
|
93235
|
+
return true;
|
|
93236
|
+
return this.license.features.includes(feature);
|
|
93237
|
+
}
|
|
93238
|
+
getInfo() {
|
|
93239
|
+
this.getPlan();
|
|
93240
|
+
return { ...this.license };
|
|
93241
|
+
}
|
|
93242
|
+
getInstanceId() {
|
|
93243
|
+
return this.license.instanceId;
|
|
93244
|
+
}
|
|
93245
|
+
async activateLicense(licenseKey) {
|
|
93246
|
+
const hubToken = this.readHubToken();
|
|
93247
|
+
if (!hubToken) {
|
|
93248
|
+
return { success: false, error: "Not authenticated with Markus Hub" };
|
|
93249
|
+
}
|
|
93250
|
+
try {
|
|
93251
|
+
const res = await hubFetch(`${this.hubUrl}/api/licenses/activate`, {
|
|
93252
|
+
method: "POST",
|
|
93253
|
+
headers: {
|
|
93254
|
+
"Content-Type": "application/json",
|
|
93255
|
+
"Authorization": `Bearer ${hubToken}`
|
|
93256
|
+
},
|
|
93257
|
+
body: JSON.stringify({
|
|
93258
|
+
licenseKey,
|
|
93259
|
+
instanceId: this.license.instanceId
|
|
93260
|
+
})
|
|
93261
|
+
});
|
|
93262
|
+
const data = await res.json();
|
|
93263
|
+
if (res.ok && data.success) {
|
|
93264
|
+
this.license.licenseKey = licenseKey;
|
|
93265
|
+
this.license.plan = data.plan ?? "enterprise";
|
|
93266
|
+
this.license.validUntil = data.validUntil;
|
|
93267
|
+
this.license.isTrial = data.isTrial;
|
|
93268
|
+
this.license.isOffline = false;
|
|
93269
|
+
this.license.features = data.features ?? [...ENTERPRISE_FEATURES];
|
|
93270
|
+
this.license.limits = { ...PLAN_LIMITS[this.license.plan] };
|
|
93271
|
+
this.license.lastValidated = (/* @__PURE__ */ new Date()).toISOString();
|
|
93272
|
+
this.license.orgId = data.orgId;
|
|
93273
|
+
this.license.orgName = data.orgName;
|
|
93274
|
+
this.license.maxSeats = data.maxSeats;
|
|
93275
|
+
this.license.usedSeats = data.usedSeats;
|
|
93276
|
+
this.saveLicense(this.license);
|
|
93277
|
+
log64.info(`License activated: ${this.license.plan} (valid until ${this.license.validUntil})`);
|
|
93278
|
+
return { success: true };
|
|
93279
|
+
}
|
|
93280
|
+
return { success: false, error: data.error ?? "Activation failed" };
|
|
93281
|
+
} catch {
|
|
93282
|
+
return { success: false, error: "Could not connect to Markus Hub" };
|
|
93283
|
+
}
|
|
93284
|
+
}
|
|
93285
|
+
async activateTrial() {
|
|
93286
|
+
const hubToken = this.readHubToken();
|
|
93287
|
+
if (!hubToken) {
|
|
93288
|
+
return { success: false, error: "Not authenticated with Markus Hub" };
|
|
93289
|
+
}
|
|
93290
|
+
try {
|
|
93291
|
+
const res = await hubFetch(`${this.hubUrl}/api/licenses/trial`, {
|
|
93292
|
+
method: "POST",
|
|
93293
|
+
headers: {
|
|
93294
|
+
"Content-Type": "application/json",
|
|
93295
|
+
"Authorization": `Bearer ${hubToken}`
|
|
93296
|
+
},
|
|
93297
|
+
body: JSON.stringify({
|
|
93298
|
+
instanceId: this.license.instanceId
|
|
93299
|
+
})
|
|
93300
|
+
});
|
|
93301
|
+
const data = await res.json();
|
|
93302
|
+
if (res.ok && data.success && data.licenseKey) {
|
|
93303
|
+
this.license.licenseKey = data.licenseKey;
|
|
93304
|
+
this.license.plan = data.plan ?? "enterprise";
|
|
93305
|
+
this.license.validUntil = data.validUntil;
|
|
93306
|
+
this.license.isTrial = true;
|
|
93307
|
+
this.license.isOffline = false;
|
|
93308
|
+
this.license.features = [...ENTERPRISE_FEATURES];
|
|
93309
|
+
this.license.limits = { ...PLAN_LIMITS.enterprise };
|
|
93310
|
+
this.license.lastValidated = (/* @__PURE__ */ new Date()).toISOString();
|
|
93311
|
+
this.license.orgId = data.orgId;
|
|
93312
|
+
this.license.orgName = data.orgName;
|
|
93313
|
+
this.license.maxSeats = data.maxSeats;
|
|
93314
|
+
this.saveLicense(this.license);
|
|
93315
|
+
log64.info(`Trial activated (valid until ${this.license.validUntil})`);
|
|
93316
|
+
return { success: true };
|
|
93317
|
+
}
|
|
93318
|
+
return { success: false, error: data.error ?? "Trial activation failed" };
|
|
93319
|
+
} catch {
|
|
93320
|
+
return { success: false, error: "Could not connect to Markus Hub" };
|
|
93321
|
+
}
|
|
93322
|
+
}
|
|
93323
|
+
importOfflineLicense(fileContent) {
|
|
93324
|
+
try {
|
|
93325
|
+
const payload = JSON.parse(fileContent);
|
|
93326
|
+
if (payload.version !== 1 || payload.plan !== "enterprise") {
|
|
93327
|
+
return { success: false, error: "Invalid license file format" };
|
|
93328
|
+
}
|
|
93329
|
+
if (new Date(payload.validUntil) < /* @__PURE__ */ new Date()) {
|
|
93330
|
+
return { success: false, error: "License has expired" };
|
|
93331
|
+
}
|
|
93332
|
+
if (payload.signature) {
|
|
93333
|
+
try {
|
|
93334
|
+
const verifier = createVerify("Ed25519");
|
|
93335
|
+
const signData = JSON.stringify({
|
|
93336
|
+
version: payload.version,
|
|
93337
|
+
licenseId: payload.licenseId,
|
|
93338
|
+
plan: payload.plan,
|
|
93339
|
+
issuedTo: payload.issuedTo,
|
|
93340
|
+
validFrom: payload.validFrom,
|
|
93341
|
+
validUntil: payload.validUntil,
|
|
93342
|
+
maxInstances: payload.maxInstances,
|
|
93343
|
+
features: payload.features
|
|
93344
|
+
});
|
|
93345
|
+
verifier.update(signData);
|
|
93346
|
+
const valid = verifier.verify(HUB_LICENSE_PUBLIC_KEY, payload.signature, "base64");
|
|
93347
|
+
if (!valid) {
|
|
93348
|
+
log64.warn("Offline license signature verification failed \u2014 accepting in dev mode");
|
|
93349
|
+
}
|
|
93350
|
+
} catch {
|
|
93351
|
+
log64.warn("Offline license signature verification skipped (key format)");
|
|
93352
|
+
}
|
|
93353
|
+
}
|
|
93354
|
+
this.license.licenseKey = payload.licenseId;
|
|
93355
|
+
this.license.plan = "enterprise";
|
|
93356
|
+
this.license.validUntil = payload.validUntil;
|
|
93357
|
+
this.license.isTrial = false;
|
|
93358
|
+
this.license.isOffline = true;
|
|
93359
|
+
this.license.features = payload.features ?? [...ENTERPRISE_FEATURES];
|
|
93360
|
+
this.license.limits = { ...PLAN_LIMITS.enterprise };
|
|
93361
|
+
this.license.lastValidated = (/* @__PURE__ */ new Date()).toISOString();
|
|
93362
|
+
this.saveLicense(this.license);
|
|
93363
|
+
log64.info(`Offline license imported: ${payload.licenseId} (valid until ${payload.validUntil})`);
|
|
93364
|
+
return { success: true };
|
|
93365
|
+
} catch {
|
|
93366
|
+
return { success: false, error: "Could not parse license file" };
|
|
93367
|
+
}
|
|
93368
|
+
}
|
|
93369
|
+
async deactivate() {
|
|
93370
|
+
if (this.license.licenseKey && !this.license.isOffline) {
|
|
93371
|
+
const hubToken = this.readHubToken();
|
|
93372
|
+
if (hubToken) {
|
|
93373
|
+
try {
|
|
93374
|
+
await hubFetch(`${this.hubUrl}/api/licenses/deactivate`, {
|
|
93375
|
+
method: "POST",
|
|
93376
|
+
headers: {
|
|
93377
|
+
"Content-Type": "application/json",
|
|
93378
|
+
"Authorization": `Bearer ${hubToken}`
|
|
93379
|
+
},
|
|
93380
|
+
body: JSON.stringify({
|
|
93381
|
+
licenseKey: this.license.licenseKey,
|
|
93382
|
+
instanceId: this.license.instanceId
|
|
93383
|
+
})
|
|
93384
|
+
});
|
|
93385
|
+
} catch {
|
|
93386
|
+
}
|
|
93387
|
+
}
|
|
93388
|
+
}
|
|
93389
|
+
this.revertToFree();
|
|
93390
|
+
log64.info("License deactivated");
|
|
93391
|
+
}
|
|
93392
|
+
async revalidate() {
|
|
93393
|
+
if (!this.license.licenseKey) {
|
|
93394
|
+
const saved = this.loadLicense();
|
|
93395
|
+
if (saved.licenseKey) {
|
|
93396
|
+
this.license = saved;
|
|
93397
|
+
}
|
|
93398
|
+
}
|
|
93399
|
+
await this.syncFromHub();
|
|
93400
|
+
if (this.license.licenseKey) {
|
|
93401
|
+
await this.sendHeartbeat();
|
|
93402
|
+
}
|
|
93403
|
+
this.getPlan();
|
|
93404
|
+
return { ...this.license };
|
|
93405
|
+
}
|
|
93406
|
+
async syncFromHub() {
|
|
93407
|
+
const hubToken = this.readHubToken();
|
|
93408
|
+
if (!hubToken)
|
|
93409
|
+
return;
|
|
93410
|
+
try {
|
|
93411
|
+
const res = await hubFetch(`${this.hubUrl}/api/licenses/mine`, {
|
|
93412
|
+
headers: { "Authorization": `Bearer ${hubToken}` }
|
|
93413
|
+
});
|
|
93414
|
+
if (!res.ok)
|
|
93415
|
+
return;
|
|
93416
|
+
const data = await res.json();
|
|
93417
|
+
if (!data.license)
|
|
93418
|
+
return;
|
|
93419
|
+
const currentKey = this.license.licenseKey;
|
|
93420
|
+
if (currentKey === data.license.licenseKey) {
|
|
93421
|
+
if (data.license.usedSeats !== null && data.license.usedSeats !== void 0 && data.license.usedSeats !== this.license.usedSeats) {
|
|
93422
|
+
this.license.usedSeats = data.license.usedSeats;
|
|
93423
|
+
this.saveLicense(this.license);
|
|
93424
|
+
}
|
|
93425
|
+
return;
|
|
93426
|
+
}
|
|
93427
|
+
const currentIsTrial = this.license.isTrial;
|
|
93428
|
+
const newIsBetter = !currentKey || currentIsTrial && !data.license.isTrial || !currentIsTrial && !data.license.isTrial && new Date(data.license.validUntil) > new Date(this.license.validUntil ?? "");
|
|
93429
|
+
if (!newIsBetter)
|
|
93430
|
+
return;
|
|
93431
|
+
log64.info(`Found better license on Hub: ${data.license.licenseKey} (current: ${currentKey ?? "none"})`);
|
|
93432
|
+
const result = await this.activateLicense(data.license.licenseKey);
|
|
93433
|
+
if (result.success) {
|
|
93434
|
+
if (data.license.orgId)
|
|
93435
|
+
this.license.orgId = data.license.orgId;
|
|
93436
|
+
if (data.license.orgName)
|
|
93437
|
+
this.license.orgName = data.license.orgName;
|
|
93438
|
+
if (data.license.maxSeats !== null && data.license.maxSeats !== void 0)
|
|
93439
|
+
this.license.maxSeats = data.license.maxSeats;
|
|
93440
|
+
this.saveLicense(this.license);
|
|
93441
|
+
log64.info(`Upgraded license from Hub: ${data.license.licenseKey}`);
|
|
93442
|
+
}
|
|
93443
|
+
} catch {
|
|
93444
|
+
log64.debug("Failed to sync license from Hub");
|
|
93445
|
+
}
|
|
93446
|
+
}
|
|
93447
|
+
setHubUrl(url) {
|
|
93448
|
+
this.hubUrl = url;
|
|
93449
|
+
}
|
|
93450
|
+
destroy() {
|
|
93451
|
+
if (this.heartbeatTimer) {
|
|
93452
|
+
clearInterval(this.heartbeatTimer);
|
|
93453
|
+
this.heartbeatTimer = null;
|
|
93454
|
+
}
|
|
93455
|
+
}
|
|
93456
|
+
};
|
|
93457
|
+
}
|
|
93458
|
+
});
|
|
93459
|
+
|
|
93460
|
+
// ../org-manager/dist/telemetry-service.js
|
|
93461
|
+
import { readFileSync as readFileSync24, writeFileSync as writeFileSync19, existsSync as existsSync31, mkdirSync as mkdirSync21 } from "node:fs";
|
|
93462
|
+
import { join as join26, dirname as dirname10 } from "node:path";
|
|
93463
|
+
import { homedir as homedir17, platform as platform3, arch as arch2 } from "node:os";
|
|
93464
|
+
async function hubFetch2(url, init) {
|
|
93465
|
+
let currentUrl = url;
|
|
93466
|
+
for (let i = 0; i < 3; i++) {
|
|
93467
|
+
const res = await fetch(currentUrl, { ...init, redirect: "manual" });
|
|
93468
|
+
if (res.status >= 300 && res.status < 400) {
|
|
93469
|
+
const location = res.headers.get("location");
|
|
93470
|
+
if (!location)
|
|
93471
|
+
return res;
|
|
93472
|
+
currentUrl = new URL(location, currentUrl).href;
|
|
93473
|
+
continue;
|
|
93474
|
+
}
|
|
93475
|
+
return res;
|
|
93476
|
+
}
|
|
93477
|
+
return fetch(currentUrl, init);
|
|
93478
|
+
}
|
|
93479
|
+
var log65, TELEMETRY_CONFIG_FILE, REPORT_INTERVAL_MS, TelemetryService;
|
|
93480
|
+
var init_telemetry_service = __esm({
|
|
93481
|
+
"../org-manager/dist/telemetry-service.js"() {
|
|
93482
|
+
"use strict";
|
|
93483
|
+
init_dist();
|
|
93484
|
+
log65 = createLogger("telemetry");
|
|
93485
|
+
TELEMETRY_CONFIG_FILE = join26(homedir17(), ".markus", "telemetry.json");
|
|
93486
|
+
REPORT_INTERVAL_MS = 6 * 60 * 60 * 1e3;
|
|
93487
|
+
TelemetryService = class {
|
|
93488
|
+
enabled;
|
|
93489
|
+
hubUrl;
|
|
93490
|
+
instanceId;
|
|
93491
|
+
timer = null;
|
|
93492
|
+
statsProvider = null;
|
|
93493
|
+
constructor(hubUrl, instanceId) {
|
|
93494
|
+
this.hubUrl = hubUrl;
|
|
93495
|
+
this.instanceId = instanceId;
|
|
93496
|
+
const config = this.loadConfig();
|
|
93497
|
+
this.enabled = config.enabled;
|
|
93498
|
+
}
|
|
93499
|
+
loadConfig() {
|
|
93500
|
+
try {
|
|
93501
|
+
if (existsSync31(TELEMETRY_CONFIG_FILE)) {
|
|
93502
|
+
return JSON.parse(readFileSync24(TELEMETRY_CONFIG_FILE, "utf-8"));
|
|
93503
|
+
}
|
|
93504
|
+
} catch {
|
|
93505
|
+
}
|
|
93506
|
+
return { enabled: true };
|
|
93507
|
+
}
|
|
93508
|
+
saveConfig(config) {
|
|
93509
|
+
try {
|
|
93510
|
+
mkdirSync21(dirname10(TELEMETRY_CONFIG_FILE), { recursive: true });
|
|
93511
|
+
writeFileSync19(TELEMETRY_CONFIG_FILE, JSON.stringify(config, null, 2), "utf-8");
|
|
93512
|
+
} catch {
|
|
93513
|
+
}
|
|
93514
|
+
}
|
|
93515
|
+
setEnabled(enabled) {
|
|
93516
|
+
this.enabled = enabled;
|
|
93517
|
+
const config = this.loadConfig();
|
|
93518
|
+
config.enabled = enabled;
|
|
93519
|
+
this.saveConfig(config);
|
|
93520
|
+
log65.info(`Telemetry ${enabled ? "enabled" : "disabled"}`);
|
|
93521
|
+
}
|
|
93522
|
+
isEnabled() {
|
|
93523
|
+
return this.enabled;
|
|
93524
|
+
}
|
|
93525
|
+
setStatsProvider(provider) {
|
|
93526
|
+
this.statsProvider = provider;
|
|
93527
|
+
}
|
|
93528
|
+
start() {
|
|
93529
|
+
if (this.timer)
|
|
93530
|
+
return;
|
|
93531
|
+
this.timer = setInterval(() => void this.report(), REPORT_INTERVAL_MS);
|
|
93532
|
+
setTimeout(() => void this.report(), 6e4);
|
|
93533
|
+
}
|
|
93534
|
+
async report() {
|
|
93535
|
+
if (!this.enabled || !this.statsProvider)
|
|
93536
|
+
return;
|
|
93537
|
+
try {
|
|
93538
|
+
const stats = this.statsProvider();
|
|
93539
|
+
const payload = {
|
|
93540
|
+
instanceId: this.instanceId,
|
|
93541
|
+
version: APP_VERSION,
|
|
93542
|
+
os: `${platform3()}/${arch2()}`,
|
|
93543
|
+
...stats
|
|
93544
|
+
};
|
|
93545
|
+
const hubToken = this.readHubToken();
|
|
93546
|
+
const headers = { "Content-Type": "application/json" };
|
|
93547
|
+
if (hubToken)
|
|
93548
|
+
headers["Authorization"] = `Bearer ${hubToken}`;
|
|
93549
|
+
await hubFetch2(`${this.hubUrl}/api/telemetry`, {
|
|
93550
|
+
method: "POST",
|
|
93551
|
+
headers,
|
|
93552
|
+
body: JSON.stringify(payload)
|
|
93553
|
+
});
|
|
93554
|
+
const config = this.loadConfig();
|
|
93555
|
+
config.lastReportAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
93556
|
+
this.saveConfig(config);
|
|
93557
|
+
} catch {
|
|
93558
|
+
log65.debug("Telemetry report failed (network)");
|
|
93559
|
+
}
|
|
93560
|
+
}
|
|
93561
|
+
readHubToken() {
|
|
93562
|
+
try {
|
|
93563
|
+
const tokenPath = join26(homedir17(), ".markus", "hub-token");
|
|
93564
|
+
return existsSync31(tokenPath) ? readFileSync24(tokenPath, "utf-8").trim() : void 0;
|
|
93565
|
+
} catch {
|
|
93566
|
+
return void 0;
|
|
93567
|
+
}
|
|
93568
|
+
}
|
|
93569
|
+
destroy() {
|
|
93570
|
+
if (this.timer) {
|
|
93571
|
+
clearInterval(this.timer);
|
|
93572
|
+
this.timer = null;
|
|
93573
|
+
}
|
|
93574
|
+
}
|
|
93575
|
+
};
|
|
93576
|
+
}
|
|
93577
|
+
});
|
|
93578
|
+
|
|
92609
93579
|
// ../org-manager/dist/audit-service.js
|
|
92610
|
-
var
|
|
93580
|
+
var log66, entryCounter, AuditService;
|
|
92611
93581
|
var init_audit_service = __esm({
|
|
92612
93582
|
"../org-manager/dist/audit-service.js"() {
|
|
92613
93583
|
"use strict";
|
|
92614
93584
|
init_dist();
|
|
92615
|
-
|
|
93585
|
+
log66 = createLogger("audit");
|
|
92616
93586
|
entryCounter = 0;
|
|
92617
93587
|
AuditService = class {
|
|
92618
93588
|
entries = [];
|
|
@@ -92620,7 +93590,7 @@ var init_audit_service = __esm({
|
|
|
92620
93590
|
db;
|
|
92621
93591
|
setRepository(db) {
|
|
92622
93592
|
this.db = db;
|
|
92623
|
-
|
|
93593
|
+
log66.info("Audit persistence enabled \u2014 events will be written to DB");
|
|
92624
93594
|
}
|
|
92625
93595
|
record(entry) {
|
|
92626
93596
|
const full = {
|
|
@@ -92646,7 +93616,7 @@ var init_audit_service = __esm({
|
|
|
92646
93616
|
durationMs: full.durationMs,
|
|
92647
93617
|
success: full.success,
|
|
92648
93618
|
createdAt: new Date(full.timestamp)
|
|
92649
|
-
}).catch((err) =>
|
|
93619
|
+
}).catch((err) => log66.warn("Failed to persist audit entry", { id: full.id, error: String(err) }));
|
|
92650
93620
|
}
|
|
92651
93621
|
return full;
|
|
92652
93622
|
}
|
|
@@ -92729,12 +93699,12 @@ var init_audit_service = __esm({
|
|
|
92729
93699
|
});
|
|
92730
93700
|
|
|
92731
93701
|
// ../org-manager/dist/project-service.js
|
|
92732
|
-
var
|
|
93702
|
+
var log67, ProjectService;
|
|
92733
93703
|
var init_project_service = __esm({
|
|
92734
93704
|
"../org-manager/dist/project-service.js"() {
|
|
92735
93705
|
"use strict";
|
|
92736
93706
|
init_dist();
|
|
92737
|
-
|
|
93707
|
+
log67 = createLogger("project-service");
|
|
92738
93708
|
ProjectService = class {
|
|
92739
93709
|
projects = /* @__PURE__ */ new Map();
|
|
92740
93710
|
projectRepo;
|
|
@@ -92764,9 +93734,9 @@ var init_project_service = __esm({
|
|
|
92764
93734
|
};
|
|
92765
93735
|
this.projects.set(project.id, project);
|
|
92766
93736
|
}
|
|
92767
|
-
|
|
93737
|
+
log67.info(`Loaded ${this.projects.size} projects from DB`);
|
|
92768
93738
|
} catch (err) {
|
|
92769
|
-
|
|
93739
|
+
log67.warn("Failed to load projects from DB", { error: String(err) });
|
|
92770
93740
|
}
|
|
92771
93741
|
}
|
|
92772
93742
|
}
|
|
@@ -92803,8 +93773,8 @@ var init_project_service = __esm({
|
|
|
92803
93773
|
reportSchedule: project.reportSchedule,
|
|
92804
93774
|
onboardingConfig: project.onboardingConfig,
|
|
92805
93775
|
createdBy: opts.createdBy
|
|
92806
|
-
}).catch((err) =>
|
|
92807
|
-
|
|
93776
|
+
}).catch((err) => log67.warn("Failed to persist project", { error: String(err) }));
|
|
93777
|
+
log67.info("Project created", { id: project.id, name: project.name });
|
|
92808
93778
|
return project;
|
|
92809
93779
|
}
|
|
92810
93780
|
getProject(id) {
|
|
@@ -92819,14 +93789,14 @@ var init_project_service = __esm({
|
|
|
92819
93789
|
if (!project)
|
|
92820
93790
|
throw new Error(`Project not found: ${id}`);
|
|
92821
93791
|
Object.assign(project, updates, { updatedAt: (/* @__PURE__ */ new Date()).toISOString() });
|
|
92822
|
-
this.projectRepo?.update(id, updates).catch((err) =>
|
|
92823
|
-
|
|
93792
|
+
this.projectRepo?.update(id, updates).catch((err) => log67.warn("Failed to persist project update", { error: String(err) }));
|
|
93793
|
+
log67.info("Project updated", { id });
|
|
92824
93794
|
return project;
|
|
92825
93795
|
}
|
|
92826
93796
|
deleteProject(id) {
|
|
92827
93797
|
this.projects.delete(id);
|
|
92828
|
-
this.projectRepo?.delete(id).catch((err) =>
|
|
92829
|
-
|
|
93798
|
+
this.projectRepo?.delete(id).catch((err) => log67.warn("Failed to delete project from DB", { error: String(err) }));
|
|
93799
|
+
log67.info("Project deleted", { id });
|
|
92830
93800
|
}
|
|
92831
93801
|
// ─── Agent Onboarding ──────────────────────────────────────────────────────
|
|
92832
93802
|
async onboardAgent(agentId2, projectId) {
|
|
@@ -92851,7 +93821,7 @@ var init_project_service = __esm({
|
|
|
92851
93821
|
parts.push(`- Max pending tasks per agent: ${project.governancePolicy.maxPendingTasksPerAgent}`);
|
|
92852
93822
|
}
|
|
92853
93823
|
const onboardingDoc = parts.join("\n");
|
|
92854
|
-
|
|
93824
|
+
log67.info("Agent onboarded to project", { agentId: agentId2, projectId });
|
|
92855
93825
|
return onboardingDoc;
|
|
92856
93826
|
}
|
|
92857
93827
|
};
|
|
@@ -92859,12 +93829,12 @@ var init_project_service = __esm({
|
|
|
92859
93829
|
});
|
|
92860
93830
|
|
|
92861
93831
|
// ../org-manager/dist/requirement-service.js
|
|
92862
|
-
var
|
|
93832
|
+
var log68, RequirementService;
|
|
92863
93833
|
var init_requirement_service = __esm({
|
|
92864
93834
|
"../org-manager/dist/requirement-service.js"() {
|
|
92865
93835
|
"use strict";
|
|
92866
93836
|
init_dist();
|
|
92867
|
-
|
|
93837
|
+
log68 = createLogger("requirement-service");
|
|
92868
93838
|
RequirementService = class _RequirementService {
|
|
92869
93839
|
requirements = /* @__PURE__ */ new Map();
|
|
92870
93840
|
requirementRepo;
|
|
@@ -92945,7 +93915,7 @@ var init_requirement_service = __esm({
|
|
|
92945
93915
|
reason: reason ?? null
|
|
92946
93916
|
});
|
|
92947
93917
|
} catch (e) {
|
|
92948
|
-
|
|
93918
|
+
log68.warn("Failed to record requirement status transition", { reqId, from, to, error: String(e) });
|
|
92949
93919
|
}
|
|
92950
93920
|
}
|
|
92951
93921
|
getRequirementStatusHistory(reqId, limit = 50) {
|
|
@@ -93025,7 +93995,7 @@ var init_requirement_service = __esm({
|
|
|
93025
93995
|
approvedBy: req.approvedBy ?? void 0,
|
|
93026
93996
|
approvedAt: req.approvedAt ? new Date(req.approvedAt) : void 0,
|
|
93027
93997
|
tags: req.tags
|
|
93028
|
-
}).catch((e) =>
|
|
93998
|
+
}).catch((e) => log68.error("Failed to persist requirement", { id: req.id, error: String(e) }));
|
|
93029
93999
|
}
|
|
93030
94000
|
this.broadcast("requirement:created", req);
|
|
93031
94001
|
if (this.hitlService && req.source === "agent") {
|
|
@@ -93048,10 +94018,10 @@ var init_requirement_service = __esm({
|
|
|
93048
94018
|
this.rejectRequirement(req.id, result.respondedBy ?? "hitl", result.comment || "Rejected via approval");
|
|
93049
94019
|
}
|
|
93050
94020
|
}).catch((err) => {
|
|
93051
|
-
|
|
94021
|
+
log68.error("HITL approval flow error for requirement", { requirementId: req.id, error: String(err) });
|
|
93052
94022
|
});
|
|
93053
94023
|
}
|
|
93054
|
-
|
|
94024
|
+
log68.info("Requirement created", {
|
|
93055
94025
|
id: req.id,
|
|
93056
94026
|
source: req.source,
|
|
93057
94027
|
status: req.status,
|
|
@@ -93094,11 +94064,11 @@ var init_requirement_service = __esm({
|
|
|
93094
94064
|
req.approvedAt = now3;
|
|
93095
94065
|
req.updatedAt = now3;
|
|
93096
94066
|
if (this.requirementRepo) {
|
|
93097
|
-
this.requirementRepo.approve(id, userId2).catch((e) =>
|
|
94067
|
+
this.requirementRepo.approve(id, userId2).catch((e) => log68.error("Failed to persist requirement approval", { id, error: String(e) }));
|
|
93098
94068
|
}
|
|
93099
94069
|
this.recordTransition(id, oldStatus, "in_progress", userId2, "human", "Approved");
|
|
93100
94070
|
this.broadcast("requirement:approved", req);
|
|
93101
|
-
|
|
94071
|
+
log68.info("Requirement approved", { id, approvedBy: userId2 });
|
|
93102
94072
|
this.notifyCreatorOnDecision(req, "approved", userId2);
|
|
93103
94073
|
return req;
|
|
93104
94074
|
}
|
|
@@ -93125,11 +94095,11 @@ var init_requirement_service = __esm({
|
|
|
93125
94095
|
req.rejectedBy = userId2;
|
|
93126
94096
|
req.updatedAt = now3;
|
|
93127
94097
|
if (this.requirementRepo) {
|
|
93128
|
-
this.requirementRepo.reject(id, reason, userId2).catch((e) =>
|
|
94098
|
+
this.requirementRepo.reject(id, reason, userId2).catch((e) => log68.error("Failed to persist requirement rejection", { id, error: String(e) }));
|
|
93129
94099
|
}
|
|
93130
94100
|
this.recordTransition(id, oldStatus, "rejected", userId2, "human", reason);
|
|
93131
94101
|
this.broadcast("requirement:rejected", req);
|
|
93132
|
-
|
|
94102
|
+
log68.info("Requirement rejected", { id, reason });
|
|
93133
94103
|
this.notifyCreatorOnDecision(req, "rejected", userId2, reason);
|
|
93134
94104
|
return req;
|
|
93135
94105
|
}
|
|
@@ -93162,7 +94132,7 @@ var init_requirement_service = __esm({
|
|
|
93162
94132
|
req.updatedAt = now3;
|
|
93163
94133
|
this.recordTransition(id, oldStatus, "pending", req.createdBy, "agent", "Resubmitted");
|
|
93164
94134
|
if (this.requirementRepo) {
|
|
93165
|
-
const persistErr = (e) =>
|
|
94135
|
+
const persistErr = (e) => log68.error("Failed to persist requirement resubmission", { id, error: String(e) });
|
|
93166
94136
|
this.requirementRepo.updateStatus(id, "pending").catch(persistErr);
|
|
93167
94137
|
this.requirementRepo.clearRejectionMetadata(id).catch(persistErr);
|
|
93168
94138
|
if (updates) {
|
|
@@ -93170,7 +94140,7 @@ var init_requirement_service = __esm({
|
|
|
93170
94140
|
}
|
|
93171
94141
|
}
|
|
93172
94142
|
this.broadcast("requirement:resubmitted", req);
|
|
93173
|
-
|
|
94143
|
+
log68.info("Requirement resubmitted for review", { id, hasUpdates: !!updates });
|
|
93174
94144
|
if (this.hitlService && req.source === "agent") {
|
|
93175
94145
|
const creatorName = this.resolveAgentName(req.createdBy);
|
|
93176
94146
|
this.hitlService.requestApprovalAndWait({
|
|
@@ -93191,7 +94161,7 @@ var init_requirement_service = __esm({
|
|
|
93191
94161
|
this.rejectRequirement(req.id, result.respondedBy ?? "hitl", result.comment || "Rejected via approval");
|
|
93192
94162
|
}
|
|
93193
94163
|
}).catch((err) => {
|
|
93194
|
-
|
|
94164
|
+
log68.error("HITL approval flow error for resubmitted requirement", { requirementId: req.id, error: String(err) });
|
|
93195
94165
|
});
|
|
93196
94166
|
}
|
|
93197
94167
|
return req;
|
|
@@ -93227,7 +94197,7 @@ var init_requirement_service = __esm({
|
|
|
93227
94197
|
req.rejectedBy = void 0;
|
|
93228
94198
|
}
|
|
93229
94199
|
if (this.requirementRepo) {
|
|
93230
|
-
const persistErr = (e) =>
|
|
94200
|
+
const persistErr = (e) => log68.error("Failed to persist requirement status update", { id, error: String(e) });
|
|
93231
94201
|
if (newStatus === "in_progress" && oldStatus === "pending") {
|
|
93232
94202
|
this.requirementRepo.approve(id, req.approvedBy ?? "unknown").catch(persistErr);
|
|
93233
94203
|
} else if (newStatus === "rejected") {
|
|
@@ -93258,7 +94228,7 @@ var init_requirement_service = __esm({
|
|
|
93258
94228
|
const resolvedActorType = actorType ?? (userId2 ? "human" : "system");
|
|
93259
94229
|
this.recordTransition(id, oldStatus, newStatus, userId2, resolvedActorType);
|
|
93260
94230
|
this.broadcast("requirement:updated", req);
|
|
93261
|
-
|
|
94231
|
+
log68.info("Requirement status updated", { id, from: oldStatus, to: newStatus });
|
|
93262
94232
|
return req;
|
|
93263
94233
|
}
|
|
93264
94234
|
/**
|
|
@@ -93278,7 +94248,7 @@ var init_requirement_service = __esm({
|
|
|
93278
94248
|
req.tags = data.tags;
|
|
93279
94249
|
req.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
93280
94250
|
if (this.requirementRepo) {
|
|
93281
|
-
this.requirementRepo.update(id, data).catch((e) =>
|
|
94251
|
+
this.requirementRepo.update(id, data).catch((e) => log68.error("Failed to persist requirement update", { id, error: String(e) }));
|
|
93282
94252
|
}
|
|
93283
94253
|
this.broadcast("requirement:updated", req);
|
|
93284
94254
|
return req;
|
|
@@ -93360,11 +94330,11 @@ var init_requirement_service = __esm({
|
|
|
93360
94330
|
req.status = "cancelled";
|
|
93361
94331
|
req.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
93362
94332
|
if (this.requirementRepo) {
|
|
93363
|
-
this.requirementRepo.updateStatus(id, "cancelled").catch((e) =>
|
|
94333
|
+
this.requirementRepo.updateStatus(id, "cancelled").catch((e) => log68.error("Failed to persist requirement cancellation", { id, error: String(e) }));
|
|
93364
94334
|
}
|
|
93365
94335
|
this.recordTransition(id, oldStatus, "cancelled", cancelledBy, cancelledByType ?? "system", "Cancelled");
|
|
93366
94336
|
this.broadcast("requirement:cancelled", req);
|
|
93367
|
-
|
|
94337
|
+
log68.info("Requirement cancelled", { id });
|
|
93368
94338
|
return req;
|
|
93369
94339
|
}
|
|
93370
94340
|
getRequirement(id) {
|
|
@@ -93421,9 +94391,9 @@ var init_requirement_service = __esm({
|
|
|
93421
94391
|
};
|
|
93422
94392
|
this.requirements.set(req.id, req);
|
|
93423
94393
|
}
|
|
93424
|
-
|
|
94394
|
+
log68.info("Loaded requirements from storage", { orgId: orgId2, count: rows.length });
|
|
93425
94395
|
} catch (e) {
|
|
93426
|
-
|
|
94396
|
+
log68.error("Failed to load requirements from storage", { orgId: orgId2, error: String(e) });
|
|
93427
94397
|
}
|
|
93428
94398
|
}
|
|
93429
94399
|
/**
|
|
@@ -93445,7 +94415,7 @@ var init_requirement_service = __esm({
|
|
|
93445
94415
|
}
|
|
93446
94416
|
const linked = [...this.requirements.values()].filter((r) => r.taskIds.length > 0).length;
|
|
93447
94417
|
if (linked > 0) {
|
|
93448
|
-
|
|
94418
|
+
log68.info("Rebuilt requirement-task links", { linkedRequirements: linked });
|
|
93449
94419
|
}
|
|
93450
94420
|
}
|
|
93451
94421
|
deleteRequirement(id) {
|
|
@@ -93454,7 +94424,7 @@ var init_requirement_service = __esm({
|
|
|
93454
94424
|
}
|
|
93455
94425
|
this.requirements.delete(id);
|
|
93456
94426
|
if (this.requirementRepo) {
|
|
93457
|
-
this.requirementRepo.delete(id).catch((e) =>
|
|
94427
|
+
this.requirementRepo.delete(id).catch((e) => log68.error("Failed to delete requirement from storage", { id, error: String(e) }));
|
|
93458
94428
|
}
|
|
93459
94429
|
}
|
|
93460
94430
|
/**
|
|
@@ -93503,7 +94473,7 @@ var init_requirement_service = __esm({
|
|
|
93503
94473
|
priority: 1,
|
|
93504
94474
|
metadata: { senderName: "System", senderRole: "manager" }
|
|
93505
94475
|
});
|
|
93506
|
-
|
|
94476
|
+
log68.info("Notified creator agent about requirement decision", {
|
|
93507
94477
|
requirementId: req.id,
|
|
93508
94478
|
creatorId,
|
|
93509
94479
|
decision
|
|
@@ -93548,12 +94518,12 @@ var init_requirement_service = __esm({
|
|
|
93548
94518
|
});
|
|
93549
94519
|
|
|
93550
94520
|
// ../org-manager/dist/knowledge-service.js
|
|
93551
|
-
var
|
|
94521
|
+
var log69, KnowledgeService;
|
|
93552
94522
|
var init_knowledge_service = __esm({
|
|
93553
94523
|
"../org-manager/dist/knowledge-service.js"() {
|
|
93554
94524
|
"use strict";
|
|
93555
94525
|
init_dist();
|
|
93556
|
-
|
|
94526
|
+
log69 = createLogger("knowledge-service");
|
|
93557
94527
|
KnowledgeService = class {
|
|
93558
94528
|
entries = /* @__PURE__ */ new Map();
|
|
93559
94529
|
fileStore;
|
|
@@ -93563,7 +94533,7 @@ var init_knowledge_service = __esm({
|
|
|
93563
94533
|
for (const entry of fileStore.loadAll()) {
|
|
93564
94534
|
this.entries.set(entry.id, entry);
|
|
93565
94535
|
}
|
|
93566
|
-
|
|
94536
|
+
log69.info("Knowledge loaded from file store", { count: this.entries.size });
|
|
93567
94537
|
}
|
|
93568
94538
|
}
|
|
93569
94539
|
/** Returns the absolute file path of a knowledge entry (for agent file_read). */
|
|
@@ -93608,7 +94578,7 @@ var init_knowledge_service = __esm({
|
|
|
93608
94578
|
}
|
|
93609
94579
|
}
|
|
93610
94580
|
this.persistScope(entry.scope, entry.scopeId);
|
|
93611
|
-
|
|
94581
|
+
log69.info("Knowledge contributed", {
|
|
93612
94582
|
id: entry.id,
|
|
93613
94583
|
scope: entry.scope,
|
|
93614
94584
|
category: entry.category,
|
|
@@ -93686,7 +94656,7 @@ var init_knowledge_service = __esm({
|
|
|
93686
94656
|
entry.status = "outdated";
|
|
93687
94657
|
entry.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
93688
94658
|
this.persistScope(entry.scope, entry.scopeId);
|
|
93689
|
-
|
|
94659
|
+
log69.info("Knowledge flagged as outdated", { id, reason });
|
|
93690
94660
|
}
|
|
93691
94661
|
flagDisputed(id, reason) {
|
|
93692
94662
|
const entry = this.entries.get(id);
|
|
@@ -93695,7 +94665,7 @@ var init_knowledge_service = __esm({
|
|
|
93695
94665
|
entry.status = "disputed";
|
|
93696
94666
|
entry.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
93697
94667
|
this.persistScope(entry.scope, entry.scopeId);
|
|
93698
|
-
|
|
94668
|
+
log69.info("Knowledge flagged as disputed", { id, reason });
|
|
93699
94669
|
}
|
|
93700
94670
|
verify(id, verifiedBy) {
|
|
93701
94671
|
const entry = this.entries.get(id);
|
|
@@ -93705,7 +94675,7 @@ var init_knowledge_service = __esm({
|
|
|
93705
94675
|
entry.verifiedBy = verifiedBy;
|
|
93706
94676
|
entry.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
93707
94677
|
this.persistScope(entry.scope, entry.scopeId);
|
|
93708
|
-
|
|
94678
|
+
log69.info("Knowledge verified", { id, verifiedBy });
|
|
93709
94679
|
}
|
|
93710
94680
|
// ─── Metrics ───────────────────────────────────────────────────────────────
|
|
93711
94681
|
getContributions(scopeId, periodStart, periodEnd) {
|
|
@@ -93729,8 +94699,8 @@ var init_knowledge_service = __esm({
|
|
|
93729
94699
|
});
|
|
93730
94700
|
|
|
93731
94701
|
// ../org-manager/dist/file-knowledge-store.js
|
|
93732
|
-
import { readFileSync as
|
|
93733
|
-
import { join as
|
|
94702
|
+
import { readFileSync as readFileSync25, writeFileSync as writeFileSync20, existsSync as existsSync32, mkdirSync as mkdirSync22, readdirSync as readdirSync12, unlinkSync as unlinkSync3 } from "node:fs";
|
|
94703
|
+
import { join as join27 } from "node:path";
|
|
93734
94704
|
function readdirSafe(dir) {
|
|
93735
94705
|
try {
|
|
93736
94706
|
return readdirSync12(dir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
|
|
@@ -93738,62 +94708,62 @@ function readdirSafe(dir) {
|
|
|
93738
94708
|
return [];
|
|
93739
94709
|
}
|
|
93740
94710
|
}
|
|
93741
|
-
var
|
|
94711
|
+
var log70, FileKnowledgeStore;
|
|
93742
94712
|
var init_file_knowledge_store = __esm({
|
|
93743
94713
|
"../org-manager/dist/file-knowledge-store.js"() {
|
|
93744
94714
|
"use strict";
|
|
93745
94715
|
init_dist();
|
|
93746
|
-
|
|
94716
|
+
log70 = createLogger("file-knowledge-store");
|
|
93747
94717
|
FileKnowledgeStore = class {
|
|
93748
94718
|
baseDir;
|
|
93749
94719
|
constructor(baseDir) {
|
|
93750
94720
|
this.baseDir = baseDir;
|
|
93751
|
-
|
|
94721
|
+
mkdirSync22(baseDir, { recursive: true });
|
|
93752
94722
|
}
|
|
93753
94723
|
scopeDir(scope, scopeId) {
|
|
93754
|
-
return
|
|
94724
|
+
return join27(this.baseDir, scope, scopeId);
|
|
93755
94725
|
}
|
|
93756
94726
|
indexPath(scope, scopeId) {
|
|
93757
|
-
return
|
|
94727
|
+
return join27(this.scopeDir(scope, scopeId), "_index.json");
|
|
93758
94728
|
}
|
|
93759
94729
|
entryPath(entry) {
|
|
93760
|
-
return
|
|
94730
|
+
return join27(this.scopeDir(entry.scope, entry.scopeId), `${entry.id}.json`);
|
|
93761
94731
|
}
|
|
93762
94732
|
// ─── Load ────────────────────────────────────────────────────────────────
|
|
93763
94733
|
loadAll() {
|
|
93764
94734
|
const entries2 = [];
|
|
93765
|
-
if (!
|
|
94735
|
+
if (!existsSync32(this.baseDir))
|
|
93766
94736
|
return entries2;
|
|
93767
94737
|
for (const scope of readdirSafe(this.baseDir)) {
|
|
93768
|
-
const scopePath =
|
|
94738
|
+
const scopePath = join27(this.baseDir, scope);
|
|
93769
94739
|
for (const scopeId of readdirSafe(scopePath)) {
|
|
93770
|
-
const idxPath =
|
|
93771
|
-
if (!
|
|
94740
|
+
const idxPath = join27(scopePath, scopeId, "_index.json");
|
|
94741
|
+
if (!existsSync32(idxPath))
|
|
93772
94742
|
continue;
|
|
93773
94743
|
try {
|
|
93774
|
-
const data = JSON.parse(
|
|
94744
|
+
const data = JSON.parse(readFileSync25(idxPath, "utf-8"));
|
|
93775
94745
|
entries2.push(...data);
|
|
93776
94746
|
} catch (err) {
|
|
93777
|
-
|
|
94747
|
+
log70.warn("Failed to load index", { path: idxPath, error: String(err) });
|
|
93778
94748
|
}
|
|
93779
94749
|
}
|
|
93780
94750
|
}
|
|
93781
|
-
|
|
94751
|
+
log70.info("Knowledge loaded from disk", { count: entries2.length });
|
|
93782
94752
|
return entries2;
|
|
93783
94753
|
}
|
|
93784
94754
|
// ─── Write ───────────────────────────────────────────────────────────────
|
|
93785
94755
|
saveEntry(entry) {
|
|
93786
94756
|
const dir = this.scopeDir(entry.scope, entry.scopeId);
|
|
93787
|
-
|
|
93788
|
-
|
|
94757
|
+
mkdirSync22(dir, { recursive: true });
|
|
94758
|
+
writeFileSync20(join27(dir, `${entry.id}.json`), JSON.stringify(entry, null, 2));
|
|
93789
94759
|
}
|
|
93790
94760
|
saveIndex(scope, scopeId, entries2) {
|
|
93791
94761
|
const dir = this.scopeDir(scope, scopeId);
|
|
93792
|
-
|
|
93793
|
-
|
|
94762
|
+
mkdirSync22(dir, { recursive: true });
|
|
94763
|
+
writeFileSync20(join27(dir, "_index.json"), JSON.stringify(entries2, null, 2));
|
|
93794
94764
|
}
|
|
93795
94765
|
removeEntryFile(entry) {
|
|
93796
|
-
const p =
|
|
94766
|
+
const p = join27(this.scopeDir(entry.scope, entry.scopeId), `${entry.id}.json`);
|
|
93797
94767
|
try {
|
|
93798
94768
|
unlinkSync3(p);
|
|
93799
94769
|
} catch {
|
|
@@ -93816,17 +94786,17 @@ var init_file_knowledge_store = __esm({
|
|
|
93816
94786
|
});
|
|
93817
94787
|
|
|
93818
94788
|
// ../org-manager/dist/deliverable-service.js
|
|
93819
|
-
import { existsSync as
|
|
93820
|
-
import { join as
|
|
94789
|
+
import { existsSync as existsSync33, cpSync as cpSync3, mkdirSync as mkdirSync23 } from "node:fs";
|
|
94790
|
+
import { join as join28, basename } from "node:path";
|
|
93821
94791
|
function isUrl(s2) {
|
|
93822
94792
|
return /^https?:\/\//i.test(s2);
|
|
93823
94793
|
}
|
|
93824
|
-
var
|
|
94794
|
+
var log71, DeliverableService;
|
|
93825
94795
|
var init_deliverable_service = __esm({
|
|
93826
94796
|
"../org-manager/dist/deliverable-service.js"() {
|
|
93827
94797
|
"use strict";
|
|
93828
94798
|
init_dist();
|
|
93829
|
-
|
|
94799
|
+
log71 = createLogger("deliverable-service");
|
|
93830
94800
|
DeliverableService = class {
|
|
93831
94801
|
repo;
|
|
93832
94802
|
cache = /* @__PURE__ */ new Map();
|
|
@@ -93844,7 +94814,7 @@ var init_deliverable_service = __esm({
|
|
|
93844
94814
|
for (const r of rows) {
|
|
93845
94815
|
this.cache.set(r.id, this.rowToDeliverable(r));
|
|
93846
94816
|
}
|
|
93847
|
-
|
|
94817
|
+
log71.info("Deliverables loaded", { count: this.cache.size });
|
|
93848
94818
|
}
|
|
93849
94819
|
async create(opts) {
|
|
93850
94820
|
const ref = opts.reference?.trim();
|
|
@@ -93870,7 +94840,7 @@ var init_deliverable_service = __esm({
|
|
|
93870
94840
|
if (opts.taskId && !existing.taskId)
|
|
93871
94841
|
patch.taskId = opts.taskId;
|
|
93872
94842
|
const updated = await this.update(existing.id, patch);
|
|
93873
|
-
|
|
94843
|
+
log71.info("Deliverable upserted (updated existing)", { id: existing.id, reference: ref });
|
|
93874
94844
|
this.ws?.broadcastDeliverableUpdate(existing.id, "updated", {
|
|
93875
94845
|
type: opts.type,
|
|
93876
94846
|
title: opts.title,
|
|
@@ -93923,7 +94893,7 @@ var init_deliverable_service = __esm({
|
|
|
93923
94893
|
testResults: opts.testResults
|
|
93924
94894
|
});
|
|
93925
94895
|
this.cache.set(id, deliverable);
|
|
93926
|
-
|
|
94896
|
+
log71.info("Deliverable created", { id, type: opts.type, title: opts.title });
|
|
93927
94897
|
this.ws?.broadcastDeliverableUpdate(id, "created", {
|
|
93928
94898
|
type: opts.type,
|
|
93929
94899
|
title: opts.title,
|
|
@@ -94020,7 +94990,7 @@ var init_deliverable_service = __esm({
|
|
|
94020
94990
|
if (data.testResults !== void 0 && !arrEq(data.testResults, d.testResults))
|
|
94021
94991
|
changed.push("testResults");
|
|
94022
94992
|
if (changed.length === 0) {
|
|
94023
|
-
|
|
94993
|
+
log71.debug("Deliverable update skipped (no-op)", { id });
|
|
94024
94994
|
return d;
|
|
94025
94995
|
}
|
|
94026
94996
|
const now3 = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -94054,7 +95024,7 @@ var init_deliverable_service = __esm({
|
|
|
94054
95024
|
d.testResults = data.testResults;
|
|
94055
95025
|
d.updatedAt = now3;
|
|
94056
95026
|
await this.repo?.update(id, data);
|
|
94057
|
-
|
|
95027
|
+
log71.info("Deliverable updated", { id, fields: changed });
|
|
94058
95028
|
this.ws?.broadcastDeliverableUpdate(id, "updated", {
|
|
94059
95029
|
type: d.type,
|
|
94060
95030
|
title: d.title,
|
|
@@ -94071,7 +95041,7 @@ var init_deliverable_service = __esm({
|
|
|
94071
95041
|
d.status = "outdated";
|
|
94072
95042
|
d.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
94073
95043
|
await this.repo?.update(id, { status: "outdated" });
|
|
94074
|
-
|
|
95044
|
+
log71.info("Deliverable flagged outdated", { id });
|
|
94075
95045
|
this.ws?.broadcastDeliverableUpdate(id, "removed", {
|
|
94076
95046
|
type: d.type,
|
|
94077
95047
|
title: d.title,
|
|
@@ -94133,7 +95103,7 @@ var init_deliverable_service = __esm({
|
|
|
94133
95103
|
}
|
|
94134
95104
|
}
|
|
94135
95105
|
if (cleaned > 0) {
|
|
94136
|
-
|
|
95106
|
+
log71.info("Deduplicated deliverables by reference", { cleaned });
|
|
94137
95107
|
}
|
|
94138
95108
|
return cleaned;
|
|
94139
95109
|
}
|
|
@@ -94146,30 +95116,30 @@ var init_deliverable_service = __esm({
|
|
|
94146
95116
|
const deliverables = this.findByAgent(agentId2);
|
|
94147
95117
|
if (deliverables.length === 0)
|
|
94148
95118
|
return 0;
|
|
94149
|
-
const sharedDeliverables =
|
|
95119
|
+
const sharedDeliverables = join28(sharedDataDir, "deliverables");
|
|
94150
95120
|
let migrated = 0;
|
|
94151
95121
|
for (const d of deliverables) {
|
|
94152
95122
|
if (!d.reference || isUrl(d.reference))
|
|
94153
95123
|
continue;
|
|
94154
95124
|
if (!d.reference.startsWith(agentDir + "/") && d.reference !== agentDir)
|
|
94155
95125
|
continue;
|
|
94156
|
-
if (!
|
|
95126
|
+
if (!existsSync33(d.reference))
|
|
94157
95127
|
continue;
|
|
94158
95128
|
try {
|
|
94159
|
-
const destDir =
|
|
94160
|
-
|
|
95129
|
+
const destDir = join28(sharedDeliverables, d.id);
|
|
95130
|
+
mkdirSync23(destDir, { recursive: true });
|
|
94161
95131
|
const fileName = basename(d.reference);
|
|
94162
|
-
const destPath =
|
|
95132
|
+
const destPath = join28(destDir, fileName);
|
|
94163
95133
|
cpSync3(d.reference, destPath, { recursive: true });
|
|
94164
95134
|
await this.update(d.id, { reference: destPath });
|
|
94165
95135
|
migrated++;
|
|
94166
|
-
|
|
95136
|
+
log71.info("Deliverable file migrated to shared", { id: d.id, from: d.reference, to: destPath });
|
|
94167
95137
|
} catch (err) {
|
|
94168
|
-
|
|
95138
|
+
log71.warn("Failed to migrate deliverable file", { id: d.id, reference: d.reference, error: String(err) });
|
|
94169
95139
|
}
|
|
94170
95140
|
}
|
|
94171
95141
|
if (migrated > 0) {
|
|
94172
|
-
|
|
95142
|
+
log71.info("Migrated agent deliverable files to shared directory", { agentId: agentId2, migrated, total: deliverables.length });
|
|
94173
95143
|
}
|
|
94174
95144
|
return migrated;
|
|
94175
95145
|
}
|
|
@@ -94183,7 +95153,7 @@ var init_deliverable_service = __esm({
|
|
|
94183
95153
|
for (const d of deliverables) {
|
|
94184
95154
|
if (!d.reference || isUrl(d.reference))
|
|
94185
95155
|
continue;
|
|
94186
|
-
if (!
|
|
95156
|
+
if (!existsSync33(d.reference)) {
|
|
94187
95157
|
missing.push(d.id);
|
|
94188
95158
|
}
|
|
94189
95159
|
}
|
|
@@ -94205,7 +95175,7 @@ var init_deliverable_service = __esm({
|
|
|
94205
95175
|
}
|
|
94206
95176
|
}
|
|
94207
95177
|
if (branchCleaned > 0) {
|
|
94208
|
-
|
|
95178
|
+
log71.info("Cleaned up legacy branch-type deliverables", { count: branchCleaned });
|
|
94209
95179
|
}
|
|
94210
95180
|
const existingTaskIds = this.repo ? await this.repo.listTaskIdsWithDeliverables() : new Set([...this.cache.values()].map((d) => d.taskId).filter(Boolean));
|
|
94211
95181
|
let migrated = 0;
|
|
@@ -94232,12 +95202,12 @@ var init_deliverable_service = __esm({
|
|
|
94232
95202
|
});
|
|
94233
95203
|
migrated++;
|
|
94234
95204
|
} catch (err) {
|
|
94235
|
-
|
|
95205
|
+
log71.warn("Failed to migrate task deliverable", { taskId: task.id, ref: d.reference, error: String(err) });
|
|
94236
95206
|
}
|
|
94237
95207
|
}
|
|
94238
95208
|
}
|
|
94239
95209
|
if (migrated > 0) {
|
|
94240
|
-
|
|
95210
|
+
log71.info("Migrated task deliverables to unified table", { migrated });
|
|
94241
95211
|
}
|
|
94242
95212
|
return migrated;
|
|
94243
95213
|
}
|
|
@@ -94292,12 +95262,12 @@ var init_deliverable_service = __esm({
|
|
|
94292
95262
|
});
|
|
94293
95263
|
|
|
94294
95264
|
// ../org-manager/dist/report-service.js
|
|
94295
|
-
var
|
|
95265
|
+
var log72, ReportService;
|
|
94296
95266
|
var init_report_service = __esm({
|
|
94297
95267
|
"../org-manager/dist/report-service.js"() {
|
|
94298
95268
|
"use strict";
|
|
94299
95269
|
init_dist();
|
|
94300
|
-
|
|
95270
|
+
log72 = createLogger("report-service");
|
|
94301
95271
|
ReportService = class {
|
|
94302
95272
|
taskService;
|
|
94303
95273
|
billingService;
|
|
@@ -94350,7 +95320,7 @@ var init_report_service = __esm({
|
|
|
94350
95320
|
generatedBy: opts.generatedBy ?? "system"
|
|
94351
95321
|
};
|
|
94352
95322
|
this.reports.set(report.id, report);
|
|
94353
|
-
|
|
95323
|
+
log72.info("Report generated", { id: report.id, type: report.type, scope: report.scope });
|
|
94354
95324
|
return report;
|
|
94355
95325
|
}
|
|
94356
95326
|
getReport(id) {
|
|
@@ -94372,7 +95342,7 @@ var init_report_service = __esm({
|
|
|
94372
95342
|
if (!report?.upcomingPlan)
|
|
94373
95343
|
throw new Error("Report has no plan");
|
|
94374
95344
|
report.upcomingPlan.status = "pending";
|
|
94375
|
-
|
|
95345
|
+
log72.info("Plan submitted for approval", { reportId });
|
|
94376
95346
|
}
|
|
94377
95347
|
approvePlan(reportId, userId2) {
|
|
94378
95348
|
const report = this.reports.get(reportId);
|
|
@@ -94399,7 +95369,7 @@ var init_report_service = __esm({
|
|
|
94399
95369
|
projectId: report.scope === "project" ? report.scopeId : void 0
|
|
94400
95370
|
});
|
|
94401
95371
|
}
|
|
94402
|
-
|
|
95372
|
+
log72.info("Plan approved \u2014 tasks created", {
|
|
94403
95373
|
reportId,
|
|
94404
95374
|
taskCount: report.upcomingPlan.plannedTasks.length
|
|
94405
95375
|
});
|
|
@@ -94411,7 +95381,7 @@ var init_report_service = __esm({
|
|
|
94411
95381
|
throw new Error("Report has no plan");
|
|
94412
95382
|
report.upcomingPlan.status = "rejected";
|
|
94413
95383
|
report.upcomingPlan.rejectionReason = reason;
|
|
94414
|
-
|
|
95384
|
+
log72.info("Plan rejected", { reportId, reason });
|
|
94415
95385
|
return report;
|
|
94416
95386
|
}
|
|
94417
95387
|
// ─── Feedback ──────────────────────────────────────────────────────────────
|
|
@@ -94463,7 +95433,7 @@ var init_report_service = __esm({
|
|
|
94463
95433
|
const existing = this.feedbackStore.get(opts.reportId) ?? [];
|
|
94464
95434
|
existing.push(feedback);
|
|
94465
95435
|
this.feedbackStore.set(opts.reportId, existing);
|
|
94466
|
-
|
|
95436
|
+
log72.info("Feedback added to report", {
|
|
94467
95437
|
reportId: opts.reportId,
|
|
94468
95438
|
type: opts.type,
|
|
94469
95439
|
disclosure: opts.disclosure.scope
|
|
@@ -94548,12 +95518,12 @@ var init_report_service = __esm({
|
|
|
94548
95518
|
});
|
|
94549
95519
|
|
|
94550
95520
|
// ../org-manager/dist/trust-service.js
|
|
94551
|
-
var
|
|
95521
|
+
var log73, TrustService;
|
|
94552
95522
|
var init_trust_service = __esm({
|
|
94553
95523
|
"../org-manager/dist/trust-service.js"() {
|
|
94554
95524
|
"use strict";
|
|
94555
95525
|
init_dist();
|
|
94556
|
-
|
|
95526
|
+
log73 = createLogger("trust-service");
|
|
94557
95527
|
TrustService = class {
|
|
94558
95528
|
trustLevels = /* @__PURE__ */ new Map();
|
|
94559
95529
|
getOrCreate(agentId2) {
|
|
@@ -94602,7 +95572,7 @@ var init_trust_service = __esm({
|
|
|
94602
95572
|
trust.level = this.scoreToLevel(trust.score, trust.totalDeliveries);
|
|
94603
95573
|
trust.lastEvaluatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
94604
95574
|
if (trust.level !== oldLevel) {
|
|
94605
|
-
|
|
95575
|
+
log73.info("Trust level changed", {
|
|
94606
95576
|
agentId: trust.agentId,
|
|
94607
95577
|
oldLevel,
|
|
94608
95578
|
newLevel: trust.level,
|
|
@@ -94647,12 +95617,12 @@ var init_trust_service = __esm({
|
|
|
94647
95617
|
});
|
|
94648
95618
|
|
|
94649
95619
|
// ../org-manager/dist/archive-service.js
|
|
94650
|
-
var
|
|
95620
|
+
var log74, ARCHIVABLE_STATUSES, ACTIVE_DISCUSSION_DAYS, ACTIVE_DISCUSSION_MS, ArchiveService;
|
|
94651
95621
|
var init_archive_service = __esm({
|
|
94652
95622
|
"../org-manager/dist/archive-service.js"() {
|
|
94653
95623
|
"use strict";
|
|
94654
95624
|
init_dist();
|
|
94655
|
-
|
|
95625
|
+
log74 = createLogger("archive-service");
|
|
94656
95626
|
ARCHIVABLE_STATUSES = /* @__PURE__ */ new Set(["completed", "failed", "rejected", "cancelled"]);
|
|
94657
95627
|
ACTIVE_DISCUSSION_DAYS = 7;
|
|
94658
95628
|
ACTIVE_DISCUSSION_MS = ACTIVE_DISCUSSION_DAYS * 864e5;
|
|
@@ -94673,11 +95643,11 @@ var init_archive_service = __esm({
|
|
|
94673
95643
|
* then repeats at the configured interval.
|
|
94674
95644
|
*/
|
|
94675
95645
|
start(intervalMs = ARCHIVE_SCAN_INTERVAL_MS) {
|
|
94676
|
-
this.runArchiveScan().catch((err) =>
|
|
95646
|
+
this.runArchiveScan().catch((err) => log74.warn("Initial archive scan failed", { error: String(err) }));
|
|
94677
95647
|
this.scanInterval = setInterval(() => {
|
|
94678
|
-
this.runArchiveScan().catch((err) =>
|
|
95648
|
+
this.runArchiveScan().catch((err) => log74.warn("Archive scan failed", { error: String(err) }));
|
|
94679
95649
|
}, intervalMs);
|
|
94680
|
-
|
|
95650
|
+
log74.info("Archive service started", { intervalMs });
|
|
94681
95651
|
}
|
|
94682
95652
|
stop() {
|
|
94683
95653
|
if (this.scanInterval) {
|
|
@@ -94689,7 +95659,7 @@ var init_archive_service = __esm({
|
|
|
94689
95659
|
const archivedTasks = await this.archiveTasks();
|
|
94690
95660
|
const archivedRequirements = this.archiveRequirements();
|
|
94691
95661
|
if (archivedTasks > 0 || archivedRequirements > 0) {
|
|
94692
|
-
|
|
95662
|
+
log74.info("Archive scan complete", { archivedTasks, archivedRequirements });
|
|
94693
95663
|
}
|
|
94694
95664
|
return { archivedTasks, archivedRequirements };
|
|
94695
95665
|
}
|
|
@@ -94712,7 +95682,7 @@ var init_archive_service = __esm({
|
|
|
94712
95682
|
this.taskService.archiveTask(task.id);
|
|
94713
95683
|
archived++;
|
|
94714
95684
|
} catch (err) {
|
|
94715
|
-
|
|
95685
|
+
log74.warn("Failed to archive task", { taskId: task.id, error: String(err) });
|
|
94716
95686
|
}
|
|
94717
95687
|
}
|
|
94718
95688
|
}
|
|
@@ -94737,7 +95707,7 @@ var init_archive_service = __esm({
|
|
|
94737
95707
|
this.requirementService.updateRequirementStatus(req.id, "archived");
|
|
94738
95708
|
archived++;
|
|
94739
95709
|
} catch (err) {
|
|
94740
|
-
|
|
95710
|
+
log74.warn("Failed to archive requirement", { requirementId: req.id, error: String(err) });
|
|
94741
95711
|
}
|
|
94742
95712
|
}
|
|
94743
95713
|
}
|
|
@@ -94779,12 +95749,12 @@ var init_archive_service = __esm({
|
|
|
94779
95749
|
});
|
|
94780
95750
|
|
|
94781
95751
|
// ../org-manager/dist/stale-detector.js
|
|
94782
|
-
var
|
|
95752
|
+
var log75, DEFAULT_CONFIG4, StaleDetector;
|
|
94783
95753
|
var init_stale_detector = __esm({
|
|
94784
95754
|
"../org-manager/dist/stale-detector.js"() {
|
|
94785
95755
|
"use strict";
|
|
94786
95756
|
init_dist();
|
|
94787
|
-
|
|
95757
|
+
log75 = createLogger("stale-detector");
|
|
94788
95758
|
DEFAULT_CONFIG4 = {
|
|
94789
95759
|
maxInProgressMs: 24 * 60 * 60 * 1e3,
|
|
94790
95760
|
maxReviewWaitMs: 12 * 60 * 60 * 1e3,
|
|
@@ -94807,9 +95777,9 @@ var init_stale_detector = __esm({
|
|
|
94807
95777
|
if (items.length > 0 && this.onStaleItems) {
|
|
94808
95778
|
this.onStaleItems(items);
|
|
94809
95779
|
}
|
|
94810
|
-
}).catch((err) =>
|
|
95780
|
+
}).catch((err) => log75.warn("Stale scan failed", { error: String(err) }));
|
|
94811
95781
|
}, intervalMs);
|
|
94812
|
-
|
|
95782
|
+
log75.info("Stale detector started", { intervalMs });
|
|
94813
95783
|
}
|
|
94814
95784
|
stop() {
|
|
94815
95785
|
if (this.scanInterval) {
|
|
@@ -94852,7 +95822,7 @@ var init_stale_detector = __esm({
|
|
|
94852
95822
|
}
|
|
94853
95823
|
}
|
|
94854
95824
|
if (staleItems.length > 0) {
|
|
94855
|
-
|
|
95825
|
+
log75.info(`Found ${staleItems.length} stale items`);
|
|
94856
95826
|
}
|
|
94857
95827
|
return staleItems;
|
|
94858
95828
|
}
|
|
@@ -94861,12 +95831,12 @@ var init_stale_detector = __esm({
|
|
|
94861
95831
|
});
|
|
94862
95832
|
|
|
94863
95833
|
// ../org-manager/dist/scheduled-task-runner.js
|
|
94864
|
-
var
|
|
95834
|
+
var log76, MIN_STAGGER_MS, MAX_STAGGER_MS, ScheduledTaskRunner;
|
|
94865
95835
|
var init_scheduled_task_runner = __esm({
|
|
94866
95836
|
"../org-manager/dist/scheduled-task-runner.js"() {
|
|
94867
95837
|
"use strict";
|
|
94868
95838
|
init_dist();
|
|
94869
|
-
|
|
95839
|
+
log76 = createLogger("scheduled-task-runner");
|
|
94870
95840
|
MIN_STAGGER_MS = 2 * 6e4;
|
|
94871
95841
|
MAX_STAGGER_MS = 15 * 6e4;
|
|
94872
95842
|
ScheduledTaskRunner = class {
|
|
@@ -94885,11 +95855,11 @@ var init_scheduled_task_runner = __esm({
|
|
|
94885
95855
|
return;
|
|
94886
95856
|
this.running = true;
|
|
94887
95857
|
this.startedAt = Date.now();
|
|
94888
|
-
this.tick().catch((e) =>
|
|
95858
|
+
this.tick().catch((e) => log76.error("Initial scheduled task tick failed", { error: String(e) }));
|
|
94889
95859
|
this.timer = setInterval(() => {
|
|
94890
|
-
this.tick().catch((e) =>
|
|
95860
|
+
this.tick().catch((e) => log76.error("Scheduled task tick failed", { error: String(e) }));
|
|
94891
95861
|
}, this.pollIntervalMs);
|
|
94892
|
-
|
|
95862
|
+
log76.info("ScheduledTaskRunner started", { pollIntervalMs: this.pollIntervalMs });
|
|
94893
95863
|
}
|
|
94894
95864
|
stop() {
|
|
94895
95865
|
if (this.timer) {
|
|
@@ -94900,7 +95870,7 @@ var init_scheduled_task_runner = __esm({
|
|
|
94900
95870
|
clearTimeout(t);
|
|
94901
95871
|
this.staggerTimers = [];
|
|
94902
95872
|
this.running = false;
|
|
94903
|
-
|
|
95873
|
+
log76.info("ScheduledTaskRunner stopped");
|
|
94904
95874
|
}
|
|
94905
95875
|
isRunning() {
|
|
94906
95876
|
return this.running;
|
|
@@ -94934,7 +95904,7 @@ var init_scheduled_task_runner = __esm({
|
|
|
94934
95904
|
}
|
|
94935
95905
|
if (startup && nextRun < this.startedAt) {
|
|
94936
95906
|
const delay = MIN_STAGGER_MS + Math.random() * (MAX_STAGGER_MS - MIN_STAGGER_MS);
|
|
94937
|
-
|
|
95907
|
+
log76.info("Staggering overdue scheduled task", {
|
|
94938
95908
|
taskId: task.id,
|
|
94939
95909
|
title: task.title,
|
|
94940
95910
|
overdueBy: `${Math.round((now3 - nextRun) / 6e4)}m`,
|
|
@@ -94943,7 +95913,7 @@ var init_scheduled_task_runner = __esm({
|
|
|
94943
95913
|
const timer = setTimeout(() => {
|
|
94944
95914
|
if (!this.running)
|
|
94945
95915
|
return;
|
|
94946
|
-
this.fireScheduledTask(task).catch((e) =>
|
|
95916
|
+
this.fireScheduledTask(task).catch((e) => log76.error("Failed to fire staggered scheduled task", { taskId: task.id, error: String(e) }));
|
|
94947
95917
|
}, delay);
|
|
94948
95918
|
this.staggerTimers.push(timer);
|
|
94949
95919
|
continue;
|
|
@@ -94951,27 +95921,27 @@ var init_scheduled_task_runner = __esm({
|
|
|
94951
95921
|
try {
|
|
94952
95922
|
await this.fireScheduledTask(task);
|
|
94953
95923
|
} catch (e) {
|
|
94954
|
-
|
|
95924
|
+
log76.error("Failed to fire scheduled task", { taskId: task.id, error: String(e) });
|
|
94955
95925
|
}
|
|
94956
95926
|
}
|
|
94957
95927
|
}
|
|
94958
95928
|
async fireScheduledTask(task) {
|
|
94959
|
-
|
|
95929
|
+
log76.info("Firing scheduled task", { taskId: task.id, title: task.title });
|
|
94960
95930
|
await this.taskService.advanceScheduleConfig(task.id);
|
|
94961
95931
|
const resettableStatuses = ["completed", "cancelled", "failed"];
|
|
94962
95932
|
if (resettableStatuses.includes(task.status)) {
|
|
94963
95933
|
await this.taskService.resetTaskForRerun(task.id);
|
|
94964
95934
|
} else if (!["in_progress", "review", "blocked", "pending"].includes(task.status)) {
|
|
94965
|
-
|
|
95935
|
+
log76.warn("Scheduled task has unexpected status, resetting for rerun", { taskId: task.id, status: task.status });
|
|
94966
95936
|
await this.taskService.resetTaskForRerun(task.id);
|
|
94967
95937
|
}
|
|
94968
95938
|
const current = this.taskService.getTask(task.id);
|
|
94969
95939
|
if (current && current.status === "in_progress") {
|
|
94970
95940
|
try {
|
|
94971
95941
|
await this.taskService.runTask(task.id);
|
|
94972
|
-
|
|
95942
|
+
log76.info("Scheduled task auto-started", { taskId: task.id });
|
|
94973
95943
|
} catch (err) {
|
|
94974
|
-
|
|
95944
|
+
log76.warn("Failed to auto-start scheduled task (agent may be busy)", { taskId: task.id, error: String(err) });
|
|
94975
95945
|
}
|
|
94976
95946
|
}
|
|
94977
95947
|
}
|
|
@@ -94981,11 +95951,11 @@ var init_scheduled_task_runner = __esm({
|
|
|
94981
95951
|
|
|
94982
95952
|
// ../storage/dist/sqlite-storage.js
|
|
94983
95953
|
import { DatabaseSync } from "node:sqlite";
|
|
94984
|
-
import { randomUUID } from "node:crypto";
|
|
94985
|
-
import { mkdirSync as
|
|
94986
|
-
import { dirname as
|
|
95954
|
+
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
95955
|
+
import { mkdirSync as mkdirSync24 } from "node:fs";
|
|
95956
|
+
import { dirname as dirname11 } from "node:path";
|
|
94987
95957
|
function generateId2(prefix = "") {
|
|
94988
|
-
const uuid =
|
|
95958
|
+
const uuid = randomUUID2().replace(/-/g, "").slice(0, 16);
|
|
94989
95959
|
return prefix ? `${prefix}_${uuid}` : uuid;
|
|
94990
95960
|
}
|
|
94991
95961
|
function now2() {
|
|
@@ -95003,7 +95973,7 @@ function toDate(v) {
|
|
|
95003
95973
|
function openSqlite(dbPath) {
|
|
95004
95974
|
if (_db)
|
|
95005
95975
|
return _db;
|
|
95006
|
-
|
|
95976
|
+
mkdirSync24(dirname11(dbPath), { recursive: true });
|
|
95007
95977
|
_db = new DatabaseSync(dbPath);
|
|
95008
95978
|
_db.exec("PRAGMA journal_mode = WAL");
|
|
95009
95979
|
_db.exec("PRAGMA foreign_keys = ON");
|
|
@@ -95047,6 +96017,8 @@ function openSqlite(dbPath) {
|
|
|
95047
96017
|
{ table: "projects", column: "created_by", sql: "ALTER TABLE projects ADD COLUMN created_by TEXT" },
|
|
95048
96018
|
{ table: "approvals", column: "target_user_id", sql: "ALTER TABLE approvals ADD COLUMN target_user_id TEXT" },
|
|
95049
96019
|
{ table: "users", column: "deleted_at", sql: "ALTER TABLE users ADD COLUMN deleted_at TEXT" },
|
|
96020
|
+
{ table: "users", column: "hub_user_id", sql: "ALTER TABLE users ADD COLUMN hub_user_id TEXT" },
|
|
96021
|
+
{ table: "users", column: "hub_username", sql: "ALTER TABLE users ADD COLUMN hub_username TEXT" },
|
|
95050
96022
|
{ table: "agents", column: "deleted_at", sql: "ALTER TABLE agents ADD COLUMN deleted_at TEXT" },
|
|
95051
96023
|
{ table: "deliverables", column: "format", sql: "ALTER TABLE deliverables ADD COLUMN format TEXT" },
|
|
95052
96024
|
{ table: "task_comments", column: "reply_to_id", sql: "ALTER TABLE task_comments ADD COLUMN reply_to_id TEXT" },
|
|
@@ -95056,7 +96028,7 @@ function openSqlite(dbPath) {
|
|
|
95056
96028
|
const cols = _db.prepare(`PRAGMA table_info(${m.table})`).all();
|
|
95057
96029
|
if (!cols.some((c) => c.name === m.column)) {
|
|
95058
96030
|
_db.exec(m.sql);
|
|
95059
|
-
|
|
96031
|
+
log77.info(`Migration: added column ${m.column} to ${m.table}`);
|
|
95060
96032
|
}
|
|
95061
96033
|
}
|
|
95062
96034
|
_db.exec("CREATE INDEX IF NOT EXISTS idx_agent_activities_mailbox ON agent_activities(mailbox_item_id)");
|
|
@@ -95070,10 +96042,10 @@ function openSqlite(dbPath) {
|
|
|
95070
96042
|
for (const m of statusMigrations) {
|
|
95071
96043
|
const result = _db.prepare(m.sql).run();
|
|
95072
96044
|
if (result.changes > 0) {
|
|
95073
|
-
|
|
96045
|
+
log77.info(`Status migration: ${m.desc} (${result.changes} rows)`);
|
|
95074
96046
|
}
|
|
95075
96047
|
}
|
|
95076
|
-
|
|
96048
|
+
log77.info("SQLite database opened", { path: dbPath });
|
|
95077
96049
|
return _db;
|
|
95078
96050
|
}
|
|
95079
96051
|
function closeSqlite() {
|
|
@@ -95093,7 +96065,7 @@ function migrateToExecutionStreamLogs(db) {
|
|
|
95093
96065
|
SELECT id, 'task', task_id, agent_id, seq, type, content, metadata, execution_round, created_at
|
|
95094
96066
|
FROM task_logs
|
|
95095
96067
|
`);
|
|
95096
|
-
|
|
96068
|
+
log77.info(`Migration: copied ${taskLogCount} task_logs to execution_stream_logs`);
|
|
95097
96069
|
}
|
|
95098
96070
|
const actLogCount = db.prepare("SELECT COUNT(*) as cnt FROM agent_activity_logs").get().cnt;
|
|
95099
96071
|
if (actLogCount > 0) {
|
|
@@ -95104,15 +96076,15 @@ function migrateToExecutionStreamLogs(db) {
|
|
|
95104
96076
|
seq, type, content, metadata, NULL, created_at
|
|
95105
96077
|
FROM agent_activity_logs
|
|
95106
96078
|
`);
|
|
95107
|
-
|
|
96079
|
+
log77.info(`Migration: copied ${actLogCount} agent_activity_logs to execution_stream_logs`);
|
|
95108
96080
|
}
|
|
95109
96081
|
}
|
|
95110
|
-
var
|
|
96082
|
+
var log77, SCHEMA_SQL, _db, SqliteOrgRepo, SqliteAgentRepo, SqliteTaskRepo, SqliteRequirementRepo, SqliteProjectRepo, SqliteAuditRepo, SqliteTaskLogRepo, SqliteTaskCommentRepo, SqliteRequirementCommentRepo, SqliteMessageRepo, SqliteChatSessionRepo, SqliteChannelMessageRepo, SqliteUserRepo, SqliteTeamRepo, SqliteMarketplaceTemplateRepo, SqliteMarketplaceSkillRepo, SqliteMarketplaceRatingRepo, SqliteAgentKnowledgeRepo, SqliteExternalAgentRepo, SqliteDeliverableRepo, SqliteActivityRepo, SqliteExecutionStreamRepo, SqliteMailboxRepo, SqliteDecisionRepo, SqliteNotificationRepo, SqliteApprovalRepo, SqliteGroupChatRepo, SqliteStatusTransitionRepo, SqliteReadCursorRepo;
|
|
95111
96083
|
var init_sqlite_storage = __esm({
|
|
95112
96084
|
"../storage/dist/sqlite-storage.js"() {
|
|
95113
96085
|
"use strict";
|
|
95114
96086
|
init_dist();
|
|
95115
|
-
|
|
96087
|
+
log77 = createLogger("sqlite-storage");
|
|
95116
96088
|
SCHEMA_SQL = `
|
|
95117
96089
|
CREATE TABLE IF NOT EXISTS organizations (
|
|
95118
96090
|
id TEXT PRIMARY KEY,
|
|
@@ -96594,7 +97566,7 @@ CREATE TABLE IF NOT EXISTS user_read_cursors (
|
|
|
96594
97566
|
migrated++;
|
|
96595
97567
|
}
|
|
96596
97568
|
if (migrated > 0) {
|
|
96597
|
-
|
|
97569
|
+
log77.info(`Migrated ${migrated} legacy chat messages to segment format`);
|
|
96598
97570
|
}
|
|
96599
97571
|
return migrated;
|
|
96600
97572
|
}
|
|
@@ -96606,7 +97578,7 @@ CREATE TABLE IF NOT EXISTS user_read_cursors (
|
|
|
96606
97578
|
const result = this.db.prepare("UPDATE chat_sessions SET user_id = ? WHERE user_id IS NULL").run(defaultUserId);
|
|
96607
97579
|
const count = Number(result.changes);
|
|
96608
97580
|
if (count > 0) {
|
|
96609
|
-
|
|
97581
|
+
log77.info(`Migrated ${count} chat sessions with NULL user_id to user ${defaultUserId}`);
|
|
96610
97582
|
}
|
|
96611
97583
|
return count;
|
|
96612
97584
|
}
|
|
@@ -96620,7 +97592,7 @@ CREATE TABLE IF NOT EXISTS user_read_cursors (
|
|
|
96620
97592
|
const result = this.db.prepare("UPDATE chat_sessions SET user_id = ? WHERE user_id = 'default'").run(realOwnerId);
|
|
96621
97593
|
const count = Number(result.changes);
|
|
96622
97594
|
if (count > 0) {
|
|
96623
|
-
|
|
97595
|
+
log77.info(`Migrated ${count} chat sessions from user_id='default' to ${realOwnerId}`);
|
|
96624
97596
|
}
|
|
96625
97597
|
return count;
|
|
96626
97598
|
}
|
|
@@ -96766,13 +97738,13 @@ CREATE TABLE IF NOT EXISTS user_read_cursors (
|
|
|
96766
97738
|
this.db = db;
|
|
96767
97739
|
}
|
|
96768
97740
|
create(data) {
|
|
96769
|
-
this.db.prepare("INSERT INTO users (id, org_id, name, email, role, team_id, password_hash, created_at) VALUES (
|
|
97741
|
+
this.db.prepare("INSERT INTO users (id, org_id, name, email, role, team_id, password_hash, hub_user_id, avatar_url, created_at) VALUES (?,?,?,?,?,?,?,?,?,?)").run(data.id, data.orgId, data.name, data.email ?? null, data.role ?? "member", data.teamId ?? null, data.passwordHash ?? null, data.hubUserId ?? null, data.avatarUrl ?? null, now2());
|
|
96770
97742
|
return this.findById(data.id);
|
|
96771
97743
|
}
|
|
96772
97744
|
async upsert(data) {
|
|
96773
|
-
this.db.prepare(`INSERT INTO users (id, org_id, name, email, role, team_id, password_hash, created_at)
|
|
96774
|
-
VALUES (
|
|
96775
|
-
ON CONFLICT(id) DO UPDATE SET name = excluded.name, email = excluded.email, role = excluded.role, team_id = excluded.team_id, password_hash = COALESCE(excluded.password_hash, password_hash)`).run(data.id, data.orgId, data.name, data.email ?? null, data.role ?? "member", data.teamId ?? null, data.passwordHash ?? null, now2());
|
|
97745
|
+
this.db.prepare(`INSERT INTO users (id, org_id, name, email, role, team_id, password_hash, hub_user_id, created_at)
|
|
97746
|
+
VALUES (?,?,?,?,?,?,?,?,?)
|
|
97747
|
+
ON CONFLICT(id) DO UPDATE SET name = excluded.name, email = excluded.email, role = excluded.role, team_id = excluded.team_id, password_hash = COALESCE(excluded.password_hash, password_hash), hub_user_id = COALESCE(excluded.hub_user_id, hub_user_id)`).run(data.id, data.orgId, data.name, data.email ?? null, data.role ?? "member", data.teamId ?? null, data.passwordHash ?? null, data.hubUserId ?? null, now2());
|
|
96776
97748
|
}
|
|
96777
97749
|
async updateTeamId(id, teamId) {
|
|
96778
97750
|
this.db.prepare("UPDATE users SET team_id = ? WHERE id = ?").run(teamId, id);
|
|
@@ -96787,6 +97759,17 @@ CREATE TABLE IF NOT EXISTS user_read_cursors (
|
|
|
96787
97759
|
const r = this.db.prepare("SELECT * FROM users WHERE email = ? AND deleted_at IS NULL").get(email);
|
|
96788
97760
|
return r ? this._map(r) : null;
|
|
96789
97761
|
}
|
|
97762
|
+
findByHubUserId(hubUserId) {
|
|
97763
|
+
const r = this.db.prepare("SELECT * FROM users WHERE hub_user_id = ? AND deleted_at IS NULL").get(hubUserId);
|
|
97764
|
+
return r ? this._map(r) : null;
|
|
97765
|
+
}
|
|
97766
|
+
updateHubUserId(id, hubUserId, hubUsername) {
|
|
97767
|
+
if (hubUsername) {
|
|
97768
|
+
this.db.prepare("UPDATE users SET hub_user_id = ?, hub_username = ? WHERE id = ?").run(hubUserId, hubUsername, id);
|
|
97769
|
+
} else {
|
|
97770
|
+
this.db.prepare("UPDATE users SET hub_user_id = ? WHERE id = ?").run(hubUserId, id);
|
|
97771
|
+
}
|
|
97772
|
+
}
|
|
96790
97773
|
findById(id) {
|
|
96791
97774
|
const r = this.db.prepare("SELECT * FROM users WHERE id = ?").get(id);
|
|
96792
97775
|
return r ? this._map(r) : null;
|
|
@@ -96863,7 +97846,7 @@ CREATE TABLE IF NOT EXISTS user_read_cursors (
|
|
|
96863
97846
|
return newId;
|
|
96864
97847
|
}
|
|
96865
97848
|
this.db.prepare("UPDATE users SET id = ? WHERE id = 'default'").run(newId);
|
|
96866
|
-
|
|
97849
|
+
log77.info(`Migrated user id='default' to '${newId}'`);
|
|
96867
97850
|
return newId;
|
|
96868
97851
|
}
|
|
96869
97852
|
_map(r) {
|
|
@@ -96876,6 +97859,8 @@ CREATE TABLE IF NOT EXISTS user_read_cursors (
|
|
|
96876
97859
|
teamId: r["team_id"],
|
|
96877
97860
|
passwordHash: r["password_hash"],
|
|
96878
97861
|
avatarUrl: r["avatar_url"],
|
|
97862
|
+
hubUserId: r["hub_user_id"],
|
|
97863
|
+
hubUsername: r["hub_username"],
|
|
96879
97864
|
inviteToken: r["invite_token"],
|
|
96880
97865
|
inviteExpiresAt: r["invite_expires_at"],
|
|
96881
97866
|
createdAt: toDate(r["created_at"]),
|
|
@@ -97922,7 +98907,7 @@ CREATE TABLE IF NOT EXISTS user_read_cursors (
|
|
|
97922
98907
|
const result = this.db.prepare("UPDATE user_notifications SET user_id = ? WHERE user_id = 'default'").run(realOwnerId);
|
|
97923
98908
|
const count = Number(result.changes);
|
|
97924
98909
|
if (count > 0) {
|
|
97925
|
-
|
|
98910
|
+
log77.info(`Migrated ${count} notifications from user_id='default' to ${realOwnerId}`);
|
|
97926
98911
|
}
|
|
97927
98912
|
return count;
|
|
97928
98913
|
}
|
|
@@ -98003,7 +98988,7 @@ CREATE TABLE IF NOT EXISTS user_read_cursors (
|
|
|
98003
98988
|
const result = this.db.prepare("UPDATE approvals SET target_user_id = ? WHERE target_user_id = 'default'").run(realOwnerId);
|
|
98004
98989
|
const count = Number(result.changes);
|
|
98005
98990
|
if (count > 0) {
|
|
98006
|
-
|
|
98991
|
+
log77.info(`Migrated ${count} approvals from target_user_id='default' to ${realOwnerId}`);
|
|
98007
98992
|
}
|
|
98008
98993
|
return count;
|
|
98009
98994
|
}
|
|
@@ -98252,17 +99237,17 @@ var init_dist5 = __esm({
|
|
|
98252
99237
|
});
|
|
98253
99238
|
|
|
98254
99239
|
// ../org-manager/dist/storage-bridge.js
|
|
98255
|
-
import { homedir as
|
|
98256
|
-
import { join as
|
|
99240
|
+
import { homedir as homedir18 } from "node:os";
|
|
99241
|
+
import { join as join29 } from "node:path";
|
|
98257
99242
|
function resolveSqlitePath(url) {
|
|
98258
99243
|
if (url?.startsWith("sqlite:")) {
|
|
98259
99244
|
let p = url.slice("sqlite:".length);
|
|
98260
99245
|
if (p.startsWith("~/") || p === "~") {
|
|
98261
|
-
p =
|
|
99246
|
+
p = join29(homedir18(), p.slice(2));
|
|
98262
99247
|
}
|
|
98263
99248
|
return p;
|
|
98264
99249
|
}
|
|
98265
|
-
return
|
|
99250
|
+
return join29(homedir18(), ".markus", "data.db");
|
|
98266
99251
|
}
|
|
98267
99252
|
async function initStorage(databaseUrl) {
|
|
98268
99253
|
const url = databaseUrl ?? process.env["DATABASE_URL"];
|
|
@@ -98300,28 +99285,28 @@ async function initSqliteStorage(url) {
|
|
|
98300
99285
|
statusTransitionRepo: new storage.SqliteStatusTransitionRepo(db),
|
|
98301
99286
|
readCursorRepo: new storage.SqliteReadCursorRepo(db)
|
|
98302
99287
|
};
|
|
98303
|
-
|
|
99288
|
+
log78.info("SQLite storage initialized", { path: dbPath });
|
|
98304
99289
|
return bridge;
|
|
98305
99290
|
} catch (error) {
|
|
98306
|
-
|
|
99291
|
+
log78.warn("Failed to initialize SQLite storage, falling back to memory-only mode", {
|
|
98307
99292
|
error: String(error)
|
|
98308
99293
|
});
|
|
98309
99294
|
return null;
|
|
98310
99295
|
}
|
|
98311
99296
|
}
|
|
98312
|
-
var
|
|
99297
|
+
var log78;
|
|
98313
99298
|
var init_storage_bridge = __esm({
|
|
98314
99299
|
"../org-manager/dist/storage-bridge.js"() {
|
|
98315
99300
|
"use strict";
|
|
98316
99301
|
init_dist();
|
|
98317
|
-
|
|
99302
|
+
log78 = createLogger("storage-bridge");
|
|
98318
99303
|
}
|
|
98319
99304
|
});
|
|
98320
99305
|
|
|
98321
99306
|
// ../org-manager/dist/file-storage-provider.js
|
|
98322
|
-
import { mkdirSync as
|
|
98323
|
-
import { join as
|
|
98324
|
-
import { homedir as
|
|
99307
|
+
import { mkdirSync as mkdirSync25, writeFileSync as writeFileSync21, unlinkSync as unlinkSync4, existsSync as existsSync34 } from "node:fs";
|
|
99308
|
+
import { join as join30, extname } from "node:path";
|
|
99309
|
+
import { homedir as homedir19 } from "node:os";
|
|
98325
99310
|
function mimeToExt(mime) {
|
|
98326
99311
|
const map = {
|
|
98327
99312
|
"image/jpeg": ".jpg",
|
|
@@ -98341,27 +99326,27 @@ var init_file_storage_provider = __esm({
|
|
|
98341
99326
|
LocalFileStorageProvider = class {
|
|
98342
99327
|
baseDir;
|
|
98343
99328
|
constructor(baseDir) {
|
|
98344
|
-
this.baseDir = baseDir ??
|
|
98345
|
-
|
|
99329
|
+
this.baseDir = baseDir ?? join30(homedir19(), ".markus", "uploads");
|
|
99330
|
+
mkdirSync25(this.baseDir, { recursive: true });
|
|
98346
99331
|
}
|
|
98347
99332
|
async upload(data, opts) {
|
|
98348
99333
|
const ext = extname(opts.name) || mimeToExt(opts.contentType);
|
|
98349
99334
|
const key2 = `${generateId("upl")}${ext}`;
|
|
98350
|
-
const subDir = opts.prefix ?
|
|
98351
|
-
|
|
98352
|
-
|
|
99335
|
+
const subDir = opts.prefix ? join30(this.baseDir, opts.prefix) : this.baseDir;
|
|
99336
|
+
mkdirSync25(subDir, { recursive: true });
|
|
99337
|
+
writeFileSync21(join30(subDir, key2), data);
|
|
98353
99338
|
const urlPath = opts.prefix ? `/api/uploads/${opts.prefix}/${key2}` : `/api/uploads/${key2}`;
|
|
98354
99339
|
return { url: urlPath, key: opts.prefix ? `${opts.prefix}/${key2}` : key2 };
|
|
98355
99340
|
}
|
|
98356
99341
|
async delete(key2) {
|
|
98357
|
-
const filePath =
|
|
98358
|
-
if (
|
|
99342
|
+
const filePath = join30(this.baseDir, key2);
|
|
99343
|
+
if (existsSync34(filePath)) {
|
|
98359
99344
|
unlinkSync4(filePath);
|
|
98360
99345
|
}
|
|
98361
99346
|
}
|
|
98362
99347
|
/** Resolve a storage key to an absolute filesystem path (for serving). */
|
|
98363
99348
|
resolve(key2) {
|
|
98364
|
-
return
|
|
99349
|
+
return join30(this.baseDir, key2);
|
|
98365
99350
|
}
|
|
98366
99351
|
};
|
|
98367
99352
|
}
|
|
@@ -98379,6 +99364,7 @@ __export(dist_exports5, {
|
|
|
98379
99364
|
FileKnowledgeStore: () => FileKnowledgeStore,
|
|
98380
99365
|
HITLService: () => HITLService,
|
|
98381
99366
|
KnowledgeService: () => KnowledgeService,
|
|
99367
|
+
LicenseService: () => LicenseService,
|
|
98382
99368
|
LocalFileStorageProvider: () => LocalFileStorageProvider,
|
|
98383
99369
|
OrganizationService: () => OrganizationService,
|
|
98384
99370
|
ProjectService: () => ProjectService,
|
|
@@ -98387,6 +99373,7 @@ __export(dist_exports5, {
|
|
|
98387
99373
|
ScheduledTaskRunner: () => ScheduledTaskRunner,
|
|
98388
99374
|
StaleDetector: () => StaleDetector,
|
|
98389
99375
|
TaskService: () => TaskService,
|
|
99376
|
+
TelemetryService: () => TelemetryService,
|
|
98390
99377
|
TrustService: () => TrustService,
|
|
98391
99378
|
WSBroadcaster: () => WSBroadcaster,
|
|
98392
99379
|
initStorage: () => initStorage,
|
|
@@ -98402,6 +99389,8 @@ var init_dist6 = __esm({
|
|
|
98402
99389
|
init_ws_server();
|
|
98403
99390
|
init_hitl_service();
|
|
98404
99391
|
init_billing_service();
|
|
99392
|
+
init_license_service();
|
|
99393
|
+
init_telemetry_service();
|
|
98405
99394
|
init_audit_service();
|
|
98406
99395
|
init_project_service();
|
|
98407
99396
|
init_requirement_service();
|
|
@@ -98421,12 +99410,12 @@ var init_dist6 = __esm({
|
|
|
98421
99410
|
});
|
|
98422
99411
|
|
|
98423
99412
|
// ../comms/dist/feishu/client.js
|
|
98424
|
-
var
|
|
99413
|
+
var log79, FeishuClient;
|
|
98425
99414
|
var init_client = __esm({
|
|
98426
99415
|
"../comms/dist/feishu/client.js"() {
|
|
98427
99416
|
"use strict";
|
|
98428
99417
|
init_dist();
|
|
98429
|
-
|
|
99418
|
+
log79 = createLogger("feishu-client");
|
|
98430
99419
|
FeishuClient = class {
|
|
98431
99420
|
appId;
|
|
98432
99421
|
appSecret;
|
|
@@ -98456,7 +99445,7 @@ var init_client = __esm({
|
|
|
98456
99445
|
}
|
|
98457
99446
|
this.tenantToken = data.tenant_access_token;
|
|
98458
99447
|
this.tokenExpiresAt = Date.now() + (data.expire - 300) * 1e3;
|
|
98459
|
-
|
|
99448
|
+
log79.info("Feishu tenant token refreshed");
|
|
98460
99449
|
return this.tenantToken;
|
|
98461
99450
|
}
|
|
98462
99451
|
async sendTextMessage(chatId, text) {
|
|
@@ -98590,13 +99579,13 @@ var init_client = __esm({
|
|
|
98590
99579
|
import { createServer as createServer3 } from "node:http";
|
|
98591
99580
|
import { createDecipheriv, scrypt } from "node:crypto";
|
|
98592
99581
|
import { promisify as promisify3 } from "node:util";
|
|
98593
|
-
var
|
|
99582
|
+
var log80, scryptAsync, FeishuAdapter;
|
|
98594
99583
|
var init_adapter = __esm({
|
|
98595
99584
|
"../comms/dist/feishu/adapter.js"() {
|
|
98596
99585
|
"use strict";
|
|
98597
99586
|
init_dist();
|
|
98598
99587
|
init_client();
|
|
98599
|
-
|
|
99588
|
+
log80 = createLogger("feishu-adapter");
|
|
98600
99589
|
scryptAsync = promisify3(scrypt);
|
|
98601
99590
|
FeishuAdapter = class {
|
|
98602
99591
|
platform = "feishu";
|
|
@@ -98617,10 +99606,10 @@ var init_adapter = __esm({
|
|
|
98617
99606
|
const port = this.config.webhookPort ?? 9e3;
|
|
98618
99607
|
this.server = createServer3((req, res) => this.handleWebhook(req, res));
|
|
98619
99608
|
this.server.listen(port, () => {
|
|
98620
|
-
|
|
99609
|
+
log80.info(`Feishu webhook server listening on port ${port}`);
|
|
98621
99610
|
});
|
|
98622
99611
|
this.connected = true;
|
|
98623
|
-
|
|
99612
|
+
log80.info("Feishu adapter connected");
|
|
98624
99613
|
}
|
|
98625
99614
|
async disconnect() {
|
|
98626
99615
|
if (this.server) {
|
|
@@ -98628,7 +99617,7 @@ var init_adapter = __esm({
|
|
|
98628
99617
|
this.server = void 0;
|
|
98629
99618
|
}
|
|
98630
99619
|
this.connected = false;
|
|
98631
|
-
|
|
99620
|
+
log80.info("Feishu adapter disconnected");
|
|
98632
99621
|
}
|
|
98633
99622
|
async sendMessage(channelId, content, options) {
|
|
98634
99623
|
if (!this.client)
|
|
@@ -98704,12 +99693,12 @@ var init_adapter = __esm({
|
|
|
98704
99693
|
res.end("ok");
|
|
98705
99694
|
if (event.header?.event_type === "im.message.receive_v1") {
|
|
98706
99695
|
this.processMessageEvent(event).catch((err) => {
|
|
98707
|
-
|
|
99696
|
+
log80.error("Failed to process Feishu message event", { error: err.message });
|
|
98708
99697
|
});
|
|
98709
99698
|
}
|
|
98710
99699
|
if (event["action"]) {
|
|
98711
99700
|
this.processCardAction(event).catch((err) => {
|
|
98712
|
-
|
|
99701
|
+
log80.error("Failed to process card action", { error: err.message });
|
|
98713
99702
|
});
|
|
98714
99703
|
}
|
|
98715
99704
|
};
|
|
@@ -98720,14 +99709,14 @@ var init_adapter = __esm({
|
|
|
98720
99709
|
const event = JSON.parse(decrypted);
|
|
98721
99710
|
processEvent(event);
|
|
98722
99711
|
} else if (raw.encrypt && !this.config?.encryptKey) {
|
|
98723
|
-
|
|
99712
|
+
log80.warn("Received encrypted Feishu payload but no encryptKey configured");
|
|
98724
99713
|
res.writeHead(200);
|
|
98725
99714
|
res.end("ok");
|
|
98726
99715
|
} else {
|
|
98727
99716
|
processEvent(raw);
|
|
98728
99717
|
}
|
|
98729
99718
|
} catch (err) {
|
|
98730
|
-
|
|
99719
|
+
log80.error("Failed to process Feishu webhook", { error: err instanceof Error ? err.message : String(err) });
|
|
98731
99720
|
res.writeHead(400);
|
|
98732
99721
|
res.end("bad request");
|
|
98733
99722
|
}
|
|
@@ -98772,7 +99761,7 @@ var init_adapter = __esm({
|
|
|
98772
99761
|
try {
|
|
98773
99762
|
await handler4(message);
|
|
98774
99763
|
} catch (error) {
|
|
98775
|
-
|
|
99764
|
+
log80.error("Message handler failed", { error });
|
|
98776
99765
|
}
|
|
98777
99766
|
}
|
|
98778
99767
|
}
|
|
@@ -98807,7 +99796,7 @@ var init_adapter = __esm({
|
|
|
98807
99796
|
try {
|
|
98808
99797
|
await handler4(message);
|
|
98809
99798
|
} catch (error) {
|
|
98810
|
-
|
|
99799
|
+
log80.error("Card action handler failed", { error });
|
|
98811
99800
|
}
|
|
98812
99801
|
}
|
|
98813
99802
|
}
|
|
@@ -98824,12 +99813,12 @@ var init_cards = __esm({
|
|
|
98824
99813
|
|
|
98825
99814
|
// ../comms/dist/webui/adapter.js
|
|
98826
99815
|
import { createServer as createServer4 } from "node:http";
|
|
98827
|
-
var
|
|
99816
|
+
var log81, WebUIAdapter;
|
|
98828
99817
|
var init_adapter2 = __esm({
|
|
98829
99818
|
"../comms/dist/webui/adapter.js"() {
|
|
98830
99819
|
"use strict";
|
|
98831
99820
|
init_dist();
|
|
98832
|
-
|
|
99821
|
+
log81 = createLogger("webui-adapter");
|
|
98833
99822
|
WebUIAdapter = class {
|
|
98834
99823
|
platform = "webui";
|
|
98835
99824
|
handlers = [];
|
|
@@ -98841,7 +99830,7 @@ var init_adapter2 = __esm({
|
|
|
98841
99830
|
this.port = config["port"] ?? 8058;
|
|
98842
99831
|
this.server = createServer4((req, res) => this.handleRequest(req, res));
|
|
98843
99832
|
this.server.listen(this.port, "0.0.0.0", () => {
|
|
98844
|
-
|
|
99833
|
+
log81.info(`WebUI comm server listening on 0.0.0.0:${this.port}`);
|
|
98845
99834
|
});
|
|
98846
99835
|
this.connected = true;
|
|
98847
99836
|
}
|
|
@@ -98914,7 +99903,7 @@ var init_adapter2 = __esm({
|
|
|
98914
99903
|
res.end(JSON.stringify({ received: true, messageId: message.id }));
|
|
98915
99904
|
for (const handler4 of this.handlers) {
|
|
98916
99905
|
handler4(message).catch((err) => {
|
|
98917
|
-
|
|
99906
|
+
log81.error("WebUI message handler failed", { error: String(err) });
|
|
98918
99907
|
});
|
|
98919
99908
|
}
|
|
98920
99909
|
} catch (error) {
|
|
@@ -98928,87 +99917,87 @@ var init_adapter2 = __esm({
|
|
|
98928
99917
|
});
|
|
98929
99918
|
|
|
98930
99919
|
// ../comms/dist/whatsapp/client.js
|
|
98931
|
-
var
|
|
99920
|
+
var log82;
|
|
98932
99921
|
var init_client2 = __esm({
|
|
98933
99922
|
"../comms/dist/whatsapp/client.js"() {
|
|
98934
99923
|
"use strict";
|
|
98935
99924
|
init_dist();
|
|
98936
|
-
|
|
99925
|
+
log82 = createLogger("whatsapp-client");
|
|
98937
99926
|
}
|
|
98938
99927
|
});
|
|
98939
99928
|
|
|
98940
99929
|
// ../comms/dist/whatsapp/adapter.js
|
|
98941
|
-
var
|
|
99930
|
+
var log83;
|
|
98942
99931
|
var init_adapter3 = __esm({
|
|
98943
99932
|
"../comms/dist/whatsapp/adapter.js"() {
|
|
98944
99933
|
"use strict";
|
|
98945
99934
|
init_dist();
|
|
98946
99935
|
init_client2();
|
|
98947
|
-
|
|
99936
|
+
log83 = createLogger("whatsapp-adapter");
|
|
98948
99937
|
}
|
|
98949
99938
|
});
|
|
98950
99939
|
|
|
98951
99940
|
// ../comms/dist/slack/client.js
|
|
98952
|
-
var
|
|
99941
|
+
var log84;
|
|
98953
99942
|
var init_client3 = __esm({
|
|
98954
99943
|
"../comms/dist/slack/client.js"() {
|
|
98955
99944
|
"use strict";
|
|
98956
99945
|
init_dist();
|
|
98957
|
-
|
|
99946
|
+
log84 = createLogger("slack-client");
|
|
98958
99947
|
}
|
|
98959
99948
|
});
|
|
98960
99949
|
|
|
98961
99950
|
// ../comms/dist/slack/adapter.js
|
|
98962
|
-
var
|
|
99951
|
+
var log85;
|
|
98963
99952
|
var init_adapter4 = __esm({
|
|
98964
99953
|
"../comms/dist/slack/adapter.js"() {
|
|
98965
99954
|
"use strict";
|
|
98966
99955
|
init_dist();
|
|
98967
99956
|
init_client3();
|
|
98968
|
-
|
|
99957
|
+
log85 = createLogger("slack-adapter");
|
|
98969
99958
|
}
|
|
98970
99959
|
});
|
|
98971
99960
|
|
|
98972
99961
|
// ../comms/dist/telegram/client.js
|
|
98973
|
-
var
|
|
99962
|
+
var log86;
|
|
98974
99963
|
var init_client4 = __esm({
|
|
98975
99964
|
"../comms/dist/telegram/client.js"() {
|
|
98976
99965
|
"use strict";
|
|
98977
99966
|
init_dist();
|
|
98978
|
-
|
|
99967
|
+
log86 = createLogger("telegram-client");
|
|
98979
99968
|
}
|
|
98980
99969
|
});
|
|
98981
99970
|
|
|
98982
99971
|
// ../comms/dist/telegram/adapter.js
|
|
98983
|
-
var
|
|
99972
|
+
var log87;
|
|
98984
99973
|
var init_adapter5 = __esm({
|
|
98985
99974
|
"../comms/dist/telegram/adapter.js"() {
|
|
98986
99975
|
"use strict";
|
|
98987
99976
|
init_dist();
|
|
98988
99977
|
init_client4();
|
|
98989
|
-
|
|
99978
|
+
log87 = createLogger("telegram-adapter");
|
|
98990
99979
|
}
|
|
98991
99980
|
});
|
|
98992
99981
|
|
|
98993
99982
|
// ../comms/dist/router.js
|
|
98994
|
-
var
|
|
99983
|
+
var log88, MessageRouter;
|
|
98995
99984
|
var init_router2 = __esm({
|
|
98996
99985
|
"../comms/dist/router.js"() {
|
|
98997
99986
|
"use strict";
|
|
98998
99987
|
init_dist();
|
|
98999
|
-
|
|
99988
|
+
log88 = createLogger("message-router");
|
|
99000
99989
|
MessageRouter = class {
|
|
99001
99990
|
adapters = /* @__PURE__ */ new Map();
|
|
99002
99991
|
agentChannelMap = /* @__PURE__ */ new Map();
|
|
99003
99992
|
agentHandler;
|
|
99004
99993
|
registerAdapter(adapter2) {
|
|
99005
99994
|
this.adapters.set(adapter2.platform, adapter2);
|
|
99006
|
-
|
|
99995
|
+
log88.info(`Registered comm adapter: ${adapter2.platform}`);
|
|
99007
99996
|
}
|
|
99008
|
-
bindAgentToChannel(agentId2,
|
|
99009
|
-
const key2 = `${
|
|
99997
|
+
bindAgentToChannel(agentId2, platform5, channelId) {
|
|
99998
|
+
const key2 = `${platform5}:${channelId}`;
|
|
99010
99999
|
this.agentChannelMap.set(key2, agentId2);
|
|
99011
|
-
|
|
100000
|
+
log88.info(`Bound agent ${agentId2} to ${key2}`);
|
|
99012
100001
|
}
|
|
99013
100002
|
setAgentHandler(handler4) {
|
|
99014
100003
|
this.agentHandler = handler4;
|
|
@@ -99017,7 +100006,7 @@ var init_router2 = __esm({
|
|
|
99017
100006
|
for (const config of configs) {
|
|
99018
100007
|
const adapter2 = this.adapters.get(config.platform);
|
|
99019
100008
|
if (!adapter2) {
|
|
99020
|
-
|
|
100009
|
+
log88.warn(`No adapter registered for platform: ${config.platform}`);
|
|
99021
100010
|
continue;
|
|
99022
100011
|
}
|
|
99023
100012
|
await adapter2.connect(config);
|
|
@@ -99033,22 +100022,22 @@ var init_router2 = __esm({
|
|
|
99033
100022
|
}
|
|
99034
100023
|
}
|
|
99035
100024
|
}
|
|
99036
|
-
async sendToChannel(
|
|
99037
|
-
const adapter2 = this.adapters.get(
|
|
100025
|
+
async sendToChannel(platform5, channelId, content) {
|
|
100026
|
+
const adapter2 = this.adapters.get(platform5);
|
|
99038
100027
|
if (!adapter2 || !adapter2.isConnected()) {
|
|
99039
|
-
|
|
100028
|
+
log88.warn(`Adapter not available for platform: ${platform5}`);
|
|
99040
100029
|
return void 0;
|
|
99041
100030
|
}
|
|
99042
100031
|
return adapter2.sendMessage(channelId, content);
|
|
99043
100032
|
}
|
|
99044
|
-
async sendAsAgent(agentId2,
|
|
99045
|
-
return this.sendToChannel(
|
|
100033
|
+
async sendAsAgent(agentId2, platform5, channelId, content) {
|
|
100034
|
+
return this.sendToChannel(platform5, channelId, content);
|
|
99046
100035
|
}
|
|
99047
100036
|
async routeIncomingMessage(message) {
|
|
99048
100037
|
const key2 = `${message.platform}:${message.channelId}`;
|
|
99049
100038
|
const agentId2 = message.agentId || this.agentChannelMap.get(key2);
|
|
99050
100039
|
if (!agentId2) {
|
|
99051
|
-
|
|
100040
|
+
log88.debug("No agent bound to channel, skipping message", { key: key2 });
|
|
99052
100041
|
return;
|
|
99053
100042
|
}
|
|
99054
100043
|
message.agentId = agentId2;
|
|
@@ -99064,7 +100053,7 @@ var init_router2 = __esm({
|
|
|
99064
100053
|
}
|
|
99065
100054
|
}
|
|
99066
100055
|
} catch (error) {
|
|
99067
|
-
|
|
100056
|
+
log88.error("Agent handler failed", { agentId: agentId2, error: String(error) });
|
|
99068
100057
|
}
|
|
99069
100058
|
}
|
|
99070
100059
|
}
|
|
@@ -99091,17 +100080,17 @@ var init_dist7 = __esm({
|
|
|
99091
100080
|
});
|
|
99092
100081
|
|
|
99093
100082
|
// src/utils/logger.ts
|
|
99094
|
-
import { createWriteStream as createWriteStream2, existsSync as
|
|
99095
|
-
import { join as
|
|
99096
|
-
import { homedir as
|
|
100083
|
+
import { createWriteStream as createWriteStream2, existsSync as existsSync35, mkdirSync as mkdirSync26, appendFileSync as appendFileSync3 } from "node:fs";
|
|
100084
|
+
import { join as join31 } from "node:path";
|
|
100085
|
+
import { homedir as homedir20 } from "node:os";
|
|
99097
100086
|
function ensureLogDir2() {
|
|
99098
|
-
if (!
|
|
99099
|
-
|
|
100087
|
+
if (!existsSync35(LOG_DIR2)) {
|
|
100088
|
+
mkdirSync26(LOG_DIR2, { recursive: true, mode: 493 });
|
|
99100
100089
|
}
|
|
99101
100090
|
}
|
|
99102
100091
|
function getStartupLogPath() {
|
|
99103
100092
|
const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
99104
|
-
return
|
|
100093
|
+
return join31(LOG_DIR2, `startup-${date}.log`);
|
|
99105
100094
|
}
|
|
99106
100095
|
function setSuppressConsole(suppress) {
|
|
99107
100096
|
_suppressConsole = suppress;
|
|
@@ -99156,7 +100145,7 @@ var LOG_DIR2, startupLogStream, startupLogPath, _suppressConsole, LEVEL_PREFIX;
|
|
|
99156
100145
|
var init_logger2 = __esm({
|
|
99157
100146
|
"src/utils/logger.ts"() {
|
|
99158
100147
|
"use strict";
|
|
99159
|
-
LOG_DIR2 =
|
|
100148
|
+
LOG_DIR2 = join31(homedir20(), ".markus", "logs");
|
|
99160
100149
|
startupLogStream = null;
|
|
99161
100150
|
startupLogPath = "";
|
|
99162
100151
|
_suppressConsole = false;
|
|
@@ -99174,10 +100163,10 @@ var init_logger2 = __esm({
|
|
|
99174
100163
|
// src/utils/browser.ts
|
|
99175
100164
|
import { exec } from "node:child_process";
|
|
99176
100165
|
import { get as httpGet } from "node:http";
|
|
99177
|
-
import { platform as
|
|
100166
|
+
import { platform as platform4 } from "node:os";
|
|
99178
100167
|
function openBrowser(url) {
|
|
99179
100168
|
if (process.env["NO_BROWSER"]) return;
|
|
99180
|
-
const sys =
|
|
100169
|
+
const sys = platform4();
|
|
99181
100170
|
const cmd = sys === "darwin" ? `open "${url}"` : sys === "win32" ? `start "" "${url}"` : `xdg-open "${url}"`;
|
|
99182
100171
|
exec(cmd, (err) => {
|
|
99183
100172
|
if (err) {
|
|
@@ -99212,9 +100201,9 @@ var init_browser = __esm({
|
|
|
99212
100201
|
});
|
|
99213
100202
|
|
|
99214
100203
|
// src/utils/startupProgress.ts
|
|
99215
|
-
import { homedir as
|
|
99216
|
-
import { appendFileSync as appendFileSync4, existsSync as
|
|
99217
|
-
import { join as
|
|
100204
|
+
import { homedir as homedir21 } from "node:os";
|
|
100205
|
+
import { appendFileSync as appendFileSync4, existsSync as existsSync36, mkdirSync as mkdirSync27 } from "node:fs";
|
|
100206
|
+
import { join as join32 } from "node:path";
|
|
99218
100207
|
function clearScreen() {
|
|
99219
100208
|
return "\x1B[2J\x1B[H";
|
|
99220
100209
|
}
|
|
@@ -99376,8 +100365,8 @@ var init_startupProgress = __esm({
|
|
|
99376
100365
|
const line = `${ts} ${msg}
|
|
99377
100366
|
`;
|
|
99378
100367
|
try {
|
|
99379
|
-
const dir =
|
|
99380
|
-
if (!
|
|
100368
|
+
const dir = join32(homedir21(), ".markus", "logs");
|
|
100369
|
+
if (!existsSync36(dir)) mkdirSync27(dir, { recursive: true, mode: 493 });
|
|
99381
100370
|
appendFileSync4(this.logPath, line, { mode: 420 });
|
|
99382
100371
|
} catch {
|
|
99383
100372
|
}
|
|
@@ -99486,13 +100475,13 @@ var init_startupProgress = __esm({
|
|
|
99486
100475
|
});
|
|
99487
100476
|
|
|
99488
100477
|
// src/connector-service.ts
|
|
99489
|
-
import { resolve as resolve16, join as
|
|
99490
|
-
import { existsSync as
|
|
99491
|
-
import { homedir as
|
|
100478
|
+
import { resolve as resolve16, join as join33, dirname as dirname12 } from "node:path";
|
|
100479
|
+
import { existsSync as existsSync37, readFileSync as readFileSync26, writeFileSync as writeFileSync22, mkdirSync as mkdirSync28, readdirSync as readdirSync13, cpSync as cpSync4 } from "node:fs";
|
|
100480
|
+
import { homedir as homedir22 } from "node:os";
|
|
99492
100481
|
import { execSync as execSync4 } from "node:child_process";
|
|
99493
100482
|
import { fileURLToPath as fileURLToPath6 } from "node:url";
|
|
99494
100483
|
function expandHome(p) {
|
|
99495
|
-
return p.replace(/^~/,
|
|
100484
|
+
return p.replace(/^~/, homedir22());
|
|
99496
100485
|
}
|
|
99497
100486
|
function loadConnectors() {
|
|
99498
100487
|
const connectors = /* @__PURE__ */ new Map();
|
|
@@ -99500,16 +100489,16 @@ function loadConnectors() {
|
|
|
99500
100489
|
loadFromDir(builtinDir, connectors);
|
|
99501
100490
|
const devDir = resolve16(process.cwd(), "packages", "cli", "connectors");
|
|
99502
100491
|
if (devDir !== builtinDir) loadFromDir(devDir, connectors);
|
|
99503
|
-
const userDir =
|
|
100492
|
+
const userDir = join33(homedir22(), ".markus", "connectors");
|
|
99504
100493
|
loadFromDir(userDir, connectors);
|
|
99505
100494
|
return [...connectors.values()].filter((c) => c.platform !== "_template");
|
|
99506
100495
|
}
|
|
99507
100496
|
function loadFromDir(dir, map) {
|
|
99508
|
-
if (!
|
|
100497
|
+
if (!existsSync37(dir)) return;
|
|
99509
100498
|
for (const file of readdirSync13(dir)) {
|
|
99510
100499
|
if (!file.endsWith(".json") || file.startsWith("_")) continue;
|
|
99511
100500
|
try {
|
|
99512
|
-
const raw =
|
|
100501
|
+
const raw = readFileSync26(join33(dir, file), "utf-8");
|
|
99513
100502
|
const desc = JSON.parse(raw);
|
|
99514
100503
|
if (desc.platform) {
|
|
99515
100504
|
map.set(desc.platform, desc);
|
|
@@ -99518,8 +100507,8 @@ function loadFromDir(dir, map) {
|
|
|
99518
100507
|
}
|
|
99519
100508
|
}
|
|
99520
100509
|
}
|
|
99521
|
-
function findConnector(
|
|
99522
|
-
return loadConnectors().find((c) => c.platform ===
|
|
100510
|
+
function findConnector(platform5) {
|
|
100511
|
+
return loadConnectors().find((c) => c.platform === platform5);
|
|
99523
100512
|
}
|
|
99524
100513
|
function scanInstalledPlatforms() {
|
|
99525
100514
|
const connectors = loadConnectors();
|
|
@@ -99534,7 +100523,7 @@ function scanInstalledPlatforms() {
|
|
|
99534
100523
|
};
|
|
99535
100524
|
for (const p of c.detection.configPaths) {
|
|
99536
100525
|
const expanded = expandHome(p);
|
|
99537
|
-
if (
|
|
100526
|
+
if (existsSync37(expanded)) {
|
|
99538
100527
|
result.installed = true;
|
|
99539
100528
|
result.configPath = expanded;
|
|
99540
100529
|
break;
|
|
@@ -99561,9 +100550,9 @@ function scanInstalledPlatforms() {
|
|
|
99561
100550
|
}
|
|
99562
100551
|
function readPlatformConfig(connector) {
|
|
99563
100552
|
const configPath = expandHome(connector.integration.configPath);
|
|
99564
|
-
if (!
|
|
100553
|
+
if (!existsSync37(configPath)) return null;
|
|
99565
100554
|
try {
|
|
99566
|
-
const raw =
|
|
100555
|
+
const raw = readFileSync26(configPath, "utf-8");
|
|
99567
100556
|
if (connector.integration.configFormat === "json5") {
|
|
99568
100557
|
const cleaned = raw.replace(/\/\/.*$/gm, "").replace(/\/\*[\s\S]*?\*\//g, "").replace(/,\s*([\]}])/g, "$1");
|
|
99569
100558
|
return JSON.parse(cleaned);
|
|
@@ -99575,12 +100564,12 @@ function readPlatformConfig(connector) {
|
|
|
99575
100564
|
}
|
|
99576
100565
|
function writePlatformConfig(connector, markusUrl, token) {
|
|
99577
100566
|
const configPath = expandHome(connector.integration.configPath);
|
|
99578
|
-
const configDir =
|
|
99579
|
-
if (!
|
|
99580
|
-
|
|
100567
|
+
const configDir = dirname12(configPath);
|
|
100568
|
+
if (!existsSync37(configDir)) {
|
|
100569
|
+
mkdirSync28(configDir, { recursive: true });
|
|
99581
100570
|
}
|
|
99582
100571
|
let config = {};
|
|
99583
|
-
if (
|
|
100572
|
+
if (existsSync37(configPath)) {
|
|
99584
100573
|
const existing = readPlatformConfig(connector);
|
|
99585
100574
|
if (existing) config = existing;
|
|
99586
100575
|
}
|
|
@@ -99588,7 +100577,7 @@ function writePlatformConfig(connector, markusUrl, token) {
|
|
|
99588
100577
|
setNestedField(config, connector.integration.tokenField, token);
|
|
99589
100578
|
try {
|
|
99590
100579
|
const content = JSON.stringify(config, null, 2);
|
|
99591
|
-
|
|
100580
|
+
writeFileSync22(configPath, content, "utf-8");
|
|
99592
100581
|
return true;
|
|
99593
100582
|
} catch {
|
|
99594
100583
|
return false;
|
|
@@ -99601,21 +100590,21 @@ function installSkillTemplate(connector) {
|
|
|
99601
100590
|
const skillDir = expandHome(connector.integration.skillDir);
|
|
99602
100591
|
const templateName = connector.integration.skillTemplateName;
|
|
99603
100592
|
const candidates = [
|
|
99604
|
-
|
|
100593
|
+
join33(homedir22(), ".markus", "templates", templateName),
|
|
99605
100594
|
resolve16(process.cwd(), "templates", templateName),
|
|
99606
100595
|
resolve16(__dirname5, "..", "templates", templateName)
|
|
99607
100596
|
];
|
|
99608
100597
|
let sourceDir;
|
|
99609
100598
|
for (const c of candidates) {
|
|
99610
|
-
if (
|
|
100599
|
+
if (existsSync37(c)) {
|
|
99611
100600
|
sourceDir = c;
|
|
99612
100601
|
break;
|
|
99613
100602
|
}
|
|
99614
100603
|
}
|
|
99615
100604
|
if (!sourceDir) return false;
|
|
99616
|
-
const targetDir =
|
|
99617
|
-
if (!
|
|
99618
|
-
|
|
100605
|
+
const targetDir = join33(skillDir, templateName);
|
|
100606
|
+
if (!existsSync37(targetDir)) {
|
|
100607
|
+
mkdirSync28(targetDir, { recursive: true });
|
|
99619
100608
|
}
|
|
99620
100609
|
try {
|
|
99621
100610
|
cpSync4(sourceDir, targetDir, { recursive: true });
|
|
@@ -99657,7 +100646,7 @@ var init_connector_service = __esm({
|
|
|
99657
100646
|
"src/connector-service.ts"() {
|
|
99658
100647
|
"use strict";
|
|
99659
100648
|
__filename4 = fileURLToPath6(import.meta.url);
|
|
99660
|
-
__dirname5 =
|
|
100649
|
+
__dirname5 = dirname12(__filename4);
|
|
99661
100650
|
}
|
|
99662
100651
|
});
|
|
99663
100652
|
|
|
@@ -99668,8 +100657,8 @@ __export(init_exports, {
|
|
|
99668
100657
|
registerInitCommand: () => registerInitCommand
|
|
99669
100658
|
});
|
|
99670
100659
|
import { resolve as resolve17 } from "node:path";
|
|
99671
|
-
import { readFileSync as
|
|
99672
|
-
import { homedir as
|
|
100660
|
+
import { readFileSync as readFileSync27, existsSync as existsSync38, cpSync as cpSync5 } from "node:fs";
|
|
100661
|
+
import { homedir as homedir23 } from "node:os";
|
|
99673
100662
|
function registerInitCommand(program2) {
|
|
99674
100663
|
program2.command("init").description("Setup wizard: configure LLM provider, API keys, and server settings").option("--force", "Overwrite existing configuration").option("--non-interactive", "Run without prompts (use env vars or --import-from)").option("--provider <name>", "LLM provider (anthropic/openai/google/minimax/siliconflow/zai/deepseek/ollama)").option("--api-key <key>", "LLM API key").option("--port <port>", "API server port", "8056").option("--import-from <platform>", "Import LLM config from an installed agent platform (e.g. openclaw, hermes)").option("--auto-connect", "Auto-connect detected agent platforms after init").action(async (opts) => {
|
|
99675
100664
|
await quickInit({
|
|
@@ -99684,7 +100673,7 @@ function registerInitCommand(program2) {
|
|
|
99684
100673
|
});
|
|
99685
100674
|
}
|
|
99686
100675
|
async function quickInit(options) {
|
|
99687
|
-
const { writeFileSync:
|
|
100676
|
+
const { writeFileSync: writeFileSync23, mkdirSync: mkdirSync29 } = await import("node:fs");
|
|
99688
100677
|
const { join: pathJoin } = await import("node:path");
|
|
99689
100678
|
const readline3 = await import("node:readline");
|
|
99690
100679
|
const nonInteractive = options?.nonInteractive ?? false;
|
|
@@ -99705,7 +100694,7 @@ async function quickInit(options) {
|
|
|
99705
100694
|
\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518
|
|
99706
100695
|
`);
|
|
99707
100696
|
const configPath = getDefaultConfigPath();
|
|
99708
|
-
if (
|
|
100697
|
+
if (existsSync38(configPath) && !options?.force) {
|
|
99709
100698
|
if (nonInteractive) {
|
|
99710
100699
|
console.log(` Existing configuration found. Use --force to overwrite.`);
|
|
99711
100700
|
rl?.close();
|
|
@@ -99738,11 +100727,11 @@ async function quickInit(options) {
|
|
|
99738
100727
|
const installedPlatforms = scanInstalledPlatforms().filter((p) => p.installed);
|
|
99739
100728
|
let openclawPath = "";
|
|
99740
100729
|
const openclawCandidates = [
|
|
99741
|
-
pathJoin(
|
|
99742
|
-
pathJoin(
|
|
100730
|
+
pathJoin(homedir23(), ".openclaw", "openclaw.json"),
|
|
100731
|
+
pathJoin(homedir23(), ".openclaw", "openclaw.json5")
|
|
99743
100732
|
];
|
|
99744
100733
|
for (const p of openclawCandidates) {
|
|
99745
|
-
if (
|
|
100734
|
+
if (existsSync38(p)) {
|
|
99746
100735
|
openclawPath = p;
|
|
99747
100736
|
break;
|
|
99748
100737
|
}
|
|
@@ -99816,7 +100805,7 @@ async function quickInit(options) {
|
|
|
99816
100805
|
}
|
|
99817
100806
|
} else if (mode === "openclaw") {
|
|
99818
100807
|
try {
|
|
99819
|
-
const raw =
|
|
100808
|
+
const raw = readFileSync27(openclawPath, "utf-8");
|
|
99820
100809
|
const cleaned = raw.replace(/\/\/.*$/gm, "").replace(/\/\*[\s\S]*?\*\//g, "").replace(/,\s*([\]}])/g, "$1");
|
|
99821
100810
|
const parsed = JSON.parse(cleaned);
|
|
99822
100811
|
const modelsSection = parsed.models;
|
|
@@ -99944,18 +100933,18 @@ async function quickInit(options) {
|
|
|
99944
100933
|
console.error(`
|
|
99945
100934
|
Failed to save config: ${e}`);
|
|
99946
100935
|
}
|
|
99947
|
-
const userTemplatesDir = pathJoin(
|
|
100936
|
+
const userTemplatesDir = pathJoin(homedir23(), ".markus", "templates");
|
|
99948
100937
|
const builtinTemplatesDir = resolveTemplatesDir("roles");
|
|
99949
|
-
if (builtinTemplatesDir &&
|
|
100938
|
+
if (builtinTemplatesDir && existsSync38(builtinTemplatesDir) && !existsSync38(userTemplatesDir)) {
|
|
99950
100939
|
const builtinRoot = resolve17(builtinTemplatesDir, "..");
|
|
99951
|
-
|
|
100940
|
+
mkdirSync29(userTemplatesDir, { recursive: true });
|
|
99952
100941
|
cpSync5(builtinRoot, userTemplatesDir, { recursive: true });
|
|
99953
100942
|
console.log(` Copied templates to ${userTemplatesDir}`);
|
|
99954
100943
|
}
|
|
99955
100944
|
const devRoleDir = pathJoin(userTemplatesDir || pathJoin(process.cwd(), "templates"), "roles", "developer");
|
|
99956
|
-
if (!
|
|
99957
|
-
|
|
99958
|
-
|
|
100945
|
+
if (!existsSync38(devRoleDir)) {
|
|
100946
|
+
mkdirSync29(devRoleDir, { recursive: true });
|
|
100947
|
+
writeFileSync23(
|
|
99959
100948
|
pathJoin(devRoleDir, "ROLE.md"),
|
|
99960
100949
|
[
|
|
99961
100950
|
"---",
|
|
@@ -99997,7 +100986,7 @@ async function quickInit(options) {
|
|
|
99997
100986
|
console.log("");
|
|
99998
100987
|
}
|
|
99999
100988
|
console.log(` Config: ${configPath}`);
|
|
100000
|
-
console.log(` Data: ${pathJoin(
|
|
100989
|
+
console.log(` Data: ${pathJoin(homedir23(), ".markus")}`);
|
|
100001
100990
|
console.log(` Server: http://localhost:${apiPort}`);
|
|
100002
100991
|
console.log("");
|
|
100003
100992
|
}
|
|
@@ -100035,12 +101024,12 @@ function signJwt(payload, secret) {
|
|
|
100035
101024
|
const sig = base64url(createHmac2("sha256", secret).update(`${header}.${body}`).digest());
|
|
100036
101025
|
return `${header}.${body}.${sig}`;
|
|
100037
101026
|
}
|
|
100038
|
-
var
|
|
101027
|
+
var log89, _rtcModule, STUN_SERVERS, RECONNECT_BASE_MS, RECONNECT_MAX_MS, HEARTBEAT_INTERVAL_MS2, PEER_PING_INTERVAL_MS, PEER_PING_TIMEOUT_MS, RELAY_INACTIVITY_TIMEOUT_MS, RemoteAccessAgent;
|
|
100039
101028
|
var init_agent3 = __esm({
|
|
100040
101029
|
"../remote/dist/agent.js"() {
|
|
100041
101030
|
"use strict";
|
|
100042
101031
|
init_dist();
|
|
100043
|
-
|
|
101032
|
+
log89 = createLogger("remote");
|
|
100044
101033
|
_rtcModule = null;
|
|
100045
101034
|
STUN_SERVERS = [
|
|
100046
101035
|
"stun:stun.l.google.com:19302",
|
|
@@ -100048,7 +101037,7 @@ var init_agent3 = __esm({
|
|
|
100048
101037
|
];
|
|
100049
101038
|
RECONNECT_BASE_MS = 2e3;
|
|
100050
101039
|
RECONNECT_MAX_MS = 6e4;
|
|
100051
|
-
|
|
101040
|
+
HEARTBEAT_INTERVAL_MS2 = 25e3;
|
|
100052
101041
|
PEER_PING_INTERVAL_MS = 15e3;
|
|
100053
101042
|
PEER_PING_TIMEOUT_MS = 1e4;
|
|
100054
101043
|
RELAY_INACTIVITY_TIMEOUT_MS = 5 * 6e4;
|
|
@@ -100069,19 +101058,19 @@ var init_agent3 = __esm({
|
|
|
100069
101058
|
// ── Public API ────────────────────────────────────────────────────────────
|
|
100070
101059
|
async start() {
|
|
100071
101060
|
this.destroyed = false;
|
|
100072
|
-
|
|
101061
|
+
log89.info("Starting remote access agent...");
|
|
100073
101062
|
const rtc = await loadRtcModule();
|
|
100074
101063
|
rtc.initLogger("Warning");
|
|
100075
101064
|
await this.discoverLocalOwner();
|
|
100076
101065
|
try {
|
|
100077
101066
|
this.registration = await this.registerInstance();
|
|
100078
|
-
|
|
101067
|
+
log89.info("Registered with Hub", {
|
|
100079
101068
|
instanceId: this.registration.instanceId,
|
|
100080
101069
|
remoteUrl: this.registration.remoteUrl
|
|
100081
101070
|
});
|
|
100082
101071
|
this.connectSignaling();
|
|
100083
101072
|
} catch (err) {
|
|
100084
|
-
|
|
101073
|
+
log89.error("Failed to register with Hub", { error: String(err) });
|
|
100085
101074
|
this.scheduleReconnect();
|
|
100086
101075
|
}
|
|
100087
101076
|
}
|
|
@@ -100102,14 +101091,14 @@ var init_agent3 = __esm({
|
|
|
100102
101091
|
if (users?.length) {
|
|
100103
101092
|
const owner = users.find((u) => u.role === "owner") ?? users[0];
|
|
100104
101093
|
this.localOwnerUserId = owner.id;
|
|
100105
|
-
|
|
101094
|
+
log89.info("Discovered local owner", { userId: this.localOwnerUserId });
|
|
100106
101095
|
}
|
|
100107
101096
|
return;
|
|
100108
101097
|
} catch (err) {
|
|
100109
101098
|
if (attempt < 2) {
|
|
100110
101099
|
await new Promise((r) => setTimeout(r, 1e3 * (attempt + 1)));
|
|
100111
101100
|
} else {
|
|
100112
|
-
|
|
101101
|
+
log89.warn("Failed to discover local owner, using synthetic user", { error: String(err) });
|
|
100113
101102
|
}
|
|
100114
101103
|
}
|
|
100115
101104
|
}
|
|
@@ -100141,7 +101130,7 @@ var init_agent3 = __esm({
|
|
|
100141
101130
|
this.registration = null;
|
|
100142
101131
|
}
|
|
100143
101132
|
this.emitStatus();
|
|
100144
|
-
|
|
101133
|
+
log89.info("Remote access agent stopped");
|
|
100145
101134
|
}
|
|
100146
101135
|
getStatus() {
|
|
100147
101136
|
const wsOpen = this.ws?.readyState === WebSocket2.OPEN;
|
|
@@ -100250,11 +101239,11 @@ var init_agent3 = __esm({
|
|
|
100250
101239
|
return;
|
|
100251
101240
|
const { signalUrl, signalingToken } = this.registration;
|
|
100252
101241
|
const wsUrl = `${signalUrl}?token=${encodeURIComponent(signalingToken)}`;
|
|
100253
|
-
|
|
101242
|
+
log89.info("Connecting to signal server...", { signalUrl });
|
|
100254
101243
|
const ws = new WebSocket2(wsUrl);
|
|
100255
101244
|
this.ws = ws;
|
|
100256
101245
|
ws.on("open", () => {
|
|
100257
|
-
|
|
101246
|
+
log89.info("Signal server connected");
|
|
100258
101247
|
this.reconnectAttempts = 0;
|
|
100259
101248
|
this.startHeartbeat();
|
|
100260
101249
|
this.emitStatus();
|
|
@@ -100265,11 +101254,11 @@ var init_agent3 = __esm({
|
|
|
100265
101254
|
const msg = JSON.parse(data.toString());
|
|
100266
101255
|
this.handleSignalingMessage(msg);
|
|
100267
101256
|
} catch (err) {
|
|
100268
|
-
|
|
101257
|
+
log89.warn("Invalid signaling message", { error: String(err) });
|
|
100269
101258
|
}
|
|
100270
101259
|
});
|
|
100271
101260
|
ws.on("close", (code) => {
|
|
100272
|
-
|
|
101261
|
+
log89.warn("Signal server disconnected", { code });
|
|
100273
101262
|
this.stopHeartbeat();
|
|
100274
101263
|
this.ws = null;
|
|
100275
101264
|
this.emitStatus();
|
|
@@ -100277,7 +101266,7 @@ var init_agent3 = __esm({
|
|
|
100277
101266
|
this.scheduleReconnect();
|
|
100278
101267
|
});
|
|
100279
101268
|
ws.on("error", (err) => {
|
|
100280
|
-
|
|
101269
|
+
log89.error("Signal server error", { error: err.message });
|
|
100281
101270
|
});
|
|
100282
101271
|
}
|
|
100283
101272
|
handleSignalingMessage(msg) {
|
|
@@ -100288,7 +101277,7 @@ var init_agent3 = __esm({
|
|
|
100288
101277
|
this.send({ type: "pong" });
|
|
100289
101278
|
break;
|
|
100290
101279
|
case "registered":
|
|
100291
|
-
|
|
101280
|
+
log89.info("Registered with signal server", { instanceId: msg["instanceId"] });
|
|
100292
101281
|
break;
|
|
100293
101282
|
case "peer_request":
|
|
100294
101283
|
if (peerId)
|
|
@@ -100310,7 +101299,7 @@ var init_agent3 = __esm({
|
|
|
100310
101299
|
break;
|
|
100311
101300
|
case "relay_activated":
|
|
100312
101301
|
if (peerId)
|
|
100313
|
-
|
|
101302
|
+
log89.info("Peer activated relay mode", { peerId });
|
|
100314
101303
|
break;
|
|
100315
101304
|
case "relay_frame":
|
|
100316
101305
|
if (peerId && msg["data"]) {
|
|
@@ -100318,21 +101307,21 @@ var init_agent3 = __esm({
|
|
|
100318
101307
|
}
|
|
100319
101308
|
break;
|
|
100320
101309
|
default:
|
|
100321
|
-
|
|
101310
|
+
log89.debug("Unknown signaling message type", { type });
|
|
100322
101311
|
}
|
|
100323
101312
|
}
|
|
100324
101313
|
// ── WebRTC Peer Connections ───────────────────────────────────────────────
|
|
100325
101314
|
handlePeerRequest(peerId) {
|
|
100326
|
-
|
|
101315
|
+
log89.info("Peer connection requested", { peerId });
|
|
100327
101316
|
this.createPeerConnection(peerId);
|
|
100328
101317
|
}
|
|
100329
101318
|
handleOffer(peerId, sdp) {
|
|
100330
101319
|
let session = this.peers.get(peerId);
|
|
100331
101320
|
if (!session) {
|
|
100332
|
-
|
|
101321
|
+
log89.info("Received offer, creating new peer connection", { peerId });
|
|
100333
101322
|
session = this.createPeerConnection(peerId);
|
|
100334
101323
|
} else if (!session.pc) {
|
|
100335
|
-
|
|
101324
|
+
log89.info("Received offer for relay-only peer, upgrading to P2P", { peerId });
|
|
100336
101325
|
const newSession = this.createPeerConnection(peerId);
|
|
100337
101326
|
newSession.markusToken = session.markusToken;
|
|
100338
101327
|
newSession.connectedAt = session.connectedAt;
|
|
@@ -100341,14 +101330,14 @@ var init_agent3 = __esm({
|
|
|
100341
101330
|
clearInterval(session.pingTimer);
|
|
100342
101331
|
session = newSession;
|
|
100343
101332
|
} else {
|
|
100344
|
-
|
|
101333
|
+
log89.info("Received offer for existing peer (ICE restart)", { peerId });
|
|
100345
101334
|
}
|
|
100346
101335
|
session.pc.setRemoteDescription(sdp, getRtcModule().DescriptionType.Offer);
|
|
100347
101336
|
}
|
|
100348
101337
|
handleIce(peerId, candidate, mid) {
|
|
100349
101338
|
const session = this.peers.get(peerId);
|
|
100350
101339
|
if (!session?.pc) {
|
|
100351
|
-
|
|
101340
|
+
log89.warn("Received ICE candidate but no PC", { peerId, hasSession: !!session });
|
|
100352
101341
|
return;
|
|
100353
101342
|
}
|
|
100354
101343
|
session.pc.addRemoteCandidate(candidate, mid ?? "0");
|
|
@@ -100387,25 +101376,25 @@ var init_agent3 = __esm({
|
|
|
100387
101376
|
const session = { pc, dc: null, pendingChunks: /* @__PURE__ */ new Map(), markusToken: null, connectedAt: now3, lastActiveAt: now3, pingTimer: null, lastPong: now3 };
|
|
100388
101377
|
this.peers.set(peerId, session);
|
|
100389
101378
|
pc.onStateChange((state) => {
|
|
100390
|
-
|
|
101379
|
+
log89.info("Peer RTC state", { peerId, state });
|
|
100391
101380
|
if (state === "failed" || state === "closed") {
|
|
100392
101381
|
this.handlePcFailed(peerId);
|
|
100393
101382
|
}
|
|
100394
101383
|
this.emitStatus();
|
|
100395
101384
|
});
|
|
100396
101385
|
pc.onGatheringStateChange((state) => {
|
|
100397
|
-
|
|
101386
|
+
log89.info("ICE gathering", { peerId, state });
|
|
100398
101387
|
});
|
|
100399
101388
|
pc.onLocalDescription((sdp, type) => {
|
|
100400
|
-
|
|
101389
|
+
log89.info("Sending local description", { peerId, type });
|
|
100401
101390
|
this.send({ type, peerId, sdp });
|
|
100402
101391
|
});
|
|
100403
101392
|
pc.onLocalCandidate((candidate, mid) => {
|
|
100404
|
-
|
|
101393
|
+
log89.info("Sending ICE candidate", { peerId, candidate: candidate.slice(0, 60) });
|
|
100405
101394
|
this.send({ type: "ice", peerId, candidate, mid });
|
|
100406
101395
|
});
|
|
100407
101396
|
pc.onDataChannel((dc) => {
|
|
100408
|
-
|
|
101397
|
+
log89.info("DataChannel opened", { peerId, label: dc.getLabel() });
|
|
100409
101398
|
session.dc = dc;
|
|
100410
101399
|
session.lastPong = Date.now();
|
|
100411
101400
|
this.emitStatus();
|
|
@@ -100415,7 +101404,7 @@ var init_agent3 = __esm({
|
|
|
100415
101404
|
this.handleDataChannelMessage(peerId, data);
|
|
100416
101405
|
});
|
|
100417
101406
|
dc.onClosed(() => {
|
|
100418
|
-
|
|
101407
|
+
log89.info("DataChannel closed, keeping session for relay", { peerId });
|
|
100419
101408
|
session.dc = null;
|
|
100420
101409
|
this.emitStatus();
|
|
100421
101410
|
});
|
|
@@ -100426,7 +101415,7 @@ var init_agent3 = __esm({
|
|
|
100426
101415
|
const session = this.peers.get(peerId);
|
|
100427
101416
|
if (!session)
|
|
100428
101417
|
return;
|
|
100429
|
-
|
|
101418
|
+
log89.info("WebRTC failed, keeping session alive for relay", { peerId });
|
|
100430
101419
|
try {
|
|
100431
101420
|
session.dc?.close();
|
|
100432
101421
|
} catch {
|
|
@@ -100460,7 +101449,7 @@ var init_agent3 = __esm({
|
|
|
100460
101449
|
}
|
|
100461
101450
|
this.peers.delete(peerId);
|
|
100462
101451
|
this.emitStatus();
|
|
100463
|
-
|
|
101452
|
+
log89.info("Peer cleaned up", { peerId });
|
|
100464
101453
|
}
|
|
100465
101454
|
startPeerPing(peerId, session) {
|
|
100466
101455
|
if (session.pingTimer)
|
|
@@ -100470,13 +101459,13 @@ var init_agent3 = __esm({
|
|
|
100470
101459
|
session.pingTimer = setInterval(() => {
|
|
100471
101460
|
const now3 = Date.now();
|
|
100472
101461
|
if (now3 - session.lastActiveAt > RELAY_INACTIVITY_TIMEOUT_MS) {
|
|
100473
|
-
|
|
101462
|
+
log89.info("Peer inactive for too long, cleaning up", { peerId });
|
|
100474
101463
|
this.cleanupPeer(peerId);
|
|
100475
101464
|
return;
|
|
100476
101465
|
}
|
|
100477
101466
|
const elapsed = now3 - session.lastPong;
|
|
100478
101467
|
if (elapsed > PEER_PING_INTERVAL_MS + PEER_PING_TIMEOUT_MS) {
|
|
100479
|
-
|
|
101468
|
+
log89.warn("Peer ping timeout, unresponsive", { peerId, elapsed });
|
|
100480
101469
|
this.cleanupPeer(peerId);
|
|
100481
101470
|
return;
|
|
100482
101471
|
}
|
|
@@ -100517,12 +101506,12 @@ var init_agent3 = __esm({
|
|
|
100517
101506
|
this.sendToPeer(peerId, { type: "error", error: `Unknown message type: ${type}` });
|
|
100518
101507
|
}
|
|
100519
101508
|
} catch (err) {
|
|
100520
|
-
|
|
101509
|
+
log89.warn("Invalid DataChannel message", { peerId, error: String(err) });
|
|
100521
101510
|
}
|
|
100522
101511
|
}
|
|
100523
101512
|
handleRelayFrame(peerId, data) {
|
|
100524
101513
|
if (!this.peers.has(peerId)) {
|
|
100525
|
-
|
|
101514
|
+
log89.info("Relay frame from unknown peer, creating relay-only session", { peerId });
|
|
100526
101515
|
const now3 = Date.now();
|
|
100527
101516
|
this.peers.set(peerId, {
|
|
100528
101517
|
pc: null,
|
|
@@ -100716,14 +101705,14 @@ var init_agent3 = __esm({
|
|
|
100716
101705
|
session.dc.sendMessage(data);
|
|
100717
101706
|
return;
|
|
100718
101707
|
} catch (err) {
|
|
100719
|
-
|
|
101708
|
+
log89.warn("DataChannel send failed, falling back to relay", { peerId, error: String(err) });
|
|
100720
101709
|
}
|
|
100721
101710
|
}
|
|
100722
101711
|
if (this.ws?.readyState === WebSocket2.OPEN) {
|
|
100723
101712
|
this.send({ type: "relay_frame", peerId, data });
|
|
100724
101713
|
return;
|
|
100725
101714
|
}
|
|
100726
|
-
|
|
101715
|
+
log89.warn("No transport available for peer", { peerId });
|
|
100727
101716
|
}
|
|
100728
101717
|
send(msg) {
|
|
100729
101718
|
if (this.ws?.readyState === WebSocket2.OPEN) {
|
|
@@ -100734,7 +101723,7 @@ var init_agent3 = __esm({
|
|
|
100734
101723
|
this.stopHeartbeat();
|
|
100735
101724
|
this.heartbeatTimer = setInterval(() => {
|
|
100736
101725
|
this.send({ type: "pong" });
|
|
100737
|
-
},
|
|
101726
|
+
}, HEARTBEAT_INTERVAL_MS2);
|
|
100738
101727
|
}
|
|
100739
101728
|
stopHeartbeat() {
|
|
100740
101729
|
if (this.heartbeatTimer) {
|
|
@@ -100747,7 +101736,7 @@ var init_agent3 = __esm({
|
|
|
100747
101736
|
return;
|
|
100748
101737
|
const delay = Math.min(RECONNECT_BASE_MS * Math.pow(2, this.reconnectAttempts), RECONNECT_MAX_MS);
|
|
100749
101738
|
this.reconnectAttempts++;
|
|
100750
|
-
|
|
101739
|
+
log89.info(`Reconnecting in ${delay}ms (attempt ${this.reconnectAttempts})...`);
|
|
100751
101740
|
this.reconnectTimer = setTimeout(() => this.start(), delay);
|
|
100752
101741
|
}
|
|
100753
101742
|
emitStatus() {
|
|
@@ -100780,15 +101769,15 @@ var start_exports = {};
|
|
|
100780
101769
|
__export(start_exports, {
|
|
100781
101770
|
registerStartCommand: () => registerStartCommand
|
|
100782
101771
|
});
|
|
100783
|
-
import { resolve as resolve18, join as
|
|
100784
|
-
import { existsSync as
|
|
100785
|
-
import { homedir as
|
|
101772
|
+
import { resolve as resolve18, join as join34, dirname as dirname13 } from "node:path";
|
|
101773
|
+
import { existsSync as existsSync39, readFileSync as readFileSync28 } from "node:fs";
|
|
101774
|
+
import { homedir as homedir24 } from "node:os";
|
|
100786
101775
|
function registerStartCommand(program2) {
|
|
100787
101776
|
program2.command("start").description("Start the Markus server (auto-initializes on first run)").option("--setup", "Force re-run the interactive setup wizard before starting").action(async (opts) => {
|
|
100788
101777
|
const globalOpts = program2.optsWithGlobals();
|
|
100789
101778
|
const configPath = globalOpts.config ?? getDefaultConfigPath();
|
|
100790
|
-
if (opts.setup || !
|
|
100791
|
-
if (!
|
|
101779
|
+
if (opts.setup || !existsSync39(configPath)) {
|
|
101780
|
+
if (!existsSync39(configPath)) {
|
|
100792
101781
|
console.log(" No configuration found \u2014 auto-configuring from environment...\n");
|
|
100793
101782
|
}
|
|
100794
101783
|
const { quickInit: quickInit2 } = await Promise.resolve().then(() => (init_init(), init_exports));
|
|
@@ -100917,8 +101906,8 @@ async function createServices(config) {
|
|
|
100917
101906
|
extraSkillDirs: skillDirs
|
|
100918
101907
|
});
|
|
100919
101908
|
const storage = await initStorage(config.database?.url);
|
|
100920
|
-
const markusDataDir =
|
|
100921
|
-
const sharedDataDir =
|
|
101909
|
+
const markusDataDir = join34(homedir24(), ".markus");
|
|
101910
|
+
const sharedDataDir = join34(markusDataDir, "shared");
|
|
100922
101911
|
const taskService = new TaskService();
|
|
100923
101912
|
taskService.setSharedDataDir(sharedDataDir);
|
|
100924
101913
|
if (storage) {
|
|
@@ -100950,7 +101939,7 @@ async function createServices(config) {
|
|
|
100950
101939
|
const agentManager = new AgentManager({
|
|
100951
101940
|
llmRouter,
|
|
100952
101941
|
roleLoader,
|
|
100953
|
-
dataDir:
|
|
101942
|
+
dataDir: join34(markusDataDir, "agents"),
|
|
100954
101943
|
sharedDataDir,
|
|
100955
101944
|
skillRegistry,
|
|
100956
101945
|
taskService,
|
|
@@ -100990,8 +101979,10 @@ async function createServices(config) {
|
|
|
100990
101979
|
const hitlService = new HITLService();
|
|
100991
101980
|
hitlService.setOrgService(orgService);
|
|
100992
101981
|
taskService.setHITLService(hitlService);
|
|
101982
|
+
const licenseService = new LicenseService(config.hub?.url);
|
|
101983
|
+
const telemetryService = new TelemetryService(config.hub?.url ?? "https://markus.global", licenseService.getInstanceId());
|
|
100993
101984
|
const billingService = new BillingService();
|
|
100994
|
-
billingService.setOrgPlan("default",
|
|
101985
|
+
billingService.setOrgPlan("default", licenseService.getPlan());
|
|
100995
101986
|
const auditService = new AuditService();
|
|
100996
101987
|
taskService.setAuditService(auditService);
|
|
100997
101988
|
if (storage?.auditRepo) {
|
|
@@ -101006,6 +101997,8 @@ async function createServices(config) {
|
|
|
101006
101997
|
skillRegistry,
|
|
101007
101998
|
hitlService,
|
|
101008
101999
|
billingService,
|
|
102000
|
+
licenseService,
|
|
102001
|
+
telemetryService,
|
|
101009
102002
|
auditService,
|
|
101010
102003
|
bootstrapOwnerId
|
|
101011
102004
|
};
|
|
@@ -101065,10 +102058,10 @@ async function startServer(config, values) {
|
|
|
101065
102058
|
startupLog("INFO", "\u6B63\u5728\u542F\u52A8\u670D\u52A1...");
|
|
101066
102059
|
const currentPath = process.env["PATH"] ?? "";
|
|
101067
102060
|
const extraPaths = [];
|
|
101068
|
-
const selfBinDir =
|
|
102061
|
+
const selfBinDir = dirname13(resolve18(process.argv[1] ?? ""));
|
|
101069
102062
|
if (selfBinDir && !currentPath.includes(selfBinDir)) extraPaths.push(selfBinDir);
|
|
101070
|
-
const cwdBin =
|
|
101071
|
-
if (
|
|
102063
|
+
const cwdBin = join34(process.cwd(), "node_modules", ".bin");
|
|
102064
|
+
if (existsSync39(cwdBin) && !currentPath.includes(cwdBin)) extraPaths.push(cwdBin);
|
|
101072
102065
|
if (extraPaths.length > 0) {
|
|
101073
102066
|
process.env["PATH"] = `${extraPaths.join(":")}:${currentPath}`;
|
|
101074
102067
|
}
|
|
@@ -101111,6 +102104,8 @@ async function startServer(config, values) {
|
|
|
101111
102104
|
skillRegistry,
|
|
101112
102105
|
hitlService,
|
|
101113
102106
|
billingService,
|
|
102107
|
+
licenseService,
|
|
102108
|
+
telemetryService,
|
|
101114
102109
|
auditService,
|
|
101115
102110
|
bootstrapOwnerId
|
|
101116
102111
|
} = await createServices(config);
|
|
@@ -101120,6 +102115,8 @@ async function startServer(config, values) {
|
|
|
101120
102115
|
apiServer.setSkillRegistry(skillRegistry);
|
|
101121
102116
|
apiServer.setHITLService(hitlService);
|
|
101122
102117
|
apiServer.setBillingService(billingService);
|
|
102118
|
+
apiServer.setLicenseService(licenseService);
|
|
102119
|
+
apiServer.setTelemetryService(telemetryService);
|
|
101123
102120
|
apiServer.setAuditService(auditService);
|
|
101124
102121
|
const projectService = new ProjectService();
|
|
101125
102122
|
const storage = orgService.getStorage();
|
|
@@ -101133,7 +102130,7 @@ async function startServer(config, values) {
|
|
|
101133
102130
|
projectService.setProjectRepo(storage.projectRepo);
|
|
101134
102131
|
}
|
|
101135
102132
|
await projectService.loadFromDB("default");
|
|
101136
|
-
const knowledgeStore = new FileKnowledgeStore(
|
|
102133
|
+
const knowledgeStore = new FileKnowledgeStore(join34(homedir24(), ".markus", "knowledge"));
|
|
101137
102134
|
const knowledgeService = new KnowledgeService(knowledgeStore);
|
|
101138
102135
|
const deliverableService = new DeliverableService(storage?.deliverableRepo);
|
|
101139
102136
|
await deliverableService.load();
|
|
@@ -101200,17 +102197,28 @@ async function startServer(config, values) {
|
|
|
101200
102197
|
await modelCatalog.initialize();
|
|
101201
102198
|
apiServer.setModelCatalog(modelCatalog);
|
|
101202
102199
|
if (config.hub?.url) apiServer.setHubUrl(config.hub.url);
|
|
102200
|
+
telemetryService.setStatsProvider(() => {
|
|
102201
|
+
const am = orgService.getAgentManager();
|
|
102202
|
+
return {
|
|
102203
|
+
agentCount: am ? am.listAgents().length : 0,
|
|
102204
|
+
taskCount: taskService.listTasks().length,
|
|
102205
|
+
toolCallCount: billingService.getUsageSummary("default").toolCalls,
|
|
102206
|
+
teamCount: orgService.listTeams("default").length,
|
|
102207
|
+
plan: licenseService.getPlan()
|
|
102208
|
+
};
|
|
102209
|
+
});
|
|
102210
|
+
telemetryService.start();
|
|
101203
102211
|
const webUiDir = resolveWebUiDir();
|
|
101204
102212
|
if (webUiDir) {
|
|
101205
102213
|
apiServer.setWebUiDir(webUiDir);
|
|
101206
|
-
|
|
102214
|
+
log90.info("Web UI static files enabled", { dir: webUiDir });
|
|
101207
102215
|
}
|
|
101208
102216
|
{
|
|
101209
102217
|
const { LocalFileStorageProvider: LocalFileStorageProvider2 } = await Promise.resolve().then(() => (init_dist6(), dist_exports5));
|
|
101210
102218
|
const localDir = config.fileStorage?.local?.dir;
|
|
101211
102219
|
const fileStorage = new LocalFileStorageProvider2(localDir ?? void 0);
|
|
101212
102220
|
apiServer.setFileStorage(fileStorage);
|
|
101213
|
-
|
|
102221
|
+
log90.info("File storage initialized", { provider: "local", dir: localDir ?? "~/.markus/uploads" });
|
|
101214
102222
|
}
|
|
101215
102223
|
const firstOrgId = "default";
|
|
101216
102224
|
let ownerUserId = bootstrapOwnerId;
|
|
@@ -101231,7 +102239,7 @@ async function startServer(config, values) {
|
|
|
101231
102239
|
const builderService = apiServer.getBuilderService();
|
|
101232
102240
|
if (builderService) {
|
|
101233
102241
|
const builtinTeamsDir = resolveTemplatesDir("teams");
|
|
101234
|
-
if (builtinTeamsDir &&
|
|
102242
|
+
if (builtinTeamsDir && existsSync39(builtinTeamsDir)) {
|
|
101235
102243
|
builderService.setBuiltinTeamTemplatesDir(builtinTeamsDir);
|
|
101236
102244
|
}
|
|
101237
102245
|
agentManager.setBuilderService(builderService);
|
|
@@ -101294,29 +102302,29 @@ async function startServer(config, values) {
|
|
|
101294
102302
|
try {
|
|
101295
102303
|
storage.chatSessionRepo.migrateLegacyMessages();
|
|
101296
102304
|
} catch (e) {
|
|
101297
|
-
|
|
102305
|
+
log90.warn("Legacy chat message migration failed", { error: String(e) });
|
|
101298
102306
|
}
|
|
101299
102307
|
const defaultSessionUserId = ownerUserId;
|
|
101300
102308
|
try {
|
|
101301
102309
|
storage.chatSessionRepo.migrateNullUserSessions(defaultSessionUserId);
|
|
101302
102310
|
} catch (e) {
|
|
101303
|
-
|
|
102311
|
+
log90.warn("NULL user_id session migration failed", { error: String(e) });
|
|
101304
102312
|
}
|
|
101305
102313
|
try {
|
|
101306
102314
|
storage.chatSessionRepo.migrateDefaultUserSessions(defaultSessionUserId);
|
|
101307
102315
|
} catch (e) {
|
|
101308
|
-
|
|
102316
|
+
log90.warn("'default' user_id session migration failed", { error: String(e) });
|
|
101309
102317
|
}
|
|
101310
102318
|
try {
|
|
101311
102319
|
storage.notificationRepo.migrateDefaultUserId(defaultSessionUserId);
|
|
101312
102320
|
} catch (e) {
|
|
101313
|
-
|
|
102321
|
+
log90.warn("'default' user_id notification migration failed", { error: String(e) });
|
|
101314
102322
|
}
|
|
101315
102323
|
if (storage.approvalRepo) {
|
|
101316
102324
|
try {
|
|
101317
102325
|
storage.approvalRepo.migrateDefaultTargetUserId(defaultSessionUserId);
|
|
101318
102326
|
} catch (e) {
|
|
101319
|
-
|
|
102327
|
+
log90.warn("'default' target_user_id approval migration failed", { error: String(e) });
|
|
101320
102328
|
}
|
|
101321
102329
|
}
|
|
101322
102330
|
for (const info2 of agentManager.listAgents()) {
|
|
@@ -101345,7 +102353,7 @@ async function startServer(config, values) {
|
|
|
101345
102353
|
isMainSession: true
|
|
101346
102354
|
}, defaultSessionUserId);
|
|
101347
102355
|
} catch (e) {
|
|
101348
|
-
|
|
102356
|
+
log90.warn("Failed to persist activity log", { agentId: agentId2, error: String(e) });
|
|
101349
102357
|
}
|
|
101350
102358
|
});
|
|
101351
102359
|
agentManager.getEventBus().on("agent:notify-user", async (evt) => {
|
|
@@ -101398,7 +102406,7 @@ ${body}${contextSuffix}`;
|
|
|
101398
102406
|
metadata: { agentId: agentId2, agentName: agent.config.name, taskId: taskId2, requirementId: requirementId2, sessionId: mainSession.id }
|
|
101399
102407
|
});
|
|
101400
102408
|
} catch (e) {
|
|
101401
|
-
|
|
102409
|
+
log90.warn("Failed to handle notify-user event", { agentId: agentId2, error: String(e) });
|
|
101402
102410
|
}
|
|
101403
102411
|
});
|
|
101404
102412
|
agentManager.getEventBus().on("agent:escalation", async (evt) => {
|
|
@@ -101440,7 +102448,7 @@ ${reason}`;
|
|
|
101440
102448
|
success: false
|
|
101441
102449
|
});
|
|
101442
102450
|
} catch (e) {
|
|
101443
|
-
|
|
102451
|
+
log90.warn("Failed to handle escalation event", { agentId: agentId2, error: String(e) });
|
|
101444
102452
|
}
|
|
101445
102453
|
});
|
|
101446
102454
|
agentManager.getEventBus().on("agent:created", (evt) => {
|
|
@@ -101486,7 +102494,7 @@ ${reason}`;
|
|
|
101486
102494
|
heartbeatIntervalMs: agent.config.heartbeatIntervalMs
|
|
101487
102495
|
});
|
|
101488
102496
|
} catch (err) {
|
|
101489
|
-
|
|
102497
|
+
log90.warn("Failed to persist gateway agent to DB (may already exist)", { error: String(err) });
|
|
101490
102498
|
}
|
|
101491
102499
|
}
|
|
101492
102500
|
return { id: agent.id };
|
|
@@ -101531,11 +102539,11 @@ ${reason}`;
|
|
|
101531
102539
|
}));
|
|
101532
102540
|
});
|
|
101533
102541
|
apiServer.setGateway(gateway, gatewaySecret);
|
|
101534
|
-
|
|
102542
|
+
log90.info("External Agent Gateway enabled", { secret: gatewaySecret === "markus-gateway-default-secret-change-me" ? "(default)" : "(custom)" });
|
|
101535
102543
|
{
|
|
101536
|
-
const hubTokenPath =
|
|
102544
|
+
const hubTokenPath = join34(homedir24(), ".markus", "hub-token");
|
|
101537
102545
|
const createRemoteAgent = async () => {
|
|
101538
|
-
const token =
|
|
102546
|
+
const token = existsSync39(hubTokenPath) ? readFileSync28(hubTokenPath, "utf-8").trim() : void 0;
|
|
101539
102547
|
if (!token) return null;
|
|
101540
102548
|
const { RemoteAccessAgent: RemoteAccessAgent2 } = await Promise.resolve().then(() => (init_dist8(), dist_exports6));
|
|
101541
102549
|
return new RemoteAccessAgent2({
|
|
@@ -101547,7 +102555,7 @@ ${reason}`;
|
|
|
101547
102555
|
});
|
|
101548
102556
|
};
|
|
101549
102557
|
apiServer.setRemoteAgentFactory(createRemoteAgent);
|
|
101550
|
-
if (config.remote?.enabled
|
|
102558
|
+
if (config.remote?.enabled === true) {
|
|
101551
102559
|
const remoteAgent = await createRemoteAgent();
|
|
101552
102560
|
if (remoteAgent) {
|
|
101553
102561
|
apiServer.setRemoteAgent(remoteAgent);
|
|
@@ -101555,14 +102563,14 @@ ${reason}`;
|
|
|
101555
102563
|
remoteAgent.start().then(() => {
|
|
101556
102564
|
const status = remoteAgent.getStatus();
|
|
101557
102565
|
if (status.remoteUrl) {
|
|
101558
|
-
|
|
102566
|
+
log90.info(`Remote access available at ${status.remoteUrl}`);
|
|
101559
102567
|
}
|
|
101560
102568
|
}).catch((err) => {
|
|
101561
|
-
|
|
102569
|
+
log90.warn("Remote access failed to start", { error: String(err) });
|
|
101562
102570
|
});
|
|
101563
102571
|
}
|
|
101564
102572
|
} else {
|
|
101565
|
-
|
|
102573
|
+
log90.debug("Remote access: no Hub token yet (can enable later via Settings)");
|
|
101566
102574
|
}
|
|
101567
102575
|
}
|
|
101568
102576
|
}
|
|
@@ -101573,7 +102581,7 @@ ${reason}`;
|
|
|
101573
102581
|
const scheduledTaskRunner = new ScheduledTaskRunner(taskService);
|
|
101574
102582
|
scheduledTaskRunner.start();
|
|
101575
102583
|
agentManager.setEscalationHandler((agentId2, reason) => {
|
|
101576
|
-
|
|
102584
|
+
log90.warn("Agent escalation", { agentId: agentId2, reason });
|
|
101577
102585
|
});
|
|
101578
102586
|
agentManager.setApprovalHandler(async (agentId2, request) => {
|
|
101579
102587
|
const agents = agentManager.listAgents();
|
|
@@ -101640,6 +102648,17 @@ ${reason}`;
|
|
|
101640
102648
|
});
|
|
101641
102649
|
}
|
|
101642
102650
|
});
|
|
102651
|
+
billingService.setToolCallsTodayProvider(() => {
|
|
102652
|
+
let total = 0;
|
|
102653
|
+
for (const a of agentManager.listAgents()) {
|
|
102654
|
+
try {
|
|
102655
|
+
total += agentManager.getAgent(a.id).getUsageStats().toolCallsToday;
|
|
102656
|
+
} catch {
|
|
102657
|
+
}
|
|
102658
|
+
}
|
|
102659
|
+
return total;
|
|
102660
|
+
});
|
|
102661
|
+
agentManager.setToolCallLimitChecker(() => billingService.checkLimit("default", "tool_call"));
|
|
101643
102662
|
if (storage) {
|
|
101644
102663
|
agentManager.setStateChangeHandler(async (agentId2, state) => {
|
|
101645
102664
|
try {
|
|
@@ -101648,7 +102667,7 @@ ${reason}`;
|
|
|
101648
102667
|
state.status
|
|
101649
102668
|
);
|
|
101650
102669
|
} catch (err) {
|
|
101651
|
-
|
|
102670
|
+
log90.warn("Failed to persist agent state", { agentId: agentId2, error: String(err) });
|
|
101652
102671
|
}
|
|
101653
102672
|
apiServer.getWSBroadcaster().broadcastAgentUpdate(agentId2, state.status, {
|
|
101654
102673
|
lastError: state.lastError,
|
|
@@ -101673,7 +102692,7 @@ ${reason}`;
|
|
|
101673
102692
|
startedAt: activity.startedAt
|
|
101674
102693
|
});
|
|
101675
102694
|
} catch (err) {
|
|
101676
|
-
|
|
102695
|
+
log90.warn("Failed to persist activity start", { activityId: activity.id, error: String(err) });
|
|
101677
102696
|
}
|
|
101678
102697
|
},
|
|
101679
102698
|
onLog: (data) => {
|
|
@@ -101689,20 +102708,20 @@ ${reason}`;
|
|
|
101689
102708
|
metadata: data.metadata
|
|
101690
102709
|
});
|
|
101691
102710
|
} catch (err) {
|
|
101692
|
-
|
|
102711
|
+
log90.warn("Failed to persist execution stream activity log", { activityId: data.activityId, error: String(err) });
|
|
101693
102712
|
}
|
|
101694
102713
|
}
|
|
101695
102714
|
try {
|
|
101696
102715
|
actRepo.insertActivityLog(data);
|
|
101697
102716
|
} catch (err) {
|
|
101698
|
-
|
|
102717
|
+
log90.warn("Failed to persist activity log", { activityId: data.activityId, error: String(err) });
|
|
101699
102718
|
}
|
|
101700
102719
|
},
|
|
101701
102720
|
onEnd: (activityId, summary) => {
|
|
101702
102721
|
try {
|
|
101703
102722
|
actRepo.updateActivity(activityId, summary);
|
|
101704
102723
|
} catch (err) {
|
|
101705
|
-
|
|
102724
|
+
log90.warn("Failed to persist activity end", { activityId, error: String(err) });
|
|
101706
102725
|
}
|
|
101707
102726
|
}
|
|
101708
102727
|
});
|
|
@@ -101745,14 +102764,14 @@ ${reason}`;
|
|
|
101745
102764
|
queuedAt: item.queuedAt
|
|
101746
102765
|
});
|
|
101747
102766
|
} catch (e) {
|
|
101748
|
-
|
|
102767
|
+
log90.warn("Failed to persist mailbox item", { id: item.id, error: String(e) });
|
|
101749
102768
|
}
|
|
101750
102769
|
},
|
|
101751
102770
|
updateStatus: (itemId, status, extra) => {
|
|
101752
102771
|
try {
|
|
101753
102772
|
mbRepo.updateStatus(itemId, status, extra);
|
|
101754
102773
|
} catch (e) {
|
|
101755
|
-
|
|
102774
|
+
log90.warn("Failed to update mailbox status", { itemId, error: String(e) });
|
|
101756
102775
|
}
|
|
101757
102776
|
},
|
|
101758
102777
|
markStaleProcessingAsDropped: (aid) => mbRepo.markStaleProcessingAsDropped(aid),
|
|
@@ -101795,7 +102814,7 @@ ${reason}`;
|
|
|
101795
102814
|
}
|
|
101796
102815
|
});
|
|
101797
102816
|
const { dropped, restored, expired, merged } = mailbox.recoverStaleItems();
|
|
101798
|
-
if (dropped > 0 || restored > 0 || expired > 0 || merged > 0)
|
|
102817
|
+
if (dropped > 0 || restored > 0 || expired > 0 || merged > 0) log90.info("Mailbox recovery on startup", { agentId: agentId2, dropped, restored, expired, merged });
|
|
101799
102818
|
agent.getAttentionController().setDecisionPersistence({
|
|
101800
102819
|
save: (decision) => {
|
|
101801
102820
|
try {
|
|
@@ -101810,7 +102829,7 @@ ${reason}`;
|
|
|
101810
102829
|
createdAt: decision.createdAt
|
|
101811
102830
|
});
|
|
101812
102831
|
} catch (e) {
|
|
101813
|
-
|
|
102832
|
+
log90.warn("Failed to persist decision", { id: decision.id, error: String(e) });
|
|
101814
102833
|
}
|
|
101815
102834
|
}
|
|
101816
102835
|
});
|
|
@@ -101905,7 +102924,7 @@ ${reason}`;
|
|
|
101905
102924
|
llmConfig: agent.config.llmConfig,
|
|
101906
102925
|
heartbeatIntervalMs: agent.config.heartbeatIntervalMs
|
|
101907
102926
|
}).catch((err) => {
|
|
101908
|
-
|
|
102927
|
+
log90.warn("Failed to persist runtime-created agent to DB", { agentId: agentId2, error: String(err) });
|
|
101909
102928
|
});
|
|
101910
102929
|
} catch {
|
|
101911
102930
|
}
|
|
@@ -101988,7 +103007,7 @@ ${reason}`;
|
|
|
101988
103007
|
const nextMidnight = new Date(now3.getFullYear(), now3.getMonth(), now3.getDate() + 1, 0, 0, 0, 0);
|
|
101989
103008
|
const msUntilMidnight = nextMidnight.getTime() - now3.getTime();
|
|
101990
103009
|
setTimeout(() => {
|
|
101991
|
-
|
|
103010
|
+
log90.info("Daily token reset triggered");
|
|
101992
103011
|
for (const agentInfo of agentManager.listAgents()) {
|
|
101993
103012
|
try {
|
|
101994
103013
|
const agent = agentManager.getAgent(agentInfo.id);
|
|
@@ -101998,7 +103017,7 @@ ${reason}`;
|
|
|
101998
103017
|
}
|
|
101999
103018
|
scheduleDailyReset();
|
|
102000
103019
|
}, msUntilMidnight);
|
|
102001
|
-
|
|
103020
|
+
log90.info(`Daily token reset scheduled in ${Math.round(msUntilMidnight / 6e4)} minutes`);
|
|
102002
103021
|
};
|
|
102003
103022
|
scheduleDailyReset();
|
|
102004
103023
|
const messageRouter = new MessageRouter();
|
|
@@ -102029,7 +103048,7 @@ ${reason}`;
|
|
|
102029
103048
|
durationMs: Date.now() - startTs,
|
|
102030
103049
|
success: false
|
|
102031
103050
|
});
|
|
102032
|
-
|
|
103051
|
+
log90.error("Agent message handler error", { error: String(error) });
|
|
102033
103052
|
return void 0;
|
|
102034
103053
|
}
|
|
102035
103054
|
});
|
|
@@ -102065,7 +103084,7 @@ ${reason}`;
|
|
|
102065
103084
|
if (info2.updateAvailable) {
|
|
102066
103085
|
console.log(`
|
|
102067
103086
|
\x1B[33m\u2B06 New version available: v${info2.latestVersion} (current: v${info2.currentVersion})\x1B[0m`);
|
|
102068
|
-
console.log(`
|
|
103087
|
+
console.log(` Visit \x1B[1mhttps://markus.global/download\x1B[0m to download the latest version
|
|
102069
103088
|
`);
|
|
102070
103089
|
}
|
|
102071
103090
|
}).catch(() => {
|
|
@@ -102074,7 +103093,7 @@ ${reason}`;
|
|
|
102074
103093
|
try {
|
|
102075
103094
|
await taskService.resumeInProgressTasks();
|
|
102076
103095
|
} catch (err) {
|
|
102077
|
-
|
|
103096
|
+
log90.warn("Failed to auto-resume in_progress tasks", { error: String(err) });
|
|
102078
103097
|
}
|
|
102079
103098
|
});
|
|
102080
103099
|
process.on("SIGINT", () => {
|
|
@@ -102090,7 +103109,7 @@ ${reason}`;
|
|
|
102090
103109
|
await new Promise(() => {
|
|
102091
103110
|
});
|
|
102092
103111
|
}
|
|
102093
|
-
var
|
|
103112
|
+
var log90;
|
|
102094
103113
|
var init_start = __esm({
|
|
102095
103114
|
"src/commands/start.ts"() {
|
|
102096
103115
|
"use strict";
|
|
@@ -102102,7 +103121,7 @@ var init_start = __esm({
|
|
|
102102
103121
|
init_logger2();
|
|
102103
103122
|
init_browser();
|
|
102104
103123
|
init_startupProgress();
|
|
102105
|
-
|
|
103124
|
+
log90 = createLogger("cli");
|
|
102106
103125
|
}
|
|
102107
103126
|
});
|
|
102108
103127
|
|
|
@@ -102731,8 +103750,8 @@ ${C3.BOLD}${C3.CYAN}\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
|
102731
103750
|
}
|
|
102732
103751
|
}
|
|
102733
103752
|
section("Storage");
|
|
102734
|
-
const { homedir:
|
|
102735
|
-
const storageDir = `${
|
|
103753
|
+
const { homedir: homedir25 } = await import("node:os");
|
|
103754
|
+
const storageDir = `${homedir25()}/.markus`;
|
|
102736
103755
|
const dataFile = `${storageDir}/data.db`;
|
|
102737
103756
|
try {
|
|
102738
103757
|
if (!fs.existsSync(storageDir)) {
|
|
@@ -102756,7 +103775,7 @@ ${C3.BOLD}${C3.CYAN}\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
|
102756
103775
|
checkFail(`Storage check failed: ${e}`);
|
|
102757
103776
|
}
|
|
102758
103777
|
section("Skills");
|
|
102759
|
-
const skillsDir = `${
|
|
103778
|
+
const skillsDir = `${homedir25()}/.markus/skills`;
|
|
102760
103779
|
if (fs.existsSync(skillsDir)) {
|
|
102761
103780
|
try {
|
|
102762
103781
|
const entries2 = fs.readdirSync(skillsDir);
|
|
@@ -102835,9 +103854,9 @@ ${C3.BOLD}\u25C6 Summary${C3.RESET}
|
|
|
102835
103854
|
}
|
|
102836
103855
|
}
|
|
102837
103856
|
async function getDefaultConfigPath2() {
|
|
102838
|
-
const { homedir:
|
|
102839
|
-
const { join:
|
|
102840
|
-
return
|
|
103857
|
+
const { homedir: homedir25 } = await import("node:os");
|
|
103858
|
+
const { join: join35 } = await import("node:path");
|
|
103859
|
+
return join35(homedir25(), ".markus", "markus.json");
|
|
102841
103860
|
}
|
|
102842
103861
|
function registerDoctorCommand(program2) {
|
|
102843
103862
|
program2.command("doctor").description("Diagnose Markus configuration issues and environment health").option("--fix", "Attempt to automatically fix issues").option("--verbose", "Show detailed output").action(async (opts) => {
|
|
@@ -103339,19 +104358,19 @@ __export(install_agent_exports, {
|
|
|
103339
104358
|
import { execSync as execSync5 } from "node:child_process";
|
|
103340
104359
|
import { randomBytes as randomBytes6 } from "node:crypto";
|
|
103341
104360
|
function registerInstallAgentCommands(program2) {
|
|
103342
|
-
program2.command("install <platform>").description("Install an external agent platform and connect it to Markus").option("--org-id <id>", "Organization ID", "default").option("--agent-name <name>", "Agent display name").option("--skip-install", "Skip npm install (platform already installed)").option("--skip-init", "Skip platform initialization").option("--skip-connect", "Only install, do not register with Markus").action(async (
|
|
104361
|
+
program2.command("install <platform>").description("Install an external agent platform and connect it to Markus").option("--org-id <id>", "Organization ID", "default").option("--agent-name <name>", "Agent display name").option("--skip-install", "Skip npm install (platform already installed)").option("--skip-init", "Skip platform initialization").option("--skip-connect", "Only install, do not register with Markus").action(async (platform5, opts, cmd) => {
|
|
103343
104362
|
const g = cmd.optsWithGlobals();
|
|
103344
|
-
const connector = findConnector(
|
|
104363
|
+
const connector = findConnector(platform5);
|
|
103345
104364
|
if (!connector) {
|
|
103346
104365
|
const available = loadConnectors().map((c) => c.platform).join(", ");
|
|
103347
|
-
fail(`Unknown platform "${
|
|
104366
|
+
fail(`Unknown platform "${platform5}". Available: ${available || "none"}`);
|
|
103348
104367
|
return;
|
|
103349
104368
|
}
|
|
103350
104369
|
console.log(`
|
|
103351
104370
|
Installing ${connector.displayName}...
|
|
103352
104371
|
`);
|
|
103353
104372
|
const scan = scanInstalledPlatforms();
|
|
103354
|
-
const existing = scan.find((s2) => s2.platform ===
|
|
104373
|
+
const existing = scan.find((s2) => s2.platform === platform5);
|
|
103355
104374
|
const alreadyInstalled = existing?.installed;
|
|
103356
104375
|
if (alreadyInstalled && !opts.skipInstall) {
|
|
103357
104376
|
console.log(` [1/5] ${connector.displayName} is already installed.`);
|
|
@@ -103387,13 +104406,13 @@ function registerInstallAgentCommands(program2) {
|
|
|
103387
104406
|
console.log(` [4/5] Token generation skipped.`);
|
|
103388
104407
|
console.log(` [5/5] Config write skipped.`);
|
|
103389
104408
|
console.log(`
|
|
103390
|
-
${connector.displayName} installed. Run \`markus install ${
|
|
104409
|
+
${connector.displayName} installed. Run \`markus install ${platform5}\` again without --skip-connect to connect later.
|
|
103391
104410
|
`);
|
|
103392
104411
|
return;
|
|
103393
104412
|
}
|
|
103394
104413
|
const client = createClient(g);
|
|
103395
104414
|
const serverUrl = g.server || process.env["MARKUS_API_URL"] || "http://localhost:8056";
|
|
103396
|
-
const agentId2 = `${
|
|
104415
|
+
const agentId2 = `${platform5}-${randomBytes6(4).toString("hex")}`;
|
|
103397
104416
|
const agentName = opts.agentName || connector.defaultAgentName || `${connector.displayName} Agent`;
|
|
103398
104417
|
const capabilities = connector.defaultCapabilities ?? [];
|
|
103399
104418
|
try {
|
|
@@ -103456,7 +104475,7 @@ function registerInstallAgentCommands(program2) {
|
|
|
103456
104475
|
Connection failed: ${e.message}`);
|
|
103457
104476
|
console.log(` ${connector.displayName} was installed but could not connect to Markus.`);
|
|
103458
104477
|
console.log(` Make sure the Markus server is running (\`markus start\`), then run:`);
|
|
103459
|
-
console.log(` markus install ${
|
|
104478
|
+
console.log(` markus install ${platform5}
|
|
103460
104479
|
`);
|
|
103461
104480
|
return;
|
|
103462
104481
|
}
|
|
@@ -103552,14 +104571,14 @@ __export(system_exports, {
|
|
|
103552
104571
|
registerSystemCommands: () => registerSystemCommands
|
|
103553
104572
|
});
|
|
103554
104573
|
import { execSync as execSync6 } from "node:child_process";
|
|
103555
|
-
import { existsSync as
|
|
103556
|
-
import { resolve as resolve19, dirname as
|
|
104574
|
+
import { existsSync as existsSync40, readFileSync as readFileSync29 } from "node:fs";
|
|
104575
|
+
import { resolve as resolve19, dirname as dirname14 } from "node:path";
|
|
103557
104576
|
import { fileURLToPath as fileURLToPath7 } from "node:url";
|
|
103558
104577
|
function findMarkusRoot() {
|
|
103559
|
-
let dir =
|
|
104578
|
+
let dir = dirname14(fileURLToPath7(import.meta.url));
|
|
103560
104579
|
for (let i = 0; i < 10; i++) {
|
|
103561
|
-
if (
|
|
103562
|
-
dir =
|
|
104580
|
+
if (existsSync40(resolve19(dir, "package.json")) && existsSync40(resolve19(dir, "packages"))) return dir;
|
|
104581
|
+
dir = dirname14(dir);
|
|
103563
104582
|
}
|
|
103564
104583
|
return null;
|
|
103565
104584
|
}
|
|
@@ -103609,13 +104628,13 @@ function registerSystemCommands(program2) {
|
|
|
103609
104628
|
if (markusRoot) {
|
|
103610
104629
|
if (!info2.currentVersion) {
|
|
103611
104630
|
try {
|
|
103612
|
-
const pkg = JSON.parse(
|
|
104631
|
+
const pkg = JSON.parse(readFileSync29(resolve19(markusRoot, "package.json"), "utf-8"));
|
|
103613
104632
|
info2.currentVersion = pkg.version;
|
|
103614
104633
|
} catch {
|
|
103615
104634
|
}
|
|
103616
104635
|
}
|
|
103617
104636
|
try {
|
|
103618
|
-
const isGit =
|
|
104637
|
+
const isGit = existsSync40(resolve19(markusRoot, ".git"));
|
|
103619
104638
|
if (isGit) {
|
|
103620
104639
|
info2.gitBranch = execSync6("git rev-parse --abbrev-ref HEAD", { cwd: markusRoot, encoding: "utf-8" }).trim();
|
|
103621
104640
|
info2.gitCommit = execSync6("git rev-parse --short HEAD", { cwd: markusRoot, encoding: "utf-8" }).trim();
|
|
@@ -103654,7 +104673,7 @@ function registerSystemCommands(program2) {
|
|
|
103654
104673
|
fail("Cannot locate Markus installation directory");
|
|
103655
104674
|
return;
|
|
103656
104675
|
}
|
|
103657
|
-
if (!
|
|
104676
|
+
if (!existsSync40(resolve19(markusRoot, ".git"))) {
|
|
103658
104677
|
fail("Markus installation is not a git repository. Update manually.");
|
|
103659
104678
|
return;
|
|
103660
104679
|
}
|
|
@@ -103689,7 +104708,7 @@ var init_system = __esm({
|
|
|
103689
104708
|
|
|
103690
104709
|
// src/index.ts
|
|
103691
104710
|
import { resolve as resolve20 } from "node:path";
|
|
103692
|
-
import { readFileSync as
|
|
104711
|
+
import { readFileSync as readFileSync30, existsSync as existsSync41 } from "node:fs";
|
|
103693
104712
|
import process2 from "node:process";
|
|
103694
104713
|
|
|
103695
104714
|
// ../../node_modules/.pnpm/commander@14.0.3/node_modules/commander/esm.mjs
|
|
@@ -103713,8 +104732,8 @@ var {
|
|
|
103713
104732
|
init_dist();
|
|
103714
104733
|
init_output();
|
|
103715
104734
|
var envPath = resolve20(process2.cwd(), ".env");
|
|
103716
|
-
if (
|
|
103717
|
-
for (const line of
|
|
104735
|
+
if (existsSync41(envPath)) {
|
|
104736
|
+
for (const line of readFileSync30(envPath, "utf-8").split("\n")) {
|
|
103718
104737
|
const trimmed = line.trim();
|
|
103719
104738
|
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
103720
104739
|
const eqIdx = trimmed.indexOf("=");
|