@canonmsg/codex-plugin 0.13.1 → 0.13.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/README.md +3 -1
- package/dist/adapter.d.ts +2 -0
- package/dist/adapter.js +6 -0
- package/dist/app-server-adapter.js +31 -6
- package/dist/host.js +43 -8
- package/dist/turn-activity.d.ts +21 -0
- package/dist/turn-activity.js +47 -0
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -80,11 +80,13 @@ Worktree mode is project isolation, not an operating-system sandbox. The Codex C
|
|
|
80
80
|
Useful flags:
|
|
81
81
|
|
|
82
82
|
```bash
|
|
83
|
-
canon-codex --cwd /path/to/project --model gpt-5.
|
|
83
|
+
canon-codex --cwd /path/to/project --model gpt-5.5 --full-auto
|
|
84
84
|
```
|
|
85
85
|
|
|
86
86
|
Codex also supports `--add-dir /extra/path` for additional writable directories passed through to `codex exec`. Canon does not yet render those extra directories as workspace choices.
|
|
87
87
|
|
|
88
|
+
`gpt-5.5` requires a recent local Codex CLI. Older CLIs fail early with an upgrade message; upgrade Codex or choose a model supported by your installed CLI.
|
|
89
|
+
|
|
88
90
|
Recent Codex CLI releases no longer accept `--ask-for-approval` with `codex exec`. If you previously launched Canon with `--sandbox workspace-write --ask-for-approval never`, switch to `--full-auto`.
|
|
89
91
|
|
|
90
92
|
Do not start Canon with `--sandbox danger-full-access` as an unlabeled default. Use `--dangerously-bypass-approvals-and-sandbox` only when you intentionally want Canon to advertise the owner-only Bypass policy.
|
package/dist/adapter.d.ts
CHANGED
|
@@ -17,11 +17,13 @@ export type CodexEvent = {
|
|
|
17
17
|
} | {
|
|
18
18
|
type: 'command.started';
|
|
19
19
|
command: string;
|
|
20
|
+
itemId?: string;
|
|
20
21
|
} | {
|
|
21
22
|
type: 'command.completed';
|
|
22
23
|
command: string;
|
|
23
24
|
output: string;
|
|
24
25
|
exitCode: number | null;
|
|
26
|
+
itemId?: string;
|
|
25
27
|
} | {
|
|
26
28
|
type: 'turn.completed';
|
|
27
29
|
usage?: {
|
package/dist/adapter.js
CHANGED
|
@@ -83,6 +83,9 @@ export class CodexConversationAdapter {
|
|
|
83
83
|
onEvent({
|
|
84
84
|
type: 'command.started',
|
|
85
85
|
command: String(event.item.command ?? ''),
|
|
86
|
+
...(typeof event.item.id === 'string' && event.item.id.trim()
|
|
87
|
+
? { itemId: event.item.id.trim() }
|
|
88
|
+
: {}),
|
|
86
89
|
});
|
|
87
90
|
}
|
|
88
91
|
break;
|
|
@@ -99,6 +102,9 @@ export class CodexConversationAdapter {
|
|
|
99
102
|
command: String(event.item.command ?? ''),
|
|
100
103
|
output: String(event.item.aggregated_output ?? ''),
|
|
101
104
|
exitCode: typeof event.item.exit_code === 'number' ? event.item.exit_code : null,
|
|
105
|
+
...(typeof event.item.id === 'string' && event.item.id.trim()
|
|
106
|
+
? { itemId: event.item.id.trim() }
|
|
107
|
+
: {}),
|
|
102
108
|
});
|
|
103
109
|
}
|
|
104
110
|
break;
|
|
@@ -311,10 +311,10 @@ export class CodexAppServerAdapter {
|
|
|
311
311
|
}
|
|
312
312
|
if (method === 'item/agentMessage/delta') {
|
|
313
313
|
const itemId = readString(params, 'itemId') ?? 'agent-message';
|
|
314
|
-
const delta =
|
|
314
|
+
const delta = readRawString(params, 'delta') ?? '';
|
|
315
315
|
const next = `${this.messageTextByItem.get(itemId) ?? ''}${delta}`;
|
|
316
316
|
this.messageTextByItem.set(itemId, next);
|
|
317
|
-
this.currentFinalMessage = next.trim()
|
|
317
|
+
this.currentFinalMessage = next.trim() ? next : this.currentFinalMessage;
|
|
318
318
|
if (next.trim())
|
|
319
319
|
this.currentOnEvent?.({ type: 'message', text: next });
|
|
320
320
|
return;
|
|
@@ -327,9 +327,9 @@ export class CodexAppServerAdapter {
|
|
|
327
327
|
return;
|
|
328
328
|
}
|
|
329
329
|
if (method === 'item/plan/delta') {
|
|
330
|
-
const delta =
|
|
330
|
+
const delta = readRawString(params, 'delta') ?? '';
|
|
331
331
|
this.planText = `${this.planText}${delta}`;
|
|
332
|
-
this.currentFinalMessage = this.planText.trim()
|
|
332
|
+
this.currentFinalMessage = this.planText.trim() ? this.planText : this.currentFinalMessage;
|
|
333
333
|
if (this.planText.trim())
|
|
334
334
|
this.currentOnEvent?.({ type: 'plan.updated', text: this.planText });
|
|
335
335
|
return;
|
|
@@ -337,8 +337,14 @@ export class CodexAppServerAdapter {
|
|
|
337
337
|
if (method === 'item/started') {
|
|
338
338
|
const item = params.item;
|
|
339
339
|
const summary = summarizeItem(item);
|
|
340
|
-
if (summary)
|
|
341
|
-
|
|
340
|
+
if (summary) {
|
|
341
|
+
const itemId = readString(item, 'id');
|
|
342
|
+
this.currentOnEvent?.({
|
|
343
|
+
type: 'command.started',
|
|
344
|
+
command: summary,
|
|
345
|
+
...(itemId ? { itemId } : {}),
|
|
346
|
+
});
|
|
347
|
+
}
|
|
342
348
|
return;
|
|
343
349
|
}
|
|
344
350
|
if (method === 'item/completed') {
|
|
@@ -351,13 +357,28 @@ export class CodexAppServerAdapter {
|
|
|
351
357
|
}
|
|
352
358
|
}
|
|
353
359
|
else if (item?.type === 'commandExecution') {
|
|
360
|
+
const itemId = readString(item, 'id');
|
|
354
361
|
this.currentOnEvent?.({
|
|
355
362
|
type: 'command.completed',
|
|
356
363
|
command: readString(item, 'command') ?? 'Command',
|
|
357
364
|
output: readString(item, 'aggregatedOutput') ?? '',
|
|
358
365
|
exitCode: typeof item.exitCode === 'number' ? item.exitCode : null,
|
|
366
|
+
...(itemId ? { itemId } : {}),
|
|
359
367
|
});
|
|
360
368
|
}
|
|
369
|
+
else {
|
|
370
|
+
const summary = summarizeItem(item);
|
|
371
|
+
if (summary) {
|
|
372
|
+
const itemId = readString(item, 'id');
|
|
373
|
+
this.currentOnEvent?.({
|
|
374
|
+
type: 'command.completed',
|
|
375
|
+
command: summary,
|
|
376
|
+
output: '',
|
|
377
|
+
exitCode: null,
|
|
378
|
+
...(itemId ? { itemId } : {}),
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
}
|
|
361
382
|
return;
|
|
362
383
|
}
|
|
363
384
|
if (method === 'turn/completed') {
|
|
@@ -432,6 +453,10 @@ function readString(record, key) {
|
|
|
432
453
|
const value = record?.[key];
|
|
433
454
|
return typeof value === 'string' && value.trim() ? value.trim() : undefined;
|
|
434
455
|
}
|
|
456
|
+
function readRawString(record, key) {
|
|
457
|
+
const value = record?.[key];
|
|
458
|
+
return typeof value === 'string' ? value : undefined;
|
|
459
|
+
}
|
|
435
460
|
function stringifyPreview(value) {
|
|
436
461
|
if (typeof value === 'string')
|
|
437
462
|
return value;
|
package/dist/host.js
CHANGED
|
@@ -5,7 +5,7 @@ import { spawnSync } from 'node:child_process';
|
|
|
5
5
|
import { dirname } from 'node:path';
|
|
6
6
|
import { parseArgs } from 'node:util';
|
|
7
7
|
import { getCodexImagePath, materializeMessageMedia, materializeReplyContextMedia, } from '@canonmsg/agent-sdk';
|
|
8
|
-
import { RUNTIME_NEW_SESSION_ACTION, RUNTIME_STOP_ACTION, RUNTIME_STOP_AND_DROP_ACTION, buildRuntimeCardOutcome, buildPlanApprovalRequest, buildCanonHostPrompt, buildConfiguredWorkspaceOptionsWithRoots, buildFirstPartyCodingRuntimeDescriptor, buildHydratedInboundContext, diffCanonMemberIds, buildPublicWorkspaceRoots, buildPublicWorkspaceOptions, buildRuntimePresentationPolicy, DEFAULT_FIRST_PARTY_RUNTIME_PRESENTATION, createConversationMetadataLoader, createRuntimeStatePublisher, createTypingStatusPublisher, EXECUTION_ENVIRONMENT_MODES, ExecutionEnvironmentError, CanonClient, CanonStream, DEFAULT_PARTICIPATION_HISTORY_FETCH_LIMIT, DEFAULT_RUNTIME_CAPABILITIES, FINAL_MESSAGE_HANDOFF_MS, getActiveProfileLock, initRTDBAuth, buildLocalRuntimeId, heartbeatLocalRuntimeEntry, loadRuntimeSessionState, markLocalRuntimeStopped, normalizeTurnMetadata, parseRuntimeCardV1, prepareConversationEnvironment, loadHostSessionConfig, releaseConversationEnvironment, resolveCanonAgent, rtdbRead, rtdbWrite, sendMessageWithRetry, shouldTriggerAgentTurn, saveRuntimeSessionState, buildBoundedTurnTrail, publishHostAgentRuntime, publishHostSessionSnapshots, renderCanonHostInboundContent, resolveHostWorkspaceCwd, upsertLocalRuntimeEntry, } from '@canonmsg/core';
|
|
8
|
+
import { RUNTIME_NEW_SESSION_ACTION, RUNTIME_STOP_ACTION, RUNTIME_STOP_AND_DROP_ACTION, buildRuntimeCardOutcome, buildPlanApprovalRequest, buildCanonHostPrompt, buildCanonTurnEnvelopeV1, buildConfiguredWorkspaceOptionsWithRoots, buildFirstPartyCodingRuntimeDescriptor, buildHydratedInboundContext, diffCanonMemberIds, buildPublicWorkspaceRoots, buildPublicWorkspaceOptions, buildRuntimePresentationPolicy, DEFAULT_FIRST_PARTY_RUNTIME_PRESENTATION, createConversationMetadataLoader, createRuntimeStatePublisher, createTypingStatusPublisher, EXECUTION_ENVIRONMENT_MODES, ExecutionEnvironmentError, CanonClient, CanonStream, DEFAULT_PARTICIPATION_HISTORY_FETCH_LIMIT, DEFAULT_RUNTIME_CAPABILITIES, FINAL_MESSAGE_HANDOFF_MS, getActiveProfileLock, initRTDBAuth, buildLocalRuntimeId, heartbeatLocalRuntimeEntry, loadRuntimeSessionState, markLocalRuntimeStopped, normalizeTurnMetadata, parseRuntimeCardV1, prepareConversationEnvironment, loadHostSessionConfig, releaseConversationEnvironment, resolveCanonAgent, rtdbRead, rtdbWrite, CanonApiError, sendMessageWithRetry, sendMessageWithRetryChunked, shouldTriggerAgentTurn, saveRuntimeSessionState, buildBoundedTurnTrail, publishHostAgentRuntime, publishHostSessionSnapshots, renderCanonHostInboundContent, renderCanonTurnEnvelopePrompt, resolveCanonHostPromptMode, resolveHostWorkspaceCwd, upsertLocalRuntimeEntry, } from '@canonmsg/core';
|
|
9
9
|
import { buildInboundContextLines, decideAutoReply, } from './inbound-policy.js';
|
|
10
10
|
import { CodexConversationAdapter, } from './adapter.js';
|
|
11
11
|
import { CodexAppServerAdapter } from './app-server-adapter.js';
|
|
@@ -16,6 +16,7 @@ import { detectCodexCliVersion } from './codex-cli-version.js';
|
|
|
16
16
|
import { buildCodexModelGuardMessage, formatCodexTurnFailure, isRecoverableCodexThreadError, } from './error-format.js';
|
|
17
17
|
import { startCodexStreamInBackground } from './host-lifecycle.js';
|
|
18
18
|
import { runCli } from './cli-entry.js';
|
|
19
|
+
import { beginCommandBlock, claimCommandBlock, createCommandBlockTracker, } from './turn-activity.js';
|
|
19
20
|
const HELP = `canon-codex — run a local Codex agent host for Canon
|
|
20
21
|
|
|
21
22
|
USAGE
|
|
@@ -49,6 +50,7 @@ Keep this terminal open while you want Canon to reach the agent. Closing it,
|
|
|
49
50
|
logging out, rebooting, or sleeping long enough to stop the process takes the
|
|
50
51
|
local agent offline until you revive it. Docs:
|
|
51
52
|
https://canonmail.com/agents/integrations`;
|
|
53
|
+
const HOST_PROMPT_MODE = resolveCanonHostPromptMode(process.env.CANON_HOST_PROMPT_MODE);
|
|
52
54
|
const MAX_SESSIONS = 12;
|
|
53
55
|
const IDLE_TIMEOUT_MS = 30 * 60 * 1000;
|
|
54
56
|
const HEARTBEAT_MS = 30_000;
|
|
@@ -125,6 +127,7 @@ function buildCodexRuntimeDescriptor(input) {
|
|
|
125
127
|
result: 'action_or_values',
|
|
126
128
|
maxTimeoutMs: 30 * 60_000,
|
|
127
129
|
blockKinds: ['summary', 'metricGrid', 'chart', 'table', 'list', 'callout', 'actions'],
|
|
130
|
+
actionFieldTypes: ['text', 'textarea', 'select', 'multiSelect', 'boolean'],
|
|
128
131
|
native: true,
|
|
129
132
|
},
|
|
130
133
|
},
|
|
@@ -226,6 +229,20 @@ function resolveCodexEffectiveRuntimePolicy(input) {
|
|
|
226
229
|
};
|
|
227
230
|
}
|
|
228
231
|
function buildCanonPrompt(input) {
|
|
232
|
+
if (HOST_PROMPT_MODE === 'envelope') {
|
|
233
|
+
return renderCanonTurnEnvelopePrompt(buildCanonTurnEnvelopeV1({
|
|
234
|
+
content: input.content,
|
|
235
|
+
conversationId: input.conversationId,
|
|
236
|
+
participantContext: input.participantContext,
|
|
237
|
+
behavior: input.behavior,
|
|
238
|
+
selfContexts: input.selfContexts,
|
|
239
|
+
activeSelfContextId: input.activeSelfContextId,
|
|
240
|
+
provenance: input.provenance,
|
|
241
|
+
replyContext: input.replyContext,
|
|
242
|
+
message: input.message,
|
|
243
|
+
hydratedFromPage: input.hydratedFromPage,
|
|
244
|
+
}));
|
|
245
|
+
}
|
|
229
246
|
return buildCanonHostPrompt({
|
|
230
247
|
hostLabel: 'Codex',
|
|
231
248
|
buildInboundContextLines,
|
|
@@ -843,6 +860,7 @@ export async function main() {
|
|
|
843
860
|
closed: false,
|
|
844
861
|
turnLiveText: '',
|
|
845
862
|
turnBlocks: [],
|
|
863
|
+
turnCommandBlocks: createCommandBlockTracker(),
|
|
846
864
|
};
|
|
847
865
|
sessions.set(conversationId, session);
|
|
848
866
|
await Promise.all([
|
|
@@ -1213,7 +1231,7 @@ export async function main() {
|
|
|
1213
1231
|
const userMessage = error instanceof ExecutionEnvironmentError ? error.userMessage : message;
|
|
1214
1232
|
console.error(`[canon-codex] [${input.conversationId.slice(0, 8)}] Failed to create session: ${message}`);
|
|
1215
1233
|
await markQueuedMessageAccepted(input.conversationId, input.message.id, shouldMarkAccepted);
|
|
1216
|
-
await
|
|
1234
|
+
await sendMessageWithRetryChunked(client, input.conversationId, `I couldn't start a coding session for this workspace: ${userMessage}`, {
|
|
1217
1235
|
messageId: `codex-start-failed-${input.message.id}`,
|
|
1218
1236
|
...(activeSelfContextId ? { selfContextId: activeSelfContextId } : {}),
|
|
1219
1237
|
metadata: {
|
|
@@ -1230,7 +1248,11 @@ export async function main() {
|
|
|
1230
1248
|
participantContext,
|
|
1231
1249
|
behavior,
|
|
1232
1250
|
selfContexts,
|
|
1251
|
+
activeSelfContextId,
|
|
1252
|
+
provenance: hydrated.provenance,
|
|
1233
1253
|
replyContext,
|
|
1254
|
+
message: input.message,
|
|
1255
|
+
hydratedFromPage: hydrated.hydratedFromPage,
|
|
1234
1256
|
});
|
|
1235
1257
|
if (session.running && deliveryIntent === 'interrupt') {
|
|
1236
1258
|
enqueuePrompt(session, prompt, deliveryIntent, true, input.message.id, shouldMarkAccepted, imagePaths, mediaAddDirs, planCommand.planMode);
|
|
@@ -1254,6 +1276,7 @@ export async function main() {
|
|
|
1254
1276
|
session.currentTurnId = randomUUID();
|
|
1255
1277
|
session.turnLiveText = '';
|
|
1256
1278
|
session.turnBlocks = [];
|
|
1279
|
+
session.turnCommandBlocks = createCommandBlockTracker();
|
|
1257
1280
|
session.currentTurnOpenedAt = Date.now();
|
|
1258
1281
|
session.currentTurnUpdatedAt = session.currentTurnOpenedAt;
|
|
1259
1282
|
session.lastAcceptedIntent = nextTurn.intent;
|
|
@@ -1317,8 +1340,13 @@ export async function main() {
|
|
|
1317
1340
|
markTurnProgress(session);
|
|
1318
1341
|
writeTurn(session);
|
|
1319
1342
|
startVisibleWorkSignal(session);
|
|
1343
|
+
const blockId = beginCommandBlock(session.turnCommandBlocks, {
|
|
1344
|
+
turnId: session.currentTurnId,
|
|
1345
|
+
command: event.command,
|
|
1346
|
+
itemId: event.itemId,
|
|
1347
|
+
});
|
|
1320
1348
|
upsertTurnBlock(session, {
|
|
1321
|
-
id:
|
|
1349
|
+
id: blockId,
|
|
1322
1350
|
kind: 'tool',
|
|
1323
1351
|
status: 'running',
|
|
1324
1352
|
title: summarizeCommand(event.command),
|
|
@@ -1328,7 +1356,12 @@ export async function main() {
|
|
|
1328
1356
|
return;
|
|
1329
1357
|
}
|
|
1330
1358
|
if (event.type === 'command.completed') {
|
|
1331
|
-
|
|
1359
|
+
const blockId = claimCommandBlock(session.turnCommandBlocks, {
|
|
1360
|
+
turnId: session.currentTurnId,
|
|
1361
|
+
command: event.command,
|
|
1362
|
+
itemId: event.itemId,
|
|
1363
|
+
});
|
|
1364
|
+
completeTurnBlock(session, blockId, 'Command completed');
|
|
1332
1365
|
if (session.turnState === 'tool') {
|
|
1333
1366
|
session.turnState = 'thinking';
|
|
1334
1367
|
markTurnProgress(session);
|
|
@@ -1389,7 +1422,7 @@ export async function main() {
|
|
|
1389
1422
|
clearStoredThread();
|
|
1390
1423
|
}
|
|
1391
1424
|
const turnTrail = buildFinalTurnTrail(session);
|
|
1392
|
-
await
|
|
1425
|
+
await sendMessageWithRetryChunked(client, session.conversationId, result.finalMessage, {
|
|
1393
1426
|
messageId: buildCodexMessageId(session, 'final'),
|
|
1394
1427
|
...(session.activeSelfContextId
|
|
1395
1428
|
? { selfContextId: session.activeSelfContextId }
|
|
@@ -1412,7 +1445,7 @@ export async function main() {
|
|
|
1412
1445
|
console.error(`[canon-codex] [${session.conversationId.slice(0, 8)}] Turn exited ${result.exitCode}: ${result.errorText}`);
|
|
1413
1446
|
}
|
|
1414
1447
|
const turnTrail = buildFinalTurnTrail(session);
|
|
1415
|
-
await
|
|
1448
|
+
await sendMessageWithRetryChunked(client, session.conversationId, userVisibleError, {
|
|
1416
1449
|
messageId: buildCodexMessageId(session, 'error'),
|
|
1417
1450
|
...(session.activeSelfContextId
|
|
1418
1451
|
? { selfContextId: session.activeSelfContextId }
|
|
@@ -1441,10 +1474,12 @@ export async function main() {
|
|
|
1441
1474
|
catch (error) {
|
|
1442
1475
|
const message = error instanceof ExecutionEnvironmentError
|
|
1443
1476
|
? error.userMessage
|
|
1444
|
-
:
|
|
1477
|
+
: error instanceof CanonApiError
|
|
1478
|
+
? `The Codex host completed the turn, but Canon could not deliver the reply: ${error.message}`
|
|
1479
|
+
: `The Codex host failed during the turn: ${error instanceof Error ? error.message : String(error)}`;
|
|
1445
1480
|
session.state.lastError = message;
|
|
1446
1481
|
writeState(session);
|
|
1447
|
-
await
|
|
1482
|
+
await sendMessageWithRetryChunked(client, session.conversationId, message, {
|
|
1448
1483
|
messageId: buildCodexMessageId(session, 'failure'),
|
|
1449
1484
|
...(session.activeSelfContextId
|
|
1450
1485
|
? { selfContextId: session.activeSelfContextId }
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
interface RunningCommandBlock {
|
|
2
|
+
command: string;
|
|
3
|
+
blockId: string;
|
|
4
|
+
itemId?: string;
|
|
5
|
+
}
|
|
6
|
+
export interface CommandBlockTracker {
|
|
7
|
+
sequence: number;
|
|
8
|
+
running: RunningCommandBlock[];
|
|
9
|
+
}
|
|
10
|
+
export declare function createCommandBlockTracker(): CommandBlockTracker;
|
|
11
|
+
export declare function beginCommandBlock(tracker: CommandBlockTracker, input: {
|
|
12
|
+
turnId: string | null | undefined;
|
|
13
|
+
command: string;
|
|
14
|
+
itemId?: string;
|
|
15
|
+
}): string;
|
|
16
|
+
export declare function claimCommandBlock(tracker: CommandBlockTracker, input: {
|
|
17
|
+
turnId: string | null | undefined;
|
|
18
|
+
command: string;
|
|
19
|
+
itemId?: string;
|
|
20
|
+
}): string;
|
|
21
|
+
export {};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export function createCommandBlockTracker() {
|
|
2
|
+
return {
|
|
3
|
+
sequence: 0,
|
|
4
|
+
running: [],
|
|
5
|
+
};
|
|
6
|
+
}
|
|
7
|
+
function normalizeOptionalString(value) {
|
|
8
|
+
const normalized = value?.trim();
|
|
9
|
+
return normalized ? normalized : undefined;
|
|
10
|
+
}
|
|
11
|
+
function nextCommandBlockId(tracker, turnId, itemId) {
|
|
12
|
+
const stableTurnId = turnId ?? 'turn';
|
|
13
|
+
if (itemId)
|
|
14
|
+
return `command:${stableTurnId}:${itemId}`;
|
|
15
|
+
tracker.sequence += 1;
|
|
16
|
+
return `command:${stableTurnId}:${tracker.sequence}`;
|
|
17
|
+
}
|
|
18
|
+
export function beginCommandBlock(tracker, input) {
|
|
19
|
+
const itemId = normalizeOptionalString(input.itemId);
|
|
20
|
+
if (itemId) {
|
|
21
|
+
const existing = tracker.running.find((block) => block.itemId === itemId);
|
|
22
|
+
if (existing)
|
|
23
|
+
return existing.blockId;
|
|
24
|
+
}
|
|
25
|
+
const blockId = nextCommandBlockId(tracker, input.turnId, itemId);
|
|
26
|
+
tracker.running.push({
|
|
27
|
+
command: input.command.trim(),
|
|
28
|
+
blockId,
|
|
29
|
+
...(itemId ? { itemId } : {}),
|
|
30
|
+
});
|
|
31
|
+
return blockId;
|
|
32
|
+
}
|
|
33
|
+
export function claimCommandBlock(tracker, input) {
|
|
34
|
+
const itemId = normalizeOptionalString(input.itemId);
|
|
35
|
+
const command = input.command.trim();
|
|
36
|
+
const matchingIndex = itemId
|
|
37
|
+
? tracker.running.findIndex((block) => block.itemId === itemId)
|
|
38
|
+
: tracker.running.findIndex((block) => !block.itemId && block.command === command);
|
|
39
|
+
const fallbackIndex = matchingIndex >= 0
|
|
40
|
+
? matchingIndex
|
|
41
|
+
: tracker.running.findIndex((block) => !block.itemId);
|
|
42
|
+
if (fallbackIndex >= 0) {
|
|
43
|
+
const [block] = tracker.running.splice(fallbackIndex, 1);
|
|
44
|
+
return block.blockId;
|
|
45
|
+
}
|
|
46
|
+
return nextCommandBlockId(tracker, input.turnId, itemId);
|
|
47
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@canonmsg/codex-plugin",
|
|
3
|
-
"version": "0.13.
|
|
3
|
+
"version": "0.13.3",
|
|
4
4
|
"description": "Canon host integration for Codex CLI",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -29,8 +29,8 @@
|
|
|
29
29
|
"prepack": "npm run build"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@canonmsg/agent-sdk": "^2.
|
|
33
|
-
"@canonmsg/core": "^1.
|
|
32
|
+
"@canonmsg/agent-sdk": "^2.4.0",
|
|
33
|
+
"@canonmsg/core": "^1.7.0"
|
|
34
34
|
},
|
|
35
35
|
"engines": {
|
|
36
36
|
"node": ">=18.0.0"
|