@kenkaiiii/ggcoder 5.26.2 → 5.27.0

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 (107) hide show
  1. package/dist/app-sidecar.js +81 -47
  2. package/dist/app-sidecar.js.map +1 -1
  3. package/dist/core/agent-session-marker-anchors.test.js +181 -2
  4. package/dist/core/agent-session-marker-anchors.test.js.map +1 -1
  5. package/dist/core/agent-session-process-gate.test.d.ts +2 -0
  6. package/dist/core/agent-session-process-gate.test.d.ts.map +1 -0
  7. package/dist/core/agent-session-process-gate.test.js +88 -0
  8. package/dist/core/agent-session-process-gate.test.js.map +1 -0
  9. package/dist/core/agent-session-slash-restore.test.d.ts +2 -0
  10. package/dist/core/agent-session-slash-restore.test.d.ts.map +1 -0
  11. package/dist/core/agent-session-slash-restore.test.js +121 -0
  12. package/dist/core/agent-session-slash-restore.test.js.map +1 -0
  13. package/dist/core/agent-session.d.ts +66 -0
  14. package/dist/core/agent-session.d.ts.map +1 -1
  15. package/dist/core/agent-session.js +304 -35
  16. package/dist/core/agent-session.js.map +1 -1
  17. package/dist/core/compaction/compactor.d.ts +21 -0
  18. package/dist/core/compaction/compactor.d.ts.map +1 -1
  19. package/dist/core/compaction/compactor.js +16 -0
  20. package/dist/core/compaction/compactor.js.map +1 -1
  21. package/dist/core/compaction/compactor.test.js +91 -0
  22. package/dist/core/compaction/compactor.test.js.map +1 -1
  23. package/dist/core/foreign-session-import.d.ts +120 -0
  24. package/dist/core/foreign-session-import.d.ts.map +1 -0
  25. package/dist/core/foreign-session-import.js +594 -0
  26. package/dist/core/foreign-session-import.js.map +1 -0
  27. package/dist/core/foreign-session-import.test.d.ts +2 -0
  28. package/dist/core/foreign-session-import.test.d.ts.map +1 -0
  29. package/dist/core/foreign-session-import.test.js +220 -0
  30. package/dist/core/foreign-session-import.test.js.map +1 -0
  31. package/dist/core/foreign-transcript-blocks.d.ts +51 -0
  32. package/dist/core/foreign-transcript-blocks.d.ts.map +1 -0
  33. package/dist/core/foreign-transcript-blocks.js +151 -0
  34. package/dist/core/foreign-transcript-blocks.js.map +1 -0
  35. package/dist/core/mcp/catalog-cache.d.ts +63 -0
  36. package/dist/core/mcp/catalog-cache.d.ts.map +1 -0
  37. package/dist/core/mcp/catalog-cache.js +163 -0
  38. package/dist/core/mcp/catalog-cache.js.map +1 -0
  39. package/dist/core/mcp/catalog-cache.test.d.ts +2 -0
  40. package/dist/core/mcp/catalog-cache.test.d.ts.map +1 -0
  41. package/dist/core/mcp/catalog-cache.test.js +99 -0
  42. package/dist/core/mcp/catalog-cache.test.js.map +1 -0
  43. package/dist/core/mcp/client.d.ts +61 -0
  44. package/dist/core/mcp/client.d.ts.map +1 -1
  45. package/dist/core/mcp/client.js +216 -31
  46. package/dist/core/mcp/client.js.map +1 -1
  47. package/dist/core/mcp/legacy-negotiation.test.d.ts +2 -0
  48. package/dist/core/mcp/legacy-negotiation.test.d.ts.map +1 -0
  49. package/dist/core/mcp/legacy-negotiation.test.js +80 -0
  50. package/dist/core/mcp/legacy-negotiation.test.js.map +1 -0
  51. package/dist/core/mcp/oauth-provider.d.ts +1 -2
  52. package/dist/core/mcp/oauth-provider.d.ts.map +1 -1
  53. package/dist/core/mcp/oauth-provider.js +5 -1
  54. package/dist/core/mcp/oauth-provider.js.map +1 -1
  55. package/dist/core/mcp/oauth-store.d.ts +1 -1
  56. package/dist/core/mcp/oauth-store.d.ts.map +1 -1
  57. package/dist/core/mcp/oauth-store.js.map +1 -1
  58. package/dist/core/mcp/when-connected.test.d.ts +2 -0
  59. package/dist/core/mcp/when-connected.test.d.ts.map +1 -0
  60. package/dist/core/mcp/when-connected.test.js +46 -0
  61. package/dist/core/mcp/when-connected.test.js.map +1 -0
  62. package/dist/core/process-gate.d.ts +45 -0
  63. package/dist/core/process-gate.d.ts.map +1 -0
  64. package/dist/core/process-gate.js +71 -0
  65. package/dist/core/process-gate.js.map +1 -0
  66. package/dist/core/process-gate.test.d.ts +2 -0
  67. package/dist/core/process-gate.test.d.ts.map +1 -0
  68. package/dist/core/process-gate.test.js +87 -0
  69. package/dist/core/process-gate.test.js.map +1 -0
  70. package/dist/core/process-manager.d.ts +9 -0
  71. package/dist/core/process-manager.d.ts.map +1 -1
  72. package/dist/core/process-manager.js +17 -15
  73. package/dist/core/process-manager.js.map +1 -1
  74. package/dist/core/session-history.d.ts +61 -4
  75. package/dist/core/session-history.d.ts.map +1 -1
  76. package/dist/core/session-history.js +144 -15
  77. package/dist/core/session-history.js.map +1 -1
  78. package/dist/core/session-history.test.js +50 -1
  79. package/dist/core/session-history.test.js.map +1 -1
  80. package/dist/core/session-manager.d.ts +35 -6
  81. package/dist/core/session-manager.d.ts.map +1 -1
  82. package/dist/core/session-manager.js +39 -10
  83. package/dist/core/session-manager.js.map +1 -1
  84. package/dist/core/session-manager.test.js +14 -2
  85. package/dist/core/session-manager.test.js.map +1 -1
  86. package/dist/core/settings-manager.d.ts +1 -0
  87. package/dist/core/settings-manager.d.ts.map +1 -1
  88. package/dist/core/settings-manager.js +6 -0
  89. package/dist/core/settings-manager.js.map +1 -1
  90. package/dist/core/slash-commands.d.ts +2 -0
  91. package/dist/core/slash-commands.d.ts.map +1 -1
  92. package/dist/core/slash-commands.js +17 -0
  93. package/dist/core/slash-commands.js.map +1 -1
  94. package/dist/core/slash-commands.test.js +1 -0
  95. package/dist/core/slash-commands.test.js.map +1 -1
  96. package/dist/tools/tool-search.d.ts +12 -1
  97. package/dist/tools/tool-search.d.ts.map +1 -1
  98. package/dist/tools/tool-search.js +22 -3
  99. package/dist/tools/tool-search.js.map +1 -1
  100. package/dist/tools/tool-search.test.d.ts +2 -0
  101. package/dist/tools/tool-search.test.d.ts.map +1 -0
  102. package/dist/tools/tool-search.test.js +69 -0
  103. package/dist/tools/tool-search.test.js.map +1 -0
  104. package/dist/ui/App.d.ts.map +1 -1
  105. package/dist/ui/App.js +27 -1
  106. package/dist/ui/App.js.map +1 -1
  107. package/package.json +5 -5
