pumuki 6.3.196 → 6.3.198
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/core/facts/detectors/text/ios.test.ts +28 -0
- package/core/facts/detectors/text/ios.ts +19 -0
- package/core/facts/extractHeuristicFacts.ts +13 -0
- package/core/rules/presets/heuristics/ios.test.ts +11 -1
- package/core/rules/presets/heuristics/ios.ts +36 -0
- package/docs/codex-skills/ios-enterprise-rules.md +5 -0
- package/integrations/config/skillsDetectorRegistry.ts +16 -0
- package/integrations/config/skillsMarkdownRules.ts +14 -0
- package/package.json +1 -1
- package/skills.lock.json +7 -43
|
@@ -45,6 +45,7 @@ import {
|
|
|
45
45
|
hasSwiftScrollViewShowsIndicatorsUsage,
|
|
46
46
|
hasSwiftSensitiveLoggingUsage,
|
|
47
47
|
hasSwiftSensitiveUserDefaultsStorageUsage,
|
|
48
|
+
hasSwiftInsecureTransportUsage,
|
|
48
49
|
hasSwiftJSONSerializationUsage,
|
|
49
50
|
hasSwiftStringFormatUsage,
|
|
50
51
|
hasSwiftTabItemUsage,
|
|
@@ -240,6 +241,33 @@ let text = "UserDefaults.standard.set(accessToken, forKey: \\"accessToken\\")"
|
|
|
240
241
|
assert.equal(hasSwiftSensitiveUserDefaultsStorageUsage(ignored), false);
|
|
241
242
|
});
|
|
242
243
|
|
|
244
|
+
test('detector iOS de seguridad detecta transporte inseguro HTTP y ATS permisivo', () => {
|
|
245
|
+
const source = `
|
|
246
|
+
final class CatalogClient {
|
|
247
|
+
func load() {
|
|
248
|
+
_ = URL(string: "http://example.com/catalog.json")
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
`;
|
|
252
|
+
const plist = `
|
|
253
|
+
<dict>
|
|
254
|
+
<key>NSAppTransportSecurity</key>
|
|
255
|
+
<dict>
|
|
256
|
+
<key>NSAllowsArbitraryLoads</key>
|
|
257
|
+
<true/>
|
|
258
|
+
</dict>
|
|
259
|
+
</dict>
|
|
260
|
+
`;
|
|
261
|
+
const ignored = `
|
|
262
|
+
// _ = URL(string: "http://example.com/catalog.json")
|
|
263
|
+
let text = "https://example.com/catalog.json"
|
|
264
|
+
`;
|
|
265
|
+
|
|
266
|
+
assert.equal(hasSwiftInsecureTransportUsage(source), true);
|
|
267
|
+
assert.equal(hasSwiftInsecureTransportUsage(plist), true);
|
|
268
|
+
assert.equal(hasSwiftInsecureTransportUsage(ignored), false);
|
|
269
|
+
});
|
|
270
|
+
|
|
243
271
|
test('hasSwiftUncheckedSendableUsage detecta @unchecked Sendable', () => {
|
|
244
272
|
const source = `
|
|
245
273
|
final class LegacyBox: @unchecked Sendable {}
|
|
@@ -492,6 +492,25 @@ export const hasSwiftSensitiveUserDefaultsStorageUsage = (source: string): boole
|
|
|
492
492
|
});
|
|
493
493
|
};
|
|
494
494
|
|
|
495
|
+
export const hasSwiftInsecureTransportUsage = (source: string): boolean => {
|
|
496
|
+
const withoutBlockComments = source.replace(/\/\*[\s\S]*?\*\//g, '\n');
|
|
497
|
+
const hasHttpUrlLiteral = withoutBlockComments.split(/\r?\n/).some((line) => {
|
|
498
|
+
if (/^\s*\/\//.test(line)) {
|
|
499
|
+
return false;
|
|
500
|
+
}
|
|
501
|
+
return /["']http:\/\/[^"']*["']/.test(line);
|
|
502
|
+
});
|
|
503
|
+
|
|
504
|
+
if (hasHttpUrlLiteral) {
|
|
505
|
+
return true;
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
return (
|
|
509
|
+
/<key>\s*NSAllowsArbitraryLoads\s*<\/key>\s*<true\s*\/>/i.test(source) ||
|
|
510
|
+
/\bNSAllowsArbitraryLoads\b\s*=\s*(?:true|YES|1)\b/i.test(source)
|
|
511
|
+
);
|
|
512
|
+
};
|
|
513
|
+
|
|
495
514
|
export const hasSwiftUncheckedSendableUsage = (source: string): boolean => {
|
|
496
515
|
return scanCodeLikeSource(source, ({ source: swiftSource, index, current }) => {
|
|
497
516
|
if (current !== '@' || !swiftSource.startsWith('@unchecked', index)) {
|
|
@@ -92,6 +92,16 @@ const isIOSCartfilePath = (path: string): boolean => {
|
|
|
92
92
|
);
|
|
93
93
|
};
|
|
94
94
|
|
|
95
|
+
const isIOSInfoPlistPath = (path: string): boolean => {
|
|
96
|
+
const normalized = path.replace(/\\/g, '/');
|
|
97
|
+
return normalized.startsWith('apps/ios/') && normalized.endsWith('/Info.plist');
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
const isIOSLocalizableStringsPath = (path: string): boolean => {
|
|
101
|
+
const normalized = path.replace(/\\/g, '/');
|
|
102
|
+
return normalized.startsWith('apps/ios/') && normalized.endsWith('/Localizable.strings');
|
|
103
|
+
};
|
|
104
|
+
|
|
95
105
|
const isIOSApplicationOrPresentationPath = (path: string): boolean => {
|
|
96
106
|
return (
|
|
97
107
|
isIOSSwiftPath(path) &&
|
|
@@ -641,6 +651,9 @@ const textDetectorRegistry: ReadonlyArray<TextDetectorRegistryEntry> = [
|
|
|
641
651
|
{ platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftAlamofireUsage, ruleId: 'heuristics.ios.networking.alamofire.ast', code: 'HEURISTICS_IOS_NETWORKING_ALAMOFIRE_AST', message: 'AST heuristic detected Alamofire usage in iOS production code; URLSession remains the preferred baseline for new code.' },
|
|
642
652
|
{ platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftJSONSerializationUsage, ruleId: 'heuristics.ios.json.jsonserialization.ast', code: 'HEURISTICS_IOS_JSON_JSONSERIALIZATION_AST', message: 'AST heuristic detected JSONSerialization usage in iOS production code; Codable remains the preferred baseline for new code.' },
|
|
643
653
|
{ platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftSensitiveUserDefaultsStorageUsage, ruleId: 'heuristics.ios.security.userdefaults-sensitive-data.ast', code: 'HEURISTICS_IOS_SECURITY_USERDEFAULTS_SENSITIVE_DATA_AST', message: 'AST heuristic detected sensitive data stored in UserDefaults/AppStorage; native Keychain remains the preferred baseline for secrets.' },
|
|
654
|
+
{ platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftInsecureTransportUsage, ruleId: 'heuristics.ios.security.insecure-transport.ast', code: 'HEURISTICS_IOS_SECURITY_INSECURE_TRANSPORT_AST', message: 'AST heuristic detected insecure HTTP transport in iOS production code; HTTPS and ATS remain the preferred baseline.' },
|
|
655
|
+
{ platform: 'ios', pathCheck: isIOSInfoPlistPath, excludePaths: [], detect: TextIOS.hasSwiftInsecureTransportUsage, ruleId: 'heuristics.ios.security.insecure-transport.ast', code: 'HEURISTICS_IOS_SECURITY_INSECURE_TRANSPORT_AST', message: 'AST heuristic detected permissive App Transport Security configuration; HTTPS and ATS remain the preferred baseline.' },
|
|
656
|
+
{ platform: 'ios', pathCheck: isIOSLocalizableStringsPath, excludePaths: [], detect: detectsTrackedFilePresence, ruleId: 'heuristics.ios.localization.localizable-strings.ast', code: 'HEURISTICS_IOS_LOCALIZATION_LOCALIZABLE_STRINGS_AST', message: 'AST heuristic detected Localizable.strings usage; String Catalogs (.xcstrings) remain the preferred baseline for new localization work.' },
|
|
644
657
|
{ platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftUncheckedSendableUsage, ruleId: 'heuristics.ios.unchecked-sendable.ast', code: 'HEURISTICS_IOS_UNCHECKED_SENDABLE_AST', message: 'AST heuristic detected @unchecked Sendable usage.' },
|
|
645
658
|
{ platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftPreconcurrencyUsage, ruleId: 'heuristics.ios.preconcurrency.ast', code: 'HEURISTICS_IOS_PRECONCURRENCY_AST', message: 'AST heuristic detected @preconcurrency usage.' },
|
|
646
659
|
{ platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftNonisolatedUnsafeUsage, ruleId: 'heuristics.ios.nonisolated-unsafe.ast', code: 'HEURISTICS_IOS_NONISOLATED_UNSAFE_AST', message: 'AST heuristic detected nonisolated(unsafe) usage.' },
|
|
@@ -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, 52);
|
|
7
7
|
|
|
8
8
|
const ids = iosRules.map((rule) => rule.id);
|
|
9
9
|
assert.deepEqual(ids, [
|
|
@@ -24,6 +24,8 @@ test('iosRules define reglas heurísticas locked para plataforma ios', () => {
|
|
|
24
24
|
'heuristics.ios.dependencies.cocoapods.ast',
|
|
25
25
|
'heuristics.ios.dependencies.carthage.ast',
|
|
26
26
|
'heuristics.ios.security.userdefaults-sensitive-data.ast',
|
|
27
|
+
'heuristics.ios.security.insecure-transport.ast',
|
|
28
|
+
'heuristics.ios.localization.localizable-strings.ast',
|
|
27
29
|
'heuristics.ios.unchecked-sendable.ast',
|
|
28
30
|
'heuristics.ios.preconcurrency.ast',
|
|
29
31
|
'heuristics.ios.nonisolated-unsafe.ast',
|
|
@@ -96,6 +98,14 @@ test('iosRules define reglas heurísticas locked para plataforma ios', () => {
|
|
|
96
98
|
byId.get('heuristics.ios.security.userdefaults-sensitive-data.ast')?.then.code,
|
|
97
99
|
'HEURISTICS_IOS_SECURITY_USERDEFAULTS_SENSITIVE_DATA_AST'
|
|
98
100
|
);
|
|
101
|
+
assert.equal(
|
|
102
|
+
byId.get('heuristics.ios.security.insecure-transport.ast')?.then.code,
|
|
103
|
+
'HEURISTICS_IOS_SECURITY_INSECURE_TRANSPORT_AST'
|
|
104
|
+
);
|
|
105
|
+
assert.equal(
|
|
106
|
+
byId.get('heuristics.ios.localization.localizable-strings.ast')?.then.code,
|
|
107
|
+
'HEURISTICS_IOS_LOCALIZATION_LOCALIZABLE_STRINGS_AST'
|
|
108
|
+
);
|
|
99
109
|
assert.equal(
|
|
100
110
|
byId.get('heuristics.ios.preconcurrency.ast')?.then.code,
|
|
101
111
|
'HEURISTICS_IOS_PRECONCURRENCY_AST'
|
|
@@ -307,6 +307,42 @@ export const iosRules: RuleSet = [
|
|
|
307
307
|
code: 'HEURISTICS_IOS_SECURITY_USERDEFAULTS_SENSITIVE_DATA_AST',
|
|
308
308
|
},
|
|
309
309
|
},
|
|
310
|
+
{
|
|
311
|
+
id: 'heuristics.ios.security.insecure-transport.ast',
|
|
312
|
+
description: 'Detects insecure HTTP transport or permissive ATS configuration in iOS projects.',
|
|
313
|
+
severity: 'WARN',
|
|
314
|
+
platform: 'ios',
|
|
315
|
+
locked: true,
|
|
316
|
+
when: {
|
|
317
|
+
kind: 'Heuristic',
|
|
318
|
+
where: {
|
|
319
|
+
ruleId: 'heuristics.ios.security.insecure-transport.ast',
|
|
320
|
+
},
|
|
321
|
+
},
|
|
322
|
+
then: {
|
|
323
|
+
kind: 'Finding',
|
|
324
|
+
message: 'AST heuristic detected insecure iOS transport configuration; HTTPS and ATS remain the preferred baseline.',
|
|
325
|
+
code: 'HEURISTICS_IOS_SECURITY_INSECURE_TRANSPORT_AST',
|
|
326
|
+
},
|
|
327
|
+
},
|
|
328
|
+
{
|
|
329
|
+
id: 'heuristics.ios.localization.localizable-strings.ast',
|
|
330
|
+
description: 'Detects legacy Localizable.strings files where String Catalogs are the preferred iOS baseline.',
|
|
331
|
+
severity: 'WARN',
|
|
332
|
+
platform: 'ios',
|
|
333
|
+
locked: true,
|
|
334
|
+
when: {
|
|
335
|
+
kind: 'Heuristic',
|
|
336
|
+
where: {
|
|
337
|
+
ruleId: 'heuristics.ios.localization.localizable-strings.ast',
|
|
338
|
+
},
|
|
339
|
+
},
|
|
340
|
+
then: {
|
|
341
|
+
kind: 'Finding',
|
|
342
|
+
message: 'AST heuristic detected Localizable.strings usage; String Catalogs (.xcstrings) remain the preferred baseline for new localization work.',
|
|
343
|
+
code: 'HEURISTICS_IOS_LOCALIZATION_LOCALIZABLE_STRINGS_AST',
|
|
344
|
+
},
|
|
345
|
+
},
|
|
310
346
|
{
|
|
311
347
|
id: 'heuristics.ios.unchecked-sendable.ast',
|
|
312
348
|
description: 'Detects @unchecked Sendable usage in iOS production code.',
|
|
@@ -602,6 +602,11 @@ struct APIEndpoint: Sendable {
|
|
|
602
602
|
- `skills.ios.guideline.ios.userdefaults-settings-simples-no-datos-sensibles` se mapea a `heuristics.ios.security.userdefaults-sensitive-data.ast`.
|
|
603
603
|
- En `PROJECT MODE: brownfield`, este hallazgo es señal de baseline/adopción y debe evitar drift nuevo sin bloquear deuda histórica salvo promoción explícita de policy. Keychain nativo permanece como baseline preferente para secretos.
|
|
604
604
|
|
|
605
|
+
### Enforcement AST inicial de transporte seguro iOS
|
|
606
|
+
|
|
607
|
+
- `skills.ios.guideline.ios.app-transport-security-ats-https-por-defecto` se mapea a `heuristics.ios.security.insecure-transport.ast`.
|
|
608
|
+
- En `PROJECT MODE: brownfield`, este hallazgo detecta `http://` en Swift production y `NSAllowsArbitraryLoads=true` en `Info.plist` como señal de baseline/adopción sin bloquear deuda histórica salvo promoción explícita de policy. HTTPS y ATS permanecen como baseline preferente.
|
|
609
|
+
|
|
605
610
|
### Combine (Reactive):
|
|
606
611
|
✅ **Publishers** - AsyncSequence para async, Combine para streams complejos
|
|
607
612
|
✅ **@Published** - En ViewModels para binding con Views
|
|
@@ -87,6 +87,22 @@ const registryByRuleId: Record<string, SkillsDetectorBinding> = {
|
|
|
87
87
|
'ios.security.userdefaults-sensitive-data',
|
|
88
88
|
['heuristics.ios.security.userdefaults-sensitive-data.ast']
|
|
89
89
|
),
|
|
90
|
+
'skills.ios.guideline.ios.app-transport-security-ats-https-por-defecto': heuristicDetector(
|
|
91
|
+
'ios.security.insecure-transport',
|
|
92
|
+
['heuristics.ios.security.insecure-transport.ast']
|
|
93
|
+
),
|
|
94
|
+
'skills.ios.guideline.ios.localizable-strings-deprecado-usar-string-catalogs': heuristicDetector(
|
|
95
|
+
'ios.localization.localizable-strings',
|
|
96
|
+
['heuristics.ios.localization.localizable-strings.ast']
|
|
97
|
+
),
|
|
98
|
+
'skills.ios.guideline.ios.string-catalogs-xcstrings': heuristicDetector(
|
|
99
|
+
'ios.localization.localizable-strings',
|
|
100
|
+
['heuristics.ios.localization.localizable-strings.ast']
|
|
101
|
+
),
|
|
102
|
+
'skills.ios.guideline.ios.string-catalogs-xcstrings-sistema-moderno-de-localizacio-n-xcode-15': heuristicDetector(
|
|
103
|
+
'ios.localization.localizable-strings',
|
|
104
|
+
['heuristics.ios.localization.localizable-strings.ast']
|
|
105
|
+
),
|
|
90
106
|
'skills.ios.no-unchecked-sendable': heuristicDetector('ios.unchecked-sendable', [
|
|
91
107
|
'heuristics.ios.unchecked-sendable.ast',
|
|
92
108
|
]),
|
|
@@ -381,6 +381,20 @@ const normalizeKnownRuleTarget = (
|
|
|
381
381
|
) {
|
|
382
382
|
return 'skills.ios.no-legacy-expectation-description';
|
|
383
383
|
}
|
|
384
|
+
if (
|
|
385
|
+
includes('app transport security') ||
|
|
386
|
+
includes('ats https') ||
|
|
387
|
+
includes('https por defecto')
|
|
388
|
+
) {
|
|
389
|
+
return 'skills.ios.guideline.ios.app-transport-security-ats-https-por-defecto';
|
|
390
|
+
}
|
|
391
|
+
if (
|
|
392
|
+
includes('localizable strings') ||
|
|
393
|
+
includes('string catalogs') ||
|
|
394
|
+
includes('xcstrings')
|
|
395
|
+
) {
|
|
396
|
+
return 'skills.ios.guideline.ios.localizable-strings-deprecado-usar-string-catalogs';
|
|
397
|
+
}
|
|
384
398
|
if (
|
|
385
399
|
includes('mixing legacy xctest style') ||
|
|
386
400
|
includes('mixed xctest and swift testing') ||
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pumuki",
|
|
3
|
-
"version": "6.3.
|
|
3
|
+
"version": "6.3.198",
|
|
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": {
|
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-13T11:
|
|
4
|
+
"generatedAt": "2026-05-13T11:18:53.521Z",
|
|
5
5
|
"bundles": [
|
|
6
6
|
{
|
|
7
7
|
"name": "android-guidelines",
|
|
@@ -5764,7 +5764,7 @@
|
|
|
5764
5764
|
"name": "ios-guidelines",
|
|
5765
5765
|
"version": "1.0.0",
|
|
5766
5766
|
"source": "file:vendor/skills/ios-enterprise-rules/SKILL.md",
|
|
5767
|
-
"hash": "
|
|
5767
|
+
"hash": "30c5afdca8ca553960a3063adf318d314f3d60489bf88465b670e82e6e157d51",
|
|
5768
5768
|
"rules": [
|
|
5769
5769
|
{
|
|
5770
5770
|
"id": "skills.ios.guideline.ios.accessibility-identifiers-para-localizar-elementos",
|
|
@@ -5871,7 +5871,7 @@
|
|
|
5871
5871
|
"sourcePath": "vendor/skills/ios-enterprise-rules/SKILL.md",
|
|
5872
5872
|
"confidence": "MEDIUM",
|
|
5873
5873
|
"locked": true,
|
|
5874
|
-
"evaluationMode": "
|
|
5874
|
+
"evaluationMode": "AUTO",
|
|
5875
5875
|
"origin": "core"
|
|
5876
5876
|
},
|
|
5877
5877
|
{
|
|
@@ -5946,18 +5946,6 @@
|
|
|
5946
5946
|
"evaluationMode": "DECLARATIVE",
|
|
5947
5947
|
"origin": "core"
|
|
5948
5948
|
},
|
|
5949
|
-
{
|
|
5950
|
-
"id": "skills.ios.guideline.ios.automatic-plural-handling-en-string-catalogs",
|
|
5951
|
-
"description": "Automatic plural handling - En String Catalogs",
|
|
5952
|
-
"severity": "WARN",
|
|
5953
|
-
"platform": "ios",
|
|
5954
|
-
"sourceSkill": "ios-guidelines",
|
|
5955
|
-
"sourcePath": "vendor/skills/ios-enterprise-rules/SKILL.md",
|
|
5956
|
-
"confidence": "MEDIUM",
|
|
5957
|
-
"locked": true,
|
|
5958
|
-
"evaluationMode": "DECLARATIVE",
|
|
5959
|
-
"origin": "core"
|
|
5960
|
-
},
|
|
5961
5949
|
{
|
|
5962
5950
|
"id": "skills.ios.guideline.ios.avoid-over-use-async-await-ma-s-simple-para-single-values",
|
|
5963
5951
|
"description": "Avoid over-use - async/await más simple para single values",
|
|
@@ -6933,14 +6921,14 @@
|
|
|
6933
6921
|
},
|
|
6934
6922
|
{
|
|
6935
6923
|
"id": "skills.ios.guideline.ios.localizable-strings-deprecado-usar-string-catalogs",
|
|
6936
|
-
"description": "
|
|
6937
|
-
"severity": "
|
|
6924
|
+
"description": "String Catalogs (.xcstrings)",
|
|
6925
|
+
"severity": "WARN",
|
|
6938
6926
|
"platform": "ios",
|
|
6939
6927
|
"sourceSkill": "ios-guidelines",
|
|
6940
6928
|
"sourcePath": "vendor/skills/ios-enterprise-rules/SKILL.md",
|
|
6941
|
-
"confidence": "
|
|
6929
|
+
"confidence": "MEDIUM",
|
|
6942
6930
|
"locked": true,
|
|
6943
|
-
"evaluationMode": "
|
|
6931
|
+
"evaluationMode": "AUTO",
|
|
6944
6932
|
"origin": "core"
|
|
6945
6933
|
},
|
|
6946
6934
|
{
|
|
@@ -7891,30 +7879,6 @@
|
|
|
7891
7879
|
"evaluationMode": "DECLARATIVE",
|
|
7892
7880
|
"origin": "core"
|
|
7893
7881
|
},
|
|
7894
|
-
{
|
|
7895
|
-
"id": "skills.ios.guideline.ios.string-catalogs-xcstrings",
|
|
7896
|
-
"description": "String Catalogs (.xcstrings)",
|
|
7897
|
-
"severity": "WARN",
|
|
7898
|
-
"platform": "ios",
|
|
7899
|
-
"sourceSkill": "ios-guidelines",
|
|
7900
|
-
"sourcePath": "vendor/skills/ios-enterprise-rules/SKILL.md",
|
|
7901
|
-
"confidence": "MEDIUM",
|
|
7902
|
-
"locked": true,
|
|
7903
|
-
"evaluationMode": "DECLARATIVE",
|
|
7904
|
-
"origin": "core"
|
|
7905
|
-
},
|
|
7906
|
-
{
|
|
7907
|
-
"id": "skills.ios.guideline.ios.string-catalogs-xcstrings-sistema-moderno-de-localizacio-n-xcode-15",
|
|
7908
|
-
"description": "String Catalogs (.xcstrings) - Sistema moderno de localización (Xcode 15+)",
|
|
7909
|
-
"severity": "WARN",
|
|
7910
|
-
"platform": "ios",
|
|
7911
|
-
"sourceSkill": "ios-guidelines",
|
|
7912
|
-
"sourcePath": "vendor/skills/ios-enterprise-rules/SKILL.md",
|
|
7913
|
-
"confidence": "MEDIUM",
|
|
7914
|
-
"locked": true,
|
|
7915
|
-
"evaluationMode": "DECLARATIVE",
|
|
7916
|
-
"origin": "core"
|
|
7917
|
-
},
|
|
7918
7882
|
{
|
|
7919
7883
|
"id": "skills.ios.guideline.ios.string-localized-api-moderna-para-strings-traducibles",
|
|
7920
7884
|
"description": "String(localized:) - API moderna para strings traducibles",
|