@smartsoft001/pro-claude-plugins 0.2.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-plugin/marketplace.json +26 -0
- package/README.md +56 -0
- package/package.json +14 -0
- package/plugins/flow/.claude-plugin/README.md +91 -0
- package/plugins/flow/.claude-plugin/merge-permissions.js +115 -0
- package/plugins/flow/.claude-plugin/plugin.json +5 -0
- package/plugins/flow/.claude-plugin/settings.template.json +86 -0
- package/plugins/flow/agents/angular-component-scaffolder.md +176 -0
- package/plugins/flow/agents/angular-directive-builder.md +154 -0
- package/plugins/flow/agents/angular-guard-builder.md +244 -0
- package/plugins/flow/agents/angular-jest-test-writer.md +475 -0
- package/plugins/flow/agents/angular-pipe-builder.md +170 -0
- package/plugins/flow/agents/angular-resolver-builder.md +287 -0
- package/plugins/flow/agents/angular-service-builder.md +162 -0
- package/plugins/flow/agents/angular-signal-state-builder.md +340 -0
- package/plugins/flow/agents/angular-test-diagnostician.md +279 -0
- package/plugins/flow/agents/angular-testbed-configurator.md +315 -0
- package/plugins/flow/agents/arch-scaffolder.md +278 -0
- package/plugins/flow/agents/e2e-data-testid-injector.md +195 -0
- package/plugins/flow/agents/e2e-project-scaffolder.md +194 -0
- package/plugins/flow/agents/e2e-test-writer.md +357 -0
- package/plugins/flow/agents/shared-agent-evolver.md +294 -0
- package/plugins/flow/agents/shared-build-verifier.md +160 -0
- package/plugins/flow/agents/shared-config-updater.md +310 -0
- package/plugins/flow/agents/shared-coverage-enforcer.md +184 -0
- package/plugins/flow/agents/shared-error-handler.md +217 -0
- package/plugins/flow/agents/shared-file-creator.md +344 -0
- package/plugins/flow/agents/shared-impl-orchestrator.md +312 -0
- package/plugins/flow/agents/shared-impl-reporter.md +368 -0
- package/plugins/flow/agents/shared-impl-teammate.md +201 -0
- package/plugins/flow/agents/shared-linear-subtask-iterator.md +337 -0
- package/plugins/flow/agents/shared-logic-implementer.md +244 -0
- package/plugins/flow/agents/shared-maia-api.md +26 -0
- package/plugins/flow/agents/shared-parallelization-analyzer.md +343 -0
- package/plugins/flow/agents/shared-performance-validator.md +168 -0
- package/plugins/flow/agents/shared-plan-perspective.md +271 -0
- package/plugins/flow/agents/shared-project-standardizer.md +205 -0
- package/plugins/flow/agents/shared-report-synthesizer.md +188 -0
- package/plugins/flow/agents/shared-review-teammate.md +189 -0
- package/plugins/flow/agents/shared-security-scanner.md +186 -0
- package/plugins/flow/agents/shared-style-enforcer.md +230 -0
- package/plugins/flow/agents/shared-subtask-dependency-analyzer.md +189 -0
- package/plugins/flow/agents/shared-tdd-developer.md +350 -0
- package/plugins/flow/agents/shared-team-coordinator.md +192 -0
- package/plugins/flow/agents/shared-test-fixer.md +186 -0
- package/plugins/flow/agents/shared-test-runner.md +191 -0
- package/plugins/flow/agents/shared-ui-classifier.md +263 -0
- package/plugins/flow/agents/shared-verification-orchestrator.md +194 -0
- package/plugins/flow/agents/shared-verification-runner.md +140 -0
- package/plugins/flow/agents/ui-a11y-validator.md +305 -0
- package/plugins/flow/agents/ui-screenshot-reporter.md +329 -0
- package/plugins/flow/agents/ui-web-designer.md +214 -0
- package/plugins/flow/scripts/compute-session-tokens.sh +39 -0
- package/plugins/flow/skills/a11y-audit/SKILL.md +214 -0
- package/plugins/flow/skills/angular-patterns/SKILL.md +191 -0
- package/plugins/flow/skills/browser-capture/SKILL.md +238 -0
- package/plugins/flow/skills/commit/SKILL.md +259 -0
- package/plugins/flow/skills/debug-helper/SKILL.md +375 -0
- package/plugins/flow/skills/impl/SKILL.md +992 -0
- package/plugins/flow/skills/karpathy-guidelines/SKILL.md +72 -0
- package/plugins/flow/skills/linear-suggestion/SKILL.md +132 -0
- package/plugins/flow/skills/maia-files-delete/SKILL.md +59 -0
- package/plugins/flow/skills/maia-files-upload/SKILL.md +57 -0
- package/plugins/flow/skills/nx-conventions/SKILL.md +326 -0
- package/plugins/flow/skills/plan/SKILL.md +1033 -0
- package/plugins/flow/skills/push/SKILL.md +759 -0
- package/plugins/flow/skills/review/SKILL.md +443 -0
- package/plugins/flow/skills/test-e2e/SKILL.md +164 -0
- package/plugins/flow/skills/test-unit/SKILL.md +456 -0
- package/plugins/flow-external/.claude-plugin/README.md +146 -0
- package/plugins/flow-external/.claude-plugin/merge-permissions.js +94 -0
- package/plugins/flow-external/.claude-plugin/plugin.json +5 -0
- package/plugins/flow-external/.claude-plugin/settings.template.json +78 -0
- package/plugins/flow-external/agents/angular-component-scaffolder.md +271 -0
- package/plugins/flow-external/agents/angular-directive-builder.md +134 -0
- package/plugins/flow-external/agents/angular-guard-builder.md +73 -0
- package/plugins/flow-external/agents/angular-pipe-builder.md +90 -0
- package/plugins/flow-external/agents/angular-resolver-builder.md +79 -0
- package/plugins/flow-external/agents/angular-service-builder.md +168 -0
- package/plugins/flow-external/agents/angular-state-builder.md +263 -0
- package/plugins/flow-external/agents/shared-build-verifier.md +67 -0
- package/plugins/flow-external/agents/shared-impl-orchestrator.md +90 -0
- package/plugins/flow-external/agents/shared-impl-reporter.md +135 -0
- package/plugins/flow-external/agents/shared-linear-subtask-iterator.md +70 -0
- package/plugins/flow-external/agents/shared-ui-classifier.md +38 -0
- package/plugins/flow-external/agents/ui-web-designer.md +203 -0
- package/plugins/flow-external/scripts/compute-session-tokens.sh +39 -0
- package/plugins/flow-external/skills/a11y-audit/SKILL.md +97 -0
- package/plugins/flow-external/skills/angular-cli-conventions/SKILL.md +268 -0
- package/plugins/flow-external/skills/angular-patterns/SKILL.md +182 -0
- package/plugins/flow-external/skills/browser-capture/SKILL.md +74 -0
- package/plugins/flow-external/skills/commit/SKILL.md +114 -0
- package/plugins/flow-external/skills/debug-helper/SKILL.md +135 -0
- package/plugins/flow-external/skills/impl/SKILL.md +218 -0
- package/plugins/flow-external/skills/karpathy-guidelines/SKILL.md +72 -0
- package/plugins/flow-external/skills/linear-suggestion/SKILL.md +62 -0
- package/plugins/flow-external/skills/maia-files-delete/SKILL.md +34 -0
- package/plugins/flow-external/skills/maia-files-upload/SKILL.md +41 -0
- package/plugins/flow-external/skills/plan/SKILL.md +334 -0
- package/plugins/flow-external/skills/push/SKILL.md +232 -0
- package/plugins/flow-legacy/.claude-plugin/README.md +143 -0
- package/plugins/flow-legacy/.claude-plugin/merge-permissions.js +94 -0
- package/plugins/flow-legacy/.claude-plugin/plugin.json +5 -0
- package/plugins/flow-legacy/.claude-plugin/settings.template.json +79 -0
- package/plugins/flow-legacy/agents/angular-component-scaffolder.md +327 -0
- package/plugins/flow-legacy/agents/angular-directive-builder.md +253 -0
- package/plugins/flow-legacy/agents/angular-guard-builder.md +326 -0
- package/plugins/flow-legacy/agents/angular-pipe-builder.md +238 -0
- package/plugins/flow-legacy/agents/angular-resolver-builder.md +339 -0
- package/plugins/flow-legacy/agents/angular-service-builder.md +271 -0
- package/plugins/flow-legacy/agents/angular-state-builder.md +480 -0
- package/plugins/flow-legacy/agents/shared-impl-orchestrator.md +174 -0
- package/plugins/flow-legacy/agents/shared-impl-reporter.md +232 -0
- package/plugins/flow-legacy/agents/shared-linear-subtask-iterator.md +198 -0
- package/plugins/flow-legacy/agents/shared-tdd-developer.md +307 -0
- package/plugins/flow-legacy/agents/shared-test-runner.md +133 -0
- package/plugins/flow-legacy/agents/shared-ui-classifier.md +145 -0
- package/plugins/flow-legacy/scripts/compute-session-tokens.sh +39 -0
- package/plugins/flow-legacy/skills/a11y-audit/SKILL.md +214 -0
- package/plugins/flow-legacy/skills/angular-patterns/SKILL.md +346 -0
- package/plugins/flow-legacy/skills/browser-capture/SKILL.md +238 -0
- package/plugins/flow-legacy/skills/commit/SKILL.md +215 -0
- package/plugins/flow-legacy/skills/debug-helper/SKILL.md +395 -0
- package/plugins/flow-legacy/skills/impl/SKILL.md +710 -0
- package/plugins/flow-legacy/skills/karpathy-guidelines/SKILL.md +72 -0
- package/plugins/flow-legacy/skills/linear-suggestion/SKILL.md +132 -0
- package/plugins/flow-legacy/skills/maia-files-delete/SKILL.md +59 -0
- package/plugins/flow-legacy/skills/maia-files-upload/SKILL.md +57 -0
- package/plugins/flow-legacy/skills/nx-conventions/SKILL.md +368 -0
- package/plugins/flow-legacy/skills/plan/SKILL.md +742 -0
- package/plugins/flow-legacy/skills/push/SKILL.md +645 -0
- package/plugins/flow-legacy/skills/test-unit/SKILL.md +500 -0
- package/plugins/smart-pro/.claude-plugin/README.md +115 -0
- package/plugins/smart-pro/.claude-plugin/merge-permissions.js +129 -0
- package/plugins/smart-pro/.claude-plugin/plugin.json +5 -0
- package/plugins/smart-pro/.claude-plugin/settings.template.json +94 -0
- package/plugins/smart-pro/agents/angular-components/AGENT.md +214 -0
- package/plugins/smart-pro/hooks/CONFIG.md +198 -0
- package/plugins/smart-pro/hooks/README.md +139 -0
- package/plugins/smart-pro/hooks/audit_logger.py +107 -0
- package/plugins/smart-pro/hooks/auto_format.sh +11 -0
- package/plugins/smart-pro/hooks/hooks.json +79 -0
- package/plugins/smart-pro/hooks/safety_validator.py +129 -0
- package/plugins/smart-pro/hooks/sensitive_file_blocker.py +58 -0
- package/plugins/smart-pro/hooks/skill_validator.py +220 -0
- package/plugins/smart-pro/skills/angular-components-action-panel/SKILL.md +159 -0
- package/plugins/smart-pro/skills/angular-components-avatar/SKILL.md +142 -0
- package/plugins/smart-pro/skills/angular-components-badge/SKILL.md +110 -0
- package/plugins/smart-pro/skills/angular-components-breadcrumbs/SKILL.md +91 -0
- package/plugins/smart-pro/skills/angular-components-button/SKILL.md +146 -0
- package/plugins/smart-pro/skills/angular-components-button-group/SKILL.md +121 -0
- package/plugins/smart-pro/skills/angular-components-calendar/SKILL.md +78 -0
- package/plugins/smart-pro/skills/angular-components-card/SKILL.md +110 -0
- package/plugins/smart-pro/skills/angular-components-card-heading/SKILL.md +105 -0
- package/plugins/smart-pro/skills/angular-components-command-palette/SKILL.md +168 -0
- package/plugins/smart-pro/skills/angular-components-container/SKILL.md +93 -0
- package/plugins/smart-pro/skills/angular-components-description-list/SKILL.md +102 -0
- package/plugins/smart-pro/skills/angular-components-details/SKILL.md +70 -0
- package/plugins/smart-pro/skills/angular-components-divider/SKILL.md +110 -0
- package/plugins/smart-pro/skills/angular-components-drawer/SKILL.md +136 -0
- package/plugins/smart-pro/skills/angular-components-dropdown/SKILL.md +131 -0
- package/plugins/smart-pro/skills/angular-components-empty-state/SKILL.md +103 -0
- package/plugins/smart-pro/skills/angular-components-feed/SKILL.md +110 -0
- package/plugins/smart-pro/skills/angular-components-form/SKILL.md +77 -0
- package/plugins/smart-pro/skills/angular-components-grid-list/SKILL.md +91 -0
- package/plugins/smart-pro/skills/angular-components-input/SKILL.md +118 -0
- package/plugins/smart-pro/skills/angular-components-list/SKILL.md +75 -0
- package/plugins/smart-pro/skills/angular-components-list-container/SKILL.md +106 -0
- package/plugins/smart-pro/skills/angular-components-media-object/SKILL.md +133 -0
- package/plugins/smart-pro/skills/angular-components-modal/SKILL.md +159 -0
- package/plugins/smart-pro/skills/angular-components-multi-column-layout/SKILL.md +84 -0
- package/plugins/smart-pro/skills/angular-components-navbar/SKILL.md +93 -0
- package/plugins/smart-pro/skills/angular-components-notification/SKILL.md +147 -0
- package/plugins/smart-pro/skills/angular-components-page/SKILL.md +162 -0
- package/plugins/smart-pro/skills/angular-components-page-heading/SKILL.md +96 -0
- package/plugins/smart-pro/skills/angular-components-paging/SKILL.md +86 -0
- package/plugins/smart-pro/skills/angular-components-progress-bars/SKILL.md +94 -0
- package/plugins/smart-pro/skills/angular-components-searchbar/SKILL.md +113 -0
- package/plugins/smart-pro/skills/angular-components-section-heading/SKILL.md +156 -0
- package/plugins/smart-pro/skills/angular-components-select-menu/SKILL.md +101 -0
- package/plugins/smart-pro/skills/angular-components-sidebar-layout/SKILL.md +121 -0
- package/plugins/smart-pro/skills/angular-components-sidebar-navigation/SKILL.md +80 -0
- package/plugins/smart-pro/skills/angular-components-sign-in-form/SKILL.md +91 -0
- package/plugins/smart-pro/skills/angular-components-stacked-layout/SKILL.md +114 -0
- package/plugins/smart-pro/skills/angular-components-stacked-list/SKILL.md +93 -0
- package/plugins/smart-pro/skills/angular-components-stats/SKILL.md +87 -0
- package/plugins/smart-pro/skills/angular-components-table/SKILL.md +98 -0
- package/plugins/smart-pro/skills/angular-components-tabs/SKILL.md +99 -0
- package/plugins/smart-pro/skills/angular-components-textarea/SKILL.md +111 -0
- package/plugins/smart-pro/skills/angular-components-toggle/SKILL.md +109 -0
- package/plugins/smart-pro/skills/angular-components-vertical-navigation/SKILL.md +139 -0
- package/plugins/smart-pro/skills/audit-log/SKILL.md +82 -0
- package/plugins/smart-pro/skills/format-code/SKILL.md +46 -0
- package/plugins/smart-pro/skills/project-conventions/SKILL.md +90 -0
- package/plugins/smart-pro/skills/safety-check/SKILL.md +0 -0
- package/src/index.d.ts +6 -0
- package/src/index.js +7 -0
- package/src/index.js.map +1 -0
|
@@ -0,0 +1,456 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: test-unit
|
|
3
|
+
description: Write unit tests following project conventions. Generates Jest tests for Angular components, services, and NestJS services using AAA pattern.
|
|
4
|
+
allowed-tools:
|
|
5
|
+
- Bash
|
|
6
|
+
- Read
|
|
7
|
+
- Write
|
|
8
|
+
- Edit
|
|
9
|
+
- Glob
|
|
10
|
+
- Grep
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# Unit Test Skill
|
|
14
|
+
|
|
15
|
+
Write unit tests following project conventions using Jest framework with AAA (Arrange-Act-Assert) pattern.
|
|
16
|
+
|
|
17
|
+
## Testing Framework
|
|
18
|
+
|
|
19
|
+
- **Framework**: Jest for all unit tests
|
|
20
|
+
- **File naming**: `{name}.spec.ts` alongside source files
|
|
21
|
+
- **Test runner**: Nx (`nx test {project}`)
|
|
22
|
+
|
|
23
|
+
## Test File Location
|
|
24
|
+
|
|
25
|
+
Place test files next to the source files they test:
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
feature/
|
|
29
|
+
├── feature.service.ts
|
|
30
|
+
├── feature.service.spec.ts
|
|
31
|
+
├── feature.component.ts
|
|
32
|
+
└── feature.component.spec.ts
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Naming Convention
|
|
36
|
+
|
|
37
|
+
- **Describe blocks**: `@{package-name}: ClassName`
|
|
38
|
+
- **Test format**: `it('should...')` with clear behavior description
|
|
39
|
+
|
|
40
|
+
## Test Structure (AAA Pattern)
|
|
41
|
+
|
|
42
|
+
Always use Arrange-Act-Assert pattern with blank line separation (no comments):
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
it('should perform expected operation', () => {
|
|
46
|
+
const input = 'test';
|
|
47
|
+
|
|
48
|
+
const result = service.performOperation(input);
|
|
49
|
+
|
|
50
|
+
expect(result).toBe('expected output');
|
|
51
|
+
});
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Angular Component Testing
|
|
55
|
+
|
|
56
|
+
### Basic Component Test
|
|
57
|
+
|
|
58
|
+
```typescript
|
|
59
|
+
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
60
|
+
|
|
61
|
+
import { FeatureComponent } from './feature.component';
|
|
62
|
+
|
|
63
|
+
describe('@mms/shared-angular: FeatureComponent', () => {
|
|
64
|
+
let component: FeatureComponent;
|
|
65
|
+
let fixture: ComponentFixture<FeatureComponent>;
|
|
66
|
+
|
|
67
|
+
beforeEach(async () => {
|
|
68
|
+
await TestBed.configureTestingModule({
|
|
69
|
+
imports: [FeatureComponent], // Standalone components
|
|
70
|
+
}).compileComponents();
|
|
71
|
+
|
|
72
|
+
fixture = TestBed.createComponent(FeatureComponent);
|
|
73
|
+
component = fixture.componentInstance;
|
|
74
|
+
fixture.detectChanges();
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it('should create', () => {
|
|
78
|
+
expect(component).toBeTruthy();
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it('should display expected content', () => {
|
|
82
|
+
component.title = 'Test Title';
|
|
83
|
+
fixture.detectChanges();
|
|
84
|
+
|
|
85
|
+
const compiled = fixture.nativeElement;
|
|
86
|
+
expect(compiled.querySelector('h1')?.textContent).toContain('Test Title');
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Testing Signal-based Components
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
95
|
+
import { signal } from '@angular/core';
|
|
96
|
+
|
|
97
|
+
import { SignalComponent } from './signal.component';
|
|
98
|
+
|
|
99
|
+
describe('@mms/shared-angular: SignalComponent', () => {
|
|
100
|
+
let component: SignalComponent;
|
|
101
|
+
let fixture: ComponentFixture<SignalComponent>;
|
|
102
|
+
|
|
103
|
+
beforeEach(async () => {
|
|
104
|
+
await TestBed.configureTestingModule({
|
|
105
|
+
imports: [SignalComponent],
|
|
106
|
+
}).compileComponents();
|
|
107
|
+
|
|
108
|
+
fixture = TestBed.createComponent(SignalComponent);
|
|
109
|
+
component = fixture.componentInstance;
|
|
110
|
+
fixture.detectChanges();
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it('should update when signal changes', () => {
|
|
114
|
+
component.count.set(5);
|
|
115
|
+
fixture.detectChanges();
|
|
116
|
+
|
|
117
|
+
expect(fixture.nativeElement.textContent).toContain('5');
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it('should compute derived value', () => {
|
|
121
|
+
component.items.set([1, 2, 3]);
|
|
122
|
+
|
|
123
|
+
expect(component.total()).toBe(6);
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Testing Components with input()/output()
|
|
129
|
+
|
|
130
|
+
```typescript
|
|
131
|
+
describe('@mms/shared-angular: InputOutputComponent', () => {
|
|
132
|
+
let component: InputOutputComponent;
|
|
133
|
+
let fixture: ComponentFixture<InputOutputComponent>;
|
|
134
|
+
|
|
135
|
+
beforeEach(async () => {
|
|
136
|
+
await TestBed.configureTestingModule({
|
|
137
|
+
imports: [InputOutputComponent],
|
|
138
|
+
}).compileComponents();
|
|
139
|
+
|
|
140
|
+
fixture = TestBed.createComponent(InputOutputComponent);
|
|
141
|
+
component = fixture.componentInstance;
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
it('should accept input value', () => {
|
|
145
|
+
fixture.componentRef.setInput('value', 'test');
|
|
146
|
+
fixture.detectChanges();
|
|
147
|
+
|
|
148
|
+
expect(component.value()).toBe('test');
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
it('should emit output event', () => {
|
|
152
|
+
const spy = jest.fn();
|
|
153
|
+
component.changed.subscribe(spy);
|
|
154
|
+
|
|
155
|
+
component.emitChange('new value');
|
|
156
|
+
|
|
157
|
+
expect(spy).toHaveBeenCalledWith('new value');
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### Testing with Services
|
|
163
|
+
|
|
164
|
+
```typescript
|
|
165
|
+
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
166
|
+
|
|
167
|
+
import { FeatureComponent } from './feature.component';
|
|
168
|
+
import { DataService } from './data.service';
|
|
169
|
+
|
|
170
|
+
describe('@mms/shared-angular: FeatureComponent', () => {
|
|
171
|
+
let component: FeatureComponent;
|
|
172
|
+
let fixture: ComponentFixture<FeatureComponent>;
|
|
173
|
+
let mockDataService: jest.Mocked<DataService>;
|
|
174
|
+
|
|
175
|
+
beforeEach(async () => {
|
|
176
|
+
mockDataService = {
|
|
177
|
+
getData: jest.fn().mockReturnValue(of(['item1', 'item2'])),
|
|
178
|
+
saveData: jest.fn().mockReturnValue(of(true)),
|
|
179
|
+
} as unknown as jest.Mocked<DataService>;
|
|
180
|
+
|
|
181
|
+
await TestBed.configureTestingModule({
|
|
182
|
+
imports: [FeatureComponent],
|
|
183
|
+
providers: [{ provide: DataService, useValue: mockDataService }],
|
|
184
|
+
}).compileComponents();
|
|
185
|
+
|
|
186
|
+
fixture = TestBed.createComponent(FeatureComponent);
|
|
187
|
+
component = fixture.componentInstance;
|
|
188
|
+
fixture.detectChanges();
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
it('should load data on init', () => {
|
|
192
|
+
expect(mockDataService.getData).toHaveBeenCalled();
|
|
193
|
+
expect(component.items()).toEqual(['item1', 'item2']);
|
|
194
|
+
});
|
|
195
|
+
});
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
## Angular Service Testing
|
|
199
|
+
|
|
200
|
+
```typescript
|
|
201
|
+
import { TestBed } from '@angular/core/testing';
|
|
202
|
+
import {
|
|
203
|
+
HttpTestingController,
|
|
204
|
+
provideHttpClientTesting,
|
|
205
|
+
} from '@angular/common/http/testing';
|
|
206
|
+
import { provideHttpClient } from '@angular/common/http';
|
|
207
|
+
|
|
208
|
+
import { DataService } from './data.service';
|
|
209
|
+
|
|
210
|
+
describe('@mms/shared-angular: DataService', () => {
|
|
211
|
+
let service: DataService;
|
|
212
|
+
let httpMock: HttpTestingController;
|
|
213
|
+
|
|
214
|
+
beforeEach(() => {
|
|
215
|
+
TestBed.configureTestingModule({
|
|
216
|
+
providers: [DataService, provideHttpClient(), provideHttpClientTesting()],
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
service = TestBed.inject(DataService);
|
|
220
|
+
httpMock = TestBed.inject(HttpTestingController);
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
afterEach(() => {
|
|
224
|
+
httpMock.verify();
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
it('should be created', () => {
|
|
228
|
+
expect(service).toBeTruthy();
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
it('should fetch data', () => {
|
|
232
|
+
const mockData = [{ id: 1, name: 'Test' }];
|
|
233
|
+
|
|
234
|
+
service.getData().subscribe((data) => {
|
|
235
|
+
expect(data).toEqual(mockData);
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
const req = httpMock.expectOne('/api/data');
|
|
239
|
+
expect(req.request.method).toBe('GET');
|
|
240
|
+
req.flush(mockData);
|
|
241
|
+
});
|
|
242
|
+
});
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
## NestJS Service Testing
|
|
246
|
+
|
|
247
|
+
### Basic Service Test
|
|
248
|
+
|
|
249
|
+
```typescript
|
|
250
|
+
import { TestingModule, Test } from '@nestjs/testing';
|
|
251
|
+
|
|
252
|
+
import { FeatureService } from './feature.service';
|
|
253
|
+
|
|
254
|
+
describe('@mms/module-name: FeatureService', () => {
|
|
255
|
+
let service: FeatureService;
|
|
256
|
+
let module: TestingModule;
|
|
257
|
+
|
|
258
|
+
beforeEach(async () => {
|
|
259
|
+
module = await Test.createTestingModule({
|
|
260
|
+
providers: [FeatureService],
|
|
261
|
+
}).compile();
|
|
262
|
+
|
|
263
|
+
service = module.get<FeatureService>(FeatureService);
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
afterEach(async () => {
|
|
267
|
+
await module.close();
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
it('should be defined', () => {
|
|
271
|
+
expect(service).toBeDefined();
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
it('should perform expected operation', () => {
|
|
275
|
+
const input = 'test';
|
|
276
|
+
|
|
277
|
+
const result = service.performOperation(input);
|
|
278
|
+
|
|
279
|
+
expect(result).toBe('expected output');
|
|
280
|
+
});
|
|
281
|
+
});
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
### Service with Repository
|
|
285
|
+
|
|
286
|
+
```typescript
|
|
287
|
+
import { TestingModule, Test } from '@nestjs/testing';
|
|
288
|
+
import { getRepositoryToken } from '@nestjs/typeorm';
|
|
289
|
+
|
|
290
|
+
import { UserService } from './user.service';
|
|
291
|
+
import { User } from './user.entity';
|
|
292
|
+
|
|
293
|
+
describe('@mms/module-name: UserService', () => {
|
|
294
|
+
let service: UserService;
|
|
295
|
+
let module: TestingModule;
|
|
296
|
+
let mockRepository: Record<string, jest.Mock>;
|
|
297
|
+
|
|
298
|
+
beforeEach(async () => {
|
|
299
|
+
mockRepository = {
|
|
300
|
+
findOne: jest.fn(),
|
|
301
|
+
find: jest.fn(),
|
|
302
|
+
save: jest.fn(),
|
|
303
|
+
update: jest.fn(),
|
|
304
|
+
delete: jest.fn(),
|
|
305
|
+
};
|
|
306
|
+
|
|
307
|
+
module = await Test.createTestingModule({
|
|
308
|
+
providers: [
|
|
309
|
+
UserService,
|
|
310
|
+
{
|
|
311
|
+
provide: getRepositoryToken(User),
|
|
312
|
+
useValue: mockRepository,
|
|
313
|
+
},
|
|
314
|
+
],
|
|
315
|
+
}).compile();
|
|
316
|
+
|
|
317
|
+
service = module.get<UserService>(UserService);
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
afterEach(async () => {
|
|
321
|
+
await module.close();
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
it('should find user by id', async () => {
|
|
325
|
+
const mockUser = { id: '1', name: 'Test User' };
|
|
326
|
+
mockRepository.findOne.mockResolvedValue(mockUser);
|
|
327
|
+
|
|
328
|
+
const result = await service.findById('1');
|
|
329
|
+
|
|
330
|
+
expect(result).toEqual(mockUser);
|
|
331
|
+
expect(mockRepository.findOne).toHaveBeenCalledWith({ where: { id: '1' } });
|
|
332
|
+
});
|
|
333
|
+
});
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
## Mocking Patterns
|
|
337
|
+
|
|
338
|
+
### HTTP Client Mock
|
|
339
|
+
|
|
340
|
+
```typescript
|
|
341
|
+
const mockHttpClient = {
|
|
342
|
+
get: jest.fn(),
|
|
343
|
+
post: jest.fn(),
|
|
344
|
+
put: jest.fn(),
|
|
345
|
+
delete: jest.fn(),
|
|
346
|
+
};
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
### Service Mock
|
|
350
|
+
|
|
351
|
+
```typescript
|
|
352
|
+
const mockService = {
|
|
353
|
+
getData: jest.fn().mockReturnValue(of(mockData)),
|
|
354
|
+
createItem: jest.fn().mockReturnValue(of(mockItem)),
|
|
355
|
+
updateItem: jest.fn().mockReturnValue(of(updatedMockItem)),
|
|
356
|
+
};
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
### LocalStorage Mock
|
|
360
|
+
|
|
361
|
+
```typescript
|
|
362
|
+
let localStorageMock: any;
|
|
363
|
+
|
|
364
|
+
beforeEach(() => {
|
|
365
|
+
localStorageMock = (() => {
|
|
366
|
+
let store: Record<string, string> = {};
|
|
367
|
+
return {
|
|
368
|
+
getItem: jest.fn((key: string) => store[key] || null),
|
|
369
|
+
setItem: jest.fn((key: string, value: string) => {
|
|
370
|
+
store[key] = value;
|
|
371
|
+
}),
|
|
372
|
+
removeItem: jest.fn((key: string) => {
|
|
373
|
+
delete store[key];
|
|
374
|
+
}),
|
|
375
|
+
clear: jest.fn(() => {
|
|
376
|
+
store = {};
|
|
377
|
+
}),
|
|
378
|
+
};
|
|
379
|
+
})();
|
|
380
|
+
Object.defineProperty(window, 'localStorage', { value: localStorageMock });
|
|
381
|
+
});
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
## Test Data Factory Pattern
|
|
385
|
+
|
|
386
|
+
```typescript
|
|
387
|
+
export const createMockUser = (overrides: Partial<User> = {}): User => ({
|
|
388
|
+
id: 'test-id',
|
|
389
|
+
login: 'testuser',
|
|
390
|
+
name: 'Test',
|
|
391
|
+
surname: 'User',
|
|
392
|
+
email: 'test@example.com',
|
|
393
|
+
phoneNumber: '+1234567890',
|
|
394
|
+
del: false,
|
|
395
|
+
createdAt: new Date(),
|
|
396
|
+
updatedAt: new Date(),
|
|
397
|
+
...overrides,
|
|
398
|
+
});
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
## Test Commands
|
|
402
|
+
|
|
403
|
+
```bash
|
|
404
|
+
# Run tests for specific project
|
|
405
|
+
nx test web
|
|
406
|
+
nx test shared-angular
|
|
407
|
+
|
|
408
|
+
# Run tests in watch mode
|
|
409
|
+
nx test web --watch
|
|
410
|
+
|
|
411
|
+
# Run tests with coverage
|
|
412
|
+
nx test web --coverage
|
|
413
|
+
|
|
414
|
+
# Run all tests
|
|
415
|
+
nx run-many --target=test
|
|
416
|
+
|
|
417
|
+
# Run specific test file
|
|
418
|
+
nx test shared-angular --testFile=feature.service.spec.ts
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
## What to Test
|
|
422
|
+
|
|
423
|
+
- Business logic in services
|
|
424
|
+
- Component behavior and state changes
|
|
425
|
+
- Public API contracts
|
|
426
|
+
- Error handling scenarios
|
|
427
|
+
- Input validation
|
|
428
|
+
- Edge cases and boundary conditions
|
|
429
|
+
|
|
430
|
+
## What NOT to Test
|
|
431
|
+
|
|
432
|
+
- Third-party libraries
|
|
433
|
+
- Framework internals (Angular/NestJS)
|
|
434
|
+
- Simple getters/setters without logic
|
|
435
|
+
- Auto-generated code
|
|
436
|
+
- Private methods directly (test through public API)
|
|
437
|
+
|
|
438
|
+
## Workflow
|
|
439
|
+
|
|
440
|
+
1. **Read source file** to understand the code being tested
|
|
441
|
+
2. **Create test file** with `.spec.ts` extension next to source
|
|
442
|
+
3. **Write describe block** with package and class name
|
|
443
|
+
4. **Add beforeEach** with TestBed/Test setup
|
|
444
|
+
5. **Write tests** using AAA pattern
|
|
445
|
+
6. **Run tests** with `nx test {project}`
|
|
446
|
+
7. **Fix failures** and ensure all pass
|
|
447
|
+
|
|
448
|
+
## Best Practices
|
|
449
|
+
|
|
450
|
+
1. **One assertion per test** when practical
|
|
451
|
+
2. **Descriptive test names** that explain behavior
|
|
452
|
+
3. **Independent tests** - no shared state between tests
|
|
453
|
+
4. **Mock external dependencies** - isolate unit under test
|
|
454
|
+
5. **Test edge cases** - empty arrays, null values, boundaries
|
|
455
|
+
6. **Keep tests fast** - avoid real HTTP calls or timers
|
|
456
|
+
7. **Clean up** - use afterEach for cleanup when needed
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# Flow-External Plugin for Claude Code
|
|
2
|
+
|
|
3
|
+
Development flow skills for **standalone Angular 6-11 projects** without the Pro framework. These are external projects using Angular CLI with their own styling approach (Bootstrap 4, custom SCSS, or other).
|
|
4
|
+
|
|
5
|
+
## Target Projects
|
|
6
|
+
|
|
7
|
+
This plugin is designed for standalone Angular 6-11 projects without the Pro framework — typical use case: legacy client apps using Angular CLI with their own styling and project layout.
|
|
8
|
+
|
|
9
|
+
### Technology Stack
|
|
10
|
+
|
|
11
|
+
| Feature | External Projects |
|
|
12
|
+
|---------|-------------------|
|
|
13
|
+
| Angular | 6 - 11 |
|
|
14
|
+
| Build system | Angular CLI (`ng`) |
|
|
15
|
+
| Styling | Project-specific (Bootstrap 4 / custom SCSS) |
|
|
16
|
+
| i18n | ngx-translate + LocalizeRouter |
|
|
17
|
+
| State | NgRx + localStorage sync |
|
|
18
|
+
| Project structure | Standalone (app/cli/docker) |
|
|
19
|
+
|
|
20
|
+
### Patterns (what this plugin supports)
|
|
21
|
+
|
|
22
|
+
| Feature | External (Angular 6-11) | Legacy (Angular 14) | Modern (Angular 20+) |
|
|
23
|
+
|---------|-------------------------|---------------------|----------------------|
|
|
24
|
+
| Control flow | `*ngIf`, `*ngFor` | `*ngIf`, `*ngFor` | `@if`, `@for` |
|
|
25
|
+
| DI | Constructor injection | Constructor injection | `inject()` |
|
|
26
|
+
| Inputs/Outputs | `@Input()`, `@Output()` | `@Input()`, `@Output()` | `input()`, `output()` |
|
|
27
|
+
| State | BehaviorSubject, NgRx | BehaviorSubject | Signals |
|
|
28
|
+
| Components | NgModules | NgModules | Standalone |
|
|
29
|
+
| Styling | Bootstrap 4 / custom SCSS | Tailwind CSS | Tailwind CSS |
|
|
30
|
+
| Build | `ng build` | `nx build` | `nx build` |
|
|
31
|
+
|
|
32
|
+
## Workflow Skills
|
|
33
|
+
|
|
34
|
+
| Skill | Description |
|
|
35
|
+
|-------|-------------|
|
|
36
|
+
| `/commit` | Create conventional commit based on Linear task |
|
|
37
|
+
| `/impl` | Implement plans from Linear task comments |
|
|
38
|
+
| `/plan` | Create implementation plan and save to Linear |
|
|
39
|
+
| `/push` | Push changes and update Linear status |
|
|
40
|
+
|
|
41
|
+
## Installation
|
|
42
|
+
|
|
43
|
+
### 1. Enable plugin in project's `.claude/settings.json`:
|
|
44
|
+
|
|
45
|
+
```json
|
|
46
|
+
{
|
|
47
|
+
"enabledPlugins": {
|
|
48
|
+
"flow-external@smart-pro": true
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### 2. Merge permissions from template
|
|
54
|
+
|
|
55
|
+
Run the merge script:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
node node_modules/@smartsoft001/pro-claude-plugins/plugins/flow-external/.claude-plugin/merge-permissions.js
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Required MCP Servers
|
|
62
|
+
|
|
63
|
+
Configure these in your `.mcp.json`:
|
|
64
|
+
|
|
65
|
+
- `linear` - Linear API integration (MCP prefix `mcp__linear__`)
|
|
66
|
+
- `playwright` - Browser automation for screenshots
|
|
67
|
+
|
|
68
|
+
## Permission Strategy
|
|
69
|
+
|
|
70
|
+
### Automatic (allow)
|
|
71
|
+
- Git read operations (status, diff, log, show)
|
|
72
|
+
- Angular CLI commands (ng build, ng lint, ng serve)
|
|
73
|
+
- Linear API (read/write issues, comments)
|
|
74
|
+
- Playwright (screenshots)
|
|
75
|
+
- Utility skills
|
|
76
|
+
|
|
77
|
+
### Requires Confirmation (ask)
|
|
78
|
+
- Workflow skills (/commit, /impl, /plan, /push)
|
|
79
|
+
- `git commit` - creating commits
|
|
80
|
+
- `git push` - pushing to remote
|
|
81
|
+
- `gh pr create` - creating pull requests
|
|
82
|
+
|
|
83
|
+
## Utility Skills
|
|
84
|
+
|
|
85
|
+
| Skill | Description |
|
|
86
|
+
|-------|-------------|
|
|
87
|
+
| `maia-files-upload` | Upload files to Maia API |
|
|
88
|
+
| `maia-files-delete` | Delete files from Maia API |
|
|
89
|
+
| `browser-capture` | Capture screenshots with Playwright |
|
|
90
|
+
| `linear-suggestion` | Create Linear issues for improvements |
|
|
91
|
+
| `a11y-audit` | Accessibility audit |
|
|
92
|
+
|
|
93
|
+
## Agents
|
|
94
|
+
|
|
95
|
+
### Angular Agents (Legacy CLI patterns)
|
|
96
|
+
- `angular-component-scaffolder` - Components with NgModules, `*ngIf`/`*ngFor`, constructor DI
|
|
97
|
+
- `angular-service-builder` - Services with BehaviorSubject, constructor DI
|
|
98
|
+
- `angular-state-builder` - NgRx state management with reducers and effects
|
|
99
|
+
- `angular-directive-builder` - Directives with constructor DI
|
|
100
|
+
- `angular-pipe-builder` - Pipes with constructor DI
|
|
101
|
+
- `angular-guard-builder` - Class-based guards with constructor DI
|
|
102
|
+
- `angular-resolver-builder` - Class-based resolvers with constructor DI
|
|
103
|
+
|
|
104
|
+
### Shared Agents
|
|
105
|
+
- `shared-impl-orchestrator` - Implementation orchestration
|
|
106
|
+
- `shared-impl-reporter` - Implementation reporting
|
|
107
|
+
- `shared-linear-subtask-iterator` - Linear subtask iteration
|
|
108
|
+
- `shared-build-verifier` - Build verification via `ng build`
|
|
109
|
+
- `shared-ui-classifier` - UI change classification
|
|
110
|
+
- `ui-web-designer` - Styling with project-specific approach (Bootstrap 4 or custom SCSS)
|
|
111
|
+
|
|
112
|
+
## Differences from other plugins
|
|
113
|
+
|
|
114
|
+
| Aspect | `flow` (modern) | `flow-legacy` | `flow-external` |
|
|
115
|
+
|--------|-----------------|---------------|-----------------|
|
|
116
|
+
| Angular version | 20+ | 14 | 6-11 |
|
|
117
|
+
| Build system | Nx | Nx | Angular CLI |
|
|
118
|
+
| Styling | Tailwind | Tailwind | Project-specific |
|
|
119
|
+
| State | Signals | BehaviorSubject | NgRx + BehaviorSubject |
|
|
120
|
+
| Project structure | Nx monorepo | Nx monorepo | Standalone app/ |
|
|
121
|
+
|
|
122
|
+
## Example Project Structure
|
|
123
|
+
|
|
124
|
+
```
|
|
125
|
+
project-root/
|
|
126
|
+
app/ # Frontend Angular application
|
|
127
|
+
src/
|
|
128
|
+
app/
|
|
129
|
+
components/
|
|
130
|
+
services/
|
|
131
|
+
pipes/
|
|
132
|
+
directives/
|
|
133
|
+
interceptors/
|
|
134
|
+
guards/
|
|
135
|
+
state/ # NgRx store
|
|
136
|
+
assets/
|
|
137
|
+
environments/
|
|
138
|
+
angular.json
|
|
139
|
+
package.json
|
|
140
|
+
tsconfig.json
|
|
141
|
+
cli/ # CLI scripts
|
|
142
|
+
frontend-cli
|
|
143
|
+
docker/ # Docker configuration
|
|
144
|
+
Dockerfile
|
|
145
|
+
.env
|
|
146
|
+
```
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Merge flow-external plugin permissions into project's .claude/settings.json
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
* npx @smartsoft001/pro-claude-plugins flow-external:merge-permissions
|
|
7
|
+
*
|
|
8
|
+
* Or directly:
|
|
9
|
+
* node node_modules/@smartsoft001/pro-claude-plugins/plugins/flow-external/.claude-plugin/merge-permissions.js
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const fs = require('fs');
|
|
13
|
+
const path = require('path');
|
|
14
|
+
|
|
15
|
+
const SETTINGS_PATH = path.join(process.cwd(), '.claude', 'settings.json');
|
|
16
|
+
const TEMPLATE_PATH = path.join(__dirname, 'settings.template.json');
|
|
17
|
+
|
|
18
|
+
function loadJson(filePath) {
|
|
19
|
+
try {
|
|
20
|
+
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
|
21
|
+
} catch (e) {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function mergeArrays(existing, template) {
|
|
27
|
+
return [...new Set([...existing, ...template])];
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function main() {
|
|
31
|
+
console.log('Flow-External Plugin - Merge Permissions\n');
|
|
32
|
+
|
|
33
|
+
// Load template
|
|
34
|
+
const template = loadJson(TEMPLATE_PATH);
|
|
35
|
+
if (!template) {
|
|
36
|
+
console.error('ERROR: Could not load template from:', TEMPLATE_PATH);
|
|
37
|
+
process.exit(1);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Load or create settings
|
|
41
|
+
let settings = loadJson(SETTINGS_PATH);
|
|
42
|
+
if (!settings) {
|
|
43
|
+
console.log('Creating new .claude/settings.json...');
|
|
44
|
+
fs.mkdirSync(path.dirname(SETTINGS_PATH), { recursive: true });
|
|
45
|
+
settings = { permissions: { allow: [], deny: [], ask: [] } };
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Ensure permissions structure exists
|
|
49
|
+
settings.permissions = settings.permissions || {
|
|
50
|
+
allow: [],
|
|
51
|
+
deny: [],
|
|
52
|
+
ask: [],
|
|
53
|
+
};
|
|
54
|
+
settings.permissions.allow = settings.permissions.allow || [];
|
|
55
|
+
settings.permissions.ask = settings.permissions.ask || [];
|
|
56
|
+
settings.permissions.deny = settings.permissions.deny || [];
|
|
57
|
+
|
|
58
|
+
// Count before
|
|
59
|
+
const beforeAllow = settings.permissions.allow.length;
|
|
60
|
+
const beforeAsk = settings.permissions.ask.length;
|
|
61
|
+
|
|
62
|
+
// Merge permissions
|
|
63
|
+
settings.permissions.allow = mergeArrays(
|
|
64
|
+
settings.permissions.allow,
|
|
65
|
+
template.permissions.allow,
|
|
66
|
+
);
|
|
67
|
+
settings.permissions.ask = mergeArrays(
|
|
68
|
+
settings.permissions.ask,
|
|
69
|
+
template.permissions.ask,
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
// Enable plugin
|
|
73
|
+
settings.enabledPlugins = settings.enabledPlugins || {};
|
|
74
|
+
settings.enabledPlugins['flow-external@smart-pro'] = true;
|
|
75
|
+
|
|
76
|
+
// Write back
|
|
77
|
+
fs.writeFileSync(SETTINGS_PATH, JSON.stringify(settings, null, 2) + '\n');
|
|
78
|
+
|
|
79
|
+
// Report
|
|
80
|
+
const addedAllow = settings.permissions.allow.length - beforeAllow;
|
|
81
|
+
const addedAsk = settings.permissions.ask.length - beforeAsk;
|
|
82
|
+
|
|
83
|
+
console.log('Permissions merged successfully!\n');
|
|
84
|
+
console.log(
|
|
85
|
+
` allow: ${beforeAllow} -> ${settings.permissions.allow.length} (+${addedAllow})`,
|
|
86
|
+
);
|
|
87
|
+
console.log(
|
|
88
|
+
` ask: ${beforeAsk} -> ${settings.permissions.ask.length} (+${addedAsk})`,
|
|
89
|
+
);
|
|
90
|
+
console.log(`\nPlugin enabled: flow-external@smart-pro`);
|
|
91
|
+
console.log(`\nFile updated: ${SETTINGS_PATH}`);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
main();
|