@kenkaiiii/ggcoder 4.3.159 → 4.3.161

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 (52) hide show
  1. package/dist/core/language-detector.d.ts +32 -0
  2. package/dist/core/language-detector.d.ts.map +1 -0
  3. package/dist/core/language-detector.js +191 -0
  4. package/dist/core/language-detector.js.map +1 -0
  5. package/dist/core/language-detector.test.d.ts +2 -0
  6. package/dist/core/language-detector.test.d.ts.map +1 -0
  7. package/dist/core/language-detector.test.js +109 -0
  8. package/dist/core/language-detector.test.js.map +1 -0
  9. package/dist/core/prompt-commands.d.ts.map +1 -1
  10. package/dist/core/prompt-commands.js +93 -0
  11. package/dist/core/prompt-commands.js.map +1 -1
  12. package/dist/core/setup-history.d.ts +7 -0
  13. package/dist/core/setup-history.d.ts.map +1 -0
  14. package/dist/core/setup-history.js +50 -0
  15. package/dist/core/setup-history.js.map +1 -0
  16. package/dist/core/setup-history.test.d.ts +2 -0
  17. package/dist/core/setup-history.test.d.ts.map +1 -0
  18. package/dist/core/setup-history.test.js +48 -0
  19. package/dist/core/setup-history.test.js.map +1 -0
  20. package/dist/core/style-packs/index.d.ts +19 -0
  21. package/dist/core/style-packs/index.d.ts.map +1 -0
  22. package/dist/core/style-packs/index.js +50 -0
  23. package/dist/core/style-packs/index.js.map +1 -0
  24. package/dist/core/style-packs/packs.d.ts +18 -0
  25. package/dist/core/style-packs/packs.d.ts.map +1 -0
  26. package/dist/core/style-packs/packs.js +228 -0
  27. package/dist/core/style-packs/packs.js.map +1 -0
  28. package/dist/core/verify-commands.d.ts +35 -0
  29. package/dist/core/verify-commands.d.ts.map +1 -0
  30. package/dist/core/verify-commands.js +209 -0
  31. package/dist/core/verify-commands.js.map +1 -0
  32. package/dist/core/verify-commands.test.d.ts +2 -0
  33. package/dist/core/verify-commands.test.d.ts.map +1 -0
  34. package/dist/core/verify-commands.test.js +85 -0
  35. package/dist/core/verify-commands.test.js.map +1 -0
  36. package/dist/system-prompt.d.ts +2 -1
  37. package/dist/system-prompt.d.ts.map +1 -1
  38. package/dist/system-prompt.js +25 -3
  39. package/dist/system-prompt.js.map +1 -1
  40. package/dist/ui/App.d.ts +19 -1
  41. package/dist/ui/App.d.ts.map +1 -1
  42. package/dist/ui/App.js +189 -7
  43. package/dist/ui/App.js.map +1 -1
  44. package/dist/ui/theme/dark-ansi.json +2 -1
  45. package/dist/ui/theme/dark-daltonized.json +2 -1
  46. package/dist/ui/theme/dark.json +2 -1
  47. package/dist/ui/theme/light-ansi.json +2 -1
  48. package/dist/ui/theme/light-daltonized.json +2 -1
  49. package/dist/ui/theme/light.json +2 -1
  50. package/dist/ui/theme/theme.d.ts +1 -0
  51. package/dist/ui/theme/theme.d.ts.map +1 -1
  52. package/package.json +4 -4
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Supported language identifiers for style packs.
3
+ * Adding a new language: add the id here, add a marker entry to MARKERS,
4
+ * and add the pack content in `style-packs/packs.ts`.
5
+ */
6
+ export type LanguageId = "typescript" | "javascript" | "python" | "go" | "rust" | "java" | "kotlin" | "csharp" | "cpp" | "c" | "ruby" | "php" | "swift" | "scala" | "elixir" | "haskell" | "ocaml" | "fsharp" | "clojure" | "dart" | "lua" | "zig" | "sql" | "bash" | "terraform";
7
+ /**
8
+ * Detect active languages in a project root.
9
+ *
10
+ * Pure, synchronous, side-effect free. Cheap: a bounded number of fs stats
11
+ * and one directory listing per scanned subdir. Safe to call after every
12
+ * tool result — see `App.tsx` integration.
13
+ */
14
+ export declare function detectLanguages(cwd: string): Set<LanguageId>;
15
+ /**
16
+ * Stable, deterministic ordering of a language set — used for cache-key
17
+ * equality checks and consistent style-pack section ordering.
18
+ */
19
+ export declare function languagesToSortedArray(set: Set<LanguageId>): LanguageId[];
20
+ /**
21
+ * Human-facing display names for each language id. Used by the TUI badge
22
+ * (`StylePackItem` in App.tsx) so the user sees "TypeScript" rather than
23
+ * `typescript`. Keep these short — they're rendered inline.
24
+ */
25
+ export declare const LANGUAGE_DISPLAY_NAMES: Readonly<Record<LanguageId, string>>;
26
+ /**
27
+ * Returns true iff `next` contains every member of `prev` plus at least one
28
+ * additional language. Used to gate system-prompt rebuilds: we only re-inject
29
+ * when the active set grows, never when it merely changes order.
30
+ */
31
+ export declare function isStrictSuperset(next: Set<LanguageId>, prev: Set<LanguageId>): boolean;
32
+ //# sourceMappingURL=language-detector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"language-detector.d.ts","sourceRoot":"","sources":["../../src/core/language-detector.ts"],"names":[],"mappings":"AAGA;;;;GAIG;AACH,MAAM,MAAM,UAAU,GAClB,YAAY,GACZ,YAAY,GACZ,QAAQ,GACR,IAAI,GACJ,MAAM,GACN,MAAM,GACN,QAAQ,GACR,QAAQ,GACR,KAAK,GACL,GAAG,GACH,MAAM,GACN,KAAK,GACL,OAAO,GACP,OAAO,GACP,QAAQ,GACR,SAAS,GACT,OAAO,GACP,QAAQ,GACR,SAAS,GACT,MAAM,GACN,KAAK,GACL,KAAK,GACL,KAAK,GACL,MAAM,GACN,WAAW,CAAC;AAkEhB;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC,UAAU,CAAC,CA8D5D;AAsBD;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,GAAG,CAAC,UAAU,CAAC,GAAG,UAAU,EAAE,CAIzE;AAED;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,EAAE,QAAQ,CAAC,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,CA0BvE,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,GAAG,CAAC,UAAU,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,UAAU,CAAC,GAAG,OAAO,CAMtF"}
@@ -0,0 +1,191 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ const MARKERS = {
4
+ typescript: { manifests: ["tsconfig.json"], extensions: [".ts", ".tsx", ".mts", ".cts"] },
5
+ // JS is only flagged when there's a package.json AND no tsconfig — pure JS projects.
6
+ // Handled specially in detectLanguages.
7
+ javascript: { manifests: ["package.json"], extensions: [".js", ".jsx", ".mjs", ".cjs"] },
8
+ python: {
9
+ manifests: ["pyproject.toml", "setup.py", "setup.cfg", "requirements.txt", "Pipfile"],
10
+ extensions: [".py"],
11
+ },
12
+ go: { manifests: ["go.mod"], extensions: [".go"] },
13
+ rust: { manifests: ["Cargo.toml"], extensions: [".rs"] },
14
+ java: { manifests: ["pom.xml", "build.gradle", "build.gradle.kts"], extensions: [".java"] },
15
+ kotlin: { manifests: ["build.gradle.kts"], extensions: [".kt", ".kts"] },
16
+ csharp: { manifests: [], extensions: [".cs", ".csproj", ".sln"] },
17
+ cpp: {
18
+ manifests: ["CMakeLists.txt"],
19
+ extensions: [".cpp", ".cc", ".cxx", ".hpp", ".hh"],
20
+ },
21
+ c: { manifests: [], extensions: [".c", ".h"] },
22
+ ruby: { manifests: ["Gemfile", "Rakefile", ".ruby-version"], extensions: [".rb"] },
23
+ php: { manifests: ["composer.json"], extensions: [".php"] },
24
+ swift: { manifests: ["Package.swift"], extensions: [".swift"] },
25
+ scala: { manifests: ["build.sbt"], extensions: [".scala", ".sc"] },
26
+ elixir: { manifests: ["mix.exs"], extensions: [".ex", ".exs"] },
27
+ haskell: { manifests: ["stack.yaml", "cabal.project"], extensions: [".hs"] },
28
+ ocaml: { manifests: ["dune-project"], extensions: [".ml", ".mli"] },
29
+ fsharp: { manifests: [], extensions: [".fs", ".fsx", ".fsproj"] },
30
+ clojure: { manifests: ["project.clj", "deps.edn"], extensions: [".clj", ".cljs", ".cljc"] },
31
+ dart: { manifests: ["pubspec.yaml"], extensions: [".dart"] },
32
+ lua: { manifests: [".luarc.json"], extensions: [".lua"] },
33
+ zig: { manifests: ["build.zig"], extensions: [".zig"] },
34
+ sql: { manifests: [], extensions: [".sql"] },
35
+ bash: { manifests: [], extensions: [".sh", ".bash"] },
36
+ terraform: { manifests: [], extensions: [".tf", ".tfvars"] },
37
+ };
38
+ const ALL_LANGUAGES = Object.keys(MARKERS);
39
+ /**
40
+ * Subdirectories scanned for source-file extensions, in addition to cwd root.
41
+ * Kept short to bound cost. Detection is intentionally biased toward
42
+ * marker-file presence over extension scans.
43
+ */
44
+ const SCAN_DIRS = ["src", "lib", "app", "scripts", "internal", "cmd", "pkg"];
45
+ /** Cap on entries read per directory — prevents pathological cost on huge dirs. */
46
+ const MAX_ENTRIES_PER_DIR = 50;
47
+ /**
48
+ * Detect active languages in a project root.
49
+ *
50
+ * Pure, synchronous, side-effect free. Cheap: a bounded number of fs stats
51
+ * and one directory listing per scanned subdir. Safe to call after every
52
+ * tool result — see `App.tsx` integration.
53
+ */
54
+ export function detectLanguages(cwd) {
55
+ const detected = new Set();
56
+ // Pass 1: manifest files at cwd root — cheap, deterministic.
57
+ for (const lang of ALL_LANGUAGES) {
58
+ const manifests = MARKERS[lang].manifests;
59
+ if (!manifests || manifests.length === 0)
60
+ continue;
61
+ for (const manifest of manifests) {
62
+ if (fileExists(path.join(cwd, manifest))) {
63
+ detected.add(lang);
64
+ break;
65
+ }
66
+ }
67
+ }
68
+ // Pass 2: extension scan in root + select subdirs — covers languages without
69
+ // a canonical manifest (C, C#, SQL, Bash, Terraform, etc.).
70
+ const dirsToScan = [cwd, ...SCAN_DIRS.map((d) => path.join(cwd, d))];
71
+ for (const dir of dirsToScan) {
72
+ let entries;
73
+ try {
74
+ entries = fs.readdirSync(dir).slice(0, MAX_ENTRIES_PER_DIR);
75
+ }
76
+ catch {
77
+ continue;
78
+ }
79
+ for (const entry of entries) {
80
+ const ext = path.extname(entry).toLowerCase();
81
+ if (!ext)
82
+ continue;
83
+ for (const lang of ALL_LANGUAGES) {
84
+ if (detected.has(lang))
85
+ continue;
86
+ const exts = MARKERS[lang].extensions;
87
+ if (exts && exts.includes(ext)) {
88
+ detected.add(lang);
89
+ }
90
+ }
91
+ }
92
+ }
93
+ // Disambiguate JS vs TS — if both are flagged, prefer TypeScript only.
94
+ // A package.json + tsconfig.json + .ts files is a TS project, not "both".
95
+ if (detected.has("typescript") && detected.has("javascript")) {
96
+ detected.delete("javascript");
97
+ }
98
+ // Disambiguate Java vs Kotlin — `build.gradle.kts` triggers both. Keep both
99
+ // when there are actual .kt source files; otherwise treat as Java.
100
+ if (detected.has("java") && detected.has("kotlin")) {
101
+ const hasKotlinSources = dirsToScan.some((d) => hasExtensionAt(d, [".kt"]));
102
+ if (!hasKotlinSources)
103
+ detected.delete("kotlin");
104
+ }
105
+ // Disambiguate C vs C++ — if both flagged from extensions, and a CMakeLists
106
+ // exists, prefer C++. Otherwise keep whichever has source files present.
107
+ if (detected.has("c") && detected.has("cpp")) {
108
+ // .h files alone trigger C; if there are any .cpp/.cc/.cxx files, drop C.
109
+ const hasCppSources = dirsToScan.some((d) => hasExtensionAt(d, [".cpp", ".cc", ".cxx", ".hpp"]));
110
+ if (hasCppSources)
111
+ detected.delete("c");
112
+ }
113
+ return detected;
114
+ }
115
+ function fileExists(p) {
116
+ try {
117
+ return fs.statSync(p).isFile();
118
+ }
119
+ catch {
120
+ return false;
121
+ }
122
+ }
123
+ function hasExtensionAt(dir, exts) {
124
+ try {
125
+ const entries = fs.readdirSync(dir).slice(0, MAX_ENTRIES_PER_DIR);
126
+ for (const entry of entries) {
127
+ if (exts.includes(path.extname(entry).toLowerCase()))
128
+ return true;
129
+ }
130
+ }
131
+ catch {
132
+ /* directory missing — fine */
133
+ }
134
+ return false;
135
+ }
136
+ /**
137
+ * Stable, deterministic ordering of a language set — used for cache-key
138
+ * equality checks and consistent style-pack section ordering.
139
+ */
140
+ export function languagesToSortedArray(set) {
141
+ const sorted = [...set];
142
+ sorted.sort();
143
+ return sorted;
144
+ }
145
+ /**
146
+ * Human-facing display names for each language id. Used by the TUI badge
147
+ * (`StylePackItem` in App.tsx) so the user sees "TypeScript" rather than
148
+ * `typescript`. Keep these short — they're rendered inline.
149
+ */
150
+ export const LANGUAGE_DISPLAY_NAMES = {
151
+ typescript: "TypeScript",
152
+ javascript: "JavaScript",
153
+ python: "Python",
154
+ go: "Go",
155
+ rust: "Rust",
156
+ java: "Java",
157
+ kotlin: "Kotlin",
158
+ csharp: "C#",
159
+ cpp: "C++",
160
+ c: "C",
161
+ ruby: "Ruby",
162
+ php: "PHP",
163
+ swift: "Swift",
164
+ scala: "Scala",
165
+ elixir: "Elixir",
166
+ haskell: "Haskell",
167
+ ocaml: "OCaml",
168
+ fsharp: "F#",
169
+ clojure: "Clojure",
170
+ dart: "Dart",
171
+ lua: "Lua",
172
+ zig: "Zig",
173
+ sql: "SQL",
174
+ bash: "Bash",
175
+ terraform: "Terraform",
176
+ };
177
+ /**
178
+ * Returns true iff `next` contains every member of `prev` plus at least one
179
+ * additional language. Used to gate system-prompt rebuilds: we only re-inject
180
+ * when the active set grows, never when it merely changes order.
181
+ */
182
+ export function isStrictSuperset(next, prev) {
183
+ if (next.size <= prev.size)
184
+ return false;
185
+ for (const id of prev) {
186
+ if (!next.has(id))
187
+ return false;
188
+ }
189
+ return true;
190
+ }
191
+ //# sourceMappingURL=language-detector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"language-detector.js","sourceRoot":"","sources":["../../src/core/language-detector.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=language-detector.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"language-detector.test.d.ts","sourceRoot":"","sources":["../../src/core/language-detector.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,109 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from "vitest";
2
+ import fs from "node:fs";
3
+ import os from "node:os";
4
+ import path from "node:path";
5
+ import { detectLanguages, isStrictSuperset, languagesToSortedArray, } from "./language-detector.js";
6
+ let tmpDir;
7
+ beforeEach(() => {
8
+ tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "lang-detect-"));
9
+ });
10
+ afterEach(() => {
11
+ fs.rmSync(tmpDir, { recursive: true, force: true });
12
+ });
13
+ function touch(rel) {
14
+ const full = path.join(tmpDir, rel);
15
+ fs.mkdirSync(path.dirname(full), { recursive: true });
16
+ fs.writeFileSync(full, "");
17
+ }
18
+ describe("detectLanguages", () => {
19
+ it("returns an empty set for an empty directory", () => {
20
+ expect(detectLanguages(tmpDir).size).toBe(0);
21
+ });
22
+ it("detects TypeScript via tsconfig.json", () => {
23
+ touch("tsconfig.json");
24
+ touch("package.json");
25
+ const detected = detectLanguages(tmpDir);
26
+ expect(detected.has("typescript")).toBe(true);
27
+ // JS is suppressed when TS is present
28
+ expect(detected.has("javascript")).toBe(false);
29
+ });
30
+ it("detects JavaScript only when no tsconfig", () => {
31
+ touch("package.json");
32
+ const detected = detectLanguages(tmpDir);
33
+ expect(detected.has("javascript")).toBe(true);
34
+ expect(detected.has("typescript")).toBe(false);
35
+ });
36
+ it("detects Python via pyproject.toml", () => {
37
+ touch("pyproject.toml");
38
+ expect(detectLanguages(tmpDir).has("python")).toBe(true);
39
+ });
40
+ it("detects Go via go.mod", () => {
41
+ touch("go.mod");
42
+ expect(detectLanguages(tmpDir).has("go")).toBe(true);
43
+ });
44
+ it("detects Rust via Cargo.toml", () => {
45
+ touch("Cargo.toml");
46
+ expect(detectLanguages(tmpDir).has("rust")).toBe(true);
47
+ });
48
+ it("detects multiple languages in a polyglot repo", () => {
49
+ touch("package.json");
50
+ touch("tsconfig.json");
51
+ touch("pyproject.toml");
52
+ touch("Cargo.toml");
53
+ const detected = detectLanguages(tmpDir);
54
+ expect(detected.has("typescript")).toBe(true);
55
+ expect(detected.has("python")).toBe(true);
56
+ expect(detected.has("rust")).toBe(true);
57
+ expect(detected.has("javascript")).toBe(false); // suppressed by TS
58
+ });
59
+ it("detects extension-only languages (C, SQL, Bash)", () => {
60
+ touch("script.sh");
61
+ touch("query.sql");
62
+ touch("main.c");
63
+ const detected = detectLanguages(tmpDir);
64
+ expect(detected.has("bash")).toBe(true);
65
+ expect(detected.has("sql")).toBe(true);
66
+ expect(detected.has("c")).toBe(true);
67
+ });
68
+ it("prefers C++ over C when .cpp sources exist alongside headers", () => {
69
+ touch("src/main.cpp");
70
+ touch("src/util.h");
71
+ const detected = detectLanguages(tmpDir);
72
+ expect(detected.has("cpp")).toBe(true);
73
+ expect(detected.has("c")).toBe(false);
74
+ });
75
+ it("does not crash on unreadable subdirs", () => {
76
+ touch("tsconfig.json");
77
+ // Pretend `src/` exists but is unreadable — just don't create it.
78
+ expect(() => detectLanguages(tmpDir)).not.toThrow();
79
+ });
80
+ });
81
+ describe("isStrictSuperset", () => {
82
+ it("returns true when next has all of prev plus more", () => {
83
+ const prev = new Set(["typescript"]);
84
+ const next = new Set(["typescript", "python"]);
85
+ expect(isStrictSuperset(next, prev)).toBe(true);
86
+ });
87
+ it("returns false when sets are equal", () => {
88
+ const a = new Set(["typescript", "python"]);
89
+ const b = new Set(["typescript", "python"]);
90
+ expect(isStrictSuperset(a, b)).toBe(false);
91
+ });
92
+ it("returns false when next is missing a member of prev", () => {
93
+ const prev = new Set(["typescript", "python"]);
94
+ const next = new Set(["typescript", "rust"]);
95
+ expect(isStrictSuperset(next, prev)).toBe(false);
96
+ });
97
+ it("returns false when next is smaller", () => {
98
+ const prev = new Set(["typescript", "python"]);
99
+ const next = new Set(["typescript"]);
100
+ expect(isStrictSuperset(next, prev)).toBe(false);
101
+ });
102
+ });
103
+ describe("languagesToSortedArray", () => {
104
+ it("returns a deterministic sorted order", () => {
105
+ const set = new Set(["rust", "typescript", "python"]);
106
+ expect(languagesToSortedArray(set)).toEqual(["python", "rust", "typescript"]);
107
+ });
108
+ });
109
+ //# sourceMappingURL=language-detector.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"language-detector.test.js","sourceRoot":"","sources":["../../src/core/language-detector.test.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"prompt-commands.d.ts","sourceRoot":"","sources":["../../src/core/prompt-commands.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,eAAO,MAAM,eAAe,EAAE,aAAa,EAy0B1C,CAAC;AAEF,gDAAgD;AAChD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS,CAExE"}
1
+ {"version":3,"file":"prompt-commands.d.ts","sourceRoot":"","sources":["../../src/core/prompt-commands.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,eAAO,MAAM,eAAe,EAAE,aAAa,EAs6B1C,CAAC;AAEF,gDAAgD;AAChD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS,CAExE"}
@@ -843,6 +843,99 @@ If strong candidates had no ecosystem match, list them at the bottom:
843
843
 
844
844
  After presenting the list, ask which (if any) to install. Install nothing without explicit confirmation. Once confirmed, hand off to find-skills to perform the actual install.`,
845
845
  },
846
+ {
847
+ name: "setup",
848
+ aliases: ["setup-project"],
849
+ description: "Audit project hygiene, tooling, verify pipeline, and style-pack alignment",
850
+ prompt: `Audit this project across six categories and report gaps. **Do not fix anything yet.** Wait for me to choose what to address after the report.
851
+
852
+ Language-agnostic and project-agnostic — adapt findings to the languages and stack actually present. Ignore categories that don't apply (e.g. skip CI for a local-only scratchpad).
853
+
854
+ ## Categories
855
+
856
+ ### 1. Project hygiene
857
+
858
+ - \`.gitignore\` present and covers the active language(s)?
859
+ - \`README.md\` present with at least install + run instructions?
860
+ - License file present (if this looks like a public/shareable project)?
861
+ - \`.editorconfig\` present?
862
+ - Git initialized? (\`.git\` directory exists)
863
+
864
+ ### 2. Toolchain version pinning
865
+
866
+ - Language version pinned in a canonical file: \`.nvmrc\` / \`package.json#engines\` (Node), \`.python-version\` / \`pyproject.toml#requires-python\` (Python), \`rust-toolchain.toml\` (Rust), the \`go\` line in \`go.mod\`, \`.ruby-version\` (Ruby), etc.
867
+ - Lockfile present and committed? (\`package-lock.json\`, \`pnpm-lock.yaml\`, \`yarn.lock\`, \`bun.lockb\`, \`uv.lock\`, \`poetry.lock\`, \`Cargo.lock\`, \`go.sum\`, \`Gemfile.lock\`, \`composer.lock\`)
868
+
869
+ ### 3. Code quality tooling
870
+
871
+ For each active language, check that a formatter, linter, and (where applicable) type checker are configured:
872
+ - **Formatter**: Prettier / ruff format / gofmt (built-in) / rustfmt (built-in) / clang-format / etc.
873
+ - **Linter**: ESLint / Ruff / golangci-lint / Clippy / etc. — with a reasonable strictness preset
874
+ - **Type checker** (statically-typed langs only): tsc strict, Pyright strict, mypy strict
875
+ - **Test framework**: vitest / jest / pytest / go test / cargo test / rspec / etc.
876
+
877
+ Report which are present, missing, or configured below the pack's strictness recommendation.
878
+
879
+ ### 4. Verify pipeline
880
+
881
+ - Are \`lint\` / \`typecheck\` / \`format:check\` / \`test\` (or language-equivalent) wired as runnable commands? (scripts in \`package.json\`, \`pyproject.toml\`, a \`Makefile\`, or \`justfile\`)
882
+ - Pre-commit hook configured? (\`.husky/\`, \`pre-commit\` framework, \`lefthook\`, etc.) — nice-to-have, not required.
883
+ - CI config present? (\`.github/workflows/\`, \`.gitlab-ci.yml\`, \`.circleci/\`, etc.)
884
+
885
+ ### 5. Style pack alignment
886
+
887
+ "Active style packs" refers specifically to the **Language Style Packs** section in your system prompt (e.g. TypeScript, Python, Go). It does **NOT** include Skills (\`.gg/skills/\`) or any other extension category. If the Language Style Packs section is absent or empty, **skip this entire section entirely** — do not substitute Skills or any other concept.
888
+
889
+ When Language Style Packs are present, compare the project against each pack's **Tooling** bullet and the system prompt's **Verification** commands:
890
+ - Tooling: which strict-mode flags or lint-rule presets does the pack recommend that the project is missing? (e.g. \`tsconfig\` missing \`noUncheckedIndexedAccess\`, \`pyproject\` missing \`[tool.ruff]\`).
891
+ - Dependencies: list which pack-mentioned libs (Zod, neverthrow, Pydantic, thiserror, etc.) the project uses, has an equivalent for, or lacks. **Observation only — no recommendation to install.**
892
+
893
+ ### 6. Documentation hygiene
894
+
895
+ - \`CLAUDE.md\` or \`AGENTS.md\` present?
896
+ - Public API documented? (top-level docstrings, type signatures, or README examples)
897
+ - Architecture doc for non-trivial projects? (\`ARCHITECTURE.md\`, \`docs/architecture/\`, ADRs)
898
+
899
+ ## How to investigate
900
+
901
+ - Read the project root + obvious config locations (\`./\`, \`.github/\`, \`.husky/\`, \`docs/\`).
902
+ - Don't recurse into \`node_modules\`, \`dist\`, \`build\`, \`target\`, vendored folders.
903
+ - Use \`ls\`, \`read\`, \`find\` (with name patterns) — do not \`grep\` source code for this audit; it's about scaffolding, not code review.
904
+ - Cap at ~20 file reads total. If a file is huge (e.g. \`pnpm-lock.yaml\`), don't read its body — presence is what matters.
905
+
906
+ ## Output format
907
+
908
+ A single Markdown report, organized by category. Within each category, mark each item as one of:
909
+ - \`[OK]\` — present and reasonable
910
+ - \`[GAP]\` — missing or misconfigured; safe to add/fix
911
+ - \`[INFO]\` — observation only, no action implied
912
+ - \`[N/A]\` — doesn't apply to this project (omit from output if obvious)
913
+
914
+ Keep each line to one sentence. No prose paragraphs.
915
+
916
+ At the end:
917
+
918
+ \`\`\`
919
+ ## Summary
920
+
921
+ <N> gaps in hygiene, <N> in tooling, <N> in verify pipeline, <N> in style-pack alignment.
922
+
923
+ Which (if any) would you like me to fix? Options:
924
+ - A) All [GAP] items that are safe + additive (no overwrites)
925
+ - B) Pick category: hygiene / tooling / verify / style-pack alignment
926
+ - C) Specific items — tell me which
927
+ - D) None — just the report
928
+ \`\`\`
929
+
930
+ ## Rules
931
+
932
+ - **Report only.** No edits, no installs, no commits without explicit user confirmation after the report.
933
+ - **No code refactors recommended.** This audit is about scaffolding/tooling, not code review. Use \`/scan\` or \`/verify\` for code-level findings.
934
+ - **No dependency installations in the report.** Listing them as observations is fine; recommending installation is not — that's the user's call.
935
+ - **Skip empty categories.** If a category has no findings, omit it.
936
+ - **Adapt to scale.** A 50-line script doesn't need CI, a license, or an ARCHITECTURE.md. Use judgment.
937
+ - **Brand-new empty project**: report "Empty project — nothing to audit. To bootstrap, tell me the stack you want and I'll scaffold from scratch." and stop.`,
938
+ },
846
939
  ];
