@cristiancorreau/forge 2.1.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 (153) hide show
  1. package/CHANGELOG.md +228 -0
  2. package/LICENSE +191 -0
  3. package/README.md +156 -0
  4. package/assets/adapters/claude-code/commands/deploy-check.md +12 -0
  5. package/assets/adapters/claude-code/commands/new-feature.md +11 -0
  6. package/assets/adapters/claude-code/commands/plan.md +116 -0
  7. package/assets/adapters/claude-code/commands/review.md +219 -0
  8. package/assets/adapters/claude-code/commands/session-close.md +109 -0
  9. package/assets/adapters/claude-code/commands/session-start.md +59 -0
  10. package/assets/adapters/claude-code/commands/ship.md +133 -0
  11. package/assets/adapters/claude-code/commands/wiki-ingest.md +7 -0
  12. package/assets/adapters/claude-code/commands/wiki-lint.md +5 -0
  13. package/assets/adapters/claude-code/commands/wiki-query.md +7 -0
  14. package/assets/adapters/claude-code/commands/work.md +101 -0
  15. package/assets/adapters/claude-code/generate-claude-md.py +304 -0
  16. package/assets/adapters/codex/commands/plan.md +63 -0
  17. package/assets/adapters/codex/commands/review.md +53 -0
  18. package/assets/adapters/codex/commands/session-close.md +53 -0
  19. package/assets/adapters/codex/commands/session-start.md +49 -0
  20. package/assets/adapters/codex/commands/ship.md +53 -0
  21. package/assets/adapters/codex/commands/work.md +53 -0
  22. package/assets/adapters/codex/generate-codex-config.py +269 -0
  23. package/assets/adapters/codex/hooks/codex.yaml.tpl +43 -0
  24. package/assets/adapters/codex/hooks/forge-codex-finish.sh +158 -0
  25. package/assets/adapters/codex/hooks/forge-codex-start.sh +186 -0
  26. package/assets/adapters/kiro/generate-steering.py +367 -0
  27. package/assets/adapters/opencode/HOOKS.md +123 -0
  28. package/assets/adapters/opencode/commands/plan.md +119 -0
  29. package/assets/adapters/opencode/commands/review.md +164 -0
  30. package/assets/adapters/opencode/commands/session-close.md +111 -0
  31. package/assets/adapters/opencode/commands/session-start.md +62 -0
  32. package/assets/adapters/opencode/commands/ship.md +135 -0
  33. package/assets/adapters/opencode/commands/work.md +82 -0
  34. package/assets/adapters/opencode/generate-agents-md.py +262 -0
  35. package/assets/core/agents/backend-engineer.md +61 -0
  36. package/assets/core/agents/compliance-reviewer.md +83 -0
  37. package/assets/core/agents/docs-writer.md +77 -0
  38. package/assets/core/agents/frontend-engineer.md +70 -0
  39. package/assets/core/agents/orchestrator.md +104 -0
  40. package/assets/core/agents/security-auditor.md +54 -0
  41. package/assets/core/agents/test-engineer.md +57 -0
  42. package/assets/core/hooks/hooks-registry.yaml +48 -0
  43. package/assets/core/hooks/post-turn-check.sh +139 -0
  44. package/assets/core/hooks/pre-bash-check.py +202 -0
  45. package/assets/core/hooks/pre-edit-check.py +317 -0
  46. package/assets/core/hooks/session-start.sh +184 -0
  47. package/assets/core/schemas/project.schema.json +503 -0
  48. package/assets/core/skills/README.md +88 -0
  49. package/assets/core/skills/aitmpl-search/SKILL.md +74 -0
  50. package/assets/core/skills/browser-test/SKILL.md +177 -0
  51. package/assets/core/skills/db-migrate/SKILL.md +163 -0
  52. package/assets/core/skills/local2prod/SKILL.md +147 -0
  53. package/assets/core/skills/new-feature/SKILL.md +155 -0
  54. package/assets/core/skills/obsidian-sync/SKILL.md +152 -0
  55. package/assets/core/skills/phase-kickoff/SKILL.md +69 -0
  56. package/assets/core/skills/security-audit/SKILL.md +125 -0
  57. package/assets/core/skills/spec/SKILL.md +72 -0
  58. package/assets/core/skills/wiki-ingest/SKILL.md +183 -0
  59. package/assets/core/skills/wiki-lint/SKILL.md +109 -0
  60. package/assets/core/skills/wiki-query/SKILL.md +100 -0
  61. package/assets/core/templates/claude-md/architecture.rules +20 -0
  62. package/assets/core/templates/claude-md/global.md +30 -0
  63. package/assets/core/templates/claude-md/project.md +36 -0
  64. package/assets/core/templates/daily-note.md +38 -0
  65. package/assets/core/templates/spec-template.md +43 -0
  66. package/assets/core/workflows/sdd.md +69 -0
  67. package/assets/core/workflows/sprint.md +59 -0
  68. package/assets/forge.py +1265 -0
  69. package/assets/hooks/pre-commit +43 -0
  70. package/assets/manifest.json +274 -0
  71. package/assets/profiles/astro/README.md +24 -0
  72. package/assets/profiles/astro/agents/frontend-engineer.md +74 -0
  73. package/assets/profiles/django/agents/api-engineer.md +83 -0
  74. package/assets/profiles/expo/README.md +24 -0
  75. package/assets/profiles/expo/agents/mobile-engineer.md +69 -0
  76. package/assets/profiles/express/agents/api-engineer.md +60 -0
  77. package/assets/profiles/fastapi/README.md +32 -0
  78. package/assets/profiles/fastapi/agents/api-engineer.md +87 -0
  79. package/assets/profiles/go-gin/agents/api-engineer.md +98 -0
  80. package/assets/profiles/hono-drizzle/README.md +31 -0
  81. package/assets/profiles/hono-drizzle/agents/api-engineer.md +82 -0
  82. package/assets/profiles/laravel/README.md +32 -0
  83. package/assets/profiles/laravel/agents/api-engineer.md +114 -0
  84. package/assets/profiles/laravel/agents/fullstack-engineer.md +67 -0
  85. package/assets/profiles/laravel/agents/migration-specialist.md +420 -0
  86. package/assets/profiles/nestjs/agents/api-engineer.md +79 -0
  87. package/assets/profiles/nextjs-admin/README.md +32 -0
  88. package/assets/profiles/nextjs-admin/agents/admin-engineer.md +78 -0
  89. package/assets/profiles/playwright-crawler/agents/scanner-engineer.md +51 -0
  90. package/assets/profiles/rails/agents/fullstack-engineer.md +61 -0
  91. package/assets/profiles/sveltekit/agents/frontend-engineer.md +96 -0
  92. package/assets/profiles/vuenuxt/agents/frontend-engineer.md +82 -0
  93. package/assets/profiles/wordpress/README.md +30 -0
  94. package/assets/profiles/wordpress/agents/divi-engineer.md +273 -0
  95. package/assets/profiles/wordpress/agents/elementor-engineer.md +310 -0
  96. package/assets/profiles/wordpress/agents/wp-engineer.md +216 -0
  97. package/assets/requirements.txt +2 -0
  98. package/assets/scripts/aitmpl-search.py +808 -0
  99. package/assets/scripts/forge-add-opportunities.py +92 -0
  100. package/assets/scripts/forge-audit.py +1061 -0
  101. package/assets/scripts/forge-generate-all.py +283 -0
  102. package/assets/scripts/forge-init.py +900 -0
  103. package/assets/scripts/forge-migrate-project-yaml.py +397 -0
  104. package/assets/scripts/forge-scaffold-profile.py +181 -0
  105. package/assets/scripts/forge-teardown.py +193 -0
  106. package/assets/scripts/forge-validate-project-yaml.py +457 -0
  107. package/assets/scripts/forge-wizard.py +1003 -0
  108. package/assets/scripts/setup-codex.sh +229 -0
  109. package/assets/scripts/team-install.sh +147 -0
  110. package/assets/scripts/token-stats.py +201 -0
  111. package/assets/templates/modes/enterprise.yaml.tpl +114 -0
  112. package/assets/templates/modes/multi-runtime.yaml.tpl +89 -0
  113. package/assets/templates/modes/new-stack.yaml.tpl +101 -0
  114. package/assets/templates/modes/startup.yaml.tpl +74 -0
  115. package/assets/templates/project.yaml.tpl +185 -0
  116. package/assets/templates/wiki/concepts/_template.md +22 -0
  117. package/assets/templates/wiki/entities/_template.md +19 -0
  118. package/assets/templates/wiki/index.md +32 -0
  119. package/assets/templates/wiki/log.md +6 -0
  120. package/assets/templates/wiki/sources/_template.md +25 -0
  121. package/dist/cli.d.ts +3 -0
  122. package/dist/cli.d.ts.map +1 -0
  123. package/dist/cli.js +64 -0
  124. package/dist/cli.js.map +1 -0
  125. package/dist/commands/audit.d.ts +2 -0
  126. package/dist/commands/audit.d.ts.map +1 -0
  127. package/dist/commands/audit.js +21 -0
  128. package/dist/commands/audit.js.map +1 -0
  129. package/dist/commands/doctor.d.ts +2 -0
  130. package/dist/commands/doctor.d.ts.map +1 -0
  131. package/dist/commands/doctor.js +58 -0
  132. package/dist/commands/doctor.js.map +1 -0
  133. package/dist/commands/generate.d.ts +2 -0
  134. package/dist/commands/generate.d.ts.map +1 -0
  135. package/dist/commands/generate.js +27 -0
  136. package/dist/commands/generate.js.map +1 -0
  137. package/dist/commands/init.d.ts +2 -0
  138. package/dist/commands/init.d.ts.map +1 -0
  139. package/dist/commands/init.js +22 -0
  140. package/dist/commands/init.js.map +1 -0
  141. package/dist/commands/validate.d.ts +2 -0
  142. package/dist/commands/validate.d.ts.map +1 -0
  143. package/dist/commands/validate.js +20 -0
  144. package/dist/commands/validate.js.map +1 -0
  145. package/dist/lib/paths.d.ts +10 -0
  146. package/dist/lib/paths.d.ts.map +1 -0
  147. package/dist/lib/paths.js +49 -0
  148. package/dist/lib/paths.js.map +1 -0
  149. package/dist/lib/python.d.ts +4 -0
  150. package/dist/lib/python.d.ts.map +1 -0
  151. package/dist/lib/python.js +46 -0
  152. package/dist/lib/python.js.map +1 -0
  153. package/package.json +46 -0
