@kenkaiiii/ggcoder 5.8.0 → 5.8.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 +168 -34
- package/dist/app-sidecar.js.map +1 -1
- package/dist/core/agent-session.d.ts +32 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +129 -19
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/mcp/deferred-catalog.d.ts +28 -0
- package/dist/core/mcp/deferred-catalog.d.ts.map +1 -0
- package/dist/core/mcp/deferred-catalog.js +72 -0
- package/dist/core/mcp/deferred-catalog.js.map +1 -0
- package/dist/core/session-history.d.ts +51 -0
- package/dist/core/session-history.d.ts.map +1 -0
- package/dist/core/session-history.js +145 -0
- package/dist/core/session-history.js.map +1 -0
- package/dist/core/session-history.test.d.ts +2 -0
- package/dist/core/session-history.test.d.ts.map +1 -0
- package/dist/core/session-history.test.js +95 -0
- package/dist/core/session-history.test.js.map +1 -0
- package/dist/core/session-manager.d.ts +16 -0
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +32 -0
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/session-manager.test.js +61 -1
- package/dist/core/session-manager.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 +4 -0
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/system-prompt.d.ts.map +1 -1
- package/dist/system-prompt.js +13 -3
- package/dist/system-prompt.js.map +1 -1
- package/dist/system-prompt.test.js +19 -0
- package/dist/system-prompt.test.js.map +1 -1
- package/dist/tools/prompt-hints.d.ts.map +1 -1
- package/dist/tools/prompt-hints.js +3 -0
- package/dist/tools/prompt-hints.js.map +1 -1
- package/dist/tools/tool-search.d.ts +15 -0
- package/dist/tools/tool-search.d.ts.map +1 -0
- package/dist/tools/tool-search.js +35 -0
- package/dist/tools/tool-search.js.map +1 -0
- package/dist/ui/hooks/useAgentLoop.d.ts.map +1 -1
- package/dist/ui/hooks/useAgentLoop.js +22 -9
- package/dist/ui/hooks/useAgentLoop.js.map +1 -1
- package/package.json +4 -4
package/dist/app-sidecar.js
CHANGED
|
@@ -27,6 +27,7 @@ import { parseAutopilotVerdict } from "./core/autopilot-verdict.js";
|
|
|
27
27
|
import { isWorkflowCommandText, countAssistantMessages, shouldStartAutopilotCycle, extractTurnToolCalls, isMechanicalOnlyTurn, } from "./core/autopilot-gate.js";
|
|
28
28
|
import { driveAutopilotCycle } from "./core/autopilot-cycle.js";
|
|
29
29
|
import { validateKenModelPref, effectiveKenModel } from "./core/ken-model.js";
|
|
30
|
+
import { normalizeAutopilotMarkersForHistory, normalizeAppMarkersForHistory, normalizeKenTurnsForHistory, restoreUserRow, restoreAssistantTexts, autopilotMarkerCopySeed, } from "./core/session-history.js";
|
|
30
31
|
import { AuthStorage } from "./core/auth-storage.js";
|
|
31
32
|
import { MOONSHOT_OAUTH_KEY, XIAOMI_CREDITS_KEY } from "@kenkaiiii/gg-core";
|
|
32
33
|
import { loginAnthropic } from "./core/oauth/anthropic.js";
|
|
@@ -811,6 +812,16 @@ async function createSession(deps, opts) {
|
|
|
811
812
|
...(f.statusCode != null ? { statusCode: f.statusCode } : {}),
|
|
812
813
|
...(f.resetsAt != null ? { resetsAt: f.resetsAt } : {}),
|
|
813
814
|
});
|
|
815
|
+
// Persist the error row (display-only marker) so a resumed session shows
|
|
816
|
+
// the same headline/message/guidance the live run did. Best-effort.
|
|
817
|
+
void session
|
|
818
|
+
.persistAppMarker("error", {
|
|
819
|
+
scope: type,
|
|
820
|
+
headline: f.headline,
|
|
821
|
+
...(f.message ? { message: f.message } : {}),
|
|
822
|
+
guidance: f.guidance,
|
|
823
|
+
})
|
|
824
|
+
.catch(() => { });
|
|
814
825
|
}
|
|
815
826
|
// The session file path to resume (passed by the daemon's POST /session);
|
|
816
827
|
// empty/unset starts a fresh session.
|
|
@@ -835,6 +846,8 @@ async function createSession(deps, opts) {
|
|
|
835
846
|
onEnterPlan: async (reason) => {
|
|
836
847
|
await session.setPlanMode(true);
|
|
837
848
|
broadcast("plan_enter", { reason: reason ?? "" });
|
|
849
|
+
// Persist the plan-mode banner so a resumed session still shows it.
|
|
850
|
+
void session.persistAppMarker("plan", { reason: reason ?? "" }).catch(() => { });
|
|
838
851
|
},
|
|
839
852
|
onExitPlan: async (planPath) => {
|
|
840
853
|
await session.setPlanMode(false);
|
|
@@ -1371,14 +1384,24 @@ async function createSession(deps, opts) {
|
|
|
1371
1384
|
},
|
|
1372
1385
|
runPrompt: (body) => runAgent(body, () => session.prompt(body)),
|
|
1373
1386
|
emit: (event) => {
|
|
1374
|
-
broadcast(event.type, event.data);
|
|
1375
1387
|
// Persist the terminal verdict marker so a resumed session renders the
|
|
1376
1388
|
// same Ken bubble the live run showed instead of dropping it or
|
|
1377
1389
|
// falling back to the raw verdict text (e.g. ALL_CLEAR).
|
|
1378
1390
|
if (event.type === "autopilot_done") {
|
|
1391
|
+
// Broadcast the SAME copySeed the persisted marker will produce on
|
|
1392
|
+
// resume, so the live all-clear wording matches the resumed one
|
|
1393
|
+
// (computed before persist — same synchronous message count).
|
|
1394
|
+
const seed = autopilotMarkerCopySeed({
|
|
1395
|
+
version: 1,
|
|
1396
|
+
phase: "done",
|
|
1397
|
+
afterMessageCount: session.getMessages().filter((m) => m.role !== "system").length,
|
|
1398
|
+
});
|
|
1399
|
+
broadcast(event.type, { ...event.data, copySeed: seed });
|
|
1379
1400
|
void session.persistAutopilotMarker("done");
|
|
1401
|
+
return;
|
|
1380
1402
|
}
|
|
1381
|
-
|
|
1403
|
+
broadcast(event.type, event.data);
|
|
1404
|
+
if (event.type === "autopilot_human") {
|
|
1382
1405
|
void session.persistAutopilotMarker("human", { reason: event.data.reason });
|
|
1383
1406
|
}
|
|
1384
1407
|
else if (event.type === "autopilot_capped") {
|
|
@@ -1481,6 +1504,8 @@ async function createSession(deps, opts) {
|
|
|
1481
1504
|
markTaskInProgress(cwd, task.id);
|
|
1482
1505
|
broadcast("tasks_list", { tasks: loadTasksSync(cwd) });
|
|
1483
1506
|
broadcast("task_start", { id: task.id, title: task.title });
|
|
1507
|
+
// Persist the task header so a resumed task session shows what ran.
|
|
1508
|
+
void session.persistAppMarker("task", { title: task.title }).catch(() => { });
|
|
1484
1509
|
const shortId = task.id.slice(0, 8);
|
|
1485
1510
|
const completionHint = `\n\n---\nWhen you have fully completed this task, call the tasks tool to mark it done:\n` +
|
|
1486
1511
|
`tasks({ action: "done", id: "${shortId}" })`;
|
|
@@ -1771,8 +1796,11 @@ async function createSession(deps, opts) {
|
|
|
1771
1796
|
// they were recorded after, so each lands right after that message. A
|
|
1772
1797
|
// turn becomes two wire rows: the `@Ken` question (user) + Ken's reply
|
|
1773
1798
|
// (assistant), both flagged `ken` so the webview tints them.
|
|
1799
|
+
// Deduped; stale anchors are clamped to the last message (Ken turns
|
|
1800
|
+
// carry real conversation, so they render at the end instead of
|
|
1801
|
+
// vanishing).
|
|
1774
1802
|
const kenByCount = new Map();
|
|
1775
|
-
for (const turn of session.getKenTurns()) {
|
|
1803
|
+
for (const turn of normalizeKenTurnsForHistory(session.getKenTurns(), messages.filter((m) => m.role !== "system").length)) {
|
|
1776
1804
|
const list = kenByCount.get(turn.afterMessageCount) ?? [];
|
|
1777
1805
|
list.push(turn);
|
|
1778
1806
|
kenByCount.set(turn.afterMessageCount, list);
|
|
@@ -1790,8 +1818,12 @@ async function createSession(deps, opts) {
|
|
|
1790
1818
|
// Autopilot verdict markers to interleave, same anchor scheme as Ken
|
|
1791
1819
|
// turns — each becomes a single assistant row the webview renders
|
|
1792
1820
|
// exactly like the live `autopilot` item (never a raw verdict string).
|
|
1821
|
+
// Compact/continuation rewrites can carry old markers whose original
|
|
1822
|
+
// afterMessageCount is beyond the restored message list; dropping those
|
|
1823
|
+
// prevents stale all-clear bubbles from bunching at the bottom on resume.
|
|
1824
|
+
const restoredMessageCount = messages.filter((m) => m.role !== "system").length;
|
|
1793
1825
|
const autopilotByCount = new Map();
|
|
1794
|
-
for (const marker of session.getAutopilotMarkers()) {
|
|
1826
|
+
for (const marker of normalizeAutopilotMarkersForHistory(session.getAutopilotMarkers(), restoredMessageCount)) {
|
|
1795
1827
|
const list = autopilotByCount.get(marker.afterMessageCount) ?? [];
|
|
1796
1828
|
list.push(marker);
|
|
1797
1829
|
autopilotByCount.set(marker.afterMessageCount, list);
|
|
@@ -1809,15 +1841,77 @@ async function createSession(deps, opts) {
|
|
|
1809
1841
|
phase: marker.phase,
|
|
1810
1842
|
...(marker.reason !== undefined ? { reason: marker.reason } : {}),
|
|
1811
1843
|
...(marker.body !== undefined ? { body: marker.body } : {}),
|
|
1844
|
+
copySeed: marker.copySeed,
|
|
1812
1845
|
},
|
|
1813
1846
|
});
|
|
1814
1847
|
}
|
|
1815
1848
|
};
|
|
1849
|
+
// App transcript markers (plan banner / task header / error rows /
|
|
1850
|
+
// user-bubble hints), same anchor scheme. user_hint markers don't
|
|
1851
|
+
// become rows — they decorate the user row at their anchor instead.
|
|
1852
|
+
const appMarkersByCount = new Map();
|
|
1853
|
+
const userHintByCount = new Map();
|
|
1854
|
+
// Compaction-count markers pair with compacted summary rows in file
|
|
1855
|
+
// order (FIFO), not by anchor — the summary user message is what
|
|
1856
|
+
// positions the notice.
|
|
1857
|
+
const compactionCounts = [];
|
|
1858
|
+
for (const marker of normalizeAppMarkersForHistory(session.getAppMarkers(), restoredMessageCount)) {
|
|
1859
|
+
if (marker.kind === "user_hint") {
|
|
1860
|
+
userHintByCount.set(marker.afterMessageCount, marker.data);
|
|
1861
|
+
continue;
|
|
1862
|
+
}
|
|
1863
|
+
if (marker.kind === "compaction") {
|
|
1864
|
+
const d = marker.data;
|
|
1865
|
+
if (typeof d.originalCount === "number" && typeof d.newCount === "number") {
|
|
1866
|
+
compactionCounts.push({ originalCount: d.originalCount, newCount: d.newCount });
|
|
1867
|
+
}
|
|
1868
|
+
continue;
|
|
1869
|
+
}
|
|
1870
|
+
const list = appMarkersByCount.get(marker.afterMessageCount) ?? [];
|
|
1871
|
+
list.push(marker);
|
|
1872
|
+
appMarkersByCount.set(marker.afterMessageCount, list);
|
|
1873
|
+
}
|
|
1874
|
+
const flushAppMarkers = (count) => {
|
|
1875
|
+
const markers = appMarkersByCount.get(count);
|
|
1876
|
+
if (!markers)
|
|
1877
|
+
return;
|
|
1878
|
+
appMarkersByCount.delete(count);
|
|
1879
|
+
for (const marker of markers) {
|
|
1880
|
+
const d = marker.data;
|
|
1881
|
+
if (marker.kind === "plan") {
|
|
1882
|
+
history.push({
|
|
1883
|
+
role: "assistant",
|
|
1884
|
+
text: "",
|
|
1885
|
+
plan: { reason: typeof d.reason === "string" ? d.reason : "" },
|
|
1886
|
+
});
|
|
1887
|
+
}
|
|
1888
|
+
else if (marker.kind === "task") {
|
|
1889
|
+
history.push({
|
|
1890
|
+
role: "assistant",
|
|
1891
|
+
text: "",
|
|
1892
|
+
task: { title: typeof d.title === "string" ? d.title : "" },
|
|
1893
|
+
});
|
|
1894
|
+
}
|
|
1895
|
+
else if (marker.kind === "error" && typeof d.headline === "string") {
|
|
1896
|
+
history.push({
|
|
1897
|
+
role: "assistant",
|
|
1898
|
+
text: "",
|
|
1899
|
+
error: {
|
|
1900
|
+
scope: typeof d.scope === "string" ? d.scope : "error",
|
|
1901
|
+
headline: d.headline,
|
|
1902
|
+
...(typeof d.message === "string" ? { message: d.message } : {}),
|
|
1903
|
+
...(typeof d.guidance === "string" ? { guidance: d.guidance } : {}),
|
|
1904
|
+
},
|
|
1905
|
+
});
|
|
1906
|
+
}
|
|
1907
|
+
}
|
|
1908
|
+
};
|
|
1816
1909
|
let nonSystemCount = 0;
|
|
1817
1910
|
// Turns/markers recorded before any build message (anchor 0) render at
|
|
1818
1911
|
// the top.
|
|
1819
1912
|
flushKen(0);
|
|
1820
1913
|
flushAutopilot(0);
|
|
1914
|
+
flushAppMarkers(0);
|
|
1821
1915
|
for (const msg of messages) {
|
|
1822
1916
|
if (msg.role === "system")
|
|
1823
1917
|
continue;
|
|
@@ -1867,30 +1961,54 @@ async function createSession(deps, opts) {
|
|
|
1867
1961
|
}
|
|
1868
1962
|
continue;
|
|
1869
1963
|
}
|
|
1870
|
-
// User or assistant message —
|
|
1871
|
-
//
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1964
|
+
// User or assistant message — text/hook/command/compacted extraction,
|
|
1965
|
+
// plus sub-agent group detection for assistant tool_calls.
|
|
1966
|
+
if (msg.role === "user") {
|
|
1967
|
+
// Rebuild the live bubble: strip the steering wrapper, drop
|
|
1968
|
+
// attachment/file notes the model saw but the bubble never showed.
|
|
1969
|
+
const restored = restoreUserRow(msg.content);
|
|
1970
|
+
const text = restored.text;
|
|
1971
|
+
const hook = detectHookKind(text);
|
|
1972
|
+
const compacted = !hook && text.startsWith("[Previous conversation summary]");
|
|
1973
|
+
const command = !hook && !compacted ? detectPromptCommand(text, commandCandidates) : null;
|
|
1974
|
+
if (text.trim() || restored.images.length > 0) {
|
|
1975
|
+
const hint = userHintByCount.get(nonSystemCount);
|
|
1976
|
+
history.push({
|
|
1977
|
+
role: "user",
|
|
1978
|
+
text: command ?? text,
|
|
1979
|
+
images: restored.images,
|
|
1980
|
+
hook,
|
|
1981
|
+
command: command !== null,
|
|
1982
|
+
compacted,
|
|
1983
|
+
// Markers accumulate across continuation files (each rewrite
|
|
1984
|
+
// re-persists prior ones) but only the LATEST summary row
|
|
1985
|
+
// survives compaction — so consume from the newest end.
|
|
1986
|
+
...(compacted && compactionCounts.length > 0
|
|
1987
|
+
? { compactionCounts: compactionCounts.pop() }
|
|
1988
|
+
: {}),
|
|
1989
|
+
...(hint?.kenSent === true ? { kenSent: true } : {}),
|
|
1990
|
+
...(Array.isArray(hint?.enhancements) ? { enhancements: hint.enhancements } : {}),
|
|
1991
|
+
});
|
|
1992
|
+
// Live showed the video-capability warning right after the bubble.
|
|
1993
|
+
if (restored.videoWarning) {
|
|
1994
|
+
history.push({ role: "assistant", text: "", infoKind: "video_warning" });
|
|
1995
|
+
}
|
|
1996
|
+
}
|
|
1997
|
+
}
|
|
1998
|
+
else {
|
|
1999
|
+
// Assistant: one wire row per persisted text block — live streaming
|
|
2000
|
+
// splits bubbles at server_tool_call boundaries, and the persisted
|
|
2001
|
+
// content keeps those blocks separate.
|
|
2002
|
+
for (const blockText of restoreAssistantTexts(msg.content)) {
|
|
2003
|
+
history.push({
|
|
2004
|
+
role: "assistant",
|
|
2005
|
+
text: blockText,
|
|
2006
|
+
images: [],
|
|
2007
|
+
hook: null,
|
|
2008
|
+
command: false,
|
|
2009
|
+
compacted: false,
|
|
2010
|
+
});
|
|
2011
|
+
}
|
|
1894
2012
|
}
|
|
1895
2013
|
// Assistant tool_call blocks: detect sub-agent delegations.
|
|
1896
2014
|
if (msg.role === "assistant" && typeof msg.content !== "string") {
|
|
@@ -1911,19 +2029,21 @@ async function createSession(deps, opts) {
|
|
|
1911
2029
|
});
|
|
1912
2030
|
}
|
|
1913
2031
|
}
|
|
1914
|
-
// Interleave any Ken turns / autopilot markers recorded right
|
|
1915
|
-
// this message.
|
|
2032
|
+
// Interleave any Ken turns / autopilot / app markers recorded right
|
|
2033
|
+
// after this message.
|
|
1916
2034
|
flushKen(nonSystemCount);
|
|
1917
2035
|
flushAutopilot(nonSystemCount);
|
|
2036
|
+
flushAppMarkers(nonSystemCount);
|
|
1918
2037
|
}
|
|
1919
|
-
// Flush remaining Ken turns
|
|
1920
|
-
//
|
|
1921
|
-
//
|
|
1922
|
-
// are dropped.
|
|
2038
|
+
// Flush remaining Ken turns whose anchor is at/after the message count so
|
|
2039
|
+
// none are dropped. Autopilot/app markers beyond the restored message
|
|
2040
|
+
// count were already filtered above; any remaining marker here is valid.
|
|
1923
2041
|
for (const count of [...kenByCount.keys()].sort((a, b) => a - b))
|
|
1924
2042
|
flushKen(count);
|
|
1925
2043
|
for (const count of [...autopilotByCount.keys()].sort((a, b) => a - b))
|
|
1926
2044
|
flushAutopilot(count);
|
|
2045
|
+
for (const count of [...appMarkersByCount.keys()].sort((a, b) => a - b))
|
|
2046
|
+
flushAppMarkers(count);
|
|
1927
2047
|
json(res, 200, { history });
|
|
1928
2048
|
})();
|
|
1929
2049
|
return;
|
|
@@ -1956,10 +2076,12 @@ async function createSession(deps, opts) {
|
|
|
1956
2076
|
void readBody(req).then(async (raw) => {
|
|
1957
2077
|
let text;
|
|
1958
2078
|
let attachments;
|
|
2079
|
+
let meta;
|
|
1959
2080
|
try {
|
|
1960
2081
|
const body = JSON.parse(raw);
|
|
1961
2082
|
text = body.text ?? "";
|
|
1962
2083
|
attachments = Array.isArray(body.attachments) ? body.attachments : [];
|
|
2084
|
+
meta = typeof body.meta === "object" && body.meta !== null ? body.meta : undefined;
|
|
1963
2085
|
}
|
|
1964
2086
|
catch {
|
|
1965
2087
|
json(res, 400, { error: "invalid JSON body" });
|
|
@@ -1983,6 +2105,18 @@ async function createSession(deps, opts) {
|
|
|
1983
2105
|
return;
|
|
1984
2106
|
}
|
|
1985
2107
|
json(res, 202, { accepted: true });
|
|
2108
|
+
// Webview display hint for this prompt's user bubble (kenSent shimmer
|
|
2109
|
+
// label / enhancer highlight segments). Anchored +1 so it attaches to
|
|
2110
|
+
// the user message the prompt below is about to push. Queued prompts
|
|
2111
|
+
// skip this (their position in the run is unpredictable).
|
|
2112
|
+
if (meta && (meta.kenSent === true || Array.isArray(meta.enhancements))) {
|
|
2113
|
+
void session
|
|
2114
|
+
.persistAppMarker("user_hint", {
|
|
2115
|
+
...(meta.kenSent === true ? { kenSent: true } : {}),
|
|
2116
|
+
...(Array.isArray(meta.enhancements) ? { enhancements: meta.enhancements } : {}),
|
|
2117
|
+
}, 1)
|
|
2118
|
+
.catch(() => { });
|
|
2119
|
+
}
|
|
1986
2120
|
// Fresh user turn: clear any cancel flag left from a prior cycle so this
|
|
1987
2121
|
// turn's autopilot review can run.
|
|
1988
2122
|
autopilotCancelled = false;
|