mellos-mapping 0.19.0 → 0.20.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 +17 -4
- package/README.zh-CN.md +16 -4
- package/dist/server.mjs +147 -112
- package/dist/watch.mjs +238 -159
- package/lib/domain/ops.d.ts +112 -0
- package/lib/domain/ops.js +253 -0
- package/lib/domain/types.d.ts +242 -0
- package/lib/domain/types.js +122 -0
- package/lib/render/render.d.ts +102 -0
- package/lib/render/render.js +859 -0
- package/lib/semantics/semantics.d.ts +120 -0
- package/lib/semantics/semantics.js +256 -0
- package/lib/store/format.d.ts +50 -0
- package/lib/store/format.js +215 -0
- package/lib/store/store.d.ts +96 -0
- package/lib/store/store.js +281 -0
- package/package.json +30 -2
- package/scripts/codex-register.mjs +1 -1
- package/scripts/open-pane.mjs +1 -1
package/README.md
CHANGED
|
@@ -147,7 +147,7 @@ npx -y mellos-mapping
|
|
|
147
147
|
```
|
|
148
148
|
|
|
149
149
|
The map file lands in the client session's working directory
|
|
150
|
-
(`.
|
|
150
|
+
(`.mellos/map.json`). Open the live pane from the same project:
|
|
151
151
|
|
|
152
152
|
```
|
|
153
153
|
npx -y -p mellos-mapping mellos-mapping-watch
|
|
@@ -224,8 +224,8 @@ its own pan, zoom and pinned node. Because every page is its own file, two
|
|
|
224
224
|
Claude sessions writing two pages can never clobber each other — this is
|
|
225
225
|
also the answer to running several Claude sessions in one project.
|
|
226
226
|
|
|
227
|
-
State lives in `.
|
|
228
|
-
`.
|
|
227
|
+
State lives in `.mellos/map.json` (the default page) plus
|
|
228
|
+
`.mellos/pages/<page>.json` for named pages — plain JSON,
|
|
229
229
|
safe to commit if you want the maps' history in git.
|
|
230
230
|
|
|
231
231
|
### Diagram kinds
|
|
@@ -299,7 +299,9 @@ The repo is itself layered bottom-up, and each layer has its spec:
|
|
|
299
299
|
| Layer | Code | Owns |
|
|
300
300
|
| --- | --- | --- |
|
|
301
301
|
| 0 domain | `src/domain/` | the map value, structural invariants, pure ops |
|
|
302
|
-
| 1
|
|
302
|
+
| 1 format | `src/store/format.ts` | the state-file format: replay-validated parse, serialize — I/O-free |
|
|
303
|
+
| 1 store | `src/store/store.ts` | atomic state-file persistence on Node |
|
|
304
|
+
| 1 semantics | `src/semantics/` | medium-neutral view semantics: zoom ladder, group aggregation, sequence flip |
|
|
303
305
|
| 2 apply | `src/server/apply.ts` | tool inputs → transactional op sequences |
|
|
304
306
|
| 3 server | `src/server/server.ts` | the four MCP tools over stdio |
|
|
305
307
|
| 4 render | `src/render/`, `src/watch/` | ASCII renderer and the polling pane |
|
|
@@ -307,6 +309,17 @@ The repo is itself layered bottom-up, and each layer has its spec:
|
|
|
307
309
|
`dist/` is committed deliberately: plugin installation clones this repo and
|
|
308
310
|
runs nothing, so entry points ship bundled.
|
|
309
311
|
|
|
312
|
+
### Library
|
|
313
|
+
|
|
314
|
+
The lower layers are also a library (`npm run build` emits `lib/` with type
|
|
315
|
+
declarations; npm packs it). Subpath exports mirror the source:
|
|
316
|
+
`mellos-mapping/domain/types`, `/domain/ops`, `/format`, `/semantics` are
|
|
317
|
+
**browser-safe** — no Node builtins in their import closure, gated by a test —
|
|
318
|
+
so a graphical client (a web panel, an editor view) can parse state files and
|
|
319
|
+
reuse the exact aggregation and zoom semantics the terminal pane draws with.
|
|
320
|
+
`/store` (Node filesystem persistence) and `/render` (the terminal renderer)
|
|
321
|
+
complete the surface for Node hosts.
|
|
322
|
+
|
|
310
323
|
## License
|
|
311
324
|
|
|
312
325
|
MIT
|
package/README.zh-CN.md
CHANGED
|
@@ -134,7 +134,7 @@ CLI……)都能用标准 stdio 条目接入:
|
|
|
134
134
|
npx -y mellos-mapping
|
|
135
135
|
```
|
|
136
136
|
|
|
137
|
-
地图文件落在客户端会话的工作目录(`.
|
|
137
|
+
地图文件落在客户端会话的工作目录(`.mellos/map.json`)。在同
|
|
138
138
|
一项目里打开实况面板:
|
|
139
139
|
|
|
140
140
|
```
|
|
@@ -204,8 +204,8 @@ npx -y -p mellos-mapping mellos-mapping-watch
|
|
|
204
204
|
每页就是一个独立文件,两个 Claude 会话各写各页永远不会互相覆盖——这也是
|
|
205
205
|
同一项目里跑多个 Claude 会话的正确姿势。
|
|
206
206
|
|
|
207
|
-
地图状态存在 `.
|
|
208
|
-
`.
|
|
207
|
+
地图状态存在 `.mellos/map.json`(默认页)和
|
|
208
|
+
`.mellos/pages/<页名>.json`(命名页)——纯 JSON,想在 git
|
|
209
209
|
里留下地图的历史就把它们提交进去。
|
|
210
210
|
|
|
211
211
|
### 图种
|
|
@@ -272,7 +272,9 @@ npm run verify # 类型检查 + 测试 + 打包
|
|
|
272
272
|
| 层 | 代码 | 职责 |
|
|
273
273
|
| --- | --- | --- |
|
|
274
274
|
| 0 domain | `src/domain/` | 地图值、结构不变量、纯操作 |
|
|
275
|
-
| 1
|
|
275
|
+
| 1 format | `src/store/format.ts` | 状态文件格式:重放校验的解析与序列化,零 I/O |
|
|
276
|
+
| 1 store | `src/store/store.ts` | Node 上的原子化状态文件持久化 |
|
|
277
|
+
| 1 semantics | `src/semantics/` | 媒介无关的视图语义:缩放阶梯、分组聚合、时序翻转 |
|
|
276
278
|
| 2 apply | `src/server/apply.ts` | 工具输入 → 事务性操作序列 |
|
|
277
279
|
| 3 server | `src/server/server.ts` | stdio 上的四个 MCP 工具 |
|
|
278
280
|
| 4 render | `src/render/`、`src/watch/` | ASCII 渲染器和轮询面板 |
|
|
@@ -280,6 +282,16 @@ npm run verify # 类型检查 + 测试 + 打包
|
|
|
280
282
|
`dist/` 是刻意提交的:插件安装就是克隆本仓库、不运行任何东西,所以入口
|
|
281
283
|
文件以打包形式随仓库分发。
|
|
282
284
|
|
|
285
|
+
### 库
|
|
286
|
+
|
|
287
|
+
底部各层同时是一个库(`npm run build` 产出带类型声明的 `lib/`,npm 打包
|
|
288
|
+
收录)。子路径导出与源码结构一一对应:`mellos-mapping/domain/types`、
|
|
289
|
+
`/domain/ops`、`/format`、`/semantics` 是**浏览器安全**的——import 闭包中
|
|
290
|
+
没有任何 Node 内建模块,由测试门禁守护——图形客户端(web 面板、编辑器
|
|
291
|
+
视图)可以直接解析状态文件,并复用与终端面板完全一致的聚合与缩放语义。
|
|
292
|
+
`/store`(Node 文件系统持久化)与 `/render`(终端渲染器)补齐 Node 宿主
|
|
293
|
+
所需的完整表面。
|
|
294
|
+
|
|
283
295
|
## 许可证
|
|
284
296
|
|
|
285
297
|
MIT
|
package/dist/server.mjs
CHANGED
|
@@ -21388,13 +21388,66 @@ function removeLayer(map, id) {
|
|
|
21388
21388
|
return ok({ ...map, layers: map.layers.filter((l) => l.id !== id) });
|
|
21389
21389
|
}
|
|
21390
21390
|
|
|
21391
|
-
// src/
|
|
21391
|
+
// src/semantics/semantics.ts
|
|
21392
21392
|
var ZOOM_MIN = -4;
|
|
21393
21393
|
var ZOOM_MAX = 2;
|
|
21394
21394
|
var ZOOM_DEFAULT = 0;
|
|
21395
21395
|
function clampZoom(n) {
|
|
21396
21396
|
return Math.max(ZOOM_MIN, Math.min(ZOOM_MAX, Math.round(n)));
|
|
21397
21397
|
}
|
|
21398
|
+
function zoomMode(zoom) {
|
|
21399
|
+
if (zoom >= 1) return "detail";
|
|
21400
|
+
if (zoom <= -4) return "overview";
|
|
21401
|
+
return "boxes";
|
|
21402
|
+
}
|
|
21403
|
+
function isNeutralKind(map) {
|
|
21404
|
+
return map.kind !== void 0 && map.kind !== "dev";
|
|
21405
|
+
}
|
|
21406
|
+
function aggregateMap(map) {
|
|
21407
|
+
if (map.groups.length === 0) return void 0;
|
|
21408
|
+
const representative = /* @__PURE__ */ new Map();
|
|
21409
|
+
for (const n of map.nodes) representative.set(n.id, n.group ?? n.id);
|
|
21410
|
+
const nodes = map.groups.map((g) => {
|
|
21411
|
+
const members = map.nodes.filter((n) => n.group === g.id);
|
|
21412
|
+
const done = members.filter((n) => n.status === "done").length;
|
|
21413
|
+
return {
|
|
21414
|
+
id: g.id,
|
|
21415
|
+
// neutral kinds document structure, not progress — no member counts
|
|
21416
|
+
label: isNeutralKind(map) ? g.label : `${g.label} ${done}/${members.length}`,
|
|
21417
|
+
layer: g.layer,
|
|
21418
|
+
status: groupStatus(map, g.id)
|
|
21419
|
+
};
|
|
21420
|
+
});
|
|
21421
|
+
for (const n of map.nodes) if (n.group === void 0) nodes.push(n);
|
|
21422
|
+
const seen = /* @__PURE__ */ new Set();
|
|
21423
|
+
const edges = [];
|
|
21424
|
+
for (const e of map.edges) {
|
|
21425
|
+
const from = representative.get(e.from);
|
|
21426
|
+
const to = representative.get(e.to);
|
|
21427
|
+
if (from === to || seen.has(`${from}->${to}`)) continue;
|
|
21428
|
+
seen.add(`${from}->${to}`);
|
|
21429
|
+
edges.push({ from, to });
|
|
21430
|
+
}
|
|
21431
|
+
return {
|
|
21432
|
+
...map.title !== void 0 ? { title: map.title } : {},
|
|
21433
|
+
...map.kind !== void 0 ? { kind: map.kind } : {},
|
|
21434
|
+
layers: map.layers,
|
|
21435
|
+
groups: [],
|
|
21436
|
+
lanes: map.lanes,
|
|
21437
|
+
nodes,
|
|
21438
|
+
edges
|
|
21439
|
+
};
|
|
21440
|
+
}
|
|
21441
|
+
function flipForSequence(map) {
|
|
21442
|
+
if (map.kind !== "sequence") return map;
|
|
21443
|
+
return {
|
|
21444
|
+
...map,
|
|
21445
|
+
layers: map.layers.map((l) => ({ ...l, rank: -l.rank })),
|
|
21446
|
+
edges: map.edges.map((e) => ({ from: e.to, to: e.from, ...e.label !== void 0 ? { label: e.label } : {} }))
|
|
21447
|
+
};
|
|
21448
|
+
}
|
|
21449
|
+
|
|
21450
|
+
// src/render/render.ts
|
|
21398
21451
|
var WIDE_RANGES = [
|
|
21399
21452
|
[4352, 4447],
|
|
21400
21453
|
// Hangul Jamo
|
|
@@ -21659,9 +21712,6 @@ function kindGlyph(kind, unicode) {
|
|
|
21659
21712
|
const pair = NODE_KIND_GLYPHS[kind];
|
|
21660
21713
|
return pair === void 0 ? void 0 : unicode ? pair[0] : pair[1];
|
|
21661
21714
|
}
|
|
21662
|
-
function isNeutralKind(map) {
|
|
21663
|
-
return map.kind !== void 0 && map.kind !== "dev";
|
|
21664
|
-
}
|
|
21665
21715
|
function neutralSkin(unicode) {
|
|
21666
21716
|
return unicode ? { h: "\u2500", v: "\u2502", corners: ["\u256D", "\u256E", "\u2570", "\u256F"], style: "none" } : { h: "-", v: "|", corners: ["+", "+", "+", "+"], style: "none" };
|
|
21667
21717
|
}
|
|
@@ -21671,21 +21721,23 @@ var LEFT_MARGIN = 2;
|
|
|
21671
21721
|
var DETAIL_BUDGET = { innerMin: 22, innerMax: 32, noteRows: 3 };
|
|
21672
21722
|
var DETAIL_PLUS_BUDGET = { innerMin: 30, innerMax: 48, noteRows: 12 };
|
|
21673
21723
|
function zoomGeometry(zoom) {
|
|
21724
|
+
const m = zoomMode(zoom);
|
|
21725
|
+
const mode = m === "overview" ? "constellation" : m;
|
|
21674
21726
|
switch (zoom) {
|
|
21675
21727
|
case 2:
|
|
21676
|
-
return { mode
|
|
21728
|
+
return { mode, scale: 1, pad: 1, boxGap: BOX_GAP, breathe: 1, titleGap: 1, barGap: 1, bandCounts: false, detail: DETAIL_PLUS_BUDGET };
|
|
21677
21729
|
case 1:
|
|
21678
|
-
return { mode
|
|
21730
|
+
return { mode, scale: 1, pad: 1, boxGap: BOX_GAP, breathe: 1, titleGap: 1, barGap: 1, bandCounts: false, detail: DETAIL_BUDGET };
|
|
21679
21731
|
case 0:
|
|
21680
|
-
return { mode
|
|
21732
|
+
return { mode, scale: 1, pad: 1, boxGap: BOX_GAP, breathe: 1, titleGap: 1, barGap: 1, bandCounts: false };
|
|
21681
21733
|
case -1:
|
|
21682
|
-
return { mode
|
|
21734
|
+
return { mode, scale: 0.85, pad: 1, boxGap: BOX_GAP, breathe: 1, titleGap: 1, barGap: 1, bandCounts: false };
|
|
21683
21735
|
case -2:
|
|
21684
|
-
return { mode
|
|
21736
|
+
return { mode, scale: 0.7, pad: 0, boxGap: BOX_GAP, breathe: 0, titleGap: 0, barGap: 1, bandCounts: false };
|
|
21685
21737
|
case -3:
|
|
21686
|
-
return { mode
|
|
21738
|
+
return { mode, scale: 0.55, pad: 0, boxGap: 1, breathe: 0, titleGap: 0, barGap: 1, bandCounts: true };
|
|
21687
21739
|
case -4:
|
|
21688
|
-
return { mode
|
|
21740
|
+
return { mode, scale: 0, pad: 0, boxGap: BOX_GAP, breathe: 0, titleGap: 0, barGap: 1, bandCounts: true };
|
|
21689
21741
|
}
|
|
21690
21742
|
}
|
|
21691
21743
|
var LABEL_BUDGET_MIN = 4;
|
|
@@ -21733,41 +21785,6 @@ function renderMap(map, opts) {
|
|
|
21733
21785
|
const built = buildCanvas(map, opts);
|
|
21734
21786
|
return built.canvas.emit(opts);
|
|
21735
21787
|
}
|
|
21736
|
-
function aggregateMap(map) {
|
|
21737
|
-
if (map.groups.length === 0) return void 0;
|
|
21738
|
-
const representative = /* @__PURE__ */ new Map();
|
|
21739
|
-
for (const n of map.nodes) representative.set(n.id, n.group ?? n.id);
|
|
21740
|
-
const nodes = map.groups.map((g) => {
|
|
21741
|
-
const members = map.nodes.filter((n) => n.group === g.id);
|
|
21742
|
-
const done = members.filter((n) => n.status === "done").length;
|
|
21743
|
-
return {
|
|
21744
|
-
id: g.id,
|
|
21745
|
-
// neutral kinds document structure, not progress — no member counts
|
|
21746
|
-
label: isNeutralKind(map) ? g.label : `${g.label} ${done}/${members.length}`,
|
|
21747
|
-
layer: g.layer,
|
|
21748
|
-
status: groupStatus(map, g.id)
|
|
21749
|
-
};
|
|
21750
|
-
});
|
|
21751
|
-
for (const n of map.nodes) if (n.group === void 0) nodes.push(n);
|
|
21752
|
-
const seen = /* @__PURE__ */ new Set();
|
|
21753
|
-
const edges = [];
|
|
21754
|
-
for (const e of map.edges) {
|
|
21755
|
-
const from = representative.get(e.from);
|
|
21756
|
-
const to = representative.get(e.to);
|
|
21757
|
-
if (from === to || seen.has(`${from}->${to}`)) continue;
|
|
21758
|
-
seen.add(`${from}->${to}`);
|
|
21759
|
-
edges.push({ from, to });
|
|
21760
|
-
}
|
|
21761
|
-
return {
|
|
21762
|
-
...map.title !== void 0 ? { title: map.title } : {},
|
|
21763
|
-
...map.kind !== void 0 ? { kind: map.kind } : {},
|
|
21764
|
-
layers: map.layers,
|
|
21765
|
-
groups: [],
|
|
21766
|
-
lanes: map.lanes,
|
|
21767
|
-
nodes,
|
|
21768
|
-
edges
|
|
21769
|
-
};
|
|
21770
|
-
}
|
|
21771
21788
|
var AGGREGATE_GEO = {
|
|
21772
21789
|
mode: "boxes",
|
|
21773
21790
|
scale: 1,
|
|
@@ -21778,14 +21795,6 @@ var AGGREGATE_GEO = {
|
|
|
21778
21795
|
barGap: 1,
|
|
21779
21796
|
bandCounts: false
|
|
21780
21797
|
};
|
|
21781
|
-
function flipForSequence(map) {
|
|
21782
|
-
if (map.kind !== "sequence") return map;
|
|
21783
|
-
return {
|
|
21784
|
-
...map,
|
|
21785
|
-
layers: map.layers.map((l) => ({ ...l, rank: -l.rank })),
|
|
21786
|
-
edges: map.edges.map((e) => ({ from: e.to, to: e.from, ...e.label !== void 0 ? { label: e.label } : {} }))
|
|
21787
|
-
};
|
|
21788
|
-
}
|
|
21789
21798
|
function buildCanvas(map, opts) {
|
|
21790
21799
|
const oriented = flipForSequence(map);
|
|
21791
21800
|
const plainGeo = zoomGeometry(opts.zoom ?? ZOOM_DEFAULT);
|
|
@@ -22135,63 +22144,9 @@ function drawBox(canvas, box, opts, neutral, focused = false) {
|
|
|
22135
22144
|
// src/store/store.ts
|
|
22136
22145
|
import { existsSync, mkdirSync, readdirSync, readFileSync, renameSync, rmSync, writeFileSync } from "node:fs";
|
|
22137
22146
|
import { basename, dirname, join } from "node:path";
|
|
22147
|
+
|
|
22148
|
+
// src/store/format.ts
|
|
22138
22149
|
var STATE_FILE_VERSION = 1;
|
|
22139
|
-
var STATE_FILE_RELATIVE_PATH = join(".claude", "mellos-mapping.json");
|
|
22140
|
-
var PAGES_DIR_NAME = "mellos-mapping.pages";
|
|
22141
|
-
function pageFilePath(defaultFile, page) {
|
|
22142
|
-
return page === void 0 ? defaultFile : join(dirname(defaultFile), PAGES_DIR_NAME, `${page}.json`);
|
|
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
|
-
}
|
|
22195
22150
|
function describeStoreError(e) {
|
|
22196
22151
|
switch (e.kind) {
|
|
22197
22152
|
case "not-found":
|
|
@@ -22346,6 +22301,84 @@ function serializeMap(map) {
|
|
|
22346
22301
|
};
|
|
22347
22302
|
return JSON.stringify(body, null, 2) + "\n";
|
|
22348
22303
|
}
|
|
22304
|
+
|
|
22305
|
+
// src/store/store.ts
|
|
22306
|
+
var STATE_FILE_RELATIVE_PATH = join(".mellos", "map.json");
|
|
22307
|
+
var PAGES_DIR_NAME = "pages";
|
|
22308
|
+
function pageFilePath(defaultFile, page) {
|
|
22309
|
+
return page === void 0 ? defaultFile : join(dirname(defaultFile), PAGES_DIR_NAME, `${page}.json`);
|
|
22310
|
+
}
|
|
22311
|
+
var CONFIG_FILE_NAME = "config.json";
|
|
22312
|
+
var CONFIG_FILE_VERSION = 1;
|
|
22313
|
+
function configFilePath(defaultFile) {
|
|
22314
|
+
return join(dirname(defaultFile), CONFIG_FILE_NAME);
|
|
22315
|
+
}
|
|
22316
|
+
var MAPPING_POLICIES = ["always", "complex", "on-request"];
|
|
22317
|
+
function makeMappingPolicy(raw) {
|
|
22318
|
+
return MAPPING_POLICIES.includes(raw) ? ok(raw) : err({ kind: "invalid-policy", raw, allowed: MAPPING_POLICIES });
|
|
22319
|
+
}
|
|
22320
|
+
function describeMappingPolicy(policy) {
|
|
22321
|
+
switch (policy) {
|
|
22322
|
+
case "always":
|
|
22323
|
+
return "map every structured task \u2014 workflows, designs, architecture, technical dependencies";
|
|
22324
|
+
case "complex":
|
|
22325
|
+
return "map only medium or complex tasks \u2014 several modules, a new subsystem, roughly an hour or more";
|
|
22326
|
+
case "on-request":
|
|
22327
|
+
return "map only when the user explicitly asks";
|
|
22328
|
+
}
|
|
22329
|
+
}
|
|
22330
|
+
function isRecord2(v) {
|
|
22331
|
+
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
22332
|
+
}
|
|
22333
|
+
function loadMappingPolicy(defaultFile) {
|
|
22334
|
+
const path = configFilePath(defaultFile);
|
|
22335
|
+
let text2;
|
|
22336
|
+
try {
|
|
22337
|
+
text2 = readFileSync(path, "utf8");
|
|
22338
|
+
} catch (e) {
|
|
22339
|
+
if (e.code === "ENOENT") return ok(void 0);
|
|
22340
|
+
throw e;
|
|
22341
|
+
}
|
|
22342
|
+
let raw;
|
|
22343
|
+
try {
|
|
22344
|
+
raw = JSON.parse(text2);
|
|
22345
|
+
} catch (e) {
|
|
22346
|
+
return err({ kind: "malformed-json", path, detail: e.message });
|
|
22347
|
+
}
|
|
22348
|
+
if (!isRecord2(raw)) return err({ kind: "bad-shape", path, detail: "root is not an object" });
|
|
22349
|
+
if (raw["version"] !== CONFIG_FILE_VERSION) {
|
|
22350
|
+
return err({ kind: "bad-shape", path, detail: `version is ${String(raw["version"])}, expected ${CONFIG_FILE_VERSION}` });
|
|
22351
|
+
}
|
|
22352
|
+
const rawPolicy = raw["policy"];
|
|
22353
|
+
if (rawPolicy === void 0) return ok(void 0);
|
|
22354
|
+
if (typeof rawPolicy !== "string") return err({ kind: "bad-shape", path, detail: "policy is not a string" });
|
|
22355
|
+
const policy = makeMappingPolicy(rawPolicy);
|
|
22356
|
+
return policy.ok ? ok(policy.value) : err({ kind: "bad-shape", path, detail: `policy is "${rawPolicy}", expected one of: ${MAPPING_POLICIES.join(" | ")}` });
|
|
22357
|
+
}
|
|
22358
|
+
function saveMappingPolicy(defaultFile, policy) {
|
|
22359
|
+
const path = configFilePath(defaultFile);
|
|
22360
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
22361
|
+
const tmp = path + ".tmp";
|
|
22362
|
+
writeFileSync(tmp, JSON.stringify({ version: CONFIG_FILE_VERSION, policy }, null, 2) + "\n", "utf8");
|
|
22363
|
+
renameSync(tmp, path);
|
|
22364
|
+
}
|
|
22365
|
+
var LEGACY_STATE_FILE_RELATIVE_PATH = join(".claude", "mellos-mapping.json");
|
|
22366
|
+
var LEGACY_PAGES_DIR_NAME = "mellos-mapping.pages";
|
|
22367
|
+
var LEGACY_CONFIG_FILE_NAME = "mellos-mapping.config.json";
|
|
22368
|
+
function migrateLegacyStore(defaultFile) {
|
|
22369
|
+
const projectRoot = dirname(dirname(defaultFile));
|
|
22370
|
+
const legacyDefault = join(projectRoot, LEGACY_STATE_FILE_RELATIVE_PATH);
|
|
22371
|
+
const legacyPages = join(dirname(legacyDefault), LEGACY_PAGES_DIR_NAME);
|
|
22372
|
+
const legacyConfig = join(dirname(legacyDefault), LEGACY_CONFIG_FILE_NAME);
|
|
22373
|
+
const hasLegacy = existsSync(legacyDefault) || existsSync(legacyPages) || existsSync(legacyConfig);
|
|
22374
|
+
const hasCurrent = existsSync(defaultFile) || existsSync(join(dirname(defaultFile), PAGES_DIR_NAME)) || existsSync(configFilePath(defaultFile));
|
|
22375
|
+
if (!hasLegacy || hasCurrent) return false;
|
|
22376
|
+
mkdirSync(dirname(defaultFile), { recursive: true });
|
|
22377
|
+
if (existsSync(legacyDefault)) renameSync(legacyDefault, defaultFile);
|
|
22378
|
+
if (existsSync(legacyPages)) renameSync(legacyPages, join(dirname(defaultFile), PAGES_DIR_NAME));
|
|
22379
|
+
if (existsSync(legacyConfig)) renameSync(legacyConfig, configFilePath(defaultFile));
|
|
22380
|
+
return true;
|
|
22381
|
+
}
|
|
22349
22382
|
function loadMapFile(path) {
|
|
22350
22383
|
let text2;
|
|
22351
22384
|
try {
|
|
@@ -22566,7 +22599,7 @@ function summarize(map) {
|
|
|
22566
22599
|
|
|
22567
22600
|
// src/server/server.ts
|
|
22568
22601
|
var SERVER_NAME = "mellos-mapping";
|
|
22569
|
-
var SERVER_VERSION = "0.
|
|
22602
|
+
var SERVER_VERSION = "0.20.0";
|
|
22570
22603
|
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");
|
|
22571
22604
|
var PAGE = ID.optional().describe(
|
|
22572
22605
|
"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."
|
|
@@ -22753,7 +22786,9 @@ function resolveStateFile(env, cwd) {
|
|
|
22753
22786
|
return join2(projectDir, STATE_FILE_RELATIVE_PATH);
|
|
22754
22787
|
}
|
|
22755
22788
|
async function main() {
|
|
22756
|
-
const
|
|
22789
|
+
const stateFile = resolveStateFile(process.env, process.cwd());
|
|
22790
|
+
migrateLegacyStore(stateFile);
|
|
22791
|
+
const server = buildServer(stateFile);
|
|
22757
22792
|
await server.connect(new StdioServerTransport());
|
|
22758
22793
|
}
|
|
22759
22794
|
function launchedAsEntry(argv1, moduleUrl) {
|