@dsalazardev/ai-hub-cli 0.3.0 → 0.3.1
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/README.md +1 -0
- package/dist/cli/onboarding.js +33 -9
- package/dist/speckit/commands.d.ts +23 -5
- package/dist/speckit/commands.js +54 -14
- package/dist/speckit/doctor.d.ts +5 -2
- package/dist/speckit/doctor.js +21 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -95,6 +95,7 @@ ejecuta Python ni `uvx`. En el checkout del motor todos informan `no aplica`.
|
|
|
95
95
|
| `speckit:managed` | `speckit.managed` no es `false`; un arnés con `--no-speckit` es **degradado** y `doctor` sale 1 | `ai-hub install` (sin `--no-speckit`) |
|
|
96
96
|
| `speckit:installed` | Existe `.specify/init-options.json` | `ai-hub install` |
|
|
97
97
|
| `speckit:version` | `speckit_version` coincide con la versión fijada (o la que restrinja `speckit.version`) | `ai-hub install` |
|
|
98
|
+
| `speckit:script` | El script declarado en el manifest coincide con el instalado en `.specify/init-options.json` (`sh`/`ps`) | `ai-hub install` |
|
|
98
99
|
| `speckit:shell` | El shell del script declarado ejecuta `echo ok` (`bash` para `sh`, PowerShell para `ps`) | Instalar Git Bash/bash, o declarar `speckit.script: ps` |
|
|
99
100
|
| `speckit:integrations` | `.specify/integration.json` tiene exactamente las integraciones de los destinos con Spec Kit, sin `copilot`, y la integración por defecto declarada | `ai-hub install`; si aparece `copilot`, `specify integration uninstall copilot` |
|
|
100
101
|
| `speckit:targets` | Informativo: `copilot: sin Spec Kit` (recibe agentes y reglas, no comandos) | — |
|
package/dist/cli/onboarding.js
CHANGED
|
@@ -37,9 +37,25 @@ function speckitPlan(settings) {
|
|
|
37
37
|
extensions: settings.extensions,
|
|
38
38
|
};
|
|
39
39
|
}
|
|
40
|
-
/** Bloque `speckit` a escribir: conserva las restricciones del proyecto y fija `managed
|
|
41
|
-
function speckitBlock(existing, managed) {
|
|
42
|
-
return { ...(existing ?? {}), managed };
|
|
40
|
+
/** Bloque `speckit` a escribir: conserva las restricciones del proyecto y fija `managed` y el script explícito. */
|
|
41
|
+
function speckitBlock(existing, managed, script) {
|
|
42
|
+
return { ...(existing ?? {}), managed, ...(script !== undefined ? { script } : {}) };
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Lee `--script <sh|ps>` (design D3): valida antes de cualquier sondeo y nombra el comando concreto.
|
|
46
|
+
* Devuelve `undefined` cuando la bandera no se usó y `null` cuando es inválida (ya reportado).
|
|
47
|
+
*/
|
|
48
|
+
function parseScriptFlag(args, ctx, command) {
|
|
49
|
+
if (!('script' in args.flags)) {
|
|
50
|
+
return undefined;
|
|
51
|
+
}
|
|
52
|
+
const value = flagString(args, 'script');
|
|
53
|
+
if (value === 'sh' || value === 'ps') {
|
|
54
|
+
return value;
|
|
55
|
+
}
|
|
56
|
+
ctx.io.err(`--script acepta sh o ps${value === null ? ' y necesita un valor' : ` (recibido: ${value})`}; ` +
|
|
57
|
+
`ejecuta ai-hub ${command} --script sh o ai-hub ${command} --script ps`);
|
|
58
|
+
return null;
|
|
43
59
|
}
|
|
44
60
|
function speckitSettingsFor(targets, block, engine) {
|
|
45
61
|
return effectiveSpeckit({ targets, speckit: block }, engine);
|
|
@@ -51,8 +67,8 @@ async function environmentFor(settings, ctx) {
|
|
|
51
67
|
return probeEnvironment(settings, ctx.exec, ctx.root);
|
|
52
68
|
}
|
|
53
69
|
/** Preflight de Spec Kit; devuelve `false` y explica el motivo si hay que salir con 2. */
|
|
54
|
-
async function preflightOrReport(settings, ctx) {
|
|
55
|
-
const preflight = await speckitPreflight(settings, ctx.exec, ctx.root);
|
|
70
|
+
async function preflightOrReport(settings, ctx, command) {
|
|
71
|
+
const preflight = await speckitPreflight(settings, ctx.exec, ctx.root, command);
|
|
56
72
|
if (!preflight.ok) {
|
|
57
73
|
ctx.io.err('preflight de Spec Kit fallido; no se escribió nada:');
|
|
58
74
|
for (const problem of preflight.problems) {
|
|
@@ -359,6 +375,10 @@ async function resolveSelection(args, ctx) {
|
|
|
359
375
|
};
|
|
360
376
|
}
|
|
361
377
|
export async function cmdInit(args, ctx) {
|
|
378
|
+
const scriptFlag = parseScriptFlag(args, ctx, 'init');
|
|
379
|
+
if (scriptFlag === null) {
|
|
380
|
+
return 2;
|
|
381
|
+
}
|
|
362
382
|
const sourceCheckout = await isEngineCheckout(ctx.root);
|
|
363
383
|
let selection;
|
|
364
384
|
try {
|
|
@@ -394,7 +414,7 @@ export async function cmdInit(args, ctx) {
|
|
|
394
414
|
}
|
|
395
415
|
const includeMcp = await exists(path.join(ctx.root, 'mcp-manifest.yaml'));
|
|
396
416
|
const assets = await buildAssetPlan(spec, engine, selection.targets, includeMcp);
|
|
397
|
-
const speckit = speckitBlock(existing?.speckit, !args.flags['no-speckit']);
|
|
417
|
+
const speckit = speckitBlock(existing?.speckit, !args.flags['no-speckit'], scriptFlag);
|
|
398
418
|
const speckitSettings = speckitSettingsFor(selection.targets, speckit, engine);
|
|
399
419
|
// El taller nunca ejecuta Spec Kit: su .specify/ es del mantenedor.
|
|
400
420
|
const runSpeckit = speckitSettings.managed && !sourceCheckout;
|
|
@@ -429,7 +449,7 @@ export async function cmdInit(args, ctx) {
|
|
|
429
449
|
}
|
|
430
450
|
return 0;
|
|
431
451
|
}
|
|
432
|
-
if (runSpeckit && !(await preflightOrReport(speckitSettings, ctx))) {
|
|
452
|
+
if (runSpeckit && !(await preflightOrReport(speckitSettings, ctx, 'init'))) {
|
|
433
453
|
return 2;
|
|
434
454
|
}
|
|
435
455
|
// Backup restaurable antes de que Spec Kit toque un proyecto existente (constitución incluida).
|
|
@@ -538,6 +558,10 @@ async function retiredCatalogSkills(ids) {
|
|
|
538
558
|
return ids.filter((id) => retired.has(id));
|
|
539
559
|
}
|
|
540
560
|
export async function cmdInstall(args, ctx) {
|
|
561
|
+
const scriptFlag = parseScriptFlag(args, ctx, 'install');
|
|
562
|
+
if (scriptFlag === null) {
|
|
563
|
+
return 2;
|
|
564
|
+
}
|
|
541
565
|
let context;
|
|
542
566
|
try {
|
|
543
567
|
context = await loadManifestContext(ctx.root);
|
|
@@ -556,7 +580,7 @@ export async function cmdInstall(args, ctx) {
|
|
|
556
580
|
}
|
|
557
581
|
const includeMcp = await exists(path.join(ctx.root, 'mcp-manifest.yaml'));
|
|
558
582
|
// install sin --no-speckit reactiva Spec Kit en un arnés degradado; con la bandera lo mantiene apagado.
|
|
559
|
-
const speckit = speckitBlock(context.manifest.speckit, !args.flags['no-speckit']);
|
|
583
|
+
const speckit = speckitBlock(context.manifest.speckit, !args.flags['no-speckit'], scriptFlag);
|
|
560
584
|
const speckitSettings = speckitSettingsFor(context.manifest.targets, speckit, context.engine);
|
|
561
585
|
const runSpeckit = speckitSettings.managed && !(await isEngineCheckout(ctx.root));
|
|
562
586
|
if (args.flags['dry-run']) {
|
|
@@ -575,7 +599,7 @@ export async function cmdInstall(args, ctx) {
|
|
|
575
599
|
}, null, 2));
|
|
576
600
|
return 0;
|
|
577
601
|
}
|
|
578
|
-
if (runSpeckit && !(await preflightOrReport(speckitSettings, ctx))) {
|
|
602
|
+
if (runSpeckit && !(await preflightOrReport(speckitSettings, ctx, 'install'))) {
|
|
579
603
|
return 2;
|
|
580
604
|
}
|
|
581
605
|
const backupId = runSpeckit ? (await createBackup(ctx.root, 'install')).id : null;
|
|
@@ -15,14 +15,31 @@ export interface SpeckitEnvironment {
|
|
|
15
15
|
shell: 'found' | 'missing';
|
|
16
16
|
shellCommand: string;
|
|
17
17
|
}
|
|
18
|
+
export interface ShellCandidate {
|
|
19
|
+
command: string;
|
|
20
|
+
args: string[];
|
|
21
|
+
}
|
|
18
22
|
/**
|
|
19
|
-
*
|
|
20
|
-
*
|
|
23
|
+
* Rutas estándar de Git for Windows (design D1), construidas desde el entorno del proceso;
|
|
24
|
+
* una variable ausente omite sus candidatos. Nunca hay rutas de usuario hardcodeadas.
|
|
25
|
+
*/
|
|
26
|
+
export declare function gitBashCandidates(env?: NodeJS.ProcessEnv): string[];
|
|
27
|
+
/**
|
|
28
|
+
* Candidatos del script declarado, en orden de preferencia. Para `sh` en Windows va primero el
|
|
29
|
+
* `bash` del PATH y después las rutas estándar de Git for Windows; en Linux y macOS sólo el del PATH.
|
|
21
30
|
*/
|
|
22
|
-
export declare function
|
|
31
|
+
export declare function shellCandidates(settings: SpeckitSettings, platform?: NodeJS.Platform, env?: NodeJS.ProcessEnv): ShellCandidate[];
|
|
32
|
+
export interface ShellProbe {
|
|
23
33
|
ok: boolean;
|
|
24
34
|
command: string;
|
|
25
|
-
|
|
35
|
+
/** Comandos probados en orden; las rutas absolutas inexistentes no se prueban. */
|
|
36
|
+
tried: string[];
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Ejecuta el shell en lugar de buscarlo en el PATH: en Windows `bash` puede ser el lanzador
|
|
40
|
+
* de WSL, que existe pero no ejecuta sin una distribución instalada.
|
|
41
|
+
*/
|
|
42
|
+
export declare function probeShell(settings: SpeckitSettings, runner: ProcessRunner, cwd: string, platform?: NodeJS.Platform, env?: NodeJS.ProcessEnv): Promise<ShellProbe>;
|
|
26
43
|
/** Sonda del entorno para el plan: describe la máquina y no entra en el hash. */
|
|
27
44
|
export declare function probeEnvironment(settings: SpeckitSettings, runner: ProcessRunner, cwd: string): Promise<SpeckitEnvironment>;
|
|
28
45
|
export interface PreflightResult {
|
|
@@ -32,8 +49,9 @@ export interface PreflightResult {
|
|
|
32
49
|
/**
|
|
33
50
|
* Preflight (design D3, paso 6). Se ejecuta antes de escribir cualquier archivo.
|
|
34
51
|
* Comprueba uv, la resolución de la versión fijada (caché o red) y el shell del script declarado.
|
|
52
|
+
* `command` nombra la bandera exacta en el mensaje; nunca se remite a un manifest que no existe.
|
|
35
53
|
*/
|
|
36
|
-
export declare function speckitPreflight(settings: SpeckitSettings, runner: ProcessRunner, cwd: string): Promise<PreflightResult>;
|
|
54
|
+
export declare function speckitPreflight(settings: SpeckitSettings, runner: ProcessRunner, cwd: string, command?: 'init' | 'install'): Promise<PreflightResult>;
|
|
37
55
|
export interface SpeckitRunResult {
|
|
38
56
|
ok: boolean;
|
|
39
57
|
steps: string[][];
|
package/dist/speckit/commands.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { existsSync } from 'node:fs';
|
|
1
3
|
import { TARGETS } from '../sync/targets.js';
|
|
2
4
|
import { succeeded } from './runner.js';
|
|
3
5
|
/** Argumentos de `uvx` que fijan el paquete y la fecha de resolución. */
|
|
@@ -42,27 +44,63 @@ export function speckitSequence(settings) {
|
|
|
42
44
|
}
|
|
43
45
|
return steps;
|
|
44
46
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
47
|
+
/**
|
|
48
|
+
* Rutas estándar de Git for Windows (design D1), construidas desde el entorno del proceso;
|
|
49
|
+
* una variable ausente omite sus candidatos. Nunca hay rutas de usuario hardcodeadas.
|
|
50
|
+
*/
|
|
51
|
+
export function gitBashCandidates(env = process.env) {
|
|
52
|
+
const candidates = [];
|
|
53
|
+
const programFiles = env['ProgramFiles'];
|
|
54
|
+
const programFilesX86 = env['ProgramFiles(x86)'];
|
|
55
|
+
const localAppData = env['LOCALAPPDATA'];
|
|
56
|
+
if (programFiles !== undefined) {
|
|
57
|
+
candidates.push(path.join(programFiles, 'Git', 'bin', 'bash.exe'));
|
|
58
|
+
}
|
|
59
|
+
if (programFilesX86 !== undefined) {
|
|
60
|
+
candidates.push(path.join(programFilesX86, 'Git', 'bin', 'bash.exe'));
|
|
61
|
+
}
|
|
62
|
+
if (localAppData !== undefined) {
|
|
63
|
+
candidates.push(path.join(localAppData, 'Programs', 'Git', 'bin', 'bash.exe'));
|
|
64
|
+
}
|
|
65
|
+
if (programFiles !== undefined) {
|
|
66
|
+
candidates.push(path.join(programFiles, 'Git', 'usr', 'bin', 'bash.exe'));
|
|
67
|
+
}
|
|
68
|
+
return candidates;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Candidatos del script declarado, en orden de preferencia. Para `sh` en Windows va primero el
|
|
72
|
+
* `bash` del PATH y después las rutas estándar de Git for Windows; en Linux y macOS sólo el del PATH.
|
|
73
|
+
*/
|
|
74
|
+
export function shellCandidates(settings, platform = process.platform, env = process.env) {
|
|
75
|
+
if (settings.script === 'ps') {
|
|
76
|
+
return [
|
|
48
77
|
{ command: 'pwsh', args: ['-NoProfile', '-Command', 'echo ok'] },
|
|
49
78
|
{ command: 'powershell', args: ['-NoProfile', '-Command', 'echo ok'] },
|
|
50
|
-
]
|
|
51
|
-
|
|
79
|
+
];
|
|
80
|
+
}
|
|
81
|
+
if (platform !== 'win32') {
|
|
82
|
+
return [{ command: 'bash', args: ['-c', 'echo ok'] }];
|
|
83
|
+
}
|
|
84
|
+
return [
|
|
85
|
+
{ command: 'bash', args: ['-c', 'echo ok'] },
|
|
86
|
+
...gitBashCandidates(env).map((command) => ({ command, args: ['-c', 'echo ok'] })),
|
|
87
|
+
];
|
|
52
88
|
}
|
|
53
89
|
/**
|
|
54
90
|
* Ejecuta el shell en lugar de buscarlo en el PATH: en Windows `bash` puede ser el lanzador
|
|
55
91
|
* de WSL, que existe pero no ejecuta sin una distribución instalada.
|
|
56
92
|
*/
|
|
57
|
-
export async function probeShell(settings, runner, cwd) {
|
|
58
|
-
const candidates = shellCandidates(settings);
|
|
93
|
+
export async function probeShell(settings, runner, cwd, platform = process.platform, env = process.env) {
|
|
94
|
+
const candidates = shellCandidates(settings, platform, env).filter((candidate) => !path.isAbsolute(candidate.command) || existsSync(candidate.command));
|
|
95
|
+
const tried = [];
|
|
59
96
|
for (const candidate of candidates) {
|
|
97
|
+
tried.push(candidate.command);
|
|
60
98
|
const result = await runner(candidate.command, candidate.args, { cwd, timeoutMs: 30_000 });
|
|
61
99
|
if (succeeded(result) && result.stdout.trim() === 'ok') {
|
|
62
|
-
return { ok: true, command: candidate.command };
|
|
100
|
+
return { ok: true, command: candidate.command, tried };
|
|
63
101
|
}
|
|
64
102
|
}
|
|
65
|
-
return { ok: false, command: candidates[0]
|
|
103
|
+
return { ok: false, command: candidates[0]?.command ?? 'bash', tried };
|
|
66
104
|
}
|
|
67
105
|
async function uvxAvailable(runner, cwd) {
|
|
68
106
|
return succeeded(await runner('uvx', ['--version'], { cwd, timeoutMs: 30_000 }));
|
|
@@ -86,8 +124,9 @@ export async function probeEnvironment(settings, runner, cwd) {
|
|
|
86
124
|
/**
|
|
87
125
|
* Preflight (design D3, paso 6). Se ejecuta antes de escribir cualquier archivo.
|
|
88
126
|
* Comprueba uv, la resolución de la versión fijada (caché o red) y el shell del script declarado.
|
|
127
|
+
* `command` nombra la bandera exacta en el mensaje; nunca se remite a un manifest que no existe.
|
|
89
128
|
*/
|
|
90
|
-
export async function speckitPreflight(settings, runner, cwd) {
|
|
129
|
+
export async function speckitPreflight(settings, runner, cwd, command = 'init') {
|
|
91
130
|
const problems = [];
|
|
92
131
|
if (!(await uvxAvailable(runner, cwd))) {
|
|
93
132
|
problems.push('uv no está disponible (uvx no está en el PATH). Instálalo: https://docs.astral.sh/uv/getting-started/installation/ ' +
|
|
@@ -103,10 +142,11 @@ export async function speckitPreflight(settings, runner, cwd) {
|
|
|
103
142
|
const shell = await probeShell(settings, runner, cwd);
|
|
104
143
|
if (!shell.ok) {
|
|
105
144
|
problems.push(settings.script === 'ps'
|
|
106
|
-
?
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
'
|
|
145
|
+
? `PowerShell no ejecuta \`echo ok\` (probados: ${shell.tried.join(', ')}). ` +
|
|
146
|
+
`Instala PowerShell (pwsh o powershell). Alternativa: ai-hub ${command} --script sh.`
|
|
147
|
+
: `ningún bash ejecuta \`bash -c "echo ok"\` (probados: ${shell.tried.join(', ')}). ` +
|
|
148
|
+
'En Windows instala Git for Windows (Git Bash); el lanzador de WSL sin distribución no sirve. ' +
|
|
149
|
+
`Alternativa sin bash: ai-hub ${command} --script ps.`);
|
|
110
150
|
}
|
|
111
151
|
return { ok: problems.length === 0, problems };
|
|
112
152
|
}
|
package/dist/speckit/doctor.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import type { EngineManifest } from '../engine/engine.js';
|
|
1
|
+
import type { EngineManifest, SpeckitScript } from '../engine/engine.js';
|
|
2
2
|
import type { ProjectManifest } from '../manifest/manifest.js';
|
|
3
|
+
import { type ShellProbe } from './commands.js';
|
|
3
4
|
import type { ProcessRunner } from './runner.js';
|
|
4
5
|
export interface SpeckitCheck {
|
|
5
6
|
id: string;
|
|
@@ -7,7 +8,9 @@ export interface SpeckitCheck {
|
|
|
7
8
|
detail: string;
|
|
8
9
|
}
|
|
9
10
|
/** Ids de los checks de Spec Kit, en el orden en que `doctor` los imprime. */
|
|
10
|
-
export declare const SPECKIT_CHECK_IDS: readonly ["speckit:managed", "speckit:installed", "speckit:version", "speckit:shell", "speckit:integrations", "speckit:extensions", "speckit:integrity", "speckit:collision", "speckit:constitution", "speckit:versioning"];
|
|
11
|
+
export declare const SPECKIT_CHECK_IDS: readonly ["speckit:managed", "speckit:installed", "speckit:version", "speckit:script", "speckit:shell", "speckit:integrations", "speckit:extensions", "speckit:integrity", "speckit:collision", "speckit:constitution", "speckit:versioning"];
|
|
12
|
+
/** Detalle del check `speckit:shell`: distingue el shell resuelto fuera del PATH del que está en el PATH. */
|
|
13
|
+
export declare function speckitShellDetail(probe: ShellProbe, script: SpeckitScript): string;
|
|
11
14
|
/** Checks de doctor para una instalación (dev-cli "Doctor verifies the Spec Kit installation"). */
|
|
12
15
|
export declare function speckitDoctorChecks(root: string, manifest: ProjectManifest, engine: EngineManifest, runner: ProcessRunner): Promise<SpeckitCheck[]>;
|
|
13
16
|
/** En el checkout del motor los checks de Spec Kit no aplican: su .specify/ es del mantenedor. */
|
package/dist/speckit/doctor.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { spawnSync } from 'node:child_process';
|
|
2
|
+
import path from 'node:path';
|
|
2
3
|
import { readLock } from '../sync/lock.js';
|
|
3
4
|
import { probeShell } from './commands.js';
|
|
4
5
|
import { effectiveSpeckit } from './settings.js';
|
|
@@ -8,6 +9,7 @@ export const SPECKIT_CHECK_IDS = [
|
|
|
8
9
|
'speckit:managed',
|
|
9
10
|
'speckit:installed',
|
|
10
11
|
'speckit:version',
|
|
12
|
+
'speckit:script',
|
|
11
13
|
'speckit:shell',
|
|
12
14
|
'speckit:integrations',
|
|
13
15
|
'speckit:extensions',
|
|
@@ -21,6 +23,17 @@ const VERSIONED_STATE = ['.specify/memory/constitution.md', '.specify/init-optio
|
|
|
21
23
|
function list(items, limit = 5) {
|
|
22
24
|
return items.slice(0, limit).join('; ') + (items.length > limit ? ` (+${items.length - limit})` : '');
|
|
23
25
|
}
|
|
26
|
+
/** Detalle del check `speckit:shell`: distingue el shell resuelto fuera del PATH del que está en el PATH. */
|
|
27
|
+
export function speckitShellDetail(probe, script) {
|
|
28
|
+
if (probe.ok) {
|
|
29
|
+
return path.isAbsolute(probe.command)
|
|
30
|
+
? `${probe.command} (resuelto fuera del PATH) ejecuta los scripts ${script}`
|
|
31
|
+
: `${probe.command} ejecuta los scripts ${script}`;
|
|
32
|
+
}
|
|
33
|
+
return script === 'ps'
|
|
34
|
+
? `PowerShell no ejecuta (probados: ${probe.tried.join(', ')}); instala PowerShell, o ejecuta ai-hub install --script sh`
|
|
35
|
+
: `bash no está disponible o no ejecuta (probados: ${probe.tried.join(', ')}); en Windows instala Git for Windows, o ejecuta ai-hub install --script ps`;
|
|
36
|
+
}
|
|
24
37
|
function gitIgnored(root, rel) {
|
|
25
38
|
const inside = spawnSync('git', ['rev-parse', '--is-inside-work-tree'], { cwd: root, encoding: 'utf8', shell: false });
|
|
26
39
|
if (inside.status !== 0 || (inside.stdout ?? '').trim() !== 'true') {
|
|
@@ -51,12 +64,15 @@ export async function speckitDoctorChecks(root, manifest, engine, runner) {
|
|
|
51
64
|
add('speckit:version', installed === settings.version, installed === settings.version
|
|
52
65
|
? `${installed}`
|
|
53
66
|
: `instalada ${installed ?? '(ninguna)'}; se esperaba ${settings.version}; ejecuta ai-hub install`);
|
|
67
|
+
// speckit:script (design D7): el manifest y la instalación deben declarar el mismo script.
|
|
68
|
+
const installedScript = state.initOptions?.script ?? null;
|
|
69
|
+
add('speckit:script', state.initOptions === null || installedScript === settings.script, state.initOptions === null
|
|
70
|
+
? 'no aplica: falta .specify/init-options.json'
|
|
71
|
+
: installedScript === settings.script
|
|
72
|
+
? `manifest e instalación coinciden: ${settings.script}`
|
|
73
|
+
: `desvío: manifest ${settings.script}, instalación ${installedScript}; ejecuta ai-hub install`);
|
|
54
74
|
const shell = await probeShell(settings, runner, root);
|
|
55
|
-
add('speckit:shell', shell.ok, shell.
|
|
56
|
-
? `${shell.command} ejecuta los scripts ${settings.script}`
|
|
57
|
-
: settings.script === 'ps'
|
|
58
|
-
? 'PowerShell (pwsh o powershell) no está disponible para los scripts ps'
|
|
59
|
-
: 'bash no está disponible o no ejecuta; en Windows instala Git Bash, o declara speckit.script: ps');
|
|
75
|
+
add('speckit:shell', shell.ok, speckitShellDetail(shell, settings.script));
|
|
60
76
|
const integrations = checkIntegrations(settings, state);
|
|
61
77
|
add('speckit:integrations', integrations.length === 0, integrations.length === 0
|
|
62
78
|
? `${settings.integrations.join(', ')} (por defecto ${settings.defaultIntegration ?? '-'})`
|