@openshain/tools 0.3.1 → 0.4.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/NOTICE ADDED
@@ -0,0 +1,4 @@
1
+ openshain
2
+ Copyright 2026 openshain contributors
3
+
4
+ Licensed under the Apache License, Version 2.0.
package/dist/index.d.ts CHANGED
@@ -1 +1 @@
1
- export { MAX_READ_BYTES, standardTools } from "./standard.ts";
1
+ export { csvText, MAX_READ_BYTES, standardTools } from "./standard.ts";
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
1
  // @openshain/tools: Standard tool provider: filesystem, CSV, Markdown, documents, email
2
- export { MAX_READ_BYTES, standardTools } from "./standard.js";
2
+ export { csvText, MAX_READ_BYTES, standardTools } from "./standard.js";
@@ -14,3 +14,12 @@ export declare const DEFAULT_WINDOW: {
14
14
  };
15
15
  /** The tools every workspace gets: files, CSV and Markdown, all confined to the workspace. */
16
16
  export declare function standardTools(): ToolProvider;
17
+ /**
18
+ * Spreadsheets run a cell that starts with =, +, @ or - as a formula. A leading apostrophe keeps
19
+ * it text. Negative numbers are left alone.
20
+ */
21
+ /**
22
+ * The rows of a csv_write as the file will read them, with the header and the formula guard.
23
+ * The screen shows this before a person approves a write, so both go through one function.
24
+ */
25
+ export declare function csvText(rows: Record<string, unknown>[], columns?: string[]): string;
package/dist/standard.js CHANGED
@@ -391,11 +391,7 @@ async function csvAggregate(ctx, path, input) {
391
391
  async function csvWrite(ctx, path, rows, columns) {
392
392
  if (!Array.isArray(rows))
393
393
  throw new Error("rows must be an array of objects");
394
- const safeRows = rows.map((row) => Object.fromEntries(Object.entries(row).map(([key, value]) => [key, neutralizeFormula(value)])));
395
- const content = stringify(safeRows, {
396
- header: true,
397
- ...(Array.isArray(columns) && { columns: columns }),
398
- });
394
+ const content = csvText(rows, Array.isArray(columns) ? columns : undefined);
399
395
  const after = await writeText(ctx, path, content);
400
396
  return {
401
397
  content: [{ type: "text", text: `wrote ${rows.length} rows to ${after.path}` }],
@@ -659,6 +655,14 @@ function failure(message) {
659
655
  * Spreadsheets run a cell that starts with =, +, @ or - as a formula. A leading apostrophe keeps
660
656
  * it text. Negative numbers are left alone.
661
657
  */
658
+ /**
659
+ * The rows of a csv_write as the file will read them, with the header and the formula guard.
660
+ * The screen shows this before a person approves a write, so both go through one function.
661
+ */
662
+ export function csvText(rows, columns) {
663
+ const safeRows = rows.map((row) => Object.fromEntries(Object.entries(row).map(([key, value]) => [key, neutralizeFormula(value)])));
664
+ return stringify(safeRows, { header: true, ...(columns && { columns }) });
665
+ }
662
666
  function neutralizeFormula(value) {
663
667
  if (typeof value !== "string")
664
668
  return value;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openshain/tools",
3
- "version": "0.3.1",
3
+ "version": "0.4.0",
4
4
  "description": "Standard tool provider: filesystem, CSV, Markdown, documents, email",
5
5
  "keywords": [
6
6
  "openshain",
@@ -30,7 +30,8 @@
30
30
  "!src/**/*.test.ts",
31
31
  "!src/**/*.test.tsx",
32
32
  "README.md",
33
- "LICENSE"
33
+ "LICENSE",
34
+ "NOTICE"
34
35
  ],
35
36
  "exports": {
36
37
  ".": {
@@ -44,7 +45,7 @@
44
45
  "prepublishOnly": "rm -rf dist && ../../node_modules/.bin/tsc -p tsconfig.build.json"
45
46
  },
46
47
  "dependencies": {
47
- "@openshain/core": "0.3.1",
48
+ "@openshain/core": "0.4.0",
48
49
  "csv-parse": "7.0.2",
49
50
  "csv-stringify": "6.8.3"
50
51
  },
package/src/index.ts CHANGED
@@ -1,2 +1,2 @@
1
1
  // @openshain/tools: Standard tool provider: filesystem, CSV, Markdown, documents, email
2
- export { MAX_READ_BYTES, standardTools } from "./standard.ts";
2
+ export { csvText, MAX_READ_BYTES, standardTools } from "./standard.ts";
package/src/standard.ts CHANGED
@@ -497,13 +497,10 @@ async function csvWrite(
497
497
  columns: unknown,
498
498
  ): Promise<ToolResult> {
499
499
  if (!Array.isArray(rows)) throw new Error("rows must be an array of objects");
500
- const safeRows = (rows as Record<string, unknown>[]).map((row) =>
501
- Object.fromEntries(Object.entries(row).map(([key, value]) => [key, neutralizeFormula(value)])),
500
+ const content = csvText(
501
+ rows as Record<string, unknown>[],
502
+ Array.isArray(columns) ? (columns as string[]) : undefined,
502
503
  );
503
- const content = stringify(safeRows, {
504
- header: true,
505
- ...(Array.isArray(columns) && { columns: columns as string[] }),
506
- });
507
504
  const after = await writeText(ctx, path, content);
508
505
  return {
509
506
  content: [{ type: "text", text: `wrote ${rows.length} rows to ${after.path}` }],
@@ -790,6 +787,17 @@ function failure(message: string): ToolResult {
790
787
  * Spreadsheets run a cell that starts with =, +, @ or - as a formula. A leading apostrophe keeps
791
788
  * it text. Negative numbers are left alone.
792
789
  */
790
+ /**
791
+ * The rows of a csv_write as the file will read them, with the header and the formula guard.
792
+ * The screen shows this before a person approves a write, so both go through one function.
793
+ */
794
+ export function csvText(rows: Record<string, unknown>[], columns?: string[]): string {
795
+ const safeRows = rows.map((row) =>
796
+ Object.fromEntries(Object.entries(row).map(([key, value]) => [key, neutralizeFormula(value)])),
797
+ );
798
+ return stringify(safeRows, { header: true, ...(columns && { columns }) });
799
+ }
800
+
793
801
  function neutralizeFormula(value: unknown): unknown {
794
802
  if (typeof value !== "string") return value;
795
803
  return /^[=+@\t\r]/.test(value) || /^-(?![0-9.])/.test(value) ? `'${value}` : value;