opencode-skills-collection 4.0.54 → 4.0.55
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/bundled-skills/.antigravity-install-manifest.json +1 -1
- package/bundled-skills/antigravity-maintainer-batch-release/SKILL.md +10 -1
- package/bundled-skills/backend-security-coder/resources/implementation-playbook.md +23 -0
- package/bundled-skills/business-analyst/resources/implementation-playbook.md +23 -0
- package/bundled-skills/devops-troubleshooter/resources/implementation-playbook.md +23 -0
- package/bundled-skills/distributed-tracing/SKILL.md +22 -435
- package/bundled-skills/distributed-tracing/references/instrumentation.md +13 -0
- package/bundled-skills/distributed-tracing/references/jaeger-setup.md +13 -0
- package/bundled-skills/distributed-tracing/resources/implementation-playbook.md +23 -0
- package/bundled-skills/django-pro/resources/implementation-playbook.md +23 -0
- package/bundled-skills/embedding-strategies/SKILL.md +40 -64
- package/bundled-skills/embedding-strategies/resources/implementation-playbook.md +23 -0
- package/bundled-skills/fastapi-pro/resources/implementation-playbook.md +23 -0
- package/bundled-skills/find-complementary-founders/scripts/assess_profile.py +7 -1
- package/bundled-skills/frontend-security-coder/SKILL.md +5 -5
- package/bundled-skills/frontend-security-coder/resources/implementation-playbook.md +23 -0
- package/bundled-skills/github-actions-templates/SKILL.md +34 -314
- package/bundled-skills/github-actions-templates/references/common-workflows.md +13 -0
- package/bundled-skills/github-actions-templates/resources/implementation-playbook.md +23 -0
- package/bundled-skills/google-docs-automation/SKILL.md +19 -69
- package/bundled-skills/google-sheets-automation/SKILL.md +20 -128
- package/bundled-skills/google-slides-automation/SKILL.md +19 -128
- package/bundled-skills/grafana-dashboards/SKILL.md +6 -6
- package/bundled-skills/grafana-dashboards/references/dashboard-design.md +13 -0
- package/bundled-skills/grafana-dashboards/resources/implementation-playbook.md +23 -0
- package/bundled-skills/incident-responder/resources/implementation-playbook.md +23 -0
- package/bundled-skills/instagram/scripts/config.py +33 -8
- package/bundled-skills/ios-developer/resources/implementation-playbook.md +23 -0
- package/bundled-skills/junta-leiloeiros/scripts/.snyk +5 -0
- package/bundled-skills/junta-leiloeiros/scripts/requirements.txt +2 -0
- package/bundled-skills/kpi-dashboard-design/SKILL.md +7 -67
- package/bundled-skills/kpi-dashboard-design/resources/implementation-playbook.md +23 -0
- package/bundled-skills/kpi-dashboard-design/resources/metric-queries.sql +30 -0
- package/bundled-skills/lint-and-validate/SKILL.md +17 -45
- package/bundled-skills/lint-and-validate/scripts/lint_runner.py +17 -8
- package/bundled-skills/lint-and-validate/scripts/type_coverage.py +77 -167
- package/bundled-skills/mobile-developer/resources/implementation-playbook.md +23 -0
- package/bundled-skills/multi-platform-apps-multi-platform/resources/implementation-playbook.md +23 -0
- package/bundled-skills/notebooklm/scripts/config.py +33 -11
- package/bundled-skills/observability-and-instrumentation/SKILL.md +4 -1
- package/bundled-skills/observability-and-instrumentation/references/observability-checklist.md +13 -0
- package/bundled-skills/pci-compliance/SKILL.md +23 -469
- package/bundled-skills/pci-compliance/resources/implementation-playbook.md +23 -0
- package/bundled-skills/postmortem-writing/SKILL.md +1 -1
- package/bundled-skills/postmortem-writing/resources/implementation-playbook.md +23 -0
- package/bundled-skills/pydantic-models-py/SKILL.md +1 -3
- package/bundled-skills/secrets-management/SKILL.md +24 -349
- package/bundled-skills/secrets-management/references/github-secrets.md +13 -0
- package/bundled-skills/secrets-management/references/vault-setup.md +13 -0
- package/bundled-skills/security-and-hardening/SKILL.md +8 -6
- package/bundled-skills/security-and-hardening/references/security-checklist.md +13 -0
- package/bundled-skills/seo-content-planner/resources/implementation-playbook.md +23 -0
- package/bundled-skills/seo-content-writer/SKILL.md +2 -2
- package/bundled-skills/seo-content-writer/resources/implementation-playbook.md +23 -0
- package/bundled-skills/shopify-development/scripts/.snyk +3 -0
- package/bundled-skills/slack-gif-creator/.snyk +5 -0
- package/bundled-skills/slack-gif-creator/requirements.txt +2 -2
- package/bundled-skills/slo-implementation/SKILL.md +24 -9
- package/bundled-skills/slo-implementation/references/error-budget.md +13 -0
- package/bundled-skills/slo-implementation/references/slo-definitions.md +13 -0
- package/bundled-skills/slo-implementation/resources/implementation-playbook.md +23 -0
- package/bundled-skills/sql-optimization-patterns/SKILL.md +10 -6
- package/bundled-skills/sql-optimization-patterns/resources/implementation-playbook.md +52 -56
- package/bundled-skills/telegram/assets/boilerplate/nodejs/package-lock.json +1888 -0
- package/bundled-skills/telegram/assets/boilerplate/nodejs/package.json +3 -0
- package/bundled-skills/vector-database-engineer/resources/implementation-playbook.md +23 -0
- package/bundled-skills/videodb/scripts/ws_listener.py +8 -1
- package/bundled-skills/whatsapp-cloud-api/assets/boilerplate/nodejs/package-lock.json +1881 -0
- package/bundled-skills/whatsapp-cloud-api/assets/boilerplate/nodejs/package.json +3 -0
- package/bundled-skills/whatsapp-cloud-api/assets/boilerplate/python/.snyk +3 -0
- package/package.json +1 -1
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Native iOS implementation
|
|
2
|
+
|
|
3
|
+
## Inputs
|
|
4
|
+
|
|
5
|
+
Xcode/Swift versions, deployment target, project scheme, feature brief and available simulator/device.
|
|
6
|
+
|
|
7
|
+
## Procedure
|
|
8
|
+
|
|
9
|
+
1. Reuse the project's state and navigation architecture. Check API availability against the deployment target before adding platform features.
|
|
10
|
+
2. Implement loading, success, failure and cancellation paths. Keep UI state changes on the appropriate actor and credentials in the project's secure storage abstraction.
|
|
11
|
+
3. Build the actual scheme and test navigation, Dynamic Type, VoiceOver labels and interrupted network requests. State separately which checks used a simulator and which used hardware.
|
|
12
|
+
|
|
13
|
+
## Worked example
|
|
14
|
+
|
|
15
|
+
Add a document list with retry. Leaving the screen during loading must not update a disposed view; large text must keep the retry action reachable.
|
|
16
|
+
|
|
17
|
+
## Verification and handoff
|
|
18
|
+
|
|
19
|
+
Report the actual files or configuration changed, checks performed, observed results and any untested environment. Keep the original inputs and evidence sufficient to reproduce the conclusion.
|
|
20
|
+
|
|
21
|
+
## Limitations
|
|
22
|
+
|
|
23
|
+
Simulator success does not verify signing, push delivery, biometrics or App Store acceptance. Do not upload or distribute without authorization.
|
|
@@ -251,71 +251,10 @@ Efficiency:
|
|
|
251
251
|
|
|
252
252
|
### SQL for KPI Calculations
|
|
253
253
|
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
DATE_TRUNC('month', billing_date) AS month,
|
|
259
|
-
SUM(
|
|
260
|
-
CASE subscription_interval
|
|
261
|
-
WHEN 'monthly' THEN amount
|
|
262
|
-
WHEN 'yearly' THEN amount / 12
|
|
263
|
-
WHEN 'quarterly' THEN amount / 3
|
|
264
|
-
END
|
|
265
|
-
) AS mrr
|
|
266
|
-
FROM subscriptions
|
|
267
|
-
WHERE status = 'active'
|
|
268
|
-
GROUP BY DATE_TRUNC('month', billing_date)
|
|
269
|
-
)
|
|
270
|
-
SELECT
|
|
271
|
-
month,
|
|
272
|
-
mrr,
|
|
273
|
-
LAG(mrr) OVER (ORDER BY month) AS prev_mrr,
|
|
274
|
-
(mrr - LAG(mrr) OVER (ORDER BY month)) / LAG(mrr) OVER (ORDER BY month) * 100 AS growth_pct
|
|
275
|
-
FROM mrr_calculation;
|
|
276
|
-
|
|
277
|
-
-- Cohort Retention
|
|
278
|
-
WITH cohorts AS (
|
|
279
|
-
SELECT
|
|
280
|
-
user_id,
|
|
281
|
-
DATE_TRUNC('month', created_at) AS cohort_month
|
|
282
|
-
FROM users
|
|
283
|
-
),
|
|
284
|
-
activity AS (
|
|
285
|
-
SELECT
|
|
286
|
-
user_id,
|
|
287
|
-
DATE_TRUNC('month', event_date) AS activity_month
|
|
288
|
-
FROM user_events
|
|
289
|
-
WHERE event_type = 'active_session'
|
|
290
|
-
)
|
|
291
|
-
SELECT
|
|
292
|
-
c.cohort_month,
|
|
293
|
-
EXTRACT(MONTH FROM age(a.activity_month, c.cohort_month)) AS months_since_signup,
|
|
294
|
-
COUNT(DISTINCT a.user_id) AS active_users,
|
|
295
|
-
COUNT(DISTINCT a.user_id)::FLOAT / COUNT(DISTINCT c.user_id) * 100 AS retention_rate
|
|
296
|
-
FROM cohorts c
|
|
297
|
-
LEFT JOIN activity a ON c.user_id = a.user_id
|
|
298
|
-
AND a.activity_month >= c.cohort_month
|
|
299
|
-
GROUP BY c.cohort_month, EXTRACT(MONTH FROM age(a.activity_month, c.cohort_month))
|
|
300
|
-
ORDER BY c.cohort_month, months_since_signup;
|
|
301
|
-
|
|
302
|
-
-- Customer Acquisition Cost (CAC)
|
|
303
|
-
SELECT
|
|
304
|
-
DATE_TRUNC('month', acquired_date) AS month,
|
|
305
|
-
SUM(marketing_spend) / NULLIF(COUNT(new_customers), 0) AS cac,
|
|
306
|
-
SUM(marketing_spend) AS total_spend,
|
|
307
|
-
COUNT(new_customers) AS customers_acquired
|
|
308
|
-
FROM (
|
|
309
|
-
SELECT
|
|
310
|
-
DATE_TRUNC('month', u.created_at) AS acquired_date,
|
|
311
|
-
u.id AS new_customers,
|
|
312
|
-
m.spend AS marketing_spend
|
|
313
|
-
FROM users u
|
|
314
|
-
JOIN marketing_spend m ON DATE_TRUNC('month', u.created_at) = m.month
|
|
315
|
-
WHERE u.source = 'marketing'
|
|
316
|
-
) acquisition
|
|
317
|
-
GROUP BY DATE_TRUNC('month', acquired_date);
|
|
318
|
-
```
|
|
254
|
+
Use `resources/metric-queries.sql` for executable normalized-input examples. `users` contains one row per customer, `events` contains user/month observations, `spend` contains source spend rows, and `monthly_revenue` contains one reconciled amount per month. Represent months as an integer year × 12 + month − 1 so offsets do not wrap after December.
|
|
255
|
+
|
|
256
|
+
The queries keep the original cohort denominator, deduplicate activity before counting, aggregate spend before joining customers, and return NULL for undefined growth or acquisition cost. Missing cohort/month combinations need an explicit reporting calendar if zero-activity rows must be displayed. Normalize subscription intervals, currency, refunds and revenue recognition before producing monthly revenue; these examples do not define accounting policy.
|
|
257
|
+
|
|
319
258
|
|
|
320
259
|
### Python Dashboard Code (Streamlit)
|
|
321
260
|
|
|
@@ -327,7 +266,8 @@ import plotly.graph_objects as go
|
|
|
327
266
|
|
|
328
267
|
st.set_page_config(page_title="KPI Dashboard", layout="wide")
|
|
329
268
|
|
|
330
|
-
#
|
|
269
|
+
# Synthetic layout illustration; this is not a connected or filterable dashboard.
|
|
270
|
+
# Header with illustrative date selector
|
|
331
271
|
col1, col2 = st.columns([3, 1])
|
|
332
272
|
with col1:
|
|
333
273
|
st.title("Executive Dashboard")
|
|
@@ -363,7 +303,7 @@ col1, col2 = st.columns(2)
|
|
|
363
303
|
with col1:
|
|
364
304
|
st.subheader("Revenue Trend")
|
|
365
305
|
revenue_data = pd.DataFrame({
|
|
366
|
-
'Month': pd.date_range('2024-01-01', periods=12, freq='
|
|
306
|
+
'Month': pd.date_range('2024-01-01', periods=12, freq='ME'),
|
|
367
307
|
'Revenue': [180000, 195000, 210000, 225000, 240000, 255000,
|
|
368
308
|
270000, 285000, 300000, 315000, 330000, 345000]
|
|
369
309
|
})
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# KPI dashboard verification
|
|
2
|
+
|
|
3
|
+
## Inputs
|
|
4
|
+
|
|
5
|
+
Decision, audience, reporting grain, source tables, metric owner and period definitions.
|
|
6
|
+
|
|
7
|
+
## Procedure
|
|
8
|
+
|
|
9
|
+
1. Define each metric's numerator, denominator, exclusions, unit and freshness. Keep cohort size independent from later activity and aggregate spend before joining to customers.
|
|
10
|
+
2. Build a small reconciliation table with hand-calculated results, zero denominators, duplicate events and cohorts older than twelve months.
|
|
11
|
+
3. Connect every card and chart to the selected date range. Distinguish missing data from zero; show whether higher or lower is better and verify drill-down totals.
|
|
12
|
+
|
|
13
|
+
## Worked example
|
|
14
|
+
|
|
15
|
+
A cohort has ten customers and four return in month thirteen. Retention is 40% at month 13, not 100% at month 1. Keep that fixture alongside the query.
|
|
16
|
+
|
|
17
|
+
## Verification and handoff
|
|
18
|
+
|
|
19
|
+
Report the actual files or configuration changed, checks performed, observed results and any untested environment. Keep the original inputs and evidence sufficient to reproduce the conclusion.
|
|
20
|
+
|
|
21
|
+
## Limitations
|
|
22
|
+
|
|
23
|
+
Example dashboards use synthetic data. A visually correct dashboard is not proof that its financial or attribution definitions are valid.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
-- Inputs are normalized month_index integers, one user per id, and spend rows at source grain.
|
|
2
|
+
-- query: retention
|
|
3
|
+
WITH cohort_sizes AS (
|
|
4
|
+
SELECT cohort_month, COUNT(*) AS cohort_size FROM users GROUP BY cohort_month
|
|
5
|
+
), active AS (
|
|
6
|
+
SELECT DISTINCT u.cohort_month, e.month_index - u.cohort_month AS month_offset, u.id
|
|
7
|
+
FROM users u JOIN events e ON e.user_id = u.id
|
|
8
|
+
WHERE e.month_index >= u.cohort_month
|
|
9
|
+
)
|
|
10
|
+
SELECT a.cohort_month, a.month_offset, COUNT(*) AS active_users,
|
|
11
|
+
100.0 * COUNT(*) / c.cohort_size AS retention_pct
|
|
12
|
+
FROM active a JOIN cohort_sizes c ON c.cohort_month = a.cohort_month
|
|
13
|
+
GROUP BY a.cohort_month, a.month_offset, c.cohort_size;
|
|
14
|
+
-- query: cac
|
|
15
|
+
WITH spend_by_month AS (
|
|
16
|
+
SELECT month_index, SUM(amount) AS spend FROM spend GROUP BY month_index
|
|
17
|
+
), acquired AS (
|
|
18
|
+
SELECT cohort_month AS month_index, COUNT(*) AS customers
|
|
19
|
+
FROM users WHERE source = 'marketing' GROUP BY cohort_month
|
|
20
|
+
)
|
|
21
|
+
SELECT s.month_index, s.spend, COALESCE(a.customers, 0) AS customers,
|
|
22
|
+
1.0 * s.spend / NULLIF(a.customers, 0) AS cac
|
|
23
|
+
FROM spend_by_month s LEFT JOIN acquired a ON a.month_index = s.month_index;
|
|
24
|
+
-- query: growth
|
|
25
|
+
WITH previous AS (
|
|
26
|
+
SELECT month_index, amount, LAG(amount) OVER (ORDER BY month_index) AS previous_amount
|
|
27
|
+
FROM monthly_revenue
|
|
28
|
+
)
|
|
29
|
+
SELECT month_index, amount, 100.0 * (amount - previous_amount) / NULLIF(previous_amount, 0) AS growth_pct
|
|
30
|
+
FROM previous;
|
|
@@ -1,62 +1,34 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: lint-and-validate
|
|
3
|
-
description: "
|
|
3
|
+
description: "Run configured lint and type checks, distinguish failures from checks that did not run, and report concrete validation results."
|
|
4
4
|
risk: critical
|
|
5
5
|
source: community
|
|
6
6
|
date_added: "2026-02-27"
|
|
7
7
|
---
|
|
8
8
|
|
|
9
|
-
# Lint and Validate
|
|
9
|
+
# Lint and Validate
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
### Procedures by Ecosystem
|
|
14
|
-
|
|
15
|
-
#### Node.js / TypeScript
|
|
16
|
-
1. **Lint/Fix:** `npm run lint` or `npx eslint "path" --fix`
|
|
17
|
-
2. **Types:** `npx tsc --noEmit`
|
|
18
|
-
3. **Security:** `npm audit --audit-level=high`
|
|
19
|
-
|
|
20
|
-
#### Python
|
|
21
|
-
1. **Linter (Ruff):** `ruff check "path" --fix` (Fast & Modern)
|
|
22
|
-
2. **Security (Bandit):** `bandit -r "path" -ll`
|
|
23
|
-
3. **Types (MyPy):** `mypy "path"`
|
|
24
|
-
|
|
25
|
-
## The Quality Loop
|
|
26
|
-
1. **Write/Edit Code**
|
|
27
|
-
2. **Run Audit** for the project's ecosystem:
|
|
28
|
-
- **Node.js / TypeScript:** `npm run lint && npx tsc --noEmit`
|
|
29
|
-
- **Python:** `ruff check . --fix && mypy . && bandit -r . -ll`
|
|
30
|
-
3. **Analyze Report:** Check the "FINAL AUDIT REPORT" section.
|
|
31
|
-
4. **Fix & Repeat:** Submitting code with "FINAL AUDIT" failures is NOT allowed.
|
|
32
|
-
|
|
33
|
-
## Error Handling
|
|
34
|
-
- If `lint` fails: Fix the style or syntax issues immediately.
|
|
35
|
-
- If `tsc` fails: Correct type mismatches before proceeding.
|
|
36
|
-
- If no tool is configured: Check the project root for `.eslintrc`, `tsconfig.json`, `pyproject.toml` and suggest creating one.
|
|
37
|
-
|
|
38
|
-
---
|
|
39
|
-
**Strict Rule:** No code should be committed or reported as "done" without passing these checks.
|
|
40
|
-
|
|
41
|
-
---
|
|
11
|
+
## When to Use
|
|
42
12
|
|
|
43
|
-
|
|
13
|
+
Use after behavior or configuration changes when a repository has relevant lint or type checks. Read the repository's instructions and package scripts first. Run focused checks during development and the required checks before completion.
|
|
44
14
|
|
|
45
|
-
|
|
46
|
-
|--------|---------|---------|
|
|
47
|
-
| `scripts/lint_runner.py` | Unified lint check | `python scripts/lint_runner.py <project_path>` |
|
|
48
|
-
| `scripts/type_coverage.py` | Type coverage analysis | `python scripts/type_coverage.py <project_path>` |
|
|
15
|
+
## Procedure
|
|
49
16
|
|
|
50
|
-
|
|
51
|
-
|
|
17
|
+
1. Identify the changed languages, configured commands, and installed tools. Inspect package scripts before executing them: a script named `lint` can modify files or run arbitrary project code.
|
|
18
|
+
2. Run the project's read-only lint/type-check commands. For Node projects, prefer declared scripts such as `npm run lint` and `npm run typecheck`. Do not use `npx` to silently fetch an absent checker.
|
|
19
|
+
3. For Python, use configured, already installed tools such as `ruff check .` or `mypy .`. Do not assume every `pyproject.toml` configures both. Never add `--fix` without inspecting the proposed changes and the task's authorization.
|
|
20
|
+
4. Fix relevant failures without deleting user work, weakening rules, or raising timeouts just to pass. If a required tool is unavailable, report the exact check that did not run.
|
|
21
|
+
5. Report commands, exit results, scope and remaining limitations. Passing lint does not prove the absence of runtime or security defects.
|
|
52
22
|
|
|
53
23
|
## Example
|
|
54
24
|
|
|
55
|
-
|
|
25
|
+
After correcting a TypeScript behavior, inspect `package.json`, run the configured focused regression test, then `npm run lint` and `npm run typecheck` if those scripts exist. If TypeScript is declared but not installed, report the missing local checker; do not substitute a downloaded package or call the result a pass.
|
|
26
|
+
|
|
27
|
+
## Bundled helpers
|
|
56
28
|
|
|
57
|
-
|
|
29
|
+
- `python scripts/lint_runner.py /absolute/project`: runs a conservative set of candidate checks. Node fallback checkers must exist in local `node_modules/.bin`; Python candidates must be installed. Inspect the project scripts first. A missing command or failing check exits 1; no configured checks or invalid project metadata exits 2. Exit 0 means the invoked checks passed, not that every needed check was discovered. Python detection is heuristic and may suggest unconfigured Ruff/MyPy commands.
|
|
30
|
+
- `python scripts/type_coverage.py /absolute/project`: read-only annotation inventory, despite its retained compatibility filename. Samples at most 30 files per language, skips links and build/dependency directories, and bounds file reads. Python uses AST nodes to avoid double-counting functions. TypeScript reports lexical `: any` occurrences, including possible comments and strings. No quality percentage or pass/fail threshold is inferred. Exit 2 means no applicable files; parse/read errors exit 1.
|
|
58
31
|
|
|
59
32
|
## Limitations
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
- Stop and ask for clarification if required inputs, permissions, safety boundaries, or success criteria are missing.
|
|
33
|
+
|
|
34
|
+
The runner executes trusted project commands, which may mutate files or access the network. It does not install dependencies, detect every monorepo configuration, or replace the project's CI contract. The inventory is a bounded source sample, not semantic type coverage; inferred types, generics, decorator behavior and correctness require the actual type checker. Do not label unrun checks as successful.
|
|
@@ -7,13 +7,14 @@ Usage:
|
|
|
7
7
|
python lint_runner.py <project_path>
|
|
8
8
|
|
|
9
9
|
Supports:
|
|
10
|
-
- Node.js: npm run lint,
|
|
10
|
+
- Node.js: npm run lint, installed local tsc --noEmit
|
|
11
11
|
- Python: ruff check, mypy
|
|
12
12
|
"""
|
|
13
13
|
|
|
14
14
|
import subprocess
|
|
15
15
|
import sys
|
|
16
16
|
import json
|
|
17
|
+
import os
|
|
17
18
|
from pathlib import Path
|
|
18
19
|
from datetime import datetime
|
|
19
20
|
|
|
@@ -44,14 +45,14 @@ def detect_project_type(project_path: Path) -> dict:
|
|
|
44
45
|
if "lint" in scripts:
|
|
45
46
|
result["linters"].append({"name": "npm lint", "cmd": ["npm", "run", "lint"]})
|
|
46
47
|
elif "eslint" in deps:
|
|
47
|
-
result["linters"].append({"name": "eslint", "cmd": ["
|
|
48
|
+
result["linters"].append({"name": "eslint", "cmd": [str(project_path / "node_modules" / ".bin" / ("eslint.cmd" if os.name == "nt" else "eslint")), "."]})
|
|
48
49
|
|
|
49
50
|
# Check for TypeScript
|
|
50
51
|
if "typescript" in deps or (project_path / "tsconfig.json").exists():
|
|
51
|
-
result["linters"].append({"name": "tsc", "cmd": ["
|
|
52
|
+
result["linters"].append({"name": "tsc", "cmd": [str(project_path / "node_modules" / ".bin" / ("tsc.cmd" if os.name == "nt" else "tsc")), "--noEmit"]})
|
|
52
53
|
|
|
53
|
-
except:
|
|
54
|
-
|
|
54
|
+
except (OSError, ValueError, TypeError, AttributeError) as error:
|
|
55
|
+
raise ValueError(f"Cannot inspect package.json: {error}") from error
|
|
55
56
|
|
|
56
57
|
# Python project
|
|
57
58
|
if (project_path / "pyproject.toml").exists() or (project_path / "requirements.txt").exists():
|
|
@@ -111,7 +112,14 @@ def main():
|
|
|
111
112
|
print(f"Time: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
|
|
112
113
|
|
|
113
114
|
# Detect project type
|
|
114
|
-
|
|
115
|
+
if not project_path.is_dir():
|
|
116
|
+
print("Project directory does not exist.", file=sys.stderr)
|
|
117
|
+
sys.exit(2)
|
|
118
|
+
try:
|
|
119
|
+
project_info = detect_project_type(project_path)
|
|
120
|
+
except ValueError as error:
|
|
121
|
+
print(str(error), file=sys.stderr)
|
|
122
|
+
sys.exit(2)
|
|
115
123
|
print(f"Type: {project_info['type']}")
|
|
116
124
|
print(f"Linters: {len(project_info['linters'])}")
|
|
117
125
|
print("-"*60)
|
|
@@ -123,11 +131,12 @@ def main():
|
|
|
123
131
|
"project": str(project_path),
|
|
124
132
|
"type": project_info["type"],
|
|
125
133
|
"checks": [],
|
|
126
|
-
"passed":
|
|
134
|
+
"passed": False,
|
|
135
|
+
"status": "not-checked",
|
|
127
136
|
"message": "No linters configured"
|
|
128
137
|
}
|
|
129
138
|
print(json.dumps(output, indent=2))
|
|
130
|
-
sys.exit(
|
|
139
|
+
sys.exit(2)
|
|
131
140
|
|
|
132
141
|
# Run each linter
|
|
133
142
|
results = []
|
|
@@ -1,173 +1,83 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
|
-
"""
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
import sys
|
|
7
|
-
import re
|
|
8
|
-
import subprocess
|
|
2
|
+
"""Bounded annotation inventory, not type coverage or a type-safety verdict."""
|
|
3
|
+
import ast
|
|
4
|
+
import json
|
|
5
|
+
import os
|
|
9
6
|
from pathlib import Path
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
# Find functions without return types
|
|
39
|
-
# function name(params) { - no return type
|
|
40
|
-
untyped = re.findall(r'function\s+\w+\s*\([^)]*\)\s*{', content)
|
|
41
|
-
# Arrow functions without types: const fn = (x) => or (x) =>
|
|
42
|
-
untyped += re.findall(r'=\s*\([^:)]*\)\s*=>', content)
|
|
43
|
-
stats['untyped_functions'] += len(untyped)
|
|
44
|
-
|
|
45
|
-
# Count typed functions
|
|
46
|
-
typed = re.findall(r'function\s+\w+\s*\([^)]*\)\s*:\s*\w+', content)
|
|
47
|
-
typed += re.findall(r':\s*\([^)]*\)\s*=>\s*\w+', content)
|
|
48
|
-
stats['total_functions'] += len(typed) + len(untyped)
|
|
49
|
-
|
|
50
|
-
except Exception:
|
|
51
|
-
continue
|
|
52
|
-
|
|
53
|
-
# Analyze results
|
|
54
|
-
if stats['any_count'] == 0:
|
|
55
|
-
passed.append("[OK] No 'any' types found")
|
|
56
|
-
elif stats['any_count'] <= 5:
|
|
57
|
-
issues.append(f"[!] {stats['any_count']} 'any' types found (acceptable)")
|
|
58
|
-
else:
|
|
59
|
-
issues.append(f"[X] {stats['any_count']} 'any' types found (too many)")
|
|
60
|
-
|
|
61
|
-
if stats['total_functions'] > 0:
|
|
62
|
-
typed_ratio = (stats['total_functions'] - stats['untyped_functions']) / stats['total_functions'] * 100
|
|
63
|
-
if typed_ratio >= 80:
|
|
64
|
-
passed.append(f"[OK] Type coverage: {typed_ratio:.0f}%")
|
|
65
|
-
elif typed_ratio >= 50:
|
|
66
|
-
issues.append(f"[!] Type coverage: {typed_ratio:.0f}% (improve)")
|
|
67
|
-
else:
|
|
68
|
-
issues.append(f"[X] Type coverage: {typed_ratio:.0f}% (too low)")
|
|
69
|
-
|
|
70
|
-
passed.append(f"[OK] Analyzed {len(ts_files)} TypeScript files")
|
|
71
|
-
|
|
72
|
-
return {'type': 'typescript', 'files': len(ts_files), 'passed': passed, 'issues': issues, 'stats': stats}
|
|
73
|
-
|
|
74
|
-
def check_python_coverage(project_path: Path) -> dict:
|
|
75
|
-
"""Check Python type hints coverage."""
|
|
76
|
-
issues = []
|
|
77
|
-
passed = []
|
|
78
|
-
stats = {'untyped_functions': 0, 'typed_functions': 0, 'any_count': 0}
|
|
79
|
-
|
|
80
|
-
py_files = list(project_path.rglob("*.py"))
|
|
81
|
-
py_files = [f for f in py_files if not any(x in str(f) for x in ['venv', '__pycache__', '.git', 'node_modules'])]
|
|
82
|
-
|
|
83
|
-
if not py_files:
|
|
84
|
-
return {'type': 'python', 'files': 0, 'passed': [], 'issues': ["[!] No Python files found"], 'stats': stats}
|
|
85
|
-
|
|
86
|
-
for file_path in py_files[:30]: # Limit
|
|
7
|
+
import re
|
|
8
|
+
import sys
|
|
9
|
+
import stat
|
|
10
|
+
|
|
11
|
+
MAX_FILES = 30
|
|
12
|
+
MAX_BYTES = 1_000_000
|
|
13
|
+
SKIP = {'.git', 'node_modules', 'venv', '.venv', '__pycache__', 'dist', 'build'}
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def source_files(root, suffixes):
|
|
17
|
+
"""Yield a deterministic sample without following directory or file links."""
|
|
18
|
+
for directory, dirs, files in os.walk(root, followlinks=False):
|
|
19
|
+
dirs[:] = sorted(name for name in dirs if name not in SKIP and not (Path(directory) / name).is_symlink())
|
|
20
|
+
for name in sorted(files):
|
|
21
|
+
path = Path(directory) / name
|
|
22
|
+
if path.suffix in suffixes and not path.name.endswith('.d.ts') and not path.is_symlink():
|
|
23
|
+
yield path
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def inventory(project_path, language):
|
|
27
|
+
result = {'type': language, 'files': 0, 'sample_limit': MAX_FILES, 'truncated': False, 'errors': [], 'stats': {}}
|
|
28
|
+
stats = result['stats']
|
|
29
|
+
stats.update({'functions': 0, 'fully_annotated_functions': 0} if language == 'python' else {'explicit_any_text_matches': 0})
|
|
30
|
+
for index, path in enumerate(source_files(project_path, {'.py'} if language == 'python' else {'.ts', '.tsx'})):
|
|
31
|
+
if index == MAX_FILES:
|
|
32
|
+
result['truncated'] = True
|
|
33
|
+
break
|
|
87
34
|
try:
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
else:
|
|
122
|
-
issues.append(f"[X] {stats['any_count']} 'Any' types found")
|
|
35
|
+
flags = os.O_RDONLY | getattr(os, 'O_NOFOLLOW', 0) | getattr(os, 'O_NONBLOCK', 0)
|
|
36
|
+
fd = os.open(path, flags)
|
|
37
|
+
with os.fdopen(fd, 'rb') as handle:
|
|
38
|
+
if not stat.S_ISREG(os.fstat(handle.fileno()).st_mode):
|
|
39
|
+
raise ValueError('source is not a regular file')
|
|
40
|
+
raw = handle.read(MAX_BYTES + 1)
|
|
41
|
+
if len(raw) > MAX_BYTES:
|
|
42
|
+
raise ValueError('source exceeds byte limit')
|
|
43
|
+
text = raw.decode('utf-8')
|
|
44
|
+
if language == 'python':
|
|
45
|
+
tree = ast.parse(text)
|
|
46
|
+
for node in ast.walk(tree):
|
|
47
|
+
if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)):
|
|
48
|
+
stats['functions'] += 1
|
|
49
|
+
args = node.args.posonlyargs + node.args.args + node.args.kwonlyargs
|
|
50
|
+
args += [arg for arg in (node.args.vararg, node.args.kwarg) if arg]
|
|
51
|
+
annotated = node.returns is not None and all(arg.annotation is not None for arg in args)
|
|
52
|
+
stats['fully_annotated_functions'] += int(annotated)
|
|
53
|
+
else:
|
|
54
|
+
# This includes comments/string literals and misses inferred/aliased any.
|
|
55
|
+
stats['explicit_any_text_matches'] += len(re.findall(r':\s*any\b', text))
|
|
56
|
+
result['files'] += 1
|
|
57
|
+
except (OSError, UnicodeError, ValueError, SyntaxError) as error:
|
|
58
|
+
result['errors'].append({'file': str(path.relative_to(project_path)), 'error': str(error)})
|
|
59
|
+
return result
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def check_python_coverage(project_path):
|
|
63
|
+
return inventory(project_path, 'python')
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def check_typescript_coverage(project_path):
|
|
67
|
+
return inventory(project_path, 'typescript')
|
|
123
68
|
|
|
124
|
-
passed.append(f"[OK] Analyzed {len(py_files)} Python files")
|
|
125
|
-
|
|
126
|
-
return {'type': 'python', 'files': len(py_files), 'passed': passed, 'issues': issues, 'stats': stats}
|
|
127
69
|
|
|
128
70
|
def main():
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
print(
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
# Check Python
|
|
144
|
-
py_result = check_python_coverage(project_path)
|
|
145
|
-
if py_result['files'] > 0:
|
|
146
|
-
results.append(py_result)
|
|
147
|
-
|
|
148
|
-
if not results:
|
|
149
|
-
print("[!] No TypeScript or Python files found.")
|
|
150
|
-
sys.exit(0)
|
|
151
|
-
|
|
152
|
-
# Print results
|
|
153
|
-
critical_issues = 0
|
|
154
|
-
for result in results:
|
|
155
|
-
print(f"\n[{result['type'].upper()}]")
|
|
156
|
-
print("-" * 40)
|
|
157
|
-
for item in result['passed']:
|
|
158
|
-
print(f" {item}")
|
|
159
|
-
for item in result['issues']:
|
|
160
|
-
print(f" {item}")
|
|
161
|
-
if item.startswith("[X]"):
|
|
162
|
-
critical_issues += 1
|
|
163
|
-
|
|
164
|
-
print("\n" + "=" * 60)
|
|
165
|
-
if critical_issues == 0:
|
|
166
|
-
print("[OK] TYPE COVERAGE: ACCEPTABLE")
|
|
167
|
-
sys.exit(0)
|
|
168
|
-
else:
|
|
169
|
-
print(f"[X] TYPE COVERAGE: {critical_issues} critical issues")
|
|
170
|
-
sys.exit(1)
|
|
171
|
-
|
|
172
|
-
if __name__ == "__main__":
|
|
173
|
-
main()
|
|
71
|
+
root = Path(sys.argv[1] if len(sys.argv) > 1 else '.').resolve()
|
|
72
|
+
if not root.is_dir():
|
|
73
|
+
print('Project directory does not exist.', file=sys.stderr)
|
|
74
|
+
return 2
|
|
75
|
+
results = [inventory(root, language) for language in ('python', 'typescript')]
|
|
76
|
+
print(json.dumps({'kind': 'annotation-inventory', 'limitation': 'Not type coverage. Annotations do not establish correctness; TypeScript counts are lexical. Run the configured type checker.', 'results': results}, indent=2))
|
|
77
|
+
if any(result['errors'] for result in results):
|
|
78
|
+
return 1
|
|
79
|
+
return 0 if any(result['files'] for result in results) else 2
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
if __name__ == '__main__':
|
|
83
|
+
sys.exit(main())
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Mobile feature delivery
|
|
2
|
+
|
|
3
|
+
## Inputs
|
|
4
|
+
|
|
5
|
+
Existing stack/version, target OS range, device access, offline requirements and API contract.
|
|
6
|
+
|
|
7
|
+
## Procedure
|
|
8
|
+
|
|
9
|
+
1. Use the existing framework and define platform-specific exceptions. Model loading, failed requests, permission denial and offline edits explicitly.
|
|
10
|
+
2. Implement the shared behavior behind tested adapters. Bound retries and define duplicate/conflict handling before queueing writes for reconnection.
|
|
11
|
+
3. Run the feature on each available target, checking background/foreground transitions, network loss, keyboard, accessibility and persistent state after restart.
|
|
12
|
+
|
|
13
|
+
## Worked example
|
|
14
|
+
|
|
15
|
+
An offline note is edited twice and synced after reconnecting. Verify one intended final record, a visible conflict policy and no duplicated submission.
|
|
16
|
+
|
|
17
|
+
## Verification and handoff
|
|
18
|
+
|
|
19
|
+
Report the actual files or configuration changed, checks performed, observed results and any untested environment. Keep the original inputs and evidence sufficient to reproduce the conclusion.
|
|
20
|
+
|
|
21
|
+
## Limitations
|
|
22
|
+
|
|
23
|
+
A cross-platform build does not prove feature parity on untested devices. Store submission and signing remain separate authorized actions.
|
package/bundled-skills/multi-platform-apps-multi-platform/resources/implementation-playbook.md
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Cross-platform parity playbook
|
|
2
|
+
|
|
3
|
+
## Inputs
|
|
4
|
+
|
|
5
|
+
Requested platforms, shared API contract, existing stacks, feature acceptance criteria and available tools.
|
|
6
|
+
|
|
7
|
+
## Procedure
|
|
8
|
+
|
|
9
|
+
1. Define behavior as observable scenarios, not a percentage of shared code. Record intentional platform differences before implementation.
|
|
10
|
+
2. Implement shared contracts first, then platform adapters. Use available tools directly; agent role names in the main guide describe responsibilities and do not guarantee a delegation API exists.
|
|
11
|
+
3. Maintain a matrix of scenario, platform, observed result and evidence. Check offline conflict handling, permission denial and accessible navigation separately for each target.
|
|
12
|
+
|
|
13
|
+
## Worked example
|
|
14
|
+
|
|
15
|
+
A saved item must appear on web and mobile after synchronization. Test add, delete, retry and a conflicting edit on both platforms; identify any platform not exercised.
|
|
16
|
+
|
|
17
|
+
## Verification and handoff
|
|
18
|
+
|
|
19
|
+
Report the actual files or configuration changed, checks performed, observed results and any untested environment. Keep the original inputs and evidence sufficient to reproduce the conclusion.
|
|
20
|
+
|
|
21
|
+
## Limitations
|
|
22
|
+
|
|
23
|
+
Do not install every framework or manufacture parallel agents. Packaging, store upload and production deployment require the relevant authorization.
|