@solarains/va-cli 0.1.6 → 0.1.10

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.
@@ -7,6 +7,7 @@ const doctor_command_1 = require("../commands/doctor/doctor-command");
7
7
  const init_command_1 = require("../commands/init/init-command");
8
8
  const intelligence_command_1 = require("../commands/intelligence/intelligence-command");
9
9
  const reports_command_1 = require("../commands/reports/reports-command");
10
+ const subscription_command_1 = require("../commands/subscription/subscription-command");
10
11
  const update_command_1 = require("../commands/update/update-command");
11
12
  const uninstall_command_1 = require("../commands/uninstall/uninstall-command");
12
13
  const usage_command_1 = require("../commands/usage/usage-command");
@@ -23,6 +24,7 @@ exports.rootCommand = {
23
24
  auth_command_1.authCommand,
24
25
  assets_command_1.assetsCommand,
25
26
  usage_command_1.usageCommand,
27
+ subscription_command_1.subscriptionCommand,
26
28
  reports_command_1.reportsCommand,
27
29
  intelligence_command_1.intelligenceCommand,
28
30
  doctor_command_1.doctorCommand,
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.subscriptionCommand = void 0;
4
+ exports.runSubscriptionCommand = runSubscriptionCommand;
5
+ const authenticated_api_client_1 = require("../../features/auth/authenticated-api-client");
6
+ const subscription_api_client_1 = require("../../features/subscription/subscription-api-client");
7
+ const subscription_output_1 = require("../../features/subscription/subscription-output");
8
+ const subscribe_handoff_1 = require("../../features/subscription/subscribe-handoff");
9
+ function isUnauthorizedError(error) {
10
+ if (error instanceof authenticated_api_client_1.CliApiError && error.status === 401) {
11
+ return true;
12
+ }
13
+ return error instanceof Error && error.message === 'Unauthorized';
14
+ }
15
+ async function runSubscriptionCommand(context, options = {}) {
16
+ try {
17
+ const status = await (options.getStatus ?? subscription_api_client_1.getSubscriptionStatus)(context);
18
+ (options.renderStatus ?? subscription_output_1.renderSubscriptionStatus)(context.logger, status);
19
+ if (!status.active && status.subscribe) {
20
+ await (options.handoff ?? subscribe_handoff_1.runSubscribeHandoff)(context.logger, status.subscribe);
21
+ }
22
+ return 0;
23
+ }
24
+ catch (error) {
25
+ if (error instanceof authenticated_api_client_1.AuthRequiredError) {
26
+ throw new Error('Subscription status requires login. Run `vaone auth login` first.');
27
+ }
28
+ if (isUnauthorizedError(error)) {
29
+ throw new Error('Subscription status requires a valid CLI login session.');
30
+ }
31
+ throw error;
32
+ }
33
+ }
34
+ exports.subscriptionCommand = {
35
+ name: 'subscription',
36
+ summary: 'Show current subscription status.',
37
+ usage: 'vaone subscription',
38
+ async run(context) {
39
+ return runSubscriptionCommand(context);
40
+ },
41
+ };
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.runSubscribeHandoff = runSubscribeHandoff;
4
+ const promises_1 = require("node:readline/promises");
5
+ const node_process_1 = require("node:process");
6
+ const browser_login_1 = require("../auth/browser-login");
7
+ async function promptToOpenInTerminal(entry) {
8
+ if (!node_process_1.stdin.isTTY || !node_process_1.stdout.isTTY) {
9
+ return false;
10
+ }
11
+ const rl = (0, promises_1.createInterface)({ input: node_process_1.stdin, output: node_process_1.stdout });
12
+ try {
13
+ const answer = await rl.question(`Press Enter to open the subscribe URL in your browser, or type anything else to skip: ${entry.url}\n`);
14
+ return answer.trim().length === 0;
15
+ }
16
+ finally {
17
+ rl.close();
18
+ }
19
+ }
20
+ async function runSubscribeHandoff(logger, entry, options = {}) {
21
+ const shouldOpen = await (options.promptToOpen ?? promptToOpenInTerminal)(entry);
22
+ if (!shouldOpen) {
23
+ logger.plain(`Open this URL manually when ready: ${entry.url}`);
24
+ return;
25
+ }
26
+ const opened = await (options.openBrowser ?? browser_login_1.openSystemBrowser)(entry.url);
27
+ if (opened) {
28
+ logger.plain('Opened subscribe URL in your default browser.');
29
+ return;
30
+ }
31
+ logger.plain(`Could not open the browser automatically. Open this URL manually: ${entry.url}`);
32
+ }
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getSubscriptionStatus = getSubscriptionStatus;
4
+ const authenticated_api_client_1 = require("../auth/authenticated-api-client");
5
+ async function getSubscriptionStatus(context) {
6
+ return (0, authenticated_api_client_1.requestAuthenticatedJson)(context, '/v1/subscription/status');
7
+ }
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.renderSubscriptionStatus = renderSubscriptionStatus;
4
+ function renderSubscriptionStatus(logger, status) {
5
+ logger.plain(`Subscription: ${status.active ? 'active' : 'inactive'}`);
6
+ logger.plain(`Status: ${status.status}`);
7
+ if (status.subscribe) {
8
+ logger.plain(`Subscribe URL: ${status.subscribe.url}`);
9
+ logger.plain('Next step: Press Enter when prompted to open it in your browser, or copy the URL above.');
10
+ }
11
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solarains/va-cli",
3
- "version": "0.1.6",
3
+ "version": "0.1.10",
4
4
  "description": "Bootstrap CLI for the VAOne product.",
5
5
  "bin": {
6
6
  "vaone": "dist/main.js"
@@ -27,6 +27,7 @@ Use this skill when the user:
27
27
 
28
28
  - Daily reports: read [references/daily-reports.md](references/daily-reports.md)
29
29
  - Usage summary: read [references/usage-summary.md](references/usage-summary.md)
30
+ - Subscription status: read [references/subscription-status.md](references/subscription-status.md)
30
31
  - Auth recovery or logout: read [references/auth-recovery.md](references/auth-recovery.md)
31
32
  - Asset intelligence query: read [references/asset-intelligence.md](references/asset-intelligence.md)
32
33
  - Asset catalog listing: read [references/assets.md](references/assets.md)
@@ -34,5 +35,4 @@ Use this skill when the user:
34
35
  ## Unsupported in this version
35
36
 
36
37
  - Installations or device-slot management: explain that this currently routes through the web portal. Do not invent CLI steps.
37
- - Billing or subscription actions: explain that this currently routes through the web portal. Do not invent CLI steps.
38
-
38
+ - Browser checkout execution: keep this on the web portal. Use `vaone subscription` for subscription query plus subscribe-entry handoff, but do not invent payment steps or direct billing API calls.
@@ -0,0 +1,37 @@
1
+ # Subscription Status
2
+
3
+ Use this reference when the user asks whether the current VA or VisionAlpha account has an active subscription.
4
+
5
+ ## Command
6
+
7
+ - `vaone subscription`
8
+
9
+ ## Workflow
10
+
11
+ 1. Run `vaone subscription`.
12
+ 2. Summarize the CLI verdict instead of inventing subscription state.
13
+ 3. If the CLI reports an inactive account, surface the subscribe URL shown by the CLI and let the CLI own the Enter-to-open browser prompt.
14
+
15
+ ## Required outcomes
16
+
17
+ ### Authenticated and active
18
+
19
+ - Tell the user the current account has an active subscription.
20
+ - Keep the answer short and based on the CLI verdict.
21
+
22
+ ### Authenticated and not active
23
+
24
+ - Tell the user the current account does not have an active subscription.
25
+ - Use the subscribe URL already printed by `vaone subscription`.
26
+ - Let `vaone subscription` handle the explicit browser-open prompt instead of inventing alternate steps.
27
+
28
+ ### Authentication required
29
+
30
+ - Tell the user to run `vaone auth login` first.
31
+ - Do not ask the user to paste tokens or secrets into chat.
32
+
33
+ ## Phase boundary
34
+
35
+ - `vaone subscription` now covers both subscription query and subscribe-entry handoff.
36
+ - Checkout execution still remains on the web portal after the CLI opens the canonical subscribe URL.
37
+ - Do not call private HTTP APIs directly from the skill.