pumuki 6.3.113 → 6.3.115
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 +52 -5
- package/README.md +4 -2
- package/VERSION +1 -1
- package/core/facts/detectors/typescript/index.test.ts +0 -229
- package/core/facts/detectors/typescript/index.ts +0 -278
- package/core/facts/extractHeuristicFacts.ts +0 -4
- package/core/rules/presets/heuristics/typescript.test.ts +1 -21
- package/core/rules/presets/heuristics/typescript.ts +0 -72
- package/docs/README.md +13 -9
- package/docs/codex-skills/backend-enterprise-rules.md +3 -3
- package/docs/operations/RELEASE_NOTES.md +41 -4
- package/docs/product/API_REFERENCE.md +1 -1
- package/docs/product/HOW_IT_WORKS.md +6 -0
- package/docs/product/INSTALLATION.md +1 -1
- package/docs/product/USAGE.md +42 -5
- package/docs/tracking/plan-curso-pumuki-stack-my-architecture.md +100 -44
- package/docs/validation/README.md +6 -3
- package/integrations/config/skillsDetectorRegistry.ts +0 -24
- package/integrations/config/skillsMarkdownRules.ts +0 -57
- package/integrations/evidence/buildEvidence.ts +0 -24
- package/integrations/evidence/repoState.ts +9 -7
- package/integrations/evidence/schema.ts +0 -18
- package/integrations/evidence/writeEvidence.ts +0 -24
- package/integrations/gate/evaluateAiGate.ts +8 -251
- package/integrations/gate/remediationCatalog.ts +0 -8
- package/integrations/git/GitService.ts +44 -5
- package/integrations/git/aiGateRepoPolicyFindings.ts +86 -17
- package/integrations/git/runPlatformGate.ts +1 -9
- package/integrations/git/runPlatformGateFacts.ts +19 -1
- package/integrations/git/runPlatformGateOutput.ts +41 -42
- package/integrations/lifecycle/adapter.templates.json +1 -0
- package/integrations/lifecycle/adapter.ts +0 -24
- package/integrations/lifecycle/audit.ts +101 -0
- package/integrations/lifecycle/cli.ts +120 -99
- package/integrations/lifecycle/cliSdd.ts +4 -26
- package/integrations/lifecycle/doctor.ts +40 -102
- package/integrations/lifecycle/index.ts +2 -0
- package/integrations/lifecycle/install.ts +0 -21
- package/integrations/lifecycle/packageInfo.ts +1 -118
- package/integrations/lifecycle/state.ts +1 -8
- package/integrations/lifecycle/status.ts +40 -59
- package/integrations/lifecycle/watch.ts +1 -1
- package/integrations/mcp/aiGateCheck.ts +10 -194
- package/integrations/mcp/autoExecuteAiStart.ts +116 -92
- package/integrations/mcp/enterpriseServer.ts +7 -23
- package/integrations/mcp/enterpriseStdioServer.cli.ts +4 -31
- package/integrations/mcp/preFlightCheck.ts +5 -67
- package/integrations/platform/detectPlatforms.ts +37 -0
- package/integrations/sdd/policy.ts +28 -20
- package/package.json +1 -1
- package/scripts/check-tracking-single-active.sh +1 -1
- package/scripts/consumer-menu-matrix-baseline-report-lib.ts +13 -38
- package/scripts/consumer-postinstall-resolve-args.cjs +44 -0
- package/scripts/consumer-postinstall.cjs +76 -21
- package/scripts/framework-menu-advanced-view-lib.ts +0 -49
- package/scripts/framework-menu-consumer-actions-lib.ts +28 -4
- package/scripts/framework-menu-consumer-preflight-hints.ts +5 -2
- package/scripts/framework-menu-consumer-preflight-render.ts +0 -10
- package/scripts/framework-menu-consumer-preflight-run.ts +0 -23
- package/scripts/framework-menu-consumer-preflight-types.ts +0 -12
- package/scripts/framework-menu-consumer-runtime-actions.ts +87 -17
- package/scripts/framework-menu-consumer-runtime-audit.ts +36 -2
- package/scripts/framework-menu-consumer-runtime-evidence-classic.ts +140 -0
- package/scripts/framework-menu-consumer-runtime-lib.ts +2 -38
- package/scripts/framework-menu-consumer-runtime-menu.ts +4 -31
- package/scripts/framework-menu-consumer-runtime-types.ts +3 -5
- package/scripts/framework-menu-evidence-summary-lib.ts +1 -0
- package/scripts/framework-menu-evidence-summary-read.ts +57 -5
- package/scripts/framework-menu-evidence-summary-severity.ts +3 -1
- package/scripts/framework-menu-evidence-summary-types.ts +7 -0
- package/scripts/framework-menu-gate-lib.ts +9 -0
- package/scripts/framework-menu-layout-data.ts +5 -0
- package/scripts/framework-menu-matrix-baseline-lib.ts +15 -14
- package/scripts/framework-menu-matrix-canary-lib.ts +22 -1
- package/scripts/framework-menu-matrix-evidence-lib.ts +1 -0
- package/scripts/framework-menu-matrix-evidence-types.ts +13 -1
- package/scripts/framework-menu-matrix-runner-lib.ts +35 -0
- package/scripts/framework-menu-system-notifications-cause.ts +0 -3
- package/scripts/framework-menu-system-notifications-macos-swift-source.ts +24 -204
- package/scripts/framework-menu-system-notifications-macos.ts +4 -0
- package/scripts/framework-menu-system-notifications-payloads-blocked.ts +1 -1
- package/scripts/framework-menu-system-notifications-text.ts +1 -7
- package/scripts/framework-menu.ts +3 -24
- package/scripts/package-install-smoke-consumer-git-repo-lib.ts +1 -10
- package/scripts/package-install-smoke-consumer-npm-lib.ts +9 -46
- package/scripts/pumuki-full-surface-smoke-lib.ts +37 -0
- package/scripts/pumuki-full-surface-smoke.ts +346 -0
- package/scripts/pumuki-smoke-installed-wrapper.cjs +31 -0
- package/integrations/evidence/trackingContract.ts +0 -17
- package/integrations/gate/governanceActionCatalog.ts +0 -275
- package/integrations/lifecycle/bootstrapManifest.ts +0 -248
- package/integrations/lifecycle/cliGovernanceConsole.ts +0 -69
- package/integrations/lifecycle/governanceNextAction.ts +0 -171
- package/integrations/lifecycle/governanceObservationSnapshot.ts +0 -369
- package/integrations/lifecycle/trackingState.ts +0 -403
- package/integrations/mcp/alignedPlatformGate.ts +0 -232
- package/integrations/mcp/readMcpPrePushStdin.ts +0 -7
- package/scripts/build-ruralgo-s1-evidence-pack.ts +0 -85
- package/scripts/ruralgo-s1-evidence-pack-lib.ts +0 -200
|
@@ -1,16 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
resolveGovernanceCatalogAction,
|
|
3
|
-
type GovernanceCatalogNextAction,
|
|
4
|
-
} from '../gate/governanceActionCatalog';
|
|
5
1
|
import { evaluateAiGate, type AiGateStage, type AiGateViolation } from '../gate/evaluateAiGate';
|
|
6
2
|
import { collectWorktreeAtomicSlices } from '../git/worktreeAtomicSlices';
|
|
7
|
-
import { readLifecyclePolicyValidationSnapshot } from '../lifecycle/policyValidationSnapshot';
|
|
8
3
|
import { resolveLearningContextExperimentalFeature } from '../policy/experimentalFeatures';
|
|
9
|
-
import { resolvePreWriteEnforcement } from '../policy/preWriteEnforcement';
|
|
10
4
|
import { readSddLearningContext, type SddLearningContext } from '../sdd/learningInsights';
|
|
11
5
|
|
|
12
6
|
const ACTIONABLE_HINTS_BY_CODE: Readonly<Record<string, string>> = {
|
|
13
|
-
EVIDENCE_MISSING:
|
|
7
|
+
EVIDENCE_MISSING:
|
|
8
|
+
'Ejecuta una auditoría (1/2/3/4 u opciones de motor 11–14) para regenerar .ai_evidence.json.',
|
|
14
9
|
EVIDENCE_INVALID: 'Regenera .ai_evidence.json desde una opción de auditoría.',
|
|
15
10
|
EVIDENCE_INTEGRITY_MISSING: 'Refresca evidencia para regenerar metadatos de integridad.',
|
|
16
11
|
EVIDENCE_ACTIVE_RULE_IDS_EMPTY_FOR_CODE_CHANGES:
|
|
@@ -44,28 +39,6 @@ const ACTIONABLE_HINTS_BY_CODE: Readonly<Record<string, string>> = {
|
|
|
44
39
|
'Mapea todas las reglas AUTO a detectores AST antes de continuar.',
|
|
45
40
|
EVIDENCE_TIMESTAMP_FUTURE: 'Corrige la hora del sistema y regenera evidencia.',
|
|
46
41
|
GITFLOW_PROTECTED_BRANCH: 'Evita trabajo directo en ramas protegidas (usa feature/*).',
|
|
47
|
-
GITFLOW_BRANCH_NAMING_INVALID:
|
|
48
|
-
'La rama actual no cumple GitFlow. Usa feature/*, bugfix/*, hotfix/*, release/*, chore/*, refactor/* o docs/*.',
|
|
49
|
-
TRACKING_CANONICAL_SOURCE_CONFLICT:
|
|
50
|
-
'AGENTS.md y los README del repo no apuntan a la misma fuente canónica de tracking.',
|
|
51
|
-
TRACKING_CANONICAL_FILE_MISSING:
|
|
52
|
-
'El repo declara un MD de tracking canónico que ahora mismo no existe.',
|
|
53
|
-
TRACKING_CANONICAL_IN_PROGRESS_INVALID:
|
|
54
|
-
'El MD canónico de tracking debe dejar exactamente una task o fase en construcción.',
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
const normalizeGovernanceCatalogCode = (code: string): string => {
|
|
58
|
-
switch (code) {
|
|
59
|
-
case 'EVIDENCE_INVALID':
|
|
60
|
-
case 'EVIDENCE_CHAIN_INVALID':
|
|
61
|
-
return 'EVIDENCE_INVALID_OR_CHAIN';
|
|
62
|
-
case 'GITFLOW_PROTECTED_BRANCH':
|
|
63
|
-
return 'GITFLOW_PROTECTED_BRANCH_CONTEXT';
|
|
64
|
-
case 'GITFLOW_BRANCH_NAMING_INVALID':
|
|
65
|
-
return 'GITFLOW_BRANCH_NAMING_INVALID_CONTEXT';
|
|
66
|
-
default:
|
|
67
|
-
return code;
|
|
68
|
-
}
|
|
69
42
|
};
|
|
70
43
|
|
|
71
44
|
const buildPreFlightHints = (params: {
|
|
@@ -142,14 +115,6 @@ export type EnterprisePreFlightCheckResult = {
|
|
|
142
115
|
phase: 'GREEN' | 'RED';
|
|
143
116
|
message: string;
|
|
144
117
|
instruction: string;
|
|
145
|
-
reason_code: string;
|
|
146
|
-
prewrite_effective: {
|
|
147
|
-
mode: ReturnType<typeof resolvePreWriteEnforcement>['mode'];
|
|
148
|
-
source: ReturnType<typeof resolvePreWriteEnforcement>['source'];
|
|
149
|
-
blocking: boolean;
|
|
150
|
-
strict_policy: boolean;
|
|
151
|
-
};
|
|
152
|
-
next_action: GovernanceCatalogNextAction;
|
|
153
118
|
stage: ReturnType<typeof evaluateAiGate>['stage'];
|
|
154
119
|
policy: ReturnType<typeof evaluateAiGate>['policy'];
|
|
155
120
|
violations: ReturnType<typeof evaluateAiGate>['violations'];
|
|
@@ -180,8 +145,6 @@ export const runEnterprisePreFlightCheck = (params: {
|
|
|
180
145
|
: readSddLearningContext({
|
|
181
146
|
repoRoot: params.repoRoot,
|
|
182
147
|
});
|
|
183
|
-
const preWriteEnforcement = resolvePreWriteEnforcement();
|
|
184
|
-
const policyValidation = readLifecyclePolicyValidationSnapshot(params.repoRoot);
|
|
185
148
|
|
|
186
149
|
const hints = buildPreFlightHints({
|
|
187
150
|
repoRoot: params.repoRoot,
|
|
@@ -191,30 +154,13 @@ export const runEnterprisePreFlightCheck = (params: {
|
|
|
191
154
|
upstream: evaluation.repo_state.git.upstream,
|
|
192
155
|
learningContext,
|
|
193
156
|
});
|
|
194
|
-
const firstViolation = evaluation.violations[0];
|
|
195
|
-
const reasonCode = firstViolation?.code ?? 'READY';
|
|
196
|
-
const governanceAction = firstViolation
|
|
197
|
-
? resolveGovernanceCatalogAction({
|
|
198
|
-
code: normalizeGovernanceCatalogCode(firstViolation.code),
|
|
199
|
-
stage: evaluation.stage,
|
|
200
|
-
})
|
|
201
|
-
: resolveGovernanceCatalogAction({
|
|
202
|
-
code: 'READY',
|
|
203
|
-
stage: evaluation.stage,
|
|
204
|
-
});
|
|
205
157
|
const phase: 'GREEN' | 'RED' = evaluation.allowed ? 'GREEN' : 'RED';
|
|
206
158
|
const message = evaluation.allowed
|
|
207
159
|
? '✅ Pre-flight aprobado: puedes continuar con la implementación.'
|
|
208
|
-
: `🔴 Pre-flight bloqueado: corrige ${
|
|
209
|
-
const instruction =
|
|
160
|
+
: `🔴 Pre-flight bloqueado: corrige ${evaluation.violations[0]?.code ?? 'la causa'} y vuelve a ejecutar.`;
|
|
161
|
+
const instruction = evaluation.allowed
|
|
210
162
|
? 'Implementa el cambio mínimo para pasar en verde y vuelve a validar.'
|
|
211
|
-
:
|
|
212
|
-
const nextAction: GovernanceCatalogNextAction = evaluation.allowed
|
|
213
|
-
? {
|
|
214
|
-
kind: 'info',
|
|
215
|
-
message: governanceAction.next_action.message,
|
|
216
|
-
}
|
|
217
|
-
: governanceAction.next_action;
|
|
163
|
+
: hints[0] ?? 'Corrige la causa bloqueante y vuelve a ejecutar el pre-flight.';
|
|
218
164
|
|
|
219
165
|
return {
|
|
220
166
|
tool: 'pre_flight_check',
|
|
@@ -227,14 +173,6 @@ export const runEnterprisePreFlightCheck = (params: {
|
|
|
227
173
|
phase,
|
|
228
174
|
message,
|
|
229
175
|
instruction,
|
|
230
|
-
reason_code: reasonCode,
|
|
231
|
-
prewrite_effective: {
|
|
232
|
-
mode: preWriteEnforcement.mode,
|
|
233
|
-
source: preWriteEnforcement.source,
|
|
234
|
-
blocking: preWriteEnforcement.blocking,
|
|
235
|
-
strict_policy: policyValidation.stages.PRE_WRITE.strict,
|
|
236
|
-
},
|
|
237
|
-
next_action: nextAction,
|
|
238
176
|
stage: evaluation.stage,
|
|
239
177
|
policy: evaluation.policy,
|
|
240
178
|
violations: evaluation.violations,
|
|
@@ -51,6 +51,38 @@ const collectFilePaths = (facts: ReadonlyArray<Fact>): string[] => {
|
|
|
51
51
|
.filter((path): path is string => typeof path === 'string');
|
|
52
52
|
};
|
|
53
53
|
|
|
54
|
+
const ALLOWED_PIN_KEYS = new Set(['ios', 'android', 'backend', 'frontend']);
|
|
55
|
+
|
|
56
|
+
const readPinnedPlatformsFromEnv = (): ReadonlySet<keyof DetectedPlatforms> | null => {
|
|
57
|
+
const raw = process.env.PUMUKI_PIN_PLATFORMS?.trim().toLowerCase();
|
|
58
|
+
if (!raw) {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
const tokens = raw
|
|
62
|
+
.split(',')
|
|
63
|
+
.map((token) => token.trim())
|
|
64
|
+
.filter((token) => token.length > 0)
|
|
65
|
+
.filter((token) => ALLOWED_PIN_KEYS.has(token)) as Array<keyof DetectedPlatforms>;
|
|
66
|
+
if (tokens.length === 0) {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
return new Set(tokens);
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
const applyPinnedPlatformsFilter = (
|
|
73
|
+
detected: DetectedPlatforms,
|
|
74
|
+
pin: ReadonlySet<keyof DetectedPlatforms>
|
|
75
|
+
): DetectedPlatforms => {
|
|
76
|
+
const next: DetectedPlatforms = {};
|
|
77
|
+
for (const key of pin) {
|
|
78
|
+
const state = detected[key];
|
|
79
|
+
if (state) {
|
|
80
|
+
next[key] = state;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return next;
|
|
84
|
+
};
|
|
85
|
+
|
|
54
86
|
export const detectPlatformsFromFacts = (
|
|
55
87
|
facts: ReadonlyArray<Fact>
|
|
56
88
|
): DetectedPlatforms => {
|
|
@@ -102,5 +134,10 @@ export const detectPlatformsFromFacts = (
|
|
|
102
134
|
};
|
|
103
135
|
}
|
|
104
136
|
|
|
137
|
+
const pin = readPinnedPlatformsFromEnv();
|
|
138
|
+
if (pin && pin.size > 0) {
|
|
139
|
+
return applyPinnedPlatformsFilter(result, pin);
|
|
140
|
+
}
|
|
141
|
+
|
|
105
142
|
return result;
|
|
106
143
|
};
|
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
} from './sessionStore';
|
|
15
15
|
import type { ILifecycleGitService } from '../lifecycle/gitService';
|
|
16
16
|
import { resolveDegradedMode } from '../gate/degradedMode';
|
|
17
|
+
import { getCurrentPumukiVersion } from '../lifecycle/packageInfo';
|
|
17
18
|
import { resolveSddCompletenessEnforcement } from '../policy/sddCompletenessEnforcement';
|
|
18
19
|
import { resolveSddExperimentalFeature } from '../policy/experimentalFeatures';
|
|
19
20
|
import type {
|
|
@@ -23,16 +24,20 @@ import type {
|
|
|
23
24
|
SddStatusPayload,
|
|
24
25
|
} from './types';
|
|
25
26
|
|
|
26
|
-
const SDD_SESSION_REFRESH_COMMAND =
|
|
27
|
-
'npx --yes --package pumuki@latest pumuki sdd session --refresh --ttl-minutes=90';
|
|
28
|
-
const SDD_SESSION_OPEN_AUTO_COMMAND =
|
|
29
|
-
'npx --yes --package pumuki@latest pumuki sdd session --open --change=auto';
|
|
30
|
-
const SDD_SESSION_OPEN_EXPLICIT_COMMAND =
|
|
31
|
-
'npx --yes --package pumuki@latest pumuki sdd session --open --change=<id>';
|
|
32
27
|
const SDD_COMPLETENESS_CONTRACT_VERSION = '1.0';
|
|
33
28
|
|
|
34
|
-
const
|
|
35
|
-
`
|
|
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`;
|
|
36
41
|
|
|
37
42
|
const resolveMissingSessionGuidance = (repoRoot: string): {
|
|
38
43
|
message: string;
|
|
@@ -41,15 +46,17 @@ const resolveMissingSessionGuidance = (repoRoot: string): {
|
|
|
41
46
|
suggestedChangeId?: string;
|
|
42
47
|
availableChangeIds: ReadonlyArray<string>;
|
|
43
48
|
} => {
|
|
49
|
+
const sessionOpenAutoCommand = buildSddSessionOpenAutoCommand(repoRoot);
|
|
50
|
+
const sessionOpenExplicitCommand = buildSddSessionOpenExplicitCommand(repoRoot);
|
|
44
51
|
const availableChangeIds = listActiveOpenSpecChangeIds(repoRoot);
|
|
45
52
|
if (availableChangeIds.length === 1) {
|
|
46
53
|
const suggestedChangeId = availableChangeIds[0] ?? '';
|
|
47
54
|
const command =
|
|
48
|
-
|
|
55
|
+
`${buildPinnedPumukiNpxCommand(getCurrentPumukiVersion({ repoRoot }))} sdd session --open --change=${suggestedChangeId}`;
|
|
49
56
|
return {
|
|
50
57
|
message: `SDD session is not active. Run \`${command}\` and retry.`,
|
|
51
58
|
command,
|
|
52
|
-
fallbackCommand:
|
|
59
|
+
fallbackCommand: sessionOpenAutoCommand,
|
|
53
60
|
suggestedChangeId,
|
|
54
61
|
availableChangeIds,
|
|
55
62
|
};
|
|
@@ -57,17 +64,17 @@ const resolveMissingSessionGuidance = (repoRoot: string): {
|
|
|
57
64
|
if (availableChangeIds.length > 1) {
|
|
58
65
|
return {
|
|
59
66
|
message:
|
|
60
|
-
`SDD session is not active. Run \`${
|
|
67
|
+
`SDD session is not active. Run \`${sessionOpenExplicitCommand}\` ` +
|
|
61
68
|
`with one active change id. Active changes: ${availableChangeIds.join(', ')}.`,
|
|
62
|
-
command:
|
|
63
|
-
fallbackCommand:
|
|
69
|
+
command: sessionOpenExplicitCommand,
|
|
70
|
+
fallbackCommand: sessionOpenExplicitCommand,
|
|
64
71
|
availableChangeIds,
|
|
65
72
|
};
|
|
66
73
|
}
|
|
67
74
|
return {
|
|
68
|
-
message: `SDD session is not active. Run \`${
|
|
69
|
-
command:
|
|
70
|
-
fallbackCommand:
|
|
75
|
+
message: `SDD session is not active. Run \`${sessionOpenAutoCommand}\` and retry.`,
|
|
76
|
+
command: sessionOpenAutoCommand,
|
|
77
|
+
fallbackCommand: sessionOpenAutoCommand,
|
|
71
78
|
availableChangeIds,
|
|
72
79
|
};
|
|
73
80
|
};
|
|
@@ -182,8 +189,9 @@ const evaluateSessionRequirements = (params: {
|
|
|
182
189
|
);
|
|
183
190
|
}
|
|
184
191
|
if (!status.session.valid || !status.session.changeId) {
|
|
192
|
+
const refreshCommand = buildSddSessionRefreshCommand(params.repoRoot);
|
|
185
193
|
const details: Record<string, string | boolean> = {
|
|
186
|
-
command:
|
|
194
|
+
command: refreshCommand,
|
|
187
195
|
autoRefreshEnabled: params.autoRefreshEnabled,
|
|
188
196
|
autoRefreshAttempted: params.autoRefreshAttempted,
|
|
189
197
|
};
|
|
@@ -192,8 +200,8 @@ const evaluateSessionRequirements = (params: {
|
|
|
192
200
|
}
|
|
193
201
|
const message =
|
|
194
202
|
params.autoRefreshAttempted && params.autoRefreshError
|
|
195
|
-
? `SDD session is invalid or expired. Auto-refresh failed (${params.autoRefreshError}). Run \`${
|
|
196
|
-
: `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.`;
|
|
197
205
|
return blocked(
|
|
198
206
|
'SDD_SESSION_INVALID',
|
|
199
207
|
message,
|
|
@@ -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
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pumuki",
|
|
3
|
-
"version": "6.3.
|
|
3
|
+
"version": "6.3.115",
|
|
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": {
|
|
@@ -31,7 +31,7 @@ for FILE in "${FILES[@]}"; do
|
|
|
31
31
|
fi
|
|
32
32
|
|
|
33
33
|
if [[ "${FILE}" == "PUMUKI-RESET-MASTER-PLAN.md" ]]; then
|
|
34
|
-
ACTIVE_PATTERN='
|
|
34
|
+
ACTIVE_PATTERN='^- Estado: 🚧'
|
|
35
35
|
else
|
|
36
36
|
ACTIVE_PATTERN='^- 🚧 (`?P[0-9A-Za-z.-]+`?)'
|
|
37
37
|
fi
|
|
@@ -4,10 +4,11 @@ import type {
|
|
|
4
4
|
ConsumerMenuMatrixReport,
|
|
5
5
|
MatrixOptionId,
|
|
6
6
|
} from './framework-menu-matrix-baseline-lib';
|
|
7
|
+
import { MATRIX_MENU_OPTION_IDS } from './framework-menu-matrix-evidence-lib';
|
|
7
8
|
import type { DoctorDeepCheckLayer, LifecycleDoctorReport } from '../integrations/lifecycle/doctor';
|
|
8
9
|
import type { LifecycleStatus } from '../integrations/lifecycle/status';
|
|
9
10
|
|
|
10
|
-
const OPTION_IDS: ReadonlyArray<MatrixOptionId> = [
|
|
11
|
+
const OPTION_IDS: ReadonlyArray<MatrixOptionId> = [...MATRIX_MENU_OPTION_IDS];
|
|
11
12
|
const DOCTOR_LAYERS: ReadonlyArray<DoctorDeepCheckLayer> = [
|
|
12
13
|
'core',
|
|
13
14
|
'operational',
|
|
@@ -51,45 +52,19 @@ export type ConsumerMenuMatrixBaselineSnapshot = {
|
|
|
51
52
|
};
|
|
52
53
|
};
|
|
53
54
|
|
|
55
|
+
const UNKNOWN_OPTION_REPORT = {
|
|
56
|
+
stage: 'UNKNOWN',
|
|
57
|
+
outcome: 'UNKNOWN',
|
|
58
|
+
filesScanned: 0,
|
|
59
|
+
totalViolations: 0,
|
|
60
|
+
diagnosis: 'unknown' as const,
|
|
61
|
+
};
|
|
62
|
+
|
|
54
63
|
const buildEmptyRound = (): ConsumerMenuMatrixReport => {
|
|
55
64
|
return {
|
|
56
|
-
byOption:
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
outcome: 'UNKNOWN',
|
|
60
|
-
filesScanned: 0,
|
|
61
|
-
totalViolations: 0,
|
|
62
|
-
diagnosis: 'unknown',
|
|
63
|
-
},
|
|
64
|
-
'2': {
|
|
65
|
-
stage: 'UNKNOWN',
|
|
66
|
-
outcome: 'UNKNOWN',
|
|
67
|
-
filesScanned: 0,
|
|
68
|
-
totalViolations: 0,
|
|
69
|
-
diagnosis: 'unknown',
|
|
70
|
-
},
|
|
71
|
-
'3': {
|
|
72
|
-
stage: 'UNKNOWN',
|
|
73
|
-
outcome: 'UNKNOWN',
|
|
74
|
-
filesScanned: 0,
|
|
75
|
-
totalViolations: 0,
|
|
76
|
-
diagnosis: 'unknown',
|
|
77
|
-
},
|
|
78
|
-
'4': {
|
|
79
|
-
stage: 'UNKNOWN',
|
|
80
|
-
outcome: 'UNKNOWN',
|
|
81
|
-
filesScanned: 0,
|
|
82
|
-
totalViolations: 0,
|
|
83
|
-
diagnosis: 'unknown',
|
|
84
|
-
},
|
|
85
|
-
'9': {
|
|
86
|
-
stage: 'UNKNOWN',
|
|
87
|
-
outcome: 'UNKNOWN',
|
|
88
|
-
filesScanned: 0,
|
|
89
|
-
totalViolations: 0,
|
|
90
|
-
diagnosis: 'unknown',
|
|
91
|
-
},
|
|
92
|
-
},
|
|
65
|
+
byOption: Object.fromEntries(
|
|
66
|
+
MATRIX_MENU_OPTION_IDS.map((id) => [id, { ...UNKNOWN_OPTION_REPORT }])
|
|
67
|
+
) as ConsumerMenuMatrixReport['byOption'],
|
|
93
68
|
};
|
|
94
69
|
};
|
|
95
70
|
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const KNOWN_MCP_AGENTS = new Set(['cursor', 'codex', 'claude', 'repo']);
|
|
4
|
+
|
|
5
|
+
const normalizeExplicitAgent = (raw) => {
|
|
6
|
+
const trimmed = (raw ?? '').trim();
|
|
7
|
+
if (!trimmed) {
|
|
8
|
+
return '';
|
|
9
|
+
}
|
|
10
|
+
const lower = trimmed.toLowerCase();
|
|
11
|
+
if (lower === '0' || lower === 'none' || lower === 'false') {
|
|
12
|
+
return '';
|
|
13
|
+
}
|
|
14
|
+
if (!KNOWN_MCP_AGENTS.has(lower)) {
|
|
15
|
+
return '';
|
|
16
|
+
}
|
|
17
|
+
return lower;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const resolveConsumerPostinstallInstallExtras = (_consumerRoot, env = process.env) => {
|
|
21
|
+
if (env.PUMUKI_POSTINSTALL_SKIP_MCP === '1') {
|
|
22
|
+
return { extras: [], reason: 'skip_mcp' };
|
|
23
|
+
}
|
|
24
|
+
const withMcpFlag =
|
|
25
|
+
env.PUMUKI_POSTINSTALL_WITH_MCP === '1' ||
|
|
26
|
+
env.PUMUKI_POSTINSTALL_WITH_MCP?.toLowerCase() === 'true';
|
|
27
|
+
const explicit = normalizeExplicitAgent(env.PUMUKI_POSTINSTALL_MCP_AGENT);
|
|
28
|
+
if (explicit) {
|
|
29
|
+
return { extras: ['--with-mcp', `--agent=${explicit}`], reason: 'explicit_agent' };
|
|
30
|
+
}
|
|
31
|
+
if (withMcpFlag) {
|
|
32
|
+
return { extras: ['--with-mcp', '--agent=repo'], reason: 'explicit_repo_flag' };
|
|
33
|
+
}
|
|
34
|
+
return {
|
|
35
|
+
extras: [],
|
|
36
|
+
reason: 'disabled_default',
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
module.exports = {
|
|
41
|
+
KNOWN_MCP_AGENTS,
|
|
42
|
+
resolveConsumerPostinstallInstallExtras,
|
|
43
|
+
normalizeExplicitAgent,
|
|
44
|
+
};
|
|
@@ -4,56 +4,111 @@
|
|
|
4
4
|
const { existsSync } = require('node:fs');
|
|
5
5
|
const { join, resolve } = require('node:path');
|
|
6
6
|
const { spawnSync } = require('node:child_process');
|
|
7
|
+
const { resolveConsumerPostinstallInstallExtras } = require('./consumer-postinstall-resolve-args.cjs');
|
|
7
8
|
|
|
8
|
-
const skipReason = () => {
|
|
9
|
-
if (
|
|
9
|
+
const skipReason = (env = process.env) => {
|
|
10
|
+
if (env.PUMUKI_SKIP_POSTINSTALL === '1') {
|
|
10
11
|
return 'PUMUKI_SKIP_POSTINSTALL=1';
|
|
11
12
|
}
|
|
12
|
-
if (
|
|
13
|
+
if (env.CI === 'true' || env.CI === '1') {
|
|
13
14
|
return 'CI';
|
|
14
15
|
}
|
|
15
|
-
if (
|
|
16
|
+
if (env.npm_config_ignore_scripts === 'true') {
|
|
16
17
|
return 'npm ignore-scripts';
|
|
17
18
|
}
|
|
18
19
|
return '';
|
|
19
20
|
};
|
|
20
21
|
|
|
21
|
-
const
|
|
22
|
-
|
|
22
|
+
const normalizePumukiInstallResult = (result) => {
|
|
23
|
+
if (result.error) {
|
|
24
|
+
return {
|
|
25
|
+
code: 1,
|
|
26
|
+
errorMessage: result.error.message ?? String(result.error),
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return { code: typeof result.status === 'number' ? result.status : 1, errorMessage: null };
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const runPostinstall = ({
|
|
34
|
+
spawnSyncFn = spawnSync,
|
|
35
|
+
packageRoot = resolve(__dirname, '..'),
|
|
36
|
+
consumerRoot = process.env.INIT_CWD || process.cwd(),
|
|
37
|
+
env = process.env,
|
|
38
|
+
logger = console,
|
|
39
|
+
} = {}) => {
|
|
40
|
+
const reason = skipReason(env);
|
|
23
41
|
if (reason) {
|
|
24
42
|
return 0;
|
|
25
43
|
}
|
|
26
44
|
|
|
27
|
-
const consumerRoot = process.env.INIT_CWD || process.cwd();
|
|
28
45
|
if (!existsSync(join(consumerRoot, '.git'))) {
|
|
29
46
|
return 0;
|
|
30
47
|
}
|
|
31
48
|
|
|
32
|
-
const packageRoot = resolve(__dirname, '..');
|
|
33
49
|
const pumukiCli = join(packageRoot, 'bin', 'pumuki.js');
|
|
34
50
|
if (!existsSync(pumukiCli)) {
|
|
35
51
|
return 0;
|
|
36
52
|
}
|
|
37
53
|
|
|
38
|
-
const
|
|
39
|
-
...
|
|
54
|
+
const postinstallEnv = {
|
|
55
|
+
...env,
|
|
40
56
|
PUMUKI_AUTO_POSTINSTALL: '1',
|
|
41
|
-
PUMUKI_SKIP_OPENSPEC_BOOTSTRAP:
|
|
57
|
+
PUMUKI_SKIP_OPENSPEC_BOOTSTRAP: env.PUMUKI_SKIP_OPENSPEC_BOOTSTRAP ?? '1',
|
|
42
58
|
};
|
|
43
59
|
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
60
|
+
const { extras: installExtras, reason: mcpReason } = resolveConsumerPostinstallInstallExtras(
|
|
61
|
+
consumerRoot,
|
|
62
|
+
postinstallEnv
|
|
63
|
+
);
|
|
64
|
+
if (installExtras.length > 0 && postinstallEnv.PUMUKI_VERBOSE_INSTALL === '1') {
|
|
65
|
+
logger.debug(
|
|
66
|
+
`[pumuki] postinstall: mcp wiring (${mcpReason}): ${installExtras.join(' ')}`
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (installExtras.length === 0 && postinstallEnv.PUMUKI_VERBOSE_INSTALL === '1') {
|
|
71
|
+
logger.debug('[pumuki] postinstall: no extra args; running baseline install only.');
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const result = normalizePumukiInstallResult(
|
|
75
|
+
spawnSyncFn(process.execPath, [pumukiCli, 'install', ...installExtras], {
|
|
76
|
+
cwd: consumerRoot,
|
|
77
|
+
env: postinstallEnv,
|
|
78
|
+
stdio: 'inherit',
|
|
79
|
+
})
|
|
80
|
+
);
|
|
49
81
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
82
|
+
if (result.code !== 0) {
|
|
83
|
+
const scope = installExtras.length > 0 ? 'postinstall+extras' : 'postinstall';
|
|
84
|
+
const severityHint =
|
|
85
|
+
installExtras.length > 0
|
|
86
|
+
? 'Run `pumuki install` manually with the desired options to investigar y resolver el fallo.'
|
|
87
|
+
: 'Run `pumuki install` o `pumuki doctor` desde la raíz del repo.';
|
|
88
|
+
logger.error(
|
|
89
|
+
`[pumuki] postinstall: install exited non-zero (scope=${scope}, reason=${mcpReason}). ${severityHint}`
|
|
54
90
|
);
|
|
91
|
+
if (result.errorMessage) {
|
|
92
|
+
logger.error(`[pumuki] postinstall: ${result.errorMessage}`);
|
|
93
|
+
}
|
|
55
94
|
}
|
|
56
|
-
|
|
95
|
+
|
|
96
|
+
return result.code;
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
const main = () => {
|
|
100
|
+
return runPostinstall({
|
|
101
|
+
spawnSyncFn: spawnSync,
|
|
102
|
+
packageRoot: resolve(__dirname, '..'),
|
|
103
|
+
consumerRoot: process.env.INIT_CWD || process.cwd(),
|
|
104
|
+
env: process.env,
|
|
105
|
+
logger: console,
|
|
106
|
+
});
|
|
57
107
|
};
|
|
58
108
|
|
|
59
109
|
process.exitCode = main();
|
|
110
|
+
|
|
111
|
+
module.exports = {
|
|
112
|
+
runPostinstall,
|
|
113
|
+
skipReason,
|
|
114
|
+
};
|
|
@@ -19,47 +19,20 @@ import {
|
|
|
19
19
|
renderActionRow,
|
|
20
20
|
renderBadge,
|
|
21
21
|
} from './framework-menu-ui-components-lib';
|
|
22
|
-
import {
|
|
23
|
-
buildGovernanceConsoleSummaryLines,
|
|
24
|
-
type GovernanceConsoleSnapshot,
|
|
25
|
-
} from '../integrations/lifecycle/cliGovernanceConsole';
|
|
26
|
-
import type { ConsumerPreflightResult } from './framework-menu-consumer-preflight-types';
|
|
27
22
|
|
|
28
23
|
export const formatAdvancedMenuView = (
|
|
29
24
|
actions: ReadonlyArray<MenuAction>,
|
|
30
25
|
options?: {
|
|
31
26
|
evidenceSummary?: FrameworkMenuEvidenceSummary;
|
|
32
|
-
preflight?: ConsumerPreflightResult | null;
|
|
33
|
-
governanceConsole?: GovernanceConsoleSnapshot | null;
|
|
34
27
|
}
|
|
35
28
|
): string => {
|
|
36
29
|
const evidenceSummary = options?.evidenceSummary ?? readEvidenceSummaryForMenu(process.cwd());
|
|
37
30
|
const tokens = buildCliDesignTokens();
|
|
38
31
|
const statusBadge = resolveAdvancedStatusBadge(evidenceSummary, tokens);
|
|
39
32
|
const groupedActions = resolveAdvancedMenuLayout(actions);
|
|
40
|
-
const governanceConsole = options?.preflight
|
|
41
|
-
? {
|
|
42
|
-
governanceObservation: options.preflight.governanceObservation,
|
|
43
|
-
governanceNextAction: options.preflight.governanceNextAction,
|
|
44
|
-
policyValidation: options.preflight.policyValidation,
|
|
45
|
-
experimentalFeatures: options.preflight.experimentalFeatures,
|
|
46
|
-
}
|
|
47
|
-
: (options?.governanceConsole ?? null);
|
|
48
33
|
const lines = [
|
|
49
34
|
'Pumuki Framework Menu (Advanced)',
|
|
50
35
|
`Status: ${statusBadge}`,
|
|
51
|
-
...(governanceConsole
|
|
52
|
-
? [
|
|
53
|
-
'Governance Console',
|
|
54
|
-
...buildGovernanceConsoleSummaryLines({
|
|
55
|
-
governanceObservation: governanceConsole.governanceObservation,
|
|
56
|
-
governanceNextAction: governanceConsole.governanceNextAction,
|
|
57
|
-
policyValidation: governanceConsole.policyValidation,
|
|
58
|
-
experimentalFeatures: governanceConsole.experimentalFeatures,
|
|
59
|
-
}).map((line) => ` ${line}`),
|
|
60
|
-
'',
|
|
61
|
-
]
|
|
62
|
-
: []),
|
|
63
36
|
'C. Switch to consumer menu',
|
|
64
37
|
'',
|
|
65
38
|
...groupedActions.flatMap((group, groupIndex) => [
|
|
@@ -87,33 +60,11 @@ export const formatAdvancedMenuClassicView = (
|
|
|
87
60
|
actions: ReadonlyArray<MenuAction>,
|
|
88
61
|
options?: {
|
|
89
62
|
evidenceSummary?: FrameworkMenuEvidenceSummary;
|
|
90
|
-
preflight?: ConsumerPreflightResult | null;
|
|
91
|
-
governanceConsole?: GovernanceConsoleSnapshot | null;
|
|
92
63
|
}
|
|
93
64
|
): string => {
|
|
94
65
|
const evidenceSummary = options?.evidenceSummary ?? readEvidenceSummaryForMenu(process.cwd());
|
|
95
|
-
const governanceConsole = options?.preflight
|
|
96
|
-
? {
|
|
97
|
-
governanceObservation: options.preflight.governanceObservation,
|
|
98
|
-
governanceNextAction: options.preflight.governanceNextAction,
|
|
99
|
-
policyValidation: options.preflight.policyValidation,
|
|
100
|
-
experimentalFeatures: options.preflight.experimentalFeatures,
|
|
101
|
-
}
|
|
102
|
-
: (options?.governanceConsole ?? null);
|
|
103
66
|
const lines = [
|
|
104
67
|
'Pumuki Framework Menu (Advanced)',
|
|
105
|
-
...(governanceConsole
|
|
106
|
-
? [
|
|
107
|
-
'Governance Console',
|
|
108
|
-
...buildGovernanceConsoleSummaryLines({
|
|
109
|
-
governanceObservation: governanceConsole.governanceObservation,
|
|
110
|
-
governanceNextAction: governanceConsole.governanceNextAction,
|
|
111
|
-
policyValidation: governanceConsole.policyValidation,
|
|
112
|
-
experimentalFeatures: governanceConsole.experimentalFeatures,
|
|
113
|
-
}).map((line) => ` ${line}`),
|
|
114
|
-
'',
|
|
115
|
-
]
|
|
116
|
-
: []),
|
|
117
68
|
'C. Switch to consumer menu',
|
|
118
69
|
...actions.map((action) => {
|
|
119
70
|
const help = ADVANCED_MENU_HELP[action.id];
|