@kenkaiiii/ggcoder 5.68.1 → 5.69.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 (76) hide show
  1. package/dist/app-sidecar.js +26 -11
  2. package/dist/app-sidecar.js.map +1 -1
  3. package/dist/cli.js +15 -14
  4. package/dist/cli.js.map +1 -1
  5. package/dist/core/agent-session.d.ts +17 -0
  6. package/dist/core/agent-session.js +77 -0
  7. package/dist/core/agent-session.js.map +1 -1
  8. package/dist/core/cache-diagnostics.d.ts +6 -0
  9. package/dist/core/cache-diagnostics.js +31 -0
  10. package/dist/core/cache-diagnostics.js.map +1 -1
  11. package/dist/core/cache-expiry.d.ts +87 -0
  12. package/dist/core/cache-expiry.js +111 -0
  13. package/dist/core/cache-expiry.js.map +1 -0
  14. package/dist/core/destructive-git-guard.d.ts +27 -0
  15. package/dist/core/destructive-git-guard.js +94 -54
  16. package/dist/core/destructive-git-guard.js.map +1 -1
  17. package/dist/core/injection-detect.d.ts +38 -0
  18. package/dist/core/injection-detect.js +232 -0
  19. package/dist/core/injection-detect.js.map +1 -0
  20. package/dist/core/mcp/client.d.ts +72 -0
  21. package/dist/core/mcp/client.js +264 -41
  22. package/dist/core/mcp/client.js.map +1 -1
  23. package/dist/core/mcp/store.d.ts +6 -1
  24. package/dist/core/mcp/store.js +12 -1
  25. package/dist/core/mcp/store.js.map +1 -1
  26. package/dist/core/mcp/types.d.ts +18 -0
  27. package/dist/core/persistent-shell.d.ts +58 -6
  28. package/dist/core/persistent-shell.js +331 -49
  29. package/dist/core/persistent-shell.js.map +1 -1
  30. package/dist/core/progress/git-xp.js +8 -14
  31. package/dist/core/progress/git-xp.js.map +1 -1
  32. package/dist/core/subagent-manager.d.ts +9 -0
  33. package/dist/core/subagent-manager.js +7 -1
  34. package/dist/core/subagent-manager.js.map +1 -1
  35. package/dist/core/subagent-receipt.d.ts +54 -0
  36. package/dist/core/subagent-receipt.js +276 -0
  37. package/dist/core/subagent-receipt.js.map +1 -0
  38. package/dist/core/subagent-turn-record.d.ts +2 -0
  39. package/dist/core/subagent-turn-record.js.map +1 -1
  40. package/dist/core/verification-snapshot.js +3 -5
  41. package/dist/core/verification-snapshot.js.map +1 -1
  42. package/dist/core/workspace-guard.d.ts +18 -7
  43. package/dist/core/workspace-guard.js +227 -60
  44. package/dist/core/workspace-guard.js.map +1 -1
  45. package/dist/modes/subagent-worker-mode.js +18 -2
  46. package/dist/modes/subagent-worker-mode.js.map +1 -1
  47. package/dist/tools/bash.js +12 -4
  48. package/dist/tools/bash.js.map +1 -1
  49. package/dist/tools/read.js +3 -2
  50. package/dist/tools/read.js.map +1 -1
  51. package/dist/tools/steroids.d.ts +1 -1
  52. package/dist/tools/subagent-control.js +34 -6
  53. package/dist/tools/subagent-control.js.map +1 -1
  54. package/dist/tools/subagent-shared.d.ts +13 -0
  55. package/dist/tools/subagent-shared.js +25 -0
  56. package/dist/tools/subagent-shared.js.map +1 -1
  57. package/dist/tools/subagent.js +14 -3
  58. package/dist/tools/subagent.js.map +1 -1
  59. package/dist/tools/task-output.js +3 -2
  60. package/dist/tools/task-output.js.map +1 -1
  61. package/dist/tools/truncate.d.ts +21 -0
  62. package/dist/tools/truncate.js +187 -0
  63. package/dist/tools/truncate.js.map +1 -1
  64. package/dist/tools/ui-adopt.js +2 -0
  65. package/dist/tools/ui-adopt.js.map +1 -1
  66. package/dist/utils/git.d.ts +77 -0
  67. package/dist/utils/git.js +285 -21
  68. package/dist/utils/git.js.map +1 -1
  69. package/dist/utils/github-ci.js +2 -1
  70. package/dist/utils/github-ci.js.map +1 -1
  71. package/dist/utils/github.js +11 -9
  72. package/dist/utils/github.js.map +1 -1
  73. package/dist/utils/process.d.ts +20 -0
  74. package/dist/utils/process.js +98 -0
  75. package/dist/utils/process.js.map +1 -1
  76. package/package.json +4 -4
@@ -58,4 +58,191 @@ export function truncateTail(content, maxLines = MAX_LINES, maxBytes = MAX_BYTES
58
58
  keptLines: kept.length,
59
59
  };
60
60
  }
