@code-yeongyu/senpi-codemode 2026.8.9 → 2026.8.11-2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -12,6 +12,56 @@
12
12
 
13
13
  ### Removed
14
14
 
15
+ ## [2026.8.11-2] - 2026-08-10
16
+
17
+ ### Breaking Changes
18
+
19
+ ### Added
20
+
21
+ ### Changed
22
+
23
+ ### Fixed
24
+
25
+ ### Removed
26
+
27
+ ## [2026.8.11] - 2026-08-10
28
+
29
+ ### Breaking Changes
30
+
31
+ ### Added
32
+
33
+ ### Changed
34
+
35
+ ### Fixed
36
+
37
+ ### Removed
38
+
39
+ ## [2026.8.10] - 2026-08-10
40
+
41
+ ### Breaking Changes
42
+
43
+ ### Added
44
+
45
+ ### Changed
46
+
47
+ ### Fixed
48
+
49
+ ### Removed
50
+
51
+ ## [2026.8.9-2] - 2026-08-09
52
+
53
+ ### Breaking Changes
54
+
55
+ ### Added
56
+
57
+ ### Changed
58
+
59
+ - Detached eval cells now emit the shared `wake_source_state` event under source `senpi-codemode` when they detach, complete, stop, or are disposed. The optional host event passthrough remains guarded, synchronous cells emit no lifecycle transition, and per-cell snapshot metadata is preserved.
60
+
61
+ ### Fixed
62
+
63
+ ### Removed
64
+
15
65
  ## [2026.8.9] - 2026-08-09
16
66
 
17
67
  ### Breaking Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@code-yeongyu/senpi-codemode",
3
- "version": "2026.8.9",
3
+ "version": "2026.8.11-2",
4
4
  "description": "Source-only senpi extension package for codemode evaluation tools",
5
5
  "type": "module",
6
6
  "main": "./src/index.ts",
@@ -30,14 +30,14 @@
30
30
  },
31
31
  "dependencies": {
32
32
  "@babel/parser": "8.0.4",
33
- "@earendil-works/pi-ai": "npm:@code-yeongyu/senpi-ai@2026.8.9",
33
+ "@earendil-works/pi-ai": "npm:@code-yeongyu/senpi-ai@2026.8.11-2",
34
34
  "typebox": "1.3.8"
35
35
  },
36
36
  "peerDependencies": {
37
- "@code-yeongyu/senpi": "2026.8.9"
37
+ "@code-yeongyu/senpi": "2026.8.11-2"
38
38
  },
39
39
  "devDependencies": {
40
- "@code-yeongyu/senpi": "2026.8.9"
40
+ "@code-yeongyu/senpi": "2026.8.11-2"
41
41
  },
