@kenkaiiii/ggcoder 5.72.0 → 5.74.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 (94) hide show
  1. package/assets/skills/refactoring/SKILL.md +3 -1
  2. package/dist/app-error.d.ts +21 -0
  3. package/dist/app-error.js +39 -0
  4. package/dist/app-error.js.map +1 -0
  5. package/dist/app-sidecar.js +39 -35
  6. package/dist/app-sidecar.js.map +1 -1
  7. package/dist/core/agent-session.d.ts +2 -2
  8. package/dist/core/agent-session.js +17 -7
  9. package/dist/core/agent-session.js.map +1 -1
  10. package/dist/core/checklist-detection.d.ts +11 -0
  11. package/dist/core/checklist-detection.js +238 -0
  12. package/dist/core/checklist-detection.js.map +1 -0
  13. package/dist/core/checklist-items.d.ts +180 -0
  14. package/dist/core/checklist-items.js +204 -0
  15. package/dist/core/checklist-items.js.map +1 -0
  16. package/dist/core/checklist-prompt.d.ts +3 -0
  17. package/dist/core/checklist-prompt.js +34 -0
  18. package/dist/core/checklist-prompt.js.map +1 -0
  19. package/dist/core/checklist-snapshot.d.ts +13 -0
  20. package/dist/core/checklist-snapshot.js +29 -0
  21. package/dist/core/checklist-snapshot.js.map +1 -0
  22. package/dist/core/checklist-store.d.ts +59 -0
  23. package/dist/core/checklist-store.js +242 -0
  24. package/dist/core/checklist-store.js.map +1 -0
  25. package/dist/core/compaction/compactor.js +6 -0
  26. package/dist/core/compaction/compactor.js.map +1 -1
  27. package/dist/core/ken-context.js +7 -3
  28. package/dist/core/ken-context.js.map +1 -1
  29. package/dist/core/lsp/client.d.ts +4 -0
  30. package/dist/core/lsp/client.js +71 -3
  31. package/dist/core/lsp/client.js.map +1 -1
  32. package/dist/core/lsp/manager.d.ts +1 -0
  33. package/dist/core/lsp/manager.js +9 -3
  34. package/dist/core/lsp/manager.js.map +1 -1
  35. package/dist/core/lsp/project-root.d.ts +9 -0
  36. package/dist/core/lsp/project-root.js +75 -0
  37. package/dist/core/lsp/project-root.js.map +1 -0
  38. package/dist/core/lsp/reference-project.d.ts +6 -0
  39. package/dist/core/lsp/reference-project.js +110 -0
  40. package/dist/core/lsp/reference-project.js.map +1 -0
  41. package/dist/core/lsp/servers.js +1 -0
  42. package/dist/core/lsp/servers.js.map +1 -1
  43. package/dist/core/subagent-receipt.js +3 -1
  44. package/dist/core/subagent-receipt.js.map +1 -1
  45. package/dist/modes/acp-mode.d.ts +2 -1
  46. package/dist/modes/acp-mode.js +4 -1
  47. package/dist/modes/acp-mode.js.map +1 -1
  48. package/dist/motion-agent/motion-review-session.js +7 -3
  49. package/dist/motion-agent/motion-review-session.js.map +1 -1
  50. package/dist/system-prompt.js +14 -13
  51. package/dist/system-prompt.js.map +1 -1
  52. package/dist/tools/bash.d.ts +4 -1
  53. package/dist/tools/bash.js +32 -7
  54. package/dist/tools/bash.js.map +1 -1
  55. package/dist/tools/checklist.d.ts +56 -0
  56. package/dist/tools/checklist.js +178 -0
  57. package/dist/tools/checklist.js.map +1 -0
  58. package/dist/tools/code-nav.d.ts +1 -1
  59. package/dist/tools/code-nav.js +3 -2
  60. package/dist/tools/code-nav.js.map +1 -1
  61. package/dist/tools/edit-targets.d.ts +10 -0
  62. package/dist/tools/edit-targets.js +31 -0
  63. package/dist/tools/edit-targets.js.map +1 -0
  64. package/dist/tools/edit.d.ts +11 -3
  65. package/dist/tools/edit.js +386 -312
  66. package/dist/tools/edit.js.map +1 -1
  67. package/dist/tools/exit-plan.d.ts +2 -2
  68. package/dist/tools/exit-plan.js +7 -1
  69. package/dist/tools/exit-plan.js.map +1 -1
  70. package/dist/tools/index.d.ts +3 -2
  71. package/dist/tools/index.js +3 -0
  72. package/dist/tools/index.js.map +1 -1
  73. package/dist/tools/prompt-hints.js +3 -1
  74. package/dist/tools/prompt-hints.js.map +1 -1
  75. package/dist/tools/skill.js +6 -3
  76. package/dist/tools/skill.js.map +1 -1
  77. package/dist/tools/subagent.js +2 -1
  78. package/dist/tools/subagent.js.map +1 -1
  79. package/dist/tools/tool-tiers.js +1 -0
  80. package/dist/tools/tool-tiers.js.map +1 -1
  81. package/dist/tools/verification-review.d.ts +2 -0
  82. package/dist/tools/verification-review.js +41 -0
  83. package/dist/tools/verification-review.js.map +1 -0
  84. package/dist/ui/components/ToolExecution.js +3 -2
  85. package/dist/ui/components/ToolExecution.js.map +1 -1
  86. package/dist/ui/terminal-history.js +3 -1
  87. package/dist/ui/terminal-history.js.map +1 -1
  88. package/dist/ui/tool-line-summary.js +14 -2
  89. package/dist/ui/tool-line-summary.js.map +1 -1
  90. package/dist/ui/transcript/tool-presentation.js +1 -1
  91. package/dist/ui/transcript/tool-presentation.js.map +1 -1
  92. package/dist/utils/format.js +5 -1
  93. package/dist/utils/format.js.map +1 -1
  94. package/package.json +4 -4
