nexus-windows-codex 0.0.0-stage → 3.0.1
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/CHANGELOG.md +311 -0
- package/LICENSE +21 -0
- package/README.md +438 -3
- package/SECURITY.md +13 -0
- package/bin/nexus-windows-codex.mjs +45 -0
- package/garde-fous.json +176 -0
- package/lib/garde-fous.mjs +340 -0
- package/lib/journal.mjs +56 -0
- package/lib/mcp.mjs +281 -0
- package/lib/memory.mjs +109 -0
- package/lib/native-provider.mjs +37 -0
- package/lib/native.mjs +215 -0
- package/lib/presence.mjs +77 -0
- package/lib/session.mjs +1490 -0
- package/lib/stop.mjs +184 -0
- package/lib/tree.mjs +152 -0
- package/native/bin/NexusCodex.UIA.exe +4 -0
- package/native/bin/logo.png +0 -0
- package/package.json +44 -6
package/lib/presence.mjs
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
// Présence de Julien au clavier et à la souris, alimentée par le garde .NET (`--stop-guard`).
|
|
2
|
+
// Source « raw-input » : seules les entrées physiques arrivent (les injections, dont celles de Sky, n'ont pas de
|
|
3
|
+
// périphérique d'origine). Source « last-input-info » (repli) : toute entrée arrive, et les événements reçus pendant
|
|
4
|
+
// une injection de cette session (plus une marge) sont écartés. Aucune touche ni position n'est lue ni gardée :
|
|
5
|
+
// seulement l'instant de la dernière entrée.
|
|
6
|
+
export const QUIET_MS = 1618; // pause demandée avant une entrée physique (nombre d'or, en secondes)
|
|
7
|
+
export const MAX_WAIT_MS = 8000; // au-delà, l'entrée physique est différée (rien n'est envoyé)
|
|
8
|
+
const INJECTION_TAIL_MS = 300;
|
|
9
|
+
|
|
10
|
+
export class JulienActiveError extends Error {
|
|
11
|
+
constructor(idleMs) {
|
|
12
|
+
super(`Julien utilise le clavier ou la souris (dernière entrée il y a ${Math.round(idleMs)} ms) : entrée physique différée, rien n'a été envoyé. Réobserver plus tard ; ne jamais rejouer automatiquement.`);
|
|
13
|
+
this.name = 'JulienActiveError';
|
|
14
|
+
this.deferred = true;
|
|
15
|
+
this.julienActive = true;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Garde prévu mais présence inconnue (garde arrêté ou en cours de relance) : une inactivité supposée serait fausse.
|
|
20
|
+
export class PresenceUnknownError extends Error {
|
|
21
|
+
constructor(guard) {
|
|
22
|
+
super(`Présence de Julien inconnue (garde de l'arrêt d'urgence : ${guard}, relance en cours) : entrée physique différée, rien n'a été envoyé. Réobserver dans quelques secondes ; ne jamais rejouer automatiquement.`);
|
|
23
|
+
this.name = 'PresenceUnknownError';
|
|
24
|
+
this.deferred = true;
|
|
25
|
+
this.presenceUnknown = true;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export class Presence {
|
|
30
|
+
#monotonic; #source = 'none'; #since = null; #last = -Infinity; #injections = [];
|
|
31
|
+
constructor({ monotonic = () => performance.now() } = {}) { this.#monotonic = monotonic; }
|
|
32
|
+
get source() { return this.#source; }
|
|
33
|
+
get available() { return this.#source === 'raw-input' || this.#source === 'last-input-info'; }
|
|
34
|
+
setSource(source) {
|
|
35
|
+
if (!['raw-input', 'last-input-info', 'none'].includes(source)) return;
|
|
36
|
+
this.#source = source;
|
|
37
|
+
this.#since ??= this.#monotonic();
|
|
38
|
+
}
|
|
39
|
+
// Entrée signalée par le garde. Avec GetLastInputInfo, une entrée pendant nos propres injections est la nôtre.
|
|
40
|
+
input({ injectedPossible = false, at = this.#monotonic() } = {}) {
|
|
41
|
+
if ((injectedPossible || this.#source === 'last-input-info') &&
|
|
42
|
+
this.#injections.some(([start, end]) => at >= start && at <= end + INJECTION_TAIL_MS)) return false;
|
|
43
|
+
this.#last = Math.max(this.#last, at);
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
// Fenêtre d'injection de cette session (entrée physique Sky en cours) : ouverte avant l'entrée, fermée après.
|
|
47
|
+
beginInjection() {
|
|
48
|
+
const horizon = this.#monotonic() - 60000;
|
|
49
|
+
this.#injections = this.#injections.filter(([, e]) => e >= horizon);
|
|
50
|
+
const entry = [this.#monotonic(), Infinity];
|
|
51
|
+
this.#injections.push(entry);
|
|
52
|
+
return entry;
|
|
53
|
+
}
|
|
54
|
+
endInjection(entry) { if (entry) entry[1] = this.#monotonic(); }
|
|
55
|
+
now() { return this.#monotonic(); }
|
|
56
|
+
// Inactivité connue : depuis la dernière entrée, sinon depuis le début de l'écoute (rien n'est supposé avant).
|
|
57
|
+
idleMs() {
|
|
58
|
+
if (!this.available) return null;
|
|
59
|
+
const reference = Number.isFinite(this.#last) ? this.#last : this.#since;
|
|
60
|
+
return Math.max(0, this.#monotonic() - reference);
|
|
61
|
+
}
|
|
62
|
+
since(moment) { return this.#last > moment; }
|
|
63
|
+
status() {
|
|
64
|
+
return { source: this.#source, available: this.available, idleMs: this.idleMs() };
|
|
65
|
+
}
|
|
66
|
+
// Attend une pause de quietMs avant une entrée physique ; Julien toujours actif après maxWaitMs : différé.
|
|
67
|
+
async waitForPause({ quietMs = QUIET_MS, maxWaitMs = MAX_WAIT_MS, sleep = ms => new Promise(r => setTimeout(r, ms)) } = {}) {
|
|
68
|
+
if (!this.available) return { waitedMs: 0, source: this.#source, idleMs: null };
|
|
69
|
+
const start = this.#monotonic();
|
|
70
|
+
for (;;) {
|
|
71
|
+
const idle = this.idleMs();
|
|
72
|
+
if (idle >= quietMs) return { waitedMs: this.#monotonic() - start, source: this.#source, idleMs: idle };
|
|
73
|
+
if (this.#monotonic() - start >= maxWaitMs) throw new JulienActiveError(idle);
|
|
74
|
+
await sleep(Math.min(Math.max(quietMs - idle, 20), 200));
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|