@autohq/cli 0.1.158 → 0.1.159

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.
@@ -22702,27 +22702,11 @@ var SessionDispatchCommandRecordSchema = external_exports.discriminatedUnion("ki
22702
22702
  ]);
22703
22703
 
22704
22704
  // ../../packages/schemas/src/setup.ts
22705
- var SetupPullRequestFilePathSchema = external_exports.string().trim().min(1).max(255).refine((path2) => !path2.startsWith("/") && !path2.includes(".."), {
22706
- message: "file path must be relative and must not contain .."
22707
- });
22708
- var SetupPullRequestFileSchema = external_exports.object({
22709
- path: SetupPullRequestFilePathSchema,
22710
- content: external_exports.string().min(1).max(256e3)
22711
- });
22712
22705
  var SetupOnboardingPullRequestCreateRequestSchema = external_exports.object({
22713
22706
  githubConnection: external_exports.string().trim().min(1).optional(),
22714
22707
  slackConnection: external_exports.string().trim().min(1).optional(),
22715
22708
  repo: GithubSyncRepositoryFullNameSchema,
22716
- baseBranch: GithubSyncProductionBranchSchema.optional(),
22717
- branchName: GithubSyncProductionBranchSchema.default("auto/setup-onboarding"),
22718
- title: external_exports.string().trim().min(1).max(200).default("Add Auto onboarding agent"),
22719
- body: external_exports.string().trim().max(1e4).optional(),
22720
- files: external_exports.array(SetupPullRequestFileSchema).min(1).max(5).refine(
22721
- (files) => files.some((file2) => file2.path === ".auto/agents/onboarding.yaml"),
22722
- {
22723
- message: "files must include .auto/agents/onboarding.yaml"
22724
- }
22725
- )
22709
+ baseBranch: GithubSyncProductionBranchSchema.optional()
22726
22710
  });
