@kenkaiiii/ggcoder 5.26.0 → 5.26.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/dist/app-sidecar.js +71 -52
- package/dist/app-sidecar.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +0 -3
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +0 -2
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +0 -3
- package/dist/config.js.map +1 -1
- package/dist/config.test.js +0 -12
- package/dist/config.test.js.map +1 -1
- package/dist/core/agent-session-queue.test.js +65 -0
- package/dist/core/agent-session-queue.test.js.map +1 -1
- package/dist/core/agent-session.d.ts +11 -13
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +34 -64
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/event-bus.d.ts +7 -0
- package/dist/core/event-bus.d.ts.map +1 -1
- package/dist/core/event-bus.js.map +1 -1
- package/dist/core/run-claim.d.ts +37 -0
- package/dist/core/run-claim.d.ts.map +1 -0
- package/dist/core/run-claim.js +46 -0
- package/dist/core/run-claim.js.map +1 -0
- package/dist/core/run-claim.test.d.ts +2 -0
- package/dist/core/run-claim.test.d.ts.map +1 -0
- package/dist/core/run-claim.test.js +107 -0
- package/dist/core/run-claim.test.js.map +1 -0
- package/dist/core/settings-manager.d.ts +0 -1
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +0 -7
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/ui/App.d.ts +0 -2
- package/dist/ui/App.d.ts.map +1 -1
- package/dist/ui/App.js +1 -35
- package/dist/ui/App.js.map +1 -1
- package/dist/ui/render.d.ts +0 -2
- package/dist/ui/render.d.ts.map +1 -1
- package/dist/ui/render.js +0 -1
- package/dist/ui/render.js.map +1 -1
- package/package.json +4 -4
- package/dist/core/memory/compaction-notes.d.ts +0 -31
- package/dist/core/memory/compaction-notes.d.ts.map +0 -1
- package/dist/core/memory/compaction-notes.js +0 -162
- package/dist/core/memory/compaction-notes.js.map +0 -1
- package/dist/core/memory/compaction-notes.test.d.ts +0 -2
- package/dist/core/memory/compaction-notes.test.d.ts.map +0 -1
- package/dist/core/memory/compaction-notes.test.js +0 -110
- package/dist/core/memory/compaction-notes.test.js.map +0 -1
- package/dist/core/memory/journal.d.ts +0 -55
- package/dist/core/memory/journal.d.ts.map +0 -1
- package/dist/core/memory/journal.js +0 -212
- package/dist/core/memory/journal.js.map +0 -1
- package/dist/core/memory/journal.test.d.ts +0 -2
- package/dist/core/memory/journal.test.d.ts.map +0 -1
- package/dist/core/memory/journal.test.js +0 -184
- package/dist/core/memory/journal.test.js.map +0 -1
package/dist/app-sidecar.js
CHANGED
|
@@ -24,6 +24,7 @@ import { runSubagentWorkerMode } from "./modes/subagent-worker-mode.js";
|
|
|
24
24
|
import { setStreamDiagnostic } from "@kenkaiiii/gg-agent";
|
|
25
25
|
import { AgentSession } from "./core/agent-session.js";
|
|
26
26
|
import { RunLifecycle } from "./core/run-lifecycle.js";
|
|
27
|
+
import { RunClaim } from "./core/run-claim.js";
|
|
27
28
|
import { CHAT_AGENT_IDS, chatAgentSessionsDir, createChatAgent, parseChatAgentId, switchChatAgent, } from "./chat-agents/index.js";
|
|
28
29
|
import { buildJiwaTools, JiwaStore } from "./chat-agents/jiwa.js";
|
|
29
30
|
import { buildMemoryTools, MemoryStore } from "./chat-agents/memory.js";
|
|
@@ -1532,6 +1533,10 @@ async function createSession(deps, opts) {
|
|
|
1532
1533
|
recordApprovedPlanMarkers(d.text);
|
|
1533
1534
|
});
|
|
1534
1535
|
session.eventBus.on("thinking_delta", (d) => broadcast("thinking_delta", d));
|
|
1536
|
+
// The agent consumed queued steering at a turn boundary. Re-broadcast as the
|
|
1537
|
+
// usual `queued` depth update so the webview drops the pending affordance the
|
|
1538
|
+
// moment the message lands in the loop, not at run_end.
|
|
1539
|
+
session.eventBus.on("queue_drained", (d) => broadcast("queued", { count: d.count, messages: session.listQueuedMessages() }));
|
|
1535
1540
|
session.eventBus.on("tool_call_start", (d) => {
|
|
1536
1541
|
toolCallNames.set(d.toolCallId, d.name);
|
|
1537
1542
|
broadcast("tool_call_start", d);
|
|
@@ -1577,6 +1582,10 @@ async function createSession(deps, opts) {
|
|
|
1577
1582
|
session.eventBus.on("compaction_start", (d) => broadcast("compaction_start", d));
|
|
1578
1583
|
session.eventBus.on("compaction_end", (d) => broadcast("compaction_end", d));
|
|
1579
1584
|
let running = false;
|
|
1585
|
+
// Closes the window between `/prompt` deciding to start a run and `runAgent`
|
|
1586
|
+
// flipping `running` — that stretch awaits, so Node yields inside it. See
|
|
1587
|
+
// RunClaim.
|
|
1588
|
+
const runClaim = new RunClaim();
|
|
1580
1589
|
const runLifecycle = new RunLifecycle((runState) => {
|
|
1581
1590
|
running = runState !== "idle";
|
|
1582
1591
|
if (runState === "cancelling")
|
|
@@ -1913,7 +1922,10 @@ async function createSession(deps, opts) {
|
|
|
1913
1922
|
// runAutopilotCycle), NOT from this shared finally — that keeps injected
|
|
1914
1923
|
// runs from recursively entering the same review loop.
|
|
1915
1924
|
broadcast("tasks_list", { tasks: pruneDoneTasksSync(cwd) });
|
|
1916
|
-
broadcast("queued", {
|
|
1925
|
+
broadcast("queued", {
|
|
1926
|
+
count: session.getQueuedCount(),
|
|
1927
|
+
messages: session.listQueuedMessages(),
|
|
1928
|
+
});
|
|
1917
1929
|
broadcast("extras", footerExtras());
|
|
1918
1930
|
}
|
|
1919
1931
|
}
|
|
@@ -2159,7 +2171,10 @@ async function createSession(deps, opts) {
|
|
|
2159
2171
|
const next = session.takeNextQueuedMessage();
|
|
2160
2172
|
if (!next)
|
|
2161
2173
|
return;
|
|
2162
|
-
broadcast("queued", {
|
|
2174
|
+
broadcast("queued", {
|
|
2175
|
+
count: session.getQueuedCount(),
|
|
2176
|
+
messages: session.listQueuedMessages(),
|
|
2177
|
+
});
|
|
2163
2178
|
if (!next.text.trim() && next.attachments.length === 0)
|
|
2164
2179
|
continue;
|
|
2165
2180
|
// A queued message draining as a fresh turn supersedes any pending
|
|
@@ -2402,50 +2417,6 @@ async function createSession(deps, opts) {
|
|
|
2402
2417
|
});
|
|
2403
2418
|
return;
|
|
2404
2419
|
}
|
|
2405
|
-
// Durable per-project journal (.gg/memory.md). Distinct from /memories,
|
|
2406
|
-
// which is the personal chat-memory store shared by the chat agents.
|
|
2407
|
-
if (method === "GET" && url === "/project-memory") {
|
|
2408
|
-
void (async () => {
|
|
2409
|
-
try {
|
|
2410
|
-
const sm = new SettingsManager(paths.settingsFile);
|
|
2411
|
-
await sm.load();
|
|
2412
|
-
json(res, 200, { enabled: sm.get("memoryEnabled") });
|
|
2413
|
-
}
|
|
2414
|
-
catch (error) {
|
|
2415
|
-
captureSidecarError(error, "app-sidecar.project-memory.get");
|
|
2416
|
-
json(res, 500, { error: error instanceof Error ? error.message : String(error) });
|
|
2417
|
-
}
|
|
2418
|
-
})();
|
|
2419
|
-
return;
|
|
2420
|
-
}
|
|
2421
|
-
if (method === "POST" && url === "/project-memory") {
|
|
2422
|
-
void readBody(req, res).then(async (raw) => {
|
|
2423
|
-
if (raw === null)
|
|
2424
|
-
return;
|
|
2425
|
-
let enabled;
|
|
2426
|
-
try {
|
|
2427
|
-
enabled = JSON.parse(raw).enabled === true;
|
|
2428
|
-
}
|
|
2429
|
-
catch {
|
|
2430
|
-
json(res, 400, { error: "invalid JSON body" });
|
|
2431
|
-
return;
|
|
2432
|
-
}
|
|
2433
|
-
try {
|
|
2434
|
-
const sm = new SettingsManager(paths.settingsFile);
|
|
2435
|
-
await sm.load();
|
|
2436
|
-
await sm.set("memoryEnabled", enabled);
|
|
2437
|
-
// Applies from the next session: the journal handle is built during
|
|
2438
|
-
// AgentSession.initialize(), so a live run keeps its current behaviour
|
|
2439
|
-
// rather than half-applying the change mid-task.
|
|
2440
|
-
json(res, 200, { enabled });
|
|
2441
|
-
}
|
|
2442
|
-
catch (error) {
|
|
2443
|
-
captureSidecarError(error, "app-sidecar.project-memory.set");
|
|
2444
|
-
json(res, 500, { error: error instanceof Error ? error.message : String(error) });
|
|
2445
|
-
}
|
|
2446
|
-
});
|
|
2447
|
-
return;
|
|
2448
|
-
}
|
|
2449
2420
|
if (method === "GET" && url === "/jiwa") {
|
|
2450
2421
|
void jiwaStore
|
|
2451
2422
|
.snapshot()
|
|
@@ -3009,7 +2980,12 @@ async function createSession(deps, opts) {
|
|
|
3009
2980
|
return;
|
|
3010
2981
|
}
|
|
3011
2982
|
if (method === "POST" && url === "/prompt") {
|
|
3012
|
-
|
|
2983
|
+
// Per-request: only the prompt that actually claimed the start may release
|
|
2984
|
+
// it. A bare release would let an early-returning request (bad JSON, or a
|
|
2985
|
+
// prompt that queued) clear a claim another request is still holding.
|
|
2986
|
+
let claimedStart = false;
|
|
2987
|
+
void readBody(req, res)
|
|
2988
|
+
.then(async (raw) => {
|
|
3013
2989
|
if (raw === null)
|
|
3014
2990
|
return;
|
|
3015
2991
|
let text;
|
|
@@ -3029,14 +3005,17 @@ async function createSession(deps, opts) {
|
|
|
3029
3005
|
json(res, 400, { error: "empty prompt" });
|
|
3030
3006
|
return;
|
|
3031
3007
|
}
|
|
3032
|
-
if (runLifecycle.running &&
|
|
3008
|
+
if (runLifecycle.running &&
|
|
3009
|
+
runLifecycle.isCancellationRequested(runLifecycle.generation)) {
|
|
3033
3010
|
json(res, 409, {
|
|
3034
3011
|
error: runLifecycle.state === "cancelling" ? "run_cancelling" : "cancel_failed",
|
|
3035
3012
|
runState: runLifecycle.state,
|
|
3036
3013
|
});
|
|
3037
3014
|
return;
|
|
3038
3015
|
}
|
|
3039
|
-
|
|
3016
|
+
// `runClaim` covers the gap before `runAgent` flips `running`: a
|
|
3017
|
+
// prompt arriving in that window must queue, not start a second run.
|
|
3018
|
+
if (running || runClaim.active || autopilotActive) {
|
|
3040
3019
|
// Queue prompts as mid-run steering (mirrors the CLI). Also queue while
|
|
3041
3020
|
// an autopilot cycle is active but between injected runs (build idle,
|
|
3042
3021
|
// Ken reviewing) so the message never starts a run that collides with
|
|
@@ -3045,10 +3024,13 @@ async function createSession(deps, opts) {
|
|
|
3045
3024
|
// path as a non-queued attachment prompt when it drains.
|
|
3046
3025
|
const prepared = attachments.length > 0 ? await prepareAttachments(cwd, attachments) : [];
|
|
3047
3026
|
const count = session.queueMessage(text, prepared);
|
|
3048
|
-
broadcast("queued", { count });
|
|
3027
|
+
broadcast("queued", { count, messages: session.listQueuedMessages() });
|
|
3049
3028
|
json(res, 202, { queued: true, count });
|
|
3050
3029
|
return;
|
|
3051
3030
|
}
|
|
3031
|
+
// Claim the run NOW, synchronously. Everything below this line may
|
|
3032
|
+
// yield, and `running` does not flip until runAgent begins.
|
|
3033
|
+
claimedStart = runClaim.claim();
|
|
3052
3034
|
json(res, 202, { accepted: true });
|
|
3053
3035
|
// Webview display hint for this prompt's user bubble (kenSent shimmer
|
|
3054
3036
|
// label / enhancer highlight segments). Anchored +1 so it attaches to
|
|
@@ -3074,7 +3056,8 @@ async function createSession(deps, opts) {
|
|
|
3074
3056
|
// how many assistant messages the run actually adds. Computed even when
|
|
3075
3057
|
// autopilot is currently off — the toggle can flip ON mid-run, and the
|
|
3076
3058
|
// gate reads the post-run value.
|
|
3077
|
-
const workflowCommand = attachments.length === 0 &&
|
|
3059
|
+
const workflowCommand = attachments.length === 0 &&
|
|
3060
|
+
isWorkflowCommandText(text, await loadWorkflowCommandSpecs());
|
|
3078
3061
|
const assistantsBefore = countAssistantMessages(session.getMessages());
|
|
3079
3062
|
const messagesBefore = session.getMessages().length;
|
|
3080
3063
|
await runAgent(text, async () => {
|
|
@@ -3126,6 +3109,10 @@ async function createSession(deps, opts) {
|
|
|
3126
3109
|
// A prompt sent while Ken was reviewing (build idle) queued but had no
|
|
3127
3110
|
// run to steer into — run it now as a fresh turn so it never strands.
|
|
3128
3111
|
await runStrandedQueue();
|
|
3112
|
+
})
|
|
3113
|
+
.finally(() => {
|
|
3114
|
+
if (claimedStart)
|
|
3115
|
+
runClaim.release();
|
|
3129
3116
|
});
|
|
3130
3117
|
return;
|
|
3131
3118
|
}
|
|
@@ -3529,6 +3516,38 @@ async function createSession(deps, opts) {
|
|
|
3529
3516
|
});
|
|
3530
3517
|
return;
|
|
3531
3518
|
}
|
|
3519
|
+
// Pending queued steering, for the composer's cancel affordance.
|
|
3520
|
+
if (method === "GET" && url === "/queued") {
|
|
3521
|
+
json(res, 200, { queued: session.listQueuedMessages() });
|
|
3522
|
+
return;
|
|
3523
|
+
}
|
|
3524
|
+
// Cancel one pending queued message by id.
|
|
3525
|
+
if (method === "POST" && url === "/queued/cancel") {
|
|
3526
|
+
void readBody(req, res).then((raw) => {
|
|
3527
|
+
if (raw === null)
|
|
3528
|
+
return;
|
|
3529
|
+
let id;
|
|
3530
|
+
try {
|
|
3531
|
+
id = JSON.parse(raw).id ?? "";
|
|
3532
|
+
}
|
|
3533
|
+
catch {
|
|
3534
|
+
json(res, 400, { error: "invalid JSON body" });
|
|
3535
|
+
return;
|
|
3536
|
+
}
|
|
3537
|
+
if (!id.trim()) {
|
|
3538
|
+
json(res, 400, { error: "missing queued message id" });
|
|
3539
|
+
return;
|
|
3540
|
+
}
|
|
3541
|
+
// `false` means it already drained into the run between render and
|
|
3542
|
+
// click. That is a race, not an error, so report it as a normal result
|
|
3543
|
+
// and let the client reconcile from the fresh list.
|
|
3544
|
+
const cancelled = session.cancelQueuedMessage(id);
|
|
3545
|
+
const queued = session.listQueuedMessages();
|
|
3546
|
+
broadcast("queued", { count: queued.length, messages: queued });
|
|
3547
|
+
json(res, 200, { cancelled, queued });
|
|
3548
|
+
});
|
|
3549
|
+
return;
|
|
3550
|
+
}
|
|
3532
3551
|
if (method === "POST" && url === "/kill") {
|
|
3533
3552
|
void readBody(req, res).then(async (raw) => {
|
|
3534
3553
|
if (raw === null)
|
|
@@ -3586,7 +3605,7 @@ async function createSession(deps, opts) {
|
|
|
3586
3605
|
const generation = runLifecycle.generation;
|
|
3587
3606
|
if (!pendingCancelDrain || pendingCancelDrain.generation !== generation) {
|
|
3588
3607
|
pendingCancelDrain = { generation, text: session.drainQueue() };
|
|
3589
|
-
broadcast("queued", { count: 0 });
|
|
3608
|
+
broadcast("queued", { count: 0, messages: [] });
|
|
3590
3609
|
}
|
|
3591
3610
|
const result = await runLifecycle.cancel(CANCEL_TIMEOUT_MS);
|
|
3592
3611
|
const drained = pendingCancelDrain.text;
|