@markus-global/cli 0.7.13 → 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 +1586 -469
- package/dist/web-ui/assets/{browser-DWGYIG_5.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-BJxNeAk8.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);
|
|
@@ -44727,7 +44758,8 @@ var init_attention = __esm({
|
|
|
44727
44758
|
}
|
|
44728
44759
|
await this.processFocusedItem(item);
|
|
44729
44760
|
} catch (err) {
|
|
44730
|
-
|
|
44761
|
+
const isUserInteraction = _AttentionController.USER_INTERACTION_TYPES.has(item.sourceType);
|
|
44762
|
+
log14.error(`Attention loop iteration failed \u2014 ${isUserInteraction ? "completing" : "requeueing"} item and continuing`, {
|
|
44731
44763
|
agentId: this.agentId,
|
|
44732
44764
|
itemId: item.id,
|
|
44733
44765
|
type: item.sourceType,
|
|
@@ -44738,9 +44770,16 @@ var init_attention = __esm({
|
|
|
44738
44770
|
this.interruptSignal = false;
|
|
44739
44771
|
this.pendingInterruptItem = void 0;
|
|
44740
44772
|
this.lastYieldDecision = void 0;
|
|
44741
|
-
|
|
44742
|
-
|
|
44743
|
-
|
|
44773
|
+
if (isUserInteraction) {
|
|
44774
|
+
try {
|
|
44775
|
+
this.mailbox.complete(item.id);
|
|
44776
|
+
} catch {
|
|
44777
|
+
}
|
|
44778
|
+
} else {
|
|
44779
|
+
try {
|
|
44780
|
+
this.mailbox.requeue(item);
|
|
44781
|
+
} catch {
|
|
44782
|
+
}
|
|
44744
44783
|
}
|
|
44745
44784
|
}
|
|
44746
44785
|
} catch (outerErr) {
|
|
@@ -44841,15 +44880,33 @@ var init_attention = __esm({
|
|
|
44841
44880
|
} else {
|
|
44842
44881
|
const abnormalReason = detectAbnormalCompletion(reply, item);
|
|
44843
44882
|
const retries = item.retryCount ?? 0;
|
|
44883
|
+
const isUserInteraction = _AttentionController.USER_INTERACTION_TYPES.has(item.sourceType);
|
|
44844
44884
|
if (abnormalReason && retries < MAILBOX_ITEM_MAX_RETRIES) {
|
|
44845
|
-
|
|
44846
|
-
|
|
44847
|
-
|
|
44848
|
-
|
|
44849
|
-
|
|
44850
|
-
|
|
44851
|
-
|
|
44852
|
-
|
|
44885
|
+
if (abnormalReason === "completion marker missing from reply") {
|
|
44886
|
+
log14.warn("Completion marker still missing after in-session continuation \u2014 completing without retry", {
|
|
44887
|
+
agentId: this.agentId,
|
|
44888
|
+
itemId: item.id,
|
|
44889
|
+
type: item.sourceType
|
|
44890
|
+
});
|
|
44891
|
+
this.mailbox.complete(item.id);
|
|
44892
|
+
} else if (isUserInteraction) {
|
|
44893
|
+
log14.warn("Abnormal completion for user interaction \u2014 completing without retry", {
|
|
44894
|
+
agentId: this.agentId,
|
|
44895
|
+
itemId: item.id,
|
|
44896
|
+
type: item.sourceType,
|
|
44897
|
+
reason: abnormalReason
|
|
44898
|
+
});
|
|
44899
|
+
this.mailbox.complete(item.id);
|
|
44900
|
+
} else {
|
|
44901
|
+
log14.warn("Abnormal completion detected, requeueing for retry", {
|
|
44902
|
+
agentId: this.agentId,
|
|
44903
|
+
itemId: item.id,
|
|
44904
|
+
type: item.sourceType,
|
|
44905
|
+
retryCount: retries + 1,
|
|
44906
|
+
reason: abnormalReason
|
|
44907
|
+
});
|
|
44908
|
+
this.mailbox.requeue(item);
|
|
44909
|
+
}
|
|
44853
44910
|
} else {
|
|
44854
44911
|
if (abnormalReason) {
|
|
44855
44912
|
log14.error("Abnormal completion persisted after max retries, completing anyway", {
|
|
@@ -46779,6 +46836,7 @@ var init_agent2 = __esm({
|
|
|
46779
46836
|
auditCallback;
|
|
46780
46837
|
escalationCallback;
|
|
46781
46838
|
approvalCallback;
|
|
46839
|
+
toolCallLimitChecker;
|
|
46782
46840
|
tasksFetcher;
|
|
46783
46841
|
consecutiveFailures = 0;
|
|
46784
46842
|
metricsCollector;
|
|
@@ -47328,6 +47386,57 @@ ${notification.stdoutTail}`);
|
|
|
47328
47386
|
}
|
|
47329
47387
|
};
|
|
47330
47388
|
}
|
|
47389
|
+
/**
|
|
47390
|
+
* If the reply is missing the required completion marker, inject a
|
|
47391
|
+
* continuation prompt into the existing session and make one more LLM
|
|
47392
|
+
* call to obtain it — instead of letting the attention controller
|
|
47393
|
+
* requeue the entire item from scratch (which duplicates side effects).
|
|
47394
|
+
*
|
|
47395
|
+
* Limited to a single attempt; if the marker is still missing afterwards
|
|
47396
|
+
* the reply is returned as-is and the attention controller will complete
|
|
47397
|
+
* the item without retry.
|
|
47398
|
+
*/
|
|
47399
|
+
async ensureCompletionMarker(reply, sessionId) {
|
|
47400
|
+
if (!reply || reply === "[cancelled]" || reply === "[preempted]" || reply === "[merged]")
|
|
47401
|
+
return reply;
|
|
47402
|
+
if (reply.includes(COMPLETION_MARKER))
|
|
47403
|
+
return reply;
|
|
47404
|
+
if (!sessionId || !this.memory.getSession(sessionId))
|
|
47405
|
+
return reply;
|
|
47406
|
+
log17.info("Completion marker missing \u2014 continuing in-session to obtain marker", {
|
|
47407
|
+
agentId: this.id,
|
|
47408
|
+
sessionId,
|
|
47409
|
+
replyLength: reply.length
|
|
47410
|
+
});
|
|
47411
|
+
this.memory.appendMessage(sessionId, {
|
|
47412
|
+
role: "user",
|
|
47413
|
+
content: `[SYSTEM] Your previous response did not include the required completion marker. You MUST end your response with exactly: ${COMPLETION_MARKER}`
|
|
47414
|
+
});
|
|
47415
|
+
try {
|
|
47416
|
+
const sessionMessages = this.memory.getRecentMessages(sessionId, 50);
|
|
47417
|
+
const prepared = await this.contextEngine.prepareMessages({
|
|
47418
|
+
systemPrompt: "You are completing a previous response. Finish any remaining work and end your response with the required completion marker.",
|
|
47419
|
+
sessionMessages,
|
|
47420
|
+
memory: this.memory,
|
|
47421
|
+
sessionId,
|
|
47422
|
+
agentId: this.id,
|
|
47423
|
+
modelContextWindow: this.llmRouter.getModelContextWindow(this.getEffectiveProvider()),
|
|
47424
|
+
modelMaxOutput: this.llmRouter.getModelMaxOutput(this.getEffectiveProvider()),
|
|
47425
|
+
toolDefinitions: []
|
|
47426
|
+
});
|
|
47427
|
+
const continuation = await this.llmRouter.chat({ messages: prepared.messages }, this.getEffectiveProvider());
|
|
47428
|
+
const contReply = continuation.content ?? "";
|
|
47429
|
+
this.memory.appendMessage(sessionId, { role: "assistant", content: contReply });
|
|
47430
|
+
return reply + contReply;
|
|
47431
|
+
} catch (err) {
|
|
47432
|
+
log17.warn("Failed to obtain completion marker via continuation \u2014 returning original reply", {
|
|
47433
|
+
agentId: this.id,
|
|
47434
|
+
sessionId,
|
|
47435
|
+
error: String(err)
|
|
47436
|
+
});
|
|
47437
|
+
return reply;
|
|
47438
|
+
}
|
|
47439
|
+
}
|
|
47331
47440
|
/**
|
|
47332
47441
|
* Route a mailbox item to the appropriate Agent processing method.
|
|
47333
47442
|
* Options like sessionId/images/scenario are forwarded from payload.extra
|
|
@@ -47410,7 +47519,9 @@ ${item.payload.content}` + batchSuffix;
|
|
|
47410
47519
|
itemId: item.id
|
|
47411
47520
|
});
|
|
47412
47521
|
} else {
|
|
47413
|
-
|
|
47522
|
+
let reply2 = await this.handleMessageStream(item.payload.content + markerSuffix, extra.onEvent, item.metadata?.senderId, senderInfo, ct, extra.images, extra.fileNames);
|
|
47523
|
+
if (needsMarker)
|
|
47524
|
+
reply2 = await this.ensureCompletionMarker(reply2, this.currentSessionId);
|
|
47414
47525
|
resolveResponse(reply2);
|
|
47415
47526
|
return reply2;
|
|
47416
47527
|
}
|
|
@@ -47424,7 +47535,9 @@ ${item.payload.content}` + batchSuffix;
|
|
|
47424
47535
|
const opts = buildHandleOpts(defaults);
|
|
47425
47536
|
if (item.sourceType === "a2a_message")
|
|
47426
47537
|
opts.scenario = "a2a";
|
|
47427
|
-
|
|
47538
|
+
let reply = await this.handleMessage(item.payload.content + markerSuffix, item.metadata?.senderId, senderInfo, opts);
|
|
47539
|
+
if (needsMarker)
|
|
47540
|
+
reply = await this.ensureCompletionMarker(reply, opts.sessionId ?? this.currentSessionId);
|
|
47428
47541
|
resolveResponse(reply);
|
|
47429
47542
|
return reply;
|
|
47430
47543
|
}
|
|
@@ -47454,7 +47567,10 @@ ${item.payload.content}` + batchSuffix;
|
|
|
47454
47567
|
return;
|
|
47455
47568
|
}
|
|
47456
47569
|
case "mention": {
|
|
47457
|
-
const
|
|
47570
|
+
const mentionSessionId = `sys_${this.id}_${ts}`;
|
|
47571
|
+
let reply = await this.handleMessage(item.payload.content + markerSuffix, item.metadata?.senderId, senderInfo, buildHandleOpts({ sessionId: mentionSessionId, scenario: "a2a" }));
|
|
47572
|
+
if (needsMarker)
|
|
47573
|
+
reply = await this.ensureCompletionMarker(reply, mentionSessionId);
|
|
47458
47574
|
resolveResponse(reply);
|
|
47459
47575
|
return reply;
|
|
47460
47576
|
}
|
|
@@ -47492,7 +47608,10 @@ ${item.payload.content}` + batchSuffix;
|
|
|
47492
47608
|
return;
|
|
47493
47609
|
}
|
|
47494
47610
|
case "review_request": {
|
|
47495
|
-
const
|
|
47611
|
+
const reviewSessionId = `review_${this.id}_${ts}`;
|
|
47612
|
+
let reply = await this.handleMessage(item.payload.content + markerSuffix, item.metadata?.senderId, item.metadata?.senderName ? { name: item.metadata.senderName, role: item.metadata.senderRole ?? "worker" } : void 0, buildHandleOpts({ sessionId: reviewSessionId, scenario: "review" }));
|
|
47613
|
+
if (needsMarker)
|
|
47614
|
+
reply = await this.ensureCompletionMarker(reply, reviewSessionId);
|
|
47496
47615
|
resolveResponse(reply);
|
|
47497
47616
|
return reply;
|
|
47498
47617
|
}
|
|
@@ -47507,12 +47626,18 @@ ${item.payload.content}` + batchSuffix;
|
|
|
47507
47626
|
}
|
|
47508
47627
|
case "system_event":
|
|
47509
47628
|
case "daily_report": {
|
|
47510
|
-
const
|
|
47629
|
+
const sysSessionId = `sys_${this.id}_${ts}`;
|
|
47630
|
+
let reply = await this.handleMessage(item.payload.content + markerSuffix, void 0, void 0, buildHandleOpts({ sessionId: sysSessionId, scenario: "heartbeat" }));
|
|
47631
|
+
if (needsMarker)
|
|
47632
|
+
reply = await this.ensureCompletionMarker(reply, sysSessionId);
|
|
47511
47633
|
resolveResponse(reply);
|
|
47512
47634
|
return reply;
|
|
47513
47635
|
}
|
|
47514
47636
|
case "memory_consolidation": {
|
|
47515
|
-
const
|
|
47637
|
+
const memSessionId = `sys_${this.id}_${ts}`;
|
|
47638
|
+
let reply = await this.handleMessage(item.payload.content + markerSuffix, void 0, void 0, buildHandleOpts({ sessionId: memSessionId, scenario: "memory_consolidation" }));
|
|
47639
|
+
if (needsMarker)
|
|
47640
|
+
reply = await this.ensureCompletionMarker(reply, memSessionId);
|
|
47516
47641
|
resolveResponse(reply);
|
|
47517
47642
|
return reply;
|
|
47518
47643
|
}
|
|
@@ -47521,11 +47646,16 @@ ${item.payload.content}` + batchSuffix;
|
|
|
47521
47646
|
const onLog = extra.onLog ?? (() => {
|
|
47522
47647
|
});
|
|
47523
47648
|
if (sessionId) {
|
|
47524
|
-
|
|
47649
|
+
let reply2 = await this.respondInSession(sessionId, item.payload.content + markerSuffix, onLog);
|
|
47650
|
+
if (needsMarker)
|
|
47651
|
+
reply2 = await this.ensureCompletionMarker(reply2, sessionId);
|
|
47525
47652
|
resolveResponse(reply2);
|
|
47526
47653
|
return reply2;
|
|
47527
47654
|
}
|
|
47528
|
-
const
|
|
47655
|
+
const srFallbackSessionId = `sys_${this.id}_${ts}`;
|
|
47656
|
+
let reply = await this.handleMessage(item.payload.content + markerSuffix, item.metadata?.senderId, senderInfo, buildHandleOpts({ sessionId: srFallbackSessionId }));
|
|
47657
|
+
if (needsMarker)
|
|
47658
|
+
reply = await this.ensureCompletionMarker(reply, srFallbackSessionId);
|
|
47529
47659
|
resolveResponse(reply);
|
|
47530
47660
|
return reply;
|
|
47531
47661
|
}
|
|
@@ -48493,6 +48623,9 @@ ${instructions}
|
|
|
48493
48623
|
setEscalationCallback(cb) {
|
|
48494
48624
|
this.escalationCallback = cb;
|
|
48495
48625
|
}
|
|
48626
|
+
setToolCallLimitChecker(cb) {
|
|
48627
|
+
this.toolCallLimitChecker = cb;
|
|
48628
|
+
}
|
|
48496
48629
|
setStateChangeCallback(cb) {
|
|
48497
48630
|
this.stateChangeCallback = cb;
|
|
48498
48631
|
}
|
|
@@ -48640,16 +48773,16 @@ ${instructions}
|
|
|
48640
48773
|
const toolNames = /* @__PURE__ */ new Set();
|
|
48641
48774
|
const errors = [];
|
|
48642
48775
|
let lastText = "";
|
|
48643
|
-
for (const
|
|
48644
|
-
if (
|
|
48645
|
-
const name =
|
|
48776
|
+
for (const log91 of logs) {
|
|
48777
|
+
if (log91.type === "tool_start") {
|
|
48778
|
+
const name = log91.metadata?.toolName ?? "";
|
|
48646
48779
|
if (name)
|
|
48647
48780
|
toolNames.add(name);
|
|
48648
48781
|
}
|
|
48649
|
-
if (
|
|
48650
|
-
errors.push(
|
|
48651
|
-
if (
|
|
48652
|
-
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);
|
|
48653
48786
|
}
|
|
48654
48787
|
const parts = [];
|
|
48655
48788
|
if (toolNames.size > 0)
|
|
@@ -51040,6 +51173,15 @@ ${body}${contextSuffix}`;
|
|
|
51040
51173
|
error: beforeResult.reason ?? "Blocked by tool hook"
|
|
51041
51174
|
});
|
|
51042
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
|
+
}
|
|
51043
51185
|
const baseArgs = beforeResult.modifiedArgs ?? toolCall.arguments;
|
|
51044
51186
|
const effectiveArgs = sessionId ? { ...baseArgs, _browserSessionId: sessionId } : baseArgs;
|
|
51045
51187
|
let lastError;
|
|
@@ -57831,6 +57973,7 @@ var init_agent_manager = __esm({
|
|
|
57831
57973
|
agentAuditCallback;
|
|
57832
57974
|
escalationHandler;
|
|
57833
57975
|
approvalHandler;
|
|
57976
|
+
toolCallLimitChecker;
|
|
57834
57977
|
stateChangeHandler;
|
|
57835
57978
|
/** Grace timers for releasing scoped MCP processes after agent goes idle */
|
|
57836
57979
|
mcpReleaseTimers = /* @__PURE__ */ new Map();
|
|
@@ -58812,6 +58955,9 @@ Known issues: ${knownIssues}` : ""}`
|
|
|
58812
58955
|
const ah = this.approvalHandler;
|
|
58813
58956
|
agent.setApprovalCallback(async (req) => ah(id, req));
|
|
58814
58957
|
}
|
|
58958
|
+
if (this.toolCallLimitChecker) {
|
|
58959
|
+
agent.setToolCallLimitChecker(this.toolCallLimitChecker);
|
|
58960
|
+
}
|
|
58815
58961
|
agent.setStateChangeCallback(this.buildStateChangeCallback());
|
|
58816
58962
|
if (this.activityCallbacks) {
|
|
58817
58963
|
agent.setActivityCallbacks(this.activityCallbacks);
|
|
@@ -59446,6 +59592,9 @@ Known issues: ${knownIssues}` : ""}`
|
|
|
59446
59592
|
const ah = this.approvalHandler;
|
|
59447
59593
|
agent.setApprovalCallback(async (req) => ah(id, req));
|
|
59448
59594
|
}
|
|
59595
|
+
if (this.toolCallLimitChecker) {
|
|
59596
|
+
agent.setToolCallLimitChecker(this.toolCallLimitChecker);
|
|
59597
|
+
}
|
|
59449
59598
|
agent.setStateChangeCallback(this.buildStateChangeCallback());
|
|
59450
59599
|
if (this.activityCallbacks) {
|
|
59451
59600
|
agent.setActivityCallbacks(this.activityCallbacks);
|
|
@@ -59592,6 +59741,12 @@ Known issues: ${knownIssues}` : ""}`
|
|
|
59592
59741
|
agent.setApprovalCallback(async (req) => handler4(id, req));
|
|
59593
59742
|
}
|
|
59594
59743
|
}
|
|
59744
|
+
setToolCallLimitChecker(checker) {
|
|
59745
|
+
this.toolCallLimitChecker = checker;
|
|
59746
|
+
for (const [, agent] of this.agents) {
|
|
59747
|
+
agent.setToolCallLimitChecker(checker);
|
|
59748
|
+
}
|
|
59749
|
+
}
|
|
59595
59750
|
/**
|
|
59596
59751
|
* Build the combined state-change callback for an agent. Handles:
|
|
59597
59752
|
* 1. MCP scoped-process lifecycle (release on idle, cancel release on working)
|
|
@@ -63859,7 +64014,7 @@ var init_external_gateway = __esm({
|
|
|
63859
64014
|
return rows.length;
|
|
63860
64015
|
}
|
|
63861
64016
|
async register(request) {
|
|
63862
|
-
const { externalAgentId, agentName, orgId: orgId2, capabilities = [], platform:
|
|
64017
|
+
const { externalAgentId, agentName, orgId: orgId2, capabilities = [], platform: platform5, platformConfig, agentCardUrl, openClawConfig } = request;
|
|
63863
64018
|
if (!externalAgentId || !agentName || !orgId2) {
|
|
63864
64019
|
throw new GatewayError("Missing required fields: externalAgentId, agentName, orgId", 400);
|
|
63865
64020
|
}
|
|
@@ -63886,7 +64041,7 @@ var init_external_gateway = __esm({
|
|
|
63886
64041
|
agentName,
|
|
63887
64042
|
orgId: orgId2,
|
|
63888
64043
|
capabilities,
|
|
63889
|
-
platform:
|
|
64044
|
+
platform: platform5 ?? (openClawConfig ? "openclaw" : void 0),
|
|
63890
64045
|
platformConfig: platformConfig ?? openClawConfig,
|
|
63891
64046
|
agentCardUrl,
|
|
63892
64047
|
openClawConfig,
|
|
@@ -76683,8 +76838,8 @@ var require_CronFileParser = __commonJS({
|
|
|
76683
76838
|
* @throws If file cannot be read
|
|
76684
76839
|
*/
|
|
76685
76840
|
static parseFileSync(filePath) {
|
|
76686
|
-
const { readFileSync:
|
|
76687
|
-
const data =
|
|
76841
|
+
const { readFileSync: readFileSync31 } = __require("fs");
|
|
76842
|
+
const data = readFileSync31(filePath, "utf8");
|
|
76688
76843
|
return _CronFileParser.#parseContent(data);
|
|
76689
76844
|
}
|
|
76690
76845
|
/**
|
|
@@ -82013,6 +82168,8 @@ var init_api_server = __esm({
|
|
|
82013
82168
|
hitlService;
|
|
82014
82169
|
billingService;
|
|
82015
82170
|
auditService;
|
|
82171
|
+
licenseService;
|
|
82172
|
+
telemetryService;
|
|
82016
82173
|
storage;
|
|
82017
82174
|
llmRouter;
|
|
82018
82175
|
markusConfigPath;
|
|
@@ -82032,7 +82189,40 @@ var init_api_server = __esm({
|
|
|
82032
82189
|
remoteAgent;
|
|
82033
82190
|
remoteAgentFactory;
|
|
82034
82191
|
modelCatalog;
|
|
82035
|
-
|
|
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
|
+
}
|
|
82036
82226
|
constructor(orgService, taskService, port = 8056) {
|
|
82037
82227
|
this.orgService = orgService;
|
|
82038
82228
|
this.taskService = taskService;
|
|
@@ -82241,7 +82431,7 @@ ${cleanText}`,
|
|
|
82241
82431
|
const headers = { "Content-Type": "application/json" };
|
|
82242
82432
|
if (token)
|
|
82243
82433
|
headers["Authorization"] = `Bearer ${token}`;
|
|
82244
|
-
const res = await
|
|
82434
|
+
const res = await self.hubFetch(`${hubUrl}/api/items${qs ? `?${qs}` : ""}`, { headers });
|
|
82245
82435
|
if (!res.ok)
|
|
82246
82436
|
throw new Error(`Hub search failed: ${res.status}`);
|
|
82247
82437
|
const data = await res.json();
|
|
@@ -82261,7 +82451,7 @@ ${cleanText}`,
|
|
|
82261
82451
|
if (!token)
|
|
82262
82452
|
throw new Error("Hub token not configured. Please login to Markus Hub first.");
|
|
82263
82453
|
const headers = { "Content-Type": "application/json", "Authorization": `Bearer ${token}` };
|
|
82264
|
-
const res = await
|
|
82454
|
+
const res = await self.hubFetch(`${hubUrl}/api/items/${itemId}/download`, { method: "POST", headers });
|
|
82265
82455
|
if (!res.ok)
|
|
82266
82456
|
throw new Error(`Hub download failed: ${res.status}`);
|
|
82267
82457
|
const data = await res.json();
|
|
@@ -82295,6 +82485,12 @@ ${cleanText}`,
|
|
|
82295
82485
|
setBillingService(service) {
|
|
82296
82486
|
this.billingService = service;
|
|
82297
82487
|
}
|
|
82488
|
+
setLicenseService(service) {
|
|
82489
|
+
this.licenseService = service;
|
|
82490
|
+
}
|
|
82491
|
+
setTelemetryService(service) {
|
|
82492
|
+
this.telemetryService = service;
|
|
82493
|
+
}
|
|
82298
82494
|
setAuditService(service) {
|
|
82299
82495
|
this.auditService = service;
|
|
82300
82496
|
}
|
|
@@ -83047,12 +83243,18 @@ ${cleanText}`,
|
|
|
83047
83243
|
}
|
|
83048
83244
|
if (path === "/api/auth/status" && req.method === "GET") {
|
|
83049
83245
|
if (!this.storage || !this.authEnabled) {
|
|
83050
|
-
this.json(res, 200, { initialized: true });
|
|
83246
|
+
this.json(res, 200, { initialized: true, hasOwner: true, hasMultipleUsers: false });
|
|
83051
83247
|
return;
|
|
83052
83248
|
}
|
|
83053
83249
|
const allUsers = await this.storage.userRepo.listByOrg("default");
|
|
83054
|
-
const
|
|
83055
|
-
|
|
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
|
+
});
|
|
83056
83258
|
return;
|
|
83057
83259
|
}
|
|
83058
83260
|
if (path === "/api/auth/init" && req.method === "POST") {
|
|
@@ -83154,6 +83356,135 @@ ${cleanText}`,
|
|
|
83154
83356
|
});
|
|
83155
83357
|
return;
|
|
83156
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
|
+
}
|
|
83157
83488
|
if (path === "/api/auth/logout" && req.method === "POST") {
|
|
83158
83489
|
res.setHeader("Set-Cookie", "markus_token=; HttpOnly; SameSite=Strict; Path=/; Max-Age=0");
|
|
83159
83490
|
this.json(res, 200, { ok: true });
|
|
@@ -84242,6 +84573,16 @@ ${cleanText}`,
|
|
|
84242
84573
|
this.json(res, 400, { error: "name is required" });
|
|
84243
84574
|
return;
|
|
84244
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
|
+
}
|
|
84245
84586
|
const team = await this.orgService.createTeam(orgId2, name, body["description"]);
|
|
84246
84587
|
this.ws?.broadcast({
|
|
84247
84588
|
type: "chat:group_created",
|
|
@@ -86372,6 +86713,16 @@ EXPLANATION_END`;
|
|
|
86372
86713
|
const authUser = await this.requireAuth(req, res);
|
|
86373
86714
|
if (!authUser)
|
|
86374
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
|
+
}
|
|
86375
86726
|
const body = await this.readBody(req);
|
|
86376
86727
|
const orgId2 = body["orgId"] ?? "default";
|
|
86377
86728
|
const name = body["name"];
|
|
@@ -86652,14 +87003,14 @@ EXPLANATION_END`;
|
|
|
86652
87003
|
const installedSkills = new Map((this.skillRegistry?.list() ?? []).map((s2) => [s2.name, s2]));
|
|
86653
87004
|
const rawManifests = /* @__PURE__ */ new Map();
|
|
86654
87005
|
try {
|
|
86655
|
-
const { readdirSync: readdirSync14, readFileSync:
|
|
87006
|
+
const { readdirSync: readdirSync14, readFileSync: readFileSync31, existsSync: existsSync42 } = await import("node:fs");
|
|
86656
87007
|
for (const entry of readdirSync14(builtinDir, { withFileTypes: true })) {
|
|
86657
87008
|
if (!entry.isDirectory())
|
|
86658
87009
|
continue;
|
|
86659
87010
|
const sjPath = resolve15(builtinDir, entry.name, "skill.json");
|
|
86660
|
-
if (
|
|
87011
|
+
if (existsSync42(sjPath)) {
|
|
86661
87012
|
try {
|
|
86662
|
-
rawManifests.set(entry.name, JSON.parse(
|
|
87013
|
+
rawManifests.set(entry.name, JSON.parse(readFileSync31(sjPath, "utf-8")));
|
|
86663
87014
|
} catch {
|
|
86664
87015
|
}
|
|
86665
87016
|
}
|
|
@@ -87086,6 +87437,16 @@ EXPLANATION_END`;
|
|
|
87086
87437
|
this.json(res, 500, { error: "BuilderService not initialized" });
|
|
87087
87438
|
return;
|
|
87088
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
|
+
}
|
|
87089
87450
|
try {
|
|
87090
87451
|
const result = await this.builderService.installArtifact(type, name);
|
|
87091
87452
|
this.json(res, 201, result);
|
|
@@ -88101,11 +88462,11 @@ EXPLANATION_END`;
|
|
|
88101
88462
|
}
|
|
88102
88463
|
if (path === "/api/templates/teams" && req.method === "GET") {
|
|
88103
88464
|
try {
|
|
88104
|
-
const { readdirSync: readdirSync14, readFileSync:
|
|
88465
|
+
const { readdirSync: readdirSync14, readFileSync: readFileSync31 } = await import("node:fs");
|
|
88105
88466
|
const { resolve: resolve21 } = await import("node:path");
|
|
88106
88467
|
const teamsDir = resolve21(process.cwd(), "templates", "teams");
|
|
88107
88468
|
const files = readdirSync14(teamsDir).filter((f) => f.endsWith(".json"));
|
|
88108
|
-
const teams = files.map((f) => JSON.parse(
|
|
88469
|
+
const teams = files.map((f) => JSON.parse(readFileSync31(resolve21(teamsDir, f), "utf-8")));
|
|
88109
88470
|
this.json(res, 200, { templates: teams });
|
|
88110
88471
|
} catch {
|
|
88111
88472
|
this.json(res, 200, { templates: [] });
|
|
@@ -88146,6 +88507,183 @@ EXPLANATION_END`;
|
|
|
88146
88507
|
this.json(res, 200, { usage });
|
|
88147
88508
|
return;
|
|
88148
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
|
+
}
|
|
88149
88687
|
if (path === "/api/hub/publish" && req.method === "POST") {
|
|
88150
88688
|
const authUser = await this.requireAuth(req, res);
|
|
88151
88689
|
if (!authUser)
|
|
@@ -88193,8 +88731,16 @@ EXPLANATION_END`;
|
|
|
88193
88731
|
else
|
|
88194
88732
|
proxyHeaders["Content-Type"] = req.headers["content-type"];
|
|
88195
88733
|
const authHeader = req.headers["authorization"];
|
|
88196
|
-
if (authHeader)
|
|
88734
|
+
if (authHeader) {
|
|
88197
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
|
+
}
|
|
88198
88744
|
try {
|
|
88199
88745
|
let body;
|
|
88200
88746
|
if (req.method === "POST" || req.method === "PUT" || req.method === "PATCH") {
|
|
@@ -88279,6 +88825,10 @@ EXPLANATION_END`;
|
|
|
88279
88825
|
}
|
|
88280
88826
|
this.remoteAgent.start().catch(() => {
|
|
88281
88827
|
});
|
|
88828
|
+
try {
|
|
88829
|
+
saveConfig({ remote: { enabled: true } }, this.markusConfigPath);
|
|
88830
|
+
} catch {
|
|
88831
|
+
}
|
|
88282
88832
|
this.json(res, 200, { ok: true, status: this.remoteAgent.getStatus() });
|
|
88283
88833
|
return;
|
|
88284
88834
|
}
|
|
@@ -88286,6 +88836,10 @@ EXPLANATION_END`;
|
|
|
88286
88836
|
if (this.remoteAgent) {
|
|
88287
88837
|
await this.remoteAgent.stop();
|
|
88288
88838
|
}
|
|
88839
|
+
try {
|
|
88840
|
+
saveConfig({ remote: { enabled: false } }, this.markusConfigPath);
|
|
88841
|
+
} catch {
|
|
88842
|
+
}
|
|
88289
88843
|
this.json(res, 200, { ok: true });
|
|
88290
88844
|
return;
|
|
88291
88845
|
}
|
|
@@ -88563,7 +89117,7 @@ EXPLANATION_END`;
|
|
|
88563
89117
|
const { fileURLToPath: fileURLToPath8 } = await import("node:url");
|
|
88564
89118
|
const { dirname: dn, resolve: rslv, join: jn } = await import("node:path");
|
|
88565
89119
|
const { execSync: execSync7 } = await import("node:child_process");
|
|
88566
|
-
const { existsSync: ex, readFileSync:
|
|
89120
|
+
const { existsSync: ex, readFileSync: readFileSync31, statSync: statSync8 } = await import("node:fs");
|
|
88567
89121
|
const thisDir = dn(fileURLToPath8(import.meta.url));
|
|
88568
89122
|
const zipCandidates = [
|
|
88569
89123
|
jn(rslv(thisDir, "..", "..", "chrome-extension"), "dist", "markus-browser-extension.zip"),
|
|
@@ -88592,7 +89146,7 @@ EXPLANATION_END`;
|
|
|
88592
89146
|
this.json(res, 404, { error: "Extension zip not found." });
|
|
88593
89147
|
return;
|
|
88594
89148
|
}
|
|
88595
|
-
const data =
|
|
89149
|
+
const data = readFileSync31(zipPath);
|
|
88596
89150
|
res.writeHead(200, {
|
|
88597
89151
|
"Content-Type": "application/zip",
|
|
88598
89152
|
"Content-Disposition": 'attachment; filename="markus-browser-extension.zip"',
|
|
@@ -88610,11 +89164,11 @@ EXPLANATION_END`;
|
|
|
88610
89164
|
return;
|
|
88611
89165
|
try {
|
|
88612
89166
|
const { exec: execCb2 } = await import("node:child_process");
|
|
88613
|
-
const
|
|
88614
|
-
if (
|
|
89167
|
+
const platform5 = process.platform;
|
|
89168
|
+
if (platform5 === "darwin") {
|
|
88615
89169
|
execCb2('open -a "Google Chrome" "chrome://extensions"', () => {
|
|
88616
89170
|
});
|
|
88617
|
-
} else if (
|
|
89171
|
+
} else if (platform5 === "win32") {
|
|
88618
89172
|
execCb2('start "" "chrome://extensions"', () => {
|
|
88619
89173
|
});
|
|
88620
89174
|
} else {
|
|
@@ -89693,11 +90247,11 @@ data: ${JSON.stringify({ error: msg })}
|
|
|
89693
90247
|
const { configPath, preview } = body;
|
|
89694
90248
|
const { existsSync: fsExists, readFileSync: fsRead } = await import("node:fs");
|
|
89695
90249
|
const { join: pathJoin } = await import("node:path");
|
|
89696
|
-
const { homedir:
|
|
90250
|
+
const { homedir: homedir25 } = await import("node:os");
|
|
89697
90251
|
const possiblePaths = [
|
|
89698
90252
|
configPath,
|
|
89699
|
-
pathJoin(
|
|
89700
|
-
pathJoin(
|
|
90253
|
+
pathJoin(homedir25(), ".openclaw", "openclaw.json"),
|
|
90254
|
+
pathJoin(homedir25(), ".openclaw", "openclaw.json5")
|
|
89701
90255
|
].filter(Boolean);
|
|
89702
90256
|
let found = "";
|
|
89703
90257
|
let rawContent = "";
|
|
@@ -89916,10 +90470,10 @@ data: ${JSON.stringify({ error: msg })}
|
|
|
89916
90470
|
this.json(res, 400, { error: "Invalid or non-existent path" });
|
|
89917
90471
|
return;
|
|
89918
90472
|
}
|
|
89919
|
-
const
|
|
89920
|
-
if (
|
|
90473
|
+
const platform5 = process.platform;
|
|
90474
|
+
if (platform5 === "darwin")
|
|
89921
90475
|
execSync3(`open ${JSON.stringify(dirPath)}`);
|
|
89922
|
-
else if (
|
|
90476
|
+
else if (platform5 === "win32")
|
|
89923
90477
|
execSync3(`explorer ${JSON.stringify(dirPath)}`);
|
|
89924
90478
|
else
|
|
89925
90479
|
execSync3(`xdg-open ${JSON.stringify(dirPath)}`);
|
|
@@ -90071,9 +90625,9 @@ data: ${JSON.stringify({ error: msg })}
|
|
|
90071
90625
|
}
|
|
90072
90626
|
try {
|
|
90073
90627
|
const { resolve: resolve21, extname: extname2 } = await import("node:path");
|
|
90074
|
-
const { existsSync:
|
|
90075
|
-
const { homedir:
|
|
90076
|
-
const home =
|
|
90628
|
+
const { existsSync: existsSync42, statSync: statSync8 } = await import("node:fs");
|
|
90629
|
+
const { homedir: homedir25 } = await import("node:os");
|
|
90630
|
+
const home = homedir25();
|
|
90077
90631
|
const results = {};
|
|
90078
90632
|
const mdExts = [".md", ".markdown"];
|
|
90079
90633
|
const htmlExts = [".html", ".htm"];
|
|
@@ -90083,7 +90637,7 @@ data: ${JSON.stringify({ error: msg })}
|
|
|
90083
90637
|
try {
|
|
90084
90638
|
const expanded = p.startsWith("~/") ? resolve21(home, p.slice(2)) : p === "~" ? home : p;
|
|
90085
90639
|
const resolved = resolve21(expanded);
|
|
90086
|
-
if (!
|
|
90640
|
+
if (!existsSync42(resolved)) {
|
|
90087
90641
|
results[p] = { exists: false, isFile: false, type: "unknown" };
|
|
90088
90642
|
continue;
|
|
90089
90643
|
}
|
|
@@ -90120,21 +90674,21 @@ data: ${JSON.stringify({ error: msg })}
|
|
|
90120
90674
|
}
|
|
90121
90675
|
try {
|
|
90122
90676
|
const { resolve: resolve21, extname: extname2 } = await import("node:path");
|
|
90123
|
-
const { readFileSync:
|
|
90124
|
-
const { homedir:
|
|
90125
|
-
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();
|
|
90126
90680
|
const expanded = filePath.startsWith("~/") ? resolve21(home, filePath.slice(2)) : filePath === "~" ? home : filePath;
|
|
90127
90681
|
const resolved = resolve21(expanded);
|
|
90128
|
-
if (!
|
|
90682
|
+
if (!existsSync42(resolved)) {
|
|
90129
90683
|
this.json(res, 404, { error: "File not found" });
|
|
90130
90684
|
return;
|
|
90131
90685
|
}
|
|
90132
90686
|
const stat = statSync8(resolved);
|
|
90133
90687
|
if (stat.isDirectory()) {
|
|
90134
90688
|
const { readdirSync: readdirSync14 } = await import("node:fs");
|
|
90135
|
-
const { join:
|
|
90689
|
+
const { join: join35, extname: extDir } = await import("node:path");
|
|
90136
90690
|
const entries2 = readdirSync14(resolved, { withFileTypes: true }).filter((e) => !e.name.startsWith(".")).map((e) => {
|
|
90137
|
-
const full =
|
|
90691
|
+
const full = join35(resolved, e.name);
|
|
90138
90692
|
const isDir = e.isDirectory();
|
|
90139
90693
|
let size;
|
|
90140
90694
|
try {
|
|
@@ -90163,7 +90717,7 @@ data: ${JSON.stringify({ error: msg })}
|
|
|
90163
90717
|
const ext = extname2(resolved).toLowerCase();
|
|
90164
90718
|
const imageExts = [".png", ".jpg", ".jpeg", ".gif", ".webp", ".svg"];
|
|
90165
90719
|
if (imageExts.includes(ext)) {
|
|
90166
|
-
const data =
|
|
90720
|
+
const data = readFileSync31(resolved);
|
|
90167
90721
|
const mimeMap = { ".png": "image/png", ".jpg": "image/jpeg", ".jpeg": "image/jpeg", ".gif": "image/gif", ".webp": "image/webp", ".svg": "image/svg+xml" };
|
|
90168
90722
|
this.json(res, 200, {
|
|
90169
90723
|
type: "image",
|
|
@@ -90172,7 +90726,7 @@ data: ${JSON.stringify({ error: msg })}
|
|
|
90172
90726
|
content: data.toString("base64")
|
|
90173
90727
|
});
|
|
90174
90728
|
} else {
|
|
90175
|
-
const content =
|
|
90729
|
+
const content = readFileSync31(resolved, "utf-8");
|
|
90176
90730
|
const mdExts = [".md", ".markdown"];
|
|
90177
90731
|
const htmlExts = [".html", ".htm"];
|
|
90178
90732
|
const jsonExts = [".json"];
|
|
@@ -90205,12 +90759,12 @@ data: ${JSON.stringify({ error: msg })}
|
|
|
90205
90759
|
}
|
|
90206
90760
|
try {
|
|
90207
90761
|
const { resolve: resolve21, extname: extname2 } = await import("node:path");
|
|
90208
|
-
const { readFileSync:
|
|
90209
|
-
const { homedir:
|
|
90210
|
-
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();
|
|
90211
90765
|
const expanded = filePath.startsWith("~/") ? resolve21(home, filePath.slice(2)) : filePath === "~" ? home : filePath;
|
|
90212
90766
|
const resolved = resolve21(expanded);
|
|
90213
|
-
if (!
|
|
90767
|
+
if (!existsSync42(resolved) || !statSync8(resolved).isFile()) {
|
|
90214
90768
|
this.json(res, 404, { error: "Image not found" });
|
|
90215
90769
|
return;
|
|
90216
90770
|
}
|
|
@@ -90235,7 +90789,7 @@ data: ${JSON.stringify({ error: msg })}
|
|
|
90235
90789
|
this.json(res, 400, { error: "Not an image file" });
|
|
90236
90790
|
return;
|
|
90237
90791
|
}
|
|
90238
|
-
const data =
|
|
90792
|
+
const data = readFileSync31(resolved);
|
|
90239
90793
|
res.writeHead(200, {
|
|
90240
90794
|
"Content-Type": mime,
|
|
90241
90795
|
"Content-Length": data.length,
|
|
@@ -90255,26 +90809,26 @@ data: ${JSON.stringify({ error: msg })}
|
|
|
90255
90809
|
return;
|
|
90256
90810
|
}
|
|
90257
90811
|
try {
|
|
90258
|
-
const { resolve: resolve21, dirname:
|
|
90259
|
-
const { existsSync:
|
|
90812
|
+
const { resolve: resolve21, dirname: dirname15 } = await import("node:path");
|
|
90813
|
+
const { existsSync: existsSync42, statSync: statSync8 } = await import("node:fs");
|
|
90260
90814
|
const { exec: exec2 } = await import("node:child_process");
|
|
90261
|
-
const { homedir:
|
|
90262
|
-
const home =
|
|
90815
|
+
const { homedir: homedir25 } = await import("node:os");
|
|
90816
|
+
const home = homedir25();
|
|
90263
90817
|
const expanded = filePath.startsWith("~/") ? resolve21(home, filePath.slice(2)) : filePath === "~" ? home : filePath;
|
|
90264
90818
|
const resolved = resolve21(expanded);
|
|
90265
|
-
if (!
|
|
90819
|
+
if (!existsSync42(resolved)) {
|
|
90266
90820
|
this.json(res, 404, { error: "Path not found" });
|
|
90267
90821
|
return;
|
|
90268
90822
|
}
|
|
90269
90823
|
const isDir = statSync8(resolved).isDirectory();
|
|
90270
|
-
const
|
|
90824
|
+
const platform5 = process.platform;
|
|
90271
90825
|
let cmd;
|
|
90272
|
-
if (
|
|
90826
|
+
if (platform5 === "darwin") {
|
|
90273
90827
|
cmd = isDir ? `open "${resolved}"` : `open -R "${resolved}"`;
|
|
90274
|
-
} else if (
|
|
90828
|
+
} else if (platform5 === "win32") {
|
|
90275
90829
|
cmd = isDir ? `explorer "${resolved}"` : `explorer /select,"${resolved}"`;
|
|
90276
90830
|
} else {
|
|
90277
|
-
cmd = `xdg-open "${isDir ? resolved :
|
|
90831
|
+
cmd = `xdg-open "${isDir ? resolved : dirname15(resolved)}"`;
|
|
90278
90832
|
}
|
|
90279
90833
|
exec2(cmd, (err) => {
|
|
90280
90834
|
if (err) {
|
|
@@ -90971,6 +91525,7 @@ data: ${JSON.stringify({ error: msg })}
|
|
|
90971
91525
|
return [
|
|
90972
91526
|
// ── Auth ─────────────────────────────────────────────────────────────
|
|
90973
91527
|
exact("/api/auth/login", "POST"),
|
|
91528
|
+
exact("/api/auth/hub-login", "POST"),
|
|
90974
91529
|
exact("/api/auth/logout", "POST"),
|
|
90975
91530
|
exact("/api/auth/me", "GET"),
|
|
90976
91531
|
exact("/api/auth/change-password", "POST"),
|
|
@@ -91130,6 +91685,13 @@ data: ${JSON.stringify({ error: msg })}
|
|
|
91130
91685
|
exact("/api/models/validate-key", "POST"),
|
|
91131
91686
|
regex(/^\/api\/models\/live\/[^/]+$/, "GET"),
|
|
91132
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"),
|
|
91133
91695
|
exact("/api/settings/hub", "GET"),
|
|
91134
91696
|
exact("/api/settings/hub-token", "POST"),
|
|
91135
91697
|
exact("/api/settings/llm", "GET", "POST"),
|
|
@@ -92278,17 +92840,10 @@ var init_billing_service = __esm({
|
|
|
92278
92840
|
DEFAULT_PLANS = {
|
|
92279
92841
|
free: {
|
|
92280
92842
|
maxAgents: -1,
|
|
92281
|
-
maxTokensPerMonth:
|
|
92282
|
-
maxToolCallsPerDay:
|
|
92283
|
-
maxMessagesPerDay:
|
|
92284
|
-
maxStorageBytes:
|
|
92285
|
-
},
|
|
92286
|
-
pro: {
|
|
92287
|
-
maxAgents: 20,
|
|
92288
|
-
maxTokensPerMonth: 5e6,
|
|
92289
|
-
maxToolCallsPerDay: 5e3,
|
|
92290
|
-
maxMessagesPerDay: 2e3,
|
|
92291
|
-
maxStorageBytes: 5 * 1024 * 1024 * 1024
|
|
92843
|
+
maxTokensPerMonth: -1,
|
|
92844
|
+
maxToolCallsPerDay: 500,
|
|
92845
|
+
maxMessagesPerDay: -1,
|
|
92846
|
+
maxStorageBytes: -1
|
|
92292
92847
|
},
|
|
92293
92848
|
enterprise: {
|
|
92294
92849
|
maxAgents: -1,
|
|
@@ -92304,6 +92859,10 @@ var init_billing_service = __esm({
|
|
|
92304
92859
|
apiKeys = /* @__PURE__ */ new Map();
|
|
92305
92860
|
apiKeysByKey = /* @__PURE__ */ new Map();
|
|
92306
92861
|
orgPlans = /* @__PURE__ */ new Map();
|
|
92862
|
+
toolCallsTodayProvider;
|
|
92863
|
+
setToolCallsTodayProvider(fn) {
|
|
92864
|
+
this.toolCallsTodayProvider = fn;
|
|
92865
|
+
}
|
|
92307
92866
|
setOrgPlan(orgId2, tier) {
|
|
92308
92867
|
const plan = {
|
|
92309
92868
|
orgId: orgId2,
|
|
@@ -92379,8 +92938,7 @@ var init_billing_service = __esm({
|
|
|
92379
92938
|
}
|
|
92380
92939
|
}
|
|
92381
92940
|
if (type === "tool_call") {
|
|
92382
|
-
const
|
|
92383
|
-
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);
|
|
92384
92942
|
if (plan.limits.maxToolCallsPerDay > 0 && todayCount + additionalAmount > plan.limits.maxToolCallsPerDay) {
|
|
92385
92943
|
return {
|
|
92386
92944
|
allowed: false,
|
|
@@ -92508,13 +93066,523 @@ var init_billing_service = __esm({
|
|
|
92508
93066
|
}
|
|
92509
93067
|
});
|
|
92510
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
|
+
|
|
92511
93579
|
// ../org-manager/dist/audit-service.js
|
|
92512
|
-
var
|
|
93580
|
+
var log66, entryCounter, AuditService;
|
|
92513
93581
|
var init_audit_service = __esm({
|
|
92514
93582
|
"../org-manager/dist/audit-service.js"() {
|
|
92515
93583
|
"use strict";
|
|
92516
93584
|
init_dist();
|
|
92517
|
-
|
|
93585
|
+
log66 = createLogger("audit");
|
|
92518
93586
|
entryCounter = 0;
|
|
92519
93587
|
AuditService = class {
|
|
92520
93588
|
entries = [];
|
|
@@ -92522,7 +93590,7 @@ var init_audit_service = __esm({
|
|
|
92522
93590
|
db;
|
|
92523
93591
|
setRepository(db) {
|
|
92524
93592
|
this.db = db;
|
|
92525
|
-
|
|
93593
|
+
log66.info("Audit persistence enabled \u2014 events will be written to DB");
|
|
92526
93594
|
}
|
|
92527
93595
|
record(entry) {
|
|
92528
93596
|
const full = {
|
|
@@ -92548,7 +93616,7 @@ var init_audit_service = __esm({
|
|
|
92548
93616
|
durationMs: full.durationMs,
|
|
92549
93617
|
success: full.success,
|
|
92550
93618
|
createdAt: new Date(full.timestamp)
|
|
92551
|
-
}).catch((err) =>
|
|
93619
|
+
}).catch((err) => log66.warn("Failed to persist audit entry", { id: full.id, error: String(err) }));
|
|
92552
93620
|
}
|
|
92553
93621
|
return full;
|
|
92554
93622
|
}
|
|
@@ -92631,12 +93699,12 @@ var init_audit_service = __esm({
|
|
|
92631
93699
|
});
|
|
92632
93700
|
|
|
92633
93701
|
// ../org-manager/dist/project-service.js
|
|
92634
|
-
var
|
|
93702
|
+
var log67, ProjectService;
|
|
92635
93703
|
var init_project_service = __esm({
|
|
92636
93704
|
"../org-manager/dist/project-service.js"() {
|
|
92637
93705
|
"use strict";
|
|
92638
93706
|
init_dist();
|
|
92639
|
-
|
|
93707
|
+
log67 = createLogger("project-service");
|
|
92640
93708
|
ProjectService = class {
|
|
92641
93709
|
projects = /* @__PURE__ */ new Map();
|
|
92642
93710
|
projectRepo;
|
|
@@ -92666,9 +93734,9 @@ var init_project_service = __esm({
|
|
|
92666
93734
|
};
|
|
92667
93735
|
this.projects.set(project.id, project);
|
|
92668
93736
|
}
|
|
92669
|
-
|
|
93737
|
+
log67.info(`Loaded ${this.projects.size} projects from DB`);
|
|
92670
93738
|
} catch (err) {
|
|
92671
|
-
|
|
93739
|
+
log67.warn("Failed to load projects from DB", { error: String(err) });
|
|
92672
93740
|
}
|
|
92673
93741
|
}
|
|
92674
93742
|
}
|
|
@@ -92705,8 +93773,8 @@ var init_project_service = __esm({
|
|
|
92705
93773
|
reportSchedule: project.reportSchedule,
|
|
92706
93774
|
onboardingConfig: project.onboardingConfig,
|
|
92707
93775
|
createdBy: opts.createdBy
|
|
92708
|
-
}).catch((err) =>
|
|
92709
|
-
|
|
93776
|
+
}).catch((err) => log67.warn("Failed to persist project", { error: String(err) }));
|
|
93777
|
+
log67.info("Project created", { id: project.id, name: project.name });
|
|
92710
93778
|
return project;
|
|
92711
93779
|
}
|
|
92712
93780
|
getProject(id) {
|
|
@@ -92721,14 +93789,14 @@ var init_project_service = __esm({
|
|
|
92721
93789
|
if (!project)
|
|
92722
93790
|
throw new Error(`Project not found: ${id}`);
|
|
92723
93791
|
Object.assign(project, updates, { updatedAt: (/* @__PURE__ */ new Date()).toISOString() });
|
|
92724
|
-
this.projectRepo?.update(id, updates).catch((err) =>
|
|
92725
|
-
|
|
93792
|
+
this.projectRepo?.update(id, updates).catch((err) => log67.warn("Failed to persist project update", { error: String(err) }));
|
|
93793
|
+
log67.info("Project updated", { id });
|
|
92726
93794
|
return project;
|
|
92727
93795
|
}
|
|
92728
93796
|
deleteProject(id) {
|
|
92729
93797
|
this.projects.delete(id);
|
|
92730
|
-
this.projectRepo?.delete(id).catch((err) =>
|
|
92731
|
-
|
|
93798
|
+
this.projectRepo?.delete(id).catch((err) => log67.warn("Failed to delete project from DB", { error: String(err) }));
|
|
93799
|
+
log67.info("Project deleted", { id });
|
|
92732
93800
|
}
|
|
92733
93801
|
// ─── Agent Onboarding ──────────────────────────────────────────────────────
|
|
92734
93802
|
async onboardAgent(agentId2, projectId) {
|
|
@@ -92753,7 +93821,7 @@ var init_project_service = __esm({
|
|
|
92753
93821
|
parts.push(`- Max pending tasks per agent: ${project.governancePolicy.maxPendingTasksPerAgent}`);
|
|
92754
93822
|
}
|
|
92755
93823
|
const onboardingDoc = parts.join("\n");
|
|
92756
|
-
|
|
93824
|
+
log67.info("Agent onboarded to project", { agentId: agentId2, projectId });
|
|
92757
93825
|
return onboardingDoc;
|
|
92758
93826
|
}
|
|
92759
93827
|
};
|
|
@@ -92761,12 +93829,12 @@ var init_project_service = __esm({
|
|
|
92761
93829
|
});
|
|
92762
93830
|
|
|
92763
93831
|
// ../org-manager/dist/requirement-service.js
|
|
92764
|
-
var
|
|
93832
|
+
var log68, RequirementService;
|
|
92765
93833
|
var init_requirement_service = __esm({
|
|
92766
93834
|
"../org-manager/dist/requirement-service.js"() {
|
|
92767
93835
|
"use strict";
|
|
92768
93836
|
init_dist();
|
|
92769
|
-
|
|
93837
|
+
log68 = createLogger("requirement-service");
|
|
92770
93838
|
RequirementService = class _RequirementService {
|
|
92771
93839
|
requirements = /* @__PURE__ */ new Map();
|
|
92772
93840
|
requirementRepo;
|
|
@@ -92847,7 +93915,7 @@ var init_requirement_service = __esm({
|
|
|
92847
93915
|
reason: reason ?? null
|
|
92848
93916
|
});
|
|
92849
93917
|
} catch (e) {
|
|
92850
|
-
|
|
93918
|
+
log68.warn("Failed to record requirement status transition", { reqId, from, to, error: String(e) });
|
|
92851
93919
|
}
|
|
92852
93920
|
}
|
|
92853
93921
|
getRequirementStatusHistory(reqId, limit = 50) {
|
|
@@ -92927,7 +93995,7 @@ var init_requirement_service = __esm({
|
|
|
92927
93995
|
approvedBy: req.approvedBy ?? void 0,
|
|
92928
93996
|
approvedAt: req.approvedAt ? new Date(req.approvedAt) : void 0,
|
|
92929
93997
|
tags: req.tags
|
|
92930
|
-
}).catch((e) =>
|
|
93998
|
+
}).catch((e) => log68.error("Failed to persist requirement", { id: req.id, error: String(e) }));
|
|
92931
93999
|
}
|
|
92932
94000
|
this.broadcast("requirement:created", req);
|
|
92933
94001
|
if (this.hitlService && req.source === "agent") {
|
|
@@ -92950,10 +94018,10 @@ var init_requirement_service = __esm({
|
|
|
92950
94018
|
this.rejectRequirement(req.id, result.respondedBy ?? "hitl", result.comment || "Rejected via approval");
|
|
92951
94019
|
}
|
|
92952
94020
|
}).catch((err) => {
|
|
92953
|
-
|
|
94021
|
+
log68.error("HITL approval flow error for requirement", { requirementId: req.id, error: String(err) });
|
|
92954
94022
|
});
|
|
92955
94023
|
}
|
|
92956
|
-
|
|
94024
|
+
log68.info("Requirement created", {
|
|
92957
94025
|
id: req.id,
|
|
92958
94026
|
source: req.source,
|
|
92959
94027
|
status: req.status,
|
|
@@ -92996,11 +94064,11 @@ var init_requirement_service = __esm({
|
|
|
92996
94064
|
req.approvedAt = now3;
|
|
92997
94065
|
req.updatedAt = now3;
|
|
92998
94066
|
if (this.requirementRepo) {
|
|
92999
|
-
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) }));
|
|
93000
94068
|
}
|
|
93001
94069
|
this.recordTransition(id, oldStatus, "in_progress", userId2, "human", "Approved");
|
|
93002
94070
|
this.broadcast("requirement:approved", req);
|
|
93003
|
-
|
|
94071
|
+
log68.info("Requirement approved", { id, approvedBy: userId2 });
|
|
93004
94072
|
this.notifyCreatorOnDecision(req, "approved", userId2);
|
|
93005
94073
|
return req;
|
|
93006
94074
|
}
|
|
@@ -93027,11 +94095,11 @@ var init_requirement_service = __esm({
|
|
|
93027
94095
|
req.rejectedBy = userId2;
|
|
93028
94096
|
req.updatedAt = now3;
|
|
93029
94097
|
if (this.requirementRepo) {
|
|
93030
|
-
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) }));
|
|
93031
94099
|
}
|
|
93032
94100
|
this.recordTransition(id, oldStatus, "rejected", userId2, "human", reason);
|
|
93033
94101
|
this.broadcast("requirement:rejected", req);
|
|
93034
|
-
|
|
94102
|
+
log68.info("Requirement rejected", { id, reason });
|
|
93035
94103
|
this.notifyCreatorOnDecision(req, "rejected", userId2, reason);
|
|
93036
94104
|
return req;
|
|
93037
94105
|
}
|
|
@@ -93064,7 +94132,7 @@ var init_requirement_service = __esm({
|
|
|
93064
94132
|
req.updatedAt = now3;
|
|
93065
94133
|
this.recordTransition(id, oldStatus, "pending", req.createdBy, "agent", "Resubmitted");
|
|
93066
94134
|
if (this.requirementRepo) {
|
|
93067
|
-
const persistErr = (e) =>
|
|
94135
|
+
const persistErr = (e) => log68.error("Failed to persist requirement resubmission", { id, error: String(e) });
|
|
93068
94136
|
this.requirementRepo.updateStatus(id, "pending").catch(persistErr);
|
|
93069
94137
|
this.requirementRepo.clearRejectionMetadata(id).catch(persistErr);
|
|
93070
94138
|
if (updates) {
|
|
@@ -93072,7 +94140,7 @@ var init_requirement_service = __esm({
|
|
|
93072
94140
|
}
|
|
93073
94141
|
}
|
|
93074
94142
|
this.broadcast("requirement:resubmitted", req);
|
|
93075
|
-
|
|
94143
|
+
log68.info("Requirement resubmitted for review", { id, hasUpdates: !!updates });
|
|
93076
94144
|
if (this.hitlService && req.source === "agent") {
|
|
93077
94145
|
const creatorName = this.resolveAgentName(req.createdBy);
|
|
93078
94146
|
this.hitlService.requestApprovalAndWait({
|
|
@@ -93093,7 +94161,7 @@ var init_requirement_service = __esm({
|
|
|
93093
94161
|
this.rejectRequirement(req.id, result.respondedBy ?? "hitl", result.comment || "Rejected via approval");
|
|
93094
94162
|
}
|
|
93095
94163
|
}).catch((err) => {
|
|
93096
|
-
|
|
94164
|
+
log68.error("HITL approval flow error for resubmitted requirement", { requirementId: req.id, error: String(err) });
|
|
93097
94165
|
});
|
|
93098
94166
|
}
|
|
93099
94167
|
return req;
|
|
@@ -93129,7 +94197,7 @@ var init_requirement_service = __esm({
|
|
|
93129
94197
|
req.rejectedBy = void 0;
|
|
93130
94198
|
}
|
|
93131
94199
|
if (this.requirementRepo) {
|
|
93132
|
-
const persistErr = (e) =>
|
|
94200
|
+
const persistErr = (e) => log68.error("Failed to persist requirement status update", { id, error: String(e) });
|
|
93133
94201
|
if (newStatus === "in_progress" && oldStatus === "pending") {
|
|
93134
94202
|
this.requirementRepo.approve(id, req.approvedBy ?? "unknown").catch(persistErr);
|
|
93135
94203
|
} else if (newStatus === "rejected") {
|
|
@@ -93160,7 +94228,7 @@ var init_requirement_service = __esm({
|
|
|
93160
94228
|
const resolvedActorType = actorType ?? (userId2 ? "human" : "system");
|
|
93161
94229
|
this.recordTransition(id, oldStatus, newStatus, userId2, resolvedActorType);
|
|
93162
94230
|
this.broadcast("requirement:updated", req);
|
|
93163
|
-
|
|
94231
|
+
log68.info("Requirement status updated", { id, from: oldStatus, to: newStatus });
|
|
93164
94232
|
return req;
|
|
93165
94233
|
}
|
|
93166
94234
|
/**
|
|
@@ -93180,7 +94248,7 @@ var init_requirement_service = __esm({
|
|
|
93180
94248
|
req.tags = data.tags;
|
|
93181
94249
|
req.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
93182
94250
|
if (this.requirementRepo) {
|
|
93183
|
-
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) }));
|
|
93184
94252
|
}
|
|
93185
94253
|
this.broadcast("requirement:updated", req);
|
|
93186
94254
|
return req;
|
|
@@ -93262,11 +94330,11 @@ var init_requirement_service = __esm({
|
|
|
93262
94330
|
req.status = "cancelled";
|
|
93263
94331
|
req.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
93264
94332
|
if (this.requirementRepo) {
|
|
93265
|
-
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) }));
|
|
93266
94334
|
}
|
|
93267
94335
|
this.recordTransition(id, oldStatus, "cancelled", cancelledBy, cancelledByType ?? "system", "Cancelled");
|
|
93268
94336
|
this.broadcast("requirement:cancelled", req);
|
|
93269
|
-
|
|
94337
|
+
log68.info("Requirement cancelled", { id });
|
|
93270
94338
|
return req;
|
|
93271
94339
|
}
|
|
93272
94340
|
getRequirement(id) {
|
|
@@ -93323,9 +94391,9 @@ var init_requirement_service = __esm({
|
|
|
93323
94391
|
};
|
|
93324
94392
|
this.requirements.set(req.id, req);
|
|
93325
94393
|
}
|
|
93326
|
-
|
|
94394
|
+
log68.info("Loaded requirements from storage", { orgId: orgId2, count: rows.length });
|
|
93327
94395
|
} catch (e) {
|
|
93328
|
-
|
|
94396
|
+
log68.error("Failed to load requirements from storage", { orgId: orgId2, error: String(e) });
|
|
93329
94397
|
}
|
|
93330
94398
|
}
|
|
93331
94399
|
/**
|
|
@@ -93347,7 +94415,7 @@ var init_requirement_service = __esm({
|
|
|
93347
94415
|
}
|
|
93348
94416
|
const linked = [...this.requirements.values()].filter((r) => r.taskIds.length > 0).length;
|
|
93349
94417
|
if (linked > 0) {
|
|
93350
|
-
|
|
94418
|
+
log68.info("Rebuilt requirement-task links", { linkedRequirements: linked });
|
|
93351
94419
|
}
|
|
93352
94420
|
}
|
|
93353
94421
|
deleteRequirement(id) {
|
|
@@ -93356,7 +94424,7 @@ var init_requirement_service = __esm({
|
|
|
93356
94424
|
}
|
|
93357
94425
|
this.requirements.delete(id);
|
|
93358
94426
|
if (this.requirementRepo) {
|
|
93359
|
-
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) }));
|
|
93360
94428
|
}
|
|
93361
94429
|
}
|
|
93362
94430
|
/**
|
|
@@ -93405,7 +94473,7 @@ var init_requirement_service = __esm({
|
|
|
93405
94473
|
priority: 1,
|
|
93406
94474
|
metadata: { senderName: "System", senderRole: "manager" }
|
|
93407
94475
|
});
|
|
93408
|
-
|
|
94476
|
+
log68.info("Notified creator agent about requirement decision", {
|
|
93409
94477
|
requirementId: req.id,
|
|
93410
94478
|
creatorId,
|
|
93411
94479
|
decision
|
|
@@ -93450,12 +94518,12 @@ var init_requirement_service = __esm({
|
|
|
93450
94518
|
});
|
|
93451
94519
|
|
|
93452
94520
|
// ../org-manager/dist/knowledge-service.js
|
|
93453
|
-
var
|
|
94521
|
+
var log69, KnowledgeService;
|
|
93454
94522
|
var init_knowledge_service = __esm({
|
|
93455
94523
|
"../org-manager/dist/knowledge-service.js"() {
|
|
93456
94524
|
"use strict";
|
|
93457
94525
|
init_dist();
|
|
93458
|
-
|
|
94526
|
+
log69 = createLogger("knowledge-service");
|
|
93459
94527
|
KnowledgeService = class {
|
|
93460
94528
|
entries = /* @__PURE__ */ new Map();
|
|
93461
94529
|
fileStore;
|
|
@@ -93465,7 +94533,7 @@ var init_knowledge_service = __esm({
|
|
|
93465
94533
|
for (const entry of fileStore.loadAll()) {
|
|
93466
94534
|
this.entries.set(entry.id, entry);
|
|
93467
94535
|
}
|
|
93468
|
-
|
|
94536
|
+
log69.info("Knowledge loaded from file store", { count: this.entries.size });
|
|
93469
94537
|
}
|
|
93470
94538
|
}
|
|
93471
94539
|
/** Returns the absolute file path of a knowledge entry (for agent file_read). */
|
|
@@ -93510,7 +94578,7 @@ var init_knowledge_service = __esm({
|
|
|
93510
94578
|
}
|
|
93511
94579
|
}
|
|
93512
94580
|
this.persistScope(entry.scope, entry.scopeId);
|
|
93513
|
-
|
|
94581
|
+
log69.info("Knowledge contributed", {
|
|
93514
94582
|
id: entry.id,
|
|
93515
94583
|
scope: entry.scope,
|
|
93516
94584
|
category: entry.category,
|
|
@@ -93588,7 +94656,7 @@ var init_knowledge_service = __esm({
|
|
|
93588
94656
|
entry.status = "outdated";
|
|
93589
94657
|
entry.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
93590
94658
|
this.persistScope(entry.scope, entry.scopeId);
|
|
93591
|
-
|
|
94659
|
+
log69.info("Knowledge flagged as outdated", { id, reason });
|
|
93592
94660
|
}
|
|
93593
94661
|
flagDisputed(id, reason) {
|
|
93594
94662
|
const entry = this.entries.get(id);
|
|
@@ -93597,7 +94665,7 @@ var init_knowledge_service = __esm({
|
|
|
93597
94665
|
entry.status = "disputed";
|
|
93598
94666
|
entry.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
93599
94667
|
this.persistScope(entry.scope, entry.scopeId);
|
|
93600
|
-
|
|
94668
|
+
log69.info("Knowledge flagged as disputed", { id, reason });
|
|
93601
94669
|
}
|
|
93602
94670
|
verify(id, verifiedBy) {
|
|
93603
94671
|
const entry = this.entries.get(id);
|
|
@@ -93607,7 +94675,7 @@ var init_knowledge_service = __esm({
|
|
|
93607
94675
|
entry.verifiedBy = verifiedBy;
|
|
93608
94676
|
entry.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
93609
94677
|
this.persistScope(entry.scope, entry.scopeId);
|
|
93610
|
-
|
|
94678
|
+
log69.info("Knowledge verified", { id, verifiedBy });
|
|
93611
94679
|
}
|
|
93612
94680
|
// ─── Metrics ───────────────────────────────────────────────────────────────
|
|
93613
94681
|
getContributions(scopeId, periodStart, periodEnd) {
|
|
@@ -93631,8 +94699,8 @@ var init_knowledge_service = __esm({
|
|
|
93631
94699
|
});
|
|
93632
94700
|
|
|
93633
94701
|
// ../org-manager/dist/file-knowledge-store.js
|
|
93634
|
-
import { readFileSync as
|
|
93635
|
-
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";
|
|
93636
94704
|
function readdirSafe(dir) {
|
|
93637
94705
|
try {
|
|
93638
94706
|
return readdirSync12(dir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
|
|
@@ -93640,62 +94708,62 @@ function readdirSafe(dir) {
|
|
|
93640
94708
|
return [];
|
|
93641
94709
|
}
|
|
93642
94710
|
}
|
|
93643
|
-
var
|
|
94711
|
+
var log70, FileKnowledgeStore;
|
|
93644
94712
|
var init_file_knowledge_store = __esm({
|
|
93645
94713
|
"../org-manager/dist/file-knowledge-store.js"() {
|
|
93646
94714
|
"use strict";
|
|
93647
94715
|
init_dist();
|
|
93648
|
-
|
|
94716
|
+
log70 = createLogger("file-knowledge-store");
|
|
93649
94717
|
FileKnowledgeStore = class {
|
|
93650
94718
|
baseDir;
|
|
93651
94719
|
constructor(baseDir) {
|
|
93652
94720
|
this.baseDir = baseDir;
|
|
93653
|
-
|
|
94721
|
+
mkdirSync22(baseDir, { recursive: true });
|
|
93654
94722
|
}
|
|
93655
94723
|
scopeDir(scope, scopeId) {
|
|
93656
|
-
return
|
|
94724
|
+
return join27(this.baseDir, scope, scopeId);
|
|
93657
94725
|
}
|
|
93658
94726
|
indexPath(scope, scopeId) {
|
|
93659
|
-
return
|
|
94727
|
+
return join27(this.scopeDir(scope, scopeId), "_index.json");
|
|
93660
94728
|
}
|
|
93661
94729
|
entryPath(entry) {
|
|
93662
|
-
return
|
|
94730
|
+
return join27(this.scopeDir(entry.scope, entry.scopeId), `${entry.id}.json`);
|
|
93663
94731
|
}
|
|
93664
94732
|
// ─── Load ────────────────────────────────────────────────────────────────
|
|
93665
94733
|
loadAll() {
|
|
93666
94734
|
const entries2 = [];
|
|
93667
|
-
if (!
|
|
94735
|
+
if (!existsSync32(this.baseDir))
|
|
93668
94736
|
return entries2;
|
|
93669
94737
|
for (const scope of readdirSafe(this.baseDir)) {
|
|
93670
|
-
const scopePath =
|
|
94738
|
+
const scopePath = join27(this.baseDir, scope);
|
|
93671
94739
|
for (const scopeId of readdirSafe(scopePath)) {
|
|
93672
|
-
const idxPath =
|
|
93673
|
-
if (!
|
|
94740
|
+
const idxPath = join27(scopePath, scopeId, "_index.json");
|
|
94741
|
+
if (!existsSync32(idxPath))
|
|
93674
94742
|
continue;
|
|
93675
94743
|
try {
|
|
93676
|
-
const data = JSON.parse(
|
|
94744
|
+
const data = JSON.parse(readFileSync25(idxPath, "utf-8"));
|
|
93677
94745
|
entries2.push(...data);
|
|
93678
94746
|
} catch (err) {
|
|
93679
|
-
|
|
94747
|
+
log70.warn("Failed to load index", { path: idxPath, error: String(err) });
|
|
93680
94748
|
}
|
|
93681
94749
|
}
|
|
93682
94750
|
}
|
|
93683
|
-
|
|
94751
|
+
log70.info("Knowledge loaded from disk", { count: entries2.length });
|
|
93684
94752
|
return entries2;
|
|
93685
94753
|
}
|
|
93686
94754
|
// ─── Write ───────────────────────────────────────────────────────────────
|
|
93687
94755
|
saveEntry(entry) {
|
|
93688
94756
|
const dir = this.scopeDir(entry.scope, entry.scopeId);
|
|
93689
|
-
|
|
93690
|
-
|
|
94757
|
+
mkdirSync22(dir, { recursive: true });
|
|
94758
|
+
writeFileSync20(join27(dir, `${entry.id}.json`), JSON.stringify(entry, null, 2));
|
|
93691
94759
|
}
|
|
93692
94760
|
saveIndex(scope, scopeId, entries2) {
|
|
93693
94761
|
const dir = this.scopeDir(scope, scopeId);
|
|
93694
|
-
|
|
93695
|
-
|
|
94762
|
+
mkdirSync22(dir, { recursive: true });
|
|
94763
|
+
writeFileSync20(join27(dir, "_index.json"), JSON.stringify(entries2, null, 2));
|
|
93696
94764
|
}
|
|
93697
94765
|
removeEntryFile(entry) {
|
|
93698
|
-
const p =
|
|
94766
|
+
const p = join27(this.scopeDir(entry.scope, entry.scopeId), `${entry.id}.json`);
|
|
93699
94767
|
try {
|
|
93700
94768
|
unlinkSync3(p);
|
|
93701
94769
|
} catch {
|
|
@@ -93718,17 +94786,17 @@ var init_file_knowledge_store = __esm({
|
|
|
93718
94786
|
});
|
|
93719
94787
|
|
|
93720
94788
|
// ../org-manager/dist/deliverable-service.js
|
|
93721
|
-
import { existsSync as
|
|
93722
|
-
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";
|
|
93723
94791
|
function isUrl(s2) {
|
|
93724
94792
|
return /^https?:\/\//i.test(s2);
|
|
93725
94793
|
}
|
|
93726
|
-
var
|
|
94794
|
+
var log71, DeliverableService;
|
|
93727
94795
|
var init_deliverable_service = __esm({
|
|
93728
94796
|
"../org-manager/dist/deliverable-service.js"() {
|
|
93729
94797
|
"use strict";
|
|
93730
94798
|
init_dist();
|
|
93731
|
-
|
|
94799
|
+
log71 = createLogger("deliverable-service");
|
|
93732
94800
|
DeliverableService = class {
|
|
93733
94801
|
repo;
|
|
93734
94802
|
cache = /* @__PURE__ */ new Map();
|
|
@@ -93746,7 +94814,7 @@ var init_deliverable_service = __esm({
|
|
|
93746
94814
|
for (const r of rows) {
|
|
93747
94815
|
this.cache.set(r.id, this.rowToDeliverable(r));
|
|
93748
94816
|
}
|
|
93749
|
-
|
|
94817
|
+
log71.info("Deliverables loaded", { count: this.cache.size });
|
|
93750
94818
|
}
|
|
93751
94819
|
async create(opts) {
|
|
93752
94820
|
const ref = opts.reference?.trim();
|
|
@@ -93772,7 +94840,7 @@ var init_deliverable_service = __esm({
|
|
|
93772
94840
|
if (opts.taskId && !existing.taskId)
|
|
93773
94841
|
patch.taskId = opts.taskId;
|
|
93774
94842
|
const updated = await this.update(existing.id, patch);
|
|
93775
|
-
|
|
94843
|
+
log71.info("Deliverable upserted (updated existing)", { id: existing.id, reference: ref });
|
|
93776
94844
|
this.ws?.broadcastDeliverableUpdate(existing.id, "updated", {
|
|
93777
94845
|
type: opts.type,
|
|
93778
94846
|
title: opts.title,
|
|
@@ -93825,7 +94893,7 @@ var init_deliverable_service = __esm({
|
|
|
93825
94893
|
testResults: opts.testResults
|
|
93826
94894
|
});
|
|
93827
94895
|
this.cache.set(id, deliverable);
|
|
93828
|
-
|
|
94896
|
+
log71.info("Deliverable created", { id, type: opts.type, title: opts.title });
|
|
93829
94897
|
this.ws?.broadcastDeliverableUpdate(id, "created", {
|
|
93830
94898
|
type: opts.type,
|
|
93831
94899
|
title: opts.title,
|
|
@@ -93922,7 +94990,7 @@ var init_deliverable_service = __esm({
|
|
|
93922
94990
|
if (data.testResults !== void 0 && !arrEq(data.testResults, d.testResults))
|
|
93923
94991
|
changed.push("testResults");
|
|
93924
94992
|
if (changed.length === 0) {
|
|
93925
|
-
|
|
94993
|
+
log71.debug("Deliverable update skipped (no-op)", { id });
|
|
93926
94994
|
return d;
|
|
93927
94995
|
}
|
|
93928
94996
|
const now3 = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -93956,7 +95024,7 @@ var init_deliverable_service = __esm({
|
|
|
93956
95024
|
d.testResults = data.testResults;
|
|
93957
95025
|
d.updatedAt = now3;
|
|
93958
95026
|
await this.repo?.update(id, data);
|
|
93959
|
-
|
|
95027
|
+
log71.info("Deliverable updated", { id, fields: changed });
|
|
93960
95028
|
this.ws?.broadcastDeliverableUpdate(id, "updated", {
|
|
93961
95029
|
type: d.type,
|
|
93962
95030
|
title: d.title,
|
|
@@ -93973,7 +95041,7 @@ var init_deliverable_service = __esm({
|
|
|
93973
95041
|
d.status = "outdated";
|
|
93974
95042
|
d.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
93975
95043
|
await this.repo?.update(id, { status: "outdated" });
|
|
93976
|
-
|
|
95044
|
+
log71.info("Deliverable flagged outdated", { id });
|
|
93977
95045
|
this.ws?.broadcastDeliverableUpdate(id, "removed", {
|
|
93978
95046
|
type: d.type,
|
|
93979
95047
|
title: d.title,
|
|
@@ -94035,7 +95103,7 @@ var init_deliverable_service = __esm({
|
|
|
94035
95103
|
}
|
|
94036
95104
|
}
|
|
94037
95105
|
if (cleaned > 0) {
|
|
94038
|
-
|
|
95106
|
+
log71.info("Deduplicated deliverables by reference", { cleaned });
|
|
94039
95107
|
}
|
|
94040
95108
|
return cleaned;
|
|
94041
95109
|
}
|
|
@@ -94048,30 +95116,30 @@ var init_deliverable_service = __esm({
|
|
|
94048
95116
|
const deliverables = this.findByAgent(agentId2);
|
|
94049
95117
|
if (deliverables.length === 0)
|
|
94050
95118
|
return 0;
|
|
94051
|
-
const sharedDeliverables =
|
|
95119
|
+
const sharedDeliverables = join28(sharedDataDir, "deliverables");
|
|
94052
95120
|
let migrated = 0;
|
|
94053
95121
|
for (const d of deliverables) {
|
|
94054
95122
|
if (!d.reference || isUrl(d.reference))
|
|
94055
95123
|
continue;
|
|
94056
95124
|
if (!d.reference.startsWith(agentDir + "/") && d.reference !== agentDir)
|
|
94057
95125
|
continue;
|
|
94058
|
-
if (!
|
|
95126
|
+
if (!existsSync33(d.reference))
|
|
94059
95127
|
continue;
|
|
94060
95128
|
try {
|
|
94061
|
-
const destDir =
|
|
94062
|
-
|
|
95129
|
+
const destDir = join28(sharedDeliverables, d.id);
|
|
95130
|
+
mkdirSync23(destDir, { recursive: true });
|
|
94063
95131
|
const fileName = basename(d.reference);
|
|
94064
|
-
const destPath =
|
|
95132
|
+
const destPath = join28(destDir, fileName);
|
|
94065
95133
|
cpSync3(d.reference, destPath, { recursive: true });
|
|
94066
95134
|
await this.update(d.id, { reference: destPath });
|
|
94067
95135
|
migrated++;
|
|
94068
|
-
|
|
95136
|
+
log71.info("Deliverable file migrated to shared", { id: d.id, from: d.reference, to: destPath });
|
|
94069
95137
|
} catch (err) {
|
|
94070
|
-
|
|
95138
|
+
log71.warn("Failed to migrate deliverable file", { id: d.id, reference: d.reference, error: String(err) });
|
|
94071
95139
|
}
|
|
94072
95140
|
}
|
|
94073
95141
|
if (migrated > 0) {
|
|
94074
|
-
|
|
95142
|
+
log71.info("Migrated agent deliverable files to shared directory", { agentId: agentId2, migrated, total: deliverables.length });
|
|
94075
95143
|
}
|
|
94076
95144
|
return migrated;
|
|
94077
95145
|
}
|
|
@@ -94085,7 +95153,7 @@ var init_deliverable_service = __esm({
|
|
|
94085
95153
|
for (const d of deliverables) {
|
|
94086
95154
|
if (!d.reference || isUrl(d.reference))
|
|
94087
95155
|
continue;
|
|
94088
|
-
if (!
|
|
95156
|
+
if (!existsSync33(d.reference)) {
|
|
94089
95157
|
missing.push(d.id);
|
|
94090
95158
|
}
|
|
94091
95159
|
}
|
|
@@ -94107,7 +95175,7 @@ var init_deliverable_service = __esm({
|
|
|
94107
95175
|
}
|
|
94108
95176
|
}
|
|
94109
95177
|
if (branchCleaned > 0) {
|
|
94110
|
-
|
|
95178
|
+
log71.info("Cleaned up legacy branch-type deliverables", { count: branchCleaned });
|
|
94111
95179
|
}
|
|
94112
95180
|
const existingTaskIds = this.repo ? await this.repo.listTaskIdsWithDeliverables() : new Set([...this.cache.values()].map((d) => d.taskId).filter(Boolean));
|
|
94113
95181
|
let migrated = 0;
|
|
@@ -94134,12 +95202,12 @@ var init_deliverable_service = __esm({
|
|
|
94134
95202
|
});
|
|
94135
95203
|
migrated++;
|
|
94136
95204
|
} catch (err) {
|
|
94137
|
-
|
|
95205
|
+
log71.warn("Failed to migrate task deliverable", { taskId: task.id, ref: d.reference, error: String(err) });
|
|
94138
95206
|
}
|
|
94139
95207
|
}
|
|
94140
95208
|
}
|
|
94141
95209
|
if (migrated > 0) {
|
|
94142
|
-
|
|
95210
|
+
log71.info("Migrated task deliverables to unified table", { migrated });
|
|
94143
95211
|
}
|
|
94144
95212
|
return migrated;
|
|
94145
95213
|
}
|
|
@@ -94194,12 +95262,12 @@ var init_deliverable_service = __esm({
|
|
|
94194
95262
|
});
|
|
94195
95263
|
|
|
94196
95264
|
// ../org-manager/dist/report-service.js
|
|
94197
|
-
var
|
|
95265
|
+
var log72, ReportService;
|
|
94198
95266
|
var init_report_service = __esm({
|
|
94199
95267
|
"../org-manager/dist/report-service.js"() {
|
|
94200
95268
|
"use strict";
|
|
94201
95269
|
init_dist();
|
|
94202
|
-
|
|
95270
|
+
log72 = createLogger("report-service");
|
|
94203
95271
|
ReportService = class {
|
|
94204
95272
|
taskService;
|
|
94205
95273
|
billingService;
|
|
@@ -94252,7 +95320,7 @@ var init_report_service = __esm({
|
|
|
94252
95320
|
generatedBy: opts.generatedBy ?? "system"
|
|
94253
95321
|
};
|
|
94254
95322
|
this.reports.set(report.id, report);
|
|
94255
|
-
|
|
95323
|
+
log72.info("Report generated", { id: report.id, type: report.type, scope: report.scope });
|
|
94256
95324
|
return report;
|
|
94257
95325
|
}
|
|
94258
95326
|
getReport(id) {
|
|
@@ -94274,7 +95342,7 @@ var init_report_service = __esm({
|
|
|
94274
95342
|
if (!report?.upcomingPlan)
|
|
94275
95343
|
throw new Error("Report has no plan");
|
|
94276
95344
|
report.upcomingPlan.status = "pending";
|
|
94277
|
-
|
|
95345
|
+
log72.info("Plan submitted for approval", { reportId });
|
|
94278
95346
|
}
|
|
94279
95347
|
approvePlan(reportId, userId2) {
|
|
94280
95348
|
const report = this.reports.get(reportId);
|
|
@@ -94301,7 +95369,7 @@ var init_report_service = __esm({
|
|
|
94301
95369
|
projectId: report.scope === "project" ? report.scopeId : void 0
|
|
94302
95370
|
});
|
|
94303
95371
|
}
|
|
94304
|
-
|
|
95372
|
+
log72.info("Plan approved \u2014 tasks created", {
|
|
94305
95373
|
reportId,
|
|
94306
95374
|
taskCount: report.upcomingPlan.plannedTasks.length
|
|
94307
95375
|
});
|
|
@@ -94313,7 +95381,7 @@ var init_report_service = __esm({
|
|
|
94313
95381
|
throw new Error("Report has no plan");
|
|
94314
95382
|
report.upcomingPlan.status = "rejected";
|
|
94315
95383
|
report.upcomingPlan.rejectionReason = reason;
|
|
94316
|
-
|
|
95384
|
+
log72.info("Plan rejected", { reportId, reason });
|
|
94317
95385
|
return report;
|
|
94318
95386
|
}
|
|
94319
95387
|
// ─── Feedback ──────────────────────────────────────────────────────────────
|
|
@@ -94365,7 +95433,7 @@ var init_report_service = __esm({
|
|
|
94365
95433
|
const existing = this.feedbackStore.get(opts.reportId) ?? [];
|
|
94366
95434
|
existing.push(feedback);
|
|
94367
95435
|
this.feedbackStore.set(opts.reportId, existing);
|
|
94368
|
-
|
|
95436
|
+
log72.info("Feedback added to report", {
|
|
94369
95437
|
reportId: opts.reportId,
|
|
94370
95438
|
type: opts.type,
|
|
94371
95439
|
disclosure: opts.disclosure.scope
|
|
@@ -94450,12 +95518,12 @@ var init_report_service = __esm({
|
|
|
94450
95518
|
});
|
|
94451
95519
|
|
|
94452
95520
|
// ../org-manager/dist/trust-service.js
|
|
94453
|
-
var
|
|
95521
|
+
var log73, TrustService;
|
|
94454
95522
|
var init_trust_service = __esm({
|
|
94455
95523
|
"../org-manager/dist/trust-service.js"() {
|
|
94456
95524
|
"use strict";
|
|
94457
95525
|
init_dist();
|
|
94458
|
-
|
|
95526
|
+
log73 = createLogger("trust-service");
|
|
94459
95527
|
TrustService = class {
|
|
94460
95528
|
trustLevels = /* @__PURE__ */ new Map();
|
|
94461
95529
|
getOrCreate(agentId2) {
|
|
@@ -94504,7 +95572,7 @@ var init_trust_service = __esm({
|
|
|
94504
95572
|
trust.level = this.scoreToLevel(trust.score, trust.totalDeliveries);
|
|
94505
95573
|
trust.lastEvaluatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
94506
95574
|
if (trust.level !== oldLevel) {
|
|
94507
|
-
|
|
95575
|
+
log73.info("Trust level changed", {
|
|
94508
95576
|
agentId: trust.agentId,
|
|
94509
95577
|
oldLevel,
|
|
94510
95578
|
newLevel: trust.level,
|
|
@@ -94549,12 +95617,12 @@ var init_trust_service = __esm({
|
|
|
94549
95617
|
});
|
|
94550
95618
|
|
|
94551
95619
|
// ../org-manager/dist/archive-service.js
|
|
94552
|
-
var
|
|
95620
|
+
var log74, ARCHIVABLE_STATUSES, ACTIVE_DISCUSSION_DAYS, ACTIVE_DISCUSSION_MS, ArchiveService;
|
|
94553
95621
|
var init_archive_service = __esm({
|
|
94554
95622
|
"../org-manager/dist/archive-service.js"() {
|
|
94555
95623
|
"use strict";
|
|
94556
95624
|
init_dist();
|
|
94557
|
-
|
|
95625
|
+
log74 = createLogger("archive-service");
|
|
94558
95626
|
ARCHIVABLE_STATUSES = /* @__PURE__ */ new Set(["completed", "failed", "rejected", "cancelled"]);
|
|
94559
95627
|
ACTIVE_DISCUSSION_DAYS = 7;
|
|
94560
95628
|
ACTIVE_DISCUSSION_MS = ACTIVE_DISCUSSION_DAYS * 864e5;
|
|
@@ -94575,11 +95643,11 @@ var init_archive_service = __esm({
|
|
|
94575
95643
|
* then repeats at the configured interval.
|
|
94576
95644
|
*/
|
|
94577
95645
|
start(intervalMs = ARCHIVE_SCAN_INTERVAL_MS) {
|
|
94578
|
-
this.runArchiveScan().catch((err) =>
|
|
95646
|
+
this.runArchiveScan().catch((err) => log74.warn("Initial archive scan failed", { error: String(err) }));
|
|
94579
95647
|
this.scanInterval = setInterval(() => {
|
|
94580
|
-
this.runArchiveScan().catch((err) =>
|
|
95648
|
+
this.runArchiveScan().catch((err) => log74.warn("Archive scan failed", { error: String(err) }));
|
|
94581
95649
|
}, intervalMs);
|
|
94582
|
-
|
|
95650
|
+
log74.info("Archive service started", { intervalMs });
|
|
94583
95651
|
}
|
|
94584
95652
|
stop() {
|
|
94585
95653
|
if (this.scanInterval) {
|
|
@@ -94591,7 +95659,7 @@ var init_archive_service = __esm({
|
|
|
94591
95659
|
const archivedTasks = await this.archiveTasks();
|
|
94592
95660
|
const archivedRequirements = this.archiveRequirements();
|
|
94593
95661
|
if (archivedTasks > 0 || archivedRequirements > 0) {
|
|
94594
|
-
|
|
95662
|
+
log74.info("Archive scan complete", { archivedTasks, archivedRequirements });
|
|
94595
95663
|
}
|
|
94596
95664
|
return { archivedTasks, archivedRequirements };
|
|
94597
95665
|
}
|
|
@@ -94614,7 +95682,7 @@ var init_archive_service = __esm({
|
|
|
94614
95682
|
this.taskService.archiveTask(task.id);
|
|
94615
95683
|
archived++;
|
|
94616
95684
|
} catch (err) {
|
|
94617
|
-
|
|
95685
|
+
log74.warn("Failed to archive task", { taskId: task.id, error: String(err) });
|
|
94618
95686
|
}
|
|
94619
95687
|
}
|
|
94620
95688
|
}
|
|
@@ -94639,7 +95707,7 @@ var init_archive_service = __esm({
|
|
|
94639
95707
|
this.requirementService.updateRequirementStatus(req.id, "archived");
|
|
94640
95708
|
archived++;
|
|
94641
95709
|
} catch (err) {
|
|
94642
|
-
|
|
95710
|
+
log74.warn("Failed to archive requirement", { requirementId: req.id, error: String(err) });
|
|
94643
95711
|
}
|
|
94644
95712
|
}
|
|
94645
95713
|
}
|
|
@@ -94681,12 +95749,12 @@ var init_archive_service = __esm({
|
|
|
94681
95749
|
});
|
|
94682
95750
|
|
|
94683
95751
|
// ../org-manager/dist/stale-detector.js
|
|
94684
|
-
var
|
|
95752
|
+
var log75, DEFAULT_CONFIG4, StaleDetector;
|
|
94685
95753
|
var init_stale_detector = __esm({
|
|
94686
95754
|
"../org-manager/dist/stale-detector.js"() {
|
|
94687
95755
|
"use strict";
|
|
94688
95756
|
init_dist();
|
|
94689
|
-
|
|
95757
|
+
log75 = createLogger("stale-detector");
|
|
94690
95758
|
DEFAULT_CONFIG4 = {
|
|
94691
95759
|
maxInProgressMs: 24 * 60 * 60 * 1e3,
|
|
94692
95760
|
maxReviewWaitMs: 12 * 60 * 60 * 1e3,
|
|
@@ -94709,9 +95777,9 @@ var init_stale_detector = __esm({
|
|
|
94709
95777
|
if (items.length > 0 && this.onStaleItems) {
|
|
94710
95778
|
this.onStaleItems(items);
|
|
94711
95779
|
}
|
|
94712
|
-
}).catch((err) =>
|
|
95780
|
+
}).catch((err) => log75.warn("Stale scan failed", { error: String(err) }));
|
|
94713
95781
|
}, intervalMs);
|
|
94714
|
-
|
|
95782
|
+
log75.info("Stale detector started", { intervalMs });
|
|
94715
95783
|
}
|
|
94716
95784
|
stop() {
|
|
94717
95785
|
if (this.scanInterval) {
|
|
@@ -94754,7 +95822,7 @@ var init_stale_detector = __esm({
|
|
|
94754
95822
|
}
|
|
94755
95823
|
}
|
|
94756
95824
|
if (staleItems.length > 0) {
|
|
94757
|
-
|
|
95825
|
+
log75.info(`Found ${staleItems.length} stale items`);
|
|
94758
95826
|
}
|
|
94759
95827
|
return staleItems;
|
|
94760
95828
|
}
|
|
@@ -94763,12 +95831,12 @@ var init_stale_detector = __esm({
|
|
|
94763
95831
|
});
|
|
94764
95832
|
|
|
94765
95833
|
// ../org-manager/dist/scheduled-task-runner.js
|
|
94766
|
-
var
|
|
95834
|
+
var log76, MIN_STAGGER_MS, MAX_STAGGER_MS, ScheduledTaskRunner;
|
|
94767
95835
|
var init_scheduled_task_runner = __esm({
|
|
94768
95836
|
"../org-manager/dist/scheduled-task-runner.js"() {
|
|
94769
95837
|
"use strict";
|
|
94770
95838
|
init_dist();
|
|
94771
|
-
|
|
95839
|
+
log76 = createLogger("scheduled-task-runner");
|
|
94772
95840
|
MIN_STAGGER_MS = 2 * 6e4;
|
|
94773
95841
|
MAX_STAGGER_MS = 15 * 6e4;
|
|
94774
95842
|
ScheduledTaskRunner = class {
|
|
@@ -94787,11 +95855,11 @@ var init_scheduled_task_runner = __esm({
|
|
|
94787
95855
|
return;
|
|
94788
95856
|
this.running = true;
|
|
94789
95857
|
this.startedAt = Date.now();
|
|
94790
|
-
this.tick().catch((e) =>
|
|
95858
|
+
this.tick().catch((e) => log76.error("Initial scheduled task tick failed", { error: String(e) }));
|
|
94791
95859
|
this.timer = setInterval(() => {
|
|
94792
|
-
this.tick().catch((e) =>
|
|
95860
|
+
this.tick().catch((e) => log76.error("Scheduled task tick failed", { error: String(e) }));
|
|
94793
95861
|
}, this.pollIntervalMs);
|
|
94794
|
-
|
|
95862
|
+
log76.info("ScheduledTaskRunner started", { pollIntervalMs: this.pollIntervalMs });
|
|
94795
95863
|
}
|
|
94796
95864
|
stop() {
|
|
94797
95865
|
if (this.timer) {
|
|
@@ -94802,7 +95870,7 @@ var init_scheduled_task_runner = __esm({
|
|
|
94802
95870
|
clearTimeout(t);
|
|
94803
95871
|
this.staggerTimers = [];
|
|
94804
95872
|
this.running = false;
|
|
94805
|
-
|
|
95873
|
+
log76.info("ScheduledTaskRunner stopped");
|
|
94806
95874
|
}
|
|
94807
95875
|
isRunning() {
|
|
94808
95876
|
return this.running;
|
|
@@ -94836,7 +95904,7 @@ var init_scheduled_task_runner = __esm({
|
|
|
94836
95904
|
}
|
|
94837
95905
|
if (startup && nextRun < this.startedAt) {
|
|
94838
95906
|
const delay = MIN_STAGGER_MS + Math.random() * (MAX_STAGGER_MS - MIN_STAGGER_MS);
|
|
94839
|
-
|
|
95907
|
+
log76.info("Staggering overdue scheduled task", {
|
|
94840
95908
|
taskId: task.id,
|
|
94841
95909
|
title: task.title,
|
|
94842
95910
|
overdueBy: `${Math.round((now3 - nextRun) / 6e4)}m`,
|
|
@@ -94845,7 +95913,7 @@ var init_scheduled_task_runner = __esm({
|
|
|
94845
95913
|
const timer = setTimeout(() => {
|
|
94846
95914
|
if (!this.running)
|
|
94847
95915
|
return;
|
|
94848
|
-
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) }));
|
|
94849
95917
|
}, delay);
|
|
94850
95918
|
this.staggerTimers.push(timer);
|
|
94851
95919
|
continue;
|
|
@@ -94853,27 +95921,27 @@ var init_scheduled_task_runner = __esm({
|
|
|
94853
95921
|
try {
|
|
94854
95922
|
await this.fireScheduledTask(task);
|
|
94855
95923
|
} catch (e) {
|
|
94856
|
-
|
|
95924
|
+
log76.error("Failed to fire scheduled task", { taskId: task.id, error: String(e) });
|
|
94857
95925
|
}
|
|
94858
95926
|
}
|
|
94859
95927
|
}
|
|
94860
95928
|
async fireScheduledTask(task) {
|
|
94861
|
-
|
|
95929
|
+
log76.info("Firing scheduled task", { taskId: task.id, title: task.title });
|
|
94862
95930
|
await this.taskService.advanceScheduleConfig(task.id);
|
|
94863
95931
|
const resettableStatuses = ["completed", "cancelled", "failed"];
|
|
94864
95932
|
if (resettableStatuses.includes(task.status)) {
|
|
94865
95933
|
await this.taskService.resetTaskForRerun(task.id);
|
|
94866
95934
|
} else if (!["in_progress", "review", "blocked", "pending"].includes(task.status)) {
|
|
94867
|
-
|
|
95935
|
+
log76.warn("Scheduled task has unexpected status, resetting for rerun", { taskId: task.id, status: task.status });
|
|
94868
95936
|
await this.taskService.resetTaskForRerun(task.id);
|
|
94869
95937
|
}
|
|
94870
95938
|
const current = this.taskService.getTask(task.id);
|
|
94871
95939
|
if (current && current.status === "in_progress") {
|
|
94872
95940
|
try {
|
|
94873
95941
|
await this.taskService.runTask(task.id);
|
|
94874
|
-
|
|
95942
|
+
log76.info("Scheduled task auto-started", { taskId: task.id });
|
|
94875
95943
|
} catch (err) {
|
|
94876
|
-
|
|
95944
|
+
log76.warn("Failed to auto-start scheduled task (agent may be busy)", { taskId: task.id, error: String(err) });
|
|
94877
95945
|
}
|
|
94878
95946
|
}
|
|
94879
95947
|
}
|
|
@@ -94883,11 +95951,11 @@ var init_scheduled_task_runner = __esm({
|
|
|
94883
95951
|
|
|
94884
95952
|
// ../storage/dist/sqlite-storage.js
|
|
94885
95953
|
import { DatabaseSync } from "node:sqlite";
|
|
94886
|
-
import { randomUUID } from "node:crypto";
|
|
94887
|
-
import { mkdirSync as
|
|
94888
|
-
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";
|
|
94889
95957
|
function generateId2(prefix = "") {
|
|
94890
|
-
const uuid =
|
|
95958
|
+
const uuid = randomUUID2().replace(/-/g, "").slice(0, 16);
|
|
94891
95959
|
return prefix ? `${prefix}_${uuid}` : uuid;
|
|
94892
95960
|
}
|
|
94893
95961
|
function now2() {
|
|
@@ -94905,7 +95973,7 @@ function toDate(v) {
|
|
|
94905
95973
|
function openSqlite(dbPath) {
|
|
94906
95974
|
if (_db)
|
|
94907
95975
|
return _db;
|
|
94908
|
-
|
|
95976
|
+
mkdirSync24(dirname11(dbPath), { recursive: true });
|
|
94909
95977
|
_db = new DatabaseSync(dbPath);
|
|
94910
95978
|
_db.exec("PRAGMA journal_mode = WAL");
|
|
94911
95979
|
_db.exec("PRAGMA foreign_keys = ON");
|
|
@@ -94949,6 +96017,8 @@ function openSqlite(dbPath) {
|
|
|
94949
96017
|
{ table: "projects", column: "created_by", sql: "ALTER TABLE projects ADD COLUMN created_by TEXT" },
|
|
94950
96018
|
{ table: "approvals", column: "target_user_id", sql: "ALTER TABLE approvals ADD COLUMN target_user_id TEXT" },
|
|
94951
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" },
|
|
94952
96022
|
{ table: "agents", column: "deleted_at", sql: "ALTER TABLE agents ADD COLUMN deleted_at TEXT" },
|
|
94953
96023
|
{ table: "deliverables", column: "format", sql: "ALTER TABLE deliverables ADD COLUMN format TEXT" },
|
|
94954
96024
|
{ table: "task_comments", column: "reply_to_id", sql: "ALTER TABLE task_comments ADD COLUMN reply_to_id TEXT" },
|
|
@@ -94958,7 +96028,7 @@ function openSqlite(dbPath) {
|
|
|
94958
96028
|
const cols = _db.prepare(`PRAGMA table_info(${m.table})`).all();
|
|
94959
96029
|
if (!cols.some((c) => c.name === m.column)) {
|
|
94960
96030
|
_db.exec(m.sql);
|
|
94961
|
-
|
|
96031
|
+
log77.info(`Migration: added column ${m.column} to ${m.table}`);
|
|
94962
96032
|
}
|
|
94963
96033
|
}
|
|
94964
96034
|
_db.exec("CREATE INDEX IF NOT EXISTS idx_agent_activities_mailbox ON agent_activities(mailbox_item_id)");
|
|
@@ -94972,10 +96042,10 @@ function openSqlite(dbPath) {
|
|
|
94972
96042
|
for (const m of statusMigrations) {
|
|
94973
96043
|
const result = _db.prepare(m.sql).run();
|
|
94974
96044
|
if (result.changes > 0) {
|
|
94975
|
-
|
|
96045
|
+
log77.info(`Status migration: ${m.desc} (${result.changes} rows)`);
|
|
94976
96046
|
}
|
|
94977
96047
|
}
|
|
94978
|
-
|
|
96048
|
+
log77.info("SQLite database opened", { path: dbPath });
|
|
94979
96049
|
return _db;
|
|
94980
96050
|
}
|
|
94981
96051
|
function closeSqlite() {
|
|
@@ -94995,7 +96065,7 @@ function migrateToExecutionStreamLogs(db) {
|
|
|
94995
96065
|
SELECT id, 'task', task_id, agent_id, seq, type, content, metadata, execution_round, created_at
|
|
94996
96066
|
FROM task_logs
|
|
94997
96067
|
`);
|
|
94998
|
-
|
|
96068
|
+
log77.info(`Migration: copied ${taskLogCount} task_logs to execution_stream_logs`);
|
|
94999
96069
|
}
|
|
95000
96070
|
const actLogCount = db.prepare("SELECT COUNT(*) as cnt FROM agent_activity_logs").get().cnt;
|
|
95001
96071
|
if (actLogCount > 0) {
|
|
@@ -95006,15 +96076,15 @@ function migrateToExecutionStreamLogs(db) {
|
|
|
95006
96076
|
seq, type, content, metadata, NULL, created_at
|
|
95007
96077
|
FROM agent_activity_logs
|
|
95008
96078
|
`);
|
|
95009
|
-
|
|
96079
|
+
log77.info(`Migration: copied ${actLogCount} agent_activity_logs to execution_stream_logs`);
|
|
95010
96080
|
}
|
|
95011
96081
|
}
|
|
95012
|
-
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;
|
|
95013
96083
|
var init_sqlite_storage = __esm({
|
|
95014
96084
|
"../storage/dist/sqlite-storage.js"() {
|
|
95015
96085
|
"use strict";
|
|
95016
96086
|
init_dist();
|
|
95017
|
-
|
|
96087
|
+
log77 = createLogger("sqlite-storage");
|
|
95018
96088
|
SCHEMA_SQL = `
|
|
95019
96089
|
CREATE TABLE IF NOT EXISTS organizations (
|
|
95020
96090
|
id TEXT PRIMARY KEY,
|
|
@@ -96496,7 +97566,7 @@ CREATE TABLE IF NOT EXISTS user_read_cursors (
|
|
|
96496
97566
|
migrated++;
|
|
96497
97567
|
}
|
|
96498
97568
|
if (migrated > 0) {
|
|
96499
|
-
|
|
97569
|
+
log77.info(`Migrated ${migrated} legacy chat messages to segment format`);
|
|
96500
97570
|
}
|
|
96501
97571
|
return migrated;
|
|
96502
97572
|
}
|
|
@@ -96508,7 +97578,7 @@ CREATE TABLE IF NOT EXISTS user_read_cursors (
|
|
|
96508
97578
|
const result = this.db.prepare("UPDATE chat_sessions SET user_id = ? WHERE user_id IS NULL").run(defaultUserId);
|
|
96509
97579
|
const count = Number(result.changes);
|
|
96510
97580
|
if (count > 0) {
|
|
96511
|
-
|
|
97581
|
+
log77.info(`Migrated ${count} chat sessions with NULL user_id to user ${defaultUserId}`);
|
|
96512
97582
|
}
|
|
96513
97583
|
return count;
|
|
96514
97584
|
}
|
|
@@ -96522,7 +97592,7 @@ CREATE TABLE IF NOT EXISTS user_read_cursors (
|
|
|
96522
97592
|
const result = this.db.prepare("UPDATE chat_sessions SET user_id = ? WHERE user_id = 'default'").run(realOwnerId);
|
|
96523
97593
|
const count = Number(result.changes);
|
|
96524
97594
|
if (count > 0) {
|
|
96525
|
-
|
|
97595
|
+
log77.info(`Migrated ${count} chat sessions from user_id='default' to ${realOwnerId}`);
|
|
96526
97596
|
}
|
|
96527
97597
|
return count;
|
|
96528
97598
|
}
|
|
@@ -96668,13 +97738,13 @@ CREATE TABLE IF NOT EXISTS user_read_cursors (
|
|
|
96668
97738
|
this.db = db;
|
|
96669
97739
|
}
|
|
96670
97740
|
create(data) {
|
|
96671
|
-
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());
|
|
96672
97742
|
return this.findById(data.id);
|
|
96673
97743
|
}
|
|
96674
97744
|
async upsert(data) {
|
|
96675
|
-
this.db.prepare(`INSERT INTO users (id, org_id, name, email, role, team_id, password_hash, created_at)
|
|
96676
|
-
VALUES (
|
|
96677
|
-
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());
|
|
96678
97748
|
}
|
|
96679
97749
|
async updateTeamId(id, teamId) {
|
|
96680
97750
|
this.db.prepare("UPDATE users SET team_id = ? WHERE id = ?").run(teamId, id);
|
|
@@ -96689,6 +97759,17 @@ CREATE TABLE IF NOT EXISTS user_read_cursors (
|
|
|
96689
97759
|
const r = this.db.prepare("SELECT * FROM users WHERE email = ? AND deleted_at IS NULL").get(email);
|
|
96690
97760
|
return r ? this._map(r) : null;
|
|
96691
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
|
+
}
|
|
96692
97773
|
findById(id) {
|
|
96693
97774
|
const r = this.db.prepare("SELECT * FROM users WHERE id = ?").get(id);
|
|
96694
97775
|
return r ? this._map(r) : null;
|
|
@@ -96765,7 +97846,7 @@ CREATE TABLE IF NOT EXISTS user_read_cursors (
|
|
|
96765
97846
|
return newId;
|
|
96766
97847
|
}
|
|
96767
97848
|
this.db.prepare("UPDATE users SET id = ? WHERE id = 'default'").run(newId);
|
|
96768
|
-
|
|
97849
|
+
log77.info(`Migrated user id='default' to '${newId}'`);
|
|
96769
97850
|
return newId;
|
|
96770
97851
|
}
|
|
96771
97852
|
_map(r) {
|
|
@@ -96778,6 +97859,8 @@ CREATE TABLE IF NOT EXISTS user_read_cursors (
|
|
|
96778
97859
|
teamId: r["team_id"],
|
|
96779
97860
|
passwordHash: r["password_hash"],
|
|
96780
97861
|
avatarUrl: r["avatar_url"],
|
|
97862
|
+
hubUserId: r["hub_user_id"],
|
|
97863
|
+
hubUsername: r["hub_username"],
|
|
96781
97864
|
inviteToken: r["invite_token"],
|
|
96782
97865
|
inviteExpiresAt: r["invite_expires_at"],
|
|
96783
97866
|
createdAt: toDate(r["created_at"]),
|
|
@@ -97824,7 +98907,7 @@ CREATE TABLE IF NOT EXISTS user_read_cursors (
|
|
|
97824
98907
|
const result = this.db.prepare("UPDATE user_notifications SET user_id = ? WHERE user_id = 'default'").run(realOwnerId);
|
|
97825
98908
|
const count = Number(result.changes);
|
|
97826
98909
|
if (count > 0) {
|
|
97827
|
-
|
|
98910
|
+
log77.info(`Migrated ${count} notifications from user_id='default' to ${realOwnerId}`);
|
|
97828
98911
|
}
|
|
97829
98912
|
return count;
|
|
97830
98913
|
}
|
|
@@ -97905,7 +98988,7 @@ CREATE TABLE IF NOT EXISTS user_read_cursors (
|
|
|
97905
98988
|
const result = this.db.prepare("UPDATE approvals SET target_user_id = ? WHERE target_user_id = 'default'").run(realOwnerId);
|
|
97906
98989
|
const count = Number(result.changes);
|
|
97907
98990
|
if (count > 0) {
|
|
97908
|
-
|
|
98991
|
+
log77.info(`Migrated ${count} approvals from target_user_id='default' to ${realOwnerId}`);
|
|
97909
98992
|
}
|
|
97910
98993
|
return count;
|
|
97911
98994
|
}
|
|
@@ -98154,17 +99237,17 @@ var init_dist5 = __esm({
|
|
|
98154
99237
|
});
|
|
98155
99238
|
|
|
98156
99239
|
// ../org-manager/dist/storage-bridge.js
|
|
98157
|
-
import { homedir as
|
|
98158
|
-
import { join as
|
|
99240
|
+
import { homedir as homedir18 } from "node:os";
|
|
99241
|
+
import { join as join29 } from "node:path";
|
|
98159
99242
|
function resolveSqlitePath(url) {
|
|
98160
99243
|
if (url?.startsWith("sqlite:")) {
|
|
98161
99244
|
let p = url.slice("sqlite:".length);
|
|
98162
99245
|
if (p.startsWith("~/") || p === "~") {
|
|
98163
|
-
p =
|
|
99246
|
+
p = join29(homedir18(), p.slice(2));
|
|
98164
99247
|
}
|
|
98165
99248
|
return p;
|
|
98166
99249
|
}
|
|
98167
|
-
return
|
|
99250
|
+
return join29(homedir18(), ".markus", "data.db");
|
|
98168
99251
|
}
|
|
98169
99252
|
async function initStorage(databaseUrl) {
|
|
98170
99253
|
const url = databaseUrl ?? process.env["DATABASE_URL"];
|
|
@@ -98202,28 +99285,28 @@ async function initSqliteStorage(url) {
|
|
|
98202
99285
|
statusTransitionRepo: new storage.SqliteStatusTransitionRepo(db),
|
|
98203
99286
|
readCursorRepo: new storage.SqliteReadCursorRepo(db)
|
|
98204
99287
|
};
|
|
98205
|
-
|
|
99288
|
+
log78.info("SQLite storage initialized", { path: dbPath });
|
|
98206
99289
|
return bridge;
|
|
98207
99290
|
} catch (error) {
|
|
98208
|
-
|
|
99291
|
+
log78.warn("Failed to initialize SQLite storage, falling back to memory-only mode", {
|
|
98209
99292
|
error: String(error)
|
|
98210
99293
|
});
|
|
98211
99294
|
return null;
|
|
98212
99295
|
}
|
|
98213
99296
|
}
|
|
98214
|
-
var
|
|
99297
|
+
var log78;
|
|
98215
99298
|
var init_storage_bridge = __esm({
|
|
98216
99299
|
"../org-manager/dist/storage-bridge.js"() {
|
|
98217
99300
|
"use strict";
|
|
98218
99301
|
init_dist();
|
|
98219
|
-
|
|
99302
|
+
log78 = createLogger("storage-bridge");
|
|
98220
99303
|
}
|
|
98221
99304
|
});
|
|
98222
99305
|
|
|
98223
99306
|
// ../org-manager/dist/file-storage-provider.js
|
|
98224
|
-
import { mkdirSync as
|
|
98225
|
-
import { join as
|
|
98226
|
-
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";
|
|
98227
99310
|
function mimeToExt(mime) {
|
|
98228
99311
|
const map = {
|
|
98229
99312
|
"image/jpeg": ".jpg",
|
|
@@ -98243,27 +99326,27 @@ var init_file_storage_provider = __esm({
|
|
|
98243
99326
|
LocalFileStorageProvider = class {
|
|
98244
99327
|
baseDir;
|
|
98245
99328
|
constructor(baseDir) {
|
|
98246
|
-
this.baseDir = baseDir ??
|
|
98247
|
-
|
|
99329
|
+
this.baseDir = baseDir ?? join30(homedir19(), ".markus", "uploads");
|
|
99330
|
+
mkdirSync25(this.baseDir, { recursive: true });
|
|
98248
99331
|
}
|
|
98249
99332
|
async upload(data, opts) {
|
|
98250
99333
|
const ext = extname(opts.name) || mimeToExt(opts.contentType);
|
|
98251
99334
|
const key2 = `${generateId("upl")}${ext}`;
|
|
98252
|
-
const subDir = opts.prefix ?
|
|
98253
|
-
|
|
98254
|
-
|
|
99335
|
+
const subDir = opts.prefix ? join30(this.baseDir, opts.prefix) : this.baseDir;
|
|
99336
|
+
mkdirSync25(subDir, { recursive: true });
|
|
99337
|
+
writeFileSync21(join30(subDir, key2), data);
|
|
98255
99338
|
const urlPath = opts.prefix ? `/api/uploads/${opts.prefix}/${key2}` : `/api/uploads/${key2}`;
|
|
98256
99339
|
return { url: urlPath, key: opts.prefix ? `${opts.prefix}/${key2}` : key2 };
|
|
98257
99340
|
}
|
|
98258
99341
|
async delete(key2) {
|
|
98259
|
-
const filePath =
|
|
98260
|
-
if (
|
|
99342
|
+
const filePath = join30(this.baseDir, key2);
|
|
99343
|
+
if (existsSync34(filePath)) {
|
|
98261
99344
|
unlinkSync4(filePath);
|
|
98262
99345
|
}
|
|
98263
99346
|
}
|
|
98264
99347
|
/** Resolve a storage key to an absolute filesystem path (for serving). */
|
|
98265
99348
|
resolve(key2) {
|
|
98266
|
-
return
|
|
99349
|
+
return join30(this.baseDir, key2);
|
|
98267
99350
|
}
|
|
98268
99351
|
};
|
|
98269
99352
|
}
|
|
@@ -98281,6 +99364,7 @@ __export(dist_exports5, {
|
|
|
98281
99364
|
FileKnowledgeStore: () => FileKnowledgeStore,
|
|
98282
99365
|
HITLService: () => HITLService,
|
|
98283
99366
|
KnowledgeService: () => KnowledgeService,
|
|
99367
|
+
LicenseService: () => LicenseService,
|
|
98284
99368
|
LocalFileStorageProvider: () => LocalFileStorageProvider,
|
|
98285
99369
|
OrganizationService: () => OrganizationService,
|
|
98286
99370
|
ProjectService: () => ProjectService,
|
|
@@ -98289,6 +99373,7 @@ __export(dist_exports5, {
|
|
|
98289
99373
|
ScheduledTaskRunner: () => ScheduledTaskRunner,
|
|
98290
99374
|
StaleDetector: () => StaleDetector,
|
|
98291
99375
|
TaskService: () => TaskService,
|
|
99376
|
+
TelemetryService: () => TelemetryService,
|
|
98292
99377
|
TrustService: () => TrustService,
|
|
98293
99378
|
WSBroadcaster: () => WSBroadcaster,
|
|
98294
99379
|
initStorage: () => initStorage,
|
|
@@ -98304,6 +99389,8 @@ var init_dist6 = __esm({
|
|
|
98304
99389
|
init_ws_server();
|
|
98305
99390
|
init_hitl_service();
|
|
98306
99391
|
init_billing_service();
|
|
99392
|
+
init_license_service();
|
|
99393
|
+
init_telemetry_service();
|
|
98307
99394
|
init_audit_service();
|
|
98308
99395
|
init_project_service();
|
|
98309
99396
|
init_requirement_service();
|
|
@@ -98323,12 +99410,12 @@ var init_dist6 = __esm({
|
|
|
98323
99410
|
});
|
|
98324
99411
|
|
|
98325
99412
|
// ../comms/dist/feishu/client.js
|
|
98326
|
-
var
|
|
99413
|
+
var log79, FeishuClient;
|
|
98327
99414
|
var init_client = __esm({
|
|
98328
99415
|
"../comms/dist/feishu/client.js"() {
|
|
98329
99416
|
"use strict";
|
|
98330
99417
|
init_dist();
|
|
98331
|
-
|
|
99418
|
+
log79 = createLogger("feishu-client");
|
|
98332
99419
|
FeishuClient = class {
|
|
98333
99420
|
appId;
|
|
98334
99421
|
appSecret;
|
|
@@ -98358,7 +99445,7 @@ var init_client = __esm({
|
|
|
98358
99445
|
}
|
|
98359
99446
|
this.tenantToken = data.tenant_access_token;
|
|
98360
99447
|
this.tokenExpiresAt = Date.now() + (data.expire - 300) * 1e3;
|
|
98361
|
-
|
|
99448
|
+
log79.info("Feishu tenant token refreshed");
|
|
98362
99449
|
return this.tenantToken;
|
|
98363
99450
|
}
|
|
98364
99451
|
async sendTextMessage(chatId, text) {
|
|
@@ -98492,13 +99579,13 @@ var init_client = __esm({
|
|
|
98492
99579
|
import { createServer as createServer3 } from "node:http";
|
|
98493
99580
|
import { createDecipheriv, scrypt } from "node:crypto";
|
|
98494
99581
|
import { promisify as promisify3 } from "node:util";
|
|
98495
|
-
var
|
|
99582
|
+
var log80, scryptAsync, FeishuAdapter;
|
|
98496
99583
|
var init_adapter = __esm({
|
|
98497
99584
|
"../comms/dist/feishu/adapter.js"() {
|
|
98498
99585
|
"use strict";
|
|
98499
99586
|
init_dist();
|
|
98500
99587
|
init_client();
|
|
98501
|
-
|
|
99588
|
+
log80 = createLogger("feishu-adapter");
|
|
98502
99589
|
scryptAsync = promisify3(scrypt);
|
|
98503
99590
|
FeishuAdapter = class {
|
|
98504
99591
|
platform = "feishu";
|
|
@@ -98519,10 +99606,10 @@ var init_adapter = __esm({
|
|
|
98519
99606
|
const port = this.config.webhookPort ?? 9e3;
|
|
98520
99607
|
this.server = createServer3((req, res) => this.handleWebhook(req, res));
|
|
98521
99608
|
this.server.listen(port, () => {
|
|
98522
|
-
|
|
99609
|
+
log80.info(`Feishu webhook server listening on port ${port}`);
|
|
98523
99610
|
});
|
|
98524
99611
|
this.connected = true;
|
|
98525
|
-
|
|
99612
|
+
log80.info("Feishu adapter connected");
|
|
98526
99613
|
}
|
|
98527
99614
|
async disconnect() {
|
|
98528
99615
|
if (this.server) {
|
|
@@ -98530,7 +99617,7 @@ var init_adapter = __esm({
|
|
|
98530
99617
|
this.server = void 0;
|
|
98531
99618
|
}
|
|
98532
99619
|
this.connected = false;
|
|
98533
|
-
|
|
99620
|
+
log80.info("Feishu adapter disconnected");
|
|
98534
99621
|
}
|
|
98535
99622
|
async sendMessage(channelId, content, options) {
|
|
98536
99623
|
if (!this.client)
|
|
@@ -98606,12 +99693,12 @@ var init_adapter = __esm({
|
|
|
98606
99693
|
res.end("ok");
|
|
98607
99694
|
if (event.header?.event_type === "im.message.receive_v1") {
|
|
98608
99695
|
this.processMessageEvent(event).catch((err) => {
|
|
98609
|
-
|
|
99696
|
+
log80.error("Failed to process Feishu message event", { error: err.message });
|
|
98610
99697
|
});
|
|
98611
99698
|
}
|
|
98612
99699
|
if (event["action"]) {
|
|
98613
99700
|
this.processCardAction(event).catch((err) => {
|
|
98614
|
-
|
|
99701
|
+
log80.error("Failed to process card action", { error: err.message });
|
|
98615
99702
|
});
|
|
98616
99703
|
}
|
|
98617
99704
|
};
|
|
@@ -98622,14 +99709,14 @@ var init_adapter = __esm({
|
|
|
98622
99709
|
const event = JSON.parse(decrypted);
|
|
98623
99710
|
processEvent(event);
|
|
98624
99711
|
} else if (raw.encrypt && !this.config?.encryptKey) {
|
|
98625
|
-
|
|
99712
|
+
log80.warn("Received encrypted Feishu payload but no encryptKey configured");
|
|
98626
99713
|
res.writeHead(200);
|
|
98627
99714
|
res.end("ok");
|
|
98628
99715
|
} else {
|
|
98629
99716
|
processEvent(raw);
|
|
98630
99717
|
}
|
|
98631
99718
|
} catch (err) {
|
|
98632
|
-
|
|
99719
|
+
log80.error("Failed to process Feishu webhook", { error: err instanceof Error ? err.message : String(err) });
|
|
98633
99720
|
res.writeHead(400);
|
|
98634
99721
|
res.end("bad request");
|
|
98635
99722
|
}
|
|
@@ -98674,7 +99761,7 @@ var init_adapter = __esm({
|
|
|
98674
99761
|
try {
|
|
98675
99762
|
await handler4(message);
|
|
98676
99763
|
} catch (error) {
|
|
98677
|
-
|
|
99764
|
+
log80.error("Message handler failed", { error });
|
|
98678
99765
|
}
|
|
98679
99766
|
}
|
|
98680
99767
|
}
|
|
@@ -98709,7 +99796,7 @@ var init_adapter = __esm({
|
|
|
98709
99796
|
try {
|
|
98710
99797
|
await handler4(message);
|
|
98711
99798
|
} catch (error) {
|
|
98712
|
-
|
|
99799
|
+
log80.error("Card action handler failed", { error });
|
|
98713
99800
|
}
|
|
98714
99801
|
}
|
|
98715
99802
|
}
|
|
@@ -98726,12 +99813,12 @@ var init_cards = __esm({
|
|
|
98726
99813
|
|
|
98727
99814
|
// ../comms/dist/webui/adapter.js
|
|
98728
99815
|
import { createServer as createServer4 } from "node:http";
|
|
98729
|
-
var
|
|
99816
|
+
var log81, WebUIAdapter;
|
|
98730
99817
|
var init_adapter2 = __esm({
|
|
98731
99818
|
"../comms/dist/webui/adapter.js"() {
|
|
98732
99819
|
"use strict";
|
|
98733
99820
|
init_dist();
|
|
98734
|
-
|
|
99821
|
+
log81 = createLogger("webui-adapter");
|
|
98735
99822
|
WebUIAdapter = class {
|
|
98736
99823
|
platform = "webui";
|
|
98737
99824
|
handlers = [];
|
|
@@ -98743,7 +99830,7 @@ var init_adapter2 = __esm({
|
|
|
98743
99830
|
this.port = config["port"] ?? 8058;
|
|
98744
99831
|
this.server = createServer4((req, res) => this.handleRequest(req, res));
|
|
98745
99832
|
this.server.listen(this.port, "0.0.0.0", () => {
|
|
98746
|
-
|
|
99833
|
+
log81.info(`WebUI comm server listening on 0.0.0.0:${this.port}`);
|
|
98747
99834
|
});
|
|
98748
99835
|
this.connected = true;
|
|
98749
99836
|
}
|
|
@@ -98816,7 +99903,7 @@ var init_adapter2 = __esm({
|
|
|
98816
99903
|
res.end(JSON.stringify({ received: true, messageId: message.id }));
|
|
98817
99904
|
for (const handler4 of this.handlers) {
|
|
98818
99905
|
handler4(message).catch((err) => {
|
|
98819
|
-
|
|
99906
|
+
log81.error("WebUI message handler failed", { error: String(err) });
|
|
98820
99907
|
});
|
|
98821
99908
|
}
|
|
98822
99909
|
} catch (error) {
|
|
@@ -98830,87 +99917,87 @@ var init_adapter2 = __esm({
|
|
|
98830
99917
|
});
|
|
98831
99918
|
|
|
98832
99919
|
// ../comms/dist/whatsapp/client.js
|
|
98833
|
-
var
|
|
99920
|
+
var log82;
|
|
98834
99921
|
var init_client2 = __esm({
|
|
98835
99922
|
"../comms/dist/whatsapp/client.js"() {
|
|
98836
99923
|
"use strict";
|
|
98837
99924
|
init_dist();
|
|
98838
|
-
|
|
99925
|
+
log82 = createLogger("whatsapp-client");
|
|
98839
99926
|
}
|
|
98840
99927
|
});
|
|
98841
99928
|
|
|
98842
99929
|
// ../comms/dist/whatsapp/adapter.js
|
|
98843
|
-
var
|
|
99930
|
+
var log83;
|
|
98844
99931
|
var init_adapter3 = __esm({
|
|
98845
99932
|
"../comms/dist/whatsapp/adapter.js"() {
|
|
98846
99933
|
"use strict";
|
|
98847
99934
|
init_dist();
|
|
98848
99935
|
init_client2();
|
|
98849
|
-
|
|
99936
|
+
log83 = createLogger("whatsapp-adapter");
|
|
98850
99937
|
}
|
|
98851
99938
|
});
|
|
98852
99939
|
|
|
98853
99940
|
// ../comms/dist/slack/client.js
|
|
98854
|
-
var
|
|
99941
|
+
var log84;
|
|
98855
99942
|
var init_client3 = __esm({
|
|
98856
99943
|
"../comms/dist/slack/client.js"() {
|
|
98857
99944
|
"use strict";
|
|
98858
99945
|
init_dist();
|
|
98859
|
-
|
|
99946
|
+
log84 = createLogger("slack-client");
|
|
98860
99947
|
}
|
|
98861
99948
|
});
|
|
98862
99949
|
|
|
98863
99950
|
// ../comms/dist/slack/adapter.js
|
|
98864
|
-
var
|
|
99951
|
+
var log85;
|
|
98865
99952
|
var init_adapter4 = __esm({
|
|
98866
99953
|
"../comms/dist/slack/adapter.js"() {
|
|
98867
99954
|
"use strict";
|
|
98868
99955
|
init_dist();
|
|
98869
99956
|
init_client3();
|
|
98870
|
-
|
|
99957
|
+
log85 = createLogger("slack-adapter");
|
|
98871
99958
|
}
|
|
98872
99959
|
});
|
|
98873
99960
|
|
|
98874
99961
|
// ../comms/dist/telegram/client.js
|
|
98875
|
-
var
|
|
99962
|
+
var log86;
|
|
98876
99963
|
var init_client4 = __esm({
|
|
98877
99964
|
"../comms/dist/telegram/client.js"() {
|
|
98878
99965
|
"use strict";
|
|
98879
99966
|
init_dist();
|
|
98880
|
-
|
|
99967
|
+
log86 = createLogger("telegram-client");
|
|
98881
99968
|
}
|
|
98882
99969
|
});
|
|
98883
99970
|
|
|
98884
99971
|
// ../comms/dist/telegram/adapter.js
|
|
98885
|
-
var
|
|
99972
|
+
var log87;
|
|
98886
99973
|
var init_adapter5 = __esm({
|
|
98887
99974
|
"../comms/dist/telegram/adapter.js"() {
|
|
98888
99975
|
"use strict";
|
|
98889
99976
|
init_dist();
|
|
98890
99977
|
init_client4();
|
|
98891
|
-
|
|
99978
|
+
log87 = createLogger("telegram-adapter");
|
|
98892
99979
|
}
|
|
98893
99980
|
});
|
|
98894
99981
|
|
|
98895
99982
|
// ../comms/dist/router.js
|
|
98896
|
-
var
|
|
99983
|
+
var log88, MessageRouter;
|
|
98897
99984
|
var init_router2 = __esm({
|
|
98898
99985
|
"../comms/dist/router.js"() {
|
|
98899
99986
|
"use strict";
|
|
98900
99987
|
init_dist();
|
|
98901
|
-
|
|
99988
|
+
log88 = createLogger("message-router");
|
|
98902
99989
|
MessageRouter = class {
|
|
98903
99990
|
adapters = /* @__PURE__ */ new Map();
|
|
98904
99991
|
agentChannelMap = /* @__PURE__ */ new Map();
|
|
98905
99992
|
agentHandler;
|
|
98906
99993
|
registerAdapter(adapter2) {
|
|
98907
99994
|
this.adapters.set(adapter2.platform, adapter2);
|
|
98908
|
-
|
|
99995
|
+
log88.info(`Registered comm adapter: ${adapter2.platform}`);
|
|
98909
99996
|
}
|
|
98910
|
-
bindAgentToChannel(agentId2,
|
|
98911
|
-
const key2 = `${
|
|
99997
|
+
bindAgentToChannel(agentId2, platform5, channelId) {
|
|
99998
|
+
const key2 = `${platform5}:${channelId}`;
|
|
98912
99999
|
this.agentChannelMap.set(key2, agentId2);
|
|
98913
|
-
|
|
100000
|
+
log88.info(`Bound agent ${agentId2} to ${key2}`);
|
|
98914
100001
|
}
|
|
98915
100002
|
setAgentHandler(handler4) {
|
|
98916
100003
|
this.agentHandler = handler4;
|
|
@@ -98919,7 +100006,7 @@ var init_router2 = __esm({
|
|
|
98919
100006
|
for (const config of configs) {
|
|
98920
100007
|
const adapter2 = this.adapters.get(config.platform);
|
|
98921
100008
|
if (!adapter2) {
|
|
98922
|
-
|
|
100009
|
+
log88.warn(`No adapter registered for platform: ${config.platform}`);
|
|
98923
100010
|
continue;
|
|
98924
100011
|
}
|
|
98925
100012
|
await adapter2.connect(config);
|
|
@@ -98935,22 +100022,22 @@ var init_router2 = __esm({
|
|
|
98935
100022
|
}
|
|
98936
100023
|
}
|
|
98937
100024
|
}
|
|
98938
|
-
async sendToChannel(
|
|
98939
|
-
const adapter2 = this.adapters.get(
|
|
100025
|
+
async sendToChannel(platform5, channelId, content) {
|
|
100026
|
+
const adapter2 = this.adapters.get(platform5);
|
|
98940
100027
|
if (!adapter2 || !adapter2.isConnected()) {
|
|
98941
|
-
|
|
100028
|
+
log88.warn(`Adapter not available for platform: ${platform5}`);
|
|
98942
100029
|
return void 0;
|
|
98943
100030
|
}
|
|
98944
100031
|
return adapter2.sendMessage(channelId, content);
|
|
98945
100032
|
}
|
|
98946
|
-
async sendAsAgent(agentId2,
|
|
98947
|
-
return this.sendToChannel(
|
|
100033
|
+
async sendAsAgent(agentId2, platform5, channelId, content) {
|
|
100034
|
+
return this.sendToChannel(platform5, channelId, content);
|
|
98948
100035
|
}
|
|
98949
100036
|
async routeIncomingMessage(message) {
|
|
98950
100037
|
const key2 = `${message.platform}:${message.channelId}`;
|
|
98951
100038
|
const agentId2 = message.agentId || this.agentChannelMap.get(key2);
|
|
98952
100039
|
if (!agentId2) {
|
|
98953
|
-
|
|
100040
|
+
log88.debug("No agent bound to channel, skipping message", { key: key2 });
|
|
98954
100041
|
return;
|
|
98955
100042
|
}
|
|
98956
100043
|
message.agentId = agentId2;
|
|
@@ -98966,7 +100053,7 @@ var init_router2 = __esm({
|
|
|
98966
100053
|
}
|
|
98967
100054
|
}
|
|
98968
100055
|
} catch (error) {
|
|
98969
|
-
|
|
100056
|
+
log88.error("Agent handler failed", { agentId: agentId2, error: String(error) });
|
|
98970
100057
|
}
|
|
98971
100058
|
}
|
|
98972
100059
|
}
|
|
@@ -98993,17 +100080,17 @@ var init_dist7 = __esm({
|
|
|
98993
100080
|
});
|
|
98994
100081
|
|
|
98995
100082
|
// src/utils/logger.ts
|
|
98996
|
-
import { createWriteStream as createWriteStream2, existsSync as
|
|
98997
|
-
import { join as
|
|
98998
|
-
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";
|
|
98999
100086
|
function ensureLogDir2() {
|
|
99000
|
-
if (!
|
|
99001
|
-
|
|
100087
|
+
if (!existsSync35(LOG_DIR2)) {
|
|
100088
|
+
mkdirSync26(LOG_DIR2, { recursive: true, mode: 493 });
|
|
99002
100089
|
}
|
|
99003
100090
|
}
|
|
99004
100091
|
function getStartupLogPath() {
|
|
99005
100092
|
const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
99006
|
-
return
|
|
100093
|
+
return join31(LOG_DIR2, `startup-${date}.log`);
|
|
99007
100094
|
}
|
|
99008
100095
|
function setSuppressConsole(suppress) {
|
|
99009
100096
|
_suppressConsole = suppress;
|
|
@@ -99058,7 +100145,7 @@ var LOG_DIR2, startupLogStream, startupLogPath, _suppressConsole, LEVEL_PREFIX;
|
|
|
99058
100145
|
var init_logger2 = __esm({
|
|
99059
100146
|
"src/utils/logger.ts"() {
|
|
99060
100147
|
"use strict";
|
|
99061
|
-
LOG_DIR2 =
|
|
100148
|
+
LOG_DIR2 = join31(homedir20(), ".markus", "logs");
|
|
99062
100149
|
startupLogStream = null;
|
|
99063
100150
|
startupLogPath = "";
|
|
99064
100151
|
_suppressConsole = false;
|
|
@@ -99076,10 +100163,10 @@ var init_logger2 = __esm({
|
|
|
99076
100163
|
// src/utils/browser.ts
|
|
99077
100164
|
import { exec } from "node:child_process";
|
|
99078
100165
|
import { get as httpGet } from "node:http";
|
|
99079
|
-
import { platform as
|
|
100166
|
+
import { platform as platform4 } from "node:os";
|
|
99080
100167
|
function openBrowser(url) {
|
|
99081
100168
|
if (process.env["NO_BROWSER"]) return;
|
|
99082
|
-
const sys =
|
|
100169
|
+
const sys = platform4();
|
|
99083
100170
|
const cmd = sys === "darwin" ? `open "${url}"` : sys === "win32" ? `start "" "${url}"` : `xdg-open "${url}"`;
|
|
99084
100171
|
exec(cmd, (err) => {
|
|
99085
100172
|
if (err) {
|
|
@@ -99114,9 +100201,9 @@ var init_browser = __esm({
|
|
|
99114
100201
|
});
|
|
99115
100202
|
|
|
99116
100203
|
// src/utils/startupProgress.ts
|
|
99117
|
-
import { homedir as
|
|
99118
|
-
import { appendFileSync as appendFileSync4, existsSync as
|
|
99119
|
-
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";
|
|
99120
100207
|
function clearScreen() {
|
|
99121
100208
|
return "\x1B[2J\x1B[H";
|
|
99122
100209
|
}
|
|
@@ -99278,8 +100365,8 @@ var init_startupProgress = __esm({
|
|
|
99278
100365
|
const line = `${ts} ${msg}
|
|
99279
100366
|
`;
|
|
99280
100367
|
try {
|
|
99281
|
-
const dir =
|
|
99282
|
-
if (!
|
|
100368
|
+
const dir = join32(homedir21(), ".markus", "logs");
|
|
100369
|
+
if (!existsSync36(dir)) mkdirSync27(dir, { recursive: true, mode: 493 });
|
|
99283
100370
|
appendFileSync4(this.logPath, line, { mode: 420 });
|
|
99284
100371
|
} catch {
|
|
99285
100372
|
}
|
|
@@ -99388,13 +100475,13 @@ var init_startupProgress = __esm({
|
|
|
99388
100475
|
});
|
|
99389
100476
|
|
|
99390
100477
|
// src/connector-service.ts
|
|
99391
|
-
import { resolve as resolve16, join as
|
|
99392
|
-
import { existsSync as
|
|
99393
|
-
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";
|
|
99394
100481
|
import { execSync as execSync4 } from "node:child_process";
|
|
99395
100482
|
import { fileURLToPath as fileURLToPath6 } from "node:url";
|
|
99396
100483
|
function expandHome(p) {
|
|
99397
|
-
return p.replace(/^~/,
|
|
100484
|
+
return p.replace(/^~/, homedir22());
|
|
99398
100485
|
}
|
|
99399
100486
|
function loadConnectors() {
|
|
99400
100487
|
const connectors = /* @__PURE__ */ new Map();
|
|
@@ -99402,16 +100489,16 @@ function loadConnectors() {
|
|
|
99402
100489
|
loadFromDir(builtinDir, connectors);
|
|
99403
100490
|
const devDir = resolve16(process.cwd(), "packages", "cli", "connectors");
|
|
99404
100491
|
if (devDir !== builtinDir) loadFromDir(devDir, connectors);
|
|
99405
|
-
const userDir =
|
|
100492
|
+
const userDir = join33(homedir22(), ".markus", "connectors");
|
|
99406
100493
|
loadFromDir(userDir, connectors);
|
|
99407
100494
|
return [...connectors.values()].filter((c) => c.platform !== "_template");
|
|
99408
100495
|
}
|
|
99409
100496
|
function loadFromDir(dir, map) {
|
|
99410
|
-
if (!
|
|
100497
|
+
if (!existsSync37(dir)) return;
|
|
99411
100498
|
for (const file of readdirSync13(dir)) {
|
|
99412
100499
|
if (!file.endsWith(".json") || file.startsWith("_")) continue;
|
|
99413
100500
|
try {
|
|
99414
|
-
const raw =
|
|
100501
|
+
const raw = readFileSync26(join33(dir, file), "utf-8");
|
|
99415
100502
|
const desc = JSON.parse(raw);
|
|
99416
100503
|
if (desc.platform) {
|
|
99417
100504
|
map.set(desc.platform, desc);
|
|
@@ -99420,8 +100507,8 @@ function loadFromDir(dir, map) {
|
|
|
99420
100507
|
}
|
|
99421
100508
|
}
|
|
99422
100509
|
}
|
|
99423
|
-
function findConnector(
|
|
99424
|
-
return loadConnectors().find((c) => c.platform ===
|
|
100510
|
+
function findConnector(platform5) {
|
|
100511
|
+
return loadConnectors().find((c) => c.platform === platform5);
|
|
99425
100512
|
}
|
|
99426
100513
|
function scanInstalledPlatforms() {
|
|
99427
100514
|
const connectors = loadConnectors();
|
|
@@ -99436,7 +100523,7 @@ function scanInstalledPlatforms() {
|
|
|
99436
100523
|
};
|
|
99437
100524
|
for (const p of c.detection.configPaths) {
|
|
99438
100525
|
const expanded = expandHome(p);
|
|
99439
|
-
if (
|
|
100526
|
+
if (existsSync37(expanded)) {
|
|
99440
100527
|
result.installed = true;
|
|
99441
100528
|
result.configPath = expanded;
|
|
99442
100529
|
break;
|
|
@@ -99463,9 +100550,9 @@ function scanInstalledPlatforms() {
|
|
|
99463
100550
|
}
|
|
99464
100551
|
function readPlatformConfig(connector) {
|
|
99465
100552
|
const configPath = expandHome(connector.integration.configPath);
|
|
99466
|
-
if (!
|
|
100553
|
+
if (!existsSync37(configPath)) return null;
|
|
99467
100554
|
try {
|
|
99468
|
-
const raw =
|
|
100555
|
+
const raw = readFileSync26(configPath, "utf-8");
|
|
99469
100556
|
if (connector.integration.configFormat === "json5") {
|
|
99470
100557
|
const cleaned = raw.replace(/\/\/.*$/gm, "").replace(/\/\*[\s\S]*?\*\//g, "").replace(/,\s*([\]}])/g, "$1");
|
|
99471
100558
|
return JSON.parse(cleaned);
|
|
@@ -99477,12 +100564,12 @@ function readPlatformConfig(connector) {
|
|
|
99477
100564
|
}
|
|
99478
100565
|
function writePlatformConfig(connector, markusUrl, token) {
|
|
99479
100566
|
const configPath = expandHome(connector.integration.configPath);
|
|
99480
|
-
const configDir =
|
|
99481
|
-
if (!
|
|
99482
|
-
|
|
100567
|
+
const configDir = dirname12(configPath);
|
|
100568
|
+
if (!existsSync37(configDir)) {
|
|
100569
|
+
mkdirSync28(configDir, { recursive: true });
|
|
99483
100570
|
}
|
|
99484
100571
|
let config = {};
|
|
99485
|
-
if (
|
|
100572
|
+
if (existsSync37(configPath)) {
|
|
99486
100573
|
const existing = readPlatformConfig(connector);
|
|
99487
100574
|
if (existing) config = existing;
|
|
99488
100575
|
}
|
|
@@ -99490,7 +100577,7 @@ function writePlatformConfig(connector, markusUrl, token) {
|
|
|
99490
100577
|
setNestedField(config, connector.integration.tokenField, token);
|
|
99491
100578
|
try {
|
|
99492
100579
|
const content = JSON.stringify(config, null, 2);
|
|
99493
|
-
|
|
100580
|
+
writeFileSync22(configPath, content, "utf-8");
|
|
99494
100581
|
return true;
|
|
99495
100582
|
} catch {
|
|
99496
100583
|
return false;
|
|
@@ -99503,21 +100590,21 @@ function installSkillTemplate(connector) {
|
|
|
99503
100590
|
const skillDir = expandHome(connector.integration.skillDir);
|
|
99504
100591
|
const templateName = connector.integration.skillTemplateName;
|
|
99505
100592
|
const candidates = [
|
|
99506
|
-
|
|
100593
|
+
join33(homedir22(), ".markus", "templates", templateName),
|
|
99507
100594
|
resolve16(process.cwd(), "templates", templateName),
|
|
99508
100595
|
resolve16(__dirname5, "..", "templates", templateName)
|
|
99509
100596
|
];
|
|
99510
100597
|
let sourceDir;
|
|
99511
100598
|
for (const c of candidates) {
|
|
99512
|
-
if (
|
|
100599
|
+
if (existsSync37(c)) {
|
|
99513
100600
|
sourceDir = c;
|
|
99514
100601
|
break;
|
|
99515
100602
|
}
|
|
99516
100603
|
}
|
|
99517
100604
|
if (!sourceDir) return false;
|
|
99518
|
-
const targetDir =
|
|
99519
|
-
if (!
|
|
99520
|
-
|
|
100605
|
+
const targetDir = join33(skillDir, templateName);
|
|
100606
|
+
if (!existsSync37(targetDir)) {
|
|
100607
|
+
mkdirSync28(targetDir, { recursive: true });
|
|
99521
100608
|
}
|
|
99522
100609
|
try {
|
|
99523
100610
|
cpSync4(sourceDir, targetDir, { recursive: true });
|
|
@@ -99559,7 +100646,7 @@ var init_connector_service = __esm({
|
|
|
99559
100646
|
"src/connector-service.ts"() {
|
|
99560
100647
|
"use strict";
|
|
99561
100648
|
__filename4 = fileURLToPath6(import.meta.url);
|
|
99562
|
-
__dirname5 =
|
|
100649
|
+
__dirname5 = dirname12(__filename4);
|
|
99563
100650
|
}
|
|
99564
100651
|
});
|
|
99565
100652
|
|
|
@@ -99570,8 +100657,8 @@ __export(init_exports, {
|
|
|
99570
100657
|
registerInitCommand: () => registerInitCommand
|
|
99571
100658
|
});
|
|
99572
100659
|
import { resolve as resolve17 } from "node:path";
|
|
99573
|
-
import { readFileSync as
|
|
99574
|
-
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";
|
|
99575
100662
|
function registerInitCommand(program2) {
|
|
99576
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) => {
|
|
99577
100664
|
await quickInit({
|
|
@@ -99586,7 +100673,7 @@ function registerInitCommand(program2) {
|
|
|
99586
100673
|
});
|
|
99587
100674
|
}
|
|
99588
100675
|
async function quickInit(options) {
|
|
99589
|
-
const { writeFileSync:
|
|
100676
|
+
const { writeFileSync: writeFileSync23, mkdirSync: mkdirSync29 } = await import("node:fs");
|
|
99590
100677
|
const { join: pathJoin } = await import("node:path");
|
|
99591
100678
|
const readline3 = await import("node:readline");
|
|
99592
100679
|
const nonInteractive = options?.nonInteractive ?? false;
|
|
@@ -99607,7 +100694,7 @@ async function quickInit(options) {
|
|
|
99607
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
|
|
99608
100695
|
`);
|
|
99609
100696
|
const configPath = getDefaultConfigPath();
|
|
99610
|
-
if (
|
|
100697
|
+
if (existsSync38(configPath) && !options?.force) {
|
|
99611
100698
|
if (nonInteractive) {
|
|
99612
100699
|
console.log(` Existing configuration found. Use --force to overwrite.`);
|
|
99613
100700
|
rl?.close();
|
|
@@ -99640,11 +100727,11 @@ async function quickInit(options) {
|
|
|
99640
100727
|
const installedPlatforms = scanInstalledPlatforms().filter((p) => p.installed);
|
|
99641
100728
|
let openclawPath = "";
|
|
99642
100729
|
const openclawCandidates = [
|
|
99643
|
-
pathJoin(
|
|
99644
|
-
pathJoin(
|
|
100730
|
+
pathJoin(homedir23(), ".openclaw", "openclaw.json"),
|
|
100731
|
+
pathJoin(homedir23(), ".openclaw", "openclaw.json5")
|
|
99645
100732
|
];
|
|
99646
100733
|
for (const p of openclawCandidates) {
|
|
99647
|
-
if (
|
|
100734
|
+
if (existsSync38(p)) {
|
|
99648
100735
|
openclawPath = p;
|
|
99649
100736
|
break;
|
|
99650
100737
|
}
|
|
@@ -99718,7 +100805,7 @@ async function quickInit(options) {
|
|
|
99718
100805
|
}
|
|
99719
100806
|
} else if (mode === "openclaw") {
|
|
99720
100807
|
try {
|
|
99721
|
-
const raw =
|
|
100808
|
+
const raw = readFileSync27(openclawPath, "utf-8");
|
|
99722
100809
|
const cleaned = raw.replace(/\/\/.*$/gm, "").replace(/\/\*[\s\S]*?\*\//g, "").replace(/,\s*([\]}])/g, "$1");
|
|
99723
100810
|
const parsed = JSON.parse(cleaned);
|
|
99724
100811
|
const modelsSection = parsed.models;
|
|
@@ -99846,18 +100933,18 @@ async function quickInit(options) {
|
|
|
99846
100933
|
console.error(`
|
|
99847
100934
|
Failed to save config: ${e}`);
|
|
99848
100935
|
}
|
|
99849
|
-
const userTemplatesDir = pathJoin(
|
|
100936
|
+
const userTemplatesDir = pathJoin(homedir23(), ".markus", "templates");
|
|
99850
100937
|
const builtinTemplatesDir = resolveTemplatesDir("roles");
|
|
99851
|
-
if (builtinTemplatesDir &&
|
|
100938
|
+
if (builtinTemplatesDir && existsSync38(builtinTemplatesDir) && !existsSync38(userTemplatesDir)) {
|
|
99852
100939
|
const builtinRoot = resolve17(builtinTemplatesDir, "..");
|
|
99853
|
-
|
|
100940
|
+
mkdirSync29(userTemplatesDir, { recursive: true });
|
|
99854
100941
|
cpSync5(builtinRoot, userTemplatesDir, { recursive: true });
|
|
99855
100942
|
console.log(` Copied templates to ${userTemplatesDir}`);
|
|
99856
100943
|
}
|
|
99857
100944
|
const devRoleDir = pathJoin(userTemplatesDir || pathJoin(process.cwd(), "templates"), "roles", "developer");
|
|
99858
|
-
if (!
|
|
99859
|
-
|
|
99860
|
-
|
|
100945
|
+
if (!existsSync38(devRoleDir)) {
|
|
100946
|
+
mkdirSync29(devRoleDir, { recursive: true });
|
|
100947
|
+
writeFileSync23(
|
|
99861
100948
|
pathJoin(devRoleDir, "ROLE.md"),
|
|
99862
100949
|
[
|
|
99863
100950
|
"---",
|
|
@@ -99899,7 +100986,7 @@ async function quickInit(options) {
|
|
|
99899
100986
|
console.log("");
|
|
99900
100987
|
}
|
|
99901
100988
|
console.log(` Config: ${configPath}`);
|
|
99902
|
-
console.log(` Data: ${pathJoin(
|
|
100989
|
+
console.log(` Data: ${pathJoin(homedir23(), ".markus")}`);
|
|
99903
100990
|
console.log(` Server: http://localhost:${apiPort}`);
|
|
99904
100991
|
console.log("");
|
|
99905
100992
|
}
|
|
@@ -99937,12 +101024,12 @@ function signJwt(payload, secret) {
|
|
|
99937
101024
|
const sig = base64url(createHmac2("sha256", secret).update(`${header}.${body}`).digest());
|
|
99938
101025
|
return `${header}.${body}.${sig}`;
|
|
99939
101026
|
}
|
|
99940
|
-
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;
|
|
99941
101028
|
var init_agent3 = __esm({
|
|
99942
101029
|
"../remote/dist/agent.js"() {
|
|
99943
101030
|
"use strict";
|
|
99944
101031
|
init_dist();
|
|
99945
|
-
|
|
101032
|
+
log89 = createLogger("remote");
|
|
99946
101033
|
_rtcModule = null;
|
|
99947
101034
|
STUN_SERVERS = [
|
|
99948
101035
|
"stun:stun.l.google.com:19302",
|
|
@@ -99950,7 +101037,7 @@ var init_agent3 = __esm({
|
|
|
99950
101037
|
];
|
|
99951
101038
|
RECONNECT_BASE_MS = 2e3;
|
|
99952
101039
|
RECONNECT_MAX_MS = 6e4;
|
|
99953
|
-
|
|
101040
|
+
HEARTBEAT_INTERVAL_MS2 = 25e3;
|
|
99954
101041
|
PEER_PING_INTERVAL_MS = 15e3;
|
|
99955
101042
|
PEER_PING_TIMEOUT_MS = 1e4;
|
|
99956
101043
|
RELAY_INACTIVITY_TIMEOUT_MS = 5 * 6e4;
|
|
@@ -99971,19 +101058,19 @@ var init_agent3 = __esm({
|
|
|
99971
101058
|
// ── Public API ────────────────────────────────────────────────────────────
|
|
99972
101059
|
async start() {
|
|
99973
101060
|
this.destroyed = false;
|
|
99974
|
-
|
|
101061
|
+
log89.info("Starting remote access agent...");
|
|
99975
101062
|
const rtc = await loadRtcModule();
|
|
99976
101063
|
rtc.initLogger("Warning");
|
|
99977
101064
|
await this.discoverLocalOwner();
|
|
99978
101065
|
try {
|
|
99979
101066
|
this.registration = await this.registerInstance();
|
|
99980
|
-
|
|
101067
|
+
log89.info("Registered with Hub", {
|
|
99981
101068
|
instanceId: this.registration.instanceId,
|
|
99982
101069
|
remoteUrl: this.registration.remoteUrl
|
|
99983
101070
|
});
|
|
99984
101071
|
this.connectSignaling();
|
|
99985
101072
|
} catch (err) {
|
|
99986
|
-
|
|
101073
|
+
log89.error("Failed to register with Hub", { error: String(err) });
|
|
99987
101074
|
this.scheduleReconnect();
|
|
99988
101075
|
}
|
|
99989
101076
|
}
|
|
@@ -100004,14 +101091,14 @@ var init_agent3 = __esm({
|
|
|
100004
101091
|
if (users?.length) {
|
|
100005
101092
|
const owner = users.find((u) => u.role === "owner") ?? users[0];
|
|
100006
101093
|
this.localOwnerUserId = owner.id;
|
|
100007
|
-
|
|
101094
|
+
log89.info("Discovered local owner", { userId: this.localOwnerUserId });
|
|
100008
101095
|
}
|
|
100009
101096
|
return;
|
|
100010
101097
|
} catch (err) {
|
|
100011
101098
|
if (attempt < 2) {
|
|
100012
101099
|
await new Promise((r) => setTimeout(r, 1e3 * (attempt + 1)));
|
|
100013
101100
|
} else {
|
|
100014
|
-
|
|
101101
|
+
log89.warn("Failed to discover local owner, using synthetic user", { error: String(err) });
|
|
100015
101102
|
}
|
|
100016
101103
|
}
|
|
100017
101104
|
}
|
|
@@ -100043,7 +101130,7 @@ var init_agent3 = __esm({
|
|
|
100043
101130
|
this.registration = null;
|
|
100044
101131
|
}
|
|
100045
101132
|
this.emitStatus();
|
|
100046
|
-
|
|
101133
|
+
log89.info("Remote access agent stopped");
|
|
100047
101134
|
}
|
|
100048
101135
|
getStatus() {
|
|
100049
101136
|
const wsOpen = this.ws?.readyState === WebSocket2.OPEN;
|
|
@@ -100152,11 +101239,11 @@ var init_agent3 = __esm({
|
|
|
100152
101239
|
return;
|
|
100153
101240
|
const { signalUrl, signalingToken } = this.registration;
|
|
100154
101241
|
const wsUrl = `${signalUrl}?token=${encodeURIComponent(signalingToken)}`;
|
|
100155
|
-
|
|
101242
|
+
log89.info("Connecting to signal server...", { signalUrl });
|
|
100156
101243
|
const ws = new WebSocket2(wsUrl);
|
|
100157
101244
|
this.ws = ws;
|
|
100158
101245
|
ws.on("open", () => {
|
|
100159
|
-
|
|
101246
|
+
log89.info("Signal server connected");
|
|
100160
101247
|
this.reconnectAttempts = 0;
|
|
100161
101248
|
this.startHeartbeat();
|
|
100162
101249
|
this.emitStatus();
|
|
@@ -100167,11 +101254,11 @@ var init_agent3 = __esm({
|
|
|
100167
101254
|
const msg = JSON.parse(data.toString());
|
|
100168
101255
|
this.handleSignalingMessage(msg);
|
|
100169
101256
|
} catch (err) {
|
|
100170
|
-
|
|
101257
|
+
log89.warn("Invalid signaling message", { error: String(err) });
|
|
100171
101258
|
}
|
|
100172
101259
|
});
|
|
100173
101260
|
ws.on("close", (code) => {
|
|
100174
|
-
|
|
101261
|
+
log89.warn("Signal server disconnected", { code });
|
|
100175
101262
|
this.stopHeartbeat();
|
|
100176
101263
|
this.ws = null;
|
|
100177
101264
|
this.emitStatus();
|
|
@@ -100179,7 +101266,7 @@ var init_agent3 = __esm({
|
|
|
100179
101266
|
this.scheduleReconnect();
|
|
100180
101267
|
});
|
|
100181
101268
|
ws.on("error", (err) => {
|
|
100182
|
-
|
|
101269
|
+
log89.error("Signal server error", { error: err.message });
|
|
100183
101270
|
});
|
|
100184
101271
|
}
|
|
100185
101272
|
handleSignalingMessage(msg) {
|
|
@@ -100190,7 +101277,7 @@ var init_agent3 = __esm({
|
|
|
100190
101277
|
this.send({ type: "pong" });
|
|
100191
101278
|
break;
|
|
100192
101279
|
case "registered":
|
|
100193
|
-
|
|
101280
|
+
log89.info("Registered with signal server", { instanceId: msg["instanceId"] });
|
|
100194
101281
|
break;
|
|
100195
101282
|
case "peer_request":
|
|
100196
101283
|
if (peerId)
|
|
@@ -100212,7 +101299,7 @@ var init_agent3 = __esm({
|
|
|
100212
101299
|
break;
|
|
100213
101300
|
case "relay_activated":
|
|
100214
101301
|
if (peerId)
|
|
100215
|
-
|
|
101302
|
+
log89.info("Peer activated relay mode", { peerId });
|
|
100216
101303
|
break;
|
|
100217
101304
|
case "relay_frame":
|
|
100218
101305
|
if (peerId && msg["data"]) {
|
|
@@ -100220,21 +101307,21 @@ var init_agent3 = __esm({
|
|
|
100220
101307
|
}
|
|
100221
101308
|
break;
|
|
100222
101309
|
default:
|
|
100223
|
-
|
|
101310
|
+
log89.debug("Unknown signaling message type", { type });
|
|
100224
101311
|
}
|
|
100225
101312
|
}
|
|
100226
101313
|
// ── WebRTC Peer Connections ───────────────────────────────────────────────
|
|
100227
101314
|
handlePeerRequest(peerId) {
|
|
100228
|
-
|
|
101315
|
+
log89.info("Peer connection requested", { peerId });
|
|
100229
101316
|
this.createPeerConnection(peerId);
|
|
100230
101317
|
}
|
|
100231
101318
|
handleOffer(peerId, sdp) {
|
|
100232
101319
|
let session = this.peers.get(peerId);
|
|
100233
101320
|
if (!session) {
|
|
100234
|
-
|
|
101321
|
+
log89.info("Received offer, creating new peer connection", { peerId });
|
|
100235
101322
|
session = this.createPeerConnection(peerId);
|
|
100236
101323
|
} else if (!session.pc) {
|
|
100237
|
-
|
|
101324
|
+
log89.info("Received offer for relay-only peer, upgrading to P2P", { peerId });
|
|
100238
101325
|
const newSession = this.createPeerConnection(peerId);
|
|
100239
101326
|
newSession.markusToken = session.markusToken;
|
|
100240
101327
|
newSession.connectedAt = session.connectedAt;
|
|
@@ -100243,14 +101330,14 @@ var init_agent3 = __esm({
|
|
|
100243
101330
|
clearInterval(session.pingTimer);
|
|
100244
101331
|
session = newSession;
|
|
100245
101332
|
} else {
|
|
100246
|
-
|
|
101333
|
+
log89.info("Received offer for existing peer (ICE restart)", { peerId });
|
|
100247
101334
|
}
|
|
100248
101335
|
session.pc.setRemoteDescription(sdp, getRtcModule().DescriptionType.Offer);
|
|
100249
101336
|
}
|
|
100250
101337
|
handleIce(peerId, candidate, mid) {
|
|
100251
101338
|
const session = this.peers.get(peerId);
|
|
100252
101339
|
if (!session?.pc) {
|
|
100253
|
-
|
|
101340
|
+
log89.warn("Received ICE candidate but no PC", { peerId, hasSession: !!session });
|
|
100254
101341
|
return;
|
|
100255
101342
|
}
|
|
100256
101343
|
session.pc.addRemoteCandidate(candidate, mid ?? "0");
|
|
@@ -100289,25 +101376,25 @@ var init_agent3 = __esm({
|
|
|
100289
101376
|
const session = { pc, dc: null, pendingChunks: /* @__PURE__ */ new Map(), markusToken: null, connectedAt: now3, lastActiveAt: now3, pingTimer: null, lastPong: now3 };
|
|
100290
101377
|
this.peers.set(peerId, session);
|
|
100291
101378
|
pc.onStateChange((state) => {
|
|
100292
|
-
|
|
101379
|
+
log89.info("Peer RTC state", { peerId, state });
|
|
100293
101380
|
if (state === "failed" || state === "closed") {
|
|
100294
101381
|
this.handlePcFailed(peerId);
|
|
100295
101382
|
}
|
|
100296
101383
|
this.emitStatus();
|
|
100297
101384
|
});
|
|
100298
101385
|
pc.onGatheringStateChange((state) => {
|
|
100299
|
-
|
|
101386
|
+
log89.info("ICE gathering", { peerId, state });
|
|
100300
101387
|
});
|
|
100301
101388
|
pc.onLocalDescription((sdp, type) => {
|
|
100302
|
-
|
|
101389
|
+
log89.info("Sending local description", { peerId, type });
|
|
100303
101390
|
this.send({ type, peerId, sdp });
|
|
100304
101391
|
});
|
|
100305
101392
|
pc.onLocalCandidate((candidate, mid) => {
|
|
100306
|
-
|
|
101393
|
+
log89.info("Sending ICE candidate", { peerId, candidate: candidate.slice(0, 60) });
|
|
100307
101394
|
this.send({ type: "ice", peerId, candidate, mid });
|
|
100308
101395
|
});
|
|
100309
101396
|
pc.onDataChannel((dc) => {
|
|
100310
|
-
|
|
101397
|
+
log89.info("DataChannel opened", { peerId, label: dc.getLabel() });
|
|
100311
101398
|
session.dc = dc;
|
|
100312
101399
|
session.lastPong = Date.now();
|
|
100313
101400
|
this.emitStatus();
|
|
@@ -100317,7 +101404,7 @@ var init_agent3 = __esm({
|
|
|
100317
101404
|
this.handleDataChannelMessage(peerId, data);
|
|
100318
101405
|
});
|
|
100319
101406
|
dc.onClosed(() => {
|
|
100320
|
-
|
|
101407
|
+
log89.info("DataChannel closed, keeping session for relay", { peerId });
|
|
100321
101408
|
session.dc = null;
|
|
100322
101409
|
this.emitStatus();
|
|
100323
101410
|
});
|
|
@@ -100328,7 +101415,7 @@ var init_agent3 = __esm({
|
|
|
100328
101415
|
const session = this.peers.get(peerId);
|
|
100329
101416
|
if (!session)
|
|
100330
101417
|
return;
|
|
100331
|
-
|
|
101418
|
+
log89.info("WebRTC failed, keeping session alive for relay", { peerId });
|
|
100332
101419
|
try {
|
|
100333
101420
|
session.dc?.close();
|
|
100334
101421
|
} catch {
|
|
@@ -100362,7 +101449,7 @@ var init_agent3 = __esm({
|
|
|
100362
101449
|
}
|
|
100363
101450
|
this.peers.delete(peerId);
|
|
100364
101451
|
this.emitStatus();
|
|
100365
|
-
|
|
101452
|
+
log89.info("Peer cleaned up", { peerId });
|
|
100366
101453
|
}
|
|
100367
101454
|
startPeerPing(peerId, session) {
|
|
100368
101455
|
if (session.pingTimer)
|
|
@@ -100372,13 +101459,13 @@ var init_agent3 = __esm({
|
|
|
100372
101459
|
session.pingTimer = setInterval(() => {
|
|
100373
101460
|
const now3 = Date.now();
|
|
100374
101461
|
if (now3 - session.lastActiveAt > RELAY_INACTIVITY_TIMEOUT_MS) {
|
|
100375
|
-
|
|
101462
|
+
log89.info("Peer inactive for too long, cleaning up", { peerId });
|
|
100376
101463
|
this.cleanupPeer(peerId);
|
|
100377
101464
|
return;
|
|
100378
101465
|
}
|
|
100379
101466
|
const elapsed = now3 - session.lastPong;
|
|
100380
101467
|
if (elapsed > PEER_PING_INTERVAL_MS + PEER_PING_TIMEOUT_MS) {
|
|
100381
|
-
|
|
101468
|
+
log89.warn("Peer ping timeout, unresponsive", { peerId, elapsed });
|
|
100382
101469
|
this.cleanupPeer(peerId);
|
|
100383
101470
|
return;
|
|
100384
101471
|
}
|
|
@@ -100419,12 +101506,12 @@ var init_agent3 = __esm({
|
|
|
100419
101506
|
this.sendToPeer(peerId, { type: "error", error: `Unknown message type: ${type}` });
|
|
100420
101507
|
}
|
|
100421
101508
|
} catch (err) {
|
|
100422
|
-
|
|
101509
|
+
log89.warn("Invalid DataChannel message", { peerId, error: String(err) });
|
|
100423
101510
|
}
|
|
100424
101511
|
}
|
|
100425
101512
|
handleRelayFrame(peerId, data) {
|
|
100426
101513
|
if (!this.peers.has(peerId)) {
|
|
100427
|
-
|
|
101514
|
+
log89.info("Relay frame from unknown peer, creating relay-only session", { peerId });
|
|
100428
101515
|
const now3 = Date.now();
|
|
100429
101516
|
this.peers.set(peerId, {
|
|
100430
101517
|
pc: null,
|
|
@@ -100618,14 +101705,14 @@ var init_agent3 = __esm({
|
|
|
100618
101705
|
session.dc.sendMessage(data);
|
|
100619
101706
|
return;
|
|
100620
101707
|
} catch (err) {
|
|
100621
|
-
|
|
101708
|
+
log89.warn("DataChannel send failed, falling back to relay", { peerId, error: String(err) });
|
|
100622
101709
|
}
|
|
100623
101710
|
}
|
|
100624
101711
|
if (this.ws?.readyState === WebSocket2.OPEN) {
|
|
100625
101712
|
this.send({ type: "relay_frame", peerId, data });
|
|
100626
101713
|
return;
|
|
100627
101714
|
}
|
|
100628
|
-
|
|
101715
|
+
log89.warn("No transport available for peer", { peerId });
|
|
100629
101716
|
}
|
|
100630
101717
|
send(msg) {
|
|
100631
101718
|
if (this.ws?.readyState === WebSocket2.OPEN) {
|
|
@@ -100636,7 +101723,7 @@ var init_agent3 = __esm({
|
|
|
100636
101723
|
this.stopHeartbeat();
|
|
100637
101724
|
this.heartbeatTimer = setInterval(() => {
|
|
100638
101725
|
this.send({ type: "pong" });
|
|
100639
|
-
},
|
|
101726
|
+
}, HEARTBEAT_INTERVAL_MS2);
|
|
100640
101727
|
}
|
|
100641
101728
|
stopHeartbeat() {
|
|
100642
101729
|
if (this.heartbeatTimer) {
|
|
@@ -100649,7 +101736,7 @@ var init_agent3 = __esm({
|
|
|
100649
101736
|
return;
|
|
100650
101737
|
const delay = Math.min(RECONNECT_BASE_MS * Math.pow(2, this.reconnectAttempts), RECONNECT_MAX_MS);
|
|
100651
101738
|
this.reconnectAttempts++;
|
|
100652
|
-
|
|
101739
|
+
log89.info(`Reconnecting in ${delay}ms (attempt ${this.reconnectAttempts})...`);
|
|
100653
101740
|
this.reconnectTimer = setTimeout(() => this.start(), delay);
|
|
100654
101741
|
}
|
|
100655
101742
|
emitStatus() {
|
|
@@ -100682,15 +101769,15 @@ var start_exports = {};
|
|
|
100682
101769
|
__export(start_exports, {
|
|
100683
101770
|
registerStartCommand: () => registerStartCommand
|
|
100684
101771
|
});
|
|
100685
|
-
import { resolve as resolve18, join as
|
|
100686
|
-
import { existsSync as
|
|
100687
|
-
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";
|
|
100688
101775
|
function registerStartCommand(program2) {
|
|
100689
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) => {
|
|
100690
101777
|
const globalOpts = program2.optsWithGlobals();
|
|
100691
101778
|
const configPath = globalOpts.config ?? getDefaultConfigPath();
|
|
100692
|
-
if (opts.setup || !
|
|
100693
|
-
if (!
|
|
101779
|
+
if (opts.setup || !existsSync39(configPath)) {
|
|
101780
|
+
if (!existsSync39(configPath)) {
|
|
100694
101781
|
console.log(" No configuration found \u2014 auto-configuring from environment...\n");
|
|
100695
101782
|
}
|
|
100696
101783
|
const { quickInit: quickInit2 } = await Promise.resolve().then(() => (init_init(), init_exports));
|
|
@@ -100819,8 +101906,8 @@ async function createServices(config) {
|
|
|
100819
101906
|
extraSkillDirs: skillDirs
|
|
100820
101907
|
});
|
|
100821
101908
|
const storage = await initStorage(config.database?.url);
|
|
100822
|
-
const markusDataDir =
|
|
100823
|
-
const sharedDataDir =
|
|
101909
|
+
const markusDataDir = join34(homedir24(), ".markus");
|
|
101910
|
+
const sharedDataDir = join34(markusDataDir, "shared");
|
|
100824
101911
|
const taskService = new TaskService();
|
|
100825
101912
|
taskService.setSharedDataDir(sharedDataDir);
|
|
100826
101913
|
if (storage) {
|
|
@@ -100852,7 +101939,7 @@ async function createServices(config) {
|
|
|
100852
101939
|
const agentManager = new AgentManager({
|
|
100853
101940
|
llmRouter,
|
|
100854
101941
|
roleLoader,
|
|
100855
|
-
dataDir:
|
|
101942
|
+
dataDir: join34(markusDataDir, "agents"),
|
|
100856
101943
|
sharedDataDir,
|
|
100857
101944
|
skillRegistry,
|
|
100858
101945
|
taskService,
|
|
@@ -100892,8 +101979,10 @@ async function createServices(config) {
|
|
|
100892
101979
|
const hitlService = new HITLService();
|
|
100893
101980
|
hitlService.setOrgService(orgService);
|
|
100894
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());
|
|
100895
101984
|
const billingService = new BillingService();
|
|
100896
|
-
billingService.setOrgPlan("default",
|
|
101985
|
+
billingService.setOrgPlan("default", licenseService.getPlan());
|
|
100897
101986
|
const auditService = new AuditService();
|
|
100898
101987
|
taskService.setAuditService(auditService);
|
|
100899
101988
|
if (storage?.auditRepo) {
|
|
@@ -100908,6 +101997,8 @@ async function createServices(config) {
|
|
|
100908
101997
|
skillRegistry,
|
|
100909
101998
|
hitlService,
|
|
100910
101999
|
billingService,
|
|
102000
|
+
licenseService,
|
|
102001
|
+
telemetryService,
|
|
100911
102002
|
auditService,
|
|
100912
102003
|
bootstrapOwnerId
|
|
100913
102004
|
};
|
|
@@ -100967,10 +102058,10 @@ async function startServer(config, values) {
|
|
|
100967
102058
|
startupLog("INFO", "\u6B63\u5728\u542F\u52A8\u670D\u52A1...");
|
|
100968
102059
|
const currentPath = process.env["PATH"] ?? "";
|
|
100969
102060
|
const extraPaths = [];
|
|
100970
|
-
const selfBinDir =
|
|
102061
|
+
const selfBinDir = dirname13(resolve18(process.argv[1] ?? ""));
|
|
100971
102062
|
if (selfBinDir && !currentPath.includes(selfBinDir)) extraPaths.push(selfBinDir);
|
|
100972
|
-
const cwdBin =
|
|
100973
|
-
if (
|
|
102063
|
+
const cwdBin = join34(process.cwd(), "node_modules", ".bin");
|
|
102064
|
+
if (existsSync39(cwdBin) && !currentPath.includes(cwdBin)) extraPaths.push(cwdBin);
|
|
100974
102065
|
if (extraPaths.length > 0) {
|
|
100975
102066
|
process.env["PATH"] = `${extraPaths.join(":")}:${currentPath}`;
|
|
100976
102067
|
}
|
|
@@ -101013,6 +102104,8 @@ async function startServer(config, values) {
|
|
|
101013
102104
|
skillRegistry,
|
|
101014
102105
|
hitlService,
|
|
101015
102106
|
billingService,
|
|
102107
|
+
licenseService,
|
|
102108
|
+
telemetryService,
|
|
101016
102109
|
auditService,
|
|
101017
102110
|
bootstrapOwnerId
|
|
101018
102111
|
} = await createServices(config);
|
|
@@ -101022,6 +102115,8 @@ async function startServer(config, values) {
|
|
|
101022
102115
|
apiServer.setSkillRegistry(skillRegistry);
|
|
101023
102116
|
apiServer.setHITLService(hitlService);
|
|
101024
102117
|
apiServer.setBillingService(billingService);
|
|
102118
|
+
apiServer.setLicenseService(licenseService);
|
|
102119
|
+
apiServer.setTelemetryService(telemetryService);
|
|
101025
102120
|
apiServer.setAuditService(auditService);
|
|
101026
102121
|
const projectService = new ProjectService();
|
|
101027
102122
|
const storage = orgService.getStorage();
|
|
@@ -101035,7 +102130,7 @@ async function startServer(config, values) {
|
|
|
101035
102130
|
projectService.setProjectRepo(storage.projectRepo);
|
|
101036
102131
|
}
|
|
101037
102132
|
await projectService.loadFromDB("default");
|
|
101038
|
-
const knowledgeStore = new FileKnowledgeStore(
|
|
102133
|
+
const knowledgeStore = new FileKnowledgeStore(join34(homedir24(), ".markus", "knowledge"));
|
|
101039
102134
|
const knowledgeService = new KnowledgeService(knowledgeStore);
|
|
101040
102135
|
const deliverableService = new DeliverableService(storage?.deliverableRepo);
|
|
101041
102136
|
await deliverableService.load();
|
|
@@ -101102,17 +102197,28 @@ async function startServer(config, values) {
|
|
|
101102
102197
|
await modelCatalog.initialize();
|
|
101103
102198
|
apiServer.setModelCatalog(modelCatalog);
|
|
101104
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();
|
|
101105
102211
|
const webUiDir = resolveWebUiDir();
|
|
101106
102212
|
if (webUiDir) {
|
|
101107
102213
|
apiServer.setWebUiDir(webUiDir);
|
|
101108
|
-
|
|
102214
|
+
log90.info("Web UI static files enabled", { dir: webUiDir });
|
|
101109
102215
|
}
|
|
101110
102216
|
{
|
|
101111
102217
|
const { LocalFileStorageProvider: LocalFileStorageProvider2 } = await Promise.resolve().then(() => (init_dist6(), dist_exports5));
|
|
101112
102218
|
const localDir = config.fileStorage?.local?.dir;
|
|
101113
102219
|
const fileStorage = new LocalFileStorageProvider2(localDir ?? void 0);
|
|
101114
102220
|
apiServer.setFileStorage(fileStorage);
|
|
101115
|
-
|
|
102221
|
+
log90.info("File storage initialized", { provider: "local", dir: localDir ?? "~/.markus/uploads" });
|
|
101116
102222
|
}
|
|
101117
102223
|
const firstOrgId = "default";
|
|
101118
102224
|
let ownerUserId = bootstrapOwnerId;
|
|
@@ -101133,7 +102239,7 @@ async function startServer(config, values) {
|
|
|
101133
102239
|
const builderService = apiServer.getBuilderService();
|
|
101134
102240
|
if (builderService) {
|
|
101135
102241
|
const builtinTeamsDir = resolveTemplatesDir("teams");
|
|
101136
|
-
if (builtinTeamsDir &&
|
|
102242
|
+
if (builtinTeamsDir && existsSync39(builtinTeamsDir)) {
|
|
101137
102243
|
builderService.setBuiltinTeamTemplatesDir(builtinTeamsDir);
|
|
101138
102244
|
}
|
|
101139
102245
|
agentManager.setBuilderService(builderService);
|
|
@@ -101196,29 +102302,29 @@ async function startServer(config, values) {
|
|
|
101196
102302
|
try {
|
|
101197
102303
|
storage.chatSessionRepo.migrateLegacyMessages();
|
|
101198
102304
|
} catch (e) {
|
|
101199
|
-
|
|
102305
|
+
log90.warn("Legacy chat message migration failed", { error: String(e) });
|
|
101200
102306
|
}
|
|
101201
102307
|
const defaultSessionUserId = ownerUserId;
|
|
101202
102308
|
try {
|
|
101203
102309
|
storage.chatSessionRepo.migrateNullUserSessions(defaultSessionUserId);
|
|
101204
102310
|
} catch (e) {
|
|
101205
|
-
|
|
102311
|
+
log90.warn("NULL user_id session migration failed", { error: String(e) });
|
|
101206
102312
|
}
|
|
101207
102313
|
try {
|
|
101208
102314
|
storage.chatSessionRepo.migrateDefaultUserSessions(defaultSessionUserId);
|
|
101209
102315
|
} catch (e) {
|
|
101210
|
-
|
|
102316
|
+
log90.warn("'default' user_id session migration failed", { error: String(e) });
|
|
101211
102317
|
}
|
|
101212
102318
|
try {
|
|
101213
102319
|
storage.notificationRepo.migrateDefaultUserId(defaultSessionUserId);
|
|
101214
102320
|
} catch (e) {
|
|
101215
|
-
|
|
102321
|
+
log90.warn("'default' user_id notification migration failed", { error: String(e) });
|
|
101216
102322
|
}
|
|
101217
102323
|
if (storage.approvalRepo) {
|
|
101218
102324
|
try {
|
|
101219
102325
|
storage.approvalRepo.migrateDefaultTargetUserId(defaultSessionUserId);
|
|
101220
102326
|
} catch (e) {
|
|
101221
|
-
|
|
102327
|
+
log90.warn("'default' target_user_id approval migration failed", { error: String(e) });
|
|
101222
102328
|
}
|
|
101223
102329
|
}
|
|
101224
102330
|
for (const info2 of agentManager.listAgents()) {
|
|
@@ -101247,7 +102353,7 @@ async function startServer(config, values) {
|
|
|
101247
102353
|
isMainSession: true
|
|
101248
102354
|
}, defaultSessionUserId);
|
|
101249
102355
|
} catch (e) {
|
|
101250
|
-
|
|
102356
|
+
log90.warn("Failed to persist activity log", { agentId: agentId2, error: String(e) });
|
|
101251
102357
|
}
|
|
101252
102358
|
});
|
|
101253
102359
|
agentManager.getEventBus().on("agent:notify-user", async (evt) => {
|
|
@@ -101300,7 +102406,7 @@ ${body}${contextSuffix}`;
|
|
|
101300
102406
|
metadata: { agentId: agentId2, agentName: agent.config.name, taskId: taskId2, requirementId: requirementId2, sessionId: mainSession.id }
|
|
101301
102407
|
});
|
|
101302
102408
|
} catch (e) {
|
|
101303
|
-
|
|
102409
|
+
log90.warn("Failed to handle notify-user event", { agentId: agentId2, error: String(e) });
|
|
101304
102410
|
}
|
|
101305
102411
|
});
|
|
101306
102412
|
agentManager.getEventBus().on("agent:escalation", async (evt) => {
|
|
@@ -101342,7 +102448,7 @@ ${reason}`;
|
|
|
101342
102448
|
success: false
|
|
101343
102449
|
});
|
|
101344
102450
|
} catch (e) {
|
|
101345
|
-
|
|
102451
|
+
log90.warn("Failed to handle escalation event", { agentId: agentId2, error: String(e) });
|
|
101346
102452
|
}
|
|
101347
102453
|
});
|
|
101348
102454
|
agentManager.getEventBus().on("agent:created", (evt) => {
|
|
@@ -101388,7 +102494,7 @@ ${reason}`;
|
|
|
101388
102494
|
heartbeatIntervalMs: agent.config.heartbeatIntervalMs
|
|
101389
102495
|
});
|
|
101390
102496
|
} catch (err) {
|
|
101391
|
-
|
|
102497
|
+
log90.warn("Failed to persist gateway agent to DB (may already exist)", { error: String(err) });
|
|
101392
102498
|
}
|
|
101393
102499
|
}
|
|
101394
102500
|
return { id: agent.id };
|
|
@@ -101433,11 +102539,11 @@ ${reason}`;
|
|
|
101433
102539
|
}));
|
|
101434
102540
|
});
|
|
101435
102541
|
apiServer.setGateway(gateway, gatewaySecret);
|
|
101436
|
-
|
|
102542
|
+
log90.info("External Agent Gateway enabled", { secret: gatewaySecret === "markus-gateway-default-secret-change-me" ? "(default)" : "(custom)" });
|
|
101437
102543
|
{
|
|
101438
|
-
const hubTokenPath =
|
|
102544
|
+
const hubTokenPath = join34(homedir24(), ".markus", "hub-token");
|
|
101439
102545
|
const createRemoteAgent = async () => {
|
|
101440
|
-
const token =
|
|
102546
|
+
const token = existsSync39(hubTokenPath) ? readFileSync28(hubTokenPath, "utf-8").trim() : void 0;
|
|
101441
102547
|
if (!token) return null;
|
|
101442
102548
|
const { RemoteAccessAgent: RemoteAccessAgent2 } = await Promise.resolve().then(() => (init_dist8(), dist_exports6));
|
|
101443
102549
|
return new RemoteAccessAgent2({
|
|
@@ -101449,7 +102555,7 @@ ${reason}`;
|
|
|
101449
102555
|
});
|
|
101450
102556
|
};
|
|
101451
102557
|
apiServer.setRemoteAgentFactory(createRemoteAgent);
|
|
101452
|
-
if (config.remote?.enabled
|
|
102558
|
+
if (config.remote?.enabled === true) {
|
|
101453
102559
|
const remoteAgent = await createRemoteAgent();
|
|
101454
102560
|
if (remoteAgent) {
|
|
101455
102561
|
apiServer.setRemoteAgent(remoteAgent);
|
|
@@ -101457,14 +102563,14 @@ ${reason}`;
|
|
|
101457
102563
|
remoteAgent.start().then(() => {
|
|
101458
102564
|
const status = remoteAgent.getStatus();
|
|
101459
102565
|
if (status.remoteUrl) {
|
|
101460
|
-
|
|
102566
|
+
log90.info(`Remote access available at ${status.remoteUrl}`);
|
|
101461
102567
|
}
|
|
101462
102568
|
}).catch((err) => {
|
|
101463
|
-
|
|
102569
|
+
log90.warn("Remote access failed to start", { error: String(err) });
|
|
101464
102570
|
});
|
|
101465
102571
|
}
|
|
101466
102572
|
} else {
|
|
101467
|
-
|
|
102573
|
+
log90.debug("Remote access: no Hub token yet (can enable later via Settings)");
|
|
101468
102574
|
}
|
|
101469
102575
|
}
|
|
101470
102576
|
}
|
|
@@ -101475,7 +102581,7 @@ ${reason}`;
|
|
|
101475
102581
|
const scheduledTaskRunner = new ScheduledTaskRunner(taskService);
|
|
101476
102582
|
scheduledTaskRunner.start();
|
|
101477
102583
|
agentManager.setEscalationHandler((agentId2, reason) => {
|
|
101478
|
-
|
|
102584
|
+
log90.warn("Agent escalation", { agentId: agentId2, reason });
|
|
101479
102585
|
});
|
|
101480
102586
|
agentManager.setApprovalHandler(async (agentId2, request) => {
|
|
101481
102587
|
const agents = agentManager.listAgents();
|
|
@@ -101542,6 +102648,17 @@ ${reason}`;
|
|
|
101542
102648
|
});
|
|
101543
102649
|
}
|
|
101544
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"));
|
|
101545
102662
|
if (storage) {
|
|
101546
102663
|
agentManager.setStateChangeHandler(async (agentId2, state) => {
|
|
101547
102664
|
try {
|
|
@@ -101550,7 +102667,7 @@ ${reason}`;
|
|
|
101550
102667
|
state.status
|
|
101551
102668
|
);
|
|
101552
102669
|
} catch (err) {
|
|
101553
|
-
|
|
102670
|
+
log90.warn("Failed to persist agent state", { agentId: agentId2, error: String(err) });
|
|
101554
102671
|
}
|
|
101555
102672
|
apiServer.getWSBroadcaster().broadcastAgentUpdate(agentId2, state.status, {
|
|
101556
102673
|
lastError: state.lastError,
|
|
@@ -101575,7 +102692,7 @@ ${reason}`;
|
|
|
101575
102692
|
startedAt: activity.startedAt
|
|
101576
102693
|
});
|
|
101577
102694
|
} catch (err) {
|
|
101578
|
-
|
|
102695
|
+
log90.warn("Failed to persist activity start", { activityId: activity.id, error: String(err) });
|
|
101579
102696
|
}
|
|
101580
102697
|
},
|
|
101581
102698
|
onLog: (data) => {
|
|
@@ -101591,20 +102708,20 @@ ${reason}`;
|
|
|
101591
102708
|
metadata: data.metadata
|
|
101592
102709
|
});
|
|
101593
102710
|
} catch (err) {
|
|
101594
|
-
|
|
102711
|
+
log90.warn("Failed to persist execution stream activity log", { activityId: data.activityId, error: String(err) });
|
|
101595
102712
|
}
|
|
101596
102713
|
}
|
|
101597
102714
|
try {
|
|
101598
102715
|
actRepo.insertActivityLog(data);
|
|
101599
102716
|
} catch (err) {
|
|
101600
|
-
|
|
102717
|
+
log90.warn("Failed to persist activity log", { activityId: data.activityId, error: String(err) });
|
|
101601
102718
|
}
|
|
101602
102719
|
},
|
|
101603
102720
|
onEnd: (activityId, summary) => {
|
|
101604
102721
|
try {
|
|
101605
102722
|
actRepo.updateActivity(activityId, summary);
|
|
101606
102723
|
} catch (err) {
|
|
101607
|
-
|
|
102724
|
+
log90.warn("Failed to persist activity end", { activityId, error: String(err) });
|
|
101608
102725
|
}
|
|
101609
102726
|
}
|
|
101610
102727
|
});
|
|
@@ -101647,14 +102764,14 @@ ${reason}`;
|
|
|
101647
102764
|
queuedAt: item.queuedAt
|
|
101648
102765
|
});
|
|
101649
102766
|
} catch (e) {
|
|
101650
|
-
|
|
102767
|
+
log90.warn("Failed to persist mailbox item", { id: item.id, error: String(e) });
|
|
101651
102768
|
}
|
|
101652
102769
|
},
|
|
101653
102770
|
updateStatus: (itemId, status, extra) => {
|
|
101654
102771
|
try {
|
|
101655
102772
|
mbRepo.updateStatus(itemId, status, extra);
|
|
101656
102773
|
} catch (e) {
|
|
101657
|
-
|
|
102774
|
+
log90.warn("Failed to update mailbox status", { itemId, error: String(e) });
|
|
101658
102775
|
}
|
|
101659
102776
|
},
|
|
101660
102777
|
markStaleProcessingAsDropped: (aid) => mbRepo.markStaleProcessingAsDropped(aid),
|
|
@@ -101697,7 +102814,7 @@ ${reason}`;
|
|
|
101697
102814
|
}
|
|
101698
102815
|
});
|
|
101699
102816
|
const { dropped, restored, expired, merged } = mailbox.recoverStaleItems();
|
|
101700
|
-
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 });
|
|
101701
102818
|
agent.getAttentionController().setDecisionPersistence({
|
|
101702
102819
|
save: (decision) => {
|
|
101703
102820
|
try {
|
|
@@ -101712,7 +102829,7 @@ ${reason}`;
|
|
|
101712
102829
|
createdAt: decision.createdAt
|
|
101713
102830
|
});
|
|
101714
102831
|
} catch (e) {
|
|
101715
|
-
|
|
102832
|
+
log90.warn("Failed to persist decision", { id: decision.id, error: String(e) });
|
|
101716
102833
|
}
|
|
101717
102834
|
}
|
|
101718
102835
|
});
|
|
@@ -101807,7 +102924,7 @@ ${reason}`;
|
|
|
101807
102924
|
llmConfig: agent.config.llmConfig,
|
|
101808
102925
|
heartbeatIntervalMs: agent.config.heartbeatIntervalMs
|
|
101809
102926
|
}).catch((err) => {
|
|
101810
|
-
|
|
102927
|
+
log90.warn("Failed to persist runtime-created agent to DB", { agentId: agentId2, error: String(err) });
|
|
101811
102928
|
});
|
|
101812
102929
|
} catch {
|
|
101813
102930
|
}
|
|
@@ -101890,7 +103007,7 @@ ${reason}`;
|
|
|
101890
103007
|
const nextMidnight = new Date(now3.getFullYear(), now3.getMonth(), now3.getDate() + 1, 0, 0, 0, 0);
|
|
101891
103008
|
const msUntilMidnight = nextMidnight.getTime() - now3.getTime();
|
|
101892
103009
|
setTimeout(() => {
|
|
101893
|
-
|
|
103010
|
+
log90.info("Daily token reset triggered");
|
|
101894
103011
|
for (const agentInfo of agentManager.listAgents()) {
|
|
101895
103012
|
try {
|
|
101896
103013
|
const agent = agentManager.getAgent(agentInfo.id);
|
|
@@ -101900,7 +103017,7 @@ ${reason}`;
|
|
|
101900
103017
|
}
|
|
101901
103018
|
scheduleDailyReset();
|
|
101902
103019
|
}, msUntilMidnight);
|
|
101903
|
-
|
|
103020
|
+
log90.info(`Daily token reset scheduled in ${Math.round(msUntilMidnight / 6e4)} minutes`);
|
|
101904
103021
|
};
|
|
101905
103022
|
scheduleDailyReset();
|
|
101906
103023
|
const messageRouter = new MessageRouter();
|
|
@@ -101931,7 +103048,7 @@ ${reason}`;
|
|
|
101931
103048
|
durationMs: Date.now() - startTs,
|
|
101932
103049
|
success: false
|
|
101933
103050
|
});
|
|
101934
|
-
|
|
103051
|
+
log90.error("Agent message handler error", { error: String(error) });
|
|
101935
103052
|
return void 0;
|
|
101936
103053
|
}
|
|
101937
103054
|
});
|
|
@@ -101967,7 +103084,7 @@ ${reason}`;
|
|
|
101967
103084
|
if (info2.updateAvailable) {
|
|
101968
103085
|
console.log(`
|
|
101969
103086
|
\x1B[33m\u2B06 New version available: v${info2.latestVersion} (current: v${info2.currentVersion})\x1B[0m`);
|
|
101970
|
-
console.log(`
|
|
103087
|
+
console.log(` Visit \x1B[1mhttps://markus.global/download\x1B[0m to download the latest version
|
|
101971
103088
|
`);
|
|
101972
103089
|
}
|
|
101973
103090
|
}).catch(() => {
|
|
@@ -101976,7 +103093,7 @@ ${reason}`;
|
|
|
101976
103093
|
try {
|
|
101977
103094
|
await taskService.resumeInProgressTasks();
|
|
101978
103095
|
} catch (err) {
|
|
101979
|
-
|
|
103096
|
+
log90.warn("Failed to auto-resume in_progress tasks", { error: String(err) });
|
|
101980
103097
|
}
|
|
101981
103098
|
});
|
|
101982
103099
|
process.on("SIGINT", () => {
|
|
@@ -101992,7 +103109,7 @@ ${reason}`;
|
|
|
101992
103109
|
await new Promise(() => {
|
|
101993
103110
|
});
|
|
101994
103111
|
}
|
|
101995
|
-
var
|
|
103112
|
+
var log90;
|
|
101996
103113
|
var init_start = __esm({
|
|
101997
103114
|
"src/commands/start.ts"() {
|
|
101998
103115
|
"use strict";
|
|
@@ -102004,7 +103121,7 @@ var init_start = __esm({
|
|
|
102004
103121
|
init_logger2();
|
|
102005
103122
|
init_browser();
|
|
102006
103123
|
init_startupProgress();
|
|
102007
|
-
|
|
103124
|
+
log90 = createLogger("cli");
|
|
102008
103125
|
}
|
|
102009
103126
|
});
|
|
102010
103127
|
|
|
@@ -102633,8 +103750,8 @@ ${C3.BOLD}${C3.CYAN}\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
|
102633
103750
|
}
|
|
102634
103751
|
}
|
|
102635
103752
|
section("Storage");
|
|
102636
|
-
const { homedir:
|
|
102637
|
-
const storageDir = `${
|
|
103753
|
+
const { homedir: homedir25 } = await import("node:os");
|
|
103754
|
+
const storageDir = `${homedir25()}/.markus`;
|
|
102638
103755
|
const dataFile = `${storageDir}/data.db`;
|
|
102639
103756
|
try {
|
|
102640
103757
|
if (!fs.existsSync(storageDir)) {
|
|
@@ -102658,7 +103775,7 @@ ${C3.BOLD}${C3.CYAN}\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
|
102658
103775
|
checkFail(`Storage check failed: ${e}`);
|
|
102659
103776
|
}
|
|
102660
103777
|
section("Skills");
|
|
102661
|
-
const skillsDir = `${
|
|
103778
|
+
const skillsDir = `${homedir25()}/.markus/skills`;
|
|
102662
103779
|
if (fs.existsSync(skillsDir)) {
|
|
102663
103780
|
try {
|
|
102664
103781
|
const entries2 = fs.readdirSync(skillsDir);
|
|
@@ -102737,9 +103854,9 @@ ${C3.BOLD}\u25C6 Summary${C3.RESET}
|
|
|
102737
103854
|
}
|
|
102738
103855
|
}
|
|
102739
103856
|
async function getDefaultConfigPath2() {
|
|
102740
|
-
const { homedir:
|
|
102741
|
-
const { join:
|
|
102742
|
-
return
|
|
103857
|
+
const { homedir: homedir25 } = await import("node:os");
|
|
103858
|
+
const { join: join35 } = await import("node:path");
|
|
103859
|
+
return join35(homedir25(), ".markus", "markus.json");
|
|
102743
103860
|
}
|
|
102744
103861
|
function registerDoctorCommand(program2) {
|
|
102745
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) => {
|
|
@@ -103241,19 +104358,19 @@ __export(install_agent_exports, {
|
|
|
103241
104358
|
import { execSync as execSync5 } from "node:child_process";
|
|
103242
104359
|
import { randomBytes as randomBytes6 } from "node:crypto";
|
|
103243
104360
|
function registerInstallAgentCommands(program2) {
|
|
103244
|
-
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) => {
|
|
103245
104362
|
const g = cmd.optsWithGlobals();
|
|
103246
|
-
const connector = findConnector(
|
|
104363
|
+
const connector = findConnector(platform5);
|
|
103247
104364
|
if (!connector) {
|
|
103248
104365
|
const available = loadConnectors().map((c) => c.platform).join(", ");
|
|
103249
|
-
fail(`Unknown platform "${
|
|
104366
|
+
fail(`Unknown platform "${platform5}". Available: ${available || "none"}`);
|
|
103250
104367
|
return;
|
|
103251
104368
|
}
|
|
103252
104369
|
console.log(`
|
|
103253
104370
|
Installing ${connector.displayName}...
|
|
103254
104371
|
`);
|
|
103255
104372
|
const scan = scanInstalledPlatforms();
|
|
103256
|
-
const existing = scan.find((s2) => s2.platform ===
|
|
104373
|
+
const existing = scan.find((s2) => s2.platform === platform5);
|
|
103257
104374
|
const alreadyInstalled = existing?.installed;
|
|
103258
104375
|
if (alreadyInstalled && !opts.skipInstall) {
|
|
103259
104376
|
console.log(` [1/5] ${connector.displayName} is already installed.`);
|
|
@@ -103289,13 +104406,13 @@ function registerInstallAgentCommands(program2) {
|
|
|
103289
104406
|
console.log(` [4/5] Token generation skipped.`);
|
|
103290
104407
|
console.log(` [5/5] Config write skipped.`);
|
|
103291
104408
|
console.log(`
|
|
103292
|
-
${connector.displayName} installed. Run \`markus install ${
|
|
104409
|
+
${connector.displayName} installed. Run \`markus install ${platform5}\` again without --skip-connect to connect later.
|
|
103293
104410
|
`);
|
|
103294
104411
|
return;
|
|
103295
104412
|
}
|
|
103296
104413
|
const client = createClient(g);
|
|
103297
104414
|
const serverUrl = g.server || process.env["MARKUS_API_URL"] || "http://localhost:8056";
|
|
103298
|
-
const agentId2 = `${
|
|
104415
|
+
const agentId2 = `${platform5}-${randomBytes6(4).toString("hex")}`;
|
|
103299
104416
|
const agentName = opts.agentName || connector.defaultAgentName || `${connector.displayName} Agent`;
|
|
103300
104417
|
const capabilities = connector.defaultCapabilities ?? [];
|
|
103301
104418
|
try {
|
|
@@ -103358,7 +104475,7 @@ function registerInstallAgentCommands(program2) {
|
|
|
103358
104475
|
Connection failed: ${e.message}`);
|
|
103359
104476
|
console.log(` ${connector.displayName} was installed but could not connect to Markus.`);
|
|
103360
104477
|
console.log(` Make sure the Markus server is running (\`markus start\`), then run:`);
|
|
103361
|
-
console.log(` markus install ${
|
|
104478
|
+
console.log(` markus install ${platform5}
|
|
103362
104479
|
`);
|
|
103363
104480
|
return;
|
|
103364
104481
|
}
|
|
@@ -103454,14 +104571,14 @@ __export(system_exports, {
|
|
|
103454
104571
|
registerSystemCommands: () => registerSystemCommands
|
|
103455
104572
|
});
|
|
103456
104573
|
import { execSync as execSync6 } from "node:child_process";
|
|
103457
|
-
import { existsSync as
|
|
103458
|
-
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";
|
|
103459
104576
|
import { fileURLToPath as fileURLToPath7 } from "node:url";
|
|
103460
104577
|
function findMarkusRoot() {
|
|
103461
|
-
let dir =
|
|
104578
|
+
let dir = dirname14(fileURLToPath7(import.meta.url));
|
|
103462
104579
|
for (let i = 0; i < 10; i++) {
|
|
103463
|
-
if (
|
|
103464
|
-
dir =
|
|
104580
|
+
if (existsSync40(resolve19(dir, "package.json")) && existsSync40(resolve19(dir, "packages"))) return dir;
|
|
104581
|
+
dir = dirname14(dir);
|
|
103465
104582
|
}
|
|
103466
104583
|
return null;
|
|
103467
104584
|
}
|
|
@@ -103511,13 +104628,13 @@ function registerSystemCommands(program2) {
|
|
|
103511
104628
|
if (markusRoot) {
|
|
103512
104629
|
if (!info2.currentVersion) {
|
|
103513
104630
|
try {
|
|
103514
|
-
const pkg = JSON.parse(
|
|
104631
|
+
const pkg = JSON.parse(readFileSync29(resolve19(markusRoot, "package.json"), "utf-8"));
|
|
103515
104632
|
info2.currentVersion = pkg.version;
|
|
103516
104633
|
} catch {
|
|
103517
104634
|
}
|
|
103518
104635
|
}
|
|
103519
104636
|
try {
|
|
103520
|
-
const isGit =
|
|
104637
|
+
const isGit = existsSync40(resolve19(markusRoot, ".git"));
|
|
103521
104638
|
if (isGit) {
|
|
103522
104639
|
info2.gitBranch = execSync6("git rev-parse --abbrev-ref HEAD", { cwd: markusRoot, encoding: "utf-8" }).trim();
|
|
103523
104640
|
info2.gitCommit = execSync6("git rev-parse --short HEAD", { cwd: markusRoot, encoding: "utf-8" }).trim();
|
|
@@ -103556,7 +104673,7 @@ function registerSystemCommands(program2) {
|
|
|
103556
104673
|
fail("Cannot locate Markus installation directory");
|
|
103557
104674
|
return;
|
|
103558
104675
|
}
|
|
103559
|
-
if (!
|
|
104676
|
+
if (!existsSync40(resolve19(markusRoot, ".git"))) {
|
|
103560
104677
|
fail("Markus installation is not a git repository. Update manually.");
|
|
103561
104678
|
return;
|
|
103562
104679
|
}
|
|
@@ -103591,7 +104708,7 @@ var init_system = __esm({
|
|
|
103591
104708
|
|
|
103592
104709
|
// src/index.ts
|
|
103593
104710
|
import { resolve as resolve20 } from "node:path";
|
|
103594
|
-
import { readFileSync as
|
|
104711
|
+
import { readFileSync as readFileSync30, existsSync as existsSync41 } from "node:fs";
|
|
103595
104712
|
import process2 from "node:process";
|
|
103596
104713
|
|
|
103597
104714
|
// ../../node_modules/.pnpm/commander@14.0.3/node_modules/commander/esm.mjs
|
|
@@ -103615,8 +104732,8 @@ var {
|
|
|
103615
104732
|
init_dist();
|
|
103616
104733
|
init_output();
|
|
103617
104734
|
var envPath = resolve20(process2.cwd(), ".env");
|
|
103618
|
-
if (
|
|
103619
|
-
for (const line of
|
|
104735
|
+
if (existsSync41(envPath)) {
|
|
104736
|
+
for (const line of readFileSync30(envPath, "utf-8").split("\n")) {
|
|
103620
104737
|
const trimmed = line.trim();
|
|
103621
104738
|
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
103622
104739
|
const eqIdx = trimmed.indexOf("=");
|