@lightupai/polaris 0.0.26 → 0.0.28
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/deploy.sh +1 -1
- package/docker/Caddyfile +2 -2
- package/docker-compose.prod.yml +2 -2
- package/docs/deploy-hetzner.md +9 -9
- package/package.json +1 -1
- package/skills/polaris/SKILL.md +5 -5
- package/src/cli/cli.ts +9 -9
- package/src/client/client.ts +5 -4
- package/src/daemon/daemon.ts +1 -1
- package/src/web/views.ts +2 -2
- package/tests/web.test.ts +2 -2
package/deploy.sh
CHANGED
package/docker/Caddyfile
CHANGED
package/docker-compose.prod.yml
CHANGED
|
@@ -41,10 +41,10 @@ services:
|
|
|
41
41
|
WEB_PORT: 3000
|
|
42
42
|
GOOGLE_CLIENT_ID: ${GOOGLE_CLIENT_ID}
|
|
43
43
|
GOOGLE_CLIENT_SECRET: ${GOOGLE_CLIENT_SECRET}
|
|
44
|
-
GOOGLE_REDIRECT_URI: https://app.
|
|
44
|
+
GOOGLE_REDIRECT_URI: https://app.withpolaris.ai/auth/google/callback
|
|
45
45
|
SLACK_CLIENT_ID: ${SLACK_CLIENT_ID}
|
|
46
46
|
SLACK_CLIENT_SECRET: ${SLACK_CLIENT_SECRET}
|
|
47
|
-
SLACK_REDIRECT_URI: https://app.
|
|
47
|
+
SLACK_REDIRECT_URI: https://app.withpolaris.ai/slack/callback
|
|
48
48
|
depends_on:
|
|
49
49
|
postgres:
|
|
50
50
|
condition: service_healthy
|
package/docs/deploy-hetzner.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
Polaris runs entirely on localhost. We need a production deployment so the API, web dashboard, Slack bridge, and Postgres all run on a Hetzner Cloud VPS with proper HTTPS. The daemon and MCP client stay local on each developer's machine — they talk to the cloud API.
|
|
6
6
|
|
|
7
|
-
Domain: `
|
|
7
|
+
Domain: `withpolaris.ai` (subdomains: `api.withpolaris.ai`, `app.withpolaris.ai`)
|
|
8
8
|
|
|
9
9
|
## Architecture
|
|
10
10
|
|
|
@@ -25,7 +25,7 @@ Domain: `polaris.lightup.ai` (subdomains: `api.polaris.lightup.ai`, `app.polaris
|
|
|
25
25
|
| File | Purpose |
|
|
26
26
|
|------|---------|
|
|
27
27
|
| `docker/Dockerfile` | Single Bun image, each service overrides CMD |
|
|
28
|
-
| `docker/Caddyfile` | Reverse proxy: app.
|
|
28
|
+
| `docker/Caddyfile` | Reverse proxy: app.withpolaris.ai → web:3000, api.withpolaris.ai → api:4321 |
|
|
29
29
|
| `docker/bridge-entrypoint.sh` | Wait for Postgres, discover org ID, start bridge |
|
|
30
30
|
| `src/bridge-discover-org.ts` | Tiny script: query DB for Slack-connected org ID |
|
|
31
31
|
| `docker-compose.prod.yml` | Full production orchestration |
|
|
@@ -58,11 +58,11 @@ CMD ["bun", "run", "src/service/server.ts"]
|
|
|
58
58
|
## Caddy Config
|
|
59
59
|
|
|
60
60
|
```
|
|
61
|
-
app.
|
|
61
|
+
app.withpolaris.ai {
|
|
62
62
|
reverse_proxy web:3000
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
-
api.
|
|
65
|
+
api.withpolaris.ai {
|
|
66
66
|
reverse_proxy api:4321
|
|
67
67
|
}
|
|
68
68
|
```
|
|
@@ -84,16 +84,16 @@ Caddy auto-provisions Let's Encrypt certs. WebSocket upgrades pass through trans
|
|
|
84
84
|
3. Create deploy user, add SSH key
|
|
85
85
|
4. Clone repo to `/opt/polaris`
|
|
86
86
|
5. Create `.env` with production secrets
|
|
87
|
-
6. DNS: A records for `api.
|
|
88
|
-
7. Update Google OAuth + Slack redirect URIs to `https://app.
|
|
87
|
+
6. DNS: A records for `api.withpolaris.ai` and `app.withpolaris.ai` → VPS IP
|
|
88
|
+
7. Update Google OAuth + Slack redirect URIs to `https://app.withpolaris.ai/...`
|
|
89
89
|
8. Firewall: allow 80, 443, 22 only
|
|
90
90
|
9. `docker compose -f docker-compose.prod.yml up -d`
|
|
91
91
|
|
|
92
92
|
## Verification
|
|
93
93
|
|
|
94
94
|
1. `docker compose -f docker-compose.prod.yml up --build` locally — all services start
|
|
95
|
-
2. `curl https://api.
|
|
96
|
-
3. `https://app.
|
|
95
|
+
2. `curl https://api.withpolaris.ai/status` returns `{"ok":true}`
|
|
96
|
+
3. `https://app.withpolaris.ai` loads login page
|
|
97
97
|
4. Google SSO login works end-to-end
|
|
98
98
|
5. Slack bridge connects and posts to channels
|
|
99
|
-
6. Local daemon connects to `https://api.
|
|
99
|
+
6. Local daemon connects to `https://api.withpolaris.ai` and events flow
|
package/package.json
CHANGED
package/skills/polaris/SKILL.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: polaris
|
|
3
3
|
description: Connect to a Polaris multiplayer collaboration session
|
|
4
4
|
allowed-tools: polaris_connect polaris_disconnect polaris_status polaris_reply polaris_context polaris_rename
|
|
5
|
-
argument-hint: [join
|
|
5
|
+
argument-hint: [join #channel | rename <new-name> | disconnect | (no args for status)]
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
## Polaris — Multiplayer Collaboration
|
|
@@ -13,12 +13,12 @@ Manage your connection to a Polaris collaboration session.
|
|
|
13
13
|
|
|
14
14
|
Based on the arguments provided, do ONE of the following:
|
|
15
15
|
|
|
16
|
-
**`/polaris join
|
|
17
|
-
1. Call `polaris_connect` with the given
|
|
18
|
-
2. A session name is auto-generated
|
|
16
|
+
**`/polaris join #channel-name`** — Connect to a channel:
|
|
17
|
+
1. Call `polaris_connect` with the given channel and user identity `user:manu.bansal`
|
|
18
|
+
2. A session name is auto-generated
|
|
19
19
|
3. Report the connection status including the session name
|
|
20
20
|
|
|
21
|
-
**`/polaris rename <new-name>`** — Rename the current
|
|
21
|
+
**`/polaris rename <new-name>`** — Rename the current channel:
|
|
22
22
|
1. Call `polaris_rename` with the new name
|
|
23
23
|
2. Report the result
|
|
24
24
|
|
package/src/cli/cli.ts
CHANGED
|
@@ -22,7 +22,7 @@ const CONFIG_FILE = join(POLARIS_DIR, "config.json");
|
|
|
22
22
|
const LEGACY_CREDENTIALS_FILE = join(POLARIS_DIR, "credentials.json");
|
|
23
23
|
const CLAUDE_DIR = join(homedir(), ".claude");
|
|
24
24
|
|
|
25
|
-
const DEFAULT_APP_URL = "https://app.
|
|
25
|
+
const DEFAULT_APP_URL = "https://app.withpolaris.ai";
|
|
26
26
|
const LOCAL_APP_URL = "http://localhost:3000";
|
|
27
27
|
|
|
28
28
|
// --- Config ---
|
|
@@ -88,8 +88,8 @@ function deriveProfileName(appUrl: string): string {
|
|
|
88
88
|
if (appUrl.includes("localhost") || appUrl.includes("127.0.0.1")) return "local";
|
|
89
89
|
try {
|
|
90
90
|
const host = new URL(appUrl).hostname;
|
|
91
|
-
// app.
|
|
92
|
-
if (host.includes("
|
|
91
|
+
// app.withpolaris.ai → prod
|
|
92
|
+
if (host.includes("withpolaris.ai")) return "prod";
|
|
93
93
|
// strip common prefixes
|
|
94
94
|
return host.replace(/^app\./, "").replace(/\./g, "-");
|
|
95
95
|
} catch {
|
|
@@ -183,7 +183,7 @@ async function install(participantId?: string) {
|
|
|
183
183
|
name: polaris
|
|
184
184
|
description: Connect to a Polaris multiplayer collaboration session
|
|
185
185
|
allowed-tools: polaris_connect polaris_disconnect polaris_status polaris_reply polaris_context polaris_rename
|
|
186
|
-
argument-hint: [join
|
|
186
|
+
argument-hint: [join #channel | rename <new-name> | disconnect | (no args for status)]
|
|
187
187
|
---
|
|
188
188
|
|
|
189
189
|
## Polaris — Multiplayer Collaboration
|
|
@@ -194,7 +194,7 @@ Manage your connection to a Polaris collaboration session.
|
|
|
194
194
|
|
|
195
195
|
Based on the arguments provided, do ONE of the following:
|
|
196
196
|
|
|
197
|
-
**\`/polaris join
|
|
197
|
+
**\`/polaris join #channel-name\`** — Connect to a channel:
|
|
198
198
|
1. Call \`polaris_connect\` with the given project and user identity ${identity}
|
|
199
199
|
2. A session name is auto-generated
|
|
200
200
|
3. Report the connection status including the session name
|
|
@@ -315,7 +315,7 @@ async function login(appUrl: string, profileName?: string) {
|
|
|
315
315
|
name: polaris
|
|
316
316
|
description: Connect to a Polaris multiplayer collaboration session
|
|
317
317
|
allowed-tools: polaris_connect polaris_disconnect polaris_status polaris_reply polaris_context polaris_rename
|
|
318
|
-
argument-hint: [join
|
|
318
|
+
argument-hint: [join #channel | rename <new-name> | disconnect | (no args for status)]
|
|
319
319
|
---
|
|
320
320
|
|
|
321
321
|
## Polaris — Multiplayer Collaboration
|
|
@@ -326,7 +326,7 @@ Manage your connection to a Polaris collaboration session.
|
|
|
326
326
|
|
|
327
327
|
Based on the arguments provided, do ONE of the following:
|
|
328
328
|
|
|
329
|
-
**\`/polaris join
|
|
329
|
+
**\`/polaris join #channel-name\`** — Connect to a channel:
|
|
330
330
|
1. Call \`polaris_connect\` with the given project and user identity ${identity}
|
|
331
331
|
2. A session name is auto-generated
|
|
332
332
|
3. Report the connection status including the session name
|
|
@@ -533,7 +533,7 @@ switch (command) {
|
|
|
533
533
|
}).unref?.();
|
|
534
534
|
console.log(" ✓ Daemon started in background");
|
|
535
535
|
|
|
536
|
-
console.log("\nNext: restart Claude Code, then run `/polaris join
|
|
536
|
+
console.log("\nNext: restart Claude Code, then run `/polaris join #channel-name` in your AI agent.");
|
|
537
537
|
break;
|
|
538
538
|
}
|
|
539
539
|
|
|
@@ -579,7 +579,7 @@ switch (command) {
|
|
|
579
579
|
}).unref?.();
|
|
580
580
|
console.log(" ✓ Daemon started in background");
|
|
581
581
|
|
|
582
|
-
console.log("\nNext: restart Claude Code, then run `/polaris join
|
|
582
|
+
console.log("\nNext: restart Claude Code, then run `/polaris join #channel-name` in your AI agent.");
|
|
583
583
|
break;
|
|
584
584
|
|
|
585
585
|
default:
|
package/src/client/client.ts
CHANGED
|
@@ -53,12 +53,12 @@ mcp.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
|
53
53
|
inputSchema: {
|
|
54
54
|
type: "object" as const,
|
|
55
55
|
properties: {
|
|
56
|
-
|
|
56
|
+
channel: { type: "string", description: "Channel name (e.g., #polaris-dev or polaris-dev)" },
|
|
57
57
|
user: { type: "string", description: "Your participant ID (e.g., user:manu)" },
|
|
58
58
|
session: { type: "string", description: "Session name (optional — auto-generated if omitted)" },
|
|
59
59
|
agent: { type: "string", description: "Agent identity (optional — defaults to agent:claude)" },
|
|
60
60
|
},
|
|
61
|
-
required: ["
|
|
61
|
+
required: ["channel", "user"],
|
|
62
62
|
},
|
|
63
63
|
},
|
|
64
64
|
{
|
|
@@ -117,7 +117,8 @@ mcp.setRequestHandler(CallToolRequestSchema, async (req) => {
|
|
|
117
117
|
const { name, arguments: args } = req.params;
|
|
118
118
|
|
|
119
119
|
if (name === "polaris_connect") {
|
|
120
|
-
const {
|
|
120
|
+
const { channel, user, session, agent } = args as { channel: string; user: string; session?: string; agent?: string };
|
|
121
|
+
const project = channel.replace(/^#/, ""); // strip leading # if present
|
|
121
122
|
try {
|
|
122
123
|
const res = await daemonPost("/connect", {
|
|
123
124
|
ccSessionId: CC_SESSION_ID,
|
|
@@ -131,7 +132,7 @@ mcp.setRequestHandler(CallToolRequestSchema, async (req) => {
|
|
|
131
132
|
currentProject = body.project ?? project;
|
|
132
133
|
currentSession = body.session ?? session ?? "";
|
|
133
134
|
currentUser = user;
|
|
134
|
-
return { content: [{ type: "text", text: `Connected to
|
|
135
|
+
return { content: [{ type: "text", text: `Connected to #${currentProject}/${currentSession} as ${user}.` }] };
|
|
135
136
|
}
|
|
136
137
|
return { content: [{ type: "text", text: `Failed to connect: ${body.error ?? "unknown error"}` }] };
|
|
137
138
|
} catch {
|
package/src/daemon/daemon.ts
CHANGED
|
@@ -53,7 +53,7 @@ function getServiceUrl(): string {
|
|
|
53
53
|
return cachedConfig.profiles[cachedConfig.active].api;
|
|
54
54
|
}
|
|
55
55
|
// 3. Fallback
|
|
56
|
-
return "https://api.
|
|
56
|
+
return "https://api.withpolaris.ai";
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
let cachedToken: string | null | undefined = undefined;
|
package/src/web/views.ts
CHANGED
|
@@ -208,7 +208,7 @@ function renderProjectsSessionsSection(ctx: ViewContext, sessions: SessionFixtur
|
|
|
208
208
|
<summary class="text-xs text-polaris-700 hover:text-polaris-800 font-medium cursor-pointer select-none">+ Join another session</summary>
|
|
209
209
|
<div class="mt-2 bg-white border border-gray-200 rounded-lg p-4">
|
|
210
210
|
<p class="text-sm text-gray-500">Inside your AI agent, run:</p>
|
|
211
|
-
${copyBlock("/polaris join
|
|
211
|
+
${copyBlock("/polaris join #channel-name")}
|
|
212
212
|
</div>
|
|
213
213
|
</details>
|
|
214
214
|
<div class="space-y-4">
|
|
@@ -231,7 +231,7 @@ function renderProjectsSessionsSection(ctx: ViewContext, sessions: SessionFixtur
|
|
|
231
231
|
: "Inside your AI agent (Claude Code, Cursor, etc.), run:"}</p>
|
|
232
232
|
${ctx.hasConnectedSession
|
|
233
233
|
? ""
|
|
234
|
-
: copyBlock("/polaris join my-
|
|
234
|
+
: copyBlock("/polaris join #my-channel")}
|
|
235
235
|
</div>
|
|
236
236
|
</div>`);
|
|
237
237
|
}
|
package/tests/web.test.ts
CHANGED
|
@@ -38,7 +38,7 @@ describe("renderSetupView", () => {
|
|
|
38
38
|
// Install CLI command is present
|
|
39
39
|
expect(html).toContain("npx @lightupai/polaris");
|
|
40
40
|
// Connect session command is present
|
|
41
|
-
expect(html).toContain("/polaris join my-
|
|
41
|
+
expect(html).toContain("/polaris join #my-channel");
|
|
42
42
|
});
|
|
43
43
|
|
|
44
44
|
test("slack done: floor shows connected, devices is highlighted, sessions grayed", () => {
|
|
@@ -66,7 +66,7 @@ describe("renderSetupView", () => {
|
|
|
66
66
|
const lastHighlight = html.lastIndexOf("border-polaris-300");
|
|
67
67
|
expect(lastHighlight).toBeGreaterThan(sessIdx);
|
|
68
68
|
// Connect session command present
|
|
69
|
-
expect(html).toContain("/polaris join my-
|
|
69
|
+
expect(html).toContain("/polaris join #my-channel");
|
|
70
70
|
});
|
|
71
71
|
|
|
72
72
|
test("includes nav with user info", () => {
|