pumuki 6.3.114 → 6.3.116

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,13 +6,23 @@ This project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
- ## [6.3.114] - 2026-04-24
9
+ ## [6.3.116] - 2026-04-25
10
+
11
+ ### Fixed
12
+
13
+ - **Inventario real de dependencia local en `status` y `doctor`:** la línea publicada diferencia por fin la señal de seguridad Git (`trackedNodeModulesCount` / `trackedNodeModulesPaths`) del estado real de instalación local (`dependencyInventory`).
14
+ - **Diagnóstico consumer-facing de `pumuki`:** `status --json` y `doctor --json` exponen si existe `package.json`, lockfile, `node_modules`, declaración de `pumuki`, versión instalada y binario local.
15
+ - **Salida humana alineada:** `status` y `doctor` imprimen una línea compacta `dependency pumuki` para que el operador no confunda ausencia de `node_modules` trackeados con ausencia de instalación local.
16
+ - **Cobertura de regresión de `PUMUKI-INC-088`:** nuevas pruebas fijan el inventario de dependencia en ambas superficies lifecycle sin arrastrar el delta amplio de `develop`.
17
+
18
+ ## [6.3.115] - 2026-04-24
10
19
 
11
20
  ### Fixed
12
21
 
13
22
  - **`status` y `doctor` exponen `issues` canónicos también en evidencia `WARN`:** la línea publicada deja de reservar la lista de findings a estados bloqueados y pasa a emitir una advertencia consumible por automatización cuando governance está en atención operativa real.
14
23
  - **Hotfix mínimo sobre la superficie estable de `main`:** el contrato bloqueado existente se conserva, pero ahora la evidencia `WARN` produce `Governance requires attention (...)` como issue canónico sin arrastrar snapshots adicionales de `develop`.
15
24
  - **Cobertura de regresión de `INC-084` en la línea publicada:** nuevas pruebas fijan el caso `WARN` tanto en `status` como en `doctor`, manteniendo la semántica previa para estados `BLOCK`.
25
+ - **Regresión de `postinstall` resuelta en la línea publicada:** `captureRepoState` deja de importar `status.ts` y rompe el ciclo que hacía fallar `scripts/consumer-postinstall.cjs` con `ReferenceError: Cannot access 'captureRepoState' before initialization`.
16
26
 
17
27
  ## [6.3.108] - 2026-04-22
18
28
 
package/VERSION CHANGED
@@ -1 +1 @@
1
- v6.3.114
1
+ v6.3.116
@@ -6,11 +6,18 @@ 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-04-24 (v6.3.114)
9
+ ### 2026-04-25 (v6.3.116)
10
+
11
+ - **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.
12
+ - **Cierre útil de `PUMUKI-INC-088`:** los consumers pueden ver si `pumuki` está declarado, instalado, con qué versión y si el binario local existe, sin inferirlo desde `git ls-files node_modules`.
13
+ - **Rollout recomendado:** publicar `pumuki@6.3.116`, repin inmediato en `RuralGo` y revalidar `status --json` / `doctor --json` comprobando `dependencyInventory.pumuki.installedVersion`.
14
+
15
+ ### 2026-04-24 (v6.3.115)
10
16
 
11
17
  - **`issues` canónicos también para `WARN`:** `status` y `doctor` ya no dejan `issues=[]` cuando la evidencia operativa real está en atención (`WARN`) pero aún no bloquea el gate.
12
18
  - **Cierre útil de `PUMUKI-INC-084` en la línea publicada:** el consumer puede automatizar tanto estados `BLOCK` como `WARN` sin recombinar `attention_codes` y `human_summary_preview` por su cuenta.
13
- - **Rollout recomendado:** publicar `pumuki@6.3.114`, repin inmediato en `RuralGo` y revalidar `status --json` / `doctor --json` comprobando que la evidencia `WARN` ya aparece dentro de `issues`.
19
+ - **`postinstall` vuelve a ser instalable en consumers reales:** la release evita el ciclo en `repoState` que rompía `npm install pumuki@6.3.114`.
20
+ - **Rollout recomendado:** publicar `pumuki@6.3.115`, repin inmediato en `RuralGo` y revalidar `status --json` / `doctor --json` comprobando que la evidencia `WARN` ya aparece dentro de `issues`.
14
21
 
