-
Notifications
You must be signed in to change notification settings - Fork 35
enable agentic workflows #912
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
7a882de
600f9de
ca19c3f
dc0dde7
c618263
16ad23c
00b4501
010c361
00d5e86
eb6ffde
27cc8ba
d37a99b
bb03e00
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -192,6 +192,9 @@ class InitCommand extends TemplatesCommand { | |||||||||||||||||||||||||||||||||||||||||||
| this.error(`Extension(s) '${notFound.join(', ')}' not found in the Template Registry.`) | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
| return extensionTemplates.map(t => t.name) | ||||||||||||||||||||||||||||||||||||||||||||
| } else if (flags.yes) { | ||||||||||||||||||||||||||||||||||||||||||||
| // with --yes and no explicit template, default to standalone app (no prompts) | ||||||||||||||||||||||||||||||||||||||||||||
| return [] | ||||||||||||||||||||||||||||||||||||||||||||
| } else if (!flags['standalone-app']) { | ||||||||||||||||||||||||||||||||||||||||||||
| const noLogin = flags.import || !flags.login | ||||||||||||||||||||||||||||||||||||||||||||
| let [searchCriteria, orderByCriteria] = await this.getSearchCriteria(orgSupportedServices) | ||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -210,9 +213,12 @@ class InitCommand extends TemplatesCommand { | |||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| async ensureDevTermAccepted (consoleCLI, orgId) { | ||||||||||||||||||||||||||||||||||||||||||||
| async ensureDevTermAccepted (consoleCLI, orgId, skipPrompts = false) { | ||||||||||||||||||||||||||||||||||||||||||||
| const isTermAccepted = await consoleCLI.checkDevTermsForOrg(orgId) | ||||||||||||||||||||||||||||||||||||||||||||
| if (!isTermAccepted) { | ||||||||||||||||||||||||||||||||||||||||||||
| if (skipPrompts) { | ||||||||||||||||||||||||||||||||||||||||||||
| this.error('Developer Terms of Service have not been accepted for this organization. Please run `aio app init` without --yes to accept the terms first.') | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
| const terms = await consoleCLI.getDevTermsForOrg() | ||||||||||||||||||||||||||||||||||||||||||||
| const confirmDevTerms = await consoleCLI.prompt.promptConfirm(`${terms.text} | ||||||||||||||||||||||||||||||||||||||||||||
| \nYou have not accepted the Developer Terms of Service. Go to ${hyperlinker('https://www.adobe.com/go/developer-terms', 'https://www.adobe.com/go/developer-terms')} to view the terms. Do you accept the terms? (y/n):`) | ||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -294,26 +300,110 @@ class InitCommand extends TemplatesCommand { | |||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| async selectConsoleOrg (consoleCLI, flags) { | ||||||||||||||||||||||||||||||||||||||||||||
| const organizations = await consoleCLI.getOrganizations() | ||||||||||||||||||||||||||||||||||||||||||||
| const selectedOrg = await consoleCLI.promptForSelectOrganization(organizations, { orgId: flags.org, orgCode: flags.org }) | ||||||||||||||||||||||||||||||||||||||||||||
| await this.ensureDevTermAccepted(consoleCLI, selectedOrg.id) | ||||||||||||||||||||||||||||||||||||||||||||
| if (!organizations || organizations.length === 0) { | ||||||||||||||||||||||||||||||||||||||||||||
| this.error('No organizations found for the logged-in user') | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
| // If --org was supplied, validate it against the full list regardless of how many orgs | ||||||||||||||||||||||||||||||||||||||||||||
| // exist. This prevents silent mismatches when there is only one org but the caller | ||||||||||||||||||||||||||||||||||||||||||||
| // passed a wrong id or code. | ||||||||||||||||||||||||||||||||||||||||||||
| let selectedOrg | ||||||||||||||||||||||||||||||||||||||||||||
| if (flags.org) { | ||||||||||||||||||||||||||||||||||||||||||||
| selectedOrg = organizations.find(o => o.id === flags.org || o.code === flags.org) | ||||||||||||||||||||||||||||||||||||||||||||
| if (!selectedOrg) { | ||||||||||||||||||||||||||||||||||||||||||||
| this.error(`--org ${flags.org} not found`) | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
| } else if (organizations.length > 1 && !flags.yes) { | ||||||||||||||||||||||||||||||||||||||||||||
| // Multiple orgs and no --org: prompt interactively (only when not in --yes mode). | ||||||||||||||||||||||||||||||||||||||||||||
| selectedOrg = await consoleCLI.promptForSelectOrganization(organizations, {}) | ||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||
| // Single org, or --yes with no --org: auto-select the first (and likely only) org. | ||||||||||||||||||||||||||||||||||||||||||||
| selectedOrg = organizations[0] | ||||||||||||||||||||||||||||||||||||||||||||
| this.log(`Auto-selecting organization: '${selectedOrg.name || selectedOrg.id}'`) | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
| await this.ensureDevTermAccepted(consoleCLI, selectedOrg.id, flags.yes) | ||||||||||||||||||||||||||||||||||||||||||||
| return selectedOrg | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| async selectOrCreateConsoleProject (consoleCLI, org, flags) { | ||||||||||||||||||||||||||||||||||||||||||||
| // Fetch all projects in the org upfront. This list is used both for uniqueness | ||||||||||||||||||||||||||||||||||||||||||||
| // checks (--yes path) and for the interactive selection prompt (non-yes path). | ||||||||||||||||||||||||||||||||||||||||||||
| const projects = await consoleCLI.getProjects(org.id) | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| if (flags.yes) { | ||||||||||||||||||||||||||||||||||||||||||||
| // Non-interactive path: no prompts are shown. Behavior depends on whether | ||||||||||||||||||||||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Re-raised] When flags.yes is true and there are multiple orgs, the code auto-selects organizations[0] (the first org) and ignores the --org flag entirely. If --org is also provided it should try to match the specified org rather than blindly picking the first one.
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||
| // --project was explicitly supplied by the caller. | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| if (flags.project) { | ||||||||||||||||||||||||||||||||||||||||||||
| // --project was supplied. Try to find it in the existing list by id or name. | ||||||||||||||||||||||||||||||||||||||||||||
| // Matching by id supports callers who pass a project id rather than a name. | ||||||||||||||||||||||||||||||||||||||||||||
| const existing = projects.find(p => p.id === flags.project || p.name === flags.project) | ||||||||||||||||||||||||||||||||||||||||||||
| if (existing) { | ||||||||||||||||||||||||||||||||||||||||||||
| // Project already exists — return it as-is. isNew is intentionally NOT set | ||||||||||||||||||||||||||||||||||||||||||||
| // so downstream code knows not to treat this as a newly created project. | ||||||||||||||||||||||||||||||||||||||||||||
| this.log(`Using existing project: '${existing.name}'`) | ||||||||||||||||||||||||||||||||||||||||||||
|
purplecabbage marked this conversation as resolved.
|
||||||||||||||||||||||||||||||||||||||||||||
| return existing | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
| // Project does not exist — create it using the caller-supplied name directly. | ||||||||||||||||||||||||||||||||||||||||||||
| // title and description are derived from the name since no other info is available. | ||||||||||||||||||||||||||||||||||||||||||||
| this.log(`Project '${flags.project}' not found, creating it`) | ||||||||||||||||||||||||||||||||||||||||||||
| const project = await consoleCLI.createProject(org.id, { | ||||||||||||||||||||||||||||||||||||||||||||
| name: flags.project, | ||||||||||||||||||||||||||||||||||||||||||||
| title: flags.project, | ||||||||||||||||||||||||||||||||||||||||||||
| description: `App Builder Project ${flags.project} - generated by an agent` | ||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||
|
purplecabbage marked this conversation as resolved.
|
||||||||||||||||||||||||||||||||||||||||||||
| project.isNew = true | ||||||||||||||||||||||||||||||||||||||||||||
| return project | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| // No --project supplied. Auto-generate a unique name of the form "App{N}" | ||||||||||||||||||||||||||||||||||||||||||||
| // where N is the lowest positive integer not already used by an existing project. | ||||||||||||||||||||||||||||||||||||||||||||
| // This mimics sequential behaviour (App1, App2, ...) and fills | ||||||||||||||||||||||||||||||||||||||||||||
| // gaps left by deleted projects (e.g. if App2 was deleted, it is reused | ||||||||||||||||||||||||||||||||||||||||||||
| // before App4 is attempted). | ||||||||||||||||||||||||||||||||||||||||||||
| const existingNames = new Set(projects.map(p => p.name)) | ||||||||||||||||||||||||||||||||||||||||||||
| const MAX_SUFFIX = 10000 | ||||||||||||||||||||||||||||||||||||||||||||
| let suffix = 1 | ||||||||||||||||||||||||||||||||||||||||||||
| while (existingNames.has(`App${suffix}`)) { | ||||||||||||||||||||||||||||||||||||||||||||
| suffix++ | ||||||||||||||||||||||||||||||||||||||||||||
| if (suffix > MAX_SUFFIX) { | ||||||||||||||||||||||||||||||||||||||||||||
| this.error(`Could not find an available generated App name after ${MAX_SUFFIX} attempts`) | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| const generatedName = `App${suffix}` | ||||||||||||||||||||||||||||||||||||||||||||
| const generatedTitle = `App Builder Project ${suffix}` | ||||||||||||||||||||||||||||||||||||||||||||
| const generatedDescription = `App Builder Project ${suffix} - generated` | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| this.log(`Auto-generating project name: '${generatedName}'`) | ||||||||||||||||||||||||||||||||||||||||||||
| const project = await consoleCLI.createProject(org.id, { | ||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+332
to
+378
|
||||||||||||||||||||||||||||||||||||||||||||
| name: generatedName, | ||||||||||||||||||||||||||||||||||||||||||||
| title: generatedTitle, | ||||||||||||||||||||||||||||||||||||||||||||
| description: generatedDescription | ||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||
| project.isNew = true | ||||||||||||||||||||||||||||||||||||||||||||
| return project | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| // Interactive path: prompt the user to select an existing project or create a new one. | ||||||||||||||||||||||||||||||||||||||||||||
| // If --project was supplied it is used to pre-populate the selection (by id or name) | ||||||||||||||||||||||||||||||||||||||||||||
| // but the prompt is still shown so the user can confirm or change it. | ||||||||||||||||||||||||||||||||||||||||||||
| let project = await consoleCLI.promptForSelectProject( | ||||||||||||||||||||||||||||||||||||||||||||
| projects, | ||||||||||||||||||||||||||||||||||||||||||||
| { projectId: flags.project, projectName: flags.project }, | ||||||||||||||||||||||||||||||||||||||||||||
| { allowCreate: true } | ||||||||||||||||||||||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The condition
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||
| if (!project) { | ||||||||||||||||||||||||||||||||||||||||||||
| // promptForSelectProject returns null when the user selects "Create new project" or | ||||||||||||||||||||||||||||||||||||||||||||
| // escapes the prompt. If --project was explicitly provided but not found/selected, | ||||||||||||||||||||||||||||||||||||||||||||
| // always error — never silently create a different project. | ||||||||||||||||||||||||||||||||||||||||||||
| if (flags.project) { | ||||||||||||||||||||||||||||||||||||||||||||
| this.error(`--project ${flags.project} not found`) | ||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||
| // User chose to create a new project — collect details interactively and create it. | ||||||||||||||||||||||||||||||||||||||||||||
| const projectDetails = await consoleCLI.promptForCreateProjectDetails() | ||||||||||||||||||||||||||||||||||||||||||||
| project = await consoleCLI.createProject(org.id, projectDetails) | ||||||||||||||||||||||||||||||||||||||||||||
| project.isNew = true | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
| // user has escaped project selection prompt, let's create a new one | ||||||||||||||||||||||||||||||||||||||||||||
| const projectDetails = await consoleCLI.promptForCreateProjectDetails() | ||||||||||||||||||||||||||||||||||||||||||||
| project = await consoleCLI.createProject(org.id, projectDetails) | ||||||||||||||||||||||||||||||||||||||||||||
| project.isNew = true | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
| return project | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+401
to
409
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Re-raised] The condition
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -324,7 +414,7 @@ class InitCommand extends TemplatesCommand { | |||||||||||||||||||||||||||||||||||||||||||
| const workspaces = await consoleCLI.getWorkspaces(org.id, project.id) | ||||||||||||||||||||||||||||||||||||||||||||
| let workspace = workspaces.find(w => w.name.toLowerCase() === workspaceName.toLowerCase()) | ||||||||||||||||||||||||||||||||||||||||||||
| if (!workspace) { | ||||||||||||||||||||||||||||||||||||||||||||
| if (flags['confirm-new-workspace']) { | ||||||||||||||||||||||||||||||||||||||||||||
| if (!flags.yes && flags['confirm-new-workspace']) { | ||||||||||||||||||||||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When flags.yes is true and a workspace doesn't exist, it silently auto-creates it. But if the user did NOT pass --confirm-new-workspace and also did NOT pass --yes, the original code would also skip the prompt and auto-create (only prompts when confirm-new-workspace is set). The condition
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||
| const shouldNewWorkspace = await consoleCLI.prompt.promptConfirm(`Workspace '${workspaceName}' does not exist \n > Do you wish to create a new workspace?`) | ||||||||||||||||||||||||||||||||||||||||||||
| if (!shouldNewWorkspace) { | ||||||||||||||||||||||||||||||||||||||||||||
| this.error(`Workspace '${workspaceName}' does not exist and creation aborted`) | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
getProjects(org.id)is executed before the--yesearly-return branch but its result is unused whenflags.yesis true, adding an avoidable network/API call to non-interactive runs. Consider moving thegetProjectscall into the non---yesbranch.