@rigour-labs/core 6.8.0 → 6.8.1-rc.1
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/inference/cloud-provider.js +12 -2
- package/package.json +11 -8
- package/dist/brief/briefing.test.d.ts +0 -1
- package/dist/brief/briefing.test.js +0 -107
- package/dist/context/automatic-index-cache.test.d.ts +0 -1
- package/dist/context/automatic-index-cache.test.js +0 -30
- package/dist/context/automatic-index.test.d.ts +0 -1
- package/dist/context/automatic-index.test.js +0 -45
- package/dist/context/cache-engine.test.d.ts +0 -1
- package/dist/context/cache-engine.test.js +0 -99
- package/dist/context/dependency-graph.test.d.ts +0 -1
- package/dist/context/dependency-graph.test.js +0 -13
- package/dist/context/index-status.test.d.ts +0 -1
- package/dist/context/index-status.test.js +0 -26
- package/dist/context.test.d.ts +0 -1
- package/dist/context.test.js +0 -228
- package/dist/deep/agent-review.test.d.ts +0 -1
- package/dist/deep/agent-review.test.js +0 -53
- package/dist/deep/code-context.test.d.ts +0 -1
- package/dist/deep/code-context.test.js +0 -48
- package/dist/deep/code-pass.test.d.ts +0 -1
- package/dist/deep/code-pass.test.js +0 -112
- package/dist/deep/code-review-prompt.test.d.ts +0 -1
- package/dist/deep/code-review-prompt.test.js +0 -20
- package/dist/deep/code-verifier.test.d.ts +0 -1
- package/dist/deep/code-verifier.test.js +0 -54
- package/dist/deep/diff-tests/calls.test.d.ts +0 -1
- package/dist/deep/diff-tests/calls.test.js +0 -33
- package/dist/deep/diff-tests/run.test.d.ts +0 -1
- package/dist/deep/diff-tests/run.test.js +0 -58
- package/dist/deep/fact-extractor.test.d.ts +0 -1
- package/dist/deep/fact-extractor.test.js +0 -581
- package/dist/deep/parse-findings.test.d.ts +0 -1
- package/dist/deep/parse-findings.test.js +0 -25
- package/dist/deep/pr-review.test.d.ts +0 -1
- package/dist/deep/pr-review.test.js +0 -80
- package/dist/deep/prompts.test.d.ts +0 -1
- package/dist/deep/prompts.test.js +0 -235
- package/dist/deep/reference-pack.test.d.ts +0 -1
- package/dist/deep/reference-pack.test.js +0 -46
- package/dist/deep/related-changes.test.d.ts +0 -1
- package/dist/deep/related-changes.test.js +0 -33
- package/dist/deep/review-context-export.test.d.ts +0 -1
- package/dist/deep/review-context-export.test.js +0 -32
- package/dist/deep/review-tools.test.d.ts +0 -1
- package/dist/deep/review-tools.test.js +0 -39
- package/dist/deep/risk.test.d.ts +0 -1
- package/dist/deep/risk.test.js +0 -101
- package/dist/deep/verifier.test.d.ts +0 -1
- package/dist/deep/verifier.test.js +0 -635
- package/dist/discovery.test.d.ts +0 -1
- package/dist/discovery.test.js +0 -93
- package/dist/environment.test.d.ts +0 -1
- package/dist/environment.test.js +0 -94
- package/dist/firewall/firewall.test.d.ts +0 -1
- package/dist/firewall/firewall.test.js +0 -117
- package/dist/firewall/trust-boundaries.test.d.ts +0 -1
- package/dist/firewall/trust-boundaries.test.js +0 -64
- package/dist/firewall/trusted-control.test.d.ts +0 -1
- package/dist/firewall/trusted-control.test.js +0 -188
- package/dist/gates/agent-team.test.d.ts +0 -1
- package/dist/gates/agent-team.test.js +0 -113
- package/dist/gates/ast.test.d.ts +0 -1
- package/dist/gates/ast.test.js +0 -112
- package/dist/gates/checkpoint.test.d.ts +0 -1
- package/dist/gates/checkpoint.test.js +0 -105
- package/dist/gates/content.test.d.ts +0 -1
- package/dist/gates/content.test.js +0 -73
- package/dist/gates/coverage.test.d.ts +0 -1
- package/dist/gates/coverage.test.js +0 -53
- package/dist/gates/dedupe-failures.test.d.ts +0 -1
- package/dist/gates/dedupe-failures.test.js +0 -12
- package/dist/gates/deep-analysis.test.d.ts +0 -1
- package/dist/gates/deep-analysis.test.js +0 -86
- package/dist/gates/deep-intent.test.d.ts +0 -1
- package/dist/gates/deep-intent.test.js +0 -51
- package/dist/gates/deep-timeout.test.d.ts +0 -1
- package/dist/gates/deep-timeout.test.js +0 -10
- package/dist/gates/deprecated-apis.test.d.ts +0 -1
- package/dist/gates/deprecated-apis.test.js +0 -318
- package/dist/gates/deprecated-dependencies.test.d.ts +0 -1
- package/dist/gates/deprecated-dependencies.test.js +0 -55
- package/dist/gates/frontend-secret-exposure.test.d.ts +0 -1
- package/dist/gates/frontend-secret-exposure.test.js +0 -148
- package/dist/gates/hallucinated-imports/framework-modules-nuxt.test.d.ts +0 -1
- package/dist/gates/hallucinated-imports/framework-modules-nuxt.test.js +0 -27
- package/dist/gates/hallucinated-imports/js-resolver-types.test.d.ts +0 -1
- package/dist/gates/hallucinated-imports/js-resolver-types.test.js +0 -14
- package/dist/gates/hallucinated-imports-sveltekit.test.d.ts +0 -1
- package/dist/gates/hallucinated-imports-sveltekit.test.js +0 -132
- package/dist/gates/hallucinated-imports.test.d.ts +0 -1
- package/dist/gates/hallucinated-imports.test.js +0 -1206
- package/dist/gates/js-style-context.test.d.ts +0 -1
- package/dist/gates/js-style-context.test.js +0 -35
- package/dist/gates/logic-drift.test.d.ts +0 -1
- package/dist/gates/logic-drift.test.js +0 -52
- package/dist/gates/phantom-apis.test.d.ts +0 -1
- package/dist/gates/phantom-apis.test.js +0 -396
- package/dist/gates/promise-safety.test.d.ts +0 -1
- package/dist/gates/promise-safety.test.js +0 -34
- package/dist/gates/runner.test.d.ts +0 -1
- package/dist/gates/runner.test.js +0 -77
- package/dist/gates/scoped-gates.test.d.ts +0 -1
- package/dist/gates/scoped-gates.test.js +0 -52
- package/dist/gates/security-patterns-owasp.test.d.ts +0 -1
- package/dist/gates/security-patterns-owasp.test.js +0 -186
- package/dist/gates/security-patterns.test.d.ts +0 -1
- package/dist/gates/security-patterns.test.js +0 -194
- package/dist/gates/semantic-bugs.test.d.ts +0 -1
- package/dist/gates/semantic-bugs.test.js +0 -76
- package/dist/gates/side-effect-analysis.test.d.ts +0 -1
- package/dist/gates/side-effect-analysis.test.js +0 -162
- package/dist/gates/style-drift.test.d.ts +0 -1
- package/dist/gates/style-drift.test.js +0 -26
- package/dist/gates/test-quality.test.d.ts +0 -1
- package/dist/gates/test-quality.test.js +0 -325
- package/dist/gates/trusted-reviews.test.d.ts +0 -1
- package/dist/gates/trusted-reviews.test.js +0 -16
- package/dist/gates/unindexed-reads/queries.test.d.ts +0 -1
- package/dist/gates/unindexed-reads/queries.test.js +0 -54
- package/dist/gates/unindexed-reads/schema.test.d.ts +0 -1
- package/dist/gates/unindexed-reads/schema.test.js +0 -81
- package/dist/gates/unindexed-reads/unindexed-reads.test.d.ts +0 -1
- package/dist/gates/unindexed-reads/unindexed-reads.test.js +0 -90
- package/dist/hooks/checker.test.d.ts +0 -1
- package/dist/hooks/checker.test.js +0 -159
- package/dist/hooks/dlp-confidence.test.d.ts +0 -1
- package/dist/hooks/dlp-confidence.test.js +0 -51
- package/dist/hooks/dlp-feedback.test.d.ts +0 -1
- package/dist/hooks/dlp-feedback.test.js +0 -131
- package/dist/hooks/input-validator.test.d.ts +0 -1
- package/dist/hooks/input-validator.test.js +0 -329
- package/dist/hooks/templates.test.d.ts +0 -1
- package/dist/hooks/templates.test.js +0 -27
- package/dist/inference/brain-placeholder.test.d.ts +0 -1
- package/dist/inference/brain-placeholder.test.js +0 -28
- package/dist/inference/cloud-provider.test.d.ts +0 -1
- package/dist/inference/cloud-provider.test.js +0 -139
- package/dist/inference/executable.test.d.ts +0 -1
- package/dist/inference/executable.test.js +0 -41
- package/dist/inference/http-download.test.d.ts +0 -1
- package/dist/inference/http-download.test.js +0 -109
- package/dist/inference/llama-engine-checksum.test.d.ts +0 -1
- package/dist/inference/llama-engine-checksum.test.js +0 -27
- package/dist/inference/llama-engine.test.d.ts +0 -1
- package/dist/inference/llama-engine.test.js +0 -51
- package/dist/inference/llama-process.test.d.ts +0 -1
- package/dist/inference/llama-process.test.js +0 -61
- package/dist/inference/local-model.test.d.ts +0 -1
- package/dist/inference/local-model.test.js +0 -23
- package/dist/inference/model-download.test.d.ts +0 -1
- package/dist/inference/model-download.test.js +0 -125
- package/dist/inference/model-manager.test.d.ts +0 -1
- package/dist/inference/model-manager.test.js +0 -24
- package/dist/inference/types.test.d.ts +0 -1
- package/dist/inference/types.test.js +0 -19
- package/dist/memory/recall.test.d.ts +0 -1
- package/dist/memory/recall.test.js +0 -36
- package/dist/pattern-index/indexer.test.d.ts +0 -6
- package/dist/pattern-index/indexer.test.js +0 -197
- package/dist/pattern-index/matcher.test.d.ts +0 -6
- package/dist/pattern-index/matcher.test.js +0 -238
- package/dist/pattern-index/pattern-reuse.test.d.ts +0 -1
- package/dist/pattern-index/pattern-reuse.test.js +0 -76
- package/dist/pattern-index/semantic-runtime.test.d.ts +0 -1
- package/dist/pattern-index/semantic-runtime.test.js +0 -31
- package/dist/pattern-index/staleness.test.d.ts +0 -6
- package/dist/pattern-index/staleness.test.js +0 -211
- package/dist/review/agent-fixes.test.d.ts +0 -1
- package/dist/review/agent-fixes.test.js +0 -32
- package/dist/review/backtest-init.test.d.ts +0 -1
- package/dist/review/backtest-init.test.js +0 -136
- package/dist/review/backtest-judges.test.d.ts +0 -1
- package/dist/review/backtest-judges.test.js +0 -32
- package/dist/review/backtest-last.test.d.ts +0 -1
- package/dist/review/backtest-last.test.js +0 -109
- package/dist/review/backtest.test.d.ts +0 -1
- package/dist/review/backtest.test.js +0 -183
- package/dist/review/baseline.test.d.ts +0 -1
- package/dist/review/baseline.test.js +0 -22
- package/dist/review/branch-checks.test.d.ts +0 -1
- package/dist/review/branch-checks.test.js +0 -48
- package/dist/review/check-outcomes.test.d.ts +0 -1
- package/dist/review/check-outcomes.test.js +0 -56
- package/dist/review/code-patterns.test.d.ts +0 -1
- package/dist/review/code-patterns.test.js +0 -142
- package/dist/review/dead-code.test.d.ts +0 -1
- package/dist/review/dead-code.test.js +0 -154
- package/dist/review/deep-runs.test.d.ts +0 -1
- package/dist/review/deep-runs.test.js +0 -23
- package/dist/review/effectiveness.test.d.ts +0 -1
- package/dist/review/effectiveness.test.js +0 -42
- package/dist/review/fix-scope.test.d.ts +0 -1
- package/dist/review/fix-scope.test.js +0 -104
- package/dist/review/generated-files.test.d.ts +0 -1
- package/dist/review/generated-files.test.js +0 -25
- package/dist/review/migration-order.test.d.ts +0 -1
- package/dist/review/migration-order.test.js +0 -62
- package/dist/review/quiet.test.d.ts +0 -1
- package/dist/review/quiet.test.js +0 -38
- package/dist/review/receipt.test.d.ts +0 -1
- package/dist/review/receipt.test.js +0 -60
- package/dist/review/review-task.test.d.ts +0 -1
- package/dist/review/review-task.test.js +0 -89
- package/dist/review/review.test.d.ts +0 -1
- package/dist/review/review.test.js +0 -203
- package/dist/review/reviewer/adapters.test.d.ts +0 -1
- package/dist/review/reviewer/adapters.test.js +0 -100
- package/dist/review/reviewer/api-judge.test.d.ts +0 -1
- package/dist/review/reviewer/api-judge.test.js +0 -108
- package/dist/review/reviewer/background.test.d.ts +0 -1
- package/dist/review/reviewer/background.test.js +0 -118
- package/dist/review/reviewer/context.test.d.ts +0 -1
- package/dist/review/reviewer/context.test.js +0 -45
- package/dist/review/reviewer/exec.test.d.ts +0 -1
- package/dist/review/reviewer/exec.test.js +0 -59
- package/dist/review/reviewer/inputs.test.d.ts +0 -1
- package/dist/review/reviewer/inputs.test.js +0 -52
- package/dist/review/reviewer/panel.test.d.ts +0 -1
- package/dist/review/reviewer/panel.test.js +0 -110
- package/dist/review/reviewer/record.test.d.ts +0 -1
- package/dist/review/reviewer/record.test.js +0 -40
- package/dist/review/reviewer/rule-writer.test.d.ts +0 -1
- package/dist/review/reviewer/rule-writer.test.js +0 -52
- package/dist/review/reviewer/settings.test.d.ts +0 -1
- package/dist/review/reviewer/settings.test.js +0 -57
- package/dist/review/reviewer/usage.test.d.ts +0 -1
- package/dist/review/reviewer/usage.test.js +0 -14
- package/dist/review/reviewer.test.d.ts +0 -1
- package/dist/review/reviewer.test.js +0 -792
- package/dist/review/stories.test.d.ts +0 -1
- package/dist/review/stories.test.js +0 -58
- package/dist/review/toolchain.test.d.ts +0 -1
- package/dist/review/toolchain.test.js +0 -108
- package/dist/review/typed/redundancy.test.d.ts +0 -1
- package/dist/review/typed/redundancy.test.js +0 -315
- package/dist/review/typed/schema-nullability.test.d.ts +0 -1
- package/dist/review/typed/schema-nullability.test.js +0 -63
- package/dist/review-learning/human-edits.test.d.ts +0 -1
- package/dist/review-learning/human-edits.test.js +0 -47
- package/dist/review-learning/repo-rules.test.d.ts +0 -1
- package/dist/review-learning/repo-rules.test.js +0 -93
- package/dist/review-learning/review-learning.test.d.ts +0 -1
- package/dist/review-learning/review-learning.test.js +0 -249
- package/dist/safety.test.d.ts +0 -1
- package/dist/safety.test.js +0 -42
- package/dist/semantic/benchmark.test.d.ts +0 -1
- package/dist/semantic/benchmark.test.js +0 -22
- package/dist/semantic/intent/intent.test.d.ts +0 -1
- package/dist/semantic/intent/intent.test.js +0 -46
- package/dist/semantic/learn/learn.test.d.ts +0 -1
- package/dist/semantic/learn/learn.test.js +0 -67
- package/dist/semantic/origins.test.d.ts +0 -1
- package/dist/semantic/origins.test.js +0 -77
- package/dist/semantic/project-facts.test.d.ts +0 -1
- package/dist/semantic/project-facts.test.js +0 -45
- package/dist/semantic/sites/call-sites.test.d.ts +0 -1
- package/dist/semantic/sites/call-sites.test.js +0 -46
- package/dist/services/adaptive-thresholds.test.d.ts +0 -1
- package/dist/services/adaptive-thresholds.test.js +0 -53
- package/dist/services/agent-history.test.d.ts +0 -1
- package/dist/services/agent-history.test.js +0 -69
- package/dist/services/context-scope-summary.test.d.ts +0 -1
- package/dist/services/context-scope-summary.test.js +0 -17
- package/dist/services/context-telemetry-service.test.d.ts +0 -1
- package/dist/services/context-telemetry-service.test.js +0 -182
- package/dist/services/cursor-usage-sync.test.d.ts +0 -1
- package/dist/services/cursor-usage-sync.test.js +0 -173
- package/dist/services/engineering-knowledge-graph.test.d.ts +0 -1
- package/dist/services/engineering-knowledge-graph.test.js +0 -76
- package/dist/services/model-pricing.test.d.ts +0 -1
- package/dist/services/model-pricing.test.js +0 -44
- package/dist/services/observed-savings.test.d.ts +0 -1
- package/dist/services/observed-savings.test.js +0 -37
- package/dist/services/score-history.test.d.ts +0 -1
- package/dist/services/score-history.test.js +0 -61
- package/dist/smoke.test.d.ts +0 -1
- package/dist/smoke.test.js +0 -17
- package/dist/storage/cache-cleanup.test.d.ts +0 -1
- package/dist/storage/cache-cleanup.test.js +0 -54
- package/dist/storage/context-telemetry.test.d.ts +0 -1
- package/dist/storage/context-telemetry.test.js +0 -80
- package/dist/storage/db.test.d.ts +0 -1
- package/dist/storage/db.test.js +0 -46
- package/dist/storage/fix-lessons.test.d.ts +0 -1
- package/dist/storage/fix-lessons.test.js +0 -61
- package/dist/storage/lessons.test.d.ts +0 -1
- package/dist/storage/lessons.test.js +0 -81
- package/dist/storage/local-encryption.test.d.ts +0 -1
- package/dist/storage/local-encryption.test.js +0 -34
- package/dist/storage/local-memory.test.d.ts +0 -1
- package/dist/storage/local-memory.test.js +0 -55
- package/dist/storage/share-memory.test.d.ts +0 -1
- package/dist/storage/share-memory.test.js +0 -34
- package/dist/storage/team-diagnostics.test.d.ts +0 -1
- package/dist/storage/team-diagnostics.test.js +0 -51
- package/dist/storage/team-scope.test.d.ts +0 -1
- package/dist/storage/team-scope.test.js +0 -22
- package/dist/storage/team-store.test.d.ts +0 -1
- package/dist/storage/team-store.test.js +0 -11
- package/dist/storage/team-sync-scope.test.d.ts +0 -1
- package/dist/storage/team-sync-scope.test.js +0 -100
- package/dist/storage/team-vector-store.test.d.ts +0 -1
- package/dist/storage/team-vector-store.test.js +0 -56
- package/dist/storage/telemetry-scope.test.d.ts +0 -1
- package/dist/storage/telemetry-scope.test.js +0 -38
- package/dist/task/thread.test.d.ts +0 -1
- package/dist/task/thread.test.js +0 -133
- package/dist/telemetry/telemetry.test.d.ts +0 -1
- package/dist/telemetry/telemetry.test.js +0 -64
- package/dist/types/index.test.d.ts +0 -1
- package/dist/types/index.test.js +0 -33
- package/dist/utils/command-line.test.d.ts +0 -1
- package/dist/utils/command-line.test.js +0 -8
- package/dist/utils/diff-removed.test.d.ts +0 -1
- package/dist/utils/diff-removed.test.js +0 -29
- package/dist/utils/diff.test.d.ts +0 -1
- package/dist/utils/diff.test.js +0 -38
- package/dist/utils/glob-paths.test.d.ts +0 -1
- package/dist/utils/glob-paths.test.js +0 -40
- package/dist/utils/profile.test.d.ts +0 -1
- package/dist/utils/profile.test.js +0 -68
- package/dist/utils/scanner.test.d.ts +0 -1
- package/dist/utils/scanner.test.js +0 -48
- package/dist/utils/scope.test.d.ts +0 -1
- package/dist/utils/scope.test.js +0 -38
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
import fs from 'fs';
|
|
2
|
-
import os from 'os';
|
|
3
|
-
import path from 'path';
|
|
4
|
-
import ts from 'typescript';
|
|
5
|
-
import { afterEach, describe, expect, it } from 'vitest';
|
|
6
|
-
import { forEachNode, symbolOf } from './ast.js';
|
|
7
|
-
import { originsOf } from './origins.js';
|
|
8
|
-
import { programBatches } from './program.js';
|
|
9
|
-
let dir;
|
|
10
|
-
afterEach(() => { if (dir)
|
|
11
|
-
fs.rmSync(dir, { recursive: true, force: true }); dir = undefined; });
|
|
12
|
-
/** Program over `files`; returns the checker and a finder for `probe(<expr>)` arguments in main.ts. */
|
|
13
|
-
function setup(files) {
|
|
14
|
-
dir = fs.mkdtempSync(path.join(os.tmpdir(), 'origins-'));
|
|
15
|
-
for (const [name, body] of Object.entries(files))
|
|
16
|
-
fs.writeFileSync(path.join(dir, name), body);
|
|
17
|
-
const [program] = [...programBatches([path.join(dir, 'main.ts')], { strict: true, noEmit: true })];
|
|
18
|
-
const checker = program.getTypeChecker();
|
|
19
|
-
const main = program.getSourceFile(path.join(dir, 'main.ts'));
|
|
20
|
-
const probe = () => {
|
|
21
|
-
let found;
|
|
22
|
-
forEachNode(main, (n) => {
|
|
23
|
-
if (ts.isCallExpression(n) && ts.isIdentifier(n.expression) && n.expression.text === 'probe')
|
|
24
|
-
found = n.arguments[0];
|
|
25
|
-
});
|
|
26
|
-
return found;
|
|
27
|
-
};
|
|
28
|
-
const kinds = () => originsOf(checker, probe()).map(o => o.kind === 'call' ? `call:${o.node.expression.getText()}` : o.kind === 'param' ? `param:${o.index}` : o.kind);
|
|
29
|
-
return { kinds };
|
|
30
|
-
}
|
|
31
|
-
const PRELUDE = 'declare function probe(v: unknown): void;\ndeclare function a(): number;\ndeclare function b(): number;\n';
|
|
32
|
-
describe('originsOf', () => {
|
|
33
|
-
it('follows const initializers and let reassignments', () => {
|
|
34
|
-
const { kinds } = setup({ 'main.ts': `${PRELUDE}let x = a();\nif (Math.random()) x = b();\nconst y = x;\nprobe(y);\n` });
|
|
35
|
-
expect(kinds().sort()).toEqual(['call:a', 'call:b']);
|
|
36
|
-
});
|
|
37
|
-
it('maps an element of Promise.all([...]) to the matching call', async () => {
|
|
38
|
-
const { kinds } = setup({ 'main.ts': `${PRELUDE}async function f() {\n const [first, second] = await Promise.all([a(), b()]);\n probe(second);\n return first;\n}\n` });
|
|
39
|
-
expect(kinds()).toEqual(['call:b']);
|
|
40
|
-
});
|
|
41
|
-
it('reads a destructured property from an object literal', () => {
|
|
42
|
-
const { kinds } = setup({ 'main.ts': `${PRELUDE}const obj = { left: a(), right: b() };\nconst { right } = obj;\nprobe(right);\n` });
|
|
43
|
-
expect(kinds()).toEqual(['call:b']);
|
|
44
|
-
});
|
|
45
|
-
it('keeps both sides of ?? and of a conditional', () => {
|
|
46
|
-
const { kinds } = setup({ 'main.ts': `${PRELUDE}const v = Math.random() > 0.5 ? a() : (b() ?? a());\nprobe(v);\n` });
|
|
47
|
-
expect(kinds().sort()).toEqual(['call:a', 'call:a', 'call:b']);
|
|
48
|
-
});
|
|
49
|
-
it('reports a parameter with its index', () => {
|
|
50
|
-
const { kinds } = setup({ 'main.ts': `${PRELUDE}function f(first: number, second: number) {\n probe(second);\n return first;\n}\n` });
|
|
51
|
-
expect(kinds()).toEqual(['param:1']);
|
|
52
|
-
});
|
|
53
|
-
it('follows imports across files to the declaration', () => {
|
|
54
|
-
const { kinds } = setup({
|
|
55
|
-
'lib.ts': 'export const shared = Math.max(1, 2);\n',
|
|
56
|
-
'main.ts': `${PRELUDE}import { shared } from './lib';\nprobe(shared);\n`,
|
|
57
|
-
});
|
|
58
|
-
expect(kinds()).toEqual(['call:Math.max']);
|
|
59
|
-
});
|
|
60
|
-
it('stays unknown for an import that does not resolve', () => {
|
|
61
|
-
const { kinds } = setup({ 'main.ts': `${PRELUDE}import { missing } from './nowhere';\nprobe(missing);\n` });
|
|
62
|
-
expect(kinds()).toEqual(['unknown']);
|
|
63
|
-
});
|
|
64
|
-
});
|
|
65
|
-
describe('symbolOf', () => {
|
|
66
|
-
it('resolves the name in a shorthand property to the variable it reads', () => {
|
|
67
|
-
dir = fs.mkdtempSync(path.join(os.tmpdir(), 'origins-'));
|
|
68
|
-
fs.writeFileSync(path.join(dir, 'main.ts'), "const headers = { 'x-token': 't' };\nexport const init = { headers };\n");
|
|
69
|
-
const [program] = [...programBatches([path.join(dir, 'main.ts')], { strict: true, noEmit: true })];
|
|
70
|
-
const main = program.getSourceFile(path.join(dir, 'main.ts'));
|
|
71
|
-
let shorthand;
|
|
72
|
-
forEachNode(main, (n) => { if (ts.isShorthandPropertyAssignment(n))
|
|
73
|
-
shorthand = n; });
|
|
74
|
-
const decl = symbolOf(program.getTypeChecker(), shorthand.name)?.valueDeclaration;
|
|
75
|
-
expect(decl && ts.isVariableDeclaration(decl) && decl.name.getText()).toBe('headers');
|
|
76
|
-
});
|
|
77
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import fs from 'fs';
|
|
2
|
-
import os from 'os';
|
|
3
|
-
import path from 'path';
|
|
4
|
-
import { afterEach, describe, expect, it } from 'vitest';
|
|
5
|
-
import { ProjectFacts } from './project-facts.js';
|
|
6
|
-
let root;
|
|
7
|
-
afterEach(() => { if (root)
|
|
8
|
-
fs.rmSync(root, { recursive: true, force: true }); root = undefined; });
|
|
9
|
-
function write(files) {
|
|
10
|
-
root = fs.mkdtempSync(path.join(os.tmpdir(), 'project-facts-'));
|
|
11
|
-
for (const [name, text] of Object.entries(files)) {
|
|
12
|
-
fs.mkdirSync(path.dirname(path.join(root, name)), { recursive: true });
|
|
13
|
-
fs.writeFileSync(path.join(root, name), text);
|
|
14
|
-
}
|
|
15
|
-
return root;
|
|
16
|
-
}
|
|
17
|
-
describe('ProjectFacts', () => {
|
|
18
|
-
it('reads the nearest package.json, so each monorepo package is judged by its own', () => {
|
|
19
|
-
const dir = write({
|
|
20
|
-
'package.json': JSON.stringify({ name: 'root', devDependencies: { vite: '^5.0.0' } }),
|
|
21
|
-
'packages/ui/package.json': JSON.stringify({ name: '@x/ui', peerDependencies: { 'solid-js': '^1.8.0' } }),
|
|
22
|
-
'packages/ui/src/a.tsx': '',
|
|
23
|
-
});
|
|
24
|
-
const facts = new ProjectFacts(dir);
|
|
25
|
-
expect(facts.declares('packages/ui/src/a.tsx', 'solid-js')).toBe(true);
|
|
26
|
-
expect(facts.declares('packages/ui/src/a.tsx', 'vite')).toBe(false);
|
|
27
|
-
expect(facts.majorVersion('packages/ui/src/a.tsx', 'solid-js')).toBe(1);
|
|
28
|
-
expect(facts.packageName('packages/ui/src/a.tsx')).toBe('@x/ui');
|
|
29
|
-
expect(facts.packageDir('packages/ui/src/a.tsx')).toBe(path.join(dir, 'packages/ui'));
|
|
30
|
-
});
|
|
31
|
-
it('never reads a manifest above cwd', () => {
|
|
32
|
-
const dir = write({ 'package.json': JSON.stringify({ dependencies: { react: '^19.0.0' } }), 'app/src/a.tsx': '' });
|
|
33
|
-
const facts = new ProjectFacts(path.join(dir, 'app'));
|
|
34
|
-
expect(facts.dependencies('src/a.tsx').size).toBe(0);
|
|
35
|
-
expect(facts.packageDir('src/a.tsx')).toBeUndefined();
|
|
36
|
-
});
|
|
37
|
-
it('resolves compiler options through tsconfig extends', () => {
|
|
38
|
-
const dir = write({
|
|
39
|
-
'tsconfig.base.json': JSON.stringify({ compilerOptions: { stripInternal: true } }),
|
|
40
|
-
'pkg/tsconfig.json': JSON.stringify({ extends: '../tsconfig.base.json' }),
|
|
41
|
-
'pkg/src/a.ts': '',
|
|
42
|
-
});
|
|
43
|
-
expect(new ProjectFacts(dir).compilerOptions('pkg/src/a.ts').stripInternal).toBe(true);
|
|
44
|
-
});
|
|
45
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import fs from 'fs';
|
|
2
|
-
import os from 'os';
|
|
3
|
-
import path from 'path';
|
|
4
|
-
import { afterEach, describe, expect, it } from 'vitest';
|
|
5
|
-
import { exportCallSites } from './export.js';
|
|
6
|
-
let dir;
|
|
7
|
-
afterEach(() => { if (dir)
|
|
8
|
-
fs.rmSync(dir, { recursive: true, force: true }); dir = undefined; });
|
|
9
|
-
function sites(code) {
|
|
10
|
-
dir = fs.mkdtempSync(path.join(os.tmpdir(), 'call-sites-'));
|
|
11
|
-
fs.writeFileSync(path.join(dir, 'main.ts'), code);
|
|
12
|
-
return exportCallSites(dir, ['main.ts']).map(s => [s.function, s.callee, s.ordinal, s.handledBy]);
|
|
13
|
-
}
|
|
14
|
-
const DECLS = 'declare function a(): Promise<number>;\ndeclare function b(): Promise<number>;\n';
|
|
15
|
-
describe('findCallSites', () => {
|
|
16
|
-
it('reports awaited calls and says how each handles failure', () => {
|
|
17
|
-
expect(sites(`${DECLS}
|
|
18
|
-
export async function load() {
|
|
19
|
-
const x = await a();
|
|
20
|
-
try { await b(); } catch { return 0; }
|
|
21
|
-
const y = await a().catch(() => 0);
|
|
22
|
-
return x + y;
|
|
23
|
-
}`)).toEqual([
|
|
24
|
-
['load', 'a', 0, null],
|
|
25
|
-
['load', 'b', 0, 'try'],
|
|
26
|
-
['load', 'a', 1, 'call'],
|
|
27
|
-
]);
|
|
28
|
-
});
|
|
29
|
-
it('treats each element of Promise.all as a site, and allSettled as handled', () => {
|
|
30
|
-
expect(sites(`${DECLS}
|
|
31
|
-
export async function both() {
|
|
32
|
-
const [x, y] = await Promise.all([a(), b()]);
|
|
33
|
-
const settled = await Promise.allSettled([a()]);
|
|
34
|
-
return [x, y, settled];
|
|
35
|
-
}`)).toEqual([
|
|
36
|
-
['both', 'a', 0, null],
|
|
37
|
-
['both', 'b', 0, null],
|
|
38
|
-
['both', 'a', 1, 'all-settled'],
|
|
39
|
-
]);
|
|
40
|
-
});
|
|
41
|
-
it('counts a callee that catches and returns as handled', () => {
|
|
42
|
-
expect(sites(`${DECLS}
|
|
43
|
-
async function safeA() { try { return await a(); } catch { return 0; } }
|
|
44
|
-
export async function use() { return await safeA(); }`)).toContainEqual(['use', 'safeA', 0, 'call']);
|
|
45
|
-
});
|
|
46
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
2
|
-
import { recordGateRun, getQualityTrend, clearAdaptiveHistory, } from './adaptive-thresholds.js';
|
|
3
|
-
import * as fs from 'fs';
|
|
4
|
-
import * as path from 'path';
|
|
5
|
-
import * as os from 'os';
|
|
6
|
-
describe('AdaptiveThresholds', () => {
|
|
7
|
-
let testDir;
|
|
8
|
-
beforeEach(() => {
|
|
9
|
-
testDir = fs.mkdtempSync(path.join(os.tmpdir(), 'adaptive-test-'));
|
|
10
|
-
});
|
|
11
|
-
afterEach(() => {
|
|
12
|
-
clearAdaptiveHistory(testDir);
|
|
13
|
-
fs.rmSync(testDir, { recursive: true, force: true });
|
|
14
|
-
});
|
|
15
|
-
describe('historical tracking', () => {
|
|
16
|
-
it('should record gate runs', () => {
|
|
17
|
-
recordGateRun(testDir, 5, 2, 10);
|
|
18
|
-
recordGateRun(testDir, 6, 1, 5);
|
|
19
|
-
const historyPath = path.join(testDir, '.rigour', 'adaptive-history.json');
|
|
20
|
-
expect(fs.existsSync(historyPath)).toBe(true);
|
|
21
|
-
const history = JSON.parse(fs.readFileSync(historyPath, 'utf-8'));
|
|
22
|
-
expect(history.runs).toHaveLength(2);
|
|
23
|
-
});
|
|
24
|
-
it('should return stable trend for new projects', () => {
|
|
25
|
-
const trend = getQualityTrend(testDir);
|
|
26
|
-
expect(trend).toBe('stable');
|
|
27
|
-
});
|
|
28
|
-
it('should detect improving trend', () => {
|
|
29
|
-
// Baseline: 15 runs with high failures (with variance for valid std dev)
|
|
30
|
-
for (let i = 0; i < 15; i++) {
|
|
31
|
-
recordGateRun(testDir, 3, 5, 15 + (i % 5) * 3); // 15,18,21,24,27 repeating
|
|
32
|
-
}
|
|
33
|
-
// Recent: 5 runs with very low failures (clear improvement)
|
|
34
|
-
for (let i = 0; i < 5; i++) {
|
|
35
|
-
recordGateRun(testDir, 7, 0, 1);
|
|
36
|
-
}
|
|
37
|
-
const trend = getQualityTrend(testDir);
|
|
38
|
-
expect(trend).toBe('improving');
|
|
39
|
-
});
|
|
40
|
-
it('should detect degrading trend', () => {
|
|
41
|
-
// Baseline: 15 runs with low failures (with variance for valid std dev)
|
|
42
|
-
for (let i = 0; i < 15; i++) {
|
|
43
|
-
recordGateRun(testDir, 7, 1, 1 + (i % 3)); // 1,2,3 repeating
|
|
44
|
-
}
|
|
45
|
-
// Recent: 5 runs with high failures (clear degradation)
|
|
46
|
-
for (let i = 0; i < 5; i++) {
|
|
47
|
-
recordGateRun(testDir, 3, 5, 25);
|
|
48
|
-
}
|
|
49
|
-
const trend = getQualityTrend(testDir);
|
|
50
|
-
expect(trend).toBe('degrading');
|
|
51
|
-
});
|
|
52
|
-
});
|
|
53
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest';
|
|
2
|
-
import { buildAgentRuns, normalizeAgentEvent, normalizeAgentEvents } from './agent-history.js';
|
|
3
|
-
describe('agent history', () => {
|
|
4
|
-
it('normalizes incomplete historical records without dropping them', () => {
|
|
5
|
-
const event = normalizeAgentEvent({ type: 'tool_error', arguments: { files: ['src/a.ts'] } });
|
|
6
|
-
expect(event.agentId).toBe('unknown-agent');
|
|
7
|
-
expect(event.outcome).toBe('error');
|
|
8
|
-
expect(event.files).toEqual(['src/a.ts']);
|
|
9
|
-
});
|
|
10
|
-
it('groups events into stable runs and retains outcomes', () => {
|
|
11
|
-
const events = [
|
|
12
|
-
normalizeAgentEvent({ id: '1', sessionId: 's1', agentId: 'a1', timestamp: '2026-01-01T00:00:00Z', tool: 'read' }),
|
|
13
|
-
normalizeAgentEvent({ id: '2', sessionId: 's1', agentId: 'a1', timestamp: '2026-01-01T00:01:00Z', type: 'completed', files: ['src/a.ts'] }),
|
|
14
|
-
];
|
|
15
|
-
expect(buildAgentRuns(events)).toMatchObject([{ id: 's1', eventCount: 2, status: 'success', files: ['src/a.ts'] }]);
|
|
16
|
-
});
|
|
17
|
-
it('normalizes guidance safely and builds an honest impact receipt', () => {
|
|
18
|
-
const events = [normalizeAgentEvent({
|
|
19
|
-
id: 'response-1', requestId: 'request-1', agentId: 'agent-1', timestamp: '2026-01-01T00:00:00Z',
|
|
20
|
-
type: 'tool_response', status: 'success',
|
|
21
|
-
guidance: {
|
|
22
|
-
kind: 'context-scope',
|
|
23
|
-
recommendation: 'Read only the two evidence-backed files.',
|
|
24
|
-
patternRefs: [{ id: 'p1', label: 'withTransaction' }, { bad: true }],
|
|
25
|
-
lessonRefs: [{ id: 'l1', label: 'Bound retries' }],
|
|
26
|
-
selectedFiles: ['src/a.ts', 42],
|
|
27
|
-
excludedFileCount: 18,
|
|
28
|
-
},
|
|
29
|
-
telemetry: {
|
|
30
|
-
candidateTokens: 2400,
|
|
31
|
-
returnedTokens: 400,
|
|
32
|
-
candidateFiles: 20,
|
|
33
|
-
returnedFiles: 2,
|
|
34
|
-
cacheStatus: 'exact-hit',
|
|
35
|
-
classification: 'measured estimate',
|
|
36
|
-
},
|
|
37
|
-
})];
|
|
38
|
-
expect(events[0].guidance?.selectedFiles).toEqual(['src/a.ts']);
|
|
39
|
-
expect(buildAgentRuns(events)[0].impact).toMatchObject({
|
|
40
|
-
guidanceCount: 1,
|
|
41
|
-
knowledgeItems: 2,
|
|
42
|
-
avoidedTokens: 2000,
|
|
43
|
-
excludedFiles: 18,
|
|
44
|
-
cacheHits: 1,
|
|
45
|
-
});
|
|
46
|
-
});
|
|
47
|
-
it('ignores malformed guidance rather than breaking legacy history', () => {
|
|
48
|
-
const event = normalizeAgentEvent({ guidance: { kind: 'context-scope', recommendation: 42 }, telemetry: 'bad' });
|
|
49
|
-
expect(event.guidance).toBeUndefined();
|
|
50
|
-
expect(event.telemetry).toBeUndefined();
|
|
51
|
-
});
|
|
52
|
-
});
|
|
53
|
-
describe('normalizeAgentEvents', () => {
|
|
54
|
-
it('carries request identity into the matching response', () => {
|
|
55
|
-
const events = normalizeAgentEvents([
|
|
56
|
-
{
|
|
57
|
-
type: 'tool_call', requestId: 'request-1', tool: 'rigour_checkpoint',
|
|
58
|
-
timestamp: '2026-09-10T00:00:00Z',
|
|
59
|
-
arguments: { agentId: 'agent-a', taskId: 'task-a', filesChanged: ['src/a.ts'] },
|
|
60
|
-
},
|
|
61
|
-
{
|
|
62
|
-
type: 'tool_response', requestId: 'request-1', tool: 'rigour_checkpoint', status: 'success',
|
|
63
|
-
timestamp: '2026-09-10T00:00:01Z',
|
|
64
|
-
},
|
|
65
|
-
]);
|
|
66
|
-
expect(events[1]).toMatchObject({ agentId: 'agent-a', taskId: 'task-a', files: ['src/a.ts'] });
|
|
67
|
-
expect(buildAgentRuns(events)).toHaveLength(1);
|
|
68
|
-
});
|
|
69
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import fs from 'fs';
|
|
2
|
-
import os from 'os';
|
|
3
|
-
import path from 'path';
|
|
4
|
-
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
|
5
|
-
import { getContextScopeSummary } from './context-telemetry-service.js';
|
|
6
|
-
let root;
|
|
7
|
-
beforeEach(() => { root = fs.mkdtempSync(path.join(os.tmpdir(), 'scope-summary-')); });
|
|
8
|
-
afterEach(() => fs.rmSync(root, { recursive: true, force: true }));
|
|
9
|
-
describe('getContextScopeSummary', () => {
|
|
10
|
-
it('counts rule files and skips a rules directory such as .clinerules/', async () => {
|
|
11
|
-
fs.mkdirSync(path.join(root, '.clinerules'));
|
|
12
|
-
fs.writeFileSync(path.join(root, '.clinerules', 'rigour.md'), 'rules');
|
|
13
|
-
fs.writeFileSync(path.join(root, 'CLAUDE.md'), 'Use small PRs.');
|
|
14
|
-
const summary = await getContextScopeSummary(root);
|
|
15
|
-
expect(summary.alwaysOnRuleTokens).toBeGreaterThan(0);
|
|
16
|
-
});
|
|
17
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,182 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
|
2
|
-
import path from 'path';
|
|
3
|
-
import os from 'os';
|
|
4
|
-
import fs from 'fs-extra';
|
|
5
|
-
vi.mock('../storage/db.js', () => ({
|
|
6
|
-
isSQLiteAvailable: () => false,
|
|
7
|
-
openDatabase: async () => null,
|
|
8
|
-
DB_PATH: '/tmp/rigour-test.db',
|
|
9
|
-
RIGOUR_DIR: '/tmp/.rigour',
|
|
10
|
-
}));
|
|
11
|
-
import { getTaskContextStats, getTaskCostStats, getCacheStats, importCursorUsageCsv, importCursorUsageJson, getContextScopeSummary, getCheckpointSummary, estimateTokenCount, } from './context-telemetry-service.js';
|
|
12
|
-
import { recordContextEvent, recordCheckpointMetric } from '../storage/context-telemetry.js';
|
|
13
|
-
describe('context-telemetry-service', () => {
|
|
14
|
-
const testCwd = path.join(os.tmpdir(), `rigour-ctx-service-${Date.now()}-${Math.random().toString(36).slice(2)}`);
|
|
15
|
-
const taskId = `task-${Date.now()}`;
|
|
16
|
-
beforeEach(async () => {
|
|
17
|
-
await fs.ensureDir(path.join(testCwd, '.rigour'));
|
|
18
|
-
});
|
|
19
|
-
afterEach(async () => {
|
|
20
|
-
await fs.remove(testCwd);
|
|
21
|
-
});
|
|
22
|
-
it('returns zeroed stats when no telemetry exists for task', async () => {
|
|
23
|
-
const stats = await getTaskContextStats(taskId, testCwd);
|
|
24
|
-
expect(stats.retrievals).toBe(0);
|
|
25
|
-
expect(stats.candidateTokens).toBe(0);
|
|
26
|
-
expect(stats.potentialAvoidedTokens).toBe(0);
|
|
27
|
-
expect(stats.isEstimated).toBe(true);
|
|
28
|
-
});
|
|
29
|
-
it('calculates avoided context from recorded events', async () => {
|
|
30
|
-
await recordContextEvent({
|
|
31
|
-
taskId,
|
|
32
|
-
toolName: 'rigour_check_pattern',
|
|
33
|
-
cacheStatus: 'exact-hit',
|
|
34
|
-
candidateTokens: 10000,
|
|
35
|
-
returnedTokens: 2000,
|
|
36
|
-
deduplicatedTokens: 3000,
|
|
37
|
-
}, testCwd);
|
|
38
|
-
const stats = await getTaskContextStats(taskId, testCwd);
|
|
39
|
-
expect(stats.retrievals).toBe(1);
|
|
40
|
-
expect(stats.potentialAvoidedTokens).toBe(8000);
|
|
41
|
-
expect(stats.repeatedReadsPrevented).toBeGreaterThan(0);
|
|
42
|
-
expect(stats.deduplicatedTokens).toBe(3000);
|
|
43
|
-
expect(stats.isEstimated).toBe(false);
|
|
44
|
-
});
|
|
45
|
-
it('aggregates cache performance from events', async () => {
|
|
46
|
-
const cacheTaskId = `${taskId}-cache`;
|
|
47
|
-
await recordContextEvent({
|
|
48
|
-
taskId: cacheTaskId,
|
|
49
|
-
toolName: 'rigour_recall',
|
|
50
|
-
cacheStatus: 'exact-hit',
|
|
51
|
-
candidateTokens: 1000,
|
|
52
|
-
returnedTokens: 200,
|
|
53
|
-
}, testCwd);
|
|
54
|
-
await recordContextEvent({
|
|
55
|
-
taskId: cacheTaskId,
|
|
56
|
-
toolName: 'rigour_context_explain',
|
|
57
|
-
cacheStatus: 'miss',
|
|
58
|
-
candidateTokens: 500,
|
|
59
|
-
returnedTokens: 500,
|
|
60
|
-
}, testCwd);
|
|
61
|
-
const events = await import('../storage/context-telemetry.js').then(m => m.getContextEvents(cacheTaskId, testCwd));
|
|
62
|
-
const cache = await getCacheStats(testCwd);
|
|
63
|
-
const taskHits = events.filter(e => e.cacheStatus === 'exact-hit').length;
|
|
64
|
-
const taskMisses = events.filter(e => e.cacheStatus === 'miss').length;
|
|
65
|
-
expect(taskHits).toBe(1);
|
|
66
|
-
expect(taskMisses).toBe(1);
|
|
67
|
-
expect(cache.hitRate).toBe(0.5);
|
|
68
|
-
expect(cache.isEstimated).toBe(false);
|
|
69
|
-
});
|
|
70
|
-
it('imports CSV usage and marks cost stats as observed', async () => {
|
|
71
|
-
const csv = `Date,Model,Input Tokens,Output Tokens,Cost
|
|
72
|
-
2026-08-05,claude-3-5-sonnet,510000,62000,4.83`;
|
|
73
|
-
const imported = await importCursorUsageCsv(csv, testCwd);
|
|
74
|
-
expect(imported).toBe(1);
|
|
75
|
-
const cost = await getTaskCostStats('cursor-imported', testCwd);
|
|
76
|
-
expect(cost.actual.inputTokens).toBe(510000);
|
|
77
|
-
expect(cost.actual.costUsd).toBe(4.83);
|
|
78
|
-
expect(cost.actual.isEstimated).toBe(false);
|
|
79
|
-
expect(cost.actual.classification).toBe('observed');
|
|
80
|
-
});
|
|
81
|
-
it('deduplicates CSV rows on re-import', async () => {
|
|
82
|
-
const csv = `Date,Model,Input Tokens,Output Tokens,Cost
|
|
83
|
-
2026-08-05,claude-3-5-sonnet,1000,100,1.00`;
|
|
84
|
-
expect(await importCursorUsageCsv(csv, testCwd)).toBe(1);
|
|
85
|
-
expect(await importCursorUsageCsv(csv, testCwd)).toBe(0);
|
|
86
|
-
});
|
|
87
|
-
it('imports JSON usage records', async () => {
|
|
88
|
-
const jsonTaskId = `${taskId}-json-${Math.random().toString(36).slice(2)}`;
|
|
89
|
-
const imported = await importCursorUsageJson([{
|
|
90
|
-
taskId: jsonTaskId,
|
|
91
|
-
inputTokens: 2500,
|
|
92
|
-
outputTokens: 300,
|
|
93
|
-
observedCostUsd: 0.42,
|
|
94
|
-
model: 'gpt-4o',
|
|
95
|
-
}], testCwd);
|
|
96
|
-
expect(imported).toBe(1);
|
|
97
|
-
const cost = await getTaskCostStats(jsonTaskId, testCwd);
|
|
98
|
-
expect(cost.actual.inputTokens).toBe(2500);
|
|
99
|
-
});
|
|
100
|
-
it('imports Admin API JSON events with chargedCents and dedupes against sync IDs', async () => {
|
|
101
|
-
const adminEvent = {
|
|
102
|
-
timestamp: '1750979225854',
|
|
103
|
-
conversationId: 'conv-dedupe',
|
|
104
|
-
model: 'composer-2.5-standard',
|
|
105
|
-
chargedCents: 42.5,
|
|
106
|
-
tokenUsage: { inputTokens: 100, outputTokens: 50 },
|
|
107
|
-
};
|
|
108
|
-
expect(await importCursorUsageJson([adminEvent], testCwd)).toBe(1);
|
|
109
|
-
expect(await importCursorUsageJson([adminEvent], testCwd)).toBe(0);
|
|
110
|
-
const cost = await getTaskCostStats('conv-dedupe', testCwd);
|
|
111
|
-
expect(cost.actual.costUsd).toBeCloseTo(0.425, 3);
|
|
112
|
-
expect(cost.actual.isEstimated).toBe(false);
|
|
113
|
-
});
|
|
114
|
-
it('summarizes agent scope overlap from session file', async () => {
|
|
115
|
-
await fs.writeJson(path.join(testCwd, '.rigour', 'agent-session.json'), {
|
|
116
|
-
agents: [
|
|
117
|
-
{ agentId: 'agent-a', taskScope: ['src/api/**'] },
|
|
118
|
-
{ agentId: 'agent-b', taskScope: ['src/api/**', 'tests/**'] },
|
|
119
|
-
],
|
|
120
|
-
});
|
|
121
|
-
const scope = await getContextScopeSummary(testCwd);
|
|
122
|
-
expect(scope.activeAgentCount).toBe(2);
|
|
123
|
-
expect(scope.overlappingScopesResolved).toBeGreaterThan(0);
|
|
124
|
-
});
|
|
125
|
-
it('estimates governance rule token overhead from AGENTS.md', async () => {
|
|
126
|
-
await fs.writeFile(path.join(testCwd, 'AGENTS.md'), '# Agent rules\n'.repeat(40));
|
|
127
|
-
const scope = await getContextScopeSummary(testCwd);
|
|
128
|
-
expect(scope.alwaysOnRuleTokens).toBe(estimateTokenCount('# Agent rules\n'.repeat(40)));
|
|
129
|
-
});
|
|
130
|
-
it('aggregates checkpoint compression metrics', async () => {
|
|
131
|
-
const cpTaskId = `${taskId}-cp`;
|
|
132
|
-
await recordCheckpointMetric({
|
|
133
|
-
checkpointId: `checkpoint:${cpTaskId}:a1:phase`,
|
|
134
|
-
taskId: cpTaskId,
|
|
135
|
-
agentId: 'a1',
|
|
136
|
-
rawStateTokens: 10000,
|
|
137
|
-
checkpointTokens: 500,
|
|
138
|
-
replayTokensAvoided: 9500,
|
|
139
|
-
}, testCwd);
|
|
140
|
-
const summary = await getCheckpointSummary(cpTaskId, testCwd);
|
|
141
|
-
expect(summary.checkpointCount).toBe(1);
|
|
142
|
-
expect(summary.rawStateTokens).toBe(10000);
|
|
143
|
-
expect(summary.compressionRatio).toBe(20);
|
|
144
|
-
expect(summary.replayTokensAvoided).toBe(9500);
|
|
145
|
-
});
|
|
146
|
-
it('marks observed cost from usages and estimates avoided cost by model', async () => {
|
|
147
|
-
const jsonTaskId = `${taskId}-composer-${Math.random().toString(36).slice(2)}`;
|
|
148
|
-
await importCursorUsageJson([{
|
|
149
|
-
id: `json-composer-${jsonTaskId}`,
|
|
150
|
-
taskId: jsonTaskId,
|
|
151
|
-
inputTokens: 2_000_000,
|
|
152
|
-
outputTokens: 0,
|
|
153
|
-
observedCostUsd: 1.25,
|
|
154
|
-
model: 'composer-2.5-standard',
|
|
155
|
-
source: 'cursor-admin-api',
|
|
156
|
-
}], testCwd);
|
|
157
|
-
await recordContextEvent({
|
|
158
|
-
taskId: jsonTaskId,
|
|
159
|
-
toolName: 'rigour_context_scope',
|
|
160
|
-
cacheStatus: 'miss',
|
|
161
|
-
candidateTokens: 3_000_000,
|
|
162
|
-
returnedTokens: 1_000_000,
|
|
163
|
-
}, testCwd);
|
|
164
|
-
const cost = await getTaskCostStats(jsonTaskId, testCwd);
|
|
165
|
-
expect(cost.actual.isEstimated).toBe(false);
|
|
166
|
-
expect(cost.actual.costUsd).toBe(1.25);
|
|
167
|
-
expect(cost.estimated.isEstimated).toBe(true);
|
|
168
|
-
expect(cost.estimated.inputPricePerMillionUsd).toBe(0.5);
|
|
169
|
-
expect(cost.estimated.estimatedCostAvoidedUsd).toBeGreaterThan(0);
|
|
170
|
-
});
|
|
171
|
-
it('does not combine retrieval and checkpoint counterfactuals', async () => {
|
|
172
|
-
const id = `${taskId}-separate-${Math.random().toString(36).slice(2)}`;
|
|
173
|
-
await recordContextEvent({ taskId: id, toolName: 'rigour_context_scope', cacheStatus: 'miss', candidateTokens: 5000, returnedTokens: 1000 }, testCwd);
|
|
174
|
-
await recordCheckpointMetric({ checkpointId: `${id}-cp`, taskId: id, agentId: 'a1', rawStateTokens: 9000, checkpointTokens: 1000, replayTokensAvoided: 8000 }, testCwd);
|
|
175
|
-
const cost = await getTaskCostStats(id, testCwd);
|
|
176
|
-
expect(cost.estimated.retrievalAvoidedTokens).toBe(4000);
|
|
177
|
-
expect(cost.estimated.checkpointReplayAvoidedTokens).toBe(8000);
|
|
178
|
-
expect(cost.estimated.potentialContextAvoided).toBe(4000);
|
|
179
|
-
expect(cost.estimated.categoriesAreAdditive).toBe(false);
|
|
180
|
-
expect(cost.estimated.retrievalAvoidedCostRangeUsd?.max).toBeGreaterThan(cost.estimated.retrievalAvoidedCostRangeUsd?.min ?? 0);
|
|
181
|
-
});
|
|
182
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|