audrey 1.0.0 → 1.0.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 (234) hide show
  1. package/CHANGELOG.md +54 -0
  2. package/README.md +30 -6
  3. package/benchmarks/adapter-self-test.mjs +6 -2
  4. package/benchmarks/adapters/example-allow.mjs +5 -2
  5. package/benchmarks/adapters/mem0-platform.mjs +19 -12
  6. package/benchmarks/adapters/zep-cloud.mjs +51 -27
  7. package/benchmarks/baselines.js +11 -6
  8. package/benchmarks/build-leaderboard.mjs +36 -23
  9. package/benchmarks/cases.js +24 -12
  10. package/benchmarks/create-conformance-card.mjs +12 -3
  11. package/benchmarks/create-submission-bundle.mjs +22 -8
  12. package/benchmarks/dry-run-external-adapters.mjs +24 -12
  13. package/benchmarks/guardbench.js +354 -124
  14. package/benchmarks/output/adapter-self-test/guardbench-adapter-self-test.json +7 -7
  15. package/benchmarks/output/external/guardbench-external-dry-run.json +1 -1
  16. package/benchmarks/output/external/guardbench-external-evidence.json +1 -1
  17. package/benchmarks/output/guardbench-conformance-card.json +12 -12
  18. package/benchmarks/output/guardbench-raw.json +243 -144
  19. package/benchmarks/output/guardbench-summary.json +354 -230
  20. package/benchmarks/output/leaderboard/guardbench-leaderboard.json +5 -5
  21. package/benchmarks/output/leaderboard/guardbench-leaderboard.md +2 -2
  22. package/benchmarks/output/submission-bundle/guardbench-conformance-card.json +12 -12
  23. package/benchmarks/output/submission-bundle/guardbench-raw.json +243 -144
  24. package/benchmarks/output/submission-bundle/guardbench-summary.json +354 -230
  25. package/benchmarks/output/submission-bundle/schemas/guardbench-raw.schema.json +21 -1
  26. package/benchmarks/output/submission-bundle/schemas/guardbench-summary.schema.json +23 -2
  27. package/benchmarks/output/submission-bundle/submission-manifest.json +15 -15
  28. package/benchmarks/output/submission-bundle/validation-report.json +1 -1
  29. package/benchmarks/output/summary.json +58 -58
  30. package/benchmarks/perf-snapshot.js +12 -9
  31. package/benchmarks/perf.bench.js +14 -6
  32. package/benchmarks/public-paths.mjs +11 -5
  33. package/benchmarks/reference-results.js +10 -5
  34. package/benchmarks/report.js +48 -27
  35. package/benchmarks/run-external-guardbench.mjs +47 -25
  36. package/benchmarks/run.js +112 -59
  37. package/benchmarks/schemas/guardbench-raw.schema.json +21 -1
  38. package/benchmarks/schemas/guardbench-summary.schema.json +23 -2
  39. package/benchmarks/validate-adapter-module.mjs +13 -10
  40. package/benchmarks/validate-adapter-registry.mjs +16 -5
  41. package/benchmarks/validate-guardbench-artifacts.mjs +76 -19
  42. package/benchmarks/verify-external-evidence.mjs +86 -31
  43. package/benchmarks/verify-publication-artifacts.mjs +34 -11
  44. package/benchmarks/verify-submission-bundle.mjs +9 -4
  45. package/dist/mcp-server/config.d.ts +1 -1
  46. package/dist/mcp-server/config.d.ts.map +1 -1
  47. package/dist/mcp-server/config.js +5 -3
  48. package/dist/mcp-server/config.js.map +1 -1
  49. package/dist/mcp-server/index.d.ts +4 -3
  50. package/dist/mcp-server/index.d.ts.map +1 -1
  51. package/dist/mcp-server/index.js +479 -172
  52. package/dist/mcp-server/index.js.map +1 -1
  53. package/dist/src/action-key.d.ts.map +1 -1
  54. package/dist/src/action-key.js +6 -2
  55. package/dist/src/action-key.js.map +1 -1
  56. package/dist/src/adaptive.d.ts.map +1 -1
  57. package/dist/src/adaptive.js +4 -2
  58. package/dist/src/adaptive.js.map +1 -1
  59. package/dist/src/affect.d.ts.map +1 -1
  60. package/dist/src/affect.js +8 -5
  61. package/dist/src/affect.js.map +1 -1
  62. package/dist/src/audrey.d.ts +11 -1
  63. package/dist/src/audrey.d.ts.map +1 -1
  64. package/dist/src/audrey.js +110 -53
  65. package/dist/src/audrey.js.map +1 -1
  66. package/dist/src/capsule.d.ts.map +1 -1
  67. package/dist/src/capsule.js +37 -15
  68. package/dist/src/capsule.js.map +1 -1
  69. package/dist/src/causal.d.ts +1 -1
  70. package/dist/src/causal.d.ts.map +1 -1
  71. package/dist/src/causal.js +4 -2
  72. package/dist/src/causal.js.map +1 -1
  73. package/dist/src/confidence.d.ts.map +1 -1
  74. package/dist/src/confidence.js +5 -5
  75. package/dist/src/confidence.js.map +1 -1
  76. package/dist/src/consolidate.d.ts.map +1 -1
  77. package/dist/src/consolidate.js +17 -9
  78. package/dist/src/consolidate.js.map +1 -1
  79. package/dist/src/context.js +1 -1
  80. package/dist/src/context.js.map +1 -1
  81. package/dist/src/controller.d.ts +17 -1
  82. package/dist/src/controller.d.ts.map +1 -1
  83. package/dist/src/controller.js +73 -23
  84. package/dist/src/controller.js.map +1 -1
  85. package/dist/src/db.d.ts.map +1 -1
  86. package/dist/src/db.js +78 -27
  87. package/dist/src/db.js.map +1 -1
  88. package/dist/src/decay.d.ts +1 -1
  89. package/dist/src/decay.d.ts.map +1 -1
  90. package/dist/src/decay.js +1 -1
  91. package/dist/src/decay.js.map +1 -1
  92. package/dist/src/embedding.d.ts +12 -4
  93. package/dist/src/embedding.d.ts.map +1 -1
  94. package/dist/src/embedding.js +18 -16
  95. package/dist/src/embedding.js.map +1 -1
  96. package/dist/src/encode.d.ts.map +1 -1
  97. package/dist/src/encode.js +5 -4
  98. package/dist/src/encode.js.map +1 -1
  99. package/dist/src/events.d.ts +3 -2
  100. package/dist/src/events.d.ts.map +1 -1
  101. package/dist/src/events.js +7 -3
  102. package/dist/src/events.js.map +1 -1
  103. package/dist/src/export.d.ts.map +1 -1
  104. package/dist/src/export.js +21 -7
  105. package/dist/src/export.js.map +1 -1
  106. package/dist/src/feedback.d.ts.map +1 -1
  107. package/dist/src/feedback.js +1 -1
  108. package/dist/src/feedback.js.map +1 -1
  109. package/dist/src/forget.d.ts.map +1 -1
  110. package/dist/src/forget.js +12 -6
  111. package/dist/src/forget.js.map +1 -1
  112. package/dist/src/fts.d.ts.map +1 -1
  113. package/dist/src/fts.js +20 -8
  114. package/dist/src/fts.js.map +1 -1
  115. package/dist/src/hybrid-recall.d.ts.map +1 -1
  116. package/dist/src/hybrid-recall.js +12 -6
  117. package/dist/src/hybrid-recall.js.map +1 -1
  118. package/dist/src/impact.d.ts.map +1 -1
  119. package/dist/src/impact.js +26 -10
  120. package/dist/src/impact.js.map +1 -1
  121. package/dist/src/import.d.ts.map +1 -1
  122. package/dist/src/import.js +11 -6
  123. package/dist/src/import.js.map +1 -1
  124. package/dist/src/index.d.ts +5 -4
  125. package/dist/src/index.d.ts.map +1 -1
  126. package/dist/src/index.js +4 -4
  127. package/dist/src/index.js.map +1 -1
  128. package/dist/src/interference.d.ts.map +1 -1
  129. package/dist/src/interference.js +10 -5
  130. package/dist/src/interference.js.map +1 -1
  131. package/dist/src/introspect.d.ts.map +1 -1
  132. package/dist/src/introspect.js +12 -6
  133. package/dist/src/introspect.js.map +1 -1
  134. package/dist/src/llm.d.ts +2 -2
  135. package/dist/src/llm.d.ts.map +1 -1
  136. package/dist/src/llm.js +6 -6
  137. package/dist/src/llm.js.map +1 -1
  138. package/dist/src/migrate.d.ts.map +1 -1
  139. package/dist/src/migrate.js +10 -4
  140. package/dist/src/migrate.js.map +1 -1
  141. package/dist/src/preflight.d.ts.map +1 -1
  142. package/dist/src/preflight.js +6 -8
  143. package/dist/src/preflight.js.map +1 -1
  144. package/dist/src/profile.d.ts.map +1 -1
  145. package/dist/src/profile.js.map +1 -1
  146. package/dist/src/promote.d.ts.map +1 -1
  147. package/dist/src/promote.js +16 -7
  148. package/dist/src/promote.js.map +1 -1
  149. package/dist/src/prompts.d.ts.map +1 -1
  150. package/dist/src/prompts.js +1 -2
  151. package/dist/src/prompts.js.map +1 -1
  152. package/dist/src/recall.d.ts.map +1 -1
  153. package/dist/src/recall.js +85 -18
  154. package/dist/src/recall.js.map +1 -1
  155. package/dist/src/redact.d.ts.map +1 -1
  156. package/dist/src/redact.js +9 -4
  157. package/dist/src/redact.js.map +1 -1
  158. package/dist/src/reflexes.d.ts.map +1 -1
  159. package/dist/src/reflexes.js +1 -7
  160. package/dist/src/reflexes.js.map +1 -1
  161. package/dist/src/rollback.d.ts.map +1 -1
  162. package/dist/src/rollback.js +4 -2
  163. package/dist/src/rollback.js.map +1 -1
  164. package/dist/src/routes.d.ts.map +1 -1
  165. package/dist/src/routes.js +37 -14
  166. package/dist/src/routes.js.map +1 -1
  167. package/dist/src/rules-compiler.d.ts.map +1 -1
  168. package/dist/src/rules-compiler.js +24 -2
  169. package/dist/src/rules-compiler.js.map +1 -1
  170. package/dist/src/server.js +2 -2
  171. package/dist/src/server.js.map +1 -1
  172. package/dist/src/tool-trace.d.ts +2 -2
  173. package/dist/src/tool-trace.d.ts.map +1 -1
  174. package/dist/src/tool-trace.js +12 -4
  175. package/dist/src/tool-trace.js.map +1 -1
  176. package/dist/src/types.d.ts.map +1 -1
  177. package/dist/src/ulid.js +1 -1
  178. package/dist/src/ulid.js.map +1 -1
  179. package/dist/src/utils.d.ts.map +1 -1
  180. package/dist/src/utils.js.map +1 -1
  181. package/dist/src/validate.d.ts.map +1 -1
  182. package/dist/src/validate.js +20 -10
  183. package/dist/src/validate.js.map +1 -1
  184. package/docs/paper/07-evaluation.md +5 -5
  185. package/docs/paper/audrey-paper-v1.md +6 -6
  186. package/docs/paper/evidence-ledger.md +1 -1
  187. package/docs/paper/output/arxiv/arxiv-manifest.json +4 -4
  188. package/docs/paper/output/arxiv/main.tex +6 -6
  189. package/docs/paper/output/arxiv-compile-report.json +3 -3
  190. package/docs/paper/output/submission-bundle/README.md +30 -6
  191. package/docs/paper/output/submission-bundle/benchmarks/output/adapter-self-test/guardbench-adapter-self-test.json +7 -7
  192. package/docs/paper/output/submission-bundle/benchmarks/output/external/guardbench-external-dry-run.json +1 -1
  193. package/docs/paper/output/submission-bundle/benchmarks/output/external/guardbench-external-evidence.json +1 -1
  194. package/docs/paper/output/submission-bundle/benchmarks/output/guardbench-conformance-card.json +12 -12
  195. package/docs/paper/output/submission-bundle/benchmarks/output/guardbench-raw.json +243 -144
  196. package/docs/paper/output/submission-bundle/benchmarks/output/guardbench-summary.json +354 -230
  197. package/docs/paper/output/submission-bundle/benchmarks/output/leaderboard/guardbench-leaderboard.json +5 -5
  198. package/docs/paper/output/submission-bundle/benchmarks/output/leaderboard/guardbench-leaderboard.md +2 -2
  199. package/docs/paper/output/submission-bundle/benchmarks/output/submission-bundle/submission-manifest.json +15 -15
  200. package/docs/paper/output/submission-bundle/benchmarks/output/submission-bundle/validation-report.json +1 -1
  201. package/docs/paper/output/submission-bundle/benchmarks/output/summary.json +52 -52
  202. package/docs/paper/output/submission-bundle/benchmarks/schemas/guardbench-raw.schema.json +21 -1
  203. package/docs/paper/output/submission-bundle/benchmarks/schemas/guardbench-summary.schema.json +23 -2
  204. package/docs/paper/output/submission-bundle/docs/paper/07-evaluation.md +5 -5
  205. package/docs/paper/output/submission-bundle/docs/paper/audrey-paper-v1.md +6 -6
  206. package/docs/paper/output/submission-bundle/docs/paper/evidence-ledger.md +1 -1
  207. package/docs/paper/output/submission-bundle/docs/paper/output/arxiv/arxiv-manifest.json +4 -4
  208. package/docs/paper/output/submission-bundle/docs/paper/output/arxiv/main.tex +6 -6
  209. package/docs/paper/output/submission-bundle/docs/paper/output/arxiv-compile-report.json +3 -3
  210. package/docs/paper/output/submission-bundle/package.json +18 -5
  211. package/docs/paper/output/submission-bundle/paper-submission-manifest.json +40 -40
  212. package/examples/fintech-ops-demo.js +12 -5
  213. package/examples/healthcare-ops-demo.js +8 -4
  214. package/examples/ollama-memory-agent.js +41 -13
  215. package/examples/stripe-demo.js +12 -5
  216. package/package.json +18 -5
  217. package/scripts/audit-release-completion.mjs +179 -101
  218. package/scripts/create-arxiv-source.mjs +20 -14
  219. package/scripts/create-paper-submission-bundle.mjs +6 -2
  220. package/scripts/finalize-release.mjs +111 -36
  221. package/scripts/prepare-release-cut.mjs +14 -6
  222. package/scripts/publish-release-bundle.mjs +62 -23
  223. package/scripts/publish-release-github-api.mjs +89 -24
  224. package/scripts/smoke-cli.js +26 -6
  225. package/scripts/sync-paper-artifacts.mjs +5 -1
  226. package/scripts/verify-arxiv-compile.mjs +52 -16
  227. package/scripts/verify-arxiv-source.mjs +45 -15
  228. package/scripts/verify-browser-launch-plan.mjs +28 -11
  229. package/scripts/verify-browser-launch-results.mjs +32 -14
  230. package/scripts/verify-paper-artifacts.mjs +539 -79
  231. package/scripts/verify-paper-claims.mjs +48 -20
  232. package/scripts/verify-paper-submission-bundle.mjs +22 -11
  233. package/scripts/verify-publication-pack.mjs +23 -9
  234. package/scripts/verify-release-readiness.mjs +250 -71
