codehere 0.7.1 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (139) hide show
  1. package/README.md +22 -13
  2. package/dist/application/services/verdict-service.js +154 -0
  3. package/dist/application/use-cases/assess-cross-vendor.js +126 -0
  4. package/dist/application/use-cases/build-cross-vendor-verdict.js +118 -0
  5. package/dist/application/use-cases/export-aat.js +107 -0
  6. package/dist/application/use-cases/generate-acceptance-criteria.js +223 -0
  7. package/dist/application/use-cases/generate-final-report.js +140 -15
  8. package/dist/application/use-cases/generate-narration.js +5 -3
  9. package/dist/application/use-cases/generate-thread-title.js +5 -2
  10. package/dist/application/use-cases/narrator-prompt-template.js +1 -1
  11. package/dist/application/use-cases/plan-auto-review.js +57 -0
  12. package/dist/application/use-cases/reconcile-audit.js +100 -0
  13. package/dist/application/use-cases/rerun-tests.js +226 -0
  14. package/dist/application/use-cases/search-sessions.js +70 -0
  15. package/dist/application/use-cases/should-auto-review.js +71 -0
  16. package/dist/application/use-cases/thread-export.js +90 -0
  17. package/dist/application/use-cases/verify-claim.js +187 -5
  18. package/dist/domain/audit.js +11 -0
  19. package/dist/domain/services/codebase-detector.js +0 -6
  20. package/dist/domain/task.js +91 -0
  21. package/dist/error-handler.js +3 -115
  22. package/dist/index.js +279 -31
  23. package/dist/infrastructure/completion/bash-completion.js +7 -3
  24. package/dist/infrastructure/completion/fish-completion.js +7 -12
  25. package/dist/infrastructure/completion/zsh-completion.js +7 -12
  26. package/dist/infrastructure/config/config-manager.js +4 -3
  27. package/dist/infrastructure/config/product-context.js +1 -19
  28. package/dist/infrastructure/context/adapters/figma-source.js +37 -2
  29. package/dist/infrastructure/context/adapters/github-issue-source.js +3 -2
  30. package/dist/infrastructure/context/github-api.js +110 -0
  31. package/dist/infrastructure/context/github-device-flow.js +65 -0
  32. package/dist/infrastructure/context/oauth-store.js +5 -2
  33. package/dist/infrastructure/context/registry-bootstrap.js +0 -4
  34. package/dist/infrastructure/cost/budget-config.js +4 -3
  35. package/dist/infrastructure/cost/cost-router.js +16 -23
  36. package/dist/infrastructure/cost/spend-aggregator.js +91 -16
  37. package/dist/infrastructure/cost/team-ledger.js +355 -0
  38. package/dist/infrastructure/discovery/discovery-log.js +85 -0
  39. package/dist/infrastructure/hooks/audit-tip-signature.js +336 -0
  40. package/dist/infrastructure/hooks/claude-sdk-hook.js +139 -3
  41. package/dist/infrastructure/hooks/hook-mode.js +20 -4
  42. package/dist/infrastructure/hooks/mirror-tool-call-to-audit.js +8 -2
  43. package/dist/infrastructure/hooks/pre-prompt-scan.js +3 -3
  44. package/dist/infrastructure/observability/execution-tracer.js +1 -1
  45. package/dist/infrastructure/orchestration/agents-config-seed.js +23 -11
  46. package/dist/infrastructure/orchestration/aider-adapter.js +188 -24
  47. package/dist/infrastructure/orchestration/artifacts-extractor.js +60 -2
  48. package/dist/infrastructure/orchestration/cassette-recorder.js +1 -1
  49. package/dist/infrastructure/orchestration/claude-code-adapter.js +117 -3
  50. package/dist/infrastructure/orchestration/codex-adapter.js +52 -16
  51. package/dist/infrastructure/orchestration/conductor-adapter.js +46 -7
  52. package/dist/infrastructure/orchestration/context-handoff.js +32 -14
  53. package/dist/infrastructure/orchestration/detect-ollama.js +75 -0
  54. package/dist/infrastructure/orchestration/failover-config.js +1 -11
  55. package/dist/infrastructure/orchestration/gemini-adapter.js +92 -12
  56. package/dist/infrastructure/orchestration/generic-cli-adapter.js +134 -3
  57. package/dist/infrastructure/orchestration/graphify-context.js +14 -59
  58. package/dist/infrastructure/orchestration/memory-injector.js +4 -1
  59. package/dist/infrastructure/orchestration/mocks/mock-agent-repl.js +167 -9
  60. package/dist/infrastructure/orchestration/opencode-adapter.js +84 -14
  61. package/dist/infrastructure/orchestration/progress-aggregator.js +275 -23
  62. package/dist/infrastructure/orchestration/session-manager.js +593 -94
  63. package/dist/infrastructure/orchestration/session-persistence.js +177 -41
  64. package/dist/infrastructure/orchestration/thread-key-store.js +1 -1
  65. package/dist/infrastructure/orchestration/write-pass-store.js +0 -8
  66. package/dist/infrastructure/protocols/cloud-sync.js +2 -2
  67. package/dist/infrastructure/protocols/mcp-helpers.js +1 -1
  68. package/dist/infrastructure/protocols/mcp-server-impl.js +1498 -354
  69. package/dist/infrastructure/protocols/mcp-tools.js +401 -0
  70. package/dist/infrastructure/protocols/ui/app-script-artifacts.js +121 -0
  71. package/dist/infrastructure/protocols/ui/app-script-audit-footer.js +44 -0
  72. package/dist/infrastructure/protocols/ui/app-script-audit-verify.js +56 -0
  73. package/dist/infrastructure/protocols/ui/app-script-composer-cost.js +588 -0
  74. package/dist/infrastructure/protocols/ui/app-script-context-sources.js +168 -0
  75. package/dist/infrastructure/protocols/ui/app-script-conversation.js +67 -0
  76. package/dist/infrastructure/protocols/ui/app-script-drawer.js +115 -0
  77. package/dist/infrastructure/protocols/ui/app-script-failover.js +133 -0
  78. package/dist/infrastructure/protocols/ui/app-script-github.js +113 -0
  79. package/dist/infrastructure/protocols/ui/app-script-observer.js +104 -0
  80. package/dist/infrastructure/protocols/ui/app-script-onboarding.js +80 -0
  81. package/dist/infrastructure/protocols/ui/app-script-overlay.js +203 -0
  82. package/dist/infrastructure/protocols/ui/app-script-recovery.js +136 -0
  83. package/dist/infrastructure/protocols/ui/app-script-render.js +166 -0
  84. package/dist/infrastructure/protocols/ui/app-script-share.js +78 -0
  85. package/dist/infrastructure/protocols/ui/app-script-sidebar.js +194 -0
  86. package/dist/infrastructure/protocols/ui/app-script-tour.js +78 -0
  87. package/dist/infrastructure/protocols/ui/app-script-wpass.js +312 -0
  88. package/dist/infrastructure/protocols/ui/app-script.js +2998 -0
  89. package/dist/infrastructure/protocols/ui/font-faces.js +7 -0
  90. package/dist/infrastructure/protocols/ui/styles.js +2147 -0
  91. package/dist/infrastructure/protocols/ui/tokens.js +96 -0
  92. package/dist/infrastructure/protocols/ui-page-v2.js +116 -4126
  93. package/dist/infrastructure/protocols/verify-page.js +884 -148
  94. package/dist/infrastructure/security/fix-code.js +144 -0
  95. package/dist/infrastructure/security/fix-secret.js +89 -0
  96. package/dist/infrastructure/security/permissions-config.js +3 -2
  97. package/dist/infrastructure/security/scan-types.js +10 -0
  98. package/dist/infrastructure/security/ship-scan.js +195 -0
  99. package/dist/infrastructure/security/trust-scorer.js +70 -3
  100. package/dist/infrastructure/security/vibe-checks.js +99 -0
  101. package/dist/infrastructure/storage/atomic-write.js +86 -0
  102. package/dist/infrastructure/storage/project-thread-mirror.js +151 -4
  103. package/dist/infrastructure/storage/project-thread-reader.js +262 -25
  104. package/dist/infrastructure/storage/project-thread-title-backfill.js +1 -1
  105. package/dist/monitoring.js +2 -2
  106. package/dist/presentation/cli/commands/audit-command.js +79 -4
  107. package/dist/presentation/cli/commands/budget-command.js +2 -2
  108. package/dist/presentation/cli/commands/check-command.js +96 -0
  109. package/dist/presentation/cli/commands/context-source-command.js +20 -1
  110. package/dist/presentation/cli/commands/help-command.js +5 -5
  111. package/dist/presentation/cli/commands/hook-command.js +5 -5
  112. package/dist/presentation/cli/commands/init-command.js +89 -66
  113. package/dist/presentation/cli/commands/memory-command.js +28 -28
  114. package/dist/presentation/cli/commands/permission-command.js +1 -12
  115. package/dist/presentation/cli/commands/protocols-builder.js +2 -2
  116. package/dist/presentation/cli/commands/protocols-command.js +4 -4
  117. package/dist/presentation/cli/commands/repo-map-builder.js +1 -1
  118. package/dist/presentation/cli/commands/report-command.js +48 -32
  119. package/dist/presentation/cli/commands/scan-command.js +52 -0
  120. package/dist/presentation/cli/commands/scan-tool-command.js +24 -8
  121. package/dist/presentation/cli/commands/search-command.js +51 -0
  122. package/dist/presentation/cli/commands/setup-command.js +31 -8
  123. package/dist/presentation/cli/commands/status-command.js +39 -86
  124. package/dist/presentation/cli/commands/team-command.js +256 -0
  125. package/dist/presentation/cli/commands/thread-command.js +87 -5
  126. package/dist/presentation/cli/commands/trust-command.js +53 -31
  127. package/dist/presentation/cli/commands/verify-command.js +74 -9
  128. package/dist/presentation/cli/error-display.js +0 -8
  129. package/dist/presentation/cli/repl.js +15 -7
  130. package/dist/presentation/cli/task-deliverable.js +36 -10
  131. package/dist/testing/replay-adapter.js +0 -19
  132. package/dist/ui.js +51 -239
  133. package/dist/utils/version.js +0 -6
  134. package/package.json +30 -10
  135. package/dist/domain/entities/task.js +0 -61
  136. package/dist/infrastructure/protocols/ui-page.js +0 -2377
  137. package/dist/infrastructure/security/input-validator.js +0 -152
  138. package/dist/infrastructure/storage/embeddings-path.js +0 -37
  139. package/dist/infrastructure/storage/task-repository.js +0 -206
