pumuki 6.3.247 → 6.3.248
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 +8 -0
- package/core/facts/detectors/text/ios.test.ts +51 -0
- package/core/facts/detectors/text/ios.ts +47 -0
- package/core/facts/extractHeuristicFacts.ts +2 -0
- package/core/rules/presets/heuristics/ios.test.ts +11 -1
- package/core/rules/presets/heuristics/ios.ts +37 -0
- package/docs/operations/RELEASE_NOTES.md +7 -0
- package/integrations/config/skillsCompilerTemplates.ts +10 -0
- package/integrations/config/skillsDetectorRegistry.ts +14 -24
- package/integrations/config/skillsMarkdownRules.ts +136 -9
- package/integrations/gate/evaluateAiGate.ts +3 -2
- package/package.json +1 -1
- package/scripts/framework-menu-gate-lib.ts +5 -0
- package/scripts/framework-menu-system-notifications-gate.ts +13 -1
- package/scripts/package-install-smoke-consumer-git-payload-lib.ts +6 -2
- package/scripts/package-install-smoke-consumer-git-repo-lib.ts +1 -1
- package/skills.lock.json +111 -194
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,14 @@ This project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [6.3.248] - 2026-05-14
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
|
|
13
|
+
- **PRE_WRITE iOS critical skills parity:** `skills.ios.critical-test-quality` vuelve a materializarse como cobertura crítica de `PRE_WRITE`; el modo advisory informa sin bloquear y `PUMUKI_SKILLS_ENFORCEMENT=strict` bloquea cuando la regla crítica falta.
|
|
14
|
+
- **Notification opt-out parity:** `PUMUKI_SYSTEM_NOTIFICATIONS=0` y `PUMUKI_NOTIFICATIONS=0` desactivan también el canal de notificaciones del sistema, evitando diálogos macOS en smokes/CI no interactivos.
|
|
15
|
+
- **Release validation alignment:** package smoke, metadata, framework-menu, policy y `rules_coverage.contract=AUTO_RUNTIME_RULES_FOR_STAGE` quedan alineados con la política zero-violation actual.
|
|
16
|
+
|
|
9
17
|
## [6.3.247] - 2026-05-14
|
|
10
18
|
|
|
11
19
|
### Added
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
findSwiftConcreteDependencyDipMatch,
|
|
8
8
|
findSwiftPresentationSrpMatch,
|
|
9
9
|
hasSwiftAnyViewUsage,
|
|
10
|
+
hasSwiftAsyncWithoutAwaitUsage,
|
|
10
11
|
hasSwiftCallbackStyleSignature,
|
|
11
12
|
hasSwiftCornerRadiusUsage,
|
|
12
13
|
hasSwiftDispatchGroupUsage,
|
|
@@ -14,6 +15,7 @@ import {
|
|
|
14
15
|
hasSwiftDispatchSemaphoreUsage,
|
|
15
16
|
hasSwiftAdHocLoggingUsage,
|
|
16
17
|
hasSwiftAlamofireUsage,
|
|
18
|
+
hasSwiftEmptyCatchUsage,
|
|
17
19
|
hasSwiftForEachIndicesUsage,
|
|
18
20
|
hasSwiftForEachSelfIdentityUsage,
|
|
19
21
|
hasSwiftForceCastUsage,
|
|
@@ -136,6 +138,27 @@ test('hasSwiftAnyViewUsage ignora comentarios, strings y coincidencias parciales
|
|
|
136
138
|
assert.equal(hasSwiftAnyViewUsage(source), false);
|
|
137
139
|
});
|
|
138
140
|
|
|
141
|
+
test('hasSwiftEmptyCatchUsage detecta catch vacio e ignora comentarios y strings', () => {
|
|
142
|
+
const source = `
|
|
143
|
+
do {
|
|
144
|
+
try repository.save()
|
|
145
|
+
} catch {
|
|
146
|
+
// TODO: report error
|
|
147
|
+
}
|
|
148
|
+
`;
|
|
149
|
+
const safe = `
|
|
150
|
+
let sample = "catch {}"
|
|
151
|
+
do {
|
|
152
|
+
try repository.save()
|
|
153
|
+
} catch {
|
|
154
|
+
logger.error("Save failed")
|
|
155
|
+
}
|
|
156
|
+
`;
|
|
157
|
+
|
|
158
|
+
assert.equal(hasSwiftEmptyCatchUsage(source), true);
|
|
159
|
+
assert.equal(hasSwiftEmptyCatchUsage(safe), false);
|
|
160
|
+
});
|
|
161
|
+
|
|
139
162
|
test('hasSwiftNonLazyScrollForEachUsage detecta ScrollView con stack no lazy y preserva LazyVStack', () => {
|
|
140
163
|
const source = `
|
|
141
164
|
struct FeedView: View {
|
|
@@ -1019,6 +1042,34 @@ func wait() async throws {
|
|
|
1019
1042
|
assert.equal(hasSwiftMainThreadBlockingSleepUsage(ignored), false);
|
|
1020
1043
|
});
|
|
1021
1044
|
|
|
1045
|
+
test('detector iOS de concurrencia detecta async privado sin await y evita boundaries publicos', () => {
|
|
1046
|
+
const source = `
|
|
1047
|
+
final class ProfileLoader {
|
|
1048
|
+
private func buildSnapshot() async throws -> ProfileSnapshot {
|
|
1049
|
+
ProfileSnapshot.empty
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
`;
|
|
1053
|
+
const ignored = `
|
|
1054
|
+
protocol RemoteLoader {
|
|
1055
|
+
func load() async throws -> ProfileSnapshot
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1058
|
+
final class ProfileLoader: RemoteLoader {
|
|
1059
|
+
func load() async throws -> ProfileSnapshot {
|
|
1060
|
+
ProfileSnapshot.empty
|
|
1061
|
+
}
|
|
1062
|
+
|
|
1063
|
+
private func refresh() async throws -> ProfileSnapshot {
|
|
1064
|
+
try await api.load()
|
|
1065
|
+
}
|
|
1066
|
+
}
|
|
1067
|
+
`;
|
|
1068
|
+
|
|
1069
|
+
assert.equal(hasSwiftAsyncWithoutAwaitUsage(source), true);
|
|
1070
|
+
assert.equal(hasSwiftAsyncWithoutAwaitUsage(ignored), false);
|
|
1071
|
+
});
|
|
1072
|
+
|
|
1022
1073
|
test('detector iOS de accesibilidad detecta botones icon-only sin label explicita', () => {
|
|
1023
1074
|
const source = `
|
|
1024
1075
|
struct ToolbarView: View {
|
|
@@ -476,6 +476,53 @@ export const hasSwiftTaskDetachedUsage = (source: string): boolean => {
|
|
|
476
476
|
});
|
|
477
477
|
};
|
|
478
478
|
|
|
479
|
+
const findMatchingSwiftBrace = (source: string, openBraceIndex: number): number => {
|
|
480
|
+
let depth = 0;
|
|
481
|
+
for (let index = openBraceIndex; index < source.length; index += 1) {
|
|
482
|
+
const current = source[index];
|
|
483
|
+
if (current === '{') {
|
|
484
|
+
depth += 1;
|
|
485
|
+
} else if (current === '}') {
|
|
486
|
+
depth -= 1;
|
|
487
|
+
if (depth === 0) {
|
|
488
|
+
return index;
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
return -1;
|
|
493
|
+
};
|
|
494
|
+
|
|
495
|
+
export const hasSwiftAsyncWithoutAwaitUsage = (source: string): boolean => {
|
|
496
|
+
const sanitized = sanitizeSwiftSourceForMultilineRegex(source);
|
|
497
|
+
const privateAsyncFunctionPattern =
|
|
498
|
+
/\bprivate\s+(?:static\s+|class\s+)?func\s+[A-Za-z_][A-Za-z0-9_]*[^{};]*\basync\b[^{};]*\{/g;
|
|
499
|
+
|
|
500
|
+
for (const match of sanitized.matchAll(privateAsyncFunctionPattern)) {
|
|
501
|
+
const header = match[0] ?? '';
|
|
502
|
+
if (/\boverride\b|\bprotocol\b/.test(header)) {
|
|
503
|
+
continue;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
const openBraceIndex = (match.index ?? 0) + header.length - 1;
|
|
507
|
+
const closeBraceIndex = findMatchingSwiftBrace(sanitized, openBraceIndex);
|
|
508
|
+
if (closeBraceIndex < 0) {
|
|
509
|
+
continue;
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
const body = sanitized.slice(openBraceIndex + 1, closeBraceIndex);
|
|
513
|
+
if (!/\bawait\b/.test(body)) {
|
|
514
|
+
return true;
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
return false;
|
|
519
|
+
};
|
|
520
|
+
|
|
521
|
+
export const hasSwiftEmptyCatchUsage = (source: string): boolean => {
|
|
522
|
+
const sanitized = sanitizeSwiftSourceForMultilineRegex(source);
|
|
523
|
+
return /\bcatch(?:\s+(?:let|var)\s+[A-Za-z_][A-Za-z0-9_]*)?\s*\{\s*\}/.test(sanitized);
|
|
524
|
+
};
|
|
525
|
+
|
|
479
526
|
export const hasSwiftOnAppearTaskUsage = (source: string): boolean => {
|
|
480
527
|
const sanitized = sanitizeSwiftSourceForMultilineRegex(source);
|
|
481
528
|
return /\.onAppear\s*\{[\s\S]{0,500}?\bTask\s*(?:\([^)]*\))?\s*\{/.test(sanitized);
|
|
@@ -646,6 +646,8 @@ const textDetectorRegistry: ReadonlyArray<TextDetectorRegistryEntry> = [
|
|
|
646
646
|
{ platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftDispatchSemaphoreUsage, ruleId: 'heuristics.ios.dispatchsemaphore.ast', code: 'HEURISTICS_IOS_DISPATCHSEMAPHORE_AST', message: 'AST heuristic detected DispatchSemaphore usage.' },
|
|
647
647
|
{ platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftOperationQueueUsage, ruleId: 'heuristics.ios.operation-queue.ast', code: 'HEURISTICS_IOS_OPERATION_QUEUE_AST', message: 'AST heuristic detected OperationQueue usage.' },
|
|
648
648
|
{ platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftTaskDetachedUsage, ruleId: 'heuristics.ios.task-detached.ast', code: 'HEURISTICS_IOS_TASK_DETACHED_AST', message: 'AST heuristic detected Task.detached usage.' },
|
|
649
|
+
{ platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftAsyncWithoutAwaitUsage, ruleId: 'heuristics.ios.concurrency.async-without-await.ast', code: 'HEURISTICS_IOS_CONCURRENCY_ASYNC_WITHOUT_AWAIT_AST', message: 'AST heuristic detected a private async function without await; remove async unless a protocol/override boundary requires it.' },
|
|
650
|
+
{ platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftEmptyCatchUsage, ruleId: 'heuristics.ios.error.empty-catch.ast', code: 'HEURISTICS_IOS_ERROR_EMPTY_CATCH_AST', message: 'AST heuristic detected an empty Swift catch block; handle, log, or propagate the error.' },
|
|
649
651
|
{ platform: 'ios', pathCheck: isIOSPresentationPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftOnAppearTaskUsage, ruleId: 'heuristics.ios.swiftui.onappear-task.ast', code: 'HEURISTICS_IOS_SWIFTUI_ONAPPEAR_TASK_AST', message: 'AST heuristic detected Task launched from SwiftUI onAppear; .task/.task(id:) provides lifecycle-aware cancellation.' },
|
|
650
652
|
{ platform: 'ios', pathCheck: isIOSPresentationPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftOnChangeTaskUsage, ruleId: 'heuristics.ios.swiftui.onchange-task.ast', code: 'HEURISTICS_IOS_SWIFTUI_ONCHANGE_TASK_AST', message: 'AST heuristic detected Task launched from SwiftUI onChange; .task(id:) provides lifecycle-aware cancellation for value-dependent async work.' },
|
|
651
653
|
{ platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftStrongDelegateReferenceUsage, ruleId: 'heuristics.ios.memory.strong-delegate.ast', code: 'HEURISTICS_IOS_MEMORY_STRONG_DELEGATE_AST', message: 'AST heuristic detected a strong delegate/dataSource reference; weak delegates remain the preferred baseline to avoid retain cycles.' },
|
|
@@ -3,7 +3,7 @@ import test from 'node:test';
|
|
|
3
3
|
import { iosRules } from './ios';
|
|
4
4
|
|
|
5
5
|
test('iosRules define reglas heurísticas locked para plataforma ios', () => {
|
|
6
|
-
assert.equal(iosRules.length,
|
|
6
|
+
assert.equal(iosRules.length, 88);
|
|
7
7
|
|
|
8
8
|
const ids = iosRules.map((rule) => rule.id);
|
|
9
9
|
assert.deepEqual(ids, [
|
|
@@ -17,6 +17,8 @@ test('iosRules define reglas heurísticas locked para plataforma ios', () => {
|
|
|
17
17
|
'heuristics.ios.dispatchsemaphore.ast',
|
|
18
18
|
'heuristics.ios.operation-queue.ast',
|
|
19
19
|
'heuristics.ios.task-detached.ast',
|
|
20
|
+
'heuristics.ios.concurrency.async-without-await.ast',
|
|
21
|
+
'heuristics.ios.error.empty-catch.ast',
|
|
20
22
|
'heuristics.ios.swiftui.onappear-task.ast',
|
|
21
23
|
'heuristics.ios.swiftui.onchange-task.ast',
|
|
22
24
|
'heuristics.ios.memory.strong-delegate.ast',
|
|
@@ -104,6 +106,14 @@ test('iosRules define reglas heurísticas locked para plataforma ios', () => {
|
|
|
104
106
|
byId.get('heuristics.ios.task-detached.ast')?.then.code,
|
|
105
107
|
'HEURISTICS_IOS_TASK_DETACHED_AST'
|
|
106
108
|
);
|
|
109
|
+
assert.equal(
|
|
110
|
+
byId.get('heuristics.ios.concurrency.async-without-await.ast')?.then.code,
|
|
111
|
+
'HEURISTICS_IOS_CONCURRENCY_ASYNC_WITHOUT_AWAIT_AST'
|
|
112
|
+
);
|
|
113
|
+
assert.equal(
|
|
114
|
+
byId.get('heuristics.ios.error.empty-catch.ast')?.then.code,
|
|
115
|
+
'HEURISTICS_IOS_ERROR_EMPTY_CATCH_AST'
|
|
116
|
+
);
|
|
107
117
|
assert.equal(
|
|
108
118
|
byId.get('heuristics.ios.swiftui.onchange-task.ast')?.then.code,
|
|
109
119
|
'HEURISTICS_IOS_SWIFTUI_ONCHANGE_TASK_AST'
|
|
@@ -181,6 +181,43 @@ export const iosRules: RuleSet = [
|
|
|
181
181
|
code: 'HEURISTICS_IOS_TASK_DETACHED_AST',
|
|
182
182
|
},
|
|
183
183
|
},
|
|
184
|
+
{
|
|
185
|
+
id: 'heuristics.ios.concurrency.async-without-await.ast',
|
|
186
|
+
description: 'Detects private async functions that do not await in iOS production code.',
|
|
187
|
+
severity: 'WARN',
|
|
188
|
+
platform: 'ios',
|
|
189
|
+
locked: true,
|
|
190
|
+
when: {
|
|
191
|
+
kind: 'Heuristic',
|
|
192
|
+
where: {
|
|
193
|
+
ruleId: 'heuristics.ios.concurrency.async-without-await.ast',
|
|
194
|
+
},
|
|
195
|
+
},
|
|
196
|
+
then: {
|
|
197
|
+
kind: 'Finding',
|
|
198
|
+
message:
|
|
199
|
+
'AST heuristic detected a private async function without await; remove async unless a protocol/override boundary requires it.',
|
|
200
|
+
code: 'HEURISTICS_IOS_CONCURRENCY_ASYNC_WITHOUT_AWAIT_AST',
|
|
201
|
+
},
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
id: 'heuristics.ios.error.empty-catch.ast',
|
|
205
|
+
description: 'Detects Swift catch blocks that silently swallow errors.',
|
|
206
|
+
severity: 'WARN',
|
|
207
|
+
platform: 'ios',
|
|
208
|
+
locked: true,
|
|
209
|
+
when: {
|
|
210
|
+
kind: 'Heuristic',
|
|
211
|
+
where: {
|
|
212
|
+
ruleId: 'heuristics.ios.error.empty-catch.ast',
|
|
213
|
+
},
|
|
214
|
+
},
|
|
215
|
+
then: {
|
|
216
|
+
kind: 'Finding',
|
|
217
|
+
message: 'AST heuristic detected an empty Swift catch block.',
|
|
218
|
+
code: 'HEURISTICS_IOS_ERROR_EMPTY_CATCH_AST',
|
|
219
|
+
},
|
|
220
|
+
},
|
|
184
221
|
{
|
|
185
222
|
id: 'heuristics.ios.swiftui.onappear-task.ast',
|
|
186
223
|
description: 'Detects Task launches from SwiftUI onAppear where .task can provide lifecycle cancellation.',
|
|
@@ -6,6 +6,13 @@ This file keeps only the operational highlights and rollout notes that matter wh
|
|
|
6
6
|
|
|
7
7
|
## 2026-04 (CLI stability and macOS notifications)
|
|
8
8
|
|
|
9
|
+
### 2026-05-14 (v6.3.248)
|
|
10
|
+
|
|
11
|
+
- **Normalización iOS mode-aware:** la línea activa conserva reglas iOS automatizables con evidencia concreta y deja como declarativas las reglas greenfield/brownfield que requieren contexto de adopción, baseline o migración.
|
|
12
|
+
- **Package smoke estable para fixtures Git:** los commits y pushes internos de preparación del consumer smoke no disparan hooks del paquete bajo prueba; el gate real sigue validándose en los pasos explícitos del smoke.
|
|
13
|
+
- **Smokes no interactivos sin diálogos macOS:** `PUMUKI_SYSTEM_NOTIFICATIONS=0` y `PUMUKI_NOTIFICATIONS=0` vuelven a apagar el canal de sistema, evitando bloqueos por Swift dialog en validaciones de release.
|
|
14
|
+
- **Rollout recomendado:** publicar `pumuki@6.3.248` tras el test suite global verde; `validation:package-smoke`, metadata local y `PRE_WRITE` strict/advisory quedan alineados para esta versión.
|
|
15
|
+
|
|
9
16
|
### 2026-04-25 (v6.3.116)
|
|
10
17
|
|
|
11
18
|
- **Inventario local real de dependencias:** `status` y `doctor` conservan `trackedNodeModules*` como señal estricta de seguridad Git y añaden `dependencyInventory` como fuente de verdad de instalación local.
|
|
@@ -108,6 +108,16 @@ export const skillsCompilerTemplates: Record<string, SkillsCompilerTemplate> = {
|
|
|
108
108
|
stage: 'PRE_PUSH',
|
|
109
109
|
locked: true,
|
|
110
110
|
},
|
|
111
|
+
{
|
|
112
|
+
id: 'skills.ios.no-async-without-await',
|
|
113
|
+
description:
|
|
114
|
+
'Avoid private async functions without await; remove async unless a protocol or override boundary requires it.',
|
|
115
|
+
severity: 'WARN',
|
|
116
|
+
platform: 'ios',
|
|
117
|
+
confidence: 'MEDIUM',
|
|
118
|
+
stage: 'PRE_PUSH',
|
|
119
|
+
locked: true,
|
|
120
|
+
},
|
|
111
121
|
{
|
|
112
122
|
id: 'skills.ios.no-unchecked-sendable',
|
|
113
123
|
description: 'Avoid @unchecked Sendable in production iOS code without strict safety invariant.',
|
|
@@ -47,6 +47,9 @@ const registryByRuleId: Record<string, SkillsDetectorBinding> = {
|
|
|
47
47
|
'skills.ios.no-task-detached': heuristicDetector('ios.task-detached', [
|
|
48
48
|
'heuristics.ios.task-detached.ast',
|
|
49
49
|
]),
|
|
50
|
+
'skills.ios.no-async-without-await': heuristicDetector('ios.concurrency.async-without-await', [
|
|
51
|
+
'heuristics.ios.concurrency.async-without-await.ast',
|
|
52
|
+
]),
|
|
50
53
|
'skills.ios.guideline.ios.delegation-pattern-weak-delegates-para-evitar-retain-cycles': heuristicDetector(
|
|
51
54
|
'ios.memory.strong-delegate',
|
|
52
55
|
['heuristics.ios.memory.strong-delegate.ast']
|
|
@@ -58,6 +61,13 @@ const registryByRuleId: Record<string, SkillsDetectorBinding> = {
|
|
|
58
61
|
'heuristics.ios.memory.strong-self-escaping-closure.ast',
|
|
59
62
|
]
|
|
60
63
|
),
|
|
64
|
+
'skills.ios.guideline.ios.retain-cycles-memory-leaks': heuristicDetector(
|
|
65
|
+
'ios.memory.retain-cycles',
|
|
66
|
+
[
|
|
67
|
+
'heuristics.ios.memory.strong-delegate.ast',
|
|
68
|
+
'heuristics.ios.memory.strong-self-escaping-closure.ast',
|
|
69
|
+
]
|
|
70
|
+
),
|
|
61
71
|
'skills.ios.guideline.ios.no-singleton-usar-inyeccio-n-de-dependencias-no-compartir-instancias-g': heuristicDetector(
|
|
62
72
|
'ios.architecture.custom-singleton',
|
|
63
73
|
['heuristics.ios.architecture.custom-singleton.ast']
|
|
@@ -98,6 +108,10 @@ const registryByRuleId: Record<string, SkillsDetectorBinding> = {
|
|
|
98
108
|
'ios.logging.adhoc-print',
|
|
99
109
|
['heuristics.ios.logging.adhoc-print.ast']
|
|
100
110
|
),
|
|
111
|
+
'skills.ios.guideline.ios.catch-vaci-os-prohibido-silenciar-errores-ast-common-error-emptycatch': heuristicDetector(
|
|
112
|
+
'ios.error.empty-catch',
|
|
113
|
+
['heuristics.ios.error.empty-catch.ast']
|
|
114
|
+
),
|
|
101
115
|
'skills.ios.guideline.ios.no-loggear-pii-tokens-emails-ids-sensibles': heuristicDetector(
|
|
102
116
|
'ios.logging.sensitive-data',
|
|
103
117
|
['heuristics.ios.logging.sensitive-data.ast']
|
|
@@ -110,10 +124,6 @@ const registryByRuleId: Record<string, SkillsDetectorBinding> = {
|
|
|
110
124
|
'ios.localization.unlocalized-dateformatter',
|
|
111
125
|
['heuristics.ios.localization.unlocalized-dateformatter.ast']
|
|
112
126
|
),
|
|
113
|
-
'skills.ios.guideline.ios.alamofire-prohibido-usar-urlsession-nativo': heuristicDetector(
|
|
114
|
-
'ios.networking.alamofire',
|
|
115
|
-
['heuristics.ios.networking.alamofire.ast']
|
|
116
|
-
),
|
|
117
127
|
'skills.ios.guideline.ios.codable-decodificacio-n-automa-tica-de-json-nunca-jsonserialization': heuristicDetector(
|
|
118
128
|
'ios.json.jsonserialization',
|
|
119
129
|
['heuristics.ios.json.jsonserialization.ast']
|
|
@@ -122,14 +132,6 @@ const registryByRuleId: Record<string, SkillsDetectorBinding> = {
|
|
|
122
132
|
'ios.json.jsonserialization',
|
|
123
133
|
['heuristics.ios.json.jsonserialization.ast']
|
|
124
134
|
),
|
|
125
|
-
'skills.ios.guideline.ios.cocoapods-prohibido': heuristicDetector(
|
|
126
|
-
'ios.dependencies.cocoapods',
|
|
127
|
-
['heuristics.ios.dependencies.cocoapods.ast']
|
|
128
|
-
),
|
|
129
|
-
'skills.ios.guideline.ios.carthage-prohibido': heuristicDetector(
|
|
130
|
-
'ios.dependencies.carthage',
|
|
131
|
-
['heuristics.ios.dependencies.carthage.ast']
|
|
132
|
-
),
|
|
133
135
|
'skills.ios.guideline.ios.keychain-passwords-tokens-no-userdefaults': heuristicDetector(
|
|
134
136
|
'ios.security.userdefaults-sensitive-data',
|
|
135
137
|
['heuristics.ios.security.userdefaults-sensitive-data.ast']
|
|
@@ -146,18 +148,6 @@ const registryByRuleId: Record<string, SkillsDetectorBinding> = {
|
|
|
146
148
|
'ios.security.insecure-transport',
|
|
147
149
|
['heuristics.ios.security.insecure-transport.ast']
|
|
148
150
|
),
|
|
149
|
-
'skills.ios.guideline.ios.localizable-strings-deprecado-usar-string-catalogs': heuristicDetector(
|
|
150
|
-
'ios.localization.localizable-strings',
|
|
151
|
-
['heuristics.ios.localization.localizable-strings.ast']
|
|
152
|
-
),
|
|
153
|
-
'skills.ios.guideline.ios.string-catalogs-xcstrings': heuristicDetector(
|
|
154
|
-
'ios.localization.localizable-strings',
|
|
155
|
-
['heuristics.ios.localization.localizable-strings.ast']
|
|
156
|
-
),
|
|
157
|
-
'skills.ios.guideline.ios.string-catalogs-xcstrings-sistema-moderno-de-localizacio-n-xcode-15': heuristicDetector(
|
|
158
|
-
'ios.localization.localizable-strings',
|
|
159
|
-
['heuristics.ios.localization.localizable-strings.ast']
|
|
160
|
-
),
|
|
161
151
|
'skills.ios.guideline.ios.cero-strings-hardcodeadas-en-ui': heuristicDetector(
|
|
162
152
|
'ios.localization.hardcoded-ui-string',
|
|
163
153
|
['heuristics.ios.localization.hardcoded-ui-string.ast']
|
|
@@ -233,6 +233,13 @@ const normalizeKnownRuleTarget = (
|
|
|
233
233
|
if (includes('task detached') || includes('task.detached')) {
|
|
234
234
|
return 'skills.ios.no-task-detached';
|
|
235
235
|
}
|
|
236
|
+
if (
|
|
237
|
+
includes('remove async if not required') ||
|
|
238
|
+
includes('async without await') ||
|
|
239
|
+
includes('async_without_await')
|
|
240
|
+
) {
|
|
241
|
+
return 'skills.ios.no-async-without-await';
|
|
242
|
+
}
|
|
236
243
|
if (includes('unchecked sendable')) {
|
|
237
244
|
return 'skills.ios.no-unchecked-sendable';
|
|
238
245
|
}
|
|
@@ -491,6 +498,12 @@ const normalizeKnownRuleTarget = (
|
|
|
491
498
|
if (includes('uiscreen main bounds') || includes('uiscreen.main.bounds')) {
|
|
492
499
|
return 'skills.ios.no-uiscreen-main-bounds';
|
|
493
500
|
}
|
|
501
|
+
if (
|
|
502
|
+
(includes('task id') && includes('value dependent')) ||
|
|
503
|
+
(includes('task id') && includes('value-dependent'))
|
|
504
|
+
) {
|
|
505
|
+
return 'skills.ios.guideline.ios-swiftui-expert.use-task-id-for-value-dependent-tasks';
|
|
506
|
+
}
|
|
494
507
|
if (
|
|
495
508
|
includes('task/.task(id') ||
|
|
496
509
|
includes('trabajos async con cancelacion automatica') ||
|
|
@@ -500,15 +513,127 @@ const normalizeKnownRuleTarget = (
|
|
|
500
513
|
) {
|
|
501
514
|
return 'skills.ios.guideline.ios-swiftui-expert.use-task-modifier-for-automatic-cancellation-of-async-work';
|
|
502
515
|
}
|
|
516
|
+
if (includes('jsonserialization')) {
|
|
517
|
+
if (includes('decodificacion automatica') || includes('decoding')) {
|
|
518
|
+
return 'skills.ios.guideline.ios.codable-decodificacio-n-automa-tica-de-json-nunca-jsonserialization';
|
|
519
|
+
}
|
|
520
|
+
if (includes('codable')) {
|
|
521
|
+
return 'skills.ios.guideline.ios.codable-para-serializacio-n-json-nunca-jsonserialization';
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
if (
|
|
525
|
+
(includes('keychain') && includes('userdefaults')) ||
|
|
526
|
+
(includes('passwords') && includes('tokens') && includes('userdefaults'))
|
|
527
|
+
) {
|
|
528
|
+
return 'skills.ios.guideline.ios.keychain-passwords-tokens-no-userdefaults';
|
|
529
|
+
}
|
|
530
|
+
if (includes('userdefaults') && includes('no datos sensibles')) {
|
|
531
|
+
return 'skills.ios.guideline.ios.userdefaults-settings-simples-no-datos-sensibles';
|
|
532
|
+
}
|
|
533
|
+
if (
|
|
534
|
+
includes('print y logs ad hoc') ||
|
|
535
|
+
includes('print() y logs ad hoc') ||
|
|
536
|
+
includes('logs ad hoc')
|
|
537
|
+
) {
|
|
538
|
+
return 'skills.ios.guideline.ios.prohibido-print-y-logs-ad-hoc';
|
|
539
|
+
}
|
|
540
|
+
if (
|
|
541
|
+
includes('catch vac') ||
|
|
542
|
+
includes('catch vaci') ||
|
|
543
|
+
includes('emptycatch') ||
|
|
544
|
+
includes('empty catch')
|
|
545
|
+
) {
|
|
546
|
+
return 'skills.ios.guideline.ios.catch-vaci-os-prohibido-silenciar-errores-ast-common-error-emptycatch';
|
|
547
|
+
}
|
|
548
|
+
if (includes('no loggear pii') || includes('tokens emails ids sensibles')) {
|
|
549
|
+
return 'skills.ios.guideline.ios.no-loggear-pii-tokens-emails-ids-sensibles';
|
|
550
|
+
}
|
|
551
|
+
if (includes('obfuscation') && includes('strings sensibles')) {
|
|
552
|
+
return 'skills.ios.guideline.ios.obfuscation-strings-sensibles-en-co-digo';
|
|
553
|
+
}
|
|
554
|
+
if (includes('dateformatter') && includes('fechas localizadas')) {
|
|
555
|
+
return 'skills.ios.guideline.ios.dateformatter-fechas-localizadas';
|
|
556
|
+
}
|
|
557
|
+
if (includes('strings hardcodeadas') && includes('ui')) {
|
|
558
|
+
return 'skills.ios.guideline.ios.cero-strings-hardcodeadas-en-ui';
|
|
559
|
+
}
|
|
560
|
+
if (includes('assets en asset catalogs')) {
|
|
561
|
+
return 'skills.ios.guideline.ios.assets-en-asset-catalogs-con-soporte-para-todos-los-taman-os';
|
|
562
|
+
}
|
|
563
|
+
if (includes('dynamic type') && includes('font scaling')) {
|
|
564
|
+
return 'skills.ios.guideline.ios.dynamic-type-font-scaling-automa-tico';
|
|
565
|
+
}
|
|
566
|
+
if (includes('dynamic type') && includes('fuentes escalables')) {
|
|
567
|
+
return 'skills.ios.guideline.ios.dynamic-type-fuentes-escalables-y-layouts-adaptativos';
|
|
568
|
+
}
|
|
569
|
+
if (includes('rtl support') || includes('right to left')) {
|
|
570
|
+
return 'skills.ios.guideline.ios.rtl-support-right-to-left-para-a-rabe-hebreo';
|
|
571
|
+
}
|
|
572
|
+
if (includes('background threads') && includes('no bloquear main thread')) {
|
|
573
|
+
return 'skills.ios.guideline.ios.background-threads-no-bloquear-main-thread';
|
|
574
|
+
}
|
|
575
|
+
if (includes('accessibility labels') || includes('accessibilitylabel')) {
|
|
576
|
+
return 'skills.ios.guideline.ios.accessibility-labels-accessibilitylabel';
|
|
577
|
+
}
|
|
578
|
+
if (includes('delegation pattern') && includes('weak delegates')) {
|
|
579
|
+
return 'skills.ios.guideline.ios.delegation-pattern-weak-delegates-para-evitar-retain-cycles';
|
|
580
|
+
}
|
|
581
|
+
if (includes('retain cycles') && includes('memory leaks')) {
|
|
582
|
+
return 'skills.ios.guideline.ios.retain-cycles-memory-leaks';
|
|
583
|
+
}
|
|
584
|
+
if (includes('retain cycles') && includes('closures')) {
|
|
585
|
+
return 'skills.ios.guideline.ios.evitar-retain-cycles-especialmente-en-closures-delegates';
|
|
586
|
+
}
|
|
587
|
+
if (includes('no singleton') || includes('no singletons')) {
|
|
588
|
+
return 'skills.ios.guideline.ios.no-singleton-usar-inyeccio-n-de-dependencias-no-compartir-instancias-g';
|
|
589
|
+
}
|
|
590
|
+
if (includes('massive view controllers')) {
|
|
591
|
+
return 'skills.ios.guideline.ios.massive-view-controllers-viewcontrollers-que-mezclan-presentacio-n-nav';
|
|
592
|
+
}
|
|
593
|
+
if (includes('implicitly unwrapped')) {
|
|
594
|
+
return 'skills.ios.guideline.ios.implicitly-unwrapped-solo-para-iboutlets-y-casos-muy-especi-ficos';
|
|
595
|
+
}
|
|
596
|
+
if (includes('magic numbers')) {
|
|
597
|
+
return 'skills.ios.guideline.ios.magic-numbers-usar-constantes-con-nombres';
|
|
598
|
+
}
|
|
599
|
+
if (includes('swinject')) {
|
|
600
|
+
return 'skills.ios.guideline.ios.swinject-prohibido-di-manual-o-environment';
|
|
601
|
+
}
|
|
602
|
+
if (
|
|
603
|
+
includes('navigationstack navigationpath') ||
|
|
604
|
+
includes('navigationstack + navigationpath')
|
|
605
|
+
) {
|
|
606
|
+
return 'skills.ios.no-navigation-view';
|
|
607
|
+
}
|
|
608
|
+
if (
|
|
609
|
+
includes('onchange') &&
|
|
610
|
+
(includes('2 parametros') || includes('2 para metros') || includes('sin parametros'))
|
|
611
|
+
) {
|
|
612
|
+
return 'skills.ios.no-legacy-onchange';
|
|
613
|
+
}
|
|
614
|
+
if (
|
|
615
|
+
includes('lazyvstack lazyhstack') ||
|
|
616
|
+
(includes('lazy loading') && includes('lazyvstack'))
|
|
617
|
+
) {
|
|
618
|
+
return 'skills.ios.guideline.ios-swiftui-expert.use-lazyvstack-lazyhstack-for-large-lists';
|
|
619
|
+
}
|
|
620
|
+
if (includes('singletons') && includes('dificultan testing')) {
|
|
621
|
+
return 'skills.ios.guideline.ios.singletons-dificultan-testing';
|
|
622
|
+
}
|
|
503
623
|
if (
|
|
504
624
|
includes('swift testing over xctest') ||
|
|
505
625
|
includes('prefer import testing') ||
|
|
506
626
|
includes('prefer test functions over test methods') ||
|
|
507
627
|
includes('test functions over test methods') ||
|
|
508
628
|
includes('xctest-only unit tests') ||
|
|
629
|
+
includes('xctest only unit tests') ||
|
|
509
630
|
includes('new xctest-only unit tests') ||
|
|
631
|
+
includes('new xctest only unit tests') ||
|
|
510
632
|
includes('xctest only for ui') ||
|
|
511
|
-
includes('xctest only for ui performance')
|
|
633
|
+
includes('xctest only for ui performance') ||
|
|
634
|
+
(includes('xctest solo') && includes('legacy')) ||
|
|
635
|
+
(includes('xctest') && includes('solo para proyectos legacy')) ||
|
|
636
|
+
(includes('xctest') && includes('ui tests'))
|
|
512
637
|
) {
|
|
513
638
|
return 'skills.ios.prefer-swift-testing';
|
|
514
639
|
}
|
|
@@ -539,13 +664,6 @@ const normalizeKnownRuleTarget = (
|
|
|
539
664
|
) {
|
|
540
665
|
return 'skills.ios.guideline.ios.app-transport-security-ats-https-por-defecto';
|
|
541
666
|
}
|
|
542
|
-
if (
|
|
543
|
-
includes('localizable strings') ||
|
|
544
|
-
includes('string catalogs') ||
|
|
545
|
-
includes('xcstrings')
|
|
546
|
-
) {
|
|
547
|
-
return 'skills.ios.guideline.ios.localizable-strings-deprecado-usar-string-catalogs';
|
|
548
|
-
}
|
|
549
667
|
if (includes('strings hardcodeadas') || includes('string localized')) {
|
|
550
668
|
return 'skills.ios.guideline.ios.cero-strings-hardcodeadas-en-ui';
|
|
551
669
|
}
|
|
@@ -646,9 +764,16 @@ const normalizeKnownRuleTarget = (
|
|
|
646
764
|
}
|
|
647
765
|
if (
|
|
648
766
|
includes('nsmanagedobject across boundaries') ||
|
|
767
|
+
includes('nsmanagedobjectid or mapped dto') ||
|
|
768
|
+
includes('mapped dto domain models') ||
|
|
649
769
|
includes('passing nsmanagedobject') ||
|
|
770
|
+
includes('pass nsmanagedobjectid when a different context') ||
|
|
650
771
|
includes('nsmanagedobject through service') ||
|
|
651
|
-
includes('nsmanagedobject in shared function and property boundaries')
|
|
772
|
+
includes('nsmanagedobject in shared function and property boundaries') ||
|
|
773
|
+
includes('managed objects as context scoped references') ||
|
|
774
|
+
includes('not as portable domain entities') ||
|
|
775
|
+
includes('managed objects into domain models before crossing module boundaries') ||
|
|
776
|
+
includes('map managed objects into domain models')
|
|
652
777
|
) {
|
|
653
778
|
return 'skills.ios.no-nsmanagedobject-boundary';
|
|
654
779
|
}
|
|
@@ -670,6 +795,8 @@ const normalizeKnownRuleTarget = (
|
|
|
670
795
|
}
|
|
671
796
|
if (
|
|
672
797
|
includes('core data orchestration inside infrastructure') ||
|
|
798
|
+
includes('make context ownership explicit') ||
|
|
799
|
+
includes('merge boundaries controlled') ||
|
|
673
800
|
includes('instead of presentation code') ||
|
|
674
801
|
includes('core data apis in application or presentation code') ||
|
|
675
802
|
includes('avoid core data apis in application or presentation code') ||
|
|
@@ -151,7 +151,7 @@ const PLATFORM_REQUIRED_SKILLS_BUNDLES: Readonly<Record<PreWriteSkillsPlatform,
|
|
|
151
151
|
frontend: ['frontend-guidelines'],
|
|
152
152
|
};
|
|
153
153
|
const PREWRITE_CRITICAL_SKILLS_RULES: Readonly<Record<PreWriteSkillsPlatform, ReadonlyArray<string>>> = {
|
|
154
|
-
ios: [],
|
|
154
|
+
ios: ['skills.ios.critical-test-quality'],
|
|
155
155
|
android: [],
|
|
156
156
|
backend: [],
|
|
157
157
|
frontend: [],
|
|
@@ -644,7 +644,8 @@ const collectPreWritePlatformSkillsViolations = (params: {
|
|
|
644
644
|
|
|
645
645
|
if (missingCriticalRulesByPlatform.length > 0) {
|
|
646
646
|
violations.push(
|
|
647
|
-
|
|
647
|
+
toSkillsViolation(
|
|
648
|
+
params.skillsEnforcement,
|
|
648
649
|
'EVIDENCE_PLATFORM_CRITICAL_SKILLS_RULES_MISSING',
|
|
649
650
|
`Detected platforms missing critical skill-rule enforcement in PRE_WRITE: ${missingCriticalRulesByPlatform.join(' | ')}.`
|
|
650
651
|
)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pumuki",
|
|
3
|
-
"version": "6.3.
|
|
3
|
+
"version": "6.3.248",
|
|
4
4
|
"description": "Enterprise-grade AST Intelligence System with multi-platform support (iOS, Android, Backend, Frontend) and Feature-First + DDD + Clean Architecture enforcement. Includes dynamic violations API for intelligent querying.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -156,6 +156,11 @@ const runMenuAuditGate = async (
|
|
|
156
156
|
await defaultDependencies.runPlatformGate({
|
|
157
157
|
...gateParams,
|
|
158
158
|
auditMode: 'engine',
|
|
159
|
+
sddDecisionOverride: {
|
|
160
|
+
allowed: true,
|
|
161
|
+
code: 'ALLOWED',
|
|
162
|
+
message: 'Framework menu audit gate runs without implicit SDD/OpenSpec bootstrap.',
|
|
163
|
+
},
|
|
159
164
|
dependencies: {
|
|
160
165
|
printGateFindings: () => {},
|
|
161
166
|
evaluatePlatformGateFindings: (params) =>
|
|
@@ -5,12 +5,24 @@ import type {
|
|
|
5
5
|
} from './framework-menu-system-notifications-types';
|
|
6
6
|
import { isTruthyEnvValue } from './framework-menu-system-notifications-env';
|
|
7
7
|
|
|
8
|
+
const isDisabledEnvValue = (value?: string): boolean => {
|
|
9
|
+
if (!value) {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
const normalized = value.trim().toLowerCase();
|
|
13
|
+
return normalized === '0' || normalized === 'false' || normalized === 'no' || normalized === 'off';
|
|
14
|
+
};
|
|
15
|
+
|
|
8
16
|
export const resolveSystemNotificationGate = (params: {
|
|
9
17
|
config: SystemNotificationsConfig;
|
|
10
18
|
nowMs: number;
|
|
11
19
|
env?: NodeJS.ProcessEnv;
|
|
12
20
|
}): SystemNotificationEmitResult | null => {
|
|
13
|
-
if (
|
|
21
|
+
if (
|
|
22
|
+
isTruthyEnvValue(params.env?.PUMUKI_DISABLE_SYSTEM_NOTIFICATIONS) ||
|
|
23
|
+
isDisabledEnvValue(params.env?.PUMUKI_SYSTEM_NOTIFICATIONS) ||
|
|
24
|
+
isDisabledEnvValue(params.env?.PUMUKI_NOTIFICATIONS)
|
|
25
|
+
) {
|
|
14
26
|
return { delivered: false, reason: 'disabled' };
|
|
15
27
|
}
|
|
16
28
|
if (!params.config.enabled) {
|
|
@@ -13,7 +13,11 @@ export const commitBaseline = (
|
|
|
13
13
|
): void => {
|
|
14
14
|
writeBaselineFile(workspace.consumerRepo);
|
|
15
15
|
runGitStep(workspace, ['add', '.'], 'git add baseline');
|
|
16
|
-
runGitStep(
|
|
16
|
+
runGitStep(
|
|
17
|
+
workspace,
|
|
18
|
+
['commit', '--no-verify', '-m', 'chore: baseline'],
|
|
19
|
+
'git commit baseline'
|
|
20
|
+
);
|
|
17
21
|
};
|
|
18
22
|
|
|
19
23
|
export const writeAndCommitRangePayloadForBlockMode = (
|
|
@@ -28,7 +32,7 @@ export const writeAndCommitRangePayloadForBlockMode = (
|
|
|
28
32
|
runGitStep(workspace, ['add', '.'], 'git add range payload');
|
|
29
33
|
runGitStep(
|
|
30
34
|
workspace,
|
|
31
|
-
['commit', '-m', 'test: range payload for package smoke'],
|
|
35
|
+
['commit', '--no-verify', '-m', 'test: range payload for package smoke'],
|
|
32
36
|
'git commit range payload'
|
|
33
37
|
);
|
|
34
38
|
};
|
|
@@ -39,7 +39,7 @@ export const configureRemoteAndFeatureBranch = (
|
|
|
39
39
|
workspace.tmpRoot
|
|
40
40
|
);
|
|
41
41
|
runGitStep(workspace, ['remote', 'add', 'origin', workspace.bareRemote], 'git remote add origin');
|
|
42
|
-
runGitStep(workspace, ['push', '-u', 'origin', 'main'], 'git push origin main');
|
|
42
|
+
runGitStep(workspace, ['push', '--no-verify', '-u', 'origin', 'main'], 'git push origin main');
|
|
43
43
|
runGitStep(workspace, ['checkout', '-b', 'feature/package-smoke'], 'git checkout feature branch');
|
|
44
44
|
runGitStep(
|
|
45
45
|
workspace,
|
package/skills.lock.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": "1.0",
|
|
3
3
|
"compilerVersion": "1.0.0",
|
|
4
|
-
"generatedAt": "2026-05-
|
|
4
|
+
"generatedAt": "2026-05-14T09:20:03.683Z",
|
|
5
5
|
"bundles": [
|
|
6
6
|
{
|
|
7
7
|
"name": "android-guidelines",
|
|
@@ -5387,7 +5387,7 @@
|
|
|
5387
5387
|
"name": "ios-concurrency-guidelines",
|
|
5388
5388
|
"version": "1.0.0",
|
|
5389
5389
|
"source": "file:vendor/skills/swift-concurrency/SKILL.md",
|
|
5390
|
-
"hash": "
|
|
5390
|
+
"hash": "38629be89a118780cf411e11520b34fe1aee005a38703ef4793ff37eecd10dfa",
|
|
5391
5391
|
"rules": [
|
|
5392
5392
|
{
|
|
5393
5393
|
"id": "skills.ios.guideline.ios-concurrency.async-sequences-md-asyncsequence-asyncstream-when-to-use-vs-regular-as",
|
|
@@ -5401,18 +5401,6 @@
|
|
|
5401
5401
|
"evaluationMode": "DECLARATIVE",
|
|
5402
5402
|
"origin": "core"
|
|
5403
5403
|
},
|
|
5404
|
-
{
|
|
5405
|
-
"id": "skills.ios.guideline.ios-concurrency.remove-async-if-not-required-if-required-by-protocol-override-concurre",
|
|
5406
|
-
"description": "Remove async if not required; if required by protocol/override/@concurrent, prefer narrow suppression over adding fake awaits. See references/linting.md.",
|
|
5407
|
-
"severity": "ERROR",
|
|
5408
|
-
"platform": "ios",
|
|
5409
|
-
"sourceSkill": "ios-concurrency-guidelines",
|
|
5410
|
-
"sourcePath": "vendor/skills/swift-concurrency/SKILL.md",
|
|
5411
|
-
"confidence": "HIGH",
|
|
5412
|
-
"locked": true,
|
|
5413
|
-
"evaluationMode": "DECLARATIVE",
|
|
5414
|
-
"origin": "core"
|
|
5415
|
-
},
|
|
5416
5404
|
{
|
|
5417
5405
|
"id": "skills.ios.guideline.ios-concurrency.then-use-references-actors-md-global-actors-nonisolated-isolated-param",
|
|
5418
5406
|
"description": "Then: use references/actors.md (global actors, nonisolated, isolated parameters) and references/threading.md (default isolation)",
|
|
@@ -5522,6 +5510,19 @@
|
|
|
5522
5510
|
"evaluationMode": "AUTO",
|
|
5523
5511
|
"origin": "core"
|
|
5524
5512
|
},
|
|
5513
|
+
{
|
|
5514
|
+
"id": "skills.ios.no-async-without-await",
|
|
5515
|
+
"description": "Avoid private async functions without await; remove async unless a protocol or override boundary requires it.",
|
|
5516
|
+
"severity": "WARN",
|
|
5517
|
+
"platform": "ios",
|
|
5518
|
+
"confidence": "MEDIUM",
|
|
5519
|
+
"stage": "PRE_PUSH",
|
|
5520
|
+
"locked": true,
|
|
5521
|
+
"sourceSkill": "ios-concurrency-guidelines",
|
|
5522
|
+
"sourcePath": "vendor/skills/swift-concurrency/SKILL.md",
|
|
5523
|
+
"evaluationMode": "AUTO",
|
|
5524
|
+
"origin": "core"
|
|
5525
|
+
},
|
|
5525
5526
|
{
|
|
5526
5527
|
"id": "skills.ios.no-dispatchgroup",
|
|
5527
5528
|
"description": "Avoid DispatchGroup in production iOS code; prefer TaskGroup.",
|
|
@@ -5644,56 +5645,8 @@
|
|
|
5644
5645
|
"name": "ios-core-data-guidelines",
|
|
5645
5646
|
"version": "1.0.0",
|
|
5646
5647
|
"source": "file:vendor/skills/core-data-expert/SKILL.md",
|
|
5647
|
-
"hash": "
|
|
5648
|
+
"hash": "a84487522605588f76e31278324b5153f2a437ba2ac56f972f24e1a7226c4365",
|
|
5648
5649
|
"rules": [
|
|
5649
|
-
{
|
|
5650
|
-
"id": "skills.ios.guideline.ios-core-data.make-context-ownership-explicit-and-keep-merge-boundaries-controlled",
|
|
5651
|
-
"description": "Make context ownership explicit and keep merge boundaries controlled.",
|
|
5652
|
-
"severity": "WARN",
|
|
5653
|
-
"platform": "ios",
|
|
5654
|
-
"sourceSkill": "ios-core-data-guidelines",
|
|
5655
|
-
"sourcePath": "vendor/skills/core-data-expert/SKILL.md",
|
|
5656
|
-
"confidence": "MEDIUM",
|
|
5657
|
-
"locked": true,
|
|
5658
|
-
"evaluationMode": "DECLARATIVE",
|
|
5659
|
-
"origin": "core"
|
|
5660
|
-
},
|
|
5661
|
-
{
|
|
5662
|
-
"id": "skills.ios.guideline.ios-core-data.pass-nsmanagedobjectid-when-a-different-context-must-resolve-the-entit",
|
|
5663
|
-
"description": "Pass NSManagedObjectID when a different context must resolve the entity later.",
|
|
5664
|
-
"severity": "ERROR",
|
|
5665
|
-
"platform": "ios",
|
|
5666
|
-
"sourceSkill": "ios-core-data-guidelines",
|
|
5667
|
-
"sourcePath": "vendor/skills/core-data-expert/SKILL.md",
|
|
5668
|
-
"confidence": "HIGH",
|
|
5669
|
-
"locked": true,
|
|
5670
|
-
"evaluationMode": "DECLARATIVE",
|
|
5671
|
-
"origin": "core"
|
|
5672
|
-
},
|
|
5673
|
-
{
|
|
5674
|
-
"id": "skills.ios.guideline.ios-core-data.treat-managed-objects-as-context-scoped-references-not-as-portable-dom",
|
|
5675
|
-
"description": "Treat managed objects as context-scoped references, not as portable domain entities.",
|
|
5676
|
-
"severity": "WARN",
|
|
5677
|
-
"platform": "ios",
|
|
5678
|
-
"sourceSkill": "ios-core-data-guidelines",
|
|
5679
|
-
"sourcePath": "vendor/skills/core-data-expert/SKILL.md",
|
|
5680
|
-
"confidence": "MEDIUM",
|
|
5681
|
-
"locked": true,
|
|
5682
|
-
"evaluationMode": "DECLARATIVE",
|
|
5683
|
-
"origin": "core"
|
|
5684
|
-
},
|
|
5685
|
-
{
|
|
5686
|
-
"id": "skills.ios.guideline.ios-core-data.use-repositories-that-map-managed-objects-into-domain-models-before-cr",
|
|
5687
|
-
"description": "Use repositories that map managed objects into domain models before crossing module boundaries.",
|
|
5688
|
-
"severity": "WARN",
|
|
5689
|
-
"platform": "ios",
|
|
5690
|
-
"sourceSkill": "ios-core-data-guidelines",
|
|
5691
|
-
"sourcePath": "vendor/skills/core-data-expert/SKILL.md",
|
|
5692
|
-
"confidence": "MEDIUM",
|
|
5693
|
-
"locked": true,
|
|
5694
|
-
"evaluationMode": "DECLARATIVE",
|
|
5695
|
-
"origin": "core"
|
|
5696
|
-
},
|
|
5697
5650
|
{
|
|
5698
5651
|
"id": "skills.ios.no-core-data-layer-leak",
|
|
5699
5652
|
"description": "Keep Core Data orchestration inside infrastructure or repository layers; avoid Core Data APIs in application or presentation code.",
|
|
@@ -5764,8 +5717,20 @@
|
|
|
5764
5717
|
"name": "ios-guidelines",
|
|
5765
5718
|
"version": "1.0.0",
|
|
5766
5719
|
"source": "file:vendor/skills/ios-enterprise-rules/SKILL.md",
|
|
5767
|
-
"hash": "
|
|
5720
|
+
"hash": "3eb1d2a79500bce846244c510c96e83ef1b0046695eb4ff7dc506dbd94d10154",
|
|
5768
5721
|
"rules": [
|
|
5722
|
+
{
|
|
5723
|
+
"id": "skills.ios.guideline.ios-swiftui-expert.use-lazyvstack-lazyhstack-for-large-lists",
|
|
5724
|
+
"description": "LazyVStack/LazyHStack - Para listas grandes",
|
|
5725
|
+
"severity": "WARN",
|
|
5726
|
+
"platform": "ios",
|
|
5727
|
+
"sourceSkill": "ios-guidelines",
|
|
5728
|
+
"sourcePath": "vendor/skills/ios-enterprise-rules/SKILL.md",
|
|
5729
|
+
"confidence": "MEDIUM",
|
|
5730
|
+
"locked": true,
|
|
5731
|
+
"evaluationMode": "AUTO",
|
|
5732
|
+
"origin": "core"
|
|
5733
|
+
},
|
|
5769
5734
|
{
|
|
5770
5735
|
"id": "skills.ios.guideline.ios-swiftui-expert.use-navigationdestination-for-for-type-safe-navigation",
|
|
5771
5736
|
"description": "navigationDestination(for:) - Destinos tipados",
|
|
@@ -5970,6 +5935,18 @@
|
|
|
5970
5935
|
"evaluationMode": "DECLARATIVE",
|
|
5971
5936
|
"origin": "core"
|
|
5972
5937
|
},
|
|
5938
|
+
{
|
|
5939
|
+
"id": "skills.ios.guideline.ios.automatic-plural-handling-en-string-catalogs",
|
|
5940
|
+
"description": "Automatic plural handling - En String Catalogs",
|
|
5941
|
+
"severity": "WARN",
|
|
5942
|
+
"platform": "ios",
|
|
5943
|
+
"sourceSkill": "ios-guidelines",
|
|
5944
|
+
"sourcePath": "vendor/skills/ios-enterprise-rules/SKILL.md",
|
|
5945
|
+
"confidence": "MEDIUM",
|
|
5946
|
+
"locked": true,
|
|
5947
|
+
"evaluationMode": "DECLARATIVE",
|
|
5948
|
+
"origin": "core"
|
|
5949
|
+
},
|
|
5973
5950
|
{
|
|
5974
5951
|
"id": "skills.ios.guideline.ios.avoid-over-use-async-await-ma-s-simple-para-single-values",
|
|
5975
5952
|
"description": "Avoid over-use - async/await más simple para single values",
|
|
@@ -6087,7 +6064,7 @@
|
|
|
6087
6064
|
"sourcePath": "vendor/skills/ios-enterprise-rules/SKILL.md",
|
|
6088
6065
|
"confidence": "HIGH",
|
|
6089
6066
|
"locked": true,
|
|
6090
|
-
"evaluationMode": "
|
|
6067
|
+
"evaluationMode": "AUTO",
|
|
6091
6068
|
"origin": "core"
|
|
6092
6069
|
},
|
|
6093
6070
|
{
|
|
@@ -6138,28 +6115,16 @@
|
|
|
6138
6115
|
"evaluationMode": "DECLARATIVE",
|
|
6139
6116
|
"origin": "core"
|
|
6140
6117
|
},
|
|
6141
|
-
{
|
|
6142
|
-
"id": "skills.ios.guideline.ios.codable-decodificacio-n-automa-tica-de-json-nunca-jsonserialization",
|
|
6143
|
-
"description": "Codable - Decodificación automática de JSON (nunca JSONSerialization)",
|
|
6144
|
-
"severity": "ERROR",
|
|
6145
|
-
"platform": "ios",
|
|
6146
|
-
"sourceSkill": "ios-guidelines",
|
|
6147
|
-
"sourcePath": "vendor/skills/ios-enterprise-rules/SKILL.md",
|
|
6148
|
-
"confidence": "MEDIUM",
|
|
6149
|
-
"locked": true,
|
|
6150
|
-
"evaluationMode": "DECLARATIVE",
|
|
6151
|
-
"origin": "core"
|
|
6152
|
-
},
|
|
6153
6118
|
{
|
|
6154
6119
|
"id": "skills.ios.guideline.ios.codable-para-serializacio-n-json-nunca-jsonserialization",
|
|
6155
|
-
"description": "Codable
|
|
6120
|
+
"description": "Codable - Decodificación automática de JSON (nunca JSONSerialization)",
|
|
6156
6121
|
"severity": "ERROR",
|
|
6157
6122
|
"platform": "ios",
|
|
6158
6123
|
"sourceSkill": "ios-guidelines",
|
|
6159
6124
|
"sourcePath": "vendor/skills/ios-enterprise-rules/SKILL.md",
|
|
6160
6125
|
"confidence": "MEDIUM",
|
|
6161
6126
|
"locked": true,
|
|
6162
|
-
"evaluationMode": "
|
|
6127
|
+
"evaluationMode": "AUTO",
|
|
6163
6128
|
"origin": "core"
|
|
6164
6129
|
},
|
|
6165
6130
|
{
|
|
@@ -6392,7 +6357,7 @@
|
|
|
6392
6357
|
},
|
|
6393
6358
|
{
|
|
6394
6359
|
"id": "skills.ios.guideline.ios.dynamic-type-font-scaling-automa-tico",
|
|
6395
|
-
"description": "Dynamic Type -
|
|
6360
|
+
"description": "Dynamic Type - Font scaling automático",
|
|
6396
6361
|
"severity": "WARN",
|
|
6397
6362
|
"platform": "ios",
|
|
6398
6363
|
"sourceSkill": "ios-guidelines",
|
|
@@ -6403,15 +6368,15 @@
|
|
|
6403
6368
|
"origin": "core"
|
|
6404
6369
|
},
|
|
6405
6370
|
{
|
|
6406
|
-
"id": "skills.ios.guideline.ios.
|
|
6407
|
-
"description": "
|
|
6371
|
+
"id": "skills.ios.guideline.ios.dynamic-type-fuentes-escalables-y-layouts-adaptativos",
|
|
6372
|
+
"description": "Dynamic Type - fuentes escalables y layouts adaptativos",
|
|
6408
6373
|
"severity": "WARN",
|
|
6409
6374
|
"platform": "ios",
|
|
6410
6375
|
"sourceSkill": "ios-guidelines",
|
|
6411
6376
|
"sourcePath": "vendor/skills/ios-enterprise-rules/SKILL.md",
|
|
6412
6377
|
"confidence": "MEDIUM",
|
|
6413
6378
|
"locked": true,
|
|
6414
|
-
"evaluationMode": "
|
|
6379
|
+
"evaluationMode": "AUTO",
|
|
6415
6380
|
"origin": "core"
|
|
6416
6381
|
},
|
|
6417
6382
|
{
|
|
@@ -6811,28 +6776,16 @@
|
|
|
6811
6776
|
"evaluationMode": "DECLARATIVE",
|
|
6812
6777
|
"origin": "core"
|
|
6813
6778
|
},
|
|
6814
|
-
{
|
|
6815
|
-
"id": "skills.ios.guideline.ios.jsonserialization-prohibido-usar-codable",
|
|
6816
|
-
"description": "JSONSerialization - Prohibido, usar Codable",
|
|
6817
|
-
"severity": "ERROR",
|
|
6818
|
-
"platform": "ios",
|
|
6819
|
-
"sourceSkill": "ios-guidelines",
|
|
6820
|
-
"sourcePath": "vendor/skills/ios-enterprise-rules/SKILL.md",
|
|
6821
|
-
"confidence": "HIGH",
|
|
6822
|
-
"locked": true,
|
|
6823
|
-
"evaluationMode": "DECLARATIVE",
|
|
6824
|
-
"origin": "core"
|
|
6825
|
-
},
|
|
6826
6779
|
{
|
|
6827
6780
|
"id": "skills.ios.guideline.ios.keychain-passwords-tokens-no-userdefaults",
|
|
6828
|
-
"description": "
|
|
6781
|
+
"description": "En producción ni un mocks ni un spies - Todo real de APIs y persistencia (Core Data, UserDefaults, Keychain)",
|
|
6829
6782
|
"severity": "WARN",
|
|
6830
6783
|
"platform": "ios",
|
|
6831
6784
|
"sourceSkill": "ios-guidelines",
|
|
6832
6785
|
"sourcePath": "vendor/skills/ios-enterprise-rules/SKILL.md",
|
|
6833
6786
|
"confidence": "MEDIUM",
|
|
6834
6787
|
"locked": true,
|
|
6835
|
-
"evaluationMode": "
|
|
6788
|
+
"evaluationMode": "AUTO",
|
|
6836
6789
|
"origin": "core"
|
|
6837
6790
|
},
|
|
6838
6791
|
{
|
|
@@ -6859,30 +6812,6 @@
|
|
|
6859
6812
|
"evaluationMode": "DECLARATIVE",
|
|
6860
6813
|
"origin": "core"
|
|
6861
6814
|
},
|
|
6862
|
-
{
|
|
6863
|
-
"id": "skills.ios.guideline.ios.lazy-loading-lazyvstack-on-demand-data",
|
|
6864
|
-
"description": "Lazy loading - LazyVStack, on-demand data",
|
|
6865
|
-
"severity": "WARN",
|
|
6866
|
-
"platform": "ios",
|
|
6867
|
-
"sourceSkill": "ios-guidelines",
|
|
6868
|
-
"sourcePath": "vendor/skills/ios-enterprise-rules/SKILL.md",
|
|
6869
|
-
"confidence": "MEDIUM",
|
|
6870
|
-
"locked": true,
|
|
6871
|
-
"evaluationMode": "DECLARATIVE",
|
|
6872
|
-
"origin": "core"
|
|
6873
|
-
},
|
|
6874
|
-
{
|
|
6875
|
-
"id": "skills.ios.guideline.ios.lazyvstack-lazyhstack-para-listas-grandes",
|
|
6876
|
-
"description": "LazyVStack/LazyHStack - Para listas grandes",
|
|
6877
|
-
"severity": "WARN",
|
|
6878
|
-
"platform": "ios",
|
|
6879
|
-
"sourceSkill": "ios-guidelines",
|
|
6880
|
-
"sourcePath": "vendor/skills/ios-enterprise-rules/SKILL.md",
|
|
6881
|
-
"confidence": "MEDIUM",
|
|
6882
|
-
"locked": true,
|
|
6883
|
-
"evaluationMode": "DECLARATIVE",
|
|
6884
|
-
"origin": "core"
|
|
6885
|
-
},
|
|
6886
6815
|
{
|
|
6887
6816
|
"id": "skills.ios.guideline.ios.libreri-as-de-terceros-usar-apis-nativas",
|
|
6888
6817
|
"description": "Librerías de terceros - Usar APIs nativas",
|
|
@@ -6909,14 +6838,14 @@
|
|
|
6909
6838
|
},
|
|
6910
6839
|
{
|
|
6911
6840
|
"id": "skills.ios.guideline.ios.localizable-strings-deprecado-usar-string-catalogs",
|
|
6912
|
-
"description": "String Catalogs
|
|
6913
|
-
"severity": "
|
|
6841
|
+
"description": "Localizable.strings - Deprecado, usar String Catalogs",
|
|
6842
|
+
"severity": "ERROR",
|
|
6914
6843
|
"platform": "ios",
|
|
6915
6844
|
"sourceSkill": "ios-guidelines",
|
|
6916
6845
|
"sourcePath": "vendor/skills/ios-enterprise-rules/SKILL.md",
|
|
6917
|
-
"confidence": "
|
|
6846
|
+
"confidence": "HIGH",
|
|
6918
6847
|
"locked": true,
|
|
6919
|
-
"evaluationMode": "
|
|
6848
|
+
"evaluationMode": "DECLARATIVE",
|
|
6920
6849
|
"origin": "core"
|
|
6921
6850
|
},
|
|
6922
6851
|
{
|
|
@@ -7063,30 +6992,6 @@
|
|
|
7063
6992
|
"evaluationMode": "DECLARATIVE",
|
|
7064
6993
|
"origin": "core"
|
|
7065
6994
|
},
|
|
7066
|
-
{
|
|
7067
|
-
"id": "skills.ios.guideline.ios.navigationstack-navigationpath-con-rutas-tipadas",
|
|
7068
|
-
"description": "NavigationStack + NavigationPath con rutas tipadas",
|
|
7069
|
-
"severity": "WARN",
|
|
7070
|
-
"platform": "ios",
|
|
7071
|
-
"sourceSkill": "ios-guidelines",
|
|
7072
|
-
"sourcePath": "vendor/skills/ios-enterprise-rules/SKILL.md",
|
|
7073
|
-
"confidence": "MEDIUM",
|
|
7074
|
-
"locked": true,
|
|
7075
|
-
"evaluationMode": "DECLARATIVE",
|
|
7076
|
-
"origin": "core"
|
|
7077
|
-
},
|
|
7078
|
-
{
|
|
7079
|
-
"id": "skills.ios.guideline.ios.navigationstack-navigationpath-para-navegacio-n-moderna",
|
|
7080
|
-
"description": "NavigationStack + NavigationPath - Para navegación moderna",
|
|
7081
|
-
"severity": "WARN",
|
|
7082
|
-
"platform": "ios",
|
|
7083
|
-
"sourceSkill": "ios-guidelines",
|
|
7084
|
-
"sourcePath": "vendor/skills/ios-enterprise-rules/SKILL.md",
|
|
7085
|
-
"confidence": "MEDIUM",
|
|
7086
|
-
"locked": true,
|
|
7087
|
-
"evaluationMode": "DECLARATIVE",
|
|
7088
|
-
"origin": "core"
|
|
7089
|
-
},
|
|
7090
6995
|
{
|
|
7091
6996
|
"id": "skills.ios.guideline.ios.network-layer-abstrai-do-apiclient-protocol-en-domain",
|
|
7092
6997
|
"description": "Network layer abstraído - APIClient protocol en Domain",
|
|
@@ -7132,7 +7037,7 @@
|
|
|
7132
7037
|
"sourcePath": "vendor/skills/ios-enterprise-rules/SKILL.md",
|
|
7133
7038
|
"confidence": "MEDIUM",
|
|
7134
7039
|
"locked": true,
|
|
7135
|
-
"evaluationMode": "
|
|
7040
|
+
"evaluationMode": "AUTO",
|
|
7136
7041
|
"origin": "core"
|
|
7137
7042
|
},
|
|
7138
7043
|
{
|
|
@@ -7219,18 +7124,6 @@
|
|
|
7219
7124
|
"evaluationMode": "DECLARATIVE",
|
|
7220
7125
|
"origin": "core"
|
|
7221
7126
|
},
|
|
7222
|
-
{
|
|
7223
|
-
"id": "skills.ios.guideline.ios.onchange-of-con-variante-de-2-para-metros-o-sin-para-metros",
|
|
7224
|
-
"description": "onChange(of:) con variante de 2 parámetros o sin parámetros",
|
|
7225
|
-
"severity": "WARN",
|
|
7226
|
-
"platform": "ios",
|
|
7227
|
-
"sourceSkill": "ios-guidelines",
|
|
7228
|
-
"sourcePath": "vendor/skills/ios-enterprise-rules/SKILL.md",
|
|
7229
|
-
"confidence": "MEDIUM",
|
|
7230
|
-
"locked": true,
|
|
7231
|
-
"evaluationMode": "DECLARATIVE",
|
|
7232
|
-
"origin": "core"
|
|
7233
|
-
},
|
|
7234
7127
|
{
|
|
7235
7128
|
"id": "skills.ios.guideline.ios.opaque-types-some-view-some-publisher-cuando-sea-apropiado",
|
|
7236
7129
|
"description": "Opaque types - some View, some Publisher cuando sea apropiado",
|
|
@@ -7348,7 +7241,7 @@
|
|
|
7348
7241
|
"sourcePath": "vendor/skills/ios-enterprise-rules/SKILL.md",
|
|
7349
7242
|
"confidence": "MEDIUM",
|
|
7350
7243
|
"locked": true,
|
|
7351
|
-
"evaluationMode": "
|
|
7244
|
+
"evaluationMode": "AUTO",
|
|
7352
7245
|
"origin": "core"
|
|
7353
7246
|
},
|
|
7354
7247
|
{
|
|
@@ -7540,7 +7433,7 @@
|
|
|
7540
7433
|
"sourcePath": "vendor/skills/ios-enterprise-rules/SKILL.md",
|
|
7541
7434
|
"confidence": "HIGH",
|
|
7542
7435
|
"locked": true,
|
|
7543
|
-
"evaluationMode": "
|
|
7436
|
+
"evaluationMode": "AUTO",
|
|
7544
7437
|
"origin": "core"
|
|
7545
7438
|
},
|
|
7546
7439
|
{
|
|
@@ -7696,7 +7589,7 @@
|
|
|
7696
7589
|
"sourcePath": "vendor/skills/ios-enterprise-rules/SKILL.md",
|
|
7697
7590
|
"confidence": "HIGH",
|
|
7698
7591
|
"locked": true,
|
|
7699
|
-
"evaluationMode": "
|
|
7592
|
+
"evaluationMode": "AUTO",
|
|
7700
7593
|
"origin": "core"
|
|
7701
7594
|
},
|
|
7702
7595
|
{
|
|
@@ -7819,6 +7712,30 @@
|
|
|
7819
7712
|
"evaluationMode": "DECLARATIVE",
|
|
7820
7713
|
"origin": "core"
|
|
7821
7714
|
},
|
|
7715
|
+
{
|
|
7716
|
+
"id": "skills.ios.guideline.ios.string-catalogs-xcstrings",
|
|
7717
|
+
"description": "String Catalogs (.xcstrings)",
|
|
7718
|
+
"severity": "WARN",
|
|
7719
|
+
"platform": "ios",
|
|
7720
|
+
"sourceSkill": "ios-guidelines",
|
|
7721
|
+
"sourcePath": "vendor/skills/ios-enterprise-rules/SKILL.md",
|
|
7722
|
+
"confidence": "MEDIUM",
|
|
7723
|
+
"locked": true,
|
|
7724
|
+
"evaluationMode": "DECLARATIVE",
|
|
7725
|
+
"origin": "core"
|
|
7726
|
+
},
|
|
7727
|
+
{
|
|
7728
|
+
"id": "skills.ios.guideline.ios.string-catalogs-xcstrings-sistema-moderno-de-localizacio-n-xcode-15",
|
|
7729
|
+
"description": "String Catalogs (.xcstrings) - Sistema moderno de localización (Xcode 15+)",
|
|
7730
|
+
"severity": "WARN",
|
|
7731
|
+
"platform": "ios",
|
|
7732
|
+
"sourceSkill": "ios-guidelines",
|
|
7733
|
+
"sourcePath": "vendor/skills/ios-enterprise-rules/SKILL.md",
|
|
7734
|
+
"confidence": "MEDIUM",
|
|
7735
|
+
"locked": true,
|
|
7736
|
+
"evaluationMode": "DECLARATIVE",
|
|
7737
|
+
"origin": "core"
|
|
7738
|
+
},
|
|
7822
7739
|
{
|
|
7823
7740
|
"id": "skills.ios.guideline.ios.struct-por-defecto-class-solo-cuando-necesites-identity-o-herencia",
|
|
7824
7741
|
"description": "struct por defecto - class solo cuando necesites identity o herencia",
|
|
@@ -8080,7 +7997,7 @@
|
|
|
8080
7997
|
"sourcePath": "vendor/skills/ios-enterprise-rules/SKILL.md",
|
|
8081
7998
|
"confidence": "MEDIUM",
|
|
8082
7999
|
"locked": true,
|
|
8083
|
-
"evaluationMode": "
|
|
8000
|
+
"evaluationMode": "AUTO",
|
|
8084
8001
|
"origin": "core"
|
|
8085
8002
|
},
|
|
8086
8003
|
{
|
|
@@ -8215,18 +8132,6 @@
|
|
|
8215
8132
|
"evaluationMode": "DECLARATIVE",
|
|
8216
8133
|
"origin": "core"
|
|
8217
8134
|
},
|
|
8218
|
-
{
|
|
8219
|
-
"id": "skills.ios.guideline.ios.xctest-solo-para-proyectos-legacy-o-ui-tests",
|
|
8220
|
-
"description": "XCTest - Solo para proyectos legacy o UI tests",
|
|
8221
|
-
"severity": "WARN",
|
|
8222
|
-
"platform": "ios",
|
|
8223
|
-
"sourceSkill": "ios-guidelines",
|
|
8224
|
-
"sourcePath": "vendor/skills/ios-enterprise-rules/SKILL.md",
|
|
8225
|
-
"confidence": "MEDIUM",
|
|
8226
|
-
"locked": true,
|
|
8227
|
-
"evaluationMode": "DECLARATIVE",
|
|
8228
|
-
"origin": "core"
|
|
8229
|
-
},
|
|
8230
8135
|
{
|
|
8231
8136
|
"id": "skills.ios.guideline.ios.xcuitest-ui-testing-nativo",
|
|
8232
8137
|
"description": "XCUITest - UI testing nativo",
|
|
@@ -8360,9 +8265,21 @@
|
|
|
8360
8265
|
"evaluationMode": "AUTO",
|
|
8361
8266
|
"origin": "core"
|
|
8362
8267
|
},
|
|
8268
|
+
{
|
|
8269
|
+
"id": "skills.ios.no-legacy-onchange",
|
|
8270
|
+
"description": "onChange(of:) con variante de 2 parámetros o sin parámetros",
|
|
8271
|
+
"severity": "WARN",
|
|
8272
|
+
"platform": "ios",
|
|
8273
|
+
"sourceSkill": "ios-guidelines",
|
|
8274
|
+
"sourcePath": "vendor/skills/ios-enterprise-rules/SKILL.md",
|
|
8275
|
+
"confidence": "MEDIUM",
|
|
8276
|
+
"locked": true,
|
|
8277
|
+
"evaluationMode": "AUTO",
|
|
8278
|
+
"origin": "core"
|
|
8279
|
+
},
|
|
8363
8280
|
{
|
|
8364
8281
|
"id": "skills.ios.no-navigation-view",
|
|
8365
|
-
"description": "NavigationStack
|
|
8282
|
+
"description": "NavigationStack + NavigationPath - Para navegación moderna",
|
|
8366
8283
|
"severity": "WARN",
|
|
8367
8284
|
"platform": "ios",
|
|
8368
8285
|
"sourceSkill": "ios-guidelines",
|
|
@@ -8491,6 +8408,18 @@
|
|
|
8491
8408
|
"locked": true,
|
|
8492
8409
|
"evaluationMode": "AUTO",
|
|
8493
8410
|
"origin": "core"
|
|
8411
|
+
},
|
|
8412
|
+
{
|
|
8413
|
+
"id": "skills.ios.prefer-swift-testing",
|
|
8414
|
+
"description": "XCTest - Solo para proyectos legacy o UI tests",
|
|
8415
|
+
"severity": "WARN",
|
|
8416
|
+
"platform": "ios",
|
|
8417
|
+
"sourceSkill": "ios-guidelines",
|
|
8418
|
+
"sourcePath": "vendor/skills/ios-enterprise-rules/SKILL.md",
|
|
8419
|
+
"confidence": "MEDIUM",
|
|
8420
|
+
"locked": true,
|
|
8421
|
+
"evaluationMode": "AUTO",
|
|
8422
|
+
"origin": "core"
|
|
8494
8423
|
}
|
|
8495
8424
|
]
|
|
8496
8425
|
},
|
|
@@ -8498,7 +8427,7 @@
|
|
|
8498
8427
|
"name": "ios-swift-testing-guidelines",
|
|
8499
8428
|
"version": "1.0.0",
|
|
8500
8429
|
"source": "file:vendor/skills/swift-testing-expert/SKILL.md",
|
|
8501
|
-
"hash": "
|
|
8430
|
+
"hash": "48249808a0c025bb5fb16ac2e5cec4d44ac4b0634273509ee2165ad60d0fe81f",
|
|
8502
8431
|
"rules": [
|
|
8503
8432
|
{
|
|
8504
8433
|
"id": "skills.ios.guideline.ios-swift-testing.keep-tests-isolated-expressive-and-aligned-with-swift-concurrency",
|
|
@@ -8512,18 +8441,6 @@
|
|
|
8512
8441
|
"evaluationMode": "DECLARATIVE",
|
|
8513
8442
|
"origin": "core"
|
|
8514
8443
|
},
|
|
8515
|
-
{
|
|
8516
|
-
"id": "skills.ios.guideline.ios-swift-testing.new-xctest-only-unit-tests-when-swift-testing-is-available",
|
|
8517
|
-
"description": "New XCTest-only unit tests when Swift Testing is available.",
|
|
8518
|
-
"severity": "ERROR",
|
|
8519
|
-
"platform": "ios",
|
|
8520
|
-
"sourceSkill": "ios-swift-testing-guidelines",
|
|
8521
|
-
"sourcePath": "vendor/skills/swift-testing-expert/SKILL.md",
|
|
8522
|
-
"confidence": "HIGH",
|
|
8523
|
-
"locked": true,
|
|
8524
|
-
"evaluationMode": "DECLARATIVE",
|
|
8525
|
-
"origin": "core"
|
|
8526
|
-
},
|
|
8527
8444
|
{
|
|
8528
8445
|
"id": "skills.ios.guideline.ios-swift-testing.preserve-repository-specific-test-contracts-such-as-makesut-and-memory",
|
|
8529
8446
|
"description": "Preserve repository-specific test contracts such as makeSUT() and memory-leak tracking helpers when they are mandatory.",
|
|
@@ -8620,7 +8537,7 @@
|
|
|
8620
8537
|
"name": "ios-swiftui-expert-guidelines",
|
|
8621
8538
|
"version": "1.0.0",
|
|
8622
8539
|
"source": "file:vendor/skills/swiftui-expert-skill/SKILL.md",
|
|
8623
|
-
"hash": "
|
|
8540
|
+
"hash": "d4914b86eb46b5cf0408a922c4f034789a672d95ac6c01922e94257044b8aa01",
|
|
8624
8541
|
"rules": [
|
|
8625
8542
|
{
|
|
8626
8543
|
"id": "skills.ios.guideline.ios-swiftui-expert.action-handlers-should-reference-methods-not-contain-inline-logic",
|
|
@@ -8943,7 +8860,7 @@
|
|
|
8943
8860
|
"sourcePath": "vendor/skills/swiftui-expert-skill/SKILL.md",
|
|
8944
8861
|
"confidence": "MEDIUM",
|
|
8945
8862
|
"locked": true,
|
|
8946
|
-
"evaluationMode": "
|
|
8863
|
+
"evaluationMode": "AUTO",
|
|
8947
8864
|
"origin": "core"
|
|
8948
8865
|
},
|
|
8949
8866
|
{
|