@@ -27,11 +27,14 @@ function parseArgs(argv = process.argv.slice(2)) {
27
27
 
28
28
  for (let i = 0; i < argv.length; i++) {
29
29
  const token = argv[i];
30
- if ((token === '--repository' || token === '--repo') && argv[i + 1]) args.repository = argv[++i];
30
+ if ((token === '--repository' || token === '--repo') && argv[i + 1])
31
+ args.repository = argv[++i];
31
32
  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 === '--version' || token === '--target-version') && argv[i + 1])
34
+ args.version = argv[++i];
33
35
  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);
36
+ else if (token === '--concurrency' && argv[i + 1])
37
+ args.concurrency = Number.parseInt(argv[++i], 10);
35
38
  else if (token === '--apply') args.apply = true;
36
39
  else if (token === '--json') args.json = true;
37
40
  else if (token === '--force') args.force = true;
@@ -84,7 +87,10 @@ function run(command, args, options = {}) {
84
87
  }
85
88
 
86
89
  function assertOk(result) {
87
- if (!result.ok) throw new Error(`${result.command} failed: ${result.stderr || result.stdout || result.error || result.status}`);
90
+ if (!result.ok)
91
+ throw new Error(
92
+ `${result.command} failed: ${result.stderr || result.stdout || result.error || result.status}`,
93
+ );
88
94
  return result.stdout;
89
95
  }
