@autohq/cli 0.1.157 → 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.
@@ -22701,6 +22701,24 @@ var SessionDispatchCommandRecordSchema = external_exports.discriminatedUnion("ki
22701
22701
  })
22702
22702
  ]);
22703
22703
 
22704
+ // ../../packages/schemas/src/setup.ts
22705
+ var SetupOnboardingPullRequestCreateRequestSchema = external_exports.object({
22706
+ githubConnection: external_exports.string().trim().min(1).optional(),
22707
+ slackConnection: external_exports.string().trim().min(1).optional(),
22708
+ repo: GithubSyncRepositoryFullNameSchema,
22709
+ baseBranch: GithubSyncProductionBranchSchema.optional()
22710
+ });
22711
+ var SetupOnboardingPullRequestSchema = external_exports.object({
22712
+ number: external_exports.number().int().positive(),
22713
+ url: external_exports.string().url().optional(),
22714
+ branchName: GithubSyncProductionBranchSchema,
22715
+ baseBranch: GithubSyncProductionBranchSchema,
22716
+ headSha: external_exports.string().trim().min(1)
22717
+ });
22718
+ var SetupOnboardingPullRequestCreateResponseSchema = external_exports.object({
22719
+ pullRequest: SetupOnboardingPullRequestSchema
22720
+ });
22721
+
22704
22722
  // ../../packages/schemas/src/runtimes.ts
22705
22723
  var RuntimeRecordSchema = external_exports.object({
22706
22724
  id: RuntimeIdSchema2,
@@ -26361,7 +26379,7 @@ Object.assign(lookup, {
26361
26379
  // package.json
26362
26380
  var package_default = {
26363
26381
  name: "@autohq/cli",
26364
- version: "0.1.157",
26382
+ version: "0.1.159",
26365
26383
  license: "SEE LICENSE IN README.md",
26366
26384
  publishConfig: {
26367
26385
  access: "public"
package/dist/index.js CHANGED
@@ -19491,6 +19491,32 @@ var init_session_commands = __esm({
19491
19491
  }
19492
19492
  });
19493
19493
 
19494
+ // ../../packages/schemas/src/setup.ts
19495
+ var SetupOnboardingPullRequestCreateRequestSchema, SetupOnboardingPullRequestSchema, SetupOnboardingPullRequestCreateResponseSchema;
19496
+ var init_setup = __esm({
19497
+ "../../packages/schemas/src/setup.ts"() {
19498
+ "use strict";
19499
+ init_zod();
19500
+ init_github_sync();
19501
+ SetupOnboardingPullRequestCreateRequestSchema = external_exports.object({
19502
+ githubConnection: external_exports.string().trim().min(1).optional(),
19503
+ slackConnection: external_exports.string().trim().min(1).optional(),
19504
+ repo: GithubSyncRepositoryFullNameSchema,
19505
+ baseBranch: GithubSyncProductionBranchSchema.optional()
19506
+ });
19507
+ SetupOnboardingPullRequestSchema = external_exports.object({
19508
+ number: external_exports.number().int().positive(),
19509
+ url: external_exports.string().url().optional(),
19510
+ branchName: GithubSyncProductionBranchSchema,
19511
+ baseBranch: GithubSyncProductionBranchSchema,
19512
+ headSha: external_exports.string().trim().min(1)
19513
+ });
19514
+ SetupOnboardingPullRequestCreateResponseSchema = external_exports.object({
19515
+ pullRequest: SetupOnboardingPullRequestSchema
19516
+ });
19517
+ }
19518
+ });
19519
+
19494
19520
  // ../../packages/schemas/src/runtimes.ts
19495
19521
  var RuntimeRecordSchema, SessionCommandDispatchWorkflowInputSchema, SessionCommandDispatchSignalPayloadSchema, RealtimeRunCursorSchema;
19496
19522
  var init_runtimes = __esm({
@@ -19556,6 +19582,7 @@ var init_src = __esm({
19556
19582
  init_session_introspection();
19557
19583
  init_secrets();
19558
19584
  init_session_commands();
19585
+ init_setup();
19559
19586
  init_runtimes();
19560
19587
  init_sessions();
19561
19588
  init_agents();
@@ -20830,6 +20857,17 @@ function createApiClient(input) {
20830
20857
  }
20831
20858
  return GithubSyncBindingListResponseSchema.parse(await response.json());
20832
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
+ },
20833
20871
  ...createResourceApi({
20834
20872
  activeProject,
20835
20873
  apiUrl,
@@ -21374,7 +21412,7 @@ var init_package = __esm({
21374
21412
  "package.json"() {
21375
21413
  package_default = {
21376
21414
  name: "@autohq/cli",
21377
- version: "0.1.157",
21415
+ version: "0.1.159",
21378
21416
  license: "SEE LICENSE IN README.md",
21379
21417
  publishConfig: {
21380
21418
  access: "public"
@@ -35080,6 +35118,359 @@ function registerSessionCommands(program, context) {
35080
35118
  );
35081
35119
  }
35082
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
+
35083
35474
  // src/commands/sync/repo.ts
35084
35475
  import { execFile as execFileWithCallback } from "child_process";
35085
35476
  import { promisify } from "util";
@@ -35375,6 +35766,7 @@ function createProgram(options = {}) {
35375
35766
  registerProjectCommands(program, context);
35376
35767
  registerConnectionCommands(program, context);
35377
35768
  registerSecretCommands(program, context);
35769
+ registerSetupCommands(program, context);
35378
35770
  registerSyncCommands(program, context);
35379
35771
  registerAgentCommands(program, context);
35380
35772
  registerSessionCommands(program, context);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@autohq/cli",
3
- "version": "0.1.157",
3
+ "version": "0.1.159",
4
4
  "license": "SEE LICENSE IN README.md",
5
5
  "publishConfig": {
6
6
  "access": "public"