sinapse-ai 1.9.0 → 1.10.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 (94) hide show
  1. package/.claude/rules/mandatory-delegation.md +1 -1
  2. package/.codex/delegation-matrix.json +4 -3
  3. package/.codex/delegation-parity.json +4 -3
  4. package/.codex/instructions.md +2 -2
  5. package/.sinapse-ai/constitution.md +2 -2
  6. package/.sinapse-ai/core/doctor/checks/git-hooks.js +76 -10
  7. package/.sinapse-ai/core/execution/subagent-dispatcher.js +1 -1
  8. package/.sinapse-ai/core/synapse/engine.js +15 -0
  9. package/.sinapse-ai/data/entity-registry.yaml +13 -13
  10. package/.sinapse-ai/development/agents/snps-orqx.md +4 -4
  11. package/.sinapse-ai/git-hooks/lib/secret-scanner-core.js +76 -4
  12. package/.sinapse-ai/git-hooks/pre-push +7 -1
  13. package/.sinapse-ai/install-manifest.yaml +9 -9
  14. package/AGENTS.md +4 -4
  15. package/CHANGELOG.md +1257 -0
  16. package/README.en.md +4 -3
  17. package/README.md +5 -6
  18. package/bin/commands/install.js +6 -3
  19. package/bin/commands/uninstall.js +2 -2
  20. package/bin/sinapse.js +20 -0
  21. package/bin/utils/secret-scanner-core.js +76 -4
  22. package/docs/agent-reference-guide.md +1 -1
  23. package/docs/framework/architecture-overview.md +4 -4
  24. package/docs/framework/guiding-principles.md +9 -9
  25. package/docs/getting-started.md +1 -1
  26. package/docs/guides/agent-reference.md +1 -1
  27. package/docs/guides/codex-config.md +4 -5
  28. package/docs/pt/architecture/sub-orqx-pattern.md +20 -18
  29. package/package.json +8 -2
  30. package/packages/installer/src/installer/git-hooks-installer.js +3 -1
  31. package/packages/installer/src/installer/sinapse-ai-installer.js +32 -7
  32. package/packages/installer/src/wizard/ide-config-generator.js +9 -1
  33. package/packages/installer/src/wizard/index.js +3 -4
  34. package/scripts/regenerate-orqx-stubs.ps1 +0 -1
  35. package/scripts/sync-counts.js +10 -2
  36. package/scripts/sync-squad-yaml-components.js +108 -6
  37. package/scripts/validate-article-vii.js +68 -7
  38. package/scripts/validate-squad-orqx.js +19 -9
  39. package/sinapse/agents/sinapse-orqx.md +4 -4
  40. package/sinapse/agents/snps-orqx.md +4 -4
  41. package/sinapse/knowledge-base/routing-catalog.md +1 -1
  42. package/sinapse/tasks/diagnose-and-route.md +1 -1
  43. package/sinapse/tasks/squad-status-report.md +1 -1
  44. package/squads/claude-code-mastery/agents/claude-mastery-chief.md +1 -1
  45. package/squads/claude-code-mastery/agents/hooks-architect.md +60 -68
  46. package/squads/claude-code-mastery/knowledge-base/swarm-orchestration-patterns.md +1 -1
  47. package/squads/claude-code-mastery/tasks/audit-setup.md +1 -1
  48. package/squads/claude-code-mastery/workflows/optimization-cycle.yaml +4 -4
  49. package/squads/claude-code-mastery/workflows/project-setup-cycle.yaml +4 -4
  50. package/squads/squad-animations/README.md +1 -1
  51. package/squads/squad-cloning/README.md +1 -1
  52. package/squads/squad-commercial/README.md +1 -1
  53. package/squads/squad-content/README.md +1 -1
  54. package/squads/squad-copy/README.md +1 -1
  55. package/squads/squad-council/README.md +1 -1
  56. package/squads/squad-courses/README.md +1 -1
  57. package/squads/squad-cybersecurity/README.md +1 -1
  58. package/squads/squad-design/README.md +1 -1
  59. package/squads/squad-finance/README.md +1 -1
  60. package/squads/squad-growth/README.md +1 -1
  61. package/squads/squad-paidmedia/README.md +1 -1
  62. package/squads/squad-product/README.md +1 -1
  63. package/squads/squad-research/README.md +1 -1
  64. package/squads/squad-storytelling/README.md +1 -1
  65. package/.sinapse-ai/core/memory/__tests__/active-modules.verify.js +0 -265
  66. package/.sinapse-ai/core/permissions/__tests__/permission-mode.test.js +0 -293
  67. package/.sinapse-ai/infrastructure/tests/project-status-loader.test.js +0 -569
  68. package/.sinapse-ai/infrastructure/tests/regression-suite-v2.md +0 -622
  69. package/.sinapse-ai/infrastructure/tests/validate-module.js +0 -98
  70. package/.sinapse-ai/infrastructure/tests/worktree-manager.test.js +0 -620
  71. package/.sinapse-ai/workflow-intelligence/__tests__/confidence-scorer.test.js +0 -335
  72. package/.sinapse-ai/workflow-intelligence/__tests__/integration.test.js +0 -340
  73. package/.sinapse-ai/workflow-intelligence/__tests__/suggestion-engine.test.js +0 -438
  74. package/.sinapse-ai/workflow-intelligence/__tests__/wave-analyzer.test.js +0 -448
  75. package/.sinapse-ai/workflow-intelligence/__tests__/workflow-registry.test.js +0 -303
  76. package/packages/installer/src/__tests__/performance-benchmark.js +0 -383
  77. package/packages/installer/tests/integration/environment-configuration.test.js +0 -332
  78. package/packages/installer/tests/integration/wizard-detection.test.js +0 -352
  79. package/packages/installer/tests/unit/artifact-copy-pipeline/artifact-copy-pipeline.test.js +0 -402
  80. package/packages/installer/tests/unit/claude-md-template-v5/claude-md-template-v5.test.js +0 -193
  81. package/packages/installer/tests/unit/config-validator.test.js +0 -315
  82. package/packages/installer/tests/unit/detection/detect-project-type.test.js +0 -539
  83. package/packages/installer/tests/unit/doctor/doctor-checks.test.js +0 -675
  84. package/packages/installer/tests/unit/doctor/doctor-orchestrator.test.js +0 -192
  85. package/packages/installer/tests/unit/entity-registry-bootstrap.test.js +0 -192
  86. package/packages/installer/tests/unit/env-template.test.js +0 -187
  87. package/packages/installer/tests/unit/generate-settings-json/generate-settings-json.test.js +0 -310
  88. package/packages/installer/tests/unit/git-hooks-installer.test.js +0 -262
  89. package/packages/installer/tests/unit/ide-sync-integration/ide-sync-integration.test.js +0 -231
  90. package/packages/installer/tests/unit/merger/env-merger.test.js +0 -191
  91. package/packages/installer/tests/unit/merger/markdown-merger.test.js +0 -262
  92. package/packages/installer/tests/unit/merger/strategies.test.js +0 -154
  93. package/packages/installer/tests/unit/merger/yaml-merger.test.js +0 -328
  94. package/packages/sinapse-install/tests/unit/chrome-brain.smoke.test.js +0 -66
