@forwardimpact/basecamp 2.9.2 → 2.9.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.
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@forwardimpact/basecamp",
|
|
3
|
-
"version": "2.9.
|
|
3
|
+
"version": "2.9.3",
|
|
4
4
|
"description": "Claude Code-native personal knowledge system with autonomous agents",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"node": ">=18.0.0"
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"
|
|
33
|
+
"read-excel-file": "^7.0.3"
|
|
34
34
|
},
|
|
35
35
|
"publishConfig": {
|
|
36
36
|
"access": "public"
|
|
@@ -28,9 +28,9 @@ Run this skill:
|
|
|
28
28
|
|
|
29
29
|
- A Workday requisition export file (`.xlsx`) accessible on the filesystem
|
|
30
30
|
(typically in `~/Downloads/`)
|
|
31
|
-
- The `
|
|
31
|
+
- The `read-excel-file` npm package installed in the KB root:
|
|
32
32
|
```bash
|
|
33
|
-
npm install
|
|
33
|
+
npm install read-excel-file
|
|
34
34
|
```
|
|
35
35
|
- User identity configured in `USER.md`
|
|
36
36
|
|
|
@@ -135,9 +135,9 @@ Names may include parenthetical annotations:
|
|
|
135
135
|
|
|
136
136
|
1. Read `USER.md` to get the user's name, email, and domain.
|
|
137
137
|
2. Confirm the XLSX file path with the user (or use the provided path).
|
|
138
|
-
3. Ensure the `
|
|
138
|
+
3. Ensure the `read-excel-file` package is installed:
|
|
139
139
|
```bash
|
|
140
|
-
npm list
|
|
140
|
+
npm list read-excel-file 2>/dev/null || npm install read-excel-file
|
|
141
141
|
```
|
|
142
142
|
|
|
143
143
|
## Step 1: Parse the Export
|
|
@@ -19,11 +19,9 @@
|
|
|
19
19
|
* node scripts/parse-workday.mjs <path-to-xlsx> --summary
|
|
20
20
|
* node scripts/parse-workday.mjs -h|--help
|
|
21
21
|
*
|
|
22
|
-
* Requires: npm install
|
|
22
|
+
* Requires: npm install read-excel-file
|
|
23
23
|
*/
|
|
24
24
|
|
|
25
|
-
import { readFileSync } from "node:fs";
|
|
26
|
-
|
|
27
25
|
if (
|
|
28
26
|
process.argv.includes("-h") ||
|
|
29
27
|
process.argv.includes("--help") ||
|
|
@@ -39,16 +37,16 @@ Usage:
|
|
|
39
37
|
Output (JSON):
|
|
40
38
|
{ requisition: { id, title, ... }, candidates: [ { name, ... }, ... ] }
|
|
41
39
|
|
|
42
|
-
Requires: npm install
|
|
40
|
+
Requires: npm install read-excel-file`);
|
|
43
41
|
process.exit(process.argv.length < 3 ? 1 : 0);
|
|
44
42
|
}
|
|
45
43
|
|
|
46
|
-
let
|
|
44
|
+
let readXlsxFile;
|
|
47
45
|
try {
|
|
48
|
-
|
|
46
|
+
readXlsxFile = (await import("read-excel-file/node")).default;
|
|
49
47
|
} catch {
|
|
50
48
|
console.error(
|
|
51
|
-
"Error:
|
|
49
|
+
"Error: read-excel-file package not found. Install it first:\n npm install read-excel-file",
|
|
52
50
|
);
|
|
53
51
|
process.exit(1);
|
|
54
52
|
}
|
|
@@ -56,13 +54,20 @@ try {
|
|
|
56
54
|
const filePath = process.argv[2];
|
|
57
55
|
const summaryMode = process.argv.includes("--summary");
|
|
58
56
|
|
|
59
|
-
|
|
60
|
-
|
|
57
|
+
/** Read a sheet by number (1-indexed) or name, returning rows as arrays of strings. */
|
|
58
|
+
async function readSheet(file, sheet) {
|
|
59
|
+
const rows = await readXlsxFile(file, { sheet });
|
|
60
|
+
// Normalise null cells to empty strings to match previous behaviour
|
|
61
|
+
return rows.map((row) => row.map((cell) => (cell == null ? "" : cell)));
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Get sheet names to find the candidates sheet
|
|
65
|
+
const sheets = await readXlsxFile(filePath, { getSheets: true });
|
|
66
|
+
const sheetNames = sheets.map((s) => s.name);
|
|
61
67
|
|
|
62
68
|
// --- Sheet 1: Requisition metadata ---
|
|
63
69
|
|
|
64
|
-
const
|
|
65
|
-
const sheet1Rows = XLSX.utils.sheet_to_json(ws1, { header: 1, defval: "" });
|
|
70
|
+
const sheet1Rows = await readSheet(filePath, 1);
|
|
66
71
|
|
|
67
72
|
/** Extract the requisition ID and title from the header row. */
|
|
68
73
|
function parseReqHeader(headerText) {
|
|
@@ -113,10 +118,9 @@ const requisition = {
|
|
|
113
118
|
// - Old format: 3+ sheets, candidates on a sheet named "Candidates" or Sheet3
|
|
114
119
|
// - New format: 2 sheets, candidates on Sheet2
|
|
115
120
|
const candSheetName =
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
const
|
|
119
|
-
const candRows = XLSX.utils.sheet_to_json(ws3, { header: 1, defval: "" });
|
|
121
|
+
sheetNames.find((n) => n.toLowerCase() === "candidates") ||
|
|
122
|
+
sheetNames[Math.min(2, sheetNames.length - 1)];
|
|
123
|
+
const candRows = await readSheet(filePath, candSheetName);
|
|
120
124
|
|
|
121
125
|
// Find the header row dynamically — look for a row containing "Stage"
|
|
122
126
|
// Old format: row 3 (index 2). New format: row 8 (index 7).
|
|
@@ -199,7 +203,7 @@ function parseName(raw) {
|
|
|
199
203
|
const match = name.match(/^(.+?)\s*\(([^)]+)\)\s*$/);
|
|
200
204
|
if (match) {
|
|
201
205
|
const annotation = match[2].trim();
|
|
202
|
-
let ie
|
|
206
|
+
let ie;
|
|
203
207
|
if (/prior\s*worker/i.test(annotation)) ie = "External (Prior Worker)";
|
|
204
208
|
else if (/internal/i.test(annotation)) ie = "Internal";
|
|
205
209
|
else ie = annotation;
|