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.
Files changed (93) hide show
  1. package/.claude/CLAUDE.md +2 -2
  2. package/.claude/rules/agent-memory-imports.md +2 -0
  3. package/.sinapse-ai/cli/commands/pro/index.js +8 -48
  4. package/.sinapse-ai/constitution.md +6 -2
  5. package/.sinapse-ai/core-config.yaml +5 -1
  6. package/.sinapse-ai/data/entity-registry.yaml +95 -95
  7. package/.sinapse-ai/development/agents/architect/MEMORY.md +35 -0
  8. package/.sinapse-ai/development/agents/data-engineer/MEMORY.md +38 -0
  9. package/.sinapse-ai/development/agents/developer/MEMORY.md +36 -0
  10. package/.sinapse-ai/development/agents/devops/MEMORY.md +39 -0
  11. package/.sinapse-ai/development/agents/devops.md +0 -1
  12. package/.sinapse-ai/development/agents/product-lead/MEMORY.md +36 -0
  13. package/.sinapse-ai/development/agents/project-lead/MEMORY.md +36 -0
  14. package/.sinapse-ai/development/agents/quality-gate/MEMORY.md +35 -0
  15. package/.sinapse-ai/development/agents/quality-gate.md +1 -1
  16. package/.sinapse-ai/development/agents/snps-orqx.md +4 -0
  17. package/.sinapse-ai/development/agents/sprint-lead/MEMORY.md +36 -0
  18. package/.sinapse-ai/development/templates/chrome-brain/knowledge-base/chrome-brain.md +2 -2
  19. package/.sinapse-ai/infrastructure/scripts/ide-sync/index.js +15 -0
  20. package/.sinapse-ai/infrastructure/scripts/validate-agents.js +159 -8
  21. package/.sinapse-ai/install-manifest.yaml +20 -156
  22. package/AGENTS.md +13 -2
  23. package/CHANGELOG.md +119 -4
  24. package/README.en.md +1 -1
  25. package/README.md +6 -26
  26. package/bin/cli.js +2 -7
  27. package/bin/commands/install.js +19 -257
  28. package/bin/commands/update.js +18 -78
  29. package/bin/lib/command-generator.js +261 -0
  30. package/bin/lib/prompts.js +2 -65
  31. package/bin/modules/chrome-brain-installer.js +2 -1
  32. package/bin/postinstall.js +6 -6
  33. package/docs/getting-started.md +0 -1
  34. package/docs/pt/getting-started.md +1 -1
  35. package/docs/security/dependabot-triage.md +17 -17
  36. package/package.json +6 -3
  37. package/packages/installer/src/wizard/i18n.js +3 -204
  38. package/packages/installer/src/wizard/index.js +1 -1
  39. package/packages/installer/src/wizard/questions.js +5 -368
  40. package/packages/installer/src/wizard/wizard.js +0 -9
  41. package/scripts/generate-install-manifest.js +6 -0
  42. package/scripts/validate-changelog-tags.js +97 -0
  43. package/scripts/validate-no-personal-leaks.js +184 -28
  44. package/scripts/validate-schemas.js +55 -10
  45. package/scripts/validate-story-meta.js +25 -12
  46. package/squads/claude-code-mastery/agents/claude-mastery-chief.md +1 -1
  47. package/squads/claude-code-mastery/agents/hooks-architect.md +12 -20
  48. package/squads/claude-code-mastery/tasks/audit-setup.md +1 -1
  49. package/squads/squad-product/agents/product-orqx.md +0 -1
  50. package/squads/squad-product/agents/ps-client-product-manager.md +0 -1
  51. package/squads/squad-product/agents/ps-delivery-manager.md +0 -1
  52. package/squads/squad-product/agents/ps-discovery-lead.md +0 -1
  53. package/squads/squad-product/agents/ps-product-analyst.md +0 -1
  54. package/squads/squad-product/agents/ps-product-ops-specialist.md +0 -1
  55. package/squads/squad-product/agents/ps-product-strategist.md +0 -1
  56. package/.sinapse-ai/core/grounding/README.md +0 -83
  57. package/.sinapse-ai/core/grounding/brand.cjs +0 -29
  58. package/.sinapse-ai/core/grounding/config-loader.cjs +0 -52
  59. package/.sinapse-ai/core/grounding/design-system.cjs +0 -29
  60. package/.sinapse-ai/core/grounding/vault.cjs +0 -36
  61. package/.sinapse-ai/development/scripts/approval-workflow.js +0 -643
  62. package/.sinapse-ai/development/scripts/backup-manager.js +0 -607
  63. package/.sinapse-ai/development/scripts/branch-manager.js +0 -390
  64. package/.sinapse-ai/development/scripts/code-quality-improver.js +0 -1329
  65. package/.sinapse-ai/development/scripts/commit-message-generator.js +0 -850
  66. package/.sinapse-ai/development/scripts/conflict-resolver.js +0 -675
  67. package/.sinapse-ai/development/scripts/dependency-analyzer.js +0 -638
  68. package/.sinapse-ai/development/scripts/diff-generator.js +0 -352
  69. package/.sinapse-ai/development/scripts/git-wrapper.js +0 -462
  70. package/.sinapse-ai/development/scripts/modification-validator.js +0 -555
  71. package/.sinapse-ai/development/scripts/performance-analyzer.js +0 -758
  72. package/.sinapse-ai/development/scripts/refactoring-suggester.js +0 -1148
  73. package/.sinapse-ai/development/scripts/rollback-handler.js +0 -531
  74. package/.sinapse-ai/development/scripts/security-checker.js +0 -359
  75. package/.sinapse-ai/development/scripts/template-engine.js +0 -240
  76. package/.sinapse-ai/development/scripts/template-validator.js +0 -279
  77. package/.sinapse-ai/development/scripts/test-generator.js +0 -844
  78. package/.sinapse-ai/development/scripts/transaction-manager.js +0 -590
  79. package/.sinapse-ai/development/scripts/yaml-validator.js +0 -397
  80. package/.sinapse-ai/hooks/sinapse-brand-grounding.cjs +0 -162
  81. package/.sinapse-ai/hooks/sinapse-ds-grounding.cjs +0 -211
  82. package/.sinapse-ai/hooks/sinapse-vault-grounding.cjs +0 -194
  83. package/bin/lib/register-grounding-hooks.js +0 -145
  84. package/docs/guides/agents/traces/execution-traces.zip +0 -0
  85. package/docs/guides/grounding-setup.md +0 -154
  86. package/docs/guides/workflows/SINAPSE-WORKFLOWS.zip +0 -0
  87. package/packages/installer/src/pro/pro-scaffolder.js +0 -449
  88. package/packages/installer/src/wizard/grounding-config.js +0 -131
  89. package/packages/installer/src/wizard/pro-setup.js +0 -1439
  90. package/packages/installer/templates/README.md +0 -16
  91. package/packages/installer/templates/brand-routing.example.json +0 -12
  92. package/packages/installer/templates/ds-routing.example.json +0 -12
  93. 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
