pumuki 6.3.217 → 6.3.219
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 +59 -0
- package/core/facts/detectors/text/ios.ts +16 -0
- package/core/facts/extractHeuristicFacts.ts +2 -0
- package/core/rules/presets/heuristics/ios.ts +38 -0
- package/integrations/config/skillsDetectorRegistry.ts +12 -0
- package/integrations/config/skillsMarkdownRules.ts +16 -0
- package/package.json +1 -1
- package/skills.lock.json +17 -17
|
@@ -43,8 +43,10 @@ import {
|
|
|
43
43
|
hasSwiftNSManagedObjectBoundaryUsage,
|
|
44
44
|
hasSwiftNSManagedObjectStateLeakUsage,
|
|
45
45
|
hasSwiftNavigationViewUsage,
|
|
46
|
+
hasSwiftNonPrivateStateOwnershipUsage,
|
|
46
47
|
hasSwiftNonIBOutletImplicitlyUnwrappedOptionalUsage,
|
|
47
48
|
hasSwiftObservableObjectUsage,
|
|
49
|
+
hasSwiftOnAppearTaskUsage,
|
|
48
50
|
hasSwiftOnTapGestureUsage,
|
|
49
51
|
hasSwiftOperationQueueUsage,
|
|
50
52
|
hasSwiftContainsUserFilterUsage,
|
|
@@ -186,6 +188,43 @@ Task {
|
|
|
186
188
|
assert.equal(hasSwiftTaskDetachedUsage(negative), false);
|
|
187
189
|
});
|
|
188
190
|
|
|
191
|
+
test('hasSwiftOnAppearTaskUsage detecta Task dentro de onAppear y preserva task modifier', () => {
|
|
192
|
+
const source = `
|
|
193
|
+
struct FeedView: View {
|
|
194
|
+
var body: some View {
|
|
195
|
+
List(items) { item in
|
|
196
|
+
Text(item.title)
|
|
197
|
+
}
|
|
198
|
+
.onAppear {
|
|
199
|
+
Task {
|
|
200
|
+
await viewModel.load()
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
`;
|
|
206
|
+
const safe = `
|
|
207
|
+
struct FeedView: View {
|
|
208
|
+
var body: some View {
|
|
209
|
+
List(items) { item in
|
|
210
|
+
Text(item.title)
|
|
211
|
+
}
|
|
212
|
+
.task {
|
|
213
|
+
await viewModel.load()
|
|
214
|
+
}
|
|
215
|
+
.onAppear {
|
|
216
|
+
analytics.trackScreen()
|
|
217
|
+
}
|
|
218
|
+
let text = ".onAppear { Task { await load() } }"
|
|
219
|
+
// .onAppear { Task { await load() } }
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
`;
|
|
223
|
+
|
|
224
|
+
assert.equal(hasSwiftOnAppearTaskUsage(source), true);
|
|
225
|
+
assert.equal(hasSwiftOnAppearTaskUsage(safe), false);
|
|
226
|
+
});
|
|
227
|
+
|
|
189
228
|
test('hasSwiftStrongDelegateReferenceUsage detecta delegates fuertes y preserva weak delegates', () => {
|
|
190
229
|
const positive = `
|
|
191
230
|
final class CheckoutCoordinator {
|
|
@@ -890,6 +929,26 @@ struct ContentView: View {
|
|
|
890
929
|
assert.equal(hasSwiftLegacySwiftUiObservableWrapperUsage(modernWrapper), false);
|
|
891
930
|
});
|
|
892
931
|
|
|
932
|
+
test('hasSwiftNonPrivateStateOwnershipUsage detecta @State y @StateObject no privados', () => {
|
|
933
|
+
const source = `
|
|
934
|
+
struct DashboardView: View {
|
|
935
|
+
@State var query = ""
|
|
936
|
+
@StateObject var viewModel = DashboardViewModel()
|
|
937
|
+
}
|
|
938
|
+
`;
|
|
939
|
+
const safe = `
|
|
940
|
+
struct DashboardView: View {
|
|
941
|
+
@State private var query = ""
|
|
942
|
+
@StateObject private var viewModel = DashboardViewModel()
|
|
943
|
+
let text = "@State var query = \\"\\""
|
|
944
|
+
// @State var query = ""
|
|
945
|
+
}
|
|
946
|
+
`;
|
|
947
|
+
|
|
948
|
+
assert.equal(hasSwiftNonPrivateStateOwnershipUsage(source), true);
|
|
949
|
+
assert.equal(hasSwiftNonPrivateStateOwnershipUsage(safe), false);
|
|
950
|
+
});
|
|
951
|
+
|
|
893
952
|
test('hasSwiftPassedValueStateWrapperUsage detecta valores inyectados guardados como @State o @StateObject', () => {
|
|
894
953
|
const invalidOwnership = `
|
|
895
954
|
struct DetailView: View {
|
|
@@ -437,6 +437,11 @@ export const hasSwiftTaskDetachedUsage = (source: string): boolean => {
|
|
|
437
437
|
});
|
|
438
438
|
};
|
|
439
439
|
|
|
440
|
+
export const hasSwiftOnAppearTaskUsage = (source: string): boolean => {
|
|
441
|
+
const sanitized = sanitizeSwiftSourceForMultilineRegex(source);
|
|
442
|
+
return /\.onAppear\s*\{[\s\S]{0,500}?\bTask\s*(?:\([^)]*\))?\s*\{/.test(sanitized);
|
|
443
|
+
};
|
|
444
|
+
|
|
440
445
|
export const hasSwiftStrongDelegateReferenceUsage = (source: string): boolean => {
|
|
441
446
|
const delegatePropertyPattern =
|
|
442
447
|
/\b(?:var|let)\s+(?:[A-Za-z_][A-Za-z0-9_]*(?:Delegate|DataSource)|delegate|dataSource)\s*:\s*(?:any\s+)?[A-Za-z_][A-Za-z0-9_]*(?:Delegate|DataSource)\b/;
|
|
@@ -855,6 +860,17 @@ export const hasSwiftLegacySwiftUiObservableWrapperUsage = (source: string): boo
|
|
|
855
860
|
return hasSwiftSanitizedRegexMatch(source, /@\s*(?:StateObject|ObservedObject)\b/);
|
|
856
861
|
};
|
|
857
862
|
|
|
863
|
+
export const hasSwiftNonPrivateStateOwnershipUsage = (source: string): boolean => {
|
|
864
|
+
return source.split(/\r?\n/).some((line) => {
|
|
865
|
+
const sanitizedLine = stripSwiftLineForSemanticScan(line);
|
|
866
|
+
return (
|
|
867
|
+
/@\s*(?:State|StateObject)\b/.test(sanitizedLine) &&
|
|
868
|
+
/\bvar\b/.test(sanitizedLine) &&
|
|
869
|
+
!/\bprivate\b/.test(sanitizedLine)
|
|
870
|
+
);
|
|
871
|
+
});
|
|
872
|
+
};
|
|
873
|
+
|
|
858
874
|
const hasSwiftPassedValueWrapperInitialization = (
|
|
859
875
|
source: string,
|
|
860
876
|
options: {
|
|
@@ -646,6 +646,7 @@ 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: 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.' },
|
|
649
650
|
{ 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.' },
|
|
650
651
|
{ platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftStrongSelfEscapingClosureUsage, ruleId: 'heuristics.ios.memory.strong-self-escaping-closure.ast', code: 'HEURISTICS_IOS_MEMORY_STRONG_SELF_ESCAPING_CLOSURE_AST', message: 'AST heuristic detected strong self capture in an escaping iOS closure; weak or unowned captures remain the preferred baseline when ownership is not explicit.' },
|
|
651
652
|
{ platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftCustomSingletonUsage, ruleId: 'heuristics.ios.architecture.custom-singleton.ast', code: 'HEURISTICS_IOS_ARCHITECTURE_CUSTOM_SINGLETON_AST', message: 'AST heuristic detected a custom static shared singleton in iOS production code; dependency injection remains the preferred baseline for app-owned services.' },
|
|
@@ -674,6 +675,7 @@ const textDetectorRegistry: ReadonlyArray<TextDetectorRegistryEntry> = [
|
|
|
674
675
|
{ platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftAssumeIsolatedUsage, ruleId: 'heuristics.ios.assume-isolated.ast', code: 'HEURISTICS_IOS_ASSUME_ISOLATED_AST', message: 'AST heuristic detected assumeIsolated usage.' },
|
|
675
676
|
{ platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftObservableObjectUsage, ruleId: 'heuristics.ios.observable-object.ast', code: 'HEURISTICS_IOS_OBSERVABLE_OBJECT_AST', message: 'AST heuristic detected ObservableObject usage.' },
|
|
676
677
|
{ platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftLegacySwiftUiObservableWrapperUsage, ruleId: 'heuristics.ios.legacy-swiftui-observable-wrapper.ast', code: 'HEURISTICS_IOS_LEGACY_SWIFTUI_OBSERVABLE_WRAPPER_AST', message: 'AST heuristic detected @StateObject/@ObservedObject usage in a modern SwiftUI path.' },
|
|
678
|
+
{ platform: 'ios', pathCheck: isIOSPresentationPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftNonPrivateStateOwnershipUsage, ruleId: 'heuristics.ios.swiftui.non-private-state-ownership.ast', code: 'HEURISTICS_IOS_SWIFTUI_NON_PRIVATE_STATE_OWNERSHIP_AST', message: 'AST heuristic detected @State/@StateObject without private visibility; SwiftUI owned state should be private.' },
|
|
677
679
|
{ platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftPassedValueStateWrapperUsage, ruleId: 'heuristics.ios.passed-value-state-wrapper.ast', code: 'HEURISTICS_IOS_PASSED_VALUE_STATE_WRAPPER_AST', message: 'AST heuristic detected a passed value stored as @State/@StateObject via init wrapper ownership.' },
|
|
678
680
|
{ platform: 'ios', pathCheck: isIOSPresentationPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftForEachIndicesUsage, ruleId: 'heuristics.ios.foreach-indices.ast', code: 'HEURISTICS_IOS_FOREACH_INDICES_AST', message: 'AST heuristic detected ForEach(...indices...) usage where stable element identity may be preferred.' },
|
|
679
681
|
{ platform: 'ios', pathCheck: isIOSApplicationOrPresentationPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftContainsUserFilterUsage, ruleId: 'heuristics.ios.contains-user-filter.ast', code: 'HEURISTICS_IOS_CONTAINS_USER_FILTER_AST', message: 'AST heuristic detected contains() in a user-facing filter where localizedStandardContains() may be preferred.' },
|
|
@@ -181,6 +181,25 @@ export const iosRules: RuleSet = [
|
|
|
181
181
|
code: 'HEURISTICS_IOS_TASK_DETACHED_AST',
|
|
182
182
|
},
|
|
183
183
|
},
|
|
184
|
+
{
|
|
185
|
+
id: 'heuristics.ios.swiftui.onappear-task.ast',
|
|
186
|
+
description: 'Detects Task launches from SwiftUI onAppear where .task can provide lifecycle cancellation.',
|
|
187
|
+
severity: 'WARN',
|
|
188
|
+
platform: 'ios',
|
|
189
|
+
locked: true,
|
|
190
|
+
when: {
|
|
191
|
+
kind: 'Heuristic',
|
|
192
|
+
where: {
|
|
193
|
+
ruleId: 'heuristics.ios.swiftui.onappear-task.ast',
|
|
194
|
+
},
|
|
195
|
+
},
|
|
196
|
+
then: {
|
|
197
|
+
kind: 'Finding',
|
|
198
|
+
message:
|
|
199
|
+
'AST heuristic detected Task launched from SwiftUI onAppear; .task/.task(id:) provides lifecycle-aware cancellation.',
|
|
200
|
+
code: 'HEURISTICS_IOS_SWIFTUI_ONAPPEAR_TASK_AST',
|
|
201
|
+
},
|
|
202
|
+
},
|
|
184
203
|
{
|
|
185
204
|
id: 'heuristics.ios.memory.strong-delegate.ast',
|
|
186
205
|
description: 'Detects strong delegate/dataSource references in iOS production code.',
|
|
@@ -711,6 +730,25 @@ export const iosRules: RuleSet = [
|
|
|
711
730
|
code: 'HEURISTICS_IOS_LEGACY_SWIFTUI_OBSERVABLE_WRAPPER_AST',
|
|
712
731
|
},
|
|
713
732
|
},
|
|
733
|
+
{
|
|
734
|
+
id: 'heuristics.ios.swiftui.non-private-state-ownership.ast',
|
|
735
|
+
description: 'Detects @State/@StateObject declarations without private visibility in SwiftUI presentation code.',
|
|
736
|
+
severity: 'WARN',
|
|
737
|
+
platform: 'ios',
|
|
738
|
+
locked: true,
|
|
739
|
+
when: {
|
|
740
|
+
kind: 'Heuristic',
|
|
741
|
+
where: {
|
|
742
|
+
ruleId: 'heuristics.ios.swiftui.non-private-state-ownership.ast',
|
|
743
|
+
},
|
|
744
|
+
},
|
|
745
|
+
then: {
|
|
746
|
+
kind: 'Finding',
|
|
747
|
+
message:
|
|
748
|
+
'AST heuristic detected @State/@StateObject without private visibility; SwiftUI owned state should be private.',
|
|
749
|
+
code: 'HEURISTICS_IOS_SWIFTUI_NON_PRIVATE_STATE_OWNERSHIP_AST',
|
|
750
|
+
},
|
|
751
|
+
},
|
|
714
752
|
{
|
|
715
753
|
id: 'heuristics.ios.passed-value-state-wrapper.ast',
|
|
716
754
|
description: 'Detects passed values stored as @State or @StateObject through init ownership in SwiftUI production code.',
|
|
@@ -201,6 +201,10 @@ const registryByRuleId: Record<string, SkillsDetectorBinding> = {
|
|
|
201
201
|
'ios.legacy-swiftui-observable-wrapper',
|
|
202
202
|
['heuristics.ios.legacy-swiftui-observable-wrapper.ast']
|
|
203
203
|
),
|
|
204
|
+
'skills.ios.guideline.ios-swiftui-expert.always-mark-state-and-stateobject-as-private-makes-dependencies-clear': heuristicDetector(
|
|
205
|
+
'ios.swiftui.non-private-state-ownership',
|
|
206
|
+
['heuristics.ios.swiftui.non-private-state-ownership.ast']
|
|
207
|
+
),
|
|
204
208
|
'skills.ios.no-passed-value-state-wrapper': heuristicDetector('ios.passed-value-state-wrapper', [
|
|
205
209
|
'heuristics.ios.passed-value-state-wrapper.ast',
|
|
206
210
|
]),
|
|
@@ -244,6 +248,14 @@ const registryByRuleId: Record<string, SkillsDetectorBinding> = {
|
|
|
244
248
|
'skills.ios.no-legacy-onchange': heuristicDetector('ios.legacy-onchange', [
|
|
245
249
|
'heuristics.ios.legacy-onchange.ast',
|
|
246
250
|
]),
|
|
251
|
+
'skills.ios.guideline.ios.task-task-id-trabajos-async-con-cancelacio-n-automa-tica': heuristicDetector(
|
|
252
|
+
'ios.swiftui.onappear-task',
|
|
253
|
+
['heuristics.ios.swiftui.onappear-task.ast']
|
|
254
|
+
),
|
|
255
|
+
'skills.ios.guideline.ios-swiftui-expert.use-task-modifier-for-automatic-cancellation-of-async-work': heuristicDetector(
|
|
256
|
+
'ios.swiftui.onappear-task',
|
|
257
|
+
['heuristics.ios.swiftui.onappear-task.ast']
|
|
258
|
+
),
|
|
247
259
|
'skills.ios.no-uiscreen-main-bounds': heuristicDetector('ios.uiscreen-main-bounds', [
|
|
248
260
|
'heuristics.ios.uiscreen-main-bounds.ast',
|
|
249
261
|
]),
|
|
@@ -260,6 +260,13 @@ const normalizeKnownRuleTarget = (
|
|
|
260
260
|
) {
|
|
261
261
|
return 'skills.ios.no-legacy-swiftui-observable-wrapper';
|
|
262
262
|
}
|
|
263
|
+
if (
|
|
264
|
+
includes('state and stateobject as private') ||
|
|
265
|
+
includes('stateobject as private') ||
|
|
266
|
+
(includes('mark state') && includes('private'))
|
|
267
|
+
) {
|
|
268
|
+
return 'skills.ios.guideline.ios-swiftui-expert.always-mark-state-and-stateobject-as-private-makes-dependencies-clear';
|
|
269
|
+
}
|
|
263
270
|
if (
|
|
264
271
|
includes('passed values as state') ||
|
|
265
272
|
includes('passed values as state or stateobject') ||
|
|
@@ -360,6 +367,15 @@ const normalizeKnownRuleTarget = (
|
|
|
360
367
|
if (includes('uiscreen main bounds') || includes('uiscreen.main.bounds')) {
|
|
361
368
|
return 'skills.ios.no-uiscreen-main-bounds';
|
|
362
369
|
}
|
|
370
|
+
if (
|
|
371
|
+
includes('task/.task(id') ||
|
|
372
|
+
includes('trabajos async con cancelacion automatica') ||
|
|
373
|
+
includes('trabajos async con cancelacio n automa tica') ||
|
|
374
|
+
includes('task modifier for automatic cancellation') ||
|
|
375
|
+
includes('automatic cancellation of async work')
|
|
376
|
+
) {
|
|
377
|
+
return 'skills.ios.guideline.ios-swiftui-expert.use-task-modifier-for-automatic-cancellation-of-async-work';
|
|
378
|
+
}
|
|
363
379
|
if (
|
|
364
380
|
includes('swift testing over xctest') ||
|
|
365
381
|
includes('prefer import testing') ||
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pumuki",
|
|
3
|
-
"version": "6.3.
|
|
3
|
+
"version": "6.3.219",
|
|
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-
|
|
4
|
+
"generatedAt": "2026-05-13T15:50:45.972Z",
|
|
5
5
|
"bundles": [
|
|
6
6
|
{
|
|
7
7
|
"name": "android-guidelines",
|
|
@@ -5764,8 +5764,20 @@
|
|
|
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": "2d56094eff6a0b688d9f20ef6970de5945dfa74aaf3a3973dfee2091b9e98542",
|
|
5768
5768
|
"rules": [
|
|
5769
|
+
{
|
|
5770
|
+
"id": "skills.ios.guideline.ios-swiftui-expert.use-task-modifier-for-automatic-cancellation-of-async-work",
|
|
5771
|
+
"description": ".task/.task(id:) - Trabajos async con cancelación automática",
|
|
5772
|
+
"severity": "WARN",
|
|
5773
|
+
"platform": "ios",
|
|
5774
|
+
"sourceSkill": "ios-guidelines",
|
|
5775
|
+
"sourcePath": "vendor/skills/ios-enterprise-rules/SKILL.md",
|
|
5776
|
+
"confidence": "MEDIUM",
|
|
5777
|
+
"locked": true,
|
|
5778
|
+
"evaluationMode": "AUTO",
|
|
5779
|
+
"origin": "core"
|
|
5780
|
+
},
|
|
5769
5781
|
{
|
|
5770
5782
|
"id": "skills.ios.guideline.ios.accessibility-identifiers-para-localizar-elementos",
|
|
5771
5783
|
"description": "Accessibility identifiers - Para localizar elementos",
|
|
@@ -7927,18 +7939,6 @@
|
|
|
7927
7939
|
"evaluationMode": "DECLARATIVE",
|
|
7928
7940
|
"origin": "core"
|
|
7929
7941
|
},
|
|
7930
|
-
{
|
|
7931
|
-
"id": "skills.ios.guideline.ios.task-task-id-trabajos-async-con-cancelacio-n-automa-tica",
|
|
7932
|
-
"description": ".task/.task(id:) - Trabajos async con cancelación automática",
|
|
7933
|
-
"severity": "WARN",
|
|
7934
|
-
"platform": "ios",
|
|
7935
|
-
"sourceSkill": "ios-guidelines",
|
|
7936
|
-
"sourcePath": "vendor/skills/ios-enterprise-rules/SKILL.md",
|
|
7937
|
-
"confidence": "MEDIUM",
|
|
7938
|
-
"locked": true,
|
|
7939
|
-
"evaluationMode": "DECLARATIVE",
|
|
7940
|
-
"origin": "core"
|
|
7941
|
-
},
|
|
7942
7942
|
{
|
|
7943
7943
|
"id": "skills.ios.guideline.ios.taskgroup-para-operaciones-paralelas",
|
|
7944
7944
|
"description": "TaskGroup - Para operaciones paralelas",
|
|
@@ -8632,7 +8632,7 @@
|
|
|
8632
8632
|
"name": "ios-swiftui-expert-guidelines",
|
|
8633
8633
|
"version": "1.0.0",
|
|
8634
8634
|
"source": "file:vendor/skills/swiftui-expert-skill/SKILL.md",
|
|
8635
|
-
"hash": "
|
|
8635
|
+
"hash": "b936508c5fea766c83bca01087374a8c0281ba86c4ee022d43db316b89c07cd6",
|
|
8636
8636
|
"rules": [
|
|
8637
8637
|
{
|
|
8638
8638
|
"id": "skills.ios.guideline.ios-swiftui-expert.always-mark-state-and-stateobject-as-private-makes-dependencies-clear",
|
|
@@ -8643,7 +8643,7 @@
|
|
|
8643
8643
|
"sourcePath": "vendor/skills/swiftui-expert-skill/SKILL.md",
|
|
8644
8644
|
"confidence": "MEDIUM",
|
|
8645
8645
|
"locked": true,
|
|
8646
|
-
"evaluationMode": "
|
|
8646
|
+
"evaluationMode": "AUTO",
|
|
8647
8647
|
"origin": "core"
|
|
8648
8648
|
},
|
|
8649
8649
|
{
|
|
@@ -8907,7 +8907,7 @@
|
|
|
8907
8907
|
"sourcePath": "vendor/skills/swiftui-expert-skill/SKILL.md",
|
|
8908
8908
|
"confidence": "MEDIUM",
|
|
8909
8909
|
"locked": true,
|
|
8910
|
-
"evaluationMode": "
|
|
8910
|
+
"evaluationMode": "AUTO",
|
|
8911
8911
|
"origin": "core"
|
|
8912
8912
|
},
|
|
8913
8913
|
{
|