@forwardimpact/basecamp 2.9.2 → 2.9.4

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.2",
3
+ "version": "2.9.4",
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
- "xlsx": "^0.18.5"
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 `xlsx` npm package installed in the KB root:
31
+ - The `read-excel-file` npm package installed in the KB root:
32
32
  ```bash
33
- npm install xlsx
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 `xlsx` package is installed:
138
+ 3. Ensure the `read-excel-file` package is installed:
139
139
  ```bash
140
- npm list xlsx 2>/dev/null || npm install xlsx
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 xlsx
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 xlsx`);
40
+ Requires: npm install read-excel-file`);
43
41
  process.exit(process.argv.length < 3 ? 1 : 0);
44
42
  }
45
43
 
46
- let XLSX;
44
+ let readXlsxFile;
47
45
  try {
48
- XLSX = await import("xlsx");
46
+ readXlsxFile = (await import("read-excel-file/node")).default;
49
47
  } catch {
50
48
  console.error(
51
- "Error: xlsx package not found. Install it first:\n npm install xlsx",
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
- const data = readFileSync(filePath);
60
- const wb = XLSX.read(data, { type: "buffer", cellDates: true });
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 ws1 = wb.Sheets[wb.SheetNames[0]];
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
- wb.SheetNames.find((n) => n.toLowerCase() === "candidates") ||
117
- wb.SheetNames[Math.min(2, wb.SheetNames.length - 1)];
118
- const ws3 = wb.Sheets[candSheetName];
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;
package/README.md DELETED
@@ -1,229 +0,0 @@
1
- # @forwardimpact/basecamp
2
-
3
- A personal knowledge system that runs as scheduled Claude Code tasks. No server,
4
- no database — just plain files, markdown, and the `claude` CLI. Packaged as a
5
- native macOS app bundle (`Basecamp.app`) with TCC-compliant process management.
6
-
7
- Part of the [Forward Impact](https://www.forwardimpact.team) monorepo.
8
-
9
- ## Architecture
10
-
11
- ```
12
- Basecamp.app/ # macOS app bundle
13
- └── Contents/
14
- ├── Info.plist # Bundle metadata (LSUIElement)
15
- ├── MacOS/
16
- │ ├── Basecamp # Swift launcher (TCC responsible)
17
- │ └── fit-basecamp # Deno scheduler (child process)
18
- └── Resources/
19
- ├── config/scheduler.json # Default config
20
- └── template/ # KB template
21
-
22
- ~/.fit/basecamp/ # Scheduler home (user config)
23
- ├── scheduler.json # Task definitions
24
- ├── state.json # Task run state
25
- ├── basecamp.sock # IPC socket
26
- └── logs/ # Scheduler logs
27
-
28
- ~/Documents/Personal/ # Default personal knowledge base
29
- ├── CLAUDE.md # Claude Code instructions for this KB
30
- ├── knowledge/ # The knowledge graph
31
- │ ├── People/
32
- │ ├── Organizations/
33
- │ ├── Projects/
34
- │ └── Topics/
35
- ├── .claude/skills/ # Claude Code skill files
36
- └── drafts/ # Email drafts
37
- ```
38
-
39
- ### Process Tree
40
-
41
- ```
42
- Basecamp (Swift launcher, CFBundleExecutable, TCC responsible)
43
- ├── fit-basecamp --daemon (Deno scheduler, spawned via posix_spawn)
44
- │ └── claude --print ... (spawned via posix_spawn FFI)
45
- └── [status menu UI] (AppKit menu bar, in-process)
46
- ```
47
-
48
- The Swift launcher is the main executable and TCC responsible process. It spawns
49
- the Deno scheduler via `posix_spawn` so child processes inherit TCC attributes.
50
- Users grant Calendar, Contacts, and other permissions once to Basecamp.app.
51
-
52
- ## Install from Package
53
-
54
- 1. Double-click `fit-basecamp-<version>.pkg`
55
- 2. Follow the installer prompts
56
-
57
- The installer places `Basecamp.app` in `/Applications/` and initializes
58
- `~/Documents/Personal/` as the default knowledge base.
59
-
60
- After installing, open Basecamp from `/Applications/`. It runs as a menu bar app
61
- — use "Quit Basecamp" from the status menu to stop it.
62
-
63
- To uninstall, run `just uninstall` from the source tree.
64
-
65
- ## Install from Source
66
-
67
- ```bash
68
- cd products/basecamp
69
-
70
- # Run the scheduler in dev mode
71
- just daemon
72
-
73
- # Or initialize a new KB
74
- just init ~/Documents/Personal
75
-
76
- # Configure your identity
77
- vi ~/Documents/Personal/USER.md
78
- ```
79
-
80
- ## Building
81
-
82
- Requires [Deno](https://deno.com) >= 2.x and Xcode Command Line Tools.
83
-
84
- ```bash
85
- # Build scheduler + launcher binaries
86
- just build
87
-
88
- # Build + assemble Basecamp.app
89
- just build-app
90
-
91
- # Build + assemble + .pkg installer
92
- just pkg
93
-
94
- # Or via npm:
95
- npm run build # binaries only
96
- npm run build:app # + Basecamp.app
97
- npm run build:pkg # + .pkg installer
98
- ```
99
-
100
- Output goes to `dist/`:
101
-
102
- ```
103
- dist/
104
- ├── fit-basecamp # Deno scheduler binary
105
- ├── Basecamp # Swift launcher binary
106
- └── Basecamp.app/ # Assembled app bundle
107
- ```
108
-
109
- ## Multiple Knowledge Bases
110
-
111
- The scheduler can run tasks across multiple knowledge bases. Each KB is an
112
- independent directory with its own CLAUDE.md, skills, and knowledge graph.
113
-
114
- ### Adding a new KB
115
-
116
- ```bash
117
- # Initialize a new knowledge base
118
- deno run --allow-all src/basecamp.js --init ~/Documents/Team
119
-
120
- # Edit the scheduler config to register it
121
- vi ~/.fit/basecamp/scheduler.json
122
- ```
123
-
124
- ### Scheduler config format
125
-
126
- `~/.fit/basecamp/scheduler.json`:
127
-
128
- ```json
129
- {
130
- "tasks": {
131
- "sync-personal-mail": {
132
- "kb": "~/Documents/Personal",
133
- "schedule": { "type": "interval", "minutes": 5 },
134
- "enabled": true,
135
- "skill": "sync-apple-mail",
136
- "prompt": "Sync Apple Mail."
137
- },
138
- "sync-team-calendar": {
139
- "kb": "~/Documents/Team",
140
- "schedule": { "type": "interval", "minutes": 10 },
141
- "enabled": true,
142
- "skill": "sync-apple-calendar",
143
- "prompt": "Sync Apple Calendar."
144
- }
145
- }
146
- }
147
- ```
148
-
149
- ### Task fields
150
-
151
- | Field | Required | Description |
152
- | ---------- | -------- | --------------------------------------------------------------- |
153
- | `kb` | yes | Path to the knowledge base directory (supports `~`) |
154
- | `schedule` | yes | When to run (`interval`, `cron`, or `once`) |
155
- | `prompt` | yes | The prompt sent to Claude |
156
- | `enabled` | no | Set to `false` to disable. Default: `true` |
157
- | `agent` | no | Claude sub-agent name (passed as `--agent`) |
158
- | `skill` | no | Skill name (matches `.claude/skills/<name>/SKILL.md` in the KB) |
159
-
160
- ### Schedule types
161
-
162
- ```json
163
- { "type": "interval", "minutes": 5 }
164
- { "type": "cron", "expression": "0 8 * * *" }
165
- { "type": "once", "runAt": "2025-02-12T10:00:00Z" }
166
- ```
167
-
168
- ## Updating
169
-
170
- When you upgrade Basecamp (install a new `.pkg`), the installer automatically
171
- runs `--update` on all configured knowledge bases. This pushes the latest
172
- `CLAUDE.md`, skills, and agents into each KB without touching your data.
173
-
174
- You can also run it manually at any time:
175
-
176
- ```bash
177
- # Update all configured knowledge bases
178
- /Applications/Basecamp.app/Contents/MacOS/fit-basecamp --update
179
-
180
- # Update a specific knowledge base
181
- /Applications/Basecamp.app/Contents/MacOS/fit-basecamp --update ~/Documents/Personal
182
- ```
183
-
184
- The update merges `.claude/settings.json` non-destructively — new entries are
185
- added but your existing permissions are preserved.
186
-
187
- ## CLI Reference
188
-
189
- ```
190
- fit-basecamp Run due tasks once and exit
191
- fit-basecamp --daemon Run continuously (poll every 60s)
192
- fit-basecamp --run <task> Run a specific task immediately
193
- fit-basecamp --init <path> Initialize a new knowledge base
194
- fit-basecamp --update [path] Update KB skills, agents, and CLAUDE.md
195
- fit-basecamp --status Show knowledge bases and task status
196
- fit-basecamp --validate Validate agents and skills exist
197
- fit-basecamp --help Show this help
198
- ```
199
-
200
- When running from source, use `deno run --allow-all src/basecamp.js` or
201
- `just run` instead of `fit-basecamp`.
202
-
203
- ## Skills
204
-
205
- Skills are Claude Code-native `SKILL.md` files that are auto-discovered from
206
- `.claude/skills/<name>/SKILL.md` inside each knowledge base. The default KB
207
- ships with these skills:
208
-
209
- | Skill | Directory | Purpose |
210
- | ---------------------- | ---------------------- | ---------------------------------------------- |
211
- | Sync Apple Mail | `sync-apple-mail` | Sync Apple Mail threads via SQLite |
212
- | Sync Apple Calendar | `sync-apple-calendar` | Sync Apple Calendar events via SQLite |
213
- | Extract Entities | `extract-entities` | Process synced data into knowledge graph notes |
214
- | Draft Emails | `draft-emails` | Draft email responses using knowledge context |
215
- | Meeting Prep | `meeting-prep` | Prepare briefings for upcoming meetings |
216
- | Create Presentations | `create-presentations` | Create slide decks as PDF |
217
- | Document Collaboration | `doc-collab` | Document creation and collaboration |
218
- | Organize Files | `organize-files` | File organization and cleanup |
219
-
220
- ## Requirements
221
-
222
- - Claude CLI (`claude`) installed and authenticated
223
- - macOS 13+ (Ventura or later)
224
- - Xcode Command Line Tools (for building the Swift launcher)
225
- - Deno >= 2.x (for building the standalone binary)
226
-
227
- ## License
228
-
229
- Apache-2.0