@@ -1,11 +1,13 @@
1
1
  ---
2
2
  name: refactoring
3
- description: Use when restructuring existing code without changing behavior — "refactor", "clean up", "reduce duplication", "split this god class", "modernize", migrating legacy code or APIs (strangler fig, parallel change, codemods across many files, callback→async), planning a refactor, or mid-build when a change needs preparatory restructuring first. Two hats, test-guarded steps, revert-on-red. Do NOT use for new features, bug fixes (stubborn ones: root-cause), performance tuning (lean), schema/data migrations (durable), styling or copy, the refactor step of a user-requested TDD flow (tdd), or a from-scratch rewrite.
3
+ description: Use for behavior-preserving restructuring: extract, move, split, deduplicate, plan a refactor, or migrate an implementation behind an unchanged contract. Baseline tests, small steps, revert-on-red. Do NOT use for requested behavior or API-contract changes (including new return/error semantics), even when called a "refactor"; use the normal implementation workflow with regression tests and update affected callers together. Also exclude bug fixes (root-cause when stubborn), performance work (lean), data migrations (durable), styling/copy, TDD's refactor step (tdd), and rewrites.
4
4
  license: Behavior-preservation methodology synthesized from public sources (Fowler's Refactoring catalog, Tidy First?, and community agent skills by bienhoang, wondelai, mattpocock, jeffallan, vasilyu1983), audited 2026-09-12.
5
5
  ---
6
6
 
7
7
  # Refactoring
8
8
 
9
+ **Scope gate:** Decide from the requested behavior, not the word "refactor". A requested change to return values, error handling, or an API contract is implementation work, not a behavior-preserving cleanup. Use the normal implementation workflow: inspect the affected callers, make the requested contract and caller changes together, add regression coverage, and run the checks. Do not manufacture a separate pure-rename stage merely to enter this skill. Existing authorization and safety controls still apply. For a genuine behavior-preserving refactor, use the gated loop below unchanged.
10
+
9
11
  **Route first:**
10
12
 
11
13
  | Situation | Mode | Next |
@@ -0,0 +1,21 @@
1
+ import { z } from "zod";
2
+ import { type FormattedChatError } from "@kenkaiiii/gg-ai";
3
+ declare const appErrorSchema: z.ZodObject<{
4
+ scope: z.ZodDefault<z.ZodString>;
5
+ headline: z.ZodString;
6
+ message: z.ZodCatch<z.ZodOptional<z.ZodString>>;
7
+ guidance: z.ZodCatch<z.ZodOptional<z.ZodString>>;
8
+ reason: z.ZodCatch<z.ZodOptional<z.ZodString>>;
9
+ source: z.ZodCatch<z.ZodOptional<z.ZodString>>;
10
+ provider: z.ZodCatch<z.ZodOptional<z.ZodString>>;
11
+ statusCode: z.ZodCatch<z.ZodOptional<z.ZodNumber>>;
12
+ requestId: z.ZodCatch<z.ZodOptional<z.ZodString>>;
13
+ occurredAt: z.ZodCatch<z.ZodOptional<z.ZodNumber>>;
14
+ resetsAt: z.ZodCatch<z.ZodOptional<z.ZodNumber>>;
15
+ }, z.core.$strip>;
16
+ export type AppErrorPayload = z.infer<typeof appErrorSchema>;
17
+ /** The same sanitized snapshot goes to SSE and the append-only history marker. */
18
+ export declare function createAppErrorPayload(error: FormattedChatError, scope: string, occurredAt: number, secrets: Iterable<string>): AppErrorPayload;
19
+ /** Backward-compatible read: no migration or reclassification of old saved text. */
20
+ export declare function restoreAppErrorPayload(value: unknown): AppErrorPayload | undefined;
21
+ export {};
@@ -0,0 +1,39 @@
1
+ import { z } from "zod";
2
+ import { redactValue } from "@kenkaiiii/gg-ai";
3
+ const timestamp = z.number().int().nonnegative().max(8_640_000_000_000).optional().catch(undefined);
4
+ const optionalText = z.string().max(8_000).optional().catch(undefined);
5
+ const appErrorSchema = z.object({
6
+ scope: z.string().max(80).default("error"),
7
+ headline: z.string().min(1).max(1_000),
8
+ message: optionalText,
9
+ guidance: optionalText,
10
+ reason: z.string().max(40).optional().catch(undefined),
11
+ source: z.string().max(40).optional().catch(undefined),
12
+ provider: z.string().max(80).optional().catch(undefined),
13
+ statusCode: z.number().int().min(100).max(599).optional().catch(undefined),
14
+ requestId: z.string().max(300).optional().catch(undefined),
15
+ occurredAt: timestamp,
16
+ resetsAt: timestamp,
17
+ });
18
+ /** The same sanitized snapshot goes to SSE and the append-only history marker. */
19
+ export function createAppErrorPayload(error, scope, occurredAt, secrets) {
20
+ return redactValue({
21
+ scope,
22
+ headline: error.headline,
23
+ message: error.message,
24
+ guidance: error.guidance,
25
+ reason: error.reason,
26
+ source: error.source,
27
+ provider: error.provider,
28
+ statusCode: error.statusCode,
29
+ requestId: error.requestId,
30
+ occurredAt,
31
+ resetsAt: error.resetsAt,
32
+ }, { secrets, maxStringLength: 8_000 });
33
+ }
34
+ /** Backward-compatible read: no migration or reclassification of old saved text. */
35
+ export function restoreAppErrorPayload(value) {
36
+ const parsed = appErrorSchema.safeParse(value);
37
+ return parsed.success ? parsed.data : undefined;
38
+ }
39
+ //# sourceMappingURL=app-error.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app-error.js","sourceRoot":"","sources":["../src/app-error.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,WAAW,EAA2B,MAAM,kBAAkB,CAAC;AAExE,MAAM,SAAS,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC,QAAQ,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;AACpG,MAAM,YAAY,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,QAAQ,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;AACvE,MAAM,cAAc,GAAG,CAAC,CAAC,MAAM,CAAC;IAC9B,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC;IAC1C,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC;IACtC,OAAO,EAAE,YAAY;IACrB,QAAQ,EAAE,YAAY;IACtB,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC;IACtD,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC;IACtD,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC;IACxD,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC;IAC1E,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC;IAC1D,UAAU,EAAE,SAAS;IACrB,QAAQ,EAAE,SAAS;CACpB,CAAC,CAAC;AAGH,kFAAkF;AAClF,MAAM,UAAU,qBAAqB,CACnC,KAAyB,EACzB,KAAa,EACb,UAAkB,EAClB,OAAyB;IAEzB,OAAO,WAAW,CAChB;QACE,KAAK;QACL,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,UAAU,EAAE,KAAK,CAAC,UAAU;QAC5B,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,UAAU;QACV,QAAQ,EAAE,KAAK,CAAC,QAAQ;KACzB,EACD,EAAE,OAAO,EAAE,eAAe,EAAE,KAAK,EAAE,CACpC,CAAC;AACJ,CAAC;AAED,oFAAoF;AACpF,MAAM,UAAU,sBAAsB,CAAC,KAAc;IACnD,MAAM,MAAM,GAAG,cAAc,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IAC/C,OAAO,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;AAClD,CAAC"}
@@ -19,7 +19,8 @@ import path from "node:path";
19
19
  import { randomUUID } from "node:crypto";
20
20
  import { parseArgs } from "node:util";
21
21
  import { spawn } from "node:child_process";
22
- import { environmentSecrets, formatError, redactValue, } from "@kenkaiiii/gg-ai";
22
+ import { environmentSecrets, formatChatError, redactValue, } from "@kenkaiiii/gg-ai";
23
+ import { createAppErrorPayload, restoreAppErrorPayload, } from "./app-error.js";
23
24
  import { runJsonMode } from "./modes/json-mode.js";
24
25
  import { runSubagentWorkerMode } from "./modes/subagent-worker-mode.js";
25
26
  import { setStreamDiagnostic } from "@kenkaiiii/gg-agent";
@@ -68,6 +69,7 @@ import { loadCustomCommands } from "./core/custom-commands.js";
68
69
  import { discoverProjects } from "./core/project-discovery.js";
69
70
  import { listSidecarSessions } from "./app-sidecar-sessions.js";
70
71
  import { loadTasksSync, saveTasksSync, pruneDoneTasksSync, getNextPendingTask, markTaskInProgress, } from "./core/tasks-store.js";
72
+ import { readChecklistSnapshot } from "./core/checklist-snapshot.js";
71
73
  import { initLogger, log } from "./core/logger.js";
72
74
  import { installTerminationHandlers } from "./core/shutdown.js";
73
75
  import { KeepAwake } from "./core/keep-awake.js";
@@ -1319,35 +1321,21 @@ async function createSession(deps, opts) {
1319
1321
  // `400 {"code":"400",...}` with no "is this me or them / when does it reset"
1320
1322
  // context that the CLI has always given.
1321
1323
  function broadcastError(type, logLabel, err) {
1322
- const f = formatError(err);
1324
+ const f = formatChatError(err);
1323
1325
  const message = f.message ? desktopGuidance(f.message) : undefined;
1324
1326
  const guidance = localNetworkGuidance(f.source) ?? desktopGuidance(f.guidance);
1327
+ const payload = createAppErrorPayload({ ...f, ...(message ? { message } : {}), guidance }, type, Date.now(), environmentSecrets(process.env));
1325
1328
  log("ERROR", "app-sidecar", logLabel, {
1326
- headline: f.headline,
1329
+ headline: payload.headline,
1327
1330
  source: f.source,
1328
- ...(message ? { message } : {}),
1329
- ...(f.provider ? { provider: f.provider } : {}),
1330
- ...(f.statusCode != null ? { statusCode: String(f.statusCode) } : {}),
1331
- ...(f.requestId ? { requestId: f.requestId } : {}),
1331
+ ...(payload.message ? { message: payload.message } : {}),
1332
+ ...(payload.provider ? { provider: payload.provider } : {}),
1333
+ ...(payload.statusCode != null ? { statusCode: String(payload.statusCode) } : {}),
1334
+ ...(payload.requestId ? { requestId: payload.requestId } : {}),
1332
1335
  });
1333
- broadcast(type, {
1334
- headline: f.headline,
1335
- ...(message ? { message } : {}),
1336
- guidance,
1337
- ...(f.provider ? { provider: f.provider } : {}),
1338
- ...(f.statusCode != null ? { statusCode: f.statusCode } : {}),
1339
- ...(f.resetsAt != null ? { resetsAt: f.resetsAt } : {}),
1340
- });
1341
- // Persist the error row (display-only marker) so a resumed session shows
1342
- // the same headline/message/guidance the live run did. Best-effort.
1343
- void session
1344
- .persistAppMarker("error", {
1345
- scope: type,
1346
- headline: f.headline,
1347
- ...(message ? { message } : {}),
1348
- guidance,
1349
- })
1350
- .catch(() => { });
1336
+ broadcast(type, payload);
1337
+ // Same sanitized snapshot for live and restored rows, including reset metadata.
1338
+ void session.persistAppMarker("error", payload).catch(() => { });
1351
1339
  }
1352
1340
  // ── MCP elicitation bridge ─────────────────────────────────
1353
1341
  // An MCP server can ask for user input in the middle of a tool call. The
@@ -3412,16 +3400,9 @@ async function createSession(deps, opts) {
3412
3400
  });
3413
3401
  }
