@openacp/cli 0.3.2 → 0.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/{autostart-N4HIL6C3.js → autostart-DZ3MHHMM.js} +3 -3
- package/dist/{chunk-LVSQQRCF.js → chunk-2SY7Y2VB.js} +3 -3
- package/dist/{chunk-7W5SOJPD.js → chunk-3QACY5E3.js} +2 -2
- package/dist/{chunk-CA6FXPLH.js → chunk-BLVZFCKN.js} +4 -4
- package/dist/chunk-KSIQZC3J.js +98 -0
- package/dist/chunk-KSIQZC3J.js.map +1 -0
- package/dist/{chunk-JOSJGZGF.js → chunk-LYKCQTH5.js} +1 -9
- package/dist/{chunk-JOSJGZGF.js.map → chunk-LYKCQTH5.js.map} +1 -1
- package/dist/{chunk-5E6ZXCNN.js → chunk-MRKYJ422.js} +2 -2
- package/dist/{chunk-RBDPCHGD.js → chunk-V3BA2MJ6.js} +2 -2
- package/dist/{chunk-YXMRR2E3.js → chunk-WF5XDN4D.js} +65 -40
- package/dist/chunk-WF5XDN4D.js.map +1 -0
- package/dist/{chunk-NS2L445T.js → chunk-WHKLPZGK.js} +4 -4
- package/dist/{chunk-66PHSLNS.js → chunk-WXPN5UOT.js} +599 -323
- package/dist/chunk-WXPN5UOT.js.map +1 -0
- package/dist/cli.js +258 -316
- package/dist/cli.js.map +1 -1
- package/dist/{config-2CBRLF3R.js → config-J5YQOMDU.js} +3 -3
- package/dist/config-editor-IXL4BFG3.js +11 -0
- package/dist/{daemon-UXC7PB4P.js → daemon-SLGQGRKO.js} +4 -4
- package/dist/index.d.ts +184 -71
- package/dist/index.js +18 -10
- package/dist/install-cloudflared-ILUXKLAC.js +8 -0
- package/dist/{main-P3OUOY7X.js → main-5QGMP7VG.js} +53 -17
- package/dist/main-5QGMP7VG.js.map +1 -0
- package/dist/{setup-UKWBLJIT.js → setup-JQZBPXWS.js} +4 -4
- package/dist/{tunnel-service-4GISQZNP.js → tunnel-service-DASSH7OA.js} +3 -3
- package/dist/version-VC5CPXBX.js +15 -0
- package/dist/version-VC5CPXBX.js.map +1 -0
- package/package.json +1 -1
- package/dist/chunk-66PHSLNS.js.map +0 -1
- package/dist/chunk-YXMRR2E3.js.map +0 -1
- package/dist/config-editor-UN56HQCW.js +0 -11
- package/dist/install-cloudflared-LMM7MFQX.js +0 -8
- package/dist/main-P3OUOY7X.js.map +0 -1
- /package/dist/{autostart-N4HIL6C3.js.map → autostart-DZ3MHHMM.js.map} +0 -0
- /package/dist/{chunk-LVSQQRCF.js.map → chunk-2SY7Y2VB.js.map} +0 -0
- /package/dist/{chunk-7W5SOJPD.js.map → chunk-3QACY5E3.js.map} +0 -0
- /package/dist/{chunk-CA6FXPLH.js.map → chunk-BLVZFCKN.js.map} +0 -0
- /package/dist/{chunk-5E6ZXCNN.js.map → chunk-MRKYJ422.js.map} +0 -0
- /package/dist/{chunk-RBDPCHGD.js.map → chunk-V3BA2MJ6.js.map} +0 -0
- /package/dist/{chunk-NS2L445T.js.map → chunk-WHKLPZGK.js.map} +0 -0
- /package/dist/{config-2CBRLF3R.js.map → config-J5YQOMDU.js.map} +0 -0
- /package/dist/{config-editor-UN56HQCW.js.map → config-editor-IXL4BFG3.js.map} +0 -0
- /package/dist/{daemon-UXC7PB4P.js.map → daemon-SLGQGRKO.js.map} +0 -0
- /package/dist/{install-cloudflared-LMM7MFQX.js.map → install-cloudflared-ILUXKLAC.js.map} +0 -0
- /package/dist/{setup-UKWBLJIT.js.map → setup-JQZBPXWS.js.map} +0 -0
- /package/dist/{tunnel-service-4GISQZNP.js.map → tunnel-service-DASSH7OA.js.map} +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createChildLogger,
|
|
3
3
|
createSessionLogger
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-LYKCQTH5.js";
|
|
5
5
|
|
|
6
6
|
// src/core/streams.ts
|
|
7
7
|
function nodeToWebWritable(nodeStream) {
|
|
@@ -504,10 +504,174 @@ var AgentManager = class {
|
|
|
504
504
|
}
|
|
505
505
|
};
|
|
506
506
|
|
|
507
|
+
// src/core/typed-emitter.ts
|
|
508
|
+
var TypedEmitter = class {
|
|
509
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
510
|
+
listeners = /* @__PURE__ */ new Map();
|
|
511
|
+
paused = false;
|
|
512
|
+
buffer = [];
|
|
513
|
+
on(event, listener) {
|
|
514
|
+
let set = this.listeners.get(event);
|
|
515
|
+
if (!set) {
|
|
516
|
+
set = /* @__PURE__ */ new Set();
|
|
517
|
+
this.listeners.set(event, set);
|
|
518
|
+
}
|
|
519
|
+
set.add(listener);
|
|
520
|
+
return this;
|
|
521
|
+
}
|
|
522
|
+
off(event, listener) {
|
|
523
|
+
this.listeners.get(event)?.delete(listener);
|
|
524
|
+
return this;
|
|
525
|
+
}
|
|
526
|
+
emit(event, ...args) {
|
|
527
|
+
if (this.paused) {
|
|
528
|
+
if (this.passthroughFn?.(event, args)) {
|
|
529
|
+
this.deliver(event, args);
|
|
530
|
+
} else {
|
|
531
|
+
this.buffer.push({ event, args });
|
|
532
|
+
}
|
|
533
|
+
return;
|
|
534
|
+
}
|
|
535
|
+
this.deliver(event, args);
|
|
536
|
+
}
|
|
537
|
+
/**
|
|
538
|
+
* Pause event delivery. Events emitted while paused are buffered.
|
|
539
|
+
* Optionally pass a filter to allow specific events through even while paused.
|
|
540
|
+
*/
|
|
541
|
+
pause(passthrough) {
|
|
542
|
+
this.paused = true;
|
|
543
|
+
this.passthroughFn = passthrough;
|
|
544
|
+
}
|
|
545
|
+
passthroughFn;
|
|
546
|
+
/** Resume event delivery and replay buffered events in order. */
|
|
547
|
+
resume() {
|
|
548
|
+
this.paused = false;
|
|
549
|
+
this.passthroughFn = void 0;
|
|
550
|
+
const buffered = this.buffer.splice(0);
|
|
551
|
+
for (const { event, args } of buffered) {
|
|
552
|
+
this.deliver(event, args);
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
/** Discard all buffered events without delivering them. */
|
|
556
|
+
clearBuffer() {
|
|
557
|
+
this.buffer.length = 0;
|
|
558
|
+
}
|
|
559
|
+
get isPaused() {
|
|
560
|
+
return this.paused;
|
|
561
|
+
}
|
|
562
|
+
get bufferSize() {
|
|
563
|
+
return this.buffer.length;
|
|
564
|
+
}
|
|
565
|
+
removeAllListeners(event) {
|
|
566
|
+
if (event) {
|
|
567
|
+
this.listeners.delete(event);
|
|
568
|
+
} else {
|
|
569
|
+
this.listeners.clear();
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
deliver(event, args) {
|
|
573
|
+
const set = this.listeners.get(event);
|
|
574
|
+
if (!set) return;
|
|
575
|
+
for (const listener of set) {
|
|
576
|
+
listener(...args);
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
};
|
|
580
|
+
|
|
581
|
+
// src/core/prompt-queue.ts
|
|
582
|
+
var PromptQueue = class {
|
|
583
|
+
constructor(processor, onError) {
|
|
584
|
+
this.processor = processor;
|
|
585
|
+
this.onError = onError;
|
|
586
|
+
}
|
|
587
|
+
queue = [];
|
|
588
|
+
processing = false;
|
|
589
|
+
async enqueue(text) {
|
|
590
|
+
if (this.processing) {
|
|
591
|
+
return new Promise((resolve) => {
|
|
592
|
+
this.queue.push({ text, resolve });
|
|
593
|
+
});
|
|
594
|
+
}
|
|
595
|
+
await this.process(text);
|
|
596
|
+
}
|
|
597
|
+
async process(text) {
|
|
598
|
+
this.processing = true;
|
|
599
|
+
try {
|
|
600
|
+
await this.processor(text);
|
|
601
|
+
} catch (err) {
|
|
602
|
+
this.onError?.(err);
|
|
603
|
+
} finally {
|
|
604
|
+
this.processing = false;
|
|
605
|
+
this.drainNext();
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
drainNext() {
|
|
609
|
+
const next = this.queue.shift();
|
|
610
|
+
if (next) {
|
|
611
|
+
this.process(next.text).then(next.resolve);
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
clear() {
|
|
615
|
+
for (const item of this.queue) {
|
|
616
|
+
item.resolve();
|
|
617
|
+
}
|
|
618
|
+
this.queue = [];
|
|
619
|
+
}
|
|
620
|
+
get pending() {
|
|
621
|
+
return this.queue.length;
|
|
622
|
+
}
|
|
623
|
+
get isProcessing() {
|
|
624
|
+
return this.processing;
|
|
625
|
+
}
|
|
626
|
+
};
|
|
627
|
+
|
|
628
|
+
// src/core/permission-gate.ts
|
|
629
|
+
var PermissionGate = class {
|
|
630
|
+
request;
|
|
631
|
+
resolveFn;
|
|
632
|
+
rejectFn;
|
|
633
|
+
settled = false;
|
|
634
|
+
setPending(request) {
|
|
635
|
+
this.request = request;
|
|
636
|
+
this.settled = false;
|
|
637
|
+
return new Promise((resolve, reject) => {
|
|
638
|
+
this.resolveFn = resolve;
|
|
639
|
+
this.rejectFn = reject;
|
|
640
|
+
});
|
|
641
|
+
}
|
|
642
|
+
resolve(optionId) {
|
|
643
|
+
if (this.settled || !this.resolveFn) return;
|
|
644
|
+
this.settled = true;
|
|
645
|
+
this.resolveFn(optionId);
|
|
646
|
+
this.cleanup();
|
|
647
|
+
}
|
|
648
|
+
reject(reason) {
|
|
649
|
+
if (this.settled || !this.rejectFn) return;
|
|
650
|
+
this.settled = true;
|
|
651
|
+
this.rejectFn(new Error(reason ?? "Permission rejected"));
|
|
652
|
+
this.cleanup();
|
|
653
|
+
}
|
|
654
|
+
get isPending() {
|
|
655
|
+
return !!this.request && !this.settled;
|
|
656
|
+
}
|
|
657
|
+
get currentRequest() {
|
|
658
|
+
return this.isPending ? this.request : void 0;
|
|
659
|
+
}
|
|
660
|
+
/** The request ID of the current pending request, undefined after settlement */
|
|
661
|
+
get requestId() {
|
|
662
|
+
return this.request?.id;
|
|
663
|
+
}
|
|
664
|
+
cleanup() {
|
|
665
|
+
this.request = void 0;
|
|
666
|
+
this.resolveFn = void 0;
|
|
667
|
+
this.rejectFn = void 0;
|
|
668
|
+
}
|
|
669
|
+
};
|
|
670
|
+
|
|
507
671
|
// src/core/session.ts
|
|
508
672
|
import { nanoid } from "nanoid";
|
|
509
673
|
var moduleLog = createChildLogger({ module: "session" });
|
|
510
|
-
var Session = class {
|
|
674
|
+
var Session = class extends TypedEmitter {
|
|
511
675
|
id;
|
|
512
676
|
channelId;
|
|
513
677
|
threadId = "";
|
|
@@ -517,15 +681,15 @@ var Session = class {
|
|
|
517
681
|
agentSessionId = "";
|
|
518
682
|
status = "initializing";
|
|
519
683
|
name;
|
|
520
|
-
promptQueue = [];
|
|
521
|
-
promptRunning = false;
|
|
522
684
|
createdAt = /* @__PURE__ */ new Date();
|
|
523
685
|
adapter;
|
|
524
686
|
// Set by wireSessionEvents for renaming
|
|
525
|
-
pendingPermission;
|
|
526
687
|
dangerousMode = false;
|
|
527
688
|
log;
|
|
689
|
+
permissionGate = new PermissionGate();
|
|
690
|
+
queue;
|
|
528
691
|
constructor(opts) {
|
|
692
|
+
super();
|
|
529
693
|
this.id = opts.id || nanoid(12);
|
|
530
694
|
this.channelId = opts.channelId;
|
|
531
695
|
this.agentName = opts.agentName;
|
|
@@ -533,45 +697,57 @@ var Session = class {
|
|
|
533
697
|
this.agentInstance = opts.agentInstance;
|
|
534
698
|
this.log = createSessionLogger(this.id, moduleLog);
|
|
535
699
|
this.log.info({ agentName: this.agentName }, "Session created");
|
|
700
|
+
this.queue = new PromptQueue(
|
|
701
|
+
(text) => this.processPrompt(text),
|
|
702
|
+
(err) => {
|
|
703
|
+
this.status = "error";
|
|
704
|
+
this.log.error({ err }, "Prompt execution failed");
|
|
705
|
+
}
|
|
706
|
+
);
|
|
707
|
+
}
|
|
708
|
+
// --- Backward-compatible properties ---
|
|
709
|
+
/** @deprecated Use permissionGate directly */
|
|
710
|
+
get pendingPermission() {
|
|
711
|
+
if (!this.permissionGate.isPending) return void 0;
|
|
712
|
+
return {
|
|
713
|
+
requestId: this.permissionGate.requestId,
|
|
714
|
+
resolve: (optionId) => this.permissionGate.resolve(optionId)
|
|
715
|
+
};
|
|
716
|
+
}
|
|
717
|
+
set pendingPermission(val) {
|
|
536
718
|
}
|
|
719
|
+
/** Number of prompts waiting in queue */
|
|
720
|
+
get queueDepth() {
|
|
721
|
+
return this.queue.pending;
|
|
722
|
+
}
|
|
723
|
+
get promptRunning() {
|
|
724
|
+
return this.queue.isProcessing;
|
|
725
|
+
}
|
|
726
|
+
// --- Public API ---
|
|
537
727
|
async enqueuePrompt(text) {
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
728
|
+
await this.queue.enqueue(text);
|
|
729
|
+
}
|
|
730
|
+
async processPrompt(text) {
|
|
731
|
+
if (text === "\0__warmup__") {
|
|
732
|
+
await this.runWarmup();
|
|
541
733
|
return;
|
|
542
734
|
}
|
|
543
|
-
await this.runPrompt(text);
|
|
544
|
-
}
|
|
545
|
-
async runPrompt(text) {
|
|
546
|
-
this.promptRunning = true;
|
|
547
735
|
this.status = "active";
|
|
548
736
|
const promptStart = Date.now();
|
|
549
737
|
this.log.debug("Prompt execution started");
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
await this.autoName();
|
|
558
|
-
}
|
|
559
|
-
} catch (err) {
|
|
560
|
-
this.status = "error";
|
|
561
|
-
this.log.error({ err }, "Prompt execution failed");
|
|
562
|
-
} finally {
|
|
563
|
-
this.promptRunning = false;
|
|
564
|
-
if (this.promptQueue.length > 0) {
|
|
565
|
-
const next = this.promptQueue.shift();
|
|
566
|
-
await this.runPrompt(next);
|
|
567
|
-
}
|
|
738
|
+
await this.agentInstance.prompt(text);
|
|
739
|
+
this.log.info(
|
|
740
|
+
{ durationMs: Date.now() - promptStart },
|
|
741
|
+
"Prompt execution completed"
|
|
742
|
+
);
|
|
743
|
+
if (!this.name) {
|
|
744
|
+
await this.autoName();
|
|
568
745
|
}
|
|
569
746
|
}
|
|
570
747
|
// NOTE: This injects a summary prompt into the agent's conversation history.
|
|
571
|
-
// Known Phase 1 limitation — the agent sees this prompt in its context.
|
|
572
748
|
async autoName() {
|
|
573
749
|
let title = "";
|
|
574
|
-
const
|
|
750
|
+
const originalHandler = this.agentInstance.onSessionUpdate;
|
|
575
751
|
this.agentInstance.onSessionUpdate = (event) => {
|
|
576
752
|
if (event.type === "text") title += event.content;
|
|
577
753
|
};
|
|
@@ -579,7 +755,7 @@ var Session = class {
|
|
|
579
755
|
await this.agentInstance.prompt(
|
|
580
756
|
"Summarize this conversation in max 5 words for a topic title. Reply ONLY with the title, nothing else."
|
|
581
757
|
);
|
|
582
|
-
this.name = title.trim().slice(0, 50)
|
|
758
|
+
this.name = title.trim().slice(0, 50) || `Session ${this.id.slice(0, 6)}`;
|
|
583
759
|
this.log.info({ name: this.name }, "Session auto-named");
|
|
584
760
|
if (this.adapter && this.name) {
|
|
585
761
|
await this.adapter.renameSessionThread(this.id, this.name);
|
|
@@ -587,16 +763,18 @@ var Session = class {
|
|
|
587
763
|
} catch {
|
|
588
764
|
this.name = `Session ${this.id.slice(0, 6)}`;
|
|
589
765
|
} finally {
|
|
590
|
-
this.agentInstance.onSessionUpdate =
|
|
766
|
+
this.agentInstance.onSessionUpdate = originalHandler;
|
|
591
767
|
}
|
|
592
768
|
}
|
|
593
769
|
/** Fire-and-forget warm-up: primes model cache while user types their first message */
|
|
594
770
|
async warmup() {
|
|
595
|
-
this.
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
771
|
+
await this.queue.enqueue("\0__warmup__");
|
|
772
|
+
}
|
|
773
|
+
async runWarmup() {
|
|
774
|
+
this.pause((_event, args) => {
|
|
775
|
+
const agentEvent = args[0];
|
|
776
|
+
return agentEvent?.type === "commands_update";
|
|
777
|
+
});
|
|
600
778
|
try {
|
|
601
779
|
const start = Date.now();
|
|
602
780
|
await this.agentInstance.prompt('Reply with only "ready".');
|
|
@@ -605,19 +783,14 @@ var Session = class {
|
|
|
605
783
|
} catch (err) {
|
|
606
784
|
this.log.error({ err }, "Warm-up failed");
|
|
607
785
|
} finally {
|
|
608
|
-
this.
|
|
609
|
-
this.
|
|
610
|
-
if (this.promptQueue.length > 0) {
|
|
611
|
-
const next = this.promptQueue.shift();
|
|
612
|
-
await this.runPrompt(next);
|
|
613
|
-
}
|
|
786
|
+
this.clearBuffer();
|
|
787
|
+
this.resume();
|
|
614
788
|
}
|
|
615
789
|
}
|
|
616
790
|
async cancel() {
|
|
617
|
-
this.
|
|
791
|
+
this.queue.clear();
|
|
618
792
|
this.log.info("Session cancelled");
|
|
619
793
|
await this.agentInstance.cancel();
|
|
620
|
-
this.promptRunning = false;
|
|
621
794
|
this.status = "active";
|
|
622
795
|
}
|
|
623
796
|
async destroy() {
|
|
@@ -764,6 +937,206 @@ var NotificationManager = class {
|
|
|
764
937
|
}
|
|
765
938
|
};
|
|
766
939
|
|
|
940
|
+
// src/tunnel/extract-file-info.ts
|
|
941
|
+
function extractFileInfo(name, kind, content, rawInput, meta) {
|
|
942
|
+
if (kind && !["read", "edit", "write"].includes(kind)) return null;
|
|
943
|
+
let info = null;
|
|
944
|
+
if (meta) {
|
|
945
|
+
const m = meta;
|
|
946
|
+
const tr = m?.claudeCode?.toolResponse;
|
|
947
|
+
const file = tr?.file;
|
|
948
|
+
if (file?.filePath && file?.content) {
|
|
949
|
+
info = { filePath: file.filePath, content: file.content };
|
|
950
|
+
}
|
|
951
|
+
if (!info && tr?.filePath && tr?.content) {
|
|
952
|
+
info = { filePath: tr.filePath, content: tr.content };
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
if (!info && rawInput) {
|
|
956
|
+
const ri = rawInput;
|
|
957
|
+
const filePath = ri?.file_path || ri?.filePath || ri?.path;
|
|
958
|
+
if (typeof filePath === "string") {
|
|
959
|
+
const parsed = content ? parseContent(content) : null;
|
|
960
|
+
info = { filePath, content: parsed?.content || ri?.content, oldContent: parsed?.oldContent };
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
if (!info && content) {
|
|
964
|
+
info = parseContent(content);
|
|
965
|
+
}
|
|
966
|
+
if (!info) return null;
|
|
967
|
+
if (!info.filePath) {
|
|
968
|
+
const pathMatch = name.match(/(?:Read|Edit|Write|View)\s+(.+)/i);
|
|
969
|
+
if (pathMatch) info.filePath = pathMatch[1].trim();
|
|
970
|
+
}
|
|
971
|
+
if (!info.filePath || !info.content) return null;
|
|
972
|
+
return info;
|
|
973
|
+
}
|
|
974
|
+
function parseContent(content) {
|
|
975
|
+
if (typeof content === "string") {
|
|
976
|
+
return { content };
|
|
977
|
+
}
|
|
978
|
+
if (Array.isArray(content)) {
|
|
979
|
+
for (const block of content) {
|
|
980
|
+
const result = parseContent(block);
|
|
981
|
+
if (result?.content || result?.filePath) return result;
|
|
982
|
+
}
|
|
983
|
+
return null;
|
|
984
|
+
}
|
|
985
|
+
if (typeof content === "object" && content !== null) {
|
|
986
|
+
const c = content;
|
|
987
|
+
if (c.type === "diff" && typeof c.path === "string") {
|
|
988
|
+
const newText = c.newText;
|
|
989
|
+
const oldText = c.oldText;
|
|
990
|
+
if (newText) {
|
|
991
|
+
return {
|
|
992
|
+
filePath: c.path,
|
|
993
|
+
content: newText,
|
|
994
|
+
oldContent: oldText ?? void 0
|
|
995
|
+
};
|
|
996
|
+
}
|
|
997
|
+
}
|
|
998
|
+
if (c.type === "content" && c.content) {
|
|
999
|
+
return parseContent(c.content);
|
|
1000
|
+
}
|
|
1001
|
+
if (c.type === "text" && typeof c.text === "string") {
|
|
1002
|
+
return { content: c.text, filePath: c.filePath };
|
|
1003
|
+
}
|
|
1004
|
+
if (typeof c.text === "string") {
|
|
1005
|
+
return { content: c.text, filePath: c.filePath };
|
|
1006
|
+
}
|
|
1007
|
+
if (typeof c.file_path === "string" || typeof c.filePath === "string" || typeof c.path === "string") {
|
|
1008
|
+
const filePath = c.file_path || c.filePath || c.path;
|
|
1009
|
+
const fileContent = c.content || c.text || c.output || c.newText;
|
|
1010
|
+
if (typeof fileContent === "string") {
|
|
1011
|
+
return {
|
|
1012
|
+
filePath,
|
|
1013
|
+
content: fileContent,
|
|
1014
|
+
oldContent: c.old_content || c.oldText
|
|
1015
|
+
};
|
|
1016
|
+
}
|
|
1017
|
+
}
|
|
1018
|
+
if (c.input) {
|
|
1019
|
+
const result = parseContent(c.input);
|
|
1020
|
+
if (result) return result;
|
|
1021
|
+
}
|
|
1022
|
+
if (c.output) {
|
|
1023
|
+
const result = parseContent(c.output);
|
|
1024
|
+
if (result) return result;
|
|
1025
|
+
}
|
|
1026
|
+
}
|
|
1027
|
+
return null;
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
// src/core/message-transformer.ts
|
|
1031
|
+
var log2 = createChildLogger({ module: "message-transformer" });
|
|
1032
|
+
var MessageTransformer = class {
|
|
1033
|
+
constructor(tunnelService) {
|
|
1034
|
+
this.tunnelService = tunnelService;
|
|
1035
|
+
}
|
|
1036
|
+
transform(event, sessionContext) {
|
|
1037
|
+
switch (event.type) {
|
|
1038
|
+
case "text":
|
|
1039
|
+
return { type: "text", text: event.content };
|
|
1040
|
+
case "thought":
|
|
1041
|
+
return { type: "thought", text: event.content };
|
|
1042
|
+
case "tool_call": {
|
|
1043
|
+
const metadata = {
|
|
1044
|
+
id: event.id,
|
|
1045
|
+
name: event.name,
|
|
1046
|
+
kind: event.kind,
|
|
1047
|
+
status: event.status,
|
|
1048
|
+
content: event.content,
|
|
1049
|
+
locations: event.locations
|
|
1050
|
+
};
|
|
1051
|
+
this.enrichWithViewerLinks(event, metadata, sessionContext);
|
|
1052
|
+
return { type: "tool_call", text: event.name, metadata };
|
|
1053
|
+
}
|
|
1054
|
+
case "tool_update": {
|
|
1055
|
+
const metadata = {
|
|
1056
|
+
id: event.id,
|
|
1057
|
+
name: event.name,
|
|
1058
|
+
kind: event.kind,
|
|
1059
|
+
status: event.status,
|
|
1060
|
+
content: event.content
|
|
1061
|
+
};
|
|
1062
|
+
this.enrichWithViewerLinks(event, metadata, sessionContext);
|
|
1063
|
+
return { type: "tool_update", text: "", metadata };
|
|
1064
|
+
}
|
|
1065
|
+
case "plan":
|
|
1066
|
+
return {
|
|
1067
|
+
type: "plan",
|
|
1068
|
+
text: "",
|
|
1069
|
+
metadata: { entries: event.entries }
|
|
1070
|
+
};
|
|
1071
|
+
case "usage":
|
|
1072
|
+
return {
|
|
1073
|
+
type: "usage",
|
|
1074
|
+
text: "",
|
|
1075
|
+
metadata: {
|
|
1076
|
+
tokensUsed: event.tokensUsed,
|
|
1077
|
+
contextSize: event.contextSize,
|
|
1078
|
+
cost: event.cost
|
|
1079
|
+
}
|
|
1080
|
+
};
|
|
1081
|
+
case "session_end":
|
|
1082
|
+
return { type: "session_end", text: `Done (${event.reason})` };
|
|
1083
|
+
case "error":
|
|
1084
|
+
return { type: "error", text: event.message };
|
|
1085
|
+
default:
|
|
1086
|
+
return { type: "text", text: "" };
|
|
1087
|
+
}
|
|
1088
|
+
}
|
|
1089
|
+
enrichWithViewerLinks(event, metadata, sessionContext) {
|
|
1090
|
+
if (!this.tunnelService || !sessionContext) return;
|
|
1091
|
+
const name = "name" in event ? event.name || "" : "";
|
|
1092
|
+
const kind = "kind" in event ? event.kind : void 0;
|
|
1093
|
+
log2.debug(
|
|
1094
|
+
{ name, kind, status: event.status, hasContent: !!event.content },
|
|
1095
|
+
"enrichWithViewerLinks: inspecting event"
|
|
1096
|
+
);
|
|
1097
|
+
const fileInfo = extractFileInfo(
|
|
1098
|
+
name,
|
|
1099
|
+
kind,
|
|
1100
|
+
event.content,
|
|
1101
|
+
event.rawInput,
|
|
1102
|
+
event.meta
|
|
1103
|
+
);
|
|
1104
|
+
if (!fileInfo) return;
|
|
1105
|
+
log2.info(
|
|
1106
|
+
{
|
|
1107
|
+
name,
|
|
1108
|
+
kind,
|
|
1109
|
+
filePath: fileInfo.filePath,
|
|
1110
|
+
hasOldContent: !!fileInfo.oldContent
|
|
1111
|
+
},
|
|
1112
|
+
"enrichWithViewerLinks: extracted file info"
|
|
1113
|
+
);
|
|
1114
|
+
const store = this.tunnelService.getStore();
|
|
1115
|
+
const viewerLinks = {};
|
|
1116
|
+
if (fileInfo.oldContent) {
|
|
1117
|
+
const id2 = store.storeDiff(
|
|
1118
|
+
sessionContext.id,
|
|
1119
|
+
fileInfo.filePath,
|
|
1120
|
+
fileInfo.oldContent,
|
|
1121
|
+
fileInfo.content,
|
|
1122
|
+
sessionContext.workingDirectory
|
|
1123
|
+
);
|
|
1124
|
+
if (id2) viewerLinks.diff = this.tunnelService.diffUrl(id2);
|
|
1125
|
+
}
|
|
1126
|
+
const id = store.storeFile(
|
|
1127
|
+
sessionContext.id,
|
|
1128
|
+
fileInfo.filePath,
|
|
1129
|
+
fileInfo.content,
|
|
1130
|
+
sessionContext.workingDirectory
|
|
1131
|
+
);
|
|
1132
|
+
if (id) viewerLinks.file = this.tunnelService.fileUrl(id);
|
|
1133
|
+
if (Object.keys(viewerLinks).length > 0) {
|
|
1134
|
+
metadata.viewerLinks = viewerLinks;
|
|
1135
|
+
metadata.viewerFilePath = fileInfo.filePath;
|
|
1136
|
+
}
|
|
1137
|
+
}
|
|
1138
|
+
};
|
|
1139
|
+
|
|
767
1140
|
// src/core/core.ts
|
|
768
1141
|
import path3 from "path";
|
|
769
1142
|
import os from "os";
|
|
@@ -771,7 +1144,7 @@ import os from "os";
|
|
|
771
1144
|
// src/core/session-store.ts
|
|
772
1145
|
import fs2 from "fs";
|
|
773
1146
|
import path2 from "path";
|
|
774
|
-
var
|
|
1147
|
+
var log3 = createChildLogger({ module: "session-store" });
|
|
775
1148
|
var DEBOUNCE_MS = 2e3;
|
|
776
1149
|
var JsonFileSessionStore = class {
|
|
777
1150
|
records = /* @__PURE__ */ new Map();
|
|
@@ -848,7 +1221,7 @@ var JsonFileSessionStore = class {
|
|
|
848
1221
|
fs2.readFileSync(this.filePath, "utf-8")
|
|
849
1222
|
);
|
|
850
1223
|
if (raw.version !== 1) {
|
|
851
|
-
|
|
1224
|
+
log3.warn(
|
|
852
1225
|
{ version: raw.version },
|
|
853
1226
|
"Unknown session store version, skipping load"
|
|
854
1227
|
);
|
|
@@ -857,9 +1230,9 @@ var JsonFileSessionStore = class {
|
|
|
857
1230
|
for (const [id, record] of Object.entries(raw.sessions)) {
|
|
858
1231
|
this.records.set(id, record);
|
|
859
1232
|
}
|
|
860
|
-
|
|
1233
|
+
log3.info({ count: this.records.size }, "Loaded session records");
|
|
861
1234
|
} catch (err) {
|
|
862
|
-
|
|
1235
|
+
log3.error({ err }, "Failed to load session store");
|
|
863
1236
|
}
|
|
864
1237
|
}
|
|
865
1238
|
cleanup() {
|
|
@@ -875,7 +1248,7 @@ var JsonFileSessionStore = class {
|
|
|
875
1248
|
}
|
|
876
1249
|
}
|
|
877
1250
|
if (removed > 0) {
|
|
878
|
-
|
|
1251
|
+
log3.info({ removed }, "Cleaned up expired session records");
|
|
879
1252
|
this.scheduleDiskWrite();
|
|
880
1253
|
}
|
|
881
1254
|
}
|
|
@@ -887,105 +1260,18 @@ var JsonFileSessionStore = class {
|
|
|
887
1260
|
}
|
|
888
1261
|
};
|
|
889
1262
|
|
|
890
|
-
// src/tunnel/extract-file-info.ts
|
|
891
|
-
function extractFileInfo(name, kind, content, rawInput, meta) {
|
|
892
|
-
if (kind && !["read", "edit", "write"].includes(kind)) return null;
|
|
893
|
-
let info = null;
|
|
894
|
-
if (meta) {
|
|
895
|
-
const m = meta;
|
|
896
|
-
const tr = m?.claudeCode?.toolResponse;
|
|
897
|
-
const file = tr?.file;
|
|
898
|
-
if (file?.filePath && file?.content) {
|
|
899
|
-
info = { filePath: file.filePath, content: file.content };
|
|
900
|
-
}
|
|
901
|
-
if (!info && tr?.filePath && tr?.content) {
|
|
902
|
-
info = { filePath: tr.filePath, content: tr.content };
|
|
903
|
-
}
|
|
904
|
-
}
|
|
905
|
-
if (!info && rawInput) {
|
|
906
|
-
const ri = rawInput;
|
|
907
|
-
const filePath = ri?.file_path || ri?.filePath || ri?.path;
|
|
908
|
-
if (typeof filePath === "string") {
|
|
909
|
-
const parsed = content ? parseContent(content) : null;
|
|
910
|
-
info = { filePath, content: parsed?.content || ri?.content, oldContent: parsed?.oldContent };
|
|
911
|
-
}
|
|
912
|
-
}
|
|
913
|
-
if (!info && content) {
|
|
914
|
-
info = parseContent(content);
|
|
915
|
-
}
|
|
916
|
-
if (!info) return null;
|
|
917
|
-
if (!info.filePath) {
|
|
918
|
-
const pathMatch = name.match(/(?:Read|Edit|Write|View)\s+(.+)/i);
|
|
919
|
-
if (pathMatch) info.filePath = pathMatch[1].trim();
|
|
920
|
-
}
|
|
921
|
-
if (!info.filePath || !info.content) return null;
|
|
922
|
-
return info;
|
|
923
|
-
}
|
|
924
|
-
function parseContent(content) {
|
|
925
|
-
if (typeof content === "string") {
|
|
926
|
-
return { content };
|
|
927
|
-
}
|
|
928
|
-
if (Array.isArray(content)) {
|
|
929
|
-
for (const block of content) {
|
|
930
|
-
const result = parseContent(block);
|
|
931
|
-
if (result?.content || result?.filePath) return result;
|
|
932
|
-
}
|
|
933
|
-
return null;
|
|
934
|
-
}
|
|
935
|
-
if (typeof content === "object" && content !== null) {
|
|
936
|
-
const c = content;
|
|
937
|
-
if (c.type === "diff" && typeof c.path === "string") {
|
|
938
|
-
const newText = c.newText;
|
|
939
|
-
const oldText = c.oldText;
|
|
940
|
-
if (newText) {
|
|
941
|
-
return {
|
|
942
|
-
filePath: c.path,
|
|
943
|
-
content: newText,
|
|
944
|
-
oldContent: oldText ?? void 0
|
|
945
|
-
};
|
|
946
|
-
}
|
|
947
|
-
}
|
|
948
|
-
if (c.type === "content" && c.content) {
|
|
949
|
-
return parseContent(c.content);
|
|
950
|
-
}
|
|
951
|
-
if (c.type === "text" && typeof c.text === "string") {
|
|
952
|
-
return { content: c.text, filePath: c.filePath };
|
|
953
|
-
}
|
|
954
|
-
if (typeof c.text === "string") {
|
|
955
|
-
return { content: c.text, filePath: c.filePath };
|
|
956
|
-
}
|
|
957
|
-
if (typeof c.file_path === "string" || typeof c.filePath === "string" || typeof c.path === "string") {
|
|
958
|
-
const filePath = c.file_path || c.filePath || c.path;
|
|
959
|
-
const fileContent = c.content || c.text || c.output || c.newText;
|
|
960
|
-
if (typeof fileContent === "string") {
|
|
961
|
-
return {
|
|
962
|
-
filePath,
|
|
963
|
-
content: fileContent,
|
|
964
|
-
oldContent: c.old_content || c.oldText
|
|
965
|
-
};
|
|
966
|
-
}
|
|
967
|
-
}
|
|
968
|
-
if (c.input) {
|
|
969
|
-
const result = parseContent(c.input);
|
|
970
|
-
if (result) return result;
|
|
971
|
-
}
|
|
972
|
-
if (c.output) {
|
|
973
|
-
const result = parseContent(c.output);
|
|
974
|
-
if (result) return result;
|
|
975
|
-
}
|
|
976
|
-
}
|
|
977
|
-
return null;
|
|
978
|
-
}
|
|
979
|
-
|
|
980
1263
|
// src/core/core.ts
|
|
981
|
-
var
|
|
1264
|
+
var log4 = createChildLogger({ module: "core" });
|
|
982
1265
|
var OpenACPCore = class {
|
|
983
1266
|
configManager;
|
|
984
1267
|
agentManager;
|
|
985
1268
|
sessionManager;
|
|
986
1269
|
notificationManager;
|
|
1270
|
+
messageTransformer;
|
|
987
1271
|
adapters = /* @__PURE__ */ new Map();
|
|
988
|
-
|
|
1272
|
+
/** Set by main.ts — triggers graceful shutdown with restart exit code */
|
|
1273
|
+
requestRestart = null;
|
|
1274
|
+
_tunnelService;
|
|
989
1275
|
sessionStore = null;
|
|
990
1276
|
resumeLocks = /* @__PURE__ */ new Map();
|
|
991
1277
|
constructor(configManager) {
|
|
@@ -999,6 +1285,14 @@ var OpenACPCore = class {
|
|
|
999
1285
|
);
|
|
1000
1286
|
this.sessionManager = new SessionManager(this.sessionStore);
|
|
1001
1287
|
this.notificationManager = new NotificationManager(this.adapters);
|
|
1288
|
+
this.messageTransformer = new MessageTransformer();
|
|
1289
|
+
}
|
|
1290
|
+
get tunnelService() {
|
|
1291
|
+
return this._tunnelService;
|
|
1292
|
+
}
|
|
1293
|
+
set tunnelService(service) {
|
|
1294
|
+
this._tunnelService = service;
|
|
1295
|
+
this.messageTransformer = new MessageTransformer(service);
|
|
1002
1296
|
}
|
|
1003
1297
|
registerAdapter(name, adapter) {
|
|
1004
1298
|
this.adapters.set(name, adapter);
|
|
@@ -1025,7 +1319,7 @@ var OpenACPCore = class {
|
|
|
1025
1319
|
// --- Message Routing ---
|
|
1026
1320
|
async handleMessage(message) {
|
|
1027
1321
|
const config = this.configManager.get();
|
|
1028
|
-
|
|
1322
|
+
log4.debug(
|
|
1029
1323
|
{
|
|
1030
1324
|
channelId: message.channelId,
|
|
1031
1325
|
threadId: message.threadId,
|
|
@@ -1035,7 +1329,7 @@ var OpenACPCore = class {
|
|
|
1035
1329
|
);
|
|
1036
1330
|
if (config.security.allowedUserIds.length > 0) {
|
|
1037
1331
|
if (!config.security.allowedUserIds.includes(message.userId)) {
|
|
1038
|
-
|
|
1332
|
+
log4.warn(
|
|
1039
1333
|
{ userId: message.userId },
|
|
1040
1334
|
"Rejected message from unauthorized user"
|
|
1041
1335
|
);
|
|
@@ -1044,7 +1338,7 @@ var OpenACPCore = class {
|
|
|
1044
1338
|
}
|
|
1045
1339
|
const activeSessions = this.sessionManager.listSessions().filter((s) => s.status === "active" || s.status === "initializing");
|
|
1046
1340
|
if (activeSessions.length >= config.security.maxConcurrentSessions) {
|
|
1047
|
-
|
|
1341
|
+
log4.warn(
|
|
1048
1342
|
{
|
|
1049
1343
|
userId: message.userId,
|
|
1050
1344
|
currentCount: activeSessions.length,
|
|
@@ -1075,7 +1369,7 @@ var OpenACPCore = class {
|
|
|
1075
1369
|
async handleNewSession(channelId, agentName, workspacePath) {
|
|
1076
1370
|
const config = this.configManager.get();
|
|
1077
1371
|
const resolvedAgent = agentName || config.defaultAgent;
|
|
1078
|
-
|
|
1372
|
+
log4.info({ channelId, agentName: resolvedAgent }, "New session request");
|
|
1079
1373
|
const resolvedWorkspace = this.configManager.resolveWorkspace(
|
|
1080
1374
|
workspacePath || config.agents[resolvedAgent]?.workingDirectory
|
|
1081
1375
|
);
|
|
@@ -1153,13 +1447,13 @@ var OpenACPCore = class {
|
|
|
1153
1447
|
status: "active",
|
|
1154
1448
|
lastActiveAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1155
1449
|
});
|
|
1156
|
-
|
|
1450
|
+
log4.info(
|
|
1157
1451
|
{ sessionId: session.id, threadId: message.threadId },
|
|
1158
1452
|
"Lazy resume successful"
|
|
1159
1453
|
);
|
|
1160
1454
|
return session;
|
|
1161
1455
|
} catch (err) {
|
|
1162
|
-
|
|
1456
|
+
log4.error({ err, record }, "Lazy resume failed");
|
|
1163
1457
|
return null;
|
|
1164
1458
|
} finally {
|
|
1165
1459
|
this.resumeLocks.delete(lockKey);
|
|
@@ -1169,98 +1463,27 @@ var OpenACPCore = class {
|
|
|
1169
1463
|
return resumePromise;
|
|
1170
1464
|
}
|
|
1171
1465
|
// --- Event Wiring ---
|
|
1172
|
-
toOutgoingMessage(event, session) {
|
|
1173
|
-
switch (event.type) {
|
|
1174
|
-
case "text":
|
|
1175
|
-
return { type: "text", text: event.content };
|
|
1176
|
-
case "thought":
|
|
1177
|
-
return { type: "thought", text: event.content };
|
|
1178
|
-
case "tool_call": {
|
|
1179
|
-
const metadata = {
|
|
1180
|
-
id: event.id,
|
|
1181
|
-
name: event.name,
|
|
1182
|
-
kind: event.kind,
|
|
1183
|
-
status: event.status,
|
|
1184
|
-
content: event.content,
|
|
1185
|
-
locations: event.locations
|
|
1186
|
-
};
|
|
1187
|
-
this.enrichWithViewerLinks(event, metadata, session);
|
|
1188
|
-
return { type: "tool_call", text: event.name, metadata };
|
|
1189
|
-
}
|
|
1190
|
-
case "tool_update": {
|
|
1191
|
-
const metadata = {
|
|
1192
|
-
id: event.id,
|
|
1193
|
-
name: event.name,
|
|
1194
|
-
kind: event.kind,
|
|
1195
|
-
status: event.status,
|
|
1196
|
-
content: event.content
|
|
1197
|
-
};
|
|
1198
|
-
this.enrichWithViewerLinks(event, metadata, session);
|
|
1199
|
-
return { type: "tool_update", text: "", metadata };
|
|
1200
|
-
}
|
|
1201
|
-
case "plan":
|
|
1202
|
-
return { type: "plan", text: "", metadata: { entries: event.entries } };
|
|
1203
|
-
case "usage":
|
|
1204
|
-
return {
|
|
1205
|
-
type: "usage",
|
|
1206
|
-
text: "",
|
|
1207
|
-
metadata: {
|
|
1208
|
-
tokensUsed: event.tokensUsed,
|
|
1209
|
-
contextSize: event.contextSize,
|
|
1210
|
-
cost: event.cost
|
|
1211
|
-
}
|
|
1212
|
-
};
|
|
1213
|
-
default:
|
|
1214
|
-
return { type: "text", text: "" };
|
|
1215
|
-
}
|
|
1216
|
-
}
|
|
1217
|
-
enrichWithViewerLinks(event, metadata, session) {
|
|
1218
|
-
if (!this.tunnelService || !session) return;
|
|
1219
|
-
const name = "name" in event ? event.name || "" : "";
|
|
1220
|
-
const kind = "kind" in event ? event.kind : void 0;
|
|
1221
|
-
log3.debug(
|
|
1222
|
-
{ name, kind, status: event.status, hasContent: !!event.content },
|
|
1223
|
-
"enrichWithViewerLinks: inspecting event"
|
|
1224
|
-
);
|
|
1225
|
-
const fileInfo = extractFileInfo(name, kind, event.content, event.rawInput, event.meta);
|
|
1226
|
-
if (!fileInfo) return;
|
|
1227
|
-
log3.info(
|
|
1228
|
-
{
|
|
1229
|
-
name,
|
|
1230
|
-
kind,
|
|
1231
|
-
filePath: fileInfo.filePath,
|
|
1232
|
-
hasOldContent: !!fileInfo.oldContent
|
|
1233
|
-
},
|
|
1234
|
-
"enrichWithViewerLinks: extracted file info"
|
|
1235
|
-
);
|
|
1236
|
-
const store = this.tunnelService.getStore();
|
|
1237
|
-
const viewerLinks = {};
|
|
1238
|
-
if (fileInfo.oldContent) {
|
|
1239
|
-
const id2 = store.storeDiff(
|
|
1240
|
-
session.id,
|
|
1241
|
-
fileInfo.filePath,
|
|
1242
|
-
fileInfo.oldContent,
|
|
1243
|
-
fileInfo.content,
|
|
1244
|
-
session.workingDirectory
|
|
1245
|
-
);
|
|
1246
|
-
if (id2) viewerLinks.diff = this.tunnelService.diffUrl(id2);
|
|
1247
|
-
}
|
|
1248
|
-
const id = store.storeFile(
|
|
1249
|
-
session.id,
|
|
1250
|
-
fileInfo.filePath,
|
|
1251
|
-
fileInfo.content,
|
|
1252
|
-
session.workingDirectory
|
|
1253
|
-
);
|
|
1254
|
-
if (id) viewerLinks.file = this.tunnelService.fileUrl(id);
|
|
1255
|
-
if (Object.keys(viewerLinks).length > 0) {
|
|
1256
|
-
metadata.viewerLinks = viewerLinks;
|
|
1257
|
-
metadata.viewerFilePath = fileInfo.filePath;
|
|
1258
|
-
}
|
|
1259
|
-
}
|
|
1260
1466
|
// Public — adapters call this for assistant session wiring
|
|
1261
1467
|
wireSessionEvents(session, adapter) {
|
|
1262
1468
|
session.adapter = adapter;
|
|
1263
1469
|
session.agentInstance.onSessionUpdate = (event) => {
|
|
1470
|
+
session.emit("agent_event", event);
|
|
1471
|
+
};
|
|
1472
|
+
session.agentInstance.onPermissionRequest = async (request) => {
|
|
1473
|
+
session.emit("permission_request", request);
|
|
1474
|
+
const promise = session.permissionGate.setPending(request);
|
|
1475
|
+
await adapter.sendPermissionRequest(session.id, request);
|
|
1476
|
+
return promise;
|
|
1477
|
+
};
|
|
1478
|
+
const sessionContext = {
|
|
1479
|
+
get id() {
|
|
1480
|
+
return session.id;
|
|
1481
|
+
},
|
|
1482
|
+
get workingDirectory() {
|
|
1483
|
+
return session.workingDirectory;
|
|
1484
|
+
}
|
|
1485
|
+
};
|
|
1486
|
+
session.on("agent_event", (event) => {
|
|
1264
1487
|
switch (event.type) {
|
|
1265
1488
|
case "text":
|
|
1266
1489
|
case "thought":
|
|
@@ -1270,17 +1493,17 @@ var OpenACPCore = class {
|
|
|
1270
1493
|
case "usage":
|
|
1271
1494
|
adapter.sendMessage(
|
|
1272
1495
|
session.id,
|
|
1273
|
-
this.
|
|
1496
|
+
this.messageTransformer.transform(event, sessionContext)
|
|
1274
1497
|
);
|
|
1275
1498
|
break;
|
|
1276
1499
|
case "session_end":
|
|
1277
1500
|
session.status = "finished";
|
|
1278
1501
|
this.sessionManager.updateSessionStatus(session.id, "finished");
|
|
1279
1502
|
adapter.cleanupSkillCommands(session.id);
|
|
1280
|
-
adapter.sendMessage(
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1503
|
+
adapter.sendMessage(
|
|
1504
|
+
session.id,
|
|
1505
|
+
this.messageTransformer.transform(event)
|
|
1506
|
+
);
|
|
1284
1507
|
this.notificationManager.notify(session.channelId, {
|
|
1285
1508
|
sessionId: session.id,
|
|
1286
1509
|
sessionName: session.name,
|
|
@@ -1291,10 +1514,10 @@ var OpenACPCore = class {
|
|
|
1291
1514
|
case "error":
|
|
1292
1515
|
this.sessionManager.updateSessionStatus(session.id, "error");
|
|
1293
1516
|
adapter.cleanupSkillCommands(session.id);
|
|
1294
|
-
adapter.sendMessage(
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1517
|
+
adapter.sendMessage(
|
|
1518
|
+
session.id,
|
|
1519
|
+
this.messageTransformer.transform(event)
|
|
1520
|
+
);
|
|
1298
1521
|
this.notificationManager.notify(session.channelId, {
|
|
1299
1522
|
sessionId: session.id,
|
|
1300
1523
|
sessionName: session.name,
|
|
@@ -1303,18 +1526,11 @@ var OpenACPCore = class {
|
|
|
1303
1526
|
});
|
|
1304
1527
|
break;
|
|
1305
1528
|
case "commands_update":
|
|
1306
|
-
|
|
1529
|
+
log4.debug({ commands: event.commands }, "Commands available");
|
|
1307
1530
|
adapter.sendSkillCommands(session.id, event.commands);
|
|
1308
1531
|
break;
|
|
1309
1532
|
}
|
|
1310
|
-
};
|
|
1311
|
-
session.agentInstance.onPermissionRequest = async (request) => {
|
|
1312
|
-
const promise = new Promise((resolve) => {
|
|
1313
|
-
session.pendingPermission = { requestId: request.id, resolve };
|
|
1314
|
-
});
|
|
1315
|
-
await adapter.sendPermissionRequest(session.id, request);
|
|
1316
|
-
return promise;
|
|
1317
|
-
};
|
|
1533
|
+
});
|
|
1318
1534
|
}
|
|
1319
1535
|
};
|
|
1320
1536
|
|
|
@@ -1336,7 +1552,7 @@ import * as http from "http";
|
|
|
1336
1552
|
import * as fs3 from "fs";
|
|
1337
1553
|
import * as path4 from "path";
|
|
1338
1554
|
import * as os2 from "os";
|
|
1339
|
-
var
|
|
1555
|
+
var log5 = createChildLogger({ module: "api-server" });
|
|
1340
1556
|
var DEFAULT_PORT_FILE = path4.join(os2.homedir(), ".openacp", "api.port");
|
|
1341
1557
|
var ApiServer = class {
|
|
1342
1558
|
constructor(core, config, portFilePath) {
|
|
@@ -1352,7 +1568,7 @@ var ApiServer = class {
|
|
|
1352
1568
|
await new Promise((resolve, reject) => {
|
|
1353
1569
|
this.server.on("error", (err) => {
|
|
1354
1570
|
if (err.code === "EADDRINUSE") {
|
|
1355
|
-
|
|
1571
|
+
log5.warn({ port: this.config.port }, "API port in use, continuing without API server");
|
|
1356
1572
|
this.server = null;
|
|
1357
1573
|
resolve();
|
|
1358
1574
|
} else {
|
|
@@ -1365,7 +1581,7 @@ var ApiServer = class {
|
|
|
1365
1581
|
this.actualPort = addr.port;
|
|
1366
1582
|
}
|
|
1367
1583
|
this.writePortFile();
|
|
1368
|
-
|
|
1584
|
+
log5.info({ host: this.config.host, port: this.actualPort }, "API server listening");
|
|
1369
1585
|
resolve();
|
|
1370
1586
|
});
|
|
1371
1587
|
});
|
|
@@ -1410,7 +1626,7 @@ var ApiServer = class {
|
|
|
1410
1626
|
this.sendJson(res, 404, { error: "Not found" });
|
|
1411
1627
|
}
|
|
1412
1628
|
} catch (err) {
|
|
1413
|
-
|
|
1629
|
+
log5.error({ err }, "API request error");
|
|
1414
1630
|
this.sendJson(res, 500, { error: "Internal server error" });
|
|
1415
1631
|
}
|
|
1416
1632
|
}
|
|
@@ -1445,17 +1661,17 @@ var ApiServer = class {
|
|
|
1445
1661
|
session.threadId = threadId;
|
|
1446
1662
|
this.core.wireSessionEvents(session, adapter);
|
|
1447
1663
|
} catch (err) {
|
|
1448
|
-
|
|
1664
|
+
log5.warn({ err, sessionId: session.id }, "Failed to create session thread on adapter, running headless");
|
|
1449
1665
|
}
|
|
1450
1666
|
}
|
|
1451
1667
|
if (!adapter) {
|
|
1452
1668
|
session.agentInstance.onPermissionRequest = async (request) => {
|
|
1453
1669
|
const allowOption = request.options.find((o) => o.isAllow);
|
|
1454
|
-
|
|
1670
|
+
log5.debug({ sessionId: session.id, permissionId: request.id, option: allowOption?.id }, "Auto-approving permission for API session");
|
|
1455
1671
|
return allowOption?.id ?? request.options[0]?.id ?? "";
|
|
1456
1672
|
};
|
|
1457
1673
|
}
|
|
1458
|
-
session.warmup().catch((err) =>
|
|
1674
|
+
session.warmup().catch((err) => log5.warn({ err, sessionId: session.id }, "API session warmup failed"));
|
|
1459
1675
|
this.sendJson(res, 200, {
|
|
1460
1676
|
sessionId: session.id,
|
|
1461
1677
|
agent: session.agentName,
|
|
@@ -1825,10 +2041,10 @@ function buildDeepLink(chatId, messageId) {
|
|
|
1825
2041
|
// src/adapters/telegram/commands.ts
|
|
1826
2042
|
import { InlineKeyboard } from "grammy";
|
|
1827
2043
|
import { nanoid as nanoid2 } from "nanoid";
|
|
1828
|
-
var
|
|
2044
|
+
var log7 = createChildLogger({ module: "telegram-commands" });
|
|
1829
2045
|
function setupCommands(bot, core, chatId, assistant) {
|
|
1830
2046
|
bot.command("new", (ctx) => handleNew(ctx, core, chatId, assistant));
|
|
1831
|
-
bot.command("
|
|
2047
|
+
bot.command("newchat", (ctx) => handleNewChat(ctx, core, chatId));
|
|
1832
2048
|
bot.command("cancel", (ctx) => handleCancel(ctx, core, assistant));
|
|
1833
2049
|
bot.command("status", (ctx) => handleStatus(ctx, core));
|
|
1834
2050
|
bot.command("agents", (ctx) => handleAgents(ctx, core));
|
|
@@ -1836,9 +2052,11 @@ function setupCommands(bot, core, chatId, assistant) {
|
|
|
1836
2052
|
bot.command("menu", (ctx) => handleMenu(ctx));
|
|
1837
2053
|
bot.command("enable_dangerous", (ctx) => handleEnableDangerous(ctx, core));
|
|
1838
2054
|
bot.command("disable_dangerous", (ctx) => handleDisableDangerous(ctx, core));
|
|
2055
|
+
bot.command("restart", (ctx) => handleRestart(ctx, core));
|
|
2056
|
+
bot.command("update", (ctx) => handleUpdate(ctx, core));
|
|
1839
2057
|
}
|
|
1840
2058
|
function buildMenuKeyboard() {
|
|
1841
|
-
return new InlineKeyboard().text("\u{1F195} New Session", "m:new").text("\u{1F4AC} New Chat", "m:
|
|
2059
|
+
return new InlineKeyboard().text("\u{1F195} New Session", "m:new").text("\u{1F4AC} New Chat", "m:newchat").row().text("\u26D4 Cancel", "m:cancel").text("\u{1F4CA} Status", "m:status").row().text("\u{1F916} Agents", "m:agents").text("\u2753 Help", "m:help").row().text("\u{1F504} Restart", "m:restart").text("\u2B06\uFE0F Update", "m:update");
|
|
1842
2060
|
}
|
|
1843
2061
|
function setupMenuCallbacks(bot, core, chatId) {
|
|
1844
2062
|
bot.callbackQuery(/^m:/, async (ctx) => {
|
|
@@ -1851,7 +2069,7 @@ function setupMenuCallbacks(bot, core, chatId) {
|
|
|
1851
2069
|
case "m:new":
|
|
1852
2070
|
await handleNew(ctx, core, chatId);
|
|
1853
2071
|
break;
|
|
1854
|
-
case "m:
|
|
2072
|
+
case "m:newchat":
|
|
1855
2073
|
await handleNewChat(ctx, core, chatId);
|
|
1856
2074
|
break;
|
|
1857
2075
|
case "m:cancel":
|
|
@@ -1866,6 +2084,12 @@ function setupMenuCallbacks(bot, core, chatId) {
|
|
|
1866
2084
|
case "m:help":
|
|
1867
2085
|
await handleHelp(ctx);
|
|
1868
2086
|
break;
|
|
2087
|
+
case "m:restart":
|
|
2088
|
+
await handleRestart(ctx, core);
|
|
2089
|
+
break;
|
|
2090
|
+
case "m:update":
|
|
2091
|
+
await handleUpdate(ctx, core);
|
|
2092
|
+
break;
|
|
1869
2093
|
}
|
|
1870
2094
|
});
|
|
1871
2095
|
}
|
|
@@ -1891,7 +2115,7 @@ async function handleNew(ctx, core, chatId, assistant) {
|
|
|
1891
2115
|
return;
|
|
1892
2116
|
}
|
|
1893
2117
|
}
|
|
1894
|
-
|
|
2118
|
+
log7.info({ userId: ctx.from?.id, agentName }, "New session command");
|
|
1895
2119
|
let threadId;
|
|
1896
2120
|
try {
|
|
1897
2121
|
const topicName = `\u{1F504} New Session`;
|
|
@@ -1925,9 +2149,9 @@ async function handleNew(ctx, core, chatId, assistant) {
|
|
|
1925
2149
|
reply_markup: buildDangerousModeKeyboard(session.id, false)
|
|
1926
2150
|
}
|
|
1927
2151
|
);
|
|
1928
|
-
session.warmup().catch((err) =>
|
|
2152
|
+
session.warmup().catch((err) => log7.error({ err }, "Warm-up error"));
|
|
1929
2153
|
} catch (err) {
|
|
1930
|
-
|
|
2154
|
+
log7.error({ err }, "Session creation failed");
|
|
1931
2155
|
if (threadId) {
|
|
1932
2156
|
try {
|
|
1933
2157
|
await ctx.api.deleteForumTopic(chatId, threadId);
|
|
@@ -1942,7 +2166,7 @@ async function handleNewChat(ctx, core, chatId) {
|
|
|
1942
2166
|
const threadId = ctx.message?.message_thread_id;
|
|
1943
2167
|
if (!threadId) {
|
|
1944
2168
|
await ctx.reply(
|
|
1945
|
-
"Use /
|
|
2169
|
+
"Use /newchat inside a session topic to inherit its config.",
|
|
1946
2170
|
{ parse_mode: "HTML" }
|
|
1947
2171
|
);
|
|
1948
2172
|
return;
|
|
@@ -1999,7 +2223,7 @@ async function handleNewChat(ctx, core, chatId) {
|
|
|
1999
2223
|
reply_markup: buildDangerousModeKeyboard(session.id, false)
|
|
2000
2224
|
}
|
|
2001
2225
|
);
|
|
2002
|
-
session.warmup().catch((err) =>
|
|
2226
|
+
session.warmup().catch((err) => log7.error({ err }, "Warm-up error"));
|
|
2003
2227
|
} catch (err) {
|
|
2004
2228
|
if (newThreadId) {
|
|
2005
2229
|
try {
|
|
@@ -2028,14 +2252,14 @@ async function handleCancel(ctx, core, assistant) {
|
|
|
2028
2252
|
String(threadId)
|
|
2029
2253
|
);
|
|
2030
2254
|
if (session) {
|
|
2031
|
-
|
|
2255
|
+
log7.info({ sessionId: session.id }, "Cancel session command");
|
|
2032
2256
|
await session.cancel();
|
|
2033
2257
|
await ctx.reply("\u26D4 Session cancelled.", { parse_mode: "HTML" });
|
|
2034
2258
|
return;
|
|
2035
2259
|
}
|
|
2036
2260
|
const record = core.sessionManager.getRecordByThread("telegram", String(threadId));
|
|
2037
2261
|
if (record && record.status !== "cancelled" && record.status !== "error") {
|
|
2038
|
-
|
|
2262
|
+
log7.info({ sessionId: record.sessionId }, "Cancel session command (from store)");
|
|
2039
2263
|
await core.sessionManager.cancelSession(record.sessionId);
|
|
2040
2264
|
await ctx.reply("\u26D4 Session cancelled.", { parse_mode: "HTML" });
|
|
2041
2265
|
}
|
|
@@ -2053,7 +2277,7 @@ async function handleStatus(ctx, core) {
|
|
|
2053
2277
|
<b>Agent:</b> ${escapeHtml(session.agentName)}
|
|
2054
2278
|
<b>Status:</b> ${escapeHtml(session.status)}
|
|
2055
2279
|
<b>Workspace:</b> <code>${escapeHtml(session.workingDirectory)}</code>
|
|
2056
|
-
<b>Queue:</b> ${session.
|
|
2280
|
+
<b>Queue:</b> ${session.queueDepth} pending`,
|
|
2057
2281
|
{ parse_mode: "HTML" }
|
|
2058
2282
|
);
|
|
2059
2283
|
} else {
|
|
@@ -2104,11 +2328,13 @@ async function handleHelp(ctx) {
|
|
|
2104
2328
|
`<b>OpenACP Commands:</b>
|
|
2105
2329
|
|
|
2106
2330
|
/new [agent] [workspace] \u2014 Create new session
|
|
2107
|
-
/
|
|
2331
|
+
/newchat \u2014 New chat, same agent & workspace
|
|
2108
2332
|
/cancel \u2014 Cancel current session
|
|
2109
2333
|
/status \u2014 Show session/system status
|
|
2110
2334
|
/agents \u2014 List available agents
|
|
2111
2335
|
/menu \u2014 Show interactive menu
|
|
2336
|
+
/restart \u2014 Restart OpenACP
|
|
2337
|
+
/update \u2014 Update to latest version and restart
|
|
2112
2338
|
/help \u2014 Show this help
|
|
2113
2339
|
|
|
2114
2340
|
Or just chat in the \u{1F916} Assistant topic for help!`,
|
|
@@ -2133,7 +2359,7 @@ function setupDangerousModeCallbacks(bot, core) {
|
|
|
2133
2359
|
return;
|
|
2134
2360
|
}
|
|
2135
2361
|
session.dangerousMode = !session.dangerousMode;
|
|
2136
|
-
|
|
2362
|
+
log7.info({ sessionId, dangerousMode: session.dangerousMode }, "Dangerous mode toggled via button");
|
|
2137
2363
|
const toastText = session.dangerousMode ? "\u2620\uFE0F Dangerous mode enabled \u2014 permissions auto-approved" : "\u{1F510} Dangerous mode disabled \u2014 permissions shown normally";
|
|
2138
2364
|
try {
|
|
2139
2365
|
await ctx.answerCallbackQuery({ text: toastText });
|
|
@@ -2172,6 +2398,52 @@ Use /disable_dangerous to restore normal behaviour.`,
|
|
|
2172
2398
|
{ parse_mode: "HTML" }
|
|
2173
2399
|
);
|
|
2174
2400
|
}
|
|
2401
|
+
async function handleUpdate(ctx, core) {
|
|
2402
|
+
if (!core.requestRestart) {
|
|
2403
|
+
await ctx.reply("\u26A0\uFE0F Update is not available (no restart handler registered).", { parse_mode: "HTML" });
|
|
2404
|
+
return;
|
|
2405
|
+
}
|
|
2406
|
+
const { getCurrentVersion, getLatestVersion, compareVersions, runUpdate } = await import("./version-VC5CPXBX.js");
|
|
2407
|
+
const current = getCurrentVersion();
|
|
2408
|
+
const statusMsg = await ctx.reply(`\u{1F50D} Checking for updates... (current: v${escapeHtml(current)})`, { parse_mode: "HTML" });
|
|
2409
|
+
const latest = await getLatestVersion();
|
|
2410
|
+
if (!latest) {
|
|
2411
|
+
await ctx.api.editMessageText(ctx.chat.id, statusMsg.message_id, "\u274C Could not check for updates.", { parse_mode: "HTML" });
|
|
2412
|
+
return;
|
|
2413
|
+
}
|
|
2414
|
+
if (compareVersions(current, latest) >= 0) {
|
|
2415
|
+
await ctx.api.editMessageText(ctx.chat.id, statusMsg.message_id, `\u2705 Already up to date (v${escapeHtml(current)}).`, { parse_mode: "HTML" });
|
|
2416
|
+
return;
|
|
2417
|
+
}
|
|
2418
|
+
await ctx.api.editMessageText(
|
|
2419
|
+
ctx.chat.id,
|
|
2420
|
+
statusMsg.message_id,
|
|
2421
|
+
`\u2B07\uFE0F Updating v${escapeHtml(current)} \u2192 v${escapeHtml(latest)}...`,
|
|
2422
|
+
{ parse_mode: "HTML" }
|
|
2423
|
+
);
|
|
2424
|
+
const ok = await runUpdate();
|
|
2425
|
+
if (!ok) {
|
|
2426
|
+
await ctx.api.editMessageText(ctx.chat.id, statusMsg.message_id, "\u274C Update failed. Try manually: <code>npm install -g @openacp/cli@latest</code>", { parse_mode: "HTML" });
|
|
2427
|
+
return;
|
|
2428
|
+
}
|
|
2429
|
+
await ctx.api.editMessageText(
|
|
2430
|
+
ctx.chat.id,
|
|
2431
|
+
statusMsg.message_id,
|
|
2432
|
+
`\u2705 Updated to v${escapeHtml(latest)}. Restarting...`,
|
|
2433
|
+
{ parse_mode: "HTML" }
|
|
2434
|
+
);
|
|
2435
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
2436
|
+
await core.requestRestart();
|
|
2437
|
+
}
|
|
2438
|
+
async function handleRestart(ctx, core) {
|
|
2439
|
+
if (!core.requestRestart) {
|
|
2440
|
+
await ctx.reply("\u26A0\uFE0F Restart is not available (no restart handler registered).", { parse_mode: "HTML" });
|
|
2441
|
+
return;
|
|
2442
|
+
}
|
|
2443
|
+
await ctx.reply("\u{1F504} <b>Restarting OpenACP...</b>\nRebuilding and restarting. Be back shortly.", { parse_mode: "HTML" });
|
|
2444
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
2445
|
+
await core.requestRestart();
|
|
2446
|
+
}
|
|
2175
2447
|
async function handleDisableDangerous(ctx, core) {
|
|
2176
2448
|
const threadId = ctx.message?.message_thread_id;
|
|
2177
2449
|
if (!threadId) {
|
|
@@ -2248,7 +2520,7 @@ async function executeNewSession(bot, core, chatId, agentName, workspace) {
|
|
|
2248
2520
|
});
|
|
2249
2521
|
const finalName = `\u{1F504} ${session.agentName} \u2014 New Session`;
|
|
2250
2522
|
await renameSessionTopic(bot, chatId, threadId, finalName);
|
|
2251
|
-
session.warmup().catch((err) =>
|
|
2523
|
+
session.warmup().catch((err) => log7.error({ err }, "Warm-up error"));
|
|
2252
2524
|
return { session, threadId, firstMsgId };
|
|
2253
2525
|
} catch (err) {
|
|
2254
2526
|
try {
|
|
@@ -2267,20 +2539,22 @@ async function executeCancelSession(core, excludeSessionId) {
|
|
|
2267
2539
|
}
|
|
2268
2540
|
var STATIC_COMMANDS = [
|
|
2269
2541
|
{ command: "new", description: "Create new session" },
|
|
2270
|
-
{ command: "
|
|
2542
|
+
{ command: "newchat", description: "New chat, same agent & workspace" },
|
|
2271
2543
|
{ command: "cancel", description: "Cancel current session" },
|
|
2272
2544
|
{ command: "status", description: "Show status" },
|
|
2273
2545
|
{ command: "agents", description: "List available agents" },
|
|
2274
2546
|
{ command: "help", description: "Help" },
|
|
2275
2547
|
{ command: "menu", description: "Show menu" },
|
|
2276
2548
|
{ command: "enable_dangerous", description: "Auto-approve all permission requests (session only)" },
|
|
2277
|
-
{ command: "disable_dangerous", description: "Restore normal permission prompts (session only)" }
|
|
2549
|
+
{ command: "disable_dangerous", description: "Restore normal permission prompts (session only)" },
|
|
2550
|
+
{ command: "restart", description: "Restart OpenACP" },
|
|
2551
|
+
{ command: "update", description: "Update to latest version and restart" }
|
|
2278
2552
|
];
|
|
2279
2553
|
|
|
2280
2554
|
// src/adapters/telegram/permissions.ts
|
|
2281
2555
|
import { InlineKeyboard as InlineKeyboard2 } from "grammy";
|
|
2282
2556
|
import { nanoid as nanoid3 } from "nanoid";
|
|
2283
|
-
var
|
|
2557
|
+
var log8 = createChildLogger({ module: "telegram-permissions" });
|
|
2284
2558
|
var PermissionHandler = class {
|
|
2285
2559
|
constructor(bot, chatId, getSession, sendNotification) {
|
|
2286
2560
|
this.bot = bot;
|
|
@@ -2340,10 +2614,9 @@ ${escapeHtml(request.description)}`,
|
|
|
2340
2614
|
}
|
|
2341
2615
|
const session = this.getSession(pending.sessionId);
|
|
2342
2616
|
const isAllow = pending.options.find((o) => o.id === optionId)?.isAllow ?? false;
|
|
2343
|
-
|
|
2344
|
-
if (session?.
|
|
2345
|
-
session.
|
|
2346
|
-
session.pendingPermission = void 0;
|
|
2617
|
+
log8.info({ requestId: pending.requestId, optionId, isAllow }, "Permission responded");
|
|
2618
|
+
if (session?.permissionGate.requestId === pending.requestId) {
|
|
2619
|
+
session.permissionGate.resolve(optionId);
|
|
2347
2620
|
}
|
|
2348
2621
|
this.pending.delete(callbackKey);
|
|
2349
2622
|
try {
|
|
@@ -2359,10 +2632,10 @@ ${escapeHtml(request.description)}`,
|
|
|
2359
2632
|
};
|
|
2360
2633
|
|
|
2361
2634
|
// src/adapters/telegram/assistant.ts
|
|
2362
|
-
var
|
|
2635
|
+
var log9 = createChildLogger({ module: "telegram-assistant" });
|
|
2363
2636
|
async function spawnAssistant(core, adapter, assistantTopicId) {
|
|
2364
2637
|
const config = core.configManager.get();
|
|
2365
|
-
|
|
2638
|
+
log9.info({ agent: config.defaultAgent }, "Creating assistant session...");
|
|
2366
2639
|
const session = await core.sessionManager.createSession(
|
|
2367
2640
|
"telegram",
|
|
2368
2641
|
config.defaultAgent,
|
|
@@ -2371,13 +2644,13 @@ async function spawnAssistant(core, adapter, assistantTopicId) {
|
|
|
2371
2644
|
);
|
|
2372
2645
|
session.threadId = String(assistantTopicId);
|
|
2373
2646
|
session.name = "Assistant";
|
|
2374
|
-
|
|
2647
|
+
log9.info({ sessionId: session.id }, "Assistant agent spawned");
|
|
2375
2648
|
core.wireSessionEvents(session, adapter);
|
|
2376
2649
|
const systemPrompt = buildAssistantSystemPrompt(config);
|
|
2377
2650
|
const ready = session.enqueuePrompt(systemPrompt).then(() => {
|
|
2378
|
-
|
|
2651
|
+
log9.info({ sessionId: session.id }, "Assistant system prompt completed");
|
|
2379
2652
|
}).catch((err) => {
|
|
2380
|
-
|
|
2653
|
+
log9.warn({ err }, "Assistant system prompt failed");
|
|
2381
2654
|
});
|
|
2382
2655
|
return { session, ready };
|
|
2383
2656
|
}
|
|
@@ -2396,7 +2669,7 @@ When a user wants to create a session, guide them through:
|
|
|
2396
2669
|
|
|
2397
2670
|
Commands reference:
|
|
2398
2671
|
- /new [agent] [workspace] \u2014 Create new session
|
|
2399
|
-
- /
|
|
2672
|
+
- /newchat \u2014 New chat with same agent & workspace
|
|
2400
2673
|
- /cancel \u2014 Cancel current session
|
|
2401
2674
|
- /status \u2014 Show status
|
|
2402
2675
|
- /agents \u2014 List agents
|
|
@@ -2415,7 +2688,7 @@ function redirectToAssistant(chatId, assistantTopicId) {
|
|
|
2415
2688
|
}
|
|
2416
2689
|
|
|
2417
2690
|
// src/adapters/telegram/activity.ts
|
|
2418
|
-
var
|
|
2691
|
+
var log10 = createChildLogger({ module: "telegram:activity" });
|
|
2419
2692
|
var THINKING_REFRESH_MS = 15e3;
|
|
2420
2693
|
var THINKING_MAX_MS = 3 * 60 * 1e3;
|
|
2421
2694
|
var ThinkingIndicator = class {
|
|
@@ -2447,7 +2720,7 @@ var ThinkingIndicator = class {
|
|
|
2447
2720
|
this.startRefreshTimer();
|
|
2448
2721
|
}
|
|
2449
2722
|
} catch (err) {
|
|
2450
|
-
|
|
2723
|
+
log10.warn({ err }, "ThinkingIndicator.show() failed");
|
|
2451
2724
|
} finally {
|
|
2452
2725
|
this.sending = false;
|
|
2453
2726
|
}
|
|
@@ -2520,7 +2793,7 @@ var UsageMessage = class {
|
|
|
2520
2793
|
if (result) this.msgId = result.message_id;
|
|
2521
2794
|
}
|
|
2522
2795
|
} catch (err) {
|
|
2523
|
-
|
|
2796
|
+
log10.warn({ err }, "UsageMessage.send() failed");
|
|
2524
2797
|
}
|
|
2525
2798
|
}
|
|
2526
2799
|
getMsgId() {
|
|
@@ -2533,7 +2806,7 @@ var UsageMessage = class {
|
|
|
2533
2806
|
try {
|
|
2534
2807
|
await this.sendQueue.enqueue(() => this.api.deleteMessage(this.chatId, id));
|
|
2535
2808
|
} catch (err) {
|
|
2536
|
-
|
|
2809
|
+
log10.warn({ err }, "UsageMessage.delete() failed");
|
|
2537
2810
|
}
|
|
2538
2811
|
}
|
|
2539
2812
|
};
|
|
@@ -2616,7 +2889,7 @@ var PlanCard = class {
|
|
|
2616
2889
|
if (result) this.msgId = result.message_id;
|
|
2617
2890
|
}
|
|
2618
2891
|
} catch (err) {
|
|
2619
|
-
|
|
2892
|
+
log10.warn({ err }, "PlanCard flush failed");
|
|
2620
2893
|
}
|
|
2621
2894
|
}
|
|
2622
2895
|
};
|
|
@@ -2679,7 +2952,7 @@ var ActivityTracker = class {
|
|
|
2679
2952
|
})
|
|
2680
2953
|
);
|
|
2681
2954
|
} catch (err) {
|
|
2682
|
-
|
|
2955
|
+
log10.warn({ err }, "ActivityTracker.onComplete() Done send failed");
|
|
2683
2956
|
}
|
|
2684
2957
|
}
|
|
2685
2958
|
}
|
|
@@ -2906,7 +3179,7 @@ function setupActionCallbacks(bot, core, chatId, getAssistantSessionId) {
|
|
|
2906
3179
|
}
|
|
2907
3180
|
|
|
2908
3181
|
// src/adapters/telegram/adapter.ts
|
|
2909
|
-
var
|
|
3182
|
+
var log11 = createChildLogger({ module: "telegram" });
|
|
2910
3183
|
function patchedFetch(input, init) {
|
|
2911
3184
|
if (init?.signal && !(init.signal instanceof AbortSignal)) {
|
|
2912
3185
|
const nativeController = new AbortController();
|
|
@@ -2957,7 +3230,7 @@ var TelegramAdapter = class extends ChannelAdapter {
|
|
|
2957
3230
|
this.bot = new Bot(this.telegramConfig.botToken, { client: { fetch: patchedFetch } });
|
|
2958
3231
|
this.bot.catch((err) => {
|
|
2959
3232
|
const rootCause = err.error instanceof Error ? err.error : err;
|
|
2960
|
-
|
|
3233
|
+
log11.error({ err: rootCause }, "Telegram bot error");
|
|
2961
3234
|
});
|
|
2962
3235
|
this.bot.api.config.use(async (prev, method, payload, signal) => {
|
|
2963
3236
|
const maxRetries = 3;
|
|
@@ -2971,7 +3244,7 @@ var TelegramAdapter = class extends ChannelAdapter {
|
|
|
2971
3244
|
if (rateLimitedMethods.includes(method)) {
|
|
2972
3245
|
this.sendQueue.onRateLimited();
|
|
2973
3246
|
}
|
|
2974
|
-
|
|
3247
|
+
log11.warn(
|
|
2975
3248
|
{ method, retryAfter, attempt: attempt + 1 },
|
|
2976
3249
|
"Rate limited by Telegram, retrying"
|
|
2977
3250
|
);
|
|
@@ -3041,7 +3314,7 @@ var TelegramAdapter = class extends ChannelAdapter {
|
|
|
3041
3314
|
this.setupRoutes();
|
|
3042
3315
|
this.bot.start({
|
|
3043
3316
|
allowed_updates: ["message", "callback_query"],
|
|
3044
|
-
onStart: () =>
|
|
3317
|
+
onStart: () => log11.info(
|
|
3045
3318
|
{ chatId: this.telegramConfig.chatId },
|
|
3046
3319
|
"Telegram bot started"
|
|
3047
3320
|
)
|
|
@@ -3063,10 +3336,10 @@ Workspace: <code>${workspace}</code>
|
|
|
3063
3336
|
reply_markup: buildMenuKeyboard()
|
|
3064
3337
|
});
|
|
3065
3338
|
} catch (err) {
|
|
3066
|
-
|
|
3339
|
+
log11.warn({ err }, "Failed to send welcome message");
|
|
3067
3340
|
}
|
|
3068
3341
|
try {
|
|
3069
|
-
|
|
3342
|
+
log11.info("Spawning assistant session...");
|
|
3070
3343
|
const { session, ready } = await spawnAssistant(
|
|
3071
3344
|
this.core,
|
|
3072
3345
|
this,
|
|
@@ -3074,13 +3347,13 @@ Workspace: <code>${workspace}</code>
|
|
|
3074
3347
|
);
|
|
3075
3348
|
this.assistantSession = session;
|
|
3076
3349
|
this.assistantInitializing = true;
|
|
3077
|
-
|
|
3350
|
+
log11.info({ sessionId: session.id }, "Assistant session ready, system prompt running in background");
|
|
3078
3351
|
ready.then(() => {
|
|
3079
3352
|
this.assistantInitializing = false;
|
|
3080
|
-
|
|
3353
|
+
log11.info({ sessionId: session.id }, "Assistant ready for user messages");
|
|
3081
3354
|
});
|
|
3082
3355
|
} catch (err) {
|
|
3083
|
-
|
|
3356
|
+
log11.error({ err }, "Failed to spawn assistant");
|
|
3084
3357
|
this.bot.api.sendMessage(
|
|
3085
3358
|
this.telegramConfig.chatId,
|
|
3086
3359
|
`\u26A0\uFE0F <b>Failed to start assistant session.</b>
|
|
@@ -3096,7 +3369,7 @@ Workspace: <code>${workspace}</code>
|
|
|
3096
3369
|
await this.assistantSession.destroy();
|
|
3097
3370
|
}
|
|
3098
3371
|
await this.bot.stop();
|
|
3099
|
-
|
|
3372
|
+
log11.info("Telegram bot stopped");
|
|
3100
3373
|
}
|
|
3101
3374
|
setupRoutes() {
|
|
3102
3375
|
this.bot.on("message:text", async (ctx) => {
|
|
@@ -3119,7 +3392,7 @@ Workspace: <code>${workspace}</code>
|
|
|
3119
3392
|
ctx.replyWithChatAction("typing").catch(() => {
|
|
3120
3393
|
});
|
|
3121
3394
|
handleAssistantMessage(this.assistantSession, ctx.message.text).catch(
|
|
3122
|
-
(err) =>
|
|
3395
|
+
(err) => log11.error({ err }, "Assistant error")
|
|
3123
3396
|
);
|
|
3124
3397
|
return;
|
|
3125
3398
|
}
|
|
@@ -3136,7 +3409,7 @@ Workspace: <code>${workspace}</code>
|
|
|
3136
3409
|
threadId: String(threadId),
|
|
3137
3410
|
userId: String(ctx.from.id),
|
|
3138
3411
|
text: ctx.message.text
|
|
3139
|
-
}).catch((err) =>
|
|
3412
|
+
}).catch((err) => log11.error({ err }, "handleMessage error"));
|
|
3140
3413
|
});
|
|
3141
3414
|
}
|
|
3142
3415
|
// --- ChannelAdapter implementations ---
|
|
@@ -3216,7 +3489,7 @@ Workspace: <code>${workspace}</code>
|
|
|
3216
3489
|
if (toolState) {
|
|
3217
3490
|
if (meta.viewerLinks) {
|
|
3218
3491
|
toolState.viewerLinks = meta.viewerLinks;
|
|
3219
|
-
|
|
3492
|
+
log11.debug({ toolId: meta.id, viewerLinks: meta.viewerLinks }, "Accumulated viewerLinks");
|
|
3220
3493
|
}
|
|
3221
3494
|
const viewerFilePath = content.metadata?.viewerFilePath;
|
|
3222
3495
|
if (viewerFilePath) toolState.viewerFilePath = viewerFilePath;
|
|
@@ -3225,7 +3498,7 @@ Workspace: <code>${workspace}</code>
|
|
|
3225
3498
|
const isTerminal = meta.status === "completed" || meta.status === "failed";
|
|
3226
3499
|
if (!isTerminal && !meta.viewerLinks) break;
|
|
3227
3500
|
await toolState.ready;
|
|
3228
|
-
|
|
3501
|
+
log11.debug(
|
|
3229
3502
|
{ toolId: meta.id, status: meta.status, hasViewerLinks: !!toolState.viewerLinks, viewerLinks: toolState.viewerLinks, name: toolState.name, msgId: toolState.msgId },
|
|
3230
3503
|
"Tool completed, preparing edit"
|
|
3231
3504
|
);
|
|
@@ -3247,7 +3520,7 @@ Workspace: <code>${workspace}</code>
|
|
|
3247
3520
|
)
|
|
3248
3521
|
);
|
|
3249
3522
|
} catch (err) {
|
|
3250
|
-
|
|
3523
|
+
log11.warn(
|
|
3251
3524
|
{ err, msgId: toolState.msgId, textLen: formattedText.length, hasViewerLinks: !!merged.viewerLinks },
|
|
3252
3525
|
"Tool update edit failed"
|
|
3253
3526
|
);
|
|
@@ -3342,17 +3615,16 @@ Task completed.
|
|
|
3342
3615
|
}
|
|
3343
3616
|
}
|
|
3344
3617
|
async sendPermissionRequest(sessionId, request) {
|
|
3345
|
-
|
|
3618
|
+
log11.info({ sessionId, requestId: request.id }, "Permission request sent");
|
|
3346
3619
|
const session = this.core.sessionManager.getSession(
|
|
3347
3620
|
sessionId
|
|
3348
3621
|
);
|
|
3349
3622
|
if (!session) return;
|
|
3350
3623
|
if (session.dangerousMode) {
|
|
3351
3624
|
const allowOption = request.options.find((o) => o.isAllow);
|
|
3352
|
-
if (allowOption && session.
|
|
3353
|
-
|
|
3354
|
-
session.
|
|
3355
|
-
session.pendingPermission = void 0;
|
|
3625
|
+
if (allowOption && session.permissionGate.requestId === request.id) {
|
|
3626
|
+
log11.info({ sessionId, requestId: request.id, optionId: allowOption.id }, "Dangerous mode: auto-approving permission");
|
|
3627
|
+
session.permissionGate.resolve(allowOption.id);
|
|
3356
3628
|
}
|
|
3357
3629
|
return;
|
|
3358
3630
|
}
|
|
@@ -3362,7 +3634,7 @@ Task completed.
|
|
|
3362
3634
|
}
|
|
3363
3635
|
async sendNotification(notification) {
|
|
3364
3636
|
if (notification.sessionId === this.assistantSession?.id) return;
|
|
3365
|
-
|
|
3637
|
+
log11.info(
|
|
3366
3638
|
{ sessionId: notification.sessionId, type: notification.type },
|
|
3367
3639
|
"Notification sent"
|
|
3368
3640
|
);
|
|
@@ -3398,7 +3670,7 @@ Task completed.
|
|
|
3398
3670
|
);
|
|
3399
3671
|
}
|
|
3400
3672
|
async createSessionThread(sessionId, name) {
|
|
3401
|
-
|
|
3673
|
+
log11.info({ sessionId, name }, "Session topic created");
|
|
3402
3674
|
return String(
|
|
3403
3675
|
await createSessionTopic(this.bot, this.telegramConfig.chatId, name)
|
|
3404
3676
|
);
|
|
@@ -3483,7 +3755,7 @@ Task completed.
|
|
|
3483
3755
|
}
|
|
3484
3756
|
);
|
|
3485
3757
|
} catch (err) {
|
|
3486
|
-
|
|
3758
|
+
log11.error({ err, sessionId }, "Failed to send skill commands");
|
|
3487
3759
|
}
|
|
3488
3760
|
await this.updateCommandAutocomplete(session.agentName, commands);
|
|
3489
3761
|
}
|
|
@@ -3519,12 +3791,12 @@ Task completed.
|
|
|
3519
3791
|
await this.bot.api.setMyCommands(all, {
|
|
3520
3792
|
scope: { type: "chat", chat_id: this.telegramConfig.chatId }
|
|
3521
3793
|
});
|
|
3522
|
-
|
|
3794
|
+
log11.info(
|
|
3523
3795
|
{ count: all.length, skills: validSkills.length },
|
|
3524
3796
|
"Updated command autocomplete"
|
|
3525
3797
|
);
|
|
3526
3798
|
} catch (err) {
|
|
3527
|
-
|
|
3799
|
+
log11.error(
|
|
3528
3800
|
{ err, commands: all },
|
|
3529
3801
|
"Failed to update command autocomplete"
|
|
3530
3802
|
);
|
|
@@ -3565,12 +3837,16 @@ export {
|
|
|
3565
3837
|
StderrCapture,
|
|
3566
3838
|
AgentInstance,
|
|
3567
3839
|
AgentManager,
|
|
3840
|
+
TypedEmitter,
|
|
3841
|
+
PromptQueue,
|
|
3842
|
+
PermissionGate,
|
|
3568
3843
|
Session,
|
|
3569
3844
|
SessionManager,
|
|
3570
3845
|
NotificationManager,
|
|
3846
|
+
MessageTransformer,
|
|
3571
3847
|
OpenACPCore,
|
|
3572
3848
|
ChannelAdapter,
|
|
3573
3849
|
ApiServer,
|
|
3574
3850
|
TelegramAdapter
|
|
3575
3851
|
};
|
|
3576
|
-
//# sourceMappingURL=chunk-
|
|
3852
|
+
//# sourceMappingURL=chunk-WXPN5UOT.js.map
|