tau-all-agent 0.2.0 → 0.3.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/extensions/answer.ts +112 -85
- package/extensions/branch-term/index.ts +9 -5
- package/extensions/btw.ts +67 -36
- package/extensions/insights.ts +67 -56
- package/extensions/loop.ts +14 -52
- package/extensions/memory.ts +65 -33
- package/extensions/notify.ts +5 -3
- package/extensions/review/fix.ts +10 -16
- package/extensions/review/git.ts +7 -1
- package/extensions/review/index.ts +2 -2
- package/extensions/review/models.ts +12 -2
- package/extensions/review/review.ts +3 -5
- package/extensions/review/runtime.ts +9 -8
- package/extensions/review/triage.ts +2 -4
- package/extensions/sandbox/README.md +5 -0
- package/extensions/sandbox/bash.ts +83 -85
- package/extensions/sandbox/index.ts +21 -11
- package/extensions/sandbox/permissions/network.ts +8 -3
- package/extensions/sandbox/permissions/unsandboxed.ts +1 -240
- package/extensions/sandbox/runtime.ts +53 -19
- package/extensions/subagent/README.md +58 -1
- package/extensions/subagent/config.ts +118 -0
- package/extensions/subagent/index.ts +54 -22
- package/extensions/telegram/README.md +2 -0
- package/extensions/telegram/assistant-result.d.mts +4 -1
- package/extensions/telegram/assistant-result.mjs +31 -16
- package/extensions/telegram/daemon.mjs +146 -194
- package/extensions/telegram/index.ts +11 -7
- package/extensions/tool-display-mode.ts +29 -50
- package/extensions/usage/README.md +5 -0
- package/extensions/usage/index.ts +139 -80
- package/extensions/websearch/README.md +8 -1
- package/extensions/websearch/config.ts +2 -1
- package/extensions/websearch/index.ts +18 -9
- package/extensions/websearch/providers/{openai-codex.pi.ts → openai.pi.ts} +51 -16
- package/extensions/websearch/providers/shared.ts +10 -3
- package/extensions/websearch/types.ts +2 -1
- package/extensions/worktree.ts +33 -89
- package/package.json +1 -1
- package/skills/oracle/SKILL.md +14 -8
- package/skills/oracle/scripts/oracle +43 -19
- package/skills/update-changelog/SKILL.md +8 -4
package/extensions/worktree.ts
CHANGED
|
@@ -19,25 +19,14 @@
|
|
|
19
19
|
*/
|
|
20
20
|
|
|
21
21
|
import type { ExtensionAPI, ExtensionCommandContext, Theme } from "@earendil-works/pi-coding-agent";
|
|
22
|
-
import {
|
|
23
|
-
|
|
24
|
-
SessionManager,
|
|
25
|
-
highlightCode,
|
|
26
|
-
type SessionHeader,
|
|
27
|
-
} from "@earendil-works/pi-coding-agent";
|
|
28
|
-
import {
|
|
29
|
-
Box,
|
|
30
|
-
Container,
|
|
31
|
-
type SelectItem,
|
|
32
|
-
SelectList,
|
|
33
|
-
Text,
|
|
34
|
-
matchesKey,
|
|
35
|
-
} from "@earendil-works/pi-tui";
|
|
22
|
+
import { SessionManager, highlightCode, type SessionHeader } from "@earendil-works/pi-coding-agent";
|
|
23
|
+
import { Box, Text } from "@earendil-works/pi-tui";
|
|
36
24
|
import { spawnSync } from "node:child_process";
|
|
37
25
|
import * as fs from "node:fs";
|
|
38
26
|
import * as path from "node:path";
|
|
39
27
|
|
|
40
28
|
const STATUS_KEY = "0-worktree";
|
|
29
|
+
const LIST_ENTRY_TYPE = "worktree-list";
|
|
41
30
|
const MANUAL_OPEN_ENTRY_TYPE = "worktree-open-command";
|
|
42
31
|
const RESTORE_STASH_ENTRY_TYPE = "worktree-restore-command";
|
|
43
32
|
const SCRIPT_RERUN_ENTRY_TYPE = "worktree-script-rerun-command";
|
|
@@ -200,7 +189,7 @@ function showCommandMessage(
|
|
|
200
189
|
command: string,
|
|
201
190
|
): void {
|
|
202
191
|
const copiedToClipboard = copyToClipboard(command);
|
|
203
|
-
if (
|
|
192
|
+
if (ctx.mode === "print") {
|
|
204
193
|
console.log(formatCommandMessageIntro(intro, copiedToClipboard));
|
|
205
194
|
console.log(command);
|
|
206
195
|
return;
|
|
@@ -1262,8 +1251,8 @@ function hasValidSessionFile(sessionFile: string): boolean {
|
|
|
1262
1251
|
function createFreshSessionFile(targetCwd: string, sessionDir?: string): string {
|
|
1263
1252
|
const session = SessionManager.create(targetCwd, sessionDir);
|
|
1264
1253
|
const sessionFile = session.getSessionFile()!;
|
|
1265
|
-
// Pi
|
|
1266
|
-
//
|
|
1254
|
+
// Pi persists the session on its first user or assistant message. Persist the
|
|
1255
|
+
// native header so switchSession can open an otherwise empty conversation.
|
|
1267
1256
|
fs.writeFileSync(sessionFile, `${JSON.stringify(session.getHeader())}\n`, { flag: "wx" });
|
|
1268
1257
|
return sessionFile;
|
|
1269
1258
|
}
|
|
@@ -1308,9 +1297,13 @@ async function switchToWorktree(
|
|
|
1308
1297
|
// including when the source has not been persisted yet.
|
|
1309
1298
|
const storage = SessionManager.create(ctx.sessionManager.getCwd(), currentSessionDir);
|
|
1310
1299
|
const sessionDir = storage.usesDefaultSessionDir() ? undefined : currentSessionDir;
|
|
1311
|
-
const
|
|
1300
|
+
const hasPersistedMessage = ctx.sessionManager
|
|
1312
1301
|
.getEntries()
|
|
1313
|
-
.some(
|
|
1302
|
+
.some(
|
|
1303
|
+
(entry) =>
|
|
1304
|
+
entry.type === "message" &&
|
|
1305
|
+
(entry.message.role === "user" || entry.message.role === "assistant"),
|
|
1306
|
+
);
|
|
1314
1307
|
|
|
1315
1308
|
let sessionFile: string;
|
|
1316
1309
|
if (hasValidSessionFile(currentSessionFile)) {
|
|
@@ -1326,13 +1319,13 @@ async function switchToWorktree(
|
|
|
1326
1319
|
}
|
|
1327
1320
|
sessionFile = forkedSessionFile;
|
|
1328
1321
|
} else {
|
|
1329
|
-
if (
|
|
1322
|
+
if (hasPersistedMessage) {
|
|
1330
1323
|
throw new Error(`Current session file is missing or invalid: ${currentSessionFile}`);
|
|
1331
1324
|
}
|
|
1332
1325
|
|
|
1333
1326
|
const message = "Current session has no persisted history yet. Switching with a fresh session.";
|
|
1334
1327
|
if (ctx.hasUI) ctx.ui.notify(message, "warning");
|
|
1335
|
-
else console.
|
|
1328
|
+
else console.error(message);
|
|
1336
1329
|
|
|
1337
1330
|
sessionFile = createFreshSessionFile(targetPath, sessionDir);
|
|
1338
1331
|
}
|
|
@@ -1965,6 +1958,11 @@ async function handleList(pi: ExtensionAPI, ctx: ExtensionCommandContext): Promi
|
|
|
1965
1958
|
return { repo, items };
|
|
1966
1959
|
});
|
|
1967
1960
|
|
|
1961
|
+
if (ctx.mode === "json") {
|
|
1962
|
+
pi.appendEntry(LIST_ENTRY_TYPE, { items });
|
|
1963
|
+
return;
|
|
1964
|
+
}
|
|
1965
|
+
|
|
1968
1966
|
if (ctx.mode !== "tui") {
|
|
1969
1967
|
const output = items
|
|
1970
1968
|
.map((item) => {
|
|
@@ -1985,80 +1983,26 @@ async function handleList(pi: ExtensionAPI, ctx: ExtensionCommandContext): Promi
|
|
|
1985
1983
|
return;
|
|
1986
1984
|
}
|
|
1987
1985
|
|
|
1988
|
-
const
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
value: item.wt.path,
|
|
1992
|
-
label: formatWorktreeLabel(item, theme),
|
|
1993
|
-
}));
|
|
1994
|
-
|
|
1995
|
-
const itemByValue = new Map(items.map((item) => [item.wt.path, item]));
|
|
1986
|
+
const options = items.map((item) => formatWorktreeLabel(item, ctx.ui.theme));
|
|
1987
|
+
const choice = await ctx.ui.select("Choose worktree", options);
|
|
1988
|
+
if (choice === undefined) return;
|
|
1996
1989
|
|
|
1997
|
-
|
|
1990
|
+
const item = items[options.indexOf(choice)];
|
|
1991
|
+
if (!item) return;
|
|
1998
1992
|
|
|
1999
|
-
const
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
selectedText: (t) => theme.fg("accent", t),
|
|
2006
|
-
description: (t) => t,
|
|
2007
|
-
scrollInfo: (t) => theme.fg("dim", t),
|
|
2008
|
-
noMatch: (t) => theme.fg("warning", t),
|
|
2009
|
-
});
|
|
2010
|
-
selectList.onSelect = (si) => {
|
|
2011
|
-
const item = itemByValue.get(si.value);
|
|
2012
|
-
if (item) done({ action: "switch", item });
|
|
2013
|
-
else done(null);
|
|
2014
|
-
};
|
|
2015
|
-
selectList.onCancel = () => done(null);
|
|
2016
|
-
container.addChild(selectList);
|
|
2017
|
-
|
|
2018
|
-
container.addChild(
|
|
2019
|
-
new Text(theme.fg("dim", " ↑↓ navigate enter switch a archive esc close"), 0, 0),
|
|
2020
|
-
);
|
|
2021
|
-
container.addChild(new DynamicBorder((s: string) => theme.fg("borderMuted", s)));
|
|
2022
|
-
|
|
2023
|
-
return {
|
|
2024
|
-
render: (w) => container.render(w),
|
|
2025
|
-
invalidate: () => container.invalidate(),
|
|
2026
|
-
handleInput: (data) => {
|
|
2027
|
-
if (matchesKey(data, "a")) {
|
|
2028
|
-
const si = selectList.getSelectedItem();
|
|
2029
|
-
if (si) {
|
|
2030
|
-
const item = itemByValue.get(si.value);
|
|
2031
|
-
if (item) {
|
|
2032
|
-
done({ action: "archive", item });
|
|
2033
|
-
return;
|
|
2034
|
-
}
|
|
2035
|
-
}
|
|
2036
|
-
}
|
|
2037
|
-
selectList.handleInput(data);
|
|
2038
|
-
tui.requestRender();
|
|
2039
|
-
},
|
|
2040
|
-
};
|
|
2041
|
-
});
|
|
2042
|
-
|
|
2043
|
-
if (!result) return;
|
|
2044
|
-
|
|
2045
|
-
if (result.action === "switch") {
|
|
2046
|
-
await switchToWorktree(pi, ctx, result.item.wt.path, repo.currentRoot);
|
|
1993
|
+
const action = await ctx.ui.select(`Worktree: ${collapsePath(item.wt.path)}`, [
|
|
1994
|
+
"Switch",
|
|
1995
|
+
"Archive",
|
|
1996
|
+
]);
|
|
1997
|
+
if (action === "Switch") {
|
|
1998
|
+
await switchToWorktree(pi, ctx, item.wt.path, repo.currentRoot);
|
|
2047
1999
|
return;
|
|
2048
2000
|
}
|
|
2049
2001
|
|
|
2050
|
-
if (
|
|
2051
|
-
await withSpinnerStatus(ctx, `archiving ${
|
|
2002
|
+
if (action === "Archive") {
|
|
2003
|
+
await withSpinnerStatus(ctx, `archiving ${item.branch}`, async () => {
|
|
2052
2004
|
const defaultMain = await getDefaultMainBranch(pi, repo.mainRoot);
|
|
2053
|
-
await archiveWorktree(
|
|
2054
|
-
pi,
|
|
2055
|
-
ctx,
|
|
2056
|
-
repo,
|
|
2057
|
-
result.item.branch,
|
|
2058
|
-
"prompt",
|
|
2059
|
-
defaultMain,
|
|
2060
|
-
result.item.wt,
|
|
2061
|
-
);
|
|
2005
|
+
await archiveWorktree(pi, ctx, repo, item.branch, "prompt", defaultMain, item.wt);
|
|
2062
2006
|
});
|
|
2063
2007
|
}
|
|
2064
2008
|
}
|
package/package.json
CHANGED
package/skills/oracle/SKILL.md
CHANGED
|
@@ -7,11 +7,13 @@ description: "Get independent reviews, second opinions, or help getting unstuck
|
|
|
7
7
|
|
|
8
8
|
Use this skill when you want a second opinion from a capable model in a different family than the current session.
|
|
9
9
|
|
|
10
|
-
The oracle workflow bundles selected files into a standalone prompt, selects an alternate model with `pi --list-models`, and sends the bundle to `pi -p --no-tools`.
|
|
10
|
+
The oracle workflow bundles selected files into a standalone prompt, selects an alternate model with `pi --list-models`, and sends the bundle to `pi -p --no-tools`.
|
|
11
|
+
|
|
12
|
+
Discovery and generation disable extensions, skills, prompt templates, themes, and context files (`AGENTS.md` / `CLAUDE.md`). A fixed system prompt and empty append prompt replace discovered `SYSTEM.md` / `APPEND_SYSTEM.md`. The bundle supplies the task and project context. Pi retains normal authentication and configuration, but has no tools or persisted session. This isolates instructions, not the process. It is not a filesystem sandbox or a read-only guarantee.
|
|
11
13
|
|
|
12
14
|
## Model selection
|
|
13
15
|
|
|
14
|
-
The
|
|
16
|
+
The `scripts/oracle` wrapper chooses the strongest known model it can find in the first usable family from this order:
|
|
15
17
|
|
|
16
18
|
| Current family | Oracle preference |
|
|
17
19
|
| ------------------ | ----------------------------------------------------- |
|
|
@@ -33,24 +35,28 @@ If the current model is not obvious to the script, pass it explicitly with `--cu
|
|
|
33
35
|
|
|
34
36
|
## Commands
|
|
35
37
|
|
|
36
|
-
Run
|
|
38
|
+
Run from the repository being reviewed, not this skill directory. Use the installed scripts' absolute paths. In the examples, replace `/absolute/path/to/oracle` with the directory containing this `SKILL.md`.
|
|
39
|
+
|
|
40
|
+
The wrapper resolves the invocation's Git root once (or uses the invocation directory outside Git) and uses it for model discovery, bundling, and generation. Relative file selectors are rooted there, even when invoked from a repository subdirectory.
|
|
37
41
|
|
|
38
42
|
```bash
|
|
39
43
|
# Preview selected files
|
|
40
|
-
|
|
44
|
+
/absolute/path/to/oracle/scripts/oracle-bundle --dry-run \
|
|
45
|
+
-p "<task>" --file "src/**" --file "!**/*.test.*"
|
|
41
46
|
|
|
42
47
|
# Preview the full bundle
|
|
43
|
-
|
|
48
|
+
/absolute/path/to/oracle/scripts/oracle-bundle \
|
|
49
|
+
-p "<task>" --file "src/**" --file "!**/*.test.*"
|
|
44
50
|
|
|
45
51
|
# Show which oracle model would be selected
|
|
46
|
-
|
|
52
|
+
/absolute/path/to/oracle/scripts/oracle --list-models --current openai-codex/gpt-6-astra
|
|
47
53
|
|
|
48
54
|
# Ask the automatically selected oracle model
|
|
49
|
-
|
|
55
|
+
/absolute/path/to/oracle/scripts/oracle --current openai-codex/gpt-6-astra \
|
|
50
56
|
-p "<task>" --file "src/**" --file "!**/*.test.*"
|
|
51
57
|
|
|
52
58
|
# Override the oracle model when the automatic choice is wrong
|
|
53
|
-
|
|
59
|
+
/absolute/path/to/oracle/scripts/oracle --model anthropic/claude-fable-5-1 \
|
|
54
60
|
-p "<task>" --file "src/**" --file "!**/*.test.*"
|
|
55
61
|
```
|
|
56
62
|
|
|
@@ -15,6 +15,11 @@ const BARE_PI_ARGS = [
|
|
|
15
15
|
"--no-skills",
|
|
16
16
|
"--no-prompt-templates",
|
|
17
17
|
"--no-themes",
|
|
18
|
+
"--no-context-files",
|
|
19
|
+
"--system-prompt",
|
|
20
|
+
"You are an independent advisor. Use the supplied task and files as your context.",
|
|
21
|
+
"--append-system-prompt",
|
|
22
|
+
"/dev/null",
|
|
18
23
|
];
|
|
19
24
|
|
|
20
25
|
const FAMILY_ORDER = {
|
|
@@ -25,8 +30,10 @@ const FAMILY_ORDER = {
|
|
|
25
30
|
};
|
|
26
31
|
|
|
27
32
|
const args = parseArgs(process.argv.slice(2));
|
|
33
|
+
const cwd = repoRoot();
|
|
28
34
|
const settings = readSettings();
|
|
29
|
-
const currentModel =
|
|
35
|
+
const currentModel =
|
|
36
|
+
args.currentModel ?? process.env.ORACLE_CURRENT_MODEL ?? defaultModel(settings);
|
|
30
37
|
const currentFamily = modelFamily(currentModel ?? "") ?? "unknown";
|
|
31
38
|
const availableModels = listPiModels();
|
|
32
39
|
const enabledModels = new Set((settings.enabledModels ?? []).map(normalizeModelSpec));
|
|
@@ -46,7 +53,7 @@ console.error(
|
|
|
46
53
|
);
|
|
47
54
|
|
|
48
55
|
const bundle = run(path.join(SCRIPT_DIR, "oracle-bundle"), args.bundleArgs, {
|
|
49
|
-
cwd
|
|
56
|
+
cwd,
|
|
50
57
|
encoding: "utf8",
|
|
51
58
|
maxBuffer: 64 * 1024 * 1024,
|
|
52
59
|
});
|
|
@@ -60,7 +67,7 @@ const pi = spawnSync(
|
|
|
60
67
|
"pi",
|
|
61
68
|
[...BARE_PI_ARGS, "--model", oracleModel, "--thinking", THINKING_LEVEL],
|
|
62
69
|
{
|
|
63
|
-
cwd
|
|
70
|
+
cwd,
|
|
64
71
|
input: bundle.stdout,
|
|
65
72
|
stdio: ["pipe", "inherit", "inherit"],
|
|
66
73
|
},
|
|
@@ -119,7 +126,7 @@ function getAgentDir() {
|
|
|
119
126
|
if (!configured) return path.join(homedir(), ".pi", "agent");
|
|
120
127
|
if (configured === "~") return homedir();
|
|
121
128
|
if (configured.startsWith("~/")) return path.join(homedir(), configured.slice(2));
|
|
122
|
-
return path.resolve(configured);
|
|
129
|
+
return path.resolve(cwd, configured);
|
|
123
130
|
}
|
|
124
131
|
|
|
125
132
|
function defaultModel(settings) {
|
|
@@ -128,7 +135,11 @@ function defaultModel(settings) {
|
|
|
128
135
|
}
|
|
129
136
|
|
|
130
137
|
function listPiModels() {
|
|
131
|
-
const result = run("pi", ["--list-models"], {
|
|
138
|
+
const result = run("pi", [...BARE_PI_ARGS, "--list-models"], {
|
|
139
|
+
cwd,
|
|
140
|
+
encoding: "utf8",
|
|
141
|
+
maxBuffer: 16 * 1024 * 1024,
|
|
142
|
+
});
|
|
132
143
|
if (result.error) die(result.error.message);
|
|
133
144
|
if (result.status !== 0) die(result.stderr || "pi --list-models failed");
|
|
134
145
|
|
|
@@ -200,8 +211,11 @@ function modelRank(model, family) {
|
|
|
200
211
|
const normalized = model.toLowerCase();
|
|
201
212
|
|
|
202
213
|
if (family === "openai") {
|
|
203
|
-
if (/gpt-6[-_.]astra/.test(normalized)) return
|
|
204
|
-
if (/gpt-
|
|
214
|
+
if (/gpt-6[-_.]astra/.test(normalized)) return 14;
|
|
215
|
+
if (/gpt-6\.1[-_.]sol/.test(normalized)) return 13;
|
|
216
|
+
if (/gpt-6[-_.]sol/.test(normalized)) return 12;
|
|
217
|
+
if (/gpt-5\.6[-_.]sol/.test(normalized)) return 11;
|
|
218
|
+
if (/gpt-6[-_.]luna/.test(normalized)) return 10;
|
|
205
219
|
if (/gpt-5\.6/.test(normalized)) return 9;
|
|
206
220
|
if (/gpt-5\.5/.test(normalized)) return 8;
|
|
207
221
|
if (/gpt-5\.4/.test(normalized)) return 7;
|
|
@@ -215,16 +229,22 @@ function modelRank(model, family) {
|
|
|
215
229
|
}
|
|
216
230
|
|
|
217
231
|
if (family === "anthropic") {
|
|
218
|
-
if (/claude[-_.]fable[-_.]5/.test(normalized)) return
|
|
219
|
-
if (/claude[-_.]
|
|
220
|
-
if (/claude[-_.]opus[-_.]
|
|
221
|
-
if (/claude[-_.]opus[-_.]
|
|
222
|
-
if (/claude[-_.]opus[-_.]4[-_.]
|
|
223
|
-
if (/claude[-_.]opus[-_.]4[-_.]
|
|
224
|
-
if (/claude[-_.]opus[-_.]4/.test(normalized)) return
|
|
225
|
-
if (/claude[-_.]
|
|
226
|
-
if (/claude[-_.]
|
|
227
|
-
if (/claude[-_.]
|
|
232
|
+
if (/claude[-_.]fable[-_.]5[-_.]1/.test(normalized)) return 16;
|
|
233
|
+
if (/claude[-_.]fable[-_.]5/.test(normalized)) return 15;
|
|
234
|
+
if (/claude[-_.]opus[-_.]5[-_.]5/.test(normalized)) return 14;
|
|
235
|
+
if (/claude[-_.]opus[-_.]5/.test(normalized)) return 13;
|
|
236
|
+
if (/claude[-_.]opus[-_.]4[-_.]8/.test(normalized)) return 12;
|
|
237
|
+
if (/claude[-_.]opus[-_.]4[-_.]7/.test(normalized)) return 11;
|
|
238
|
+
if (/claude[-_.]opus[-_.]4[-_.]6/.test(normalized)) return 10;
|
|
239
|
+
if (/claude[-_.]opus[-_.]4[-_.]5/.test(normalized)) return 9;
|
|
240
|
+
if (/claude[-_.]opus[-_.]4[-_.]1/.test(normalized)) return 8;
|
|
241
|
+
if (/claude[-_.]opus[-_.]4/.test(normalized)) return 7;
|
|
242
|
+
if (/claude[-_.]sonnet[-_.]5[-_.]5/.test(normalized)) return 6;
|
|
243
|
+
if (/claude[-_.]sonnet[-_.]5/.test(normalized)) return 5;
|
|
244
|
+
if (/claude[-_.]sonnet[-_.]4[-_.]6/.test(normalized)) return 4;
|
|
245
|
+
if (/claude[-_.]sonnet[-_.]4[-_.]5/.test(normalized)) return 3;
|
|
246
|
+
if (/claude[-_.]sonnet[-_.]4/.test(normalized)) return 2;
|
|
247
|
+
if (/claude[-_.]haiku[-_.]5[-_.]5/.test(normalized)) return 1;
|
|
228
248
|
return 0;
|
|
229
249
|
}
|
|
230
250
|
|
|
@@ -248,13 +268,17 @@ function modelFamily(spec) {
|
|
|
248
268
|
}
|
|
249
269
|
|
|
250
270
|
function normalizeModelSpec(spec) {
|
|
251
|
-
return String(spec)
|
|
271
|
+
return String(spec)
|
|
272
|
+
.trim()
|
|
273
|
+
.replace(/:(off|minimal|low|medium|high|xhigh|max)$/i, "");
|
|
252
274
|
}
|
|
253
275
|
|
|
254
276
|
function printModelPlan(models, enabledModels, currentModel, currentFamily) {
|
|
255
277
|
console.log(`Current model: ${currentModel ?? "unknown"}`);
|
|
256
278
|
console.log(`Current family: ${currentFamily}`);
|
|
257
|
-
console.log(
|
|
279
|
+
console.log(
|
|
280
|
+
`Family order: ${(FAMILY_ORDER[currentFamily] ?? FAMILY_ORDER.unknown).join(" -> ")}`,
|
|
281
|
+
);
|
|
258
282
|
console.log("");
|
|
259
283
|
|
|
260
284
|
for (const family of ["anthropic", "openai", "google"]) {
|
|
@@ -9,20 +9,24 @@ Use [Keep a Changelog 2.0.0](https://keepachangelog.com/en/2.0.0/) and preserve
|
|
|
9
9
|
|
|
10
10
|
## Choose the scope
|
|
11
11
|
|
|
12
|
-
- **Document a specific change:** inspect the relevant diff, issue, or PR and the existing `Unreleased` entries. Update only that change; a complete release-history audit is unnecessary.
|
|
13
|
-
- **Audit changes since a release:**
|
|
12
|
+
- **Document a specific change:** inspect the relevant diff, issue, or PR and the existing `Unreleased` entries. Update only that change, checking its same-release feature history when needed to classify or merge it correctly; a complete release-history audit is unnecessary.
|
|
13
|
+
- **Audit changes since a release:** compare the requested baseline, or the latest release tag (`git describe --tags --abbrev=0`), with `HEAD`. For a specified released section, compare its preceding release with that target release instead. If tags are missing or inconsistent, use release sections and history to establish the boundaries. Inspect `git log <baseline>..<target> --oneline` and relevant diffs or PRs.
|
|
14
14
|
- **Prepare a release:** move `Unreleased` entries into a versioned section only when the release operation is requested.
|
|
15
15
|
|
|
16
|
+
During audits and release preparation, reconcile existing entries for duplicates, superseded notes, and misclassification as well as notable omissions.
|
|
17
|
+
|
|
16
18
|
A changelog request does not authorize committing, publishing, or creating a release.
|
|
17
19
|
|
|
18
20
|
## Entry rules
|
|
19
21
|
|
|
20
22
|
- Include notable user-visible behavior, APIs, flags, bug fixes, and security changes. Exclude internal cleanup, tests, typo-only documentation edits, dependency bumps, and other changes without visible user impact.
|
|
21
|
-
-
|
|
23
|
+
- Describe net changes since the previous released baseline, not development chronology. Omit regressions introduced and resolved within the same release, including in existing features. Genuine changes to previously released features or integrations still warrant `Changed` or `Fixed` entries.
|
|
24
|
+
- Give each feature first shipped in this release one coherent `Added` description in its final form. Fold notable pre-release refinements and fixes into that description or omit them, rather than listing them separately under `Changed` or `Fixed`.
|
|
25
|
+
- Write concise, concrete entries matching the repository's bullet grammar. Explain user impact rather than copying commit subjects or listing implementation details. Avoid mechanically repeating section labels such as “Added”, “Fixed”, or “Removed” in bullets; write grammatical descriptions rather than merely deleting those prefixes.
|
|
22
26
|
- Link issues or pull requests when useful, but prefer plain prose over lists of references.
|
|
23
27
|
- Mark breaking changes with `**Breaking:**` within their change category, and say what breaks.
|
|
24
28
|
- Keep upgrade notes brief. Link substantial procedures to a migration guide or release notes.
|
|
25
|
-
- Add entries under `Unreleased` unless an explicitly requested release requires moving them. Preserve released content
|
|
29
|
+
- Add entries under `Unreleased` unless an explicitly requested release requires moving them or an audit/correction targets a released section. Preserve released content otherwise.
|
|
26
30
|
- Merge with an existing entry when it describes the same change rather than adding a duplicate.
|
|
27
31
|
|
|
28
32
|
## Categories
|