42
42
  "keywords": [
43
43
  "senpi",
@@ -1,29 +1,29 @@
1
1
  /**
2
- * Resumption-channel liveness contract shared with the goal builtin.
2
+ * Wake-source liveness contract shared with the goal builtin.
3
3
  *
4
- * The goal builtin delays its hidden continuation while any live resumption
5
- * channel can still wake the session. Each emitter publishes a full per-source
4
+ * The goal builtin delays its hidden continuation while any live wake source
5
+ * can still wake the session. Each emitter publishes a full per-source
6
6
  * snapshot on every liveness transition and once on `session_start`.
7
7
  *
8
8
  * The event name is duplicated here on purpose: senpi-codemode is a separate
9
9
  * package and must not import across the packages/coding-agent boundary, so
10
10
  * the sentinel test pins this literal to the exact cross-package contract.
11
11
  */
12
- export const RESUMPTION_CHANNEL_STATE_EVENT = "resumption_channel_state";
12
+ export const WAKE_SOURCE_STATE_EVENT = "wake_source_state";
13
13
 
14
14
  /** Source key identifying detached eval cells in the per-source snapshot. */
15
- export const EVAL_DETACHED_CHANNEL_SOURCE = "eval-detached";
15
+ export const SENPI_CODEMODE_WAKE_SOURCE = "senpi-codemode";
16
16
 
17
- /** One live channel as broadcast on the resumption channel state event. */
18
- export interface ResumptionChannelEntry {
17
+ /** One detached cell as broadcast on the wake-source state event. */
18
+ export interface WakeSourceStateItem {
19
19
  readonly id: string;
20
20
  readonly description: string;
21
21
  /** Epoch milliseconds when the channel registered; lets consumers render their own elapsed labels. */
22
22
  readonly startedAtMs: number;
23
23
  }
24
24
 
25
- export interface ResumptionChannelState {
25
+ export interface WakeSourceState {
26
26
  readonly source: string;
27
27
  readonly activeCount: number;
28
- readonly channels?: readonly ResumptionChannelEntry[];
28
+ readonly items?: readonly WakeSourceStateItem[];
29
29
  }
package/src/index.ts CHANGED
@@ -7,7 +7,6 @@ import { defaultCodemodeSettings } from "./config/settings.ts";
7
7
  import { EvalNotifier } from "./extension/eval-notifier.ts";
8
8
  import { EVAL_CELLS_STATUS_KEY } from "./extension/eval-status.ts";
9
9
  import { EvalStatusTicker } from "./extension/eval-status-ticker.ts";
10
- import { RESUMPTION_CHANNEL_STATE_EVENT, type ResumptionChannelState } from "./extension/resumption-channel.ts";
11
10
  import {
12
11
  createExecuteTool,
13
12
  createRuntime,
@@ -16,6 +15,7 @@ import {
16
15
  } from "./extension/runtime-factory.ts";
17
16
  import type { CodemodeSessionManager, CreateCodemodeSessionManagerOptions } from "./extension/session-manager.ts";
18
17
  import { SessionManagerProxy } from "./extension/session-manager-proxy.ts";
18
+ import { WAKE_SOURCE_STATE_EVENT, type WakeSourceState } from "./extension/wake-source-state.ts";
19
19
  import { EvalDetachedCellManager, type EvalDetachedCellStatusEntry } from "./tool/detached-cell-manager.ts";
20
20
  import { createEvalTool } from "./tool/eval-tool.ts";
21
21
  import { renderEvalCall, renderEvalResult } from "./tool/render.ts";
@@ -39,7 +39,7 @@ export interface CodemodeExtensionAPI {
39
39
  getActiveTools(): string[];
40
40
  getAllTools(): readonly EvalSchemaToolInfo[];
41
41
  sendUserMessage(content: string, options?: { deliverAs?: "steer" | "followUp" }): void;
42
- /** Optional host event bus; a host without one turns resumption-channel emission into a harmless no-op. */
42
+ /** Optional host event bus; a host without one turns wake-source emission into a harmless no-op. */
43
43
  events?: { emit(name: string, data: unknown): void };
44
44
  }
45
45
 
@@ -82,8 +82,8 @@ export default function senpiCodemode(pi: CodemodeExtensionAPI, options: SenpiCo
82
82
  const showDetachedCells = (entries: readonly EvalDetachedCellStatusEntry[]): void => {
83
83
  statusTicker.sync(entries);
84
84
  };
85
- const emitChannelState = (state: ResumptionChannelState): void => {
86
- pi.events?.emit(RESUMPTION_CHANNEL_STATE_EVENT, state);
85
+ const emitWakeSourceState = (state: WakeSourceState): void => {
86
+ pi.events?.emit(WAKE_SOURCE_STATE_EVENT, state);
87
87
  };
88
88
  const registerEvalForRuntime = (
89
89
  runtime: SessionRuntime,
@@ -132,7 +132,7 @@ export default function senpiCodemode(pi: CodemodeExtensionAPI, options: SenpiCo
132
132
  cellManager: new EvalDetachedCellManager({
133
133
  notifier,
134
134
  onStatusChange: showDetachedCells,
135
- onChannelState: emitChannelState,
135
+ onWakeSourceState: emitWakeSourceState,
136
136
  ...(options.now === undefined ? {} : { now: options.now }),
137
137
  }),
138
138
  executionTracker: manager,
@@ -163,12 +163,12 @@ export default function senpiCodemode(pi: CodemodeExtensionAPI, options: SenpiCo
163
163
  artifactsDir: runtime.artifactsDir,
164
164
  notifier,
165
165
  onStatusChange: showDetachedCells,
166
- onChannelState: emitChannelState,
166
+ onWakeSourceState: emitWakeSourceState,
167
167
  ...(options.now === undefined ? {} : { now: options.now }),
168
168
  });
169
169
  activeCells = cellManager;
170
170
  // The goal builtin clears its per-session counts at session_start; re-publish our snapshot.
171
- cellManager.publishChannelState();
171
+ cellManager.publishWakeSourceState();
172
172
  activeRuntime = runtime;
173
173
  activeModelId = ctx.model?.id;
174
174
  registerEvalForRuntime(runtime, activeModelId, cellManager);
@@ -1,5 +1,5 @@
1
1
  import type { AgentToolResult } from "@code-yeongyu/senpi";
2
- import { EVAL_DETACHED_CHANNEL_SOURCE, type ResumptionChannelState } from "../extension/resumption-channel.ts";
2
+ import { SENPI_CODEMODE_WAKE_SOURCE, type WakeSourceState } from "../extension/wake-source-state.ts";
3
3
  import { detachedNotificationSpillPath } from "./detached-cell-notification.ts";
4
4
  import { currentDetachedResult, detachedErrorResult, snapshotDetachedCell } from "./detached-cell-snapshot.ts";
5
5
  import {
@@ -60,14 +60,14 @@ export interface EvalDetachedCellManagerOptions {
60
60
  readonly notifier?: EvalDetachedCellNotifier;
61
61
  readonly onStatusChange?: (entries: readonly EvalDetachedCellStatusEntry[]) => void;
62
62
  /** Receives a full per-source liveness snapshot on every detached-cell transition; used by the goal builtin. */
63
- readonly onChannelState?: (state: ResumptionChannelState) => void;
63
+ readonly onWakeSourceState?: (state: WakeSourceState) => void;
64
64
  readonly now?: () => number;
65
65
  }
66
66
 
67
67
  export class EvalDetachedCellManager {
68
68
  readonly #artifactsDir: string | undefined;
69
69
  readonly #onStatusChange: ((entries: readonly EvalDetachedCellStatusEntry[]) => void) | undefined;
70
- readonly #onChannelState: ((state: ResumptionChannelState) => void) | undefined;
70
+ readonly #onWakeSourceState: ((state: WakeSourceState) => void) | undefined;
71
71
  readonly #cells = new Map<string, ManagedCell>();
72
72
  readonly #detachedByLanguage = new Map<EvalLanguage, ManagedCell>();
73
73
  readonly #notificationQueue: DetachedNotificationQueue;
@@ -76,7 +76,7 @@ export class EvalDetachedCellManager {
76
76
  constructor(options: EvalDetachedCellManagerOptions = {}) {
77
77
  this.#artifactsDir = options.artifactsDir;
78
78
  this.#onStatusChange = options.onStatusChange;
79
- this.#onChannelState = options.onChannelState;
79
+ this.#onWakeSourceState = options.onWakeSourceState;
80
80
  this.#notificationQueue = new DetachedNotificationQueue(options.notifier, options.artifactsDir);
81
81
  this.#now = options.now ?? Date.now;
82
82
  }
@@ -160,6 +160,7 @@ export class EvalDetachedCellManager {
160
160
  await Promise.allSettled(
161
161
  detached.map(async (cell) => await this.stop(cell.cellId, "Session ended; detached eval cell cancelled")),
162
162
  );
163
+ if (detached.length === 0) this.#emitWakeSourceState([]);
163
164
  await this.#notificationQueue.flush();
164
165
  }
165
166
 
@@ -168,8 +169,8 @@ export class EvalDetachedCellManager {
168
169
  }
169
170
 
170
171
  /** Re-publish the current snapshot; consumers reset their per-source counts at session_start. */
171
- publishChannelState(): void {
172
- this.#emitChannelState([...this.#detachedByLanguage.values()]);
172
+ publishWakeSourceState(): void {
173
+ this.#emitWakeSourceState([...this.#detachedByLanguage.values()]);
173
174
  }
174
175
 
175
176
  #settle(
@@ -207,14 +208,14 @@ export class EvalDetachedCellManager {
207
208
  ...(cell.input.summary === undefined ? {} : { summary: cell.input.summary }),
208
209
  })),
209
210
  );
210
- this.#emitChannelState(liveCells);
211
+ this.#emitWakeSourceState(liveCells);
211
212
  }
212
213
 
213
- #emitChannelState(liveCells: readonly ManagedCell[]): void {
214
- this.#onChannelState?.({
215
- source: EVAL_DETACHED_CHANNEL_SOURCE,
214
+ #emitWakeSourceState(liveCells: readonly ManagedCell[]): void {
215
+ this.#onWakeSourceState?.({
216
+ source: SENPI_CODEMODE_WAKE_SOURCE,
216
217
  activeCount: liveCells.length,
217
- channels: liveCells.map((cell) => ({
218
+ items: liveCells.map((cell) => ({
218
219
  id: cell.cellId,
219
220
  description:
220
221
  cell.input.summary === undefined || cell.input.summary.length === 0 ? cell.cellId : cell.input.summary,