pumuki 6.3.97 → 6.3.99

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.
Files changed (96) hide show
  1. package/AGENTS.md +269 -0
  2. package/CHANGELOG.md +697 -0
  3. package/README.md +4 -2
  4. package/VERSION +1 -1
  5. package/docs/README.md +13 -9
  6. package/docs/operations/RELEASE_NOTES.md +12 -76
  7. package/docs/product/HOW_IT_WORKS.md +6 -0
  8. package/docs/product/INSTALLATION.md +1 -1
  9. package/docs/product/USAGE.md +41 -4
  10. package/docs/tracking/plan-curso-pumuki-stack-my-architecture.md +118 -0
  11. package/docs/validation/README.md +6 -3
  12. package/integrations/config/skillsCustomRules.ts +18 -99
  13. package/integrations/evidence/buildEvidence.ts +0 -24
  14. package/integrations/evidence/repoState.ts +0 -3
  15. package/integrations/evidence/schema.ts +0 -18
  16. package/integrations/evidence/writeEvidence.ts +0 -24
  17. package/integrations/gate/evaluateAiGate.ts +15 -232
  18. package/integrations/gate/remediationCatalog.ts +0 -8
  19. package/integrations/git/GitService.ts +44 -5
  20. package/integrations/git/aiGateRepoPolicyFindings.ts +0 -4
  21. package/integrations/git/runPlatformGate.ts +1 -9
  22. package/integrations/git/runPlatformGateFacts.ts +19 -1
  23. package/integrations/git/runPlatformGateOutput.ts +27 -36
  24. package/integrations/lifecycle/adapter.templates.json +7 -13
  25. package/integrations/lifecycle/adapter.ts +0 -24
  26. package/integrations/lifecycle/artifacts.ts +1 -6
  27. package/integrations/lifecycle/audit.ts +101 -0
  28. package/integrations/lifecycle/cli.ts +110 -70
  29. package/integrations/lifecycle/cliSdd.ts +13 -8
  30. package/integrations/lifecycle/doctor.ts +16 -48
  31. package/integrations/lifecycle/hookManager.ts +0 -77
  32. package/integrations/lifecycle/index.ts +2 -0
  33. package/integrations/lifecycle/install.ts +0 -21
  34. package/integrations/lifecycle/npmService.ts +3 -155
  35. package/integrations/lifecycle/policyValidationSnapshot.ts +8 -2
  36. package/integrations/lifecycle/preWriteAutomation.ts +7 -77
  37. package/integrations/lifecycle/state.ts +1 -8
  38. package/integrations/lifecycle/status.ts +2 -29
  39. package/integrations/mcp/aiGateCheck.ts +26 -206
  40. package/integrations/mcp/autoExecuteAiStart.ts +87 -94
  41. package/integrations/mcp/enterpriseServer.ts +7 -23
  42. package/integrations/mcp/enterpriseStdioServer.cli.ts +4 -31
  43. package/integrations/mcp/preFlightCheck.ts +5 -51
  44. package/integrations/platform/detectPlatforms.ts +37 -0
  45. package/integrations/policy/experimentalFeatures.ts +1 -1
  46. package/integrations/sdd/evidenceScaffold.ts +2 -109
  47. package/package.json +10 -2
  48. package/scripts/check-tracking-single-active.sh +1 -1
  49. package/scripts/consumer-menu-matrix-baseline-report-lib.ts +13 -38
  50. package/scripts/consumer-postinstall-resolve-args.cjs +44 -0
  51. package/scripts/consumer-postinstall.cjs +76 -21
  52. package/scripts/framework-menu-advanced-view-lib.ts +0 -15
  53. package/scripts/framework-menu-consumer-actions-lib.ts +28 -4
  54. package/scripts/framework-menu-consumer-preflight-hints.ts +5 -2
  55. package/scripts/framework-menu-consumer-preflight-render.ts +0 -10
  56. package/scripts/framework-menu-consumer-preflight-run.ts +0 -23
  57. package/scripts/framework-menu-consumer-preflight-types.ts +0 -12
  58. package/scripts/framework-menu-consumer-runtime-actions.ts +87 -17
  59. package/scripts/framework-menu-consumer-runtime-audit.ts +36 -2
  60. package/scripts/framework-menu-consumer-runtime-evidence-classic.ts +140 -0
  61. package/scripts/framework-menu-consumer-runtime-lib.ts +2 -10
  62. package/scripts/framework-menu-consumer-runtime-menu.ts +4 -18
  63. package/scripts/framework-menu-consumer-runtime-types.ts +3 -3
  64. package/scripts/framework-menu-evidence-summary-lib.ts +1 -0
  65. package/scripts/framework-menu-evidence-summary-read.ts +57 -5
  66. package/scripts/framework-menu-evidence-summary-severity.ts +3 -1
  67. package/scripts/framework-menu-evidence-summary-types.ts +7 -0
  68. package/scripts/framework-menu-gate-lib.ts +9 -0
  69. package/scripts/framework-menu-layout-data.ts +5 -0
  70. package/scripts/framework-menu-matrix-baseline-lib.ts +15 -14
  71. package/scripts/framework-menu-matrix-canary-lib.ts +22 -1
  72. package/scripts/framework-menu-matrix-evidence-lib.ts +1 -0
  73. package/scripts/framework-menu-matrix-evidence-types.ts +13 -1
  74. package/scripts/framework-menu-matrix-runner-lib.ts +35 -0
  75. package/scripts/framework-menu-system-notifications-cause.ts +0 -24
  76. package/scripts/framework-menu-system-notifications-macos-swift-source.ts +24 -204
  77. package/scripts/framework-menu-system-notifications-macos.ts +4 -0
  78. package/scripts/framework-menu-system-notifications-payloads-blocked.ts +1 -1
  79. package/scripts/framework-menu-system-notifications-remediation.ts +13 -24
  80. package/scripts/framework-menu-system-notifications-text.ts +1 -7
  81. package/scripts/framework-menu.ts +3 -2
  82. package/scripts/package-install-smoke-consumer-git-repo-lib.ts +1 -10
  83. package/scripts/package-install-smoke-consumer-npm-lib.ts +9 -46
  84. package/scripts/pumuki-full-surface-smoke-lib.ts +37 -0
  85. package/scripts/pumuki-full-surface-smoke.ts +346 -0
  86. package/scripts/pumuki-smoke-installed-wrapper.cjs +31 -0
  87. package/integrations/evidence/trackingContract.ts +0 -150
  88. package/integrations/gate/governanceActionCatalog.ts +0 -275
  89. package/integrations/lifecycle/bootstrapManifest.ts +0 -248
  90. package/integrations/lifecycle/cliGovernanceConsole.ts +0 -69
  91. package/integrations/lifecycle/governanceNextAction.ts +0 -164
  92. package/integrations/lifecycle/governanceObservationSnapshot.ts +0 -613
  93. package/integrations/mcp/alignedPlatformGate.ts +0 -232
  94. package/integrations/mcp/readMcpPrePushStdin.ts +0 -7
  95. package/scripts/build-ruralgo-s1-evidence-pack.ts +0 -85
  96. package/scripts/ruralgo-s1-evidence-pack-lib.ts +0 -200
