Implements Phases 1-8 of the TFTSR implementation plan. Rust backend (Tauri 2.x, src-tauri/): - Multi-provider AI: OpenAI-compatible, Anthropic, Gemini, Mistral, Ollama - PII detection engine: 11 regex patterns with overlap resolution - SQLCipher AES-256 encrypted database with 10 versioned migrations - 28 Tauri IPC commands for triage, analysis, document, and system ops - Ollama: hardware probe, model recommendations, pull/delete with events - RCA and blameless post-mortem Markdown document generators - PDF export via printpdf - Audit log: SHA-256 hash of every external data send - Integration stubs for Confluence, ServiceNow, Azure DevOps (v0.2) Frontend (React 18 + TypeScript + Vite, src/): - 9 pages: full triage workflow NewIssue→LogUpload→Triage→Resolution→RCA→Postmortem→History+Settings - 7 components: ChatWindow, TriageProgress, PiiDiffViewer, DocEditor, HardwareReport, ModelSelector, UI primitives - 3 Zustand stores: session, settings (persisted), history - Type-safe tauriCommands.ts matching Rust backend types exactly - 8 IT domain system prompts (Linux, Windows, Network, K8s, DB, Virt, HW, Obs) DevOps: - .woodpecker/test.yml: rustfmt, clippy, cargo test, tsc, vitest on every push - .woodpecker/release.yml: linux/amd64 + linux/arm64 builds, Gogs release upload Verified: - cargo check: zero errors - tsc --noEmit: zero errors - vitest run: 13/13 unit tests passing Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
89 lines
3.1 KiB
JavaScript
89 lines
3.1 KiB
JavaScript
import { argsert } from './argsert.js';
|
|
import { isPromise } from './utils/is-promise.js';
|
|
export class GlobalMiddleware {
|
|
constructor(yargs) {
|
|
this.globalMiddleware = [];
|
|
this.frozens = [];
|
|
this.yargs = yargs;
|
|
}
|
|
addMiddleware(callback, applyBeforeValidation, global = true, mutates = false) {
|
|
argsert('<array|function> [boolean] [boolean] [boolean]', [callback, applyBeforeValidation, global], arguments.length);
|
|
if (Array.isArray(callback)) {
|
|
for (let i = 0; i < callback.length; i++) {
|
|
if (typeof callback[i] !== 'function') {
|
|
throw Error('middleware must be a function');
|
|
}
|
|
const m = callback[i];
|
|
m.applyBeforeValidation = applyBeforeValidation;
|
|
m.global = global;
|
|
}
|
|
Array.prototype.push.apply(this.globalMiddleware, callback);
|
|
}
|
|
else if (typeof callback === 'function') {
|
|
const m = callback;
|
|
m.applyBeforeValidation = applyBeforeValidation;
|
|
m.global = global;
|
|
m.mutates = mutates;
|
|
this.globalMiddleware.push(callback);
|
|
}
|
|
return this.yargs;
|
|
}
|
|
addCoerceMiddleware(callback, option) {
|
|
const aliases = this.yargs.getAliases();
|
|
this.globalMiddleware = this.globalMiddleware.filter(m => {
|
|
const toCheck = [...(aliases[option] || []), option];
|
|
if (!m.option)
|
|
return true;
|
|
else
|
|
return !toCheck.includes(m.option);
|
|
});
|
|
callback.option = option;
|
|
return this.addMiddleware(callback, true, true, true);
|
|
}
|
|
getMiddleware() {
|
|
return this.globalMiddleware;
|
|
}
|
|
freeze() {
|
|
this.frozens.push([...this.globalMiddleware]);
|
|
}
|
|
unfreeze() {
|
|
const frozen = this.frozens.pop();
|
|
if (frozen !== undefined)
|
|
this.globalMiddleware = frozen;
|
|
}
|
|
reset() {
|
|
this.globalMiddleware = this.globalMiddleware.filter(m => m.global);
|
|
}
|
|
}
|
|
export function commandMiddlewareFactory(commandMiddleware) {
|
|
if (!commandMiddleware)
|
|
return [];
|
|
return commandMiddleware.map(middleware => {
|
|
middleware.applyBeforeValidation = false;
|
|
return middleware;
|
|
});
|
|
}
|
|
export function applyMiddleware(argv, yargs, middlewares, beforeValidation) {
|
|
return middlewares.reduce((acc, middleware) => {
|
|
if (middleware.applyBeforeValidation !== beforeValidation) {
|
|
return acc;
|
|
}
|
|
if (middleware.mutates) {
|
|
if (middleware.applied)
|
|
return acc;
|
|
middleware.applied = true;
|
|
}
|
|
if (isPromise(acc)) {
|
|
return acc
|
|
.then(initialObj => Promise.all([initialObj, middleware(initialObj, yargs)]))
|
|
.then(([initialObj, middlewareObj]) => Object.assign(initialObj, middlewareObj));
|
|
}
|
|
else {
|
|
const result = middleware(acc, yargs);
|
|
return isPromise(result)
|
|
? result.then(middlewareObj => Object.assign(acc, middlewareObj))
|
|
: Object.assign(acc, result);
|
|
}
|
|
}, argv);
|
|
}
|