@fprad0/skill-master-mcp 1.0.0 → 1.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 +9 -3
- package/README.md +2 -2
- package/VERSION.md +4 -4
- package/bin/lib/client-config.mjs +11 -9
- package/bin/lib/menu-core.mjs +241 -70
- package/bin/skill-master-activation.mjs +3 -1
- package/bin/skill-master-menu.mjs +127 -17
- package/bin/skill-master-success-skills.mjs +52 -2
- package/docs/operations/assets/menu-frame-compact.html +78 -75
- package/docs/operations/assets/menu-frame-dna-hero.html +87 -0
- package/docs/operations/assets/menu-frame-fine-helix.html +89 -0
- package/docs/operations/assets/menu-frame-large.html +86 -83
- package/docs/operations/assets/menu-frame-running.html +82 -79
- package/docs/operations/assets/menu-frame-score-10-contact-sheet.html +184 -0
- package/docs/planning/mcp-1.0.0/00_RESUMO_EXECUTIVO_AUDITORIA_MENU.md +118 -0
- package/docs/planning/mcp-1.0.0/01_MATRIZ_TESTES_MENU_E_RESULTADOS.md +250 -0
- package/docs/planning/mcp-1.0.0/02_PLANO_CORRECAO_ATIVAR_SKILL_APRENDIDA.md +200 -0
- package/docs/planning/mcp-1.0.0/03_PLANO_COMPATIBILIDADE_WINDOWS_LINUX_MACOS.md +167 -0
- package/docs/planning/mcp-1.0.0/04_PLANO_UI_CYBERPUNK_PIXEL_ART_E_PERFORMANCE.md +165 -0
- package/docs/planning/mcp-1.0.0/05_PROMPT_TASK_EXECUCAO_CORRECOES.md +151 -0
- package/docs/planning/mcp-1.0.0/06_CHECKLIST_REGRESSAO_PRE_RELEASE.md +159 -0
- package/docs/planning/mcp-1.0.0/07_RELATORIO_APLICACAO_CORRECOES_MENU_SKILL_MASTER.md +136 -0
- package/docs/planning/mcp-1.0.0/08_AUDITORIA_CRITICA_MENU_NOTA_E_DNA_REFINADO.md +184 -0
- package/docs/planning/mcp-1.0.0/prompt-tasks-nota-10-10/00_PROMPT_TASK_MASTER_NOTA_10_10.md +103 -0
- package/docs/planning/mcp-1.0.0/prompt-tasks-nota-10-10/01_PROMPT_TASK_FINE_HELIX_DNA.md +116 -0
- package/docs/planning/mcp-1.0.0/prompt-tasks-nota-10-10/02_PROMPT_TASK_DNA_HERO_BOOT_AND_MOTION.md +109 -0
- package/docs/planning/mcp-1.0.0/prompt-tasks-nota-10-10/03_PROMPT_TASK_MENU_UX_HELP_ERROR_COPY.md +99 -0
- package/docs/planning/mcp-1.0.0/prompt-tasks-nota-10-10/04_PROMPT_TASK_EVIDENCE_RENDERER_1_0_0.md +97 -0
- package/docs/planning/mcp-1.0.0/prompt-tasks-nota-10-10/05_PROMPT_TASK_CROSS_PLATFORM_UTF8_MOJIBAKE.md +99 -0
- package/docs/planning/mcp-1.0.0/prompt-tasks-nota-10-10/06_PROMPT_TASK_VISUAL_REGRESSION_QA.md +105 -0
- package/docs/planning/mcp-1.0.0/prompt-tasks-nota-10-10/07_PROMPT_TASK_PRE_RELEASE_SCORE_GATE_10_10.md +104 -0
- package/docs/planning/mcp-1.0.0/prompt-tasks-nota-10-10/README_ORDEM_EXECUCAO_NOTA_10_10.md +77 -0
- package/manifests/channels/beta.json +7 -7
- package/manifests/channels/stable.json +8 -8
- package/package.json +16 -14
- package/scripts/render-menu-evidence.mjs +115 -49
- package/scripts/verify-menu-actions.mjs +13 -8
- package/scripts/verify-menu-visual.mjs +90 -0
package/bin/lib/menu-core.mjs
CHANGED
|
@@ -188,6 +188,44 @@ const SUPPORT_SYSTEM_SETUP_ACTIONS = new Set([
|
|
|
188
188
|
'registerClients',
|
|
189
189
|
]);
|
|
190
190
|
|
|
191
|
+
const ASCII_SPARKLINE = ['.', ':', ':', '-', '=', '=', '#', '#'];
|
|
192
|
+
const UNICODE_SPARKLINE = ['▁', '▂', '▃', '▄', '▅', '▆', '▇', '█'];
|
|
193
|
+
|
|
194
|
+
function supportsUnicodeTerminal(env = process.env) {
|
|
195
|
+
if (env.SKILL_MASTER_ASCII === '1') return false;
|
|
196
|
+
if (env.TERM === 'dumb') return false;
|
|
197
|
+
if (env.CI === 'true') return false;
|
|
198
|
+
const locale = `${env.LC_ALL ?? ''} ${env.LC_CTYPE ?? ''} ${env.LANG ?? ''}`.toLowerCase();
|
|
199
|
+
if (locale && !locale.includes('utf') && !locale.includes('65001')) return false;
|
|
200
|
+
if (process.platform === 'win32') {
|
|
201
|
+
const termProgram = `${env.WT_SESSION ?? ''} ${env.TERM_PROGRAM ?? ''} ${env.ConEmuANSI ?? ''}`.toLowerCase();
|
|
202
|
+
const codepage = `${env.CMDCMDLINE ?? ''} ${env.TERM ?? ''}`.toLowerCase();
|
|
203
|
+
return Boolean(termProgram.trim()) || codepage.includes('65001') || locale.includes('utf');
|
|
204
|
+
}
|
|
205
|
+
return true;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
export function resolveGlyphSet({ ascii = false, env = process.env } = {}) {
|
|
209
|
+
const useAscii = ascii || !supportsUnicodeTerminal(env);
|
|
210
|
+
return useAscii
|
|
211
|
+
? {
|
|
212
|
+
ascii: true,
|
|
213
|
+
frame: 'ascii',
|
|
214
|
+
meterFilled: '#',
|
|
215
|
+
meterEmpty: '.',
|
|
216
|
+
sparkline: ASCII_SPARKLINE,
|
|
217
|
+
brailleFilled: '*',
|
|
218
|
+
}
|
|
219
|
+
: {
|
|
220
|
+
ascii: false,
|
|
221
|
+
frame: 'unicode',
|
|
222
|
+
meterFilled: '█',
|
|
223
|
+
meterEmpty: '░',
|
|
224
|
+
sparkline: UNICODE_SPARKLINE,
|
|
225
|
+
brailleFilled: null,
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
|
|
191
229
|
function colorize(text, color, enabled) {
|
|
192
230
|
return enabled ? `${color}${text}${ANSI.reset}` : text;
|
|
193
231
|
}
|
|
@@ -208,6 +246,15 @@ function getActionAttentionBadge(command, status) {
|
|
|
208
246
|
return '';
|
|
209
247
|
}
|
|
210
248
|
|
|
249
|
+
function formatActionBadges(action) {
|
|
250
|
+
const badges = [];
|
|
251
|
+
if (action?.effect) badges.push(action.effect.toUpperCase());
|
|
252
|
+
if (action?.risk) badges.push(`RISK:${action.risk.toUpperCase()}`);
|
|
253
|
+
if (action?.confirmMessage) badges.push('CONFIRM');
|
|
254
|
+
if (action?.requiresTty) badges.push('TTY');
|
|
255
|
+
return badges.map((badge) => `[${badge}]`).join(' ');
|
|
256
|
+
}
|
|
257
|
+
|
|
211
258
|
function getActionLineColor(command, selected, status) {
|
|
212
259
|
const state = getActionAttentionState(command, status);
|
|
213
260
|
if (selected && state === 'critical') return ANSI.rose;
|
|
@@ -225,8 +272,12 @@ function buildSetupAlertLine(status, compact) {
|
|
|
225
272
|
: 'SETUP GLOBAL PENDENTE -> priorize [SETUP AGORA] e [SISTEMA] para autenticar o MCP no computador';
|
|
226
273
|
}
|
|
227
274
|
|
|
275
|
+
function stripAnsi(text) {
|
|
276
|
+
return String(text).replace(/\x1b\[[0-9;?]*[ -/]*[@-~]/g, '');
|
|
277
|
+
}
|
|
278
|
+
|
|
228
279
|
function visibleLength(text) {
|
|
229
|
-
return
|
|
280
|
+
return stripAnsi(text).length;
|
|
230
281
|
}
|
|
231
282
|
|
|
232
283
|
function fitText(text, width) {
|
|
@@ -681,8 +732,13 @@ export function buildMenuCommands({ rootDir, currentFile, nodeExecPath = process
|
|
|
681
732
|
description: 'Abre um fluxo interativo para avaliar um prompt pelo router local.',
|
|
682
733
|
details: ['Ajuda a decidir se skill-master, skill_master ou skill-master-mcp deve agir.', 'Nao publica nem altera skills.'],
|
|
683
734
|
success: 'Router imprime recomendacao, modo de ativacao e gates aplicaveis.',
|
|
735
|
+
effect: 'read-only',
|
|
736
|
+
risk: 'low',
|
|
737
|
+
requiresTty: true,
|
|
738
|
+
automationHint: 'skill-master-menu --run prompt-router --prompt "seu prompt".',
|
|
684
739
|
command: nodeExecPath,
|
|
685
740
|
args: [join(rootDir, 'bin', 'skill-master-activation.mjs'), '--route-prompt-interactive'],
|
|
741
|
+
cwd: invocationCwd,
|
|
686
742
|
},
|
|
687
743
|
{
|
|
688
744
|
key: 'successNotifications',
|
|
@@ -711,6 +767,8 @@ export function buildMenuCommands({ rootDir, currentFile, nodeExecPath = process
|
|
|
711
767
|
description: 'Cria um relatorio local para revisar e aprovar skills aprendidas.',
|
|
712
768
|
details: ['Exige decisao humana antes de ativacao.', 'Inclui riscos, evidencias e recomendacao.'],
|
|
713
769
|
success: 'Pacote local de aprovacao gerado.',
|
|
770
|
+
effect: 'writes-local',
|
|
771
|
+
risk: 'medium',
|
|
714
772
|
command: nodeExecPath,
|
|
715
773
|
args: [join(rootDir, 'bin', 'skill-master-success-skills.mjs'), '--approval-package'],
|
|
716
774
|
},
|
|
@@ -742,8 +800,13 @@ export function buildMenuCommands({ rootDir, currentFile, nodeExecPath = process
|
|
|
742
800
|
description: 'Instala uma skill aprendida em .codex/skills do projeto atual.',
|
|
743
801
|
details: ['Escopo limitado ao workspace.', 'Mais conservador que ativar globalmente.'],
|
|
744
802
|
success: 'Skill copiada para .codex/skills do projeto.',
|
|
803
|
+
effect: 'writes-local',
|
|
804
|
+
risk: 'medium',
|
|
805
|
+
requiresTty: true,
|
|
806
|
+
automationHint: 'use --manifest <manifest.json> --yes ou --yes quando houver exatamente um draft pronto.',
|
|
745
807
|
command: nodeExecPath,
|
|
746
808
|
args: [join(rootDir, 'bin', 'skill-master-success-skills.mjs'), '--activate-interactive', '--target', 'local'],
|
|
809
|
+
cwd: invocationCwd,
|
|
747
810
|
confirmMessage: 'Selecionar e ativar uma skill aprendida no workspace atual?',
|
|
748
811
|
},
|
|
749
812
|
{
|
|
@@ -753,8 +816,13 @@ export function buildMenuCommands({ rootDir, currentFile, nodeExecPath = process
|
|
|
753
816
|
description: 'Instala uma skill aprendida em CODEX_HOME/skills ou ~/.codex/skills.',
|
|
754
817
|
details: ['Afeta todos os projetos deste usuario.', 'Use apenas depois de aprovacao humana.'],
|
|
755
818
|
success: 'Skill instalada no diretorio global de skills.',
|
|
819
|
+
effect: 'writes-global',
|
|
820
|
+
risk: 'high',
|
|
821
|
+
requiresTty: true,
|
|
822
|
+
automationHint: 'use --manifest <manifest.json> --yes ou --yes quando houver exatamente um draft pronto.',
|
|
756
823
|
command: nodeExecPath,
|
|
757
824
|
args: [join(rootDir, 'bin', 'skill-master-success-skills.mjs'), '--activate-interactive', '--target', 'global'],
|
|
825
|
+
cwd: invocationCwd,
|
|
758
826
|
confirmMessage: 'Selecionar e ativar uma skill aprendida como skill global deste usuario?',
|
|
759
827
|
},
|
|
760
828
|
{
|
|
@@ -887,7 +955,14 @@ function patternFill(pattern, width) {
|
|
|
887
955
|
return Array.from({ length: Math.ceil(width / pattern.length) }, () => pattern).join('').slice(0, width);
|
|
888
956
|
}
|
|
889
957
|
|
|
890
|
-
function frameTokens(style) {
|
|
958
|
+
function frameTokens(style, glyphSet = resolveGlyphSet()) {
|
|
959
|
+
if (glyphSet.ascii) {
|
|
960
|
+
if (style === 'running') {
|
|
961
|
+
return { topLeft: '+-', topRight: '-+', bottomLeft: '+-', bottomRight: '-+', fill: '=', left: '||', right: '||', accent: '#', micro: '.' };
|
|
962
|
+
}
|
|
963
|
+
return { topLeft: '+-', topRight: '-+', bottomLeft: '+-', bottomRight: '-+', fill: style === 'focus' ? '=' : '-', left: '| ', right: ' |', accent: '#', micro: '.' };
|
|
964
|
+
}
|
|
965
|
+
|
|
891
966
|
if (style === 'focus') {
|
|
892
967
|
return { topLeft: '╭╼', topRight: '╾╮', bottomLeft: '╰╼', bottomRight: '╾╯', fill: '═', left: '▌ ', right: ' ▐', accent: '▰', micro: '▱' };
|
|
893
968
|
}
|
|
@@ -932,10 +1007,10 @@ function renderCyberRail(width, title, tokens, { bottom = false, tick = 0 } = {}
|
|
|
932
1007
|
return `${left}${fillWithPattern(`${lead}${safeTitle}${chip}${tab}`, innerWidth, tokens.fill)}${right}`;
|
|
933
1008
|
}
|
|
934
1009
|
|
|
935
|
-
function renderCyberFrame(lines, width, title, { useColor = false, color = ANSI.cyan, style = 'data', tick = 0 } = {}) {
|
|
1010
|
+
function renderCyberFrame(lines, width, title, { useColor = false, color = ANSI.cyan, style = 'data', tick = 0, glyphSet = resolveGlyphSet() } = {}) {
|
|
936
1011
|
const safeWidth = Math.max(16, width);
|
|
937
1012
|
const innerWidth = safeWidth - 4;
|
|
938
|
-
const tokens = frameTokens(style);
|
|
1013
|
+
const tokens = frameTokens(style, glyphSet);
|
|
939
1014
|
const top = renderCyberRail(safeWidth, title, tokens, { tick });
|
|
940
1015
|
const bottom = renderCyberRail(safeWidth, title, tokens, { bottom: true, tick });
|
|
941
1016
|
const body = lines.map((line, index) => {
|
|
@@ -1026,9 +1101,10 @@ function drawBrailleLine(canvas, x0, y0, x1, y1, thickness = 0, color = 'gray',
|
|
|
1026
1101
|
}
|
|
1027
1102
|
}
|
|
1028
1103
|
|
|
1029
|
-
function renderBrailleCanvas(canvas, { useColor = false } = {}) {
|
|
1104
|
+
function renderBrailleCanvas(canvas, { useColor = false, glyphSet = resolveGlyphSet() } = {}) {
|
|
1030
1105
|
return canvas.dots.map((row, rowIndex) => row.map((value, colIndex) => {
|
|
1031
1106
|
if (value === 0) return ' ';
|
|
1107
|
+
if (glyphSet.ascii) return glyphSet.brailleFilled;
|
|
1032
1108
|
const color = ANSI[canvas.colors[rowIndex][colIndex]] ?? ANSI.teal;
|
|
1033
1109
|
return colorize(String.fromCodePoint(0x2800 + value), color, useColor);
|
|
1034
1110
|
}).join(''));
|
|
@@ -1068,33 +1144,33 @@ export function formatMenuBanner(status, { useColor = false } = {}) {
|
|
|
1068
1144
|
].join('\n\n');
|
|
1069
1145
|
}
|
|
1070
1146
|
|
|
1071
|
-
function dnaPanelLines(tick, width, height, status, selected, { useColor = false, compact = false } = {}) {
|
|
1147
|
+
function dnaPanelLines(tick, width, height, status, selected, { useColor = false, compact = false, glyphSet = resolveGlyphSet() } = {}) {
|
|
1072
1148
|
const lines = [];
|
|
1073
1149
|
const canvasWidth = Math.max(18, width);
|
|
1074
1150
|
const canvasHeight = Math.max(compact ? 8 : 10, height - 4);
|
|
1075
1151
|
const pixelWidth = canvasWidth * 2;
|
|
1076
1152
|
const pixelHeight = canvasHeight * 4;
|
|
1077
1153
|
const center = Math.floor(pixelWidth / 2);
|
|
1078
|
-
const amplitude = Math.max(
|
|
1154
|
+
const amplitude = Math.max(7, Math.min(Math.floor(pixelWidth * 0.2), compact ? 10 : 15));
|
|
1079
1155
|
const frameCount = 48;
|
|
1080
1156
|
const frameRatio = (tick % frameCount) / frameCount;
|
|
1081
1157
|
const phase = frameRatio * Math.PI * 2;
|
|
1082
1158
|
const scanPhase = (1 - Math.cos(frameRatio * Math.PI * 2)) / 2;
|
|
1083
|
-
const pairEvery = compact ?
|
|
1159
|
+
const pairEvery = compact ? 11 : 9;
|
|
1084
1160
|
const actionArea = resolveCommandArea(selected);
|
|
1085
1161
|
const canvas = createBrailleCanvas(canvasWidth, canvasHeight);
|
|
1086
1162
|
|
|
1087
1163
|
lines.push(fitText(colorize(`DNA CYBER HELIX / ${actionArea}`, ANSI.bold, useColor), width));
|
|
1088
|
-
lines.push(fitText(colorize(compact ? '
|
|
1164
|
+
lines.push(fitText(colorize(compact ? 'fine strand / focus' : 'luminous fine helix / low flicker', ANSI.dim, useColor), width));
|
|
1089
1165
|
|
|
1090
|
-
const twist = compact ? 0.
|
|
1166
|
+
const twist = compact ? 0.19 : 0.168;
|
|
1091
1167
|
const xA = (y) => Math.round(center + Math.sin(y * twist + phase) * amplitude);
|
|
1092
1168
|
const xB = (y) => Math.round(center - Math.sin(y * twist + phase) * amplitude);
|
|
1093
1169
|
const frontA = (y) => Math.cos(y * twist + phase) >= 0;
|
|
1094
1170
|
const scanY = Math.floor(scanPhase * Math.max(1, pixelHeight - 1));
|
|
1095
|
-
const pulse = 0.
|
|
1171
|
+
const pulse = 0.72 + ((Math.sin(phase * 2) + 1) / 2) * 0.18;
|
|
1096
1172
|
|
|
1097
|
-
for (let y = 0; y < pixelHeight; y +=
|
|
1173
|
+
for (let y = 0; y < pixelHeight; y += 12) {
|
|
1098
1174
|
plotBrailleThick(canvas, center, y, 0, 'gray', 0);
|
|
1099
1175
|
}
|
|
1100
1176
|
|
|
@@ -1114,26 +1190,21 @@ function dnaPanelLines(tick, width, height, status, selected, { useColor = false
|
|
|
1114
1190
|
const wave = y * twist + phase;
|
|
1115
1191
|
const depthA = (Math.cos(wave) + 1) / 2;
|
|
1116
1192
|
const depthB = 1 - depthA;
|
|
1117
|
-
const strandAWidth = Math.max(1, Math.round(
|
|
1118
|
-
const strandBWidth = Math.max(1, Math.round(
|
|
1119
|
-
const edgeSpread = compact ? 2 : 3;
|
|
1193
|
+
const strandAWidth = Math.max(0, Math.min(1, Math.round(depthA * pulse)));
|
|
1194
|
+
const strandBWidth = Math.max(0, Math.min(1, Math.round(depthB * pulse)));
|
|
1120
1195
|
const strandAColor = active ? 'white' : nearA ? 'rose' : 'violet';
|
|
1121
1196
|
const strandBColor = active ? 'white' : nearA ? 'teal' : 'blue';
|
|
1122
1197
|
const strandAPriority = active ? 7 : nearA ? 5 : 3;
|
|
1123
1198
|
const strandBPriority = active ? 7 : nearA ? 3 : 5;
|
|
1124
1199
|
|
|
1125
1200
|
if (y > 0) {
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1201
|
+
if (y % 3 === 0) {
|
|
1202
|
+
drawBrailleLine(canvas, previousA + (nearA ? -2 : 2), y - 1, a + (nearA ? -2 : 2), y, 0, nearA ? 'gray' : 'blue', 1);
|
|
1203
|
+
drawBrailleLine(canvas, previousB + (nearA ? 2 : -2), y - 1, b + (nearA ? 2 : -2), y, 0, nearA ? 'blue' : 'gray', 1);
|
|
1204
|
+
}
|
|
1130
1205
|
drawBrailleLine(canvas, previousA, y - 1, a, y, strandAWidth, strandAColor, strandAPriority);
|
|
1131
1206
|
drawBrailleLine(canvas, previousB, y - 1, b, y, strandBWidth, strandBColor, strandBPriority);
|
|
1132
1207
|
} else {
|
|
1133
|
-
plotBrailleThick(canvas, a - edgeSpread, y, 0, nearA ? 'gray' : 'blue', 1);
|
|
1134
|
-
plotBrailleThick(canvas, a + edgeSpread, y, 0, nearA ? 'gray' : 'blue', 1);
|
|
1135
|
-
plotBrailleThick(canvas, b - edgeSpread, y, 0, nearA ? 'blue' : 'gray', 1);
|
|
1136
|
-
plotBrailleThick(canvas, b + edgeSpread, y, 0, nearA ? 'blue' : 'gray', 1);
|
|
1137
1208
|
plotBrailleThick(canvas, a, y, strandAWidth, strandAColor, strandAPriority);
|
|
1138
1209
|
plotBrailleThick(canvas, b, y, strandBWidth, strandBColor, strandBPriority);
|
|
1139
1210
|
}
|
|
@@ -1143,17 +1214,17 @@ function dnaPanelLines(tick, width, height, status, selected, { useColor = false
|
|
|
1143
1214
|
const right = Math.max(a, b);
|
|
1144
1215
|
const rungColor = active ? 'white' : nearA ? 'teal' : 'rose';
|
|
1145
1216
|
const rungPriority = active ? 6 : 4;
|
|
1146
|
-
drawBrailleLine(canvas, left + 3, y, right - 3, y,
|
|
1147
|
-
for (let x = left + 3; x < right - 2; x += active ?
|
|
1148
|
-
plotBrailleThick(canvas, x, y,
|
|
1217
|
+
drawBrailleLine(canvas, left + 3, y, right - 3, y, 0, rungColor, rungPriority);
|
|
1218
|
+
for (let x = left + 3; x < right - 2; x += active ? 4 : 5) {
|
|
1219
|
+
plotBrailleThick(canvas, x, y, 0, rungColor, rungPriority);
|
|
1149
1220
|
}
|
|
1150
1221
|
plotBrailleThick(canvas, Math.round((left + right) / 2), y, active ? 1 : 0, active ? 'white' : 'amber', rungPriority + 1);
|
|
1151
|
-
plotBrailleThick(canvas, a, y,
|
|
1152
|
-
plotBrailleThick(canvas, b, y,
|
|
1222
|
+
plotBrailleThick(canvas, a, y, 0, strandAColor, strandAPriority + 1);
|
|
1223
|
+
plotBrailleThick(canvas, b, y, 0, strandBColor, strandBPriority + 1);
|
|
1153
1224
|
}
|
|
1154
1225
|
}
|
|
1155
1226
|
|
|
1156
|
-
for (const line of renderBrailleCanvas(canvas, { useColor })) {
|
|
1227
|
+
for (const line of renderBrailleCanvas(canvas, { useColor, glyphSet })) {
|
|
1157
1228
|
lines.push(line);
|
|
1158
1229
|
}
|
|
1159
1230
|
|
|
@@ -1162,17 +1233,17 @@ function dnaPanelLines(tick, width, height, status, selected, { useColor = false
|
|
|
1162
1233
|
return lines.slice(0, height).map((line) => fitText(line, width));
|
|
1163
1234
|
}
|
|
1164
1235
|
|
|
1165
|
-
function renderMeterBar(value, total, width, { useColor = false, color = ANSI.teal } = {}) {
|
|
1236
|
+
function renderMeterBar(value, total, width, { useColor = false, color = ANSI.teal, glyphSet = resolveGlyphSet() } = {}) {
|
|
1166
1237
|
const safeTotal = Math.max(1, total);
|
|
1167
1238
|
const safeValue = Math.max(0, Math.min(value, safeTotal));
|
|
1168
1239
|
const fill = Math.round((safeValue / safeTotal) * width);
|
|
1169
|
-
const filled =
|
|
1170
|
-
const empty =
|
|
1240
|
+
const filled = glyphSet.meterFilled.repeat(fill);
|
|
1241
|
+
const empty = glyphSet.meterEmpty.repeat(Math.max(0, width - fill));
|
|
1171
1242
|
return `${colorize(filled, color, useColor)}${colorize(empty, ANSI.gray, useColor)}`;
|
|
1172
1243
|
}
|
|
1173
1244
|
|
|
1174
|
-
function renderSparkline(series, { useColor = false, color = ANSI.teal } = {}) {
|
|
1175
|
-
const blocks =
|
|
1245
|
+
function renderSparkline(series, { useColor = false, color = ANSI.teal, glyphSet = resolveGlyphSet() } = {}) {
|
|
1246
|
+
const blocks = glyphSet.sparkline;
|
|
1176
1247
|
return series.map((value) => colorize(blocks[Math.max(0, Math.min(blocks.length - 1, value))], color, useColor)).join('');
|
|
1177
1248
|
}
|
|
1178
1249
|
|
|
@@ -1184,23 +1255,23 @@ function buildTelemetrySeries(seed, length, tick) {
|
|
|
1184
1255
|
});
|
|
1185
1256
|
}
|
|
1186
1257
|
|
|
1187
|
-
function buildOverviewSignalLine(status, width, tick, { useColor = false, compact = false } = {}) {
|
|
1258
|
+
function buildOverviewSignalLine(status, width, tick, { useColor = false, compact = false, glyphSet = resolveGlyphSet() } = {}) {
|
|
1188
1259
|
const signalWidth = Math.max(6, Math.min(compact ? 8 : 12, Math.floor(width / (compact ? 10 : 8))));
|
|
1189
1260
|
const healthWidth = Math.max(6, Math.min(compact ? 8 : 12, Math.floor(width / (compact ? 10 : 8))));
|
|
1190
1261
|
const signal = renderSparkline(
|
|
1191
1262
|
buildTelemetrySeries(status.globalReadiness.installed.length + status.pendingSuccessDrafts, signalWidth, tick),
|
|
1192
|
-
{ useColor, color: ANSI.teal },
|
|
1263
|
+
{ useColor, color: ANSI.teal, glyphSet },
|
|
1193
1264
|
);
|
|
1194
1265
|
const health = renderSparkline(
|
|
1195
1266
|
buildTelemetrySeries(status.studyCandidates + (status.globalReadiness.ready ? 7 : 3), healthWidth, tick + 3),
|
|
1196
|
-
{ useColor, color: ANSI.amber },
|
|
1267
|
+
{ useColor, color: ANSI.amber, glyphSet },
|
|
1197
1268
|
);
|
|
1198
1269
|
return compact
|
|
1199
1270
|
? `signal ${signal} health ${health}`
|
|
1200
1271
|
: `signal ${signal} health ${health}`;
|
|
1201
1272
|
}
|
|
1202
1273
|
|
|
1203
|
-
function telemetryPanelLines(status, selected, width, height, { useColor = false, tick = 0, compact = false } = {}) {
|
|
1274
|
+
function telemetryPanelLines(status, selected, width, height, { useColor = false, tick = 0, compact = false, glyphSet = resolveGlyphSet() } = {}) {
|
|
1204
1275
|
const commandArea = resolveCommandArea(selected);
|
|
1205
1276
|
const bundledCatalog = status.bundledCatalog ?? { total: 0, categories: [] };
|
|
1206
1277
|
const categoryLead = bundledCatalog.categories
|
|
@@ -1210,20 +1281,20 @@ function telemetryPanelLines(status, selected, width, height, { useColor = false
|
|
|
1210
1281
|
const categoryCount = categoryLead?.count ?? 0;
|
|
1211
1282
|
const meterWidth = Math.max(8, Math.min(16, width - 14));
|
|
1212
1283
|
const sparkWidth = Math.max(8, Math.min(compact ? 8 : 12, width - 18));
|
|
1213
|
-
const skillsSpark = renderSparkline(buildTelemetrySeries(status.globalReadiness.installed.length + categoryCount, sparkWidth, tick), { useColor, color: ANSI.amber });
|
|
1214
|
-
const draftsSpark = renderSparkline(buildTelemetrySeries(status.pendingSuccessDrafts + 2, sparkWidth, tick + 2), { useColor, color: ANSI.teal });
|
|
1215
|
-
const studySpark = renderSparkline(buildTelemetrySeries(status.studyCandidates + 4, sparkWidth, tick + 4), { useColor, color: ANSI.blue });
|
|
1284
|
+
const skillsSpark = renderSparkline(buildTelemetrySeries(status.globalReadiness.installed.length + categoryCount, sparkWidth, tick), { useColor, color: ANSI.amber, glyphSet });
|
|
1285
|
+
const draftsSpark = renderSparkline(buildTelemetrySeries(status.pendingSuccessDrafts + 2, sparkWidth, tick + 2), { useColor, color: ANSI.teal, glyphSet });
|
|
1286
|
+
const studySpark = renderSparkline(buildTelemetrySeries(status.studyCandidates + 4, sparkWidth, tick + 4), { useColor, color: ANSI.blue, glyphSet });
|
|
1216
1287
|
const lines = [
|
|
1217
1288
|
fitText(colorize('SYSTEM WINDOWS', ANSI.bold, useColor), width),
|
|
1218
1289
|
renderStatusCapsule('AREA', commandArea, width, { useColor, color: ANSI.blue }),
|
|
1219
1290
|
renderStatusCapsule('LEAD', `${categoryName} ${categoryCount}`, width, { useColor, color: ANSI.gray }),
|
|
1220
|
-
fitText(`bundle ${String(bundledCatalog.total).padStart(2, '0')} ${renderMeterBar(bundledCatalog.total, Math.max(36, bundledCatalog.total), meterWidth, { useColor, color: ANSI.white })}`, width),
|
|
1221
|
-
fitText(`global ${status.globalReadiness.installed.length}/${status.globalReadiness.required} ${renderMeterBar(status.globalReadiness.installed.length, status.globalReadiness.required, meterWidth, { useColor, color: ANSI.amber })}`, width),
|
|
1291
|
+
fitText(`bundle ${String(bundledCatalog.total).padStart(2, '0')} ${renderMeterBar(bundledCatalog.total, Math.max(36, bundledCatalog.total), meterWidth, { useColor, color: ANSI.white, glyphSet })}`, width),
|
|
1292
|
+
fitText(`global ${status.globalReadiness.installed.length}/${status.globalReadiness.required} ${renderMeterBar(status.globalReadiness.installed.length, status.globalReadiness.required, meterWidth, { useColor, color: ANSI.amber, glyphSet })}`, width),
|
|
1222
1293
|
renderStatusCapsule('LINK', summarizeClientReadiness(status.globalReadiness), width, { useColor, color: ANSI.teal }),
|
|
1223
1294
|
fitText(`skills ${skillsSpark}`, width),
|
|
1224
|
-
fitText(`drafts ${String(status.pendingSuccessDrafts).padStart(2, '0')} ${renderMeterBar(status.pendingSuccessDrafts, Math.max(6, status.pendingSuccessDrafts || 1), meterWidth, { useColor, color: ANSI.teal })}`, width),
|
|
1295
|
+
fitText(`drafts ${String(status.pendingSuccessDrafts).padStart(2, '0')} ${renderMeterBar(status.pendingSuccessDrafts, Math.max(6, status.pendingSuccessDrafts || 1), meterWidth, { useColor, color: ANSI.teal, glyphSet })}`, width),
|
|
1225
1296
|
fitText(`queue ${draftsSpark}`, width),
|
|
1226
|
-
fitText(`study ${String(status.studyCandidates).padStart(2, '0')} ${renderMeterBar(status.studyCandidates, Math.max(8, status.studyCandidates || 1), meterWidth, { useColor, color: ANSI.blue })}`, width),
|
|
1297
|
+
fitText(`study ${String(status.studyCandidates).padStart(2, '0')} ${renderMeterBar(status.studyCandidates, Math.max(8, status.studyCandidates || 1), meterWidth, { useColor, color: ANSI.blue, glyphSet })}`, width),
|
|
1227
1298
|
fitText(`links ${studySpark}`, width),
|
|
1228
1299
|
fitText(colorize(compact ? 'codex / claude / gemini' : 'codex / claude / gemini / antigravity', ANSI.dim, useColor), width),
|
|
1229
1300
|
];
|
|
@@ -1295,11 +1366,13 @@ export function formatCyberMenuFrame(status, commands, selectedIndex, tick = 0,
|
|
|
1295
1366
|
columns = 120,
|
|
1296
1367
|
rows = 32,
|
|
1297
1368
|
useColor = false,
|
|
1369
|
+
ascii = false,
|
|
1298
1370
|
} = {}) {
|
|
1371
|
+
const glyphSet = resolveGlyphSet({ ascii });
|
|
1299
1372
|
const width = Math.max(72, Math.min(columns, 150));
|
|
1300
1373
|
const height = Math.max(22, Math.min(rows - 1, 42));
|
|
1301
1374
|
const compactMode = width < 104 || height < 27;
|
|
1302
|
-
const rightWidth = compactMode ? (width >= 92 ? 28 : 26) : width >= 132 ? 44 : width >= 118 ?
|
|
1375
|
+
const rightWidth = compactMode ? (width >= 92 ? 28 : 26) : width >= 132 ? 44 : width >= 118 ? 40 : width >= 108 ? 36 : 34;
|
|
1303
1376
|
const gutter = 2;
|
|
1304
1377
|
const leftWidth = width - rightWidth - gutter;
|
|
1305
1378
|
const selected = commands[selectedIndex] ?? commands[0];
|
|
@@ -1339,7 +1412,7 @@ export function formatCyberMenuFrame(status, commands, selectedIndex, tick = 0,
|
|
|
1339
1412
|
`version ${status.semver} | channel ${status.manifestVersion} | readiness ${status.globalReadiness.ready ? 'ready' : status.globalReadiness.mode}`,
|
|
1340
1413
|
colorize(`GLOBAL SKILLS ${status.globalReadiness.installed.length}/${status.globalReadiness.required}`, ANSI.amber, useColor),
|
|
1341
1414
|
`bundle ${bundledCatalog.total} | drafts ${status.pendingSuccessDrafts} | study ${status.studyCandidates}`,
|
|
1342
|
-
buildOverviewSignalLine(status, summaryInnerWidth, tick, { useColor, compact: true }),
|
|
1415
|
+
buildOverviewSignalLine(status, summaryInnerWidth, tick, { useColor, compact: true, glyphSet }),
|
|
1343
1416
|
colorize(buildSetupAlertLine(status, true) ?? 'compact cyberpunk hud / operator safe', status.globalReadiness.ready ? ANSI.dim : ANSI.rose, useColor),
|
|
1344
1417
|
]
|
|
1345
1418
|
: [
|
|
@@ -1348,7 +1421,7 @@ export function formatCyberMenuFrame(status, commands, selectedIndex, tick = 0,
|
|
|
1348
1421
|
colorize(`GLOBAL SKILLS ${status.globalReadiness.installed.length}/${status.globalReadiness.required}`, ANSI.amber, useColor),
|
|
1349
1422
|
`bundle ${bundledCatalog.total} | drafts ${status.pendingSuccessDrafts} | study ${status.studyCandidates}`,
|
|
1350
1423
|
renderStatusCapsule('FOCUS', `${actionArea} / ${selected?.key ?? 'status'}`, summaryInnerWidth, { useColor, color: ANSI.teal }),
|
|
1351
|
-
buildOverviewSignalLine(status, summaryInnerWidth, tick, { useColor, compact: false }),
|
|
1424
|
+
buildOverviewSignalLine(status, summaryInnerWidth, tick, { useColor, compact: false, glyphSet }),
|
|
1352
1425
|
colorize(buildSetupAlertLine(status, false) ?? formatBundledCategoryLine(bundledCatalog), status.globalReadiness.ready ? ANSI.white : ANSI.rose, useColor),
|
|
1353
1426
|
colorize(buildSetupAlertLine(status, false) ?? `clients ${summarizeClientReadiness(status.globalReadiness)}`, status.globalReadiness.ready ? ANSI.dim : ANSI.rose, useColor),
|
|
1354
1427
|
];
|
|
@@ -1359,9 +1432,9 @@ export function formatCyberMenuFrame(status, commands, selectedIndex, tick = 0,
|
|
|
1359
1432
|
fitText(colorize(`window ${Math.min(selectedIndex + 1, commands.length)}/${commands.length} | visible ${visibleCommands.length}`, ANSI.gray, useColor), actionInnerWidth),
|
|
1360
1433
|
...visibleCommands.map((command, offset) => {
|
|
1361
1434
|
const index = scrollStart + offset;
|
|
1362
|
-
const marker = index === selectedIndex ? '>' : '·';
|
|
1435
|
+
const marker = index === selectedIndex ? '>' : glyphSet.ascii ? '-' : '·';
|
|
1363
1436
|
const disabled = command.disabledReason ? ' [off]' : '';
|
|
1364
|
-
const flair = index === selectedIndex && !compactMode ? ' ◢' : '';
|
|
1437
|
+
const flair = index === selectedIndex && !compactMode ? glyphSet.ascii ? ' >' : ' ◢' : '';
|
|
1365
1438
|
const badge = getActionAttentionBadge(command, status);
|
|
1366
1439
|
const label = `${marker} ${badge}${command.label}${disabled}${flair}`;
|
|
1367
1440
|
const color = getActionLineColor(command, index === selectedIndex, status);
|
|
@@ -1378,6 +1451,7 @@ export function formatCyberMenuFrame(status, commands, selectedIndex, tick = 0,
|
|
|
1378
1451
|
colorize('DETAIL FOCUS', ANSI.amber, useColor),
|
|
1379
1452
|
colorize(selected?.label ?? 'Nenhuma acao', ANSI.bold, useColor),
|
|
1380
1453
|
renderStatusCapsule('AREA', `${actionArea} | action ${Math.min(selectedIndex + 1, commands.length)}/${commands.length}`, detailInnerWidth, { useColor, color: ANSI.gray }),
|
|
1454
|
+
...((selected?.effect || selected?.risk || selected?.requiresTty) && formatActionBadges(selected) ? [fitText(formatActionBadges(selected), detailInnerWidth)] : []),
|
|
1381
1455
|
fitText(colorize(patternFill('=-', 32), ANSI.amber, useColor), detailInnerWidth),
|
|
1382
1456
|
...(() => {
|
|
1383
1457
|
const attention = getActionAttentionState(selected, status);
|
|
@@ -1390,12 +1464,14 @@ export function formatCyberMenuFrame(status, commands, selectedIndex, tick = 0,
|
|
|
1390
1464
|
return [];
|
|
1391
1465
|
})(),
|
|
1392
1466
|
...splitText(selected?.description ? `desc: ${selected.description}` : '', detailInnerWidth, 1),
|
|
1467
|
+
...((selected?.details ?? []).slice(0, 1).flatMap((detail) => splitText(`detail: ${detail}`, detailInnerWidth, 1))),
|
|
1393
1468
|
...(selected?.key === 'updateGlobal'
|
|
1394
1469
|
? splitText('recommended: se houver handoff ou aviso, feche o menu, rode o comando exibido e reabra os clientes MCP depois.', detailInnerWidth, 3)
|
|
1395
1470
|
: []),
|
|
1396
|
-
...(
|
|
1397
|
-
...splitText(`exec: ${formatActionCommand(selected)}`, detailInnerWidth, 1),
|
|
1471
|
+
...(selected?.automationHint ? splitText(`automation: ${selected.automationHint}`, detailInnerWidth, 2) : []),
|
|
1472
|
+
...splitText(`exec: ${formatActionCommand(selected)}`, detailInnerWidth, 1),
|
|
1398
1473
|
...splitText(selected?.success ? `result: ${selected.success}` : '', detailInnerWidth, 1),
|
|
1474
|
+
...((selected?.details ?? []).slice(1).flatMap((detail) => splitText(`detail: ${detail}`, detailInnerWidth, 2))),
|
|
1399
1475
|
...(selected?.confirmMessage ? splitText(`confirmacao: ${selected.confirmMessage}`, detailInnerWidth, 2) : []),
|
|
1400
1476
|
...(selected?.disabledReason ? splitText(`Indisponivel: ${selected.disabledReason}`, detailInnerWidth, 2) : []),
|
|
1401
1477
|
];
|
|
@@ -1404,28 +1480,28 @@ export function formatCyberMenuFrame(status, commands, selectedIndex, tick = 0,
|
|
|
1404
1480
|
descriptionLines.push(fitText('', detailInnerWidth));
|
|
1405
1481
|
}
|
|
1406
1482
|
|
|
1407
|
-
const rightTopLines = dnaPanelLines(tick, rightInnerWidth, rightTopInnerHeight, status, selected, { useColor, compact: compactMode });
|
|
1408
|
-
const rightBottomLines = telemetryPanelLines(status, selected, rightInnerWidth, rightBottomInnerHeight, { useColor, tick, compact: compactMode });
|
|
1483
|
+
const rightTopLines = dnaPanelLines(tick, rightInnerWidth, rightTopInnerHeight, status, selected, { useColor, compact: compactMode, glyphSet });
|
|
1484
|
+
const rightBottomLines = telemetryPanelLines(status, selected, rightInnerWidth, rightBottomInnerHeight, { useColor, tick, compact: compactMode, glyphSet });
|
|
1409
1485
|
const summaryBox = renderCyberFrame(
|
|
1410
1486
|
summaryLines.slice(0, summaryInnerHeight).map((line) => fitText(line, summaryInnerWidth)),
|
|
1411
1487
|
width,
|
|
1412
1488
|
'overview',
|
|
1413
|
-
{ useColor, color: ANSI.white, style: 'hud', tick },
|
|
1489
|
+
{ useColor, color: ANSI.white, style: 'hud', tick, glyphSet },
|
|
1414
1490
|
);
|
|
1415
1491
|
const actionBox = renderCyberFrame(
|
|
1416
1492
|
actionLines.slice(0, actionInnerHeight).map((line) => fitText(line, actionInnerWidth)),
|
|
1417
1493
|
leftWidth,
|
|
1418
1494
|
'actions',
|
|
1419
|
-
{ useColor, color: ANSI.gray, style: 'thin', tick },
|
|
1495
|
+
{ useColor, color: ANSI.gray, style: 'thin', tick, glyphSet },
|
|
1420
1496
|
);
|
|
1421
1497
|
const detailBox = renderCyberFrame(
|
|
1422
1498
|
descriptionLines.slice(0, detailInnerHeight).map((line) => fitText(line, detailInnerWidth)),
|
|
1423
1499
|
leftWidth,
|
|
1424
1500
|
'details',
|
|
1425
|
-
{ useColor, color: ANSI.amber, style: 'focus', tick },
|
|
1501
|
+
{ useColor, color: ANSI.amber, style: 'focus', tick, glyphSet },
|
|
1426
1502
|
);
|
|
1427
|
-
const dnaBox = renderCyberFrame(rightTopLines, rightWidth, 'dna-core', { useColor, color: ANSI.white, style: 'hud', tick });
|
|
1428
|
-
const telemetryBox = renderCyberFrame(rightBottomLines, rightWidth, 'telemetry', { useColor, color: ANSI.blue, style: 'thin', tick });
|
|
1503
|
+
const dnaBox = renderCyberFrame(rightTopLines, rightWidth, 'dna-core', { useColor, color: ANSI.white, style: 'hud', tick, glyphSet });
|
|
1504
|
+
const telemetryBox = renderCyberFrame(rightBottomLines, rightWidth, 'telemetry', { useColor, color: ANSI.blue, style: 'thin', tick, glyphSet });
|
|
1429
1505
|
const bodyRows = joinHorizontalBoxes([
|
|
1430
1506
|
{ lines: [...actionBox, ...detailBox], width: leftWidth },
|
|
1431
1507
|
{ lines: [...dnaBox, ...telemetryBox], width: rightWidth },
|
|
@@ -1438,12 +1514,14 @@ export function formatRunningActionFrame(status, action, tick = 0, {
|
|
|
1438
1514
|
columns = 120,
|
|
1439
1515
|
rows = 32,
|
|
1440
1516
|
useColor = false,
|
|
1517
|
+
ascii = false,
|
|
1441
1518
|
} = {}) {
|
|
1519
|
+
const glyphSet = resolveGlyphSet({ ascii });
|
|
1442
1520
|
const width = Math.max(72, Math.min(columns, 150));
|
|
1443
1521
|
const height = Math.max(18, Math.min(rows - 1, 30));
|
|
1444
1522
|
const innerWidth = width - 4;
|
|
1445
1523
|
const commandArea = resolveCommandArea(action);
|
|
1446
|
-
const pulse = renderSparkline(buildTelemetrySeries((status.globalReadiness.installed.length || 1) + tick, Math.max(8, Math.min(18, Math.floor(innerWidth / 5))), tick), { useColor, color: ANSI.teal });
|
|
1524
|
+
const pulse = renderSparkline(buildTelemetrySeries((status.globalReadiness.installed.length || 1) + tick, Math.max(8, Math.min(18, Math.floor(innerWidth / 5))), tick), { useColor, color: ANSI.teal, glyphSet });
|
|
1447
1525
|
const gridHeight = Math.max(4, Math.min(8, height - 14));
|
|
1448
1526
|
const lines = [
|
|
1449
1527
|
colorize('SKILL_MASTER WORKFLOW ONLINE', ANSI.bold, useColor),
|
|
@@ -1467,7 +1545,7 @@ export function formatRunningActionFrame(status, action, tick = 0, {
|
|
|
1467
1545
|
lines.slice(0, Math.max(8, height - 2)).map((line) => fitText(line, innerWidth)),
|
|
1468
1546
|
width,
|
|
1469
1547
|
'running',
|
|
1470
|
-
{ useColor, color: ANSI.teal, style: 'running', tick },
|
|
1548
|
+
{ useColor, color: ANSI.teal, style: 'running', tick, glyphSet },
|
|
1471
1549
|
).join('\n');
|
|
1472
1550
|
}
|
|
1473
1551
|
|
|
@@ -1475,13 +1553,15 @@ export function formatSkillMasterIntroFrame(status, tick = 0, {
|
|
|
1475
1553
|
columns = 120,
|
|
1476
1554
|
rows = 32,
|
|
1477
1555
|
useColor = false,
|
|
1556
|
+
ascii = false,
|
|
1478
1557
|
message = 'skill_master assumindo o workflow',
|
|
1479
1558
|
} = {}) {
|
|
1559
|
+
const glyphSet = resolveGlyphSet({ ascii });
|
|
1480
1560
|
const width = Math.max(72, Math.min(columns, 150));
|
|
1481
1561
|
const height = Math.max(18, Math.min(rows - 1, 34));
|
|
1482
1562
|
const innerWidth = width - 4;
|
|
1483
1563
|
const gridHeight = Math.max(6, Math.min(12, height - 12));
|
|
1484
|
-
const signal = renderSparkline(buildTelemetrySeries(status.pendingSuccessDrafts + status.studyCandidates + 5, Math.max(12, Math.min(28, Math.floor(innerWidth / 4))), tick), { useColor, color: ANSI.teal });
|
|
1564
|
+
const signal = renderSparkline(buildTelemetrySeries(status.pendingSuccessDrafts + status.studyCandidates + 5, Math.max(12, Math.min(28, Math.floor(innerWidth / 4))), tick), { useColor, color: ANSI.teal, glyphSet });
|
|
1485
1565
|
const lines = [
|
|
1486
1566
|
colorize('REBORN / SKILL_MASTER', ANSI.bold, useColor),
|
|
1487
1567
|
fitText(colorize(message, ANSI.amber, useColor), innerWidth),
|
|
@@ -1502,7 +1582,57 @@ export function formatSkillMasterIntroFrame(status, tick = 0, {
|
|
|
1502
1582
|
lines.slice(0, Math.max(8, height - 2)).map((line) => fitText(line, innerWidth)),
|
|
1503
1583
|
width,
|
|
1504
1584
|
'boot-sequence',
|
|
1505
|
-
{ useColor, color: ANSI.teal, style: 'hud', tick },
|
|
1585
|
+
{ useColor, color: ANSI.teal, style: 'hud', tick, glyphSet },
|
|
1586
|
+
).join('\n');
|
|
1587
|
+
}
|
|
1588
|
+
|
|
1589
|
+
export function formatSkillMasterDnaHeroFrame(status, tick = 0, {
|
|
1590
|
+
columns = 120,
|
|
1591
|
+
rows = 32,
|
|
1592
|
+
useColor = false,
|
|
1593
|
+
ascii = false,
|
|
1594
|
+
} = {}) {
|
|
1595
|
+
const glyphSet = resolveGlyphSet({ ascii });
|
|
1596
|
+
const width = Math.max(72, Math.min(columns, 150));
|
|
1597
|
+
const height = Math.max(18, Math.min(rows - 1, 34));
|
|
1598
|
+
const innerWidth = width - 4;
|
|
1599
|
+
const dnaHeight = Math.max(10, Math.min(16, height - 10));
|
|
1600
|
+
const dnaWidth = Math.max(34, Math.min(innerWidth, 72));
|
|
1601
|
+
const signal = renderSparkline(
|
|
1602
|
+
buildTelemetrySeries(status.globalReadiness.installed.length + status.studyCandidates + 9, Math.max(14, Math.min(30, Math.floor(innerWidth / 4))), tick),
|
|
1603
|
+
{ useColor, color: ANSI.teal, glyphSet },
|
|
1604
|
+
);
|
|
1605
|
+
const dnaLines = dnaPanelLines(
|
|
1606
|
+
tick,
|
|
1607
|
+
dnaWidth,
|
|
1608
|
+
dnaHeight,
|
|
1609
|
+
status,
|
|
1610
|
+
{ key: 'dnaHero', label: 'DNA hero' },
|
|
1611
|
+
{ useColor, compact: false, glyphSet },
|
|
1612
|
+
);
|
|
1613
|
+
const centeredDna = dnaLines.map((line) => {
|
|
1614
|
+
const pad = Math.max(0, Math.floor((innerWidth - dnaWidth) / 2));
|
|
1615
|
+
return fitText(`${' '.repeat(pad)}${line.trimEnd()}`, innerWidth);
|
|
1616
|
+
});
|
|
1617
|
+
const lines = [
|
|
1618
|
+
colorize('SKILL_MASTER DNA ONLINE', ANSI.bold, useColor),
|
|
1619
|
+
fitText(colorize('boot hero / intelligence configuration / terminal-safe animation', ANSI.amber, useColor), innerWidth),
|
|
1620
|
+
fitText(colorize(`package ${status.packageName} | version ${status.semver} | channel ${status.manifestVersion}`, ANSI.gray, useColor), innerWidth),
|
|
1621
|
+
fitText(colorize(`DNA signal ${signal}`, ANSI.teal, useColor), innerWidth),
|
|
1622
|
+
...centeredDna,
|
|
1623
|
+
fitText(renderCircuitRail(innerWidth, tick, { useColor, color: ANSI.teal }), innerWidth),
|
|
1624
|
+
fitText(colorize(`ONLINE | global ${status.globalReadiness.installed.length}/${status.globalReadiness.required} | bundle ${status.bundledCatalog?.total ?? 0}`, ANSI.gray, useColor), innerWidth),
|
|
1625
|
+
];
|
|
1626
|
+
|
|
1627
|
+
while (lines.length < Math.max(8, height - 2)) {
|
|
1628
|
+
lines.push(fitText('', innerWidth));
|
|
1629
|
+
}
|
|
1630
|
+
|
|
1631
|
+
return renderCyberFrame(
|
|
1632
|
+
lines.slice(0, Math.max(8, height - 2)).map((line) => fitText(line, innerWidth)),
|
|
1633
|
+
width,
|
|
1634
|
+
'dna-hero',
|
|
1635
|
+
{ useColor, color: ANSI.teal, style: 'hud', tick, glyphSet },
|
|
1506
1636
|
).join('\n');
|
|
1507
1637
|
}
|
|
1508
1638
|
|
|
@@ -1510,7 +1640,9 @@ export function formatCyberConfirmFrame(status, action, tick = 0, {
|
|
|
1510
1640
|
columns = 120,
|
|
1511
1641
|
rows = 32,
|
|
1512
1642
|
useColor = false,
|
|
1643
|
+
ascii = false,
|
|
1513
1644
|
} = {}) {
|
|
1645
|
+
const glyphSet = resolveGlyphSet({ ascii });
|
|
1514
1646
|
const width = Math.max(72, Math.min(columns, 140));
|
|
1515
1647
|
const height = Math.max(16, Math.min(rows - 1, 28));
|
|
1516
1648
|
const innerWidth = width - 4;
|
|
@@ -1534,15 +1666,17 @@ export function formatCyberConfirmFrame(status, action, tick = 0, {
|
|
|
1534
1666
|
lines.slice(0, Math.max(8, height - 2)).map((line) => fitText(line, innerWidth)),
|
|
1535
1667
|
width,
|
|
1536
1668
|
'subroutine',
|
|
1537
|
-
{ useColor, color: ANSI.amber, style: 'focus', tick },
|
|
1669
|
+
{ useColor, color: ANSI.amber, style: 'focus', tick, glyphSet },
|
|
1538
1670
|
).join('\n');
|
|
1539
1671
|
}
|
|
1540
1672
|
|
|
1541
1673
|
export function formatActionHeader(action, { useColor = false } = {}) {
|
|
1542
1674
|
const lines = [
|
|
1543
1675
|
colorize(action.label, ANSI.bold, useColor),
|
|
1676
|
+
formatActionBadges(action),
|
|
1544
1677
|
action.description,
|
|
1545
1678
|
...(action.details ?? []),
|
|
1679
|
+
action.automationHint ? `Automacao: ${action.automationHint}` : null,
|
|
1546
1680
|
action.success ? `Resultado esperado: ${action.success}` : null,
|
|
1547
1681
|
action.disabledReason ? `Indisponivel: ${action.disabledReason}` : null,
|
|
1548
1682
|
].filter(Boolean);
|
|
@@ -1585,21 +1719,58 @@ export function formatHelp(commands) {
|
|
|
1585
1719
|
const actionList = commands.map((command) => {
|
|
1586
1720
|
const aliases = command.aliases.length ? ` aliases: ${command.aliases.join(', ')}` : '';
|
|
1587
1721
|
const disabled = command.disabledReason ? ` indisponivel: ${command.disabledReason}` : '';
|
|
1588
|
-
|
|
1722
|
+
const badges = formatActionBadges(command);
|
|
1723
|
+
const hint = command.automationHint ? `\n ${command.automationHint}` : '';
|
|
1724
|
+
return ` - ${command.key}: ${command.label}${badges ? ` ${badges}` : ''}\n ${command.description}${aliases}${disabled}${hint}`;
|
|
1589
1725
|
}).join('\n');
|
|
1726
|
+
const workspaceActions = commands
|
|
1727
|
+
.filter((command) => ['check', 'build', 'installProjectSkills', 'activateLearnedLocal'].includes(command.key))
|
|
1728
|
+
.map((command) => ` - ${command.key}: ${command.label}`)
|
|
1729
|
+
.join('\n');
|
|
1730
|
+
const globalActions = commands
|
|
1731
|
+
.filter((command) => ['updateGlobal', 'privateRegistry', 'activationAlwaysOn', 'installGlobalSkills', 'bootstrapGlobal', 'registerClients', 'rejectLearnedSkill', 'activateLearnedGlobal'].includes(command.key))
|
|
1732
|
+
.map((command) => ` - ${command.key}: ${command.label}`)
|
|
1733
|
+
.join('\n');
|
|
1590
1734
|
|
|
1591
1735
|
return `Skill Master Menu
|
|
1592
1736
|
|
|
1593
|
-
Uso:
|
|
1737
|
+
Uso humano:
|
|
1594
1738
|
skill-master-menu
|
|
1595
|
-
skill-master-menu --status
|
|
1596
|
-
skill-master-menu --run <acao>
|
|
1597
|
-
skill-master-menu --run update --yes
|
|
1598
1739
|
skill-master-menu --help
|
|
1599
1740
|
|
|
1600
|
-
|
|
1741
|
+
Automacao sem TTY:
|
|
1742
|
+
skill-master-menu --status
|
|
1743
|
+
skill-master-menu --run <acao>
|
|
1744
|
+
skill-master-menu --run update --yes
|
|
1745
|
+
skill-master-menu --run activate-learned-local --manifest <manifest.json> --yes
|
|
1746
|
+
skill-master-menu --run activate-learned-global --manifest <manifest.json> --yes
|
|
1747
|
+
skill-master-menu --run prompt-router --prompt "validar menu nota 10"
|
|
1748
|
+
skill-master-menu --run activate-learned-local --list
|
|
1749
|
+
skill-master-menu --run activate-learned-global --list
|
|
1750
|
+
skill-master-menu --help
|
|
1751
|
+
|
|
1752
|
+
Diagnostico seguro:
|
|
1753
|
+
skill-master-menu --status
|
|
1754
|
+
skill-master-menu --run doctor
|
|
1755
|
+
skill-master-menu --run public-npm
|
|
1756
|
+
skill-master-menu --run notifications
|
|
1757
|
+
|
|
1758
|
+
Acoes que escrevem no workspace:
|
|
1759
|
+
${workspaceActions}
|
|
1760
|
+
|
|
1761
|
+
Acoes globais ou de risco alto:
|
|
1762
|
+
${globalActions}
|
|
1763
|
+
|
|
1764
|
+
Acoes disponiveis:
|
|
1601
1765
|
${actionList}
|
|
1602
1766
|
|
|
1767
|
+
Parametros uteis:
|
|
1768
|
+
--prompt "texto" passa prompt direto ao router sem abrir pergunta interativa
|
|
1769
|
+
--manifest <arquivo> seleciona manifest explicito de skill aprendida
|
|
1770
|
+
--list lista drafts quando usado com activate-learned-local/global
|
|
1771
|
+
--yes confirma acoes mutantes em automacao
|
|
1772
|
+
--overwrite permite substituir skill ja instalada quando usado com --manifest
|
|
1773
|
+
|
|
1603
1774
|
O comando de menu e voltado para operacao humana. O binario MCP stdio continua sendo:
|
|
1604
1775
|
skill-master-mcp
|
|
1605
1776
|
`;
|
|
@@ -67,7 +67,9 @@ const loadSkills = async () => {
|
|
|
67
67
|
};
|
|
68
68
|
|
|
69
69
|
const routePrompt = async (prompt, { format }) => {
|
|
70
|
-
if (!prompt)
|
|
70
|
+
if (!prompt) {
|
|
71
|
+
throw new Error('Missing prompt. Use: skill-master-menu --run prompt-router --prompt "validar menu nota 10"');
|
|
72
|
+
}
|
|
71
73
|
const config = readActivationConfig();
|
|
72
74
|
const skills = await loadSkills();
|
|
73
75
|
const decision = routeSkillMasterPrompt(skills, prompt, {
|