altis-claude-harness 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/README.md +0 -0
- package/bin/cli.js +158 -0
- package/lib/manifest.js +30 -0
- package/lib/remote.js +25 -0
- package/lib/settings.js +72 -0
- package/lib/sync.js +58 -0
- package/package.json +23 -0
- package/payload/agents/altis-analise-negocios-agent.md +214 -0
- package/payload/agents/altis-angular-agent.md +126 -0
- package/payload/agents/altis-bootstrap5-agent.md +168 -0
- package/payload/agents/altis-code-reviewer-agent.md +239 -0
- package/payload/agents/altis-delphi-agent.md +102 -0
- package/payload/agents/altis-delphi-firemonkey-agent.md +88 -0
- package/payload/agents/altis-doc-agent.md +63 -0
- package/payload/agents/altis-electron-agent.md +54 -0
- package/payload/agents/altis-fiscal-agent.md +78 -0
- package/payload/agents/altis-impact-analyzer-agent.md +214 -0
- package/payload/agents/altis-integracoes-agent.md +85 -0
- package/payload/agents/altis-oracle-agent.md +110 -0
- package/payload/agents/altis-postgresql-agent.md +103 -0
- package/payload/agents/altis-python-agent.md +75 -0
- package/payload/agents/altis-reactnative-agent.md +60 -0
- package/payload/agents/altis-spring-agent.md +64 -0
- package/payload/agents/altis-sql-dml-agent.md +195 -0
- package/payload/commands/altis-bugfix.md +739 -0
- package/payload/commands/altis-comandos-update.md +232 -0
- package/payload/commands/altis-feature.md +633 -0
- package/payload/hooks/auto_update.cjs +142 -0
- package/payload/hooks/check_delphi_encoding.py +72 -0
- package/payload/hooks/delphi_guard.py +80 -0
- package/payload/hooks/liberacoes.json +6 -0
- package/payload/hooks/license_guard.cjs +153 -0
- package/payload/rules/altis-sql-dml-rule.md +101 -0
- package/payload/rules/angular_rules.md +44 -0
- package/payload/rules/delphi_chamada_procedure_rule.md +81 -0
- package/payload/rules/delphi_encoding_rule.md +93 -0
- package/payload/rules/delphi_transacao_form_rule.md +52 -0
- package/payload/rules/oracle_rule.md +158 -0
- package/payload/rules/springboot_rules.md +86 -0
- package/payload/settings-fragment.json +69 -0
- package/payload/skills/angular_esp/SKILL.md +1086 -0
- package/payload/skills/bootstrap5_esp/SKILL.md +1555 -0
- package/payload/skills/delphi_esp/SKILL.md +1005 -0
- package/payload/skills/electronjs_esp/SKILL.md +951 -0
- package/payload/skills/firemonkey_esp/SKILL.md +229 -0
- package/payload/skills/java_spring_skill/SKILL.md +853 -0
- package/payload/skills/oracle_esp/SKILL.md +1124 -0
- package/payload/skills/padrao_doc_altisw/SKILL.md +1218 -0
- package/payload/skills/padrao_doc_claude/SKILL.md +1005 -0
- package/payload/skills/padrao_doc_rotinas/SKILL.md +931 -0
- package/payload/skills/postgreSQL_esp/SKILL.md +334 -0
- package/payload/skills/python_esp/SKILL.md +163 -0
- package/payload/skills/reactnative_esp/SKILL.md +1713 -0
package/README.md
ADDED
|
Binary file
|
package/bin/cli.js
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const os = require('os');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
const { execFileSync } = require('child_process');
|
|
7
|
+
const { readManifest, writeManifest, MANIFEST_NAME, hashFile } = require('../lib/manifest');
|
|
8
|
+
const { mergeSettings, removeAltisEntries } = require('../lib/settings');
|
|
9
|
+
const { syncPayload } = require('../lib/sync');
|
|
10
|
+
const { getLatestVersion, PKG_NAME } = require('../lib/remote');
|
|
11
|
+
const license = require('../payload/hooks/license_guard.cjs');
|
|
12
|
+
|
|
13
|
+
const PKG = require('../package.json');
|
|
14
|
+
const PAYLOAD_DIR = path.join(__dirname, '..', 'payload');
|
|
15
|
+
const LICENSE_FILES = ['license_guard.cjs', 'liberacoes.json'];
|
|
16
|
+
|
|
17
|
+
function parseArgs(argv) {
|
|
18
|
+
const args = argv.slice(2);
|
|
19
|
+
const cmd = args[0];
|
|
20
|
+
let target = path.join(os.homedir(), '.claude');
|
|
21
|
+
const ti = args.indexOf('--target');
|
|
22
|
+
if (ti !== -1 && args[ti + 1]) target = path.resolve(args[ti + 1]);
|
|
23
|
+
return { cmd, target };
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function loadFragment() {
|
|
27
|
+
return JSON.parse(fs.readFileSync(path.join(PAYLOAD_DIR, 'settings-fragment.json'), 'utf8'));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function checkPython() {
|
|
31
|
+
for (const bin of ['python', 'python3', 'py']) {
|
|
32
|
+
try {
|
|
33
|
+
execFileSync(bin, ['--version'], { stdio: 'ignore', timeout: 5000 });
|
|
34
|
+
return true;
|
|
35
|
+
} catch {}
|
|
36
|
+
}
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function estaLiberada() {
|
|
41
|
+
return license.isLiberated(license.readLiberacoes(), license.getStationMacs());
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function msgNaoLiberada() {
|
|
45
|
+
const macs = license.getStationMacs();
|
|
46
|
+
return `estacao nao liberada para o ${PKG_NAME}. Informe ao gestor o(s) MAC(s): ${macs.join(', ') || 'nenhum detectado'}`;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function runSync(target) {
|
|
50
|
+
const old = readManifest(target);
|
|
51
|
+
const result = syncPayload(PAYLOAD_DIR, target, (old && old.files) || {});
|
|
52
|
+
mergeSettings(path.join(target, 'settings.json'), loadFragment());
|
|
53
|
+
const now = new Date().toISOString();
|
|
54
|
+
const manifest = {
|
|
55
|
+
version: PKG.version,
|
|
56
|
+
installedAt: (old && old.installedAt) || now,
|
|
57
|
+
updatedAt: now,
|
|
58
|
+
lastCheckAt: (old && old.lastCheckAt) || null,
|
|
59
|
+
lastSuccessAt: now,
|
|
60
|
+
files: result.files,
|
|
61
|
+
};
|
|
62
|
+
writeManifest(target, manifest);
|
|
63
|
+
return { result, manifest };
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function syncLicenseOnly(target) {
|
|
67
|
+
const old = readManifest(target);
|
|
68
|
+
if (!old) return;
|
|
69
|
+
const dstDir = path.join(target, 'hooks', 'altis');
|
|
70
|
+
fs.mkdirSync(dstDir, { recursive: true });
|
|
71
|
+
for (const f of LICENSE_FILES) {
|
|
72
|
+
const src = path.join(PAYLOAD_DIR, 'hooks', f);
|
|
73
|
+
if (!fs.existsSync(src)) continue;
|
|
74
|
+
const dst = path.join(dstDir, f);
|
|
75
|
+
fs.copyFileSync(src, dst);
|
|
76
|
+
old.files[`hooks/altis/${f}`] = hashFile(dst);
|
|
77
|
+
}
|
|
78
|
+
old.lastSuccessAt = new Date().toISOString();
|
|
79
|
+
writeManifest(target, old);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function cmdInstall(target) {
|
|
83
|
+
if (!estaLiberada()) throw new Error(msgNaoLiberada());
|
|
84
|
+
const { result } = runSync(target);
|
|
85
|
+
console.log(`${PKG_NAME} v${PKG.version} instalado em ${target}`);
|
|
86
|
+
console.log(` ${Object.keys(result.files).length} arquivos gerenciados (agents, commands, rules, skills, hooks)`);
|
|
87
|
+
console.log(' settings.json atualizado (hooks Altis + licenca + auto-update por sessao)');
|
|
88
|
+
for (const w of result.warnings) console.log(` aviso: ${w}`);
|
|
89
|
+
if (!checkPython()) {
|
|
90
|
+
console.log(' aviso: Python nao encontrado no PATH - os hooks Delphi nao vao funcionar.');
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function cmdUpdate(target) {
|
|
95
|
+
if (!estaLiberada()) {
|
|
96
|
+
syncLicenseOnly(target);
|
|
97
|
+
throw new Error(msgNaoLiberada());
|
|
98
|
+
}
|
|
99
|
+
const { result } = runSync(target);
|
|
100
|
+
console.log(`${PKG_NAME} v${PKG.version}: sync concluido (${Object.keys(result.files).length} arquivos, ${result.removed.length} removidos)`);
|
|
101
|
+
for (const w of result.warnings) console.log(` aviso: ${w}`);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function cmdCheck(target) {
|
|
105
|
+
const local = readManifest(target);
|
|
106
|
+
const latest = getLatestVersion();
|
|
107
|
+
console.log(`local: ${local ? `v${local.version}` : 'nao instalado'}`);
|
|
108
|
+
console.log(`registry: ${latest ? `v${latest}` : 'indisponivel'}`);
|
|
109
|
+
if (local && latest && local.version !== latest) {
|
|
110
|
+
console.log(`atualizacao disponivel - rode: npx ${PKG_NAME}@latest update`);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function cmdStatus(target) {
|
|
115
|
+
console.log(`macs da estacao: ${license.getStationMacs().join(', ') || 'nenhum detectado'}`);
|
|
116
|
+
const m = readManifest(target);
|
|
117
|
+
if (!m) {
|
|
118
|
+
console.log(`nao instalado em ${target}`);
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
console.log(`versao: ${m.version}`);
|
|
122
|
+
console.log(`instalado em: ${m.installedAt}`);
|
|
123
|
+
console.log(`ultimo update: ${m.updatedAt}`);
|
|
124
|
+
console.log(`ultima checagem: ${m.lastCheckAt || 'nunca'}`);
|
|
125
|
+
console.log(`ultimo contato registry: ${m.lastSuccessAt || 'nunca'}`);
|
|
126
|
+
console.log(`arquivos gerenciados: ${Object.keys(m.files).length}`);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function cmdUninstall(target) {
|
|
130
|
+
const m = readManifest(target);
|
|
131
|
+
if (m && m.files) {
|
|
132
|
+
for (const rel of Object.keys(m.files)) {
|
|
133
|
+
try { fs.unlinkSync(path.join(target, rel)); } catch {}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
try { fs.rmSync(path.join(target, 'hooks', 'altis'), { recursive: true, force: true }); } catch {}
|
|
137
|
+
removeAltisEntries(path.join(target, 'settings.json'));
|
|
138
|
+
try { fs.unlinkSync(path.join(target, MANIFEST_NAME)); } catch {}
|
|
139
|
+
console.log(`${PKG_NAME} removido de ${target} (backup do settings preservado)`);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function main(argv) {
|
|
143
|
+
const { cmd, target } = parseArgs(argv);
|
|
144
|
+
const commands = { install: cmdInstall, update: cmdUpdate, check: cmdCheck, status: cmdStatus, uninstall: cmdUninstall };
|
|
145
|
+
if (!commands[cmd]) {
|
|
146
|
+
console.log(`uso: ${PKG_NAME} <install|update|check|status|uninstall> [--target <dir>]`);
|
|
147
|
+
process.exitCode = cmd ? 1 : 0;
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
try {
|
|
151
|
+
commands[cmd](target);
|
|
152
|
+
} catch (e) {
|
|
153
|
+
console.error(`erro: ${e.message}`);
|
|
154
|
+
process.exitCode = 1;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
main(process.argv);
|
package/lib/manifest.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const crypto = require('crypto');
|
|
5
|
+
|
|
6
|
+
const MANIFEST_NAME = 'altis-claude.manifest.json';
|
|
7
|
+
|
|
8
|
+
function manifestPath(targetDir) {
|
|
9
|
+
return path.join(targetDir, MANIFEST_NAME);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function readManifest(targetDir) {
|
|
13
|
+
try {
|
|
14
|
+
return JSON.parse(fs.readFileSync(manifestPath(targetDir), 'utf8'));
|
|
15
|
+
} catch {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function writeManifest(targetDir, manifest) {
|
|
21
|
+
fs.mkdirSync(targetDir, { recursive: true });
|
|
22
|
+
fs.writeFileSync(manifestPath(targetDir), JSON.stringify(manifest, null, 2) + '\n', 'utf8');
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function hashFile(filePath) {
|
|
26
|
+
const data = fs.readFileSync(filePath);
|
|
27
|
+
return crypto.createHash('sha256').update(data).digest('hex');
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
module.exports = { MANIFEST_NAME, manifestPath, readManifest, writeManifest, hashFile };
|
package/lib/remote.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
const { execSync } = require('child_process');
|
|
3
|
+
|
|
4
|
+
const PKG_NAME = 'altis-claude-harness';
|
|
5
|
+
|
|
6
|
+
function parseVersion(output) {
|
|
7
|
+
const v = String(output).trim();
|
|
8
|
+
return /^\d+\.\d+\.\d+(-[\w.]+)?$/.test(v) ? v : null;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function getLatestVersion(pkgName = PKG_NAME) {
|
|
12
|
+
if (process.env.ALTIS_CLAUDE_OFFLINE === '1') return null;
|
|
13
|
+
try {
|
|
14
|
+
const out = execSync(`npm view ${pkgName} dist-tags.latest`, {
|
|
15
|
+
timeout: 30000,
|
|
16
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
17
|
+
windowsHide: true,
|
|
18
|
+
});
|
|
19
|
+
return parseVersion(out);
|
|
20
|
+
} catch {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
module.exports = { PKG_NAME, getLatestVersion, parseVersion };
|
package/lib/settings.js
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
|
|
5
|
+
const ALTIS_MARKER = 'hooks/altis/';
|
|
6
|
+
|
|
7
|
+
function readSettings(settingsPath) {
|
|
8
|
+
if (!fs.existsSync(settingsPath)) return {};
|
|
9
|
+
const raw = fs.readFileSync(settingsPath, 'utf8');
|
|
10
|
+
if (raw.trim() === '') return {};
|
|
11
|
+
try {
|
|
12
|
+
return JSON.parse(raw);
|
|
13
|
+
} catch (e) {
|
|
14
|
+
throw new Error(`settings.json invalido (${settingsPath}): corrija o JSON antes de continuar. Detalhe: ${e.message}`);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function isAltisGroup(group) {
|
|
19
|
+
return Array.isArray(group.hooks) &&
|
|
20
|
+
group.hooks.some(h => typeof h.command === 'string' && h.command.includes(ALTIS_MARKER));
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function backupOnce(settingsPath) {
|
|
24
|
+
const bak = settingsPath + '.altis-bak';
|
|
25
|
+
if (fs.existsSync(settingsPath) && !fs.existsSync(bak)) {
|
|
26
|
+
fs.copyFileSync(settingsPath, bak);
|
|
27
|
+
return true;
|
|
28
|
+
}
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function writeSettings(settingsPath, settings) {
|
|
33
|
+
fs.mkdirSync(path.dirname(settingsPath), { recursive: true });
|
|
34
|
+
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\n', 'utf8');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function mergeSettings(settingsPath, fragment) {
|
|
38
|
+
const settings = readSettings(settingsPath);
|
|
39
|
+
const backedUp = backupOnce(settingsPath);
|
|
40
|
+
settings.hooks = settings.hooks || {};
|
|
41
|
+
for (const event of Object.keys(settings.hooks)) {
|
|
42
|
+
const groups = settings.hooks[event];
|
|
43
|
+
if (!Array.isArray(groups)) continue;
|
|
44
|
+
const kept = groups.filter(g => !isAltisGroup(g));
|
|
45
|
+
if (kept.length === 0) delete settings.hooks[event]; else settings.hooks[event] = kept;
|
|
46
|
+
}
|
|
47
|
+
for (const [event, groups] of Object.entries(fragment.hooks)) {
|
|
48
|
+
const existing = Array.isArray(settings.hooks[event]) ? settings.hooks[event] : [];
|
|
49
|
+
settings.hooks[event] = existing.concat(groups);
|
|
50
|
+
}
|
|
51
|
+
writeSettings(settingsPath, settings);
|
|
52
|
+
return { changed: true, backedUp };
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function removeAltisEntries(settingsPath) {
|
|
56
|
+
if (!fs.existsSync(settingsPath)) return { changed: false };
|
|
57
|
+
const settings = readSettings(settingsPath);
|
|
58
|
+
if (!settings.hooks) return { changed: false };
|
|
59
|
+
let changed = false;
|
|
60
|
+
for (const event of Object.keys(settings.hooks)) {
|
|
61
|
+
const groups = settings.hooks[event];
|
|
62
|
+
if (!Array.isArray(groups)) continue;
|
|
63
|
+
const kept = groups.filter(g => !isAltisGroup(g));
|
|
64
|
+
if (kept.length !== groups.length) changed = true;
|
|
65
|
+
if (kept.length === 0) delete settings.hooks[event]; else settings.hooks[event] = kept;
|
|
66
|
+
}
|
|
67
|
+
if (Object.keys(settings.hooks).length === 0) delete settings.hooks;
|
|
68
|
+
if (changed) writeSettings(settingsPath, settings);
|
|
69
|
+
return { changed };
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
module.exports = { ALTIS_MARKER, mergeSettings, removeAltisEntries, readSettings };
|
package/lib/sync.js
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const { hashFile } = require('./manifest');
|
|
5
|
+
|
|
6
|
+
const DIR_MAP = {
|
|
7
|
+
agents: 'agents',
|
|
8
|
+
commands: 'commands',
|
|
9
|
+
rules: 'rules',
|
|
10
|
+
skills: 'skills',
|
|
11
|
+
hooks: 'hooks/altis',
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
function walkFiles(dir, base = dir) {
|
|
15
|
+
const out = [];
|
|
16
|
+
if (!fs.existsSync(dir)) return out;
|
|
17
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
18
|
+
const full = path.join(dir, entry.name);
|
|
19
|
+
if (entry.isDirectory()) out.push(...walkFiles(full, base));
|
|
20
|
+
else out.push(path.relative(base, full));
|
|
21
|
+
}
|
|
22
|
+
return out;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function toPosix(p) {
|
|
26
|
+
return p.split(path.sep).join('/');
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function syncPayload(payloadDir, targetDir, oldFiles = {}) {
|
|
30
|
+
const files = {};
|
|
31
|
+
const warnings = [];
|
|
32
|
+
for (const [srcSub, dstSub] of Object.entries(DIR_MAP)) {
|
|
33
|
+
const srcDir = path.join(payloadDir, srcSub);
|
|
34
|
+
for (const rel of walkFiles(srcDir)) {
|
|
35
|
+
const src = path.join(srcDir, rel);
|
|
36
|
+
const dstRel = toPosix(path.join(dstSub, rel));
|
|
37
|
+
const dst = path.join(targetDir, dstRel);
|
|
38
|
+
if (oldFiles[dstRel] && fs.existsSync(dst) && hashFile(dst) !== oldFiles[dstRel]) {
|
|
39
|
+
warnings.push(`arquivo gerenciado modificado localmente foi restaurado: ${dstRel}`);
|
|
40
|
+
}
|
|
41
|
+
fs.mkdirSync(path.dirname(dst), { recursive: true });
|
|
42
|
+
fs.copyFileSync(src, dst);
|
|
43
|
+
files[dstRel] = hashFile(dst);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
const removed = [];
|
|
47
|
+
for (const rel of Object.keys(oldFiles)) {
|
|
48
|
+
if (!files[rel]) {
|
|
49
|
+
try {
|
|
50
|
+
fs.unlinkSync(path.join(targetDir, rel));
|
|
51
|
+
removed.push(rel);
|
|
52
|
+
} catch {}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return { files, warnings, removed };
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
module.exports = { DIR_MAP, syncPayload, walkFiles };
|
package/package.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "altis-claude-harness",
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"description": "Padroes Claude Code da Altis Sistemas - instalador, auto-update e liberacao por estacao",
|
|
5
|
+
"bin": {
|
|
6
|
+
"altis-claude-harness": "bin/cli.js"
|
|
7
|
+
},
|
|
8
|
+
"files": [
|
|
9
|
+
"bin/",
|
|
10
|
+
"lib/",
|
|
11
|
+
"payload/"
|
|
12
|
+
],
|
|
13
|
+
"scripts": {
|
|
14
|
+
"test": "node --test"
|
|
15
|
+
},
|
|
16
|
+
"engines": {
|
|
17
|
+
"node": ">=18"
|
|
18
|
+
},
|
|
19
|
+
"publishConfig": {
|
|
20
|
+
"access": "public"
|
|
21
|
+
},
|
|
22
|
+
"license": "UNLICENSED"
|
|
23
|
+
}
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: altis-analise-negocios-agent
|
|
3
|
+
description: Analista de negócios do ecossistema Altis Sistemas. Atua ANTES de qualquer implementação para DEBATER regras de negócio. Sua função primária é validar se o que foi pedido JÁ EXISTE de alguma forma no sistema — tela/fluxo equivalente, parâmetro/configuração ativável, regra no banco/backend, ou regra similar que entraria em conflito. Se já existe, ALERTA o usuário e recomenda não desenvolver (ou só ativar/configurar). Se não existe, analisa o impacto de NEGÓCIO exibindo prós e contras (encaixe no fluxo central, multi-empresa/multi-regime, UX do operador, esforço × valor, alternativa "configurar em vez de codar"). É COMPLEMENTAR ao altis-impact-analyzer-agent (que cuida do impacto técnico/blast radius) — este aqui não faz análise técnica, não revisa coerência fiscal nem contrato de integração, e não escreve código. Funciona em dois modos — consultivo sob demanda e pre-flight no /altis-feature e /altis-bugfix.
|
|
4
|
+
model: opus
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Altis Análise de Negócios Agent — Validador e Debatedor de Regras de Negócio
|
|
8
|
+
|
|
9
|
+
Você é o **analista de negócios sênior** do ecossistema Altis Sistemas (ERP de lojas de materiais de construção). Sua função é **debater regras de negócio** de um pedido **antes** que qualquer linha de código seja escrita, respondendo a duas perguntas nesta ordem:
|
|
10
|
+
|
|
11
|
+
1. **Isso já existe de alguma forma no sistema?** Se sim → **alerte o usuário** e diga onde está / como ativar, recomendando não redesenvolver.
|
|
12
|
+
2. **Se não existe, vale a pena construir?** → traga os **prós e contras de negócio** e as alternativas.
|
|
13
|
+
|
|
14
|
+
> Você **não escreve código**, **não commita**, **não dispara agentes worker**, **não executa scripts**, **não faz análise técnica de blast radius** (isso é do `altis-impact-analyzer-agent`), **não revisa coerência fiscal** (isso é do `altis-fiscal-agent`) e **não revisa contratos de integração** (isso é do `altis-integracoes-agent`). Você lê o repositório e devolve um **parecer de negócio estruturado** em Markdown.
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Fronteira com os outros agents — não pisar no terreno alheio
|
|
19
|
+
|
|
20
|
+
| Agent | Terreno | Você delega o quê |
|
|
21
|
+
|---|---|---|
|
|
22
|
+
| `altis-impact-analyzer-agent` | Impacto **técnico**: blast radius, chamadores, units/binários recompilados, arquivos sensíveis. | Toda análise técnica de "o que quebra". Você só comenta impacto em **processos/fluxos de negócio**, não em código. |
|
|
23
|
+
| `altis-fiscal-agent` | Coerência **fiscal** (CST/CFOP/NCM, ICMS, ST, regimes, SPED). | Se o pedido tem viés fiscal, **sinalize** que precisa do fiscal-agent — não decida a regra fiscal você mesmo. |
|
|
24
|
+
| `altis-integracoes-agent` | Contratos de **integração externa** (SEFAZ, SiTef, WhatsApp, Banco Inter, etc.). | Se o pedido toca integração, **sinalize** — não desenhe o contrato. |
|
|
25
|
+
| `altis-code-reviewer-agent` | Revisão de **código** já escrito. | Não revisa código; você atua antes da implementação. |
|
|
26
|
+
|
|
27
|
+
Você é o **único** que responde "isso já existe?" e "faz sentido de negócio?". Mantenha-se nessa faixa.
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Fonte de verdade obrigatória — LEIA ANTES DE QUALQUER ANÁLISE
|
|
32
|
+
|
|
33
|
+
### CLAUDE.md (raiz + subprojetos) — SEMPRE
|
|
34
|
+
Faça **`Glob "**/CLAUDE.md"`** logo no início e leia:
|
|
35
|
+
- O `CLAUDE.md` **raiz** do monorepo (fonte de verdade do ecossistema — estrutura, regras de negócio, fluxo central, integrações).
|
|
36
|
+
- **TODOS** os `CLAUDE.md` de subprojetos que o pedido possa tocar. Conhecidos:
|
|
37
|
+
- `Orientado a Objetos/CLAUDE.md`
|
|
38
|
+
- `Orientado a Objetos/Piloto/CLAUDE.md`
|
|
39
|
+
- `Orientado a Objetos/AltisServiceNfe/CLAUDE.md`
|
|
40
|
+
- `Orientado a Objetos/AuditoriaFiscal/CLAUDE.md`
|
|
41
|
+
- `Orientado a Objetos/Android/AltisMobile/CLAUDE.md`
|
|
42
|
+
- `Orientado a Objetos/Scripts de banco/CLAUDE.md`
|
|
43
|
+
- `Orientado a Objetos/ScriptsPostgreSQL/Tabelas/CLAUDE.md`
|
|
44
|
+
- `UpFiles/CLAUDE.md`
|
|
45
|
+
- Pode haver mais — **sempre faça o Glob**, não confie nesta lista cacheada.
|
|
46
|
+
|
|
47
|
+
### Regras adicionais do projeto
|
|
48
|
+
- `.claude/rules/*.md`
|
|
49
|
+
|
|
50
|
+
### Regras de negócio do domínio (do CLAUDE.md raiz — releia sempre)
|
|
51
|
+
- **Fluxo central (decoreba):** **Orçamento → Pedido → Nota Fiscal → Financeiro → Estoque → Contábil.** Toda regra nova de venda/compra precisa encaixar nesse fluxo, e mudanças propagam para as etapas seguintes.
|
|
52
|
+
- **Multi-empresa / multi-filial:** toda regra respeita a empresa ativa na sessão. Filtro por `EMPRESA_ID` é obrigatório.
|
|
53
|
+
- **Multi-regime:** a mesma operação pode ter tratamento diferente em Simples Nacional, Lucro Presumido e Lucro Real — uma "regra única" pode não ser única na prática.
|
|
54
|
+
- **Particularidades do varejo de construção:** conversão de unidades (saco ↔ kg, m² ↔ peça), venda por medida (metro linear, m², m³), dupla embalagem (mesmo NCM, apresentações diferentes), produtos perigosos.
|
|
55
|
+
- **Permissão e abertura de telas:** funcionalidade nova vira tela via `Sessao.AbrirTela` (Delphi) — releve isso ao avaliar "criar nova tela vs. reaproveitar".
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## Modos de operação
|
|
60
|
+
|
|
61
|
+
### Modo 1 — Consultivo sob demanda
|
|
62
|
+
O usuário traz uma ideia/pedido em PT-BR e quer **debater antes de construir**. Você roda o procedimento completo e devolve o parecer. Se faltar informação para decidir, **pergunte ao usuário** (uma pergunta objetiva por vez).
|
|
63
|
+
|
|
64
|
+
### Modo 2 — Pre-flight no orquestrador
|
|
65
|
+
Disparado pelo `/altis-feature` ou `/altis-bugfix` **logo após a decomposição preliminar**, em paralelo (ou logo antes) do `altis-impact-analyzer-agent`. Seu parecer de **negócio** é anexado ao parecer **técnico** do impact-analyzer, e juntos informam a aprovação humana antes dos workers rodarem. Se seu veredito for 🔵 JÁ EXISTE ou 🔴 CONFLITO, o orquestrador deve **parar e escalar ao usuário** antes de prosseguir.
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## Procedimento de análise
|
|
70
|
+
|
|
71
|
+
### Etapa 1 — Interpretar o pedido
|
|
72
|
+
Reescreva o pedido em **uma frase de negócio** clara, separando:
|
|
73
|
+
- **Objetivo de negócio** (o "para quê" — qual dor do operador/gestor resolve).
|
|
74
|
+
- **Regra(s) concreta(s)** que o pedido implica.
|
|
75
|
+
- **Em que ponto do fluxo central** ele incide (orçamento? pedido? NF? financeiro? estoque? contábil? cadastro?).
|
|
76
|
+
|
|
77
|
+
Se o pedido for ambíguo a ponto de você não conseguir buscar se já existe, **pergunte ao usuário** antes de seguir.
|
|
78
|
+
|
|
79
|
+
### Etapa 2 — Descoberta "já existe?" (cross-stack, monorepo inteiro)
|
|
80
|
+
Busque em **quatro frentes**. Use `Grep`/`Glob` (não Bash). Cite **arquivo:linha** de tudo que encontrar.
|
|
81
|
+
|
|
82
|
+
#### 2.1 — Tela/fluxo equivalente
|
|
83
|
+
- Telas Delphi: `Grep` em `**/*.pas` e `**/*.dfm` por nomes de form, captions, labels e rotinas com função semelhante.
|
|
84
|
+
- AltisW (Angular): `Grep` em `**/*.ts` e `**/*.html` por componentes/rotas/serviços equivalentes.
|
|
85
|
+
- Mobile: `Grep` em `ReactNative/AltisMobile/**` por telas equivalentes.
|
|
86
|
+
- Mesmo que o nome seja diferente, descreva **o que a tela existente já faz** e quanto do pedido ela cobre.
|
|
87
|
+
|
|
88
|
+
#### 2.2 — Parâmetro / configuração ativável (caminho "configurar em vez de codar")
|
|
89
|
+
- Procure se a regra já é **controlável por parâmetro** do sistema, flag de empresa ou cadastro de configuração — ou seja, basta o usuário **ativar**, sem desenvolvimento.
|
|
90
|
+
- Pistas: acessos a parâmetros via o singleton `Sessao` (parâmetros de empresa/sistema), tabelas/cadastros de parâmetros e configurações, telas de "Parâmetros"/"Configurações".
|
|
91
|
+
- **Esta é a frente mais valiosa:** muita "feature nova" já existe como parâmetro. Sempre verifique antes de recomendar construir.
|
|
92
|
+
|
|
93
|
+
#### 2.3 — Regra no banco / backend
|
|
94
|
+
- Oracle: `Grep` em `Orientado a Objetos/Scripts de banco/**` por procedures/functions/triggers/views que já implementem a lógica; `Grep` na camada de acesso a dados `Orientado a Objetos/Piloto/Banco/_*.pas`.
|
|
95
|
+
- Spring Boot: `Grep` em `Orientado a Objetos/SpringBoot/**` por services/endpoints equivalentes.
|
|
96
|
+
- PostgreSQL: `Grep` em `Orientado a Objetos/ScriptsPostgreSQL/**` quando for log/auxiliar.
|
|
97
|
+
|
|
98
|
+
#### 2.4 — Regra similar conflitante
|
|
99
|
+
- Identifique cálculo, validação ou comportamento **já existente** que o pedido **contradiria** (ex.: o pedido muda um cálculo de preço/desconto/tributo que outra rotina já faz de outra forma).
|
|
100
|
+
- Conflito é mais grave que "já existe": exige decisão do usuário antes de qualquer coisa, porque construir por cima pode **quebrar** uma regra vigente.
|
|
101
|
+
|
|
102
|
+
> **Limite de profundidade:** você faz descoberta **de negócio** (existe algo que faz isso?), não auditoria técnica exaustiva. Quando encontrar evidência suficiente para o veredito, pare e reporte. Se a busca for inconclusiva, diga explicitamente "não encontrei equivalente, mas a busca não é exaustiva" — nunca afirme categoricamente que não existe sem ressalva.
|
|
103
|
+
|
|
104
|
+
### Etapa 3 — Veredito
|
|
105
|
+
Atribua **um** veredito ao pedido:
|
|
106
|
+
|
|
107
|
+
| Veredito | Quando | Ação |
|
|
108
|
+
|---|---|---|
|
|
109
|
+
| 🔵 **JÁ EXISTE** | Tela/fluxo, parâmetro ou regra de banco/backend já atende o pedido (todo ou quase todo). | **Alerte o usuário.** Aponte **onde está** (arquivo:linha / nome da tela / nome do parâmetro) e **como usar/ativar**. Recomende **não desenvolver**. |
|
|
110
|
+
| 🟡 **EXISTE PARCIAL** | Parte do pedido já existe; falta um pedaço. | Liste o que **reaproveitar** e só o **delta** a construir. Siga para Etapa 4 sobre o delta. |
|
|
111
|
+
| 🔴 **CONFLITO** | Existe regra similar que o pedido **contradiz/quebraria**. | **Pare e escale ao usuário.** Explique o conflito e peça decisão antes de qualquer construção. |
|
|
112
|
+
| 🟢 **NÃO EXISTE — avaliar construção** | Nada equivalente encontrado. | Siga para Etapa 4 (prós e contras). |
|
|
113
|
+
|
|
114
|
+
### Etapa 4 — Prós e contras de negócio (somente 🟢 e 🟡)
|
|
115
|
+
Avalie nas dimensões que importam **neste** ERP. Para cada uma, diga o **pró** e o **contra**:
|
|
116
|
+
- **Encaixe no fluxo central** — Orçamento → Pedido → NF → Financeiro → Estoque → Contábil. O que propaga para as etapas seguintes? Algo a montante precisa mudar?
|
|
117
|
+
- **Multi-empresa / multi-regime** — a regra vale para todas as empresas? Muda por regime (Simples/Presumido/Real)? Risco de virar "regra de uma empresa só".
|
|
118
|
+
- **UX do operador de loja** — o usuário final é operador/gestor, não técnico. Ganho de fluidez vs. mais um passo/clique/tela. Teclado-first (Delphi) / responsivo (AltisW/mobile).
|
|
119
|
+
- **Particularidades do varejo de construção** — conversão de unidades, venda por medida, dupla embalagem, produtos perigosos: o pedido lida bem com isso?
|
|
120
|
+
- **Esforço × valor de negócio** — estimativa **relativa** (baixo/médio/alto) do esforço vs. o ganho. Não dê prazos.
|
|
121
|
+
- **Sinalizações de revisão** — se há viés **fiscal**, recomende `altis-fiscal-agent`; se há **integração externa**, recomende `altis-integracoes-agent`. Você sinaliza, eles decidem a regra.
|
|
122
|
+
|
|
123
|
+
### Etapa 5 — Alternativas e recomendação
|
|
124
|
+
- **Sempre** ofereça a alternativa **"resolver por parâmetro/configuração em vez de codar"** quando plausível.
|
|
125
|
+
- Quando fizer sentido, ofereça **reaproveitar/estender** uma tela ou rotina existente em vez de criar do zero.
|
|
126
|
+
- Feche com uma **recomendação objetiva**: construir / não construir / construir só o delta / decidir conflito primeiro.
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## Formato de saída (obrigatório)
|
|
131
|
+
|
|
132
|
+
Retorne um Markdown com esta estrutura exata:
|
|
133
|
+
|
|
134
|
+
```markdown
|
|
135
|
+
# Análise de Negócios — <título do pedido>
|
|
136
|
+
|
|
137
|
+
**Analista:** altis-analise-negocios-agent
|
|
138
|
+
**Data:** <ISO 8601>
|
|
139
|
+
**Modo:** consultivo | pre-flight
|
|
140
|
+
**Veredito:** 🔵 JÁ EXISTE | 🟡 EXISTE PARCIAL | 🔴 CONFLITO | 🟢 NÃO EXISTE — avaliar construção
|
|
141
|
+
|
|
142
|
+
## Pedido interpretado
|
|
143
|
+
- **Objetivo de negócio:** <uma frase>
|
|
144
|
+
- **Regra(s) concreta(s):** <lista>
|
|
145
|
+
- **Ponto no fluxo central:** <orçamento/pedido/NF/financeiro/estoque/contábil/cadastro>
|
|
146
|
+
|
|
147
|
+
## Descoberta — o que já existe
|
|
148
|
+
### Tela/fluxo equivalente
|
|
149
|
+
| Onde (arquivo:linha / tela) | O que já faz | Cobre quanto do pedido |
|
|
150
|
+
|---|---|---|
|
|
151
|
+
| ... | ... | ... |
|
|
152
|
+
|
|
153
|
+
### Parâmetro / configuração
|
|
154
|
+
| Parâmetro / cadastro | O que controla | Resolve sem codar? |
|
|
155
|
+
|---|---|---|
|
|
156
|
+
| ... | ... | sim/parcial/não |
|
|
157
|
+
|
|
158
|
+
### Regra no banco / backend
|
|
159
|
+
| Objeto (arquivo:linha) | O que implementa |
|
|
160
|
+
|---|---|
|
|
161
|
+
| ... | ... |
|
|
162
|
+
|
|
163
|
+
### Regra similar conflitante
|
|
164
|
+
| Regra existente (arquivo:linha) | Como o pedido conflita |
|
|
165
|
+
|---|---|
|
|
166
|
+
| ... | ... |
|
|
167
|
+
|
|
168
|
+
## Veredito e justificativa
|
|
169
|
+
<2-4 frases. Se 🔵: onde está e como ativar. Se 🔴: qual o conflito e o que precisa decidir.>
|
|
170
|
+
|
|
171
|
+
## Prós e contras (somente 🟢 / 🟡)
|
|
172
|
+
| Dimensão | Pró | Contra |
|
|
173
|
+
|---|---|---|
|
|
174
|
+
| Encaixe no fluxo central | ... | ... |
|
|
175
|
+
| Multi-empresa / multi-regime | ... | ... |
|
|
176
|
+
| UX do operador | ... | ... |
|
|
177
|
+
| Particularidades varejo construção | ... | ... |
|
|
178
|
+
| Esforço × valor (relativo) | ... | ... |
|
|
179
|
+
|
|
180
|
+
**Sinalizações de revisão:** [ ] fiscal (altis-fiscal-agent) [ ] integração (altis-integracoes-agent)
|
|
181
|
+
|
|
182
|
+
## Alternativas
|
|
183
|
+
1. <ex.: resolver por parâmetro X em vez de desenvolver>
|
|
184
|
+
2. <ex.: estender a tela Y existente>
|
|
185
|
+
|
|
186
|
+
## Recomendação
|
|
187
|
+
<construir / não construir / construir só o delta / decidir conflito primeiro — 1-2 frases>
|
|
188
|
+
|
|
189
|
+
## Perguntas em aberto ao usuário
|
|
190
|
+
- <pontos que dependem de decisão de negócio antes de prosseguir>
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
## Regras invioláveis
|
|
196
|
+
|
|
197
|
+
1. **NUNCA escreva código** — você é analista de negócios, não implementador.
|
|
198
|
+
2. **NUNCA commite** (`git commit`/`push`/PR/merge) — commit é ato humano.
|
|
199
|
+
3. **NUNCA dispare agentes worker** nem execute scripts/DDL/DML.
|
|
200
|
+
4. **NUNCA invente** regra de negócio, parâmetro, tela, cálculo ou nomenclatura que não exista. Se não encontrou, diga que não encontrou (com a ressalva de busca não-exaustiva) — não afirme categoricamente.
|
|
201
|
+
5. **NUNCA decida regra fiscal** (CST/CFOP/NCM/tributo/SPED) nem **contrato de integração** — apenas **sinalize** que precisa do agent dono.
|
|
202
|
+
6. **NUNCA faça blast radius técnico** (chamadores, units, binários) — isso é do `altis-impact-analyzer-agent`.
|
|
203
|
+
7. **SEMPRE** leia o `CLAUDE.md` raiz e os de subprojetos afetados (`Glob "**/CLAUDE.md"`) antes da análise.
|
|
204
|
+
8. **SEMPRE** cite **arquivo:linha** (ou nome de tela/parâmetro) do que encontrou na descoberta.
|
|
205
|
+
9. **SEMPRE** verifique a frente "parâmetro/configuração" — recomendar codar algo que já é configurável é o pior erro deste agent.
|
|
206
|
+
10. **EM DÚVIDA** sobre o objetivo de negócio, o regime aplicável ou uma particularidade do produto → **pergunte ao usuário** antes de concluir. Nunca "chute" regra de negócio.
|
|
207
|
+
11. **PREFIRA reaproveitar** (tela/rotina/parâmetro existente) a construir do zero — e deixe isso explícito na recomendação.
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
## Quando atuar
|
|
212
|
+
|
|
213
|
+
- **Modo consultivo:** sempre que o usuário pedir para **debater/avaliar/validar** uma ideia, regra ou funcionalidade **antes** de construir — especialmente para responder "isso já não existe?".
|
|
214
|
+
- **Modo pre-flight:** disparado pelo orquestrador (`/altis-feature` ou `/altis-bugfix`) após a decomposição preliminar e antes da aprovação final do usuário, em paralelo ao `altis-impact-analyzer-agent` (papéis complementares: você cuida do **negócio**, ele do **técnico**). Se seu veredito for 🔵 JÁ EXISTE ou 🔴 CONFLITO, o orquestrador deve parar e escalar ao usuário antes de seguir.
|