@sma1lboy/kobe 0.8.166 → 0.8.168
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/index.js +342 -342
- package/dist/cli/kobe-run.js +359 -359
- package/dist/cli/pty-host-node.mjs +135 -106
- package/dist/cli/rove-run.js +359 -359
- package/package.json +1 -1
|
@@ -683,6 +683,85 @@ async function terminatePtyChild(proc, onSettled) {
|
|
|
683
683
|
onSettled();
|
|
684
684
|
}
|
|
685
685
|
|
|
686
|
+
// ../kobe-daemon/src/daemon/pty-child-controller.ts
|
|
687
|
+
class PtyChildController {
|
|
688
|
+
deps;
|
|
689
|
+
constructor(deps) {
|
|
690
|
+
this.deps = deps;
|
|
691
|
+
}
|
|
692
|
+
spawn(key, spec, spare = false) {
|
|
693
|
+
const argv = spec.command && spec.command.length > 0 ? [...spec.command] : [spec.shell ?? resolveLoginShell()];
|
|
694
|
+
const session = freshSessionState(key, spec, argv);
|
|
695
|
+
this.startChild(session);
|
|
696
|
+
if (session.alive) {
|
|
697
|
+
this.deps.log?.("pty", `spawned ${argv[0]} for ${key} (pid ${session.proc?.pid})`);
|
|
698
|
+
this.deps.onSessionStart?.(spare);
|
|
699
|
+
}
|
|
700
|
+
return session;
|
|
701
|
+
}
|
|
702
|
+
startChild(session) {
|
|
703
|
+
try {
|
|
704
|
+
session.proc = (this.deps.driver ?? bunTerminalDriver())({
|
|
705
|
+
argv: [...session.command],
|
|
706
|
+
cwd: session.cwd,
|
|
707
|
+
env: embeddedTerminalEnv(process.env, {
|
|
708
|
+
TERM: "xterm-256color",
|
|
709
|
+
COLUMNS: String(session.cols),
|
|
710
|
+
LINES: String(session.rows),
|
|
711
|
+
BASH_SILENCE_DEPRECATION_WARNING: "1",
|
|
712
|
+
KOBE_TERMINAL_PTY: "1"
|
|
713
|
+
}),
|
|
714
|
+
cols: session.cols,
|
|
715
|
+
rows: session.rows,
|
|
716
|
+
onData: (data) => this.onData(session, data)
|
|
717
|
+
});
|
|
718
|
+
session.alive = true;
|
|
719
|
+
session.proc.exited.then((exit) => this.markExited(session, exit), () => this.markExited(session));
|
|
720
|
+
} catch (err) {
|
|
721
|
+
session.alive = false;
|
|
722
|
+
this.deps.log?.("pty", `spawn failed for ${session.key}: ${err instanceof Error ? err.message : String(err)}`);
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
async endChild(session) {
|
|
726
|
+
if (!session.alive)
|
|
727
|
+
return;
|
|
728
|
+
const proc = session.proc;
|
|
729
|
+
if (!proc) {
|
|
730
|
+
this.markExited(session);
|
|
731
|
+
return;
|
|
732
|
+
}
|
|
733
|
+
await terminatePtyChild(proc, () => this.markExited(session));
|
|
734
|
+
}
|
|
735
|
+
markExited(session, exit) {
|
|
736
|
+
if (!session.alive)
|
|
737
|
+
return;
|
|
738
|
+
session.alive = false;
|
|
739
|
+
const sessionExit = {
|
|
740
|
+
code: exit?.code ?? null,
|
|
741
|
+
signal: exit?.signal ?? null,
|
|
742
|
+
at: new Date().toISOString()
|
|
743
|
+
};
|
|
744
|
+
session.exit = sessionExit;
|
|
745
|
+
try {
|
|
746
|
+
session.proc?.close();
|
|
747
|
+
} catch {}
|
|
748
|
+
this.deps.onExit?.(session, sessionExit);
|
|
749
|
+
}
|
|
750
|
+
onData(session, data) {
|
|
751
|
+
const buf = typeof data === "string" ? Buffer.from(data, "utf8") : Buffer.from(data);
|
|
752
|
+
scanOscTitle(session, buf);
|
|
753
|
+
session.chunks.push(buf);
|
|
754
|
+
session.bytes += buf.byteLength;
|
|
755
|
+
session.totalBytes += buf.byteLength;
|
|
756
|
+
while (session.bytes > this.deps.scrollbackCap && session.chunks.length > 1) {
|
|
757
|
+
const dropped = session.chunks.shift();
|
|
758
|
+
if (dropped)
|
|
759
|
+
session.bytes -= dropped.byteLength;
|
|
760
|
+
}
|
|
761
|
+
this.deps.onOutput?.(session, buf);
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
|
|
686
765
|
// ../kobe-daemon/src/daemon/pty-warm.ts
|
|
687
766
|
class WarmSpare {
|
|
688
767
|
deps;
|
|
@@ -746,16 +825,61 @@ class PtyHost {
|
|
|
746
825
|
scrollbackCap;
|
|
747
826
|
parkRestoreDeltas = 0;
|
|
748
827
|
parkRestoreFallbacks = 0;
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
endChild: (session) => this.endChild(session),
|
|
752
|
-
markExited: (session) => this.markExited(session),
|
|
753
|
-
log: (event, message) => this.opts.log?.(event, message),
|
|
754
|
-
onSessionStart: () => this.opts.onSessionStart?.()
|
|
755
|
-
});
|
|
828
|
+
childController;
|
|
829
|
+
warmSpare;
|
|
756
830
|
constructor(opts = {}) {
|
|
757
831
|
this.opts = opts;
|
|
758
832
|
this.scrollbackCap = opts.scrollbackCap ?? DEFAULT_SCROLLBACK_CAP;
|
|
833
|
+
this.childController = new PtyChildController({
|
|
834
|
+
driver: opts.driver,
|
|
835
|
+
scrollbackCap: this.scrollbackCap,
|
|
836
|
+
onSessionStart: (spare) => {
|
|
837
|
+
if (!spare)
|
|
838
|
+
this.opts.onSessionStart?.();
|
|
839
|
+
},
|
|
840
|
+
onOutput: (session, data) => {
|
|
841
|
+
if (session.sinks.size === 0) {
|
|
842
|
+
this.maybeFreeze(session);
|
|
843
|
+
return;
|
|
844
|
+
}
|
|
845
|
+
const frame = {
|
|
846
|
+
type: "event",
|
|
847
|
+
name: "pty.data",
|
|
848
|
+
payload: { key: session.key, data: data.toString("base64") }
|
|
849
|
+
};
|
|
850
|
+
for (const sink of session.sinks.values())
|
|
851
|
+
sink(frame);
|
|
852
|
+
this.maybeFreeze(session);
|
|
853
|
+
},
|
|
854
|
+
onExit: (session, exit) => {
|
|
855
|
+
const frame = {
|
|
856
|
+
type: "event",
|
|
857
|
+
name: "pty.exit",
|
|
858
|
+
payload: { key: session.key, pid: session.proc?.pid ?? null, ...exit }
|
|
859
|
+
};
|
|
860
|
+
for (const sink of session.sinks.values())
|
|
861
|
+
sink(frame);
|
|
862
|
+
this.opts.log?.("pty", `session ${session.key} exited${describeExit(exit)}`);
|
|
863
|
+
this.maybeFreeze(session, true);
|
|
864
|
+
try {
|
|
865
|
+
this.opts.onSessionExit?.({
|
|
866
|
+
key: session.key,
|
|
867
|
+
pid: session.proc?.pid ?? null,
|
|
868
|
+
exit,
|
|
869
|
+
tail: ringTail(session.chunks, session.bytes, EXIT_TAIL_BYTES)
|
|
870
|
+
});
|
|
871
|
+
} catch {}
|
|
872
|
+
this.opts.onSessionEnd?.();
|
|
873
|
+
},
|
|
874
|
+
log: (event, message) => this.opts.log?.(event, message)
|
|
875
|
+
});
|
|
876
|
+
this.warmSpare = new WarmSpare({
|
|
877
|
+
spawn: (key, spec, spare) => this.childController.spawn(key, spec, spare),
|
|
878
|
+
endChild: (session) => this.childController.endChild(session),
|
|
879
|
+
markExited: (session) => this.childController.markExited(session),
|
|
880
|
+
log: (event, message) => this.opts.log?.(event, message),
|
|
881
|
+
onSessionStart: () => this.opts.onSessionStart?.()
|
|
882
|
+
});
|
|
759
883
|
}
|
|
760
884
|
open(key, spec, token, sink, sinceOffset, sincePid) {
|
|
761
885
|
let session = this.sessions.get(key);
|
|
@@ -763,7 +887,7 @@ class PtyHost {
|
|
|
763
887
|
let respawned = false;
|
|
764
888
|
if (!session) {
|
|
765
889
|
created = true;
|
|
766
|
-
session = this.warmSpare.adopt(key, spec) ?? this.spawn(key, spec);
|
|
890
|
+
session = this.warmSpare.adopt(key, spec) ?? this.childController.spawn(key, spec);
|
|
767
891
|
this.sessions.set(key, session);
|
|
768
892
|
} else if (!session.alive && session.restored) {
|
|
769
893
|
this.respawn(session, spec);
|
|
@@ -824,7 +948,7 @@ class PtyHost {
|
|
|
824
948
|
return Promise.resolve();
|
|
825
949
|
this.sessions.delete(key);
|
|
826
950
|
this.opts.freeze?.drop(key);
|
|
827
|
-
return this.endChild(session);
|
|
951
|
+
return this.childController.endChild(session);
|
|
828
952
|
}
|
|
829
953
|
rename(from, to) {
|
|
830
954
|
const session = this.sessions.get(from);
|
|
@@ -880,7 +1004,7 @@ class PtyHost {
|
|
|
880
1004
|
}
|
|
881
1005
|
async shutdown() {
|
|
882
1006
|
this.flushFrozen();
|
|
883
|
-
const endings = Array.from(this.sessions.values(), (session) => this.endChild(session));
|
|
1007
|
+
const endings = Array.from(this.sessions.values(), (session) => this.childController.endChild(session));
|
|
884
1008
|
endings.push(this.warmSpare.end());
|
|
885
1009
|
await Promise.all(endings);
|
|
886
1010
|
}
|
|
@@ -910,7 +1034,7 @@ class PtyHost {
|
|
|
910
1034
|
session.command = [...spec.command];
|
|
911
1035
|
session.cols = spec.cols ?? session.cols;
|
|
912
1036
|
session.rows = spec.rows ?? session.rows;
|
|
913
|
-
this.startChild(session);
|
|
1037
|
+
this.childController.startChild(session);
|
|
914
1038
|
if (!session.alive)
|
|
915
1039
|
return;
|
|
916
1040
|
this.opts.log?.("pty", `respawned restored session ${session.key} (pid ${session.proc?.pid})`);
|
|
@@ -933,101 +1057,6 @@ class PtyHost {
|
|
|
933
1057
|
n++;
|
|
934
1058
|
return n;
|
|
935
1059
|
}
|
|
936
|
-
spawn(key, spec, spare = false) {
|
|
937
|
-
const argv = spec.command && spec.command.length > 0 ? [...spec.command] : [spec.shell ?? resolveLoginShell()];
|
|
938
|
-
const session = freshSessionState(key, spec, argv);
|
|
939
|
-
this.startChild(session);
|
|
940
|
-
if (session.alive) {
|
|
941
|
-
this.opts.log?.("pty", `spawned ${argv[0]} for ${key} (pid ${session.proc?.pid})`);
|
|
942
|
-
if (!spare)
|
|
943
|
-
this.opts.onSessionStart?.();
|
|
944
|
-
}
|
|
945
|
-
return session;
|
|
946
|
-
}
|
|
947
|
-
startChild(session) {
|
|
948
|
-
try {
|
|
949
|
-
session.proc = (this.opts.driver ?? bunTerminalDriver())({
|
|
950
|
-
argv: [...session.command],
|
|
951
|
-
cwd: session.cwd,
|
|
952
|
-
env: embeddedTerminalEnv(process.env, {
|
|
953
|
-
TERM: "xterm-256color",
|
|
954
|
-
COLUMNS: String(session.cols),
|
|
955
|
-
LINES: String(session.rows),
|
|
956
|
-
BASH_SILENCE_DEPRECATION_WARNING: "1",
|
|
957
|
-
KOBE_TERMINAL_PTY: "1"
|
|
958
|
-
}),
|
|
959
|
-
cols: session.cols,
|
|
960
|
-
rows: session.rows,
|
|
961
|
-
onData: (data) => this.onData(session, data)
|
|
962
|
-
});
|
|
963
|
-
session.alive = true;
|
|
964
|
-
session.proc.exited.then((exit) => this.markExited(session, exit), () => this.markExited(session));
|
|
965
|
-
} catch (err) {
|
|
966
|
-
session.alive = false;
|
|
967
|
-
this.opts.log?.("pty", `spawn failed for ${session.key}: ${err instanceof Error ? err.message : String(err)}`);
|
|
968
|
-
}
|
|
969
|
-
}
|
|
970
|
-
onData(session, data) {
|
|
971
|
-
const buf = typeof data === "string" ? Buffer.from(data, "utf8") : Buffer.from(data);
|
|
972
|
-
scanOscTitle(session, buf);
|
|
973
|
-
session.chunks.push(buf);
|
|
974
|
-
session.bytes += buf.byteLength;
|
|
975
|
-
session.totalBytes += buf.byteLength;
|
|
976
|
-
while (session.bytes > this.scrollbackCap && session.chunks.length > 1) {
|
|
977
|
-
const dropped = session.chunks.shift();
|
|
978
|
-
if (dropped)
|
|
979
|
-
session.bytes -= dropped.byteLength;
|
|
980
|
-
}
|
|
981
|
-
if (session.sinks.size === 0) {
|
|
982
|
-
this.maybeFreeze(session);
|
|
983
|
-
return;
|
|
984
|
-
}
|
|
985
|
-
const frame = {
|
|
986
|
-
type: "event",
|
|
987
|
-
name: "pty.data",
|
|
988
|
-
payload: { key: session.key, data: buf.toString("base64") }
|
|
989
|
-
};
|
|
990
|
-
for (const sink of session.sinks.values())
|
|
991
|
-
sink(frame);
|
|
992
|
-
this.maybeFreeze(session);
|
|
993
|
-
}
|
|
994
|
-
markExited(session, exit) {
|
|
995
|
-
if (!session.alive)
|
|
996
|
-
return;
|
|
997
|
-
session.alive = false;
|
|
998
|
-
session.exit = { code: exit?.code ?? null, signal: exit?.signal ?? null, at: new Date().toISOString() };
|
|
999
|
-
try {
|
|
1000
|
-
session.proc?.close();
|
|
1001
|
-
} catch {}
|
|
1002
|
-
const frame = {
|
|
1003
|
-
type: "event",
|
|
1004
|
-
name: "pty.exit",
|
|
1005
|
-
payload: { key: session.key, pid: session.proc?.pid ?? null, ...session.exit }
|
|
1006
|
-
};
|
|
1007
|
-
for (const sink of session.sinks.values())
|
|
1008
|
-
sink(frame);
|
|
1009
|
-
this.opts.log?.("pty", `session ${session.key} exited${describeExit(session.exit)}`);
|
|
1010
|
-
this.maybeFreeze(session, true);
|
|
1011
|
-
try {
|
|
1012
|
-
this.opts.onSessionExit?.({
|
|
1013
|
-
key: session.key,
|
|
1014
|
-
pid: session.proc?.pid ?? null,
|
|
1015
|
-
exit: session.exit,
|
|
1016
|
-
tail: ringTail(session.chunks, session.bytes, EXIT_TAIL_BYTES)
|
|
1017
|
-
});
|
|
1018
|
-
} catch {}
|
|
1019
|
-
this.opts.onSessionEnd?.();
|
|
1020
|
-
}
|
|
1021
|
-
async endChild(session) {
|
|
1022
|
-
if (!session.alive)
|
|
1023
|
-
return;
|
|
1024
|
-
const proc = session.proc;
|
|
1025
|
-
if (!proc) {
|
|
1026
|
-
this.markExited(session);
|
|
1027
|
-
return;
|
|
1028
|
-
}
|
|
1029
|
-
await terminatePtyChild(proc, () => this.markExited(session));
|
|
1030
|
-
}
|
|
1031
1060
|
}
|
|
1032
1061
|
|
|
1033
1062
|
// ../kobe-daemon/src/daemon/pty-server.ts
|