@@ -1,438 +0,0 @@
1
- /**
2
- * @fileoverview Unit tests for SuggestionEngine
3
- * @story WIS-3 - *next Task Implementation
4
- */
5
-
6
- 'use strict';
7
-
8
- const path = require('path');
9
- const fs = require('fs');
10
-
11
- // Mock dependencies before requiring SuggestionEngine
12
- jest.mock('../../core/session/context-loader', () => {
13
- return jest.fn().mockImplementation(() => ({
14
- loadContext: jest.fn().mockReturnValue({
15
- sessionType: 'existing',
16
- lastCommands: ['develop'],
17
- currentStory: 'docs/stories/test-story.md',
18
- workflowActive: 'story_development',
19
- }),
20
- }));
21
- });
22
-
23
- const {
24
- SuggestionEngine,
25
- createSuggestionEngine,
26
- SUGGESTION_CACHE_TTL,
27
- LOW_CONFIDENCE_THRESHOLD,
28
- } = require('../engine/suggestion-engine');
29
-
30
- describe('SuggestionEngine', () => {
31
- let engine;
32
-
33
- beforeEach(() => {
34
- engine = createSuggestionEngine({ lazyLoad: true });
35
- engine.invalidateCache();
36
- });
37
-
38
- afterEach(() => {
39
- jest.clearAllMocks();
40
- });
41
-
42
- describe('constructor', () => {
43
- it('should create engine with default options', () => {
44
- const defaultEngine = createSuggestionEngine();
45
- expect(defaultEngine).toBeInstanceOf(SuggestionEngine);
46
- expect(defaultEngine.cacheTTL).toBe(SUGGESTION_CACHE_TTL);
47
- });
48
-
49
- it('should accept custom cache TTL', () => {
50
- const customEngine = createSuggestionEngine({ cacheTTL: 60000 });
51
- expect(customEngine.cacheTTL).toBe(60000);
52
- });
53
-
54
- it('should support lazy loading option', () => {
55
- const lazyEngine = createSuggestionEngine({ lazyLoad: true });
56
- expect(lazyEngine.lazyLoad).toBe(true);
57
- });
58
- });
59
-
60
- describe('buildContext()', () => {
61
- it('should return context object with required properties', async () => {
62
- const context = await engine.buildContext({});
63
-
64
- expect(context).toHaveProperty('agentId');
65
- expect(context).toHaveProperty('lastCommand');
66
- expect(context).toHaveProperty('lastCommands');
67
- expect(context).toHaveProperty('storyPath');
68
- expect(context).toHaveProperty('branch');
69
- expect(context).toHaveProperty('projectState');
70
- });
71
-
72
- it('should use story override when provided', async () => {
73
- // Create a temporary file for testing
74
- const testStoryPath = path.join(process.cwd(), 'test-story-temp.md');
75
- fs.writeFileSync(testStoryPath, '# Test Story');
76
-
77
- try {
78
- const context = await engine.buildContext({
79
- storyOverride: testStoryPath,
80
- });
81
-
82
- expect(context.storyPath).toBe(testStoryPath);
83
- } finally {
84
- // Cleanup
85
- if (fs.existsSync(testStoryPath)) {
86
- fs.unlinkSync(testStoryPath);
87
- }
88
- }
89
- });
90
-
91
- it('should use provided agent ID', async () => {
92
- const context = await engine.buildContext({
93
- agentId: 'qa',
94
- });
95
-
96
- expect(context.agentId).toBe('qa');
97
- });
98
-
99
- it('should detect git branch when in git repo', async () => {
100
- const context = await engine.buildContext({});
101
-
102
- // Branch should be detected or null (if not in git repo)
103
- expect(context.branch === null || typeof context.branch === 'string').toBe(true);
104
- });
105
-
106
- it('should build project state', async () => {
107
- const context = await engine.buildContext({});
108
-
109
- expect(context.projectState).toBeDefined();
110
- expect(typeof context.projectState.activeStory).toBe('boolean');
111
- });
112
- });
113
-
114
- describe('suggestNext()', () => {
115
- it('should return result object with required properties', async () => {
116
- const context = {
117
- agentId: 'dev',
118
- lastCommand: 'develop',
119
- lastCommands: ['develop'],
120
- storyPath: null,
121
- branch: 'main',
122
- projectState: {},
123
- };
124
-
125
- const result = await engine.suggestNext(context);
126
-
127
- expect(result).toHaveProperty('workflow');
128
- expect(result).toHaveProperty('currentState');
129
- expect(result).toHaveProperty('confidence');
130
- expect(result).toHaveProperty('suggestions');
131
- expect(result).toHaveProperty('isUncertain');
132
- expect(Array.isArray(result.suggestions)).toBe(true);
133
- });
134
-
135
- it('should return suggestions with proper structure', async () => {
136
- const context = {
137
- agentId: 'dev',
138
- lastCommand: 'develop',
139
- lastCommands: ['validate-story-draft', 'develop'],
140
- storyPath: 'docs/stories/test.md',
141
- branch: 'feature/test',
142
- projectState: {},
143
- };
144
-
145
- const result = await engine.suggestNext(context);
146
-
147
- if (result.suggestions.length > 0) {
148
- const suggestion = result.suggestions[0];
149
- expect(suggestion).toHaveProperty('command');
150
- expect(suggestion).toHaveProperty('args');
151
- expect(suggestion).toHaveProperty('description');
152
- expect(suggestion).toHaveProperty('confidence');
153
- expect(suggestion).toHaveProperty('priority');
154
- expect(suggestion.command.startsWith('*')).toBe(true);
155
- }
156
- });
157
-
158
- it('should mark low confidence results as uncertain', async () => {
159
- const context = {
160
- agentId: 'unknown',
161
- lastCommand: 'random-command',
162
- lastCommands: ['random-command'],
163
- storyPath: null,
164
- branch: null,
165
- projectState: {},
166
- };
167
-
168
- const result = await engine.suggestNext(context);
169
-
170
- // When no match, should be uncertain
171
- if (result.confidence < LOW_CONFIDENCE_THRESHOLD) {
172
- expect(result.isUncertain).toBe(true);
173
- }
174
- });
175
-
176
- it('should use cache for repeated calls with same context', async () => {
177
- const context = {
178
- agentId: 'dev',
179
- lastCommand: 'develop',
180
- lastCommands: ['develop'],
181
- storyPath: null,
182
- branch: 'main',
183
- projectState: {},
184
- };
185
-
186
- // First call
187
- const result1 = await engine.suggestNext(context);
188
-
189
- // Second call should use cache
190
- const result2 = await engine.suggestNext(context);
191
-
192
- expect(result1).toEqual(result2);
193
- });
194
-
195
- it('should invalidate cache on different context', async () => {
196
- const context1 = {
197
- agentId: 'dev',
198
- lastCommand: 'develop',
199
- lastCommands: ['develop'],
200
- storyPath: null,
201
- branch: 'main',
202
- projectState: {},
203
- };
204
-
205
- const context2 = {
206
- agentId: 'qa',
207
- lastCommand: 'review-qa',
208
- lastCommands: ['review-qa'],
209
- storyPath: null,
210
- branch: 'main',
211
- projectState: {},
212
- };
213
-
214
- await engine.suggestNext(context1);
215
- const result2 = await engine.suggestNext(context2);
216
-
217
- // Should get different result for different context
218
- expect(result2.workflow).toBeDefined();
219
- });
220
- });
221
-
222
- describe('getFallbackSuggestions()', () => {
223
- it('should return fallback for dev agent', () => {
224
- const result = engine.getFallbackSuggestions({ agentId: 'dev' });
225
-
226
- expect(result.suggestions.length).toBeGreaterThan(0);
227
- expect(result.isUncertain).toBe(true);
228
- expect(result.suggestions.some((s) => s.command === '*help')).toBe(true);
229
- });
230
-
231
- it('should return fallback for po agent', () => {
232
- const result = engine.getFallbackSuggestions({ agentId: 'po' });
233
-
234
- expect(result.suggestions.length).toBeGreaterThan(0);
235
- expect(
236
- result.suggestions.some((s) => s.command.includes('backlog') || s.command.includes('story')),
237
- ).toBe(true);
238
- });
239
-
240
- it('should return fallback for qa agent', () => {
241
- const result = engine.getFallbackSuggestions({ agentId: 'qa' });
242
-
243
- expect(result.suggestions.length).toBeGreaterThan(0);
244
- expect(
245
- result.suggestions.some((s) => s.command.includes('test') || s.command.includes('qa')),
246
- ).toBe(true);
247
- });
248
-
249
- it('should return default fallback for unknown agent', () => {
250
- const result = engine.getFallbackSuggestions({ agentId: 'unknown' });
251
-
252
- expect(result.suggestions.length).toBeGreaterThan(0);
253
- expect(result.suggestions.some((s) => s.command === '*help')).toBe(true);
254
- });
255
- });
256
-
257
- describe('invalidateCache()', () => {
258
- it('should clear cached suggestions', async () => {
259
- const context = {
260
- agentId: 'dev',
261
- lastCommand: 'develop',
262
- lastCommands: ['develop'],
263
- storyPath: null,
264
- branch: 'main',
265
- projectState: {},
266
- };
267
-
268
- // Prime the cache
269
- await engine.suggestNext(context);
270
-
271
- // Invalidate
272
- engine.invalidateCache();
273
-
274
- // Cache should be null
275
- expect(engine.suggestionCache).toBeNull();
276
- expect(engine.cacheTimestamp).toBeNull();
277
- expect(engine.cacheKey).toBeNull();
278
- });
279
- });
280
-
281
- describe('_interpolateArgs()', () => {
282
- it('should interpolate story_path variable', () => {
283
- const context = {
284
- storyPath: 'docs/stories/test.md',
285
- };
286
-
287
- const result = engine._interpolateArgs('${story_path}', context);
288
- expect(result).toBe('docs/stories/test.md');
289
- });
290
-
291
- it('should interpolate branch variable', () => {
292
- const context = {
293
- branch: 'feature/test',
294
- };
295
-
296
- const result = engine._interpolateArgs('${branch}', context);
297
- expect(result).toBe('feature/test');
298
- });
299
-
300
- it('should handle missing variables', () => {
301
- const context = {};
302
-
303
- const result = engine._interpolateArgs('${story_path}', context);
304
- expect(result).toBe('');
305
- });
306
-
307
- it('should handle null template', () => {
308
- const result = engine._interpolateArgs(null, {});
309
- expect(result).toBe('');
310
- });
311
- });
312
-
313
- describe('_resolveStoryPath()', () => {
314
- it('should return null for non-existent file', () => {
315
- const result = engine._resolveStoryPath('/non/existent/file.md');
316
- expect(result).toBeNull();
317
- });
318
-
319
- it('should return resolved path for existing file', () => {
320
- const testPath = path.join(process.cwd(), 'package.json');
321
- const result = engine._resolveStoryPath(testPath);
322
- expect(result).toBe(testPath);
323
- });
324
-
325
- it('should handle relative paths', () => {
326
- const result = engine._resolveStoryPath('package.json');
327
- expect(result).toBe(path.resolve(process.cwd(), 'package.json'));
328
- });
329
-
330
- it('should return null for null input', () => {
331
- const result = engine._resolveStoryPath(null);
332
- expect(result).toBeNull();
333
- });
334
- });
335
-
336
- describe('_generateCacheKey()', () => {
337
- it('should generate consistent key for same context', () => {
338
- const context = {
339
- agentId: 'dev',
340
- lastCommand: 'develop',
341
- lastCommands: ['a', 'b', 'c'],
342
- storyPath: 'test.md',
343
- branch: 'main',
344
- };
345
-
346
- const key1 = engine._generateCacheKey(context);
347
- const key2 = engine._generateCacheKey(context);
348
-
349
- expect(key1).toBe(key2);
350
- });
351
-
352
- it('should generate different key for different context', () => {
353
- const context1 = {
354
- agentId: 'dev',
355
- lastCommand: 'develop',
356
- };
357
- const context2 = {
358
- agentId: 'qa',
359
- lastCommand: 'review',
360
- };
361
-
362
- const key1 = engine._generateCacheKey(context1);
363
- const key2 = engine._generateCacheKey(context2);
364
-
365
- expect(key1).not.toBe(key2);
366
- });
367
- });
368
-
369
- describe('constants', () => {
370
- it('should export SUGGESTION_CACHE_TTL', () => {
371
- expect(SUGGESTION_CACHE_TTL).toBe(5 * 60 * 1000); // 5 minutes
372
- });
373
-
374
- it('should export LOW_CONFIDENCE_THRESHOLD', () => {
375
- expect(LOW_CONFIDENCE_THRESHOLD).toBe(0.5);
376
- });
377
- });
378
- });
379
-
380
- describe('SuggestionEngine Performance', () => {
381
- let engine;
382
-
383
- beforeEach(() => {
384
- engine = createSuggestionEngine();
385
- engine.invalidateCache();
386
- });
387
-
388
- it('should complete suggestNext within 100ms', async () => {
389
- const context = {
390
- agentId: 'dev',
391
- lastCommand: 'develop',
392
- lastCommands: ['develop'],
393
- storyPath: null,
394
- branch: 'main',
395
- projectState: {},
396
- };
397
-
398
- const start = Date.now();
399
- await engine.suggestNext(context);
400
- const duration = Date.now() - start;
401
-
402
- expect(duration).toBeLessThan(100);
403
- });
404
-
405
- it('should complete buildContext within 50ms', async () => {
406
- const start = Date.now();
407
- await engine.buildContext({});
408
- const duration = Date.now() - start;
409
-
410
- expect(duration).toBeLessThan(50);
411
- });
412
-
413
- it('should be faster on cache hit', async () => {
414
- const context = {
415
- agentId: 'dev',
416
- lastCommand: 'develop',
417
- lastCommands: ['develop'],
418
- storyPath: null,
419
- branch: 'main',
420
- projectState: {},
421
- };
422
-
423
- // Cold start
424
- const start1 = Date.now();
425
- await engine.suggestNext(context);
426
- const coldDuration = Date.now() - start1;
427
-
428
- // Warm cache
429
- const start2 = Date.now();
430
- await engine.suggestNext(context);
431
- const warmDuration = Date.now() - start2;
432
-
433
- // Allow 5ms tolerance for timing noise (Date.now() has ~1ms resolution)
434
- // In CI environments, timing can be inconsistent
435
- expect(warmDuration).toBeLessThanOrEqual(coldDuration + 5);
436
- });
437
- });
438
-