@cristiancorreau/forge 3.0.1 → 3.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.
Files changed (96) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/README.md +265 -109
  3. package/assets/adapters/claude-code/commands/laravel-eloquent.md +7 -0
  4. package/assets/adapters/claude-code/commands/laravel-mcp.md +7 -0
  5. package/assets/adapters/claude-code/commands/laravel-pest.md +7 -0
  6. package/assets/adapters/claude-code/commands/laravel-security.md +7 -0
  7. package/assets/adapters/claude-code/commands/laravel-verify.md +7 -0
  8. package/assets/core/hooks/pre-bash-check.js +46 -0
  9. package/assets/core/hooks/pre-edit-check.js +24 -1
  10. package/assets/core/schemas/project.schema.json +3 -1
  11. package/assets/core/skills/laravel-eloquent/SKILL.md +453 -0
  12. package/assets/core/skills/laravel-mcp/SKILL.md +468 -0
  13. package/assets/core/skills/laravel-pest/SKILL.md +686 -0
  14. package/assets/core/skills/laravel-security/SKILL.md +658 -0
  15. package/assets/core/skills/laravel-verify/SKILL.md +462 -0
  16. package/assets/manifest.json +27 -2
  17. package/assets/profiles/astro/agents/frontend-engineer.md +2 -0
  18. package/assets/profiles/django/agents/api-engineer.md +2 -0
  19. package/assets/profiles/expo/agents/mobile-engineer.md +2 -0
  20. package/assets/profiles/express/agents/api-engineer.md +2 -0
  21. package/assets/profiles/fastapi/agents/api-engineer.md +2 -0
  22. package/assets/profiles/flask/agents/api-engineer.md +2 -0
  23. package/assets/profiles/flutter/agents/mobile-engineer.md +12 -10
  24. package/assets/profiles/go-gin/agents/api-engineer.md +3 -1
  25. package/assets/profiles/hono-drizzle/agents/api-engineer.md +2 -0
  26. package/assets/profiles/laravel/README.md +16 -2
  27. package/assets/profiles/laravel/agents/api-engineer.md +2 -0
  28. package/assets/profiles/laravel/agents/fullstack-engineer.md +4 -2
  29. package/assets/profiles/laravel/agents/laravel-specialist.md +607 -0
  30. package/assets/profiles/laravel/agents/laravel-test-engineer.md +448 -0
  31. package/assets/profiles/nestjs/agents/api-engineer.md +3 -1
  32. package/assets/profiles/nextjs-admin/agents/admin-engineer.md +2 -0
  33. package/assets/profiles/playwright-crawler/agents/scanner-engineer.md +2 -0
  34. package/assets/profiles/rails/agents/fullstack-engineer.md +2 -0
  35. package/assets/profiles/rust/agents/api-engineer.md +2 -0
  36. package/assets/profiles/springboot/agents/api-engineer.md +11 -9
  37. package/assets/profiles/sveltekit/agents/frontend-engineer.md +4 -2
  38. package/assets/profiles/vuenuxt/agents/frontend-engineer.md +12 -10
  39. package/assets/profiles/wordpress/agents/divi-engineer.md +2 -0
  40. package/assets/profiles/wordpress/agents/elementor-engineer.md +2 -0
  41. package/dist/cli.js +15 -0
  42. package/dist/cli.js.map +1 -1
  43. package/dist/commands/add.d.ts +2 -0
  44. package/dist/commands/add.d.ts.map +1 -0
  45. package/dist/commands/add.js +187 -0
  46. package/dist/commands/add.js.map +1 -0
  47. package/dist/commands/mcp.d.ts +42 -0
  48. package/dist/commands/mcp.d.ts.map +1 -0
  49. package/dist/commands/mcp.js +141 -0
  50. package/dist/commands/mcp.js.map +1 -0
  51. package/dist/commands/update.d.ts +30 -0
  52. package/dist/commands/update.d.ts.map +1 -0
  53. package/dist/commands/update.js +180 -0
  54. package/dist/commands/update.js.map +1 -0
  55. package/dist/commands/validate.d.ts.map +1 -1
  56. package/dist/commands/validate.js +40 -1
  57. package/dist/commands/validate.js.map +1 -1
  58. package/dist/lib/catalog.d.ts +7 -0
  59. package/dist/lib/catalog.d.ts.map +1 -1
  60. package/dist/lib/catalog.js +20 -0
  61. package/dist/lib/catalog.js.map +1 -1
  62. package/dist/lib/mcp-tools.d.ts +37 -0
  63. package/dist/lib/mcp-tools.d.ts.map +1 -0
  64. package/dist/lib/mcp-tools.js +124 -0
  65. package/dist/lib/mcp-tools.js.map +1 -0
  66. package/dist/lib/skill-security.d.ts +66 -0
  67. package/dist/lib/skill-security.d.ts.map +1 -0
  68. package/dist/lib/skill-security.js +225 -0
  69. package/dist/lib/skill-security.js.map +1 -0
  70. package/dist/lib/skill-source.d.ts +29 -0
  71. package/dist/lib/skill-source.d.ts.map +1 -0
  72. package/dist/lib/skill-source.js +94 -0
  73. package/dist/lib/skill-source.js.map +1 -0
  74. package/dist/tui/dashboard.d.ts.map +1 -1
  75. package/dist/tui/dashboard.js +3 -6
  76. package/dist/tui/dashboard.js.map +1 -1
  77. package/dist/tui/panel.d.ts.map +1 -1
  78. package/dist/tui/panel.js +3 -6
  79. package/dist/tui/panel.js.map +1 -1
  80. package/dist/tui/wizard.d.ts.map +1 -1
  81. package/dist/tui/wizard.js +3 -13
  82. package/dist/tui/wizard.js.map +1 -1
  83. package/dist/ui/colors.d.ts +3 -1
  84. package/dist/ui/colors.d.ts.map +1 -1
  85. package/dist/ui/colors.js +11 -2
  86. package/dist/ui/colors.js.map +1 -1
  87. package/dist/ui/header.d.ts.map +1 -1
  88. package/dist/ui/header.js +4 -3
  89. package/dist/ui/header.js.map +1 -1
  90. package/dist/ui/theme.d.ts +24 -0
  91. package/dist/ui/theme.d.ts.map +1 -0
  92. package/dist/ui/theme.js +32 -0
  93. package/dist/ui/theme.js.map +1 -0
  94. package/dist/version.d.ts +1 -1
  95. package/dist/version.js +1 -1
  96. package/package.json +2 -2