@@ -34,7 +34,7 @@ import { parseAutopilotVerdict } from "./core/autopilot-verdict.js";
34
34
  import { isWorkflowCommandText, countAssistantMessages, shouldStartAutopilotCycle, extractTurnToolCalls, isMechanicalOnlyTurn, } from "./core/autopilot-gate.js";
35
35
  import { driveAutopilotCycle, frameAutopilotInjection } from "./core/autopilot-cycle.js";
36
36
  import { validateKenModelPref, effectiveKenModel } from "./core/ken-model.js";
37
- import { normalizeAutopilotMarkersForHistory, normalizeAppMarkersForHistory, normalizeKenTurnsForHistory, restoreUserRow, restoreAssistantTexts, autopilotMarkerCopySeed, } from "./core/session-history.js";
37
+ import { normalizeAutopilotMarkersForHistory, normalizeAppMarkersForHistory, normalizeKenTurnsForHistory, restoreUserRow, restoreAssistantTexts, resolveRestoredCommand, autopilotMarkerCopySeed, } from "./core/session-history.js";
38
38
  import { sessionToMarkdown, defaultExportFilename, } from "./core/session-export.js";
39
39
  import { AuthStorage } from "./core/auth-storage.js";
40
40
  import { cleanupToolOutputs } from "./tools/overflow.js";
