@mindrian_os/install 1.13.0-beta.16 → 1.13.0-beta.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/CHANGELOG.md +10 -0
  3. package/commands/file-meeting.md +2 -0
  4. package/commands/grade.md +2 -0
  5. package/commands/mva-brief.md +56 -0
  6. package/commands/mva-option.md +89 -0
  7. package/commands/new-project.md +2 -0
  8. package/commands/onboard.md +2 -0
  9. package/hooks/hooks.json +9 -0
  10. package/lib/agents/mva/brain-classic-traps.cjs +77 -0
  11. package/lib/agents/mva/brain-cross-domain.cjs +79 -0
  12. package/lib/agents/mva/brain-similar-ventures.cjs +93 -0
  13. package/lib/agents/mva/dashboard-graph-neighborhood.cjs +72 -0
  14. package/lib/agents/mva/index.cjs +42 -0
  15. package/lib/agents/mva/six-hats-red-black.cjs +137 -0
  16. package/lib/agents/mva/tavily-funding-scan.cjs +147 -0
  17. package/lib/agents/mva/test-all-six-agents.cjs +467 -0
  18. package/lib/conversation/operator.cjs +64 -0
  19. package/lib/conversation/operator.test.cjs +160 -0
  20. package/lib/core/mva-agent-contract.cjs +170 -0
  21. package/lib/core/mva-agent-contract.test.cjs +169 -0
  22. package/lib/core/mva-budget.cjs +75 -0
  23. package/lib/core/mva-budget.test.cjs +68 -0
  24. package/lib/core/mva-classifier.cjs +370 -0
  25. package/lib/core/mva-classifier.test.cjs +248 -0
  26. package/lib/core/mva-deck-builder.cjs +452 -0
  27. package/lib/core/mva-deck-builder.test.cjs +287 -0
  28. package/lib/core/mva-detect.smoke.test.cjs +197 -0
  29. package/lib/core/mva-dispatcher.cjs +110 -0
  30. package/lib/core/mva-dispatcher.test.cjs +216 -0
  31. package/lib/core/mva-option-router.cjs +292 -0
  32. package/lib/core/mva-option-router.test.cjs +483 -0
  33. package/lib/core/mva-orchestrator.cjs +324 -0
  34. package/lib/core/mva-orchestrator.test.cjs +908 -0
  35. package/lib/core/mva-progressive-renderer.cjs +194 -0
  36. package/lib/core/mva-progressive-renderer.test.cjs +157 -0
  37. package/lib/core/mva-rule-linter.cjs +213 -0
  38. package/lib/core/mva-rule-linter.test.cjs +336 -0
  39. package/lib/core/mva-state.cjs +159 -0
  40. package/lib/core/mva-telemetry.cjs +170 -0
  41. package/lib/core/mva-telemetry.test.cjs +196 -0
  42. package/lib/core/mva-vercel-deploy.cjs +168 -0
  43. package/lib/core/mva-vercel-deploy.test.cjs +239 -0
  44. package/lib/core/navigation/dashboard-helpers.cjs +145 -0
  45. package/lib/core/navigation.cjs +11 -0
  46. package/lib/core/resolve-vercel-key.cjs +107 -0
  47. package/lib/core/resolve-vercel-key.test.cjs +137 -0
  48. package/lib/memory/run-feynman-tests.cjs +27 -0
  49. package/package.json +1 -1
  50. package/skills/mva-pipeline/SKILL.md +129 -0