3414
3402
  else if (marker.kind === "error" && typeof d.headline === "string") {
3415
- history.push({
3416
- role: "assistant",
3417
- text: "",
3418
- error: {
3419
- scope: typeof d.scope === "string" ? d.scope : "error",
3420
- headline: d.headline,
3421
- ...(typeof d.message === "string" ? { message: d.message } : {}),
3422
- ...(typeof d.guidance === "string" ? { guidance: d.guidance } : {}),
3423
- },
3424
- });
3403
+ const error = restoreAppErrorPayload(d);
3404
+ if (error)
3405
+ history.push({ role: "assistant", text: "", error });
3425
3406
  }
3426
3407
  else if (marker.kind === "interrupted_run") {
3427
3408
  // Rendered as an error row: the run's tools already changed the
@@ -3968,6 +3949,29 @@ async function createSession(deps, opts) {
3968
3949
  json(res, 200, { tasks: pruneDoneTasksSync(cwd) });
3969
3950
  return;
3970
3951
  }
3952
+ if (method === "GET" && url === "/checklist") {
3953
+ const controller = new AbortController();
3954
+ res.once("close", () => controller.abort());
3955
+ void (async () => {
3956
+ try {
3957
+ const result = await readChecklistSnapshot(cwd, new Date(), controller.signal);
3958
+ if (res.destroyed)
3959
+ return;
3960
+ if (!result.ok) {
3961
+ log("WARN", "app-sidecar", "checklist read failed", { error: result.error });
3962
+ json(res, 500, { error: result.error });
3963
+ return;
3964
+ }
3965
+ json(res, 200, result.value);
3966
+ }
3967
+ catch (error) {
3968
+ log("WARN", "app-sidecar", "checklist snapshot failed", { error: String(error) });
3969
+ if (!res.destroyed)
3970
+ json(res, 500, { error: "Could not read the project checklist" });
3971
+ }
3972
+ })();
3973
+ return;
3974
+ }
3971
3975
  // ── Radio (app-wide) ──────────────────────────────────────
3972
3976
  // Radio is now APP-WIDE: all windows share one daemon process, and the
3973
3977
  // player lives in `core/radio.ts` module-level singletons (one stream for