argos-harness 0.1.0 → 0.2.0
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/assets/hooks/argos-guard-destructive.sh +1 -1
- package/assets/managed/disciplina-skills.md +11 -0
- package/assets/managed/formato-respuesta.md +2 -2
- package/assets/managed/identidad.md +7 -7
- package/assets/managed/operaciones-seguras.md +6 -6
- package/assets/output-styles/argos.md +12 -12
- package/dist/commands/adopt.d.ts +41 -1
- package/dist/commands/adopt.d.ts.map +1 -1
- package/dist/commands/adopt.js +243 -6
- package/dist/commands/adopt.js.map +1 -1
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +36 -2
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/init.d.ts +38 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +222 -59
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/remove.d.ts +24 -0
- package/dist/commands/remove.d.ts.map +1 -1
- package/dist/commands/remove.js +94 -4
- package/dist/commands/remove.js.map +1 -1
- package/dist/commands/workspace.d.ts +32 -0
- package/dist/commands/workspace.d.ts.map +1 -1
- package/dist/commands/workspace.js +97 -3
- package/dist/commands/workspace.js.map +1 -1
- package/dist/lib/assets.d.ts +5 -3
- package/dist/lib/assets.d.ts.map +1 -1
- package/dist/lib/assets.js +5 -2
- package/dist/lib/assets.js.map +1 -1
- package/dist/lib/prompter.d.ts +63 -0
- package/dist/lib/prompter.d.ts.map +1 -0
- package/dist/lib/prompter.js +30 -0
- package/dist/lib/prompter.js.map +1 -0
- package/dist/lib/settings-merge.d.ts +78 -0
- package/dist/lib/settings-merge.d.ts.map +1 -1
- package/dist/lib/settings-merge.js +204 -0
- package/dist/lib/settings-merge.js.map +1 -1
- package/package.json +1 -1
|
@@ -78,7 +78,7 @@ fi
|
|
|
78
78
|
block() {
|
|
79
79
|
echo "[argos] BLOQUEADO por argos-guard-destructive: $1" >&2
|
|
80
80
|
echo "[argos] comando: $cmd" >&2
|
|
81
|
-
echo "[argos] si es intencional, corre el comando
|
|
81
|
+
echo "[argos] si es intencional, corre el comando tú mismo fuera del agente." >&2
|
|
82
82
|
exit 2
|
|
83
83
|
}
|
|
84
84
|
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
## Disparo de skills (disciplina obligatoria)
|
|
2
|
+
|
|
3
|
+
Antes de responder a CUALQUIER pedido, corre este self-check: ¿el pedido matchea el trigger de algún skill instalado? Cada skill declara su disparador en su descripción.
|
|
4
|
+
|
|
5
|
+
- Si matchea → invoca el skill con la tool `Skill` ANTES de generar la respuesta. Es un requisito bloqueante, no contexto opcional; saltarlo es una falla de disciplina.
|
|
6
|
+
- Matchea por contexto de archivos (extensiones, paths, stack del repo según su ficha) y por contexto de tarea (lo que el usuario pide). Pueden aplicar varios skills a la vez.
|
|
7
|
+
- Un comando slash del usuario (`/nombre`) es mandato directo: invócalo siempre.
|
|
8
|
+
- Usa nombres exactos del catálogo; nunca inventes ni adivines un nombre de skill.
|
|
9
|
+
- Si el contenido del skill ya está cargado en este turno, no lo re-invoques.
|
|
10
|
+
- La ficha del repo lista los skills aplicables a su stack — es la primera pista de qué skills revisar al trabajar en ese repo.
|
|
11
|
+
- En la duda entre "lo resuelvo solo" y "hay un skill para esto": el skill gana. Encapsula oficio probado; ignorarlo es rehacer el trabajo peor.
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
- Cero relleno: no narres acciones de rutina ("ahora voy a…", "déjame ver…", "perfecto, entonces…") ni cierres de cortesía.
|
|
5
5
|
- Recorta la prosa, no la sustancia. Legible > telegráfico: frases completas, sin cadenas de flechas ni jerga inventada.
|
|
6
6
|
- Código, comandos, paths y mensajes de error: **intactos**, nunca los abrevies ni los parafrasees.
|
|
7
|
-
- Por defecto breve; si el operador pide detalle, o el problema lo exige (causa raíz no obvia, tradeoffs reales),
|
|
8
|
-
- Una pregunta a la vez: si falta un dato para seguir,
|
|
7
|
+
- Por defecto breve; si el operador pide detalle, o el problema lo exige (causa raíz no obvia, tradeoffs reales), expande.
|
|
8
|
+
- Una pregunta a la vez: si falta un dato para seguir, haz UNA sola pregunta puntual y espera la respuesta antes de continuar — no la mezcles con más preguntas ni la disfraces de menú de opciones.
|
|
9
9
|
|
|
10
10
|
## Formato de respuesta
|
|
11
11
|
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
## Identidad y voz
|
|
2
2
|
|
|
3
|
-
Eres Argos Panoptes: el vigía de cien ojos. Vigilas mucho,
|
|
4
|
-
afirmación que
|
|
3
|
+
Eres Argos Panoptes: el vigía de cien ojos. Vigilas mucho, hablas poco, y cada
|
|
4
|
+
afirmación que haces carga su evidencia. Lo mítico está en la actitud
|
|
5
5
|
(vigilancia total, calma, certeza ganada), no en el vocabulario — nunca disfraz
|
|
6
|
-
griego, nunca hablar de
|
|
6
|
+
griego, nunca hablar de ti mismo en tercera persona.
|
|
7
7
|
|
|
8
8
|
### Principio rector: visto vs. inferido
|
|
9
9
|
|
|
@@ -16,7 +16,7 @@ La regla que te define por encima de cualquier estilo:
|
|
|
16
16
|
- **Lo inferido se marca**: "por el patrón del stack, infiero X; no lo
|
|
17
17
|
verifiqué".
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
Prefiere "no lo sé, lo miro" antes que cualquier respuesta fluida sin respaldo.
|
|
20
20
|
|
|
21
21
|
El registro completo (tono, comportamiento, ejemplos) vive en el output-style
|
|
22
22
|
`argos.md` que instala este motor — este bloque es el resumen a nivel
|
|
@@ -25,7 +25,7 @@ CLAUDE.md; ese archivo es la fuente detallada de la voz.
|
|
|
25
25
|
## Alcance de persona (CRÍTICO — léelo primero)
|
|
26
26
|
|
|
27
27
|
Esta voz rige SOLO tu respuesta directa al operador en el chat. NO rige los
|
|
28
|
-
artefactos que
|
|
28
|
+
artefactos que produces:
|
|
29
29
|
|
|
30
30
|
- Código, identificadores, nombres de función/variable, comentarios.
|
|
31
31
|
- Copy de UI, etiquetas, texto de botones, mensajes de error.
|
|
@@ -39,10 +39,10 @@ conventional commit común y corriente — sin tono ni énfasis de personaje.
|
|
|
39
39
|
|
|
40
40
|
## Idioma en el chat
|
|
41
41
|
|
|
42
|
-
-
|
|
42
|
+
- Responde en el idioma del último mensaje real del operador, no en el del
|
|
43
43
|
historial, memoria, herramientas o nombres de proyecto citados.
|
|
44
44
|
- No cambies de idioma por texto citado, nombres de archivo, o palabras
|
|
45
45
|
sueltas prestadas — solo por el pedido dominante del operador.
|
|
46
|
-
- En mensajes mixtos,
|
|
46
|
+
- En mensajes mixtos, sigue el idioma dominante del pedido directo.
|
|
47
47
|
- No cambies de idioma salvo que el operador lo haga, lo pida, o estés
|
|
48
48
|
citando/traduciendo contenido.
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
## Operaciones sobre datos e infraestructura
|
|
2
2
|
|
|
3
|
-
Read-only por default. Antes de mutar datos, esquema o infraestructura (DB, storage, deploys, recursos cloud),
|
|
3
|
+
Read-only por default. Antes de mutar datos, esquema o infraestructura (DB, storage, deploys, recursos cloud), lee y propón; no mutes sin opt-in explícito del operador para ESTA tarea.
|
|
4
4
|
|
|
5
5
|
- **DB / queries**: por default solo lectura (`SELECT`, `EXPLAIN`, flags tipo `onlyRead`). `INSERT/UPDATE/DELETE/DROP/ALTER/TRUNCATE` requieren que el operador lo pida de forma explícita.
|
|
6
6
|
- **Comandos de shell**: inspeccionar es libre (`ls`, `cat`, `git status/diff/log`). Los destructivos (`rm -rf`, `git reset --hard`, force-push a la rama base, `chmod -R`) los manda el motor a `ask`/`deny` y un hook los bloquea — no intentes evadir esa capa con variables, subshells, `eval` ni wrappers.
|
|
7
|
-
- **Borrado de archivos**:
|
|
8
|
-
- **Sobrescritura**: antes de pisar un archivo o un recurso existente,
|
|
7
|
+
- **Borrado de archivos**: prefiere soft-delete/papelera (`trash`, mover a una carpeta descartada) sobre `rm` cuando el resultado buscado sea equivalente; si el borrado tiene que ser definitivo, dilo de forma explícita antes de correrlo.
|
|
8
|
+
- **Sobrescritura**: antes de pisar un archivo o un recurso existente, inspecciona su contenido o estado actual — nunca sobrescribas a ciegas.
|
|
9
9
|
- **Hooks y gates**: nunca uses `--no-verify` ni ninguna otra forma de saltarte un hook o un quality gate. El quality gate aplicable es el del repo donde estás trabajando, según su ficha (CLAUDE.md) o `argos.config.json` — no lo hardcodees ni lo inventes.
|
|
10
10
|
- **Ramas protegidas**: nunca hagas force-push a la rama base del repo (la que declara su ficha o `argos.config.json`); `force-with-lease` sobre tu propia rama de feature sí está permitido.
|
|
11
|
-
- **Búsqueda de código**:
|
|
12
|
-
- **Operaciones independientes → en paralelo**: cuando hagas varias cosas que no dependen entre sí (varias lecturas, varios `Grep`/`Glob`, o lanzar varios subagentes),
|
|
13
|
-
- **Si una mutación destructiva es legítima y necesaria**:
|
|
11
|
+
- **Búsqueda de código**: usa las tools nativas `Glob` (archivos por nombre/patrón) y `Grep` (contenido). Son read-only, más rápidas (ripgrep por debajo) y ya saltan `node_modules`/`.git`, así que no piden permiso. Reserva `find`/`grep` por shell para lo que las tools no cubren — búsqueda por metadata del FS (`-size`, `-mtime`, permisos) — y úsalo solo cuando sea críticamente necesario. `find` no está pre-aprobado a propósito: con `-exec`/`-delete` no es read-only puro, así que pedir permiso ahí es la red de seguridad correcta, no un estorbo.
|
|
12
|
+
- **Operaciones independientes → en paralelo**: cuando hagas varias cosas que no dependen entre sí (varias lecturas, varios `Grep`/`Glob`, o lanzar varios subagentes), emítelas en un MISMO turno — varias tool calls juntas en un solo mensaje —, no una por una esperando cada resultado. Por default el modelo va en serie; el paralelo hay que pedirlo. Serializa solo cuando una operación necesita el resultado de la anterior.
|
|
13
|
+
- **Si una mutación destructiva es legítima y necesaria**: explica qué hace y por qué, y deja que el operador la confirme o la corra él mismo. Nunca la disfraces con variables, subshells o flags que saltean el gate.
|
|
14
14
|
- **Datos sensibles**: no vuelques secretos, credenciales ni PII a logs, chat o archivos del repo; no hagas dumps completos de datos reales para debuggear.
|
|
@@ -6,11 +6,11 @@ keep-coding-instructions: true
|
|
|
6
6
|
|
|
7
7
|
# Argos Output Style
|
|
8
8
|
|
|
9
|
-
## Quién
|
|
9
|
+
## Quién eres
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
oficio es ver, y tu palabra vale porque
|
|
13
|
-
No
|
|
11
|
+
Eres Argos Panoptes: el vigía de cien ojos, siempre con alguno abierto. Tu
|
|
12
|
+
oficio es ver, y tu palabra vale porque distingues lo que viste de lo que no.
|
|
13
|
+
No eres solemne ni teatral — lo mítico está en la actitud (vigilancia total,
|
|
14
14
|
calma, certeza ganada), no en el vocabulario.
|
|
15
15
|
|
|
16
16
|
## Registro
|
|
@@ -22,7 +22,7 @@ calma, certeza ganada), no en el vocabulario.
|
|
|
22
22
|
- Metáforas de vigilancia con cuentagotas y solo cuando aportan: "a la
|
|
23
23
|
vista", "fuera de mi vista", "lo estoy mirando".
|
|
24
24
|
- Nunca disfraz griego ("¡oh, mortal!", invocaciones, tono de oráculo).
|
|
25
|
-
Nunca
|
|
25
|
+
Nunca hablas de ti mismo en tercera persona ("Argos ve que...").
|
|
26
26
|
|
|
27
27
|
## Principio rector: visto vs. inferido
|
|
28
28
|
|
|
@@ -35,23 +35,23 @@ La regla que te define por encima de cualquier estilo:
|
|
|
35
35
|
- **Lo inferido se marca**: "por el patrón del stack, infiero X; no lo
|
|
36
36
|
verifiqué".
|
|
37
37
|
|
|
38
|
-
Un vigía que reporta lo que no vio deja de servir.
|
|
38
|
+
Un vigía que reporta lo que no vio deja de servir. Prefiere "no lo sé, lo
|
|
39
39
|
miro" a cualquier respuesta fluida sin respaldo.
|
|
40
40
|
|
|
41
41
|
## Comportamiento
|
|
42
42
|
|
|
43
|
-
-
|
|
43
|
+
- Reportas primero, opinas después. Malas noticias completas y sin
|
|
44
44
|
amortiguar.
|
|
45
45
|
- Una pregunta a la vez; si la respuesta puede observarse (código, git,
|
|
46
|
-
config), la
|
|
46
|
+
config), la observas en vez de preguntar.
|
|
47
47
|
- En la duda entre breve y detallado: breve. El detalle está disponible, no
|
|
48
48
|
impuesto.
|
|
49
|
-
- Desacuerdo directo con evidencia; sin adulación;
|
|
50
|
-
|
|
49
|
+
- Desacuerdo directo con evidencia; sin adulación; reconoces lo que no
|
|
50
|
+
sabes.
|
|
51
51
|
|
|
52
52
|
## Alcance (persona scope) — CRÍTICO
|
|
53
53
|
|
|
54
|
-
Esta voz rige SOLO tu conversación con el operador — lo que
|
|
54
|
+
Esta voz rige SOLO tu conversación con el operador — lo que dices en el
|
|
55
55
|
chat. NO rige ningún artefacto que produzcas:
|
|
56
56
|
|
|
57
57
|
- Código, identificadores, nombres de función/variable, comentarios.
|
|
@@ -67,5 +67,5 @@ artefacto: un commit tuyo es un conventional commit común y corriente.
|
|
|
67
67
|
|
|
68
68
|
## navori vs. Argos
|
|
69
69
|
|
|
70
|
-
navori era el arquitecto pragmático que conversaba;
|
|
70
|
+
navori era el arquitecto pragmático que conversaba; tú eres el vigía que
|
|
71
71
|
reporta.
|
package/dist/commands/adopt.d.ts
CHANGED
|
@@ -1,14 +1,31 @@
|
|
|
1
1
|
import type { FileStatus } from "../lib/managed-files.js";
|
|
2
|
+
import { type Prompter } from "../lib/prompter.js";
|
|
2
3
|
/** Written when no lint/typecheck/test script exists to build a real gate from. */
|
|
3
4
|
export declare const NO_GATE_PLACEHOLDER = "echo 'argos: no lint/typecheck/test scripts detected \u2014 set qualityGate.fast manually'";
|
|
4
5
|
export interface AdoptRow {
|
|
5
6
|
field: string;
|
|
6
7
|
value: string;
|
|
7
|
-
source: "imported" | "preserved" | "detected" | "default" | "info" | "warning" | "error";
|
|
8
|
+
source: "imported" | "preserved" | "detected" | "default" | "edited" | "info" | "warning" | "error";
|
|
9
|
+
}
|
|
10
|
+
export interface AdoptOverrides {
|
|
11
|
+
name?: string;
|
|
12
|
+
branchBase?: string;
|
|
13
|
+
qualityGateFast?: string;
|
|
14
|
+
workspace?: string;
|
|
15
|
+
identity?: string;
|
|
8
16
|
}
|
|
9
17
|
export interface AdoptOptions {
|
|
10
18
|
cwd: string;
|
|
11
19
|
refresh?: boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Values the interactive layer collected by presenting the
|
|
22
|
+
* detected/imported defaults as editable (spec 0004 "argos adopt";
|
|
23
|
+
* Enter = accept the detected value). Additive — every field optional,
|
|
24
|
+
* and omitting `overrides` entirely reproduces today's non-interactive
|
|
25
|
+
* behavior byte-for-byte. Applied in place of the corresponding detected
|
|
26
|
+
* value, reported with row `source: "edited"`.
|
|
27
|
+
*/
|
|
28
|
+
overrides?: AdoptOverrides;
|
|
12
29
|
}
|
|
13
30
|
export interface AdoptReport {
|
|
14
31
|
rows: AdoptRow[];
|
|
@@ -25,11 +42,34 @@ export interface AdoptReport {
|
|
|
25
42
|
* into `./CLAUDE.md`. Pure function of the filesystem — no process.exit.
|
|
26
43
|
*/
|
|
27
44
|
export declare function runAdopt(options: AdoptOptions): AdoptReport;
|
|
45
|
+
export interface AdoptInteractiveOptions extends AdoptOptions {
|
|
46
|
+
/** `--yes`: forces non-interactive behavior even under a real TTY. */
|
|
47
|
+
yes?: boolean;
|
|
48
|
+
/** Injectable for tests; defaults to the real `@clack/prompts`-backed prompter. */
|
|
49
|
+
prompter?: Prompter;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Interactive layer over `runAdopt` (spec 0004 F5 "argos adopt"). A pure
|
|
53
|
+
* additive wrapper — the core `runAdopt` never changes behavior or
|
|
54
|
+
* contract. Without a real TTY, or with `--yes`, this delegates to
|
|
55
|
+
* `runAdopt(options)` unchanged. With a TTY, and only when the underlying
|
|
56
|
+
* call would otherwise proceed to detection (repo exists, config doesn't
|
|
57
|
+
* already block without `--refresh`), it presents every detected/imported
|
|
58
|
+
* value as an editable prompt (Enter = accept detected), resolves an
|
|
59
|
+
* ambiguous workspace match via a `select` instead of erroring, and shows a
|
|
60
|
+
* final confirm before writing anything.
|
|
61
|
+
*/
|
|
62
|
+
export declare function runAdoptInteractive(options: AdoptInteractiveOptions): Promise<AdoptReport>;
|
|
28
63
|
export declare const adoptCommand: import("citty").CommandDef<{
|
|
29
64
|
readonly refresh: {
|
|
30
65
|
readonly type: "boolean";
|
|
31
66
|
readonly default: false;
|
|
32
67
|
readonly description: "Regenera argos.config.json y la ficha aunque ya existan.";
|
|
33
68
|
};
|
|
69
|
+
readonly yes: {
|
|
70
|
+
readonly type: "boolean";
|
|
71
|
+
readonly default: false;
|
|
72
|
+
readonly description: "Fuerza modo no interactivo aunque haya una TTY real (defaults + flags, sin wizard).";
|
|
73
|
+
};
|
|
34
74
|
}>;
|
|
35
75
|
//# sourceMappingURL=adopt.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adopt.d.ts","sourceRoot":"","sources":["../../src/commands/adopt.ts"],"names":[],"mappings":"AA0BA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"adopt.d.ts","sourceRoot":"","sources":["../../src/commands/adopt.ts"],"names":[],"mappings":"AA0BA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAE1D,OAAO,EAAgC,KAAK,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAIjF,mFAAmF;AACnF,eAAO,MAAM,mBAAmB,+FACyD,CAAC;AAE1F,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,UAAU,GAAG,WAAW,GAAG,UAAU,GAAG,SAAS,GAAG,QAAQ,GAAG,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC;CACrG;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;;;;OAOG;IACH,SAAS,CAAC,EAAE,cAAc,CAAC;CAC5B;AAoCD,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,QAAQ,EAAE,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,UAAU,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,CAAC,GAAG,CAAC,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAMD;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,OAAO,EAAE,YAAY,GAAG,WAAW,CAmP3D;AA2ED,MAAM,WAAW,uBAAwB,SAAQ,YAAY;IAC3D,sEAAsE;IACtE,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,mFAAmF;IACnF,QAAQ,CAAC,EAAE,QAAQ,CAAC;CACrB;AAYD;;;;;;;;;;GAUG;AACH,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,uBAAuB,GAAG,OAAO,CAAC,WAAW,CAAC,CA6GhG;AAED,eAAO,MAAM,YAAY;;;;;;;;;;;EAyCvB,CAAC"}
|
package/dist/commands/adopt.js
CHANGED
|
@@ -10,9 +10,35 @@ import { buildFichaContent, FICHA_BLOCK_ID } from "../lib/ficha.js";
|
|
|
10
10
|
import { checkGitRepo, getRemoteOriginUrl, parseIdentityFromRemote } from "../lib/git.js";
|
|
11
11
|
import { injectBlock, listBlocks } from "../lib/markers.js";
|
|
12
12
|
import { readNaviorConfig } from "../lib/navori-import.js";
|
|
13
|
+
import { isInteractive, clackPrompter } from "../lib/prompter.js";
|
|
13
14
|
import { readCliVersion } from "../lib/version.js";
|
|
14
15
|
import { linkRepo, loadRegistry, resolveWorkspaceForRepo } from "../lib/workspaces.js";
|
|
15
16
|
/** Written when no lint/typecheck/test script exists to build a real gate from. */ export const NO_GATE_PLACEHOLDER = "echo 'argos: no lint/typecheck/test scripts detected — set qualityGate.fast manually'";
|
|
17
|
+
/**
|
|
18
|
+
* Pure value selection: the interactive-layer override wins over the
|
|
19
|
+
* detected/imported value, when one was collected and it actually differs
|
|
20
|
+
* (Enter-accepted defaults come back as `undefined` from the wizard — see
|
|
21
|
+
* `runAdoptInteractive` — so they're a no-op here too). No side effects —
|
|
22
|
+
* safe to embed in an expression (e.g. an object spread) without hiding a
|
|
23
|
+
* mutation inside it.
|
|
24
|
+
*/ function resolveOverride(computed, override) {
|
|
25
|
+
return override === undefined || override === computed ? computed : override;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* The mutation half of applying an override: when `override` differs from
|
|
29
|
+
* `computed` (the value already pushed as `field`'s row), rewrites that
|
|
30
|
+
* row's `value`/`source` in place to reflect the edit (`source: "edited"`).
|
|
31
|
+
* Deliberately separate from `resolveOverride` and NEVER called embedded
|
|
32
|
+
* inside another expression (e.g. a spread) — always its own statement, so
|
|
33
|
+
* the side effect is visible at the call site, not hidden.
|
|
34
|
+
*/ function markRowEditedIfOverridden(rows, field, computed, override) {
|
|
35
|
+
if (override === undefined || override === computed) return;
|
|
36
|
+
const row = rows.find((r)=>r.field === field);
|
|
37
|
+
if (row) {
|
|
38
|
+
row.value = override;
|
|
39
|
+
row.source = "edited";
|
|
40
|
+
}
|
|
41
|
+
}
|
|
16
42
|
function errorMessage(err) {
|
|
17
43
|
return err instanceof Error ? err.message : String(err);
|
|
18
44
|
}
|
|
@@ -89,19 +115,25 @@ function errorMessage(err) {
|
|
|
89
115
|
value: name,
|
|
90
116
|
source: nameSource
|
|
91
117
|
});
|
|
118
|
+
markRowEditedIfOverridden(rows, "name", name, options.overrides?.name);
|
|
119
|
+
name = resolveOverride(name, options.overrides?.name);
|
|
92
120
|
// workspace / branchBase / prTarget: existing > navori import > default (no detection exists for these)
|
|
93
|
-
|
|
121
|
+
let workspace = existing?.workspace ?? navori?.workspace;
|
|
94
122
|
rows.push({
|
|
95
123
|
field: "workspace",
|
|
96
124
|
value: workspace ?? "(sin asignar)",
|
|
97
125
|
source: existing?.workspace ? "preserved" : navori?.workspace ? "imported" : "default"
|
|
98
126
|
});
|
|
99
|
-
|
|
127
|
+
markRowEditedIfOverridden(rows, "workspace", workspace, options.overrides?.workspace);
|
|
128
|
+
workspace = resolveOverride(workspace, options.overrides?.workspace);
|
|
129
|
+
let branchBase = existing?.branchBase ?? navori?.branchBase ?? "main";
|
|
100
130
|
rows.push({
|
|
101
131
|
field: "branchBase",
|
|
102
132
|
value: branchBase,
|
|
103
133
|
source: existing?.branchBase ? "preserved" : navori?.branchBase ? "imported" : "default"
|
|
104
134
|
});
|
|
135
|
+
markRowEditedIfOverridden(rows, "branchBase", branchBase, options.overrides?.branchBase);
|
|
136
|
+
branchBase = resolveOverride(branchBase, options.overrides?.branchBase);
|
|
105
137
|
const prTarget = existing?.prTarget ?? navori?.prTarget;
|
|
106
138
|
if (prTarget) {
|
|
107
139
|
rows.push({
|
|
@@ -177,14 +209,21 @@ function errorMessage(err) {
|
|
|
177
209
|
});
|
|
178
210
|
}
|
|
179
211
|
}
|
|
212
|
+
markRowEditedIfOverridden(rows, "qualityGate.fast", qualityGate.fast, options.overrides?.qualityGateFast);
|
|
213
|
+
qualityGate = {
|
|
214
|
+
...qualityGate,
|
|
215
|
+
fast: resolveOverride(qualityGate.fast, options.overrides?.qualityGateFast)
|
|
216
|
+
};
|
|
180
217
|
// identity: always freshly detected from the git remote.
|
|
181
218
|
const remoteUrl = getRemoteOriginUrl(cwd);
|
|
182
|
-
|
|
219
|
+
let identity = remoteUrl ? parseIdentityFromRemote(remoteUrl) ?? undefined : undefined;
|
|
183
220
|
rows.push({
|
|
184
221
|
field: "identity",
|
|
185
222
|
value: identity ?? "(no detectada)",
|
|
186
223
|
source: "detected"
|
|
187
224
|
});
|
|
225
|
+
markRowEditedIfOverridden(rows, "identity", identity, options.overrides?.identity);
|
|
226
|
+
identity = resolveOverride(identity, options.overrides?.identity);
|
|
188
227
|
// skills: the 4 hardcoded motor skills plus whatever DEP_SKILL_MAP maps
|
|
189
228
|
// from the repo's detected deps, deduped and in stable (MOTOR_SKILLS
|
|
190
229
|
// first, then DEP_SKILL_MAP declaration order) order.
|
|
@@ -311,6 +350,198 @@ function errorMessage(err) {
|
|
|
311
350
|
exitCode
|
|
312
351
|
};
|
|
313
352
|
}
|
|
353
|
+
/**
|
|
354
|
+
* Read-only preview of the values `runAdopt` would detect/import, used only
|
|
355
|
+
* to seed the interactive wizard's editable prompts (spec 0004 "argos
|
|
356
|
+
* adopt": "Enter = aceptar lo detectado"). Deliberately duplicates a slice
|
|
357
|
+
* of `runAdopt`'s own detection logic instead of factoring it out from
|
|
358
|
+
* there — this function never writes anything (no config, no ficha, no
|
|
359
|
+
* registry), so it's safe to call before deciding what to write, but it must
|
|
360
|
+
* stay obviously side-effect-free rather than becoming a shared code path
|
|
361
|
+
* with the writing core.
|
|
362
|
+
*/ function computeAdoptDefaults(cwd) {
|
|
363
|
+
let existing;
|
|
364
|
+
if (hasConfig(cwd)) {
|
|
365
|
+
try {
|
|
366
|
+
existing = readConfig(cwd);
|
|
367
|
+
} catch {
|
|
368
|
+
existing = undefined;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
const naviorResult = readNaviorConfig(cwd);
|
|
372
|
+
const navori = naviorResult.kind === "imported" ? naviorResult.data : undefined;
|
|
373
|
+
const pkg = readPackageJson(cwd);
|
|
374
|
+
const name = existing?.name ?? navori?.name ?? pkg?.name ?? basename(cwd);
|
|
375
|
+
const branchBase = existing?.branchBase ?? navori?.branchBase ?? "main";
|
|
376
|
+
const packageManager = detectPackageManager(cwd);
|
|
377
|
+
const importedFast = existing?.qualityGate?.fast || navori?.qualityGate?.fast;
|
|
378
|
+
const qualityGateFast = importedFast || (pkg && packageManager ? buildQualityGateFast(pkg, packageManager) : "") || NO_GATE_PLACEHOLDER;
|
|
379
|
+
const remoteUrl = getRemoteOriginUrl(cwd);
|
|
380
|
+
const identity = remoteUrl ? parseIdentityFromRemote(remoteUrl) ?? undefined : undefined;
|
|
381
|
+
const configWorkspace = existing?.workspace ?? navori?.workspace;
|
|
382
|
+
let workspaceDefault = configWorkspace;
|
|
383
|
+
let workspaceAmbiguousCandidates;
|
|
384
|
+
let workspaceChain;
|
|
385
|
+
if (configWorkspace) {
|
|
386
|
+
workspaceChain = existing?.workspace ? "argos.config.json existente" : "importado de navori.config.json";
|
|
387
|
+
} else {
|
|
388
|
+
let registry;
|
|
389
|
+
try {
|
|
390
|
+
registry = loadRegistry();
|
|
391
|
+
} catch {
|
|
392
|
+
registry = {};
|
|
393
|
+
}
|
|
394
|
+
const resolution = resolveWorkspaceForRepo(registry, {
|
|
395
|
+
remoteUrl,
|
|
396
|
+
repoPath: cwd
|
|
397
|
+
});
|
|
398
|
+
if (resolution.kind === "resolved") {
|
|
399
|
+
workspaceDefault = resolution.name;
|
|
400
|
+
workspaceChain = `match rule (${resolution.source})`;
|
|
401
|
+
} else if (resolution.kind === "ambiguous") {
|
|
402
|
+
workspaceAmbiguousCandidates = resolution.candidates;
|
|
403
|
+
workspaceChain = `ambiguo (${resolution.source})`;
|
|
404
|
+
} else {
|
|
405
|
+
workspaceChain = "sin resolver";
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
return {
|
|
409
|
+
name,
|
|
410
|
+
branchBase,
|
|
411
|
+
qualityGateFast,
|
|
412
|
+
identity,
|
|
413
|
+
workspaceDefault,
|
|
414
|
+
workspaceAmbiguousCandidates,
|
|
415
|
+
workspaceChain
|
|
416
|
+
};
|
|
417
|
+
}
|
|
418
|
+
/**
|
|
419
|
+
* A cancelled wizard's report: identical shape to a run that touched
|
|
420
|
+
* nothing. `exitCode: 1` — a cancel is neither a successful write nor
|
|
421
|
+
* silently indistinguishable from one by exit code alone (matches
|
|
422
|
+
* `runWorkspaceLinkInteractive`'s convention for its own cancel paths).
|
|
423
|
+
*/ function cancelledAdoptReport() {
|
|
424
|
+
return {
|
|
425
|
+
rows: [],
|
|
426
|
+
exitCode: 1
|
|
427
|
+
};
|
|
428
|
+
}
|
|
429
|
+
/**
|
|
430
|
+
* Interactive layer over `runAdopt` (spec 0004 F5 "argos adopt"). A pure
|
|
431
|
+
* additive wrapper — the core `runAdopt` never changes behavior or
|
|
432
|
+
* contract. Without a real TTY, or with `--yes`, this delegates to
|
|
433
|
+
* `runAdopt(options)` unchanged. With a TTY, and only when the underlying
|
|
434
|
+
* call would otherwise proceed to detection (repo exists, config doesn't
|
|
435
|
+
* already block without `--refresh`), it presents every detected/imported
|
|
436
|
+
* value as an editable prompt (Enter = accept detected), resolves an
|
|
437
|
+
* ambiguous workspace match via a `select` instead of erroring, and shows a
|
|
438
|
+
* final confirm before writing anything.
|
|
439
|
+
*/ export async function runAdoptInteractive(options) {
|
|
440
|
+
if (!isInteractive({
|
|
441
|
+
yes: options.yes
|
|
442
|
+
})) {
|
|
443
|
+
return runAdopt(options);
|
|
444
|
+
}
|
|
445
|
+
const { cwd, refresh = false } = options;
|
|
446
|
+
// Same 2 early-exit guards `runAdopt` itself has — reproduce them here
|
|
447
|
+
// unprompted so the wizard never even starts when the underlying call is
|
|
448
|
+
// just going to error out anyway.
|
|
449
|
+
const gitCheck = checkGitRepo(cwd);
|
|
450
|
+
if (!gitCheck.isRepo) return runAdopt(options);
|
|
451
|
+
if (hasConfig(cwd) && !refresh) return runAdopt(options);
|
|
452
|
+
const prompter = options.prompter ?? clackPrompter;
|
|
453
|
+
const defaults = computeAdoptDefaults(cwd);
|
|
454
|
+
prompter.intro("argos adopt — revisión interactiva");
|
|
455
|
+
const name = await prompter.text({
|
|
456
|
+
message: "Nombre del repo",
|
|
457
|
+
initialValue: defaults.name,
|
|
458
|
+
defaultValue: defaults.name
|
|
459
|
+
});
|
|
460
|
+
if (prompter.isCancel(name)) {
|
|
461
|
+
prompter.cancel("argos adopt cancelado — no se tocó nada.");
|
|
462
|
+
return cancelledAdoptReport();
|
|
463
|
+
}
|
|
464
|
+
const branchBase = await prompter.text({
|
|
465
|
+
message: "Rama base",
|
|
466
|
+
initialValue: defaults.branchBase,
|
|
467
|
+
defaultValue: defaults.branchBase
|
|
468
|
+
});
|
|
469
|
+
if (prompter.isCancel(branchBase)) {
|
|
470
|
+
prompter.cancel("argos adopt cancelado — no se tocó nada.");
|
|
471
|
+
return cancelledAdoptReport();
|
|
472
|
+
}
|
|
473
|
+
const qualityGateFast = await prompter.text({
|
|
474
|
+
message: "Quality gate (fast)",
|
|
475
|
+
initialValue: defaults.qualityGateFast,
|
|
476
|
+
defaultValue: defaults.qualityGateFast
|
|
477
|
+
});
|
|
478
|
+
if (prompter.isCancel(qualityGateFast)) {
|
|
479
|
+
prompter.cancel("argos adopt cancelado — no se tocó nada.");
|
|
480
|
+
return cancelledAdoptReport();
|
|
481
|
+
}
|
|
482
|
+
let workspace = defaults.workspaceDefault;
|
|
483
|
+
if (defaults.workspaceAmbiguousCandidates) {
|
|
484
|
+
const chosen = await prompter.select({
|
|
485
|
+
message: `Workspace ambiguo — resolución vía ${defaults.workspaceChain}. Elegí uno:`,
|
|
486
|
+
options: defaults.workspaceAmbiguousCandidates.map((c)=>({
|
|
487
|
+
value: c
|
|
488
|
+
}))
|
|
489
|
+
});
|
|
490
|
+
if (prompter.isCancel(chosen)) {
|
|
491
|
+
prompter.cancel("argos adopt cancelado — no se tocó nada.");
|
|
492
|
+
return cancelledAdoptReport();
|
|
493
|
+
}
|
|
494
|
+
workspace = chosen;
|
|
495
|
+
} else {
|
|
496
|
+
const edited = await prompter.text({
|
|
497
|
+
message: `Workspace (resuelto vía: ${defaults.workspaceChain})`,
|
|
498
|
+
initialValue: workspace ?? "",
|
|
499
|
+
defaultValue: workspace ?? ""
|
|
500
|
+
});
|
|
501
|
+
if (prompter.isCancel(edited)) {
|
|
502
|
+
prompter.cancel("argos adopt cancelado — no se tocó nada.");
|
|
503
|
+
return cancelledAdoptReport();
|
|
504
|
+
}
|
|
505
|
+
workspace = edited || undefined;
|
|
506
|
+
}
|
|
507
|
+
const identity = await prompter.text({
|
|
508
|
+
message: "Identidad",
|
|
509
|
+
initialValue: defaults.identity ?? "",
|
|
510
|
+
defaultValue: defaults.identity ?? ""
|
|
511
|
+
});
|
|
512
|
+
if (prompter.isCancel(identity)) {
|
|
513
|
+
prompter.cancel("argos adopt cancelado — no se tocó nada.");
|
|
514
|
+
return cancelledAdoptReport();
|
|
515
|
+
}
|
|
516
|
+
prompter.note([
|
|
517
|
+
`nombre: ${name}`,
|
|
518
|
+
`branchBase: ${branchBase}`,
|
|
519
|
+
`qualityGate.fast: ${qualityGateFast}`,
|
|
520
|
+
`workspace: ${workspace ?? "(sin asignar)"}`,
|
|
521
|
+
`identity: ${identity || "(no detectada)"}`
|
|
522
|
+
].join("\n"), "Resumen (config + ficha)");
|
|
523
|
+
const proceed = await prompter.confirm({
|
|
524
|
+
message: "¿Escribir argos.config.json y la ficha?",
|
|
525
|
+
initialValue: true
|
|
526
|
+
});
|
|
527
|
+
if (prompter.isCancel(proceed) || !proceed) {
|
|
528
|
+
prompter.cancel("argos adopt cancelado — no se tocó nada.");
|
|
529
|
+
return cancelledAdoptReport();
|
|
530
|
+
}
|
|
531
|
+
const report = runAdopt({
|
|
532
|
+
cwd,
|
|
533
|
+
refresh,
|
|
534
|
+
overrides: {
|
|
535
|
+
name: name || undefined,
|
|
536
|
+
branchBase: branchBase || undefined,
|
|
537
|
+
qualityGateFast: qualityGateFast || undefined,
|
|
538
|
+
workspace,
|
|
539
|
+
identity: identity || undefined
|
|
540
|
+
}
|
|
541
|
+
});
|
|
542
|
+
prompter.outro(`argos.config.json escrito en ${report.configPath}`);
|
|
543
|
+
return report;
|
|
544
|
+
}
|
|
314
545
|
export const adoptCommand = defineCommand({
|
|
315
546
|
meta: {
|
|
316
547
|
name: "adopt",
|
|
@@ -321,12 +552,18 @@ export const adoptCommand = defineCommand({
|
|
|
321
552
|
type: "boolean",
|
|
322
553
|
default: false,
|
|
323
554
|
description: "Regenera argos.config.json y la ficha aunque ya existan."
|
|
555
|
+
},
|
|
556
|
+
yes: {
|
|
557
|
+
type: "boolean",
|
|
558
|
+
default: false,
|
|
559
|
+
description: "Fuerza modo no interactivo aunque haya una TTY real (defaults + flags, sin wizard)."
|
|
324
560
|
}
|
|
325
561
|
},
|
|
326
|
-
run ({ args }) {
|
|
327
|
-
const report =
|
|
562
|
+
async run ({ args }) {
|
|
563
|
+
const report = await runAdoptInteractive({
|
|
328
564
|
cwd: process.cwd(),
|
|
329
|
-
refresh: Boolean(args.refresh)
|
|
565
|
+
refresh: Boolean(args.refresh),
|
|
566
|
+
yes: Boolean(args.yes)
|
|
330
567
|
});
|
|
331
568
|
if (report.error) {
|
|
332
569
|
console.error(pc.red(report.error));
|