@p_tipso/agentive 1.0.0 → 1.0.2
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 +67 -83
- package/package.json +2 -2
- package/src/commands/init.js +65 -100
- package/src/templates/base/AGENTS.md +29 -0
- package/src/templates/base/commands/README.md +26 -0
- package/src/templates/base/commands/fix-issue.md +41 -0
- package/src/templates/base/commands/review.md +37 -0
- package/src/templates/base/rules/README.md +29 -0
- package/src/templates/base/skills/README.md +29 -0
- package/src/templates/mobile/expo/rules/01-expo-components.md +17 -0
- package/src/templates/mobile/expo/rules/02-expo-styling.md +16 -0
- package/src/templates/mobile/expo/rules/expo-router.md +16 -0
- package/src/templates/mobile/expo/skills/create-expo-app.md +19 -0
- package/src/templates/mobile/expo/skills/expo-upgrader.md +10 -0
- package/src/templates/mobile/react-native/rules/01-native-primitives.md +18 -0
- package/src/templates/mobile/react-native/rules/02-native-styling.md +29 -0
- package/src/templates/mobile/react-native/rules/03-ios-android-builds.md +14 -0
- package/src/templates/mobile/react-native/skills/native-linking.md +27 -0
- package/src/utils/compilers.js +22 -21
- package/src/utils/fileSystem.js +86 -48
- package/src/templates/context/project_overview.md +0 -62
- package/src/templates/rules/architecture.md +0 -42
- package/src/templates/skills/data-extractor.md +0 -56
- package/src/templates/skills/data-transformer.md +0 -62
- package/src/templates/skills/output-dispatcher.md +0 -79
- package/src/templates/skills/web-browser.md +0 -54
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Rule: Expo Router
|
|
2
|
+
|
|
3
|
+
1. **File-Based Routing Architecture**:
|
|
4
|
+
- You MUST use Expo Router (`expo-router`) exclusively. Do NOT install or use `@react-navigation/native` directly.
|
|
5
|
+
- All screens must be placed inside the `app/` directory (or `src/app/` if a `src` folder is used).
|
|
6
|
+
|
|
7
|
+
2. **Layouts and Navigation**:
|
|
8
|
+
- Use `_layout.tsx` files to define shared UI (like Stack or Tabs) across multiple screens in a directory.
|
|
9
|
+
- NEVER use `<NavigationContainer>`. Expo Router handles this automatically.
|
|
10
|
+
|
|
11
|
+
3. **Links and Dynamic Routes**:
|
|
12
|
+
- ALWAYS use the `<Link>` component from `expo-router` for navigation between screens, or the `useRouter()` hook for programmatic navigation.
|
|
13
|
+
- Dynamic routes use square brackets (e.g., `app/user/[id].tsx`). Retrieve parameters using the `useLocalSearchParams()` hook from `expo-router`.
|
|
14
|
+
|
|
15
|
+
4. **Not-Found Screens**:
|
|
16
|
+
- Use `+not-found.tsx` to handle 404 routes.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Skill: Create Expo App
|
|
2
|
+
|
|
3
|
+
## Context
|
|
4
|
+
When a user asks to start a new Expo project from scratch, follow these modern initialization standards based on the latest Expo documentation.
|
|
5
|
+
|
|
6
|
+
## Execution Steps
|
|
7
|
+
1. **Initialize Command**:
|
|
8
|
+
- Propose running `npx create-expo-app@latest` in the terminal. This uses the default template which includes Expo Router and modern defaults.
|
|
9
|
+
- If a specific template is requested, use `npx create-expo-app@latest --template <template-name>`.
|
|
10
|
+
|
|
11
|
+
2. **Start the Development Server**:
|
|
12
|
+
- Propose running `npx expo start` to start the Metro bundler.
|
|
13
|
+
- Explain to the user that they can press `i` to open the iOS simulator, or `a` to open the Android emulator.
|
|
14
|
+
|
|
15
|
+
3. **Resetting Cache**:
|
|
16
|
+
- If the user reports weird bundling errors or missing modules, propose running `npx expo start --clear` (or `-c`) to clear the Metro cache.
|
|
17
|
+
|
|
18
|
+
4. **Dependencies**:
|
|
19
|
+
- ALWAYS use `npx expo install <package>` instead of `npm install` or `yarn add` when installing native packages. This ensures the version installed is compatible with the current Expo SDK.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Skill: Expo SDK Migration Expert
|
|
2
|
+
|
|
3
|
+
## Operational Objective
|
|
4
|
+
Safely upgrade the local codebase's native wrappers and library versions to the targeted modern Expo SDK layout without generating cascade system failures.
|
|
5
|
+
|
|
6
|
+
## Step-by-Step Execution Protocol
|
|
7
|
+
1. **Context Extraction:** Check `package.json` and `.agents/settings.json` to confirm current project dependencies and target thresholds.
|
|
8
|
+
2. **Reference Audit:** Compare existing components against any files found in `.agents/reference/`. Identify breaking changes, deprecated hooks, and required config plugins before making code mutations.
|
|
9
|
+
3. **Strict Live Verification:** Do not guess method arguments. If internet permissions are active, query `site:docs.expo.dev/versions/` appending the target SDK code to verify exact API shifts.
|
|
10
|
+
4. **Isolated Incremental Assembly:** Modify files sequentially. Complete dependency resolution inside configuration files first, verify type parameters, and fix breaking interface adjustments step-by-step.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Rule: React Native Primitives
|
|
2
|
+
|
|
3
|
+
1. **NO HTML Elements**:
|
|
4
|
+
- NEVER use HTML DOM elements like `<div>`, `<span>`, `<button>`, `<p>`, `<a>`, `<ul>`, `<li>`, or `<input>`.
|
|
5
|
+
- React Native does not use the browser DOM. Using web elements will crash the app instantly.
|
|
6
|
+
|
|
7
|
+
2. **Core Components**:
|
|
8
|
+
- ALWAYS use React Native core components imported from `react-native`.
|
|
9
|
+
- Use `<View>` instead of `<div>`.
|
|
10
|
+
- Use `<Text>` instead of `<span>` or `<p>`. All strings MUST be wrapped in a `<Text>` component.
|
|
11
|
+
- Use `<Pressable>` or `<TouchableOpacity>` instead of `<button>`.
|
|
12
|
+
- Use `<TextInput>` instead of `<input>`.
|
|
13
|
+
- Use `<Image>` instead of `<img>` (and note that local images require `source={require('./path')}`, while remote require `source={{ uri: '...' }}`).
|
|
14
|
+
- Use `<ScrollView>` or `<FlatList>` for scrollable areas.
|
|
15
|
+
|
|
16
|
+
3. **Event Handlers**:
|
|
17
|
+
- Do NOT use `onClick`. The correct prop for `<Pressable>` is `onPress`.
|
|
18
|
+
- Do NOT use `onChange` for text inputs. The correct prop for `<TextInput>` is `onChangeText`.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Rule: Native Styling
|
|
2
|
+
|
|
3
|
+
1. **No Web CSS Attributes**:
|
|
4
|
+
- Do NOT use web-specific CSS properties like `grid`, `float`, `display: block`, etc.
|
|
5
|
+
- Do NOT use string styles for dimensions like `width: "100px"`.
|
|
6
|
+
|
|
7
|
+
2. **Unitless Pixels**:
|
|
8
|
+
- Layout dimensions and font sizes must use unitless values (e.g., `width: 100`, `fontSize: 16`). These represent logical pixels.
|
|
9
|
+
- Percentages are allowed as strings (e.g., `width: "100%"`).
|
|
10
|
+
|
|
11
|
+
3. **Flexbox Architecture**:
|
|
12
|
+
- In React Native, `flexDirection` defaults to `"column"`. If you want items side-by-side, you MUST explicitly set `flexDirection: "row"`.
|
|
13
|
+
- `display: "flex"` is the default and only display type for Views.
|
|
14
|
+
- Use `justifyContent` and `alignItems` heavily for positioning.
|
|
15
|
+
|
|
16
|
+
4. **StyleSheet**:
|
|
17
|
+
- ALWAYS use `StyleSheet.create` for defining component styles to ensure performance and avoid inline object recreation on every render.
|
|
18
|
+
- Example:
|
|
19
|
+
```javascript
|
|
20
|
+
const styles = StyleSheet.create({
|
|
21
|
+
container: {
|
|
22
|
+
flex: 1,
|
|
23
|
+
justifyContent: 'center',
|
|
24
|
+
alignItems: 'center',
|
|
25
|
+
backgroundColor: '#fff',
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
```
|
|
29
|
+
- Only use inline styles for values that change dynamically during render.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Rule: Native iOS & Android Builds
|
|
2
|
+
|
|
3
|
+
In a bare React Native project, you must manage native dependencies meticulously.
|
|
4
|
+
|
|
5
|
+
1. **iOS Dependencies (`pod install`)**:
|
|
6
|
+
- ANY time you install a new NPM package that includes native code (e.g., `react-native-device-info`, `react-native-reanimated`), you MUST remind the user to run `cd ios && pod install` (or `npx pod-install`).
|
|
7
|
+
- If an iOS build fails with a "module not found" error for a native module, the most likely solution is to run `pod install`.
|
|
8
|
+
|
|
9
|
+
2. **Android Gradle Sync**:
|
|
10
|
+
- If a new native module is added, the Android project must be rebuilt.
|
|
11
|
+
- If weird caching issues occur in Android, propose running `cd android && ./gradlew clean`.
|
|
12
|
+
|
|
13
|
+
3. **Avoid Manual Native Edits Unless Requested**:
|
|
14
|
+
- Do not manually edit `ios/Podfile`, `android/app/build.gradle`, `MainApplication.java`, or `AppDelegate.mm` unless the library's official documentation explicitly requires manual linking (which is rare in modern React Native due to autolinking).
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Skill: Native Module Linking & Troubleshooting
|
|
2
|
+
|
|
3
|
+
## Context
|
|
4
|
+
Use this skill when a user encounters build errors, native module crashes, or needs help installing a library with deep native hooks in a bare React Native app.
|
|
5
|
+
|
|
6
|
+
## Execution Steps
|
|
7
|
+
|
|
8
|
+
1. **Verify Autolinking**:
|
|
9
|
+
- React Native uses Autolinking by default for iOS and Android.
|
|
10
|
+
- Check the `package.json` to ensure the library is installed.
|
|
11
|
+
- For iOS: Propose running `cd ios && pod install`. If the user is on an Apple Silicon Mac and encounters FFI errors, propose `arch -x86_64 pod install`.
|
|
12
|
+
- For Android: Propose running `cd android && ./gradlew clean`.
|
|
13
|
+
|
|
14
|
+
2. **Manual Linking (Only if Autolinking Fails)**:
|
|
15
|
+
- Only propose manual changes to `settings.gradle` and `MainApplication.java` (Android) or `Podfile` (iOS) if the specific library documentation states that it does not support autolinking.
|
|
16
|
+
|
|
17
|
+
3. **Clearing Caches**:
|
|
18
|
+
- The React Native packager (Metro) often caches aggressively. If JS changes aren't reflecting or weird module resolution errors occur, propose:
|
|
19
|
+
`npx react-native start --reset-cache`
|
|
20
|
+
- For a deeper clean, propose clearing Watchman watches:
|
|
21
|
+
`watchman watch-del-all`
|
|
22
|
+
`rm -rf node_modules && npm install`
|
|
23
|
+
`rm -rf $TMPDIR/metro-*`
|
|
24
|
+
|
|
25
|
+
4. **Rebuilding**:
|
|
26
|
+
- Remind the user that after installing a native module, they CANNOT simply rely on fast refresh. They MUST recompile the app:
|
|
27
|
+
`npx react-native run-ios` OR `npx react-native run-android`
|
package/src/utils/compilers.js
CHANGED
|
@@ -7,6 +7,7 @@ const path = require('path');
|
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Read all .md files from a directory and return their concatenated content.
|
|
10
|
+
* Skips README.md files since those are directory documentation, not agent rules.
|
|
10
11
|
* @param {string} dir
|
|
11
12
|
* @returns {Promise<string>}
|
|
12
13
|
*/
|
|
@@ -15,7 +16,7 @@ async function readMarkdownDir(dir) {
|
|
|
15
16
|
try {
|
|
16
17
|
const entries = await fs.readdir(dir, { withFileTypes: true });
|
|
17
18
|
for (const entry of entries) {
|
|
18
|
-
if (entry.isFile() && entry.name.endsWith('.md')) {
|
|
19
|
+
if (entry.isFile() && entry.name.endsWith('.md') && entry.name !== 'README.md') {
|
|
19
20
|
const filePath = path.join(dir, entry.name);
|
|
20
21
|
const fileContent = await fs.readFile(filePath, 'utf-8');
|
|
21
22
|
const section = entry.name.replace('.md', '').replace(/-/g, ' ');
|
|
@@ -57,12 +58,12 @@ async function copyDir(src, dest) {
|
|
|
57
58
|
// ─── Cursor ──────────────────────────────────────────────────────────────────
|
|
58
59
|
|
|
59
60
|
/**
|
|
60
|
-
* Sync .
|
|
61
|
-
* @param {string}
|
|
61
|
+
* Sync .agents/rules/ → .cursor/rules/
|
|
62
|
+
* @param {string} agentsDir
|
|
62
63
|
* @param {string} cwd
|
|
63
64
|
*/
|
|
64
|
-
async function syncToCursor(
|
|
65
|
-
const src = path.join(
|
|
65
|
+
async function syncToCursor(agentsDir, cwd) {
|
|
66
|
+
const src = path.join(agentsDir, 'rules');
|
|
66
67
|
const dest = path.join(cwd, '.cursor', 'rules');
|
|
67
68
|
await copyDir(src, dest);
|
|
68
69
|
}
|
|
@@ -70,19 +71,19 @@ async function syncToCursor(agentDir, cwd) {
|
|
|
70
71
|
// ─── Claude ──────────────────────────────────────────────────────────────────
|
|
71
72
|
|
|
72
73
|
/**
|
|
73
|
-
* Compile .
|
|
74
|
-
* @param {string}
|
|
74
|
+
* Compile .agents/ into a single CLAUDE.md file.
|
|
75
|
+
* @param {string} agentsDir
|
|
75
76
|
* @param {string} cwd
|
|
76
77
|
* @param {string} techStack
|
|
77
78
|
*/
|
|
78
|
-
async function syncToClaude(
|
|
79
|
-
const rulesContent
|
|
80
|
-
const
|
|
79
|
+
async function syncToClaude(agentsDir, cwd, techStack) {
|
|
80
|
+
const rulesContent = await readMarkdownDir(path.join(agentsDir, 'rules'));
|
|
81
|
+
const commandsContent = await readMarkdownDir(path.join(agentsDir, 'commands'));
|
|
81
82
|
|
|
82
83
|
const claudeMd = `# CLAUDE.md — AI Agent Instructions
|
|
83
84
|
|
|
84
85
|
> This file was auto-generated by [agentive](https://github.com/TiPS0/agentive).
|
|
85
|
-
> Edit the source files in \`.
|
|
86
|
+
> Edit the source files in \`.agents/\` and re-run \`npx @p_tipso/agentive\` to regenerate.
|
|
86
87
|
|
|
87
88
|
## Project Context
|
|
88
89
|
|
|
@@ -91,8 +92,8 @@ async function syncToClaude(agentDir, cwd, techStack) {
|
|
|
91
92
|
# Rules
|
|
92
93
|
${rulesContent}
|
|
93
94
|
|
|
94
|
-
#
|
|
95
|
-
${
|
|
95
|
+
# Commands
|
|
96
|
+
${commandsContent}
|
|
96
97
|
`.trim();
|
|
97
98
|
|
|
98
99
|
await fs.writeFile(path.join(cwd, 'CLAUDE.md'), claudeMd, 'utf-8');
|
|
@@ -101,27 +102,27 @@ ${skillsContent}
|
|
|
101
102
|
// ─── Windsurf ────────────────────────────────────────────────────────────────
|
|
102
103
|
|
|
103
104
|
/**
|
|
104
|
-
* Compile .
|
|
105
|
-
* @param {string}
|
|
105
|
+
* Compile .agents/rules/ into a single .windsurfrules file.
|
|
106
|
+
* @param {string} agentsDir
|
|
106
107
|
* @param {string} cwd
|
|
107
108
|
* @param {string} techStack
|
|
108
109
|
*/
|
|
109
|
-
async function syncToWindsurf(
|
|
110
|
-
const rulesContent
|
|
111
|
-
const
|
|
110
|
+
async function syncToWindsurf(agentsDir, cwd, techStack) {
|
|
111
|
+
const rulesContent = await readMarkdownDir(path.join(agentsDir, 'rules'));
|
|
112
|
+
const commandsContent = await readMarkdownDir(path.join(agentsDir, 'commands'));
|
|
112
113
|
|
|
113
114
|
const windsurfRules = `# .windsurfrules — AI Agent Instructions
|
|
114
115
|
|
|
115
116
|
> Auto-generated by [agentive](https://github.com/TiPS0/agentive).
|
|
116
|
-
> Edit \`.
|
|
117
|
+
> Edit \`.agents/\` and re-run \`npx @p_tipso/agentive\` to regenerate.
|
|
117
118
|
|
|
118
119
|
**Tech Stack:** ${techStack}
|
|
119
120
|
|
|
120
121
|
# Rules
|
|
121
122
|
${rulesContent}
|
|
122
123
|
|
|
123
|
-
#
|
|
124
|
-
${
|
|
124
|
+
# Commands
|
|
125
|
+
${commandsContent}
|
|
125
126
|
`.trim();
|
|
126
127
|
|
|
127
128
|
await fs.writeFile(path.join(cwd, '.windsurfrules'), windsurfRules, 'utf-8');
|
package/src/utils/fileSystem.js
CHANGED
|
@@ -6,13 +6,13 @@ const path = require('path');
|
|
|
6
6
|
// ─── Guards ──────────────────────────────────────────────────────────────────
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
|
-
* Check if a .
|
|
9
|
+
* Check if a .agents/ directory already exists in the given working directory.
|
|
10
10
|
* @param {string} cwd
|
|
11
11
|
* @returns {Promise<boolean>}
|
|
12
12
|
*/
|
|
13
13
|
async function agentDirectoryExists(cwd) {
|
|
14
14
|
try {
|
|
15
|
-
await fs.access(path.join(cwd, '.
|
|
15
|
+
await fs.access(path.join(cwd, '.agents'));
|
|
16
16
|
return true;
|
|
17
17
|
} catch {
|
|
18
18
|
return false;
|
|
@@ -22,57 +22,63 @@ async function agentDirectoryExists(cwd) {
|
|
|
22
22
|
// ─── Directory Creation ───────────────────────────────────────────────────────
|
|
23
23
|
|
|
24
24
|
/**
|
|
25
|
-
* Create (or recreate) the .
|
|
25
|
+
* Create (or recreate) the .agents/ directory structure inside the user's project.
|
|
26
26
|
*
|
|
27
27
|
* Structure:
|
|
28
|
-
* .
|
|
28
|
+
* AGENTS.md ← project root
|
|
29
|
+
* .agents/
|
|
29
30
|
* ├── settings.json
|
|
30
31
|
* ├── settings.local.json
|
|
31
|
-
* ├──
|
|
32
|
-
*
|
|
32
|
+
* ├── commands/
|
|
33
|
+
* ├── skills/
|
|
34
|
+
* └── rules/
|
|
33
35
|
*
|
|
34
36
|
* @param {string} cwd - The user's current working directory
|
|
35
|
-
* @param {boolean} overwrite - Whether to remove an existing .
|
|
36
|
-
* @returns {Promise<string>} The path to the created .
|
|
37
|
+
* @param {boolean} overwrite - Whether to remove an existing .agents/ directory first
|
|
38
|
+
* @returns {Promise<string>} The path to the created .agents/ directory
|
|
37
39
|
*/
|
|
38
40
|
async function createAgentDirectory(cwd, overwrite = false) {
|
|
39
|
-
const
|
|
41
|
+
const agentsDir = path.join(cwd, '.agents');
|
|
40
42
|
|
|
41
43
|
if (overwrite) {
|
|
42
|
-
await fs.rm(
|
|
44
|
+
await fs.rm(agentsDir, { recursive: true, force: true });
|
|
45
|
+
// Also remove old AGENTS.md if overwriting
|
|
46
|
+
try { await fs.rm(path.join(cwd, 'AGENTS.md'), { force: true }); } catch { /* noop */ }
|
|
43
47
|
}
|
|
44
48
|
|
|
45
|
-
await fs.mkdir(
|
|
46
|
-
await fs.mkdir(path.join(
|
|
47
|
-
await fs.mkdir(path.join(
|
|
49
|
+
await fs.mkdir(agentsDir, { recursive: true });
|
|
50
|
+
await fs.mkdir(path.join(agentsDir, 'commands'), { recursive: true });
|
|
51
|
+
await fs.mkdir(path.join(agentsDir, 'skills'), { recursive: true });
|
|
52
|
+
await fs.mkdir(path.join(agentsDir, 'rules'), { recursive: true });
|
|
48
53
|
|
|
49
|
-
return
|
|
54
|
+
return agentsDir;
|
|
50
55
|
}
|
|
51
56
|
|
|
52
57
|
// ─── Settings Files ───────────────────────────────────────────────────────────
|
|
53
58
|
|
|
54
59
|
/**
|
|
55
|
-
* Write settings.json and settings.local.json inside .
|
|
60
|
+
* Write settings.json and settings.local.json inside .agents/.
|
|
56
61
|
*
|
|
57
62
|
* - settings.json → tracked by git (project-wide config)
|
|
58
63
|
* - settings.local.json → gitignored (machine-specific overrides)
|
|
59
64
|
*
|
|
60
|
-
* Also appends `.
|
|
65
|
+
* Also appends `.agents/settings.local.json` to the project's .gitignore if one exists.
|
|
66
|
+
* Settings no longer include techStack or tools since the wizard was removed.
|
|
61
67
|
*
|
|
62
|
-
* @param {string}
|
|
68
|
+
* @param {string} agentsDir - Absolute path to .agents/
|
|
63
69
|
* @param {object} settings - The wizard answers to persist
|
|
64
70
|
*/
|
|
65
|
-
async function writeSettings(
|
|
71
|
+
async function writeSettings(agentsDir, settings) {
|
|
66
72
|
// settings.json — committed to git
|
|
67
73
|
const settingsJson = {
|
|
68
74
|
projectName: settings.projectName,
|
|
69
|
-
|
|
70
|
-
|
|
75
|
+
projectType: settings.projectType || 'general',
|
|
76
|
+
framework: settings.framework || null,
|
|
71
77
|
agentiveVersion: settings.agentiveVersion,
|
|
72
78
|
createdAt: settings.createdAt,
|
|
73
79
|
};
|
|
74
80
|
await fs.writeFile(
|
|
75
|
-
path.join(
|
|
81
|
+
path.join(agentsDir, 'settings.json'),
|
|
76
82
|
JSON.stringify(settingsJson, null, 2) + '\n',
|
|
77
83
|
'utf-8'
|
|
78
84
|
);
|
|
@@ -83,17 +89,17 @@ async function writeSettings(agentDir, settings) {
|
|
|
83
89
|
overrides: {},
|
|
84
90
|
};
|
|
85
91
|
await fs.writeFile(
|
|
86
|
-
path.join(
|
|
92
|
+
path.join(agentsDir, 'settings.local.json'),
|
|
87
93
|
JSON.stringify(localSettingsJson, null, 2) + '\n',
|
|
88
94
|
'utf-8'
|
|
89
95
|
);
|
|
90
96
|
|
|
91
97
|
// Auto-append to .gitignore if it exists in cwd
|
|
92
|
-
const cwd = path.dirname(
|
|
98
|
+
const cwd = path.dirname(agentsDir);
|
|
93
99
|
const gitignorePath = path.join(cwd, '.gitignore');
|
|
94
100
|
try {
|
|
95
101
|
let gitignore = await fs.readFile(gitignorePath, 'utf-8');
|
|
96
|
-
const entry = '.
|
|
102
|
+
const entry = '.agents/settings.local.json';
|
|
97
103
|
if (!gitignore.includes(entry)) {
|
|
98
104
|
gitignore += `\n# Agentive local settings (machine-specific)\n${entry}\n`;
|
|
99
105
|
await fs.writeFile(gitignorePath, gitignore, 'utf-8');
|
|
@@ -106,40 +112,74 @@ async function writeSettings(agentDir, settings) {
|
|
|
106
112
|
// ─── Template Copying ─────────────────────────────────────────────────────────
|
|
107
113
|
|
|
108
114
|
/**
|
|
109
|
-
* Copy
|
|
110
|
-
* Replaces {{TECH_STACK}} and {{YEAR}} placeholders in template files.
|
|
115
|
+
* Copy template files from src/templates/ into the user's project.
|
|
111
116
|
*
|
|
112
|
-
*
|
|
117
|
+
* - AGENTS.md → project root (cwd)
|
|
118
|
+
* - commands/, skills/, rules/ → .agents/
|
|
119
|
+
*
|
|
120
|
+
* Replaces {{PROJECT_NAME}} and {{YEAR}} placeholders.
|
|
113
121
|
*
|
|
114
122
|
* @param {string} templatesDir - Absolute path to src/templates/
|
|
115
|
-
* @param {string}
|
|
116
|
-
* @param {string}
|
|
123
|
+
* @param {string} agentsDir - Absolute path to .agents/
|
|
124
|
+
* @param {string} projectName - The user's project name
|
|
125
|
+
* @param {string} projectType - e.g., 'general', 'web', 'mobile'
|
|
126
|
+
* @param {string} framework - e.g., 'expo', 'react-native'
|
|
117
127
|
*/
|
|
118
|
-
async function copyTemplates(templatesDir,
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
128
|
+
async function copyTemplates(templatesDir, agentsDir, projectName, projectType = 'general', framework = null) {
|
|
129
|
+
const cwd = path.dirname(agentsDir);
|
|
130
|
+
|
|
131
|
+
// 1. Copy AGENTS.md from base to project root
|
|
132
|
+
const agentMdSrc = path.join(templatesDir, 'base', 'AGENTS.md');
|
|
133
|
+
try {
|
|
134
|
+
let content = await fs.readFile(agentMdSrc, 'utf-8');
|
|
135
|
+
content = replacePlaceholders(content, projectName);
|
|
136
|
+
await fs.writeFile(path.join(cwd, 'AGENTS.md'), content, 'utf-8');
|
|
137
|
+
} catch { /* template may not exist */ }
|
|
138
|
+
|
|
139
|
+
const foldersToInclude = ['commands', 'skills', 'rules'];
|
|
140
|
+
|
|
141
|
+
// Helper to copy a specific template layer
|
|
142
|
+
const copyLayer = async (layerPath) => {
|
|
143
|
+
for (const folder of foldersToInclude) {
|
|
144
|
+
const srcFolder = path.join(layerPath, folder);
|
|
145
|
+
const destFolder = path.join(agentsDir, folder);
|
|
146
|
+
try {
|
|
147
|
+
await fs.access(srcFolder);
|
|
148
|
+
await copyDirectoryRecursive(srcFolder, destFolder, projectName);
|
|
149
|
+
} catch {
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
130
152
|
}
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
// 2. Copy Base Layer
|
|
156
|
+
await copyLayer(path.join(templatesDir, 'base'));
|
|
131
157
|
|
|
132
|
-
|
|
158
|
+
// 3. Copy Framework Layer (if applicable)
|
|
159
|
+
if (projectType !== 'general' && framework) {
|
|
160
|
+
await copyLayer(path.join(templatesDir, projectType, framework));
|
|
133
161
|
}
|
|
134
162
|
}
|
|
135
163
|
|
|
164
|
+
/**
|
|
165
|
+
* Replace template placeholders with actual values.
|
|
166
|
+
* @param {string} content
|
|
167
|
+
* @param {string} projectName
|
|
168
|
+
* @returns {string}
|
|
169
|
+
*/
|
|
170
|
+
function replacePlaceholders(content, projectName) {
|
|
171
|
+
return content
|
|
172
|
+
.replace(/\{\{PROJECT_NAME\}\}/g, projectName || '')
|
|
173
|
+
.replace(/\{\{YEAR\}\}/g, new Date().getFullYear().toString());
|
|
174
|
+
}
|
|
175
|
+
|
|
136
176
|
/**
|
|
137
177
|
* Internal: recursively copies files from src to dest, replacing placeholders.
|
|
138
178
|
* @param {string} src
|
|
139
179
|
* @param {string} dest
|
|
140
|
-
* @param {string}
|
|
180
|
+
* @param {string} projectName
|
|
141
181
|
*/
|
|
142
|
-
async function copyDirectoryRecursive(src, dest,
|
|
182
|
+
async function copyDirectoryRecursive(src, dest, projectName) {
|
|
143
183
|
const entries = await fs.readdir(src, { withFileTypes: true });
|
|
144
184
|
|
|
145
185
|
for (const entry of entries) {
|
|
@@ -148,12 +188,10 @@ async function copyDirectoryRecursive(src, dest, techStack) {
|
|
|
148
188
|
|
|
149
189
|
if (entry.isDirectory()) {
|
|
150
190
|
await fs.mkdir(destPath, { recursive: true });
|
|
151
|
-
await copyDirectoryRecursive(srcPath, destPath,
|
|
191
|
+
await copyDirectoryRecursive(srcPath, destPath, projectName);
|
|
152
192
|
} else {
|
|
153
193
|
let content = await fs.readFile(srcPath, 'utf-8');
|
|
154
|
-
content = content
|
|
155
|
-
.replace(/\{\{TECH_STACK\}\}/g, techStack)
|
|
156
|
-
.replace(/\{\{YEAR\}\}/g, new Date().getFullYear().toString());
|
|
194
|
+
content = replacePlaceholders(content, projectName);
|
|
157
195
|
await fs.writeFile(destPath, content, 'utf-8');
|
|
158
196
|
}
|
|
159
197
|
}
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
# Project Overview
|
|
2
|
-
|
|
3
|
-
> This file provides essential context for AI agents working on this project.
|
|
4
|
-
> Keep it updated as the project evolves.
|
|
5
|
-
|
|
6
|
-
## About This Project
|
|
7
|
-
|
|
8
|
-
<!-- Describe what this project does and who it is for -->
|
|
9
|
-
|
|
10
|
-
**Tech Stack:** {{TECH_STACK}}
|
|
11
|
-
|
|
12
|
-
## Project Goals
|
|
13
|
-
|
|
14
|
-
<!-- List the primary goals and success criteria for this project -->
|
|
15
|
-
|
|
16
|
-
1.
|
|
17
|
-
2.
|
|
18
|
-
3.
|
|
19
|
-
|
|
20
|
-
## Architecture Overview
|
|
21
|
-
|
|
22
|
-
<!-- Briefly describe the high-level architecture and major components -->
|
|
23
|
-
|
|
24
|
-
```
|
|
25
|
-
your-project/
|
|
26
|
-
├── src/ # Application source code
|
|
27
|
-
├── tests/ # Test files
|
|
28
|
-
└── docs/ # Documentation
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
## Key Conventions
|
|
32
|
-
|
|
33
|
-
<!-- Document conventions that are unique to this project -->
|
|
34
|
-
|
|
35
|
-
- **Branch naming**: `feat/`, `fix/`, `chore/` prefixes
|
|
36
|
-
- **Commit messages**: Follow [Conventional Commits](https://www.conventionalcommits.org/)
|
|
37
|
-
- **PR size**: Keep pull requests focused and under 400 lines changed
|
|
38
|
-
|
|
39
|
-
## Important Files & Directories
|
|
40
|
-
|
|
41
|
-
| Path | Purpose |
|
|
42
|
-
|------|---------|
|
|
43
|
-
| `src/` | Application source |
|
|
44
|
-
| `.ai/` | Agent rules, skills, and context (source of truth) |
|
|
45
|
-
|
|
46
|
-
## External Services & APIs
|
|
47
|
-
|
|
48
|
-
<!-- List any external services, APIs, or integrations this project depends on -->
|
|
49
|
-
|
|
50
|
-
| Service | Purpose | Docs |
|
|
51
|
-
|---------|---------|------|
|
|
52
|
-
| | | |
|
|
53
|
-
|
|
54
|
-
## Known Gotchas
|
|
55
|
-
|
|
56
|
-
<!-- Document non-obvious things that have caused bugs or confusion in the past -->
|
|
57
|
-
|
|
58
|
-
-
|
|
59
|
-
|
|
60
|
-
---
|
|
61
|
-
|
|
62
|
-
*Generated by [agentive](https://github.com/TiPS0/agentive) on {{YEAR}}.*
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
# Architecture Rules
|
|
2
|
-
|
|
3
|
-
> These rules govern how AI agents should reason about, write, and modify code
|
|
4
|
-
> in this project. All agents operating in this repository must follow them.
|
|
5
|
-
|
|
6
|
-
## Tech Stack
|
|
7
|
-
|
|
8
|
-
This project uses: **{{TECH_STACK}}**
|
|
9
|
-
|
|
10
|
-
All generated code must be idiomatic for this stack and follow its established patterns.
|
|
11
|
-
|
|
12
|
-
## Structural Principles
|
|
13
|
-
|
|
14
|
-
- **Single Responsibility**: Every function, module, or class should do one thing well.
|
|
15
|
-
- **Separation of Concerns**: Keep data fetching, business logic, and presentation in separate layers.
|
|
16
|
-
- **DRY (Don't Repeat Yourself)**: Before adding new code, search for existing utilities or helpers.
|
|
17
|
-
- **YAGNI (You Aren't Gonna Need It)**: Do not add features or abstractions that aren't required right now.
|
|
18
|
-
|
|
19
|
-
## Code Style
|
|
20
|
-
|
|
21
|
-
- Prefer **async/await** over raw Promises or callbacks.
|
|
22
|
-
- Always handle errors explicitly — never swallow exceptions silently.
|
|
23
|
-
- Use **descriptive, intent-revealing names** for variables, functions, and files.
|
|
24
|
-
- Write **small, focused functions** (prefer < 30 lines per function).
|
|
25
|
-
- Add **JSDoc or TSDoc comments** to all exported functions.
|
|
26
|
-
|
|
27
|
-
## File Organisation
|
|
28
|
-
|
|
29
|
-
- Group related code by **feature**, not by type (avoid giant `utils/` or `helpers/` dumping grounds).
|
|
30
|
-
- Keep files focused — if a file grows past ~200 lines, consider splitting it.
|
|
31
|
-
- Barrel exports (`index.js`) should only re-export, never contain logic.
|
|
32
|
-
|
|
33
|
-
## Testing
|
|
34
|
-
|
|
35
|
-
- Every new feature should have a corresponding test.
|
|
36
|
-
- Test **behaviour**, not implementation details.
|
|
37
|
-
- Prefer unit tests for pure functions; integration tests for side-effecting code.
|
|
38
|
-
|
|
39
|
-
## Dependencies
|
|
40
|
-
|
|
41
|
-
- Before adding a new dependency, consider if the task can be accomplished with built-ins.
|
|
42
|
-
- Avoid dependencies with no active maintenance or that have known security advisories.
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
# Skill: Data Extractor Agent
|
|
2
|
-
|
|
3
|
-
> This skill defines how an AI agent should behave when its role is to
|
|
4
|
-
> extract structured data from raw, unstructured, or semi-structured sources.
|
|
5
|
-
|
|
6
|
-
## Role Description
|
|
7
|
-
|
|
8
|
-
You are a **Data Extractor Agent**. Your job is to parse raw content (HTML, text,
|
|
9
|
-
JSON, PDF, CSV, etc.) and extract specific, structured data points as defined by
|
|
10
|
-
the schema provided by the orchestrator. You surface data — you do not transform
|
|
11
|
-
or enrich it.
|
|
12
|
-
|
|
13
|
-
## Responsibilities
|
|
14
|
-
|
|
15
|
-
- Parse the provided raw content using the most appropriate method for its format.
|
|
16
|
-
- Extract only the fields specified in the schema — do not add extra fields.
|
|
17
|
-
- Return `null` for any field that cannot be found; do not guess or hallucinate values.
|
|
18
|
-
- Normalise whitespace and remove HTML tags from text values.
|
|
19
|
-
- Flag ambiguous or low-confidence extractions to the orchestrator.
|
|
20
|
-
|
|
21
|
-
## Inputs
|
|
22
|
-
|
|
23
|
-
| Input | Type | Description |
|
|
24
|
-
|-------|------|-------------|
|
|
25
|
-
| `content` | `string` | The raw content to parse |
|
|
26
|
-
| `format` | `string` | One of: `html`, `text`, `json`, `csv`, `markdown` |
|
|
27
|
-
| `schema` | `object` | JSON Schema defining the fields to extract |
|
|
28
|
-
|
|
29
|
-
## Outputs
|
|
30
|
-
|
|
31
|
-
```json
|
|
32
|
-
{
|
|
33
|
-
"data": {
|
|
34
|
-
"field_name": "extracted value",
|
|
35
|
-
"another_field": null
|
|
36
|
-
},
|
|
37
|
-
"confidence": 0.95,
|
|
38
|
-
"warnings": ["Could not find 'phone_number' in source"]
|
|
39
|
-
}
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
## Constraints
|
|
43
|
-
|
|
44
|
-
- **Never infer** or fabricate a value that isn't explicitly present in the source.
|
|
45
|
-
- **Always** include a `confidence` score between `0.0` and `1.0`.
|
|
46
|
-
- If `confidence < 0.7`, always include a `warnings` entry explaining the uncertainty.
|
|
47
|
-
- **Do not** make external network requests — work only with the content provided.
|
|
48
|
-
|
|
49
|
-
## Error Handling
|
|
50
|
-
|
|
51
|
-
| Error | Response |
|
|
52
|
-
|-------|----------|
|
|
53
|
-
| `Unsupported format` | Return an error; list supported formats |
|
|
54
|
-
| `Schema mismatch` | Return partial data with warnings for missing fields |
|
|
55
|
-
| `Empty content` | Return all fields as `null` with a warning |
|
|
56
|
-
| `Parse error` | Report the specific parse error and return an empty `data` object |
|