@kenkaiiii/ggcoder 5.44.1 → 5.44.2
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/assets/skills/bulletproof/SKILL.md +6 -4
- package/assets/skills/bulletproof/references/audit-protocol.md +14 -21
- package/assets/skills/bulletproof/references/platform-playbooks.md +18 -3
- package/assets/skills/bulletproof/references/secure-defaults.md +4 -0
- package/dist/app-sidecar.js +10 -1
- package/dist/app-sidecar.js.map +1 -1
- package/dist/core/event-bus.d.ts +1 -1
- package/dist/core/event-bus.d.ts.map +1 -1
- package/dist/core/event-bus.js.map +1 -1
- package/dist/ui/App.d.ts.map +1 -1
- package/dist/ui/App.js +4 -2
- package/dist/ui/App.js.map +1 -1
- package/dist/ui/app-items.d.ts +2 -0
- package/dist/ui/app-items.d.ts.map +1 -1
- package/dist/ui/app-items.js +2 -0
- package/dist/ui/app-items.js.map +1 -1
- package/dist/ui/hooks/useAgentLoop.d.ts +1 -1
- package/dist/ui/hooks/useAgentLoop.d.ts.map +1 -1
- package/dist/ui/hooks/useAgentLoop.js.map +1 -1
- package/package.json +4 -4
|
@@ -9,6 +9,8 @@ compatibility: Works offline from the bundled references, which are a snapshot d
|
|
|
9
9
|
|
|
10
10
|
Make software hold up against a real attacker — one that is now partly automated, reads your public code end-to-end, and moves in minutes. Built for solo developers and small teams, who get breached through a short list of boring mistakes, not exotic ones.
|
|
11
11
|
|
|
12
|
+
**This skill is on from the first line of code.** The default mode is the inline gate below — write the safe version while building, in the main thread. Nothing here requires spawning subagents or scheduling an audit.
|
|
13
|
+
|
|
12
14
|
## Governing rules
|
|
13
15
|
|
|
14
16
|
1. **Reachability decides everything.** A vulnerability class only matters if untrusted data can actually reach the dangerous operation. Trace the path before you rank the risk — source, hops, sink. No path, no finding. Conversely: if a path exists, the framework's reputation does not save it.
|
|
@@ -16,7 +18,7 @@ Make software hold up against a real attacker — one that is now partly automat
|
|
|
16
18
|
3. **Assume a machine-speed adversary.** Public code is continuously read by automated scanners on both sides. Leaked credentials get used, not filed. Design so that one mistake is survivable: scope credentials, cap blast radius, make rotation possible. See `references/threat-landscape.md`.
|
|
17
19
|
4. **Fix, do not just flag.** Inline, build the control into the feature as you write it. In a full review, report first — then fix what the user selects. A list of findings nobody implements has done nothing.
|
|
18
20
|
5. **Never certify.** Do not write or say "secure", "hardened", "unhackable", "bulletproof", "audited", or "no vulnerabilities". State what you checked, what you fixed, what you could not verify, and what remains. Absence of findings is absence of findings.
|
|
19
|
-
6. **Defensive output only.** Describe risk at the data-flow level — where untrusted data enters, what it reaches, why that is fixable. No working exploits, no weaponized payloads, no attack tooling, in any mode
|
|
21
|
+
6. **Defensive output only.** Describe risk at the data-flow level — where untrusted data enters, what it reaches, why that is fixable. No working exploits, no weaponized payloads, no attack tooling, in any mode. If you cannot explain a risk without writing an exploit, describe the flow and the fix instead.
|
|
20
22
|
7. **Proportionality.** Rank by realistic exposure: probability × blast radius. A prototype with no users and no secrets does not need forty findings. Five real fixes beat forty ignored ones.
|
|
21
23
|
8. **Date-check before asserting.** The references are a snapshot dated **12 August 2026**. CVEs, versions, defaults, and incident details move weekly. Re-verify with web access when available; when unavailable, say the claim is from a dated snapshot. Never invent a CVE number, a version, or an advisory.
|
|
22
24
|
|
|
@@ -26,7 +28,7 @@ Make software hold up against a real attacker — one that is now partly automat
|
|
|
26
28
|
|
|
27
29
|
This mode matters most, because the users who need this skill will never ask for it. They ask for a login page, a file upload, an admin route, a Stripe webhook, a CLI that runs a command. **Write the safe version the first time** — parameterize the query, enforce authorization at the data layer, resolve the path and check containment, pass argv instead of a shell string, pin the dependency after verifying it exists. Do not stop the build to deliver a lecture, and do not ship the unsafe version intending to flag it later.
|
|
28
30
|
|
|
29
|
-
**Full review** — triggered by "is this safe to ship", a hardening pass, pre-launch, suspected compromise, or first use of this skill on a project. Run the workflow below; the full
|
|
31
|
+
**Full review** — triggered by "is this safe to ship", a hardening pass, pre-launch, suspected compromise, or first use of this skill on a project. Run the workflow below yourself, in the main thread; the full protocol, audit catalog, false-positive filter, and report template live in `references/audit-protocol.md`.
|
|
30
32
|
|
|
31
33
|
## Workflow
|
|
32
34
|
|
|
@@ -147,8 +149,8 @@ Building detection, hardening, monitoring, honeypots on your own systems, and CT
|
|
|
147
149
|
Resolve every path from the installed skill root. Load only what the profile triggered.
|
|
148
150
|
|
|
149
151
|
- `references/threat-landscape.md` — who is attacking this class of software in 2026, how automation changed the economics, named incidents with defensive fingerprints. Read once per full review.
|
|
150
|
-
- `references/audit-protocol.md` — the full-review protocol: recon
|
|
151
|
-
- `references/platform-playbooks.md` — per-platform controls and grep targets: web/API, mobile, desktop, CLI/dev tooling, embedded, smart contracts, ML pipelines, games. Read the sections the profile triggered.
|
|
152
|
+
- `references/audit-protocol.md` — the full-review protocol, run single-threaded: recon lenses, audit catalog, false-positive filter, hard exclusions, report template. Read for any full review.
|
|
153
|
+
- `references/platform-playbooks.md` — per-platform controls and grep targets: web/API (including the bypass sweeps for SSRF, open redirect, file upload, XXE, XSS sources, GraphQL), mobile, desktop, CLI/dev tooling, embedded, smart contracts, ML pipelines, games. Read the sections the profile triggered.
|
|
152
154
|
- `references/supply-chain.md` — dependencies, install-time execution, registries, CI/CD, signing and provenance, editor extensions, update channels.
|
|
153
155
|
- `references/agent-surface.md` — LLM, agent, and MCP security: prompt injection, the lethal trifecta, tool poisoning, sandbox escapes, context and memory poisoning.
|
|
154
156
|
- `references/secure-defaults.md` — the values to write the first time: crypto, password storage, tokens and sessions, secrets handling, HTTP headers, cloud and container defaults.
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# Full Review Protocol
|
|
2
2
|
|
|
3
|
-
The
|
|
3
|
+
The flow for "is this safe to ship", a hardening pass, or a requested audit. **Run it yourself, in the main thread — no subagents required.** For inline work, do not run this — apply the control and move on.
|
|
4
4
|
|
|
5
|
-
**
|
|
5
|
+
**Every phase is authorized defensive review for the code owner.** The deliverable is a remediation report. No exploit code, no payloads, no attack tooling, at any phase. Describe risk at the data-flow level: where untrusted data enters, what it reaches, why it is fixable.
|
|
6
6
|
|
|
7
7
|
**Confidence bar: report only findings at ≥0.8 confidence with a concrete data-flow path.** Missing a theoretical issue is cheaper than burying a real one in noise.
|
|
8
8
|
|
|
@@ -10,17 +10,17 @@ The multi-agent flow for "is this safe to ship", a hardening pass, or a requeste
|
|
|
10
10
|
|
|
11
11
|
## Phase 1 — Recon
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
Work the **four lenses** below yourself, in order. Batch the reads and greps — they are independent. **No vulnerabilities are flagged in this phase** — recon describes, it does not judge.
|
|
14
14
|
|
|
15
|
-
**
|
|
15
|
+
**Lens A — Stack & deployment.** Manifests, lockfiles, CI/CD configs, Dockerfiles, IaC, deploy scripts, store metadata. Produce: languages, frameworks, runtimes; deploy target (browser / server / CLI / desktop / mobile / embedded / serverless / container / contract / firmware / ML pipeline / library / SaaS / self-hosted); how it ships (registry, app store, binary, image, chart); where it runs, and whether it is multi-tenant.
|
|
16
16
|
|
|
17
|
-
**
|
|
17
|
+
**Lens B — Trust boundaries & sources.** Entry-point code: route handlers, argv/stdin parsing, env reads, queue consumers, WebSocket and IPC receivers, deep links and URL schemes, file and archive readers, deserializers, plugin and model loaders, MCP and tool handlers, webhooks. Produce a **sources table**: location (`file:line`), input shape, and who controls it — anonymous, authenticated user, another tenant, admin, another service, build-time, local user, physical.
|
|
18
18
|
|
|
19
|
-
**
|
|
19
|
+
**Lens C — Sinks.** Dangerous operations. Produce a **sinks table** with `file:line` and type: shell exec, SQL/NoSQL/LDAP/XPath, eval/Function/exec/pickle/yaml.load/Marshal/ObjectInputStream, file write, dynamic require/import, network egress, auth decisions, secret reads, native deserializers, contract external calls, privileged setters, child process spawn.
|
|
20
20
|
|
|
21
|
-
**
|
|
21
|
+
**Lens D — Assets & existing controls.** What must be protected, and what already protects it. Produce an **assets table** (credentials and token stores, PII stores, signing and update keys, CI secrets, model API keys, on-chain funds, session state, MCP configs, license keys) **plus a controls table** — the auth middleware, the ORM, RLS policies, CSP, sandbox, escaping layer, validation schema. The controls table is what stops Phase 3 from reporting forty things the framework already handles.
|
|
22
22
|
|
|
23
|
-
**Then synthesize
|
|
23
|
+
**Then synthesize:**
|
|
24
24
|
|
|
25
25
|
1. Assemble the four tables.
|
|
26
26
|
2. Write the **threat model** — specific to this project. Who realistically targets it, for what, and through which surface? Ground it in `threat-landscape.md`, but name concrete actors and objectives for *this* codebase: supply-chain risk to downstream users of a library; cross-tenant abuse on a SaaS; a malicious repository opened by a developer tool; a hostile counterparty on a contract; a physical attacker with the device.
|
|
@@ -45,29 +45,22 @@ From recon, choose which classes apply. **Skip audits with no entry surface.** A
|
|
|
45
45
|
| **Taint dataflow** | sources and sinks tables are both non-empty | trace each source to every reachable sink; flag reachable paths with no effective sanitization between |
|
|
46
46
|
| **Platform-specific** | recon surfaced one | from `platform-playbooks.md`: mobile IPC/deep links/WebView bridges; desktop IPC, loopback servers, updater integrity, packaging fuses; CLI shell-out and repo-config trust; firmware boot and debug interfaces; contract access control and oracles; ML deserialization and endpoint exposure |
|
|
47
47
|
|
|
48
|
-
## Phase 3 —
|
|
48
|
+
## Phase 3 — Audits
|
|
49
49
|
|
|
50
|
-
|
|
50
|
+
Run each selected audit yourself, one class at a time, in the priority order from the skill's rank table. Do not pad the list, and do not drop a selected audit. Load only the reference sections (`platform-playbooks.md`, `supply-chain.md`, `agent-surface.md`, `secure-defaults.md`) the selection triggered.
|
|
51
51
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
- the specific class scope,
|
|
55
|
-
- the relevant recon rows (sources, sinks, assets, **controls**, threat-model lines — condensed),
|
|
56
|
-
- the applicable reference lines from `platform-playbooks.md`, `supply-chain.md`, `agent-surface.md`, or `secure-defaults.md`,
|
|
57
|
-
- the confidence bar and the exclusions list below.
|
|
58
|
-
|
|
59
|
-
Each auditor must:
|
|
52
|
+
For each audit, work from the recon tables — sources, sinks, assets, **controls** — not from fresh greps, and:
|
|
60
53
|
|
|
61
54
|
1. **Trace data flow** source → sink. Not pattern matching. A grep hit with no path is not a finding.
|
|
62
55
|
2. Apply the **untrusted-input test**: is this input actually reachable by an untrusted party, or is it a constant, a build-time value, or operator-controlled configuration?
|
|
63
56
|
3. Check the **controls table** before flagging: does the ORM parameterize, does the template engine escape, does middleware already enforce this, does the type system make it unreachable?
|
|
64
57
|
4. Describe a concrete **risk scenario** at data-flow level — what kind of input arrives, how the system processes it, what the attacker ends up holding. No payloads. If the steps cannot be described, it is not a finding.
|
|
65
|
-
5. Assign **confidence 0.0–1.0** and drop anything below 0.8 before
|
|
66
|
-
6.
|
|
58
|
+
5. Assign **confidence 0.0–1.0** and drop anything below 0.8 before it enters the candidate list.
|
|
59
|
+
6. Record location, source→sink, scenario, impact, CWE, and a concrete code-level fix.
|
|
67
60
|
|
|
68
61
|
## Phase 4 — False-positive filter
|
|
69
62
|
|
|
70
|
-
|
|
63
|
+
Switch sides. For each candidate finding, start from "this is a false positive" and try to kill it: re-read the actual code path (not your notes), hunt for the control you missed — middleware, ORM parameterization, framework escaping, a type that makes the path unreachable — and check whether the input is genuinely attacker-reachable rather than a constant or operator config. Drop what dies, downgrade what survives weakened, and keep the count of dropped candidates for the report. Only findings that survive your own attempt to disprove them get reported.
|
|
71
64
|
|
|
72
65
|
**Hard exclusions — do not report these, even when technically real:**
|
|
73
66
|
|
|
@@ -16,8 +16,11 @@ The best-understood surface; the failures are still the same three.
|
|
|
16
16
|
| **Parameterized queries** | No string concatenation or f-strings into SQL/NoSQL/LDAP/XPath; ORM `raw`/`literal`/`$where` calls audited individually | The ORM covers 95% and the last 5% is a report filter or a dynamic sort column |
|
|
17
17
|
| **Output encoding** | Framework escaping left on; explicit unsafe sinks (`dangerouslySetInnerHTML`, `v-html`, `bypassSecurityTrust*`, `innerHTML`, raw template filters) each justified | XSS is still CWE-25 rank 1. Modern frameworks make the safe path default and the unsafe path a one-liner |
|
|
18
18
|
| **Server-side validation** | A schema at every entry point, allowlist-shaped, rejecting unknown fields; never trust client validation | Mass assignment: the model accepts `is_admin` because the schema was permissive |
|
|
19
|
-
| **CSRF** | State-changing routes require a token or `SameSite=Lax/Strict` cookies plus origin checks; API-token auth is exempt, cookie auth is not | Cookie-authenticated JSON endpoints assumed safe because "it's an API" |
|
|
20
|
-
| **SSRF** | Any URL from input: allowlist hosts, resolve then validate the IP, block private and link-local ranges, disable redirects or re-validate each hop | Metadata endpoints on cloud hosts turn SSRF into credential theft. Folded into A01 in the 2025 Top 10 |
|
|
19
|
+
| **CSRF** | State-changing routes require a token or `SameSite=Lax/Strict` cookies plus origin checks; API-token auth is exempt, cookie auth is not. Pre-auth flows need it too — login, signup, password reset (login CSRF is real). Validation must reject a **missing** token, not just a wrong one | Cookie-authenticated JSON endpoints assumed safe because "it's an API"; token checks that only run when a token is present |
|
|
20
|
+
| **SSRF** | Any URL from input: allowlist hosts, resolve then validate the IP, block private and link-local ranges, disable redirects or re-validate each hop — full sweep below | Metadata endpoints on cloud hosts turn SSRF into credential theft. Folded into A01 in the 2025 Top 10 |
|
|
21
|
+
| **Open redirect** | Any redirect target from input: prefer relative paths starting `/` (reject `//` and `/\`), or map named keys to URLs server-side; if full URLs are required, parse, canonicalize to Punycode, then match the hostname against an allowlist | Raw-string checks fall to `legit.com@evil.com` (userinfo trick), `legit.com.evil.com` (attacker subdomain), protocol-relative `//evil.com`, `javascript:`/`data:` schemes, backslash and double-encoded variants, and IDN homographs. Validate the **parsed hostname**, never the string |
|
|
22
|
+
| **File upload** | Three independent checks: extension allowlist **and** magic-byte sniff **and** a parse as the claimed type. Random generated names, original discarded; stored outside the web root; served from a separate origin with `Content-Disposition: attachment` and `nosniff`; size caps server-side | Any single check falls to double extensions (`x.php.jpg`), null bytes in names, spoofed `Content-Type`, prepended magic bytes, or polyglot files. SVG is a scriptable XML document — sanitize or refuse it. Archives get zip-slip path checks per entry |
|
|
23
|
+
| **XXE** | Every XML parse of untrusted input has DTDs, external entities, and XInclude disabled at the parser. XML hides in DOCX/XLSX/PPTX (ZIP of XML), SVG, SAML, RSS, SOAP — and in JSON APIs converted to XML server-side | Several stacks still default entity resolution on: Java needs `disallow-doctype-decl`; Python should parse with `defusedxml`; .NET needs `DtdProcessing.Prohibit` and a null resolver |
|
|
21
24
|
| **Rate limits on credential paths** | Login, reset, MFA, token exchange, invite acceptance | These are the endpoints where volume converts directly to account takeover |
|
|
22
25
|
| **Errors** | Generic message to the client, detail to the log; no stack traces, SQL text, or env in responses | A10:2025 is new and is exactly this: fail-open and mishandled exceptional conditions |
|
|
23
26
|
|
|
@@ -32,6 +35,18 @@ The best-understood surface; the failures are still the same three.
|
|
|
32
35
|
|
|
33
36
|
**Verification that actually proves it:** call the endpoint as user B for user A's row and require a 403/404. One such test per protected resource is worth more than a header audit.
|
|
34
37
|
|
|
38
|
+
**SSRF, hardened** — the naive "block 127.0.0.1 and 10.x" string check is the one that gets bypassed:
|
|
39
|
+
|
|
40
|
+
1. Validate the **resolved IP** with a canonical IP parser, not the hostname string. Internal ranges are reachable as decimal (`2130706433`), octal (`0177.0.0.1`), hex, shortened (`127.1`), IPv6 loopback (`[::1]`, `[::]`), and IPv4-mapped IPv6 (`[::ffff:127.0.0.1]`) forms — canonicalization collapses all of them; a denylist of spellings never will.
|
|
41
|
+
2. **Pin the resolved IP for the actual connection** (connect to the IP, send the hostname in the Host/SNI). Resolve-validate-then-fetch re-resolves, and that second resolution is the DNS-rebinding hole. A CNAME to an internal hostname is the same trick.
|
|
42
|
+
3. Block link-local `169.254.0.0/16` and metadata hostnames (`169.254.169.254`, `metadata.google.internal`) explicitly, and enforce IMDSv2 anyway — SSRF plus legacy metadata service equals cloud credentials.
|
|
43
|
+
4. Disable redirect following, or re-run the **full** validation on every hop; a compliant external URL that 302s to an internal address is the standard bypass.
|
|
44
|
+
5. Scheme allowlist `http`/`https` only; bounded timeout and response size.
|
|
45
|
+
|
|
46
|
+
**XSS enters from more than form fields.** When auditing sinks, sweep the indirect sources too: URL query **and fragment**, request headers the app displays (Referer, User-Agent), third-party API data rendered to users, WebSocket and `postMessage` payloads (validate `event.origin`), localStorage/sessionStorage values rendered later, uploaded file names, error messages that reflect input, markdown and rich-text renderers with HTML enabled, admin log viewers, and HTML-to-PDF or email-template generators — an injection there executes in the generator's context, often server-side. Sanitize rich text with an allowlist library (DOMPurify), never a homemade regex. Trusted Types plus nonce CSP (see `secure-defaults.md`) backstop the misses.
|
|
47
|
+
|
|
48
|
+
**GraphQL, if present:** introspection off in production; server-enforced depth limit (~10) and query cost/complexity limit; cap operations per request — batching turns one HTTP request into a thousand login attempts and walks past per-request rate limits; authorization still happens per-object in resolvers, because the graph is one endpoint and route-level auth checks nothing.
|
|
49
|
+
|
|
35
50
|
---
|
|
36
51
|
|
|
37
52
|
## Mobile (iOS / Android)
|
|
@@ -158,4 +173,4 @@ Apply only to languages actually present. A grep hit here is a lead, not a findi
|
|
|
158
173
|
| **PHP** | `unserialize`, `eval`, `assert(string)`, `include`/`require` with a dynamic path, `preg_replace` with the `/e` modifier |
|
|
159
174
|
| **C / C++** | `strcpy`/`sprintf`/`gets`, integer overflow in size arithmetic, `printf(userInput)`, use-after-free, double-free. New parsing code here needs a written justification, sanitizers, and fuzzing |
|
|
160
175
|
| **Shell** | Unquoted variable expansion, `eval`, word splitting on filenames, `curl | sh`, missing `set -euo pipefail` |
|
|
161
|
-
| **SQL** | String-built queries, dynamic identifiers
|
|
176
|
+
| **SQL** | String-built queries, dynamic identifiers and `ORDER BY` columns (cannot be parameterized — allowlist them), `LIKE` patterns built from input without escaping `%`/`_`, `IN` lists interpolated instead of expanded as placeholders, `SECURITY DEFINER` functions without a locked `search_path` |
|
|
@@ -32,6 +32,7 @@ Implementation:
|
|
|
32
32
|
- Session tokens from a CSPRNG, ≥128 bits. Rotate the session identifier on login and on privilege change. Server-side revocation must exist — a stateless token you cannot revoke is an outage during an incident.
|
|
33
33
|
- Constant-time comparison for tokens, signatures, and MFA codes — but **validate the shape before you compare**. A stored credential whose hex/base64 decodes to the wrong length, or whose scheme/salt/hash does not parse, must be rejected as malformed and fail closed; never fall through to the comparison. `timingSafeEqual` on two empty buffers returns true, so an unparsed record can verify any password.
|
|
34
34
|
- Rate-limit and lock out on login, reset, MFA, and token exchange. Generic failure messages: never reveal whether the account exists.
|
|
35
|
+
- **JWTs, when used:** pin the verification algorithm from your own config — never read `alg` from the token header, reject `none`. HMAC secrets ≥256 bits from a CSPRNG, never a passphrase. Always set and validate `exp` (minutes, not days) and include `jti` so revocation is possible. In a browser, the token lives in an `HttpOnly`/`Secure`/`SameSite` cookie — localStorage is readable by any XSS. Rotate refresh tokens on use; a reused refresh token means theft — revoke the whole family.
|
|
35
36
|
|
|
36
37
|
## Authorization
|
|
37
38
|
|
|
@@ -40,6 +41,9 @@ Implementation:
|
|
|
40
41
|
- Authorize on the **object**, not just the route: `canRead(user, invoice)`, never "the route is under `/admin` so it is fine".
|
|
41
42
|
- Never accept a client-supplied user, tenant, role, or price. Derive them from the session server-side.
|
|
42
43
|
- Re-check on every request; a permission granted at login can be revoked mid-session.
|
|
44
|
+
- **Removal is revocation.** Leaving an org, a role downgrade, or account deletion must invalidate that user's sessions, refresh tokens, and API keys immediately — not at next login.
|
|
45
|
+
- Return the same 404 for "does not exist" and "not yours" — a 403 confirms the resource exists and invites enumeration. Non-guessable IDs (UUIDv4) are defense-in-depth on top; authorization is still the control.
|
|
46
|
+
- Check the **parent chain**: accessing a comment means verifying ownership of the post it belongs to, not just that the comment ID resolves.
|
|
43
47
|
- Test it: the cross-user access test (user B requests user A's resource, expect 403/404) is the highest-value security test a small team can write.
|
|
44
48
|
|
|
45
49
|
## Cryptography
|
package/dist/app-sidecar.js
CHANGED
|
@@ -1664,7 +1664,16 @@ async function createSession(deps, opts) {
|
|
|
1664
1664
|
session.eventBus.on("agent_done", (d) => broadcast("agent_done", d));
|
|
1665
1665
|
// Non-clean stop (max_tokens/refusal/provider error) — info-style frame so
|
|
1666
1666
|
// the webview can warn instead of presenting truncated output as complete.
|
|
1667
|
-
|
|
1667
|
+
// empty_response is a hard failure (no output at all): route it through
|
|
1668
|
+
// broadcastError so the app renders an error row — the webview does not
|
|
1669
|
+
// render bare "truncated" frames.
|
|
1670
|
+
session.eventBus.on("truncated", (d) => {
|
|
1671
|
+
if (d.reason === "empty_response") {
|
|
1672
|
+
broadcastError("error", "empty response", new Error("The model returned an empty response after retries — try sending again."));
|
|
1673
|
+
return;
|
|
1674
|
+
}
|
|
1675
|
+
broadcast("truncated", d);
|
|
1676
|
+
});
|
|
1668
1677
|
session.eventBus.on("error", (d) => {
|
|
1669
1678
|
broadcastError("error", "agent error", d.error);
|
|
1670
1679
|
});
|