@agents-ensemble/core 0.20.0 → 0.22.0
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/assets/pi/pi-cli-env-wrapper.cmd +28 -0
- package/assets/pi/pi-cli-env-wrapper.sh +19 -0
- package/assets/pi/settings.json +4 -0
- package/dist/acp/acp-preset-bins.d.ts +3 -3
- package/dist/acp/acp-preset-bins.d.ts.map +1 -1
- package/dist/acp/acp-preset-bins.js +3 -3
- package/dist/acp/acp-preset-bins.js.map +1 -1
- package/dist/acp/index.d.ts +3 -1
- package/dist/acp/index.d.ts.map +1 -1
- package/dist/acp/index.js +2 -1
- package/dist/acp/index.js.map +1 -1
- package/dist/acp/pi-acp-wrapper.d.ts +3 -0
- package/dist/acp/pi-acp-wrapper.d.ts.map +1 -0
- package/dist/acp/pi-acp-wrapper.js +41 -0
- package/dist/acp/pi-acp-wrapper.js.map +1 -0
- package/dist/acp/pi-builtin-config.d.ts +10 -0
- package/dist/acp/pi-builtin-config.d.ts.map +1 -0
- package/dist/acp/pi-builtin-config.js +36 -0
- package/dist/acp/pi-builtin-config.js.map +1 -0
- package/dist/acp/pi-runtime.d.ts +23 -0
- package/dist/acp/pi-runtime.d.ts.map +1 -0
- package/dist/acp/pi-runtime.js +160 -0
- package/dist/acp/pi-runtime.js.map +1 -0
- package/dist/acp/pi-session-map.d.ts +36 -0
- package/dist/acp/pi-session-map.d.ts.map +1 -0
- package/dist/acp/pi-session-map.js +266 -0
- package/dist/acp/pi-session-map.js.map +1 -0
- package/dist/acp/resolve-acp-spawn.d.ts +9 -3
- package/dist/acp/resolve-acp-spawn.d.ts.map +1 -1
- package/dist/acp/resolve-acp-spawn.js +41 -9
- package/dist/acp/resolve-acp-spawn.js.map +1 -1
- package/dist/acp/resolve-bundled-acp-bin.d.ts +2 -2
- package/dist/acp/resolve-bundled-acp-bin.d.ts.map +1 -1
- package/dist/acp/resolve-bundled-acp-bin.js +4 -4
- package/dist/acp/resolve-bundled-acp-bin.js.map +1 -1
- package/dist/acp/validate-acp-preset-prerequisites.d.ts +1 -1
- package/dist/acp/validate-acp-preset-prerequisites.d.ts.map +1 -1
- package/dist/acp/validate-acp-preset-prerequisites.js +30 -10
- package/dist/acp/validate-acp-preset-prerequisites.js.map +1 -1
- package/dist/conductor/conductor-agent.d.ts +15 -3
- package/dist/conductor/conductor-agent.d.ts.map +1 -1
- package/dist/conductor/conductor-auth.d.ts +4 -3
- package/dist/conductor/conductor-auth.d.ts.map +1 -1
- package/dist/conductor/conductor-auth.js +20 -4
- package/dist/conductor/conductor-auth.js.map +1 -1
- package/dist/conductor/conductor-dispatch-lifecycle.d.ts +85 -0
- package/dist/conductor/conductor-dispatch-lifecycle.d.ts.map +1 -0
- package/dist/conductor/conductor-dispatch-lifecycle.js +190 -0
- package/dist/conductor/conductor-dispatch-lifecycle.js.map +1 -0
- package/dist/conductor/conductor-history.d.ts +15 -0
- package/dist/conductor/conductor-history.d.ts.map +1 -1
- package/dist/conductor/conductor-history.js +38 -7
- package/dist/conductor/conductor-history.js.map +1 -1
- package/dist/conductor/conductor-path-safety.d.ts +23 -0
- package/dist/conductor/conductor-path-safety.d.ts.map +1 -0
- package/dist/conductor/conductor-path-safety.js +319 -0
- package/dist/conductor/conductor-path-safety.js.map +1 -0
- package/dist/conductor/conductor-pi-auth.d.ts +57 -2
- package/dist/conductor/conductor-pi-auth.d.ts.map +1 -1
- package/dist/conductor/conductor-pi-auth.js +718 -40
- package/dist/conductor/conductor-pi-auth.js.map +1 -1
- package/dist/conductor/conductor-recovery-inbox.d.ts +73 -0
- package/dist/conductor/conductor-recovery-inbox.d.ts.map +1 -0
- package/dist/conductor/conductor-recovery-inbox.js +181 -0
- package/dist/conductor/conductor-recovery-inbox.js.map +1 -0
- package/dist/conductor/conductor-send-reconnect.d.ts +33 -4
- package/dist/conductor/conductor-send-reconnect.d.ts.map +1 -1
- package/dist/conductor/conductor-send-reconnect.js +89 -24
- package/dist/conductor/conductor-send-reconnect.js.map +1 -1
- package/dist/conductor/conductor-session-driver.d.ts +34 -1
- package/dist/conductor/conductor-session-driver.d.ts.map +1 -1
- package/dist/conductor/conductor-session-driver.js +529 -75
- package/dist/conductor/conductor-session-driver.js.map +1 -1
- package/dist/conductor/conductor-session.d.ts +4 -0
- package/dist/conductor/conductor-session.d.ts.map +1 -1
- package/dist/conductor/conductor-session.js +416 -145
- package/dist/conductor/conductor-session.js.map +1 -1
- package/dist/conductor/conductor-setup.d.ts +30 -0
- package/dist/conductor/conductor-setup.d.ts.map +1 -0
- package/dist/conductor/conductor-setup.js +243 -0
- package/dist/conductor/conductor-setup.js.map +1 -0
- package/dist/conductor/cursor-bootstrap-state.d.ts +9 -0
- package/dist/conductor/cursor-bootstrap-state.d.ts.map +1 -0
- package/dist/conductor/cursor-bootstrap-state.js +11 -0
- package/dist/conductor/cursor-bootstrap-state.js.map +1 -0
- package/dist/conductor/cursor-run-snapshots.d.ts +30 -0
- package/dist/conductor/cursor-run-snapshots.d.ts.map +1 -0
- package/dist/conductor/cursor-run-snapshots.js +120 -0
- package/dist/conductor/cursor-run-snapshots.js.map +1 -0
- package/dist/conductor/index.d.ts +18 -7
- package/dist/conductor/index.d.ts.map +1 -1
- package/dist/conductor/index.js +9 -4
- package/dist/conductor/index.js.map +1 -1
- package/dist/conductor/operator-command.d.ts +5 -0
- package/dist/conductor/operator-command.d.ts.map +1 -1
- package/dist/conductor/operator-command.js +6 -0
- package/dist/conductor/operator-command.js.map +1 -1
- package/dist/conductor/operator-input-binding.d.ts +17 -0
- package/dist/conductor/operator-input-binding.d.ts.map +1 -1
- package/dist/conductor/pi-auth-recovery-snapshot-store.d.ts +45 -0
- package/dist/conductor/pi-auth-recovery-snapshot-store.d.ts.map +1 -0
- package/dist/conductor/pi-auth-recovery-snapshot-store.js +116 -0
- package/dist/conductor/pi-auth-recovery-snapshot-store.js.map +1 -0
- package/dist/conductor/pi-conductor-agent.d.ts +6 -3
- package/dist/conductor/pi-conductor-agent.d.ts.map +1 -1
- package/dist/conductor/pi-conductor-agent.js +276 -53
- package/dist/conductor/pi-conductor-agent.js.map +1 -1
- package/dist/conductor/pi-conductor-session-file.d.ts +13 -0
- package/dist/conductor/pi-conductor-session-file.d.ts.map +1 -0
- package/dist/conductor/pi-conductor-session-file.js +21 -0
- package/dist/conductor/pi-conductor-session-file.js.map +1 -0
- package/dist/conductor/pi-resource-loader.d.ts +6 -0
- package/dist/conductor/pi-resource-loader.d.ts.map +1 -1
- package/dist/conductor/pi-resource-loader.js +26 -12
- package/dist/conductor/pi-resource-loader.js.map +1 -1
- package/dist/conductor/pi-user-root-lock.d.ts +8 -0
- package/dist/conductor/pi-user-root-lock.d.ts.map +1 -0
- package/dist/conductor/pi-user-root-lock.js +53 -0
- package/dist/conductor/pi-user-root-lock.js.map +1 -0
- package/dist/conductor/recovery-inbox-command.d.ts +29 -0
- package/dist/conductor/recovery-inbox-command.d.ts.map +1 -0
- package/dist/conductor/recovery-inbox-command.js +248 -0
- package/dist/conductor/recovery-inbox-command.js.map +1 -0
- package/dist/conductor/session/events/index.d.ts +1 -1
- package/dist/conductor/session/events/index.d.ts.map +1 -1
- package/dist/conductor/session/events/index.js.map +1 -1
- package/dist/conductor/session/events/session-event.d.ts +43 -1
- package/dist/conductor/session/events/session-event.d.ts.map +1 -1
- package/dist/conductor/session/events/session-log-event-groups.d.ts +1 -1
- package/dist/conductor/session/events/session-log-event-groups.d.ts.map +1 -1
- package/dist/conductor/session/events/session-log-event-groups.js +2 -0
- package/dist/conductor/session/events/session-log-event-groups.js.map +1 -1
- package/dist/conductor/session/events/session-log-event.d.ts +4 -0
- package/dist/conductor/session/events/session-log-event.d.ts.map +1 -1
- package/dist/conductor/session/format-session-event.js +57 -5
- package/dist/conductor/session/format-session-event.js.map +1 -1
- package/dist/conductor/session/select-dispatch-batch.d.ts +2 -0
- package/dist/conductor/session/select-dispatch-batch.d.ts.map +1 -1
- package/dist/conductor/session/select-dispatch-batch.js +36 -2
- package/dist/conductor/session/select-dispatch-batch.js.map +1 -1
- package/dist/conductor/session/session-event-queue.d.ts +14 -0
- package/dist/conductor/session/session-event-queue.d.ts.map +1 -1
- package/dist/conductor/session/session-event-queue.js +82 -10
- package/dist/conductor/session/session-event-queue.js.map +1 -1
- package/dist/conductor/session/session-event.d.ts +1 -1
- package/dist/conductor/session/session-event.d.ts.map +1 -1
- package/dist/conductor/session-policy.d.ts.map +1 -1
- package/dist/conductor/session-policy.js +8 -4
- package/dist/conductor/session-policy.js.map +1 -1
- package/dist/conductor/submit-operator-input.d.ts +3 -0
- package/dist/conductor/submit-operator-input.d.ts.map +1 -1
- package/dist/conductor/submit-operator-input.js +21 -0
- package/dist/conductor/submit-operator-input.js.map +1 -1
- package/dist/config/deep-merge.d.ts.map +1 -1
- package/dist/config/deep-merge.js +13 -3
- package/dist/config/deep-merge.js.map +1 -1
- package/dist/config/defaults.d.ts.map +1 -1
- package/dist/config/defaults.js +1 -1
- package/dist/config/defaults.js.map +1 -1
- package/dist/config/doctor-settings.d.ts +59 -0
- package/dist/config/doctor-settings.d.ts.map +1 -0
- package/dist/config/doctor-settings.js +343 -0
- package/dist/config/doctor-settings.js.map +1 -0
- package/dist/config/ensemble-config-digest.d.ts +2 -4
- package/dist/config/ensemble-config-digest.d.ts.map +1 -1
- package/dist/config/ensemble-config-digest.js +2 -4
- package/dist/config/ensemble-config-digest.js.map +1 -1
- package/dist/config/index.d.ts +3 -1
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +1 -0
- package/dist/config/index.js.map +1 -1
- package/dist/config/load-ensemble-config.d.ts.map +1 -1
- package/dist/config/load-ensemble-config.js +8 -1
- package/dist/config/load-ensemble-config.js.map +1 -1
- package/dist/config/parse-config.d.ts.map +1 -1
- package/dist/config/parse-config.js +34 -14
- package/dist/config/parse-config.js.map +1 -1
- package/dist/config/resolve-settings.d.ts +3 -1
- package/dist/config/resolve-settings.d.ts.map +1 -1
- package/dist/config/resolve-settings.js +7 -4
- package/dist/config/resolve-settings.js.map +1 -1
- package/dist/config/types.d.ts +14 -5
- package/dist/config/types.d.ts.map +1 -1
- package/dist/dispatch/attach-worker.js +1 -1
- package/dist/dispatch/attach-worker.js.map +1 -1
- package/dist/dispatch/worker-acp-session.d.ts +21 -3
- package/dist/dispatch/worker-acp-session.d.ts.map +1 -1
- package/dist/dispatch/worker-acp-session.js +50 -13
- package/dist/dispatch/worker-acp-session.js.map +1 -1
- package/dist/ensemble-paths.d.ts +19 -19
- package/dist/ensemble-paths.d.ts.map +1 -1
- package/dist/ensemble-paths.js +40 -22
- package/dist/ensemble-paths.js.map +1 -1
- package/dist/issue/resolve-issue-url.d.ts +4 -0
- package/dist/issue/resolve-issue-url.d.ts.map +1 -1
- package/dist/issue/resolve-issue-url.js +2 -2
- package/dist/issue/resolve-issue-url.js.map +1 -1
- package/dist/operator-runtime.d.ts +19 -4
- package/dist/operator-runtime.d.ts.map +1 -1
- package/dist/operator-runtime.js +13 -2
- package/dist/operator-runtime.js.map +1 -1
- package/dist/profile/types.d.ts +4 -0
- package/dist/profile/types.d.ts.map +1 -1
- package/dist/profile/types.js +29 -12
- package/dist/profile/types.js.map +1 -1
- package/dist/representation/escape-terminal-control-characters.d.ts +9 -0
- package/dist/representation/escape-terminal-control-characters.d.ts.map +1 -0
- package/dist/representation/escape-terminal-control-characters.js +34 -0
- package/dist/representation/escape-terminal-control-characters.js.map +1 -0
- package/dist/representation/index.d.ts +1 -0
- package/dist/representation/index.d.ts.map +1 -1
- package/dist/representation/index.js +1 -0
- package/dist/representation/index.js.map +1 -1
- package/dist/runtime/types.d.ts +9 -0
- package/dist/runtime/types.d.ts.map +1 -1
- package/dist/runtime/worker-runtime.d.ts +14 -1
- package/dist/runtime/worker-runtime.d.ts.map +1 -1
- package/dist/runtime/worker-runtime.js +197 -50
- package/dist/runtime/worker-runtime.js.map +1 -1
- package/dist/runtime/worker-session.d.ts +2 -1
- package/dist/runtime/worker-session.d.ts.map +1 -1
- package/dist/runtime/worker-session.js +1 -0
- package/dist/runtime/worker-session.js.map +1 -1
- package/dist/session/export-session-bundle.d.ts +77 -0
- package/dist/session/export-session-bundle.d.ts.map +1 -0
- package/dist/session/export-session-bundle.js +640 -0
- package/dist/session/export-session-bundle.js.map +1 -0
- package/dist/session/index.d.ts +6 -3
- package/dist/session/index.d.ts.map +1 -1
- package/dist/session/index.js +4 -1
- package/dist/session/index.js.map +1 -1
- package/dist/session/open-question-control.d.ts +9 -0
- package/dist/session/open-question-control.d.ts.map +1 -1
- package/dist/session/open-question-control.js +26 -1
- package/dist/session/open-question-control.js.map +1 -1
- package/dist/session/open-questions-store.d.ts +1 -1
- package/dist/session/open-questions-store.d.ts.map +1 -1
- package/dist/session/open-questions-store.js +3 -6
- package/dist/session/open-questions-store.js.map +1 -1
- package/dist/session/persisted-file.d.ts +5 -0
- package/dist/session/persisted-file.d.ts.map +1 -0
- package/dist/session/persisted-file.js +56 -0
- package/dist/session/persisted-file.js.map +1 -0
- package/dist/session/session-resume-store.d.ts +79 -10
- package/dist/session/session-resume-store.d.ts.map +1 -1
- package/dist/session/session-resume-store.js +353 -83
- package/dist/session/session-resume-store.js.map +1 -1
- package/dist/session/session-snapshot-paths.d.ts +11 -0
- package/dist/session/session-snapshot-paths.d.ts.map +1 -0
- package/dist/session/session-snapshot-paths.js +41 -0
- package/dist/session/session-snapshot-paths.js.map +1 -0
- package/dist/session/session-state-store.d.ts +2 -2
- package/dist/session/session-state-store.d.ts.map +1 -1
- package/dist/session/session-state-store.js +5 -16
- package/dist/session/session-state-store.js.map +1 -1
- package/dist/session/tool-call-snapshot-history.d.ts +12 -1
- package/dist/session/tool-call-snapshot-history.d.ts.map +1 -1
- package/dist/session/tool-call-snapshot-history.js +75 -70
- package/dist/session/tool-call-snapshot-history.js.map +1 -1
- package/dist/session/worker-session-history.d.ts +51 -0
- package/dist/session/worker-session-history.d.ts.map +1 -0
- package/dist/session/worker-session-history.js +654 -0
- package/dist/session/worker-session-history.js.map +1 -0
- package/dist/workspace/index.d.ts +1 -1
- package/dist/workspace/index.d.ts.map +1 -1
- package/dist/worktree/worktree.d.ts +6 -1
- package/dist/worktree/worktree.d.ts.map +1 -1
- package/dist/worktree/worktree.js +123 -2
- package/dist/worktree/worktree.js.map +1 -1
- package/package.json +9 -4
|
@@ -0,0 +1,654 @@
|
|
|
1
|
+
import { createReadStream } from 'node:fs';
|
|
2
|
+
import { readFile, readdir, stat } from 'node:fs/promises';
|
|
3
|
+
import { homedir } from 'node:os';
|
|
4
|
+
import { extname, isAbsolute, join, resolve } from 'node:path';
|
|
5
|
+
import { createInterface } from 'node:readline';
|
|
6
|
+
import { SessionManager, parseSessionEntries, } from '@earendil-works/pi-coding-agent';
|
|
7
|
+
import { parseIssueUrl } from '../issue/issue-ref.js';
|
|
8
|
+
import { resolveEnsemblePaths } from '../ensemble-paths.js';
|
|
9
|
+
import { resolvePiAcpSessionMapPaths } from '../acp/pi-session-map.js';
|
|
10
|
+
import { findSessionResumeStoreBySelector, listUserLocatedSessionResumeStoresPage, } from './session-resume-store.js';
|
|
11
|
+
const PI_ACP_JSONL_READER_ID = 'pi-acp-jsonl';
|
|
12
|
+
const CODEX_CLI_ROLLOUT_READER_ID = 'codex-cli-rollout-jsonl';
|
|
13
|
+
const CODEX_UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/iu;
|
|
14
|
+
const workerSessionHistoryReaders = new Map([
|
|
15
|
+
[
|
|
16
|
+
'pi',
|
|
17
|
+
{
|
|
18
|
+
id: PI_ACP_JSONL_READER_ID,
|
|
19
|
+
preset: 'pi',
|
|
20
|
+
read: async (input) => (await readPiAcpSessionHistoryWithSources(input)).messages,
|
|
21
|
+
readWithSources: readPiAcpSessionHistoryWithSources,
|
|
22
|
+
},
|
|
23
|
+
],
|
|
24
|
+
[
|
|
25
|
+
'codex',
|
|
26
|
+
{
|
|
27
|
+
id: CODEX_CLI_ROLLOUT_READER_ID,
|
|
28
|
+
preset: 'codex',
|
|
29
|
+
read: async (input) => (await readCodexAcpSessionHistoryWithSources(input)).messages,
|
|
30
|
+
readWithSources: readCodexAcpSessionHistoryWithSources,
|
|
31
|
+
},
|
|
32
|
+
],
|
|
33
|
+
]);
|
|
34
|
+
export function getWorkerSessionHistoryReaderSupport(preset) {
|
|
35
|
+
const normalizedPreset = preset?.trim() || undefined;
|
|
36
|
+
if (!normalizedPreset) {
|
|
37
|
+
return {
|
|
38
|
+
preset: null,
|
|
39
|
+
status: 'unsupported',
|
|
40
|
+
reason: 'SessionResumeStore に ACP preset がないため、読み取り方式を判定できません。',
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
const reader = workerSessionHistoryReaders.get(normalizedPreset);
|
|
44
|
+
if (reader) {
|
|
45
|
+
return {
|
|
46
|
+
preset: normalizedPreset,
|
|
47
|
+
status: 'supported',
|
|
48
|
+
reader: reader.id,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
return {
|
|
52
|
+
preset: normalizedPreset,
|
|
53
|
+
status: 'unsupported',
|
|
54
|
+
reason: `ACP preset「${normalizedPreset}」のオフライン transcript reader は未対応です。`,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
export async function readWorkerSessionHistory(input) {
|
|
58
|
+
const conductorAgentId = requireNonEmpty(input.conductorAgentId, 'conductorAgentId');
|
|
59
|
+
const workerName = requireNonEmpty(input.workerName, 'workerName');
|
|
60
|
+
const located = input.userEnsembleRoot
|
|
61
|
+
? await findUserWorkerSessionResumeStore({
|
|
62
|
+
userEnsembleRoot: input.userEnsembleRoot,
|
|
63
|
+
conductorAgentId,
|
|
64
|
+
githubRepo: input.githubRepo,
|
|
65
|
+
issueUrl: input.issueUrl,
|
|
66
|
+
})
|
|
67
|
+
: await findSessionResumeStoreBySelector(requireRepoRoot(input.repoRoot), {
|
|
68
|
+
githubRepo: input.githubRepo,
|
|
69
|
+
issueUrl: input.issueUrl,
|
|
70
|
+
conductorAgentId,
|
|
71
|
+
});
|
|
72
|
+
if (!located) {
|
|
73
|
+
throw new Error(`No saved session found for ${conductorAgentId}.`);
|
|
74
|
+
}
|
|
75
|
+
const repoRoot = resolve(input.repoRoot ?? located.resumeStore.repoRoot);
|
|
76
|
+
const worker = located.resumeStore.workers[workerName];
|
|
77
|
+
if (!worker) {
|
|
78
|
+
throw new Error(`No saved worker session found for ${workerName} in ${conductorAgentId}.`);
|
|
79
|
+
}
|
|
80
|
+
const support = getWorkerSessionHistoryReaderSupport(worker.acpSpawn?.preset);
|
|
81
|
+
const base = {
|
|
82
|
+
conductorAgentId,
|
|
83
|
+
worker: workerName,
|
|
84
|
+
...support,
|
|
85
|
+
};
|
|
86
|
+
if (support.status === 'unsupported') {
|
|
87
|
+
return {
|
|
88
|
+
...base,
|
|
89
|
+
status: 'unsupported',
|
|
90
|
+
messages: [],
|
|
91
|
+
...(input.includeSourceFiles ? { sourceFiles: [] } : {}),
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
if (!support.preset) {
|
|
95
|
+
return {
|
|
96
|
+
...base,
|
|
97
|
+
status: 'unsupported',
|
|
98
|
+
reason: '対応 reader の ACP preset を解決できません。',
|
|
99
|
+
messages: [],
|
|
100
|
+
...(input.includeSourceFiles ? { sourceFiles: [] } : {}),
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
const reader = workerSessionHistoryReaders.get(support.preset);
|
|
104
|
+
if (!reader) {
|
|
105
|
+
throw new Error(`Worker session history reader is missing: ${support.preset}`);
|
|
106
|
+
}
|
|
107
|
+
if (!worker.acpCwd?.trim()) {
|
|
108
|
+
return {
|
|
109
|
+
...base,
|
|
110
|
+
status: 'unavailable',
|
|
111
|
+
reason: 'SessionResumeStore に worker ACP cwd がないため、transcript を照合できません。',
|
|
112
|
+
messages: [],
|
|
113
|
+
...(input.includeSourceFiles ? { sourceFiles: [] } : {}),
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
try {
|
|
117
|
+
const piRuntime = worker.acpSpawn?.piRuntime;
|
|
118
|
+
let issueNumber;
|
|
119
|
+
if (piRuntime === 'builtin') {
|
|
120
|
+
try {
|
|
121
|
+
issueNumber = parseIssueUrl(located.resumeStore.issueUrl).number;
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
throw new WorkerSessionHistoryUnavailableError('SessionResumeStore に有効な Issue URL がないため、builtin Pi の保存先を解決できません。');
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
const readerInput = {
|
|
128
|
+
repoRoot,
|
|
129
|
+
fallbackRepoRoots: [located.resumeStore.repoRoot],
|
|
130
|
+
...(input.userEnsembleRoot
|
|
131
|
+
? { userEnsembleRoot: input.userEnsembleRoot }
|
|
132
|
+
: {}),
|
|
133
|
+
workerName,
|
|
134
|
+
acpSessionId: worker.acpSessionId,
|
|
135
|
+
acpCwd: worker.acpCwd,
|
|
136
|
+
...(piRuntime
|
|
137
|
+
? { piRuntime }
|
|
138
|
+
: {}),
|
|
139
|
+
...(issueNumber !== undefined ? { issueNumber } : {}),
|
|
140
|
+
};
|
|
141
|
+
const result = input.includeSourceFiles
|
|
142
|
+
? await reader.readWithSources(readerInput)
|
|
143
|
+
: {
|
|
144
|
+
messages: await reader.read(readerInput),
|
|
145
|
+
sourceFiles: [],
|
|
146
|
+
};
|
|
147
|
+
return {
|
|
148
|
+
...base,
|
|
149
|
+
status: 'supported',
|
|
150
|
+
messages: result.messages,
|
|
151
|
+
...(input.includeSourceFiles
|
|
152
|
+
? { sourceFiles: result.sourceFiles }
|
|
153
|
+
: {}),
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
catch (error) {
|
|
157
|
+
if (!(error instanceof WorkerSessionHistoryUnavailableError)) {
|
|
158
|
+
throw error;
|
|
159
|
+
}
|
|
160
|
+
return {
|
|
161
|
+
...base,
|
|
162
|
+
status: 'unavailable',
|
|
163
|
+
reason: error.message,
|
|
164
|
+
messages: [],
|
|
165
|
+
...(input.includeSourceFiles ? { sourceFiles: [] } : {}),
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
async function findUserWorkerSessionResumeStore(input) {
|
|
170
|
+
if (!input.githubRepo && !input.issueUrl) {
|
|
171
|
+
throw new Error('Repository scope is required to read a session; pass githubRepo or issueUrl.');
|
|
172
|
+
}
|
|
173
|
+
const page = await listUserLocatedSessionResumeStoresPage({
|
|
174
|
+
githubRepo: input.githubRepo,
|
|
175
|
+
issueUrl: input.issueUrl,
|
|
176
|
+
conductorAgentId: input.conductorAgentId,
|
|
177
|
+
}, { userEnsembleRoot: input.userEnsembleRoot });
|
|
178
|
+
if (page.sessions.length > 1) {
|
|
179
|
+
throw new Error(`Session ${input.conductorAgentId} is ambiguous in this repository; specify issueUrl.`);
|
|
180
|
+
}
|
|
181
|
+
return page.sessions[0];
|
|
182
|
+
}
|
|
183
|
+
function requireRepoRoot(value) {
|
|
184
|
+
if (!value?.trim()) {
|
|
185
|
+
throw new Error('repoRoot is required to read a repository-scoped session.');
|
|
186
|
+
}
|
|
187
|
+
return resolve(value);
|
|
188
|
+
}
|
|
189
|
+
class WorkerSessionHistoryUnavailableError extends Error {
|
|
190
|
+
constructor(message) {
|
|
191
|
+
super(message);
|
|
192
|
+
this.name = 'WorkerSessionHistoryUnavailableError';
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
async function readPiAcpSessionHistoryWithSources(input) {
|
|
196
|
+
const paths = input.piRuntime === 'builtin'
|
|
197
|
+
? resolveEnsemblePaths({
|
|
198
|
+
repoRoot: input.repoRoot,
|
|
199
|
+
userEnsembleRoot: input.userEnsembleRoot,
|
|
200
|
+
})
|
|
201
|
+
: undefined;
|
|
202
|
+
let session;
|
|
203
|
+
let foundMap = false;
|
|
204
|
+
let malformedMap = false;
|
|
205
|
+
let sessionMapPaths;
|
|
206
|
+
if (paths) {
|
|
207
|
+
const issueNumber = input.issueNumber;
|
|
208
|
+
if (issueNumber === undefined ||
|
|
209
|
+
!Number.isSafeInteger(issueNumber) ||
|
|
210
|
+
issueNumber < 1) {
|
|
211
|
+
throw new WorkerSessionHistoryUnavailableError('builtin Pi の Issue number がなく、session map を解決できません。');
|
|
212
|
+
}
|
|
213
|
+
sessionMapPaths = [
|
|
214
|
+
...[input.repoRoot, ...(input.fallbackRepoRoots ?? [])].flatMap((repoRoot) => {
|
|
215
|
+
const rootPaths = resolveEnsemblePaths({
|
|
216
|
+
repoRoot,
|
|
217
|
+
userEnsembleRoot: input.userEnsembleRoot,
|
|
218
|
+
});
|
|
219
|
+
const mapPaths = resolvePiAcpSessionMapPaths(rootPaths.piWorkerDir(input.workerName, issueNumber), rootPaths.legacyPiWorkerDir(input.workerName));
|
|
220
|
+
return [mapPaths.upstreamPath, ...mapPaths.compatibilityPaths];
|
|
221
|
+
}),
|
|
222
|
+
];
|
|
223
|
+
}
|
|
224
|
+
else {
|
|
225
|
+
sessionMapPaths = [join(homedir(), '.pi', 'pi-acp', 'session-map.json')];
|
|
226
|
+
}
|
|
227
|
+
for (const path of new Set(sessionMapPaths)) {
|
|
228
|
+
let raw;
|
|
229
|
+
try {
|
|
230
|
+
raw = await readFile(path, 'utf8');
|
|
231
|
+
foundMap = true;
|
|
232
|
+
}
|
|
233
|
+
catch (error) {
|
|
234
|
+
if (isEnoent(error))
|
|
235
|
+
continue;
|
|
236
|
+
throw new WorkerSessionHistoryUnavailableError('Pi ACP の session map を読み取れませんでした。');
|
|
237
|
+
}
|
|
238
|
+
let parsed;
|
|
239
|
+
try {
|
|
240
|
+
parsed = JSON.parse(raw);
|
|
241
|
+
}
|
|
242
|
+
catch {
|
|
243
|
+
malformedMap = true;
|
|
244
|
+
continue;
|
|
245
|
+
}
|
|
246
|
+
session = findPiAcpSessionMapEntry(parsed, input.acpSessionId);
|
|
247
|
+
if (session)
|
|
248
|
+
break;
|
|
249
|
+
}
|
|
250
|
+
if (!session) {
|
|
251
|
+
if (!foundMap) {
|
|
252
|
+
throw new WorkerSessionHistoryUnavailableError('Pi ACP の session map が見つかりません。');
|
|
253
|
+
}
|
|
254
|
+
if (malformedMap) {
|
|
255
|
+
throw new WorkerSessionHistoryUnavailableError('Pi ACP の session map が不正な JSON です。');
|
|
256
|
+
}
|
|
257
|
+
throw new WorkerSessionHistoryUnavailableError('Pi ACP の session map に対象 session がありません。');
|
|
258
|
+
}
|
|
259
|
+
if (!isAbsolute(session.cwd) || resolve(session.cwd) !== resolve(input.acpCwd)) {
|
|
260
|
+
throw new WorkerSessionHistoryUnavailableError('Pi ACP session map の cwd が SessionResumeStore と一致しません。');
|
|
261
|
+
}
|
|
262
|
+
if (!isAbsolute(session.sessionFile) ||
|
|
263
|
+
extname(session.sessionFile).toLowerCase() !== '.jsonl') {
|
|
264
|
+
throw new WorkerSessionHistoryUnavailableError('Pi ACP session map に有効な transcript path がありません。');
|
|
265
|
+
}
|
|
266
|
+
let transcriptStat;
|
|
267
|
+
try {
|
|
268
|
+
transcriptStat = await stat(session.sessionFile);
|
|
269
|
+
}
|
|
270
|
+
catch (error) {
|
|
271
|
+
if (isEnoent(error)) {
|
|
272
|
+
throw new WorkerSessionHistoryUnavailableError('Pi ACP session map が指す transcript file が見つかりません。');
|
|
273
|
+
}
|
|
274
|
+
throw new WorkerSessionHistoryUnavailableError('Pi ACP transcript file を読み取れませんでした。');
|
|
275
|
+
}
|
|
276
|
+
if (!transcriptStat.isFile()) {
|
|
277
|
+
throw new WorkerSessionHistoryUnavailableError('Pi ACP session map が指す transcript path は file ではありません。');
|
|
278
|
+
}
|
|
279
|
+
let transcript;
|
|
280
|
+
try {
|
|
281
|
+
transcript = await readFile(session.sessionFile, 'utf8');
|
|
282
|
+
}
|
|
283
|
+
catch (error) {
|
|
284
|
+
if (isEnoent(error)) {
|
|
285
|
+
throw new WorkerSessionHistoryUnavailableError('Pi ACP session map が指す transcript file が見つかりません。');
|
|
286
|
+
}
|
|
287
|
+
throw new WorkerSessionHistoryUnavailableError('Pi ACP transcript file を読み取れませんでした。');
|
|
288
|
+
}
|
|
289
|
+
const entries = parseSessionEntries(transcript);
|
|
290
|
+
const header = getPiSessionHeader(entries[0]);
|
|
291
|
+
if (!header) {
|
|
292
|
+
throw new WorkerSessionHistoryUnavailableError('Pi ACP transcript に有効な session header がありません。');
|
|
293
|
+
}
|
|
294
|
+
if (header.id !== input.acpSessionId) {
|
|
295
|
+
throw new WorkerSessionHistoryUnavailableError('Pi ACP transcript の session ID が保存状態と一致しません。');
|
|
296
|
+
}
|
|
297
|
+
if (!isAbsolute(header.cwd) ||
|
|
298
|
+
resolve(header.cwd) !== resolve(input.acpCwd)) {
|
|
299
|
+
throw new WorkerSessionHistoryUnavailableError('Pi ACP transcript header の cwd が保存状態と一致しません。');
|
|
300
|
+
}
|
|
301
|
+
let sessionManager;
|
|
302
|
+
try {
|
|
303
|
+
// `open()` persists empty-session initialization and legacy migrations.
|
|
304
|
+
sessionManager = SessionManager.inMemory(header.cwd, undefined, entries);
|
|
305
|
+
}
|
|
306
|
+
catch {
|
|
307
|
+
throw new WorkerSessionHistoryUnavailableError('Pi ACP transcript を Pi session format として読み取れませんでした。');
|
|
308
|
+
}
|
|
309
|
+
if (sessionManager.getSessionId() !== input.acpSessionId) {
|
|
310
|
+
throw new WorkerSessionHistoryUnavailableError('Pi ACP transcript の session ID が保存状態と一致しません。');
|
|
311
|
+
}
|
|
312
|
+
let branch;
|
|
313
|
+
try {
|
|
314
|
+
branch = sessionManager.getBranch();
|
|
315
|
+
}
|
|
316
|
+
catch {
|
|
317
|
+
throw new WorkerSessionHistoryUnavailableError('Pi ACP transcript の active branch を読み取れませんでした。');
|
|
318
|
+
}
|
|
319
|
+
return {
|
|
320
|
+
messages: branch.flatMap((entry) => {
|
|
321
|
+
if (!isSessionMessageEntry(entry))
|
|
322
|
+
return [];
|
|
323
|
+
const role = entry.message.role;
|
|
324
|
+
if (role !== 'user' && role !== 'assistant')
|
|
325
|
+
return [];
|
|
326
|
+
const text = extractPiMessageText(entry.message.content);
|
|
327
|
+
if (!text.trim())
|
|
328
|
+
return [];
|
|
329
|
+
const at = getMessageTimestamp(entry);
|
|
330
|
+
return [
|
|
331
|
+
{
|
|
332
|
+
source: `worker:${input.workerName}`,
|
|
333
|
+
providerId: entry.id,
|
|
334
|
+
role,
|
|
335
|
+
...(at !== undefined ? { at } : {}),
|
|
336
|
+
text,
|
|
337
|
+
},
|
|
338
|
+
];
|
|
339
|
+
}),
|
|
340
|
+
sourceFiles: [session.sessionFile],
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
async function readCodexAcpSessionHistoryWithSources(input) {
|
|
344
|
+
const sessionId = input.acpSessionId.trim();
|
|
345
|
+
if (!sessionId) {
|
|
346
|
+
throw new WorkerSessionHistoryUnavailableError('SessionResumeStore に Codex ACP session ID がありません。');
|
|
347
|
+
}
|
|
348
|
+
if (!isAbsolute(input.acpCwd)) {
|
|
349
|
+
throw new WorkerSessionHistoryUnavailableError('SessionResumeStore に有効な Codex ACP cwd がありません。');
|
|
350
|
+
}
|
|
351
|
+
const codexHome = resolveCodexHome(input.acpCwd);
|
|
352
|
+
const rolloutPath = await findCodexAcpRollout(codexHome, sessionId);
|
|
353
|
+
if (!rolloutPath) {
|
|
354
|
+
throw new WorkerSessionHistoryUnavailableError('現在の Codex home に対象 session の rollout が見つかりません。');
|
|
355
|
+
}
|
|
356
|
+
let decompressor;
|
|
357
|
+
if (rolloutPath.endsWith('.jsonl.zst')) {
|
|
358
|
+
const zlib = await import('node:zlib');
|
|
359
|
+
const createZstdDecompress = zlib.createZstdDecompress;
|
|
360
|
+
if (!createZstdDecompress) {
|
|
361
|
+
throw new WorkerSessionHistoryUnavailableError('現在の Node.js は Codex の圧縮 rollout(zstd)に対応していません。');
|
|
362
|
+
}
|
|
363
|
+
decompressor = createZstdDecompress();
|
|
364
|
+
}
|
|
365
|
+
const sourceStream = createReadStream(rolloutPath);
|
|
366
|
+
const inputStream = decompressor
|
|
367
|
+
? sourceStream.pipe(decompressor)
|
|
368
|
+
: sourceStream;
|
|
369
|
+
let streamError;
|
|
370
|
+
const recordStreamError = (error) => {
|
|
371
|
+
streamError ??= error;
|
|
372
|
+
};
|
|
373
|
+
sourceStream.on('error', (error) => {
|
|
374
|
+
recordStreamError(error);
|
|
375
|
+
if (decompressor)
|
|
376
|
+
decompressor.destroy(error);
|
|
377
|
+
});
|
|
378
|
+
if (decompressor)
|
|
379
|
+
decompressor.on('error', recordStreamError);
|
|
380
|
+
try {
|
|
381
|
+
const lines = createInterface({
|
|
382
|
+
input: inputStream,
|
|
383
|
+
crlfDelay: Infinity,
|
|
384
|
+
});
|
|
385
|
+
let header;
|
|
386
|
+
let lineNumber = 0;
|
|
387
|
+
const messages = [];
|
|
388
|
+
try {
|
|
389
|
+
for await (const line of lines) {
|
|
390
|
+
lineNumber += 1;
|
|
391
|
+
if (!line.trim())
|
|
392
|
+
continue;
|
|
393
|
+
let envelope;
|
|
394
|
+
try {
|
|
395
|
+
envelope = JSON.parse(line);
|
|
396
|
+
}
|
|
397
|
+
catch {
|
|
398
|
+
throw new WorkerSessionHistoryUnavailableError('Codex CLI rollout の JSONL に不正な行があります。');
|
|
399
|
+
}
|
|
400
|
+
if (!header) {
|
|
401
|
+
header = getCodexSessionHeader(envelope);
|
|
402
|
+
if (!header) {
|
|
403
|
+
throw new WorkerSessionHistoryUnavailableError('Codex CLI rollout に有効な session_meta がありません。');
|
|
404
|
+
}
|
|
405
|
+
if (header.id !== sessionId) {
|
|
406
|
+
throw new WorkerSessionHistoryUnavailableError('Codex CLI rollout の session ID が保存状態と一致しません。');
|
|
407
|
+
}
|
|
408
|
+
if (!isAbsolute(header.cwd) ||
|
|
409
|
+
resolve(header.cwd) !== resolve(input.acpCwd)) {
|
|
410
|
+
throw new WorkerSessionHistoryUnavailableError('Codex CLI rollout の cwd が保存状態と一致しません。');
|
|
411
|
+
}
|
|
412
|
+
continue;
|
|
413
|
+
}
|
|
414
|
+
const message = codexRolloutMessage(envelope, input.workerName, lineNumber);
|
|
415
|
+
if (message)
|
|
416
|
+
messages.push(message);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
finally {
|
|
420
|
+
lines.close();
|
|
421
|
+
}
|
|
422
|
+
if (streamError) {
|
|
423
|
+
throw new WorkerSessionHistoryUnavailableError('Codex CLI rollout を読み取れませんでした。');
|
|
424
|
+
}
|
|
425
|
+
if (!header) {
|
|
426
|
+
throw new WorkerSessionHistoryUnavailableError('Codex CLI rollout に有効な session_meta がありません。');
|
|
427
|
+
}
|
|
428
|
+
return {
|
|
429
|
+
messages,
|
|
430
|
+
sourceFiles: [rolloutPath],
|
|
431
|
+
};
|
|
432
|
+
}
|
|
433
|
+
catch (error) {
|
|
434
|
+
if (error instanceof WorkerSessionHistoryUnavailableError)
|
|
435
|
+
throw error;
|
|
436
|
+
throw new WorkerSessionHistoryUnavailableError('Codex CLI rollout を読み取れませんでした。');
|
|
437
|
+
}
|
|
438
|
+
finally {
|
|
439
|
+
decompressor?.destroy();
|
|
440
|
+
sourceStream.destroy();
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
function resolveCodexHome(acpCwd) {
|
|
444
|
+
const configuredHome = process.env.CODEX_HOME;
|
|
445
|
+
if (configuredHome) {
|
|
446
|
+
return resolve(acpCwd, configuredHome);
|
|
447
|
+
}
|
|
448
|
+
return join(homedir(), '.codex');
|
|
449
|
+
}
|
|
450
|
+
async function findCodexAcpRollout(codexHome, sessionId) {
|
|
451
|
+
const candidates = [];
|
|
452
|
+
for (const directoryName of ['sessions', 'archived_sessions']) {
|
|
453
|
+
const directory = join(codexHome, directoryName);
|
|
454
|
+
await collectCodexAcpRolloutCandidates(directory, sessionId, candidates);
|
|
455
|
+
}
|
|
456
|
+
if (candidates.length > 1) {
|
|
457
|
+
throw new WorkerSessionHistoryUnavailableError('Codex CLI store に同じ session ID の rollout が複数あり、対象を一意に決められません。');
|
|
458
|
+
}
|
|
459
|
+
return candidates[0]?.path;
|
|
460
|
+
}
|
|
461
|
+
async function collectCodexAcpRolloutCandidates(directory, sessionId, candidates) {
|
|
462
|
+
let entries;
|
|
463
|
+
try {
|
|
464
|
+
entries = await readdir(directory, { withFileTypes: true });
|
|
465
|
+
}
|
|
466
|
+
catch (error) {
|
|
467
|
+
if (isEnoent(error))
|
|
468
|
+
return;
|
|
469
|
+
throw new WorkerSessionHistoryUnavailableError('Codex CLI store を探索できませんでした。');
|
|
470
|
+
}
|
|
471
|
+
const plainRolloutNames = new Set(entries
|
|
472
|
+
.filter((entry) => entry.isFile() && entry.name.endsWith('.jsonl'))
|
|
473
|
+
.map((entry) => entry.name));
|
|
474
|
+
for (const entry of entries) {
|
|
475
|
+
const path = join(directory, entry.name);
|
|
476
|
+
if (entry.isDirectory()) {
|
|
477
|
+
await collectCodexAcpRolloutCandidates(path, sessionId, candidates);
|
|
478
|
+
continue;
|
|
479
|
+
}
|
|
480
|
+
if (!entry.isFile())
|
|
481
|
+
continue;
|
|
482
|
+
const plainFileName = codexRolloutPlainFileName(entry.name);
|
|
483
|
+
if (!plainFileName ||
|
|
484
|
+
(entry.name.endsWith('.jsonl.zst') &&
|
|
485
|
+
plainRolloutNames.has(plainFileName))) {
|
|
486
|
+
continue;
|
|
487
|
+
}
|
|
488
|
+
const threadId = codexThreadIdFromRolloutFileName(entry.name);
|
|
489
|
+
if (threadId !== sessionId)
|
|
490
|
+
continue;
|
|
491
|
+
candidates.push({ path });
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
function codexRolloutPlainFileName(fileName) {
|
|
495
|
+
if (fileName.endsWith('.jsonl.zst'))
|
|
496
|
+
return fileName.slice(0, -4);
|
|
497
|
+
if (fileName.endsWith('.jsonl'))
|
|
498
|
+
return fileName;
|
|
499
|
+
return undefined;
|
|
500
|
+
}
|
|
501
|
+
function codexThreadIdFromRolloutFileName(fileName) {
|
|
502
|
+
const plainFileName = codexRolloutPlainFileName(fileName);
|
|
503
|
+
if (!plainFileName)
|
|
504
|
+
return undefined;
|
|
505
|
+
const baseName = plainFileName.slice(0, -'.jsonl'.length);
|
|
506
|
+
if (!baseName.startsWith('rollout-'))
|
|
507
|
+
return undefined;
|
|
508
|
+
const identity = baseName.slice('rollout-'.length);
|
|
509
|
+
const timestamp = identity.slice(0, 19);
|
|
510
|
+
if (!/^\d{4}-\d{2}-\d{2}T\d{2}-\d{2}-\d{2}$/u.test(timestamp) ||
|
|
511
|
+
identity[19] !== '-') {
|
|
512
|
+
return undefined;
|
|
513
|
+
}
|
|
514
|
+
const rolloutIds = identity.slice(20);
|
|
515
|
+
const separator = rolloutIds.indexOf('_');
|
|
516
|
+
const threadId = separator < 0 ? rolloutIds : rolloutIds.slice(0, separator);
|
|
517
|
+
const rolloutId = separator < 0 ? threadId : rolloutIds.slice(separator + 1);
|
|
518
|
+
if (!threadId || (separator >= 0 && !rolloutIds.slice(separator + 1))) {
|
|
519
|
+
return undefined;
|
|
520
|
+
}
|
|
521
|
+
if (!CODEX_UUID_PATTERN.test(threadId) ||
|
|
522
|
+
!CODEX_UUID_PATTERN.test(rolloutId) ||
|
|
523
|
+
!isCodexRolloutTimestamp(timestamp)) {
|
|
524
|
+
return undefined;
|
|
525
|
+
}
|
|
526
|
+
return threadId;
|
|
527
|
+
}
|
|
528
|
+
function isCodexRolloutTimestamp(value) {
|
|
529
|
+
const isoTimestamp = `${value.slice(0, 10)}T${value.slice(11, 13)}:${value.slice(14, 16)}:${value.slice(17, 19)}Z`;
|
|
530
|
+
const timestamp = new Date(isoTimestamp);
|
|
531
|
+
return (Number.isFinite(timestamp.getTime()) &&
|
|
532
|
+
timestamp.toISOString().slice(0, 19).replaceAll(':', '-') === value);
|
|
533
|
+
}
|
|
534
|
+
function getCodexSessionHeader(value) {
|
|
535
|
+
if (!isRecord(value) ||
|
|
536
|
+
value.type !== 'session_meta' ||
|
|
537
|
+
!isRecord(value.payload) ||
|
|
538
|
+
typeof value.payload.id !== 'string' ||
|
|
539
|
+
!value.payload.id.trim() ||
|
|
540
|
+
typeof value.payload.cwd !== 'string' ||
|
|
541
|
+
!value.payload.cwd.trim()) {
|
|
542
|
+
return undefined;
|
|
543
|
+
}
|
|
544
|
+
return {
|
|
545
|
+
id: value.payload.id,
|
|
546
|
+
cwd: value.payload.cwd,
|
|
547
|
+
};
|
|
548
|
+
}
|
|
549
|
+
function codexRolloutMessage(value, workerName, lineNumber) {
|
|
550
|
+
if (!isRecord(value) ||
|
|
551
|
+
value.type !== 'response_item' ||
|
|
552
|
+
!isRecord(value.payload) ||
|
|
553
|
+
value.payload.type !== 'message' ||
|
|
554
|
+
(value.payload.role !== 'user' && value.payload.role !== 'assistant')) {
|
|
555
|
+
return undefined;
|
|
556
|
+
}
|
|
557
|
+
const text = extractCodexMessageText(value.payload.content);
|
|
558
|
+
if (!text.trim())
|
|
559
|
+
return undefined;
|
|
560
|
+
const ordinal = value.ordinal;
|
|
561
|
+
const providerId = typeof ordinal === 'number' && Number.isSafeInteger(ordinal)
|
|
562
|
+
? `codex:${ordinal}`
|
|
563
|
+
: `codex:${lineNumber}`;
|
|
564
|
+
const timestamp = typeof value.timestamp === 'string' ? Date.parse(value.timestamp) : NaN;
|
|
565
|
+
return {
|
|
566
|
+
source: `worker:${workerName}`,
|
|
567
|
+
providerId,
|
|
568
|
+
role: value.payload.role,
|
|
569
|
+
...(Number.isFinite(timestamp) ? { at: timestamp } : {}),
|
|
570
|
+
text,
|
|
571
|
+
};
|
|
572
|
+
}
|
|
573
|
+
function extractCodexMessageText(content) {
|
|
574
|
+
if (typeof content === 'string')
|
|
575
|
+
return content;
|
|
576
|
+
if (!Array.isArray(content))
|
|
577
|
+
return '';
|
|
578
|
+
return content
|
|
579
|
+
.filter((block) => isRecord(block) &&
|
|
580
|
+
(block.type === 'input_text' || block.type === 'output_text') &&
|
|
581
|
+
typeof block.text === 'string')
|
|
582
|
+
.map((block) => block.text)
|
|
583
|
+
.join('');
|
|
584
|
+
}
|
|
585
|
+
function getPiSessionHeader(value) {
|
|
586
|
+
if (!isRecord(value) ||
|
|
587
|
+
value.type !== 'session' ||
|
|
588
|
+
typeof value.id !== 'string' ||
|
|
589
|
+
!value.id.trim() ||
|
|
590
|
+
typeof value.cwd !== 'string' ||
|
|
591
|
+
!value.cwd.trim()) {
|
|
592
|
+
return undefined;
|
|
593
|
+
}
|
|
594
|
+
return { id: value.id, cwd: value.cwd };
|
|
595
|
+
}
|
|
596
|
+
function findPiAcpSessionMapEntry(value, sessionId) {
|
|
597
|
+
if (!isRecord(value) || value.version !== 1 || !isRecord(value.sessions)) {
|
|
598
|
+
return undefined;
|
|
599
|
+
}
|
|
600
|
+
const entry = value.sessions[sessionId];
|
|
601
|
+
if (!isRecord(entry) ||
|
|
602
|
+
entry.sessionId !== sessionId ||
|
|
603
|
+
typeof entry.cwd !== 'string' ||
|
|
604
|
+
typeof entry.sessionFile !== 'string') {
|
|
605
|
+
return undefined;
|
|
606
|
+
}
|
|
607
|
+
return {
|
|
608
|
+
sessionId,
|
|
609
|
+
cwd: entry.cwd,
|
|
610
|
+
sessionFile: entry.sessionFile,
|
|
611
|
+
};
|
|
612
|
+
}
|
|
613
|
+
function isSessionMessageEntry(entry) {
|
|
614
|
+
return (isRecord(entry) &&
|
|
615
|
+
entry.type === 'message' &&
|
|
616
|
+
isRecord(entry.message) &&
|
|
617
|
+
typeof entry.message.role === 'string');
|
|
618
|
+
}
|
|
619
|
+
function extractPiMessageText(content) {
|
|
620
|
+
if (typeof content === 'string')
|
|
621
|
+
return content;
|
|
622
|
+
if (!Array.isArray(content))
|
|
623
|
+
return '';
|
|
624
|
+
return content
|
|
625
|
+
.filter((block) => isRecord(block) &&
|
|
626
|
+
block.type === 'text' &&
|
|
627
|
+
typeof block.text === 'string')
|
|
628
|
+
.map((block) => block.text)
|
|
629
|
+
.join('');
|
|
630
|
+
}
|
|
631
|
+
function getMessageTimestamp(entry) {
|
|
632
|
+
const messageTimestamp = entry.message.timestamp;
|
|
633
|
+
if (typeof messageTimestamp === 'number' &&
|
|
634
|
+
Number.isFinite(messageTimestamp)) {
|
|
635
|
+
return messageTimestamp;
|
|
636
|
+
}
|
|
637
|
+
const entryTimestamp = Date.parse(entry.timestamp);
|
|
638
|
+
return Number.isFinite(entryTimestamp) ? entryTimestamp : undefined;
|
|
639
|
+
}
|
|
640
|
+
function isRecord(value) {
|
|
641
|
+
return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
|
|
642
|
+
}
|
|
643
|
+
function isEnoent(error) {
|
|
644
|
+
return (isRecord(error) &&
|
|
645
|
+
error.code === 'ENOENT');
|
|
646
|
+
}
|
|
647
|
+
function requireNonEmpty(value, name) {
|
|
648
|
+
const normalized = value.trim();
|
|
649
|
+
if (!normalized) {
|
|
650
|
+
throw new Error(`${name} must be a non-empty string.`);
|
|
651
|
+
}
|
|
652
|
+
return normalized;
|
|
653
|
+
}
|
|
654
|
+
//# sourceMappingURL=worker-session-history.js.map
|