@mnemom/mnemom 0.17.38-next.0 → 0.17.38-next.2

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 (79) hide show
  1. package/dist/commands/agent-doctor.d.ts +2 -2
  2. package/dist/commands/agent-doctor.js +4 -4
  3. package/dist/commands/agent-run.d.ts +10 -2
  4. package/dist/commands/agent-run.js +12 -6
  5. package/dist/commands/agent-setup.d.ts +11 -9
  6. package/dist/commands/agent-setup.js +24 -19
  7. package/dist/commands/card.js +1 -1
  8. package/dist/commands/onboard.js +5 -4
  9. package/dist/commands/scan.d.ts +21 -7
  10. package/dist/commands/scan.js +93 -56
  11. package/dist/commands/verify-card.d.ts +25 -1
  12. package/dist/commands/verify-card.js +29 -2
  13. package/dist/commands/wrap.js +4 -3
  14. package/dist/index.js +7 -5
  15. package/dist/lib/runner/executor-client.d.ts +6 -0
  16. package/dist/lib/runner/executor-client.js +6 -0
  17. package/dist/lib/runner/job.d.ts +12 -3
  18. package/dist/lib/runner/job.js +30 -2
  19. package/dist/lib/scan/caps.d.ts +1 -35
  20. package/dist/lib/scan/caps.js +2 -67
  21. package/dist/lib/scan/cost-per-pr.d.ts +1 -93
  22. package/dist/lib/scan/cost-per-pr.js +2 -101
  23. package/dist/lib/scan/credential.d.ts +2 -26
  24. package/dist/lib/scan/credential.js +5 -58
  25. package/dist/lib/scan/failure.d.ts +1 -10
  26. package/dist/lib/scan/failure.js +2 -43
  27. package/dist/lib/scan/pr-source.d.ts +1 -57
  28. package/dist/lib/scan/pr-source.js +2 -132
  29. package/dist/lib/scan/report-email.d.ts +9 -89
  30. package/dist/lib/scan/report-email.js +76 -92
  31. package/dist/lib/scan/scan.d.ts +1 -67
  32. package/dist/lib/scan/scan.js +2 -194
  33. package/dist/lib/scan/share.d.ts +10 -6
  34. package/dist/lib/scan/share.js +28 -11
  35. package/dist/lib/scan/spend/ai-tool-detect.d.ts +1 -6
  36. package/dist/lib/scan/spend/ai-tool-detect.js +2 -18
  37. package/dist/lib/scan/spend/anthropic-usage.d.ts +1 -76
  38. package/dist/lib/scan/spend/anthropic-usage.js +2 -269
  39. package/dist/lib/scan/spend/prices.d.ts +1 -33
  40. package/dist/lib/scan/spend/prices.js +2 -57
  41. package/dist/lib/scan/spend/spend-estimate.d.ts +1 -30
  42. package/dist/lib/scan/spend/spend-estimate.js +2 -70
  43. package/dist/lib/scan/spend/spend-tiers.d.ts +1 -16
  44. package/dist/lib/scan/spend/spend-tiers.js +6 -26
  45. package/dist/lib/scan/spend/token-rate.d.ts +1 -30
  46. package/dist/lib/scan/spend/token-rate.js +2 -54
  47. package/dist/lib/starter-integrity.d.ts +20 -0
  48. package/dist/lib/starter-integrity.js +28 -0
  49. package/dist/vendor/shared/org-scan-core/caps.d.ts +35 -0
  50. package/dist/vendor/shared/org-scan-core/caps.js +68 -0
  51. package/dist/vendor/shared/org-scan-core/cost-per-pr.d.ts +93 -0
  52. package/dist/vendor/shared/org-scan-core/cost-per-pr.js +101 -0
  53. package/dist/vendor/shared/org-scan-core/credential.d.ts +43 -0
  54. package/dist/vendor/shared/org-scan-core/credential.js +74 -0
  55. package/dist/vendor/shared/org-scan-core/failure.d.ts +10 -0
  56. package/dist/vendor/shared/org-scan-core/failure.js +43 -0
  57. package/dist/vendor/shared/org-scan-core/index.d.ts +18 -0
  58. package/dist/vendor/shared/org-scan-core/index.js +19 -0
  59. package/dist/vendor/shared/org-scan-core/pr-source.d.ts +61 -0
  60. package/dist/vendor/shared/org-scan-core/pr-source.js +138 -0
  61. package/dist/vendor/shared/org-scan-core/report-build.d.ts +120 -0
  62. package/dist/vendor/shared/org-scan-core/report-build.js +119 -0
  63. package/dist/vendor/shared/org-scan-core/scan.d.ts +75 -0
  64. package/dist/vendor/shared/org-scan-core/scan.js +202 -0
  65. package/dist/vendor/shared/org-scan-core/spend/ai-tool-detect.d.ts +6 -0
  66. package/dist/vendor/shared/org-scan-core/spend/ai-tool-detect.js +18 -0
  67. package/dist/vendor/shared/org-scan-core/spend/anthropic-usage.d.ts +76 -0
  68. package/dist/vendor/shared/org-scan-core/spend/anthropic-usage.js +270 -0
  69. package/dist/{lib/scan → vendor/shared/org-scan-core}/spend/cost-corpus.v1.js +1 -0
  70. package/dist/vendor/shared/org-scan-core/spend/prices.d.ts +33 -0
  71. package/dist/vendor/shared/org-scan-core/spend/prices.js +58 -0
  72. package/dist/vendor/shared/org-scan-core/spend/spend-estimate.d.ts +30 -0
  73. package/dist/vendor/shared/org-scan-core/spend/spend-estimate.js +71 -0
  74. package/dist/vendor/shared/org-scan-core/spend/spend-select.d.ts +16 -0
  75. package/dist/vendor/shared/org-scan-core/spend/spend-select.js +26 -0
  76. package/dist/vendor/shared/org-scan-core/spend/token-rate.d.ts +30 -0
  77. package/dist/vendor/shared/org-scan-core/spend/token-rate.js +55 -0
  78. package/package.json +2 -2
  79. /package/dist/{lib/scan → vendor/shared/org-scan-core}/spend/cost-corpus.v1.d.ts +0 -0
