@hone-ai/cli 1.20.0 → 1.21.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.
Files changed (2) hide show
  1. package/hone-cli.js +109 -2
  2. package/package.json +1 -1
package/hone-cli.js CHANGED
@@ -2032,8 +2032,18 @@ byoKeyCmd
2032
2032
  const { data: plan } = await client.get('/orgs/me/plan');
2033
2033
  if (plan.mode === 'trial') {
2034
2034
  console.log(`Trial: active — ${plan.trial.daysLeft}d left, $${Number(plan.trial.creditRemaining).toFixed(2)} credit`);
2035
+ if (plan.trial.creditWarning) {
2036
+ console.log(plan.billingEnabled
2037
+ ? `Heads up: over half your trial credit is used. To continue after the trial you'll need your own key (set ✓) AND a subscription (\`hone upgrade\`).`
2038
+ : `Heads up: over half your trial credit is used. Your own key covers you after the trial.`);
2039
+ }
2035
2040
  } else if (plan.mode === 'expired') {
2036
- console.log('Trial: ended (set a key or upgrade)');
2041
+ // §11-F14: with the paywall live, BOTH a key AND a subscription are
2042
+ // needed (an "or" would imply either alone suffices). Billing-off
2043
+ // servers keep the legacy message — a key alone still works there.
2044
+ console.log(plan.billingEnabled
2045
+ ? 'Trial: ended — needs `hone byo-key set` AND `hone upgrade`'
2046
+ : 'Trial: ended (set a key to continue)');
2037
2047
  }
2038
2048
  } catch { /* trial line is a nicety — never block byo-key status */ }
2039
2049
  console.log('Tip: run `hone byo-key check` to verify the key still authenticates with Anthropic.');
@@ -2083,9 +2093,26 @@ trialCmd
2083
2093
  if (t.status === 'active') {
2084
2094
  console.log(`Days left: ${t.daysLeft}`);
2085
2095
  console.log(`Credit: $${Number(t.creditUsdUsed || 0).toFixed(2)} used / $${Number(t.creditUsdCap).toFixed(2)} cap ($${Number(t.creditRemaining).toFixed(2)} left)`);
2096
+ if (t.creditWarning) {
2097
+ // Owner decision: proactive heads-up at half the trial credit so the
2098
+ // post-trial requirement (key AND subscription when billing is on)
2099
+ // never lands as a surprise.
2100
+ console.log(data.billingEnabled
2101
+ ? 'Heads up: over half your trial credit is used. After the trial you need `hone byo-key set` AND `hone upgrade` to keep running.'
2102
+ : 'Heads up: over half your trial credit is used. Set your own key (`hone byo-key set`) to keep running after the trial.');
2103
+ }
2104
+ }
2105
+ if (data.subscription && data.billingEnabled) {
2106
+ console.log(`Subscription: ${data.subscription.status}${data.subscription.entitled ? ' (entitled)' : ''}`);
2107
+ if (data.subscription.graceUntil) {
2108
+ console.log(`Grace until: ${String(data.subscription.graceUntil).split('T')[0]} — payment failing, fix via \`hone billing portal\``);
2109
+ }
2086
2110
  }
2087
2111
  if (data.mode === 'expired') {
2088
- console.log('Trial ended — set your own key (`hone byo-key set`) or upgrade to continue.');
2112
+ // §11-F14: AND, not or — with the paywall live both are required.
2113
+ console.log(data.billingEnabled
2114
+ ? 'Trial ended — run `hone byo-key set` AND `hone upgrade` to continue.'
2115
+ : 'Trial ended — set your own key (`hone byo-key set`) to continue.');
2089
2116
  }
2090
2117
  } catch (e) { _handleByoKeyError(e); }
2091
2118
  });
@@ -2102,6 +2129,86 @@ trialCmd
2102
2129
  } catch (e) { _handleByoKeyError(e); }
2103
2130
  });
2104
2131
 