@@ -364,30 +364,6 @@ function detectHookKind(text) {
364
364
  return "regrounding";
365
365
  return null;
366
366
  }
367
- // Separator AgentSession.prompt() inserts between a command's prompt body and
368
- // the user's trailing args. Must stay in sync with the expansion there.
369
- const COMMAND_ARGS_SEP = "\n\n## User Instructions\n\n";
370
- /**
371
- * Reverse a prompt-template command's expansion. When a `/name` command runs,
372
- * the agent persists the FULL expanded prompt body as the user message — so on
373
- * resume the raw body would render instead of the short `/name` chip the user
374
- * saw live. Given the candidate commands (built-in + custom) and a restored
375
- * message body, recover the original `/name [args]` invocation. Returns null
376
- * when the text isn't a known command body (an ordinary user message).
377
- */
378
- function detectPromptCommand(text, candidates) {
379
- for (const c of candidates) {
380
- if (!c.prompt)
381
- continue;
382
- if (text === c.prompt)
383
- return `/${c.name}`;
384
- if (text.startsWith(c.prompt + COMMAND_ARGS_SEP)) {
385
- const args = text.slice(c.prompt.length + COMMAND_ARGS_SEP.length).trim();
386
- return args ? `/${c.name} ${args}` : `/${c.name}`;
387
- }
388
- }
389
- return null;
390
- }
391
367
  /** A short transport summary for display (URL for http/sse, command+args for stdio). */