22727
22711
  var SetupOnboardingPullRequestSchema = external_exports.object({
22728
22712
  number: external_exports.number().int().positive(),
@@ -26395,7 +26379,7 @@ Object.assign(lookup, {
26395
26379
  // package.json
26396
26380
  var package_default = {
26397
26381
  name: "@autohq/cli",
26398
- version: "0.1.158",
26382
+ version: "0.1.159",
26399
26383
  license: "SEE LICENSE IN README.md",
26400
26384
  publishConfig: {
26401
26385
  access: "public"
package/dist/index.js CHANGED
@@ -19492,33 +19492,17 @@ var init_session_commands = __esm({
19492
19492
  });
19493
19493
 
19494
19494
  // ../../packages/schemas/src/setup.ts
19495
- var SetupPullRequestFilePathSchema, SetupPullRequestFileSchema, SetupOnboardingPullRequestCreateRequestSchema, SetupOnboardingPullRequestSchema, SetupOnboardingPullRequestCreateResponseSchema;
19495
+ var SetupOnboardingPullRequestCreateRequestSchema, SetupOnboardingPullRequestSchema, SetupOnboardingPullRequestCreateResponseSchema;
19496
19496
  var init_setup = __esm({
19497
19497
  "../../packages/schemas/src/setup.ts"() {
19498
19498
  "use strict";
19499
19499
  init_zod();
19500
19500
  init_github_sync();
19501
- SetupPullRequestFilePathSchema = external_exports.string().trim().min(1).max(255).refine((path2) => !path2.startsWith("/") && !path2.includes(".."), {
19502
- message: "file path must be relative and must not contain .."
19503
- });
19504
- SetupPullRequestFileSchema = external_exports.object({
19505
- path: SetupPullRequestFilePathSchema,
19506
- content: external_exports.string().min(1).max(256e3)
19507
- });
19508
19501
  SetupOnboardingPullRequestCreateRequestSchema = external_exports.object({
19509
19502
  githubConnection: external_exports.string().trim().min(1).optional(),
19510
19503
  slackConnection: external_exports.string().trim().min(1).optional(),
19511
19504
  repo: GithubSyncRepositoryFullNameSchema,
19512
- baseBranch: GithubSyncProductionBranchSchema.optional(),
19513
- branchName: GithubSyncProductionBranchSchema.default("auto/setup-onboarding"),
19514
- title: external_exports.string().trim().min(1).max(200).default("Add Auto onboarding agent"),
19515
- body: external_exports.string().trim().max(1e4).optional(),
19516
- files: external_exports.array(SetupPullRequestFileSchema).min(1).max(5).refine(
19517
- (files) => files.some((file2) => file2.path === ".auto/agents/onboarding.yaml"),
19518
- {
19519
- message: "files must include .auto/agents/onboarding.yaml"
19520
- }
19521
- )
19505
+ baseBranch: GithubSyncProductionBranchSchema.optional()
19522
19506
  });
19523
19507
  SetupOnboardingPullRequestSchema = external_exports.object({
19524
19508
  number: external_exports.number().int().positive(),
@@ -20873,6 +20857,17 @@ function createApiClient(input) {
20873
20857
  }
20874
20858
  return GithubSyncBindingListResponseSchema.parse(await response.json());
20875
20859
  },
20860
+ async createSetupOnboardingPullRequest(request, options = {}) {
20861
+ const project = await activeProject();
20862
+ return requestJson(
20863
+ projectApiPath(project, "/setup/onboarding-pr"),
20864
+ {
20865
+ method: "POST",
20866
+ apiBaseUrl: options.apiBaseUrl,
20867
+ body: request
20868
+ }
20869
+ );
20870
+ },
20876
20871
  ...createResourceApi({
20877
20872
  activeProject,
20878
20873
  apiUrl,
@@ -21417,7 +21412,7 @@ var init_package = __esm({
21417
21412
  "package.json"() {
21418
21413
  package_default = {
21419
21414
  name: "@autohq/cli",
21420
- version: "0.1.158",
21415
+ version: "0.1.159",
21421
21416
  license: "SEE LICENSE IN README.md",
21422
21417
  publishConfig: {
21423
21418
  access: "public"
@@ -35123,6 +35118,359 @@ function registerSessionCommands(program, context) {
35123
35118
  );
35124
35119
  }
35125
35120
 
35121
+ // src/commands/setup/actions.ts
35122
+ init_file();
35123
+ init_login();
35124
+ async function setupAction(context, options) {
35125
+ const apiBaseUrl = apiUrlFromOptions(context, options);
35126
+ const client = createContextApiClient(context);
35127
+ await showPitchAndWait(context);
35128
+ await ensureAuthenticated(context, options, apiBaseUrl);
35129
+ const project = await selectProject(context, apiBaseUrl);
35130
+ const github = await selectGithubConnection(context, options, apiBaseUrl);
35131
+ await client.allowConnection("github", project.projectId, {
35132
+ connection: github.name,
35133
+ apiBaseUrl
35134
+ });
35135
+ const repo = await selectRepository(context, github, options.repo);
35136
+ const slack = await selectSlackConnection(context, options, apiBaseUrl);
35137
+ await client.allowConnection("slack", project.projectId, {
35138
+ connection: slack.name,
35139
+ apiBaseUrl
35140
+ });
35141
+ context.writeOutput("");
35142
+ context.writeOutput("Opening the onboarding PR...");
35143
+ const response = await client.createSetupOnboardingPullRequest(
35144
+ {
35145
+ githubConnection: github.name,
35146
+ slackConnection: slack.name,
35147
+ repo
35148
+ },
35149
+ { apiBaseUrl }
35150
+ );
35151
+ context.writeOutput("");
35152
+ context.writeOutput(`Opened PR #${response.pullRequest.number}.`);
35153
+ if (response.pullRequest.url) {
35154
+ context.writeOutput(response.pullRequest.url);
35155
+ }
35156
+ context.writeOutput("");
35157
+ context.writeOutput("Next steps:");
35158
+ context.writeOutput("1. Review and merge the PR.");
35159
+ context.writeOutput(
35160
+ "2. Wait for GitHub Sync to apply the merged `.auto` directory."
35161
+ );
35162
+ context.writeOutput("3. Tag `@auto.onboarding` in Slack to begin.");
35163
+ }
35164
+ async function showPitchAndWait(context) {
35165
+ context.writeOutput(setupPitchText());
35166
+ if (!context.io.canPrompt()) {
35167
+ throw new Error("`auto setup` requires an interactive terminal.");
35168
+ }
35169
+ const readline = createCliReadline({
35170
+ stdin: context.stdin,
35171
+ stdout: context.stdout
35172
+ });
35173
+ try {
35174
+ await readline.question("Press Enter to continue with setup.");
35175
+ } finally {
35176
+ readline.close();
35177
+ }
35178
+ }
35179
+ async function ensureAuthenticated(context, options, apiBaseUrl) {
35180
+ const config2 = readConfig(context.configPath);
35181
+ if (context.env.AUTO_API_TOKEN?.trim() || context.env.AUTO_DEV_USER_ID?.trim() || config2.refreshToken) {
35182
+ return;
35183
+ }
35184
+ context.writeOutput("");
35185
+ context.writeOutput("First, sign in to Auto.");
35186
+ const useDeviceLogin = options.device || options.browser === false;
35187
+ context.writeOutput(
35188
+ useDeviceLogin ? "Starting device login." : "Heads-up: this opens your browser for Auto login and prints the URL as a fallback."
35189
+ );
35190
+ await login({
35191
+ options: {
35192
+ apiUrl: apiBaseUrl,
35193
+ device: useDeviceLogin
35194
+ },
35195
+ env: context.env,
35196
+ fetch: context.fetch,
35197
+ configPath: context.configPath,
35198
+ writeOutput: context.writeOutput,
35199
+ writeError: context.writeError,
35200
+ style: context.io.style
35201
+ });
35202
+ }
35203
+ async function selectProject(context, apiBaseUrl) {
35204
+ const client = createContextApiClient(context);
35205
+ const active = await client.resolveActiveSelection();
35206
+ const projects = (await client.listProjects({ apiBaseUrl })).projects;
35207
+ const activeProject = projects.find(
35208
+ (project) => project.projectId === active.projectId
35209
+ );
35210
+ if (activeProject) {
35211
+ context.writeOutput(
35212
+ `Using active project ${activeProject.organizationName}/${activeProject.projectName}.`
35213
+ );
35214
+ return activeProject;
35215
+ }
35216
+ if (projects.length === 1) {
35217
+ const project = projects[0];
35218
+ setActiveProject(context, {
35219
+ organizationId: project.organizationId,
35220
+ projectId: project.projectId
35221
+ });
35222
+ context.writeOutput(
35223
+ `Using project ${project.organizationName}/${project.projectName}.`
35224
+ );
35225
+ return project;
35226
+ }
35227
+ if (projects.length > 1) {
35228
+ const selected = await chooseFromList(context, {
35229
+ label: "project",
35230
+ items: projects,
35231
+ render: (project) => `${project.organizationName}/${project.projectName} (${project.projectSlug})`
35232
+ });
35233
+ setActiveProject(context, {
35234
+ organizationId: selected.organizationId,
35235
+ projectId: selected.projectId
35236
+ });
35237
+ return selected;
35238
+ }
35239
+ return createInitialProject(context, apiBaseUrl);
35240
+ }
35241
+ async function createInitialProject(context, apiBaseUrl) {
35242
+ const client = createContextApiClient(context);
35243
+ const organizations = (await client.listOrganizations({ apiBaseUrl })).organizations;
35244
+ if (organizations.length === 0) {
35245
+ const organizationName = await askRequired(context, "Organization name: ");
35246
+ const projectName2 = await askRequired(context, "Project name: ");
35247
+ const created2 = await client.createOrganization({
35248
+ organizationName,
35249
+ projectName: projectName2,
35250
+ apiBaseUrl
35251
+ });
35252
+ if (!created2.project) {
35253
+ throw new Error("Organization was created without a project.");
35254
+ }
35255
+ setActiveProject(context, {
35256
+ organizationId: created2.project.organizationId,
35257
+ projectId: created2.project.projectId
35258
+ });
35259
+ return created2.project;
35260
+ }
35261
+ const organization = organizations.length === 1 ? organizations[0] : await chooseFromList(context, {
35262
+ label: "organization",
35263
+ items: organizations,
35264
+ render: organizationLabel
35265
+ });
35266
+ setActiveOrganization(context, organization.organizationId);
35267
+ const projectName = await askRequired(context, "Project name: ");
35268
+ const created = await client.createProject({ projectName, apiBaseUrl });
35269
+ setActiveProject(context, {
35270
+ organizationId: created.project.organizationId,
35271
+ projectId: created.project.projectId
35272
+ });
35273
+ return created.project;
35274
+ }
35275
+ async function selectGithubConnection(context, options, apiBaseUrl) {
35276
+ const existing = await activeConnections(context, "github", apiBaseUrl);
35277
+ if (existing.length === 0) {
35278
+ context.writeOutput("");
35279
+ context.writeOutput(
35280
+ "Next, connect GitHub. Heads-up: this opens your browser to install or authorize the GitHub App."
35281
+ );
35282
+ await connectProviderAction(context, "github", {
35283
+ apiBaseUrl,
35284
+ browser: options.browser,
35285
+ wait: true
35286
+ });
35287
+ return requireSingleConnection(context, "github", apiBaseUrl);
35288
+ }
35289
+ const selected = await selectConnection(context, {
35290
+ provider: "GitHub",
35291
+ selector: options.githubConnection,
35292
+ connections: existing
35293
+ });
35294
+ context.writeOutput(`Using GitHub connection ${selected.name}.`);
35295
+ return selected;
35296
+ }
35297
+ async function selectSlackConnection(context, options, apiBaseUrl) {
35298
+ const existing = await activeConnections(context, "slack", apiBaseUrl);
35299
+ if (existing.length === 0) {
35300
+ context.writeOutput("");
35301
+ context.writeOutput(
35302
+ "Now connect Slack. Heads-up: this opens your browser for Slack OAuth."
35303
+ );
35304
+ await connectProviderAction(context, "slack", {
35305
+ apiBaseUrl,
35306
+ browser: options.browser,
35307
+ wait: true
35308
+ });
35309
+ return requireSingleConnection(context, "slack", apiBaseUrl);
35310
+ }
35311
+ const selected = await selectConnection(context, {
35312
+ provider: "Slack",
35313
+ selector: options.slackConnection,
35314
+ connections: existing
35315
+ });
35316
+ context.writeOutput(`Using Slack connection ${selected.name}.`);
35317
+ return selected;
35318
+ }
35319
+ async function selectRepository(context, github, explicitRepo) {
35320
+ if (explicitRepo) {
35321
+ return explicitRepo;
35322
+ }
35323
+ const selection = github.grant.providerResourceSelection;
35324
+ if (selection.kind === "selected") {
35325
+ const repos = selection.resources.map(
35326
+ (resource) => isRecord3(resource) && typeof resource.fullName === "string" ? resource.fullName : void 0
35327
+ ).filter(isDefined);
35328
+ if (repos.length === 1) {
35329
+ context.writeOutput(`Using GitHub repository ${repos[0]}.`);
35330
+ return repos[0];
35331
+ }
35332
+ if (repos.length > 1) {
35333
+ return chooseFromList(context, {
35334
+ label: "repository",
35335
+ items: repos,
35336
+ render: (repo) => repo
35337
+ });
35338
+ }
35339
+ }
35340
+ return askRequired(
35341
+ context,
35342
+ "GitHub repository to install Auto in (owner/repo): "
35343
+ );
35344
+ }
35345
+ function setupPitchText() {
35346
+ return [
35347
+ "auto lets you program software factories the same way you program CI/CD.",
35348
+ "",
35349
+ "Compose agents and triggers into workflows using simple YAML files, and deploy them into the cloud on merge.",
35350
+ "",
35351
+ "Simple workflows you can build with auto:",
35352
+ "- Ticket / feedback triage and resolution",
35353
+ "- Automated incident / bug response",
35354
+ "- Custom tailored code review agents",
35355
+ "",
35356
+ "Frontier workflows auto can help you explore:",
35357
+ "- Organized fleets of agents on long-horizon tasks",
35358
+ "- Multi-agent autoresearch / optimization loops",
35359
+ "- Agentic BDR and outbound lead engines",
35360
+ "- More ideas we have not dreamed up yet",
35361
+ "",
35362
+ "Before you continue, have two things ready:",
35363
+ "1. A GitHub repository where Auto can add a `.auto/` directory.",
35364
+ "2. A Slack workspace where Auto can install its Slack connection.",
35365
+ "",
35366
+ "If you do not already have a repo and Slack workspace ready to go, create them before continuing.",
35367
+ "",
35368
+ "Auto is in early alpha, and you are one of the very first users. If anything feels confusing, breaks, or sparks an idea, please tell us. That feedback directly shapes the product.",
35369
+ ""
35370
+ ].join("\n");
35371
+ }
35372
+ async function activeConnections(context, provider, apiBaseUrl) {
35373
+ const response = await createContextApiClient(context).listConnections({
35374
+ provider,
35375
+ apiBaseUrl
35376
+ });
35377
+ return response.connections.flatMap(
35378
+ (connection) => activeGrants(connection).map((grant) => ({ name: grant.name, grant }))
35379
+ );
35380
+ }
35381
+ function activeGrants(connection) {
35382
+ return connection.grants.filter((grant) => grant.status === "active");
35383
+ }
35384
+ async function requireSingleConnection(context, provider, apiBaseUrl) {
35385
+ const connections = await activeConnections(context, provider, apiBaseUrl);
35386
+ if (connections.length === 0) {
35387
+ throw new Error(`No active ${provider} connection found after setup.`);
35388
+ }
35389
+ if (connections.length > 1) {
35390
+ return chooseFromList(context, {
35391
+ label: `${provider} connection`,
35392
+ items: connections,
35393
+ render: (connection) => connection.name
35394
+ });
35395
+ }
35396
+ return connections[0];
35397
+ }
35398
+ async function selectConnection(context, input) {
35399
+ if (input.selector) {
35400
+ const selected = input.connections.find(
35401
+ (connection) => connection.name === input.selector || connection.grant.id === input.selector
35402
+ );
35403
+ if (!selected) {
35404
+ throw new Error(
35405
+ `No ${input.provider} connection matched ${input.selector}.`
35406
+ );
35407
+ }
35408
+ return selected;
35409
+ }
35410
+ if (input.connections.length === 1) {
35411
+ return input.connections[0];
35412
+ }
35413
+ context.writeOutput(`Existing ${input.provider} connections:`);
35414
+ return chooseFromList(context, {
35415
+ label: `${input.provider} connection`,
35416
+ items: input.connections,
35417
+ render: (connection) => connectionLabel(connection)
35418
+ });
35419
+ }
35420
+ function connectionLabel(connection) {
35421
+ const selection = connection.grant.providerResourceSelection;
35422
+ const scope = selection.kind === "all" ? "all resources" : `${selection.resources.length} selected resources`;
35423
+ return `${connection.name} (${scope})`;
35424
+ }
35425
+ async function chooseFromList(context, input) {
35426
+ if (!context.io.canPrompt()) {
35427
+ throw new Error(`Multiple ${input.label}s found; rerun with a flag.`);
35428
+ }
35429
+ for (const [index2, item] of input.items.entries()) {
35430
+ context.writeOutput(`${index2 + 1}. ${input.render(item)}`);
35431
+ }
35432
+ const answer = await askRequired(context, `Select ${input.label}: `);
35433
+ const index = Number.parseInt(answer, 10) - 1;
35434
+ if (!Number.isInteger(index) || index < 0 || index >= input.items.length) {
35435
+ throw new Error(`Invalid ${input.label} selection: ${answer}`);
35436
+ }
35437
+ return input.items[index];
35438
+ }
35439
+ async function askRequired(context, question) {
35440
+ if (!context.io.canPrompt()) {
35441
+ throw new Error(`Cannot prompt for ${question.trim()}`);
35442
+ }
35443
+ const readline = createCliReadline({
35444
+ stdin: context.stdin,
35445
+ stdout: context.stdout
35446
+ });
35447
+ try {
35448
+ const answer = (await readline.question(question)).trim();
35449
+ if (!answer) {
35450
+ throw new Error("A non-empty answer is required.");
35451
+ }
35452
+ return answer;
35453
+ } finally {
35454
+ readline.close();
35455
+ }
35456
+ }
35457
+ function organizationLabel(organization) {
35458
+ return `${organization.organizationName} (${organization.organizationSlug})`;
35459
+ }
35460
+ function isRecord3(value) {
35461
+ return typeof value === "object" && value !== null && !Array.isArray(value);
35462
+ }
35463
+ function isDefined(value) {
35464
+ return value !== void 0;
35465
+ }
35466
+
35467
+ // src/commands/setup/commands.ts
35468
+ function registerSetupCommands(program, context) {
35469
+ program.command("setup").description("Launch the interactive first-run setup wizard.").option("--device", "use device authorization for Auto login").option("--no-browser", "do not open authorization URLs in a browser").option("--github-connection <name>", "GitHub connection name or id").option("--repo <owner/repo>", "GitHub repository to install Auto in").option("--slack-connection <name>", "Slack connection name or id").option("--api-url <url>", "Auto API base URL").option("--api-base-url <url>", "Auto API base URL").action(async (options) => {
35470
+ await setupAction(context, options);
35471
+ });
35472
+ }
35473
+
35126
35474
  // src/commands/sync/repo.ts
35127
35475
  import { execFile as execFileWithCallback } from "child_process";
35128
35476
  import { promisify } from "util";
@@ -35418,6 +35766,7 @@ function createProgram(options = {}) {
35418
35766
  registerProjectCommands(program, context);
35419
35767
  registerConnectionCommands(program, context);
35420
35768
  registerSecretCommands(program, context);
35769
+ registerSetupCommands(program, context);
35421
35770
  registerSyncCommands(program, context);
35422
35771
  registerAgentCommands(program, context);
35423
35772
  registerSessionCommands(program, context);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@autohq/cli",
3
- "version": "0.1.158",
3
+ "version": "0.1.159",
4
4
  "license": "SEE LICENSE IN README.md",
5
5
  "publishConfig": {
6
6
  "access": "public"