@components-kit/open-workbook 0.1.1 → 0.1.3

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.
@@ -1,12 +1,13 @@
1
1
  import { mkdir, readFile, stat, unlink, writeFile } from "node:fs/promises";
2
2
  import { createHash } from "node:crypto";
3
3
  import path from "node:path";
4
- import { BackupManager, BatchCompiler, DefaultPermissionPolicy, buildFormulaDependencyGraph, attachConflictGuidance, extractFormulaReferences, hashStable, LockManager, parseA1Address, PlanManager, SnapshotManager, TaskRegistry, TemplateRegistry, TransactionManager, traceDependents, tracePrecedents } from "@components-kit/open-workbook-excel-core";
4
+ import { BackupManager, BatchCompiler, DefaultPermissionPolicy, buildFormulaDependencyGraph, attachConflictGuidance, extractFormulaReferences, hashStable, LockManager, formatA1Address, parseA1Address, PlanManager, SnapshotManager, TaskRegistry, TemplateRegistry, TransactionManager, traceDependents, tracePrecedents } from "@components-kit/open-workbook-excel-core";
5
5
  import { makeRollbackConflict } from "@components-kit/open-workbook-excel-core";
6
6
  import { getToolCatalogSummary, PromptCatalog, ResourceCatalog, makeId, runtimeError } from "@components-kit/open-workbook-protocol";
7
7
  import { SessionRegistry } from "./session-registry.js";
8
8
  import { NativeFileBridge } from "./native-file-bridge.js";
9
9
  import { RuntimeStateStore } from "./state-store.js";