90
96
 
@@ -97,7 +103,9 @@ function normalized(path) {
97
103
  }
98
104
 
99
105
  function sha256(path) {
100
- return createHash('sha256').update(readFileSync(resolve(ROOT, path))).digest('hex');
106
+ return createHash('sha256')
107
+ .update(readFileSync(resolve(ROOT, path)))
108
+ .digest('hex');
101
109
  }
102
110
 
103
111
  function readJsonIfExists(path) {
@@ -106,9 +114,24 @@ function readJsonIfExists(path) {
106
114
  }
107
115
 
108
116
  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));
117
+ const changed = splitZ(
118
+ assertOk(run('git', ['-c', 'core.quotepath=false', 'diff', '--name-only', '-z', 'HEAD', '--'])),
119
+ );
120
+ const untracked = splitZ(
121
+ assertOk(
122
+ run('git', [
123
+ '-c',
124
+ 'core.quotepath=false',
125
+ 'ls-files',
126
+ '--others',
127
+ '--exclude-standard',
128
+ '-z',
129
+ ]),
130
+ ),
131
+ );
132
+ return [...new Set([...changed, ...untracked].map(normalized))].sort((a, b) =>
133
+ a.localeCompare(b),
134
+ );
112
135
  }
113
136
 
114
137
  function fileMode(path) {
@@ -136,9 +159,34 @@ function changedEntries() {
136
159
  }
137
160
 
138
161
  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 });