@@ -0,0 +1,180 @@
1
+ import { existsSync, copyFileSync, mkdirSync } from 'fs';
2
+ import { join, dirname } from 'path';
3
+ import { findProjectYaml, projectRoot } from '../lib/yaml.js';
4
+ import { resolveForgeRoot } from '../lib/paths.js';
5
+ import { loadManifest, saveManifest, sha256file } from '../lib/lock.js';
6
+ import { listCatalogAgents } from '../lib/catalog.js';
7
+ import { VERSION } from '../version.js';
8
+ import { dim } from '../ui/colors.js';
9
+ const HELP = `Usage: forge update [options]
10
+
11
+ Update forge-managed files in the current project to the bundled catalog version.
12
+ Reads .forge/manifest.json, and for each managed file compares the on-disk hash
13
+ (did you edit it?) against the install-time hash and the current catalog source.
14
+
15
+ - Files you did NOT modify are updated when the catalog source differs.
16
+ - Files you modified are SKIPPED with a warning (use --force to overwrite).
17
+ - Generated files (CLAUDE.md, settings.json, architecture.rules) and files
18
+ without a 1:1 catalog source are never touched.
19
+ - The manifest is rewritten with the new install-time hashes for updated files.
20
+
21
+ Options:
22
+ --dry-run Show the plan without writing any files
23
+ --force Overwrite user-modified files too
24
+ -h, --help Show this help
25
+ `;
26
+ /**
27
+ * Files that forge GENERATES (not copied 1:1 from a catalog asset). They have no
28
+ * single source file to diff against, so `forge update` never touches them.
29
+ */
30
+ const GENERATED_FILES = new Set([
31
+ 'CLAUDE.md',
32
+ '.claude/settings.json',
33
+ '.claude/architecture.rules',
34
+ 'AGENTS.md',
35
+ ]);
36
+ /**
37
+ * Maps a managed file's project-relative path (as stored in the manifest) to its
38
+ * source path inside the forge catalog (forgeRoot). Returns null when the file is
39
+ * generated or has no 1:1 catalog source (e.g. a Tier 3 project-specific agent
40
+ * that doesn't live in core/agents/ or any profile's agents/ dir).
41
+ *
42
+ * Mapping:
43
+ * .claude/hooks/<f> -> core/hooks/<f>
44
+ * .claude/commands/<...> -> adapters/claude-code/commands/<...>
45
+ * .claude/agents/<f>.md -> core/agents/<f>.md OR a profile's agents/ dir
46
+ */
47
+ export function resolveCatalogSource(relPath, forgeRoot) {
48
+ const norm = relPath.split('\\').join('/');
49
+ if (GENERATED_FILES.has(norm))
50
+ return null;
51
+ if (norm.startsWith('.claude/hooks/')) {
52
+ const rest = norm.slice('.claude/hooks/'.length);
53
+ return join(forgeRoot, 'core', 'hooks', rest);
54
+ }
55
+ if (norm.startsWith('.claude/commands/')) {
56
+ const rest = norm.slice('.claude/commands/'.length);
57
+ return join(forgeRoot, 'adapters', 'claude-code', 'commands', rest);
58
+ }
59
+ if (norm.startsWith('.claude/agents/')) {
60
+ const file = norm.slice('.claude/agents/'.length);
61
+ const coreSrc = join(forgeRoot, 'core', 'agents', file);
62
+ if (existsSync(coreSrc))
63
+ return coreSrc;
64
+ // Search every profile's agents/ dir for a matching agent file.
65
+ const { profiles } = listCatalogAgents(forgeRoot);
66
+ const agentId = file.replace(/\.md$/, '');
67
+ for (const [profile, agents] of Object.entries(profiles)) {
68
+ if (agents.includes(agentId)) {
69
+ return join(forgeRoot, 'profiles', profile, 'agents', file);
70
+ }
71
+ }
72
+ // Source not found in the catalog (Tier 3 / removed agent) → not managed.
73
+ return null;
74
+ }
75
+ return null;
76
+ }
77
+ /**
78
+ * Computes the update plan from a manifest. For each managed file with a catalog
79
+ * source it decides whether the file would be updated, is user-modified, or is
80
+ * missing on disk. Files in sync (disk == manifest == catalog) are omitted.
81
+ */
82
+ export function computeUpdatePlan(manifest, projRoot, forgeRoot) {
83
+ const plan = [];
84
+ for (const [file, entry] of Object.entries(manifest.files)) {
85
+ const source = resolveCatalogSource(file, forgeRoot);
86
+ if (!source || !existsSync(source))
87
+ continue; // no catalog source → not managed by update
88
+ const catalogHash = sha256file(source);
89
+ const abs = join(projRoot, file);
90
+ if (!existsSync(abs)) {
91
+ // File was deleted by the user — restore it from the catalog.
92
+ plan.push({ file, source, kind: 'missing' });
93
+ continue;
94
+ }
95
+ const diskHash = sha256file(abs);
96
+ const userModified = diskHash !== entry.sha256;
97
+ if (catalogHash === diskHash)
98
+ continue; // already at the catalog version
99
+ if (userModified) {
100
+ plan.push({ file, source, kind: 'modified' });
101
+ }
102
+ else {
103
+ plan.push({ file, source, kind: 'update' });
104
+ }
105
+ }
106
+ return plan;
107
+ }
108
+ export async function update(args) {
109
+ if (args.includes('-h') || args.includes('--help')) {
110
+ process.stdout.write(HELP);
111
+ return 0;
112
+ }
113
+ const dryRun = args.includes('--dry-run');
114
+ const force = args.includes('--force');
115
+ const projectYamlPath = findProjectYaml(process.cwd());
116
+ if (!projectYamlPath) {
117
+ console.error('ERROR: No se encontró project.yaml. Ejecutá `forge init` primero.');
118
+ return 1;
119
+ }
120
+ const projRoot = projectRoot(projectYamlPath);
121
+ const manifest = loadManifest(projRoot);
122
+ if (!manifest) {
123
+ console.error('ERROR: No se encontró .forge/manifest.json. ¿Está forge instalado en este proyecto?');
124
+ return 1;
125
+ }
126
+ let forgeRoot;
127
+ try {
128
+ forgeRoot = resolveForgeRoot();
129
+ }
130
+ catch (e) {
131
+ console.error(`ERROR: ${e instanceof Error ? e.message : String(e)}`);
132
+ return 1;
133
+ }
134
+ const plan = computeUpdatePlan(manifest, projRoot, forgeRoot);
135
+ const toUpdate = plan.filter(p => p.kind === 'update' || p.kind === 'missing');
136
+ const modified = plan.filter(p => p.kind === 'modified');
137
+ // With --force, user-modified files are updated too.
138
+ const willWrite = force ? [...toUpdate, ...modified] : toUpdate;
139
+ const willSkip = force ? [] : modified;
140
+ console.log(`forge update — catálogo v${VERSION} (manifest instalado: v${manifest.forgeVersion})\n`);
141
+ if (plan.length === 0) {
142
+ console.log('Todo al día — no hay archivos gestionados para actualizar.');
143
+ return 0;
144
+ }
145
+ if (willWrite.length > 0) {
146
+ console.log(`${dryRun ? 'Se actualizarían' : 'Actualizando'} ${willWrite.length} archivo(s):`);
147
+ for (const p of willWrite) {
148
+ const tag = p.kind === 'missing' ? ' (restaurar)' : p.kind === 'modified' ? ' (--force, sobrescribe edición)' : '';
149
+ console.log(` [UPD] ${p.file}${dim(tag)}`);
150
+ }
151
+ }
152
+ if (willSkip.length > 0) {
153
+ console.log(`\nSaltando ${willSkip.length} archivo(s) modificado(s) por el usuario (usá --force para sobrescribir):`);
154
+ for (const p of willSkip) {
155
+ console.log(` [SKIP] ${p.file}`);
156
+ }
157
+ }
158
+ if (dryRun) {
159
+ console.log('\n' + dim('Dry-run: no se escribió nada. Ejecutá sin --dry-run para aplicar.'));
160
+ return 0;
161
+ }
162
+ // Apply updates and refresh the manifest entries for the written files.
163
+ const ts = new Date().toISOString();
164
+ for (const p of willWrite) {
165
+ const abs = join(projRoot, p.file);
166
+ mkdirSync(dirname(abs), { recursive: true });
167
+ copyFileSync(p.source, abs);
168
+ manifest.files[p.file] = { sha256: sha256file(abs), installedAt: ts };
169
+ }
170
+ if (willWrite.length > 0) {
171
+ manifest.forgeVersion = VERSION;
172
+ saveManifest(projRoot, manifest);
173
+ console.log(`\nOK — ${willWrite.length} archivo(s) actualizado(s). Manifest → v${VERSION}.`);
174
+ }
175
+ else {
176
+ console.log('\nNada para escribir.');
177
+ }
178
+ return 0;
179
+ }
180
+ //# sourceMappingURL=update.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update.js","sourceRoot":"","sources":["../../src/commands/update.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/commands/validate.ts"],"names":[],"mappings":"AAiEA,wBAAsB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAwE9D"}
1
+ {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/commands/validate.ts"],"names":[],"mappings":"AAuGA,wBAAsB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CA2E9D"}
@@ -8,6 +8,7 @@ const Ajv = require('ajv');
8
8
  const addFormats = require('ajv-formats');
9
9
  import { findProjectYaml, loadProjectYaml, projectRoot } from '../lib/yaml.js';
10
10
  import { resolveForgeRoot } from '../lib/paths.js';
11
+ import { listCatalogProfiles } from '../lib/catalog.js';
11
12
  const HELP = `Usage: forge validate [options]
12
13
 
13
14
  Validate project.yaml in the current directory against the forge v2 schema.
@@ -22,12 +23,47 @@ function loadSchema(forgeRoot) {
22
23
  if (!existsSync(schemaPath))
23
24
  return null;
24
25
  try {
25
- return JSON.parse(readFileSync(schemaPath, 'utf-8'));
26
+ const schema = JSON.parse(readFileSync(schemaPath, 'utf-8'));
27
+ // agents.profiles is validated DYNAMICALLY against profiles/ (issue #71),
28
+ // so we drop the hand-maintained enum before AJV compiles the schema. This
29
+ // prevents the enum drifting and rejecting a real profile (e.g. laravel,
30
+ // wordpress). The dynamic check in dynamicProfileErrors() does the real work.
31
+ const profilesItems = schema?.properties?.agents?.properties?.profiles?.items;
32
+ if (profilesItems && Array.isArray(profilesItems.enum)) {
33
+ delete profilesItems.enum;
34
+ }
35
+ return schema;
26
36
  }
27
37
  catch {
28
38
  return null;
29
39
  }
30
40
  }
41
+ /**
42
+ * Validates agents.profiles against the profiles that physically exist under the
43
+ * forge root's profiles/ directory (issue #71). Accepts ANY real profile and
44
+ * flags only those that don't correspond to a real directory — keeping validate
45
+ * in sync with the catalog without depending on the hand-maintained enum.
46
+ */
47
+ function dynamicProfileErrors(data, forgeRoot) {
48
+ const errors = [];
49
+ const agents = (data.agents ?? null);
50
+ const profiles = agents?.profiles;
51
+ if (!Array.isArray(profiles))
52
+ return errors;
53
+ const available = new Set(listCatalogProfiles(forgeRoot));
54
+ // No profiles on disk (e.g. forge root not found) → can't validate, skip.
55
+ if (available.size === 0)
56
+ return errors;
57
+ for (const name of profiles) {
58
+ if (typeof name !== 'string')
59
+ continue;
60
+ if (!available.has(name)) {
61
+ errors.push(`/agents/profiles: el profile '${name}' no existe en profiles/ ` +
62
+ `(disponibles: ${[...available].join(', ')})`);
63
+ }
64
+ }
65
+ return errors;
66
+ }
31
67
  function businessWarnings(data) {
32
68
  const warnings = [];
33
69
  if (!data.deploy)
@@ -99,6 +135,9 @@ export async function validate(args) {
99
135
  });
100
136
  }
101
137
  }
138
+ // Dynamic, anti-drift profile check (issue #71): accept any profile that
139
+ // exists as a directory under profiles/, regardless of the schema enum.
140
+ errors.push(...dynamicProfileErrors(data, forgeRoot));
102
141
  }
103
142
  catch {
104
143
  // schema not available — skip schema validation
@@ -1 +1 @@
1
- {"version":3,"file":"validate.js","sourceRoot":"","sources":["../../src/commands/validate.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"validate.js","sourceRoot":"","sources":["../../src/commands/validate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AAC9C,OAAO,EAAE,IAAI,EAAW,MAAM,MAAM,CAAC;AAGrC,OAAO,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AACvC,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC/C,8DAA8D;AAC9D,MAAM,GAAG,GAAQ,OAAO,CAAC,KAAK,CAAC,CAAC;AAChC,8DAA8D;AAC9D,MAAM,UAAU,GAAQ,OAAO,CAAC,aAAa,CAAC,CAAC;AAC/C,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC/E,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAExD,MAAM,IAAI,GAAG;;;;;;;;CAQZ,CAAC;AAEF,SAAS,UAAU,CAAC,SAAiB;IACnC,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,qBAAqB,CAAC,CAAC;IAC7E,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC;QAAE,OAAO,IAAI,CAAC;IACzC,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC;QAC7D,0EAA0E;QAC1E,2EAA2E;QAC3E,yEAAyE;QACzE,8EAA8E;QAC9E,MAAM,aAAa,GAAG,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,KAAK,CAAC;QAC9E,IAAI,aAAa,IAAI,KAAK,CAAC,OAAO,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC;YACvD,OAAO,aAAa,CAAC,IAAI,CAAC;QAC5B,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,SAAS,oBAAoB,CAAC,IAA6B,EAAE,SAAiB;IAC5E,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,MAAM,MAAM,GAAG,CAAC,IAAI,CAAC,MAAM,IAAI,IAAI,CAAkC,CAAC;IACtE,MAAM,QAAQ,GAAG,MAAM,EAAE,QAAQ,CAAC;IAClC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC;QAAE,OAAO,MAAM,CAAC;IAE5C,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,mBAAmB,CAAC,SAAS,CAAC,CAAC,CAAC;IAC1D,0EAA0E;IAC1E,IAAI,SAAS,CAAC,IAAI,KAAK,CAAC;QAAE,OAAO,MAAM,CAAC;IAExC,KAAK,MAAM,IAAI,IAAI,QAAQ,EAAE,CAAC;QAC5B,IAAI,OAAO,IAAI,KAAK,QAAQ;YAAE,SAAS;QACvC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YACzB,MAAM,CAAC,IAAI,CACT,iCAAiC,IAAI,2BAA2B;gBAChE,iBAAiB,CAAC,GAAG,SAAS,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAC9C,CAAC;QACJ,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,gBAAgB,CAAC,IAA6B;IACrD,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,IAAI,CAAC,IAAI,CAAC,MAAM;QAAE,QAAQ,CAAC,IAAI,CAAC,wFAAwF,CAAC,CAAC;IAC1H,IAAI,CAAC,IAAI,CAAC,KAAK;QAAE,QAAQ,CAAC,IAAI,CAAC,0EAA0E,CAAC,CAAC;IAC3G,IAAI,CAAC,IAAI,CAAC,MAAM;QAAE,QAAQ,CAAC,IAAI,CAAC,wEAAwE,CAAC,CAAC;IAC1G,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;;;GAIG;AACH,SAAS,sBAAsB,CAAC,IAA6B,EAAE,IAAY;IACzE,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,MAAM,MAAM,GAAG,CAAC,IAAI,CAAC,MAAM,IAAI,IAAI,CAAqC,CAAC;IACzE,MAAM,WAAW,GAAG,MAAM,EAAE,WAAW,CAAC;IACxC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC;QAAE,OAAO,MAAM,CAAC;IAE/C,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC;IAClD,KAAK,MAAM,IAAI,IAAI,WAAW,EAAE,CAAC;QAC/B,IAAI,OAAO,IAAI,KAAK,QAAQ;YAAE,SAAS;QACvC,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,EAAE,GAAG,IAAI,KAAK,CAAC,CAAC;QAC3C,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;YACtB,MAAM,CAAC,IAAI,CACT,0CAA0C,IAAI,8DAA8D,IAAI,KAAK,CACtH,CAAC;QACJ,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,IAAc;IAC3C,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QACnD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC3B,OAAO,CAAC,CAAC;IACX,CAAC;IACD,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAEzC,MAAM,eAAe,GAAG,eAAe,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IACvD,IAAI,CAAC,eAAe,EAAE,CAAC;QACrB,MAAM,MAAM,GAAG,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,6BAA6B,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;QACvF,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,oCAAoC,CAAC,CAAC;QAC9G,OAAO,CAAC,CAAC;IACX,CAAC;IAED,IAAI,IAA6B,CAAC;IAClC,IAAI,CAAC;QACH,IAAI,GAAG,eAAe,CAAC,eAAe,CAAuC,CAAC;IAChF,CAAC;IAAC,OAAO,CAAU,EAAE,CAAC;QACpB,MAAM,GAAG,GAAG,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QACvD,MAAM,MAAM,GAAG,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,GAAG,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;QAC7D,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,UAAU,GAAG,EAAE,CAAC,CAAC;QACzF,OAAO,CAAC,CAAC;IACX,CAAC;IAED,IAAI,MAAM,GAAa,EAAE,CAAC;IAE1B,IAAI,CAAC;QACH,MAAM,SAAS,GAAG,gBAAgB,EAAE,CAAC;QACrC,MAAM,MAAM,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC;QACrC,IAAI,MAAM,EAAE,CAAC;YACX,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;YACxD,UAAU,CAAC,GAAG,CAAC,CAAC;YAChB,MAAM,QAAQ,GAAG,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;YACrC,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;YAC7B,IAAI,CAAC,KAAK,IAAI,QAAQ,CAAC,MAAM,EAAE,CAAC;gBAC9B,8DAA8D;gBAC9D,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAM,EAAE,EAAE;oBACtC,MAAM,IAAI,GAAG,CAAC,CAAC,YAAY,IAAI,MAAM,CAAC;oBACtC,OAAO,GAAG,IAAI,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC;gBACjC,CAAC,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QACD,yEAAyE;QACzE,wEAAwE;QACxE,MAAM,CAAC,IAAI,CAAC,GAAG,oBAAoB,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC;IACxD,CAAC;IAAC,MAAM,CAAC;QACP,gDAAgD;IAClD,CAAC;IAED,sFAAsF;IACtF,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,MAAM,GAAG,sBAAsB,CAAC,IAAI,EAAE,WAAW,CAAC,eAAe,CAAC,CAAC,CAAC;IACtE,CAAC;IAED,MAAM,QAAQ,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;IACxC,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC;IAClC,MAAM,MAAM,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;IAE3C,IAAI,QAAQ,EAAE,CAAC;QACb,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IAC/C,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,GAAG,CAAC,cAAc,eAAe,IAAI,CAAC,CAAC;QAC/C,IAAI,KAAK,EAAE,CAAC;YACV,OAAO,CAAC,GAAG,CAAC,6BAA6B,CAAC,CAAC;QAC7C,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,cAAc,MAAM,CAAC,MAAM,0BAA0B,CAAC,CAAC;YACnE,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC,CAAC;QACrD,CAAC;QACD,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACxB,OAAO,CAAC,GAAG,CAAC,KAAK,QAAQ,CAAC,MAAM,kBAAkB,CAAC,CAAC;YACpD,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC,CAAC;QACvD,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACvB,CAAC"}
@@ -14,6 +14,13 @@ export interface RuntimeInfo {
14
14
  }
15
15
  export declare const SKILLS: SkillInfo[];
16
16
  export declare const RUNTIMES: RuntimeInfo[];
17
+ /**
18
+ * List the profile ids that physically exist as directories under the forge
19
+ * root's profiles/ tree. This is the source of truth for `forge validate`'s
20
+ * dynamic, anti-drift profile check (issue #71): any directory here is a valid
21
+ * profile, regardless of the hand-maintained enum in project.schema.json.
22
+ */
23
+ export declare function listCatalogProfiles(forgeRoot: string): string[];
17
24
  /** List agent ids available in the forge assets tree (core + profiles). */
18
25
  export declare function listCatalogAgents(forgeRoot: string): {
19
26
  core: string[];
@@ -1 +1 @@
1
- {"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../../src/lib/catalog.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,SAAS;IAAG,EAAE,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;CAAE;AAC/G,MAAM,WAAW,WAAW;IAAG,EAAE,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,EAAE,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;CAAE;AAE3G,eAAO,MAAM,MAAM,EAAE,SAAS,EAe7B,CAAC;AAEF,eAAO,MAAM,QAAQ,EAAE,WAAW,EAKjC,CAAC;AAEF,2EAA2E;AAC3E,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAA;CAAE,CAiB3G"}
1
+ {"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../../src/lib/catalog.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,SAAS;IAAG,EAAE,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;CAAE;AAC/G,MAAM,WAAW,WAAW;IAAG,EAAE,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,EAAE,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;CAAE;AAE3G,eAAO,MAAM,MAAM,EAAE,SAAS,EAoB7B,CAAC;AAEF,eAAO,MAAM,QAAQ,EAAE,WAAW,EAKjC,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,CAO/D;AAED,2EAA2E;AAC3E,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAA;CAAE,CAiB3G"}
@@ -20,6 +20,11 @@ export const SKILLS = [
20
20
  { id: 'wiki-lint', command: '/wiki-lint', category: 'Wiki', purpose: 'Verifica integridad del wiki (links, huérfanos)', trigger: '"verificar wiki"' },
21
21
  { id: 'aitmpl-search', command: '/aitmpl-search', category: 'Catálogo', purpose: 'Busca en el catálogo de frameworks/MCP/profiles', trigger: '"buscar templates", "buscar MCP"' },
22
22
  { id: 'obsidian-sync', command: '/obsidian-sync', category: 'Integración', purpose: 'Sincroniza un vault de Obsidian con el código', trigger: '"actualizar obsidian", "sync vault"' },
23
+ { id: 'laravel-eloquent', command: '/laravel-eloquent', category: 'Laravel', purpose: 'Eloquent: relaciones, eager loading, evitar N+1, casts, pgvector', trigger: '"modelo eloquent", "evitar N+1", "query lenta"' },
24
+ { id: 'laravel-pest', command: '/laravel-pest', category: 'Laravel', purpose: 'TDD con Pest 3: factories, fakes, HTTP tests, coverage', trigger: '"test laravel", "pest", "factory"' },
25
+ { id: 'laravel-security', command: '/laravel-security', category: 'Laravel', purpose: 'Auth, policies, Form Requests, CSRF, rate limiting, deploy seguro', trigger: '"seguridad laravel", "auth laravel", "policy"' },
26
+ { id: 'laravel-verify', command: '/laravel-verify', category: 'Laravel', purpose: 'Loop Pint + Larastan + Pest (coverage) + composer audit', trigger: '"verificar laravel", "pint phpstan pest"' },
27
+ { id: 'laravel-mcp', command: '/laravel-mcp', category: 'Laravel', purpose: 'Laravel 13 agents/MCP: Boost, laravel/mcp, AI SDK, embeddings/RAG', trigger: '"laravel mcp", "laravel boost", "laravel ai sdk"' },
23
28
  ];
24
29
  export const RUNTIMES = [
25
30
  { id: 'claude-code', label: 'Claude Code', cmd: ['claude', '--version'], install: 'npm i -g @anthropic-ai/claude-code', marker: 'CLAUDE.md + .claude/' },
@@ -27,6 +32,21 @@ export const RUNTIMES = [
27
32
  { id: 'codex', label: 'Codex CLI', cmd: ['codex', '--version'], install: 'npm i -g @openai/codex', marker: 'AGENTS.md + .codex/' },
28
33
  { id: 'kiro', label: 'Kiro IDE', cmd: ['kiro', '--version'], install: 'descargar desde kiro.dev', marker: '.kiro/steering/' },
29
34
  ];
35
+ /**
36
+ * List the profile ids that physically exist as directories under the forge
37
+ * root's profiles/ tree. This is the source of truth for `forge validate`'s
38
+ * dynamic, anti-drift profile check (issue #71): any directory here is a valid
39
+ * profile, regardless of the hand-maintained enum in project.schema.json.
40
+ */
41
+ export function listCatalogProfiles(forgeRoot) {
42
+ const profDir = join(forgeRoot, 'profiles');
43
+ if (!existsSync(profDir))
44
+ return [];
45
+ return readdirSync(profDir, { withFileTypes: true })
46
+ .filter(e => e.isDirectory())
47
+ .map(e => e.name)
48
+ .sort();
49
+ }
30
50
  /** List agent ids available in the forge assets tree (core + profiles). */
31
51
  export function listCatalogAgents(forgeRoot) {
32
52
  const core = [];
@@ -1 +1 @@
1
- {"version":3,"file":"catalog.js","sourceRoot":"","sources":["../../src/lib/catalog.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,IAAI,CAAC;AAC7C,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAK5B,MAAM,CAAC,MAAM,MAAM,GAAgB;IACjC,EAAE,EAAE,EAAE,eAAe,EAAG,OAAO,EAAE,gBAAgB,EAAG,QAAQ,EAAE,QAAQ,EAAM,OAAO,EAAE,kDAAkD,EAAK,OAAO,EAAE,yCAAyC,EAAE;IAChM,EAAE,EAAE,EAAE,eAAe,EAAG,OAAO,EAAE,gBAAgB,EAAG,QAAQ,EAAE,QAAQ,EAAM,OAAO,EAAE,mDAAmD,EAAI,OAAO,EAAE,0CAA0C,EAAE;IACjM,EAAE,EAAE,EAAE,MAAM,EAAY,OAAO,EAAE,OAAO,EAAY,QAAQ,EAAE,YAAY,EAAE,OAAO,EAAE,4CAA4C,EAAW,OAAO,EAAE,4BAA4B,EAAE;IACnL,EAAE,EAAE,EAAE,aAAa,EAAK,OAAO,EAAE,cAAc,EAAK,QAAQ,EAAE,YAAY,EAAE,OAAO,EAAE,uCAAuC,EAAgB,OAAO,EAAE,gCAAgC,EAAE;IACvL,EAAE,EAAE,EAAE,gBAAgB,EAAE,OAAO,EAAE,iBAAiB,EAAE,QAAQ,EAAE,YAAY,EAAE,OAAO,EAAE,8CAA8C,EAAS,OAAO,EAAE,qCAAqC,EAAE;IAC5L,EAAE,EAAE,EAAE,YAAY,EAAM,OAAO,EAAE,aAAa,EAAM,QAAQ,EAAE,YAAY,EAAE,OAAO,EAAE,+CAA+C,EAAQ,OAAO,EAAE,sBAAsB,EAAE;IAC7K,EAAE,EAAE,EAAE,YAAY,EAAM,OAAO,EAAE,aAAa,EAAM,QAAQ,EAAE,OAAO,EAAO,OAAO,EAAE,oDAAoD,EAAG,OAAO,EAAE,oCAAoC,EAAE;IAC3L,EAAE,EAAE,EAAE,cAAc,EAAI,OAAO,EAAE,eAAe,EAAI,QAAQ,EAAE,SAAS,EAAK,OAAO,EAAE,8CAA8C,EAAS,OAAO,EAAE,+BAA+B,EAAE;IACtL,EAAE,EAAE,EAAE,eAAe,EAAG,OAAO,EAAE,gBAAgB,EAAG,QAAQ,EAAE,QAAQ,EAAM,OAAO,EAAE,8CAA8C,EAAS,OAAO,EAAE,8BAA8B,EAAE;IACrL,EAAE,EAAE,EAAE,aAAa,EAAK,OAAO,EAAE,cAAc,EAAK,QAAQ,EAAE,MAAM,EAAQ,OAAO,EAAE,yCAAyC,EAAc,OAAO,EAAE,kCAAkC,EAAE;IACzL,EAAE,EAAE,EAAE,YAAY,EAAM,OAAO,EAAE,aAAa,EAAM,QAAQ,EAAE,MAAM,EAAQ,OAAO,EAAE,uCAAuC,EAAgB,OAAO,EAAE,4BAA4B,EAAE;IACnL,EAAE,EAAE,EAAE,WAAW,EAAO,OAAO,EAAE,YAAY,EAAO,QAAQ,EAAE,MAAM,EAAQ,OAAO,EAAE,iDAAiD,EAAM,OAAO,EAAE,kBAAkB,EAAE;IACzK,EAAE,EAAE,EAAE,eAAe,EAAG,OAAO,EAAE,gBAAgB,EAAG,QAAQ,EAAE,UAAU,EAAI,OAAO,EAAE,iDAAiD,EAAM,OAAO,EAAE,kCAAkC,EAAE;IACzL,EAAE,EAAE,EAAE,eAAe,EAAG,OAAO,EAAE,gBAAgB,EAAG,QAAQ,EAAE,aAAa,EAAC,OAAO,EAAE,+CAA+C,EAAQ,OAAO,EAAE,qCAAqC,EAAE;CAC7L,CAAC;AAEF,MAAM,CAAC,MAAM,QAAQ,GAAkB;IACrC,EAAE,EAAE,EAAE,aAAa,EAAE,KAAK,EAAE,aAAa,EAAE,GAAG,EAAE,CAAC,QAAQ,EAAE,WAAW,CAAC,EAAI,OAAO,EAAE,oCAAoC,EAAE,MAAM,EAAE,sBAAsB,EAAE;IAC1J,EAAE,EAAE,EAAE,UAAU,EAAK,KAAK,EAAE,UAAU,EAAK,GAAG,EAAE,CAAC,UAAU,EAAE,WAAW,CAAC,EAAE,OAAO,EAAE,sBAAsB,EAAgB,MAAM,EAAE,wBAAwB,EAAE;IAC5J,EAAE,EAAE,EAAE,OAAO,EAAQ,KAAK,EAAE,WAAW,EAAI,GAAG,EAAE,CAAC,OAAO,EAAE,WAAW,CAAC,EAAK,OAAO,EAAE,wBAAwB,EAAc,MAAM,EAAE,qBAAqB,EAAE;IACzJ,EAAE,EAAE,EAAE,MAAM,EAAS,KAAK,EAAE,UAAU,EAAK,GAAG,EAAE,CAAC,MAAM,EAAE,WAAW,CAAC,EAAM,OAAO,EAAE,0BAA0B,EAAY,MAAM,EAAE,iBAAiB,EAAE;CACtJ,CAAC;AAEF,2EAA2E;AAC3E,MAAM,UAAU,iBAAiB,CAAC,SAAiB;IACjD,MAAM,IAAI,GAAa,EAAE,CAAC;IAC1B,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;IAClD,IAAI,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QACxB,KAAK,MAAM,CAAC,IAAI,WAAW,CAAC,OAAO,CAAC;YAAE,IAAI,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC;gBAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC;IAC/F,CAAC;IACD,MAAM,QAAQ,GAA6B,EAAE,CAAC;IAC9C,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;IAC5C,IAAI,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QACxB,KAAK,MAAM,CAAC,IAAI,WAAW,CAAC,OAAO,CAAC,EAAE,CAAC;YACrC,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC,EAAE,QAAQ,CAAC,CAAC;YAC7C,IAAI,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;gBAC1B,QAAQ,CAAC,CAAC,CAAC,GAAG,WAAW,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC;YACrG,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;AAC5B,CAAC"}
1
+ {"version":3,"file":"catalog.js","sourceRoot":"","sources":["../../src/lib/catalog.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ /** The exact, allowlisted set of tools. Adding to this is a deliberate review. */
2
+ export declare const MCP_TOOLS: readonly ["guardrail_status", "wiki_search"];
3
+ export interface GuardrailInput {
4
+ /** A shell command to evaluate against pre-bash-check. */
5
+ command?: string;
6
+ /** A file path to evaluate against pre-edit-check (with optional new content). */
7
+ file?: string;
8
+ content?: string;
9
+ }
10
+ export interface GuardrailResult {
11
+ verdict: 'allow' | 'warn' | 'block';
12
+ blocked: boolean;
13
+ message: string;
14
+ }
15
+ /**
16
+ * Returns the LIVE guardrail verdict by running the project's OWN installed hook
17
+ * (.claude/hooks/*) with the given payload and interpreting its exit code. This
18
+ * reuses the exact same logic the runtime enforces — no duplication, no drift.
19
+ * Read-only: it never executes the command, only asks the hook for a verdict.
20
+ */
21
+ export declare function guardrailStatus(input: GuardrailInput, projectRoot: string): GuardrailResult;
22
+ export interface WikiHit {
23
+ /** Page path relative to wiki/ (e.g. "concepts/auth.md"). */
24
+ page: string;
25
+ line: number;
26
+ snippet: string;
27
+ }
28
+ /**
29
+ * Lexical, case-insensitive search over the project's `wiki/` knowledge pages.
30
+ * CONFINED by construction: it only ever reads files under `<projectRoot>/wiki/`
31
+ * and takes a query STRING (never a path), so there is no path-traversal surface.
32
+ * Mirrors `forge wiki query` (the static floor); this is the additive interface.
33
+ */
34
+ export declare function wikiSearch(query: string, projectRoot: string, opts?: {
35
+ limit?: number;
36
+ }): WikiHit[];
37
+ //# sourceMappingURL=mcp-tools.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-tools.d.ts","sourceRoot":"","sources":["../../src/lib/mcp-tools.ts"],"names":[],"mappings":"AAiBA,kFAAkF;AAClF,eAAO,MAAM,SAAS,8CAA+C,CAAC;AAItE,MAAM,WAAW,cAAc;IAC7B,0DAA0D;IAC1D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,kFAAkF;IAClF,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,GAAG,MAAM,GAAG,OAAO,CAAC;IACpC,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,GAAG,eAAe,CAiC3F;AAID,MAAM,WAAW,OAAO;IACtB,6DAA6D;IAC7D,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAuBD;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,IAAI,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,OAAO,EAAE,CAwBvG"}
@@ -0,0 +1,124 @@
1
+ /**
2
+ * The two DYNAMIC tools behind `forge mcp` (RFC-003). PURE + testable: no MCP
3
+ * SDK here, no network. commands/mcp.ts lazily loads the SDK and delegates to
4
+ * these functions.
5
+ *
6
+ * Golden rule (enforced by an allowlist test): the static floor stays complete;
7
+ * MCP is strictly ADDITIVE (a freshness layer). Nothing forge knows is reachable
8
+ * ONLY via MCP. These two tools expose only values that genuinely change at use
9
+ * time and cannot be precomputed in `forge generate`:
10
+ * - guardrail_status: the LIVE verdict of the project's own hooks.
11
+ * - wiki_search: a query over the confined wiki/ corpus.
12
+ * Both are READ-ONLY and tightly scoped. Neither takes a free-form path it reads.
13
+ */
14
+ import { existsSync, readFileSync, readdirSync } from 'fs';
15
+ import { join, basename, relative, sep } from 'path';
16
+ import { spawnSync } from 'child_process';
17
+ /** The exact, allowlisted set of tools. Adding to this is a deliberate review. */
18
+ export const MCP_TOOLS = ['guardrail_status', 'wiki_search'];
19
+ /**
20
+ * Returns the LIVE guardrail verdict by running the project's OWN installed hook
21
+ * (.claude/hooks/*) with the given payload and interpreting its exit code. This
22
+ * reuses the exact same logic the runtime enforces — no duplication, no drift.
23
+ * Read-only: it never executes the command, only asks the hook for a verdict.
24
+ */
25
+ export function guardrailStatus(input, projectRoot) {
26
+ let hook;
27
+ let payload;
28
+ if (input.command !== undefined) {
29
+ hook = join(projectRoot, '.claude', 'hooks', 'pre-bash-check.js');
30
+ payload = { tool_name: 'Bash', tool_input: { command: input.command } };
31
+ }
32
+ else if (input.file !== undefined) {
33
+ hook = join(projectRoot, '.claude', 'hooks', 'pre-edit-check.js');
34
+ payload = { tool_name: 'Edit', tool_input: { file_path: input.file, new_string: input.content ?? '' } };
35
+ }
36
+ else {
37
+ return { verdict: 'allow', blocked: false, message: 'Sin entrada: pasá `command` o `file`.' };
38
+ }
39
+ if (!existsSync(hook)) {
40
+ return {
41
+ verdict: 'allow', blocked: false,
42
+ message: 'Guardrails no instalados en este proyecto (.claude/hooks/ ausente).',
43
+ };
44
+ }
45
+ const res = spawnSync(process.execPath, [hook], {
46
+ cwd: projectRoot,
47
+ input: JSON.stringify(payload),
48
+ encoding: 'utf-8',
49
+ timeout: 5000,
50
+ env: { ...process.env, DEBUG: '' },
51
+ });
52
+ const out = ((res.stdout ?? '') + (res.stderr ?? '')).trim();
53
+ const status = res.status ?? 0;
54
+ if (status === 2)
55
+ return { verdict: 'block', blocked: true, message: out || 'Bloqueado por el guardrail.' };
56
+ if (out && /ADVERTENCIA|warning/i.test(out))
57
+ return { verdict: 'warn', blocked: false, message: out };
58
+ return { verdict: 'allow', blocked: false, message: out || 'Permitido por los guardrails.' };
59
+ }
60
+ const CONTROL_FILES = ['index.md', 'log.md'];
61
+ /** True for a real knowledge page (excludes raw/ sources, control + template seeds). */
62
+ function isWikiPage(wikiRoot, path) {
63
+ if (path.startsWith(join(wikiRoot, 'raw') + sep))
64
+ return false;
65
+ const name = basename(path);
66
+ if (name === '_template.md')
67
+ return false;
68
+ if (CONTROL_FILES.includes(name))
69
+ return false;
70
+ return true;
71
+ }
72
+ function collectMarkdown(dir, out = []) {
73
+ if (!existsSync(dir))
74
+ return out;
75
+ for (const entry of readdirSync(dir, { withFileTypes: true })) {
76
+ const full = join(dir, entry.name);
77
+ if (entry.isDirectory())
78
+ collectMarkdown(full, out);
79
+ else if (entry.name.endsWith('.md'))
80
+ out.push(full);
81
+ }
82
+ return out;
83
+ }
84
+ /**
85
+ * Lexical, case-insensitive search over the project's `wiki/` knowledge pages.
86
+ * CONFINED by construction: it only ever reads files under `<projectRoot>/wiki/`
87
+ * and takes a query STRING (never a path), so there is no path-traversal surface.
88
+ * Mirrors `forge wiki query` (the static floor); this is the additive interface.
89
+ */
90
+ export function wikiSearch(query, projectRoot, opts = {}) {
91
+ const q = (query ?? '').trim().toLowerCase();
92
+ if (!q)
93
+ return [];
94
+ const wikiRoot = join(projectRoot, 'wiki');
95
+ if (!existsSync(wikiRoot))
96
+ return [];
97
+ const limit = opts.limit ?? 25;
98
+ const hits = [];
99
+ for (const file of collectMarkdown(wikiRoot)) {
100
+ if (!isWikiPage(wikiRoot, file))
101
+ continue;
102
+ // Defense in depth: never read outside wiki/ even if collect returned an odd path.
103
+ const rel = relative(wikiRoot, file);
104
+ if (rel.startsWith('..') || rel.includes(`..${sep}`))
105
+ continue;
106
+ let content;
107
+ try {
108
+ content = readFileSync(file, 'utf-8');
109
+ }
110
+ catch {
111
+ continue;
112
+ }
113
+ const lines = content.split('\n');
114
+ for (let i = 0; i < lines.length; i++) {
115
+ if (lines[i].toLowerCase().includes(q)) {
116
+ hits.push({ page: rel.split(sep).join('/'), line: i + 1, snippet: lines[i].trim().slice(0, 200) });
117
+ if (hits.length >= limit)
118
+ return hits;
119
+ }
120
+ }
121
+ }
122
+ return hits;
123
+ }
124
+ //# sourceMappingURL=mcp-tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-tools.js","sourceRoot":"","sources":["../../src/lib/mcp-tools.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,66 @@
1
+ export type Severity = 'high' | 'medium' | 'low';
2
+ export interface Finding {
3
+ category: string;
4
+ severity: Severity;
5
+ line: number;
6
+ snippet: string;
7
+ reason: string;
8
+ }
9
+ export interface HygieneResult {
10
+ /** Content with invisible/unsafe characters removed (semantics untouched). */
11
+ clean: string;
12
+ issues: Finding[];
13
+ }
14
+ export interface Capabilities {
15
+ /** Globs/paths the skill is allowed to write. */
16
+ fs_write?: string[];
17
+ /** Commands the skill is allowed to run. */
18
+ bash?: string[];
19
+ /** Whether the skill needs network. Absent/false → no network. */
20
+ network?: boolean;
21
+ }
22
+ export interface Assessment {
23
+ /** Skill id from the `# Skill: <id>` header, or null if absent. */
24
+ name: string | null;
25
+ formatOk: boolean;
26
+ formatIssues: string[];
27
+ hygiene: HygieneResult;
28
+ /** Risk findings scanned on the hygiene-cleaned content. */
29
+ findings: Finding[];
30
+ capabilities: Capabilities | null;
31
+ counts: {
32
+ high: number;
33
+ medium: number;
34
+ low: number;
35
+ };
36
+ /** allow → no risks; confirm → needs explicit consent; block → high risk. */
37
+ decision: 'allow' | 'confirm' | 'block';
38
+ }
39
+ /**
40
+ * Strips invisible/bidi characters (safe, semantics-preserving) and flags
41
+ * homoglyphs. Returns the cleaned content plus the hygiene findings.
42
+ */
43
+ export declare function normalizeHygiene(raw: string): HygieneResult;
44
+ /** Scans risk patterns over already-hygiene-cleaned content. Classifies, never edits. */
45
+ export declare function scanRisks(clean: string): Finding[];
46
+ export declare function validateFormat(content: string): {
47
+ ok: boolean;
48
+ name: string | null;
49
+ issues: string[];
50
+ };
51
+ /** Extracts a `capabilities:` block from YAML frontmatter, if present. */
52
+ export declare function parseCapabilities(content: string): Capabilities | null;
53
+ /**
54
+ * Full security assessment of a skill's raw text. The `decision` is advisory:
55
+ * - block → at least one high-severity finding (install needs explicit --force)
56
+ * - confirm → medium findings OR no declared capabilities (needs consent)
57
+ * - allow → clean and capability-scoped
58
+ */
59
+ export declare function assessSkill(raw: string): Assessment;
60
+ /**
61
+ * Wraps the flagged lines in a visible "external/untrusted — do not execute
62
+ * without human verification" callout so the agent itself is told to distrust
63
+ * them. Preserves all content (no false-positive deletions).
64
+ */
65
+ export declare function demoteRiskyLines(clean: string, findings: Finding[]): string;
66
+ //# sourceMappingURL=skill-security.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skill-security.d.ts","sourceRoot":"","sources":["../../src/lib/skill-security.ts"],"names":[],"mappings":"AAcA,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;AAEjD,MAAM,WAAW,OAAO;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,QAAQ,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,aAAa;IAC5B,8EAA8E;IAC9E,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,OAAO,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,iDAAiD;IACjD,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,4CAA4C;IAC5C,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,kEAAkE;IAClE,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,UAAU;IACzB,mEAAmE;IACnE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,QAAQ,EAAE,OAAO,CAAC;IAClB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,OAAO,EAAE,aAAa,CAAC;IACvB,4DAA4D;IAC5D,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,YAAY,EAAE,YAAY,GAAG,IAAI,CAAC;IAClC,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IACtD,6EAA6E;IAC7E,QAAQ,EAAE,OAAO,GAAG,SAAS,GAAG,OAAO,CAAC;CACzC;AAgBD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,aAAa,CAiC3D;AA2DD,yFAAyF;AACzF,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,EAAE,CAkBlD;AAMD,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,CAStG;AAED,0EAA0E;AAC1E,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CAkBtE;AAID;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,CA2BnD;AAID;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,MAAM,CAa3E"}