audrey 0.23.1 → 1.0.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/CHANGELOG.md +81 -19
- package/LICENSE +21 -21
- package/README.md +209 -5
- package/SECURITY.md +2 -1
- package/benchmarks/adapter-kit.mjs +20 -0
- package/benchmarks/adapter-self-test.mjs +166 -0
- package/benchmarks/adapters/example-allow.mjs +28 -0
- package/benchmarks/adapters/mem0-platform.mjs +267 -0
- package/benchmarks/adapters/registry.json +51 -0
- package/benchmarks/adapters/zep-cloud.mjs +280 -0
- package/benchmarks/baselines.js +169 -0
- package/benchmarks/build-leaderboard.mjs +170 -0
- package/benchmarks/cases.js +537 -0
- package/benchmarks/create-conformance-card.mjs +139 -0
- package/benchmarks/create-submission-bundle.mjs +176 -0
- package/benchmarks/dry-run-external-adapters.mjs +165 -0
- package/benchmarks/guardbench.js +1035 -0
- package/benchmarks/output/adapter-self-test/guardbench-adapter-self-test.json +50 -0
- package/benchmarks/output/external/guardbench-external-dry-run.json +69 -0
- package/benchmarks/output/external/guardbench-external-evidence.json +56 -0
- package/benchmarks/output/guardbench-conformance-card.json +63 -0
- package/benchmarks/output/guardbench-manifest.json +414 -0
- package/benchmarks/output/guardbench-raw.json +1171 -0
- package/benchmarks/output/guardbench-summary.json +1981 -0
- package/benchmarks/output/leaderboard/guardbench-leaderboard.json +93 -0
- package/benchmarks/output/leaderboard/guardbench-leaderboard.md +7 -0
- package/benchmarks/output/submission-bundle/guardbench-conformance-card.json +63 -0
- package/benchmarks/output/submission-bundle/guardbench-manifest.json +414 -0
- package/benchmarks/output/submission-bundle/guardbench-raw.json +1171 -0
- package/benchmarks/output/submission-bundle/guardbench-summary.json +1981 -0
- package/benchmarks/output/submission-bundle/schemas/guardbench-adapter-registry.schema.json +69 -0
- package/benchmarks/output/submission-bundle/schemas/guardbench-adapter-self-test.schema.json +156 -0
- package/benchmarks/output/submission-bundle/schemas/guardbench-conformance-card.schema.json +184 -0
- package/benchmarks/output/submission-bundle/schemas/guardbench-external-dry-run.schema.json +74 -0
- package/benchmarks/output/submission-bundle/schemas/guardbench-external-evidence.schema.json +108 -0
- package/benchmarks/output/submission-bundle/schemas/guardbench-external-run.schema.json +160 -0
- package/benchmarks/output/submission-bundle/schemas/guardbench-leaderboard.schema.json +179 -0
- package/benchmarks/output/submission-bundle/schemas/guardbench-manifest.schema.json +213 -0
- package/benchmarks/output/submission-bundle/schemas/guardbench-publication-verification.schema.json +47 -0
- package/benchmarks/output/submission-bundle/schemas/guardbench-raw.schema.json +164 -0
- package/benchmarks/output/submission-bundle/schemas/guardbench-submission-manifest.schema.json +151 -0
- package/benchmarks/output/submission-bundle/schemas/guardbench-summary.schema.json +228 -0
- package/benchmarks/output/submission-bundle/submission-manifest.json +131 -0
- package/benchmarks/output/submission-bundle/validation-report.json +31 -0
- package/benchmarks/output/summary.json +2354 -0
- package/benchmarks/perf-snapshot.js +304 -0
- package/benchmarks/perf.bench.js +161 -0
- package/benchmarks/public-paths.mjs +78 -0
- package/benchmarks/reference-results.js +70 -0
- package/benchmarks/report.js +259 -0
- package/benchmarks/run-external-guardbench.mjs +281 -0
- package/benchmarks/run.js +682 -0
- package/benchmarks/schemas/guardbench-adapter-registry.schema.json +69 -0
- package/benchmarks/schemas/guardbench-adapter-self-test.schema.json +156 -0
- package/benchmarks/schemas/guardbench-conformance-card.schema.json +184 -0
- package/benchmarks/schemas/guardbench-external-dry-run.schema.json +74 -0
- package/benchmarks/schemas/guardbench-external-evidence.schema.json +108 -0
- package/benchmarks/schemas/guardbench-external-run.schema.json +160 -0
- package/benchmarks/schemas/guardbench-leaderboard.schema.json +179 -0
- package/benchmarks/schemas/guardbench-manifest.schema.json +213 -0
- package/benchmarks/schemas/guardbench-publication-verification.schema.json +47 -0
- package/benchmarks/schemas/guardbench-raw.schema.json +164 -0
- package/benchmarks/schemas/guardbench-submission-manifest.schema.json +151 -0
- package/benchmarks/schemas/guardbench-summary.schema.json +228 -0
- package/benchmarks/snapshots/perf-0.22.2.json +123 -0
- package/benchmarks/snapshots/perf-0.23.0.json +123 -0
- package/benchmarks/validate-adapter-module.mjs +104 -0
- package/benchmarks/validate-adapter-registry.mjs +134 -0
- package/benchmarks/validate-adapter-self-test.mjs +96 -0
- package/benchmarks/validate-guardbench-artifacts.mjs +343 -0
- package/benchmarks/verify-external-evidence.mjs +296 -0
- package/benchmarks/verify-publication-artifacts.mjs +286 -0
- package/benchmarks/verify-submission-bundle.mjs +167 -0
- package/dist/mcp-server/config.d.ts +1 -1
- package/dist/mcp-server/config.d.ts.map +1 -1
- package/dist/mcp-server/config.js +1 -1
- package/dist/mcp-server/config.js.map +1 -1
- package/dist/mcp-server/index.d.ts +65 -3
- package/dist/mcp-server/index.d.ts.map +1 -1
- package/dist/mcp-server/index.js +675 -157
- package/dist/mcp-server/index.js.map +1 -1
- package/dist/src/action-key.d.ts +9 -0
- package/dist/src/action-key.d.ts.map +1 -0
- package/dist/src/action-key.js +49 -0
- package/dist/src/action-key.js.map +1 -0
- package/dist/src/adaptive.js +5 -5
- package/dist/src/affect.js +8 -8
- package/dist/src/audrey.d.ts +3 -0
- package/dist/src/audrey.d.ts.map +1 -1
- package/dist/src/audrey.js +55 -3
- package/dist/src/audrey.js.map +1 -1
- package/dist/src/capsule.js +4 -4
- package/dist/src/causal.js +3 -3
- package/dist/src/consolidate.js +48 -48
- package/dist/src/controller.d.ts +61 -5
- package/dist/src/controller.d.ts.map +1 -1
- package/dist/src/controller.js +230 -49
- package/dist/src/controller.js.map +1 -1
- package/dist/src/db.js +172 -172
- package/dist/src/decay.js +8 -8
- package/dist/src/embedding.d.ts +2 -1
- package/dist/src/embedding.d.ts.map +1 -1
- package/dist/src/embedding.js +39 -29
- package/dist/src/embedding.js.map +1 -1
- package/dist/src/encode.js +6 -6
- package/dist/src/feedback.d.ts +6 -0
- package/dist/src/feedback.d.ts.map +1 -1
- package/dist/src/feedback.js +6 -0
- package/dist/src/feedback.js.map +1 -1
- package/dist/src/forget.js +12 -12
- package/dist/src/hybrid-recall.js +9 -9
- package/dist/src/impact.js +6 -6
- package/dist/src/import.d.ts +3 -3
- package/dist/src/import.js +41 -41
- package/dist/src/index.d.ts +3 -3
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +2 -2
- package/dist/src/index.js.map +1 -1
- package/dist/src/interference.js +14 -14
- package/dist/src/introspect.js +18 -18
- package/dist/src/preflight.d.ts.map +1 -1
- package/dist/src/preflight.js +41 -0
- package/dist/src/preflight.js.map +1 -1
- package/dist/src/promote.js +7 -7
- package/dist/src/prompts.js +118 -118
- package/dist/src/recall.js +30 -30
- package/dist/src/reflexes.d.ts +1 -0
- package/dist/src/reflexes.d.ts.map +1 -1
- package/dist/src/reflexes.js +3 -0
- package/dist/src/reflexes.js.map +1 -1
- package/dist/src/rollback.js +4 -4
- package/dist/src/routes.d.ts.map +1 -1
- package/dist/src/routes.js +67 -1
- package/dist/src/routes.js.map +1 -1
- package/dist/src/validate.js +25 -25
- package/docs/AUDREY_PAPER_OUTLINE.md +175 -0
- package/docs/MEMORY_BENCHMARKING.md +59 -0
- package/docs/PRODUCTION_BACKLOG.md +304 -0
- package/docs/paper/00-master.md +48 -0
- package/docs/paper/01-introduction.md +27 -0
- package/docs/paper/02-related-work.md +47 -0
- package/docs/paper/03-problem-definition.md +108 -0
- package/docs/paper/04-design.md +164 -0
- package/docs/paper/05-guardbench-spec.md +412 -0
- package/docs/paper/06-implementation.md +113 -0
- package/docs/paper/07-evaluation.md +168 -0
- package/docs/paper/08-discussion-limitations.md +61 -0
- package/docs/paper/09-conclusion.md +11 -0
- package/docs/paper/SUBMISSION_README.md +162 -0
- package/docs/paper/appendix-a-demo-transcript.md +114 -0
- package/docs/paper/arxiv-compile-report.schema.json +116 -0
- package/docs/paper/arxiv-source.schema.json +61 -0
- package/docs/paper/audrey-paper-v1.md +1106 -0
- package/docs/paper/browser-launch-plan.json +209 -0
- package/docs/paper/browser-launch-plan.schema.json +100 -0
- package/docs/paper/browser-launch-results.json +86 -0
- package/docs/paper/browser-launch-results.schema.json +66 -0
- package/docs/paper/claim-register.json +138 -0
- package/docs/paper/claim-register.schema.json +81 -0
- package/docs/paper/evidence-ledger.md +103 -0
- package/docs/paper/output/arxiv/README-arxiv.txt +8 -0
- package/docs/paper/output/arxiv/arxiv-manifest.json +41 -0
- package/docs/paper/output/arxiv/main.tex +949 -0
- package/docs/paper/output/arxiv/references.bib +222 -0
- package/docs/paper/output/arxiv-compile-report.json +24 -0
- package/docs/paper/output/submission-bundle/LICENSE +21 -0
- package/docs/paper/output/submission-bundle/README.md +533 -0
- package/docs/paper/output/submission-bundle/benchmarks/output/adapter-self-test/guardbench-adapter-self-test.json +50 -0
- package/docs/paper/output/submission-bundle/benchmarks/output/external/guardbench-external-dry-run.json +69 -0
- package/docs/paper/output/submission-bundle/benchmarks/output/external/guardbench-external-evidence.json +56 -0
- package/docs/paper/output/submission-bundle/benchmarks/output/guardbench-conformance-card.json +63 -0
- package/docs/paper/output/submission-bundle/benchmarks/output/guardbench-manifest.json +414 -0
- package/docs/paper/output/submission-bundle/benchmarks/output/guardbench-raw.json +1171 -0
- package/docs/paper/output/submission-bundle/benchmarks/output/guardbench-summary.json +1981 -0
- package/docs/paper/output/submission-bundle/benchmarks/output/leaderboard/guardbench-leaderboard.json +93 -0
- package/docs/paper/output/submission-bundle/benchmarks/output/leaderboard/guardbench-leaderboard.md +7 -0
- package/docs/paper/output/submission-bundle/benchmarks/output/submission-bundle/submission-manifest.json +131 -0
- package/docs/paper/output/submission-bundle/benchmarks/output/submission-bundle/validation-report.json +31 -0
- package/docs/paper/output/submission-bundle/benchmarks/output/summary.json +2354 -0
- package/docs/paper/output/submission-bundle/benchmarks/schemas/guardbench-adapter-registry.schema.json +69 -0
- package/docs/paper/output/submission-bundle/benchmarks/schemas/guardbench-adapter-self-test.schema.json +156 -0
- package/docs/paper/output/submission-bundle/benchmarks/schemas/guardbench-conformance-card.schema.json +184 -0
- package/docs/paper/output/submission-bundle/benchmarks/schemas/guardbench-external-dry-run.schema.json +74 -0
- package/docs/paper/output/submission-bundle/benchmarks/schemas/guardbench-external-evidence.schema.json +108 -0
- package/docs/paper/output/submission-bundle/benchmarks/schemas/guardbench-external-run.schema.json +160 -0
- package/docs/paper/output/submission-bundle/benchmarks/schemas/guardbench-leaderboard.schema.json +179 -0
- package/docs/paper/output/submission-bundle/benchmarks/schemas/guardbench-manifest.schema.json +213 -0
- package/docs/paper/output/submission-bundle/benchmarks/schemas/guardbench-publication-verification.schema.json +47 -0
- package/docs/paper/output/submission-bundle/benchmarks/schemas/guardbench-raw.schema.json +164 -0
- package/docs/paper/output/submission-bundle/benchmarks/schemas/guardbench-submission-manifest.schema.json +151 -0
- package/docs/paper/output/submission-bundle/benchmarks/schemas/guardbench-summary.schema.json +228 -0
- package/docs/paper/output/submission-bundle/docs/AUDREY_PAPER_OUTLINE.md +175 -0
- package/docs/paper/output/submission-bundle/docs/paper/00-master.md +48 -0
- package/docs/paper/output/submission-bundle/docs/paper/01-introduction.md +27 -0
- package/docs/paper/output/submission-bundle/docs/paper/02-related-work.md +47 -0
- package/docs/paper/output/submission-bundle/docs/paper/03-problem-definition.md +108 -0
- package/docs/paper/output/submission-bundle/docs/paper/04-design.md +164 -0
- package/docs/paper/output/submission-bundle/docs/paper/05-guardbench-spec.md +412 -0
- package/docs/paper/output/submission-bundle/docs/paper/06-implementation.md +113 -0
- package/docs/paper/output/submission-bundle/docs/paper/07-evaluation.md +168 -0
- package/docs/paper/output/submission-bundle/docs/paper/08-discussion-limitations.md +61 -0
- package/docs/paper/output/submission-bundle/docs/paper/09-conclusion.md +11 -0
- package/docs/paper/output/submission-bundle/docs/paper/SUBMISSION_README.md +162 -0
- package/docs/paper/output/submission-bundle/docs/paper/appendix-a-demo-transcript.md +114 -0
- package/docs/paper/output/submission-bundle/docs/paper/arxiv-compile-report.schema.json +116 -0
- package/docs/paper/output/submission-bundle/docs/paper/arxiv-source.schema.json +61 -0
- package/docs/paper/output/submission-bundle/docs/paper/audrey-paper-v1.md +1106 -0
- package/docs/paper/output/submission-bundle/docs/paper/browser-launch-plan.json +209 -0
- package/docs/paper/output/submission-bundle/docs/paper/browser-launch-plan.schema.json +100 -0
- package/docs/paper/output/submission-bundle/docs/paper/browser-launch-results.json +86 -0
- package/docs/paper/output/submission-bundle/docs/paper/browser-launch-results.schema.json +66 -0
- package/docs/paper/output/submission-bundle/docs/paper/claim-register.json +138 -0
- package/docs/paper/output/submission-bundle/docs/paper/claim-register.schema.json +81 -0
- package/docs/paper/output/submission-bundle/docs/paper/evidence-ledger.md +103 -0
- package/docs/paper/output/submission-bundle/docs/paper/output/arxiv/README-arxiv.txt +8 -0
- package/docs/paper/output/submission-bundle/docs/paper/output/arxiv/arxiv-manifest.json +41 -0
- package/docs/paper/output/submission-bundle/docs/paper/output/arxiv/main.tex +949 -0
- package/docs/paper/output/submission-bundle/docs/paper/output/arxiv/references.bib +222 -0
- package/docs/paper/output/submission-bundle/docs/paper/output/arxiv-compile-report.json +24 -0
- package/docs/paper/output/submission-bundle/docs/paper/paper-submission-bundle.schema.json +70 -0
- package/docs/paper/output/submission-bundle/docs/paper/publication-pack.json +81 -0
- package/docs/paper/output/submission-bundle/docs/paper/publication-pack.schema.json +60 -0
- package/docs/paper/output/submission-bundle/docs/paper/references.bib +222 -0
- package/docs/paper/output/submission-bundle/package.json +212 -0
- package/docs/paper/output/submission-bundle/paper-submission-manifest.json +379 -0
- package/docs/paper/paper-submission-bundle.schema.json +70 -0
- package/docs/paper/publication-pack.json +81 -0
- package/docs/paper/publication-pack.schema.json +60 -0
- package/docs/paper/references.bib +222 -0
- package/package.json +87 -4
- package/scripts/audit-release-completion.mjs +362 -0
- package/scripts/create-arxiv-source.mjs +362 -0
- package/scripts/create-paper-submission-bundle.mjs +210 -0
- package/scripts/finalize-release.mjs +526 -0
- package/scripts/prepare-release-cut.mjs +269 -0
- package/scripts/publish-release-bundle.mjs +209 -0
- package/scripts/publish-release-github-api.mjs +429 -0
- package/scripts/run-vitest.mjs +34 -0
- package/scripts/smoke-cli.js +72 -0
- package/scripts/sync-paper-artifacts.mjs +109 -0
- package/scripts/verify-arxiv-compile.mjs +440 -0
- package/scripts/verify-arxiv-source.mjs +194 -0
- package/scripts/verify-browser-launch-plan.mjs +237 -0
- package/scripts/verify-browser-launch-results.mjs +285 -0
- package/scripts/verify-paper-artifacts.mjs +338 -0
- package/scripts/verify-paper-claims.mjs +226 -0
- package/scripts/verify-paper-submission-bundle.mjs +207 -0
- package/scripts/verify-publication-pack.mjs +196 -0
- package/scripts/verify-python-package.py +201 -0
- package/scripts/verify-release-readiness.mjs +741 -0
|
@@ -0,0 +1,429 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { spawnSync } from 'node:child_process';
|
|
4
|
+
import { createHash } from 'node:crypto';
|
|
5
|
+
import { existsSync, readFileSync, statSync } from 'node:fs';
|
|
6
|
+
import { resolve } from 'node:path';
|
|
7
|
+
|
|
8
|
+
const ROOT = process.cwd();
|
|
9
|
+
const DEFAULT_REPOSITORY = 'Evilander/Audrey';
|
|
10
|
+
const DEFAULT_BRANCH = 'master';
|
|
11
|
+
const DEFAULT_VERSION = '1.0.0';
|
|
12
|
+
const DEFAULT_TOKEN_ENV = 'GITHUB_TOKEN';
|
|
13
|
+
const API_VERSION = '2022-11-28';
|
|
14
|
+
|
|
15
|
+
function parseArgs(argv = process.argv.slice(2)) {
|
|
16
|
+
const args = {
|
|
17
|
+
repository: DEFAULT_REPOSITORY,
|
|
18
|
+
branch: DEFAULT_BRANCH,
|
|
19
|
+
version: DEFAULT_VERSION,
|
|
20
|
+
tokenEnv: DEFAULT_TOKEN_ENV,
|
|
21
|
+
apply: false,
|
|
22
|
+
json: false,
|
|
23
|
+
force: false,
|
|
24
|
+
concurrency: 4,
|
|
25
|
+
includeEntries: false,
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
for (let i = 0; i < argv.length; i++) {
|
|
29
|
+
const token = argv[i];
|
|
30
|
+
if ((token === '--repository' || token === '--repo') && argv[i + 1]) args.repository = argv[++i];
|
|
31
|
+
else if (token === '--branch' && argv[i + 1]) args.branch = argv[++i];
|
|
32
|
+
else if ((token === '--version' || token === '--target-version') && argv[i + 1]) args.version = argv[++i];
|
|
33
|
+
else if (token === '--token-env' && argv[i + 1]) args.tokenEnv = argv[++i];
|
|
34
|
+
else if (token === '--concurrency' && argv[i + 1]) args.concurrency = Number.parseInt(argv[++i], 10);
|
|
35
|
+
else if (token === '--apply') args.apply = true;
|
|
36
|
+
else if (token === '--json') args.json = true;
|
|
37
|
+
else if (token === '--force') args.force = true;
|
|
38
|
+
else if (token === '--include-entries') args.includeEntries = true;
|
|
39
|
+
else if (token === '--help' || token === '-h') args.help = true;
|
|
40
|
+
else throw new Error(`Unknown argument: ${token}`);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (!Number.isInteger(args.concurrency) || args.concurrency < 1 || args.concurrency > 12) {
|
|
44
|
+
throw new Error('--concurrency must be an integer between 1 and 12');
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return args;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function usage() {
|
|
51
|
+
return `Usage: node scripts/publish-release-github-api.mjs [options]
|
|
52
|
+
|
|
53
|
+
Options:
|
|
54
|
+
--apply Create GitHub blobs/tree/commit/tag and update the branch.
|
|
55
|
+
--repository <owner/repo> Repository to publish. Default: ${DEFAULT_REPOSITORY}.
|
|
56
|
+
--branch <name> Branch ref to update. Default: ${DEFAULT_BRANCH}.
|
|
57
|
+
--version <version> Release version. Default: ${DEFAULT_VERSION}.
|
|
58
|
+
--token-env <name> Environment variable containing a GitHub token. Default: ${DEFAULT_TOKEN_ENV}.
|
|
59
|
+
--concurrency <n> Concurrent blob uploads. Default: 4.
|
|
60
|
+
--force Force branch ref update if remote branch moved.
|
|
61
|
+
--include-entries Include every changed path in the JSON report.
|
|
62
|
+
--json Print the machine-readable report.
|
|
63
|
+
`;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function run(command, args, options = {}) {
|
|
67
|
+
const result = spawnSync(command, args, {
|
|
68
|
+
cwd: ROOT,
|
|
69
|
+
encoding: 'utf-8',
|
|
70
|
+
timeout: options.timeout ?? 120_000,
|
|
71
|
+
env: {
|
|
72
|
+
...process.env,
|
|
73
|
+
...options.env,
|
|
74
|
+
},
|
|
75
|
+
});
|
|
76
|
+
return {
|
|
77
|
+
command: [command, ...args].join(' '),
|
|
78
|
+
ok: result.status === 0,
|
|
79
|
+
status: result.status,
|
|
80
|
+
stdout: result.stdout?.trim() ?? '',
|
|
81
|
+
stderr: result.stderr?.trim() ?? '',
|
|
82
|
+
error: result.error?.message ?? null,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function assertOk(result) {
|
|
87
|
+
if (!result.ok) throw new Error(`${result.command} failed: ${result.stderr || result.stdout || result.error || result.status}`);
|
|
88
|
+
return result.stdout;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function splitZ(output) {
|
|
92
|
+
return output.split('\0').filter(Boolean);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function normalized(path) {
|
|
96
|
+
return path.replaceAll('\\', '/');
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function sha256(path) {
|
|
100
|
+
return createHash('sha256').update(readFileSync(resolve(ROOT, path))).digest('hex');
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function readJsonIfExists(path) {
|
|
104
|
+
const full = resolve(ROOT, path);
|
|
105
|
+
return existsSync(full) ? JSON.parse(readFileSync(full, 'utf-8').replace(/^\uFEFF/, '')) : null;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function collectChangedPaths() {
|
|
109
|
+
const changed = splitZ(assertOk(run('git', ['-c', 'core.quotepath=false', 'diff', '--name-only', '-z', 'HEAD', '--'])));
|
|
110
|
+
const untracked = splitZ(assertOk(run('git', ['-c', 'core.quotepath=false', 'ls-files', '--others', '--exclude-standard', '-z'])));
|
|
111
|
+
return [...new Set([...changed, ...untracked].map(normalized))].sort((a, b) => a.localeCompare(b));
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function fileMode(path) {
|
|
115
|
+
const listing = run('git', ['ls-files', '-s', '--', path]);
|
|
116
|
+
if (listing.ok && listing.stdout) return listing.stdout.split(/\s+/)[0] || '100644';
|
|
117
|
+
return '100644';
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function changedEntries() {
|
|
121
|
+
return collectChangedPaths().map(path => {
|
|
122
|
+
const full = resolve(ROOT, path);
|
|
123
|
+
if (!existsSync(full)) {
|
|
124
|
+
return { path, deleted: true, mode: '100644', bytes: 0, sha256: null };
|
|
125
|
+
}
|
|
126
|
+
const stat = statSync(full);
|
|
127
|
+
if (!stat.isFile()) throw new Error(`Changed path is not a file: ${path}`);
|
|
128
|
+
return {
|
|
129
|
+
path,
|
|
130
|
+
deleted: false,
|
|
131
|
+
mode: fileMode(path),
|
|
132
|
+
bytes: stat.size,
|
|
133
|
+
sha256: sha256(path),
|
|
134
|
+
};
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function remoteRefs(repository, branch, version) {
|
|
139
|
+
let result = run('git', ['ls-remote', `https://github.com/${repository}.git`, `refs/heads/${branch}`, `refs/tags/v${version}`], { timeout: 60_000 });
|
|
140
|
+
if (!result.ok && /schannel|AcquireCredentialsHandle|SEC_E_NO_CREDENTIALS/i.test(`${result.stderr}\n${result.stdout}`)) {
|
|
141
|
+
result = run('git', ['-c', 'http.sslBackend=openssl', 'ls-remote', `https://github.com/${repository}.git`, `refs/heads/${branch}`, `refs/tags/v${version}`], { timeout: 60_000 });
|
|
142
|
+
result.fallback = 'openssl';
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const refs = {};
|
|
146
|
+
for (const line of result.stdout.split(/\r?\n/)) {
|
|
147
|
+
const [sha, ref] = line.trim().split(/\s+/);
|
|
148
|
+
if (sha && ref) refs[ref] = sha;
|
|
149
|
+
}
|
|
150
|
+
return {
|
|
151
|
+
result,
|
|
152
|
+
branch: refs[`refs/heads/${branch}`] ?? null,
|
|
153
|
+
tag: refs[`refs/tags/v${version}`] ?? null,
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function releaseDates() {
|
|
158
|
+
const headTime = Number.parseInt(assertOk(run('git', ['show', '-s', '--format=%ct', 'HEAD'])), 10);
|
|
159
|
+
const commitEpoch = headTime + 1;
|
|
160
|
+
return {
|
|
161
|
+
commitEpoch,
|
|
162
|
+
tagEpoch: commitEpoch + 1,
|
|
163
|
+
commitIso: isoWithOffset(commitEpoch, -300),
|
|
164
|
+
tagIso: isoWithOffset(commitEpoch + 1, -300),
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function isoWithOffset(epochSeconds, offsetMinutes) {
|
|
169
|
+
const shifted = new Date((epochSeconds + offsetMinutes * 60) * 1000);
|
|
170
|
+
const stamp = shifted.toISOString().replace(/\.\d{3}Z$/, '');
|
|
171
|
+
const sign = offsetMinutes < 0 ? '-' : '+';
|
|
172
|
+
const absolute = Math.abs(offsetMinutes);
|
|
173
|
+
const hours = String(Math.floor(absolute / 60)).padStart(2, '0');
|
|
174
|
+
const minutes = String(absolute % 60).padStart(2, '0');
|
|
175
|
+
return `${stamp}${sign}${hours}:${minutes}`;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
async function githubJson(token, repository, path, options = {}) {
|
|
179
|
+
const response = await fetch(`https://api.github.com/repos/${repository}${path}`, {
|
|
180
|
+
method: options.method ?? 'GET',
|
|
181
|
+
headers: {
|
|
182
|
+
Accept: 'application/vnd.github+json',
|
|
183
|
+
Authorization: `Bearer ${token}`,
|
|
184
|
+
'Content-Type': 'application/json',
|
|
185
|
+
'User-Agent': 'audrey-release-publisher',
|
|
186
|
+
'X-GitHub-Api-Version': API_VERSION,
|
|
187
|
+
},
|
|
188
|
+
body: options.body ? JSON.stringify(options.body) : undefined,
|
|
189
|
+
});
|
|
190
|
+
const text = await response.text();
|
|
191
|
+
const payload = text ? JSON.parse(text) : null;
|
|
192
|
+
if (!response.ok) {
|
|
193
|
+
const message = payload?.message ?? text.slice(0, 500) ?? response.statusText;
|
|
194
|
+
throw new Error(`GitHub API ${options.method ?? 'GET'} ${path} failed (${response.status}): ${message}`);
|
|
195
|
+
}
|
|
196
|
+
return payload;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
async function mapLimit(items, limit, mapper) {
|
|
200
|
+
const results = new Array(items.length);
|
|
201
|
+
let next = 0;
|
|
202
|
+
async function worker() {
|
|
203
|
+
while (next < items.length) {
|
|
204
|
+
const index = next++;
|
|
205
|
+
results[index] = await mapper(items[index], index);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
await Promise.all(Array.from({ length: Math.min(limit, items.length) }, worker));
|
|
209
|
+
return results;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
async function uploadBlob(token, repository, entry) {
|
|
213
|
+
const content = readFileSync(resolve(ROOT, entry.path)).toString('base64');
|
|
214
|
+
const blob = await githubJson(token, repository, '/git/blobs', {
|
|
215
|
+
method: 'POST',
|
|
216
|
+
body: {
|
|
217
|
+
content,
|
|
218
|
+
encoding: 'base64',
|
|
219
|
+
},
|
|
220
|
+
});
|
|
221
|
+
return {
|
|
222
|
+
path: entry.path,
|
|
223
|
+
mode: entry.mode,
|
|
224
|
+
type: 'blob',
|
|
225
|
+
sha: blob.sha,
|
|
226
|
+
bytes: entry.bytes,
|
|
227
|
+
sha256: entry.sha256,
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
function localState(args) {
|
|
232
|
+
const localHead = assertOk(run('git', ['rev-parse', 'HEAD']));
|
|
233
|
+
const localTree = assertOk(run('git', ['rev-parse', 'HEAD^{tree}']));
|
|
234
|
+
const objectReport = readJsonIfExists('.tmp/release-git-object-report.json');
|
|
235
|
+
const finalizeReport = readJsonIfExists('.tmp/release-artifacts/release-finalize-report.json');
|
|
236
|
+
const refs = remoteRefs(args.repository, args.branch, args.version);
|
|
237
|
+
const entries = changedEntries();
|
|
238
|
+
const bytes = entries.reduce((total, entry) => total + entry.bytes, 0);
|
|
239
|
+
const blockers = [];
|
|
240
|
+
|
|
241
|
+
if (!refs.result.ok) blockers.push(`Remote ref check failed: ${refs.result.stderr || refs.result.stdout || refs.result.error}`);
|
|
242
|
+
if (refs.branch && refs.branch !== localHead && !args.force) {
|
|
243
|
+
blockers.push(`Remote ${args.branch} is ${refs.branch}, but local HEAD is ${localHead}`);
|
|
244
|
+
}
|
|
245
|
+
if (refs.tag) blockers.push(`Remote tag v${args.version} already exists at ${refs.tag}`);
|
|
246
|
+
if (!objectReport?.commit || !objectReport?.tree) blockers.push('Missing .tmp/release-git-object-report.json; run npm run release:artifacts first');
|
|
247
|
+
|
|
248
|
+
return {
|
|
249
|
+
localHead,
|
|
250
|
+
localTree,
|
|
251
|
+
expectedReleaseTree: objectReport?.tree ?? null,
|
|
252
|
+
expectedReleaseCommit: objectReport?.commit ?? null,
|
|
253
|
+
expectedReleaseTag: objectReport?.tag ?? null,
|
|
254
|
+
remoteBranch: refs.branch,
|
|
255
|
+
remoteTag: refs.tag,
|
|
256
|
+
remoteCheck: refs.result,
|
|
257
|
+
changedFiles: entries.length,
|
|
258
|
+
changedBytes: bytes,
|
|
259
|
+
entries,
|
|
260
|
+
finalizeArtifacts: finalizeReport?.artifacts ?? [],
|
|
261
|
+
blockers,
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
async function publishWithGitHubApi(args, state, token) {
|
|
266
|
+
const apiCommit = await githubJson(token, args.repository, `/git/commits/${state.remoteBranch}`);
|
|
267
|
+
const uploaded = await mapLimit(
|
|
268
|
+
state.entries.filter(entry => !entry.deleted),
|
|
269
|
+
args.concurrency,
|
|
270
|
+
entry => uploadBlob(token, args.repository, entry),
|
|
271
|
+
);
|
|
272
|
+
const uploadedByPath = new Map(uploaded.map(entry => [entry.path, entry]));
|
|
273
|
+
const tree = await githubJson(token, args.repository, '/git/trees', {
|
|
274
|
+
method: 'POST',
|
|
275
|
+
body: {
|
|
276
|
+
base_tree: apiCommit.tree.sha,
|
|
277
|
+
tree: state.entries.map(entry => {
|
|
278
|
+
if (entry.deleted) return { path: entry.path, mode: entry.mode, type: 'blob', sha: null };
|
|
279
|
+
const blob = uploadedByPath.get(entry.path);
|
|
280
|
+
return { path: entry.path, mode: entry.mode, type: 'blob', sha: blob.sha };
|
|
281
|
+
}),
|
|
282
|
+
},
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
if (state.expectedReleaseTree && tree.sha !== state.expectedReleaseTree) {
|
|
286
|
+
throw new Error(`GitHub release tree ${tree.sha} does not match local source-bundle tree ${state.expectedReleaseTree}`);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
const dates = releaseDates();
|
|
290
|
+
const identity = { name: 'Tyler Eveland', email: 'j.tyler.eveland@gmail.com' };
|
|
291
|
+
const commit = await githubJson(token, args.repository, '/git/commits', {
|
|
292
|
+
method: 'POST',
|
|
293
|
+
body: {
|
|
294
|
+
message: `Release Audrey ${args.version}`,
|
|
295
|
+
tree: tree.sha,
|
|
296
|
+
parents: [state.remoteBranch],
|
|
297
|
+
author: { ...identity, date: dates.commitIso },
|
|
298
|
+
committer: { ...identity, date: dates.commitIso },
|
|
299
|
+
},
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
if (state.expectedReleaseCommit && commit.sha !== state.expectedReleaseCommit) {
|
|
303
|
+
throw new Error(`GitHub release commit ${commit.sha} does not match local source-bundle commit ${state.expectedReleaseCommit}`);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
const branchUpdate = await githubJson(token, args.repository, `/git/refs/heads/${args.branch}`, {
|
|
307
|
+
method: 'PATCH',
|
|
308
|
+
body: {
|
|
309
|
+
sha: commit.sha,
|
|
310
|
+
force: args.force,
|
|
311
|
+
},
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
const tagObject = await githubJson(token, args.repository, '/git/tags', {
|
|
315
|
+
method: 'POST',
|
|
316
|
+
body: {
|
|
317
|
+
tag: `v${args.version}`,
|
|
318
|
+
message: `Audrey ${args.version}`,
|
|
319
|
+
object: commit.sha,
|
|
320
|
+
type: 'commit',
|
|
321
|
+
tagger: { ...identity, date: dates.tagIso },
|
|
322
|
+
},
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
const tagRef = await githubJson(token, args.repository, '/git/refs', {
|
|
326
|
+
method: 'POST',
|
|
327
|
+
body: {
|
|
328
|
+
ref: `refs/tags/v${args.version}`,
|
|
329
|
+
sha: tagObject.sha,
|
|
330
|
+
},
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
return {
|
|
334
|
+
uploadedBlobs: uploaded.length,
|
|
335
|
+
tree: tree.sha,
|
|
336
|
+
commit: commit.sha,
|
|
337
|
+
tagObject: tagObject.sha,
|
|
338
|
+
branchRef: branchUpdate.object?.sha ?? commit.sha,
|
|
339
|
+
tagRef: tagRef.object?.sha ?? tagObject.sha,
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
function printableReport(report, json) {
|
|
344
|
+
if (json) return JSON.stringify(report, null, 2);
|
|
345
|
+
const lines = [
|
|
346
|
+
`Audrey GitHub API source publisher: apply=${report.apply}`,
|
|
347
|
+
`repository=${report.repository}`,
|
|
348
|
+
`branch=${report.branch}`,
|
|
349
|
+
`changed files=${report.changedFiles}`,
|
|
350
|
+
`changed bytes=${report.changedBytes}`,
|
|
351
|
+
`remote branch=${report.remoteBranch ?? 'missing'}`,
|
|
352
|
+
`remote tag=${report.remoteTag ?? 'missing'}`,
|
|
353
|
+
`expected release commit=${report.expectedReleaseCommit ?? 'missing'}`,
|
|
354
|
+
];
|
|
355
|
+
if (report.blockers.length) {
|
|
356
|
+
lines.push('Blockers:');
|
|
357
|
+
for (const blocker of report.blockers) lines.push(`- ${blocker}`);
|
|
358
|
+
}
|
|
359
|
+
if (report.publish) {
|
|
360
|
+
lines.push(`published commit=${report.publish.commit}`);
|
|
361
|
+
lines.push(`published tag=${report.publish.tagRef}`);
|
|
362
|
+
}
|
|
363
|
+
return lines.join('\n');
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
async function main() {
|
|
367
|
+
const args = parseArgs();
|
|
368
|
+
if (args.help) {
|
|
369
|
+
console.log(usage());
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
const state = localState(args);
|
|
374
|
+
const report = {
|
|
375
|
+
schemaVersion: '1.0.0',
|
|
376
|
+
suite: 'Audrey GitHub API source publication',
|
|
377
|
+
generatedAt: new Date().toISOString(),
|
|
378
|
+
apply: args.apply,
|
|
379
|
+
repository: args.repository,
|
|
380
|
+
branch: args.branch,
|
|
381
|
+
version: args.version,
|
|
382
|
+
tokenEnv: args.tokenEnv,
|
|
383
|
+
localHead: state.localHead,
|
|
384
|
+
localTree: state.localTree,
|
|
385
|
+
expectedReleaseTree: state.expectedReleaseTree,
|
|
386
|
+
expectedReleaseCommit: state.expectedReleaseCommit,
|
|
387
|
+
expectedReleaseTag: state.expectedReleaseTag,
|
|
388
|
+
remoteBranch: state.remoteBranch,
|
|
389
|
+
remoteTag: state.remoteTag,
|
|
390
|
+
changedFiles: state.changedFiles,
|
|
391
|
+
changedBytes: state.changedBytes,
|
|
392
|
+
changedEntrySample: state.entries.slice(0, 12).map(entry => ({
|
|
393
|
+
path: entry.path,
|
|
394
|
+
deleted: entry.deleted,
|
|
395
|
+
mode: entry.mode,
|
|
396
|
+
bytes: entry.bytes,
|
|
397
|
+
sha256: entry.sha256,
|
|
398
|
+
})),
|
|
399
|
+
changedEntries: args.includeEntries
|
|
400
|
+
? state.entries.map(entry => ({
|
|
401
|
+
path: entry.path,
|
|
402
|
+
deleted: entry.deleted,
|
|
403
|
+
mode: entry.mode,
|
|
404
|
+
bytes: entry.bytes,
|
|
405
|
+
sha256: entry.sha256,
|
|
406
|
+
}))
|
|
407
|
+
: undefined,
|
|
408
|
+
finalizeArtifacts: state.finalizeArtifacts,
|
|
409
|
+
blockers: [...state.blockers],
|
|
410
|
+
publish: null,
|
|
411
|
+
};
|
|
412
|
+
|
|
413
|
+
if (args.apply) {
|
|
414
|
+
const token = process.env[args.tokenEnv];
|
|
415
|
+
if (!token) {
|
|
416
|
+
report.blockers.push(`Set ${args.tokenEnv} to a GitHub token with contents:write before applying`);
|
|
417
|
+
} else if (report.blockers.length === 0) {
|
|
418
|
+
report.publish = await publishWithGitHubApi(args, state, token);
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
console.log(printableReport(report, args.json));
|
|
423
|
+
if (report.blockers.length) process.exit(1);
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
main().catch(error => {
|
|
427
|
+
console.error(error.stack ?? error.message);
|
|
428
|
+
process.exit(1);
|
|
429
|
+
});
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
import { mkdirSync } from 'node:fs';
|
|
3
|
+
import { resolve } from 'node:path';
|
|
4
|
+
|
|
5
|
+
const tempDir = resolve('.tmp-vitest');
|
|
6
|
+
mkdirSync(tempDir, { recursive: true });
|
|
7
|
+
|
|
8
|
+
const vitestEntry = resolve('node_modules/vitest/vitest.mjs');
|
|
9
|
+
const args = process.argv.slice(2);
|
|
10
|
+
const mode = args[0] === 'watch' ? [] : ['run'];
|
|
11
|
+
const passthrough = args[0] === 'watch' ? args.slice(1) : args;
|
|
12
|
+
|
|
13
|
+
const child = spawn(process.execPath, [vitestEntry, ...mode, ...passthrough], {
|
|
14
|
+
stdio: 'inherit',
|
|
15
|
+
env: {
|
|
16
|
+
...process.env,
|
|
17
|
+
TEMP: tempDir,
|
|
18
|
+
TMP: tempDir,
|
|
19
|
+
TMPDIR: tempDir,
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
child.on('error', err => {
|
|
24
|
+
console.error(err);
|
|
25
|
+
process.exit(1);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
child.on('exit', (code, signal) => {
|
|
29
|
+
if (signal) {
|
|
30
|
+
process.kill(process.pid, signal);
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
process.exit(code ?? 1);
|
|
34
|
+
});
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { spawnSync } from 'node:child_process';
|
|
4
|
+
import { existsSync, mkdtempSync, rmSync, readFileSync } from 'node:fs';
|
|
5
|
+
import { tmpdir } from 'node:os';
|
|
6
|
+
import { dirname, join, resolve } from 'node:path';
|
|
7
|
+
import { fileURLToPath } from 'node:url';
|
|
8
|
+
|
|
9
|
+
const root = resolve(dirname(fileURLToPath(import.meta.url)), '..');
|
|
10
|
+
const cli = join(root, 'dist', 'mcp-server', 'index.js');
|
|
11
|
+
const pkg = JSON.parse(readFileSync(join(root, 'package.json'), 'utf8'));
|
|
12
|
+
|
|
13
|
+
function fail(message, result) {
|
|
14
|
+
console.error(`[audrey smoke] ${message}`);
|
|
15
|
+
if (result) {
|
|
16
|
+
if (result.stdout) console.error(`stdout:\n${result.stdout}`);
|
|
17
|
+
if (result.stderr) console.error(`stderr:\n${result.stderr}`);
|
|
18
|
+
}
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (!existsSync(cli)) {
|
|
23
|
+
fail(`missing built CLI at ${cli}; run npm run build first`);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const tempRoot = mkdtempSync(join(tmpdir(), 'audrey-smoke-'));
|
|
27
|
+
const env = {
|
|
28
|
+
...process.env,
|
|
29
|
+
AUDREY_DATA_DIR: join(tempRoot, 'store'),
|
|
30
|
+
AUDREY_EMBEDDING_PROVIDER: 'mock',
|
|
31
|
+
AUDREY_LLM_PROVIDER: 'mock',
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
function run(label, args) {
|
|
35
|
+
const result = spawnSync(process.execPath, [cli, ...args], {
|
|
36
|
+
cwd: root,
|
|
37
|
+
env,
|
|
38
|
+
encoding: 'utf8',
|
|
39
|
+
timeout: 60_000,
|
|
40
|
+
});
|
|
41
|
+
if (result.error) {
|
|
42
|
+
fail(`${label} failed to spawn: ${result.error.message}`, result);
|
|
43
|
+
}
|
|
44
|
+
if (result.status !== 0) {
|
|
45
|
+
fail(`${label} exited ${result.status}`, result);
|
|
46
|
+
}
|
|
47
|
+
return result.stdout;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
try {
|
|
51
|
+
const version = run('--version', ['--version']).trim();
|
|
52
|
+
if (version !== `audrey ${pkg.version}`) {
|
|
53
|
+
fail(`version mismatch: expected audrey ${pkg.version}, got ${version}`);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const doctor = JSON.parse(run('doctor --json', ['doctor', '--json']));
|
|
57
|
+
if (doctor.version !== pkg.version || doctor.ok !== true) {
|
|
58
|
+
fail(`doctor --json returned unexpected release status: ${JSON.stringify({
|
|
59
|
+
version: doctor.version,
|
|
60
|
+
ok: doctor.ok,
|
|
61
|
+
})}`);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const demo = run('demo', ['demo']);
|
|
65
|
+
if (!demo.includes('Audrey 60-second memory demo') || !demo.includes('Recall proof:')) {
|
|
66
|
+
fail('demo output did not include expected proof markers', { stdout: demo, stderr: '' });
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
console.log(`[audrey smoke] CLI smoke checks passed for ${pkg.version}`);
|
|
70
|
+
} finally {
|
|
71
|
+
rmSync(tempRoot, { recursive: true, force: true });
|
|
72
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { resolve } from 'node:path';
|
|
3
|
+
|
|
4
|
+
const ROOT = process.cwd();
|
|
5
|
+
|
|
6
|
+
function readText(path) {
|
|
7
|
+
const absolute = resolve(ROOT, path);
|
|
8
|
+
if (!existsSync(absolute)) throw new Error(`Missing required file: ${path}`);
|
|
9
|
+
return readFileSync(absolute, 'utf-8');
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function writeText(path, content) {
|
|
13
|
+
writeFileSync(resolve(ROOT, path), content, 'utf-8');
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function readJson(path) {
|
|
17
|
+
return JSON.parse(readText(path));
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function metric(value) {
|
|
21
|
+
return String(value);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function replaceOrFail(text, pattern, replacement, label) {
|
|
25
|
+
if (!pattern.test(text)) throw new Error(`Could not update ${label}`);
|
|
26
|
+
return text.replace(pattern, replacement);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function localRows(summary) {
|
|
30
|
+
return Object.fromEntries(summary.local.overall.map(row => [row.system, row]));
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function benchmarkTable(summary) {
|
|
34
|
+
const rows = localRows(summary);
|
|
35
|
+
return [
|
|
36
|
+
`| Audrey | ${rows.Audrey.scorePercent} | ${rows.Audrey.passRate} | ${metric(rows.Audrey.avgDurationMs)} |`,
|
|
37
|
+
`| Vector Only | ${rows['Vector Only'].scorePercent} | ${rows['Vector Only'].passRate} | ${metric(rows['Vector Only'].avgDurationMs)} |`,
|
|
38
|
+
`| Keyword + Recency | ${rows['Keyword + Recency'].scorePercent} | ${rows['Keyword + Recency'].passRate} | ${metric(rows['Keyword + Recency'].avgDurationMs)} |`,
|
|
39
|
+
`| Recent Window | ${rows['Recent Window'].scorePercent} | ${rows['Recent Window'].passRate} | ${metric(rows['Recent Window'].avgDurationMs)} |`,
|
|
40
|
+
].join('\n');
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function syncEvaluationText(text, summary, guardSummary) {
|
|
44
|
+
let next = text;
|
|
45
|
+
next = replaceOrFail(
|
|
46
|
+
next,
|
|
47
|
+
/The current `benchmarks\/output\/summary\.json` was generated on [^ ]+ with command `node benchmarks\/run\.js --provider mock --dimensions 64` \(Ledger: E24\)\. It reports:/,
|
|
48
|
+
`The current \`benchmarks/output/summary.json\` was generated on ${summary.generatedAt} with command \`node benchmarks/run.js --provider mock --dimensions 64\` (Ledger: E24). It reports:`,
|
|
49
|
+
'benchmark generatedAt',
|
|
50
|
+
);
|
|
51
|
+
next = replaceOrFail(
|
|
52
|
+
next,
|
|
53
|
+
/\| Audrey \| .* \|\n\| Vector Only \| .* \|\n\| Keyword \+ Recency \| .* \|\n\| Recent Window \| .* \|/,
|
|
54
|
+
benchmarkTable(summary),
|
|
55
|
+
'benchmark table',
|
|
56
|
+
);
|
|
57
|
+
next = replaceOrFail(
|
|
58
|
+
next,
|
|
59
|
+
/\| Guard latency p50 \/ p95 \| [^|]+ \|/,
|
|
60
|
+
`| Guard latency p50 / p95 | ${metric(guardSummary.latency.p50Ms)} ms / ${metric(guardSummary.latency.p95Ms)} ms |`,
|
|
61
|
+
'GuardBench latency row',
|
|
62
|
+
);
|
|
63
|
+
return next;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function syncReadme(text, guardSummary) {
|
|
67
|
+
return replaceOrFail(
|
|
68
|
+
text,
|
|
69
|
+
/Latest local result in this checkout: 10\/10 scenarios passed, 100% prevention\r?\nrate, 0% false-block rate, 0 raw secret leaks, 0 published artifact leaks in\r?\nthe raw-secret sweep, and [^\r\n]+\r?\np50\/p95 guard latency under the mock-provider methodology\./,
|
|
70
|
+
[
|
|
71
|
+
'Latest local result in this checkout: 10/10 scenarios passed, 100% prevention',
|
|
72
|
+
'rate, 0% false-block rate, 0 raw secret leaks, 0 published artifact leaks in',
|
|
73
|
+
`the raw-secret sweep, and ${metric(guardSummary.latency.p50Ms)}ms / ${metric(guardSummary.latency.p95Ms)}ms`,
|
|
74
|
+
'p50/p95 guard latency under the mock-provider methodology.',
|
|
75
|
+
].join('\n'),
|
|
76
|
+
'README GuardBench summary',
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function syncLedger(text, guardSummary) {
|
|
81
|
+
return replaceOrFail(
|
|
82
|
+
text,
|
|
83
|
+
/and [0-9.]+ms\/[0-9.]+ms p50\/p95 guard latency under the mock-provider methodology\. Baseline decision accuracy was no-memory 10%, recent-window 60%, vector-only 40%, and FTS-only 10%, with 0% full-contract pass rate for each baseline\. \| GuardBench local comparative results/,
|
|
84
|
+
`and ${metric(guardSummary.latency.p50Ms)}ms/${metric(guardSummary.latency.p95Ms)}ms p50/p95 guard latency under the mock-provider methodology. Baseline decision accuracy was no-memory 10%, recent-window 60%, vector-only 40%, and FTS-only 10%, with 0% full-contract pass rate for each baseline. | GuardBench local comparative results`,
|
|
85
|
+
'E46 GuardBench latency',
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const summary = readJson('benchmarks/output/summary.json');
|
|
90
|
+
const guardSummary = readJson('benchmarks/output/guardbench-summary.json');
|
|
91
|
+
|
|
92
|
+
const updates = [
|
|
93
|
+
['README.md', text => syncReadme(text, guardSummary)],
|
|
94
|
+
['docs/paper/07-evaluation.md', text => syncEvaluationText(text, summary, guardSummary)],
|
|
95
|
+
['docs/paper/audrey-paper-v1.md', text => syncEvaluationText(text, summary, guardSummary)],
|
|
96
|
+
['docs/paper/evidence-ledger.md', text => syncLedger(text, guardSummary)],
|
|
97
|
+
];
|
|
98
|
+
|
|
99
|
+
const changed = [];
|
|
100
|
+
for (const [path, updater] of updates) {
|
|
101
|
+
const before = readText(path);
|
|
102
|
+
const after = updater(before);
|
|
103
|
+
if (after !== before) {
|
|
104
|
+
writeText(path, after);
|
|
105
|
+
changed.push(path);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
console.log(changed.length ? `Synced paper artifacts: ${changed.join(', ')}` : 'Paper artifacts already in sync.');
|