auroq-os 2.8.7 → 2.8.9
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/.auroq-core/core-config.yaml +1 -1
- package/.claude/settings.json +6 -3
- package/CHANGELOG.md +3 -0
- package/README.md +3 -3
- package/bin/auroq-os.js +2 -1
- package/installer/install.ps1 +2 -2
- package/installer/install.sh +2 -2
- package/lib/cofre.js +7 -3
- package/lib/onepassword.js +193 -19
- package/lib/runtime-integrity.json +8 -8
- package/package.json +1 -1
- package/scripts/runtime-integrity.mjs +4 -2
package/.claude/settings.json
CHANGED
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
"hooks": [
|
|
9
9
|
{
|
|
10
10
|
"type": "command",
|
|
11
|
-
"command": "node
|
|
11
|
+
"command": "node",
|
|
12
|
+
"args": ["${CLAUDE_PROJECT_DIR}/.claude/hooks/auroq-sync.cjs", "--session-start"],
|
|
12
13
|
"timeout": 25000
|
|
13
14
|
}
|
|
14
15
|
]
|
|
@@ -20,7 +21,8 @@
|
|
|
20
21
|
"hooks": [
|
|
21
22
|
{
|
|
22
23
|
"type": "command",
|
|
23
|
-
"command": "node
|
|
24
|
+
"command": "node",
|
|
25
|
+
"args": ["${CLAUDE_PROJECT_DIR}/.claude/hooks/auroq-sync.cjs", "--remind"],
|
|
24
26
|
"timeout": 5000
|
|
25
27
|
}
|
|
26
28
|
]
|
|
@@ -31,7 +33,8 @@
|
|
|
31
33
|
"hooks": [
|
|
32
34
|
{
|
|
33
35
|
"type": "command",
|
|
34
|
-
"command": "node
|
|
36
|
+
"command": "node",
|
|
37
|
+
"args": ["${CLAUDE_PROJECT_DIR}/.claude/hooks/auroq-ate-o-fim.cjs"],
|
|
35
38
|
"timeout": 10
|
|
36
39
|
}
|
|
37
40
|
]
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
## Unreleased
|
|
2
2
|
|
|
3
|
+
- 2.8.9 — 1Password no Mac sem Homebrew (teste real num usuário novo do macOS, 06/11/2026): o Mac de aluno não tem Homebrew, e o `conectar-1password` parava em `app-nao-instalou` e `sem-op`. Agora, sem Homebrew (ou se ele falhar), o comando baixa o app oficial do 1Password (`1Password-latest`, assinatura da AgileBits conferida com `codesign --deep` e Team ID 2BUA8C4S2C) e copia para a pasta Aplicativos, e instala o 1Password CLI 2.41.1 oficial (SHA-256 fixo, o mesmo do app Auroq OS, mais a assinatura) em `~/.auroq/op/bin`, sem senha de administrador. `segredo` acha o `op` nessa pasta mesmo num terminal que não a tem no PATH.
|
|
4
|
+
- 1Password no Windows: o CLI do 1Password passa pelo PowerShell, como no teste real do Marcos; isso evita a falha de sessão que ocorria quando o Node o iniciava diretamente. `--estado` usa o mesmo caminho para detectar o CLI, e a lista de contas deixa de depender do shell em que o aluno abriu o comando. Os três ganchos do Claude Code usam o caminho do projeto mesmo depois de entrar numa subpasta. A skill do cofre orienta o diagnóstico quando a aprovação se repete. Catálogo `auroq-core` 2.3.55.
|
|
5
|
+
|
|
3
6
|
- Conteúdo ao vivo (catálogo `auroq-core` 2.3.54, 04/11): a peça do 1Password da skill do cofre avisa o Companion de que, no Windows, o app pode estar instalado só como pacote MSIX (é o que o `winget` instala hoje) e não aparece nas pastas de sempre: antes de dizer "o app não está instalado" (resultado `instalar-app`, ou o aluno dizendo que não acha) ele confere a lista de pacotes do Windows, e, se o app estiver lá, vai direto para entrar na conta e ligar a chave. Também descreve o instalador de reserva com limite de 3 minutos; o mesmo aviso entra no pré-gate da skill `configurar-computador`. Precisa do auroq-os 2.8.6 no npm (a detecção e o limite vivem no comando).
|
|
4
7
|
- Conteúdo ao vivo (catálogo `auroq-core` 2.3.53, 29/10): **a skill do cofre de senhas foi dividida em seis peças** (entrada, 1Password, Infisical grátis com os resultados à parte, passar do grátis para o 1Password, e uso do dia a dia). Antes era um texto só de 62 mil caracteres, grande demais para o Claude Code ler de uma vez (o Marcos viu isso no teste de 27/10). O Companion continua entrando pelo mesmo gatilho (`conectar-cofre`) e a entrada diz qual peça abrir. O Companion agora pede o OK do aluno em uma frase antes de criar a chave do agente, de instalar o app e de passar as chaves (a proteção do Claude Code barrava esses passos sem aviso), explica a Chave Secreta e o Kit de Emergência do 1Password (guardar o PDF fora do computador e fora do GitHub), ensina a ligar o Windows Hello ou o Touch ID quando a digital não aparece, e não manda mais ligar a chave do app de novo quando ela já está ligada. Precisa do auroq-os 2.8.5 no npm (comando `--instalar-app` e códigos novos).
|
|
5
8
|
- Conteúdo ao vivo (catálogo `auroq-core` 2.3.52, 27/10): **documentação revisada para o jeito de hoje.** O guia do sistema que o Companion usa com o aluno, a fundação do Companion e as fichas do Consultor não apresentam mais o Ops como técnico nem o nome personalizado do Companion; ensinam a abrir uma conversa nova dentro do projeto e chamar o Companion (quantas quiser, uma por assunto, nunca um chat por squad) e dizem que, com o app aberto, o salvamento na internet é automático a cada 15 minutos e ao abrir e fechar. A skill `configurar-computador` e o guia longo do Ops dizem que as contas são conectadas pelo Companion na primeira conversa, não na instalação.
|
package/README.md
CHANGED
|
@@ -290,13 +290,13 @@ a parte tecnica e com o Companion.
|
|
|
290
290
|
|
|
291
291
|
## Observabilidade e integridade do motor
|
|
292
292
|
|
|
293
|
-
Apos publicacao, `npx -y auroq-os@2.8.
|
|
294
|
-
manutencao/diagnostico. `npx -y auroq-os@2.8.
|
|
293
|
+
Apos publicacao, `npx -y auroq-os@2.8.9 doctor` mostra a fila local segura e os comandos pinados de
|
|
294
|
+
manutencao/diagnostico. `npx -y auroq-os@2.8.9 manutencao` preserva o caminho existente
|
|
295
295
|
de consentimento legado, studentFiles, customizacoes e dados do negocio. Nao ha
|
|
296
296
|
migracao forcada. O registro MCP aponta para `arcane-mcp@0.7.1` — o pin mora no campo
|
|
297
297
|
`arcaneMcpPin` do package.json (fonte unica; o servidor le o mesmo campo no npm).
|
|
298
298
|
`npm run release:verify` recusa publicar com um pin que o npm nao resolva.
|
|
299
|
-
Os instaladores do repositorio ficam preparados para 2.8.
|
|
299
|
+
Os instaladores do repositorio ficam preparados para 2.8.9; as copias publicas so recebem
|
|
300
300
|
a versao apos os gates nativos e a verificacao do tarball publicado.
|
|
301
301
|
O pacote inclui `lib/runtime-integrity.json`: inventario SHA-256 gerado depois da montagem da casca, verificavel com `npm run integrity:verify` dentro do pacote extraido. Ele comprova consistencia do conteudo; nao e uma assinatura de autoria.
|
|
302
302
|
|
package/bin/auroq-os.js
CHANGED
|
@@ -240,7 +240,8 @@ const HOOK_DO_FRAMEWORK = /(?:^|[\s"'\\/])(?:auroq-sync|auroq-ate-o-fim|synapse-
|
|
|
240
240
|
// Gancho de IA do sistema (type "prompt", sem `command`): o texto comeca com uma marca `[auroq-...]`.
|
|
241
241
|
// Sem ela, a manutencao o tomava por gancho do aluno e o duplicava a cada versao.
|
|
242
242
|
const MARCA_DO_FRAMEWORK = /^\s*\[auroq-[a-z-]+\]/;
|
|
243
|
-
const
|
|
243
|
+
const textoDoHook = h => [h?.command, ...(Array.isArray(h?.args) ? h.args : [])].join(' ');
|
|
244
|
+
const ehHookDoFramework = h => HOOK_DO_FRAMEWORK.test(textoDoHook(h)) || MARCA_DO_FRAMEWORK.test(String(h?.prompt || ''));
|
|
244
245
|
const CHAVES_DO_ALUNO = ['permissions', 'statusLine', 'env'];
|
|
245
246
|
const temChave = (obj, chave) => Object.prototype.hasOwnProperty.call(obj, chave);
|
|
246
247
|
|
package/installer/install.ps1
CHANGED
|
@@ -589,7 +589,7 @@ function Invoke-AuroqLogin {
|
|
|
589
589
|
# sucesso. Usado como pergunta de sim/nao, ele dizia "voce ja estava logado"
|
|
590
590
|
# pra quem nunca logou, pulava o portao e deixava a conta sem acesso chegar ate
|
|
591
591
|
# a criacao da pasta.
|
|
592
|
-
& (Get-AuroqNpx) -y auroq-os@2.8.
|
|
592
|
+
& (Get-AuroqNpx) -y auroq-os@2.8.9 check-access
|
|
593
593
|
if ($LASTEXITCODE -ne 0) {
|
|
594
594
|
Write-AuroqLog 'login' 'recusado'
|
|
595
595
|
Write-Host ''
|
|
@@ -677,7 +677,7 @@ function Invoke-AuroqInit {
|
|
|
677
677
|
if ($env:AUROQ_INSTALL_DRY_RUN) { Write-AuroqOk 'Sistema - seria montado aqui'; return }
|
|
678
678
|
|
|
679
679
|
Set-Location $script:AuroqPastaAlvo
|
|
680
|
-
& (Get-AuroqNpx) -y auroq-os@2.8.
|
|
680
|
+
& (Get-AuroqNpx) -y auroq-os@2.8.9 instalar
|
|
681
681
|
if ($LASTEXITCODE -ne 0) {
|
|
682
682
|
Write-AuroqLog 'init' 'falhou'
|
|
683
683
|
Write-AuroqErro 'A montagem do sistema parou no meio.' 'Rode o mesmo comando de novo. Se repetir, mande pro suporte o arquivo install.log da pasta .auroq.'
|
package/installer/install.sh
CHANGED
|
@@ -219,9 +219,9 @@ auroq_tem_terminal() {
|
|
|
219
219
|
# recebem pedaco do script no lugar da resposta dele.
|
|
220
220
|
auroq_npx_aluno() {
|
|
221
221
|
if [ -t 0 ]; then
|
|
222
|
-
npx -y auroq-os@2.8.
|
|
222
|
+
npx -y auroq-os@2.8.9 "$@"
|
|
223
223
|
else
|
|
224
|
-
npx -y auroq-os@2.8.
|
|
224
|
+
npx -y auroq-os@2.8.9 "$@" < /dev/tty
|
|
225
225
|
fi
|
|
226
226
|
}
|
|
227
227
|
|
package/lib/cofre.js
CHANGED
|
@@ -88,6 +88,10 @@ function ehWindows(d) {
|
|
|
88
88
|
return ((d && d.platform) || process.platform) === 'win32';
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
+
function ehMac(d) {
|
|
92
|
+
return ((d && d.platform) || process.platform) === 'darwin';
|
|
93
|
+
}
|
|
94
|
+
|
|
91
95
|
function nowOf(d) {
|
|
92
96
|
return d && typeof d.now === 'function' ? d.now() : Date.now();
|
|
93
97
|
}
|
|
@@ -501,14 +505,14 @@ function makeOpBackend(d) {
|
|
|
501
505
|
}
|
|
502
506
|
|
|
503
507
|
// Windows: o `op` instalado DEPOIS de o programa-pai abrir (winget so muda o PATH no registro) nao esta no PATH deste
|
|
504
|
-
// processo: o spawn da ENOENT. Recompoe o PATH UMA vez por backend (cada recomposicao abre o PowerShell) e tenta o
|
|
508
|
+
// processo: o spawn da ENOENT. Mac sem Homebrew: o `op` mora em ~/.auroq/op/bin, que um terminal comum nao tem no PATH. Recompoe o PATH UMA vez por backend (cada recomposicao abre o PowerShell) e tenta o
|
|
505
509
|
// comando de novo; chamadas em paralelo esperam a mesma recomposicao. Devolve false se nao ha como recompor.
|
|
506
510
|
let recomposicao = null;
|
|
507
511
|
function recomporPathUmaVez() {
|
|
508
512
|
if (!recomposicao) {
|
|
509
513
|
recomposicao = (async () => {
|
|
510
514
|
const o = mod(d, 'onepassword');
|
|
511
|
-
const recompor = typeof d.refreshPath === 'function' ? d.refreshPath : o.refreshWindowsPath;
|
|
515
|
+
const recompor = typeof d.refreshPath === 'function' ? d.refreshPath : (ehWindows(d) ? o.refreshWindowsPath : o.refreshPath);
|
|
512
516
|
if (typeof recompor !== 'function') return false;
|
|
513
517
|
try { await recompor(); } catch { /* melhor esforco: o comando decide se achou */ }
|
|
514
518
|
return true;
|
|
@@ -531,7 +535,7 @@ function makeOpBackend(d) {
|
|
|
531
535
|
return run(args, { env, input, timeoutMs: OP_TIMEOUT_MS });
|
|
532
536
|
};
|
|
533
537
|
let r = await tentar();
|
|
534
|
-
if (r && r.missing && ehWindows(d) && (await recomporPathUmaVez())) r = await tentar();
|
|
538
|
+
if (r && r.missing && (ehWindows(d) || ehMac(d)) && (await recomporPathUmaVez())) r = await tentar();
|
|
535
539
|
return r;
|
|
536
540
|
}
|
|
537
541
|
|
package/lib/onepassword.js
CHANGED
|
@@ -80,27 +80,106 @@ function hasCommand(cmd) {
|
|
|
80
80
|
}
|
|
81
81
|
|
|
82
82
|
function opVersion() {
|
|
83
|
+
const r = runOp(['--version'], { noStdin: true, timeoutMs: 10000 });
|
|
84
|
+
return r.ok ? r.stdout.trim() : null;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// 1Password CLI oficial para Mac SEM Homebrew (teste real num Mac novo, 06/11/2026: aluno nao tem `brew`, e instalar o
|
|
88
|
+
// Homebrew pede a senha de admin e as ferramentas da Apple). Mesma versao, mesmo endereco e mesmo SHA-256 que o app
|
|
89
|
+
// Auroq OS usa (auroq-os-app, auroq/primeira-execucao/instalador-do-op.ts), na mesma pasta: ~/.auroq/op/bin.
|
|
90
|
+
const OP_DIRETO = {
|
|
91
|
+
versao: '2.41.1',
|
|
92
|
+
pacotes: {
|
|
93
|
+
arm64: '2289771b68b521ee3dc1d63a013a6a1c5691e0c53e4c4fe79af8042b6ad3c7f5',
|
|
94
|
+
x64: 'e77fc9a8ebb23c176fed7c56ea6e4a7184d2b89957e9a5d9a2feb724e7e0574b',
|
|
95
|
+
},
|
|
96
|
+
};
|
|
97
|
+
// Team ID da AgileBits (dona do 1Password) na assinatura da Apple: o `op` e o app so entram se vierem assinados por ela.
|
|
98
|
+
const AGILEBITS_TEAM_ID = '2BUA8C4S2C';
|
|
99
|
+
|
|
100
|
+
/** Pasta do `op` instalado sem Homebrew (a mesma do app Auroq OS, que ja a poe no PATH dos terminais dele). */
|
|
101
|
+
function auroqOpBin(home = os.homedir()) {
|
|
102
|
+
return path.join(home, '.auroq', 'op', 'bin');
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function opDiretoUrl(arch) {
|
|
106
|
+
const pacote = arch === 'arm64' ? 'arm64' : 'amd64';
|
|
107
|
+
return `https://cache.agilebits.com/dist/1P/op2/pkg/v${OP_DIRETO.versao}/op_darwin_${pacote}_v${OP_DIRETO.versao}.zip`;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Requisito de assinatura conferido pelo proprio macOS: certificado emitido pela Apple (Developer ID) para a equipe
|
|
111
|
+
// da AgileBits. So o texto "TeamIdentifier=" nao basta: uma assinatura propria poderia imitar o identificador.
|
|
112
|
+
const AGILEBITS_REQUISITO = `anchor apple generic and certificate leaf[subject.OU] = "${AGILEBITS_TEAM_ID}"`;
|
|
113
|
+
|
|
114
|
+
/** O programa tem assinatura valida, emitida pela Apple para a AgileBits (`codesign -R`)? Nunca lanca. */
|
|
115
|
+
function assinadoPelaAgilebits(alvo, run, { deep = false } = {}) {
|
|
116
|
+
const v = run('/usr/bin/codesign', ['--verify', '--strict', ...(deep ? ['--deep'] : []), `-R=${AGILEBITS_REQUISITO}`, alvo]);
|
|
117
|
+
if (!v || !v.ok) return false;
|
|
118
|
+
const info = run('/usr/bin/codesign', ['-dv', '--verbose=2', alvo]);
|
|
119
|
+
const texto = `${(info && info.stdout) || ''}\n${(info && info.stderr) || ''}`;
|
|
120
|
+
return new RegExp(`^TeamIdentifier=${AGILEBITS_TEAM_ID}$`, 'm').test(texto);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Mac sem Homebrew: baixa o `op` oficial (versao fixa), confere o SHA-256 e a assinatura da AgileBits ANTES de por no
|
|
125
|
+
* lugar e instala em ~/.auroq/op/bin, sem senha. Poe a pasta no PATH deste processo. Nunca lanca; devolve true/false.
|
|
126
|
+
* `deps` so existe para os testes.
|
|
127
|
+
*/
|
|
128
|
+
function installOpDirect(deps = {}) {
|
|
129
|
+
const d = {
|
|
130
|
+
arch: process.arch,
|
|
131
|
+
home: os.homedir(),
|
|
132
|
+
run: (cmd, args, o) => runProgram(cmd, args, o),
|
|
133
|
+
pacotes: OP_DIRETO.pacotes,
|
|
134
|
+
tmpdir: os.tmpdir(),
|
|
135
|
+
out: { log, err },
|
|
136
|
+
...deps,
|
|
137
|
+
};
|
|
138
|
+
const esperado = d.pacotes[d.arch === 'arm64' ? 'arm64' : 'x64'];
|
|
139
|
+
const destino = auroqOpBin(d.home);
|
|
140
|
+
let tmp = null;
|
|
83
141
|
try {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
142
|
+
tmp = fs.mkdtempSync(path.join(d.tmpdir, 'auroq-op-'));
|
|
143
|
+
const zip = path.join(tmp, 'op.zip');
|
|
144
|
+
const aberto = path.join(tmp, 'aberto');
|
|
145
|
+
d.out.log(`${DIM}Baixando o 1Password CLI oficial ${OP_DIRETO.versao} (sem Homebrew)...${RESET}`);
|
|
146
|
+
const baixou = d.run('/usr/bin/curl', ['-fL', '--proto', '=https', '--proto-redir', '=https', '--silent', '--show-error', '--connect-timeout', '30', '--max-time', '900', '-o', zip, opDiretoUrl(d.arch)]);
|
|
147
|
+
if (!baixou.ok || !fs.existsSync(zip)) { d.out.err('Nao consegui baixar o 1Password CLI oficial (internet?).'); return false; }
|
|
148
|
+
const obtido = crypto.createHash('sha256').update(fs.readFileSync(zip)).digest('hex');
|
|
149
|
+
if (obtido !== esperado) { d.out.err('O arquivo baixado do 1Password CLI nao confere (SHA-256 diferente); nao instalei nada.'); return false; }
|
|
150
|
+
fs.mkdirSync(aberto, { recursive: true });
|
|
151
|
+
const abriu = d.run('/usr/bin/ditto', ['-x', '-k', zip, aberto]);
|
|
152
|
+
const novo = path.join(aberto, 'op');
|
|
153
|
+
if (!abriu.ok || !fs.existsSync(novo)) { d.out.err('Nao consegui abrir o pacote do 1Password CLI.'); return false; }
|
|
154
|
+
if (!assinadoPelaAgilebits(novo, d.run)) { d.out.err('O 1Password CLI baixado nao tem a assinatura da AgileBits; nao instalei.'); return false; }
|
|
155
|
+
fs.mkdirSync(destino, { recursive: true });
|
|
156
|
+
const final = path.join(destino, 'op');
|
|
157
|
+
const provisorio = path.join(destino, `.op.auroq-${process.pid}.tmp`);
|
|
158
|
+
fs.copyFileSync(novo, provisorio);
|
|
159
|
+
fs.chmodSync(provisorio, 0o755);
|
|
160
|
+
fs.renameSync(provisorio, final);
|
|
161
|
+
d.run('/usr/bin/xattr', ['-d', 'com.apple.quarantine', final]); // melhor esforco: curl nao marca quarentena
|
|
162
|
+
refreshPath({ platform: 'darwin', home: d.home });
|
|
163
|
+
return true;
|
|
164
|
+
} catch (e) {
|
|
165
|
+
d.out.err(`Nao consegui instalar o 1Password CLI em ${destino} (${oneLine(e && e.message, 120)}).`);
|
|
166
|
+
return false;
|
|
167
|
+
} finally {
|
|
168
|
+
if (tmp) { try { fs.rmSync(tmp, { recursive: true, force: true }); } catch { /* fica no temp do sistema */ } }
|
|
87
169
|
}
|
|
88
170
|
}
|
|
89
171
|
|
|
90
172
|
function installOp({ upgrade = false } = {}) {
|
|
91
173
|
if (process.platform === 'darwin') {
|
|
92
|
-
if (!hasCommand('brew'))
|
|
93
|
-
err('Homebrew nao encontrado. Instale em https://brew.sh e rode este comando de novo.');
|
|
94
|
-
return false;
|
|
95
|
-
}
|
|
174
|
+
if (!hasCommand('brew')) return installOpDirect();
|
|
96
175
|
log(`${DIM}${upgrade ? 'Atualizando' : 'Instalando'} via Homebrew (pode levar um minuto)...${RESET}`);
|
|
97
176
|
const brewCmd = upgrade ? 'brew upgrade --cask 1password-cli' : 'brew install --cask 1password-cli';
|
|
98
177
|
try {
|
|
99
178
|
execSync(brewCmd, { stdio: 'pipe', maxBuffer: 64 * 1024 * 1024, env: opEnv() });
|
|
100
179
|
return true;
|
|
101
180
|
} catch {
|
|
102
|
-
|
|
103
|
-
return
|
|
181
|
+
warn(`${upgrade ? 'Atualizacao' : 'Instalacao'} via Homebrew falhou; vou usar o pacote oficial do 1Password.`);
|
|
182
|
+
return installOpDirect();
|
|
104
183
|
}
|
|
105
184
|
}
|
|
106
185
|
|
|
@@ -395,6 +474,7 @@ async function connectManual() {
|
|
|
395
474
|
|
|
396
475
|
// 1. Garantir que o op existe
|
|
397
476
|
step('Verificando 1Password CLI...');
|
|
477
|
+
refreshPath();
|
|
398
478
|
let version = opVersion();
|
|
399
479
|
if (!version) {
|
|
400
480
|
warn('1Password CLI (op) nao encontrado — instalando...');
|
|
@@ -708,9 +788,21 @@ function runOp(args, { env, input, timeoutMs = 120000, noStdin = false } = {}) {
|
|
|
708
788
|
// `noStdin`: o `op` recusa `--template` se o stdin for um pipe, ate vazio ("You can't use both piping and the
|
|
709
789
|
// --template flag"; o `input: ''` do Node vira pipe), entao esse comando roda com o stdin desligado (NUL/dev/null).
|
|
710
790
|
const useTerminal = input === undefined && !noStdin && Boolean(process.stdin.isTTY);
|
|
711
|
-
const
|
|
791
|
+
const viaPowerShell = process.platform === 'win32';
|
|
792
|
+
// No Windows, o op 2.41.1 lancado diretamente pelo Node falha antes de pedir sessao ao app.
|
|
793
|
+
// Node -> PowerShell -> op foi conferido no computador do aluno; JSON evita quoting de shell.
|
|
794
|
+
const psScript = '$OutputEncoding=New-Object System.Text.UTF8Encoding $false; [Console]::OutputEncoding=$OutputEncoding; '
|
|
795
|
+
+ '$a=@($env:AUROQ_OP_ARGS | ConvertFrom-Json); '
|
|
796
|
+
+ "if ($env:AUROQ_OP_STDIN -eq '1') { $s=[Console]::In.ReadToEnd(); $s | & op @a } else { & op @a }; exit $LASTEXITCODE";
|
|
797
|
+
const childEnv = env || opEnv();
|
|
798
|
+
const r = spawnSync(viaPowerShell ? 'powershell.exe' : 'op',
|
|
799
|
+
viaPowerShell ? ['-NoProfile', '-NonInteractive', '-Command', psScript] : args, {
|
|
712
800
|
encoding: 'utf8',
|
|
713
|
-
env:
|
|
801
|
+
env: viaPowerShell ? {
|
|
802
|
+
...childEnv,
|
|
803
|
+
AUROQ_OP_ARGS: JSON.stringify(args),
|
|
804
|
+
AUROQ_OP_STDIN: input !== undefined && input !== '' ? '1' : '0',
|
|
805
|
+
} : childEnv,
|
|
714
806
|
...(noStdin ? { stdio: ['ignore', 'pipe', 'pipe'] } : useTerminal ? { stdio: ['inherit', 'pipe', 'pipe'] } : { input: input === undefined ? '' : input }),
|
|
715
807
|
timeout: timeoutMs,
|
|
716
808
|
maxBuffer: 16 * 1024 * 1024,
|
|
@@ -777,6 +869,17 @@ function openUrl(url) {
|
|
|
777
869
|
* Windows: o winget so muda o PATH no registro, nao no processo que ja esta rodando. Recompoe o
|
|
778
870
|
* PATH deste processo (maquina + usuario + pasta de links do winget) para achar o `op` recem-instalado.
|
|
779
871
|
*/
|
|
872
|
+
/**
|
|
873
|
+
* Recompõe o PATH deste processo para achar um `op` instalado depois que ele abriu. Mac/Linux: a pasta do `op`
|
|
874
|
+
* instalado sem Homebrew (~/.auroq/op/bin), se existir. Windows: o PATH do registro (o winget so muda o registro).
|
|
875
|
+
*/
|
|
876
|
+
function refreshPath({ platform = process.platform, home = os.homedir() } = {}) {
|
|
877
|
+
if (platform === 'win32') return refreshWindowsPath();
|
|
878
|
+
const bin = auroqOpBin(home);
|
|
879
|
+
const atual = String(process.env.PATH || '').split(':');
|
|
880
|
+
if (!atual.includes(bin) && fs.existsSync(path.join(bin, 'op'))) process.env.PATH = [bin, ...atual.filter(Boolean)].join(':');
|
|
881
|
+
}
|
|
882
|
+
|
|
780
883
|
function refreshWindowsPath() {
|
|
781
884
|
if (process.platform !== 'win32') return;
|
|
782
885
|
const parts = [];
|
|
@@ -1011,23 +1114,82 @@ function makeAppDeps() {
|
|
|
1011
1114
|
lock: makeLock(),
|
|
1012
1115
|
hasCommand,
|
|
1013
1116
|
appInstalled: () => appInstalled(),
|
|
1014
|
-
refreshPath
|
|
1117
|
+
refreshPath,
|
|
1015
1118
|
run: runProgram,
|
|
1016
1119
|
runInstaller: runInstallerProgram,
|
|
1017
1120
|
onInterrupt: onInterruptCleanup,
|
|
1018
1121
|
sweepStale: () => sweepStaleAppDirs(),
|
|
1019
1122
|
download: downloadToFile,
|
|
1020
1123
|
checkSignature: checkInstallerSignature,
|
|
1124
|
+
macAppDirect: () => installMacAppDirect(),
|
|
1021
1125
|
mkdtemp: () => fs.mkdtempSync(path.join(os.tmpdir(), APP_TEMP_PREFIX)),
|
|
1022
1126
|
out: { log, step, ok, warn, err },
|
|
1023
1127
|
};
|
|
1024
1128
|
}
|
|
1025
1129
|
|
|
1130
|
+
// App do 1Password para Mac: o zip oficial do app inteiro (o mesmo arquivo que o Homebrew baixa, sem fixar versao).
|
|
1131
|
+
const MAC_APP_URL = (arch) => `https://downloads.1password.com/mac/1Password-latest-${arch === 'arm64' ? 'aarch64' : 'x86_64'}.zip`;
|
|
1132
|
+
|
|
1133
|
+
/**
|
|
1134
|
+
* Mac sem Homebrew: baixa o app oficial, confere a assinatura da AgileBits (Team ID e `codesign --deep`) e copia para
|
|
1135
|
+
* /Applications (o aluno administrador do Mac grava ali sem senha) ou, sem permissao, para ~/Applications.
|
|
1136
|
+
* Nunca lanca. { ok, motivo, destino }. `deps` so existe para os testes.
|
|
1137
|
+
*/
|
|
1138
|
+
async function installMacAppDirect(deps = {}) {
|
|
1139
|
+
const d = {
|
|
1140
|
+
arch: process.arch,
|
|
1141
|
+
home: os.homedir(),
|
|
1142
|
+
run: (cmd, args, o) => runProgram(cmd, args, o),
|
|
1143
|
+
download: downloadToFile,
|
|
1144
|
+
mkdtemp: () => fs.mkdtempSync(path.join(os.tmpdir(), APP_TEMP_PREFIX)),
|
|
1145
|
+
gravavel: (dir) => { try { fs.accessSync(dir, fs.constants.W_OK); return true; } catch { return false; } },
|
|
1146
|
+
aplicativos: '/Applications',
|
|
1147
|
+
out: { log },
|
|
1148
|
+
...deps,
|
|
1149
|
+
};
|
|
1150
|
+
let dir = null;
|
|
1151
|
+
let provisorio = null;
|
|
1152
|
+
try {
|
|
1153
|
+
dir = d.mkdtemp();
|
|
1154
|
+
const zip = path.join(dir, '1Password.zip');
|
|
1155
|
+
const aberto = path.join(dir, 'aberto');
|
|
1156
|
+
d.out.log(`${DIM}Baixando o app oficial do 1Password (uns 220 MB, pode levar alguns minutos)...${RESET}`);
|
|
1157
|
+
try {
|
|
1158
|
+
await d.download(MAC_APP_URL(d.arch), zip);
|
|
1159
|
+
} catch (e) {
|
|
1160
|
+
return { ok: false, motivo: `Nao consegui baixar o app oficial (${oneLine(e && e.message, 120)}).` };
|
|
1161
|
+
}
|
|
1162
|
+
fs.mkdirSync(aberto, { recursive: true });
|
|
1163
|
+
const abriu = d.run('/usr/bin/ditto', ['-x', '-k', zip, aberto]);
|
|
1164
|
+
const app = path.join(aberto, '1Password.app');
|
|
1165
|
+
if (!abriu.ok || !fs.existsSync(app)) return { ok: false, motivo: 'Nao consegui abrir o pacote do app.' };
|
|
1166
|
+
if (!assinadoPelaAgilebits(app, d.run, { deep: true })) return { ok: false, motivo: 'O app baixado nao tem a assinatura da AgileBits; nao instalei.' };
|
|
1167
|
+
const pasta = d.gravavel(d.aplicativos) ? d.aplicativos : path.join(d.home, 'Applications');
|
|
1168
|
+
fs.mkdirSync(pasta, { recursive: true });
|
|
1169
|
+
const destino = path.join(pasta, '1Password.app');
|
|
1170
|
+
// copia para um nome provisorio na mesma pasta, confere a COPIA e so entao poe o nome final: uma copia pela metade
|
|
1171
|
+
// nunca fica com cara de app instalado (o appInstalled olha so se a pasta existe)
|
|
1172
|
+
provisorio = path.join(pasta, `.1Password.app.auroq-${process.pid}.tmp`);
|
|
1173
|
+
const copiou = d.run('/usr/bin/ditto', [app, provisorio]);
|
|
1174
|
+
if (!copiou.ok) return { ok: false, motivo: `Nao consegui copiar o app para ${pasta}.` };
|
|
1175
|
+
if (!assinadoPelaAgilebits(provisorio, d.run, { deep: true })) return { ok: false, motivo: `A copia do app em ${pasta} nao passou na conferencia da assinatura; nao instalei.` };
|
|
1176
|
+
fs.renameSync(provisorio, destino);
|
|
1177
|
+
provisorio = null;
|
|
1178
|
+
return { ok: true, destino };
|
|
1179
|
+
} catch (e) {
|
|
1180
|
+
return { ok: false, motivo: `Nao consegui instalar o app (${oneLine(e && e.message, 120)}).` };
|
|
1181
|
+
} finally {
|
|
1182
|
+
if (provisorio) { try { fs.rmSync(provisorio, { recursive: true, force: true }); } catch { /* sobra so uma pasta oculta */ } }
|
|
1183
|
+
if (dir) { try { fs.rmSync(dir, { recursive: true, force: true }); } catch { /* fica no temp; a proxima execucao varre */ } }
|
|
1184
|
+
}
|
|
1185
|
+
}
|
|
1186
|
+
|
|
1026
1187
|
const APP_NEXT_STEPS = 'Agora abra o app do 1Password, entre na sua conta (ou crie uma: guarde a Secret Key e o Kit de Emergencia que ele oferece) e ligue "Integrar com a CLI do 1Password" em Configuracoes > Desenvolvedor. Depois rode o conectar-1password de novo.';
|
|
1027
1188
|
|
|
1028
1189
|
/**
|
|
1029
1190
|
* Instala o app do 1Password (`conectar-1password --instalar-app`). Windows: winget e, se ele falhar, o instalador
|
|
1030
|
-
* oficial, so rodado depois de conferir a assinatura (valida e do publicador Agilebits). Mac: Homebrew (cask)
|
|
1191
|
+
* oficial, so rodado depois de conferir a assinatura (valida e do publicador Agilebits). Mac: Homebrew (cask), se o aluno
|
|
1192
|
+
* tiver; senao (ou se ele falhar), o pacote oficial com a assinatura da AgileBits conferida (installMacAppDirect).
|
|
1031
1193
|
* O app e um programa novo no computador do aluno: quem chama pede o OK dele antes.
|
|
1032
1194
|
*/
|
|
1033
1195
|
async function installApp(deps = {}) {
|
|
@@ -1053,11 +1215,16 @@ async function installApp(deps = {}) {
|
|
|
1053
1215
|
};
|
|
1054
1216
|
|
|
1055
1217
|
if (d.platform === 'darwin') {
|
|
1056
|
-
if (
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1218
|
+
if (d.hasCommand('brew')) {
|
|
1219
|
+
out.log(`${DIM}Instalando via Homebrew (pode levar um minuto)...${RESET}`);
|
|
1220
|
+
const r = d.run('brew', ['install', '--cask', '1password']);
|
|
1221
|
+
if (r.ok || d.appInstalled()) return pronto('Homebrew');
|
|
1222
|
+
out.warn(`A instalacao via Homebrew falhou (${r.timedOut ? 'demorou demais' : `codigo de saida ${r.status}`}). Vou usar o pacote oficial do 1Password.`);
|
|
1223
|
+
}
|
|
1224
|
+
// Mac de aluno nao tem Homebrew (e instalar o Homebrew pede senha de admin): pacote oficial, assinatura conferida.
|
|
1225
|
+
const m = await d.macAppDirect();
|
|
1226
|
+
if (m.ok) return pronto('pacote oficial do 1Password');
|
|
1227
|
+
return falhou(m.motivo || 'Nao consegui instalar o app pelo pacote oficial.');
|
|
1061
1228
|
}
|
|
1062
1229
|
|
|
1063
1230
|
// Windows 1: winget (rapido, mas falhou no teste real com 0x80070002 mesmo depois de conferir o hash)
|
|
@@ -1261,7 +1428,7 @@ function makeDefaultDeps() {
|
|
|
1261
1428
|
return {
|
|
1262
1429
|
platform: process.platform,
|
|
1263
1430
|
openUrl,
|
|
1264
|
-
refreshPath
|
|
1431
|
+
refreshPath,
|
|
1265
1432
|
appInstalled: () => appInstalled(),
|
|
1266
1433
|
lock: makeLock(),
|
|
1267
1434
|
state: { read: readState, write: writeState },
|
|
@@ -1875,6 +2042,7 @@ async function finishWithToken(d, out, account, token, prog, { reaproveitada, ol
|
|
|
1875
2042
|
function describeState(d) {
|
|
1876
2043
|
const saved = d.state.read();
|
|
1877
2044
|
const etapas = saved ? { ...saved.etapas } : emptyEtapas();
|
|
2045
|
+
if (typeof d.refreshPath === 'function') d.refreshPath(); // Mac sem Homebrew: o op mora em ~/.auroq/op/bin
|
|
1878
2046
|
const version = d.opVersion();
|
|
1879
2047
|
const opOk = Boolean(version && isVersionAtLeast(version));
|
|
1880
2048
|
etapas.op = opOk ? 'feito' : 'pendente';
|
|
@@ -2013,6 +2181,7 @@ module.exports = {
|
|
|
2013
2181
|
sweepStaleAppDirs,
|
|
2014
2182
|
checkInstallerSignature,
|
|
2015
2183
|
writeTemplateFile,
|
|
2184
|
+
runOp,
|
|
2016
2185
|
APP_INSTALLER_URL,
|
|
2017
2186
|
ETAPAS,
|
|
2018
2187
|
makeLock,
|
|
@@ -2026,6 +2195,11 @@ module.exports = {
|
|
|
2026
2195
|
auroqDir,
|
|
2027
2196
|
openUrl,
|
|
2028
2197
|
refreshWindowsPath,
|
|
2198
|
+
refreshPath,
|
|
2199
|
+
installOpDirect,
|
|
2200
|
+
installMacAppDirect,
|
|
2201
|
+
auroqOpBin,
|
|
2202
|
+
OP_DIRETO,
|
|
2029
2203
|
runOp,
|
|
2030
2204
|
TOKEN_VAR,
|
|
2031
2205
|
MIN_OP_VERSION,
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"schema": 1,
|
|
3
3
|
"algorithm": "sha256",
|
|
4
4
|
"scope": "packaged-runtime-and-cascas",
|
|
5
|
-
"version": "2.8.
|
|
5
|
+
"version": "2.8.9",
|
|
6
6
|
"files": [
|
|
7
7
|
{
|
|
8
8
|
"path": ".auroq-core/constitution.md",
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
},
|
|
11
11
|
{
|
|
12
12
|
"path": ".auroq-core/core-config.yaml",
|
|
13
|
-
"sha256": "
|
|
13
|
+
"sha256": "7eeba357e5203bb8d0d9ade5d4a53ecfa99d7edd05212a5625b59d6425f641f4"
|
|
14
14
|
},
|
|
15
15
|
{
|
|
16
16
|
"path": ".auroq-core/core/synapse/context/context-builder.js",
|
|
@@ -206,7 +206,7 @@
|
|
|
206
206
|
},
|
|
207
207
|
{
|
|
208
208
|
"path": ".claude/settings.json",
|
|
209
|
-
"sha256": "
|
|
209
|
+
"sha256": "57c338e326586805e605229f7bcec699a52b99a113b153d06a209084e0c0fa4c"
|
|
210
210
|
},
|
|
211
211
|
{
|
|
212
212
|
"path": ".claude/settings.local.json",
|
|
@@ -214,7 +214,7 @@
|
|
|
214
214
|
},
|
|
215
215
|
{
|
|
216
216
|
"path": "bin/auroq-os.js",
|
|
217
|
-
"sha256": "
|
|
217
|
+
"sha256": "4d3bd746dc2eb4c0e0a3cce30f2bed16d41af4230645fb0f7ef4f3ae6f5b485a"
|
|
218
218
|
},
|
|
219
219
|
{
|
|
220
220
|
"path": "lib/ahi/client.mjs",
|
|
@@ -254,7 +254,7 @@
|
|
|
254
254
|
},
|
|
255
255
|
{
|
|
256
256
|
"path": "lib/cofre.js",
|
|
257
|
-
"sha256": "
|
|
257
|
+
"sha256": "a7142a3a49e7cb71f4927d567fa834b838c19987f12bd1d7fe02e1cb744378c1"
|
|
258
258
|
},
|
|
259
259
|
{
|
|
260
260
|
"path": "lib/credentials.js",
|
|
@@ -282,7 +282,7 @@
|
|
|
282
282
|
},
|
|
283
283
|
{
|
|
284
284
|
"path": "lib/onepassword.js",
|
|
285
|
-
"sha256": "
|
|
285
|
+
"sha256": "34ce88cb11b2fc9bd52905acc19903430df88db5c94b3ed9bc1000bfb1f4a666"
|
|
286
286
|
},
|
|
287
287
|
{
|
|
288
288
|
"path": "lib/supabase.js",
|
|
@@ -298,7 +298,7 @@
|
|
|
298
298
|
},
|
|
299
299
|
{
|
|
300
300
|
"path": "package.json",
|
|
301
|
-
"sha256": "
|
|
301
|
+
"sha256": "0f06b1ac3cb3201dd3f21c3ea980b47ba637fd40a300534d07610de091f54e6b"
|
|
302
302
|
},
|
|
303
303
|
{
|
|
304
304
|
"path": "scripts/build-pack.mjs",
|
|
@@ -318,7 +318,7 @@
|
|
|
318
318
|
},
|
|
319
319
|
{
|
|
320
320
|
"path": "scripts/runtime-integrity.mjs",
|
|
321
|
-
"sha256": "
|
|
321
|
+
"sha256": "7d7ed4a01df802f5421efff0444b4c399f1408c380c7084114987d4c75e313a5"
|
|
322
322
|
},
|
|
323
323
|
{
|
|
324
324
|
"path": "scripts/sync-codex-skills.mjs",
|
package/package.json
CHANGED
|
@@ -109,8 +109,10 @@ function verifyReferences(root, paths) {
|
|
|
109
109
|
const settings = JSON.parse(fs.readFileSync(checkedFile(root, source), 'utf8'));
|
|
110
110
|
for (const groups of Object.values(settings.hooks || {})) {
|
|
111
111
|
for (const group of groups) for (const hook of group.hooks || []) {
|
|
112
|
-
const
|
|
113
|
-
|
|
112
|
+
const shellPath = typeof hook.command === 'string' && hook.command.match(/^node\s+(\.claude\/hooks\/[^\s]+)(?:\s|$)/)?.[1];
|
|
113
|
+
const execPath = hook.command === 'node' && Array.isArray(hook.args)
|
|
114
|
+
&& hook.args[0]?.match(/^\$\{CLAUDE_PROJECT_DIR\}\/(\.claude\/hooks\/[^\s]+)$/)?.[1];
|
|
115
|
+
if (shellPath || execPath) checkedFile(root, shellPath || execPath);
|
|
114
116
|
}
|
|
115
117
|
}
|
|
116
118
|
}
|