61
+ /* ----------------------------------------------------------------------- */
62
+ /* "What was cut" descriptor for truncation notes */
63
+ /* ----------------------------------------------------------------------- */
64
+ /** Hard cap on the descriptor appended to a truncation note. */
65
+ export const OMITTED_NOTE_MAX_CHARS = 300;
66
+ const SAMPLE_MAX_CHARS = 80;
67
+ const MAX_SAMPLES = 3;
68
+ const MAX_LABELS = 3;
69
+ const MAX_FILES = 3;
70
+ /** Cheap gate: a line that can't contain any of these is never error/warn-shaped. */
71
+ const DIAG_PREFILTER = /err|fail|fatal|panic|exception|traceback|crit|warn|caused by|not ok|[✗✖❌×]/i;
72
+ // Optional leading timestamp / [bracketed] prefix before an UPPERCASE log level.
73
+ const LOG_PREFIX = String.raw `^\W{0,4}(?:[\d\-/:.,TZ+]+\s+|\[[^\]]{1,40}\]\s*)*`;
74
+ const LEVEL_END = String.raw `(?=[\s:\]!|]|$)(?!\s*[=,;)])`;
75
+ /**
76
+ * Shape-based (not keyword-based) error-line detectors, so source code being
77
+ * paged through by `read` (`throw new Error(...)`, `console.error(...)`) does
78
+ * not count — only lines that look like a diagnostic / log record.
79
+ */
80
+ const ERROR_LINE = [
81
+ new RegExp(`${LOG_PREFIX}(?:ERROR|ERR!|FATAL|CRITICAL|PANIC|FAIL(?:ED|URE)?)${LEVEL_END}`),
82
+ /^(?:error|fatal)(?:\[[\w-]+\])?:\s/i, // rustc/cargo/git/CLI `error: …` (column 0)
83
+ /^npm ERR!/,
84
+ /\.\w{1,6}(?::\d+){1,2}:?\s*(?:fatal\s+)?error\b/i, // gcc/clang `f.c:1:2: error:`
85
+ /\(\d+,\d+\):\s*error\b/, // tsc `f.ts(1,2): error TS…`
86
+ /^\s*\d+:\d+\s+error\s/, // eslint stylish
87
+ /^\s*(?:E\s+)?(?:Uncaught\s+)?[A-Z][\w.$]*(?:Error|Exception)(?:\s*\[[\w-]+\])?:(?:\s|$)/,
88
+ /^Traceback \(most recent call last\)/,
89
+ /^\s*(?:✗|✖|❌|not ok\b|--- FAIL\b)/,
90
+ /^thread '.*' panicked|^panic:/,
91
+ /^\s*Caused by:/,
92
+ /\blevel[=:]\s*"?(?:error|fatal)\b/i,
93
+ ];
94
+ const WARN_LINE = [
95
+ new RegExp(`${LOG_PREFIX}(?:WARN(?:ING)?)${LEVEL_END}`),
96
+ /^warn(?:ing)?(?:\[[\w-]+\])?:\s/i,
97
+ /^npm WARN\b/,
98
+ /\.\w{1,6}(?::\d+){1,2}:?\s*warning\b/i,
99
+ /\(\d+,\d+\):\s*warning\b/,
100
+ /^\s*\d+:\d+\s+warning\s/,
101
+ /^\s*[A-Z]\w*Warning:\s/,
102
+ /\blevel[=:]\s*"?warn(?:ing)?\b/i,
103
+ ];
104
+ /** Error codes / exception names (headroom #3635's "exception types"). */
105
+ const LABEL_RES = [
106
+ /\berror\[([A-Z]?\d{3,5})\]/, // rustc E0425
107
+ /\berror\s+(TS\d{3,5})\b/, // tsc TS2345
108
+ /^\s*(?:E\s+)?(?:Uncaught\s+)?(?:[\w$]+\.)*([A-Z][\w$]*(?:Error|Exception|Warning))\b(?:\s*\[[\w-]+\])?:/,
109
+ /\b(E(?:NOENT|ACCES|PERM|ADDRINUSE|CONNREFUSED|CONNRESET|TIMEDOUT|EXIST|ISDIR|NOTDIR|NOTEMPTY|MFILE|PIPE|NOTFOUND|HOSTUNREACH)|ERR_[A-Z0-9_]{3,})\b/,
110
+ ];
111
+ const SRC_EXT = "ts|tsx|js|jsx|mjs|cjs|mts|cts|py|rs|go|java|kt|kts|rb|php|c|h|cc|cpp|cxx|hpp|cs|swift|m|mm|scala|ex|exs|erl|hs|ml|lua|sh|vue|svelte|json|ya?ml|toml|css|scss|less|html|sql|proto|zig|dart";
112
+ /** A source path followed by a line location: `a/b.ts:12`, `b.ts(3,4)`. */
113
+ const FILE_LOC = new RegExp(String.raw `(?:^|[\s(\["'\`])((?:[\w.@~+-]*/)*[\w@+-][\w.@+-]*\.(?:${SRC_EXT}))(?::\d+|\(\d+,\d+\))`);
114
+ const PY_FILE = /File "([^"]+)", line \d+/;
115
+ const RUST_FILE = /-->\s*([^\s:]+):\d+/;
116
+ /** Lines whose file references are diagnostic (stack frames, locations). */
117
+ const FRAME_LINE = new RegExp(String.raw `^\s*(?:at\s|File "|-->|from\s)|^\S+\.(?:${SRC_EXT})(?::\d+|\(\d+,\d+\))`);
118
+ /** Object-literal / call-argument continuation lines in source code. */
119
+ const CODE_TAIL = /[,{([]\s*$/;
120
+ function isError(line) {
121
+ return (DIAG_PREFILTER.test(line) && !CODE_TAIL.test(line) && ERROR_LINE.some((re) => re.test(line)));
122
+ }
123
+ function isWarning(line) {
124
+ return (DIAG_PREFILTER.test(line) && !CODE_TAIL.test(line) && WARN_LINE.some((re) => re.test(line)));
125
+ }
126
+ function extractFile(line) {
127
+ return (PY_FILE.exec(line) ?? RUST_FILE.exec(line) ?? FILE_LOC.exec(line))?.[1];
128
+ }
129
+ function shorten(s, max) {
130
+ return s.length <= max ? s : `${s.slice(0, max - 1)}…`;
131
+ }
132
+ /** Last two path segments — enough to identify a file without eating the cap. */
133
+ function shortPath(p) {
134
+ const parts = p.split(/[\\/]/).filter(Boolean);
135
+ return parts.length <= 2 ? parts.join("/") : `…/${parts.slice(-2).join("/")}`;
136
+ }
137
+ function listWithMore(items, max) {
138
+ const shown = items.slice(0, max).join(", ");
139
+ return items.length > max ? `${shown}, +${items.length - max}` : shown;
140
+ }
141
+ /**
142
+ * Describe WHAT a truncation dropped, so the agent can decide whether to fetch
143
+ * the rest (modelled on headroomlabs-ai/headroom PR #3635's CCR descriptor):
144
+ * error/warning line counts, distinct error codes / exception names, distinct
145
+ * source files referenced by diagnostics/stack frames, and the first few
146
+ * distinct error lines. Labels, files and sample lines already visible in
147
+ * `shown` are left out — the note justifies retrieval, it doesn't restate.
148
+ *
149
+ * Returns `""` when nothing notable was cut (the note stays byte-identical),
150
+ * otherwise `"Omitted part: …."`, never longer than OMITTED_NOTE_MAX_CHARS.
151
+ * Deterministic: first-appearance order, no hashing or randomness.
152
+ */
153
+ export function describeOmitted(omitted, shown) {
154
+ let errors = 0;
155
+ let warnings = 0;
156
+ const labels = new Set();
157
+ const files = new Set();
158
+ const samples = [];
159
+ const sampleKeys = new Set();
160
+ // Everything already tested against `shown` (hit or miss) — each distinct
161
+ // candidate costs one substring scan, however often it repeats.
162
+ const checked = new Set();
163
+ const isNew = (s) => {
164
+ if (checked.has(s))
165
+ return false;
166
+ checked.add(s);
167
+ return !shown.includes(s);
168
+ };
169
+ for (const line of omitted) {
170
+ const err = isError(line);
171
+ const warn = !err && isWarning(line);
172
+ if (err)
173
+ errors++;
174
+ else if (warn)
175
+ warnings++;
176
+ if (err || warn) {
177
+ for (const re of LABEL_RES) {
178
+ const label = re.exec(line)?.[1];
179
+ if (label && isNew(label))
180
+ labels.add(label);
181
+ }
182
+ }
183
+ if (err || warn || FRAME_LINE.test(line)) {
184
+ const file = extractFile(line);
185
+ if (file && isNew(file))
186
+ files.add(file);
187
+ }
188
+ if (err && samples.length < MAX_SAMPLES) {
189
+ const text = line.trim().replace(/\s+/g, " ");
190
+ // Distinct modulo numbers, so a retry loop doesn't fill every slot.
191
+ const key = text.replace(/\d+/g, "#");
192
+ if (text && !sampleKeys.has(key) && isNew(line.trim())) {
193
+ sampleKeys.add(key);
194
+ samples.push(text);
195
+ }
196
+ }
197
+ }
198
+ if (errors === 0 && warnings === 0 && files.size === 0)
199
+ return "";
200
+ const parts = [];
201
+ if (errors || warnings) {
202
+ const plural = (n, what) => `${n} ${what} line${n === 1 ? "" : "s"}`;
203
+ const counts = [errors && plural(errors, "error"), warnings && plural(warnings, "warning")]
204
+ .filter(Boolean)
205
+ .join(", ");
206
+ const labelList = labels.size ? ` (${listWithMore([...labels], MAX_LABELS)})` : "";
207
+ parts.push(`${counts}${labelList}`);
208
+ }
209
+ if (files.size) {
210
+ const names = [...files].map(shortPath);
211
+ parts.push(`${files.size} file${files.size === 1 ? "" : "s"}: ${listWithMore(names, MAX_FILES)}`);
212
+ }
213
+ const head = `Omitted part: ${parts.join("; ")}`;
214
+ let note = `${head}.`;
215
+ // Add sample error lines while they fit under the hard cap.
216
+ const quoted = [];
217
+ for (const s of samples) {
218
+ const next = [...quoted, `"${shorten(s, SAMPLE_MAX_CHARS)}"`];
219
+ const candidate = `${head}; first: ${next.join(" | ")}.`;
220
+ if (candidate.length > OMITTED_NOTE_MAX_CHARS)
221
+ break;
222
+ quoted.push(next[next.length - 1]);
223
+ note = candidate;
224
+ }
225
+ return shorten(note, OMITTED_NOTE_MAX_CHARS);
226
+ }
227
+ /** Timestamps / hex addresses vary across "similar" repeats — ignore them. */
228
+ function looseKey(line) {
229
+ return line
230
+ .replace(/\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2}(?:\.\d+)?Z?/g, "")
231
+ .replace(/\b\d{2}:\d{2}:\d{2}(?:\.\d+)?\b/g, "")
232
+ .replace(/0x[0-9a-f]+/gi, "")
233
+ .trim();
234
+ }
235
+ /**
236
+ * `describeOmitted` for a non-positional cut (content-aware compression):
237
+ * the omitted lines are the original lines with no counterpart in `shown`.
238
+ * Repeats collapsed to `line (×N)` / `(×N similar)` count as shown.
239
+ */
240
+ export function describeCompressed(original, shown) {
241
+ const shownKeys = new Set();
242
+ for (const l of shown.split("\n")) {
243
+ shownKeys.add(looseKey(l.replace(/ {2}\(×\d+(?: similar)?\)$/, "")));
244
+ }
245
+ const omitted = original.split("\n").filter((l) => !shownKeys.has(looseKey(l)));
246
+ return describeOmitted(omitted, shown);
247
+ }
61
248
  //# sourceMappingURL=truncate.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"truncate.js","sourceRoot":"","sources":["../../src/tools/truncate.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,SAAS,GAAG,IAAI,CAAC;AAC9B,MAAM,CAAC,MAAM,SAAS,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,OAAO;AAE3C,sFAAsF;AACtF,MAAM,CAAC,MAAM,SAAS,GAAG,SAAS,CAAC;AASnC;;;GAGG;AACH,MAAM,UAAU,YAAY,CAC1B,OAAe,EACf,QAAQ,GAAG,SAAS,EACpB,QAAQ,GAAG,SAAS;IAEpB,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAClC,MAAM,UAAU,GAAG,KAAK,CAAC,MAAM,CAAC;IAEhC,sBAAsB;IACtB,IAAI,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;IAEpC,sBAAsB;IACtB,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,IAAI,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC;IAC3B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,IAAI,IAAI,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,iBAAiB;QAClE,IAAI,IAAI,GAAG,QAAQ,EAAE,CAAC;YACpB,QAAQ,GAAG,CAAC,CAAC;YACb,MAAM;QACR,CAAC;IACH,CAAC;IACD,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;IAE/B,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,GAAG,UAAU,CAAC;IAC3C,OAAO;QACL,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;QACxB,SAAS;QACT,UAAU;QACV,SAAS,EAAE,IAAI,CAAC,MAAM;KACvB,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,YAAY,CAC1B,OAAe,EACf,QAAQ,GAAG,SAAS,EACpB,QAAQ,GAAG,SAAS;IAEpB,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAClC,MAAM,UAAU,GAAG,KAAK,CAAC,MAAM,CAAC;IAEhC,oCAAoC;IACpC,IAAI,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC;IAElC,0CAA0C;IAC1C,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,KAAK,IAAI,CAAC,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC1C,IAAI,IAAI,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC;QAChD,IAAI,IAAI,GAAG,QAAQ,EAAE,CAAC;YACpB,QAAQ,GAAG,CAAC,GAAG,CAAC,CAAC;YACjB,MAAM;QACR,CAAC;IACH,CAAC;IACD,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IAE5B,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,GAAG,UAAU,CAAC;IAC3C,OAAO;QACL,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;QACxB,SAAS;QACT,UAAU;QACV,SAAS,EAAE,IAAI,CAAC,MAAM;KACvB,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"truncate.js","sourceRoot":"","sources":["../../src/tools/truncate.ts"],"names":[],"mappings":"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"}
@@ -12,6 +12,8 @@ const params = z.object({
12
12
  export function createUiAdoptTool(cwd, registry, writer, planModeRef) {
13
13
  return {
14
14
  name: "ui_adopt",
15
+ // Apply writes several files; a steering message must not leave it half-done.
16
+ interruptible: false,
15
17
  description: "Plan then adopt real public Bklit/Kokonut registry source into an existing React project. Reports dependency closure, relocated imports, missing packages/styles, attribution and conflicts. Apply requires the unchanged plan hash, only creates new component files through normal write controls, and never installs packages or overwrites user files.",
16
18
  parameters: params,
17
19
  executionMode: "sequential",
@@ -1 +1 @@
1
- {"version":3,"file":"ui-adopt.js","sourceRoot":"","sources":["../../src/tools/ui-adopt.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ui-adopt.js","sourceRoot":"","sources":["../../src/tools/ui-adopt.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAEzE,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAE3D,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC;IACtB,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,sDAAsD,CAAC;IACxF,QAAQ,EAAE,CAAC;SACR,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CAAC,kEAAkE,CAAC;CAChF,CAAC,CAAC;AAEH,MAAM,UAAU,iBAAiB,CAC/B,GAAW,EACX,QAAoB,EACpB,MAA0C,EAC1C,WAAkC;IAElC,OAAO;QACL,IAAI,EAAE,UAAU;QAChB,8EAA8E;QAC9E,aAAa,EAAE,KAAK;QACpB,WAAW,EACT,4VAA4V;QAC9V,UAAU,EAAE,MAAM;QAClB,aAAa,EAAE,YAAY;QAC3B,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO;YACzB,MAAM,IAAI,GAAG,MAAM,YAAY,CAAC,GAAG,EAAE,QAAQ,EAAE,IAAI,CAAC,EAAE,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;YACxE,IAAI,IAAI,CAAC,MAAM,KAAK,MAAM;gBAAE,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;YACxD,IAAI,gBAAgB,CAAC,WAAW,CAAC;gBAC/B,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;YAChE,IAAI,CAAC,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,QAAQ,KAAK,IAAI,CAAC,IAAI;gBAC/C,MAAM,IAAI,KAAK,CAAC,wEAAwE,CAAC,CAAC;YAC5F,MAAM,iBAAiB,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;YACnC,MAAM,OAAO,GAAa,EAAE,CAAC;YAC7B,MAAM,OAAO,GAAa,EAAE,CAAC;YAC7B,IAAI,SAA6B,CAAC;YAClC,IAAI,CAAC;gBACH,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;oBAC9B,OAAO,CAAC,MAAM,CAAC,cAAc,EAAE,CAAC;oBAChC,IAAI,IAAI,CAAC,MAAM,KAAK,OAAO;wBAAE,SAAS;oBACtC,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC;oBACxB,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,OAAO,CACjC,EAAE,SAAS,EAAE,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,EACjD,OAAO,CACR,CAAC;oBACF,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC;wBAC3D,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;oBAClC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;oBAC1B,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;gBACvB,CAAC;YACH,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,OAAO,IAAI,CAAC,SAAS,CAAC;oBACpB,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC;oBACpB,OAAO;oBACP,SAAS;oBACT,OAAO,EAAE,IAAI;oBACb,YAAY,EACV,gIAAgI;iBACnI,CAAC,CAAC;YACL,CAAC;YACD,OAAO,IAAI,CAAC,SAAS,CAAC;gBACpB,OAAO;gBACP,OAAO;gBACP,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;gBAC3E,eAAe,EAAE,IAAI,CAAC,eAAe;gBACrC,MAAM,EAAE,IAAI,CAAC,MAAM;gBACnB,WAAW,EAAE,IAAI,CAAC,WAAW;gBAC7B,YAAY,EAAE,IAAI,CAAC,YAAY;aAChC,CAAC,CAAC;QACL,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -1,3 +1,80 @@
1
+ /** `-c` overrides that disable every repo-config execution sink GG's calls can reach. */
2
+ export declare const GIT_HARDENING_CONFIG_ARGS: readonly string[];
3
+ /**
4
+ * Inserted right after the subcommand of diff-producing commands: external
5
+ * diff drivers (`diff.external`, `diff.<driver>.command`) and `textconv`
6
+ * filters are repo-configured programs. `-c diff.external=` is NOT used — an
7
+ * empty value makes `git diff` die with "cannot run".
8
+ */
9
+ export declare const GIT_NO_EXTERNAL_DIFF_ARGS: readonly string[];
10
+ /**
11
+ * Inserted after `status`: inspecting a submodule's work tree spawns a nested
12
+ * `git status` inside it, which honours the submodule's OWN filter drivers
13
+ * (its config was never probed). `dirty` still reports moved submodule
14
+ * commits but never enters the submodule work tree. Skipped when the caller
15
+ * passes its own `--ignore-submodules`.
16
+ */
17
+ export declare const GIT_STATUS_SUBMODULE_ARGS: readonly string[];
18
+ /**
19
+ * Build `-c` overrides that blank every filter / merge driver named in the
20
+ * NUL-separated output of `git config -z --name-only --get-regexp`. Returns
21
+ * null when a driver name contains `=` — `-c` splits at the first `=`, so the
22
+ * override could not be expressed and the caller must refuse to run.
23
+ */
24
+ export declare function buildDriverOverrides(outputs: readonly string[]): string[] | null;
25
+ /**
26
+ * The git executable. On Windows, libuv's PATH search tries the child's cwd
27
+ * first, so a `git.exe` planted at a repo root would run instead of git —
28
+ * resolve an absolute path from PATH once instead.
29
+ */
30
+ export declare function resolveGitBinary(): string;
31
+ export interface BackgroundGitOptions {
32
+ cwd: string;
33
+ timeoutMs?: number;
34
+ maxBuffer?: number;
35
+ /** Written to stdin, which is then closed. */
36
+ input?: string;
37
+ signal?: AbortSignal;
38
+ /** Extra environment on top of `process.env` and the hardening env. */
39
+ env?: Readonly<Record<string, string>>;
40
+ /**
41
+ * Repo-selecting global options (`--git-dir=…`, `--work-tree=…`) placed
42
+ * before the subcommand — and before `config` in the driver probe, so it
43
+ * inspects the same repository.
44
+ */
45
+ globalArgs?: readonly string[];
46
+ }
47
+ export interface BackgroundGitResult {
48
+ stdout: string;
49
+ stderr: string;
50
+ }
51
+ /**
52
+ * Rejection of {@link runBackgroundGit}, shaped like a promisified execFile
53
+ * error: `code` is git's exit status (number) or a spawn errno (string).
54
+ */
55
+ export declare class BackgroundGitError extends Error {
56
+ readonly code: number | string | null;
57
+ readonly killed: boolean;
58
+ readonly stdout: string;
59
+ readonly stderr: string;
60
+ constructor(message: string, details: {
61
+ code: number | string | null;
62
+ killed: boolean;
63
+ stdout: string;
64
+ stderr: string;
65
+ });
66
+ }
67
+ /**
68
+ * Full argv for a hardened background git call (minus the binary). Exposed
69
+ * for tests; callers use {@link runBackgroundGit}.
70
+ */
71
+ export declare function hardenedGitArgs(args: readonly string[], options: BackgroundGitOptions): Promise<string[]>;
72
+ /**
73
+ * Run git for GG's own background purposes with repo-config execution sinks
74
+ * disabled. Resolves `{stdout, stderr}` on exit 0; rejects with
75
+ * {@link BackgroundGitError} otherwise. Output is identical to plain git.
76
+ */
77
+ export declare function runBackgroundGit(args: readonly string[], options: BackgroundGitOptions): Promise<BackgroundGitResult>;
1
78
  export declare function getGitBranch(cwd: string): Promise<string | null>;
2
79
  /** Count staged, modified, deleted, renamed, and untracked files. */
3
80
  export declare function getGitDirtyFileCount(cwd: string): Promise<number>;
package/dist/utils/git.js CHANGED
@@ -1,37 +1,301 @@
1
1
  import { execFile } from "node:child_process";
2
- export function getGitBranch(cwd) {
3
- return new Promise((resolve) => {
4
- execFile("git", ["rev-parse", "--abbrev-ref", "HEAD"], { cwd, timeout: 2000 }, (error, stdout) => {
5
- if (error) {
6
- resolve(null);
7
- return;
2
+ import { statSync } from "node:fs";
3
+ import path from "node:path";
4
+ // ── Hardened runner for GG's own (background) git calls ─────────────────────
5
+ //
6
+ // GitSpawn: a repository's own `.git/config` (or an `include.path` it pulls
7
+ // in) can name programs that git runs during perfectly ordinary read-only
8
+ // commands — `core.fsmonitor` on any index refresh, a `post-index-change` hook
9
+ // when `git status` rewrites the index, `filter.<driver>.clean/process` (with
10
+ // `.gitattributes`) when status re-hashes a stat-dirty file, `textconv` /
11
+ // external diff drivers in `git show`, `gpg.program` via `log.showSignature`,
12
+ // credential/ssh/askpass helpers, pagers and editors. GG runs git on its own
13
+ // (project open, CI chip, XP, verification snapshots, the destructive-git
14
+ // guard), so merely opening a malicious repo must not execute anything.
15
+ //
16
+ // Every background git call goes through {@link runBackgroundGit}, which
17
+ // prepends `-c` overrides (command-line config beats every config file) and
18
+ // blanks the per-driver filter/merge commands discovered by a safe
19
+ // `git config` probe. Prior art: gptme b65f699d (`git_inspect_cmd`) and
20
+ // MoonshotAI/kimi-code#3964 (`hardenedGitConfigArgs`). The agent's own `bash`
21
+ // tool is out of scope — those are explicit, user-visible commands.
22
+ const NULL_DEVICE = process.platform === "win32" ? "NUL" : "/dev/null";
23
+ /** `-c` overrides that disable every repo-config execution sink GG's calls can reach. */
24
+ export const GIT_HARDENING_CONFIG_ARGS = [
25
+ "-c",
26
+ "core.fsmonitor=false",
27
+ "-c",
28
+ `core.hooksPath=${NULL_DEVICE}`,
29
+ "-c",
30
+ "core.pager=cat",
31
+ "-c",
32
+ "core.editor=:",
33
+ "-c",
34
+ "core.askPass=",
35
+ // Plain OpenSSH: keeps any (rare) lazy fetch working without the repo's command.
36
+ "-c",
37
+ "core.sshCommand=ssh",
38
+ // An empty value resets the helper list, dropping repo-configured helpers.
39
+ "-c",
40
+ "credential.helper=",
41
+ // Background calls never need the network. A partial clone would otherwise
42
+ // lazy-fetch missing blobs (e.g. in `git show`) through the repo's own
43
+ // `remote.<name>.uploadpack` / ext:: URL; GIT_NO_LAZY_FETCH backs this up.
44
+ "-c",
45
+ "protocol.allow=never",
46
+ "-c",
47
+ "protocol.ext.allow=never",
48
+ "-c",
49
+ "gpg.program=",
50
+ "-c",
51
+ "log.showSignature=false",
52
+ "-c",
53
+ "commit.gpgSign=false",
54
+ "-c",
55
+ "tag.gpgSign=false",
56
+ "-c",
57
+ "merge.verifySignatures=false",
58
+ "-c",
59
+ "submodule.recurse=false",
60
+ ];
61
+ /**
62
+ * Inserted right after the subcommand of diff-producing commands: external
63
+ * diff drivers (`diff.external`, `diff.<driver>.command`) and `textconv`
64
+ * filters are repo-configured programs. `-c diff.external=` is NOT used — an
65
+ * empty value makes `git diff` die with "cannot run".
66
+ */
67
+ export const GIT_NO_EXTERNAL_DIFF_ARGS = ["--no-ext-diff", "--no-textconv"];
68
+ const DIFF_FAMILY = new Set(["diff", "show", "log"]);
69
+ /**
70
+ * Inserted after `status`: inspecting a submodule's work tree spawns a nested
71
+ * `git status` inside it, which honours the submodule's OWN filter drivers
72
+ * (its config was never probed). `dirty` still reports moved submodule
73
+ * commits but never enters the submodule work tree. Skipped when the caller
74
+ * passes its own `--ignore-submodules`.
75
+ */
76
+ export const GIT_STATUS_SUBMODULE_ARGS = ["--ignore-submodules=dirty"];
77
+ /**
78
+ * Subcommands that never hash or check out work-tree content, so no
79
+ * clean/smudge/process filter can run — the per-driver probe is skipped.
80
+ */
81
+ const NO_FILTER_SUBCOMMANDS = new Set(["rev-parse", "remote", "rev-list", "patch-id", "show"]);
82
+ const PROBE_TIMEOUT_MS = 2_000;
83
+ /**
84
+ * Build `-c` overrides that blank every filter / merge driver named in the
85
+ * NUL-separated output of `git config -z --name-only --get-regexp`. Returns
86
+ * null when a driver name contains `=` — `-c` splits at the first `=`, so the
87
+ * override could not be expressed and the caller must refuse to run.
88
+ */
89
+ export function buildDriverOverrides(outputs) {
90
+ const filters = new Set();
91
+ const merges = new Set();
92
+ for (const output of outputs) {
93
+ for (const name of output.split(/[\0\n]/)) {
94
+ const filter = /^filter\.(.+)\.(?:clean|smudge|process|required)$/is.exec(name)?.[1];
95
+ const merge = /^merge\.(.+)\.driver$/is.exec(name)?.[1];
96
+ const driver = filter ?? merge;
97
+ if (driver === undefined)
98
+ continue;
99
+ if (driver.includes("="))
100
+ return null;
101
+ (filter !== undefined ? filters : merges).add(driver);
102
+ }
103
+ }
104
+ const args = [];
105
+ for (const driver of filters) {
106
+ args.push("-c", `filter.${driver}.clean=`, "-c", `filter.${driver}.smudge=`, "-c", `filter.${driver}.process=`,
107
+ // A blanked `required` filter would otherwise make status die.
108
+ "-c", `filter.${driver}.required=false`);
109
+ }
110
+ for (const driver of merges)
111
+ args.push("-c", `merge.${driver}.driver=`);
112
+ return args;
113
+ }
114
+ let cachedGitBinary;
115
+ /**
116
+ * The git executable. On Windows, libuv's PATH search tries the child's cwd
117
+ * first, so a `git.exe` planted at a repo root would run instead of git —
118
+ * resolve an absolute path from PATH once instead.
119
+ */
120
+ export function resolveGitBinary() {
121
+ if (cachedGitBinary !== undefined)
122
+ return cachedGitBinary;
123
+ cachedGitBinary = "git";
124
+ if (process.platform === "win32") {
125
+ for (const dir of (process.env.PATH ?? "").split(path.delimiter)) {
126
+ const clean = dir.trim().replace(/^"|"$/g, "");
127
+ if (!clean || !path.isAbsolute(clean))
128
+ continue;
129
+ const candidate = path.join(clean, "git.exe");
130
+ try {
131
+ if (statSync(candidate).isFile()) {
132
+ cachedGitBinary = candidate;
133
+ break;
134
+ }
8
135
  }
9
- resolve(stdout.trim() || null);
10
- });
11
- });
136
+ catch {
137
+ // not here
138
+ }
139
+ }
140
+ }
141
+ return cachedGitBinary;
12
142
  }
13
- /** Count staged, modified, deleted, renamed, and untracked files. */
14
- export function getGitDirtyFileCount(cwd) {
143
+ /**
144
+ * Rejection of {@link runBackgroundGit}, shaped like a promisified execFile
145
+ * error: `code` is git's exit status (number) or a spawn errno (string).
146
+ */
147
+ export class BackgroundGitError extends Error {
148
+ code;
149
+ killed;
150
+ stdout;
151
+ stderr;
152
+ constructor(message, details) {
153
+ super(message);
154
+ this.name = "BackgroundGitError";
155
+ this.code = details.code;
156
+ this.killed = details.killed;
157
+ this.stdout = details.stdout;
158
+ this.stderr = details.stderr;
159
+ }
160
+ }
161
+ function spawnGit(args, options) {
15
162
  return new Promise((resolve, reject) => {
16
- execFile("git", ["status", "--porcelain=v1", "--untracked-files=all"], { cwd, timeout: 2000 }, (error, stdout) => {
17
- if (error) {
18
- reject(error);
163
+ const child = execFile(resolveGitBinary(), [...args], {
164
+ cwd: options.cwd,
165
+ timeout: options.timeoutMs ?? 2_000,
166
+ maxBuffer: options.maxBuffer ?? 1024 * 1024,
167
+ signal: options.signal,
168
+ windowsHide: true,
169
+ encoding: "utf8",
170
+ env: {
171
+ ...process.env,
172
+ GIT_TERMINAL_PROMPT: "0",
173
+ GIT_OPTIONAL_LOCKS: "0",
174
+ GIT_PAGER: "cat",
175
+ GIT_NO_LAZY_FETCH: "1",
176
+ ...options.env,
177
+ },
178
+ }, (error, stdout, stderr) => {
179
+ if (!error) {
180
+ resolve({ stdout, stderr });
19
181
  return;
20
182
  }
21
- resolve(stdout.split(/\r?\n/).filter(Boolean).length);
183
+ const code = error.code;
184
+ reject(new BackgroundGitError(error.message, {
185
+ code: typeof code === "number" || typeof code === "string" ? code : null,
186
+ killed: error.killed === true,
187
+ stdout,
188
+ stderr,
189
+ }));
22
190
  });
191
+ if (options.input !== undefined && child.stdin) {
192
+ child.stdin.on("error", () => {
193
+ // git exited before reading all input; the exit callback reports it.
194
+ });
195
+ child.stdin.end(options.input);
196
+ }
197
+ });
198
+ }
199
+ /** Repo-local filter/merge driver overrides, or null when they cannot be expressed. */
200
+ async function probeDriverOverrides(options) {
201
+ const outputs = await Promise.all(["--local", "--worktree"].map(async (scope) => {
202
+ try {
203
+ const { stdout } = await spawnGit([
204
+ ...GIT_HARDENING_CONFIG_ARGS,
205
+ ...(options.globalArgs ?? []),
206
+ "config",
207
+ scope,
208
+ "--includes",
209
+ "-z",
210
+ "--name-only",
211
+ "--get-regexp",
212
+ "^(filter|merge)\\.",
213
+ ], {
214
+ cwd: options.cwd,
215
+ timeoutMs: PROBE_TIMEOUT_MS,
216
+ signal: options.signal,
217
+ env: options.env,
218
+ });
219
+ return stdout;
220
+ }
221
+ catch (error) {
222
+ // Exit 1 = no matching keys; 128/129 = not a repo / old git without
223
+ // --worktree. Spawn failures and timeouts fail closed.
224
+ if (error instanceof BackgroundGitError && typeof error.code === "number" && !error.killed)
225
+ return "";
226
+ throw error;
227
+ }
228
+ }));
229
+ return buildDriverOverrides(outputs);
230
+ }
231
+ /**
232
+ * Full argv for a hardened background git call (minus the binary). Exposed
233
+ * for tests; callers use {@link runBackgroundGit}.
234
+ */
235
+ export async function hardenedGitArgs(args, options) {
236
+ const [subcommand, ...rest] = args;
237
+ let drivers = [];
238
+ if (subcommand === undefined || !NO_FILTER_SUBCOMMANDS.has(subcommand)) {
239
+ const probed = await probeDriverOverrides(options);
240
+ if (probed === null) {
241
+ throw new BackgroundGitError("git config names a filter/merge driver that cannot be disabled", {
242
+ code: null,
243
+ killed: false,
244
+ stdout: "",
245
+ stderr: "",
246
+ });
247
+ }
248
+ drivers = probed;
249
+ }
250
+ let command = [...args];
251
+ if (subcommand !== undefined && DIFF_FAMILY.has(subcommand)) {
252
+ command = [subcommand, ...GIT_NO_EXTERNAL_DIFF_ARGS, ...rest];
253
+ }
254
+ else if (subcommand === "status" &&
255
+ !rest
256
+ .slice(0, rest.includes("--") ? rest.indexOf("--") : rest.length)
257
+ .some((arg) => arg.startsWith("--ignore-submodules"))) {
258
+ command = [subcommand, ...GIT_STATUS_SUBMODULE_ARGS, ...rest];
259
+ }
260
+ return [...GIT_HARDENING_CONFIG_ARGS, ...drivers, ...(options.globalArgs ?? []), ...command];
261
+ }
262
+ /**
263
+ * Run git for GG's own background purposes with repo-config execution sinks
264
+ * disabled. Resolves `{stdout, stderr}` on exit 0; rejects with
265
+ * {@link BackgroundGitError} otherwise. Output is identical to plain git.
266
+ */
267
+ export async function runBackgroundGit(args, options) {
268
+ return spawnGit(await hardenedGitArgs(args, options), options);
269
+ }
270
+ // ── Background helpers ──────────────────────────────────────────────────────
271
+ export async function getGitBranch(cwd) {
272
+ try {
273
+ const { stdout } = await runBackgroundGit(["rev-parse", "--abbrev-ref", "HEAD"], { cwd });
274
+ return stdout.trim() || null;
275
+ }
276
+ catch {
277
+ return null;
278
+ }
279
+ }
280
+ /** Count staged, modified, deleted, renamed, and untracked files. */
281
+ export async function getGitDirtyFileCount(cwd) {
282
+ const { stdout } = await runBackgroundGit(["status", "--porcelain=v1", "--untracked-files=all"], {
283
+ cwd,
23
284
  });
285
+ return stdout.split(/\r?\n/).filter(Boolean).length;
24
286
  }
25
287
  /**
26
288
  * Whether `cwd` is inside a git work tree. Distinct from getGitBranch, which
27
289
  * returns null both for non-repos AND for freshly-init'd repos with no commits
28
290
  * (rev-parse HEAD fails before the first commit).
29
291
  */
30
- export function isGitRepo(cwd) {
31
- return new Promise((resolve) => {
32
- execFile("git", ["rev-parse", "--is-inside-work-tree"], { cwd, timeout: 2000 }, (error, stdout) => {
33
- resolve(!error && stdout.trim() === "true");
34
- });
35
- });
292
+ export async function isGitRepo(cwd) {
293
+ try {
294
+ const { stdout } = await runBackgroundGit(["rev-parse", "--is-inside-work-tree"], { cwd });
295
+ return stdout.trim() === "true";
296
+ }
297
+ catch {
298
+ return false;
299
+ }
36
300
  }
37
301
  //# sourceMappingURL=git.js.map