@@ -1,275 +0,0 @@
1
- import type { AiGateStage } from './evaluateAiGate';
2
-
3
- export type GovernanceCatalogNextAction = {
4
- kind: 'info' | 'run_command';
5
- message: string;
6
- command?: string;
7
- };
8
-
9
- export type GovernanceCatalogAction = {
10
- reason_code: string;
11
- instruction: string;
12
- next_action: GovernanceCatalogNextAction;
13
- };
14
-
15
- const PRE_WRITE_VALIDATE_COMMAND =
16
- 'npx --yes --package pumuki@latest pumuki sdd validate --stage=PRE_WRITE --json';
17
-
18
- export const buildGovernanceValidateCommand = (stage: AiGateStage): string =>
19
- PRE_WRITE_VALIDATE_COMMAND.replace('PRE_WRITE', stage);
20
-
21
- export const buildGovernancePolicyReconcileCommand = (stage: AiGateStage): string =>
22
- `npx --yes --package pumuki@latest pumuki policy reconcile --strict --json && ${buildGovernanceValidateCommand(stage)}`;
23
-
24
- const buildFallbackAction = (code: string): GovernanceCatalogAction => ({
25
- reason_code: code,
26
- instruction: 'Corrige el bloqueante primario y vuelve a ejecutar la validación del stage actual.',
27
- next_action: {
28
- kind: 'info',
29
- message: 'Corrige el bloqueante primario y vuelve a ejecutar el mismo comando.',
30
- },
31
- });
32
-
33
- export const resolveGovernanceCatalogAction = (params: {
34
- code: string;
35
- stage?: AiGateStage;
36
- fallback?: GovernanceCatalogAction;
37
- }): GovernanceCatalogAction => {
38
- const stage = params.stage ?? 'PRE_WRITE';
39
- const validateCommand = buildGovernanceValidateCommand(stage);
40
- switch (params.code) {
41
- case 'READY':
42
- return {
43
- reason_code: 'READY',
44
- instruction: 'Puedes continuar con la siguiente slice mínima y volver a validar al cerrar.',
45
- next_action: {
46
- kind: 'info',
47
- message: 'Gate en verde. Continúa con la implementación.',
48
- },
49
- };
50
- case 'EVIDENCE_INVALID_OR_CHAIN':
51
- return {
52
- reason_code: 'EVIDENCE_INVALID_OR_CHAIN',
53
- instruction: 'Regenera la evidencia canónica antes de continuar.',
54
- next_action: {
55
- kind: 'run_command',
56
- message: 'Regenera o corrige la evidencia canónica (.ai_evidence.json) y vuelve a validar governance.',
57
- command: validateCommand,
58
- },
59
- };
60
- case 'AI_GATE_BLOCKED':
61
- return {
62
- reason_code: 'AI_GATE_BLOCKED',
63
- instruction: 'Corrige primero el bloqueo principal del gate antes de continuar.',
64
- next_action: {
65
- kind: 'run_command',
66
- message: 'Revalida el stage tras corregir la evidencia y el bloqueo principal.',
67
- command: validateCommand,
68
- },
69
- };
70
- case 'SDD_SESSION_MISSING':
71
- return {
72
- reason_code: 'SDD_SESSION_MISSING',
73
- instruction: 'Abre una sesión SDD válida antes de seguir trabajando.',
74
- next_action: {
75
- kind: 'run_command',
76
- message: 'Abre la sesión SDD del cambio activo y vuelve a validar.',
77
- command: 'npx --yes --package pumuki@latest pumuki sdd session --open --change=<id>',
78
- },
79
- };
80
- case 'SDD_SESSION_INVALID':
81
- case 'SDD_SESSION_INVALID_OR_EXPIRED':
82
- return {
83
- reason_code: 'SDD_SESSION_INVALID_OR_EXPIRED',
84
- instruction: 'Refresca o reabre la sesión SDD antes de seguir trabajando.',
85
- next_action: {
86
- kind: 'run_command',
87
- message: 'Refresca la sesión SDD y vuelve a validar governance.',
88
- command: 'npx --yes --package pumuki@latest pumuki sdd session --refresh --ttl-minutes=90',
89
- },
90
- };
91
- case 'PRE_PUSH_UPSTREAM_MISSING':
92
- return {
93
- reason_code: 'PRE_PUSH_UPSTREAM_MISSING',
94
- instruction: 'Configura el upstream remoto antes de continuar con PRE_PUSH.',
95
- next_action: {
96
- kind: 'run_command',
97
- message: 'Configura tracking remoto para la rama actual.',
98
- command: 'git push --set-upstream origin <branch>',
99
- },
100
- };
101
- case 'PRE_PUSH_UPSTREAM_MISALIGNED':
102
- return {
103
- reason_code: 'PRE_PUSH_UPSTREAM_MISALIGNED',
104
- instruction: 'Alinea el upstream remoto con la rama actual antes de continuar.',
105
- next_action: {
106
- kind: 'run_command',
107
- message: 'Reconfigura el upstream remoto de la rama actual.',
108
- command: 'git branch --unset-upstream && git push --set-upstream origin <branch>',
109
- },
110
- };
111
- case 'GITFLOW_PROTECTED_BRANCH':
112
- case 'GITFLOW_PROTECTED_BRANCH_CONTEXT':
113
- return {
114
- reason_code: 'GITFLOW_PROTECTED_BRANCH_CONTEXT',
115
- instruction: 'Sal de la rama protegida y mueve el trabajo a feature/* o refactor/*.',
116
- next_action: {
117
- kind: 'run_command',
118
- message: 'Crea una rama válida de trabajo antes de seguir.',
119
- command: 'git checkout -b feature/<descripcion-kebab-case>',
120
- },
121
- };
122
- case 'GITFLOW_BRANCH_NAMING_INVALID':
123
- case 'GITFLOW_BRANCH_NAMING_INVALID_CONTEXT':
124
- return {
125
- reason_code: 'GITFLOW_BRANCH_NAMING_INVALID_CONTEXT',
126
- instruction:
127
- 'Renombra o recrea la rama actual con un prefijo GitFlow válido antes de continuar.',
128
- next_action: {
129
- kind: 'run_command',
130
- message: 'Crea una rama válida y mueve el trabajo a esa rama antes de seguir.',
131
- command: 'git checkout -b feature/<descripcion-kebab-case>',
132
- },
133
- };
134
- case 'TRACKING_CANONICAL_SOURCE_CONFLICT':
135
- return {
136
- reason_code: 'TRACKING_CANONICAL_SOURCE_CONFLICT',
137
- instruction:
138
- 'Alinea AGENTS.md y los README canónicos para que todos apunten al mismo MD de seguimiento.',
139
- next_action: {
140
- kind: 'info',
141
- message:
142
- 'Deja una única fuente canónica de tracking y elimina referencias legacy o contradictorias.',
143
- },
144
- };
145
- case 'TRACKING_CANONICAL_FILE_MISSING':
146
- return {
147
- reason_code: 'TRACKING_CANONICAL_FILE_MISSING',
148
- instruction:
149
- 'Crea o restaura el MD de seguimiento canónico declarado por el repo antes de continuar.',
150
- next_action: {
151
- kind: 'info',
152
- message:
153
- 'Restaura el archivo canónico de tracking y vuelve a validar governance.',
154
- },
155
- };
156
- case 'TRACKING_CANONICAL_IN_PROGRESS_INVALID':
157
- return {
158
- reason_code: 'TRACKING_CANONICAL_IN_PROGRESS_INVALID',
159
- instruction:
160
- 'El tracking canónico debe tener exactamente una tarea o fase en construcción.',
161
- next_action: {
162
- kind: 'info',
163
- message:
164
- 'Corrige el MD canónico para dejar exactamente una `🚧` antes de continuar.',
165
- },
166
- };
167
- case 'POLICY_STAGE_NOT_STRICT':
168
- return {
169
- reason_code: 'POLICY_STAGE_NOT_STRICT',
170
- instruction: 'Reconcilia policy/skills en modo estricto antes de seguir.',
171
- next_action: {
172
- kind: 'run_command',
173
- message: 'Converge policy-as-code y revalida el stage actual.',
174
- command: buildGovernancePolicyReconcileCommand(stage),
175
- },
176
- };
177
- case 'SKILLS_CONTRACT_SURFACE_INCOMPLETE':
178
- case 'EVIDENCE_SKILLS_CONTRACT_INCOMPLETE':
179
- return {
180
- reason_code: 'SKILLS_CONTRACT_SURFACE_INCOMPLETE',
181
- instruction: 'Materializa el lock/sources de skills antes de dar governance efectiva.',
182
- next_action: {
183
- kind: 'run_command',
184
- message: 'Reconcilia policy/skills y vuelve a validar governance.',
185
- command: buildGovernancePolicyReconcileCommand(stage),
186
- },
187
- };
188
- case 'ADAPTER_WIRING_MISSING':
189
- return {
190
- reason_code: 'ADAPTER_WIRING_MISSING',
191
- instruction: 'Instala el adaptador canónico si quieres wiring explícito de IDE/MCP.',
192
- next_action: {
193
- kind: 'run_command',
194
- message: 'Genera `.pumuki/adapter.json` desde la instalación canónica.',
195
- command: 'npx --yes --package pumuki@latest pumuki install --with-mcp',
196
- },
197
- };
198
- case 'EVIDENCE_STALE':
199
- case 'EVIDENCE_BRANCH_MISMATCH':
200
- case 'EVIDENCE_SNAPSHOT_WARN':
201
- return {
202
- reason_code: params.code === 'EVIDENCE_SNAPSHOT_WARN' ? 'EVIDENCE_SNAPSHOT_WARN' : 'EVIDENCE_STALE',
203
- instruction: 'Refresca evidencia y revisa hallazgos WARN antes de continuar.',
204
- next_action: {
205
- kind: 'run_command',
206
- message: 'Revalida el stage actual y revisa findings WARN.',
207
- command: validateCommand,
208
- },
209
- };
210
- case 'ACTIVE_RULE_IDS_EMPTY_FOR_CODE_CHANGES_HIGH':
211
- case 'EVIDENCE_ACTIVE_RULE_IDS_EMPTY_FOR_CODE_CHANGES':
212
- return {
213
- reason_code: 'EVIDENCE_ACTIVE_RULE_IDS_EMPTY_FOR_CODE_CHANGES',
214
- instruction: 'Reconcilia policy/skills en modo estricto y revalida el stage actual.',
215
- next_action: {
216
- kind: 'run_command',
217
- message: 'Converge policy-as-code y vuelve a validar cobertura de active_rule_ids para reglas activas.',
218
- command: buildGovernancePolicyReconcileCommand(stage),
219
- },
220
- };
221
- case 'EVIDENCE_PLATFORM_SKILLS_SCOPE_INCOMPLETE':
222
- case 'EVIDENCE_PLATFORM_SKILLS_BUNDLES_MISSING':
223
- return {
224
- reason_code: params.code,
225
- instruction: 'Completa cobertura de skills por plataforma y vuelve a validar.',
226
- next_action: {
227
- kind: 'run_command',
228
- message: 'Completa bundles/prefijos de skills requeridos y revalida el stage actual.',
229
- command: validateCommand,
230
- },
231
- };
232
- case 'EVIDENCE_PLATFORM_CRITICAL_SKILLS_RULES_MISSING':
233
- case 'EVIDENCE_CROSS_PLATFORM_CRITICAL_ENFORCEMENT_INCOMPLETE':
234
- return {
235
- reason_code: params.code,
236
- instruction: 'Reconcilia policy/skills en modo estricto para enforcement crítico y revalida.',
237
- next_action: {
238
- kind: 'run_command',
239
- message: 'Materializa reglas críticas de plataforma y vuelve a validar el stage actual.',
240
- command: buildGovernancePolicyReconcileCommand(stage),
241
- },
242
- };
243
- case 'EVIDENCE_PREWRITE_WORKTREE_OVER_LIMIT':
244
- case 'EVIDENCE_PREWRITE_WORKTREE_WARN':
245
- return {
246
- reason_code: params.code,
247
- instruction: 'Particiona el worktree en slices atómicos antes de continuar.',
248
- next_action: {
249
- kind: 'run_command',
250
- message: 'Reduce el worktree pendiente y revalida el stage actual.',
251
- command: `git status --short && git add -p && ${validateCommand}`,
252
- },
253
- };
254
- case 'SKILLS_SKILLS_FRONTEND_NO_SOLID_VIOLATIONS':
255
- return {
256
- reason_code: 'SKILLS_SKILLS_FRONTEND_NO_SOLID_VIOLATIONS',
257
- instruction: 'Aplica refactor incremental por componente/hook y vuelve a validar.',
258
- next_action: {
259
- kind: 'info',
260
- message: 'Aplica refactor incremental: extrae 1 componente/hook por commit y vuelve a ejecutar el gate.',
261
- },
262
- };
263
- case 'GOVERNANCE_ATTENTION':
264
- return {
265
- reason_code: 'GOVERNANCE_ATTENTION',
266
- instruction: 'Revisa governance truth y corrige el primer hueco del contrato antes de continuar.',
267
- next_action: {
268
- kind: 'info',
269
- message: 'Revisa governance truth, corrige el primer gap visible y vuelve a validar.',
270
- },
271
- };
272
- default:
273
- return params.fallback ?? buildFallbackAction(params.code);
274
- }
275
- };
@@ -1,248 +0,0 @@
1
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'
2
- import { dirname, join } from 'node:path'
3
- import { getPumukiHooksStatus, resolvePumukiHooksDirectory } from './hookManager'
4
- import { LifecycleGitService, type ILifecycleGitService } from './gitService'
5
- import {
6
- readGovernanceObservationSnapshot,
7
- type GovernanceContractSurface,
8
- type GovernanceObservationSnapshot,
9
- } from './governanceObservationSnapshot'
10
- import { readGovernanceNextAction, type GovernanceNextActionSummary } from './governanceNextAction'
11
- import { getCurrentPumukiPackageName, getCurrentPumukiVersion } from './packageInfo'
12
- import { readLifecycleExperimentalFeaturesSnapshot } from './experimentalFeaturesSnapshot'
13
- import { readLifecyclePolicyValidationSnapshot } from './policyValidationSnapshot'
14
- import { readLifecycleState } from './state'
15
-
16
- export const BOOTSTRAP_MANIFEST_RELATIVE_PATH = '.pumuki/bootstrap-manifest.json'
17
-
18
- type AdapterCommandContract = {
19
- path: string
20
- present: boolean
21
- hooks: {
22
- pre_write?: string
23
- pre_commit?: string
24
- pre_push?: string
25
- ci?: string
26
- }
27
- mcp: {
28
- enterprise?: string
29
- evidence?: string
30
- }
31
- }
32
-
33
- export type LifecycleBootstrapManifest = {
34
- schema_version: '1'
35
- repo_root: string
36
- package: {
37
- name: string
38
- version: string
39
- }
40
- lifecycle: {
41
- installed: boolean
42
- version: string | null
43
- installed_at: string | null
44
- managed_hooks: ReadonlyArray<string>
45
- openspec_managed_artifacts: ReadonlyArray<string>
46
- }
47
- hooks_directory: {
48
- path: string
49
- source: 'git-rev-parse' | 'git-config' | 'default'
50
- }
51
- hook_status: Record<string, { managed_block_present: boolean; exists: boolean }>
52
- contract_surface: GovernanceContractSurface
53
- governance: {
54
- effective: GovernanceObservationSnapshot['governance_effective']
55
- attention_codes: ReadonlyArray<string>
56
- next_action: GovernanceNextActionSummary
57
- bootstrap_hints: ReadonlyArray<string>
58
- }
59
- sdd: {
60
- effective_mode: GovernanceObservationSnapshot['sdd']['effective_mode']
61
- experimental_source: string
62
- session_active: boolean
63
- session_valid: boolean
64
- change_id: string | null
65
- }
66
- policy_strict: GovernanceObservationSnapshot['policy_strict']
67
- git: GovernanceObservationSnapshot['git']
68
- adapter: AdapterCommandContract
69
- }
70
-
71
- export type LifecycleBootstrapManifestWriteResult = {
72
- path: string
73
- changed: boolean
74
- manifest: LifecycleBootstrapManifest
75
- }
76
-
77
- const isRecord = (value: unknown): value is Record<string, unknown> =>
78
- typeof value === 'object' && value !== null && !Array.isArray(value)
79
-
80
- const readOptionalCommand = (source: unknown): string | undefined => {
81
- if (!isRecord(source)) {
82
- return undefined
83
- }
84
- const command = source.command
85
- return typeof command === 'string' && command.trim().length > 0 ? command.trim() : undefined
86
- }
87
-
88
- const readAdapterCommandContract = (repoRoot: string): AdapterCommandContract => {
89
- const path = join(repoRoot, '.pumuki', 'adapter.json')
90
- if (!existsSync(path)) {
91
- return {
92
- path: BOOTSTRAP_MANIFEST_RELATIVE_PATH.replace('bootstrap-manifest.json', 'adapter.json'),
93
- present: false,
94
- hooks: {},
95
- mcp: {},
96
- }
97
- }
98
-
99
- try {
100
- const parsed = JSON.parse(readFileSync(path, 'utf8')) as unknown
101
- const hooks = isRecord(parsed) && isRecord(parsed.hooks) ? parsed.hooks : {}
102
- const mcp = isRecord(parsed) && isRecord(parsed.mcp) ? parsed.mcp : {}
103
- return {
104
- path: '.pumuki/adapter.json',
105
- present: true,
106
- hooks: {
107
- pre_write: readOptionalCommand(isRecord(hooks) ? hooks.pre_write : undefined),
108
- pre_commit: readOptionalCommand(isRecord(hooks) ? hooks.pre_commit : undefined),
109
- pre_push: readOptionalCommand(isRecord(hooks) ? hooks.pre_push : undefined),
110
- ci: readOptionalCommand(isRecord(hooks) ? hooks.ci : undefined),
111
- },
112
- mcp: {
113
- enterprise: readOptionalCommand(isRecord(mcp) ? mcp.enterprise : undefined),
114
- evidence: readOptionalCommand(isRecord(mcp) ? mcp.evidence : undefined),
115
- },
116
- }
117
- } catch {
118
- return {
119
- path: '.pumuki/adapter.json',
120
- present: false,
121
- hooks: {},
122
- mcp: {},
123
- }
124
- }
125
- }
126
-
127
- const parseManagedHooks = (raw?: string): string[] => {
128
- if (typeof raw !== 'string' || raw.trim().length === 0) {
129
- return []
130
- }
131
- return raw
132
- .split(',')
133
- .map((value) => value.trim())
134
- .filter((value) => value.length > 0)
135
- }
136
-
137
- const parseManagedArtifacts = (raw?: string): string[] => {
138
- if (typeof raw !== 'string' || raw.trim().length === 0) {
139
- return []
140
- }
141
- return raw
142
- .split(',')
143
- .map((value) => value.trim())
144
- .filter((value) => value.length > 0)
145
- }
146
-
147
- const toHookStatusSummary = (
148
- hookStatus: ReturnType<typeof getPumukiHooksStatus>
149
- ): Record<string, { managed_block_present: boolean; exists: boolean }> =>
150
- Object.fromEntries(
151
- Object.entries(hookStatus).map(([hook, entry]) => [
152
- hook,
153
- {
154
- managed_block_present: entry.managedBlockPresent,
155
- exists: entry.exists,
156
- },
157
- ])
158
- )
159
-
160
- export const buildLifecycleBootstrapManifest = (params: {
161
- repoRoot: string
162
- git?: ILifecycleGitService
163
- }): LifecycleBootstrapManifest => {
164
- const git = params.git ?? new LifecycleGitService()
165
- const repoRoot = git.resolveRepoRoot(params.repoRoot)
166
- const lifecycleState = readLifecycleState(git, repoRoot)
167
- const experimentalFeatures = readLifecycleExperimentalFeaturesSnapshot()
168
- const policyValidation = readLifecyclePolicyValidationSnapshot(repoRoot)
169
- const governanceObservation = readGovernanceObservationSnapshot({
170
- repoRoot,
171
- experimentalFeatures,
172
- policyValidation,
173
- git,
174
- })
175
- const governanceNextAction = readGovernanceNextAction({
176
- repoRoot,
177
- stage: 'PRE_WRITE',
178
- governanceObservation,
179
- })
180
- const hooksDirectory = resolvePumukiHooksDirectory(repoRoot)
181
- const hookStatus = getPumukiHooksStatus(repoRoot)
182
- const adapter = readAdapterCommandContract(repoRoot)
183
-
184
- return {
185
- schema_version: '1',
186
- repo_root: repoRoot,
187
- package: {
188
- name: getCurrentPumukiPackageName(),
189
- version: getCurrentPumukiVersion({ repoRoot }),
190
- },
191
- lifecycle: {
192
- installed: lifecycleState.installed === 'true',
193
- version: typeof lifecycleState.version === 'string' && lifecycleState.version.length > 0
194
- ? lifecycleState.version
195
- : null,
196
- installed_at:
197
- typeof lifecycleState.installedAt === 'string' && lifecycleState.installedAt.length > 0
198
- ? lifecycleState.installedAt
199
- : null,
200
- managed_hooks: parseManagedHooks(lifecycleState.hooks),
201
- openspec_managed_artifacts: parseManagedArtifacts(lifecycleState.openSpecManagedArtifacts),
202
- },
203
- hooks_directory: hooksDirectory,
204
- hook_status: toHookStatusSummary(hookStatus),
205
- contract_surface: governanceObservation.contract_surface,
206
- governance: {
207
- effective: governanceObservation.governance_effective,
208
- attention_codes: governanceObservation.attention_codes,
209
- next_action: governanceNextAction,
210
- bootstrap_hints: governanceObservation.agent_bootstrap_hints,
211
- },
212
- sdd: {
213
- effective_mode: governanceObservation.sdd.effective_mode,
214
- experimental_source: governanceObservation.sdd.experimental_source,
215
- session_active: governanceObservation.sdd_session.active,
216
- session_valid: governanceObservation.sdd_session.valid,
217
- change_id: governanceObservation.sdd_session.change_id,
218
- },
219
- policy_strict: governanceObservation.policy_strict,
220
- git: governanceObservation.git,
221
- adapter,
222
- }
223
- }
224
-
225
- const serializeManifest = (manifest: LifecycleBootstrapManifest): string =>
226
- `${JSON.stringify(manifest, null, 2)}\n`
227
-
228
- export const writeLifecycleBootstrapManifest = (params: {
229
- repoRoot: string
230
- git?: ILifecycleGitService
231
- }): LifecycleBootstrapManifestWriteResult => {
232
- const git = params.git ?? new LifecycleGitService()
233
- const repoRoot = git.resolveRepoRoot(params.repoRoot)
234
- const path = join(repoRoot, BOOTSTRAP_MANIFEST_RELATIVE_PATH)
235
- const manifest = buildLifecycleBootstrapManifest({ repoRoot, git })
236
- const nextContents = serializeManifest(manifest)
237
- const currentContents = existsSync(path) ? readFileSync(path, 'utf8') : ''
238
- const changed = currentContents !== nextContents
239
- if (changed) {
240
- mkdirSync(dirname(path), { recursive: true })
241
- writeFileSync(path, nextContents, 'utf8')
242
- }
243
- return {
244
- path,
245
- changed,
246
- manifest,
247
- }
248
- }
@@ -1,69 +0,0 @@
1
- import type { LifecycleExperimentalFeaturesSnapshot } from './experimentalFeaturesSnapshot';
2
- import type { GovernanceNextActionSummary } from './governanceNextAction';
3
- import { buildGovernanceNextActionSummaryLines } from './governanceNextAction';
4
- import type { GovernanceObservationSnapshot } from './governanceObservationSnapshot';
5
- import { buildGovernanceObservationSummaryLines } from './governanceObservationSnapshot';
6
- import { writeInfo } from './cliOutputs';
7
- import type { LifecyclePolicyValidationSnapshot } from './policyValidationSnapshot';
8
-
9
- export type GovernanceConsoleSnapshot = {
10
- governanceObservation: GovernanceObservationSnapshot;
11
- governanceNextAction: GovernanceNextActionSummary;
12
- policyValidation: LifecyclePolicyValidationSnapshot;
13
- experimentalFeatures: LifecycleExperimentalFeaturesSnapshot;
14
- };
15
-
16
- const GOVERNANCE_CONSOLE_FEATURE_ORDER = [
17
- 'analytics',
18
- 'heuristics',
19
- 'learning_context',
20
- 'mcp_enterprise',
21
- 'operational_memory',
22
- 'pre_write',
23
- 'saas_ingestion',
24
- 'sdd',
25
- ] as const;
26
-
27
- const buildGovernancePolicySummaryLine = (
28
- policyValidation: LifecyclePolicyValidationSnapshot
29
- ): string =>
30
- `Policy-as-code: PRE_WRITE=${policyValidation.stages.PRE_WRITE.validationCode ?? 'n/a'} strict=${policyValidation.stages.PRE_WRITE.strict ? 'yes' : 'no'} ` +
31
- `PRE_COMMIT=${policyValidation.stages.PRE_COMMIT.validationCode ?? 'n/a'} strict=${policyValidation.stages.PRE_COMMIT.strict ? 'yes' : 'no'} ` +
32
- `PRE_PUSH=${policyValidation.stages.PRE_PUSH.validationCode ?? 'n/a'} strict=${policyValidation.stages.PRE_PUSH.strict ? 'yes' : 'no'} ` +
33
- `CI=${policyValidation.stages.CI.validationCode ?? 'n/a'} strict=${policyValidation.stages.CI.strict ? 'yes' : 'no'}`;
34
-
35
- const buildGovernanceExperimentalSummaryLines = (
36
- experimentalFeatures: LifecycleExperimentalFeaturesSnapshot
37
- ): string[] =>
38
- GOVERNANCE_CONSOLE_FEATURE_ORDER.map((featureKey) => {
39
- const feature = experimentalFeatures.features[featureKey];
40
- return `Experimental: ${featureKey.toUpperCase()}=${feature.mode} source=${feature.source} layer=${feature.layer} blocking=${feature.blocking ? 'yes' : 'no'} env=${feature.activationVariable}`;
41
- });
42
-
43
- export const buildGovernanceConsoleSummaryLines = (
44
- snapshot: GovernanceConsoleSnapshot
45
- ): string[] => {
46
- const lines = ['Governance truth:'];
47
- for (const line of buildGovernanceObservationSummaryLines(snapshot.governanceObservation)) {
48
- lines.push(` ${line}`);
49
- }
50
- for (const hint of snapshot.governanceObservation.evidence.human_summary_preview) {
51
- lines.push(` Evidence hint: ${hint}`);
52
- }
53
- lines.push('Governance next action:');
54
- for (const line of buildGovernanceNextActionSummaryLines(snapshot.governanceNextAction)) {
55
- lines.push(` ${line}`);
56
- }
57
- lines.push(buildGovernancePolicySummaryLine(snapshot.policyValidation));
58
- lines.push(...buildGovernanceExperimentalSummaryLines(snapshot.experimentalFeatures));
59
- return lines;
60
- };
61
-
62
- export const printGovernanceConsoleHuman = (
63
- snapshot: GovernanceConsoleSnapshot
64
- ): void => {
65
- writeInfo('[pumuki] governance console (S1 / shared status-doctor baseline):');
66
- for (const line of buildGovernanceConsoleSummaryLines(snapshot)) {
67
- writeInfo(`[pumuki] ${line}`);
68
- }
69
- };