@canonmsg/codex-plugin 0.18.5 → 0.18.7

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/dist/adapter.d.ts CHANGED
@@ -8,6 +8,7 @@ export type CodexEvent = {
8
8
  } | {
9
9
  type: 'message';
10
10
  text: string;
11
+ itemId?: string;
11
12
  } | {
12
13
  type: 'plan.updated';
13
14
  text: string;
package/dist/adapter.js CHANGED
@@ -99,7 +99,13 @@ export class CodexConversationAdapter {
99
99
  if (event.item?.type === 'agent_message') {
100
100
  latestMessage = normalizeMessageText(event.item.text);
101
101
  if (latestMessage) {
102
- onEvent({ type: 'message', text: latestMessage });
102
+ onEvent({
103
+ type: 'message',
104
+ text: latestMessage,
105
+ ...(typeof event.item.id === 'string' && event.item.id.trim()
106
+ ? { itemId: event.item.id.trim() }
107
+ : {}),
108
+ });
103
109
  }
104
110
  }
105
111
  else if (event.item?.type === 'command_execution') {
@@ -148,18 +148,14 @@ export class CodexAppServerAdapter {
148
148
  ],
149
149
  ...(this.model ? { model: this.model } : {}),
150
150
  ...this.sandboxPolicyPayload(_extraAddDirs),
151
- ...(options.planMode
152
- ? {
153
- collaborationMode: {
154
- mode: 'plan',
155
- settings: {
156
- ...(planModel ? { model: planModel } : {}),
157
- reasoning_effort: this.reasoningEffort ?? null,
158
- developer_instructions: null,
159
- },
160
- },
161
- }
162
- : {}),
151
+ collaborationMode: {
152
+ mode: options.planMode ? 'plan' : 'default',
153
+ settings: {
154
+ ...(planModel ? { model: planModel } : {}),
155
+ reasoning_effort: this.reasoningEffort ?? null,
156
+ developer_instructions: null,
157
+ },
158
+ },
163
159
  });
164
160
  const turn = turnStarted.turn;
165
161
  if (this.currentTurnResolve) {
@@ -338,7 +334,7 @@ export class CodexAppServerAdapter {
338
334
  this.messageTextByItem.set(itemId, next);
339
335
  this.currentFinalMessage = next.trim() ? next : this.currentFinalMessage;
340
336
  if (next.trim())
341
- this.currentOnEvent?.({ type: 'message', text: next });
337
+ this.currentOnEvent?.({ type: 'message', text: next, itemId });
342
338
  return;
343
339
  }
344
340
  if (method === 'turn/plan/updated') {
@@ -372,10 +368,15 @@ export class CodexAppServerAdapter {
372
368
  if (method === 'item/completed') {
373
369
  const item = params.item;
374
370
  if (item?.type === 'agentMessage') {
371
+ const itemId = readString(item, 'id');
375
372
  const text = readString(item, 'text');
376
373
  if (text) {
377
374
  this.currentFinalMessage = text;
378
- this.currentOnEvent?.({ type: 'message', text });
375
+ this.currentOnEvent?.({
376
+ type: 'message',
377
+ text,
378
+ ...(itemId ? { itemId } : {}),
379
+ });
379
380
  }
380
381
  }
381
382
  else if (item?.type === 'commandExecution') {
package/dist/host.js CHANGED
@@ -19,7 +19,7 @@ import { startCodexStreamInBackground } from './host-lifecycle.js';
19
19
  import { createCodexControlPoller } from './control-channel.js';
20
20
  import { runCli } from './cli-entry.js';
21
21
  import { collectMissedInboundMessages, STARTUP_RECOVERY_MAX_MESSAGES, STARTUP_RECOVERY_PAGE_SIZE, } from './startup-recovery.js';
22
- import { beginCommandBlock, claimCommandBlock, createCommandBlockTracker, } from './turn-activity.js';
22
+ import { applyTextSegmentBlock, beginCommandBlock, claimCommandBlock, createCommandBlockTracker, } from './turn-activity.js';
23
23
  const HELP = `canon-codex — run a local Codex agent host for Canon
24
24
 
25
25
  USAGE
@@ -675,6 +675,18 @@ export async function main() {
675
675
  blocks: session.turnBlocks,
676
676
  }).catch(() => { });
677
677
  }
678
+ function upsertCodexTextSegment(session, event) {
679
+ const next = applyTextSegmentBlock({
680
+ turnLiveText: session.turnLiveText,
681
+ turnBlocks: session.turnBlocks,
682
+ }, {
683
+ turnId: session.currentTurnId,
684
+ itemId: event.itemId,
685
+ text: event.text,
686
+ });
687
+ session.turnLiveText = next.turnLiveText;
688
+ session.turnBlocks = next.turnBlocks;
689
+ }
678
690
  function upsertTurnBlock(session, block) {
679
691
  const now = Date.now();
680
692
  const index = session.turnBlocks.findIndex((existing) => existing.id === block.id);
@@ -1430,7 +1442,8 @@ export async function main() {
1430
1442
  markTurnProgress(session);
1431
1443
  writeTurn(session);
1432
1444
  stopVisibleWorkSignal(session);
1433
- writeCodexStreaming(session, event.text, 'streaming');
1445
+ upsertCodexTextSegment(session, event);
1446
+ writeCodexStreaming(session, null, 'streaming');
1434
1447
  return;
1435
1448
  }
1436
1449
  if (event.type === 'plan.updated') {
@@ -1,3 +1,4 @@
1
+ import type { TurnOutputBlock } from '@canonmsg/core';
1
2
  interface RunningCommandBlock {
2
3
  command: string;
3
4
  blockId: string;
@@ -7,7 +8,17 @@ export interface CommandBlockTracker {
7
8
  sequence: number;
8
9
  running: RunningCommandBlock[];
9
10
  }
11
+ export interface TextSegmentBlockState {
12
+ turnLiveText: string;
13
+ turnBlocks: TurnOutputBlock[];
14
+ }
10
15
  export declare function createCommandBlockTracker(): CommandBlockTracker;
16
+ export declare function applyTextSegmentBlock(state: TextSegmentBlockState, input: {
17
+ turnId: string | null | undefined;
18
+ itemId?: string;
19
+ text: string;
20
+ now?: number;
21
+ }): TextSegmentBlockState;
11
22
  export declare function beginCommandBlock(tracker: CommandBlockTracker, input: {
12
23
  turnId: string | null | undefined;
13
24
  command: string;
@@ -8,6 +8,49 @@ function normalizeOptionalString(value) {
8
8
  const normalized = value?.trim();
9
9
  return normalized ? normalized : undefined;
10
10
  }
11
+ function textBlockId(turnId, itemId) {
12
+ return `message:${turnId ?? 'turn'}:${normalizeOptionalString(itemId) ?? 'latest'}`;
13
+ }
14
+ function buildLiveText(blocks) {
15
+ return blocks
16
+ .filter((block) => block.kind === 'text' && block.text?.trim())
17
+ .sort((left, right) => {
18
+ if (left.sequence !== right.sequence)
19
+ return left.sequence - right.sequence;
20
+ return left.id.localeCompare(right.id);
21
+ })
22
+ .map((block) => block.text)
23
+ .join('\n\n');
24
+ }
25
+ export function applyTextSegmentBlock(state, input) {
26
+ const id = textBlockId(input.turnId, input.itemId);
27
+ const now = input.now ?? Date.now();
28
+ const index = state.turnBlocks.findIndex((block) => block.id === id);
29
+ const existing = index >= 0 ? state.turnBlocks[index] : null;
30
+ const next = {
31
+ ...(existing ?? {
32
+ sequence: state.turnBlocks.length + 1,
33
+ createdAt: now,
34
+ }),
35
+ id,
36
+ turnId: input.turnId ?? id,
37
+ kind: 'text',
38
+ status: existing?.status ?? 'running',
39
+ text: input.text,
40
+ updatedAt: now,
41
+ };
42
+ const turnBlocks = index >= 0
43
+ ? [
44
+ ...state.turnBlocks.slice(0, index),
45
+ next,
46
+ ...state.turnBlocks.slice(index + 1),
47
+ ]
48
+ : [...state.turnBlocks, next];
49
+ return {
50
+ turnBlocks,
51
+ turnLiveText: buildLiveText(turnBlocks) || state.turnLiveText,
52
+ };
53
+ }
11
54
  function nextCommandBlockId(tracker, turnId, itemId) {
12
55
  const stableTurnId = turnId ?? 'turn';
13
56
  if (itemId)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@canonmsg/codex-plugin",
3
- "version": "0.18.5",
3
+ "version": "0.18.7",
4
4
  "description": "Canon host integration for Codex CLI",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -29,9 +29,9 @@
29
29
  "prepack": "npm run build"
30
30
  },
31
31
  "dependencies": {
32
- "@canonmsg/agent-sdk": "^3.2.3",
32
+ "@canonmsg/agent-sdk": "^3.3.1",
33
33
  "@canonmsg/coding-agent-host": "^0.2.2",
34
- "@canonmsg/core": "^2.8.0"
34
+ "@canonmsg/core": "^2.8.1"
35
35
  },
36
36
  "engines": {
37
37
  "node": ">=18.0.0"