@lugom.io/hefesto 0.3.0 → 1.0.0
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/agents/hefesto-argos.md +51 -237
- package/agents/hefesto-athena.md +59 -339
- package/agents/hefesto-hermes.md +39 -71
- package/bin/install.js +105 -69
- package/hooks/hefesto-check-update.cjs +32 -11
- package/hooks/hefesto-statusline.cjs +8 -17
- package/hooks/hefesto-workflow.cjs +68 -0
- package/package.json +12 -2
- package/skills/hefesto-context/SKILL.md +59 -26
- package/skills/hefesto-debug/SKILL.md +54 -0
- package/skills/hefesto-design/SKILL.md +133 -143
- package/skills/hefesto-execute/SKILL.md +133 -0
- package/skills/hefesto-init/SKILL.md +94 -59
- package/skills/hefesto-init/references/api.md +116 -0
- package/skills/hefesto-init/references/cli.md +91 -0
- package/skills/hefesto-init/references/mobile.md +69 -0
- package/skills/hefesto-init/references/web.md +246 -0
- package/skills/hefesto-new-feature/SKILL.md +75 -41
- package/skills/hefesto-security/SKILL.md +89 -0
- package/skills/hefesto-security/references/boundaries-and-bypasses.md +152 -0
- package/skills/hefesto-security/references/secrets-detection.md +121 -0
- package/skills/hefesto-security/references/severity-and-judgment.md +176 -0
- package/skills/hefesto-simplify/SKILL.md +82 -0
- package/templates/TPL-CLAUDE.md +54 -0
- package/templates/TPL-CONFIG.json +19 -0
- package/templates/TPL-DESIGN.md +305 -0
- package/templates/{FEATURE.md → TPL-FEATURE.md} +13 -6
- package/templates/TPL-PROJECT.md +50 -0
- package/templates/{RECON.md → TPL-RECON.md} +10 -4
- package/templates/{RESEARCH.md → TPL-RESEARCH.md} +15 -15
- package/templates/TPL-SECURITY.md +42 -0
- package/templates/TPL-SIMPLIFY.md +40 -0
- package/templates/{STATE.md → TPL-STATE.md} +0 -6
- package/templates/TPL-VERDICT.md +34 -0
- package/skills/hefesto-design/data/animations.csv +0 -21
- package/skills/hefesto-design/data/anti-patterns.csv +0 -41
- package/skills/hefesto-design/data/charts.csv +0 -26
- package/skills/hefesto-design/data/colors.csv +0 -108
- package/skills/hefesto-design/data/components.csv +0 -31
- package/skills/hefesto-design/data/google-fonts.csv +0 -56
- package/skills/hefesto-design/data/icons.csv +0 -23
- package/skills/hefesto-design/data/landing-pages.csv +0 -28
- package/skills/hefesto-design/data/products.csv +0 -46
- package/skills/hefesto-design/data/spacing.csv +0 -16
- package/skills/hefesto-design/data/styles.csv +0 -53
- package/skills/hefesto-design/data/typography.csv +0 -41
- package/skills/hefesto-design/data/ux-rules.csv +0 -61
- package/skills/hefesto-design/references/accessibility.md +0 -335
- package/skills/hefesto-design/references/aesthetics.md +0 -343
- package/skills/hefesto-design/references/anti-patterns.md +0 -107
- package/skills/hefesto-design/references/checklist.md +0 -66
- package/skills/hefesto-design/references/color-psychology.md +0 -203
- package/skills/hefesto-design/references/component-specs.md +0 -318
- package/skills/hefesto-design/references/polish.md +0 -339
- package/skills/hefesto-design/references/token-architecture.md +0 -394
- package/skills/hefesto-design/references/ux-rules.md +0 -349
- package/skills/hefesto-design/scripts/__pycache__/audit.cpython-314.pyc +0 -0
- package/skills/hefesto-design/scripts/__pycache__/contrast.cpython-314.pyc +0 -0
- package/skills/hefesto-design/scripts/__pycache__/core.cpython-314.pyc +0 -0
- package/skills/hefesto-design/scripts/__pycache__/design_system.cpython-314.pyc +0 -0
- package/skills/hefesto-design/scripts/__pycache__/search.cpython-314.pyc +0 -0
- package/skills/hefesto-design/scripts/__pycache__/validate_tokens.cpython-314.pyc +0 -0
- package/skills/hefesto-design/scripts/audit.py +0 -450
- package/skills/hefesto-design/scripts/contrast.py +0 -195
- package/skills/hefesto-design/scripts/core.py +0 -155
- package/skills/hefesto-design/scripts/design_system.py +0 -311
- package/skills/hefesto-design/scripts/search.py +0 -235
- package/skills/hefesto-design/scripts/validate_tokens.py +0 -274
- package/skills/hefesto-update/SKILL.md +0 -34
- package/templates/DESIGN.md +0 -137
- package/templates/PROJECT.md +0 -28
- package/templates/ROADMAP.md +0 -23
- package/templates/VERDICT.md +0 -52
package/bin/install.js
CHANGED
|
@@ -20,14 +20,19 @@ const red = '\x1b[31m';
|
|
|
20
20
|
const dim = '\x1b[2m';
|
|
21
21
|
const reset = '\x1b[0m';
|
|
22
22
|
|
|
23
|
-
const banner =
|
|
24
|
-
|
|
23
|
+
const banner =
|
|
24
|
+
'\n' +
|
|
25
|
+
red +
|
|
26
|
+
' ██╗ ██╗███████╗███████╗███████╗███████╗████████╗ ██████╗\n' +
|
|
25
27
|
' ██║ ██║██╔════╝██╔════╝██╔════╝██╔════╝╚══██╔══╝██╔═══██╗\n' +
|
|
26
28
|
' ███████║█████╗ █████╗ █████╗ ███████╗ ██║ ██║ ██║\n' +
|
|
27
29
|
' ██╔══██║██╔══╝ ██╔══╝ ██╔══╝ ╚════██║ ██║ ██║ ██║\n' +
|
|
28
30
|
' ██║ ██║███████╗██║ ███████╗███████║ ██║ ╚██████╔╝\n' +
|
|
29
|
-
' ╚═╝ ╚═╝╚══════╝╚═╝ ╚══════╝╚══════╝ ╚═╝ ╚═════╝\n' +
|
|
30
|
-
|
|
31
|
+
' ╚═╝ ╚═╝╚══════╝╚═╝ ╚══════╝╚══════╝ ╚═╝ ╚═════╝\n' +
|
|
32
|
+
reset +
|
|
33
|
+
dim +
|
|
34
|
+
' Toolkit spec-driven + story-driven para agentes AI\n' +
|
|
35
|
+
reset;
|
|
31
36
|
|
|
32
37
|
// ── CLI Args ────────────────────────────────────────────────────────────────
|
|
33
38
|
|
|
@@ -41,6 +46,25 @@ const hasGemini = args.includes('--gemini');
|
|
|
41
46
|
const hasCodex = args.includes('--codex');
|
|
42
47
|
const hasAll = args.includes('--all');
|
|
43
48
|
|
|
49
|
+
const knownArgs = new Set([
|
|
50
|
+
'--global',
|
|
51
|
+
'-g',
|
|
52
|
+
'--uninstall',
|
|
53
|
+
'-u',
|
|
54
|
+
'--help',
|
|
55
|
+
'-h',
|
|
56
|
+
'--claude',
|
|
57
|
+
'--gemini',
|
|
58
|
+
'--codex',
|
|
59
|
+
'--all',
|
|
60
|
+
]);
|
|
61
|
+
const unknownArgs = args.filter((a) => a.startsWith('-') && !knownArgs.has(a));
|
|
62
|
+
if (unknownArgs.length > 0) {
|
|
63
|
+
console.warn(
|
|
64
|
+
`⚠ Opção desconhecida: ${unknownArgs.join(', ')}. Use --help para ver opções válidas.`
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
44
68
|
// ── Help ────────────────────────────────────────────────────────────────────
|
|
45
69
|
|
|
46
70
|
if (hasHelp) {
|
|
@@ -144,14 +168,12 @@ function removeIfExists(targetPath) {
|
|
|
144
168
|
// ── Default Config ──────────────────────────────────────────────────────────
|
|
145
169
|
|
|
146
170
|
function createDefaultConfig() {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
lifecycle: { auto_update_state: true },
|
|
154
|
-
};
|
|
171
|
+
const templatePath = path.join(PKG_ROOT, 'templates', 'TPL-CONFIG.json');
|
|
172
|
+
const template = JSON.parse(fs.readFileSync(templatePath, 'utf8'));
|
|
173
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(PKG_ROOT, 'package.json'), 'utf8'));
|
|
174
|
+
// --all: getSelectedRuntimes()[0] é 'claude' (runtime primário).
|
|
175
|
+
// Config armazena apenas o primário; todos os runtimes recebem os arquivos instalados.
|
|
176
|
+
return { ...template, version: pkg.version, runtime: getSelectedRuntimes()[0] || 'claude' };
|
|
155
177
|
}
|
|
156
178
|
|
|
157
179
|
// ── Install ─────────────────────────────────────────────────────────────────
|
|
@@ -172,12 +194,15 @@ function installHefesto() {
|
|
|
172
194
|
ensureDir(path.join(hefestoDir, 'research'));
|
|
173
195
|
|
|
174
196
|
// Copiar templates como arquivos iniciais do projeto
|
|
175
|
-
const templateFiles = [
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
197
|
+
const templateFiles = [
|
|
198
|
+
{ src: 'TPL-PROJECT.md', dest: 'PROJECT.md' },
|
|
199
|
+
{ src: 'TPL-STATE.md', dest: 'STATE.md' },
|
|
200
|
+
];
|
|
201
|
+
for (const { src, dest } of templateFiles) {
|
|
202
|
+
const srcPath = path.join(templatesDir, src);
|
|
203
|
+
const destPath = path.join(hefestoDir, dest);
|
|
204
|
+
if (fs.existsSync(srcPath)) {
|
|
205
|
+
fs.copyFileSync(srcPath, destPath);
|
|
181
206
|
}
|
|
182
207
|
}
|
|
183
208
|
|
|
@@ -187,7 +212,7 @@ function installHefesto() {
|
|
|
187
212
|
// Criar config.json
|
|
188
213
|
fs.writeFileSync(
|
|
189
214
|
path.join(hefestoDir, 'config.json'),
|
|
190
|
-
JSON.stringify(createDefaultConfig(), null, 2) + '\n'
|
|
215
|
+
JSON.stringify(createDefaultConfig(), null, 2) + '\n'
|
|
191
216
|
);
|
|
192
217
|
|
|
193
218
|
console.log(` ✅ .hefesto/ criado com scaffold do projeto.`);
|
|
@@ -210,9 +235,11 @@ function installRuntime(runtime) {
|
|
|
210
235
|
// Skills
|
|
211
236
|
const srcSkills = path.join(PKG_ROOT, 'skills');
|
|
212
237
|
if (fs.existsSync(srcSkills)) {
|
|
213
|
-
const destSkills = getSkillsDestDir(
|
|
238
|
+
const destSkills = getSkillsDestDir(runtimeDir);
|
|
214
239
|
copySkills(srcSkills, destSkills);
|
|
215
|
-
console.log(
|
|
240
|
+
console.log(
|
|
241
|
+
` ✅ Skills instaladas em ${path.relative(process.cwd(), destSkills) || destSkills}`
|
|
242
|
+
);
|
|
216
243
|
}
|
|
217
244
|
|
|
218
245
|
// Agents
|
|
@@ -220,18 +247,17 @@ function installRuntime(runtime) {
|
|
|
220
247
|
if (fs.existsSync(srcAgents)) {
|
|
221
248
|
const destAgents = path.join(runtimeDir, 'agents');
|
|
222
249
|
copyAgents(srcAgents, destAgents);
|
|
223
|
-
console.log(
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
// Agent memory directories (apenas Claude Code)
|
|
227
|
-
if (runtime === 'claude') {
|
|
228
|
-
installAgentMemory(runtimeDir);
|
|
250
|
+
console.log(
|
|
251
|
+
` ✅ Agents instalados em ${path.relative(process.cwd(), destAgents) || destAgents}`
|
|
252
|
+
);
|
|
229
253
|
}
|
|
230
254
|
|
|
231
255
|
// Cleanup: remove legacy commands (migrated to skills)
|
|
232
256
|
const legacyCmds = path.join(runtimeDir, 'commands', 'hefesto');
|
|
233
257
|
if (removeIfExists(legacyCmds)) {
|
|
234
|
-
console.log(
|
|
258
|
+
console.log(
|
|
259
|
+
` ♻️ Commands legados removidos de ${path.relative(process.cwd(), legacyCmds) || legacyCmds}`
|
|
260
|
+
);
|
|
235
261
|
const cmdsParent = path.join(runtimeDir, 'commands');
|
|
236
262
|
if (fs.existsSync(cmdsParent) && fs.readdirSync(cmdsParent).length === 0) {
|
|
237
263
|
fs.rmSync(cmdsParent, { recursive: true });
|
|
@@ -244,7 +270,7 @@ function installRuntime(runtime) {
|
|
|
244
270
|
}
|
|
245
271
|
}
|
|
246
272
|
|
|
247
|
-
function getSkillsDestDir(
|
|
273
|
+
function getSkillsDestDir(runtimeDir) {
|
|
248
274
|
// Claude: .claude/skills/
|
|
249
275
|
// Gemini: .gemini/skills/
|
|
250
276
|
// Codex: .codex/skills/
|
|
@@ -279,18 +305,6 @@ function copyAgents(srcDir, destDir) {
|
|
|
279
305
|
}
|
|
280
306
|
}
|
|
281
307
|
|
|
282
|
-
// ── Agent Memory ─────────────────────────────────────────────────────────────
|
|
283
|
-
|
|
284
|
-
function installAgentMemory(runtimeDir) {
|
|
285
|
-
const agentMemoryDir = path.join(runtimeDir, 'agent-memory');
|
|
286
|
-
const agentNames = ['hefesto-athena', 'hefesto-argos'];
|
|
287
|
-
|
|
288
|
-
for (const name of agentNames) {
|
|
289
|
-
ensureDir(path.join(agentMemoryDir, name));
|
|
290
|
-
}
|
|
291
|
-
console.log(` ✅ Agent memory criado em ${path.relative(process.cwd(), agentMemoryDir) || agentMemoryDir}`);
|
|
292
|
-
}
|
|
293
|
-
|
|
294
308
|
// ── Hooks ───────────────────────────────────────────────────────────────────
|
|
295
309
|
|
|
296
310
|
function installHooks(runtimeDir) {
|
|
@@ -299,7 +313,11 @@ function installHooks(runtimeDir) {
|
|
|
299
313
|
|
|
300
314
|
// Copiar hooks
|
|
301
315
|
ensureDir(destHooks);
|
|
302
|
-
for (const file of [
|
|
316
|
+
for (const file of [
|
|
317
|
+
'hefesto-statusline.cjs',
|
|
318
|
+
'hefesto-check-update.cjs',
|
|
319
|
+
'hefesto-workflow.cjs',
|
|
320
|
+
]) {
|
|
303
321
|
const src = path.join(srcHooks, file);
|
|
304
322
|
if (fs.existsSync(src)) {
|
|
305
323
|
fs.copyFileSync(src, path.join(destHooks, file));
|
|
@@ -332,15 +350,35 @@ function installHooks(runtimeDir) {
|
|
|
332
350
|
|
|
333
351
|
// Remover hook hefesto anterior se existir
|
|
334
352
|
settings.hooks.SessionStart = settings.hooks.SessionStart.filter(
|
|
335
|
-
h => !JSON.stringify(h).includes('hefesto-check-update')
|
|
353
|
+
(h) => !JSON.stringify(h).includes('hefesto-check-update')
|
|
336
354
|
);
|
|
337
355
|
|
|
338
356
|
settings.hooks.SessionStart.push({
|
|
339
357
|
matcher: 'startup',
|
|
340
|
-
hooks: [
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
358
|
+
hooks: [
|
|
359
|
+
{
|
|
360
|
+
type: 'command',
|
|
361
|
+
command: checkUpdateCmd,
|
|
362
|
+
},
|
|
363
|
+
],
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
// PreToolUse hook (workflow enforcement)
|
|
367
|
+
if (!settings.hooks.PreToolUse) settings.hooks.PreToolUse = [];
|
|
368
|
+
|
|
369
|
+
// Remover hook hefesto-workflow anterior se existir
|
|
370
|
+
settings.hooks.PreToolUse = settings.hooks.PreToolUse.filter(
|
|
371
|
+
(h) => !JSON.stringify(h).includes('hefesto-workflow')
|
|
372
|
+
);
|
|
373
|
+
|
|
374
|
+
settings.hooks.PreToolUse.push({
|
|
375
|
+
matcher: 'Write|Edit',
|
|
376
|
+
hooks: [
|
|
377
|
+
{
|
|
378
|
+
type: 'command',
|
|
379
|
+
command: `node "${hooksDir}/hefesto-workflow.cjs"`,
|
|
380
|
+
},
|
|
381
|
+
],
|
|
344
382
|
});
|
|
345
383
|
|
|
346
384
|
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\n');
|
|
@@ -350,7 +388,11 @@ function installHooks(runtimeDir) {
|
|
|
350
388
|
function uninstallHooks(runtimeDir) {
|
|
351
389
|
// Remover arquivos de hooks
|
|
352
390
|
const hooksDir = path.join(runtimeDir, 'hooks');
|
|
353
|
-
for (const file of [
|
|
391
|
+
for (const file of [
|
|
392
|
+
'hefesto-statusline.cjs',
|
|
393
|
+
'hefesto-check-update.cjs',
|
|
394
|
+
'hefesto-workflow.cjs',
|
|
395
|
+
]) {
|
|
354
396
|
const hookPath = path.join(hooksDir, file);
|
|
355
397
|
if (fs.existsSync(hookPath)) {
|
|
356
398
|
fs.unlinkSync(hookPath);
|
|
@@ -372,13 +414,23 @@ function uninstallHooks(runtimeDir) {
|
|
|
372
414
|
// Remover hook de SessionStart do hefesto
|
|
373
415
|
if (settings.hooks?.SessionStart) {
|
|
374
416
|
settings.hooks.SessionStart = settings.hooks.SessionStart.filter(
|
|
375
|
-
h => !JSON.stringify(h).includes('hefesto-check-update')
|
|
417
|
+
(h) => !JSON.stringify(h).includes('hefesto-check-update')
|
|
376
418
|
);
|
|
377
419
|
if (settings.hooks.SessionStart.length === 0) {
|
|
378
420
|
delete settings.hooks.SessionStart;
|
|
379
421
|
}
|
|
380
422
|
}
|
|
381
423
|
|
|
424
|
+
// Remover hook de PreToolUse do hefesto
|
|
425
|
+
if (settings.hooks?.PreToolUse) {
|
|
426
|
+
settings.hooks.PreToolUse = settings.hooks.PreToolUse.filter(
|
|
427
|
+
(h) => !JSON.stringify(h).includes('hefesto-workflow')
|
|
428
|
+
);
|
|
429
|
+
if (settings.hooks.PreToolUse.length === 0) {
|
|
430
|
+
delete settings.hooks.PreToolUse;
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
|
|
382
434
|
// Limpar hooks vazio
|
|
383
435
|
if (settings.hooks && Object.keys(settings.hooks).length === 0) {
|
|
384
436
|
delete settings.hooks;
|
|
@@ -418,7 +470,9 @@ function uninstallRuntime(runtime) {
|
|
|
418
470
|
// Remover legacy commands/hefesto/ (se existir de versão anterior)
|
|
419
471
|
const commandsDir = path.join(runtimeDir, 'commands', 'hefesto');
|
|
420
472
|
if (removeIfExists(commandsDir)) {
|
|
421
|
-
console.log(
|
|
473
|
+
console.log(
|
|
474
|
+
` ✅ Commands legados removidos de ${path.relative(process.cwd(), commandsDir) || commandsDir}`
|
|
475
|
+
);
|
|
422
476
|
const cmdsParent = path.join(runtimeDir, 'commands');
|
|
423
477
|
if (fs.existsSync(cmdsParent) && fs.readdirSync(cmdsParent).length === 0) {
|
|
424
478
|
fs.rmSync(cmdsParent, { recursive: true });
|
|
@@ -426,7 +480,7 @@ function uninstallRuntime(runtime) {
|
|
|
426
480
|
}
|
|
427
481
|
|
|
428
482
|
// Remover skills hefesto-*
|
|
429
|
-
const skillsDir = getSkillsDestDir(
|
|
483
|
+
const skillsDir = getSkillsDestDir(runtimeDir);
|
|
430
484
|
if (fs.existsSync(skillsDir)) {
|
|
431
485
|
const entries = fs.readdirSync(skillsDir, { withFileTypes: true });
|
|
432
486
|
for (const entry of entries) {
|
|
@@ -454,24 +508,6 @@ function uninstallRuntime(runtime) {
|
|
|
454
508
|
}
|
|
455
509
|
}
|
|
456
510
|
|
|
457
|
-
// Remover agent-memory hefesto-* (apenas Claude Code)
|
|
458
|
-
if (runtime === 'claude') {
|
|
459
|
-
const agentMemoryDir = path.join(runtimeDir, 'agent-memory');
|
|
460
|
-
if (fs.existsSync(agentMemoryDir)) {
|
|
461
|
-
const memEntries = fs.readdirSync(agentMemoryDir, { withFileTypes: true });
|
|
462
|
-
for (const entry of memEntries) {
|
|
463
|
-
if (entry.isDirectory() && entry.name.startsWith('hefesto-')) {
|
|
464
|
-
fs.rmSync(path.join(agentMemoryDir, entry.name), { recursive: true });
|
|
465
|
-
console.log(` ✅ Agent memory ${entry.name} removido.`);
|
|
466
|
-
}
|
|
467
|
-
}
|
|
468
|
-
// Remove agent-memory/ se vazio
|
|
469
|
-
if (fs.readdirSync(agentMemoryDir).length === 0) {
|
|
470
|
-
fs.rmSync(agentMemoryDir, { recursive: true });
|
|
471
|
-
}
|
|
472
|
-
}
|
|
473
|
-
}
|
|
474
|
-
|
|
475
511
|
// Remover hooks (apenas Claude Code)
|
|
476
512
|
if (runtime === 'claude') {
|
|
477
513
|
uninstallHooks(runtimeDir);
|
|
@@ -7,6 +7,10 @@ const path = require('path');
|
|
|
7
7
|
const os = require('os');
|
|
8
8
|
const { spawn } = require('child_process');
|
|
9
9
|
|
|
10
|
+
// Drain stdin (hook runner pode enviar dados)
|
|
11
|
+
process.stdin.resume();
|
|
12
|
+
process.stdin.on('data', () => {});
|
|
13
|
+
|
|
10
14
|
const configDir = process.env.CLAUDE_CONFIG_DIR || path.join(os.homedir(), '.claude');
|
|
11
15
|
const cacheDir = path.join(configDir, 'cache');
|
|
12
16
|
const cacheFile = path.join(cacheDir, 'hefesto-update-check.json');
|
|
@@ -17,44 +21,61 @@ if (!fs.existsSync(cacheDir)) {
|
|
|
17
21
|
}
|
|
18
22
|
|
|
19
23
|
// Rodar check em background (não bloqueia a sessão)
|
|
20
|
-
const child = spawn(
|
|
24
|
+
const child = spawn(
|
|
25
|
+
process.execPath,
|
|
26
|
+
[
|
|
27
|
+
'-e',
|
|
28
|
+
`
|
|
21
29
|
const fs = require('fs');
|
|
22
30
|
const { execSync } = require('child_process');
|
|
23
31
|
const cacheFile = ${JSON.stringify(cacheFile)};
|
|
24
32
|
|
|
25
33
|
let installed = '0.0.0';
|
|
26
34
|
try {
|
|
27
|
-
const pkg = JSON.parse(execSync('npm ls hefesto --json 2>/dev/null', {
|
|
35
|
+
const pkg = JSON.parse(execSync('npm ls @lugom.io/hefesto --json 2>/dev/null', {
|
|
28
36
|
encoding: 'utf8', timeout: 10000, windowsHide: true
|
|
29
37
|
}));
|
|
30
|
-
installed = pkg.dependencies?.hefesto?.version || '0.0.0';
|
|
38
|
+
installed = pkg.dependencies?.['@lugom.io/hefesto']?.version || '0.0.0';
|
|
31
39
|
} catch (_) {
|
|
32
40
|
// Se não conseguir detectar versão instalada, tentar package.json local
|
|
33
41
|
try {
|
|
34
|
-
const localPkg = JSON.parse(fs.readFileSync('node_modules/hefesto/package.json', 'utf8'));
|
|
42
|
+
const localPkg = JSON.parse(fs.readFileSync('node_modules/@lugom.io/hefesto/package.json', 'utf8'));
|
|
35
43
|
installed = localPkg.version || '0.0.0';
|
|
36
44
|
} catch (_) {}
|
|
37
45
|
}
|
|
38
46
|
|
|
39
47
|
let latest = null;
|
|
40
48
|
try {
|
|
41
|
-
latest = execSync('npm view hefesto version', {
|
|
49
|
+
latest = execSync('npm view @lugom.io/hefesto version', {
|
|
42
50
|
encoding: 'utf8', timeout: 10000, windowsHide: true
|
|
43
51
|
}).trim();
|
|
44
52
|
} catch (_) {}
|
|
45
53
|
|
|
54
|
+
function semverLt(a, b) {
|
|
55
|
+
const pa = a.split('.').map(s => parseInt(s, 10) || 0);
|
|
56
|
+
const pb = b.split('.').map(s => parseInt(s, 10) || 0);
|
|
57
|
+
for (let i = 0; i < 3; i++) {
|
|
58
|
+
if ((pa[i] || 0) < (pb[i] || 0)) return true;
|
|
59
|
+
if ((pa[i] || 0) > (pb[i] || 0)) return false;
|
|
60
|
+
}
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
|
|
46
64
|
const result = {
|
|
47
|
-
update_available: latest &&
|
|
65
|
+
update_available: latest && latest !== '0.0.0' && installed !== latest && semverLt(installed, latest),
|
|
48
66
|
installed,
|
|
49
67
|
latest: latest || 'unknown',
|
|
50
68
|
checked: Math.floor(Date.now() / 1000),
|
|
51
69
|
};
|
|
52
70
|
|
|
53
71
|
fs.writeFileSync(cacheFile, JSON.stringify(result));
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
72
|
+
`,
|
|
73
|
+
],
|
|
74
|
+
{
|
|
75
|
+
stdio: 'ignore',
|
|
76
|
+
windowsHide: true,
|
|
77
|
+
detached: true,
|
|
78
|
+
}
|
|
79
|
+
);
|
|
59
80
|
|
|
60
81
|
child.unref();
|
|
@@ -9,36 +9,25 @@ const os = require('os');
|
|
|
9
9
|
let input = '';
|
|
10
10
|
const stdinTimeout = setTimeout(() => process.exit(0), 3000);
|
|
11
11
|
process.stdin.setEncoding('utf8');
|
|
12
|
-
process.stdin.on('data', chunk => input += chunk);
|
|
12
|
+
process.stdin.on('data', (chunk) => (input += chunk));
|
|
13
13
|
process.stdin.on('end', () => {
|
|
14
14
|
clearTimeout(stdinTimeout);
|
|
15
15
|
try {
|
|
16
16
|
const data = JSON.parse(input);
|
|
17
17
|
const model = data.model?.display_name || 'Claude';
|
|
18
18
|
const dir = data.workspace?.current_dir || process.cwd();
|
|
19
|
-
const session = data.session_id || '';
|
|
20
19
|
const remaining = data.context_window?.remaining_percentage;
|
|
21
20
|
|
|
22
21
|
// Context window (normalizado para contexto utilizável)
|
|
23
22
|
const AUTO_COMPACT_BUFFER_PCT = 16.5;
|
|
24
23
|
let ctx = '';
|
|
25
24
|
if (remaining != null) {
|
|
26
|
-
const usableRemaining = Math.max(
|
|
25
|
+
const usableRemaining = Math.max(
|
|
26
|
+
0,
|
|
27
|
+
((remaining - AUTO_COMPACT_BUFFER_PCT) / (100 - AUTO_COMPACT_BUFFER_PCT)) * 100
|
|
28
|
+
);
|
|
27
29
|
const used = Math.max(0, Math.min(100, Math.round(100 - usableRemaining)));
|
|
28
30
|
|
|
29
|
-
// Bridge file para o context-monitor
|
|
30
|
-
if (session) {
|
|
31
|
-
try {
|
|
32
|
-
const bridgePath = path.join(os.tmpdir(), `hefesto-ctx-${session}.json`);
|
|
33
|
-
fs.writeFileSync(bridgePath, JSON.stringify({
|
|
34
|
-
session_id: session,
|
|
35
|
-
remaining_percentage: remaining,
|
|
36
|
-
used_pct: used,
|
|
37
|
-
timestamp: Math.floor(Date.now() / 1000),
|
|
38
|
-
}));
|
|
39
|
-
} catch (_) {}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
31
|
// Barra de progresso (10 segmentos)
|
|
43
32
|
const filled = Math.floor(used / 10);
|
|
44
33
|
const bar = '█'.repeat(filled) + '░'.repeat(10 - filled);
|
|
@@ -68,7 +57,9 @@ process.stdin.on('end', () => {
|
|
|
68
57
|
}
|
|
69
58
|
|
|
70
59
|
const dirname = path.basename(dir);
|
|
71
|
-
process.stdout.write(
|
|
60
|
+
process.stdout.write(
|
|
61
|
+
`${updateMsg}\x1b[1;31m⚒ HEFESTO\x1b[0m │ \x1b[2m${model}\x1b[0m │ \x1b[2m${dirname}\x1b[0m${ctx}`
|
|
62
|
+
);
|
|
72
63
|
} catch (_) {
|
|
73
64
|
// Falha silenciosa
|
|
74
65
|
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Hefesto Workflow Enforcement
|
|
3
|
+
// PreToolUse hook: avisa quando Write/Edit é usado sem feature ativa
|
|
4
|
+
// Comportamento: WARN only, nunca BLOCK — Hefesto guia, não bloqueia
|
|
5
|
+
|
|
6
|
+
const fs = require('node:fs');
|
|
7
|
+
const path = require('node:path');
|
|
8
|
+
|
|
9
|
+
let input = '';
|
|
10
|
+
const stdinTimeout = setTimeout(() => process.exit(0), 3000);
|
|
11
|
+
|
|
12
|
+
process.stdin.setEncoding('utf8');
|
|
13
|
+
process.stdin.on('data', (chunk) => (input += chunk));
|
|
14
|
+
process.stdin.on('end', () => {
|
|
15
|
+
clearTimeout(stdinTimeout);
|
|
16
|
+
try {
|
|
17
|
+
const data = JSON.parse(input);
|
|
18
|
+
const toolName = data.tool_name;
|
|
19
|
+
const filePath = data.tool_input?.file_path || data.tool_input?.path || '';
|
|
20
|
+
|
|
21
|
+
// Só verificar Write e Edit
|
|
22
|
+
if (toolName !== 'Write' && toolName !== 'Edit') return;
|
|
23
|
+
|
|
24
|
+
// Se não tem file_path, não tem como verificar
|
|
25
|
+
if (!filePath) return;
|
|
26
|
+
|
|
27
|
+
const basename = path.basename(filePath);
|
|
28
|
+
const normalized = filePath.replace(/\\/g, '/');
|
|
29
|
+
|
|
30
|
+
// Escape hatches — sempre permitir:
|
|
31
|
+
// .hefesto/ (state files do próprio Hefesto)
|
|
32
|
+
if (normalized.includes('.hefesto/')) return;
|
|
33
|
+
// Configs de runtime (.claude/, .gemini/, .codex/)
|
|
34
|
+
if (
|
|
35
|
+
normalized.includes('.claude/') ||
|
|
36
|
+
normalized.includes('.gemini/') ||
|
|
37
|
+
normalized.includes('.codex/')
|
|
38
|
+
)
|
|
39
|
+
return;
|
|
40
|
+
// Testes (test, spec, __tests__)
|
|
41
|
+
if (/test|spec|__tests__/i.test(normalized)) return;
|
|
42
|
+
// Dotfiles e package.json
|
|
43
|
+
if (basename.startsWith('.') || basename === 'package.json' || basename === 'package-lock.json')
|
|
44
|
+
return;
|
|
45
|
+
// Markdown docs
|
|
46
|
+
if (basename.endsWith('.md')) return;
|
|
47
|
+
|
|
48
|
+
// Verificar se .hefesto/STATE.md existe
|
|
49
|
+
const statePath = path.join(process.cwd(), '.hefesto', 'STATE.md');
|
|
50
|
+
if (!fs.existsSync(statePath)) return;
|
|
51
|
+
|
|
52
|
+
// Ler STATE.md e checar se tem feature ativa
|
|
53
|
+
const state = fs.readFileSync(statePath, 'utf8');
|
|
54
|
+
const featureSection = state.match(/## Feature Ativa\s*\n([\s\S]*?)(?=\n## |\n---|$)/);
|
|
55
|
+
|
|
56
|
+
if (!featureSection) return;
|
|
57
|
+
|
|
58
|
+
const content = featureSection[1].trim();
|
|
59
|
+
if (content && content !== 'Nenhuma.' && content !== 'Nenhuma') return;
|
|
60
|
+
|
|
61
|
+
// Sem feature ativa — emitir warning via stderr
|
|
62
|
+
process.stderr.write(
|
|
63
|
+
'\n⚒ HEFESTO: Nenhuma feature ativa. Considere usar /hefesto-new-feature antes de implementar.\n'
|
|
64
|
+
);
|
|
65
|
+
} catch (_) {
|
|
66
|
+
// Silent failure — nunca quebrar o runtime
|
|
67
|
+
}
|
|
68
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lugom.io/hefesto",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "A meta-prompting, context engineering and spec-driven development system for Claude Code, Gemini and Codex by lugom.io.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -8,6 +8,10 @@
|
|
|
8
8
|
},
|
|
9
9
|
"scripts": {
|
|
10
10
|
"test": "node --test tests/**/*.test.js",
|
|
11
|
+
"lint": "eslint bin/ hooks/ tests/",
|
|
12
|
+
"lint:fix": "eslint bin/ hooks/ tests/ --fix",
|
|
13
|
+
"format": "prettier --write .",
|
|
14
|
+
"format:check": "prettier --check .",
|
|
11
15
|
"sandbox": "HEFESTO=$PWD && mkdir -p $HEFESTO/tmp/hefesto-sandbox/src && cd $HEFESTO/tmp/hefesto-sandbox && test -f package.json || echo '{\"name\":\"sandbox\",\"type\":\"module\"}' > package.json && node $HEFESTO/bin/install.js && claude"
|
|
12
16
|
},
|
|
13
17
|
"engines": {
|
|
@@ -33,5 +37,11 @@
|
|
|
33
37
|
"codex-cli"
|
|
34
38
|
],
|
|
35
39
|
"author": "lugom.io",
|
|
36
|
-
"license": "MIT"
|
|
40
|
+
"license": "MIT",
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"@eslint/js": "^10.0.1",
|
|
43
|
+
"eslint": "^10.1.0",
|
|
44
|
+
"eslint-config-prettier": "^10.1.8",
|
|
45
|
+
"prettier": "^3.8.1"
|
|
46
|
+
}
|
|
37
47
|
}
|