@lightupai/polaris 0.0.36 → 0.0.38

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": "@lightupai/polaris",
3
- "version": "0.0.36",
3
+ "version": "0.0.38",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "polaris": "bin/polaris",
@@ -267,17 +267,22 @@ mcp.setRequestHandler(CallToolRequestSchema, async (req) => {
267
267
  try {
268
268
  const res = await daemonGet("/team");
269
269
  if (res.ok) {
270
- const body = await res.json() as { members: Array<{ name: string; participant_id: string; slack_id: string | null; slack_handle: string | null; slack_display: string | null }> };
270
+ const body = await res.json() as { members: Array<{ name: string; participant_id: string | null; slack_id: string | null; slack_handle: string | null; slack_display: string | null; polaris_user: boolean; alias: string | null }> };
271
271
  if (body.members.length === 0) {
272
272
  return { content: [{ type: "text", text: "No team members found." }] };
273
273
  }
274
- const list = body.members
275
- .filter((m) => m.slack_id) // only show members with Slack identity
276
- .map((m) => ` @${m.slack_handle ?? m.slack_display} — ${m.name} [${m.slack_id}]`)
274
+ const taggable = body.members.filter((m) => m.slack_id && m.slack_handle);
275
+ const list = taggable
276
+ .map((m) => {
277
+ const shortAlias = m.alias && m.alias !== m.slack_handle ? `@${m.alias}` : "";
278
+ const handle = `@${m.slack_handle}`;
279
+ const display = shortAlias ? `${shortAlias} (${handle})` : handle;
280
+ return ` ${display} — ${m.name}${m.polaris_user ? " ✓" : ""} [${m.slack_id}]`;
281
+ })
277
282
  .join("\n");
278
- const unlinked = body.members.filter((m) => !m.slack_id);
279
- const unlinkedNote = unlinked.length > 0 ? `\n\nNot linked to Slack: ${unlinked.map(m => m.name).join(", ")}` : "";
280
- return { content: [{ type: "text", text: `Team members (use @handle to tag):\n${list}${unlinkedNote}` }] };
283
+ const notTaggable = body.members.filter((m) => !m.slack_id);
284
+ const note = notTaggable.length > 0 ? `\n\nNot on Slack: ${notTaggable.map(m => m.name).join(", ")}` : "";
285
+ return { content: [{ type: "text", text: `Team (use @alias or @handle to tag, ✓ = Polaris user):\n${list}${note}` }] };
281
286
  }
282
287
  return { content: [{ type: "text", text: "Failed to fetch team list." }] };
283
288
  } catch {
@@ -472,23 +472,56 @@ export async function startServer(opts: {
472
472
  } catch { /* Slack API unavailable */ }
473
473
  }
474
474
 
475
- // Join Polaris users with Slack members by email (most reliable)
476
- const team = users.map((u) => {
477
- const slack = slackMembers.find((m) => m.email.toLowerCase() === u.email.toLowerCase())
478
- ?? slackMembers.find((m) =>
479
- m.name.toLowerCase() === u.name.toLowerCase() ||
480
- m.display_name.toLowerCase() === u.name.toLowerCase().replace(/\s+/g, ".")
481
- );
475
+ // Build team from ALL Slack workspace members, annotate with Polaris identity
476
+ const matchedEmails = new Set<string>();
477
+ const team = slackMembers.map((m) => {
478
+ const polarisUser = users.find((u) => u.email.toLowerCase() === m.email.toLowerCase())
479
+ ?? users.find((u) => u.name.toLowerCase() === m.name.toLowerCase());
480
+ if (polarisUser) matchedEmails.add(polarisUser.email.toLowerCase());
482
481
  return {
483
- name: u.name,
484
- participant_id: u.participant_id,
485
- email: u.email,
486
- slack_id: slack?.id ?? null,
487
- slack_handle: slack?.username || null,
488
- slack_display: slack?.display_name || slack?.name || null,
482
+ name: m.name || m.display_name || m.username,
483
+ slack_id: m.id,
484
+ slack_handle: m.username,
485
+ slack_display: m.display_name || m.name,
486
+ participant_id: polarisUser?.participant_id ?? null,
487
+ polaris_user: !!polarisUser,
489
488
  };
490
489
  });
491
490
 
491
+ // Add Polaris users not in Slack (e.g., synthetic test users)
492
+ for (const u of users) {
493
+ if (!matchedEmails.has(u.email.toLowerCase())) {
494
+ team.push({
495
+ name: u.name,
496
+ slack_id: null,
497
+ slack_handle: null,
498
+ slack_display: null,
499
+ participant_id: u.participant_id,
500
+ polaris_user: true,
501
+ });
502
+ }
503
+ }
504
+
505
+ // Generate short aliases from first name, disambiguate collisions
506
+ const aliasCounts = new Map<string, number>();
507
+ for (const m of team) {
508
+ const firstName = m.name.split(/\s+/)[0]?.toLowerCase().replace(/[^a-z]/g, "") || "";
509
+ if (firstName) aliasCounts.set(firstName, (aliasCounts.get(firstName) ?? 0) + 1);
510
+ }
511
+ for (const m of team) {
512
+ const parts = m.name.split(/\s+/);
513
+ const firstName = parts[0]?.toLowerCase().replace(/[^a-z]/g, "") || "";
514
+ if (!firstName) {
515
+ (m as Record<string, unknown>).alias = null;
516
+ } else if ((aliasCounts.get(firstName) ?? 0) > 1 && parts.length > 1) {
517
+ // Collision — append first letter of last name
518
+ const lastInitial = parts[parts.length - 1]?.[0]?.toLowerCase() ?? "";
519
+ (m as Record<string, unknown>).alias = `${firstName}${lastInitial}`;
520
+ } else {
521
+ (m as Record<string, unknown>).alias = firstName;
522
+ }
523
+ }
524
+
492
525
  return json({ members: team });
493
526
  }
494
527