sinapse-ai 1.12.1 → 1.13.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 +2 -2
- package/.claude/rules/agent-memory-imports.md +2 -0
- package/.sinapse-ai/cli/commands/pro/index.js +8 -48
- package/.sinapse-ai/constitution.md +6 -2
- package/.sinapse-ai/core-config.yaml +5 -1
- package/.sinapse-ai/data/entity-registry.yaml +95 -95
- package/.sinapse-ai/development/agents/architect/MEMORY.md +35 -0
- package/.sinapse-ai/development/agents/data-engineer/MEMORY.md +38 -0
- package/.sinapse-ai/development/agents/developer/MEMORY.md +36 -0
- package/.sinapse-ai/development/agents/devops/MEMORY.md +39 -0
- package/.sinapse-ai/development/agents/devops.md +0 -1
- package/.sinapse-ai/development/agents/product-lead/MEMORY.md +36 -0
- package/.sinapse-ai/development/agents/project-lead/MEMORY.md +36 -0
- package/.sinapse-ai/development/agents/quality-gate/MEMORY.md +35 -0
- package/.sinapse-ai/development/agents/quality-gate.md +1 -1
- package/.sinapse-ai/development/agents/snps-orqx.md +4 -0
- package/.sinapse-ai/development/agents/sprint-lead/MEMORY.md +36 -0
- package/.sinapse-ai/development/templates/chrome-brain/knowledge-base/chrome-brain.md +2 -2
- package/.sinapse-ai/infrastructure/scripts/ide-sync/index.js +15 -0
- package/.sinapse-ai/infrastructure/scripts/validate-agents.js +159 -8
- package/.sinapse-ai/install-manifest.yaml +20 -156
- package/AGENTS.md +13 -2
- package/CHANGELOG.md +119 -4
- package/README.en.md +1 -1
- package/README.md +6 -26
- package/bin/cli.js +2 -7
- package/bin/commands/install.js +19 -257
- package/bin/commands/update.js +18 -78
- package/bin/lib/command-generator.js +261 -0
- package/bin/lib/prompts.js +2 -65
- package/bin/modules/chrome-brain-installer.js +2 -1
- package/bin/postinstall.js +6 -6
- package/docs/getting-started.md +0 -1
- package/docs/pt/getting-started.md +1 -1
- package/docs/security/dependabot-triage.md +17 -17
- package/package.json +6 -3
- package/packages/installer/src/wizard/i18n.js +3 -204
- package/packages/installer/src/wizard/index.js +1 -1
- package/packages/installer/src/wizard/questions.js +5 -368
- package/packages/installer/src/wizard/wizard.js +0 -9
- package/scripts/generate-install-manifest.js +6 -0
- package/scripts/validate-changelog-tags.js +97 -0
- package/scripts/validate-no-personal-leaks.js +184 -28
- package/scripts/validate-schemas.js +55 -10
- package/scripts/validate-story-meta.js +25 -12
- package/squads/claude-code-mastery/agents/claude-mastery-chief.md +1 -1
- package/squads/claude-code-mastery/agents/hooks-architect.md +12 -20
- package/squads/claude-code-mastery/tasks/audit-setup.md +1 -1
- package/squads/squad-product/agents/product-orqx.md +0 -1
- package/squads/squad-product/agents/ps-client-product-manager.md +0 -1
- package/squads/squad-product/agents/ps-delivery-manager.md +0 -1
- package/squads/squad-product/agents/ps-discovery-lead.md +0 -1
- package/squads/squad-product/agents/ps-product-analyst.md +0 -1
- package/squads/squad-product/agents/ps-product-ops-specialist.md +0 -1
- package/squads/squad-product/agents/ps-product-strategist.md +0 -1
- package/.sinapse-ai/core/grounding/README.md +0 -83
- package/.sinapse-ai/core/grounding/brand.cjs +0 -29
- package/.sinapse-ai/core/grounding/config-loader.cjs +0 -52
- package/.sinapse-ai/core/grounding/design-system.cjs +0 -29
- package/.sinapse-ai/core/grounding/vault.cjs +0 -36
- package/.sinapse-ai/development/scripts/approval-workflow.js +0 -643
- package/.sinapse-ai/development/scripts/backup-manager.js +0 -607
- package/.sinapse-ai/development/scripts/branch-manager.js +0 -390
- package/.sinapse-ai/development/scripts/code-quality-improver.js +0 -1329
- package/.sinapse-ai/development/scripts/commit-message-generator.js +0 -850
- package/.sinapse-ai/development/scripts/conflict-resolver.js +0 -675
- package/.sinapse-ai/development/scripts/dependency-analyzer.js +0 -638
- package/.sinapse-ai/development/scripts/diff-generator.js +0 -352
- package/.sinapse-ai/development/scripts/git-wrapper.js +0 -462
- package/.sinapse-ai/development/scripts/modification-validator.js +0 -555
- package/.sinapse-ai/development/scripts/performance-analyzer.js +0 -758
- package/.sinapse-ai/development/scripts/refactoring-suggester.js +0 -1148
- package/.sinapse-ai/development/scripts/rollback-handler.js +0 -531
- package/.sinapse-ai/development/scripts/security-checker.js +0 -359
- package/.sinapse-ai/development/scripts/template-engine.js +0 -240
- package/.sinapse-ai/development/scripts/template-validator.js +0 -279
- package/.sinapse-ai/development/scripts/test-generator.js +0 -844
- package/.sinapse-ai/development/scripts/transaction-manager.js +0 -590
- package/.sinapse-ai/development/scripts/yaml-validator.js +0 -397
- package/.sinapse-ai/hooks/sinapse-brand-grounding.cjs +0 -162
- package/.sinapse-ai/hooks/sinapse-ds-grounding.cjs +0 -211
- package/.sinapse-ai/hooks/sinapse-vault-grounding.cjs +0 -194
- package/bin/lib/register-grounding-hooks.js +0 -145
- package/docs/guides/agents/traces/execution-traces.zip +0 -0
- package/docs/guides/grounding-setup.md +0 -154
- package/docs/guides/workflows/SINAPSE-WORKFLOWS.zip +0 -0
- package/packages/installer/src/pro/pro-scaffolder.js +0 -449
- package/packages/installer/src/wizard/grounding-config.js +0 -131
- package/packages/installer/src/wizard/pro-setup.js +0 -1439
- package/packages/installer/templates/README.md +0 -16
- package/packages/installer/templates/brand-routing.example.json +0 -12
- package/packages/installer/templates/ds-routing.example.json +0 -12
- package/packages/installer/templates/vault-routing.example.json +0 -12
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Validate Changelog Tags
|
|
4
|
+
*
|
|
5
|
+
* Guards against release/version drift: every published git version tag MUST
|
|
6
|
+
* have a matching `## [x.y.z]` heading in CHANGELOG.md. This catches the failure
|
|
7
|
+
* mode where semantic-release publishes a version but the CHANGELOG entry was
|
|
8
|
+
* never committed back to the repo (the root cause of the 1.9.0 -> 1.12.2 drift).
|
|
9
|
+
*
|
|
10
|
+
* Usage:
|
|
11
|
+
* node scripts/validate-changelog-tags.js
|
|
12
|
+
* npm run validate:changelog
|
|
13
|
+
*
|
|
14
|
+
* Exit codes:
|
|
15
|
+
* 0 - Every version tag has a CHANGELOG heading (or git unavailable -> SKIP)
|
|
16
|
+
* 1 - One or more version tags are missing a CHANGELOG heading
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
'use strict';
|
|
20
|
+
|
|
21
|
+
const fs = require('fs');
|
|
22
|
+
const path = require('path');
|
|
23
|
+
const { execFileSync } = require('child_process');
|
|
24
|
+
|
|
25
|
+
const ROOT = path.resolve(__dirname, '..');
|
|
26
|
+
const CHANGELOG_PATH = path.join(ROOT, 'CHANGELOG.md');
|
|
27
|
+
|
|
28
|
+
// Matches a clean semver core: x.y.z (no pre-release/build suffix).
|
|
29
|
+
const SEMVER_RE = /^\d+\.\d+\.\d+$/;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* List git version tags, normalized (leading `v` stripped) and filtered to
|
|
33
|
+
* clean `x.y.z` semver. Returns null if git is unavailable (offline / no repo).
|
|
34
|
+
* @returns {string[]|null}
|
|
35
|
+
*/
|
|
36
|
+
function listVersionTags() {
|
|
37
|
+
let raw;
|
|
38
|
+
try {
|
|
39
|
+
raw = execFileSync('git', ['tag', '-l'], { cwd: ROOT, encoding: 'utf8' });
|
|
40
|
+
} catch {
|
|
41
|
+
return null; // git not available or not a repo
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return raw
|
|
45
|
+
.split('\n')
|
|
46
|
+
.map((t) => t.trim())
|
|
47
|
+
.filter(Boolean)
|
|
48
|
+
.map((t) => t.replace(/^v/, ''))
|
|
49
|
+
.filter((t) => SEMVER_RE.test(t));
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Collect all `## [x.y.z]` headings from CHANGELOG.md.
|
|
54
|
+
* @returns {Set<string>}
|
|
55
|
+
*/
|
|
56
|
+
function collectChangelogVersions() {
|
|
57
|
+
const content = fs.readFileSync(CHANGELOG_PATH, 'utf8');
|
|
58
|
+
const headings = new Set();
|
|
59
|
+
const re = /^##\s*\[(\d+\.\d+\.\d+)\]/gm;
|
|
60
|
+
let m;
|
|
61
|
+
while ((m = re.exec(content)) !== null) {
|
|
62
|
+
headings.add(m[1]);
|
|
63
|
+
}
|
|
64
|
+
return headings;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function main() {
|
|
68
|
+
const tags = listVersionTags();
|
|
69
|
+
|
|
70
|
+
if (tags === null) {
|
|
71
|
+
console.log('SKIP — git is unavailable; cannot cross-check tags vs CHANGELOG.');
|
|
72
|
+
process.exit(0);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (!fs.existsSync(CHANGELOG_PATH)) {
|
|
76
|
+
console.error('FAIL — CHANGELOG.md not found.');
|
|
77
|
+
process.exit(1);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const documented = collectChangelogVersions();
|
|
81
|
+
const missing = tags.filter((t) => !documented.has(t)).sort();
|
|
82
|
+
|
|
83
|
+
if (missing.length > 0) {
|
|
84
|
+
console.error('FAIL — version tags without a CHANGELOG heading:');
|
|
85
|
+
for (const v of missing) {
|
|
86
|
+
console.error(` - ${v} (expected "## [${v}]" in CHANGELOG.md)`);
|
|
87
|
+
}
|
|
88
|
+
console.error('');
|
|
89
|
+
console.error('Add the missing entries to CHANGELOG.md before releasing.');
|
|
90
|
+
process.exit(1);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
console.log(`OK — all ${tags.length} version tag(s) have a CHANGELOG heading.`);
|
|
94
|
+
process.exit(0);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
main();
|
|
@@ -32,6 +32,20 @@
|
|
|
32
32
|
* - "Caio's Second Brain", "Caio's vault" — vault path references
|
|
33
33
|
* - "C:\\Users\\Caio Imori" — absolute paths
|
|
34
34
|
* - "OneDrive\\...\\Second-Brain" — vault path references
|
|
35
|
+
*
|
|
36
|
+
* SECOND CHECK — Conceptual leak guard (Wave 2):
|
|
37
|
+
* The literal "Caio" check above misses CONCEPTUAL internal leaks: the
|
|
38
|
+
* maintainer's private grounding mechanisms (vault-grounding, second-brain,
|
|
39
|
+
* brandbook) and the maintainer's BUSINESS CLIENT names (Módulo, Mindloop,
|
|
40
|
+
* Sayuri, Vascularte, itsoffbrand, sinapse.club). These are internal/business
|
|
41
|
+
* context and must NOT appear on the surfaces an external user actually sees:
|
|
42
|
+
* the installer, the CLI, and the public docs the npm package ships.
|
|
43
|
+
*
|
|
44
|
+
* This second check is SCOPED ONLY to user-facing surfaces (CONCEPT_SCOPES):
|
|
45
|
+
* packages/installer/**, bin/**, README.md, docs/getting-started.md,
|
|
46
|
+
* docs/pt/**, docs/en/**.
|
|
47
|
+
* It deliberately does NOT scan .sinapse-ai/development/**, squad agent files,
|
|
48
|
+
* or internal docs — those legitimately discuss framework concepts.
|
|
35
49
|
*/
|
|
36
50
|
|
|
37
51
|
'use strict';
|
|
@@ -112,6 +126,107 @@ function isAllowed(filePath) {
|
|
|
112
126
|
return ALLOWLIST_PREFIXES.some((prefix) => normalized.startsWith(prefix));
|
|
113
127
|
}
|
|
114
128
|
|
|
129
|
+
// ---------------------------------------------------------------------------
|
|
130
|
+
// SECOND CHECK — Conceptual leak guard (user-facing surfaces only).
|
|
131
|
+
// ---------------------------------------------------------------------------
|
|
132
|
+
|
|
133
|
+
// The ONLY surfaces an external user sees: the installer, the CLI, and the
|
|
134
|
+
// public docs that ship in the npm package. A concept/business leak here is a
|
|
135
|
+
// real leak. Everything else (framework internals, squad agents, internal
|
|
136
|
+
// docs) is intentionally OUT of scope.
|
|
137
|
+
const CONCEPT_FILE_SCOPES = new Set(['README.md', 'docs/getting-started.md']);
|
|
138
|
+
const CONCEPT_PREFIX_SCOPES = ['packages/installer/', 'bin/', 'docs/pt/', 'docs/en/'];
|
|
139
|
+
|
|
140
|
+
function isConceptScoped(filePath) {
|
|
141
|
+
const normalized = filePath.replace(/\\/g, '/');
|
|
142
|
+
if (CONCEPT_FILE_SCOPES.has(normalized)) return true;
|
|
143
|
+
return CONCEPT_PREFIX_SCOPES.some((prefix) => normalized.startsWith(prefix));
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Conceptual / business denylist. Each entry is paired with a friendly
|
|
147
|
+
// description. Patterns are written to catch the INTERNAL token while avoiding
|
|
148
|
+
// generic-word false positives:
|
|
149
|
+
// - "Módulo" alone is the generic Portuguese word for "module" (capitalized
|
|
150
|
+
// and accented in prose/headings: "Módulo Core", "Estrutura de Módulo"),
|
|
151
|
+
// so it CANNOT be used to identify the client. The maintainer's client
|
|
152
|
+
// "Colégio Módulo" is matched ONLY by its full, unambiguous name —
|
|
153
|
+
// "Colégio Módulo" / "Colegio Modulo".
|
|
154
|
+
// - The other client names (Mindloop, Sayuri, Vascularte, itsoffbrand) and
|
|
155
|
+
// the grounding concepts (vault-grounding, second-brain, brandbook) are
|
|
156
|
+
// distinctive enough to match as whole words.
|
|
157
|
+
const CONCEPT_PATTERNS = [
|
|
158
|
+
{
|
|
159
|
+
pattern: /\bvault-grounding\b/i,
|
|
160
|
+
description: 'Internal grounding mechanism (vault-grounding) leaked to user-facing surface',
|
|
161
|
+
suggestion: 'Describe generically (e.g. "a session-start grounding hook") — do not name the private mechanism',
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
pattern: /\bsecond-brain\b/i,
|
|
165
|
+
description: "Maintainer's private knowledge base (Second-Brain) leaked to user-facing surface",
|
|
166
|
+
suggestion: 'Generalize to "external memory source (e.g. an Obsidian vault)"',
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
pattern: /\bbrandbook\b/i,
|
|
170
|
+
description: "Maintainer's internal design-system concept (brandbook) leaked to user-facing surface",
|
|
171
|
+
suggestion: 'Use a generic term like "design system" or "brand guidelines"',
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
pattern: /Col[ée]gio\s+M[óÓoO]dulo/,
|
|
175
|
+
description: "Maintainer's business client name (Colégio Módulo) leaked to user-facing surface",
|
|
176
|
+
suggestion: 'Remove the client name; use a neutral placeholder (e.g. "your client")',
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
pattern: /\bMindloop\b/i,
|
|
180
|
+
description: "Maintainer's business client name (Mindloop) leaked to user-facing surface",
|
|
181
|
+
suggestion: 'Remove the client name; use a neutral placeholder',
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
pattern: /\bSayuri\b/i,
|
|
185
|
+
description: "Maintainer's business client name (Sayuri) leaked to user-facing surface",
|
|
186
|
+
suggestion: 'Remove the client name; use a neutral placeholder',
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
pattern: /\bVascularte\b/i,
|
|
190
|
+
description: "Maintainer's business client name (Vascularte) leaked to user-facing surface",
|
|
191
|
+
suggestion: 'Remove the client name; use a neutral placeholder',
|
|
192
|
+
},
|
|
193
|
+
{
|
|
194
|
+
pattern: /\bitsoffbrand\b/i,
|
|
195
|
+
description: "Maintainer's business client name (itsoffbrand) leaked to user-facing surface",
|
|
196
|
+
suggestion: 'Remove the client name; use a neutral placeholder',
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
pattern: /\bsinapse\.club\b/i,
|
|
200
|
+
description: "Maintainer's internal/business property (sinapse.club) leaked to user-facing surface",
|
|
201
|
+
suggestion: 'Remove the internal domain reference',
|
|
202
|
+
},
|
|
203
|
+
];
|
|
204
|
+
|
|
205
|
+
function scanFileForConcepts(filePath) {
|
|
206
|
+
const fullPath = path.join(ROOT, filePath);
|
|
207
|
+
if (!fs.existsSync(fullPath)) return [];
|
|
208
|
+
const content = fs.readFileSync(fullPath, 'utf8');
|
|
209
|
+
const lines = content.split('\n');
|
|
210
|
+
const violations = [];
|
|
211
|
+
for (let i = 0; i < lines.length; i++) {
|
|
212
|
+
const line = lines[i];
|
|
213
|
+
for (const rule of CONCEPT_PATTERNS) {
|
|
214
|
+
const match = line.match(rule.pattern);
|
|
215
|
+
if (match) {
|
|
216
|
+
violations.push({
|
|
217
|
+
file: filePath,
|
|
218
|
+
line: i + 1,
|
|
219
|
+
match: match[0],
|
|
220
|
+
description: rule.description,
|
|
221
|
+
suggestion: rule.suggestion,
|
|
222
|
+
context: line.trim().slice(0, 120),
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
return violations;
|
|
228
|
+
}
|
|
229
|
+
|
|
115
230
|
function isTextFile(filePath) {
|
|
116
231
|
const binaryExts = new Set([
|
|
117
232
|
'.png', '.jpg', '.jpeg', '.gif', '.svg', '.webp', '.ico',
|
|
@@ -157,43 +272,77 @@ function scanFile(filePath) {
|
|
|
157
272
|
function run() {
|
|
158
273
|
const files = getTrackedFiles();
|
|
159
274
|
const allViolations = [];
|
|
275
|
+
const conceptViolations = [];
|
|
160
276
|
|
|
161
277
|
for (const file of files) {
|
|
162
|
-
if (isAllowed(file)) continue;
|
|
163
278
|
if (!isTextFile(file)) continue;
|
|
164
|
-
|
|
165
|
-
|
|
279
|
+
|
|
280
|
+
// CHECK 1 — operational personal references ("Caio" literals, paths).
|
|
281
|
+
// Scanned across the whole tree except the autorship/history allow-list.
|
|
282
|
+
if (!isAllowed(file)) {
|
|
283
|
+
allViolations.push(...scanFile(file));
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// CHECK 2 — conceptual / business leaks, scoped ONLY to user-facing
|
|
287
|
+
// surfaces (installer, CLI, public docs the package ships).
|
|
288
|
+
if (isConceptScoped(file)) {
|
|
289
|
+
conceptViolations.push(...scanFileForConcepts(file));
|
|
290
|
+
}
|
|
166
291
|
}
|
|
167
292
|
|
|
168
|
-
if (allViolations.length === 0) {
|
|
169
|
-
console.log('✅ no-personal-leaks: no operational personal references found.');
|
|
170
|
-
console.log(` Scanned ${files.length} tracked files.`);
|
|
293
|
+
if (allViolations.length === 0 && conceptViolations.length === 0) {
|
|
294
|
+
console.log('✅ no-personal-leaks: no operational personal or conceptual references found.');
|
|
295
|
+
console.log(` Scanned ${files.length} tracked files (concept guard scoped to user-facing surfaces).`);
|
|
171
296
|
return 0;
|
|
172
297
|
}
|
|
173
298
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
299
|
+
if (allViolations.length > 0) {
|
|
300
|
+
console.error('');
|
|
301
|
+
console.error('❌ no-personal-leaks: found operational personal references in framework code.');
|
|
302
|
+
console.error('');
|
|
303
|
+
console.error(` ${allViolations.length} violation(s) across ${new Set(allViolations.map((v) => v.file)).size} file(s).`);
|
|
304
|
+
console.error('');
|
|
305
|
+
for (const v of allViolations) {
|
|
306
|
+
console.error(` ${v.file}:${v.line}`);
|
|
307
|
+
console.error(` Match: "${v.match}"`);
|
|
308
|
+
console.error(` Issue: ${v.description}`);
|
|
309
|
+
console.error(` Suggestion: ${v.suggestion}`);
|
|
310
|
+
console.error(` Context: ${v.context}`);
|
|
311
|
+
console.error('');
|
|
312
|
+
}
|
|
313
|
+
console.error('Why this matters:');
|
|
314
|
+
console.error(' SINAPSE-AI is a multi-tenant framework distributed via npm.');
|
|
315
|
+
console.error(' Personal/operational context belongs in ~/.claude/ (private),');
|
|
316
|
+
console.error(' not in the public framework code.');
|
|
317
|
+
console.error('');
|
|
318
|
+
console.error('Exempt locations (allowed):');
|
|
319
|
+
console.error(' README/CONTRIBUTING/LICENSE — author credit');
|
|
320
|
+
console.error(' CHANGELOG.md — historical record');
|
|
321
|
+
console.error(' docs/audits/, docs/epics/, docs/research/ — historical/archive');
|
|
322
|
+
console.error('');
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
if (conceptViolations.length > 0) {
|
|
326
|
+
console.error('');
|
|
327
|
+
console.error('❌ no-personal-leaks (concept guard): found internal/business references on user-facing surfaces.');
|
|
328
|
+
console.error('');
|
|
329
|
+
console.error(` ${conceptViolations.length} violation(s) across ${new Set(conceptViolations.map((v) => v.file)).size} file(s).`);
|
|
330
|
+
console.error('');
|
|
331
|
+
for (const v of conceptViolations) {
|
|
332
|
+
console.error(` ${v.file}:${v.line}`);
|
|
333
|
+
console.error(` Match: "${v.match}"`);
|
|
334
|
+
console.error(` Issue: ${v.description}`);
|
|
335
|
+
console.error(` Suggestion: ${v.suggestion}`);
|
|
336
|
+
console.error(` Context: ${v.context}`);
|
|
337
|
+
console.error('');
|
|
338
|
+
}
|
|
339
|
+
console.error('Why this matters:');
|
|
340
|
+
console.error(' These surfaces (installer, CLI, public docs) are what an external');
|
|
341
|
+
console.error(' user actually sees. Internal grounding concepts and the maintainer\'s');
|
|
342
|
+
console.error(' business client names must never leak into them.');
|
|
185
343
|
console.error('');
|
|
186
344
|
}
|
|
187
|
-
|
|
188
|
-
console.error(' SINAPSE-AI is a multi-tenant framework distributed via npm.');
|
|
189
|
-
console.error(' Personal/operational context belongs in ~/.claude/ (private),');
|
|
190
|
-
console.error(' not in the public framework code.');
|
|
191
|
-
console.error('');
|
|
192
|
-
console.error('Exempt locations (allowed):');
|
|
193
|
-
console.error(' README/CONTRIBUTING/LICENSE — author credit');
|
|
194
|
-
console.error(' CHANGELOG.md — historical record');
|
|
195
|
-
console.error(' docs/audits/, docs/epics/, docs/research/ — historical/archive');
|
|
196
|
-
console.error('');
|
|
345
|
+
|
|
197
346
|
return 1;
|
|
198
347
|
}
|
|
199
348
|
|
|
@@ -201,4 +350,11 @@ if (require.main === module) {
|
|
|
201
350
|
process.exit(run());
|
|
202
351
|
}
|
|
203
352
|
|
|
204
|
-
module.exports = {
|
|
353
|
+
module.exports = {
|
|
354
|
+
run,
|
|
355
|
+
BLOCKED_PATTERNS,
|
|
356
|
+
isAllowed,
|
|
357
|
+
CONCEPT_PATTERNS,
|
|
358
|
+
isConceptScoped,
|
|
359
|
+
scanFileForConcepts,
|
|
360
|
+
};
|
|
@@ -23,10 +23,15 @@
|
|
|
23
23
|
* and report found/missing. A known kind with no schema -> violation.
|
|
24
24
|
*
|
|
25
25
|
* 3. ARTIFACT VALIDATION (no-op clean when absent): kind -> glob by CONVENTION
|
|
26
|
-
* (story -> docs/stories/ ** / *.story.md, epic -> docs/epics/ ** / *.md,
|
|
27
|
-
* prd -> docs/prd/ ** / *.md).
|
|
28
|
-
*
|
|
29
|
-
*
|
|
26
|
+
* (story -> docs/stories/ ** / *.story.md, epic -> docs/epics/ ** / *.epic.md,
|
|
27
|
+
* prd -> docs/prd/ ** / *.md). By DEFAULT the artifact layer is GIT-SCOPED
|
|
28
|
+
* (git ls-files): only TRACKED artifacts are validated, so the result is
|
|
29
|
+
* hermetic — identical locally and in CI regardless of untracked local
|
|
30
|
+
* drafts. docs/stories and docs/epics are gitignored, so in a clean public
|
|
31
|
+
* checkout there are 0 tracked artifacts -> reported as skipped, NOT a
|
|
32
|
+
* failure. The --artifacts <dir> flag overrides this with a filesystem walk
|
|
33
|
+
* of <dir> (used by the jest wrapper / tests). When artifacts ARE present,
|
|
34
|
+
* extract data via
|
|
30
35
|
* TemplateValidator.extractDataFromMarkdown (or frontmatter parse) and
|
|
31
36
|
* validate via TemplateValidator.validate(data, kind); each error is
|
|
32
37
|
* reported with the instancePath that formatErrors() already produces.
|
|
@@ -47,9 +52,10 @@
|
|
|
47
52
|
* with no fallback, etc).
|
|
48
53
|
*
|
|
49
54
|
* FLAGS:
|
|
50
|
-
* --artifacts <dir> Use <dir> as the artifact root
|
|
51
|
-
*
|
|
52
|
-
*
|
|
55
|
+
* --artifacts <dir> Use <dir> as the artifact root (filesystem walk) instead
|
|
56
|
+
* of the DEFAULT git-scoped scan of the repo. Used by the
|
|
57
|
+
* jest wrapper / for testing. Globs are resolved relative
|
|
58
|
+
* to this root.
|
|
53
59
|
* --quiet Suppress the per-schema OK lines; still prints the
|
|
54
60
|
* summary and every violation.
|
|
55
61
|
*
|
|
@@ -97,7 +103,12 @@ const ARTIFACT_CONVENTIONS = [
|
|
|
97
103
|
// ---------------------------------------------------------------------------
|
|
98
104
|
|
|
99
105
|
function parseArgs(argv) {
|
|
100
|
-
|
|
106
|
+
// artifactsExplicit: whether the caller passed --artifacts. When NOT passed,
|
|
107
|
+
// the artifact layer is GIT-SCOPED (tracked files only) so it is hermetic —
|
|
108
|
+
// identical locally and in CI, regardless of untracked local drafts. When
|
|
109
|
+
// passed (jest wrapper / tests), it falls back to filesystem walking of the
|
|
110
|
+
// given dir so tests can stage fixtures outside git.
|
|
111
|
+
const opts = { artifactsRoot: REPO_ROOT, quiet: false, artifactsExplicit: false };
|
|
101
112
|
for (let i = 0; i < argv.length; i += 1) {
|
|
102
113
|
const a = argv[i];
|
|
103
114
|
if (a === '--quiet') {
|
|
@@ -109,9 +120,11 @@ function parseArgs(argv) {
|
|
|
109
120
|
process.exit(2);
|
|
110
121
|
}
|
|
111
122
|
opts.artifactsRoot = path.resolve(next);
|
|
123
|
+
opts.artifactsExplicit = true;
|
|
112
124
|
i += 1;
|
|
113
125
|
} else if (a.startsWith('--artifacts=')) {
|
|
114
126
|
opts.artifactsRoot = path.resolve(a.slice('--artifacts='.length));
|
|
127
|
+
opts.artifactsExplicit = true;
|
|
115
128
|
}
|
|
116
129
|
}
|
|
117
130
|
return opts;
|
|
@@ -338,6 +351,35 @@ async function kindCoverage() {
|
|
|
338
351
|
// LAYER 3 — artifact validation by convention (no-op clean when absent).
|
|
339
352
|
// ---------------------------------------------------------------------------
|
|
340
353
|
|
|
354
|
+
/**
|
|
355
|
+
* Collect GIT-TRACKED artifacts under `relDir` (relative to REPO_ROOT) ending
|
|
356
|
+
* with `suffix`. Hermetic: docs/stories|epics|prd are gitignored, so untracked
|
|
357
|
+
* local drafts are invisible and the result is identical locally and in CI.
|
|
358
|
+
* Returns absolute paths. Falls back to [] (not the FS) when git is unavailable
|
|
359
|
+
* — keeping the default scope strictly git-defined.
|
|
360
|
+
*/
|
|
361
|
+
function collectTrackedArtifacts(relDir, suffix) {
|
|
362
|
+
const posixDir = relDir.split(path.sep).join('/');
|
|
363
|
+
try {
|
|
364
|
+
// Use the DIRECTORY pathspec (git recurses) + filter by suffix in JS. A
|
|
365
|
+
// glob like '<dir>/**' would match only NESTED files and MISS artifacts
|
|
366
|
+
// directly in <dir> (per git pathspec semantics).
|
|
367
|
+
const out = execFileSync('git', ['ls-files', '-z', posixDir], {
|
|
368
|
+
cwd: REPO_ROOT,
|
|
369
|
+
encoding: 'utf8',
|
|
370
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
371
|
+
});
|
|
372
|
+
return out
|
|
373
|
+
.split('\0')
|
|
374
|
+
.map((l) => l.trim())
|
|
375
|
+
.filter(Boolean)
|
|
376
|
+
.filter((l) => l.endsWith(suffix))
|
|
377
|
+
.map((l) => path.join(REPO_ROOT, l));
|
|
378
|
+
} catch {
|
|
379
|
+
return [];
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
|
|
341
383
|
/** Recursively collect files under `dir` ending with `suffix`. */
|
|
342
384
|
function collectArtifacts(dir, suffix, acc) {
|
|
343
385
|
let entries;
|
|
@@ -429,8 +471,11 @@ async function validateArtifacts(opts) {
|
|
|
429
471
|
const summary = { kinds: {}, total: 0, valid: 0, invalid: 0 };
|
|
430
472
|
|
|
431
473
|
for (const conv of ARTIFACT_CONVENTIONS) {
|
|
432
|
-
|
|
433
|
-
|
|
474
|
+
// Default (no --artifacts): GIT-SCOPED, hermetic. With --artifacts: walk the
|
|
475
|
+
// given dir on disk (tests stage fixtures outside git).
|
|
476
|
+
const files = opts.artifactsExplicit
|
|
477
|
+
? collectArtifacts(path.join(opts.artifactsRoot, conv.dir), conv.suffix, [])
|
|
478
|
+
: collectTrackedArtifacts(conv.dir, conv.suffix);
|
|
434
479
|
summary.kinds[conv.kind] = files.length;
|
|
435
480
|
summary.total += files.length;
|
|
436
481
|
|
|
@@ -2,12 +2,14 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* validate-story-meta — Story 10.19
|
|
4
4
|
*
|
|
5
|
-
*
|
|
5
|
+
* Validator for `docs/stories/*.story.md` files.
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
7
|
+
* Scope (hermetic):
|
|
8
|
+
* The DEFAULT scope is git-TRACKED story files only (`git ls-files`).
|
|
9
|
+
* docs/stories/ is gitignored, so untracked local drafts are NOT scanned
|
|
10
|
+
* by default — the result is deterministic and identical locally and in CI
|
|
11
|
+
* (a clean checkout with no tracked stories is simply a no-op). Use
|
|
12
|
+
* `--staged` to scope to staged stories (lint-staged on commit).
|
|
11
13
|
*
|
|
12
14
|
* What it checks:
|
|
13
15
|
* 1. Files lack YAML frontmatter -> WARN (grandfathered)
|
|
@@ -63,12 +65,23 @@ function findStoryFiles(projectRoot, opts = {}) {
|
|
|
63
65
|
.filter((line) => line.startsWith('docs/stories/') && line.endsWith('.story.md'))
|
|
64
66
|
.map((rel) => path.join(projectRoot, rel));
|
|
65
67
|
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
68
|
+
// Default scope: git-TRACKED story files only (hermetic — same result
|
|
69
|
+
// locally and in CI). docs/stories/ is gitignored, so untracked local drafts
|
|
70
|
+
// must NOT be scanned by default; only files actually committed are checked.
|
|
71
|
+
// This mirrors validate-no-personal-leaks.js (git ls-files as source of truth).
|
|
72
|
+
// NB: use the DIRECTORY pathspec ('docs/stories') and filter by suffix in JS.
|
|
73
|
+
// A glob like 'docs/stories/**/*.story.md' would (per git pathspec semantics)
|
|
74
|
+
// match only NESTED files and MISS stories directly in docs/stories/.
|
|
75
|
+
const result = spawnSync('git', ['ls-files', 'docs/stories'], {
|
|
76
|
+
cwd: projectRoot,
|
|
77
|
+
encoding: 'utf8',
|
|
78
|
+
});
|
|
79
|
+
if (result.status !== 0 || !result.stdout) return [];
|
|
80
|
+
return result.stdout
|
|
81
|
+
.split('\n')
|
|
82
|
+
.map((line) => line.trim())
|
|
83
|
+
.filter((line) => line.endsWith('.story.md'))
|
|
84
|
+
.map((rel) => path.join(projectRoot, rel));
|
|
72
85
|
}
|
|
73
86
|
|
|
74
87
|
function parseFrontmatter(content) {
|
|
@@ -224,7 +237,7 @@ function main() {
|
|
|
224
237
|
if (files.length === 0) {
|
|
225
238
|
if (!args.quiet) {
|
|
226
239
|
console.log('=== validate-story-meta ===');
|
|
227
|
-
console.log('No story files found — skipping (
|
|
240
|
+
console.log('No git-tracked story files found — skipping (untracked local drafts are not scanned by default).');
|
|
228
241
|
}
|
|
229
242
|
return 0;
|
|
230
243
|
}
|
|
@@ -195,7 +195,7 @@ sinapse_awareness:
|
|
|
195
195
|
- 14 workflow definitions in .sinapse-ai/development/workflows/
|
|
196
196
|
- L1-L4 boundary protection model
|
|
197
197
|
- Entity registry with 740+ entities
|
|
198
|
-
- Hook system: runtime
|
|
198
|
+
- Hook system: runtime hooks in .sinapse-ai/hooks/ (wired via .claude/settings.json) + git hooks in .sinapse-ai/git-hooks/ (core.hooksPath)
|
|
199
199
|
- Template engine with Handlebars (.hbs)
|
|
200
200
|
- Quality gates (Layer 1-4: pre-commit, CI, pre-push, deployment)
|
|
201
201
|
- CLI: sinapse doctor, sinapse graph, sinapse workers, sinapse manifest, etc.
|
|
@@ -135,8 +135,8 @@ persona:
|
|
|
135
135
|
- "PRINCIPLE: Team validation pattern. Pair a Builder agent (full tools) with a Validator agent (read-only). PostToolUse hooks run validators after every write operation."
|
|
136
136
|
|
|
137
137
|
# --- SINAPSE INTEGRATION ---
|
|
138
|
-
- "PRINCIPLE: SINAPSE awareness. This project ships its own hooks in two places: .sinapse-ai/hooks/ holds runtime hooks (Node .cjs/.js:
|
|
139
|
-
- "PRINCIPLE: SINAPSE runtime hooks are wired in .claude/settings.json, where thin wrappers under .claude/hooks/ (e.g. synapse-wrapper.cjs, precompact-wrapper.cjs) delegate to the
|
|
138
|
+
- "PRINCIPLE: SINAPSE awareness. This project ships its own hooks in two places: .sinapse-ai/hooks/ holds runtime hooks (Node .cjs/.js: the unified/ runner plus IDS hooks) and .sinapse-ai/git-hooks/ holds the git hooks (pre-commit, pre-push, post-commit + lib/). Always check existing hooks before creating new ones."
|
|
139
|
+
- "PRINCIPLE: SINAPSE runtime hooks are wired in .claude/settings.json, where thin wrappers under .claude/hooks/ (e.g. synapse-wrapper.cjs, precompact-wrapper.cjs) delegate to the runner scripts in .sinapse-ai/hooks/. Git hooks are wired via core.hooksPath -> .sinapse-ai/git-hooks. Respect these wiring points when extending instead of adding parallel registrations."
|
|
140
140
|
|
|
141
141
|
# --- SCOPE & SAFETY ---
|
|
142
142
|
- "PRINCIPLE: Six scopes, choose wisely. user (~/.claude/settings.json) = all projects. project (.claude/settings.json) = shared team hooks. local (.claude/settings.local.json) = personal project hooks. managed = org-wide policy. plugin = bundled extensions. skill/agent = component-scoped."
|
|
@@ -211,10 +211,7 @@ dependencies:
|
|
|
211
211
|
reference_files:
|
|
212
212
|
- .claude/settings.json # Project hook definitions (wires runtime hooks)
|
|
213
213
|
- .claude/settings.local.json # Local hook definitions
|
|
214
|
-
- .sinapse-ai/hooks/ # SINAPSE runtime hooks (
|
|
215
|
-
- .sinapse-ai/hooks/sinapse-vault-grounding.cjs # Vault context grounding injector
|
|
216
|
-
- .sinapse-ai/hooks/sinapse-ds-grounding.cjs # Design-system grounding injector
|
|
217
|
-
- .sinapse-ai/hooks/sinapse-brand-grounding.cjs # Brand grounding injector
|
|
214
|
+
- .sinapse-ai/hooks/ # SINAPSE runtime hooks (unified/ runner + IDS hooks)
|
|
218
215
|
- .sinapse-ai/hooks/unified/ # Unified hook runner (index.js, hook-registry.js, runners/)
|
|
219
216
|
- .sinapse-ai/git-hooks/ # SINAPSE git hooks (core.hooksPath target)
|
|
220
217
|
- .sinapse-ai/git-hooks/pre-commit # Secret-scan / SQL / boundary guard
|
|
@@ -559,8 +556,8 @@ objection_algorithms:
|
|
|
559
556
|
|
|
560
557
|
"How do I integrate with the existing SINAPSE hooks?":
|
|
561
558
|
response: |
|
|
562
|
-
SINAPSE ships hooks in two layers. Runtime hooks live in .sinapse-ai/hooks/ (
|
|
563
|
-
|
|
559
|
+
SINAPSE ships hooks in two layers. Runtime hooks live in .sinapse-ai/hooks/ (the unified/
|
|
560
|
+
runner + IDS hooks) and are wired in .claude/settings.json via thin
|
|
564
561
|
wrappers under .claude/hooks/. Git hooks live in .sinapse-ai/git-hooks/ (pre-commit,
|
|
565
562
|
pre-push, post-commit) and are wired via core.hooksPath. To extend: add a new wrapper
|
|
566
563
|
entry in .claude/settings.json that delegates to a script in .sinapse-ai/hooks/, or add a
|
|
@@ -829,20 +826,15 @@ sinapse_core_hooks:
|
|
|
829
826
|
language: "Node (.cjs / .js)"
|
|
830
827
|
wiring: ".claude/settings.json -> thin wrappers in .claude/hooks/ delegate to scripts here"
|
|
831
828
|
architecture: |
|
|
832
|
-
SINAPSE runtime hooks
|
|
829
|
+
SINAPSE runtime hooks run coordinated logic at lifecycle events:
|
|
833
830
|
1. Claude Code fires the lifecycle event and runs the wrapper named in .claude/settings.json
|
|
834
|
-
2. The wrapper (.claude/hooks/*.cjs) delegates to the
|
|
835
|
-
3. The
|
|
836
|
-
4. The unified/ runner coordinates the shared runners (e.g. precompact-runner.js)
|
|
831
|
+
2. The wrapper (.claude/hooks/*.cjs) delegates to the runner script in .sinapse-ai/hooks/
|
|
832
|
+
3. The unified/ runner coordinates the shared runners (e.g. precompact-runner.js)
|
|
837
833
|
existing_hooks:
|
|
838
|
-
- file: sinapse-vault-grounding.cjs
|
|
839
|
-
behavior: "Injects relevant Second-Brain vault context based on project domain"
|
|
840
|
-
- file: sinapse-ds-grounding.cjs
|
|
841
|
-
behavior: "Resolves and injects the design-system law for any UI output"
|
|
842
|
-
- file: sinapse-brand-grounding.cjs
|
|
843
|
-
behavior: "Injects brand positioning / MVV grounding"
|
|
844
834
|
- file: unified/
|
|
845
835
|
behavior: "Unified runner: index.js, hook-registry.js, hook-interface.js, runners/ (e.g. precompact-runner.js)"
|
|
836
|
+
- file: ids-pre-push.js / ids-post-commit.js
|
|
837
|
+
behavior: "IDS (Incremental Development System) registry hooks"
|
|
846
838
|
|
|
847
839
|
git_hooks:
|
|
848
840
|
location: ".sinapse-ai/git-hooks/"
|
|
@@ -856,7 +848,7 @@ sinapse_core_hooks:
|
|
|
856
848
|
behavior: "Post-commit hook"
|
|
857
849
|
|
|
858
850
|
integration_rules:
|
|
859
|
-
- "Do NOT duplicate SINAPSE
|
|
851
|
+
- "Do NOT duplicate SINAPSE runtime or git hooks. They handle the unified runner and commit-time guards."
|
|
860
852
|
- "New runtime hooks should COMPLEMENT existing ones: add a wrapper entry in .claude/settings.json delegating to a script in .sinapse-ai/hooks/."
|
|
861
853
|
- "For additional commit-time guards, extend the managed .sinapse-ai/git-hooks/ — do not register a parallel git hook system that diverges from core.hooksPath."
|
|
862
854
|
- "For additional PreToolUse blocking, create a separate hook script -- Claude runs all matching hooks in parallel."
|
|
@@ -995,7 +987,7 @@ Add to settings file. Test with piped JSON. Verify with `*debug-hook`.
|
|
|
995
987
|
### SINAPSE Integration
|
|
996
988
|
|
|
997
989
|
The project ships its own hooks in two layers:
|
|
998
|
-
- **Runtime hooks** in `.sinapse-ai/hooks/` (
|
|
990
|
+
- **Runtime hooks** in `.sinapse-ai/hooks/` (the `unified/` runner + IDS hooks), wired in `.claude/settings.json` through thin wrappers under `.claude/hooks/`. They run coordinated logic at lifecycle events.
|
|
999
991
|
- **Git hooks** in `.sinapse-ai/git-hooks/` (`pre-commit`, `pre-push`, `post-commit`), wired via `core.hooksPath`. They enforce commit-time guards (secret-scan, SQL governance, framework boundary).
|
|
1000
992
|
|
|
1001
993
|
Do NOT duplicate these hooks. Create complementary hooks for blocking, formatting, or custom logic — add a wrapper in `.claude/settings.json` (runtime) or a guard in `.sinapse-ai/git-hooks/` (commit-time). Multiple hooks on the same event run in parallel.
|
|
@@ -113,7 +113,7 @@ Score each item:
|
|
|
113
113
|
- PreToolUse for Bash command validation
|
|
114
114
|
- PreCompact for context preservation
|
|
115
115
|
- Stop for session cleanup
|
|
116
|
-
4. If SINAPSE project: check the SINAPSE hook system — runtime
|
|
116
|
+
4. If SINAPSE project: check the SINAPSE hook system — runtime hooks in `.sinapse-ai/hooks/` (wired via `.claude/settings.json`) and git hooks in `.sinapse-ai/git-hooks/` (`core.hooksPath`)
|
|
117
117
|
|
|
118
118
|
### Phase 5: List MCP Servers
|
|
119
119
|
|