@@ -0,0 +1,30 @@
1
+ import { type AiTool } from "./prices.js";
2
+ import { type TokenRate } from "./token-rate.js";
3
+ /** AI-assisted PRs needed before a range is worth printing. */
4
+ export declare const MIN_AI_PRS = 10;
5
+ /** Per-PR input. `markText` is commit messages / PR body, read for tool marks and dropped. */
6
+ export interface SpendPrInput {
7
+ additions: number;
8
+ deletions: number;
9
+ markText: string;
10
+ /** Tools already detected inside the PR source (so the body never leaves it). Wins over markText. */
11
+ tools?: AiTool[];
12
+ }
13
+ export type NoSpendReason = "too_few_ai_prs" | "no_rate" | "invalid_input";
14
+ export type SpendEstimate = {
15
+ kind: "range";
16
+ lowUsd: number;
17
+ highUsd: number;
18
+ aiPrs: number;
19
+ scannedPrs: number;
20
+ byTool: Partial<Record<AiTool, number>>;
21
+ /** One line, labelled estimate, passes claim-lint. */
22
+ line: string;
23
+ } | {
24
+ kind: "none";
25
+ reason: NoSpendReason;
26
+ aiPrs: number;
27
+ scannedPrs: number;
28
+ line: string;
29
+ };
30
+ export declare function estimateSpend(prs: unknown, rate?: TokenRate | null): SpendEstimate;
@@ -0,0 +1,71 @@
1
+ // GENERATED from shared/org-scan-core/src/spend/spend-estimate.ts by cli/scripts/sync-org-scan-core.mjs; do not edit.
2
+ // MNE-9268: Tier-3 spend RANGE estimator. Pure and in-memory: takes per-PR counts and mark text, returns
3
+ // one labelled estimate line or an explicit "no estimate". Nothing is stored, fetched or logged.
4
+ //
5
+ // No line is produced when there are too few AI-assisted PRs to price (MIN_AI_PRS). That is a
6
+ // data-sufficiency threshold on the evidence behind the range, nothing to do with how large a
7
+ // reporting cohort is. Default-OFF behind ORG_SCAN_MODE via estimateSpendIfEnabled.
8
+ import { AI_TOOLS, detectAiTools } from "./ai-tool-detect.js";
9
+ import { PRICES_AS_OF, bandFor, blendedUsdPerToken } from "./prices.js";
10
+ import { DERIVED_TOKEN_RATE } from "./token-rate.js";
11
+ /** AI-assisted PRs needed before a range is worth printing. */
12
+ export const MIN_AI_PRS = 10;
13
+ /** Fixed strings only: a failure never carries input or an error message into the output. */
14
+ const NONE_LINES = {
15
+ too_few_ai_prs: "No spend estimate: too few AI-assisted PRs in this scan to price a range.",
16
+ no_rate: "No spend estimate: the cost reference data is not sufficient to price a range.",
17
+ invalid_input: "No spend estimate: the PR counts could not be read.",
18
+ };
19
+ const isCount = (n) => typeof n === "number" && Number.isFinite(n) && n >= 0;
20
+ function none(reason, aiPrs, scannedPrs) {
21
+ return { kind: "none", reason, aiPrs, scannedPrs, line: NONE_LINES[reason] };
22
+ }
23
+ function validPr(p) {
24
+ if (typeof p !== "object" || p === null)
25
+ return false;
26
+ const o = p;
27
+ return (isCount(o.additions) &&
28
+ isCount(o.deletions) &&
29
+ typeof o.markText === "string" &&
30
+ (o.tools === undefined ||
31
+ (Array.isArray(o.tools) && o.tools.every((t) => AI_TOOLS.includes(t)))));
32
+ }
33
+ /** Two significant figures so the range does not claim precision it lacks ($2.4, not $2; 0 stays $0). */
34
+ function usd(n) {
35
+ return `$${n.toLocaleString("en-US", { maximumSignificantDigits: 2 })}`;
36
+ }
37
+ export function estimateSpend(prs, rate = DERIVED_TOKEN_RATE) {
38
+ if (!Array.isArray(prs))
39
+ return none("invalid_input", 0, 0);
40
+ const scanned = prs.length;
41
+ if (!prs.every(validPr))
42
+ return none("invalid_input", 0, scanned);
43
+ let aiPrs = 0;
44
+ let low = 0;
45
+ let high = 0;
46
+ const byTool = {};
47
+ for (const p of prs) {
48
+ const tools = p.tools ?? detectAiTools(p.markText);
49
+ if (tools.length === 0)
50
+ continue;
51
+ aiPrs += 1;
52
+ for (const t of tools)
53
+ byTool[t] = (byTool[t] ?? 0) + 1;
54
+ if (!rate)
55
+ continue;
56
+ const lines = p.additions + p.deletions;
57
+ // A PR carrying several marks is priced once, across the widest band of the tools named.
58
+ const bands = tools.map(bandFor);
59
+ const lo = Math.min(...bands.map((b) => blendedUsdPerToken(b.low)));
60
+ const hi = Math.max(...bands.map((b) => blendedUsdPerToken(b.high)));
61
+ low += lines * rate.low * lo;
62
+ high += lines * rate.high * hi;
63
+ }
64
+ if (aiPrs < MIN_AI_PRS)
65
+ return none("too_few_ai_prs", aiPrs, scanned);
66
+ if (!rate)
67
+ return none("no_rate", aiPrs, scanned);
68
+ const line = `Estimate, AI tool spend: ${usd(low)} to ${usd(high)} across ${aiPrs} AI-assisted PRs ` +
69
+ `(public list prices as of ${PRICES_AS_OF} times a tokens-per-line rate from our own agents' PRs; not billing data).`;
70
+ return { kind: "range", lowUsd: low, highUsd: high, aiPrs, scannedPrs: scanned, byTool, line };
71
+ }
@@ -0,0 +1,16 @@
1
+ import type { SpendEstimate } from "./spend-estimate.js";
2
+ export type SpendTier = 1 | 2 | 3;
3
+ export interface SpendSelection {
4
+ /** null when the evidence is too thin: print nothing. */
5
+ tier: SpendTier | null;
6
+ line: string | null;
7
+ /** May this line leave the machine in a share payload? Never for a self-reported figure. */
8
+ shareable: boolean;
9
+ }
10
+ export declare function selectSpend(i: {
11
+ measuredUsd?: number;
12
+ /** Fraction of measured tokens from requests over 200k context; shown only with a measured figure. */
13
+ over200kShare?: number | null;
14
+ selfReportedUsd?: number | null;
15
+ estimate: SpendEstimate;
16
+ }): SpendSelection;
@@ -0,0 +1,26 @@
1
+ const usd = (n) => `$${n.toLocaleString("en-US", { maximumFractionDigits: 2 })}`;
2
+ const isUsd = (n) => typeof n === "number" && Number.isFinite(n) && n > 0;
3
+ const pct = (f) => `${Math.round(f * 100)}%`;
4
+ const isShare = (n) => typeof n === "number" && Number.isFinite(n) && n >= 0 && n <= 1;
5
+ export function selectSpend(i) {
6
+ if (isUsd(i.measuredUsd)) {
7
+ return {
8
+ tier: 1,
9
+ line: `Tier 1, measured: ${usd(i.measuredUsd)} of Anthropic usage over the period${isShare(i.over200kShare)
10
+ ? ` (${pct(i.over200kShare)} of tokens in requests over 200k context)`
11
+ : ""}.`,
12
+ shareable: true,
13
+ };
14
+ }
15
+ if (isUsd(i.selfReportedUsd)) {
16
+ return {
17
+ tier: 2,
18
+ line: `Tier 2, self-reported: about ${usd(i.selfReportedUsd)} a month (given by you; not verified, not sent, not saved).`,
19
+ shareable: false,
20
+ };
21
+ }
22
+ if (i.estimate.kind === "range") {
23
+ return { tier: 3, line: `Tier 3, ${i.estimate.line}`, shareable: true };
24
+ }
25
+ return { tier: null, line: null, shareable: false };
26
+ }
@@ -0,0 +1,30 @@
1
+ /** Rows needed before the rate is trusted at all (data sufficiency, not a group size). */
2
+ export declare const MIN_CORPUS_ROWS = 5;
3
+ export interface CostRowShape {
4
+ repo: string;
5
+ pr: number;
6
+ additions: number;
7
+ deletions: number;
8
+ cost_usd: number;
9
+ runs: number;
10
+ models: string[];
11
+ }
12
+ export interface TokenRate {
13
+ /** Price-equivalent tokens per changed (added + deleted) line: 25th percentile. */
14
+ low: number;
15
+ median: number;
16
+ /** 75th percentile. */
17
+ high: number;
18
+ rows: number;
19
+ }
20
+ /** Linear-interpolated quantile of a sorted array. */
21
+ export declare function quantile(sorted: number[], q: number): number;
22
+ /**
23
+ * Derive the rate from corpus rows: per-row tokens/line, then the 25th, 50th and 75th percentile.
24
+ * Rows that fail validation are dropped (not repaired); fewer than MIN_CORPUS_ROWS valid rows
25
+ * returns null, never a rate built on a handful.
26
+ */
27
+ export declare function deriveTokenRate(rows: unknown): TokenRate | null;
28
+ export declare const CORPUS_AS_OF: string;
29
+ /** The shipped rate: derived once from the committed fixture. */
30
+ export declare const DERIVED_TOKEN_RATE: TokenRate | null;
@@ -0,0 +1,55 @@
1
+ // GENERATED from shared/org-scan-core/src/spend/token-rate.ts by cli/scripts/sync-org-scan-core.mjs; do not edit.
2
+ // MNE-9268: tokens-per-changed-line and its spread, DERIVED from our own agents' PRs whose run cost is
3
+ // known (cost-corpus.v1.json, built by build-cost-corpus.mjs from the ADW "Run cost" PR comments).
4
+ // Nothing here is a typed-in rate: change the fixture and the rate moves, and token-rate.test.ts pins
5
+ // the derivation. Tokens are price-equivalent: cost / (our model's blended list price per token).
6
+ import rawCorpus from "./cost-corpus.v1.js";
7
+ import { TOOL_PRICES, blendedUsdPerToken } from "./prices.js";
8
+ /** Rows needed before the rate is trusted at all (data sufficiency, not a group size). */
9
+ export const MIN_CORPUS_ROWS = 5;
10
+ /** Our agents ran on Sonnet-family models in every corpus row; price their tokens as that. */
11
+ const BASIS_USD_PER_TOKEN = blendedUsdPerToken(TOOL_PRICES.claude_code.low);
12
+ const isCount = (n) => typeof n === "number" && Number.isFinite(n) && n >= 0;
13
+ function validRow(r) {
14
+ if (typeof r !== "object" || r === null)
15
+ return false;
16
+ const o = r;
17
+ return (isCount(o.additions) &&
18
+ isCount(o.deletions) &&
19
+ o.additions + o.deletions > 0 &&
20
+ isCount(o.cost_usd) &&
21
+ o.cost_usd > 0);
22
+ }
23
+ /** Linear-interpolated quantile of a sorted array. */
24
+ export function quantile(sorted, q) {
25
+ if (sorted.length === 0)
26
+ return NaN;
27
+ const pos = (sorted.length - 1) * q;
28
+ const lo = Math.floor(pos);
29
+ const hi = Math.ceil(pos);
30
+ return sorted[lo] + (sorted[hi] - sorted[lo]) * (pos - lo);
31
+ }
32
+ /**
33
+ * Derive the rate from corpus rows: per-row tokens/line, then the 25th, 50th and 75th percentile.
34
+ * Rows that fail validation are dropped (not repaired); fewer than MIN_CORPUS_ROWS valid rows
35
+ * returns null, never a rate built on a handful.
36
+ */
37
+ export function deriveTokenRate(rows) {
38
+ if (!Array.isArray(rows))
39
+ return null;
40
+ const per = rows
41
+ .filter(validRow)
42
+ .map((r) => r.cost_usd / (r.additions + r.deletions) / BASIS_USD_PER_TOKEN)
43
+ .sort((a, b) => a - b);
44
+ if (per.length < MIN_CORPUS_ROWS)
45
+ return null;
46
+ return {
47
+ low: quantile(per, 0.25),
48
+ median: quantile(per, 0.5),
49
+ high: quantile(per, 0.75),
50
+ rows: per.length,
51
+ };
52
+ }
53
+ export const CORPUS_AS_OF = rawCorpus.as_of;
54
+ /** The shipped rate: derived once from the committed fixture. */
55
+ export const DERIVED_TOKEN_RATE = deriveTokenRate(rawCorpus.rows);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mnemom/mnemom",
3
- "version": "0.17.38-next.0",
3
+ "version": "0.17.38-next.2",
4
4
  "description": "Transparent AI agent tracing",
5
5
  "type": "module",
6
6
  "bin": {
@@ -19,7 +19,7 @@
19
19
  },
20
20
  "dependencies": {
21
21
  "@mnemom/policy-engine": "^0.3.0",
22
- "@mnemom/verify": "0.6.2",
22
+ "@mnemom/verify": "0.6.3",
23
23
  "chalk": "^5.3.0",
24
24
  "commander": "^12.0.0",
25
25
  "js-yaml": "^4.3.2",