mirror of
https://github.com/qwibitai/nanoclaw.git
synced 2026-06-04 10:14:47 +08:00
Merge pull request #2313 from alipgoldberg/setup/teams-step-gate-back
setup: add back-to-channels exit at every Teams step gate
This commit is contained in:
+45
-21
@@ -95,12 +95,25 @@ export async function runTeamsChannel(_displayName: string): Promise<ChannelFlow
|
||||
const prereqsResult = await confirmPrereqs({ collected, completed });
|
||||
if (prereqsResult === 'back') return BACK_TO_CHANNEL_SELECTION;
|
||||
await stepPublicUrl({ collected, completed });
|
||||
await stepAppRegistration({ collected, completed });
|
||||
await stepClientSecret({ collected, completed });
|
||||
await stepAzureBot({ collected, completed });
|
||||
await stepEnableTeamsChannel({ collected, completed });
|
||||
if (await stepAppRegistration({ collected, completed }) === 'back') {
|
||||
return BACK_TO_CHANNEL_SELECTION;
|
||||
}
|
||||
if (await stepClientSecret({ collected, completed }) === 'back') {
|
||||
return BACK_TO_CHANNEL_SELECTION;
|
||||
}
|
||||
if (await stepAzureBot({ collected, completed }) === 'back') {
|
||||
return BACK_TO_CHANNEL_SELECTION;
|
||||
}
|
||||
if (await stepEnableTeamsChannel({ collected, completed }) === 'back') {
|
||||
return BACK_TO_CHANNEL_SELECTION;
|
||||
}
|
||||
const manifestResult = await stepGenerateManifest({ collected, completed });
|
||||
await stepSideload({ collected, completed, zipPath: manifestResult.zipPath });
|
||||
if (
|
||||
await stepSideload({ collected, completed, zipPath: manifestResult.zipPath })
|
||||
=== 'back'
|
||||
) {
|
||||
return BACK_TO_CHANNEL_SELECTION;
|
||||
}
|
||||
|
||||
await installAdapter(collected);
|
||||
completed.push('Adapter installed and service restarted.');
|
||||
@@ -229,7 +242,7 @@ async function stepPublicUrl(args: { collected: Collected; completed: string[] }
|
||||
async function stepAppRegistration(args: {
|
||||
collected: Collected;
|
||||
completed: string[];
|
||||
}): Promise<void> {
|
||||
}): Promise<'continue' | 'back'> {
|
||||
note(
|
||||
[
|
||||
`1. In ${AZURE_PORTAL_URL}, search "App registrations" → "New registration"`,
|
||||
@@ -262,15 +275,17 @@ async function stepAppRegistration(args: {
|
||||
);
|
||||
}
|
||||
|
||||
await stepGate({
|
||||
const gate = await stepGate({
|
||||
stepName: 'teams-app-registration',
|
||||
stepDescription: 'registering an app in Azure and collecting App ID + tenant type',
|
||||
reshow: () => stepAppRegistration(args),
|
||||
args,
|
||||
});
|
||||
if (gate === 'back') return 'back';
|
||||
args.completed.push(
|
||||
`App registered: ${args.collected.appId} (${args.collected.appType})`,
|
||||
);
|
||||
return 'continue';
|
||||
}
|
||||
|
||||
async function askAppType(args: {
|
||||
@@ -313,7 +328,7 @@ async function askAppType(args: {
|
||||
async function stepClientSecret(args: {
|
||||
collected: Collected;
|
||||
completed: string[];
|
||||
}): Promise<void> {
|
||||
}): Promise<'continue' | 'back'> {
|
||||
note(
|
||||
[
|
||||
`1. In your app registration, open "Certificates & secrets"`,
|
||||
@@ -356,13 +371,15 @@ async function stepClientSecret(args: {
|
||||
break;
|
||||
}
|
||||
|
||||
await stepGate({
|
||||
const gate = await stepGate({
|
||||
stepName: 'teams-client-secret',
|
||||
stepDescription: 'creating and copying the client secret',
|
||||
reshow: () => stepClientSecret(args),
|
||||
args,
|
||||
});
|
||||
if (gate === 'back') return 'back';
|
||||
args.completed.push('Client secret captured.');
|
||||
return 'continue';
|
||||
}
|
||||
|
||||
// ─── step: Azure Bot resource ──────────────────────────────────────────
|
||||
@@ -370,7 +387,7 @@ async function stepClientSecret(args: {
|
||||
async function stepAzureBot(args: {
|
||||
collected: Collected;
|
||||
completed: string[];
|
||||
}): Promise<void> {
|
||||
}): Promise<'continue' | 'back'> {
|
||||
const endpoint = `${args.collected.publicUrl}/api/webhooks/teams`;
|
||||
const tenantFlag =
|
||||
args.collected.appType === 'SingleTenant'
|
||||
@@ -405,14 +422,16 @@ async function stepAzureBot(args: {
|
||||
'Step 3 of 6 — Create Azure Bot resource',
|
||||
);
|
||||
|
||||
await stepGate({
|
||||
const gate = await stepGate({
|
||||
stepName: 'teams-azure-bot',
|
||||
stepDescription:
|
||||
'creating an Azure Bot resource linked to the app registration and setting the messaging endpoint',
|
||||
reshow: () => stepAzureBot(args),
|
||||
args,
|
||||
});
|
||||
if (gate === 'back') return 'back';
|
||||
args.completed.push('Azure Bot created; messaging endpoint configured.');
|
||||
return 'continue';
|
||||
}
|
||||
|
||||
// ─── step: enable Teams channel ────────────────────────────────────────
|
||||
@@ -420,7 +439,7 @@ async function stepAzureBot(args: {
|
||||
async function stepEnableTeamsChannel(args: {
|
||||
collected: Collected;
|
||||
completed: string[];
|
||||
}): Promise<void> {
|
||||
}): Promise<'continue' | 'back'> {
|
||||
note(
|
||||
[
|
||||
'1. Open your Azure Bot resource → Channels',
|
||||
@@ -431,13 +450,15 @@ async function stepEnableTeamsChannel(args: {
|
||||
].join('\n'),
|
||||
'Step 4 of 6 — Enable Teams channel on the bot',
|
||||
);
|
||||
await stepGate({
|
||||
const gate = await stepGate({
|
||||
stepName: 'teams-enable-channel',
|
||||
stepDescription: 'enabling the Microsoft Teams channel on the Azure Bot resource',
|
||||
reshow: () => stepEnableTeamsChannel(args),
|
||||
args,
|
||||
});
|
||||
if (gate === 'back') return 'back';
|
||||
args.completed.push('Teams channel enabled on the bot.');
|
||||
return 'continue';
|
||||
}
|
||||
|
||||
// ─── step: manifest zip ────────────────────────────────────────────────
|
||||
@@ -490,7 +511,7 @@ async function stepSideload(args: {
|
||||
collected: Collected;
|
||||
completed: string[];
|
||||
zipPath: string;
|
||||
}): Promise<void> {
|
||||
}): Promise<'continue' | 'back'> {
|
||||
note(
|
||||
[
|
||||
'1. Open Microsoft Teams',
|
||||
@@ -505,13 +526,15 @@ async function stepSideload(args: {
|
||||
].join('\n'),
|
||||
'Step 5 of 6 — Sideload the app into Teams',
|
||||
);
|
||||
await stepGate({
|
||||
const gate = await stepGate({
|
||||
stepName: 'teams-sideload',
|
||||
stepDescription: 'uploading the generated zip into Teams as a custom app',
|
||||
reshow: () => stepSideload(args),
|
||||
reshow: () => stepSideload({ ...args, zipPath: args.zipPath }),
|
||||
args,
|
||||
});
|
||||
if (gate === 'back') return 'back';
|
||||
args.completed.push('App sideloaded into Teams.');
|
||||
return 'continue';
|
||||
}
|
||||
|
||||
// ─── step: install adapter ─────────────────────────────────────────────
|
||||
@@ -623,9 +646,9 @@ async function finishWithHandoff(
|
||||
async function stepGate(args: {
|
||||
stepName: string;
|
||||
stepDescription: string;
|
||||
reshow: () => Promise<void> | Promise<unknown>;
|
||||
reshow: () => Promise<'continue' | 'back'>;
|
||||
args: { collected: Collected; completed: string[] };
|
||||
}): Promise<void> {
|
||||
}): Promise<'continue' | 'back'> {
|
||||
while (true) {
|
||||
const choice = ensureAnswer(
|
||||
await brightSelect({
|
||||
@@ -634,10 +657,12 @@ async function stepGate(args: {
|
||||
{ value: 'done', label: "Done — let's continue" },
|
||||
{ value: 'help', label: 'Stuck — hand me off to Claude' },
|
||||
{ value: 'reshow', label: 'Show me the steps again' },
|
||||
{ value: 'back', label: '← Back to channel selection' },
|
||||
],
|
||||
}),
|
||||
);
|
||||
if (choice === 'done') return;
|
||||
if (choice === 'done') return 'continue';
|
||||
if (choice === 'back') return 'back';
|
||||
if (choice === 'help') {
|
||||
await offerHandoff({
|
||||
step: args.stepName,
|
||||
@@ -647,8 +672,7 @@ async function stepGate(args: {
|
||||
continue;
|
||||
}
|
||||
if (choice === 'reshow') {
|
||||
await args.reshow();
|
||||
return;
|
||||
return args.reshow();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user