@cccarv82/freya 1.0.28 → 1.0.30
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-ui.js +6 -2
- package/cli/web.js +73 -6
- package/package.json +1 -1
package/cli/web-ui.js
CHANGED
|
@@ -347,7 +347,9 @@
|
|
|
347
347
|
const pri = (t.priority || '').toUpperCase();
|
|
348
348
|
row.innerHTML = '<div style="display:flex; justify-content:space-between; gap:10px; align-items:center">'
|
|
349
349
|
+ '<div style="min-width:0"><div style="font-weight:700">' + escapeHtml(t.description || '') + '</div>'
|
|
350
|
-
+ '<div style="opacity:.7; font-size:11px; margin-top:4px">' + escapeHtml(String(t.category || ''))
|
|
350
|
+
+ '<div style="opacity:.7; font-size:11px; margin-top:4px">' + escapeHtml(String(t.category || ''))
|
|
351
|
+
+ (t.projectSlug ? (' · <span style="font-family:var(--mono); opacity:.9">[' + escapeHtml(String(t.projectSlug)) + ']</span>') : '')
|
|
352
|
+
+ (pri ? (' · ' + escapeHtml(pri)) : '') + '</div></div>'
|
|
351
353
|
+ '<button class="btn small" type="button">Complete</button>'
|
|
352
354
|
+ '</div>';
|
|
353
355
|
const btn = row.querySelector('button');
|
|
@@ -383,7 +385,9 @@
|
|
|
383
385
|
const sev = String(b.severity || '').toUpperCase();
|
|
384
386
|
row.innerHTML = '<div style="display:flex; justify-content:space-between; gap:10px; align-items:center">'
|
|
385
387
|
+ '<div style="min-width:0"><div style="font-weight:800">' + escapeHtml(sev) + '</div>'
|
|
386
|
-
+ '<div style="margin-top:4px">' + escapeHtml(b.title || '')
|
|
388
|
+
+ '<div style="margin-top:4px">' + escapeHtml(b.title || '')
|
|
389
|
+
+ (b.projectSlug ? (' <span style="font-family:var(--mono); opacity:.8">[' + escapeHtml(String(b.projectSlug)) + ']</span>') : '')
|
|
390
|
+
+ '</div>'
|
|
387
391
|
+ '</div>'
|
|
388
392
|
+ '<div style="opacity:.7; font-size:11px; white-space:nowrap">' + escapeHtml(fmtWhen(new Date(b.createdAt || Date.now()).getTime())) + '</div>'
|
|
389
393
|
+ '</div>';
|
package/cli/web.js
CHANGED
|
@@ -91,6 +91,66 @@ function writeSettings(workspaceDir, settings) {
|
|
|
91
91
|
return out;
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
+
function projectSlugMapPath(workspaceDir) {
|
|
95
|
+
return path.join(workspaceDir, 'data', 'settings', 'project-slug-map.json');
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function readProjectSlugMap(workspaceDir) {
|
|
99
|
+
const p = projectSlugMapPath(workspaceDir);
|
|
100
|
+
try {
|
|
101
|
+
if (!exists(p)) {
|
|
102
|
+
ensureDir(path.dirname(p));
|
|
103
|
+
const defaults = {
|
|
104
|
+
schemaVersion: 1,
|
|
105
|
+
updatedAt: new Date().toISOString(),
|
|
106
|
+
rules: [
|
|
107
|
+
{ contains: 'fideliza', slug: 'vivo/fidelizacao' },
|
|
108
|
+
{ contains: 'bnpl', slug: 'vivo/bnpl' },
|
|
109
|
+
{ contains: 'dpgc', slug: 'vivo/bnpl/dpgc' },
|
|
110
|
+
{ contains: 'vivo+', slug: 'vivo/vivoplus' }
|
|
111
|
+
]
|
|
112
|
+
};
|
|
113
|
+
fs.writeFileSync(p, JSON.stringify(defaults, null, 2) + '\n', 'utf8');
|
|
114
|
+
return defaults;
|
|
115
|
+
}
|
|
116
|
+
const json = JSON.parse(fs.readFileSync(p, 'utf8'));
|
|
117
|
+
if (!json || !Array.isArray(json.rules)) return { schemaVersion: 1, rules: [] };
|
|
118
|
+
return json;
|
|
119
|
+
} catch {
|
|
120
|
+
return { schemaVersion: 1, rules: [] };
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function inferProjectSlug(text, map) {
|
|
125
|
+
const t = String(text || '').toLowerCase();
|
|
126
|
+
if (!t.trim()) return '';
|
|
127
|
+
|
|
128
|
+
let base = '';
|
|
129
|
+
const rules = (map && Array.isArray(map.rules)) ? map.rules : [];
|
|
130
|
+
for (const r of rules) {
|
|
131
|
+
if (!r) continue;
|
|
132
|
+
const needle = String(r.contains || '').toLowerCase().trim();
|
|
133
|
+
const slug = String(r.slug || '').trim();
|
|
134
|
+
if (!needle || !slug) continue;
|
|
135
|
+
if (t.includes(needle)) { base = slug; break; }
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// CHG tags
|
|
139
|
+
const chg = (t.match(/\bchg\s*0*\d{4,}\b/i) || [])[0];
|
|
140
|
+
const chgNorm = chg ? chg.toLowerCase().replace(/\s+/g, '') : '';
|
|
141
|
+
|
|
142
|
+
// If no base but looks like Vivo context, at least prefix vivo
|
|
143
|
+
if (!base && (t.includes('vivo') || t.includes('vivo+'))) base = 'vivo';
|
|
144
|
+
|
|
145
|
+
if (base && chgNorm) {
|
|
146
|
+
// keep numeric id
|
|
147
|
+
const id = chgNorm.replace(/[^0-9]/g, '');
|
|
148
|
+
if (id) base = base.replace(/\/+$/g, '') + '/chg' + id;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return base;
|
|
152
|
+
}
|
|
153
|
+
|
|
94
154
|
function listReports(workspaceDir) {
|
|
95
155
|
const dir = path.join(workspaceDir, 'docs', 'reports');
|
|
96
156
|
if (!exists(dir)) return [];
|
|
@@ -1000,8 +1060,8 @@ async function cmdWeb({ port, dir, open, dev }) {
|
|
|
1000
1060
|
const schema = {
|
|
1001
1061
|
actions: [
|
|
1002
1062
|
{ type: 'append_daily_log', text: '<string>' },
|
|
1003
|
-
{ type: 'create_task', description: '<string>', priority: 'HIGH|MEDIUM|LOW', category: 'DO_NOW|SCHEDULE|DELEGATE|IGNORE' },
|
|
1004
|
-
{ type: 'create_blocker', title: '<string>', severity: 'CRITICAL|HIGH|MEDIUM|LOW', notes: '<string>' },
|
|
1063
|
+
{ type: 'create_task', description: '<string>', priority: 'HIGH|MEDIUM|LOW', category: 'DO_NOW|SCHEDULE|DELEGATE|IGNORE', projectSlug: '<string optional>' },
|
|
1064
|
+
{ type: 'create_blocker', title: '<string>', severity: 'CRITICAL|HIGH|MEDIUM|LOW', notes: '<string>', projectSlug: '<string optional>' },
|
|
1005
1065
|
{ type: 'suggest_report', name: 'daily|status|sm-weekly|blockers' },
|
|
1006
1066
|
{ type: 'oracle_query', query: '<string>' }
|
|
1007
1067
|
]
|
|
@@ -1082,7 +1142,8 @@ async function cmdWeb({ port, dir, open, dev }) {
|
|
|
1082
1142
|
const priorityRaw = String(a.priority || '').trim().toLowerCase();
|
|
1083
1143
|
const priority = (priorityRaw === 'high' || priorityRaw === 'medium' || priorityRaw === 'low') ? priorityRaw : undefined;
|
|
1084
1144
|
if (!description) { preview.errors.push('Task missing description'); continue; }
|
|
1085
|
-
|
|
1145
|
+
const projectSlug = String(a.projectSlug || '').trim();
|
|
1146
|
+
preview.tasks.push({ description, category: validTaskCats.has(category) ? category : 'DO_NOW', priority, projectSlug: projectSlug || undefined });
|
|
1086
1147
|
continue;
|
|
1087
1148
|
}
|
|
1088
1149
|
|
|
@@ -1098,7 +1159,8 @@ async function cmdWeb({ port, dir, open, dev }) {
|
|
|
1098
1159
|
else severity = 'MEDIUM';
|
|
1099
1160
|
}
|
|
1100
1161
|
if (!title) { preview.errors.push('Blocker missing title'); continue; }
|
|
1101
|
-
|
|
1162
|
+
const projectSlug = String(a.projectSlug || '').trim();
|
|
1163
|
+
preview.blockers.push({ title, notes, severity, projectSlug: projectSlug || undefined });
|
|
1102
1164
|
continue;
|
|
1103
1165
|
}
|
|
1104
1166
|
|
|
@@ -1220,6 +1282,7 @@ async function cmdWeb({ port, dir, open, dev }) {
|
|
|
1220
1282
|
const now = new Date().toISOString();
|
|
1221
1283
|
const applyMode = String(payload.mode || 'all').trim();
|
|
1222
1284
|
const applied = { tasks: 0, blockers: 0, tasksSkipped: 0, blockersSkipped: 0, reportsSuggested: [], oracleQueries: [], mode: applyMode };
|
|
1285
|
+
const slugMap = readProjectSlugMap(workspaceDir);
|
|
1223
1286
|
|
|
1224
1287
|
function makeId(prefix) {
|
|
1225
1288
|
const rand = Math.random().toString(16).slice(2, 8);
|
|
@@ -1254,7 +1317,8 @@ async function cmdWeb({ port, dir, open, dev }) {
|
|
|
1254
1317
|
if (applyMode !== 'all' && applyMode !== 'tasks') continue;
|
|
1255
1318
|
const description = normalizeWhitespace(a.description);
|
|
1256
1319
|
if (!description) continue;
|
|
1257
|
-
const
|
|
1320
|
+
const projectSlug = String(a.projectSlug || '').trim() || inferProjectSlug(description, slugMap);
|
|
1321
|
+
const key = sha1(normalizeTextForKey((projectSlug ? projectSlug + ' ' : '') + description));
|
|
1258
1322
|
if (existingTaskKeys24h.has(key)) { applied.tasksSkipped++; continue; }
|
|
1259
1323
|
const category = validTaskCats.has(String(a.category || '').trim()) ? String(a.category).trim() : 'DO_NOW';
|
|
1260
1324
|
const priority = normPriority(a.priority);
|
|
@@ -1265,6 +1329,7 @@ async function cmdWeb({ port, dir, open, dev }) {
|
|
|
1265
1329
|
status: 'PENDING',
|
|
1266
1330
|
createdAt: now,
|
|
1267
1331
|
};
|
|
1332
|
+
if (projectSlug) task.projectSlug = projectSlug;
|
|
1268
1333
|
if (priority) task.priority = priority;
|
|
1269
1334
|
taskLog.tasks.push(task);
|
|
1270
1335
|
applied.tasks++;
|
|
@@ -1274,7 +1339,8 @@ async function cmdWeb({ port, dir, open, dev }) {
|
|
|
1274
1339
|
if (type === 'create_blocker') {
|
|
1275
1340
|
if (applyMode !== 'all' && applyMode !== 'blockers') continue;
|
|
1276
1341
|
const title = normalizeWhitespace(a.title);
|
|
1277
|
-
const
|
|
1342
|
+
const projectSlug = String(a.projectSlug || '').trim() || inferProjectSlug(title + ' ' + normalizeWhitespace(a.notes), slugMap);
|
|
1343
|
+
const key = sha1(normalizeTextForKey((projectSlug ? projectSlug + ' ' : '') + title));
|
|
1278
1344
|
if (existingBlockerKeys24h.has(key)) { applied.blockersSkipped++; continue; }
|
|
1279
1345
|
const notes = normalizeWhitespace(a.notes);
|
|
1280
1346
|
if (!title) continue;
|
|
@@ -1287,6 +1353,7 @@ async function cmdWeb({ port, dir, open, dev }) {
|
|
|
1287
1353
|
status: 'OPEN',
|
|
1288
1354
|
severity,
|
|
1289
1355
|
};
|
|
1356
|
+
if (projectSlug) blocker.projectSlug = projectSlug;
|
|
1290
1357
|
blockerLog.blockers.push(blocker);
|
|
1291
1358
|
applied.blockers++;
|
|
1292
1359
|
continue;
|