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.
Files changed (36) hide show
  1. package/AGENTS.md +11 -0
  2. package/CLAUDE.md +13 -3
  3. package/README.md +135 -286
  4. package/USAGE.md +893 -0
  5. package/bin/cli.js +198 -3
  6. package/bin/harness-artifact.js +621 -0
  7. package/bin/harness-artifact.test.js +520 -0
  8. package/bin/harness-check.js +373 -0
  9. package/bin/harness-check.test.js +159 -0
  10. package/bin/test.js +2 -0
  11. package/docs/01_Concept_Design/01_AGENT_HARNESS_REQUIREMENTS_ANALYSIS.md +162 -0
  12. package/docs/03_Technical_Specs/01_AGENT_HARNESS_ARCHITECTURE.md +376 -0
  13. package/docs/03_Technical_Specs/assets/01_agent_harness_data_flow.svg +94 -0
  14. package/docs/04_Logic_Progress/00_BACKLOG.md +339 -0
  15. package/docs/04_Logic_Progress/01_EXECUTION_PLAN.md +160 -0
  16. package/docs/04_Logic_Progress/03_DECISION_LOG.md +98 -0
  17. package/docs/05_QA_Validation/01_TEST_SCENARIOS.md +313 -0
  18. package/docs/05_QA_Validation/02_AGENT_HARNESS_DESIGN_REVIEW.md +100 -0
  19. package/docs/05_QA_Validation/03_AGENT_HARNESS_CONTRACT_QA.md +96 -0
  20. package/manage-collaboration/SKILL.md +2 -0
  21. package/package.json +6 -4
  22. package/rules-docs/SKILL.md +15 -1
  23. package/rules-product/SKILL.md +37 -6
  24. package/rules-product/agents/openai.yaml +2 -2
  25. package/rules-workflow/SKILL.md +38 -6
  26. package/rules-workflow/adapters/claude/solmate-context-reader.md +17 -0
  27. package/rules-workflow/adapters/claude/solmate-implementer.md +20 -0
  28. package/rules-workflow/adapters/claude/solmate-verifier.md +21 -0
  29. package/rules-workflow/agents/openai.yaml +2 -2
  30. package/rules-workflow/resources/agent-harness-contract.md +187 -0
  31. package/rules-workflow/resources/agent-harness-v1.schema.json +432 -0
  32. package/verify-docs/SKILL.md +33 -6
  33. package/verify-docs/agents/openai.yaml +2 -2
  34. package/verify-implementation/SKILL.md +21 -2
  35. package/verify-implementation/agents/openai.yaml +2 -2
  36. 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('\nUsage: npx solmate-skills install <skill-name> | all | hooks\n');
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();