eventmodeler 0.6.13 → 0.6.15

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 (2) hide show
  1. package/dist/index.js +489 -178
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -2573,6 +2573,15 @@ function registerStatusCommands(program, conn) {
2573
2573
  }
2574
2574
  // ../packages/canvas-model/src/build.ts
2575
2575
  import * as Y2 from "yjs";
2576
+ function buildYMap(props) {
2577
+ const m = new Y2.Map;
2578
+ for (const [k, v] of Object.entries(props)) {
2579
+ if (v === undefined)
2580
+ continue;
2581
+ m.set(k, v);
2582
+ }
2583
+ return m;
2584
+ }
2576
2585
  function buildYArray(items) {
2577
2586
  const arr = new Y2.Array;
2578
2587
  if (items.length > 0)
@@ -2630,6 +2639,7 @@ var ELEMENT_DIMENSIONS = {
2630
2639
  aggregate: { width: 300, height: 200 },
2631
2640
  actor: { width: 300, height: 200 },
2632
2641
  chapter: { width: 800, height: 1200 },
2642
+ sheet: { width: 800, height: 1200 },
2633
2643
  note: { width: 200, height: 150 },
2634
2644
  externalEvent: { width: 160, height: 100 },
2635
2645
  context: { width: 300, height: 200 },
@@ -2834,6 +2844,7 @@ var SliceSchema = baseContainer("sliceId").extend({
2834
2844
  var AggregateSchema = baseContainer("aggregateId");
2835
2845
  var ActorSchema = baseContainer("actorId");
2836
2846
  var ChapterSchema = baseContainer("chapterId");
2847
+ var SheetSchema = baseContainer("sheetId");
2837
2848
  var ContextSchema = baseContainer("contextId");
2838
2849
  var LaneKindSchema = z.enum(["actor", "interaction", "swimlane", "specification"]);
2839
2850
  var SwimLaneSchema = baseContainer("swimLaneId").extend({
@@ -2937,9 +2948,9 @@ var FlowSchema = z.object({
2937
2948
  var SheetFlowSchema = z.object({
2938
2949
  sheetFlowId: z.string().uuid().optional(),
2939
2950
  modelId: z.string().uuid().optional(),
2940
- sourceChapterId: z.string().uuid(),
2951
+ sourceSheetId: z.string().uuid(),
2941
2952
  sourceHandle: z.string().min(1),
2942
- targetChapterId: z.string().uuid(),
2953
+ targetSheetId: z.string().uuid(),
2943
2954
  targetHandle: z.string().min(1)
2944
2955
  });
2945
2956
  var CellRefSchema = z.object({
@@ -2958,6 +2969,7 @@ var SheetStructureSchema = z.object({
2958
2969
  columns: z.array(z.string().uuid()),
2959
2970
  rows: z.array(z.string().uuid()),
2960
2971
  cells: z.record(z.string(), z.array(CellRefSchema)),
2972
+ columnSlices: z.record(z.string(), z.string().uuid()).optional(),
2961
2973
  cellNotes: z.record(z.string(), z.string()).optional()
2962
2974
  });
2963
2975
  var SCOPE_SCHEMAS = {
@@ -2971,6 +2983,7 @@ var SCOPE_SCHEMAS = {
2971
2983
  aggregates: AggregateSchema,
2972
2984
  actors: ActorSchema,
2973
2985
  chapters: ChapterSchema,
2986
+ sheets: SheetSchema,
2974
2987
  contexts: ContextSchema,
2975
2988
  swimLanes: SwimLaneSchema,
2976
2989
  notes: NoteSchema,
@@ -3005,36 +3018,69 @@ var GRID_SCOPE = "grid";
3005
3018
  function getGridMap(doc) {
3006
3019
  return doc.getMap(GRID_SCOPE);
3007
3020
  }
3008
- function cellKey(sliceId, swimLaneId) {
3009
- return `${sliceId}:${swimLaneId}`;
3021
+ function cellKey(columnId, swimLaneId) {
3022
+ return `${columnId}:${swimLaneId}`;
3010
3023
  }
3011
- function resolveSheet(doc, chapterId) {
3024
+ function resolveSheet(doc, sheetId) {
3012
3025
  const grid = getGridMap(doc);
3013
- let sheet = grid.get(chapterId);
3026
+ let sheet = grid.get(sheetId);
3014
3027
  if (!sheet) {
3015
3028
  sheet = new Y6.Map;
3016
3029
  sheet.set("columns", new Y6.Array);
3017
3030
  sheet.set("rows", new Y6.Array);
3018
3031
  sheet.set("cells", new Y6.Map);
3019
- grid.set(chapterId, sheet);
3032
+ sheet.set("columnSlices", new Y6.Map);
3033
+ grid.set(sheetId, sheet);
3034
+ }
3035
+ let columnSlices = sheet.get("columnSlices");
3036
+ if (!columnSlices) {
3037
+ columnSlices = new Y6.Map;
3038
+ sheet.set("columnSlices", columnSlices);
3020
3039
  }
3021
3040
  return {
3022
3041
  sheet,
3023
3042
  columns: sheet.get("columns"),
3024
3043
  rows: sheet.get("rows"),
3025
- cells: sheet.get("cells")
3044
+ cells: sheet.get("cells"),
3045
+ columnSlices
3026
3046
  };
3027
3047
  }
3028
- function ensureSheet(doc, chapterId) {
3048
+ function sliceOf(columnSlices, columnId) {
3049
+ return columnSlices[columnId] ?? columnId;
3050
+ }
3051
+ function ensureSheet(doc, sheetId) {
3029
3052
  doc.transact(() => {
3030
- resolveSheet(doc, chapterId);
3053
+ resolveSheet(doc, sheetId);
3031
3054
  });
3032
3055
  }
3033
- function readSheet(doc, chapterId) {
3034
- const sheet = getGridMap(doc).get(chapterId);
3056
+ function readSheet(doc, sheetId) {
3057
+ const sheet = getGridMap(doc).get(sheetId);
3035
3058
  if (!sheet)
3036
3059
  return;
3037
- return sheet.toJSON();
3060
+ const json = sheet.toJSON();
3061
+ const columns = json.columns ?? [];
3062
+ const columnSlices = { ...json.columnSlices ?? {} };
3063
+ for (const c of columns)
3064
+ if (!(c in columnSlices))
3065
+ columnSlices[c] = c;
3066
+ return { ...json, columns, columnSlices };
3067
+ }
3068
+ function sliceOrder(structure) {
3069
+ const cs = structure.columnSlices ?? {};
3070
+ const seen = new Set;
3071
+ const out = [];
3072
+ for (const colId of structure.columns) {
3073
+ const sid = sliceOf(cs, colId);
3074
+ if (!seen.has(sid)) {
3075
+ seen.add(sid);
3076
+ out.push(sid);
3077
+ }
3078
+ }
3079
+ return out;
3080
+ }
3081
+ function sliceColumns(structure, sliceId) {
3082
+ const cs = structure.columnSlices ?? {};
3083
+ return structure.columns.filter((c) => sliceOf(cs, c) === sliceId);
3038
3084
  }
3039
3085
  function clampIndex(at, length) {
3040
3086
  if (at === undefined || at > length)
@@ -3046,52 +3092,91 @@ function insertUnique(arr, value, at) {
3046
3092
  return;
3047
3093
  arr.insert(clampIndex(at, arr.length), [value]);
3048
3094
  }
3049
- function addColumn(doc, chapterId, sliceId, at) {
3095
+ function addColumn(doc, sheetId, sliceId, at) {
3096
+ doc.transact(() => {
3097
+ const { columns, columnSlices } = resolveSheet(doc, sheetId);
3098
+ if (columns.toArray().includes(sliceId))
3099
+ return;
3100
+ columns.insert(clampIndex(at, columns.length), [sliceId]);
3101
+ columnSlices.set(sliceId, sliceId);
3102
+ });
3103
+ }
3104
+ function addColumnToSlice(doc, sheetId, sliceId, columnId, atWithin) {
3050
3105
  doc.transact(() => {
3051
- const { columns } = resolveSheet(doc, chapterId);
3052
- insertUnique(columns, sliceId, at);
3106
+ const { columns, columnSlices } = resolveSheet(doc, sheetId);
3107
+ const arr = columns.toArray();
3108
+ if (arr.includes(columnId))
3109
+ return;
3110
+ const slices = columnSlices.toJSON();
3111
+ const flatIdxs = arr.map((c, i) => [c, i]).filter(([c]) => sliceOf(slices, c) === sliceId).map(([, i]) => i);
3112
+ let flat;
3113
+ if (flatIdxs.length === 0) {
3114
+ flat = columns.length;
3115
+ } else {
3116
+ const within = atWithin === undefined ? flatIdxs.length : Math.max(0, Math.min(flatIdxs.length, atWithin));
3117
+ flat = within < flatIdxs.length ? flatIdxs[within] : flatIdxs[flatIdxs.length - 1] + 1;
3118
+ }
3119
+ columns.insert(flat, [columnId]);
3120
+ columnSlices.set(columnId, sliceId);
3053
3121
  });
3054
3122
  }
3055
- function moveColumn(doc, chapterId, sliceId, toIndex) {
3123
+ function moveColumn(doc, sheetId, columnId, toIndex) {
3056
3124
  doc.transact(() => {
3057
- const { columns } = resolveSheet(doc, chapterId);
3058
- const from = columns.toArray().indexOf(sliceId);
3125
+ const { columns } = resolveSheet(doc, sheetId);
3126
+ const from = columns.toArray().indexOf(columnId);
3059
3127
  if (from === -1)
3060
3128
  return;
3061
3129
  columns.delete(from, 1);
3062
- columns.insert(clampIndex(toIndex, columns.length), [sliceId]);
3130
+ columns.insert(clampIndex(toIndex, columns.length), [columnId]);
3063
3131
  });
3064
3132
  }
3065
- function removeColumn(doc, chapterId, sliceId) {
3133
+ function removeColumn(doc, sheetId, columnId) {
3066
3134
  doc.transact(() => {
3067
- const sheet = getGridMap(doc).get(chapterId);
3135
+ const sheet = getGridMap(doc).get(sheetId);
3068
3136
  if (!sheet)
3069
3137
  return;
3070
3138
  const columns = sheet.get("columns");
3071
3139
  const cells = sheet.get("cells");
3072
3140
  const cellNotes = sheet.get("cellNotes");
3073
- const idx = columns.toArray().indexOf(sliceId);
3141
+ const columnSlices = sheet.get("columnSlices");
3142
+ const idx = columns.toArray().indexOf(columnId);
3074
3143
  if (idx !== -1)
3075
3144
  columns.delete(idx, 1);
3145
+ columnSlices?.delete(columnId);
3076
3146
  for (const key of [...cells.keys()]) {
3077
- if (key.startsWith(`${sliceId}:`))
3147
+ if (key.startsWith(`${columnId}:`))
3078
3148
  cells.delete(key);
3079
3149
  }
3080
3150
  for (const key of [...cellNotes?.keys() ?? []]) {
3081
- if (key.startsWith(`${sliceId}:`))
3151
+ if (key.startsWith(`${columnId}:`))
3082
3152
  cellNotes.delete(key);
3083
3153
  }
3084
3154
  });
3085
3155
  }
3086
- function addRow(doc, chapterId, swimLaneId, at) {
3156
+ function setColumnSlice(doc, sheetId, columnId, sliceId) {
3157
+ doc.transact(() => {
3158
+ const { columnSlices } = resolveSheet(doc, sheetId);
3159
+ columnSlices.set(columnId, sliceId);
3160
+ });
3161
+ }
3162
+ function ensureColumnSlices(doc, sheetId) {
3163
+ doc.transact(() => {
3164
+ const { columns, columnSlices } = resolveSheet(doc, sheetId);
3165
+ for (const columnId of columns.toArray()) {
3166
+ if (!columnSlices.has(columnId))
3167
+ columnSlices.set(columnId, columnId);
3168
+ }
3169
+ });
3170
+ }
3171
+ function addRow(doc, sheetId, swimLaneId, at) {
3087
3172
  doc.transact(() => {
3088
- const { rows } = resolveSheet(doc, chapterId);
3173
+ const { rows } = resolveSheet(doc, sheetId);
3089
3174
  insertUnique(rows, swimLaneId, at);
3090
3175
  });
3091
3176
  }
3092
- function moveRow(doc, chapterId, swimLaneId, toIndex) {
3177
+ function moveRow(doc, sheetId, swimLaneId, toIndex) {
3093
3178
  doc.transact(() => {
3094
- const { rows } = resolveSheet(doc, chapterId);
3179
+ const { rows } = resolveSheet(doc, sheetId);
3095
3180
  const from = rows.toArray().indexOf(swimLaneId);
3096
3181
  if (from === -1)
3097
3182
  return;
@@ -3099,9 +3184,9 @@ function moveRow(doc, chapterId, swimLaneId, toIndex) {
3099
3184
  rows.insert(clampIndex(toIndex, rows.length), [swimLaneId]);
3100
3185
  });
3101
3186
  }
3102
- function removeRow(doc, chapterId, swimLaneId) {
3187
+ function removeRow(doc, sheetId, swimLaneId) {
3103
3188
  doc.transact(() => {
3104
- const sheet = getGridMap(doc).get(chapterId);
3189
+ const sheet = getGridMap(doc).get(sheetId);
3105
3190
  if (!sheet)
3106
3191
  return;
3107
3192
  const rows = sheet.get("rows");
@@ -3137,9 +3222,9 @@ function findStickyCell(cells, stickyId) {
3137
3222
  }
3138
3223
  return;
3139
3224
  }
3140
- function placeInCell(doc, chapterId, sliceId, swimLaneId, ref, at) {
3225
+ function placeInCell(doc, sheetId, sliceId, swimLaneId, ref, at) {
3141
3226
  doc.transact(() => {
3142
- const { cells } = resolveSheet(doc, chapterId);
3227
+ const { cells } = resolveSheet(doc, sheetId);
3143
3228
  const existing = findStickyCell(cells, ref.stickyId);
3144
3229
  if (existing)
3145
3230
  cells.get(existing.key).delete(existing.index, 1);
@@ -3154,9 +3239,9 @@ function placeInCell(doc, chapterId, sliceId, swimLaneId, ref, at) {
3154
3239
  ]);
3155
3240
  });
3156
3241
  }
3157
- function removeSticky(doc, chapterId, stickyId) {
3242
+ function removeSticky(doc, sheetId, stickyId) {
3158
3243
  doc.transact(() => {
3159
- const sheet = getGridMap(doc).get(chapterId);
3244
+ const sheet = getGridMap(doc).get(sheetId);
3160
3245
  if (!sheet)
3161
3246
  return;
3162
3247
  const cells = sheet.get("cells");
@@ -3166,13 +3251,13 @@ function removeSticky(doc, chapterId, stickyId) {
3166
3251
  cells.get(loc.key).delete(loc.index, 1);
3167
3252
  });
3168
3253
  }
3169
- function removeSheet(doc, chapterId) {
3254
+ function removeSheet(doc, sheetId) {
3170
3255
  doc.transact(() => {
3171
- getGridMap(doc).delete(chapterId);
3256
+ getGridMap(doc).delete(sheetId);
3172
3257
  });
3173
3258
  }
3174
- function getCellNotesMap(doc, chapterId, create) {
3175
- const sheet = getGridMap(doc).get(chapterId);
3259
+ function getCellNotesMap(doc, sheetId, create) {
3260
+ const sheet = getGridMap(doc).get(sheetId);
3176
3261
  if (!sheet)
3177
3262
  return;
3178
3263
  let notes = sheet.get("cellNotes");
@@ -3182,30 +3267,117 @@ function getCellNotesMap(doc, chapterId, create) {
3182
3267
  }
3183
3268
  return notes;
3184
3269
  }
3185
- function readCellNotes(doc, chapterId) {
3186
- const notes = getGridMap(doc).get(chapterId)?.get("cellNotes");
3270
+ function readCellNotes(doc, sheetId) {
3271
+ const notes = getGridMap(doc).get(sheetId)?.get("cellNotes");
3187
3272
  return notes ? notes.toJSON() : {};
3188
3273
  }
3189
- function setCellNote(doc, chapterId, sliceId, swimLaneId, text) {
3274
+ function setCellNote(doc, sheetId, sliceId, swimLaneId, text) {
3190
3275
  doc.transact(() => {
3191
3276
  const key = cellKey(sliceId, swimLaneId);
3192
3277
  const trimmed = text.trim();
3193
3278
  if (!trimmed) {
3194
- getCellNotesMap(doc, chapterId, false)?.delete(key);
3279
+ getCellNotesMap(doc, sheetId, false)?.delete(key);
3195
3280
  return;
3196
3281
  }
3197
- getCellNotesMap(doc, chapterId, true).set(key, trimmed);
3282
+ getCellNotesMap(doc, sheetId, true).set(key, trimmed);
3198
3283
  });
3199
3284
  }
3200
- // ../packages/canvas-model/src/sheet-delete.ts
3201
- var CHAPTERS_SCOPE = "chapters";
3285
+ // ../packages/canvas-model/src/slice-span.ts
3202
3286
  var SLICES_SCOPE2 = "slices";
3287
+ var SHEET_FLOWS_SCOPE = "sheetFlows";
3288
+ function sliceIdFromHandle(handleId) {
3289
+ if (typeof handleId !== "string")
3290
+ return;
3291
+ const parts = handleId.split(":");
3292
+ if (parts[0] === "sf" && parts[1] === "slice" && parts.length >= 5)
3293
+ return parts.slice(4).join(":");
3294
+ return;
3295
+ }
3296
+ function pruneSheetFlowsForSlice(doc, sliceId) {
3297
+ const map = getScopeMap(doc, SHEET_FLOWS_SCOPE);
3298
+ for (const [id, f] of [...map.entries()]) {
3299
+ if (sliceIdFromHandle(f.get("sourceHandle")) === sliceId || sliceIdFromHandle(f.get("targetHandle")) === sliceId) {
3300
+ map.delete(id);
3301
+ }
3302
+ }
3303
+ }
3304
+ function resizeSliceSpan(doc, sheetId, sliceId, targetLast) {
3305
+ doc.transact(() => {
3306
+ const structure = readSheet(doc, sheetId);
3307
+ if (!structure)
3308
+ return;
3309
+ const cols = structure.columns;
3310
+ const owned = sliceColumns(structure, sliceId);
3311
+ if (owned.length === 0)
3312
+ return;
3313
+ const firstFlat = cols.indexOf(owned[0]);
3314
+ const currentLast = cols.indexOf(owned[owned.length - 1]);
3315
+ const target = Math.max(firstFlat, Math.min(targetLast, cols.length - 1));
3316
+ if (target === currentLast)
3317
+ return;
3318
+ const owner = (c) => structure.columnSlices?.[c] ?? c;
3319
+ const slices = getScopeMap(doc, SLICES_SCOPE2);
3320
+ const modelId = getEntry(doc, SLICES_SCOPE2, sliceId)?.modelId;
3321
+ const d = ELEMENT_DIMENSIONS.slice;
3322
+ const claimed = cols.slice(firstFlat, target + 1);
3323
+ const prevOwners = new Set(claimed.map(owner).filter((s) => s !== sliceId));
3324
+ for (const colId of claimed)
3325
+ setColumnSlice(doc, sheetId, colId, sliceId);
3326
+ for (const colId of cols.slice(target + 1, currentLast + 1)) {
3327
+ const newSliceId = crypto.randomUUID();
3328
+ const base = { sliceId: newSliceId, name: "Slice", x: 0, y: 0, width: d.width, height: d.height };
3329
+ slices.set(newSliceId, buildYMap(modelId ? { ...base, modelId } : base));
3330
+ setColumnSlice(doc, sheetId, colId, newSliceId);
3331
+ }
3332
+ const after = readSheet(doc, sheetId);
3333
+ for (const sid of prevOwners) {
3334
+ if (sliceColumns(after, sid).length === 0) {
3335
+ slices.delete(sid);
3336
+ pruneSheetFlowsForSlice(doc, sid);
3337
+ }
3338
+ }
3339
+ });
3340
+ }
3341
+ // ../packages/canvas-model/src/migrate.ts
3342
+ function migrateChaptersToSheets(doc) {
3343
+ const chapters = getScopeMap(doc, "chapters");
3344
+ const sheets = getScopeMap(doc, "sheets");
3345
+ const sheetFlows = getScopeMap(doc, "sheetFlows");
3346
+ const needsEntityMove = sheets.size === 0 && chapters.size > 0;
3347
+ const needsFlowRename = [...sheetFlows.values()].some((f) => f.has("sourceChapterId") || f.has("targetChapterId"));
3348
+ if (!needsEntityMove && !needsFlowRename)
3349
+ return;
3350
+ doc.transact(() => {
3351
+ if (needsEntityMove) {
3352
+ for (const [id, ch] of [...chapters.entries()]) {
3353
+ const json = ch.toJSON();
3354
+ delete json.chapterId;
3355
+ json.sheetId = id;
3356
+ sheets.set(id, deepToY(json));
3357
+ chapters.delete(id);
3358
+ }
3359
+ }
3360
+ for (const f of sheetFlows.values()) {
3361
+ if (f.has("sourceChapterId")) {
3362
+ f.set("sourceSheetId", f.get("sourceChapterId"));
3363
+ f.delete("sourceChapterId");
3364
+ }
3365
+ if (f.has("targetChapterId")) {
3366
+ f.set("targetSheetId", f.get("targetChapterId"));
3367
+ f.delete("targetChapterId");
3368
+ }
3369
+ }
3370
+ });
3371
+ }
3372
+ // ../packages/canvas-model/src/sheet-delete.ts
3373
+ var SHEETS_SCOPE = "sheets";
3374
+ var SLICES_SCOPE3 = "slices";
3203
3375
  var SWIM_LANES_SCOPE = "swimLanes";
3204
3376
  var SCENARIOS_SCOPE2 = "scenarios";
3205
- var SHEET_FLOWS_SCOPE = "sheetFlows";
3206
- function deleteSheet(doc, chapterId) {
3377
+ var SHEET_FLOWS_SCOPE2 = "sheetFlows";
3378
+ function deleteSheet(doc, sheetId) {
3207
3379
  doc.transact(() => {
3208
- const sheet = getGridMap(doc).get(chapterId);
3380
+ const sheet = getGridMap(doc).get(sheetId);
3209
3381
  const removedStickies = new Set;
3210
3382
  const sliceIds = new Set;
3211
3383
  const laneIds = new Set;
@@ -3224,7 +3396,7 @@ function deleteSheet(doc, chapterId) {
3224
3396
  }
3225
3397
  }
3226
3398
  for (const id of sliceIds)
3227
- getScopeMap(doc, SLICES_SCOPE2).delete(id);
3399
+ getScopeMap(doc, SLICES_SCOPE3).delete(id);
3228
3400
  for (const id of laneIds)
3229
3401
  getScopeMap(doc, SWIM_LANES_SCOPE).delete(id);
3230
3402
  const scenarios = getScopeMap(doc, SCENARIOS_SCOPE2);
@@ -3235,14 +3407,14 @@ function deleteSheet(doc, chapterId) {
3235
3407
  }
3236
3408
  }
3237
3409
  cascadeStickyRemoval(doc, removedStickies);
3238
- const sheetFlows = getScopeMap(doc, SHEET_FLOWS_SCOPE);
3410
+ const sheetFlows = getScopeMap(doc, SHEET_FLOWS_SCOPE2);
3239
3411
  for (const [id, f] of sheetFlows.entries()) {
3240
- if (f.get("sourceChapterId") === chapterId || f.get("targetChapterId") === chapterId) {
3412
+ if (f.get("sourceSheetId") === sheetId || f.get("targetSheetId") === sheetId) {
3241
3413
  sheetFlows.delete(id);
3242
3414
  }
3243
3415
  }
3244
- removeSheet(doc, chapterId);
3245
- getScopeMap(doc, CHAPTERS_SCOPE).delete(chapterId);
3416
+ removeSheet(doc, sheetId);
3417
+ getScopeMap(doc, SHEETS_SCOPE).delete(sheetId);
3246
3418
  });
3247
3419
  }
3248
3420
  // ../packages/canvas-model/src/sheet-layout.ts
@@ -3295,8 +3467,8 @@ function cellContentSize(refs) {
3295
3467
  });
3296
3468
  return { width, height };
3297
3469
  }
3298
- function pruneOrphanCellRefs(doc, chapterId) {
3299
- const sheet = getGridMap(doc).get(chapterId);
3470
+ function pruneOrphanCellRefs(doc, sheetId) {
3471
+ const sheet = getGridMap(doc).get(sheetId);
3300
3472
  if (!sheet)
3301
3473
  return 0;
3302
3474
  const cells = sheet.get("cells");
@@ -3315,19 +3487,21 @@ function pruneOrphanCellRefs(doc, chapterId) {
3315
3487
  }
3316
3488
  return pruned;
3317
3489
  }
3318
- function computeSheetLayout(doc, chapterId, override) {
3319
- const structure = readSheet(doc, chapterId);
3490
+ function computeSheetLayout(doc, sheetId, override) {
3491
+ const structure = readSheet(doc, sheetId);
3320
3492
  if (!structure)
3321
3493
  return;
3322
- const chapter = getEntry(doc, "chapters", chapterId);
3323
- const originX = snap(chapter?.x ?? 0);
3324
- const originY = snap(chapter?.y ?? 0);
3494
+ const sheet = getEntry(doc, "sheets", sheetId);
3495
+ const originX = snap(sheet?.x ?? 0);
3496
+ const originY = snap(sheet?.y ?? 0);
3325
3497
  const { columns, rows } = structure;
3498
+ const columnSlices = structure.columnSlices ?? {};
3499
+ const ownerOf = (columnId) => columnSlices[columnId] ?? columnId;
3326
3500
  const cells = override ? applyLayoutOverride(structure.cells, override) : structure.cells;
3327
- const colWidths = columns.map((sliceId) => {
3501
+ const colWidths = columns.map((columnId) => {
3328
3502
  let w = 0;
3329
3503
  for (const swimLaneId of rows) {
3330
- const refs = cells[cellKey(sliceId, swimLaneId)] ?? [];
3504
+ const refs = cells[cellKey(columnId, swimLaneId)] ?? [];
3331
3505
  const c = cellContentSize(refs);
3332
3506
  if (c.width > 0)
3333
3507
  w = Math.max(w, c.width + SHEET_LAYOUT.cellPadX * 2);
@@ -3336,8 +3510,8 @@ function computeSheetLayout(doc, chapterId, override) {
3336
3510
  });
3337
3511
  const rowHeights = rows.map((swimLaneId) => {
3338
3512
  let h = 0;
3339
- for (const sliceId of columns) {
3340
- const refs = cells[cellKey(sliceId, swimLaneId)] ?? [];
3513
+ for (const columnId of columns) {
3514
+ const refs = cells[cellKey(columnId, swimLaneId)] ?? [];
3341
3515
  const c = cellContentSize(refs);
3342
3516
  if (c.height > 0)
3343
3517
  h = Math.max(h, c.height + SHEET_LAYOUT.cellPadY * 2);
@@ -3358,14 +3532,33 @@ function computeSheetLayout(doc, chapterId, override) {
3358
3532
  });
3359
3533
  const gridWidth = SHEET_LAYOUT.headerLeft + colWidths.reduce((a, b) => a + b, 0);
3360
3534
  const gridHeight = SHEET_LAYOUT.headerTop + rowHeights.reduce((a, b) => a + b, 0);
3361
- const columnLayouts = columns.map((sliceId, i) => ({
3362
- sliceId,
3535
+ const columnLayouts = columns.map((columnId, i) => ({
3536
+ columnId,
3537
+ sliceId: ownerOf(columnId),
3363
3538
  index: i,
3364
3539
  x: colX[i],
3365
3540
  y: originY,
3366
3541
  width: colWidths[i],
3367
3542
  height: gridHeight
3368
3543
  }));
3544
+ const sliceLayouts = [];
3545
+ for (const col of columnLayouts) {
3546
+ const last = sliceLayouts[sliceLayouts.length - 1];
3547
+ if (last && last.sliceId === col.sliceId) {
3548
+ last.columnIds.push(col.columnId);
3549
+ last.width += col.width;
3550
+ } else {
3551
+ sliceLayouts.push({
3552
+ sliceId: col.sliceId,
3553
+ columnIds: [col.columnId],
3554
+ index: sliceLayouts.length,
3555
+ x: col.x,
3556
+ y: originY,
3557
+ width: col.width,
3558
+ height: gridHeight
3559
+ });
3560
+ }
3561
+ }
3369
3562
  const rowLayouts = rows.map((swimLaneId, i) => ({
3370
3563
  swimLaneId,
3371
3564
  index: i,
@@ -3375,9 +3568,10 @@ function computeSheetLayout(doc, chapterId, override) {
3375
3568
  height: rowHeights[i]
3376
3569
  }));
3377
3570
  const stickies = [];
3378
- columns.forEach((sliceId, ci) => {
3571
+ columns.forEach((columnId, ci) => {
3572
+ const sliceId = ownerOf(columnId);
3379
3573
  rows.forEach((swimLaneId, ri) => {
3380
- const refs = cells[cellKey(sliceId, swimLaneId)] ?? [];
3574
+ const refs = cells[cellKey(columnId, swimLaneId)] ?? [];
3381
3575
  if (refs.length === 0)
3382
3576
  return;
3383
3577
  const content = cellContentSize(refs);
@@ -3392,6 +3586,7 @@ function computeSheetLayout(doc, chapterId, override) {
3392
3586
  stickies.push({
3393
3587
  stickyId: ref.stickyId,
3394
3588
  scope: ref.scope,
3589
+ columnId,
3395
3590
  sliceId,
3396
3591
  swimLaneId,
3397
3592
  x: Math.round(midX - size.width / 2),
@@ -3408,6 +3603,7 @@ function computeSheetLayout(doc, chapterId, override) {
3408
3603
  stickies.push({
3409
3604
  stickyId: ref.stickyId,
3410
3605
  scope: ref.scope,
3606
+ columnId,
3411
3607
  sliceId,
3412
3608
  swimLaneId,
3413
3609
  x: Math.round(cursorX),
@@ -3421,17 +3617,18 @@ function computeSheetLayout(doc, chapterId, override) {
3421
3617
  });
3422
3618
  });
3423
3619
  return {
3424
- chapterId,
3425
- chapter: { x: originX, y: originY, width: gridWidth, height: gridHeight },
3620
+ sheetId,
3621
+ sheet: { x: originX, y: originY, width: gridWidth, height: gridHeight },
3426
3622
  columns: columnLayouts,
3623
+ slices: sliceLayouts,
3427
3624
  rows: rowLayouts,
3428
3625
  stickies
3429
3626
  };
3430
3627
  }
3431
3628
  // ../packages/canvas-model/src/reflow.ts
3432
3629
  var REFLOW_ORIGIN = Symbol("sheet-reflow");
3433
- var CHAPTERS_SCOPE2 = "chapters";
3434
- var SLICES_SCOPE3 = "slices";
3630
+ var SHEETS_SCOPE2 = "sheets";
3631
+ var SLICES_SCOPE4 = "slices";
3435
3632
  var SWIM_LANES_SCOPE2 = "swimLanes";
3436
3633
  var STICKY_SCOPES = [
3437
3634
  "commands",
@@ -3457,27 +3654,30 @@ function applyBox(m, box, size = true) {
3457
3654
  }
3458
3655
  }
3459
3656
  function reflowAllSheets(doc, origin = REFLOW_ORIGIN) {
3460
- const chapters = getScopeMap(doc, CHAPTERS_SCOPE2);
3461
- if (chapters.size === 0)
3657
+ migrateChaptersToSheets(doc);
3658
+ const sheets = getScopeMap(doc, SHEETS_SCOPE2);
3659
+ if (sheets.size === 0)
3462
3660
  return;
3463
3661
  doc.transact(() => {
3464
- for (const chapterId of chapters.keys())
3465
- ensureSheet(doc, chapterId);
3466
- const slices = getScopeMap(doc, SLICES_SCOPE3);
3662
+ for (const sheetId of sheets.keys()) {
3663
+ ensureSheet(doc, sheetId);
3664
+ ensureColumnSlices(doc, sheetId);
3665
+ }
3666
+ const slices = getScopeMap(doc, SLICES_SCOPE4);
3467
3667
  const lanes = getScopeMap(doc, SWIM_LANES_SCOPE2);
3468
3668
  const stickyMaps = STICKY_SCOPES.map((s) => getScopeMap(doc, s));
3469
- for (const chapterId of getGridMap(doc).keys()) {
3470
- pruneOrphanCellRefs(doc, chapterId);
3471
- const layout = computeSheetLayout(doc, chapterId);
3669
+ for (const sheetId of getGridMap(doc).keys()) {
3670
+ pruneOrphanCellRefs(doc, sheetId);
3671
+ const layout = computeSheetLayout(doc, sheetId);
3472
3672
  if (!layout)
3473
3673
  continue;
3474
- const ch = chapters.get(chapterId);
3674
+ const ch = sheets.get(sheetId);
3475
3675
  if (ch) {
3476
- setIfChanged(ch, "width", layout.chapter.width);
3477
- setIfChanged(ch, "height", layout.chapter.height);
3676
+ setIfChanged(ch, "width", layout.sheet.width);
3677
+ setIfChanged(ch, "height", layout.sheet.height);
3478
3678
  }
3479
- for (const col of layout.columns)
3480
- applyBox(slices.get(col.sliceId), col);
3679
+ for (const band of layout.slices)
3680
+ applyBox(slices.get(band.sliceId), band);
3481
3681
  for (const row of layout.rows)
3482
3682
  applyBox(lanes.get(row.swimLaneId), row);
3483
3683
  const scenarioOrder = new Map;
@@ -4937,25 +5137,36 @@ function pad(s, width) {
4937
5137
  return s.length >= width ? s : s + " ".repeat(width - s.length);
4938
5138
  }
4939
5139
  var NOTE = "†";
4940
- function resolve4(doc, chapterId) {
4941
- const structure = readSheet(doc, chapterId);
5140
+ function resolve4(doc, sheetId) {
5141
+ const structure = readSheet(doc, sheetId);
4942
5142
  if (!structure)
4943
5143
  return;
4944
5144
  const { columns, rows, cells } = structure;
4945
- const notes = readCellNotes(doc, chapterId);
4946
- const cols = columns.map((sliceId, i) => ({
4947
- label: colLabel(i),
4948
- name: entityName(doc, "slices", sliceId),
4949
- note: Boolean(getEntry(doc, "slices", sliceId)?.note)
4950
- }));
5145
+ const notes = readCellNotes(doc, sheetId);
5146
+ const cols = columns.map((_, i) => ({ label: colLabel(i) }));
5147
+ const slices = sliceOrder(structure).map((sliceId) => {
5148
+ const cids = sliceColumns(structure, sliceId);
5149
+ const firstCol = columns.indexOf(cids[0]);
5150
+ const lastCol = columns.indexOf(cids[cids.length - 1]);
5151
+ const e = getEntry(doc, "slices", sliceId);
5152
+ return {
5153
+ label: firstCol === lastCol ? colLabel(firstCol) : `${colLabel(firstCol)}–${colLabel(lastCol)}`,
5154
+ name: e?.name?.trim() || "(unnamed)",
5155
+ status: e?.status ?? "",
5156
+ note: Boolean(e?.note),
5157
+ firstCol,
5158
+ lastCol
5159
+ };
5160
+ });
4951
5161
  const lanes2 = rows.map((swimLaneId, i) => {
4952
5162
  const e = getEntry(doc, "swimLanes", swimLaneId);
4953
5163
  return { label: String(i + 1), name: e?.name?.trim() || "(unnamed)", kind: e?.laneKind ?? "?", note: Boolean(e?.note) };
4954
5164
  });
4955
- const elems = columns.map((sliceId) => rows.map((swimLaneId) => (cells[cellKey(sliceId, swimLaneId)] ?? []).map((r) => elementText(doc, r))));
4956
- const cellNote = columns.map((sliceId) => rows.map((swimLaneId) => Boolean(notes[cellKey(sliceId, swimLaneId)])));
5165
+ const elems = columns.map((columnId) => rows.map((swimLaneId) => (cells[cellKey(columnId, swimLaneId)] ?? []).map((r) => elementText(doc, r))));
5166
+ const cellNote = columns.map((columnId) => rows.map((swimLaneId) => Boolean(notes[cellKey(columnId, swimLaneId)])));
4957
5167
  return {
4958
- title: entityName(doc, "chapters", chapterId),
5168
+ title: entityName(doc, "sheets", sheetId),
5169
+ slices,
4959
5170
  columns: cols,
4960
5171
  rows: lanes2,
4961
5172
  elems,
@@ -4968,7 +5179,12 @@ function rowLabel(r) {
4968
5179
  return r.note ? `${base} ${NOTE}` : base;
4969
5180
  }
4970
5181
  function header(r) {
4971
- return `Sheet "${r.title}" (${r.columns.length} slices × ${r.rows.length} lanes)`;
5182
+ return `Sheet "${r.title}" (${r.slices.length} slices · ${r.columns.length} columns × ${r.rows.length} lanes)`;
5183
+ }
5184
+ function bandLabel(s) {
5185
+ const status = s.status && s.status !== "draft" ? ` · ${s.status}` : "";
5186
+ const note = s.note ? ` ${NOTE}` : "";
5187
+ return `⟦ ${s.label} ${s.name}${status}${note} ⟧`;
4972
5188
  }
4973
5189
  function cellLines(elems, width, hasNote) {
4974
5190
  const lines = elems.length === 0 ? [EMPTY] : (() => {
@@ -4979,22 +5195,27 @@ function cellLines(elems, width, hasNote) {
4979
5195
  lines[lines.length - 1] = `${lines[lines.length - 1]} ${NOTE}`;
4980
5196
  return lines;
4981
5197
  }
4982
- function colHead(c) {
4983
- return c.note ? `${c.label} ${c.name} ${NOTE}` : `${c.label} ${c.name}`;
5198
+ function spanWidth(s, colWidths) {
5199
+ let w = 2 * (s.lastCol - s.firstCol);
5200
+ for (let i = s.firstCol;i <= s.lastCol; i += 1)
5201
+ w += colWidths[i];
5202
+ return w;
4984
5203
  }
4985
5204
  function renderTable(r, opts) {
4986
5205
  const gutter = Math.max(...r.rows.map(rowLabel).map((s) => s.length), 0);
4987
5206
  const colWidths = r.columns.map((c, ci) => {
4988
- const widest = Math.max(colHead(c).length, ...r.elems[ci].map((cell, ri) => Math.max(0, ...cell.map((e) => e.length)) + (r.cellNote[ci][ri] ? 2 : 0)), EMPTY.length);
5207
+ const widest = Math.max(c.label.length, ...r.elems[ci].map((cell, ri) => Math.max(0, ...cell.map((e) => e.length)) + (r.cellNote[ci][ri] ? 2 : 0)), EMPTY.length);
4989
5208
  return Math.min(widest, opts.maxColWidth + 2);
4990
5209
  });
5210
+ for (const s of r.slices) {
5211
+ const deficit = bandLabel(s).length - spanWidth(s, colWidths);
5212
+ if (deficit > 0)
5213
+ colWidths[s.lastCol] += deficit;
5214
+ }
4991
5215
  const totalWidth = gutter + colWidths.reduce((a, w) => a + w + 2, 0);
4992
5216
  const lines = [header(r), LEGEND, ""];
4993
- const headCells = r.columns.map((c, ci) => wrap(colHead(c), colWidths[ci]));
4994
- const headHeight = Math.max(...headCells.map((h) => h.length));
4995
- for (let i = 0;i < headHeight; i += 1) {
4996
- lines.push(pad("", gutter) + " " + r.columns.map((_, ci) => pad(headCells[ci][i] ?? "", colWidths[ci])).join(" "));
4997
- }
5217
+ lines.push(pad("", gutter) + " " + r.slices.map((s) => pad(bandLabel(s), spanWidth(s, colWidths))).join(" "));
5218
+ lines.push(pad("", gutter) + " " + r.columns.map((c, ci) => pad(c.label, colWidths[ci])).join(" "));
4998
5219
  lines.push("─".repeat(totalWidth));
4999
5220
  r.rows.forEach((row, ri) => {
5000
5221
  const cellsLines = r.columns.map((_, ci) => cellLines(r.elems[ci][ri], colWidths[ci], r.cellNote[ci][ri]));
@@ -5012,24 +5233,28 @@ function renderTable(r, opts) {
5012
5233
  }
5013
5234
  function renderListing(r) {
5014
5235
  const lines = [header(r), LEGEND, ""];
5015
- r.columns.forEach((c, ci) => {
5016
- lines.push(`${c.label} "${c.name}"${c.note ? ` ${NOTE}` : ""}`);
5236
+ r.slices.forEach((s) => {
5237
+ const status = s.status && s.status !== "draft" ? ` · ${s.status}` : "";
5238
+ lines.push(`⟦ ${s.label} ⟧ "${s.name}"${status}${s.note ? ` ${NOTE}` : ""}`);
5017
5239
  let any = false;
5018
- r.rows.forEach((row, ri) => {
5019
- const elems = r.elems[ci][ri];
5020
- const noted = r.cellNote[ci][ri];
5021
- if (elems.length === 0 && !noted)
5022
- return;
5023
- any = true;
5024
- const addr = `${c.label}${row.label}`;
5025
- const mark = noted ? ` ${NOTE}` : "";
5026
- if (elems.length <= 1) {
5027
- lines.push(` ${addr} ${elems[0] ?? EMPTY} [${row.kind}]${mark}`);
5028
- } else {
5029
- lines.push(` ${addr} [${row.kind}]${mark}`);
5030
- elems.forEach((e, i) => lines.push(` ${addr}.${i + 1} ${e}`));
5031
- }
5032
- });
5240
+ for (let ci = s.firstCol;ci <= s.lastCol; ci += 1) {
5241
+ const col = r.columns[ci];
5242
+ r.rows.forEach((row, ri) => {
5243
+ const elems = r.elems[ci][ri];
5244
+ const noted = r.cellNote[ci][ri];
5245
+ if (elems.length === 0 && !noted)
5246
+ return;
5247
+ any = true;
5248
+ const addr = `${col.label}${row.label}`;
5249
+ const mark = noted ? ` ${NOTE}` : "";
5250
+ if (elems.length <= 1) {
5251
+ lines.push(` ${addr} ${elems[0] ?? EMPTY} [${row.kind}]${mark}`);
5252
+ } else {
5253
+ lines.push(` ${addr} [${row.kind}]${mark}`);
5254
+ elems.forEach((e, i) => lines.push(` ${addr}.${i + 1} ${e}`));
5255
+ }
5256
+ });
5257
+ }
5033
5258
  if (!any)
5034
5259
  lines.push(" (empty)");
5035
5260
  lines.push("");
@@ -5037,9 +5262,9 @@ function renderListing(r) {
5037
5262
  return lines.join(`
5038
5263
  `).trimEnd();
5039
5264
  }
5040
- function renderSheetOverview(doc, chapterId, options = {}) {
5265
+ function renderSheetOverview(doc, sheetId, options = {}) {
5041
5266
  const opts = { ...DEFAULTS, ...options };
5042
- const r = resolve4(doc, chapterId);
5267
+ const r = resolve4(doc, sheetId);
5043
5268
  if (!r)
5044
5269
  return;
5045
5270
  if (r.empty)
@@ -5073,23 +5298,23 @@ function resolveSheet2(doc, ref) {
5073
5298
  const ids = [...grid2.keys()];
5074
5299
  if (ids.length === 0)
5075
5300
  throw new SheetAddressError("This model has no sheets.");
5076
- const done = (chapterId) => ({ chapterId, structure: readSheet(doc, chapterId) });
5301
+ const done = (sheetId) => ({ sheetId, structure: readSheet(doc, sheetId) });
5077
5302
  if (ref && grid2.has(ref))
5078
5303
  return done(ref);
5079
5304
  if (!ref) {
5080
5305
  if (ids.length === 1)
5081
5306
  return done(ids[0]);
5082
- const list = ids.map((id) => `"${name(doc, "chapters", id)}"`).join(", ");
5307
+ const list = ids.map((id) => `"${name(doc, "sheets", id)}"`).join(", ");
5083
5308
  throw new SheetAddressError(`Multiple sheets — name one. Available: ${list}`);
5084
5309
  }
5085
5310
  const lower = ref.toLowerCase();
5086
- const matches = ids.filter((id) => name(doc, "chapters", id).toLowerCase() === lower);
5311
+ const matches = ids.filter((id) => name(doc, "sheets", id).toLowerCase() === lower);
5087
5312
  if (matches.length === 0) {
5088
- const list = ids.map((id) => `"${name(doc, "chapters", id)}"`).join(", ") || "(none)";
5313
+ const list = ids.map((id) => `"${name(doc, "sheets", id)}"`).join(", ") || "(none)";
5089
5314
  throw new SheetAddressError(`No sheet named "${ref}". Available: ${list}`);
5090
5315
  }
5091
5316
  if (matches.length > 1)
5092
- throw new SheetAddressError(`Ambiguous sheet name "${ref}" — pass the chapterId instead.`);
5317
+ throw new SheetAddressError(`Ambiguous sheet name "${ref}" — pass the sheetId instead.`);
5093
5318
  return done(matches[0]);
5094
5319
  }
5095
5320
  function resolveColumn(doc, s, ref) {
@@ -5127,6 +5352,36 @@ function resolveRow(doc, s, ref) {
5127
5352
  throw new SheetAddressError(`Ambiguous row name "${ref}" — use its number instead.`);
5128
5353
  throw new SheetAddressError(numeric ? `No row "${ref}" — not a lane name, and row ${ref} is out of range (sheet has ${rows.length} rows).` : `No row named "${ref}".`);
5129
5354
  }
5355
+ function resolveSlice(doc, s, ref) {
5356
+ const { columns, columnSlices } = s.structure;
5357
+ const order = sliceOrder(s.structure);
5358
+ const make = (sliceId) => {
5359
+ const columnIds = sliceColumns(s.structure, sliceId);
5360
+ const firstIndex = columns.indexOf(columnIds[0]);
5361
+ const lastIndex = columns.indexOf(columnIds[columnIds.length - 1]);
5362
+ return {
5363
+ sliceId,
5364
+ columnIds,
5365
+ firstIndex,
5366
+ lastIndex,
5367
+ label: firstIndex === lastIndex ? labelOf(firstIndex) : `${labelOf(firstIndex)}–${labelOf(lastIndex)}`
5368
+ };
5369
+ };
5370
+ const lower = ref.toLowerCase();
5371
+ const byName = order.filter((sid) => name(doc, "slices", sid).toLowerCase() === lower);
5372
+ if (byName.length === 1)
5373
+ return make(byName[0]);
5374
+ if (byName.length > 1)
5375
+ throw new SheetAddressError(`Ambiguous slice name "${ref}" — use its leading column letter instead.`);
5376
+ const byLabel = colIndexFromLabel(ref);
5377
+ if (byLabel >= 0 && byLabel < columns.length) {
5378
+ const columnId = columns[byLabel];
5379
+ return make((columnSlices ?? {})[columnId] ?? columnId);
5380
+ }
5381
+ if (order.includes(ref))
5382
+ return make(ref);
5383
+ throw new SheetAddressError(`No slice "${ref}" — not a slice name, a leading column letter, or a sliceId.`);
5384
+ }
5130
5385
  function labelOf(index) {
5131
5386
  let n = index;
5132
5387
  let str = "";
@@ -5285,18 +5540,58 @@ function rejectLane(doc, swimLaneId, rowIndex, kind, type) {
5285
5540
  const allowed = (LANE_ELEMENT_SCOPES[kind] ?? []).map((sc) => TYPE_LABEL[sc] ?? sc).join(", ");
5286
5541
  throw new SheetAddressError(`Lane "${nameOf(doc, "swimLanes", swimLaneId)}" (row ${rowIndex + 1}, kind=${kind}) accepts ${allowed || "(nothing)"}, not ${type}.`);
5287
5542
  }
5288
- function insertColumn(doc, s, modelId, name2, at) {
5543
+ function insertColumn(doc, s, modelId, name2, at, cols = 1) {
5289
5544
  const id = crypto.randomUUID();
5290
5545
  const d = ELEMENT_DIMENSIONS.slice;
5291
5546
  const v = validateEntry("slices", { name: name2, x: 0, y: 0, width: d.width, height: d.height });
5292
5547
  if (!v.ok)
5293
5548
  throw new SheetAddressError(`Invalid slice: ${v.issues.join("; ")}`);
5549
+ const span = Math.max(1, cols);
5294
5550
  doc.transact(() => {
5295
5551
  getScopeMap(doc, "slices").set(id, deepToY({ ...v.data, sliceId: id, modelId }));
5296
- addColumn(doc, s.chapterId, id, at);
5552
+ addColumn(doc, s.sheetId, id, at);
5553
+ for (let i = 1;i < span; i += 1)
5554
+ addColumnToSlice(doc, s.sheetId, id, crypto.randomUUID());
5555
+ });
5556
+ const idx = readSheet(doc, s.sheetId).columns.indexOf(id);
5557
+ const note = span > 1 ? ` (${span} cols)` : "";
5558
+ return `${colLabel2(idx)} "${name2}"${note} ${id}`;
5559
+ }
5560
+ function spanSlice(doc, s, ref, toCol) {
5561
+ const slice = resolveSlice(doc, s, ref);
5562
+ const col = resolveColumn(doc, s, toCol);
5563
+ const sliceName = getEntry(doc, "slices", slice.sliceId)?.name ?? "(unnamed)";
5564
+ doc.transact(() => resizeSliceSpan(doc, s.sheetId, slice.sliceId, col.index));
5565
+ const after = resolveSlice(doc, { sheetId: s.sheetId, structure: readSheet(doc, s.sheetId) }, slice.sliceId);
5566
+ return `slice "${sliceName}" now spans ${after.label}`;
5567
+ }
5568
+ function splitSlice(doc, s, modelId, colRef) {
5569
+ const col = resolveColumn(doc, s, colRef);
5570
+ const columnId = col.sliceId;
5571
+ const owningSlice = (s.structure.columnSlices ?? {})[columnId] ?? columnId;
5572
+ const cols = sliceColumns(s.structure, owningSlice);
5573
+ const pos = cols.indexOf(columnId);
5574
+ if (pos <= 0)
5575
+ throw new SheetAddressError(`Column ${col.label} already begins its slice — nothing to split.`);
5576
+ const newId = crypto.randomUUID();
5577
+ const d = ELEMENT_DIMENSIONS.slice;
5578
+ doc.transact(() => {
5579
+ getScopeMap(doc, "slices").set(newId, deepToY({ sliceId: newId, modelId, name: "Slice", x: 0, y: 0, width: d.width, height: d.height }));
5580
+ for (const c of cols.slice(pos))
5581
+ setColumnSlice(doc, s.sheetId, c, newId);
5297
5582
  });
5298
- const idx = readSheet(doc, s.chapterId).columns.indexOf(id);
5299
- return `${colLabel2(idx)} "${name2}" ${id}`;
5583
+ return `split at ${col.label} — a new slice now covers ${col.label} onward ${newId}`;
5584
+ }
5585
+ function renameSlice(doc, s, ref, newName) {
5586
+ const slice = resolveSlice(doc, s, ref);
5587
+ if (!newName.trim())
5588
+ throw new SheetAddressError("A slice name cannot be empty.");
5589
+ doc.transact(() => {
5590
+ const e = getScopeMap(doc, "slices").get(slice.sliceId);
5591
+ if (e)
5592
+ e.set("name", newName.trim());
5593
+ });
5594
+ return `renamed slice ${slice.label} → "${newName.trim()}"`;
5300
5595
  }
5301
5596
  function insertLane(doc, s, modelId, kind, name2, at) {
5302
5597
  const id = crypto.randomUUID();
@@ -5306,9 +5601,9 @@ function insertLane(doc, s, modelId, kind, name2, at) {
5306
5601
  throw new SheetAddressError(`Invalid lane: ${v.issues.join("; ")}`);
5307
5602
  doc.transact(() => {
5308
5603
  getScopeMap(doc, "swimLanes").set(id, deepToY({ ...v.data, swimLaneId: id, modelId }));
5309
- addRow(doc, s.chapterId, id, at);
5604
+ addRow(doc, s.sheetId, id, at);
5310
5605
  });
5311
- const idx = readSheet(doc, s.chapterId).rows.indexOf(id);
5606
+ const idx = readSheet(doc, s.sheetId).rows.indexOf(id);
5312
5607
  return `${idx + 1} "${name2}" (${kind}) ${id}`;
5313
5608
  }
5314
5609
  function insertElement(doc, s, modelId, type, cellArg, nameOrJson) {
@@ -5337,7 +5632,7 @@ function insertElement(doc, s, modelId, type, cellArg, nameOrJson) {
5337
5632
  };
5338
5633
  doc.transact(() => {
5339
5634
  getScopeMap(doc, "scenarios").set(id, deepToY(entry2));
5340
- placeInCell(doc, s.chapterId, cell.sliceId, cell.swimLaneId, { stickyId: id, scope: "scenarios" });
5635
+ placeInCell(doc, s.sheetId, cell.sliceId, cell.swimLaneId, { stickyId: id, scope: "scenarios" });
5341
5636
  });
5342
5637
  return addressOf(doc, s, cell.sliceId, cell.swimLaneId, id, cell.address);
5343
5638
  }
@@ -5352,12 +5647,12 @@ function insertElement(doc, s, modelId, type, cellArg, nameOrJson) {
5352
5647
  const final = { ...v.data, [meta.idKey]: id, modelId };
5353
5648
  doc.transact(() => {
5354
5649
  getScopeMap(doc, meta.scope).set(id, deepToY(final));
5355
- placeInCell(doc, s.chapterId, cell.sliceId, cell.swimLaneId, { stickyId: id, scope: meta.scope });
5650
+ placeInCell(doc, s.sheetId, cell.sliceId, cell.swimLaneId, { stickyId: id, scope: meta.scope });
5356
5651
  });
5357
5652
  return addressOf(doc, s, cell.sliceId, cell.swimLaneId, id, cell.address);
5358
5653
  }
5359
5654
  function addressOf(doc, s, sliceId, swimLaneId, id, cellAddr) {
5360
- const refs = readSheet(doc, s.chapterId).cells[cellKey(sliceId, swimLaneId)] ?? [];
5655
+ const refs = readSheet(doc, s.sheetId).cells[cellKey(sliceId, swimLaneId)] ?? [];
5361
5656
  const ord = refs.findIndex((r) => r.stickyId === id) + 1;
5362
5657
  return `${cellAddr}.${ord} ${id}`;
5363
5658
  }
@@ -5368,7 +5663,7 @@ function moveElement(doc, s, elAddr, toCell) {
5368
5663
  if (!laneAllows(kind, el.scope))
5369
5664
  rejectLane(doc, dest.swimLaneId, dest.rowIndex, kind, TYPE_LABEL[el.scope] ?? el.scope);
5370
5665
  doc.transact(() => {
5371
- placeInCell(doc, s.chapterId, dest.sliceId, dest.swimLaneId, { stickyId: el.stickyId, scope: el.scope });
5666
+ placeInCell(doc, s.sheetId, dest.sliceId, dest.swimLaneId, { stickyId: el.stickyId, scope: el.scope });
5372
5667
  });
5373
5668
  return addressOf(doc, s, dest.sliceId, dest.swimLaneId, el.stickyId, dest.address);
5374
5669
  }
@@ -5376,14 +5671,14 @@ function reorderAxis(doc, s, ref, to) {
5376
5671
  const toIndex = to - 1;
5377
5672
  if (/^\d+$/.test(ref)) {
5378
5673
  const row = resolveRow(doc, s, ref);
5379
- doc.transact(() => moveRow(doc, s.chapterId, row.swimLaneId, toIndex));
5380
- const idx = readSheet(doc, s.chapterId).rows.indexOf(row.swimLaneId);
5674
+ doc.transact(() => moveRow(doc, s.sheetId, row.swimLaneId, toIndex));
5675
+ const idx = readSheet(doc, s.sheetId).rows.indexOf(row.swimLaneId);
5381
5676
  return `row → ${idx + 1}`;
5382
5677
  }
5383
5678
  if (colIndexFromLabel(ref) >= 0 || s.structure.columns.length > 0) {
5384
5679
  const col = resolveColumn(doc, s, ref);
5385
- doc.transact(() => moveColumn(doc, s.chapterId, col.sliceId, toIndex));
5386
- const idx = readSheet(doc, s.chapterId).columns.indexOf(col.sliceId);
5680
+ doc.transact(() => moveColumn(doc, s.sheetId, col.sliceId, toIndex));
5681
+ const idx = readSheet(doc, s.sheetId).columns.indexOf(col.sliceId);
5387
5682
  return `column → ${colLabel2(idx)}`;
5388
5683
  }
5389
5684
  throw new SheetAddressError(`reorder takes a column letter (A) or row number (1), got "${ref}".`);
@@ -5392,7 +5687,7 @@ function removeTarget(doc, s, target) {
5392
5687
  if (/^[A-Za-z]+\d+(\.\d+)?$/.test(target)) {
5393
5688
  const el = resolveElement(doc, s, target);
5394
5689
  doc.transact(() => {
5395
- removeSticky(doc, s.chapterId, el.stickyId);
5690
+ removeSticky(doc, s.sheetId, el.stickyId);
5396
5691
  getScopeMap(doc, el.scope).delete(el.stickyId);
5397
5692
  cascadeStickyRemoval(doc, new Set([el.stickyId]));
5398
5693
  });
@@ -5403,7 +5698,7 @@ function removeTarget(doc, s, target) {
5403
5698
  const laneName = nameOf(doc, "swimLanes", row.swimLaneId);
5404
5699
  const refs2 = s.structure.columns.flatMap((sliceId) => s.structure.cells[cellKey(sliceId, row.swimLaneId)] ?? []);
5405
5700
  doc.transact(() => {
5406
- removeRow(doc, s.chapterId, row.swimLaneId);
5701
+ removeRow(doc, s.sheetId, row.swimLaneId);
5407
5702
  getScopeMap(doc, "swimLanes").delete(row.swimLaneId);
5408
5703
  for (const r of refs2)
5409
5704
  getScopeMap(doc, r.scope).delete(r.stickyId);
@@ -5415,7 +5710,7 @@ function removeTarget(doc, s, target) {
5415
5710
  const sliceName = nameOf(doc, "slices", col.sliceId);
5416
5711
  const refs = s.structure.rows.flatMap((swimLaneId) => s.structure.cells[cellKey(col.sliceId, swimLaneId)] ?? []);
5417
5712
  doc.transact(() => {
5418
- removeColumn(doc, s.chapterId, col.sliceId);
5713
+ removeColumn(doc, s.sheetId, col.sliceId);
5419
5714
  getScopeMap(doc, "slices").delete(col.sliceId);
5420
5715
  for (const r of refs)
5421
5716
  getScopeMap(doc, r.scope).delete(r.stickyId);
@@ -5493,7 +5788,7 @@ function sheetEdgeHandle(side, dir) {
5493
5788
  }
5494
5789
  function resolveAnchor(doc, sheet, dir, col, side) {
5495
5790
  const flag = dir === "source" ? "from" : "to";
5496
- const sheetName = nameOf(doc, "chapters", sheet.chapterId);
5791
+ const sheetName = nameOf(doc, "sheets", sheet.sheetId);
5497
5792
  if (col !== undefined) {
5498
5793
  const c = resolveColumn(doc, sheet, col);
5499
5794
  const s2 = side ?? (dir === "source" ? "bottom" : "top");
@@ -5511,7 +5806,7 @@ function resolveAnchor(doc, sheet, dir, col, side) {
5511
5806
  function connectSheets(doc, modelId, fromRef, toRef, opts) {
5512
5807
  const src = resolveSheet2(doc, fromRef);
5513
5808
  const dst = resolveSheet2(doc, toRef);
5514
- if (src.chapterId === dst.chapterId) {
5809
+ if (src.sheetId === dst.sheetId) {
5515
5810
  throw new SheetAddressError("Connect joins two different sheets — source and target are the same sheet.");
5516
5811
  }
5517
5812
  const from = resolveAnchor(doc, src, "source", opts.from, opts.fromSide);
@@ -5519,9 +5814,9 @@ function connectSheets(doc, modelId, fromRef, toRef, opts) {
5519
5814
  const id = crypto.randomUUID();
5520
5815
  const entry = {
5521
5816
  sheetFlowId: id,
5522
- sourceChapterId: src.chapterId,
5817
+ sourceSheetId: src.sheetId,
5523
5818
  sourceHandle: from.handle,
5524
- targetChapterId: dst.chapterId,
5819
+ targetSheetId: dst.sheetId,
5525
5820
  targetHandle: to.handle
5526
5821
  };
5527
5822
  const v = validateEntry("sheetFlows", entry);
@@ -5554,7 +5849,7 @@ function copyElement(doc, s, modelId, srcAddr, toCell) {
5554
5849
  const dim = FIXED_SIZE_DIM(src.scope);
5555
5850
  doc.transact(() => {
5556
5851
  getScopeMap(doc, src.scope).set(id, deepToY({ [meta.idKey]: id, modelId, name: "", x: 0, y: 0, width: dim.width, height: dim.height, isLinkedCopy: true, [meta.originalIdKey]: originalId }));
5557
- placeInCell(doc, s.chapterId, dest.sliceId, dest.swimLaneId, { stickyId: id, scope: src.scope });
5852
+ placeInCell(doc, s.sheetId, dest.sliceId, dest.swimLaneId, { stickyId: id, scope: src.scope });
5558
5853
  });
5559
5854
  return addressOf(doc, s, dest.sliceId, dest.swimLaneId, id, dest.address);
5560
5855
  }
@@ -5584,7 +5879,7 @@ function noteTarget(doc, s, target, text) {
5584
5879
  }
5585
5880
  if (/^[A-Za-z]+\d+$/.test(target)) {
5586
5881
  const cell = resolveCell(doc, s, target);
5587
- setCellNote(doc, s.chapterId, cell.sliceId, cell.swimLaneId, t);
5882
+ setCellNote(doc, s.sheetId, cell.sliceId, cell.swimLaneId, t);
5588
5883
  return `${verb} cell ${cell.address}`;
5589
5884
  }
5590
5885
  if (/^\d+$/.test(target)) {
@@ -5684,12 +5979,12 @@ function buildFromSpec(doc, modelId, nameArg, spec) {
5684
5979
  if (f.type && f.type !== inferred)
5685
5980
  throw new SheetAddressError(`Flow ${f.from}→${f.to} is ${inferred}, not ${f.type}.`);
5686
5981
  }
5687
- const chapterId = crypto.randomUUID();
5982
+ const sheetId = crypto.randomUUID();
5688
5983
  const idByAddress = {};
5689
5984
  doc.transact(() => {
5690
- const cd = ELEMENT_DIMENSIONS.chapter;
5691
- getScopeMap(doc, "chapters").set(chapterId, deepToY({ chapterId, modelId, name: sheetName, x: 0, y: 0, width: cd.width, height: cd.height }));
5692
- ensureSheet(doc, chapterId);
5985
+ const cd = ELEMENT_DIMENSIONS.sheet;
5986
+ getScopeMap(doc, "sheets").set(sheetId, deepToY({ sheetId, modelId, name: sheetName, x: 0, y: 0, width: cd.width, height: cd.height }));
5987
+ ensureSheet(doc, sheetId);
5693
5988
  const sd = ELEMENT_DIMENSIONS.slice;
5694
5989
  const sliceIds = cols.map((c) => {
5695
5990
  const id = crypto.randomUUID();
@@ -5699,7 +5994,7 @@ function buildFromSpec(doc, modelId, nameArg, spec) {
5699
5994
  if (c.note)
5700
5995
  entry.note = c.note;
5701
5996
  getScopeMap(doc, "slices").set(id, deepToY(entry));
5702
- addColumn(doc, chapterId, id);
5997
+ addColumn(doc, sheetId, id);
5703
5998
  return id;
5704
5999
  });
5705
6000
  const ld = ELEMENT_DIMENSIONS.swimLane;
@@ -5709,7 +6004,7 @@ function buildFromSpec(doc, modelId, nameArg, spec) {
5709
6004
  if (r.note)
5710
6005
  entry.note = r.note;
5711
6006
  getScopeMap(doc, "swimLanes").set(id, deepToY(entry));
5712
- addRow(doc, chapterId, id);
6007
+ addRow(doc, sheetId, id);
5713
6008
  return id;
5714
6009
  });
5715
6010
  for (const op of ops) {
@@ -5731,10 +6026,10 @@ function buildFromSpec(doc, modelId, nameArg, spec) {
5731
6026
  width: SCENARIO_CARD.width,
5732
6027
  height: SCENARIO_CARD.height
5733
6028
  }));
5734
- placeInCell(doc, chapterId, sliceIds[op.ci], laneIds[op.ri], { stickyId: id, scope: "scenarios" });
6029
+ placeInCell(doc, sheetId, sliceIds[op.ci], laneIds[op.ri], { stickyId: id, scope: "scenarios" });
5735
6030
  } else {
5736
6031
  getScopeMap(doc, op.scope).set(id, deepToY({ ...op.data, [op.idKey]: id, modelId }));
5737
- placeInCell(doc, chapterId, sliceIds[op.ci], laneIds[op.ri], { stickyId: id, scope: op.scope });
6032
+ placeInCell(doc, sheetId, sliceIds[op.ci], laneIds[op.ri], { stickyId: id, scope: op.scope });
5738
6033
  }
5739
6034
  idByAddress[op.address] = id;
5740
6035
  }
@@ -5745,7 +6040,7 @@ function buildFromSpec(doc, modelId, nameArg, spec) {
5745
6040
  const id = crypto.randomUUID();
5746
6041
  const dim = FIXED_SIZE_DIM(op.scope);
5747
6042
  getScopeMap(doc, op.scope).set(id, deepToY({ [meta.idKey]: id, modelId, name: "", x: 0, y: 0, width: dim.width, height: dim.height, isLinkedCopy: true, [meta.originalIdKey]: idByAddress[op.copyOf] }));
5748
- placeInCell(doc, chapterId, sliceIds[op.ci], laneIds[op.ri], { stickyId: id, scope: op.scope });
6043
+ placeInCell(doc, sheetId, sliceIds[op.ci], laneIds[op.ri], { stickyId: id, scope: op.scope });
5749
6044
  idByAddress[op.address] = id;
5750
6045
  }
5751
6046
  for (const f of specFlows) {
@@ -5760,25 +6055,37 @@ function buildFromSpec(doc, modelId, nameArg, spec) {
5760
6055
  const ci = colIndexFromLabel(cl);
5761
6056
  const ri = rowNum - 1;
5762
6057
  if (ci >= 0 && ci < cols.length && ri >= 0 && ri < rows.length && text) {
5763
- setCellNote(doc, chapterId, sliceIds[ci], laneIds[ri], text);
6058
+ setCellNote(doc, sheetId, sliceIds[ci], laneIds[ri], text);
5764
6059
  }
5765
6060
  }
5766
6061
  });
5767
6062
  reflowAllSheets(doc);
5768
6063
  const nElems = ops.length;
5769
- return `built sheet "${sheetName}" — ${cols.length} slices, ${rows.length} lanes, ${nElems} elements, ${specFlows.length} flows ${chapterId}`;
6064
+ return `built sheet "${sheetName}" — ${cols.length} slices, ${rows.length} lanes, ${nElems} elements, ${specFlows.length} flows ${sheetId}`;
5770
6065
  }
5771
6066
  function buildSheetJson(doc, s) {
5772
6067
  const { columns, rows, cells } = s.structure;
5773
- const columnViews = columns.map((sliceId, i) => {
6068
+ const ownerOf = (columnId) => (s.structure.columnSlices ?? {})[columnId] ?? columnId;
6069
+ const columnViews = columns.map((columnId, i) => {
6070
+ const e = getEntry(doc, "slices", ownerOf(columnId));
6071
+ return { label: colLabel2(i), columnId, name: e?.name ?? "(unnamed)", status: e?.status ?? null, note: e?.note ?? null };
6072
+ });
6073
+ const slices = sliceOrder(s.structure).map((sliceId) => {
6074
+ const cids = sliceColumns(s.structure, sliceId);
5774
6075
  const e = getEntry(doc, "slices", sliceId);
5775
- return { label: colLabel2(i), name: e?.name ?? "(unnamed)", sliceId, status: e?.status ?? null, note: e?.note ?? null };
6076
+ return {
6077
+ sliceId,
6078
+ name: e?.name ?? "(unnamed)",
6079
+ status: e?.status ?? null,
6080
+ note: e?.note ?? null,
6081
+ cols: cids.map((c) => colLabel2(columns.indexOf(c)))
6082
+ };
5776
6083
  });
5777
6084
  const rowViews = rows.map((swimLaneId, i) => {
5778
6085
  const e = getEntry(doc, "swimLanes", swimLaneId);
5779
6086
  return { label: String(i + 1), name: e?.name ?? "(unnamed)", laneKind: e?.laneKind ?? null, swimLaneId, note: e?.note ?? null };
5780
6087
  });
5781
- const cellNotes = readCellNotes(doc, s.chapterId);
6088
+ const cellNotes = readCellNotes(doc, s.sheetId);
5782
6089
  const cellNotesByAddr = {};
5783
6090
  for (const [k, text] of Object.entries(cellNotes)) {
5784
6091
  const [sliceId, swimLaneId] = k.split(":");
@@ -5801,7 +6108,7 @@ function buildSheetJson(doc, s) {
5801
6108
  }));
5802
6109
  });
5803
6110
  });
5804
- return { sheet: nameOf(doc, "chapters", s.chapterId), chapterId: s.chapterId, columns: columnViews, rows: rowViews, cells: cellViews, cellNotes: cellNotesByAddr };
6111
+ return { sheet: nameOf(doc, "sheets", s.sheetId), sheetId: s.sheetId, slices, columns: columnViews, rows: rowViews, cells: cellViews, cellNotes: cellNotesByAddr };
5805
6112
  }
5806
6113
  function buildCellView(doc, s, cellArg) {
5807
6114
  const { ordinal } = parseCellAddress(cellArg);
@@ -5818,7 +6125,7 @@ function buildCellView(doc, s, cellArg) {
5818
6125
  const flows = getEntries(doc, "flows");
5819
6126
  return {
5820
6127
  cell: cell.address,
5821
- note: readCellNotes(doc, s.chapterId)[cellKey(cell.sliceId, cell.swimLaneId)] ?? null,
6128
+ note: readCellNotes(doc, s.sheetId)[cellKey(cell.sliceId, cell.swimLaneId)] ?? null,
5822
6129
  slice: { label: colLabel2(cell.colIndex), name: slice?.name ?? "(unnamed)", sliceId: cell.sliceId, note: slice?.note ?? null },
5823
6130
  lane: { label: String(cell.rowIndex + 1), name: lane?.name ?? "(unnamed)", laneKind: lane?.laneKind ?? null, swimLaneId: cell.swimLaneId, note: lane?.note ?? null },
5824
6131
  elements: refs.map((r) => ({
@@ -5864,7 +6171,7 @@ function registerSheetCommands(program) {
5864
6171
  return JSON.stringify(buildCellView(doc, s, cellArg), null, 2);
5865
6172
  if (opts.json)
5866
6173
  return JSON.stringify(buildSheetJson(doc, s), null, 2);
5867
- return renderSheetOverview(doc, s.chapterId) ?? "(empty sheet)";
6174
+ return renderSheetOverview(doc, s.sheetId) ?? "(empty sheet)";
5868
6175
  });
5869
6176
  console.log(output);
5870
6177
  } catch (err) {
@@ -5895,13 +6202,13 @@ function registerSheetCommands(program) {
5895
6202
  if (!name2)
5896
6203
  throw new SheetAddressError("Pass a <name> (or --from <file>).");
5897
6204
  const id = crypto.randomUUID();
5898
- const d = ELEMENT_DIMENSIONS.chapter;
5899
- const v = validateEntry("chapters", { name: name2, x: 0, y: 0, width: d.width, height: d.height });
6205
+ const d = ELEMENT_DIMENSIONS.sheet;
6206
+ const v = validateEntry("sheets", { name: name2, x: 0, y: 0, width: d.width, height: d.height });
5900
6207
  if (!v.ok)
5901
6208
  throw new SheetAddressError(`Invalid sheet: ${v.issues.join("; ")}`);
5902
6209
  const out = await withDoc(modelId, (doc) => {
5903
6210
  doc.transact(() => {
5904
- getScopeMap(doc, "chapters").set(id, deepToY({ ...v.data, chapterId: id, modelId }));
6211
+ getScopeMap(doc, "sheets").set(id, deepToY({ ...v.data, sheetId: id, modelId }));
5905
6212
  ensureSheet(doc, id);
5906
6213
  });
5907
6214
  reflowAllSheets(doc);
@@ -5921,14 +6228,14 @@ function registerSheetCommands(program) {
5921
6228
  try {
5922
6229
  const out = await withDoc(modelId, (doc) => {
5923
6230
  const s = resolveSheet2(doc, sheetRef);
5924
- const name2 = getEntry(doc, "chapters", s.chapterId)?.name ?? s.chapterId;
6231
+ const name2 = getEntry(doc, "sheets", s.sheetId)?.name ?? s.sheetId;
5925
6232
  const elements = Object.values(s.structure.cells).reduce((n, refs) => n + refs.length, 0);
5926
6233
  const summary = `sheet "${name2}" — ${s.structure.columns.length} slice(s), ${s.structure.rows.length} lane(s), ${elements} element(s)`;
5927
6234
  if (!opts.yes) {
5928
6235
  return `Would delete ${summary}.
5929
6236
  This cannot be undone. Re-run with --yes to confirm.`;
5930
6237
  }
5931
- deleteSheet(doc, s.chapterId);
6238
+ deleteSheet(doc, s.sheetId);
5932
6239
  reflowAllSheets(doc);
5933
6240
  return `Deleted ${summary}.`;
5934
6241
  });
@@ -5942,15 +6249,19 @@ This cannot be undone. Re-run with --yes to confirm.`;
5942
6249
  }
5943
6250
  });
5944
6251
  const insert = sheet.command("insert").description("Insert a slice (column), a lane (row), or an element into a cell");
5945
- insert.command("slice <name>").description("Insert a new slice (column)").option("--at <n>", "Position (1-based); appends if omitted").option("--sheet <ref>", "Which sheet (name or chapterId) when the model has several").option("--model <id>", "Target model id").action((name2, opts) => runWrite(opts, (doc, s, modelId) => insertColumn(doc, s, modelId, name2, atIndex(opts.at))));
6252
+ insert.command("slice <name>").description("Insert a new slice; --cols N makes it span N contiguous columns").option("--at <n>", "Position (1-based); appends if omitted").option("--cols <n>", "How many columns the slice spans (default 1)").option("--sheet <ref>", "Which sheet (name or sheetId) when the model has several").option("--model <id>", "Target model id").action((name2, opts) => runWrite(opts, (doc, s, modelId) => insertColumn(doc, s, modelId, name2, atIndex(opts.at), opts.cols ? Math.max(1, parseInt(opts.cols, 10) || 1) : 1)));
5946
6253
  for (const kind of LANE_KINDS) {
5947
- insert.command(`${kind} <name>`).description(`Insert a ${kind} lane (row)`).option("--at <n>", "Position (1-based); appends if omitted").option("--sheet <ref>", "Which sheet (name or chapterId) when the model has several").option("--model <id>", "Target model id").action((name2, opts) => runWrite(opts, (doc, s, modelId) => insertLane(doc, s, modelId, kind, name2, atIndex(opts.at))));
6254
+ insert.command(`${kind} <name>`).description(`Insert a ${kind} lane (row)`).option("--at <n>", "Position (1-based); appends if omitted").option("--sheet <ref>", "Which sheet (name or sheetId) when the model has several").option("--model <id>", "Target model id").action((name2, opts) => runWrite(opts, (doc, s, modelId) => insertLane(doc, s, modelId, kind, name2, atIndex(opts.at))));
5948
6255
  }
5949
6256
  for (const type of ELEMENT_TYPES) {
5950
- insert.command(`${type} <cell> <element>`).description(`Insert a ${type} into a cell (e.g. B2). <element> is a name or a JSON object.`).option("--sheet <ref>", "Which sheet (name or chapterId) when the model has several").option("--model <id>", "Target model id").action((cell, element, opts) => runWrite(opts, (doc, s, modelId) => insertElement(doc, s, modelId, type, cell, element)));
6257
+ insert.command(`${type} <cell> <element>`).description(`Insert a ${type} into a cell (e.g. B2). <element> is a name or a JSON object.`).option("--sheet <ref>", "Which sheet (name or sheetId) when the model has several").option("--model <id>", "Target model id").action((cell, element, opts) => runWrite(opts, (doc, s, modelId) => insertElement(doc, s, modelId, type, cell, element)));
5951
6258
  }
5952
6259
  sheet.command("move <element>").description("Move an element to another cell, e.g. `move B2.1 --to C2` (keeps its id + flows)").requiredOption("--to <cell>", "Destination cell (e.g. C2)").option("--sheet <ref>", "Which sheet when the model has several").option("--model <id>", "Target model id").action((element, opts) => runWrite(opts, (doc, s) => moveElement(doc, s, element, opts.to)));
5953
6260
  sheet.command("reorder <ref>").description("Reorder a slice (column letter) or lane (row number), e.g. `reorder A --to 3`").requiredOption("--to <n>", "New 1-based position").option("--sheet <ref>", "Which sheet when the model has several").option("--model <id>", "Target model id").action((ref, opts) => runWrite(opts, (doc, s) => reorderAxis(doc, s, ref, parseInt(opts.to, 10))));
6261
+ const slice = sheet.command("slice").description("Slice (work-ticket) ops: span across columns, split, rename");
6262
+ slice.command("span <slice>").description("Set a slice to span up to a column, e.g. `slice span A --to C` (grows or shrinks)").requiredOption("--to <col>", "The column the slice should end at (letter or name)").option("--sheet <ref>", "Which sheet when the model has several").option("--model <id>", "Target model id").action((sliceRef, opts) => runWrite(opts, (doc, s) => spanSlice(doc, s, sliceRef, opts.to)));
6263
+ slice.command("split <col>").description("Split a slice so <col> begins a new slice (the columns from <col> onward break off)").option("--sheet <ref>", "Which sheet when the model has several").option("--model <id>", "Target model id").action((col, opts) => runWrite(opts, (doc, s, modelId) => splitSlice(doc, s, modelId, col)));
6264
+ slice.command("rename <slice> <name>").description("Rename a slice (by name, leading column letter, or id)").option("--sheet <ref>", "Which sheet when the model has several").option("--model <id>", "Target model id").action((sliceRef, name2, opts) => runWrite(opts, (doc, s) => renameSlice(doc, s, sliceRef, name2)));
5954
6265
  sheet.command("rm <target>").description("Remove an element (B2.1), a column (A), or a lane (2) — cascades to flows/scenarios").option("--sheet <ref>", "Which sheet when the model has several").option("--model <id>", "Target model id").action((target, opts) => runWrite(opts, (doc, s) => removeTarget(doc, s, target)));
5955
6266
  sheet.command("update <address> <json>").description(`Replace an element's shape in place (e.g. \`update A2.1 '{"name":"PlaceOrderV2","fields":[…]}'\`)`).option("--sheet <ref>", "Which sheet when the model has several").option("--model <id>", "Target model id").action((address, json, opts) => runWrite(opts, (doc, s, modelId) => updateElement(doc, s, modelId, address, json)));
5956
6267
  sheet.command("flow <from> <to>").description("Connect two elements, e.g. `flow A2.1 A3.1` (flow type inferred from the element kinds)").option("--type <flowType>", "Force a flow type (otherwise inferred)").option("--sheet <ref>", "Which sheet when the model has several").option("--model <id>", "Target model id").action((from, to, opts) => runWrite(opts, (doc, s, modelId) => flowBetween(doc, s, modelId, from, to, opts.type)));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eventmodeler",
3
- "version": "0.6.13",
3
+ "version": "0.6.15",
4
4
  "description": "CLI tool for event modeling - explore, design, and generate code from your event models",
5
5
  "type": "module",
6
6
  "repository": {