@nitra/cursor 12.8.5 → 12.8.7
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/CHANGELOG.md +12 -0
- package/bin/n-cursor.js +5 -5
- package/package.json +1 -1
- package/rules/abie/js/http_route_base.mdc +25 -0
- package/rules/abie/js/ua_http_route.mdc +1 -1
- package/rules/abie/main.mdc +12 -0
- package/rules/adr/js/hooks.mdc +32 -0
- package/rules/adr/js/madr_format.mdc +96 -0
- package/rules/adr/js/settings_policy.mdc +34 -0
- package/rules/adr/main.mdc +13 -95
- package/rules/bun/js/bunfig.mdc +12 -0
- package/rules/bun/js/layout.mdc +60 -0
- package/rules/bun/js/lint.mdc +9 -0
- package/rules/bun/js/package_json.mdc +19 -0
- package/rules/bun/main.mdc +9 -61
- package/rules/capacitor/js/ios_spm.mdc +69 -0
- package/rules/capacitor/js/version.mdc +29 -0
- package/rules/capacitor/main.mdc +8 -22
- package/rules/changelog/js/agent-workflow.mdc +15 -0
- package/rules/changelog/js/changelog-format.mdc +33 -0
- package/rules/changelog/js/comparison-models.mdc +40 -0
- package/rules/changelog/main.mdc +4 -98
- package/rules/ci4/js/marksman_config.mdc +31 -0
- package/rules/ci4/js/vscode_extensions.mdc +33 -0
- package/rules/ci4/main.mdc +14 -14
- package/rules/docker/js/compile.mdc +44 -0
- package/rules/docker/js/hadolint.mdc +50 -0
- package/rules/docker/js/mirror.mdc +13 -0
- package/rules/docker/js/multistage.mdc +13 -0
- package/rules/docker/js/native-addon.mdc +43 -0
- package/rules/docker/js/nginx-tag.mdc +7 -0
- package/rules/docker/js/nginx-user.mdc +37 -0
- package/rules/docker/js/non-root.mdc +39 -0
- package/rules/docker/main.mdc +15 -196
- package/rules/ga/js/lint_toolchain.mdc +15 -0
- package/rules/ga/js/required_workflows.mdc +35 -0
- package/rules/ga/js/vscode.mdc +17 -0
- package/rules/ga/js/workflow_common.mdc +108 -0
- package/rules/ga/js/workflows.mdc +32 -0
- package/rules/ga/js/zizmor.mdc +7 -0
- package/rules/ga/main.mdc +17 -125
- package/rules/graphql/js/tooling.mdc +13 -0
- package/rules/graphql/js/vscode_extensions.mdc +13 -0
- package/rules/graphql/main.mdc +3 -22
- package/rules/hasura/js/internal_urls.mdc +27 -0
- package/rules/hasura/js/migrations.mdc +13 -0
- package/rules/hasura/js/svc_hl.mdc +17 -0
- package/rules/hasura/main.mdc +8 -30
- package/rules/image-avif/js/avif_generation.mdc +26 -0
- package/rules/image-avif/js/package_json_optout.mdc +21 -0
- package/rules/image-avif/main.mdc +7 -34
- package/rules/image-compress/js/package_json.mdc +7 -0
- package/rules/image-compress/js/package_setup.mdc +13 -0
- package/rules/image-compress/main.mdc +4 -12
- package/rules/js/docs/index.md +3 -3
- package/rules/js/js/dep-policy.mdc +17 -0
- package/rules/js/js/eslint-config.mdc +28 -0
- package/rules/js/js/extensions.mdc +8 -0
- package/rules/js/js/file-extensions.mdc +12 -0
- package/rules/js/js/for-in.mdc +26 -0
- package/rules/js/js/jscpd.mdc +42 -0
- package/rules/js/js/knip.mdc +15 -0
- package/rules/js/js/lint-js-workflow.mdc +58 -0
- package/rules/js/js/oxlintrc.mdc +20 -0
- package/rules/js/js/package-json.mdc +31 -0
- package/rules/js/js/tests.mdc +9 -0
- package/rules/js/js/utils-lib-structure.mdc +15 -0
- package/rules/js/main.mdc +21 -214
- package/rules/js-bun-db/js/bun-sql-migration.mdc +15 -0
- package/rules/js-bun-db/js/connection.mdc +42 -0
- package/rules/js-bun-db/js/pg-format-identifiers.mdc +102 -0
- package/rules/js-bun-db/js/pg-format-shim.mdc +99 -0
- package/rules/js-bun-db/js/pg-leftover.mdc +27 -0
- package/rules/js-bun-db/js/pg-listen-notify.mdc +51 -0
- package/rules/js-bun-db/js/query-safety.mdc +117 -0
- package/rules/js-bun-db/js/sql-array.mdc +88 -0
- package/rules/js-bun-db/js/unsafe.mdc +65 -0
- package/rules/js-bun-db/main.mdc +15 -605
- package/rules/js-bun-redis/js/imports.mdc +47 -0
- package/rules/js-bun-redis/js/package_json.mdc +44 -0
- package/rules/js-bun-redis/main.mdc +3 -11
- package/rules/js-mssql/js/mssql-in-list.mdc +38 -0
- package/rules/js-mssql/js/mssql-pool.mdc +56 -0
- package/rules/js-mssql/js/mssql-query-template.mdc +33 -0
- package/rules/js-mssql/js/mssql-tvp.mdc +75 -0
- package/rules/js-mssql/js/mssql-version.mdc +7 -0
- package/rules/js-mssql/main.mdc +10 -198
- package/rules/js-run/js/check-env.mdc +35 -0
- package/rules/js-run/js/conn-aliases.mdc +109 -0
- package/rules/js-run/js/jsconfig.mdc +20 -0
- package/rules/js-run/js/otel-configmap.mdc +6 -0
- package/rules/js-run/js/pino.mdc +6 -0
- package/rules/js-run/js/project-structure.mdc +11 -0
- package/rules/js-run/js/runtime.mdc +14 -0
- package/rules/js-run/js/scope.mdc +11 -0
- package/rules/js-run/js/settimeout.mdc +11 -0
- package/rules/js-run/js/temporal.mdc +5 -0
- package/rules/js-run/main.mdc +16 -218
- package/rules/k8s/js/configmap.mdc +41 -0
- package/rules/k8s/js/deployment_resources.mdc +49 -0
- package/rules/k8s/js/hasura_httproute.mdc +91 -0
- package/rules/k8s/js/hpa_apiversion.mdc +27 -0
- package/rules/k8s/js/ingress_gateway.mdc +16 -0
- package/rules/k8s/js/kustomize_structure.mdc +144 -0
- package/rules/k8s/js/lint_k8s.mdc +72 -0
- package/rules/k8s/js/multidoc_yaml.mdc +5 -0
- package/rules/k8s/js/network_policy.mdc +136 -0
- package/rules/k8s/js/schema_modeline.mdc +57 -0
- package/rules/k8s/js/service.mdc +44 -0
- package/rules/k8s/js/topology_hpa_pdb.mdc +181 -0
- package/rules/k8s/main.mdc +30 -843
- package/rules/nginx-default-tpl/js/dockerfile.mdc +36 -0
- package/rules/nginx-default-tpl/js/http-route.mdc +41 -0
- package/rules/nginx-default-tpl/js/ini-keys.mdc +21 -0
- package/rules/nginx-default-tpl/js/template-structure.mdc +86 -0
- package/rules/nginx-default-tpl/js/vscode.mdc +37 -0
- package/rules/nginx-default-tpl/main.mdc +6 -112
- package/rules/npm-module/js/docs/index.md +5 -5
- package/rules/npm-module/js/docs/rule_meta.md +6 -6
- package/rules/npm-module/js/docs/skill_meta.md +8 -8
- package/rules/npm-module/js/header_doc_pointer.mdc +18 -0
- package/rules/npm-module/js/package_structure.mdc +62 -0
- package/rules/npm-module/js/rule_meta.mdc +11 -0
- package/rules/npm-module/js/skill_meta.mdc +11 -0
- package/rules/npm-module/main.mdc +10 -55
- package/rules/php/js/lint_php_yml.mdc +12 -0
- package/rules/php/js/tooling.mdc +66 -0
- package/rules/php/main.mdc +7 -66
- package/rules/python/js/lint_python_yml.mdc +23 -0
- package/rules/python/js/pyproject_toml.mdc +32 -0
- package/rules/python/js/tooling.mdc +23 -0
- package/rules/python/main.mdc +9 -33
- package/rules/rego/js/rego-lint.mdc +31 -0
- package/rules/rego/js/vscode_extensions.mdc +11 -0
- package/rules/rego/js/vscode_settings.mdc +13 -0
- package/rules/rego/main.mdc +8 -24
- package/rules/rust/js/coverage.mdc +28 -0
- package/rules/rust/js/lint.mdc +22 -0
- package/rules/rust/js/tauri_composition.mdc +8 -0
- package/rules/rust/js/vscode_extensions.mdc +12 -0
- package/rules/rust/main.mdc +8 -38
- package/rules/security/js/rego_policies.mdc +15 -0
- package/rules/security/js/sample_secret.mdc +19 -0
- package/rules/security/js/trufflehog.mdc +21 -0
- package/rules/security/main.mdc +7 -35
- package/rules/style/js/admin-table.mdc +88 -0
- package/rules/style/js/colors.mdc +21 -0
- package/rules/style/js/gap.mdc +22 -0
- package/rules/style/js/quasar-fixes.mdc +32 -0
- package/rules/style/js/quasar.mdc +7 -0
- package/rules/style/js/tooling.mdc +85 -0
- package/rules/style/main.mdc +13 -253
- package/rules/tauri/js/cargo_mutants_config.mdc +39 -0
- package/rules/tauri/js/tool_surface.mdc +21 -0
- package/rules/tauri/js/tooling.mdc +25 -0
- package/rules/tauri/main.mdc +8 -78
- package/rules/test/js/cargo_mutants_config.mdc +18 -0
- package/rules/test/js/docs/index.md +7 -7
- package/rules/test/js/location.mdc +52 -0
- package/rules/test/js/no-console-store-restore.mdc +11 -0
- package/rules/test/js/no-process-chdir.mdc +15 -0
- package/rules/test/js/no-relative-fs-path.mdc +22 -0
- package/rules/test/js/sandbox-aware-test.mdc +28 -0
- package/rules/test/js/stryker_config.mdc +26 -0
- package/rules/test/js/vitest-config-pool-forks.mdc +33 -0
- package/rules/test/main.mdc +18 -184
- package/rules/text/js/ci-lint-text.mdc +15 -0
- package/rules/text/js/cspell.mdc +81 -0
- package/rules/text/js/dotenv-linter.mdc +16 -0
- package/rules/text/js/forbidden-prettier.mdc +13 -0
- package/rules/text/js/markdownlint.mdc +25 -0
- package/rules/text/js/oxfmt.mdc +35 -0
- package/rules/text/js/package-json.mdc +26 -0
- package/rules/text/js/shellcheck.mdc +18 -0
- package/rules/text/js/v8r.mdc +23 -0
- package/rules/text/js/vscode.mdc +86 -0
- package/rules/text/main.mdc +20 -237
- package/rules/vue/js/composition-api.mdc +82 -0
- package/rules/vue/js/nheader-layout.mdc +171 -0
- package/rules/vue/js/node-imports.mdc +25 -0
- package/rules/vue/js/quasar-ui.mdc +32 -0
- package/rules/vue/js/structure.mdc +101 -0
- package/rules/vue/js/testing.mdc +32 -0
- package/rules/vue/js/tfm-translations.mdc +26 -0
- package/rules/vue/js/vite-config.mdc +126 -0
- package/rules/vue/js/vite-env.mdc +55 -0
- package/rules/vue/js/vue-imports.mdc +25 -0
- package/rules/vue/main.mdc +16 -640
- package/scripts/auto-rules.mjs +6 -6
- package/scripts/auto-skills.mjs +3 -3
- package/scripts/docs/auto-rules.md +17 -31
- package/scripts/docs/auto-skills.md +18 -163
- package/scripts/docs/index.md +16 -16
- package/scripts/lib/docs/index.md +36 -36
- package/scripts/lib/docs/mirror-parity.md +7 -7
- package/scripts/lib/docs/rule-meta.md +12 -12
- package/scripts/lib/docs/skill-meta.md +9 -9
- package/scripts/lib/docs/worktree-notice.md +10 -8
- package/scripts/lib/rule-meta.mjs +6 -6
- package/scripts/lib/skill-meta.mjs +6 -6
- package/scripts/lib/worktree-notice.mjs +2 -2
- package/scripts/utils/docs/index.md +14 -14
package/rules/security/main.mdc
CHANGED
|
@@ -5,46 +5,18 @@ alwaysApply: false
|
|
|
5
5
|
version: '2.1'
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
[TruffleHog](https://github.com/trufflesecurity/trufflehog)
|
|
8
|
+
Правило **security** забезпечує сканування секретів через [TruffleHog](https://github.com/trufflesecurity/trufflehog) локально та на CI, а також правильне використання placeholder-значень у прикладних файлах.
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
[security-trufflehog](./js/trufflehog.mdc)
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
[security-sample-secret](./js/sample_secret.mdc)
|
|
13
13
|
|
|
14
|
-
-
|
|
14
|
+
[security-rego-policies](./js/rego_policies.mdc)
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
## Швидкий gate через conftest
|
|
17
17
|
|
|
18
|
-
- `
|
|
19
|
-
-
|
|
20
|
-
- `--exclude-paths .trufflehog-exclude` — файл з regex-patterns, які треба пропускати (аналог `[allowlist].paths` із gitleaks).
|
|
21
|
-
- `--results=verified,unknown` — показує лише верифіковані секрети + ті, що TruffleHog не зміг перевірити (`unverified` дублікат відсіюється).
|
|
22
|
-
- `--fail` — exit-code `183` за наявності знахідок (щоб лінт падав).
|
|
23
|
-
|
|
24
|
-
## `.trufflehog-exclude` (рекомендована основа)
|
|
25
|
-
|
|
26
|
-
Канон (допускає розширення): [.trufflehog-exclude.snippet.txt](./js/templates/trufflehog/.trufflehog-exclude.snippet.txt)
|
|
27
|
-
|
|
28
|
-
**Важливо:** один regex-pattern на рядок, без TOML-обгортки; коментарі починаються з `#`.
|
|
29
|
-
|
|
30
|
-
## CI: `.github/workflows/lint-security.yml`
|
|
31
|
-
|
|
32
|
-
Workflow обовʼязковий — забезпечує незалежний скан секретів на push/PR (агрегований `lint` локально + окремий fail-fast job на CI).
|
|
33
|
-
|
|
34
|
-
- Канон: [lint-security.yml.snippet.yml](./policy/lint_security_yml/template/lint-security.yml.snippet.yml)
|
|
35
|
-
|
|
36
|
-
Перевіряється policy `security.lint_security_yml`: серед `uses:` має бути крок з `trufflesecurity/trufflehog@main`. Універсальні workflow-перевірки (checkout, permissions, persist-credentials) — у `ga.workflow_common`. Для повного скану історії потрібен `fetch-depth: 0`.
|
|
37
|
-
|
|
38
|
-
## Placeholder для секретів — `sample-secret`
|
|
39
|
-
|
|
40
|
-
Фейкові credential-значення у **прикладних файлах** (`.env.example`, `.env.dist`, `*.example`, `*.sample`, `*.template`, вміст каталогів `fixtures/`) пиши як `sample-secret`, а не як bare `secret`.
|
|
41
|
-
|
|
42
|
-
`sample-secret` містить підрядок `sample` із вшитого списку `DefaultFalsePositives` TruffleHog — таке значення сканер відсіює **гарантовано** й незалежно від версії. Bare `secret` наразі не фіксується сканером лише тому, що випадково присутнє у словнику `fp_words.txt`; це крихка поведінка, що залежить від версії інструмента.
|
|
43
|
-
|
|
44
|
-
- Правильно: `DB_PASSWORD=sample-secret`, `password: "sample-secret"`
|
|
45
|
-
- Неправильно: `DB_PASSWORD=secret`, `password: "secret"`
|
|
46
|
-
|
|
47
|
-
Перевіряється лише `secret` у позиції значення (після `=`, `:`, `=>`); імена ключів на кшталт `client_secret` не чіпаються. Concern `security.sample_secret` — деталі скану в `js/sample_secret.mjs`.
|
|
18
|
+
- `security.package_json` — забороняє `trufflehog` у `dependencies`/`devDependencies`
|
|
19
|
+
- `security.lint_security_yml` — перевіряє наявність кроку `trufflesecurity/trufflehog@main` у CI workflow
|
|
48
20
|
|
|
49
21
|
## Перевірка
|
|
50
22
|
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
## Адмінські таблиці — n-admin-table
|
|
2
|
+
|
|
3
|
+
Для таблиць, що мають займати всю висоту сторінки (або блоку), додавай клас `n-admin-table` і атрибути `hide-no-data`, `dense`, `flat`. Таблиця автоматично розтягнеться на весь доступний простір. У блоках меншої висоти — задай їм явний `height`.
|
|
4
|
+
|
|
5
|
+
```vue
|
|
6
|
+
<!-- ТАБЛИЦЯ -->
|
|
7
|
+
<q-table class="n-admin-table" hide-no-data flat dense />
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
Якщо клас `.n-admin-table` не визначено в `app.scss` — додай:
|
|
11
|
+
|
|
12
|
+
```scss
|
|
13
|
+
// ADMIN TABLE
|
|
14
|
+
.n-admin-table {
|
|
15
|
+
height: calc(100vh - 106px);
|
|
16
|
+
|
|
17
|
+
thead {
|
|
18
|
+
position: sticky;
|
|
19
|
+
z-index: 3;
|
|
20
|
+
top: 0;
|
|
21
|
+
|
|
22
|
+
tr th {
|
|
23
|
+
background-color: $grey-3;
|
|
24
|
+
height: 36px !important;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// tbody td {
|
|
29
|
+
// font-size: 14px;
|
|
30
|
+
// }
|
|
31
|
+
|
|
32
|
+
tbody tr:last-child td {
|
|
33
|
+
border-bottom: 1px solid rgb(0 0 0 / 12%) !important;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
th:first-child,
|
|
37
|
+
td:first-child,
|
|
38
|
+
th:last-child,
|
|
39
|
+
td:last-child {
|
|
40
|
+
width: 1px;
|
|
41
|
+
white-space: nowrap;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.q-table__bottom {
|
|
45
|
+
background-color: $grey-3;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.q-table__progress th {
|
|
49
|
+
height: 1px !important;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.text-wrap {
|
|
53
|
+
max-width: 250px;
|
|
54
|
+
white-space: normal;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// sticky columns
|
|
58
|
+
td.sticky-left {
|
|
59
|
+
position: sticky;
|
|
60
|
+
left: 0;
|
|
61
|
+
z-index: 2;
|
|
62
|
+
background-color: white;
|
|
63
|
+
box-shadow: 2px 0 5px #0002;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
td.sticky-right {
|
|
67
|
+
position: sticky;
|
|
68
|
+
right: 0;
|
|
69
|
+
z-index: 2;
|
|
70
|
+
background-color: white;
|
|
71
|
+
box-shadow: -2px 0 5px #0002;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
th.sticky-left {
|
|
75
|
+
position: sticky;
|
|
76
|
+
left: 0;
|
|
77
|
+
z-index: 3;
|
|
78
|
+
box-shadow: 2px 0 5px #0002;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
th.sticky-right {
|
|
82
|
+
position: sticky;
|
|
83
|
+
right: 0;
|
|
84
|
+
z-index: 3;
|
|
85
|
+
box-shadow: -2px 0 5px #0002;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
```
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
## Кольори: quasar-variables.scss і app.scss
|
|
2
|
+
|
|
3
|
+
Основні кольори визначай виключно через стандартні Quasar-змінні: `$primary`, `$secondary`, `$accent`, `$positive`, `$negative`, `$warning`.
|
|
4
|
+
|
|
5
|
+
Якщо потрібен додатковий колір — визнач його в `quasar-variables.scss`, і **обов'язково** додай до `app.scss` відповідні `.text-*` / `.bg-*` класи:
|
|
6
|
+
|
|
7
|
+
```scss
|
|
8
|
+
/* quasar-variables.scss */
|
|
9
|
+
$white-a1: color.adjust(white, $alpha: -0.85);
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
```scss
|
|
13
|
+
/* app.scss */
|
|
14
|
+
.text-white-a1 {
|
|
15
|
+
color: $white-a1 !important;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
.bg-white-a1 {
|
|
19
|
+
background-color: $white-a1 !important;
|
|
20
|
+
}
|
|
21
|
+
```
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
## Gap між flex/grid-елементами — .n-gap-*
|
|
2
|
+
|
|
3
|
+
Для відступів між плаваючими елементами (flex, grid) використовуй класи `.n-gap-*` замість `q-gutter-*`. Якщо класів немає в `app.scss` — додай:
|
|
4
|
+
|
|
5
|
+
```scss
|
|
6
|
+
// GAP
|
|
7
|
+
.n-gap-xs {
|
|
8
|
+
gap: 4px;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.n-gap-sm {
|
|
12
|
+
gap: 8px;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.n-gap-md {
|
|
16
|
+
gap: 16px;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.n-gap-lg {
|
|
20
|
+
gap: 24px;
|
|
21
|
+
}
|
|
22
|
+
```
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
## Фікси компонентів Quasar
|
|
2
|
+
|
|
3
|
+
При використанні компонента `q-scroll-area` або `q-tooltip` додай до `app.scss` відповідні фікси. Аналогічно — фікс масштабування на iOS.
|
|
4
|
+
|
|
5
|
+
```scss
|
|
6
|
+
// FIX стилі для прокручуваної області по висоті екрана
|
|
7
|
+
.q-scrollarea {
|
|
8
|
+
display: flex;
|
|
9
|
+
flex-direction: column;
|
|
10
|
+
height: auto;
|
|
11
|
+
min-height: 0;
|
|
12
|
+
max-height: 100%;
|
|
13
|
+
|
|
14
|
+
.scroll {
|
|
15
|
+
flex: 10000 1 0%;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// FIX tooltip
|
|
20
|
+
.q-tooltip {
|
|
21
|
+
font-size: 1em;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// FIX не зумувати на iOS
|
|
25
|
+
@media (width <= 600px) {
|
|
26
|
+
input,
|
|
27
|
+
textarea,
|
|
28
|
+
select {
|
|
29
|
+
font-size: 16px;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
```
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
## Quasar як стильова основа
|
|
2
|
+
|
|
3
|
+
У Vue-проектах використовуй **Quasar** як базову стильову систему:
|
|
4
|
+
|
|
5
|
+
- **Класи компонентів:** `q-pa-*`, `q-ma-*`, `q-mt-*`, `q-mb-*`, `row`, `col`, `col-*`, `items-center`, `justify-between`, `text-*`, `bg-*`, `shadow-*` тощо — стандартні утиліти Quasar.
|
|
6
|
+
- **Кольори:** використовуй Quasar CSS-змінні через класи (`text-primary`, `bg-accent`, `text-negative` тощо) або через SCSS-змінні (`$primary`, `$accent`) у `.scss`-файлах.
|
|
7
|
+
- **Не пиши власні утиліти**, якщо є відповідний Quasar-клас.
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
## Генерація та редагування стилів (Cursor і інші агенти)
|
|
2
|
+
|
|
3
|
+
- **Джерело правил:** перед тим як писати або суттєво змінювати **`.css`**, **`.scss`** або стилі в **`.vue`**, переглянь у корені проєкту (і в релевантних пакетах монорепо, якщо є) поле **`stylelint`** у **`package.json`** (зокрема `extends`), наявні **`.stylelintrc.*`**, **`stylelint.config.*`** та **`.stylelintignore`**. Не покладайся на «типові» правила stylelint з пам'яті — дотримуйся **проєктного** **`@nitra/stylelint-config`** і будь-яких локальних доповнень у репозиторії.
|
|
4
|
+
- **Форматування** узгоджуй з **`n-text.mdc`** (oxfmt / `.oxfmtrc.json` для css, scss тощо), щоб форматер і stylelint не суперечили один одному.
|
|
5
|
+
- **Запуск stylelint:** лише через **`n-cursor lint style`** (локально — з auto-fix; у CI — `--read-only`, нуль мутацій). Під капотом — `npx stylelint`; **не** використовуй **`bunx stylelint`**. Після змін запускай **`n-cursor lint style`** і виправляй усе, що лишилось після auto-fix; за потреби — повний прогін `n-cursor lint --full`.
|
|
6
|
+
- **Не розширюй винятки:** не додавай зайві **`stylelint-disable`** без потреби; краще підлаштувати стилі під правила проєкту.
|
|
7
|
+
|
|
8
|
+
## Канон налаштувань
|
|
9
|
+
|
|
10
|
+
### `package.json`
|
|
11
|
+
|
|
12
|
+
- `stylelint.extends`: [package.json.snippet.json](./policy/package_json/template/package.json.snippet.json)
|
|
13
|
+
|
|
14
|
+
Окремого `lint-style` скрипта немає — запуск через **`n-cursor lint style`** (CI — `--read-only`).
|
|
15
|
+
|
|
16
|
+
```json title="package.json"
|
|
17
|
+
"devDependencies": {
|
|
18
|
+
"@nitra/stylelint-config": "^1.4.0"
|
|
19
|
+
},
|
|
20
|
+
"stylelint": {
|
|
21
|
+
"extends": "@nitra/stylelint-config"
|
|
22
|
+
},
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
У корені проєкту має бути **`.stylelintignore`**:
|
|
26
|
+
|
|
27
|
+
```text title=".stylelintignore"
|
|
28
|
+
dist/
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### `.vscode/extensions.json`
|
|
32
|
+
|
|
33
|
+
- Канон `recommendations`: [extensions.json.snippet.json](./policy/vscode_extensions/template/extensions.json.snippet.json)
|
|
34
|
+
|
|
35
|
+
### `.vscode/settings.json`
|
|
36
|
+
|
|
37
|
+
- Вимкнення вбудованої CSS-валідації VS Code: [settings.json.snippet.json](./policy/vscode_settings/template/settings.json.snippet.json)
|
|
38
|
+
|
|
39
|
+
### CI: `.github/workflows/lint-style.yml`
|
|
40
|
+
|
|
41
|
+
- Канон: [lint-style.yml.snippet.yml](./policy/lint_style_yml/template/lint-style.yml.snippet.yml)
|
|
42
|
+
|
|
43
|
+
Додай **`.github/workflows/lint-style.yml`** (лише **`.yml`**, **`ga.mdc`**): після **`checkout`** — локальний composite **`setup-bun-deps`**, далі `n-cursor lint style --read-only` у кроці **`run`**. **Не** дублюй окремі кроки **`setup-node`** / **`oven-sh/setup-bun`** / кеш / **`npm install`**.
|
|
44
|
+
|
|
45
|
+
```yaml title=".github/workflows/lint-style.yml"
|
|
46
|
+
name: StyleLint
|
|
47
|
+
|
|
48
|
+
on:
|
|
49
|
+
push:
|
|
50
|
+
branches:
|
|
51
|
+
- dev
|
|
52
|
+
- main
|
|
53
|
+
paths:
|
|
54
|
+
- '**/*.css'
|
|
55
|
+
- '**/*.scss'
|
|
56
|
+
- '**/*.vue'
|
|
57
|
+
|
|
58
|
+
pull_request:
|
|
59
|
+
branches:
|
|
60
|
+
- dev
|
|
61
|
+
- main
|
|
62
|
+
paths:
|
|
63
|
+
- '**/*.css'
|
|
64
|
+
- '**/*.scss'
|
|
65
|
+
- '**/*.vue'
|
|
66
|
+
|
|
67
|
+
concurrency:
|
|
68
|
+
group: ${{ github.ref }}-${{ github.workflow }}
|
|
69
|
+
cancel-in-progress: true
|
|
70
|
+
|
|
71
|
+
jobs:
|
|
72
|
+
stylelint:
|
|
73
|
+
runs-on: ubuntu-latest
|
|
74
|
+
permissions:
|
|
75
|
+
contents: read
|
|
76
|
+
steps:
|
|
77
|
+
- uses: actions/checkout@v6
|
|
78
|
+
with:
|
|
79
|
+
persist-credentials: false
|
|
80
|
+
|
|
81
|
+
- uses: ./.github/actions/setup-bun-deps
|
|
82
|
+
|
|
83
|
+
- name: StyleLint
|
|
84
|
+
run: npx stylelint '**/*.{css,scss,vue}'
|
|
85
|
+
```
|
package/rules/style/main.mdc
CHANGED
|
@@ -5,265 +5,25 @@ globs: "**/*.{css,scss,vue}"
|
|
|
5
5
|
alwaysApply: false
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
Правило **style** для Vue-проєктів: Quasar як стильова система, SCSS-конвенції кольорів і відступів, фікси компонентів, stylelint через `@nitra/stylelint-config`.
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
[style-quasar](./js/quasar.mdc)
|
|
11
11
|
|
|
12
|
-
-
|
|
13
|
-
- **Кольори:** використовуй Quasar CSS-змінні через класи (`text-primary`, `bg-accent`, `text-negative` тощо) або через SCSS-змінні (`$primary`, `$accent`) у `.scss`-файлах.
|
|
14
|
-
- **Не пиши власні утиліти**, якщо є відповідний Quasar-клас.
|
|
12
|
+
[style-colors](./js/colors.mdc)
|
|
15
13
|
|
|
16
|
-
|
|
14
|
+
[style-gap](./js/gap.mdc)
|
|
17
15
|
|
|
18
|
-
|
|
16
|
+
[style-quasar-fixes](./js/quasar-fixes.mdc)
|
|
19
17
|
|
|
20
|
-
|
|
18
|
+
[style-tooling](./js/tooling.mdc)
|
|
21
19
|
|
|
22
|
-
|
|
23
|
-
/* quasar-variables.scss */
|
|
24
|
-
$white-a1: color.adjust(white, $alpha: -0.85);
|
|
25
|
-
```
|
|
20
|
+
[style-admin-table](./js/admin-table.mdc)
|
|
26
21
|
|
|
27
|
-
|
|
28
|
-
/* app.scss */
|
|
29
|
-
.text-white-a1 {
|
|
30
|
-
color: $white-a1 !important;
|
|
31
|
-
}
|
|
22
|
+
## Швидкий gate через conftest (Rego)
|
|
32
23
|
|
|
33
|
-
|
|
34
|
-
background-color: $white-a1 !important;
|
|
35
|
-
}
|
|
36
|
-
```
|
|
24
|
+
Пакети у `npm/rules/style/policy/`:
|
|
37
25
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
```scss
|
|
43
|
-
// GAP
|
|
44
|
-
.n-gap-xs {
|
|
45
|
-
gap: 4px;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
.n-gap-sm {
|
|
49
|
-
gap: 8px;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
.n-gap-md {
|
|
53
|
-
gap: 16px;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
.n-gap-lg {
|
|
57
|
-
gap: 24px;
|
|
58
|
-
}
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
## Фікси компонентів Quasar
|
|
62
|
-
|
|
63
|
-
При використанні компонента `q-scroll-area` або `q-tooltip` додай до `app.scss` відповідні фікси. Аналогічно — фікс масштабування на iOS.
|
|
64
|
-
|
|
65
|
-
```scss
|
|
66
|
-
// FIX стилі для прокручуваної області по висоті екрана
|
|
67
|
-
.q-scrollarea {
|
|
68
|
-
display: flex;
|
|
69
|
-
flex-direction: column;
|
|
70
|
-
height: auto;
|
|
71
|
-
min-height: 0;
|
|
72
|
-
max-height: 100%;
|
|
73
|
-
|
|
74
|
-
.scroll {
|
|
75
|
-
flex: 10000 1 0%;
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
// FIX tooltip
|
|
80
|
-
.q-tooltip {
|
|
81
|
-
font-size: 1em;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
// FIX не зумувати на iOS
|
|
85
|
-
@media (width <= 600px) {
|
|
86
|
-
input,
|
|
87
|
-
textarea,
|
|
88
|
-
select {
|
|
89
|
-
font-size: 16px;
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
## Генерація та редагування стилів (Cursor і інші агенти)
|
|
95
|
-
|
|
96
|
-
- **Джерело правил:** перед тим як писати або суттєво змінювати **`.css`**, **`.scss`** або стилі в **`.vue`**, переглянь у корені проєкту (і в релевантних пакетах монорепо, якщо є) поле **`stylelint`** у **`package.json`** (зокрема `extends`), наявні **`.stylelintrc.*`**, **`stylelint.config.*`** та **`.stylelintignore`**. Не покладайся на «типові» правила stylelint з пам’яті — дотримуйся **проєктного** **`@nitra/stylelint-config`** і будь-яких локальних доповнень у репозиторії.
|
|
97
|
-
- **Форматування** узгоджуй з **`n-text.mdc`** (oxfmt / `.oxfmtrc.json` для css, scss тощо), щоб форматер і stylelint не суперечили один одному.
|
|
98
|
-
- **Запуск stylelint:** лише через **`n-cursor lint style`** (локально — з auto-fix; у CI — `--read-only`, нуль мутацій). Під капотом — `npx stylelint`; **не** використовуй **`bunx stylelint`**. Після змін запускай **`n-cursor lint style`** і виправляй усе, що лишилось після auto-fix; за потреби — повний прогін `n-cursor lint --full`.
|
|
99
|
-
- **Не розширюй винятки:** не додавай зайві **`stylelint-disable`** без потреби; краще підлаштувати стилі під правила проєкту.
|
|
100
|
-
|
|
101
|
-
## Канон
|
|
102
|
-
|
|
103
|
-
### `package.json`
|
|
104
|
-
|
|
105
|
-
- `stylelint.extends`: [package.json.snippet.json](./policy/package_json/template/package.json.snippet.json)
|
|
106
|
-
|
|
107
|
-
Окремого `lint-style` скрипта немає — запуск через **`n-cursor lint style`** (CI — `--read-only`).
|
|
108
|
-
|
|
109
|
-
### `.vscode/extensions.json`
|
|
110
|
-
|
|
111
|
-
- Канон `recommendations`: [extensions.json.snippet.json](./policy/vscode_extensions/template/extensions.json.snippet.json)
|
|
112
|
-
|
|
113
|
-
### `.vscode/settings.json`
|
|
114
|
-
|
|
115
|
-
- Вимкнення вбудованої CSS-валідації VS Code: [settings.json.snippet.json](./policy/vscode_settings/template/settings.json.snippet.json)
|
|
116
|
-
|
|
117
|
-
### CI: `.github/workflows/lint-style.yml`
|
|
118
|
-
|
|
119
|
-
- Канон: [lint-style.yml.snippet.yml](./policy/lint_style_yml/template/lint-style.yml.snippet.yml)
|
|
120
|
-
|
|
121
|
-
**`package.json`:**
|
|
122
|
-
|
|
123
|
-
```json title="package.json"
|
|
124
|
-
"devDependencies": {
|
|
125
|
-
"@nitra/stylelint-config": "^1.4.0"
|
|
126
|
-
},
|
|
127
|
-
"stylelint": {
|
|
128
|
-
"extends": "@nitra/stylelint-config"
|
|
129
|
-
},
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
Додай **`.github/workflows/lint-style.yml`** (лише **`.yml`**, **`ga.mdc`**): після **`checkout`** — локальний composite **`setup-bun-deps`**, далі `n-cursor lint style --read-only` у кроці **`run`**. **Не** дублюй окремі кроки **`setup-node`** / **`oven-sh/setup-bun`** / кеш / **`npm install`**.
|
|
133
|
-
|
|
134
|
-
```yaml title=".github/workflows/lint-style.yml"
|
|
135
|
-
name: StyleLint
|
|
136
|
-
|
|
137
|
-
on:
|
|
138
|
-
push:
|
|
139
|
-
branches:
|
|
140
|
-
- dev
|
|
141
|
-
- main
|
|
142
|
-
paths:
|
|
143
|
-
- '**/*.css'
|
|
144
|
-
- '**/*.scss'
|
|
145
|
-
- '**/*.vue'
|
|
146
|
-
|
|
147
|
-
pull_request:
|
|
148
|
-
branches:
|
|
149
|
-
- dev
|
|
150
|
-
- main
|
|
151
|
-
paths:
|
|
152
|
-
- '**/*.css'
|
|
153
|
-
- '**/*.scss'
|
|
154
|
-
- '**/*.vue'
|
|
155
|
-
|
|
156
|
-
concurrency:
|
|
157
|
-
group: ${{ github.ref }}-${{ github.workflow }}
|
|
158
|
-
cancel-in-progress: true
|
|
159
|
-
|
|
160
|
-
jobs:
|
|
161
|
-
stylelint:
|
|
162
|
-
runs-on: ubuntu-latest
|
|
163
|
-
permissions:
|
|
164
|
-
contents: read
|
|
165
|
-
steps:
|
|
166
|
-
- uses: actions/checkout@v6
|
|
167
|
-
with:
|
|
168
|
-
persist-credentials: false
|
|
169
|
-
|
|
170
|
-
- uses: ./.github/actions/setup-bun-deps
|
|
171
|
-
|
|
172
|
-
- name: StyleLint
|
|
173
|
-
run: npx stylelint '**/*.{css,scss,vue}'
|
|
174
|
-
```
|
|
175
|
-
|
|
176
|
-
У корені проєкту має бути **`.stylelintignore`**:
|
|
177
|
-
|
|
178
|
-
```text title=".stylelintignore"
|
|
179
|
-
dist/
|
|
180
|
-
```
|
|
181
|
-
|
|
182
|
-
## Адмінські таблиці — n-admin-table
|
|
183
|
-
|
|
184
|
-
Для таблиць, що мають займати всю висоту сторінки (або блоку), додавай клас `n-admin-table` і атрибути `hide-no-data`, `dense`, `flat`. Таблиця автоматично розтягнеться на весь доступний простір. У блоках меншої висоти — задай їм явний `height`.
|
|
185
|
-
|
|
186
|
-
```vue
|
|
187
|
-
<!-- ТАБЛИЦЯ -->
|
|
188
|
-
<q-table class="n-admin-table" hide-no-data flat dense />
|
|
189
|
-
```
|
|
190
|
-
|
|
191
|
-
Якщо клас `.n-admin-table` не визначено в `app.scss` — додай:
|
|
192
|
-
|
|
193
|
-
```scss
|
|
194
|
-
// ADMIN TABLE
|
|
195
|
-
.n-admin-table {
|
|
196
|
-
height: calc(100vh - 106px);
|
|
197
|
-
|
|
198
|
-
thead {
|
|
199
|
-
position: sticky;
|
|
200
|
-
z-index: 3;
|
|
201
|
-
top: 0;
|
|
202
|
-
|
|
203
|
-
tr th {
|
|
204
|
-
background-color: $grey-3;
|
|
205
|
-
height: 36px !important;
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
// tbody td {
|
|
210
|
-
// font-size: 14px;
|
|
211
|
-
// }
|
|
212
|
-
|
|
213
|
-
tbody tr:last-child td {
|
|
214
|
-
border-bottom: 1px solid rgb(0 0 0 / 12%) !important;
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
th:first-child,
|
|
218
|
-
td:first-child,
|
|
219
|
-
th:last-child,
|
|
220
|
-
td:last-child {
|
|
221
|
-
width: 1px;
|
|
222
|
-
white-space: nowrap;
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
.q-table__bottom {
|
|
226
|
-
background-color: $grey-3;
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
.q-table__progress th {
|
|
230
|
-
height: 1px !important;
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
.text-wrap {
|
|
234
|
-
max-width: 250px;
|
|
235
|
-
white-space: normal;
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
// sticky columns
|
|
239
|
-
td.sticky-left {
|
|
240
|
-
position: sticky;
|
|
241
|
-
left: 0;
|
|
242
|
-
z-index: 2;
|
|
243
|
-
background-color: white;
|
|
244
|
-
box-shadow: 2px 0 5px #0002;
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
td.sticky-right {
|
|
248
|
-
position: sticky;
|
|
249
|
-
right: 0;
|
|
250
|
-
z-index: 2;
|
|
251
|
-
background-color: white;
|
|
252
|
-
box-shadow: -2px 0 5px #0002;
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
th.sticky-left {
|
|
256
|
-
position: sticky;
|
|
257
|
-
left: 0;
|
|
258
|
-
z-index: 3;
|
|
259
|
-
box-shadow: 2px 0 5px #0002;
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
th.sticky-right {
|
|
263
|
-
position: sticky;
|
|
264
|
-
right: 0;
|
|
265
|
-
z-index: 3;
|
|
266
|
-
box-shadow: -2px 0 5px #0002;
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
```
|
|
26
|
+
- `style_lint.package_json` — `package.json`: `stylelint.extends == "@nitra/stylelint-config"`, `@nitra/stylelint-config` у `devDependencies`.
|
|
27
|
+
- `style_lint.vscode_extensions` — `.vscode/extensions.json`: `recommendations` містить `stylelint.vscode-stylelint`.
|
|
28
|
+
- `style_lint.vscode_settings` — `.vscode/settings.json`: `css.validate`, `less.validate`, `scss.validate` вимкнені (`false`).
|
|
29
|
+
- `style_lint.lint_style_yml` — `.github/workflows/lint-style.yml`: крок `run` містить команду `n-cursor lint style --read-only`.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
## Mutation-testing: семантика app shell та platform bridge
|
|
2
|
+
|
|
3
|
+
`tauri` rule володіє Tauri-specific семантикою mutation-testing для каталога `src-tauri/`. Концерн `js/cargo_mutants_config.mjs` без дублювання додає у `<ws>/src-tauri/.cargo/mutants.toml` такі канонічні ключі:
|
|
4
|
+
|
|
5
|
+
```toml title="<ws>/src-tauri/.cargo/mutants.toml"
|
|
6
|
+
additional_cargo_test_args = ["--lib", "--tests"]
|
|
7
|
+
|
|
8
|
+
exclude_globs = [
|
|
9
|
+
"src/main.rs",
|
|
10
|
+
"src/lib.rs",
|
|
11
|
+
"src/**/android.rs",
|
|
12
|
+
"src/**/ios.rs",
|
|
13
|
+
"src/**/mobile.rs",
|
|
14
|
+
"src/**/desktop.rs",
|
|
15
|
+
"src/**/macos.rs",
|
|
16
|
+
"src/**/windows.rs",
|
|
17
|
+
"src/**/linux.rs"
|
|
18
|
+
]
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Семантика (фіксована між Tauri-проєктами):
|
|
22
|
+
|
|
23
|
+
- **`src/main.rs`** — binary shell entrypoint: запускає Tauri runtime, реєструє plugins/handlers і повертає управління циклу подій. Тестується smoke/e2e (запуск бінарника), не mutation unit;
|
|
24
|
+
- **`src/lib.rs`** — Tauri runtime entrypoint (`pub fn run`): піднімає весь app shell. Один мутант там тримає весь Tauri runtime, тому ділить sandbox-фейл з `src/main.rs` і тестується smoke/e2e, а не mutation unit;
|
|
25
|
+
- **`*android.rs`, `*ios.rs`, `*mobile.rs`** — mobile plugin bridge / platform glue: тонка обгортка над JNI/Objective-C виклики, mapping platform errors, виклики Tauri AppHandle і native API;
|
|
26
|
+
- **`*macos.rs`, `*windows.rs`, `*linux.rs`, `*desktop.rs`** — desktop platform bridge / OS integration glue: opener/window APIs, OS-specific I/O, mapping platform errors.
|
|
27
|
+
|
|
28
|
+
Ці файли мають містити **тільки platform boundary**: виклик plugin/native API, Tauri AppHandle, opener/window APIs, OS-specific I/O, mapping platform errors. Якщо у bridge-файлі з'являється pure/business logic — її потрібно винести у platform-neutral модуль (`src/auth/oauth.rs`, `src/gmail/message.rs`, …) і тестувати mutation-testing там.
|
|
29
|
+
|
|
30
|
+
Це створює фіксовану семантику: `*android.rs`/`*macos.rs` — boundary-файли, а не місце для бізнес-логіки.
|
|
31
|
+
|
|
32
|
+
### Ідемпотентність і взаємодія з `test`-rule
|
|
33
|
+
|
|
34
|
+
- `test` rule створює універсальний нейтральний `.cargo/mutants.toml` (порожній з коментарем) для кожного Cargo.toml-manifest-файла — без framework-specific exclude'ів. Це наш baseline.
|
|
35
|
+
- `tauri` rule додає Tauri-канонічні ключі **поверх** того, що вже є у `<ws>/src-tauri/.cargo/mutants.toml`:
|
|
36
|
+
- якщо файла немає — створює з повного Tauri-baseline;
|
|
37
|
+
- якщо обидва канонічні ключі (`additional_cargo_test_args`, `exclude_globs`) вже присутні — `manual cargo-mutants config preserved`, нічого не зміниться;
|
|
38
|
+
- якщо якийсь канонічний ключ відсутній — додається окремим блоком у кінці файла, без зміни існуючих значень.
|
|
39
|
+
- Послідовний `fix test` → `fix tauri` створює Tauri-config; повторний `fix tauri` не дублює секцій; повторний `fix test` не перетирає Tauri-tuning.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
## Tool Surface у Tauri (реалізація ядра `tool-surface`)
|
|
2
|
+
|
|
3
|
+
Це per-stack реалізація правила **`tool-surface`** (`n-tool-surface`) для Tauri+Rust. Контракт (каталог → `dispatch` → UI/оркестратор/LLM, інваріант паритету, конверт) — у тому правилі; тут — як він лягає на Tauri.
|
|
4
|
+
|
|
5
|
+
**Реальна робота живе в Rust, JS-каталог — тонкий call surface.** Handler тула не містить логіки сам — він **делегує** в native. Одна реалізація в Rust-крейті backs два споживачі:
|
|
6
|
+
|
|
7
|
+
- **Бінарник** (`src-tauri` як CLI, або окремий crate-bin) — headless-вхід для оркестратора;
|
|
8
|
+
- **Tauri-команда** (`#[tauri::command]`) — той самий крейт-fn, обгорнутий для UI.
|
|
9
|
+
|
|
10
|
+
**Два транспорти одного каталогу** (`src/tool/transports`):
|
|
11
|
+
|
|
12
|
+
- **UI (in-app):** `invoke(tool.tauri, input)` → Tauri-команда → крейт. Ключі `input` мапляться 1:1 на аргументи команди (camelCase, напр. `tasksDir`); поля вкладених struct лишаються snake_case (Tauri конвертить лише імена top-level аргументів).
|
|
13
|
+
- **Оркестратор (headless):** `bin/<app>.mjs` спавнить зібраний бінарник (`<bin> <verb> …` per-verb, або уніфікований `<bin> exec '<json>'`), парсить JSON stdout.
|
|
14
|
+
|
|
15
|
+
**Конверт:** Tauri-команда повертає `Result<T, String>`; адаптер мапить у `{ ok, output }` / `{ ok:false, error }`. Бінарник друкує конверт у stdout, exit ≠ 0 на `ok:false`.
|
|
16
|
+
|
|
17
|
+
**Єдине джерело схем:** надавай перевагу `schemars`-derive на Rust-param-структурах → бінарник віддає маніфест (`<bin> schema`); або тримай схему в JS-каталозі й валідуй до `invoke`. **Не дублюй** контракт між Rust і JS — лише деривація + спільні тест-вектори.
|
|
18
|
+
|
|
19
|
+
**Дозволи:** будь-який плагін, який смикають тули (`tauri-plugin-dialog`, `tauri-plugin-http` для локальної LLM тощо), має бути в `src-tauri/capabilities/*.json` і зареєстрований у `lib.rs` — інакше виклик тихо падає.
|
|
20
|
+
|
|
21
|
+
**LLM-раннер in-app:** chat-loop ходить до OpenAI-сумісного ендпоінта через `tauri-plugin-http` fetch (бо webview-fetch обмежений CSP/capability), а тули виконує через спільний `dispatch` (той самий, що й UI).
|