@ccpocket/bridge 1.68.0 → 1.68.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.
@@ -102,12 +102,15 @@ export declare class CodexProcess extends EventEmitter<CodexProcessEvents> {
102
102
  private _skills;
103
103
  /** Full app metadata from the last `app/list` response. */
104
104
  private _apps;
105
+ /** Full plugin metadata from the last `plugin/list` response. */
106
+ private _plugins;
105
107
  /** Project path stored for re-fetching skills on `skills/changed`. */
106
108
  private _projectPath;
107
109
  /** Prevent redundant completion fetch storms from repeated change notifications. */
108
110
  private _completionFetchInFlight;
109
111
  private _lastCompletionEntitiesSignature;
110
112
  private _completionFetchCooldownUntil;
113
+ private _launchStartedAt;
111
114
  /** Expose skill metadata so session/websocket can access it. */
112
115
  get skills(): CodexSkillMetadata[];
113
116
  get apps(): CodexAppMetadata[];
@@ -300,6 +303,7 @@ export declare class CodexProcess extends EventEmitter<CodexProcessEvents> {
300
303
  private fetchCompletionEntities;
301
304
  private scheduleCompletionFetchFromNotification;
302
305
  private _fetchCompletionEntitiesInternal;
306
+ private emitCompletionEntitiesSnapshot;
303
307
  private runInputLoop;
304
308
  private handleStdoutChunk;
305
309
  private handleRpcEnvelope;
@@ -48,12 +48,15 @@ export class CodexProcess extends EventEmitter {
48
48
  _skills = [];
49
49
  /** Full app metadata from the last `app/list` response. */
50
50
  _apps = [];
51
+ /** Full plugin metadata from the last `plugin/list` response. */
52
+ _plugins = [];
51
53
  /** Project path stored for re-fetching skills on `skills/changed`. */
52
54
  _projectPath = null;
53
55
  /** Prevent redundant completion fetch storms from repeated change notifications. */
54
56
  _completionFetchInFlight = null;
55
57
  _lastCompletionEntitiesSignature = null;
56
58
  _completionFetchCooldownUntil = 0;
59
+ _launchStartedAt = 0;
57
60
  /** Expose skill metadata so session/websocket can access it. */
58
61
  get skills() {
59
62
  return this._skills;
@@ -425,6 +428,11 @@ export class CodexProcess extends EventEmitter {
425
428
  this._collaborationMode = options?.collaborationMode ?? "default";
426
429
  this.lastPlanItemText = null;
427
430
  this.lastResultText = null;
431
+ this._skills = [];
432
+ this._apps = [];
433
+ this._plugins = [];
434
+ this._lastCompletionEntitiesSignature = null;
435
+ this._launchStartedAt = Date.now();
428
436
  this.pendingAgentTextByItemId.clear();
429
437
  this.syntheticAgentTextByItemId.clear();
430
438
  this.pendingPlanCompletion = null;
@@ -1019,7 +1027,7 @@ export class CodexProcess extends EventEmitter {
1019
1027
  ...(cliJoin ? { codexCliJoin: cliJoin } : {}),
1020
1028
  });
1021
1029
  this.setStatus("idle");
1022
- // Fetch skills/apps in background (non-blocking)
1030
+ // Fetch completion entities in background (non-blocking).
1023
1031
  this._projectPath = projectPath;
1024
1032
  setTimeout(() => {
1025
1033
  if (!this.stopped) {
@@ -1116,20 +1124,6 @@ export class CodexProcess extends EventEmitter {
1116
1124
  }),
1117
1125
  new Promise((resolve) => setTimeout(() => resolve(null), TIMEOUT_MS)),
1118
1126
  ]);
1119
- const skillsResult = (await Promise.race([
1120
- this.request("skills/list", { cwds: [projectPath] }),
1121
- new Promise((resolve) => setTimeout(() => resolve(null), TIMEOUT_MS)),
1122
- ]));
1123
- const appsResult = (await Promise.race([
1124
- this.request("app/list", {
1125
- cursor: null,
1126
- limit: 100,
1127
- threadId: this._threadId ?? undefined,
1128
- forceRefetch: false,
1129
- }),
1130
- new Promise((resolve) => setTimeout(() => resolve(null), TIMEOUT_MS)),
1131
- ]));
1132
- const pluginsResult = await requestOrNull("plugin/list", { cwds: [projectPath] });
1133
1127
  const optionalString = (value) => typeof value === "string" ? value : undefined;
1134
1128
  const optionalFirstString = (value) => {
1135
1129
  if (typeof value === "string")
@@ -1138,13 +1132,24 @@ export class CodexProcess extends EventEmitter {
1138
1132
  return undefined;
1139
1133
  return value.find((entry) => typeof entry === "string");
1140
1134
  };
1141
- const skills = [];
1142
- const skillMetadata = [];
1143
- if (skillsResult?.data) {
1144
- for (const entry of skillsResult.data) {
1145
- for (const skill of entry.skills) {
1146
- if (skill.enabled) {
1147
- skills.push(skill.name);
1135
+ const skillsRequest = requestOrNull("skills/list", { cwds: [projectPath] });
1136
+ const appsRequest = requestOrNull("app/list", {
1137
+ cursor: null,
1138
+ limit: 100,
1139
+ threadId: this._threadId ?? undefined,
1140
+ forceRefetch: false,
1141
+ });
1142
+ const pluginsRequest = requestOrNull("plugin/list", { cwds: [projectPath] });
1143
+ let skillsReady = false;
1144
+ await Promise.all([
1145
+ skillsRequest.then((skillsResult) => {
1146
+ if (this.stopped || skillsResult === null)
1147
+ return;
1148
+ const skillMetadata = [];
1149
+ for (const entry of skillsResult.data ?? []) {
1150
+ for (const skill of entry.skills) {
1151
+ if (!skill.enabled)
1152
+ continue;
1148
1153
  skillMetadata.push({
1149
1154
  name: skill.name,
1150
1155
  path: skill.path,
@@ -1160,78 +1165,95 @@ export class CodexProcess extends EventEmitter {
1160
1165
  });
1161
1166
  }
1162
1167
  }
1163
- }
1164
- }
1165
- this._skills = skillMetadata;
1166
- const appMetadata = (appsResult?.data ?? [])
1167
- .filter((app) => (app.isAccessible ?? true) && (app.isEnabled ?? true))
1168
- .map((app) => ({
1169
- id: app.id,
1170
- name: app.name,
1171
- description: app.description,
1172
- installUrl: app.installUrl ?? undefined,
1173
- isAccessible: app.isAccessible ?? true,
1174
- isEnabled: app.isEnabled ?? true,
1175
- }));
1176
- this._apps = appMetadata;
1177
- const pluginMetadata = [];
1178
- for (const marketplace of pluginsResult?.marketplaces ?? []) {
1179
- for (const plugin of marketplace.plugins ?? []) {
1180
- if (!plugin.installed || !plugin.enabled)
1181
- continue;
1182
- pluginMetadata.push({
1183
- id: plugin.id,
1184
- name: plugin.name,
1185
- path: `plugin://${plugin.id}`,
1186
- marketplaceName: marketplace.name,
1187
- marketplacePath: marketplace.path ?? undefined,
1188
- installed: plugin.installed,
1189
- enabled: plugin.enabled,
1190
- displayName: optionalString(plugin.interface?.displayName),
1191
- shortDescription: optionalString(plugin.interface?.shortDescription),
1192
- longDescription: optionalString(plugin.interface?.longDescription),
1193
- defaultPrompt: optionalFirstString(plugin.interface?.defaultPrompt),
1194
- brandColor: optionalString(plugin.interface?.brandColor),
1195
- composerIcon: optionalString(plugin.interface?.composerIcon),
1196
- composerIconUrl: optionalString(plugin.interface?.composerIconUrl),
1197
- });
1198
- }
1199
- }
1200
- const plugins = pluginMetadata.map((plugin) => plugin.name);
1201
- if (this.stopped)
1202
- return;
1203
- const signature = JSON.stringify({
1204
- skills,
1205
- skillMetadata,
1206
- apps: appMetadata.map((app) => app.id),
1207
- appMetadata,
1208
- plugins,
1209
- pluginMetadata,
1210
- });
1211
- if (signature === this._lastCompletionEntitiesSignature) {
1212
- return;
1213
- }
1214
- this._lastCompletionEntitiesSignature = signature;
1215
- if (skills.length > 0 ||
1216
- appMetadata.length > 0 ||
1217
- pluginMetadata.length > 0) {
1218
- console.log(`[codex-process] completion entities loaded: ${skills.length} skills, ${appMetadata.length} apps, ${pluginMetadata.length} plugins`);
1219
- this.emitMessage({
1220
- type: "system",
1221
- subtype: "supported_commands",
1222
- skills,
1223
- skillMetadata,
1224
- apps: appMetadata.map((app) => app.id),
1225
- appMetadata,
1226
- plugins,
1227
- pluginMetadata,
1228
- });
1229
- }
1168
+ this._skills = skillMetadata;
1169
+ skillsReady = true;
1170
+ const elapsedMs = this._launchStartedAt > 0
1171
+ ? Date.now() - this._launchStartedAt
1172
+ : undefined;
1173
+ console.log(`[codex-process] completion skills ready: ${skillMetadata.length} skills${elapsedMs === undefined ? "" : ` (${elapsedMs}ms since start)`}`);
1174
+ this.emitCompletionEntitiesSnapshot("skills");
1175
+ }),
1176
+ appsRequest.then((appsResult) => {
1177
+ if (this.stopped || appsResult === null)
1178
+ return;
1179
+ this._apps = (appsResult.data ?? [])
1180
+ .filter((app) => (app.isAccessible ?? true) && (app.isEnabled ?? true))
1181
+ .map((app) => ({
1182
+ id: app.id,
1183
+ name: app.name,
1184
+ description: app.description,
1185
+ installUrl: app.installUrl ?? undefined,
1186
+ isAccessible: app.isAccessible ?? true,
1187
+ isEnabled: app.isEnabled ?? true,
1188
+ }));
1189
+ if (skillsReady)
1190
+ this.emitCompletionEntitiesSnapshot("apps");
1191
+ }),
1192
+ pluginsRequest.then((pluginsResult) => {
1193
+ if (this.stopped || pluginsResult === null)
1194
+ return;
1195
+ const pluginMetadata = [];
1196
+ for (const marketplace of pluginsResult.marketplaces ?? []) {
1197
+ for (const plugin of marketplace.plugins ?? []) {
1198
+ if (!plugin.installed || !plugin.enabled)
1199
+ continue;
1200
+ pluginMetadata.push({
1201
+ id: plugin.id,
1202
+ name: plugin.name,
1203
+ path: `plugin://${plugin.id}`,
1204
+ marketplaceName: marketplace.name,
1205
+ marketplacePath: marketplace.path ?? undefined,
1206
+ installed: plugin.installed,
1207
+ enabled: plugin.enabled,
1208
+ displayName: optionalString(plugin.interface?.displayName),
1209
+ shortDescription: optionalString(plugin.interface?.shortDescription),
1210
+ longDescription: optionalString(plugin.interface?.longDescription),
1211
+ defaultPrompt: optionalFirstString(plugin.interface?.defaultPrompt),
1212
+ brandColor: optionalString(plugin.interface?.brandColor),
1213
+ composerIcon: optionalString(plugin.interface?.composerIcon),
1214
+ composerIconUrl: optionalString(plugin.interface?.composerIconUrl),
1215
+ });
1216
+ }
1217
+ }
1218
+ this._plugins = pluginMetadata;
1219
+ if (skillsReady)
1220
+ this.emitCompletionEntitiesSnapshot("plugins");
1221
+ }),
1222
+ ]);
1230
1223
  }
1231
1224
  catch (err) {
1232
1225
  console.log(`[codex-process] completion entity fetch failed (non-fatal): ${err instanceof Error ? err.message : String(err)}`);
1233
1226
  }
1234
1227
  }
1228
+ emitCompletionEntitiesSnapshot(source) {
1229
+ if (this.stopped)
1230
+ return;
1231
+ const skills = this._skills.map((skill) => skill.name);
1232
+ const apps = this._apps.map((app) => app.id);
1233
+ const plugins = this._plugins.map((plugin) => plugin.name);
1234
+ const signature = JSON.stringify({
1235
+ skills,
1236
+ skillMetadata: this._skills,
1237
+ apps,
1238
+ appMetadata: this._apps,
1239
+ plugins,
1240
+ pluginMetadata: this._plugins,
1241
+ });
1242
+ if (signature === this._lastCompletionEntitiesSignature)
1243
+ return;
1244
+ this._lastCompletionEntitiesSignature = signature;
1245
+ console.log(`[codex-process] completion entities updated (${source}): ${skills.length} skills, ${apps.length} apps, ${plugins.length} plugins`);
1246
+ this.emitMessage({
1247
+ type: "system",
1248
+ subtype: "supported_commands",
1249
+ skills,
1250
+ skillMetadata: this._skills,
1251
+ apps,
1252
+ appMetadata: this._apps,
1253
+ plugins,
1254
+ pluginMetadata: this._plugins,
1255
+ });
1256
+ }
1235
1257
  async runInputLoop(options) {
1236
1258
  while (!this.stopped) {
1237
1259
  const pendingInput = await new Promise((resolve) => {