@reactive-skills/runtime 0.1.0 → 0.1.1
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/README.md +2 -2
- package/dist/cli/dev.js +14 -10
- package/dist/cli/index.js +30 -20
- package/dist/core/event-store.js +81 -81
- package/dist/core/fsm-engine.d.ts +1 -0
- package/dist/core/fsm-engine.js +3 -0
- package/dist/core/migration.js +1 -1
- package/dist/mcp/server.js +33 -4
- package/dist/sync/cli.js +32 -32
- package/package.json +1 -1
package/README.md
CHANGED
package/dist/cli/dev.js
CHANGED
|
@@ -4,15 +4,15 @@ import path from 'node:path';
|
|
|
4
4
|
const args = process.argv.slice(2);
|
|
5
5
|
const command = args[0];
|
|
6
6
|
function printHelp() {
|
|
7
|
-
console.log(`
|
|
8
|
-
reactive-skills-dev: Developer CLI for Reactive Skills Architecture
|
|
9
|
-
|
|
10
|
-
Usage:
|
|
11
|
-
reactive-skills-dev init <name> Scaffold new reactive skill in skills/<name>/
|
|
12
|
-
reactive-skills-dev upgrade <path> Convert legacy SKILL.md to reactive format
|
|
13
|
-
reactive-skills-dev inspect <skill> Print statechart, transitions, and guards
|
|
14
|
-
reactive-skills-dev migrate [path] Retroactively migrate project to latest schema
|
|
15
|
-
reactive-skills-dev sync Sync skills to all agent config directories
|
|
7
|
+
console.log(`
|
|
8
|
+
reactive-skills-dev: Developer CLI for Reactive Skills Architecture
|
|
9
|
+
|
|
10
|
+
Usage:
|
|
11
|
+
reactive-skills-dev init <name> Scaffold new reactive skill in skills/<name>/
|
|
12
|
+
reactive-skills-dev upgrade <path> Convert legacy SKILL.md to reactive format
|
|
13
|
+
reactive-skills-dev inspect <skill> Print statechart, transitions, and guards
|
|
14
|
+
reactive-skills-dev migrate [path] Retroactively migrate project to latest schema
|
|
15
|
+
reactive-skills-dev sync Sync skills to all agent config directories
|
|
16
16
|
`);
|
|
17
17
|
}
|
|
18
18
|
async function main() {
|
|
@@ -53,7 +53,11 @@ async function main() {
|
|
|
53
53
|
}
|
|
54
54
|
// INSPECT
|
|
55
55
|
if (command === 'inspect') {
|
|
56
|
-
const skillPath = args[1] && !args[1].startsWith('--') ? args[1] : '
|
|
56
|
+
const skillPath = args[1] && !args[1].startsWith('--') ? args[1] : '';
|
|
57
|
+
if (!skillPath) {
|
|
58
|
+
console.error('Skill path required. Usage: reactive-skills-dev inspect <skill-path>');
|
|
59
|
+
process.exit(1);
|
|
60
|
+
}
|
|
57
61
|
const targetDir = path.resolve(process.cwd(), skillPath);
|
|
58
62
|
const { FSMEngine } = await import('../core/fsm-engine.js');
|
|
59
63
|
const engine = new FSMEngine({ skillDir: targetDir });
|
package/dist/cli/index.js
CHANGED
|
@@ -8,21 +8,21 @@ const args = process.argv.slice(2);
|
|
|
8
8
|
const command = args[0];
|
|
9
9
|
const isJson = args.includes('--json');
|
|
10
10
|
function printHelp() {
|
|
11
|
-
console.log(`
|
|
12
|
-
⚡ reactive-skills: Agent Experience Interface for Reactive Skills
|
|
13
|
-
|
|
14
|
-
Usage:
|
|
15
|
-
reactive-skills mcp Run the stdio Model Context Protocol (MCP) server
|
|
16
|
-
reactive-skills install <skill> Install skill globally and sync
|
|
17
|
-
reactive-skills migrate [path] Retroactively migrate project to latest schema
|
|
18
|
-
reactive-skills state [skill] Get active state slice and prompt
|
|
19
|
-
reactive-skills emit <signal> Emit signal and step state machine
|
|
20
|
-
reactive-skills query "<sql>" Query SQLite event store
|
|
21
|
-
reactive-skills inspect <skill> Inspect statechart and transitions
|
|
22
|
-
reactive-skills events [limit] Tail event store ledger
|
|
23
|
-
reactive-skills sync Sync skills across agent platforms
|
|
24
|
-
reactive-skills init <name> Scaffold new reactive skill
|
|
25
|
-
reactive-skills upgrade <path> Upgrade legacy SKILL.md
|
|
11
|
+
console.log(`
|
|
12
|
+
⚡ reactive-skills: Agent Experience Interface for Reactive Skills
|
|
13
|
+
|
|
14
|
+
Usage:
|
|
15
|
+
reactive-skills mcp Run the stdio Model Context Protocol (MCP) server
|
|
16
|
+
reactive-skills install <skill> Install skill globally and sync
|
|
17
|
+
reactive-skills migrate [path] Retroactively migrate project to latest schema
|
|
18
|
+
reactive-skills state [skill] Get active state slice and prompt
|
|
19
|
+
reactive-skills emit <signal> Emit signal and step state machine
|
|
20
|
+
reactive-skills query "<sql>" Query SQLite event store
|
|
21
|
+
reactive-skills inspect <skill> Inspect statechart and transitions
|
|
22
|
+
reactive-skills events [limit] Tail event store ledger
|
|
23
|
+
reactive-skills sync Sync skills across agent platforms
|
|
24
|
+
reactive-skills init <name> Scaffold new reactive skill
|
|
25
|
+
reactive-skills upgrade <path> Upgrade legacy SKILL.md
|
|
26
26
|
`);
|
|
27
27
|
}
|
|
28
28
|
async function main() {
|
|
@@ -97,7 +97,11 @@ async function main() {
|
|
|
97
97
|
}
|
|
98
98
|
// 2. GET ACTIVE STATE SLICE
|
|
99
99
|
if (command === 'state') {
|
|
100
|
-
const skillPath = args[1] && !args[1].startsWith('--') ? args[1] :
|
|
100
|
+
const skillPath = args[1] && !args[1].startsWith('--') ? args[1] : '';
|
|
101
|
+
if (!skillPath) {
|
|
102
|
+
console.error(JSON.stringify({ error: 'Skill path or name required. Usage: reactive-skills state <skill-path>' }));
|
|
103
|
+
process.exit(1);
|
|
104
|
+
}
|
|
101
105
|
const targetDir = path.resolve(process.cwd(), skillPath);
|
|
102
106
|
if (!fs.existsSync(targetDir)) {
|
|
103
107
|
console.error(JSON.stringify({ error: `Skill path not found: ${targetDir}` }));
|
|
@@ -120,9 +124,10 @@ async function main() {
|
|
|
120
124
|
if (command === 'emit') {
|
|
121
125
|
const signalName = args[1];
|
|
122
126
|
if (!signalName) {
|
|
123
|
-
console.error(JSON.stringify({ error: 'Signal name required. Usage: reactive-skills emit <SIGNAL> [--payload JSON]' }));
|
|
127
|
+
console.error(JSON.stringify({ error: 'Signal name required. Usage: reactive-skills emit <SIGNAL> [--skill path] [--payload JSON]' }));
|
|
124
128
|
process.exit(1);
|
|
125
129
|
}
|
|
130
|
+
const skillArg = args[2] && !args[2].startsWith('--') ? args[2] : (args.find(a => a.startsWith('--skill='))?.split('=')[1] || '');
|
|
126
131
|
let payload = {};
|
|
127
132
|
const payloadIdx = args.indexOf('--payload');
|
|
128
133
|
if (payloadIdx !== -1 && args[payloadIdx + 1]) {
|
|
@@ -133,8 +138,9 @@ async function main() {
|
|
|
133
138
|
payload = { raw: args[payloadIdx + 1] };
|
|
134
139
|
}
|
|
135
140
|
}
|
|
136
|
-
const skillPath = path.resolve(process.cwd(),
|
|
137
|
-
const
|
|
141
|
+
const skillPath = skillArg ? path.resolve(process.cwd(), skillArg) : process.cwd();
|
|
142
|
+
const skillId = path.basename(skillPath);
|
|
143
|
+
const store = new EventStore({ enableSqlite: true, skillId });
|
|
138
144
|
const engine = new FSMEngine({ skillDir: skillPath, eventStore: store });
|
|
139
145
|
const result = await engine.handleSignal(signalName, payload);
|
|
140
146
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -159,7 +165,11 @@ async function main() {
|
|
|
159
165
|
}
|
|
160
166
|
// 5. INSPECT SKILL
|
|
161
167
|
if (command === 'inspect') {
|
|
162
|
-
const skillPath = args[1] && !args[1].startsWith('--') ? args[1] : '
|
|
168
|
+
const skillPath = args[1] && !args[1].startsWith('--') ? args[1] : '';
|
|
169
|
+
if (!skillPath) {
|
|
170
|
+
console.error(JSON.stringify({ error: 'Skill path required. Usage: reactive-skills inspect <skill-path>' }));
|
|
171
|
+
process.exit(1);
|
|
172
|
+
}
|
|
163
173
|
const targetDir = path.resolve(process.cwd(), skillPath);
|
|
164
174
|
const engine = new FSMEngine({ skillDir: targetDir });
|
|
165
175
|
const manifest = engine.getManifest();
|
package/dist/core/event-store.js
CHANGED
|
@@ -33,60 +33,60 @@ export class SQLiteStorageDriver {
|
|
|
33
33
|
this.initTables();
|
|
34
34
|
}
|
|
35
35
|
initTables() {
|
|
36
|
-
this.db.exec(`
|
|
37
|
-
CREATE TABLE IF NOT EXISTS events (
|
|
38
|
-
id TEXT PRIMARY KEY,
|
|
39
|
-
event_id TEXT,
|
|
40
|
-
seq INTEGER NOT NULL,
|
|
41
|
-
timestamp TEXT NOT NULL,
|
|
42
|
-
occurred_at TEXT,
|
|
43
|
-
type TEXT NOT NULL,
|
|
44
|
-
event_type TEXT,
|
|
45
|
-
state TEXT,
|
|
46
|
-
source TEXT,
|
|
47
|
-
causation_id TEXT,
|
|
48
|
-
correlation_id TEXT,
|
|
49
|
-
request_id TEXT,
|
|
50
|
-
trace_parent TEXT,
|
|
51
|
-
skill_id TEXT,
|
|
52
|
-
run_id TEXT,
|
|
53
|
-
parent_run_id TEXT,
|
|
54
|
-
schema_version TEXT,
|
|
55
|
-
payload TEXT NOT NULL
|
|
56
|
-
);
|
|
57
|
-
CREATE INDEX IF NOT EXISTS idx_events_seq ON events(seq);
|
|
58
|
-
CREATE INDEX IF NOT EXISTS idx_events_type ON events(type);
|
|
59
|
-
CREATE INDEX IF NOT EXISTS idx_events_state ON events(state);
|
|
60
|
-
|
|
61
|
-
CREATE TABLE IF NOT EXISTS projections (
|
|
62
|
-
name TEXT PRIMARY KEY,
|
|
63
|
-
content TEXT NOT NULL,
|
|
64
|
-
updated_at TEXT NOT NULL
|
|
65
|
-
);
|
|
66
|
-
|
|
67
|
-
CREATE TABLE IF NOT EXISTS state_snapshots (
|
|
68
|
-
seq INTEGER PRIMARY KEY,
|
|
69
|
-
state TEXT NOT NULL,
|
|
70
|
-
context TEXT NOT NULL,
|
|
71
|
-
created_at TEXT NOT NULL
|
|
72
|
-
);
|
|
73
|
-
|
|
74
|
-
CREATE TABLE IF NOT EXISTS projection_watermarks (
|
|
75
|
-
name TEXT PRIMARY KEY,
|
|
76
|
-
event_seq INTEGER NOT NULL,
|
|
77
|
-
projection_version TEXT NOT NULL,
|
|
78
|
-
updated_at TEXT NOT NULL
|
|
79
|
-
);
|
|
80
|
-
CREATE TABLE IF NOT EXISTS schema_version (
|
|
81
|
-
version INTEGER PRIMARY KEY,
|
|
82
|
-
applied_at TEXT NOT NULL
|
|
83
|
-
);
|
|
84
|
-
CREATE TABLE IF NOT EXISTS seq_counter (
|
|
85
|
-
id INTEGER PRIMARY KEY,
|
|
86
|
-
last_seq INTEGER NOT NULL
|
|
87
|
-
);
|
|
88
|
-
INSERT OR IGNORE INTO seq_counter (id, last_seq) VALUES (1, 0);
|
|
89
|
-
INSERT OR IGNORE INTO schema_version (version, applied_at) VALUES (2, datetime('now'));
|
|
36
|
+
this.db.exec(`
|
|
37
|
+
CREATE TABLE IF NOT EXISTS events (
|
|
38
|
+
id TEXT PRIMARY KEY,
|
|
39
|
+
event_id TEXT,
|
|
40
|
+
seq INTEGER NOT NULL,
|
|
41
|
+
timestamp TEXT NOT NULL,
|
|
42
|
+
occurred_at TEXT,
|
|
43
|
+
type TEXT NOT NULL,
|
|
44
|
+
event_type TEXT,
|
|
45
|
+
state TEXT,
|
|
46
|
+
source TEXT,
|
|
47
|
+
causation_id TEXT,
|
|
48
|
+
correlation_id TEXT,
|
|
49
|
+
request_id TEXT,
|
|
50
|
+
trace_parent TEXT,
|
|
51
|
+
skill_id TEXT,
|
|
52
|
+
run_id TEXT,
|
|
53
|
+
parent_run_id TEXT,
|
|
54
|
+
schema_version TEXT,
|
|
55
|
+
payload TEXT NOT NULL
|
|
56
|
+
);
|
|
57
|
+
CREATE INDEX IF NOT EXISTS idx_events_seq ON events(seq);
|
|
58
|
+
CREATE INDEX IF NOT EXISTS idx_events_type ON events(type);
|
|
59
|
+
CREATE INDEX IF NOT EXISTS idx_events_state ON events(state);
|
|
60
|
+
|
|
61
|
+
CREATE TABLE IF NOT EXISTS projections (
|
|
62
|
+
name TEXT PRIMARY KEY,
|
|
63
|
+
content TEXT NOT NULL,
|
|
64
|
+
updated_at TEXT NOT NULL
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
CREATE TABLE IF NOT EXISTS state_snapshots (
|
|
68
|
+
seq INTEGER PRIMARY KEY,
|
|
69
|
+
state TEXT NOT NULL,
|
|
70
|
+
context TEXT NOT NULL,
|
|
71
|
+
created_at TEXT NOT NULL
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
CREATE TABLE IF NOT EXISTS projection_watermarks (
|
|
75
|
+
name TEXT PRIMARY KEY,
|
|
76
|
+
event_seq INTEGER NOT NULL,
|
|
77
|
+
projection_version TEXT NOT NULL,
|
|
78
|
+
updated_at TEXT NOT NULL
|
|
79
|
+
);
|
|
80
|
+
CREATE TABLE IF NOT EXISTS schema_version (
|
|
81
|
+
version INTEGER PRIMARY KEY,
|
|
82
|
+
applied_at TEXT NOT NULL
|
|
83
|
+
);
|
|
84
|
+
CREATE TABLE IF NOT EXISTS seq_counter (
|
|
85
|
+
id INTEGER PRIMARY KEY,
|
|
86
|
+
last_seq INTEGER NOT NULL
|
|
87
|
+
);
|
|
88
|
+
INSERT OR IGNORE INTO seq_counter (id, last_seq) VALUES (1, 0);
|
|
89
|
+
INSERT OR IGNORE INTO schema_version (version, applied_at) VALUES (2, datetime('now'));
|
|
90
90
|
`);
|
|
91
91
|
this.ensureSchemaVersion();
|
|
92
92
|
}
|
|
@@ -125,9 +125,9 @@ export class SQLiteStorageDriver {
|
|
|
125
125
|
}
|
|
126
126
|
}
|
|
127
127
|
insertEvent(event) {
|
|
128
|
-
const stmt = this.db.prepare(`
|
|
129
|
-
INSERT INTO events (id, event_id, seq, timestamp, occurred_at, type, event_type, state, source, causation_id, correlation_id, request_id, trace_parent, skill_id, run_id, parent_run_id, schema_version, payload)
|
|
130
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
128
|
+
const stmt = this.db.prepare(`
|
|
129
|
+
INSERT INTO events (id, event_id, seq, timestamp, occurred_at, type, event_type, state, source, causation_id, correlation_id, request_id, trace_parent, skill_id, run_id, parent_run_id, schema_version, payload)
|
|
130
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
131
131
|
`);
|
|
132
132
|
stmt.run(event.id, event.event_id || event.id, event.seq, event.timestamp, event.occurred_at || event.timestamp, event.type, event.event_type || event.type, event.state || null, event.source || null, event.causation_id || event.causationId || null, event.correlation_id || null, event.request_id || null, event.trace_parent || null, event.skill_id || null, event.run_id || null, event.parent_run_id || null, event.schema_version || null, JSON.stringify(event.payload));
|
|
133
133
|
}
|
|
@@ -189,15 +189,15 @@ export class SQLiteStorageDriver {
|
|
|
189
189
|
return stmt.all(...params);
|
|
190
190
|
}
|
|
191
191
|
saveSnapshot(seq, state, context) {
|
|
192
|
-
const stmt = this.db.prepare(`
|
|
193
|
-
INSERT OR REPLACE INTO state_snapshots (seq, state, context, created_at)
|
|
194
|
-
VALUES (?, ?, ?, ?)
|
|
192
|
+
const stmt = this.db.prepare(`
|
|
193
|
+
INSERT OR REPLACE INTO state_snapshots (seq, state, context, created_at)
|
|
194
|
+
VALUES (?, ?, ?, ?)
|
|
195
195
|
`);
|
|
196
196
|
stmt.run(seq, state, JSON.stringify(context), new Date().toISOString());
|
|
197
197
|
}
|
|
198
198
|
getLatestSnapshot() {
|
|
199
|
-
const stmt = this.db.prepare(`
|
|
200
|
-
SELECT * FROM state_snapshots ORDER BY seq DESC LIMIT 1
|
|
199
|
+
const stmt = this.db.prepare(`
|
|
200
|
+
SELECT * FROM state_snapshots ORDER BY seq DESC LIMIT 1
|
|
201
201
|
`);
|
|
202
202
|
const row = stmt.get();
|
|
203
203
|
if (!row)
|
|
@@ -209,9 +209,9 @@ export class SQLiteStorageDriver {
|
|
|
209
209
|
};
|
|
210
210
|
}
|
|
211
211
|
saveProjectionWatermark(name, eventSeq, projectionVersion) {
|
|
212
|
-
const stmt = this.db.prepare(`
|
|
213
|
-
INSERT OR REPLACE INTO projection_watermarks (name, event_seq, projection_version, updated_at)
|
|
214
|
-
VALUES (?, ?, ?, ?)
|
|
212
|
+
const stmt = this.db.prepare(`
|
|
213
|
+
INSERT OR REPLACE INTO projection_watermarks (name, event_seq, projection_version, updated_at)
|
|
214
|
+
VALUES (?, ?, ?, ?)
|
|
215
215
|
`);
|
|
216
216
|
stmt.run(name, eventSeq, projectionVersion, new Date().toISOString());
|
|
217
217
|
}
|
|
@@ -223,15 +223,15 @@ export class SQLiteStorageDriver {
|
|
|
223
223
|
: null;
|
|
224
224
|
}
|
|
225
225
|
saveProjection(name, content) {
|
|
226
|
-
const stmt = this.db.prepare(`
|
|
227
|
-
INSERT OR REPLACE INTO projections (name, content, updated_at)
|
|
228
|
-
VALUES (?, ?, ?)
|
|
226
|
+
const stmt = this.db.prepare(`
|
|
227
|
+
INSERT OR REPLACE INTO projections (name, content, updated_at)
|
|
228
|
+
VALUES (?, ?, ?)
|
|
229
229
|
`);
|
|
230
230
|
stmt.run(name, content, new Date().toISOString());
|
|
231
231
|
}
|
|
232
232
|
getProjection(name) {
|
|
233
|
-
const stmt = this.db.prepare(`
|
|
234
|
-
SELECT content FROM projections WHERE name = ?
|
|
233
|
+
const stmt = this.db.prepare(`
|
|
234
|
+
SELECT content FROM projections WHERE name = ?
|
|
235
235
|
`);
|
|
236
236
|
const row = stmt.get(name);
|
|
237
237
|
return row ? row.content : null;
|
|
@@ -270,11 +270,11 @@ export class SQLiteStorageDriver {
|
|
|
270
270
|
};
|
|
271
271
|
}
|
|
272
272
|
clear() {
|
|
273
|
-
this.db.exec(`
|
|
274
|
-
DELETE FROM events;
|
|
275
|
-
DELETE FROM projections;
|
|
276
|
-
DELETE FROM state_snapshots;
|
|
277
|
-
DELETE FROM projection_watermarks;
|
|
273
|
+
this.db.exec(`
|
|
274
|
+
DELETE FROM events;
|
|
275
|
+
DELETE FROM projections;
|
|
276
|
+
DELETE FROM state_snapshots;
|
|
277
|
+
DELETE FROM projection_watermarks;
|
|
278
278
|
`);
|
|
279
279
|
}
|
|
280
280
|
/**
|
|
@@ -282,12 +282,12 @@ export class SQLiteStorageDriver {
|
|
|
282
282
|
* clean slate. Used by EventStore.rebuildFromJsonl().
|
|
283
283
|
*/
|
|
284
284
|
clearAll() {
|
|
285
|
-
this.db.exec(`
|
|
286
|
-
DELETE FROM events;
|
|
287
|
-
DELETE FROM projections;
|
|
288
|
-
DELETE FROM state_snapshots;
|
|
289
|
-
DELETE FROM projection_watermarks;
|
|
290
|
-
DELETE FROM seq_counter;
|
|
285
|
+
this.db.exec(`
|
|
286
|
+
DELETE FROM events;
|
|
287
|
+
DELETE FROM projections;
|
|
288
|
+
DELETE FROM state_snapshots;
|
|
289
|
+
DELETE FROM projection_watermarks;
|
|
290
|
+
DELETE FROM seq_counter;
|
|
291
291
|
`);
|
|
292
292
|
this.db.exec(`INSERT OR IGNORE INTO seq_counter (id, last_seq) VALUES (1, 0)`);
|
|
293
293
|
}
|
|
@@ -35,6 +35,7 @@ export declare class FSMEngine {
|
|
|
35
35
|
getActiveStatePath(): string[];
|
|
36
36
|
getContext(): Record<string, any>;
|
|
37
37
|
updateContext(updates: Record<string, any>): void;
|
|
38
|
+
getSkillDir(): string;
|
|
38
39
|
getEventStore(): EventStore;
|
|
39
40
|
getEventContext(): EventContext;
|
|
40
41
|
isStrictExecution(): boolean;
|
package/dist/core/fsm-engine.js
CHANGED
package/dist/core/migration.js
CHANGED
|
@@ -13,7 +13,7 @@ export class ProjectMigrator {
|
|
|
13
13
|
if (!fs.existsSync(absDir)) {
|
|
14
14
|
throw new Error(`Target project directory does not exist: ${absDir}`);
|
|
15
15
|
}
|
|
16
|
-
const docsDir = path.join(absDir, '.docs'
|
|
16
|
+
const docsDir = path.join(absDir, '.docs');
|
|
17
17
|
if (!fs.existsSync(docsDir)) {
|
|
18
18
|
fs.mkdirSync(docsDir, { recursive: true });
|
|
19
19
|
}
|
package/dist/mcp/server.js
CHANGED
|
@@ -10,7 +10,7 @@ import { EventStore } from '../core/event-store.js';
|
|
|
10
10
|
import { SkillManifestSchema } from '../core/types.js';
|
|
11
11
|
export function createReactiveMcpServer(options = {}) {
|
|
12
12
|
const workspaceDir = options.workspaceDir || process.cwd();
|
|
13
|
-
let defaultSkill = options.defaultSkill || '
|
|
13
|
+
let defaultSkill = options.defaultSkill || 'test-fsm';
|
|
14
14
|
const server = new McpServer({
|
|
15
15
|
name: 'reactive-skills-server',
|
|
16
16
|
version: '1.0.0',
|
|
@@ -29,15 +29,45 @@ export function createReactiveMcpServer(options = {}) {
|
|
|
29
29
|
}
|
|
30
30
|
function getEngine(skillName = defaultSkill) {
|
|
31
31
|
if (engines.has(skillName)) {
|
|
32
|
-
|
|
32
|
+
const cached = engines.get(skillName);
|
|
33
|
+
if (fs.existsSync(cached.getSkillDir())) {
|
|
34
|
+
return cached;
|
|
35
|
+
}
|
|
36
|
+
engines.delete(skillName);
|
|
33
37
|
}
|
|
34
38
|
const candidatePaths = [
|
|
35
39
|
path.resolve(workspaceDir, 'skills', skillName),
|
|
40
|
+
path.resolve(workspaceDir, 'skills', `_${skillName}_skill`),
|
|
36
41
|
path.resolve(workspaceDir, skillName),
|
|
42
|
+
path.resolve(workspaceDir, '..', 'skills', skillName),
|
|
37
43
|
path.join(os.homedir(), '.agents', 'skills', skillName),
|
|
38
44
|
path.join(os.homedir(), '.gemini', 'config', 'skills', skillName),
|
|
45
|
+
path.join(os.homedir(), '.kilocode', 'skills', skillName),
|
|
39
46
|
];
|
|
40
|
-
|
|
47
|
+
let skillDir = candidatePaths.find(p => fs.existsSync(p));
|
|
48
|
+
if (!skillDir) {
|
|
49
|
+
const skillsRoot = path.resolve(workspaceDir, 'skills');
|
|
50
|
+
if (fs.existsSync(skillsRoot)) {
|
|
51
|
+
for (const entry of fs.readdirSync(skillsRoot, { withFileTypes: true })) {
|
|
52
|
+
if (entry.isDirectory()) {
|
|
53
|
+
const cand = path.join(skillsRoot, entry.name);
|
|
54
|
+
const yamlFile = path.join(cand, 'skill.yaml');
|
|
55
|
+
if (fs.existsSync(yamlFile)) {
|
|
56
|
+
try {
|
|
57
|
+
const parsed = yaml.load(fs.readFileSync(yamlFile, 'utf8'));
|
|
58
|
+
if (parsed?.name === skillName) {
|
|
59
|
+
skillDir = cand;
|
|
60
|
+
break;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
// ignore
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
41
71
|
if (!skillDir) {
|
|
42
72
|
throw new Error(`Skill '${skillName}' not found in workspace or global registry.`);
|
|
43
73
|
}
|
|
@@ -427,7 +457,6 @@ export function createReactiveMcpServer(options = {}) {
|
|
|
427
457
|
};
|
|
428
458
|
}
|
|
429
459
|
const docCandidates = [
|
|
430
|
-
path.resolve(workspaceDir, '.docs', 'synthesis', `${safeName}.md`),
|
|
431
460
|
path.resolve(workspaceDir, '.docs', `${safeName}.md`),
|
|
432
461
|
path.resolve(workspaceDir, `${safeName}.md`),
|
|
433
462
|
];
|
package/dist/sync/cli.js
CHANGED
|
@@ -61,38 +61,38 @@ function parseArgs(args) {
|
|
|
61
61
|
return result;
|
|
62
62
|
}
|
|
63
63
|
function printHelp() {
|
|
64
|
-
console.log(`
|
|
65
|
-
reactive-skills sync-engine: Locked mirror/PUT skill synchronization
|
|
66
|
-
|
|
67
|
-
Usage:
|
|
68
|
-
reactive-skills sync-engine [source] [targets...] [flags]
|
|
69
|
-
|
|
70
|
-
Arguments:
|
|
71
|
-
source Source skills directory (default: ~/.agents/skills)
|
|
72
|
-
target One or more target directories (default: all known satellites)
|
|
73
|
-
|
|
74
|
-
Flags:
|
|
75
|
-
--source, -s <dir> Source skills directory
|
|
76
|
-
--target, -t <dir> Add a target directory (repeatable)
|
|
77
|
-
--skill <name> Sync a specific skill only
|
|
78
|
-
--dry-run Preview changes without writing
|
|
79
|
-
--mirror Mirror mode (default, only supported mode): destination
|
|
80
|
-
becomes identical to source distributable payload
|
|
81
|
-
--force Accepted but no-op (mirror is the only mode)
|
|
82
|
-
--no-backup Skip timestamped backup before overwrite
|
|
83
|
-
--json Machine-readable JSON output
|
|
84
|
-
--help, -h Show this help
|
|
85
|
-
|
|
86
|
-
Satellites (default targets):
|
|
87
|
-
~/.agents/skills
|
|
88
|
-
~/.claude/skills
|
|
89
|
-
~/.codex/skills
|
|
90
|
-
~/.gemini/config/skills
|
|
91
|
-
~/.pi/skills
|
|
92
|
-
~/.kilocode/skills
|
|
93
|
-
~/.copilot/skills
|
|
94
|
-
~/.hermes/skills
|
|
95
|
-
~/.crew/skills
|
|
64
|
+
console.log(`
|
|
65
|
+
reactive-skills sync-engine: Locked mirror/PUT skill synchronization
|
|
66
|
+
|
|
67
|
+
Usage:
|
|
68
|
+
reactive-skills sync-engine [source] [targets...] [flags]
|
|
69
|
+
|
|
70
|
+
Arguments:
|
|
71
|
+
source Source skills directory (default: ~/.agents/skills)
|
|
72
|
+
target One or more target directories (default: all known satellites)
|
|
73
|
+
|
|
74
|
+
Flags:
|
|
75
|
+
--source, -s <dir> Source skills directory
|
|
76
|
+
--target, -t <dir> Add a target directory (repeatable)
|
|
77
|
+
--skill <name> Sync a specific skill only
|
|
78
|
+
--dry-run Preview changes without writing
|
|
79
|
+
--mirror Mirror mode (default, only supported mode): destination
|
|
80
|
+
becomes identical to source distributable payload
|
|
81
|
+
--force Accepted but no-op (mirror is the only mode)
|
|
82
|
+
--no-backup Skip timestamped backup before overwrite
|
|
83
|
+
--json Machine-readable JSON output
|
|
84
|
+
--help, -h Show this help
|
|
85
|
+
|
|
86
|
+
Satellites (default targets):
|
|
87
|
+
~/.agents/skills
|
|
88
|
+
~/.claude/skills
|
|
89
|
+
~/.codex/skills
|
|
90
|
+
~/.gemini/config/skills
|
|
91
|
+
~/.pi/skills
|
|
92
|
+
~/.kilocode/skills
|
|
93
|
+
~/.copilot/skills
|
|
94
|
+
~/.hermes/skills
|
|
95
|
+
~/.crew/skills
|
|
96
96
|
`);
|
|
97
97
|
}
|
|
98
98
|
function defaultTargets() {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reactive-skills/runtime",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Reactive Skills Architecture (RSA) core runtime — FSM engine, event store, guard evaluator, projection engine, MCP server",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|