agentwrangler 0.1.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 (157) hide show
  1. package/LICENSE +191 -0
  2. package/README.md +116 -0
  3. package/dist/apply/jobs.js +429 -0
  4. package/dist/apply/open-terminal-child.mjs +98 -0
  5. package/dist/apply/open-terminal.js +221 -0
  6. package/dist/apply/settings-gen.js +35 -0
  7. package/dist/cli/agentwrangler.js +18 -0
  8. package/dist/daemon/config.js +51 -0
  9. package/dist/daemon/http.js +258 -0
  10. package/dist/daemon/index.js +372 -0
  11. package/dist/daemon/outcomes-pass.js +82 -0
  12. package/dist/daemon/readiness.js +15 -0
  13. package/dist/daemon/router.js +756 -0
  14. package/dist/daemon/static.js +146 -0
  15. package/dist/db/migrate.js +72 -0
  16. package/dist/db/migrations/001_observe.sql +196 -0
  17. package/dist/db/migrations/002_indexes.sql +6 -0
  18. package/dist/db/migrations/003_context_inventory_history.sql +20 -0
  19. package/dist/db/migrations/004_apply_jobs.sql +17 -0
  20. package/dist/db/migrations/005_tool_event_metadata.sql +17 -0
  21. package/dist/db/migrations/006_d7_query_indexes.sql +9 -0
  22. package/dist/db/migrations/007_work_item_branch_keys.sql +11 -0
  23. package/dist/db/migrations/008_thinking_tokens.sql +1 -0
  24. package/dist/db/migrations/009_user_turn_count.sql +1 -0
  25. package/dist/db/migrations/010_workspace_cwd.sql +1 -0
  26. package/dist/db/migrations/011_reports.sql +1 -0
  27. package/dist/db/migrations/012_reconcile_indexes.sql +2 -0
  28. package/dist/db/migrations/013_friction_fields.sql +5 -0
  29. package/dist/db/migrations/014_session_churn.sql +11 -0
  30. package/dist/db/migrations/015_gap_aggregates.sql +6 -0
  31. package/dist/db/open.js +30 -0
  32. package/dist/detector/benchmark-anchors.js +36 -0
  33. package/dist/detector/calibration.js +302 -0
  34. package/dist/detector/context-history-retention.js +312 -0
  35. package/dist/detector/context-probe.js +574 -0
  36. package/dist/detector/d1-source-identity.js +25 -0
  37. package/dist/detector/detectors/d10_catalog_footprint.js +146 -0
  38. package/dist/detector/detectors/d1_ctx_always_loaded.js +203 -0
  39. package/dist/detector/detectors/d2_session_long_full_context.js +119 -0
  40. package/dist/detector/detectors/d4_model_mismatch.js +258 -0
  41. package/dist/detector/detectors/d5_limit_burn_forecast.js +138 -0
  42. package/dist/detector/detectors/d6_tool_result_bloat.js +301 -0
  43. package/dist/detector/detectors/d7_loop_retry_waste.js +345 -0
  44. package/dist/detector/detectors/d8_cache_write_churn.js +201 -0
  45. package/dist/detector/detectors/d9_idle_background_session.js +101 -0
  46. package/dist/detector/engine.js +88 -0
  47. package/dist/detector/index.js +17 -0
  48. package/dist/detector/measurement.js +426 -0
  49. package/dist/detector/practice-registry.js +259 -0
  50. package/dist/detector/registry.js +32 -0
  51. package/dist/detector/savings.js +249 -0
  52. package/dist/detector/types.js +14 -0
  53. package/dist/evidence/common/approved-input.js +632 -0
  54. package/dist/evidence/common/boundary.js +84 -0
  55. package/dist/evidence/common/canonical.js +55 -0
  56. package/dist/evidence/common/redaction.js +321 -0
  57. package/dist/evidence/common/sqlite.js +25 -0
  58. package/dist/evidence/common/state.js +29 -0
  59. package/dist/evidence/cond1/cli.js +289 -0
  60. package/dist/evidence/cond1/packet.js +407 -0
  61. package/dist/evidence/cond1/prepare.js +295 -0
  62. package/dist/evidence/cond1/score.js +349 -0
  63. package/dist/evidence/cond1/types.js +1 -0
  64. package/dist/evidence/create-approval.js +365 -0
  65. package/dist/evidence/create-scratch.js +542 -0
  66. package/dist/evidence/d7/cli.js +113 -0
  67. package/dist/evidence/d7/measure.js +193 -0
  68. package/dist/evidence/d7/types.js +1 -0
  69. package/dist/evidence/discover-approval.js +492 -0
  70. package/dist/evidence/g2/adjudicate.js +20 -0
  71. package/dist/evidence/g2/cli.js +207 -0
  72. package/dist/evidence/g2/kappa.js +39 -0
  73. package/dist/evidence/g2/pipeline.js +92 -0
  74. package/dist/evidence/g2/store.js +14 -0
  75. package/dist/evidence/github/client.js +1 -0
  76. package/dist/evidence/github/gh-cli-client.js +301 -0
  77. package/dist/evidence/r3/cli.js +209 -0
  78. package/dist/evidence/r3/evaluate.js +417 -0
  79. package/dist/evidence/r3/packet.js +162 -0
  80. package/dist/evidence/r3/prepare.js +405 -0
  81. package/dist/evidence/r3/score.js +341 -0
  82. package/dist/evidence/r3/transcript.js +155 -0
  83. package/dist/evidence/r3/types.js +4 -0
  84. package/dist/hook/context-budget-hook.mjs +138 -0
  85. package/dist/hook/danger-guard-denylist.json +27 -0
  86. package/dist/hook/danger-guard-hook.mjs +167 -0
  87. package/dist/hook/install.js +0 -0
  88. package/dist/hook/limit-burn-hook.mjs +127 -0
  89. package/dist/hook/loop-guard-hook.mjs +104 -0
  90. package/dist/hook/precompact-checkpoint-hook.mjs +123 -0
  91. package/dist/ingest/churn-collector.js +122 -0
  92. package/dist/ingest/detector-hook.js +52 -0
  93. package/dist/ingest/discovery.js +207 -0
  94. package/dist/ingest/health.js +43 -0
  95. package/dist/ingest/index.js +28 -0
  96. package/dist/ingest/ingestor.js +509 -0
  97. package/dist/ingest/parser.js +344 -0
  98. package/dist/ingest/pricing.js +153 -0
  99. package/dist/ingest/reconcile.js +52 -0
  100. package/dist/ingest/tail.js +152 -0
  101. package/dist/ingest/types.js +24 -0
  102. package/dist/ingest/workspace-mapping.js +114 -0
  103. package/dist/oauth/anthropic-api-key.js +88 -0
  104. package/dist/oauth/count-tokens.js +86 -0
  105. package/dist/oauth/credentials.js +171 -0
  106. package/dist/oauth/judge-g2-client.js +154 -0
  107. package/dist/oauth/usage.js +167 -0
  108. package/dist/outcomes/branch-key.js +49 -0
  109. package/dist/outcomes/conclusions.js +45 -0
  110. package/dist/outcomes/derive.js +94 -0
  111. package/dist/outcomes/finding-extractors.js +131 -0
  112. package/dist/outcomes/findings.js +237 -0
  113. package/dist/outcomes/github/client.js +367 -0
  114. package/dist/outcomes/github/credential.js +195 -0
  115. package/dist/outcomes/github/gh-cli-client.js +340 -0
  116. package/dist/outcomes/linker.js +486 -0
  117. package/dist/outcomes/pool.js +24 -0
  118. package/dist/outcomes/sync.js +276 -0
  119. package/dist/query/api/agents-liveness.js +182 -0
  120. package/dist/query/api/burn-status.js +50 -0
  121. package/dist/query/api/context-budget.js +114 -0
  122. package/dist/query/api/context-composition.js +67 -0
  123. package/dist/query/api/cost-per-success.js +104 -0
  124. package/dist/query/api/delivery.js +92 -0
  125. package/dist/query/api/effectiveness.js +254 -0
  126. package/dist/query/api/efficiency-headroom.js +74 -0
  127. package/dist/query/api/headroom-trend.js +105 -0
  128. package/dist/query/api/hook-config.js +75 -0
  129. package/dist/query/api/hook-install.js +8 -0
  130. package/dist/query/api/hot-sessions.js +17 -0
  131. package/dist/query/api/idle-sessions.js +52 -0
  132. package/dist/query/api/index.js +40 -0
  133. package/dist/query/api/loop-guard.js +90 -0
  134. package/dist/query/api/offload-share.js +41 -0
  135. package/dist/query/api/outcomes.js +218 -0
  136. package/dist/query/api/overview.js +535 -0
  137. package/dist/query/api/rec-prompt.js +138 -0
  138. package/dist/query/api/recommendations-ledger.js +111 -0
  139. package/dist/query/api/recommendations.js +514 -0
  140. package/dist/query/api/reports.js +78 -0
  141. package/dist/query/api/self-churn.js +77 -0
  142. package/dist/query/api/self-percentiles.js +109 -0
  143. package/dist/query/api/session-drivers.js +153 -0
  144. package/dist/query/api/settings.js +85 -0
  145. package/dist/query/api/spend-flavor.js +234 -0
  146. package/dist/query/api/trends.js +155 -0
  147. package/dist/query/cap-weighted.js +119 -0
  148. package/dist/query/db-context.js +42 -0
  149. package/dist/query/envelope.js +71 -0
  150. package/dist/query/forecast.js +191 -0
  151. package/dist/query/settings-store.js +441 -0
  152. package/dist/query/spend.js +171 -0
  153. package/dist/query/trends.js +194 -0
  154. package/dist/ui/assets/index-DnRKgc21.css +1 -0
  155. package/dist/ui/assets/index-h1Q1wWq5.js +168 -0
  156. package/dist/ui/index.html +39 -0
  157. package/package.json +59 -0
