auroq-os 2.8.7 → 2.9.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/.auroq-core/core-config.yaml +1 -1
- package/.claude/settings.json +6 -3
- package/AGENTS.md +5 -4
- package/CHANGELOG.md +2 -0
- package/README.md +3 -3
- package/bin/auroq-os.js +17 -51
- package/installer/install.ps1 +2 -2
- package/installer/install.sh +2 -2
- package/lib/cofre.js +11 -4
- package/lib/onepassword.js +17 -7
- package/lib/runtime-integrity.json +9 -9
- package/package.json +1 -1
- package/scripts/runtime-integrity.mjs +4 -2
- package/scripts/sync-codex-skills.mjs +3 -12
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/AGENTS.md
CHANGED
|
@@ -15,15 +15,16 @@ Se alguma instrução antiga desta pasta contradisser estas regras, valem estas.
|
|
|
15
15
|
|
|
16
16
|
## Como o sistema funciona
|
|
17
17
|
|
|
18
|
-
1. Esta pasta é
|
|
18
|
+
1. Esta pasta é o ponto inicial ou o projeto central da memória. Depois da organização aprovada pelo aluno, cada projeto tem pasta, Git e cópia privada próprios; os outros projetos não ficam dentro desta pasta.
|
|
19
19
|
2. O **Companion** é o chefe da equipe. O aluno fala com ele; ele entende o pedido, escolhe quem faz e entrega.
|
|
20
20
|
3. A equipe (squads, skills, Consultor, forjas e o próprio Companion) chega ao vivo pelo MCP `arcane`,
|
|
21
21
|
catálogos `auroq-core` e `arcane-pack`. Nunca procurar esse conteúdo em `agents/`.
|
|
22
22
|
4. Não existe técnico à parte: o Companion também instala, atualiza, conserta e conecta ferramentas, pelas
|
|
23
23
|
skills técnicas dele (`conserto-tecnico`, `salvar-e-sincronizar`, `publicar-site`, `atualizar-sistema`,
|
|
24
24
|
`configurar-computador`, `conectar-cofre`, `companion-externo`). O antigo Ops foi aposentado para o aluno.
|
|
25
|
-
5.
|
|
26
|
-
|
|
25
|
+
5. A memória do Companion mora no projeto central em `agents/companion/data/` (onde paramos, decisões,
|
|
26
|
+
pendências e apelido), com conhecimento em `docs/knowledge/`. Cada outro projeto guarda seu próprio
|
|
27
|
+
trabalho e tracker; o Companion encontra a memória central mesmo quando a conversa começa nele.
|
|
27
28
|
6. Salvar é commit; entregar é mandar para o GitHub privado do aluno.
|
|
28
29
|
7. Não precisa decorar comando: o aluno fala do jeito dele. Atalhos existem (Claude: `/auroq-companion`,
|
|
29
30
|
`/auroq-consultor`; Codex: `$companion`, `$consultor`).
|
|
@@ -179,7 +180,7 @@ mesma resposta que essa parte não foi feita e por quê; nunca pule em silêncio
|
|
|
179
180
|
|
|
180
181
|
## Privacidade
|
|
181
182
|
|
|
182
|
-
Sua memória e seus documentos ficam na sua máquina e no seu GitHub
|
|
183
|
+
Sua memória e seus documentos ficam na sua máquina e nas cópias privadas de cada projeto no seu GitHub (senhas e chaves ficam só no seu cofre, o 1Password ou, se você escolheu o grátis, o Infisical; `business/vault/` guarda apenas status e referências, nunca o valor). O histórico das sessões com os squads está previsto nos Termos de Uso: vem ligado para quem aceita os termos na plataforma (quem já tinha dito "não" continua sem gravar) e você desliga quando quiser em Minha Conta, "Guardar minhas conversas". Se um projeto tem dados de clientes, desligue. Além disso, a Arka registra qual conteúdo licenciado foi entregue, quando e pra qual conta — igual a uma nota de entrega.
|
|
183
184
|
|
|
184
185
|
## Onde o aluno customiza
|
|
185
186
|
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
## Unreleased
|
|
2
2
|
|
|
3
|
+
- 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.
|
|
4
|
+
|
|
3
5
|
- 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
6
|
- 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
7
|
- 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.8 doctor` mostra a fila local segura e os comandos pinados de
|
|
294
|
+
manutencao/diagnostico. `npx -y auroq-os@2.8.8 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.8; 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
|
|
|
@@ -433,31 +434,8 @@ const HEALTH_CHECKS = [
|
|
|
433
434
|
['scripts/validate-hybrid.mjs', 'Validador hibrido'],
|
|
434
435
|
];
|
|
435
436
|
|
|
436
|
-
/**
|
|
437
|
-
* Ate 21/10/2026 o aluno dava um nome ao Companion no bootstrap (FASE 10 do Ops, que saiu:
|
|
438
|
-
* "Companion e Companion"), e quem deu continua com ele: `/atlas-companion`. Um
|
|
439
|
-
* comando com esse nome que ainda aponta pro Companion (recurso `companion` do MCP ou a
|
|
440
|
-
* pasta agents/companion/) vale como a casca dele — um clone do negocio que so tem o
|
|
441
|
-
* comando com o nome do aluno nao pode ser acusado de "arquivo faltando". So o Companion
|
|
442
|
-
* tem essa folga: os outros arquivos continuam exigidos pelo caminho exato.
|
|
443
|
-
*/
|
|
444
|
-
async function companionComNomeDoAluno(targetDir) {
|
|
445
|
-
const dir = path.join(targetDir, '.claude', 'commands');
|
|
446
|
-
let nomes = [];
|
|
447
|
-
try { nomes = await fs.readdir(dir); } catch { return null; }
|
|
448
|
-
for (const nome of nomes.filter(n => /^[a-z0-9-]+-companion\.md$/.test(n)).sort()) {
|
|
449
|
-
try {
|
|
450
|
-
const texto = await fs.readFile(path.join(dir, nome), 'utf8');
|
|
451
|
-
if (/recurso_id\s*`?companion`?/.test(texto) || /agents\/companion\//.test(texto)) return `.claude/commands/${nome}`;
|
|
452
|
-
} catch { /* ilegivel: nao conta */ }
|
|
453
|
-
}
|
|
454
|
-
return null;
|
|
455
|
-
}
|
|
456
|
-
|
|
457
437
|
async function checagemPresente(targetDir, file) {
|
|
458
|
-
|
|
459
|
-
if (file === '.claude/commands/auroq-companion.md') return Boolean(await companionComNomeDoAluno(targetDir));
|
|
460
|
-
return false;
|
|
438
|
+
return fs.pathExists(path.join(targetDir, file));
|
|
461
439
|
}
|
|
462
440
|
|
|
463
441
|
/**
|
|
@@ -1669,11 +1647,11 @@ async function init({ pasta = null, maintenance = false, modoAgente = false, mig
|
|
|
1669
1647
|
error('');
|
|
1670
1648
|
error('Crie uma pasta pro seu projeto e rode o comando de dentro dela:');
|
|
1671
1649
|
error('');
|
|
1672
|
-
error(` ${CYAN}mkdir
|
|
1673
|
-
error(` ${CYAN}cd
|
|
1650
|
+
error(` ${CYAN}mkdir primeiro-passo${RESET}`);
|
|
1651
|
+
error(` ${CYAN}cd primeiro-passo${RESET}`);
|
|
1674
1652
|
error(` ${CYAN}npx auroq-os@latest instalar${RESET}`);
|
|
1675
1653
|
error('');
|
|
1676
|
-
error('
|
|
1654
|
+
error('Depois, o Companion ajuda a criar os projetos separados.');
|
|
1677
1655
|
throw falhaMarcada('pasta', 'Esta e a pasta pessoal do usuario, nao a de um negocio. Rode na pasta do negocio.', { jaMostrado: true });
|
|
1678
1656
|
}
|
|
1679
1657
|
|
|
@@ -1698,7 +1676,8 @@ async function init({ pasta = null, maintenance = false, modoAgente = false, mig
|
|
|
1698
1676
|
}
|
|
1699
1677
|
}
|
|
1700
1678
|
}
|
|
1701
|
-
|
|
1679
|
+
const primeiroPasso = isNewInstall && process.env.AUROQ_INIT_MODE !== 'novo';
|
|
1680
|
+
if (isNewInstall && !['novo', 'primeiro-passo'].includes(process.env.AUROQ_INIT_MODE)) {
|
|
1702
1681
|
const jaUsa = await askYesNo(` Voce JA usa o Auroq OS em outra maquina e quer continuar o MESMO negocio aqui? ${DIM}(s/N)${RESET} `);
|
|
1703
1682
|
if (jaUsa) {
|
|
1704
1683
|
log('');
|
|
@@ -1800,7 +1779,7 @@ async function init({ pasta = null, maintenance = false, modoAgente = false, mig
|
|
|
1800
1779
|
'scripts',
|
|
1801
1780
|
];
|
|
1802
1781
|
|
|
1803
|
-
for (const dir of dirs) {
|
|
1782
|
+
for (const dir of dirs.filter(dir => !primeiroPasso || !dir.startsWith('business/'))) {
|
|
1804
1783
|
await fs.ensureDir(path.join(targetDir, dir));
|
|
1805
1784
|
}
|
|
1806
1785
|
success(`${dirs.length} pastas criadas`);
|
|
@@ -1945,20 +1924,6 @@ async function init({ pasta = null, maintenance = false, modoAgente = false, mig
|
|
|
1945
1924
|
'business/cockpit.md',
|
|
1946
1925
|
];
|
|
1947
1926
|
|
|
1948
|
-
// Detectar se ja existe companion personalizado (ex: taquion-companion.md)
|
|
1949
|
-
// Se existir, NAO copiar companion.md generico pra nao duplicar
|
|
1950
|
-
const commandsDir = path.join(targetDir, '.claude', 'commands');
|
|
1951
|
-
let hasCustomCompanion = false;
|
|
1952
|
-
if (await fs.pathExists(commandsDir)) {
|
|
1953
|
-
const cmdFiles = await fs.readdir(commandsDir);
|
|
1954
|
-
hasCustomCompanion = cmdFiles.some(f => f.endsWith('-companion.md') && f !== 'companion.md');
|
|
1955
|
-
if (hasCustomCompanion) {
|
|
1956
|
-
const customName = cmdFiles.find(f => f.endsWith('-companion.md') && f !== 'companion.md');
|
|
1957
|
-
log(`${DIM} Companion personalizado detectado: ${customName} — pulando companion.md generico${RESET}`);
|
|
1958
|
-
}
|
|
1959
|
-
|
|
1960
|
-
}
|
|
1961
|
-
|
|
1962
1927
|
// Pastas e comandos antigos pertencem ao aluno. Nunca excluir na manutencao.
|
|
1963
1928
|
|
|
1964
1929
|
// Atalhos do Pack Arcane. O conteudo chega ao vivo pelo MCP, mas o /comando
|
|
@@ -2009,10 +1974,7 @@ async function init({ pasta = null, maintenance = false, modoAgente = false, mig
|
|
|
2009
1974
|
let copied = 0;
|
|
2010
1975
|
let claudeMd = null;
|
|
2011
1976
|
for (const file of frameworkFiles) {
|
|
2012
|
-
|
|
2013
|
-
if (file === '.claude/commands/companion.md' && hasCustomCompanion) {
|
|
2014
|
-
continue;
|
|
2015
|
-
}
|
|
1977
|
+
if (primeiroPasso && file.startsWith('business/') && file !== 'business/cockpit.md') continue;
|
|
2016
1978
|
const src = path.join(sourceDir, file);
|
|
2017
1979
|
const dst = path.join(targetDir, file);
|
|
2018
1980
|
if (await fs.pathExists(src)) {
|
|
@@ -2062,7 +2024,11 @@ async function init({ pasta = null, maintenance = false, modoAgente = false, mig
|
|
|
2062
2024
|
|
|
2063
2025
|
const seedRoot = path.join(sourceDir, 'seeds');
|
|
2064
2026
|
if (await fs.pathExists(seedRoot)) {
|
|
2065
|
-
await fs.copy(seedRoot, targetDir, {
|
|
2027
|
+
await fs.copy(seedRoot, targetDir, {
|
|
2028
|
+
overwrite: false,
|
|
2029
|
+
filter: src => !primeiroPasso || !path.relative(seedRoot, src).startsWith(`business${path.sep}campanhas`)
|
|
2030
|
+
&& !path.relative(seedRoot, src).startsWith(`business${path.sep}templates`),
|
|
2031
|
+
});
|
|
2066
2032
|
success('Semente do aluno instalada (memoria, docs, cockpit — nunca sobrescreve)');
|
|
2067
2033
|
}
|
|
2068
2034
|
// ─── Fase 4: Synapse Engine (troca versao oficial antiga; guarda o que foi mexido a mao).
|
|
@@ -2114,9 +2080,9 @@ async function init({ pasta = null, maintenance = false, modoAgente = false, mig
|
|
|
2114
2080
|
const pkgPath = path.join(targetDir, 'package.json');
|
|
2115
2081
|
if (!(await fs.pathExists(pkgPath))) {
|
|
2116
2082
|
await fs.writeJSON(pkgPath, {
|
|
2117
|
-
name: '
|
|
2083
|
+
name: primeiroPasso ? 'primeiro-passo' : path.basename(targetDir).toLowerCase().replace(/[^a-z0-9-]+/g, '-') || 'projeto-auroq',
|
|
2118
2084
|
version: '1.0.0',
|
|
2119
|
-
description: '
|
|
2085
|
+
description: primeiroPasso ? 'Ponto de partida para organizar os projetos com o Companion' : 'Projeto com Auroq OS',
|
|
2120
2086
|
private: true,
|
|
2121
2087
|
dependencies: {
|
|
2122
2088
|
'js-yaml': '^4.1.0',
|
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.
|
|
592
|
+
& (Get-AuroqNpx) -y auroq-os@2.9.0 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.
|
|
680
|
+
& (Get-AuroqNpx) -y auroq-os@2.9.0 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.
|
|
222
|
+
npx -y auroq-os@2.9.0 "$@"
|
|
223
223
|
else
|
|
224
|
-
npx -y auroq-os@2.
|
|
224
|
+
npx -y auroq-os@2.9.0 "$@" < /dev/tty
|
|
225
225
|
fi
|
|
226
226
|
}
|
|
227
227
|
|
package/lib/cofre.js
CHANGED
|
@@ -155,7 +155,7 @@ function lockIsStale(file, staleMs) {
|
|
|
155
155
|
}
|
|
156
156
|
}
|
|
157
157
|
|
|
158
|
-
/** 'ok' (peguei)
|
|
158
|
+
/** 'ok' (peguei) ou 'ocupada' (outro comando segura ou o Windows ainda nao liberou o arquivo). */
|
|
159
159
|
function tryLock(file, nonce, staleMs) {
|
|
160
160
|
for (let attempt = 0; attempt < 3; attempt++) {
|
|
161
161
|
try {
|
|
@@ -163,7 +163,10 @@ function tryLock(file, nonce, staleMs) {
|
|
|
163
163
|
try { fs.writeSync(fd, JSON.stringify({ pid: process.pid, at: Date.now(), nonce })); } finally { fs.closeSync(fd); }
|
|
164
164
|
return 'ok';
|
|
165
165
|
} catch (e) {
|
|
166
|
-
if (e.code !== 'EEXIST')
|
|
166
|
+
if (e.code !== 'EEXIST') {
|
|
167
|
+
if (['EACCES', 'EPERM', 'EBUSY'].includes(e.code)) return 'ocupada';
|
|
168
|
+
throw e;
|
|
169
|
+
}
|
|
167
170
|
if (!lockIsStale(file, staleMs)) return 'ocupada';
|
|
168
171
|
tomarVelha(file, staleMs);
|
|
169
172
|
}
|
|
@@ -207,7 +210,7 @@ function releaseLock(file, nonce) {
|
|
|
207
210
|
|
|
208
211
|
/**
|
|
209
212
|
* Roda `fn` com a trava `file` (UMA execucao por vez nesta maquina), ESPERANDO a vez ate `waitMs`.
|
|
210
|
-
* Acabou o prazo: `onTimeout()` decide o resultado; sem `onTimeout`,
|
|
213
|
+
* Acabou o prazo: `onTimeout()` decide o resultado; sem `onTimeout`, falha sem executar a operacao.
|
|
211
214
|
*/
|
|
212
215
|
async function withFileLock(file, fn, { waitMs = LOCK_WAIT_MS, staleMs = LOCK_STALE_MS, onTimeout = null } = {}) {
|
|
213
216
|
const nonce = crypto.randomBytes(8).toString('hex');
|
|
@@ -217,7 +220,10 @@ async function withFileLock(file, fn, { waitMs = LOCK_WAIT_MS, staleMs = LOCK_ST
|
|
|
217
220
|
await sleep(40 + Math.floor(Math.random() * 80));
|
|
218
221
|
got = tryLock(file, nonce, staleMs);
|
|
219
222
|
}
|
|
220
|
-
if (got === 'ocupada'
|
|
223
|
+
if (got === 'ocupada') {
|
|
224
|
+
if (onTimeout) return onTimeout();
|
|
225
|
+
throw new Error('Outra operacao ainda segura a trava deste arquivo.');
|
|
226
|
+
}
|
|
221
227
|
try {
|
|
222
228
|
return await fn();
|
|
223
229
|
} finally {
|
|
@@ -777,6 +783,7 @@ function makeInfisicalBackend(d) {
|
|
|
777
783
|
// varios comandos juntos (o agente dispara em paralelo) entram um de cada vez: um erro seguido de acerto nao soma na trava
|
|
778
784
|
const r = await withFileLock(path.join(dirOf(d), 'cofre-infisical-login.lock'), () => entrar(list, cfg, baseUrl), {
|
|
779
785
|
waitMs: d.loginLockWaitMs === undefined ? LOGIN_LOCK_WAIT_MS : d.loginLockWaitMs,
|
|
786
|
+
onTimeout: () => failure('falha', tipo, 'Outra conexao ao cofre ainda esta em andamento. Tente de novo em alguns instantes.'),
|
|
780
787
|
});
|
|
781
788
|
if (!r.ok && (r.codigo === 'credencial-invalida' || r.codigo === 'bloqueada')) loginErro = r;
|
|
782
789
|
return r;
|
package/lib/onepassword.js
CHANGED
|
@@ -80,11 +80,8 @@ function hasCommand(cmd) {
|
|
|
80
80
|
}
|
|
81
81
|
|
|
82
82
|
function opVersion() {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
} catch {
|
|
86
|
-
return null;
|
|
87
|
-
}
|
|
83
|
+
const r = runOp(['--version'], { noStdin: true, timeoutMs: 10000 });
|
|
84
|
+
return r.ok ? r.stdout.trim() : null;
|
|
88
85
|
}
|
|
89
86
|
|
|
90
87
|
function installOp({ upgrade = false } = {}) {
|
|
@@ -708,9 +705,21 @@ function runOp(args, { env, input, timeoutMs = 120000, noStdin = false } = {}) {
|
|
|
708
705
|
// `noStdin`: o `op` recusa `--template` se o stdin for um pipe, ate vazio ("You can't use both piping and the
|
|
709
706
|
// --template flag"; o `input: ''` do Node vira pipe), entao esse comando roda com o stdin desligado (NUL/dev/null).
|
|
710
707
|
const useTerminal = input === undefined && !noStdin && Boolean(process.stdin.isTTY);
|
|
711
|
-
const
|
|
708
|
+
const viaPowerShell = process.platform === 'win32';
|
|
709
|
+
// No Windows, o op 2.41.1 lancado diretamente pelo Node falha antes de pedir sessao ao app.
|
|
710
|
+
// Node -> PowerShell -> op foi conferido no computador do aluno; JSON evita quoting de shell.
|
|
711
|
+
const psScript = '$OutputEncoding=New-Object System.Text.UTF8Encoding $false; [Console]::OutputEncoding=$OutputEncoding; '
|
|
712
|
+
+ '$a=@($env:AUROQ_OP_ARGS | ConvertFrom-Json); '
|
|
713
|
+
+ "if ($env:AUROQ_OP_STDIN -eq '1') { $s=[Console]::In.ReadToEnd(); $s | & op @a } else { & op @a }; exit $LASTEXITCODE";
|
|
714
|
+
const childEnv = env || opEnv();
|
|
715
|
+
const r = spawnSync(viaPowerShell ? 'powershell.exe' : 'op',
|
|
716
|
+
viaPowerShell ? ['-NoProfile', '-NonInteractive', '-Command', psScript] : args, {
|
|
712
717
|
encoding: 'utf8',
|
|
713
|
-
env:
|
|
718
|
+
env: viaPowerShell ? {
|
|
719
|
+
...childEnv,
|
|
720
|
+
AUROQ_OP_ARGS: JSON.stringify(args),
|
|
721
|
+
AUROQ_OP_STDIN: input !== undefined && input !== '' ? '1' : '0',
|
|
722
|
+
} : childEnv,
|
|
714
723
|
...(noStdin ? { stdio: ['ignore', 'pipe', 'pipe'] } : useTerminal ? { stdio: ['inherit', 'pipe', 'pipe'] } : { input: input === undefined ? '' : input }),
|
|
715
724
|
timeout: timeoutMs,
|
|
716
725
|
maxBuffer: 16 * 1024 * 1024,
|
|
@@ -2013,6 +2022,7 @@ module.exports = {
|
|
|
2013
2022
|
sweepStaleAppDirs,
|
|
2014
2023
|
checkInstallerSignature,
|
|
2015
2024
|
writeTemplateFile,
|
|
2025
|
+
runOp,
|
|
2016
2026
|
APP_INSTALLER_URL,
|
|
2017
2027
|
ETAPAS,
|
|
2018
2028
|
makeLock,
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"schema": 1,
|
|
3
3
|
"algorithm": "sha256",
|
|
4
4
|
"scope": "packaged-runtime-and-cascas",
|
|
5
|
-
"version": "2.
|
|
5
|
+
"version": "2.9.0",
|
|
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": "8b36ca85016ad05f1c66ca15507893d27578d5c60dcb8ea51aabb419020cb839"
|
|
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": "e8fda615af18dac7f35c1e507c9c4387f0f97112bfa1d785dc4b1ed2b4599daf"
|
|
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": "2a10098c4389bd732583c5e628c1018b1ba90a4f3c0165734ec3f21f646c63c8"
|
|
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": "d1bf61b459f81dfb7e13e2c694c1ead1d3146ba8057ff74fcf5d46beb6558cdf"
|
|
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": "c6e508a5832ae94ae186545a7aa187090826503dd7a8ece28a324ede3e827e39"
|
|
302
302
|
},
|
|
303
303
|
{
|
|
304
304
|
"path": "scripts/build-pack.mjs",
|
|
@@ -318,11 +318,11 @@
|
|
|
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",
|
|
325
|
-
"sha256": "
|
|
325
|
+
"sha256": "550509499825fcb2b96a04ad8d2c6893a7ec21824012655be04fe4c5385cc7b4"
|
|
326
326
|
},
|
|
327
327
|
{
|
|
328
328
|
"path": "scripts/validate-hybrid.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
|
}
|
|
@@ -84,9 +84,7 @@ function registerSkill(name, commandFile) {
|
|
|
84
84
|
skills.set(name, commandFile);
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
-
//
|
|
88
|
-
// e quem deu continua com ele.
|
|
89
|
-
// Se o comando base sumiu, $companion continua existindo, apontando pro comando dele.
|
|
87
|
+
// Atalhos com apelido criados antes de 1.15 ficam no disco, mas nao viram skills novas.
|
|
90
88
|
function comandoDoCompanion(file) {
|
|
91
89
|
try {
|
|
92
90
|
const texto = fs.readFileSync(file, 'utf8');
|
|
@@ -96,14 +94,6 @@ function comandoDoCompanion(file) {
|
|
|
96
94
|
}
|
|
97
95
|
}
|
|
98
96
|
|
|
99
|
-
function garantirAliasCompanion() {
|
|
100
|
-
if (skills.has('companion')) return;
|
|
101
|
-
const candidatos = [...skills.entries()]
|
|
102
|
-
.filter(([name, file]) => name.endsWith('-companion') && comandoDoCompanion(file))
|
|
103
|
-
.sort(([a], [b]) => a.localeCompare(b));
|
|
104
|
-
if (candidatos.length) skills.set('companion', candidatos[0][1]);
|
|
105
|
-
}
|
|
106
|
-
|
|
107
97
|
function collectSkills() {
|
|
108
98
|
const commandRoot = path.join(root, '.claude', 'commands');
|
|
109
99
|
if (!fs.existsSync(commandRoot)) return;
|
|
@@ -111,6 +101,8 @@ function collectSkills() {
|
|
|
111
101
|
for (const entry of fs.readdirSync(commandRoot, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
|
|
112
102
|
if (!entry.isFile() || !entry.name.endsWith('.md')) continue;
|
|
113
103
|
const basename = entry.name.replace(/\.md$/, '');
|
|
104
|
+
if (basename !== 'auroq-companion' && basename !== 'companion' &&
|
|
105
|
+
basename.endsWith('-companion') && comandoDoCompanion(path.join(commandRoot, entry.name))) continue;
|
|
114
106
|
// Aposentar distribuicao nao apaga comandos vitalicios. Se as duas grafias
|
|
115
107
|
// oficiais coexistem, a ponte usa a antiga preservada; nao mascara outras colisoes.
|
|
116
108
|
const legacyAlias = { 'clone-forge': 'cloneForge', 'mind-forge': 'mindForge', 'squad-forge': 'squadForge', 'worker-forge': 'workerForge' }[basename.replace(/^auroq-/, '')];
|
|
@@ -125,7 +117,6 @@ function collectSkills() {
|
|
|
125
117
|
registerSkill(kebab(file.replace(/\.md$/, '')), path.join(coreAgents, file));
|
|
126
118
|
}
|
|
127
119
|
}
|
|
128
|
-
garantirAliasCompanion();
|
|
129
120
|
}
|
|
130
121
|
|
|
131
122
|
function skillContent(name, commandFile, outRoot) {
|