tftsr-devops_investigation/node_modules/yargs-unparser/index.js
Shaun Arman 8839075805 feat: initial implementation of TFTSR IT Triage & RCA application
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>
2026-03-14 22:36:25 -05:00

167 lines
5.1 KiB
JavaScript

'use strict';
const flatten = require('flat');
const camelcase = require('camelcase');
const decamelize = require('decamelize');
const isPlainObj = require('is-plain-obj');
function isAlias(key, alias) {
// TODO Switch to Object.values one Node.js 6 is dropped
return Object.keys(alias).some((id) => [].concat(alias[id]).indexOf(key) !== -1);
}
function hasDefaultValue(key, value, defaults) {
return value === defaults[key];
}
function isCamelCased(key, argv) {
return /[A-Z]/.test(key) && camelcase(key) === key && // Is it camel case?
argv[decamelize(key, '-')] != null; // Is the standard version defined?
}
function keyToFlag(key) {
return key.length === 1 ? `-${key}` : `--${key}`;
}
function parseCommand(cmd) {
const extraSpacesStrippedCommand = cmd.replace(/\s{2,}/g, ' ');
const splitCommand = extraSpacesStrippedCommand.split(/\s+(?![^[]*]|[^<]*>)/);
const bregex = /\.*[\][<>]/g;
const firstCommand = splitCommand.shift();
if (!firstCommand) { throw new Error(`No command found in: ${cmd}`); }
const parsedCommand = {
cmd: firstCommand.replace(bregex, ''),
demanded: [],
optional: [],
};
splitCommand.forEach((cmd, i) => {
let variadic = false;
cmd = cmd.replace(/\s/g, '');
if (/\.+[\]>]/.test(cmd) && i === splitCommand.length - 1) { variadic = true; }
if (/^\[/.test(cmd)) {
parsedCommand.optional.push({
cmd: cmd.replace(bregex, '').split('|'),
variadic,
});
} else {
parsedCommand.demanded.push({
cmd: cmd.replace(bregex, '').split('|'),
variadic,
});
}
});
return parsedCommand;
}
function unparseOption(key, value, unparsed) {
if (typeof value === 'string') {
unparsed.push(keyToFlag(key), value);
} else if (value === true) {
unparsed.push(keyToFlag(key));
} else if (value === false) {
unparsed.push(`--no-${key}`);
} else if (Array.isArray(value)) {
value.forEach((item) => unparseOption(key, item, unparsed));
} else if (isPlainObj(value)) {
const flattened = flatten(value, { safe: true });
for (const flattenedKey in flattened) {
if (!isCamelCased(flattenedKey, flattened)) {
unparseOption(`${key}.${flattenedKey}`, flattened[flattenedKey], unparsed);
}
}
// Fallback case (numbers and other types)
} else if (value != null) {
unparsed.push(keyToFlag(key), `${value}`);
}
}
function unparsePositional(argv, options, unparsed) {
const knownPositional = [];
// Unparse command if set, collecting all known positional arguments
// e.g.: build <first> <second> <rest...>
if (options.command) {
const { 0: cmd, index } = options.command.match(/[^<[]*/);
const { demanded, optional } = parseCommand(`foo ${options.command.substr(index + cmd.length)}`);
// Push command (can be a deep command)
unparsed.push(...cmd.trim().split(/\s+/));
// Push positional arguments
[...demanded, ...optional].forEach(({ cmd: cmds, variadic }) => {
knownPositional.push(...cmds);
const cmd = cmds[0];
const args = (variadic ? argv[cmd] || [] : [argv[cmd]])
.filter((arg) => arg != null)
.map((arg) => `${arg}`);
unparsed.push(...args);
});
}
// Unparse unkown positional arguments
argv._ && unparsed.push(...argv._.slice(knownPositional.length));
return knownPositional;
}
function unparseOptions(argv, options, knownPositional, unparsed) {
for (const key of Object.keys(argv)) {
const value = argv[key];
if (
// Remove positional arguments
knownPositional.includes(key) ||
// Remove special _, -- and $0
['_', '--', '$0'].includes(key) ||
// Remove aliases
isAlias(key, options.alias) ||
// Remove default values
hasDefaultValue(key, value, options.default) ||
// Remove camel-cased
isCamelCased(key, argv)
) {
continue;
}
unparseOption(key, argv[key], unparsed);
}
}
function unparseEndOfOptions(argv, options, unparsed) {
// Unparse ending (--) arguments if set
argv['--'] && unparsed.push('--', ...argv['--']);
}
// ------------------------------------------------------------
function unparser(argv, options) {
options = Object.assign({
alias: {},
default: {},
command: null,
}, options);
const unparsed = [];
// Unparse known & unknown positional arguments (foo <first> <second> [rest...])
// All known positional will be returned so that they are not added as flags
const knownPositional = unparsePositional(argv, options, unparsed);
// Unparse option arguments (--foo hello --bar hi)
unparseOptions(argv, options, knownPositional, unparsed);
// Unparse "end-of-options" arguments (stuff after " -- ")
unparseEndOfOptions(argv, options, unparsed);
return unparsed;
}
module.exports = unparser;