@hone-ai/cli 1.20.0 → 1.22.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.
- package/hone-cli.js +109 -2
- package/lib/story-classifier.js +10 -0
- 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
|
-
|
|
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
|
-
|
|
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/lib/story-classifier.js
CHANGED
|
@@ -48,6 +48,11 @@ const ARCHITECT_AXES = Object.freeze({
|
|
|
48
48
|
EXTERNAL_COORDINATION: 'external-coordination',
|
|
49
49
|
CROSS_REPO_DEPENDENCY: 'cross-repo-dependency',
|
|
50
50
|
SECURITY_IMPLICATIONS: 'security-implications',
|
|
51
|
+
// HC-DH-001: the story gates/wraps/re-bills/re-routes a function shared by
|
|
52
|
+
// 2+ consumers (billing, auth, quota, dispatch, refusal). Origin: a billing
|
|
53
|
+
// story with single-module surface + one obvious design engaged NO axis —
|
|
54
|
+
// exactly where an independent architect caught a money leak.
|
|
55
|
+
SHARED_CHOKEPOINT: 'shared-chokepoint',
|
|
51
56
|
});
|
|
52
57
|
|
|
53
58
|
// Estimate ordering for threshold comparisons
|
|
@@ -97,6 +102,11 @@ function shouldEngageArchitect(input) {
|
|
|
97
102
|
if (input.has_security_implications === true) {
|
|
98
103
|
axes.push(ARCHITECT_AXES.SECURITY_IMPLICATIONS);
|
|
99
104
|
}
|
|
105
|
+
// Shared chokepoint → architect for whole-repo call-site + invariant review
|
|
106
|
+
// (HC-DH-001). Missing/false input = today's behavior — additive-only.
|
|
107
|
+
if (input.touches_shared_chokepoint === true) {
|
|
108
|
+
axes.push(ARCHITECT_AXES.SHARED_CHOKEPOINT);
|
|
109
|
+
}
|
|
100
110
|
return { engage: axes.length > 0, axes };
|
|
101
111
|
}
|
|
102
112
|
|