@kenkaiiii/ggcoder 4.3.158 → 4.3.160
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.
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +7 -1
- package/dist/cli.js.map +1 -1
- package/dist/core/language-detector.d.ts +32 -0
- package/dist/core/language-detector.d.ts.map +1 -0
- package/dist/core/language-detector.js +191 -0
- package/dist/core/language-detector.js.map +1 -0
- package/dist/core/language-detector.test.d.ts +2 -0
- package/dist/core/language-detector.test.d.ts.map +1 -0
- package/dist/core/language-detector.test.js +109 -0
- package/dist/core/language-detector.test.js.map +1 -0
- package/dist/core/prompt-commands.d.ts.map +1 -1
- package/dist/core/prompt-commands.js +93 -0
- package/dist/core/prompt-commands.js.map +1 -1
- package/dist/core/setup-history.d.ts +7 -0
- package/dist/core/setup-history.d.ts.map +1 -0
- package/dist/core/setup-history.js +50 -0
- package/dist/core/setup-history.js.map +1 -0
- package/dist/core/setup-history.test.d.ts +2 -0
- package/dist/core/setup-history.test.d.ts.map +1 -0
- package/dist/core/setup-history.test.js +48 -0
- package/dist/core/setup-history.test.js.map +1 -0
- package/dist/core/style-packs/index.d.ts +19 -0
- package/dist/core/style-packs/index.d.ts.map +1 -0
- package/dist/core/style-packs/index.js +50 -0
- package/dist/core/style-packs/index.js.map +1 -0
- package/dist/core/style-packs/packs.d.ts +18 -0
- package/dist/core/style-packs/packs.d.ts.map +1 -0
- package/dist/core/style-packs/packs.js +228 -0
- package/dist/core/style-packs/packs.js.map +1 -0
- package/dist/core/verify-commands.d.ts +35 -0
- package/dist/core/verify-commands.d.ts.map +1 -0
- package/dist/core/verify-commands.js +209 -0
- package/dist/core/verify-commands.js.map +1 -0
- package/dist/core/verify-commands.test.d.ts +2 -0
- package/dist/core/verify-commands.test.d.ts.map +1 -0
- package/dist/core/verify-commands.test.js +85 -0
- package/dist/core/verify-commands.test.js.map +1 -0
- package/dist/system-prompt.d.ts +2 -1
- package/dist/system-prompt.d.ts.map +1 -1
- package/dist/system-prompt.js +25 -3
- package/dist/system-prompt.js.map +1 -1
- package/dist/ui/App.d.ts +19 -1
- package/dist/ui/App.d.ts.map +1 -1
- package/dist/ui/App.js +189 -7
- package/dist/ui/App.js.map +1 -1
- package/dist/ui/theme/dark-ansi.json +2 -1
- package/dist/ui/theme/dark-daltonized.json +2 -1
- package/dist/ui/theme/dark.json +2 -1
- package/dist/ui/theme/light-ansi.json +2 -1
- package/dist/ui/theme/light-daltonized.json +2 -1
- package/dist/ui/theme/light.json +2 -1
- package/dist/ui/theme/theme.d.ts +1 -0
- package/dist/ui/theme/theme.d.ts.map +1 -1
- package/package.json +3 -3
|
@@ -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,
|
|
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 @@
|
|
|
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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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { LanguageId } from "../language-detector.js";
|
|
2
|
+
/**
|
|
3
|
+
* Load the style-pack content for a given language. Checks for a per-project
|
|
4
|
+
* override at `<cwd>/.gg/styles/<id>.md` first, falling back to the bundled
|
|
5
|
+
* pack. Returns `null` if neither exists (defensive — should not happen for
|
|
6
|
+
* any LanguageId in PACKS).
|
|
7
|
+
*/
|
|
8
|
+
export declare function loadPack(id: LanguageId, cwd: string): string | null;
|
|
9
|
+
/**
|
|
10
|
+
* Render the full "Language Style Packs" section that gets spliced into the
|
|
11
|
+
* system prompt. Returns an empty string when the active set is empty so the
|
|
12
|
+
* caller can skip the section entirely.
|
|
13
|
+
*
|
|
14
|
+
* The output is intentionally compact: a single header followed by each pack
|
|
15
|
+
* separated by a blank line. Packs already include their own \`### <Language>\`
|
|
16
|
+
* sub-headers.
|
|
17
|
+
*/
|
|
18
|
+
export declare function renderStylePacksSection(active: Set<LanguageId>, cwd: string): string;
|
|
19
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/style-packs/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAI1D;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,EAAE,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAWnE;AAED;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,GAAG,CAAC,UAAU,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAepF"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { languagesToSortedArray } from "../language-detector.js";
|
|
4
|
+
import { PACKS } from "./packs.js";
|
|
5
|
+
/**
|
|
6
|
+
* Load the style-pack content for a given language. Checks for a per-project
|
|
7
|
+
* override at `<cwd>/.gg/styles/<id>.md` first, falling back to the bundled
|
|
8
|
+
* pack. Returns `null` if neither exists (defensive — should not happen for
|
|
9
|
+
* any LanguageId in PACKS).
|
|
10
|
+
*/
|
|
11
|
+
export function loadPack(id, cwd) {
|
|
12
|
+
const overridePath = path.join(cwd, ".gg", "styles", `${id}.md`);
|
|
13
|
+
try {
|
|
14
|
+
const stat = fs.statSync(overridePath);
|
|
15
|
+
if (stat.isFile()) {
|
|
16
|
+
return fs.readFileSync(overridePath, "utf-8").trim();
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
/* no override — fall through to bundled */
|
|
21
|
+
}
|
|
22
|
+
return PACKS[id] ?? null;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Render the full "Language Style Packs" section that gets spliced into the
|
|
26
|
+
* system prompt. Returns an empty string when the active set is empty so the
|
|
27
|
+
* caller can skip the section entirely.
|
|
28
|
+
*
|
|
29
|
+
* The output is intentionally compact: a single header followed by each pack
|
|
30
|
+
* separated by a blank line. Packs already include their own \`### <Language>\`
|
|
31
|
+
* sub-headers.
|
|
32
|
+
*/
|
|
33
|
+
export function renderStylePacksSection(active, cwd) {
|
|
34
|
+
if (active.size === 0)
|
|
35
|
+
return "";
|
|
36
|
+
const ids = languagesToSortedArray(active);
|
|
37
|
+
const parts = [];
|
|
38
|
+
for (const id of ids) {
|
|
39
|
+
const pack = loadPack(id, cwd);
|
|
40
|
+
if (pack)
|
|
41
|
+
parts.push(pack);
|
|
42
|
+
}
|
|
43
|
+
if (parts.length === 0)
|
|
44
|
+
return "";
|
|
45
|
+
return (`## Language Style Packs\n\n` +
|
|
46
|
+
`Conventions for new code in each active language. Library names below are ` +
|
|
47
|
+
`illustrative — use whatever the project already imports.\n\n` +
|
|
48
|
+
parts.join("\n\n"));
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/core/style-packs/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AACjE,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAEnC;;;;;GAKG;AACH,MAAM,UAAU,QAAQ,CAAC,EAAc,EAAE,GAAW;IAClD,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;IACjE,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;QACvC,IAAI,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC;YAClB,OAAO,EAAE,CAAC,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;QACvD,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,2CAA2C;IAC7C,CAAC;IACD,OAAO,KAAK,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC;AAC3B,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,uBAAuB,CAAC,MAAuB,EAAE,GAAW;IAC1E,IAAI,MAAM,CAAC,IAAI,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IACjC,MAAM,GAAG,GAAG,sBAAsB,CAAC,MAAM,CAAC,CAAC;IAC3C,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,EAAE,IAAI,GAAG,EAAE,CAAC;QACrB,MAAM,IAAI,GAAG,QAAQ,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;QAC/B,IAAI,IAAI;YAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC7B,CAAC;IACD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAClC,OAAO,CACL,6BAA6B;QAC7B,4EAA4E;QAC5E,8DAA8D;QAC9D,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CACnB,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { LanguageId } from "../language-detector.js";
|
|
2
|
+
/**
|
|
3
|
+
* Per-language style packs injected into the system prompt when the detector
|
|
4
|
+
* sees the language is active in the project.
|
|
5
|
+
*
|
|
6
|
+
* Design principles (apply to every pack):
|
|
7
|
+
* 1. Apply the strictest reasonable subset of *idiomatic* style — nothing
|
|
8
|
+
* exotic the model has to think about. The agent already knows these
|
|
9
|
+
* patterns; the pack just narrows the choice space.
|
|
10
|
+
* 2. Optimize for low ambiguity, not for human readability. Bullet form.
|
|
11
|
+
* 3. Errors as values, schema at boundaries, mechanical formatting,
|
|
12
|
+
* one canonical way to do common tasks.
|
|
13
|
+
* 4. ~30-50 lines per pack. Anything longer is bloat in the system prompt.
|
|
14
|
+
* 5. Avoid triple backticks (template literal conflict). Use single
|
|
15
|
+
* backticks for inline tokens, escape with \\\` when needed.
|
|
16
|
+
*/
|
|
17
|
+
export declare const PACKS: Readonly<Record<LanguageId, string>>;
|
|
18
|
+
//# sourceMappingURL=packs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"packs.d.ts","sourceRoot":"","sources":["../../../src/core/style-packs/packs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAE1D;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,CA2OtD,CAAC"}
|