pumuki 6.3.246 → 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 +14 -0
- package/core/facts/detectors/text/ios.test.ts +112 -0
- package/core/facts/detectors/text/ios.ts +62 -0
- package/core/facts/extractHeuristicFacts.ts +3 -0
- package/core/rules/presets/heuristics/ios.test.ts +16 -1
- package/core/rules/presets/heuristics/ios.ts +57 -0
- package/docs/operations/RELEASE_NOTES.md +7 -0
- package/integrations/config/skillsCompilerTemplates.ts +10 -0
- package/integrations/config/skillsDetectorRegistry.ts +18 -24
- package/integrations/config/skillsMarkdownRules.ts +143 -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 +112 -195
|
@@ -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
|
}
|
|
@@ -330,6 +337,13 @@ const normalizeKnownRuleTarget = (
|
|
|
330
337
|
) {
|
|
331
338
|
return 'skills.ios.guideline.ios-swiftui-expert.prefer-modifiers-over-conditional-views-for-state-changes-maintains-vi';
|
|
332
339
|
}
|
|
340
|
+
if (
|
|
341
|
+
includes('sheets should own their actions') ||
|
|
342
|
+
(includes('call dismiss internally') && includes('sheet')) ||
|
|
343
|
+
(includes('avoid passing dismiss') && includes('callbacks to sheets'))
|
|
344
|
+
) {
|
|
345
|
+
return 'skills.ios.guideline.ios-swiftui-expert.sheets-should-own-their-actions-and-call-dismiss-internally';
|
|
346
|
+
}
|
|
333
347
|
if (
|
|
334
348
|
(includes('foreach') && includes('indices')) ||
|
|
335
349
|
includes('stable identity for foreach') ||
|
|
@@ -484,6 +498,12 @@ const normalizeKnownRuleTarget = (
|
|
|
484
498
|
if (includes('uiscreen main bounds') || includes('uiscreen.main.bounds')) {
|
|
485
499
|
return 'skills.ios.no-uiscreen-main-bounds';
|
|
486
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
|
+
}
|
|
487
507
|
if (
|
|
488
508
|
includes('task/.task(id') ||
|
|
489
509
|
includes('trabajos async con cancelacion automatica') ||
|
|
@@ -493,15 +513,127 @@ const normalizeKnownRuleTarget = (
|
|
|
493
513
|
) {
|
|
494
514
|
return 'skills.ios.guideline.ios-swiftui-expert.use-task-modifier-for-automatic-cancellation-of-async-work';
|
|
495
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
|
+
}
|
|
496
623
|
if (
|
|
497
624
|
includes('swift testing over xctest') ||
|
|
498
625
|
includes('prefer import testing') ||
|
|
499
626
|
includes('prefer test functions over test methods') ||
|
|
500
627
|
includes('test functions over test methods') ||
|
|
501
628
|
includes('xctest-only unit tests') ||
|
|
629
|
+
includes('xctest only unit tests') ||
|
|
502
630
|
includes('new xctest-only unit tests') ||
|
|
631
|
+
includes('new xctest only unit tests') ||
|
|
503
632
|
includes('xctest only for ui') ||
|
|
504
|
-
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'))
|
|
505
637
|
) {
|
|
506
638
|
return 'skills.ios.prefer-swift-testing';
|
|
507
639
|
}
|
|
@@ -532,13 +664,6 @@ const normalizeKnownRuleTarget = (
|
|
|
532
664
|
) {
|
|
533
665
|
return 'skills.ios.guideline.ios.app-transport-security-ats-https-por-defecto';
|
|
534
666
|
}
|
|
535
|
-
if (
|
|
536
|
-
includes('localizable strings') ||
|
|
537
|
-
includes('string catalogs') ||
|
|
538
|
-
includes('xcstrings')
|
|
539
|
-
) {
|
|
540
|
-
return 'skills.ios.guideline.ios.localizable-strings-deprecado-usar-string-catalogs';
|
|
541
|
-
}
|
|
542
667
|
if (includes('strings hardcodeadas') || includes('string localized')) {
|
|
543
668
|
return 'skills.ios.guideline.ios.cero-strings-hardcodeadas-en-ui';
|
|
544
669
|
}
|
|
@@ -639,9 +764,16 @@ const normalizeKnownRuleTarget = (
|
|
|
639
764
|
}
|
|
640
765
|
if (
|
|
641
766
|
includes('nsmanagedobject across boundaries') ||
|
|
767
|
+
includes('nsmanagedobjectid or mapped dto') ||
|
|
768
|
+
includes('mapped dto domain models') ||
|
|
642
769
|
includes('passing nsmanagedobject') ||
|
|
770
|
+
includes('pass nsmanagedobjectid when a different context') ||
|
|
643
771
|
includes('nsmanagedobject through service') ||
|
|
644
|
-
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')
|
|
645
777
|
) {
|
|
646
778
|
return 'skills.ios.no-nsmanagedobject-boundary';
|
|
647
779
|
}
|
|
@@ -663,6 +795,8 @@ const normalizeKnownRuleTarget = (
|
|
|
663
795
|
}
|
|
664
796
|
if (
|
|
665
797
|
includes('core data orchestration inside infrastructure') ||
|
|
798
|
+
includes('make context ownership explicit') ||
|
|
799
|
+
includes('merge boundaries controlled') ||
|
|
666
800
|
includes('instead of presentation code') ||
|
|
667
801
|
includes('core data apis in application or presentation code') ||
|
|
668
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,
|