create-foundry-workspace 1.0.0 → 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/README.md CHANGED
@@ -1,170 +1,172 @@
1
- # Foundry (`create-foundry-workspace`)
2
-
3
- > **Deterministic, local-first, zero-LLM CLI for initializing AI-ready software development workspaces.**
4
-
5
- [![CI](https://github.com/Harshitkant21/Foundry/actions/workflows/ci.yml/badge.svg)](https://github.com/Harshitkant21/Foundry/actions)
6
- [![npm version](https://img.shields.io/npm/v/create-foundry-workspace.svg?style=flat&color=CB3837)](https://www.npmjs.com/package/create-foundry-workspace)
7
- [![Node: >=18.0.0](https://img.shields.io/badge/Node->=18.0.0-green.svg)](package.json)
8
- [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
9
- [![Zero-LLM Runtime](https://img.shields.io/badge/Architecture-Deterministic%20Zero--LLM-8A2BE2.svg)](docs/ARCHITECTURE.md)
10
-
11
- ---
12
-
13
- ## What is Foundry?
14
-
15
- Modern developers increasingly rely on AI coding assistants such as **Cursor**, **Claude Code**, and **GitHub Copilot**. However, when starting a new project, developers are forced to manually author and repeatedly recreate AI instruction files, project rules, context files, and guardrails.
16
-
17
- **Foundry** is an open-source, deterministic developer tool distributed via npm as **`create-foundry-workspace`**. When starting a new project, running:
18
-
19
- ```bash
20
- npx create-foundry-workspace
21
- # or: npm create foundry-workspace
22
- ```
23
-
24
- asks a minimal set of meaningful project initialization questions and deterministically scaffolds an **AI-ready software workspace** based on predefined, versioned, and maintainable templates.
25
-
26
- ---
27
-
28
- ## What Foundry Does
29
-
30
- - **Establishes a Canonical Contract:** Generates a clean, machine-readable `ai-workspace.yaml` manifest.
31
- - **Generates Native Tool Adapters:** Renders native, complete instruction files for **Cursor** (`.cursor/rules/*.mdc`), **Claude Code** (`CLAUDE.md`), **GitHub Copilot** (`.github/copilot-instructions.md`), and the cross-tool open standard **`AGENTS.md`**.
32
- - **Generates Project README:** Creates a deterministic, human-facing `README.md` tailored to the selected project stack, commands, and AI tools.
33
- - **Enforces Architectural Guardrails:** Injects strict or standard code quality, security, and testing guardrails.
34
- - **Safeguards Existing Files:** Supports non-destructive safe-merges, overwrite protection, and dry-run execution.
35
-
36
- ---
37
-
38
- ## What Foundry Explicitly Does NOT Do
39
-
40
- Foundry is **NOT an AI agent** and does not use AI to generate workspaces:
41
- - ❌ **NO OpenAI, Anthropic, or Gemini API calls**
42
- - ❌ **NO local or remote LLM inference**
43
- - ❌ **NO network requests at runtime** (100% offline and local-first)
44
- - ❌ **NO hidden API keys or telemetry**
45
- - ❌ **NO autonomous code generation**
46
-
47
- Output is 100% deterministic: given the same inputs and version, the generated workspace is bit-for-bit identical every time.
48
-
49
- ---
50
-
51
- ## Quick Start
52
-
53
- Initialize an AI-ready workspace in your current directory:
54
- ```bash
55
- npx create-foundry-workspace
56
- # or: npm create foundry-workspace
57
- ```
58
-
59
- Or target a specific folder:
60
- ```bash
61
- npx create-foundry-workspace ./my-new-project
62
- ```
63
-
64
- ### Non-Interactive (CI / Scripted) Usage
65
- ```bash
66
- npx create-foundry-workspace ./my-new-service \
67
- --name my-new-service \
68
- --type api \
69
- --lang python \
70
- --strictness strict \
71
- --ai cursor,claude,copilot,agents \
72
- --yes
73
- ```
74
-
75
- ---
76
-
77
- ## CLI Options
78
-
79
- | Flag | Description | Default |
80
- |---|---|---|
81
- | `[directory]` | Target directory to initialize | `.` |
82
- | `-n, --name <string>` | Project name | Inferred from folder or `package.json` |
83
- | `-t, --type <type>` | `web` \| `api` \| `fullstack` \| `cli` \| `library` \| `data-ml` \| `mobile` \| `custom` | Inferred or `fullstack` |
84
- | `-l, --lang <lang>` | `typescript` \| `javascript` \| `python` \| `java` \| `go` \| `rust` \| `other` | Inferred or `typescript` |
85
- | `-r, --repo <repo>` | `github` \| `gitlab` \| `none` | `github` |
86
- | `-s, --strictness <level>` | `standard` \| `strict` | `standard` |
87
- | `-a, --ai <adapters>` | Comma-separated list of adapters (`claude,cursor,agents,copilot,codex,gemini,generic`) | `claude,cursor,agents` |
88
- | `--dry-run` | Preview files in terminal without writing to disk | `false` |
89
- | `-f, --force` | Overwrite conflicting files | `false` |
90
- | `-y, --yes` | Accept all defaults non-interactively | `false` |
91
- | `-v, --version` | Display version | |
92
- | `-h, --help` | Display help | |
93
-
94
- ---
95
-
96
- ## Generated Workspace Structure
97
-
98
- Foundry generates a deterministic, standardized workspace with zero bloat and zero hallucinations:
99
-
100
- ```text
101
- my-project/
102
- ├── ai-workspace.yaml # Canonical machine contract
103
- ├── README.md # Project documentation & stack guide
104
- ├── AI_CONTEXT.md # System map and entrypoint for AI assistants
105
- ├── PROJECT_GUARDRAILS.md # Standalone architectural guardrails & testing rules
106
- ├── CONTRIBUTING.md # Contribution workflow & guidelines
107
- ├── .gitignore # Language-tailored ignore rules
108
- │
109
- ├── .ai/ # AI operational intelligence directory
110
- │ ├── context/project-context.md # Detailed project domain background
111
- │ ├── rules/00-core-rules.md # Core workspace rules & coding conventions
112
- │ ├── architecture/system-design.md # High-level architecture & layer boundaries
113
- │ ├── decisions/0001-project-init.md # Initial architecture decision record (ADR)
114
- │ └── tasks/task-backlog.md # Operational scratchpad for AI agent task execution
115
- │
116
- ├── docs/ # Human-facing project documentation
117
- │ ├── README.md # Documentation index
118
- │ ├── ARCHITECTURE.md # System architecture & component design
119
- │ ├── DEVELOPMENT.md # Local setup, run, and test guides
120
- │ └── DECISIONS.md # Architecture decision records index
121
- │
122
- └── [Tool Adapters] # Based on user selection:
123
- ├── AGENTS.md # Multi-Agent open standard
124
- ├── CLAUDE.md # Anthropic Claude Code CLI
125
- ├── .cursor/rules/*.mdc # Cursor IDE modular rules
126
- ├── .github/copilot-instructions.md # GitHub Copilot context
127
- ├── .codex/instructions.md # OpenAI Codex context
128
- ├── GEMINI.md # Google Antigravity & Gemini CLI
129
- └── AI_INSTRUCTIONS.md # Generic AI assistant instructions
130
- ```
131
-
132
- ---
133
-
134
- ## Repository Architecture & Dogfooding
135
-
136
- Foundry strictly practices **dogfooding**. The Foundry repository itself is governed by the same `ai-workspace.yaml`, `AGENTS.md`, `CLAUDE.md`, `.cursor/`, and `.github/` files that it generates for users.
137
-
138
- For deeper architectural details, review the internal documentation:
139
- - [docs/SPECIFICATION.md](file:///d:/Extentions/Foundry/docs/SPECIFICATION.md) — Formal specification of the AI Workspace contract.
140
- - [docs/ARCHITECTURE.md](file:///d:/Extentions/Foundry/docs/ARCHITECTURE.md) — System architecture, module boundaries, and pure core pipeline.
141
- - [docs/ADAPTERS.md](file:///d:/Extentions/Foundry/docs/ADAPTERS.md) — Adapter interface specification and registry design.
142
- - [docs/DEVELOPMENT.md](file:///d:/Extentions/Foundry/docs/DEVELOPMENT.md) — Developer setup and testing guide.
143
-
144
- ---
145
-
146
- ## Development & Testing
147
-
148
- ```bash
149
- # Clone the repository
150
- git clone https://github.com/Harshitkant21/Foundry.git
151
- cd Foundry
152
-
153
- # Install dependencies
154
- npm install
155
-
156
- # Run Vitest test suite
157
- npm test
158
-
159
- # Build TypeScript to dist/
160
- npm run build
161
-
162
- # Run local development CLI
163
- npx tsx src/bin.ts --dry-run
164
- ```
165
-
166
- ---
167
-
168
- ## License
169
-
170
- MIT © Foundry Contributors
1
+ # Foundry (`create-foundry-workspace`)
2
+
3
+ > **Deterministic, local-first, zero-LLM CLI for initializing AI-ready software development workspaces.**
4
+
5
+ [![CI](https://github.com/Harshitkant21/Foundry/actions/workflows/ci.yml/badge.svg)](https://github.com/Harshitkant21/Foundry/actions)
6
+ [![npm version](https://img.shields.io/npm/v/create-foundry-workspace.svg?style=flat&color=CB3837)](https://www.npmjs.com/package/create-foundry-workspace)
7
+ [![Node: >=18.0.0](https://img.shields.io/badge/Node->=18.0.0-green.svg)](package.json)
8
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
9
+ [![Zero-LLM Runtime](https://img.shields.io/badge/Architecture-Deterministic%20Zero--LLM-8A2BE2.svg)](docs/architecture/ARCHITECTURE.md)
10
+
11
+ ---
12
+
13
+ ## What is Foundry?
14
+
15
+ Modern developers increasingly rely on AI coding assistants such as **Cursor**, **Claude Code**, and **GitHub Copilot**. However, when starting a new project, developers are forced to manually author and repeatedly recreate AI instruction files, project rules, context files, and guardrails.
16
+
17
+ **Foundry** is an open-source, deterministic developer tool distributed via npm as **`create-foundry-workspace`**. When starting a new project, running:
18
+
19
+ ```bash
20
+ npx create-foundry-workspace
21
+ # or: npm create foundry-workspace
22
+ ```
23
+
24
+ asks a minimal set of meaningful project initialization questions and deterministically scaffolds an **AI-ready software workspace** based on predefined, versioned, and maintainable templates.
25
+
26
+ ---
27
+
28
+ ## What Foundry Does
29
+
30
+ - **Establishes a Canonical Contract:** Generates a clean, machine-readable `ai-workspace.yaml` manifest.
31
+ - **Generates Native Tool Adapters:** Renders native, complete instruction files for **Cursor** (`.cursor/rules/*.mdc`), **Claude Code** (`CLAUDE.md`), **GitHub Copilot** (`.github/copilot-instructions.md`), and the cross-tool open standard **`AGENTS.md`**.
32
+ - **Generates Project README:** Creates a deterministic, human-facing `README.md` tailored to the selected project stack, commands, and AI tools.
33
+ - **Enforces Architectural Guardrails:** Injects strict or standard code quality, security, and testing guardrails.
34
+ - **Safeguards Existing Files:** Supports non-destructive safe-merges, overwrite protection, and dry-run execution.
35
+
36
+ ---
37
+
38
+ ## What Foundry Explicitly Does NOT Do
39
+
40
+ Foundry is **NOT an AI agent** and does not use AI to generate workspaces:
41
+ - ❌ **NO OpenAI, Anthropic, or Gemini API calls**
42
+ - ❌ **NO local or remote LLM inference**
43
+ - ❌ **NO network requests at runtime** (100% offline and local-first)
44
+ - ❌ **NO hidden API keys or telemetry**
45
+ - ❌ **NO autonomous code generation**
46
+
47
+ Output is 100% deterministic: given the same inputs and version, the generated workspace is bit-for-bit identical every time.
48
+
49
+ ---
50
+
51
+ ## Quick Start
52
+
53
+ Initialize an AI-ready workspace in your current directory:
54
+ ```bash
55
+ npx create-foundry-workspace
56
+ # or: npm create foundry-workspace
57
+ ```
58
+
59
+ Or target a specific folder:
60
+ ```bash
61
+ npx create-foundry-workspace ./my-new-project
62
+ ```
63
+
64
+ ### Non-Interactive (CI / Scripted) Usage
65
+ ```bash
66
+ npx create-foundry-workspace ./my-new-service \
67
+ --name my-new-service \
68
+ --type api \
69
+ --lang python \
70
+ --strictness strict \
71
+ --ai cursor,claude,copilot,agents \
72
+ --yes
73
+ ```
74
+
75
+ ---
76
+
77
+ ## CLI Options
78
+
79
+ | Flag | Description | Default |
80
+ |---|---|---|
81
+ | `[directory]` | Target directory to initialize | `.` |
82
+ | `-n, --name <string>` | Project name | Inferred from folder or `package.json` |
83
+ | `-t, --type <type>` | `web` \| `api` \| `fullstack` \| `cli` \| `library` \| `data-ml` \| `mobile` \| `custom` | Inferred or `fullstack` |
84
+ | `-l, --lang <lang>` | `typescript` \| `javascript` \| `python` \| `java` \| `go` \| `rust` \| `other` | Inferred or `typescript` |
85
+ | `-r, --repo <repo>` | `github` \| `gitlab` \| `none` | `github` |
86
+ | `-s, --strictness <level>` | `standard` \| `strict` | `standard` |
87
+ | `-a, --ai <adapters>` | Comma-separated list of adapters (`claude,cursor,agents,copilot,codex,gemini,generic`) | `claude,cursor,agents` |
88
+ | `--dry-run` | Preview files in terminal without writing to disk | `false` |
89
+ | `-f, --force` | Overwrite conflicting files | `false` |
90
+ | `-y, --yes` | Accept all defaults non-interactively | `false` |
91
+ | `-v, --version` | Display version | |
92
+ | `-h, --help` | Display help | |
93
+
94
+ ---
95
+
96
+ ## Generated Workspace Structure
97
+
98
+ Foundry generates a deterministic, standardized workspace with zero bloat and zero hallucinations:
99
+
100
+ ```text
101
+ my-project/
102
+ ├── ai-workspace.yaml # Canonical machine contract
103
+ ├── README.md # Project documentation & stack guide
104
+ ├── AI_CONTEXT.md # System map and entrypoint for AI assistants
105
+ ├── PROJECT_GUARDRAILS.md # Standalone architectural guardrails & testing rules
106
+ ├── CONTRIBUTING.md # Contribution workflow & guidelines
107
+ ├── .gitignore # Language-tailored ignore rules
108
+ │
109
+ ├── .ai/ # AI operational intelligence directory
110
+ │ ├── context/project-context.md # Detailed project domain background
111
+ │ ├── rules/00-core-rules.md # Core workspace rules & coding conventions
112
+ │ ├── architecture/system-design.md # High-level architecture & layer boundaries
113
+ │ ├── decisions/0001-project-init.md # Initial architecture decision record (ADR)
114
+ │ └── tasks/task-backlog.md # Operational scratchpad for AI agent task execution
115
+ │
116
+ ├── docs/ # Human-facing project documentation
117
+ │ ├── README.md # Documentation index
118
+ │ ├── ARCHITECTURE.md # System architecture & component design
119
+ │ ├── DEVELOPMENT.md # Local setup, run, and test guides
120
+ │ └── DECISIONS.md # Architecture decision records index
121
+ │
122
+ └── [Tool Adapters] # Based on user selection:
123
+ ├── AGENTS.md # Multi-Agent open standard
124
+ ├── CLAUDE.md # Anthropic Claude Code CLI
125
+ ├── .cursor/rules/*.mdc # Cursor IDE modular rules
126
+ ├── .github/copilot-instructions.md # GitHub Copilot context
127
+ ├── .codex/instructions.md # OpenAI Codex context
128
+ ├── GEMINI.md # Google Antigravity & Gemini CLI
129
+ └── AI_INSTRUCTIONS.md # Generic AI assistant instructions
130
+ ```
131
+
132
+ ---
133
+
134
+ ## Repository Architecture & Dogfooding
135
+
136
+ Foundry strictly practices **dogfooding**. The Foundry repository itself is governed by the same `ai-workspace.yaml`, `AGENTS.md`, `CLAUDE.md`, `.cursor/`, and `.github/` files that it generates for users.
137
+
138
+ For deeper architectural details and future roadmap, review the internal documentation:
139
+ - [docs/README.md](docs/README.md) — Documentation index and repository guide.
140
+ - [docs/specifications/SPECIFICATION.md](docs/specifications/SPECIFICATION.md) — Formal specification of the AI Workspace contract.
141
+ - [docs/architecture/ARCHITECTURE.md](docs/architecture/ARCHITECTURE.md) — System architecture, module boundaries, and pure core pipeline.
142
+ - [docs/architecture/ADAPTERS.md](docs/architecture/ADAPTERS.md) — Adapter interface specification and registry design.
143
+ - [docs/development/DEVELOPMENT.md](docs/development/DEVELOPMENT.md) — Developer setup and testing guide.
144
+ - [docs/planning/FOUNDRY_AUDIT_AND_ROADMAP.md](docs/planning/FOUNDRY_AUDIT_AND_ROADMAP.md) — Comprehensive repository audit, architecture evaluation, and phased roadmap (Proposed / Working Plan — Pending Review).
145
+
146
+ ---
147
+
148
+ ## Development & Testing
149
+
150
+ ```bash
151
+ # Clone the repository
152
+ git clone https://github.com/Harshitkant21/Foundry.git
153
+ cd Foundry
154
+
155
+ # Install dependencies
156
+ npm install
157
+
158
+ # Run Vitest test suite
159
+ npm test
160
+
161
+ # Build TypeScript to dist/
162
+ npm run build
163
+
164
+ # Run local development CLI
165
+ npx tsx src/bin.ts --dry-run
166
+ ```
167
+
168
+ ---
169
+
170
+ ## License
171
+
172
+ MIT © Foundry Contributors
@@ -1,4 +1,5 @@
1
1
  import { AppType, Language } from '../config/schema.js';
2
+ import { ProjectFileSystem } from '../io/scanner.js';
2
3
  export interface DetectedEnvironment {
3
4
  readonly name: string;
4
5
  readonly language: Language;
@@ -7,7 +8,7 @@ export interface DetectedEnvironment {
7
8
  }
8
9
  /**
9
10
  * Deterministically inspects target directory markers to infer project defaults.
10
- * Completely decoupled from CLI prompt parsing.
11
+ * Decoupled from physical disk I/O via the ProjectFileSystem abstraction.
11
12
  */
12
- export declare function detectProjectEnvironment(targetDir: string): Promise<DetectedEnvironment>;
13
+ export declare function detectProjectEnvironment(targetDir: string, projectFs?: ProjectFileSystem): Promise<DetectedEnvironment>;
13
14
  //# sourceMappingURL=detector.d.ts.map
@@ -1,5 +1,6 @@
1
1
  import path from 'node:path';
2
2
  import { DEFAULT_APP_TYPE, DEFAULT_LANGUAGE } from '../config/defaults.js';
3
+ import { NodeProjectFileSystem } from '../io/scanner.js';
3
4
  import { detectGo } from './rules/go.js';
4
5
  import { detectJava } from './rules/java.js';
5
6
  import { detectNode } from './rules/node.js';
@@ -7,12 +8,13 @@ import { detectPython } from './rules/python.js';
7
8
  import { detectRust } from './rules/rust.js';
8
9
  /**
9
10
  * Deterministically inspects target directory markers to infer project defaults.
10
- * Completely decoupled from CLI prompt parsing.
11
+ * Decoupled from physical disk I/O via the ProjectFileSystem abstraction.
11
12
  */
12
- export async function detectProjectEnvironment(targetDir) {
13
+ export async function detectProjectEnvironment(targetDir, projectFs) {
14
+ const fs = projectFs ?? new NodeProjectFileSystem(targetDir);
13
15
  const fallbackName = path.basename(path.resolve(targetDir)) || 'my-workspace';
14
16
  // Run detectors in priority order
15
- const node = await detectNode(targetDir);
17
+ const node = await detectNode(fs);
16
18
  if (node) {
17
19
  return {
18
20
  name: node.name || fallbackName,
@@ -21,7 +23,7 @@ export async function detectProjectEnvironment(targetDir) {
21
23
  isDetected: true,
22
24
  };
23
25
  }
24
- const rust = await detectRust(targetDir);
26
+ const rust = await detectRust(fs);
25
27
  if (rust) {
26
28
  return {
27
29
  name: rust.name || fallbackName,
@@ -30,7 +32,7 @@ export async function detectProjectEnvironment(targetDir) {
30
32
  isDetected: true,
31
33
  };
32
34
  }
33
- const go = await detectGo(targetDir);
35
+ const go = await detectGo(fs);
34
36
  if (go) {
35
37
  return {
36
38
  name: go.name || fallbackName,
@@ -39,7 +41,7 @@ export async function detectProjectEnvironment(targetDir) {
39
41
  isDetected: true,
40
42
  };
41
43
  }
42
- const python = await detectPython(targetDir);
44
+ const python = await detectPython(fs);
43
45
  if (python) {
44
46
  return {
45
47
  name: fallbackName,
@@ -48,7 +50,7 @@ export async function detectProjectEnvironment(targetDir) {
48
50
  isDetected: true,
49
51
  };
50
52
  }
51
- const java = await detectJava(targetDir);
53
+ const java = await detectJava(fs);
52
54
  if (java) {
53
55
  return {
54
56
  name: fallbackName,
@@ -1,3 +1,4 @@
1
+ import { ProjectFileSystem } from '../../io/scanner.js';
1
2
  import { DetectionCandidate } from './node.js';
2
- export declare function detectGo(targetDir: string): Promise<DetectionCandidate | null>;
3
+ export declare function detectGo(fs: ProjectFileSystem): Promise<DetectionCandidate | null>;
3
4
  //# sourceMappingURL=go.d.ts.map
@@ -1,9 +1,7 @@
1
- import fs from 'node:fs/promises';
2
1
  import path from 'node:path';
3
- export async function detectGo(targetDir) {
4
- const goMod = path.join(targetDir, 'go.mod');
2
+ export async function detectGo(fs) {
5
3
  try {
6
- const raw = await fs.readFile(goMod, 'utf-8');
4
+ const raw = await fs.readFile('go.mod');
7
5
  const match = raw.match(/module\s+([^\s]+)/);
8
6
  const modName = match && match[1] ? path.basename(match[1]) : undefined;
9
7
  return {
@@ -1,3 +1,4 @@
1
+ import { ProjectFileSystem } from '../../io/scanner.js';
1
2
  import { DetectionCandidate } from './node.js';
2
- export declare function detectJava(targetDir: string): Promise<DetectionCandidate | null>;
3
+ export declare function detectJava(fs: ProjectFileSystem): Promise<DetectionCandidate | null>;
3
4
  //# sourceMappingURL=java.d.ts.map
@@ -1,27 +1,10 @@
1
- import fs from 'node:fs/promises';
2
- import path from 'node:path';
3
- export async function detectJava(targetDir) {
4
- const pomXml = path.join(targetDir, 'pom.xml');
5
- const gradle = path.join(targetDir, 'build.gradle');
6
- const gradleKts = path.join(targetDir, 'build.gradle.kts');
7
- let hasJava = false;
8
- try {
9
- await fs.access(pomXml);
10
- hasJava = true;
11
- }
12
- catch { }
13
- try {
14
- await fs.access(gradle);
15
- hasJava = true;
16
- }
17
- catch { }
18
- try {
19
- await fs.access(gradleKts);
20
- hasJava = true;
21
- }
22
- catch { }
23
- if (!hasJava)
1
+ export async function detectJava(fs) {
2
+ const hasPom = await fs.exists('pom.xml');
3
+ const hasGradle = await fs.exists('build.gradle');
4
+ const hasGradleKts = await fs.exists('build.gradle.kts');
5
+ if (!hasPom && !hasGradle && !hasGradleKts) {
24
6
  return null;
7
+ }
25
8
  return {
26
9
  language: 'java',
27
10
  type: 'api',
@@ -1,8 +1,9 @@
1
1
  import { AppType, Language } from '../../config/schema.js';
2
+ import { ProjectFileSystem } from '../../io/scanner.js';
2
3
  export interface DetectionCandidate {
3
4
  name?: string;
4
5
  language?: Language;
5
6
  type?: AppType;
6
7
  }
7
- export declare function detectNode(targetDir: string): Promise<DetectionCandidate | null>;
8
+ export declare function detectNode(fs: ProjectFileSystem): Promise<DetectionCandidate | null>;
8
9
  //# sourceMappingURL=node.d.ts.map
@@ -1,9 +1,6 @@
1
- import fs from 'node:fs/promises';
2
- import path from 'node:path';
3
- export async function detectNode(targetDir) {
4
- const pkgPath = path.join(targetDir, 'package.json');
1
+ export async function detectNode(fs) {
5
2
  try {
6
- const raw = await fs.readFile(pkgPath, 'utf-8');
3
+ const raw = await fs.readFile('package.json');
7
4
  const pkg = JSON.parse(raw);
8
5
  const name = typeof pkg.name === 'string' ? pkg.name.replace(/^@[^/]+\//, '') : undefined;
9
6
  let language = 'javascript';
@@ -12,11 +9,9 @@ export async function detectNode(targetDir) {
12
9
  (pkg.dependencies && pkg.dependencies.typescript)) {
13
10
  language = 'typescript';
14
11
  }
15
- try {
16
- await fs.access(path.join(targetDir, 'tsconfig.json'));
12
+ if (await fs.exists('tsconfig.json')) {
17
13
  language = 'typescript';
18
14
  }
19
- catch { }
20
15
  let type = 'fullstack';
21
16
  if (pkg.bin) {
22
17
  type = 'cli';
@@ -1,3 +1,4 @@
1
+ import { ProjectFileSystem } from '../../io/scanner.js';
1
2
  import { DetectionCandidate } from './node.js';
2
- export declare function detectPython(targetDir: string): Promise<DetectionCandidate | null>;
3
+ export declare function detectPython(fs: ProjectFileSystem): Promise<DetectionCandidate | null>;
3
4
  //# sourceMappingURL=python.d.ts.map
@@ -1,27 +1,10 @@
1
- import fs from 'node:fs/promises';
2
- import path from 'node:path';
3
- export async function detectPython(targetDir) {
4
- const pyproject = path.join(targetDir, 'pyproject.toml');
5
- const requirements = path.join(targetDir, 'requirements.txt');
6
- const setupPy = path.join(targetDir, 'setup.py');
7
- let hasPython = false;
8
- try {
9
- await fs.access(pyproject);
10
- hasPython = true;
11
- }
12
- catch { }
13
- try {
14
- await fs.access(requirements);
15
- hasPython = true;
16
- }
17
- catch { }
18
- try {
19
- await fs.access(setupPy);
20
- hasPython = true;
21
- }
22
- catch { }
23
- if (!hasPython)
1
+ export async function detectPython(fs) {
2
+ const hasPyproject = await fs.exists('pyproject.toml');
3
+ const hasReqs = await fs.exists('requirements.txt');
4
+ const hasSetup = await fs.exists('setup.py');
5
+ if (!hasPyproject && !hasReqs && !hasSetup) {
24
6
  return null;
7
+ }
25
8
  return {
26
9
  language: 'python',
27
10
  type: 'api',
@@ -1,3 +1,4 @@
1
+ import { ProjectFileSystem } from '../../io/scanner.js';
1
2
  import { DetectionCandidate } from './node.js';
2
- export declare function detectRust(targetDir: string): Promise<DetectionCandidate | null>;
3
+ export declare function detectRust(fs: ProjectFileSystem): Promise<DetectionCandidate | null>;
3
4
  //# sourceMappingURL=rust.d.ts.map
@@ -1,9 +1,6 @@
1
- import fs from 'node:fs/promises';
2
- import path from 'node:path';
3
- export async function detectRust(targetDir) {
4
- const cargoToml = path.join(targetDir, 'Cargo.toml');
1
+ export async function detectRust(fs) {
5
2
  try {
6
- const raw = await fs.readFile(cargoToml, 'utf-8');
3
+ const raw = await fs.readFile('Cargo.toml');
7
4
  const nameMatch = raw.match(/name\s*=\s*["']([^"']+)["']/);
8
5
  const projName = nameMatch && nameMatch[1] ? nameMatch[1] : undefined;
9
6
  return {
package/dist/index.d.ts CHANGED
@@ -7,6 +7,7 @@ export * from './core/context.js';
7
7
  export * from './core/generator.js';
8
8
  export * from './core/interpolator.js';
9
9
  export * from './io/paths.js';
10
+ export * from './io/scanner.js';
10
11
  export * from './io/writer.js';
11
12
  export * from './cli/command.js';
12
13
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -7,6 +7,7 @@ export * from './core/context.js';
7
7
  export * from './core/generator.js';
8
8
  export * from './core/interpolator.js';
9
9
  export * from './io/paths.js';
10
+ export * from './io/scanner.js';
10
11
  export * from './io/writer.js';
11
12
  export * from './cli/command.js';
12
13
  //# sourceMappingURL=index.js.map
package/dist/io/paths.js CHANGED
@@ -13,7 +13,8 @@ export function normalizeRelativePath(filePath) {
13
13
  export function resolveSafePath(baseDir, relativePath) {
14
14
  const resolvedBase = path.resolve(baseDir);
15
15
  const resolvedTarget = path.resolve(resolvedBase, relativePath);
16
- if (!resolvedTarget.startsWith(resolvedBase)) {
16
+ const rel = path.relative(resolvedBase, resolvedTarget);
17
+ if (rel.startsWith('..') || path.isAbsolute(rel)) {
17
18
  throw new Error(`Security Exception: Target path '${relativePath}' traverses outside base directory.`);
18
19
  }
19
20
  return resolvedTarget;
@@ -0,0 +1,18 @@
1
+ /**
2
+ * File system scanner interface for project detection.
3
+ * Enforces pure core isolation by keeping disk access inside src/io/.
4
+ */
5
+ export interface ProjectFileSystem {
6
+ readFile(relativePath: string): Promise<string>;
7
+ exists(relativePath: string): Promise<boolean>;
8
+ }
9
+ /**
10
+ * Default Node.js filesystem adapter for inspecting project directories.
11
+ */
12
+ export declare class NodeProjectFileSystem implements ProjectFileSystem {
13
+ private readonly rootDir;
14
+ constructor(targetDir: string);
15
+ readFile(relativePath: string): Promise<string>;
16
+ exists(relativePath: string): Promise<boolean>;
17
+ }
18
+ //# sourceMappingURL=scanner.d.ts.map
@@ -0,0 +1,26 @@
1
+ import fs from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ /**
4
+ * Default Node.js filesystem adapter for inspecting project directories.
5
+ */
6
+ export class NodeProjectFileSystem {
7
+ rootDir;
8
+ constructor(targetDir) {
9
+ this.rootDir = path.resolve(targetDir);
10
+ }
11
+ async readFile(relativePath) {
12
+ const filePath = path.join(this.rootDir, relativePath);
13
+ return fs.readFile(filePath, 'utf-8');
14
+ }
15
+ async exists(relativePath) {
16
+ const filePath = path.join(this.rootDir, relativePath);
17
+ try {
18
+ await fs.access(filePath);
19
+ return true;
20
+ }
21
+ catch {
22
+ return false;
23
+ }
24
+ }
25
+ }
26
+ //# sourceMappingURL=scanner.js.map
@@ -1,19 +1,67 @@
1
1
  export function renderContributing(context) {
2
2
  const { config, commands } = context;
3
- return `# Contributing to ${config.project.name}
4
-
5
- Thank you for contributing! Please follow the established development workflow and AI guidelines.
6
-
7
- ## Development Workflow
8
- 1. Fork or branch from \`main\`.
9
- 2. Make modular, focused changes.
10
- 3. Verify formatting and linting: \`${commands.lint}\`.
11
- 4. Run the full test suite: \`${commands.test}\`.
12
- 5. Ensure build succeeds: \`${commands.build}\`.
13
-
14
- ## AI-Assisted Contributions
15
- - When using AI coding assistants (Cursor, Claude, Copilot, etc.), ensure they respect [\`PROJECT_GUARDRAILS.md\`](./PROJECT_GUARDRAILS.md).
16
- - AI-generated code must be fully understood, tested, and reviewed by a human contributor.
3
+ return `# Contributing to ${config.project.name}
4
+
5
+ Thank you for contributing! Please adhere to our standardized engineering standards, branch conventions, and AI guardrails.
6
+
7
+ ---
8
+
9
+ ## 1. Development & Quality Workflow
10
+
11
+ Before submitting changes, ensure your working tree passes all verification gates:
12
+
13
+ 1. **Install dependencies & build:**
14
+ \`\`\`bash
15
+ ${commands.build}
16
+ \`\`\`
17
+ 2. **Format and lint:**
18
+ \`\`\`bash
19
+ ${commands.lint}
20
+ \`\`\`
21
+ 3. **Execute automated tests:**
22
+ \`\`\`bash
23
+ ${commands.test}
24
+ \`\`\`
25
+
26
+ ---
27
+
28
+ ## 2. Branching & Conventional Commits
29
+
30
+ We follow the [Conventional Commits](https://www.conventionalcommits.org/) specification for structured, machine-parseable commit history:
31
+
32
+ ### Commit Format
33
+ \`\`\`text
34
+ <type>(<scope>): <short description>
35
+ \`\`\`
36
+
37
+ ### Allowed Types
38
+ - **\`feat\`**: A new feature or capability.
39
+ - **\`fix\`**: A bug or regression fix.
40
+ - **\`docs\`**: Documentation additions or corrections.
41
+ - **\`refactor\`**: Code change that neither fixes a bug nor adds a feature.
42
+ - **\`test\`**: Adding or modifying test suites.
43
+ - **\`chore\`**: Tooling, dependencies, or repository maintenance.
44
+
45
+ ### Branch Naming Patterns
46
+ - \`feature/<short-topic>\` (e.g. \`feature/langgraph-adapter\`)
47
+ - \`bugfix/<issue-number>-<short-topic>\` (e.g. \`bugfix/102-path-traversal\`)
48
+ - \`docs/<topic>\` (e.g. \`docs/contributing-guide\`)
49
+
50
+ ---
51
+
52
+ ## 3. Pull Request Standards
53
+
54
+ - **Atomic Scope:** PRs must focus on a single conceptual change. Avoid bundling unrelated refactorings.
55
+ - **Zero Broken Tests:** All tests must pass before opening a PR.
56
+ - **Commit History:** Keep history clean and avoid merge commits where squashing or rebasing is requested.
57
+
58
+ ---
59
+
60
+ ## 4. AI-Assisted Contributions
61
+
62
+ - When using AI coding assistants (Cursor, Claude, Copilot, Antigravity, etc.), verify they strictly adhere to [\`PROJECT_GUARDRAILS.md\`](./PROJECT_GUARDRAILS.md).
63
+ - AI agents operate in **read-only Git mode by default**. Never allow an agent to stage or commit code without manual human inspection.
64
+ - All AI-generated code must be fully understood, tested, and reviewed by a human maintainer.
17
65
  `;
18
66
  }
19
67
  //# sourceMappingURL=contributing.js.map
package/package.json CHANGED
@@ -1,64 +1,64 @@
1
- {
2
- "name": "create-foundry-workspace",
3
- "version": "1.0.0",
4
- "description": "Deterministic, local-first CLI for scaffolding AI-ready software workspaces.",
5
- "type": "module",
6
- "main": "./dist/index.js",
7
- "bin": {
8
- "create-foundry-workspace": "./bin/index.js",
9
- "foundry": "./bin/index.js"
10
- },
11
- "files": [
12
- "dist",
13
- "!dist/**/*.map",
14
- "bin",
15
- "README.md",
16
- "LICENSE"
17
- ],
18
- "scripts": {
19
- "build": "tsc",
20
- "dev": "tsx src/bin.ts",
21
- "prepublishOnly": "npm run build && npm test",
22
- "test": "vitest run",
23
- "test:watch": "vitest",
24
- "typecheck": "tsc --noEmit"
25
- },
26
- "keywords": [
27
- "ai",
28
- "ai-coding",
29
- "developer-tools",
30
- "cli",
31
- "scaffolding",
32
- "workspace",
33
- "developer-experience",
34
- "cursor",
35
- "claude",
36
- "copilot",
37
- "codex",
38
- "gemini"
39
- ],
40
- "author": "Harshit Kant",
41
- "repository": {
42
- "type": "git",
43
- "url": "git+https://github.com/Harshitkant21/Foundry.git"
44
- },
45
- "bugs": {
46
- "url": "https://github.com/Harshitkant21/Foundry/issues"
47
- },
48
- "homepage": "https://github.com/Harshitkant21/Foundry#readme",
49
- "license": "MIT",
50
- "dependencies": {
51
- "@clack/prompts": "^0.8.2",
52
- "commander": "^12.1.0",
53
- "zod": "^3.23.8"
54
- },
55
- "devDependencies": {
56
- "@types/node": "^22.5.5",
57
- "tsx": "^4.19.1",
58
- "typescript": "^5.6.2",
59
- "vitest": "^2.1.1"
60
- },
61
- "engines": {
62
- "node": ">=18.0.0"
63
- }
64
- }
1
+ {
2
+ "name": "create-foundry-workspace",
3
+ "version": "1.0.1",
4
+ "description": "Deterministic, local-first CLI for scaffolding AI-ready software workspaces.",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "bin": {
8
+ "create-foundry-workspace": "./bin/index.js",
9
+ "foundry": "./bin/index.js"
10
+ },
11
+ "files": [
12
+ "dist",
13
+ "!dist/**/*.map",
14
+ "bin",
15
+ "README.md",
16
+ "LICENSE"
17
+ ],
18
+ "scripts": {
19
+ "build": "tsc",
20
+ "dev": "tsx src/bin.ts",
21
+ "prepublishOnly": "npm run build && npm test",
22
+ "test": "vitest run",
23
+ "test:watch": "vitest",
24
+ "typecheck": "tsc --noEmit"
25
+ },
26
+ "keywords": [
27
+ "ai",
28
+ "ai-coding",
29
+ "developer-tools",
30
+ "cli",
31
+ "scaffolding",
32
+ "workspace",
33
+ "developer-experience",
34
+ "cursor",
35
+ "claude",
36
+ "copilot",
37
+ "codex",
38
+ "gemini"
39
+ ],
40
+ "author": "Harshit Kant",
41
+ "repository": {
42
+ "type": "git",
43
+ "url": "git+https://github.com/Harshitkant21/Foundry.git"
44
+ },
45
+ "bugs": {
46
+ "url": "https://github.com/Harshitkant21/Foundry/issues"
47
+ },
48
+ "homepage": "https://github.com/Harshitkant21/Foundry#readme",
49
+ "license": "MIT",
50
+ "dependencies": {
51
+ "@clack/prompts": "^0.8.2",
52
+ "commander": "^12.1.0",
53
+ "zod": "^3.23.8"
54
+ },
55
+ "devDependencies": {
56
+ "@types/node": "^22.5.5",
57
+ "tsx": "^4.19.1",
58
+ "typescript": "^5.6.2",
59
+ "vitest": "^2.1.1"
60
+ },
61
+ "engines": {
62
+ "node": ">=18.0.0"
63
+ }
64
+ }