@@ -12,6 +12,9 @@
12
12
  * - Report says "all tests green" but artifacts.tests.failed > 0 → MISMATCH
13
13
  * - Report says "no files changed" but artifacts.files has entries → MISMATCH
14
14
  * - Report says "5 files modified" but artifacts.files.length === 3 → MISMATCH
15
+ * - Report says "Added subtract() to calc.js" and calc.js IS in the recorded
16
+ * changes → VERIFIED (named-file claim, the dominant real-run shape)
17
+ * - Report names a changed file the recorded changes don't include → WARN
15
18
  *
16
19
  * NOT a substitute for human review · this is a tripwire for the easy lies.
17
20
  * The verifier is intentionally conservative: only flag claims it can
@@ -43,13 +46,104 @@ export function verifyClaim(input) {
43
46
  const findings = [
44
47
  ...verifyTestsClaim(input.summary, input.artifacts),
45
48
  ...verifyFilesClaim(input.summary, input.artifacts),
49
+ ...verifyNamedFileClaims(input.summary, input.artifacts),
46
50
  ];
51
+ // Tier 1.1 · codehere RE-RAN the suite (observed) and it did NOT pass. This is
52
+ // a WARN, NOT a hard `broken` — a re-run can fail for reasons the agent's run
53
+ // didn't have (a monorepo where the root `npm test` is the wrong suite, a test
54
+ // needing a server/DB, a flaky test). A verifier that fails honest work is worse
55
+ // than no verifier. We ADD the env-caveat warn but do NOT touch any `fail` the
56
+ // scrape-based verifyTestsClaim already produced — a prose-vs-own-stdout
57
+ // self-contradiction stays `broken` (a real lie), the re-run failure is a
58
+ // separate, softer signal (self-audit 2026-06-09, fixing the over-correction
59
+ // that had laundered every re-run failure — including caught lies — to warn).
60
+ const obs = input.artifacts?.tests;
61
+ if (obs?.observed &&
62
+ ((obs.exitCode != null && obs.exitCode !== 0) || (obs.failed ?? 0) > 0) &&
63
+ !findings.some((f) => f.kind === 'tests' && f.severity === 'fail')) {
64
+ findings.push({
65
+ severity: 'warn',
66
+ kind: 'tests',
67
+ claim: 'the agent reported its run as done',
68
+ reality: `codehere re-ran ${obs.command || 'the test suite'} · exit ${obs.exitCode ?? '?'}, ${obs.failed ?? 0} failing`,
69
+ message: "codehere re-ran the suite and it did NOT pass — but a re-run can differ from the agent's environment (a monorepo's root suite, a test needing a server/DB). Worth a look, not a confirmed failure.",
70
+ });
71
+ }
47
72
  const hasFail = findings.some((f) => f.severity === 'fail');
48
73
  const hasNon = findings.length > 0;
49
- const status = hasFail ? 'broken' : hasNon ? 'partial' : 'verified';
50
- const summary = buildVerdictSummary(status, findings);
74
+ // user-#1 dogfood 2026-06-07 (session 4b6bc481): an aider run that did
75
+ // NOTHING produced a Final Report that was just the startup banner. The
76
+ // banner makes no test/file claim, so the verifier found zero findings and
77
+ // returned 'verified' — laundering a no-op into "claims match reality". When
78
+ // there are no findings AND the report made no checkable claim at all, there
79
+ // is nothing to verify; say so honestly instead of vacuously passing.
80
+ const status = hasFail
81
+ ? 'broken'
82
+ : hasNon
83
+ ? 'partial'
84
+ : hasCheckableClaim(input.summary, input.artifacts)
85
+ ? 'verified'
86
+ : 'nothing-to-verify';
87
+ // Was the green earned purely by codehere's own re-run (no agent prose claim)?
88
+ // If so, say that honestly instead of "Claims match reality" (there was no claim).
89
+ const observedOnly = status === 'verified' && findings.length === 0 && !proseMakesCheckableClaim(input.summary, input.artifacts);
90
+ const summary = buildVerdictSummary(status, findings, observedOnly);
51
91
  return { status, findings, summary };
52
92
  }
