@ancleto/spec 0.6.32 → 0.6.34
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 +36 -3
- package/agents/documenter.md +1 -1
- package/agents/orchestrator.md +15 -4
- package/agents/spec-writer.md +3 -3
- package/agents/technical-discovery.md +4 -3
- package/package.json +1 -1
- package/skills/ancleto-archive/SKILL.md +4 -3
- package/skills/ancleto-bulk-archive/SKILL.md +1 -1
- package/skills/ancleto-continue/SKILL.md +1 -1
- package/skills/ancleto-explore/SKILL.md +1 -1
- package/skills/ancleto-ff/SKILL.md +1 -1
- package/skills/ancleto-new/SKILL.md +1 -1
- package/skills/ancleto-onboard/SKILL.md +1 -1
- package/skills/ancleto-propose/SKILL.md +1 -1
- package/skills/ancleto-sync-specs/SKILL.md +1 -1
- package/skills/ancleto-technical-discovery/SKILL.md +2 -1
- package/skills/ancleto-upgrade/SKILL.md +1 -1
- package/src/cli/index.js +187 -19
- package/templates/AGENTS.md +6 -2
package/README.md
CHANGED
|
@@ -178,7 +178,7 @@ El registro es tuyo y local: no viaja con el repo ni se comparte. `ANCLETO_PROJE
|
|
|
178
178
|
En la primera ejecución, un **wizard interactivo** te guía por los pasos de configuración (agente/IDE y nivel de gasto). También podés pasarlos por flags:
|
|
179
179
|
|
|
180
180
|
```bash
|
|
181
|
-
ancleto init --agent opencode --tier normal
|
|
181
|
+
ancleto init --agent opencode --tier normal --lang es
|
|
182
182
|
```
|
|
183
183
|
|
|
184
184
|
| Tier | Qué hace |
|
|
@@ -189,6 +189,39 @@ ancleto init --agent opencode --tier normal
|
|
|
189
189
|
|
|
190
190
|
La configuración se preserva en `.ancletorc` (raíz del proyecto) y `.ancleto-tier` (junto a la configuración instalada).
|
|
191
191
|
|
|
192
|
+
### Idioma de los artifacts
|
|
193
|
+
|
|
194
|
+
El contenido de `proposal.md`, `design.md`, `tasks.md` y `specs/` se escribe en el idioma de tu conversación (`auto`, el default) o en el código que fijes con `--lang`:
|
|
195
|
+
|
|
196
|
+
```bash
|
|
197
|
+
ancleto init --lang auto # detecta el idioma de tus primeros mensajes y lo guarda
|
|
198
|
+
ancleto init --lang es # fija español para ese proyecto
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Con `auto`, el orquestador detecta el idioma en tus primeros hasta 3 mensajes y lo persiste en `.ancletorc` → `language`. Podés volver a `auto` o fijar otro código cuando quieras (`auto | es | en | pt`). Lo que **nunca** se traduce: los keywords (`Requirement`, `Scenario`, `SHALL`, `WHEN`/`THEN`/`AND`) y los nombres de archivos y directorios.
|
|
202
|
+
|
|
203
|
+
### Exclusiones del discovery
|
|
204
|
+
|
|
205
|
+
En la instalación interactiva elegís qué excluir del seed técnico con un menú (tests, assets pesados, docs, migraciones/seeds, lockfiles). Excluir reduce el tamaño del pack y estabiliza la detección de cambios:
|
|
206
|
+
|
|
207
|
+
```bash
|
|
208
|
+
ancleto init --exclude "**/*.test.*,**/*.png,docs" # sin menú, directo
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
Se guarda en `.ancletorc` → `discovery.exclude` y se preserva en `update`/`upgrade`.
|
|
212
|
+
|
|
213
|
+
### Frescura del seed (impact)
|
|
214
|
+
|
|
215
|
+
`ancleto discovery --check` no solo dice si el seed está `STALE`: dice **qué tan grave** es el cambio con `impact`:
|
|
216
|
+
|
|
217
|
+
| `impact` | Significado | Qué pasa |
|
|
218
|
+
|---|---|---|
|
|
219
|
+
| `none` | Sin cambios | El agente trabaja normal |
|
|
220
|
+
| `minor` | Cambios fuera de áreas materiales (un componente, un estilo) | El agente trabaja y lo anota en el resumen; **no ofrece regenerar** |
|
|
221
|
+
| `material` | Cambió un config de runtime, un entry point o apareció un directorio raíz nuevo | El agente **ofrece regenerar** (solo con tu aprobación) |
|
|
222
|
+
|
|
223
|
+
La excepción: si el agente detecta un **hueco concreto** (info que el seed debería tener y no tiene, como una paleta nueva sin unidad), puede ofrecer regenerar aunque el `impact` sea `minor` — siempre con tu aprobación. Nunca regenera solo.
|
|
224
|
+
|
|
192
225
|
---
|
|
193
226
|
|
|
194
227
|
## Uso rápido
|
|
@@ -226,10 +259,10 @@ ancleto discovery # Genera .discovery-map.json y empaqueta el repo
|
|
|
226
259
|
## Referencia de comandos CLI
|
|
227
260
|
|
|
228
261
|
```bash
|
|
229
|
-
ancleto init [--agent <nombre>] [--tier <nivel>] [--with-azure]
|
|
262
|
+
ancleto init [--agent <nombre>] [--tier <nivel>] [--lang <codigo>] [--exclude <globs>] [--with-azure]
|
|
230
263
|
# Configura el proyecto (interactivo en TTY)
|
|
231
264
|
|
|
232
|
-
ancleto install [--project <dir>] [--tier <nivel>] [--agent <nombre>] [--no-mcp]
|
|
265
|
+
ancleto install [--project <dir>] [--tier <nivel>] [--agent <nombre>] [--lang <codigo>] [--exclude <globs>] [--no-mcp]
|
|
233
266
|
# Instala agentes, skills y templates
|
|
234
267
|
|
|
235
268
|
ancleto update # Re-instala la última versión sobre lo existente
|
package/agents/documenter.md
CHANGED
|
@@ -117,7 +117,7 @@ Do not treat archive as a blind file move.
|
|
|
117
117
|
|
|
118
118
|
When a completed change modifies behavior through aspec deltas, `aspec/specs/` must reflect that completed behavior before the change is archived.
|
|
119
119
|
|
|
120
|
-
**Language**: spec
|
|
120
|
+
**Language**: write spec content in the user's conversation language (or the project's configured `language` in `.ancletorc`). The requirement/scenario keywords (`Requirement`, `Scenario`, `SHALL`, `WHEN`/`THEN`/`AND`, `ADDED/MODIFIED/REMOVED/RENAMED Requirements`) are literal and MUST NOT be translated. Paths, file names, and identifiers stay unchanged.
|
|
121
121
|
|
|
122
122
|
Handle these delta sections carefully:
|
|
123
123
|
|
package/agents/orchestrator.md
CHANGED
|
@@ -65,12 +65,13 @@ The orchestrator never executes `ancleto discovery --check`. When the technical
|
|
|
65
65
|
| --------- | ------------------------------------------------------------------------------------------------------------------------- |
|
|
66
66
|
| `READY` | use the focused answer returned by `@technical-discovery` |
|
|
67
67
|
| `PARTIAL` | explain which required documents are unavailable and offer to complete them |
|
|
68
|
-
| `STALE`
|
|
68
|
+
| `STALE` (minor) | use the answer with a one-line freshness note; do not offer regeneration — the seed is still usable |
|
|
69
|
+
| `STALE` (material) | warn and offer regeneration only when a concrete gap (info the seed should have but lacks) or the changed area affects the work |
|
|
69
70
|
| `MISSING` | explain that broad repository context is unavailable and offer to generate the seed |
|
|
70
71
|
|
|
71
72
|
For `MISSING` and `PARTIAL`, never generate automatically. Ask for explicit user approval before invoking `@technical-seed-writer`. If approved, pass the complete check report returned by `@technical-discovery` and the action `generate` or `complete`. If declined, continue only when the request can be handled safely without broad repository context; otherwise report the limitation and stop.
|
|
72
73
|
|
|
73
|
-
For `STALE`, delegate `regenerate` to `@technical-seed-writer` only after explicit user approval.
|
|
74
|
+
For `STALE`, delegate `regenerate` to `@technical-seed-writer` only after explicit user approval. When `impact` is `minor`, keep working from the seed and mention the drift in the summary. A concrete gap found while working — needed info the seed does not cover — may justify offering regeneration even with `minor` impact, always with approval.
|
|
74
75
|
|
|
75
76
|
`@technical-discovery` owns read-only repository orientation and seed-state inspection. `@technical-seed-writer` owns all seed generation, completion, and regeneration. Never substitute an unavailable seed with a manual repository scan.
|
|
76
77
|
|
|
@@ -124,7 +125,17 @@ Azure DevOps is optional and **disabled by default**. Before any Work Item intak
|
|
|
124
125
|
|
|
125
126
|
### Resolved Context Envelope
|
|
126
127
|
|
|
127
|
-
Keep this envelope for the entire session. Do not reconstruct it from memory or reduce it to a prose summary. When a Work Item was resolved, it contains its id, title, type, project, full normalized description, and full acceptance criteria. Add the original user request, enumerated requirements, explicit restrictions, and later user decisions or exclusions.
|
|
128
|
+
Keep this envelope for the entire session. Do not reconstruct it from memory or reduce it to a prose summary. When a Work Item was resolved, it contains its id, title, type, project, full normalized description, and full acceptance criteria. Add the original user request, enumerated requirements, explicit restrictions, and later user decisions or exclusions. Carry the resolved artifacts language (`language`) in the envelope as well.
|
|
129
|
+
|
|
130
|
+
### Artifacts Language
|
|
131
|
+
|
|
132
|
+
Resolve the working language for artifact content once per session:
|
|
133
|
+
|
|
134
|
+
- Read `language` from `.ancletorc` at the repo root.
|
|
135
|
+
- If it is `auto`, detect the language from the user's first up to 3 messages in this session. If the user never deviates, that language governs.
|
|
136
|
+
- Persist it: the first write-capable delegation in the session (`@spec-writer` when spec generation runs, otherwise `@coder`) MUST update `.ancletorc` → `language` with the resolved code, but only when it is currently `auto`. This is silent bookkeeping — never ask the user for it. An explicit configured code is never overwritten.
|
|
137
|
+
- Pass the resolved `language` in the Resolved Context Envelope to every subagent that writes artifacts.
|
|
138
|
+
- Artifact content uses the resolved language; keywords (`Requirement`, `Scenario`, `SHALL`, `WHEN`/`THEN`/`AND`, `ADDED/MODIFIED/REMOVED/RENAMED Requirements`) and file/directory names stay literal English.
|
|
128
139
|
|
|
129
140
|
Pass the relevant envelope verbatim when delegating: `@coder` receives the implementation scope; `@tester` receives it plus the coder's modified files and risks; `@reviewer` receives it plus task-owned files and the Validation Ledger. Do not omit numbered requirements, paths, commands, acceptance criteria, or explicit exclusions. Only `@context-resolver` may fetch a Work Item. If a subagent says it lacks context, supply the envelope or stop; never tell it to query Azure DevOps.
|
|
130
141
|
|
|
@@ -259,7 +270,7 @@ If the runtime is read-only or plan-only:
|
|
|
259
270
|
5. **Testing**: Delegate to **`@tester`** to create or update unit tests and perform final validation against the approved scope, including a non-writing format check and one lint pass after all edits. Include the complete Resolved Context Envelope, the coder's task-owned files, and its reported risks. `@tester` returns the final union of task-owned files and the Validation Ledger. A format failure in a task-owned file is failed verification and must not be fixed silently by `@tester`.
|
|
260
271
|
6. **Review**: Delegate to **`@reviewer`** when an independent correctness or scope review is appropriate. Include the complete Resolved Context Envelope, the tester's final task-owned file union, and the full Validation Ledger.
|
|
261
272
|
7. **🛑 FINAL ARCHIVE CHECKPOINT**: If implementation, validation, and any required review are complete with no blocking issues, stop and explicitly ask the user whether to keep iterating on the same change or finalize and archive it
|
|
262
|
-
8. **Finalization / Archive**: Before archiving, verify the delta specs reflect the final implementation — if iteration changed behavior or scope, re-delegate to **`@spec-writer`** to update the delta specs first, so the merge to source-of-truth is accurate. Check the seed freshness before closing: delegate the read-only state check to **`@technical-discovery`** and, when the state is `STALE`, warn and offer regeneration via **`@technical-seed-writer`** with explicit user approval — never automatic;
|
|
273
|
+
8. **Finalization / Archive**: Before archiving, verify the delta specs reflect the final implementation — if iteration changed behavior or scope, re-delegate to **`@spec-writer`** to update the delta specs first, so the merge to source-of-truth is accurate. Check the seed freshness before closing: delegate the read-only state check to **`@technical-discovery`** and, when the state is `STALE` with `impact: material`, warn and offer regeneration via **`@technical-seed-writer`** with explicit user approval — never automatic; with `impact: minor`, continue the archive normally and note the drift in the summary. This closure check protects future sessions from a silently aging seed. Then delegate to **`@documenter`** only after explicit user approval to archive
|
|
263
274
|
9. **Memory Record**: After a successful archive, delegate to **`@memory-keeper`** in Automatic Record mode when a concrete, plausible candidate exists, with the factual completed-work summary and validation evidence supporting it. If no candidate exists, delegate Optional Draft with the factual completed-work summary, `no-automatic-candidate` classification, and the reason no candidate was identified. When Automatic Record returns `no-entry-warranted`, use its draft or delegate Optional Draft with that classification and reason if it could not provide one. Before asking, show the final work summary, classification, reason, and exact draft, then stop for explicit user approval. If no safe draft is available, report that outcome and finish without asking or storing. On approval, delegate User-Approved Record with the unchanged draft, the factual summary and validation evidence used to compose it, archived change name, and card context. On rejection, do not store.
|
|
264
275
|
10. **Report**: Return final status or blocking findings to the user after automatic storage, an explicit decline, or User-Approved Record completes.
|
|
265
276
|
|
package/agents/spec-writer.md
CHANGED
|
@@ -19,9 +19,9 @@ Read `AGENTS.md` at the repo root for project-specific conventions, tech stack,
|
|
|
19
19
|
|
|
20
20
|
## Language Requirement
|
|
21
21
|
|
|
22
|
-
-
|
|
23
|
-
- Keywords are literal and MUST NOT be translated: `Requirement`, `Scenario`, `SHALL`, `WHEN`/`THEN`, `ADDED Requirements`, `MODIFIED Requirements`, `REMOVED Requirements`, `RENAMED Requirements`
|
|
24
|
-
- File names and directory names MUST
|
|
22
|
+
- Write artifact content in the user's conversation language (or the project's configured `language` in `.ancletorc`)
|
|
23
|
+
- Keywords are literal and MUST NOT be translated: `Requirement`, `Scenario`, `SHALL`, `WHEN`/`THEN`/`AND`, `ADDED Requirements`, `MODIFIED Requirements`, `REMOVED Requirements`, `RENAMED Requirements`
|
|
24
|
+
- File names and directory names are literal and MUST NOT be translated: English kebab-case, following aspec conventions
|
|
25
25
|
|
|
26
26
|
## Primary Responsibility
|
|
27
27
|
|
|
@@ -76,7 +76,8 @@ Inspect seed state only when `docs/technical-discovery/` is the selected source.
|
|
|
76
76
|
| --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
77
77
|
| `READY` | answer from the seed |
|
|
78
78
|
| `PARTIAL` | use an available document only when it safely answers the focused question; otherwise report the missing documents and request completion |
|
|
79
|
-
| `STALE`
|
|
79
|
+
| `STALE` with `impact: minor` | answer noting the freshness drift; do not request regeneration — the seed is still usable |
|
|
80
|
+
| `STALE` with `impact: material` | answer with an explicit freshness warning when the evidence is sufficient; request regeneration only when stale evidence could materially affect the answer |
|
|
80
81
|
| `MISSING` | report that broad repository context is unavailable and request generation |
|
|
81
82
|
|
|
82
83
|
You **report** states and recommend actions. You never resolve them: generating or regenerating
|
|
@@ -117,7 +118,7 @@ Any request to create, modify, or implement — including writing aspec artifact
|
|
|
117
118
|
| Situation | Action |
|
|
118
119
|
| -------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
|
|
119
120
|
| request to create / modify / implement | return the context and escalate the request to the `@orchestrator` |
|
|
120
|
-
| seed missing, partial, or stale
|
|
121
|
+
| seed missing, partial, or stale with material impact | report the state and emit the corresponding `SEED_ACTION_REQUIRED` marker for `@orchestrator` to delegate `@technical-seed-writer` |
|
|
121
122
|
|
|
122
123
|
When you were delegated, do not address the developer as if they had called you: your output is context for the calling agent.
|
|
123
124
|
|
|
@@ -126,7 +127,7 @@ When you were delegated, do not address the developer as if they had called you:
|
|
|
126
127
|
- **Answer in Spanish.** Paths, file names, and identifiers stay as they are.
|
|
127
128
|
- Cite the paths that support each claim.
|
|
128
129
|
- State which source you used and whether seed inspection was required.
|
|
129
|
-
- When seed inspection was required, return the resolved state and the complete unchanged check report if a seed action is needed.
|
|
130
|
+
- When seed inspection was required, return the resolved state with its `impact`, and the complete unchanged check report if a seed action is needed.
|
|
130
131
|
- Declare — when they apply — the stale nodes, any direct code read, and any gap left by the budget.
|
|
131
132
|
- If the seed state prevented the answer, state that no repository sweep was performed and
|
|
132
133
|
include the required `SEED_ACTION_REQUIRED` marker.
|
package/package.json
CHANGED
|
@@ -10,7 +10,7 @@ metadata:
|
|
|
10
10
|
|
|
11
11
|
# aspec Archive
|
|
12
12
|
|
|
13
|
-
**Artifacts language**: write
|
|
13
|
+
**Artifacts language**: write artifact content in the user's conversation language (or the project's configured `language` in `.ancletorc`). Keywords (`Requirement`, `Scenario`, `SHALL`, `WHEN`/`THEN`/`AND`, `ADDED/MODIFIED/REMOVED/RENAMED Requirements`) and file/directory names are literal and MUST NOT be translated.
|
|
14
14
|
|
|
15
15
|
Archive a completed change: check completion, sync delta specs, move the directory. No external binaries.
|
|
16
16
|
|
|
@@ -46,9 +46,10 @@ Check for delta specs at `aspec/changes/<name>/specs/`; if none, proceed without
|
|
|
46
46
|
|
|
47
47
|
### 3. Check technical seed freshness
|
|
48
48
|
|
|
49
|
-
If the `ancleto` CLI is available in this project, run `ancleto discovery --check` (read-only) and read its JSON `state`.
|
|
49
|
+
If the `ancleto` CLI is available in this project, run `ancleto discovery --check` (read-only) and read its JSON `state` and `impact`.
|
|
50
50
|
|
|
51
|
-
- **`STALE`**: warn that the technical seed is out of date
|
|
51
|
+
- **`STALE` with `impact: material`**: warn that the technical seed is out of date in material areas, and offer to regenerate it now (follow the `ancleto-technical-discovery` skill) or to continue archiving with the stale seed.
|
|
52
|
+
- **`STALE` with `impact: minor`**: continue without offering — the seed is still usable; record the drift in the summary.
|
|
52
53
|
- **Any other state**: continue without comment.
|
|
53
54
|
- Never regenerate automatically — regenerate only with the user's explicit approval.
|
|
54
55
|
- If the user declines, continue the archive normally and record the stale seed in the summary.
|
|
@@ -10,7 +10,7 @@ metadata:
|
|
|
10
10
|
|
|
11
11
|
# aspec Bulk Archive
|
|
12
12
|
|
|
13
|
-
**Artifacts language**: write
|
|
13
|
+
**Artifacts language**: write artifact content in the user's conversation language (or the project's configured `language` in `.ancletorc`). Keywords (`Requirement`, `Scenario`, `SHALL`, `WHEN`/`THEN`/`AND`, `ADDED/MODIFIED/REMOVED/RENAMED Requirements`) and file/directory names are literal and MUST NOT be translated.
|
|
14
14
|
|
|
15
15
|
Archive many completed changes at once, resolving spec conflicts against the implementation. No external binaries.
|
|
16
16
|
|
|
@@ -10,7 +10,7 @@ metadata:
|
|
|
10
10
|
|
|
11
11
|
# aspec Continue
|
|
12
12
|
|
|
13
|
-
**Artifacts language**: write
|
|
13
|
+
**Artifacts language**: write artifact content in the user's conversation language (or the project's configured `language` in `.ancletorc`). Keywords (`Requirement`, `Scenario`, `SHALL`, `WHEN`/`THEN`/`AND`, `ADDED/MODIFIED/REMOVED/RENAMED Requirements`) and file/directory names are literal and MUST NOT be translated.
|
|
14
14
|
|
|
15
15
|
Continue a change by creating exactly ONE next artifact. No external binaries: state is derived by which artifact files exist.
|
|
16
16
|
|
|
@@ -10,7 +10,7 @@ metadata:
|
|
|
10
10
|
|
|
11
11
|
# aspec Explore
|
|
12
12
|
|
|
13
|
-
**Artifacts language**: write
|
|
13
|
+
**Artifacts language**: write artifact content in the user's conversation language (or the project's configured `language` in `.ancletorc`). Keywords (`Requirement`, `Scenario`, `SHALL`, `WHEN`/`THEN`/`AND`, `ADDED/MODIFIED/REMOVED/RENAMED Requirements`) and file/directory names are literal and MUST NOT be translated.
|
|
14
14
|
|
|
15
15
|
Enter explore mode. Think deeply. Visualize freely. Follow the conversation.
|
|
16
16
|
|
|
@@ -10,7 +10,7 @@ metadata:
|
|
|
10
10
|
|
|
11
11
|
# aspec FF
|
|
12
12
|
|
|
13
|
-
**Artifacts language**: write
|
|
13
|
+
**Artifacts language**: write artifact content in the user's conversation language (or the project's configured `language` in `.ancletorc`). Keywords (`Requirement`, `Scenario`, `SHALL`, `WHEN`/`THEN`/`AND`, `ADDED/MODIFIED/REMOVED/RENAMED Requirements`) and file/directory names are literal and MUST NOT be translated.
|
|
14
14
|
|
|
15
15
|
Fast-forward artifact creation: generate everything needed to start implementation, writing files directly. No external binaries.
|
|
16
16
|
|
|
@@ -10,7 +10,7 @@ metadata:
|
|
|
10
10
|
|
|
11
11
|
# aspec New
|
|
12
12
|
|
|
13
|
-
**Artifacts language**: write
|
|
13
|
+
**Artifacts language**: write artifact content in the user's conversation language (or the project's configured `language` in `.ancletorc`). Keywords (`Requirement`, `Scenario`, `SHALL`, `WHEN`/`THEN`/`AND`, `ADDED/MODIFIED/REMOVED/RENAMED Requirements`) and file/directory names are literal and MUST NOT be translated.
|
|
14
14
|
|
|
15
15
|
Start a new change with a filesystem-native, artifact-driven flow. No external binaries: every step is a direct file operation.
|
|
16
16
|
|
|
@@ -10,7 +10,7 @@ metadata:
|
|
|
10
10
|
|
|
11
11
|
# aspec Onboard
|
|
12
12
|
|
|
13
|
-
**Artifacts language**: write
|
|
13
|
+
**Artifacts language**: write artifact content in the user's conversation language (or the project's configured `language` in `.ancletorc`). Keywords (`Requirement`, `Scenario`, `SHALL`, `WHEN`/`THEN`/`AND`, `ADDED/MODIFIED/REMOVED/RENAMED Requirements`) and file/directory names are literal and MUST NOT be translated.
|
|
14
14
|
|
|
15
15
|
Walk a first-time user through one complete spec-driven cycle on a real task. No external binaries.
|
|
16
16
|
|
|
@@ -10,7 +10,7 @@ metadata:
|
|
|
10
10
|
|
|
11
11
|
# aspec Propose
|
|
12
12
|
|
|
13
|
-
**Artifacts language**: write
|
|
13
|
+
**Artifacts language**: write artifact content in the user's conversation language (or the project's configured `language` in `.ancletorc`). Keywords (`Requirement`, `Scenario`, `SHALL`, `WHEN`/`THEN`/`AND`, `ADDED/MODIFIED/REMOVED/RENAMED Requirements`) and file/directory names are literal and MUST NOT be translated.
|
|
14
14
|
|
|
15
15
|
Create a change and all its artifacts in one step, writing files directly. No external binaries.
|
|
16
16
|
|
|
@@ -10,7 +10,7 @@ metadata:
|
|
|
10
10
|
|
|
11
11
|
# aspec Sync
|
|
12
12
|
|
|
13
|
-
**Artifacts language**: write
|
|
13
|
+
**Artifacts language**: write artifact content in the user's conversation language (or the project's configured `language` in `.ancletorc`). Keywords (`Requirement`, `Scenario`, `SHALL`, `WHEN`/`THEN`/`AND`, `ADDED/MODIFIED/REMOVED/RENAMED Requirements`) and file/directory names are literal and MUST NOT be translated.
|
|
14
14
|
|
|
15
15
|
Sync delta specs from a change to main specs.
|
|
16
16
|
|
|
@@ -41,7 +41,8 @@ further or create one subagent per unit: generation happens in one sequential ex
|
|
|
41
41
|
| --- | --- |
|
|
42
42
|
| `READY` | Read `index.md` and at most two documents it routes to. |
|
|
43
43
|
| `PARTIAL` | Complete only the missing documents. |
|
|
44
|
-
| `STALE` |
|
|
44
|
+
| `STALE` with `impact: minor` | Answer from the seed and note the freshness drift; do not regenerate or run another pack for it. |
|
|
45
|
+
| `STALE` with `impact: material` | Regenerate only the affected focused dossier; update a transversal decision when it changed. |
|
|
45
46
|
| `MISSING` | Generate the concise seed. |
|
|
46
47
|
|
|
47
48
|
Never replace a missing seed with a manual repository sweep.
|
|
@@ -19,7 +19,7 @@ metadata:
|
|
|
19
19
|
|
|
20
20
|
# ancleto-upgrade
|
|
21
21
|
|
|
22
|
-
**Artifacts language**: write
|
|
22
|
+
**Artifacts language**: write artifact content in the user's conversation language (or the project's configured `language` in `.ancletorc`). Keywords (`Requirement`, `Scenario`, `SHALL`, `WHEN`/`THEN`/`AND`, `ADDED/MODIFIED/REMOVED/RENAMED Requirements`) and file/directory names are literal and MUST NOT be translated.
|
|
23
23
|
|
|
24
24
|
Generate an aspec change migrating any library/runtime to a new major version; never edit code.
|
|
25
25
|
|
package/src/cli/index.js
CHANGED
|
@@ -32,14 +32,16 @@ Uso:
|
|
|
32
32
|
ancleto install --no-mcp Igual que install pero sin tocar config MCP
|
|
33
33
|
ancleto install --with-engram Ademas configura el MCP externo engram (memoria opcional)
|
|
34
34
|
ancleto install --tier <nivel> normal | minimo | gratis (wizard interactivo en TTY)
|
|
35
|
+
ancleto install --lang <codigo> auto | es | en | pt (idioma de los artifacts; auto = idioma de la conversacion)
|
|
36
|
+
ancleto install --exclude <globs> Paths excluidos del discovery, coma-separados (ej: "**/*.png,docs")
|
|
35
37
|
ancleto install --agent <nombre> opencode | vscode | antigravity | cursor | roo (wizard si no esta guardado)
|
|
36
38
|
ancleto update [--project <dir>] Alias de install (re-instala sobre lo existente)
|
|
37
39
|
Parado en un proyecto con .ancletorc opera sobre ese proyecto;
|
|
38
40
|
usa --global para forzar el alcance global
|
|
39
41
|
ancleto upgrade [--agent <nombre>] Re-aplica templates (LOCKED) y skills sobre el proyecto actual
|
|
40
|
-
ancleto init [--with-azure] [--agent <nombre>] [--tier <nivel>]
|
|
41
|
-
|
|
42
|
-
|
|
42
|
+
ancleto init [--with-azure] [--agent <nombre>] [--tier <nivel>] [--lang <codigo>] [--exclude <globs>]
|
|
43
|
+
Crea .ancletorc en el repositorio actual
|
|
44
|
+
(interactivo en TTY: banner + menu; Azure desactivado por defecto)
|
|
43
45
|
ancleto discovery --check Estado del seed (READY/STALE/PARTIAL/MISSING)
|
|
44
46
|
ancleto discovery [--compress] [--include G] [--ignore G] [--token-budget N]
|
|
45
47
|
Empaca el repo con Repomix y guarda estado
|
|
@@ -622,6 +624,63 @@ function scanTierFlag(args) {
|
|
|
622
624
|
return t
|
|
623
625
|
}
|
|
624
626
|
|
|
627
|
+
const SUPPORTED_LANGS = ['auto', 'es', 'en', 'pt']
|
|
628
|
+
|
|
629
|
+
function scanLangFlag(args) {
|
|
630
|
+
const l = flagValue(args, '--lang')
|
|
631
|
+
if (!l) return null
|
|
632
|
+
if (!SUPPORTED_LANGS.includes(l)) {
|
|
633
|
+
console.error(`ancleto: idioma invalido: ${l} (${SUPPORTED_LANGS.join('|')})`)
|
|
634
|
+
process.exit(1)
|
|
635
|
+
}
|
|
636
|
+
return l
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
function langLabel(code) {
|
|
640
|
+
return { auto: 'automatico (idioma de la conversacion)', es: 'espanol', en: 'ingles', pt: 'portugues' }[code] || code
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
const EXCLUDE_PRESETS = [
|
|
644
|
+
{ key: 'tests', label: 'tests (*.test.*, *.spec.*, __tests__)', recommended: true, globs: ['**/*.test.*', '**/*.spec.*', '**/__tests__/**'] },
|
|
645
|
+
{ key: 'assets', label: 'assets pesados (*.png, *.jpg, *.svg, *.ico, public/)', recommended: true, globs: ['**/*.png', '**/*.jpg', '**/*.svg', '**/*.ico', 'public'] },
|
|
646
|
+
{ key: 'docs', label: 'documentacion (docs/)', recommended: false, globs: ['docs'] },
|
|
647
|
+
{ key: 'data', label: 'migraciones y seeds', recommended: false, globs: ['**/migrations/**', '**/seeds/**'] },
|
|
648
|
+
{ key: 'lockfiles', label: 'lockfiles (package-lock, yarn.lock, pnpm-lock)', recommended: true, globs: ['package-lock.json', 'yarn.lock', 'pnpm-lock.yaml'] }
|
|
649
|
+
]
|
|
650
|
+
|
|
651
|
+
function parseExcludeFlag(value) {
|
|
652
|
+
return String(value)
|
|
653
|
+
.split(',')
|
|
654
|
+
.map((s) => s.trim())
|
|
655
|
+
.filter(Boolean)
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
// null = flag ausente; [] = limpiar exclusiones; [...] = globs.
|
|
659
|
+
function scanExcludeFlag(args) {
|
|
660
|
+
const i = args.indexOf('--exclude')
|
|
661
|
+
if (i < 0) return null
|
|
662
|
+
const next = args[i + 1]
|
|
663
|
+
if (!next || next.startsWith('--')) return []
|
|
664
|
+
return parseExcludeFlag(next)
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
// Une los grupos elegidos con los globs propios del proyecto (los que no son de un preset).
|
|
668
|
+
function applyExcludePresets(existing, keys) {
|
|
669
|
+
const presetGlobs = new Set(EXCLUDE_PRESETS.flatMap((p) => p.globs))
|
|
670
|
+
const custom = (existing || []).filter((g) => !presetGlobs.has(g))
|
|
671
|
+
const chosen = EXCLUDE_PRESETS.filter((p) => keys.includes(p.key)).flatMap((p) => p.globs)
|
|
672
|
+
return [...custom, ...chosen]
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
async function askExcludePresets(existing) {
|
|
676
|
+
const presetGlobs = new Set(EXCLUDE_PRESETS.flatMap((p) => p.globs))
|
|
677
|
+
const hasPreset = (existing || []).some((g) => presetGlobs.has(g))
|
|
678
|
+
const preselected = EXCLUDE_PRESETS.map((p, i) => (hasPreset ? (p.globs.some((g) => (existing || []).includes(g)) ? i : -1) : p.recommended ? i : -1)).filter((i) => i >= 0)
|
|
679
|
+
const { cancelled, indices } = await selectMultiple('Que excluir del discovery (ademas de node_modules, dist, build)', EXCLUDE_PRESETS.map((p) => p.label), preselected)
|
|
680
|
+
if (cancelled) return existing || []
|
|
681
|
+
return applyExcludePresets(existing, indices.map((i) => EXCLUDE_PRESETS[i].key))
|
|
682
|
+
}
|
|
683
|
+
|
|
625
684
|
async function resolveAgent(args, existing, allowAsk = Boolean(process.stdin.isTTY)) {
|
|
626
685
|
const flag = scanAgentFlag(args)
|
|
627
686
|
if (flag) return flag
|
|
@@ -820,9 +879,13 @@ async function install(args) {
|
|
|
820
879
|
: null
|
|
821
880
|
|
|
822
881
|
let agent = agentFlag || (existingRc?.agent && SUPPORTED_AGENTS.includes(existingRc.agent) ? existingRc.agent : null)
|
|
882
|
+
let language = scanLangFlag(args) || (existingRc?.language && SUPPORTED_LANGS.includes(existingRc.language) ? existingRc.language : null)
|
|
883
|
+
const excludeFlag = scanExcludeFlag(args)
|
|
884
|
+
const existingDiscovery = existingRc?.discovery || { outputDir: 'docs/technical-discovery', exclude: [] }
|
|
885
|
+
let excludeChoice = excludeFlag
|
|
823
886
|
|
|
824
887
|
let bannerShown = false
|
|
825
|
-
const isInteractive = Boolean(process.stdout.isTTY) && ((projectDir && !agent) || !tier)
|
|
888
|
+
const isInteractive = Boolean(process.stdout.isTTY) && ((projectDir && !agent) || !tier || !language || (projectDir && excludeChoice === null && (existingDiscovery.exclude || []).length === 0))
|
|
826
889
|
if (isInteractive) {
|
|
827
890
|
await showBanner()
|
|
828
891
|
bannerShown = true
|
|
@@ -833,8 +896,16 @@ async function install(args) {
|
|
|
833
896
|
const current = TIERS[storedTier] ? storedTier : ''
|
|
834
897
|
tier = await selectOption('Tier de costo', Object.keys(TIERS), Math.max(0, Object.keys(TIERS).indexOf(current)))
|
|
835
898
|
}
|
|
899
|
+
if (!language) {
|
|
900
|
+
const picked = await selectOption('Idioma de los artifacts', SUPPORTED_LANGS.map(langLabel), 0)
|
|
901
|
+
language = SUPPORTED_LANGS[SUPPORTED_LANGS.map(langLabel).indexOf(picked)] || 'auto'
|
|
902
|
+
}
|
|
903
|
+
if (projectDir && excludeChoice === null && (existingDiscovery.exclude || []).length === 0) {
|
|
904
|
+
excludeChoice = await askExcludePresets(existingDiscovery.exclude || [])
|
|
905
|
+
}
|
|
836
906
|
stopBanner()
|
|
837
907
|
}
|
|
908
|
+
if (!language) language = 'auto'
|
|
838
909
|
|
|
839
910
|
if (projectDir && !agent) agent = DEFAULT_AGENT
|
|
840
911
|
if (!tier) tier = TIERS[storedTier] ? storedTier : 'normal'
|
|
@@ -862,6 +933,8 @@ async function install(args) {
|
|
|
862
933
|
const agentSkillsDir = await installAgentSkills(projectDir, agent)
|
|
863
934
|
await writeManifest(projectDir, {
|
|
864
935
|
agent,
|
|
936
|
+
language,
|
|
937
|
+
...(excludeChoice !== null ? { discovery: { ...existingDiscovery, exclude: excludeChoice } } : {}),
|
|
865
938
|
...(gratisModelChoice ? { gratisModel: gratisModelChoice } : {}),
|
|
866
939
|
installedPaths: {
|
|
867
940
|
templates: ['AGENTS.md', 'PRODUCT.md'],
|
|
@@ -942,13 +1015,17 @@ async function initProject(args) {
|
|
|
942
1015
|
const withAzure = args.includes('--with-azure')
|
|
943
1016
|
const agentFlag = scanAgentFlag(args)
|
|
944
1017
|
const tierFlag = scanTierFlag(args)
|
|
1018
|
+
const langFlag = scanLangFlag(args)
|
|
945
1019
|
const existing = await readAncletorc(projectDir)
|
|
946
1020
|
const azure = existing?.azure ?? { enabled: false }
|
|
947
|
-
|
|
1021
|
+
let discovery = existing?.discovery ?? { outputDir: 'docs/technical-discovery', exclude: [] }
|
|
948
1022
|
const tierFile = join(projectDir, '.opencode', '.ancleto-tier')
|
|
1023
|
+
const excludeFlag = scanExcludeFlag(args)
|
|
1024
|
+
let excludeChoice = excludeFlag
|
|
949
1025
|
|
|
950
|
-
let agent, tier
|
|
951
|
-
|
|
1026
|
+
let agent, tier, language
|
|
1027
|
+
language = langFlag || (existing?.language && SUPPORTED_LANGS.includes(existing.language) ? existing.language : null)
|
|
1028
|
+
const isInteractive = Boolean(process.stdout.isTTY) && (!agentFlag || !tierFlag || !language || (excludeChoice === null && (discovery.exclude || []).length === 0))
|
|
952
1029
|
if (isInteractive) {
|
|
953
1030
|
await showBanner()
|
|
954
1031
|
const agentIdx = Math.max(0, SUPPORTED_AGENTS.indexOf(existing?.agent))
|
|
@@ -956,6 +1033,13 @@ async function initProject(args) {
|
|
|
956
1033
|
const tierIdx = Math.max(0, Object.keys(TIERS).indexOf(TIERS[storedTier] ? storedTier : ''))
|
|
957
1034
|
agent = agentFlag || await selectOption('Agente/IDE', SUPPORTED_AGENTS, agentIdx)
|
|
958
1035
|
tier = tierFlag || await selectOption('Tier de costo', Object.keys(TIERS), tierIdx)
|
|
1036
|
+
if (!language) {
|
|
1037
|
+
const picked = await selectOption('Idioma de los artifacts', SUPPORTED_LANGS.map(langLabel), 0)
|
|
1038
|
+
language = SUPPORTED_LANGS[SUPPORTED_LANGS.map(langLabel).indexOf(picked)] || 'auto'
|
|
1039
|
+
}
|
|
1040
|
+
if (excludeChoice === null && (discovery.exclude || []).length === 0) {
|
|
1041
|
+
excludeChoice = await askExcludePresets(discovery.exclude || [])
|
|
1042
|
+
}
|
|
959
1043
|
if (withAzure) {
|
|
960
1044
|
azure.enabled = true
|
|
961
1045
|
} else {
|
|
@@ -965,21 +1049,23 @@ async function initProject(args) {
|
|
|
965
1049
|
} else {
|
|
966
1050
|
agent = await resolveAgent(args, existing?.agent, false)
|
|
967
1051
|
tier = tierFlag
|
|
1052
|
+
if (!language) language = 'auto'
|
|
968
1053
|
if (withAzure) azure.enabled = true
|
|
969
1054
|
}
|
|
1055
|
+
if (excludeChoice !== null) discovery = { ...discovery, exclude: excludeChoice }
|
|
970
1056
|
|
|
971
1057
|
if (tier) {
|
|
972
1058
|
await mkdir(join(projectDir, '.opencode'), { recursive: true })
|
|
973
1059
|
await writeFile(tierFile, tier + '\n')
|
|
974
1060
|
}
|
|
975
1061
|
|
|
976
|
-
const manifest = await writeManifest(projectDir, { azure, discovery, agent })
|
|
1062
|
+
const manifest = await writeManifest(projectDir, { azure, discovery, agent, language })
|
|
977
1063
|
await copyTemplates(projectDir)
|
|
978
1064
|
await scaffoldAspec(projectDir)
|
|
979
1065
|
await refreshWorkingContext(projectDir)
|
|
980
1066
|
await registerProject(projectDir, { agent, tier: tier || null })
|
|
981
1067
|
if (azure.enabled) console.log(AZURE_MCP_NOTICE)
|
|
982
|
-
console.log(`ancleto: .ancletorc actualizado en ${projectDir} (v${manifest.version})${azure.enabled ? ' (Azure habilitado)' : ' (Azure desactivado)'} (Agente: ${agent})${tier ? ` (Tier: ${tier})` : ''}`)
|
|
1068
|
+
console.log(`ancleto: .ancletorc actualizado en ${projectDir} (v${manifest.version})${azure.enabled ? ' (Azure habilitado)' : ' (Azure desactivado)'} (Agente: ${agent})${tier ? ` (Tier: ${tier})` : ''} (Idioma: ${language})`)
|
|
983
1069
|
}
|
|
984
1070
|
|
|
985
1071
|
const DEFAULT_IGNORES = ['node_modules', '.git', 'dist']
|
|
@@ -1041,9 +1127,11 @@ async function computeSources() {
|
|
|
1041
1127
|
|
|
1042
1128
|
async function hashSources(sources) {
|
|
1043
1129
|
const h = createHash('sha256')
|
|
1130
|
+
const fileHashes = {}
|
|
1044
1131
|
for (const rel of sources) {
|
|
1045
1132
|
try {
|
|
1046
1133
|
const content = await readFile(join(process.cwd(), rel))
|
|
1134
|
+
fileHashes[rel] = createHash('sha256').update(content).digest('hex').slice(0, 16)
|
|
1047
1135
|
h.update(rel)
|
|
1048
1136
|
h.update('\0')
|
|
1049
1137
|
h.update(String(content.length))
|
|
@@ -1052,7 +1140,71 @@ async function hashSources(sources) {
|
|
|
1052
1140
|
h.update('\n')
|
|
1053
1141
|
} catch {}
|
|
1054
1142
|
}
|
|
1055
|
-
return h.digest('hex')
|
|
1143
|
+
return { hash: h.digest('hex'), fileHashes }
|
|
1144
|
+
}
|
|
1145
|
+
|
|
1146
|
+
// Archivos cuyo cambio altera la arquitectura (configs de runtime, entry points).
|
|
1147
|
+
const MATERIAL_FILE_RES = [
|
|
1148
|
+
/^package\.json$/,
|
|
1149
|
+
/^tsconfig(\..+)?\.json$/,
|
|
1150
|
+
/^jsconfig\.json$/,
|
|
1151
|
+
/^(vite|webpack|rollup|next|nuxt|astro|svelte|tailwind)\.config\.[cm]?[jt]s$/,
|
|
1152
|
+
/^docker-compose\.ya?ml$/,
|
|
1153
|
+
/^Dockerfile$/,
|
|
1154
|
+
/^index\.html$/,
|
|
1155
|
+
/^src\/(main|index)\.[cm]?[jt]sx?$/
|
|
1156
|
+
]
|
|
1157
|
+
|
|
1158
|
+
function isMaterialFile(rel) {
|
|
1159
|
+
return MATERIAL_FILE_RES.some((re) => re.test(rel))
|
|
1160
|
+
}
|
|
1161
|
+
|
|
1162
|
+
// Area = directorio de primer nivel; los archivos raiz son su propia area.
|
|
1163
|
+
function areaOf(rel) {
|
|
1164
|
+
const i = rel.indexOf('/')
|
|
1165
|
+
return i === -1 ? rel : rel.slice(0, i)
|
|
1166
|
+
}
|
|
1167
|
+
|
|
1168
|
+
function computeImpact(stored, sources, fileHashes) {
|
|
1169
|
+
const storedList = new Set(stored.sources || [])
|
|
1170
|
+
const currentList = new Set(sources)
|
|
1171
|
+
const storedFiles = stored.fileHashes || null
|
|
1172
|
+
const changedAreas = new Set()
|
|
1173
|
+
const materialReasons = []
|
|
1174
|
+
const notes = []
|
|
1175
|
+
|
|
1176
|
+
for (const rel of sources) {
|
|
1177
|
+
if (!storedList.has(rel)) {
|
|
1178
|
+
changedAreas.add(areaOf(rel))
|
|
1179
|
+
if (isMaterialFile(rel)) materialReasons.push(`archivo material nuevo: ${rel}`)
|
|
1180
|
+
}
|
|
1181
|
+
}
|
|
1182
|
+
for (const rel of storedList) {
|
|
1183
|
+
if (!currentList.has(rel)) {
|
|
1184
|
+
changedAreas.add(areaOf(rel))
|
|
1185
|
+
if (isMaterialFile(rel)) materialReasons.push(`archivo material eliminado: ${rel}`)
|
|
1186
|
+
}
|
|
1187
|
+
}
|
|
1188
|
+
if (storedFiles) {
|
|
1189
|
+
for (const rel of sources) {
|
|
1190
|
+
if (storedFiles[rel] && storedFiles[rel] !== fileHashes[rel]) {
|
|
1191
|
+
changedAreas.add(areaOf(rel))
|
|
1192
|
+
if (isMaterialFile(rel)) materialReasons.push(`archivo material modificado: ${rel}`)
|
|
1193
|
+
}
|
|
1194
|
+
}
|
|
1195
|
+
}
|
|
1196
|
+
|
|
1197
|
+
const storedAreas = new Set([...storedList].map(areaOf))
|
|
1198
|
+
const currentAreas = new Set(sources.map(areaOf))
|
|
1199
|
+
for (const a of currentAreas) if (!storedAreas.has(a)) materialReasons.push(`area raiz nueva: ${a}`)
|
|
1200
|
+
for (const a of storedAreas) if (!currentAreas.has(a)) materialReasons.push(`area raiz eliminada: ${a}`)
|
|
1201
|
+
|
|
1202
|
+
if (!storedFiles && changedAreas.size === 0) {
|
|
1203
|
+
notes.push('estado previo sin hashes por archivo: el cambio de contenido no se puede atribuir a un area')
|
|
1204
|
+
}
|
|
1205
|
+
|
|
1206
|
+
const impact = materialReasons.length ? 'material' : changedAreas.size || notes.length ? 'minor' : 'none'
|
|
1207
|
+
return { impact, changedAreas: [...changedAreas].sort(), materialReasons, notes }
|
|
1056
1208
|
}
|
|
1057
1209
|
|
|
1058
1210
|
function statePath(outputDir) {
|
|
@@ -1077,7 +1229,7 @@ async function checkDiscovery() {
|
|
|
1077
1229
|
const { outputDir } = config
|
|
1078
1230
|
const tier = readProjectTier(process.cwd())
|
|
1079
1231
|
const present = await presentDocs(outputDir)
|
|
1080
|
-
let state, action, message, missingDocs
|
|
1232
|
+
let state, action, message, missingDocs, impact = 'none', changedAreas = [], materialReasons = [], notes = []
|
|
1081
1233
|
if (present.length === 0) {
|
|
1082
1234
|
state = 'MISSING'
|
|
1083
1235
|
action = 'generate'
|
|
@@ -1090,35 +1242,50 @@ async function checkDiscovery() {
|
|
|
1090
1242
|
message = `Faltan ${missingDocs.length} documentos del seed.`
|
|
1091
1243
|
} else {
|
|
1092
1244
|
const sources = await computeSources()
|
|
1093
|
-
const hash = await hashSources(sources)
|
|
1094
|
-
let
|
|
1245
|
+
const { hash, fileHashes } = await hashSources(sources)
|
|
1246
|
+
let stored = null
|
|
1095
1247
|
const sp = statePath(outputDir)
|
|
1096
1248
|
if (await exists(sp)) {
|
|
1097
1249
|
try {
|
|
1098
|
-
|
|
1250
|
+
stored = JSON.parse((await readFile(sp, 'utf8')).replace(/^\uFEFF/, ''))
|
|
1099
1251
|
} catch {}
|
|
1100
1252
|
}
|
|
1101
|
-
if (!
|
|
1253
|
+
if (!stored?.hash) {
|
|
1102
1254
|
state = 'STALE'
|
|
1255
|
+
impact = 'material'
|
|
1103
1256
|
action = 'regenerate'
|
|
1104
1257
|
message = 'Seed completo pero sin estado registrado — frescura desconocida.'
|
|
1105
|
-
} else if (
|
|
1258
|
+
} else if (stored.hash === hash) {
|
|
1106
1259
|
state = 'READY'
|
|
1107
1260
|
action = 'continue'
|
|
1108
1261
|
message = 'El seed esta al dia.'
|
|
1109
1262
|
} else {
|
|
1263
|
+
const diff = computeImpact(stored, sources, fileHashes)
|
|
1264
|
+
impact = diff.impact
|
|
1265
|
+
changedAreas = diff.changedAreas
|
|
1266
|
+
materialReasons = diff.materialReasons
|
|
1267
|
+
notes = diff.notes
|
|
1110
1268
|
state = 'STALE'
|
|
1111
|
-
|
|
1112
|
-
|
|
1269
|
+
if (impact === 'material') {
|
|
1270
|
+
action = 'regenerate'
|
|
1271
|
+
message = 'El repositorio cambio en areas materiales (config/entry points/estructura).'
|
|
1272
|
+
} else {
|
|
1273
|
+
action = 'continue'
|
|
1274
|
+
message = 'Cambios menores desde el ultimo pack; el seed sigue siendo util.'
|
|
1275
|
+
}
|
|
1113
1276
|
}
|
|
1114
1277
|
missingDocs = []
|
|
1115
1278
|
}
|
|
1116
1279
|
console.log(JSON.stringify({
|
|
1117
1280
|
schemaVersion: 2,
|
|
1118
1281
|
state,
|
|
1282
|
+
impact,
|
|
1119
1283
|
recommendedAction: action,
|
|
1120
1284
|
message,
|
|
1121
1285
|
missingDocs,
|
|
1286
|
+
changedAreas,
|
|
1287
|
+
materialReasons,
|
|
1288
|
+
notes,
|
|
1122
1289
|
config: {
|
|
1123
1290
|
outputDir,
|
|
1124
1291
|
exclude: config.exclude,
|
|
@@ -1163,12 +1330,13 @@ async function packDiscovery(flags) {
|
|
|
1163
1330
|
process.exit(1)
|
|
1164
1331
|
}
|
|
1165
1332
|
const sources = await computeSources()
|
|
1166
|
-
const hash = await hashSources(sources)
|
|
1333
|
+
const { hash, fileHashes } = await hashSources(sources)
|
|
1167
1334
|
await mkdir(outputDir, { recursive: true })
|
|
1168
1335
|
await writeFile(statePath(outputDir), JSON.stringify({
|
|
1169
1336
|
version: 1,
|
|
1170
1337
|
generatedAt: new Date().toISOString(),
|
|
1171
1338
|
sources,
|
|
1339
|
+
fileHashes,
|
|
1172
1340
|
hash,
|
|
1173
1341
|
packTokens: tokens
|
|
1174
1342
|
}, null, 2) + '\n')
|
package/templates/AGENTS.md
CHANGED
|
@@ -71,9 +71,13 @@ comparte.
|
|
|
71
71
|
- **Cambios con scope incierto / arquitectura**: Crear artifacts en `aspec/changes/<name>/`.
|
|
72
72
|
- **Cambios menores / fixes**: Implementación directa.
|
|
73
73
|
- **Cierre**: Archivar con `/cleto-archive` al finalizar.
|
|
74
|
+
|
|
75
|
+
<!-- LOCKED: artifacts-language -->
|
|
74
76
|
- **Idioma de los artifacts**: el contenido de `proposal.md`, `design.md`, `tasks.md` y `specs/` se escribe
|
|
75
|
-
en
|
|
76
|
-
|
|
77
|
+
en el idioma de la conversación con el usuario (o en el `language` configurado en `.ancletorc`).
|
|
78
|
+
Los keywords (`Requirement`, `Scenario`, `SHALL`, `WHEN`/`THEN`/`AND`, `ADDED/MODIFIED/REMOVED/RENAMED
|
|
79
|
+
Requirements`) y los nombres de archivos y directorios son literales en inglés y **no se traducen**.
|
|
80
|
+
<!-- /LOCKED: artifacts-language -->
|
|
77
81
|
|
|
78
82
|
## Tools de Soporte
|
|
79
83
|
|