@kenkaiiii/gg-boss 4.14.1 → 4.14.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.
@@ -70649,6 +70649,20 @@ var SHARP_FORMAT_TO_MEDIA = {
70649
70649
  gif: "image/gif",
70650
70650
  webp: "image/webp"
70651
70651
  };
70652
+ var VISION_MEDIA_TYPES = /* @__PURE__ */ new Set(["image/png", "image/jpeg", "image/gif", "image/webp"]);
70653
+ async function validateVisionImage(buffer) {
70654
+ try {
70655
+ const sharp = await loadSharp();
70656
+ const meta3 = await sharp(buffer).metadata();
70657
+ const mediaType = meta3.format ? SHARP_FORMAT_TO_MEDIA[meta3.format] : void 0;
70658
+ if (!mediaType || !VISION_MEDIA_TYPES.has(mediaType))
70659
+ return null;
70660
+ await sharp(buffer, { failOn: "error" }).resize(256, 256, { fit: "inside", withoutEnlargement: true }).raw().toBuffer();
70661
+ return mediaType;
70662
+ } catch {
70663
+ return null;
70664
+ }
70665
+ }
70652
70666
  async function shrinkToFit(buffer, mediaType) {
70653
70667
  const sharp = await loadSharp();
70654
70668
  const meta3 = await sharp(buffer).metadata();
@@ -70751,12 +70765,22 @@ async function readImageFile(filePath) {
70751
70765
  try {
70752
70766
  const mediaType = MEDIA_TYPES[ext] ?? "image/png";
70753
70767
  const rawBuffer = await fs11.readFile(filePath);
70754
- const { buffer, mediaType: finalMediaType } = await shrinkToFit(rawBuffer, mediaType);
70768
+ const { buffer } = await shrinkToFit(rawBuffer, mediaType);
70769
+ const validatedType = await validateVisionImage(buffer);
70770
+ if (!validatedType) {
70771
+ return {
70772
+ kind: "text",
70773
+ fileName,
70774
+ filePath,
70775
+ mediaType: "text/plain",
70776
+ data: `[image ${fileName} is not a valid/supported image (corrupt or unsupported format); saved at ${filePath} \u2014 inspect it with your tools if needed]`
70777
+ };
70778
+ }
70755
70779
  return {
70756
70780
  kind: "image",
70757
70781
  fileName,
70758
70782
  filePath,
70759
- mediaType: finalMediaType,
70783
+ mediaType: validatedType,
70760
70784
  data: buffer.toString("base64")
70761
70785
  };
70762
70786
  } catch (err) {
@@ -75240,6 +75264,76 @@ var MARKERS = {
75240
75264
  terraform: { manifests: [], extensions: [".tf", ".tfvars"] }
75241
75265
  };
75242
75266
  var ALL_LANGUAGES = Object.keys(MARKERS);
75267
+ var SCAN_DIRS = ["src", "lib", "app", "scripts", "internal", "cmd", "pkg"];
75268
+ var MAX_ENTRIES_PER_DIR = 50;
75269
+ function detectLanguages(cwd2) {
75270
+ const detected = /* @__PURE__ */ new Set();
75271
+ for (const lang of ALL_LANGUAGES) {
75272
+ const manifests = MARKERS[lang].manifests;
75273
+ if (!manifests || manifests.length === 0)
75274
+ continue;
75275
+ for (const manifest of manifests) {
75276
+ if (fileExists2(path25.join(cwd2, manifest))) {
75277
+ detected.add(lang);
75278
+ break;
75279
+ }
75280
+ }
75281
+ }
75282
+ const dirsToScan = [cwd2, ...SCAN_DIRS.map((d) => path25.join(cwd2, d))];
75283
+ for (const dir of dirsToScan) {
75284
+ let entries;
75285
+ try {
75286
+ entries = fs17.readdirSync(dir).slice(0, MAX_ENTRIES_PER_DIR);
75287
+ } catch {
75288
+ continue;
75289
+ }
75290
+ for (const entry of entries) {
75291
+ const ext = path25.extname(entry).toLowerCase();
75292
+ if (!ext)
75293
+ continue;
75294
+ for (const lang of ALL_LANGUAGES) {
75295
+ if (detected.has(lang))
75296
+ continue;
75297
+ const exts = MARKERS[lang].extensions;
75298
+ if (exts && exts.includes(ext)) {
75299
+ detected.add(lang);
75300
+ }
75301
+ }
75302
+ }
75303
+ }
75304
+ if (detected.has("typescript") && detected.has("javascript")) {
75305
+ detected.delete("javascript");
75306
+ }
75307
+ if (detected.has("java") && detected.has("kotlin")) {
75308
+ const hasKotlinSources = dirsToScan.some((d) => hasExtensionAt(d, [".kt"]));
75309
+ if (!hasKotlinSources)
75310
+ detected.delete("kotlin");
75311
+ }
75312
+ if (detected.has("c") && detected.has("cpp")) {
75313
+ const hasCppSources = dirsToScan.some((d) => hasExtensionAt(d, [".cpp", ".cc", ".cxx", ".hpp"]));
75314
+ if (hasCppSources)
75315
+ detected.delete("c");
75316
+ }
75317
+ return detected;
75318
+ }
75319
+ function fileExists2(p) {
75320
+ try {
75321
+ return fs17.statSync(p).isFile();
75322
+ } catch {
75323
+ return false;
75324
+ }
75325
+ }
75326
+ function hasExtensionAt(dir, exts) {
75327
+ try {
75328
+ const entries = fs17.readdirSync(dir).slice(0, MAX_ENTRIES_PER_DIR);
75329
+ for (const entry of entries) {
75330
+ if (exts.includes(path25.extname(entry).toLowerCase()))
75331
+ return true;
75332
+ }
75333
+ } catch {
75334
+ }
75335
+ return false;
75336
+ }
75243
75337
  function languagesToSortedArray(set2) {
75244
75338
  const sorted = [...set2];
75245
75339
  sorted.sort();
@@ -75272,6 +75366,86 @@ var LANGUAGE_DISPLAY_NAMES = {
75272
75366
  bash: "Bash",
75273
75367
  terraform: "Terraform"
75274
75368
  };
75369
+ var JS_FRAMEWORK_DEPS = [
75370
+ ["next", "Next.js"],
75371
+ ["nuxt", "Nuxt"],
75372
+ ["@remix-run/react", "Remix"],
75373
+ ["@sveltejs/kit", "SvelteKit"],
75374
+ ["astro", "Astro"],
75375
+ ["expo", "React Native (Expo)"],
75376
+ ["react-native", "React Native"],
75377
+ ["@angular/core", "Angular"],
75378
+ ["solid-js", "SolidJS"],
75379
+ ["svelte", "Svelte"],
75380
+ ["vue", "Vue"],
75381
+ ["react", "React"],
75382
+ ["@nestjs/core", "NestJS"],
75383
+ ["@tauri-apps/api", "Tauri"],
75384
+ ["electron", "Electron"],
75385
+ ["hono", "Hono"],
75386
+ ["fastify", "Fastify"],
75387
+ ["express", "Express"],
75388
+ ["tailwindcss", "Tailwind CSS"]
75389
+ ];
75390
+ var IMPLIES = {
75391
+ "Next.js": "React",
75392
+ Remix: "React",
75393
+ "React Native": "React",
75394
+ "React Native (Expo)": "React",
75395
+ Nuxt: "Vue",
75396
+ SvelteKit: "Svelte"
75397
+ };
75398
+ function detectJsFrameworks(cwd2) {
75399
+ let pkg;
75400
+ try {
75401
+ pkg = JSON.parse(fs17.readFileSync(path25.join(cwd2, "package.json"), "utf-8"));
75402
+ } catch {
75403
+ return [];
75404
+ }
75405
+ const deps = { ...pkg.dependencies ?? {}, ...pkg.devDependencies ?? {} };
75406
+ const found = JS_FRAMEWORK_DEPS.filter(([dep]) => dep in deps).map(([, display]) => display);
75407
+ const implied = new Set(found.map((f) => IMPLIES[f]).filter(Boolean));
75408
+ return found.filter((f) => !implied.has(f));
75409
+ }
75410
+ function detectFromManifest(cwd2, file2, markers) {
75411
+ let content;
75412
+ try {
75413
+ content = fs17.readFileSync(path25.join(cwd2, file2), "utf-8").toLowerCase();
75414
+ } catch {
75415
+ return [];
75416
+ }
75417
+ return markers.filter(([needle]) => content.includes(needle)).map(([, display]) => display);
75418
+ }
75419
+ function detectProjectStack(cwd2) {
75420
+ const langs = languagesToSortedArray(detectLanguages(cwd2)).map((l) => LANGUAGE_DISPLAY_NAMES[l]);
75421
+ const frameworks = [
75422
+ ...detectJsFrameworks(cwd2),
75423
+ ...detectFromManifest(cwd2, "Gemfile", [
75424
+ ["rails", "Ruby on Rails"],
75425
+ ["sinatra", "Sinatra"]
75426
+ ]),
75427
+ ...detectFromManifest(cwd2, "requirements.txt", [
75428
+ ["django", "Django"],
75429
+ ["flask", "Flask"],
75430
+ ["fastapi", "FastAPI"]
75431
+ ]),
75432
+ ...detectFromManifest(cwd2, "pyproject.toml", [
75433
+ ["django", "Django"],
75434
+ ["flask", "Flask"],
75435
+ ["fastapi", "FastAPI"]
75436
+ ]),
75437
+ ...detectFromManifest(cwd2, "composer.json", [["laravel/framework", "Laravel"]])
75438
+ ];
75439
+ const seen = /* @__PURE__ */ new Set();
75440
+ const parts = [];
75441
+ for (const item of [...frameworks, ...langs]) {
75442
+ if (item && !seen.has(item)) {
75443
+ seen.add(item);
75444
+ parts.push(item);
75445
+ }
75446
+ }
75447
+ return parts.slice(0, 6).join(", ");
75448
+ }
75275
75449
 
75276
75450
  // ../ggcoder/dist/core/style-packs/packs.js
75277
75451
  init_esm_shims();
@@ -75562,7 +75736,7 @@ function detectVerifyCommands(cwd2, active) {
75562
75736
  const testScript = pick2("test", "test:unit");
75563
75737
  if (testScript)
75564
75738
  cmds.push({ label: "test", command: `${runner} ${testScript}`, language: lang });
75565
- } else if (active.has("typescript") && fileExists2(path27.join(cwd2, "tsconfig.json"))) {
75739
+ } else if (active.has("typescript") && fileExists3(path27.join(cwd2, "tsconfig.json"))) {
75566
75740
  cmds.push({ label: "typecheck", command: "tsc --noEmit", language: "typescript" });
75567
75741
  }
75568
75742
  }
@@ -75599,10 +75773,10 @@ function detectVerifyCommands(cwd2, active) {
75599
75773
  }
75600
75774
  if (active.has("java") || active.has("kotlin")) {
75601
75775
  const lang = active.has("kotlin") ? "kotlin" : "java";
75602
- if (fileExists2(path27.join(cwd2, "gradlew"))) {
75776
+ if (fileExists3(path27.join(cwd2, "gradlew"))) {
75603
75777
  cmds.push({ label: "build", command: "./gradlew build", language: lang });
75604
75778
  cmds.push({ label: "test", command: "./gradlew test", language: lang });
75605
- } else if (fileExists2(path27.join(cwd2, "pom.xml"))) {
75779
+ } else if (fileExists3(path27.join(cwd2, "pom.xml"))) {
75606
75780
  cmds.push({ label: "verify", command: "mvn verify", language: lang });
75607
75781
  }
75608
75782
  }
@@ -75616,7 +75790,7 @@ function detectVerifyCommands(cwd2, active) {
75616
75790
  cmds.push({ label: "test", command: "dotnet test", language: "csharp" });
75617
75791
  }
75618
75792
  if (active.has("ruby")) {
75619
- if (fileExists2(path27.join(cwd2, "Gemfile"))) {
75793
+ if (fileExists3(path27.join(cwd2, "Gemfile"))) {
75620
75794
  cmds.push({ label: "lint", command: "bundle exec rubocop", language: "ruby" });
75621
75795
  cmds.push({ label: "test", command: "bundle exec rspec", language: "ruby" });
75622
75796
  }
@@ -75626,7 +75800,7 @@ function detectVerifyCommands(cwd2, active) {
75626
75800
  cmds.push({ label: "test", command: "mix test", language: "elixir" });
75627
75801
  }
75628
75802
  if (active.has("php")) {
75629
- if (fileExists2(path27.join(cwd2, "composer.json"))) {
75803
+ if (fileExists3(path27.join(cwd2, "composer.json"))) {
75630
75804
  cmds.push({ label: "test", command: "composer test", language: "php" });
75631
75805
  }
75632
75806
  }
@@ -75643,7 +75817,7 @@ function detectVerifyCommands(cwd2, active) {
75643
75817
  }
75644
75818
  return cmds;
75645
75819
  }
75646
- function fileExists2(p) {
75820
+ function fileExists3(p) {
75647
75821
  try {
75648
75822
  return fs19.statSync(p).isFile();
75649
75823
  } catch {
@@ -75669,11 +75843,11 @@ function readPackageJsonScripts(cwd2) {
75669
75843
  }
75670
75844
  }
75671
75845
  function detectNodeRunner(cwd2) {
75672
- if (fileExists2(path27.join(cwd2, "pnpm-lock.yaml")))
75846
+ if (fileExists3(path27.join(cwd2, "pnpm-lock.yaml")))
75673
75847
  return "pnpm";
75674
- if (fileExists2(path27.join(cwd2, "yarn.lock")))
75848
+ if (fileExists3(path27.join(cwd2, "yarn.lock")))
75675
75849
  return "yarn";
75676
- if (fileExists2(path27.join(cwd2, "bun.lockb")))
75850
+ if (fileExists3(path27.join(cwd2, "bun.lockb")))
75677
75851
  return "bun";
75678
75852
  return "npm run";
75679
75853
  }
@@ -75815,7 +75989,7 @@ ${planContent.trim()}
75815
75989
  function renderResearchSection() {
75816
75990
  return `## Research & Verification
75817
75991
 
75818
- Do not assume APIs, CLI flags, config schema, internals, or error wording. Use \`source_path\` for installed deps and inspect with read/grep/find/ls; use \`web_search\` then \`web_fetch\` for authoritative docs. For public code, use ReferenceSources for curated repos or DiscoverRepos for current/top repos, then verify exact snippets with SearchCode literal text/RE2 (not semantic); \`path\` is a literal path substring and \`repo\` only after broad/peek proof. Run targeted checks when they are relevant to the change; read/fix failures; never report unrun or failing checks as passing.`;
75992
+ Your training data has a cutoff; the real current date is the final line of this prompt. Assume your knowledge of library versions, APIs, CLI flags, config schema, defaults, and best practices has changed since then \u2014 treat it as a stale hint to verify, never as ground truth. Do not rely on memory for APIs, CLI flags, config schema, internals, or error wording \u2014 verify first. Use \`source_path\` for installed deps and inspect with read/grep/find/ls; use \`web_search\` then \`web_fetch\` for authoritative docs. For public code, use ReferenceSources for curated repos or DiscoverRepos for current/top repos, then verify exact snippets with SearchCode literal text/RE2 (not semantic); \`path\` is a literal path substring and \`repo\` only after broad/peek proof. Run targeted checks when they are relevant to the change; read/fix failures; never report unrun or failing checks as passing.`;
75819
75993
  }
75820
75994
  function renderCodeQualitySection() {
75821
75995
  return `## Code Quality
@@ -84683,6 +84857,94 @@ function fallbackTitle(userMessage) {
84683
84857
  return (sp > 20 ? t.slice(0, sp) : t) + "\u2026";
84684
84858
  }
84685
84859
 
84860
+ // ../ggcoder/dist/utils/prompt-enhancer.js
84861
+ init_esm_shims();
84862
+ var OPEN = "\u27E6";
84863
+ var CLOSE = "\u27E7";
84864
+ var BAR = "\xA6";
84865
+ var ENHANCER_SYSTEM_PROMPT = `You rewrite a developer's rough request into a tight, well-structured prompt for a CODING AGENT, and you teach them the correct vocabulary as you go. You only rewrite it \u2014 never answer, plan, or implement the request, never ask the user questions, and never add code snippets.
84866
+
84867
+ The teaching part: when the user described something in plain or informal words that has a precise, conventional software-engineering name, use that real name AND wrap it so the user learns the term. This highlighting is the main point \u2014 using the right term but failing to wrap it is a miss.
84868
+
84869
+ Marker format \u2014 wrap each introduced technical term EXACTLY like this, with BOTH fields always present:
84870
+ ${OPEN}correct term${BAR}the user's own words for it${BAR}short note${CLOSE}
84871
+ The third field (note) is an optional plain-language gloss and may be omitted: ${OPEN}correct term${BAR}the user's own words${CLOSE}. Never emit a marker without the user's-own-words field (no bare ${OPEN}term${CLOSE}). The user's-own-words field must quote the relevant part of THEIR phrasing, not a paraphrase.
84872
+
84873
+ Mark ONLY genuine vocabulary lessons \u2014 a real plain-words \u2192 established-technical-term upgrade, where the wrapped word is named software/CS jargon (e.g. debounce, throttle, lazy loading, caching, memoization, retry with backoff, concurrency, race, optimistic locking, idempotent, infinite scroll, virtualization, skeleton UI, mock/stub, persistence, WebSocket, cron job, deep copy, hot reload). Usually 0\u20133 per prompt, and often 0 \u2014 many requests have no jargon to teach, and that is fine. Do NOT wrap: plain descriptive English that is not a named technical concept (positions like "to the right of", directions, sizes, colors, "between", "reorder"), ordinary words (updates, changes, loading, bottom, the whole app), terms the user already used correctly, or generic rewording. If the only candidates are plain English, wrap nothing. When in doubt, leave it unwrapped.
84874
+
84875
+ Other rules:
84876
+ - Keep it concise and easy to follow (usually 1\u20133 sentences). No preamble, no headings, no code fences, no commentary.
84877
+ - Preserve every concrete detail the user gave (file names, numbers, identifiers, intent) and never invent requirements or scope.
84878
+ - NEVER ask the user for clarification or more detail, and never replace their request with a question. If the request is too vague or trivial to add real terminology (e.g. "fix the bug", "make the button blue"), return it essentially unchanged with no markers \u2014 the result must always read as the user's own instruction to the agent, never a message back to the user.
84879
+ - Output ONLY the rewritten prompt, with markers inline. Nothing else.`;
84880
+ function parseEnhanced(raw) {
84881
+ let cleaned = stripWrapping(raw);
84882
+ cleaned = cleaned.replace(new RegExp(`${OPEN}([^${BAR}${CLOSE}]*)${CLOSE}`, "g"), (_full, inner) => inner);
84883
+ const segments = [];
84884
+ const re = new RegExp(`${OPEN}([^${BAR}${CLOSE}]+)${BAR}([^${BAR}${CLOSE}]+)(?:${BAR}([^${CLOSE}]+))?${CLOSE}`, "g");
84885
+ let lastIndex = 0;
84886
+ let m;
84887
+ while ((m = re.exec(cleaned)) !== null) {
84888
+ if (m.index > lastIndex) {
84889
+ segments.push({ kind: "text", text: cleaned.slice(lastIndex, m.index) });
84890
+ }
84891
+ const term = m[1].trim();
84892
+ const original = m[2].trim();
84893
+ const note = m[3]?.trim();
84894
+ segments.push({ kind: "term", text: term, original, ...note ? { note } : {} });
84895
+ lastIndex = re.lastIndex;
84896
+ }
84897
+ if (lastIndex < cleaned.length) {
84898
+ segments.push({ kind: "text", text: cleaned.slice(lastIndex) });
84899
+ }
84900
+ const stripOrphans = (s) => s.replace(new RegExp(`[${OPEN}${CLOSE}${BAR}]`, "g"), " ").replace(/ {2,}/g, " ");
84901
+ for (const seg of segments) {
84902
+ if (seg.kind === "text")
84903
+ seg.text = stripOrphans(seg.text);
84904
+ }
84905
+ const trimmed = segments.filter((s) => s.kind !== "text" || s.text.length > 0);
84906
+ if (trimmed.length === 0) {
84907
+ trimmed.push({ kind: "text", text: stripOrphans(cleaned) });
84908
+ }
84909
+ const enhanced = trimmed.map((s) => s.text).join("");
84910
+ return { enhanced, segments: trimmed };
84911
+ }
84912
+ function stripWrapping(raw) {
84913
+ let text = raw.trim();
84914
+ const fence = text.match(/^```[^\n]*\n([\s\S]*?)\n```$/);
84915
+ if (fence)
84916
+ text = fence[1].trim();
84917
+ text = text.replace(/^(?:sure|okay|ok|here(?:'s| is)|here you go)[^\n]*:\s*\n+/i, "");
84918
+ return text.trim();
84919
+ }
84920
+ async function enhancePrompt(opts) {
84921
+ const system = opts.stack?.trim() ? `${ENHANCER_SYSTEM_PROMPT}
84922
+
84923
+ Project stack: ${opts.stack.trim()}. Prefer terminology idiomatic to this stack, but never invent stack-specific files, APIs, or scope the user didn't mention.` : ENHANCER_SYSTEM_PROMPT;
84924
+ const messages = [
84925
+ { role: "system", content: system },
84926
+ { role: "user", content: opts.prompt }
84927
+ ];
84928
+ const result2 = stream({
84929
+ provider: opts.provider,
84930
+ model: opts.model,
84931
+ messages,
84932
+ maxTokens: 700,
84933
+ // No temperature — the enhancer runs on whatever model is active, and some
84934
+ // (e.g. OpenAI reasoning models like gpt-5.5) reject the parameter outright.
84935
+ apiKey: opts.apiKey,
84936
+ baseUrl: opts.baseUrl,
84937
+ accountId: opts.accountId,
84938
+ signal: opts.signal
84939
+ });
84940
+ result2.response.catch(() => {
84941
+ });
84942
+ const response = await result2;
84943
+ const msg = response.message;
84944
+ const text = typeof msg.content === "string" ? msg.content : msg.content.filter((c2) => c2.type === "text").map((c2) => c2.text).join("");
84945
+ return parseEnhanced(text);
84946
+ }
84947
+
84686
84948
  // ../ggcoder/dist/core/ideal-review.js
84687
84949
  init_esm_shims();
84688
84950
  var IDEAL_REVIEW_PROMPT = "Ideal? Review the actual work against the user's request before the final response. Is it simple, focused, correct, and aligned? Did you over-edit, leave TODOs, miss an obvious case the request called for, or introduce risk? Judge this by reading the code you changed \u2014 do NOT run builds, typechecks, linters, or test suites now; that happens at commit time via /commit. If anything is wrong, fix it now. If everything is good, respond with the final answer only; do not mention this ideal review unless it changed the work.";
@@ -85604,6 +85866,33 @@ ${fileNotes.join("\n")}`);
85604
85866
  return null;
85605
85867
  }
85606
85868
  }
85869
+ /**
85870
+ * Rewrite a draft prompt into a tighter, terminology-correct version using
85871
+ * the ACTIVE provider/model. A stateless one-off LLM call (no agent loop, no
85872
+ * tools, no session mutation) — safe to run even mid-run. Returns the plain
85873
+ * enhanced text plus typed segments marking each corrected term. Errors throw
85874
+ * so the caller can surface them (unlike best-effort title generation).
85875
+ */
85876
+ async enhancePrompt(text) {
85877
+ if (!text.trim())
85878
+ return { enhanced: text, segments: [{ kind: "text", text }] };
85879
+ const creds = await this.authStorage.resolveCredentials(this.provider);
85880
+ let stack = "";
85881
+ try {
85882
+ stack = detectProjectStack(this.cwd);
85883
+ } catch {
85884
+ }
85885
+ return enhancePrompt({
85886
+ provider: this.provider,
85887
+ model: this.model,
85888
+ prompt: text,
85889
+ stack,
85890
+ apiKey: creds.accessToken,
85891
+ baseUrl: this.baseUrl ?? creds.baseUrl,
85892
+ accountId: creds.accountId,
85893
+ signal: this.opts.signal
85894
+ });
85895
+ }
85607
85896
  /** Current reasoning/thinking level, or undefined when thinking is off. */
85608
85897
  getThinkingLevel() {
85609
85898
  return this.thinkingLevel;
@@ -117777,4 +118066,4 @@ react/cjs/react-jsx-runtime.development.js:
117777
118066
  * LICENSE file in the root directory of this source tree.
117778
118067
  *)
117779
118068
  */
117780
- //# sourceMappingURL=chunk-JBIIZOVS.js.map
118069
+ //# sourceMappingURL=chunk-U6NZD74R.js.map