@kenkaiiii/ggcoder 5.6.1 → 5.6.3

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.
Files changed (36) hide show
  1. package/dist/app-sidecar.js +85 -20
  2. package/dist/app-sidecar.js.map +1 -1
  3. package/dist/core/agent-session.d.ts +34 -2
  4. package/dist/core/agent-session.d.ts.map +1 -1
  5. package/dist/core/agent-session.js +94 -15
  6. package/dist/core/agent-session.js.map +1 -1
  7. package/dist/core/autopilot-gate.d.ts +36 -22
  8. package/dist/core/autopilot-gate.d.ts.map +1 -1
  9. package/dist/core/autopilot-gate.js +100 -0
  10. package/dist/core/autopilot-gate.js.map +1 -1
  11. package/dist/core/autopilot-gate.test.js +112 -1
  12. package/dist/core/autopilot-gate.test.js.map +1 -1
  13. package/dist/core/autopilot-verdict.d.ts.map +1 -1
  14. package/dist/core/autopilot-verdict.js +41 -1
  15. package/dist/core/autopilot-verdict.js.map +1 -1
  16. package/dist/core/autopilot-verdict.test.js +16 -0
  17. package/dist/core/autopilot-verdict.test.js.map +1 -1
  18. package/dist/core/ken-context.d.ts +6 -2
  19. package/dist/core/ken-context.d.ts.map +1 -1
  20. package/dist/core/ken-context.js +0 -2
  21. package/dist/core/ken-context.js.map +1 -1
  22. package/dist/core/ken-context.test.js +1 -7
  23. package/dist/core/ken-context.test.js.map +1 -1
  24. package/dist/core/ken-prompt.d.ts +2 -15
  25. package/dist/core/ken-prompt.d.ts.map +1 -1
  26. package/dist/core/ken-prompt.js +39 -10
  27. package/dist/core/ken-prompt.js.map +1 -1
  28. package/dist/core/ken-prompt.test.js +37 -4
  29. package/dist/core/ken-prompt.test.js.map +1 -1
  30. package/dist/core/session-manager.d.ts +18 -0
  31. package/dist/core/session-manager.d.ts.map +1 -1
  32. package/dist/core/session-manager.js +31 -0
  33. package/dist/core/session-manager.js.map +1 -1
  34. package/dist/core/session-manager.test.js +71 -1
  35. package/dist/core/session-manager.test.js.map +1 -1
  36. package/package.json +4 -4
@@ -23,10 +23,9 @@ import { AgentSession } from "./core/agent-session.js";
23
23
  import { buildKenSystemPrompt, buildKenAutopilotSystemPrompt } from "./core/ken-prompt.js";
24
24
  import { buildKenDigest, buildKenAutopilotContext } from "./core/ken-context.js";
25
25
  import { parseAutopilotVerdict } from "./core/autopilot-verdict.js";
26
- import { isWorkflowCommandText, countAssistantMessages, shouldStartAutopilotCycle, } from "./core/autopilot-gate.js";
26
+ import { isWorkflowCommandText, countAssistantMessages, shouldStartAutopilotCycle, extractTurnToolCalls, isMechanicalOnlyTurn, } from "./core/autopilot-gate.js";
27
27
  import { driveAutopilotCycle } from "./core/autopilot-cycle.js";
28
28
  import { validateKenModelPref, effectiveKenModel } from "./core/ken-model.js";
29
- import { collectProjectContext } from "./system-prompt.js";
30
29
  import { AuthStorage } from "./core/auth-storage.js";
31
30
  import { MOONSHOT_OAUTH_KEY, XIAOMI_CREDITS_KEY } from "@kenkaiiii/gg-core";
32
31
  import { loginAnthropic } from "./core/oauth/anthropic.js";
@@ -623,17 +622,18 @@ function lastAssistantText(messages) {
623
622
  return "";
624
623
  }
625
624
  /**
626
- * Assemble Ken's context digest for one `@Ken` question: project docs (up the
627
- * tree) + git/env + the build session's compaction summary + recent activity.
628
- * Prepended to the user's question as Ken's prompt body each turn. Workflow
629
- * commands + autopilot-injected prompts are passed through so the digest
630
- * labels them as what they are instead of user-authored asks.
625
+ * Assemble Ken's context digest for one `@Ken` question: git/env + the build
626
+ * session's compaction summary + recent activity. Prepended to the user's
627
+ * question as Ken's prompt body each turn. Project docs (CLAUDE.md/AGENTS.md)
628
+ * are NOT here they're folded into Ken's cached system prompt once per
629
+ * session instead (see ken-prompt.ts), so they hit the provider prompt cache
630
+ * instead of being re-sent uncached on every question. Workflow commands +
631
+ * autopilot-injected prompts are passed through so the digest labels them as
632
+ * what they are instead of user-authored asks.
631
633
  */
