@liuyoumi/codex-history 0.5.1 → 0.6.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/CHANGELOG.md +6 -0
- package/README.en.md +5 -5
- package/README.md +5 -5
- package/dist/cli.js +24 -48
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
package/README.en.md
CHANGED
|
@@ -57,7 +57,7 @@ codex-history purge --grep "Astro"
|
|
|
57
57
|
codex-history purge-orphans
|
|
58
58
|
```
|
|
59
59
|
|
|
60
|
-
`purge` prints the resolved conversation
|
|
60
|
+
`purge` prints the resolved conversation, then shows a default-no `[y/N]` prompt. It deletes only after an explicit `y` or `yes`; pressing Enter, entering `n`, or entering anything else cancels:
|
|
61
61
|
|
|
62
62
|
```text
|
|
63
63
|
About to purge this local Codex conversation:
|
|
@@ -68,7 +68,7 @@ cwd: /Users/me/Projects/example
|
|
|
68
68
|
updated: 2026-05-28T03:16:01.959Z
|
|
69
69
|
|
|
70
70
|
This cannot be undone.
|
|
71
|
-
|
|
71
|
+
Proceed with permanent deletion? [y/N]:
|
|
72
72
|
```
|
|
73
73
|
|
|
74
74
|
## Commands
|
|
@@ -147,7 +147,7 @@ codex-history purge 019e6885
|
|
|
147
147
|
codex-history purge 019e6885 019e6874
|
|
148
148
|
```
|
|
149
149
|
|
|
150
|
-
When multiple targets are provided, the tool resolves all targets and prints a batch plan before deletion. If any id is missing, ambiguous, or active, the whole batch is refused before mutation. Interactive batch purge
|
|
150
|
+
When multiple targets are provided, the tool resolves all targets and prints a batch plan before deletion. If any id is missing, ambiguous, or active, the whole batch is refused before mutation. Interactive batch purge uses the same default-no `[y/N]` prompt and proceeds only after `y` or `yes`.
|
|
151
151
|
|
|
152
152
|
You can also select local conversations with filters:
|
|
153
153
|
|
|
@@ -158,7 +158,7 @@ codex-history purge --archived
|
|
|
158
158
|
codex-history purge --cwd /Users/me/Projects/example --grep "Astro"
|
|
159
159
|
```
|
|
160
160
|
|
|
161
|
-
`--cwd`, `--grep`, and `--archived` can be combined. Combined filters delete only conversations that match every provided condition. `--cwd` matches working-directory path fragments, while `--grep` matches only title, first user message, and preview. By default, filter mode matches non-archived conversations only; use `--archived` to target archived conversations. Filtered purge prints a batch plan and matched cwd values, then
|
|
161
|
+
`--cwd`, `--grep`, and `--archived` can be combined. Combined filters delete only conversations that match every provided condition. `--cwd` matches working-directory path fragments, while `--grep` matches only title, first user message, and preview. By default, filter mode matches non-archived conversations only; use `--archived` to target archived conversations. Filtered purge prints a batch plan and matched cwd values, then uses the default-no `[y/N]` prompt. Filters cannot be combined with explicit ids.
|
|
162
162
|
|
|
163
163
|
For scripts or non-interactive shells, use `--force`:
|
|
164
164
|
|
|
@@ -180,7 +180,7 @@ Remove orphaned local data: conversations whose `state_5.sqlite.threads.rollout_
|
|
|
180
180
|
codex-history purge-orphans
|
|
181
181
|
```
|
|
182
182
|
|
|
183
|
-
The command first prints a cleanup plan, affected SQLite row counts, files to delete, and an estimated local disk space impact.
|
|
183
|
+
The command first prints a cleanup plan, affected SQLite row counts, files to delete, and an estimated local disk space impact. It then shows the default-no `[y/N]` prompt and executes only after `y` or `yes`.
|
|
184
184
|
|
|
185
185
|
For scripts or non-interactive shells, use `--force`:
|
|
186
186
|
|
package/README.md
CHANGED
|
@@ -57,7 +57,7 @@ codex-history purge --grep "Astro"
|
|
|
57
57
|
codex-history purge-orphans
|
|
58
58
|
```
|
|
59
59
|
|
|
60
|
-
`purge`
|
|
60
|
+
`purge` 会先展示解析到的对话信息,再显示默认拒绝的 `[y/N]` 确认提示。只有显式输入 `y` 或 `yes` 才会删除;直接回车、输入 `n` 或任何其他内容都会取消:
|
|
61
61
|
|
|
62
62
|
```text
|
|
63
63
|
About to purge this local Codex conversation:
|
|
@@ -68,7 +68,7 @@ cwd: /Users/me/Projects/example
|
|
|
68
68
|
updated: 2026-05-28T03:16:01.959Z
|
|
69
69
|
|
|
70
70
|
This cannot be undone.
|
|
71
|
-
|
|
71
|
+
Proceed with permanent deletion? [y/N]:
|
|
72
72
|
```
|
|
73
73
|
|
|
74
74
|
## 命令
|
|
@@ -147,7 +147,7 @@ codex-history purge 019e6885
|
|
|
147
147
|
codex-history purge 019e6885 019e6874
|
|
148
148
|
```
|
|
149
149
|
|
|
150
|
-
删除多个目标时,工具会先解析全部目标并展示批量计划;只要任意一个 id 不存在、不唯一,或命中 active thread
|
|
150
|
+
删除多个目标时,工具会先解析全部目标并展示批量计划;只要任意一个 id 不存在、不唯一,或命中 active thread,整个批量操作都会拒绝执行,不会部分删除。交互式批量删除同样使用默认拒绝的 `[y/N]` 确认提示,只有输入 `y` 或 `yes` 才会继续。
|
|
151
151
|
|
|
152
152
|
也可以直接用过滤条件选择要删除的本地对话:
|
|
153
153
|
|
|
@@ -158,7 +158,7 @@ codex-history purge --archived
|
|
|
158
158
|
codex-history purge --cwd /Users/me/Projects/example --grep "Astro"
|
|
159
159
|
```
|
|
160
160
|
|
|
161
|
-
`--cwd`、`--grep`、`--archived` 可以组合,组合后只删除同时满足全部条件的对话。`--cwd` 会匹配工作目录路径片段,`--grep` 只匹配标题、首条用户消息和预览。默认只匹配未归档对话;如果要删除已归档对话,请使用 `--archived`。过滤式删除会展示批量计划和匹配到的 cwd
|
|
161
|
+
`--cwd`、`--grep`、`--archived` 可以组合,组合后只删除同时满足全部条件的对话。`--cwd` 会匹配工作目录路径片段,`--grep` 只匹配标题、首条用户消息和预览。默认只匹配未归档对话;如果要删除已归档对话,请使用 `--archived`。过滤式删除会展示批量计划和匹配到的 cwd,并使用默认拒绝的 `[y/N]` 确认提示。过滤条件不能和 id 同时使用。
|
|
162
162
|
|
|
163
163
|
脚本或非交互环境可以使用 `--force`:
|
|
164
164
|
|
|
@@ -180,7 +180,7 @@ codex-history purge --cwd /Users/me/Projects/example --force
|
|
|
180
180
|
codex-history purge-orphans
|
|
181
181
|
```
|
|
182
182
|
|
|
183
|
-
该命令会先展示清理计划、受影响的 SQLite
|
|
183
|
+
该命令会先展示清理计划、受影响的 SQLite 行数、将删除的文件数量,以及估算的本地磁盘空间影响。随后会显示默认拒绝的 `[y/N]` 确认提示;只有输入 `y` 或 `yes` 才会执行。
|
|
184
184
|
|
|
185
185
|
脚本或非交互环境可以使用 `--force`:
|
|
186
186
|
|
package/dist/cli.js
CHANGED
|
@@ -1105,6 +1105,12 @@ function executePurgeOrphansPlanCommand(paths, plan) {
|
|
|
1105
1105
|
return executePurgeOrphans(paths, plan);
|
|
1106
1106
|
}
|
|
1107
1107
|
|
|
1108
|
+
// src/core/confirmation.ts
|
|
1109
|
+
var affirmativeResponses = /* @__PURE__ */ new Set(["y", "yes"]);
|
|
1110
|
+
function isDestructiveActionConfirmed(answer) {
|
|
1111
|
+
return affirmativeResponses.has(answer.trim().toLowerCase());
|
|
1112
|
+
}
|
|
1113
|
+
|
|
1108
1114
|
// src/core/output.ts
|
|
1109
1115
|
function printOutput(value) {
|
|
1110
1116
|
if (typeof value === "string") {
|
|
@@ -1180,12 +1186,18 @@ program.command("purge").argument("[threadIds...]", "Codex thread id(s) or uniqu
|
|
|
1180
1186
|
}
|
|
1181
1187
|
if (plan.plans.length === 1 && !useBatchConfirmation) {
|
|
1182
1188
|
if (!force) {
|
|
1183
|
-
await
|
|
1189
|
+
await confirmDestructiveAction(
|
|
1190
|
+
"Purge requires an interactive terminal. Use --force to skip confirmation.",
|
|
1191
|
+
formatPurgeConfirmation(plan.plans[0])
|
|
1192
|
+
);
|
|
1184
1193
|
}
|
|
1185
1194
|
return formatPurgeResult(executePurgePlanCommand(paths, plan.plans[0]));
|
|
1186
1195
|
}
|
|
1187
1196
|
if (!force) {
|
|
1188
|
-
await
|
|
1197
|
+
await confirmDestructiveAction(
|
|
1198
|
+
"Batch purge requires an interactive terminal. Use --force to skip confirmation.",
|
|
1199
|
+
formatBatchPurgeConfirmation(plan)
|
|
1200
|
+
);
|
|
1189
1201
|
}
|
|
1190
1202
|
return formatBatchPurgeResult(executeBatchPurgePlanCommand(paths, plan));
|
|
1191
1203
|
})
|
|
@@ -1199,7 +1211,10 @@ program.command("purge-orphans").option("--force", "Skip interactive confirmatio
|
|
|
1199
1211
|
return formatPurgeOrphansPlan(plan);
|
|
1200
1212
|
}
|
|
1201
1213
|
if (!force) {
|
|
1202
|
-
await
|
|
1214
|
+
await confirmDestructiveAction(
|
|
1215
|
+
"purge-orphans requires an interactive terminal. Use --force to skip confirmation.",
|
|
1216
|
+
formatPurgeOrphansConfirmation(plan)
|
|
1217
|
+
);
|
|
1203
1218
|
}
|
|
1204
1219
|
return formatPurgeOrphansResult(executePurgeOrphansPlanCommand(paths, plan));
|
|
1205
1220
|
})
|
|
@@ -1234,58 +1249,19 @@ function parsePretty(value) {
|
|
|
1234
1249
|
function shouldUsePager(options) {
|
|
1235
1250
|
return Boolean(options.limit === void 0 && process.stdout.isTTY);
|
|
1236
1251
|
}
|
|
1237
|
-
async function
|
|
1238
|
-
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
1239
|
-
throw new SafetyRefusalError("Purge requires an interactive terminal. Use --force to skip confirmation.");
|
|
1240
|
-
}
|
|
1241
|
-
const expected = shortId(plan.target.id);
|
|
1242
|
-
process.stdout.write(formatPurgeConfirmation(plan));
|
|
1243
|
-
const readline = createInterface({
|
|
1244
|
-
input: process.stdin,
|
|
1245
|
-
output: process.stdout
|
|
1246
|
-
});
|
|
1247
|
-
try {
|
|
1248
|
-
const answer = await readline.question(`Type ${colorize("yellow", expected)} to confirm: `);
|
|
1249
|
-
if (answer.trim() !== expected) {
|
|
1250
|
-
throw new SafetyRefusalError("Confirmation did not match. No local Codex data was modified.");
|
|
1251
|
-
}
|
|
1252
|
-
} finally {
|
|
1253
|
-
readline.close();
|
|
1254
|
-
}
|
|
1255
|
-
}
|
|
1256
|
-
async function confirmBatchPurge(plan) {
|
|
1257
|
-
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
1258
|
-
throw new SafetyRefusalError("Batch purge requires an interactive terminal. Use --force to skip confirmation.");
|
|
1259
|
-
}
|
|
1260
|
-
const expected = "purge-selected";
|
|
1261
|
-
process.stdout.write(formatBatchPurgeConfirmation(plan));
|
|
1262
|
-
const readline = createInterface({
|
|
1263
|
-
input: process.stdin,
|
|
1264
|
-
output: process.stdout
|
|
1265
|
-
});
|
|
1266
|
-
try {
|
|
1267
|
-
const answer = await readline.question(`Type ${colorize("yellow", expected)} to confirm: `);
|
|
1268
|
-
if (answer.trim() !== expected) {
|
|
1269
|
-
throw new SafetyRefusalError("Confirmation did not match. No local Codex data was modified.");
|
|
1270
|
-
}
|
|
1271
|
-
} finally {
|
|
1272
|
-
readline.close();
|
|
1273
|
-
}
|
|
1274
|
-
}
|
|
1275
|
-
async function confirmPurgeOrphans(plan) {
|
|
1252
|
+
async function confirmDestructiveAction(terminalRefusalMessage, confirmationOutput) {
|
|
1276
1253
|
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
1277
|
-
throw new SafetyRefusalError(
|
|
1254
|
+
throw new SafetyRefusalError(terminalRefusalMessage);
|
|
1278
1255
|
}
|
|
1279
|
-
|
|
1280
|
-
process.stdout.write(formatPurgeOrphansConfirmation(plan));
|
|
1256
|
+
process.stdout.write(confirmationOutput);
|
|
1281
1257
|
const readline = createInterface({
|
|
1282
1258
|
input: process.stdin,
|
|
1283
1259
|
output: process.stdout
|
|
1284
1260
|
});
|
|
1285
1261
|
try {
|
|
1286
|
-
const answer = await readline.question(`
|
|
1287
|
-
if (answer
|
|
1288
|
-
throw new SafetyRefusalError("Confirmation
|
|
1262
|
+
const answer = await readline.question(`Proceed with permanent deletion? ${colorize("yellow", "[y/N]")}: `);
|
|
1263
|
+
if (!isDestructiveActionConfirmed(answer)) {
|
|
1264
|
+
throw new SafetyRefusalError("Confirmation was declined. No local Codex data was modified.");
|
|
1289
1265
|
}
|
|
1290
1266
|
} finally {
|
|
1291
1267
|
readline.close();
|