@mclawnet/agent 0.5.1 → 0.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
import { readFileSync, writeFileSync, mkdirSync, existsSync } from "fs";
|
|
3
3
|
import { join } from "path";
|
|
4
4
|
import { homedir, hostname } from "os";
|
|
5
|
+
import { createLogger } from "@mclawnet/logger";
|
|
6
|
+
var log = createLogger({ module: "config" });
|
|
5
7
|
var CONFIG_DIR = join(homedir(), ".clawnet");
|
|
6
8
|
var SETTINGS_FILE = join(CONFIG_DIR, "settings.json");
|
|
7
9
|
var DEFAULT_HUB_URL = process.env.CLAWNET_DEFAULT_HUB_URL || "ws://localhost:3000/ws/agent";
|
|
@@ -35,23 +37,41 @@ function applyEmbeddingConfig(embedding) {
|
|
|
35
37
|
}
|
|
36
38
|
function loadConfig(cliOpts = {}) {
|
|
37
39
|
let fileConfig = {};
|
|
40
|
+
log.info({ path: SETTINGS_FILE }, "loading config");
|
|
38
41
|
if (existsSync(SETTINGS_FILE)) {
|
|
39
42
|
try {
|
|
40
43
|
fileConfig = JSON.parse(readFileSync(SETTINGS_FILE, "utf-8"));
|
|
41
|
-
|
|
44
|
+
log.info(
|
|
45
|
+
{ hubUrl: fileConfig.hubUrl, hasToken: !!fileConfig.token, name: fileConfig.name },
|
|
46
|
+
"settings.json loaded"
|
|
47
|
+
);
|
|
48
|
+
} catch (e) {
|
|
49
|
+
log.warn({ err: e }, "failed to parse settings.json");
|
|
42
50
|
}
|
|
51
|
+
} else {
|
|
52
|
+
log.warn("settings.json not found");
|
|
43
53
|
}
|
|
44
54
|
if (fileConfig.embedding) {
|
|
45
55
|
applyEmbeddingConfig(fileConfig.embedding);
|
|
46
56
|
}
|
|
47
57
|
const hubUrl = cliOpts.hubUrl ?? process.env.CLAWNET_HUB_URL ?? fileConfig.hubUrl ?? DEFAULTS.hubUrl;
|
|
48
|
-
|
|
58
|
+
const resolved = {
|
|
49
59
|
hubUrl: normalizeHubUrl(hubUrl),
|
|
50
60
|
token: cliOpts.token ?? process.env.CLAWNET_TOKEN ?? fileConfig.token ?? DEFAULTS.token,
|
|
51
61
|
name: cliOpts.name ?? process.env.CLAWNET_NAME ?? fileConfig.name ?? DEFAULTS.name,
|
|
52
62
|
backendType: cliOpts.backendType ?? process.env.CLAWNET_BACKEND_TYPE ?? fileConfig.backendType ?? DEFAULTS.backendType,
|
|
53
63
|
embedding: fileConfig.embedding
|
|
54
64
|
};
|
|
65
|
+
log.info(
|
|
66
|
+
{
|
|
67
|
+
hubUrl: resolved.hubUrl,
|
|
68
|
+
hubUrlSource: cliOpts.hubUrl ? "cli" : process.env.CLAWNET_HUB_URL ? "env" : fileConfig.hubUrl ? "file" : "default",
|
|
69
|
+
tokenSource: cliOpts.token ? "cli" : process.env.CLAWNET_TOKEN ? "env" : fileConfig.token ? "file" : "default",
|
|
70
|
+
hasToken: !!resolved.token
|
|
71
|
+
},
|
|
72
|
+
"config resolved"
|
|
73
|
+
);
|
|
74
|
+
return resolved;
|
|
55
75
|
}
|
|
56
76
|
function saveConfig(config) {
|
|
57
77
|
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
@@ -304,8 +324,8 @@ async function handleLoadSessionHistory(workDir, claudeSessionId) {
|
|
|
304
324
|
}
|
|
305
325
|
|
|
306
326
|
// src/hub-connection.ts
|
|
307
|
-
import { createLogger } from "@mclawnet/logger";
|
|
308
|
-
var
|
|
327
|
+
import { createLogger as createLogger2 } from "@mclawnet/logger";
|
|
328
|
+
var log2 = createLogger2({ module: "agent" });
|
|
309
329
|
var HubConnection = class {
|
|
310
330
|
ws = null;
|
|
311
331
|
heartbeatTimer = null;
|
|
@@ -387,7 +407,7 @@ var HubConnection = class {
|
|
|
387
407
|
return;
|
|
388
408
|
}
|
|
389
409
|
if (this.authState === "pending" && data.type === "auth_required") {
|
|
390
|
-
|
|
410
|
+
log2.info("hub requires auth, sending credentials");
|
|
391
411
|
this.authState = "authenticating";
|
|
392
412
|
this.sendRaw({
|
|
393
413
|
type: "auth",
|
|
@@ -399,7 +419,7 @@ var HubConnection = class {
|
|
|
399
419
|
return;
|
|
400
420
|
}
|
|
401
421
|
if (this.authState === "authenticating" && data.type === "registered") {
|
|
402
|
-
|
|
422
|
+
log2.info({ agentId: data.agentId }, "registered with hub");
|
|
403
423
|
this.authState = "authenticated";
|
|
404
424
|
this.agentId = data.agentId ?? null;
|
|
405
425
|
this.startHeartbeat();
|
|
@@ -413,18 +433,18 @@ var HubConnection = class {
|
|
|
413
433
|
}
|
|
414
434
|
});
|
|
415
435
|
this.ws.on("close", (code, reason) => {
|
|
416
|
-
|
|
436
|
+
log2.info({ code, reason: reason.toString() }, "ws connection closed");
|
|
417
437
|
this.stopHeartbeat();
|
|
418
438
|
this.authState = "pending";
|
|
419
439
|
this.onDisconnect?.(code, reason.toString());
|
|
420
440
|
if (code === WS_CLOSE_INVALID_TOKEN) {
|
|
421
|
-
|
|
441
|
+
log2.error("auth failed \u2014 not reconnecting, check your token");
|
|
422
442
|
return;
|
|
423
443
|
}
|
|
424
444
|
this.scheduleReconnect();
|
|
425
445
|
});
|
|
426
446
|
this.ws.on("error", (err) => {
|
|
427
|
-
|
|
447
|
+
log2.error({ err }, "ws connection error");
|
|
428
448
|
this.onError?.(err);
|
|
429
449
|
});
|
|
430
450
|
}
|
|
@@ -442,11 +462,11 @@ var HubConnection = class {
|
|
|
442
462
|
// ── Session message handling ─────────────────────────────────────
|
|
443
463
|
handleSessionMessage(msg) {
|
|
444
464
|
if (msg.type === "fs.list_dir") {
|
|
445
|
-
|
|
465
|
+
log2.info({ path: msg.path }, "fs.list_dir");
|
|
446
466
|
handleListDir(msg.path).then((result) => {
|
|
447
467
|
this.send({ type: "fs.list_dir_result", requestId: msg.requestId, ...result });
|
|
448
468
|
}).catch((err) => {
|
|
449
|
-
|
|
469
|
+
log2.error({ err, path: msg.path }, "fs.list_dir failed");
|
|
450
470
|
this.send({
|
|
451
471
|
type: "fs.list_dir_result",
|
|
452
472
|
requestId: msg.requestId,
|
|
@@ -457,21 +477,21 @@ var HubConnection = class {
|
|
|
457
477
|
return true;
|
|
458
478
|
}
|
|
459
479
|
if (msg.type === "list_folders") {
|
|
460
|
-
|
|
480
|
+
log2.info("list_folders");
|
|
461
481
|
handleListFolders().then((result) => {
|
|
462
482
|
this.send({ type: "folders_list_result", requestId: msg.requestId, ...result });
|
|
463
483
|
}).catch((err) => {
|
|
464
|
-
|
|
484
|
+
log2.error({ err }, "list_folders failed");
|
|
465
485
|
this.send({ type: "folders_list_result", requestId: msg.requestId, folders: [] });
|
|
466
486
|
});
|
|
467
487
|
return true;
|
|
468
488
|
}
|
|
469
489
|
if (msg.type === "list_history_sessions") {
|
|
470
|
-
|
|
490
|
+
log2.info({ workDir: msg.workDir }, "list_history_sessions");
|
|
471
491
|
handleListHistorySessions(msg.workDir).then((result) => {
|
|
472
492
|
this.send({ type: "history_sessions_result", requestId: msg.requestId, ...result });
|
|
473
493
|
}).catch((err) => {
|
|
474
|
-
|
|
494
|
+
log2.error({ err, workDir: msg.workDir }, "list_history_sessions failed");
|
|
475
495
|
this.send({
|
|
476
496
|
type: "history_sessions_result",
|
|
477
497
|
requestId: msg.requestId,
|
|
@@ -482,17 +502,17 @@ var HubConnection = class {
|
|
|
482
502
|
return true;
|
|
483
503
|
}
|
|
484
504
|
if (msg.type === "load_session_history") {
|
|
485
|
-
|
|
505
|
+
log2.info({ workDir: msg.workDir, claudeSessionId: msg.claudeSessionId }, "load_session_history");
|
|
486
506
|
handleLoadSessionHistory(msg.workDir, msg.claudeSessionId).then((result) => {
|
|
487
507
|
this.send({ type: "session_history_result", requestId: msg.requestId, ...result });
|
|
488
508
|
}).catch((err) => {
|
|
489
|
-
|
|
509
|
+
log2.error({ err, workDir: msg.workDir }, "load_session_history failed");
|
|
490
510
|
this.send({ type: "session_history_result", requestId: msg.requestId, messages: [] });
|
|
491
511
|
});
|
|
492
512
|
return true;
|
|
493
513
|
}
|
|
494
514
|
if (msg.type === "list_roles") {
|
|
495
|
-
|
|
515
|
+
log2.info("list_roles");
|
|
496
516
|
const roleNames = listRoles();
|
|
497
517
|
const roles = roleNames.map((name) => {
|
|
498
518
|
try {
|
|
@@ -518,9 +538,9 @@ var HubConnection = class {
|
|
|
518
538
|
if (msg.type === "generic.request") {
|
|
519
539
|
const handler = this.namespaceHandlers.get(msg.namespace);
|
|
520
540
|
if (handler) {
|
|
521
|
-
|
|
541
|
+
log2.info({ namespace: msg.namespace, action: msg.action, requestId: msg.requestId }, "generic.request received");
|
|
522
542
|
handler(msg).then((result) => {
|
|
523
|
-
|
|
543
|
+
log2.info({ namespace: msg.namespace, action: msg.action, requestId: msg.requestId }, "generic.request handled OK");
|
|
524
544
|
this.send({
|
|
525
545
|
type: "generic.response",
|
|
526
546
|
namespace: msg.namespace,
|
|
@@ -529,7 +549,7 @@ var HubConnection = class {
|
|
|
529
549
|
requestId: msg.requestId
|
|
530
550
|
});
|
|
531
551
|
}).catch((err) => {
|
|
532
|
-
|
|
552
|
+
log2.error({ namespace: msg.namespace, action: msg.action, requestId: msg.requestId, err }, "generic.request handler error");
|
|
533
553
|
this.send({
|
|
534
554
|
type: "generic.response",
|
|
535
555
|
namespace: msg.namespace,
|
|
@@ -541,7 +561,7 @@ var HubConnection = class {
|
|
|
541
561
|
});
|
|
542
562
|
return true;
|
|
543
563
|
}
|
|
544
|
-
|
|
564
|
+
log2.warn({ namespace: msg.namespace, action: msg.action, requestId: msg.requestId }, "generic.request unknown namespace");
|
|
545
565
|
this.send({
|
|
546
566
|
type: "generic.response",
|
|
547
567
|
namespace: msg.namespace,
|
|
@@ -555,7 +575,7 @@ var HubConnection = class {
|
|
|
555
575
|
if (msg.type === "swarm.execute" && this.swarmCoordinator) {
|
|
556
576
|
const { sessionId, content, workDir, targetInstance, crewConfig } = msg;
|
|
557
577
|
if (this.swarmCoordinator.hasSwarm(sessionId)) {
|
|
558
|
-
|
|
578
|
+
log2.info({ sessionId, targetInstance }, "swarm.execute: forwarding to existing swarm");
|
|
559
579
|
this.swarmCoordinator.handleUserMessage(sessionId, content, targetInstance).catch((err) => {
|
|
560
580
|
this.send({
|
|
561
581
|
type: "session.error",
|
|
@@ -564,14 +584,14 @@ var HubConnection = class {
|
|
|
564
584
|
});
|
|
565
585
|
});
|
|
566
586
|
} else if (this.finishedSwarms.has(sessionId)) {
|
|
567
|
-
|
|
587
|
+
log2.info({ sessionId }, "swarm.execute ignored: swarm already finished");
|
|
568
588
|
this.send({
|
|
569
589
|
type: "session.error",
|
|
570
590
|
sessionId,
|
|
571
591
|
error: "\u8702\u7FA4\u4EFB\u52A1\u5DF2\u5B8C\u6210\uFF0C\u65E0\u6CD5\u7EE7\u7EED\u64CD\u4F5C\u3002\u8BF7\u521B\u5EFA\u65B0\u7684\u8702\u7FA4\u4EFB\u52A1\u3002"
|
|
572
592
|
});
|
|
573
593
|
} else if (crewConfig?.roles) {
|
|
574
|
-
|
|
594
|
+
log2.info({ sessionId, rolesCount: crewConfig.roles.length }, "swarm.execute: creating new swarm");
|
|
575
595
|
const roles = crewConfig.roles;
|
|
576
596
|
this.swarmCoordinator.create(sessionId, { workDir, roles, task: content }).catch((err) => {
|
|
577
597
|
this.send({
|
|
@@ -581,7 +601,7 @@ var HubConnection = class {
|
|
|
581
601
|
});
|
|
582
602
|
});
|
|
583
603
|
} else {
|
|
584
|
-
|
|
604
|
+
log2.info({ sessionId }, "swarm.execute ignored: swarm not found, no config");
|
|
585
605
|
this.send({
|
|
586
606
|
type: "session.error",
|
|
587
607
|
sessionId,
|
|
@@ -593,7 +613,7 @@ var HubConnection = class {
|
|
|
593
613
|
if (!this.sessionManager) return false;
|
|
594
614
|
if (msg.type === "abort_execution") {
|
|
595
615
|
const { sessionId } = msg;
|
|
596
|
-
|
|
616
|
+
log2.info({ sessionId }, "abort_execution");
|
|
597
617
|
if (this.sessionManager?.hasSession(sessionId)) {
|
|
598
618
|
this.sessionManager.abortSession(sessionId).then(() => {
|
|
599
619
|
this.send({ type: "execution_aborted", sessionId });
|
|
@@ -608,10 +628,10 @@ var HubConnection = class {
|
|
|
608
628
|
if (msg.type === "claude.execute") {
|
|
609
629
|
const { sessionId, content, workDir, claudeSessionId, useBrainCore } = msg;
|
|
610
630
|
if (this.sessionManager.hasSession(sessionId)) {
|
|
611
|
-
|
|
631
|
+
log2.info({ sessionId }, "claude.execute: reusing existing session");
|
|
612
632
|
this.sessionManager.sendInput(sessionId, content);
|
|
613
633
|
} else {
|
|
614
|
-
|
|
634
|
+
log2.info({ sessionId, workDir }, "claude.execute: creating new session");
|
|
615
635
|
this.sessionManager.createSession({ sessionId, workDir, resumeId: claudeSessionId, useBrainCore }).then(() => {
|
|
616
636
|
this.sessionManager.sendInput(sessionId, content);
|
|
617
637
|
}).catch((err) => {
|
|
@@ -625,7 +645,7 @@ var HubConnection = class {
|
|
|
625
645
|
return true;
|
|
626
646
|
}
|
|
627
647
|
if (msg.type === "session.create") {
|
|
628
|
-
|
|
648
|
+
log2.info({ sessionId: msg.sessionId }, "session.create");
|
|
629
649
|
this.sessionManager.createSession({
|
|
630
650
|
sessionId: msg.sessionId,
|
|
631
651
|
workDir: msg.workDir,
|
|
@@ -646,13 +666,13 @@ var HubConnection = class {
|
|
|
646
666
|
return true;
|
|
647
667
|
}
|
|
648
668
|
if (msg.type === "session.close") {
|
|
649
|
-
|
|
669
|
+
log2.info({ sessionId: msg.sessionId }, "session.close");
|
|
650
670
|
this.sessionManager.closeSession(msg.sessionId).catch(() => {
|
|
651
671
|
});
|
|
652
672
|
return true;
|
|
653
673
|
}
|
|
654
674
|
if (msg.type === "claude.input") {
|
|
655
|
-
|
|
675
|
+
log2.info({ sessionId: msg.sessionId }, "claude.input");
|
|
656
676
|
this.sessionManager.sendInput(msg.sessionId, msg.content);
|
|
657
677
|
return true;
|
|
658
678
|
}
|
|
@@ -668,17 +688,17 @@ var HubConnection = class {
|
|
|
668
688
|
for (const id of allIds) {
|
|
669
689
|
if (!recoverableIds.has(id)) {
|
|
670
690
|
deleteSwarmSnapshot(id);
|
|
671
|
-
|
|
691
|
+
log2.info({ swarmId: id }, "cleaned up non-recoverable swarm snapshot");
|
|
672
692
|
}
|
|
673
693
|
}
|
|
674
694
|
for (const snap of snapshots) {
|
|
675
|
-
|
|
695
|
+
log2.info({ swarmId: snap.id }, "recovering swarm");
|
|
676
696
|
recoverSwarm(this.swarmCoordinator, snap).catch((err) => {
|
|
677
|
-
|
|
697
|
+
log2.error({ err, swarmId: snap.id }, "failed to recover swarm");
|
|
678
698
|
});
|
|
679
699
|
}
|
|
680
700
|
} catch (err) {
|
|
681
|
-
|
|
701
|
+
log2.error({ err }, "swarm recovery failed");
|
|
682
702
|
}
|
|
683
703
|
}
|
|
684
704
|
sendRaw(data) {
|
|
@@ -828,8 +848,8 @@ import { SwarmCoordinator, initRoles } from "@mclawnet/swarm";
|
|
|
828
848
|
// src/brain-bridge.ts
|
|
829
849
|
import { existsSync as existsSync3, readFileSync as readFileSync3, readdirSync as readdirSync2 } from "fs";
|
|
830
850
|
import { join as join3 } from "path";
|
|
831
|
-
import { createLogger as
|
|
832
|
-
var
|
|
851
|
+
import { createLogger as createLogger3 } from "@mclawnet/logger";
|
|
852
|
+
var log3 = createLogger3({ module: "brain-bridge" });
|
|
833
853
|
var BrainBridge = class {
|
|
834
854
|
constructor(hub, options) {
|
|
835
855
|
this.hub = hub;
|
|
@@ -837,7 +857,7 @@ var BrainBridge = class {
|
|
|
837
857
|
this.brainHome = options?.brainHomePath || process.env.BRAIN_HOME || join3(home, "BrainData");
|
|
838
858
|
this.brainCorePath = options?.brainCorePath || join3(home, ".brain", "BrainCore");
|
|
839
859
|
this.hub.registerNamespace("brain", (msg) => this.handleRequest(msg));
|
|
840
|
-
|
|
860
|
+
log3.info(
|
|
841
861
|
{ brainHome: this.brainHome, brainCorePath: this.brainCorePath },
|
|
842
862
|
"BrainBridge initialized"
|
|
843
863
|
);
|
|
@@ -845,17 +865,17 @@ var BrainBridge = class {
|
|
|
845
865
|
brainHome;
|
|
846
866
|
brainCorePath;
|
|
847
867
|
async handleRequest(msg) {
|
|
848
|
-
|
|
868
|
+
log3.info({ action: msg.action, requestId: msg.requestId }, "brain request");
|
|
849
869
|
switch (msg.action) {
|
|
850
870
|
case "setup_status": {
|
|
851
871
|
const status = this.checkSetup();
|
|
852
|
-
|
|
872
|
+
log3.info({ status }, "setup_status result");
|
|
853
873
|
return { status };
|
|
854
874
|
}
|
|
855
875
|
case "get_briefing":
|
|
856
876
|
return await this.getBriefing(msg.params.date);
|
|
857
877
|
default:
|
|
858
|
-
|
|
878
|
+
log3.warn({ action: msg.action }, "unknown brain action");
|
|
859
879
|
throw new Error(`Unknown brain action: ${msg.action}`);
|
|
860
880
|
}
|
|
861
881
|
}
|
|
@@ -878,15 +898,15 @@ var BrainBridge = class {
|
|
|
878
898
|
const targetDate = date || (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
879
899
|
const reportsDir = join3(this.brainHome, "reports", "daily");
|
|
880
900
|
if (!existsSync3(reportsDir)) {
|
|
881
|
-
|
|
901
|
+
log3.info({ reportsDir }, "get_briefing: reports dir not found");
|
|
882
902
|
return { briefing: null, actions: [], projects: [], meetings: [] };
|
|
883
903
|
}
|
|
884
904
|
const files = readdirSync2(reportsDir).filter((f) => f.includes(targetDate) && f.endsWith(".md")).sort().reverse();
|
|
885
905
|
if (files.length === 0) {
|
|
886
|
-
|
|
906
|
+
log3.info({ targetDate }, "get_briefing: no report for date");
|
|
887
907
|
return { briefing: null, actions: [], projects: [], meetings: [] };
|
|
888
908
|
}
|
|
889
|
-
|
|
909
|
+
log3.info({ targetDate, file: files[0] }, "get_briefing: reading report");
|
|
890
910
|
const content = readFileSync3(join3(reportsDir, files[0]), "utf-8");
|
|
891
911
|
const tldrMatch = content.match(/## TL;DR\n([\s\S]*?)(?=\n##|\n$)/);
|
|
892
912
|
const tldr = tldrMatch ? tldrMatch[1].trim() : content.slice(0, 200);
|
|
@@ -907,29 +927,29 @@ var BrainBridge = class {
|
|
|
907
927
|
};
|
|
908
928
|
|
|
909
929
|
// src/start.ts
|
|
910
|
-
import { createLogger as
|
|
911
|
-
var
|
|
930
|
+
import { createLogger as createLogger4 } from "@mclawnet/logger";
|
|
931
|
+
var log4 = createLogger4({ module: "agent" });
|
|
912
932
|
async function startAgent(options) {
|
|
913
933
|
const config = loadConfig(options.config);
|
|
914
934
|
if (!config.token) {
|
|
915
|
-
|
|
935
|
+
log4.error("no token configured \u2014 set CLAWNET_TOKEN or use --token");
|
|
916
936
|
process.exit(1);
|
|
917
937
|
}
|
|
918
|
-
|
|
919
|
-
|
|
938
|
+
log4.info({ backend: options.adapter.type }, "starting agent");
|
|
939
|
+
log4.info({ hubUrl: config.hubUrl }, "connecting to hub");
|
|
920
940
|
await initRoles();
|
|
921
941
|
const hub = new HubConnection({
|
|
922
942
|
hubUrl: config.hubUrl,
|
|
923
943
|
token: config.token,
|
|
924
944
|
hostname: config.name,
|
|
925
945
|
onConnect: (agentId) => {
|
|
926
|
-
|
|
946
|
+
log4.info({ agentId }, "connected to hub");
|
|
927
947
|
},
|
|
928
948
|
onDisconnect: (code, reason) => {
|
|
929
|
-
|
|
949
|
+
log4.info({ code, reason }, "disconnected from hub");
|
|
930
950
|
},
|
|
931
951
|
onError: (err) => {
|
|
932
|
-
|
|
952
|
+
log4.error({ err }, "hub connection error");
|
|
933
953
|
}
|
|
934
954
|
});
|
|
935
955
|
let swarmCoordinator;
|
|
@@ -966,7 +986,7 @@ async function startAgent(options) {
|
|
|
966
986
|
hub.setSwarmCoordinator(swarmCoordinator);
|
|
967
987
|
const brainBridge = new BrainBridge(hub);
|
|
968
988
|
const shutdown = async () => {
|
|
969
|
-
|
|
989
|
+
log4.info("shutting down");
|
|
970
990
|
await sessionManager.closeAll();
|
|
971
991
|
hub.destroy();
|
|
972
992
|
process.exit(0);
|
|
@@ -985,4 +1005,4 @@ export {
|
|
|
985
1005
|
BrainBridge,
|
|
986
1006
|
startAgent
|
|
987
1007
|
};
|
|
988
|
-
//# sourceMappingURL=chunk-
|
|
1008
|
+
//# sourceMappingURL=chunk-HWECDH3X.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/config.ts","../src/hub-connection.ts","../src/fs-handler.ts","../src/session-manager.ts","../src/start.ts","../src/brain-bridge.ts"],"sourcesContent":["import { readFileSync, writeFileSync, mkdirSync, existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { homedir, hostname } from \"node:os\";\nimport type { BackendType } from \"@mclawnet/shared\";\nimport { createLogger } from \"@mclawnet/logger\";\n\nconst log = createLogger({ module: \"config\" });\n\nexport interface EmbeddingConfig {\n /** Embedding provider mode: auto / openai / ollama / hash */\n provider?: string;\n /** OpenAI-compatible API base URL (e.g. http://localhost:4141/v1 for copilot proxy) */\n openaiBaseUrl?: string;\n /** OpenAI API key (use \"dummy\" for copilot proxy) */\n openaiApiKey?: string;\n /** OpenAI embedding model name */\n openaiModel?: string;\n /** Ollama server URL */\n ollamaUrl?: string;\n /** Ollama embedding model name */\n ollamaModel?: string;\n}\n\nexport interface AgentConfig {\n hubUrl: string;\n token: string;\n name: string;\n backendType: BackendType;\n embedding?: EmbeddingConfig;\n}\n\nconst CONFIG_DIR = join(homedir(), \".clawnet\");\nconst SETTINGS_FILE = join(CONFIG_DIR, \"settings.json\");\n\nconst DEFAULT_HUB_URL = process.env.CLAWNET_DEFAULT_HUB_URL || \"ws://localhost:3000/ws/agent\";\n\nconst DEFAULTS: AgentConfig = {\n hubUrl: DEFAULT_HUB_URL,\n token: \"\",\n name: hostname(),\n backendType: \"claude-code\",\n};\n\n/** Ensure hubUrl uses ws(s):// protocol and ends with /ws/agent */\nfunction normalizeHubUrl(url: string): string {\n // Convert http(s):// to ws(s)://\n url = url.replace(/^https:\\/\\//, \"wss://\").replace(/^http:\\/\\//, \"ws://\");\n // Default to wss:// if no protocol\n if (!/^wss?:\\/\\//.test(url)) url = \"wss://\" + url;\n if (url.endsWith(\"/ws/agent\")) return url;\n return url.replace(/\\/+$/, \"\") + \"/ws/agent\";\n}\n\n/**\n * Map structured embedding config to CLAWNET_* env vars.\n * Only sets vars that are not already defined in process.env.\n */\nfunction applyEmbeddingConfig(embedding: EmbeddingConfig): void {\n const mapping: Array<[keyof EmbeddingConfig, string]> = [\n [\"provider\", \"CLAWNET_EMBEDDING_PROVIDER\"],\n [\"openaiBaseUrl\", \"CLAWNET_OPENAI_BASE_URL\"],\n [\"openaiApiKey\", \"CLAWNET_OPENAI_API_KEY\"],\n [\"openaiModel\", \"CLAWNET_OPENAI_EMBEDDING_MODEL\"],\n [\"ollamaUrl\", \"CLAWNET_OLLAMA_URL\"],\n [\"ollamaModel\", \"CLAWNET_OLLAMA_MODEL\"],\n ];\n\n for (const [configKey, envKey] of mapping) {\n const value = embedding[configKey];\n if (value !== undefined && process.env[envKey] === undefined) {\n process.env[envKey] = value;\n }\n }\n}\n\n/** Load config: CLI opts > env vars > settings file > defaults */\nexport function loadConfig(cliOpts: Partial<AgentConfig> = {}): AgentConfig {\n let fileConfig: Partial<AgentConfig> = {};\n\n log.info({ path: SETTINGS_FILE }, \"loading config\");\n\n if (existsSync(SETTINGS_FILE)) {\n try {\n fileConfig = JSON.parse(readFileSync(SETTINGS_FILE, \"utf-8\"));\n log.info(\n { hubUrl: fileConfig.hubUrl, hasToken: !!fileConfig.token, name: fileConfig.name },\n \"settings.json loaded\"\n );\n } catch (e) {\n log.warn({ err: e }, \"failed to parse settings.json\");\n }\n } else {\n log.warn(\"settings.json not found\");\n }\n\n // Apply structured embedding config to process.env\n if (fileConfig.embedding) {\n applyEmbeddingConfig(fileConfig.embedding);\n }\n\n const hubUrl =\n cliOpts.hubUrl ??\n process.env.CLAWNET_HUB_URL ??\n fileConfig.hubUrl ??\n DEFAULTS.hubUrl;\n\n const resolved = {\n hubUrl: normalizeHubUrl(hubUrl),\n token:\n cliOpts.token ??\n process.env.CLAWNET_TOKEN ??\n fileConfig.token ??\n DEFAULTS.token,\n name:\n cliOpts.name ??\n process.env.CLAWNET_NAME ??\n fileConfig.name ??\n DEFAULTS.name,\n backendType:\n (cliOpts.backendType as BackendType) ??\n (process.env.CLAWNET_BACKEND_TYPE as BackendType) ??\n (fileConfig.backendType as BackendType) ??\n DEFAULTS.backendType,\n embedding: fileConfig.embedding,\n };\n\n log.info(\n {\n hubUrl: resolved.hubUrl,\n hubUrlSource: cliOpts.hubUrl ? \"cli\" : process.env.CLAWNET_HUB_URL ? \"env\" : fileConfig.hubUrl ? \"file\" : \"default\",\n tokenSource: cliOpts.token ? \"cli\" : process.env.CLAWNET_TOKEN ? \"env\" : fileConfig.token ? \"file\" : \"default\",\n hasToken: !!resolved.token,\n },\n \"config resolved\"\n );\n\n return resolved;\n}\n\n/** Save config to ~/.clawnet/settings.json */\nexport function saveConfig(config: Partial<AgentConfig>): void {\n mkdirSync(CONFIG_DIR, { recursive: true });\n\n let existing: Partial<AgentConfig> = {};\n if (existsSync(SETTINGS_FILE)) {\n try {\n existing = JSON.parse(readFileSync(SETTINGS_FILE, \"utf-8\"));\n } catch {\n // ignore\n }\n }\n\n const merged = { ...existing, ...config };\n writeFileSync(SETTINGS_FILE, JSON.stringify(merged, null, 2) + \"\\n\");\n}\n","import { hostname as osHostname } from \"node:os\";\nimport WebSocket from \"ws\";\nimport {\n HEARTBEAT_INTERVAL_MS,\n DEFAULT_RECONNECT_MS,\n MAX_RECONNECT_MS,\n WS_CLOSE_INVALID_TOKEN,\n} from \"@mclawnet/shared\";\nimport type {\n AgentServerMessage,\n AgentClientMessage,\n AgentGenericRequest,\n} from \"@mclawnet/shared\";\nimport type { SessionManager } from \"./session-manager.js\";\nimport type { SwarmCoordinator } from \"@mclawnet/swarm\";\nimport { listRecoverableSwarms, recoverSwarm, listRoles, loadRole, listRecoverableSwarmIds, deleteSwarmSnapshot } from \"@mclawnet/swarm\";\nimport { handleListDir, handleListFolders, handleListHistorySessions, handleLoadSessionHistory } from \"./fs-handler.js\";\nimport { createLogger } from \"@mclawnet/logger\";\n\nconst log = createLogger({ module: \"agent\" });\n\nexport interface HubConnectionOptions {\n hubUrl: string;\n token: string;\n hostname?: string;\n version?: string;\n capabilities?: string[];\n heartbeatInterval?: number;\n reconnectDelay?: number;\n maxReconnectDelay?: number;\n onMessage?: (data: unknown) => void;\n onConnect?: (agentId: string) => void;\n onDisconnect?: (code: number, reason: string) => void;\n onError?: (err: Error) => void;\n}\n\ntype AuthState = \"pending\" | \"authenticating\" | \"authenticated\";\n\nexport class HubConnection {\n private ws: WebSocket | null = null;\n private heartbeatTimer: ReturnType<typeof setInterval> | null = null;\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n private reconnectDelay: number;\n private destroyed = false;\n private authState: AuthState = \"pending\";\n\n readonly hubUrl: string;\n readonly token: string;\n readonly hostname: string;\n readonly version: string | undefined;\n readonly capabilities: string[] | undefined;\n readonly heartbeatInterval: number;\n readonly maxReconnectDelay: number;\n\n /** Agent ID assigned by Hub after successful auth */\n agentId: string | null = null;\n\n /** Swarm IDs that have been completed/failed — prevents accidental recreation */\n private finishedSwarms = new Set<string>();\n\n /** Session manager — set after construction via setSessionManager() */\n private sessionManager: SessionManager | null = null;\n\n /** Swarm coordinator — set after construction via setSwarmCoordinator() */\n private swarmCoordinator: SwarmCoordinator | null = null;\n\n /** Namespace-based generic message handlers */\n private namespaceHandlers = new Map<\n string,\n (msg: AgentGenericRequest) => Promise<Record<string, unknown>>\n >();\n\n private onMessage?: (data: unknown) => void;\n private onConnectCb?: (agentId: string) => void;\n private onDisconnect?: (code: number, reason: string) => void;\n private onError?: (err: Error) => void;\n\n constructor(opts: HubConnectionOptions) {\n this.hubUrl = opts.hubUrl;\n this.token = opts.token;\n this.hostname = opts.hostname ?? osHostname();\n this.version = opts.version;\n this.capabilities = opts.capabilities;\n this.heartbeatInterval = opts.heartbeatInterval ?? HEARTBEAT_INTERVAL_MS;\n this.reconnectDelay = opts.reconnectDelay ?? DEFAULT_RECONNECT_MS;\n this.maxReconnectDelay = opts.maxReconnectDelay ?? MAX_RECONNECT_MS;\n this.onMessage = opts.onMessage;\n this.onConnectCb = opts.onConnect;\n this.onDisconnect = opts.onDisconnect;\n this.onError = opts.onError;\n }\n\n setSessionManager(manager: SessionManager): void {\n this.sessionManager = manager;\n }\n\n setSwarmCoordinator(coordinator: SwarmCoordinator): void {\n this.swarmCoordinator = coordinator;\n }\n\n registerNamespace(\n namespace: string,\n handler: (msg: AgentGenericRequest) => Promise<Record<string, unknown>>\n ) {\n this.namespaceHandlers.set(namespace, handler);\n }\n\n sendPush(namespace: string, event: string, data: Record<string, unknown>) {\n this.send({\n type: \"generic.push\",\n namespace,\n event,\n data,\n });\n }\n\n get readyState(): number {\n return this.ws?.readyState ?? WebSocket.CLOSED;\n }\n\n get isConnected(): boolean {\n return this.ws?.readyState === WebSocket.OPEN && this.authState === \"authenticated\";\n }\n\n connect(): void {\n if (this.destroyed) return;\n this.cleanup();\n this.authState = \"pending\";\n\n this.ws = new WebSocket(this.hubUrl);\n\n this.ws.on(\"open\", () => {\n this.reconnectDelay = DEFAULT_RECONNECT_MS;\n });\n\n this.ws.on(\"message\", (raw) => {\n let data: AgentServerMessage;\n try {\n data = JSON.parse(raw.toString());\n } catch {\n return;\n }\n\n // Step 1: Hub sends auth_required → reply with auth\n if (this.authState === \"pending\" && data.type === \"auth_required\") {\n log.info(\"hub requires auth, sending credentials\");\n this.authState = \"authenticating\";\n this.sendRaw({\n type: \"auth\",\n token: this.token,\n hostname: this.hostname,\n version: this.version,\n capabilities: this.capabilities,\n });\n return;\n }\n\n // Step 2: Hub sends registered → auth complete\n if (this.authState === \"authenticating\" && data.type === \"registered\") {\n log.info({ agentId: data.agentId }, \"registered with hub\");\n this.authState = \"authenticated\";\n this.agentId = data.agentId ?? null;\n this.startHeartbeat();\n this.onConnectCb?.(this.agentId!);\n\n // Attempt to recover any persisted swarms\n this.tryRecoverSwarms();\n return;\n }\n\n // Post-auth message handling\n if (this.authState === \"authenticated\") {\n if (this.handleSessionMessage(data)) return;\n this.onMessage?.(data);\n }\n });\n\n this.ws.on(\"close\", (code, reason) => {\n log.info({ code, reason: reason.toString() }, \"ws connection closed\");\n this.stopHeartbeat();\n this.authState = \"pending\";\n this.onDisconnect?.(code, reason.toString());\n if (code === WS_CLOSE_INVALID_TOKEN) {\n log.error(\"auth failed — not reconnecting, check your token\");\n return;\n }\n this.scheduleReconnect();\n });\n\n this.ws.on(\"error\", (err) => {\n log.error({ err }, \"ws connection error\");\n this.onError?.(err);\n });\n }\n\n send(data: AgentClientMessage): boolean {\n // Track swarm completion to prevent accidental recreation\n const msg = data as any;\n if (msg.type === \"swarm.status\" && (msg.swarmStatus === \"completed\" || msg.swarmStatus === \"failed\")) {\n this.finishedSwarms.add(msg.sessionId);\n }\n return this.sendRaw(data);\n }\n\n destroy(): void {\n this.destroyed = true;\n this.cleanup();\n }\n\n // ── Session message handling ─────────────────────────────────────\n\n private handleSessionMessage(msg: AgentServerMessage): boolean {\n // ── Filesystem / history requests (no sessionManager needed) ─────\n\n if (msg.type === \"fs.list_dir\") {\n log.info({ path: msg.path }, \"fs.list_dir\");\n handleListDir(msg.path)\n .then((result) => {\n this.send({ type: \"fs.list_dir_result\", requestId: msg.requestId, ...result });\n })\n .catch((err: any) => {\n log.error({ err, path: msg.path }, \"fs.list_dir failed\");\n this.send({\n type: \"fs.list_dir_result\",\n requestId: msg.requestId,\n path: msg.path || \"/\",\n entries: [],\n });\n });\n return true;\n }\n\n if (msg.type === \"list_folders\") {\n log.info(\"list_folders\");\n handleListFolders()\n .then((result) => {\n this.send({ type: \"folders_list_result\", requestId: msg.requestId, ...result });\n })\n .catch((err: any) => {\n log.error({ err }, \"list_folders failed\");\n this.send({ type: \"folders_list_result\", requestId: msg.requestId, folders: [] });\n });\n return true;\n }\n\n if (msg.type === \"list_history_sessions\") {\n log.info({ workDir: msg.workDir }, \"list_history_sessions\");\n handleListHistorySessions(msg.workDir)\n .then((result) => {\n this.send({ type: \"history_sessions_result\", requestId: msg.requestId, ...result });\n })\n .catch((err: any) => {\n log.error({ err, workDir: msg.workDir }, \"list_history_sessions failed\");\n this.send({\n type: \"history_sessions_result\",\n requestId: msg.requestId,\n workDir: msg.workDir,\n sessions: [],\n });\n });\n return true;\n }\n\n if (msg.type === \"load_session_history\") {\n log.info({ workDir: msg.workDir, claudeSessionId: msg.claudeSessionId }, \"load_session_history\");\n handleLoadSessionHistory(msg.workDir, msg.claudeSessionId)\n .then((result) => {\n this.send({ type: \"session_history_result\", requestId: msg.requestId, ...result });\n })\n .catch((err: any) => {\n log.error({ err, workDir: msg.workDir }, \"load_session_history failed\");\n this.send({ type: \"session_history_result\", requestId: msg.requestId, messages: [] });\n });\n return true;\n }\n\n // ── Swarm handling (requires swarmCoordinator) ──────────────────────\n\n if (msg.type === \"list_roles\") {\n log.info(\"list_roles\");\n const roleNames = listRoles();\n const roles = roleNames.map((name) => {\n try {\n const def = loadRole(name);\n return {\n name: def.name,\n displayName: def.shortName || def.name,\n description: def.description || \"\",\n capabilities: def.capabilities || [],\n promptBody: def.promptBody || \"\",\n };\n } catch {\n return { name, displayName: name, description: \"\", capabilities: [], promptBody: \"\" };\n }\n });\n this.send({\n type: \"roles_list_result\",\n sessionId: (msg as any).sessionId,\n roles,\n } as any);\n return true;\n }\n\n // ── Generic request: dispatch to registered namespace handlers ──\n if (msg.type === \"generic.request\") {\n const handler = this.namespaceHandlers.get(msg.namespace);\n if (handler) {\n log.info({ namespace: msg.namespace, action: msg.action, requestId: msg.requestId }, \"generic.request received\");\n handler(msg)\n .then((result) => {\n log.info({ namespace: msg.namespace, action: msg.action, requestId: msg.requestId }, \"generic.request handled OK\");\n this.send({\n type: \"generic.response\",\n namespace: msg.namespace,\n action: msg.action,\n data: result,\n requestId: msg.requestId,\n });\n })\n .catch((err) => {\n log.error({ namespace: msg.namespace, action: msg.action, requestId: msg.requestId, err }, \"generic.request handler error\");\n this.send({\n type: \"generic.response\",\n namespace: msg.namespace,\n action: msg.action,\n data: {},\n requestId: msg.requestId,\n error: err instanceof Error ? err.message : String(err),\n });\n });\n return true;\n }\n log.warn({ namespace: msg.namespace, action: msg.action, requestId: msg.requestId }, \"generic.request unknown namespace\");\n this.send({\n type: \"generic.response\",\n namespace: msg.namespace,\n action: msg.action,\n data: {},\n requestId: msg.requestId,\n error: `Unknown namespace: ${msg.namespace}`,\n });\n return true;\n }\n\n if (msg.type === \"swarm.execute\" && this.swarmCoordinator) {\n const { sessionId, content, workDir, targetInstance, crewConfig } = msg;\n\n if (this.swarmCoordinator.hasSwarm(sessionId)) {\n // Existing swarm — forward user message\n log.info({ sessionId, targetInstance }, \"swarm.execute: forwarding to existing swarm\");\n this.swarmCoordinator.handleUserMessage(sessionId, content, targetInstance).catch((err) => {\n this.send({\n type: \"session.error\",\n sessionId,\n error: err instanceof Error ? err.message : String(err),\n });\n });\n } else if (this.finishedSwarms.has(sessionId)) {\n // Swarm already completed/failed — don't recreate\n log.info({ sessionId }, \"swarm.execute ignored: swarm already finished\");\n this.send({\n type: \"session.error\",\n sessionId,\n error: \"蜂群任务已完成,无法继续操作。请创建新的蜂群任务。\",\n });\n } else if (crewConfig?.roles) {\n // Explicit create: crewConfig with roles provided — create new swarm\n log.info({ sessionId, rolesCount: crewConfig.roles.length }, \"swarm.execute: creating new swarm\");\n const roles = crewConfig.roles;\n this.swarmCoordinator.create(sessionId, { workDir, roles, task: content }).catch((err) => {\n this.send({\n type: \"session.error\",\n sessionId,\n error: err instanceof Error ? err.message : String(err),\n });\n });\n } else {\n // No swarm and no crewConfig — shouldn't happen normally\n log.info({ sessionId }, \"swarm.execute ignored: swarm not found, no config\");\n this.send({\n type: \"session.error\",\n sessionId,\n error: \"蜂群任务已完成,无法继续操作。请创建新的蜂群任务。\",\n });\n }\n return true;\n }\n\n // ── Session management (requires sessionManager) ─────────────────\n\n if (!this.sessionManager) return false;\n\n if (msg.type === \"abort_execution\") {\n const { sessionId } = msg;\n log.info({ sessionId }, \"abort_execution\");\n if (this.sessionManager?.hasSession(sessionId)) {\n this.sessionManager.abortSession(sessionId).then(() => {\n this.send({ type: \"execution_aborted\", sessionId } as any);\n }).catch(() => {\n this.send({ type: \"execution_aborted\", sessionId } as any);\n });\n } else {\n // No active session — just acknowledge\n this.send({ type: \"execution_aborted\", sessionId } as any);\n }\n return true;\n }\n\n // claude.execute — auto-create session if needed, then send input\n if (msg.type === \"claude.execute\") {\n const { sessionId, content, workDir, claudeSessionId, useBrainCore } = msg;\n if (this.sessionManager.hasSession(sessionId)) {\n log.info({ sessionId }, \"claude.execute: reusing existing session\");\n this.sessionManager.sendInput(sessionId, content);\n } else {\n log.info({ sessionId, workDir }, \"claude.execute: creating new session\");\n this.sessionManager\n .createSession({ sessionId, workDir, resumeId: claudeSessionId, useBrainCore })\n .then(() => {\n this.sessionManager!.sendInput(sessionId, content);\n })\n .catch((err) => {\n this.send({\n type: \"session.error\",\n sessionId,\n error: err instanceof Error ? err.message : String(err),\n });\n });\n }\n return true;\n }\n\n if (msg.type === \"session.create\") {\n log.info({ sessionId: msg.sessionId }, \"session.create\");\n this.sessionManager\n .createSession({\n sessionId: msg.sessionId,\n workDir: msg.workDir,\n resumeId: msg.resumeId,\n })\n .then((claudeSessionId) => {\n this.send({\n type: \"session.created\",\n sessionId: msg.sessionId,\n claudeSessionId,\n });\n })\n .catch((err) => {\n this.send({\n type: \"session.error\",\n sessionId: msg.sessionId,\n error: err instanceof Error ? err.message : String(err),\n });\n });\n return true;\n }\n\n if (msg.type === \"session.close\") {\n log.info({ sessionId: msg.sessionId }, \"session.close\");\n this.sessionManager.closeSession(msg.sessionId).catch(() => {});\n return true;\n }\n\n if (msg.type === \"claude.input\") {\n log.info({ sessionId: msg.sessionId }, \"claude.input\");\n this.sessionManager.sendInput(msg.sessionId, msg.content);\n return true;\n }\n\n return false;\n }\n\n // ── Internal helpers ─────────────────────────────────────────────\n\n private tryRecoverSwarms(): void {\n if (!this.swarmCoordinator) return;\n try {\n const allIds = listRecoverableSwarmIds();\n const snapshots = listRecoverableSwarms();\n const recoverableIds = new Set(snapshots.map((s) => s.id));\n\n // Clean up expired/completed/failed snapshots\n for (const id of allIds) {\n if (!recoverableIds.has(id)) {\n deleteSwarmSnapshot(id);\n log.info({ swarmId: id }, \"cleaned up non-recoverable swarm snapshot\");\n }\n }\n\n for (const snap of snapshots) {\n log.info({ swarmId: snap.id }, \"recovering swarm\");\n recoverSwarm(this.swarmCoordinator, snap).catch((err) => {\n log.error({ err, swarmId: snap.id }, \"failed to recover swarm\");\n });\n }\n } catch (err) {\n log.error({ err }, \"swarm recovery failed\");\n }\n }\n\n private sendRaw(data: unknown): boolean {\n if (!this.ws || this.ws.readyState !== WebSocket.OPEN) return false;\n this.ws.send(JSON.stringify(data));\n return true;\n }\n\n private startHeartbeat(): void {\n this.stopHeartbeat();\n this.heartbeatTimer = setInterval(() => {\n this.send({ type: \"heartbeat\", ts: Date.now() });\n }, this.heartbeatInterval);\n }\n\n private stopHeartbeat(): void {\n if (this.heartbeatTimer) {\n clearInterval(this.heartbeatTimer);\n this.heartbeatTimer = null;\n }\n }\n\n private scheduleReconnect(): void {\n if (this.destroyed) return;\n this.reconnectTimer = setTimeout(() => {\n this.connect();\n }, this.reconnectDelay);\n this.reconnectDelay = Math.min(this.reconnectDelay * 2, this.maxReconnectDelay);\n }\n\n private cleanup(): void {\n this.stopHeartbeat();\n this.sessionManager?.closeAll().catch(() => {});\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n if (this.ws) {\n this.ws.removeAllListeners();\n if (this.ws.readyState === WebSocket.OPEN || this.ws.readyState === WebSocket.CONNECTING) {\n this.ws.close();\n }\n this.ws = null;\n }\n }\n}\n","import { readdir, stat, readFile } from \"node:fs/promises\";\nimport { existsSync, readdirSync, statSync, readFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nconst SKIP_DIRS = new Set([\".git\", \"node_modules\", \"__pycache__\", \".next\", \".nuxt\", \".cache\"]);\n\n// ── fs.list_dir ─────────────────────────────────────────────────────\n\nexport async function handleListDir(\n path: string,\n): Promise<{ path: string; entries: Array<{ name: string; type: \"directory\" | \"file\" }> }> {\n const target = path || \"/\";\n const dirents = await readdir(target, { withFileTypes: true });\n\n const entries = dirents\n .filter((d) => !(d.isDirectory() && SKIP_DIRS.has(d.name)))\n .map((d) => ({\n name: d.name,\n type: (d.isDirectory() ? \"directory\" : \"file\") as \"directory\" | \"file\",\n }))\n .sort((a, b) => {\n if (a.type !== b.type) return a.type === \"directory\" ? -1 : 1;\n return a.name.localeCompare(b.name);\n });\n\n return { path: target, entries };\n}\n\n// ── list_folders (scan ~/.claude/projects/) ──────────────────────────\n\nfunction getClaudeProjectsDir(): string {\n return join(homedir(), \".claude\", \"projects\");\n}\n\nfunction pathToProjectFolder(workDir: string): string {\n return workDir.replace(/:/g, \"-\").replace(/[/\\\\]/g, \"-\");\n}\n\nfunction extractWorkDirFromSessionFile(filePath: string): string | null {\n try {\n const content = readFileSync(filePath, \"utf-8\");\n const lines = content.split(\"\\n\").filter((l) => l.trim());\n for (const line of lines.slice(0, 5)) {\n try {\n const data = JSON.parse(line);\n if (data.cwd) return data.cwd.replace(/\\\\/g, \"/\");\n } catch {}\n }\n } catch {}\n return null;\n}\n\nfunction getWorkDirFromProjectFolder(folderPath: string, folderName: string): string {\n try {\n const files = readdirSync(folderPath);\n for (const file of files) {\n if (file.endsWith(\".jsonl\")) {\n const workDir = extractWorkDirFromSessionFile(join(folderPath, file));\n if (workDir) return workDir;\n }\n }\n } catch {}\n\n // Fallback: simple conversion\n if (/^[A-Za-z]--/.test(folderName)) {\n return folderName.replace(/^([A-Za-z])--/, \"$1:/\").replace(/-/g, \"/\");\n }\n if (folderName.startsWith(\"-\")) {\n return \"/\" + folderName.substring(1).replace(/-/g, \"/\");\n }\n return folderName.replace(/-/g, \"/\");\n}\n\nexport async function handleListFolders(): Promise<{\n folders: Array<{ path: string; sessionCount: number; lastModified?: number }>;\n}> {\n const projectsDir = getClaudeProjectsDir();\n const folders: Array<{ path: string; sessionCount: number; lastModified?: number }> = [];\n\n if (!existsSync(projectsDir)) return { folders };\n\n const entries = readdirSync(projectsDir);\n for (const entry of entries) {\n const entryPath = join(projectsDir, entry);\n let entryStat;\n try {\n entryStat = statSync(entryPath);\n } catch {\n continue;\n }\n if (!entryStat.isDirectory()) continue;\n\n // Skip crew role directories\n if (entry.includes(\"--crew-roles-\")) continue;\n\n const originalPath = getWorkDirFromProjectFolder(entryPath, entry);\n\n let sessionCount = 0;\n let lastModified = entryStat.mtime.getTime();\n\n try {\n const files = readdirSync(entryPath);\n for (const file of files) {\n if (file.endsWith(\".jsonl\")) {\n sessionCount++;\n try {\n const fileStats = statSync(join(entryPath, file));\n if (fileStats.mtime.getTime() > lastModified) {\n lastModified = fileStats.mtime.getTime();\n }\n } catch {}\n }\n }\n } catch {}\n\n folders.push({ path: originalPath, sessionCount, lastModified });\n }\n\n folders.sort((a, b) => (b.lastModified ?? 0) - (a.lastModified ?? 0));\n return { folders };\n}\n\n// ── list_history_sessions ───────────────────────────────────────────\n\nexport async function handleListHistorySessions(workDir: string): Promise<{\n workDir: string;\n sessions: Array<{ sessionId: string; title: string; workDir?: string; lastModified?: number }>;\n}> {\n const projectsDir = getClaudeProjectsDir();\n const projectFolder = pathToProjectFolder(workDir);\n const projectPath = join(projectsDir, projectFolder);\n\n if (!existsSync(projectPath)) {\n return { workDir, sessions: [] };\n }\n\n const sessions: Array<{ sessionId: string; title: string; workDir?: string; lastModified?: number }> = [];\n const files = readdirSync(projectPath);\n\n for (const file of files) {\n if (!file.endsWith(\".jsonl\")) continue;\n\n const sessionId = file.replace(\".jsonl\", \"\");\n const filePath = join(projectPath, file);\n let fileStats;\n try {\n fileStats = statSync(filePath);\n } catch {\n continue;\n }\n\n let title = \"\";\n let hasUserMessage = false;\n let customTitle = \"\";\n let jsonlSummary = \"\";\n\n try {\n const content = readFileSync(filePath, \"utf-8\");\n const lines = content.split(\"\\n\").filter((l) => l.trim());\n\n for (const line of lines) {\n try {\n const data = JSON.parse(line);\n if (!hasUserMessage && data.type === \"user\" && data.message?.content) {\n const text =\n typeof data.message.content === \"string\"\n ? data.message.content\n : data.message.content[0]?.text || \"\";\n if (text.trim()) {\n title = text.substring(0, 100);\n hasUserMessage = true;\n }\n }\n if (data.type === \"custom-title\" && data.customTitle) {\n customTitle = data.customTitle;\n }\n if (data.type === \"summary\" && data.summary) {\n jsonlSummary = data.summary;\n }\n } catch {}\n }\n } catch {}\n\n if (hasUserMessage) {\n sessions.push({\n sessionId,\n title: customTitle || jsonlSummary || title || sessionId.slice(0, 8),\n workDir,\n lastModified: fileStats.mtime.getTime(),\n });\n }\n }\n\n sessions.sort((a, b) => (b.lastModified ?? 0) - (a.lastModified ?? 0));\n return { workDir, sessions };\n}\n\n// ── load_session_history ────────────────────────────────────────────\n\ninterface HistoryMessage {\n role: \"user\" | \"assistant\";\n content: string;\n toolCalls?: Array<{ name: string; input?: string; output?: string; status: string }>;\n thinking?: string;\n}\n\nexport async function handleLoadSessionHistory(\n workDir: string,\n claudeSessionId: string,\n): Promise<{ messages: HistoryMessage[] }> {\n const projectsDir = getClaudeProjectsDir();\n const projectFolder = pathToProjectFolder(workDir);\n const filePath = join(projectsDir, projectFolder, `${claudeSessionId}.jsonl`);\n\n if (!existsSync(filePath)) {\n return { messages: [] };\n }\n\n const messages: HistoryMessage[] = [];\n\n try {\n const content = readFileSync(filePath, \"utf-8\");\n const lines = content.split(\"\\n\").filter((l) => l.trim());\n\n for (const line of lines) {\n try {\n const data = JSON.parse(line);\n\n if (data.type === \"user\" && data.message?.content) {\n const blocks = Array.isArray(data.message.content)\n ? data.message.content\n : [{ type: \"text\", text: String(data.message.content) }];\n\n // Extract user text (only text blocks, skip tool_result etc.)\n const textParts: string[] = [];\n for (const block of blocks) {\n if (block.type === \"text\" && block.text?.trim()) {\n textParts.push(block.text);\n }\n }\n if (textParts.length > 0) {\n messages.push({ role: \"user\", content: textParts.join(\"\\n\") });\n }\n\n // Attach tool_result outputs to the last assistant's toolCalls\n const lastAssistant = messages.length > 0\n ? [...messages].reverse().find((m) => m.role === \"assistant\" && m.toolCalls?.length)\n : undefined;\n if (lastAssistant?.toolCalls) {\n for (const block of blocks) {\n if (block.type === \"tool_result\") {\n // Match by tool_use_id or just fill the next pending one\n const pending = lastAssistant.toolCalls.find((tc) => !tc.output);\n if (pending) {\n pending.output = typeof block.content === \"string\"\n ? block.content\n : Array.isArray(block.content)\n ? block.content.map((c: any) => c.text ?? \"\").join(\"\")\n : JSON.stringify(block.content);\n pending.status = block.is_error ? \"error\" : \"done\";\n }\n }\n }\n }\n }\n\n if (data.type === \"assistant\" && data.message?.content) {\n let text = \"\";\n const toolCalls: HistoryMessage[\"toolCalls\"] = [];\n let thinking = \"\";\n\n for (const block of data.message.content) {\n if (block.type === \"text\") {\n text += block.text;\n } else if (block.type === \"tool_use\") {\n toolCalls.push({\n name: block.name,\n input: typeof block.input === \"string\" ? block.input : JSON.stringify(block.input, null, 2),\n status: \"done\",\n });\n } else if (block.type === \"thinking\") {\n thinking += block.thinking ?? \"\";\n }\n }\n\n messages.push({\n role: \"assistant\",\n content: text,\n toolCalls: toolCalls.length > 0 ? toolCalls : undefined,\n thinking: thinking || undefined,\n });\n }\n } catch {}\n }\n } catch {}\n\n // Return last 50 messages to avoid overloading\n return { messages: messages.slice(-50) };\n}\n","import type { BackendAdapter, BackendProcess, SpawnOptions } from \"./backend-adapter.js\";\n\n/**\n * Manages active sessions, mapping ClawNet session IDs to BackendProcess instances.\n */\nexport class SessionManager {\n private sessions = new Map<string, BackendProcess>();\n private conversationBuffer = new Map<string, Array<{ role: string; content: string }>>();\n private adapter: BackendAdapter;\n private onOutput: (sessionId: string, data: unknown) => void;\n private onTurnComplete: (\n sessionId: string,\n info: {\n claudeSessionId?: string;\n cost?: number;\n duration?: number;\n contextUsage?: { used: number; total: number };\n },\n ) => void;\n private onSessionError: (sessionId: string, error: string) => void;\n private onBeforeClose?: (sessionId: string, messages: Array<{ role: string; content: string }>) => Promise<void>;\n\n constructor(options: {\n adapter: BackendAdapter;\n onOutput: (sessionId: string, data: unknown) => void;\n onTurnComplete: (\n sessionId: string,\n info: {\n claudeSessionId?: string;\n cost?: number;\n duration?: number;\n contextUsage?: { used: number; total: number };\n },\n ) => void;\n onSessionError: (sessionId: string, error: string) => void;\n onBeforeClose?: (sessionId: string, messages: Array<{ role: string; content: string }>) => Promise<void>;\n }) {\n this.adapter = options.adapter;\n this.onOutput = options.onOutput;\n this.onTurnComplete = options.onTurnComplete;\n this.onSessionError = options.onSessionError;\n this.onBeforeClose = options.onBeforeClose;\n }\n\n async createSession(options: SpawnOptions): Promise<string> {\n if (this.sessions.has(options.sessionId)) {\n throw new Error(`Session ${options.sessionId} already exists`);\n }\n\n try {\n const process = await this.adapter.spawn(options);\n this.sessions.set(options.sessionId, process);\n\n // Wire up output handler\n this.adapter.onOutput(process, (data) => {\n // Accumulate assistant text messages for distillation\n const msg = data as any;\n if (msg?.type === \"assistant\" && msg?.message?.content) {\n const buf = this.conversationBuffer.get(options.sessionId) ?? [];\n // Extract text from content blocks\n const text = Array.isArray(msg.message.content)\n ? msg.message.content.filter((b: any) => b.type === \"text\").map((b: any) => b.text).join(\"\\n\")\n : String(msg.message.content);\n if (text) {\n buf.push({ role: \"assistant\", content: text });\n this.conversationBuffer.set(options.sessionId, buf);\n }\n }\n this.onOutput(options.sessionId, data);\n });\n\n // Wire up turn-complete handler\n this.adapter.onTurnComplete?.(process, (info) => {\n this.onTurnComplete(options.sessionId, info);\n });\n\n // Wire up error handler\n this.adapter.onError?.(process, (error) => {\n this.onSessionError(options.sessionId, error.message);\n });\n\n return process.id;\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n this.onSessionError(options.sessionId, message);\n throw err;\n }\n }\n\n sendInput(sessionId: string, input: string): void {\n const process = this.sessions.get(sessionId);\n if (!process) {\n this.onSessionError(sessionId, `No active session: ${sessionId}`);\n return;\n }\n this.adapter.send(process, input);\n }\n\n async abortSession(sessionId: string): Promise<void> {\n const process = this.sessions.get(sessionId);\n if (!process) return;\n // Kill the process but remove from sessions map — a new process will be\n // lazily created on next claude.execute\n this.conversationBuffer.delete(sessionId);\n this.sessions.delete(sessionId);\n await this.adapter.stop(process);\n }\n\n async closeSession(sessionId: string): Promise<void> {\n const process = this.sessions.get(sessionId);\n if (!process) return;\n\n // Trigger distillation before closing\n const messages = this.conversationBuffer.get(sessionId);\n if (this.onBeforeClose && messages?.length) {\n await this.onBeforeClose(sessionId, messages).catch(() => {});\n }\n this.conversationBuffer.delete(sessionId);\n\n this.sessions.delete(sessionId);\n await this.adapter.stop(process);\n }\n\n async closeAll(): Promise<void> {\n const promises = Array.from(this.sessions.entries()).map(\n async ([sessionId, process]) => {\n // Trigger distillation before closing\n const messages = this.conversationBuffer.get(sessionId);\n if (this.onBeforeClose && messages?.length) {\n await this.onBeforeClose(sessionId, messages).catch(() => {});\n }\n this.conversationBuffer.delete(sessionId);\n this.sessions.delete(sessionId);\n await this.adapter.stop(process).catch(() => {});\n },\n );\n await Promise.all(promises);\n }\n\n hasSession(sessionId: string): boolean {\n return this.sessions.has(sessionId);\n }\n\n get activeSessionCount(): number {\n return this.sessions.size;\n }\n}\n","import { loadConfig, type AgentConfig } from \"./config.js\";\nimport { HubConnection } from \"./hub-connection.js\";\nimport { SessionManager } from \"./session-manager.js\";\nimport { SwarmCoordinator, initRoles } from \"@mclawnet/swarm\";\nimport { BrainBridge } from \"./brain-bridge.js\";\nimport type { BackendAdapter } from \"./backend-adapter.js\";\nimport { createLogger } from \"@mclawnet/logger\";\n\nconst log = createLogger({ module: \"agent\" });\n\nexport interface StartOptions {\n config?: Partial<AgentConfig>;\n adapter: BackendAdapter;\n}\n\n/**\n * Start the ClawNet agent: connect to Hub and register a BackendAdapter.\n */\nexport async function startAgent(options: StartOptions): Promise<{\n hub: HubConnection;\n sessionManager: SessionManager;\n swarmCoordinator: SwarmCoordinator;\n brainBridge: BrainBridge;\n}> {\n const config = loadConfig(options.config);\n\n if (!config.token) {\n log.error(\"no token configured — set CLAWNET_TOKEN or use --token\");\n process.exit(1);\n }\n\n log.info({ backend: options.adapter.type }, \"starting agent\");\n log.info({ hubUrl: config.hubUrl }, \"connecting to hub\");\n\n // Initialize role templates\n await initRoles();\n\n const hub = new HubConnection({\n hubUrl: config.hubUrl,\n token: config.token,\n hostname: config.name,\n onConnect: (agentId) => {\n log.info({ agentId }, \"connected to hub\");\n },\n onDisconnect: (code, reason) => {\n log.info({ code, reason }, \"disconnected from hub\");\n },\n onError: (err) => {\n log.error({ err }, \"hub connection error\");\n },\n });\n\n // Create SwarmCoordinator (needs hub reference; sessionManager set after construction)\n // We use a lazy reference so the coordinator can be created before sessionManager\n let swarmCoordinator: SwarmCoordinator;\n\n const sessionManager = new SessionManager({\n adapter: options.adapter,\n onOutput: (sessionId, data) => {\n // Intercept swarm role output\n if (swarmCoordinator.handleRoleOutput(sessionId, data)) return;\n\n // Normal (non-swarm) session output\n hub.send({\n type: \"claude.output\",\n sessionId,\n data,\n });\n },\n onTurnComplete: (sessionId, info) => {\n // Intercept swarm role turn completion\n if (swarmCoordinator.handleRoleTurnComplete(sessionId, info)) return;\n\n // Normal (non-swarm) session\n hub.send({\n type: \"claude.turn_complete\",\n sessionId,\n cost: info.cost,\n duration: info.duration,\n contextUsage: info.contextUsage,\n });\n },\n onSessionError: (sessionId, error) => {\n hub.send({\n type: \"session.error\",\n sessionId,\n error,\n });\n },\n });\n\n swarmCoordinator = new SwarmCoordinator(sessionManager, hub);\n\n hub.setSessionManager(sessionManager);\n hub.setSwarmCoordinator(swarmCoordinator);\n\n // Initialize BrainBridge (registers \"brain\" namespace handler)\n const brainBridge = new BrainBridge(hub);\n\n // Graceful shutdown\n const shutdown = async () => {\n log.info(\"shutting down\");\n await sessionManager.closeAll();\n hub.destroy();\n process.exit(0);\n };\n\n process.on(\"SIGINT\", shutdown);\n process.on(\"SIGTERM\", shutdown);\n\n hub.connect();\n\n return { hub, sessionManager, swarmCoordinator, brainBridge };\n}\n","import { existsSync, readFileSync, readdirSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { createLogger } from \"@mclawnet/logger\";\nimport type { AgentGenericRequest } from \"@mclawnet/shared\";\nimport type { HubConnection } from \"./hub-connection.js\";\n\nconst log = createLogger({ module: \"brain-bridge\" });\n\nexport type BrainSetupStatus = \"not_installed\" | \"needs_config\" | \"ready\";\n\nexport interface BrainBridgeOptions {\n brainHomePath?: string;\n brainCorePath?: string;\n}\n\nexport class BrainBridge {\n private brainHome: string;\n private brainCorePath: string;\n\n constructor(\n private hub: HubConnection,\n options?: BrainBridgeOptions\n ) {\n const home = process.env.HOME || process.env.USERPROFILE || \"\";\n this.brainHome =\n options?.brainHomePath ||\n process.env.BRAIN_HOME ||\n join(home, \"BrainData\");\n this.brainCorePath =\n options?.brainCorePath || join(home, \".brain\", \"BrainCore\");\n\n this.hub.registerNamespace(\"brain\", (msg) => this.handleRequest(msg));\n log.info(\n { brainHome: this.brainHome, brainCorePath: this.brainCorePath },\n \"BrainBridge initialized\"\n );\n }\n\n async handleRequest(\n msg: AgentGenericRequest\n ): Promise<Record<string, unknown>> {\n log.info({ action: msg.action, requestId: msg.requestId }, \"brain request\");\n switch (msg.action) {\n case \"setup_status\": {\n const status = this.checkSetup();\n log.info({ status }, \"setup_status result\");\n return { status };\n }\n case \"get_briefing\":\n return await this.getBriefing(msg.params.date as string | undefined);\n default:\n log.warn({ action: msg.action }, \"unknown brain action\");\n throw new Error(`Unknown brain action: ${msg.action}`);\n }\n }\n\n checkSetup(): BrainSetupStatus {\n if (!existsSync(this.brainCorePath)) {\n return \"not_installed\";\n }\n const home = process.env.HOME || process.env.USERPROFILE || \"\";\n const installJson = join(home, \".brain\", \"install.json\");\n if (!existsSync(installJson)) {\n return \"needs_config\";\n }\n if (!existsSync(this.brainHome)) {\n return \"needs_config\";\n }\n return \"ready\";\n }\n\n /** Read the most recent daily briefing report */\n private async getBriefing(\n date?: string\n ): Promise<Record<string, unknown>> {\n const targetDate = date || new Date().toISOString().slice(0, 10);\n const reportsDir = join(this.brainHome, \"reports\", \"daily\");\n\n if (!existsSync(reportsDir)) {\n log.info({ reportsDir }, \"get_briefing: reports dir not found\");\n return { briefing: null, actions: [], projects: [], meetings: [] };\n }\n\n const files = readdirSync(reportsDir)\n .filter((f: string) => f.includes(targetDate) && f.endsWith(\".md\"))\n .sort()\n .reverse();\n\n if (files.length === 0) {\n log.info({ targetDate }, \"get_briefing: no report for date\");\n return { briefing: null, actions: [], projects: [], meetings: [] };\n }\n\n log.info({ targetDate, file: files[0] }, \"get_briefing: reading report\");\n\n const content = readFileSync(join(reportsDir, files[0]), \"utf-8\");\n\n // Extract TL;DR (first matching section)\n const tldrMatch = content.match(/## TL;DR\\n([\\s\\S]*?)(?=\\n##|\\n$)/);\n const tldr = tldrMatch ? tldrMatch[1].trim() : content.slice(0, 200);\n\n return {\n briefing: {\n date: targetDate,\n tldr,\n generatedAt: new Date().toISOString(),\n },\n actions: [], // Phase 2: detailed parsing\n projects: [], // Phase 2\n meetings: [], // Phase 2\n };\n }\n}\n"],"mappings":"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","names":["existsSync","readFileSync","homedir","join","createLogger","log","process","existsSync","readFileSync","readdirSync","join","createLogger","log","createLogger","log"]}
|
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAKpD,MAAM,WAAW,eAAe;IAC9B,6DAA6D;IAC7D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,uFAAuF;IACvF,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,qDAAqD;IACrD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kCAAkC;IAClC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,wBAAwB;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kCAAkC;IAClC,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,WAAW,CAAC;IACzB,SAAS,CAAC,EAAE,eAAe,CAAC;CAC7B;AA8CD,kEAAkE;AAClE,wBAAgB,UAAU,CAAC,OAAO,GAAE,OAAO,CAAC,WAAW,CAAM,GAAG,WAAW,CA6D1E;AAED,8CAA8C;AAC9C,wBAAgB,UAAU,CAAC,MAAM,EAAE,OAAO,CAAC,WAAW,CAAC,GAAG,IAAI,CAc7D"}
|
package/dist/index.js
CHANGED
package/dist/start.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mclawnet/agent",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
@@ -20,10 +20,10 @@
|
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
22
|
"ws": "^8.19.0",
|
|
23
|
-
"@mclawnet/logger": "0.1.1",
|
|
24
23
|
"@mclawnet/shared": "0.1.0",
|
|
24
|
+
"@mclawnet/swarm": "0.1.0",
|
|
25
25
|
"@mclawnet/claude-adapter": "0.1.1",
|
|
26
|
-
"@mclawnet/
|
|
26
|
+
"@mclawnet/logger": "0.1.1"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
29
|
"@types/node": "^22",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/config.ts","../src/hub-connection.ts","../src/fs-handler.ts","../src/session-manager.ts","../src/start.ts","../src/brain-bridge.ts"],"sourcesContent":["import { readFileSync, writeFileSync, mkdirSync, existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { homedir, hostname } from \"node:os\";\nimport type { BackendType } from \"@mclawnet/shared\";\n\nexport interface EmbeddingConfig {\n /** Embedding provider mode: auto / openai / ollama / hash */\n provider?: string;\n /** OpenAI-compatible API base URL (e.g. http://localhost:4141/v1 for copilot proxy) */\n openaiBaseUrl?: string;\n /** OpenAI API key (use \"dummy\" for copilot proxy) */\n openaiApiKey?: string;\n /** OpenAI embedding model name */\n openaiModel?: string;\n /** Ollama server URL */\n ollamaUrl?: string;\n /** Ollama embedding model name */\n ollamaModel?: string;\n}\n\nexport interface AgentConfig {\n hubUrl: string;\n token: string;\n name: string;\n backendType: BackendType;\n embedding?: EmbeddingConfig;\n}\n\nconst CONFIG_DIR = join(homedir(), \".clawnet\");\nconst SETTINGS_FILE = join(CONFIG_DIR, \"settings.json\");\n\nconst DEFAULT_HUB_URL = process.env.CLAWNET_DEFAULT_HUB_URL || \"ws://localhost:3000/ws/agent\";\n\nconst DEFAULTS: AgentConfig = {\n hubUrl: DEFAULT_HUB_URL,\n token: \"\",\n name: hostname(),\n backendType: \"claude-code\",\n};\n\n/** Ensure hubUrl uses ws(s):// protocol and ends with /ws/agent */\nfunction normalizeHubUrl(url: string): string {\n // Convert http(s):// to ws(s)://\n url = url.replace(/^https:\\/\\//, \"wss://\").replace(/^http:\\/\\//, \"ws://\");\n // Default to wss:// if no protocol\n if (!/^wss?:\\/\\//.test(url)) url = \"wss://\" + url;\n if (url.endsWith(\"/ws/agent\")) return url;\n return url.replace(/\\/+$/, \"\") + \"/ws/agent\";\n}\n\n/**\n * Map structured embedding config to CLAWNET_* env vars.\n * Only sets vars that are not already defined in process.env.\n */\nfunction applyEmbeddingConfig(embedding: EmbeddingConfig): void {\n const mapping: Array<[keyof EmbeddingConfig, string]> = [\n [\"provider\", \"CLAWNET_EMBEDDING_PROVIDER\"],\n [\"openaiBaseUrl\", \"CLAWNET_OPENAI_BASE_URL\"],\n [\"openaiApiKey\", \"CLAWNET_OPENAI_API_KEY\"],\n [\"openaiModel\", \"CLAWNET_OPENAI_EMBEDDING_MODEL\"],\n [\"ollamaUrl\", \"CLAWNET_OLLAMA_URL\"],\n [\"ollamaModel\", \"CLAWNET_OLLAMA_MODEL\"],\n ];\n\n for (const [configKey, envKey] of mapping) {\n const value = embedding[configKey];\n if (value !== undefined && process.env[envKey] === undefined) {\n process.env[envKey] = value;\n }\n }\n}\n\n/** Load config: CLI opts > env vars > settings file > defaults */\nexport function loadConfig(cliOpts: Partial<AgentConfig> = {}): AgentConfig {\n let fileConfig: Partial<AgentConfig> = {};\n\n if (existsSync(SETTINGS_FILE)) {\n try {\n fileConfig = JSON.parse(readFileSync(SETTINGS_FILE, \"utf-8\"));\n } catch {\n // ignore corrupt config\n }\n }\n\n // Apply structured embedding config to process.env\n if (fileConfig.embedding) {\n applyEmbeddingConfig(fileConfig.embedding);\n }\n\n const hubUrl =\n cliOpts.hubUrl ??\n process.env.CLAWNET_HUB_URL ??\n fileConfig.hubUrl ??\n DEFAULTS.hubUrl;\n\n return {\n hubUrl: normalizeHubUrl(hubUrl),\n token:\n cliOpts.token ??\n process.env.CLAWNET_TOKEN ??\n fileConfig.token ??\n DEFAULTS.token,\n name:\n cliOpts.name ??\n process.env.CLAWNET_NAME ??\n fileConfig.name ??\n DEFAULTS.name,\n backendType:\n (cliOpts.backendType as BackendType) ??\n (process.env.CLAWNET_BACKEND_TYPE as BackendType) ??\n (fileConfig.backendType as BackendType) ??\n DEFAULTS.backendType,\n embedding: fileConfig.embedding,\n };\n}\n\n/** Save config to ~/.clawnet/settings.json */\nexport function saveConfig(config: Partial<AgentConfig>): void {\n mkdirSync(CONFIG_DIR, { recursive: true });\n\n let existing: Partial<AgentConfig> = {};\n if (existsSync(SETTINGS_FILE)) {\n try {\n existing = JSON.parse(readFileSync(SETTINGS_FILE, \"utf-8\"));\n } catch {\n // ignore\n }\n }\n\n const merged = { ...existing, ...config };\n writeFileSync(SETTINGS_FILE, JSON.stringify(merged, null, 2) + \"\\n\");\n}\n","import { hostname as osHostname } from \"node:os\";\nimport WebSocket from \"ws\";\nimport {\n HEARTBEAT_INTERVAL_MS,\n DEFAULT_RECONNECT_MS,\n MAX_RECONNECT_MS,\n WS_CLOSE_INVALID_TOKEN,\n} from \"@mclawnet/shared\";\nimport type {\n AgentServerMessage,\n AgentClientMessage,\n AgentGenericRequest,\n} from \"@mclawnet/shared\";\nimport type { SessionManager } from \"./session-manager.js\";\nimport type { SwarmCoordinator } from \"@mclawnet/swarm\";\nimport { listRecoverableSwarms, recoverSwarm, listRoles, loadRole, listRecoverableSwarmIds, deleteSwarmSnapshot } from \"@mclawnet/swarm\";\nimport { handleListDir, handleListFolders, handleListHistorySessions, handleLoadSessionHistory } from \"./fs-handler.js\";\nimport { createLogger } from \"@mclawnet/logger\";\n\nconst log = createLogger({ module: \"agent\" });\n\nexport interface HubConnectionOptions {\n hubUrl: string;\n token: string;\n hostname?: string;\n version?: string;\n capabilities?: string[];\n heartbeatInterval?: number;\n reconnectDelay?: number;\n maxReconnectDelay?: number;\n onMessage?: (data: unknown) => void;\n onConnect?: (agentId: string) => void;\n onDisconnect?: (code: number, reason: string) => void;\n onError?: (err: Error) => void;\n}\n\ntype AuthState = \"pending\" | \"authenticating\" | \"authenticated\";\n\nexport class HubConnection {\n private ws: WebSocket | null = null;\n private heartbeatTimer: ReturnType<typeof setInterval> | null = null;\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n private reconnectDelay: number;\n private destroyed = false;\n private authState: AuthState = \"pending\";\n\n readonly hubUrl: string;\n readonly token: string;\n readonly hostname: string;\n readonly version: string | undefined;\n readonly capabilities: string[] | undefined;\n readonly heartbeatInterval: number;\n readonly maxReconnectDelay: number;\n\n /** Agent ID assigned by Hub after successful auth */\n agentId: string | null = null;\n\n /** Swarm IDs that have been completed/failed — prevents accidental recreation */\n private finishedSwarms = new Set<string>();\n\n /** Session manager — set after construction via setSessionManager() */\n private sessionManager: SessionManager | null = null;\n\n /** Swarm coordinator — set after construction via setSwarmCoordinator() */\n private swarmCoordinator: SwarmCoordinator | null = null;\n\n /** Namespace-based generic message handlers */\n private namespaceHandlers = new Map<\n string,\n (msg: AgentGenericRequest) => Promise<Record<string, unknown>>\n >();\n\n private onMessage?: (data: unknown) => void;\n private onConnectCb?: (agentId: string) => void;\n private onDisconnect?: (code: number, reason: string) => void;\n private onError?: (err: Error) => void;\n\n constructor(opts: HubConnectionOptions) {\n this.hubUrl = opts.hubUrl;\n this.token = opts.token;\n this.hostname = opts.hostname ?? osHostname();\n this.version = opts.version;\n this.capabilities = opts.capabilities;\n this.heartbeatInterval = opts.heartbeatInterval ?? HEARTBEAT_INTERVAL_MS;\n this.reconnectDelay = opts.reconnectDelay ?? DEFAULT_RECONNECT_MS;\n this.maxReconnectDelay = opts.maxReconnectDelay ?? MAX_RECONNECT_MS;\n this.onMessage = opts.onMessage;\n this.onConnectCb = opts.onConnect;\n this.onDisconnect = opts.onDisconnect;\n this.onError = opts.onError;\n }\n\n setSessionManager(manager: SessionManager): void {\n this.sessionManager = manager;\n }\n\n setSwarmCoordinator(coordinator: SwarmCoordinator): void {\n this.swarmCoordinator = coordinator;\n }\n\n registerNamespace(\n namespace: string,\n handler: (msg: AgentGenericRequest) => Promise<Record<string, unknown>>\n ) {\n this.namespaceHandlers.set(namespace, handler);\n }\n\n sendPush(namespace: string, event: string, data: Record<string, unknown>) {\n this.send({\n type: \"generic.push\",\n namespace,\n event,\n data,\n });\n }\n\n get readyState(): number {\n return this.ws?.readyState ?? WebSocket.CLOSED;\n }\n\n get isConnected(): boolean {\n return this.ws?.readyState === WebSocket.OPEN && this.authState === \"authenticated\";\n }\n\n connect(): void {\n if (this.destroyed) return;\n this.cleanup();\n this.authState = \"pending\";\n\n this.ws = new WebSocket(this.hubUrl);\n\n this.ws.on(\"open\", () => {\n this.reconnectDelay = DEFAULT_RECONNECT_MS;\n });\n\n this.ws.on(\"message\", (raw) => {\n let data: AgentServerMessage;\n try {\n data = JSON.parse(raw.toString());\n } catch {\n return;\n }\n\n // Step 1: Hub sends auth_required → reply with auth\n if (this.authState === \"pending\" && data.type === \"auth_required\") {\n log.info(\"hub requires auth, sending credentials\");\n this.authState = \"authenticating\";\n this.sendRaw({\n type: \"auth\",\n token: this.token,\n hostname: this.hostname,\n version: this.version,\n capabilities: this.capabilities,\n });\n return;\n }\n\n // Step 2: Hub sends registered → auth complete\n if (this.authState === \"authenticating\" && data.type === \"registered\") {\n log.info({ agentId: data.agentId }, \"registered with hub\");\n this.authState = \"authenticated\";\n this.agentId = data.agentId ?? null;\n this.startHeartbeat();\n this.onConnectCb?.(this.agentId!);\n\n // Attempt to recover any persisted swarms\n this.tryRecoverSwarms();\n return;\n }\n\n // Post-auth message handling\n if (this.authState === \"authenticated\") {\n if (this.handleSessionMessage(data)) return;\n this.onMessage?.(data);\n }\n });\n\n this.ws.on(\"close\", (code, reason) => {\n log.info({ code, reason: reason.toString() }, \"ws connection closed\");\n this.stopHeartbeat();\n this.authState = \"pending\";\n this.onDisconnect?.(code, reason.toString());\n if (code === WS_CLOSE_INVALID_TOKEN) {\n log.error(\"auth failed — not reconnecting, check your token\");\n return;\n }\n this.scheduleReconnect();\n });\n\n this.ws.on(\"error\", (err) => {\n log.error({ err }, \"ws connection error\");\n this.onError?.(err);\n });\n }\n\n send(data: AgentClientMessage): boolean {\n // Track swarm completion to prevent accidental recreation\n const msg = data as any;\n if (msg.type === \"swarm.status\" && (msg.swarmStatus === \"completed\" || msg.swarmStatus === \"failed\")) {\n this.finishedSwarms.add(msg.sessionId);\n }\n return this.sendRaw(data);\n }\n\n destroy(): void {\n this.destroyed = true;\n this.cleanup();\n }\n\n // ── Session message handling ─────────────────────────────────────\n\n private handleSessionMessage(msg: AgentServerMessage): boolean {\n // ── Filesystem / history requests (no sessionManager needed) ─────\n\n if (msg.type === \"fs.list_dir\") {\n log.info({ path: msg.path }, \"fs.list_dir\");\n handleListDir(msg.path)\n .then((result) => {\n this.send({ type: \"fs.list_dir_result\", requestId: msg.requestId, ...result });\n })\n .catch((err: any) => {\n log.error({ err, path: msg.path }, \"fs.list_dir failed\");\n this.send({\n type: \"fs.list_dir_result\",\n requestId: msg.requestId,\n path: msg.path || \"/\",\n entries: [],\n });\n });\n return true;\n }\n\n if (msg.type === \"list_folders\") {\n log.info(\"list_folders\");\n handleListFolders()\n .then((result) => {\n this.send({ type: \"folders_list_result\", requestId: msg.requestId, ...result });\n })\n .catch((err: any) => {\n log.error({ err }, \"list_folders failed\");\n this.send({ type: \"folders_list_result\", requestId: msg.requestId, folders: [] });\n });\n return true;\n }\n\n if (msg.type === \"list_history_sessions\") {\n log.info({ workDir: msg.workDir }, \"list_history_sessions\");\n handleListHistorySessions(msg.workDir)\n .then((result) => {\n this.send({ type: \"history_sessions_result\", requestId: msg.requestId, ...result });\n })\n .catch((err: any) => {\n log.error({ err, workDir: msg.workDir }, \"list_history_sessions failed\");\n this.send({\n type: \"history_sessions_result\",\n requestId: msg.requestId,\n workDir: msg.workDir,\n sessions: [],\n });\n });\n return true;\n }\n\n if (msg.type === \"load_session_history\") {\n log.info({ workDir: msg.workDir, claudeSessionId: msg.claudeSessionId }, \"load_session_history\");\n handleLoadSessionHistory(msg.workDir, msg.claudeSessionId)\n .then((result) => {\n this.send({ type: \"session_history_result\", requestId: msg.requestId, ...result });\n })\n .catch((err: any) => {\n log.error({ err, workDir: msg.workDir }, \"load_session_history failed\");\n this.send({ type: \"session_history_result\", requestId: msg.requestId, messages: [] });\n });\n return true;\n }\n\n // ── Swarm handling (requires swarmCoordinator) ──────────────────────\n\n if (msg.type === \"list_roles\") {\n log.info(\"list_roles\");\n const roleNames = listRoles();\n const roles = roleNames.map((name) => {\n try {\n const def = loadRole(name);\n return {\n name: def.name,\n displayName: def.shortName || def.name,\n description: def.description || \"\",\n capabilities: def.capabilities || [],\n promptBody: def.promptBody || \"\",\n };\n } catch {\n return { name, displayName: name, description: \"\", capabilities: [], promptBody: \"\" };\n }\n });\n this.send({\n type: \"roles_list_result\",\n sessionId: (msg as any).sessionId,\n roles,\n } as any);\n return true;\n }\n\n // ── Generic request: dispatch to registered namespace handlers ──\n if (msg.type === \"generic.request\") {\n const handler = this.namespaceHandlers.get(msg.namespace);\n if (handler) {\n log.info({ namespace: msg.namespace, action: msg.action, requestId: msg.requestId }, \"generic.request received\");\n handler(msg)\n .then((result) => {\n log.info({ namespace: msg.namespace, action: msg.action, requestId: msg.requestId }, \"generic.request handled OK\");\n this.send({\n type: \"generic.response\",\n namespace: msg.namespace,\n action: msg.action,\n data: result,\n requestId: msg.requestId,\n });\n })\n .catch((err) => {\n log.error({ namespace: msg.namespace, action: msg.action, requestId: msg.requestId, err }, \"generic.request handler error\");\n this.send({\n type: \"generic.response\",\n namespace: msg.namespace,\n action: msg.action,\n data: {},\n requestId: msg.requestId,\n error: err instanceof Error ? err.message : String(err),\n });\n });\n return true;\n }\n log.warn({ namespace: msg.namespace, action: msg.action, requestId: msg.requestId }, \"generic.request unknown namespace\");\n this.send({\n type: \"generic.response\",\n namespace: msg.namespace,\n action: msg.action,\n data: {},\n requestId: msg.requestId,\n error: `Unknown namespace: ${msg.namespace}`,\n });\n return true;\n }\n\n if (msg.type === \"swarm.execute\" && this.swarmCoordinator) {\n const { sessionId, content, workDir, targetInstance, crewConfig } = msg;\n\n if (this.swarmCoordinator.hasSwarm(sessionId)) {\n // Existing swarm — forward user message\n log.info({ sessionId, targetInstance }, \"swarm.execute: forwarding to existing swarm\");\n this.swarmCoordinator.handleUserMessage(sessionId, content, targetInstance).catch((err) => {\n this.send({\n type: \"session.error\",\n sessionId,\n error: err instanceof Error ? err.message : String(err),\n });\n });\n } else if (this.finishedSwarms.has(sessionId)) {\n // Swarm already completed/failed — don't recreate\n log.info({ sessionId }, \"swarm.execute ignored: swarm already finished\");\n this.send({\n type: \"session.error\",\n sessionId,\n error: \"蜂群任务已完成,无法继续操作。请创建新的蜂群任务。\",\n });\n } else if (crewConfig?.roles) {\n // Explicit create: crewConfig with roles provided — create new swarm\n log.info({ sessionId, rolesCount: crewConfig.roles.length }, \"swarm.execute: creating new swarm\");\n const roles = crewConfig.roles;\n this.swarmCoordinator.create(sessionId, { workDir, roles, task: content }).catch((err) => {\n this.send({\n type: \"session.error\",\n sessionId,\n error: err instanceof Error ? err.message : String(err),\n });\n });\n } else {\n // No swarm and no crewConfig — shouldn't happen normally\n log.info({ sessionId }, \"swarm.execute ignored: swarm not found, no config\");\n this.send({\n type: \"session.error\",\n sessionId,\n error: \"蜂群任务已完成,无法继续操作。请创建新的蜂群任务。\",\n });\n }\n return true;\n }\n\n // ── Session management (requires sessionManager) ─────────────────\n\n if (!this.sessionManager) return false;\n\n if (msg.type === \"abort_execution\") {\n const { sessionId } = msg;\n log.info({ sessionId }, \"abort_execution\");\n if (this.sessionManager?.hasSession(sessionId)) {\n this.sessionManager.abortSession(sessionId).then(() => {\n this.send({ type: \"execution_aborted\", sessionId } as any);\n }).catch(() => {\n this.send({ type: \"execution_aborted\", sessionId } as any);\n });\n } else {\n // No active session — just acknowledge\n this.send({ type: \"execution_aborted\", sessionId } as any);\n }\n return true;\n }\n\n // claude.execute — auto-create session if needed, then send input\n if (msg.type === \"claude.execute\") {\n const { sessionId, content, workDir, claudeSessionId, useBrainCore } = msg;\n if (this.sessionManager.hasSession(sessionId)) {\n log.info({ sessionId }, \"claude.execute: reusing existing session\");\n this.sessionManager.sendInput(sessionId, content);\n } else {\n log.info({ sessionId, workDir }, \"claude.execute: creating new session\");\n this.sessionManager\n .createSession({ sessionId, workDir, resumeId: claudeSessionId, useBrainCore })\n .then(() => {\n this.sessionManager!.sendInput(sessionId, content);\n })\n .catch((err) => {\n this.send({\n type: \"session.error\",\n sessionId,\n error: err instanceof Error ? err.message : String(err),\n });\n });\n }\n return true;\n }\n\n if (msg.type === \"session.create\") {\n log.info({ sessionId: msg.sessionId }, \"session.create\");\n this.sessionManager\n .createSession({\n sessionId: msg.sessionId,\n workDir: msg.workDir,\n resumeId: msg.resumeId,\n })\n .then((claudeSessionId) => {\n this.send({\n type: \"session.created\",\n sessionId: msg.sessionId,\n claudeSessionId,\n });\n })\n .catch((err) => {\n this.send({\n type: \"session.error\",\n sessionId: msg.sessionId,\n error: err instanceof Error ? err.message : String(err),\n });\n });\n return true;\n }\n\n if (msg.type === \"session.close\") {\n log.info({ sessionId: msg.sessionId }, \"session.close\");\n this.sessionManager.closeSession(msg.sessionId).catch(() => {});\n return true;\n }\n\n if (msg.type === \"claude.input\") {\n log.info({ sessionId: msg.sessionId }, \"claude.input\");\n this.sessionManager.sendInput(msg.sessionId, msg.content);\n return true;\n }\n\n return false;\n }\n\n // ── Internal helpers ─────────────────────────────────────────────\n\n private tryRecoverSwarms(): void {\n if (!this.swarmCoordinator) return;\n try {\n const allIds = listRecoverableSwarmIds();\n const snapshots = listRecoverableSwarms();\n const recoverableIds = new Set(snapshots.map((s) => s.id));\n\n // Clean up expired/completed/failed snapshots\n for (const id of allIds) {\n if (!recoverableIds.has(id)) {\n deleteSwarmSnapshot(id);\n log.info({ swarmId: id }, \"cleaned up non-recoverable swarm snapshot\");\n }\n }\n\n for (const snap of snapshots) {\n log.info({ swarmId: snap.id }, \"recovering swarm\");\n recoverSwarm(this.swarmCoordinator, snap).catch((err) => {\n log.error({ err, swarmId: snap.id }, \"failed to recover swarm\");\n });\n }\n } catch (err) {\n log.error({ err }, \"swarm recovery failed\");\n }\n }\n\n private sendRaw(data: unknown): boolean {\n if (!this.ws || this.ws.readyState !== WebSocket.OPEN) return false;\n this.ws.send(JSON.stringify(data));\n return true;\n }\n\n private startHeartbeat(): void {\n this.stopHeartbeat();\n this.heartbeatTimer = setInterval(() => {\n this.send({ type: \"heartbeat\", ts: Date.now() });\n }, this.heartbeatInterval);\n }\n\n private stopHeartbeat(): void {\n if (this.heartbeatTimer) {\n clearInterval(this.heartbeatTimer);\n this.heartbeatTimer = null;\n }\n }\n\n private scheduleReconnect(): void {\n if (this.destroyed) return;\n this.reconnectTimer = setTimeout(() => {\n this.connect();\n }, this.reconnectDelay);\n this.reconnectDelay = Math.min(this.reconnectDelay * 2, this.maxReconnectDelay);\n }\n\n private cleanup(): void {\n this.stopHeartbeat();\n this.sessionManager?.closeAll().catch(() => {});\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n if (this.ws) {\n this.ws.removeAllListeners();\n if (this.ws.readyState === WebSocket.OPEN || this.ws.readyState === WebSocket.CONNECTING) {\n this.ws.close();\n }\n this.ws = null;\n }\n }\n}\n","import { readdir, stat, readFile } from \"node:fs/promises\";\nimport { existsSync, readdirSync, statSync, readFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nconst SKIP_DIRS = new Set([\".git\", \"node_modules\", \"__pycache__\", \".next\", \".nuxt\", \".cache\"]);\n\n// ── fs.list_dir ─────────────────────────────────────────────────────\n\nexport async function handleListDir(\n path: string,\n): Promise<{ path: string; entries: Array<{ name: string; type: \"directory\" | \"file\" }> }> {\n const target = path || \"/\";\n const dirents = await readdir(target, { withFileTypes: true });\n\n const entries = dirents\n .filter((d) => !(d.isDirectory() && SKIP_DIRS.has(d.name)))\n .map((d) => ({\n name: d.name,\n type: (d.isDirectory() ? \"directory\" : \"file\") as \"directory\" | \"file\",\n }))\n .sort((a, b) => {\n if (a.type !== b.type) return a.type === \"directory\" ? -1 : 1;\n return a.name.localeCompare(b.name);\n });\n\n return { path: target, entries };\n}\n\n// ── list_folders (scan ~/.claude/projects/) ──────────────────────────\n\nfunction getClaudeProjectsDir(): string {\n return join(homedir(), \".claude\", \"projects\");\n}\n\nfunction pathToProjectFolder(workDir: string): string {\n return workDir.replace(/:/g, \"-\").replace(/[/\\\\]/g, \"-\");\n}\n\nfunction extractWorkDirFromSessionFile(filePath: string): string | null {\n try {\n const content = readFileSync(filePath, \"utf-8\");\n const lines = content.split(\"\\n\").filter((l) => l.trim());\n for (const line of lines.slice(0, 5)) {\n try {\n const data = JSON.parse(line);\n if (data.cwd) return data.cwd.replace(/\\\\/g, \"/\");\n } catch {}\n }\n } catch {}\n return null;\n}\n\nfunction getWorkDirFromProjectFolder(folderPath: string, folderName: string): string {\n try {\n const files = readdirSync(folderPath);\n for (const file of files) {\n if (file.endsWith(\".jsonl\")) {\n const workDir = extractWorkDirFromSessionFile(join(folderPath, file));\n if (workDir) return workDir;\n }\n }\n } catch {}\n\n // Fallback: simple conversion\n if (/^[A-Za-z]--/.test(folderName)) {\n return folderName.replace(/^([A-Za-z])--/, \"$1:/\").replace(/-/g, \"/\");\n }\n if (folderName.startsWith(\"-\")) {\n return \"/\" + folderName.substring(1).replace(/-/g, \"/\");\n }\n return folderName.replace(/-/g, \"/\");\n}\n\nexport async function handleListFolders(): Promise<{\n folders: Array<{ path: string; sessionCount: number; lastModified?: number }>;\n}> {\n const projectsDir = getClaudeProjectsDir();\n const folders: Array<{ path: string; sessionCount: number; lastModified?: number }> = [];\n\n if (!existsSync(projectsDir)) return { folders };\n\n const entries = readdirSync(projectsDir);\n for (const entry of entries) {\n const entryPath = join(projectsDir, entry);\n let entryStat;\n try {\n entryStat = statSync(entryPath);\n } catch {\n continue;\n }\n if (!entryStat.isDirectory()) continue;\n\n // Skip crew role directories\n if (entry.includes(\"--crew-roles-\")) continue;\n\n const originalPath = getWorkDirFromProjectFolder(entryPath, entry);\n\n let sessionCount = 0;\n let lastModified = entryStat.mtime.getTime();\n\n try {\n const files = readdirSync(entryPath);\n for (const file of files) {\n if (file.endsWith(\".jsonl\")) {\n sessionCount++;\n try {\n const fileStats = statSync(join(entryPath, file));\n if (fileStats.mtime.getTime() > lastModified) {\n lastModified = fileStats.mtime.getTime();\n }\n } catch {}\n }\n }\n } catch {}\n\n folders.push({ path: originalPath, sessionCount, lastModified });\n }\n\n folders.sort((a, b) => (b.lastModified ?? 0) - (a.lastModified ?? 0));\n return { folders };\n}\n\n// ── list_history_sessions ───────────────────────────────────────────\n\nexport async function handleListHistorySessions(workDir: string): Promise<{\n workDir: string;\n sessions: Array<{ sessionId: string; title: string; workDir?: string; lastModified?: number }>;\n}> {\n const projectsDir = getClaudeProjectsDir();\n const projectFolder = pathToProjectFolder(workDir);\n const projectPath = join(projectsDir, projectFolder);\n\n if (!existsSync(projectPath)) {\n return { workDir, sessions: [] };\n }\n\n const sessions: Array<{ sessionId: string; title: string; workDir?: string; lastModified?: number }> = [];\n const files = readdirSync(projectPath);\n\n for (const file of files) {\n if (!file.endsWith(\".jsonl\")) continue;\n\n const sessionId = file.replace(\".jsonl\", \"\");\n const filePath = join(projectPath, file);\n let fileStats;\n try {\n fileStats = statSync(filePath);\n } catch {\n continue;\n }\n\n let title = \"\";\n let hasUserMessage = false;\n let customTitle = \"\";\n let jsonlSummary = \"\";\n\n try {\n const content = readFileSync(filePath, \"utf-8\");\n const lines = content.split(\"\\n\").filter((l) => l.trim());\n\n for (const line of lines) {\n try {\n const data = JSON.parse(line);\n if (!hasUserMessage && data.type === \"user\" && data.message?.content) {\n const text =\n typeof data.message.content === \"string\"\n ? data.message.content\n : data.message.content[0]?.text || \"\";\n if (text.trim()) {\n title = text.substring(0, 100);\n hasUserMessage = true;\n }\n }\n if (data.type === \"custom-title\" && data.customTitle) {\n customTitle = data.customTitle;\n }\n if (data.type === \"summary\" && data.summary) {\n jsonlSummary = data.summary;\n }\n } catch {}\n }\n } catch {}\n\n if (hasUserMessage) {\n sessions.push({\n sessionId,\n title: customTitle || jsonlSummary || title || sessionId.slice(0, 8),\n workDir,\n lastModified: fileStats.mtime.getTime(),\n });\n }\n }\n\n sessions.sort((a, b) => (b.lastModified ?? 0) - (a.lastModified ?? 0));\n return { workDir, sessions };\n}\n\n// ── load_session_history ────────────────────────────────────────────\n\ninterface HistoryMessage {\n role: \"user\" | \"assistant\";\n content: string;\n toolCalls?: Array<{ name: string; input?: string; output?: string; status: string }>;\n thinking?: string;\n}\n\nexport async function handleLoadSessionHistory(\n workDir: string,\n claudeSessionId: string,\n): Promise<{ messages: HistoryMessage[] }> {\n const projectsDir = getClaudeProjectsDir();\n const projectFolder = pathToProjectFolder(workDir);\n const filePath = join(projectsDir, projectFolder, `${claudeSessionId}.jsonl`);\n\n if (!existsSync(filePath)) {\n return { messages: [] };\n }\n\n const messages: HistoryMessage[] = [];\n\n try {\n const content = readFileSync(filePath, \"utf-8\");\n const lines = content.split(\"\\n\").filter((l) => l.trim());\n\n for (const line of lines) {\n try {\n const data = JSON.parse(line);\n\n if (data.type === \"user\" && data.message?.content) {\n const blocks = Array.isArray(data.message.content)\n ? data.message.content\n : [{ type: \"text\", text: String(data.message.content) }];\n\n // Extract user text (only text blocks, skip tool_result etc.)\n const textParts: string[] = [];\n for (const block of blocks) {\n if (block.type === \"text\" && block.text?.trim()) {\n textParts.push(block.text);\n }\n }\n if (textParts.length > 0) {\n messages.push({ role: \"user\", content: textParts.join(\"\\n\") });\n }\n\n // Attach tool_result outputs to the last assistant's toolCalls\n const lastAssistant = messages.length > 0\n ? [...messages].reverse().find((m) => m.role === \"assistant\" && m.toolCalls?.length)\n : undefined;\n if (lastAssistant?.toolCalls) {\n for (const block of blocks) {\n if (block.type === \"tool_result\") {\n // Match by tool_use_id or just fill the next pending one\n const pending = lastAssistant.toolCalls.find((tc) => !tc.output);\n if (pending) {\n pending.output = typeof block.content === \"string\"\n ? block.content\n : Array.isArray(block.content)\n ? block.content.map((c: any) => c.text ?? \"\").join(\"\")\n : JSON.stringify(block.content);\n pending.status = block.is_error ? \"error\" : \"done\";\n }\n }\n }\n }\n }\n\n if (data.type === \"assistant\" && data.message?.content) {\n let text = \"\";\n const toolCalls: HistoryMessage[\"toolCalls\"] = [];\n let thinking = \"\";\n\n for (const block of data.message.content) {\n if (block.type === \"text\") {\n text += block.text;\n } else if (block.type === \"tool_use\") {\n toolCalls.push({\n name: block.name,\n input: typeof block.input === \"string\" ? block.input : JSON.stringify(block.input, null, 2),\n status: \"done\",\n });\n } else if (block.type === \"thinking\") {\n thinking += block.thinking ?? \"\";\n }\n }\n\n messages.push({\n role: \"assistant\",\n content: text,\n toolCalls: toolCalls.length > 0 ? toolCalls : undefined,\n thinking: thinking || undefined,\n });\n }\n } catch {}\n }\n } catch {}\n\n // Return last 50 messages to avoid overloading\n return { messages: messages.slice(-50) };\n}\n","import type { BackendAdapter, BackendProcess, SpawnOptions } from \"./backend-adapter.js\";\n\n/**\n * Manages active sessions, mapping ClawNet session IDs to BackendProcess instances.\n */\nexport class SessionManager {\n private sessions = new Map<string, BackendProcess>();\n private conversationBuffer = new Map<string, Array<{ role: string; content: string }>>();\n private adapter: BackendAdapter;\n private onOutput: (sessionId: string, data: unknown) => void;\n private onTurnComplete: (\n sessionId: string,\n info: {\n claudeSessionId?: string;\n cost?: number;\n duration?: number;\n contextUsage?: { used: number; total: number };\n },\n ) => void;\n private onSessionError: (sessionId: string, error: string) => void;\n private onBeforeClose?: (sessionId: string, messages: Array<{ role: string; content: string }>) => Promise<void>;\n\n constructor(options: {\n adapter: BackendAdapter;\n onOutput: (sessionId: string, data: unknown) => void;\n onTurnComplete: (\n sessionId: string,\n info: {\n claudeSessionId?: string;\n cost?: number;\n duration?: number;\n contextUsage?: { used: number; total: number };\n },\n ) => void;\n onSessionError: (sessionId: string, error: string) => void;\n onBeforeClose?: (sessionId: string, messages: Array<{ role: string; content: string }>) => Promise<void>;\n }) {\n this.adapter = options.adapter;\n this.onOutput = options.onOutput;\n this.onTurnComplete = options.onTurnComplete;\n this.onSessionError = options.onSessionError;\n this.onBeforeClose = options.onBeforeClose;\n }\n\n async createSession(options: SpawnOptions): Promise<string> {\n if (this.sessions.has(options.sessionId)) {\n throw new Error(`Session ${options.sessionId} already exists`);\n }\n\n try {\n const process = await this.adapter.spawn(options);\n this.sessions.set(options.sessionId, process);\n\n // Wire up output handler\n this.adapter.onOutput(process, (data) => {\n // Accumulate assistant text messages for distillation\n const msg = data as any;\n if (msg?.type === \"assistant\" && msg?.message?.content) {\n const buf = this.conversationBuffer.get(options.sessionId) ?? [];\n // Extract text from content blocks\n const text = Array.isArray(msg.message.content)\n ? msg.message.content.filter((b: any) => b.type === \"text\").map((b: any) => b.text).join(\"\\n\")\n : String(msg.message.content);\n if (text) {\n buf.push({ role: \"assistant\", content: text });\n this.conversationBuffer.set(options.sessionId, buf);\n }\n }\n this.onOutput(options.sessionId, data);\n });\n\n // Wire up turn-complete handler\n this.adapter.onTurnComplete?.(process, (info) => {\n this.onTurnComplete(options.sessionId, info);\n });\n\n // Wire up error handler\n this.adapter.onError?.(process, (error) => {\n this.onSessionError(options.sessionId, error.message);\n });\n\n return process.id;\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n this.onSessionError(options.sessionId, message);\n throw err;\n }\n }\n\n sendInput(sessionId: string, input: string): void {\n const process = this.sessions.get(sessionId);\n if (!process) {\n this.onSessionError(sessionId, `No active session: ${sessionId}`);\n return;\n }\n this.adapter.send(process, input);\n }\n\n async abortSession(sessionId: string): Promise<void> {\n const process = this.sessions.get(sessionId);\n if (!process) return;\n // Kill the process but remove from sessions map — a new process will be\n // lazily created on next claude.execute\n this.conversationBuffer.delete(sessionId);\n this.sessions.delete(sessionId);\n await this.adapter.stop(process);\n }\n\n async closeSession(sessionId: string): Promise<void> {\n const process = this.sessions.get(sessionId);\n if (!process) return;\n\n // Trigger distillation before closing\n const messages = this.conversationBuffer.get(sessionId);\n if (this.onBeforeClose && messages?.length) {\n await this.onBeforeClose(sessionId, messages).catch(() => {});\n }\n this.conversationBuffer.delete(sessionId);\n\n this.sessions.delete(sessionId);\n await this.adapter.stop(process);\n }\n\n async closeAll(): Promise<void> {\n const promises = Array.from(this.sessions.entries()).map(\n async ([sessionId, process]) => {\n // Trigger distillation before closing\n const messages = this.conversationBuffer.get(sessionId);\n if (this.onBeforeClose && messages?.length) {\n await this.onBeforeClose(sessionId, messages).catch(() => {});\n }\n this.conversationBuffer.delete(sessionId);\n this.sessions.delete(sessionId);\n await this.adapter.stop(process).catch(() => {});\n },\n );\n await Promise.all(promises);\n }\n\n hasSession(sessionId: string): boolean {\n return this.sessions.has(sessionId);\n }\n\n get activeSessionCount(): number {\n return this.sessions.size;\n }\n}\n","import { loadConfig, type AgentConfig } from \"./config.js\";\nimport { HubConnection } from \"./hub-connection.js\";\nimport { SessionManager } from \"./session-manager.js\";\nimport { SwarmCoordinator, initRoles } from \"@mclawnet/swarm\";\nimport { BrainBridge } from \"./brain-bridge.js\";\nimport type { BackendAdapter } from \"./backend-adapter.js\";\nimport { createLogger } from \"@mclawnet/logger\";\n\nconst log = createLogger({ module: \"agent\" });\n\nexport interface StartOptions {\n config?: Partial<AgentConfig>;\n adapter: BackendAdapter;\n}\n\n/**\n * Start the ClawNet agent: connect to Hub and register a BackendAdapter.\n */\nexport async function startAgent(options: StartOptions): Promise<{\n hub: HubConnection;\n sessionManager: SessionManager;\n swarmCoordinator: SwarmCoordinator;\n brainBridge: BrainBridge;\n}> {\n const config = loadConfig(options.config);\n\n if (!config.token) {\n log.error(\"no token configured — set CLAWNET_TOKEN or use --token\");\n process.exit(1);\n }\n\n log.info({ backend: options.adapter.type }, \"starting agent\");\n log.info({ hubUrl: config.hubUrl }, \"connecting to hub\");\n\n // Initialize role templates\n await initRoles();\n\n const hub = new HubConnection({\n hubUrl: config.hubUrl,\n token: config.token,\n hostname: config.name,\n onConnect: (agentId) => {\n log.info({ agentId }, \"connected to hub\");\n },\n onDisconnect: (code, reason) => {\n log.info({ code, reason }, \"disconnected from hub\");\n },\n onError: (err) => {\n log.error({ err }, \"hub connection error\");\n },\n });\n\n // Create SwarmCoordinator (needs hub reference; sessionManager set after construction)\n // We use a lazy reference so the coordinator can be created before sessionManager\n let swarmCoordinator: SwarmCoordinator;\n\n const sessionManager = new SessionManager({\n adapter: options.adapter,\n onOutput: (sessionId, data) => {\n // Intercept swarm role output\n if (swarmCoordinator.handleRoleOutput(sessionId, data)) return;\n\n // Normal (non-swarm) session output\n hub.send({\n type: \"claude.output\",\n sessionId,\n data,\n });\n },\n onTurnComplete: (sessionId, info) => {\n // Intercept swarm role turn completion\n if (swarmCoordinator.handleRoleTurnComplete(sessionId, info)) return;\n\n // Normal (non-swarm) session\n hub.send({\n type: \"claude.turn_complete\",\n sessionId,\n cost: info.cost,\n duration: info.duration,\n contextUsage: info.contextUsage,\n });\n },\n onSessionError: (sessionId, error) => {\n hub.send({\n type: \"session.error\",\n sessionId,\n error,\n });\n },\n });\n\n swarmCoordinator = new SwarmCoordinator(sessionManager, hub);\n\n hub.setSessionManager(sessionManager);\n hub.setSwarmCoordinator(swarmCoordinator);\n\n // Initialize BrainBridge (registers \"brain\" namespace handler)\n const brainBridge = new BrainBridge(hub);\n\n // Graceful shutdown\n const shutdown = async () => {\n log.info(\"shutting down\");\n await sessionManager.closeAll();\n hub.destroy();\n process.exit(0);\n };\n\n process.on(\"SIGINT\", shutdown);\n process.on(\"SIGTERM\", shutdown);\n\n hub.connect();\n\n return { hub, sessionManager, swarmCoordinator, brainBridge };\n}\n","import { existsSync, readFileSync, readdirSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { createLogger } from \"@mclawnet/logger\";\nimport type { AgentGenericRequest } from \"@mclawnet/shared\";\nimport type { HubConnection } from \"./hub-connection.js\";\n\nconst log = createLogger({ module: \"brain-bridge\" });\n\nexport type BrainSetupStatus = \"not_installed\" | \"needs_config\" | \"ready\";\n\nexport interface BrainBridgeOptions {\n brainHomePath?: string;\n brainCorePath?: string;\n}\n\nexport class BrainBridge {\n private brainHome: string;\n private brainCorePath: string;\n\n constructor(\n private hub: HubConnection,\n options?: BrainBridgeOptions\n ) {\n const home = process.env.HOME || process.env.USERPROFILE || \"\";\n this.brainHome =\n options?.brainHomePath ||\n process.env.BRAIN_HOME ||\n join(home, \"BrainData\");\n this.brainCorePath =\n options?.brainCorePath || join(home, \".brain\", \"BrainCore\");\n\n this.hub.registerNamespace(\"brain\", (msg) => this.handleRequest(msg));\n log.info(\n { brainHome: this.brainHome, brainCorePath: this.brainCorePath },\n \"BrainBridge initialized\"\n );\n }\n\n async handleRequest(\n msg: AgentGenericRequest\n ): Promise<Record<string, unknown>> {\n log.info({ action: msg.action, requestId: msg.requestId }, \"brain request\");\n switch (msg.action) {\n case \"setup_status\": {\n const status = this.checkSetup();\n log.info({ status }, \"setup_status result\");\n return { status };\n }\n case \"get_briefing\":\n return await this.getBriefing(msg.params.date as string | undefined);\n default:\n log.warn({ action: msg.action }, \"unknown brain action\");\n throw new Error(`Unknown brain action: ${msg.action}`);\n }\n }\n\n checkSetup(): BrainSetupStatus {\n if (!existsSync(this.brainCorePath)) {\n return \"not_installed\";\n }\n const home = process.env.HOME || process.env.USERPROFILE || \"\";\n const installJson = join(home, \".brain\", \"install.json\");\n if (!existsSync(installJson)) {\n return \"needs_config\";\n }\n if (!existsSync(this.brainHome)) {\n return \"needs_config\";\n }\n return \"ready\";\n }\n\n /** Read the most recent daily briefing report */\n private async getBriefing(\n date?: string\n ): Promise<Record<string, unknown>> {\n const targetDate = date || new Date().toISOString().slice(0, 10);\n const reportsDir = join(this.brainHome, \"reports\", \"daily\");\n\n if (!existsSync(reportsDir)) {\n log.info({ reportsDir }, \"get_briefing: reports dir not found\");\n return { briefing: null, actions: [], projects: [], meetings: [] };\n }\n\n const files = readdirSync(reportsDir)\n .filter((f: string) => f.includes(targetDate) && f.endsWith(\".md\"))\n .sort()\n .reverse();\n\n if (files.length === 0) {\n log.info({ targetDate }, \"get_briefing: no report for date\");\n return { briefing: null, actions: [], projects: [], meetings: [] };\n }\n\n log.info({ targetDate, file: files[0] }, \"get_briefing: reading report\");\n\n const content = readFileSync(join(reportsDir, files[0]), \"utf-8\");\n\n // Extract TL;DR (first matching section)\n const tldrMatch = content.match(/## TL;DR\\n([\\s\\S]*?)(?=\\n##|\\n$)/);\n const tldr = tldrMatch ? tldrMatch[1].trim() : content.slice(0, 200);\n\n return {\n briefing: {\n date: targetDate,\n tldr,\n generatedAt: new Date().toISOString(),\n },\n actions: [], // Phase 2: detailed parsing\n projects: [], // Phase 2\n meetings: [], // Phase 2\n };\n }\n}\n"],"mappings":"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","names":["existsSync","readFileSync","homedir","join","process","existsSync","readFileSync","readdirSync","join","createLogger","log","createLogger","log"]}
|