93
+ /**
94
+ * True when the report makes at least one assertion the verifier can check
95
+ * against structured reality (a test claim or a file claim). If nothing is
96
+ * checkable, a green "verified" verdict would be vacuous — see status
97
+ * 'nothing-to-verify'.
98
+ */
99
+ function hasCheckableClaim(summary, artifacts) {
100
+ // Tier 1.1 · a clean OBSERVED re-run is itself a fact codehere confirmed, so it
101
+ // earns 'verified' even if the prose phrased no claim (the green ✓ here means
102
+ // "codehere ran the suite and it passed" — observed, not the agent's word).
103
+ const ot = artifacts?.tests;
104
+ if (ot?.observed && (ot.exitCode == null || ot.exitCode === 0) && (ot.failed ?? 0) === 0)
105
+ return true;
106
+ return proseMakesCheckableClaim(summary, artifacts);
107
+ }
108
+ /**
109
+ * True when the REPORT PROSE itself asserts something checkable — a count, a
110
+ * named file that matches reality, or an "all green"/"no files changed"
111
+ * qualifier — independent of any observed re-run. Lets the verdict tell apart a
112
+ * green the AGENT earned with a real claim from one codehere produced purely by
113
+ * re-running the suite itself (so the summary doesn't say "Claims match reality"
114
+ * when there was no claim — R5 refuter, 2026-06-09).
115
+ */
116
+ function proseMakesCheckableClaim(summary, artifacts) {
117
+ const lower = summary.toLowerCase();
118
+ if (matchTestCountClaim(summary) !== null)
119
+ return true;
120
+ if (matchFilesCountClaim(summary) !== null)
121
+ return true;
122
+ // Named-file claims ("Added subtract() to calc.js") count as checkable when
123
+ // the named file appears in the recorded file changes — the dominant shape
124
+ // of a REAL run's report (2026-06-07 v1 walk, session ab9cdcc9: a perfect
125
+ // run earned only "nothing to verify" because it phrased no numbers).
126
+ // A named file that does NOT match artifacts produced a warn finding in
127
+ // verifyNamedFileClaims, so status is 'partial' before this is consulted.
128
+ if (extractNamedFileClaims(summary).some((p) => fileMatchesArtifacts(p, artifacts)))
129
+ return true;
130
+ // Universal "all tests pass / green / no failures" qualifiers.
131
+ if (/\b(?:all|every|each)\s+tests?\s+(?:pass(?:ed|ing)?|green|succeed(?:ed)?)\b/i.test(lower) ||
132
+ /\btests?\s+all\s+(?:pass(?:ed|ing)?|green)\b/i.test(lower) ||
133
+ /\ball\s+(?:tests?\s+)?(?:green|passing)\b/i.test(lower) ||
134
+ /\bno\s+(?:test\s+)?(?:failures|regressions?)\b/i.test(lower))
135
+ return true;
136
+ // "no files changed / read-only / nothing written" claims. Deliberate: a
137
+ // no-op run that SAYS "no files were changed" gets 'verified' (the claim is
138
+ // true and checked against reality), not 'nothing-to-verify'. The vacuous
139
+ // green this function kills is the report that claims NOTHING (e.g. a bare
140
+ // startup banner) — an honest no-op claim is exactly what verification is for.
141
+ if (/\bno\s+files?\s+(were\s+)?(changed|modified|touched|written|created)\b/i.test(summary) ||
142
+ /\bsession\s+was\s+read-only\b/i.test(summary) ||
143
+ /\bnothing\s+(was\s+)?(written|changed|modified)\b/i.test(summary))
144
+ return true;
145
+ return false;
146
+ }
53
147
  /* ──────────────────────────────────────────────────────────────────────── */
