solmate-skills 2.0.11 → 2.0.13
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/AGENTS.md +11 -0
- package/CLAUDE.md +13 -3
- package/README.md +135 -286
- package/USAGE.md +893 -0
- package/bin/cli.js +198 -3
- package/bin/harness-artifact.js +621 -0
- package/bin/harness-artifact.test.js +520 -0
- package/bin/harness-check.js +373 -0
- package/bin/harness-check.test.js +159 -0
- package/bin/test.js +2 -0
- package/docs/01_Concept_Design/01_AGENT_HARNESS_REQUIREMENTS_ANALYSIS.md +162 -0
- package/docs/03_Technical_Specs/01_AGENT_HARNESS_ARCHITECTURE.md +376 -0
- package/docs/03_Technical_Specs/assets/01_agent_harness_data_flow.svg +94 -0
- package/docs/04_Logic_Progress/00_BACKLOG.md +339 -0
- package/docs/04_Logic_Progress/01_EXECUTION_PLAN.md +160 -0
- package/docs/04_Logic_Progress/03_DECISION_LOG.md +98 -0
- package/docs/05_QA_Validation/01_TEST_SCENARIOS.md +313 -0
- package/docs/05_QA_Validation/02_AGENT_HARNESS_DESIGN_REVIEW.md +100 -0
- package/docs/05_QA_Validation/03_AGENT_HARNESS_CONTRACT_QA.md +96 -0
- package/manage-collaboration/SKILL.md +2 -0
- package/package.json +6 -4
- package/rules-docs/SKILL.md +15 -1
- package/rules-product/SKILL.md +37 -6
- package/rules-product/agents/openai.yaml +2 -2
- package/rules-workflow/SKILL.md +38 -6
- package/rules-workflow/adapters/claude/solmate-context-reader.md +17 -0
- package/rules-workflow/adapters/claude/solmate-implementer.md +20 -0
- package/rules-workflow/adapters/claude/solmate-verifier.md +21 -0
- package/rules-workflow/agents/openai.yaml +2 -2
- package/rules-workflow/resources/agent-harness-contract.md +187 -0
- package/rules-workflow/resources/agent-harness-v1.schema.json +432 -0
- package/verify-docs/SKILL.md +33 -6
- package/verify-docs/agents/openai.yaml +2 -2
- package/verify-implementation/SKILL.md +21 -2
- package/verify-implementation/agents/openai.yaml +2 -2
- package/verify-skills/SKILL.md +34 -1
package/bin/cli.js
CHANGED
|
@@ -3,10 +3,23 @@
|
|
|
3
3
|
const fs = require('fs');
|
|
4
4
|
const path = require('path');
|
|
5
5
|
const { execSync } = require('child_process');
|
|
6
|
+
const {
|
|
7
|
+
checkHarnessTask,
|
|
8
|
+
formatHarnessResult,
|
|
9
|
+
getHarnessExitCode,
|
|
10
|
+
} = require('./harness-check');
|
|
11
|
+
const {
|
|
12
|
+
checkHarnessArtifact,
|
|
13
|
+
formatHarnessArtifactResult,
|
|
14
|
+
getHarnessArtifactExitCode,
|
|
15
|
+
} = require('./harness-artifact');
|
|
6
16
|
|
|
7
17
|
const IGNORED_FOLDERS = ['bin', 'node_modules', '.git', '.github', '.gemini', '.agent'];
|
|
8
18
|
const IGNORED_FILES = ['package.json', 'package-lock.json', 'AGENTS.md', 'SKILL.md', 'init-skills.sh', 'README.md', '.DS_Store', 'old_AGENTS.md'];
|
|
9
19
|
|
|
20
|
+
// Root-level docs copied to the target project on every install.
|
|
21
|
+
const PACKAGE_DOC_FILES = ['USAGE.md'];
|
|
22
|
+
|
|
10
23
|
// Skills that require a post-install script to be executed after copying.
|
|
11
24
|
// Key: skill name, Value: path relative to the skill folder.
|
|
12
25
|
const POST_INSTALL_SCRIPTS = {
|
|
@@ -16,6 +29,8 @@ const POST_INSTALL_SCRIPTS = {
|
|
|
16
29
|
const packageRoot = path.join(__dirname, '..');
|
|
17
30
|
const targetProjectRoot = process.cwd();
|
|
18
31
|
const targetSkillsDir = path.join(targetProjectRoot, '.agent', 'skills');
|
|
32
|
+
const claudeAgentSourceDir = path.join(packageRoot, 'rules-workflow', 'adapters', 'claude');
|
|
33
|
+
const targetClaudeAgentsDir = path.join(targetProjectRoot, '.claude', 'agents');
|
|
19
34
|
|
|
20
35
|
function getAvailableSkills() {
|
|
21
36
|
return fs.readdirSync(packageRoot, { withFileTypes: true })
|
|
@@ -28,6 +43,21 @@ function getAvailableSkills() {
|
|
|
28
43
|
.map(dirent => dirent.name);
|
|
29
44
|
}
|
|
30
45
|
|
|
46
|
+
function installPackageDocs() {
|
|
47
|
+
for (const fileName of PACKAGE_DOC_FILES) {
|
|
48
|
+
const sourcePath = path.join(packageRoot, fileName);
|
|
49
|
+
const destPath = path.join(targetProjectRoot, fileName);
|
|
50
|
+
|
|
51
|
+
if (!fs.existsSync(sourcePath)) {
|
|
52
|
+
console.warn(`Warning: ${fileName} not found in package; skipping.`);
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
fs.copyFileSync(sourcePath, destPath);
|
|
57
|
+
console.log(`Installed ${fileName} to project root`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
31
61
|
function copyFolderSync(from, to) {
|
|
32
62
|
if (!fs.existsSync(to)) {
|
|
33
63
|
fs.mkdirSync(to, { recursive: true });
|
|
@@ -43,13 +73,40 @@ function copyFolderSync(from, to) {
|
|
|
43
73
|
});
|
|
44
74
|
}
|
|
45
75
|
|
|
76
|
+
function installAgentAdapters() {
|
|
77
|
+
if (!fs.existsSync(claudeAgentSourceDir)) {
|
|
78
|
+
console.error('Error: Claude agent adapters not found in rules-workflow.');
|
|
79
|
+
process.exit(1);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
fs.mkdirSync(targetClaudeAgentsDir, { recursive: true });
|
|
83
|
+
const agentFiles = fs.readdirSync(claudeAgentSourceDir)
|
|
84
|
+
.filter(fileName => fileName.startsWith('solmate-') && fileName.endsWith('.md'));
|
|
85
|
+
|
|
86
|
+
for (const fileName of agentFiles) {
|
|
87
|
+
fs.copyFileSync(
|
|
88
|
+
path.join(claudeAgentSourceDir, fileName),
|
|
89
|
+
path.join(targetClaudeAgentsDir, fileName),
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
console.log(`Installed ${agentFiles.length} Claude agent adapters to .claude/agents`);
|
|
94
|
+
console.log('Codex uses the same contract through rules-workflow; linked AGENTS.md reinforces it globally.');
|
|
95
|
+
}
|
|
96
|
+
|
|
46
97
|
function listSkills() {
|
|
47
98
|
const skills = getAvailableSkills();
|
|
48
99
|
console.log('\nAvailable skills to install:');
|
|
49
100
|
skills.forEach(skill => console.log(` - ${skill}`));
|
|
50
101
|
console.log('\nUtilities:');
|
|
51
102
|
console.log(' - hooks (install with: npx solmate-skills install hooks)');
|
|
52
|
-
console.log('
|
|
103
|
+
console.log(' - agents (install with: npx solmate-skills install agents)');
|
|
104
|
+
console.log('\nHarness checks:');
|
|
105
|
+
console.log(' - npx solmate-skills preflight TASK-000 [--strict]');
|
|
106
|
+
console.log(' - npx solmate-skills verify TASK-000 [--strict]');
|
|
107
|
+
console.log(' - npx solmate-skills validate-harness <manifest|message|events> <path> [--manifest <path>] [--strict]');
|
|
108
|
+
console.log(' message and events validation require --manifest <path>');
|
|
109
|
+
console.log('\nUsage: npx solmate-skills install <skill-name> | all | hooks | agents\n');
|
|
53
110
|
}
|
|
54
111
|
|
|
55
112
|
function installHooks() {
|
|
@@ -64,6 +121,7 @@ function installHooks() {
|
|
|
64
121
|
console.log('Installing hooks utility...');
|
|
65
122
|
copyFolderSync(sourcePath, destPath);
|
|
66
123
|
console.log('Successfully installed hooks utility to .agent/skills/hooks');
|
|
124
|
+
installPackageDocs();
|
|
67
125
|
|
|
68
126
|
const scriptPath = path.join(destPath, 'install.sh');
|
|
69
127
|
if (fs.existsSync(scriptPath)) {
|
|
@@ -76,12 +134,14 @@ function installHooks() {
|
|
|
76
134
|
}
|
|
77
135
|
}
|
|
78
136
|
|
|
79
|
-
function installSkill(skillName) {
|
|
137
|
+
function installSkill(skillName, options = {}) {
|
|
138
|
+
const { deferPackageDocs = false } = options;
|
|
80
139
|
const skills = getAvailableSkills();
|
|
81
140
|
|
|
82
141
|
if (skillName === 'install-all') {
|
|
83
142
|
console.log('Installing all skills...');
|
|
84
|
-
skills.forEach(s => installSkill(s));
|
|
143
|
+
skills.forEach(s => installSkill(s, { deferPackageDocs: true }));
|
|
144
|
+
installPackageDocs();
|
|
85
145
|
return;
|
|
86
146
|
}
|
|
87
147
|
|
|
@@ -102,6 +162,10 @@ function installSkill(skillName) {
|
|
|
102
162
|
copyFolderSync(sourcePath, destPath);
|
|
103
163
|
console.log(`Successfully installed ${skillName} to .agent/skills/${skillName}`);
|
|
104
164
|
|
|
165
|
+
if (skillName === 'rules-workflow') {
|
|
166
|
+
installAgentAdapters();
|
|
167
|
+
}
|
|
168
|
+
|
|
105
169
|
// Run post-install script if defined for this skill
|
|
106
170
|
if (POST_INSTALL_SCRIPTS[skillName]) {
|
|
107
171
|
const scriptPath = path.join(destPath, POST_INSTALL_SCRIPTS[skillName]);
|
|
@@ -114,6 +178,124 @@ function installSkill(skillName) {
|
|
|
114
178
|
}
|
|
115
179
|
}
|
|
116
180
|
}
|
|
181
|
+
|
|
182
|
+
if (!deferPackageDocs) {
|
|
183
|
+
installPackageDocs();
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function installHarnessAgents() {
|
|
188
|
+
installSkill('rules-workflow');
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function parseHarnessOptions(rawArgs) {
|
|
192
|
+
const options = { mode: 'warning' };
|
|
193
|
+
|
|
194
|
+
for (let index = 0; index < rawArgs.length; index += 1) {
|
|
195
|
+
const arg = rawArgs[index];
|
|
196
|
+
if (arg === '--strict') {
|
|
197
|
+
options.mode = 'blocking';
|
|
198
|
+
} else if (arg === '--mode') {
|
|
199
|
+
if (!rawArgs[index + 1]) {
|
|
200
|
+
throw new Error('--mode requires warning or blocking.');
|
|
201
|
+
}
|
|
202
|
+
options.mode = rawArgs[index + 1];
|
|
203
|
+
index += 1;
|
|
204
|
+
} else if (arg === '--backlog') {
|
|
205
|
+
if (!rawArgs[index + 1]) {
|
|
206
|
+
throw new Error('--backlog requires a file path.');
|
|
207
|
+
}
|
|
208
|
+
options.backlogPath = rawArgs[index + 1];
|
|
209
|
+
index += 1;
|
|
210
|
+
} else if (arg === '--json') {
|
|
211
|
+
options.json = true;
|
|
212
|
+
} else {
|
|
213
|
+
throw new Error(`Unknown option: ${arg}`);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
return options;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
function runHarnessCommand(stage, taskId, rawArgs) {
|
|
221
|
+
let options;
|
|
222
|
+
try {
|
|
223
|
+
options = parseHarnessOptions(rawArgs);
|
|
224
|
+
} catch (error) {
|
|
225
|
+
console.error(`Error: ${error.message}`);
|
|
226
|
+
process.exitCode = 2;
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
const result = checkHarnessTask({
|
|
231
|
+
stage,
|
|
232
|
+
taskId,
|
|
233
|
+
mode: options.mode,
|
|
234
|
+
backlogPath: options.backlogPath,
|
|
235
|
+
cwd: targetProjectRoot,
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
if (options.json) {
|
|
239
|
+
console.log(JSON.stringify(result, null, 2));
|
|
240
|
+
} else {
|
|
241
|
+
console.log(formatHarnessResult(result));
|
|
242
|
+
}
|
|
243
|
+
process.exitCode = getHarnessExitCode(result);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
function parseHarnessArtifactOptions(rawArgs) {
|
|
247
|
+
const options = { mode: 'warning' };
|
|
248
|
+
|
|
249
|
+
for (let index = 0; index < rawArgs.length; index += 1) {
|
|
250
|
+
const arg = rawArgs[index];
|
|
251
|
+
if (arg === '--strict') {
|
|
252
|
+
options.mode = 'blocking';
|
|
253
|
+
} else if (arg === '--mode') {
|
|
254
|
+
if (!rawArgs[index + 1]) {
|
|
255
|
+
throw new Error('--mode requires warning or blocking.');
|
|
256
|
+
}
|
|
257
|
+
options.mode = rawArgs[index + 1];
|
|
258
|
+
index += 1;
|
|
259
|
+
} else if (arg === '--manifest') {
|
|
260
|
+
if (!rawArgs[index + 1]) {
|
|
261
|
+
throw new Error('--manifest requires a file path.');
|
|
262
|
+
}
|
|
263
|
+
options.manifestPath = rawArgs[index + 1];
|
|
264
|
+
index += 1;
|
|
265
|
+
} else if (arg === '--json') {
|
|
266
|
+
options.json = true;
|
|
267
|
+
} else {
|
|
268
|
+
throw new Error(`Unknown option: ${arg}`);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
return options;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
function runHarnessArtifactCommand(artifactType, filePath, rawArgs) {
|
|
276
|
+
let options;
|
|
277
|
+
try {
|
|
278
|
+
options = parseHarnessArtifactOptions(rawArgs);
|
|
279
|
+
} catch (error) {
|
|
280
|
+
console.error(`Error: ${error.message}`);
|
|
281
|
+
process.exitCode = 2;
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
const result = checkHarnessArtifact({
|
|
286
|
+
artifactType,
|
|
287
|
+
filePath,
|
|
288
|
+
mode: options.mode,
|
|
289
|
+
manifestPath: options.manifestPath,
|
|
290
|
+
cwd: targetProjectRoot,
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
if (options.json) {
|
|
294
|
+
console.log(JSON.stringify(result, null, 2));
|
|
295
|
+
} else {
|
|
296
|
+
console.log(formatHarnessArtifactResult(result));
|
|
297
|
+
}
|
|
298
|
+
process.exitCode = getHarnessArtifactExitCode(result);
|
|
117
299
|
}
|
|
118
300
|
|
|
119
301
|
const args = process.argv.slice(2);
|
|
@@ -132,6 +314,8 @@ if (!command || command === 'list') {
|
|
|
132
314
|
installSkill('install-all');
|
|
133
315
|
} else if (subCommand === 'hooks' || subCommand === 'install-hooks') {
|
|
134
316
|
installHooks();
|
|
317
|
+
} else if (subCommand === 'agents' || subCommand === 'install-agents') {
|
|
318
|
+
installHarnessAgents();
|
|
135
319
|
} else {
|
|
136
320
|
installSkill(subCommand);
|
|
137
321
|
}
|
|
@@ -139,6 +323,17 @@ if (!command || command === 'list') {
|
|
|
139
323
|
installSkill('install-all');
|
|
140
324
|
} else if (command === 'install-hooks' || command === 'hooks') {
|
|
141
325
|
installHooks();
|
|
326
|
+
} else if (command === 'install-agents' || command === 'agents') {
|
|
327
|
+
installHarnessAgents();
|
|
328
|
+
} else if (command === 'preflight' || command === 'verify') {
|
|
329
|
+
if (!subCommand) {
|
|
330
|
+
console.error(`Error: ${command} requires a backlog task ID.`);
|
|
331
|
+
process.exitCode = 2;
|
|
332
|
+
} else {
|
|
333
|
+
runHarnessCommand(command, subCommand, args.slice(2));
|
|
334
|
+
}
|
|
335
|
+
} else if (command === 'validate-harness') {
|
|
336
|
+
runHarnessArtifactCommand(subCommand, args[2], args.slice(3));
|
|
142
337
|
} else {
|
|
143
338
|
console.log(`Unknown command: ${command}`);
|
|
144
339
|
listSkills();
|