pumuki 6.3.163 → 6.3.165

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 CHANGED
@@ -6,6 +6,19 @@ This project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [6.3.165] - 2026-05-06
10
+
11
+ ### Fixed
12
+
13
+ - **MCP evidence stdio PRE_PUSH:** los defaults de host, ruta, puerto y timeout quedan nombrados como constantes para cumplir reglas backend de configuración y evitar bloqueos del hook al publicar ramas de release.
14
+
15
+ ## [6.3.164] - 2026-05-06
16
+
17
+ ### Fixed
18
+
19
+ - **PUMUKI-INC-130 XCTest helpers brownfield:** `trackForMemoryLeaks`/factory helpers that import `XCTest` but do not define `XCTestCase` suites or `test...` methods no longer trigger `skills.ios.critical-test-quality`.
20
+ - **Skills runtime enforcement:** declarative skill registry rules stay visible in coverage metadata without being counted as missing runtime AST detectors; AUTO rules without detector mapping still fail closed.
21
+
9
22
  ## [6.3.143] - 2026-05-05
10
23
 
11
24
  ### Fixed
package/VERSION CHANGED
@@ -1 +1 @@
1
- v6.3.132
1
+ v6.3.165
@@ -683,10 +683,46 @@ func trackForMemoryLeaks(_ instance: AnyObject, file: StaticString = #filePath,
683
683
  addTeardownBlock { _ = instance }
684
684
  }
