@apso/cli 0.24.0 → 0.25.0

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.
@@ -140,9 +140,31 @@ class Deploy extends base_command_1.default {
140
140
  git.initRepo(cwd);
141
141
  // Pick the repo: prefer what the local project is already wired to, then the
142
142
  // service's connected repo, then --repo, then ask.
143
- const conn = await services_1.githubApi.getConnection();
143
+ let conn = await services_1.githubApi.getConnection();
144
144
  if (!conn.connected || !conn.connectionId) {
145
- this.error("GitHub is not connected. Run 'apso github connect' first, then re-run deploy.");
145
+ // Connecting GitHub is a browser OAuth flow a machine can't complete.
146
+ // Headless: fail with instructions. Interactive: offer to launch it now
147
+ // (opens the browser), wait for the human, then continue the deploy.
148
+ if (!(0, interactive_1.isInteractive)()) {
149
+ this.error("GitHub is not connected. Run 'apso github connect' first, then re-run deploy.");
150
+ }
151
+ const inquirer = await Promise.resolve().then(() => tslib_1.__importStar(require("inquirer")));
152
+ const { connectNow } = await inquirer.default.prompt([
153
+ {
154
+ type: "confirm",
155
+ name: "connectNow",
156
+ message: "GitHub is not connected (required to push code). Connect now? This opens your browser.",
157
+ default: true,
158
+ },
159
+ ]);
160
+ if (!connectNow) {
161
+ this.error("GitHub connection is required to deploy. Run 'apso github connect' when ready, then re-run deploy.");
162
+ }
163
+ await this.config.runCommand("github:connect", []);
164
+ conn = await services_1.githubApi.getConnection();
165
+ if (!conn.connected || !conn.connectionId) {
166
+ this.error("GitHub still isn't connected. Complete 'apso github connect' and re-run deploy.");
167
+ }
146
168
  }
147
169
  let repoFullName = git.localRepoFullName(cwd) || service.githubRepo || repoFlag;
148
170
  if (!repoFullName) {
@@ -10,6 +10,8 @@ const base_command_1 = tslib_1.__importDefault(require("../lib/base-command"));
10
10
  const config_1 = require("../lib/config");
11
11
  const services_1 = require("../lib/api/services");
12
12
  const upgrade_1 = require("../lib/upgrade");
13
+ const interactive_1 = require("../lib/utils/interactive");
14
+ const config_2 = require("../lib/config");
13
15
  const template_1 = require("../lib/utils/template");
14
16
  class Init extends base_command_1.default {
15
17
  async run() {
@@ -28,18 +30,28 @@ class Init extends base_command_1.default {
28
30
  await (isAuthenticated ? this.runAuthenticated(flags) : this.runOffline(flags));
29
31
  }
30
32
  async runAuthenticated(flags) {
31
- // Ask: create new or clone existing
32
- const { action } = await inquirer_1.default.prompt([
33
- {
34
- type: "list",
35
- name: "action",
36
- message: "What would you like to do?",
37
- choices: [
38
- { name: "Create a new project", value: "create" },
39
- { name: "Clone an existing project", value: "clone" },
40
- ],
41
- },
42
- ]);
33
+ // Headless: init is the guided human path; require the essentials up-front so
34
+ // no prompt is reached. Agents should prefer 'apso generate' + 'apso link --create'.
35
+ if (!(0, interactive_1.isInteractive)() && (!flags.name || !flags.language)) {
36
+ this.error((0, interactive_1.missingFlag)("apso init needs --name and --language non-interactively (or use 'apso generate' + 'apso link --create')."));
37
+ }
38
+ // Ask: create new or clone existing. Headless: default to "create" (the
39
+ // scaffold path); requires --name/--language, which createNew enforces.
40
+ let action = "create";
41
+ if ((0, interactive_1.isInteractive)()) {
42
+ const answer = await inquirer_1.default.prompt([
43
+ {
44
+ type: "list",
45
+ name: "action",
46
+ message: "What would you like to do?",
47
+ choices: [
48
+ { name: "Create a new project", value: "create" },
49
+ { name: "Clone an existing project", value: "clone" },
50
+ ],
51
+ },
52
+ ]);
53
+ action = answer.action;
54
+ }
43
55
  await (action === "clone" ? this.cloneExisting() : this.createNew(flags));
44
56
  }
45
57
  async cloneExisting() {
@@ -158,26 +170,41 @@ class Init extends base_command_1.default {
158
170
  if (!resolvedPath.startsWith(path.resolve(process.cwd()))) {
159
171
  this.error("Invalid project name: path traversal detected");
160
172
  }
161
- // Select workspace
173
+ // Select workspace: active workspace (apso use), else prompt (interactive),
174
+ // else error headless.
162
175
  const workspaces = await services_1.workspacesApi.list();
163
176
  if (workspaces.length === 0) {
164
177
  this.error("No workspaces found. Create a workspace at https://app.apso.cloud first.");
165
178
  }
166
- const { workspace } = await inquirer_1.default.prompt([
167
- {
168
- type: "list",
169
- name: "workspace",
170
- message: "Select a workspace:",
171
- choices: workspaces.map((ws) => ({
172
- name: `${ws.name} (${ws.slug})`,
173
- value: ws,
174
- })),
175
- },
176
- ]);
179
+ const activeSlug = config_2.globalConfig.read().activeWorkspaceSlug;
180
+ let workspace = activeSlug
181
+ ? workspaces.find((w) => w.slug === activeSlug)
182
+ : undefined;
183
+ if (!workspace) {
184
+ if (!(0, interactive_1.isInteractive)()) {
185
+ this.error((0, interactive_1.missingFlag)("Set a workspace first with 'apso use <slug>'."));
186
+ }
187
+ const answer = await inquirer_1.default.prompt([
188
+ {
189
+ type: "list",
190
+ name: "workspace",
191
+ message: "Select a workspace:",
192
+ choices: workspaces.map((ws) => ({
193
+ name: `${ws.name} (${ws.slug})`,
194
+ value: ws,
195
+ })),
196
+ },
197
+ ]);
198
+ workspace = answer.workspace;
199
+ }
200
+ if (!workspace) {
201
+ throw new Error("No workspace selected.");
202
+ }
203
+ const ws = workspace;
177
204
  // Create service on platform
178
- this.log(`Creating service "${projectName}" in workspace "${workspace.name}"...`);
205
+ this.log(`Creating service "${projectName}" in workspace "${ws.name}"...`);
179
206
  const serviceName = projectName;
180
- const service = await (0, upgrade_1.withUpgradeRetry)(() => services_1.servicesApi.create(workspace.id, {
207
+ const service = await (0, upgrade_1.withUpgradeRetry)(() => services_1.servicesApi.create(ws.id, {
181
208
  name: serviceName,
182
209
  }));
183
210
  // Clone template
@@ -196,6 +223,12 @@ class Init extends base_command_1.default {
196
223
  this.log(`\nProject created at ${projectPath}`);
197
224
  this.log(`Language: ${language}`);
198
225
  this.log(`Linked to workspace "${workspace.name}" / service "${service.name}"`);
226
+ this.log("");
227
+ this.log("Next steps:");
228
+ this.log(` cd ${projectName}`);
229
+ this.log(" # edit .apsorc to shape your schema, then:");
230
+ this.log(" apso generate # scaffold code from the schema");
231
+ this.log(" apso deploy # ship it (prompts to connect GitHub if needed)");
199
232
  }
200
233
  async runOffline(flags) {
201
234
  // Prompt for name if not provided
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@apso/cli",
3
- "version": "0.24.0",
3
+ "version": "0.25.0",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@apso/cli",
9
- "version": "0.24.0",
9
+ "version": "0.25.0",
10
10
  "license": "Apache-2.0",
11
11
  "dependencies": {
12
12
  "@biomejs/biome": "^1.9.4",
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.24.0",
2
+ "version": "0.25.0",
3
3
  "commands": {
4
4
  "config": {
5
5
  "id": "config",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@apso/cli",
3
- "version": "0.24.0",
3
+ "version": "0.25.0",
4
4
  "mcpName": "io.github.apsoai/apso",
5
5
  "description": "Apso CLI",
6
6
  "author": "Apso by Mavric - @mavric",