cloving 1.0.1 → 1.2.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.
Files changed (309) hide show
  1. package/README.md +251 -20
  2. package/assets/watch-fonts/fira-code-OFL.md +93 -0
  3. package/assets/watch-fonts/fira-code-latin-400-normal.woff2 +0 -0
  4. package/assets/watch-fonts/fira-code-latin-500-normal.woff2 +0 -0
  5. package/assets/watch-fonts/heebo-OFL.md +93 -0
  6. package/assets/watch-fonts/heebo-latin-500-normal.woff2 +0 -0
  7. package/assets/watch-fonts/heebo-latin-700-normal.woff2 +0 -0
  8. package/assets/watch-fonts/heebo-latin-800-normal.woff2 +0 -0
  9. package/assets/watch-fonts/manifest.json +112 -0
  10. package/assets/watch-fonts/space-grotesk-OFL.md +93 -0
  11. package/assets/watch-fonts/space-grotesk-latin-400-normal.woff2 +0 -0
  12. package/assets/watch-fonts/space-grotesk-latin-500-normal.woff2 +0 -0
  13. package/assets/watch-fonts/space-grotesk-latin-600-normal.woff2 +0 -0
  14. package/assets/watch-fonts/space-grotesk-latin-700-normal.woff2 +0 -0
  15. package/dist/src/authority/commands.d.ts +1 -0
  16. package/dist/src/authority/commands.js +33 -4
  17. package/dist/src/authority/dispatch-decision.d.ts +1 -0
  18. package/dist/src/authority/dispatch-decision.js +7 -4
  19. package/dist/src/authority/events.js +2 -2
  20. package/dist/src/authority/handoff-chain.d.ts +24 -0
  21. package/dist/src/authority/handoff-chain.js +46 -0
  22. package/dist/src/authority/reconciliation.d.ts +3 -0
  23. package/dist/src/authority/reconciliation.js +21 -5
  24. package/dist/src/authority/transitions.d.ts +1 -1
  25. package/dist/src/authority/transitions.js +5 -0
  26. package/dist/src/broker/actor/authority-queries.d.ts +4 -0
  27. package/dist/src/broker/actor/authority-queries.js +51 -2
  28. package/dist/src/broker/actor/authority-session.d.ts +2 -0
  29. package/dist/src/broker/actor/authority-session.js +3 -4
  30. package/dist/src/broker/actor/delivery-intents.d.ts +1 -0
  31. package/dist/src/broker/actor/effect-delivery.js +9 -0
  32. package/dist/src/broker/authority-admission.js +13 -5
  33. package/dist/src/chats/analysis-batches.d.ts +42 -0
  34. package/dist/src/chats/analysis-batches.js +97 -0
  35. package/dist/src/chats/analysis-checkpoint.d.ts +29 -0
  36. package/dist/src/chats/analysis-checkpoint.js +31 -0
  37. package/dist/src/chats/analysis-contract.d.ts +80 -0
  38. package/dist/src/chats/analysis-contract.js +16 -0
  39. package/dist/src/chats/analysis-data.d.ts +3 -0
  40. package/dist/src/chats/analysis-data.js +85 -0
  41. package/dist/src/chats/analysis-input.d.ts +18 -0
  42. package/dist/src/chats/analysis-input.js +97 -0
  43. package/dist/src/chats/analysis-links.d.ts +2 -0
  44. package/dist/src/chats/analysis-links.js +25 -0
  45. package/dist/src/chats/analysis-merge.d.ts +16 -0
  46. package/dist/src/chats/analysis-merge.js +134 -0
  47. package/dist/src/chats/analysis-prompt.d.ts +18 -0
  48. package/dist/src/chats/analysis-prompt.js +42 -0
  49. package/dist/src/chats/analysis-proposal.d.ts +4 -0
  50. package/dist/src/chats/analysis-proposal.js +41 -0
  51. package/dist/src/chats/analysis-provenance.d.ts +4 -0
  52. package/dist/src/chats/analysis-provenance.js +99 -0
  53. package/dist/src/chats/analysis-shape.d.ts +4 -0
  54. package/dist/src/chats/analysis-shape.js +235 -0
  55. package/dist/src/chats/analysis.d.ts +3 -0
  56. package/dist/src/chats/analysis.js +42 -0
  57. package/dist/src/chats/corpus-input.d.ts +5 -0
  58. package/dist/src/chats/corpus-input.js +288 -0
  59. package/dist/src/chats/destination.js +3 -1
  60. package/dist/src/chats/import.d.ts +8 -6
  61. package/dist/src/chats/import.js +195 -23
  62. package/dist/src/chats/input-file.d.ts +3 -0
  63. package/dist/src/chats/input-file.js +32 -0
  64. package/dist/src/chats/normalize.d.ts +11 -2
  65. package/dist/src/chats/normalize.js +18 -2
  66. package/dist/src/chats/previous-import.d.ts +5 -0
  67. package/dist/src/chats/previous-import.js +34 -0
  68. package/dist/src/chats/reader.d.ts +7 -1
  69. package/dist/src/chats/reader.js +46 -15
  70. package/dist/src/chats/redact-import.d.ts +14 -0
  71. package/dist/src/chats/redact-import.js +141 -0
  72. package/dist/src/chats/redaction.d.ts +41 -0
  73. package/dist/src/chats/redaction.js +161 -0
  74. package/dist/src/chats/reference-mapping.d.ts +16 -0
  75. package/dist/src/chats/reference-mapping.js +153 -0
  76. package/dist/src/chats/revision-input.d.ts +3 -0
  77. package/dist/src/chats/revision-input.js +180 -0
  78. package/dist/src/chats/revision.d.ts +48 -0
  79. package/dist/src/chats/revision.js +94 -0
  80. package/dist/src/chats/selection.d.ts +25 -0
  81. package/dist/src/chats/selection.js +109 -0
  82. package/dist/src/chats/source.d.ts +23 -0
  83. package/dist/src/chats/source.js +135 -0
  84. package/dist/src/chats/structure.d.ts +57 -0
  85. package/dist/src/chats/structure.js +216 -0
  86. package/dist/src/chats/workflow-generation-projection.d.ts +8 -0
  87. package/dist/src/chats/workflow-generation-projection.js +75 -0
  88. package/dist/src/chats/workflow-generation-source.d.ts +25 -0
  89. package/dist/src/chats/workflow-generation-source.js +124 -0
  90. package/dist/src/chats/workflow-generation-text.d.ts +23 -0
  91. package/dist/src/chats/workflow-generation-text.js +74 -0
  92. package/dist/src/chats/workflow-generation.d.ts +69 -0
  93. package/dist/src/chats/workflow-generation.js +142 -0
  94. package/dist/src/cli/arguments.d.ts +8 -0
  95. package/dist/src/cli/arguments.js +94 -13
  96. package/dist/src/cli/client.d.ts +1 -0
  97. package/dist/src/cli/client.js +38 -1
  98. package/dist/src/cli/commands.d.ts +3 -0
  99. package/dist/src/cli/commands.js +29 -11
  100. package/dist/src/cli/main.d.ts +2 -1
  101. package/dist/src/cli/main.js +61 -14
  102. package/dist/src/cli/render.d.ts +3 -0
  103. package/dist/src/cli/render.js +122 -7
  104. package/dist/src/cli/usage-render.d.ts +3 -0
  105. package/dist/src/cli/usage-render.js +28 -0
  106. package/dist/src/cli/usage.d.ts +3 -2
  107. package/dist/src/cli/usage.js +42 -7
  108. package/dist/src/cli/watch-actions.d.ts +10 -0
  109. package/dist/src/cli/watch-actions.js +58 -0
  110. package/dist/src/cli/watch-board-view.d.ts +44 -1
  111. package/dist/src/cli/watch-board-view.js +137 -18
  112. package/dist/src/cli/watch-board.d.ts +7 -1
  113. package/dist/src/cli/watch-board.js +48 -11
  114. package/dist/src/cli/watch-card-client.d.ts +1 -0
  115. package/dist/src/cli/watch-card-client.js +44 -0
  116. package/dist/src/cli/watch-card-forms.d.ts +2 -0
  117. package/dist/src/cli/watch-card-forms.js +33 -0
  118. package/dist/src/cli/watch-card-reply.d.ts +5 -0
  119. package/dist/src/cli/watch-card-reply.js +34 -0
  120. package/dist/src/cli/watch-card-view.d.ts +40 -0
  121. package/dist/src/cli/watch-card-view.js +86 -0
  122. package/dist/src/cli/watch-client.d.ts +1 -0
  123. package/dist/src/cli/watch-client.js +122 -0
  124. package/dist/src/cli/watch-model.d.ts +10 -4
  125. package/dist/src/cli/watch-model.js +61 -67
  126. package/dist/src/cli/watch-page.d.ts +1 -1
  127. package/dist/src/cli/watch-page.js +89 -86
  128. package/dist/src/cli/watch-phases.js +3 -3
  129. package/dist/src/cli/watch-pr-board.d.ts +3 -0
  130. package/dist/src/cli/watch-pr-board.js +26 -0
  131. package/dist/src/cli/watch-pr-command.d.ts +18 -0
  132. package/dist/src/cli/watch-pr-command.js +74 -0
  133. package/dist/src/cli/watch-pr-identity.d.ts +32 -0
  134. package/dist/src/cli/watch-pr-identity.js +87 -0
  135. package/dist/src/cli/watch-pr-observer.d.ts +20 -0
  136. package/dist/src/cli/watch-pr-observer.js +150 -0
  137. package/dist/src/cli/watch-pr-settings.d.ts +8 -0
  138. package/dist/src/cli/watch-pr-settings.js +47 -0
  139. package/dist/src/cli/watch-pull-request.d.ts +10 -0
  140. package/dist/src/cli/watch-pull-request.js +130 -0
  141. package/dist/src/cli/watch-reads.d.ts +7 -1
  142. package/dist/src/cli/watch-reads.js +44 -18
  143. package/dist/src/cli/watch-render.d.ts +29 -2
  144. package/dist/src/cli/watch-render.js +11 -3
  145. package/dist/src/cli/watch-run-input.d.ts +14 -0
  146. package/dist/src/cli/watch-run-input.js +49 -0
  147. package/dist/src/cli/watch-server.d.ts +3 -0
  148. package/dist/src/cli/watch-server.js +77 -8
  149. package/dist/src/cli/watch-start-view.d.ts +18 -0
  150. package/dist/src/cli/watch-start-view.js +77 -0
  151. package/dist/src/cli/watch-turn.d.ts +1 -0
  152. package/dist/src/cli/watch-turn.js +8 -3
  153. package/dist/src/cli/watch-usage.d.ts +6 -0
  154. package/dist/src/cli/watch-usage.js +65 -0
  155. package/dist/src/cli/watch-view.d.ts +22 -0
  156. package/dist/src/cli/watch-view.js +111 -19
  157. package/dist/src/cli.js +48 -6
  158. package/dist/src/daemon/analysis-launch.d.ts +5 -0
  159. package/dist/src/daemon/analysis-launch.js +81 -0
  160. package/dist/src/daemon/analysis-token.d.ts +6 -0
  161. package/dist/src/daemon/analysis-token.js +88 -0
  162. package/dist/src/daemon/analysis-worker.d.ts +20 -0
  163. package/dist/src/daemon/analysis-worker.js +271 -0
  164. package/dist/src/daemon/chats-batch-binding.d.ts +23 -0
  165. package/dist/src/daemon/chats-batch-binding.js +99 -0
  166. package/dist/src/daemon/chats-capture.d.ts +18 -0
  167. package/dist/src/daemon/chats-capture.js +194 -0
  168. package/dist/src/daemon/chats-checkpoints.d.ts +41 -0
  169. package/dist/src/daemon/chats-checkpoints.js +186 -0
  170. package/dist/src/daemon/chats-files.d.ts +42 -0
  171. package/dist/src/daemon/chats-files.js +252 -0
  172. package/dist/src/daemon/chats-follow-up.d.ts +38 -0
  173. package/dist/src/daemon/chats-follow-up.js +180 -0
  174. package/dist/src/daemon/chats-question.d.ts +15 -0
  175. package/dist/src/daemon/chats-question.js +93 -0
  176. package/dist/src/daemon/chats-worker.d.ts +13 -0
  177. package/dist/src/daemon/chats-worker.js +201 -0
  178. package/dist/src/daemon/claude-turn.d.ts +11 -0
  179. package/dist/src/daemon/claude-turn.js +96 -15
  180. package/dist/src/daemon/claude-worker.d.ts +2 -1
  181. package/dist/src/daemon/claude-worker.js +92 -45
  182. package/dist/src/daemon/codex-stream.js +16 -0
  183. package/dist/src/daemon/daemon.d.ts +8 -1
  184. package/dist/src/daemon/daemon.js +51 -14
  185. package/dist/src/daemon/delivery-router.js +6 -0
  186. package/dist/src/daemon/github-calls.d.ts +4 -0
  187. package/dist/src/daemon/github-calls.js +16 -7
  188. package/dist/src/daemon/github-ci.d.ts +6 -0
  189. package/dist/src/daemon/github-ci.js +170 -0
  190. package/dist/src/daemon/github-merge-call.d.ts +14 -0
  191. package/dist/src/daemon/github-merge-call.js +73 -0
  192. package/dist/src/daemon/github-merge.d.ts +3 -5
  193. package/dist/src/daemon/github-merge.js +52 -95
  194. package/dist/src/daemon/github-methods.d.ts +28 -0
  195. package/dist/src/daemon/github-methods.js +84 -16
  196. package/dist/src/daemon/github-operation.d.ts +2 -0
  197. package/dist/src/daemon/github-retry.d.ts +6 -0
  198. package/dist/src/daemon/github-retry.js +49 -0
  199. package/dist/src/daemon/github-ticket-status.d.ts +3 -0
  200. package/dist/src/daemon/github-ticket-status.js +294 -0
  201. package/dist/src/daemon/github-worker.js +2 -1
  202. package/dist/src/daemon/handoff-worker.d.ts +10 -0
  203. package/dist/src/daemon/handoff-worker.js +232 -0
  204. package/dist/src/daemon/issue-queue.d.ts +2 -0
  205. package/dist/src/daemon/issue-queue.js +186 -43
  206. package/dist/src/daemon/notify-journal.d.ts +18 -0
  207. package/dist/src/daemon/notify-journal.js +108 -0
  208. package/dist/src/daemon/notify-message.js +2 -1
  209. package/dist/src/daemon/notify.js +176 -37
  210. package/dist/src/daemon/operation-journal.d.ts +1 -0
  211. package/dist/src/daemon/operation-journal.js +4 -2
  212. package/dist/src/daemon/retrying-turn.d.ts +12 -0
  213. package/dist/src/daemon/retrying-turn.js +231 -0
  214. package/dist/src/daemon/ticket-dependency-waits.d.ts +18 -0
  215. package/dist/src/daemon/ticket-dependency-waits.js +60 -0
  216. package/dist/src/daemon/ticket-registration.d.ts +8 -4
  217. package/dist/src/daemon/ticket-registration.js +76 -22
  218. package/dist/src/daemon/ticket-source.d.ts +4 -1
  219. package/dist/src/daemon/ticket-source.js +8 -2
  220. package/dist/src/decision-visibility.d.ts +2 -0
  221. package/dist/src/decision-visibility.js +10 -0
  222. package/dist/src/execution-pin.d.ts +4 -0
  223. package/dist/src/execution-pin.js +23 -2
  224. package/dist/src/host/start-delivery.d.ts +2 -1
  225. package/dist/src/host/start-delivery.js +1 -1
  226. package/dist/src/host/step-bridge-host.d.ts +1 -0
  227. package/dist/src/host/step-bridge-host.js +16 -0
  228. package/dist/src/host/world-reconciliation.d.ts +3 -0
  229. package/dist/src/host/world-reconciliation.js +9 -0
  230. package/dist/src/host/world-runs.js +14 -1
  231. package/dist/src/issue-identity.d.ts +6 -0
  232. package/dist/src/issue-identity.js +23 -0
  233. package/dist/src/service/queue-runs.d.ts +3 -0
  234. package/dist/src/service/queue-runs.js +39 -0
  235. package/dist/src/service/registry.d.ts +8 -2
  236. package/dist/src/service/registry.js +20 -8
  237. package/dist/src/service/replies.d.ts +2 -0
  238. package/dist/src/service/run-handlers.js +54 -30
  239. package/dist/src/service/service.d.ts +3 -0
  240. package/dist/src/service/service.js +3 -1
  241. package/dist/src/service/submission-handler.d.ts +1 -0
  242. package/dist/src/service/submission-handler.js +92 -13
  243. package/dist/src/service/worker-totals.d.ts +3 -0
  244. package/dist/src/service/worker-totals.js +52 -0
  245. package/dist/src/step-bridge.d.ts +9 -0
  246. package/dist/src/steps/handoff.d.ts +2 -0
  247. package/dist/src/steps/handoff.js +13 -0
  248. package/dist/src/ticket-dependencies.d.ts +1 -0
  249. package/dist/src/ticket-dependencies.js +15 -0
  250. package/dist/src/ticket-status.d.ts +8 -0
  251. package/dist/src/ticket-status.js +48 -0
  252. package/dist/src/token-prices.d.ts +21 -0
  253. package/dist/src/token-prices.js +108 -0
  254. package/dist/src/worker-usage.d.ts +31 -0
  255. package/dist/src/worker-usage.js +44 -0
  256. package/dist/src/workflow-admission.d.ts +1 -0
  257. package/dist/src/workflow-candidate.d.ts +29 -0
  258. package/dist/src/workflow-candidate.js +60 -0
  259. package/dist/src/workflow-contracts.d.ts +4 -0
  260. package/dist/src/workflow-contracts.js +32 -5
  261. package/dist/src/workflow-declaration.d.ts +12 -1
  262. package/dist/src/workflow-declaration.js +71 -13
  263. package/dist/src/workflow-discovery.d.ts +18 -0
  264. package/dist/src/workflow-discovery.js +33 -0
  265. package/dist/src/workflow-refusals.d.ts +6 -0
  266. package/dist/src/workflow-refusals.js +39 -0
  267. package/dist/src/workflows.d.ts +3 -1
  268. package/dist/src/workflows.js +2 -0
  269. package/dist/tools/admit-workflow.d.ts +13 -0
  270. package/dist/tools/admit-workflow.js +94 -0
  271. package/dist/tools/self-host-processes.js +7 -2
  272. package/dist/tools/self-host-project.d.ts +17 -0
  273. package/dist/tools/self-host-project.js +177 -0
  274. package/dist/tools/self-host-workflows.d.ts +1 -1
  275. package/dist/tools/self-host-workflows.js +2 -2
  276. package/dist/tools/self-host.js +30 -84
  277. package/dist/tools/self-update-host.d.ts +7 -0
  278. package/dist/tools/self-update-host.js +48 -1
  279. package/dist/tools/self-update.d.ts +1 -0
  280. package/dist/tools/self-update.js +85 -13
  281. package/dist/tools/workflow-bundle-dependencies.d.ts +5 -0
  282. package/dist/tools/workflow-bundle-dependencies.js +93 -0
  283. package/dist/tools/workflow-bundles.d.ts +20 -0
  284. package/dist/tools/workflow-bundles.js +173 -0
  285. package/dist/tools/workflow-candidate-counts.d.ts +8 -0
  286. package/dist/tools/workflow-candidate-counts.js +251 -0
  287. package/dist/tools/workflow-candidate-program.d.ts +11 -0
  288. package/dist/tools/workflow-candidate-program.js +78 -0
  289. package/dist/tools/workflow-candidate-source.d.ts +6 -0
  290. package/dist/tools/workflow-candidate-source.js +107 -0
  291. package/dist/tools/workflow-candidate-syntax.d.ts +15 -0
  292. package/dist/tools/workflow-candidate-syntax.js +219 -0
  293. package/dist/tools/workflow-folder-capture.d.ts +17 -0
  294. package/dist/tools/workflow-folder-capture.js +216 -0
  295. package/dist/tools/workflow-folders.d.ts +33 -0
  296. package/dist/tools/workflow-folders.js +150 -0
  297. package/dist/tools/workflow-source-effects.d.ts +10 -0
  298. package/dist/tools/workflow-source-effects.js +213 -0
  299. package/dist/workflows/analyze-chats.d.ts +15 -0
  300. package/dist/workflows/analyze-chats.declaration.json +22 -0
  301. package/dist/workflows/analyze-chats.js +250 -0
  302. package/dist/workflows/develop-prd.js +71 -3
  303. package/dist/workflows/develop-ticket.d.ts +1 -7
  304. package/dist/workflows/develop-ticket.js +47 -141
  305. package/dist/workflows/issue-labels.d.ts +3 -1
  306. package/dist/workflows/issue-labels.js +34 -0
  307. package/dist/workflows/ticket-prompts.d.ts +35 -0
  308. package/dist/workflows/ticket-prompts.js +143 -0
  309. package/package.json +25 -5
