@ccpocket/bridge 1.33.3 → 1.34.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.
- package/dist/codex-process.d.ts +43 -6
- package/dist/codex-process.js +162 -43
- package/dist/codex-process.js.map +1 -1
- package/dist/parser.d.ts +17 -0
- package/dist/parser.js +18 -0
- package/dist/parser.js.map +1 -1
- package/dist/session.d.ts +2 -0
- package/dist/session.js +19 -11
- package/dist/session.js.map +1 -1
- package/dist/websocket.js +38 -10
- package/dist/websocket.js.map +1 -1
- package/package.json +1 -1
package/dist/codex-process.d.ts
CHANGED
|
@@ -27,6 +27,15 @@ export interface CodexSkillMetadata {
|
|
|
27
27
|
defaultPrompt?: string;
|
|
28
28
|
brandColor?: string;
|
|
29
29
|
}
|
|
30
|
+
/** App / connector metadata returned by the Codex `app/list` RPC. */
|
|
31
|
+
export interface CodexAppMetadata {
|
|
32
|
+
id: string;
|
|
33
|
+
name: string;
|
|
34
|
+
description: string;
|
|
35
|
+
installUrl?: string;
|
|
36
|
+
isAccessible: boolean;
|
|
37
|
+
isEnabled: boolean;
|
|
38
|
+
}
|
|
30
39
|
export interface CodexThreadSummary {
|
|
31
40
|
id: string;
|
|
32
41
|
preview: string;
|
|
@@ -64,10 +73,17 @@ export declare class CodexProcess extends EventEmitter<CodexProcessEvents> {
|
|
|
64
73
|
private lastTokenUsage;
|
|
65
74
|
/** Full skill metadata from the last `skills/list` response. */
|
|
66
75
|
private _skills;
|
|
76
|
+
/** Full app metadata from the last `app/list` response. */
|
|
77
|
+
private _apps;
|
|
67
78
|
/** Project path stored for re-fetching skills on `skills/changed`. */
|
|
68
79
|
private _projectPath;
|
|
80
|
+
/** Prevent redundant completion fetch storms from repeated change notifications. */
|
|
81
|
+
private _completionFetchInFlight;
|
|
82
|
+
private _completionFetchQueued;
|
|
83
|
+
private _lastCompletionEntitiesSignature;
|
|
69
84
|
/** Expose skill metadata so session/websocket can access it. */
|
|
70
85
|
get skills(): CodexSkillMetadata[];
|
|
86
|
+
get apps(): CodexAppMetadata[];
|
|
71
87
|
private rpcSeq;
|
|
72
88
|
private pendingRpc;
|
|
73
89
|
private stdoutBuffer;
|
|
@@ -135,6 +151,20 @@ export declare class CodexProcess extends EventEmitter<CodexProcessEvents> {
|
|
|
135
151
|
name: string;
|
|
136
152
|
path: string;
|
|
137
153
|
}): void;
|
|
154
|
+
sendInputStructured(text: string, options?: {
|
|
155
|
+
images?: Array<{
|
|
156
|
+
base64: string;
|
|
157
|
+
mimeType: string;
|
|
158
|
+
}>;
|
|
159
|
+
skills?: Array<{
|
|
160
|
+
name: string;
|
|
161
|
+
path: string;
|
|
162
|
+
}>;
|
|
163
|
+
mentions?: Array<{
|
|
164
|
+
name: string;
|
|
165
|
+
path: string;
|
|
166
|
+
}>;
|
|
167
|
+
}): void;
|
|
138
168
|
approve(toolUseId?: string, _updatedInput?: Record<string, unknown>): void;
|
|
139
169
|
approveAlways(toolUseId?: string): void;
|
|
140
170
|
reject(toolUseId?: string, _message?: string): void;
|
|
@@ -148,6 +178,17 @@ export declare class CodexProcess extends EventEmitter<CodexProcessEvents> {
|
|
|
148
178
|
private emitToolResult;
|
|
149
179
|
private resolvePendingApproval;
|
|
150
180
|
private resolvePendingUserInput;
|
|
181
|
+
/**
|
|
182
|
+
* Approve a pending user-input request (McpElicitation fallback).
|
|
183
|
+
* Called when approve()/approveAlways() cannot find a pendingApproval —
|
|
184
|
+
* McpElicitation lives in pendingUserInputs but the app routes it through
|
|
185
|
+
* the permission (approve/reject) path.
|
|
186
|
+
*/
|
|
187
|
+
private approveUserInput;
|
|
188
|
+
/**
|
|
189
|
+
* Reject a pending user-input request (McpElicitation fallback).
|
|
190
|
+
*/
|
|
191
|
+
private rejectUserInput;
|
|
151
192
|
/**
|
|
152
193
|
* Plan approved → switch to Default mode and auto-start execution.
|
|
153
194
|
*/
|
|
@@ -158,12 +199,8 @@ export declare class CodexProcess extends EventEmitter<CodexProcessEvents> {
|
|
|
158
199
|
private handlePlanRejected;
|
|
159
200
|
private bootstrap;
|
|
160
201
|
private initializeRpcConnection;
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
* as a `supported_commands` system message so the Flutter client can display
|
|
164
|
-
* skill entries alongside built-in slash commands.
|
|
165
|
-
*/
|
|
166
|
-
private fetchSkills;
|
|
202
|
+
private fetchCompletionEntities;
|
|
203
|
+
private _fetchCompletionEntitiesInternal;
|
|
167
204
|
private runInputLoop;
|
|
168
205
|
private handleStdoutChunk;
|
|
169
206
|
private handleRpcEnvelope;
|
package/dist/codex-process.js
CHANGED
|
@@ -45,12 +45,21 @@ export class CodexProcess extends EventEmitter {
|
|
|
45
45
|
lastTokenUsage = null;
|
|
46
46
|
/** Full skill metadata from the last `skills/list` response. */
|
|
47
47
|
_skills = [];
|
|
48
|
+
/** Full app metadata from the last `app/list` response. */
|
|
49
|
+
_apps = [];
|
|
48
50
|
/** Project path stored for re-fetching skills on `skills/changed`. */
|
|
49
51
|
_projectPath = null;
|
|
52
|
+
/** Prevent redundant completion fetch storms from repeated change notifications. */
|
|
53
|
+
_completionFetchInFlight = null;
|
|
54
|
+
_completionFetchQueued = false;
|
|
55
|
+
_lastCompletionEntitiesSignature = null;
|
|
50
56
|
/** Expose skill metadata so session/websocket can access it. */
|
|
51
57
|
get skills() {
|
|
52
58
|
return this._skills;
|
|
53
59
|
}
|
|
60
|
+
get apps() {
|
|
61
|
+
return this._apps;
|
|
62
|
+
}
|
|
54
63
|
rpcSeq = 1;
|
|
55
64
|
pendingRpc = new Map();
|
|
56
65
|
stdoutBuffer = "";
|
|
@@ -273,13 +282,21 @@ export class CodexProcess extends EventEmitter {
|
|
|
273
282
|
resolve({ text, images });
|
|
274
283
|
}
|
|
275
284
|
sendInputWithSkill(text, skill) {
|
|
285
|
+
this.sendInputStructured(text, { skills: [skill] });
|
|
286
|
+
}
|
|
287
|
+
sendInputStructured(text, options) {
|
|
276
288
|
if (!this.inputResolve) {
|
|
277
|
-
console.error("[codex-process] No pending input resolver for
|
|
289
|
+
console.error("[codex-process] No pending input resolver for sendInputStructured");
|
|
278
290
|
return;
|
|
279
291
|
}
|
|
280
292
|
const resolve = this.inputResolve;
|
|
281
293
|
this.inputResolve = null;
|
|
282
|
-
resolve({
|
|
294
|
+
resolve({
|
|
295
|
+
text,
|
|
296
|
+
images: options?.images,
|
|
297
|
+
skills: options?.skills,
|
|
298
|
+
mentions: options?.mentions,
|
|
299
|
+
});
|
|
283
300
|
}
|
|
284
301
|
approve(toolUseId, _updatedInput) {
|
|
285
302
|
// Check if this is a plan completion approval
|
|
@@ -290,6 +307,9 @@ export class CodexProcess extends EventEmitter {
|
|
|
290
307
|
}
|
|
291
308
|
const pending = this.resolvePendingApproval(toolUseId);
|
|
292
309
|
if (!pending) {
|
|
310
|
+
// Fallback: McpElicitation lives in pendingUserInputs
|
|
311
|
+
if (this.approveUserInput(toolUseId, "Accept"))
|
|
312
|
+
return;
|
|
293
313
|
console.log("[codex-process] approve() called but no pending permission requests");
|
|
294
314
|
return;
|
|
295
315
|
}
|
|
@@ -303,6 +323,9 @@ export class CodexProcess extends EventEmitter {
|
|
|
303
323
|
approveAlways(toolUseId) {
|
|
304
324
|
const pending = this.resolvePendingApproval(toolUseId);
|
|
305
325
|
if (!pending) {
|
|
326
|
+
// Fallback: McpElicitation lives in pendingUserInputs
|
|
327
|
+
if (this.approveUserInput(toolUseId, "Accept"))
|
|
328
|
+
return;
|
|
306
329
|
console.log("[codex-process] approveAlways() called but no pending permission requests");
|
|
307
330
|
return;
|
|
308
331
|
}
|
|
@@ -322,6 +345,9 @@ export class CodexProcess extends EventEmitter {
|
|
|
322
345
|
}
|
|
323
346
|
const pending = this.resolvePendingApproval(toolUseId);
|
|
324
347
|
if (!pending) {
|
|
348
|
+
// Fallback: McpElicitation lives in pendingUserInputs
|
|
349
|
+
if (this.rejectUserInput(toolUseId, "Decline"))
|
|
350
|
+
return;
|
|
325
351
|
console.log("[codex-process] reject() called but no pending permission requests");
|
|
326
352
|
return;
|
|
327
353
|
}
|
|
@@ -369,7 +395,7 @@ export class CodexProcess extends EventEmitter {
|
|
|
369
395
|
return undefined;
|
|
370
396
|
return {
|
|
371
397
|
toolUseId: pendingAsk.toolUseId,
|
|
372
|
-
toolName:
|
|
398
|
+
toolName: pendingAsk.toolName,
|
|
373
399
|
input: { ...pendingAsk.input },
|
|
374
400
|
};
|
|
375
401
|
}
|
|
@@ -393,6 +419,39 @@ export class CodexProcess extends EventEmitter {
|
|
|
393
419
|
const first = this.pendingUserInputs.values().next();
|
|
394
420
|
return first.done ? undefined : first.value;
|
|
395
421
|
}
|
|
422
|
+
/**
|
|
423
|
+
* Approve a pending user-input request (McpElicitation fallback).
|
|
424
|
+
* Called when approve()/approveAlways() cannot find a pendingApproval —
|
|
425
|
+
* McpElicitation lives in pendingUserInputs but the app routes it through
|
|
426
|
+
* the permission (approve/reject) path.
|
|
427
|
+
*/
|
|
428
|
+
approveUserInput(toolUseId, result) {
|
|
429
|
+
const pending = this.resolvePendingUserInput(toolUseId);
|
|
430
|
+
if (!pending)
|
|
431
|
+
return false;
|
|
432
|
+
this.pendingUserInputs.delete(pending.toolUseId);
|
|
433
|
+
this.respondToServerRequest(pending.requestId, buildUserInputResponse(pending, result));
|
|
434
|
+
this.emitToolResult(pending.toolUseId, "Approved");
|
|
435
|
+
if (this.pendingApprovals.size === 0 && this.pendingUserInputs.size === 0) {
|
|
436
|
+
this.setStatus("running");
|
|
437
|
+
}
|
|
438
|
+
return true;
|
|
439
|
+
}
|
|
440
|
+
/**
|
|
441
|
+
* Reject a pending user-input request (McpElicitation fallback).
|
|
442
|
+
*/
|
|
443
|
+
rejectUserInput(toolUseId, result) {
|
|
444
|
+
const pending = this.resolvePendingUserInput(toolUseId);
|
|
445
|
+
if (!pending)
|
|
446
|
+
return false;
|
|
447
|
+
this.pendingUserInputs.delete(pending.toolUseId);
|
|
448
|
+
this.respondToServerRequest(pending.requestId, buildUserInputResponse(pending, result));
|
|
449
|
+
this.emitToolResult(pending.toolUseId, "Rejected");
|
|
450
|
+
if (this.pendingApprovals.size === 0 && this.pendingUserInputs.size === 0) {
|
|
451
|
+
this.setStatus("running");
|
|
452
|
+
}
|
|
453
|
+
return true;
|
|
454
|
+
}
|
|
396
455
|
// ---------------------------------------------------------------------------
|
|
397
456
|
// Plan completion handlers (native collaboration_mode)
|
|
398
457
|
// ---------------------------------------------------------------------------
|
|
@@ -526,9 +585,13 @@ export class CodexProcess extends EventEmitter {
|
|
|
526
585
|
: {}),
|
|
527
586
|
});
|
|
528
587
|
this.setStatus("idle");
|
|
529
|
-
// Fetch skills in background (non-blocking)
|
|
588
|
+
// Fetch skills/apps in background (non-blocking)
|
|
530
589
|
this._projectPath = projectPath;
|
|
531
|
-
|
|
590
|
+
setTimeout(() => {
|
|
591
|
+
if (!this.stopped) {
|
|
592
|
+
void this.fetchCompletionEntities(projectPath);
|
|
593
|
+
}
|
|
594
|
+
}, 25);
|
|
532
595
|
await this.runInputLoop(options);
|
|
533
596
|
}
|
|
534
597
|
catch (err) {
|
|
@@ -560,58 +623,101 @@ export class CodexProcess extends EventEmitter {
|
|
|
560
623
|
});
|
|
561
624
|
this.notify("initialized", {});
|
|
562
625
|
}
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
626
|
+
async fetchCompletionEntities(projectPath) {
|
|
627
|
+
if (this._completionFetchInFlight) {
|
|
628
|
+
this._completionFetchQueued = true;
|
|
629
|
+
return this._completionFetchInFlight;
|
|
630
|
+
}
|
|
631
|
+
this._completionFetchInFlight = this._fetchCompletionEntitiesInternal(projectPath);
|
|
632
|
+
try {
|
|
633
|
+
await this._completionFetchInFlight;
|
|
634
|
+
}
|
|
635
|
+
finally {
|
|
636
|
+
this._completionFetchInFlight = null;
|
|
637
|
+
if (this._completionFetchQueued && !this.stopped && this._projectPath) {
|
|
638
|
+
this._completionFetchQueued = false;
|
|
639
|
+
void this.fetchCompletionEntities(this._projectPath);
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
async _fetchCompletionEntitiesInternal(projectPath) {
|
|
569
644
|
const TIMEOUT_MS = 10_000;
|
|
570
645
|
try {
|
|
571
|
-
const
|
|
646
|
+
const skillsResult = (await Promise.race([
|
|
572
647
|
this.request("skills/list", { cwds: [projectPath] }),
|
|
573
648
|
new Promise((resolve) => setTimeout(() => resolve(null), TIMEOUT_MS)),
|
|
574
649
|
]));
|
|
575
|
-
|
|
576
|
-
|
|
650
|
+
const appsResult = (await Promise.race([
|
|
651
|
+
this.request("app/list", {
|
|
652
|
+
cursor: null,
|
|
653
|
+
limit: 100,
|
|
654
|
+
threadId: this._threadId ?? undefined,
|
|
655
|
+
forceRefetch: false,
|
|
656
|
+
}),
|
|
657
|
+
new Promise((resolve) => setTimeout(() => resolve(null), TIMEOUT_MS)),
|
|
658
|
+
]));
|
|
577
659
|
const skills = [];
|
|
578
|
-
const slashCommands = [];
|
|
579
660
|
const skillMetadata = [];
|
|
580
|
-
|
|
581
|
-
for (const
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
661
|
+
if (skillsResult?.data) {
|
|
662
|
+
for (const entry of skillsResult.data) {
|
|
663
|
+
for (const skill of entry.skills) {
|
|
664
|
+
if (skill.enabled) {
|
|
665
|
+
skills.push(skill.name);
|
|
666
|
+
skillMetadata.push({
|
|
667
|
+
name: skill.name,
|
|
668
|
+
path: skill.path,
|
|
669
|
+
description: skill.description,
|
|
670
|
+
shortDescription: skill.shortDescription ??
|
|
671
|
+
skill.interface?.shortDescription ??
|
|
672
|
+
undefined,
|
|
673
|
+
enabled: skill.enabled,
|
|
674
|
+
scope: skill.scope,
|
|
675
|
+
displayName: skill.interface?.displayName ?? undefined,
|
|
676
|
+
defaultPrompt: skill.interface?.defaultPrompt ?? undefined,
|
|
677
|
+
brandColor: skill.interface?.brandColor ?? undefined,
|
|
678
|
+
});
|
|
679
|
+
}
|
|
598
680
|
}
|
|
599
681
|
}
|
|
600
682
|
}
|
|
601
683
|
this._skills = skillMetadata;
|
|
602
|
-
|
|
603
|
-
|
|
684
|
+
const appMetadata = (appsResult?.data ?? [])
|
|
685
|
+
.filter((app) => (app.isAccessible ?? true) && (app.isEnabled ?? true))
|
|
686
|
+
.map((app) => ({
|
|
687
|
+
id: app.id,
|
|
688
|
+
name: app.name,
|
|
689
|
+
description: app.description,
|
|
690
|
+
installUrl: app.installUrl ?? undefined,
|
|
691
|
+
isAccessible: app.isAccessible ?? true,
|
|
692
|
+
isEnabled: app.isEnabled ?? true,
|
|
693
|
+
}));
|
|
694
|
+
this._apps = appMetadata;
|
|
695
|
+
if (this.stopped)
|
|
696
|
+
return;
|
|
697
|
+
const signature = JSON.stringify({
|
|
698
|
+
skills,
|
|
699
|
+
skillMetadata,
|
|
700
|
+
apps: appMetadata.map((app) => app.id),
|
|
701
|
+
appMetadata,
|
|
702
|
+
});
|
|
703
|
+
if (signature === this._lastCompletionEntitiesSignature) {
|
|
704
|
+
return;
|
|
705
|
+
}
|
|
706
|
+
this._lastCompletionEntitiesSignature = signature;
|
|
707
|
+
if (skills.length > 0 || appMetadata.length > 0) {
|
|
708
|
+
console.log(`[codex-process] completion entities loaded: ${skills.length} skills, ${appMetadata.length} apps`);
|
|
604
709
|
this.emitMessage({
|
|
605
710
|
type: "system",
|
|
606
711
|
subtype: "supported_commands",
|
|
607
|
-
slashCommands,
|
|
608
712
|
skills,
|
|
609
713
|
skillMetadata,
|
|
714
|
+
apps: appMetadata.map((app) => app.id),
|
|
715
|
+
appMetadata,
|
|
610
716
|
});
|
|
611
717
|
}
|
|
612
718
|
}
|
|
613
719
|
catch (err) {
|
|
614
|
-
console.log(`[codex-process]
|
|
720
|
+
console.log(`[codex-process] completion entity fetch failed (non-fatal): ${err instanceof Error ? err.message : String(err)}`);
|
|
615
721
|
}
|
|
616
722
|
}
|
|
617
723
|
async runInputLoop(options) {
|
|
@@ -997,9 +1103,15 @@ export class CodexProcess extends EventEmitter {
|
|
|
997
1103
|
break;
|
|
998
1104
|
}
|
|
999
1105
|
case "skills/changed": {
|
|
1000
|
-
// Re-fetch skills when Codex notifies us of changes
|
|
1106
|
+
// Re-fetch skills/apps when Codex notifies us of changes
|
|
1001
1107
|
if (this._projectPath) {
|
|
1002
|
-
void this.
|
|
1108
|
+
void this.fetchCompletionEntities(this._projectPath);
|
|
1109
|
+
}
|
|
1110
|
+
break;
|
|
1111
|
+
}
|
|
1112
|
+
case "app/list/updated": {
|
|
1113
|
+
if (this._projectPath) {
|
|
1114
|
+
void this.fetchCompletionEntities(this._projectPath);
|
|
1003
1115
|
}
|
|
1004
1116
|
break;
|
|
1005
1117
|
}
|
|
@@ -1367,12 +1479,19 @@ export class CodexProcess extends EventEmitter {
|
|
|
1367
1479
|
async toRpcInput(pendingInput) {
|
|
1368
1480
|
const input = [];
|
|
1369
1481
|
const tempPaths = [];
|
|
1370
|
-
// Prepend
|
|
1371
|
-
|
|
1482
|
+
// Prepend structured input items before the free-form text body.
|
|
1483
|
+
for (const skill of pendingInput.skills ?? []) {
|
|
1372
1484
|
input.push({
|
|
1373
1485
|
type: "skill",
|
|
1374
|
-
name:
|
|
1375
|
-
path:
|
|
1486
|
+
name: skill.name,
|
|
1487
|
+
path: skill.path,
|
|
1488
|
+
});
|
|
1489
|
+
}
|
|
1490
|
+
for (const mention of pendingInput.mentions ?? []) {
|
|
1491
|
+
input.push({
|
|
1492
|
+
type: "mention",
|
|
1493
|
+
name: mention.name,
|
|
1494
|
+
path: mention.path,
|
|
1376
1495
|
});
|
|
1377
1496
|
}
|
|
1378
1497
|
input.push({ type: "text", text: pendingInput.text });
|