@medicine-wheel/app 0.5.4 → 0.5.6
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 +39 -12
- package/dist/cli/mwsrv.js +30 -3
- package/dist/cli/skills.js +318 -3
- package/package.json +24 -23
package/dist/cli/mw.js
CHANGED
|
@@ -101,6 +101,25 @@ const C = {
|
|
|
101
101
|
bold: '\x1b[1m',
|
|
102
102
|
reset: '\x1b[0m',
|
|
103
103
|
};
|
|
104
|
+
// ── Exit codes ────────────────────────────────────────────────────
|
|
105
|
+
// A command that did not do what it was asked must never exit 0.
|
|
106
|
+
// 0 the command did what it said
|
|
107
|
+
// 1 the command ran and failed
|
|
108
|
+
// 2 usage error — unknown command / sub-command, or a missing argument
|
|
109
|
+
// 3 the sub-command is recognised but has no implementation yet
|
|
110
|
+
const EXIT_USAGE = 2;
|
|
111
|
+
const EXIT_UNIMPLEMENTED = 3;
|
|
112
|
+
/**
|
|
113
|
+
* Report an unknown sub-command and mark the process as failed.
|
|
114
|
+
*
|
|
115
|
+
* Uses `process.exitCode` rather than `process.exit()` so buffered stderr is
|
|
116
|
+
* flushed before the process leaves.
|
|
117
|
+
*/
|
|
118
|
+
function unknownSub(group, sub, available) {
|
|
119
|
+
console.error(`${C.south}Unknown ${group} sub-command: ${sub}${C.reset}`);
|
|
120
|
+
console.error(` Available: ${available.join(', ')}`);
|
|
121
|
+
process.exitCode = EXIT_USAGE;
|
|
122
|
+
}
|
|
104
123
|
function parseArgs(argv) {
|
|
105
124
|
const args = argv.slice(2);
|
|
106
125
|
const flags = {};
|
|
@@ -276,6 +295,8 @@ ${C.bold}🌿 mw — Medicine Wheel CLI${C.reset}
|
|
|
276
295
|
SKILLS
|
|
277
296
|
mw skill view List available CLI skills
|
|
278
297
|
mw skill install [name] Install a skill (or all)
|
|
298
|
+
mw skill run <name> NOT AVAILABLE — skills are definitions,
|
|
299
|
+
not programs. Exits ${EXIT_UNIMPLEMENTED}.
|
|
279
300
|
|
|
280
301
|
MEMORY
|
|
281
302
|
mw memory store <key> <value> [dir] Store relational memory
|
|
@@ -385,7 +406,7 @@ async function cmdCeremony(positional, flags) {
|
|
|
385
406
|
break;
|
|
386
407
|
}
|
|
387
408
|
default:
|
|
388
|
-
|
|
409
|
+
unknownSub('ceremony', sub, ['open', 'close', 'get', 'list']);
|
|
389
410
|
}
|
|
390
411
|
}
|
|
391
412
|
// ── Direction ─────────────────────────────────────────────────────
|
|
@@ -484,7 +505,7 @@ async function cmdCycle(positional) {
|
|
|
484
505
|
mcpCall('get_narrative_arc', { cycle_id: positional[1] ?? '' });
|
|
485
506
|
break;
|
|
486
507
|
default:
|
|
487
|
-
|
|
508
|
+
unknownSub('cycle', sub, ['create', 'list', 'advance', 'get', 'arc']);
|
|
488
509
|
}
|
|
489
510
|
}
|
|
490
511
|
// ── Node ──────────────────────────────────────────────────────────
|
|
@@ -539,7 +560,7 @@ async function cmdNode(positional, flags) {
|
|
|
539
560
|
mcpCall('search_nodes', { query: positional.slice(1).join(' ') });
|
|
540
561
|
break;
|
|
541
562
|
default:
|
|
542
|
-
|
|
563
|
+
unknownSub('node', sub, ['create', 'list', 'get', 'search']);
|
|
543
564
|
}
|
|
544
565
|
}
|
|
545
566
|
// ── Beat ──────────────────────────────────────────────────────────
|
|
@@ -605,7 +626,7 @@ async function cmdBeat(positional, flags = {}) {
|
|
|
605
626
|
break;
|
|
606
627
|
}
|
|
607
628
|
default:
|
|
608
|
-
|
|
629
|
+
unknownSub('beat', sub, ['register', 'create', 'list']);
|
|
609
630
|
}
|
|
610
631
|
}
|
|
611
632
|
// ── Edge ──────────────────────────────────────────────────────────
|
|
@@ -625,7 +646,7 @@ function cmdEdge(positional, flags) {
|
|
|
625
646
|
break;
|
|
626
647
|
}
|
|
627
648
|
default:
|
|
628
|
-
|
|
649
|
+
unknownSub('edge', sub, ['create', 'list']);
|
|
629
650
|
}
|
|
630
651
|
}
|
|
631
652
|
// ── Web ───────────────────────────────────────────────────────────
|
|
@@ -652,7 +673,7 @@ function cmdChart(positional) {
|
|
|
652
673
|
mcpCall('get_chart_progress', { chart_id: positional[1] ?? '' });
|
|
653
674
|
break;
|
|
654
675
|
default:
|
|
655
|
-
|
|
676
|
+
unknownSub('chart', sub, ['create', 'list', 'progress']);
|
|
656
677
|
}
|
|
657
678
|
}
|
|
658
679
|
// ── MMOT ──────────────────────────────────────────────────────────
|
|
@@ -692,7 +713,7 @@ function cmdValidate(positional) {
|
|
|
692
713
|
});
|
|
693
714
|
break;
|
|
694
715
|
default:
|
|
695
|
-
|
|
716
|
+
unknownSub('validate', sub, ['wilson', 'ocap', 'accountability', 'bridge']);
|
|
696
717
|
}
|
|
697
718
|
}
|
|
698
719
|
// ── Skill ─────────────────────────────────────────────────────────
|
|
@@ -705,12 +726,18 @@ function cmdSkill(positional) {
|
|
|
705
726
|
break;
|
|
706
727
|
case 'install': {
|
|
707
728
|
const name = positional[1]; // undefined means install all
|
|
708
|
-
|
|
729
|
+
// installSkill returns -1 when `name` matched no skill for this target.
|
|
730
|
+
if ((0, skills_1.installSkill)('cli', name, C) < 0)
|
|
731
|
+
process.exitCode = EXIT_USAGE;
|
|
709
732
|
break;
|
|
710
733
|
}
|
|
734
|
+
case 'run':
|
|
735
|
+
// Recognised, deliberately unimplemented. See explainSkillRunUnavailable.
|
|
736
|
+
(0, skills_1.explainSkillRunUnavailable)('mw', C);
|
|
737
|
+
process.exitCode = EXIT_UNIMPLEMENTED;
|
|
738
|
+
break;
|
|
711
739
|
default:
|
|
712
|
-
|
|
713
|
-
console.error("Available: view, install");
|
|
740
|
+
unknownSub('skill', sub, ['view', 'list', 'install']);
|
|
714
741
|
}
|
|
715
742
|
}
|
|
716
743
|
// ── Memory ────────────────────────────────────────────────────────
|
|
@@ -728,7 +755,7 @@ function cmdMemory(positional) {
|
|
|
728
755
|
break;
|
|
729
756
|
}
|
|
730
757
|
default:
|
|
731
|
-
|
|
758
|
+
unknownSub('memory', sub, ['store']);
|
|
732
759
|
}
|
|
733
760
|
}
|
|
734
761
|
// ── Main dispatch ─────────────────────────────────────────────────
|
|
@@ -811,7 +838,7 @@ async function main() {
|
|
|
811
838
|
default:
|
|
812
839
|
console.error(`${C.south}Unknown command: ${cmd}${C.reset}`);
|
|
813
840
|
console.error("Run 'mw help' for usage.");
|
|
814
|
-
process.
|
|
841
|
+
process.exitCode = EXIT_USAGE;
|
|
815
842
|
}
|
|
816
843
|
}
|
|
817
844
|
main().catch((err) => {
|
package/dist/cli/mwsrv.js
CHANGED
|
@@ -65,6 +65,14 @@ const C = {
|
|
|
65
65
|
};
|
|
66
66
|
const DEFAULT_PORT = 8040;
|
|
67
67
|
const CONTAINER_PORT = 8040;
|
|
68
|
+
// ── Exit codes ────────────────────────────────────────────────────
|
|
69
|
+
// A command that did not do what it was asked must never exit 0.
|
|
70
|
+
// 0 the command did what it said
|
|
71
|
+
// 1 the command ran and failed
|
|
72
|
+
// 2 usage error — unknown command / sub-command, or a missing argument
|
|
73
|
+
// 3 the sub-command is recognised but has no implementation yet
|
|
74
|
+
const EXIT_USAGE = 2;
|
|
75
|
+
const EXIT_UNIMPLEMENTED = 3;
|
|
68
76
|
function parseArgs(argv) {
|
|
69
77
|
const args = argv.slice(2);
|
|
70
78
|
const flags = {};
|
|
@@ -213,12 +221,20 @@ function cmdSkill(positional) {
|
|
|
213
221
|
break;
|
|
214
222
|
case 'install': {
|
|
215
223
|
const name = positional[1]; // undefined means install all
|
|
216
|
-
|
|
224
|
+
// installSkill returns -1 when `name` matched no skill for this target.
|
|
225
|
+
if ((0, skills_1.installSkill)('srv', name, C) < 0)
|
|
226
|
+
process.exitCode = EXIT_USAGE;
|
|
217
227
|
break;
|
|
218
228
|
}
|
|
229
|
+
case 'run':
|
|
230
|
+
// Recognised, deliberately unimplemented. See explainSkillRunUnavailable.
|
|
231
|
+
(0, skills_1.explainSkillRunUnavailable)('mwsrv', C);
|
|
232
|
+
process.exitCode = EXIT_UNIMPLEMENTED;
|
|
233
|
+
break;
|
|
219
234
|
default:
|
|
220
|
-
console.error(
|
|
221
|
-
console.error(
|
|
235
|
+
console.error(`${C.south}Unknown skill sub-command: ${sub}${C.reset}`);
|
|
236
|
+
console.error(' Available: view, list, install');
|
|
237
|
+
process.exitCode = EXIT_USAGE;
|
|
222
238
|
}
|
|
223
239
|
}
|
|
224
240
|
// ── Help ──────────────────────────────────────────────────────────
|
|
@@ -244,6 +260,8 @@ OPTIONS
|
|
|
244
260
|
SKILLS
|
|
245
261
|
mwsrv skill view List available server skills
|
|
246
262
|
mwsrv skill install [name] Install a skill (or all)
|
|
263
|
+
mwsrv skill run <name> NOT AVAILABLE — skills are definitions, not
|
|
264
|
+
programs. Exits ${EXIT_UNIMPLEMENTED}.
|
|
247
265
|
|
|
248
266
|
EXAMPLES
|
|
249
267
|
# Start locally (uses current directory's .mw/store)
|
|
@@ -278,6 +296,15 @@ async function main() {
|
|
|
278
296
|
cmdSkill(positional.slice(1));
|
|
279
297
|
return;
|
|
280
298
|
}
|
|
299
|
+
// Anything else positional is a typo, not a server invocation. Starting the
|
|
300
|
+
// server anyway reported success for a command that was never understood.
|
|
301
|
+
if (positional.length > 0) {
|
|
302
|
+
console.error(`${C.south}Unknown command: ${positional[0]}${C.reset}`);
|
|
303
|
+
console.error(" The only sub-command is 'skill'. Run 'mwsrv --help' for usage.");
|
|
304
|
+
console.error(" To start the server, run 'mwsrv' with no positional arguments.");
|
|
305
|
+
process.exitCode = EXIT_USAGE;
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
281
308
|
const port = Number(flags['port'] ?? flags['p'] ?? DEFAULT_PORT);
|
|
282
309
|
const directory = String(flags['directory'] ?? flags['D'] ?? process.cwd());
|
|
283
310
|
const useDocker = Boolean(flags['docker']);
|
package/dist/cli/skills.js
CHANGED
|
@@ -43,6 +43,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
43
43
|
exports.listSkills = listSkills;
|
|
44
44
|
exports.getSkill = getSkill;
|
|
45
45
|
exports.getComplement = getComplement;
|
|
46
|
+
exports.explainSkillRunUnavailable = explainSkillRunUnavailable;
|
|
46
47
|
exports.viewSkills = viewSkills;
|
|
47
48
|
exports.installSkill = installSkill;
|
|
48
49
|
const fs = __importStar(require("fs"));
|
|
@@ -73,6 +74,15 @@ Analyze an engineering task using the Four Directions framework.
|
|
|
73
74
|
- Ceremony recommendation if balance is poor
|
|
74
75
|
|
|
75
76
|
## Usage
|
|
77
|
+
|
|
78
|
+
> **Not available yet.** \`mw skill run\` has no implementation.
|
|
79
|
+
> It prints this explanation and exits 3 — nothing is executed. Planned, not shipped.
|
|
80
|
+
>
|
|
81
|
+
> **What works today:** \`mw skill install direction-inquiry\` writes this
|
|
82
|
+
> SKILL.md into \`.mw/skills/\`. Follow the steps above yourself, or hand this
|
|
83
|
+
> file to an agent.
|
|
84
|
+
|
|
85
|
+
Planned invocation (does not run yet):
|
|
76
86
|
\`\`\`
|
|
77
87
|
mw skill run direction-inquiry "Refactor auth module"
|
|
78
88
|
\`\`\`
|
|
@@ -102,6 +112,15 @@ Evaluate a proposed action against permission tiers and relational gates.
|
|
|
102
112
|
- Suggested next move
|
|
103
113
|
|
|
104
114
|
## Usage
|
|
115
|
+
|
|
116
|
+
> **Not available yet.** \`mw skill run\` has no implementation.
|
|
117
|
+
> It prints this explanation and exits 3 — nothing is executed. Planned, not shipped.
|
|
118
|
+
>
|
|
119
|
+
> **What works today:** \`mw skill install fire-keeper-check\` writes this
|
|
120
|
+
> SKILL.md into \`.mw/skills/\`. Follow the steps above yourself, or hand this
|
|
121
|
+
> file to an agent.
|
|
122
|
+
|
|
123
|
+
Planned invocation (does not run yet):
|
|
105
124
|
\`\`\`
|
|
106
125
|
mw skill run fire-keeper-check "Deploy to production"
|
|
107
126
|
\`\`\`
|
|
@@ -129,6 +148,15 @@ Create a proposal-grade wave bundle matching current .pde practice.
|
|
|
129
148
|
- artifacts/ checklist
|
|
130
149
|
|
|
131
150
|
## Usage
|
|
151
|
+
|
|
152
|
+
> **Not available yet.** \`mw skill run\` has no implementation.
|
|
153
|
+
> It prints this explanation and exits 3 — nothing is executed. Planned, not shipped.
|
|
154
|
+
>
|
|
155
|
+
> **What works today:** \`mw skill install wave-spec-generator\` writes this
|
|
156
|
+
> SKILL.md into \`.mw/skills/\`. Follow the steps above yourself, or hand this
|
|
157
|
+
> file to an agent.
|
|
158
|
+
|
|
159
|
+
Planned invocation (does not run yet):
|
|
132
160
|
\`\`\`
|
|
133
161
|
mw skill run wave-spec-generator "Add caching layer"
|
|
134
162
|
\`\`\`
|
|
@@ -156,9 +184,135 @@ Provide step-by-step guidance through the ceremony lifecycle.
|
|
|
156
184
|
- Completion criteria
|
|
157
185
|
|
|
158
186
|
## Usage
|
|
187
|
+
|
|
188
|
+
> **Not available yet.** \`mw skill run\` has no implementation.
|
|
189
|
+
> It prints this explanation and exits 3 — nothing is executed. Planned, not shipped.
|
|
190
|
+
>
|
|
191
|
+
> **What works today:** \`mw skill install ceremony-guide\` writes this
|
|
192
|
+
> SKILL.md into \`.mw/skills/\`. Follow the steps above yourself, or hand this
|
|
193
|
+
> file to an agent.
|
|
194
|
+
|
|
195
|
+
Planned invocation (does not run yet):
|
|
159
196
|
\`\`\`
|
|
160
197
|
mw skill run ceremony-guide "Community data review"
|
|
161
198
|
\`\`\`
|
|
199
|
+
`,
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
name: 'infrastructure-audit',
|
|
203
|
+
title: 'Infrastructure Audit',
|
|
204
|
+
description: 'Audit hosts, services, and port bindings across the Medicine Wheel estate',
|
|
205
|
+
target: 'cli',
|
|
206
|
+
complement: 'infra-monitor',
|
|
207
|
+
body: `# Skill: Infrastructure Audit
|
|
208
|
+
|
|
209
|
+
## Purpose
|
|
210
|
+
Analyze infrastructure facets (hosts, tenants, services) and surface relationships, conflicts, and métis.
|
|
211
|
+
|
|
212
|
+
## Input
|
|
213
|
+
- Target host (optional — audit all if omitted)
|
|
214
|
+
- Facet type filter (host / tenant / service, optional)
|
|
215
|
+
- Conflict scope (declared / observed / union)
|
|
216
|
+
|
|
217
|
+
## Output
|
|
218
|
+
- Graph: hosts → tenants → services with port bindings
|
|
219
|
+
- Port conflicts (distinct services colliding on same host|proto|port)
|
|
220
|
+
- Métis surface (invisible work, exceptions, heldBy accountability)
|
|
221
|
+
- Reachability status (lan / tailnet / cloudflare / ngrok)
|
|
222
|
+
|
|
223
|
+
## Usage
|
|
224
|
+
|
|
225
|
+
> **Not available yet.** \`mw skill run\` has no implementation.
|
|
226
|
+
> It prints this explanation and exits 3 — nothing is executed. Planned, not shipped.
|
|
227
|
+
>
|
|
228
|
+
> **What works today:** \`mw skill install infrastructure-audit\` writes this
|
|
229
|
+
> SKILL.md into \`.mw/skills/\`. Follow the steps above yourself, or hand this
|
|
230
|
+
> file to an agent.
|
|
231
|
+
|
|
232
|
+
Planned invocation (does not run yet):
|
|
233
|
+
\`\`\`
|
|
234
|
+
mw skill run infrastructure-audit --host eury
|
|
235
|
+
mw skill run infrastructure-audit --type service --conflicts
|
|
236
|
+
\`\`\`
|
|
237
|
+
`,
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
name: 'service-provisioning',
|
|
241
|
+
title: 'Service Provisioning',
|
|
242
|
+
description: 'Propose and gate service deployment through ceremony-aware preconditions',
|
|
243
|
+
target: 'cli',
|
|
244
|
+
complement: 'infra-monitor',
|
|
245
|
+
body: `# Skill: Service Provisioning
|
|
246
|
+
|
|
247
|
+
## Purpose
|
|
248
|
+
Propose a new service and check preconditions (port availability, consent, linger-state alignment) via ceremony gates.
|
|
249
|
+
|
|
250
|
+
## Input
|
|
251
|
+
- Service name and unit (e.g., assembly-mux.service)
|
|
252
|
+
- Port binding claims (host, port, proto)
|
|
253
|
+
- Owner (tenant nodeId)
|
|
254
|
+
- Optional: working directory, execStop, métis exceptions
|
|
255
|
+
|
|
256
|
+
## Output
|
|
257
|
+
- Precondition checks: port conflicts, tenant consent, linger alignment
|
|
258
|
+
- Fire Keeper gate assessment (hold / proceed)
|
|
259
|
+
- Community review recommendation
|
|
260
|
+
- Deployment ceremony phase to enter
|
|
261
|
+
- Diff against observed state
|
|
262
|
+
|
|
263
|
+
## Usage
|
|
264
|
+
|
|
265
|
+
> **Not available yet.** \`mw skill run\` has no implementation.
|
|
266
|
+
> It prints this explanation and exits 3 — nothing is executed. Planned, not shipped.
|
|
267
|
+
>
|
|
268
|
+
> **What works today:** \`mw skill install service-provisioning\` writes this
|
|
269
|
+
> SKILL.md into \`.mw/skills/\`. Follow the steps above yourself, or hand this
|
|
270
|
+
> file to an agent.
|
|
271
|
+
|
|
272
|
+
Planned invocation (does not run yet):
|
|
273
|
+
\`\`\`
|
|
274
|
+
mw skill run service-provisioning \
|
|
275
|
+
--unit zulip.service \
|
|
276
|
+
--port 3000:tcp@eury \
|
|
277
|
+
--owner "node:human:ava"
|
|
278
|
+
\`\`\`
|
|
279
|
+
`,
|
|
280
|
+
},
|
|
281
|
+
{
|
|
282
|
+
name: 'drift-reconciliation',
|
|
283
|
+
title: 'Drift Reconciliation',
|
|
284
|
+
description: 'Compare declared vs observed infrastructure state and propose healing steps',
|
|
285
|
+
target: 'cli',
|
|
286
|
+
complement: 'infra-monitor',
|
|
287
|
+
body: `# Skill: Drift Reconciliation
|
|
288
|
+
|
|
289
|
+
## Purpose
|
|
290
|
+
Detect infrastructure drift (declared state vs systemd observed reality) and recommend ceremony-gated remediation.
|
|
291
|
+
|
|
292
|
+
## Input
|
|
293
|
+
- Drift scope: specific host, all hosts, or facet type
|
|
294
|
+
- Healing mode: audit-only / propose-fix / execute-with-gates
|
|
295
|
+
|
|
296
|
+
## Output
|
|
297
|
+
- Drift report: satisfied / diverged / unobserved facets per host
|
|
298
|
+
- Healing candidates: services to restart, ports to release, linger to reconcile
|
|
299
|
+
- Ceremony phase recommendation (emergency / standard)
|
|
300
|
+
- Accountability notes (who holds métis on each remediation)
|
|
301
|
+
|
|
302
|
+
## Usage
|
|
303
|
+
|
|
304
|
+
> **Not available yet.** \`mw skill run\` has no implementation.
|
|
305
|
+
> It prints this explanation and exits 3 — nothing is executed. Planned, not shipped.
|
|
306
|
+
>
|
|
307
|
+
> **What works today:** \`mw skill install drift-reconciliation\` writes this
|
|
308
|
+
> SKILL.md into \`.mw/skills/\`. Follow the steps above yourself, or hand this
|
|
309
|
+
> file to an agent.
|
|
310
|
+
|
|
311
|
+
Planned invocation (does not run yet):
|
|
312
|
+
\`\`\`
|
|
313
|
+
mw skill run drift-reconciliation --host gaia --propose
|
|
314
|
+
mw skill run drift-reconciliation --type service --audit-only
|
|
315
|
+
\`\`\`
|
|
162
316
|
`,
|
|
163
317
|
},
|
|
164
318
|
// ── Server skills (mwsrv) ─────────────────────────────────────
|
|
@@ -180,6 +334,15 @@ Configure the Docker environment for running the Medicine Wheel server.
|
|
|
180
334
|
- Port availability
|
|
181
335
|
|
|
182
336
|
## Usage
|
|
337
|
+
|
|
338
|
+
> **Not available yet.** \`mwsrv skill run\` has no implementation.
|
|
339
|
+
> It prints this explanation and exits 3 — nothing is executed. Planned, not shipped.
|
|
340
|
+
>
|
|
341
|
+
> **What works today:** \`mwsrv skill install docker-setup\` writes this
|
|
342
|
+
> SKILL.md into \`.mw/skills/\`. Follow the steps above yourself, or hand this
|
|
343
|
+
> file to an agent.
|
|
344
|
+
|
|
345
|
+
Planned invocation (does not run yet):
|
|
183
346
|
\`\`\`
|
|
184
347
|
mwsrv skill run docker-setup
|
|
185
348
|
\`\`\`
|
|
@@ -207,6 +370,15 @@ Configure the storage backend for the Medicine Wheel server.
|
|
|
207
370
|
- Migration status
|
|
208
371
|
|
|
209
372
|
## Usage
|
|
373
|
+
|
|
374
|
+
> **Not available yet.** \`mwsrv skill run\` has no implementation.
|
|
375
|
+
> It prints this explanation and exits 3 — nothing is executed. Planned, not shipped.
|
|
376
|
+
>
|
|
377
|
+
> **What works today:** \`mwsrv skill install storage-config\` writes this
|
|
378
|
+
> SKILL.md into \`.mw/skills/\`. Follow the steps above yourself, or hand this
|
|
379
|
+
> file to an agent.
|
|
380
|
+
|
|
381
|
+
Planned invocation (does not run yet):
|
|
210
382
|
\`\`\`
|
|
211
383
|
mwsrv skill run storage-config
|
|
212
384
|
\`\`\`
|
|
@@ -230,6 +402,15 @@ Check the health and connectivity of Medicine Wheel API endpoints.
|
|
|
230
402
|
- Storage layer connectivity
|
|
231
403
|
|
|
232
404
|
## Usage
|
|
405
|
+
|
|
406
|
+
> **Not available yet.** \`mwsrv skill run\` has no implementation.
|
|
407
|
+
> It prints this explanation and exits 3 — nothing is executed. Planned, not shipped.
|
|
408
|
+
>
|
|
409
|
+
> **What works today:** \`mwsrv skill install api-health\` writes this
|
|
410
|
+
> SKILL.md into \`.mw/skills/\`. Follow the steps above yourself, or hand this
|
|
411
|
+
> file to an agent.
|
|
412
|
+
|
|
413
|
+
Planned invocation (does not run yet):
|
|
233
414
|
\`\`\`
|
|
234
415
|
mwsrv skill run api-health
|
|
235
416
|
\`\`\`
|
|
@@ -253,9 +434,96 @@ Inspect and manage active sessions on the Medicine Wheel server.
|
|
|
253
434
|
- Cleanup stale session data
|
|
254
435
|
|
|
255
436
|
## Usage
|
|
437
|
+
|
|
438
|
+
> **Not available yet.** \`mwsrv skill run\` has no implementation.
|
|
439
|
+
> It prints this explanation and exits 3 — nothing is executed. Planned, not shipped.
|
|
440
|
+
>
|
|
441
|
+
> **What works today:** \`mwsrv skill install session-manager\` writes this
|
|
442
|
+
> SKILL.md into \`.mw/skills/\`. Follow the steps above yourself, or hand this
|
|
443
|
+
> file to an agent.
|
|
444
|
+
|
|
445
|
+
Planned invocation (does not run yet):
|
|
256
446
|
\`\`\`
|
|
257
447
|
mwsrv skill run session-manager
|
|
258
448
|
\`\`\`
|
|
449
|
+
`,
|
|
450
|
+
},
|
|
451
|
+
{
|
|
452
|
+
name: 'infra-monitor',
|
|
453
|
+
title: 'Infrastructure Monitor',
|
|
454
|
+
description: 'Live monitoring and drift detection for infrastructure facets via MCP',
|
|
455
|
+
target: 'srv',
|
|
456
|
+
complement: 'infrastructure-audit',
|
|
457
|
+
body: `# Skill: Infrastructure Monitor
|
|
458
|
+
|
|
459
|
+
## Purpose
|
|
460
|
+
Monitor live infrastructure state (observed via systemd) and track drift against declared facets.
|
|
461
|
+
|
|
462
|
+
## Capabilities
|
|
463
|
+
- Poll systemd for active units, ports, linger-state across tenants
|
|
464
|
+
- Maintain observed state cache (RelationalNode facets)
|
|
465
|
+
- Detect port collisions in declared ∪ observed bindings
|
|
466
|
+
- Track métis holders and accountability chains
|
|
467
|
+
- Stream drift events to active CLI sessions
|
|
468
|
+
- Gate reconciliation requests through ceremony protocol
|
|
469
|
+
|
|
470
|
+
## Integration
|
|
471
|
+
- **Backend:** @medicine-wheel/infra (HostFacet, TenantFacet, ServiceFacet, detectPortConflicts)
|
|
472
|
+
- **MCP tools (planned, none registered yet):** infrastructure-audit, service-preconditions, drift-reconciliation, métis-surface
|
|
473
|
+
- **Data store:** Postgres/JSONL via @medicine-wheel/storage-provider
|
|
474
|
+
|
|
475
|
+
## Usage
|
|
476
|
+
|
|
477
|
+
> **Not available yet.** \`mwsrv skill run\` has no implementation.
|
|
478
|
+
> It prints this explanation and exits 3 — nothing is executed. Planned, not shipped.
|
|
479
|
+
>
|
|
480
|
+
> **What works today:** \`mwsrv skill install infra-monitor\` writes this
|
|
481
|
+
> SKILL.md into \`.mw/skills/\`. Follow the steps above yourself, or hand this
|
|
482
|
+
> file to an agent.
|
|
483
|
+
|
|
484
|
+
Planned invocation (does not run yet):
|
|
485
|
+
\`\`\`
|
|
486
|
+
mwsrv skill run infra-monitor --poll-interval 30s
|
|
487
|
+
mwsrv skill run infra-monitor --host gaia --linger-report
|
|
488
|
+
\`\`\`
|
|
489
|
+
`,
|
|
490
|
+
},
|
|
491
|
+
{
|
|
492
|
+
name: 'precondition-guard',
|
|
493
|
+
title: 'Precondition Guard',
|
|
494
|
+
description: 'Evaluate infrastructure preconditions (linger, consent, port, reachability)',
|
|
495
|
+
target: 'srv',
|
|
496
|
+
complement: 'service-provisioning',
|
|
497
|
+
body: `# Skill: Precondition Guard
|
|
498
|
+
|
|
499
|
+
## Purpose
|
|
500
|
+
Enforce precondition gates before service provisioning or relational state changes. (Roadmap: @medicine-wheel/infra@0.2.0)
|
|
501
|
+
|
|
502
|
+
## Precondition Types
|
|
503
|
+
- **Port availability** — detectPortConflicts over declared + observed
|
|
504
|
+
- **Tenant linger** — required for user.slice services; consent record must authorize root step
|
|
505
|
+
- **Consent accountability** — ConsentRecord.id must be present and active
|
|
506
|
+
- **Reachability** — host must be reachable via declared transport (lan, tailnet, cloudflare, ngrok)
|
|
507
|
+
|
|
508
|
+
## Output
|
|
509
|
+
- Unsatisfied precondition report
|
|
510
|
+
- Fire Keeper hold / proceed recommendation
|
|
511
|
+
- Next ceremony gate to enter (if held)
|
|
512
|
+
- Accountability chain (who can unlock the hold)
|
|
513
|
+
|
|
514
|
+
## Usage
|
|
515
|
+
|
|
516
|
+
> **Not available yet.** \`mwsrv skill run\` has no implementation.
|
|
517
|
+
> It prints this explanation and exits 3 — nothing is executed. Planned, not shipped.
|
|
518
|
+
>
|
|
519
|
+
> **What works today:** \`mwsrv skill install precondition-guard\` writes this
|
|
520
|
+
> SKILL.md into \`.mw/skills/\`. Follow the steps above yourself, or hand this
|
|
521
|
+
> file to an agent.
|
|
522
|
+
|
|
523
|
+
Planned invocation (does not run yet):
|
|
524
|
+
\`\`\`
|
|
525
|
+
mwsrv skill run precondition-guard --facet-id "node:knowledge:zulip:..." --intent provision
|
|
526
|
+
\`\`\`
|
|
259
527
|
`,
|
|
260
528
|
},
|
|
261
529
|
];
|
|
@@ -282,6 +550,31 @@ function getSkill(name) {
|
|
|
282
550
|
function getComplement(skill) {
|
|
283
551
|
return skill.complement ? getSkill(skill.complement) : undefined;
|
|
284
552
|
}
|
|
553
|
+
/**
|
|
554
|
+
* Print why `skill run` does nothing and what to reach for instead.
|
|
555
|
+
*
|
|
556
|
+
* A `SkillDefinition` is a name/title/description/body record — a document, not
|
|
557
|
+
* a program. Nothing in this repository executes one, so `skill run` has never
|
|
558
|
+
* had an implementation. Both CLIs call this and then exit non-zero rather than
|
|
559
|
+
* printing an error and returning 0, which is what they used to do.
|
|
560
|
+
*
|
|
561
|
+
* @param binary Which CLI is speaking ('mw' | 'mwsrv') — shapes the examples.
|
|
562
|
+
* @param colors ANSI colour map.
|
|
563
|
+
*/
|
|
564
|
+
function explainSkillRunUnavailable(binary, colors) {
|
|
565
|
+
const C = colors;
|
|
566
|
+
console.error(`${C.south}${binary} skill run is not implemented.${C.reset}`);
|
|
567
|
+
console.error('');
|
|
568
|
+
console.error(' Skills here are definitions, not programs: each one is a SKILL.md');
|
|
569
|
+
console.error(' describing inputs, outputs and steps. There is no runtime that');
|
|
570
|
+
console.error(' executes them, so nothing would have run.');
|
|
571
|
+
console.error('');
|
|
572
|
+
console.error(` ${C.bold}What works today${C.reset}`);
|
|
573
|
+
console.error(` ${binary} skill view list the skills this CLI knows`);
|
|
574
|
+
console.error(` ${binary} skill install <name> write <name>/SKILL.md into .mw/skills/`);
|
|
575
|
+
console.error('');
|
|
576
|
+
console.error(' Then follow the installed SKILL.md yourself, or hand it to an agent.');
|
|
577
|
+
}
|
|
285
578
|
/**
|
|
286
579
|
* Print skill catalog for the given target.
|
|
287
580
|
*
|
|
@@ -307,7 +600,10 @@ function viewSkills(target, colors) {
|
|
|
307
600
|
/**
|
|
308
601
|
* Install a skill (or all skills) for the given target.
|
|
309
602
|
*
|
|
310
|
-
* @returns number of newly installed skills
|
|
603
|
+
* @returns number of newly installed skills, or **-1** when `name` matched no
|
|
604
|
+
* skill for this target — callers must treat -1 as a failure and exit
|
|
605
|
+
* non-zero. Returning 0 for both "nothing to do" and "you named a
|
|
606
|
+
* skill that does not exist" is what let a bad name report success.
|
|
311
607
|
*/
|
|
312
608
|
function installSkill(target, name, colors) {
|
|
313
609
|
const C = colors ?? { bold: '', dim: '', green: '', south: '', reset: '' };
|
|
@@ -325,14 +621,30 @@ function installSkill(target, name, colors) {
|
|
|
325
621
|
else {
|
|
326
622
|
console.error(`${C.south}Unknown skill: ${name}${C.reset}`);
|
|
327
623
|
}
|
|
328
|
-
return
|
|
624
|
+
return -1;
|
|
329
625
|
}
|
|
330
626
|
let installed = 0;
|
|
627
|
+
let stale = 0;
|
|
331
628
|
for (const skill of toInstall) {
|
|
332
629
|
const skillDir = path.join(dir, skill.name);
|
|
333
630
|
const skillFile = path.join(skillDir, 'SKILL.md');
|
|
334
631
|
if (fs.existsSync(skillFile)) {
|
|
335
|
-
|
|
632
|
+
// An existing file is never overwritten. Say so honestly when the copy
|
|
633
|
+
// on disk no longer matches the catalog, otherwise "already installed"
|
|
634
|
+
// reads as "up to date" while the reader follows outdated instructions.
|
|
635
|
+
let onDisk = '';
|
|
636
|
+
try {
|
|
637
|
+
onDisk = fs.readFileSync(skillFile, 'utf8');
|
|
638
|
+
}
|
|
639
|
+
catch { /* unreadable → treat as drifted */ }
|
|
640
|
+
if (onDisk === skill.body) {
|
|
641
|
+
console.log(` ${C.dim}⊘ ${skill.name} (already installed)${C.reset}`);
|
|
642
|
+
}
|
|
643
|
+
else {
|
|
644
|
+
stale++;
|
|
645
|
+
console.log(` ${C.dim}⊘ ${skill.name} (already installed — copy on disk differs from the catalog)${C.reset}`);
|
|
646
|
+
console.log(` ${C.dim}to update: rm ${skillFile} && ${target === 'cli' ? 'mw' : 'mwsrv'} skill install ${skill.name}${C.reset}`);
|
|
647
|
+
}
|
|
336
648
|
continue;
|
|
337
649
|
}
|
|
338
650
|
fs.mkdirSync(skillDir, { recursive: true });
|
|
@@ -352,5 +664,8 @@ function installSkill(target, name, colors) {
|
|
|
352
664
|
else {
|
|
353
665
|
console.log(`\n ${C.dim}All skills already installed.${C.reset}\n`);
|
|
354
666
|
}
|
|
667
|
+
if (stale > 0) {
|
|
668
|
+
console.log(` ${C.south}${stale} installed copy/copies differ from the catalog and were left untouched.${C.reset}\n`);
|
|
669
|
+
}
|
|
355
670
|
return installed;
|
|
356
671
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@medicine-wheel/app",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.6",
|
|
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",
|
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
"//workspaces": "TOPOLOGICAL ORDER — do not alphabetize. `npm run <script> --workspaces` executes in THIS array's order, not in dependency order: a package listed before a package it imports builds first and fails TS2307 on any tree without a stale dist/. Roots first (ontology-core, creative-orientation, session-reader), then their dependents, mcp last. A new package goes after everything it imports.",
|
|
27
27
|
"workspaces": [
|
|
28
28
|
"src/ontology-core",
|
|
29
|
+
"src/infra",
|
|
29
30
|
"src/creative-orientation",
|
|
30
31
|
"src/session-reader",
|
|
31
32
|
"src/ceremony-protocol",
|
|
@@ -84,28 +85,28 @@
|
|
|
84
85
|
"release:major": "npm run version:major && npm run publish:all && npm run release:commit"
|
|
85
86
|
},
|
|
86
87
|
"dependencies": {
|
|
87
|
-
"@medicine-wheel/ceremonial-diary": "^0.5.
|
|
88
|
-
"@medicine-wheel/ceremony-protocol": "^0.5.
|
|
89
|
-
"@medicine-wheel/community-review": "^0.5.
|
|
90
|
-
"@medicine-wheel/consent-lifecycle": "^0.5.
|
|
91
|
-
"@medicine-wheel/data-store": "^0.5.
|
|
92
|
-
"@medicine-wheel/data-store-postgres": "^0.5.
|
|
93
|
-
"@medicine-wheel/fire-keeper": "^0.5.
|
|
94
|
-
"@medicine-wheel/github-ceremony": "^0.5.
|
|
95
|
-
"@medicine-wheel/graph-viz": "^0.5.
|
|
96
|
-
"@medicine-wheel/importance-unit": "^0.5.
|
|
97
|
-
"@medicine-wheel/mcp": "^4.5.
|
|
98
|
-
"@medicine-wheel/narrative-cluster": "^0.5.
|
|
99
|
-
"@medicine-wheel/narrative-engine": "^0.5.
|
|
100
|
-
"@medicine-wheel/ontology-core": "^0.5.
|
|
101
|
-
"@medicine-wheel/perception-layer": "^0.5.
|
|
102
|
-
"@medicine-wheel/prompt-decomposition": "^0.5.
|
|
103
|
-
"@medicine-wheel/relational-index": "^0.5.
|
|
104
|
-
"@medicine-wheel/relational-query": "^0.5.
|
|
105
|
-
"@medicine-wheel/session-reader": "^0.5.
|
|
106
|
-
"@medicine-wheel/storage-provider": "^0.5.
|
|
107
|
-
"@medicine-wheel/transformation-tracker": "^0.5.
|
|
108
|
-
"@medicine-wheel/ui-components": "^0.5.
|
|
88
|
+
"@medicine-wheel/ceremonial-diary": "^0.5.6",
|
|
89
|
+
"@medicine-wheel/ceremony-protocol": "^0.5.6",
|
|
90
|
+
"@medicine-wheel/community-review": "^0.5.6",
|
|
91
|
+
"@medicine-wheel/consent-lifecycle": "^0.5.6",
|
|
92
|
+
"@medicine-wheel/data-store": "^0.5.6",
|
|
93
|
+
"@medicine-wheel/data-store-postgres": "^0.5.6",
|
|
94
|
+
"@medicine-wheel/fire-keeper": "^0.5.6",
|
|
95
|
+
"@medicine-wheel/github-ceremony": "^0.5.6",
|
|
96
|
+
"@medicine-wheel/graph-viz": "^0.5.6",
|
|
97
|
+
"@medicine-wheel/importance-unit": "^0.5.6",
|
|
98
|
+
"@medicine-wheel/mcp": "^4.5.5",
|
|
99
|
+
"@medicine-wheel/narrative-cluster": "^0.5.6",
|
|
100
|
+
"@medicine-wheel/narrative-engine": "^0.5.6",
|
|
101
|
+
"@medicine-wheel/ontology-core": "^0.5.6",
|
|
102
|
+
"@medicine-wheel/perception-layer": "^0.5.6",
|
|
103
|
+
"@medicine-wheel/prompt-decomposition": "^0.5.6",
|
|
104
|
+
"@medicine-wheel/relational-index": "^0.5.6",
|
|
105
|
+
"@medicine-wheel/relational-query": "^0.5.6",
|
|
106
|
+
"@medicine-wheel/session-reader": "^0.5.6",
|
|
107
|
+
"@medicine-wheel/storage-provider": "^0.5.6",
|
|
108
|
+
"@medicine-wheel/transformation-tracker": "^0.5.6",
|
|
109
|
+
"@medicine-wheel/ui-components": "^0.5.6",
|
|
109
110
|
"@neondatabase/serverless": "^0.10.0",
|
|
110
111
|
"@xyflow/react": "^12.3.0",
|
|
111
112
|
"clsx": "^2.1.1",
|