gemstack-ai 1.0.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/.agents/rules/01-gemstack-core.md +51 -0
- package/.agents/rules/02-gemstack-constitution.md +44 -0
- package/.agents/rules/03-gemstack-security.md +49 -0
- package/.agents/rules/04-gemstack-infrastructure.md +28 -0
- package/.agents/skills/gemstack-cso/SKILL.md +50 -0
- package/.agents/skills/gemstack-dashboard/SKILL.md +31 -0
- package/.agents/skills/gemstack-guard/SKILL.md +19 -0
- package/.agents/skills/gemstack-handoff/SKILL.md +21 -0
- package/.agents/skills/gemstack-heal/SKILL.md +19 -0
- package/.agents/skills/gemstack-investigate/SKILL.md +25 -0
- package/.agents/skills/gemstack-learn/SKILL.md +18 -0
- package/.agents/skills/gemstack-office-hours/SKILL.md +18 -0
- package/.agents/skills/gemstack-plan/SKILL.md +20 -0
- package/.agents/skills/gemstack-qa/SKILL.md +17 -0
- package/.agents/skills/gemstack-qa-visual/SKILL.md +17 -0
- package/.agents/skills/gemstack-resume/SKILL.md +18 -0
- package/.agents/skills/gemstack-review/SKILL.md +18 -0
- package/.agents/skills/gemstack-sandbox/SKILL.md +19 -0
- package/.agents/skills/gemstack-ship/SKILL.md +19 -0
- package/.agents/skills/gemstack-spec/SKILL.md +24 -0
- package/.agents/skills/gemstack-swarm/SKILL.md +18 -0
- package/.agents/skills/gemstack-tasks/SKILL.md +18 -0
- package/.gemstack/learnings.md +8 -0
- package/.gemstack/state.json +11 -0
- package/.gitattributes +19 -0
- package/.github/workflows/main-ci.yml +32 -0
- package/.github/workflows/pr-ci.yml +31 -0
- package/.github/workflows/publish.yml +52 -0
- package/.github/workflows/release-readiness.yml +43 -0
- package/CHANGELOG.md +35 -0
- package/CODE_OF_CONDUCT.md +49 -0
- package/CONTRIBUTING.md +62 -0
- package/LICENSE +21 -0
- package/MANUAL.md +99 -0
- package/README.md +130 -0
- package/RELEASE_NOTES.md +149 -0
- package/bin/gemstack +31 -0
- package/bin/gemstack-doctor +16 -0
- package/bin/gemstack-doctor.ps1 +38 -0
- package/bin/gemstack.ps1 +49 -0
- package/docs/antigravity.md +6 -0
- package/docs/handoff.md +9 -0
- package/docs/qa/latest-qa.md +25 -0
- package/docs/qa-browser.md +7 -0
- package/docs/quickstart.md +21 -0
- package/docs/release.md +29 -0
- package/docs/reviews/latest-review.md +24 -0
- package/docs/security/latest-security-audit.md +35 -0
- package/docs/security.md +17 -0
- package/docs/skills.md +17 -0
- package/docs/spec-driven-development.md +10 -0
- package/gemstack-ai-1.0.1.tgz +0 -0
- package/handoff.md +45 -0
- package/handoff_archive.md +61 -0
- package/package.json +25 -0
- package/scripts/ci/check-frontmatter.js +54 -0
- package/scripts/ci/check-mojibake.js +44 -0
- package/scripts/ci/check-package-contents.js +32 -0
- package/scripts/ci/check-template-clean.js +46 -0
- package/scripts/ci/smoke-cli.js +30 -0
- package/specs/004-release-automation/plan.md +52 -0
- package/specs/004-release-automation/spec.md +49 -0
- package/specs/004-release-automation/tasks.md +25 -0
- package/specs/005-the-wow-update/plan.md +29 -0
- package/specs/005-the-wow-update/spec.md +32 -0
- package/specs/005-the-wow-update/tasks.md +16 -0
- package/specs/README.md +12 -0
- package/specs/current/plan.md +83 -0
- package/specs/current/spec.md +57 -0
- package/specs/current/tasks.md +98 -0
- package/specs/templates/plan.md +38 -0
- package/specs/templates/spec.md +35 -0
- package/specs/templates/tasks.md +21 -0
- package/specs/v0.2-cli-distribution/plan.md +112 -0
- package/specs/v0.2-cli-distribution/spec.md +27 -0
- package/specs/v0.2-cli-distribution/tasks.md +115 -0
- package/specs/v0.3-ci-cd/plan.md +83 -0
- package/specs/v0.3-ci-cd/spec.md +57 -0
- package/specs/v0.3-ci-cd/tasks.md +98 -0
- package/src/cli.js +64 -0
- package/src/commands/doctor.js +50 -0
- package/src/commands/hooks.js +67 -0
- package/src/commands/init.js +90 -0
- package/src/commands/install.js +72 -0
- package/src/commands/list.js +20 -0
- package/src/commands/show.js +18 -0
- package/src/commands/update.js +88 -0
- package/src/lib/backup.js +29 -0
- package/src/lib/filesystem-safe.js +22 -0
- package/src/lib/gitignore.js +19 -0
- package/src/lib/logger.js +6 -0
- package/src/lib/manifest.js +25 -0
- package/src/lib/parser.js +27 -0
- package/src/mcp-server.js +101 -0
- package/template/.agents/rules/01-gemstack-core.md +51 -0
- package/template/.agents/rules/02-gemstack-constitution.md +44 -0
- package/template/.agents/rules/03-gemstack-security.md +49 -0
- package/template/.agents/rules/04-gemstack-infrastructure.md +28 -0
- package/template/.agents/skills/gemstack-cso/SKILL.md +50 -0
- package/template/.agents/skills/gemstack-dashboard/SKILL.md +31 -0
- package/template/.agents/skills/gemstack-guard/SKILL.md +19 -0
- package/template/.agents/skills/gemstack-handoff/SKILL.md +21 -0
- package/template/.agents/skills/gemstack-heal/SKILL.md +19 -0
- package/template/.agents/skills/gemstack-investigate/SKILL.md +25 -0
- package/template/.agents/skills/gemstack-learn/SKILL.md +18 -0
- package/template/.agents/skills/gemstack-office-hours/SKILL.md +18 -0
- package/template/.agents/skills/gemstack-plan/SKILL.md +20 -0
- package/template/.agents/skills/gemstack-qa/SKILL.md +17 -0
- package/template/.agents/skills/gemstack-qa-visual/SKILL.md +17 -0
- package/template/.agents/skills/gemstack-resume/SKILL.md +18 -0
- package/template/.agents/skills/gemstack-review/SKILL.md +18 -0
- package/template/.agents/skills/gemstack-sandbox/SKILL.md +19 -0
- package/template/.agents/skills/gemstack-ship/SKILL.md +19 -0
- package/template/.agents/skills/gemstack-spec/SKILL.md +24 -0
- package/template/.agents/skills/gemstack-swarm/SKILL.md +18 -0
- package/template/.agents/skills/gemstack-tasks/SKILL.md +18 -0
- package/template/.gemstack/learnings.md +3 -0
- package/template/.gemstack/state.json +4 -0
- package/template/docs/antigravity.md +6 -0
- package/template/docs/handoff.md +9 -0
- package/template/docs/qa/latest-qa.md +25 -0
- package/template/docs/qa-browser.md +7 -0
- package/template/docs/quickstart.md +21 -0
- package/template/docs/release.md +10 -0
- package/template/docs/reviews/latest-review.md +19 -0
- package/template/docs/security/latest-security-audit.md +37 -0
- package/template/docs/security.md +17 -0
- package/template/docs/skills.md +17 -0
- package/template/docs/spec-driven-development.md +10 -0
- package/template/handoff.md +11 -0
- package/template/handoff_archive.md +3 -0
- package/template/specs/current/plan.md +5 -0
- package/template/specs/current/spec.md +7 -0
- package/template/specs/current/tasks.md +3 -0
- package/template/specs/templates/plan.md +38 -0
- package/template/specs/templates/spec.md +35 -0
- package/template/specs/templates/tasks.md +21 -0
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
|
|
4
|
+
const skillsDir = path.resolve(__dirname, '../../.agents/skills');
|
|
5
|
+
if (!fs.existsSync(skillsDir)) {
|
|
6
|
+
console.error(`Skills directory not found at ${skillsDir}`);
|
|
7
|
+
process.exit(1);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
let hasError = false;
|
|
11
|
+
|
|
12
|
+
fs.readdirSync(skillsDir).forEach(folder => {
|
|
13
|
+
const stat = fs.statSync(path.join(skillsDir, folder));
|
|
14
|
+
if (!stat.isDirectory()) return;
|
|
15
|
+
|
|
16
|
+
const skillPath = path.join(skillsDir, folder, 'SKILL.md');
|
|
17
|
+
if (!fs.existsSync(skillPath)) {
|
|
18
|
+
console.error(`[FAIL] ${folder} missing SKILL.md`);
|
|
19
|
+
hasError = true;
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const content = fs.readFileSync(skillPath, 'utf8');
|
|
24
|
+
const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---/);
|
|
25
|
+
if (!frontmatterMatch) {
|
|
26
|
+
console.error(`[FAIL] ${folder} missing valid frontmatter`);
|
|
27
|
+
hasError = true;
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const frontmatter = frontmatterMatch[1];
|
|
32
|
+
const nameMatch = frontmatter.match(/name:\s*(.+)/);
|
|
33
|
+
const descMatch = frontmatter.match(/description:\s*(.+)/);
|
|
34
|
+
const triggersMatch = frontmatter.match(/triggers:\s*\n((\s+-\s+.+\n?)+)/);
|
|
35
|
+
|
|
36
|
+
if (!nameMatch || nameMatch[1].trim() !== folder) {
|
|
37
|
+
console.error(`[FAIL] ${folder} name mismatch or missing. Expected: ${folder}`);
|
|
38
|
+
hasError = true;
|
|
39
|
+
}
|
|
40
|
+
if (!descMatch || descMatch[1].trim() === '') {
|
|
41
|
+
console.error(`[FAIL] ${folder} missing description`);
|
|
42
|
+
hasError = true;
|
|
43
|
+
}
|
|
44
|
+
if (!triggersMatch) {
|
|
45
|
+
console.error(`[FAIL] ${folder} missing triggers array`);
|
|
46
|
+
hasError = true;
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
if (hasError) {
|
|
51
|
+
process.exit(1);
|
|
52
|
+
} else {
|
|
53
|
+
console.log('[OK] All skills have valid frontmatter.');
|
|
54
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
|
|
4
|
+
const rootDir = path.resolve(__dirname, '../../');
|
|
5
|
+
let hasError = false;
|
|
6
|
+
|
|
7
|
+
function walkDir(dir, callback) {
|
|
8
|
+
if (!fs.existsSync(dir)) return;
|
|
9
|
+
fs.readdirSync(dir).forEach(f => {
|
|
10
|
+
const dirPath = path.join(dir, f);
|
|
11
|
+
if (f === 'node_modules' || f === '.git' || f === 'temp dirs' || f.endsWith('.tgz') || f.endsWith('.zip') || f.endsWith('.sqlite')) return;
|
|
12
|
+
if (fs.statSync(dirPath).isDirectory()) {
|
|
13
|
+
walkDir(dirPath, callback);
|
|
14
|
+
} else {
|
|
15
|
+
if (/\.(md|js|json|yml|yaml|ps1|sh)$/.test(f)) {
|
|
16
|
+
callback(dirPath);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const mojibakePatterns = new RegExp('\\xC3|\\xC2|\\xE2\\x9C|\\xF0\\x9F');
|
|
23
|
+
|
|
24
|
+
walkDir(rootDir, (filePath) => {
|
|
25
|
+
// skip this script and the specs directory
|
|
26
|
+
if (filePath.replace(/\\/g, '/').includes('scripts/ci/check-mojibake.js')) return;
|
|
27
|
+
if (filePath.replace(/\\/g, '/').includes('specs/')) return;
|
|
28
|
+
if (filePath.replace(/\\/g, '/').endsWith('handoff.md')) {
|
|
29
|
+
// Just skip handoff as it also logs the spec content
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const content = fs.readFileSync(filePath, 'utf8');
|
|
34
|
+
if (mojibakePatterns.test(content)) {
|
|
35
|
+
console.error(`[FAIL] Mojibake detected in: ${path.relative(rootDir, filePath)}`);
|
|
36
|
+
hasError = true;
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
if (hasError) {
|
|
41
|
+
process.exit(1);
|
|
42
|
+
} else {
|
|
43
|
+
console.log('[OK] No mojibake detected.');
|
|
44
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
const { execSync } = require('child_process');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
|
|
4
|
+
try {
|
|
5
|
+
const rootDir = path.resolve(__dirname, '../../');
|
|
6
|
+
const output = execSync('npm pack --dry-run --json', { cwd: rootDir, encoding: 'utf8' });
|
|
7
|
+
const result = JSON.parse(output);
|
|
8
|
+
const files = result[0].files.map(f => f.path.replace(/\\/g, '/'));
|
|
9
|
+
|
|
10
|
+
const required = ['src/cli.js', 'template/handoff.md', 'README.md', 'LICENSE', 'CHANGELOG.md', 'RELEASE_NOTES.md', 'package.json'];
|
|
11
|
+
const forbidden = ['node_modules', 'securedocs.sqlite', 'demo-app/node_modules', '.git/', 'demo-app/securedocs.sqlite'];
|
|
12
|
+
|
|
13
|
+
let hasError = false;
|
|
14
|
+
for (const req of required) {
|
|
15
|
+
if (!files.some(f => f === req || f.startsWith(req))) {
|
|
16
|
+
console.error(`[FAIL] Package missing required file/folder: ${req}`);
|
|
17
|
+
hasError = true;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
for (const fbn of forbidden) {
|
|
21
|
+
if (files.some(f => f.includes(fbn))) {
|
|
22
|
+
console.error(`[FAIL] Package includes forbidden file/folder: ${fbn}`);
|
|
23
|
+
hasError = true;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (hasError) process.exit(1);
|
|
28
|
+
console.log('[OK] Package contents are valid.');
|
|
29
|
+
} catch (err) {
|
|
30
|
+
console.error('[FAIL] Error parsing package contents:', err.message);
|
|
31
|
+
process.exit(1);
|
|
32
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
|
|
4
|
+
const templateDir = path.resolve(__dirname, '../../template');
|
|
5
|
+
let hasError = false;
|
|
6
|
+
|
|
7
|
+
function walkDir(dir, callback) {
|
|
8
|
+
if (!fs.existsSync(dir)) return;
|
|
9
|
+
fs.readdirSync(dir).forEach(f => {
|
|
10
|
+
const dirPath = path.join(dir, f);
|
|
11
|
+
if (fs.statSync(dirPath).isDirectory()) walkDir(dirPath, callback);
|
|
12
|
+
else callback(dirPath);
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const forbiddenPatterns = [/node_modules/, /\.sqlite$/, /\.db$/, /\.tgz$/, /\.zip$/, /\.gemstack[\\\/]backups/, /temp dirs/, /\.log$/];
|
|
17
|
+
walkDir(templateDir, (filePath) => {
|
|
18
|
+
for (const pattern of forbiddenPatterns) {
|
|
19
|
+
if (pattern.test(filePath)) {
|
|
20
|
+
console.error(`[FAIL] Forbidden file found in template: ${filePath}`);
|
|
21
|
+
hasError = true;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
const handoffPath = path.join(templateDir, 'handoff.md');
|
|
27
|
+
if (fs.existsSync(handoffPath)) {
|
|
28
|
+
const content = fs.readFileSync(handoffPath, 'utf8');
|
|
29
|
+
if (!content.includes('1. Objetivo') || !content.includes('5. Próximos pasos')) {
|
|
30
|
+
console.error('[FAIL] template/handoff.md is missing required sections.');
|
|
31
|
+
hasError = true;
|
|
32
|
+
}
|
|
33
|
+
if (content.match(/[a-f0-9]{40}/)) {
|
|
34
|
+
console.error('[FAIL] template/handoff.md contains what looks like real git hashes.');
|
|
35
|
+
hasError = true;
|
|
36
|
+
}
|
|
37
|
+
} else {
|
|
38
|
+
console.error('[FAIL] template/handoff.md is missing.');
|
|
39
|
+
hasError = true;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (hasError) {
|
|
43
|
+
process.exit(1);
|
|
44
|
+
} else {
|
|
45
|
+
console.log('[OK] Template directory is clean.');
|
|
46
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
const { execSync } = require('child_process');
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const os = require('os');
|
|
5
|
+
|
|
6
|
+
function runSafe(cmd, cwd) {
|
|
7
|
+
try {
|
|
8
|
+
console.log(`Running: ${cmd}`);
|
|
9
|
+
execSync(cmd, { cwd, encoding: 'utf8', stdio: 'pipe' });
|
|
10
|
+
} catch (err) {
|
|
11
|
+
console.error(`[FAIL] Command failed: ${cmd}\n${err.stderr || err.message}`);
|
|
12
|
+
process.exit(1);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const rootDir = path.resolve(__dirname, '../../');
|
|
17
|
+
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'gemstack-smoke-'));
|
|
18
|
+
|
|
19
|
+
console.log(`[INFO] Smoke testing CLI in ${tmpDir}`);
|
|
20
|
+
|
|
21
|
+
runSafe(`node "${path.join(rootDir, 'src/cli.js')}" --help`, tmpDir);
|
|
22
|
+
runSafe(`node "${path.join(rootDir, 'src/cli.js')}" list`, rootDir);
|
|
23
|
+
runSafe(`node "${path.join(rootDir, 'src/cli.js')}" show gemstack-handoff`, rootDir);
|
|
24
|
+
runSafe(`node "${path.join(rootDir, 'src/cli.js')}" init --dry-run --target "${tmpDir}"`, tmpDir);
|
|
25
|
+
runSafe(`node "${path.join(rootDir, 'src/cli.js')}" init --yes --target "${tmpDir}"`, tmpDir);
|
|
26
|
+
runSafe(`node "${path.join(rootDir, 'src/cli.js')}" doctor --target "${tmpDir}"`, tmpDir);
|
|
27
|
+
runSafe(`node "${path.join(rootDir, 'src/cli.js')}" update --dry-run --target "${tmpDir}"`, tmpDir);
|
|
28
|
+
|
|
29
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
30
|
+
console.log('[OK] CLI Smoke tests passed.');
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Plan de Implementación: Release Automation (NPM & GitHub)
|
|
2
|
+
|
|
3
|
+
**Feature Branch**: `004-release-automation` | **Spec**: `specs/004-release-automation/spec.md`
|
|
4
|
+
|
|
5
|
+
## 1. Summary & Technical Context
|
|
6
|
+
Se implementará un workflow automatizado de CI/CD para publicar Gemstack en NPM y generar un GitHub Release al hacer push de un tag (`v*`).
|
|
7
|
+
|
|
8
|
+
- **Lenguaje/Versión**: YAML (GitHub Actions), Node.js 18+ y 20+.
|
|
9
|
+
- **Dependencias core**: Acciones de GitHub `actions/checkout@v4`, `actions/setup-node@v4` y `softprops/action-gh-release@v1` (o usando `gh` CLI directo).
|
|
10
|
+
- **Restricciones**: Las publicaciones deben ser idempotentes, seguras (Zero dependencies externas en nuestro runtime local), y se debe proveer protección contra errores de publicación si los tests fallan antes.
|
|
11
|
+
|
|
12
|
+
## 2. Constitution Check (Phase -1 Gates)
|
|
13
|
+
<!-- VERIFICACIÓN DE REGLAS INMUTABLES -->
|
|
14
|
+
### Simplicity Gate (Article VII)
|
|
15
|
+
- [x] ¿Se usan el mínimo número de carpetas/archivos posibles? *(Sí, un solo archivo `.yml` de workflow)*
|
|
16
|
+
- [x] ¿No hay abstracciones prematuras (future-proofing)? *(Se usarán las herramientas directas de npm y gh-cli)*
|
|
17
|
+
|
|
18
|
+
### Anti-Abstraction Gate (Article VIII)
|
|
19
|
+
- [x] ¿Se usan las APIs nativas del framework sin wrappers innecesarios? *(Usaremos `npm publish` nativo)*
|
|
20
|
+
|
|
21
|
+
### Test-First Imperative (Article III)
|
|
22
|
+
- [x] ¿El plan incluye la creación de tests antes que el código fuente? *(Como es automatización YAML, el test será probar con `--dry-run` o validar el parsing antes de la publicación real)*
|
|
23
|
+
|
|
24
|
+
## 3. Entregables Satélites a Generar
|
|
25
|
+
- `research.md`: [Opcional] No aplica (la tecnología de actions ya fue definida y documentada).
|
|
26
|
+
- `data-model.md`: No aplica.
|
|
27
|
+
- `contracts/`: No aplica.
|
|
28
|
+
- `quickstart.md`: No aplica.
|
|
29
|
+
|
|
30
|
+
## 4. Estructura de Archivos a Modificar / Crear
|
|
31
|
+
```text
|
|
32
|
+
.github/workflows/publish.yml: [NUEVO] Workflow para automatizar la publicación tras push de un tag.
|
|
33
|
+
package.json: [MODIFICAR] Opcional, configuración extra si necesitamos scripts de validación pre-publicación.
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Flujo Técnico en `publish.yml`
|
|
37
|
+
1. **Trigger**: `on: push: tags: - 'v*'`
|
|
38
|
+
2. **Setup**: Checkout del código, Setup de Node.js.
|
|
39
|
+
3. **CI Gate**: Ejecutar `npm run ci:all` para evitar publicar versiones defectuosas.
|
|
40
|
+
4. **NPM Publish**:
|
|
41
|
+
- Ejecutar `npm pack` (opcionalmente guardar el .tgz en var temporal).
|
|
42
|
+
- Configurar registry a `registry.npmjs.org` con `NODE_AUTH_TOKEN`.
|
|
43
|
+
- Ejecutar `npm publish --access public`.
|
|
44
|
+
5. **GitHub Release**:
|
|
45
|
+
- Usar comando `gh release create` o la acción oficial para crear el release.
|
|
46
|
+
- Apuntar el `body` (notas) a `RELEASE_NOTES.md`.
|
|
47
|
+
- Adjuntar el artefacto `.tgz` generado en el paso 4.
|
|
48
|
+
|
|
49
|
+
## 5. Complexity Tracking
|
|
50
|
+
| Violación de Regla | Por qué es necesario | Alternativa simple rechazada por |
|
|
51
|
+
|--------------------|----------------------|-----------------------------------|
|
|
52
|
+
| Ninguna | N/A | N/A |
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# Especificación de Funcionalidad: Release Automation (NPM & GitHub)
|
|
2
|
+
|
|
3
|
+
**Feature Branch**: `004-release-automation`
|
|
4
|
+
|
|
5
|
+
## 1. User Scenarios & Testing (MVP)
|
|
6
|
+
<!--
|
|
7
|
+
IMPORTANTE: Las historias de usuario deben estar PRIORIZADAS (P1, P2...).
|
|
8
|
+
Cada historia debe ser INDEPENDIENTEMENTE TESTEABLE, aportando un fragmento de valor MVP.
|
|
9
|
+
-->
|
|
10
|
+
### User Story 1 - Publicación Automatizada en NPM (Prioridad: P1)
|
|
11
|
+
Como mantenedor del framework Gemstack, quiero que el sistema publique automáticamente el paquete en el registro público de NPM cuando se apruebe una nueva versión.
|
|
12
|
+
**Por qué esta prioridad:** Reduce el error humano, estandariza los empaquetados y evita la necesidad de credenciales locales en las máquinas de los desarrolladores.
|
|
13
|
+
**Test Independiente:** Ejecutar el flujo de publicación con un flag dry-run (o hacia un registry de pruebas/local) y verificar que el paquete se empaqueta y publica correctamente.
|
|
14
|
+
|
|
15
|
+
**Escenarios de Aceptación:**
|
|
16
|
+
1. **Dado** que se ha configurado un token de NPM válido, **Cuando** se dispara el proceso de release, **Entonces** el paquete se publica en npmjs.com bajo el nombre correcto.
|
|
17
|
+
|
|
18
|
+
### User Story 2 - Generación de GitHub Releases (Prioridad: P2)
|
|
19
|
+
Como mantenedor del framework, quiero que el sistema cree automáticamente un "GitHub Release" formal asociado al tag de la versión, incluyendo las notas de lanzamiento y el artefacto (`tarball`).
|
|
20
|
+
**Por qué esta prioridad:** Mantiene a los usuarios informados sobre los cambios (Changelog) y centraliza la distribución segura de binarios o empaquetados históricos.
|
|
21
|
+
**Test Independiente:** Disparar la acción y validar que aparece un Release en la pestaña de Releases de GitHub con el texto correcto extraído de las notas.
|
|
22
|
+
|
|
23
|
+
**Escenarios de Aceptación:**
|
|
24
|
+
1. **Dado** un nuevo tag de versión en el repositorio, **Cuando** se ejecuta la automatización, **Entonces** se crea un Release en GitHub adjuntando el `gemstack-x.y.z.tgz`.
|
|
25
|
+
|
|
26
|
+
## 2. Requerimientos Funcionales
|
|
27
|
+
<!--
|
|
28
|
+
Anota requerimientos explícitos.
|
|
29
|
+
SI HAY AMBIGÜEDAD, NO ADIVINES. Usa: [NEEDS CLARIFICATION: tu pregunta]
|
|
30
|
+
-->
|
|
31
|
+
- **FR-001**: El sistema DEBE empaquetar el framework de forma limpia y publicarlo en NPM.
|
|
32
|
+
- **FR-002**: El sistema DEBE generar un GitHub Release adjuntando el código fuente y el `tarball` empaquetado.
|
|
33
|
+
- **FR-003**: El flujo DEBE dispararse automáticamente cuando se empuja al repositorio un tag semántico de Git (ej. `git push origin v0.4.0`).
|
|
34
|
+
- **FR-004**: El GitHub Release DEBE crearse en estado de Publicado (Published) inmediatamente para maximizar la automatización.
|
|
35
|
+
- **FR-005**: Se DEBE utilizar el contenido del archivo `RELEASE_NOTES.md` como cuerpo (body) del GitHub Release.
|
|
36
|
+
|
|
37
|
+
## 3. Criterios de Éxito (Measurable Outcomes)
|
|
38
|
+
<!-- Definir métricas que no dependan de la tecnología -->
|
|
39
|
+
- **SC-001**: El proceso de release completo requiere cero comandos manuales de `npm publish` en las computadoras de los desarrolladores.
|
|
40
|
+
- **SC-002**: El tiempo desde la aprobación del release hasta la disponibilidad pública en NPM y GitHub es inferior a 5 minutos.
|
|
41
|
+
|
|
42
|
+
## 4. Casos Extremos (Edge Cases)
|
|
43
|
+
- ¿Qué pasa si la versión declarada en `package.json` ya existe en el registro público de NPM (colisión de versiones)?
|
|
44
|
+
- ¿Qué pasa si el NPM_TOKEN ha expirado o no tiene permisos de publicación?
|
|
45
|
+
- ¿Qué pasa si las pruebas de integración (`ci:all`) fallan justo antes de intentar publicar?
|
|
46
|
+
|
|
47
|
+
## 5. Entidades Clave (Data / Models)
|
|
48
|
+
- **[NPM Registry]**: Sistema de distribución público donde vivirá el paquete.
|
|
49
|
+
- **[GitHub Release]**: Entidad oficial del repositorio que enlaza un tag, un commit, notas de texto y archivos (assets).
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Tareas de Implementación
|
|
2
|
+
|
|
3
|
+
<!--
|
|
4
|
+
Instrucciones:
|
|
5
|
+
- Marca con `[P]` las tareas que sean seguras de paralelizar (por ej. si usas múltiples subagentes).
|
|
6
|
+
- Incluye la redacción y validación de TESTS ANTES de la implementación real.
|
|
7
|
+
-->
|
|
8
|
+
|
|
9
|
+
## Fase 1: Pruebas y Validación (Test-First Imperative)
|
|
10
|
+
- [x] 1.1 Redactar prueba de validación sintáctica YAML para el nuevo workflow (`publish.yml`) usando `actionlint` o similar, o al menos validar la estructura estáticamente.
|
|
11
|
+
- [x] 1.2 [P] Validar localmente (dry-run) que `npm pack` genera el empaquetado esperado sin errores antes de la publicación remota.
|
|
12
|
+
- [x] 1.3 Comprobar que los tests fallen (Fase Roja) - en este contexto, asegurarse de que sin el YAML, el CI no reacciona a los tags.
|
|
13
|
+
|
|
14
|
+
## Fase 2: Implementación
|
|
15
|
+
- [x] 2.1 Crear archivo `.github/workflows/publish.yml`.
|
|
16
|
+
- [x] 2.2 Configurar el trigger para `on: push: tags: ['v*']`.
|
|
17
|
+
- [x] 2.3 Añadir trabajo `publish` que ejecute `actions/checkout` y configure Node.js usando la caché de NPM.
|
|
18
|
+
- [x] 2.4 Añadir paso de compuerta de seguridad: ejecución de `npm run ci:all`.
|
|
19
|
+
- [x] 2.5 Añadir paso para ejecutar `npm publish --access public` usando `NODE_AUTH_TOKEN`.
|
|
20
|
+
- [x] 2.6 Añadir paso para capturar el nombre del `.tgz` empaquetado y ejecutar `gh release create` usando el CLI nativo, adjuntando el changelog desde `RELEASE_NOTES.md`.
|
|
21
|
+
|
|
22
|
+
## Fase 3: Integración y Validación
|
|
23
|
+
- [x] 3.1 Revisar permisos del token de GitHub (asegurar que el GITHUB_TOKEN tenga permisos de escritura `contents: write` para crear releases).
|
|
24
|
+
- [x] 3.2 Marcar los cambios, hacer commit bajo la rama actual y fusionar a main.
|
|
25
|
+
- [x] 3.3 Revisión de seguridad y dependencias (CSO).
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Plan de Implementación: The "WOW" Update
|
|
2
|
+
|
|
3
|
+
**Feature Branch**: `005-the-wow-update` | **Spec**: `specs/005-the-wow-update/spec.md`
|
|
4
|
+
|
|
5
|
+
## 1. Summary & Technical Context
|
|
6
|
+
Se introducirán 4 nuevas capacidades de autonomía extrema en el motor de Gemstack: QA Visual (`/qa-visual`), Swarm Multiplexing (`/swarm`), Auto-Sanación CI/CD (`/heal`) y Seguridad de Contenedores (`/sandbox`). Esto se implementa añadiendo los SKILLs correspondientes.
|
|
7
|
+
|
|
8
|
+
- **Lenguaje/Versión**: Markdown + YAML (Arquitectura SDD nativa del agente).
|
|
9
|
+
- **Dependencias core**: Ninguna adicional localmente. (Docker, Playwright y CLI de GitHub se asumen como externos si la IA los necesita).
|
|
10
|
+
|
|
11
|
+
## 2. Constitution Check (Phase -1 Gates)
|
|
12
|
+
### Simplicity Gate (Article VII)
|
|
13
|
+
- [x] ¿Se usan el mínimo número de carpetas/archivos posibles? *(Sí, un archivo de skill MD por feature).*
|
|
14
|
+
### Anti-Abstraction Gate (Article VIII)
|
|
15
|
+
- [x] ¿Se usan las APIs nativas del framework sin wrappers innecesarios? *(Los skills orquestarán comandos nativos).*
|
|
16
|
+
### Test-First Imperative (Article III)
|
|
17
|
+
- [x] ¿El plan incluye la creación de tests antes que el código fuente? *(Como es configuración AI, el framework central verificará la inicialización de estos nuevos skills).*
|
|
18
|
+
|
|
19
|
+
## 3. Entregables Satélites a Generar
|
|
20
|
+
- No aplican modelos de datos nuevos.
|
|
21
|
+
|
|
22
|
+
## 4. Estructura de Archivos a Modificar / Crear
|
|
23
|
+
```text
|
|
24
|
+
.agents/rules/01-gemstack-core.md: [MODIFICADO] Añadir mapeo de nuevos comandos.
|
|
25
|
+
.agents/skills/gemstack-qa-visual/SKILL.md: [NUEVO] Skill.
|
|
26
|
+
.agents/skills/gemstack-swarm/SKILL.md: [NUEVO] Skill.
|
|
27
|
+
.agents/skills/gemstack-heal/SKILL.md: [NUEVO] Skill.
|
|
28
|
+
.agents/skills/gemstack-sandbox/SKILL.md: [NUEVO] Skill.
|
|
29
|
+
```
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Especificación de Funcionalidad: The "WOW" Update (Autonomía Avanzada)
|
|
2
|
+
|
|
3
|
+
**Feature Branch**: `005-the-wow-update`
|
|
4
|
+
|
|
5
|
+
## 1. User Scenarios & Testing (MVP)
|
|
6
|
+
|
|
7
|
+
### User Story 1 - QA Visual Autónomo (P1)
|
|
8
|
+
Como desarrollador, quiero invocar `/qa-visual` para que la IA genere y ejecute scripts de UI testing en un sandbox, verificando visualmente los Criterios de Aceptación.
|
|
9
|
+
**Test Independiente**: Ejecutar `/qa-visual` en un proyecto con frontend simulado y obtener un reporte de QA basado en interacción DOM.
|
|
10
|
+
|
|
11
|
+
### User Story 2 - Enjambre de Subagentes (Swarm) (P1)
|
|
12
|
+
Como líder técnico, quiero que el comando `/tasks` delegue automáticamente las tareas marcadas con `[P]` a múltiples subagentes paralelos para reducir el tiempo de implementación.
|
|
13
|
+
**Test Independiente**: Procesar un `tasks.md` con 2 tareas `[P]`, verificando que se invocan subagentes en paralelo.
|
|
14
|
+
|
|
15
|
+
### User Story 3 - Auto-Sanación de CI/CD (P2)
|
|
16
|
+
Como mantenedor, quiero invocar `/heal` cuando un workflow de GitHub falle, para que el agente lea los logs, repare el código y haga un push automáticamente.
|
|
17
|
+
**Test Independiente**: Romper un test a propósito, subirlo, esperar que falle CI y correr `/heal` para ver cómo se auto-repara.
|
|
18
|
+
|
|
19
|
+
### User Story 4 - Ejecución Segura en Sandbox (P2)
|
|
20
|
+
Como ingeniero de seguridad, quiero usar `/sandbox` para aislar pruebas de dependencias dudosas dentro de un contenedor Docker efímero.
|
|
21
|
+
**Test Independiente**: Ejecutar un test con `/sandbox` y confirmar que corre dentro de un contenedor de Node.js sin acceso al host raíz.
|
|
22
|
+
|
|
23
|
+
## 2. Requerimientos Funcionales
|
|
24
|
+
- **FR-001**: Añadir skill `gemstack-qa-visual`.
|
|
25
|
+
- **FR-002**: Añadir skill `gemstack-swarm` y actualizar `gemstack-tasks` para orquestar `invoke_subagent`.
|
|
26
|
+
- **FR-003**: Añadir skill `gemstack-heal` que consuma logs vía CLI (`gh run view`).
|
|
27
|
+
- **FR-004**: Añadir skill `gemstack-sandbox` que use `docker run`.
|
|
28
|
+
- **FR-005**: Registrar todos los comandos en `01-gemstack-core.md`.
|
|
29
|
+
|
|
30
|
+
## 3. Criterios de Éxito (Measurable Outcomes)
|
|
31
|
+
- **SC-001**: El framework soporta delegación multiproceso nativa.
|
|
32
|
+
- **SC-002**: El flujo de resolución de bugs de CI pasa de requerir intervención humana a requerir solo 1 comando (`/heal`).
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Tareas de Implementación
|
|
2
|
+
|
|
3
|
+
## Fase 1: Pruebas y Validación (Test-First Imperative)
|
|
4
|
+
- [x] 1.1 Verificar que `01-gemstack-core.md` y la estructura base soportan nuevos skills sin fallar el CLI.
|
|
5
|
+
|
|
6
|
+
## Fase 2: Implementación
|
|
7
|
+
- [x] 2.1 Mapear los comandos `/qa-visual`, `/swarm`, `/heal`, `/sandbox` en `01-gemstack-core.md`.
|
|
8
|
+
- [x] 2.2 Crear `.agents/skills/gemstack-qa-visual/SKILL.md`.
|
|
9
|
+
- [x] 2.3 Crear `.agents/skills/gemstack-swarm/SKILL.md`.
|
|
10
|
+
- [x] 2.4 Crear `.agents/skills/gemstack-heal/SKILL.md`.
|
|
11
|
+
- [x] 2.5 Crear `.agents/skills/gemstack-sandbox/SKILL.md`.
|
|
12
|
+
|
|
13
|
+
## Fase 3: Integración y Validación
|
|
14
|
+
- [x] 3.1 Sincronizar todos los archivos modificados hacia la carpeta de distribución `template/`.
|
|
15
|
+
- [x] 3.2 Ejecutar `npm run ci:all` para garantizar que la nueva estructura no corrompe la inicialización.
|
|
16
|
+
- [ ] 3.3 Hacer commit bajo la rama actual.
|
package/specs/README.md
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# Spec-Driven Development (SDD) en Gemstack
|
|
2
|
+
|
|
3
|
+
Este directorio maneja el flujo de diseño antes del código.
|
|
4
|
+
|
|
5
|
+
## `specs/current/`
|
|
6
|
+
Aquí residen los documentos de la funcionalidad en desarrollo actual. Siempre deben estar sincronizados.
|
|
7
|
+
- `spec.md`: El "Qué" y "Por qué".
|
|
8
|
+
- `plan.md`: El diseño técnico ("Cómo").
|
|
9
|
+
- `tasks.md`: El desglose ejecutable.
|
|
10
|
+
|
|
11
|
+
## `specs/templates/`
|
|
12
|
+
Contiene las plantillas base utilizadas por los skills `/specify`, `/plan` y `/tasks` para inicializar los documentos en `current/`.
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# Plan Técnico: Gemstack v0.3 (CI/CD & Release Automation)
|
|
2
|
+
|
|
3
|
+
## 1. Arquitectura de Workflows
|
|
4
|
+
El sistema de CI/CD constará de dos archivos YAML independientes en `.github/workflows/`:
|
|
5
|
+
1. `ci.yml`: Encargado de la validación continua para proteger la rama principal (`main`).
|
|
6
|
+
2. `release.yml`: Encargado del empaquetado, pruebas reales sobre el tarball y preparación de release artifacts (solo manual).
|
|
7
|
+
|
|
8
|
+
## 2. Jobs, Triggers y Matrix Strategy
|
|
9
|
+
|
|
10
|
+
### A. CI Workflow (`ci.yml`)
|
|
11
|
+
- **Triggers:** `push` a ramas (idealmente con target main) y `pull_request`.
|
|
12
|
+
- **Estrategia Matrix Condicional:**
|
|
13
|
+
- **Quick-CI Job:** Se dispara en `pull_request` y `push` normal. Matrix: `ubuntu-latest`, Node `[18.x, 20.x]`.
|
|
14
|
+
- **Full-CI Job:** Se dispara solo en `push` directo a `main`. Matrix: `[ubuntu-latest, windows-latest, macos-latest]`, Node `[18.x, 20.x]`.
|
|
15
|
+
- **Pasos:** Checkout -> Setup Node -> Run CI Scripts -> Run Native Tests -> Run Demo App Smoke.
|
|
16
|
+
|
|
17
|
+
### B. Release Readiness Workflow (`release.yml`)
|
|
18
|
+
- **Trigger:** `workflow_dispatch` (Manual).
|
|
19
|
+
- **Matrix:** `[ubuntu-latest, windows-latest]`, Node `[20.x]`.
|
|
20
|
+
- **Pasos:** Checkout -> Setup Node -> Tests & CI Scripts -> `npm pack` -> Test Dummy Tarball -> Upload Artifact (`gemstack-*.tgz`).
|
|
21
|
+
- **Restricción Estricta:** NO habrá paso de `npm publish` ni tag automation.
|
|
22
|
+
|
|
23
|
+
## 3. Scripts CI Propuestos (`scripts/ci/`)
|
|
24
|
+
Se implementarán 5 scripts Zero-Deps nativos de Node.js que fallarán la ejecución (`process.exit(1)`) si se violan las reglas:
|
|
25
|
+
|
|
26
|
+
1. **`check-frontmatter.js`**: Lee `.agents/skills/*/SKILL.md`. Parsea el bloque YAML superior delimitado por `---`. Valida propiedades requeridas (`name`, `description`, `triggers` como array no vacío) y que el `name` coincida con el nombre del directorio padre.
|
|
27
|
+
2. **`check-template-clean.js`**: Revisa recursivamente `template/`. Valida que `handoff.md` tenga las 5 secciones, `state.json` no tenga flags privadas. Asegura la total ausencia de `node_modules`, `sqlite`, `tgz`, `.gemstack/backups/` o archivos ajenos.
|
|
28
|
+
3. **`check-mojibake.js`**: Analiza todos los textos y scripts en búsqueda exclusiva de cadenas asociadas a error UTF-8 como `Ã`, `Â`, `âœ`, `ðŸ`, y el replacement character ``. Permite acentos normativos en español (`áéíóúñ`).
|
|
29
|
+
4. **`check-package-contents.js`**: Llama a `npm pack --dry-run --json` o parsea la salida de consola, garantizando la inclusión de `src/`, `template/`, `README.md`, `LICENSE`, `CHANGELOG.md`, `package.json`, y la omisión estricta de bases de datos de la demo o configuraciones de github.
|
|
30
|
+
5. **`smoke-cli.js`**: Recrea programáticamente el uso real. Crea un temp dir con `fs.mkdtempSync`, ejecuta llamadas a `node src/cli.js` probando `--help`, `list`, `show`, `doctor`, `init --dry-run`, `init --yes` y `update --dry-run`.
|
|
31
|
+
|
|
32
|
+
## 4. Manejo de Line Endings
|
|
33
|
+
Se añadirá un `.gitattributes` conservador para forzar terminaciones en el checkout y commit, protegiendo los hashes SHA-256 de ser adulterados por Git en Windows:
|
|
34
|
+
```text
|
|
35
|
+
* text=auto
|
|
36
|
+
*.js text eol=lf
|
|
37
|
+
*.json text eol=lf
|
|
38
|
+
*.md text eol=lf
|
|
39
|
+
*.yml text eol=lf
|
|
40
|
+
*.yaml text eol=lf
|
|
41
|
+
*.sh text eol=lf
|
|
42
|
+
*.ps1 text eol=crlf
|
|
43
|
+
*.bat text eol=crlf
|
|
44
|
+
*.cmd text eol=crlf
|
|
45
|
+
|
|
46
|
+
*.png binary
|
|
47
|
+
*.jpg binary
|
|
48
|
+
*.jpeg binary
|
|
49
|
+
*.gif binary
|
|
50
|
+
*.ico binary
|
|
51
|
+
*.sqlite binary
|
|
52
|
+
*.db binary
|
|
53
|
+
*.tgz binary
|
|
54
|
+
*.zip binary
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## 5. Tarball Validation (`release.yml`)
|
|
58
|
+
1. Generar `.tgz` con `npm pack`.
|
|
59
|
+
2. Crear un temp dir (fuera del workspace de github).
|
|
60
|
+
3. `cd temp-dir && npm init -y && npm install <path-to-tgz>`.
|
|
61
|
+
4. Ejecutar comandos `npx gemstack` (`--help`, `init`, `doctor`, `update`).
|
|
62
|
+
5. Tras el test exitoso, subir el `.tgz` con la acción `actions/upload-artifact`.
|
|
63
|
+
|
|
64
|
+
## 6. Demo-app Smoke Strategy
|
|
65
|
+
Un job independiente o un step correrá:
|
|
66
|
+
`cd demo-app && npm install && npm run smoke`. Confirmará la salida exitosa del servidor y su bloqueo IDOR, validando que cambios genéricos en el framework no han roto la app de referencia.
|
|
67
|
+
|
|
68
|
+
## 7. README Badge Strategy
|
|
69
|
+
Se ubicará un badge oficial estándar en `README.md`, inmediatamente debajo del título principal, enrutado al action de CI de `main`.
|
|
70
|
+
|
|
71
|
+
## 8. Seguridad, Secrets y Logging
|
|
72
|
+
- Se forzará la asignación de permisos `permissions: contents: read` en los Workflows para prevenir writes accidentales al repositorio por cuenta del GITHUB_TOKEN.
|
|
73
|
+
- Los logs limitarán las salidas de variables de entorno u operacionales. No se invocarán scripts que tiren volcados de memoria masivos.
|
|
74
|
+
|
|
75
|
+
## 9. Test Plan
|
|
76
|
+
- Se creará un branch temporal para probar empíricamente los flujos de GitHub actions (`ci.yml`) insertando fallos intencionales (ej. introducir un mojibake adrede) y observando el bloqueo, para finalmente revertir y subir limpio.
|
|
77
|
+
|
|
78
|
+
## 10. Riesgos Principales
|
|
79
|
+
1. **Conflicto Line Endings Activos:** Instaurar un `.gitattributes` retrospectivo forzará la re-normalización del repo si hay archivos existentes en CRLF. Esto podría generar diffs falsos la próxima vez que se haga checkout.
|
|
80
|
+
2. **Dependencias del Smoke CLI:** El script de humo interactuando con procesos hijos en Windows puede quedar huérfano (zombie) si los subprocesos de Node no se terminan limpiamente tras error.
|
|
81
|
+
|
|
82
|
+
## 11. Decisiones Pendientes antes de /tasks
|
|
83
|
+
- **Implementación Matrix Condicional:** En GitHub Actions no se puede tener un array matricial "dinámico" trivial. Lo más limpio es dividir `ci.yml` en dos flujos/jobs explícitos: un Workflow para PRs (Ubuntu) y otro Workflow para Pushes (Full Matrix). ¿Autorizas crear dos YAMLs (`pr-ci.yml` y `main-ci.yml`) o mantenemos un solo YAML con jobs condicionados mediante `if: github.event_name == 'pull_request'`?
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Spec: Gemstack v0.3 (CI/CD & Release Automation)
|
|
2
|
+
|
|
3
|
+
## 1. Goal
|
|
4
|
+
Diseñar e implementar un sistema robusto de integración y entrega continua (CI/CD) utilizando GitHub Actions para validar y proteger la calidad de Gemstack en cada cambio, asegurando compatibilidad multiplataforma y previniendo el filtrado accidental de secretos o contextos privados, todo esto sin habilitar despliegues automatizados no supervisados (ej. `npm publish`).
|
|
5
|
+
|
|
6
|
+
## 2. Core Requirements
|
|
7
|
+
|
|
8
|
+
### 2.1. Workflows
|
|
9
|
+
Se dividirán las responsabilidades lógicas en, idealmente, dos flujos:
|
|
10
|
+
1. **CI Normal (Push / PR):** Validaciones exhaustivas que bloquean la integración de código roto o contaminado.
|
|
11
|
+
2. **Release Readiness (Workflow Dispatch):** Flujo de preparación manual que empaca el proyecto y potencialmente crea un GitHub Release, pero que bajo ninguna circunstancia ejecuta `npm publish`.
|
|
12
|
+
|
|
13
|
+
### 2.2. Matrix Testing
|
|
14
|
+
- **Sistemas Operativos:** `ubuntu-latest`, `windows-latest`, `macos-latest`.
|
|
15
|
+
- **Node.js Versions:** `18.18.0` (mínimo exigido) y `20.x` (LTS actual) / `22.x` (Latest).
|
|
16
|
+
|
|
17
|
+
### 2.3. CI Validation Steps (Checks)
|
|
18
|
+
- **Unit & Packaging Tests:**
|
|
19
|
+
- `npm test` (pruebas nativas).
|
|
20
|
+
- `npm run pack:dry` (validación del bundle).
|
|
21
|
+
- **CLI Smoke Tests (Cross-platform):**
|
|
22
|
+
- `node src/cli.js --help`
|
|
23
|
+
- `node src/cli.js list`
|
|
24
|
+
- `node src/cli.js show gemstack-handoff`
|
|
25
|
+
- `node src/cli.js init --dry-run --target <temp-dir>`
|
|
26
|
+
- `node src/cli.js init --yes --target <temp-dir>`
|
|
27
|
+
- `node src/cli.js update --dry-run --target <temp-dir>`
|
|
28
|
+
- **Demo App Verification:**
|
|
29
|
+
- `cd demo-app && npm install`
|
|
30
|
+
- `npm run smoke` (valida defensas anti-IDOR).
|
|
31
|
+
- **Cleanliness & Integrity Assertions:**
|
|
32
|
+
- **No Forbidden Files:** Asegurar que el repo (y el paquete) no contengan `node_modules`, `*.sqlite`, `*.tgz`, backups (`.gemstack/backups/`) o archivos temporales no ignorados.
|
|
33
|
+
- **Package Contents:** Analizar la salida del tarball para confirmar ausencia de assets restringidos.
|
|
34
|
+
- **YAML Frontmatter:** Analizar todos los `.agents/skills/*/SKILL.md` asegurando que el YAML inicial es sintácticamente válido.
|
|
35
|
+
- **Template Sandbox:** Comprobar que `template/handoff.md`, `template/handoff_archive.md` y `template/.gemstack/state.json` contengan estados limpios y no el texto real de la memoria de Gemstack.
|
|
36
|
+
- **No Mojibake:** Búsqueda simple de caracteres rotos (ej. `ó`) en docs/scripts que indican falla de encoding.
|
|
37
|
+
|
|
38
|
+
### 2.4. Seguridad y Caching
|
|
39
|
+
- Configurar cachés seguros para Node Modules de la `demo-app` (`actions/cache`).
|
|
40
|
+
- Activar enmascaramiento automático de salidas y uso estricto de secretos (`${{ secrets.GITHUB_TOKEN }}`).
|
|
41
|
+
- Deshabilitar triggers automáticos de publicación en NPM.
|
|
42
|
+
|
|
43
|
+
### 2.5. Artifacts y Badges
|
|
44
|
+
- **Artifacts:** Se subirá el archivo `gemstack-*.tgz` resultante de un `npm pack` como un Build Artifact para ser descargable desde la tab de Actions.
|
|
45
|
+
- **Badges:** Se añadirá el Badge dinámico de GitHub Actions en el `README.md`.
|
|
46
|
+
|
|
47
|
+
## 3. Edge Cases & Risks
|
|
48
|
+
- **Diferencias de File System (Windows vs Unix):** El manejo de rutas relativas y saltos de línea (CRLF vs LF) puede fallar las validaciones de checksum en Git o CI si no están configurados los `.gitattributes`.
|
|
49
|
+
- **Rutas Largas en Windows:** `npm` a veces sufre en Windows con anidamientos profundos, los paths de los tests temporales deben ser cortos.
|
|
50
|
+
- **Falsos Positivos en la Verificación de "Mojibake":** Restringir la validación de encoding a patrones conocidos (`Ã`, ``) sin bloquear caracteres legítimos en UTF-8 o en español.
|
|
51
|
+
|
|
52
|
+
## 4. Acceptance Criteria
|
|
53
|
+
- Todos los Pull Requests hacia `main` disparan el flujo CI.
|
|
54
|
+
- Los tests corren en las 3 plataformas y 2 versiones de Node de forma paralela.
|
|
55
|
+
- Cualquier detección de un archivo `.sqlite` o `handoff.md` sucio en la carpeta `template/` rompe automáticamente el build.
|
|
56
|
+
- Existe un trigger manual que genera un `.tgz` y lo adjunta como Release Draft en GitHub.
|
|
57
|
+
- NPM Publish no está configurado de forma autónoma.
|