@medicine-wheel/app 0.2.6 → 0.2.8
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/dist/cli/mw.js +27 -0
- package/dist/cli/mwsrv.js +35 -1
- package/dist/cli/skills.js +356 -0
- package/package.json +18 -18
package/dist/cli/mw.js
CHANGED
|
@@ -45,6 +45,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
45
45
|
const child_process_1 = require("child_process");
|
|
46
46
|
const path = __importStar(require("path"));
|
|
47
47
|
const fs = __importStar(require("fs"));
|
|
48
|
+
const skills_1 = require("./skills");
|
|
48
49
|
// ── Config ────────────────────────────────────────────────────────
|
|
49
50
|
const MW_API_URL = process.env.MW_API_URL ?? 'http://localhost:3940';
|
|
50
51
|
const MW_FORMAT = process.env.MW_FORMAT ?? 'pretty';
|
|
@@ -254,6 +255,10 @@ ${C.bold}🌿 mw — Medicine Wheel CLI${C.reset}
|
|
|
254
255
|
mw validate accountability <plan_json> Accountability audit
|
|
255
256
|
mw validate bridge <concept> [dir] Two-Eyed Seeing bridge
|
|
256
257
|
|
|
258
|
+
SKILLS
|
|
259
|
+
mw skill view List available CLI skills
|
|
260
|
+
mw skill install [name] Install a skill (or all)
|
|
261
|
+
|
|
257
262
|
MEMORY
|
|
258
263
|
mw memory store <key> <value> [dir] Store relational memory
|
|
259
264
|
|
|
@@ -632,6 +637,24 @@ function cmdValidate(positional) {
|
|
|
632
637
|
console.error(`Unknown validate sub-command: ${sub}`);
|
|
633
638
|
}
|
|
634
639
|
}
|
|
640
|
+
// ── Skill ─────────────────────────────────────────────────────────
|
|
641
|
+
function cmdSkill(positional) {
|
|
642
|
+
const sub = positional[0] ?? 'view';
|
|
643
|
+
switch (sub) {
|
|
644
|
+
case 'view':
|
|
645
|
+
case 'list':
|
|
646
|
+
(0, skills_1.viewSkills)('cli', C);
|
|
647
|
+
break;
|
|
648
|
+
case 'install': {
|
|
649
|
+
const name = positional[1]; // undefined means install all
|
|
650
|
+
(0, skills_1.installSkill)('cli', name, C);
|
|
651
|
+
break;
|
|
652
|
+
}
|
|
653
|
+
default:
|
|
654
|
+
console.error(`Unknown skill sub-command: ${sub}`);
|
|
655
|
+
console.error("Available: view, install");
|
|
656
|
+
}
|
|
657
|
+
}
|
|
635
658
|
// ── Memory ────────────────────────────────────────────────────────
|
|
636
659
|
function cmdMemory(positional) {
|
|
637
660
|
const sub = positional[0] ?? 'store';
|
|
@@ -716,6 +739,10 @@ async function main() {
|
|
|
716
739
|
case 'mem':
|
|
717
740
|
cmdMemory(rest);
|
|
718
741
|
break;
|
|
742
|
+
case 'skill':
|
|
743
|
+
case 'sk':
|
|
744
|
+
cmdSkill(rest);
|
|
745
|
+
break;
|
|
719
746
|
case 'arc':
|
|
720
747
|
mcpCall('get_narrative_arc', { cycle_id: rest[0] ?? '' });
|
|
721
748
|
break;
|
package/dist/cli/mwsrv.js
CHANGED
|
@@ -54,7 +54,15 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
54
54
|
const child_process_1 = require("child_process");
|
|
55
55
|
const path = __importStar(require("path"));
|
|
56
56
|
const fs = __importStar(require("fs"));
|
|
57
|
+
const skills_1 = require("./skills");
|
|
57
58
|
const DOCKER_IMAGE = 'jgwill/medicine-wheel:app';
|
|
59
|
+
const C = {
|
|
60
|
+
bold: '\x1b[1m',
|
|
61
|
+
dim: '\x1b[2m',
|
|
62
|
+
green: '\x1b[32m',
|
|
63
|
+
south: '\x1b[31m',
|
|
64
|
+
reset: '\x1b[0m',
|
|
65
|
+
};
|
|
58
66
|
const DEFAULT_PORT = 3940;
|
|
59
67
|
const CONTAINER_PORT = 3940;
|
|
60
68
|
function parseArgs(argv) {
|
|
@@ -195,6 +203,24 @@ function runLocal(opts) {
|
|
|
195
203
|
process.on('SIGTERM', shutdown);
|
|
196
204
|
proc.on('exit', (code) => process.exit(code ?? 0));
|
|
197
205
|
}
|
|
206
|
+
// ── Skill ─────────────────────────────────────────────────────────
|
|
207
|
+
function cmdSkill(positional) {
|
|
208
|
+
const sub = positional[0] ?? 'view';
|
|
209
|
+
switch (sub) {
|
|
210
|
+
case 'view':
|
|
211
|
+
case 'list':
|
|
212
|
+
(0, skills_1.viewSkills)('srv', C);
|
|
213
|
+
break;
|
|
214
|
+
case 'install': {
|
|
215
|
+
const name = positional[1]; // undefined means install all
|
|
216
|
+
(0, skills_1.installSkill)('srv', name, C);
|
|
217
|
+
break;
|
|
218
|
+
}
|
|
219
|
+
default:
|
|
220
|
+
console.error(`Unknown skill sub-command: ${sub}`);
|
|
221
|
+
console.error("Available: view, install");
|
|
222
|
+
}
|
|
223
|
+
}
|
|
198
224
|
// ── Help ──────────────────────────────────────────────────────────
|
|
199
225
|
function showHelp() {
|
|
200
226
|
console.log(`
|
|
@@ -215,6 +241,10 @@ OPTIONS
|
|
|
215
241
|
--no-open Do not auto-open browser
|
|
216
242
|
--help, -h Show this help
|
|
217
243
|
|
|
244
|
+
SKILLS
|
|
245
|
+
mwsrv skill view List available server skills
|
|
246
|
+
mwsrv skill install [name] Install a skill (or all)
|
|
247
|
+
|
|
218
248
|
EXAMPLES
|
|
219
249
|
# Start locally (uses current directory's .mw/store)
|
|
220
250
|
mwsrv
|
|
@@ -239,11 +269,15 @@ ENVIRONMENT
|
|
|
239
269
|
}
|
|
240
270
|
// ── Main ──────────────────────────────────────────────────────────
|
|
241
271
|
async function main() {
|
|
242
|
-
const { flags } = parseArgs(process.argv);
|
|
272
|
+
const { flags, positional } = parseArgs(process.argv);
|
|
243
273
|
if (flags['help'] || flags['h']) {
|
|
244
274
|
showHelp();
|
|
245
275
|
return;
|
|
246
276
|
}
|
|
277
|
+
if (positional[0] === 'skill' || positional[0] === 'sk') {
|
|
278
|
+
cmdSkill(positional.slice(1));
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
247
281
|
const port = Number(flags['port'] ?? flags['p'] ?? DEFAULT_PORT);
|
|
248
282
|
const directory = String(flags['directory'] ?? flags['D'] ?? process.cwd());
|
|
249
283
|
const useDocker = Boolean(flags['docker']);
|
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Shared skill registry and management for Medicine Wheel CLIs.
|
|
4
|
+
*
|
|
5
|
+
* Skills are curated capabilities that can be installed into a local
|
|
6
|
+
* `.mw/skills/` directory. Each CLI (mw, mwsrv) exposes its own
|
|
7
|
+
* relevant subset via `skill view` and `skill install`.
|
|
8
|
+
*/
|
|
9
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
12
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
13
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
14
|
+
}
|
|
15
|
+
Object.defineProperty(o, k2, desc);
|
|
16
|
+
}) : (function(o, m, k, k2) {
|
|
17
|
+
if (k2 === undefined) k2 = k;
|
|
18
|
+
o[k2] = m[k];
|
|
19
|
+
}));
|
|
20
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
21
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
22
|
+
}) : function(o, v) {
|
|
23
|
+
o["default"] = v;
|
|
24
|
+
});
|
|
25
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
26
|
+
var ownKeys = function(o) {
|
|
27
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
28
|
+
var ar = [];
|
|
29
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
30
|
+
return ar;
|
|
31
|
+
};
|
|
32
|
+
return ownKeys(o);
|
|
33
|
+
};
|
|
34
|
+
return function (mod) {
|
|
35
|
+
if (mod && mod.__esModule) return mod;
|
|
36
|
+
var result = {};
|
|
37
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
38
|
+
__setModuleDefault(result, mod);
|
|
39
|
+
return result;
|
|
40
|
+
};
|
|
41
|
+
})();
|
|
42
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
43
|
+
exports.listSkills = listSkills;
|
|
44
|
+
exports.getSkill = getSkill;
|
|
45
|
+
exports.getComplement = getComplement;
|
|
46
|
+
exports.viewSkills = viewSkills;
|
|
47
|
+
exports.installSkill = installSkill;
|
|
48
|
+
const fs = __importStar(require("fs"));
|
|
49
|
+
const path = __importStar(require("path"));
|
|
50
|
+
// ── Built-in skill catalog ───────────────────────────────────────
|
|
51
|
+
const SKILLS = [
|
|
52
|
+
// ── CLI skills (mw) ────────────────────────────────────────────
|
|
53
|
+
{
|
|
54
|
+
name: 'direction-inquiry',
|
|
55
|
+
title: 'Direction Inquiry',
|
|
56
|
+
description: 'Analyze tasks through the Four Directions (East / South / West / North)',
|
|
57
|
+
target: 'cli',
|
|
58
|
+
complement: 'api-health',
|
|
59
|
+
body: `# Skill: Direction Inquiry
|
|
60
|
+
|
|
61
|
+
## Purpose
|
|
62
|
+
Analyze an engineering task using the Four Directions framework.
|
|
63
|
+
|
|
64
|
+
## Input
|
|
65
|
+
- Engineering task description
|
|
66
|
+
- Optional: constraints, repo paths
|
|
67
|
+
|
|
68
|
+
## Output
|
|
69
|
+
- **East** — vision statement
|
|
70
|
+
- **South** — analysis questions
|
|
71
|
+
- **West** — validation checks
|
|
72
|
+
- **North** — action stack
|
|
73
|
+
- Ceremony recommendation if balance is poor
|
|
74
|
+
|
|
75
|
+
## Usage
|
|
76
|
+
\`\`\`
|
|
77
|
+
mw skill run direction-inquiry "Refactor auth module"
|
|
78
|
+
\`\`\`
|
|
79
|
+
`,
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
name: 'fire-keeper-check',
|
|
83
|
+
title: 'Fire Keeper Check',
|
|
84
|
+
description: 'Run gating and stewardship checks on proposed actions',
|
|
85
|
+
target: 'cli',
|
|
86
|
+
complement: 'session-manager',
|
|
87
|
+
body: `# Skill: Fire Keeper Check
|
|
88
|
+
|
|
89
|
+
## Purpose
|
|
90
|
+
Evaluate a proposed action against permission tiers and relational gates.
|
|
91
|
+
|
|
92
|
+
## Input
|
|
93
|
+
- Proposed action description
|
|
94
|
+
- Current permission tier
|
|
95
|
+
- Current ceremony phase
|
|
96
|
+
- Optional: Wilson / OCAP metadata
|
|
97
|
+
|
|
98
|
+
## Output
|
|
99
|
+
- accept / hold / human-needed assessment
|
|
100
|
+
- Unsatisfied gates
|
|
101
|
+
- Check-back step results
|
|
102
|
+
- Suggested next move
|
|
103
|
+
|
|
104
|
+
## Usage
|
|
105
|
+
\`\`\`
|
|
106
|
+
mw skill run fire-keeper-check "Deploy to production"
|
|
107
|
+
\`\`\`
|
|
108
|
+
`,
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
name: 'wave-spec-generator',
|
|
112
|
+
title: 'Wave Spec Generator',
|
|
113
|
+
description: 'Generate .pde wave specifications for development cycles',
|
|
114
|
+
target: 'cli',
|
|
115
|
+
complement: 'storage-config',
|
|
116
|
+
body: `# Skill: Wave Spec Generator
|
|
117
|
+
|
|
118
|
+
## Purpose
|
|
119
|
+
Create a proposal-grade wave bundle matching current .pde practice.
|
|
120
|
+
|
|
121
|
+
## Input
|
|
122
|
+
- Goal description
|
|
123
|
+
- Relevant specs
|
|
124
|
+
- Target paths and constraints
|
|
125
|
+
|
|
126
|
+
## Output
|
|
127
|
+
- ORCHESTRATION.md
|
|
128
|
+
- PROMPT.txt
|
|
129
|
+
- artifacts/ checklist
|
|
130
|
+
|
|
131
|
+
## Usage
|
|
132
|
+
\`\`\`
|
|
133
|
+
mw skill run wave-spec-generator "Add caching layer"
|
|
134
|
+
\`\`\`
|
|
135
|
+
`,
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
name: 'ceremony-guide',
|
|
139
|
+
title: 'Ceremony Guide',
|
|
140
|
+
description: 'Guide through ceremony lifecycle phases with protocol awareness',
|
|
141
|
+
target: 'cli',
|
|
142
|
+
complement: 'docker-setup',
|
|
143
|
+
body: `# Skill: Ceremony Guide
|
|
144
|
+
|
|
145
|
+
## Purpose
|
|
146
|
+
Provide step-by-step guidance through the ceremony lifecycle.
|
|
147
|
+
|
|
148
|
+
## Input
|
|
149
|
+
- Current ceremony state (or new ceremony intention)
|
|
150
|
+
- Phase: opening / council / integration / closure
|
|
151
|
+
|
|
152
|
+
## Output
|
|
153
|
+
- Current phase assessment
|
|
154
|
+
- Protocol requirements for next transition
|
|
155
|
+
- Relational checks and community review prompts
|
|
156
|
+
- Completion criteria
|
|
157
|
+
|
|
158
|
+
## Usage
|
|
159
|
+
\`\`\`
|
|
160
|
+
mw skill run ceremony-guide "Community data review"
|
|
161
|
+
\`\`\`
|
|
162
|
+
`,
|
|
163
|
+
},
|
|
164
|
+
// ── Server skills (mwsrv) ─────────────────────────────────────
|
|
165
|
+
{
|
|
166
|
+
name: 'docker-setup',
|
|
167
|
+
title: 'Docker Setup',
|
|
168
|
+
description: 'Configure and validate Docker environment for Medicine Wheel server',
|
|
169
|
+
target: 'srv',
|
|
170
|
+
complement: 'ceremony-guide',
|
|
171
|
+
body: `# Skill: Docker Setup
|
|
172
|
+
|
|
173
|
+
## Purpose
|
|
174
|
+
Configure the Docker environment for running the Medicine Wheel server.
|
|
175
|
+
|
|
176
|
+
## Checks
|
|
177
|
+
- Docker daemon availability
|
|
178
|
+
- Image pull status (jgwill/medicine-wheel:app)
|
|
179
|
+
- Volume mount configuration
|
|
180
|
+
- Port availability
|
|
181
|
+
|
|
182
|
+
## Usage
|
|
183
|
+
\`\`\`
|
|
184
|
+
mwsrv skill run docker-setup
|
|
185
|
+
\`\`\`
|
|
186
|
+
`,
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
name: 'storage-config',
|
|
190
|
+
title: 'Storage Configuration',
|
|
191
|
+
description: 'Configure and validate storage providers (JSONL / PostgreSQL)',
|
|
192
|
+
target: 'srv',
|
|
193
|
+
complement: 'wave-spec-generator',
|
|
194
|
+
body: `# Skill: Storage Configuration
|
|
195
|
+
|
|
196
|
+
## Purpose
|
|
197
|
+
Configure the storage backend for the Medicine Wheel server.
|
|
198
|
+
|
|
199
|
+
## Supported Providers
|
|
200
|
+
- **jsonl** — Local file-based storage (.mw/store/)
|
|
201
|
+
- **postgres** — PostgreSQL via DATABASE_URL
|
|
202
|
+
|
|
203
|
+
## Checks
|
|
204
|
+
- Current MW_STORAGE_PROVIDER value
|
|
205
|
+
- Data directory existence and permissions
|
|
206
|
+
- PostgreSQL connectivity (if applicable)
|
|
207
|
+
- Migration status
|
|
208
|
+
|
|
209
|
+
## Usage
|
|
210
|
+
\`\`\`
|
|
211
|
+
mwsrv skill run storage-config
|
|
212
|
+
\`\`\`
|
|
213
|
+
`,
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
name: 'api-health',
|
|
217
|
+
title: 'API Health Monitor',
|
|
218
|
+
description: 'Monitor and diagnose API endpoint health and connectivity',
|
|
219
|
+
target: 'srv',
|
|
220
|
+
complement: 'direction-inquiry',
|
|
221
|
+
body: `# Skill: API Health Monitor
|
|
222
|
+
|
|
223
|
+
## Purpose
|
|
224
|
+
Check the health and connectivity of Medicine Wheel API endpoints.
|
|
225
|
+
|
|
226
|
+
## Checks
|
|
227
|
+
- Server reachability (MW_API_URL)
|
|
228
|
+
- Core endpoint status (/api/directions, /api/ceremonies, /api/nodes)
|
|
229
|
+
- Response time measurements
|
|
230
|
+
- Storage layer connectivity
|
|
231
|
+
|
|
232
|
+
## Usage
|
|
233
|
+
\`\`\`
|
|
234
|
+
mwsrv skill run api-health
|
|
235
|
+
\`\`\`
|
|
236
|
+
`,
|
|
237
|
+
},
|
|
238
|
+
{
|
|
239
|
+
name: 'session-manager',
|
|
240
|
+
title: 'Session Manager',
|
|
241
|
+
description: 'Manage and inspect active server sessions and connections',
|
|
242
|
+
target: 'srv',
|
|
243
|
+
complement: 'fire-keeper-check',
|
|
244
|
+
body: `# Skill: Session Manager
|
|
245
|
+
|
|
246
|
+
## Purpose
|
|
247
|
+
Inspect and manage active sessions on the Medicine Wheel server.
|
|
248
|
+
|
|
249
|
+
## Capabilities
|
|
250
|
+
- List active sessions
|
|
251
|
+
- Inspect session state and ceremony context
|
|
252
|
+
- View session data directory contents
|
|
253
|
+
- Cleanup stale session data
|
|
254
|
+
|
|
255
|
+
## Usage
|
|
256
|
+
\`\`\`
|
|
257
|
+
mwsrv skill run session-manager
|
|
258
|
+
\`\`\`
|
|
259
|
+
`,
|
|
260
|
+
},
|
|
261
|
+
];
|
|
262
|
+
// ── Helpers ───────────────────────────────────────────────────────
|
|
263
|
+
function getSkillsDir() {
|
|
264
|
+
const dataDir = process.env.MW_DATA_DIR
|
|
265
|
+
?? path.join(process.cwd(), '.mw');
|
|
266
|
+
return path.join(dataDir, 'skills');
|
|
267
|
+
}
|
|
268
|
+
function isInstalled(skill) {
|
|
269
|
+
const dir = getSkillsDir();
|
|
270
|
+
return fs.existsSync(path.join(dir, skill.name, 'SKILL.md'));
|
|
271
|
+
}
|
|
272
|
+
// ── Public API ────────────────────────────────────────────────────
|
|
273
|
+
/** Return all skills for the given target binary. */
|
|
274
|
+
function listSkills(target) {
|
|
275
|
+
return SKILLS.filter((s) => s.target === target);
|
|
276
|
+
}
|
|
277
|
+
/** Return a single skill by name. */
|
|
278
|
+
function getSkill(name) {
|
|
279
|
+
return SKILLS.find((s) => s.name === name);
|
|
280
|
+
}
|
|
281
|
+
/** Return the complement skill for a given skill. */
|
|
282
|
+
function getComplement(skill) {
|
|
283
|
+
return skill.complement ? getSkill(skill.complement) : undefined;
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* Print skill catalog for the given target.
|
|
287
|
+
*
|
|
288
|
+
* @param target Which binary's skills to show ('cli' | 'srv')
|
|
289
|
+
* @param colors ANSI colour map (must include bold, dim, green, reset)
|
|
290
|
+
*/
|
|
291
|
+
function viewSkills(target, colors) {
|
|
292
|
+
const skills = listSkills(target);
|
|
293
|
+
const label = target === 'cli' ? 'mw' : 'mwsrv';
|
|
294
|
+
console.log(`\n ${colors.bold}🌿 ${label} skills (${skills.length} available)${colors.reset}\n`);
|
|
295
|
+
for (const s of skills) {
|
|
296
|
+
const installed = isInstalled(s);
|
|
297
|
+
const marker = installed
|
|
298
|
+
? `${colors.green}✓${colors.reset}`
|
|
299
|
+
: `${colors.dim}○${colors.reset}`;
|
|
300
|
+
const comp = s.complement
|
|
301
|
+
? `${colors.dim} ↔ ${s.complement}${colors.reset}`
|
|
302
|
+
: '';
|
|
303
|
+
console.log(` ${marker} ${s.name.padEnd(24)} ${s.description}${comp}`);
|
|
304
|
+
}
|
|
305
|
+
console.log('');
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* Install a skill (or all skills) for the given target.
|
|
309
|
+
*
|
|
310
|
+
* @returns number of newly installed skills
|
|
311
|
+
*/
|
|
312
|
+
function installSkill(target, name, colors) {
|
|
313
|
+
const C = colors ?? { bold: '', dim: '', green: '', south: '', reset: '' };
|
|
314
|
+
const dir = getSkillsDir();
|
|
315
|
+
const toInstall = name
|
|
316
|
+
? SKILLS.filter((s) => s.name === name && s.target === target)
|
|
317
|
+
: listSkills(target);
|
|
318
|
+
if (name && toInstall.length === 0) {
|
|
319
|
+
// Check if the skill exists for the other target
|
|
320
|
+
const other = SKILLS.find((s) => s.name === name);
|
|
321
|
+
if (other) {
|
|
322
|
+
const otherLabel = other.target === 'cli' ? 'mw' : 'mwsrv';
|
|
323
|
+
console.error(`${C.south}Skill "${name}" belongs to ${otherLabel}, not this CLI.${C.reset}`);
|
|
324
|
+
}
|
|
325
|
+
else {
|
|
326
|
+
console.error(`${C.south}Unknown skill: ${name}${C.reset}`);
|
|
327
|
+
}
|
|
328
|
+
return 0;
|
|
329
|
+
}
|
|
330
|
+
let installed = 0;
|
|
331
|
+
for (const skill of toInstall) {
|
|
332
|
+
const skillDir = path.join(dir, skill.name);
|
|
333
|
+
const skillFile = path.join(skillDir, 'SKILL.md');
|
|
334
|
+
if (fs.existsSync(skillFile)) {
|
|
335
|
+
console.log(` ${C.dim}⊘ ${skill.name} (already installed)${C.reset}`);
|
|
336
|
+
continue;
|
|
337
|
+
}
|
|
338
|
+
fs.mkdirSync(skillDir, { recursive: true });
|
|
339
|
+
fs.writeFileSync(skillFile, skill.body, 'utf8');
|
|
340
|
+
installed++;
|
|
341
|
+
console.log(` ${C.green}✓${C.reset} Installed ${skill.name}`);
|
|
342
|
+
// Show complement relationship
|
|
343
|
+
const comp = getComplement(skill);
|
|
344
|
+
if (comp) {
|
|
345
|
+
const compLabel = comp.target === 'cli' ? 'mw' : 'mwsrv';
|
|
346
|
+
console.log(` ${C.dim}↔ complement: ${comp.name} (${compLabel} skill install ${comp.name})${C.reset}`);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
if (installed > 0) {
|
|
350
|
+
console.log(`\n ${C.bold}${installed} skill(s) installed to ${dir}${C.reset}\n`);
|
|
351
|
+
}
|
|
352
|
+
else {
|
|
353
|
+
console.log(`\n ${C.dim}All skills already installed.${C.reset}\n`);
|
|
354
|
+
}
|
|
355
|
+
return installed;
|
|
356
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@medicine-wheel/app",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.8",
|
|
4
4
|
"description": "Medicine Wheel — Interactive visual layer for Indigenous relational research with Four Directions, ceremonies, and narrative arcs",
|
|
5
5
|
"bin": {
|
|
6
6
|
"mw": "dist/cli/mw.js",
|
|
@@ -81,23 +81,23 @@
|
|
|
81
81
|
"clsx": "^2.1.1",
|
|
82
82
|
"tailwind-merge": "^3.0.2",
|
|
83
83
|
"recharts": "^2.15.4",
|
|
84
|
-
"@medicine-wheel/ontology-core": "^0.2.
|
|
85
|
-
"@medicine-wheel/ceremony-protocol": "^0.2.
|
|
86
|
-
"@medicine-wheel/narrative-engine": "^0.2.
|
|
87
|
-
"@medicine-wheel/graph-viz": "^0.2.
|
|
88
|
-
"@medicine-wheel/relational-query": "^0.2.
|
|
89
|
-
"@medicine-wheel/prompt-decomposition": "^0.2.
|
|
90
|
-
"@medicine-wheel/ui-components": "^0.2.
|
|
91
|
-
"@medicine-wheel/data-store": "^0.2.
|
|
92
|
-
"@medicine-wheel/session-reader": "^0.2.
|
|
93
|
-
"@medicine-wheel/fire-keeper": "^0.2.
|
|
94
|
-
"@medicine-wheel/importance-unit": "^0.2.
|
|
95
|
-
"@medicine-wheel/relational-index": "^0.2.
|
|
96
|
-
"@medicine-wheel/transformation-tracker": "^0.2.
|
|
97
|
-
"@medicine-wheel/storage-provider": "^0.2.
|
|
98
|
-
"@medicine-wheel/community-review": "^0.2.
|
|
99
|
-
"@medicine-wheel/consent-lifecycle": "^0.2.
|
|
100
|
-
"@medicine-wheel/data-store-postgres": "^0.2.
|
|
84
|
+
"@medicine-wheel/ontology-core": "^0.2.8",
|
|
85
|
+
"@medicine-wheel/ceremony-protocol": "^0.2.8",
|
|
86
|
+
"@medicine-wheel/narrative-engine": "^0.2.8",
|
|
87
|
+
"@medicine-wheel/graph-viz": "^0.2.8",
|
|
88
|
+
"@medicine-wheel/relational-query": "^0.2.8",
|
|
89
|
+
"@medicine-wheel/prompt-decomposition": "^0.2.8",
|
|
90
|
+
"@medicine-wheel/ui-components": "^0.2.8",
|
|
91
|
+
"@medicine-wheel/data-store": "^0.2.8",
|
|
92
|
+
"@medicine-wheel/session-reader": "^0.2.8",
|
|
93
|
+
"@medicine-wheel/fire-keeper": "^0.2.8",
|
|
94
|
+
"@medicine-wheel/importance-unit": "^0.2.8",
|
|
95
|
+
"@medicine-wheel/relational-index": "^0.2.8",
|
|
96
|
+
"@medicine-wheel/transformation-tracker": "^0.2.8",
|
|
97
|
+
"@medicine-wheel/storage-provider": "^0.2.8",
|
|
98
|
+
"@medicine-wheel/community-review": "^0.2.8",
|
|
99
|
+
"@medicine-wheel/consent-lifecycle": "^0.2.8",
|
|
100
|
+
"@medicine-wheel/data-store-postgres": "^0.2.8",
|
|
101
101
|
"@neondatabase/serverless": "^0.10.0"
|
|
102
102
|
},
|
|
103
103
|
"devDependencies": {
|