antigravity-ai-kit 3.2.0 → 3.4.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/.agent/agents/build-error-resolver.md +158 -44
- package/.agent/agents/database-architect.md +282 -66
- package/.agent/agents/devops-engineer.md +524 -76
- package/.agent/agents/doc-updater.md +189 -39
- package/.agent/agents/e2e-runner.md +348 -55
- package/.agent/agents/explorer-agent.md +196 -68
- package/.agent/agents/knowledge-agent.md +149 -35
- package/.agent/agents/mobile-developer.md +231 -57
- package/.agent/agents/performance-optimizer.md +461 -79
- package/.agent/agents/refactor-cleaner.md +143 -35
- package/.agent/agents/reliability-engineer.md +474 -49
- package/.agent/agents/security-reviewer.md +321 -78
- package/.agent/engine/loading-rules.json +22 -6
- package/.agent/manifest.json +14 -1
- package/.agent/rules/architecture.md +111 -0
- package/.agent/rules/quality-gate.md +117 -0
- package/.agent/skills/architecture/SKILL.md +170 -49
- package/.agent/skills/database-design/SKILL.md +157 -3
- package/.agent/skills/plan-writing/domain-enhancers.md +105 -35
- package/.agent/skills/security-practices/SKILL.md +189 -9
- package/.agent/workflows/quality-gate.md +1 -0
- package/README.md +30 -13
- package/bin/ag-kit.js +87 -22
- package/lib/io.js +37 -0
- package/lib/plugin-system.js +2 -26
- package/lib/security-scanner.js +6 -0
- package/lib/updater.js +1 -0
- package/lib/verify.js +39 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# 🚀 Antigravity AI Kit
|
|
2
2
|
|
|
3
|
-

|
|
4
4
|

|
|
5
5
|

|
|
6
6
|

