@cccarv82/freya 1.0.8 → 1.0.10
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/cli/web.js +129 -32
- package/package.json +1 -1
package/cli/web.js
CHANGED
|
@@ -6,11 +6,13 @@ const path = require('path');
|
|
|
6
6
|
const { spawn } = require('child_process');
|
|
7
7
|
|
|
8
8
|
function guessNpmCmd() {
|
|
9
|
-
|
|
9
|
+
// We'll execute via cmd.exe on Windows for reliability.
|
|
10
|
+
return process.platform === 'win32' ? 'npm' : 'npm';
|
|
10
11
|
}
|
|
11
12
|
|
|
12
13
|
function guessNpxCmd() {
|
|
13
|
-
|
|
14
|
+
// We'll execute via cmd.exe on Windows for reliability.
|
|
15
|
+
return process.platform === 'win32' ? 'npx' : 'npx';
|
|
14
16
|
}
|
|
15
17
|
|
|
16
18
|
function guessNpxYesFlag() {
|
|
@@ -99,8 +101,15 @@ function readBody(req) {
|
|
|
99
101
|
function run(cmd, args, cwd) {
|
|
100
102
|
return new Promise((resolve) => {
|
|
101
103
|
let child;
|
|
104
|
+
|
|
102
105
|
try {
|
|
103
|
-
|
|
106
|
+
// On Windows, reliably execute CLI tools through cmd.exe.
|
|
107
|
+
if (process.platform === 'win32' && (cmd === 'npx' || cmd === 'npm')) {
|
|
108
|
+
const comspec = process.env.ComSpec || 'cmd.exe';
|
|
109
|
+
child = spawn(comspec, ['/d', '/s', '/c', cmd, ...args], { cwd, shell: false, env: process.env });
|
|
110
|
+
} else {
|
|
111
|
+
child = spawn(cmd, args, { cwd, shell: false, env: process.env });
|
|
112
|
+
}
|
|
104
113
|
} catch (e) {
|
|
105
114
|
return resolve({ code: 1, stdout: '', stderr: e.message || String(e) });
|
|
106
115
|
}
|
|
@@ -115,7 +124,7 @@ function run(cmd, args, cwd) {
|
|
|
115
124
|
stderr += d.toString();
|
|
116
125
|
});
|
|
117
126
|
|
|
118
|
-
// Prevent unhandled error event (e.g., ENOENT
|
|
127
|
+
// Prevent unhandled error event (e.g., ENOENT/EINVAL)
|
|
119
128
|
child.on('error', (e) => {
|
|
120
129
|
stderr += `\n${e.message || String(e)}`;
|
|
121
130
|
resolve({ code: 1, stdout, stderr });
|
|
@@ -945,72 +954,160 @@ function isoNow() {
|
|
|
945
954
|
return new Date().toISOString();
|
|
946
955
|
}
|
|
947
956
|
|
|
957
|
+
function daysAgoIso(n) {
|
|
958
|
+
return new Date(Date.now() - n * 24 * 60 * 60 * 1000).toISOString();
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
function readJsonOrNull(p) {
|
|
962
|
+
try {
|
|
963
|
+
return JSON.parse(fs.readFileSync(p, 'utf8'));
|
|
964
|
+
} catch {
|
|
965
|
+
return null;
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
function writeJson(p, obj) {
|
|
970
|
+
ensureDir(path.dirname(p));
|
|
971
|
+
fs.writeFileSync(p, JSON.stringify(obj, null, 2) + '\n', 'utf8');
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
function looksLikeDevSeed(json) {
|
|
975
|
+
if (!json || typeof json !== 'object') return false;
|
|
976
|
+
// Heuristic: any id ends with demo marker or source is dev-seed
|
|
977
|
+
const dump = JSON.stringify(json);
|
|
978
|
+
return dump.includes('dev-seed') || dump.includes('t-demo-') || dump.includes('b-demo-') || dump.includes('c-demo-');
|
|
979
|
+
}
|
|
980
|
+
|
|
948
981
|
function seedDevWorkspace(workspaceDir) {
|
|
949
|
-
//
|
|
982
|
+
// Safe by default:
|
|
983
|
+
// - create missing demo files
|
|
984
|
+
// - if file exists and looks like prior dev-seed, upgrade it to richer demo
|
|
950
985
|
ensureDir(path.join(workspaceDir, 'data', 'tasks'));
|
|
951
986
|
ensureDir(path.join(workspaceDir, 'data', 'career'));
|
|
952
987
|
ensureDir(path.join(workspaceDir, 'data', 'blockers'));
|
|
953
988
|
ensureDir(path.join(workspaceDir, 'data', 'Clients', 'acme', 'rocket'));
|
|
989
|
+
ensureDir(path.join(workspaceDir, 'data', 'Clients', 'vivo', '5g'));
|
|
954
990
|
ensureDir(path.join(workspaceDir, 'logs', 'daily'));
|
|
955
991
|
|
|
956
992
|
const taskLog = path.join(workspaceDir, 'data', 'tasks', 'task-log.json');
|
|
957
|
-
|
|
958
|
-
|
|
993
|
+
const taskExisting = readJsonOrNull(taskLog);
|
|
994
|
+
if (!exists(taskLog) || looksLikeDevSeed(taskExisting)) {
|
|
995
|
+
writeJson(taskLog, {
|
|
959
996
|
schemaVersion: 1,
|
|
960
997
|
tasks: [
|
|
961
|
-
|
|
962
|
-
{ id: 't-demo-
|
|
963
|
-
{ id: 't-demo-
|
|
998
|
+
// Completed in last 7 days
|
|
999
|
+
{ id: 't-demo-ship-1', description: 'Publicar pacote @cccarv82/freya no npm (CI)', category: 'DO_NOW', status: 'COMPLETED', createdAt: daysAgoIso(6), completedAt: daysAgoIso(5), priority: 'high', projectSlug: 'acme-rocket' },
|
|
1000
|
+
{ id: 't-demo-ship-2', description: 'Adicionar UI web local (freya web)', category: 'DO_NOW', status: 'COMPLETED', createdAt: daysAgoIso(4), completedAt: daysAgoIso(3), priority: 'high', projectSlug: 'acme-rocket' },
|
|
1001
|
+
{ id: 't-demo-ship-3', description: 'Corrigir publish via npm token/2FA', category: 'DO_NOW', status: 'COMPLETED', createdAt: daysAgoIso(3), completedAt: daysAgoIso(2), priority: 'medium' },
|
|
1002
|
+
// Pending
|
|
1003
|
+
{ id: 't-demo-now-1', description: 'Refinar UI/UX do painel web (layout + preview)', category: 'DO_NOW', status: 'PENDING', createdAt: daysAgoIso(1), priority: 'high' },
|
|
1004
|
+
{ id: 't-demo-now-2', description: 'Melhorar publish no Teams (cards + chunks)', category: 'DO_NOW', status: 'PENDING', createdAt: daysAgoIso(1), priority: 'medium' },
|
|
1005
|
+
{ id: 't-demo-schedule-1', description: 'Criar modo "freya web" com preview Markdown', category: 'SCHEDULE', status: 'PENDING', createdAt: daysAgoIso(0), priority: 'medium' },
|
|
1006
|
+
{ id: 't-demo-delegate-1', description: 'Pedir feedback de 3 usuários beta (UX)', category: 'DELEGATE', status: 'PENDING', createdAt: daysAgoIso(0), priority: 'low' }
|
|
964
1007
|
]
|
|
965
|
-
}
|
|
1008
|
+
});
|
|
966
1009
|
}
|
|
967
1010
|
|
|
968
1011
|
const careerLog = path.join(workspaceDir, 'data', 'career', 'career-log.json');
|
|
969
|
-
|
|
970
|
-
|
|
1012
|
+
const careerExisting = readJsonOrNull(careerLog);
|
|
1013
|
+
if (!exists(careerLog) || looksLikeDevSeed(careerExisting)) {
|
|
1014
|
+
writeJson(careerLog, {
|
|
971
1015
|
schemaVersion: 1,
|
|
972
1016
|
entries: [
|
|
973
|
-
{ id: 'c-demo-1', date:
|
|
974
|
-
{ id: 'c-demo-2', date:
|
|
1017
|
+
{ id: 'c-demo-1', date: daysAgoIso(6).slice(0, 10), type: 'Achievement', description: 'Estruturou pipeline de publicação npm com tags e NPM_TOKEN', tags: ['devops', 'release'], source: 'dev-seed' },
|
|
1018
|
+
{ id: 'c-demo-2', date: daysAgoIso(4).slice(0, 10), type: 'Feedback', description: 'Feedback: “Setup via npx ficou ridiculamente simples.”', tags: ['product', 'ux'], source: 'dev-seed' },
|
|
1019
|
+
{ id: 'c-demo-3', date: daysAgoIso(2).slice(0, 10), type: 'Achievement', description: 'Entregou modo web local com geração de relatórios e publish.', tags: ['shipping', 'frontend'], source: 'dev-seed' },
|
|
1020
|
+
{ id: 'c-demo-4', date: daysAgoIso(1).slice(0, 10), type: 'Goal', description: 'Validar o produto com 5 times e transformar em serviço B2B.', tags: ['business'], source: 'dev-seed' }
|
|
975
1021
|
]
|
|
976
|
-
}
|
|
1022
|
+
});
|
|
977
1023
|
}
|
|
978
1024
|
|
|
979
1025
|
const blockerLog = path.join(workspaceDir, 'data', 'blockers', 'blocker-log.json');
|
|
980
|
-
|
|
981
|
-
|
|
1026
|
+
const blockerExisting = readJsonOrNull(blockerLog);
|
|
1027
|
+
if (!exists(blockerLog) || looksLikeDevSeed(blockerExisting)) {
|
|
1028
|
+
writeJson(blockerLog, {
|
|
982
1029
|
schemaVersion: 1,
|
|
983
1030
|
blockers: [
|
|
984
|
-
{ id: 'b-demo-1', title: '
|
|
985
|
-
{ id: 'b-demo-
|
|
1031
|
+
{ id: 'b-demo-crit-1', title: 'Spawn EINVAL no Windows ao rodar npx via server', description: 'Ajustar execução via cmd.exe /c', createdAt: daysAgoIso(2), status: 'RESOLVED', severity: 'CRITICAL', resolvedAt: daysAgoIso(1), nextAction: 'Validar em ambiente real' },
|
|
1032
|
+
{ id: 'b-demo-high-1', title: 'Teams webhook truncando mensagens longas', description: 'Implementar chunking + cards', createdAt: daysAgoIso(1), status: 'OPEN', severity: 'HIGH', nextAction: 'Dividir em blocos e enviar sequencialmente' },
|
|
1033
|
+
{ id: 'b-demo-med-1', title: 'Preview Markdown no web (render)', description: 'Adicionar render de Markdown no front', createdAt: daysAgoIso(1), status: 'MITIGATING', severity: 'MEDIUM', nextAction: 'Render simples (headers/lists/code) sem deps' },
|
|
1034
|
+
{ id: 'b-demo-low-1', title: 'Polish: remover duplicações na UI', description: 'Consolidar ações na sidebar ou na página', createdAt: daysAgoIso(0), status: 'OPEN', severity: 'LOW' }
|
|
986
1035
|
]
|
|
987
|
-
}
|
|
1036
|
+
});
|
|
988
1037
|
}
|
|
989
1038
|
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
1039
|
+
// Project statuses
|
|
1040
|
+
const projectStatus1 = path.join(workspaceDir, 'data', 'Clients', 'acme', 'rocket', 'status.json');
|
|
1041
|
+
const ps1 = readJsonOrNull(projectStatus1);
|
|
1042
|
+
if (!exists(projectStatus1) || looksLikeDevSeed(ps1)) {
|
|
1043
|
+
writeJson(projectStatus1, {
|
|
993
1044
|
schemaVersion: 1,
|
|
994
1045
|
client: 'Acme',
|
|
995
1046
|
project: 'Rocket',
|
|
996
1047
|
currentStatus: 'Green — progressing as planned',
|
|
997
|
-
lastUpdated:
|
|
1048
|
+
lastUpdated: daysAgoIso(0),
|
|
998
1049
|
active: true,
|
|
999
1050
|
history: [
|
|
1000
|
-
{ date:
|
|
1001
|
-
{ date:
|
|
1051
|
+
{ date: daysAgoIso(6), type: 'Decision', content: 'Adotar publish via tags vX.Y.Z no GitHub', source: 'dev-seed' },
|
|
1052
|
+
{ date: daysAgoIso(4), type: 'Status', content: 'Painel web MVP subiu localmente (freya web)', source: 'dev-seed' },
|
|
1053
|
+
{ date: daysAgoIso(2), type: 'Risk', content: 'Windows spawn issues ao chamar npx (corrigir)', source: 'dev-seed' },
|
|
1054
|
+
{ date: daysAgoIso(1), type: 'Status', content: 'Correções de compatibilidade Windows + auto-seed', source: 'dev-seed' },
|
|
1055
|
+
{ date: daysAgoIso(0), type: 'Status', content: 'UI redesign inspirado em apps modernos (tema claro + toggle)', source: 'dev-seed' }
|
|
1002
1056
|
]
|
|
1003
|
-
}
|
|
1057
|
+
});
|
|
1004
1058
|
}
|
|
1005
1059
|
|
|
1006
|
-
const
|
|
1007
|
-
|
|
1008
|
-
|
|
1060
|
+
const projectStatus2 = path.join(workspaceDir, 'data', 'Clients', 'vivo', '5g', 'status.json');
|
|
1061
|
+
const ps2 = readJsonOrNull(projectStatus2);
|
|
1062
|
+
if (!exists(projectStatus2) || looksLikeDevSeed(ps2)) {
|
|
1063
|
+
writeJson(projectStatus2, {
|
|
1064
|
+
schemaVersion: 1,
|
|
1065
|
+
client: 'Vivo',
|
|
1066
|
+
project: '5G',
|
|
1067
|
+
currentStatus: 'Amber — dependency on vendor payload format',
|
|
1068
|
+
lastUpdated: daysAgoIso(1),
|
|
1069
|
+
active: true,
|
|
1070
|
+
history: [
|
|
1071
|
+
{ date: daysAgoIso(5), type: 'Status', content: 'Integração inicial concluída; aguardando webhook do Teams', source: 'dev-seed' },
|
|
1072
|
+
{ date: daysAgoIso(3), type: 'Blocker', content: 'Falha intermitente no webhook em ambiente com 2FA', source: 'dev-seed' },
|
|
1073
|
+
{ date: daysAgoIso(1), type: 'Decision', content: 'Implementar chunking e fallback de publish', source: 'dev-seed' }
|
|
1074
|
+
]
|
|
1075
|
+
});
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
// Daily logs: create today and yesterday if missing
|
|
1079
|
+
const today = isoDate();
|
|
1080
|
+
const yesterday = isoDate(new Date(Date.now() - 24 * 60 * 60 * 1000));
|
|
1081
|
+
|
|
1082
|
+
const daily1 = path.join(workspaceDir, 'logs', 'daily', `${yesterday}.md`);
|
|
1083
|
+
if (!exists(daily1)) {
|
|
1084
|
+
fs.writeFileSync(
|
|
1085
|
+
daily1,
|
|
1086
|
+
`# Daily Log ${yesterday}\n\n## [09:10] Raw Input\nHoje preciso melhorar a UX do web e destravar publish no Teams.\n\n## [11:25] Raw Input\nEstou travado no payload do Teams; vou dividir mensagens em chunks.\n\n## [18:05] Raw Input\nTerminei a correção do Windows (spawn) e rodei testes.\n`,
|
|
1087
|
+
'utf8'
|
|
1088
|
+
);
|
|
1089
|
+
}
|
|
1090
|
+
|
|
1091
|
+
const daily2 = path.join(workspaceDir, 'logs', 'daily', `${today}.md`);
|
|
1092
|
+
if (!exists(daily2)) {
|
|
1093
|
+
fs.writeFileSync(
|
|
1094
|
+
daily2,
|
|
1095
|
+
`# Daily Log ${today}\n\n## [09:05] Raw Input\nReunião com Acme: projeto Rocket verde, foco em polish do produto.\n\n## [14:20] Raw Input\nPreciso preparar update executivo e publicar no Discord.\n\n## [17:45] Raw Input\nFechei os blockers críticos e gerei relatório SM semanal.\n`,
|
|
1096
|
+
'utf8'
|
|
1097
|
+
);
|
|
1009
1098
|
}
|
|
1010
1099
|
|
|
1011
1100
|
return {
|
|
1012
1101
|
seeded: true,
|
|
1013
|
-
paths: {
|
|
1102
|
+
paths: {
|
|
1103
|
+
taskLog,
|
|
1104
|
+
careerLog,
|
|
1105
|
+
blockerLog,
|
|
1106
|
+
projectStatus1,
|
|
1107
|
+
projectStatus2,
|
|
1108
|
+
daily1,
|
|
1109
|
+
daily2
|
|
1110
|
+
}
|
|
1014
1111
|
};
|
|
1015
1112
|
}
|
|
1016
1113
|
|