slacklocalvibe 0.1.1 → 0.1.3
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/package.json +1 -1
- package/src/cli.js +2 -1
- package/src/commands/notify.js +13 -0
- package/src/commands/wizard.js +188 -15
- package/src/lib/notify-input.js +177 -16
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -4,13 +4,14 @@ const { runWizard } = require("./commands/wizard");
|
|
|
4
4
|
const { runNotify } = require("./commands/notify");
|
|
5
5
|
const { runDaemon } = require("./commands/daemon");
|
|
6
6
|
const { runLaunchd } = require("./commands/launchd");
|
|
7
|
+
const packageJson = require("../package.json");
|
|
7
8
|
|
|
8
9
|
const program = new Command();
|
|
9
10
|
|
|
10
11
|
program
|
|
11
12
|
.name("slacklocalvibe")
|
|
12
13
|
.description("SlackLocalVibe: Slack DM通知 + 返信resumeブリッジ")
|
|
13
|
-
.version(
|
|
14
|
+
.version(packageJson.version);
|
|
14
15
|
|
|
15
16
|
program
|
|
16
17
|
.command("notify")
|
package/src/commands/notify.js
CHANGED
|
@@ -75,6 +75,19 @@ async function runNotify({ tool }) {
|
|
|
75
75
|
});
|
|
76
76
|
return;
|
|
77
77
|
}
|
|
78
|
+
if (input.tool === "codex") {
|
|
79
|
+
const meta = input.meta || {};
|
|
80
|
+
log(LEVELS.INFO, "notify.codex_prompt_source", {
|
|
81
|
+
rollout_found: meta.codex_rollout_found,
|
|
82
|
+
rollout_source: meta.codex_rollout_source,
|
|
83
|
+
rollout_path: meta.codex_rollout_path,
|
|
84
|
+
rollout_user_messages: meta.codex_rollout_user_message_count,
|
|
85
|
+
rollout_line_count: meta.codex_rollout_line_count,
|
|
86
|
+
input_messages_len: meta.input_messages_len,
|
|
87
|
+
input_messages_has_content: meta.input_messages_has_content,
|
|
88
|
+
rollout_error: meta.codex_rollout_error,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
78
91
|
|
|
79
92
|
if (!input.session_id) {
|
|
80
93
|
log(LEVELS.ERROR, "notify.session_missing");
|
package/src/commands/wizard.js
CHANGED
|
@@ -102,21 +102,76 @@ async function runWizard() {
|
|
|
102
102
|
console.log("SlackLocalVibe セットアップを開始します。");
|
|
103
103
|
if (normalized) {
|
|
104
104
|
console.log("既存設定が見つかりました。開始方法を選んでください。");
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
105
|
+
while (true) {
|
|
106
|
+
const choice = await promptSelect({
|
|
107
|
+
message: "どこから始めますか?",
|
|
108
|
+
choices: [
|
|
109
|
+
{ title: "アップデートを確認する", value: "update" },
|
|
110
|
+
{ title: "テストから始める", value: "test" },
|
|
111
|
+
{ title: "リセットして最初からセットアップ", value: "reset" },
|
|
112
|
+
{ title: "終了(保存せず終了)", value: "exit" },
|
|
113
|
+
],
|
|
114
|
+
initial: 0,
|
|
115
|
+
});
|
|
116
|
+
if (choice === "update") {
|
|
117
|
+
log(LEVELS.INFO, "wizard.update_check_start");
|
|
118
|
+
const versionInfo = await fetchUpdateVersions({ log });
|
|
119
|
+
log(LEVELS.INFO, "wizard.update_versions", {
|
|
120
|
+
installed: versionInfo.installedVersion || "unknown",
|
|
121
|
+
latest: versionInfo.latestVersion || "unknown",
|
|
122
|
+
});
|
|
123
|
+
console.log(formatInfo(`現在: ${formatVersionLabel(versionInfo.installedVersion)}`));
|
|
124
|
+
console.log(formatInfo(`最新: ${formatVersionLabel(versionInfo.latestVersion)}`));
|
|
125
|
+
if (
|
|
126
|
+
versionInfo.installedVersion &&
|
|
127
|
+
versionInfo.latestVersion &&
|
|
128
|
+
versionInfo.installedVersion === versionInfo.latestVersion
|
|
129
|
+
) {
|
|
130
|
+
log(LEVELS.SUCCRSS, "wizard.update_latest_confirmed");
|
|
131
|
+
console.log(formatSuccess("最新バージョンです。"));
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const updateChoice = await promptSelect({
|
|
136
|
+
message: "アップデートしますか?",
|
|
137
|
+
choices: [
|
|
138
|
+
{ title: "アップデートする", value: "update" },
|
|
139
|
+
{ title: "戻る", value: "back" },
|
|
140
|
+
{ title: "終了(保存せず終了)", value: "exit" },
|
|
141
|
+
],
|
|
142
|
+
initial: 0,
|
|
143
|
+
});
|
|
144
|
+
if (updateChoice === "back") {
|
|
145
|
+
log(LEVELS.INFO, "wizard.update_skipped");
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
if (updateChoice === "exit") {
|
|
149
|
+
throw new UserExit();
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
await ensureGlobalInstall({ log });
|
|
153
|
+
const postUpdate = await fetchUpdateVersions({ log });
|
|
154
|
+
log(LEVELS.SUCCRSS, "wizard.update_applied", {
|
|
155
|
+
installed: postUpdate.installedVersion || "unknown",
|
|
156
|
+
latest: postUpdate.latestVersion || "unknown",
|
|
157
|
+
});
|
|
158
|
+
console.log(formatSuccess("アップデートが完了しました。"));
|
|
159
|
+
console.log(formatInfo(`現在: ${formatVersionLabel(postUpdate.installedVersion)}`));
|
|
160
|
+
console.log(formatInfo(`最新: ${formatVersionLabel(postUpdate.latestVersion)}`));
|
|
161
|
+
|
|
162
|
+
const launchdRecommended = Boolean(normalized?.features?.launchd_enabled);
|
|
163
|
+
await promptLaunchdReinstall({ log, recommended: launchdRecommended });
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
if (choice === "reset") {
|
|
167
|
+
resetStoredConfig({ log });
|
|
168
|
+
break;
|
|
169
|
+
}
|
|
170
|
+
if (choice === "test") {
|
|
171
|
+
startFromTest = true;
|
|
172
|
+
console.log("既存設定を使って通知テストから開始します。");
|
|
173
|
+
break;
|
|
174
|
+
}
|
|
120
175
|
throw new UserExit();
|
|
121
176
|
}
|
|
122
177
|
}
|
|
@@ -1070,6 +1125,124 @@ async function ensureGlobalInstall({ log }) {
|
|
|
1070
1125
|
}
|
|
1071
1126
|
}
|
|
1072
1127
|
|
|
1128
|
+
async function fetchUpdateVersions({ log }) {
|
|
1129
|
+
const [installedVersion, latestVersion] = await Promise.all([
|
|
1130
|
+
fetchInstalledVersion({ log }),
|
|
1131
|
+
fetchRegistryVersion({ log }),
|
|
1132
|
+
]);
|
|
1133
|
+
return { installedVersion, latestVersion };
|
|
1134
|
+
}
|
|
1135
|
+
|
|
1136
|
+
async function fetchInstalledVersion({ log }) {
|
|
1137
|
+
try {
|
|
1138
|
+
const binaryPath = resolveBinaryPath();
|
|
1139
|
+
const result = await spawnCommand({
|
|
1140
|
+
command: binaryPath,
|
|
1141
|
+
args: ["--version"],
|
|
1142
|
+
cwd: process.cwd(),
|
|
1143
|
+
});
|
|
1144
|
+
if (result.code === 0) {
|
|
1145
|
+
const version = (result.stdoutText || "").trim().split(/\s+/)[0];
|
|
1146
|
+
if (version) return version;
|
|
1147
|
+
}
|
|
1148
|
+
log(LEVELS.WARNING, "wizard.update_installed_version_empty", {
|
|
1149
|
+
stdout_len: result.stdoutLen,
|
|
1150
|
+
stderr_len: result.stderrLen,
|
|
1151
|
+
});
|
|
1152
|
+
} catch (error) {
|
|
1153
|
+
log(LEVELS.WARNING, "wizard.update_installed_version_failed", {
|
|
1154
|
+
error: safeError(error),
|
|
1155
|
+
});
|
|
1156
|
+
}
|
|
1157
|
+
return "";
|
|
1158
|
+
}
|
|
1159
|
+
|
|
1160
|
+
async function fetchRegistryVersion({ log }) {
|
|
1161
|
+
try {
|
|
1162
|
+
const npmPath = resolveCommandPathStrict("npm");
|
|
1163
|
+
const result = await spawnCommand({
|
|
1164
|
+
command: npmPath,
|
|
1165
|
+
args: ["view", "slacklocalvibe", "version"],
|
|
1166
|
+
cwd: process.cwd(),
|
|
1167
|
+
});
|
|
1168
|
+
if (result.code === 0) {
|
|
1169
|
+
const version = (result.stdoutText || "").trim().split(/\s+/)[0];
|
|
1170
|
+
if (version) return version;
|
|
1171
|
+
}
|
|
1172
|
+
log(LEVELS.WARNING, "wizard.update_registry_version_empty", {
|
|
1173
|
+
stdout_len: result.stdoutLen,
|
|
1174
|
+
stderr_len: result.stderrLen,
|
|
1175
|
+
});
|
|
1176
|
+
} catch (error) {
|
|
1177
|
+
log(LEVELS.WARNING, "wizard.update_registry_version_failed", {
|
|
1178
|
+
error: safeError(error),
|
|
1179
|
+
});
|
|
1180
|
+
}
|
|
1181
|
+
return "";
|
|
1182
|
+
}
|
|
1183
|
+
|
|
1184
|
+
function formatVersionLabel(version) {
|
|
1185
|
+
return version ? version : "不明";
|
|
1186
|
+
}
|
|
1187
|
+
|
|
1188
|
+
async function promptLaunchdReinstall({ log, recommended }) {
|
|
1189
|
+
const title = recommended
|
|
1190
|
+
? "launchd を再登録する(推奨)"
|
|
1191
|
+
: "launchd を再登録する";
|
|
1192
|
+
while (true) {
|
|
1193
|
+
const choice = await promptSelect({
|
|
1194
|
+
message: "更新後に launchd を再登録します",
|
|
1195
|
+
choices: [
|
|
1196
|
+
{ title, value: "install" },
|
|
1197
|
+
{ title: "あとでやる", value: "skip" },
|
|
1198
|
+
{ title: "終了(保存せず終了)", value: "exit" },
|
|
1199
|
+
],
|
|
1200
|
+
initial: 0,
|
|
1201
|
+
});
|
|
1202
|
+
if (choice === "skip") {
|
|
1203
|
+
log(LEVELS.INFO, "wizard.launchd_reinstall_skipped");
|
|
1204
|
+
return;
|
|
1205
|
+
}
|
|
1206
|
+
if (choice === "exit") {
|
|
1207
|
+
throw new UserExit();
|
|
1208
|
+
}
|
|
1209
|
+
try {
|
|
1210
|
+
installLaunchd();
|
|
1211
|
+
log(LEVELS.SUCCRSS, "wizard.launchd_reinstalled");
|
|
1212
|
+
console.log(formatSuccess("launchd を再登録しました。"));
|
|
1213
|
+
return;
|
|
1214
|
+
} catch (error) {
|
|
1215
|
+
log(LEVELS.ERROR, "wizard.launchd_reinstall_failed", {
|
|
1216
|
+
error: safeError(error),
|
|
1217
|
+
});
|
|
1218
|
+
console.log(formatError("launchd の再登録に失敗しました。"));
|
|
1219
|
+
const detail =
|
|
1220
|
+
error?.detail ||
|
|
1221
|
+
error?.stderrText ||
|
|
1222
|
+
error?.stdoutText ||
|
|
1223
|
+
error?.message ||
|
|
1224
|
+
"unknown";
|
|
1225
|
+
if (detail) {
|
|
1226
|
+
console.log(formatError(detail));
|
|
1227
|
+
}
|
|
1228
|
+
const next = await promptSelect({
|
|
1229
|
+
message: "次の操作を選んでください",
|
|
1230
|
+
choices: [
|
|
1231
|
+
{ title: "再試行", value: "retry" },
|
|
1232
|
+
{ title: "あとでやる", value: "skip" },
|
|
1233
|
+
{ title: "終了(保存せず終了)", value: "exit" },
|
|
1234
|
+
],
|
|
1235
|
+
});
|
|
1236
|
+
if (next === "retry") continue;
|
|
1237
|
+
if (next === "skip") {
|
|
1238
|
+
log(LEVELS.WARNING, "wizard.launchd_reinstall_skipped_after_error");
|
|
1239
|
+
return;
|
|
1240
|
+
}
|
|
1241
|
+
throw new UserExit();
|
|
1242
|
+
}
|
|
1243
|
+
}
|
|
1244
|
+
}
|
|
1245
|
+
|
|
1073
1246
|
async function promptPassword({ message, validate }) {
|
|
1074
1247
|
while (true) {
|
|
1075
1248
|
const value = await promptVisible({ message });
|
package/src/lib/notify-input.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
const fs = require("fs");
|
|
2
|
+
const os = require("os");
|
|
3
|
+
const path = require("path");
|
|
2
4
|
|
|
3
5
|
function parseCodexNotify(rawJson) {
|
|
4
6
|
const payload = JSON.parse(rawJson);
|
|
@@ -9,16 +11,9 @@ function parseCodexNotify(rawJson) {
|
|
|
9
11
|
const turnId = payload["turn-id"] ? String(payload["turn-id"]) : undefined;
|
|
10
12
|
const inputMessages = payload["input-messages"];
|
|
11
13
|
const meta = buildCodexInputMeta(inputMessages);
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
tool: "codex",
|
|
16
|
-
skip: true,
|
|
17
|
-
skip_reason: "empty_input_messages",
|
|
18
|
-
meta,
|
|
19
|
-
};
|
|
20
|
-
}
|
|
21
|
-
const userText = extractUserTextFromCodex(inputMessages);
|
|
14
|
+
const rolloutResult = readCodexUserMessageFromRollout(sessionId);
|
|
15
|
+
Object.assign(meta, rolloutResult.meta || {});
|
|
16
|
+
const userText = rolloutResult.userText || "";
|
|
22
17
|
const assistantText = extractAssistantText(payload["last-assistant-message"]);
|
|
23
18
|
const cwd = payload?.cwd ? String(payload.cwd) : "";
|
|
24
19
|
|
|
@@ -33,16 +28,11 @@ function parseCodexNotify(rawJson) {
|
|
|
33
28
|
};
|
|
34
29
|
}
|
|
35
30
|
|
|
36
|
-
function extractUserTextFromCodex(inputMessages) {
|
|
37
|
-
if (!Array.isArray(inputMessages) || inputMessages.length === 0) return "";
|
|
38
|
-
const lastMessage = inputMessages[inputMessages.length - 1];
|
|
39
|
-
return normalizeContent(lastMessage);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
31
|
function buildCodexInputMeta(inputMessages) {
|
|
43
32
|
const meta = {
|
|
44
33
|
input_messages_type: Array.isArray(inputMessages) ? "array" : typeof inputMessages,
|
|
45
34
|
input_messages_len: Array.isArray(inputMessages) ? inputMessages.length : 0,
|
|
35
|
+
input_messages_has_content: hasNonEmptyInputMessages(inputMessages),
|
|
46
36
|
input_messages_roles: [],
|
|
47
37
|
input_messages_last_role: "",
|
|
48
38
|
input_messages_last_type: "",
|
|
@@ -78,6 +68,177 @@ function extractAssistantText(content) {
|
|
|
78
68
|
return normalizeContent(content);
|
|
79
69
|
}
|
|
80
70
|
|
|
71
|
+
function readCodexUserMessageFromRollout(sessionId) {
|
|
72
|
+
const meta = {
|
|
73
|
+
codex_rollout_found: false,
|
|
74
|
+
codex_rollout_source: "",
|
|
75
|
+
codex_rollout_path: "",
|
|
76
|
+
codex_rollout_mtime_ms: 0,
|
|
77
|
+
codex_rollout_total: 0,
|
|
78
|
+
codex_rollout_user_message_count: 0,
|
|
79
|
+
codex_rollout_line_count: 0,
|
|
80
|
+
codex_rollout_error: "",
|
|
81
|
+
};
|
|
82
|
+
const rolloutPath = findCodexRolloutPath(sessionId, meta);
|
|
83
|
+
if (!rolloutPath) {
|
|
84
|
+
return { userText: "", meta };
|
|
85
|
+
}
|
|
86
|
+
try {
|
|
87
|
+
const content = fs.readFileSync(rolloutPath, "utf8");
|
|
88
|
+
const lines = content.split("\n").filter(Boolean);
|
|
89
|
+
meta.codex_rollout_line_count = lines.length;
|
|
90
|
+
let lastUser = "";
|
|
91
|
+
let lastTs = "";
|
|
92
|
+
let count = 0;
|
|
93
|
+
for (const line of lines) {
|
|
94
|
+
let record;
|
|
95
|
+
try {
|
|
96
|
+
record = JSON.parse(line);
|
|
97
|
+
} catch {
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
if (record?.type !== "event_msg") continue;
|
|
101
|
+
const payload = record?.payload;
|
|
102
|
+
if (payload?.type !== "user_message") continue;
|
|
103
|
+
const text = extractCodexUserMessage(payload);
|
|
104
|
+
if (text) {
|
|
105
|
+
lastUser = text;
|
|
106
|
+
lastTs = record?.timestamp || "";
|
|
107
|
+
}
|
|
108
|
+
count += 1;
|
|
109
|
+
}
|
|
110
|
+
meta.codex_rollout_user_message_count = count;
|
|
111
|
+
if (lastTs) {
|
|
112
|
+
meta.codex_rollout_last_user_ts = lastTs;
|
|
113
|
+
}
|
|
114
|
+
return { userText: lastUser, meta };
|
|
115
|
+
} catch (error) {
|
|
116
|
+
meta.codex_rollout_error = error?.message || "rollout_read_failed";
|
|
117
|
+
return { userText: "", meta };
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function extractCodexUserMessage(payload) {
|
|
122
|
+
if (!payload || typeof payload !== "object") return "";
|
|
123
|
+
const content =
|
|
124
|
+
payload.message ||
|
|
125
|
+
payload.text ||
|
|
126
|
+
payload.prompt ||
|
|
127
|
+
payload.input ||
|
|
128
|
+
payload.content;
|
|
129
|
+
return normalizeContent(content);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function findCodexRolloutPath(sessionId, meta) {
|
|
133
|
+
if (!sessionId) {
|
|
134
|
+
meta.codex_rollout_error = "session_id_missing";
|
|
135
|
+
return "";
|
|
136
|
+
}
|
|
137
|
+
const sessionsDir = path.join(os.homedir(), ".codex", "sessions");
|
|
138
|
+
meta.codex_sessions_dir = sessionsDir;
|
|
139
|
+
if (!fs.existsSync(sessionsDir)) {
|
|
140
|
+
meta.codex_rollout_error = "sessions_dir_missing";
|
|
141
|
+
return "";
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const files = collectRolloutFiles(sessionsDir);
|
|
145
|
+
meta.codex_rollout_total = files.length;
|
|
146
|
+
const byName = files.filter((item) => item.name.includes(sessionId));
|
|
147
|
+
if (byName.length > 0) {
|
|
148
|
+
const best = pickLatestFile(byName);
|
|
149
|
+
if (best) {
|
|
150
|
+
meta.codex_rollout_found = true;
|
|
151
|
+
meta.codex_rollout_source = "filename";
|
|
152
|
+
meta.codex_rollout_path = best.path;
|
|
153
|
+
meta.codex_rollout_mtime_ms = best.mtimeMs;
|
|
154
|
+
return best.path;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const byContent = findRolloutByContent(files, sessionId, meta);
|
|
159
|
+
if (byContent) {
|
|
160
|
+
meta.codex_rollout_found = true;
|
|
161
|
+
meta.codex_rollout_source = "content";
|
|
162
|
+
meta.codex_rollout_path = byContent.path;
|
|
163
|
+
meta.codex_rollout_mtime_ms = byContent.mtimeMs;
|
|
164
|
+
return byContent.path;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
meta.codex_rollout_error = meta.codex_rollout_error || "rollout_not_found";
|
|
168
|
+
return "";
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function collectRolloutFiles(rootDir) {
|
|
172
|
+
const results = [];
|
|
173
|
+
const stack = [rootDir];
|
|
174
|
+
while (stack.length > 0) {
|
|
175
|
+
const dir = stack.pop();
|
|
176
|
+
let entries;
|
|
177
|
+
try {
|
|
178
|
+
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
179
|
+
} catch {
|
|
180
|
+
continue;
|
|
181
|
+
}
|
|
182
|
+
for (const entry of entries) {
|
|
183
|
+
const fullPath = path.join(dir, entry.name);
|
|
184
|
+
if (entry.isDirectory()) {
|
|
185
|
+
stack.push(fullPath);
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
if (!entry.isFile()) continue;
|
|
189
|
+
if (!entry.name.startsWith("rollout-") || !entry.name.endsWith(".jsonl")) {
|
|
190
|
+
continue;
|
|
191
|
+
}
|
|
192
|
+
let stat;
|
|
193
|
+
try {
|
|
194
|
+
stat = fs.statSync(fullPath);
|
|
195
|
+
} catch {
|
|
196
|
+
continue;
|
|
197
|
+
}
|
|
198
|
+
results.push({
|
|
199
|
+
path: fullPath,
|
|
200
|
+
name: entry.name,
|
|
201
|
+
mtimeMs: stat.mtimeMs || 0,
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
return results;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function pickLatestFile(files) {
|
|
209
|
+
if (!files || files.length === 0) return null;
|
|
210
|
+
let best = files[0];
|
|
211
|
+
for (const item of files) {
|
|
212
|
+
if (item.mtimeMs > best.mtimeMs) {
|
|
213
|
+
best = item;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
return best;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function findRolloutByContent(files, sessionId, meta) {
|
|
220
|
+
if (!files || files.length === 0) {
|
|
221
|
+
meta.codex_rollout_error = "rollout_files_empty";
|
|
222
|
+
return null;
|
|
223
|
+
}
|
|
224
|
+
const sorted = [...files].sort((a, b) => b.mtimeMs - a.mtimeMs);
|
|
225
|
+
const limit = 30;
|
|
226
|
+
for (let i = 0; i < sorted.length && i < limit; i += 1) {
|
|
227
|
+
const file = sorted[i];
|
|
228
|
+
let content = "";
|
|
229
|
+
try {
|
|
230
|
+
content = fs.readFileSync(file.path, "utf8");
|
|
231
|
+
} catch {
|
|
232
|
+
continue;
|
|
233
|
+
}
|
|
234
|
+
if (content.includes(sessionId)) {
|
|
235
|
+
return file;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
meta.codex_rollout_error = "rollout_not_matched_in_recent_files";
|
|
239
|
+
return null;
|
|
240
|
+
}
|
|
241
|
+
|
|
81
242
|
function extractTextDeep(value, depth = 0) {
|
|
82
243
|
if (depth > 6) return "";
|
|
83
244
|
if (value === null || value === undefined) return "";
|