ci(release): publish npm packages last; bump codex-cli to 0.2.58 and compute version across all npm targets to avoid E403 overwrite

This commit is contained in:
James Peter
2025-09-05 18:51:00 +10:00
parent d497a1aaf4
commit cef240fd85
7 changed files with 79 additions and 38 deletions
+43 -7
View File
@@ -34,15 +34,30 @@ jobs:
node-version: '20'
registry-url: 'https://registry.npmjs.org'
- name: Determine next version
- name: Determine next version (across all npm packages)
id: version
working-directory: codex-cli
shell: bash
run: |
set -euo pipefail
CURRENT_VERSION=$(node -p "require('./package.json').version")
PUBLISHED_VERSION=$(npm view @just-every/code version 2>/dev/null || echo "0.0.0")
if [ "$CURRENT_VERSION" = "$PUBLISHED_VERSION" ] || [ "$CURRENT_VERSION" \< "$PUBLISHED_VERSION" ]; then
IFS='.' read -ra V <<< "$PUBLISHED_VERSION"
PKGS=(
"@just-every/code"
"@just-every/code-darwin-arm64"
"@just-every/code-darwin-x64"
"@just-every/code-linux-x64-musl"
"@just-every/code-linux-arm64-musl"
"@just-every/code-win32-x64"
)
VERS=("$CURRENT_VERSION")
for p in "${PKGS[@]}"; do
v=$(npm view "$p" version 2>/dev/null || echo "0.0.0")
VERS+=("$v")
done
MAX_PUBLISHED=$(printf '%s\n' "${VERS[@]}" | sort -V | tail -n1)
# If our current version is <= max published, bump the patch of max.
if [ "$CURRENT_VERSION" = "$MAX_PUBLISHED" ] || [ "$CURRENT_VERSION" \< "$MAX_PUBLISHED" ]; then
IFS='.' read -ra V <<< "$MAX_PUBLISHED"
NEW_VERSION="${V[0]}.${V[1]}.$((${V[2]} + 1))"
else
NEW_VERSION=$CURRENT_VERSION
@@ -378,8 +393,8 @@ jobs:
ls -R "$stage_root"
- name: Publish per-target npm binary packages
if: ${{ env.NPM_TOKEN != '' }}
- name: Publish per-target npm binary packages (disabled; moved to end)
if: ${{ false }}
env:
NODE_AUTH_TOKEN: ${{ env.NPM_TOKEN }}
shell: bash
@@ -526,7 +541,9 @@ jobs:
cat release-notes/context.md >> release-notes/prompt.expanded.txt
# Run Code in fully automated exec mode against the repo root.
./.code-bin/code exec --full-auto --skip-git-repo-check --cwd "$GITHUB_WORKSPACE" < release-notes/prompt.expanded.txt || {
# NOTE: `--cwd` is a top-level flag, not an `exec` subcommand flag.
# Move it before `exec` to avoid clap parsing errors in CI.
./.code-bin/code --cwd "$GITHUB_WORKSPACE" exec --full-auto --skip-git-repo-check < release-notes/prompt.expanded.txt || {
echo "Code exec returned non-zero; continuing to check for outputs..." >&2
}
@@ -599,3 +616,22 @@ jobs:
release-assets/*
env:
GITHUB_TOKEN: ${{ secrets.GH_PAT || secrets.GITHUB_TOKEN }}
- name: Publish per-target npm binary packages (last)
if: ${{ env.NPM_TOKEN != '' }}
env:
NODE_AUTH_TOKEN: ${{ env.NPM_TOKEN }}
shell: bash
run: |
set -euo pipefail
for dir in npm-binaries/*; do
echo "Publishing $(basename \"$dir\")"
(cd "$dir" && npm publish --access public)
done
- name: Publish main npm package (last)
if: steps.should_publish.outputs.publish == 'true'
working-directory: codex-cli
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
run: npm publish --access public
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@just-every/code",
"version": "0.2.56",
"version": "0.2.58",
"license": "Apache-2.0",
"description": "Lightweight coding agent that runs in your terminal - fork of OpenAI Codex",
"bin": {
+1
View File
@@ -74,6 +74,7 @@ agent_wait {"batch_id":"<batch_id>","return_all":true,"timeout_seconds": 600 } /
- Before pushing, always run `git pull` to sync with remote. Prefer merge over rebase by default; avoid rebases as a first resort.
- If a rebase is explicitly required by maintainers, confirm first and proceed carefully; otherwise stick to pull/merge to prevent history churn and conflicts.
- NEVER use `git revert` or `git checkout` unless you are sure it will not overwrite any unrelated changes. Multiple changes may have been made to the code and you can not be sure that you will revert only your changes.
- Don't perform `git push` unless you are asked to.
# WARNING (editing files)
- Never replace the content of a file before checking what exists in it. For example, when writing to AGENTS.md always append, don't just replace existing content.
+7 -4
View File
@@ -826,7 +826,7 @@ impl Session {
let event = self.make_event(
&sub_id,
EventMsg::ExecApprovalRequest(ExecApprovalRequestEvent {
call_id,
call_id: call_id.clone(),
command,
cwd,
reason,
@@ -835,7 +835,9 @@ impl Session {
let _ = self.tx_event.send(event).await;
{
let mut state = self.state.lock().unwrap();
state.pending_approvals.insert(sub_id, tx_approve);
// Track pending approval by call_id (unique per request) rather than sub_id
// so parallel approvals in the same turn do not clobber each other.
state.pending_approvals.insert(call_id, tx_approve);
}
rx_approve
}
@@ -852,7 +854,7 @@ impl Session {
let event = self.make_event(
&sub_id,
EventMsg::ApplyPatchApprovalRequest(ApplyPatchApprovalRequestEvent {
call_id,
call_id: call_id.clone(),
changes: convert_apply_patch_to_protocol(action),
reason,
grant_root,
@@ -861,7 +863,8 @@ impl Session {
let _ = self.tx_event.send(event).await;
{
let mut state = self.state.lock().unwrap();
state.pending_approvals.insert(sub_id, tx_approve);
// Track pending approval by call_id to avoid collisions.
state.pending_approvals.insert(call_id, tx_approve);
}
rx_approve
}
@@ -498,7 +498,7 @@ async fn apply_bespoke_event_handling(
outgoing: Arc<OutgoingMessageSender>,
_pending_interrupts: Arc<Mutex<HashMap<Uuid, Vec<RequestId>>>>,
) {
let Event { id: event_id, msg, .. } = event;
let Event { id: _event_id, msg, .. } = event;
match msg {
EventMsg::ApplyPatchApprovalRequest(ApplyPatchApprovalRequestEvent {
call_id,
@@ -527,7 +527,7 @@ async fn apply_bespoke_event_handling(
let params = ApplyPatchApprovalParams {
conversation_id,
call_id,
call_id: call_id.clone(),
file_changes,
reason,
grant_root,
@@ -537,8 +537,9 @@ async fn apply_bespoke_event_handling(
.send_request(APPLY_PATCH_APPROVAL_METHOD, Some(value))
.await;
// TODO(mbolin): Enforce a timeout so this task does not live indefinitely?
let approval_id = call_id.clone(); // correlate by call_id, not event_id
tokio::spawn(async move {
on_patch_approval_response(event_id, rx, conversation).await;
on_patch_approval_response(approval_id, rx, conversation).await;
});
}
EventMsg::ExecApprovalRequest(ExecApprovalRequestEvent {
@@ -549,7 +550,7 @@ async fn apply_bespoke_event_handling(
}) => {
let params = ExecCommandApprovalParams {
conversation_id,
call_id,
call_id: call_id.clone(),
command,
cwd,
reason,
@@ -560,8 +561,9 @@ async fn apply_bespoke_event_handling(
.await;
// TODO(mbolin): Enforce a timeout so this task does not live indefinitely?
let approval_id = call_id.clone(); // correlate by call_id, not event_id
tokio::spawn(async move {
on_exec_approval_response(event_id, rx, conversation).await;
on_exec_approval_response(approval_id, rx, conversation).await;
});
}
// No special handling needed for interrupts; responses are sent immediately.
@@ -611,7 +613,7 @@ fn derive_config_from_params(
}
async fn on_patch_approval_response(
event_id: String,
approval_id: String,
receiver: tokio::sync::oneshot::Receiver<mcp_types::Result>,
codex: Arc<CodexConversation>,
) {
@@ -622,7 +624,7 @@ async fn on_patch_approval_response(
error!("request failed: {err:?}");
if let Err(submit_err) = codex
.submit(Op::PatchApproval {
id: event_id.clone(),
id: approval_id.clone(),
decision: core_protocol::ReviewDecision::Denied,
})
.await
@@ -643,7 +645,7 @@ async fn on_patch_approval_response(
if let Err(err) = codex
.submit(Op::PatchApproval {
id: event_id,
id: approval_id,
decision: map_review_decision_from_wire(response.decision),
})
.await
@@ -653,7 +655,7 @@ async fn on_patch_approval_response(
}
async fn on_exec_approval_response(
event_id: String,
approval_id: String,
receiver: tokio::sync::oneshot::Receiver<mcp_types::Result>,
conversation: Arc<CodexConversation>,
) {
@@ -679,7 +681,7 @@ async fn on_exec_approval_response(
if let Err(err) = conversation
.submit(Op::ExecApproval {
id: event_id,
id: approval_id,
decision: map_review_decision_from_wire(response.decision),
})
.await
+6 -5
View File
@@ -74,7 +74,7 @@ pub(crate) async fn handle_exec_approval_request(
codex_elicitation: "exec-approval".to_string(),
codex_mcp_tool_call_id: tool_call_id.clone(),
codex_event_id: event_id.clone(),
codex_call_id: call_id,
codex_call_id: call_id.clone(),
codex_command: command,
codex_cwd: cwd,
};
@@ -106,15 +106,16 @@ pub(crate) async fn handle_exec_approval_request(
// Listen for the response on a separate task so we don't block the main agent loop.
{
let codex = codex.clone();
let event_id = event_id.clone();
// Correlate by call_id for core pending approvals
let approval_id = call_id.clone();
tokio::spawn(async move {
on_exec_approval_response(event_id, on_response, codex).await;
on_exec_approval_response(approval_id, on_response, codex).await;
});
}
}
async fn on_exec_approval_response(
event_id: String,
approval_id: String,
receiver: tokio::sync::oneshot::Receiver<mcp_types::Result>,
codex: Arc<CodexConversation>,
) {
@@ -139,7 +140,7 @@ async fn on_exec_approval_response(
if let Err(err) = codex
.submit(Op::ExecApproval {
id: event_id,
id: approval_id,
decision: response.decision,
})
.await
+9 -11
View File
@@ -707,19 +707,21 @@ impl ChatWidget<'_> {
/// Handle exec approval request immediately
fn handle_exec_approval_now(&mut self, id: String, ev: ExecApprovalRequestEvent) {
// Implementation for handling exec approval request
fn handle_exec_approval_now(&mut self, _id: String, ev: ExecApprovalRequestEvent) {
// Use call_id as the approval correlation id so responses map to the
// exact pending approval in core (supports multiple approvals per turn).
let approval_id = ev.call_id.clone();
self.bottom_pane.push_approval_request(ApprovalRequest::Exec {
id,
id: approval_id,
command: ev.command,
reason: ev.reason,
});
}
/// Handle apply patch approval request immediately
fn handle_apply_patch_approval_now(&mut self, id: String, ev: ApplyPatchApprovalRequestEvent) {
fn handle_apply_patch_approval_now(&mut self, _id: String, ev: ApplyPatchApprovalRequestEvent) {
let ApplyPatchApprovalRequestEvent {
call_id: _,
call_id,
changes,
reason,
grant_root,
@@ -764,12 +766,8 @@ impl ChatWidget<'_> {
// Enable Ctrl+D footer hint now that we have diffs to show
self.bottom_pane.set_diffs_hint(true);
// Push the approval request to the bottom pane
let request = ApprovalRequest::ApplyPatch {
id,
reason,
grant_root,
};
// Push the approval request to the bottom pane, keyed by call_id
let request = ApprovalRequest::ApplyPatch { id: call_id, reason, grant_root };
self.bottom_pane.push_approval_request(request);
}