pierre-review 0.1.60 → 0.1.62
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/dist/api/plugins/auth.js +1 -0
- package/dist/api/routes/activity.js +6 -6
- package/dist/api/routes/me.js +13 -4
- package/dist/api/routes/timeline.js +1 -0
- package/dist/auth/account.js +1 -0
- package/dist/config.js +17 -4
- package/dist/db/credits.js +46 -0
- package/dist/db/migrations/0026_ai_credit_allowance.sql +5 -0
- package/dist/db/migrations/meta/_journal.json +7 -0
- package/dist/db/migrations-pg/0015_aspiring_black_tom.sql +1 -0
- package/dist/db/migrations-pg/meta/0015_snapshot.json +2553 -0
- package/dist/db/migrations-pg/meta/_journal.json +7 -0
- package/dist/db/queries.js +190 -103
- package/dist/db/schema.pg.js +4 -0
- package/dist/db/schema.sqlite.js +4 -0
- package/dist/pro/bind.js +21 -3
- package/package.json +1 -1
- package/public/assets/index-WLWeK-9-.css +10 -0
- package/public/assets/index-eHQuClHw.js +1390 -0
- package/public/index.html +2 -2
- package/public-landing/assets/index-DoT9NPaW.js +40 -0
- package/public-landing/assets/index-HoUbJF4i.css +1 -0
- package/public-landing/index.html +2 -2
- package/public/assets/index-BfGXViGK.js +0 -1390
- package/public/assets/index-yvdhLCO_.css +0 -10
- package/public-landing/assets/index-B6mKVK3l.js +0 -40
- package/public-landing/assets/index-BVeVh56_.css +0 -1
package/dist/api/plugins/auth.js
CHANGED
|
@@ -11,17 +11,17 @@ function parseIntList(raw) {
|
|
|
11
11
|
}
|
|
12
12
|
export async function activityRoutes(app) {
|
|
13
13
|
// The Activity aggregate: per repo, current-state stats + thread totals +
|
|
14
|
-
// attention/unread flags + open PRs. Scoped to the account
|
|
15
|
-
// narrow to the active FilterBar repo + member selection
|
|
16
|
-
//
|
|
14
|
+
// attention/unread flags + open PRs. Scoped to the account's WATCHED repos (inboxWatch);
|
|
15
|
+
// `repoIds` + `userIds` narrow to the active FilterBar repo + member selection WITHIN
|
|
16
|
+
// watched. Pure DB read — no GitHub sync, no AI.
|
|
17
17
|
app.get('/api/activity', async (req) => {
|
|
18
18
|
const q = req.query;
|
|
19
19
|
return getActivity(accountIdOf(req), parseIntList(q.repoIds), parseIntList(q.userIds));
|
|
20
20
|
});
|
|
21
21
|
// The consolidated Feed (the Activity "Feed" entry): one flat, chronological stream
|
|
22
|
-
// merging My Turn actionables + the activity feed, deduped. Scoped
|
|
23
|
-
//
|
|
24
|
-
// Pure DB read — no GitHub sync, no AI.
|
|
22
|
+
// merging My Turn actionables + the activity feed, deduped. Scoped to the account's
|
|
23
|
+
// WATCHED repos (inboxWatch); the FilterBar repo + member selection narrow WITHIN
|
|
24
|
+
// watched. Pure DB read — no GitHub sync, no AI.
|
|
25
25
|
app.get('/api/activity/feed', async (req) => {
|
|
26
26
|
const q = req.query;
|
|
27
27
|
const limit = q.limit != null ? Number(q.limit) : null;
|
package/dist/api/routes/me.js
CHANGED
|
@@ -27,9 +27,20 @@ export async function meRoutes(app) {
|
|
|
27
27
|
// baseline exists (feedLastSeenAt set by the first feed view) so a fresh account
|
|
28
28
|
// never sees a scary first-load number. FYI is a Pro capability — the count comes
|
|
29
29
|
// from the plugin's enricher (0 on the free tier, where there's no provider).
|
|
30
|
+
// Per-account entitlement: local = full capabilities (unchanged); cloud = full only when
|
|
31
|
+
// the account's plan isn't 'free' (Stripe billing seam). Computed once and reused for both
|
|
32
|
+
// the FYI gate and the `pro` passthrough below.
|
|
33
|
+
const entitled = req.account
|
|
34
|
+
? entitledProCapabilities(req.account)
|
|
35
|
+
: EMPTY_CAPABILITIES;
|
|
30
36
|
const feedLastSeen = await getFeedLastSeenAt(accountId);
|
|
31
37
|
const fyi = getFyiProvider();
|
|
32
|
-
|
|
38
|
+
// FYI is the Pro `feedMyTurn` capability. Gate the count on ENTITLEMENT, not just provider
|
|
39
|
+
// presence: once Pro loads in cloud the provider is registered process-globally for every
|
|
40
|
+
// account, so a free cloud account would otherwise leak an FYI count it hasn't paid for.
|
|
41
|
+
const newFeedItems = feedLastSeen && fyi && entitled.feedMyTurn
|
|
42
|
+
? await fyi.countNewSince(accountId, feedLastSeen)
|
|
43
|
+
: 0;
|
|
33
44
|
return {
|
|
34
45
|
user,
|
|
35
46
|
counts: {
|
|
@@ -44,9 +55,7 @@ export async function meRoutes(app) {
|
|
|
44
55
|
newFeedItems,
|
|
45
56
|
// Claude Review is now the Pro `claudeReview` capability (in `pro` below).
|
|
46
57
|
deploymentMode: config.deploymentMode,
|
|
47
|
-
|
|
48
|
-
// full only when the account's plan isn't 'free' (Stripe billing seam).
|
|
49
|
-
pro: req.account ? entitledProCapabilities(req.account) : EMPTY_CAPABILITIES,
|
|
58
|
+
pro: entitled,
|
|
50
59
|
};
|
|
51
60
|
});
|
|
52
61
|
app.get('/api/my-turn', async (req) => getMyTurn(accountIdOf(req)));
|
|
@@ -81,6 +81,7 @@ export async function timelineRoutes(app) {
|
|
|
81
81
|
from: parseDate(q.from, new Date(now.getTime() - 14 * DAY_MS)),
|
|
82
82
|
to: parseDate(q.to, now),
|
|
83
83
|
repoIds: parseIntList(q.repoIds),
|
|
84
|
+
prIds: parseIntList(q.prIds),
|
|
84
85
|
userIds: parseIntList(q.userIds),
|
|
85
86
|
types: parseTypes(q.types),
|
|
86
87
|
statuses: parseStatuses(q.statuses),
|
package/dist/auth/account.js
CHANGED
|
@@ -34,6 +34,7 @@ function rowToAccount(row) {
|
|
|
34
34
|
isLocal: row.isLocal,
|
|
35
35
|
plan: row.plan === 'pro' ? 'pro' : 'free',
|
|
36
36
|
stripeCustomerId: row.stripeCustomerId,
|
|
37
|
+
aiCreditAllowance: row.aiCreditAllowance ?? null,
|
|
37
38
|
};
|
|
38
39
|
}
|
|
39
40
|
// Module cache of the local account, set by ensureLocalAccount() at startup so
|
package/dist/config.js
CHANGED
|
@@ -135,10 +135,15 @@ export const config = {
|
|
|
135
135
|
// Webhook signing secret (whsec_…) for POST /api/billing/webhook. Empty = the
|
|
136
136
|
// webhook replies 501 and no billing state ever changes.
|
|
137
137
|
stripeWebhookSecret: process.env.STRIPE_WEBHOOK_SECRET ?? '',
|
|
138
|
-
// Pro plugin master gate.
|
|
139
|
-
//
|
|
140
|
-
// the
|
|
141
|
-
|
|
138
|
+
// Pro plugin master gate. bind.ts skips the dynamic import entirely when false.
|
|
139
|
+
// PRO_DISABLED=true forces pure-OSS mode even when the submodule is checked out (used to
|
|
140
|
+
// exercise/capture the free tier). Local defaults ON. In CLOUD it stays OFF unless
|
|
141
|
+
// PRO_CLOUD_ENABLED=true (the paid summary-AI tier — set on the Railway image), so the
|
|
142
|
+
// public Dockerfile / OSS npm path is byte-identical to before. Even when true in cloud,
|
|
143
|
+
// per-account entitlement (plan !== 'free') + the /api/pro/* 402 gate decide who actually
|
|
144
|
+
// gets Pro; agentic AI stays independently gated by PRO_ADVANCED_AI_ENABLED (unset → off).
|
|
145
|
+
proEnabled: process.env.PRO_DISABLED !== 'true' &&
|
|
146
|
+
(!isCloud || process.env.PRO_CLOUD_ENABLED === 'true'),
|
|
142
147
|
// Per-repo digest (Pro, Workstream 2) config — consumed by @pierre/pro, kept in
|
|
143
148
|
// core so the model id / budgets live in one place and aren't hardcoded at call
|
|
144
149
|
// sites. Inert until the plugin is present AND digestEnabled.
|
|
@@ -235,5 +240,13 @@ export function assertCloudConfig() {
|
|
|
235
240
|
if (Buffer.from(config.encryptionKey, 'hex').length !== 32) {
|
|
236
241
|
throw new Error('ENCRYPTION_KEY must be 32 bytes as 64 hex chars (generate with `openssl rand -hex 32`).');
|
|
237
242
|
}
|
|
243
|
+
// When Pro is cloud-enabled the SUMMARY seam needs its OWN metered credential: there is no
|
|
244
|
+
// ambient logged-in `claude` session on Railway, so without SUMMARY_ANTHROPIC_API_KEY every
|
|
245
|
+
// summary completion has no credential and silently fails. Fail loud instead.
|
|
246
|
+
if (config.proEnabled && !process.env.SUMMARY_ANTHROPIC_API_KEY) {
|
|
247
|
+
throw new Error('Cloud Pro (PRO_CLOUD_ENABLED=true) requires SUMMARY_ANTHROPIC_API_KEY — the metered ' +
|
|
248
|
+
'Anthropic key the summary seam spends against (no ambient Claude session exists in cloud). ' +
|
|
249
|
+
'Set it or unset PRO_CLOUD_ENABLED. See docs/DEPLOY-RAILWAY.md.');
|
|
250
|
+
}
|
|
238
251
|
}
|
|
239
252
|
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { getAiUsageSummary } from './usage.js';
|
|
2
|
+
// USD → credits conversion, MIRRORED from @pierre-review/shared AI_CREDITS_PER_USD. Inlined
|
|
3
|
+
// here (not imported) because the release guard forbids a real runtime import of the
|
|
4
|
+
// types-only shared package into release/dist — the same reason the pro plugin inlines its
|
|
5
|
+
// own copy. Keep all three in lockstep (shared + this + packages/pro/src/insights/routes.ts).
|
|
6
|
+
// $1 of model cost = 1250 credits, so the paid plan's 2,500-credit allowance ≈ $2.00 of spend.
|
|
7
|
+
export const AI_CREDITS_PER_USD = 1250;
|
|
8
|
+
// The default monthly SUMMARY-AI credit allowance for a paid cloud account. Overridable per
|
|
9
|
+
// account via accounts.aiCreditAllowance (a forward hook for top-ups / alternate plans).
|
|
10
|
+
export const DEFAULT_AI_CREDIT_ALLOWANCE = 2500;
|
|
11
|
+
const toCredits = (usd) => Math.round(usd * AI_CREDITS_PER_USD);
|
|
12
|
+
// UTC first-of-month epoch ms — the month-to-date window start (matches the /api/pro/ai-usage
|
|
13
|
+
// route). Monthly reset is automatic: the window rolls at the UTC month boundary.
|
|
14
|
+
export function monthStartMs(nowMs) {
|
|
15
|
+
const d = new Date(nowMs);
|
|
16
|
+
return Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), 1);
|
|
17
|
+
}
|
|
18
|
+
// The account's allowance in credits, or null when unmetered.
|
|
19
|
+
// - local (isLocal): unmetered — null (never blocked; today's behavior).
|
|
20
|
+
// - paid cloud (plan !== 'free'): the per-account override, else the plan default (2,500).
|
|
21
|
+
// - free cloud: a zero allowance (belt-and-braces — the /api/pro/* 402 gate already blocks
|
|
22
|
+
// these accounts before any Pro route runs).
|
|
23
|
+
function allowanceFor(account) {
|
|
24
|
+
if (account.isLocal)
|
|
25
|
+
return null;
|
|
26
|
+
if (account.plan !== 'free')
|
|
27
|
+
return account.aiCreditAllowance ?? DEFAULT_AI_CREDIT_ALLOWANCE;
|
|
28
|
+
return 0;
|
|
29
|
+
}
|
|
30
|
+
// The PURE credit-ledger computation (no I/O) — month-to-date spend vs. the allowance. Split
|
|
31
|
+
// out from aiCreditStatus so the budget math is unit-testable without a DB. usedCredits sums
|
|
32
|
+
// each seam rounded independently, matching the /api/pro/ai-usage meter exactly.
|
|
33
|
+
export function computeAiCreditStatus(account, usage) {
|
|
34
|
+
const allowanceCredits = allowanceFor(account);
|
|
35
|
+
const usedCredits = toCredits(usage.summaryUsd) + toCredits(usage.agentUsd);
|
|
36
|
+
const remainingCredits = allowanceCredits == null ? null : Math.max(0, allowanceCredits - usedCredits);
|
|
37
|
+
const blocked = remainingCredits != null && remainingCredits <= 0;
|
|
38
|
+
return { allowanceCredits, usedCredits, remainingCredits, blocked };
|
|
39
|
+
}
|
|
40
|
+
// The per-account credit-ledger status: reads the month-to-date ledger and applies the pure
|
|
41
|
+
// computation above. This is what ctx.aiCredits.check calls per generation.
|
|
42
|
+
export async function aiCreditStatus(account, nowMs) {
|
|
43
|
+
const usage = await getAiUsageSummary(account.id, monthStartMs(nowMs));
|
|
44
|
+
return computeAiCreditStatus(account, usage);
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=credits.js.map
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
-- Per-account monthly SUMMARY-AI credit allowance override (metered cloud plan). Nullable,
|
|
2
|
+
-- no default: null = use the plan default (2,500 for a paid cloud account); local/unlimited
|
|
3
|
+
-- accounts ignore it. A forward hook for top-ups / alternate plans without another migration.
|
|
4
|
+
-- The Postgres baseline is regenerated separately via `pnpm db:generate:pg`.
|
|
5
|
+
ALTER TABLE `accounts` ADD `ai_credit_allowance` integer;
|
|
@@ -183,6 +183,13 @@
|
|
|
183
183
|
"when": 1783296000000,
|
|
184
184
|
"tag": "0025_account_billing",
|
|
185
185
|
"breakpoints": true
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
"idx": 26,
|
|
189
|
+
"version": "6",
|
|
190
|
+
"when": 1783382400000,
|
|
191
|
+
"tag": "0026_ai_credit_allowance",
|
|
192
|
+
"breakpoints": true
|
|
186
193
|
}
|
|
187
194
|
]
|
|
188
195
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
ALTER TABLE "accounts" ADD COLUMN "ai_credit_allowance" integer;
|