solmate-skills 2.0.12 → 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 +9 -0
- package/CLAUDE.md +13 -3
- package/README.md +91 -5
- package/USAGE.md +118 -12
- package/bin/cli.js +171 -1
- 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 +30 -6
- package/rules-product/agents/openai.yaml +2 -2
- package/rules-workflow/SKILL.md +32 -7
- 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 +14 -2
- package/verify-implementation/agents/openai.yaml +2 -2
- package/verify-skills/SKILL.md +27 -0
package/bin/cli.js
CHANGED
|
@@ -3,6 +3,16 @@
|
|
|
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'];
|
|
@@ -19,6 +29,8 @@ const POST_INSTALL_SCRIPTS = {
|
|
|
19
29
|
const packageRoot = path.join(__dirname, '..');
|
|
20
30
|
const targetProjectRoot = process.cwd();
|
|
21
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');
|
|
22
34
|
|
|
23
35
|
function getAvailableSkills() {
|
|
24
36
|
return fs.readdirSync(packageRoot, { withFileTypes: true })
|
|
@@ -61,13 +73,40 @@ function copyFolderSync(from, to) {
|
|
|
61
73
|
});
|
|
62
74
|
}
|
|
63
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
|
+
|
|
64
97
|
function listSkills() {
|
|
65
98
|
const skills = getAvailableSkills();
|
|
66
99
|
console.log('\nAvailable skills to install:');
|
|
67
100
|
skills.forEach(skill => console.log(` - ${skill}`));
|
|
68
101
|
console.log('\nUtilities:');
|
|
69
102
|
console.log(' - hooks (install with: npx solmate-skills install hooks)');
|
|
70
|
-
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');
|
|
71
110
|
}
|
|
72
111
|
|
|
73
112
|
function installHooks() {
|
|
@@ -123,6 +162,10 @@ function installSkill(skillName, options = {}) {
|
|
|
123
162
|
copyFolderSync(sourcePath, destPath);
|
|
124
163
|
console.log(`Successfully installed ${skillName} to .agent/skills/${skillName}`);
|
|
125
164
|
|
|
165
|
+
if (skillName === 'rules-workflow') {
|
|
166
|
+
installAgentAdapters();
|
|
167
|
+
}
|
|
168
|
+
|
|
126
169
|
// Run post-install script if defined for this skill
|
|
127
170
|
if (POST_INSTALL_SCRIPTS[skillName]) {
|
|
128
171
|
const scriptPath = path.join(destPath, POST_INSTALL_SCRIPTS[skillName]);
|
|
@@ -141,6 +184,120 @@ function installSkill(skillName, options = {}) {
|
|
|
141
184
|
}
|
|
142
185
|
}
|
|
143
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);
|
|
299
|
+
}
|
|
300
|
+
|
|
144
301
|
const args = process.argv.slice(2);
|
|
145
302
|
const command = args[0];
|
|
146
303
|
const subCommand = args[1];
|
|
@@ -157,6 +314,8 @@ if (!command || command === 'list') {
|
|
|
157
314
|
installSkill('install-all');
|
|
158
315
|
} else if (subCommand === 'hooks' || subCommand === 'install-hooks') {
|
|
159
316
|
installHooks();
|
|
317
|
+
} else if (subCommand === 'agents' || subCommand === 'install-agents') {
|
|
318
|
+
installHarnessAgents();
|
|
160
319
|
} else {
|
|
161
320
|
installSkill(subCommand);
|
|
162
321
|
}
|
|
@@ -164,6 +323,17 @@ if (!command || command === 'list') {
|
|
|
164
323
|
installSkill('install-all');
|
|
165
324
|
} else if (command === 'install-hooks' || command === 'hooks') {
|
|
166
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));
|
|
167
337
|
} else {
|
|
168
338
|
console.log(`Unknown command: ${command}`);
|
|
169
339
|
listSkills();
|