@p_tipso/agentive 1.0.2 → 1.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.
- package/README.md +13 -6
- package/bin/index.js +18 -0
- package/package.json +4 -3
- package/src/commands/init.js +3 -1
- package/src/commands/install.js +104 -0
- package/src/commands/remove.js +60 -0
- package/src/templates/base/AGENTS.md +5 -0
- package/src/templates/base/aiignore +48 -0
- package/src/utils/fileSystem.js +101 -0
package/README.md
CHANGED
|
@@ -20,16 +20,16 @@
|
|
|
20
20
|
|
|
21
21
|
---
|
|
22
22
|
|
|
23
|
-
Stop maintaining separate rule files for every AI tool. **agentive** scaffolds a universal `.agents/` directory
|
|
23
|
+
Stop maintaining separate rule files for every AI tool. **agentive** scaffolds a universal `.agents/` directory, an `AGENTS.md` file, and an `.aiignore` file in your project — providing a **single source of truth** for all your agent commands, skills, and rules, while significantly saving token usage.
|
|
24
24
|
|
|
25
25
|
## ✨ Why Agentive?
|
|
26
26
|
|
|
27
27
|
| Feature | Description |
|
|
28
28
|
| :---------------------------- | :------------------------------------------------------------------- |
|
|
29
|
-
| 🚀 **
|
|
29
|
+
| 🚀 **Interactive Setup** | Select your environment (General, Expo, React Native) to get tailored rules. |
|
|
30
30
|
| 🌍 **Universal** | Framework-agnostic setup. Works with React, Python, Go, you name it. |
|
|
31
31
|
| 🧠 **Single Source of Truth** | Centralize skills and rules for _all_ your AI agents in one place. |
|
|
32
|
-
| ⚡ **
|
|
32
|
+
| ⚡ **Dynamic Layering** | Scaffolds base rules and safely merges framework-specific guardrails. |
|
|
33
33
|
|
|
34
34
|
---
|
|
35
35
|
|
|
@@ -52,7 +52,9 @@ agentive
|
|
|
52
52
|
|
|
53
53
|
| Command | Description |
|
|
54
54
|
| :-------------------------------- | :----------------------------------------------------------- |
|
|
55
|
-
| `npx @p_tipso/agentive`
|
|
55
|
+
| `npx @p_tipso/agentive init` | Scaffold `.agents/` workspace instantly in current directory |
|
|
56
|
+
| `npx @p_tipso/agentive install <pkg>`| Install an agent skill or rule from the registry (alias: `add`) |
|
|
57
|
+
| `npx @p_tipso/agentive remove <pkg>` | Remove an installed skill or rule (alias: `rm`) |
|
|
56
58
|
| `npx @p_tipso/agentive --version` | Print the current CLI version |
|
|
57
59
|
| `npx @p_tipso/agentive --help` | Show available commands and options |
|
|
58
60
|
|
|
@@ -60,11 +62,12 @@ agentive
|
|
|
60
62
|
|
|
61
63
|
## 🏗 What Happens Under the Hood?
|
|
62
64
|
|
|
63
|
-
When you run `agentive`, it
|
|
65
|
+
When you run `agentive`, it launches an interactive wizard asking about your project environment (e.g., General, Mobile > Expo, React Native). It then intelligently scaffolds a tailored workspace:
|
|
64
66
|
|
|
65
67
|
```text
|
|
66
68
|
your-project/
|
|
67
69
|
├── AGENTS.md ← Root agent instructions
|
|
70
|
+
├── .aiignore ← Hides irrelevant files from AI to save tokens
|
|
68
71
|
├── .agents/
|
|
69
72
|
│ ├── settings.json ← Project config
|
|
70
73
|
│ ├── settings.local.json ← Local machine overrides (auto-gitignored)
|
|
@@ -78,12 +81,16 @@ your-project/
|
|
|
78
81
|
│ └── README.md ← Guide: how to add rules
|
|
79
82
|
```
|
|
80
83
|
|
|
81
|
-
### 📂 Folder Guide
|
|
84
|
+
### 📂 File & Folder Guide
|
|
82
85
|
|
|
86
|
+
- **`.aiignore`**: Prevents context pollution and saves tokens by hiding files (like `node_modules` or build outputs) from your AI agents.
|
|
83
87
|
- **`commands/`**: Reusable prompt instructions that agents can execute on demand (e.g. `review.md`).
|
|
84
88
|
- **`skills/`**: Skill definitions that teach agents how to behave in specific roles.
|
|
85
89
|
- **`rules/`**: Project-wide rules that all agents must follow strictly.
|
|
86
90
|
|
|
91
|
+
### 🌟 Framework-Specific Guardrails
|
|
92
|
+
By selecting a specific framework (like **Expo** or **React Native**), `agentive` overlays expertly crafted rules into your `.agents/` folder. This ensures your AI understands nuances like *Expo Router*, *Native Modules*, or *Unitless Pixels* right out of the box—preventing common hallucinations.
|
|
93
|
+
|
|
87
94
|
---
|
|
88
95
|
|
|
89
96
|
## 🤝 Contributing
|
package/bin/index.js
CHANGED
|
@@ -20,4 +20,22 @@ program
|
|
|
20
20
|
await runInit();
|
|
21
21
|
});
|
|
22
22
|
|
|
23
|
+
program
|
|
24
|
+
.command('install <package>')
|
|
25
|
+
.alias('add')
|
|
26
|
+
.description('Install a skill or rule from the registry')
|
|
27
|
+
.action(async (packageName) => {
|
|
28
|
+
const { runInstall } = require('../src/commands/install');
|
|
29
|
+
await runInstall(packageName);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
program
|
|
33
|
+
.command('remove <package>')
|
|
34
|
+
.alias('rm')
|
|
35
|
+
.description('Remove an installed skill or rule')
|
|
36
|
+
.action(async (packageName) => {
|
|
37
|
+
const { runRemove } = require('../src/commands/remove');
|
|
38
|
+
await runRemove(packageName);
|
|
39
|
+
});
|
|
40
|
+
|
|
23
41
|
program.parse(process.argv);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@p_tipso/agentive",
|
|
3
|
-
"version": "1.0
|
|
4
|
-
"description": "A universal, framework-agnostic AI agent repository setup CLI. Scaffold a .
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "A universal, framework-agnostic AI agent repository setup CLI. Scaffold a .agents/ workspace, AGENTS.md, and .aiignore to sync and optimize context for Cursor, Claude, and Windsurf.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Pakawat Tipso",
|
|
7
7
|
"type": "commonjs",
|
|
@@ -27,7 +27,8 @@
|
|
|
27
27
|
"scaffold",
|
|
28
28
|
"init",
|
|
29
29
|
"rules",
|
|
30
|
-
"context"
|
|
30
|
+
"context",
|
|
31
|
+
"aiignore"
|
|
31
32
|
],
|
|
32
33
|
"repository": {
|
|
33
34
|
"type": "git",
|
package/src/commands/init.js
CHANGED
|
@@ -57,7 +57,7 @@ async function runInit() {
|
|
|
57
57
|
name: 'framework',
|
|
58
58
|
message: 'Which framework are you using?',
|
|
59
59
|
choices: [
|
|
60
|
-
{ title: 'Expo', value: 'expo' },
|
|
60
|
+
{ title: 'Expo (Recommended)', value: 'expo' },
|
|
61
61
|
{ title: 'React Native', value: 'react-native' },
|
|
62
62
|
],
|
|
63
63
|
initial: 0,
|
|
@@ -88,6 +88,7 @@ async function runInit() {
|
|
|
88
88
|
});
|
|
89
89
|
|
|
90
90
|
console.log(chalk.green(' ✔ ') + chalk.white('Created ') + chalk.cyan('AGENTS.md'));
|
|
91
|
+
console.log(chalk.green(' ✔ ') + chalk.white('Created ') + chalk.cyan('.aiignore'));
|
|
91
92
|
console.log(chalk.green(' ✔ ') + chalk.white('Scaffolded ') + chalk.cyan('.agents/') + chalk.white(' workspace'));
|
|
92
93
|
|
|
93
94
|
// --- Done ---
|
|
@@ -97,6 +98,7 @@ async function runInit() {
|
|
|
97
98
|
console.log(chalk.white(' Your AI workspace is ready:'));
|
|
98
99
|
console.log('');
|
|
99
100
|
console.log(chalk.gray(' AGENTS.md ← root agent instructions'));
|
|
101
|
+
console.log(chalk.gray(' .aiignore ← hides files from AI to save tokens'));
|
|
100
102
|
console.log(chalk.gray(' .agents/'));
|
|
101
103
|
console.log(chalk.gray(' ├── settings.json ← project config'));
|
|
102
104
|
console.log(chalk.gray(' ├── settings.local.json ← local overrides (gitignored)'));
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const chalk = require('chalk');
|
|
5
|
+
const fs = require('fs/promises');
|
|
6
|
+
const { agentDirectoryExists, addDependency, linkAgentFile } = require('../utils/fileSystem');
|
|
7
|
+
|
|
8
|
+
// A simple regex to parse YAML frontmatter block at the start of a string
|
|
9
|
+
const frontmatterRegex = /^---\r?\n([\s\S]*?)\r?\n---\r?\n/;
|
|
10
|
+
|
|
11
|
+
function parseFrontmatter(content) {
|
|
12
|
+
const match = content.match(frontmatterRegex);
|
|
13
|
+
const metadata = {};
|
|
14
|
+
if (match && match[1]) {
|
|
15
|
+
const lines = match[1].split('\n');
|
|
16
|
+
lines.forEach(line => {
|
|
17
|
+
const parts = line.split(':');
|
|
18
|
+
if (parts.length >= 2) {
|
|
19
|
+
const key = parts[0].trim();
|
|
20
|
+
const value = parts.slice(1).join(':').trim().replace(/^['"](.*)['"]$/, '$1');
|
|
21
|
+
metadata[key] = value;
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
return { metadata, rawMatch: match ? match[0] : '' };
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async function runInstall(packageName) {
|
|
29
|
+
const cwd = process.cwd();
|
|
30
|
+
|
|
31
|
+
console.log('');
|
|
32
|
+
console.log(chalk.bold.cyan(' 🤖 agentive') + chalk.gray(' — Installing Package'));
|
|
33
|
+
console.log(chalk.gray(' ─────────────────────────────────────────────'));
|
|
34
|
+
console.log('');
|
|
35
|
+
|
|
36
|
+
const exists = await agentDirectoryExists(cwd);
|
|
37
|
+
if (!exists) {
|
|
38
|
+
console.log(chalk.red(' ✖ ') + 'No .agents/ directory found. Run `npx agentive init` first.');
|
|
39
|
+
process.exit(1);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (!packageName) {
|
|
43
|
+
console.log(chalk.red(' ✖ ') + 'Please specify a package to install.');
|
|
44
|
+
process.exit(1);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
console.log(chalk.gray(` Fetching ${packageName}...`));
|
|
48
|
+
|
|
49
|
+
let fileContent = '';
|
|
50
|
+
try {
|
|
51
|
+
let url = packageName;
|
|
52
|
+
if (!url.startsWith('http')) {
|
|
53
|
+
// Mock registry URL for demonstration
|
|
54
|
+
url = `https://raw.githubusercontent.com/TiPS0/agentive-registry/main/packages/${packageName}.md`;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Attempt fetch
|
|
58
|
+
const response = await fetch(url);
|
|
59
|
+
if (!response.ok) {
|
|
60
|
+
throw new Error(`Failed to fetch from registry (Status: ${response.status})`);
|
|
61
|
+
}
|
|
62
|
+
fileContent = await response.text();
|
|
63
|
+
} catch (err) {
|
|
64
|
+
console.log(chalk.yellow(' ⚠ ') + `Fetch failed: ${err.message}`);
|
|
65
|
+
console.log(chalk.gray(' Creating a mock package for demonstration...'));
|
|
66
|
+
fileContent = `---
|
|
67
|
+
name: ${packageName}
|
|
68
|
+
type: skill
|
|
69
|
+
version: 1.0.0
|
|
70
|
+
description: A mock skill for ${packageName}
|
|
71
|
+
---
|
|
72
|
+
# ${packageName}
|
|
73
|
+
This is a generated placeholder skill because the registry could not be reached.
|
|
74
|
+
`;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const { metadata } = parseFrontmatter(fileContent);
|
|
78
|
+
const type = metadata.type || 'skill';
|
|
79
|
+
const name = metadata.name || packageName;
|
|
80
|
+
const version = metadata.version || '1.0.0';
|
|
81
|
+
|
|
82
|
+
// Pluralize type for folder name (skill -> skills, rule -> rules)
|
|
83
|
+
const folderName = type.endsWith('s') ? type : `${type}s`;
|
|
84
|
+
const agentsDir = path.join(cwd, '.agents');
|
|
85
|
+
const targetFolder = path.join(agentsDir, folderName);
|
|
86
|
+
const targetFile = path.join(targetFolder, `${packageName}.md`);
|
|
87
|
+
|
|
88
|
+
try {
|
|
89
|
+
await fs.mkdir(targetFolder, { recursive: true });
|
|
90
|
+
await fs.writeFile(targetFile, fileContent, 'utf-8');
|
|
91
|
+
|
|
92
|
+
await addDependency(agentsDir, packageName, version, type);
|
|
93
|
+
await linkAgentFile(cwd, `.agents/${folderName}/${packageName}.md`, `[${type.toUpperCase()}] ${name}`);
|
|
94
|
+
|
|
95
|
+
console.log(chalk.green(' ✔ ') + `Successfully installed ${chalk.cyan(name)} v${version}`);
|
|
96
|
+
console.log(chalk.gray(` Location: .agents/${folderName}/${packageName}.md`));
|
|
97
|
+
} catch (err) {
|
|
98
|
+
console.log(chalk.red(' ✖ ') + `Failed to write file: ${err.message}`);
|
|
99
|
+
process.exit(1);
|
|
100
|
+
}
|
|
101
|
+
console.log('');
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
module.exports = { runInstall };
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const chalk = require('chalk');
|
|
5
|
+
const fs = require('fs/promises');
|
|
6
|
+
const { agentDirectoryExists, removeDependency, readSettings, unlinkAgentFile } = require('../utils/fileSystem');
|
|
7
|
+
|
|
8
|
+
async function runRemove(packageName) {
|
|
9
|
+
const cwd = process.cwd();
|
|
10
|
+
|
|
11
|
+
console.log('');
|
|
12
|
+
console.log(chalk.bold.cyan(' 🤖 agentive') + chalk.gray(' — Removing Package'));
|
|
13
|
+
console.log(chalk.gray(' ─────────────────────────────────────────────'));
|
|
14
|
+
console.log('');
|
|
15
|
+
|
|
16
|
+
const exists = await agentDirectoryExists(cwd);
|
|
17
|
+
if (!exists) {
|
|
18
|
+
console.log(chalk.red(' ✖ ') + 'No .agents/ directory found.');
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (!packageName) {
|
|
23
|
+
console.log(chalk.red(' ✖ ') + 'Please specify a package to remove.');
|
|
24
|
+
process.exit(1);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const agentsDir = path.join(cwd, '.agents');
|
|
28
|
+
const settings = await readSettings(agentsDir);
|
|
29
|
+
|
|
30
|
+
if (!settings || !settings.dependencies || !settings.dependencies[packageName]) {
|
|
31
|
+
console.log(chalk.yellow(' ⚠ ') + `Package '${packageName}' is not installed in settings.json.`);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
let type = 'skill';
|
|
35
|
+
let name = packageName;
|
|
36
|
+
if (settings && settings.dependencies && settings.dependencies[packageName]) {
|
|
37
|
+
type = settings.dependencies[packageName].type || 'skill';
|
|
38
|
+
name = settings.dependencies[packageName].name || packageName;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const folderName = type.endsWith('s') ? type : `${type}s`;
|
|
42
|
+
const targetFile = path.join(agentsDir, folderName, `${packageName}.md`);
|
|
43
|
+
|
|
44
|
+
try {
|
|
45
|
+
await fs.rm(targetFile, { force: true });
|
|
46
|
+
const removedFromSettings = await removeDependency(agentsDir, packageName);
|
|
47
|
+
await unlinkAgentFile(cwd, `.agents/${folderName}/${packageName}.md`, `[${type.toUpperCase()}] ${name}`);
|
|
48
|
+
|
|
49
|
+
if (removedFromSettings) {
|
|
50
|
+
console.log(chalk.green(' ✔ ') + `Successfully removed ${chalk.cyan(packageName)}`);
|
|
51
|
+
} else {
|
|
52
|
+
console.log(chalk.green(' ✔ ') + `Deleted file for ${chalk.cyan(packageName)}`);
|
|
53
|
+
}
|
|
54
|
+
} catch (err) {
|
|
55
|
+
console.log(chalk.red(' ✖ ') + `Failed to remove: ${err.message}`);
|
|
56
|
+
}
|
|
57
|
+
console.log('');
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
module.exports = { runRemove };
|
|
@@ -19,6 +19,11 @@ All agent configuration lives inside the `.agents/` directory:
|
|
|
19
19
|
| `.agents/skills/` | Skill definitions that teach agents how to behave |
|
|
20
20
|
| `.agents/rules/` | Project-wide rules all agents must follow |
|
|
21
21
|
|
|
22
|
+
## Context Management
|
|
23
|
+
|
|
24
|
+
When exploring, reading, or searching this repository, you **MUST** respect the exclusion rules defined in `.aiignore`.
|
|
25
|
+
Additionally, you must also read and respect any rules defined in `.gitignore`, `.cursorignore`, or `.aiexclude` if they exist in the repository to prevent context pollution and save token usage.
|
|
26
|
+
|
|
22
27
|
## Getting Started
|
|
23
28
|
|
|
24
29
|
1. Edit the markdown files inside `.agents/` to customise agent behaviour
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Standard AI Ignore file - prevents context pollution & saves tokens
|
|
2
|
+
# Learn more: https://github.com/TiPS0/agentive
|
|
3
|
+
|
|
4
|
+
# Dependencies
|
|
5
|
+
node_modules/
|
|
6
|
+
.pnp
|
|
7
|
+
.pnp.js
|
|
8
|
+
vendor/
|
|
9
|
+
|
|
10
|
+
# Environment variables
|
|
11
|
+
.env
|
|
12
|
+
.env.local
|
|
13
|
+
.env.development.local
|
|
14
|
+
.env.test.local
|
|
15
|
+
.env.production.local
|
|
16
|
+
|
|
17
|
+
# Build outputs & generated files
|
|
18
|
+
dist/
|
|
19
|
+
build/
|
|
20
|
+
out/
|
|
21
|
+
coverage/
|
|
22
|
+
.next/
|
|
23
|
+
.nuxt/
|
|
24
|
+
.vuepress/
|
|
25
|
+
.cache/
|
|
26
|
+
|
|
27
|
+
# Logs
|
|
28
|
+
logs
|
|
29
|
+
*.log
|
|
30
|
+
npm-debug.log*
|
|
31
|
+
yarn-debug.log*
|
|
32
|
+
yarn-error.log*
|
|
33
|
+
pnpm-debug.log*
|
|
34
|
+
lerna-debug.log*
|
|
35
|
+
|
|
36
|
+
# Version control & OS files
|
|
37
|
+
.git/
|
|
38
|
+
.DS_Store
|
|
39
|
+
*.pem
|
|
40
|
+
|
|
41
|
+
# Editor directories and files
|
|
42
|
+
.idea/
|
|
43
|
+
.vscode/
|
|
44
|
+
*.suo
|
|
45
|
+
*.ntvs*
|
|
46
|
+
*.njsproj
|
|
47
|
+
*.sln
|
|
48
|
+
*.sw?
|
package/src/utils/fileSystem.js
CHANGED
|
@@ -136,6 +136,13 @@ async function copyTemplates(templatesDir, agentsDir, projectName, projectType =
|
|
|
136
136
|
await fs.writeFile(path.join(cwd, 'AGENTS.md'), content, 'utf-8');
|
|
137
137
|
} catch { /* template may not exist */ }
|
|
138
138
|
|
|
139
|
+
// 1.5 Copy aiignore from base to project root as .aiignore
|
|
140
|
+
const aiignoreSrc = path.join(templatesDir, 'base', 'aiignore');
|
|
141
|
+
try {
|
|
142
|
+
let content = await fs.readFile(aiignoreSrc, 'utf-8');
|
|
143
|
+
await fs.writeFile(path.join(cwd, '.aiignore'), content, 'utf-8');
|
|
144
|
+
} catch { /* template may not exist */ }
|
|
145
|
+
|
|
139
146
|
const foldersToInclude = ['commands', 'skills', 'rules'];
|
|
140
147
|
|
|
141
148
|
// Helper to copy a specific template layer
|
|
@@ -196,10 +203,104 @@ async function copyDirectoryRecursive(src, dest, projectName) {
|
|
|
196
203
|
}
|
|
197
204
|
}
|
|
198
205
|
}
|
|
206
|
+
// ─── Package Manager Utilities ────────────────────────────────────────────────
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Read the settings.json file.
|
|
210
|
+
*/
|
|
211
|
+
async function readSettings(agentsDir) {
|
|
212
|
+
try {
|
|
213
|
+
const content = await fs.readFile(path.join(agentsDir, 'settings.json'), 'utf-8');
|
|
214
|
+
return JSON.parse(content);
|
|
215
|
+
} catch {
|
|
216
|
+
return null;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Update the settings.json file.
|
|
222
|
+
*/
|
|
223
|
+
async function updateSettings(agentsDir, newSettings) {
|
|
224
|
+
await fs.writeFile(
|
|
225
|
+
path.join(agentsDir, 'settings.json'),
|
|
226
|
+
JSON.stringify(newSettings, null, 2) + '\n',
|
|
227
|
+
'utf-8'
|
|
228
|
+
);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Add a dependency to settings.json
|
|
233
|
+
*/
|
|
234
|
+
async function addDependency(agentsDir, packageName, version, type = 'skill') {
|
|
235
|
+
const settings = await readSettings(agentsDir);
|
|
236
|
+
if (!settings) return false;
|
|
237
|
+
if (!settings.dependencies) settings.dependencies = {};
|
|
238
|
+
settings.dependencies[packageName] = { version, type };
|
|
239
|
+
await updateSettings(agentsDir, settings);
|
|
240
|
+
return true;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Remove a dependency from settings.json
|
|
245
|
+
*/
|
|
246
|
+
async function removeDependency(agentsDir, packageName) {
|
|
247
|
+
const settings = await readSettings(agentsDir);
|
|
248
|
+
if (!settings) return false;
|
|
249
|
+
if (settings.dependencies && settings.dependencies[packageName]) {
|
|
250
|
+
delete settings.dependencies[packageName];
|
|
251
|
+
await updateSettings(agentsDir, settings);
|
|
252
|
+
return true;
|
|
253
|
+
}
|
|
254
|
+
return false;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Link a downloaded agent file into AGENTS.md
|
|
259
|
+
*/
|
|
260
|
+
async function linkAgentFile(cwd, relativePath, title) {
|
|
261
|
+
const agentMdPath = path.join(cwd, 'AGENTS.md');
|
|
262
|
+
try {
|
|
263
|
+
let content = await fs.readFile(agentMdPath, 'utf-8');
|
|
264
|
+
const linkStr = `- [${title}](${relativePath})`;
|
|
265
|
+
if (!content.includes(linkStr)) {
|
|
266
|
+
content += `\n${linkStr}\n`;
|
|
267
|
+
await fs.writeFile(agentMdPath, content, 'utf-8');
|
|
268
|
+
}
|
|
269
|
+
} catch (err) {
|
|
270
|
+
// AGENTS.md might not exist
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Unlink a removed agent file from AGENTS.md
|
|
276
|
+
*/
|
|
277
|
+
async function unlinkAgentFile(cwd, relativePath, title) {
|
|
278
|
+
const agentMdPath = path.join(cwd, 'AGENTS.md');
|
|
279
|
+
try {
|
|
280
|
+
let content = await fs.readFile(agentMdPath, 'utf-8');
|
|
281
|
+
const linkStr = `- [${title}](${relativePath})`;
|
|
282
|
+
if (content.includes(linkStr)) {
|
|
283
|
+
content = content.replace(new RegExp(`\\n?${escapeRegex(linkStr)}\\n?`, 'g'), '\n');
|
|
284
|
+
await fs.writeFile(agentMdPath, content, 'utf-8');
|
|
285
|
+
}
|
|
286
|
+
} catch (err) {
|
|
287
|
+
// AGENTS.md might not exist
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
function escapeRegex(string) {
|
|
292
|
+
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
293
|
+
}
|
|
199
294
|
|
|
200
295
|
module.exports = {
|
|
201
296
|
agentDirectoryExists,
|
|
202
297
|
createAgentDirectory,
|
|
203
298
|
writeSettings,
|
|
204
299
|
copyTemplates,
|
|
300
|
+
readSettings,
|
|
301
|
+
updateSettings,
|
|
302
|
+
addDependency,
|
|
303
|
+
removeDependency,
|
|
304
|
+
linkAgentFile,
|
|
305
|
+
unlinkAgentFile,
|
|
205
306
|
};
|