392
368
  function mcpRowSummary(config) {
393
369
  if (config.url)
@@ -2121,12 +2097,14 @@ async function createSession(deps, opts) {
2121
2097
  // falling back to the raw verdict text (e.g. ALL_CLEAR).
2122
2098
  if (event.type === "autopilot_done") {
2123
2099
  // Broadcast the SAME copySeed the persisted marker will produce on
2124
- // resume, so the live all-clear wording matches the resumed one
2125
- // (computed before persistsame synchronous message count).
2100
+ // resume, so the live all-clear wording matches the resumed one.
2101
+ // Must use the PERSISTED count that's what persistAutopilotMarker
2102
+ // anchors against, and it trails the in-memory list after a run
2103
+ // whose messages never made it to disk.
2126
2104
  const seed = autopilotMarkerCopySeed({
2127
2105
  version: 1,
2128
2106
  phase: "done",
2129
- afterMessageCount: session.getMessages().filter((m) => m.role !== "system").length,
2107
+ afterMessageCount: session.getPersistedTranscriptCount(),
2130
2108
  });
2131
2109
  broadcast(event.type, { ...event.data, copySeed: seed });
2132
2110
  void session.persistAutopilotMarker("done");
@@ -2698,9 +2676,9 @@ async function createSession(deps, opts) {
2698
2676
  // Autopilot verdict markers to interleave, same anchor scheme as Ken
2699
2677
  // turns — each becomes a single assistant row the webview renders
2700
2678
  // exactly like the live `autopilot` item (never a raw verdict string).
2701
- // Compact/continuation rewrites can carry old markers whose original
2702
- // afterMessageCount is beyond the restored message list; dropping those
2703
- // prevents stale all-clear bubbles from bunching at the bottom on resume.
2679
+ // Normalization pulls anchors left over from an unrebased compaction
2680
+ // back to where the marker was actually written, so stale all-clear
2681
+ // bubbles no longer bunch at the bottom of a reopened session.
2704
2682
  const restoredMessageCount = messages.filter((m) => m.role !== "system").length;
2705
2683
  const autopilotByCount = new Map();
2706
2684
  for (const marker of normalizeAutopilotMarkersForHistory(session.getAutopilotMarkers(), restoredMessageCount)) {
@@ -2850,9 +2828,21 @@ async function createSession(deps, opts) {
2850
2828
  const text = restored.text;
2851
2829
  const hook = detectHookKind(text);
2852
2830
  const compacted = !hook && text.startsWith("[Previous conversation summary]");
2853
- const command = !hook && !compacted ? detectPromptCommand(text, commandCandidates) : null;
2854
- if (text.trim() || restored.images.length > 0) {
2855
- const hint = userHintByCount.get(nonSystemCount);
2831
+ const hint = userHintByCount.get(nonSystemCount);
2832
+ // The typed invocation persisted alongside the prompt is
2833
+ // authoritative. Reversing the expanded body only works while the
2834
+ // template is byte-identical, and templates drift (edited
2835
+ // `.gg/commands/*.md`, reworded built-ins, app-vs-CLI phrasing) —
2836
+ // after which the resumed session dumped the raw multi-KB body
2837
+ // instead of the `/name` chip. Older sessions have no hint, so the
2838
+ // body match stays as the fallback.
2839
+ const command = !hook && !compacted
2840
+ ? resolveRestoredCommand(typeof hint?.command === "string" ? hint.command : null, text, commandCandidates)
2841
+ : null;
2842
+ // Autopilot injected this turn — live showed only the Ken-tinted
2843
+ // marker for it, never a user bubble. Emitting one here would print
2844
+ // the injected instruction a second time, unstyled.
2845
+ if (!restored.autopilotInjected && (text.trim() || restored.images.length > 0)) {
2856
2846
  history.push({
2857
2847
  role: "user",
2858
2848
  text: command ?? text,
@@ -3032,15 +3022,39 @@ async function createSession(deps, opts) {
3032
3022
  // yield, and `running` does not flip until runAgent begins.
3033
3023
  claimedStart = runClaim.claim();
3034
3024
  json(res, 202, { accepted: true });
3025
+ // Gate inputs captured around the run: whether this turn is a workflow
3026
+ // slash command (attachment prompts skip slash expansion entirely), and
3027
+ // how many assistant messages the run actually adds. Computed even when
3028
+ // autopilot is currently off — the toggle can flip ON mid-run, and the
3029
+ // gate reads the post-run value.
3030
+ const workflowCommand = attachments.length === 0 &&
3031
+ isWorkflowCommandText(text, await loadWorkflowCommandSpecs());
3032
+ // Does this input actually expand into a persisted user message? Asked
3033
+ // of the session itself, because only it knows whether the command
3034
+ // resolves here (name/alias casing, custom `.gg/commands`, non-coder
3035
+ // agents that don't expand at all). A looser guess would anchor the
3036
+ // hint at +1 with no message to land on — decorating an unrelated
3037
+ // later bubble with the wrong `/name`.
3038
+ const expandsToTemplate = attachments.length === 0 && (await session.willExpandPromptTemplate(text));
3035
3039
  // Webview display hint for this prompt's user bubble (kenSent shimmer
3036
- // label / enhancer highlight segments). Anchored +1 so it attaches to
3037
- // the user message the prompt below is about to push. Queued prompts
3038
- // skip this (their position in the run is unpredictable).
3039
- if (meta && (meta.kenSent === true || Array.isArray(meta.enhancements))) {
3040
+ // label / enhancer highlight segments / the `/name` a command was typed
3041
+ // as). Anchored +1 so it attaches to the user message the prompt below
3042
+ // is about to push. Queued prompts skip this (their position in the run
3043
+ // is unpredictable).
3044
+ //
3045
+ // Recording the invocation matters because the agent persists the
3046
+ // EXPANDED template as the user message. Resume used to recover
3047
+ // `/name` by matching that body against the current templates, which
3048
+ // silently fails the moment a template is edited or reworded — the
3049
+ // reopened session then rendered the raw multi-KB prompt instead of
3050
+ // the command chip.
3051
+ if (expandsToTemplate ||
3052
+ (meta && (meta.kenSent === true || Array.isArray(meta.enhancements)))) {
3040
3053
  void session
3041
3054
  .persistAppMarker("user_hint", {
3042
- ...(meta.kenSent === true ? { kenSent: true } : {}),
3043
- ...(Array.isArray(meta.enhancements) ? { enhancements: meta.enhancements } : {}),
3055
+ ...(expandsToTemplate ? { command: text.trim() } : {}),
3056
+ ...(meta?.kenSent === true ? { kenSent: true } : {}),
3057
+ ...(Array.isArray(meta?.enhancements) ? { enhancements: meta.enhancements } : {}),
3044
3058
  }, 1)
3045
3059
  .catch(() => { });
3046
3060
  }
@@ -3051,13 +3065,6 @@ async function createSession(deps, opts) {
3051
3065
  // feedback, anything) supersedes the pending plan — the bump also
3052
3066
  // invalidates any in-flight Ken plan review.
3053
3067
  clearPendingPlan();
3054
- // Gate inputs captured around the run: whether this turn is a workflow
3055
- // slash command (attachment prompts skip slash expansion entirely), and
3056
- // how many assistant messages the run actually adds. Computed even when
3057
- // autopilot is currently off — the toggle can flip ON mid-run, and the
3058
- // gate reads the post-run value.
3059
- const workflowCommand = attachments.length === 0 &&
3060
- isWorkflowCommandText(text, await loadWorkflowCommandSpecs());
3061
3068
  const assistantsBefore = countAssistantMessages(session.getMessages());
3062
3069
  const messagesBefore = session.getMessages().length;
3063
3070
  await runAgent(text, async () => {
@@ -3571,6 +3578,33 @@ async function createSession(deps, opts) {
3571
3578
  });
3572
3579
  return;
3573
3580
  }
3581
+ // Import a Claude Code / Codex / Cursor transcript into a resumable GG
3582
+ // Coder session. The importer never throws — it returns a typed failure so
3583
+ // the app can show the reason verbatim.
3584
+ if (method === "POST" && url === "/import-transcript") {
3585
+ void readBody(req, res).then(async (raw) => {
3586
+ if (raw === null)
3587
+ return;
3588
+ let body;
3589
+ try {
3590
+ body = JSON.parse(raw);
3591
+ }
3592
+ catch {
3593
+ json(res, 400, { error: "invalid JSON body" });
3594
+ return;
3595
+ }
3596
+ const filePath = body.path?.trim();
3597
+ if (!filePath) {
3598
+ json(res, 400, { error: "missing transcript path" });
3599
+ return;
3600
+ }
3601
+ const result = await session.importForeignTranscript(filePath, {
3602
+ ...(body.cwd ? { cwd: body.cwd } : {}),
3603
+ });
3604
+ json(res, result.ok ? 200 : 400, result);
3605
+ });
3606
+ return;
3607
+ }
3574
3608
  if (method === "POST" && url === "/thinking") {
3575
3609
  const st = session.getState();
3576
3610
  const next = getNextThinkingLevel(st.provider, st.model, session.getThinkingLevel());