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>
151 lines
3.1 KiB
JavaScript
151 lines
3.1 KiB
JavaScript
const { InvalidArgumentError } = require('./error.js');
|
|
|
|
class Argument {
|
|
/**
|
|
* Initialize a new command argument with the given name and description.
|
|
* The default is that the argument is required, and you can explicitly
|
|
* indicate this with <> around the name. Put [] around the name for an optional argument.
|
|
*
|
|
* @param {string} name
|
|
* @param {string} [description]
|
|
*/
|
|
|
|
constructor(name, description) {
|
|
this.description = description || '';
|
|
this.variadic = false;
|
|
this.parseArg = undefined;
|
|
this.defaultValue = undefined;
|
|
this.defaultValueDescription = undefined;
|
|
this.argChoices = undefined;
|
|
|
|
switch (name[0]) {
|
|
case '<': // e.g. <required>
|
|
this.required = true;
|
|
this._name = name.slice(1, -1);
|
|
break;
|
|
case '[': // e.g. [optional]
|
|
this.required = false;
|
|
this._name = name.slice(1, -1);
|
|
break;
|
|
default:
|
|
this.required = true;
|
|
this._name = name;
|
|
break;
|
|
}
|
|
|
|
if (this._name.endsWith('...')) {
|
|
this.variadic = true;
|
|
this._name = this._name.slice(0, -3);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Return argument name.
|
|
*
|
|
* @return {string}
|
|
*/
|
|
|
|
name() {
|
|
return this._name;
|
|
}
|
|
|
|
/**
|
|
* @package
|
|
*/
|
|
|
|
_collectValue(value, previous) {
|
|
if (previous === this.defaultValue || !Array.isArray(previous)) {
|
|
return [value];
|
|
}
|
|
|
|
previous.push(value);
|
|
return previous;
|
|
}
|
|
|
|
/**
|
|
* Set the default value, and optionally supply the description to be displayed in the help.
|
|
*
|
|
* @param {*} value
|
|
* @param {string} [description]
|
|
* @return {Argument}
|
|
*/
|
|
|
|
default(value, description) {
|
|
this.defaultValue = value;
|
|
this.defaultValueDescription = description;
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Set the custom handler for processing CLI command arguments into argument values.
|
|
*
|
|
* @param {Function} [fn]
|
|
* @return {Argument}
|
|
*/
|
|
|
|
argParser(fn) {
|
|
this.parseArg = fn;
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Only allow argument value to be one of choices.
|
|
*
|
|
* @param {string[]} values
|
|
* @return {Argument}
|
|
*/
|
|
|
|
choices(values) {
|
|
this.argChoices = values.slice();
|
|
this.parseArg = (arg, previous) => {
|
|
if (!this.argChoices.includes(arg)) {
|
|
throw new InvalidArgumentError(
|
|
`Allowed choices are ${this.argChoices.join(', ')}.`,
|
|
);
|
|
}
|
|
if (this.variadic) {
|
|
return this._collectValue(arg, previous);
|
|
}
|
|
return arg;
|
|
};
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Make argument required.
|
|
*
|
|
* @returns {Argument}
|
|
*/
|
|
argRequired() {
|
|
this.required = true;
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Make argument optional.
|
|
*
|
|
* @returns {Argument}
|
|
*/
|
|
argOptional() {
|
|
this.required = false;
|
|
return this;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Takes an argument and returns its human readable equivalent for help usage.
|
|
*
|
|
* @param {Argument} arg
|
|
* @return {string}
|
|
* @private
|
|
*/
|
|
|
|
function humanReadableArgName(arg) {
|
|
const nameOutput = arg.name() + (arg.variadic === true ? '...' : '');
|
|
|
|
return arg.required ? '<' + nameOutput + '>' : '[' + nameOutput + ']';
|
|
}
|
|
|
|
exports.Argument = Argument;
|
|
exports.humanReadableArgName = humanReadableArgName;
|