Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ Everything is in [docs/CONFIG.md](docs/CONFIG.md).
| `v` / `x` | Validate the finding / propose a fix |
| `y` / `r` | Apply / discard a proposed fix |
| `g` | Discuss the finding in the conversation you came from |
| `e` / `u` | Run a scan again / resume a stopped Deep scan |
| `e` / `u` | Run a scan again / resume a stopped scan |
| `tab` | Switch between scans and other activity |
| `h` | List every key available right now |

Expand Down Expand Up @@ -189,7 +189,7 @@ Context files for a scan may be absolute paths in other checkouts. Any UTF-8 tex
- **Your source goes to your model provider.** Every scan, validation, fix and policy draft shows where, and waits for your approval.
- **Costs are estimates.** `scan.maxCostUsd` stops a scan on the SDK's estimate; it is not a billing cap. Validation and fixes have no cost limit.
- **Findings arrive when a scan completes**, not while it runs. If a scan fails or is cancelled, whatever it had saved is shown as partial results.
- **Standard scans have no time limit** unless you set one, and treat it as a target. A stopped Standard scan can be run again; a stopped Deep scan can be resumed where it left off.
- **Standard scans have no time limit** unless you set one, and treat it as a target. A scan that lost its connection or was cut off by a restart can be resumed where it left off; any other stopped scan can be run again.
- **A fix is written against your last commit.** It does not see uncommitted work, and applying it fails cleanly if you have since changed the same lines.
- **Change scans run at Standard depth.**
- **Restarts.** Scan results and finding status are kept. A scan that was running is marked interrupted, and policy drafts, validations and unapplied fixes in progress are lost.
Expand Down
2 changes: 1 addition & 1 deletion docs/PUBLISHING.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,4 +79,4 @@ Provenance identifies the staging workflow; `build-manifest.json` links the byte
- [npm trust prerequisites](https://docs.npmjs.com/cli/v11/commands/npm-trust/)
- [npm dual-use policy](https://docs.npmjs.com/policies/dual-use/)

Verified November 10, 2026; recheck before release. Installed metadata identifies Codex Security 0.9.1 as Apache-2.0, OpenCode plugin/Solid as MIT, and OpenTUI native binaries as MIT AND LGPL-2.1-or-later. Dependencies stay external; this is not comprehensive legal clearance.
Verified November 10, 2026; recheck before release. Installed metadata identifies Codex Security 0.10.0 as Apache-2.0, OpenCode plugin/Solid as MIT, and OpenTUI native binaries as MIT AND LGPL-2.1-or-later. Dependencies stay external; this is not comprehensive legal clearance.
179 changes: 124 additions & 55 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
"test:runtime": "node --test tests/sdk-runtime.test.mjs"
},
"dependencies": {
"@openai/codex-security": "0.9.1",
"@openai/codex-security": "0.10.0",
"@opencode/plugin": "2.2.6",
"smol-toml": "1.9.1"
},
Expand Down
11 changes: 8 additions & 3 deletions src/core/codex-adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,10 @@ export function mapSdkFinding(finding: SdkFinding): Finding | null {
* provider answered, and whether trying again can help.
*/
export function providerFailure(message: string, reason?: string): string {
const answer = /^Reconnecting\.\.\. \d+\/\d+ \((.*)\)$/s.exec(message.trim())?.[1];
if (!answer) return message;
// The SDK appends its CLI's resume command; the views have their own.
const text = message.replace(/\nResume when connected: .*$/s, '').trim();
const answer = /^Reconnecting\.\.\. \d+\/\d+ \((.*)\)$/s.exec(text)?.[1];
if (!answer) return text;
const status = /unexpected status (\d{3})/.exec(answer)?.[1];
const refused =
reason === 'authorization' ||
Expand Down Expand Up @@ -223,7 +225,7 @@ export class CodexScanService {
target: await scanTarget(plan),
...(plan.scanPrompt ? { scanPrompt: plan.scanPrompt } : {}),
knowledgeBasePaths: plan.contextFiles.map((file) => resolve(this.root, file.path)),
// Not in the SDK's public types: its CLI resumes a Deep scan with these two options.
// Not in the SDK's public types: its CLI resumes a scan with these two options.
...(plan.sdk.resume
? { resumeScanId: plan.sdk.resume.scanId, outputDir: plan.sdk.resume.outputDir }
: {}),
Expand Down Expand Up @@ -391,6 +393,9 @@ export class CodexScanService {
? 'Cancelled; results incomplete'
: 'Codex Security scan failed';
const budget = signal.aborted ? undefined : scanBudgetFailure(error);
// The SDK keeps a scan open only when the connection dropped. A refusal or a failure closes it.
this.#state.resumable =
!signal.aborted && (error as Error)?.constructor?.name === 'ScanInterruptedError';
if (budget) {
this.#state.estimatedCostUsd = budget.estimatedCostUsd;
const cost = costSummary((error as { cost: Parameters<typeof costSummary>[0] }).cost);
Expand Down
Loading
Loading