sinapse-ai 1.6.1 → 1.8.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/.claude/CLAUDE.md +5 -11
- package/.claude/hooks/README.md +14 -1
- package/.claude/hooks/code-intel-pretool.cjs +115 -0
- package/.claude/hooks/enforce-delegation.cjs +31 -3
- package/.claude/hooks/enforce-framework-boundary.cjs +324 -0
- package/.claude/hooks/enforce-permission-mode.cjs +249 -0
- package/.claude/hooks/secret-scanning.cjs +34 -43
- package/.claude/hooks/synapse-engine.cjs +23 -23
- package/.claude/hooks/telemetry-post-tool.cjs +128 -0
- package/.claude/hooks/telemetry-stop.cjs +132 -0
- package/.claude/hooks/verify-packages.cjs +9 -2
- package/.claude/rules/documentation-first.md +1 -1
- package/.claude/rules/hook-governance.md +2 -0
- package/.sinapse-ai/cli/commands/health/index.js +24 -0
- package/.sinapse-ai/core/README.md +11 -0
- package/.sinapse-ai/core/config/config-loader.js +19 -0
- package/.sinapse-ai/core/config/merge-utils.js +8 -0
- package/.sinapse-ai/core/errors/constants.js +147 -0
- package/.sinapse-ai/core/errors/error-registry.js +176 -0
- package/.sinapse-ai/core/errors/index.js +50 -0
- package/.sinapse-ai/core/errors/serializer.js +147 -0
- package/.sinapse-ai/core/errors/sinapse-error.js +144 -0
- package/.sinapse-ai/core/errors/utils.js +187 -0
- package/.sinapse-ai/core/execution/build-orchestrator.js +47 -49
- package/.sinapse-ai/core/execution/build-state-manager.js +183 -31
- package/.sinapse-ai/core/execution/parallel-executor.js +7 -1
- package/.sinapse-ai/core/execution/semantic-merge-engine.js +26 -14
- package/.sinapse-ai/core/execution/subagent-dispatcher.js +201 -60
- package/.sinapse-ai/core/execution/wave-executor.js +4 -1
- package/.sinapse-ai/core/grounding/README.md +71 -11
- package/.sinapse-ai/core/health-check/checks/project/framework-config.js +38 -2
- package/.sinapse-ai/core/health-check/checks/project/package-json.js +47 -3
- package/.sinapse-ai/core/health-check/checks/services/gemini-cli.js +117 -0
- package/.sinapse-ai/core/health-check/checks/services/index.js +2 -0
- package/.sinapse-ai/core/health-check/healers/index.js +40 -3
- package/.sinapse-ai/core/ideation/ideation-engine.js +212 -107
- package/.sinapse-ai/core/ids/gate-evaluator.js +318 -0
- package/.sinapse-ai/core/ids/gates/g5-semantic-handshake.js +190 -0
- package/.sinapse-ai/core/ids/gates/g6-ci-integrity.js +162 -0
- package/.sinapse-ai/core/ids/index.js +30 -0
- package/.sinapse-ai/core/memory/__tests__/active-modules.verify.js +11 -0
- package/.sinapse-ai/core/memory/gotchas-memory.js +37 -2
- package/.sinapse-ai/core/orchestration/agent-invoker.js +29 -6
- package/.sinapse-ai/core/orchestration/brownfield-handler.js +36 -3
- package/.sinapse-ai/core/orchestration/condition-evaluator.js +57 -0
- package/.sinapse-ai/core/orchestration/executors/epic-3-executor.js +76 -5
- package/.sinapse-ai/core/orchestration/executors/epic-4-executor.js +63 -17
- package/.sinapse-ai/core/orchestration/executors/epic-6-executor.js +153 -41
- package/.sinapse-ai/core/orchestration/executors/epic-executor.js +40 -0
- package/.sinapse-ai/core/orchestration/greenfield-handler.js +87 -3
- package/.sinapse-ai/core/orchestration/master-orchestrator.js +150 -10
- package/.sinapse-ai/core/orchestration/parallel-executor.js +6 -1
- package/.sinapse-ai/core/orchestration/recovery-handler.js +81 -8
- package/.sinapse-ai/core/orchestration/workflow-executor.js +41 -0
- package/.sinapse-ai/core/registry/registry-loader.js +71 -5
- package/.sinapse-ai/core/registry/squad-agent-resolver.js +253 -0
- package/.sinapse-ai/core/synapse/context/context-tracker.js +104 -9
- package/.sinapse-ai/core/synapse/context/index.js +19 -0
- package/.sinapse-ai/core/synapse/context/semantic-handshake-engine.js +555 -0
- package/.sinapse-ai/core/synapse/diagnostics/collectors/pipeline-collector.js +4 -2
- package/.sinapse-ai/core/synapse/engine.js +43 -3
- package/.sinapse-ai/core/telemetry/ids-sink.js +188 -0
- package/.sinapse-ai/core/utils/output-formatter.js +8 -290
- package/.sinapse-ai/core/utils/spawn-safe.js +186 -0
- package/.sinapse-ai/core-config.yaml +68 -1
- package/.sinapse-ai/data/entity-registry.yaml +15082 -13618
- package/.sinapse-ai/data/registry-update-log.jsonl +143 -0
- package/.sinapse-ai/development/agents/developer.md +2 -0
- package/.sinapse-ai/development/agents/devops.md +9 -0
- package/.sinapse-ai/development/external-executors/README.md +18 -0
- package/.sinapse-ai/development/external-executors/codex.md +56 -0
- package/.sinapse-ai/development/scripts/populate-entity-registry.js +65 -9
- package/.sinapse-ai/development/scripts/squad/squad-downloader.js +169 -14
- package/.sinapse-ai/development/tasks/delegate-to-external-executor.md +152 -0
- package/.sinapse-ai/development/tasks/github-devops-pre-push-quality-gate.md +46 -29
- package/.sinapse-ai/development/tasks/update-sinapse.md +3 -3
- package/.sinapse-ai/hooks/sinapse-brand-grounding.cjs +4 -7
- package/.sinapse-ai/hooks/sinapse-ds-grounding.cjs +5 -8
- package/.sinapse-ai/hooks/sinapse-vault-grounding.cjs +6 -9
- package/.sinapse-ai/infrastructure/integrations/ai-providers/ai-provider-factory.js +4 -1
- package/.sinapse-ai/infrastructure/integrations/ai-providers/claude-provider.js +57 -55
- package/.sinapse-ai/infrastructure/integrations/pm-adapters/github-adapter.js +9 -7
- package/.sinapse-ai/infrastructure/scripts/ide-sync/gemini-commands.js +298 -0
- package/.sinapse-ai/infrastructure/scripts/ide-sync/index.js +127 -6
- package/.sinapse-ai/infrastructure/scripts/ide-sync/persona-renderer.js +97 -0
- package/.sinapse-ai/infrastructure/scripts/ide-sync/transformers/antigravity.js +121 -0
- package/.sinapse-ai/infrastructure/scripts/ide-sync/transformers/cursor.js +119 -0
- package/.sinapse-ai/infrastructure/scripts/ide-sync/transformers/github-copilot.js +191 -0
- package/.sinapse-ai/infrastructure/scripts/ide-sync/transformers/kimi.js +448 -0
- package/.sinapse-ai/install-manifest.yaml +218 -114
- package/.sinapse-ai/product/templates/engine/renderer.js +20 -1
- package/.sinapse-ai/scripts/pm.sh +18 -6
- package/bin/cli.js +17 -0
- package/bin/commands/agents.js +96 -0
- package/bin/commands/doctor.js +15 -0
- package/bin/commands/ideate.js +129 -0
- package/bin/commands/uninstall.js +40 -0
- package/bin/postinstall.js +50 -4
- package/bin/sinapse.js +146 -2
- package/bin/utils/secret-scanner-core.js +253 -0
- package/bin/utils/staged-secret-scan.js +106 -40
- package/docs/framework/collaboration-autonomy-plan.md +18 -18
- package/docs/guides/parallel-workflow.md +6 -6
- package/package.json +22 -5
- package/packages/installer/src/installer/git-hooks-installer.js +384 -0
- package/packages/installer/src/installer/sinapse-ai-installer.js +16 -0
- package/packages/installer/src/wizard/ide-config-generator.js +23 -0
- package/packages/installer/src/wizard/validators.js +38 -1
- package/packages/installer/tests/unit/artifact-copy-pipeline/artifact-copy-pipeline.test.js +5 -1
- package/packages/installer/tests/unit/doctor/doctor-checks.test.js +44 -22
- package/packages/installer/tests/unit/git-hooks-installer.test.js +262 -0
- package/scripts/eval-runner.js +422 -0
- package/scripts/generate-install-manifest.js +13 -9
- package/scripts/generate-synapse-runtime.js +51 -0
- package/scripts/regenerate-orqx-stubs.ps1 +6 -5
- package/scripts/validate-all.js +1 -0
- package/scripts/validate-evals.js +466 -0
- package/scripts/validate-schemas.js +539 -0
- package/scripts/validate-squad-orqx.js +9 -2
- package/squads/claude-code-mastery/knowledge-base/memory-systems-reference.md +1 -1
- package/squads/squad-brand/templates/client-delivery-template.md +1 -1
- package/squads/squad-content/knowledge-base/social-compression-framework.md +1 -1
- package/squads/squad-council/knowledge-base/brand-strategy-models.md +1 -1
- package/.sinapse-ai/development/scripts/elicitation-engine.js +0 -385
- package/.sinapse-ai/development/scripts/elicitation-session-manager.js +0 -300
- package/.sinapse-ai/development/tasks/test-validation-task.md +0 -172
- package/docs/chrome-brain-upgrade-plan.md +0 -624
- package/docs/constitution-compliance.md +0 -87
- package/docs/mega-upgrade-orchestration-plan.md +0 -71
- package/docs/research-synthesis-for-upgrade.md +0 -511
- package/docs/security-audit-report.md +0 -306
|
@@ -0,0 +1,422 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Eval Harness — Runner (CLI)
|
|
6
|
+
*
|
|
7
|
+
* Discovers eval suites under `tests/evals/<gate>/evals.json`, runs each case
|
|
8
|
+
* against the REAL verification gate (the exact same class the SDC workflow uses
|
|
9
|
+
* via GateEvaluator), scores the GateResult with the deterministic scorer, and
|
|
10
|
+
* prints a JSON report per gate plus a final aggregate block.
|
|
11
|
+
*
|
|
12
|
+
* Usage:
|
|
13
|
+
* node scripts/eval-runner.js # run every gate that has tests/evals/<gate>/evals.json
|
|
14
|
+
* node scripts/eval-runner.js G5 # run only the G5 suite
|
|
15
|
+
*
|
|
16
|
+
* Exit code (FAIL-CLOSED — eval is a test, not production runtime):
|
|
17
|
+
* 0 -> every case in every suite succeeded (success === true)
|
|
18
|
+
* 1 -> at least one case failed, OR a suite file was malformed/unrunnable
|
|
19
|
+
*
|
|
20
|
+
* Hard guarantees:
|
|
21
|
+
* - Reads gates from the barrel (.sinapse-ai/core/ids/index.js). Never mutates
|
|
22
|
+
* a gate or verification-gate.js.
|
|
23
|
+
* - Pure Node, zero new dependencies, Windows-native paths via `path`.
|
|
24
|
+
* - Malformed evals.json produce an ACTIONABLE error naming the file.
|
|
25
|
+
*
|
|
26
|
+
* @module scripts/eval-runner
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
const fs = require('fs');
|
|
30
|
+
const path = require('path');
|
|
31
|
+
|
|
32
|
+
// ---------------------------------------------------------------------------
|
|
33
|
+
// Paths
|
|
34
|
+
// ---------------------------------------------------------------------------
|
|
35
|
+
|
|
36
|
+
const REPO_ROOT = path.resolve(__dirname, '..');
|
|
37
|
+
const EVALS_ROOT = path.resolve(REPO_ROOT, 'tests', 'evals');
|
|
38
|
+
const IDS_BARREL = path.resolve(REPO_ROOT, '.sinapse-ai', 'core', 'ids', 'index.js');
|
|
39
|
+
const SCORE_LIB = path.resolve(EVALS_ROOT, '_lib', 'score.js');
|
|
40
|
+
|
|
41
|
+
// Folders under tests/evals/ that are libraries, not gate suites.
|
|
42
|
+
const RESERVED_DIRS = new Set(['_lib']);
|
|
43
|
+
|
|
44
|
+
// ---------------------------------------------------------------------------
|
|
45
|
+
// Quiet logger — suppresses gate console noise during eval runs.
|
|
46
|
+
// ---------------------------------------------------------------------------
|
|
47
|
+
|
|
48
|
+
const QUIET_LOGGER = { info() {}, warn() {}, error() {}, log() {} };
|
|
49
|
+
|
|
50
|
+
// ---------------------------------------------------------------------------
|
|
51
|
+
// Lazy module loads (so a missing barrel produces an actionable message, not a
|
|
52
|
+
// raw stack at require time).
|
|
53
|
+
// ---------------------------------------------------------------------------
|
|
54
|
+
|
|
55
|
+
function loadIdsBarrel() {
|
|
56
|
+
if (!fs.existsSync(IDS_BARREL)) {
|
|
57
|
+
fail(`IDS barrel not found at ${IDS_BARREL}. Cannot instantiate gates.`);
|
|
58
|
+
}
|
|
59
|
+
try {
|
|
60
|
+
return require(IDS_BARREL);
|
|
61
|
+
} catch (err) {
|
|
62
|
+
fail(`Failed to load IDS barrel ${IDS_BARREL}: ${err.message}`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function loadScoreLib() {
|
|
67
|
+
if (!fs.existsSync(SCORE_LIB)) {
|
|
68
|
+
fail(`Scorer not found at ${SCORE_LIB}.`);
|
|
69
|
+
}
|
|
70
|
+
try {
|
|
71
|
+
return require(SCORE_LIB);
|
|
72
|
+
} catch (err) {
|
|
73
|
+
fail(`Failed to load scorer ${SCORE_LIB}: ${err.message}`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// ---------------------------------------------------------------------------
|
|
78
|
+
// Gate factory — maps a gateId to a constructed gate instance.
|
|
79
|
+
//
|
|
80
|
+
// Mirrors GateEvaluator._buildGate wiring (timeoutMs + quiet logger). G3/G5
|
|
81
|
+
// take extra deps; G3 needs a RegistryLoader, the rest need a decisionEngine.
|
|
82
|
+
// We reuse the barrel's classes so the eval exercises the production gate.
|
|
83
|
+
// ---------------------------------------------------------------------------
|
|
84
|
+
|
|
85
|
+
function makeGateFactory(ids) {
|
|
86
|
+
const {
|
|
87
|
+
G1EpicCreationGate,
|
|
88
|
+
G2StoryCreationGate,
|
|
89
|
+
G3StoryValidationGate,
|
|
90
|
+
G4DevContextGate,
|
|
91
|
+
G5SemanticHandshakeGate,
|
|
92
|
+
RegistryLoader,
|
|
93
|
+
IncrementalDecisionEngine,
|
|
94
|
+
} = ids;
|
|
95
|
+
|
|
96
|
+
// Lazily built, shared across gates within one runner invocation.
|
|
97
|
+
let registryLoader = null;
|
|
98
|
+
let decisionEngine = null;
|
|
99
|
+
|
|
100
|
+
function getRegistryLoader() {
|
|
101
|
+
if (!registryLoader) registryLoader = new RegistryLoader();
|
|
102
|
+
return registryLoader;
|
|
103
|
+
}
|
|
104
|
+
function getDecisionEngine() {
|
|
105
|
+
if (!decisionEngine) decisionEngine = new IncrementalDecisionEngine(getRegistryLoader());
|
|
106
|
+
return decisionEngine;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const logger = QUIET_LOGGER;
|
|
110
|
+
|
|
111
|
+
return function buildGate(gateId) {
|
|
112
|
+
switch (gateId) {
|
|
113
|
+
case 'G1':
|
|
114
|
+
return new G1EpicCreationGate({ decisionEngine: getDecisionEngine(), logger });
|
|
115
|
+
case 'G2':
|
|
116
|
+
return new G2StoryCreationGate({ decisionEngine: getDecisionEngine(), logger });
|
|
117
|
+
case 'G3':
|
|
118
|
+
return new G3StoryValidationGate({
|
|
119
|
+
decisionEngine: getDecisionEngine(),
|
|
120
|
+
registryLoader: getRegistryLoader(),
|
|
121
|
+
logger,
|
|
122
|
+
});
|
|
123
|
+
case 'G4':
|
|
124
|
+
return new G4DevContextGate({ decisionEngine: getDecisionEngine(), logger });
|
|
125
|
+
case 'G5':
|
|
126
|
+
return new G5SemanticHandshakeGate({ logger });
|
|
127
|
+
default:
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// ---------------------------------------------------------------------------
|
|
134
|
+
// Suite discovery
|
|
135
|
+
// ---------------------------------------------------------------------------
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Discover every `tests/evals/<gate>/evals.json`.
|
|
139
|
+
* @returns {Array<{ gateDir:string, gateFolder:string, evalsPath:string }>}
|
|
140
|
+
*/
|
|
141
|
+
function discoverSuites() {
|
|
142
|
+
if (!fs.existsSync(EVALS_ROOT)) {
|
|
143
|
+
return [];
|
|
144
|
+
}
|
|
145
|
+
const entries = fs.readdirSync(EVALS_ROOT, { withFileTypes: true });
|
|
146
|
+
const suites = [];
|
|
147
|
+
for (const entry of entries) {
|
|
148
|
+
if (!entry.isDirectory()) continue;
|
|
149
|
+
if (RESERVED_DIRS.has(entry.name)) continue;
|
|
150
|
+
const evalsPath = path.resolve(EVALS_ROOT, entry.name, 'evals.json');
|
|
151
|
+
if (fs.existsSync(evalsPath)) {
|
|
152
|
+
suites.push({
|
|
153
|
+
gateFolder: entry.name,
|
|
154
|
+
gateDir: path.resolve(EVALS_ROOT, entry.name),
|
|
155
|
+
evalsPath,
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
// Deterministic ordering by folder name.
|
|
160
|
+
suites.sort((a, b) => a.gateFolder.localeCompare(b.gateFolder));
|
|
161
|
+
return suites;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// ---------------------------------------------------------------------------
|
|
165
|
+
// Suite loading + shallow validation (actionable errors that name the file).
|
|
166
|
+
// ---------------------------------------------------------------------------
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Read + parse + shallow-validate an evals.json file.
|
|
170
|
+
* Throws an Error with an actionable, file-scoped message on any problem.
|
|
171
|
+
* @param {string} evalsPath
|
|
172
|
+
* @returns {{ gateId:string, phase?:string, cases:Array<object> }}
|
|
173
|
+
*/
|
|
174
|
+
function loadSuite(evalsPath) {
|
|
175
|
+
let raw;
|
|
176
|
+
try {
|
|
177
|
+
raw = fs.readFileSync(evalsPath, 'utf8');
|
|
178
|
+
} catch (err) {
|
|
179
|
+
throw new Error(`Cannot read eval suite '${evalsPath}': ${err.message}`);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
let suite;
|
|
183
|
+
try {
|
|
184
|
+
suite = JSON.parse(raw);
|
|
185
|
+
} catch (err) {
|
|
186
|
+
throw new Error(`Malformed JSON in '${evalsPath}': ${err.message}`);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
if (!suite || typeof suite !== 'object' || Array.isArray(suite)) {
|
|
190
|
+
throw new Error(`Eval suite '${evalsPath}' must be a JSON object.`);
|
|
191
|
+
}
|
|
192
|
+
if (typeof suite.gateId !== 'string' || !/^G[1-9][0-9]*$/.test(suite.gateId)) {
|
|
193
|
+
throw new Error(
|
|
194
|
+
`Eval suite '${evalsPath}' has missing/invalid "gateId" (expected /^G[1-9][0-9]*$/, got ${JSON.stringify(
|
|
195
|
+
suite.gateId,
|
|
196
|
+
)}).`,
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
if (!Array.isArray(suite.cases)) {
|
|
200
|
+
throw new Error(`Eval suite '${evalsPath}' is missing a "cases" array.`);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
suite.cases.forEach((caseObj, i) => {
|
|
204
|
+
const where = `'${evalsPath}' case[${i}]${caseObj && caseObj.id ? ` (id="${caseObj.id}")` : ''}`;
|
|
205
|
+
if (!caseObj || typeof caseObj !== 'object' || Array.isArray(caseObj)) {
|
|
206
|
+
throw new Error(`${where} must be an object.`);
|
|
207
|
+
}
|
|
208
|
+
if (typeof caseObj.id !== 'string' || caseObj.id.length === 0) {
|
|
209
|
+
throw new Error(`${where} is missing a non-empty string "id".`);
|
|
210
|
+
}
|
|
211
|
+
if (!caseObj.context || typeof caseObj.context !== 'object' || Array.isArray(caseObj.context)) {
|
|
212
|
+
throw new Error(`${where} is missing a "context" object (passed verbatim to gate.verify()).`);
|
|
213
|
+
}
|
|
214
|
+
if (!Array.isArray(caseObj.expectations) || caseObj.expectations.length === 0) {
|
|
215
|
+
throw new Error(`${where} is missing a non-empty "expectations" array.`);
|
|
216
|
+
}
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
return suite;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// ---------------------------------------------------------------------------
|
|
223
|
+
// Running a single suite
|
|
224
|
+
// ---------------------------------------------------------------------------
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Run every case in a loaded suite against its gate and score the results.
|
|
228
|
+
*
|
|
229
|
+
* @param {object} suite — { gateId, phase?, cases[] } from loadSuite().
|
|
230
|
+
* @param {string} evalsPath — for error messages.
|
|
231
|
+
* @param {function} buildGate — gateId -> gate instance.
|
|
232
|
+
* @param {function} evaluateCase — scorer from score.js.
|
|
233
|
+
* @returns {Promise<object>} per-gate report.
|
|
234
|
+
*/
|
|
235
|
+
async function runSuite(suite, evalsPath, buildGate, evaluateCase) {
|
|
236
|
+
const gate = buildGate(suite.gateId);
|
|
237
|
+
if (!gate) {
|
|
238
|
+
throw new Error(
|
|
239
|
+
`Eval suite '${evalsPath}' targets unknown gateId "${suite.gateId}". ` +
|
|
240
|
+
'Known gates: G1, G2, G3, G4, G5.',
|
|
241
|
+
);
|
|
242
|
+
}
|
|
243
|
+
if (typeof gate.verify !== 'function') {
|
|
244
|
+
throw new Error(`Gate "${suite.gateId}" (from '${evalsPath}') has no verify() method.`);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
const cases = [];
|
|
248
|
+
let passedCount = 0;
|
|
249
|
+
|
|
250
|
+
for (const caseObj of suite.cases) {
|
|
251
|
+
let gateResult;
|
|
252
|
+
try {
|
|
253
|
+
gateResult = await gate.verify(caseObj.context);
|
|
254
|
+
} catch (err) {
|
|
255
|
+
// VerificationGate.verify() is fail-open and should not throw; if it does,
|
|
256
|
+
// record the case as a hard failure with an actionable reason.
|
|
257
|
+
cases.push({
|
|
258
|
+
id: caseObj.id,
|
|
259
|
+
score: 0,
|
|
260
|
+
success: false,
|
|
261
|
+
reason: `gate.verify() threw: ${err.message}`,
|
|
262
|
+
failedExpectations: (caseObj.expectations || []).map((e) => ({
|
|
263
|
+
id: e && e.id,
|
|
264
|
+
reason: 'gate.verify() threw before scoring',
|
|
265
|
+
})),
|
|
266
|
+
});
|
|
267
|
+
continue;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
const scored = evaluateCase(gateResult, caseObj);
|
|
271
|
+
if (scored.success) passedCount += 1;
|
|
272
|
+
|
|
273
|
+
const failedExpectations = (scored.details || [])
|
|
274
|
+
.filter((d) => !d.passed)
|
|
275
|
+
.map((d) => ({ id: d.id, reason: d.reason }));
|
|
276
|
+
|
|
277
|
+
cases.push({
|
|
278
|
+
id: scored.id,
|
|
279
|
+
score: scored.score,
|
|
280
|
+
success: scored.success,
|
|
281
|
+
reason: scored.reason,
|
|
282
|
+
failedExpectations,
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
return {
|
|
287
|
+
gateId: suite.gateId,
|
|
288
|
+
phase: suite.phase || null,
|
|
289
|
+
source: evalsPath,
|
|
290
|
+
cases,
|
|
291
|
+
summary: {
|
|
292
|
+
total: cases.length,
|
|
293
|
+
passed: passedCount,
|
|
294
|
+
failed: cases.length - passedCount,
|
|
295
|
+
},
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// ---------------------------------------------------------------------------
|
|
300
|
+
// Orchestration
|
|
301
|
+
// ---------------------------------------------------------------------------
|
|
302
|
+
|
|
303
|
+
async function main() {
|
|
304
|
+
const argv = process.argv.slice(2);
|
|
305
|
+
const requestedGate = (argv[0] || '').trim();
|
|
306
|
+
|
|
307
|
+
if (requestedGate && !/^G[1-9][0-9]*$/i.test(requestedGate)) {
|
|
308
|
+
fail(
|
|
309
|
+
`Invalid gateId argument "${requestedGate}". Expected something like "G5", ` +
|
|
310
|
+
'or no argument to run all suites.',
|
|
311
|
+
);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
const allSuites = discoverSuites();
|
|
315
|
+
|
|
316
|
+
let suites = allSuites;
|
|
317
|
+
if (requestedGate) {
|
|
318
|
+
const target = requestedGate.toUpperCase();
|
|
319
|
+
const targetFolder = target.toLowerCase();
|
|
320
|
+
suites = allSuites.filter(
|
|
321
|
+
(s) => s.gateFolder.toLowerCase() === targetFolder || s.gateFolder.toLowerCase() === target.toLowerCase(),
|
|
322
|
+
);
|
|
323
|
+
if (suites.length === 0) {
|
|
324
|
+
fail(
|
|
325
|
+
`No eval suite found for gate "${target}". Expected ` +
|
|
326
|
+
`${path.resolve(EVALS_ROOT, targetFolder, 'evals.json')}.`,
|
|
327
|
+
);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// Nothing to do — clean exit, never crash (per smoke-run contract).
|
|
332
|
+
if (suites.length === 0) {
|
|
333
|
+
const empty = {
|
|
334
|
+
runner: 'eval-runner',
|
|
335
|
+
evalsRoot: EVALS_ROOT,
|
|
336
|
+
gates: [],
|
|
337
|
+
summary: { gates: 0, cases: 0, passed: 0, failed: 0, malformedSuites: 0 },
|
|
338
|
+
success: true,
|
|
339
|
+
};
|
|
340
|
+
process.stdout.write(JSON.stringify(empty, null, 2) + '\n');
|
|
341
|
+
process.exit(0);
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
const ids = loadIdsBarrel();
|
|
345
|
+
const { evaluateCase } = loadScoreLib();
|
|
346
|
+
const buildGate = makeGateFactory(ids);
|
|
347
|
+
|
|
348
|
+
const reports = [];
|
|
349
|
+
const malformed = [];
|
|
350
|
+
|
|
351
|
+
for (const suiteRef of suites) {
|
|
352
|
+
let suite;
|
|
353
|
+
try {
|
|
354
|
+
suite = loadSuite(suiteRef.evalsPath);
|
|
355
|
+
} catch (err) {
|
|
356
|
+
// Actionable, file-scoped error. Record as malformed -> fail-closed.
|
|
357
|
+
malformed.push({ source: suiteRef.evalsPath, error: err.message });
|
|
358
|
+
process.stderr.write(`[eval-runner] ${err.message}\n`);
|
|
359
|
+
continue;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
let report;
|
|
363
|
+
try {
|
|
364
|
+
report = await runSuite(suite, suiteRef.evalsPath, buildGate, evaluateCase);
|
|
365
|
+
} catch (err) {
|
|
366
|
+
malformed.push({ source: suiteRef.evalsPath, error: err.message });
|
|
367
|
+
process.stderr.write(`[eval-runner] ${err.message}\n`);
|
|
368
|
+
continue;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
reports.push(report);
|
|
372
|
+
// Per-gate report block.
|
|
373
|
+
process.stdout.write(JSON.stringify(report, null, 2) + '\n');
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
// Aggregate.
|
|
377
|
+
const totalCases = reports.reduce((acc, r) => acc + r.summary.total, 0);
|
|
378
|
+
const totalPassed = reports.reduce((acc, r) => acc + r.summary.passed, 0);
|
|
379
|
+
const totalFailed = reports.reduce((acc, r) => acc + r.summary.failed, 0);
|
|
380
|
+
const success = totalFailed === 0 && malformed.length === 0;
|
|
381
|
+
|
|
382
|
+
const aggregate = {
|
|
383
|
+
runner: 'eval-runner',
|
|
384
|
+
evalsRoot: EVALS_ROOT,
|
|
385
|
+
gates: reports.map((r) => ({
|
|
386
|
+
gateId: r.gateId,
|
|
387
|
+
total: r.summary.total,
|
|
388
|
+
passed: r.summary.passed,
|
|
389
|
+
failed: r.summary.failed,
|
|
390
|
+
})),
|
|
391
|
+
malformedSuites: malformed,
|
|
392
|
+
summary: {
|
|
393
|
+
gates: reports.length,
|
|
394
|
+
cases: totalCases,
|
|
395
|
+
passed: totalPassed,
|
|
396
|
+
failed: totalFailed,
|
|
397
|
+
malformedSuites: malformed.length,
|
|
398
|
+
},
|
|
399
|
+
success,
|
|
400
|
+
};
|
|
401
|
+
|
|
402
|
+
process.stdout.write('=== AGGREGATE ===\n');
|
|
403
|
+
process.stdout.write(JSON.stringify(aggregate, null, 2) + '\n');
|
|
404
|
+
|
|
405
|
+
// FAIL-CLOSED: any failed case or malformed suite -> exit 1.
|
|
406
|
+
process.exit(success ? 0 : 1);
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
// ---------------------------------------------------------------------------
|
|
410
|
+
// Fatal helper — actionable message, exit 1 (fail-closed).
|
|
411
|
+
// ---------------------------------------------------------------------------
|
|
412
|
+
|
|
413
|
+
function fail(message) {
|
|
414
|
+
process.stderr.write(`[eval-runner] ERROR: ${message}\n`);
|
|
415
|
+
process.exit(1);
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
main().catch((err) => {
|
|
419
|
+
// Last-resort guard: any unexpected throw fails closed with a stack.
|
|
420
|
+
process.stderr.write(`[eval-runner] FATAL: ${err && err.stack ? err.stack : err}\n`);
|
|
421
|
+
process.exit(1);
|
|
422
|
+
});
|
|
@@ -63,15 +63,19 @@ const EXCLUDE_PATTERNS = [
|
|
|
63
63
|
/\.bak$/,
|
|
64
64
|
/\.tmp$/,
|
|
65
65
|
/~$/,
|
|
66
|
-
// Gitignored legacy docs (not tracked in repo)
|
|
67
|
-
/
|
|
68
|
-
/docs
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
66
|
+
// Gitignored legacy docs (not tracked in repo).
|
|
67
|
+
// Anchored to ^docs/ so they only match the top-level .sinapse-ai/docs/ tree.
|
|
68
|
+
// Unanchored, /docs\/.../ also matched nested core/docs/*.md and wrongly
|
|
69
|
+
// excluded 5 TRACKED framework docs from the manifest (so brownfield upgrades
|
|
70
|
+
// never tracked their drift).
|
|
71
|
+
/^docs\/standards\/SINAPSE-LIVRO-DE-OURO/,
|
|
72
|
+
/^docs\/standards\/SINAPSE-FRAMEWORK-MASTER\.md$/,
|
|
73
|
+
/^docs\/standards\/V3-ARCHITECTURAL-DECISIONS\.md$/,
|
|
74
|
+
/^docs\/SHARD-TRANSLATION-GUIDE\.md$/,
|
|
75
|
+
/^docs\/component-creation-guide\.md$/,
|
|
76
|
+
/^docs\/template-syntax\.md$/,
|
|
77
|
+
/^docs\/troubleshooting-guide\.md$/,
|
|
78
|
+
/^docs\/session-update-pattern\.md$/,
|
|
75
79
|
// Gitignored generated files
|
|
76
80
|
/data\/registry-update-log\.jsonl$/,
|
|
77
81
|
/data\/registry-healing-log\.jsonl$/,
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Generate the .synapse/ runtime domains consumed by the SYNAPSE context engine.
|
|
6
|
+
*
|
|
7
|
+
* Currently builds the L0 constitution domain from .sinapse-ai/constitution.md.
|
|
8
|
+
* (L1/L2 domains degrade gracefully when absent — loadDomainFile returns []).
|
|
9
|
+
*
|
|
10
|
+
* TOLERANT BY DESIGN: a generation hiccup must NEVER fail the build or block the
|
|
11
|
+
* test suite. The engine already degrades gracefully when domains are missing
|
|
12
|
+
* (the hook silently emits no context). So this wrapper always exits 0 and only
|
|
13
|
+
* surfaces detail under DEBUG=1.
|
|
14
|
+
*
|
|
15
|
+
* Wired into: `npm run generate:synapse`, `pretest`, and the postinstall setup.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
function generate() {
|
|
19
|
+
// Silence the generator's own console.log (e.g. "Constitution generated…")
|
|
20
|
+
// during pretest unless DEBUG=1 — keeps `npm test` output clean.
|
|
21
|
+
const debug = process.env.DEBUG === '1';
|
|
22
|
+
const origLog = console.log;
|
|
23
|
+
if (!debug) console.log = () => {};
|
|
24
|
+
try {
|
|
25
|
+
const { main } = require('../.sinapse-ai/core/synapse/scripts/generate-constitution.js');
|
|
26
|
+
const result = main();
|
|
27
|
+
if (result && result.success) {
|
|
28
|
+
if (debug) {
|
|
29
|
+
console.error(`[generate-synapse] constitution: ${result.articles} articles, ${result.rules} rules`);
|
|
30
|
+
}
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
if (debug) {
|
|
34
|
+
console.error(`[generate-synapse] constitution skipped: ${result && result.error}`);
|
|
35
|
+
}
|
|
36
|
+
} catch (err) {
|
|
37
|
+
if (debug) {
|
|
38
|
+
console.error(`[generate-synapse] error: ${err && err.message}`);
|
|
39
|
+
}
|
|
40
|
+
} finally {
|
|
41
|
+
console.log = origLog;
|
|
42
|
+
}
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (require.main === module) {
|
|
47
|
+
generate();
|
|
48
|
+
process.exitCode = 0; // never block the build/test
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
module.exports = { generate };
|
|
@@ -34,11 +34,12 @@ $stubsDir = Join-Path $env:USERPROFILE '.claude\agents'
|
|
|
34
34
|
foreach ($m in $mapping) {
|
|
35
35
|
$id = $m.id
|
|
36
36
|
$squad = $m.squad
|
|
37
|
-
$
|
|
38
|
-
$
|
|
39
|
-
$
|
|
40
|
-
$
|
|
41
|
-
$
|
|
37
|
+
$sinapseHome = Join-Path $env:USERPROFILE '.sinapse'
|
|
38
|
+
$canonical = "$sinapseHome/$squad/agents/$id.md"
|
|
39
|
+
$manifest = "$sinapseHome/$squad/squad.yaml"
|
|
40
|
+
$tasks = "$sinapseHome/$squad/tasks/"
|
|
41
|
+
$kb = "$sinapseHome/$squad/knowledge-base/"
|
|
42
|
+
$wf = "$sinapseHome/$squad/workflows/"
|
|
42
43
|
$invocation = "/SINAPSE:agents:$id"
|
|
43
44
|
|
|
44
45
|
$content = @"
|
package/scripts/validate-all.js
CHANGED
|
@@ -52,6 +52,7 @@ const GUARDS = [
|
|
|
52
52
|
{ name: 'cross-refs', script: 'validate:cross-refs' },
|
|
53
53
|
{ name: 'manifest:parity', script: 'validate:manifest:parity' },
|
|
54
54
|
{ name: 'squad-yaml', script: 'validate:squad-yaml' },
|
|
55
|
+
{ name: 'squad-orqx', script: 'validate:squad-orqx' },
|
|
55
56
|
];
|
|
56
57
|
|
|
57
58
|
/**
|