@jingyi0605/codingns 0.9.5 → 0.9.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/bin/codingns.mjs +75 -0
- package/dist/public/assets/{AdaptiveButlerPage-kkJDsnCO.js → AdaptiveButlerPage-DclGPzEx.js} +2 -2
- package/dist/public/assets/{App-DrNI9lWA.js → App-BxX5mm9o.js} +6 -6
- package/dist/public/assets/{BootstrapPage-QgVH5Mps.js → BootstrapPage-Bl21SsuW.js} +1 -1
- package/dist/public/assets/{ConversationPage-DVk8VfIj.js → ConversationPage-CmiVCV0q.js} +7 -7
- package/dist/public/assets/{DesktopDetachPreviewPage-BhfP0TpH.js → DesktopDetachPreviewPage-uaOHVsjV.js} +1 -1
- package/dist/public/assets/{DesktopModal-DRmDrv0S.js → DesktopModal-BxsogpLf.js} +1 -1
- package/dist/public/assets/{DesktopWindowPage-DNbJXnSs.js → DesktopWindowPage-Bubfw1nC.js} +1 -1
- package/dist/public/assets/{FileContextPanel---fLO4ve.js → FileContextPanel-DrYWcTkp.js} +1 -1
- package/dist/public/assets/{GitSidebar-sXUE0TqT.js → GitSidebar-CQsfJqun.js} +1 -1
- package/dist/public/assets/{MobileCreateSessionSheet-BftZ5pvb.js → MobileCreateSessionSheet-CqtmfVNo.js} +1 -1
- package/dist/public/assets/{MobileSheet-nw5SCa3N.js → MobileSheet-C5IVmUsO.js} +1 -1
- package/dist/public/assets/{MobileTopHeaderFrame-DH_D02Wy.js → MobileTopHeaderFrame-EoBm3-X0.js} +1 -1
- package/dist/public/assets/{MobileWorkspaceSwitcherHeader-2K406G5p.js → MobileWorkspaceSwitcherHeader-BC8MMQs_.js} +1 -1
- package/dist/public/assets/{PluginAccessOverview-BVJihw3D.js → PluginAccessOverview-CrQiQxxZ.js} +1 -1
- package/dist/public/assets/{PluginContainerPage-CR4vStvr.js → PluginContainerPage-_2u-9thM.js} +1 -1
- package/dist/public/assets/{PluginDetailPage-CrMX0Mnm.js → PluginDetailPage-F9cKjSCp.js} +1 -1
- package/dist/public/assets/{PluginsListPage-FtIL71Yg.js → PluginsListPage-BOhcua_4.js} +1 -1
- package/dist/public/assets/{RelayConnectEntryPage-Bt1apX53.js → RelayConnectEntryPage-Ck_uZLzj.js} +1 -1
- package/dist/public/assets/{ServerSettingsModal-D-guzPrI.js → ServerSettingsModal-ICd82a_x.js} +1 -1
- package/dist/public/assets/SessionIndexPage-Cox6P6dw.js +1 -0
- package/dist/public/assets/SettingsPage-BI5cM3j5.js +2 -0
- package/dist/public/assets/{TerminalManagerPanel-B5MKGPy-.js → TerminalManagerPanel-DiVhBQhf.js} +1 -1
- package/dist/public/assets/{TerminalPage-C2dTNGHK.js → TerminalPage-DUMUO7Ng.js} +1 -1
- package/dist/public/assets/{TerminalRuntimeFallbackModal-DAqOxFD8.js → TerminalRuntimeFallbackModal-DGPR_CMh.js} +1 -1
- package/dist/public/assets/{ToolFilesPage-IsNwyE6T.js → ToolFilesPage-m88CAp-r.js} +1 -1
- package/dist/public/assets/{ToolGitPage-BK1JBERN.js → ToolGitPage-DCYpfTsb.js} +1 -1
- package/dist/public/assets/{ToolProcessesPage-DwTYUQCK.js → ToolProcessesPage-Bk5ulsyq.js} +1 -1
- package/dist/public/assets/{ToolsHomePage-BLOy7lPg.js → ToolsHomePage-BrTwfjI7.js} +1 -1
- package/dist/public/assets/{WorkbenchLandingPage-CqZKR6EA.js → WorkbenchLandingPage-q4AAmdMV.js} +1 -1
- package/dist/public/assets/WorkbenchLayout-DD8b-m2G.js +1027 -0
- package/dist/public/assets/{WorkbenchModal-BM-OeW-b.js → WorkbenchModal-CsZeLArg.js} +1 -1
- package/dist/public/assets/WorkbenchShellRoute-BaiW_vfb.js +1 -0
- package/dist/public/assets/WorkbenchShellRoute-CxKYZ6uF.css +1 -0
- package/dist/public/assets/{WorkspaceDebugDetailPage-BMsEN5iG.js → WorkspaceDebugDetailPage-BcUUDEyw.js} +1 -1
- package/dist/public/assets/WorkspaceDetailPage-zEZ1VARA.js +1 -0
- package/dist/public/assets/{WorkspaceHomePage-DQiXKgiP.js → WorkspaceHomePage-CR0rqS4e.js} +1 -1
- package/dist/public/assets/{client-runtime-manager-CgPJq21V.js → client-runtime-manager-BgGugw8T.js} +1 -1
- package/dist/public/assets/index-CFyk1rgJ.js +50 -0
- package/dist/public/assets/index-CrU73EIV.css +1 -0
- package/dist/public/assets/{login-direct-candidate-resolver-CGaxAXV8.js → login-direct-candidate-resolver-ty2uOY5y.js} +1 -1
- package/dist/public/assets/{plugin-permission-copy-BR9gWy8b.js → plugin-permission-copy-iK3faI3n.js} +1 -1
- package/dist/public/assets/{plugins-api-CdCsrG2e.js → plugins-api-CmV7aDGA.js} +1 -1
- package/dist/public/assets/{preferences-service-lOhnlxzP.js → preferences-service-BoSmT_ny.js} +1 -1
- package/dist/public/assets/{relay-entry-CQpxTS8y.js → relay-entry-C8k5qsl5.js} +1 -1
- package/dist/public/assets/styles-BhKoKfQ_.css +1 -0
- package/dist/public/assets/{terminal-runtime-meta-oteTx66X.js → terminal-runtime-meta-okQIDzfA.js} +1 -1
- package/dist/public/assets/{useRegisteredDebugTemplates-Bu2ykZ6s.js → useRegisteredDebugTemplates-B_vXUtSe.js} +1 -1
- package/dist/public/assets/{workbench-navigation-DlgXuFW2.js → workbench-navigation-DoDaQR4z.js} +1 -1
- package/dist/public/index.html +2 -2
- package/dist/server/modules/affairs-indexer/core/src/repositories/catalog-repository.d.ts +1 -0
- package/dist/server/modules/affairs-indexer/core/src/repositories/catalog-repository.js +31 -0
- package/dist/server/modules/affairs-indexer/core/src/repositories/catalog-repository.js.map +1 -1
- package/dist/server/modules/affairs-indexer/core/src/services/dirty/dirty-scope-resolver.d.ts +1 -0
- package/dist/server/modules/affairs-indexer/core/src/services/dirty/dirty-scope-resolver.js +1 -0
- package/dist/server/modules/affairs-indexer/core/src/services/dirty/dirty-scope-resolver.js.map +1 -1
- package/dist/server/modules/affairs-indexer/core/src/services/export/export-builder.js +4 -1
- package/dist/server/modules/affairs-indexer/core/src/services/export/export-builder.js.map +1 -1
- package/dist/server/modules/affairs-indexer/core/src/services/search/search-index-builder.js +140 -16
- package/dist/server/modules/affairs-indexer/core/src/services/search/search-index-builder.js.map +1 -1
- package/dist/server/modules/assistant-capability/assistant-capability-controller.d.ts +1 -1
- package/dist/server/modules/assistant-capability/assistant-capability-controller.js +8 -7
- package/dist/server/modules/assistant-capability/assistant-capability-controller.js.map +1 -1
- package/dist/server/modules/assistant-capability/assistant-capability-service.d.ts +14 -13
- package/dist/server/modules/assistant-capability/assistant-capability-service.js +27 -24
- package/dist/server/modules/assistant-capability/assistant-capability-service.js.map +1 -1
- package/dist/server/modules/auth/auth-controller.d.ts +27 -1
- package/dist/server/modules/auth/auth-controller.js +20 -0
- package/dist/server/modules/auth/auth-controller.js.map +1 -1
- package/dist/server/modules/auth/auth-service.d.ts +32 -1
- package/dist/server/modules/auth/auth-service.js +217 -2
- package/dist/server/modules/auth/auth-service.js.map +1 -1
- package/dist/server/modules/bootstrap/bootstrap-service.js +1 -0
- package/dist/server/modules/bootstrap/bootstrap-service.js.map +1 -1
- package/dist/server/modules/butler/assistant-automation-service.d.ts +1 -1
- package/dist/server/modules/butler/assistant-automation-service.js +9 -10
- package/dist/server/modules/butler/assistant-automation-service.js.map +1 -1
- package/dist/server/modules/butler/butler-action-context-service.js +2 -2
- package/dist/server/modules/butler/butler-action-context-service.js.map +1 -1
- package/dist/server/modules/butler/butler-control-action-service.d.ts +5 -5
- package/dist/server/modules/butler/butler-control-action-service.js +19 -19
- package/dist/server/modules/butler/butler-control-action-service.js.map +1 -1
- package/dist/server/modules/butler/butler-control-session-service.d.ts +1 -1
- package/dist/server/modules/butler/butler-control-session-service.js +27 -26
- package/dist/server/modules/butler/butler-control-session-service.js.map +1 -1
- package/dist/server/modules/butler/butler-control-timer-service.js +4 -5
- package/dist/server/modules/butler/butler-control-timer-service.js.map +1 -1
- package/dist/server/modules/butler/butler-controller.d.ts +2 -2
- package/dist/server/modules/butler/butler-controller.js +19 -17
- package/dist/server/modules/butler/butler-controller.js.map +1 -1
- package/dist/server/modules/butler/butler-profile-service.d.ts +5 -5
- package/dist/server/modules/butler/butler-profile-service.js +17 -16
- package/dist/server/modules/butler/butler-profile-service.js.map +1 -1
- package/dist/server/modules/butler/butler-project-service.d.ts +7 -6
- package/dist/server/modules/butler/butler-project-service.js +35 -21
- package/dist/server/modules/butler/butler-project-service.js.map +1 -1
- package/dist/server/modules/butler/butler-session-service.d.ts +2 -2
- package/dist/server/modules/butler/butler-session-service.js +33 -27
- package/dist/server/modules/butler/butler-session-service.js.map +1 -1
- package/dist/server/modules/butler/butler-session-summary-service.d.ts +2 -2
- package/dist/server/modules/butler/butler-session-summary-service.js +23 -9
- package/dist/server/modules/butler/butler-session-summary-service.js.map +1 -1
- package/dist/server/modules/butler/context-aggregator.js +9 -9
- package/dist/server/modules/butler/context-aggregator.js.map +1 -1
- package/dist/server/modules/butler/patrol-execution-service.d.ts +0 -1
- package/dist/server/modules/butler/patrol-execution-service.js +6 -12
- package/dist/server/modules/butler/patrol-execution-service.js.map +1 -1
- package/dist/server/modules/provider/provider-discovery-runtime.js +16 -1
- package/dist/server/modules/provider/provider-discovery-runtime.js.map +1 -1
- package/dist/server/modules/sessions/codex-app-server-helper-client.js +14 -0
- package/dist/server/modules/sessions/codex-app-server-helper-client.js.map +1 -1
- package/dist/server/modules/sessions/codex-app-server-helper-process.js +59 -0
- package/dist/server/modules/sessions/codex-app-server-helper-process.js.map +1 -1
- package/dist/server/modules/sessions/codex-session-title-generator.d.ts +19 -0
- package/dist/server/modules/sessions/codex-session-title-generator.js +295 -0
- package/dist/server/modules/sessions/codex-session-title-generator.js.map +1 -0
- package/dist/server/modules/sessions/session-controller.js +3 -3
- package/dist/server/modules/sessions/session-controller.js.map +1 -1
- package/dist/server/modules/sessions/session-history-service.d.ts +13 -3
- package/dist/server/modules/sessions/session-history-service.js +309 -11
- package/dist/server/modules/sessions/session-history-service.js.map +1 -1
- package/dist/server/modules/sessions/session-live-runtime-service.js +25 -15
- package/dist/server/modules/sessions/session-live-runtime-service.js.map +1 -1
- package/dist/server/modules/sessions/session-permission-request-service.js +28 -15
- package/dist/server/modules/sessions/session-permission-request-service.js.map +1 -1
- package/dist/server/modules/tasks/task-types.d.ts +1 -0
- package/dist/server/modules/tasks/task-types.js +1 -0
- package/dist/server/modules/tasks/task-types.js.map +1 -1
- package/dist/server/modules/workbench/workbench-service.js +9 -9
- package/dist/server/modules/workbench/workbench-service.js.map +1 -1
- package/dist/server/modules/workspace/affairs-library-service.d.ts +3 -1
- package/dist/server/modules/workspace/affairs-library-service.js +112 -54
- package/dist/server/modules/workspace/affairs-library-service.js.map +1 -1
- package/dist/server/modules/workspace/affairs-lightweight-session-service.js +13 -9
- package/dist/server/modules/workspace/affairs-lightweight-session-service.js.map +1 -1
- package/dist/server/modules/workspace/affairs-tag-service.d.ts +12 -0
- package/dist/server/modules/workspace/affairs-tag-service.js +527 -2
- package/dist/server/modules/workspace/affairs-tag-service.js.map +1 -1
- package/dist/server/modules/workspace/workspace-controller.d.ts +1 -1
- package/dist/server/modules/workspace/workspace-controller.js +7 -7
- package/dist/server/modules/workspace/workspace-controller.js.map +1 -1
- package/dist/server/modules/workspace/workspace-service.d.ts +7 -0
- package/dist/server/modules/workspace/workspace-service.js +151 -10
- package/dist/server/modules/workspace/workspace-service.js.map +1 -1
- package/dist/server/routes/auth.js +6 -0
- package/dist/server/routes/auth.js.map +1 -1
- package/dist/server/server/create-server.d.ts +4 -0
- package/dist/server/server/create-server.js +26 -0
- package/dist/server/server/create-server.js.map +1 -1
- package/dist/server/server/start-host.js +20 -0
- package/dist/server/server/start-host.js.map +1 -1
- package/dist/server/shared/http/request-diagnostics.d.ts +56 -0
- package/dist/server/shared/http/request-diagnostics.js +256 -0
- package/dist/server/shared/http/request-diagnostics.js.map +1 -0
- package/dist/server/storage/repositories/auth-token-repository.d.ts +1 -0
- package/dist/server/storage/repositories/auth-token-repository.js +8 -0
- package/dist/server/storage/repositories/auth-token-repository.js.map +1 -1
- package/dist/server/storage/repositories/auth-user-repository.d.ts +50 -0
- package/dist/server/storage/repositories/auth-user-repository.js +198 -27
- package/dist/server/storage/repositories/auth-user-repository.js.map +1 -1
- package/dist/server/storage/repositories/butler-control-session-repository.d.ts +4 -1
- package/dist/server/storage/repositories/butler-control-session-repository.js +55 -8
- package/dist/server/storage/repositories/butler-control-session-repository.js.map +1 -1
- package/dist/server/storage/repositories/butler-profile-repository.d.ts +2 -1
- package/dist/server/storage/repositories/butler-profile-repository.js +35 -6
- package/dist/server/storage/repositories/butler-profile-repository.js.map +1 -1
- package/dist/server/storage/repositories/butler-project-repository.d.ts +2 -0
- package/dist/server/storage/repositories/butler-project-repository.js +38 -4
- package/dist/server/storage/repositories/butler-project-repository.js.map +1 -1
- package/dist/server/storage/repositories/butler-session-repository.d.ts +2 -1
- package/dist/server/storage/repositories/butler-session-repository.js +35 -6
- package/dist/server/storage/repositories/butler-session-repository.js.map +1 -1
- package/dist/server/storage/repositories/session-binding-repository.d.ts +3 -0
- package/dist/server/storage/repositories/session-binding-repository.js +70 -2
- package/dist/server/storage/repositories/session-binding-repository.js.map +1 -1
- package/dist/server/storage/repositories/session-index-repository.js +7 -5
- package/dist/server/storage/repositories/session-index-repository.js.map +1 -1
- package/dist/server/storage/repositories/workspace-repository.d.ts +3 -1
- package/dist/server/storage/repositories/workspace-repository.js +24 -10
- package/dist/server/storage/repositories/workspace-repository.js.map +1 -1
- package/dist/server/storage/sqlite/client.js +288 -0
- package/dist/server/storage/sqlite/client.js.map +1 -1
- package/dist/server/storage/sqlite/schema.sql +33 -9
- package/dist/server/types/domain.d.ts +8 -1
- package/node_modules/@codingns/session-sync-core/dist/providers/claude-session-store.js +34 -7
- package/node_modules/@codingns/session-sync-core/dist/providers/claude-session-store.js.map +1 -1
- package/node_modules/@codingns/session-sync-core/dist/providers/codex.d.ts +7 -0
- package/node_modules/@codingns/session-sync-core/dist/providers/codex.js +596 -6
- package/node_modules/@codingns/session-sync-core/dist/providers/codex.js.map +1 -1
- package/node_modules/@codingns/session-sync-core/dist/runtime/claude-runtime.js +3 -7
- package/node_modules/@codingns/session-sync-core/dist/runtime/claude-runtime.js.map +1 -1
- package/node_modules/@codingns/session-sync-core/dist/runtime/codex-runtime.d.ts +1 -0
- package/node_modules/@codingns/session-sync-core/dist/runtime/codex-runtime.js +249 -6
- package/node_modules/@codingns/session-sync-core/dist/runtime/codex-runtime.js.map +1 -1
- package/node_modules/@codingns/session-sync-core/dist/types.d.ts +11 -0
- package/package.json +1 -1
- package/dist/public/assets/SessionIndexPage-CX2FppcJ.js +0 -1
- package/dist/public/assets/SettingsPage-BI2Olcvr.js +0 -2
- package/dist/public/assets/WorkbenchLayout-CJHQtwuL.js +0 -1022
- package/dist/public/assets/WorkbenchShellRoute-2bKI6Q9k.js +0 -1
- package/dist/public/assets/WorkbenchShellRoute-BjuZD101.css +0 -1
- package/dist/public/assets/WorkspaceDetailPage-5H9Gosx2.js +0 -1
- package/dist/public/assets/index-BARqMVSw.css +0 -1
- package/dist/public/assets/index-BUoNjVrY.js +0 -50
- package/dist/public/assets/styles-DkbkRgWw.css +0 -1
- /package/dist/public/assets/{styles-JKFlsYFv.js → styles-DwSuZo1w.js} +0 -0
|
@@ -35,7 +35,7 @@ export class CodexAdapter {
|
|
|
35
35
|
const startedAt = Date.now();
|
|
36
36
|
const targetPath = normalizeWorkspacePath(workspacePath);
|
|
37
37
|
const knownSessions = (options?.knownSessions ?? []).filter((session) => session.provider === this.providerId);
|
|
38
|
-
const threadMetadataIndex = this.
|
|
38
|
+
const threadMetadataIndex = await this.readThreadMetadataIndexForWorkspace(targetPath);
|
|
39
39
|
const files = this.listSessionFiles(targetPath, threadMetadataIndex, knownSessions);
|
|
40
40
|
const knownByRawStoreRef = new Map(knownSessions.map((session) => [session.rawStoreRef, session]));
|
|
41
41
|
const knownByProviderSessionId = new Map(knownSessions.map((session) => [session.providerSessionId, session]));
|
|
@@ -239,6 +239,7 @@ export class CodexAdapter {
|
|
|
239
239
|
resolveCodexFallbackTitle(messages) ??
|
|
240
240
|
fileSessionId;
|
|
241
241
|
const lastMessageAt = messages.at(-1)?.timestamp ?? (ensureText(metaPayload.timestamp) || null);
|
|
242
|
+
const fileActivityObservation = resolveCodexJsonlActivityObservation(filterInheritedCodexSubagentRecords(records, codexSessionId));
|
|
242
243
|
const summary = this.hydrateSessionSummary({
|
|
243
244
|
provider: this.providerId,
|
|
244
245
|
providerSessionId: codexSessionId,
|
|
@@ -247,7 +248,8 @@ export class CodexAdapter {
|
|
|
247
248
|
rawStoreRef: filePath,
|
|
248
249
|
lastMessageAt,
|
|
249
250
|
messageCount: messages.length,
|
|
250
|
-
isArchived: false
|
|
251
|
+
isArchived: false,
|
|
252
|
+
activityObservation: fileActivityObservation
|
|
251
253
|
}, filePath, stats, currentThreadMetadata, currentSpawnRelation);
|
|
252
254
|
sessionsByProviderSessionId.set(codexSessionId, summary);
|
|
253
255
|
this.touchSessionSummaryCache(filePath, {
|
|
@@ -556,6 +558,19 @@ export class CodexAdapter {
|
|
|
556
558
|
}
|
|
557
559
|
async renameSessionTitle(providerSessionId, rawStoreRef, title) {
|
|
558
560
|
const nextTitle = title.trim();
|
|
561
|
+
const transport = this.options.threadControlTransportFactory?.();
|
|
562
|
+
if (transport) {
|
|
563
|
+
try {
|
|
564
|
+
await transport.initialize();
|
|
565
|
+
await transport.setThreadName?.(providerSessionId, nextTitle);
|
|
566
|
+
}
|
|
567
|
+
catch {
|
|
568
|
+
// app-server 的 thread/name/set 是首选,但失败时不能破坏原有本地改名能力。
|
|
569
|
+
}
|
|
570
|
+
finally {
|
|
571
|
+
transport.close();
|
|
572
|
+
}
|
|
573
|
+
}
|
|
559
574
|
const resolvedStoreRef = this.resolveSessionFilePath(rawStoreRef, providerSessionId);
|
|
560
575
|
const indexPath = join(this.options.homeDir, "session_index.jsonl");
|
|
561
576
|
const stateDbPath = findLatestCodexStateDatabase(this.options.homeDir);
|
|
@@ -794,11 +809,15 @@ export class CodexAdapter {
|
|
|
794
809
|
title: normalizeCodexIndexedTitle(ensureText(record.thread_name)) || null,
|
|
795
810
|
cwd: null,
|
|
796
811
|
createdAtMs: null,
|
|
812
|
+
updatedAtMs: null,
|
|
797
813
|
firstUserMessage: null,
|
|
798
814
|
agentNickname: null,
|
|
799
815
|
agentRole: null,
|
|
816
|
+
parentProviderSessionId: null,
|
|
817
|
+
parentRelationKind: null,
|
|
800
818
|
isArchived: null,
|
|
801
|
-
rolloutPath: null
|
|
819
|
+
rolloutPath: null,
|
|
820
|
+
activityObservation: null
|
|
802
821
|
});
|
|
803
822
|
}
|
|
804
823
|
catch {
|
|
@@ -844,15 +863,19 @@ export class CodexAdapter {
|
|
|
844
863
|
title: current?.title ?? dbTitle,
|
|
845
864
|
cwd: ensureText(row.cwd).trim() || (current?.cwd ?? null),
|
|
846
865
|
createdAtMs: Number.isFinite(createdAtSeconds) ? createdAtSeconds * 1000 : null,
|
|
866
|
+
updatedAtMs: current?.updatedAtMs ?? null,
|
|
847
867
|
firstUserMessage: ensureText(row.first_user_message).trim() || (current?.firstUserMessage ?? null),
|
|
848
868
|
agentNickname: ensureText(row.agent_nickname).trim() || (current?.agentNickname ?? null),
|
|
849
869
|
agentRole: ensureText(row.agent_role).trim() || (current?.agentRole ?? null),
|
|
870
|
+
parentProviderSessionId: current?.parentProviderSessionId ?? null,
|
|
871
|
+
parentRelationKind: current?.parentRelationKind ?? null,
|
|
850
872
|
rolloutPath: ensureText(row.rollout_path).trim() || (current?.rolloutPath ?? null),
|
|
851
873
|
isArchived: typeof row.archived === "number"
|
|
852
874
|
? row.archived === 1
|
|
853
875
|
: ensureText(row.rollout_path).includes("archived_sessions")
|
|
854
876
|
? true
|
|
855
|
-
: (current?.isArchived ?? null)
|
|
877
|
+
: (current?.isArchived ?? null),
|
|
878
|
+
activityObservation: current?.activityObservation ?? null
|
|
856
879
|
});
|
|
857
880
|
}
|
|
858
881
|
}
|
|
@@ -876,6 +899,91 @@ export class CodexAdapter {
|
|
|
876
899
|
};
|
|
877
900
|
return index;
|
|
878
901
|
}
|
|
902
|
+
async readThreadMetadataIndexForWorkspace(workspacePath) {
|
|
903
|
+
const index = new Map(this.readThreadMetadataIndex());
|
|
904
|
+
await this.mergeAppServerThreadMetadata(index, workspacePath);
|
|
905
|
+
return index;
|
|
906
|
+
}
|
|
907
|
+
async mergeAppServerThreadMetadata(index, workspacePath) {
|
|
908
|
+
const createTransport = this.options.threadControlTransportFactory;
|
|
909
|
+
if (!createTransport) {
|
|
910
|
+
return;
|
|
911
|
+
}
|
|
912
|
+
const transport = createTransport();
|
|
913
|
+
try {
|
|
914
|
+
await transport.initialize();
|
|
915
|
+
const threads = await transport.listThreads?.({ workspacePath });
|
|
916
|
+
if (!threads || threads.length === 0) {
|
|
917
|
+
return;
|
|
918
|
+
}
|
|
919
|
+
for (const thread of threads) {
|
|
920
|
+
const metadata = normalizeCodexAppServerThreadMetadata(thread);
|
|
921
|
+
if (!metadata) {
|
|
922
|
+
continue;
|
|
923
|
+
}
|
|
924
|
+
const current = index.get(metadata.threadId);
|
|
925
|
+
index.set(metadata.threadId, {
|
|
926
|
+
title: metadata.title ?? current?.title ?? null,
|
|
927
|
+
cwd: metadata.cwd ?? current?.cwd ?? null,
|
|
928
|
+
createdAtMs: metadata.createdAtMs ?? current?.createdAtMs ?? null,
|
|
929
|
+
updatedAtMs: metadata.updatedAtMs ?? current?.updatedAtMs ?? null,
|
|
930
|
+
firstUserMessage: metadata.firstUserMessage ?? current?.firstUserMessage ?? null,
|
|
931
|
+
agentNickname: metadata.agentNickname ?? current?.agentNickname ?? null,
|
|
932
|
+
agentRole: metadata.agentRole ?? current?.agentRole ?? null,
|
|
933
|
+
parentProviderSessionId: metadata.parentProviderSessionId ?? current?.parentProviderSessionId ?? null,
|
|
934
|
+
parentRelationKind: metadata.parentRelationKind ?? current?.parentRelationKind ?? null,
|
|
935
|
+
isArchived: metadata.isArchived ?? current?.isArchived ?? null,
|
|
936
|
+
rolloutPath: metadata.rolloutPath ?? current?.rolloutPath ?? null,
|
|
937
|
+
activityObservation: metadata.activityObservation ?? current?.activityObservation ?? null
|
|
938
|
+
});
|
|
939
|
+
}
|
|
940
|
+
await this.mergeAppServerSubagentActivityFromParentThreads(index, threads, transport);
|
|
941
|
+
}
|
|
942
|
+
catch {
|
|
943
|
+
// app-server 是增强信息来源,失败时退回 JSONL/state DB,不能拖垮会话列表。
|
|
944
|
+
}
|
|
945
|
+
finally {
|
|
946
|
+
transport.close();
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
async mergeAppServerSubagentActivityFromParentThreads(index, threads, transport) {
|
|
950
|
+
const childrenByParentThreadId = new Map();
|
|
951
|
+
for (const thread of threads) {
|
|
952
|
+
const metadata = normalizeCodexAppServerThreadMetadata(thread);
|
|
953
|
+
if (!metadata
|
|
954
|
+
|| metadata.parentRelationKind !== "spawn"
|
|
955
|
+
|| !metadata.parentProviderSessionId) {
|
|
956
|
+
continue;
|
|
957
|
+
}
|
|
958
|
+
const children = childrenByParentThreadId.get(metadata.parentProviderSessionId) ?? [];
|
|
959
|
+
children.push(metadata.threadId);
|
|
960
|
+
childrenByParentThreadId.set(metadata.parentProviderSessionId, children);
|
|
961
|
+
}
|
|
962
|
+
for (const [parentThreadId, childThreadIds] of childrenByParentThreadId) {
|
|
963
|
+
let parentThread = null;
|
|
964
|
+
try {
|
|
965
|
+
const result = await transport.readThread(parentThreadId);
|
|
966
|
+
parentThread = asCodexRecord(result.thread) ?? result;
|
|
967
|
+
}
|
|
968
|
+
catch {
|
|
969
|
+
continue;
|
|
970
|
+
}
|
|
971
|
+
for (const childThreadId of childThreadIds) {
|
|
972
|
+
const observation = resolveLatestCodexCollabAgentActivityObservation(parentThread, childThreadId);
|
|
973
|
+
if (!observation) {
|
|
974
|
+
continue;
|
|
975
|
+
}
|
|
976
|
+
const current = index.get(childThreadId);
|
|
977
|
+
if (!current) {
|
|
978
|
+
continue;
|
|
979
|
+
}
|
|
980
|
+
index.set(childThreadId, {
|
|
981
|
+
...current,
|
|
982
|
+
activityObservation: observation
|
|
983
|
+
});
|
|
984
|
+
}
|
|
985
|
+
}
|
|
986
|
+
}
|
|
879
987
|
listSessionFiles(targetPath, threadMetadataIndex, knownSessions) {
|
|
880
988
|
const activeFiles = walkJsonlFiles(join(this.options.homeDir, "sessions"));
|
|
881
989
|
const archivedFiles = this.listArchivedSessionFiles(targetPath, threadMetadataIndex, knownSessions);
|
|
@@ -1151,12 +1259,20 @@ export class CodexAdapter {
|
|
|
1151
1259
|
const indexedTitle = normalizeCodexIndexedTitle(metadata?.title);
|
|
1152
1260
|
const normalizedFirstUserMessage = normalizeCodexIndexedTitle(metadata?.firstUserMessage);
|
|
1153
1261
|
if (indexedTitle) {
|
|
1262
|
+
if (isCodexSubagentThread(metadata, null)
|
|
1263
|
+
&& normalizedFirstUserMessage
|
|
1264
|
+
&& indexedTitle === normalizedFirstUserMessage) {
|
|
1265
|
+
return null;
|
|
1266
|
+
}
|
|
1154
1267
|
// Codex 有时会把第一条用户消息原样回填成 title,这种脏标题仍然按统一长度预算裁掉。
|
|
1155
1268
|
if (normalizedFirstUserMessage && indexedTitle === normalizedFirstUserMessage) {
|
|
1156
1269
|
return indexedTitle.slice(0, CODEX_SESSION_TITLE_MAX_LENGTH);
|
|
1157
1270
|
}
|
|
1158
1271
|
return indexedTitle;
|
|
1159
1272
|
}
|
|
1273
|
+
if (isCodexSubagentThread(metadata, null)) {
|
|
1274
|
+
return null;
|
|
1275
|
+
}
|
|
1160
1276
|
return normalizeCodexMessageTitle(metadata?.firstUserMessage);
|
|
1161
1277
|
}
|
|
1162
1278
|
readSpawnedAgentRelationIndex(files, targetPath, threadMetadataIndex, candidateThreadIds) {
|
|
@@ -1283,6 +1399,13 @@ export class CodexAdapter {
|
|
|
1283
1399
|
if (directRelations.has(threadId)) {
|
|
1284
1400
|
continue;
|
|
1285
1401
|
}
|
|
1402
|
+
if (metadata.parentProviderSessionId) {
|
|
1403
|
+
directRelations.set(threadId, {
|
|
1404
|
+
parentProviderSessionId: metadata.parentProviderSessionId,
|
|
1405
|
+
kind: metadata.parentRelationKind ?? "spawn"
|
|
1406
|
+
});
|
|
1407
|
+
continue;
|
|
1408
|
+
}
|
|
1286
1409
|
if (!metadata.agentRole && !metadata.agentNickname) {
|
|
1287
1410
|
continue;
|
|
1288
1411
|
}
|
|
@@ -1331,11 +1454,13 @@ export class CodexAdapter {
|
|
|
1331
1454
|
hydrateSessionSummary(summary, filePath, stats, metadata, relation) {
|
|
1332
1455
|
const resolvedRelation = relation ?? null;
|
|
1333
1456
|
const resolvedMetadata = metadata ?? null;
|
|
1457
|
+
const metadataTitle = resolveCodexMetadataTitle(resolvedMetadata);
|
|
1334
1458
|
const isSubagent = resolvedMetadata || resolvedRelation
|
|
1335
1459
|
? isCodexSubagentThread(resolvedMetadata, resolvedRelation)
|
|
1336
1460
|
: Boolean(summary.isSubagent);
|
|
1337
1461
|
return {
|
|
1338
1462
|
...summary,
|
|
1463
|
+
title: metadataTitle ?? summary.title,
|
|
1339
1464
|
rawStoreRef: filePath,
|
|
1340
1465
|
isArchived: resolveCodexArchivedState(resolvedMetadata, filePath),
|
|
1341
1466
|
parentProviderSessionId: resolvedRelation?.parentProviderSessionId ?? summary.parentProviderSessionId ?? null,
|
|
@@ -1344,14 +1469,15 @@ export class CodexAdapter {
|
|
|
1344
1469
|
? buildCodexSubagentLabel(resolvedMetadata)
|
|
1345
1470
|
: summary.subagentLabel ?? null,
|
|
1346
1471
|
sourceMtimeMs: stats.mtimeMs,
|
|
1347
|
-
sourceSizeBytes: stats.size
|
|
1472
|
+
sourceSizeBytes: stats.size,
|
|
1473
|
+
activityObservation: mergeCodexActivityObservation(resolvedMetadata?.activityObservation ?? null, summary.activityObservation ?? null)
|
|
1348
1474
|
};
|
|
1349
1475
|
}
|
|
1350
1476
|
parseMessages(filePath, records, providerSessionId) {
|
|
1351
1477
|
return this.parseMessagesFromEntries(filePath, records, providerSessionId);
|
|
1352
1478
|
}
|
|
1353
1479
|
parseMessagesFromEntries(filePath, records, providerSessionId) {
|
|
1354
|
-
const effectiveRecords = filterRolledBackCodexRecords(records);
|
|
1480
|
+
const effectiveRecords = filterRolledBackCodexRecords(filterInheritedCodexSubagentRecords(records, providerSessionId));
|
|
1355
1481
|
const messages = [];
|
|
1356
1482
|
const messageIndexesByKey = new Map();
|
|
1357
1483
|
const toolNameById = new Map();
|
|
@@ -1699,6 +1825,105 @@ function filterRolledBackCodexRecords(records) {
|
|
|
1699
1825
|
}
|
|
1700
1826
|
return filteredRecords;
|
|
1701
1827
|
}
|
|
1828
|
+
function filterInheritedCodexSubagentRecords(records, providerSessionId) {
|
|
1829
|
+
const boundary = resolveCodexSessionInheritanceBoundary(records, providerSessionId);
|
|
1830
|
+
if (!boundary.inheritedParentThreadId || boundary.startLineNumber === null) {
|
|
1831
|
+
return records;
|
|
1832
|
+
}
|
|
1833
|
+
const startLineNumber = boundary.startLineNumber;
|
|
1834
|
+
return records.filter((record) => {
|
|
1835
|
+
if (record.lineNumber < startLineNumber) {
|
|
1836
|
+
return shouldKeepCodexRecordBeforeSubagentBoundary(record, boundary.threadId);
|
|
1837
|
+
}
|
|
1838
|
+
return true;
|
|
1839
|
+
});
|
|
1840
|
+
}
|
|
1841
|
+
function resolveCodexSessionInheritanceBoundary(records, providerSessionId) {
|
|
1842
|
+
const fallbackThreadId = ensureText(providerSessionId).trim();
|
|
1843
|
+
let currentThreadId = fallbackThreadId;
|
|
1844
|
+
let inheritedParentThreadId = null;
|
|
1845
|
+
let startLineNumber = null;
|
|
1846
|
+
for (const record of records) {
|
|
1847
|
+
if (record.data.type !== "session_meta") {
|
|
1848
|
+
continue;
|
|
1849
|
+
}
|
|
1850
|
+
const payload = (record.data.payload ?? {});
|
|
1851
|
+
const metaId = ensureText(payload.id).trim();
|
|
1852
|
+
const threadId = looksLikeCodexThreadId(metaId) ? metaId : fallbackThreadId || metaId;
|
|
1853
|
+
const parentRelation = resolveCodexParentThreadRelation(payload);
|
|
1854
|
+
const isSubagent = parentRelation.kind === "spawn"
|
|
1855
|
+
|| ensureText(payload.thread_source).trim() === "subagent"
|
|
1856
|
+
|| ensureText(payload.agent_nickname).trim().length > 0
|
|
1857
|
+
|| ensureText(payload.agent_role).trim().length > 0;
|
|
1858
|
+
if (isSubagent
|
|
1859
|
+
&& parentRelation.parentThreadId
|
|
1860
|
+
&& (!fallbackThreadId || threadId === fallbackThreadId)) {
|
|
1861
|
+
currentThreadId = threadId;
|
|
1862
|
+
inheritedParentThreadId = parentRelation.parentThreadId;
|
|
1863
|
+
continue;
|
|
1864
|
+
}
|
|
1865
|
+
if (inheritedParentThreadId && threadId === inheritedParentThreadId) {
|
|
1866
|
+
continue;
|
|
1867
|
+
}
|
|
1868
|
+
if (inheritedParentThreadId && threadId === currentThreadId && startLineNumber === null) {
|
|
1869
|
+
startLineNumber = record.lineNumber;
|
|
1870
|
+
}
|
|
1871
|
+
}
|
|
1872
|
+
if (inheritedParentThreadId && startLineNumber === null) {
|
|
1873
|
+
startLineNumber = findFirstOwnCodexSubagentTurnLineNumber(records, currentThreadId, inheritedParentThreadId);
|
|
1874
|
+
}
|
|
1875
|
+
return {
|
|
1876
|
+
threadId: currentThreadId,
|
|
1877
|
+
inheritedParentThreadId,
|
|
1878
|
+
startLineNumber
|
|
1879
|
+
};
|
|
1880
|
+
}
|
|
1881
|
+
function findFirstOwnCodexSubagentTurnLineNumber(records, threadId, inheritedParentThreadId) {
|
|
1882
|
+
for (const record of records) {
|
|
1883
|
+
if (record.data.type === "turn_context") {
|
|
1884
|
+
const payload = (record.data.payload ?? {});
|
|
1885
|
+
const turnId = ensureText(payload.turn_id).trim();
|
|
1886
|
+
if (isCodexOwnTurnId(turnId, threadId, inheritedParentThreadId)) {
|
|
1887
|
+
return record.lineNumber;
|
|
1888
|
+
}
|
|
1889
|
+
continue;
|
|
1890
|
+
}
|
|
1891
|
+
if (record.data.type !== "event_msg") {
|
|
1892
|
+
continue;
|
|
1893
|
+
}
|
|
1894
|
+
const payload = (record.data.payload ?? {});
|
|
1895
|
+
const eventType = ensureText(payload.type).trim();
|
|
1896
|
+
const turnId = ensureText(payload.turn_id).trim();
|
|
1897
|
+
if (eventType === "task_started"
|
|
1898
|
+
&& turnId.length > 0
|
|
1899
|
+
&& isCodexOwnTurnId(turnId, threadId, inheritedParentThreadId)) {
|
|
1900
|
+
return record.lineNumber;
|
|
1901
|
+
}
|
|
1902
|
+
}
|
|
1903
|
+
return null;
|
|
1904
|
+
}
|
|
1905
|
+
function isCodexOwnTurnId(turnId, threadId, inheritedParentThreadId) {
|
|
1906
|
+
if (!looksLikeCodexThreadId(turnId)) {
|
|
1907
|
+
return false;
|
|
1908
|
+
}
|
|
1909
|
+
if (turnId === inheritedParentThreadId) {
|
|
1910
|
+
return false;
|
|
1911
|
+
}
|
|
1912
|
+
if (looksLikeCodexThreadId(threadId)) {
|
|
1913
|
+
// Codex 的 thread id / turn id 都是 UUIDv7。子 Agent 自己的 turn 会在子 thread 创建之后;
|
|
1914
|
+
// fork 继承来的父会话 turn 一定早于子 thread。这里用时间有序 ID 切掉继承前缀。
|
|
1915
|
+
return turnId.localeCompare(threadId) >= 0;
|
|
1916
|
+
}
|
|
1917
|
+
return !turnId.startsWith(inheritedParentThreadId.slice(0, 8));
|
|
1918
|
+
}
|
|
1919
|
+
function shouldKeepCodexRecordBeforeSubagentBoundary(record, threadId) {
|
|
1920
|
+
if (record.data.type !== "session_meta") {
|
|
1921
|
+
return false;
|
|
1922
|
+
}
|
|
1923
|
+
const payload = (record.data.payload ?? {});
|
|
1924
|
+
const metaId = ensureText(payload.id).trim();
|
|
1925
|
+
return metaId === threadId;
|
|
1926
|
+
}
|
|
1702
1927
|
function buildRecentHistoryPage(messages, totalMessageCount, limit) {
|
|
1703
1928
|
const effectiveTotal = Math.max(totalMessageCount, messages.length);
|
|
1704
1929
|
const pageMessages = messages.slice(-Math.min(limit, messages.length)).map((message, index, items) => ({
|
|
@@ -1952,6 +2177,13 @@ function readNonNegativeInteger(value) {
|
|
|
1952
2177
|
}
|
|
1953
2178
|
return null;
|
|
1954
2179
|
}
|
|
2180
|
+
function readFiniteNumber(value) {
|
|
2181
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
2182
|
+
return value;
|
|
2183
|
+
}
|
|
2184
|
+
const parsed = Number.parseFloat(ensureText(value));
|
|
2185
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
2186
|
+
}
|
|
1955
2187
|
function clampUsageRatio(promptTokens, contextWindow) {
|
|
1956
2188
|
if (contextWindow <= 0) {
|
|
1957
2189
|
return 0;
|
|
@@ -2019,6 +2251,353 @@ function resolveCodexParentThreadRelation(payload) {
|
|
|
2019
2251
|
kind: null
|
|
2020
2252
|
};
|
|
2021
2253
|
}
|
|
2254
|
+
function normalizeCodexAppServerThreadMetadata(thread) {
|
|
2255
|
+
const threadId = ensureText(thread.id).trim();
|
|
2256
|
+
if (!looksLikeCodexThreadId(threadId)) {
|
|
2257
|
+
return null;
|
|
2258
|
+
}
|
|
2259
|
+
const source = thread.source;
|
|
2260
|
+
const sourceRecord = typeof source === "object" && source !== null
|
|
2261
|
+
? source
|
|
2262
|
+
: null;
|
|
2263
|
+
const subAgentSource = typeof sourceRecord?.subAgent === "object" && sourceRecord.subAgent !== null
|
|
2264
|
+
? sourceRecord.subAgent
|
|
2265
|
+
: typeof sourceRecord?.subagent === "object" && sourceRecord.subagent !== null
|
|
2266
|
+
? sourceRecord.subagent
|
|
2267
|
+
: null;
|
|
2268
|
+
const threadSpawn = typeof subAgentSource?.thread_spawn === "object" && subAgentSource.thread_spawn !== null
|
|
2269
|
+
? subAgentSource.thread_spawn
|
|
2270
|
+
: typeof subAgentSource?.threadSpawn === "object" && subAgentSource.threadSpawn !== null
|
|
2271
|
+
? subAgentSource.threadSpawn
|
|
2272
|
+
: null;
|
|
2273
|
+
const spawnParentThreadId = ensureText(threadSpawn?.parent_thread_id).trim()
|
|
2274
|
+
|| ensureText(threadSpawn?.parentThreadId).trim();
|
|
2275
|
+
const forkedFromId = ensureText(thread.forkedFromId ?? thread.forked_from_id).trim();
|
|
2276
|
+
const parentProviderSessionId = spawnParentThreadId || forkedFromId || null;
|
|
2277
|
+
const agentNickname = ensureText(thread.agentNickname ?? thread.agent_nickname).trim()
|
|
2278
|
+
|| ensureText(threadSpawn?.agent_nickname ?? threadSpawn?.agentNickname).trim()
|
|
2279
|
+
|| null;
|
|
2280
|
+
const agentRole = ensureText(thread.agentRole ?? thread.agent_role).trim()
|
|
2281
|
+
|| ensureText(threadSpawn?.agent_role ?? threadSpawn?.agentRole).trim()
|
|
2282
|
+
|| null;
|
|
2283
|
+
const createdAtSeconds = readFiniteNumber(thread.createdAt ?? thread.created_at);
|
|
2284
|
+
const updatedAtSeconds = readFiniteNumber(thread.updatedAt ?? thread.updated_at);
|
|
2285
|
+
const preview = ensureText(thread.preview).trim();
|
|
2286
|
+
const name = normalizeCodexIndexedTitle(ensureText(thread.name));
|
|
2287
|
+
const path = ensureText(thread.path).trim();
|
|
2288
|
+
const cwd = ensureText(thread.cwd).trim();
|
|
2289
|
+
const activityObservation = resolveCodexThreadActivityObservation(thread);
|
|
2290
|
+
return {
|
|
2291
|
+
threadId,
|
|
2292
|
+
title: name || null,
|
|
2293
|
+
cwd: cwd || null,
|
|
2294
|
+
createdAtMs: createdAtSeconds !== null ? createdAtSeconds * 1000 : null,
|
|
2295
|
+
updatedAtMs: updatedAtSeconds !== null ? updatedAtSeconds * 1000 : null,
|
|
2296
|
+
firstUserMessage: preview || null,
|
|
2297
|
+
agentNickname,
|
|
2298
|
+
agentRole,
|
|
2299
|
+
parentProviderSessionId,
|
|
2300
|
+
parentRelationKind: spawnParentThreadId.length > 0
|
|
2301
|
+
? "spawn"
|
|
2302
|
+
: forkedFromId.length > 0
|
|
2303
|
+
? "fork"
|
|
2304
|
+
: null,
|
|
2305
|
+
isArchived: null,
|
|
2306
|
+
rolloutPath: path || null,
|
|
2307
|
+
activityObservation
|
|
2308
|
+
};
|
|
2309
|
+
}
|
|
2310
|
+
function resolveCodexThreadActivityObservation(thread) {
|
|
2311
|
+
const direct = resolveCodexThreadStatusActivityObservation(thread);
|
|
2312
|
+
const threadId = ensureText(thread.id).trim();
|
|
2313
|
+
const parent = resolveLatestCodexCollabAgentActivityObservation(thread, threadId);
|
|
2314
|
+
if (!direct) {
|
|
2315
|
+
return parent;
|
|
2316
|
+
}
|
|
2317
|
+
if (!parent) {
|
|
2318
|
+
return direct;
|
|
2319
|
+
}
|
|
2320
|
+
if (isTerminalProviderSessionObservation(parent)
|
|
2321
|
+
&& (direct.runningState === "starting" || direct.runningState === "running")) {
|
|
2322
|
+
return parent;
|
|
2323
|
+
}
|
|
2324
|
+
const directAt = direct.observedAt ?? "";
|
|
2325
|
+
const parentAt = parent.observedAt ?? "";
|
|
2326
|
+
if (parentAt && (!directAt || parentAt.localeCompare(directAt) >= 0)) {
|
|
2327
|
+
return parent;
|
|
2328
|
+
}
|
|
2329
|
+
return direct;
|
|
2330
|
+
}
|
|
2331
|
+
function resolveCodexJsonlActivityObservation(records) {
|
|
2332
|
+
let latest = null;
|
|
2333
|
+
for (const record of records) {
|
|
2334
|
+
if (record.data.type !== "event_msg") {
|
|
2335
|
+
continue;
|
|
2336
|
+
}
|
|
2337
|
+
const payload = (record.data.payload ?? {});
|
|
2338
|
+
const eventType = ensureText(payload.type).trim();
|
|
2339
|
+
const turnId = ensureText(payload.turn_id).trim() || null;
|
|
2340
|
+
const observedAt = (codexSecondsToIso(payload.completed_at ?? payload.completedAt)
|
|
2341
|
+
?? codexSecondsToIso(payload.started_at ?? payload.startedAt)
|
|
2342
|
+
?? ensureText(record.data.timestamp).trim())
|
|
2343
|
+
|| null;
|
|
2344
|
+
let observation = null;
|
|
2345
|
+
if (eventType === "task_started") {
|
|
2346
|
+
observation = {
|
|
2347
|
+
runningState: "running",
|
|
2348
|
+
confidence: "strong",
|
|
2349
|
+
observedAt,
|
|
2350
|
+
detail: null,
|
|
2351
|
+
errorCode: null,
|
|
2352
|
+
runId: turnId
|
|
2353
|
+
};
|
|
2354
|
+
}
|
|
2355
|
+
else if (eventType === "task_complete") {
|
|
2356
|
+
observation = {
|
|
2357
|
+
runningState: "completed",
|
|
2358
|
+
confidence: "strong",
|
|
2359
|
+
observedAt,
|
|
2360
|
+
detail: null,
|
|
2361
|
+
errorCode: null,
|
|
2362
|
+
runId: turnId
|
|
2363
|
+
};
|
|
2364
|
+
}
|
|
2365
|
+
else if (eventType === "task_failed") {
|
|
2366
|
+
observation = {
|
|
2367
|
+
runningState: "failed",
|
|
2368
|
+
confidence: "strong",
|
|
2369
|
+
observedAt,
|
|
2370
|
+
detail: ensureText(payload.error).trim()
|
|
2371
|
+
|| ensureText(payload.message).trim()
|
|
2372
|
+
|| "Codex task failed",
|
|
2373
|
+
errorCode: "CODEX_TASK_FAILED",
|
|
2374
|
+
runId: turnId
|
|
2375
|
+
};
|
|
2376
|
+
}
|
|
2377
|
+
if (!observation) {
|
|
2378
|
+
continue;
|
|
2379
|
+
}
|
|
2380
|
+
if (!latest || compareNullableIso(observation.observedAt, latest.observedAt) >= 0) {
|
|
2381
|
+
latest = observation;
|
|
2382
|
+
}
|
|
2383
|
+
}
|
|
2384
|
+
return latest;
|
|
2385
|
+
}
|
|
2386
|
+
function mergeCodexActivityObservation(primary, fallback) {
|
|
2387
|
+
if (!primary) {
|
|
2388
|
+
return fallback;
|
|
2389
|
+
}
|
|
2390
|
+
if (!fallback) {
|
|
2391
|
+
return primary;
|
|
2392
|
+
}
|
|
2393
|
+
if (isTerminalProviderSessionObservation(primary)) {
|
|
2394
|
+
return primary;
|
|
2395
|
+
}
|
|
2396
|
+
if (isTerminalProviderSessionObservation(fallback)) {
|
|
2397
|
+
return fallback;
|
|
2398
|
+
}
|
|
2399
|
+
if (primary.runningState === "starting" || primary.runningState === "running") {
|
|
2400
|
+
return primary;
|
|
2401
|
+
}
|
|
2402
|
+
if (fallback.runningState === "starting" || fallback.runningState === "running") {
|
|
2403
|
+
return fallback;
|
|
2404
|
+
}
|
|
2405
|
+
const primaryAt = primary.observedAt ?? "";
|
|
2406
|
+
const fallbackAt = fallback.observedAt ?? "";
|
|
2407
|
+
return fallbackAt && (!primaryAt || fallbackAt.localeCompare(primaryAt) > 0)
|
|
2408
|
+
? fallback
|
|
2409
|
+
: primary;
|
|
2410
|
+
}
|
|
2411
|
+
function isTerminalProviderSessionObservation(observation) {
|
|
2412
|
+
return observation.runningState === "completed"
|
|
2413
|
+
|| observation.runningState === "interrupted"
|
|
2414
|
+
|| observation.runningState === "failed";
|
|
2415
|
+
}
|
|
2416
|
+
function resolveCodexThreadStatusActivityObservation(thread) {
|
|
2417
|
+
const status = asCodexRecord(thread.status);
|
|
2418
|
+
const statusType = ensureText(status?.type).trim();
|
|
2419
|
+
const observedAt = codexSecondsToIso(thread.updatedAt ?? thread.updated_at);
|
|
2420
|
+
if (statusType === "active") {
|
|
2421
|
+
return {
|
|
2422
|
+
runningState: "running",
|
|
2423
|
+
confidence: "authoritative",
|
|
2424
|
+
observedAt,
|
|
2425
|
+
detail: null,
|
|
2426
|
+
errorCode: null,
|
|
2427
|
+
runId: null
|
|
2428
|
+
};
|
|
2429
|
+
}
|
|
2430
|
+
if (statusType === "idle" || statusType === "notLoaded") {
|
|
2431
|
+
return {
|
|
2432
|
+
runningState: "idle",
|
|
2433
|
+
confidence: "strong",
|
|
2434
|
+
observedAt,
|
|
2435
|
+
detail: null,
|
|
2436
|
+
errorCode: null,
|
|
2437
|
+
runId: null
|
|
2438
|
+
};
|
|
2439
|
+
}
|
|
2440
|
+
if (statusType === "systemError") {
|
|
2441
|
+
return {
|
|
2442
|
+
runningState: "failed",
|
|
2443
|
+
confidence: "strong",
|
|
2444
|
+
observedAt,
|
|
2445
|
+
detail: "Codex app-server reported a system error",
|
|
2446
|
+
errorCode: "CODEX_APP_SERVER_SYSTEM_ERROR",
|
|
2447
|
+
runId: null
|
|
2448
|
+
};
|
|
2449
|
+
}
|
|
2450
|
+
return null;
|
|
2451
|
+
}
|
|
2452
|
+
function resolveLatestCodexCollabAgentActivityObservation(thread, threadId) {
|
|
2453
|
+
if (!threadId) {
|
|
2454
|
+
return null;
|
|
2455
|
+
}
|
|
2456
|
+
let latest = null;
|
|
2457
|
+
for (const turn of collectCodexThreadTurns(thread)) {
|
|
2458
|
+
const turnRecord = asCodexRecord(turn);
|
|
2459
|
+
const observedAt = codexSecondsToIso(turnRecord?.completedAt ?? turnRecord?.completed_at)
|
|
2460
|
+
?? codexSecondsToIso(turnRecord?.startedAt ?? turnRecord?.started_at)
|
|
2461
|
+
?? codexSecondsToIso(thread.updatedAt ?? thread.updated_at);
|
|
2462
|
+
const runId = ensureText(turnRecord?.id).trim() || null;
|
|
2463
|
+
const items = Array.isArray(turnRecord?.items) ? turnRecord.items : [];
|
|
2464
|
+
for (const item of items) {
|
|
2465
|
+
const itemRecord = asCodexRecord(item);
|
|
2466
|
+
if (!itemRecord || ensureText(itemRecord.type).trim() !== "collabAgentToolCall") {
|
|
2467
|
+
continue;
|
|
2468
|
+
}
|
|
2469
|
+
const receivers = Array.isArray(itemRecord.receiverThreadIds)
|
|
2470
|
+
? itemRecord.receiverThreadIds.map((value) => ensureText(value).trim())
|
|
2471
|
+
: [];
|
|
2472
|
+
if (!receivers.includes(threadId)) {
|
|
2473
|
+
continue;
|
|
2474
|
+
}
|
|
2475
|
+
const agentsStates = asCodexRecord(itemRecord.agentsStates);
|
|
2476
|
+
const agentState = asCodexRecord(agentsStates?.[threadId]);
|
|
2477
|
+
const agentStatus = ensureText(agentState?.status).trim();
|
|
2478
|
+
const observation = mapCodexCollabAgentStatusToActivityObservation({
|
|
2479
|
+
status: agentStatus,
|
|
2480
|
+
message: ensureText(agentState?.message).trim() || null,
|
|
2481
|
+
tool: ensureText(itemRecord.tool).trim(),
|
|
2482
|
+
callStatus: ensureText(itemRecord.status).trim(),
|
|
2483
|
+
observedAt,
|
|
2484
|
+
runId
|
|
2485
|
+
});
|
|
2486
|
+
if (!observation) {
|
|
2487
|
+
continue;
|
|
2488
|
+
}
|
|
2489
|
+
if (!latest || compareNullableIso(observation.observedAt, latest.observedAt) >= 0) {
|
|
2490
|
+
latest = observation;
|
|
2491
|
+
}
|
|
2492
|
+
}
|
|
2493
|
+
}
|
|
2494
|
+
return latest;
|
|
2495
|
+
}
|
|
2496
|
+
function mapCodexCollabAgentStatusToActivityObservation(input) {
|
|
2497
|
+
const terminalDetail = input.message ?? null;
|
|
2498
|
+
switch (input.status) {
|
|
2499
|
+
case "pendingInit":
|
|
2500
|
+
return {
|
|
2501
|
+
runningState: "starting",
|
|
2502
|
+
confidence: "authoritative",
|
|
2503
|
+
observedAt: input.observedAt,
|
|
2504
|
+
detail: input.tool ? `Codex sub-agent ${input.tool} is pending` : null,
|
|
2505
|
+
errorCode: null,
|
|
2506
|
+
runId: input.runId
|
|
2507
|
+
};
|
|
2508
|
+
case "running":
|
|
2509
|
+
return {
|
|
2510
|
+
runningState: "running",
|
|
2511
|
+
confidence: "authoritative",
|
|
2512
|
+
observedAt: input.observedAt,
|
|
2513
|
+
detail: null,
|
|
2514
|
+
errorCode: null,
|
|
2515
|
+
runId: input.runId
|
|
2516
|
+
};
|
|
2517
|
+
case "completed":
|
|
2518
|
+
return {
|
|
2519
|
+
runningState: "completed",
|
|
2520
|
+
confidence: "strong",
|
|
2521
|
+
observedAt: input.observedAt,
|
|
2522
|
+
detail: terminalDetail,
|
|
2523
|
+
errorCode: null,
|
|
2524
|
+
runId: input.runId
|
|
2525
|
+
};
|
|
2526
|
+
case "interrupted":
|
|
2527
|
+
return {
|
|
2528
|
+
runningState: "interrupted",
|
|
2529
|
+
confidence: "strong",
|
|
2530
|
+
observedAt: input.observedAt,
|
|
2531
|
+
detail: terminalDetail,
|
|
2532
|
+
errorCode: null,
|
|
2533
|
+
runId: input.runId
|
|
2534
|
+
};
|
|
2535
|
+
case "errored":
|
|
2536
|
+
return {
|
|
2537
|
+
runningState: "failed",
|
|
2538
|
+
confidence: "strong",
|
|
2539
|
+
observedAt: input.observedAt,
|
|
2540
|
+
detail: terminalDetail ?? "Codex sub-agent failed",
|
|
2541
|
+
errorCode: "CODEX_SUBAGENT_FAILED",
|
|
2542
|
+
runId: input.runId
|
|
2543
|
+
};
|
|
2544
|
+
case "shutdown":
|
|
2545
|
+
case "notFound":
|
|
2546
|
+
return {
|
|
2547
|
+
runningState: "completed",
|
|
2548
|
+
confidence: "strong",
|
|
2549
|
+
observedAt: input.observedAt,
|
|
2550
|
+
detail: terminalDetail,
|
|
2551
|
+
errorCode: null,
|
|
2552
|
+
runId: input.runId
|
|
2553
|
+
};
|
|
2554
|
+
default:
|
|
2555
|
+
if (input.tool === "closeAgent" && input.callStatus === "completed") {
|
|
2556
|
+
return {
|
|
2557
|
+
runningState: "completed",
|
|
2558
|
+
confidence: "strong",
|
|
2559
|
+
observedAt: input.observedAt,
|
|
2560
|
+
detail: terminalDetail,
|
|
2561
|
+
errorCode: null,
|
|
2562
|
+
runId: input.runId
|
|
2563
|
+
};
|
|
2564
|
+
}
|
|
2565
|
+
return null;
|
|
2566
|
+
}
|
|
2567
|
+
}
|
|
2568
|
+
function collectCodexThreadTurns(thread) {
|
|
2569
|
+
if (Array.isArray(thread.turns)) {
|
|
2570
|
+
return thread.turns;
|
|
2571
|
+
}
|
|
2572
|
+
const nestedThread = asCodexRecord(thread.thread);
|
|
2573
|
+
if (Array.isArray(nestedThread?.turns)) {
|
|
2574
|
+
return nestedThread.turns;
|
|
2575
|
+
}
|
|
2576
|
+
return [];
|
|
2577
|
+
}
|
|
2578
|
+
function asCodexRecord(value) {
|
|
2579
|
+
return value && typeof value === "object" ? value : null;
|
|
2580
|
+
}
|
|
2581
|
+
function codexSecondsToIso(value) {
|
|
2582
|
+
const seconds = readFiniteNumber(value);
|
|
2583
|
+
if (seconds === null) {
|
|
2584
|
+
return null;
|
|
2585
|
+
}
|
|
2586
|
+
const date = new Date(seconds * 1000);
|
|
2587
|
+
return Number.isFinite(date.getTime()) ? date.toISOString() : null;
|
|
2588
|
+
}
|
|
2589
|
+
function compareNullableIso(left, right) {
|
|
2590
|
+
if (left === right) {
|
|
2591
|
+
return 0;
|
|
2592
|
+
}
|
|
2593
|
+
if (!left) {
|
|
2594
|
+
return -1;
|
|
2595
|
+
}
|
|
2596
|
+
if (!right) {
|
|
2597
|
+
return 1;
|
|
2598
|
+
}
|
|
2599
|
+
return left.localeCompare(right);
|
|
2600
|
+
}
|
|
2022
2601
|
function toTimestampMs(value) {
|
|
2023
2602
|
const timestampMs = Date.parse(ensureText(value).trim());
|
|
2024
2603
|
return Number.isFinite(timestampMs) ? timestampMs : null;
|
|
@@ -2043,6 +2622,17 @@ function pickClosestCodexSpawnRecord(spawnRecords, workspacePath, message, creat
|
|
|
2043
2622
|
function isCodexSubagentThread(metadata, relation) {
|
|
2044
2623
|
return Boolean(relation?.kind === "spawn" || metadata?.agentRole || metadata?.agentNickname);
|
|
2045
2624
|
}
|
|
2625
|
+
function resolveCodexMetadataTitle(metadata) {
|
|
2626
|
+
const title = normalizeCodexIndexedTitle(metadata?.title);
|
|
2627
|
+
if (!title) {
|
|
2628
|
+
return null;
|
|
2629
|
+
}
|
|
2630
|
+
const firstUserMessage = normalizeCodexIndexedTitle(metadata?.firstUserMessage);
|
|
2631
|
+
if (firstUserMessage && title === firstUserMessage) {
|
|
2632
|
+
return null;
|
|
2633
|
+
}
|
|
2634
|
+
return title;
|
|
2635
|
+
}
|
|
2046
2636
|
function buildCodexSubagentLabel(metadata) {
|
|
2047
2637
|
const agentRole = metadata?.agentRole?.trim() || "";
|
|
2048
2638
|
const agentNickname = metadata?.agentNickname?.trim() || "";
|