15
22
  ### 2026-04-22 (v6.3.108)
16
23
 
@@ -1,8 +1,10 @@
1
1
  import { execFileSync as runBinarySync } from 'node:child_process';
2
2
  import { existsSync, readFileSync } from 'node:fs';
3
3
  import { join } from 'node:path';
4
- import { readLifecycleStatus } from '../lifecycle/status';
4
+ import { LifecycleGitService } from '../lifecycle/gitService';
5
+ import { getPumukiHooksStatus } from '../lifecycle/hookManager';
5
6
  import { resolvePumukiVersionMetadata } from '../lifecycle/packageInfo';
7
+ import { readLifecycleState } from '../lifecycle/state';
6
8
  import { readPersistedHardModeConfig } from '../policy/policyProfiles';
7
9
  import type { RepoHardModeState, RepoHookState, RepoState } from './schema';
8
10
 
@@ -73,10 +75,13 @@ const toAheadBehind = (
73
75
  };
74
76
 
75
77
  const readLifecycleStatusSafe = (repoRoot: string): LifecycleStatusShape => {
78
+ const git = new LifecycleGitService();
76
79
  try {
77
- return readLifecycleStatus({
78
- cwd: repoRoot,
79
- });
80
+ return {
81
+ lifecycleState: readLifecycleState(git, repoRoot),
82
+ packageVersion: resolvePumukiVersionMetadata({ repoRoot }).resolvedVersion,
83
+ hookStatus: getPumukiHooksStatus(repoRoot),
84
+ };
80
85
  } catch {
81
86
  return {
82
87
  lifecycleState: {},
@@ -1555,6 +1555,9 @@ const printDoctorReport = (
1555
1555
  writeInfo(
1556
1556
  `[pumuki] tracked node_modules paths: ${report.trackedNodeModulesPaths.length}`
1557
1557
  );
1558
+ writeInfo(
1559
+ `[pumuki] dependency pumuki: declared=${report.dependencyInventory.pumuki.declared ? 'yes' : 'no'}, installed=${report.dependencyInventory.pumuki.installed ? 'yes' : 'no'}, version=${report.dependencyInventory.pumuki.installedVersion ?? 'unknown'}, bin=${report.dependencyInventory.pumuki.binPresent ? 'present' : 'missing'}`
1560
+ );
1558
1561
  writeInfo(
1559
1562
  `[pumuki] hook pre-commit: ${report.hookStatus['pre-commit'].managedBlockPresent ? 'managed' : 'missing'}`
1560
1563
  );
@@ -2428,6 +2431,9 @@ export const runLifecycleCli = async (
2428
2431
  writeInfo(
2429
2432
  `[pumuki] tracked node_modules paths: ${status.trackedNodeModulesCount}`
2430
2433
  );
2434
+ writeInfo(
2435
+ `[pumuki] dependency pumuki: declared=${status.dependencyInventory.pumuki.declared ? 'yes' : 'no'}, installed=${status.dependencyInventory.pumuki.installed ? 'yes' : 'no'}, version=${status.dependencyInventory.pumuki.installedVersion ?? 'unknown'}, bin=${status.dependencyInventory.pumuki.binPresent ? 'present' : 'missing'}`
2436
+ );
2431
2437
  writeInfo(
2432
2438
  `[pumuki] policy-as-code: PRE_COMMIT=${status.policyValidation.stages.PRE_COMMIT.validationCode ?? 'n/a'} strict=${status.policyValidation.stages.PRE_COMMIT.strict ? 'yes' : 'no'} ` +
2433
2439
  `PRE_PUSH=${status.policyValidation.stages.PRE_PUSH.validationCode ?? 'n/a'} strict=${status.policyValidation.stages.PRE_PUSH.strict ? 'yes' : 'no'} ` +
@@ -0,0 +1,92 @@
1
+ import { existsSync, readFileSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import packageJson from '../../package.json';
4
+
5
+ export type LifecycleDependencyInventory = {
6
+ nodeModulesPresent: boolean;
7
+ packageJsonPresent: boolean;
8
+ lockfilePresent: boolean;
9
+ pumuki: {
10
+ declared: boolean;
11
+ declaredRange: string | null;
12
+ installed: boolean;
13
+ installedVersion: string | null;
14
+ packageJsonPath: string | null;
15
+ binPath: string | null;
16
+ binPresent: boolean;
17
+ };
18
+ };
19
+
20
+ const readJsonRecord = (path: string): Record<string, unknown> | null => {
21
+ if (!existsSync(path)) {
22
+ return null;
23
+ }
24
+
25
+ try {
26
+ const parsed = JSON.parse(readFileSync(path, 'utf8')) as unknown;
27
+ return typeof parsed === 'object' && parsed !== null && !Array.isArray(parsed)
28
+ ? (parsed as Record<string, unknown>)
29
+ : null;
30
+ } catch {
31
+ return null;
32
+ }
33
+ };
34
+
35
+ const readDependencyRange = (
36
+ manifest: Record<string, unknown> | null,
37
+ dependencyName: string
38
+ ): string | null => {
39
+ if (!manifest) {
40
+ return null;
41
+ }
42
+
43
+ for (const section of ['dependencies', 'devDependencies', 'optionalDependencies'] as const) {
44
+ const dependencies = manifest[section];
45
+ if (typeof dependencies !== 'object' || dependencies === null || Array.isArray(dependencies)) {
46
+ continue;
47
+ }
48
+
49
+ const value = (dependencies as Record<string, unknown>)[dependencyName];
50
+ if (typeof value === 'string' && value.trim().length > 0) {
51
+ return value.trim();
52
+ }
53
+ }
54
+
55
+ return null;
56
+ };
57
+
58
+ const readInstalledVersion = (installedManifest: Record<string, unknown> | null): string | null => {
59
+ const version = installedManifest?.version;
60
+ return typeof version === 'string' && version.trim().length > 0 ? version.trim() : null;
61
+ };
62
+
63
+ export const readLifecycleDependencyInventory = (
64
+ repoRoot: string
65
+ ): LifecycleDependencyInventory => {
66
+ const manifestPath = join(repoRoot, 'package.json');
67
+ const nodeModulesPath = join(repoRoot, 'node_modules');
68
+ const lockfilePath = join(repoRoot, 'package-lock.json');
69
+ const installedPackageJsonPath = join(nodeModulesPath, packageJson.name, 'package.json');
70
+ const binName = process.platform === 'win32' ? `${packageJson.name}.cmd` : packageJson.name;
71
+ const binPath = join(nodeModulesPath, '.bin', binName);
72
+ const manifest = readJsonRecord(manifestPath);
73
+ const installedManifest = readJsonRecord(installedPackageJsonPath);
74
+ const declaredRange = readDependencyRange(manifest, packageJson.name);
75
+ const installedVersion = readInstalledVersion(installedManifest);
76
+ const binPresent = existsSync(binPath);
77
+
78
+ return {
79
+ nodeModulesPresent: existsSync(nodeModulesPath),
80
+ packageJsonPresent: existsSync(manifestPath),
81
+ lockfilePresent: existsSync(lockfilePath),
82
+ pumuki: {
83
+ declared: declaredRange !== null,
84
+ declaredRange,
85
+ installed: installedVersion !== null,
86
+ installedVersion,
87
+ packageJsonPath: installedVersion !== null ? `node_modules/${packageJson.name}/package.json` : null,
88
+ binPath: binPresent ? `node_modules/.bin/${binName}` : null,
89
+ binPresent,
90
+ },
91
+ };
92
+ };
@@ -16,6 +16,10 @@ import {
16
16
  evaluateOpenSpecCompatibility,
17
17
  isOpenSpecProjectInitialized,
18
18
  } from '../sdd/openSpecCli';
19
+ import {
20
+ readLifecycleDependencyInventory,
21
+ type LifecycleDependencyInventory,
22
+ } from './dependencyInventory';
19
23
 
20
24
  export type DoctorIssueSeverity = 'warning' | 'error';
21
25
 
@@ -91,6 +95,7 @@ export type LifecycleDoctorReport = {
91
95
  packageVersion: string;
92
96
  version: ReturnType<typeof buildLifecycleVersionReport>;
93
97
  lifecycleState: LifecycleState;
98
+ dependencyInventory: LifecycleDependencyInventory;
94
99
  trackedNodeModulesPaths: ReadonlyArray<string>;
95
100
  hookStatus: ReturnType<typeof getPumukiHooksStatus>;
96
101
  hooksDirectory: string;
@@ -842,6 +847,7 @@ export const runLifecycleDoctor = (params?: {
842
847
  const cwd = params?.cwd ?? process.cwd();
843
848
  const repoRoot = git.resolveRepoRoot(cwd);
844
849
  const trackedNodeModulesPaths = git.trackedNodeModulesPaths(repoRoot);
850
+ const dependencyInventory = readLifecycleDependencyInventory(repoRoot);
845
851
  const hooksDirectory = resolvePumukiHooksDirectory(repoRoot);
846
852
  const hookStatus = getPumukiHooksStatus(repoRoot);
847
853
  const lifecycleState = readLifecycleState(git, repoRoot);
@@ -886,6 +892,7 @@ export const runLifecycleDoctor = (params?: {
886
892
  packageVersion: version.effective,
887
893
  version,
888
894
  lifecycleState,
895
+ dependencyInventory,
889
896
  trackedNodeModulesPaths,
890
897
  hookStatus,
891
898
  hooksDirectory: hooksDirectory.path,
@@ -13,6 +13,10 @@ import {
13
13
  } from './policyValidationSnapshot';
14
14
  import { readLifecycleState, type LifecycleState } from './state';
15
15
  import type { DoctorIssue } from './doctor';
16
+ import {
17
+ readLifecycleDependencyInventory,
18
+ type LifecycleDependencyInventory,
19
+ } from './dependencyInventory';
16
20
 
17
21
  export type LifecycleStatus = {
18
22
  repoRoot: string;
@@ -23,6 +27,7 @@ export type LifecycleStatus = {
23
27
  hooksDirectory: string;
24
28
  hooksDirectoryResolution: 'git-rev-parse' | 'git-config' | 'default';
25
29
  trackedNodeModulesCount: number;
30
+ dependencyInventory: LifecycleDependencyInventory;
26
31
  policyValidation: LifecyclePolicyValidationSnapshot;
27
32
  experimentalFeatures: LifecycleExperimentalFeaturesSnapshot;
28
33
  issues: ReadonlyArray<DoctorIssue>;
@@ -79,6 +84,7 @@ export const readLifecycleStatus = (params?: {
79
84
  const repoRoot = git.resolveRepoRoot(cwd);
80
85
  const hooksDirectory = resolvePumukiHooksDirectory(repoRoot);
81
86
  const trackedNodeModulesCount = git.trackedNodeModulesPaths(repoRoot).length;
87
+ const dependencyInventory = readLifecycleDependencyInventory(repoRoot);
82
88
  const lifecycleState = readLifecycleState(git, repoRoot);
83
89
  const version = buildLifecycleVersionReport({
84
90
  repoRoot,
@@ -97,6 +103,7 @@ export const readLifecycleStatus = (params?: {
97
103
  hooksDirectory: hooksDirectory.path,
98
104
  hooksDirectoryResolution: hooksDirectory.source,
99
105
  trackedNodeModulesCount,
106
+ dependencyInventory,
100
107
  policyValidation,
101
108
  experimentalFeatures,
102
109
  issues,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pumuki",
3
- "version": "6.3.114",
3
+ "version": "6.3.116",
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": {