bms-speckit-plugin 6.3.0 → 6.3.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.
|
@@ -232,80 +232,73 @@ Search for `.github/workflows/*.yml`, `.gitlab-ci.yml`, `Jenkinsfile`, etc. For
|
|
|
232
232
|
|
|
233
233
|
> **Skip this phase entirely if the project has no SQL statements (no .sql files, no SQL strings in source code).**
|
|
234
234
|
|
|
235
|
-
|
|
235
|
+
**Philosophy: write SQL once, run on both.** All SQL must use syntax that works identically on MySQL and PostgreSQL without runtime database-type detection or dialect branching. Do NOT introduce `if (dialect === 'mysql')` patterns — instead, always use the ANSI SQL or cross-compatible form.
|
|
236
236
|
|
|
237
237
|
### G1. Identifier Quoting
|
|
238
238
|
|
|
239
|
-
|
|
240
|
-
- Fix: Replace with double quotes `"table_name"` (ANSI SQL, works on both) or remove quoting if identifiers don't need escaping
|
|
241
|
-
- If using an ORM, prefer the ORM's quoting mechanism instead of raw quoting
|
|
239
|
+
Grep for backtick-quoted identifiers (MySQL-only). Fix by removing quoting entirely (preferred) or replacing with ANSI double quotes. If using an ORM, prefer the ORM's quoting mechanism.
|
|
242
240
|
|
|
243
241
|
### G2. Data Types
|
|
244
242
|
|
|
245
|
-
Grep SQL files and SQL strings in source code for database-specific types:
|
|
246
|
-
|
|
247
|
-
|
|
|
248
|
-
|
|
249
|
-
| `TINYINT(1)` for booleans | `BOOLEAN` |
|
|
250
|
-
| `AUTO_INCREMENT`
|
|
251
|
-
| `DOUBLE` | `DOUBLE PRECISION` |
|
|
252
|
-
| `DATETIME` | `TIMESTAMP` |
|
|
253
|
-
| `TINYINT`, `MEDIUMINT` |
|
|
254
|
-
| `LONGTEXT`, `MEDIUMTEXT`, `TINYTEXT` |
|
|
255
|
-
| `LONGBLOB`, `MEDIUMBLOB`, `TINYBLOB
|
|
256
|
-
| `ENUM('a','b')`
|
|
257
|
-
| `UNSIGNED` |
|
|
258
|
-
| `
|
|
259
|
-
|
|
260
|
-
### G3. SQL Syntax
|
|
261
|
-
|
|
262
|
-
Grep for
|
|
263
|
-
|
|
264
|
-
|
|
|
265
|
-
|
|
266
|
-
|
|
|
267
|
-
|
|
|
268
|
-
|
|
|
269
|
-
|
|
|
270
|
-
|
|
|
271
|
-
|
|
|
272
|
-
|
|
|
273
|
-
|
|
|
274
|
-
|
|
|
275
|
-
|
|
|
276
|
-
|
|
|
277
|
-
|
|
|
278
|
-
|
|
|
279
|
-
|
|
|
280
|
-
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
1. **
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
const upsertSQL = dialect === 'mysql'
|
|
305
|
-
? 'INSERT INTO t (...) VALUES (?) ON DUPLICATE KEY UPDATE ...'
|
|
306
|
-
: 'INSERT INTO t (...) VALUES ($1) ON CONFLICT (...) DO UPDATE ...';
|
|
307
|
-
```
|
|
308
|
-
2. **Document exceptions** — If a query intentionally uses dialect-specific syntax, it must have a comment explaining which database it targets and why cross-compatibility isn't possible.
|
|
243
|
+
Grep SQL files and SQL strings in source code for database-specific types. Replace with the cross-compatible form:
|
|
244
|
+
|
|
245
|
+
| Flag this | Replace with |
|
|
246
|
+
|---|---|
|
|
247
|
+
| `TINYINT(1)` for booleans | `BOOLEAN` |
|
|
248
|
+
| `AUTO_INCREMENT` or `SERIAL` | ORM-managed auto-increment identity column |
|
|
249
|
+
| `DOUBLE` | `DOUBLE PRECISION` |
|
|
250
|
+
| `DATETIME` | `TIMESTAMP` |
|
|
251
|
+
| `TINYINT`, `MEDIUMINT` | `SMALLINT` or `INTEGER` |
|
|
252
|
+
| `LONGTEXT`, `MEDIUMTEXT`, `TINYTEXT` | `TEXT` |
|
|
253
|
+
| `LONGBLOB`, `MEDIUMBLOB`, `TINYBLOB`, `BYTEA` | ORM binary type or `BLOB`/`BYTEA` handled by ORM layer |
|
|
254
|
+
| `ENUM('a','b')` or `CREATE TYPE AS ENUM` | `VARCHAR` + `CHECK` constraint or application-level validation |
|
|
255
|
+
| `UNSIGNED` | Remove; use `CHECK (col >= 0)` if needed |
|
|
256
|
+
| `JSONB` | `JSON` (works on both; index optimization is a deployment concern, not a code concern) |
|
|
257
|
+
|
|
258
|
+
### G3. SQL Syntax — Always Use the Cross-Compatible Form
|
|
259
|
+
|
|
260
|
+
Grep for database-specific syntax. Every match must be replaced with the form that runs on both MySQL and PostgreSQL without modification:
|
|
261
|
+
|
|
262
|
+
| Flag this | Replace with (works on both) |
|
|
263
|
+
|---|---|
|
|
264
|
+
| `LIMIT 10, 20` (MySQL offset syntax) | `LIMIT 20 OFFSET 10` |
|
|
265
|
+
| `IFNULL(a, b)` | `COALESCE(a, b)` |
|
|
266
|
+
| `IF(cond, a, b)` | `CASE WHEN cond THEN a ELSE b END` |
|
|
267
|
+
| `a \|\| b` for string concat (PG-only when sql_mode strict) | `CONCAT(a, b)` |
|
|
268
|
+
| `DATEDIFF(a, b)` (MySQL) or `a - b` interval (PG) | `EXTRACT(DAY FROM (a - b))` or ORM date math |
|
|
269
|
+
| `DATE_FORMAT(d, '%Y-%m-%d')` (MySQL) or `TO_CHAR(d, 'YYYY-MM-DD')` (PG) | ORM date formatting function |
|
|
270
|
+
| `GROUP_CONCAT(col)` (MySQL) or `STRING_AGG(col, ',')` (PG) | ORM aggregate or application-level concatenation |
|
|
271
|
+
| `ON DUPLICATE KEY UPDATE` (MySQL) | ORM upsert method (most ORMs abstract this) |
|
|
272
|
+
| `INSERT IGNORE` (MySQL) | ORM upsert with ignore/skip-duplicate option |
|
|
273
|
+
| `ON CONFLICT ... DO UPDATE` (PG-only) | ORM upsert method |
|
|
274
|
+
| `REGEXP` / `RLIKE` (MySQL) or `~` / `~*` (PG) | Application-level regex or ORM pattern matching |
|
|
275
|
+
| `1`/`0` for booleans | `TRUE`/`FALSE` |
|
|
276
|
+
| `SHOW TABLES`, `DESCRIBE table`, `SHOW COLUMNS` | `SELECT FROM information_schema.tables` / `information_schema.columns` |
|
|
277
|
+
| `\\d table`, `\\dt` (PG CLI commands) | `information_schema` queries |
|
|
278
|
+
| `\\'` backslash string escape | `''` (ANSI double single-quote) |
|
|
279
|
+
| `NOW()` | `CURRENT_TIMESTAMP` (ANSI standard; `NOW()` also works on both but `CURRENT_TIMESTAMP` is more portable) |
|
|
280
|
+
| `::type` PostgreSQL cast syntax | `CAST(expr AS type)` (ANSI SQL) |
|
|
281
|
+
|
|
282
|
+
### G4. ORM and Raw SQL
|
|
283
|
+
|
|
284
|
+
1. **Prefer ORM abstractions** — For operations that have no single cross-compatible SQL form (upsert, date formatting, group concat, regex), the ORM's built-in method is the correct solution. It generates the right SQL per dialect automatically.
|
|
285
|
+
|
|
286
|
+
2. **Raw SQL must be cross-compatible** — Any raw SQL string (ORM raw queries, migration files, seed files) must use only the cross-compatible forms listed above. No exceptions — if a raw query can't be written cross-compatibly, it must be replaced with an ORM call.
|
|
287
|
+
|
|
288
|
+
3. **Migration files** — Check all migration files for dialect-specific DDL. Replace `AUTO_INCREMENT`, backtick quoting, MySQL-specific types, and PG-specific types with cross-compatible alternatives or ORM schema methods.
|
|
289
|
+
|
|
290
|
+
4. **Placeholder syntax** — Use the ORM's parameterization. If writing raw parameterized SQL, use named parameters (`:id`) which most ORMs translate per dialect, rather than `?` (MySQL) or `$1` (PG) which are dialect-specific.
|
|
291
|
+
|
|
292
|
+
### G5. No Dialect Branching
|
|
293
|
+
|
|
294
|
+
**Do NOT accept or introduce patterns like:**
|
|
295
|
+
- `if (dialect === 'mysql') { sql = '...' } else { sql = '...' }`
|
|
296
|
+
- `config.database.type === 'postgres' ? pgQuery : mysqlQuery`
|
|
297
|
+
- Separate `.mysql.sql` and `.postgres.sql` files
|
|
298
|
+
|
|
299
|
+
If code like this already exists, refactor it to use the single cross-compatible form or an ORM method. The goal is one SQL statement that runs on both databases identically.
|
|
300
|
+
|
|
301
|
+
**Only exception:** ORM configuration that specifies the connection dialect (e.g., Sequelize `dialect`, Django `ENGINE`, SQLAlchemy connection URL). This is infrastructure config, not SQL branching.
|
|
309
302
|
|
|
310
303
|
**Output Format:**
|
|
311
304
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bms-speckit-plugin",
|
|
3
|
-
"version": "6.3.
|
|
3
|
+
"version": "6.3.1",
|
|
4
4
|
"description": "Chain-orchestrated development pipeline: /bms-speckit takes requirements and runs brainstorm → constitution → specify → plan → tasks → analyze → implement → verify with per-step error handling",
|
|
5
5
|
"files": [
|
|
6
6
|
".claude-plugin/",
|
|
@@ -205,7 +205,7 @@ After the subagent completes, update tasks 1-8 as completed using TaskUpdate, th
|
|
|
205
205
|
- **D. Accessibility** — alt text, form labels, keyboard nav, heading hierarchy
|
|
206
206
|
- **E. Integration check** — verify all components work together end-to-end
|
|
207
207
|
- **F. Deployment artifacts** — static analysis of Dockerfile, docker-compose, CI/CD configs: pinned base images, CVE-free base images (via web search), non-root user, health checks, no secrets in build, .dockerignore coverage (skipped if no deployment files exist)
|
|
208
|
-
- **G. Database compatibility** —
|
|
208
|
+
- **G. Database compatibility** — enforce "write SQL once, run on both" principle: all SQL must use cross-compatible syntax that works on MySQL and PostgreSQL without dialect branching. Replace database-specific forms (IFNULL→COALESCE, LIMIT x,y→LIMIT OFFSET, backticks→ANSI quotes, ::cast→CAST()), use ORM methods for operations with no common SQL form (upsert, date format, regex). No `if dialect` patterns allowed. (skipped if no SQL in project)
|
|
209
209
|
- The agent fixes everything it can. Major dependency updates are flagged for user review.
|
|
210
210
|
- **Completion rule:** When the QC agent returns its report, proceed to Step 12 **unless** the report contains unfixed build errors, unfixed test failures, or unfixed critical security vulnerabilities. Informational findings, flagged-for-review items, and already-fixed issues do NOT block progression. If uncertain, proceed — the QC agent already fixed what it could.
|
|
211
211
|
- **Post-action:** Commit all fixes and push. Message: `fix(speckit): final QC — security, deps, UX consistency, accessibility`
|