2132
+ // ── UPGRADE + BILLING commands (HC-COMM-015 / A4 / 015f) ─────────────────────
2133
+ // The subscription pays for Hone (orchestration/prompts/skills); LLM usage
2134
+ // stays on your own Anthropic key (`hone byo-key set`). Checkout happens on a
2135
+ // Stripe-hosted page — the CLI only prints the URL, no card data ever touches
2136
+ // Hone or this terminal.
2137
+ function _handleBillingError(e) {
2138
+ const status = e.response?.status;
2139
+ const msg = e.response?.data?.error;
2140
+ if (status === 401) {
2141
+ console.error('Not authenticated. Run: hone init --token <token>');
2142
+ } else if (status === 409) {
2143
+ console.error(msg || 'Conflict — check `hone billing status`.');
2144
+ } else if (status === 503) {
2145
+ console.error(msg === 'Billing not configured'
2146
+ ? "Billing isn't enabled on this server (self-hosted / not yet configured)."
2147
+ : `Server unavailable: ${msg || e.message}`);
2148
+ } else if (status === 429) {
2149
+ console.error('Rate limited — try again shortly.');
2150
+ } else {
2151
+ console.error(`Failed: ${msg || e.message}`);
2152
+ }
2153
+ process.exit(1);
2154
+ }
2155
+
2156
+ program
2157
+ .command('upgrade')
2158
+ .description('Subscribe to Hone (opens a Stripe-hosted checkout URL)')
2159
+ .action(async () => {
2160
+ const config = getConfig();
2161
+ const client = api(config);
2162
+ try {
2163
+ const { data } = await client.post('/orgs/me/billing/checkout');
2164
+ console.log('Complete your subscription in the browser:');
2165
+ console.log(` ${data.url}`);
2166
+ console.log('Then run `hone billing status` to confirm.');
2167
+ } catch (e) { _handleBillingError(e); }
2168
+ });
2169
+
2170
+ const billingCmd = program
2171
+ .command('billing')
2172
+ .description("View or manage your org's Hone subscription");
2173
+
2174
+ billingCmd
2175
+ .command('status')
2176
+ .description('Show subscription status, period end, and grace state')
2177
+ .option('--format <fmt>', 'Output format: pretty | json', 'pretty')
2178
+ .action(async (opts) => {
2179
+ const config = getConfig();
2180
+ const client = api(config);
2181
+ try {
2182
+ const { data } = await client.get('/orgs/me/plan');
2183
+ if (opts.format === 'json') { console.log(JSON.stringify(data, null, 2)); return; }
2184
+ const s = data.subscription || {};
2185
+ console.log(`Plan mode: ${data.mode}`);
2186
+ if (!data.billingEnabled) {
2187
+ console.log('Billing: not enabled on this server');
2188
+ return;
2189
+ }
2190
+ console.log(`Subscription: ${s.status}${s.entitled ? ' (entitled)' : ''}`);
2191
+ if (s.currentPeriodEnd) console.log(`Period ends: ${String(s.currentPeriodEnd).split('T')[0]}`);
2192
+ if (s.graceUntil) console.log(`Grace until: ${String(s.graceUntil).split('T')[0]} — payment failing, fix via \`hone billing portal\``);
2193
+ if (s.status === 'none' || s.status === 'canceled') {
2194
+ console.log('Subscribe with: hone upgrade');
2195
+ }
2196
+ } catch (e) { _handleBillingError(e); }
2197
+ });
2198
+
2199
+ billingCmd
2200
+ .command('portal')
2201
+ .description('Open the Stripe billing portal (update card, cancel, invoices)')
2202
+ .action(async () => {
2203
+ const config = getConfig();
2204
+ const client = api(config);
2205
+ try {
2206
+ const { data } = await client.post('/orgs/me/billing/portal');
2207
+ console.log('Manage your subscription in the browser:');
2208
+ console.log(` ${data.url}`);
2209
+ } catch (e) { _handleBillingError(e); }
2210
+ });
2211
+
2105
2212
  // ── ADMIN-USAGE command ──────────────────────────────────────────────────────
2106
2213
  program
2107
2214
  .command('admin-usage')
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hone-ai/cli",
3
- "version": "1.20.0",
3
+ "version": "1.21.0",
4
4
  "description": "Hone AI — Enterprise SDLC Pipeline CLI",
5
5
  "main": "hone-cli.js",
6
6
  "bin": {