@@ -0,0 +1,58 @@
1
+ import { findPython, hasPyyaml } from '../lib/python.js';
2
+ import { resolveForgeRoot } from '../lib/paths.js';
3
+ export async function doctor(_args) {
4
+ let ok = true;
5
+ console.log('forge doctor — environment check\n');
6
+ // Python
7
+ const python = findPython();
8
+ if (python) {
9
+ console.log(` ✓ Python: ${python}`);
10
+ }
11
+ else {
12
+ console.log(' ✗ Python 3.9+ not found');
13
+ console.log(' macOS: brew install python3');
14
+ console.log(' Ubuntu: sudo apt install python3');
15
+ console.log(' Win: https://python.org/downloads');
16
+ ok = false;
17
+ }
18
+ // pyyaml
19
+ if (python) {
20
+ if (hasPyyaml(python)) {
21
+ console.log(' ✓ pyyaml: installed');
22
+ }
23
+ else {
24
+ console.log(' ✗ pyyaml not found');
25
+ console.log(` ${python} -m pip install pyyaml`);
26
+ ok = false;
27
+ }
28
+ }
29
+ // forge root
30
+ try {
31
+ const root = resolveForgeRoot();
32
+ console.log(` ✓ forge root: ${root}`);
33
+ }
34
+ catch (e) {
35
+ const msg = e instanceof Error ? e.message : String(e);
36
+ console.log(` ✗ forge root: ${msg}`);
37
+ ok = false;
38
+ }
39
+ // project.yaml
40
+ const { existsSync } = await import('fs');
41
+ const { join } = await import('path');
42
+ const projectYaml = join(process.cwd(), 'project.yaml');
43
+ if (existsSync(projectYaml)) {
44
+ console.log(' ✓ project.yaml: found');
45
+ }
46
+ else {
47
+ console.log(' ~ project.yaml: not found (run forge init)');
48
+ }
49
+ console.log('');
50
+ if (ok) {
51
+ console.log('All checks passed.');
52
+ }
53
+ else {
54
+ console.log('Some checks failed. Fix the issues above and run forge doctor again.');
55
+ }
56
+ return ok ? 0 : 1;
57
+ }
58
+ //# sourceMappingURL=doctor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAEnD,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,KAAe;IAC1C,IAAI,EAAE,GAAG,IAAI,CAAC;IAEd,OAAO,CAAC,GAAG,CAAC,oCAAoC,CAAC,CAAC;IAElD,SAAS;IACT,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,IAAI,MAAM,EAAE,CAAC;QACX,OAAO,CAAC,GAAG,CAAC,eAAe,MAAM,EAAE,CAAC,CAAC;IACvC,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAC;QACzC,OAAO,CAAC,GAAG,CAAC,kCAAkC,CAAC,CAAC;QAChD,OAAO,CAAC,GAAG,CAAC,sCAAsC,CAAC,CAAC;QACpD,OAAO,CAAC,GAAG,CAAC,0CAA0C,CAAC,CAAC;QACxD,EAAE,GAAG,KAAK,CAAC;IACb,CAAC;IAED,SAAS;IACT,IAAI,MAAM,EAAE,CAAC;QACX,IAAI,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC;YACtB,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;QACvC,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC;YACpC,OAAO,CAAC,GAAG,CAAC,OAAO,MAAM,wBAAwB,CAAC,CAAC;YACnD,EAAE,GAAG,KAAK,CAAC;QACb,CAAC;IACH,CAAC;IAED,aAAa;IACb,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,gBAAgB,EAAE,CAAC;QAChC,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,EAAE,CAAC,CAAC;IACzC,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,OAAO,CAAC,GAAG,CAAC,mBAAmB,GAAG,EAAE,CAAC,CAAC;QACtC,EAAE,GAAG,KAAK,CAAC;IACb,CAAC;IAED,eAAe;IACf,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,CAAC;IAC1C,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,CAAC;IACtC,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,cAAc,CAAC,CAAC;IACxD,IAAI,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QAC5B,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC,CAAC;IACzC,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,GAAG,CAAC,8CAA8C,CAAC,CAAC;IAC9D,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,IAAI,EAAE,EAAE,CAAC;QACP,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;IACpC,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,GAAG,CAAC,sEAAsE,CAAC,CAAC;IACtF,CAAC;IAED,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACpB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function generate(args: string[]): Promise<number>;
2
+ //# sourceMappingURL=generate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../src/commands/generate.ts"],"names":[],"mappings":"AAoBA,wBAAsB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAO9D"}
@@ -0,0 +1,27 @@
1
+ import { resolveScript } from '../lib/paths.js';
2
+ import { runPython } from '../lib/python.js';
3
+ const HELP = `Usage: forge generate [options]
4
+
5
+ Generate runtime configuration files from project.yaml.
6
+ Auto-detects active runtimes by filesystem markers.
7
+
8
+ Options:
9
+ --runtime <name> Generate for specific runtime: claude-code, opencode, codex, kiro, all
10
+ --dry-run Show what would be generated without writing files
11
+ --force Overwrite existing files without prompting
12
+ -h, --help Show this help
13
+
14
+ Examples:
15
+ forge generate # auto-detect runtimes
16
+ forge generate --runtime claude-code
17
+ forge generate --runtime all --dry-run
18
+ `;
19
+ export async function generate(args) {
20
+ if (args.includes('-h') || args.includes('--help')) {
21
+ process.stdout.write(HELP);
22
+ return 0;
23
+ }
24
+ const script = resolveScript('forge-generate-all.py');
25
+ return runPython(script, args);
26
+ }
27
+ //# sourceMappingURL=generate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate.js","sourceRoot":"","sources":["../../src/commands/generate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAE7C,MAAM,IAAI,GAAG;;;;;;;;;;;;;;;CAeZ,CAAC;AAEF,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,MAAM,GAAG,aAAa,CAAC,uBAAuB,CAAC,CAAC;IACtD,OAAO,SAAS,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;AACjC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function init(args: string[]): Promise<number>;
2
+ //# sourceMappingURL=init.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAeA,wBAAsB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAO1D"}
@@ -0,0 +1,22 @@
1
+ import { resolveScript } from '../lib/paths.js';
2
+ import { runPython } from '../lib/python.js';
3
+ const HELP = `Usage: forge init [options]
4
+
5
+ Initialize forge in a project. Creates project.yaml via interactive wizard
6
+ and generates agent files for the selected runtime.
7
+
8
+ Options:
9
+ --runtime <name> Target runtime: claude-code, opencode, codex, kiro
10
+ --dry-run Show what would be created without writing files
11
+ --force Skip confirmation prompts
12
+ -h, --help Show this help
13
+ `;
14
+ export async function init(args) {
15
+ if (args.includes('-h') || args.includes('--help')) {
16
+ process.stdout.write(HELP);
17
+ return 0;
18
+ }
19
+ const script = resolveScript('forge-init.py');
20
+ return runPython(script, args);
21
+ }
22
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAE7C,MAAM,IAAI,GAAG;;;;;;;;;;CAUZ,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,IAAI,CAAC,IAAc;IACvC,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,MAAM,GAAG,aAAa,CAAC,eAAe,CAAC,CAAC;IAC9C,OAAO,SAAS,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;AACjC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function validate(args: string[]): Promise<number>;
2
+ //# sourceMappingURL=validate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/commands/validate.ts"],"names":[],"mappings":"AAaA,wBAAsB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAO9D"}
@@ -0,0 +1,20 @@
1
+ import { resolveScript } from '../lib/paths.js';
2
+ import { runPython } from '../lib/python.js';
3
+ const HELP = `Usage: forge validate [options]
4
+
5
+ Validate project.yaml in the current directory against the forge v2 schema.
6
+ Exits with code 1 if validation fails (suitable for CI pre-checks).
7
+
8
+ Options:
9
+ --json Output errors as JSON
10
+ -h, --help Show this help
11
+ `;
12
+ export async function validate(args) {
13
+ if (args.includes('-h') || args.includes('--help')) {
14
+ process.stdout.write(HELP);
15
+ return 0;
16
+ }
17
+ const script = resolveScript('forge-validate-project-yaml.py');
18
+ return runPython(script, args);
19
+ }
20
+ //# sourceMappingURL=validate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.js","sourceRoot":"","sources":["../../src/commands/validate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAE7C,MAAM,IAAI,GAAG;;;;;;;;CAQZ,CAAC;AAEF,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,MAAM,GAAG,aAAa,CAAC,gCAAgC,CAAC,CAAC;IAC/D,OAAO,SAAS,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;AACjC,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Resolves the forge root directory in priority order:
3
+ * 1. FORGE_HOME env var
4
+ * 2. assets/ next to the compiled CLI (npm package mode)
5
+ * 3. Walk up from __dirname looking for forge.py (dev mode / legacy .agentic/)
6
+ * 4. .agentic/ or forge/ in cwd (consumer project with submodule)
7
+ */
8
+ export declare function resolveForgeRoot(): string;
9
+ export declare function resolveScript(name: string): string;
10
+ //# sourceMappingURL=paths.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/lib/paths.ts"],"names":[],"mappings":"AAMA;;;;;;GAMG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,CA6BzC;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAOlD"}
@@ -0,0 +1,49 @@
1
+ import { existsSync } from 'fs';
2
+ import { join, dirname } from 'path';
3
+ import { fileURLToPath } from 'url';
4
+ const __dirname = dirname(fileURLToPath(import.meta.url));
5
+ /**
6
+ * Resolves the forge root directory in priority order:
7
+ * 1. FORGE_HOME env var
8
+ * 2. assets/ next to the compiled CLI (npm package mode)
9
+ * 3. Walk up from __dirname looking for forge.py (dev mode / legacy .agentic/)
10
+ * 4. .agentic/ or forge/ in cwd (consumer project with submodule)
11
+ */
12
+ export function resolveForgeRoot() {
13
+ if (process.env.FORGE_HOME) {
14
+ const p = process.env.FORGE_HOME;
15
+ if (existsSync(join(p, 'forge.py')))
16
+ return p;
17
+ throw new Error(`FORGE_HOME="${p}" does not contain forge.py`);
18
+ }
19
+ // npm package mode: __dirname is dist/lib/, assets/ is at package root (two levels up)
20
+ const assetsPath = join(__dirname, '..', '..', 'assets');
21
+ if (existsSync(join(assetsPath, 'forge.py')))
22
+ return assetsPath;
23
+ // dev mode: walk up from __dirname to find forge.py
24
+ let dir = __dirname;
25
+ for (let i = 0; i < 8; i++) {
26
+ if (existsSync(join(dir, 'forge.py')))
27
+ return dir;
28
+ const parent = dirname(dir);
29
+ if (parent === dir)
30
+ break;
31
+ dir = parent;
32
+ }
33
+ // consumer project: look for .agentic/ or forge/ from cwd
34
+ for (const candidate of ['.agentic', 'forge']) {
35
+ const p = join(process.cwd(), candidate);
36
+ if (existsSync(join(p, 'forge.py')))
37
+ return p;
38
+ }
39
+ throw new Error('forge root not found. Set FORGE_HOME or install via: npx @cristiancorreau/forge');
40
+ }
41
+ export function resolveScript(name) {
42
+ const root = resolveForgeRoot();
43
+ const scriptPath = join(root, 'scripts', name);
44
+ if (!existsSync(scriptPath)) {
45
+ throw new Error(`Script not found: ${scriptPath}`);
46
+ }
47
+ return scriptPath;
48
+ }
49
+ //# sourceMappingURL=paths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/lib/paths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAChC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AACrC,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AAEpC,MAAM,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAE1D;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB;IAC9B,IAAI,OAAO,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC;QAC3B,MAAM,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC;QACjC,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC;YAAE,OAAO,CAAC,CAAC;QAC9C,MAAM,IAAI,KAAK,CAAC,eAAe,CAAC,6BAA6B,CAAC,CAAC;IACjE,CAAC;IAED,uFAAuF;IACvF,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;IACzD,IAAI,UAAU,CAAC,IAAI,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;QAAE,OAAO,UAAU,CAAC;IAEhE,oDAAoD;IACpD,IAAI,GAAG,GAAG,SAAS,CAAC;IACpB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3B,IAAI,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC;YAAE,OAAO,GAAG,CAAC;QAClD,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;QAC5B,IAAI,MAAM,KAAK,GAAG;YAAE,MAAM;QAC1B,GAAG,GAAG,MAAM,CAAC;IACf,CAAC;IAED,0DAA0D;IAC1D,KAAK,MAAM,SAAS,IAAI,CAAC,UAAU,EAAE,OAAO,CAAC,EAAE,CAAC;QAC9C,MAAM,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,SAAS,CAAC,CAAC;QACzC,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC;YAAE,OAAO,CAAC,CAAC;IAChD,CAAC;IAED,MAAM,IAAI,KAAK,CACb,iFAAiF,CAClF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,MAAM,IAAI,GAAG,gBAAgB,EAAE,CAAC;IAChC,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC;IAC/C,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CAAC,qBAAqB,UAAU,EAAE,CAAC,CAAC;IACrD,CAAC;IACD,OAAO,UAAU,CAAC;AACpB,CAAC"}
@@ -0,0 +1,4 @@
1
+ export declare function findPython(): string | null;
2
+ export declare function hasPyyaml(python: string): boolean;
3
+ export declare function runPython(script: string, args: string[]): number;
4
+ //# sourceMappingURL=python.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"python.d.ts","sourceRoot":"","sources":["../../src/lib/python.ts"],"names":[],"mappings":"AAIA,wBAAgB,UAAU,IAAI,MAAM,GAAG,IAAI,CAgB1C;AAED,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAGjD;AAED,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,CA2BhE"}
@@ -0,0 +1,46 @@
1
+ import { spawnSync } from 'child_process';
2
+ const PYTHON_CANDIDATES = ['python3', 'python'];
3
+ export function findPython() {
4
+ for (const bin of PYTHON_CANDIDATES) {
5
+ try {
6
+ const result = spawnSync(bin, ['--version'], { encoding: 'utf8' });
7
+ if (result.status === 0) {
8
+ const version = result.stdout || result.stderr || '';
9
+ const match = version.match(/Python (\d+)\.(\d+)/);
10
+ if (match && (parseInt(match[1]) > 3 || (parseInt(match[1]) === 3 && parseInt(match[2]) >= 9))) {
11
+ return bin;
12
+ }
13
+ }
14
+ }
15
+ catch {
16
+ // not found, try next
17
+ }
18
+ }
19
+ return null;
20
+ }
21
+ export function hasPyyaml(python) {
22
+ const result = spawnSync(python, ['-c', 'import yaml'], { encoding: 'utf8' });
23
+ return result.status === 0;
24
+ }
25
+ export function runPython(script, args) {
26
+ const python = findPython();
27
+ if (!python) {
28
+ console.error('Error: Python 3.9+ is required but was not found.\n\n' +
29
+ 'Install Python:\n' +
30
+ ' macOS: brew install python3\n' +
31
+ ' Ubuntu: sudo apt install python3\n' +
32
+ ' Win: https://python.org/downloads\n');
33
+ return 1;
34
+ }
35
+ if (!hasPyyaml(python)) {
36
+ console.error('Error: pyyaml is required but not installed.\n\n' +
37
+ ` ${python} -m pip install pyyaml\n`);
38
+ return 1;
39
+ }
40
+ const result = spawnSync(python, [script, ...args], {
41
+ stdio: 'inherit',
42
+ env: { ...process.env },
43
+ });
44
+ return result.status ?? 1;
45
+ }
46
+ //# sourceMappingURL=python.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"python.js","sourceRoot":"","sources":["../../src/lib/python.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAY,MAAM,eAAe,CAAC;AAEpD,MAAM,iBAAiB,GAAG,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;AAEhD,MAAM,UAAU,UAAU;IACxB,KAAK,MAAM,GAAG,IAAI,iBAAiB,EAAE,CAAC;QACpC,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,SAAS,CAAC,GAAG,EAAE,CAAC,WAAW,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;YACnE,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACxB,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,IAAI,EAAE,CAAC;gBACrD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC;gBACnD,IAAI,KAAK,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;oBAC/F,OAAO,GAAG,CAAC;gBACb,CAAC;YACH,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,sBAAsB;QACxB,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,MAAc;IACtC,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,aAAa,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;IAC9E,OAAO,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC;AAC7B,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,MAAc,EAAE,IAAc;IACtD,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,CAAC,KAAK,CACX,uDAAuD;YACvD,mBAAmB;YACnB,kCAAkC;YAClC,sCAAsC;YACtC,0CAA0C,CAC3C,CAAC;QACF,OAAO,CAAC,CAAC;IACX,CAAC;IAED,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC;QACvB,OAAO,CAAC,KAAK,CACX,kDAAkD;YAClD,KAAK,MAAM,0BAA0B,CACtC,CAAC;QACF,OAAO,CAAC,CAAC;IACX,CAAC;IAED,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,EAAE;QAClD,KAAK,EAAE,SAAS;QAChB,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE;KACxB,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC,MAAM,IAAI,CAAC,CAAC;AAC5B,CAAC"}
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "@cristiancorreau/forge",
3
+ "version": "2.1.0",
4
+ "description": "Agentic development framework — multi-runtime support for Claude Code, OpenCode, Codex and Kiro",
5
+ "author": "Cristian Correa <cristian@socialweb.cl>",
6
+ "license": "Apache-2.0",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/cristiancorreau/forge"
10
+ },
11
+ "keywords": [
12
+ "ai",
13
+ "agents",
14
+ "claude-code",
15
+ "opencode",
16
+ "codex",
17
+ "kiro",
18
+ "agentic",
19
+ "framework"
20
+ ],
21
+ "type": "module",
22
+ "bin": {
23
+ "forge": "dist/cli.js"
24
+ },
25
+ "scripts": {
26
+ "build": "tsc",
27
+ "build:assets": "node scripts/build-assets.mjs",
28
+ "build:all": "npm run build:assets && npm run build",
29
+ "dev": "tsc --watch",
30
+ "prepublishOnly": "npm run build:all"
31
+ },
32
+ "files": [
33
+ "dist",
34
+ "assets",
35
+ "README.md",
36
+ "LICENSE",
37
+ "CHANGELOG.md"
38
+ ],
39
+ "devDependencies": {
40
+ "@types/node": "^20.0.0",
41
+ "typescript": "^5.4.0"
42
+ },
43
+ "engines": {
44
+ "node": ">=18.0.0"
45
+ }
46
+ }