pumuki 6.3.105 → 6.3.107
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 +15 -0
- package/VERSION +1 -1
- package/docs/operations/RELEASE_NOTES.md +12 -0
- package/integrations/lifecycle/cli.ts +13 -4
- package/integrations/lifecycle/cliSdd.ts +4 -4
- package/integrations/sdd/policy.ts +34 -26
- package/integrations/sdd/sessionStore.ts +3 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,21 @@ This project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [6.3.107] - 2026-04-22
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
|
|
13
|
+
- **Semántica inequívoca para sesión SDD expirada:** una sesión vencida deja de proyectarse como `active=true` y pasa a exponerse como inactiva (`active=false`) manteniendo `valid=false` y `remainingSeconds=0`.
|
|
14
|
+
- **Refresh de sesión expiradas todavía permitido:** `refreshSddSession` ya no exige `active=true`; basta con conservar el `changeId` para poder renovar una sesión caducada sin reabrirla manualmente.
|
|
15
|
+
- **Policy SDD alineada con esa semántica:** `evaluateSddPolicy` trata la sesión como `missing` solo cuando falta `changeId`, y conserva `SDD_SESSION_INVALID` para sesiones expiradas con contexto recuperable.
|
|
16
|
+
|
|
17
|
+
## [6.3.106] - 2026-04-22
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
|
|
21
|
+
- **Activación advisory de SDD/PRE_WRITE fijada al runtime diagnosticado:** `sdd validate` deja de devolver `activation_command` con `pumuki@latest` cuando el namespace experimental está desactivado por defecto.
|
|
22
|
+
- **Session guidance reproducible en SDD:** las instrucciones de `session --refresh` y `session --open` también quedan fijadas a la versión efectiva del runtime en lugar de depender de `latest`.
|
|
23
|
+
|
|
9
24
|
## [6.3.105] - 2026-04-22
|
|
10
25
|
|
|
11
26
|
### Fixed
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
v6.3.
|
|
1
|
+
v6.3.106
|
|
@@ -6,6 +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-22 (v6.3.107)
|
|
10
|
+
|
|
11
|
+
- **Sesión SDD expirada sin semántica ambigua:** la línea publicada deja de diagnosticar sesiones vencidas como `active=true` con `valid=false`; ahora las proyecta como inactivas y mantiene la señal de expiración con `remainingSeconds=0`.
|
|
12
|
+
- **Refresh reproducible de sesiones caducadas:** si el `changeId` sigue siendo válido, `session --refresh` vuelve a servir para recuperar la sesión sin exigir un `session --open` innecesario.
|
|
13
|
+
- **Rollout recomendado:** publicar `pumuki@6.3.107`, repin inmediato en `RuralGo` y revalidar `sdd validate --stage=PRE_WRITE --json` comprobando que `status.session.active=false`, `valid=false` y que la remediación siga permitiendo refresh sobre el mismo `changeId`.
|
|
14
|
+
|
|
15
|
+
### 2026-04-22 (v6.3.106)
|
|
16
|
+
|
|
17
|
+
- **Cierre útil del literal residual en RuralGo:** `sdd validate --stage=PRE_WRITE --json` ya no recomienda activar SDD con `pumuki@latest`; devuelve el mismo runtime versionado que está diagnosticando.
|
|
18
|
+
- **Guía de sesión SDD alineada:** `session --refresh` y `session --open` quedan versionados para evitar drift en repos consumidores.
|
|
19
|
+
- **Rollout recomendado:** publicar `pumuki@6.3.106`, repin inmediato en `RuralGo` y revalidar `sdd validate --stage=PRE_WRITE --json` comprobando `activation_command` fijo a `6.3.106`.
|
|
20
|
+
|
|
9
21
|
### 2026-04-22 (v6.3.105)
|
|
10
22
|
|
|
11
23
|
- **Remediación reproducible en la línea publicada:** las rutas bloqueantes de `PRE_WRITE` dejan de sugerir `pumuki@latest` y fijan la versión efectiva del runtime al construir `next_action.command`.
|
|
@@ -1670,10 +1670,19 @@ export type PreWriteOpenSpecBootstrapTrace = {
|
|
|
1670
1670
|
details?: string;
|
|
1671
1671
|
};
|
|
1672
1672
|
|
|
1673
|
-
export const
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
`
|
|
1673
|
+
export const buildPreWriteExperimentalEnableAdvisoryCommand = (
|
|
1674
|
+
repoRoot: string = process.cwd()
|
|
1675
|
+
): string =>
|
|
1676
|
+
`PUMUKI_EXPERIMENTAL_PRE_WRITE=advisory ${buildPinnedPumukiNpxCommand(
|
|
1677
|
+
getCurrentPumukiVersion({ repoRoot })
|
|
1678
|
+
)} sdd validate --stage=PRE_WRITE --json`;
|
|
1679
|
+
export const buildSddExperimentalEnableAdvisoryCommand = (
|
|
1680
|
+
stage: SddStage,
|
|
1681
|
+
repoRoot: string = process.cwd()
|
|
1682
|
+
): string =>
|
|
1683
|
+
`PUMUKI_EXPERIMENTAL_SDD=advisory ${buildPinnedPumukiNpxCommand(
|
|
1684
|
+
getCurrentPumukiVersion({ repoRoot })
|
|
1685
|
+
)} sdd validate --stage=${stage} --json`;
|
|
1677
1686
|
const buildAnalyticsExperimentalEnableCommand = (action: AnalyticsHotspotsCommand): string =>
|
|
1678
1687
|
`PUMUKI_EXPERIMENTAL_ANALYTICS=advisory npx --yes --package pumuki@latest pumuki analytics hotspots ${action} --json`;
|
|
1679
1688
|
const SAAS_INGESTION_ENABLE_ADVISORY_COMMAND =
|
|
@@ -36,7 +36,7 @@ import {
|
|
|
36
36
|
buildPreWriteExperimentalDisabledResult,
|
|
37
37
|
buildSddExperimentalEnableAdvisoryCommand,
|
|
38
38
|
runRawPreWriteAiGateCheck,
|
|
39
|
-
|
|
39
|
+
buildPreWriteExperimentalEnableAdvisoryCommand,
|
|
40
40
|
} from './cli';
|
|
41
41
|
|
|
42
42
|
export const runSddCommand = async (parsed: ParsedArgs, activeDependencies: LifecycleCliDependencies): Promise<number> => {
|
|
@@ -106,7 +106,7 @@ export const runSddCommand = async (parsed: ParsedArgs, activeDependencies: Life
|
|
|
106
106
|
},
|
|
107
107
|
next_action: {
|
|
108
108
|
reason: 'PRE_WRITE_EXPERIMENTAL_DISABLED',
|
|
109
|
-
command:
|
|
109
|
+
command: buildPreWriteExperimentalEnableAdvisoryCommand(process.cwd()),
|
|
110
110
|
},
|
|
111
111
|
},
|
|
112
112
|
null,
|
|
@@ -127,7 +127,7 @@ export const runSddCommand = async (parsed: ParsedArgs, activeDependencies: Life
|
|
|
127
127
|
`[pumuki][sdd] pre-write enforcement: mode=${preWriteEnforcement.mode} source=${preWriteEnforcement.source} blocking=no`
|
|
128
128
|
);
|
|
129
129
|
writeInfo(
|
|
130
|
-
`[pumuki][sdd] next action (PRE_WRITE_EXPERIMENTAL_DISABLED): ${
|
|
130
|
+
`[pumuki][sdd] next action (PRE_WRITE_EXPERIMENTAL_DISABLED): ${buildPreWriteExperimentalEnableAdvisoryCommand(process.cwd())}`
|
|
131
131
|
);
|
|
132
132
|
}
|
|
133
133
|
return 0;
|
|
@@ -209,7 +209,7 @@ export const runSddCommand = async (parsed: ParsedArgs, activeDependencies: Life
|
|
|
209
209
|
!aiGate && result.decision.code === 'SDD_EXPERIMENTAL_DISABLED'
|
|
210
210
|
? {
|
|
211
211
|
reason: 'SDD_EXPERIMENTAL_DISABLED',
|
|
212
|
-
command: buildSddExperimentalEnableAdvisoryCommand(result.stage),
|
|
212
|
+
command: buildSddExperimentalEnableAdvisoryCommand(result.stage, process.cwd()),
|
|
213
213
|
}
|
|
214
214
|
: undefined;
|
|
215
215
|
if (parsed.json) {
|
|
@@ -12,7 +12,9 @@ import {
|
|
|
12
12
|
readSddSession,
|
|
13
13
|
refreshSddSession,
|
|
14
14
|
} from './sessionStore';
|
|
15
|
+
import type { ILifecycleGitService } from '../lifecycle/gitService';
|
|
15
16
|
import { resolveDegradedMode } from '../gate/degradedMode';
|
|
17
|
+
import { getCurrentPumukiVersion } from '../lifecycle/packageInfo';
|
|
16
18
|
import { resolveSddCompletenessEnforcement } from '../policy/sddCompletenessEnforcement';
|
|
17
19
|
import { resolveSddExperimentalFeature } from '../policy/experimentalFeatures';
|
|
18
20
|
import type {
|
|
@@ -22,16 +24,20 @@ import type {
|
|
|
22
24
|
SddStatusPayload,
|
|
23
25
|
} from './types';
|
|
24
26
|
|
|
25
|
-
const SDD_SESSION_REFRESH_COMMAND =
|
|
26
|
-
'npx --yes --package pumuki@latest pumuki sdd session --refresh --ttl-minutes=90';
|
|
27
|
-
const SDD_SESSION_OPEN_AUTO_COMMAND =
|
|
28
|
-
'npx --yes --package pumuki@latest pumuki sdd session --open --change=auto';
|
|
29
|
-
const SDD_SESSION_OPEN_EXPLICIT_COMMAND =
|
|
30
|
-
'npx --yes --package pumuki@latest pumuki sdd session --open --change=<id>';
|
|
31
27
|
const SDD_COMPLETENESS_CONTRACT_VERSION = '1.0';
|
|
32
28
|
|
|
33
|
-
const
|
|
34
|
-
`
|
|
29
|
+
const buildPinnedPumukiNpxCommand = (version: string): string =>
|
|
30
|
+
`npx --yes --package pumuki@${version} pumuki`;
|
|
31
|
+
const buildSddSessionRefreshCommand = (repoRoot: string): string =>
|
|
32
|
+
`${buildPinnedPumukiNpxCommand(getCurrentPumukiVersion({ repoRoot }))} sdd session --refresh --ttl-minutes=90`;
|
|
33
|
+
const buildSddSessionOpenAutoCommand = (repoRoot: string): string =>
|
|
34
|
+
`${buildPinnedPumukiNpxCommand(getCurrentPumukiVersion({ repoRoot }))} sdd session --open --change=auto`;
|
|
35
|
+
const buildSddSessionOpenExplicitCommand = (repoRoot: string): string =>
|
|
36
|
+
`${buildPinnedPumukiNpxCommand(getCurrentPumukiVersion({ repoRoot }))} sdd session --open --change=<id>`;
|
|
37
|
+
const buildSddExperimentalEnableCommand = (stage: SddStage, repoRoot: string): string =>
|
|
38
|
+
`PUMUKI_EXPERIMENTAL_SDD=advisory ${buildPinnedPumukiNpxCommand(
|
|
39
|
+
getCurrentPumukiVersion({ repoRoot })
|
|
40
|
+
)} sdd validate --stage=${stage} --json`;
|
|
35
41
|
|
|
36
42
|
const resolveMissingSessionGuidance = (repoRoot: string): {
|
|
37
43
|
message: string;
|
|
@@ -40,15 +46,17 @@ const resolveMissingSessionGuidance = (repoRoot: string): {
|
|
|
40
46
|
suggestedChangeId?: string;
|
|
41
47
|
availableChangeIds: ReadonlyArray<string>;
|
|
42
48
|
} => {
|
|
49
|
+
const sessionOpenAutoCommand = buildSddSessionOpenAutoCommand(repoRoot);
|
|
50
|
+
const sessionOpenExplicitCommand = buildSddSessionOpenExplicitCommand(repoRoot);
|
|
43
51
|
const availableChangeIds = listActiveOpenSpecChangeIds(repoRoot);
|
|
44
52
|
if (availableChangeIds.length === 1) {
|
|
45
53
|
const suggestedChangeId = availableChangeIds[0] ?? '';
|
|
46
54
|
const command =
|
|
47
|
-
|
|
55
|
+
`${buildPinnedPumukiNpxCommand(getCurrentPumukiVersion({ repoRoot }))} sdd session --open --change=${suggestedChangeId}`;
|
|
48
56
|
return {
|
|
49
57
|
message: `SDD session is not active. Run \`${command}\` and retry.`,
|
|
50
58
|
command,
|
|
51
|
-
fallbackCommand:
|
|
59
|
+
fallbackCommand: sessionOpenAutoCommand,
|
|
52
60
|
suggestedChangeId,
|
|
53
61
|
availableChangeIds,
|
|
54
62
|
};
|
|
@@ -56,25 +64,25 @@ const resolveMissingSessionGuidance = (repoRoot: string): {
|
|
|
56
64
|
if (availableChangeIds.length > 1) {
|
|
57
65
|
return {
|
|
58
66
|
message:
|
|
59
|
-
`SDD session is not active. Run \`${
|
|
67
|
+
`SDD session is not active. Run \`${sessionOpenExplicitCommand}\` ` +
|
|
60
68
|
`with one active change id. Active changes: ${availableChangeIds.join(', ')}.`,
|
|
61
|
-
command:
|
|
62
|
-
fallbackCommand:
|
|
69
|
+
command: sessionOpenExplicitCommand,
|
|
70
|
+
fallbackCommand: sessionOpenExplicitCommand,
|
|
63
71
|
availableChangeIds,
|
|
64
72
|
};
|
|
65
73
|
}
|
|
66
74
|
return {
|
|
67
|
-
message: `SDD session is not active. Run \`${
|
|
68
|
-
command:
|
|
69
|
-
fallbackCommand:
|
|
75
|
+
message: `SDD session is not active. Run \`${sessionOpenAutoCommand}\` and retry.`,
|
|
76
|
+
command: sessionOpenAutoCommand,
|
|
77
|
+
fallbackCommand: sessionOpenAutoCommand,
|
|
70
78
|
availableChangeIds,
|
|
71
79
|
};
|
|
72
80
|
};
|
|
73
81
|
|
|
74
|
-
const buildStatus = (repoRoot: string): SddStatusPayload => {
|
|
82
|
+
const buildStatus = (repoRoot: string, git?: ILifecycleGitService): SddStatusPayload => {
|
|
75
83
|
const openspec = detectOpenSpecInstallation(repoRoot);
|
|
76
84
|
const compatibility = evaluateOpenSpecCompatibility(openspec);
|
|
77
|
-
const session = readSddSession(repoRoot);
|
|
85
|
+
const session = readSddSession(repoRoot, git);
|
|
78
86
|
return {
|
|
79
87
|
repoRoot,
|
|
80
88
|
openspec: {
|
|
@@ -164,7 +172,7 @@ const evaluateSessionRequirements = (params: {
|
|
|
164
172
|
autoRefreshError?: string;
|
|
165
173
|
}): SddDecision | undefined => {
|
|
166
174
|
const { status } = params;
|
|
167
|
-
if (!status.session.
|
|
175
|
+
if (!status.session.changeId) {
|
|
168
176
|
const guidance = resolveMissingSessionGuidance(status.repoRoot);
|
|
169
177
|
const details: Record<string, string | number | boolean | bigint | symbol | null | Date | object> = {
|
|
170
178
|
command: guidance.command,
|
|
@@ -181,8 +189,9 @@ const evaluateSessionRequirements = (params: {
|
|
|
181
189
|
);
|
|
182
190
|
}
|
|
183
191
|
if (!status.session.valid || !status.session.changeId) {
|
|
192
|
+
const refreshCommand = buildSddSessionRefreshCommand(params.repoRoot);
|
|
184
193
|
const details: Record<string, string | boolean> = {
|
|
185
|
-
command:
|
|
194
|
+
command: refreshCommand,
|
|
186
195
|
autoRefreshEnabled: params.autoRefreshEnabled,
|
|
187
196
|
autoRefreshAttempted: params.autoRefreshAttempted,
|
|
188
197
|
};
|
|
@@ -191,8 +200,8 @@ const evaluateSessionRequirements = (params: {
|
|
|
191
200
|
}
|
|
192
201
|
const message =
|
|
193
202
|
params.autoRefreshAttempted && params.autoRefreshError
|
|
194
|
-
? `SDD session is invalid or expired. Auto-refresh failed (${params.autoRefreshError}). Run \`${
|
|
195
|
-
: `SDD session is invalid or expired. Run \`${
|
|
203
|
+
? `SDD session is invalid or expired. Auto-refresh failed (${params.autoRefreshError}). Run \`${refreshCommand}\` or reopen it.`
|
|
204
|
+
: `SDD session is invalid or expired. Run \`${refreshCommand}\` or reopen it.`;
|
|
196
205
|
return blocked(
|
|
197
206
|
'SDD_SESSION_INVALID',
|
|
198
207
|
message,
|
|
@@ -221,7 +230,6 @@ const shouldAttemptSessionAutoRefresh = (params: {
|
|
|
221
230
|
}): boolean =>
|
|
222
231
|
params.stage !== 'PRE_WRITE'
|
|
223
232
|
&& params.autoRefreshEnabled
|
|
224
|
-
&& params.status.session.active
|
|
225
233
|
&& !!params.status.session.changeId
|
|
226
234
|
&& !params.status.session.valid;
|
|
227
235
|
|
|
@@ -327,7 +335,7 @@ export const evaluateSddPolicy = (params: {
|
|
|
327
335
|
experimentalSource: sddExperimentalFeature.source,
|
|
328
336
|
activation_env: sddExperimentalFeature.activationVariable,
|
|
329
337
|
legacy_activation_env: sddExperimentalFeature.legacyActivationVariable,
|
|
330
|
-
activation_command: buildSddExperimentalEnableCommand(params.stage),
|
|
338
|
+
activation_command: buildSddExperimentalEnableCommand(params.stage, params.repoRoot),
|
|
331
339
|
},
|
|
332
340
|
},
|
|
333
341
|
};
|
|
@@ -545,5 +553,5 @@ export const evaluateSddPolicy = (params: {
|
|
|
545
553
|
});
|
|
546
554
|
};
|
|
547
555
|
|
|
548
|
-
export const readSddStatus = (repoRoot?: string): SddStatusPayload =>
|
|
549
|
-
buildStatus(repoRoot ?? process.cwd());
|
|
556
|
+
export const readSddStatus = (repoRoot?: string, git?: ILifecycleGitService): SddStatusPayload =>
|
|
557
|
+
buildStatus(repoRoot ?? process.cwd(), git);
|
|
@@ -86,7 +86,7 @@ const readConfig = (
|
|
|
86
86
|
repoRoot: string,
|
|
87
87
|
git: ILifecycleGitService
|
|
88
88
|
): SddSessionState => {
|
|
89
|
-
const
|
|
89
|
+
const rawActive = git.localConfig(repoRoot, SDD_KEYS.active) === 'true';
|
|
90
90
|
const rawChangeId = git.localConfig(repoRoot, SDD_KEYS.change);
|
|
91
91
|
const changeId =
|
|
92
92
|
typeof rawChangeId === 'string' && rawChangeId.trim().length > 0
|
|
@@ -101,6 +101,7 @@ const readConfig = (
|
|
|
101
101
|
: undefined;
|
|
102
102
|
|
|
103
103
|
const validity = computeValidity(expiresAt);
|
|
104
|
+
const active = rawActive && !!changeId && validity.valid;
|
|
104
105
|
return {
|
|
105
106
|
repoRoot,
|
|
106
107
|
active,
|
|
@@ -174,7 +175,7 @@ export const refreshSddSession = (params?: {
|
|
|
174
175
|
const git = params?.git ?? new LifecycleGitService();
|
|
175
176
|
const repoRoot = resolveRepoRoot(params?.cwd ?? process.cwd(), git);
|
|
176
177
|
const current = readConfig(repoRoot, git);
|
|
177
|
-
if (!current.
|
|
178
|
+
if (!current.changeId) {
|
|
178
179
|
throw new Error('No active SDD session to refresh. Run `pumuki sdd session --open --change=<id>` first.');
|
|
179
180
|
}
|
|
180
181
|
const ttlMinutes = parsePositiveMinutes(params?.ttlMinutes ?? current.ttlMinutes);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pumuki",
|
|
3
|
-
"version": "6.3.
|
|
3
|
+
"version": "6.3.107",
|
|
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": {
|