632
- async function buildKenContext(buildSession, cwd, gitBranch, question, workflowCommands, injectedPrompts) {
633
- const projectContext = await collectProjectContext(cwd).catch(() => []);
634
+ function buildKenContext(buildSession, cwd, gitBranch, question, workflowCommands, injectedPrompts) {
634
635
  return buildKenDigest({
635
636
  question,
636
- projectContext,
637
637
  cwd,
638
638
  gitBranch,
639
639
  messages: buildSession.getMessages(),
@@ -912,11 +912,14 @@ async function createSession(deps, opts) {
912
912
  provider: target.provider,
913
913
  model: target.model,
914
914
  cwd,
915
- systemPrompt: buildKenSystemPrompt(),
915
+ systemPrompt: await buildKenSystemPrompt(cwd),
916
916
  allowedTools: KEN_ALLOWED_TOOLS,
917
917
  allowedMcpServers: KEN_ALLOWED_MCP_SERVERS,
918
918
  transient: true,
919
919
  signal: kenAbort.signal,
920
+ // Ken's bursty, spread-out turns (chat) outlast the default 5-min cache
921
+ // TTL regardless of the user's global speedProfile pick.
922
+ forceLongCacheRetention: true,
920
923
  });
921
924
  await ken.initialize();
922
925
  // Bridge Ken's bus to the shared SSE fan-out with ken_-prefixed types so the
@@ -978,11 +981,14 @@ async function createSession(deps, opts) {
978
981
  provider: target.provider,
979
982
  model: target.model,
980
983
  cwd,
981
- systemPrompt: buildKenAutopilotSystemPrompt(),
984
+ systemPrompt: await buildKenAutopilotSystemPrompt(cwd),
982
985
  allowedTools: KEN_ALLOWED_TOOLS,
983
986
  allowedMcpServers: KEN_ALLOWED_MCP_SERVERS,
984
987
  transient: true,
985
988
  signal: kenAutoAbort.signal,
989
+ // Autopilot review rounds routinely span the injected GG Coder run
990
+ // (often >5 min) regardless of the user's global speedProfile pick.
991
+ forceLongCacheRetention: true,
986
992
  });
987
993
  await ken.initialize();
988
994
  // Deliberately no bus bridge: the review is silent. Errors surface via the
@@ -1062,9 +1068,7 @@ async function createSession(deps, opts) {
1062
1068
  broadcast("autopilot_review_start", {});
1063
1069
  try {
1064
1070
  const ken = await ensureKenAutoSession();
1065
- const projectContext = await collectProjectContext(cwd).catch(() => []);
1066
1071
  const digest = buildKenAutopilotContext({
1067
- projectContext,
1068
1072
  cwd,
1069
1073
  gitBranch,
1070
1074
  messages: session.getMessages(),
@@ -1121,9 +1125,25 @@ async function createSession(deps, opts) {
1121
1125
  onInjected: (body, round) => {
1122
1126
  injectedAutopilotPrompts.push(body);
1123
1127
  broadcast("autopilot_prompted", { round, body });
1128
+ void session.persistAutopilotMarker("prompted", { body });
1124
1129
  },
1125
1130
  runPrompt: (body) => runAgent(body, () => session.prompt(body)),
1126
- emit: (event) => broadcast(event.type, event.data),
1131
+ emit: (event) => {
1132
+ broadcast(event.type, event.data);
1133
+ // Persist the terminal verdict marker so a resumed session renders the
1134
+ // same Ken bubble the live run showed instead of dropping it or
1135
+ // falling back to the raw verdict text (e.g. ALL_CLEAR).
1136
+ if (event.type === "autopilot_done") {
1137
+ void session.persistAutopilotMarker("done");
1138
+ }
1139
+ else if (event.type === "autopilot_human") {
1140
+ void session.persistAutopilotMarker("human", { reason: event.data.reason });
1141
+ }
1142
+ else if (event.type === "autopilot_capped") {
1143
+ void session.persistAutopilotMarker("capped");
1144
+ }
1145
+ // autopilot_ignored renders nothing live, so nothing is persisted either.
1146
+ },
1127
1147
  });
1128
1148
  }
1129
1149
  finally {
@@ -1157,6 +1177,7 @@ async function createSession(deps, opts) {
1157
1177
  const workflowCommand = next.attachments.length === 0 &&
1158
1178
  isWorkflowCommandText(next.text, await loadWorkflowCommandSpecs());
1159
1179
  const assistantsBefore = countAssistantMessages(session.getMessages());
1180
+ const messagesBefore = session.getMessages().length;
1160
1181
  await runAgent(next.text, async () => {
1161
1182
  if (next.attachments.length > 0) {
1162
1183
  await session.promptWithAttachments(next.text, next.attachments);
@@ -1171,6 +1192,11 @@ async function createSession(deps, opts) {
1171
1192
  planMode: session.getPlanMode(),
1172
1193
  workflowCommand,
1173
1194
  assistantMessagesAdded: countAssistantMessages(session.getMessages()) - assistantsBefore,
1195
+ // Skip the review API call outright for turns that only started a
1196
+ // background process (dev server/watcher), ran a read-only lookup, or
1197
+ // committed/pushed — Ken's autopilot contract already IGNOREs these,
1198
+ // so there's no reason to pay for that verdict.
1199
+ mechanicalOnly: isMechanicalOnlyTurn(extractTurnToolCalls(session.getMessages(), messagesBefore)),
1174
1200
  });
1175
1201
  if (decision.start) {
1176
1202
  await runAutopilotCycle(next.text);
@@ -1505,9 +1531,37 @@ async function createSession(deps, opts) {
1505
1531
  history.push({ role: "assistant", text: turn.reply, ken: true });
1506
1532
  }
1507
1533
  };
1534
+ // Autopilot verdict markers to interleave, same anchor scheme as Ken
1535
+ // turns — each becomes a single assistant row the webview renders
1536
+ // exactly like the live `autopilot` item (never a raw verdict string).
1537
+ const autopilotByCount = new Map();
1538
+ for (const marker of session.getAutopilotMarkers()) {
1539
+ const list = autopilotByCount.get(marker.afterMessageCount) ?? [];
1540
+ list.push(marker);
1541
+ autopilotByCount.set(marker.afterMessageCount, list);
1542
+ }
1543
+ const flushAutopilot = (count) => {
1544
+ const markers = autopilotByCount.get(count);
1545
+ if (!markers)
1546
+ return;
1547
+ autopilotByCount.delete(count);
1548
+ for (const marker of markers) {
1549
+ history.push({
1550
+ role: "assistant",
1551
+ text: "",
1552
+ autopilot: {
1553
+ phase: marker.phase,
1554
+ ...(marker.reason !== undefined ? { reason: marker.reason } : {}),
1555
+ ...(marker.body !== undefined ? { body: marker.body } : {}),
1556
+ },
1557
+ });
1558
+ }
1559
+ };
1508
1560
  let nonSystemCount = 0;
1509
- // Turns recorded before any build message (anchor 0) render at the top.
1561
+ // Turns/markers recorded before any build message (anchor 0) render at
1562
+ // the top.
1510
1563
  flushKen(0);
1564
+ flushAutopilot(0);
1511
1565
  for (const msg of messages) {
1512
1566
  if (msg.role === "system")
1513
1567
  continue;
@@ -1601,14 +1655,19 @@ async function createSession(deps, opts) {
1601
1655
  });
1602
1656
  }
1603
1657
  }
1604
- // Interleave any Ken turns recorded right after this message.
1658
+ // Interleave any Ken turns / autopilot markers recorded right after
1659
+ // this message.
1605
1660
  flushKen(nonSystemCount);
1661
+ flushAutopilot(nonSystemCount);
1606
1662
  }
1607
- // Flush remaining Ken turns whose anchor is at/after the message count
1608
- // (e.g. asked before any build message, or anchors beyond the current
1609
- // count after compaction shrank the history) so none are dropped.
1663
+ // Flush remaining Ken turns / autopilot markers whose anchor is at/after
1664
+ // the message count (e.g. recorded before any build message, or anchors
1665
+ // beyond the current count after compaction shrank the history) so none
1666
+ // are dropped.
1610
1667
  for (const count of [...kenByCount.keys()].sort((a, b) => a - b))
1611
1668
  flushKen(count);
1669
+ for (const count of [...autopilotByCount.keys()].sort((a, b) => a - b))
1670
+ flushAutopilot(count);
1612
1671
  json(res, 200, { history });
1613
1672
  })();
1614
1673
  return;
@@ -1678,6 +1737,7 @@ async function createSession(deps, opts) {
1678
1737
  // gate reads the post-run value.
1679
1738
  const workflowCommand = attachments.length === 0 && isWorkflowCommandText(text, await loadWorkflowCommandSpecs());
1680
1739
  const assistantsBefore = countAssistantMessages(session.getMessages());
1740
+ const messagesBefore = session.getMessages().length;
1681
1741
  await runAgent(text, async () => {
1682
1742
  if (attachments.length > 0) {
1683
1743
  // Persist each attachment under .gg/uploads so files are inspectable
@@ -1708,6 +1768,11 @@ async function createSession(deps, opts) {
1708
1768
  planMode: session.getPlanMode(),
1709
1769
  workflowCommand,
1710
1770
  assistantMessagesAdded: countAssistantMessages(session.getMessages()) - assistantsBefore,
1771
+ // Skip the review API call outright for turns that only started a
1772
+ // background process (dev server/watcher), ran a read-only lookup, or
1773
+ // committed/pushed — Ken's autopilot contract already IGNOREs these,
1774
+ // so there's no reason to pay for that verdict.
1775
+ mechanicalOnly: isMechanicalOnlyTurn(extractTurnToolCalls(session.getMessages(), messagesBefore)),
1711
1776
  });
1712
1777
  if (decision.start) {
1713
1778
  await runAutopilotCycle(text);