@mindrian_os/install 1.13.0-beta.16 → 1.13.0-beta.19
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 +36 -0
- package/commands/act.md +1 -0
- package/commands/admin.md +1 -0
- package/commands/analyze-needs.md +2 -0
- package/commands/analyze-systems.md +2 -0
- package/commands/analyze-timing.md +2 -0
- package/commands/auto-explore.md +2 -0
- package/commands/beautiful-question.md +2 -0
- package/commands/brain-derive.md +2 -0
- package/commands/build-knowledge.md +2 -0
- package/commands/build-thesis.md +2 -0
- package/commands/causal.md +2 -0
- package/commands/challenge-assumptions.md +2 -0
- package/commands/compare-ventures.md +2 -0
- package/commands/dashboard.md +2 -1
- package/commands/deep-grade.md +2 -0
- package/commands/diagnose.md +21 -1
- package/commands/diagnostics.md +14 -3
- package/commands/doctor.md +4 -1
- package/commands/dogfood-flush.md +92 -0
- package/commands/dominant-designs.md +2 -0
- package/commands/explain-decision.md +2 -0
- package/commands/explore-domains.md +2 -0
- package/commands/explore-futures.md +2 -0
- package/commands/explore-trends.md +2 -0
- package/commands/export.md +1 -0
- package/commands/feynman-timeline-refresh.md +2 -0
- package/commands/file-meeting.md +4 -0
- package/commands/find-analogies.md +1 -0
- package/commands/find-bottlenecks.md +2 -0
- package/commands/find-connections.md +2 -0
- package/commands/funding.md +1 -0
- package/commands/grade.md +4 -0
- package/commands/graph.md +1 -0
- package/commands/hat-briefing.md +1 -0
- package/commands/heal.md +22 -170
- package/commands/help.md +54 -334
- package/commands/hmi-status.md +23 -144
- package/commands/jtbd.md +1 -0
- package/commands/leadership.md +2 -0
- package/commands/lean-canvas.md +2 -0
- package/commands/macro-trends.md +2 -0
- package/commands/map-unknowns.md +2 -0
- package/commands/memory.md +1 -0
- package/commands/models.md +1 -0
- package/commands/mos-reason.md +2 -0
- package/commands/mos.md +139 -0
- package/commands/mullins.md +2 -0
- package/commands/mva-brief.md +58 -0
- package/commands/mva-option.md +91 -0
- package/commands/new-project.md +4 -0
- package/commands/onboard.md +22 -7
- package/commands/operator.md +1 -0
- package/commands/opportunities.md +1 -0
- package/commands/organize.md +22 -469
- package/commands/persona.md +1 -0
- package/commands/pipeline.md +2 -0
- package/commands/present.md +1 -0
- package/commands/publish.md +2 -0
- package/commands/query.md +24 -102
- package/commands/radar.md +2 -0
- package/commands/reanalyze.md +1 -0
- package/commands/research.md +2 -0
- package/commands/room.md +2 -0
- package/commands/rooms.md +1 -0
- package/commands/root-cause.md +2 -0
- package/commands/rs-experts.md +1 -0
- package/commands/rs-explain.md +1 -0
- package/commands/rs-fetch.md +1 -0
- package/commands/rs-thesis.md +1 -0
- package/commands/scenario-plan.md +2 -0
- package/commands/scheduled-tasks.md +1 -0
- package/commands/score-innovation.md +2 -0
- package/commands/scout.md +1 -0
- package/commands/setup.md +2 -0
- package/commands/snapshot.md +2 -0
- package/commands/speakers.md +1 -0
- package/commands/splash.md +5 -2
- package/commands/status.md +1 -0
- package/commands/structure-argument.md +2 -0
- package/commands/suggest-next.md +2 -0
- package/commands/systems-thinking.md +2 -0
- package/commands/think-hats.md +2 -0
- package/commands/update.md +2 -0
- package/commands/user-needs.md +2 -0
- package/commands/validate.md +2 -0
- package/commands/value-proposition.md +2 -0
- package/commands/vault.md +2 -0
- package/commands/visualize.md +24 -29
- package/commands/whitespace.md +2 -1
- package/commands/wiki.md +1 -0
- package/hooks/hooks.json +31 -88
- package/lib/agents/auto-explore-agent.cjs +82 -0
- package/lib/agents/mva/brain-classic-traps.cjs +77 -0
- package/lib/agents/mva/brain-cross-domain.cjs +79 -0
- package/lib/agents/mva/brain-similar-ventures.cjs +93 -0
- package/lib/agents/mva/dashboard-graph-neighborhood.cjs +72 -0
- package/lib/agents/mva/index.cjs +42 -0
- package/lib/agents/mva/six-hats-red-black.cjs +137 -0
- package/lib/agents/mva/tavily-funding-scan.cjs +147 -0
- package/lib/agents/mva/test-all-six-agents.cjs +467 -0
- package/lib/conversation/operator.cjs +64 -0
- package/lib/conversation/operator.test.cjs +160 -0
- package/lib/core/breakthrough/canary.cjs +134 -0
- package/lib/core/breakthrough/canary.test.cjs +136 -0
- package/lib/core/breakthrough/detectors.cjs +359 -0
- package/lib/core/breakthrough/detectors.test.cjs +333 -0
- package/lib/core/breakthrough/ethics-fence.cjs +127 -0
- package/lib/core/breakthrough/ethics-fence.test.cjs +178 -0
- package/lib/core/breakthrough/resurfacing.cjs +150 -0
- package/lib/core/breakthrough/resurfacing.test.cjs +233 -0
- package/lib/core/breakthrough/review-queue.cjs +154 -0
- package/lib/core/breakthrough/review-queue.test.cjs +160 -0
- package/lib/core/breakthrough/scanner-d17-d18.test.cjs +229 -0
- package/lib/core/breakthrough/scanner.cjs +426 -0
- package/lib/core/breakthrough/scanner.test.cjs +267 -0
- package/lib/core/breakthrough/schema.cjs +164 -0
- package/lib/core/breakthrough/schema.test.cjs +256 -0
- package/lib/core/breakthrough/scoring.cjs +293 -0
- package/lib/core/breakthrough/scoring.test.cjs +423 -0
- package/lib/core/breakthrough/verb-dispatch.cjs +221 -0
- package/lib/core/breakthrough/verb-dispatch.test.cjs +185 -0
- package/lib/core/breakthrough/voice-scaffold.cjs +247 -0
- package/lib/core/breakthrough/voice-scaffold.test.cjs +251 -0
- package/lib/core/first-touch-version-stamper.cjs +113 -0
- package/lib/core/larry-thinness-acknowledgment.cjs +64 -0
- package/lib/core/larry-thinness-acknowledgment.test.cjs +97 -0
- package/lib/core/llm-name-suggester.cjs +194 -0
- package/lib/core/llm-name-suggester.test.cjs +132 -0
- package/lib/core/mva-agent-contract.cjs +170 -0
- package/lib/core/mva-agent-contract.test.cjs +169 -0
- package/lib/core/mva-budget.cjs +75 -0
- package/lib/core/mva-budget.test.cjs +68 -0
- package/lib/core/mva-classifier.cjs +370 -0
- package/lib/core/mva-classifier.test.cjs +248 -0
- package/lib/core/mva-deck-builder.cjs +452 -0
- package/lib/core/mva-deck-builder.test.cjs +287 -0
- package/lib/core/mva-detect.smoke.test.cjs +197 -0
- package/lib/core/mva-dispatcher.cjs +110 -0
- package/lib/core/mva-dispatcher.test.cjs +216 -0
- package/lib/core/mva-option-router.cjs +292 -0
- package/lib/core/mva-option-router.test.cjs +483 -0
- package/lib/core/mva-orchestrator.cjs +365 -0
- package/lib/core/mva-orchestrator.test.cjs +908 -0
- package/lib/core/mva-progressive-renderer.cjs +194 -0
- package/lib/core/mva-progressive-renderer.test.cjs +157 -0
- package/lib/core/mva-rule-linter.cjs +213 -0
- package/lib/core/mva-rule-linter.test.cjs +336 -0
- package/lib/core/mva-state.cjs +159 -0
- package/lib/core/mva-telemetry.cjs +58 -0
- package/lib/core/mva-telemetry.test.cjs +196 -0
- package/lib/core/mva-vercel-deploy.cjs +168 -0
- package/lib/core/mva-vercel-deploy.test.cjs +239 -0
- package/lib/core/navigation/dashboard-helpers.cjs +145 -0
- package/lib/core/navigation/edges.cjs +35 -0
- package/lib/core/navigation/memory-events.cjs +126 -0
- package/lib/core/navigation.cjs +11 -0
- package/lib/core/resolve-vercel-key.cjs +107 -0
- package/lib/core/resolve-vercel-key.test.cjs +137 -0
- package/lib/core/room-auto-create.cjs +318 -0
- package/lib/core/room-auto-create.test.cjs +198 -0
- package/lib/core/room-discard-cascade.cjs +225 -0
- package/lib/core/room-discard-cascade.test.cjs +135 -0
- package/lib/core/room-name-validator.cjs +132 -0
- package/lib/core/room-name-validator.test.cjs +156 -0
- package/lib/core/room-naming-selector.cjs +357 -0
- package/lib/core/room-naming-selector.test.cjs +277 -0
- package/lib/core/room-receipt-emit.cjs +63 -0
- package/lib/core/room-skeleton-scaffold.cjs +315 -0
- package/lib/core/room-skeleton-scaffold.test.cjs +291 -0
- package/lib/core/stale-copy-scanner.cjs +190 -0
- package/lib/core/state-aware-router.cjs +78 -0
- package/lib/core/telemetry/schema.cjs +168 -0
- package/lib/core/telemetry/schema.test.cjs +124 -0
- package/lib/core/telemetry/validator.cjs +197 -0
- package/lib/core/telemetry/validator.test.cjs +188 -0
- package/lib/core/telemetry/writer.cjs +141 -0
- package/lib/core/telemetry/writer.test.cjs +331 -0
- package/lib/core/terminal-capability.cjs +88 -0
- package/lib/core/venture-shape-nudge.cjs +163 -0
- package/lib/core/venture-shape-nudge.test.cjs +161 -0
- package/lib/core/visual-ops.cjs +70 -2
- package/lib/hmi/selector-dispatcher.cjs +90 -1
- package/lib/hmi/shape-f7-breakthrough-renderer.cjs +222 -0
- package/lib/hmi/shape-f7-breakthrough-renderer.test.cjs +233 -0
- package/lib/memory/body-shape-coverage.test.cjs +268 -0
- package/lib/memory/doctor-deprecation-surface.test.cjs +185 -0
- package/lib/memory/first-touch-version.test.cjs +198 -0
- package/lib/memory/help-coverage.test.cjs +108 -0
- package/lib/memory/help-renderer.test.cjs +145 -0
- package/lib/memory/palette-consistency.test.cjs +127 -0
- package/lib/memory/pending-tension-store.cjs +80 -0
- package/lib/memory/render-v2-disposition.test.cjs +199 -0
- package/lib/memory/run-feynman-tests.cjs +240 -0
- package/lib/memory/sessionstart-coordinator.test.cjs +446 -0
- package/lib/memory/skill-vs-code-drift.test.cjs +257 -0
- package/lib/memory/soft-alias.test.cjs +144 -0
- package/lib/memory/stale-copy-scanner.test.cjs +291 -0
- package/lib/memory/state-aware-router.test.cjs +90 -0
- package/lib/memory/statusline-two-row.test.cjs +338 -0
- package/lib/memory/terminal-capability.test.cjs +155 -0
- package/lib/render/ROOM.md +74 -22
- package/lib/sessionstart/budget-compressor.cjs +130 -0
- package/lib/sessionstart/contributor-interface.cjs +134 -0
- package/lib/sessionstart/contributor-isolator.cjs +128 -0
- package/lib/sessionstart/precedence-ladder.cjs +47 -0
- package/lib/statusline/governing-thought-truncator.cjs +45 -0
- package/lib/statusline/two-row-renderer.cjs +186 -0
- package/lib/statusline/version-resolver.cjs +81 -0
- package/package.json +1 -1
- package/references/visual/ROOM.md +55 -0
- package/references/visual/palette.json +54 -0
- package/skills/larry-personality/SKILL.md +34 -0
- package/skills/mva-pipeline/SKILL.md +129 -0
- package/skills/ui-system/SKILL.md +109 -1
- package/skills/ui-system/rules/dual-palette.md +156 -0
- package/skills/ui-system/rules/glyph-disambiguation.md +171 -0
- package/skills/ui-system/rules/shape-f-zero-and-six.md +169 -0
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
/*
|
|
3
|
+
* Phase 118 Plan 02 -- dashboard-helpers: thin wrappers used by the Plan
|
|
4
|
+
* 118-02 dashboard-graph-neighborhood MVA agent (Agent 6 of 6 in B1).
|
|
5
|
+
*
|
|
6
|
+
* Two wrappers, both kept under lib/core/navigation/ so the chokepoint module
|
|
7
|
+
* (lib/core/navigation.cjs) re-exports them as the navigator-facing API. The
|
|
8
|
+
* dashboard MVA agent goes through navigation.cjs only -- the Phase 109 D-06
|
|
9
|
+
* chokepoint invariant (Canon Part 9).
|
|
10
|
+
*
|
|
11
|
+
* Wrappers:
|
|
12
|
+
* detectActiveRoom() -> { roomDir, hasRoomDb } | null
|
|
13
|
+
* Resolves the active room via MindrianRooms/.rooms/registry.json (the
|
|
14
|
+
* scripts/brain-derive-command.cjs precedent at line 142). Returns null if
|
|
15
|
+
* no registry, no active slug, or the resolved path is not a directory.
|
|
16
|
+
*
|
|
17
|
+
* getRecentDecisionNeighborhood(roomDir, opts) -> { nodes:[], edges:[] }
|
|
18
|
+
* Opens room.db via lib/core/room-db.cjs (the SOLE owner of better-sqlite3
|
|
19
|
+
* instantiation), picks the most recent 'decision' node, calls the
|
|
20
|
+
* existing getNeighborhood() chokepoint, returns the typed neighborhood.
|
|
21
|
+
* Returns { nodes:[], edges:[] } when room.db has no decisions yet.
|
|
22
|
+
*
|
|
23
|
+
* Canon Part 9 (Memory Locality + Interpretation): this helper IS a navigation
|
|
24
|
+
* surface; agents that need room-graph reads go through here.
|
|
25
|
+
*
|
|
26
|
+
* Canon Part 8: zero network surface. Pure LOCAL filesystem + SQLite reads.
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
const fs = require('node:fs');
|
|
30
|
+
const path = require('node:path');
|
|
31
|
+
const os = require('node:os');
|
|
32
|
+
const roomDbMod = require('../room-db.cjs');
|
|
33
|
+
const neighborhoodMod = require('./neighborhood.cjs');
|
|
34
|
+
|
|
35
|
+
function _safeIsFile(p) {
|
|
36
|
+
try { return fs.statSync(p).isFile(); } catch (_e) { return false; }
|
|
37
|
+
}
|
|
38
|
+
function _safeIsDir(p) {
|
|
39
|
+
try { return fs.statSync(p).isDirectory(); } catch (_e) { return false; }
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Resolve the active room via the MindrianRooms registry. Mirrors
|
|
44
|
+
* scripts/brain-derive-command.cjs::resolveActiveRoom verbatim so the same
|
|
45
|
+
* detection rules apply across CLI commands and MVA agents.
|
|
46
|
+
*
|
|
47
|
+
* @returns {{ roomDir: string, hasRoomDb: boolean } | null}
|
|
48
|
+
*/
|
|
49
|
+
function detectActiveRoom() {
|
|
50
|
+
const home = process.env.HOME || process.env.USERPROFILE || os.homedir();
|
|
51
|
+
const roomsRoot = process.env.MINDRIAN_ROOMS_ROOT
|
|
52
|
+
|| process.env.MINDRIAN_ROOMS_HOME
|
|
53
|
+
|| path.join(home, 'MindrianRooms');
|
|
54
|
+
const registryPath = path.join(roomsRoot, '.rooms', 'registry.json');
|
|
55
|
+
if (!_safeIsFile(registryPath)) return null;
|
|
56
|
+
let reg;
|
|
57
|
+
try {
|
|
58
|
+
reg = JSON.parse(fs.readFileSync(registryPath, 'utf8'));
|
|
59
|
+
} catch (_e) {
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
if (!reg || typeof reg !== 'object') return null;
|
|
63
|
+
const activeSlug = reg.active;
|
|
64
|
+
if (!activeSlug || typeof activeSlug !== 'string') return null;
|
|
65
|
+
const entry = reg.rooms && reg.rooms[activeSlug];
|
|
66
|
+
if (!entry || typeof entry !== 'object') return null;
|
|
67
|
+
const relPath = entry.path || activeSlug;
|
|
68
|
+
const absPath = path.resolve(roomsRoot, relPath);
|
|
69
|
+
if (!_safeIsDir(absPath)) return null;
|
|
70
|
+
const roomDbPath = path.join(absPath, '.mindrian', 'room.db');
|
|
71
|
+
const hasRoomDb = _safeIsFile(roomDbPath);
|
|
72
|
+
return { roomDir: absPath, hasRoomDb: hasRoomDb };
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Return a 1-2 hop neighborhood snapshot of the most-recent Decision node in
|
|
77
|
+
* the room graph. The dashboard MVA agent renders this as the "your room
|
|
78
|
+
* already has N related decision nodes" surface.
|
|
79
|
+
*
|
|
80
|
+
* @param {string} roomDir absolute path to the active room
|
|
81
|
+
* @param {{ hops?: number, limit?: number }} [opts]
|
|
82
|
+
* @returns {{ nodes: Array, edges: Array }}
|
|
83
|
+
*/
|
|
84
|
+
function getRecentDecisionNeighborhood(roomDir, opts) {
|
|
85
|
+
const options = opts || {};
|
|
86
|
+
const hops = Number.isInteger(options.hops) && options.hops >= 1 ? options.hops : 1;
|
|
87
|
+
const limit = Number.isInteger(options.limit) && options.limit > 0 ? options.limit : 5;
|
|
88
|
+
|
|
89
|
+
let db;
|
|
90
|
+
try {
|
|
91
|
+
db = roomDbMod.openRoomDb(roomDir);
|
|
92
|
+
} catch (_e) {
|
|
93
|
+
return { nodes: [], edges: [] };
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
let nodes = [];
|
|
97
|
+
let edges = [];
|
|
98
|
+
try {
|
|
99
|
+
// Pick the most recent decision node (or any node if no decisions) as focus.
|
|
100
|
+
const focusRow = db.prepare(
|
|
101
|
+
"SELECT id FROM nodes WHERE type = 'decision' ORDER BY created_at DESC LIMIT 1"
|
|
102
|
+
).get();
|
|
103
|
+
if (!focusRow) {
|
|
104
|
+
return { nodes: [], edges: [] };
|
|
105
|
+
}
|
|
106
|
+
const focusNodeId = focusRow.id;
|
|
107
|
+
// Use the existing chokepoint to get the neighborhood. The depth + topK
|
|
108
|
+
// map onto Plan 118-02's "1-2 hop / 5-node snapshot" contract.
|
|
109
|
+
const neighborhood = neighborhoodMod.getNeighborhood(db, focusNodeId, {
|
|
110
|
+
maxDepth: hops,
|
|
111
|
+
topK: limit,
|
|
112
|
+
});
|
|
113
|
+
// Always include the focus node itself as the first node in the returned set.
|
|
114
|
+
nodes = [{ id: focusNodeId, type: 'decision' }].concat(neighborhood.map((n) => ({
|
|
115
|
+
id: n.id,
|
|
116
|
+
type: n.type,
|
|
117
|
+
score: n.score,
|
|
118
|
+
edgeTypeIn: n.edgeTypeIn,
|
|
119
|
+
depth: n.depth,
|
|
120
|
+
})));
|
|
121
|
+
// The closed neighborhood query also returns edge_path; surface a flat
|
|
122
|
+
// edges array of (source, target, type) tuples derived from the path
|
|
123
|
+
// metadata so the deck renderer (Plan 118-03) can draw the graph.
|
|
124
|
+
for (const n of neighborhood) {
|
|
125
|
+
if (n.edgePath && n.edgePath.length >= 2) {
|
|
126
|
+
const pathArr = n.edgePath;
|
|
127
|
+
for (let i = 0; i + 1 < pathArr.length; i++) {
|
|
128
|
+
edges.push({
|
|
129
|
+
source: pathArr[i],
|
|
130
|
+
target: pathArr[i + 1],
|
|
131
|
+
type: i + 1 === pathArr.length - 1 ? (n.edgeTypeIn || 'unknown') : 'path',
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
} catch (_e) {
|
|
137
|
+
nodes = [];
|
|
138
|
+
edges = [];
|
|
139
|
+
} finally {
|
|
140
|
+
try { roomDbMod.closeRoomDb(db); } catch (_e) { /* tolerant */ }
|
|
141
|
+
}
|
|
142
|
+
return { nodes, edges };
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
module.exports = { detectActiveRoom, getRecentDecisionNeighborhood };
|
|
@@ -33,6 +33,41 @@ const ALLOWED_EDGE_TYPES = Object.freeze(new Set([
|
|
|
33
33
|
// Phase 125 D7 -- F-selector decision edges (LOCKED LOCAL per Canon Part 8).
|
|
34
34
|
'DEFERRED',
|
|
35
35
|
'REJECTED',
|
|
36
|
+
// Phase 120-00 Wave 1 extension (Breakthrough Scan / Category G; D-18 HARD FLOOR enforcement
|
|
37
|
+
// + D-20 Cypher-provable principle). DERIVED_FROM is the structural enforcement: a
|
|
38
|
+
// Breakthrough node CANNOT surface without at least one DERIVED_FROM edge to an
|
|
39
|
+
// Artifact node. Mirrors the Phase 125-00 DEFERRED + REJECTED additive idiom.
|
|
40
|
+
//
|
|
41
|
+
// Canon Part 4: every choice is graph data. The Breakthrough node + its DERIVED_FROM
|
|
42
|
+
// edges are the graph-native artifact of pattern detection.
|
|
43
|
+
//
|
|
44
|
+
// Canon Part 8: writeEdge takes (db, params) over a LOCAL room.db handle; DERIVED_FROM
|
|
45
|
+
// never crosses to Brain. Cross-room aggregation forbidden (Phase 8 cross-room fence).
|
|
46
|
+
//
|
|
47
|
+
// D-20 enforcement: lib/core/breakthrough/schema.cjs::writeBreakthrough wraps the
|
|
48
|
+
// Breakthrough node insert + N DERIVED_FROM edge inserts in a single SQLite transaction.
|
|
49
|
+
// If any step fails, the transaction rolls back -- partial Breakthrough state CANNOT
|
|
50
|
+
// land. The Cypher invariant `MATCH (b:Breakthrough)-[:DERIVED_FROM]->(a:Artifact)
|
|
51
|
+
// RETURN count(a)` is guaranteed >= 1 by construction.
|
|
52
|
+
'DERIVED_FROM',
|
|
53
|
+
// Phase 120-02 Wave 2 extension (Breakthrough Scan / Category G; D-09 file-as-decision
|
|
54
|
+
// bridge). FILED_AS_DECISION is the typed edge that promotes a Breakthrough node into
|
|
55
|
+
// the Phase 88 decision-log machinery when the user picks the [File as decision]
|
|
56
|
+
// verb on F.7. Mirrors the Phase 120-00 DERIVED_FROM additive idiom verbatim.
|
|
57
|
+
//
|
|
58
|
+
// Canon Part 4: every choice is graph data. The Breakthrough -> Decision edge is the
|
|
59
|
+
// graph-native bridge that lets future related breakthroughs reference the filed
|
|
60
|
+
// decision via ENABLES edges (per CONTEXT.md D-15 "may be referenced as ENABLES in
|
|
61
|
+
// future related breakthroughs").
|
|
62
|
+
//
|
|
63
|
+
// Canon Part 8: writeEdge takes (db, params) over a LOCAL room.db handle;
|
|
64
|
+
// FILED_AS_DECISION never crosses to Brain. Cross-room aggregation forbidden.
|
|
65
|
+
//
|
|
66
|
+
// Emitted by: lib/core/breakthrough/verb-dispatch.cjs::handleFileAsDecision.
|
|
67
|
+
// The destination Decision node id is 'decision:' + breakthroughId by convention;
|
|
68
|
+
// Phase 88 decision-log machinery (or a future Phase 121 housekeeping pass) is
|
|
69
|
+
// responsible for materializing the Decision node body when one does not yet exist.
|
|
70
|
+
'FILED_AS_DECISION',
|
|
36
71
|
]));
|
|
37
72
|
|
|
38
73
|
function isPlainObject(v) {
|
|
@@ -109,6 +109,132 @@ const EVENT_TYPES = Object.freeze(new Set([
|
|
|
109
109
|
// investment_level_at_decision}. NO cascade edge written (miss is temporal-only).
|
|
110
110
|
// Canon Part 8: user_intent stays LOCAL; never sent to Brain.
|
|
111
111
|
'f_selector_miss',
|
|
112
|
+
// Phase 121.5-00 extension (SessionStart Coordinator: D-16 isolation + D-14 budget telemetry).
|
|
113
|
+
// Emitted by lib/sessionstart/contributor-isolator.cjs::runContributor on contributor failure
|
|
114
|
+
// and by scripts/sessionstart-coordinator.cjs::runAll on every coordinator pass.
|
|
115
|
+
// sessionstart_contributor_failed -> a single contributor threw / validation-failed; coordinator
|
|
116
|
+
// dropped it and continued. Payload: {contributor_id: <ladder id>,
|
|
117
|
+
// error_class: <constructor name; enum-only>}. No stack, no
|
|
118
|
+
// user content -- Canon Part 8 boundary preserved by the
|
|
119
|
+
// isolator (stack lives in the LOCAL JSONL telemetry only).
|
|
120
|
+
// sessionstart_coordinator_run -> one envelope emitted; payload carries scalar counts
|
|
121
|
+
// (fragments_total, fragments_compressed, fragments_dropped,
|
|
122
|
+
// bytes_emitted). Scalars + enums only.
|
|
123
|
+
// Additive extension only; mirrors the Phase 110-02 / 116-00 / 117-00 / 124-02 / 125-01 / 125-06
|
|
124
|
+
// / 125-07 idiom verbatim. logEvent already rejects event_type values outside EVENT_TYPES.
|
|
125
|
+
'sessionstart_contributor_failed',
|
|
126
|
+
'sessionstart_coordinator_run',
|
|
127
|
+
// Phase 119-00 Wave 1 extension (Room-as-Receipt Invariant; D-01 + D-04 + D-06 telemetry mirror).
|
|
128
|
+
// Per CONTEXT.md Implementation Decisions D-01 + D-04 + D-06: the auto-create entrypoint
|
|
129
|
+
// (room_auto_created) fires synchronously inside scripts/auto-explore-fingerprint.cjs BEFORE
|
|
130
|
+
// the detached auto-explore-fire spawn so the spawned auto-explore output lands in a real
|
|
131
|
+
// room.db. The naming-decided + discarded events land in Plan 119-01.
|
|
132
|
+
//
|
|
133
|
+
// Additive extension; mirrors the Phase 124-02 2-string idiom and the Phase 117-00 6-string
|
|
134
|
+
// idiom. logEvent already rejects event_type values outside EVENT_TYPES -- so these are
|
|
135
|
+
// accepted only because they are now IN the Set. Set size grows by 3 (was 38 before Phase
|
|
136
|
+
// 119; now 41 baseline; coexists additively with any concurrent phase extension).
|
|
137
|
+
//
|
|
138
|
+
// Canon Part 9: SQL is the local mind; every choice is graph data. These three events are
|
|
139
|
+
// the canonical Part 10 sub-claim 3 ("rooms are receipts, not entry points") telemetry mirror.
|
|
140
|
+
'room_auto_created',
|
|
141
|
+
'room_naming_decided',
|
|
142
|
+
'room_discarded',
|
|
143
|
+
// Phase 119-01 Wave 2 extension (Room-as-Receipt Invariant; D-06 discard-cascade safety net).
|
|
144
|
+
// Per CONTEXT.md Architectural Decision item 4 (Claude's Discretion): the discard cascade
|
|
145
|
+
// is a SQLite transaction wrapping fs.rmSync + registry purge + memory_event emission.
|
|
146
|
+
// When the transaction fails partway (fs.rmSync raises EBUSY / EACCES, OR the registry
|
|
147
|
+
// purge fails non-atomically), the memory_event below lands so /mos:doctor can find
|
|
148
|
+
// orphaned rooms on next session-start.
|
|
149
|
+
//
|
|
150
|
+
// Additive extension only; mirrors the Plan 119-00 idiom verbatim. logEvent already
|
|
151
|
+
// rejects event_type values outside EVENT_TYPES -- so this is accepted only because
|
|
152
|
+
// it is now IN the Set. Set size grows by 1 (was 41 after Plan 119-00; now 42 baseline).
|
|
153
|
+
//
|
|
154
|
+
// Canon Part 9: SQL is the local mind; even partial failures become graph data so the
|
|
155
|
+
// recovery hook (/mos:doctor --orphaned-room-cleanup, deferred to v1.13.0 housekeeping)
|
|
156
|
+
// can scan + remediate.
|
|
157
|
+
'room_discard_partial_failure',
|
|
158
|
+
// Phase 120-00 Wave 1 extension (Breakthrough Scan / Category G; D-01..D-06 detector tier
|
|
159
|
+
// + D-09 file-as-decision bridge + D-10 mandatory dismiss + D-19 canary auto-throttle).
|
|
160
|
+
//
|
|
161
|
+
// Six strings; mirrors the Phase 119-00 3-string + 117-00 6-string + 124-02 2-string
|
|
162
|
+
// additive idiom. logEvent already rejects event_type values outside EVENT_TYPES -- so
|
|
163
|
+
// these are accepted only because they are now IN the Set. Set size grows by 6 (was 42
|
|
164
|
+
// baseline after Phase 119-01; now 48 baseline).
|
|
165
|
+
//
|
|
166
|
+
// Canon Part 10 sub-claim 5: variable reward fires automatically; the math IS the surface.
|
|
167
|
+
// These six events are the canonical telemetry mirror for the breakthrough lifecycle:
|
|
168
|
+
// soft-fire (buffer-only) -> hard-fire (surfaced) -> user response (confirm/dismiss/file)
|
|
169
|
+
// -> canary auto-throttle (D-19 30%-over-100-fire-window static threshold).
|
|
170
|
+
//
|
|
171
|
+
// Canon Part 4: every choice is graph data. The breakthrough_filed_as_decision event is
|
|
172
|
+
// the bridge to Phase 88 decision-log machinery -- promotes a breakthrough to a
|
|
173
|
+
// first-class decision with audit trail.
|
|
174
|
+
//
|
|
175
|
+
// Canon Part 8: payloads carry scalar enums + framework names + sha256 hashes only;
|
|
176
|
+
// theme strings are sanitized at write time per the Phase 90-06 sanitizeDetailScalar
|
|
177
|
+
// precedent. Raw artifact content never lands in a memory_event.
|
|
178
|
+
'breakthrough_detected_soft',
|
|
179
|
+
'breakthrough_surfaced',
|
|
180
|
+
'breakthrough_confirmed',
|
|
181
|
+
'breakthrough_dismissed',
|
|
182
|
+
'breakthrough_filed_as_decision',
|
|
183
|
+
'breakthrough_throttled',
|
|
184
|
+
// Phase 120-02 Wave 2 additive extension (D-20 third structural enforcement
|
|
185
|
+
// point: surfaceBreakthrough refuses provenance-less Breakthrough nodes at
|
|
186
|
+
// surface time and emits this event for /mos:doctor traceability). Mirrors
|
|
187
|
+
// the Phase 120-00 6-string additive idiom verbatim. logEvent already
|
|
188
|
+
// rejects event_type values outside EVENT_TYPES -- so this is accepted only
|
|
189
|
+
// because it is now IN the Set. Set size grows additively by 1.
|
|
190
|
+
//
|
|
191
|
+
// Canon Part 4: every choice is graph data -- the refusal itself is a typed
|
|
192
|
+
// signal that an upstream caller attempted to bypass the D-20 invariant.
|
|
193
|
+
// Canon Part 8: pure LOCAL telemetry; no Brain coupling; payload carries
|
|
194
|
+
// breakthrough_id + reason scalars only.
|
|
195
|
+
'breakthrough_surface_blocked',
|
|
196
|
+
// Phase 120-03 Wave 2 additive extension (D-18 SOFT_BAND review queue telemetry
|
|
197
|
+
// mirror). Mirrors the Phase 120-02 1-string + Phase 120-00 6-string + 117-00
|
|
198
|
+
// 6-string + 124-02 2-string additive idiom verbatim. logEvent already rejects
|
|
199
|
+
// event_type values outside EVENT_TYPES -- so this is accepted only because it
|
|
200
|
+
// is now IN the Set. Set size grows additively by 1.
|
|
201
|
+
//
|
|
202
|
+
// Canon Part 4: every choice is graph data; the SOFT_BAND review queue is the
|
|
203
|
+
// typed graph signal for D-18 mid-confidence candidates that the system queues
|
|
204
|
+
// for manual sample-20% weekly review (becomes retraining data per CONTEXT.md).
|
|
205
|
+
// Canon Part 8: payload carries scalar enums (kind), numeric confidence, and the
|
|
206
|
+
// queue_id handle; no raw artifact content lands in this event.
|
|
207
|
+
// Canon Part 9: ALL writes via navigation.cjs::logMemoryEvent chokepoint.
|
|
208
|
+
'breakthrough_in_review_queue',
|
|
209
|
+
// 260517-dcw dogfood-bridge extension (Canon Part 6 Product-as-Venture; D-04
|
|
210
|
+
// dog-fooding mandate telemetry mirror). Six strings; mirrors the Phase 120-00
|
|
211
|
+
// 6-string + 117-00 6-string + 124-02 2-string + 110-02 3-string additive idiom.
|
|
212
|
+
// logEvent already rejects event_type values outside EVENT_TYPES -- so these are
|
|
213
|
+
// accepted only because they are now IN the Set. Set size grows by 6 (was 48
|
|
214
|
+
// baseline after Phase 120-00; now 54 baseline).
|
|
215
|
+
//
|
|
216
|
+
// Canon Part 9 binding: SQL is the local mind; the plugin's own development
|
|
217
|
+
// activity becomes graph data in the plugin's own venture room. Every Edit/
|
|
218
|
+
// Write/MultiEdit on the plugin repo that matches the dog-food filter is a
|
|
219
|
+
// file_changed event in ~/MindrianRooms/mindrian/room.db.
|
|
220
|
+
//
|
|
221
|
+
// Canon Part 8 binding: payloads carry the absolute path string (LOCAL data,
|
|
222
|
+
// already on the local box; never sent to Brain), the tool name (enum scalar:
|
|
223
|
+
// Edit / Write / MultiEdit), and the ISO timestamp. Zero user-content egress.
|
|
224
|
+
//
|
|
225
|
+
// Active emit site: scripts/dogfood-emit.cjs (file_changed only in this plan).
|
|
226
|
+
// Stub event types (no callers yet; reserved for future triggers per task_scope):
|
|
227
|
+
// commit_landed -> a git post-commit hook (future)
|
|
228
|
+
// phase_completed -> /gsd:phase-complete (future)
|
|
229
|
+
// release_shipped -> scripts/release.sh post-publish (future)
|
|
230
|
+
// tester_signal -> tester reply ingestion (future)
|
|
231
|
+
// decision_captured -> /mos:decide F.1 selector (future)
|
|
232
|
+
'file_changed',
|
|
233
|
+
'commit_landed',
|
|
234
|
+
'phase_completed',
|
|
235
|
+
'release_shipped',
|
|
236
|
+
'tester_signal',
|
|
237
|
+
'decision_captured',
|
|
112
238
|
]));
|
|
113
239
|
|
|
114
240
|
function isPlainObject(v) {
|
package/lib/core/navigation.cjs
CHANGED
|
@@ -30,6 +30,7 @@ const packet = require('./navigation/packet.cjs');
|
|
|
30
30
|
const ingestion = require('./navigation/ingestion.cjs');
|
|
31
31
|
const roomHome = require('./navigation/room-home.cjs');
|
|
32
32
|
const edges = require('./navigation/edges.cjs');
|
|
33
|
+
const dashboardHelpers = require('./navigation/dashboard-helpers.cjs');
|
|
33
34
|
|
|
34
35
|
function notImplementedYet(name, plan) {
|
|
35
36
|
return function () {
|
|
@@ -88,4 +89,14 @@ module.exports = {
|
|
|
88
89
|
// 116/117/118 will extend the allowlist additively for tension / auto-explore /
|
|
89
90
|
// MVA edges. Same additive-re-export pattern as logMemoryEvent + firstCapturedLastTouchedBySection.)
|
|
90
91
|
writeEdge: edges.writeEdge,
|
|
92
|
+
|
|
93
|
+
// Dashboard MVA helpers (Phase 118 Plan 02 -- additive re-export so the
|
|
94
|
+
// lib/agents/mva/dashboard-graph-neighborhood.cjs agent goes through the
|
|
95
|
+
// navigation chokepoint per Canon Part 9 D-06 invariant. Same additive-
|
|
96
|
+
// re-export pattern as logMemoryEvent / firstCapturedLastTouchedBySection /
|
|
97
|
+
// writeEdge. detectActiveRoom mirrors scripts/brain-derive-command.cjs
|
|
98
|
+
// line 142 verbatim; getRecentDecisionNeighborhood is a thin wrapper that
|
|
99
|
+
// resolves the focus node + calls the existing getNeighborhood chokepoint.)
|
|
100
|
+
detectActiveRoom: dashboardHelpers.detectActiveRoom,
|
|
101
|
+
getRecentDecisionNeighborhood: dashboardHelpers.getRecentDecisionNeighborhood,
|
|
91
102
|
};
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2026 Mindrian. BSL 1.1.
|
|
3
|
+
*
|
|
4
|
+
* Phase 118-04 Plan 04 Task 1 -- resolve-vercel-key.
|
|
5
|
+
*
|
|
6
|
+
* The ONE resolver for "where is the Vercel deploy token on this machine?".
|
|
7
|
+
* Mirrors lib/core/resolve-brain-key.cjs (Phase 95.6 / Phase 123 Plan-07).
|
|
8
|
+
*
|
|
9
|
+
* Precedence per LD2 (Locked Decision 2 in 118-CONTEXT.md):
|
|
10
|
+
* 1. process.env.VERCEL_TOKEN -- explicit operator intent, highest.
|
|
11
|
+
* 2. <home>/.mindrian.env -- global backup, persists across CWDs.
|
|
12
|
+
* 3. <cwd>/.env -- project-local override.
|
|
13
|
+
* 4. null -- triggers local-file fallback path.
|
|
14
|
+
*
|
|
15
|
+
* Quote-stripping: handles both `VERCEL_TOKEN="abc"` (double-quoted) and
|
|
16
|
+
* `VERCEL_TOKEN=abc` (raw) per feedback_gmail_qp_env_var_corruption.md.
|
|
17
|
+
*
|
|
18
|
+
* Returns:
|
|
19
|
+
* resolveVercelKey({home?, cwd?}) -> string | null
|
|
20
|
+
*
|
|
21
|
+
* Constants:
|
|
22
|
+
* VERCEL_PROJECT_NAME = 'mindrianos-briefs'
|
|
23
|
+
*
|
|
24
|
+
* Canon Part 8: this module reads LOCAL files and env only. Zero network
|
|
25
|
+
* surface. The Vercel API call is mva-vercel-deploy.cjs's job; this module
|
|
26
|
+
* only DISCOVERS whether a token exists.
|
|
27
|
+
*
|
|
28
|
+
* No transitive runtime dependencies; node built-ins only.
|
|
29
|
+
*/
|
|
30
|
+
'use strict';
|
|
31
|
+
|
|
32
|
+
const fs = require('node:fs');
|
|
33
|
+
const path = require('node:path');
|
|
34
|
+
const os = require('node:os');
|
|
35
|
+
|
|
36
|
+
/** @type {string} The project name on Vercel where deck deploys live. */
|
|
37
|
+
const VERCEL_PROJECT_NAME = 'mindrianos-briefs';
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Parse a single VERCEL_TOKEN=... line out of a (possibly multi-line) env-file
|
|
41
|
+
* body. Returns the trimmed value with surrounding double-quotes stripped, or
|
|
42
|
+
* null if the line is absent or the value is empty.
|
|
43
|
+
*
|
|
44
|
+
* @param {string} body
|
|
45
|
+
* @returns {string|null}
|
|
46
|
+
*/
|
|
47
|
+
function _parseKey(body) {
|
|
48
|
+
const m = body.match(/^VERCEL_TOKEN\s*=\s*(.+?)\s*$/m);
|
|
49
|
+
if (!m) return null;
|
|
50
|
+
let v = m[1].trim();
|
|
51
|
+
// Strip surrounding double-quotes if present
|
|
52
|
+
if (v.length >= 2 && v.startsWith('"') && v.endsWith('"')) {
|
|
53
|
+
v = v.slice(1, -1);
|
|
54
|
+
}
|
|
55
|
+
return v.length > 0 ? v : null;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Resolve the Vercel deploy token from the standard precedence chain.
|
|
60
|
+
*
|
|
61
|
+
* The `home` and `cwd` parameters exist as test seams (mirrors
|
|
62
|
+
* resolve-brain-key.cjs pattern). Env-aware home resolution so hermetic tests
|
|
63
|
+
* overriding process.env.HOME work on Linux/POSIX, where os.homedir() reads
|
|
64
|
+
* /etc/passwd and ignores the env override.
|
|
65
|
+
*
|
|
66
|
+
* @param {{home?: string, cwd?: string}} [opts]
|
|
67
|
+
* @returns {string|null}
|
|
68
|
+
*/
|
|
69
|
+
function resolveVercelKey(opts) {
|
|
70
|
+
const o = opts || {};
|
|
71
|
+
const home = o.home || process.env.HOME || process.env.USERPROFILE || os.homedir();
|
|
72
|
+
const cwd = o.cwd || process.cwd();
|
|
73
|
+
|
|
74
|
+
// (1) Env var wins.
|
|
75
|
+
if (process.env.VERCEL_TOKEN) {
|
|
76
|
+
const v = String(process.env.VERCEL_TOKEN).trim();
|
|
77
|
+
if (v.length > 0) return v;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// (2) <home>/.mindrian.env
|
|
81
|
+
const mindrianEnvPath = path.join(home, '.mindrian.env');
|
|
82
|
+
if (fs.existsSync(mindrianEnvPath)) {
|
|
83
|
+
try {
|
|
84
|
+
const body = fs.readFileSync(mindrianEnvPath, 'utf8');
|
|
85
|
+
const v = _parseKey(body);
|
|
86
|
+
if (v) return v;
|
|
87
|
+
} catch (_e) { /* fall through */ }
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// (3) <cwd>/.env
|
|
91
|
+
const cwdEnvPath = path.join(cwd, '.env');
|
|
92
|
+
if (fs.existsSync(cwdEnvPath)) {
|
|
93
|
+
try {
|
|
94
|
+
const body = fs.readFileSync(cwdEnvPath, 'utf8');
|
|
95
|
+
const v = _parseKey(body);
|
|
96
|
+
if (v) return v;
|
|
97
|
+
} catch (_e) { /* fall through */ }
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// (4) not-found
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
module.exports = {
|
|
105
|
+
resolveVercelKey,
|
|
106
|
+
VERCEL_PROJECT_NAME,
|
|
107
|
+
};
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2026 Mindrian. BSL 1.1.
|
|
3
|
+
*
|
|
4
|
+
* Phase 118-04 Plan 04 Task 1 -- resolve-vercel-key tests.
|
|
5
|
+
*
|
|
6
|
+
* Mirrors test patterns from lib/core/resolve-brain-key.cjs tests.
|
|
7
|
+
* Precedence per LD2: process.env.VERCEL_TOKEN -> <home>/.mindrian.env ->
|
|
8
|
+
* <cwd>/.env -> null.
|
|
9
|
+
*
|
|
10
|
+
* Quote-stripping: handles both `VERCEL_TOKEN="abc"` (double-quoted) and
|
|
11
|
+
* `VERCEL_TOKEN=abc` (raw) per feedback_gmail_qp_env_var_corruption.md.
|
|
12
|
+
*
|
|
13
|
+
* VERCEL_PROJECT_NAME is exported as the constant 'mindrianos-briefs'.
|
|
14
|
+
*/
|
|
15
|
+
'use strict';
|
|
16
|
+
|
|
17
|
+
const test = require('node:test');
|
|
18
|
+
const assert = require('node:assert/strict');
|
|
19
|
+
const fs = require('node:fs');
|
|
20
|
+
const os = require('node:os');
|
|
21
|
+
const path = require('node:path');
|
|
22
|
+
|
|
23
|
+
function _mkTmpHome() {
|
|
24
|
+
return fs.mkdtempSync(path.join(os.tmpdir(), 'mva-vercel-key-test-'));
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function _cleanup(dir) {
|
|
28
|
+
try { fs.rmSync(dir, { recursive: true, force: true }); } catch (_e) { /* ignore */ }
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Force-reload module after env mutation
|
|
32
|
+
function _freshRequire() {
|
|
33
|
+
const p = require.resolve('./resolve-vercel-key.cjs');
|
|
34
|
+
delete require.cache[p];
|
|
35
|
+
return require('./resolve-vercel-key.cjs');
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
test('Test 1: process.env.VERCEL_TOKEN takes precedence over file', () => {
|
|
39
|
+
const home = _mkTmpHome();
|
|
40
|
+
try {
|
|
41
|
+
fs.writeFileSync(path.join(home, '.mindrian.env'),
|
|
42
|
+
'VERCEL_TOKEN="from-file"\n', { mode: 0o600 });
|
|
43
|
+
const prev = process.env.VERCEL_TOKEN;
|
|
44
|
+
process.env.VERCEL_TOKEN = 'from-env';
|
|
45
|
+
try {
|
|
46
|
+
const { resolveVercelKey } = _freshRequire();
|
|
47
|
+
const r = resolveVercelKey({ home });
|
|
48
|
+
assert.equal(r, 'from-env');
|
|
49
|
+
} finally {
|
|
50
|
+
if (prev === undefined) { delete process.env.VERCEL_TOKEN; }
|
|
51
|
+
else { process.env.VERCEL_TOKEN = prev; }
|
|
52
|
+
}
|
|
53
|
+
} finally {
|
|
54
|
+
_cleanup(home);
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
test('Test 2: ~/.mindrian.env with quoted VERCEL_TOKEN resolves correctly', () => {
|
|
59
|
+
const home = _mkTmpHome();
|
|
60
|
+
try {
|
|
61
|
+
fs.writeFileSync(path.join(home, '.mindrian.env'),
|
|
62
|
+
'OTHER_VAR=ignore\nVERCEL_TOKEN="abc123"\n', { mode: 0o600 });
|
|
63
|
+
const prev = process.env.VERCEL_TOKEN;
|
|
64
|
+
delete process.env.VERCEL_TOKEN;
|
|
65
|
+
try {
|
|
66
|
+
const { resolveVercelKey } = _freshRequire();
|
|
67
|
+
const r = resolveVercelKey({ home, cwd: home });
|
|
68
|
+
assert.equal(r, 'abc123');
|
|
69
|
+
} finally {
|
|
70
|
+
if (prev !== undefined) process.env.VERCEL_TOKEN = prev;
|
|
71
|
+
}
|
|
72
|
+
} finally {
|
|
73
|
+
_cleanup(home);
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
test('Test 3: no env + no file = null', () => {
|
|
78
|
+
const home = _mkTmpHome();
|
|
79
|
+
try {
|
|
80
|
+
const prev = process.env.VERCEL_TOKEN;
|
|
81
|
+
delete process.env.VERCEL_TOKEN;
|
|
82
|
+
try {
|
|
83
|
+
const { resolveVercelKey } = _freshRequire();
|
|
84
|
+
const r = resolveVercelKey({ home, cwd: home });
|
|
85
|
+
assert.equal(r, null);
|
|
86
|
+
} finally {
|
|
87
|
+
if (prev !== undefined) process.env.VERCEL_TOKEN = prev;
|
|
88
|
+
}
|
|
89
|
+
} finally {
|
|
90
|
+
_cleanup(home);
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
test('Test 4: ~/.mindrian.env with unquoted VERCEL_TOKEN resolves correctly', () => {
|
|
95
|
+
const home = _mkTmpHome();
|
|
96
|
+
try {
|
|
97
|
+
fs.writeFileSync(path.join(home, '.mindrian.env'),
|
|
98
|
+
'VERCEL_TOKEN=raw-no-quotes\n', { mode: 0o600 });
|
|
99
|
+
const prev = process.env.VERCEL_TOKEN;
|
|
100
|
+
delete process.env.VERCEL_TOKEN;
|
|
101
|
+
try {
|
|
102
|
+
const { resolveVercelKey } = _freshRequire();
|
|
103
|
+
const r = resolveVercelKey({ home, cwd: home });
|
|
104
|
+
assert.equal(r, 'raw-no-quotes');
|
|
105
|
+
} finally {
|
|
106
|
+
if (prev !== undefined) process.env.VERCEL_TOKEN = prev;
|
|
107
|
+
}
|
|
108
|
+
} finally {
|
|
109
|
+
_cleanup(home);
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
test('Test 5: VERCEL_PROJECT_NAME exported constant === mindrianos-briefs', () => {
|
|
114
|
+
const { VERCEL_PROJECT_NAME } = _freshRequire();
|
|
115
|
+
assert.equal(VERCEL_PROJECT_NAME, 'mindrianos-briefs');
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
test('Test 5b: CWD .env fallback when ~/.mindrian.env absent', () => {
|
|
119
|
+
const home = _mkTmpHome();
|
|
120
|
+
const cwd = _mkTmpHome();
|
|
121
|
+
try {
|
|
122
|
+
fs.writeFileSync(path.join(cwd, '.env'),
|
|
123
|
+
'VERCEL_TOKEN="from-cwd-env"\n', { mode: 0o600 });
|
|
124
|
+
const prev = process.env.VERCEL_TOKEN;
|
|
125
|
+
delete process.env.VERCEL_TOKEN;
|
|
126
|
+
try {
|
|
127
|
+
const { resolveVercelKey } = _freshRequire();
|
|
128
|
+
const r = resolveVercelKey({ home, cwd });
|
|
129
|
+
assert.equal(r, 'from-cwd-env');
|
|
130
|
+
} finally {
|
|
131
|
+
if (prev !== undefined) process.env.VERCEL_TOKEN = prev;
|
|
132
|
+
}
|
|
133
|
+
} finally {
|
|
134
|
+
_cleanup(home);
|
|
135
|
+
_cleanup(cwd);
|
|
136
|
+
}
|
|
137
|
+
});
|