@@ -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.16",
4
+ "version": "1.13.0-beta.17",
5
5
  "author": {
6
6
  "name": "Jonathan Sagir",
7
7
  "url": "https://mindrian.ai"
package/CHANGELOG.md CHANGED
@@ -1,3 +1,13 @@
1
+ ## [1.13.0-beta.17] - 2026-05-15
2
+
3
+ ### Fixed
4
+ - **Step 6.6 ordering hole (Bug 1 -- Phase 126.1 hotfix, 2026-05-15).** Phase 126 beta.16 hotfix `3fc008b` moved `verify-release-clean-tree` from `applies_to: ['pre-tag', 'full']` to `['full']` because `release.sh` Step 6.6 calls `--pre-tag` AFTER Steps 3-6 intentionally bump `plugin.json` + `package.json` + `CHANGELOG.md`. That made the cut sail through, but the strict clean-tree gate no longer ran pre-tag AND Test 2 of `tests/test-doctor-acceptance-preflight-checks.cjs` was converted to SKIP rather than re-pointed. Real gap, predicted by `docs/install-cache-family-premortem.md` Section 3. Fix (Option B): added a new `pre-flight` tier to the `applies_to` enum (strict subset of `pre-tag` minus in-flight-incompatible checks); added the `--pre-flight` CLI flag to `scripts/doctor.cjs`; added Step 2.5 to `scripts/release.sh` calling `doctor --acceptance --pre-flight` BEFORE Step 3 mutates the tree (HARD ABORT, no rollback needed because nothing is yet mutated); kept the existing Step 6.6 `--pre-tag` call after Step 6 (still the right tier for post-bump checks). Restored Test 2 from SKIP to PASS under the new tier; added Test 8 asserting tier filter behavior. (`scripts/doctor.cjs`, `scripts/release.sh`, `tests/test-doctor-acceptance-preflight-checks.cjs`.)
5
+ - **Commit B 7-place lockstep gap (Bug 2 -- Phase 126.1 hotfix, 2026-05-15).** `scripts/release.sh` Step 7.5 (Commit B, the next-pre-release advance) bumped `plugin.json` + `package.json` to `NEXT_VERSION` but left `~/mindrian-marketplace/.claude-plugin/marketplace.json` at `vN`. Per `feedback_install_minisite_lockstep.md`, the 7-place lockstep contract requires the marketplace.json `version` field to advance with the plugin repo. The bug recurred in beta.16. Fix: Step 7.5 now writes a second `node -e` block that bumps `MARKETPLACE_DIR/.claude-plugin/marketplace.json` to `NEXT_VERSION` (version field only -- `source.ref` deliberately stays at `vNEW_VERSION` pinning the marketplace commit at Commit A's tag); parallel marketplace-repo `git commit` follows with message `chore: bump marketplace.json to v$NEXT_VERSION (Commit B 7-place lockstep)`. Test H asserts the bump pattern is present in `scripts/release.sh`. (`scripts/release.sh`, `tests/test-release-bump-algebra.cjs`.)
6
+ - **Step 9.7 npx-publish self-test sandbox bug (Bug 3 -- Phase 126.1 hotfix, 2026-05-15).** `scripts/release.sh` Step 9.7 ran `npx --yes @mindrian_os/install@<version>` from an `mktemp -d` temp dir and checked the dir was non-empty after install -- but `@mindrian_os/install` installs into `~/.claude/` (the Claude Code plugin install root), NOT into cwd, so the temp-dir check spuriously failed during the beta.16 cut. Fix (Option A): switched to a HOME-override sandbox at `~/.claude/_test-install-<sha8>/` (subpath under `~/.claude/` per scope; mirrors the Phase 123 `doctor.cjs:2336` sandbox pattern). The npx run sets `HOME=$NPX_TEST_DIR` + `USERPROFILE=$NPX_TEST_DIR` + `npm_config_cache=$NPX_TEST_DIR/.npm` so the install resolves into the sandbox subpath, never touching the operator's real `~/.claude/`. Scaffold marker check now asserts `$NPX_TEST_DIR/.claude/plugins/installed_plugins.json` exists AND is parseable JSON. `trap` cleanup guarantees the sandbox dir + the pre-snapshot file are removed even on abort. Option B (extend `~/mindrianos-install-site` npm-installer with a `--target=<dir>` flag) is the cleaner long-term fix but out of scope for this hotfix (separate repo). Test I asserts the sandbox path + HOME-override are present in `scripts/release.sh` and the legacy `mktemp -d -t mos-npx-selftest` pattern is gone. (`scripts/release.sh`, `tests/test-release-bump-algebra.cjs`.)
7
+
8
+ ### Changed
9
+ - **Phase 122 `teaching:` frontmatter on `/mos:mva-brief` + `/mos:mva-option` verified clean (Phase 126.1 hotfix audit, 2026-05-15).** Per `118/deferred-items.md` lines 5-20 the two MVA helper commands lacked `teaching:` strings as of Plan 118-06. Inspection found the strings were already added between then and now (`commands/mva-brief.md` line 6: 200 chars; `commands/mva-option.md` line 6: 180 chars). All four Phase 122 invariants verified: length 50-300 chars (200 + 180), zero em-dashes (`grep -nP "[—–]"` empty), 1-2 sentences each (terminal `.`), Larry-voice with WHY lede. `node scripts/build-command-registry.cjs --check` exits 0. No edits required; verification-only commit. The pre-existing `118/deferred-items.md` "Pre-existing build-command-registry teaching-field gap" entry can be marked RESOLVED in a follow-up. (`commands/mva-brief.md`, `commands/mva-option.md`.)
10
+
1
11
  ## [1.13.0-beta.16] - 2026-05-14
2
12
 
3
13
  ### Added
@@ -4,6 +4,8 @@ description: File a meeting transcript into the Data Room
4
4
  argument-hint: [--latest|--paste|<file>]
5
5
  serves_jtbd: ["file-meeting"]
6
6
  teaching: "When a meeting just happened, /mos:file-meeting captures the transcript and routes the intelligence into the right room sections. Meetings are where institutional knowledge actually lives."
7
+ # Per docs/reward-before-investment-rule.md line 60-62: surface first-paragraph extraction preview before full transcript ask. Remediation tracked as follow-up phase.
8
+ interactive_first_reward: paragraph_preview
7
9
  allowed-tools:
8
10
  - Read
9
11
  - Write
package/commands/grade.md CHANGED
@@ -3,6 +3,8 @@ name: grade
3
3
  description: Grade problem-discovery quality (6 components)
4
4
  serves_jtbd: ["audit-room"]
5
5
  teaching: "When you want a fast read on problem-discovery quality, /mos:grade scores the room on six components in under a minute. The lightweight cousin of /mos:deep-grade."
6
+ # Per docs/reward-before-investment-rule.md line 64-66: show anonymized calibration distribution before requiring content. Remediation tracked as follow-up phase.
7
+ interactive_first_reward: calibration_distribution_preview
6
8
  # --- Phase 122 workflow-layer frontmatter ---
7
9
  kind: methodology
8
10
  frameworks: ["PWS Triple Validation Compass"]
@@ -0,0 +1,56 @@
1
+ ---
2
+ name: mva-brief
3
+ description: Run the 30-second MVA pipeline for the user's current venture sentence
4
+ argument-hint: (no args -- reads pending state from UserPromptSubmit detection)
5
+ serves_jtbd: ["explore"]
6
+ teaching: "When you have just typed a venture sentence and want a brief in under a minute, /mos:mva-brief runs the 6-agent fan-out and deploys a shareable deck. The reward-before-investment surface of Phase 118."
7
+ allowed-tools: Bash
8
+ interactive_first_reward: instant_brief
9
+ ---
10
+
11
+ # /mos:mva-brief
12
+
13
+ Run the 30-second MVA pipeline against the pending venture sentence detected by
14
+ the UserPromptSubmit hook (Plan 118-00).
15
+
16
+ ## What this does
17
+
18
+ 1. Reads pending state from `~/.mindrian/mva/<session-id>.json` (written by
19
+ Plan 118-00 detection hook).
20
+ 2. Fires 6 parallel agents (Brain similar + Brain cross-domain + Brain classic
21
+ traps + Tavily funding + Six-hats red/black + Dashboard graph) under the
22
+ 45-second hard budget.
23
+ 3. Streams agent results as they return -- each one rendered in Larry's
24
+ GUIDED voice (per feedback_larry_pedagogical_guided_first.md).
25
+ 4. Closes with the 3-option footer:
26
+ - [1] Just tell me what's new (stay in "tell me" mode)
27
+ - [2] Build a room around this (invest)
28
+ - [3] Challenge me -- Devil's Advocate (go deeper cognitively)
29
+
30
+ ## Instructions for the model
31
+
32
+ Invoke `node scripts/mva-run.cjs` via Bash with no arguments. The script reads
33
+ the pending state file, runs the orchestrator, and writes the rendered output
34
+ to stdout.
35
+
36
+ Relay the stdout to the user VERBATIM. Do NOT:
37
+
38
+ - Add commentary or interpretation before the rendered output
39
+ - Re-summarize the agent findings ("So basically what this means is...")
40
+ - Skip the 3-option footer
41
+ - Autonomously pick option 1, 2, or 3 for the user
42
+ - Add Larry-voice framing ("Here's what I found for you...") -- the renderer
43
+ already speaks in Larry's voice; double-voicing breaks the GUIDED tone
44
+
45
+ The 3-option footer IS the user's decision point. Wait for the user to type
46
+ 1, 2, or 3 (or their own free-text), then route per the option behavior:
47
+
48
+ - 1: stay in JUST_TALK mode; keep brief in scrollback; user can ask follow-ups
49
+ - 2: invoke /mos:new-project (stub for v1.13.0; Phase 119 wires fully)
50
+ - 3: invoke /mos:challenge-assumptions against the brief
51
+
52
+ ## Canon parts implemented
53
+
54
+ - Part 2 (team around navigator -- 6 agents as a parallel team)
55
+ - Part 8 (boundary -- agents send only generic handles to Brain / Tavily)
56
+ - Part 10 sub-claim 3 (room as receipt -- the brief IS the reward)
@@ -0,0 +1,89 @@
1
+ ---
2
+ name: mva-option
3
+ description: Route the user's 3-option footer selection after a 30-second MVA brief
4
+ argument-hint: <1|2|3> [<sha8>]
5
+ serves_jtbd: ["explore"]
6
+ teaching: "When the 3-option footer shows after an MVA brief, /mos:mva-option routes your pick (refine / build a room / iterate) into the right next move. The hand-off after the first reward."
7
+ allowed-tools: Bash
8
+ interactive_first_reward: --none (scripting only)
9
+ ---
10
+
11
+ # /mos:mva-option <N> [<sha8>]
12
+
13
+ Route the user's selection from the 3-option footer that appears after a 30-second MVA brief.
14
+
15
+ ## Why this exists
16
+
17
+ The 3-option footer renders after every MVA brief (per binding decision B4):
18
+
19
+ ```
20
+ What now?
21
+ [1] Just tell me what's new (stay in "tell me" mode)
22
+ [2] Build a room around this (invest)
23
+ [3] Challenge me -- Devil's Advocate (go deeper cognitively)
24
+ ```
25
+
26
+ The user types `1`, `2`, or `3` (or `/mos:mva-option N` directly). This command dispatches the routing.
27
+
28
+ ## Arguments
29
+
30
+ - `<N>` (required): `1`, `2`, or `3` -- the user's selection
31
+ - `[<sha8>]` (optional): the 8-char prefix identifying the target brief. When OMITTED, the command auto-discovers the most recent brief by calling `resolveCurrentSha8()` which reads `~/.mindrian/mva/state.json` (the manifest atomically written by Plan 118-03's orchestrator after `mva_brief_rendered` fires).
32
+
33
+ ## How to invoke
34
+
35
+ The model invokes this command via Bash + Node. Two patterns:
36
+
37
+ **With explicit sha8:**
38
+
39
+ ```bash
40
+ node -e "const r=require('./lib/core/mva-option-router.cjs'); r.routeOption(N, '<sha8>').then(out => console.log(JSON.stringify(out, null, 2)))"
41
+ ```
42
+
43
+ **Without sha8 (auto-resolve via state.json):**
44
+
45
+ ```bash
46
+ node -e "const r=require('./lib/core/mva-option-router.cjs'); const sha=r.resolveCurrentSha8(); if(!sha){console.log(JSON.stringify({ok:false,error:'no_current_brief',message:'No recent brief found. Type your venture sentence to fire the pipeline.'}));process.exit(0);} r.routeOption(N, sha).then(out => console.log(JSON.stringify(out, null, 2)))"
47
+ ```
48
+
49
+ The auto-resolve form is what the `mva-pipeline` skill instructs the model to run when the user types `1`, `2`, or `3` as a plain message immediately after a brief renders. See the "## Routing the 3-option footer" section in `skills/mva-pipeline/SKILL.md` for the full recognition rule.
50
+
51
+ ## What happens per option
52
+
53
+ - **Option 1** -- operator transitions to `JUST_TALK`; the brief stays in scrollback; the user can ask any follow-up about the 6 cells. The router returns `{ action: 'stay_in_just_talk', next_state: 'JUST_TALK', message: ... }`.
54
+
55
+ - **Option 2** -- operator unchanged; the router returns `{ action: 'phase_119_stub', next_state: null, message: STUB_MESSAGE_119 }`. The stub message reads:
56
+
57
+ > Building a room around this is the next layer; shipping in beta.18 (Phase 119). For now, press option 1 to keep this brief visible, or option 3 to go deeper.
58
+
59
+ Per binding decision B6 OPTION A, option 2 is deferred to Phase 119 / v1.13.0-beta.18. The router does NOT invoke `/mos:new-project` in v1.13.0.
60
+
61
+ - **Option 3** -- operator transitions to `METHODOLOGY`; the router returns `{ action: 'invoke_challenge_assumptions', next_state: 'METHODOLOGY', invoke_command: '/mos:challenge-assumptions --from-brief <sha8>' }`. The model then runs the named slash command against the brief.
62
+
63
+ ## Edge cases
64
+
65
+ | Situation | Router return | Model surfaces |
66
+ | --------- | ------------- | -------------- |
67
+ | No `state.json` (fresh install / Hebrew refusal) | wrapper short-circuits | "No recent brief found. Type your venture sentence to fire the pipeline." |
68
+ | Side-file `<sha8>.json` missing (brief expired) | `{ ok:false, error:'brief_not_found' }` | "The brief data has expired or was not deployed. Type your sentence again to re-fire the pipeline." |
69
+ | `mva_brief_rendered` event not yet logged (pipeline still streaming) | `{ ok:false, error:'brief_still_rendering' }` | "Brief is still rendering -- options will activate when it completes." |
70
+ | Invalid `N` (0, 4, 99, "1", null) | `{ ok:false, error:'invalid_option' }` | Treat as free-text; route through normal Larry conversation. |
71
+
72
+ ## Telemetry
73
+
74
+ Each successful invocation emits `mva_option_selected` to `~/.mindrian/telemetry/v1.13/mva.jsonl` with the frozen `ALLOWED_FIELDS` schema:
75
+
76
+ ```
77
+ { sentence_sha256, option_id, time_to_click_ms }
78
+ ```
79
+
80
+ `time_to_click_ms` is computed from the most recent `mva_brief_rendered` event timestamp for the brief's `sentence_sha256`. Plan 118-06's Dror 2.0 harness reads these events to validate "subject types one sentence and clicks an option within 60 seconds of brief rendering."
81
+
82
+ Per Canon Part 8: the telemetry payload carries ONLY the sha256 hash + option_id + time delta. Zero user content. Zero URLs.
83
+
84
+ ## Canon parts implemented
85
+
86
+ - Part 3 (Tri-Context Decision Gate) -- the 3-option footer IS a Decision Gate offering a closed-vocabulary choice (verbs 7 Synthesize / 8 Bank Opportunity / 5 Devil's Advocate)
87
+ - Part 4 (Every Choice Is Graph Data) -- `mva_option_selected` telemetry captures every click; operator transitions write `OPERATOR_TRANSITION` edges to the local room graph (Phase 99 substrate)
88
+ - Part 8 (Graph Boundary) -- zero user content in telemetry; zero raw_sentence reads from the side-file; the router source passes the forbidden-token sweep
89
+ - Part 10 sub-claim 3 (room as receipt) -- the 3-option footer is the user's self-selected commitment level immediately after the reward (the brief itself)
@@ -4,6 +4,8 @@ description: Start a new venture project and create its room
4
4
  argument-hint: [name]
5
5
  serves_jtbd: ["explore"]
6
6
  teaching: "When you are starting a new venture, /mos:new-project creates the room scaffolding and registers it in the room registry. The first move of every Mindrian journey."
7
+ # Per docs/reward-before-investment-rule.md line 56-58 remediation: first sentence -> Instant Brief pipeline (this phase's deliverable). Room creation is option 2 of the 3-option footer (Phase 119 wires fully in beta.18).
8
+ interactive_first_reward: instant_brief
7
9
  allowed-tools:
8
10
  - Read
9
11
  - Write
@@ -5,6 +5,8 @@ body_shape: B (Semantic Tree)
5
5
  body_shape_detail: Steps as conversational flow, context building as nested nodes
6
6
  serves_jtbd: ["explore"]
7
7
  teaching: "When you just installed MindrianOS, /mos:onboard walks you through the system and builds your first room. Designed so a stranger can self-activate without Larry holding their hand."
8
+ # Per docs/reward-before-investment-rule.md line 68-70: first screen is a question, not a tutorial. Remediation tracked as follow-up phase.
9
+ interactive_first_reward: reframe_question
8
10
  ui_reference: skills/ui-system/SKILL.md
9
11
  allowed-tools:
10
12
  - Read
package/hooks/hooks.json CHANGED
@@ -292,6 +292,15 @@
292
292
  }
293
293
  ]
294
294
  },
295
+ {
296
+ "hooks": [
297
+ {
298
+ "type": "command",
299
+ "command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/mva-detect.cjs\"",
300
+ "timeout": 1500
301
+ }
302
+ ]
303
+ },
295
304
  {
296
305
  "hooks": [
297
306
  {
@@ -0,0 +1,77 @@
1
+ /*
2
+ * Copyright (c) 2026 Mindrian. BSL 1.1.
3
+ *
4
+ * Phase 118-02 Plan 02 Task 1 -- brain-classic-traps agent (Agent 3 of 6 in
5
+ * B1; agent_id 'brain_classic_traps' in lib/agents/mva/index.cjs).
6
+ *
7
+ * Calls Brain via lib/core/brain-client.cjs::query() with a GENERIC Cypher
8
+ * template from data/mva-agent-prompts.json. Returns top-1 FailureMode pattern
9
+ * with a "Classic trap:" summary line.
10
+ *
11
+ * Graph-native HARD RULES (memory feedback_reverse_salient_agent_graph_native.md):
12
+ * 1. NEVER require room-db.cjs directly (Phase 109 D-06 chokepoint).
13
+ * 2. NEVER require any Brain-MCP client module DIRECTLY for raw queries;
14
+ * use lib/core/brain-client.cjs which enforces the wire-schema sanitization
15
+ * AND only with framework-name/phase-id/enum args, never user content.
16
+ * 3. NEVER write to stdout / stderr (telemetry side-channel rule).
17
+ *
18
+ * Canon Part 8 hard invariant (MVA-118-10):
19
+ * The Cypher carries ONLY $-bound parameters with hardcoded stage labels.
20
+ * NEVER the user's raw sentence. NEVER the sentence_sha256 as a Cypher
21
+ * string interpolation. NEVER any user-content env var (token name elided
22
+ * per the Test 6 grep regression).
23
+ *
24
+ * Pure CJS, node built-ins only, zero new runtime dependencies.
25
+ */
26
+ 'use strict';
27
+
28
+ const path = require('node:path');
29
+ const brainClient = require('../../core/brain-client.cjs');
30
+
31
+ const PROMPTS_PATH = path.resolve(__dirname, '..', '..', '..', 'data', 'mva-agent-prompts.json');
32
+
33
+ /**
34
+ * @param {{ sentence_sha256: string, remaining_budget_ms: number }} _context
35
+ * @param {AbortSignal} signal
36
+ * @returns {Promise<{ status:'ok'|'empty', payload:any } | null>}
37
+ */
38
+ async function run(_context, signal) {
39
+ if (!brainClient.isAvailable()) {
40
+ return { status: 'empty', payload: { reason: 'brain_unavailable' } };
41
+ }
42
+ if (signal && signal.aborted) return null;
43
+
44
+ let prompts;
45
+ try {
46
+ prompts = require(PROMPTS_PATH).brain_classic_traps;
47
+ } catch (_e) {
48
+ return { status: 'empty', payload: { reason: 'prompts_unavailable' } };
49
+ }
50
+
51
+ let result;
52
+ try {
53
+ result = await brainClient.query(prompts.cypher, prompts.params);
54
+ } catch (_e) {
55
+ return { status: 'empty', payload: { reason: 'brain_error' } };
56
+ }
57
+
58
+ if (signal && signal.aborted) return null;
59
+
60
+ const records = (result && Array.isArray(result.records)) ? result.records : [];
61
+ if (records.length === 0) {
62
+ return { status: 'empty', payload: { reason: 'no_trap' } };
63
+ }
64
+ const trap = records[0];
65
+ const tail = trap.signature || 'classic failure pattern';
66
+ const summary = 'Classic trap: ' + (trap.name || 'unnamed') + ' -- ' + tail;
67
+
68
+ return {
69
+ status: 'ok',
70
+ payload: {
71
+ summary_line: summary,
72
+ deck_data: { trap: trap },
73
+ },
74
+ };
75
+ }
76
+
77
+ module.exports = { run };
@@ -0,0 +1,79 @@
1
+ /*
2
+ * Copyright (c) 2026 Mindrian. BSL 1.1.
3
+ *
4
+ * Phase 118-02 Plan 02 Task 1 -- brain-cross-domain agent (Agent 2 of 6 in
5
+ * B1; agent_id 'brain_cross_domain' in lib/agents/mva/index.cjs).
6
+ *
7
+ * Calls Brain via lib/core/brain-client.cjs::search() in cross-domain mode
8
+ * (GENERIC handle from data/mva-agent-prompts.json) and returns top-1
9
+ * analogous framework with a one-line "Cross-domain analogy:" summary.
10
+ *
11
+ * Graph-native HARD RULES (memory feedback_reverse_salient_agent_graph_native.md):
12
+ * 1. NEVER require room-db.cjs directly (Phase 109 D-06 chokepoint).
13
+ * 2. NEVER require any Brain-MCP client module DIRECTLY for raw queries;
14
+ * use lib/core/brain-client.cjs which enforces the wire-schema sanitization
15
+ * AND only with framework-name/phase-id/enum args, never user content.
16
+ * 3. NEVER write to stdout / stderr (telemetry side-channel rule).
17
+ *
18
+ * Canon Part 8 hard invariant (MVA-118-09):
19
+ * The Brain query carries ONLY a hardcoded generic handle. NEVER the user's
20
+ * raw sentence. NEVER the sentence_sha256 as a free-text query body. NEVER
21
+ * any user-content env var (token name elided per the Test 6 grep regression).
22
+ *
23
+ * Pure CJS, node built-ins only, zero new runtime dependencies.
24
+ */
25
+ 'use strict';
26
+
27
+ const path = require('node:path');
28
+ const brainClient = require('../../core/brain-client.cjs');
29
+
30
+ const PROMPTS_PATH = path.resolve(__dirname, '..', '..', '..', 'data', 'mva-agent-prompts.json');
31
+
32
+ /**
33
+ * @param {{ sentence_sha256: string, remaining_budget_ms: number }} _context
34
+ * @param {AbortSignal} signal
35
+ * @returns {Promise<{ status:'ok'|'empty', payload:any } | null>}
36
+ */
37
+ async function run(_context, signal) {
38
+ if (!brainClient.isAvailable()) {
39
+ return { status: 'empty', payload: { reason: 'brain_unavailable' } };
40
+ }
41
+ if (signal && signal.aborted) return null;
42
+
43
+ let prompts;
44
+ try {
45
+ prompts = require(PROMPTS_PATH).brain_cross_domain;
46
+ } catch (_e) {
47
+ return { status: 'empty', payload: { reason: 'prompts_unavailable' } };
48
+ }
49
+
50
+ let result;
51
+ try {
52
+ result = await brainClient.search(prompts.query, {
53
+ filters: prompts.filters,
54
+ limit: prompts.limit,
55
+ });
56
+ } catch (_e) {
57
+ return { status: 'empty', payload: { reason: 'brain_error' } };
58
+ }
59
+
60
+ if (signal && signal.aborted) return null;
61
+
62
+ const analogies = (result && Array.isArray(result.results)) ? result.results : [];
63
+ if (analogies.length === 0) {
64
+ return { status: 'empty', payload: { reason: 'no_analogy' } };
65
+ }
66
+ const analogy = analogies[0];
67
+ const tail = analogy.signature || 'pattern transfer applicable';
68
+ const summary = 'Cross-domain analogy: ' + (analogy.name || 'unnamed') + ' -- ' + tail;
69
+
70
+ return {
71
+ status: 'ok',
72
+ payload: {
73
+ summary_line: summary,
74
+ deck_data: { analogy: analogy },
75
+ },
76
+ };
77
+ }
78
+
79
+ module.exports = { run };
@@ -0,0 +1,93 @@
1
+ /*
2
+ * Copyright (c) 2026 Mindrian. BSL 1.1.
3
+ *
4
+ * Phase 118-02 Plan 02 Task 1 -- brain-similar-ventures agent (Agent 1 of 6
5
+ * in B1; agent_id 'brain_similar' in lib/agents/mva/index.cjs).
6
+ *
7
+ * Calls Brain via lib/core/brain-client.cjs::search() with a GENERIC handle
8
+ * from data/mva-agent-prompts.json. Returns the top-3 venture matches with a
9
+ * one-line human-readable summary + structured deck_data.
10
+ *
11
+ * Mirrors lib/agents/auto-explore-agent.cjs structure verbatim per the plan.
12
+ *
13
+ * Graph-native HARD RULES (memory feedback_reverse_salient_agent_graph_native.md):
14
+ * 1. NEVER require room-db.cjs directly (Phase 109 D-06 chokepoint).
15
+ * 2. NEVER require any Brain-MCP client module DIRECTLY for raw queries;
16
+ * use lib/core/brain-client.cjs which enforces the wire-schema sanitization
17
+ * AND only with framework-name/phase-id/enum args, never user content.
18
+ * 3. NEVER write to stdout / stderr (telemetry side-channel rule).
19
+ *
20
+ * Canon Part 8 hard invariant (MVA-118-08):
21
+ * The Brain query carries ONLY generic handles loaded from
22
+ * data/mva-agent-prompts.json. NEVER the user's raw sentence. NEVER the
23
+ * sentence_sha256 as a free-text query body. NEVER any user-content env
24
+ * var (which is never set; see Plan 118-01's AgentContext invariant -- the
25
+ * sentence-bearing env var name is elided here so the grep regression in
26
+ * test-all-six-agents.cjs Test 6 returns zero matches on this file).
27
+ *
28
+ * Pure CJS, node built-ins only, zero new runtime dependencies.
29
+ */
30
+ 'use strict';
31
+
32
+ const path = require('node:path');
33
+ const brainClient = require('../../core/brain-client.cjs');
34
+
35
+ const PROMPTS_PATH = path.resolve(__dirname, '..', '..', '..', 'data', 'mva-agent-prompts.json');
36
+
37
+ /**
38
+ * Agent run function. Conforms to the Plan 118-01 Agent contract:
39
+ * async function agent(context, signal) -> { status:'ok'|'empty', payload } | null
40
+ *
41
+ * @param {{ sentence_sha256: string, remaining_budget_ms: number }} _context
42
+ * @param {AbortSignal} signal
43
+ * @returns {Promise<{ status:'ok'|'empty', payload:any } | null>}
44
+ */
45
+ async function run(_context, signal) {
46
+ // Fast-fail when Brain is unreachable (no key configured). Per the plan's
47
+ // done-criteria: this must return status='empty' in <100ms.
48
+ if (!brainClient.isAvailable()) {
49
+ return { status: 'empty', payload: { reason: 'brain_unavailable' } };
50
+ }
51
+ if (signal && signal.aborted) return null;
52
+
53
+ // Load the generic prompt template. Per Canon Part 8 this file is the SOLE
54
+ // source of Brain query bodies for this agent -- audited in one place.
55
+ let prompts;
56
+ try {
57
+ // require() caches; that is desirable here (the JSON is static config).
58
+ prompts = require(PROMPTS_PATH).brain_similar_ventures;
59
+ } catch (_e) {
60
+ return { status: 'empty', payload: { reason: 'prompts_unavailable' } };
61
+ }
62
+
63
+ let result;
64
+ try {
65
+ result = await brainClient.search(prompts.query, {
66
+ filters: prompts.filters,
67
+ limit: prompts.limit,
68
+ });
69
+ } catch (_e) {
70
+ return { status: 'empty', payload: { reason: 'brain_error' } };
71
+ }
72
+
73
+ if (signal && signal.aborted) return null;
74
+
75
+ // brain-client may return { results: [...] } or null on quota-exhaustion + fallback.
76
+ const ventures = (result && Array.isArray(result.results)) ? result.results.slice(0, 3) : [];
77
+ if (ventures.length === 0) {
78
+ return { status: 'empty', payload: { reason: 'no_matches' } };
79
+ }
80
+
81
+ const summary = 'Found ' + ventures.length + ' ventures in this space: ' +
82
+ ventures.map((v) => (v.name || 'unnamed') + ' (' + (v.status || 'active') + ')').join(', ');
83
+
84
+ return {
85
+ status: 'ok',
86
+ payload: {
87
+ summary_line: summary,
88
+ deck_data: { ventures: ventures },
89
+ },
90
+ };
91
+ }
92
+
93
+ module.exports = { run };
@@ -0,0 +1,72 @@
1
+ /*
2
+ * Copyright (c) 2026 Mindrian. BSL 1.1.
3
+ *
4
+ * Phase 118-02 Plan 02 Task 3 -- dashboard-graph-neighborhood agent (Agent 6
5
+ * of 6 in B1; agent_id 'dashboard_graph' in lib/agents/mva/index.cjs).
6
+ *
7
+ * Reads the active room's graph via lib/core/navigation.cjs (the Phase 109
8
+ * single chokepoint; Canon Part 9 D-06 invariant) and returns a 1-2 hop
9
+ * neighborhood snapshot of recent decision nodes.
10
+ *
11
+ * Graph-native HARD RULES (memory feedback_reverse_salient_agent_graph_native.md):
12
+ * 1. NEVER require lib/core/room-db.cjs directly (the Phase 109 D-06
13
+ * chokepoint allow-list does NOT include MVA agents).
14
+ * 2. NEVER require better-sqlite3 / node:sqlite directly.
15
+ * 3. NEVER write to stdout / stderr (telemetry side-channel rule).
16
+ * 4. NEVER call out over the network (the dashboard is purely LOCAL graph).
17
+ *
18
+ * Canon Part 8 hard invariant (MVA-118-12):
19
+ * The room graph read is LOCAL only. Zero outbound. The summary line + deck
20
+ * data carry only structural identifiers + counts, never raw artifact text.
21
+ *
22
+ * Pure CJS, node built-ins only, zero new runtime dependencies.
23
+ */
24
+ 'use strict';
25
+
26
+ const nav = require('../../core/navigation.cjs');
27
+
28
+ /**
29
+ * @param {{ sentence_sha256: string, remaining_budget_ms: number }} _context
30
+ * @param {AbortSignal} signal
31
+ * @returns {Promise<{ status:'ok'|'empty', payload:any } | null>}
32
+ */
33
+ async function run(_context, signal) {
34
+ if (signal && signal.aborted) return null;
35
+
36
+ let active;
37
+ try {
38
+ active = nav.detectActiveRoom();
39
+ } catch (_e) {
40
+ return { status: 'empty', payload: { reason: 'no_active_room' } };
41
+ }
42
+ if (!active || !active.hasRoomDb) {
43
+ return { status: 'empty', payload: { reason: 'no_active_room' } };
44
+ }
45
+ if (signal && signal.aborted) return null;
46
+
47
+ let neighborhood;
48
+ try {
49
+ neighborhood = nav.getRecentDecisionNeighborhood(active.roomDir, { hops: 1, limit: 5 });
50
+ } catch (_e) {
51
+ return { status: 'empty', payload: { reason: 'graph_error' } };
52
+ }
53
+ if (signal && signal.aborted) return null;
54
+
55
+ const nodes = (neighborhood && Array.isArray(neighborhood.nodes)) ? neighborhood.nodes : [];
56
+ const edges = (neighborhood && Array.isArray(neighborhood.edges)) ? neighborhood.edges : [];
57
+ if (nodes.length === 0) {
58
+ return { status: 'empty', payload: { reason: 'empty_room' } };
59
+ }
60
+ const count = nodes.length;
61
+ const suffix = count === 1 ? '' : 's';
62
+ const summary = 'Your room already has ' + count + ' related decision node' + suffix + '. Quick preview:';
63
+ return {
64
+ status: 'ok',
65
+ payload: {
66
+ summary_line: summary,
67
+ deck_data: { nodes: nodes, edges: edges },
68
+ },
69
+ };
70
+ }
71
+
72
+ module.exports = { run };
@@ -0,0 +1,42 @@
1
+ /*
2
+ * Copyright (c) 2026 Mindrian. BSL 1.1.
3
+ *
4
+ * Phase 118-02 Plan 02 -- ALL_AGENTS aggregator for the 6 MVA agents (Binding
5
+ * Decision B1). Consumed by lib/core/mva-dispatcher.cjs which knows nothing
6
+ * about which agents are which -- it accepts any { id, fn } tuple conforming
7
+ * to the Agent contract in lib/core/mva-agent-contract.cjs.
8
+ *
9
+ * Agent ID -> source-file mapping (short forms per B1; long forms here):
10
+ *
11
+ * brain_similar <- brain-similar-ventures.cjs (Agent 1)
12
+ * brain_cross_domain <- brain-cross-domain.cjs (Agent 2)
13
+ * brain_classic_traps <- brain-classic-traps.cjs (Agent 3)
14
+ * tavily_funding <- tavily-funding-scan.cjs (Agent 4)
15
+ * six_hats_red_black <- six-hats-red-black.cjs (Agent 5)
16
+ * dashboard_graph <- dashboard-graph-neighborhood.cjs (Agent 6)
17
+ *
18
+ * NOTE on filename drift (NIT-2 invariant from plan-checker iteration 2):
19
+ * The canonical filenames in this plan's files_modified (e.g.
20
+ * brain-cross-domain.cjs, dashboard-graph-neighborhood.cjs) are the
21
+ * implementation-time source files. The JSDoc above documents the agent-id
22
+ * -> source-file mapping using the B1 short forms so Plan 118-03's renderer
23
+ * prefixes ([brain] / [analogy] / [traps] / [funding] / [worth chewing on]
24
+ * / [your room]) deterministically resolve from agent_id alone. If an
25
+ * executor renames a source file, update both this comment block AND the
26
+ * require() path immediately below in the same commit.
27
+ *
28
+ * Canon Part 8: this module is a pure aggregator. Zero I/O. Each agent owns
29
+ * its own boundary; the array shape preserves the dispatcher contract.
30
+ */
31
+ 'use strict';
32
+
33
+ const ALL_AGENTS = Object.freeze([
34
+ { id: 'brain_similar', fn: require('./brain-similar-ventures.cjs').run },
35
+ { id: 'brain_cross_domain', fn: require('./brain-cross-domain.cjs').run },
36
+ { id: 'brain_classic_traps', fn: require('./brain-classic-traps.cjs').run },
37
+ { id: 'tavily_funding', fn: require('./tavily-funding-scan.cjs').run },
38
+ { id: 'six_hats_red_black', fn: require('./six-hats-red-black.cjs').run },
39
+ { id: 'dashboard_graph', fn: require('./dashboard-graph-neighborhood.cjs').run },
40
+ ]);
41
+
42
+ module.exports = { ALL_AGENTS };