ai-cli-mcp 2.10.0 → 2.11.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/.github/workflows/watch-session-prs.yml +276 -0
- package/CHANGELOG.md +7 -0
- package/README.ja.md +2 -2
- package/README.md +2 -2
- package/dist/__tests__/cli-builder.test.js +49 -2
- package/dist/__tests__/validation.test.js +2 -2
- package/dist/cli-builder.js +28 -16
- package/dist/cli.js +1 -1
- package/dist/server.js +2 -2
- package/package.json +1 -1
- package/src/__tests__/cli-builder.test.ts +62 -3
- package/src/__tests__/validation.test.ts +2 -2
- package/src/cli-builder.ts +31 -15
- package/src/cli.ts +1 -1
- package/src/server.ts +2 -2
- package/.github/workflows/watch-codex-fork-pr.yml +0 -98
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
name: Watch Session PRs
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
schedule:
|
|
5
|
+
- cron: '17 0 * * *'
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
issues: write
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
watch-codex-fork:
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
steps:
|
|
16
|
+
- name: Check Codex fork PR and update issue
|
|
17
|
+
uses: actions/github-script@v7
|
|
18
|
+
env:
|
|
19
|
+
UPSTREAM_OWNER: openai
|
|
20
|
+
UPSTREAM_REPO: codex
|
|
21
|
+
UPSTREAM_PR_NUMBER: '13537'
|
|
22
|
+
TARGET_ISSUE_NUMBER: '7'
|
|
23
|
+
COMMENT_MARKER: '<!-- codex-fork-pr-13537-status -->'
|
|
24
|
+
READY_LABEL: '[ready]'
|
|
25
|
+
STOP_LABEL: '[stop]'
|
|
26
|
+
with:
|
|
27
|
+
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
28
|
+
script: |
|
|
29
|
+
const owner = process.env.UPSTREAM_OWNER;
|
|
30
|
+
const repo = process.env.UPSTREAM_REPO;
|
|
31
|
+
const pull_number = Number(process.env.UPSTREAM_PR_NUMBER);
|
|
32
|
+
const issue_number = Number(process.env.TARGET_ISSUE_NUMBER);
|
|
33
|
+
const marker = process.env.COMMENT_MARKER;
|
|
34
|
+
const readyLabel = process.env.READY_LABEL;
|
|
35
|
+
const stopLabel = process.env.STOP_LABEL;
|
|
36
|
+
|
|
37
|
+
const { data: pr } = await github.rest.pulls.get({ owner, repo, pull_number });
|
|
38
|
+
const desiredLabel = pr.merged_at ? readyLabel : stopLabel;
|
|
39
|
+
const staleLabel = pr.merged_at ? stopLabel : readyLabel;
|
|
40
|
+
const { data: issue } = await github.rest.issues.get({
|
|
41
|
+
owner: context.repo.owner,
|
|
42
|
+
repo: context.repo.repo,
|
|
43
|
+
issue_number,
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
if (!issue.labels.some((label) => label.name === desiredLabel)) {
|
|
47
|
+
await github.rest.issues.addLabels({
|
|
48
|
+
owner: context.repo.owner,
|
|
49
|
+
repo: context.repo.repo,
|
|
50
|
+
issue_number,
|
|
51
|
+
labels: [desiredLabel],
|
|
52
|
+
});
|
|
53
|
+
core.info(`Added label ${desiredLabel} to issue #${issue_number}.`);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (issue.labels.some((label) => label.name === staleLabel)) {
|
|
57
|
+
try {
|
|
58
|
+
await github.rest.issues.removeLabel({
|
|
59
|
+
owner: context.repo.owner,
|
|
60
|
+
repo: context.repo.repo,
|
|
61
|
+
issue_number,
|
|
62
|
+
name: staleLabel,
|
|
63
|
+
});
|
|
64
|
+
core.info(`Removed label ${staleLabel} from issue #${issue_number}.`);
|
|
65
|
+
} catch (error) {
|
|
66
|
+
core.warning(`Failed to remove label ${staleLabel}: ${error.message}`);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
core.summary
|
|
71
|
+
.addHeading('Codex PR status')
|
|
72
|
+
.addTable([
|
|
73
|
+
[
|
|
74
|
+
{ data: 'Field', header: true },
|
|
75
|
+
{ data: 'Value', header: true },
|
|
76
|
+
],
|
|
77
|
+
['PR', `${owner}/${repo}#${pr.number}`],
|
|
78
|
+
['Title', pr.title],
|
|
79
|
+
['State', pr.state],
|
|
80
|
+
['Merged', pr.merged_at ? 'yes' : 'no'],
|
|
81
|
+
['Merged at', pr.merged_at ?? 'not merged'],
|
|
82
|
+
['Updated at', pr.updated_at],
|
|
83
|
+
['URL', pr.html_url],
|
|
84
|
+
]);
|
|
85
|
+
|
|
86
|
+
const comments = await github.paginate(github.rest.issues.listComments, {
|
|
87
|
+
owner: context.repo.owner,
|
|
88
|
+
repo: context.repo.repo,
|
|
89
|
+
issue_number,
|
|
90
|
+
per_page: 100,
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
const existingComment = comments.find((comment) => comment.body?.includes(marker));
|
|
94
|
+
const body = [
|
|
95
|
+
marker,
|
|
96
|
+
'upstream PR `openai/codex#13537` status watcher',
|
|
97
|
+
'',
|
|
98
|
+
`- PR: ${pr.html_url}`,
|
|
99
|
+
`- State: ${pr.state}`,
|
|
100
|
+
`- Merged: ${pr.merged_at ? 'yes' : 'no'}`,
|
|
101
|
+
`- Merged at: ${pr.merged_at ?? 'not merged'}`,
|
|
102
|
+
`- Updated at: ${pr.updated_at}`,
|
|
103
|
+
'',
|
|
104
|
+
pr.merged_at
|
|
105
|
+
? 'This PR has been merged. `codex exec --fork <SESSION_ID> [PROMPT]` should become available once the change lands in the installed Codex version.'
|
|
106
|
+
: 'This PR is not merged yet. Non-interactive forking is still not available in released Codex builds.',
|
|
107
|
+
'A new session ID is expected when using `--fork`; `resume` itself continues the same session.',
|
|
108
|
+
].join('\n');
|
|
109
|
+
|
|
110
|
+
if (existingComment?.body === body) {
|
|
111
|
+
core.info(`Issue #${issue_number} status comment is already up to date.`);
|
|
112
|
+
await core.summary.addRaw(`No update needed: ${existingComment.html_url}\n`).write();
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (existingComment) {
|
|
117
|
+
const { data: comment } = await github.rest.issues.updateComment({
|
|
118
|
+
owner: context.repo.owner,
|
|
119
|
+
repo: context.repo.repo,
|
|
120
|
+
comment_id: existingComment.id,
|
|
121
|
+
body,
|
|
122
|
+
});
|
|
123
|
+
core.info(`Updated issue #${issue_number}: ${comment.html_url}`);
|
|
124
|
+
await core.summary.addRaw(`Updated status comment: ${comment.html_url}\n`).write();
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const { data: comment } = await github.rest.issues.createComment({
|
|
129
|
+
owner: context.repo.owner,
|
|
130
|
+
repo: context.repo.repo,
|
|
131
|
+
issue_number,
|
|
132
|
+
body,
|
|
133
|
+
});
|
|
134
|
+
core.info(`Created issue #${issue_number} status comment: ${comment.html_url}`);
|
|
135
|
+
await core.summary.addRaw(`Created status comment: ${comment.html_url}\n`).write();
|
|
136
|
+
|
|
137
|
+
watch-gemini-session-work:
|
|
138
|
+
runs-on: ubuntu-latest
|
|
139
|
+
steps:
|
|
140
|
+
- name: Check Gemini session PRs and update issue
|
|
141
|
+
uses: actions/github-script@v7
|
|
142
|
+
env:
|
|
143
|
+
UPSTREAM_OWNER: google-gemini
|
|
144
|
+
UPSTREAM_REPO: gemini-cli
|
|
145
|
+
TARGET_ISSUE_NUMBER: '16'
|
|
146
|
+
COMMENT_MARKER: '<!-- gemini-session-pr-status -->'
|
|
147
|
+
WATCH_PR_NUMBERS: '17921,19629,19994'
|
|
148
|
+
READY_PR_NUMBERS: '17921,19629'
|
|
149
|
+
READY_LABEL: '[ready]'
|
|
150
|
+
STOP_LABEL: '[stop]'
|
|
151
|
+
with:
|
|
152
|
+
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
153
|
+
script: |
|
|
154
|
+
const owner = process.env.UPSTREAM_OWNER;
|
|
155
|
+
const repo = process.env.UPSTREAM_REPO;
|
|
156
|
+
const issue_number = Number(process.env.TARGET_ISSUE_NUMBER);
|
|
157
|
+
const marker = process.env.COMMENT_MARKER;
|
|
158
|
+
const pullNumbers = process.env.WATCH_PR_NUMBERS.split(',').map((value) => Number(value.trim()));
|
|
159
|
+
const readyPullNumbers = process.env.READY_PR_NUMBERS.split(',').map((value) => Number(value.trim()));
|
|
160
|
+
const readyLabel = process.env.READY_LABEL;
|
|
161
|
+
const stopLabel = process.env.STOP_LABEL;
|
|
162
|
+
|
|
163
|
+
const pulls = await Promise.all(
|
|
164
|
+
pullNumbers.map(async (pull_number) => {
|
|
165
|
+
const { data: pr } = await github.rest.pulls.get({ owner, repo, pull_number });
|
|
166
|
+
return pr;
|
|
167
|
+
}),
|
|
168
|
+
);
|
|
169
|
+
const isReady = pulls.some((pr) => readyPullNumbers.includes(pr.number) && Boolean(pr.merged_at));
|
|
170
|
+
const desiredLabel = isReady ? readyLabel : stopLabel;
|
|
171
|
+
const staleLabel = isReady ? stopLabel : readyLabel;
|
|
172
|
+
|
|
173
|
+
const { data: issue } = await github.rest.issues.get({
|
|
174
|
+
owner: context.repo.owner,
|
|
175
|
+
repo: context.repo.repo,
|
|
176
|
+
issue_number,
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
if (!issue.labels.some((label) => label.name === desiredLabel)) {
|
|
180
|
+
await github.rest.issues.addLabels({
|
|
181
|
+
owner: context.repo.owner,
|
|
182
|
+
repo: context.repo.repo,
|
|
183
|
+
issue_number,
|
|
184
|
+
labels: [desiredLabel],
|
|
185
|
+
});
|
|
186
|
+
core.info(`Added label ${desiredLabel} to issue #${issue_number}.`);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
if (issue.labels.some((label) => label.name === staleLabel)) {
|
|
190
|
+
try {
|
|
191
|
+
await github.rest.issues.removeLabel({
|
|
192
|
+
owner: context.repo.owner,
|
|
193
|
+
repo: context.repo.repo,
|
|
194
|
+
issue_number,
|
|
195
|
+
name: staleLabel,
|
|
196
|
+
});
|
|
197
|
+
core.info(`Removed label ${staleLabel} from issue #${issue_number}.`);
|
|
198
|
+
} catch (error) {
|
|
199
|
+
core.warning(`Failed to remove label ${staleLabel}: ${error.message}`);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
const lines = pulls.flatMap((pr) => [
|
|
204
|
+
`- \`${owner}/${repo}#${pr.number}\` ${pr.title}`,
|
|
205
|
+
` - State: ${pr.state}`,
|
|
206
|
+
` - Merged: ${pr.merged_at ? 'yes' : 'no'}`,
|
|
207
|
+
` - Merged at: ${pr.merged_at ?? 'not merged'}`,
|
|
208
|
+
` - Updated at: ${pr.updated_at}`,
|
|
209
|
+
` - URL: ${pr.html_url}`,
|
|
210
|
+
]);
|
|
211
|
+
|
|
212
|
+
core.summary
|
|
213
|
+
.addHeading('Gemini PR status')
|
|
214
|
+
.addTable([
|
|
215
|
+
[
|
|
216
|
+
{ data: 'PR', header: true },
|
|
217
|
+
{ data: 'State', header: true },
|
|
218
|
+
{ data: 'Merged', header: true },
|
|
219
|
+
{ data: 'Updated at', header: true },
|
|
220
|
+
],
|
|
221
|
+
...pulls.map((pr) => [
|
|
222
|
+
`${owner}/${repo}#${pr.number}`,
|
|
223
|
+
pr.state,
|
|
224
|
+
pr.merged_at ? 'yes' : 'no',
|
|
225
|
+
pr.updated_at,
|
|
226
|
+
]),
|
|
227
|
+
]);
|
|
228
|
+
|
|
229
|
+
const comments = await github.paginate(github.rest.issues.listComments, {
|
|
230
|
+
owner: context.repo.owner,
|
|
231
|
+
repo: context.repo.repo,
|
|
232
|
+
issue_number,
|
|
233
|
+
per_page: 100,
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
const existingComment = comments.find((comment) => comment.body?.includes(marker));
|
|
237
|
+
const body = [
|
|
238
|
+
marker,
|
|
239
|
+
'upstream Gemini CLI session-related PR status watcher',
|
|
240
|
+
'',
|
|
241
|
+
'Tracked PRs:',
|
|
242
|
+
...lines,
|
|
243
|
+
'',
|
|
244
|
+
'Interpretation:',
|
|
245
|
+
'- `#19994` is a fix for resumed session ID stats mismatch, not a fork/new-session feature.',
|
|
246
|
+
'- `#17921` is the `/new` command proposal for starting a fresh session while preserving the previous one.',
|
|
247
|
+
'- `#19629` is the `--session-id` proposal for explicit session UUID control.',
|
|
248
|
+
'- Even if these land, that still does not automatically imply Codex-style headless fork semantics from `--resume` alone.',
|
|
249
|
+
].join('\n');
|
|
250
|
+
|
|
251
|
+
if (existingComment?.body === body) {
|
|
252
|
+
core.info(`Issue #${issue_number} Gemini status comment is already up to date.`);
|
|
253
|
+
await core.summary.addRaw(`No update needed: ${existingComment.html_url}\n`).write();
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
if (existingComment) {
|
|
258
|
+
const { data: comment } = await github.rest.issues.updateComment({
|
|
259
|
+
owner: context.repo.owner,
|
|
260
|
+
repo: context.repo.repo,
|
|
261
|
+
comment_id: existingComment.id,
|
|
262
|
+
body,
|
|
263
|
+
});
|
|
264
|
+
core.info(`Updated issue #${issue_number}: ${comment.html_url}`);
|
|
265
|
+
await core.summary.addRaw(`Updated status comment: ${comment.html_url}\n`).write();
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
const { data: comment } = await github.rest.issues.createComment({
|
|
270
|
+
owner: context.repo.owner,
|
|
271
|
+
repo: context.repo.repo,
|
|
272
|
+
issue_number,
|
|
273
|
+
body,
|
|
274
|
+
});
|
|
275
|
+
core.info(`Created issue #${issue_number} status comment: ${comment.html_url}`);
|
|
276
|
+
await core.summary.addRaw(`Created status comment: ${comment.html_url}\n`).write();
|
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
# [2.11.0](https://github.com/mkXultra/ai-cli-mcp/compare/v2.10.0...v2.11.0) (2026-03-08)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* ClaudeモデルへのReasoning Effort(--effort)サポートを追加 ([ac6b8cc](https://github.com/mkXultra/ai-cli-mcp/commit/ac6b8cc47a06a2d207258e85cc21b1d4ce83e5b2))
|
|
7
|
+
|
|
1
8
|
# [2.10.0](https://github.com/mkXultra/ai-cli-mcp/compare/v2.9.1...v2.10.0) (2026-03-07)
|
|
2
9
|
|
|
3
10
|
|
package/README.ja.md
CHANGED
|
@@ -131,11 +131,11 @@ Claude CLI、Codex CLI、またはGemini CLIを使用してプロンプトを実
|
|
|
131
131
|
- `prompt_file` (string, 任意): プロンプトを含むファイルへのパス。`prompt` または `prompt_file` のいずれかが必須です。絶対パス、または `workFolder` からの相対パスが指定可能です。
|
|
132
132
|
- `workFolder` (string, 必須): CLIを実行する作業ディレクトリ。絶対パスである必要があります。
|
|
133
133
|
- **モデル (Models):**
|
|
134
|
-
- **Ultra エイリアス:** `claude-ultra
|
|
134
|
+
- **Ultra エイリアス:** `claude-ultra` (自動的に high effort に設定), `codex-ultra` (自動的に xhigh reasoning に設定), `gemini-ultra`
|
|
135
135
|
- Claude: `sonnet`, `sonnet[1m]`, `opus`, `opusplan`, `haiku`
|
|
136
136
|
- Codex: `gpt-5.4`, `gpt-5.3-codex`, `gpt-5.2-codex`, `gpt-5.1-codex-mini`, `gpt-5.1-codex-max`, `gpt-5.2`, `gpt-5.1`, `gpt-5`
|
|
137
137
|
- Gemini: `gemini-2.5-pro`, `gemini-2.5-flash`, `gemini-3.1-pro-preview`, `gemini-3-pro-preview`, `gemini-3-flash-preview`
|
|
138
|
-
- `reasoning_effort` (string, 任意): Codex
|
|
138
|
+
- `reasoning_effort` (string, 任意): Claude と Codex の推論制御。Claude では `--effort` を使います(許容値: "low", "medium", "high")。Codex では `model_reasoning_effort` を使います(許容値: "low", "medium", "high", "xhigh")。
|
|
139
139
|
- `session_id` (string, 任意): 以前のセッションを再開するためのセッションID。対応モデル: haiku, sonnet, opus, gemini-2.5-pro, gemini-2.5-flash, gemini-3.1-pro-preview, gemini-3-pro-preview, gemini-3-flash-preview。
|
|
140
140
|
|
|
141
141
|
### `wait`
|
package/README.md
CHANGED
|
@@ -130,11 +130,11 @@ Executes a prompt using Claude CLI, Codex CLI, or Gemini CLI. The appropriate CL
|
|
|
130
130
|
- `prompt_file` (string, optional): Path to a file containing the prompt. Either `prompt` or `prompt_file` is required. Can be absolute path or relative to `workFolder`.
|
|
131
131
|
- `workFolder` (string, required): The working directory for the CLI execution. Must be an absolute path.
|
|
132
132
|
**Models:**
|
|
133
|
-
- **Ultra Aliases:** `claude-ultra
|
|
133
|
+
- **Ultra Aliases:** `claude-ultra` (defaults to high effort), `codex-ultra` (defaults to xhigh reasoning), `gemini-ultra`
|
|
134
134
|
- Claude: `sonnet`, `sonnet[1m]`, `opus`, `opusplan`, `haiku`
|
|
135
135
|
- Codex: `gpt-5.4`, `gpt-5.3-codex`, `gpt-5.2-codex`, `gpt-5.1-codex-mini`, `gpt-5.1-codex-max`, `gpt-5.2`, `gpt-5.1`, `gpt-5`
|
|
136
136
|
- Gemini: `gemini-2.5-pro`, `gemini-2.5-flash`, `gemini-3.1-pro-preview`, `gemini-3-pro-preview`, `gemini-3-flash-preview`
|
|
137
|
-
- `reasoning_effort` (string, optional): Codex
|
|
137
|
+
- `reasoning_effort` (string, optional): Reasoning control for Claude and Codex. Claude uses `--effort` (allowed: "low", "medium", "high"). Codex uses `model_reasoning_effort` (allowed: "low", "medium", "high", "xhigh").
|
|
138
138
|
- `session_id` (string, optional): Optional session ID to resume a previous session. Supported for: haiku, sonnet, opus, gemini-2.5-pro, gemini-2.5-flash, gemini-3.1-pro-preview, gemini-3-pro-preview, gemini-3-flash-preview.
|
|
139
139
|
|
|
140
140
|
### `wait`
|
|
@@ -58,12 +58,17 @@ describe('cli-builder', () => {
|
|
|
58
58
|
expect(getReasoningEffort('gpt-5.2', 'medium')).toBe('medium');
|
|
59
59
|
expect(getReasoningEffort('gpt-5.2', 'high')).toBe('high');
|
|
60
60
|
expect(getReasoningEffort('gpt-5.2', 'xhigh')).toBe('xhigh');
|
|
61
|
+
expect(getReasoningEffort('sonnet', 'high')).toBe('high');
|
|
62
|
+
expect(getReasoningEffort('', 'low')).toBe('low');
|
|
61
63
|
});
|
|
62
64
|
it('should throw for invalid reasoning effort value', () => {
|
|
63
65
|
expect(() => getReasoningEffort('gpt-5.2', 'ultra')).toThrow('Invalid reasoning_effort: ultra. Allowed values: low, medium, high, xhigh.');
|
|
64
66
|
});
|
|
65
|
-
it('should
|
|
66
|
-
expect(() => getReasoningEffort('sonnet', '
|
|
67
|
+
it('should reject xhigh for claude models', () => {
|
|
68
|
+
expect(() => getReasoningEffort('sonnet', 'xhigh')).toThrow('Claude reasoning_effort supports only low, medium, high.');
|
|
69
|
+
});
|
|
70
|
+
it('should throw for unsupported model families', () => {
|
|
71
|
+
expect(() => getReasoningEffort('gemini-2.5-pro', 'high')).toThrow('reasoning_effort is only supported for Claude and Codex models.');
|
|
67
72
|
});
|
|
68
73
|
});
|
|
69
74
|
describe('buildCliCommand', () => {
|
|
@@ -173,6 +178,48 @@ describe('cli-builder', () => {
|
|
|
173
178
|
expect(cmd.resolvedModel).toBe('opus');
|
|
174
179
|
expect(cmd.args).toContain('opus');
|
|
175
180
|
});
|
|
181
|
+
it('should resolve claude-ultra and default to high effort', () => {
|
|
182
|
+
const cmd = buildCliCommand({
|
|
183
|
+
prompt: 'test',
|
|
184
|
+
workFolder: '/tmp',
|
|
185
|
+
model: 'claude-ultra',
|
|
186
|
+
cliPaths: DEFAULT_CLI_PATHS,
|
|
187
|
+
});
|
|
188
|
+
expect(cmd.args).toContain('--effort');
|
|
189
|
+
expect(cmd.args).toContain('high');
|
|
190
|
+
});
|
|
191
|
+
it('should build claude command with reasoning_effort using --effort', () => {
|
|
192
|
+
const cmd = buildCliCommand({
|
|
193
|
+
prompt: 'test',
|
|
194
|
+
workFolder: '/tmp',
|
|
195
|
+
model: 'sonnet',
|
|
196
|
+
reasoning_effort: 'medium',
|
|
197
|
+
cliPaths: DEFAULT_CLI_PATHS,
|
|
198
|
+
});
|
|
199
|
+
expect(cmd.args).toContain('--effort');
|
|
200
|
+
expect(cmd.args).toContain('medium');
|
|
201
|
+
});
|
|
202
|
+
it('should reject xhigh reasoning_effort for claude', () => {
|
|
203
|
+
expect(() => buildCliCommand({
|
|
204
|
+
prompt: 'test',
|
|
205
|
+
workFolder: '/tmp',
|
|
206
|
+
model: 'sonnet',
|
|
207
|
+
reasoning_effort: 'xhigh',
|
|
208
|
+
cliPaths: DEFAULT_CLI_PATHS,
|
|
209
|
+
})).toThrow('Claude reasoning_effort supports only low, medium, high.');
|
|
210
|
+
});
|
|
211
|
+
it('should allow overriding reasoning_effort for claude-ultra', () => {
|
|
212
|
+
const cmd = buildCliCommand({
|
|
213
|
+
prompt: 'test',
|
|
214
|
+
workFolder: '/tmp',
|
|
215
|
+
model: 'claude-ultra',
|
|
216
|
+
reasoning_effort: 'low',
|
|
217
|
+
cliPaths: DEFAULT_CLI_PATHS,
|
|
218
|
+
});
|
|
219
|
+
expect(cmd.args).toContain('--effort');
|
|
220
|
+
expect(cmd.args).toContain('low');
|
|
221
|
+
expect(cmd.args).not.toContain('high');
|
|
222
|
+
});
|
|
176
223
|
});
|
|
177
224
|
describe('codex agent', () => {
|
|
178
225
|
it('should build codex command', () => {
|
|
@@ -251,7 +251,7 @@ describe('Argument Validation Tests', () => {
|
|
|
251
251
|
}
|
|
252
252
|
})).rejects.toThrow(/reasoning_effort/i);
|
|
253
253
|
});
|
|
254
|
-
it('should reject reasoning_effort for
|
|
254
|
+
it('should reject reasoning_effort for unsupported model families', async () => {
|
|
255
255
|
await setupServer();
|
|
256
256
|
const handler = handlers.get('callTool');
|
|
257
257
|
await expect(handler({
|
|
@@ -260,7 +260,7 @@ describe('Argument Validation Tests', () => {
|
|
|
260
260
|
arguments: {
|
|
261
261
|
prompt: 'test',
|
|
262
262
|
workFolder: '/tmp',
|
|
263
|
-
model: '
|
|
263
|
+
model: 'gemini-2.5-pro',
|
|
264
264
|
reasoning_effort: 'low'
|
|
265
265
|
}
|
|
266
266
|
}
|
package/dist/cli-builder.js
CHANGED
|
@@ -7,6 +7,16 @@ export const MODEL_ALIASES = {
|
|
|
7
7
|
'gemini-ultra': 'gemini-3.1-pro-preview'
|
|
8
8
|
};
|
|
9
9
|
export const ALLOWED_REASONING_EFFORTS = new Set(['low', 'medium', 'high', 'xhigh']);
|
|
10
|
+
const CLAUDE_REASONING_EFFORTS = new Set(['low', 'medium', 'high']);
|
|
11
|
+
function getAgentForModel(model) {
|
|
12
|
+
if (model.startsWith('gpt-')) {
|
|
13
|
+
return 'codex';
|
|
14
|
+
}
|
|
15
|
+
if (model.startsWith('gemini')) {
|
|
16
|
+
return 'gemini';
|
|
17
|
+
}
|
|
18
|
+
return 'claude';
|
|
19
|
+
}
|
|
10
20
|
/**
|
|
11
21
|
* Resolves model aliases to their full model names
|
|
12
22
|
* @param model - The model name or alias to resolve
|
|
@@ -32,8 +42,12 @@ export function getReasoningEffort(model, rawValue) {
|
|
|
32
42
|
if (!ALLOWED_REASONING_EFFORTS.has(normalized)) {
|
|
33
43
|
throw new Error(`Invalid reasoning_effort: ${rawValue}. Allowed values: low, medium, high, xhigh.`);
|
|
34
44
|
}
|
|
35
|
-
|
|
36
|
-
|
|
45
|
+
const agent = getAgentForModel(model);
|
|
46
|
+
if (agent === 'gemini') {
|
|
47
|
+
throw new Error('reasoning_effort is only supported for Claude and Codex models.');
|
|
48
|
+
}
|
|
49
|
+
if (agent === 'claude' && !CLAUDE_REASONING_EFFORTS.has(normalized)) {
|
|
50
|
+
throw new Error('Claude reasoning_effort supports only low, medium, high.');
|
|
37
51
|
}
|
|
38
52
|
return normalized;
|
|
39
53
|
}
|
|
@@ -83,23 +97,18 @@ export function buildCliCommand(options) {
|
|
|
83
97
|
// Resolve model
|
|
84
98
|
const rawModel = options.model || '';
|
|
85
99
|
const resolvedModel = resolveModelAlias(rawModel);
|
|
86
|
-
|
|
100
|
+
const agent = getAgentForModel(resolvedModel);
|
|
101
|
+
// Special handling for ultra aliases: default to higher reasoning if not specified
|
|
87
102
|
let reasoningEffortArg = options.reasoning_effort;
|
|
88
|
-
if (
|
|
89
|
-
|
|
103
|
+
if (!reasoningEffortArg) {
|
|
104
|
+
if (rawModel === 'codex-ultra') {
|
|
105
|
+
reasoningEffortArg = 'xhigh';
|
|
106
|
+
}
|
|
107
|
+
else if (rawModel === 'claude-ultra') {
|
|
108
|
+
reasoningEffortArg = 'high';
|
|
109
|
+
}
|
|
90
110
|
}
|
|
91
111
|
const reasoningEffort = getReasoningEffort(resolvedModel, reasoningEffortArg);
|
|
92
|
-
// Determine agent
|
|
93
|
-
let agent;
|
|
94
|
-
if (resolvedModel.startsWith('gpt-')) {
|
|
95
|
-
agent = 'codex';
|
|
96
|
-
}
|
|
97
|
-
else if (resolvedModel.startsWith('gemini')) {
|
|
98
|
-
agent = 'gemini';
|
|
99
|
-
}
|
|
100
|
-
else {
|
|
101
|
-
agent = 'claude';
|
|
102
|
-
}
|
|
103
112
|
// Build CLI path and args
|
|
104
113
|
let cliPath;
|
|
105
114
|
let args;
|
|
@@ -136,6 +145,9 @@ export function buildCliCommand(options) {
|
|
|
136
145
|
if (options.session_id && typeof options.session_id === 'string') {
|
|
137
146
|
args.push('-r', options.session_id, '--fork-session');
|
|
138
147
|
}
|
|
148
|
+
if (reasoningEffort) {
|
|
149
|
+
args.push('--effort', reasoningEffort);
|
|
150
|
+
}
|
|
139
151
|
args.push('-p', prompt);
|
|
140
152
|
if (resolvedModel) {
|
|
141
153
|
args.push('--model', resolvedModel);
|
package/dist/cli.js
CHANGED
|
@@ -40,7 +40,7 @@ Options:
|
|
|
40
40
|
--prompt Prompt string (mutually exclusive with --prompt_file)
|
|
41
41
|
--prompt_file Path to a file containing the prompt
|
|
42
42
|
--session_id Session ID to resume
|
|
43
|
-
--reasoning_effort Codex
|
|
43
|
+
--reasoning_effort Claude/Codex: Claude=low|medium|high, Codex=low|medium|high|xhigh
|
|
44
44
|
--help Show this help message
|
|
45
45
|
|
|
46
46
|
Raw CLI output goes to stdout. Use cli.run.parse to parse the output:
|
package/dist/server.js
CHANGED
|
@@ -144,11 +144,11 @@ export class ClaudeCodeServer {
|
|
|
144
144
|
},
|
|
145
145
|
model: {
|
|
146
146
|
type: 'string',
|
|
147
|
-
description: 'The model to use. Aliases: "claude-ultra", "codex-ultra" (auto
|
|
147
|
+
description: 'The model to use. Aliases: "claude-ultra" (auto high effort), "codex-ultra" (auto xhigh reasoning), "gemini-ultra". Standard: "sonnet", "sonnet[1m]", "opus", "opusplan", "haiku", "gpt-5.4", "gpt-5.3-codex", "gpt-5.2-codex", "gpt-5.1-codex-mini", "gpt-5.1", "gemini-2.5-pro", "gemini-3.1-pro-preview", "gemini-3-pro-preview", "gemini-3-flash-preview", etc.',
|
|
148
148
|
},
|
|
149
149
|
reasoning_effort: {
|
|
150
150
|
type: 'string',
|
|
151
|
-
description: 'Codex
|
|
151
|
+
description: 'Reasoning control for Claude and Codex. Claude uses --effort with "low", "medium", "high". Codex uses model_reasoning_effort with "low", "medium", "high", "xhigh".',
|
|
152
152
|
},
|
|
153
153
|
session_id: {
|
|
154
154
|
type: 'string',
|
package/package.json
CHANGED
|
@@ -76,6 +76,8 @@ describe('cli-builder', () => {
|
|
|
76
76
|
expect(getReasoningEffort('gpt-5.2', 'medium')).toBe('medium');
|
|
77
77
|
expect(getReasoningEffort('gpt-5.2', 'high')).toBe('high');
|
|
78
78
|
expect(getReasoningEffort('gpt-5.2', 'xhigh')).toBe('xhigh');
|
|
79
|
+
expect(getReasoningEffort('sonnet', 'high')).toBe('high');
|
|
80
|
+
expect(getReasoningEffort('', 'low')).toBe('low');
|
|
79
81
|
});
|
|
80
82
|
|
|
81
83
|
it('should throw for invalid reasoning effort value', () => {
|
|
@@ -84,9 +86,15 @@ describe('cli-builder', () => {
|
|
|
84
86
|
);
|
|
85
87
|
});
|
|
86
88
|
|
|
87
|
-
it('should
|
|
88
|
-
expect(() => getReasoningEffort('sonnet', '
|
|
89
|
-
'reasoning_effort
|
|
89
|
+
it('should reject xhigh for claude models', () => {
|
|
90
|
+
expect(() => getReasoningEffort('sonnet', 'xhigh')).toThrow(
|
|
91
|
+
'Claude reasoning_effort supports only low, medium, high.'
|
|
92
|
+
);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it('should throw for unsupported model families', () => {
|
|
96
|
+
expect(() => getReasoningEffort('gemini-2.5-pro', 'high')).toThrow(
|
|
97
|
+
'reasoning_effort is only supported for Claude and Codex models.'
|
|
90
98
|
);
|
|
91
99
|
});
|
|
92
100
|
});
|
|
@@ -224,6 +232,57 @@ describe('cli-builder', () => {
|
|
|
224
232
|
expect(cmd.resolvedModel).toBe('opus');
|
|
225
233
|
expect(cmd.args).toContain('opus');
|
|
226
234
|
});
|
|
235
|
+
|
|
236
|
+
it('should resolve claude-ultra and default to high effort', () => {
|
|
237
|
+
const cmd = buildCliCommand({
|
|
238
|
+
prompt: 'test',
|
|
239
|
+
workFolder: '/tmp',
|
|
240
|
+
model: 'claude-ultra',
|
|
241
|
+
cliPaths: DEFAULT_CLI_PATHS,
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
expect(cmd.args).toContain('--effort');
|
|
245
|
+
expect(cmd.args).toContain('high');
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
it('should build claude command with reasoning_effort using --effort', () => {
|
|
249
|
+
const cmd = buildCliCommand({
|
|
250
|
+
prompt: 'test',
|
|
251
|
+
workFolder: '/tmp',
|
|
252
|
+
model: 'sonnet',
|
|
253
|
+
reasoning_effort: 'medium',
|
|
254
|
+
cliPaths: DEFAULT_CLI_PATHS,
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
expect(cmd.args).toContain('--effort');
|
|
258
|
+
expect(cmd.args).toContain('medium');
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
it('should reject xhigh reasoning_effort for claude', () => {
|
|
262
|
+
expect(() =>
|
|
263
|
+
buildCliCommand({
|
|
264
|
+
prompt: 'test',
|
|
265
|
+
workFolder: '/tmp',
|
|
266
|
+
model: 'sonnet',
|
|
267
|
+
reasoning_effort: 'xhigh',
|
|
268
|
+
cliPaths: DEFAULT_CLI_PATHS,
|
|
269
|
+
})
|
|
270
|
+
).toThrow('Claude reasoning_effort supports only low, medium, high.');
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
it('should allow overriding reasoning_effort for claude-ultra', () => {
|
|
274
|
+
const cmd = buildCliCommand({
|
|
275
|
+
prompt: 'test',
|
|
276
|
+
workFolder: '/tmp',
|
|
277
|
+
model: 'claude-ultra',
|
|
278
|
+
reasoning_effort: 'low',
|
|
279
|
+
cliPaths: DEFAULT_CLI_PATHS,
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
expect(cmd.args).toContain('--effort');
|
|
283
|
+
expect(cmd.args).toContain('low');
|
|
284
|
+
expect(cmd.args).not.toContain('high');
|
|
285
|
+
});
|
|
227
286
|
});
|
|
228
287
|
|
|
229
288
|
describe('codex agent', () => {
|
|
@@ -301,7 +301,7 @@ describe('Argument Validation Tests', () => {
|
|
|
301
301
|
).rejects.toThrow(/reasoning_effort/i);
|
|
302
302
|
});
|
|
303
303
|
|
|
304
|
-
it('should reject reasoning_effort for
|
|
304
|
+
it('should reject reasoning_effort for unsupported model families', async () => {
|
|
305
305
|
await setupServer();
|
|
306
306
|
const handler = handlers.get('callTool')!;
|
|
307
307
|
|
|
@@ -312,7 +312,7 @@ describe('Argument Validation Tests', () => {
|
|
|
312
312
|
arguments: {
|
|
313
313
|
prompt: 'test',
|
|
314
314
|
workFolder: '/tmp',
|
|
315
|
-
model: '
|
|
315
|
+
model: 'gemini-2.5-pro',
|
|
316
316
|
reasoning_effort: 'low'
|
|
317
317
|
}
|
|
318
318
|
}
|
package/src/cli-builder.ts
CHANGED
|
@@ -9,6 +9,17 @@ export const MODEL_ALIASES: Record<string, string> = {
|
|
|
9
9
|
};
|
|
10
10
|
|
|
11
11
|
export const ALLOWED_REASONING_EFFORTS = new Set(['low', 'medium', 'high', 'xhigh']);
|
|
12
|
+
const CLAUDE_REASONING_EFFORTS = new Set(['low', 'medium', 'high']);
|
|
13
|
+
|
|
14
|
+
function getAgentForModel(model: string): 'codex' | 'claude' | 'gemini' {
|
|
15
|
+
if (model.startsWith('gpt-')) {
|
|
16
|
+
return 'codex';
|
|
17
|
+
}
|
|
18
|
+
if (model.startsWith('gemini')) {
|
|
19
|
+
return 'gemini';
|
|
20
|
+
}
|
|
21
|
+
return 'claude';
|
|
22
|
+
}
|
|
12
23
|
|
|
13
24
|
/**
|
|
14
25
|
* Resolves model aliases to their full model names
|
|
@@ -38,9 +49,15 @@ export function getReasoningEffort(model: string, rawValue: unknown): string {
|
|
|
38
49
|
`Invalid reasoning_effort: ${rawValue}. Allowed values: low, medium, high, xhigh.`
|
|
39
50
|
);
|
|
40
51
|
}
|
|
41
|
-
|
|
52
|
+
const agent = getAgentForModel(model);
|
|
53
|
+
if (agent === 'gemini') {
|
|
54
|
+
throw new Error(
|
|
55
|
+
'reasoning_effort is only supported for Claude and Codex models.'
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
if (agent === 'claude' && !CLAUDE_REASONING_EFFORTS.has(normalized)) {
|
|
42
59
|
throw new Error(
|
|
43
|
-
'reasoning_effort
|
|
60
|
+
'Claude reasoning_effort supports only low, medium, high.'
|
|
44
61
|
);
|
|
45
62
|
}
|
|
46
63
|
return normalized;
|
|
@@ -117,25 +134,20 @@ export function buildCliCommand(options: BuildCliCommandOptions): CliCommand {
|
|
|
117
134
|
// Resolve model
|
|
118
135
|
const rawModel = options.model || '';
|
|
119
136
|
const resolvedModel = resolveModelAlias(rawModel);
|
|
137
|
+
const agent = getAgentForModel(resolvedModel);
|
|
120
138
|
|
|
121
|
-
// Special handling for
|
|
139
|
+
// Special handling for ultra aliases: default to higher reasoning if not specified
|
|
122
140
|
let reasoningEffortArg: string | undefined = options.reasoning_effort;
|
|
123
|
-
if (
|
|
124
|
-
|
|
141
|
+
if (!reasoningEffortArg) {
|
|
142
|
+
if (rawModel === 'codex-ultra') {
|
|
143
|
+
reasoningEffortArg = 'xhigh';
|
|
144
|
+
} else if (rawModel === 'claude-ultra') {
|
|
145
|
+
reasoningEffortArg = 'high';
|
|
146
|
+
}
|
|
125
147
|
}
|
|
126
148
|
|
|
127
149
|
const reasoningEffort = getReasoningEffort(resolvedModel, reasoningEffortArg);
|
|
128
150
|
|
|
129
|
-
// Determine agent
|
|
130
|
-
let agent: 'codex' | 'claude' | 'gemini';
|
|
131
|
-
if (resolvedModel.startsWith('gpt-')) {
|
|
132
|
-
agent = 'codex';
|
|
133
|
-
} else if (resolvedModel.startsWith('gemini')) {
|
|
134
|
-
agent = 'gemini';
|
|
135
|
-
} else {
|
|
136
|
-
agent = 'claude';
|
|
137
|
-
}
|
|
138
|
-
|
|
139
151
|
// Build CLI path and args
|
|
140
152
|
let cliPath: string;
|
|
141
153
|
let args: string[];
|
|
@@ -180,6 +192,10 @@ export function buildCliCommand(options: BuildCliCommandOptions): CliCommand {
|
|
|
180
192
|
args.push('-r', options.session_id, '--fork-session');
|
|
181
193
|
}
|
|
182
194
|
|
|
195
|
+
if (reasoningEffort) {
|
|
196
|
+
args.push('--effort', reasoningEffort);
|
|
197
|
+
}
|
|
198
|
+
|
|
183
199
|
args.push('-p', prompt);
|
|
184
200
|
if (resolvedModel) {
|
|
185
201
|
args.push('--model', resolvedModel);
|
package/src/cli.ts
CHANGED
|
@@ -40,7 +40,7 @@ Options:
|
|
|
40
40
|
--prompt Prompt string (mutually exclusive with --prompt_file)
|
|
41
41
|
--prompt_file Path to a file containing the prompt
|
|
42
42
|
--session_id Session ID to resume
|
|
43
|
-
--reasoning_effort Codex
|
|
43
|
+
--reasoning_effort Claude/Codex: Claude=low|medium|high, Codex=low|medium|high|xhigh
|
|
44
44
|
--help Show this help message
|
|
45
45
|
|
|
46
46
|
Raw CLI output goes to stdout. Use cli.run.parse to parse the output:
|
package/src/server.ts
CHANGED
|
@@ -190,11 +190,11 @@ export class ClaudeCodeServer {
|
|
|
190
190
|
},
|
|
191
191
|
model: {
|
|
192
192
|
type: 'string',
|
|
193
|
-
description: 'The model to use. Aliases: "claude-ultra", "codex-ultra" (auto
|
|
193
|
+
description: 'The model to use. Aliases: "claude-ultra" (auto high effort), "codex-ultra" (auto xhigh reasoning), "gemini-ultra". Standard: "sonnet", "sonnet[1m]", "opus", "opusplan", "haiku", "gpt-5.4", "gpt-5.3-codex", "gpt-5.2-codex", "gpt-5.1-codex-mini", "gpt-5.1", "gemini-2.5-pro", "gemini-3.1-pro-preview", "gemini-3-pro-preview", "gemini-3-flash-preview", etc.',
|
|
194
194
|
},
|
|
195
195
|
reasoning_effort: {
|
|
196
196
|
type: 'string',
|
|
197
|
-
description: 'Codex
|
|
197
|
+
description: 'Reasoning control for Claude and Codex. Claude uses --effort with "low", "medium", "high". Codex uses model_reasoning_effort with "low", "medium", "high", "xhigh".',
|
|
198
198
|
},
|
|
199
199
|
session_id: {
|
|
200
200
|
type: 'string',
|
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
name: Watch Codex Fork PR
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
schedule:
|
|
5
|
-
- cron: '17 0 * * *'
|
|
6
|
-
workflow_dispatch:
|
|
7
|
-
|
|
8
|
-
permissions:
|
|
9
|
-
contents: read
|
|
10
|
-
issues: write
|
|
11
|
-
|
|
12
|
-
jobs:
|
|
13
|
-
watch-pr:
|
|
14
|
-
runs-on: ubuntu-latest
|
|
15
|
-
steps:
|
|
16
|
-
- name: Check upstream PR and notify issue
|
|
17
|
-
uses: actions/github-script@v7
|
|
18
|
-
env:
|
|
19
|
-
UPSTREAM_OWNER: openai
|
|
20
|
-
UPSTREAM_REPO: codex
|
|
21
|
-
UPSTREAM_PR_NUMBER: '13537'
|
|
22
|
-
TARGET_ISSUE_NUMBER: '7'
|
|
23
|
-
COMMENT_MARKER: '<!-- codex-fork-pr-13537-merged -->'
|
|
24
|
-
with:
|
|
25
|
-
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
26
|
-
script: |
|
|
27
|
-
const upstreamOwner = process.env.UPSTREAM_OWNER;
|
|
28
|
-
const upstreamRepo = process.env.UPSTREAM_REPO;
|
|
29
|
-
const pull_number = Number(process.env.UPSTREAM_PR_NUMBER);
|
|
30
|
-
const issue_number = Number(process.env.TARGET_ISSUE_NUMBER);
|
|
31
|
-
const marker = process.env.COMMENT_MARKER;
|
|
32
|
-
|
|
33
|
-
const { data: pr } = await github.rest.pulls.get({
|
|
34
|
-
owner: upstreamOwner,
|
|
35
|
-
repo: upstreamRepo,
|
|
36
|
-
pull_number,
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
core.summary
|
|
40
|
-
.addHeading('Upstream PR status')
|
|
41
|
-
.addTable([
|
|
42
|
-
[
|
|
43
|
-
{ data: 'Field', header: true },
|
|
44
|
-
{ data: 'Value', header: true },
|
|
45
|
-
],
|
|
46
|
-
['PR', `${upstreamOwner}/${upstreamRepo}#${pr.number}`],
|
|
47
|
-
['Title', pr.title],
|
|
48
|
-
['State', pr.state],
|
|
49
|
-
['Merged', String(Boolean(pr.merged_at))],
|
|
50
|
-
['Merged at', pr.merged_at ?? 'not merged'],
|
|
51
|
-
['Updated at', pr.updated_at],
|
|
52
|
-
['URL', pr.html_url],
|
|
53
|
-
]);
|
|
54
|
-
|
|
55
|
-
if (!pr.merged_at) {
|
|
56
|
-
core.info(`PR #${pr.number} is not merged yet. No issue comment posted.`);
|
|
57
|
-
await core.summary.write();
|
|
58
|
-
return;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
const comments = await github.paginate(github.rest.issues.listComments, {
|
|
62
|
-
owner: context.repo.owner,
|
|
63
|
-
repo: context.repo.repo,
|
|
64
|
-
issue_number,
|
|
65
|
-
per_page: 100,
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
const existingComment = comments.find((comment) => comment.body?.includes(marker));
|
|
69
|
-
if (existingComment) {
|
|
70
|
-
core.info(`Issue #${issue_number} already has a merged notification comment.`);
|
|
71
|
-
await core.summary.addRaw(`Merged notification already exists: ${existingComment.html_url}\n`).write();
|
|
72
|
-
return;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
const body = [
|
|
76
|
-
marker,
|
|
77
|
-
'upstream PR `openai/codex#13537` has been merged.',
|
|
78
|
-
'',
|
|
79
|
-
`- PR: ${pr.html_url}`,
|
|
80
|
-
`- Merged at: ${pr.merged_at}`,
|
|
81
|
-
'',
|
|
82
|
-
'This is the PR that adds non-interactive forking via `codex exec --fork <SESSION_ID> [PROMPT]`.',
|
|
83
|
-
'That means a new session ID can be issued when forking an existing session headlessly.',
|
|
84
|
-
'`resume` itself still continues the same session and does not issue a new session ID.',
|
|
85
|
-
].join('\n');
|
|
86
|
-
|
|
87
|
-
const { data: comment } = await github.rest.issues.createComment({
|
|
88
|
-
owner: context.repo.owner,
|
|
89
|
-
repo: context.repo.repo,
|
|
90
|
-
issue_number,
|
|
91
|
-
body,
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
core.info(`Posted merged notification to issue #${issue_number}: ${comment.html_url}`);
|
|
95
|
-
await core.summary
|
|
96
|
-
.addHeading('Issue notification')
|
|
97
|
-
.addRaw(`Posted merged notification: ${comment.html_url}\n`)
|
|
98
|
-
.write();
|