@@ -0,0 +1,289 @@
1
+ import * as path from "node:path";
2
+ import { fileURLToPath, pathToFileURL } from "node:url";
3
+ import { EXTRACTOR_VERSIONS } from "../../outcomes/finding-extractors.js";
4
+ import { readGithubToken } from "../../outcomes/github/credential.js";
5
+ import { loadApprovedEvidenceInput, publishApprovedOutput, } from "../common/approved-input.js";
6
+ import { EvidenceBoundaryError } from "../common/boundary.js";
7
+ import { canonicalJson } from "../common/canonical.js";
8
+ import { EvidenceGhCliClient } from "../github/gh-cli-client.js";
9
+ import { packetCond1, parseCond1Manifest, parseCond1Prepared, readApprovedArtifactJson, } from "./packet.js";
10
+ import { prepareCond1 } from "./prepare.js";
11
+ import { COND1_RUNNER_VERSION, canonicalAnswerKeySha256, scoreCond1 } from "./score.js";
12
+ const COMMON = [
13
+ "approval-manifest",
14
+ "approval-sha256",
15
+ "scratch-preparation-manifest",
16
+ "scratch-preparation-sha256",
17
+ "scratch-db",
18
+ "approved-scratch-db-sha256",
19
+ "repo-map",
20
+ "repo-map-sha256",
21
+ "scratch-state",
22
+ "scratch-verification",
23
+ "live-db",
24
+ ];
25
+ function fail(code) {
26
+ throw new Error(code);
27
+ }
28
+ function parseArgs(argv, allowed) {
29
+ const values = new Map();
30
+ for (let index = 0; index < argv.length; index += 2) {
31
+ const flag = argv[index];
32
+ const value = argv[index + 1];
33
+ if (flag === undefined || value === undefined || !flag.startsWith("--") || value.length === 0) {
34
+ fail("cond1_cli_argument_invalid");
35
+ }
36
+ const key = flag.slice(2);
37
+ if (!allowed.includes(key) || values.has(key))
38
+ fail("cond1_cli_argument_unknown_or_duplicate");
39
+ values.set(key, value);
40
+ }
41
+ if (values.size !== allowed.length || allowed.some((key) => !values.has(key))) {
42
+ fail("cond1_cli_argument_missing");
43
+ }
44
+ return values;
45
+ }
46
+ function required(values, key) {
47
+ return values.get(key) ?? fail("cond1_cli_argument_missing");
48
+ }
49
+ function approved(values) {
50
+ return {
51
+ approvalManifestPath: required(values, "approval-manifest"),
52
+ approvalManifestSha256: required(values, "approval-sha256"),
53
+ preparationManifestPath: required(values, "scratch-preparation-manifest"),
54
+ preparationManifestSha256: required(values, "scratch-preparation-sha256"),
55
+ scratchDbPath: required(values, "scratch-db"),
56
+ scratchDbSha256: required(values, "approved-scratch-db-sha256"),
57
+ repoMapPath: required(values, "repo-map"),
58
+ repoMapSha256: required(values, "repo-map-sha256"),
59
+ scratchStatePath: required(values, "scratch-state"),
60
+ scratchVerificationPath: required(values, "scratch-verification"),
61
+ liveDbPath: required(values, "live-db"),
62
+ repositoryRoot: process.cwd(),
63
+ };
64
+ }
65
+ export function strictSealedKey(value) {
66
+ if (value === null || typeof value !== "object" || Array.isArray(value))
67
+ fail("cond1_key_invalid");
68
+ const record = value;
69
+ if (Object.keys(record).sort().join("|") !==
70
+ ["answerCanonicalSha256", "answers", "campaignId", "randomizationSeed", "version"]
71
+ .sort()
72
+ .join("|") ||
73
+ record.version !== "cond1-sealed-key-v1" ||
74
+ typeof record.campaignId !== "string" ||
75
+ !/^cond1-[0-9a-f]{32}$/u.test(record.campaignId) ||
76
+ typeof record.randomizationSeed !== "string" ||
77
+ !/^[0-9a-f]{64}$/u.test(record.randomizationSeed) ||
78
+ typeof record.answerCanonicalSha256 !== "string" ||
79
+ !/^[0-9a-f]{64}$/u.test(record.answerCanonicalSha256) ||
80
+ !Array.isArray(record.answers)) {
81
+ fail("cond1_key_shape_invalid");
82
+ }
83
+ const aliases = new Set();
84
+ const sources = new Set();
85
+ for (const answer of record.answers) {
86
+ if (answer === null || typeof answer !== "object" || Array.isArray(answer))
87
+ fail("cond1_answer_invalid");
88
+ if (Object.keys(answer)
89
+ .sort()
90
+ .join("|") !==
91
+ [
92
+ "findingAlias",
93
+ "extractor",
94
+ "extractorVersion",
95
+ "sourceFindingId",
96
+ "corpusPrKey",
97
+ "evidenceSufficient",
98
+ "projectionFailure",
99
+ ]
100
+ .sort()
101
+ .join("|")) {
102
+ fail("cond1_answer_keys_invalid");
103
+ }
104
+ const row = answer;
105
+ if (typeof row.findingAlias !== "string" ||
106
+ !/^[0-9a-f]{32}$/u.test(row.findingAlias) ||
107
+ !(row.extractor === "E1" || row.extractor === "E2" || row.extractor === "E3") ||
108
+ row.extractorVersion !== EXTRACTOR_VERSIONS[row.extractor] ||
109
+ typeof row.sourceFindingId !== "string" ||
110
+ row.sourceFindingId.length === 0 ||
111
+ typeof row.corpusPrKey !== "string" ||
112
+ row.corpusPrKey.length === 0 ||
113
+ typeof row.evidenceSufficient !== "boolean" ||
114
+ !(row.projectionFailure === null || row.projectionFailure === "REDACTION_FAILED") ||
115
+ row.evidenceSufficient === (row.projectionFailure !== null)) {
116
+ fail("cond1_answer_value_invalid");
117
+ }
118
+ const source = JSON.stringify([row.extractor, row.corpusPrKey, row.sourceFindingId]);
119
+ if (aliases.has(row.findingAlias) || sources.has(source))
120
+ fail("cond1_answer_duplicate");
121
+ aliases.add(row.findingAlias);
122
+ sources.add(source);
123
+ }
124
+ return value;
125
+ }
126
+ export function strictVerdicts(value) {
127
+ if (!Array.isArray(value))
128
+ fail("cond1_verdicts_invalid");
129
+ const aliases = new Set();
130
+ for (const verdict of value) {
131
+ if (verdict === null || typeof verdict !== "object" || Array.isArray(verdict)) {
132
+ fail("cond1_verdict_invalid");
133
+ }
134
+ if (Object.keys(verdict)
135
+ .sort()
136
+ .join("|") !==
137
+ ["findingAlias", "verdict", "adjudicatorAlias", "reasonCode"].sort().join("|")) {
138
+ fail("cond1_verdict_keys_invalid");
139
+ }
140
+ const row = verdict;
141
+ if (typeof row.findingAlias !== "string" ||
142
+ !/^[0-9a-f]{32}$/u.test(row.findingAlias) ||
143
+ !(row.verdict === "TRUE_POSITIVE" ||
144
+ row.verdict === "FALSE_POSITIVE" ||
145
+ row.verdict === "UNCERTAIN") ||
146
+ typeof row.adjudicatorAlias !== "string" ||
147
+ row.adjudicatorAlias.length === 0 ||
148
+ !(row.reasonCode === "EVIDENCE_SUPPORTS" ||
149
+ row.reasonCode === "CONTEXT_NEGATES" ||
150
+ row.reasonCode === "NOT_A_DEFERRAL" ||
151
+ row.reasonCode === "NOT_AN_ADDED_MARKER" ||
152
+ row.reasonCode === "WRONG_THREAD_STATE" ||
153
+ row.reasonCode === "INSUFFICIENT_EVIDENCE")) {
154
+ fail("cond1_verdict_value_invalid");
155
+ }
156
+ if (aliases.has(row.findingAlias))
157
+ fail("cond1_verdict_duplicate");
158
+ aliases.add(row.findingAlias);
159
+ }
160
+ return value;
161
+ }
162
+ export async function runCond1Cli(argv, dependencies = {}) {
163
+ const writeOut = dependencies.stdout ?? ((line) => process.stdout.write(`${line}\n`));
164
+ const writeErr = dependencies.stderr ?? ((line) => process.stderr.write(`${line}\n`));
165
+ try {
166
+ const [command, ...rest] = argv;
167
+ if (command === undefined)
168
+ fail("cond1_cli_command_missing");
169
+ if (command === "prepare") {
170
+ const extra = [
171
+ "manifest-out",
172
+ "prepared-out",
173
+ "extractor-commit",
174
+ "findings-module-sha256",
175
+ "as-of",
176
+ "corpus",
177
+ ];
178
+ const values = parseArgs(rest, [...COMMON, ...extra]);
179
+ if (required(values, "corpus") !== "full-merged")
180
+ fail("cond1_corpus_mode_invalid");
181
+ const identity = {
182
+ sourceCommit: required(values, "extractor-commit"),
183
+ runnerVersion: COND1_RUNNER_VERSION,
184
+ findingsModuleSha256: required(values, "findings-module-sha256"),
185
+ extractorVersions: EXTRACTOR_VERSIONS,
186
+ packetVersion: "cond1-blinded-v1",
187
+ scorerVersion: "cond1-precision-v1",
188
+ asOf: required(values, "as-of"),
189
+ };
190
+ const github = dependencies.github ??
191
+ new EvidenceGhCliClient(await readGithubToken(dependencies.tokenReader));
192
+ const result = await prepareCond1({
193
+ approvedInput: approved(values),
194
+ github,
195
+ identity,
196
+ manifestOutPath: required(values, "manifest-out"),
197
+ preparedOutPath: required(values, "prepared-out"),
198
+ });
199
+ writeOut(canonicalJson({ status: "PREPARED", ...result }));
200
+ return 0;
201
+ }
202
+ if (command === "packet") {
203
+ const extra = [
204
+ "manifest",
205
+ "manifest-sha256",
206
+ "prepared",
207
+ "prepared-sha256",
208
+ "packet-out",
209
+ "key-out",
210
+ ];
211
+ const values = parseArgs(rest, [...COMMON, ...extra]);
212
+ const loaded = await loadApprovedEvidenceInput(approved(values));
213
+ const manifest = parseCond1Manifest(readApprovedArtifactJson(loaded, required(values, "manifest"), required(values, "manifest-sha256")));
214
+ const prepared = parseCond1Prepared(readApprovedArtifactJson(loaded, required(values, "prepared"), required(values, "prepared-sha256")));
215
+ const result = packetCond1({
216
+ loaded,
217
+ manifest,
218
+ prepared,
219
+ preparedFileSha256: required(values, "prepared-sha256"),
220
+ packetOutPath: required(values, "packet-out"),
221
+ keyOutPath: required(values, "key-out"),
222
+ ...(dependencies.randomBytes === undefined
223
+ ? {}
224
+ : { randomBytes: dependencies.randomBytes }),
225
+ });
226
+ writeOut(canonicalJson({ status: "PACKET_CREATED", ...result }));
227
+ return 0;
228
+ }
229
+ if (command === "score") {
230
+ const extra = [
231
+ "manifest",
232
+ "manifest-sha256",
233
+ "sealed-key",
234
+ "sealed-key-sha256",
235
+ "verdicts",
236
+ "verdicts-sha256",
237
+ "out",
238
+ ];
239
+ const values = parseArgs(rest, [...COMMON, ...extra]);
240
+ const loaded = await loadApprovedEvidenceInput(approved(values));
241
+ const manifest = parseCond1Manifest(readApprovedArtifactJson(loaded, required(values, "manifest"), required(values, "manifest-sha256")));
242
+ const key = strictSealedKey(readApprovedArtifactJson(loaded, required(values, "sealed-key"), required(values, "sealed-key-sha256")));
243
+ const verdicts = strictVerdicts(readApprovedArtifactJson(loaded, required(values, "verdicts"), required(values, "verdicts-sha256")));
244
+ if (manifest.scratchDbSha256 !== loaded.scratchDbSha256 ||
245
+ manifest.repoMapSha256 !== loaded.repoMapSha256 ||
246
+ key.campaignId !== manifest.campaignId ||
247
+ key.answerCanonicalSha256 !== manifest.answerCanonicalSha256 ||
248
+ canonicalAnswerKeySha256(key.answers) !== manifest.answerCanonicalSha256) {
249
+ fail("cond1_key_manifest_mismatch");
250
+ }
251
+ const score = scoreCond1({
252
+ manifest,
253
+ corpusManifestFileSha256: required(values, "manifest-sha256"),
254
+ answers: key.answers,
255
+ verdicts,
256
+ });
257
+ const publication = publishApprovedOutput(loaded, required(values, "out"), `${canonicalJson(score)}\n`);
258
+ writeOut(canonicalJson({
259
+ status: "SCORED",
260
+ overallStatus: score.overallStatus,
261
+ eligiblePrN: score.corpus.eligiblePrN,
262
+ emittedFindingN: {
263
+ E1: score.extractors.E1.emittedN,
264
+ E2: score.extractors.E2.emittedN,
265
+ E3: score.extractors.E3.emittedN,
266
+ },
267
+ scoreSha256: publication.sha256,
268
+ }));
269
+ return 0;
270
+ }
271
+ fail("cond1_cli_command_invalid");
272
+ }
273
+ catch (error) {
274
+ const message = error instanceof Error ? error.message : "unexpected_failure";
275
+ const failure = error instanceof EvidenceBoundaryError || /^[a-z0-9_]+$/u.test(message)
276
+ ? message
277
+ : "unexpected_failure";
278
+ writeErr(canonicalJson({ status: "REFUSED", failure }));
279
+ return 1;
280
+ }
281
+ }
282
+ const invokedPath = process.argv[1];
283
+ if (invokedPath !== undefined &&
284
+ pathToFileURL(path.resolve(invokedPath)).href ===
285
+ pathToFileURL(fileURLToPath(import.meta.url)).href) {
286
+ void runCond1Cli(process.argv.slice(2)).then((code) => {
287
+ process.exitCode = code;
288
+ });
289
+ }