sinapse-ai 1.11.3 → 1.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/hooks/enforce-architecture-first.cjs +2 -2
- package/.claude/hooks/enforce-delegation.cjs +2 -2
- package/.claude/hooks/enforce-permission-mode.cjs +12 -12
- package/.claude/hooks/enforce-story-gate.cjs +5 -5
- package/.claude/hooks/precompact-session-digest.cjs +2 -2
- package/.claude/hooks/secret-scanning.cjs +6 -6
- package/.claude/hooks/telemetry-post-tool.cjs +0 -1
- package/.claude/hooks/write-path-validation.cjs +2 -2
- package/.sinapse-ai/core/code-intel/helpers/dev-helper.js +1 -1
- package/.sinapse-ai/core/code-intel/helpers/devops-helper.js +0 -1
- package/.sinapse-ai/core/code-intel/helpers/planning-helper.js +1 -1
- package/.sinapse-ai/core/code-intel/helpers/qa-helper.js +2 -2
- package/.sinapse-ai/core/config/template-overrides.js +1 -1
- package/.sinapse-ai/core/doctor/checks/git-hooks.js +6 -3
- package/.sinapse-ai/core/doctor/checks/npm-packages.js +1 -1
- package/.sinapse-ai/core/doctor/checks/rules-files.js +0 -1
- package/.sinapse-ai/core/doctor/index.js +0 -1
- package/.sinapse-ai/core/graph-dashboard/cli.js +1 -1
- package/.sinapse-ai/core/graph-dashboard/data-sources/code-intel-source.js +1 -1
- package/.sinapse-ai/core/health-check/checks/project/constitution-consistency.js +0 -1
- package/.sinapse-ai/core/ideation/ideation-engine.js +0 -2
- package/.sinapse-ai/core/ids/layer-classifier.js +1 -1
- package/.sinapse-ai/core/registry/build-registry.js +12 -2
- package/.sinapse-ai/core/registry/service-registry.json +178 -55
- package/.sinapse-ai/core/registry/squad-agent-resolver.js +6 -0
- package/.sinapse-ai/core/synapse/layers/layer-processor.js +1 -1
- package/.sinapse-ai/data/capability-detection.js +15 -15
- package/.sinapse-ai/data/tok3-token-comparison.js +0 -3
- package/.sinapse-ai/data/tool-search-validation.js +1 -1
- package/.sinapse-ai/development/agents/snps-orqx.md +109 -0
- package/.sinapse-ai/development/scripts/agent-config-loader.js +8 -2
- package/.sinapse-ai/development/templates/sinapse-doc-template.md +6 -6
- package/.sinapse-ai/git-hooks/lib/framework-guard.js +1 -0
- package/.sinapse-ai/git-hooks/lib/staged-protected-files-guard.js +63 -0
- package/.sinapse-ai/git-hooks/pre-commit +3 -1
- package/.sinapse-ai/index.d.ts +19 -0
- package/.sinapse-ai/infrastructure/scripts/validate-agents.js +46 -16
- package/.sinapse-ai/install-manifest.yaml +61 -57
- package/.sinapse-ai/package.json +0 -1
- package/.sinapse-ai/utils/filters/index.js +2 -1
- package/CHANGELOG.md +38 -2
- package/README.md +132 -132
- package/bin/commands/doctor.js +1 -1
- package/bin/commands/help.js +3 -4
- package/bin/commands/install.js +7 -7
- package/bin/commands/status.js +3 -3
- package/bin/modules/chrome-brain-installer.js +3 -3
- package/bin/postinstall.js +1 -1
- package/bin/sinapse-init.js +11 -9
- package/bin/sinapse.js +1 -1
- package/bin/utils/framework-guard.js +1 -0
- package/bin/utils/staged-protected-files-guard.js +63 -0
- package/package.json +19 -2
- package/packages/installer/src/index.js +1 -1
- package/packages/installer/src/installer/brownfield-upgrader.js +1 -1
- package/packages/installer/src/installer/git-hooks-installer.js +10 -3
- package/packages/installer/src/pro/pro-scaffolder.js +3 -3
- package/packages/installer/src/wizard/ide-config-generator.js +1 -1
- package/packages/installer/src/wizard/index.js +4 -41
- package/scripts/audit-tasks.cjs +1 -1
- package/scripts/package-synapse.js +1 -1
- package/scripts/sinapse-patch.js +31 -31
- package/scripts/sync-squad-yaml-components.js +3 -3
- package/scripts/validate-agents-md.js +1 -1
- package/scripts/validate-no-external-refs.js +2 -2
- package/scripts/validate-no-personal-leaks.js +1 -1
- package/scripts/validate-orqx-discipline.js +0 -2
- package/scripts/validate-package-completeness.js +7 -7
- package/scripts/validate-squad-yaml.js +6 -6
- package/sinapse/agents/sinapse-orqx.md +1 -1
- package/sinapse/agents/snps-orqx.md +110 -1
- package/squads/claude-code-mastery/agents/swarm-orqx.md +12 -11
- package/squads/claude-code-mastery/scripts/validate-setup.js +2 -2
- package/squads/squad-brand/agents/brand-orqx.md +16 -1
- package/squads/squad-cloning/agents/cloning-orqx.md +2 -0
- package/squads/squad-commercial/agents/commercial-orqx.md +7 -4
- package/squads/squad-council/squad.yaml +67 -11
- package/squads/squad-design/agents/design-orqx.md +20 -0
- package/squads/squad-finance/agents/finance-orqx.md +6 -0
- package/squads/squad-paidmedia/agents/paidmedia-orqx.md +3 -1
package/bin/commands/install.js
CHANGED
|
@@ -155,7 +155,7 @@ async function cmdInstallGlobal(opts = {}) {
|
|
|
155
155
|
if (squads.length === 0) {
|
|
156
156
|
logger.error(`${RED}Erro: nenhum diretório de squad encontrado no pacote.${NC}`);
|
|
157
157
|
logger.error(`Tente reinstalar: ${CYAN}npm install -g sinapse-ai${NC}`);
|
|
158
|
-
logger.error(
|
|
158
|
+
logger.error('Se persistir, abra um issue: https://github.com/caioimori/sinapse-ai/issues');
|
|
159
159
|
process.exit(1);
|
|
160
160
|
}
|
|
161
161
|
|
|
@@ -275,7 +275,7 @@ async function cmdInstallGlobal(opts = {}) {
|
|
|
275
275
|
for (const f of fs.readdirSync(CLAUDE_COMMANDS_DIR)) {
|
|
276
276
|
fs.unlinkSync(path.join(CLAUDE_COMMANDS_DIR, f));
|
|
277
277
|
}
|
|
278
|
-
} catch {}
|
|
278
|
+
} catch { /* dir may not exist on a fresh install */ }
|
|
279
279
|
|
|
280
280
|
const sinapseBase = toForwardSlash(SINAPSE_HOME);
|
|
281
281
|
const writtenAgents = new Set();
|
|
@@ -622,13 +622,13 @@ function generateCommandMd(agentId, agentName, agentIcon, squadName, squadPath,
|
|
|
622
622
|
? `4. Briefing-on-activation check (this agent is an ORCHESTRATOR):
|
|
623
623
|
- If user provided briefing/context with the activation → proceed IMMEDIATELY: absorb → diagnose → plan with phases + agents + handoffs → execute (YOLO). NEVER ask "do you want me to plan?".
|
|
624
624
|
- If bare activation only → await briefing. On receipt, apply same flow automatically.`
|
|
625
|
-
:
|
|
625
|
+
: '4. HALT and await user input';
|
|
626
626
|
|
|
627
627
|
const step6 = isOrchestrator
|
|
628
628
|
? `6. Briefing-on-activation check (ORCHESTRATOR):
|
|
629
629
|
- If user provided briefing → proceed IMMEDIATELY: absorb → diagnose → plan → execute
|
|
630
630
|
- If bare activation → await briefing, then plan automatically. NEVER ask "do you want me to plan?".`
|
|
631
|
-
:
|
|
631
|
+
: '6. HALT and await user input';
|
|
632
632
|
|
|
633
633
|
// Frontmatter (name + description) is REQUIRED so the file resolves as a Claude Code
|
|
634
634
|
// subagent (@id) — without it, @id matches nothing. The same file doubles as a slash
|
|
@@ -754,7 +754,7 @@ See \`.claude/rules/squad-awareness.md\` for the full delegation map.
|
|
|
754
754
|
try {
|
|
755
755
|
const orqxFile = fs.readdirSync(sAgentsDir).find(f => f.endsWith('-orqx.md'));
|
|
756
756
|
if (orqxFile) orqxName = orqxFile.replace('.md', '');
|
|
757
|
-
} catch {}
|
|
757
|
+
} catch { /* fall back to the derived orqx name */ }
|
|
758
758
|
return `| ${s.name} | @${orqxName} | ${s.agents} agents, ${s.tasks} tasks |`;
|
|
759
759
|
}).join('\n');
|
|
760
760
|
|
|
@@ -828,12 +828,12 @@ exec claude --add-dir "${sinapsePathForBash}" --agent sinapse-orqx "$@"
|
|
|
828
828
|
`;
|
|
829
829
|
const bashPath = path.join(BIN_DIR, 'sinapse');
|
|
830
830
|
fs.writeFileSync(bashPath, bashLauncher);
|
|
831
|
-
try { fs.chmodSync(bashPath, 0o755); } catch {}
|
|
831
|
+
try { fs.chmodSync(bashPath, 0o755); } catch { /* chmod is best-effort (no-op on non-POSIX) */ }
|
|
832
832
|
logger.always(` ${GREEN}OK${NC} ~/bin/sinapse`);
|
|
833
833
|
|
|
834
834
|
// Windows CMD launcher
|
|
835
835
|
if (IS_WIN) {
|
|
836
|
-
const cmdLauncher =
|
|
836
|
+
const cmdLauncher = '@echo off\r\nclaude --add-dir "%USERPROFILE%\\.sinapse" --agent sinapse-orqx %*\r\n';
|
|
837
837
|
fs.writeFileSync(path.join(BIN_DIR, 'sinapse.cmd'), cmdLauncher);
|
|
838
838
|
logger.always(` ${GREEN}OK${NC} ~/bin/sinapse.cmd`);
|
|
839
839
|
}
|
package/bin/commands/status.js
CHANGED
|
@@ -23,9 +23,9 @@ function verifyInstall() {
|
|
|
23
23
|
const logger = getLogger();
|
|
24
24
|
const checks = [
|
|
25
25
|
[fs.existsSync(SINAPSE_HOME), `${getSquads(SINAPSE_HOME).length} squads in ~/.sinapse/`],
|
|
26
|
-
[fs.existsSync(CLAUDE_COMMANDS_DIR),
|
|
27
|
-
[fs.existsSync(path.join(BIN_DIR, 'sinapse')),
|
|
28
|
-
[fs.existsSync(path.join(SINAPSE_HOME, '.claude', 'rules', 'squad-awareness.md')),
|
|
26
|
+
[fs.existsSync(CLAUDE_COMMANDS_DIR), 'Commands in ~/.claude/commands/SINAPSE/agents/'],
|
|
27
|
+
[fs.existsSync(path.join(BIN_DIR, 'sinapse')), 'Launcher at ~/bin/sinapse'],
|
|
28
|
+
[fs.existsSync(path.join(SINAPSE_HOME, '.claude', 'rules', 'squad-awareness.md')), 'squad-awareness.md'],
|
|
29
29
|
];
|
|
30
30
|
|
|
31
31
|
for (const [ok, msg] of checks) {
|
|
@@ -183,7 +183,7 @@ function removeHooks(settingsPath, matchers) {
|
|
|
183
183
|
function sanitizeChromePath(chromePath) {
|
|
184
184
|
// Validate Chrome path contains only safe characters to prevent shell injection
|
|
185
185
|
const sanitized = chromePath.replace(/\\/g, '/');
|
|
186
|
-
if (!/^[a-zA-Z0-9\s/\-_.:()
|
|
186
|
+
if (!/^[a-zA-Z0-9\s/\-_.:()[\]]+$/.test(sanitized)) {
|
|
187
187
|
throw new Error(`Unsafe Chrome path detected: ${chromePath}`);
|
|
188
188
|
}
|
|
189
189
|
return sanitized;
|
|
@@ -201,7 +201,7 @@ if command -v taskkill &>/dev/null; then
|
|
|
201
201
|
elif command -v pgrep &>/dev/null; then
|
|
202
202
|
pgrep -f "user-data-dir=$CHROME_DEBUG_PROFILE" 2>/dev/null | xargs kill 2>/dev/null || true
|
|
203
203
|
fi`
|
|
204
|
-
:
|
|
204
|
+
: 'pgrep -f "user-data-dir=$CHROME_DEBUG_PROFILE" 2>/dev/null | xargs kill 2>/dev/null || true';
|
|
205
205
|
|
|
206
206
|
return `#!/bin/bash
|
|
207
207
|
# Chrome Brain — chrome-ensure (auto-launch)
|
|
@@ -253,7 +253,7 @@ if command -v taskkill &>/dev/null; then
|
|
|
253
253
|
elif command -v pgrep &>/dev/null; then
|
|
254
254
|
pgrep -f "user-data-dir=$CHROME_DEBUG_PROFILE" 2>/dev/null | xargs kill 2>/dev/null || true
|
|
255
255
|
fi`
|
|
256
|
-
:
|
|
256
|
+
: 'pgrep -f "user-data-dir=$CHROME_DEBUG_PROFILE" 2>/dev/null | xargs kill 2>/dev/null || true';
|
|
257
257
|
|
|
258
258
|
return `#!/bin/bash
|
|
259
259
|
# Chrome Brain — chrome-debug (manual launch)
|
package/bin/postinstall.js
CHANGED
|
@@ -485,7 +485,7 @@ function renderFinalSummary(opts = {}) {
|
|
|
485
485
|
}
|
|
486
486
|
lines.push('');
|
|
487
487
|
if (isGlobal) {
|
|
488
|
-
lines.push(
|
|
488
|
+
lines.push('Próximo passo:');
|
|
489
489
|
lines.push(` cd ${c.cyan}seu-projeto${c.reset}`);
|
|
490
490
|
lines.push(` ${c.cyan}sinapse install${c.reset}`);
|
|
491
491
|
} else {
|
package/bin/sinapse-init.js
CHANGED
|
@@ -55,17 +55,19 @@ function spawnAsync(command, options = {}) {
|
|
|
55
55
|
});
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
-
// ASCII Art Banner
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
58
|
+
// ASCII Art Banner — canonical SNPS AI wordmark in white (matches bin/lib/header.js).
|
|
59
|
+
// Kept in sync with the live banner so the legacy fallback installer never shows
|
|
60
|
+
// off-brand art (this banner predated the SINAPSE rebrand).
|
|
61
|
+
const BANNER = chalk.white.bold(`
|
|
62
|
+
███████╗███╗ ██╗██████╗ ███████╗ █████╗ ██╗
|
|
63
|
+
██╔════╝████╗ ██║██╔══██╗██╔════╝ ██╔══██╗██║
|
|
64
|
+
███████╗██╔██╗ ██║██████╔╝███████╗ ███████║██║
|
|
65
|
+
╚════██║██║╚██╗██║██╔═══╝ ╚════██║ ██╔══██║██║
|
|
66
|
+
███████║██║ ╚████║██║ ███████║ ██║ ██║██║
|
|
67
|
+
╚══════╝╚═╝ ╚═══╝╚═╝ ╚══════╝ ╚═╝ ╚═╝╚═╝
|
|
66
68
|
`);
|
|
67
69
|
|
|
68
|
-
const SUBTITLE = chalk.
|
|
70
|
+
const SUBTITLE = chalk.dim('Seu copiloto de inteligencia artificial');
|
|
69
71
|
// Read version from package.json dynamically
|
|
70
72
|
const packageJsonVersion = require(path.join(__dirname, '..', 'package.json')).version;
|
|
71
73
|
const VERSION = chalk.yellow(`Installer v${packageJsonVersion}`);
|
package/bin/sinapse.js
CHANGED
|
@@ -548,7 +548,7 @@ function findClaudeCliPath() {
|
|
|
548
548
|
try {
|
|
549
549
|
const npmRoot = execSync('npm root -g', { encoding: 'utf8' }).trim();
|
|
550
550
|
candidates.unshift(path.join(npmRoot, '@anthropic-ai/claude-code/cli.js'));
|
|
551
|
-
} catch {}
|
|
551
|
+
} catch { /* npm root -g may be unavailable; fall through to other candidates */ }
|
|
552
552
|
for (const p of candidates) {
|
|
553
553
|
if (fs.existsSync(p)) return p;
|
|
554
554
|
}
|
|
@@ -54,6 +54,7 @@ function globToRegex(glob) {
|
|
|
54
54
|
pattern = pattern.replace(/\*/g, '[^/]+');
|
|
55
55
|
|
|
56
56
|
// 4. Restore ** placeholder to any-depth matcher
|
|
57
|
+
// eslint-disable-next-line no-control-regex -- internal placeholder char (set above), never user input
|
|
57
58
|
pattern = pattern.replace(/\u0000/g, '.+');
|
|
58
59
|
|
|
59
60
|
// If pattern ends with .+ (was **), match prefix
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* staged-protected-files-guard — blocks a commit that DELETES (or untracks) a
|
|
6
|
+
* protected, committed-but-critical framework file.
|
|
7
|
+
*
|
|
8
|
+
* Why: on 2026-06-20 a "snapshot migracao notebook" sweep (`git add -A`) untracked
|
|
9
|
+
* `.sinapse-ai/core/registry/service-registry.json` (the committed registry drift
|
|
10
|
+
* detector, ~12k lines), bundled it with unrelated work, and pushed it. The
|
|
11
|
+
* framework-boundary guard is a no-op in contributor mode
|
|
12
|
+
* (boundary.frameworkProtection=false), so nothing stopped the deletion. This guard
|
|
13
|
+
* is ALWAYS on and narrowly targets that class of damage — it never touches normal
|
|
14
|
+
* edits, only the removal of a curated set of protected paths.
|
|
15
|
+
*
|
|
16
|
+
* Intentional removal (done in a story) bypasses with: git commit --no-verify
|
|
17
|
+
*
|
|
18
|
+
* Self-contained: Node built-ins + `git` only (matches the other lib guards so it
|
|
19
|
+
* bundles into <hooksDir>/lib/ with no extra deps).
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
const { spawnSync } = require('child_process');
|
|
23
|
+
|
|
24
|
+
// Curated, high-signal list. Keep small to guarantee zero false positives on
|
|
25
|
+
// normal work. These files are committed on purpose and must never be removed by
|
|
26
|
+
// an automated sweep without an explicit story.
|
|
27
|
+
const PROTECTED = ['.sinapse-ai/core/registry/service-registry.json'];
|
|
28
|
+
|
|
29
|
+
function stagedDeletions() {
|
|
30
|
+
// --no-renames forces a rename-away of a protected file to surface as a real
|
|
31
|
+
// deletion (D) of the old path, so moving the file out also trips the guard.
|
|
32
|
+
const res = spawnSync('git', ['diff', '--cached', '--name-status', '--no-renames'], {
|
|
33
|
+
encoding: 'utf8',
|
|
34
|
+
});
|
|
35
|
+
if (!res || res.status !== 0 || typeof res.stdout !== 'string') return [];
|
|
36
|
+
const deleted = [];
|
|
37
|
+
for (const line of res.stdout.split('\n')) {
|
|
38
|
+
if (!line) continue;
|
|
39
|
+
const parts = line.split('\t');
|
|
40
|
+
const status = parts[0];
|
|
41
|
+
const file = (parts[parts.length - 1] || '').replace(/\\/g, '/');
|
|
42
|
+
if (status === 'D') deleted.push(file);
|
|
43
|
+
}
|
|
44
|
+
return deleted;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const offenders = stagedDeletions().filter((f) => PROTECTED.includes(f));
|
|
48
|
+
|
|
49
|
+
if (offenders.length > 0) {
|
|
50
|
+
process.stderr.write(
|
|
51
|
+
'SINAPSE Protected Files: blocking commit — it deletes/untracks a protected file:\n',
|
|
52
|
+
);
|
|
53
|
+
for (const f of offenders) process.stderr.write(' - ' + f + '\n');
|
|
54
|
+
process.stderr.write(
|
|
55
|
+
'\nThese files are committed on purpose (e.g. service-registry.json is the registry\n' +
|
|
56
|
+
'drift detector). They must not be removed by an automated sweep (git add -A) or a\n' +
|
|
57
|
+
'machine-migration snapshot. If this removal is intentional, do it in a story and\n' +
|
|
58
|
+
'bypass once with: git commit --no-verify\n',
|
|
59
|
+
);
|
|
60
|
+
process.exit(1);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
process.exit(0);
|
package/package.json
CHANGED
|
@@ -1,12 +1,23 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sinapse-ai",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.12.1",
|
|
4
4
|
"description": "SINAPSE AI: Framework de orquestracao de IA — 17 squads, 172 agentes especializados",
|
|
5
5
|
"bin": {
|
|
6
6
|
"sinapse": "bin/sinapse.js",
|
|
7
7
|
"sinapse-ai": "bin/cli.js",
|
|
8
8
|
"sinapse-delegate": "bin/sinapse-delegate.js"
|
|
9
9
|
},
|
|
10
|
+
"main": ".sinapse-ai/index.js",
|
|
11
|
+
"module": ".sinapse-ai/index.esm.js",
|
|
12
|
+
"types": ".sinapse-ai/index.d.ts",
|
|
13
|
+
"exports": {
|
|
14
|
+
".": {
|
|
15
|
+
"types": "./.sinapse-ai/index.d.ts",
|
|
16
|
+
"default": "./.sinapse-ai/index.js"
|
|
17
|
+
},
|
|
18
|
+
"./package.json": "./package.json",
|
|
19
|
+
"./*": "./*"
|
|
20
|
+
},
|
|
10
21
|
"preferGlobal": false,
|
|
11
22
|
"workspaces": [
|
|
12
23
|
"packages/*"
|
|
@@ -16,6 +27,8 @@
|
|
|
16
27
|
"scripts/",
|
|
17
28
|
"packages/",
|
|
18
29
|
".sinapse-ai/",
|
|
30
|
+
"!.sinapse-ai/node_modules",
|
|
31
|
+
"!**/node_modules/**",
|
|
19
32
|
".claude/CLAUDE.md",
|
|
20
33
|
".claude/rules/",
|
|
21
34
|
".claude/hooks/",
|
|
@@ -139,6 +152,7 @@
|
|
|
139
152
|
"cli-progress": "^3.12.0",
|
|
140
153
|
"commander": "^12.1.0",
|
|
141
154
|
"cross-spawn": "^7.0.6",
|
|
155
|
+
"diff": "^5.2.0",
|
|
142
156
|
"execa": "^5.1.1",
|
|
143
157
|
"fast-glob": "^3.3.3",
|
|
144
158
|
"fs-extra": "^11.3.2",
|
|
@@ -178,6 +192,9 @@
|
|
|
178
192
|
"url": "https://github.com/caioimori/sinapse-ai/issues"
|
|
179
193
|
},
|
|
180
194
|
"homepage": "https://github.com/caioimori/sinapse-ai#readme",
|
|
195
|
+
"publishConfig": {
|
|
196
|
+
"access": "public"
|
|
197
|
+
},
|
|
181
198
|
"engines": {
|
|
182
199
|
"node": ">=18.0.0",
|
|
183
200
|
"npm": ">=9.0.0"
|
|
@@ -216,7 +233,7 @@
|
|
|
216
233
|
]
|
|
217
234
|
},
|
|
218
235
|
"overrides": {
|
|
219
|
-
"diff": "^
|
|
236
|
+
"diff": "^5.2.0",
|
|
220
237
|
"serialize-javascript": "^7.0.5",
|
|
221
238
|
"picomatch": "^4.0.4",
|
|
222
239
|
"brace-expansion": "^5.0.6",
|
|
@@ -19,7 +19,7 @@ if (require.main === module) {
|
|
|
19
19
|
Promise.resolve()
|
|
20
20
|
.then(() => wizard.runWizard())
|
|
21
21
|
.catch((error) => {
|
|
22
|
-
|
|
22
|
+
|
|
23
23
|
console.error('Installer failed:', error && error.message ? error.message : error);
|
|
24
24
|
process.exit(1);
|
|
25
25
|
});
|
|
@@ -287,7 +287,7 @@ async function applyUpgrade(report, sourceDir, targetDir, options = {}) {
|
|
|
287
287
|
result.mergeWarnings = result.mergeWarnings || [];
|
|
288
288
|
for (const conflict of conflicts) {
|
|
289
289
|
result.mergeWarnings.push(
|
|
290
|
-
`core-config.yaml: ${conflict.identifier} — ${conflict.reason}
|
|
290
|
+
`core-config.yaml: ${conflict.identifier} — ${conflict.reason}`,
|
|
291
291
|
);
|
|
292
292
|
}
|
|
293
293
|
}
|
|
@@ -67,6 +67,9 @@ const SCANNER_SOURCES = [
|
|
|
67
67
|
{ from: path.join(BIN_UTILS, 'staged-sql-guard.js'), to: 'staged-sql-guard.js' },
|
|
68
68
|
// --- framework boundary guard (FASE C; respects boundary.frameworkProtection) ---
|
|
69
69
|
{ from: path.join(BIN_UTILS, 'framework-guard.js'), to: 'framework-guard.js' },
|
|
70
|
+
// --- protected-files guard (always-on; blocks deletion/untrack of committed
|
|
71
|
+
// critical files like service-registry.json — anti git-add-A-sweep) ---
|
|
72
|
+
{ from: path.join(BIN_UTILS, 'staged-protected-files-guard.js'), to: 'staged-protected-files-guard.js' },
|
|
70
73
|
];
|
|
71
74
|
|
|
72
75
|
/**
|
|
@@ -173,13 +176,15 @@ function copyScannerLib(hooksDir) {
|
|
|
173
176
|
/**
|
|
174
177
|
* Build the content of the managed `pre-commit` Node hook.
|
|
175
178
|
*
|
|
176
|
-
* The hook runs
|
|
179
|
+
* The hook runs FOUR bundled guards in sequence (each a standalone module
|
|
177
180
|
* under ./lib that exits non-zero on a finding), then chains to a pre-existing
|
|
178
181
|
* husky hook:
|
|
179
182
|
* 1. staged-secret-scan.js — secret/.env/private-key/entropy leak (fail-CLOSED)
|
|
180
183
|
* 2. staged-sql-guard.js — destructive DDL/DML (DROP/TRUNCATE/DELETE-no-WHERE)
|
|
181
184
|
* 3. framework-guard.js — L1/L2 boundary (no-op unless boundary
|
|
182
185
|
* .frameworkProtection is true in core-config.yaml)
|
|
186
|
+
* 4. staged-protected-files-guard.js — always-on; blocks deletion/untrack of
|
|
187
|
+
* committed critical files (e.g. service-registry.json)
|
|
183
188
|
*
|
|
184
189
|
* Each guard is spawned as a child Node process (cwd = project root, where git
|
|
185
190
|
* already runs hooks) so it gets the same staged index and reuses its own
|
|
@@ -209,13 +214,15 @@ const { spawnSync } = require('child_process');
|
|
|
209
214
|
const projectRoot = process.cwd();
|
|
210
215
|
const libDir = path.join(__dirname, 'lib');
|
|
211
216
|
|
|
212
|
-
// --- 1-
|
|
213
|
-
// Order: secret scan,
|
|
217
|
+
// --- 1-4. SINAPSE staged guards (each fail-CLOSED) ---------------------------
|
|
218
|
+
// Order: secret scan, destructive-SQL guard, framework-boundary guard, then
|
|
219
|
+
// protected-files guard (always-on anti-sweep; does NOT respect frameworkProtection).
|
|
214
220
|
// framework-guard self-disables when boundary.frameworkProtection is false.
|
|
215
221
|
const GUARDS = [
|
|
216
222
|
{ file: 'staged-secret-scan.js', label: 'Secret Scan' },
|
|
217
223
|
{ file: 'staged-sql-guard.js', label: 'SQL Guard' },
|
|
218
224
|
{ file: 'framework-guard.js', label: 'Framework Boundary' },
|
|
225
|
+
{ file: 'staged-protected-files-guard.js', label: 'Protected Files' },
|
|
219
226
|
];
|
|
220
227
|
|
|
221
228
|
for (const guard of GUARDS) {
|
|
@@ -80,7 +80,7 @@ async function scaffoldProContent(targetDir, proSourceDir, options = {}) {
|
|
|
80
80
|
// Validate pro source exists
|
|
81
81
|
if (!await fs.pathExists(proSourceDir)) {
|
|
82
82
|
result.errors.push(
|
|
83
|
-
`Pro package not found at ${proSourceDir}. Run "npm install @sinapse-fullstack/pro" first
|
|
83
|
+
`Pro package not found at ${proSourceDir}. Run "npm install @sinapse-fullstack/pro" first.`,
|
|
84
84
|
);
|
|
85
85
|
return result;
|
|
86
86
|
}
|
|
@@ -160,7 +160,7 @@ async function scaffoldProContent(targetDir, proSourceDir, options = {}) {
|
|
|
160
160
|
result.errors.push(`Rollback errors: ${rollbackResult.errors.join(', ')}`);
|
|
161
161
|
}
|
|
162
162
|
result.warnings.push(
|
|
163
|
-
`Scaffolding failed: ${error.message}. ${rollbackResult.removed} files cleaned up
|
|
163
|
+
`Scaffolding failed: ${error.message}. ${rollbackResult.removed} files cleaned up.`,
|
|
164
164
|
);
|
|
165
165
|
}
|
|
166
166
|
|
|
@@ -425,7 +425,7 @@ async function installSquadCommands(targetDir) {
|
|
|
425
425
|
for (const agentFile of agentFiles) {
|
|
426
426
|
await fs.copy(
|
|
427
427
|
path.join(agentsDir, agentFile),
|
|
428
|
-
path.join(destDir, agentFile)
|
|
428
|
+
path.join(destDir, agentFile),
|
|
429
429
|
);
|
|
430
430
|
files.push(path.relative(targetDir, path.join(destDir, agentFile)).replace(/\\/g, '/'));
|
|
431
431
|
}
|
|
@@ -182,7 +182,7 @@ function generateTemplateVariables(wizardState) {
|
|
|
182
182
|
* @param {Object} ideConfig - IDE configuration object (optional, for special handling)
|
|
183
183
|
* @returns {Promise<string[]>} List of copied files
|
|
184
184
|
*/
|
|
185
|
-
async function copyAgentFiles(projectRoot, agentFolder,
|
|
185
|
+
async function copyAgentFiles(projectRoot, agentFolder, _ideConfig = null) {
|
|
186
186
|
// v4: Agents are in development/agents/ (not root agents/)
|
|
187
187
|
const sourceDir = path.join(__dirname, '..', '..', '..', '..', '.sinapse-ai', 'development', 'agents');
|
|
188
188
|
const targetDir = path.join(projectRoot, agentFolder);
|
|
@@ -15,14 +15,9 @@ const { execSync } = require('child_process');
|
|
|
15
15
|
const { colors } = require('../utils/sinapse-colors');
|
|
16
16
|
const {
|
|
17
17
|
getLanguageQuestion,
|
|
18
|
-
getUserProfileQuestion,
|
|
19
18
|
getLLMQuestion,
|
|
20
|
-
getProjectTypeQuestion,
|
|
21
|
-
getIDEQuestions,
|
|
22
|
-
getTechPresetQuestion,
|
|
23
19
|
} = require('./questions');
|
|
24
|
-
const { setLanguage, t
|
|
25
|
-
const yaml = require('js-yaml');
|
|
20
|
+
const { setLanguage, t } = require('./i18n');
|
|
26
21
|
const { detectProjectTypeExtended } = require('../detection/detect-project-type');
|
|
27
22
|
const { showWelcome, showCompletion, showCancellation } = require('./feedback');
|
|
28
23
|
const { generateIDEConfigs, showSuccessSummary, copySkillFiles, copyExtraCommandFiles } = require('./ide-config-generator');
|
|
@@ -47,38 +42,6 @@ const {
|
|
|
47
42
|
isLLMRoutingInstalled,
|
|
48
43
|
} = require('../../../../.sinapse-ai/infrastructure/scripts/llm-routing/install-llm-routing');
|
|
49
44
|
|
|
50
|
-
/**
|
|
51
|
-
* Check for existing user_profile in core-config.yaml (Story 10.2 - Idempotency)
|
|
52
|
-
* Returns the existing profile if found, null otherwise
|
|
53
|
-
*
|
|
54
|
-
* @param {string} targetDir - Target directory to check
|
|
55
|
-
* @returns {Promise<string|null>} Existing user profile or null
|
|
56
|
-
*/
|
|
57
|
-
async function getExistingUserProfile(targetDir = process.cwd()) {
|
|
58
|
-
const coreConfigPath = path.join(targetDir, '.sinapse-ai', 'core-config.yaml');
|
|
59
|
-
|
|
60
|
-
try {
|
|
61
|
-
if (await fse.pathExists(coreConfigPath)) {
|
|
62
|
-
const content = await fse.readFile(coreConfigPath, 'utf8');
|
|
63
|
-
const config = yaml.load(content);
|
|
64
|
-
|
|
65
|
-
if (config && config.user_profile) {
|
|
66
|
-
// Validate the value
|
|
67
|
-
const validProfiles = ['bob', 'advanced'];
|
|
68
|
-
const normalizedProfile = String(config.user_profile).toLowerCase().trim();
|
|
69
|
-
|
|
70
|
-
if (validProfiles.includes(normalizedProfile)) {
|
|
71
|
-
return normalizedProfile;
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
} catch {
|
|
76
|
-
// Config doesn't exist or is invalid - will ask for profile
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
return null;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
45
|
/**
|
|
83
46
|
* Map wizard language code to Claude Code settings.json language name (Story ACT-12)
|
|
84
47
|
* Claude Code uses full language names, not ISO codes.
|
|
@@ -369,7 +332,7 @@ function buildAgentTemplate(agentId, squadName, homedir) {
|
|
|
369
332
|
'ACTIVATION-NOTICE: This command activates an agent from sinapse.',
|
|
370
333
|
'',
|
|
371
334
|
`CRITICAL: Read the agent definition file at \`${agentDefPath}\` to understand your full operating parameters. Then:`,
|
|
372
|
-
|
|
335
|
+
'1. Adopt the persona defined in that file',
|
|
373
336
|
`2. Load the squad manifest at \`${squadManifestPath}\` for context`,
|
|
374
337
|
'3. Display a greeting showing your agent name, role, and available commands',
|
|
375
338
|
'4. Briefing-on-activation check (this agent is an ORCHESTRATOR):',
|
|
@@ -781,7 +744,7 @@ async function runWizard(options = {}) {
|
|
|
781
744
|
try {
|
|
782
745
|
await commandValidate({ quiet: true });
|
|
783
746
|
answers.ideSyncValidation = 'pass';
|
|
784
|
-
} catch
|
|
747
|
+
} catch {
|
|
785
748
|
answers.ideSyncValidation = 'drift';
|
|
786
749
|
} finally {
|
|
787
750
|
console.log = _origLog;
|
|
@@ -879,7 +842,7 @@ async function runWizard(options = {}) {
|
|
|
879
842
|
projectType: answers.projectType || 'greenfield',
|
|
880
843
|
selectedIDEs: answers.selectedIDEs || [],
|
|
881
844
|
mcpServers: answers.mcpServers || [],
|
|
882
|
-
userProfile: answers.userProfile || '
|
|
845
|
+
userProfile: answers.userProfile || 'bob', // Assisted-by-default (open-source p/ leigos); advanced é toggle opt-in pós-install
|
|
883
846
|
skipPrompts: options.quiet || false, // Skip prompts in quiet mode
|
|
884
847
|
forceMerge: options.forceMerge, // Story 9.4: Smart Merge support
|
|
885
848
|
noMerge: options.noMerge, // Story 9.4: Smart Merge support
|
package/scripts/audit-tasks.cjs
CHANGED
|
@@ -223,7 +223,7 @@ Add to \`.claude/settings.local.json\`:
|
|
|
223
223
|
"UserPromptSubmit": [
|
|
224
224
|
{
|
|
225
225
|
"type": "command",
|
|
226
|
-
"command": "node
|
|
226
|
+
"command": "node \\"$CLAUDE_PROJECT_DIR/.claude/hooks/synapse-engine.cjs\\"",
|
|
227
227
|
"timeout": 10
|
|
228
228
|
}
|
|
229
229
|
]
|
package/scripts/sinapse-patch.js
CHANGED
|
@@ -159,21 +159,21 @@ r('"Run /status in Claude Code to check your account."',
|
|
|
159
159
|
r(/future Claude Code sessions/g, 'future SINAPSE CODE sessions', 'model switch');
|
|
160
160
|
r(/Claude Code will automatically update/g, 'SINAPSE CODE will automatically update', 'auto-update');
|
|
161
161
|
r('"Please install git and restart Claude Code."', '"Please install git and restart SINAPSE CODE."', 'git install');
|
|
162
|
-
r(
|
|
163
|
-
r(
|
|
164
|
-
r(
|
|
165
|
-
r(
|
|
166
|
-
r(
|
|
167
|
-
r(
|
|
168
|
-
r(
|
|
169
|
-
r(
|
|
170
|
-
r(
|
|
171
|
-
r(
|
|
172
|
-
r(
|
|
173
|
-
r(
|
|
174
|
-
r(
|
|
175
|
-
r(
|
|
176
|
-
r(
|
|
162
|
+
r('Claude is up to date!\n', 'SINAPSE is up to date!\n', 'up to date');
|
|
163
|
+
r('Claude is managed by winget.\n', 'SINAPSE is managed by winget.\n', 'winget');
|
|
164
|
+
r('Claude is managed by apk.\n', 'SINAPSE is managed by apk.\n', 'apk');
|
|
165
|
+
r('Claude is managed by a package manager.\n', 'SINAPSE is managed by a package manager.\n', 'pkg manager');
|
|
166
|
+
r('This tool allows Claude Code to read images', 'This tool allows SINAPSE CODE to read images', 'read tool');
|
|
167
|
+
r('Claude Code is a multimodal LLM', 'SINAPSE CODE is a multimodal LLM', 'multimodal');
|
|
168
|
+
r('Default permission mode when Claude Code needs access', 'Default permission mode when SINAPSE CODE needs access', 'settings 1');
|
|
169
|
+
r('JSON Schema reference for Claude Code settings', 'JSON Schema reference for SINAPSE CODE settings', 'settings 2');
|
|
170
|
+
r('Environment variables to set for Claude Code sessions', 'Environment variables to set for SINAPSE CODE sessions', 'settings 3');
|
|
171
|
+
r('standard Claude Code attribution', 'standard SINAPSE CODE attribution', 'attribution');
|
|
172
|
+
r('Override the default model used by Claude Code', 'Override the default model used by SINAPSE CODE', 'model desc');
|
|
173
|
+
r('Claude Code auto-stash', 'SINAPSE CODE auto-stash', 'git stash');
|
|
174
|
+
r('Claude Code was unable to find', 'SINAPSE CODE was unable to find', 'win bash');
|
|
175
|
+
r('Claude Code on Windows requires git-bash', 'SINAPSE CODE on Windows requires git-bash', 'win git-bash');
|
|
176
|
+
r('Cost of the Claude Code session', 'Cost of the SINAPSE CODE session', 'cost counter');
|
|
177
177
|
|
|
178
178
|
// ═══════════════════════════════════════════════════
|
|
179
179
|
// 4. LOGO — Substitui mascot Clawd por SINAPSE ASCII
|
|
@@ -182,24 +182,24 @@ r("Cost of the Claude Code session", "Cost of the SINAPSE CODE session", 'cost c
|
|
|
182
182
|
console.log('[Logo]');
|
|
183
183
|
|
|
184
184
|
const LOGO_LINES = [
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
185
|
+
'███████╗██╗███╗ ██╗ █████╗ ██████╗ ███████╗███████╗',
|
|
186
|
+
'██╔════╝██║████╗ ██║██╔══██╗██╔══██╗██╔════╝██╔════╝',
|
|
187
|
+
'███████╗██║██╔██╗ ██║███████║██████╔╝███████╗█████╗ ',
|
|
188
|
+
'╚════██║██║██║╚██╗██║██╔══██║██╔═══╝ ╚════██║██╔══╝ ',
|
|
189
|
+
'███████║██║██║ ╚████║██║ ██║██║ ███████║███████╗',
|
|
190
|
+
'╚══════╝╚═╝╚═╝ ╚═══╝╚═╝ ╚═╝╚═╝ ╚══════╝╚══════╝',
|
|
191
191
|
];
|
|
192
192
|
|
|
193
|
-
const newLogo = `function HV6(){let q=z6(2),P;if(q[0]===Symbol.for("react.memo_cache_sentinel")){let lines=[${LOGO_LINES.map(l => JSON.stringify(l)).join(
|
|
193
|
+
const newLogo = `function HV6(){let q=z6(2),P;if(q[0]===Symbol.for("react.memo_cache_sentinel")){let lines=[${LOGO_LINES.map(l => JSON.stringify(l)).join(',')}];P=i9.createElement(B,{flexDirection:"column",flexShrink:0},lines.map((l,i)=>i9.createElement(T,{key:i,color:"claude",wrap:"truncate"},l))),q[0]=P}else P=q[0];return P}`;
|
|
194
194
|
|
|
195
195
|
// Substitui HV6 (componente principal do mascot)
|
|
196
|
-
const hv6Start = content.indexOf(
|
|
196
|
+
const hv6Start = content.indexOf('function HV6(A){');
|
|
197
197
|
if (hv6Start !== -1) {
|
|
198
198
|
const hv6Area = content.substring(hv6Start);
|
|
199
199
|
let depth = 0, endPos = -1;
|
|
200
|
-
for (let i = hv6Area.indexOf(
|
|
201
|
-
if (hv6Area[i] ===
|
|
202
|
-
if (hv6Area[i] ===
|
|
200
|
+
for (let i = hv6Area.indexOf('{'); i < hv6Area.length; i++) {
|
|
201
|
+
if (hv6Area[i] === '{') depth++;
|
|
202
|
+
if (hv6Area[i] === '}') { depth--; if (depth === 0) { endPos = i + 1; break; } }
|
|
203
203
|
}
|
|
204
204
|
if (endPos !== -1) {
|
|
205
205
|
content = content.substring(0, hv6Start) + newLogo + content.substring(hv6Start + endPos);
|
|
@@ -209,16 +209,16 @@ if (hv6Start !== -1) {
|
|
|
209
209
|
}
|
|
210
210
|
|
|
211
211
|
// Substitui dKY (fallback Apple Terminal)
|
|
212
|
-
const dkyStart = content.indexOf(
|
|
212
|
+
const dkyStart = content.indexOf('function dKY(A){');
|
|
213
213
|
if (dkyStart !== -1) {
|
|
214
214
|
const dkyArea = content.substring(dkyStart);
|
|
215
215
|
let depth = 0, endPos = -1;
|
|
216
|
-
for (let i = dkyArea.indexOf(
|
|
217
|
-
if (dkyArea[i] ===
|
|
218
|
-
if (dkyArea[i] ===
|
|
216
|
+
for (let i = dkyArea.indexOf('{'); i < dkyArea.length; i++) {
|
|
217
|
+
if (dkyArea[i] === '{') depth++;
|
|
218
|
+
if (dkyArea[i] === '}') { depth--; if (depth === 0) { endPos = i + 1; break; } }
|
|
219
219
|
}
|
|
220
220
|
if (endPos !== -1) {
|
|
221
|
-
const newDKY = newLogo.replace(
|
|
221
|
+
const newDKY = newLogo.replace('HV6', 'dKY');
|
|
222
222
|
content = content.substring(0, dkyStart) + newDKY + content.substring(dkyStart + endPos);
|
|
223
223
|
changes++;
|
|
224
224
|
console.log(' + dKY fallback -> SINAPSE logo');
|
|
@@ -194,9 +194,9 @@ function run() {
|
|
|
194
194
|
for (const r of results) {
|
|
195
195
|
const marker = r.status === 'updated' ? 'UPDATED'
|
|
196
196
|
: r.status === 'needs-update' ? 'NEEDS UPDATE'
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
197
|
+
: r.status === 'drift' ? 'DRIFT'
|
|
198
|
+
: r.status === 'already-declared' ? 'ok'
|
|
199
|
+
: r.status.toUpperCase();
|
|
200
200
|
console.log(` ${marker.padEnd(14)} ${r.squadName} (${r.changes} agent(s))`);
|
|
201
201
|
if (r.status === 'drift') {
|
|
202
202
|
if (r.declaredOnly.length > 0) {
|
|
@@ -77,7 +77,7 @@ function main() {
|
|
|
77
77
|
if (!fs.existsSync(AGENTS_MD)) fail('AGENTS.md not found at repo root');
|
|
78
78
|
|
|
79
79
|
const stats = readStats();
|
|
80
|
-
|
|
80
|
+
const content = fs.readFileSync(AGENTS_MD, 'utf8');
|
|
81
81
|
|
|
82
82
|
const mismatches = [];
|
|
83
83
|
let fixed = content;
|
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
* the MIT `LICENSE` file (legal attribution requirement), the historical
|
|
14
14
|
* process document `docs/research-synthesis-for-upgrade.md`, and a small set
|
|
15
15
|
* of pre-existing upstream-attribution files inherited from the BMAD fork
|
|
16
|
-
* lineage (flagged for future per-file review — see
|
|
17
|
-
*
|
|
16
|
+
* lineage (flagged for future per-file review — see the internal
|
|
17
|
+
* upstream-attribution follow-up backlog).
|
|
18
18
|
*
|
|
19
19
|
* === Source of truth: `git ls-files` (QA v1.1 fix) ===
|
|
20
20
|
*
|