@forwardimpact/basecamp 0.2.0 → 0.3.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/README.md CHANGED
@@ -54,14 +54,11 @@ To uninstall, run `/usr/local/share/basecamp/uninstall.sh`.
54
54
 
55
55
  ```bash
56
56
  cd apps/basecamp
57
- ./scripts/install.sh
57
+ ./scripts/init.sh
58
58
 
59
59
  # Configure your identity
60
60
  vi ~/Documents/Personal/USER.md
61
61
 
62
- # Start the daemon
63
- npx fit-basecamp --install-launchd
64
-
65
62
  # Open your KB interactively
66
63
  cd ~/Documents/Personal && claude
67
64
  ```
@@ -180,8 +177,6 @@ fit-basecamp Run due tasks once and exit
180
177
  fit-basecamp --daemon Run continuously (poll every 60s)
181
178
  fit-basecamp --run <task> Run a specific task immediately
182
179
  fit-basecamp --init <path> Initialize a new knowledge base
183
- fit-basecamp --install-launchd Install macOS LaunchAgent for auto-start
184
- fit-basecamp --uninstall-launchd Remove macOS LaunchAgent
185
180
  fit-basecamp --status Show knowledge bases and task status
186
181
  fit-basecamp --help Show this help
187
182
  ```
@@ -220,7 +215,7 @@ ships with these skills:
220
215
  ## Requirements
221
216
 
222
217
  - Claude CLI (`claude`) installed and authenticated
223
- - macOS (for Apple Mail/Calendar sync and launchd)
218
+ - macOS (for Apple Mail/Calendar sync)
224
219
  - Node.js >= 18 (for running from source) or the standalone binary
225
220
  - Deno >= 2.x (for building the standalone binary)
226
221
 
package/basecamp.js CHANGED
@@ -7,8 +7,6 @@
7
7
  // node basecamp.js --daemon Run continuously (poll every 60s)
8
8
  // node basecamp.js --run <task> Run a specific task immediately
9
9
  // node basecamp.js --init <path> Initialize a new knowledge base
10
- // node basecamp.js --install-launchd Install macOS LaunchAgent
11
- // node basecamp.js --uninstall-launchd Remove macOS LaunchAgent
12
10
  // node basecamp.js --validate Validate agents and skills exist
13
11
  // node basecamp.js --status Show task status
14
12
  // node basecamp.js --help Show this help
@@ -34,16 +32,10 @@ const BASECAMP_HOME = join(HOME, ".fit", "basecamp");
34
32
  const CONFIG_PATH = join(BASECAMP_HOME, "scheduler.json");
35
33
  const STATE_PATH = join(BASECAMP_HOME, "state.json");
36
34
  const LOG_DIR = join(BASECAMP_HOME, "logs");
37
- const PLIST_NAME = "com.fit-basecamp.scheduler";
38
- const PLIST_PATH = join(HOME, "Library", "LaunchAgents", `${PLIST_NAME}.plist`);
39
35
  const __dirname =
40
36
  import.meta.dirname || dirname(fileURLToPath(import.meta.url));
41
37
  const KB_TEMPLATE_DIR = join(__dirname, "template");
42
38
  const SOCKET_PATH = join(BASECAMP_HOME, "basecamp.sock");
43
- const IS_COMPILED =
44
- typeof Deno !== "undefined" &&
45
- Deno.execPath &&
46
- !Deno.execPath().endsWith("deno");
47
39
 
48
40
  let daemonStartedAt = null;
49
41
 
@@ -347,14 +339,7 @@ function handleStatusRequest(socket) {
347
339
 
348
340
  function handleRestartRequest(socket) {
349
341
  send(socket, { type: "ack", command: "restart" });
350
- const uid = execSync("id -u", { encoding: "utf8" }).trim();
351
- setTimeout(() => {
352
- try {
353
- execSync(`launchctl kickstart -k gui/${uid}/${PLIST_NAME}`);
354
- } catch {
355
- process.exit(0);
356
- }
357
- }, 100);
342
+ setTimeout(() => process.exit(0), 100);
358
343
  }
359
344
 
360
345
  function handleRunRequest(socket, taskName) {
@@ -498,69 +483,6 @@ function initKB(targetPath) {
498
483
  );
499
484
  }
500
485
 
501
- // --- LaunchAgent ------------------------------------------------------------
502
-
503
- function installLaunchd() {
504
- const execPath =
505
- typeof Deno !== "undefined" ? Deno.execPath() : process.execPath;
506
- const isCompiled = IS_COMPILED || !execPath.includes("node");
507
- const progArgs = isCompiled
508
- ? ` <string>${execPath}</string>\n <string>--daemon</string>`
509
- : ` <string>${execPath}</string>\n <string>${join(__dirname, "basecamp.js")}</string>\n <string>--daemon</string>`;
510
-
511
- const plist = `<?xml version="1.0" encoding="UTF-8"?>
512
- <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
513
- <plist version="1.0">
514
- <dict>
515
- <key>Label</key>
516
- <string>${PLIST_NAME}</string>
517
- <key>ProgramArguments</key>
518
- <array>
519
- ${progArgs}
520
- </array>
521
- <key>RunAtLoad</key>
522
- <true/>
523
- <key>KeepAlive</key>
524
- <true/>
525
- <key>StandardOutPath</key>
526
- <string>${join(LOG_DIR, "launchd-stdout.log")}</string>
527
- <key>StandardErrorPath</key>
528
- <string>${join(LOG_DIR, "launchd-stderr.log")}</string>
529
- <key>WorkingDirectory</key>
530
- <string>${BASECAMP_HOME}</string>
531
- <key>EnvironmentVariables</key>
532
- <dict>
533
- <key>PATH</key>
534
- <string>/usr/local/bin:/usr/bin:/bin:/opt/homebrew/bin:${join(HOME, ".local", "bin")}</string>
535
- </dict>
536
- </dict>
537
- </plist>`;
538
-
539
- ensureDir(dirname(PLIST_PATH));
540
- ensureDir(LOG_DIR);
541
- writeFileSync(PLIST_PATH, plist);
542
-
543
- try {
544
- execSync(`launchctl unload "${PLIST_PATH}" 2>/dev/null`, {
545
- stdio: "ignore",
546
- });
547
- } catch {}
548
- execSync(`launchctl load "${PLIST_PATH}"`);
549
- console.log(
550
- `LaunchAgent installed and loaded.\n Plist: ${PLIST_PATH}\n Logs: ${LOG_DIR}/\n Config: ${CONFIG_PATH}`,
551
- );
552
- }
553
-
554
- function uninstallLaunchd() {
555
- try {
556
- execSync(`launchctl unload "${PLIST_PATH}" 2>/dev/null`);
557
- } catch {}
558
- try {
559
- execSync(`rm -f "${PLIST_PATH}"`);
560
- } catch {}
561
- console.log("LaunchAgent uninstalled.");
562
- }
563
-
564
486
  // --- Status -----------------------------------------------------------------
565
487
 
566
488
  function showStatus() {
@@ -591,15 +513,6 @@ function showStatus() {
591
513
  if (s.lastError) lines.push(` Error: ${s.lastError.slice(0, 80)}`);
592
514
  console.log(lines.join("\n"));
593
515
  }
594
-
595
- try {
596
- execSync(`launchctl list 2>/dev/null | grep ${PLIST_NAME}`, {
597
- encoding: "utf8",
598
- });
599
- console.log("\nLaunchAgent: loaded");
600
- } catch {
601
- console.log("\nLaunchAgent: not loaded (run --install-launchd to start)");
602
- }
603
516
  }
604
517
 
605
518
  // --- Validate ---------------------------------------------------------------
@@ -680,8 +593,6 @@ Usage:
680
593
  ${bin} --daemon Run continuously (poll every 60s)
681
594
  ${bin} --run <task> Run a specific task immediately
682
595
  ${bin} --init <path> Initialize a new knowledge base
683
- ${bin} --install-launchd Install macOS LaunchAgent for auto-start
684
- ${bin} --uninstall-launchd Remove macOS LaunchAgent
685
596
  ${bin} --validate Validate agents and skills exist
686
597
  ${bin} --status Show task status
687
598
  ${bin} --help Show this help
@@ -719,8 +630,6 @@ const commands = {
719
630
  "--help": showHelp,
720
631
  "-h": showHelp,
721
632
  "--daemon": daemon,
722
- "--install-launchd": installLaunchd,
723
- "--uninstall-launchd": uninstallLaunchd,
724
633
  "--validate": validate,
725
634
  "--status": showStatus,
726
635
  "--init": () => {
package/build.js CHANGED
@@ -90,7 +90,7 @@ function buildPKG(statusMenuBinaryPath) {
90
90
 
91
91
  console.log(`\nBuilding pkg: ${pkgName}...`);
92
92
 
93
- const buildPkg = join(__dirname, "scripts", "build-pkg.sh");
93
+ const buildPkg = join(__dirname, "pkg", "macos", "build-pkg.sh");
94
94
  run(
95
95
  `"${buildPkg}" "${DIST_DIR}" "${APP_NAME}" "${VERSION}" "${statusMenuBinaryPath}"`,
96
96
  { cwd: __dirname },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@forwardimpact/basecamp",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Claude Code-native personal knowledge system with scheduled tasks",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -20,15 +20,12 @@
20
20
  "build": "deno run --allow-all build.js",
21
21
  "build:pkg": "deno run --allow-all build.js --pkg",
22
22
  "build:all": "deno run --allow-all build.js --all",
23
- "install:basecamp": "./scripts/install.sh",
24
- "scheduler:install": "node basecamp.js --install-launchd",
25
- "scheduler:uninstall": "node basecamp.js --uninstall-launchd"
23
+ "init": "./scripts/init.sh"
26
24
  },
27
25
  "files": [
28
26
  "basecamp.js",
29
27
  "build.js",
30
28
  "config/",
31
- "scripts/",
32
29
  "template/"
33
30
  ],
34
31
  "engines": {
@@ -1,115 +0,0 @@
1
- #!/bin/bash
2
- set -e
3
-
4
- # Build a macOS installer package (.pkg) for Basecamp (arm64).
5
- #
6
- # Uses pkgbuild (component) + productbuild (distribution) to create a .pkg
7
- # that installs the binary to /usr/local/bin/ and runs a postinstall script
8
- # to set up the LaunchAgent, config, and default knowledge base.
9
- #
10
- # Usage: build-pkg.sh <dist_dir> <app_name> <version> <status_menu_binary>
11
- # e.g. build-pkg.sh dist fit-basecamp 1.0.0 dist/BasecampStatus
12
-
13
- DIST_DIR="${1:?Usage: build-pkg.sh <dist_dir> <app_name> <version> <status_menu_binary>}"
14
- APP_NAME="${2:?Usage: build-pkg.sh <dist_dir> <app_name> <version> <status_menu_binary>}"
15
- VERSION="${3:?Usage: build-pkg.sh <dist_dir> <app_name> <version> <status_menu_binary>}"
16
- STATUS_MENU_BINARY="${4:?Usage: build-pkg.sh <dist_dir> <app_name> <version> <status_menu_binary>}"
17
-
18
- SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
19
- PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
20
- BINARY_PATH="$DIST_DIR/$APP_NAME"
21
- IDENTIFIER="com.fit-basecamp.scheduler"
22
-
23
- if [ ! -f "$BINARY_PATH" ]; then
24
- echo "Error: binary not found at $BINARY_PATH"
25
- echo "Run compile.sh first."
26
- exit 1
27
- fi
28
-
29
- PKG_NAME="$APP_NAME-$VERSION.pkg"
30
- PKG_PATH="$DIST_DIR/$PKG_NAME"
31
- PAYLOAD_DIR="$DIST_DIR/pkg-payload"
32
- SCRIPTS_DIR="$DIST_DIR/pkg-scripts"
33
- RESOURCES_DIR="$DIST_DIR/pkg-resources"
34
- COMPONENT_PKG="$DIST_DIR/pkg-component.pkg"
35
-
36
- echo ""
37
- echo "Building pkg: $PKG_NAME..."
38
-
39
- # --- Clean previous artifacts ------------------------------------------------
40
-
41
- rm -rf "$PAYLOAD_DIR" "$SCRIPTS_DIR" "$RESOURCES_DIR" "$COMPONENT_PKG"
42
- rm -f "$PKG_PATH"
43
-
44
- # --- Create payload (files to install) ---------------------------------------
45
-
46
- mkdir -p "$PAYLOAD_DIR/usr/local/bin"
47
- mkdir -p "$PAYLOAD_DIR/usr/local/share/fit-basecamp/config"
48
-
49
- cp "$BINARY_PATH" "$PAYLOAD_DIR/usr/local/bin/$APP_NAME"
50
- chmod +x "$PAYLOAD_DIR/usr/local/bin/$APP_NAME"
51
-
52
- cp "$PROJECT_DIR/config/scheduler.json" "$PAYLOAD_DIR/usr/local/share/fit-basecamp/config/scheduler.json"
53
- cp "$SCRIPT_DIR/uninstall.sh" "$PAYLOAD_DIR/usr/local/share/fit-basecamp/uninstall.sh"
54
- chmod +x "$PAYLOAD_DIR/usr/local/share/fit-basecamp/uninstall.sh"
55
-
56
- # Status menu binary
57
- cp "$STATUS_MENU_BINARY" "$PAYLOAD_DIR/usr/local/bin/BasecampStatus"
58
- chmod +x "$PAYLOAD_DIR/usr/local/bin/BasecampStatus"
59
-
60
- # --- Create scripts directory ------------------------------------------------
61
-
62
- mkdir -p "$SCRIPTS_DIR"
63
- cp "$SCRIPT_DIR/postinstall" "$SCRIPTS_DIR/postinstall"
64
- chmod +x "$SCRIPTS_DIR/postinstall"
65
-
66
- # --- Build component package -------------------------------------------------
67
-
68
- pkgbuild \
69
- --root "$PAYLOAD_DIR" \
70
- --scripts "$SCRIPTS_DIR" \
71
- --identifier "$IDENTIFIER" \
72
- --version "$VERSION" \
73
- --install-location "/" \
74
- "$COMPONENT_PKG"
75
-
76
- # --- Create distribution resources -------------------------------------------
77
-
78
- mkdir -p "$RESOURCES_DIR"
79
- cp "$SCRIPT_DIR/pkg-resources/welcome.html" "$RESOURCES_DIR/welcome.html"
80
- cp "$SCRIPT_DIR/pkg-resources/conclusion.html" "$RESOURCES_DIR/conclusion.html"
81
-
82
- # --- Create distribution.xml ------------------------------------------------
83
-
84
- DIST_XML="$DIST_DIR/distribution.xml"
85
- cat > "$DIST_XML" <<EOF
86
- <?xml version="1.0" encoding="utf-8"?>
87
- <installer-gui-script minSpecVersion="2">
88
- <title>Basecamp ${VERSION}</title>
89
- <welcome file="welcome.html" mime-type="text/html" />
90
- <conclusion file="conclusion.html" mime-type="text/html" />
91
- <options customize="never" require-scripts="false" hostArchitectures="arm64" />
92
- <domains enable_localSystem="true" />
93
- <pkg-ref id="$IDENTIFIER" version="$VERSION">pkg-component.pkg</pkg-ref>
94
- <choices-outline>
95
- <line choice="$IDENTIFIER" />
96
- </choices-outline>
97
- <choice id="$IDENTIFIER" visible="false">
98
- <pkg-ref id="$IDENTIFIER" />
99
- </choice>
100
- </installer-gui-script>
101
- EOF
102
-
103
- # --- Build distribution package ----------------------------------------------
104
-
105
- productbuild \
106
- --distribution "$DIST_XML" \
107
- --resources "$RESOURCES_DIR" \
108
- --package-path "$DIST_DIR" \
109
- "$PKG_PATH"
110
-
111
- # --- Clean up staging --------------------------------------------------------
112
-
113
- rm -rf "$PAYLOAD_DIR" "$SCRIPTS_DIR" "$RESOURCES_DIR" "$COMPONENT_PKG" "$DIST_XML"
114
-
115
- echo " -> $PKG_NAME"
@@ -1,25 +0,0 @@
1
- #!/bin/bash
2
- set -e
3
-
4
- # Compile Basecamp into a standalone Deno binary (arm64 macOS).
5
- #
6
- # Usage: compile.sh <dist_dir> <app_name>
7
- # e.g. compile.sh dist fit-basecamp
8
-
9
- DIST_DIR="${1:?Usage: compile.sh <dist_dir> <app_name>}"
10
- APP_NAME="${2:?Usage: compile.sh <dist_dir> <app_name>}"
11
-
12
- OUTPUT="$DIST_DIR/$APP_NAME"
13
-
14
- echo ""
15
- echo "Compiling $APP_NAME..."
16
- mkdir -p "$DIST_DIR"
17
-
18
- deno compile \
19
- --allow-all \
20
- --no-check \
21
- --output "$OUTPUT" \
22
- --include template/ \
23
- basecamp.js
24
-
25
- echo " -> $OUTPUT"
@@ -1,108 +0,0 @@
1
- #!/bin/bash
2
- set -e
3
-
4
- # Basecamp Installer (development / repo context)
5
- #
6
- # Sets up scheduler config, default knowledge base, and LaunchAgent for local
7
- # development. The compiled binary is installed via the .pkg installer instead.
8
- #
9
- # This script is for engineers running from the repo with deno or node.
10
-
11
- SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
12
- APP_NAME="fit-basecamp"
13
- BASECAMP_HOME="$HOME/.fit/basecamp"
14
- DEFAULT_KB="$HOME/Documents/Personal"
15
-
16
- echo ""
17
- echo "Basecamp Installer (dev)"
18
- echo "========================"
19
- echo ""
20
-
21
- # ---------------------------------------------------------------------------
22
- # 1. Set up scheduler home
23
- # ---------------------------------------------------------------------------
24
-
25
- echo "Setting up scheduler home at $BASECAMP_HOME ..."
26
- mkdir -p "$BASECAMP_HOME/logs"
27
-
28
- # ---------------------------------------------------------------------------
29
- # 2. Copy scheduler config (single source of truth: config/scheduler.json)
30
- # ---------------------------------------------------------------------------
31
-
32
- CONFIG_SRC=""
33
- if [ -f "$SCRIPT_DIR/../config/scheduler.json" ]; then
34
- CONFIG_SRC="$SCRIPT_DIR/../config/scheduler.json"
35
- fi
36
-
37
- if [ ! -f "$BASECAMP_HOME/scheduler.json" ]; then
38
- if [ -n "$CONFIG_SRC" ]; then
39
- cp "$CONFIG_SRC" "$BASECAMP_HOME/scheduler.json"
40
- echo " Created $BASECAMP_HOME/scheduler.json"
41
- else
42
- echo " Warning: config/scheduler.json not found, skipping config setup."
43
- fi
44
- else
45
- echo " Scheduler config already exists, skipping."
46
- fi
47
-
48
- # ---------------------------------------------------------------------------
49
- # 3. Initialize state file
50
- # ---------------------------------------------------------------------------
51
-
52
- if [ ! -f "$BASECAMP_HOME/state.json" ]; then
53
- echo '{ "tasks": {} }' > "$BASECAMP_HOME/state.json"
54
- echo " Created $BASECAMP_HOME/state.json"
55
- fi
56
-
57
- # ---------------------------------------------------------------------------
58
- # 4. Initialize default knowledge base
59
- # ---------------------------------------------------------------------------
60
-
61
- echo ""
62
- if [ ! -d "$DEFAULT_KB" ]; then
63
- echo "Initializing default knowledge base at $DEFAULT_KB ..."
64
- SCHEDULER="$SCRIPT_DIR/../basecamp.js"
65
- if command -v deno &>/dev/null && [ -f "$SCHEDULER" ]; then
66
- deno run --allow-all "$SCHEDULER" --init "$DEFAULT_KB"
67
- elif command -v node &>/dev/null && [ -f "$SCHEDULER" ]; then
68
- node "$SCHEDULER" --init "$DEFAULT_KB"
69
- else
70
- echo " Neither deno nor node found, skipping KB initialization."
71
- fi
72
- else
73
- echo "Basecamp already initialized at $DEFAULT_KB/"
74
- fi
75
-
76
- # ---------------------------------------------------------------------------
77
- # 5. Install LaunchAgent
78
- # ---------------------------------------------------------------------------
79
-
80
- echo ""
81
- echo "Installing background scheduler (LaunchAgent)..."
82
- SCHEDULER="$SCRIPT_DIR/../basecamp.js"
83
- if command -v deno &>/dev/null && [ -f "$SCHEDULER" ]; then
84
- deno run --allow-all "$SCHEDULER" --install-launchd
85
- elif command -v node &>/dev/null && [ -f "$SCHEDULER" ]; then
86
- node "$SCHEDULER" --install-launchd
87
- else
88
- echo " Neither deno nor node found, skipping LaunchAgent install."
89
- fi
90
-
91
- # ---------------------------------------------------------------------------
92
- # Summary
93
- # ---------------------------------------------------------------------------
94
-
95
- echo ""
96
- echo "Done! Basecamp is installed."
97
- echo ""
98
- echo " Config: $BASECAMP_HOME/scheduler.json"
99
- echo " Knowledge: $DEFAULT_KB/"
100
- echo " Logs: $BASECAMP_HOME/logs/"
101
- echo ""
102
- echo "Next steps:"
103
- echo " 1. Edit $DEFAULT_KB/USER.md with your name, email, and domain"
104
- echo " 2. Edit $BASECAMP_HOME/scheduler.json to configure tasks"
105
- echo " 3. Run the scheduler: deno run --allow-all basecamp.js --status"
106
- echo " 4. Start the daemon: deno run --allow-all basecamp.js --install-launchd"
107
- echo " 5. Open your KB: cd $DEFAULT_KB && claude"
108
- echo ""
@@ -1,62 +0,0 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <style>
5
- body {
6
- font-family:
7
- -apple-system,
8
- Helvetica Neue,
9
- sans-serif;
10
- padding: 20px;
11
- color: #1d1d1f;
12
- }
13
- h1 {
14
- font-size: 22px;
15
- font-weight: 600;
16
- margin-bottom: 16px;
17
- }
18
- p {
19
- font-size: 14px;
20
- line-height: 1.6;
21
- color: #424245;
22
- }
23
- code {
24
- font-family:
25
- SF Mono,
26
- Menlo,
27
- monospace;
28
- font-size: 13px;
29
- background: #f5f5f7;
30
- padding: 2px 6px;
31
- border-radius: 4px;
32
- }
33
- .cmd {
34
- margin: 8px 0 8px 16px;
35
- }
36
- .note {
37
- font-size: 12px;
38
- color: #86868b;
39
- margin-top: 20px;
40
- }
41
- </style>
42
- </head>
43
- <body>
44
- <h1>Basecamp is installed</h1>
45
- <p>
46
- The scheduler is running in the background and will start automatically on
47
- login.
48
- </p>
49
- <p><strong>Next steps:</strong></p>
50
- <p>1. Edit your identity file:</p>
51
- <p class="cmd"><code>vim ~/Documents/Personal/USER.md</code></p>
52
- <p>2. Configure scheduled tasks:</p>
53
- <p class="cmd"><code>vim ~/.fit/basecamp/scheduler.json</code></p>
54
- <p>3. Check scheduler status:</p>
55
- <p class="cmd"><code>fit-basecamp --status</code></p>
56
- <p>4. Open your knowledge base interactively:</p>
57
- <p class="cmd"><code>cd ~/Documents/Personal &amp;&amp; claude</code></p>
58
- <p class="note">
59
- To uninstall, run: <code>/usr/local/share/fit-basecamp/uninstall.sh</code>
60
- </p>
61
- </body>
62
- </html>
@@ -1,64 +0,0 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <style>
5
- body {
6
- font-family:
7
- -apple-system,
8
- Helvetica Neue,
9
- sans-serif;
10
- padding: 20px;
11
- color: #1d1d1f;
12
- }
13
- h1 {
14
- font-size: 22px;
15
- font-weight: 600;
16
- margin-bottom: 16px;
17
- }
18
- p {
19
- font-size: 14px;
20
- line-height: 1.6;
21
- color: #424245;
22
- }
23
- ul {
24
- font-size: 14px;
25
- line-height: 1.8;
26
- color: #424245;
27
- padding-left: 20px;
28
- }
29
- .note {
30
- font-size: 12px;
31
- color: #86868b;
32
- margin-top: 20px;
33
- }
34
- </style>
35
- </head>
36
- <body>
37
- <h1>Basecamp</h1>
38
- <p>
39
- Personal knowledge system with scheduled AI tasks. No server, no database.
40
- just plain files, markdown, and Claude Code.
41
- </p>
42
- <p>This installer will:</p>
43
- <ul>
44
- <li>
45
- Install the <code>fit-basecamp</code> binary to
46
- <code>/usr/local/bin/</code>
47
- </li>
48
- <li>
49
- Set up the scheduler configuration at <code>~/.fit/basecamp/</code>
50
- </li>
51
- <li>
52
- Initialize a default knowledge base at
53
- <code>~/Documents/Personal/</code>
54
- </li>
55
- <li>
56
- Install a LaunchAgent so the scheduler runs automatically on login
57
- </li>
58
- </ul>
59
- <p class="note">
60
- Requires the Claude Code CLI (<code>claude</code>) to be installed and
61
- authenticated.
62
- </p>
63
- </body>
64
- </html>
@@ -1,84 +0,0 @@
1
- #!/bin/bash
2
-
3
- # Basecamp postinstall script — runs as root after macOS pkg installation.
4
- #
5
- # Sets up per-user config, default knowledge base, and LaunchAgent for the
6
- # console user (the person who double-clicked the installer).
7
-
8
- REAL_USER=$(/usr/bin/stat -f "%Su" /dev/console)
9
- REAL_HOME=$(/usr/bin/dscl . -read "/Users/$REAL_USER" NFSHomeDirectory | /usr/bin/awk '{print $2}')
10
-
11
- BASECAMP_HOME="$REAL_HOME/.fit/basecamp"
12
- DEFAULT_KB="$REAL_HOME/Documents/Personal"
13
- SHARE_DIR="/usr/local/share/fit-basecamp"
14
- BINARY="/usr/local/bin/fit-basecamp"
15
- STATUS_MENU_BINARY="/usr/local/bin/BasecampStatus"
16
-
17
- # --- Config home -------------------------------------------------------------
18
-
19
- /usr/bin/sudo -u "$REAL_USER" /bin/mkdir -p "$BASECAMP_HOME/logs"
20
-
21
- if [ ! -f "$BASECAMP_HOME/scheduler.json" ] && [ -f "$SHARE_DIR/config/scheduler.json" ]; then
22
- /usr/bin/sudo -u "$REAL_USER" /bin/cp "$SHARE_DIR/config/scheduler.json" "$BASECAMP_HOME/scheduler.json"
23
- fi
24
-
25
- if [ ! -f "$BASECAMP_HOME/state.json" ]; then
26
- echo '{ "tasks": {} }' | /usr/bin/sudo -u "$REAL_USER" /usr/bin/tee "$BASECAMP_HOME/state.json" > /dev/null
27
- fi
28
-
29
- # --- Default knowledge base --------------------------------------------------
30
-
31
- if [ ! -d "$DEFAULT_KB" ]; then
32
- /usr/bin/sudo -u "$REAL_USER" "$BINARY" --init "$DEFAULT_KB" 2>/dev/null || true
33
- fi
34
-
35
- # --- LaunchAgent (runs as user, not root) ------------------------------------
36
-
37
- PLIST="$REAL_HOME/Library/LaunchAgents/com.fit-basecamp.scheduler.plist"
38
- if [ -f "$PLIST" ]; then
39
- # Upgrade: binary already replaced by pkg payload. Kill the old daemon and
40
- # let KeepAlive restart it with the new binary. No plist rewrite needed.
41
- /usr/bin/killall fit-basecamp 2>/dev/null || true
42
- else
43
- # Fresh install: create plist and load it.
44
- /usr/bin/sudo -u "$REAL_USER" "$BINARY" --install-launchd 2>/dev/null || true
45
- fi
46
-
47
- # --- Status menu LaunchAgent (runs as user, not root) -----------------------
48
-
49
- STATUS_PLIST="$REAL_HOME/Library/LaunchAgents/com.fit-basecamp.status-menu.plist"
50
-
51
- if [ -f "$STATUS_MENU_BINARY" ]; then
52
- # Kill old status menu if running (picks up new binary on relaunch)
53
- /usr/bin/killall BasecampStatus 2>/dev/null || true
54
-
55
- # Write LaunchAgent plist
56
- /usr/bin/sudo -u "$REAL_USER" /usr/bin/tee "$STATUS_PLIST" > /dev/null <<PLIST
57
- <?xml version="1.0" encoding="UTF-8"?>
58
- <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
59
- <plist version="1.0">
60
- <dict>
61
- <key>Label</key>
62
- <string>com.fit-basecamp.status-menu</string>
63
- <key>ProgramArguments</key>
64
- <array>
65
- <string>/usr/local/bin/BasecampStatus</string>
66
- </array>
67
- <key>RunAtLoad</key>
68
- <true/>
69
- <key>KeepAlive</key>
70
- <true/>
71
- <key>StandardOutPath</key>
72
- <string>$BASECAMP_HOME/logs/status-menu-stdout.log</string>
73
- <key>StandardErrorPath</key>
74
- <string>$BASECAMP_HOME/logs/status-menu-stderr.log</string>
75
- </dict>
76
- </plist>
77
- PLIST
78
-
79
- # Load the LaunchAgent (unload first for upgrades)
80
- /usr/bin/sudo -u "$REAL_USER" /usr/bin/launchctl unload "$STATUS_PLIST" 2>/dev/null || true
81
- /usr/bin/sudo -u "$REAL_USER" /usr/bin/launchctl load "$STATUS_PLIST"
82
- fi
83
-
84
- exit 0
@@ -1,73 +0,0 @@
1
- #!/bin/bash
2
- set -e
3
-
4
- # Basecamp Uninstaller
5
- #
6
- # Removes the binary, LaunchAgent, and shared data installed by the .pkg.
7
- # User data at ~/Documents/Personal/ and config at ~/.fit/basecamp/ are preserved.
8
-
9
- APP_NAME="${1:-fit-basecamp}"
10
- PLIST_NAME="${2:-com.fit-basecamp.scheduler}"
11
-
12
- echo ""
13
- echo "Basecamp Uninstaller"
14
- echo "====================="
15
- echo ""
16
-
17
- # Remove LaunchAgent
18
- PLIST="$HOME/Library/LaunchAgents/$PLIST_NAME.plist"
19
- if [ -f "$PLIST" ]; then
20
- launchctl unload "$PLIST" 2>/dev/null || true
21
- rm -f "$PLIST"
22
- echo " Removed LaunchAgent"
23
- else
24
- echo " LaunchAgent not found, skipping."
25
- fi
26
-
27
- # Remove status menu LaunchAgent
28
- STATUS_PLIST="$HOME/Library/LaunchAgents/com.fit-basecamp.status-menu.plist"
29
- if [ -f "$STATUS_PLIST" ]; then
30
- launchctl unload "$STATUS_PLIST" 2>/dev/null || true
31
- rm -f "$STATUS_PLIST"
32
- echo " Removed status menu LaunchAgent"
33
- fi
34
- killall BasecampStatus 2>/dev/null || true
35
- if [ -f "/usr/local/bin/BasecampStatus" ]; then
36
- sudo rm -f "/usr/local/bin/BasecampStatus"
37
- echo " Removed /usr/local/bin/BasecampStatus"
38
- fi
39
-
40
- # Remove stale socket file
41
- # Socket path: ~/.fit/basecamp/basecamp.sock (must match SOCKET_PATH in basecamp.js)
42
- rm -f "$HOME/.fit/basecamp/basecamp.sock"
43
-
44
- # Remove binary
45
- if [ -f "/usr/local/bin/$APP_NAME" ]; then
46
- sudo rm -f "/usr/local/bin/$APP_NAME"
47
- echo " Removed /usr/local/bin/$APP_NAME"
48
- else
49
- echo " Binary not found at /usr/local/bin/$APP_NAME, skipping."
50
- fi
51
-
52
- # Remove shared data (default config template, this uninstall script's installed copy)
53
- if [ -d "/usr/local/share/fit-basecamp" ]; then
54
- sudo rm -rf "/usr/local/share/fit-basecamp"
55
- echo " Removed /usr/local/share/fit-basecamp/"
56
- else
57
- echo " Shared data not found, skipping."
58
- fi
59
-
60
- # Forget pkg receipt
61
- pkgutil --pkgs 2>/dev/null | grep -q "com.fit-basecamp.scheduler" && {
62
- sudo pkgutil --forget "com.fit-basecamp.scheduler" >/dev/null 2>&1
63
- echo " Removed installer receipt"
64
- } || true
65
-
66
- echo ""
67
- echo "Basecamp uninstalled."
68
- echo "Your data at ~/Documents/Personal/ has been preserved."
69
- echo "Your config at ~/.fit/basecamp/ has been preserved."
70
- echo ""
71
- echo "To remove all data: rm -rf ~/Documents/Personal/"
72
- echo "To remove all config: rm -rf ~/.fit/basecamp/"
73
- echo ""