@mindrian_os/install 1.13.0-beta.11 → 1.13.0-beta.12
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/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +26 -3
- package/bin/cli.js +114 -57
- package/commands/act.md +16 -2
- package/commands/pipeline.md +16 -1
- package/commands/suggest-next.md +17 -3
- package/lib/core/active-plugin-root.cjs +142 -0
- package/lib/core/framework-chain-composer.cjs +156 -43
- package/lib/core/migrations/phase-109-nodes-provenance.cjs +47 -0
- package/lib/hmi/jtbd-taxonomy.json +2 -1
- package/lib/memory/framework-chain-composer.test.cjs +54 -20
- package/lib/memory/navigation-hook-resolver.test.cjs +177 -0
- package/lib/memory/run-feynman-tests.cjs +17 -0
- package/lib/memory/suggest-next-workflow.test.cjs +176 -0
- package/lib/memory/workflow-layer-e2e.test.cjs +262 -0
- package/lib/workflow/ROOM.md +1 -1
- package/package.json +1 -1
- package/references/brain/command-triggers-schema.md +10 -221
- package/references/methodology/index.md +11 -74
- package/skills/brain-connector/SKILL.md +3 -5
- package/skills/pws-methodology/SKILL.md +7 -5
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mos",
|
|
3
3
|
"description": "MindrianOS -- Your AI innovation co-founder. Larry thinks with you through PWS methodology, builds your Data Room as you explore, and chains frameworks intelligently. Install and go.",
|
|
4
|
-
"version": "1.13.0-beta.
|
|
4
|
+
"version": "1.13.0-beta.12",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Jonathan Sagir",
|
|
7
7
|
"url": "https://mindrian.ai"
|
package/CHANGELOG.md
CHANGED
|
@@ -9,17 +9,40 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
9
9
|
<!-- When onboarding: true, the onboard_steps list is shown to returning users in the What's New flow -->
|
|
10
10
|
<!-- This allows new releases to automatically surface relevant guidance without code changes -->
|
|
11
11
|
|
|
12
|
-
## [
|
|
12
|
+
## [1.13.0-beta.12] - 2026-05-12
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
The v1.13.0 CAPSTONE release -- headline content is the **Workflow Layer** (Phase 122: framework <-> command registry + reliable invocation; spec at `.planning/WORKFLOW-LAYER-SPEC.md`, doc at `docs/WORKFLOWS.md`) plus the npm-installer overhaul (`npx @mindrian_os/install` is now a real one-command installer), the `@mindrian_os/cli` -> `@mindrian_os/install` rename, and the install-machinery fixes a Windows live test surfaced (doctor/update path resolution, the statusline pre-release blind spot, and the single plugin-root resolver that retires that whole bug family). Version trail to here: `1.13.0-beta.10` (a token-validation npm publish on 2026-05-12 -- now deprecated), `1.13.0-beta.11` (the real npm installer + the package rename, npm-only -- now deprecated, doctor path bug), `1.13.0-beta.12` (this release: the capstone, tagged `v1.13.0-beta.12`, marketplace `source.ref` pinned, `@mindrian_os/install` published with the `@next` dist-tag).
|
|
15
15
|
|
|
16
16
|
### Added
|
|
17
17
|
|
|
18
|
+
- **The Workflow Layer (Phase 122) -- the framework-to-command registry + reliable invocation.** Larry can now turn "the methodology suggests framework X" into "run `/mos:x`" as a CI-enforced guarantee, not model recall:
|
|
19
|
+
- **`data/command-registry.json`** -- the generated, committed framework-to-command registry (`{ ontology_ref, commands[], framework_index, curated_chains[] }`), built from each `commands/*.md` frontmatter; never hand-edited. Plus `data/framework-names.json` -- the FEEDS_INTO-linked Brain `:Framework` name slice (+ a small curated whitelist), the only Brain-derived artifact in this loop.
|
|
20
|
+
- **`scripts/build-command-registry.cjs`** -- the generator + the `--check` drift tripwire (fails on a stale registry or an unresolvable framework name) + `--refresh-names` (a read-only build-time Brain query that snapshots the allowlist). The `--check` is wired into the pre-commit hook (when any `commands/*.md` / `data/command-registry.json` / `data/framework-names.json` is staged) and the Feynman test runner.
|
|
21
|
+
- **`lib/workflow/command-resolver.cjs`** -- the SOLE deterministic framework-to-command door (`commandsForFramework`, `frameworksForCommand`, `composeWorkflow`, `validateChainAutonomy`); reads only `data/command-registry.json`; zero Brain calls; degrades to empty results / `{ command: null, optional: true }` on a missing registry or a command-less framework (degrade, do not fabricate).
|
|
22
|
+
- **`lib/brain/chain-recommender.cjs`** -- `recommendFrameworkChain({problemType?, currentFramework?, roomState?}) -> [frameworkName]` via the Brain's `FEEDS_INTO` traversal (framework names + problem-type enums only, never a command string, never user content); degrades to `[seed]`.
|
|
23
|
+
- **The five new `/mos:` command frontmatter keys** -- `kind` (`methodology | utility | meta`), `frameworks[]` (the exact Brain `:Framework` name(s)), `produces`, `inputs`, `autonomous_safe` -- retrofitted across 44 commands (the algorithmic cohort first). Contract: `docs/COMMAND-FRONTMATTER.md`.
|
|
24
|
+
- **`/mos:pipeline --from-problem-type <x>` / `--from-framework <x>`** -- Brain-derive the chain, compose commands, print the `/mos:` run order. **`/mos:act --chain`** -- runs the composed workflow but `validateChainAutonomy` first and STOPS at the first non-`autonomous_safe` (or command-less) step with a "needs you here" gate (the Canon Part 3 "human confirms" clause made literal). **`/mos:suggest-next`** -- now returns a step-numbered command sequence, not just a framework list.
|
|
25
|
+
- **The pre-commit registry-drift tripwire** -- `build-command-registry.cjs --check` runs in `.git/hooks/pre-commit`; the Feynman runner runs it too.
|
|
26
|
+
- **`docs/WORKFLOWS.md`** -- the Brain <-> registry <-> Larry join, the five reliability rules, the Canon Part 8 boundary (commands never enter the Brain -- no `Command` node, ever), and the resolver/recommender surface. `docs/THE-BRAIN.md` and `docs/CANON-PHASE-MAP.md` point at it.
|
|
27
|
+
- **`lib/memory/workflow-layer-e2e.test.cjs`** -- walks frontmatter -> `build-command-registry --check` -> `resolver.composeWorkflow(the spec's acceptance example)` -> the command-less degrade case -> the `validateChainAutonomy` stop-point, then runs the Canon Part 8 zero-Brain-mutation grep sweep. Registered in the Feynman runner + `tests/run-all-122.sh`.
|
|
18
28
|
- **`npx @mindrian_os/install` is a real one-command installer, not a printout.** Previously `npx @mindrian_os/cli install` only echoed the marketplace commands for the user to paste into Claude Code by hand ("no side effects, just guidance"). It now drives Claude Code's own plugin CLI: it checks that `claude` is on PATH (and prints how to install Claude Code if not), runs `claude plugin marketplace add jsagir/mindrian-marketplace`, then `claude plugin install mos@mindrian-marketplace`. Running it with no subcommand -- or with only flags, e.g. `npx @mindrian_os/install --version 1.13.0-beta.9` -- does the install; flags pass through to `claude plugin install`. `doctor` and `update` are still explicit subcommands. The Brain key stays a printed hint -- writing it to the environment is the one side effect left to the user. This unblocks un-gating the npm-quick-install card on the install site (`mindrianos-install-site.vercel.app`). (`bin/cli.js`.)
|
|
29
|
+
- Post-beta.11 follow-up (2026-05-12, after a Windows live test): `mindrian-os doctor` / `update` were resolving the plugin at the legacy `~/.claude/plugins/mindrian-os/` path, which does not exist for a `claude plugin install` -- the plugin is named `mos` and lives at `~/.claude/plugins/cache/<marketplace>/mos/<version>/`. So `npx @mindrian_os/install doctor` was throwing a raw node `MODULE_NOT_FOUND` stack. `bin/cli.js` now resolves the plugin root in order (MINDRIAN_OS_ROOT -> newest marketplace-cache `mos/<version>/` with a `scripts/doctor.cjs` -> legacy clone -> not-found), prints a plain "not installed -- run `npx @mindrian_os/install`" message when truly absent, and `update` uses `claude plugin marketplace update` + `claude plugin update mos@mindrian-marketplace` for a marketplace install (the `git pull` + `install.sh` path is kept only for a dev clone / MINDRIAN_OS_ROOT). The `install` flow also now runs `claude plugin marketplace update` then `claude plugin install` + `claude plugin update` (so an already-installed plugin gets moved to the current ref rather than just reported "already installed", which was the misleading message in the Windows test where the version actually moved 1.12.0 -> 1.13.0-beta.9). Lands in the next `@mindrian_os/install` npm publish.
|
|
30
|
+
- Same Windows test surfaced a pre-release blind spot in `scripts/statusline-mos` (the self-healing statusline resolver): it picked the "latest" cache version with `grep -E '^[0-9]+\.[0-9]+\.[0-9]+$'`, which rejects `-beta.N` suffixes. A box with `1.12.0` + `1.13.0-beta.9` in the marketplace cache picked `1.12.0`, rendered the stale statusline from there, and exported `MINDRIAN_OS_ROOT` pointing at it -- so the version banner / room-context lookup / focus glyph were all computed from the wrong version. Widened the anchor to `^[0-9]+(\.[0-9]+)+(-[A-Za-z0-9.]+)?$` (`sort -V` already orders pre-releases correctly: `1.12.0 < 1.13.0-beta.9 < 1.13.0`). Ships in the next plugin release; the deployed `~/.claude/statusline-mos` (or the `register_statusline` block in `~/.claude/settings.json` that points at `<install-dir>/scripts/statusline-mos`) picks it up when the plugin re-stamps on next install/update. Immediate workaround on an affected box: delete the stale lower-version cache dir under `~/.claude/plugins/cache/mindrian-marketplace/mos/`.
|
|
31
|
+
- Root-cause fix (the three above were band-aids on three independent guessers): **`lib/core/active-plugin-root.cjs`** -- the ONE plugin-root resolver. Precedence: `MINDRIAN_OS_ROOT` env -> `~/.claude/plugins/installed_plugins.json` (Claude Code's own registry of the *active* `mos@mindrian-marketplace` install; temporal truth -- right even when "highest semver" isn't the active version) -> newest pre-release-tolerant `~/.claude/plugins/cache/<marketplace>/mos/<version>/` -> legacy `~/.claude/plugins/mindrian-os/` -> not-found. Usable as a module (`resolveActivePluginRoot()`) and as a CLI (`node active-plugin-root.cjs` prints the path; `--json` for `{root, source}`). `bin/cli.js` (doctor/update) now delegates to it; `scripts/statusline-mos` shells out to its CLI form (with the cache-scan as a fallback for older deployed copies of the wrapper). Reads LOCAL files only (Canon Part 8). Still TODO (separate, lower-risk pass): have `scripts/session-start` re-stamp the `register_statusline` block in `~/.claude/settings.json` from this resolver on every run, so the deployed wrapper / settings pointer can never drift.
|
|
19
32
|
|
|
20
33
|
### Changed
|
|
21
34
|
|
|
22
|
-
-
|
|
35
|
+
- **`/mos:suggest-next` returns a command sequence**, not just a framework list; **`framework-chain-composer.proposeNextFramework` routes through `lib/workflow/command-resolver.cjs`** (the only door -- `command:null` degrade for a command-less next framework); **the `pws-methodology` and `brain-connector` skills point at the resolver** (framework routing goes through `command-resolver.commandsForFramework` / `composeWorkflow`, never a `/mos:` named from memory). **The three remaining hand-maintained framework-to-command maps were pruned:** `framework-chain-composer.FRAMEWORK_TO_COMMAND_SLUG` is now an empty back-compat export, `lib/hmi/jtbd-taxonomy.json:methodology_hooks` is marked informational-only (the resolver is authoritative), and `references/methodology/index.md` is now just a pointer to `docs/COMMAND-FRONTMATTER.md` / `data/command-registry.json` / `docs/WORKFLOWS.md` -- it no longer hand-maintains a routing table.
|
|
36
|
+
- **npm package renamed (twice): `@mindrian/os` -> `@mindrian_os/cli` -> `@mindrian_os/install`.** First rename (2026-05-11): the `@mindrian` npm scope never existed (`{"error":"Scope not found"}`), so `@mindrian/os` could never be published; the maintainer created the `@mindrian_os` org and the package moved to `@mindrian_os/cli`; first npm publish was `@mindrian_os/cli@1.13.0-beta.10` on 2026-05-12 (a token-validation build, dist-tag `@next`, no git tag, not on the marketplace) -- now deprecated. Second rename (2026-05-12): `@mindrian_os/cli` implied "a CLI tool" / a guidance printer, which is exactly what it had been; once `install` became a real installer the package name should be the verb, so it moved to `@mindrian_os/install` -- `npx @mindrian_os/install` reads as "install MindrianOS". The `bin` entry stays `mindrian-os` (the post-install command for `doctor`/`update`). `package.json` + `.claude-plugin/plugin.json` ship as `1.13.0-beta.12` (this release); the npm-only intermediate publishes `@mindrian_os/cli@1.13.0-beta.10` and `@mindrian_os/install@1.13.0-beta.11` are deprecated. The install site's npm-quick-install card already names `@mindrian_os/install`; `scripts/release.sh` still says `@mindrian_os/cli` (Step 9.5) and only handles clean `X.Y.Z` bumps (it choked on the pre-release version, so this release was hand-rolled per the CLAUDE.md release process) -- both worth a follow-up. `docs/install/PACKAGING-PATHS.md`, `tests/manual/95.6-windows-cold-install-acceptance.md`, `tests/test-release-npm-gate.sh` still name `@mindrian_os/cli` and need updating to `@mindrian_os/install`. (The `[1.13.0-beta.9]` entry below is left intact as the historical record of the pre-rename release -- which shipped to GitHub and the marketplace as `v1.13.0-beta.9` but was never published to npm.)
|
|
37
|
+
|
|
38
|
+
### Fixed
|
|
39
|
+
|
|
40
|
+
- **The hallucinated-command failure mode.** Larry could name a non-existent or semantically wrong command -- e.g. `/mos:jtbd` for the JTBD *methodology* when `/mos:analyze-needs` is the framework command (`/mos:jtbd` is the active-JTBD management command, not a methodology runner). With the Workflow Layer, every command Larry surfaces comes back from `lib/workflow/command-resolver.cjs` reading the generated registry -- `composeWorkflow(["Jobs to Be Done (JTBD)"])` returns `/mos:analyze-needs`. A hallucinated command cannot be emitted.
|
|
41
|
+
- **A latent Canon Part 8 breach in prose.** `skills/brain-connector/SKILL.md` carried dead "Brain has Command nodes linked to Frameworks ... `brain_proactive_command` ... `FOLLOWS_FRAMEWORK -> Command`" prose, and `references/brain/command-triggers-schema.md` was a whole dead "commands are first-class Neo4j nodes" schema doc -- both asserted that plugin commands live in the Brain, which the live Brain never implemented (no `Command` label) and which Canon Part 8 forbids. Both were deleted; the `command-triggers-schema.md` path now carries a `REMOVED` tombstone pointing at the Workflow Layer. The `lib/memory/workflow-layer-e2e.test.cjs` grep sweep now fails the build if a `Command`-node assertion ever returns anywhere in `skills/`, `agents/`, or `references/`.
|
|
42
|
+
|
|
43
|
+
### Maintainer Notes
|
|
44
|
+
|
|
45
|
+
- **Release steps (maintainer-gated -- NOT performed in this phase):** cut the `v1.13.0-beta.11` tag, pin `~/mindrian-marketplace/.claude-plugin/marketplace.json` `source.ref` to the tag, and `npm publish @mindrian_os/install` with the `@next` dist-tag -- per the CLAUDE.md release process and the `feedback_release_lockstep_npm` rule (every plugin release publishes the npm package in lockstep). Phase 122 only finalized this CHANGELOG block and shipped the Workflow Layer code/docs/tests; it did not bump any version, did not `git tag`, did not `npm publish`, and did not edit `marketplace.json`.
|
|
23
46
|
|
|
24
47
|
### Notes
|
|
25
48
|
|
package/bin/cli.js
CHANGED
|
@@ -10,53 +10,83 @@
|
|
|
10
10
|
* flags, e.g. `npx @mindrian_os/install --version 1.13.0-beta.9`) does the
|
|
11
11
|
* install. `doctor` and `update` are still explicit subcommands.
|
|
12
12
|
*
|
|
13
|
-
* install
|
|
14
|
-
* own plugin CLI: registers the Mindrian marketplace,
|
|
15
|
-
* `claude plugin install
|
|
16
|
-
* `claude` CLI on PATH (prints
|
|
17
|
-
*
|
|
18
|
-
* (e.g.
|
|
19
|
-
*
|
|
20
|
-
* one side effect
|
|
21
|
-
* doctor
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
* update
|
|
27
|
-
*
|
|
28
|
-
*
|
|
13
|
+
* install Install (or bring current) MindrianOS by driving Claude Code's
|
|
14
|
+
* own plugin CLI: registers the Mindrian marketplace, refreshes the
|
|
15
|
+
* catalog, then `claude plugin install` + `claude plugin update` on
|
|
16
|
+
* mos@mindrian-marketplace. Requires the `claude` CLI on PATH (prints
|
|
17
|
+
* how to get it if missing). Flags pass through to `claude plugin
|
|
18
|
+
* install` (e.g. `--version 1.13.0-beta.9`); when a version is pinned
|
|
19
|
+
* the update step is skipped. The Brain key stays a printed hint --
|
|
20
|
+
* writing it to the environment is the one side effect left to you.
|
|
21
|
+
* doctor Run /mos:doctor's diagnostic from OUTSIDE Claude Code so you catch
|
|
22
|
+
* install/drift problems before a session. Resolves the installed
|
|
23
|
+
* plugin (marketplace cache, dev clone, or MINDRIAN_OS_ROOT), then
|
|
24
|
+
* `node <pluginRoot>/scripts/doctor.cjs <args...>`. If the plugin is
|
|
25
|
+
* not installed, says so plainly instead of throwing a node stack.
|
|
26
|
+
* update Bring MindrianOS current. For a marketplace install: `claude plugin
|
|
27
|
+
* marketplace update` + `claude plugin update mos@mindrian-marketplace`.
|
|
28
|
+
* For a dev clone (MINDRIAN_OS_ROOT set): `git -C <root> pull --ff-only`
|
|
29
|
+
* + `bash <root>/install.sh`.
|
|
29
30
|
*
|
|
30
31
|
* GSD pattern: pure CJS, node built-ins only, zero npm deps. No CLI framework
|
|
31
32
|
* (no commander/yargs/meow). process.argv switch-case routing, mirroring
|
|
32
33
|
* bin/mindrian-tools.cjs and ~/.claude/get-shit-done/bin/gsd-tools.cjs.
|
|
33
34
|
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
35
|
+
* Plugin-root resolution is delegated to lib/core/active-plugin-root.cjs (the
|
|
36
|
+
* single source of truth: MINDRIAN_OS_ROOT -> installed_plugins.json -> newest
|
|
37
|
+
* marketplace-cache mos/<version>/ -> legacy clone -> not-found). doctor and
|
|
38
|
+
* update both read from it; scripts/statusline-mos shells out to its CLI form.
|
|
36
39
|
*/
|
|
37
40
|
|
|
38
41
|
const { spawnSync } = require('node:child_process');
|
|
39
42
|
const path = require('node:path');
|
|
40
43
|
const os = require('node:os');
|
|
44
|
+
const fs = require('node:fs');
|
|
45
|
+
// The ONE plugin-root resolver: installed_plugins.json (temporal truth) first,
|
|
46
|
+
// then the pre-release-tolerant marketplace-cache scan, then a legacy clone.
|
|
47
|
+
const { resolveActivePluginRoot } = require('../lib/core/active-plugin-root.cjs');
|
|
41
48
|
|
|
42
|
-
const
|
|
43
|
-
|
|
49
|
+
const MARKETPLACE = 'jsagir/mindrian-marketplace';
|
|
50
|
+
const PLUGIN_SPEC = 'mos@mindrian-marketplace';
|
|
44
51
|
|
|
45
52
|
function run(cmd, args, opts) {
|
|
46
53
|
return spawnSync(cmd, args, { stdio: 'inherit', ...opts });
|
|
47
54
|
}
|
|
48
55
|
|
|
56
|
+
function ok(result) {
|
|
57
|
+
return result && typeof result.status === 'number' && result.status === 0;
|
|
58
|
+
}
|
|
59
|
+
|
|
49
60
|
function exitFrom(result) {
|
|
50
61
|
// spawnSync sets status=null when the process was killed by a signal or
|
|
51
62
|
// failed to launch; treat that as a generic failure.
|
|
52
63
|
process.exit(result && typeof result.status === 'number' ? result.status : 1);
|
|
53
64
|
}
|
|
54
65
|
|
|
66
|
+
function hasDoctor(dir) {
|
|
67
|
+
try {
|
|
68
|
+
return !!dir && fs.existsSync(path.join(dir, 'scripts', 'doctor.cjs'));
|
|
69
|
+
} catch {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
55
74
|
function printUsage() {
|
|
56
75
|
console.log('mindrian-os <install|doctor|update> (no subcommand = install)');
|
|
57
|
-
console.log(' install install
|
|
58
|
-
console.log(' doctor run the MindrianOS install/drift diagnostic (
|
|
59
|
-
console.log(' update
|
|
76
|
+
console.log(' install install / bring current via Claude Code (marketplace add + plugin install/update)');
|
|
77
|
+
console.log(' doctor run the MindrianOS install/drift diagnostic (passes flags through to /mos:doctor)');
|
|
78
|
+
console.log(' update bring MindrianOS current (marketplace update + plugin update; or git pull for a dev clone)');
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function requireClaudeCli() {
|
|
82
|
+
const check = spawnSync('claude', ['--version'], { stdio: 'ignore' });
|
|
83
|
+
if (ok(check)) return true;
|
|
84
|
+
console.error('Claude Code is not installed (no `claude` command on your PATH).');
|
|
85
|
+
console.error('Install it first:');
|
|
86
|
+
console.error(' npm install -g @anthropic-ai/claude-code');
|
|
87
|
+
console.error('Then re-run:');
|
|
88
|
+
console.error(' npx @mindrian_os/install');
|
|
89
|
+
return false;
|
|
60
90
|
}
|
|
61
91
|
|
|
62
92
|
// No subcommand, or flags only (e.g. `npx @mindrian_os/install --version 1.13.0-beta.9`),
|
|
@@ -70,68 +100,95 @@ if (!sub || sub.startsWith('-')) {
|
|
|
70
100
|
|
|
71
101
|
switch (sub) {
|
|
72
102
|
case 'doctor': {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
103
|
+
const { root } = resolveActivePluginRoot();
|
|
104
|
+
if (!root || !hasDoctor(root)) {
|
|
105
|
+
console.error('MindrianOS does not appear to be installed (could not find scripts/doctor.cjs).');
|
|
106
|
+
console.error('Looked under: ' + path.join(os.homedir(), '.claude', 'plugins') + (process.env.MINDRIAN_OS_ROOT ? ' and $MINDRIAN_OS_ROOT' : ''));
|
|
107
|
+
console.error('Install it first:');
|
|
108
|
+
console.error(' npx @mindrian_os/install');
|
|
109
|
+
process.exit(1);
|
|
110
|
+
}
|
|
111
|
+
const r = run(process.execPath, [path.join(root, 'scripts', 'doctor.cjs'), ...process.argv.slice(argOffset)]);
|
|
76
112
|
exitFrom(r);
|
|
77
113
|
break;
|
|
78
114
|
}
|
|
79
115
|
|
|
80
116
|
case 'update': {
|
|
81
|
-
//
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
117
|
+
// Dev clone (MINDRIAN_OS_ROOT or a legacy hand-clone): git pull + re-run install.sh.
|
|
118
|
+
const { root } = resolveActivePluginRoot();
|
|
119
|
+
const isDevClone = !!process.env.MINDRIAN_OS_ROOT
|
|
120
|
+
|| (root && fs.existsSync(path.join(root, '.git')) && fs.existsSync(path.join(root, 'install.sh')));
|
|
121
|
+
if (isDevClone && root) {
|
|
122
|
+
run('git', ['-C', root, 'pull', '--ff-only']);
|
|
123
|
+
const r = run('bash', [path.join(root, 'install.sh')]);
|
|
124
|
+
exitFrom(r);
|
|
125
|
+
break;
|
|
126
|
+
}
|
|
127
|
+
// Marketplace install: use Claude Code's own update path.
|
|
128
|
+
if (!requireClaudeCli()) process.exit(1);
|
|
129
|
+
console.log('Refreshing the marketplace catalog...');
|
|
130
|
+
run('claude', ['plugin', 'marketplace', 'update']);
|
|
131
|
+
console.log('Updating the MindrianOS plugin...');
|
|
132
|
+
const r = run('claude', ['plugin', 'update', PLUGIN_SPEC]);
|
|
133
|
+
if (!ok(r)) {
|
|
134
|
+
console.error('');
|
|
135
|
+
console.error('`claude plugin update ' + PLUGIN_SPEC + '` did not complete.');
|
|
136
|
+
console.error('Try inside Claude Code: /plugin marketplace update then /plugin update ' + PLUGIN_SPEC);
|
|
137
|
+
exitFrom(r);
|
|
138
|
+
}
|
|
139
|
+
console.log('');
|
|
140
|
+
console.log('MindrianOS is up to date. Run `claude plugin list` to confirm the version.');
|
|
141
|
+
console.log('Verify: mindrian-os doctor (or /mos:doctor inside Claude Code)');
|
|
142
|
+
process.exit(0);
|
|
86
143
|
break;
|
|
87
144
|
}
|
|
88
145
|
|
|
89
146
|
case 'install': {
|
|
90
|
-
// Path B: actually install MindrianOS by driving Claude Code's plugin CLI.
|
|
91
|
-
// Registers the Mindrian marketplace, then `claude plugin install mos@...`.
|
|
92
147
|
// Flags after `install` (or leading flags when `install` is implied) pass
|
|
93
|
-
// through to `claude plugin install` (e.g. `...
|
|
148
|
+
// through to `claude plugin install` (e.g. `... --version 1.13.0-beta.9`).
|
|
94
149
|
const passthrough = process.argv.slice(argOffset);
|
|
150
|
+
const pinned = passthrough.some((a) => a === '--version' || a.startsWith('--version='));
|
|
95
151
|
|
|
96
|
-
|
|
97
|
-
const claudeCheck = spawnSync('claude', ['--version'], { stdio: 'ignore' });
|
|
98
|
-
if (!claudeCheck || claudeCheck.status !== 0) {
|
|
99
|
-
console.error('Claude Code is not installed (no `claude` command on your PATH).');
|
|
100
|
-
console.error('Install it first:');
|
|
101
|
-
console.error(' npm install -g @anthropic-ai/claude-code');
|
|
102
|
-
console.error('Then re-run:');
|
|
103
|
-
console.error(' npx @mindrian_os/install');
|
|
104
|
-
process.exit(1);
|
|
105
|
-
}
|
|
152
|
+
if (!requireClaudeCli()) process.exit(1);
|
|
106
153
|
|
|
107
|
-
//
|
|
108
|
-
//
|
|
109
|
-
//
|
|
154
|
+
// Register the Mindrian marketplace (idempotent) and refresh its catalog so
|
|
155
|
+
// we resolve the current ref. Both are best-effort -- "already added" /
|
|
156
|
+
// "already up to date" exit non-zero on some Claude Code versions; fine.
|
|
110
157
|
console.log('Adding the Mindrian marketplace...');
|
|
111
|
-
run('claude', ['plugin', 'marketplace', 'add',
|
|
158
|
+
run('claude', ['plugin', 'marketplace', 'add', MARKETPLACE]);
|
|
159
|
+
console.log('Refreshing the marketplace catalog...');
|
|
160
|
+
run('claude', ['plugin', 'marketplace', 'update']);
|
|
112
161
|
|
|
113
|
-
//
|
|
162
|
+
// Install. On an already-installed plugin Claude Code reports "already
|
|
163
|
+
// installed" and still exits 0 -- the update step below then moves it
|
|
164
|
+
// forward to the current ref (unless the caller pinned a version).
|
|
114
165
|
console.log('Installing the MindrianOS plugin...');
|
|
115
|
-
const inst = run('claude', ['plugin', 'install',
|
|
116
|
-
|
|
166
|
+
const inst = run('claude', ['plugin', 'install', PLUGIN_SPEC, ...passthrough]);
|
|
167
|
+
let updated = false;
|
|
168
|
+
if (!pinned) {
|
|
169
|
+
console.log('Bringing the plugin to the current build...');
|
|
170
|
+
const upd = run('claude', ['plugin', 'update', PLUGIN_SPEC]);
|
|
171
|
+
updated = ok(upd);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
if (!ok(inst) && !updated) {
|
|
117
175
|
console.error('');
|
|
118
|
-
console.error('
|
|
176
|
+
console.error('Installing ' + PLUGIN_SPEC + ' did not complete.');
|
|
119
177
|
console.error('Finish it by hand inside Claude Code:');
|
|
120
|
-
console.error(' /plugin marketplace add
|
|
121
|
-
console.error(' /plugin install
|
|
178
|
+
console.error(' /plugin marketplace add ' + MARKETPLACE);
|
|
179
|
+
console.error(' /plugin install ' + PLUGIN_SPEC);
|
|
122
180
|
exitFrom(inst);
|
|
123
181
|
}
|
|
124
182
|
|
|
125
|
-
// 4. Done. Point at the Brain key + first run.
|
|
126
183
|
console.log('');
|
|
127
|
-
console.log('MindrianOS installed.');
|
|
184
|
+
console.log('MindrianOS is installed and current. Run `claude plugin list` to see the version.');
|
|
128
185
|
console.log('');
|
|
129
186
|
console.log('Optional -- connect the Brain for enriched intelligence:');
|
|
130
187
|
console.log(' inside Claude Code: /mos:setup (choose "Configure Brain", paste your key)');
|
|
131
188
|
console.log(' or set it directly: export MINDRIAN_BRAIN_KEY="<your-key>" (or add it to ~/.claude/.env)');
|
|
132
189
|
console.log('');
|
|
133
190
|
console.log('Verify: mindrian-os doctor (or /mos:doctor inside Claude Code)');
|
|
134
|
-
console.log('Start:
|
|
191
|
+
console.log('Start: open a fresh Claude Code session, then /mos:onboard');
|
|
135
192
|
process.exit(0);
|
|
136
193
|
break;
|
|
137
194
|
}
|
package/commands/act.md
CHANGED
|
@@ -211,9 +211,23 @@ Display the thinking trace (Step 4) and the execution plan following the dry-run
|
|
|
211
211
|
Run /mos:act to execute this plan.
|
|
212
212
|
```
|
|
213
213
|
|
|
214
|
-
### Chain Mode (`/mos:act --chain`)
|
|
214
|
+
### Chain Mode (`/mos:act --chain`) -- the autonomy gate
|
|
215
215
|
|
|
216
|
-
|
|
216
|
+
**Before anything else in `--chain` mode, plan + autonomy-gate the chain through the resolver:**
|
|
217
|
+
|
|
218
|
+
```bash
|
|
219
|
+
node "${CLAUDE_PLUGIN_ROOT}/scripts/act-command.cjs" --chain --room ./room
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
The helper picks the framework chain for the room state via `lib/brain/chain-recommender.cjs` `recommendFrameworkChain` (a FEEDS_INTO traversal -- framework names + problem-type enums only; Canon Part 8: never a command string, never user content), composes it into `/mos:` commands via `lib/workflow/command-resolver.cjs` `composeWorkflow` (the SOLE framework -> command path, reading only the generated `data/command-registry.json`), calls `validateChainAutonomy(workflow)` FIRST, then walks the steps in order. At the FIRST step whose command is not `autonomous_safe: true` (or whose framework has no `/mos:` command at all), it STOPS and renders a "needs you here" gate (a Shape F.0 / E action report: "[GATE] Chain reached step N: /mos:x for <framework>. This step is not autonomous_safe -- it needs your eyes. [continue] [stop]"). You then:
|
|
223
|
+
- run the `autonomous_safe` prefix steps unattended (dispatch `agents/framework-runner.md` per step, with the checkpoint pause between steps as below),
|
|
224
|
+
- at the gate step, do NOT run it autonomously -- surface the gate to the user and wait. `[continue]` = the user runs that step themselves (or approves running it), then resume the chain from the next step. `[stop]` = halt; what ran above is filed.
|
|
225
|
+
|
|
226
|
+
You NEVER name a `/mos:` command in `--chain` mode from memory and you NEVER decide a step is safe to run unattended from memory -- the command came back from the resolver and the autonomy decision came back from `validateChainAutonomy` / `data/command-registry.json`'s `autonomous_safe` field. `--chain --from-framework <x>` / `--chain --problem-type <x>` seed the chain explicitly.
|
|
227
|
+
|
|
228
|
+
Then, for the steps the helper greenlit:
|
|
229
|
+
|
|
230
|
+
1. Select 3-5 frameworks using the chain selection logic (the helper already did this via the recommender; this list is the same chain):
|
|
217
231
|
- First framework: targets weakest section or most pressing gap
|
|
218
232
|
- Subsequent frameworks: build on previous, guided by Brain `FEEDS_INTO` relationships or natural progression (Exploration -> Analysis -> Synthesis -> Validation)
|
|
219
233
|
- Never select redundant frameworks
|
package/commands/pipeline.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: pipeline
|
|
3
3
|
description: Chain a multi-step methodology pipeline
|
|
4
|
-
argument-hint: [pipeline-name]
|
|
4
|
+
argument-hint: '[pipeline-name] [--from-problem-type <x>] [--from-framework <x>]'
|
|
5
5
|
serves_jtbd: ["plan-execution"]
|
|
6
6
|
# --- Phase 122 workflow-layer frontmatter ---
|
|
7
7
|
kind: meta
|
|
@@ -20,6 +20,18 @@ allowed-tools:
|
|
|
20
20
|
|
|
21
21
|
You are Larry. This command orchestrates multi-step methodology chains -- connected sequences where each framework's output feeds the next as structured input.
|
|
22
22
|
|
|
23
|
+
## Brain-Derived Chains -- `--from-problem-type <x>` / `--from-framework <x>`
|
|
24
|
+
|
|
25
|
+
`/mos:pipeline --from-problem-type ill-defined` (or `--from-framework "Beautiful Question Framework"`) does NOT run a static named pipeline -- it Brain-derives the framework chain and runs the resolver-composed `/mos:` command sequence end to end:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
node "${CLAUDE_PLUGIN_ROOT}/scripts/pipeline-command.cjs" --from-problem-type ill-defined --room ./room
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
The helper calls `lib/brain/chain-recommender.cjs` `recommendFrameworkChain` (a FEEDS_INTO traversal -- framework names + problem-type enums only; Canon Part 8: never a command string, never user content), composes that chain into `/mos:` commands via `lib/workflow/command-resolver.cjs` `composeWorkflow` (the SOLE framework -> command path, reading only the generated `data/command-registry.json`), and prints the run order. Then run the printed `/mos:` commands in sequence using the Stage Execution Loop machinery below -- one resolved command per step. For a step whose framework has no `/mos:` command, the helper prints "no /mos: for <framework> -- run it manually; continuing"; skip that step (or run the framework manually) and continue. Every command the helper prints exists in the registry -- the resolver only ever returns registered commands, so you never invoke a `/mos:` that does not exist.
|
|
32
|
+
|
|
33
|
+
`--from-problem-type` accepts the canonical `UDP` / `IDP` / `WDP` tokens and the `undefined` / `ill-defined` / `well-defined` aliases. With neither flag and no named pipeline, the helper falls back to the room's `ProblemType` from `room/STATE.md`.
|
|
34
|
+
|
|
23
35
|
## Brain Enhancement (Optional)
|
|
24
36
|
|
|
25
37
|
Try calling Brain: first `mcp__mindrian-brain__brain_schema`, then `mcp__mindrian-brain__get_neo4j_schema` as fallback. If it succeeds, Brain mode is active. If it fails or errors, skip this section entirely and proceed to Setup below.
|
|
@@ -45,6 +57,9 @@ Proceed to Setup below with this additional context. Static chains remain the de
|
|
|
45
57
|
|
|
46
58
|
### Chain Selection
|
|
47
59
|
|
|
60
|
+
**If user passes `--from-problem-type <x>` or `--from-framework <x>`:**
|
|
61
|
+
Run the helper above (`scripts/pipeline-command.cjs`) to Brain-derive the chain and get the resolver-composed `/mos:` run order, then execute those commands in sequence via the Stage Execution Loop. This is the dynamic, graph-derived path -- no `CHAIN.md` file involved.
|
|
62
|
+
|
|
48
63
|
**If user specifies a pipeline name** (e.g., `/mos:pipeline discovery`):
|
|
49
64
|
Load `pipelines/{name}/CHAIN.md` and proceed to Stage 1.
|
|
50
65
|
|
package/commands/suggest-next.md
CHANGED
|
@@ -17,9 +17,23 @@ allowed-tools:
|
|
|
17
17
|
|
|
18
18
|
# /mos:suggest-next
|
|
19
19
|
|
|
20
|
-
You are Larry. This command
|
|
20
|
+
You are Larry. This command recommends what the user should work on next as a COMMAND SEQUENCE, not just a list of frameworks: it reads the room's ProblemType (and active JTBD), Brain-derives the framework chain, and composes that chain into the exact `/mos:` commands to run, in order.
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
## The resolver is the only door
|
|
23
|
+
|
|
24
|
+
Run the helper to get the resolver-composed command sequence:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
node "${CLAUDE_PLUGIN_ROOT}/scripts/suggest-next-command.cjs" --room ./room
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
It reads `room/STATE.md` for the ProblemType / active JTBD (or pass `--problem-type <x>` / `--from-framework <x>` explicitly), calls `lib/brain/chain-recommender.cjs` `recommendFrameworkChain` (a FEEDS_INTO traversal -- framework names + problem-type enums only; Canon Part 8: never a command string, never user content), composes the chain into `/mos:` commands via `lib/workflow/command-resolver.cjs` `composeWorkflow` (the SOLE framework -> command path, reading only the generated `data/command-registry.json`), and prints BOTH the framework chain AND the step-numbered command sequence. A framework with no `/mos:` yet renders as "(no /mos: for this -- run it manually)" -- degrade, do not fabricate.
|
|
31
|
+
|
|
32
|
+
**Larry NEVER names a `/mos:` command from memory.** Every command you surface came back from the resolver via this helper. If you find yourself about to type a `/mos:` you have not seen the resolver return, stop -- run the helper first. Render in Shape B (Semantic Tree) per `skills/ui-system/SKILL.md`; do not invent a format.
|
|
33
|
+
|
|
34
|
+
When Brain is connected you may additionally weave the co-occurrence narrative below; when it is not, the helper still produces a true command sequence from the registry (framework-only advice degrades gracefully -- still through the resolver).
|
|
35
|
+
|
|
36
|
+
**Note on Brain MCP:** the deeper "similar venture patterns" enrichment below benefits from Brain. If Brain is not available, skip those queries -- the resolver-composed sequence above still stands.
|
|
23
37
|
|
|
24
38
|
## Setup
|
|
25
39
|
|
|
@@ -61,7 +75,7 @@ Combine both query results. Present 2-3 next steps ranked by:
|
|
|
61
75
|
- Co-occurrence patterns from similar ventures
|
|
62
76
|
|
|
63
77
|
For each recommendation:
|
|
64
|
-
- **What to do:** Name the framework
|
|
78
|
+
- **What to do:** Name the framework AND the specific `/mos:` command -- but take the command from the helper's resolver-composed sequence above (or `lib/workflow/command-resolver.cjs` `commandsForFramework(<framework>)`), never from memory. If a framework has no command, say "run <framework> manually -- there is no /mos: for it" rather than inventing one.
|
|
65
79
|
- **Why this sequence:** Cite the relationship type from the graph (e.g., "Explore Domains FEEDS_INTO Analyze Needs with 0.85 confidence -- mapping the landscape first sharpens your customer discovery")
|
|
66
80
|
- **What similar ventures did:** Reference co-occurrence data ("Projects that used Beautiful Question most commonly followed with Explore Domains or Map Unknowns")
|
|
67
81
|
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
/*
|
|
3
|
+
* lib/core/active-plugin-root.cjs -- the ONE resolver for "where is the active
|
|
4
|
+
* MindrianOS plugin install on this machine?"
|
|
5
|
+
*
|
|
6
|
+
* Background: before this module, three different places guessed independently
|
|
7
|
+
* (bin/cli.js hardcoded a legacy path; scripts/statusline-mos did `ls cache |
|
|
8
|
+
* sort -V` with a pure-semver regex that rejected `-beta.N`; context-monitor
|
|
9
|
+
* inherited whatever those picked). Three guessers, three failure modes -- a box
|
|
10
|
+
* with 1.12.0 + 1.13.0-beta.9 in the cache ended up rendering the statusline,
|
|
11
|
+
* the version banner, and MINDRIAN_OS_ROOT from the wrong (older) version. This
|
|
12
|
+
* collapses them into one source of truth.
|
|
13
|
+
*
|
|
14
|
+
* Precedence (first hit wins):
|
|
15
|
+
* 1. MINDRIAN_OS_ROOT env var -- tests, dev boxes, hand clones.
|
|
16
|
+
* 2. ~/.claude/plugins/installed_plugins.json
|
|
17
|
+
* -- Claude Code's own registry of the
|
|
18
|
+
* ACTIVE install of mos@mindrian-marketplace.
|
|
19
|
+
* Temporal truth: it knows which one is
|
|
20
|
+
* current even when "highest semver" is not
|
|
21
|
+
* the active one (e.g. a pinned older version).
|
|
22
|
+
* 3. ~/.claude/plugins/cache/<marketplace>/mos/<version>/
|
|
23
|
+
* -- newest valid version dir; pre-release
|
|
24
|
+
* tolerant (`sort -V` ordering). Fallback
|
|
25
|
+
* for when installed_plugins.json is missing
|
|
26
|
+
* or unparseable.
|
|
27
|
+
* 4. ~/.claude/plugins/mindrian-os/ -- legacy hand-clone layout.
|
|
28
|
+
* 5. null -- not installed.
|
|
29
|
+
*
|
|
30
|
+
* Use as a module:
|
|
31
|
+
* const { resolveActivePluginRoot } = require('<...>/lib/core/active-plugin-root.cjs');
|
|
32
|
+
* const { root, source } = resolveActivePluginRoot(); // root may be null
|
|
33
|
+
*
|
|
34
|
+
* Use as a CLI (so a bash wrapper -- e.g. scripts/statusline-mos -- can shell out):
|
|
35
|
+
* node active-plugin-root.cjs -> prints the resolved path, or nothing; exit 0 if found, 1 if not
|
|
36
|
+
* node active-plugin-root.cjs --json -> prints {"root": "<path|null>", "source": "<...>"}
|
|
37
|
+
*
|
|
38
|
+
* Canon Part 8: this reads LOCAL files only (~/.claude/plugins/). Zero network.
|
|
39
|
+
*/
|
|
40
|
+
|
|
41
|
+
const fs = require('node:fs');
|
|
42
|
+
const path = require('node:path');
|
|
43
|
+
const os = require('node:os');
|
|
44
|
+
|
|
45
|
+
const PLUGIN_KEYS = ['mos', 'mindrian-os']; // accept either marketplace plugin name
|
|
46
|
+
|
|
47
|
+
// A valid plugin install dir has a .claude-plugin/plugin.json.
|
|
48
|
+
function isPluginDir(dir) {
|
|
49
|
+
try {
|
|
50
|
+
return !!dir && fs.statSync(dir).isDirectory() && fs.existsSync(path.join(dir, '.claude-plugin', 'plugin.json'));
|
|
51
|
+
} catch {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function fromInstalledPlugins(home) {
|
|
57
|
+
// Shape (Claude Code 2.x):
|
|
58
|
+
// { "version": N, "plugins": { "mos@mindrian-marketplace": [ { "installPath": "...", ... } ], ... } }
|
|
59
|
+
// Defensive: the key might be just "mos"; the value might be an object not a
|
|
60
|
+
// 1-element array; the path field might be installPath / path / dir.
|
|
61
|
+
const file = path.join(home, '.claude', 'plugins', 'installed_plugins.json');
|
|
62
|
+
let data;
|
|
63
|
+
try {
|
|
64
|
+
data = JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
65
|
+
} catch {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
const plugins = (data && (data.plugins || data)) || {};
|
|
69
|
+
for (const key of Object.keys(plugins)) {
|
|
70
|
+
const name = String(key).split('@')[0];
|
|
71
|
+
if (!PLUGIN_KEYS.includes(name)) continue;
|
|
72
|
+
let entry = plugins[key];
|
|
73
|
+
if (Array.isArray(entry)) entry = entry[0];
|
|
74
|
+
if (!entry || typeof entry !== 'object') continue;
|
|
75
|
+
const p = entry.installPath || entry.path || entry.dir;
|
|
76
|
+
if (p && isPluginDir(p)) return p;
|
|
77
|
+
}
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function fromMarketplaceCache(home) {
|
|
82
|
+
const cacheBase = path.join(home, '.claude', 'plugins', 'cache');
|
|
83
|
+
let marketplaces;
|
|
84
|
+
try {
|
|
85
|
+
marketplaces = fs.readdirSync(cacheBase, { withFileTypes: true });
|
|
86
|
+
} catch {
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
const found = [];
|
|
90
|
+
for (const mk of marketplaces) {
|
|
91
|
+
if (!mk.isDirectory()) continue;
|
|
92
|
+
for (const pluginName of PLUGIN_KEYS) {
|
|
93
|
+
const pluginDir = path.join(cacheBase, mk.name, pluginName);
|
|
94
|
+
let versions;
|
|
95
|
+
try {
|
|
96
|
+
versions = fs.readdirSync(pluginDir, { withFileTypes: true });
|
|
97
|
+
} catch {
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
for (const v of versions) {
|
|
101
|
+
if (!v.isDirectory()) continue;
|
|
102
|
+
const candidate = path.join(pluginDir, v.name);
|
|
103
|
+
if (isPluginDir(candidate)) found.push({ dir: candidate, ver: v.name });
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
if (!found.length) return null;
|
|
108
|
+
// `localeCompare` numeric ordering matches `sort -V` for the cases we care
|
|
109
|
+
// about: 1.12.0 < 1.12.5.1 < 1.13.0-beta.9 < 1.13.0-beta.11 < 1.13.0.
|
|
110
|
+
found.sort((a, b) => String(a.ver).localeCompare(String(b.ver), undefined, { numeric: true }));
|
|
111
|
+
return found[found.length - 1].dir;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function fromLegacyClone(home) {
|
|
115
|
+
const legacy = path.join(home, '.claude', 'plugins', 'mindrian-os');
|
|
116
|
+
return isPluginDir(legacy) ? legacy : null;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function resolveActivePluginRoot() {
|
|
120
|
+
const envRoot = process.env.MINDRIAN_OS_ROOT;
|
|
121
|
+
if (envRoot) return { root: envRoot, source: 'MINDRIAN_OS_ROOT' };
|
|
122
|
+
|
|
123
|
+
const home = os.homedir();
|
|
124
|
+
let r;
|
|
125
|
+
if ((r = fromInstalledPlugins(home))) return { root: r, source: 'installed_plugins.json' };
|
|
126
|
+
if ((r = fromMarketplaceCache(home))) return { root: r, source: 'marketplace-cache' };
|
|
127
|
+
if ((r = fromLegacyClone(home))) return { root: r, source: 'legacy-clone' };
|
|
128
|
+
return { root: null, source: 'not-found' };
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
module.exports = { resolveActivePluginRoot };
|
|
132
|
+
|
|
133
|
+
// CLI entry point.
|
|
134
|
+
if (require.main === module) {
|
|
135
|
+
const out = resolveActivePluginRoot();
|
|
136
|
+
if (process.argv.includes('--json')) {
|
|
137
|
+
process.stdout.write(JSON.stringify(out) + '\n');
|
|
138
|
+
} else if (out.root) {
|
|
139
|
+
process.stdout.write(out.root + '\n');
|
|
140
|
+
}
|
|
141
|
+
process.exit(out.root ? 0 : 1);
|
|
142
|
+
}
|