|
|
@@ -100,22 +100,14 @@ Creates a new project with `.agent/` pre-configured. Templates: `minimal`, `node
|
|
|
100
100
|
npx antigravity-ai-kit init
|
|
101
101
|
```
|
|
102
102
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
### Option 3: Manual Installation
|
|
103
|
+
### 🔄 Updating
|
|
106
104
|
|
|
107
105
|
```bash
|
|
108
|
-
#
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
# 2. Copy .agent/ to your project
|
|
112
|
-
cp -r antigravity-ai-kit/.agent/ your-project/.agent/
|
|
113
|
-
|
|
114
|
-
# 3. Start your session
|
|
115
|
-
/status
|
|
106
|
+
ag-kit update # Non-destructive — preserves your customizations
|
|
107
|
+
ag-kit update --dry-run # Preview changes without applying
|
|
116
108
|
```
|
|
117
109
|
|
|
118
|
-
|
|
110
|
+
> **Prefer `ag-kit update` over `ag-kit init --force`**. The update command preserves your session data, ADRs, learning contexts, and customizations. Use `init --force` only for clean reinstalls.
|
|
119
111
|
|
|
120
112
|
### ✅ Verify Installation
|
|
121
113
|
|
|
@@ -124,6 +116,31 @@ ag-kit verify # Manifest integrity check
|
|
|
124
116
|
ag-kit scan # Security scan
|
|
125
117
|
```
|
|
126
118
|
|
|
119
|
+
### 🛡️ Safety Guarantees
|
|
120
|
+
|
|
121
|
+
Antigravity AI Kit is designed to **never touch your project files**. All operations are scoped to the `.agent/` directory.
|
|
122
|
+
|
|
123
|
+
| Your Project Files | Safe? | Details |
|
|
124
|
+
|:---|:---|:---|
|
|
125
|
+
| Source code (`src/`, `lib/`, `app/`) | ✅ Never touched | Init/update only operates on `.agent/` |
|
|
126
|
+
| Config files (`.env`, `package.json`) | ✅ Never touched | No project config is read or written |
|
|
127
|
+
| Documentation (`docs/`, `README.md`) | ✅ Never touched | Only `.agent/` docs are managed |
|
|
128
|
+
| Tests (`tests/`, `__tests__/`) | ✅ Never touched | Kit tests are internal to the package |
|
|
129
|
+
| Platform files (`android/`, `ios/`) | ✅ Never touched | No platform-specific operations |
|
|
130
|
+
|
|
131
|
+
**`init --force` safety features (v3.3.1+):**
|
|
132
|
+
- 🔒 **Auto-backup**: Creates timestamped backup of existing `.agent/` before overwriting
|
|
133
|
+
- ⚛️ **Atomic copy**: Uses temp directory + rename to prevent corruption on failure
|
|
134
|
+
- 🔗 **Symlink guard**: Skips symbolic links to prevent path traversal attacks
|
|
135
|
+
- ⚠️ **Session warning**: Alerts if active work-in-progress would be destroyed
|
|
136
|
+
- 🔍 **Dry-run preview**: `--dry-run --force` shows exactly which user files would be overwritten
|
|
137
|
+
|
|
138
|
+
**`update` preserved files:**
|
|
139
|
+
- `session-context.md` — Your active session notes
|
|
140
|
+
- `session-state.json` — Your session metadata
|
|
141
|
+
- `decisions/` — Your Architecture Decision Records
|
|
142
|
+
- `contexts/` — Your learning data and plan quality logs
|
|
143
|
+
|
|
127
144
|
---
|
|
128
145
|
|
|
129
146
|
## 🏗️ Architecture Overview
|
package/bin/ag-kit.js
CHANGED
|
@@ -16,6 +16,7 @@ const path = require('path');
|
|
|
16
16
|
|
|
17
17
|
const VERSION = require('../package.json').version;
|
|
18
18
|
const AGENT_FOLDER = '.agent';
|
|
19
|
+
const { safeCopyDirSync, readJsonSafe } = require('../lib/io');
|
|
19
20
|
|
|
20
21
|
// ANSI colors
|
|
21
22
|
const colors = {
|
|
@@ -49,7 +50,7 @@ ${colors.reset}
|
|
|
49
50
|
${colors.green}🚀 Antigravity AI Kit v${VERSION}${colors.reset}
|
|
50
51
|
${colors.yellow} Transform Your IDE into an Autonomous Engineering Team${colors.reset}
|
|
51
52
|
|
|
52
|
-
• 19 AI Agents •
|
|
53
|
+
• 19 AI Agents • 32 Skills
|
|
53
54
|
• 31 Commands • 14 Workflows
|
|
54
55
|
• Runtime Engine • Error Budget
|
|
55
56
|
`);
|
|
@@ -95,23 +96,28 @@ ${colors.bright}IDE Reference:${colors.reset}
|
|
|
95
96
|
`);
|
|
96
97
|
}
|
|
97
98
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
99
|
+
/**
|
|
100
|
+
* Creates a timestamped backup of a directory.
|
|
101
|
+
* @param {string} dirPath - Directory to back up
|
|
102
|
+
* @returns {string} Path to the backup directory
|
|
103
|
+
*/
|
|
104
|
+
function backupDirectory(dirPath) {
|
|
105
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
106
|
+
const backupPath = `${dirPath}.backup-${timestamp}`;
|
|
107
|
+
safeCopyDirSync(dirPath, backupPath);
|
|
108
|
+
return backupPath;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Checks if there is an active session with in-progress work.
|
|
113
|
+
* @param {string} agentPath - Path to existing .agent directory
|
|
114
|
+
* @returns {boolean} True if session-state indicates active work
|
|
115
|
+
*/
|
|
116
|
+
function hasActiveSession(agentPath) {
|
|
117
|
+
const statePath = path.join(agentPath, 'session-state.json');
|
|
118
|
+
const state = readJsonSafe(statePath, null);
|
|
119
|
+
if (!state) return false;
|
|
120
|
+
return state.currentTask || state.inProgress || state.activeWorkflow;
|
|
115
121
|
}
|
|
116
122
|
|
|
117
123
|
function countItems(dir, type = 'dir') {
|
|
@@ -146,24 +152,76 @@ function initCommand(options) {
|
|
|
146
152
|
// Check if already exists
|
|
147
153
|
if (fs.existsSync(agentPath) && !options.force) {
|
|
148
154
|
log(`\n⚠️ ${AGENT_FOLDER} folder already exists!`, 'yellow');
|
|
149
|
-
log(' Use --force to overwrite
|
|
155
|
+
log(' Use --force to overwrite', 'yellow');
|
|
156
|
+
log(' Use ag-kit update for non-destructive updates\n', 'yellow');
|
|
150
157
|
process.exit(1);
|
|
151
158
|
}
|
|
152
159
|
|
|
160
|
+
// M-3: Active session warning for --force
|
|
161
|
+
if (options.force && fs.existsSync(agentPath) && hasActiveSession(agentPath)) {
|
|
162
|
+
log('\n⚠️ Active session detected! Force-overwrite will destroy in-progress work.', 'yellow');
|
|
163
|
+
log(' Consider using ag-kit update instead.\n', 'yellow');
|
|
164
|
+
}
|
|
165
|
+
|
|
153
166
|
if (options.dryRun) {
|
|
154
167
|
log('\n🔍 Dry run mode - no changes will be made\n', 'cyan');
|
|
155
168
|
log(` Would copy: ${sourcePath}`, 'cyan');
|
|
156
169
|
log(` To: ${agentPath}\n`, 'cyan');
|
|
170
|
+
// M-2: Show force damage preview
|
|
171
|
+
if (options.force && fs.existsSync(agentPath)) {
|
|
172
|
+
log(' ⚠️ --force would overwrite these user files:', 'yellow');
|
|
173
|
+
const userFiles = ['session-context.md', 'session-state.json'];
|
|
174
|
+
const userDirs = ['decisions', 'contexts'];
|
|
175
|
+
for (const f of userFiles) {
|
|
176
|
+
if (fs.existsSync(path.join(agentPath, f))) {
|
|
177
|
+
log(` • ${f}`, 'yellow');
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
for (const d of userDirs) {
|
|
181
|
+
if (fs.existsSync(path.join(agentPath, d))) {
|
|
182
|
+
log(` • ${d}/ (directory)`, 'yellow');
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
log('', 'reset');
|
|
186
|
+
}
|
|
157
187
|
return;
|
|
158
188
|
}
|
|
159
189
|
|
|
160
|
-
//
|
|
161
|
-
|
|
190
|
+
// C-2: Auto-backup before force-overwrite
|
|
191
|
+
if (options.force && fs.existsSync(agentPath)) {
|
|
192
|
+
logStep('1/4', 'Backing up existing .agent folder...');
|
|
193
|
+
try {
|
|
194
|
+
const backupPath = backupDirectory(agentPath);
|
|
195
|
+
log(` ✓ Backup created: ${path.basename(backupPath)}`, 'green');
|
|
196
|
+
} catch (err) {
|
|
197
|
+
log(` ⚠️ Backup failed: ${err.message}`, 'yellow');
|
|
198
|
+
log(' Proceeding without backup...', 'yellow');
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// C-3: Atomic copy via temp directory
|
|
203
|
+
const stepPrefix = options.force && fs.existsSync(agentPath) ? '2/4' : '1/3';
|
|
204
|
+
logStep(stepPrefix, 'Copying .agent folder...');
|
|
162
205
|
|
|
206
|
+
const tempPath = `${agentPath}.tmp-${Date.now()}`;
|
|
163
207
|
try {
|
|
164
|
-
|
|
208
|
+
safeCopyDirSync(sourcePath, tempPath);
|
|
209
|
+
// Remove old directory if force-overwriting
|
|
210
|
+
if (fs.existsSync(agentPath)) {
|
|
211
|
+
fs.rmSync(agentPath, { recursive: true, force: true });
|
|
212
|
+
}
|
|
213
|
+
// Atomic rename: move temp to final
|
|
214
|
+
fs.renameSync(tempPath, agentPath);
|
|
165
215
|
log(' ✓ Copied successfully', 'green');
|
|
166
216
|
} catch (err) {
|
|
217
|
+
// Cleanup temp directory on failure
|
|
218
|
+
try {
|
|
219
|
+
if (fs.existsSync(tempPath)) {
|
|
220
|
+
fs.rmSync(tempPath, { recursive: true, force: true });
|
|
221
|
+
}
|
|
222
|
+
} catch {
|
|
223
|
+
// Cleanup failure is non-critical
|
|
224
|
+
}
|
|
167
225
|
log(` ✗ Failed to copy: ${err.message}`, 'red');
|
|
168
226
|
process.exit(1);
|
|
169
227
|
}
|
|
@@ -366,6 +424,13 @@ function updateCommand(updateOptions) {
|
|
|
366
424
|
const updater = require('../lib/updater');
|
|
367
425
|
const isDryRun = updateOptions.dryRun;
|
|
368
426
|
|
|
427
|
+
// M-1: Show version transition
|
|
428
|
+
const currentManifest = readJsonSafe(path.join(agentPath, 'manifest.json'), {});
|
|
429
|
+
const currentVersion = currentManifest.kitVersion || 'unknown';
|
|
430
|
+
if (currentVersion !== VERSION) {
|
|
431
|
+
log(`\n 📦 Upgrading from v${currentVersion} → v${VERSION}`, 'cyan');
|
|
432
|
+
}
|
|
433
|
+
|
|
369
434
|
if (isDryRun) {
|
|
370
435
|
log('\n🔍 Dry run mode — no changes will be made\n', 'cyan');
|
|
371
436
|
}
|
package/lib/io.js
CHANGED
|
@@ -68,7 +68,44 @@ function readJsonSafe(filePath, defaultValue = null) {
|
|
|
68
68
|
}
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
+
/**
|
|
72
|
+
* Recursively copies a directory, skipping symbolic links for security.
|
|
73
|
+
*
|
|
74
|
+
* Symlinks are skipped because they could point outside the intended
|
|
75
|
+
* scope (e.g., outside .agent/), enabling path traversal attacks.
|
|
76
|
+
*
|
|
77
|
+
* @param {string} src - Source directory path
|
|
78
|
+
* @param {string} dest - Destination directory path
|
|
79
|
+
* @returns {void}
|
|
80
|
+
*/
|
|
81
|
+
function safeCopyDirSync(src, dest) {
|
|
82
|
+
if (!fs.existsSync(dest)) {
|
|
83
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const entries = fs.readdirSync(src, { withFileTypes: true });
|
|
87
|
+
|
|
88
|
+
for (const entry of entries) {
|
|
89
|
+
const srcPath = path.join(src, entry.name);
|
|
90
|
+
const destPath = path.join(dest, entry.name);
|
|
91
|
+
|
|
92
|
+
// Security: skip symlinks to prevent path traversal
|
|
93
|
+
const stat = fs.lstatSync(srcPath);
|
|
94
|
+
if (stat.isSymbolicLink()) {
|
|
95
|
+
log.debug('Skipping symlink for security', { path: srcPath });
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (entry.isDirectory()) {
|
|
100
|
+
safeCopyDirSync(srcPath, destPath);
|
|
101
|
+
} else {
|
|
102
|
+
fs.copyFileSync(srcPath, destPath);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
71
107
|
module.exports = {
|
|
72
108
|
writeJsonAtomic,
|
|
73
109
|
readJsonSafe,
|
|
110
|
+
safeCopyDirSync,
|
|
74
111
|
};
|
package/lib/plugin-system.js
CHANGED
|
@@ -16,7 +16,7 @@ const fs = require('fs');
|
|
|
16
16
|
const path = require('path');
|
|
17
17
|
|
|
18
18
|
const { AGENT_DIR, ENGINE_DIR, PLUGINS_DIR, HOOKS_DIR } = require('./constants');
|
|
19
|
-
const { writeJsonAtomic } = require('./io');
|
|
19
|
+
const { writeJsonAtomic, safeCopyDirSync } = require('./io');
|
|
20
20
|
const { createLogger } = require('./logger');
|
|
21
21
|
const log = createLogger('plugin-system');
|
|
22
22
|
const PLUGINS_REGISTRY = 'plugins-registry.json';
|
|
@@ -289,7 +289,7 @@ function installPlugin(pluginPath, projectRoot) {
|
|
|
289
289
|
for (const skillDir of (manifest.skills || [])) {
|
|
290
290
|
const src = path.join(pluginPath, 'skills', skillDir);
|
|
291
291
|
const dest = path.join(projectRoot, AGENT_DIR, 'skills', skillDir);
|
|
292
|
-
|
|
292
|
+
safeCopyDirSync(src, dest);
|
|
293
293
|
installed.skills++;
|
|
294
294
|
}
|
|
295
295
|
|
|
@@ -593,31 +593,7 @@ function copyFileSync(src, dest) {
|
|
|
593
593
|
fs.copyFileSync(src, dest);
|
|
594
594
|
}
|
|
595
595
|
|
|
596
|
-
/**
|
|
597
|
-
* Recursively copies a directory.
|
|
598
|
-
*
|
|
599
|
-
* @param {string} src - Source directory
|
|
600
|
-
* @param {string} dest - Destination directory
|
|
601
|
-
* @returns {void}
|
|
602
|
-
*/
|
|
603
|
-
function copyDirSync(src, dest) {
|
|
604
|
-
if (!fs.existsSync(dest)) {
|
|
605
|
-
fs.mkdirSync(dest, { recursive: true });
|
|
606
|
-
}
|
|
607
|
-
|
|
608
|
-
const entries = fs.readdirSync(src, { withFileTypes: true });
|
|
609
596
|
|
|
610
|
-
for (const entry of entries) {
|
|
611
|
-
const srcPath = path.join(src, entry.name);
|
|
612
|
-
const destPath = path.join(dest, entry.name);
|
|
613
|
-
|
|
614
|
-
if (entry.isDirectory()) {
|
|
615
|
-
copyDirSync(srcPath, destPath);
|
|
616
|
-
} else {
|
|
617
|
-
fs.copyFileSync(srcPath, destPath);
|
|
618
|
-
}
|
|
619
|
-
}
|
|
620
|
-
}
|
|
621
597
|
|
|
622
598
|
module.exports = {
|
|
623
599
|
validatePlugin,
|
package/lib/security-scanner.js
CHANGED
|
@@ -262,6 +262,12 @@ function collectAllFiles(dirPath) {
|
|
|
262
262
|
for (const entry of entries) {
|
|
263
263
|
const fullPath = path.join(dirPath, entry.name);
|
|
264
264
|
|
|
265
|
+
// Security: skip symlinks to prevent path traversal
|
|
266
|
+
const stat = fs.lstatSync(fullPath);
|
|
267
|
+
if (stat.isSymbolicLink()) {
|
|
268
|
+
continue;
|
|
269
|
+
}
|
|
270
|
+
|
|
265
271
|
if (entry.isDirectory() && entry.name !== 'node_modules' && entry.name !== '.git') {
|
|
266
272
|
files.push(...collectAllFiles(fullPath));
|
|
267
273
|
} else if (entry.isFile()) {
|
package/lib/updater.js
CHANGED
package/lib/verify.js
CHANGED
|
@@ -189,6 +189,32 @@ function runAllChecks(projectRoot) {
|
|
|
189
189
|
results.push(checkJsonFile(path.join(agentDir, ENGINE_DIR, engineFile), `engine:${engineFile}`));
|
|
190
190
|
}
|
|
191
191
|
|
|
192
|
+
// --- Check 10a: Rule files exist ---
|
|
193
|
+
const manifestRules = manifest.capabilities?.rules?.items || [];
|
|
194
|
+
for (const rule of manifestRules) {
|
|
195
|
+
const rulePath = path.join(agentDir, rule.file);
|
|
196
|
+
const exists = fs.existsSync(rulePath);
|
|
197
|
+
results.push({
|
|
198
|
+
name: `rule-file:${rule.name}`,
|
|
199
|
+
status: exists ? 'pass' : 'fail',
|
|
200
|
+
message: exists ? `Rule exists: ${rule.name}` : `Missing rule file: ${rule.file}`,
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// --- Check 10b: Rule count matches ---
|
|
205
|
+
const ruleCountManifest = manifest.capabilities?.rules?.count || 0;
|
|
206
|
+
const ruleCountFS = fs.existsSync(path.join(agentDir, 'rules'))
|
|
207
|
+
? fs.readdirSync(path.join(agentDir, 'rules')).filter((f) => f.endsWith('.md') && f !== 'README.md').length
|
|
208
|
+
: 0;
|
|
209
|
+
results.push({
|
|
210
|
+
name: 'rule-count',
|
|
211
|
+
status: ruleCountManifest === ruleCountFS ? 'pass' : 'fail',
|
|
212
|
+
message:
|
|
213
|
+
ruleCountManifest === ruleCountFS
|
|
214
|
+
? `Rule count matches: ${ruleCountFS}`
|
|
215
|
+
: `Rule count mismatch: manifest=${ruleCountManifest}, filesystem=${ruleCountFS}`,
|
|
216
|
+
});
|
|
217
|
+
|
|
192
218
|
// --- Check 11: Hooks file valid ---
|
|
193
219
|
results.push(checkJsonFile(path.join(agentDir, HOOKS_DIR, 'hooks.json'), 'hooks-json'));
|
|
194
220
|
|
|
@@ -212,6 +238,19 @@ function runAllChecks(projectRoot) {
|
|
|
212
238
|
});
|
|
213
239
|
}
|
|
214
240
|
}
|
|
241
|
+
// --- Check 13: Cross-reference — alwaysLoadRules files exist ---
|
|
242
|
+
const mandatoryRules = loadingRules.planningMandates?.alwaysLoadRules || [];
|
|
243
|
+
for (const ruleName of mandatoryRules) {
|
|
244
|
+
const rulePath = path.join(agentDir, 'rules', `${ruleName}.md`);
|
|
245
|
+
const ruleExists = fs.existsSync(rulePath);
|
|
246
|
+
results.push({
|
|
247
|
+
name: `xref:mandatory-rule:${ruleName}`,
|
|
248
|
+
status: ruleExists ? 'pass' : 'fail',
|
|
249
|
+
message: ruleExists
|
|
250
|
+
? `Mandatory rule "${ruleName}" exists`
|
|
251
|
+
: `Mandatory rule "${ruleName}" referenced in alwaysLoadRules but file missing: rules/${ruleName}.md`,
|
|
252
|
+
});
|
|
253
|
+
}
|
|
215
254
|
} catch {
|
|
216
255
|
results.push({ name: 'xref:loading-rules', status: 'warn', message: 'Could not parse loading-rules.json for cross-reference check' });
|
|
217
256
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "antigravity-ai-kit",
|
|
3
|
-
"version": "3.
|
|
4
|
-
"description": "🚀 Trust-Grade AI development framework with a 29-module runtime engine — 19 Agents, 32 Skills, 31 Commands, 14 Workflows,
|
|
3
|
+
"version": "3.4.0",
|
|
4
|
+
"description": "🚀 Trust-Grade AI development framework with a 29-module runtime engine — 19 Agents, 32 Skills, 31 Commands, 14 Workflows, 8 Rules, 330 Tests. Workflow enforcement, task governance, agent reputation, self-healing, and skill marketplace.",
|
|
5
5
|
"main": "bin/ag-kit.js",
|
|
6
6
|
"bin": {
|
|
7
7
|
"ag-kit": "./bin/ag-kit.js"
|