@ai-support-agent/cli 0.1.32 → 0.1.33-beta.1
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/dist/alert-processor.d.ts +0 -8
- package/dist/alert-processor.d.ts.map +1 -1
- package/dist/alert-processor.js +5 -73
- package/dist/alert-processor.js.map +1 -1
- package/dist/api-client.d.ts +0 -4
- package/dist/api-client.d.ts.map +1 -1
- package/dist/api-client.js +0 -4
- package/dist/api-client.js.map +1 -1
- package/dist/commands/claude-code-args.d.ts +1 -0
- package/dist/commands/claude-code-args.d.ts.map +1 -1
- package/dist/commands/claude-code-args.js +3 -0
- package/dist/commands/claude-code-args.js.map +1 -1
- package/dist/commands/claude-code-runner.d.ts.map +1 -1
- package/dist/commands/claude-code-runner.js +2 -1
- package/dist/commands/claude-code-runner.js.map +1 -1
- package/dist/commands/plugin-dir.d.ts +20 -0
- package/dist/commands/plugin-dir.d.ts.map +1 -0
- package/dist/commands/plugin-dir.js +71 -0
- package/dist/commands/plugin-dir.js.map +1 -0
- package/dist/constants.d.ts +0 -1
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +0 -1
- package/dist/constants.js.map +1 -1
- package/dist/plugin/.claude-plugin/plugin.json +9 -0
- package/dist/plugin/LICENSE +26 -0
- package/dist/plugin/README.md +86 -0
- package/dist/plugin/SYNC.md +113 -0
- package/dist/plugin/agents/build-error-resolver.md +159 -0
- package/dist/plugin/agents/code-reviewer.md +277 -0
- package/dist/plugin/agents/django-reviewer.md +159 -0
- package/dist/plugin/agents/infra-reviewer.md +172 -0
- package/dist/plugin/agents/investigator.md +75 -0
- package/dist/plugin/agents/nextjs-reviewer.md +191 -0
- package/dist/plugin/agents/php-reviewer.md +167 -0
- package/dist/plugin/agents/planner.md +184 -0
- package/dist/plugin/agents/python-reviewer.md +161 -0
- package/dist/plugin/agents/react-reviewer.md +150 -0
- package/dist/plugin/agents/silent-failure-hunter.md +158 -0
- package/dist/plugin/agents/typescript-reviewer.md +179 -0
- package/dist/plugin/agents/ui-reviewer.md +203 -0
- package/dist/plugin/commands/add-feature.md +301 -0
- package/dist/plugin/commands/build-fix.md +47 -0
- package/dist/plugin/commands/code-review.md +228 -0
- package/dist/plugin/commands/fix-defect.md +393 -0
- package/dist/plugin/commands/learn-eval.md +94 -0
- package/dist/plugin/commands/learn.md +84 -0
- package/dist/plugin/commands/plan.md +211 -0
- package/dist/plugin/commands/test-coverage.md +64 -0
- package/dist/plugin/commands/update-docs.md +98 -0
- package/dist/plugin/hooks/hooks.json +59 -0
- package/dist/plugin/hooks/scripts/auto-format.sh +63 -0
- package/dist/plugin/hooks/scripts/check-secrets-before-commit.sh +50 -0
- package/dist/plugin/hooks/scripts/guard-dangerous-commands.sh +55 -0
- package/dist/plugin/hooks/scripts/on-command-resume.sh +112 -0
- package/dist/plugin/hooks/scripts/on-command-stop.sh +200 -0
- package/dist/plugin/hooks/scripts/protect-sensitive-files.sh +58 -0
- package/dist/plugin/rules/common/coding-guidelines.md +73 -0
- package/dist/plugin/rules/documentation/api-docs.md +46 -0
- package/dist/plugin/rules/documentation/docs-site.md +60 -0
- package/dist/plugin/rules/documentation/source-docs.md +89 -0
- package/dist/plugin/rules/documentation/test-docs.md +39 -0
- package/dist/plugin/rules/logging/logging-rules.md +83 -0
- package/dist/plugin/rules/php/coding-rules.md +40 -0
- package/dist/plugin/rules/python/coding-rules.md +40 -0
- package/dist/plugin/rules/typescript/coding-rules.md +45 -0
- package/dist/plugin/skills/api-design/SKILL.md +269 -0
- package/dist/plugin/skills/backend-patterns/SKILL.md +312 -0
- package/dist/plugin/skills/database-migrations/SKILL.md +323 -0
- package/dist/plugin/skills/docker-patterns/SKILL.md +308 -0
- package/dist/plugin/skills/docs-site/SKILL.md +341 -0
- package/dist/plugin/skills/e2e-testing/SKILL.md +334 -0
- package/dist/plugin/skills/frontend-patterns/SKILL.md +318 -0
- package/dist/plugin/skills/integration-testing/SKILL.md +273 -0
- package/package.json +2 -2
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: integration-testing
|
|
3
|
+
description: A collection of integration-testing patterns for verifying actual database reads and writes. Covers the limits of mocking, isolating the test database, transaction rollback, and how to verify constraint violations, optimistic locking, and N+1 queries, for NestJS (TypeORM/Prisma), Django, Flask, Laravel, and CakePHP. Use this when writing or reviewing tests for DB-touching features, when you want to avoid a "green only because it's mocked" false sense of safety, or when designing how DB tests run in CI.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# integration-testing: Integration Testing (DB Read/Write Verification) Patterns
|
|
7
|
+
|
|
8
|
+
## 1. Why Integration Tests Are Necessary (The Limits of Mocking)
|
|
9
|
+
|
|
10
|
+
Unit tests that mock the repository or ORM never verify any of the following:
|
|
11
|
+
|
|
12
|
+
- Correctness of SQL or query-builder output (typo'd column names, wrong JOIN conditions)
|
|
13
|
+
- Consistency with the schema (missing migrations, type mismatches)
|
|
14
|
+
- DB constraint behavior (unique constraints, foreign keys, NOT NULL, CHECK)
|
|
15
|
+
- Transaction boundaries (commit/rollback timing)
|
|
16
|
+
- Optimistic locking and concurrency conflicts
|
|
17
|
+
|
|
18
|
+
### The Classic Trap: Tests Are Green, but the DB Breaks
|
|
19
|
+
|
|
20
|
+
```typescript
|
|
21
|
+
// Bad: the repository is mocked, so a unique-constraint violation is never caught
|
|
22
|
+
it('can register a user', async () => {
|
|
23
|
+
const repo = { save: jest.fn().mockResolvedValue({ id: 1 }) };
|
|
24
|
+
const service = new UserService(repo as any);
|
|
25
|
+
await service.register('taro@example.com');
|
|
26
|
+
await service.register('taro@example.com'); // the mock silently succeeds
|
|
27
|
+
expect(repo.save).toHaveBeenCalledTimes(2); // green, but in production the
|
|
28
|
+
}); // second call hits a unique-constraint 500 error
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
```typescript
|
|
32
|
+
// Good: register against a real DB and verify the behavior on duplicates
|
|
33
|
+
it('throws ConflictException when the email address is duplicated', async () => {
|
|
34
|
+
await service.register('taro@example.com');
|
|
35
|
+
await expect(service.register('taro@example.com'))
|
|
36
|
+
.rejects.toThrow(ConflictException); // confirms constraint-violation handling against a real DB
|
|
37
|
+
});
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
As long as the mocked `save` keeps returning success, the test stays green forever — and a unit test will never catch "the second registration fails on the DB's unique constraint" or "the service layer never converts that exception into the right HTTP error." Those are exactly the failures that show up in production.
|
|
41
|
+
|
|
42
|
+
## 2. Dividing Responsibilities Across Test Layers
|
|
43
|
+
|
|
44
|
+
| Layer | Target | DB | Responsibility |
|
|
45
|
+
|---|---|---|---|
|
|
46
|
+
| Unit | Pure logic (calculations, transforms, validation) | Not used | Branch coverage, edge cases |
|
|
47
|
+
| Integration | Repository/service layer, queries | Real DB | Correctness of DB-touching code |
|
|
48
|
+
| E2E | Business flows through the UI/API | Real DB (production-like) | User-facing scenarios |
|
|
49
|
+
|
|
50
|
+
- Verifying DB-touching code is the responsibility of integration tests. Pushing that burden onto E2E tests makes them slow and flaky.
|
|
51
|
+
- For E2E test structure and waiting strategies, see the e2e-testing skill.
|
|
52
|
+
|
|
53
|
+
## 3. Core Principles for DB Testing
|
|
54
|
+
|
|
55
|
+
### 3.1 Isolate the Test Database
|
|
56
|
+
|
|
57
|
+
Never share the development database. Test runs will destroy data if you do, so use a dedicated database (e.g. `myapp_test`) or a disposable container. Switch the connection target via environment variables, and verify "this is really the test connection" at test startup to prevent accidents.
|
|
58
|
+
|
|
59
|
+
### 3.2 Keep Tests Independent of Each Other
|
|
60
|
+
|
|
61
|
+
No test may depend on data left behind by a previous test. There are two cleanup strategies:
|
|
62
|
+
|
|
63
|
+
- **Transaction rollback**: wrap each test in a transaction and roll it back at the end. Fast — but it can't verify code paths where the code under test explicitly commits, uses a separate connection, or relies on nested transactions.
|
|
64
|
+
- **Truncate/recreate**: truncate all tables between tests. Slower, but it also works for logic that involves an actual commit (i.e. testing the transaction boundary itself).
|
|
65
|
+
|
|
66
|
+
Rule of thumb: default to the rollback strategy, and switch to truncation only for the specific tests that verify transaction behavior or post-commit hooks.
|
|
67
|
+
|
|
68
|
+
### 3.3 Use the Same DB Engine as Production (the SQLite-Substitute Trap)
|
|
69
|
+
|
|
70
|
+
"Let's just use SQLite for speed" is a reliable source of both false positives and false negatives.
|
|
71
|
+
|
|
72
|
+
- **Loose typing**: SQLite will happily store 100 characters in a `VARCHAR(10)`. Length-overflow bugs go undetected.
|
|
73
|
+
- **Constraints**: foreign keys are disabled by default, and CHECK constraints and some unique-constraint behaviors differ from production engines.
|
|
74
|
+
- **Functions and SQL dialect**: differences in `ILIKE`, `ON CONFLICT`, window functions, and date functions mean things break only in production, or only in tests.
|
|
75
|
+
- **Locking behavior**: SQLite locks the whole database rather than individual rows, so concurrency and deadlock tests can't meaningfully run against it.
|
|
76
|
+
|
|
77
|
+
Use Testcontainers or Docker Compose to spin up the same PostgreSQL/MySQL you run in production. The few seconds of startup cost is easily absorbed by reusing one container per test suite.
|
|
78
|
+
|
|
79
|
+
### 3.4 Mock External APIs, but Never Mock the Database
|
|
80
|
+
|
|
81
|
+
The boundary for an integration test is: "things we own are real, things we don't own can be mocked." Payment gateways, email delivery, and external SaaS can reasonably be mocked (or stubbed). The database, however, is the very thing whose schema and constraints you're trying to verify — so it must never be mocked.
|
|
82
|
+
|
|
83
|
+
## 4. What You Must Always Test
|
|
84
|
+
|
|
85
|
+
1. **Read-back after write**: read the saved value back through a separate path (a repository `find`, or raw SQL) and confirm what was actually persisted. Checking only the return value of `save` will miss values that never made it to the DB — lost conversions, missing column mappings, and the like.
|
|
86
|
+
2. **Behavior on constraint violations**: deliberately trigger unique-constraint, foreign-key, and NOT NULL violations, and confirm the application layer converts them into the right exception or error response.
|
|
87
|
+
3. **Transaction atomicity**: force a failure partway through a multi-table update (e.g. the second of two writes violates a constraint), then read back the first write to confirm it was rolled back too.
|
|
88
|
+
4. **Concurrency and optimistic locking**: fetch a versioned entity in two separate contexts, update one first, then update the other, and confirm a conflict exception is raised.
|
|
89
|
+
5. **Complex queries**: for JOINs, aggregations, and pagination, insert real data that includes boundary conditions and verify the results (zero rows, exact page boundaries, stable sort ordering on duplicate keys).
|
|
90
|
+
6. **N+1 detection**: assert on the query count, confirming that listing endpoints don't issue a number of queries proportional to the row count.
|
|
91
|
+
|
|
92
|
+
## 5. Stack-Specific Implementation Patterns
|
|
93
|
+
|
|
94
|
+
### 5.1 NestJS + TypeORM (Testcontainers)
|
|
95
|
+
|
|
96
|
+
```typescript
|
|
97
|
+
// Good: spin up a real PostgreSQL via Testcontainers and verify against the real repository
|
|
98
|
+
import { PostgreSqlContainer, StartedPostgreSqlContainer } from '@testcontainers/postgresql';
|
|
99
|
+
|
|
100
|
+
let container: StartedPostgreSqlContainer;
|
|
101
|
+
let module: TestingModule;
|
|
102
|
+
|
|
103
|
+
beforeAll(async () => {
|
|
104
|
+
container = await new PostgreSqlContainer('postgres:16').start();
|
|
105
|
+
module = await Test.createTestingModule({
|
|
106
|
+
imports: [
|
|
107
|
+
TypeOrmModule.forRoot({
|
|
108
|
+
type: 'postgres',
|
|
109
|
+
url: container.getConnectionUri(),
|
|
110
|
+
entities: [User, Order],
|
|
111
|
+
migrations: ['migrations/*.ts'],
|
|
112
|
+
migrationsRun: true, // apply real migrations instead of `synchronize`
|
|
113
|
+
}),
|
|
114
|
+
UserModule, // use the real repository, not a mock
|
|
115
|
+
],
|
|
116
|
+
}).compile();
|
|
117
|
+
}, 60_000);
|
|
118
|
+
|
|
119
|
+
afterEach(async () => {
|
|
120
|
+
// truncate strategy: needed because this suite tests transaction boundaries
|
|
121
|
+
await module.get(DataSource).query('TRUNCATE "user", "order" CASCADE');
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it('rolls back the stock decrement when order confirmation fails partway through', async () => {
|
|
125
|
+
const service = module.get(OrderService);
|
|
126
|
+
await expect(service.confirm(orderWithInvalidItem)).rejects.toThrow();
|
|
127
|
+
const stock = await module.get(DataSource).getRepository(Stock).findOneBy({ sku: 'A' });
|
|
128
|
+
expect(stock.quantity).toBe(10); // the first decrement was rolled back too
|
|
129
|
+
});
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### 5.2 NestJS + Prisma
|
|
133
|
+
|
|
134
|
+
```typescript
|
|
135
|
+
// Good: point DATABASE_URL at the container and run `prisma migrate deploy`
|
|
136
|
+
beforeAll(async () => {
|
|
137
|
+
container = await new PostgreSqlContainer('postgres:16').start();
|
|
138
|
+
process.env.DATABASE_URL = container.getConnectionUri();
|
|
139
|
+
execSync('npx prisma migrate deploy'); // build the schema from real migrations
|
|
140
|
+
prisma = new PrismaClient();
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it('reads back a saved value', async () => {
|
|
144
|
+
await service.createUser({ email: 'taro@example.com', name: 'Taro' });
|
|
145
|
+
// read back directly from the DB instead of trusting the return value of save
|
|
146
|
+
const row = await prisma.user.findUnique({ where: { email: 'taro@example.com' } });
|
|
147
|
+
expect(row?.name).toBe('Taro');
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
it('catches a unique-constraint violation as P2002 and handles it', async () => {
|
|
151
|
+
await service.createUser({ email: 'a@example.com', name: 'A' });
|
|
152
|
+
await expect(service.createUser({ email: 'a@example.com', name: 'B' }))
|
|
153
|
+
.rejects.toThrow(ConflictException);
|
|
154
|
+
});
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### 5.3 Django + pytest-django
|
|
158
|
+
|
|
159
|
+
```python
|
|
160
|
+
# Good: the django_db mark uses a real DB; by default each test is rolled back afterward
|
|
161
|
+
import pytest
|
|
162
|
+
|
|
163
|
+
@pytest.mark.django_db
|
|
164
|
+
def test_read_back_after_save():
|
|
165
|
+
Order.objects.create(code="A-001", total=1000)
|
|
166
|
+
row = Order.objects.get(code="A-001")
|
|
167
|
+
assert row.total == 1000
|
|
168
|
+
|
|
169
|
+
# Use transaction=True (equivalent to TransactionTestCase) when testing the
|
|
170
|
+
# transaction boundary itself — select_for_update and on_commit hooks only work here
|
|
171
|
+
@pytest.mark.django_db(transaction=True)
|
|
172
|
+
def test_full_rollback_on_partial_failure():
|
|
173
|
+
with pytest.raises(IntegrityError):
|
|
174
|
+
place_order_with_invalid_item()
|
|
175
|
+
assert Stock.objects.get(sku="A").quantity == 10
|
|
176
|
+
|
|
177
|
+
# N+1 detection: assert on the query count
|
|
178
|
+
def test_listing_uses_2_queries_regardless_of_row_count(django_assert_num_queries):
|
|
179
|
+
OrderFactory.create_batch(20)
|
|
180
|
+
with django_assert_num_queries(2): # pins down the effect of select_related / prefetch_related
|
|
181
|
+
list_orders_with_items()
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Rule of thumb: default to `@pytest.mark.django_db` (the fast rollback strategy). `transaction=True` actually commits, so it's slower — reserve it for the specific tests that need it.
|
|
185
|
+
|
|
186
|
+
### 5.4 Flask + pytest (SQLAlchemy)
|
|
187
|
+
|
|
188
|
+
```python
|
|
189
|
+
# Good: share one PostgreSQL container for the whole session, and roll back after each test
|
|
190
|
+
@pytest.fixture(scope="session")
|
|
191
|
+
def engine():
|
|
192
|
+
with PostgresContainer("postgres:16") as pg:
|
|
193
|
+
engine = create_engine(pg.get_connection_url())
|
|
194
|
+
run_migrations(engine) # apply the real schema via Alembic
|
|
195
|
+
yield engine
|
|
196
|
+
|
|
197
|
+
@pytest.fixture
|
|
198
|
+
def db_session(engine):
|
|
199
|
+
conn = engine.connect()
|
|
200
|
+
trans = conn.begin()
|
|
201
|
+
session = Session(bind=conn, join_transaction_mode="create_savepoint")
|
|
202
|
+
yield session # even if the code under test commits, it stays inside the savepoint
|
|
203
|
+
session.close()
|
|
204
|
+
trans.rollback() # the independence between tests is guaranteed by the outer transaction
|
|
205
|
+
conn.close()
|
|
206
|
+
|
|
207
|
+
def test_foreign_key_violation_becomes_400(client, db_session):
|
|
208
|
+
res = client.post("/orders", json={"user_id": 9999}) # a user that doesn't exist
|
|
209
|
+
assert res.status_code == 400 # confirms IntegrityError is converted, not swallowed
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### 5.5 Laravel + PHPUnit
|
|
213
|
+
|
|
214
|
+
```php
|
|
215
|
+
// Good: RefreshDatabase wraps each test in a transaction and rolls it back quickly
|
|
216
|
+
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
217
|
+
|
|
218
|
+
class OrderTest extends TestCase
|
|
219
|
+
{
|
|
220
|
+
use RefreshDatabase;
|
|
221
|
+
|
|
222
|
+
public function test_saved_value_is_persisted_to_the_database(): void
|
|
223
|
+
{
|
|
224
|
+
$user = User::factory()->create();
|
|
225
|
+
$this->postJson('/api/orders', ['user_id' => $user->id, 'total' => 1000])
|
|
226
|
+
->assertCreated();
|
|
227
|
+
// Good: use assertDatabaseHas to verify the actual data in the DB
|
|
228
|
+
$this->assertDatabaseHas('orders', ['user_id' => $user->id, 'total' => 1000]);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
public function test_duplicate_registration_returns_409(): void
|
|
232
|
+
{
|
|
233
|
+
User::factory()->create(['email' => 'taro@example.com']);
|
|
234
|
+
$this->postJson('/api/users', ['email' => 'taro@example.com'])
|
|
235
|
+
->assertStatus(409);
|
|
236
|
+
$this->assertDatabaseCount('users', 1); // also confirm no extra row was created
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
Note: pin the connection in `phpunit.xml` to the test database. Don't swap in SQLite's `:memory:` — that reintroduces the trap described in 3.3. If production runs MySQL, test against a MySQL container.
|
|
242
|
+
|
|
243
|
+
### 5.6 CakePHP + PHPUnit
|
|
244
|
+
|
|
245
|
+
```php
|
|
246
|
+
// Good: manage tables and data via fixtures against the `test` connection
|
|
247
|
+
class OrdersTableTest extends TestCase
|
|
248
|
+
{
|
|
249
|
+
protected array $fixtures = ['app.Orders', 'app.Users']; // loaded into the test connection
|
|
250
|
+
|
|
251
|
+
public function test_total_aggregation_query_is_correct(): void
|
|
252
|
+
{
|
|
253
|
+
$orders = $this->getTableLocator()->get('Orders');
|
|
254
|
+
$total = $orders->find()->where(['user_id' => 1])->sumOf('total');
|
|
255
|
+
$this->assertSame(3000, $total); // expected value is derived from the fixture data
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
Define a dedicated database under `Datasources.test` in `config/app_local.php`. It's worth verifying in your test bootstrap that this isn't accidentally pointing at the same database as the default connection.
|
|
261
|
+
|
|
262
|
+
## 6. Running in CI
|
|
263
|
+
|
|
264
|
+
- **Starting the DB container**: on GitHub Actions, either define it under `services:` (PostgreSQL/MySQL) or run Testcontainers directly (requires a runner with Docker available). Wait for a health check (e.g. `pg_isready`) before starting the tests.
|
|
265
|
+
- **Applying migrations**: always run real migrations before the test suite. Relying on `synchronize` or schema auto-generation means you can't detect missing migrations.
|
|
266
|
+
- **DB isolation under parallel execution**: assign each worker its own database. For Jest, suffix the DB name with `JEST_WORKER_ID`; for pytest-xdist, split by worker ID such as `gw0` (pytest-django appends a suffix automatically). If you can't isolate databases, fall back to serial execution (e.g. `--runInBand`).
|
|
267
|
+
- **Debugging CI-only failures**: if a test only fails in CI, suspect insufficient container-startup waiting, database sharing under parallel execution, or timezone/locale differences.
|
|
268
|
+
|
|
269
|
+
## 7. Related
|
|
270
|
+
|
|
271
|
+
- Overall test-layer picture and how to write E2E tests: the e2e-testing skill
|
|
272
|
+
- Measuring coverage and finding gaps: `/test-coverage`
|
|
273
|
+
- Reviewing test code: the code-reviewer subagent
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ai-support-agent/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.33-beta.1",
|
|
4
4
|
"description": "AI Support Agent CLI client",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
],
|
|
31
31
|
"scripts": {
|
|
32
32
|
"dev": "node --env-file-if-exists=.env --require ts-node/register src/index.ts",
|
|
33
|
-
"build": "tsc && cp -r src/locales dist/locales",
|
|
33
|
+
"build": "tsc && cp -r src/locales dist/locales && cp -r src/plugin dist/plugin && chmod +x dist/plugin/hooks/scripts/*.sh",
|
|
34
34
|
"prepublishOnly": "npm run build && npm test",
|
|
35
35
|
"test": "jest",
|
|
36
36
|
"test:cov": "jest --coverage",
|