162
+ let result = run(
163
+ 'git',
164
+ [
165
+ 'ls-remote',
166
+ `https://github.com/${repository}.git`,
167
+ `refs/heads/${branch}`,
168
+ `refs/tags/v${version}`,
169
+ ],
170
+ { timeout: 60_000 },
171
+ );
172
+ if (
173
+ !result.ok &&
174
+ /schannel|AcquireCredentialsHandle|SEC_E_NO_CREDENTIALS/i.test(
175
+ `${result.stderr}\n${result.stdout}`,
176
+ )
177
+ ) {
178
+ result = run(
179
+ 'git',
180
+ [
181
+ '-c',
182
+ 'http.sslBackend=openssl',
183
+ 'ls-remote',
184
+ `https://github.com/${repository}.git`,
185
+ `refs/heads/${branch}`,
186
+ `refs/tags/v${version}`,
187
+ ],
188
+ { timeout: 60_000 },
189
+ );
142
190
  result.fallback = 'openssl';
143
191
  }
144
192
 
@@ -155,7 +203,10 @@ function remoteRefs(repository, branch, version) {
155
203
  }
156
204
 
157
205
  function releaseDates() {
158
- const headTime = Number.parseInt(assertOk(run('git', ['show', '-s', '--format=%ct', 'HEAD'])), 10);
206
+ const headTime = Number.parseInt(
207
+ assertOk(run('git', ['show', '-s', '--format=%ct', 'HEAD'])),
208
+ 10,
209
+ );
159
210
  const commitEpoch = headTime + 1;
160
211
  return {
161
212
  commitEpoch,
@@ -191,7 +242,9 @@ async function githubJson(token, repository, path, options = {}) {
191
242
  const payload = text ? JSON.parse(text) : null;
192
243
  if (!response.ok) {
193
244
  const message = payload?.message ?? text.slice(0, 500) ?? response.statusText;
194
- throw new Error(`GitHub API ${options.method ?? 'GET'} ${path} failed (${response.status}): ${message}`);
245
+ throw new Error(
246
+ `GitHub API ${options.method ?? 'GET'} ${path} failed (${response.status}): ${message}`,
247
+ );
195
248
  }
196
249
  return payload;
197
250
  }
@@ -238,12 +291,18 @@ function localState(args) {
238
291
  const bytes = entries.reduce((total, entry) => total + entry.bytes, 0);
239
292
  const blockers = [];
240
293
 
241
- if (!refs.result.ok) blockers.push(`Remote ref check failed: ${refs.result.stderr || refs.result.stdout || refs.result.error}`);
294
+ if (!refs.result.ok)
295
+ blockers.push(
296
+ `Remote ref check failed: ${refs.result.stderr || refs.result.stdout || refs.result.error}`,
297
+ );
242
298
  if (refs.branch && refs.branch !== localHead && !args.force) {
243
299
  blockers.push(`Remote ${args.branch} is ${refs.branch}, but local HEAD is ${localHead}`);
244
300
  }
245
301
  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');
302
+ if (!objectReport?.commit || !objectReport?.tree)
303
+ blockers.push(
304
+ 'Missing .tmp/release-git-object-report.json; run npm run release:artifacts first',
305
+ );
247
306
 
248
307
  return {
249
308
  localHead,
@@ -283,7 +342,9 @@ async function publishWithGitHubApi(args, state, token) {
283
342
  });
284
343
 
285
344
  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}`);
345
+ throw new Error(
346
+ `GitHub release tree ${tree.sha} does not match local source-bundle tree ${state.expectedReleaseTree}`,
347
+ );
287
348
  }
288
349
 
289
350
  const dates = releaseDates();
@@ -300,7 +361,9 @@ async function publishWithGitHubApi(args, state, token) {
300
361
  });
301
362
 
302
363
  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}`);
364
+ throw new Error(
365
+ `GitHub release commit ${commit.sha} does not match local source-bundle commit ${state.expectedReleaseCommit}`,
366
+ );
304
367
  }
305
368
 
306
369
  const branchUpdate = await githubJson(token, args.repository, `/git/refs/heads/${args.branch}`, {
@@ -398,12 +461,12 @@ async function main() {
398
461
  })),
399
462
  changedEntries: args.includeEntries
400
463
  ? 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
- }))
464
+ path: entry.path,
465
+ deleted: entry.deleted,
466
+ mode: entry.mode,
467
+ bytes: entry.bytes,
468
+ sha256: entry.sha256,
469
+ }))
407
470
  : undefined,
408
471
  finalizeArtifacts: state.finalizeArtifacts,
409
472
  blockers: [...state.blockers],
