iron-edge 2.4.4 → 2.4.5
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 +7 -1
- package/bin/iron-edge.js +2 -1
- package/installer/atalho.js +87 -0
- package/installer/doctor.js +16 -3
- package/installer/install.js +5 -1
- package/installer/office.js +4 -4
- package/installer/update.js +5 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -168,12 +168,18 @@ Instalada junto. Depois de `npx iron-edge install`, os dois arquivos abaixo est
|
|
|
168
168
|
# Conferir a instalação: o que é seu, o que está diferente sem registro, o que sumiu
|
|
169
169
|
npx iron-edge verify
|
|
170
170
|
|
|
171
|
-
# Medir a máquina (Node, git, Claude Code, Iron Edge, chave, plugin, cofre). Com a chave do
|
|
171
|
+
# Medir a máquina (Node, git, Claude Code, Iron Edge, chave, plugin, cofre, atalho). Com a chave do
|
|
172
172
|
# Iron Office aceita, o resultado acende o checklist da página de Setup do site.
|
|
173
173
|
npx iron-edge doctor
|
|
174
174
|
|
|
175
175
|
# Instalar já criando um cofre vazio em ~/Iron Cofre (pronto pro Obsidian, nunca sobrescreve)
|
|
176
176
|
npx iron-edge install --cofre
|
|
177
|
+
|
|
178
|
+
# Ligar o Iron Office: depois do install (ou update), no Mac/Linux, o comando curto é
|
|
179
|
+
ironoffice # = npx iron-edge office (abra um terminal novo na primeira vez)
|
|
180
|
+
|
|
181
|
+
# Instalar sem criar o atalho ironoffice no ~/.zshrc (ou ~/.bashrc)
|
|
182
|
+
npx iron-edge install --sem-atalho
|
|
177
183
|
```
|
|
178
184
|
|
|
179
185
|
**Atualizar é um comando. Remover é operação conduzida.**
|
package/bin/iron-edge.js
CHANGED
|
@@ -18,10 +18,11 @@
|
|
|
18
18
|
* Claude Code conversando com o chat do dashboard
|
|
19
19
|
*
|
|
20
20
|
* doctor [--json] mede a maquina (Node, git, Claude Code, Iron Edge, chave,
|
|
21
|
-
* plugin, cofre) e, com a chave aceita, manda o resultado
|
|
21
|
+
* plugin, cofre, atalho) e, com a chave aceita, manda o resultado
|
|
22
22
|
* pra pagina de Setup do Iron Office
|
|
23
23
|
*
|
|
24
24
|
* install --cofre alem do install, cria ~/Iron Cofre/ (cofre vazio pro Obsidian)
|
|
25
|
+
* install/update --sem-atalho nao cria o alias ironoffice (= office) no ~/.zshrc ou ~/.bashrc
|
|
25
26
|
*
|
|
26
27
|
* Nao existe 'uninstall' automatico: remover continua sendo operacao conduzida, com o
|
|
27
28
|
* manifesto na mao (o README descreve o procedimento).
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* atalho.js — cria o comando curto `ironoffice` (= `npx iron-edge office`) no shell do aluno.
|
|
4
|
+
* Roda no fim do install e do update com sucesso; `--sem-atalho` pula.
|
|
5
|
+
*
|
|
6
|
+
* Regras:
|
|
7
|
+
* - Windows: nao faz nada (o PowerShell nao le .zshrc/.bashrc). O aluno usa `npx iron-edge office`.
|
|
8
|
+
* - escolhe ~/.zshrc se existir, senao ~/.bashrc se existir, senao cria ~/.zshrc (padrao do Mac).
|
|
9
|
+
* - se o arquivo ja tem `alias ironoffice=`, nao mexe: nunca duplica.
|
|
10
|
+
* - so' ACRESCENTA no fim. Nunca remove nem edita linha existente: o arquivo e' do aluno.
|
|
11
|
+
* - escrita atomica: grava ao lado e renomeia por cima. Se o .zshrc e' um link (dotfiles),
|
|
12
|
+
* escreve no arquivo de verdade e o link continua link. Link quebrado: nao mexe.
|
|
13
|
+
* - os bytes do aluno ficam intactos: le e grava em Buffer (um .zshrc em Latin-1 nao e' recodificado).
|
|
14
|
+
* - arquivo que existe e nao da pra ler (permissao, pasta no lugar): nao escreve nada. So' "nao existe"
|
|
15
|
+
* (ENOENT) vale como arquivo novo. Antes, qualquer erro de leitura virava "vazio" e o rename
|
|
16
|
+
* apagava o .zshrc do aluno (gate da onda 9).
|
|
17
|
+
* - dryRun so' diz o que faria.
|
|
18
|
+
*
|
|
19
|
+
* Saida so' em ASCII, como o resto do instalador.
|
|
20
|
+
*/
|
|
21
|
+
const fs = require('fs');
|
|
22
|
+
const path = require('path');
|
|
23
|
+
const os = require('os');
|
|
24
|
+
|
|
25
|
+
const LINHA = 'alias ironoffice="npx iron-edge office"';
|
|
26
|
+
const BLOCO = '\n# Iron Edge: atalho do canal do Iron Office\n' + LINHA + '\n';
|
|
27
|
+
const JA_TEM = /^\s*alias\s+ironoffice=/m;
|
|
28
|
+
|
|
29
|
+
function arquivoDoShell(home) {
|
|
30
|
+
for (const nome of ['.zshrc', '.bashrc']) {
|
|
31
|
+
const p = path.join(home, nome);
|
|
32
|
+
if (fs.existsSync(p)) return p;
|
|
33
|
+
}
|
|
34
|
+
return path.join(home, '.zshrc');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Devolve { criado: caminho } | { criaria: caminho }
|
|
38
|
+
// | { pulado: 'windows' | 'ja existe' | 'sem-atalho' | 'sem leitura' | 'link quebrado', arquivo? }
|
|
39
|
+
function criarAtalho(opts) {
|
|
40
|
+
const o = opts || {};
|
|
41
|
+
const platform = o.platform || process.platform;
|
|
42
|
+
if (o.semAtalho) return { pulado: 'sem-atalho' };
|
|
43
|
+
if (platform === 'win32') return { pulado: 'windows' };
|
|
44
|
+
const home = o.HOME || os.homedir();
|
|
45
|
+
const rc = arquivoDoShell(home);
|
|
46
|
+
let link = false;
|
|
47
|
+
try { link = fs.lstatSync(rc).isSymbolicLink(); } catch (_) { /* nao existe */ }
|
|
48
|
+
let real = rc;
|
|
49
|
+
if (link) {
|
|
50
|
+
try { real = fs.realpathSync.native(rc); } catch (_) { return { pulado: 'link quebrado', arquivo: rc }; }
|
|
51
|
+
}
|
|
52
|
+
let atual = Buffer.alloc(0);
|
|
53
|
+
try { atual = fs.readFileSync(real); } catch (e) {
|
|
54
|
+
if (!e || e.code !== 'ENOENT') return { pulado: 'sem leitura', arquivo: rc };
|
|
55
|
+
}
|
|
56
|
+
// latin1 mapeia byte a byte: acha o alias (ASCII) em qualquer codificacao sem estourar
|
|
57
|
+
if (JA_TEM.test(atual.toString('latin1'))) return { pulado: 'ja existe', arquivo: rc };
|
|
58
|
+
if (o.dryRun) return { criaria: rc };
|
|
59
|
+
let modo = 0o644;
|
|
60
|
+
try { modo = fs.statSync(real).mode & 0o777; } catch (_) {}
|
|
61
|
+
const tmp = real + '.iron-tmp-' + process.pid;
|
|
62
|
+
fs.writeFileSync(tmp, Buffer.concat([atual, Buffer.from(BLOCO)]), { mode: modo });
|
|
63
|
+
try { fs.renameSync(tmp, real); } catch (e) { try { fs.unlinkSync(tmp); } catch (_) {} throw e; }
|
|
64
|
+
return { criado: rc };
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Linha do relatorio do install/update
|
|
68
|
+
function relatarAtalho(r) {
|
|
69
|
+
if (r.criado) return 'Atalho criado: ironoffice em ' + r.criado + ' (abra um terminal novo)';
|
|
70
|
+
if (r.criaria) return 'criaria o atalho ironoffice em ' + r.criaria;
|
|
71
|
+
if (r.pulado === 'ja existe') return 'Atalho ja existia: ironoffice';
|
|
72
|
+
if (r.pulado === 'windows') return 'Windows: use npx iron-edge office';
|
|
73
|
+
if (r.pulado === 'sem leitura') return 'Atalho nao criado: nao consegui ler ' + r.arquivo + ' (nada foi mexido). Use npx iron-edge office';
|
|
74
|
+
if (r.pulado === 'link quebrado') return 'Atalho nao criado: ' + r.arquivo + ' aponta pra um arquivo que nao existe (nada foi mexido). Use npx iron-edge office';
|
|
75
|
+
return 'Atalho pulado (--sem-atalho): use npx iron-edge office';
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Rodado no fim do install/update: nunca derruba a instalacao que ja deu certo.
|
|
79
|
+
function atalhoNoFim(opts) {
|
|
80
|
+
try {
|
|
81
|
+
return relatarAtalho(criarAtalho(opts));
|
|
82
|
+
} catch (e) {
|
|
83
|
+
return 'Atalho nao criado (' + (e.code || e.message) + '): use npx iron-edge office';
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
module.exports = { criarAtalho, relatarAtalho, atalhoNoFim, LINHA };
|
package/installer/doctor.js
CHANGED
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
* pra a pagina de Setup acender cada passo sozinha (o site nao enxerga a maquina).
|
|
5
5
|
*
|
|
6
6
|
* Mede: node (>= 20), git, Claude Code, Iron Edge instalado pelo npm (manifesto), chave do Iron
|
|
7
|
-
* Office (formato + confere com o site), plugin iron-office, cofre (~/Iron Cofre, informativo)
|
|
7
|
+
* Office (formato + confere com o site), plugin iron-office, cofre (~/Iron Cofre, informativo),
|
|
8
|
+
* atalho ironoffice no .zshrc/.bashrc (informativo).
|
|
8
9
|
*
|
|
9
10
|
* Envio: SO' com a chave aceita pelo site (ping = ok) faz POST /api/chat/setup-status. Sem chave,
|
|
10
11
|
* com chave recusada ou sem rede, o resultado fica so' no terminal. Falhar o envio e' aviso, nao erro.
|
|
@@ -90,6 +91,17 @@ function checkPlugin(claudeBin) {
|
|
|
90
91
|
return out.includes(PLUGIN) ? item(true, PLUGIN) : item(false, 'falta o plugin: rode npx iron-edge office');
|
|
91
92
|
}
|
|
92
93
|
|
|
94
|
+
// alias ironoffice (installer/atalho.js): no Windows nao existe, entao conta como ok
|
|
95
|
+
function checkAtalho(home) {
|
|
96
|
+
if (IS_WIN) return item(true, 'não se aplica (Windows: npx iron-edge office)');
|
|
97
|
+
for (const nome of ['.zshrc', '.bashrc']) {
|
|
98
|
+
let txt = '';
|
|
99
|
+
try { txt = fs.readFileSync(path.join(home, nome), 'utf8'); } catch (_) { continue; }
|
|
100
|
+
if (/^\s*alias\s+ironoffice=/m.test(txt)) return item(true, 'ironoffice em ~/' + nome);
|
|
101
|
+
}
|
|
102
|
+
return item(false, 'ausente: rode npx iron-edge update');
|
|
103
|
+
}
|
|
104
|
+
|
|
93
105
|
function checkCofre(home) {
|
|
94
106
|
const ok = fs.existsSync(path.join(home, 'Iron Cofre', 'CLAUDE.md'));
|
|
95
107
|
return item(ok, ok ? '~/Iron Cofre' : 'sem cofre pronto (opcional: npx iron-edge install --cofre)');
|
|
@@ -111,6 +123,7 @@ async function medir(opts) {
|
|
|
111
123
|
key: key.check,
|
|
112
124
|
plugin: checkPlugin(claude.bin),
|
|
113
125
|
cofre: checkCofre(home),
|
|
126
|
+
atalho: checkAtalho(home),
|
|
114
127
|
},
|
|
115
128
|
ran_at: new Date().toISOString(),
|
|
116
129
|
};
|
|
@@ -138,7 +151,7 @@ async function enviar(result, key, baseUrl) {
|
|
|
138
151
|
}
|
|
139
152
|
}
|
|
140
153
|
|
|
141
|
-
const ROTULO = { node: 'Node', git: 'git', claude: 'Claude Code', iron_edge: 'Iron Edge', key: 'chave', plugin: 'plugin', cofre: 'cofre' };
|
|
154
|
+
const ROTULO = { node: 'Node', git: 'git', claude: 'Claude Code', iron_edge: 'Iron Edge', key: 'chave', plugin: 'plugin', cofre: 'cofre', atalho: 'atalho' };
|
|
142
155
|
const OBRIGATORIOS = ['node', 'git', 'claude', 'iron_edge'];
|
|
143
156
|
|
|
144
157
|
async function main(argv, opts) {
|
|
@@ -153,7 +166,7 @@ async function main(argv, opts) {
|
|
|
153
166
|
}
|
|
154
167
|
console.log('Iron Edge doctor ' + result.doctor);
|
|
155
168
|
for (const [k, c] of Object.entries(result.checks)) {
|
|
156
|
-
console.log(' ' + (c.ok ? '[ok] ' : (k === 'cofre' ? '[info] ' : '[falta] ')) + ROTULO[k] + ': ' + ascii(c.detail));
|
|
169
|
+
console.log(' ' + (c.ok ? '[ok] ' : (k === 'cofre' || k === 'atalho' ? '[info] ' : '[falta] ')) + ROTULO[k] + ': ' + ascii(c.detail));
|
|
157
170
|
}
|
|
158
171
|
console.log('');
|
|
159
172
|
if (!key && !readKey(o.home || homeDir())) {
|
package/installer/install.js
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
* - Manifesto com SHA-256 (gerados marcados generated:true).
|
|
17
17
|
* - shopify.yaml nasce desativado. config em branco (sem PII).
|
|
18
18
|
*
|
|
19
|
-
* Uso: node install.js [--dry-run] [--source <dir>] [--cofre]
|
|
19
|
+
* Uso: node install.js [--dry-run] [--source <dir>] [--cofre] [--sem-atalho]
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
22
|
'use strict';
|
|
@@ -42,6 +42,7 @@ function abort(msg) {
|
|
|
42
42
|
const args = process.argv.slice(2);
|
|
43
43
|
const DRY_RUN = args.includes('--dry-run');
|
|
44
44
|
const COFRE = args.includes('--cofre'); // cria ~/Iron Cofre/ no fim (installer/cofre.js)
|
|
45
|
+
const SEM_ATALHO = args.includes('--sem-atalho'); // nao cria o alias ironoffice (installer/atalho.js)
|
|
45
46
|
const srcIdx = args.indexOf('--source');
|
|
46
47
|
let SOURCE = srcIdx >= 0 && args[srcIdx + 1] ? path.resolve(args[srcIdx + 1]) : __dirname;
|
|
47
48
|
// Opera sobre o caminho FISICO: ancestral symlink herdado da maquina (perfil
|
|
@@ -337,6 +338,8 @@ if (DRY_RUN) {
|
|
|
337
338
|
log('\n--- arquivos que SERAO gerados ---');
|
|
338
339
|
for (const g of GENERATED) log(' ' + g.dest);
|
|
339
340
|
if (COFRE) require('./cofre').criarCofre({ home: HOME, dryRun: true });
|
|
341
|
+
log('\n--- atalho ---');
|
|
342
|
+
log(' ' + require('./atalho').atalhoNoFim({ HOME, dryRun: true, semAtalho: SEM_ATALHO }));
|
|
340
343
|
log('\nDRY-RUN concluido. Nada foi copiado.');
|
|
341
344
|
process.exit(0);
|
|
342
345
|
}
|
|
@@ -552,6 +555,7 @@ log(`Agentes : ${AGENTS_DEST}`);
|
|
|
552
555
|
log(`Skills : ${SKILLS_DEST}`);
|
|
553
556
|
log(`Nucleo : ${IRON_DIR}`);
|
|
554
557
|
log(`Manifesto: ${manifestPath}`);
|
|
558
|
+
log(require('./atalho').atalhoNoFim({ HOME, semAtalho: SEM_ATALHO }));
|
|
555
559
|
log('\n--------------------------------');
|
|
556
560
|
log(' PROXIMO PASSO');
|
|
557
561
|
log('--------------------------------');
|
package/installer/office.js
CHANGED
|
@@ -37,7 +37,7 @@ function isValidKey(key) {
|
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
// Le o arquivo da chave e devolve so' uma chave no formato certo; qualquer outra coisa vira ''.
|
|
40
|
-
// O `echo` do passo
|
|
40
|
+
// O `echo` do passo 2 no Windows pode gravar UTF-16 com BOM: normaliza antes de decidir.
|
|
41
41
|
function readKey(home) {
|
|
42
42
|
try {
|
|
43
43
|
const buf = fs.readFileSync(keyPath(home));
|
|
@@ -108,9 +108,9 @@ async function main(argv) {
|
|
|
108
108
|
if (!key) {
|
|
109
109
|
if (keyFileExists()) {
|
|
110
110
|
console.error('A chave em ' + keyPath() + ' esta invalida (nao tem o formato iok_...).');
|
|
111
|
-
console.error('Refaca o passo
|
|
111
|
+
console.error('Refaca o passo 2 (Ligar o Iron) em ' + ONBOARDING);
|
|
112
112
|
} else {
|
|
113
|
-
console.error('Falta a chave do Iron Office. Faca o passo
|
|
113
|
+
console.error('Falta a chave do Iron Office. Faca o passo 2 (Ligar o Iron) em ' + ONBOARDING);
|
|
114
114
|
}
|
|
115
115
|
return 1;
|
|
116
116
|
}
|
|
@@ -124,7 +124,7 @@ async function main(argv) {
|
|
|
124
124
|
console.log('Iron Office - preparando o canal');
|
|
125
125
|
const verdict = await ping(key);
|
|
126
126
|
if (verdict === 'rejected') {
|
|
127
|
-
console.error(' [falhou] chave recusada pelo Iron Office: ela foi trocada. Refaca o passo
|
|
127
|
+
console.error(' [falhou] chave recusada pelo Iron Office: ela foi trocada. Refaca o passo 2 (Ligar o Iron) em ' + ONBOARDING);
|
|
128
128
|
return 1;
|
|
129
129
|
}
|
|
130
130
|
if (verdict === 'ok') console.log(' [ok] chave aceita pelo Iron Office');
|
package/installer/update.js
CHANGED
|
@@ -28,6 +28,8 @@ const MANIFEST = path.join(IRON_DIR, 'install-manifest.json');
|
|
|
28
28
|
|
|
29
29
|
const args = process.argv.slice(2);
|
|
30
30
|
const DRY = args.includes('--dry-run');
|
|
31
|
+
const SEM_ATALHO = args.includes('--sem-atalho'); // nao cria o alias ironoffice (installer/atalho.js)
|
|
32
|
+
const atalho = (dryRun) => require('./atalho').atalhoNoFim({ HOME, dryRun, semAtalho: SEM_ATALHO });
|
|
31
33
|
const srcIdx = args.indexOf('--source');
|
|
32
34
|
const SOURCE = srcIdx >= 0 && args[srcIdx + 1] ? path.resolve(args[srcIdx + 1]) : path.join(__dirname, '..');
|
|
33
35
|
|
|
@@ -292,7 +294,7 @@ log('');
|
|
|
292
294
|
relatarConfig();
|
|
293
295
|
|
|
294
296
|
|
|
295
|
-
if (DRY) { log(''); log('--dry-run: nada foi escrito.'); process.exit(0); }
|
|
297
|
+
if (DRY) { log(''); log(atalho(true)); log('--dry-run: nada foi escrito.'); process.exit(0); }
|
|
296
298
|
|
|
297
299
|
// Permissao da pasta de segredos, TAMBEM no update. O chmod entrou no install no ciclo 2 e o
|
|
298
300
|
// gate mediu a lacuna: quem ja tinha o Iron instalado seguia com `secrets/` em 755, porque o
|
|
@@ -385,6 +387,7 @@ const versaoDoPacote = process.env.IRON_EDGE_VERSION ? 'iron-edge-' + process.en
|
|
|
385
387
|
const versaoDesatualizada = Boolean(versaoDoPacote) && versaoRegistrada !== versaoDoPacote;
|
|
386
388
|
if (!plano.trocar.length && !plano.adicionar.length && !plano.restaurar.length && !plano.remover.length && !plano.gerar.length && !plano.preservar.length && !versaoDesatualizada && !metadataReparado) {
|
|
387
389
|
log(''); log('Nada a fazer: sua instalacao ja esta na versao deste pacote.');
|
|
390
|
+
log(atalho(false));
|
|
388
391
|
process.exit(0);
|
|
389
392
|
}
|
|
390
393
|
|
|
@@ -519,6 +522,7 @@ log('');
|
|
|
519
522
|
log('================================');
|
|
520
523
|
log(' Atualizado com sucesso');
|
|
521
524
|
log('================================');
|
|
525
|
+
log(atalho(false));
|
|
522
526
|
log('Confira quando quiser: npx iron-edge verify');
|
|
523
527
|
log('Reabra o Claude Code para carregar o que mudou.');
|
|
524
528
|
log('');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "iron-edge",
|
|
3
|
-
"version": "2.4.
|
|
3
|
+
"version": "2.4.5",
|
|
4
4
|
"description": "Ecossistema de agentes para Claude Code: 44 agentes de topo, 18 squads e 14 skills, com quality gate, memoria, instalador que nunca sobrescreve o comando office (chat do Iron Office no dashboard; confere a chave com o site antes de abrir o Claude) e o doctor (mede a maquina e acende o Setup do site).",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"claude",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"node": ">=18.0.0"
|
|
33
33
|
},
|
|
34
34
|
"scripts": {
|
|
35
|
-
"test": "node scripts/lint.js && node scripts/test-verify.js && node scripts/test-update.js && node scripts/test-office.js && node scripts/test-cofre.js",
|
|
35
|
+
"test": "node scripts/lint.js && node scripts/test-verify.js && node scripts/test-update.js && node scripts/test-office.js && node scripts/test-cofre.js && node scripts/test-atalho.js",
|
|
36
36
|
"test:matriz": "node scripts/test-matriz-update.js"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|