@prestyj/cli 4.3.160 → 4.3.164
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 +13 -0
- package/dist/core/setup-history.d.ts.map +1 -0
- package/dist/core/setup-history.js +71 -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 +74 -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 +70 -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 +229 -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 +32 -5
- package/dist/system-prompt.js.map +1 -1
- package/dist/tools/prompt-hints.js +1 -1
- package/dist/tools/prompt-hints.js.map +1 -1
- package/dist/ui/App.d.ts +23 -1
- package/dist/ui/App.d.ts.map +1 -1
- package/dist/ui/App.js +227 -15
- package/dist/ui/App.js.map +1 -1
- package/dist/ui/pixel.test.js +1 -1
- package/dist/ui/pixel.test.js.map +1 -1
- package/dist/ui/render.d.ts +8 -0
- package/dist/ui/render.d.ts.map +1 -1
- package/dist/ui/render.js +2 -0
- package/dist/ui/render.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 per-language sub-sections inside the **Language Style Packs** section in your system prompt (e.g. \`### TypeScript\`, \`### Python\`, \`### Go\`). It does **NOT** include the cross-cutting \`### Agent-Written Code\` preamble that sits above them — those are guidelines for how code is *written*, not project-scaffolding to audit. It also does **NOT** include Skills (\`.ezcoder/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 per-language 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]\`, Go project missing \`golangci-lint\` config).
|
|
891
|
+
- Dependencies: list which pack-mentioned libs (Zod, Pydantic, thiserror, anyhow, 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,13 @@
|
|
|
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
|
+
/** Returns the language ids that have already been announced via the
|
|
8
|
+
* "STYLE PACK ACTIVE" badge for this cwd. */
|
|
9
|
+
export declare function getAnnouncedLanguages(cwd: string): string[];
|
|
10
|
+
/** Add language ids to the announced set for this cwd. No-op if the input
|
|
11
|
+
* is empty or adds nothing new. */
|
|
12
|
+
export declare function markLanguagesAnnounced(cwd: string, langs: readonly string[]): void;
|
|
13
|
+
//# 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":"AAiDA,wEAAwE;AACxE,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAGrD;AAED;;sCAEsC;AACtC,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAKlD;AAED;8CAC8C;AAC9C,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAG3D;AAED;oCACoC;AACpC,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,CASlF"}
|
|
@@ -0,0 +1,71 @@
|
|
|
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(), ".ezcoder", "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 `~/.ezcoder/setup-history.json`. Keys are absolute cwd paths. The file
|
|
11
|
+
* is small (one line per project the user has ever opened with ezcoder) 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]?.lastAuditedAt === 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
|
+
const existing = history[cwd] ?? {};
|
|
48
|
+
history[cwd] = { ...existing, lastAuditedAt: new Date().toISOString() };
|
|
49
|
+
writeHistory(history);
|
|
50
|
+
}
|
|
51
|
+
/** Returns the language ids that have already been announced via the
|
|
52
|
+
* "STYLE PACK ACTIVE" badge for this cwd. */
|
|
53
|
+
export function getAnnouncedLanguages(cwd) {
|
|
54
|
+
const history = readHistory();
|
|
55
|
+
return history[cwd]?.announcedLanguages ?? [];
|
|
56
|
+
}
|
|
57
|
+
/** Add language ids to the announced set for this cwd. No-op if the input
|
|
58
|
+
* is empty or adds nothing new. */
|
|
59
|
+
export function markLanguagesAnnounced(cwd, langs) {
|
|
60
|
+
if (langs.length === 0)
|
|
61
|
+
return;
|
|
62
|
+
const history = readHistory();
|
|
63
|
+
const existing = history[cwd] ?? {};
|
|
64
|
+
const prev = existing.announcedLanguages ?? [];
|
|
65
|
+
const merged = Array.from(new Set([...prev, ...langs]));
|
|
66
|
+
if (merged.length === prev.length)
|
|
67
|
+
return;
|
|
68
|
+
history[cwd] = { ...existing, announcedLanguages: merged };
|
|
69
|
+
writeHistory(history);
|
|
70
|
+
}
|
|
71
|
+
//# 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,UAAU,EAAE,oBAAoB,CAAC,CAAC;AAa/E;;;;;;;;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,EAAE,aAAa,KAAK,SAAS,CAAC;AACnD,CAAC;AAED;;sCAEsC;AACtC,MAAM,UAAU,gBAAgB,CAAC,GAAW;IAC1C,MAAM,OAAO,GAAG,WAAW,EAAE,CAAC;IAC9B,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;IACpC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,QAAQ,EAAE,aAAa,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC;IACxE,YAAY,CAAC,OAAO,CAAC,CAAC;AACxB,CAAC;AAED;8CAC8C;AAC9C,MAAM,UAAU,qBAAqB,CAAC,GAAW;IAC/C,MAAM,OAAO,GAAG,WAAW,EAAE,CAAC;IAC9B,OAAO,OAAO,CAAC,GAAG,CAAC,EAAE,kBAAkB,IAAI,EAAE,CAAC;AAChD,CAAC;AAED;oCACoC;AACpC,MAAM,UAAU,sBAAsB,CAAC,GAAW,EAAE,KAAwB;IAC1E,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO;IAC/B,MAAM,OAAO,GAAG,WAAW,EAAE,CAAC;IAC9B,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;IACpC,MAAM,IAAI,GAAG,QAAQ,CAAC,kBAAkB,IAAI,EAAE,CAAC;IAC/C,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,IAAI,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IACxD,IAAI,MAAM,CAAC,MAAM,KAAK,IAAI,CAAC,MAAM;QAAE,OAAO;IAC1C,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,QAAQ,EAAE,kBAAkB,EAAE,MAAM,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,74 @@
|
|
|
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, ".ezcoder");
|
|
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
|
+
it("getAnnouncedLanguages returns [] when never announced", async () => {
|
|
48
|
+
const { getAnnouncedLanguages } = await loadModule();
|
|
49
|
+
expect(getAnnouncedLanguages("/tmp/fresh")).toEqual([]);
|
|
50
|
+
});
|
|
51
|
+
it("markLanguagesAnnounced persists and dedupes across calls", async () => {
|
|
52
|
+
const { getAnnouncedLanguages, markLanguagesAnnounced } = await loadModule();
|
|
53
|
+
const cwd = "/tmp/proj";
|
|
54
|
+
markLanguagesAnnounced(cwd, ["typescript"]);
|
|
55
|
+
expect(getAnnouncedLanguages(cwd)).toEqual(["typescript"]);
|
|
56
|
+
markLanguagesAnnounced(cwd, ["typescript", "rust"]);
|
|
57
|
+
expect(getAnnouncedLanguages(cwd).sort()).toEqual(["rust", "typescript"]);
|
|
58
|
+
});
|
|
59
|
+
it("markLanguagesAnnounced and markSetupAudited coexist without clobbering", async () => {
|
|
60
|
+
const { isFirstTimeSetup, markSetupAudited, getAnnouncedLanguages, markLanguagesAnnounced } = await loadModule();
|
|
61
|
+
const cwd = "/tmp/coexist";
|
|
62
|
+
markLanguagesAnnounced(cwd, ["python"]);
|
|
63
|
+
expect(isFirstTimeSetup(cwd)).toBe(true);
|
|
64
|
+
markSetupAudited(cwd);
|
|
65
|
+
expect(isFirstTimeSetup(cwd)).toBe(false);
|
|
66
|
+
expect(getAnnouncedLanguages(cwd)).toEqual(["python"]);
|
|
67
|
+
});
|
|
68
|
+
it("markLanguagesAnnounced is a no-op for empty input", async () => {
|
|
69
|
+
const { getAnnouncedLanguages, markLanguagesAnnounced } = await loadModule();
|
|
70
|
+
markLanguagesAnnounced("/tmp/noop", []);
|
|
71
|
+
expect(getAnnouncedLanguages("/tmp/noop")).toEqual([]);
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
//# 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>/.ezcoder/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,CAgBpF"}
|
|
@@ -0,0 +1,70 @@
|
|
|
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>/.ezcoder/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, ".ezcoder", "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
|
+
`${AGENT_WRITTEN_CODE_PREAMBLE}\n\n` +
|
|
49
|
+
parts.join("\n\n"));
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Cross-cutting rules that apply to every language pack. These are agent-native
|
|
53
|
+
* concerns (determinism, observability, no hidden state, output stability) that
|
|
54
|
+
* matter more for code written *by* and *read by* agents than for human-only
|
|
55
|
+
* codebases. Kept terse — every line is a load-bearing constraint, not advice.
|
|
56
|
+
*
|
|
57
|
+
* Lives in the system prompt above the per-language packs so the model reads
|
|
58
|
+
* universal rules first, then specializes per language.
|
|
59
|
+
*/
|
|
60
|
+
const AGENT_WRITTEN_CODE_PREAMBLE = `### Agent-Written Code (cross-cutting)
|
|
61
|
+
|
|
62
|
+
Universal rules — apply to every language below.
|
|
63
|
+
|
|
64
|
+
- **Observability at boundaries.** Structured logging (key/value pairs, not string interpolation) at every external I/O — HTTP calls, DB queries, file reads, subprocess runs. Log inputs, outcome, and elapsed time. Use the language's stdlib or canonical structured logger (\`log/slog\`, \`tracing\`, \`structlog\`, Pino, \`Microsoft.Extensions.Logging\`, etc.). Never leave \`console.log\`/\`print\`/\`fmt.Println\` debugging in committed code.
|
|
65
|
+
- **Determinism by default.** Sort before iterating maps/sets where output order is observable. Stable IDs (UUIDv7, ULID, or content hash) — never \`random + timestamp\`. Never read wall-clock time inside pure logic; inject a clock at the boundary. Use canonical-form serialization (sorted keys) for anything that gets compared, hashed, persisted, or diffed.
|
|
66
|
+
- **No hidden state.** No module-level mutables, no global singletons as the primary state container, no implicit DI through container magic. Pass dependencies explicitly through function signatures or constructors. State that escapes the signature is invisible at the call site, which means invisible to the agent reading it later.
|
|
67
|
+
- **Local verifiability.** A function should be small enough that its correctness is confirmable by reading it plus its direct callers — not by tracing through four layers of indirection. Prefer composing small pure functions over deep class hierarchies. The agent will re-read this code; optimize for that.
|
|
68
|
+
- **Tests pin behavior, not implementation.** Arrange-Act-Assert with each phase visible. No shared mutable fixtures across tests. Each test runnable independently in any order. Table-driven when there's a clear input→output mapping. A test that breaks on a refactor without a behavior change is a bad test.
|
|
69
|
+
- **Fail loudly at boundaries, handle locally inside.** Validate untrusted input the moment it crosses into your code (per the per-language Data rules). Once validated, interior code trusts the types. Errors as values for the local-handling half — see each pack's Errors rule.`;
|
|
70
|
+
//# 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,UAAU,EAAE,QAAQ,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;IACtE,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,GAAG,2BAA2B,MAAM;QACpC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CACnB,CAAC;AACJ,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,2BAA2B,GAAG;;;;;;;;;qRASiP,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,CA4OtD,CAAC"}
|