@@ -413,7 +476,9 @@ async function main() {
413
476
  if (args.apply) {
414
477
  const token = process.env[args.tokenEnv];
415
478
  if (!token) {
416
- report.blockers.push(`Set ${args.tokenEnv} to a GitHub token with contents:write before applying`);
479
+ report.blockers.push(
480
+ `Set ${args.tokenEnv} to a GitHub token with contents:write before applying`,
481
+ );
417
482
  } else if (report.blockers.length === 0) {
418
483
  report.publish = await publishWithGitHubApi(args, state, token);
419
484
  }
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  import { spawnSync } from 'node:child_process';
4
- import { existsSync, mkdtempSync, rmSync, readFileSync } from 'node:fs';
4
+ import { existsSync, mkdirSync, mkdtempSync, rmSync, readFileSync } from 'node:fs';
5
5
  import { tmpdir } from 'node:os';
6
6
  import { dirname, join, resolve } from 'node:path';
7
7
  import { fileURLToPath } from 'node:url';
@@ -23,7 +23,25 @@ if (!existsSync(cli)) {
23
23
  fail(`missing built CLI at ${cli}; run npm run build first`);
24
24
  }
25
25
 
26
- const tempRoot = mkdtempSync(join(tmpdir(), 'audrey-smoke-'));
26
+ function createTempRoot() {
27
+ const candidates = [process.env.AUDREY_SMOKE_TMPDIR, tmpdir(), join(root, '.tmp')].filter(
28
+ Boolean,
29
+ );
30
+ const failures = [];
31
+
32
+ for (const candidate of candidates) {
33
+ try {
34
+ mkdirSync(candidate, { recursive: true });
35
+ return mkdtempSync(join(candidate, 'audrey-smoke-'));
36
+ } catch (error) {
37
+ failures.push(`${candidate}: ${error.code ?? error.message}`);
38
+ }
39
+ }
40
+
41
+ fail(`unable to create smoke temp directory (${failures.join('; ')})`);
42
+ }
43
+
44
+ const tempRoot = createTempRoot();
27
45
  const env = {
28
46
  ...process.env,
29
47
  AUDREY_DATA_DIR: join(tempRoot, 'store'),
@@ -55,10 +73,12 @@ try {
55
73
 
56
74
  const doctor = JSON.parse(run('doctor --json', ['doctor', '--json']));
57
75
  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
- })}`);
76
+ fail(
77
+ `doctor --json returned unexpected release status: ${JSON.stringify({
78
+ version: doctor.version,
79
+ ok: doctor.ok,
80
+ })}`,
81
+ );
62
82
  }
63
83
 
64
84
  const demo = run('demo', ['demo']);
@@ -106,4 +106,8 @@ for (const [path, updater] of updates) {
106
106
  }
107
107
  }
108
108
 
109
- console.log(changed.length ? `Synced paper artifacts: ${changed.join(', ')}` : 'Paper artifacts already in sync.');
109
+ console.log(
110
+ changed.length
111
+ ? `Synced paper artifacts: ${changed.join(', ')}`
112
+ : 'Paper artifacts already in sync.',
113
+ );
@@ -37,9 +37,12 @@ function pathForReport(path) {
37
37
  }
38
38
 
39
39
  function commandExists(command) {
40
- const result = process.platform === 'win32'
41
- ? spawnSync(process.env.ComSpec ?? 'cmd.exe', ['/d', '/c', 'where', command], { encoding: 'utf-8' })
42
- : spawnSync('sh', ['-lc', `command -v ${command}`], { encoding: 'utf-8' });
40
+ const result =
41
+ process.platform === 'win32'
42
+ ? spawnSync(process.env.ComSpec ?? 'cmd.exe', ['/d', '/c', 'where', command], {
43
+ encoding: 'utf-8',
44
+ })
45
+ : spawnSync('sh', ['-lc', `command -v ${command}`], { encoding: 'utf-8' });
43
46
  return result.status === 0;
44
47
  }
45
48
 
@@ -47,16 +50,17 @@ function compilerPlan(exists = commandExists) {
47
50
  if (exists('tectonic')) {
48
51
  return {
49
52
  name: 'tectonic',
50
- stages: [
51
- { command: 'tectonic', args: ['--keep-logs', '--keep-intermediates', MAIN_TEX] },
52
- ],
53
+ stages: [{ command: 'tectonic', args: ['--keep-logs', '--keep-intermediates', MAIN_TEX] }],
53
54
  };
54
55
  }
55
56
  if (exists('latexmk')) {
56
57
  return {
57
58
  name: 'latexmk',
58
59
  stages: [
59
- { command: 'latexmk', args: ['-pdf', '-interaction=nonstopmode', '-halt-on-error', MAIN_TEX] },
60
+ {
61
+ command: 'latexmk',
62
+ args: ['-pdf', '-interaction=nonstopmode', '-halt-on-error', MAIN_TEX],
63
+ },
60
64
  ],
61
65
  };
62
66
  }
@@ -78,7 +82,18 @@ function compilerPlan(exists = commandExists) {
78
82
  stages: [
79
83
  {
80
84
  command: 'uvx',
81
- args: ['tecto', '-X', 'compile', '--bundle', '__TECTONIC_BUNDLE_URL__', '--keep-logs', '--keep-intermediates', '--reruns', '2', MAIN_TEX],
85
+ args: [
86
+ 'tecto',
87
+ '-X',
88
+ 'compile',
89
+ '--bundle',
90
+ '__TECTONIC_BUNDLE_URL__',
91
+ '--keep-logs',
92
+ '--keep-intermediates',
93
+ '--reruns',
94
+ '2',
95
+ MAIN_TEX,
96
+ ],
82
97
  },
83
98
  ],
84
99
  };
@@ -164,7 +179,14 @@ async function startTectonicBundleProxy(bundleUrl = TECTONIC_BUNDLE_URL) {
164
179
  if (request.headers.range) headers.range = request.headers.range;
165
180
  const upstream = await fetch(remoteUrl, { headers });
166
181
  response.statusCode = upstream.status;
167
- for (const header of ['accept-ranges', 'content-length', 'content-range', 'content-type', 'etag', 'last-modified']) {
182
+ for (const header of [
183
+ 'accept-ranges',
184
+ 'content-length',
185
+ 'content-range',
186
+ 'content-type',
187
+ 'etag',
188
+ 'last-modified',
189
+ ]) {
168
190
  const value = upstream.headers.get(header);
169
191
  if (value) response.setHeader(header, value);
170
192
  }
@@ -196,7 +218,7 @@ async function startTectonicBundleProxy(bundleUrl = TECTONIC_BUNDLE_URL) {
196
218
  function stageWithBundle(stage, bundleUrl) {
197
219
  return {
198
220
  command: stage.command,
199
- args: stage.args.map(arg => arg === '__TECTONIC_BUNDLE_URL__' ? bundleUrl : arg),
221
+ args: stage.args.map(arg => (arg === '__TECTONIC_BUNDLE_URL__' ? bundleUrl : arg)),
200
222
  };
201
223
  }
202
224
 
@@ -210,7 +232,12 @@ function runStage(stage, cwd) {
210
232
  child.kill();
211
233
  if (!settled) {
212
234
  settled = true;
213
- resolveRun({ status: 1, signal: 'TIMEOUT', stdout, stderr: `${stderr}\nTimed out after 120000ms`.trim() });
235
+ resolveRun({
236
+ status: 1,
237
+ signal: 'TIMEOUT',
238
+ stdout,
239
+ stderr: `${stderr}\nTimed out after 120000ms`.trim(),
240
+ });
214
241
  }
215
242
  }, 120000);
216
243
 
@@ -297,7 +324,9 @@ export async function verifyArxivCompile(options = {}) {
297
324
  const logLines = [];
298
325
  try {
299
326
  proxy = plan.bundleProxy ? await startTectonicBundleProxy() : null;
300
- const stages = proxy ? plan.stages.map(stage => stageWithBundle(stage, proxy.url)) : plan.stages;
327
+ const stages = proxy
328
+ ? plan.stages.map(stage => stageWithBundle(stage, proxy.url))
329
+ : plan.stages;
301
330
  for (const stage of stages) {
302
331
  logLines.push(`$ ${stage.command} ${stage.args.join(' ')}`);
303
332
  const result = await runStage(stage, outDir);
@@ -344,7 +373,7 @@ export function verifyArxivCompileReport(options = {}) {
344
373
  const allowPending = options.allowPending !== false;
345
374
  const failures = [];
346
375
  const blockers = [];
347
- let report = null;
376
+ let report;
348
377
 
349
378
  try {
350
379
  report = JSON.parse(readFileSync(reportPath, 'utf-8'));
@@ -359,7 +388,9 @@ export function verifyArxivCompileReport(options = {}) {
359
388
  }
360
389
 
361
390
  try {
362
- failures.push(...validateSchema(report, readJson(pathForReport(schemaPath)), 'audrey-arxiv-compile-report'));
391
+ failures.push(
392
+ ...validateSchema(report, readJson(pathForReport(schemaPath)), 'audrey-arxiv-compile-report'),
393
+ );
363
394
  } catch (error) {
364
395
  failures.push(`schema: ${error.message}`);
365
396
  }
@@ -386,8 +417,13 @@ export function verifyArxivCompileReport(options = {}) {
386
417
  } else if (report.status === 'failed') {
387
418
  failures.push(...(report.failures?.length ? report.failures : ['arXiv compile failed']));
388
419
  } else if (report.status === 'passed') {
389
- if (!report.outputPdf || !existsSync(fromRoot(report.outputPdf))) failures.push('arxiv-compile-report.json: outputPdf is missing');
390
- if (report.outputPdf && report.outputPdfSha256 && sha256File(fromRoot(report.outputPdf)) !== report.outputPdfSha256) {
420
+ if (!report.outputPdf || !existsSync(fromRoot(report.outputPdf)))
421
+ failures.push('arxiv-compile-report.json: outputPdf is missing');
422
+ if (
423
+ report.outputPdf &&
424
+ report.outputPdfSha256 &&
425
+ sha256File(fromRoot(report.outputPdf)) !== report.outputPdfSha256
426
+ ) {
391
427
  failures.push('arxiv-compile-report.json: outputPdfSha256 is stale');
392
428
  }
393
429
  }
@@ -41,7 +41,8 @@ function checkSourceHash(label, sourcePath, expectedHash, failures) {
41
41
  failures.push(`arxiv-manifest.json: missing source file for ${label}: ${sourcePath}`);
42
42
  return;
43
43
  }
44
- if (expectedHash !== sha256File(absolute)) failures.push(`arxiv-manifest.json: ${label} hash is stale`);
44
+ if (expectedHash !== sha256File(absolute))
45
+ failures.push(`arxiv-manifest.json: ${label} hash is stale`);
45
46
  }
46
47
 
47
48
  function parseArgs(argv = process.argv.slice(2)) {
@@ -76,7 +77,7 @@ export function verifyArxivSourcePackage(options = {}) {
76
77
  const schemaPath = fromRoot(options.schema ?? DEFAULT_SCHEMA);
77
78
  const manifestPath = join(dir, 'arxiv-manifest.json');
78
79
  const failures = [];
79
- let manifest = null;
80
+ let manifest;
80
81
 
81
82
  try {
82
83
  manifest = readJson(manifestPath);
@@ -99,12 +100,29 @@ export function verifyArxivSourcePackage(options = {}) {
99
100
 
100
101
  const listed = new Map((manifest.files ?? []).map(file => [file.path, file]));
101
102
  for (const file of REQUIRED_FILES) {
102
- if (!listed.has(file)) failures.push(`arxiv-manifest.json: missing required file record ${file}`);
103
+ if (!listed.has(file))
104
+ failures.push(`arxiv-manifest.json: missing required file record ${file}`);
103
105
  }
104
- if (listed.has('arxiv-manifest.json')) failures.push('arxiv-manifest.json: must not include a self-hash file record');
105
- checkSourceHash('sourceMarkdown', manifest.sourceMarkdown, manifest.sourceHashes?.sourceMarkdown, failures);
106
- checkSourceHash('publicationPack', manifest.publicationPack, manifest.sourceHashes?.publicationPack, failures);
107
- checkSourceHash('referencesBib', 'docs/paper/references.bib', manifest.sourceHashes?.referencesBib, failures);
106
+ if (listed.has('arxiv-manifest.json'))
107
+ failures.push('arxiv-manifest.json: must not include a self-hash file record');
108
+ checkSourceHash(
109
+ 'sourceMarkdown',
110
+ manifest.sourceMarkdown,
111
+ manifest.sourceHashes?.sourceMarkdown,
112
+ failures,
113
+ );
114
+ checkSourceHash(
115
+ 'publicationPack',
116
+ manifest.publicationPack,
117
+ manifest.sourceHashes?.publicationPack,
118
+ failures,
119
+ );
120
+ checkSourceHash(
121
+ 'referencesBib',
122
+ 'docs/paper/references.bib',
123
+ manifest.sourceHashes?.referencesBib,
124
+ failures,
125
+ );
108
126
 
109
127
  for (const [file, record] of listed) {
110
128
  const path = join(dir, file);
@@ -126,11 +144,14 @@ export function verifyArxivSourcePackage(options = {}) {
126
144
  }
127
145
  }
128
146
 
129
- const actualFiles = walkFiles(dir).filter(file => file !== 'arxiv-manifest.json').sort();
147
+ const actualFiles = walkFiles(dir)
148
+ .filter(file => file !== 'arxiv-manifest.json')
149
+ .sort();
130
150
  const listedFiles = [...listed.keys()].sort();
131
151
  const listedSet = new Set(listedFiles);
132
152
  for (const file of actualFiles) {
133
- if (!listedSet.has(file)) failures.push(`${file}: present in package but missing from manifest`);
153
+ if (!listedSet.has(file))
154
+ failures.push(`${file}: present in package but missing from manifest`);
134
155
  }
135
156
 
136
157
  const mainPath = join(dir, 'main.tex');
@@ -138,24 +159,33 @@ export function verifyArxivSourcePackage(options = {}) {
138
159
  const main = existsSync(mainPath) ? readFileSync(mainPath, 'utf-8') : '';
139
160
  const bib = existsSync(bibPath) ? readFileSync(bibPath, 'utf-8') : '';
140
161
  const citationCount = [...main.matchAll(/\\cite\{([^}]+)\}/g)].length;
141
- const citedIds = new Set([...main.matchAll(/\\cite\{([^}]+)\}/g)].flatMap(match => match[1].split(',').map(id => id.trim())));
162
+ const citedIds = new Set(
163
+ [...main.matchAll(/\\cite\{([^}]+)\}/g)].flatMap(match =>
164
+ match[1].split(',').map(id => id.trim()),
165
+ ),
166
+ );
142
167
  const bibIds = new Set([...bib.matchAll(/@\w+\s*\{\s*([^,\s]+)/g)].map(match => match[1].trim()));
143
168
  const bibEntries = countBibEntries(bib);
144
169
 
145
170
  if (!main.includes('\\documentclass')) failures.push('main.tex: missing documentclass');
146
171
  if (!main.includes('\\begin{abstract}')) failures.push('main.tex: missing abstract');
147
- if (!main.includes('\\bibliography{references}')) failures.push('main.tex: missing bibliography command');
172
+ if (!main.includes('\\bibliography{references}'))
173
+ failures.push('main.tex: missing bibliography command');
148
174
  if (main.includes('[@')) failures.push('main.tex: contains unconverted Markdown citation syntax');
149
- if (/^#{1,6}\s/m.test(main)) failures.push('main.tex: contains unconverted Markdown heading syntax');
175
+ if (/^#{1,6}\s/m.test(main))
176
+ failures.push('main.tex: contains unconverted Markdown heading syntax');
150
177
  if (main.includes(SEEDED_SECRET)) failures.push('main.tex: contains seeded raw secret');
151
- if (/([A-Z]:\\|file:\/\/|C:\\Users\\|B:\\Projects\\)/i.test(main)) failures.push('main.tex: contains a local absolute path');
178
+ if (/([A-Z]:\\|file:\/\/|C:\\Users\\|B:\\Projects\\)/i.test(main))
179
+ failures.push('main.tex: contains a local absolute path');
152
180
  if (citationCount < 1) failures.push('main.tex: expected at least one citation');
153
181
  if (bibEntries !== 21) failures.push(`references.bib: expected 21 entries, found ${bibEntries}`);
154
182
  for (const id of citedIds) {
155
183
  if (!bibIds.has(id)) failures.push(`main.tex: cites missing bibliography id ${id}`);
156
184
  }
157
- if (manifest.tex?.citationCount !== citationCount) failures.push('arxiv-manifest.json: citation count is stale');
158
- if (manifest.tex?.bibEntryCount !== bibEntries) failures.push('arxiv-manifest.json: bibliography count is stale');
185
+ if (manifest.tex?.citationCount !== citationCount)
186
+ failures.push('arxiv-manifest.json: citation count is stale');
187
+ if (manifest.tex?.bibEntryCount !== bibEntries)
188
+ failures.push('arxiv-manifest.json: bibliography count is stale');
159
189
 
160
190
  return {
161
191
  ok: failures.length === 0,
@@ -89,7 +89,9 @@ function isAllowedHost(platform, value) {
89
89
  }
90
90
 
91
91
  function hasPendingBoundary(text) {
92
- return /\b(pending|not claim|not claimed|does not report|remain pending|live evidence|strict evidence)\b/i.test(text);
92
+ return /\b(pending|not claim|not claimed|does not report|remain pending|live evidence|strict evidence)\b/i.test(
93
+ text,
94
+ );
93
95
  }
94
96
 
95
97
  function validateTarget(target, entryMap, sourceIds) {
@@ -107,7 +109,9 @@ function validateTarget(target, entryMap, sourceIds) {
107
109
  continue;
108
110
  }
109
111
  if (entry.platform !== target.platform) {
110
- failures.push(`${target.id}: entry ${entryId} belongs to ${entry.platform}, not ${target.platform}`);
112
+ failures.push(
113
+ `${target.id}: entry ${entryId} belongs to ${entry.platform}, not ${target.platform}`,
114
+ );
111
115
  }
112
116
  if (!allowedEntries.has(entryId)) {
113
117
  failures.push(`${target.id}: entry ${entryId} is not approved for ${target.platform}`);
@@ -116,7 +120,9 @@ function validateTarget(target, entryMap, sourceIds) {
116
120
  failures.push(`${target.id}: entry ${entryId} exceeds maxChars`);
117
121
  }
118
122
  if (/\b(Mem0|Zep)\b/.test(entry.text) && !hasPendingBoundary(entry.text)) {
119
- failures.push(`${target.id}: entry ${entryId} mentions Mem0/Zep without pending boundary language`);
123
+ failures.push(
124
+ `${target.id}: entry ${entryId} mentions Mem0/Zep without pending boundary language`,
125
+ );
120
126
  }
121
127
  targetEntries.push(entry);
122
128
  }
@@ -124,7 +130,8 @@ function validateTarget(target, entryMap, sourceIds) {
124
130
  if (!sourceIds.has(sourceId)) failures.push(`${target.id}: unknown sourceRef ${sourceId}`);
125
131
  }
126
132
  for (const artifact of target.artifactRefs) {
127
- if (!existsSync(fromRoot(artifact))) failures.push(`${target.id}: missing artifactRef ${artifact}`);
133
+ if (!existsSync(fromRoot(artifact)))
134
+ failures.push(`${target.id}: missing artifactRef ${artifact}`);
128
135
  }
129
136
  if (target.platform === 'reddit' && target.manualRuleCheckRequired !== true) {
130
137
  failures.push(`${target.id}: Reddit target must require a manual subreddit rule check`);
@@ -135,16 +142,21 @@ function validateTarget(target, entryMap, sourceIds) {
135
142
  if (target.platform === 'arxiv' && target.manualRuleCheckRequired !== true) {
136
143
  failures.push(`${target.id}: arXiv target must require a manual category/metadata check`);
137
144
  }
138
- if (!target.humanRequired) failures.push(`${target.id}: browser launch targets must require a human operator`);
139
- if (!target.authRequired) failures.push(`${target.id}: browser launch targets must require authenticated account review`);
140
- if (target.operatorChecks.length < 2) failures.push(`${target.id}: operator checklist is too thin`);
145
+ if (!target.humanRequired)
146
+ failures.push(`${target.id}: browser launch targets must require a human operator`);
147
+ if (!target.authRequired)
148
+ failures.push(`${target.id}: browser launch targets must require authenticated account review`);
149
+ if (target.operatorChecks.length < 2)
150
+ failures.push(`${target.id}: operator checklist is too thin`);
141
151
  if (target.postSubmitChecks.length < 1) failures.push(`${target.id}: missing post-submit checks`);
142
152
  if (
143
153
  target.platform === 'x' &&
144
154
  target.status === 'blocked-until-artifact-url' &&
145
155
  !targetEntries.some(entry => entry.requiresArtifactUrl === true)
146
156
  ) {
147
- failures.push(`${target.id}: X artifact-url launch target must include a publication entry with reserved URL budget`);
157
+ failures.push(
158
+ `${target.id}: X artifact-url launch target must include a publication entry with reserved URL budget`,
159
+ );
148
160
  }
149
161
 
150
162
  return failures;
@@ -160,7 +172,9 @@ export async function verifyBrowserLaunchPlan(options = {}) {
160
172
  const ids = new Set();
161
173
  const targetReports = [];
162
174
  const failures = [
163
- ...validateSchema(plan, schema, 'audrey-browser-launch-plan').map(failure => `browser launch plan schema: ${failure}`),
175
+ ...validateSchema(plan, schema, 'audrey-browser-launch-plan').map(
176
+ failure => `browser launch plan schema: ${failure}`,
177
+ ),
164
178
  ];
165
179
 
166
180
  if (!publicationReport.ok) {
@@ -170,7 +184,8 @@ export async function verifyBrowserLaunchPlan(options = {}) {
170
184
  failures.push('browser launch plan must point at docs/paper/publication-pack.json');
171
185
  }
172
186
  for (const command of REQUIRED_PREFLIGHT_COMMANDS) {
173
- if (!(plan.preflightCommands ?? []).includes(command)) failures.push(`Missing browser-launch preflight command: ${command}`);
187
+ if (!(plan.preflightCommands ?? []).includes(command))
188
+ failures.push(`Missing browser-launch preflight command: ${command}`);
174
189
  }
175
190
  for (const target of plan.targets ?? []) {
176
191
  const targetFailures = [];
@@ -192,7 +207,9 @@ export async function verifyBrowserLaunchPlan(options = {}) {
192
207
  for (const id of REQUIRED_TARGETS) {
193
208
  if (!ids.has(id)) failures.push(`Missing browser-launch target: ${id}`);
194
209
  }
195
- const ordered = [...(plan.targets ?? [])].sort((a, b) => a.order - b.order).map(target => target.id);
210
+ const ordered = [...(plan.targets ?? [])]
211
+ .sort((a, b) => a.order - b.order)
212
+ .map(target => target.id);
196
213
  if (ordered.join('|') !== REQUIRED_TARGETS.join('|')) {
197
214
  failures.push(`Browser-launch target order must be ${REQUIRED_TARGETS.join(', ')}`);
198
215
  }