@hienlh/ppm 0.20.3 → 0.20.5
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/.release-bin/zip +15 -0
- package/.release-node-shim.sh +11 -0
- package/CHANGELOG.md +13 -0
- package/assets/skills/ppm/SKILL.md +1 -1
- package/assets/skills/ppm/references/cli-reference.md +4 -4
- package/assets/skills/ppm/references/http-api.md +1 -1
- package/dist/web/assets/{accounts-settings-section-DzDmIsPe.js → accounts-settings-section-Cmmozwer.js} +1 -1
- package/dist/web/assets/{ai-resource-editor-D7C9wmwA.js → ai-resource-editor-BlrWV3xU.js} +1 -1
- package/dist/web/assets/{ai-settings-section-DZuwllLy.js → ai-settings-section-PaEh_o0w.js} +1 -1
- package/dist/web/assets/{ai-settings-section-BW5a07-Z.js → ai-settings-section-dDsgddSt.js} +1 -1
- package/dist/web/assets/{appearance-settings-section-RfH2N1rj.js → appearance-settings-section-DRxziHFt.js} +1 -1
- package/dist/web/assets/{chat-tab-Bz0pk0_E.js → chat-tab-MNuc18Os.js} +4 -4
- package/dist/web/assets/{code-editor-C4o1SyuO.js → code-editor-DYkmDRRF.js} +2 -2
- package/dist/web/assets/{conflict-editor-Dk65mBIe.js → conflict-editor-D9_sr59D.js} +1 -1
- package/dist/web/assets/{csv-preview-DENi3CFz.js → csv-preview-BMC8jnpF.js} +1 -1
- package/dist/web/assets/{database-viewer-BiBC7ulB.js → database-viewer-Box3z5-Q.js} +1 -1
- package/dist/web/assets/{diff-viewer-CSvZJHak.js → diff-viewer-B4PlZ1Dt.js} +1 -1
- package/dist/web/assets/{explorer-body-QXS0h4AF.js → explorer-body-SvWDS84f.js} +1 -1
- package/dist/web/assets/{explorer-window-content-CQgqoRsj.js → explorer-window-content-DBHBTA7B.js} +1 -1
- package/dist/web/assets/{extension-manager-section-CyC7wX35.js → extension-manager-section-BSt5I_H8.js} +1 -1
- package/dist/web/assets/{extension-webview-Da8SIlRa.js → extension-webview-DBGMUU97.js} +1 -1
- package/dist/web/assets/{files-settings-section-D8cebM51.js → files-settings-section-0dwYLZou.js} +1 -1
- package/dist/web/assets/{general-settings-section-1HVTvlIw.js → general-settings-section-BgLy_6yj.js} +1 -1
- package/dist/web/assets/{git-log-panel-C7a4rp8f.js → git-log-panel-BkgmcWk1.js} +1 -1
- package/dist/web/assets/{glide-data-grid-BT9p_4AN.js → glide-data-grid-CZVu-zCw.js} +1 -1
- package/dist/web/assets/{group-chat-tab-BUHGnUyW.js → group-chat-tab-Cy9zIynj.js} +1 -1
- package/dist/web/assets/{index-kGmcC9cb.js → index-DYGLdCpe.js} +4 -4
- package/dist/web/assets/{jira-watcher-section-BxzwW4uQ.js → jira-watcher-section-DRQx632s.js} +1 -1
- package/dist/web/assets/{keybindings-store-DjJum4OS.js → keybindings-store-C2HZ1mT4.js} +1 -1
- package/dist/web/assets/{keyboard-shortcuts-section-DDKG3BU1.js → keyboard-shortcuts-section-WiZSZ-Wr.js} +1 -1
- package/dist/web/assets/{markdown-renderer-dHeak2mE.js → markdown-renderer-BFYBVcZP.js} +1 -1
- package/dist/web/assets/{markdown-renderer-iBw1fCI_.js → markdown-renderer-CklcWnd6.js} +1 -1
- package/dist/web/assets/{mobile-explorer-sheet-CzL8SLtz.js → mobile-explorer-sheet-D1OXw7op.js} +1 -1
- package/dist/web/assets/{notification-store-DVi6Ds71.js → notification-store-DyKshGRs.js} +1 -1
- package/dist/web/assets/{notifications-settings-section-shQ-ugKh.js → notifications-settings-section-BEQEjvan.js} +1 -1
- package/dist/web/assets/{pdf-preview-DB26KSzm.js → pdf-preview-DmQazeeV.js} +1 -1
- package/dist/web/assets/{postgres-viewer-CJe2meyF.js → postgres-viewer-Cd_wXjkT.js} +1 -1
- package/dist/web/assets/{ppmbot-settings-section-Ba4c9AI9.js → ppmbot-settings-section-PzCLPm8a.js} +1 -1
- package/dist/web/assets/{process-table-PXwLsMuG.js → process-table-C2TdkJck.js} +1 -1
- package/dist/web/assets/{proxy-settings-section-BHBhK6HC.js → proxy-settings-section-DsZ6KcHD.js} +1 -1
- package/dist/web/assets/{query-audit-section-BD5ZVqDz.js → query-audit-section-2eX9-6mO.js} +1 -1
- package/dist/web/assets/{remote-desktop-mobile-sheet-Di4QG8VX.js → remote-desktop-mobile-sheet-CMXSUcAN.js} +2 -2
- package/dist/web/assets/{remote-desktop-mobile-view-DzoZvAqc.js → remote-desktop-mobile-view-Bw6p5ikf.js} +1 -1
- package/dist/web/assets/{remote-desktop-readiness-gate-CHO-KJ9Z.js → remote-desktop-readiness-gate-W0lAhHq9.js} +1 -1
- package/dist/web/assets/{remote-desktop-window-content-X324gYbW.js → remote-desktop-window-content-P888YEqm.js} +1 -1
- package/dist/web/assets/{schedules-settings-section-a4-h6THc.js → schedules-settings-section-C8YDAxlo.js} +1 -1
- package/dist/web/assets/{settings-body-Fq7BVDw2.js → settings-body-B5v3_Tnb.js} +2 -2
- package/dist/web/assets/{settings-tab-CVLQy-ie.js → settings-tab-CauShulf.js} +1 -1
- package/dist/web/assets/{settings-window-content-Bi7M0iaZ.js → settings-window-content-BIosR7RY.js} +1 -1
- package/dist/web/assets/{sql-query-editor-D1r265fl.js → sql-query-editor-DMihDPnw.js} +1 -1
- package/dist/web/assets/{sqlite-viewer-DHkIotRl.js → sqlite-viewer-jCIGt2GP.js} +1 -1
- package/dist/web/assets/{system-monitor-body-y6VUkYTL.js → system-monitor-body-IUamfS5w.js} +2 -2
- package/dist/web/assets/{system-monitor-tab-DRAOejhk.js → system-monitor-tab-DaWeif4k.js} +1 -1
- package/dist/web/assets/{system-monitor-window-content-B5i57xHD.js → system-monitor-window-content-Bq3BS7Mg.js} +1 -1
- package/dist/web/assets/{tab-host-window-content-SkyPFFlc.js → tab-host-window-content-vfYLLIKU.js} +1 -1
- package/dist/web/assets/{team-member-sheet-BB63u-Lf.js → team-member-sheet-Be7OSGMT.js} +2 -2
- package/dist/web/assets/{team-member-window-content-D6tVTXuV.js → team-member-window-content-D5cYZzBq.js} +1 -1
- package/dist/web/assets/{terminal-tab-BYaHAkI5.js → terminal-tab-C89DQllY.js} +1 -1
- package/dist/web/assets/tool-cards-CWotDH_2.js +9 -0
- package/dist/web/assets/{use-accounts-data-Ba1_uvEE.js → use-accounts-data-lmmmG4ep.js} +1 -1
- package/dist/web/assets/{use-monaco-theme-Uakgj3hJ.js → use-monaco-theme-0ziS4xlp.js} +1 -1
- package/dist/web/assets/{use-remote-desktop-display-choice-Cd3Xalca.js → use-remote-desktop-display-choice-qBZ8ej7J.js} +1 -1
- package/dist/web/assets/{use-websocket-BC_EGf5q.js → use-websocket-DAvfbjxh.js} +1 -1
- package/dist/web/assets/{video-preview-BUb43zWb.js → video-preview-B8xALVkh.js} +1 -1
- package/dist/web/index.html +1 -1
- package/dist/web/sw.js +1 -1
- package/package.json +1 -1
- package/src/providers/codex-app-server/codex-event-mapper.ts +8 -2
- package/src/providers/codex-app-server/codex-history.ts +4 -2
- package/src/providers/codex-app-server/codex-protocol.ts +4 -0
- package/src/providers/codex-app-server/codex-provider.ts +69 -5
- package/src/server/routes/chat.ts +22 -3
- package/src/server/ws/chat.ts +6 -1
- package/src/services/edge-forwarder.ts +191 -191
- package/src/services/windows-process-tree.ts +351 -351
- package/src/types/api.ts +1 -1
- package/src/types/chat.ts +1 -1
- package/src/web/components/chat/message-list.tsx +1 -1
- package/src/web/components/chat/tool-cards.tsx +10 -0
- package/src/web/hooks/use-chat.ts +22 -11
- package/dist/web/assets/tool-cards-DRJu20sL.js +0 -9
- package/packages/vscode-compat/node_modules/.bin/tsc.bunx +0 -0
- package/packages/vscode-compat/node_modules/.bin/tsc.exe +0 -0
- package/packages/vscode-compat/node_modules/.bin/tsserver.bunx +0 -0
- package/packages/vscode-compat/node_modules/.bin/tsserver.exe +0 -0
|
@@ -126,11 +126,13 @@ export function itemToToolResult(item: Item): ChatEvent {
|
|
|
126
126
|
const type = item.type;
|
|
127
127
|
let output = "";
|
|
128
128
|
let isError = false;
|
|
129
|
+
let exitCode: number | undefined;
|
|
129
130
|
|
|
130
131
|
if (type === "commandExecution") {
|
|
131
132
|
output = redactTruncate(item.aggregatedOutput ?? "");
|
|
132
133
|
const exit = item.exitCode;
|
|
133
|
-
|
|
134
|
+
exitCode = typeof exit === "number" ? exit : undefined;
|
|
135
|
+
isError = exitCode != null && exitCode !== 0;
|
|
134
136
|
} else if (type === "mcpToolCall") {
|
|
135
137
|
output = redactTruncate(item.result ?? item.error ?? "");
|
|
136
138
|
isError = item.error != null;
|
|
@@ -153,7 +155,7 @@ export function itemToToolResult(item: Item): ChatEvent {
|
|
|
153
155
|
output = redactTruncate(item);
|
|
154
156
|
}
|
|
155
157
|
|
|
156
|
-
return { type: "tool_result", output, isError, toolUseId: item.id };
|
|
158
|
+
return { type: "tool_result", output, isError, ...(exitCode != null ? { exitCode } : {}), toolUseId: item.id };
|
|
157
159
|
}
|
|
158
160
|
|
|
159
161
|
/**
|
|
@@ -168,6 +170,10 @@ export function mapCodexEvent(notif: Notif, sessionId: string): ChatEvent[] {
|
|
|
168
170
|
return typeof p.delta === "string" ? [{ type: "text", content: p.delta }] : [];
|
|
169
171
|
|
|
170
172
|
case "item/reasoning/textDelta":
|
|
173
|
+
// `summary` is what turn/start requests for PPM's Thinking switch. Recent
|
|
174
|
+
// app-server builds stream it under this method, while older builds used
|
|
175
|
+
// textDelta directly. Both are safe, user-visible reasoning summaries.
|
|
176
|
+
case "item/reasoning/summaryTextDelta":
|
|
171
177
|
return typeof p.delta === "string" ? [{ type: "thinking", content: p.delta }] : [];
|
|
172
178
|
|
|
173
179
|
case "item/started": {
|
|
@@ -411,10 +411,12 @@ export function getRolloutMessages(sessionsDir: string, threadId: string, reques
|
|
|
411
411
|
} catch { return []; }
|
|
412
412
|
}
|
|
413
413
|
|
|
414
|
-
/** True when a path points at a codex rollout
|
|
414
|
+
/** True when a path points at a codex rollout in the ambient or a PPM account home. */
|
|
415
415
|
export function isCodexRolloutPath(p: string): boolean {
|
|
416
416
|
const n = normPath(p);
|
|
417
|
-
|
|
417
|
+
const ambient = normPath(join(homedir(), ".codex", "sessions"));
|
|
418
|
+
const managed = normPath(join(homedir(), ".ppm", "codex-accounts"));
|
|
419
|
+
return n.endsWith(".jsonl") && (n.includes(ambient) || (n.includes(managed) && n.includes("/sessions/")));
|
|
418
420
|
}
|
|
419
421
|
|
|
420
422
|
/**
|
|
@@ -56,6 +56,10 @@ export interface TurnStartParams {
|
|
|
56
56
|
approvalPolicy?: AskForApproval;
|
|
57
57
|
sandboxPolicy?: unknown;
|
|
58
58
|
model?: string;
|
|
59
|
+
/** Codex's per-turn reasoning depth (low through ultra, model dependent). */
|
|
60
|
+
effort?: string;
|
|
61
|
+
/** Controls whether Codex streams a safe reasoning summary to the client. */
|
|
62
|
+
summary?: "none" | "auto" | "concise" | "detailed";
|
|
59
63
|
}
|
|
60
64
|
|
|
61
65
|
// ── Decisions (approval responses) ──
|
|
@@ -10,7 +10,7 @@ import type {
|
|
|
10
10
|
UsageInfo,
|
|
11
11
|
} from "../provider.interface.ts";
|
|
12
12
|
import { configService } from "../../services/config.service.ts";
|
|
13
|
-
import { setSessionMetadata, getSessionProjectPath, setSessionProvider, setSessionCodexAccount, getSessionCodexAccount, getSessionTitles } from "../../services/db.service.ts";
|
|
13
|
+
import { setSessionMetadata, getSessionProjectPath, setSessionProvider, setSessionCodexAccount, getSessionCodexAccount, getSessionTitles, insertTurnUsage } from "../../services/db.service.ts";
|
|
14
14
|
import {
|
|
15
15
|
resolveCodexAccountForSession,
|
|
16
16
|
getCodexAccount,
|
|
@@ -29,6 +29,7 @@ import { join } from "node:path";
|
|
|
29
29
|
import { CodexJsonRpcClient, CONTROL_REQUEST_TIMEOUT_MS } from "./codex-jsonrpc-client.ts";
|
|
30
30
|
import { permissionModeToCodex, type CodexPermission } from "./codex-permission-map.ts";
|
|
31
31
|
import { mapCodexEvent, parseTokenUsage } from "./codex-event-mapper.ts";
|
|
32
|
+
import { subagentCardId } from "./codex-subagent-thread.ts";
|
|
32
33
|
import { decisionFor, isApprovalMethod, type ApprovalMethod } from "./codex-approval-decision.ts";
|
|
33
34
|
import { parseModelList } from "./codex-model-parser.ts";
|
|
34
35
|
import { getOrFetchUsage, registerUsageSource } from "../../services/provider-usage/usage-registry.ts";
|
|
@@ -147,6 +148,8 @@ interface LiveSession {
|
|
|
147
148
|
compactRequested?: boolean;
|
|
148
149
|
/** Token counts from the most recent usage notification, attached to `done`. */
|
|
149
150
|
lastUsage?: import("../../shared/turn-usage.ts").TurnUsage;
|
|
151
|
+
/** Spawned thread ids. Notifications from these threads belong inside their Agent card. */
|
|
152
|
+
subagentThreadIds: Set<string>;
|
|
150
153
|
/** A turn is running on the thread. Codex accepts exactly one at a time: a
|
|
151
154
|
* second `turn/start` resolves with the ALREADY-RUNNING turn (same id,
|
|
152
155
|
* status `inProgress`) and silently discards the new input — no error, so
|
|
@@ -219,6 +222,21 @@ function createEventChannel(): EventChannel {
|
|
|
219
222
|
};
|
|
220
223
|
}
|
|
221
224
|
|
|
225
|
+
/** The app-server puts the owner thread on every item notification. An
|
|
226
|
+
* `agentThreadId` inside a SubAgentActivity is the newly spawned child, so it
|
|
227
|
+
* must never be used here: that would nest the launch card inside itself. */
|
|
228
|
+
export function threadIdFromNotification(params: unknown): string | null {
|
|
229
|
+
if (!params || typeof params !== "object") return null;
|
|
230
|
+
const p = params as Record<string, unknown>;
|
|
231
|
+
const direct = p.threadId ?? p.thread_id;
|
|
232
|
+
if (typeof direct === "string" && direct) return direct;
|
|
233
|
+
const thread = p.thread;
|
|
234
|
+
if (thread && typeof thread === "object" && typeof (thread as Record<string, unknown>).id === "string") {
|
|
235
|
+
return (thread as Record<string, unknown>).id as string;
|
|
236
|
+
}
|
|
237
|
+
return null;
|
|
238
|
+
}
|
|
239
|
+
|
|
222
240
|
/**
|
|
223
241
|
* Drop a model id that isn't a codex model. PPM's per-session model can fall back
|
|
224
242
|
* to the global Claude default (e.g. `claude-opus-4-8`), which codex rejects
|
|
@@ -425,6 +443,7 @@ export class CodexAppServerProvider implements AIProvider {
|
|
|
425
443
|
live.lastTurnInput = { message, opts };
|
|
426
444
|
live.currentAssistant = "";
|
|
427
445
|
live.currentEvents = [];
|
|
446
|
+
live.lastUsage = undefined;
|
|
428
447
|
// Codex takes an image as a path, never as a payload, so the uploaded copy is what it
|
|
429
448
|
// gets. Images lead: the text usually refers to them ("what is this?").
|
|
430
449
|
const input: UserInput[] = [
|
|
@@ -432,10 +451,17 @@ export class CodexAppServerProvider implements AIProvider {
|
|
|
432
451
|
{ type: "text" as const, text: message, text_elements: [] },
|
|
433
452
|
];
|
|
434
453
|
const turnModel = codexModel(opts?.model);
|
|
454
|
+
const turnEffort = opts?.effort ?? this.config?.effort;
|
|
455
|
+
const configuredThinking = this.config?.thinking_budget_tokens;
|
|
456
|
+
// Codex does not accept a token budget. Its equivalent is an effort level,
|
|
457
|
+
// while `summary` controls the safe thinking text the UI can show.
|
|
458
|
+
const thinkingEnabled = (opts?.thinkingBudget ?? configuredThinking ?? -1) !== 0;
|
|
435
459
|
live.client.request("turn/start", {
|
|
436
460
|
threadId: live.threadId,
|
|
437
461
|
input,
|
|
438
462
|
...(turnModel ? { model: turnModel } : {}),
|
|
463
|
+
...(turnEffort ? { effort: turnEffort } : {}),
|
|
464
|
+
summary: thinkingEnabled ? "detailed" : "none",
|
|
439
465
|
}).then((res) => {
|
|
440
466
|
// Backup for the `turn/started` notification, which is what normally names
|
|
441
467
|
// the turn — an interrupt arriving in between has nothing to address.
|
|
@@ -678,7 +704,7 @@ export class CodexAppServerProvider implements AIProvider {
|
|
|
678
704
|
client, threadId: null, cwd, channel, permission, model,
|
|
679
705
|
pendingApprovals: new Map(), answeredCodexIds: new Set(),
|
|
680
706
|
history: [], transcript: [], currentAssistant: "", currentEvents: [],
|
|
681
|
-
pendingTurns: [],
|
|
707
|
+
pendingTurns: [], subagentThreadIds: new Set(),
|
|
682
708
|
};
|
|
683
709
|
this.live.set(sessionId, live);
|
|
684
710
|
|
|
@@ -750,14 +776,26 @@ export class CodexAppServerProvider implements AIProvider {
|
|
|
750
776
|
const usage = parseTokenUsage(notif.params, live.model);
|
|
751
777
|
if (usage) live.lastUsage = usage;
|
|
752
778
|
}
|
|
779
|
+
const notificationThreadId = threadIdFromNotification(notif.params);
|
|
780
|
+
const parentToolUseId = notificationThreadId && live.subagentThreadIds.has(notificationThreadId)
|
|
781
|
+
? subagentCardId(notificationThreadId)
|
|
782
|
+
: undefined;
|
|
753
783
|
const events = mapCodexEvent(notif, live.threadId ?? "");
|
|
754
784
|
for (const ev of events) {
|
|
755
785
|
// The counts arrive on their own notification just before the turn ends,
|
|
756
786
|
// so `done` is where they become visible to a consumer.
|
|
757
|
-
if (ev.type === "done" && live.lastUsage)
|
|
758
|
-
|
|
787
|
+
if (ev.type === "done" && live.lastUsage) {
|
|
788
|
+
ev.usage = live.lastUsage;
|
|
789
|
+
this.recordTurnUsage(live, live.lastUsage);
|
|
790
|
+
}
|
|
791
|
+
const nested = parentToolUseId ? { ...ev, parentToolUseId } as ChatEvent : ev;
|
|
792
|
+
live.channel.push(nested);
|
|
759
793
|
// Accumulate tool calls into the turn so getMessages (live) keeps them.
|
|
760
|
-
if (
|
|
794
|
+
if (nested.type === "tool_use" || nested.type === "tool_result") live.currentEvents.push(nested);
|
|
795
|
+
if (nested.type === "tool_use" && nested.tool === "Agent" && typeof nested.toolUseId === "string"
|
|
796
|
+
&& nested.toolUseId.startsWith("subagent-")) {
|
|
797
|
+
live.subagentThreadIds.add(nested.toolUseId.slice("subagent-".length));
|
|
798
|
+
}
|
|
761
799
|
}
|
|
762
800
|
if (notif.method === "turn/completed") {
|
|
763
801
|
if (live.currentAssistant || live.currentEvents.length) {
|
|
@@ -798,6 +836,32 @@ export class CodexAppServerProvider implements AIProvider {
|
|
|
798
836
|
}
|
|
799
837
|
}
|
|
800
838
|
|
|
839
|
+
/** Persist Codex's per-turn token and prompt-cache split for the debug panel. */
|
|
840
|
+
private recordTurnUsage(live: LiveSession, usage: import("../../shared/turn-usage.ts").TurnUsage): void {
|
|
841
|
+
const accountId = live.threadId ? getSessionCodexAccount(live.threadId) ?? undefined : undefined;
|
|
842
|
+
const account = accountId ? getCodexAccount(accountId) : null;
|
|
843
|
+
try {
|
|
844
|
+
insertTurnUsage({
|
|
845
|
+
sessionId: live.threadId ?? "",
|
|
846
|
+
model: usage.model,
|
|
847
|
+
inputTokens: usage.inputTokens,
|
|
848
|
+
outputTokens: usage.outputTokens,
|
|
849
|
+
cacheReadTokens: usage.cacheReadTokens,
|
|
850
|
+
cacheWriteTokens: usage.cacheWriteTokens,
|
|
851
|
+
contextWindow: usage.contextWindow,
|
|
852
|
+
costUsd: usage.costUsd,
|
|
853
|
+
// A cache miss alone does not prove a process restart: a first turn and
|
|
854
|
+
// an evicted prompt cache look the same on the wire. Keep this false
|
|
855
|
+
// until the provider has an explicit lifecycle reason to record.
|
|
856
|
+
coldStart: false,
|
|
857
|
+
...(accountId ? { accountId } : {}),
|
|
858
|
+
...(account?.label ? { accountLabel: account.label } : {}),
|
|
859
|
+
});
|
|
860
|
+
} catch (err) {
|
|
861
|
+
console.warn(`[usage] failed to persist codex usage: ${(err as Error).message}`);
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
|
|
801
865
|
private handleServerRequest(live: LiveSession, req: ServerRequest): void {
|
|
802
866
|
const method = req.method;
|
|
803
867
|
if (isApprovalMethod(method)) {
|
|
@@ -19,6 +19,8 @@ import { parseJsonlTranscript, validateJsonlPath } from "../../services/jsonl-tr
|
|
|
19
19
|
import { aggregateTasks } from "../../services/task-status-aggregator.ts";
|
|
20
20
|
import { MANY_IMAGE_DIMENSION_LIMIT, type StripMode } from "../../services/transcript-images.ts";
|
|
21
21
|
import { auditTranscriptImagesFile, stripTranscriptImagesFile } from "../../services/transcript-images-file.ts";
|
|
22
|
+
import { listCodexAccounts } from "../../services/codex-account.service.ts";
|
|
23
|
+
import { findRolloutByThreadId } from "../../providers/codex-app-server/codex-history.ts";
|
|
22
24
|
import { getSessionProjectPath, setSessionMetadata, setSessionTitle, getSessionTitle, getPinnedSessionIds, pinSession, unpinSession, deleteSessionMapping, deleteSessionMetadata, deleteSessionTitle, getAllUnread, clearSessionUnread, setSessionUnread } from "../../services/db.service.ts";
|
|
23
25
|
import { setSessionTag, bulkSetSessionTag, getTagById, getSessionTags, getProjectDefaultTagId } from "../../services/tag.service.ts";
|
|
24
26
|
import { recordBranch, resolveVersionGroup, resolveVersionMap, collapseTreesToHeads, hasChildren, deleteBranchesFor, getRootId } from "../../services/session-branch.service.ts";
|
|
@@ -469,8 +471,11 @@ chatRoutes.patch("/sessions/:id", async (c) => {
|
|
|
469
471
|
const projectPath = c.get("projectPath");
|
|
470
472
|
// Persist to PPM DB (authoritative source for user-set titles)
|
|
471
473
|
setSessionTitle(id, title);
|
|
472
|
-
//
|
|
473
|
-
|
|
474
|
+
// Codex owns its rollout title and has no Claude SDK session to rename.
|
|
475
|
+
// PPM's title table is the authoritative title for both providers.
|
|
476
|
+
if (getSessionProvider(id) !== "codex") {
|
|
477
|
+
await sdkRenameSession(id, title, { dir: projectPath });
|
|
478
|
+
}
|
|
474
479
|
// Also update in-memory session
|
|
475
480
|
const session = chatService.getSession(id);
|
|
476
481
|
if (session) session.title = title;
|
|
@@ -763,9 +768,22 @@ chatRoutes.get("/sessions/:id/logs", (c) => {
|
|
|
763
768
|
*/
|
|
764
769
|
function resolveSessionJsonlPath(sessionId: string): { jsonlPath: string; jsonlDir: string; projectPath: string; exists: boolean } {
|
|
765
770
|
const homedir = process.env.HOME ?? process.env.USERPROFILE ?? "";
|
|
771
|
+
const providerId = getSessionProvider(sessionId);
|
|
772
|
+
const storedProjectPath = getSessionProjectPath(sessionId) ?? "";
|
|
773
|
+
if (providerId === "codex") {
|
|
774
|
+
const dirs = [
|
|
775
|
+
...listCodexAccounts().map((account) => join(account.home, "sessions")),
|
|
776
|
+
...(homedir ? [resolve(homedir, ".codex", "sessions")] : []),
|
|
777
|
+
];
|
|
778
|
+
for (const dir of dirs) {
|
|
779
|
+
const found = findRolloutByThreadId(dir, sessionId, storedProjectPath || undefined);
|
|
780
|
+
if (found) return { jsonlPath: found, jsonlDir: dir, projectPath: storedProjectPath, exists: true };
|
|
781
|
+
}
|
|
782
|
+
return { jsonlPath: "", jsonlDir: "", projectPath: storedProjectPath, exists: false };
|
|
783
|
+
}
|
|
766
784
|
const provider = providerRegistry.get("claude") as any;
|
|
767
785
|
const projectPath = provider?.activeSessions?.get(sessionId)?.projectPath
|
|
768
|
-
??
|
|
786
|
+
?? storedProjectPath
|
|
769
787
|
?? "";
|
|
770
788
|
const projectsRoot = homedir ? resolve(homedir, ".claude", "projects") : "";
|
|
771
789
|
// SDK encodes cwd by replacing path separators + drive colon with "-".
|
|
@@ -815,6 +833,7 @@ chatRoutes.get("/sessions/:id/debug", (c) => {
|
|
|
815
833
|
return c.json(ok({
|
|
816
834
|
ppmSessionId: sessionId,
|
|
817
835
|
sdkSessionId: sessionId,
|
|
836
|
+
providerId: getSessionProvider(sessionId) ?? "claude",
|
|
818
837
|
sessionId,
|
|
819
838
|
jsonlPath: exists ? jsonlPath : null,
|
|
820
839
|
jsonlDir,
|
package/src/server/ws/chat.ts
CHANGED
|
@@ -333,7 +333,7 @@ function bufferAndBroadcast(sessionId: string, event: unknown): void {
|
|
|
333
333
|
for (let i = entry.turnEvents.length - 1; i >= 0; i--) {
|
|
334
334
|
const buffered = entry.turnEvents[i] as any;
|
|
335
335
|
if (buffered.type === "tool_use" && buffered.toolUseId === toolUseId) {
|
|
336
|
-
buffered.result = { output: (event as any).output, isError: (event as any).isError };
|
|
336
|
+
buffered.result = { output: (event as any).output, isError: (event as any).isError, exitCode: (event as any).exitCode };
|
|
337
337
|
break;
|
|
338
338
|
}
|
|
339
339
|
}
|
|
@@ -1286,10 +1286,15 @@ export const chatWebSocket = {
|
|
|
1286
1286
|
} else {
|
|
1287
1287
|
// Follow-up: push into existing generator via provider
|
|
1288
1288
|
if (provider && "pushMessage" in provider && parsed.type === "message") {
|
|
1289
|
+
const effort = getSessionEffort(sessionId) ?? undefined;
|
|
1290
|
+
const thinkingBudget = getSessionThinking(sessionId);
|
|
1289
1291
|
(provider as any).pushMessage(sessionId, parsed.content, {
|
|
1290
1292
|
priority: parsed.priority ?? 'next',
|
|
1291
1293
|
images: parsed.images,
|
|
1292
1294
|
imagePaths: parsed.imagePaths,
|
|
1295
|
+
...(entry.model ? { model: entry.model } : {}),
|
|
1296
|
+
...(effort ? { effort } : {}),
|
|
1297
|
+
...(thinkingBudget != null ? { thinkingBudget } : {}),
|
|
1293
1298
|
});
|
|
1294
1299
|
}
|
|
1295
1300
|
// Clear turn events for new turn display + transition phase
|