@kenkaiiii/ggcoder 5.18.0 → 5.19.1
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/dist/app-sidecar.js +64 -9
- package/dist/app-sidecar.js.map +1 -1
- package/dist/cli/auth.d.ts.map +1 -1
- package/dist/cli/auth.js +5 -2
- package/dist/cli/auth.js.map +1 -1
- package/dist/cli/shared.d.ts.map +1 -1
- package/dist/cli/shared.js +2 -0
- package/dist/cli/shared.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +6 -1
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +1 -0
- package/dist/config.js.map +1 -1
- package/dist/config.test.js +7 -0
- package/dist/config.test.js.map +1 -1
- package/dist/core/agent-session-compaction.test.js +517 -9
- package/dist/core/agent-session-compaction.test.js.map +1 -1
- package/dist/core/agent-session-memory-tail.test.js +1 -1
- package/dist/core/agent-session-memory-tail.test.js.map +1 -1
- package/dist/core/agent-session-queue.test.js +1 -1
- package/dist/core/agent-session-queue.test.js.map +1 -1
- package/dist/core/agent-session-review-coverage.test.js +26 -0
- package/dist/core/agent-session-review-coverage.test.js.map +1 -1
- package/dist/core/agent-session-tool-result-policy.test.js +14 -1
- package/dist/core/agent-session-tool-result-policy.test.js.map +1 -1
- package/dist/core/agent-session.d.ts +32 -0
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +229 -42
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/auth-providers.d.ts.map +1 -1
- package/dist/core/auth-providers.js +14 -7
- package/dist/core/auth-providers.js.map +1 -1
- package/dist/core/compaction/active-context.d.ts +17 -0
- package/dist/core/compaction/active-context.d.ts.map +1 -0
- package/dist/core/compaction/active-context.js +20 -0
- package/dist/core/compaction/active-context.js.map +1 -0
- package/dist/core/compaction/active-context.test.d.ts +2 -0
- package/dist/core/compaction/active-context.test.d.ts.map +1 -0
- package/dist/core/compaction/active-context.test.js +36 -0
- package/dist/core/compaction/active-context.test.js.map +1 -0
- package/dist/core/compaction/compactor.d.ts +18 -17
- package/dist/core/compaction/compactor.d.ts.map +1 -1
- package/dist/core/compaction/compactor.js +54 -37
- package/dist/core/compaction/compactor.js.map +1 -1
- package/dist/core/compaction/compactor.test.js +101 -64
- package/dist/core/compaction/compactor.test.js.map +1 -1
- package/dist/core/compaction/tool-result-pruner.d.ts +37 -0
- package/dist/core/compaction/tool-result-pruner.d.ts.map +1 -0
- package/dist/core/compaction/tool-result-pruner.js +103 -0
- package/dist/core/compaction/tool-result-pruner.js.map +1 -0
- package/dist/core/compaction/tool-result-pruner.test.d.ts +2 -0
- package/dist/core/compaction/tool-result-pruner.test.d.ts.map +1 -0
- package/dist/core/compaction/tool-result-pruner.test.js +148 -0
- package/dist/core/compaction/tool-result-pruner.test.js.map +1 -0
- package/dist/core/ideal-review.d.ts +6 -0
- package/dist/core/ideal-review.d.ts.map +1 -1
- package/dist/core/ideal-review.js +14 -0
- package/dist/core/ideal-review.js.map +1 -1
- package/dist/core/ideal-review.test.js +10 -1
- package/dist/core/ideal-review.test.js.map +1 -1
- package/dist/core/resolve-start.test.js +1 -0
- package/dist/core/resolve-start.test.js.map +1 -1
- package/dist/core/settings-manager.d.ts +1 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +1 -0
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/subagent-manager.test.js +7 -3
- package/dist/core/subagent-manager.test.js.map +1 -1
- package/dist/ui/App.d.ts.map +1 -1
- package/dist/ui/App.js +3 -16
- package/dist/ui/App.js.map +1 -1
- package/dist/ui/components/ModelSelector.d.ts.map +1 -1
- package/dist/ui/components/ModelSelector.js +1 -0
- package/dist/ui/components/ModelSelector.js.map +1 -1
- package/dist/ui/hooks/useAgentLoop.d.ts +2 -4
- package/dist/ui/hooks/useAgentLoop.d.ts.map +1 -1
- package/dist/ui/hooks/useAgentLoop.js +6 -2
- package/dist/ui/hooks/useAgentLoop.js.map +1 -1
- package/dist/ui/hooks/useAgentLoop.test.js +31 -0
- package/dist/ui/hooks/useAgentLoop.test.js.map +1 -1
- package/dist/ui/hooks/useContextCompaction.d.ts +5 -8
- package/dist/ui/hooks/useContextCompaction.d.ts.map +1 -1
- package/dist/ui/hooks/useContextCompaction.js +72 -14
- package/dist/ui/hooks/useContextCompaction.js.map +1 -1
- package/dist/ui/hooks/useContextCompaction.test.d.ts +2 -0
- package/dist/ui/hooks/useContextCompaction.test.d.ts.map +1 -0
- package/dist/ui/hooks/useContextCompaction.test.js +120 -0
- package/dist/ui/hooks/useContextCompaction.test.js.map +1 -0
- package/dist/ui/login.d.ts.map +1 -1
- package/dist/ui/login.js +2 -1
- package/dist/ui/login.js.map +1 -1
- package/package.json +4 -4
package/dist/app-sidecar.js
CHANGED
|
@@ -64,16 +64,20 @@ import { awardPrompt, awardCommits } from "./core/progress/engine.js";
|
|
|
64
64
|
import { detectNewCommits, repoKey } from "./core/progress/git-xp.js";
|
|
65
65
|
import { rebuildFromSessions } from "./core/progress/rebuild.js";
|
|
66
66
|
const ALL_PROVIDERS = [
|
|
67
|
+
// US
|
|
67
68
|
"anthropic",
|
|
68
|
-
"xiaomi",
|
|
69
69
|
"openai",
|
|
70
70
|
"gemini",
|
|
71
|
-
"
|
|
71
|
+
"xai",
|
|
72
|
+
// China
|
|
72
73
|
"moonshot",
|
|
74
|
+
"glm",
|
|
73
75
|
"minimax",
|
|
76
|
+
"xiaomi",
|
|
74
77
|
"deepseek",
|
|
75
|
-
|
|
78
|
+
// Japan, then provider-agnostic gateway last
|
|
76
79
|
"sakana",
|
|
80
|
+
"openrouter",
|
|
77
81
|
];
|
|
78
82
|
function appSettingsFile() {
|
|
79
83
|
return path.join(os.homedir(), ".gg", "gg-app.json");
|
|
@@ -536,6 +540,11 @@ async function main() {
|
|
|
536
540
|
});
|
|
537
541
|
const usageCache = new Map();
|
|
538
542
|
const usageRequests = new Map();
|
|
543
|
+
// 429 backoff: when the provider rate-limits the usage endpoint, hold the
|
|
544
|
+
// error result until this timestamp instead of re-polling (and re-logging a
|
|
545
|
+
// WARN) every 60s — the old cadence hammered a limited endpoint for hours.
|
|
546
|
+
const usageRateLimitedUntil = new Map();
|
|
547
|
+
const USAGE_RATE_LIMIT_BACKOFF_MS = 5 * 60_000;
|
|
539
548
|
async function fetchUsageProvider(provider) {
|
|
540
549
|
const displayName = provider === "anthropic" ? "Anthropic" : "Codex";
|
|
541
550
|
if (!(await auth.hasProviderAuth(provider))) {
|
|
@@ -544,14 +553,24 @@ async function main() {
|
|
|
544
553
|
try {
|
|
545
554
|
let credentials = await auth.resolveCredentials(provider);
|
|
546
555
|
try {
|
|
547
|
-
|
|
556
|
+
const snapshot = {
|
|
557
|
+
...(await fetchSubscriptionUsage(provider, credentials)),
|
|
558
|
+
connected: true,
|
|
559
|
+
};
|
|
560
|
+
usageRateLimitedUntil.delete(provider);
|
|
561
|
+
return snapshot;
|
|
548
562
|
}
|
|
549
563
|
catch (error) {
|
|
550
564
|
// A provider can revoke an access token before its stored expiry. Refresh
|
|
551
565
|
// once on 401, matching inference auth recovery, then retry the usage call.
|
|
552
566
|
if (error instanceof SubscriptionUsageError && error.status === 401) {
|
|
553
567
|
credentials = await auth.resolveCredentials(provider, { forceRefresh: true });
|
|
554
|
-
|
|
568
|
+
const snapshot = {
|
|
569
|
+
...(await fetchSubscriptionUsage(provider, credentials)),
|
|
570
|
+
connected: true,
|
|
571
|
+
};
|
|
572
|
+
usageRateLimitedUntil.delete(provider);
|
|
573
|
+
return snapshot;
|
|
555
574
|
}
|
|
556
575
|
throw error;
|
|
557
576
|
}
|
|
@@ -559,6 +578,9 @@ async function main() {
|
|
|
559
578
|
catch (error) {
|
|
560
579
|
const message = error instanceof Error ? error.message : String(error);
|
|
561
580
|
log("WARN", "app-sidecar", "subscription usage fetch failed", { provider, message });
|
|
581
|
+
if (error instanceof SubscriptionUsageError && error.status === 429) {
|
|
582
|
+
usageRateLimitedUntil.set(provider, Date.now() + USAGE_RATE_LIMIT_BACKOFF_MS);
|
|
583
|
+
}
|
|
562
584
|
const connected = await auth.hasProviderAuth(provider);
|
|
563
585
|
return {
|
|
564
586
|
provider,
|
|
@@ -587,9 +609,12 @@ async function main() {
|
|
|
587
609
|
const missingReset = result.connected &&
|
|
588
610
|
result.windows.length > 0 &&
|
|
589
611
|
result.windows.some((window) => window.resetsAt === undefined);
|
|
612
|
+
const rateLimitedUntil = usageRateLimitedUntil.get(provider) ?? 0;
|
|
590
613
|
usageCache.set(provider, {
|
|
591
614
|
result,
|
|
592
|
-
expiresAt: Date.now()
|
|
615
|
+
expiresAt: rateLimitedUntil > Date.now()
|
|
616
|
+
? rateLimitedUntil
|
|
617
|
+
: Date.now() + (missingReset ? 10_000 : 60_000),
|
|
593
618
|
});
|
|
594
619
|
return result;
|
|
595
620
|
}
|
|
@@ -1012,6 +1037,11 @@ async function createSession(deps, opts) {
|
|
|
1012
1037
|
signal: abort.signal,
|
|
1013
1038
|
// Keep MCP startup off the readiness path in both modes.
|
|
1014
1039
|
backgroundMcpConnect: true,
|
|
1040
|
+
// Keep restore-time auto-compaction off the readiness path too: its summary
|
|
1041
|
+
// LLM call (30s timeout) used to freeze waitForReady — and with it the whole
|
|
1042
|
+
// window (project picker, session list) — whenever a resumed session was
|
|
1043
|
+
// over the context threshold. First prompt compacts instead, with UI events.
|
|
1044
|
+
deferLoadCompaction: true,
|
|
1015
1045
|
};
|
|
1016
1046
|
let session;
|
|
1017
1047
|
if (mode === "chat") {
|
|
@@ -1238,8 +1268,10 @@ async function createSession(deps, opts) {
|
|
|
1238
1268
|
// Autopilot (auto-review) toggle for THIS window's project. Loaded from
|
|
1239
1269
|
// gg-app.json on boot; flipped via POST /autopilot. When on, POST /prompt runs
|
|
1240
1270
|
// runAutopilotCycle after the user's turn settles — Ken auto-reviews the work
|
|
1241
|
-
// and drives the review→prompt→review loop.
|
|
1271
|
+
// and drives the review→prompt→review loop. Ken is the sole verification
|
|
1272
|
+
// owner in this mode, so suppress the build session's redundant Ideal hook.
|
|
1242
1273
|
let autopilot = mode === "code" && (await loadAutopilot(cwd));
|
|
1274
|
+
session.setIdealReviewSuppressed(autopilot);
|
|
1243
1275
|
// True while an autopilot review is in flight (used to defer kenAuto model
|
|
1244
1276
|
// switches, like kenRunning does for chat Ken, and to drive the spinner).
|
|
1245
1277
|
let autopilotReviewing = false;
|
|
@@ -1436,6 +1468,9 @@ async function createSession(deps, opts) {
|
|
|
1436
1468
|
// (often >5 min) regardless of the user's global speedProfile pick.
|
|
1437
1469
|
forceLongCacheRetention: true,
|
|
1438
1470
|
});
|
|
1471
|
+
// Ken is already the independent autopilot reviewer; recursively running
|
|
1472
|
+
// his own Ideal self-review adds latency and can corrupt the verdict shape.
|
|
1473
|
+
ken.setIdealReviewSuppressed(true);
|
|
1439
1474
|
await ken.initialize();
|
|
1440
1475
|
// Deliberately no bus bridge: the review is silent. Errors surface via the
|
|
1441
1476
|
// runAutopilotReview try/catch as autopilot_error frames.
|
|
@@ -1658,6 +1693,7 @@ async function createSession(deps, opts) {
|
|
|
1658
1693
|
const generation = runLifecycle.begin(abortOwnedWork).generation;
|
|
1659
1694
|
pendingCancelDrain = null;
|
|
1660
1695
|
autopilotActive = true;
|
|
1696
|
+
session.setIdealReviewSuppressed(true);
|
|
1661
1697
|
// Generation captured by the last plan review; acceptPlan re-checks it so
|
|
1662
1698
|
// a user Accept/Reject landing mid-review always wins.
|
|
1663
1699
|
let planGenAtReview = -1;
|
|
@@ -1771,6 +1807,7 @@ async function createSession(deps, opts) {
|
|
|
1771
1807
|
}
|
|
1772
1808
|
finally {
|
|
1773
1809
|
autopilotActive = false;
|
|
1810
|
+
session.setIdealReviewSuppressed(autopilot);
|
|
1774
1811
|
finishOwnedGeneration(generation, true);
|
|
1775
1812
|
queueMicrotask(() => void runStrandedQueue());
|
|
1776
1813
|
}
|
|
@@ -2237,6 +2274,20 @@ async function createSession(deps, opts) {
|
|
|
2237
2274
|
void (async () => {
|
|
2238
2275
|
const commandCandidates = [...PROMPT_COMMANDS, ...(await loadCustomCommands(cwd))];
|
|
2239
2276
|
const messages = session.getMessages();
|
|
2277
|
+
// An Ideal hook is injected immediately after the assistant's candidate
|
|
2278
|
+
// no-tool response. That response is review scratch, not a user-visible
|
|
2279
|
+
// final answer. Live SSE drops it when the hook event arrives; mark the
|
|
2280
|
+
// same assistant message here so resumed history stays identical.
|
|
2281
|
+
const hiddenIdealDrafts = new Set();
|
|
2282
|
+
for (let i = 0; i < messages.length - 1; i++) {
|
|
2283
|
+
const draft = messages[i];
|
|
2284
|
+
const hookPrompt = messages[i + 1];
|
|
2285
|
+
if (draft?.role !== "assistant" || hookPrompt?.role !== "user")
|
|
2286
|
+
continue;
|
|
2287
|
+
const restored = restoreUserRow(hookPrompt.content);
|
|
2288
|
+
if (detectHookKind(restored.text) === "ideal")
|
|
2289
|
+
hiddenIdealDrafts.add(draft);
|
|
2290
|
+
}
|
|
2240
2291
|
// Pre-index tool results by toolCallId so we can pair tool calls with
|
|
2241
2292
|
// their results (for sub-agent status + image extraction).
|
|
2242
2293
|
const toolResultMap = new Map();
|
|
@@ -2454,10 +2505,11 @@ async function createSession(deps, opts) {
|
|
|
2454
2505
|
}
|
|
2455
2506
|
}
|
|
2456
2507
|
}
|
|
2457
|
-
else {
|
|
2508
|
+
else if (!hiddenIdealDrafts.has(msg)) {
|
|
2458
2509
|
// Assistant: one wire row per persisted text block — live streaming
|
|
2459
2510
|
// splits bubbles at server_tool_call boundaries, and the persisted
|
|
2460
|
-
// content keeps those blocks separate.
|
|
2511
|
+
// content keeps those blocks separate. Ideal-review candidate drafts
|
|
2512
|
+
// are intentionally omitted to match the live pre-final hook flow.
|
|
2461
2513
|
for (const blockText of restoreAssistantTexts(msg.content)) {
|
|
2462
2514
|
history.push({
|
|
2463
2515
|
role: "assistant",
|
|
@@ -2736,6 +2788,9 @@ async function createSession(deps, opts) {
|
|
|
2736
2788
|
return;
|
|
2737
2789
|
}
|
|
2738
2790
|
autopilot = enabled;
|
|
2791
|
+
// A toggle-off during an active cycle takes effect after Ken finishes;
|
|
2792
|
+
// until then, injected build runs must not re-enable Ideal self-review.
|
|
2793
|
+
session.setIdealReviewSuppressed(enabled || autopilotActive);
|
|
2739
2794
|
await saveAutopilot(cwd, enabled);
|
|
2740
2795
|
log("INFO", "app-sidecar", "autopilot toggled", { enabled: String(enabled) });
|
|
2741
2796
|
broadcast("autopilot", { autopilot: enabled });
|