@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 +2 -7
- package/basecamp.js +1 -92
- package/build.js +1 -1
- package/package.json +2 -5
- package/scripts/build-pkg.sh +0 -115
- package/scripts/compile.sh +0 -25
- package/scripts/install.sh +0 -108
- package/scripts/pkg-resources/conclusion.html +0 -62
- package/scripts/pkg-resources/welcome.html +0 -64
- package/scripts/postinstall +0 -84
- package/scripts/uninstall.sh +0 -73
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/
|
|
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
|
|
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
|
-
|
|
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, "
|
|
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.
|
|
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
|
-
"
|
|
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": {
|
package/scripts/build-pkg.sh
DELETED
|
@@ -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"
|
package/scripts/compile.sh
DELETED
|
@@ -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"
|
package/scripts/install.sh
DELETED
|
@@ -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 && 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>
|
package/scripts/postinstall
DELETED
|
@@ -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
|
package/scripts/uninstall.sh
DELETED
|
@@ -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 ""
|