54
148
  /* Tests claim verification */
55
149
  /* ──────────────────────────────────────────────────────────────────────── */
@@ -61,7 +155,14 @@ export function verifyClaim(input) {
61
155
  export function verifyTestsClaim(summary, artifacts) {
62
156
  const out = [];
63
157
  const lower = summary.toLowerCase();
64
- const tests = artifacts?.tests;
158
+ // Check the prose against the AGENT'S OWN scraped numbers. When codehere
159
+ // re-ran (observed), `artifacts.tests` holds the re-run result and the original
160
+ // scrape is preserved in `.claimed` — use the scrape here so a prose-vs-own-run
161
+ // self-contradiction ("all pass" while its own stdout showed failures) is still
162
+ // caught as a real lie, separate from a re-run that fails on an env difference
163
+ // (handled as a warn in verifyClaim). Self-audit 2026-06-09.
164
+ const scrape = artifacts?.tests?.claimed;
165
+ const tests = scrape ? { passed: scrape.passed, failed: scrape.failed } : artifacts?.tests;
65
166
  // Extract numeric "X tests passed" / "X passed" / "X of Y" patterns.
66
167
  // We deliberately keep the regex tight to avoid false positives on prose
67
168
  // like "this is the 5th attempt".
@@ -242,6 +343,69 @@ export function verifyFilesClaim(summary, artifacts) {
242
343
  }
243
344
  return out;
244
345
  }
346
+ /* ──────────────────────────────────────────────────────────────────────── */
347
+ /* Named-file claims · "Added subtract() to calc.js" */
348
+ /* ──────────────────────────────────────────────────────────────────────── */
349
+ // Library/runtime names that look like files but never are ("migrated to
350
+ // Next.js", "Node.js 20"). Skipped to keep the tripwire conservative.
351
+ const NON_FILE_NAMES = /^(node|next|vue|react|express|d3|three|angular|nuxt|deno|bun|ember|backbone)\.js$/i;
352
+ /**
353
+ * Extract file paths the report claims to have CHANGED — an edit verb followed
354
+ * (within the same sentence) by a path-shaped token. Deliberately verb-gated:
355
+ * "read calc.js" or a bare mention is NOT a change claim.
356
+ */
357
+ export function extractNamedFileClaims(summary) {
358
+ const out = new Set();
359
+ const re = /\b(?:added|created|wrote|modified|updated|changed|edited|fixed|patched|refactored|renamed|implemented|extended)\b[^.!?\n]{0,80}?`?([\w][\w./-]*\.[A-Za-z0-9]{1,8})(?::\d+)?`?/gi;
360
+ let m;
361
+ while ((m = re.exec(summary)) !== null) {
362
+ const path = m[1];
363
+ if (NON_FILE_NAMES.test(path))
364
+ continue;
365
+ out.add(path);
366
+ }
367
+ return [...out];
368
+ }
369
+ /** True when a claimed path matches a recorded file change (exact, suffix, or basename). */
370
+ function fileMatchesArtifacts(claimPath, artifacts) {
371
+ if (!artifacts?.files?.length)
372
+ return false;
373
+ // LOW #26 (atomic audit) · the bare-basename fallback only applies when the
374
+ // CLAIM is a bare basename. A directory-qualified claim ('src/a/calc.js')
375
+ // must not green-match a same-named file elsewhere ('lib/b/calc.js').
376
+ const claimIsBare = !claimPath.includes('/');
377
+ return artifacts.files.some((f) => {
378
+ const p = f.path ?? '';
379
+ if (p === claimPath || p.endsWith('/' + claimPath) || claimPath.endsWith('/' + p))
380
+ return true;
381
+ return claimIsBare && (p.split('/').pop() ?? p) === claimPath;
382
+ });
383
+ }
384
+ /**
385
+ * Tripwire side of named-file claims: the report says it changed a specific
386
+ * file but the recorded changes don't include it. Warn, not fail — the token
387
+ * might be a tool/library mention the verb regex over-read; the count/no-files
388
+ * checks above own the hard contradictions.
389
+ */
390
+ export function verifyNamedFileClaims(summary, artifacts) {
391
+ if (artifacts?.files === undefined)
392
+ return []; // can't check (e.g. non-git cwd) — stays unverifiable
393
+ const out = [];
394
+ for (const path of extractNamedFileClaims(summary)) {
395
+ if (!fileMatchesArtifacts(path, artifacts)) {
396
+ out.push({
397
+ severity: 'warn',
398
+ kind: 'files',
399
+ claim: `changed ${path}`,
400
+ reality: artifacts.files.length === 0
401
+ ? 'no file changes recorded'
402
+ : `recorded changes: ${artifacts.files.map((f) => f.path).join(', ')}`,
403
+ message: `Final Report says it changed ${path} but the recorded file changes don't include it.`,
404
+ });
405
+ }
406
+ }
407
+ return out;
408
+ }
245
409
  function matchFilesCountClaim(summary) {
246
410
  // "X files changed" / "X files modified" / "X files were touched"
247
411
  const m1 = summary.match(/\b(\d+)\s+files?\s+(were\s+)?(?:changed|modified|touched|written|created|added|updated)\b/i);
@@ -253,14 +417,32 @@ function matchFilesCountClaim(summary) {
253
417
  return { quote: m2[0], value: parseInt(m2[1], 10) };
254
418
  return null;
255
419
  }
420
+ /**
421
+ * The "verified requires git" SURFACE invariant, single-sourced (R11 / M2).
422
+ * A rendered verifier panel must never show 'verified' while its git-tracked
423
+ * flag is off: without git-tracked artifacts the file-claims are unverifiable
424
+ * (see verifyNamedFileClaims's undefined-files early-return above), so a green
425
+ * "verified" there would be an overclaim. The /verify dogfood page (H1 in
426
+ * verify-page.ts) interpolates THIS function's compiled source into its client
427
+ * script and executes it — it no longer re-encodes the rule, so the rule can't
428
+ * drift between the engine and the harness. Keep it self-contained (no captured
429
+ * scope, no imports) — its .toString() must run standalone in a browser.
430
+ */
431
+ export function violatesGitInvariant(verdict, gitTracked) {
432
+ return verdict === 'verified' && !gitTracked;
433
+ }
256
434
  /* ──────────────────────────────────────────────────────────────────────── */
257
435
  /* Verdict summary */
258
436
  /* ──────────────────────────────────────────────────────────────────────── */
259
- function buildVerdictSummary(status, findings) {
437
+ function buildVerdictSummary(status, findings, observedOnly = false) {
260
438
  if (status === 'verified')
261
- return 'Claims match the recorded reality. No gaps detected.';
439
+ return observedOnly
440
+ ? "codehere re-ran the test suite and it passed — observed by codehere, not just the agent's word."
441
+ : 'Claims match the recorded reality. No gaps detected.';
262
442
  if (status === 'no-report')
263
443
  return 'No Final Report to verify.';
444
+ if (status === 'nothing-to-verify')
445
+ return "The report makes no checkable claim, so there's nothing to verify against the recorded reality.";
264
446
  const failCount = findings.filter((f) => f.severity === 'fail').length;
265
447
  const warnCount = findings.filter((f) => f.severity === 'warn').length;
266
448
  if (failCount > 0 && warnCount > 0) {
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Domain types for the tamper-evident-aspiring audit chain.
3
+ *
4
+ * These are pure data shapes — no I/O, no clock, no dependencies. They live in
5
+ * `domain/` (not `infrastructure/hooks/`) so the dependency rule points inward:
6
+ * the hook, the daemon, and the use-cases all import these DOWN from domain,
7
+ * rather than reaching up into a hook file for the core vocabulary.
8
+ * Moved here 2026-06-09 (spec R14 / ARCHITECTURE.md M1).
9
+ */
10
+ export {};
11
+ //# sourceMappingURL=audit.js.map
@@ -82,10 +82,4 @@ function findPackageRoot(startPath) {
82
82
  }
83
83
  return null;
84
84
  }
85
- /**
86
- * Get codebase info for a given file path
87
- */
88
- export function getCodebaseForFile(filepath) {
89
- return findCodebaseRoot(dirname(filepath));
90
- }
91
85
  //# sourceMappingURL=codebase-detector.js.map
@@ -0,0 +1,91 @@
1
+ /**
2
+ * Domain types for a task's observable shape — status, progress steps, and the
3
+ * end-of-task artifacts. Pure data: no I/O, no behavior, no dependencies. These
4
+ * live in `domain/` so application + infrastructure import them DOWN, rather than
5
+ * reaching up into an adapter file for the core vocabulary.
6
+ * Moved here 2026-06-09 (spec R14 / ARCHITECTURE.md M1) from
7
+ * infrastructure/orchestration/agent-adapter.ts. The `TaskSession` runtime handle
8
+ * (which has behavior: subscribe/kill/appendMessage) and the `AgentAdapter` port
9
+ * stay with the adapters; only the pure data shapes move here.
10
+ */
11
+ /**
12
+ * R13/M3 — THE one owned transition for `artifacts.tests`. Before this, the
13
+ * exit-path re-run mutated the artifact inline in the session manager: the
14
+ * exit-code-authoritative merge, the claim-preservation rule, and the
15
+ * silent-blank-when-unobservable gap all lived in untyped infra code. This is
16
+ * now the only writer of the post-exit tests artifact.
17
+ *
18
+ * Mutates `artifacts` IN PLACE by design: the live TaskSession exposes
19
+ * `artifacts` as a readonly getter over one shared object that the API layer
20
+ * re-reads each poll — replacing the reference would detach the live verdict.
21
+ *
22
+ * Rules (verbatim from the prior inline code, now pinned by unit tests):
23
+ * - exit code is authoritative: a non-zero exit with no parseable count still
24
+ * forces failed >= 1, so a "tests pass" claim that didn't pass gets caught;
25
+ * - the agent's ORIGINAL scrape is preserved as `claimed` so the verifier can
26
+ * still catch a prose-vs-own-stdout self-contradiction;
27
+ * - couldn't run → the explicit reason lands in `testsUnobserved` instead of
28
+ * leaving the artifact silently blank (the R5 leftover).
29
+ */
30
+ export function applyTestObservation(artifacts, observation) {
31
+ if (!observation.ran) {
32
+ artifacts.testsUnobserved = observation.skippedReason ?? 'could not re-run the tests';
33
+ return 'unobserved';
34
+ }
35
+ const claimed = artifacts.tests;
36
+ let failed = observation.failed ?? 0;
37
+ if (observation.exitCode !== 0 && failed === 0)
38
+ failed = 1;
39
+ // LOW #28 (atomic audit) · exit 0 with no parseable count reuses the
40
+ // AGENT'S claimed number. The exit code is ground truth (the suite ran and
41
+ // passed) but the COUNT is not — say which is which (countSource) so the
42
+ // surface can label "re-run ✓ · count as reported" instead of implying the
43
+ // number itself was observed.
44
+ const countParsed = observation.passed !== undefined;
45
+ const passed = observation.passed ?? (observation.exitCode === 0 ? (claimed?.passed ?? 0) : 0);
46
+ artifacts.tests = {
47
+ passed,
48
+ failed,
49
+ observed: true,
50
+ ...(countParsed ? {} : { countSource: 'claimed' }),
51
+ ...(claimed ? { claimed: { passed: claimed.passed, failed: claimed.failed } } : {}),
52
+ ...(observation.command ? { command: observation.command } : {}),
53
+ ...(observation.exitCode !== undefined ? { exitCode: observation.exitCode } : {}),
54
+ ...(observation.durationMs !== undefined ? { durationMs: observation.durationMs } : {}),
55
+ };
56
+ delete artifacts.testsUnobserved; // an observed result supersedes any earlier couldn't-observe
57
+ return 'observed';
58
+ }
59
+ /** Derive the typed completeness view from a session's recorded parts. */
60
+ export function describeCompleted(input) {
61
+ const a = input.artifacts;
62
+ return {
63
+ sessionId: input.sessionId,
64
+ agent: input.agent,
65
+ status: input.status,
66
+ completedAt: input.completedAt,
67
+ durationMs: input.durationMs,
68
+ steps: input.steps ?? [],
69
+ files: a?.files
70
+ ? { present: a.files }
71
+ : {
72
+ absent: a?.noGitTracking
73
+ ? "ran in a non-git folder — codehere can't see what changed"
74
+ : 'no file changes recorded',
75
+ },
76
+ tests: a?.tests
77
+ ? { present: a.tests }
78
+ : { absent: a?.testsUnobserved ?? 'not test-relevant — no claim made, no test files touched' },
79
+ report: input.finalReport?.summary
80
+ ? { present: { summary: input.finalReport.summary } }
81
+ : { absent: input.failedReport ? 'report generation failed' : 'no written report' },
82
+ audit: input.auditRecon
83
+ ? { present: input.auditRecon }
84
+ : {
85
+ // Precise: reconciliation RUNS in the daemon at completion but is
86
+ // held in memory, not persisted — so a later reader can't see it.
87
+ absent: 'reconciliation not visible here — it runs in the daemon that observed the exit and is not persisted',
88
+ },
89
+ };
90
+ }
91
+ //# sourceMappingURL=task.js.map
@@ -1,6 +1,5 @@
1
1
  /**
2
- * Enterprise-Grade Error Handling & Recovery System
3
- * Ensures 24/7 operation with automatic recovery
2
+ * Error classification + circuit breaker for API calls.
4
3
  */
5
4
  export var ErrorType;
6
5
  (function (ErrorType) {
@@ -73,104 +72,17 @@ export function classifyError(error) {
73
72
  // Default to retryable
74
73
  return ErrorType.RETRYABLE;
75
74
  }
76
- /**
77
- * Check if error is retryable
78
- * Rate limit errors (429) should NOT be retried - they indicate quota exceeded
79
- */
80
- export function isRetryable(error) {
81
- // Check for 429 status code directly - don't retry monthly quota limits
82
- if (error && typeof error === 'object') {
83
- const err = error;
84
- // Cohere SDK error structure
85
- if (err.statusCode === 429 || err.status === 429) {
86
- return false; // Monthly quota exceeded - retrying won't help
87
- }
88
- // Check error name/class (Cohere SDK uses TooManyRequestsError)
89
- const errorName = err.constructor?.name || err.name || '';
90
- if (errorName.includes('TooManyRequests') || errorName === 'TooManyRequestsError') {
91
- return false;
92
- }
93
- // Check error message for trial key limit message
94
- const errorMsg = err.message || String(err);
95
- if (errorMsg.includes('Trial key') && errorMsg.includes('1000 API calls')) {
96
- return false; // Monthly quota exceeded
97
- }
98
- }
99
- const errorType = classifyError(error);
100
- // Don't retry rate limit errors - they indicate quota/limit exceeded
101
- if (errorType === ErrorType.RATE_LIMIT) {
102
- return false;
103
- }
104
- return [ErrorType.RETRYABLE, ErrorType.NETWORK, ErrorType.API_ERROR].includes(errorType);
105
- }
106
- /**
107
- * Calculate exponential backoff delay
108
- */
109
- export function calculateBackoff(attempt, baseDelay = 1000, maxDelay = 60000) {
110
- const delay = Math.min(baseDelay * Math.pow(2, attempt), maxDelay);
111
- // Add jitter to prevent thundering herd
112
- const jitter = Math.random() * 0.3 * delay;
113
- return Math.floor(delay + jitter);
114
- }
115
- /**
116
- * Retry with exponential backoff
117
- */
118
- export async function retryWithBackoff(operation, options = {}) {
119
- const { maxRetries = 5, baseDelay = 1000, maxDelay = 60000, operationName = 'operation', onRetry } = options;
120
- let lastError;
121
- for (let attempt = 0; attempt <= maxRetries; attempt++) {
122
- try {
123
- return await operation();
124
- }
125
- catch (error) {
126
- lastError = error;
127
- // Don't retry on fatal errors
128
- if (!isRetryable(error)) {
129
- throw new EnterpriseError(`Fatal error in ${operationName}: ${error instanceof Error ? error.message : String(error)}`, classifyError(error), {
130
- operation: operationName,
131
- attempt,
132
- maxRetries,
133
- timestamp: new Date().toISOString(),
134
- errorType: classifyError(error),
135
- originalError: error instanceof Error ? error : new Error(String(error)),
136
- }, false);
137
- }
138
- // Last attempt, throw error
139
- if (attempt === maxRetries) {
140
- break;
141
- }
142
- // Calculate delay and wait
143
- const delay = calculateBackoff(attempt, baseDelay, maxDelay);
144
- if (onRetry) {
145
- onRetry(attempt + 1, error);
146
- }
147
- await new Promise((resolve) => setTimeout(resolve, delay));
148
- }
149
- }
150
- // All retries exhausted
151
- throw new EnterpriseError(`Operation ${operationName} failed after ${maxRetries} retries: ${lastError instanceof Error ? lastError.message : String(lastError)}`, classifyError(lastError), {
152
- operation: operationName,
153
- attempt: maxRetries,
154
- maxRetries,
155
- timestamp: new Date().toISOString(),
156
- errorType: classifyError(lastError),
157
- originalError: lastError instanceof Error ? lastError : new Error(String(lastError)),
158
- }, false);
159
- }
160
75
  /**
161
76
  * Circuit breaker pattern for API calls
162
77
  */
163
78
  export class CircuitBreaker {
164
79
  threshold;
165
- timeout;
166
80
  resetTimeout;
167
81
  failures = 0;
168
82
  lastFailureTime = 0;
169
83
  state = 'CLOSED';
170
- constructor(threshold = 5, timeout = 60000, // 1 minute
171
- resetTimeout = 30000) {
84
+ constructor(threshold = 5, resetTimeout = 30000) {
172
85
  this.threshold = threshold;
173
- this.timeout = timeout;
174
86
  this.resetTimeout = resetTimeout;
175
87
  }
176
88
  async execute(operation) {
@@ -223,29 +135,5 @@ export class CircuitBreaker {
223
135
  /**
224
136
  * Global circuit breaker for Cohere API
225
137
  */
226
- export const cohereCircuitBreaker = new CircuitBreaker(5, 60000, 30000);
227
- /**
228
- * Graceful error handler with recovery strategies
229
- */
230
- export function handleError(error, context) {
231
- const errorType = classifyError(error);
232
- const errorMessage = error instanceof Error ? error.message : String(error);
233
- const fullContext = {
234
- operation: context.operation || 'unknown',
235
- filepath: context.filepath,
236
- attempt: context.attempt,
237
- maxRetries: context.maxRetries,
238
- timestamp: new Date().toISOString(),
239
- errorType,
240
- originalError: error instanceof Error ? error : new Error(errorMessage),
241
- metadata: context.metadata,
242
- };
243
- // Log error with full context
244
- console.error('Enterprise Error:', {
245
- message: errorMessage,
246
- type: errorType,
247
- context: fullContext,
248
- });
249
- throw new EnterpriseError(errorMessage, errorType, fullContext, isRetryable(error));
250
- }
138
+ export const cohereCircuitBreaker = new CircuitBreaker(5, 30000);
251
139
  //# sourceMappingURL=error-handler.js.map