mirror of
https://github.com/hansjone/dsh-im-ops.git
synced 2026-10-20 17:23:20 +08:00
110 lines
3.9 KiB
JavaScript
110 lines
3.9 KiB
JavaScript
import { isAbsolute } from 'node:path';
|
|
|
|
const MAX_SESSION_ID_LENGTH = 256;
|
|
const UNSAFE_SESSION_ID = /[\p{White_Space}\p{Cc}\p{Cf}\p{Zl}\p{Zp}]/u;
|
|
const UNSAFE_WORKSPACE_PATH = /[\p{Cc}\p{Cf}\p{Zl}\p{Zp}]/u;
|
|
|
|
function bindingError(code, message) {
|
|
const error = new Error(message);
|
|
error.code = code;
|
|
return error;
|
|
}
|
|
|
|
function validatedSessionId(value) {
|
|
if (typeof value !== 'string' || !value || value.length > MAX_SESSION_ID_LENGTH
|
|
|| UNSAFE_SESSION_ID.test(value)) {
|
|
throw bindingError('session-id-invalid', 'A non-empty, safe session id is required');
|
|
}
|
|
return value;
|
|
}
|
|
|
|
function sessionWorkspace(sessionId, value) {
|
|
if (!Array.isArray(value?.items) || !Array.isArray(value?.archivedSessionIds)
|
|
|| value.archivedSessionIds.some((id) => typeof id !== 'string' || !id)) {
|
|
throw new Error('Harness returned an invalid response for workspace.list');
|
|
}
|
|
|
|
const owners = [];
|
|
for (const workspace of value.items) {
|
|
if (typeof workspace?.workspaceId !== 'string' || !workspace.workspaceId
|
|
|| typeof workspace.path !== 'string' || !isAbsolute(workspace.path)
|
|
|| !Array.isArray(workspace.sessionIds)
|
|
|| workspace.sessionIds.some((id) => typeof id !== 'string' || !id)) {
|
|
throw new Error('Harness returned an invalid response for workspace.list');
|
|
}
|
|
for (const accountedId of workspace.sessionIds) {
|
|
if (accountedId === sessionId) owners.push(workspace);
|
|
}
|
|
}
|
|
|
|
if (owners.length === 0) {
|
|
throw bindingError('session-not-registered', 'The session is not registered to a Harness workspace');
|
|
}
|
|
if (owners.length !== 1) {
|
|
throw bindingError(
|
|
'session-workspace-ambiguous',
|
|
'The session is registered to more than one Harness workspace',
|
|
);
|
|
}
|
|
if (UNSAFE_WORKSPACE_PATH.test(owners[0].path)) {
|
|
throw new Error('Harness returned an unsafe workspace path for the session');
|
|
}
|
|
return {
|
|
workspace: owners[0],
|
|
archived: value.archivedSessionIds.includes(sessionId),
|
|
};
|
|
}
|
|
|
|
function sessionSummary(sessionId, value) {
|
|
if (!Array.isArray(value?.items)
|
|
|| value.items.some((item) => typeof item?.sessionId !== 'string' || !item.sessionId)) {
|
|
throw new Error('Harness returned an invalid response for session.list');
|
|
}
|
|
const matches = value.items.filter((item) => item.sessionId === sessionId);
|
|
if (matches.length === 0) {
|
|
throw bindingError('session-summary-unavailable', 'The session is no longer available from Harness');
|
|
}
|
|
if (matches.length !== 1) {
|
|
throw new Error('Harness returned duplicate session summaries for session.list');
|
|
}
|
|
|
|
const [summary] = matches;
|
|
if (summary.origin === 'subagent') {
|
|
throw bindingError(
|
|
'session-subagent-unsupported',
|
|
'Subagent sessions cannot be adopted as a bot conversation',
|
|
);
|
|
}
|
|
if (summary.origin !== undefined) {
|
|
throw new Error('Harness returned an invalid session origin for session.list');
|
|
}
|
|
const title = summary.projections?.values?.title;
|
|
if (title !== undefined && title !== null && typeof title !== 'string') {
|
|
throw new Error('Harness returned an invalid session title for session.list');
|
|
}
|
|
return { title: typeof title === 'string' ? title : null };
|
|
}
|
|
|
|
export async function adoptRegisteredWorkspaceSession(client, value, options = {}, timeoutMs = 30_000) {
|
|
const sessionId = validatedSessionId(value);
|
|
await client.ensureRunning(options);
|
|
const workspaceList = await client.rpc('workspace.list', {}, timeoutMs, options);
|
|
const { workspace, archived } = sessionWorkspace(sessionId, workspaceList);
|
|
const summary = sessionSummary(
|
|
sessionId,
|
|
await client.rpc('session.list', {}, timeoutMs, options),
|
|
);
|
|
const adopted = await client.rpc('session.create', {
|
|
workspaceId: workspace.workspaceId,
|
|
sessionId,
|
|
}, timeoutMs, options);
|
|
if (!adopted || adopted.sessionId !== sessionId) {
|
|
throw new Error('Harness returned an invalid response for session.create');
|
|
}
|
|
return {
|
|
sessionId,
|
|
workspace: workspace.path,
|
|
title: summary.title,
|
|
archived,
|
|
};
|
|
}
|