- const violations = scanFile(file);
165
- allViolations.push(...violations);
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
- console.error('');
175
- console.error('❌ no-personal-leaks: found operational personal references in framework code.');
176
- console.error('');
177
- console.error(` ${allViolations.length} violation(s) across ${new Set(allViolations.map((v) => v.file)).size} file(s).`);
178
- console.error('');
179
- for (const v of allViolations) {
180
- console.error(` ${v.file}:${v.line}`);
181
- console.error(` Match: "${v.match}"`);
182
- console.error(` Issue: ${v.description}`);
183
- console.error(` Suggestion: ${v.suggestion}`);
184
- console.error(` Context: ${v.context}`);
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
- console.error('Why this matters:');
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 = { run, BLOCKED_PATTERNS, isAllowed };
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). docs/stories and docs/epics are gitignored,
28
- * so in public CI there are 0 artifacts -> reported as skipped, NOT a
29
- * failure. When artifacts ARE present, extract data via
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 instead of the repo root
51
- * (used by the jest wrapper / for testing). Globs are
52
- * resolved relative to this root.
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
- const opts = { artifactsRoot: REPO_ROOT, quiet: false };
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
- const root = path.join(opts.artifactsRoot, conv.dir);
433
- const files = collectArtifacts(root, conv.suffix, []);
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
- * LOCAL-ONLY validator for `docs/stories/*.story.md` files.
5
+ * Validator for `docs/stories/*.story.md` files.
6
6
  *
7
- * Why local-only:
8
- * docs/stories/ is gitignored, so a CI checkout contains zero story
9
- * files. Running this in CI would always be a no-op. Use it instead
10
- * via `npm run validate:story-meta` and via lint-staged on commit.
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
- const dir = path.join(projectRoot, 'docs', 'stories');
67
- if (!fs.existsSync(dir)) return [];
68
- return fs
69
- .readdirSync(dir)
70
- .filter((name) => name.endsWith('.story.md'))
71
- .map((name) => path.join(dir, name));
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 (this is expected in CI checkouts).');
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 grounding hooks in .sinapse-ai/hooks/ (wired via .claude/settings.json) + git hooks in .sinapse-ai/git-hooks/ (core.hooksPath)
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: grounding injectors like sinapse-vault-grounding.cjs, sinapse-ds-grounding.cjs, sinapse-brand-grounding.cjs, plus the unified/ runner) 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 grounding/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."
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 (grounding injectors + unified/ runner)
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/ (Node .cjs
563
- grounding injectors + the unified/ runner) and are wired in .claude/settings.json via thin
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 inject grounding context into Claude's prompt at lifecycle events:
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 grounding/runner script in .sinapse-ai/hooks/
835
- 3. The grounding script resolves project domain (vault / design-system / brand) and emits context
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 grounding or git hooks. They handle context injection and commit-time guards."
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/` (Node grounding injectors + the `unified/` runner), wired in `.claude/settings.json` through thin wrappers under `.claude/hooks/`. They inject grounding context (vault, design-system, brand) at lifecycle events.
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 grounding hooks in `.sinapse-ai/hooks/` (wired via `.claude/settings.json`) and git hooks in `.sinapse-ai/git-hooks/` (`core.hooksPath`)
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
 
@@ -1,4 +1,3 @@
1
- ---
2
1
  # Agent: Vector 🎯
3
2
 
4
3
  ## Identity
@@ -1,4 +1,3 @@
1
- ---
2
1
  # Agent: Proxy 🤝
3
2
 
4
3
  ## Identity
@@ -1,4 +1,3 @@
1
- ---
2
1
  # Agent: Tempo ⏱️
3
2
 
4
3
  ## Identity
@@ -1,4 +1,3 @@
1
- ---
2
1
  # Agent: Quorum 🔬
3
2
 
4
3
  ## Identity
@@ -1,4 +1,3 @@
1
- ---
2
1
  # Agent: Delta 📈
3
2
 
4
3
  ## Identity
@@ -1,4 +1,3 @@
1
- ---
2
1
  # Agent: Mosaic 🧩
3
2
 
4
3
  ## Identity
@@ -1,4 +1,3 @@
1
- ---
2
1
  # Agent: Charter 📐
3
2
 
4
3
  ## Identity