attacca-forge 0.5.1 → 0.5.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.
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
{
|
|
10
10
|
"name": "attacca-forge",
|
|
11
11
|
"description": "AI agent development methodology — design, evaluate, and align autonomous agents with production-grade specifications, factorial stress testing, and intent engineering",
|
|
12
|
-
"version": "0.5.
|
|
12
|
+
"version": "0.5.2",
|
|
13
13
|
"author": {
|
|
14
14
|
"name": "Attacca"
|
|
15
15
|
},
|
package/package.json
CHANGED
package/src/commands/install.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// attacca-forge install — Install skills into Claude Code plugin directory
|
|
3
3
|
// =============================================================================
|
|
4
4
|
|
|
5
|
-
import { cpSync, existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
5
|
+
import { cpSync, existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from 'node:fs';
|
|
6
6
|
import { join } from 'node:path';
|
|
7
7
|
import { getClaudeDir, getPluginDir, isClaudeInstalled } from '../utils/detect-claude.js';
|
|
8
8
|
|
|
@@ -26,7 +26,6 @@ function registerMarketplace(claudeDir, targetDir) {
|
|
|
26
26
|
const marketplaces = readJsonFile(marketplacesPath) || {};
|
|
27
27
|
|
|
28
28
|
if (marketplaces[MARKETPLACE_NAME]) {
|
|
29
|
-
// Update timestamp
|
|
30
29
|
marketplaces[MARKETPLACE_NAME].lastUpdated = new Date().toISOString();
|
|
31
30
|
} else {
|
|
32
31
|
marketplaces[MARKETPLACE_NAME] = {
|
|
@@ -43,30 +42,27 @@ function registerMarketplace(claudeDir, targetDir) {
|
|
|
43
42
|
return true;
|
|
44
43
|
}
|
|
45
44
|
|
|
46
|
-
function registerPlugin(claudeDir,
|
|
45
|
+
function registerPlugin(claudeDir, pluginDir, version) {
|
|
47
46
|
const installedPath = join(claudeDir, 'plugins', 'installed_plugins.json');
|
|
48
47
|
const installed = readJsonFile(installedPath) || { version: 2, plugins: {} };
|
|
49
48
|
|
|
50
|
-
// Ensure version 2 format
|
|
51
49
|
if (!installed.version) installed.version = 2;
|
|
52
50
|
if (!installed.plugins) installed.plugins = {};
|
|
53
51
|
|
|
54
52
|
const pluginKey = `${PLUGIN_NAME}@${MARKETPLACE_NAME}`;
|
|
55
53
|
const now = new Date().toISOString();
|
|
56
54
|
|
|
57
|
-
// Set up cache directory
|
|
55
|
+
// Set up cache directory and copy skills there
|
|
58
56
|
const cachePath = join(claudeDir, 'plugins', 'cache', MARKETPLACE_NAME, PLUGIN_NAME, version);
|
|
59
57
|
if (!existsSync(cachePath)) mkdirSync(cachePath, { recursive: true });
|
|
60
58
|
|
|
61
|
-
|
|
62
|
-
const sourceSkills = join(targetDir, 'skills');
|
|
59
|
+
const sourceSkills = join(pluginDir, 'skills');
|
|
63
60
|
const cacheSkills = join(cachePath, 'skills');
|
|
64
61
|
if (existsSync(sourceSkills)) {
|
|
65
62
|
cpSync(sourceSkills, cacheSkills, { recursive: true, force: true });
|
|
66
63
|
}
|
|
67
64
|
|
|
68
65
|
if (installed.plugins[pluginKey]) {
|
|
69
|
-
// Update existing entry
|
|
70
66
|
installed.plugins[pluginKey][0].version = version;
|
|
71
67
|
installed.plugins[pluginKey][0].installPath = cachePath;
|
|
72
68
|
installed.plugins[pluginKey][0].lastUpdated = now;
|
|
@@ -102,8 +98,13 @@ export default async function install({ args, cwd, rootDir }) {
|
|
|
102
98
|
|
|
103
99
|
console.log(' ✓ Claude Code detected');
|
|
104
100
|
|
|
105
|
-
// Source
|
|
101
|
+
// Source directories (shipped with this package)
|
|
102
|
+
// Repo layout:
|
|
103
|
+
// .claude-plugin/marketplace.json ← marketplace descriptor
|
|
104
|
+
// plugins/attacca-forge/ ← plugin with .claude-plugin/plugin.json + skills/
|
|
105
|
+
const sourceMarketplace = join(rootDir, '.claude-plugin', 'marketplace.json');
|
|
106
106
|
const sourcePlugin = join(rootDir, 'plugins', 'attacca-forge');
|
|
107
|
+
|
|
107
108
|
if (!existsSync(sourcePlugin)) {
|
|
108
109
|
console.error(' ✗ Plugin source not found. Package may be corrupted.');
|
|
109
110
|
process.exit(1);
|
|
@@ -111,36 +112,35 @@ export default async function install({ args, cwd, rootDir }) {
|
|
|
111
112
|
|
|
112
113
|
// Read version from package.json
|
|
113
114
|
const pkg = readJsonFile(join(rootDir, 'package.json'));
|
|
114
|
-
const version = pkg?.version || '0.5.
|
|
115
|
+
const version = pkg?.version || '0.5.2';
|
|
115
116
|
|
|
116
|
-
// Target
|
|
117
|
+
// Target: ~/.claude/plugins/local/attacca-forge/
|
|
118
|
+
// Installed layout (mirrors nirbound-marketplace):
|
|
119
|
+
// .claude-plugin/marketplace.json
|
|
120
|
+
// plugins/attacca-forge/.claude-plugin/plugin.json
|
|
121
|
+
// plugins/attacca-forge/skills/
|
|
117
122
|
const claudeDir = getClaudeDir();
|
|
118
123
|
const targetDir = getPluginDir();
|
|
119
|
-
const localDir = join(claudeDir, 'plugins', 'local');
|
|
120
|
-
|
|
121
|
-
// Create directories
|
|
122
|
-
if (!existsSync(localDir)) mkdirSync(localDir, { recursive: true });
|
|
123
124
|
|
|
124
|
-
// Copy .claude-plugin/ and skills/
|
|
125
125
|
const existed = existsSync(targetDir);
|
|
126
126
|
if (!existsSync(targetDir)) mkdirSync(targetDir, { recursive: true });
|
|
127
127
|
|
|
128
|
-
|
|
129
|
-
const
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
if (existsSync(sourceClaudePlugin)) {
|
|
134
|
-
cpSync(sourceClaudePlugin, targetClaudePlugin, { recursive: true, force: true });
|
|
135
|
-
}
|
|
136
|
-
if (existsSync(sourceSkills)) {
|
|
137
|
-
cpSync(sourceSkills, targetSkills, { recursive: true, force: true });
|
|
128
|
+
// 1. Copy marketplace descriptor to target root
|
|
129
|
+
const targetMarketplaceDir = join(targetDir, '.claude-plugin');
|
|
130
|
+
if (!existsSync(targetMarketplaceDir)) mkdirSync(targetMarketplaceDir, { recursive: true });
|
|
131
|
+
if (existsSync(sourceMarketplace)) {
|
|
132
|
+
cpSync(sourceMarketplace, join(targetMarketplaceDir, 'marketplace.json'), { force: true });
|
|
138
133
|
}
|
|
139
134
|
|
|
135
|
+
// 2. Copy plugin (with .claude-plugin/plugin.json + skills/) into nested directory
|
|
136
|
+
const targetPlugin = join(targetDir, 'plugins', 'attacca-forge');
|
|
137
|
+
if (!existsSync(targetPlugin)) mkdirSync(targetPlugin, { recursive: true });
|
|
138
|
+
cpSync(sourcePlugin, targetPlugin, { recursive: true, force: true });
|
|
139
|
+
|
|
140
140
|
// Count skills
|
|
141
|
+
const targetSkills = join(targetPlugin, 'skills');
|
|
141
142
|
let skillCount = 0;
|
|
142
143
|
if (existsSync(targetSkills)) {
|
|
143
|
-
const { readdirSync } = await import('node:fs');
|
|
144
144
|
skillCount = readdirSync(targetSkills).filter((f) => {
|
|
145
145
|
return existsSync(join(targetSkills, f, 'SKILL.md'));
|
|
146
146
|
}).length;
|
|
@@ -149,14 +149,15 @@ export default async function install({ args, cwd, rootDir }) {
|
|
|
149
149
|
console.log(` ✓ ${existed ? 'Updated' : 'Installed'} ${skillCount} skills to Claude Code`);
|
|
150
150
|
console.log(` Location: ${targetDir}`);
|
|
151
151
|
|
|
152
|
-
// Register marketplace
|
|
152
|
+
// 3. Register marketplace in known_marketplaces.json
|
|
153
153
|
const pluginsDir = join(claudeDir, 'plugins');
|
|
154
154
|
if (!existsSync(pluginsDir)) mkdirSync(pluginsDir, { recursive: true });
|
|
155
155
|
|
|
156
156
|
registerMarketplace(claudeDir, targetDir);
|
|
157
157
|
console.log(' ✓ Marketplace registered');
|
|
158
158
|
|
|
159
|
-
|
|
159
|
+
// 4. Register plugin in installed_plugins.json + populate cache
|
|
160
|
+
registerPlugin(claudeDir, targetPlugin, version);
|
|
160
161
|
console.log(' ✓ Plugin registered');
|
|
161
162
|
|
|
162
163
|
console.log('');
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$schema": "https://anthropic.com/claude-code/marketplace.schema.json",
|
|
3
|
-
"name": "attacca-forge",
|
|
4
|
-
"description": "Attacca Forge — AI agent development methodology: design, evaluate, align, and orchestrate autonomous agents",
|
|
5
|
-
"owner": {
|
|
6
|
-
"name": "Attacca"
|
|
7
|
-
},
|
|
8
|
-
"plugins": [
|
|
9
|
-
{
|
|
10
|
-
"name": "attacca-forge",
|
|
11
|
-
"description": "AI agent development methodology — design, evaluate, and align autonomous agents. 26 skills across spec writing, stress testing, intent engineering, and build orchestration.",
|
|
12
|
-
"version": "0.5.1",
|
|
13
|
-
"author": {
|
|
14
|
-
"name": "Attacca"
|
|
15
|
-
},
|
|
16
|
-
"source": ".",
|
|
17
|
-
"category": "development"
|
|
18
|
-
}
|
|
19
|
-
]
|
|
20
|
-
}
|