mellos-mapping 0.18.0 → 0.19.0
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/README.md +15 -0
- package/README.zh-CN.md +13 -0
- package/dist/server.mjs +90 -2
- package/dist/watch.mjs +68 -57
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -265,6 +265,21 @@ When a hidden sub-map changes in the background, the footer says so.
|
|
|
265
265
|
| `mmap_update` | Record progress: `planned → in-progress → done` (+evidence), `regressed`, group/lane membership, node kind |
|
|
266
266
|
| `mmap_remove` | Revise: drop edges, nodes, groups, lanes, empty bands |
|
|
267
267
|
| `mmap_view` | Render the current map as text inline (optional `zoom`) |
|
|
268
|
+
| `mmap_setup` | Get/set the project's mapping policy — when maps open |
|
|
269
|
+
|
|
270
|
+
### Setup: choose when maps open
|
|
271
|
+
|
|
272
|
+
Each project chooses how eager mapping is, once, via `/mmap setup` (or the
|
|
273
|
+
first time the assistant declares a map — the reply nudges it to ask you):
|
|
274
|
+
|
|
275
|
+
- `always` — map every structured task: workflows, designs, architecture,
|
|
276
|
+
technical dependencies.
|
|
277
|
+
- `complex` — map only medium or complex tasks (the default until configured).
|
|
278
|
+
- `on-request` — map only when you explicitly ask.
|
|
279
|
+
|
|
280
|
+
The choice is stored in `.claude/mellos-mapping.config.json` and guides the
|
|
281
|
+
assistant; it never blocks the tools, and asking for a map explicitly always
|
|
282
|
+
works under any policy.
|
|
268
283
|
|
|
269
284
|
Structural invariants enforced by the tools: layers form a total order by
|
|
270
285
|
rank; every node lives in exactly one layer; edges point **strictly
|
package/README.zh-CN.md
CHANGED
|
@@ -242,6 +242,19 @@ npx -y -p mellos-mapping mellos-mapping-watch
|
|
|
242
242
|
| `mmap_update` | 记录进度:`planned → in-progress → done`(附证据)、`regressed`、分组/泳道归属、节点 kind |
|
|
243
243
|
| `mmap_remove` | 修订:删除边、节点、分组、泳道、空层 |
|
|
244
244
|
| `mmap_view` | 把当前地图渲染成文本,直接在对话里看(可选 `zoom` 参数) |
|
|
245
|
+
| `mmap_setup` | 查/设本项目的建图策略——什么时候开地图 |
|
|
246
|
+
|
|
247
|
+
### Setup:选择什么时候建图
|
|
248
|
+
|
|
249
|
+
每个项目选一次建图的积极程度,用 `/mmap setup`(或 AI 第一次 declare 时,
|
|
250
|
+
工具响应会引导它来问你):
|
|
251
|
+
|
|
252
|
+
- `always` —— 任何有结构的任务都建图:流程、设计、架构、技术依赖。
|
|
253
|
+
- `complex` —— 只在中等或复杂任务时建图(未配置时的默认行为)。
|
|
254
|
+
- `on-request` —— 只在你明确要求时建图。
|
|
255
|
+
|
|
256
|
+
选择保存在 `.claude/mellos-mapping.config.json`,用于引导 AI;它从不阻止
|
|
257
|
+
工具本身——无论什么策略,明确要求建图永远有效。
|
|
245
258
|
|
|
246
259
|
工具强制的结构不变量:层按 rank 构成全序;每个节点恰好属于一层;边**严格
|
|
247
260
|
向下**——因此图从构造上就是无环的;节点不能依赖同层兄弟(如果 A 需要
|
package/dist/server.mjs
CHANGED
|
@@ -22141,6 +22141,57 @@ var PAGES_DIR_NAME = "mellos-mapping.pages";
|
|
|
22141
22141
|
function pageFilePath(defaultFile, page) {
|
|
22142
22142
|
return page === void 0 ? defaultFile : join(dirname(defaultFile), PAGES_DIR_NAME, `${page}.json`);
|
|
22143
22143
|
}
|
|
22144
|
+
var CONFIG_FILE_NAME = "mellos-mapping.config.json";
|
|
22145
|
+
var CONFIG_FILE_VERSION = 1;
|
|
22146
|
+
function configFilePath(defaultFile) {
|
|
22147
|
+
return join(dirname(defaultFile), CONFIG_FILE_NAME);
|
|
22148
|
+
}
|
|
22149
|
+
var MAPPING_POLICIES = ["always", "complex", "on-request"];
|
|
22150
|
+
function makeMappingPolicy(raw) {
|
|
22151
|
+
return MAPPING_POLICIES.includes(raw) ? ok(raw) : err({ kind: "invalid-policy", raw, allowed: MAPPING_POLICIES });
|
|
22152
|
+
}
|
|
22153
|
+
function describeMappingPolicy(policy) {
|
|
22154
|
+
switch (policy) {
|
|
22155
|
+
case "always":
|
|
22156
|
+
return "map every structured task \u2014 workflows, designs, architecture, technical dependencies";
|
|
22157
|
+
case "complex":
|
|
22158
|
+
return "map only medium or complex tasks \u2014 several modules, a new subsystem, roughly an hour or more";
|
|
22159
|
+
case "on-request":
|
|
22160
|
+
return "map only when the user explicitly asks";
|
|
22161
|
+
}
|
|
22162
|
+
}
|
|
22163
|
+
function loadMappingPolicy(defaultFile) {
|
|
22164
|
+
const path = configFilePath(defaultFile);
|
|
22165
|
+
let text2;
|
|
22166
|
+
try {
|
|
22167
|
+
text2 = readFileSync(path, "utf8");
|
|
22168
|
+
} catch (e) {
|
|
22169
|
+
if (e.code === "ENOENT") return ok(void 0);
|
|
22170
|
+
throw e;
|
|
22171
|
+
}
|
|
22172
|
+
let raw;
|
|
22173
|
+
try {
|
|
22174
|
+
raw = JSON.parse(text2);
|
|
22175
|
+
} catch (e) {
|
|
22176
|
+
return err({ kind: "malformed-json", path, detail: e.message });
|
|
22177
|
+
}
|
|
22178
|
+
if (!isRecord(raw)) return err({ kind: "bad-shape", path, detail: "root is not an object" });
|
|
22179
|
+
if (raw["version"] !== CONFIG_FILE_VERSION) {
|
|
22180
|
+
return err({ kind: "bad-shape", path, detail: `version is ${String(raw["version"])}, expected ${CONFIG_FILE_VERSION}` });
|
|
22181
|
+
}
|
|
22182
|
+
const rawPolicy = raw["policy"];
|
|
22183
|
+
if (rawPolicy === void 0) return ok(void 0);
|
|
22184
|
+
if (typeof rawPolicy !== "string") return err({ kind: "bad-shape", path, detail: "policy is not a string" });
|
|
22185
|
+
const policy = makeMappingPolicy(rawPolicy);
|
|
22186
|
+
return policy.ok ? ok(policy.value) : err({ kind: "bad-shape", path, detail: `policy is "${rawPolicy}", expected one of: ${MAPPING_POLICIES.join(" | ")}` });
|
|
22187
|
+
}
|
|
22188
|
+
function saveMappingPolicy(defaultFile, policy) {
|
|
22189
|
+
const path = configFilePath(defaultFile);
|
|
22190
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
22191
|
+
const tmp = path + ".tmp";
|
|
22192
|
+
writeFileSync(tmp, JSON.stringify({ version: CONFIG_FILE_VERSION, policy }, null, 2) + "\n", "utf8");
|
|
22193
|
+
renameSync(tmp, path);
|
|
22194
|
+
}
|
|
22144
22195
|
function describeStoreError(e) {
|
|
22145
22196
|
switch (e.kind) {
|
|
22146
22197
|
case "not-found":
|
|
@@ -22515,7 +22566,7 @@ function summarize(map) {
|
|
|
22515
22566
|
|
|
22516
22567
|
// src/server/server.ts
|
|
22517
22568
|
var SERVER_NAME = "mellos-mapping";
|
|
22518
|
-
var SERVER_VERSION = "0.
|
|
22569
|
+
var SERVER_VERSION = "0.19.0";
|
|
22519
22570
|
var ID = external_exports.string().regex(/^[a-z0-9][a-z0-9-]{0,63}$/, "lowercase letters, digits and dashes, 1-64 chars").describe("stable kebab-case identifier");
|
|
22520
22571
|
var PAGE = ID.optional().describe(
|
|
22521
22572
|
"page (parallel map) this call targets; omit for the default page. One effort = one page: start a NEW effort on its own page named after the effort, so concurrent sessions never write over each other and the pane can switch between pages."
|
|
@@ -22552,6 +22603,13 @@ function buildServer(stateFile) {
|
|
|
22552
22603
|
saveMapFile(file, applied.value);
|
|
22553
22604
|
return text(summarize(applied.value) + (page !== void 0 ? ` [page: ${page}]` : ""));
|
|
22554
22605
|
};
|
|
22606
|
+
const setupNudge = () => {
|
|
22607
|
+
const policy = loadMappingPolicy(stateFile);
|
|
22608
|
+
if (!policy.ok) return `
|
|
22609
|
+
note: ${describeStoreError(policy.error)} \u2014 fix it or rerun setup (mmap_setup).`;
|
|
22610
|
+
if (policy.value !== void 0) return "";
|
|
22611
|
+
return "\nnote: mapping policy not set for this project. Ask the user when maps should open \u2014 " + MAPPING_POLICIES.map((p) => `${p} (${describeMappingPolicy(p)})`).join("; ") + " \u2014 then record the answer with mmap_setup.";
|
|
22612
|
+
};
|
|
22555
22613
|
server.registerTool(
|
|
22556
22614
|
"mmap_declare",
|
|
22557
22615
|
{
|
|
@@ -22599,7 +22657,12 @@ function buildServer(stateFile) {
|
|
|
22599
22657
|
edges: external_exports.array(EDGE.extend({ label: external_exports.string().max(80).optional().describe("what flows along the edge") })).optional()
|
|
22600
22658
|
}
|
|
22601
22659
|
},
|
|
22602
|
-
(input) =>
|
|
22660
|
+
(input) => {
|
|
22661
|
+
const result = mutate(input.page, (map) => applyDeclare(map, input));
|
|
22662
|
+
if (result.isError === true) return result;
|
|
22663
|
+
const nudge = setupNudge();
|
|
22664
|
+
return nudge === "" ? result : text((result.content[0]?.text ?? "") + nudge);
|
|
22665
|
+
}
|
|
22603
22666
|
);
|
|
22604
22667
|
server.registerTool(
|
|
22605
22668
|
"mmap_update",
|
|
@@ -22641,6 +22704,31 @@ function buildServer(stateFile) {
|
|
|
22641
22704
|
},
|
|
22642
22705
|
(input) => mutate(input.page, (map) => applyRemove(map, input))
|
|
22643
22706
|
);
|
|
22707
|
+
server.registerTool(
|
|
22708
|
+
"mmap_setup",
|
|
22709
|
+
{
|
|
22710
|
+
title: "Configure when maps open",
|
|
22711
|
+
description: `Get or set this project's mapping policy \u2014 WHEN the assistant opens a Mellos map. Call with no arguments to read it. If it reports "not set", ask the USER to choose (never pick for them): always = ` + describeMappingPolicy("always") + "; complex = " + describeMappingPolicy("complex") + "; on-request = " + describeMappingPolicy("on-request") + ". Then call again with their choice to persist it. The policy guides you; it never blocks the tools, and an explicit user request for a map always wins.",
|
|
22712
|
+
inputSchema: {
|
|
22713
|
+
policy: external_exports.enum(MAPPING_POLICIES).optional().describe("the user's choice to persist; omit to read the current policy")
|
|
22714
|
+
}
|
|
22715
|
+
},
|
|
22716
|
+
(input) => {
|
|
22717
|
+
if (input.policy !== void 0) {
|
|
22718
|
+
const policy = input.policy;
|
|
22719
|
+
saveMappingPolicy(stateFile, policy);
|
|
22720
|
+
return text(`mapping policy set: ${policy} \u2014 ${describeMappingPolicy(policy)} [${configFilePath(stateFile)}]`);
|
|
22721
|
+
}
|
|
22722
|
+
const loaded = loadMappingPolicy(stateFile);
|
|
22723
|
+
if (!loaded.ok) return text(describeStoreError(loaded.error), true);
|
|
22724
|
+
if (loaded.value === void 0) {
|
|
22725
|
+
return text(
|
|
22726
|
+
"mapping policy not set. Ask the user to choose one of: " + MAPPING_POLICIES.map((p) => `${p} (${describeMappingPolicy(p)})`).join("; ") + " \u2014 then call mmap_setup with their choice. Until then act as complex."
|
|
22727
|
+
);
|
|
22728
|
+
}
|
|
22729
|
+
return text(`mapping policy: ${loaded.value} \u2014 ${describeMappingPolicy(loaded.value)}`);
|
|
22730
|
+
}
|
|
22731
|
+
);
|
|
22644
22732
|
server.registerTool(
|
|
22645
22733
|
"mmap_view",
|
|
22646
22734
|
{
|
package/dist/watch.mjs
CHANGED
|
@@ -3,7 +3,7 @@ import { createRequire } from 'node:module'; const require = createRequire(impor
|
|
|
3
3
|
|
|
4
4
|
// src/watch/watch.ts
|
|
5
5
|
import { realpathSync, statSync } from "node:fs";
|
|
6
|
-
import { join as join2 } from "node:path";
|
|
6
|
+
import { dirname as dirname2, join as join2 } from "node:path";
|
|
7
7
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
8
8
|
|
|
9
9
|
// src/domain/types.ts
|
|
@@ -1535,19 +1535,8 @@ function nodePanel(map, focusId, unicode, width, pinned, rows = PANEL_CONTENT_RO
|
|
|
1535
1535
|
}
|
|
1536
1536
|
return lines.slice(0, rows);
|
|
1537
1537
|
}
|
|
1538
|
-
var
|
|
1539
|
-
|
|
1540
|
-
E: ["####", "#", "###", "#", "####"],
|
|
1541
|
-
L: ["#", "#", "#", "#", "####"],
|
|
1542
|
-
O: [" ###", "# #", "# #", "# #", " ###"],
|
|
1543
|
-
S: [" ####", "#", " ###", " #", "####"],
|
|
1544
|
-
A: [" ###", "# #", "#####", "# #", "# #"],
|
|
1545
|
-
P: ["####", "# #", "####", "#", "#"],
|
|
1546
|
-
I: ["###", " #", " #", " #", "###"],
|
|
1547
|
-
N: ["# #", "## #", "# # #", "# ##", "# #"],
|
|
1548
|
-
G: [" ####", "#", "# ##", "# #", " ###"]
|
|
1549
|
-
};
|
|
1550
|
-
var SPLASH_ROWS = 5;
|
|
1538
|
+
var WATER_ROWS = 7;
|
|
1539
|
+
var WATER_COLS_MAX = 60;
|
|
1551
1540
|
var SPLASH_SHADES = {
|
|
1552
1541
|
unicode: ["\u2591", "\u2591", "\u2592", "\u2592", "\u2593", "\u2593", "\u2588", "\u2588"],
|
|
1553
1542
|
ascii: [".", ".", ":", ":", "=", "=", "#", "#"]
|
|
@@ -1557,23 +1546,24 @@ var SPINNER_FRAMES = {
|
|
|
1557
1546
|
unicode: ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"],
|
|
1558
1547
|
ascii: ["|", "/", "-", "\\"]
|
|
1559
1548
|
};
|
|
1560
|
-
function
|
|
1561
|
-
const
|
|
1562
|
-
const
|
|
1563
|
-
const
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
const
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
});
|
|
1576
|
-
|
|
1549
|
+
function elapsedLabel(ms) {
|
|
1550
|
+
const s = Math.max(0, Math.floor(ms / 1e3));
|
|
1551
|
+
const m = Math.floor(s / 60);
|
|
1552
|
+
const h = Math.floor(m / 60);
|
|
1553
|
+
const two = (n) => String(n).padStart(2, "0");
|
|
1554
|
+
return h > 0 ? `${h}:${two(m % 60)}:${two(s % 60)}` : `${m}:${two(s % 60)}`;
|
|
1555
|
+
}
|
|
1556
|
+
function waitingInfo(s, width) {
|
|
1557
|
+
const w = Math.max(1, width);
|
|
1558
|
+
const clock = s.elapsedMs !== void 0 ? ` \xB7 waiting ${elapsedLabel(s.elapsedMs)}` : "";
|
|
1559
|
+
const lines = [
|
|
1560
|
+
`watching ${s.defaultFile}`,
|
|
1561
|
+
` and ${join2(s.pagesDir, "*.json")}`,
|
|
1562
|
+
`polling every ${s.intervalMs} ms${clock}`
|
|
1563
|
+
];
|
|
1564
|
+
for (const b of s.broken) lines.push(`! ${b}`);
|
|
1565
|
+
lines.push("the map appears at the first mmap_declare");
|
|
1566
|
+
return lines.map((l) => fitWidth(l, w));
|
|
1577
1567
|
}
|
|
1578
1568
|
var WAVE_INTERVAL = 18;
|
|
1579
1569
|
var WAVE_LIFETIME = 64;
|
|
@@ -1624,39 +1614,41 @@ function waveAt(ripples, x, y) {
|
|
|
1624
1614
|
function waveLevel(value) {
|
|
1625
1615
|
return Math.max(-WAVE_LEVELS, Math.min(WAVE_LEVELS, Math.round(value * WAVE_GAIN)));
|
|
1626
1616
|
}
|
|
1627
|
-
function splashFrame(notice, frame, width, height, unicode, color) {
|
|
1628
|
-
const
|
|
1629
|
-
|
|
1630
|
-
if (width < artWidth + 2 || height < art.length + 2) return void 0;
|
|
1617
|
+
function splashFrame(notice, info, frame, width, height, unicode, color) {
|
|
1618
|
+
const fieldW = Math.min(width - 4, WATER_COLS_MAX);
|
|
1619
|
+
if (fieldW < 24 || height < WATER_ROWS + info.length + 3) return void 0;
|
|
1631
1620
|
const mode = unicode ? "unicode" : "ascii";
|
|
1632
1621
|
const shades = SPLASH_SHADES[mode];
|
|
1633
|
-
const
|
|
1634
|
-
const
|
|
1635
|
-
const
|
|
1636
|
-
|
|
1637
|
-
const level = waveLevel(waveAt(ripples, x, y));
|
|
1638
|
-
return color ? `38;5;${WAVE_RAMP[WAVE_LEVELS + level]}` : shades[Math.abs(level)];
|
|
1639
|
-
};
|
|
1640
|
-
const paintRow = (row, y) => {
|
|
1641
|
-
const cells = [...row].map((ch, x) => ch === "#" ? inkOf(x, y) : void 0);
|
|
1622
|
+
const indent = " ".repeat(Math.max(0, Math.floor((width - fieldW) / 2)));
|
|
1623
|
+
const ripples = liveRipples(frame, fieldW, WATER_ROWS);
|
|
1624
|
+
const paintRow = (y) => {
|
|
1625
|
+
const levels = Array.from({ length: fieldW }, (_, x) => waveLevel(waveAt(ripples, x, y)));
|
|
1642
1626
|
let out = "";
|
|
1643
|
-
for (let i = 0; i <
|
|
1644
|
-
const
|
|
1627
|
+
for (let i = 0; i < fieldW; ) {
|
|
1628
|
+
const level = levels[i];
|
|
1645
1629
|
let j = i;
|
|
1646
|
-
while (j <
|
|
1647
|
-
if (
|
|
1648
|
-
else
|
|
1630
|
+
while (j < fieldW && levels[j] === level) j++;
|
|
1631
|
+
if (level === 0) out += " ".repeat(j - i);
|
|
1632
|
+
else {
|
|
1633
|
+
const ink = shades[Math.abs(level)].repeat(j - i);
|
|
1634
|
+
out += color ? `\x1B[38;5;${WAVE_RAMP[WAVE_LEVELS + level]}m${ink}${RESET}` : ink;
|
|
1635
|
+
}
|
|
1649
1636
|
i = j;
|
|
1650
1637
|
}
|
|
1651
1638
|
return out;
|
|
1652
1639
|
};
|
|
1640
|
+
const dim = (s) => color ? `\x1B[90m${s}${RESET}` : s;
|
|
1653
1641
|
const spinner = SPINNER_FRAMES[mode];
|
|
1654
1642
|
const status = fitWidth(`${spinner[frame % spinner.length]} ${notice}`, Math.max(1, width - 2));
|
|
1655
1643
|
const statusIndent = " ".repeat(Math.max(0, Math.floor((width - displayWidth(status)) / 2)));
|
|
1644
|
+
const infoWidth = Math.max(0, ...info.map((l) => displayWidth(l)));
|
|
1645
|
+
const infoIndent = " ".repeat(Math.max(0, Math.floor((width - infoWidth) / 2)));
|
|
1656
1646
|
const block = [
|
|
1657
|
-
...
|
|
1647
|
+
...Array.from({ length: WATER_ROWS }, (_, y) => indent + paintRow(y)),
|
|
1658
1648
|
"",
|
|
1659
|
-
statusIndent + (
|
|
1649
|
+
statusIndent + dim(status),
|
|
1650
|
+
"",
|
|
1651
|
+
...info.map((l) => infoIndent + dim(l))
|
|
1660
1652
|
];
|
|
1661
1653
|
return [...Array.from({ length: Math.max(0, Math.floor((height - block.length) / 2)) }, () => ""), ...block];
|
|
1662
1654
|
}
|
|
@@ -1685,8 +1677,10 @@ function main() {
|
|
|
1685
1677
|
let lastFrame = "";
|
|
1686
1678
|
let spinnerFrame = 0;
|
|
1687
1679
|
let splashTick = 0;
|
|
1680
|
+
const startedAt = Date.now();
|
|
1681
|
+
const standbyNotice = "waiting for the first mmap_declare ...";
|
|
1688
1682
|
let map;
|
|
1689
|
-
let notice =
|
|
1683
|
+
let notice = standbyNotice;
|
|
1690
1684
|
let lastCols = process.stdout.columns ?? 0;
|
|
1691
1685
|
let lastRows = process.stdout.rows ?? 0;
|
|
1692
1686
|
let pageFiles = [cfg.file];
|
|
@@ -1755,7 +1749,7 @@ function main() {
|
|
|
1755
1749
|
const entry = pageData.get(file);
|
|
1756
1750
|
if (entry !== void 0 && entry.fresh) pageData.set(file, { ...entry, fresh: false });
|
|
1757
1751
|
map = entry?.map;
|
|
1758
|
-
notice = map
|
|
1752
|
+
notice = map !== void 0 ? "" : entry?.error ?? (file === cfg.file ? standbyNotice : `waiting for ${file} ...`);
|
|
1759
1753
|
const top = topFiles();
|
|
1760
1754
|
const tabIndex = top.indexOf(file);
|
|
1761
1755
|
if (tabIndex >= 0) tabScroll = tabScrollFor(pageTabsOf(top), viewWidth(), cfg.unicode, tabScroll, tabIndex);
|
|
@@ -1813,7 +1807,17 @@ function main() {
|
|
|
1813
1807
|
lastContent = { w: windowed.contentWidth, h: windowed.contentHeight };
|
|
1814
1808
|
if (offsetX !== 0 || offsetY !== 0) panned = ` (+${offsetX},+${offsetY})`;
|
|
1815
1809
|
} else {
|
|
1816
|
-
|
|
1810
|
+
const info = waitingInfo(
|
|
1811
|
+
{
|
|
1812
|
+
defaultFile: cfg.file,
|
|
1813
|
+
pagesDir: join2(dirname2(cfg.file), PAGES_DIR_NAME),
|
|
1814
|
+
intervalMs: cfg.intervalMs,
|
|
1815
|
+
elapsedMs: interactive ? Date.now() - startedAt : void 0,
|
|
1816
|
+
broken: [...pageData.values()].flatMap((e) => e.map === void 0 && e.error !== void 0 ? [e.error] : [])
|
|
1817
|
+
},
|
|
1818
|
+
Math.max(1, viewW - 2)
|
|
1819
|
+
);
|
|
1820
|
+
body = (interactive ? splashFrame(notice, info, splashTick, viewW, viewH, cfg.unicode, cfg.color) : void 0) ?? [fitWidth(notice, viewW), "", ...info.map((l) => fitWidth(` ${l}`, viewW))];
|
|
1817
1821
|
}
|
|
1818
1822
|
if (notice !== "" && map !== void 0) {
|
|
1819
1823
|
body[body.length - 1] = fitWidth(` ${notice}`, viewW);
|
|
@@ -1917,8 +1921,15 @@ function main() {
|
|
|
1917
1921
|
flash = { text: `${cfg.unicode ? "\u229E " : ""}${title} updated`, until: Date.now() + 4e3 };
|
|
1918
1922
|
}
|
|
1919
1923
|
} else if (loaded.error.kind === "malformed-json") {
|
|
1924
|
+
pageData.set(file, {
|
|
1925
|
+
map: entry?.map,
|
|
1926
|
+
mtimeMs: entry?.mtimeMs ?? -1,
|
|
1927
|
+
fresh: entry?.fresh ?? false,
|
|
1928
|
+
error: describeStoreError(loaded.error)
|
|
1929
|
+
});
|
|
1930
|
+
if (file === activeFile && entry?.map === void 0) notice = describeStoreError(loaded.error);
|
|
1920
1931
|
} else {
|
|
1921
|
-
pageData.set(file, { map: entry?.map, mtimeMs, fresh: entry?.fresh ?? false });
|
|
1932
|
+
pageData.set(file, { map: entry?.map, mtimeMs, fresh: entry?.fresh ?? false, error: describeStoreError(loaded.error) });
|
|
1922
1933
|
if (file === activeFile) notice = describeStoreError(loaded.error);
|
|
1923
1934
|
}
|
|
1924
1935
|
}
|
|
@@ -2143,6 +2154,7 @@ export {
|
|
|
2143
2154
|
clampPanelRows,
|
|
2144
2155
|
diveOrigin,
|
|
2145
2156
|
dividerRow,
|
|
2157
|
+
elapsedLabel,
|
|
2146
2158
|
fitWidth,
|
|
2147
2159
|
launchedAsEntry,
|
|
2148
2160
|
liveRipples,
|
|
@@ -2153,14 +2165,13 @@ export {
|
|
|
2153
2165
|
pageTabRow,
|
|
2154
2166
|
panelRowsFromDividerY,
|
|
2155
2167
|
parseArgs,
|
|
2156
|
-
splashArt,
|
|
2157
2168
|
splashFrame,
|
|
2158
2169
|
tabScrollFor,
|
|
2159
2170
|
topLevelFiles,
|
|
2160
2171
|
usableColumns,
|
|
2172
|
+
waitingInfo,
|
|
2161
2173
|
waveAt,
|
|
2162
2174
|
waveHash,
|
|
2163
2175
|
waveLevel,
|
|
2164
|
-
wordArt,
|
|
2165
2176
|
wrapWidth
|
|
2166
2177
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mellos-mapping",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.19.0",
|
|
4
4
|
"mcpName": "io.github.GuangminJu/mellos-mapping",
|
|
5
5
|
"description": "A live layered dependency map for bottom-up development — MCP server + terminal pane. Ghost the design first, then light nodes up from the bottom as they are built and verified.",
|
|
6
6
|
"type": "module",
|