@lightupai/polaris 0.0.97 → 0.0.99
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/.github/workflows/ci.yml +0 -26
- package/package.json +1 -1
- package/skills/polaris/SKILL.md +1 -1
- package/src/cli/cli.ts +108 -14
- package/src/client/client.ts +1 -1
package/.github/workflows/ci.yml
CHANGED
|
@@ -43,32 +43,6 @@ jobs:
|
|
|
43
43
|
|
|
44
44
|
- run: bun test
|
|
45
45
|
|
|
46
|
-
publish:
|
|
47
|
-
needs: test
|
|
48
|
-
runs-on: ubuntu-latest
|
|
49
|
-
if: github.ref == 'refs/heads/master' && github.event_name == 'push'
|
|
50
|
-
|
|
51
|
-
steps:
|
|
52
|
-
- uses: actions/checkout@v4
|
|
53
|
-
|
|
54
|
-
- uses: oven-sh/setup-bun@v2
|
|
55
|
-
with:
|
|
56
|
-
bun-version: latest
|
|
57
|
-
|
|
58
|
-
- run: bun install
|
|
59
|
-
|
|
60
|
-
- name: Bump version from npm registry and publish
|
|
61
|
-
run: |
|
|
62
|
-
echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}" > .npmrc
|
|
63
|
-
PUBLISHED=$(npm view @lightupai/polaris version 2>/dev/null || echo "0.0.0")
|
|
64
|
-
# Bump patch from the latest published version
|
|
65
|
-
IFS='.' read -r MAJOR MINOR PATCH <<< "$PUBLISHED"
|
|
66
|
-
NEW="$MAJOR.$MINOR.$((PATCH + 1))"
|
|
67
|
-
echo "Published: $PUBLISHED → Publishing: $NEW"
|
|
68
|
-
# Set version in package.json for this publish only (not committed)
|
|
69
|
-
npm version "$NEW" --no-git-tag-version
|
|
70
|
-
npm publish --access public
|
|
71
|
-
|
|
72
46
|
deploy:
|
|
73
47
|
needs: test
|
|
74
48
|
runs-on: ubuntu-latest
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lightupai/polaris",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.99",
|
|
4
4
|
"description": "Record and stream Claude Code sessions to Slack. Like Gong for AI coding — capture every prompt, response, and tool call. Multiplayer collaboration across AI coding agents.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"claude-code",
|
package/skills/polaris/SKILL.md
CHANGED
|
@@ -47,6 +47,6 @@ Based on the arguments provided, do ONE of the following:
|
|
|
47
47
|
|
|
48
48
|
### Daemon
|
|
49
49
|
|
|
50
|
-
The Polaris daemon runs locally and is managed automatically — do NOT
|
|
50
|
+
The Polaris daemon runs locally and is managed automatically — do NOT manually configure launchd or systemd. If the user reports the daemon is down or not starting at login, tell them to run `polaris install` which sets up auto-restart (launchd on macOS, systemd user service on Linux).
|
|
51
51
|
|
|
52
52
|
### Arguments: $ARGUMENTS
|
package/src/cli/cli.ts
CHANGED
|
@@ -107,16 +107,13 @@ function appToApi(appUrl: string): string {
|
|
|
107
107
|
return appUrl.replace("app.", "api.");
|
|
108
108
|
}
|
|
109
109
|
|
|
110
|
-
// ---
|
|
110
|
+
// --- Daemon auto-restart (macOS: launchd, Linux: systemd user service) ---
|
|
111
111
|
|
|
112
|
+
// macOS: LaunchAgent
|
|
112
113
|
const LAUNCH_AGENT_LABEL = "ai.withpolaris.daemon";
|
|
113
114
|
const LAUNCH_AGENT_PLIST = join(homedir(), "Library", "LaunchAgents", `${LAUNCH_AGENT_LABEL}.plist`);
|
|
114
115
|
|
|
115
|
-
// Writes a runner script + launchd plist so the daemon survives crashes and
|
|
116
|
-
// starts automatically at login. No-op on non-macOS platforms.
|
|
117
116
|
async function installLaunchAgent(daemonSecret?: string): Promise<void> {
|
|
118
|
-
if (process.platform !== "darwin") return;
|
|
119
|
-
|
|
120
117
|
const binDir = join(POLARIS_DIR, "bin");
|
|
121
118
|
const runnerPath = join(binDir, "run-daemon.sh");
|
|
122
119
|
const daemonTsPath = join(
|
|
@@ -175,11 +172,108 @@ async function installLaunchAgent(daemonSecret?: string): Promise<void> {
|
|
|
175
172
|
}
|
|
176
173
|
|
|
177
174
|
async function removeLaunchAgent(): Promise<void> {
|
|
178
|
-
if (process.platform !== "darwin") return;
|
|
179
175
|
Bun.spawnSync(["launchctl", "unload", "-w", LAUNCH_AGENT_PLIST], { stdout: "ignore", stderr: "ignore" });
|
|
180
176
|
try { await rm(LAUNCH_AGENT_PLIST); } catch { /* already gone */ }
|
|
181
177
|
}
|
|
182
178
|
|
|
179
|
+
// Linux: systemd user service
|
|
180
|
+
const SYSTEMD_SERVICE_NAME = "polaris-daemon";
|
|
181
|
+
const SYSTEMD_USER_DIR = join(homedir(), ".config", "systemd", "user");
|
|
182
|
+
const SYSTEMD_SERVICE_FILE = join(SYSTEMD_USER_DIR, `${SYSTEMD_SERVICE_NAME}.service`);
|
|
183
|
+
|
|
184
|
+
async function installSystemdService(daemonSecret?: string): Promise<void> {
|
|
185
|
+
// Resolve bun's absolute path at install time so systemd's minimal PATH
|
|
186
|
+
// doesn't matter. Bun.which() searches PATH; process.execPath is the
|
|
187
|
+
// interpreter we're already running under — use whichever looks like bun.
|
|
188
|
+
const bunPath = Bun.which("bun") ?? process.execPath;
|
|
189
|
+
|
|
190
|
+
const binDir = join(POLARIS_DIR, "bin");
|
|
191
|
+
const runnerPath = join(binDir, "run-daemon.sh");
|
|
192
|
+
const daemonTsPath = join(
|
|
193
|
+
POLARIS_DIR, "mcp", "node_modules", "@lightupai", "polaris", "src", "daemon", "daemon.ts"
|
|
194
|
+
);
|
|
195
|
+
|
|
196
|
+
await mkdir(binDir, { recursive: true });
|
|
197
|
+
// Bun path is baked in at install time — no runtime search needed
|
|
198
|
+
const runner = [
|
|
199
|
+
"#!/bin/sh",
|
|
200
|
+
`# Polaris daemon — managed by systemd (${SYSTEMD_SERVICE_NAME}.service)`,
|
|
201
|
+
`# bun path resolved at install time: ${bunPath}`,
|
|
202
|
+
`exec "${bunPath}" run "${daemonTsPath}"`,
|
|
203
|
+
].join("\n") + "\n";
|
|
204
|
+
await writeFile(runnerPath, runner);
|
|
205
|
+
await chmod(runnerPath, 0o755);
|
|
206
|
+
|
|
207
|
+
const secretLine = daemonSecret ? `Environment=POLARIS_DAEMON_SECRET=${daemonSecret}\n` : "";
|
|
208
|
+
const unit = `[Unit]
|
|
209
|
+
Description=Polaris daemon
|
|
210
|
+
After=network.target
|
|
211
|
+
|
|
212
|
+
[Service]
|
|
213
|
+
Type=simple
|
|
214
|
+
ExecStart=${runnerPath}
|
|
215
|
+
Restart=always
|
|
216
|
+
RestartSec=5
|
|
217
|
+
${secretLine}StandardOutput=append:/tmp/polaris-daemon.log
|
|
218
|
+
StandardError=append:/tmp/polaris-daemon.log
|
|
219
|
+
|
|
220
|
+
[Install]
|
|
221
|
+
WantedBy=default.target
|
|
222
|
+
`;
|
|
223
|
+
|
|
224
|
+
await mkdir(SYSTEMD_USER_DIR, { recursive: true });
|
|
225
|
+
await writeFile(SYSTEMD_SERVICE_FILE, unit);
|
|
226
|
+
|
|
227
|
+
// Stop any existing manually-started daemon so it releases port 4322
|
|
228
|
+
// before systemd takes over
|
|
229
|
+
await killExistingDaemon();
|
|
230
|
+
|
|
231
|
+
// Reload unit files, enable (start-at-login) and start/restart the service
|
|
232
|
+
Bun.spawnSync(["systemctl", "--user", "daemon-reload"], { stdout: "ignore", stderr: "ignore" });
|
|
233
|
+
Bun.spawnSync(["systemctl", "--user", "enable", SYSTEMD_SERVICE_NAME], { stdout: "ignore", stderr: "ignore" });
|
|
234
|
+
Bun.spawnSync(["systemctl", "--user", "restart", SYSTEMD_SERVICE_NAME], { stdout: "ignore", stderr: "ignore" });
|
|
235
|
+
|
|
236
|
+
// Verify the service came up
|
|
237
|
+
const check = Bun.spawnSync(["systemctl", "--user", "is-active", SYSTEMD_SERVICE_NAME], { stdout: "pipe", stderr: "ignore" });
|
|
238
|
+
if (check.stdout.toString().trim() !== "active") {
|
|
239
|
+
console.error(` Warning: daemon service did not start. Check logs:`);
|
|
240
|
+
const journal = Bun.spawnSync(
|
|
241
|
+
["journalctl", "--user", "-u", SYSTEMD_SERVICE_NAME, "-n", "10", "--no-pager"],
|
|
242
|
+
{ stdout: "pipe", stderr: "ignore" }
|
|
243
|
+
);
|
|
244
|
+
console.error(journal.stdout.toString().trim());
|
|
245
|
+
console.error(` Try manually: systemctl --user restart ${SYSTEMD_SERVICE_NAME}`);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// Enable lingering so the user service survives logout and starts at boot
|
|
249
|
+
// (best-effort — requires sudo-less loginctl or appropriate privileges)
|
|
250
|
+
Bun.spawnSync(["loginctl", "enable-linger"], { stdout: "ignore", stderr: "ignore" });
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
async function removeSystemdService(): Promise<void> {
|
|
254
|
+
Bun.spawnSync(["systemctl", "--user", "disable", "--now", SYSTEMD_SERVICE_NAME], { stdout: "ignore", stderr: "ignore" });
|
|
255
|
+
try { await rm(SYSTEMD_SERVICE_FILE); } catch { /* already gone */ }
|
|
256
|
+
Bun.spawnSync(["systemctl", "--user", "daemon-reload"], { stdout: "ignore", stderr: "ignore" });
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// Platform dispatcher
|
|
260
|
+
async function installDaemonService(daemonSecret?: string): Promise<void> {
|
|
261
|
+
if (process.platform === "darwin") return installLaunchAgent(daemonSecret);
|
|
262
|
+
if (process.platform === "linux") return installSystemdService(daemonSecret);
|
|
263
|
+
// Windows and others: no managed service; daemon is started manually
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
async function removeDaemonService(): Promise<void> {
|
|
267
|
+
if (process.platform === "darwin") return removeLaunchAgent();
|
|
268
|
+
if (process.platform === "linux") return removeSystemdService();
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
function daemonServiceLabel(): string {
|
|
272
|
+
if (process.platform === "darwin") return "launchd (auto-restarts on crash, starts at login)";
|
|
273
|
+
if (process.platform === "linux") return "systemd user service (auto-restarts on crash, starts at login)";
|
|
274
|
+
return "background process";
|
|
275
|
+
}
|
|
276
|
+
|
|
183
277
|
// --- Daemon secret ---
|
|
184
278
|
|
|
185
279
|
// Shared local secret for daemon HTTP auth. Stored in ~/.polaris/config.json
|
|
@@ -347,7 +441,7 @@ Based on the arguments provided, do ONE of the following:
|
|
|
347
441
|
|
|
348
442
|
### Daemon
|
|
349
443
|
|
|
350
|
-
The Polaris daemon runs locally and is managed automatically — do NOT
|
|
444
|
+
The Polaris daemon runs locally and is managed automatically — do NOT manually configure launchd or systemd. If the user reports the daemon is down or not starting at login, tell them to run \`polaris install\` which sets up auto-restart (launchd on macOS, systemd user service on Linux).
|
|
351
445
|
|
|
352
446
|
### Arguments: $ARGUMENTS
|
|
353
447
|
`;
|
|
@@ -859,7 +953,7 @@ async function recover() {
|
|
|
859
953
|
|
|
860
954
|
async function logout(all = false) {
|
|
861
955
|
if (all) {
|
|
862
|
-
await
|
|
956
|
+
await removeDaemonService();
|
|
863
957
|
try {
|
|
864
958
|
await rm(POLARIS_DIR, { recursive: true });
|
|
865
959
|
console.log("All profiles and credentials removed.");
|
|
@@ -962,8 +1056,8 @@ switch (command) {
|
|
|
962
1056
|
case "install":
|
|
963
1057
|
console.log("Polaris — installing local components\n");
|
|
964
1058
|
await install();
|
|
965
|
-
await
|
|
966
|
-
console.log(
|
|
1059
|
+
await installDaemonService(await ensureDaemonSecret());
|
|
1060
|
+
console.log(` ✓ Daemon registered with ${daemonServiceLabel()}`);
|
|
967
1061
|
console.log("\nInstall complete.");
|
|
968
1062
|
break;
|
|
969
1063
|
|
|
@@ -973,8 +1067,8 @@ switch (command) {
|
|
|
973
1067
|
console.log("Polaris — authenticating\n");
|
|
974
1068
|
await login(appUrl, profileName);
|
|
975
1069
|
console.log("\n✓ Login complete!");
|
|
976
|
-
await
|
|
977
|
-
console.log(
|
|
1070
|
+
await installDaemonService(await ensureDaemonSecret());
|
|
1071
|
+
console.log(` ✓ Daemon registered with ${daemonServiceLabel()}`);
|
|
978
1072
|
|
|
979
1073
|
console.log("\nNext: restart Claude Code, then run `/polaris join #channel-name` in your AI agent.");
|
|
980
1074
|
break;
|
|
@@ -1027,8 +1121,8 @@ switch (command) {
|
|
|
1027
1121
|
console.log("[2/2] Authenticating...\n");
|
|
1028
1122
|
await login(DEFAULT_APP_URL);
|
|
1029
1123
|
console.log("\n✓ Polaris is set up on this machine!");
|
|
1030
|
-
await
|
|
1031
|
-
console.log(
|
|
1124
|
+
await installDaemonService(await ensureDaemonSecret());
|
|
1125
|
+
console.log(` ✓ Daemon registered with ${daemonServiceLabel()}`);
|
|
1032
1126
|
|
|
1033
1127
|
console.log("\nNext: restart Claude Code, then run `/polaris join #channel-name` in your AI agent.");
|
|
1034
1128
|
break;
|
package/src/client/client.ts
CHANGED
|
@@ -102,7 +102,7 @@ const mcp = new Server(
|
|
|
102
102
|
},
|
|
103
103
|
instructions: `You are connected to Polaris — a multiplayer collaboration system. Messages from advisors and teammates may arrive as <channel source="polaris" from="..."> tags. Use /polaris commands to manage your session, or call the polaris tools directly.
|
|
104
104
|
|
|
105
|
-
If the user reports the Polaris daemon is not running or keeps crashing, tell them to run \`polaris install\` — it registers the daemon with launchd
|
|
105
|
+
If the user reports the Polaris daemon is not running or keeps crashing, tell them to run \`polaris install\` — it registers the daemon with launchd on macOS or a systemd user service on Linux for auto-restart on crash and at login. Do NOT suggest manually configuring launchd or systemd — \`polaris install\` handles it.`,
|
|
106
106
|
}
|
|
107
107
|
);
|
|
108
108
|
|