fix: Teams user-id prefix + defer cli:local owner grant

parseUserId now falls back to user.kind when the id prefix isn't a
registered adapter — Teams uses `29:` rather than `teams:`, so the
literal prefix wouldn't resolve the channel adapter for cold DMs.

init-cli-agent no longer claims the first-owner slot on `cli:local`.
The CLI identity is scratch; owner promotion belongs to
init-first-agent once the real channel user is wired.
This commit is contained in:
gavrielc
2026-04-21 10:16:13 +03:00
parent 212fc1f1b5
commit d8d61d3695
2 changed files with 12 additions and 18 deletions
+3 -12
View File
@@ -30,7 +30,6 @@ import {
} from '../src/db/messaging-groups.js';
import { runMigrations } from '../src/db/migrations/index.js';
import { normalizeName } from '../src/modules/agent-to-agent/db/agent-destinations.js';
import { grantRole, hasAnyOwner } from '../src/modules/permissions/db/user-roles.js';
import { upsertUser } from '../src/modules/permissions/db/users.js';
import { initGroupFilesystem } from '../src/group-init.js';
import type { AgentGroup, MessagingGroup } from '../src/types.js';
@@ -91,17 +90,9 @@ async function main(): Promise<void> {
created_at: now,
});
let promotedToOwner = false;
if (!hasAnyOwner()) {
grantRole({
user_id: CLI_SYNTHETIC_USER_ID,
role: 'owner',
agent_group_id: null,
granted_by: null,
granted_at: now,
});
promotedToOwner = true;
}
// Owner grant deferred to init-first-agent when the real channel user is
// wired — cli:local is a scratch identity, not the operator.
const promotedToOwner = false;
// 2. Agent group + filesystem.
const folder = `cli-with-${normalizeName(args.displayName)}`;
+9 -6
View File
@@ -136,11 +136,14 @@ async function resolveDmPlatformId(channelType: string, handle: string): Promise
function parseUserId(user: User): { channelType: string; handle: string } | { channelType: null; handle: null } {
const idx = user.id.indexOf(':');
if (idx < 0) return { channelType: null, handle: null };
const channelType = user.id.slice(0, idx);
const prefix = user.id.slice(0, idx);
const handle = user.id.slice(idx + 1);
if (!channelType || !handle) return { channelType: null, handle: null };
// The `kind` on users mirrors the channel_type prefix in our current
// scheme. Pull it from `user.kind` if we ever decouple them later, but
// today the id prefix is authoritative.
return { channelType, handle };
if (!prefix || !handle) return { channelType: null, handle: null };
// Teams user IDs use a `29:` prefix, not `teams:`. When the id prefix
// isn't a registered adapter, fall back to user.kind and treat the full
// id as the handle.
if (!getChannelAdapter(prefix) && user.kind && getChannelAdapter(user.kind)) {
return { channelType: user.kind, handle: user.id };
}
return { channelType: prefix, handle };
}