mirror of
https://github.com/SHOGGOTH-SECTOR/sica-fondt.git
synced 2026-08-01 08:30:20 +00:00
Place useful parts of the surrounding repos into sica-fondt by layer, per the
body model (Ada = membrane; brain/endocrine/capabilities/knowledge non-Ada):
- brain/ LLM reasoning + providers (dapr, hermes, MoMoA)
- capabilities/ REPRAG sidecars: hermes tools/skills, dapr tools, parallel
dispatch, A51 channels, and the OSINT cluster
- knowledge/ LORAG corpus: 754 cyber-skills, agency personas, secure-coding,
MITRE ATT&CK data
- reference/ defensive threat-reference (C3, shhbruh doc) + AdaYaml parser
License handling: AGPL sources (worldosint, advanced_evolution, mercury,
Reticulum) and GPL DeTTECT are SPEC-only clean-room/port descriptions — no
copyleft code copied. MIT/Apache/data parts copied as working trees.
Safety: shhbruh escape/persistence material and C3 covert-C2 kept as reference
only, not wired into the running organism. See CONSOLIDATION.md.
https://claude.ai/code/session_01UehUqEXXJJCsHoA4voCU5c
135 lines
3.8 KiB
TypeScript
135 lines
3.8 KiB
TypeScript
/**
|
|
* Copyright 2026 Reto Meier
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
import WebSocket from 'ws';
|
|
|
|
interface ProgressQueueItem {
|
|
id: number;
|
|
resolved: boolean;
|
|
value?: string;
|
|
error?: boolean;
|
|
addedAt: number;
|
|
}
|
|
|
|
export class ProgressQueue {
|
|
private queue: ProgressQueueItem[] = [];
|
|
private idCounter = 0;
|
|
|
|
constructor(
|
|
private ws: WebSocket,
|
|
private clientUUID: string
|
|
) {}
|
|
|
|
add(message: string | Promise<string>) {
|
|
const item: ProgressQueueItem = {
|
|
id: this.idCounter++,
|
|
resolved: false,
|
|
addedAt: Date.now(),
|
|
};
|
|
|
|
this.queue.push(item);
|
|
|
|
if (typeof message === 'string') {
|
|
item.resolved = true;
|
|
item.value = message;
|
|
this.process();
|
|
} else {
|
|
// It's a Promise
|
|
message
|
|
.then(val => {
|
|
item.resolved = true;
|
|
item.value = val;
|
|
queueMicrotask(() => this.process());
|
|
})
|
|
.catch(err => {
|
|
console.error(`Progress update promise failed:`, err);
|
|
item.error = true;
|
|
// Capture the error message to send to the client
|
|
item.value = err instanceof Error ? err.message : String(err);
|
|
queueMicrotask(() => this.process());
|
|
});
|
|
|
|
// Add a 50ms buffer to ensure Date.now() - addedAt is strictly >= 30000
|
|
setTimeout(() => this.process(), 30050);
|
|
}
|
|
}
|
|
|
|
process() {
|
|
if (!this.ws || this.ws.readyState !== WebSocket.OPEN) return;
|
|
|
|
while (this.queue.length > 0) {
|
|
const head = this.queue[0];
|
|
|
|
// 1. Handle Rejected Promises
|
|
if (head.error) {
|
|
try {
|
|
this.ws.send(JSON.stringify({
|
|
status: 'PROGRESS_UPDATES',
|
|
completed_status_message: `Update failed: ${head.value}`,
|
|
}));
|
|
} catch (e) {
|
|
console.error('Failed to send error update, will retry:', e);
|
|
break; // Pause queue if socket throws an error
|
|
}
|
|
|
|
this.queue.shift();
|
|
continue;
|
|
}
|
|
|
|
// 2. Handle Successfully Resolved Promises / Strings
|
|
if (head.resolved) {
|
|
try {
|
|
this.ws.send(JSON.stringify({
|
|
status: 'PROGRESS_UPDATES',
|
|
completed_status_message: head.value,
|
|
isError: false
|
|
}));
|
|
} catch (e) {
|
|
console.error('Failed to send progress update, will retry:', e);
|
|
break;
|
|
}
|
|
|
|
this.queue.shift();
|
|
continue;
|
|
}
|
|
|
|
// 3. Handle Timeouts
|
|
const timeInQueue = Date.now() - head.addedAt;
|
|
// Allow timeout if a subsequent item is resolved OR errored (both mean the future moved on)
|
|
const hasFinishedSubsequent = this.queue.slice(1).some(q => q.resolved || q.error);
|
|
|
|
if (timeInQueue >= 29900 && hasFinishedSubsequent) {
|
|
console.log(`Sending timeout payload for unresolved progress update (client ${this.clientUUID}).`);
|
|
|
|
try {
|
|
this.ws.send(JSON.stringify({
|
|
status: 'PROGRESS_UPDATES',
|
|
completed_status_message: `Update failed: Operation timed out after 30 seconds`,
|
|
}));
|
|
} catch (e) {
|
|
console.error('Failed to send timeout update, will retry:', e);
|
|
break;
|
|
}
|
|
|
|
this.queue.shift();
|
|
continue;
|
|
}
|
|
|
|
// The head is unresolved and doesn't meet the skip criteria yet. Block the queue.
|
|
break;
|
|
}
|
|
}
|
|
} |