@@ -0,0 +1,41 @@
1
+ import type { MessageRecord } from "./normalize.ts";
2
+ export interface RedactionSettings {
3
+ readonly home: string | null;
4
+ readonly privateTexts: readonly string[];
5
+ }
6
+ export declare const replacements: {
7
+ readonly privateKey: "[PRIVATE_KEY]";
8
+ readonly credentialUrl: "[CREDENTIAL_URL]";
9
+ readonly homePath: "[HOME_PATH]";
10
+ readonly token: "[TOKEN]";
11
+ readonly email: "[EMAIL]";
12
+ readonly privateText: "[PRIVATE_TEXT]";
13
+ };
14
+ export declare const categories: readonly ["privateKey", "credentialUrl", "homePath", "token", "email", "privateText"];
15
+ export type Category = keyof typeof replacements;
16
+ export type RedactionCounts = Record<Category, number>;
17
+ export declare function emptyCounts(): RedactionCounts;
18
+ export declare function redactRecord(record: MessageRecord, settings: RedactionSettings): {
19
+ record: {
20
+ text: string;
21
+ blocks: Record<string, unknown>[];
22
+ sourceId: string;
23
+ role: "user" | "assistant";
24
+ timestamp: string | null;
25
+ sessionId: string | null;
26
+ schemaVersion: 1;
27
+ } | {
28
+ text: string;
29
+ blocks: Record<string, unknown>[];
30
+ sourceId: string;
31
+ role: "user" | "assistant";
32
+ timestamp: string | null;
33
+ sessionId: string | null;
34
+ schemaVersion: 2;
35
+ uuid: string | null;
36
+ isSidechain: boolean | null;
37
+ parentUuid?: string | null;
38
+ };
39
+ counts: RedactionCounts;
40
+ totalCount: number;
41
+ };
@@ -0,0 +1,161 @@
1
+ export const replacements = {
2
+ privateKey: "[PRIVATE_KEY]",
3
+ credentialUrl: "[CREDENTIAL_URL]",
4
+ homePath: "[HOME_PATH]",
5
+ token: "[TOKEN]",
6
+ email: "[EMAIL]",
7
+ privateText: "[PRIVATE_TEXT]",
8
+ };
9
+ export const categories = [
10
+ "privateKey",
11
+ "credentialUrl",
12
+ "homePath",
13
+ "token",
14
+ "email",
15
+ "privateText",
16
+ ];
17
+ export function emptyCounts() {
18
+ return {
19
+ privateKey: 0,
20
+ credentialUrl: 0,
21
+ homePath: 0,
22
+ token: 0,
23
+ email: 0,
24
+ privateText: 0,
25
+ };
26
+ }
27
+ function escaped(text) {
28
+ return text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
29
+ }
30
+ function patternSpans(text, rule) {
31
+ return [...text.matchAll(rule.pattern)].map((match) => ({
32
+ start: match.index,
33
+ end: match.index + match[0].length,
34
+ category: rule.category,
35
+ }));
36
+ }
37
+ function homeRoot(home) {
38
+ if (home === null || home === "")
39
+ return "~";
40
+ if (home === "/")
41
+ return "(?:(?=/)|~)";
42
+ return `(?:${escaped(home.replace(/\/$/, ""))}|~)`;
43
+ }
44
+ function homeSpans(text, home) {
45
+ const root = homeRoot(home);
46
+ const pattern = new RegExp(String.raw `(?<![\p{L}\p{N}_./~\\-])${root}(?=$|[\s/\x22'\x60<>,;:!?()\[\]{}])(?:/[^\s\x22'\x60<>]*)?`, "gu");
47
+ return patternSpans(text, { pattern, category: "homePath" }).map((span) => {
48
+ const quote = text[span.start - 1];
49
+ if (quote !== '"' && quote !== "'" && quote !== "`")
50
+ return span;
51
+ const end = text.indexOf(quote, span.end);
52
+ return end === -1 ? span : { ...span, end };
53
+ });
54
+ }
55
+ function spans(text, settings) {
56
+ const rules = [
57
+ {
58
+ pattern: /-----BEGIN ((?:[A-Z0-9]+ )*PRIVATE KEY)-----[\s\S]*?-----END \1-----/g,
59
+ category: "privateKey",
60
+ },
61
+ {
62
+ pattern: /\b[a-z][a-z\d+.-]*:\/\/[^\s<>"'`/?#]*@[^\s<>"'`]+/gi,
63
+ category: "credentialUrl",
64
+ },
65
+ {
66
+ pattern: /(?<![\p{L}\p{N}_])(?:gh[pousr]_|github_pat_|sk-ant-|sk-(?:proj-|svcacct-)?)[a-z\d_-]+/giu,
67
+ category: "token",
68
+ },
69
+ {
70
+ pattern: /[\w.!#$%&'*+/=?^`{|}~-]+@[\w.-]+\.[a-z]{2,}/gi,
71
+ category: "email",
72
+ },
73
+ ];
74
+ const matches = rules.flatMap((rule) => patternSpans(text, rule));
75
+ for (const match of homeSpans(text, settings.home))
76
+ matches.push(match);
77
+ for (const privateText of settings.privateTexts) {
78
+ if (privateText.trim() === "")
79
+ throw new Error("invalid-settings");
80
+ const pattern = new RegExp(`(?=(${escaped(privateText)}))`, "gi");
81
+ for (const match of text.matchAll(pattern))
82
+ matches.push({
83
+ start: match.index,
84
+ end: match.index + String(match[1]).length,
85
+ category: "privateText",
86
+ });
87
+ }
88
+ return mergeSpans(matches);
89
+ }
90
+ function mergeSpans(matches) {
91
+ const priority = categories;
92
+ const merged = [];
93
+ for (const match of matches.sort((left, right) => left.start - right.start)) {
94
+ const previous = merged.at(-1);
95
+ if (previous === undefined || previous.end <= match.start) {
96
+ merged.push({ ...match });
97
+ continue;
98
+ }
99
+ previous.end = Math.max(previous.end, match.end);
100
+ if (priority.indexOf(match.category) < priority.indexOf(previous.category))
101
+ previous.category = match.category;
102
+ }
103
+ return merged;
104
+ }
105
+ function redactText(text, context) {
106
+ const { settings, counts } = context;
107
+ let result = "";
108
+ let cursor = 0;
109
+ for (const span of spans(text, settings)) {
110
+ result += text.slice(cursor, span.start) + replacements[span.category];
111
+ cursor = span.end;
112
+ counts[span.category]++;
113
+ }
114
+ return result + text.slice(cursor);
115
+ }
116
+ function rawJsonApi(value) {
117
+ return "isRawJSON" in value && typeof value.isRawJSON === "function";
118
+ }
119
+ function rawJson(value) {
120
+ return rawJsonApi(JSON) && JSON.isRawJSON(value);
121
+ }
122
+ function nested(value, context) {
123
+ if (typeof value === "string")
124
+ return redactText(value, context);
125
+ if (rawJson(value))
126
+ return value;
127
+ if (Array.isArray(value))
128
+ return value.map((item) => nested(item, context));
129
+ if (value === null || typeof value !== "object")
130
+ return value;
131
+ const result = {};
132
+ for (const [key, item] of Object.entries(value)) {
133
+ const redactedKey = redactText(key, context);
134
+ if (Object.hasOwn(result, redactedKey))
135
+ throw new Error("member-name-collision");
136
+ Object.defineProperty(result, redactedKey, {
137
+ value: nested(item, context),
138
+ enumerable: true,
139
+ });
140
+ }
141
+ return result;
142
+ }
143
+ export function redactRecord(record, settings) {
144
+ const counts = emptyCounts();
145
+ const context = { settings, counts };
146
+ const blocks = record.blocks.map((block) => {
147
+ if (block["type"] === "tool_use")
148
+ return { ...block, input: nested(block["input"], context) };
149
+ if (block["type"] === "tool_result")
150
+ return { ...block, content: nested(block["content"], context) };
151
+ if (block["type"] === "text" && typeof block["text"] === "string")
152
+ return { ...block, text: redactText(block["text"], context) };
153
+ return block;
154
+ });
155
+ const text = redactText(record.text, context);
156
+ return {
157
+ record: { ...record, text, blocks },
158
+ counts,
159
+ totalCount: Object.values(counts).reduce((sum, count) => sum + count, 0),
160
+ };
161
+ }
@@ -0,0 +1,16 @@
1
+ import { type RevisionEntry } from "./revision.ts";
2
+ import type { OccurrenceReference } from "./structure.ts";
3
+ export interface EvidenceMappingSnapshot {
4
+ readonly importId: string;
5
+ readonly coverage: string;
6
+ readonly corpus: string;
7
+ }
8
+ export interface EvidenceReferenceMapping {
9
+ readonly previous: OccurrenceReference;
10
+ readonly current: OccurrenceReference;
11
+ }
12
+ export declare function mapEvidenceReferences(data: {
13
+ readonly previous: EvidenceMappingSnapshot;
14
+ readonly current: EvidenceMappingSnapshot;
15
+ readonly revision: readonly RevisionEntry[];
16
+ }): readonly EvidenceReferenceMapping[];
@@ -0,0 +1,153 @@
1
+ import { parseCorpus } from "./corpus-input.js";
2
+ import { parseEvidenceCoverage } from "./revision-input.js";
3
+ import { compareEvidence, pairEvidence, } from "./revision.js";
4
+ function coverageEntries(coverage) {
5
+ if ("files" in coverage)
6
+ return coverage.files;
7
+ if ("entries" in coverage)
8
+ return coverage.entries;
9
+ throw new Error("analysis-reference-map-refused");
10
+ }
11
+ function coverageCounts(text) {
12
+ const coverage = JSON.parse(text);
13
+ if (coverage === null || typeof coverage !== "object")
14
+ throw new Error("analysis-reference-map-refused");
15
+ const entries = coverageEntries(coverage);
16
+ if (!Array.isArray(entries))
17
+ throw new Error("analysis-reference-map-refused");
18
+ return entries.map((entry) => {
19
+ if (entry === null ||
20
+ typeof entry !== "object" ||
21
+ !("recordCount" in entry) ||
22
+ typeof entry.recordCount !== "number" ||
23
+ !Number.isSafeInteger(entry.recordCount) ||
24
+ entry.recordCount < 0)
25
+ throw new Error("analysis-reference-map-refused");
26
+ return entry.recordCount;
27
+ });
28
+ }
29
+ function occurrence(source, reference) {
30
+ const match = /^(sha256:[a-f\d]{64}):(0|[1-9]\d*)$/.exec(reference.sourceId);
31
+ if (match === null || match[1] !== source.digest)
32
+ throw new Error("analysis-reference-map-refused");
33
+ const offset = Number(match[2]);
34
+ if (!Number.isSafeInteger(offset) ||
35
+ (source.byteSize !== undefined && offset >= source.byteSize))
36
+ throw new Error("analysis-reference-map-refused");
37
+ return { reference, offset };
38
+ }
39
+ function readSelections(snapshot) {
40
+ if (!/^[a-f\d]{8}-[a-f\d]{4}-4[a-f\d]{3}-[89ab][a-f\d]{3}-[a-f\d]{12}$/.test(snapshot.importId))
41
+ throw new Error("analysis-reference-map-refused");
42
+ const sources = parseEvidenceCoverage(snapshot.coverage, snapshot.importId);
43
+ const records = parseCorpus(snapshot.corpus);
44
+ const counts = coverageCounts(snapshot.coverage);
45
+ if (counts.reduce((total, count) => total + count, 0) !== records.length ||
46
+ sources.some((source, index) => source.status !== "included" && counts[index] !== 0))
47
+ throw new Error("analysis-reference-map-refused");
48
+ let index = 0;
49
+ return sources.map((source, selectionIndex) => {
50
+ const count = counts[selectionIndex];
51
+ if (count === undefined)
52
+ throw new Error("analysis-reference-map-refused");
53
+ const occurrences = records
54
+ .slice(index, index + count)
55
+ .map((record, offset) => occurrence(source, {
56
+ recordIndex: index + offset,
57
+ sourceId: record.sourceId,
58
+ }));
59
+ if (occurrences.some((item, offset) => offset > 0 && item.offset <= (occurrences[offset - 1]?.offset ?? -1)))
60
+ throw new Error("analysis-reference-map-refused");
61
+ index += count;
62
+ return { ...source, occurrences };
63
+ });
64
+ }
65
+ function revisionIdentity(entry) {
66
+ return JSON.stringify([
67
+ entry.path,
68
+ entry.root,
69
+ entry.status,
70
+ entry.reason,
71
+ entry.before === null ? null : [entry.before.digest, entry.before.byteSize],
72
+ entry.after === null ? null : [entry.after.digest, entry.after.byteSize],
73
+ ]);
74
+ }
75
+ function verifyRevision(data) {
76
+ const expected = compareEvidence({
77
+ previous: data.previous,
78
+ current: data.current.map((source, index) => {
79
+ const revision = data.revision[index];
80
+ return {
81
+ ...source,
82
+ prefixDigest: revision?.status === "extended"
83
+ ? (revision.before?.digest ?? undefined)
84
+ : undefined,
85
+ };
86
+ }),
87
+ }).entries;
88
+ if (data.revision.length !== expected.length ||
89
+ expected.some((entry, index) => {
90
+ const actual = data.revision[index];
91
+ return (actual === undefined ||
92
+ revisionIdentity(entry) !== revisionIdentity(actual));
93
+ }))
94
+ throw new Error("analysis-reference-map-refused");
95
+ }
96
+ function verifyUnchangedSelection(before, after) {
97
+ if (before.byteSize !== undefined &&
98
+ after.byteSize !== undefined &&
99
+ before.byteSize !== after.byteSize)
100
+ throw new Error("analysis-reference-map-refused");
101
+ if (before.occurrences.length !== after.occurrences.length)
102
+ throw new Error("analysis-reference-map-refused");
103
+ }
104
+ function verifyExtendedSelection(before, after) {
105
+ const prefix = after.occurrences.filter((item) => item.offset < (before.byteSize ?? 0));
106
+ if (prefix.length !== before.occurrences.length ||
107
+ prefix.some((item, index) => item.offset !== before.occurrences[index]?.offset))
108
+ throw new Error("analysis-reference-map-refused");
109
+ }
110
+ function mapSelection(data) {
111
+ const { before, after, revision } = data;
112
+ if (revision?.status !== "unchanged" && revision?.status !== "extended")
113
+ return [];
114
+ if (revision.status === "unchanged")
115
+ verifyUnchangedSelection(before, after);
116
+ if (revision.status === "extended")
117
+ verifyExtendedSelection(before, after);
118
+ const indexes = new Map(after.occurrences.map((item, index) => [item.offset, index]));
119
+ return before.occurrences.flatMap((item) => {
120
+ const index = indexes.get(item.offset);
121
+ const matched = index === undefined ? undefined : after.occurrences[index];
122
+ if (matched === undefined || index === undefined)
123
+ throw new Error("analysis-reference-map-refused");
124
+ const next = after.occurrences[index + 1];
125
+ if (revision.status === "extended" &&
126
+ (before.byteSize === undefined ||
127
+ next === undefined ||
128
+ next.offset > before.byteSize))
129
+ return [];
130
+ return [{ previous: item.reference, current: matched.reference }];
131
+ });
132
+ }
133
+ export function mapEvidenceReferences(data) {
134
+ try {
135
+ const previous = readSelections(data.previous);
136
+ const current = readSelections(data.current);
137
+ verifyRevision({ previous, current, revision: data.revision });
138
+ const pairs = pairEvidence({ previous, current });
139
+ const mappings = current.flatMap((after, index) => {
140
+ const beforeIndex = pairs[index];
141
+ const before = beforeIndex === null || beforeIndex === undefined
142
+ ? undefined
143
+ : previous[beforeIndex];
144
+ return before === undefined
145
+ ? []
146
+ : mapSelection({ before, after, revision: data.revision[index] });
147
+ });
148
+ return mappings.sort((left, right) => left.previous.recordIndex - right.previous.recordIndex);
149
+ }
150
+ catch {
151
+ throw new Error("analysis-reference-map-refused");
152
+ }
153
+ }
@@ -0,0 +1,3 @@
1
+ import { type EvidenceSource } from "./revision.ts";
2
+ export declare function parseEvidenceCoverage(text: string, importId: string): readonly EvidenceSource[];
3
+ export declare function nextEvidenceRevision(text: string | undefined, importId: string): number;
@@ -0,0 +1,180 @@
1
+ import { validateCoverage, withinRoot } from "./corpus-input.js";
2
+ import { evidenceReason, revisionReasons, } from "./revision.js";
3
+ function object(value) {
4
+ return value !== null && typeof value === "object" && !Array.isArray(value);
5
+ }
6
+ function exact(value, fields) {
7
+ const { required, optional = [] } = fields;
8
+ return (required.every((key) => Object.hasOwn(value, key)) &&
9
+ Object.keys(value).every((key) => required.includes(key) || optional.includes(key)));
10
+ }
11
+ function natural(value) {
12
+ return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
13
+ }
14
+ function absolute(value) {
15
+ return (typeof value === "string" &&
16
+ value.startsWith("/") &&
17
+ !value.includes("\0") &&
18
+ value.split("/").every((part) => part !== "." && part !== ".."));
19
+ }
20
+ function digest(value) {
21
+ return (value === null ||
22
+ (typeof value === "string" && /^sha256:[a-f\d]{64}$/.test(value)));
23
+ }
24
+ function evidenceValue(value) {
25
+ return (object(value) &&
26
+ digest(value["digest"]) &&
27
+ (!Object.hasOwn(value, "byteSize") ||
28
+ (natural(value["byteSize"]) && value["byteSize"] <= 10_485_760)));
29
+ }
30
+ function source(value, roots) {
31
+ if (!evidenceValue(value) ||
32
+ !absolute(value["path"]) ||
33
+ typeof value["status"] !== "string")
34
+ throw new Error("invalid-import");
35
+ return {
36
+ path: value["path"],
37
+ root: selectedRoot(value["selection"], roots),
38
+ status: value["status"],
39
+ digest: value.digest,
40
+ ...(value.byteSize === undefined ? {} : { byteSize: value.byteSize }),
41
+ };
42
+ }
43
+ export function parseEvidenceCoverage(text, importId) {
44
+ validateCoverage(text, importId);
45
+ const value = JSON.parse(text);
46
+ if (!object(value))
47
+ throw new Error("invalid-import");
48
+ const entries = value["schemaVersion"] === 1 ? value["files"] : value["entries"];
49
+ const roots = value["schemaVersion"] === 1 ? [] : value["roots"];
50
+ if (!Array.isArray(entries) ||
51
+ !Array.isArray(roots) ||
52
+ !roots.every((root) => typeof root === "string"))
53
+ throw new Error("invalid-import");
54
+ return entries.map((entry) => source(entry, roots));
55
+ }
56
+ function revisionValue(value) {
57
+ return (value === null ||
58
+ (evidenceValue(value) &&
59
+ exact(value, { required: ["digest"], optional: ["byteSize"] })));
60
+ }
61
+ function revisionEntry(value) {
62
+ if (!object(value) ||
63
+ !exact(value, {
64
+ required: ["path", "root", "before", "after", "status", "reason"],
65
+ }))
66
+ return false;
67
+ if (!selectionKey(value))
68
+ return false;
69
+ const reason = value["reason"];
70
+ if (typeof reason !== "string" || !Object.hasOwn(revisionReasons, reason))
71
+ return false;
72
+ const expected = Object.entries(revisionReasons).find(([key]) => key === reason)?.[1];
73
+ return (value["status"] === expected &&
74
+ revisionPresence(value) &&
75
+ consistentReason(value));
76
+ }
77
+ function revisionPresence(value) {
78
+ const reason = value["reason"];
79
+ if (reason === "no-previous-entry")
80
+ return value["before"] === null && value["after"] !== null;
81
+ if (reason === "not-selected")
82
+ return value["before"] !== null && value["after"] === null;
83
+ return value["before"] !== null && value["after"] !== null;
84
+ }
85
+ function validCounts(value, entries) {
86
+ const statuses = [
87
+ "new",
88
+ "missing",
89
+ "unchanged",
90
+ "changed",
91
+ "truncated",
92
+ "extended",
93
+ ];
94
+ return (object(value) &&
95
+ exact(value, { required: statuses }) &&
96
+ statuses.every((status) => natural(value[status]) &&
97
+ value[status] ===
98
+ entries.filter((entry) => entry["status"] === status).length));
99
+ }
100
+ export function nextEvidenceRevision(text, importId) {
101
+ if (text === undefined)
102
+ return 1;
103
+ const value = JSON.parse(text);
104
+ if (!object(value) ||
105
+ !exact(value, {
106
+ required: [
107
+ "schemaVersion",
108
+ "importId",
109
+ "previousImportId",
110
+ "evidenceRevision",
111
+ "counts",
112
+ "entries",
113
+ ],
114
+ }))
115
+ throw new Error("invalid-import");
116
+ if (!revisionHeader(value, importId))
117
+ throw new Error("invalid-import");
118
+ const entries = value["entries"];
119
+ if (!Array.isArray(entries) ||
120
+ !entries.every(revisionEntry) ||
121
+ !validCounts(value["counts"], entries))
122
+ throw new Error("invalid-import");
123
+ const revision = value["evidenceRevision"];
124
+ if (!natural(revision))
125
+ throw new Error("invalid-import");
126
+ return revision + 1;
127
+ }
128
+ function selectedRoot(selection, roots) {
129
+ if (roots.length === 0 || !object(selection) || selection["kind"] !== "root")
130
+ return null;
131
+ const index = selection["index"];
132
+ if (!natural(index) || roots[index] === undefined)
133
+ throw new Error("invalid-import");
134
+ return roots[index];
135
+ }
136
+ function selectionKey(value) {
137
+ return (absolute(value["path"]) &&
138
+ (value["root"] === null ||
139
+ (absolute(value["root"]) && withinRoot(value["root"], value["path"]))));
140
+ }
141
+ function revisionHeader(value, importId) {
142
+ const revision = value["evidenceRevision"];
143
+ if (value["schemaVersion"] !== 1 ||
144
+ value["importId"] !== importId ||
145
+ !natural(revision) ||
146
+ revision === 0 ||
147
+ revision === Number.MAX_SAFE_INTEGER)
148
+ return false;
149
+ const previous = value["previousImportId"];
150
+ if (typeof previous !== "string" ||
151
+ previous === importId ||
152
+ !/^[a-f\d]{8}-[a-f\d]{4}-4[a-f\d]{3}-[89ab][a-f\d]{3}-[a-f\d]{12}$/.test(previous))
153
+ return false;
154
+ return true;
155
+ }
156
+ function consistentReason(value) {
157
+ const before = value["before"];
158
+ const after = value["after"];
159
+ if (!revisionValue(before) || !revisionValue(after))
160
+ return false;
161
+ const reason = value["reason"];
162
+ const unverified = [
163
+ "no-previous-entry",
164
+ "not-selected",
165
+ "not-included",
166
+ ].includes(String(reason));
167
+ if (!unverified && after?.digest === null)
168
+ return false;
169
+ const prefix = reason === "verified-prefix" ? before?.digest : undefined;
170
+ return (evidenceReason({
171
+ before: comparable(before, { status: "included" }),
172
+ after: comparable(after, {
173
+ status: reason === "not-included" ? "unsupported" : "included",
174
+ prefixDigest: prefix ?? undefined,
175
+ }),
176
+ }) === reason);
177
+ }
178
+ function comparable(value, state) {
179
+ return value === null ? null : { ...value, ...state };
180
+ }
@@ -0,0 +1,48 @@
1
+ export interface SelectionKey {
2
+ readonly path: string;
3
+ readonly root: string | null;
4
+ }
5
+ export interface EvidenceValue {
6
+ readonly digest: string | null;
7
+ readonly byteSize?: number | undefined;
8
+ }
9
+ export interface ComparableEvidence extends EvidenceValue {
10
+ readonly status: string;
11
+ readonly prefixDigest?: string | undefined;
12
+ }
13
+ export interface EvidenceSource extends SelectionKey, ComparableEvidence {
14
+ }
15
+ export declare const revisionReasons: {
16
+ readonly "no-previous-entry": "new";
17
+ readonly "not-selected": "missing";
18
+ readonly "not-included": "missing";
19
+ readonly "same-digest": "unchanged";
20
+ readonly "previous-digest-unknown": "changed";
21
+ readonly "previous-size-unknown": "changed";
22
+ readonly "shorter-source": "truncated";
23
+ readonly "verified-prefix": "extended";
24
+ readonly "digest-changed": "changed";
25
+ };
26
+ export type RevisionReason = keyof typeof revisionReasons;
27
+ export type RevisionStatus = (typeof revisionReasons)[RevisionReason];
28
+ export interface RevisionEntry extends SelectionKey {
29
+ readonly before: EvidenceValue | null;
30
+ readonly after: EvidenceValue | null;
31
+ readonly status: RevisionStatus;
32
+ readonly reason: RevisionReason;
33
+ }
34
+ export declare function pairEvidence(data: {
35
+ readonly previous: readonly SelectionKey[];
36
+ readonly current: readonly SelectionKey[];
37
+ }): readonly (number | null)[];
38
+ export declare function evidenceReason(data: {
39
+ readonly before: ComparableEvidence | null;
40
+ readonly after: ComparableEvidence | null;
41
+ }): RevisionReason;
42
+ export declare function compareEvidence(data: {
43
+ readonly previous: readonly EvidenceSource[];
44
+ readonly current: readonly EvidenceSource[];
45
+ }): {
46
+ counts: Record<RevisionStatus, number>;
47
+ entries: RevisionEntry[];
48
+ };