auroq-os 2.8.8 → 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.
@@ -1,7 +1,7 @@
1
1
  project:
2
2
  name: "Auroq OS"
3
3
  type: greenfield
4
- version: 2.8.8
4
+ version: 2.9.0
5
5
  installedAt: '2026-03-16'
6
6
 
7
7
  ide:
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 é a sede do negócio: memória, documentos, projetos, sites e o histórico no GitHub privado.
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. Memória: `agents/companion/data/` (onde paramos, decisões, pendências), conhecimento em
26
- `docs/knowledge/`, projetos em `business/cockpit.md` e nos trackers de cada projeto.
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 privado (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 a pasta do seu negócio 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
+ 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/bin/auroq-os.js CHANGED
@@ -434,31 +434,8 @@ const HEALTH_CHECKS = [
434
434
  ['scripts/validate-hybrid.mjs', 'Validador hibrido'],
435
435
  ];
436
436
 
437
- /**
438
- * Ate 21/10/2026 o aluno dava um nome ao Companion no bootstrap (FASE 10 do Ops, que saiu:
439
- * "Companion e Companion"), e quem deu continua com ele: `/atlas-companion`. Um
440
- * comando com esse nome que ainda aponta pro Companion (recurso `companion` do MCP ou a
441
- * pasta agents/companion/) vale como a casca dele — um clone do negocio que so tem o
442
- * comando com o nome do aluno nao pode ser acusado de "arquivo faltando". So o Companion
443
- * tem essa folga: os outros arquivos continuam exigidos pelo caminho exato.
444
- */
445
- async function companionComNomeDoAluno(targetDir) {
446
- const dir = path.join(targetDir, '.claude', 'commands');
447
- let nomes = [];
448
- try { nomes = await fs.readdir(dir); } catch { return null; }
449
- for (const nome of nomes.filter(n => /^[a-z0-9-]+-companion\.md$/.test(n)).sort()) {
450
- try {
451
- const texto = await fs.readFile(path.join(dir, nome), 'utf8');
452
- if (/recurso_id\s*`?companion`?/.test(texto) || /agents\/companion\//.test(texto)) return `.claude/commands/${nome}`;
453
- } catch { /* ilegivel: nao conta */ }
454
- }
455
- return null;
456
- }
457
-
458
437
  async function checagemPresente(targetDir, file) {
459
- if (await fs.pathExists(path.join(targetDir, file))) return true;
460
- if (file === '.claude/commands/auroq-companion.md') return Boolean(await companionComNomeDoAluno(targetDir));
461
- return false;
438
+ return fs.pathExists(path.join(targetDir, file));
462
439
  }
463
440
 
464
441
  /**
@@ -1670,11 +1647,11 @@ async function init({ pasta = null, maintenance = false, modoAgente = false, mig
1670
1647
  error('');
1671
1648
  error('Crie uma pasta pro seu projeto e rode o comando de dentro dela:');
1672
1649
  error('');
1673
- error(` ${CYAN}mkdir meu-negocio${RESET}`);
1674
- error(` ${CYAN}cd meu-negocio${RESET}`);
1650
+ error(` ${CYAN}mkdir primeiro-passo${RESET}`);
1651
+ error(` ${CYAN}cd primeiro-passo${RESET}`);
1675
1652
  error(` ${CYAN}npx auroq-os@latest instalar${RESET}`);
1676
1653
  error('');
1677
- error('Troque "meu-negocio" pelo nome que quiser pro seu projeto.');
1654
+ error('Depois, o Companion ajuda a criar os projetos separados.');
1678
1655
  throw falhaMarcada('pasta', 'Esta e a pasta pessoal do usuario, nao a de um negocio. Rode na pasta do negocio.', { jaMostrado: true });
1679
1656
  }
1680
1657
 
@@ -1699,7 +1676,8 @@ async function init({ pasta = null, maintenance = false, modoAgente = false, mig
1699
1676
  }
1700
1677
  }
1701
1678
  }
1702
- if (isNewInstall && process.env.AUROQ_INIT_MODE !== 'novo') {
1679
+ const primeiroPasso = isNewInstall && process.env.AUROQ_INIT_MODE !== 'novo';
1680
+ if (isNewInstall && !['novo', 'primeiro-passo'].includes(process.env.AUROQ_INIT_MODE)) {
1703
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} `);
1704
1682
  if (jaUsa) {
1705
1683
  log('');
@@ -1801,7 +1779,7 @@ async function init({ pasta = null, maintenance = false, modoAgente = false, mig
1801
1779
  'scripts',
1802
1780
  ];
1803
1781
 
1804
- for (const dir of dirs) {
1782
+ for (const dir of dirs.filter(dir => !primeiroPasso || !dir.startsWith('business/'))) {
1805
1783
  await fs.ensureDir(path.join(targetDir, dir));
1806
1784
  }
1807
1785
  success(`${dirs.length} pastas criadas`);
@@ -1946,20 +1924,6 @@ async function init({ pasta = null, maintenance = false, modoAgente = false, mig
1946
1924
  'business/cockpit.md',
1947
1925
  ];
1948
1926
 
1949
- // Detectar se ja existe companion personalizado (ex: taquion-companion.md)
1950
- // Se existir, NAO copiar companion.md generico pra nao duplicar
1951
- const commandsDir = path.join(targetDir, '.claude', 'commands');
1952
- let hasCustomCompanion = false;
1953
- if (await fs.pathExists(commandsDir)) {
1954
- const cmdFiles = await fs.readdir(commandsDir);
1955
- hasCustomCompanion = cmdFiles.some(f => f.endsWith('-companion.md') && f !== 'companion.md');
1956
- if (hasCustomCompanion) {
1957
- const customName = cmdFiles.find(f => f.endsWith('-companion.md') && f !== 'companion.md');
1958
- log(`${DIM} Companion personalizado detectado: ${customName} — pulando companion.md generico${RESET}`);
1959
- }
1960
-
1961
- }
1962
-
1963
1927
  // Pastas e comandos antigos pertencem ao aluno. Nunca excluir na manutencao.
1964
1928
 
1965
1929
  // Atalhos do Pack Arcane. O conteudo chega ao vivo pelo MCP, mas o /comando
@@ -2010,10 +1974,7 @@ async function init({ pasta = null, maintenance = false, modoAgente = false, mig
2010
1974
  let copied = 0;
2011
1975
  let claudeMd = null;
2012
1976
  for (const file of frameworkFiles) {
2013
- // Pular companion.md generico se ja tem personalizado
2014
- if (file === '.claude/commands/companion.md' && hasCustomCompanion) {
2015
- continue;
2016
- }
1977
+ if (primeiroPasso && file.startsWith('business/') && file !== 'business/cockpit.md') continue;
2017
1978
  const src = path.join(sourceDir, file);
2018
1979
  const dst = path.join(targetDir, file);
2019
1980
  if (await fs.pathExists(src)) {
@@ -2063,7 +2024,11 @@ async function init({ pasta = null, maintenance = false, modoAgente = false, mig
2063
2024
 
2064
2025
  const seedRoot = path.join(sourceDir, 'seeds');
2065
2026
  if (await fs.pathExists(seedRoot)) {
2066
- await fs.copy(seedRoot, targetDir, { overwrite: false });
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
+ });
2067
2032
  success('Semente do aluno instalada (memoria, docs, cockpit — nunca sobrescreve)');
2068
2033
  }
2069
2034
  // ─── Fase 4: Synapse Engine (troca versao oficial antiga; guarda o que foi mexido a mao).
@@ -2115,9 +2080,9 @@ async function init({ pasta = null, maintenance = false, modoAgente = false, mig
2115
2080
  const pkgPath = path.join(targetDir, 'package.json');
2116
2081
  if (!(await fs.pathExists(pkgPath))) {
2117
2082
  await fs.writeJSON(pkgPath, {
2118
- name: 'meu-negocio',
2083
+ name: primeiroPasso ? 'primeiro-passo' : path.basename(targetDir).toLowerCase().replace(/[^a-z0-9-]+/g, '-') || 'projeto-auroq',
2119
2084
  version: '1.0.0',
2120
- description: 'Meu negocio com Auroq OS',
2085
+ description: primeiroPasso ? 'Ponto de partida para organizar os projetos com o Companion' : 'Projeto com Auroq OS',
2121
2086
  private: true,
2122
2087
  dependencies: {
2123
2088
  'js-yaml': '^4.1.0',
@@ -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.8 check-access
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.8.8 instalar
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.'
@@ -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.8 "$@"
222
+ npx -y auroq-os@2.9.0 "$@"
223
223
  else
224
- npx -y auroq-os@2.8.8 "$@" < /dev/tty
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), 'ocupada' (outro comando segura) ou 'sem-trava' (permissao ou disco: segue sem trava, como a rota A). */
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') return 'sem-trava';
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`, roda `fn` mesmo assim (nunca trava o aluno).
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' && onTimeout) return onTimeout();
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;
@@ -2,7 +2,7 @@
2
2
  "schema": 1,
3
3
  "algorithm": "sha256",
4
4
  "scope": "packaged-runtime-and-cascas",
5
- "version": "2.8.8",
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": "f8d396a2a696af94b4a96822d5eec348510fa1e0e0fb6f71107118dd15e2adc1"
13
+ "sha256": "8b36ca85016ad05f1c66ca15507893d27578d5c60dcb8ea51aabb419020cb839"
14
14
  },
15
15
  {
16
16
  "path": ".auroq-core/core/synapse/context/context-builder.js",
@@ -214,7 +214,7 @@
214
214
  },
215
215
  {
216
216
  "path": "bin/auroq-os.js",
217
- "sha256": "4d3bd746dc2eb4c0e0a3cce30f2bed16d41af4230645fb0f7ef4f3ae6f5b485a"
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": "8dff20e576fda737f5039ceaca64e8e18fe79e19460c3ce0bac1262f7fa490df"
257
+ "sha256": "2a10098c4389bd732583c5e628c1018b1ba90a4f3c0165734ec3f21f646c63c8"
258
258
  },
259
259
  {
260
260
  "path": "lib/credentials.js",
@@ -298,7 +298,7 @@
298
298
  },
299
299
  {
300
300
  "path": "package.json",
301
- "sha256": "e8a718a7f9f7345742d5cf7a894deeee0cf9308bfaf49dc3635c530ff0e4a3bd"
301
+ "sha256": "c6e508a5832ae94ae186545a7aa187090826503dd7a8ece28a324ede3e827e39"
302
302
  },
303
303
  {
304
304
  "path": "scripts/build-pack.mjs",
@@ -322,7 +322,7 @@
322
322
  },
323
323
  {
324
324
  "path": "scripts/sync-codex-skills.mjs",
325
- "sha256": "830d88b2711e5c0b4ff64d5d03ed677a64ffb1662e290e6196fac721244640bc"
325
+ "sha256": "550509499825fcb2b96a04ad8d2c6893a7ec21824012655be04fe4c5385cc7b4"
326
326
  },
327
327
  {
328
328
  "path": "scripts/validate-hybrid.mjs",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "auroq-os",
3
- "version": "2.8.8",
3
+ "version": "2.9.0",
4
4
  "arcaneMcpPin": "0.7.1",
5
5
  "description": "Auroq OS — Sistema Operacional de IA para o negócio do aluno da Arcane",
6
6
  "bin": {
@@ -84,9 +84,7 @@ function registerSkill(name, commandFile) {
84
84
  skills.set(name, commandFile);
85
85
  }
86
86
 
87
- // Ate 21/10/2026 o aluno dava um nome ao Companion no bootstrap (FASE 10 do Ops: /atlas-companion),
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) {