685
685
  `;
686
+ const ruralGoHelperSource = `
687
+ import XCTest
688
+
689
+ final class WeakReference<T: AnyObject> {
690
+ weak var value: T?
691
+
692
+ init(_ value: T) {
693
+ self.value = value
694
+ }
695
+ }
696
+
697
+ func trackForMemoryLeaks(
698
+ _ instance: AnyObject,
699
+ testCase: XCTestCase,
700
+ file: StaticString = #filePath,
701
+ line: UInt = #line
702
+ ) {
703
+ nonisolated(unsafe) let reference = makeSUT(instance)
704
+ testCase.addTeardownBlock {
705
+ XCTAssertNil(
706
+ reference.value,
707
+ "Instance should have been deallocated. Potential memory leak.",
708
+ file: file,
709
+ line: line
710
+ )
711
+ }
712
+ }
713
+
714
+ private func makeSUT<T: AnyObject>(_ instance: T) -> WeakReference<T> {
715
+ WeakReference(instance)
716
+ }
717
+ `;
686
718
 
687
719
  assert.equal(hasSwiftLegacyXCTestImportUsage(helperSource), false);
688
720
  assert.equal(hasSwiftModernizableXCTestSuiteUsage(helperSource), false);
689
721
  assert.equal(hasSwiftXCTestAssertionUsage(helperSource), false);
722
+ assert.equal(hasSwiftLegacyXCTestImportUsage(ruralGoHelperSource), false);
723
+ assert.equal(hasSwiftModernizableXCTestSuiteUsage(ruralGoHelperSource), false);
724
+ assert.equal(hasSwiftXCTestAssertionUsage(ruralGoHelperSource), false);
725
+ assert.equal(hasSwiftXCTUnwrapUsage(ruralGoHelperSource), false);
690
726
  });
691
727
 
692
728
  test('hasSwiftXCTUnwrapUsage detecta XCTUnwrap real y evita strings', () => {
@@ -840,6 +840,14 @@ const hasSwiftXCTestOnlyBrownfieldSuiteUsage = (source: string): boolean => {
840
840
  return !hasSwiftTestingImportUsage(source) && !hasSwiftTestingSuiteAttributeUsage(source);
841
841
  };
842
842
 
843
+ const hasSwiftXCTestHelperOrFactoryUsage = (source: string): boolean => {
844
+ return (
845
+ hasSwiftXCTestImportUsage(source) &&
846
+ !hasSwiftXCTestCaseSubclassUsage(source) &&
847
+ !hasSwiftLegacyXCTestMethodUsage(source)
848
+ );
849
+ };
850
+
843
851
  export const hasSwiftLegacyXCTestImportUsage = (source: string): boolean => {
844
852
  if (!hasSwiftXCTestImportUsage(source)) {
845
853
  return false;
@@ -885,6 +893,10 @@ export const hasSwiftXCTestAssertionUsage = (source: string): boolean => {
885
893
  return false;
886
894
  }
887
895
 
896
+ if (hasSwiftXCTestHelperOrFactoryUsage(source)) {
897
+ return false;
898
+ }
899
+
888
900
  if (hasSwiftXCTestOnlyBrownfieldSuiteUsage(source)) {
889
901
  return false;
890
902
  }
@@ -900,6 +912,10 @@ export const hasSwiftXCTUnwrapUsage = (source: string): boolean => {
900
912
  return false;
901
913
  }
902
914
 
915
+ if (hasSwiftXCTestHelperOrFactoryUsage(source)) {
916
+ return false;
917
+ }
918
+
903
919
  if (hasSwiftXCTestOnlyBrownfieldSuiteUsage(source)) {
904
920
  return false;
905
921
  }
@@ -916,6 +932,10 @@ const hasSwiftConfirmationUsage = (source: string): boolean => {
916
932
  };
917
933
 
918
934
  export const hasSwiftWaitForExpectationsUsage = (source: string): boolean => {
935
+ if (hasSwiftXCTestHelperOrFactoryUsage(source)) {
936
+ return false;
937
+ }
938
+
919
939
  const legacyWaitPattern = /\bwait\s*\(\s*for\s*:|\bwaitForExpectations\s*\(/;
920
940
  return collectSwiftFunctionDeclarations(source).some((declaration) => {
921
941
  if (!/\basync\b/.test(declaration.signature)) {
@@ -927,6 +947,10 @@ export const hasSwiftWaitForExpectationsUsage = (source: string): boolean => {
927
947
  };
928
948
 
929
949
  export const hasSwiftLegacyExpectationDescriptionUsage = (source: string): boolean => {
950
+ if (hasSwiftXCTestHelperOrFactoryUsage(source)) {
951
+ return false;
952
+ }
953
+
930
954
  return collectSwiftFunctionDeclarations(source).some((declaration) => {
931
955
  if (!/\basync\b/.test(declaration.signature)) {
932
956
  return false;
@@ -8,6 +8,15 @@ const PACKAGE_ROOT = resolve(__dirname, '..', '..');
8
8
 
9
9
  let cachedCoreSkillsLock: SkillsLockV1 | undefined;
10
10
 
11
+ const writeDebugFallback = (error: unknown): void => {
12
+ if (process.env.PUMUKI_DEBUG !== '1') {
13
+ return;
14
+ }
15
+
16
+ const message = error instanceof Error ? error.message : String(error);
17
+ process.stderr.write(`[pumuki][skills-lock] compile fallback: ${message}\n`);
18
+ };
19
+
11
20
  export const resolveCoreSkillsLockForPackageRoot = (
12
21
  packageRoot: string
13
22
  ): SkillsLockV1 | undefined => {
@@ -20,7 +29,8 @@ export const resolveCoreSkillsLockForPackageRoot = (
20
29
  if (compiledLock.bundles.length > 0) {
21
30
  return compiledLock;
22
31
  }
23
- } catch {
32
+ } catch (error) {
33
+ writeDebugFallback(error);
24
34
  }
25
35
 
26
36
  return loadSkillsLock(packageRoot);
@@ -603,7 +603,6 @@ export const loadSkillsRuleSetForStage = (
603
603
  continue;
604
604
  }
605
605
  if (evaluationMode !== 'AUTO') {
606
- unsupportedDetectorRuleIds.add(compiledRule.id);
607
606
  continue;
608
607
  }
609
608
  stageApplicableAutoRuleIds.add(compiledRule.id);
@@ -21,6 +21,10 @@ type JsonRpcResponse = {
21
21
  };
22
22
 
23
23
  const MCP_PROTOCOL_VERSION = '2024-11-05';
24
+ const DEFAULT_EVIDENCE_HOST = '127.0.0.1';
25
+ const DEFAULT_EVIDENCE_ROUTE = '/ai-evidence';
26
+ const DEFAULT_EVIDENCE_PORT = 7341;
27
+ const PORT_PROBE_TIMEOUT_MS = 600;
24
28
 
25
29
  const toJsonRpcId = (value: unknown): JsonRpcId => {
26
30
  if (typeof value === 'string' || typeof value === 'number' || value === null) {
@@ -55,7 +59,7 @@ const sendError = (id: JsonRpcId, code: number, message: string): void => {
55
59
  const isPortInUse = async (host: string, port: number): Promise<boolean> =>
56
60
  await new Promise((resolve) => {
57
61
  const socket = new Socket();
58
- socket.setTimeout(600);
62
+ socket.setTimeout(PORT_PROBE_TIMEOUT_MS);
59
63
  socket.once('connect', () => {
60
64
  socket.destroy();
61
65
  resolve(true);
@@ -91,15 +95,24 @@ const fetchJson = async (url: string): Promise<unknown> => {
91
95
  return JSON.parse(text) as unknown;
92
96
  };
93
97
 
98
+ const writeDebugHealthProbeFailure = (error: unknown): void => {
99
+ if (process.env.PUMUKI_DEBUG !== '1') {
100
+ return;
101
+ }
102
+
103
+ const message = error instanceof Error ? error.message : String(error);
104
+ process.stderr.write(`[pumuki-mcp-evidence-stdio] health probe fallback: ${message}\n`);
105
+ };
106
+
94
107
  const startOrReuseEvidenceHttp = async (): Promise<{
95
108
  host: string;
96
109
  port: number;
97
110
  route: string;
98
111
  }> => {
99
- const host = process.env.PUMUKI_EVIDENCE_HOST ?? '127.0.0.1';
100
- const route = process.env.PUMUKI_EVIDENCE_ROUTE ?? '/ai-evidence';
112
+ const host = process.env.PUMUKI_EVIDENCE_HOST ?? DEFAULT_EVIDENCE_HOST;
113
+ const route = process.env.PUMUKI_EVIDENCE_ROUTE ?? DEFAULT_EVIDENCE_ROUTE;
101
114
  const parsedPort = Number.parseInt(process.env.PUMUKI_EVIDENCE_PORT ?? '', 10);
102
- const preferredPort = Number.isFinite(parsedPort) ? parsedPort : 7341;
115
+ const preferredPort = Number.isFinite(parsedPort) ? parsedPort : DEFAULT_EVIDENCE_PORT;
103
116
  const requestedPort = preferredPort > 0 ? preferredPort : await findEphemeralPort(host);
104
117
  const healthUrl = `http://${host}:${requestedPort}/health`;
105
118
 
@@ -108,8 +121,8 @@ const startOrReuseEvidenceHttp = async (): Promise<{
108
121
  if (health.status === 'ok') {
109
122
  return { host, port: requestedPort, route };
110
123
  }
111
- } catch {
112
- // ignored
124
+ } catch (error) {
125
+ writeDebugHealthProbeFailure(error);
113
126
  }
114
127
 
115
128
  const portInUse = await isPortInUse(host, requestedPort);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pumuki",
3
- "version": "6.3.163",
3
+ "version": "6.3.165",
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": {