10
+ const runtimeVersion = process.env.OPEN_WORKBOOK_VERSION ?? "0.1.3";
10
11
  export class RuntimeService {
11
12
  sessions = new SessionRegistry();
12
13
  backups = new BackupManager();
@@ -913,6 +914,12 @@ export class RuntimeService {
913
914
  const activeSession = this.sessions.getActive();
914
915
  return {
915
916
  ok: true,
917
+ runtime: {
918
+ service: "open-workbook-backend",
919
+ packageName: "@components-kit/open-workbook-backend",
920
+ version: runtimeVersion,
921
+ pid: process.pid
922
+ },
916
923
  activeAddinConnected: Boolean(activeSession),
917
924
  fileBridge: this.fileBridge.getStatus(),
918
925
  sessions: this.sessions.list(),
@@ -2703,11 +2710,9 @@ export class RuntimeService {
2703
2710
  return cleaningError(input.workbookId, "normalize_headers", target, read.error);
2704
2711
  }
2705
2712
  const headerRowIndex = input.headerRowIndex ?? detectHeaderCandidates(read.values, 10)[0]?.rowIndex ?? 0;
2706
- const values = cloneMatrix(read.values);
2707
- const before = values[headerRowIndex] ?? [];
2713
+ const before = read.values[headerRowIndex] ?? [];
2708
2714
  const normalized = dedupeHeaders(before.map((value) => normalizeHeader(String(value ?? ""))));
2709
- values[headerRowIndex] = normalized;
2710
- const result = await this.writeCleanValues(target, values, "Normalize headers");
2715
+ const result = await this.writeCleanValues(headerRowTarget(target, headerRowIndex), [normalized], "Normalize headers");
2711
2716
  return cleaningReport(input.workbookId, "normalize_headers", target, changedCellCount([before], [normalized]), { headerRowIndex, headers: normalized }, result);
2712
2717
  }
2713
2718
  async cleanTrimWhitespace(input) {
@@ -3132,6 +3137,22 @@ export class RuntimeService {
3132
3137
  async resizeTable(request) {
3133
3138
  return this.mutateTable("table.resize", request, `Before resizing table ${request.tableName}`, await this.getTableBackupRanges(request));
3134
3139
  }
3140
+ async reorderTableColumns(request) {
3141
+ const infoResult = await this.getTableInfo(request);
3142
+ const info = infoResult.info;
3143
+ if (!info) {
3144
+ return {
3145
+ ok: false,
3146
+ error: runtimeError("NOT_FOUND", `Table ${request.tableName} could not be read before column reorder.`, { retryable: false }),
3147
+ table: infoResult
3148
+ };
3149
+ }
3150
+ const validation = validateTableColumnOrder(info, request.columnOrder);
3151
+ if (!validation.ok) {
3152
+ return validation;
3153
+ }
3154
+ return this.mutateTable("table.reorder_columns", request, `Before reordering columns in table ${request.tableName}`, await this.getTableBackupRanges(request));
3155
+ }
3135
3156
  async appendTableRows(request) {
3136
3157
  return this.mutateTable("table.append_rows", request, `Before appending rows to table ${request.tableName}`, await this.getTableBackupRanges(request));
3137
3158
  }
@@ -3261,15 +3282,18 @@ export class RuntimeService {
3261
3282
  workbookId: request.workbookId,
3262
3283
  goal: reason,
3263
3284
  scopes: tableMutationScopes(request, ranges),
3264
- destructiveLevel: method.includes("resize") || method.includes("copy_structure") ? "structure" : "values"
3285
+ destructiveLevel: method.includes("resize") || method.includes("copy_structure") || method.includes("reorder_columns") ? "structure" : "values"
3265
3286
  }, async () => {
3266
3287
  const backup = await this.createWorkbookBackup({
3267
3288
  workbookId: request.workbookId,
3268
3289
  reason,
3269
3290
  ranges
3270
3291
  });
3292
+ if (!("backup" in backup)) {
3293
+ return backup;
3294
+ }
3271
3295
  const result = await client.request(method, request);
3272
- return { ok: true, backup, result };
3296
+ return { ok: true, backup: backup.backup, result };
3273
3297
  });
3274
3298
  }
3275
3299
  async mutateFormulas(method, request, reason, validate) {
@@ -5331,6 +5355,58 @@ function pivotTemplateRequiredSourceFields(info) {
5331
5355
  function uniqueDefined(values) {
5332
5356
  return [...new Set(values.filter((value) => typeof value === "string" && value.length > 0))];
5333
5357
  }
5358
+ function validateTableColumnOrder(info, columnOrder) {
5359
+ const issues = [];
5360
+ if (columnOrder.length !== info.columns.length) {
5361
+ issues.push({
5362
+ code: "TABLE_COLUMN_ORDER_LENGTH_MISMATCH",
5363
+ message: `Column order must include exactly ${info.columns.length} column(s).`,
5364
+ details: { expectedCount: info.columns.length, actualCount: columnOrder.length }
5365
+ });
5366
+ }
5367
+ const seen = new Set();
5368
+ for (const requested of columnOrder) {
5369
+ const column = typeof requested === "number"
5370
+ ? info.columns.find((candidate) => candidate.index === requested)
5371
+ : info.columns.find((candidate) => candidate.name === requested);
5372
+ if (!column) {
5373
+ issues.push({
5374
+ code: "TABLE_COLUMN_NOT_FOUND",
5375
+ message: `Column ${String(requested)} is not present in table ${info.tableName}.`,
5376
+ details: { requested, availableColumns: info.columns.map((candidate) => candidate.name) }
5377
+ });
5378
+ continue;
5379
+ }
5380
+ if (seen.has(column.index)) {
5381
+ issues.push({
5382
+ code: "TABLE_COLUMN_ORDER_DUPLICATE",
5383
+ message: `Column ${column.name} appears more than once in the requested order.`,
5384
+ details: { requested, column }
5385
+ });
5386
+ }
5387
+ seen.add(column.index);
5388
+ }
5389
+ for (const column of info.columns) {
5390
+ if (!seen.has(column.index)) {
5391
+ issues.push({
5392
+ code: "TABLE_COLUMN_ORDER_MISSING_COLUMN",
5393
+ message: `Column ${column.name} is missing from the requested order.`,
5394
+ details: { column }
5395
+ });
5396
+ }
5397
+ }
5398
+ if (issues.length > 0) {
5399
+ return {
5400
+ ok: false,
5401
+ warnings: issues,
5402
+ error: runtimeError("INVALID_ARGUMENT", "Table column reorder requires a complete, unique column order.", {
5403
+ retryable: false,
5404
+ details: { issues }
5405
+ })
5406
+ };
5407
+ }
5408
+ return { ok: true };
5409
+ }
5334
5410
  function addExpectedPivotAxisIssues(issues, axis, expectedFields, actualFields) {
5335
5411
  if (!expectedFields?.length) {
5336
5412
  return;
@@ -5542,6 +5618,14 @@ function targetFromCleanInput(input) {
5542
5618
  address: input.address
5543
5619
  };
5544
5620
  }
5621
+ function headerRowTarget(target, headerRowIndex) {
5622
+ const parsed = parseA1Address(stripSheetName(target.address));
5623
+ const row = parsed.startRow + headerRowIndex;
5624
+ return {
5625
+ ...target,
5626
+ address: formatA1Address({ startColumn: parsed.startColumn, endColumn: parsed.endColumn, startRow: row, endRow: row })
5627
+ };
5628
+ }
5545
5629
  function cleaningReport(workbookId, action, target, changedCells, data, result) {
5546
5630
  const report = {
5547
5631
  ok: result ? result.ok : true,
@@ -5886,7 +5970,7 @@ function disconnectedRuntimeCapabilities() {
5886
5970
  return {
5887
5971
  engine: {
5888
5972
  name: "open-workbook-daemon",
5889
- version: "0.1.1",
5973
+ version: runtimeVersion,
5890
5974
  platform: "unknown"
5891
5975
  },
5892
5976
  apiSets: [],