847
940
  /** Look up a prompt command by name or alias */
848
941
  export function getPromptCommand(name) {
@@ -1 +1 @@
1
- {"version":3,"file":"prompt-commands.js","sourceRoot":"","sources":["../../src/core/prompt-commands.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"prompt-commands.js","sourceRoot":"","sources":["../../src/core/prompt-commands.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ /** Returns true if this cwd has never been audited by /setup before. */
2
+ export declare function isFirstTimeSetup(cwd: string): boolean;
3
+ /** Mark this cwd as audited. Called immediately after the auto-run fires
4
+ * (whether or not the agent actually completes the audit) so we never
5
+ * double-trigger across sessions. */
6
+ export declare function markSetupAudited(cwd: string): void;
7
+ //# sourceMappingURL=setup-history.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup-history.d.ts","sourceRoot":"","sources":["../../src/core/setup-history.ts"],"names":[],"mappings":"AA6CA,wEAAwE;AACxE,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAGrD;AAED;;sCAEsC;AACtC,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAIlD"}
@@ -0,0 +1,50 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import os from "node:os";
4
+ const HISTORY_PATH = path.join(os.homedir(), ".gg", "setup-history.json");
5
+ /**
6
+ * Persisted record of which project directories have been auto-audited by
7
+ * `/setup`. Used to gate the first-time auto-run: we want the audit to fire
8
+ * exactly once per project, not once per session.
9
+ *
10
+ * Stored at `~/.gg/setup-history.json`. Keys are absolute cwd paths. The file
11
+ * is small (one line per project the user has ever opened with ggcoder) and
12
+ * read/written on session start only \u2014 not in any hot path.
13
+ */
14
+ function readHistory() {
15
+ try {
16
+ const raw = fs.readFileSync(HISTORY_PATH, "utf-8");
17
+ const parsed = JSON.parse(raw);
18
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
19
+ return parsed;
20
+ }
21
+ }
22
+ catch {
23
+ /* missing or unparseable \u2014 treat as empty */
24
+ }
25
+ return {};
26
+ }
27
+ function writeHistory(history) {
28
+ try {
29
+ fs.mkdirSync(path.dirname(HISTORY_PATH), { recursive: true });
30
+ fs.writeFileSync(HISTORY_PATH, JSON.stringify(history, null, 2), "utf-8");
31
+ }
32
+ catch {
33
+ /* best-effort \u2014 a failed write just means the auto-run will fire again
34
+ next session, which is annoying but not broken. */
35
+ }
36
+ }
37
+ /** Returns true if this cwd has never been audited by /setup before. */
38
+ export function isFirstTimeSetup(cwd) {
39
+ const history = readHistory();
40
+ return history[cwd] === undefined;
41
+ }
42
+ /** Mark this cwd as audited. Called immediately after the auto-run fires
43
+ * (whether or not the agent actually completes the audit) so we never
44
+ * double-trigger across sessions. */
45
+ export function markSetupAudited(cwd) {
46
+ const history = readHistory();
47
+ history[cwd] = { lastAuditedAt: new Date().toISOString() };
48
+ writeHistory(history);
49
+ }
50
+ //# sourceMappingURL=setup-history.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup-history.js","sourceRoot":"","sources":["../../src/core/setup-history.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,SAAS,CAAC;AAEzB,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,oBAAoB,CAAC,CAAC;AAS1E;;;;;;;;GAQG;AACH,SAAS,WAAW;IAClB,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;QACnD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAY,CAAC;QAC1C,IAAI,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YACnE,OAAO,MAAsB,CAAC;QAChC,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,kDAAkD;IACpD,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,SAAS,YAAY,CAAC,OAAqB;IACzC,IAAI,CAAC;QACH,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC9D,EAAE,CAAC,aAAa,CAAC,YAAY,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;IAC5E,CAAC;IAAC,MAAM,CAAC;QACP;6DACqD;IACvD,CAAC;AACH,CAAC;AAED,wEAAwE;AACxE,MAAM,UAAU,gBAAgB,CAAC,GAAW;IAC1C,MAAM,OAAO,GAAG,WAAW,EAAE,CAAC;IAC9B,OAAO,OAAO,CAAC,GAAG,CAAC,KAAK,SAAS,CAAC;AACpC,CAAC;AAED;;sCAEsC;AACtC,MAAM,UAAU,gBAAgB,CAAC,GAAW;IAC1C,MAAM,OAAO,GAAG,WAAW,EAAE,CAAC;IAC9B,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,aAAa,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC;IAC3D,YAAY,CAAC,OAAO,CAAC,CAAC;AACxB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=setup-history.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup-history.test.d.ts","sourceRoot":"","sources":["../../src/core/setup-history.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,48 @@
1
+ import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
2
+ import fs from "node:fs";
3
+ import os from "node:os";
4
+ import path from "node:path";
5
+ let tmpHome;
6
+ beforeEach(() => {
7
+ tmpHome = fs.mkdtempSync(path.join(os.tmpdir(), "setup-history-"));
8
+ // Re-point os.homedir() at our tmp dir. Done via a spy so the change is
9
+ // reverted after each test via vi.restoreAllMocks().
10
+ vi.spyOn(os, "homedir").mockReturnValue(tmpHome);
11
+ // setup-history.ts captures HISTORY_PATH at module load via os.homedir().
12
+ // We must re-import after the mock is in place to pick up the tmp path.
13
+ vi.resetModules();
14
+ });
15
+ afterEach(() => {
16
+ fs.rmSync(tmpHome, { recursive: true, force: true });
17
+ vi.restoreAllMocks();
18
+ });
19
+ async function loadModule() {
20
+ return await import("./setup-history.js");
21
+ }
22
+ describe("setup-history", () => {
23
+ it("isFirstTimeSetup returns true when history file is absent", async () => {
24
+ const { isFirstTimeSetup } = await loadModule();
25
+ expect(isFirstTimeSetup("/tmp/never-seen")).toBe(true);
26
+ });
27
+ it("markSetupAudited persists the cwd entry", async () => {
28
+ const { isFirstTimeSetup, markSetupAudited } = await loadModule();
29
+ const cwd = "/tmp/first-project";
30
+ expect(isFirstTimeSetup(cwd)).toBe(true);
31
+ markSetupAudited(cwd);
32
+ expect(isFirstTimeSetup(cwd)).toBe(false);
33
+ });
34
+ it("treats distinct cwds independently", async () => {
35
+ const { isFirstTimeSetup, markSetupAudited } = await loadModule();
36
+ markSetupAudited("/tmp/project-a");
37
+ expect(isFirstTimeSetup("/tmp/project-a")).toBe(false);
38
+ expect(isFirstTimeSetup("/tmp/project-b")).toBe(true);
39
+ });
40
+ it("tolerates corrupt history files (treats as empty)", async () => {
41
+ const ggDir = path.join(tmpHome, ".gg");
42
+ fs.mkdirSync(ggDir, { recursive: true });
43
+ fs.writeFileSync(path.join(ggDir, "setup-history.json"), "{ not valid json");
44
+ const { isFirstTimeSetup } = await loadModule();
45
+ expect(isFirstTimeSetup("/tmp/anywhere")).toBe(true);
46
+ });
47
+ });
48
+ //# sourceMappingURL=setup-history.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup-history.test.js","sourceRoot":"","sources":["../../src/core/setup-history.test.ts"],"names":[],"mappings":"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"}