@tech-leads-club/harness-toolkit 0.15.2 → 0.15.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/docs/log.md CHANGED
@@ -13,6 +13,10 @@ Generated from `docs/decisions/` — do not edit by hand. Run `node tools/render
13
13
  A reserved file of the [OKF v0.1](/decisions/ad-013.md) bundle: entries grouped under ISO 8601 headings,
14
14
  newest first. For what landed in which npm release, see `CHANGELOG.md` at the repository root.
15
15
 
16
+ ## 2026-09-12
17
+
18
+ - **AD-139** — lessonsView joins ProviderPort, closing the one dispatcher that bypassed it ([/decisions/ad-139.md](/decisions/ad-139.md))
19
+
16
20
  ## 2026-09-11
17
21
 
18
22
  - **AD-137** — Gate artifacts are scoped per session, the same fix AD-122 already proved for handoff ([/decisions/ad-137.md](/decisions/ad-137.md))
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tech-leads-club/harness-toolkit",
3
- "version": "0.15.2",
3
+ "version": "0.15.3",
4
4
  "type": "module",
5
5
  "description": "Multi-provider agent steering: gates, follow-up, handoff, policy",
6
6
  "keywords": [
@@ -10,7 +10,7 @@ import {
10
10
  } from "../core/index.ts";
11
11
  import { filterCodeTargets, filterTestTargets, gitRootOf, listChangedRepoFiles } from "../platform/git.ts";
12
12
  import { runProcess } from "../platform/process.ts";
13
- import { type ProviderPort, renderClaudeLessonsView, renderCursorLessonsView } from "../providers/index.ts";
13
+ import { type ProviderPort, providers } from "../providers/index.ts";
14
14
 
15
15
  // invariant: one definition, taken from core rather than restated.
16
16
  export const OBS_CONFIG = coreFacade.observability.DEFAULT_OBS;
@@ -248,18 +248,20 @@ export function renderLessonLine(lesson: HarnessLesson): string {
248
248
  return coreFacade.lesson.renderLessonBlock(lesson);
249
249
  }
250
250
 
251
- /**
252
- * invariant: one dispatcher, imported by both session entrypoints. The durable view is written at session start and
253
- * again at session end, and a copy of this switch in each would be the AD-042 defect a second time.
254
- */
255
- export function renderProviderLessonsView(providerName: string, root: string): string | null {
256
- if (providerName === "cursor") {
257
- return renderCursorLessonsView(root);
258
- }
259
- if (providerName === "claude") {
260
- return renderClaudeLessonsView(root);
261
- }
262
- return null;
251
+ // invariant: a single dispatcher, called from both session entrypoints — the durable view is written at
252
+ // session start and again at session end, so a second copy of this logic in either one would repeat the
253
+ // AD-042 defect.
254
+
255
+ // why: a registry lookup, not a name-checking chain — adding a third adapter to `providers` gets it
256
+ // dispatched here for free, exactly as it already gets `detect`/`capabilities`/`render` for free —
257
+ // `ProviderPort` itself, not this function, is what requires `lessonsView` to exist ([/decisions/ad-139.md](/decisions/ad-139.md)).
258
+ export function renderProviderLessonsView(
259
+ providerName: string,
260
+ root: string,
261
+ registry: readonly ProviderPort[] = providers,
262
+ ): string | null {
263
+ const provider = registry.find((candidate) => candidate.name === providerName);
264
+ return provider?.lessonsView(root) ?? null;
263
265
  }
264
266
 
265
267
  /**
@@ -2,6 +2,7 @@ import type { ProviderPort } from "../provider.port.ts";
2
2
  import { claudeCapabilities } from "./claude.capabilities.ts";
3
3
  import { detectClaude } from "./claude.detect.ts";
4
4
  import { claudeToEvent } from "./claude.inbound.ts";
5
+ import { renderClaudeLessonsView } from "./claude.lessons-view.ts";
5
6
  import { claudeRender } from "./claude.outbound.ts";
6
7
  import { claudePolicyDefaults } from "./claude.policy-defaults.ts";
7
8
  import { claudeWiring, claudeWiringTargets } from "./claude.wiring.ts";
@@ -15,4 +16,5 @@ export const claudeProvider: ProviderPort = {
15
16
  render: claudeRender,
16
17
  wiring: claudeWiring,
17
18
  wiringTargets: claudeWiringTargets,
19
+ lessonsView: renderClaudeLessonsView,
18
20
  };
@@ -2,6 +2,7 @@ import type { ProviderPort } from "../provider.port.ts";
2
2
  import { cursorCapabilities } from "./cursor.capabilities.ts";
3
3
  import { detectCursor } from "./cursor.detect.ts";
4
4
  import { cursorToEvent } from "./cursor.inbound.ts";
5
+ import { renderCursorLessonsView } from "./cursor.lessons-view.ts";
5
6
  import { cursorRender } from "./cursor.outbound.ts";
6
7
  import { cursorPolicyDefaults } from "./cursor.policy-defaults.ts";
7
8
  import { cursorWiring, cursorWiringTargets } from "./cursor.wiring.ts";
@@ -15,4 +16,5 @@ export const cursorProvider: ProviderPort = {
15
16
  render: cursorRender,
16
17
  wiring: cursorWiring,
17
18
  wiringTargets: cursorWiringTargets,
19
+ lessonsView: renderCursorLessonsView,
18
20
  };
@@ -1,8 +1,6 @@
1
- export { renderClaudeLessonsView } from "./claude/claude.lessons-view.ts";
2
1
  export type { TranscriptUsage } from "./claude/claude.transcript.ts";
3
2
  export { readClaudeUsage } from "./claude/claude.transcript.ts";
4
3
  export { claudeWiring, mergeClaudeSettings } from "./claude/claude.wiring.ts";
5
- export { renderCursorLessonsView } from "./cursor/cursor.lessons-view.ts";
6
4
  export type { DegradeOptions } from "./provider.degrade.ts";
7
5
  export { degrade, truncateContext } from "./provider.degrade.ts";
8
6
  export type { ProviderPort } from "./provider.port.ts";
@@ -18,4 +18,5 @@ export type ProviderPort = {
18
18
  render(decision: Decision, event: HarnessEvent): Rendered;
19
19
  wiring(runtime: RuntimePaths): ProviderWiring;
20
20
  wiringTargets(): string[];
21
+ lessonsView(root: string): string | null;
21
22
  };