ts-reviewer 1.2.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +70 -28
- package/dist/cli.js +10 -12
- package/dist/cli.js.map +1 -1
- package/dist/hash.js +3 -9
- package/dist/hash.js.map +1 -1
- package/dist/incoming.js +9 -15
- package/dist/incoming.js.map +1 -1
- package/dist/index.js +24 -30
- package/dist/index.js.map +1 -1
- package/dist/io.js +12 -20
- package/dist/io.js.map +1 -1
- package/dist/meta.js +5 -12
- package/dist/meta.js.map +1 -1
- package/dist/paths.js +17 -24
- package/dist/paths.js.map +1 -1
- package/dist/prompt.js +17 -23
- package/dist/prompt.js.map +1 -1
- package/dist/updatePolicy.js +1 -4
- package/dist/updatePolicy.js.map +1 -1
- package/package.json +6 -5
- package/ts-reviewer/SKILL.md +177 -318
- package/ts-reviewer/references/architecture.md +84 -140
- package/ts-reviewer/references/async-patterns.md +46 -106
- package/ts-reviewer/references/boundary-validation.md +29 -56
- package/ts-reviewer/references/code-quality.md +63 -112
- package/ts-reviewer/references/dependency-hygiene.md +31 -47
- package/ts-reviewer/references/error-handling.md +27 -49
- package/ts-reviewer/references/fix-workflow.md +92 -295
- package/ts-reviewer/references/modernization.md +58 -138
- package/ts-reviewer/references/security.md +56 -118
- package/ts-reviewer/references/tsconfig.md +42 -92
- package/ts-reviewer/references/type-safety.md +66 -148
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
An AI skill for deep code review and auto-fix of pure TypeScript codebases. Finds bugs, type safety holes, security vulnerabilities, async anti-patterns, outdated practices, and code smells — then fixes them with regression tests and verification.
|
|
4
4
|
|
|
5
|
-
Built for **TypeScript 5.9
|
|
5
|
+
Built for one fixed stack — **TypeScript 5.9.x, ES2024, Node 24** — without any framework-specific checks (no React, Vue, Angular, etc.). Anything below the stack is a finding, anything above it is never recommended.
|
|
6
6
|
|
|
7
7
|
## What It Does
|
|
8
8
|
|
|
@@ -14,17 +14,20 @@ Three modes, one skill:
|
|
|
14
14
|
| **fix** | Reads the report and applies fixes file-by-file with tsc/lint/test verification |
|
|
15
15
|
| **auto** | Runs scan, asks you to confirm, fixes everything, deletes the report if clean |
|
|
16
16
|
|
|
17
|
-
The review covers
|
|
17
|
+
The review covers nine domains by default, each with its own detailed checklist. Add `--arch` or `--full` to include architecture analysis:
|
|
18
18
|
|
|
19
19
|
| Domain | Examples | Default |
|
|
20
20
|
|---|---|---|
|
|
21
|
-
| **Type Safety** | `any` abuse, unsafe casts, non-null assertions, missing exhaustive checks | ✓ |
|
|
22
|
-
| **Security** | Injection, prototype pollution, ReDoS, path traversal, hardcoded secrets | ✓ |
|
|
23
|
-
| **Async Patterns** | Floating promises, race conditions, missing
|
|
24
|
-
| **Modernization** |
|
|
25
|
-
| **Code Quality** | Dead code, complexity, duplication,
|
|
26
|
-
| **Config** | tsconfig.json strict flags, module resolution, deprecated options | ✓ |
|
|
27
|
-
| **
|
|
21
|
+
| **Type Safety** | `any` abuse, unsafe casts, non-null assertions, `unknown` discipline, missing exhaustive checks | ✓ |
|
|
22
|
+
| **Security** | Injection, SSRF, prototype pollution, ReDoS, path traversal, hardcoded secrets | ✓ |
|
|
23
|
+
| **Async Patterns** | Floating promises, race conditions, missing timeouts, unbounded concurrency, `forEach(async...)` | ✓ |
|
|
24
|
+
| **Modernization** | Numeric enums, `\|\|` vs `??`, mutating array methods, `satisfies`, `using` keyword | ✓ |
|
|
25
|
+
| **Code Quality** | Dead code, complexity, duplication, debug artifacts, import-time side effects, testability | ✓ |
|
|
26
|
+
| **Config** | tsconfig.json strict flags, target/lib, module resolution, deprecated options | ✓ |
|
|
27
|
+
| **Boundary Validation** | `as T` on `JSON.parse`/`fetch`/env, DTO vs domain model separation, contract drift | ✓ |
|
|
28
|
+
| **Error Handling** | Silent failures, throw hygiene, `cause` chaining, failure design at API seams | ✓ |
|
|
29
|
+
| **Dependency Hygiene** | Lockfiles, wildcard versions, `npm audit`, duplicate-purpose and trivial deps | ✓ |
|
|
30
|
+
| **Architecture** | Shallow modules, scattered concepts, tight coupling, dependency direction, layering | `--arch` / `--full` |
|
|
28
31
|
|
|
29
32
|
## Installation
|
|
30
33
|
|
|
@@ -40,8 +43,8 @@ The installer prints a short summary before installation:
|
|
|
40
43
|
|
|
41
44
|
```text
|
|
42
45
|
TypeScript Code Reviewer
|
|
43
|
-
Checks: type safety, async patterns,
|
|
44
|
-
Target
|
|
46
|
+
Checks: type safety, security, async patterns, boundary validation, error handling, modernization, code quality, tsconfig, dependency hygiene
|
|
47
|
+
Target stack: TypeScript 5.9.x, ES2024, Node 24
|
|
45
48
|
```
|
|
46
49
|
|
|
47
50
|
Then it asks which AI agents to install for. Use Up/Down arrows to move, Space to toggle, and Enter to confirm.
|
|
@@ -51,9 +54,11 @@ Supported targets:
|
|
|
51
54
|
| AI agent | Install path |
|
|
52
55
|
|---|---|
|
|
53
56
|
| Claude Code | `.claude/skills/ts-reviewer/` |
|
|
54
|
-
| Codex | `.
|
|
57
|
+
| Codex | `.agents/skills/ts-reviewer/` |
|
|
55
58
|
| Antigravity | `.agent/skills/ts-reviewer/` |
|
|
56
59
|
|
|
60
|
+
> **Note on Codex:** project-local skills belong in `.agents/` per the Codex docs; `~/.codex/` is the *global* per-user directory. Codex also reads a project-local `.codex/` implicitly, so installs from older versions of this installer keep working — but `.agents/` is the correct location going forward.
|
|
61
|
+
|
|
57
62
|
In non-interactive terminals, the installer selects all supported targets.
|
|
58
63
|
|
|
59
64
|
### Manual Install
|
|
@@ -80,13 +85,14 @@ Claude will analyze the project and write a report to `code-smells.md` in the pr
|
|
|
80
85
|
|
|
81
86
|
#### Domain flags
|
|
82
87
|
|
|
83
|
-
By default, only the
|
|
88
|
+
By default, only the nine core domains run. Use flags to control which domains are active:
|
|
84
89
|
|
|
85
90
|
| Flag | What runs |
|
|
86
91
|
|---|---|
|
|
87
|
-
| *(none)* | Type Safety, Security, Async, Modernization, Code Quality, Config |
|
|
88
|
-
| `--arch` | Architecture only (shallow modules, coupling, dependency seams) |
|
|
89
|
-
| `--full` | All
|
|
92
|
+
| *(none)* | Type Safety, Security, Async, Modernization, Code Quality, Config, Boundary Validation, Error Handling, Dependency Hygiene |
|
|
93
|
+
| `--arch` | Architecture only (shallow modules, coupling, dependency direction, seams) |
|
|
94
|
+
| `--full` | All ten domains |
|
|
95
|
+
| `--no-arch` | The nine core domains — overrides `--arch`, `--full`, and any phrase that would enable architecture |
|
|
90
96
|
|
|
91
97
|
Examples:
|
|
92
98
|
|
|
@@ -140,7 +146,7 @@ By default the entire codebase is reviewed. You can narrow the scope:
|
|
|
140
146
|
| What you say | What gets reviewed |
|
|
141
147
|
|---|---|
|
|
142
148
|
| *"review my code"* | Full codebase |
|
|
143
|
-
| *"review my changes"*, *"check uncommitted"* | Staged + unstaged + untracked `.ts` files |
|
|
149
|
+
| *"review my changes"*, *"check uncommitted"* | Staged + unstaged + untracked `.ts`/`.mts`/`.cts` files |
|
|
144
150
|
| *"review my PR"*, *"diff against main"* | All changes on current branch vs base |
|
|
145
151
|
| *"review last commit"*, *"check last 3 commits"* | Last N commits |
|
|
146
152
|
|
|
@@ -170,21 +176,37 @@ Architecture findings use the same scale. Each candidate also carries a **Fixabi
|
|
|
170
176
|
## Project Structure
|
|
171
177
|
|
|
172
178
|
```
|
|
179
|
+
AGENTS.md # How to edit the review rules — read before changing anything below
|
|
180
|
+
CLAUDE.md # Pointer to AGENTS.md, picked up automatically by Claude Code
|
|
181
|
+
|
|
173
182
|
src/ # npm/npx installer source
|
|
174
183
|
├── cli.ts # CLI entrypoint and provider prompt
|
|
175
184
|
├── prompt.ts # raw-mode keyboard multi-select
|
|
176
185
|
└── paths.ts # target directories and skill asset loading
|
|
177
186
|
|
|
187
|
+
cnlp/ # the CNL-P format the skill files are written in
|
|
188
|
+
├── cnlp-format.md # the standard: forms, line rules, lexicon
|
|
189
|
+
├── cnlp.js # the checker — Node builtins only, no dependencies
|
|
190
|
+
├── skill-format.test.js # the conformance test, run by `npm test`
|
|
191
|
+
└── profiles/ # what each kind of document may contain
|
|
192
|
+
├── skill.md # → ts-reviewer/SKILL.md
|
|
193
|
+
├── reference.md # → ts-reviewer/references/*.md
|
|
194
|
+
├── guide.md # → AGENTS.md
|
|
195
|
+
└── profile.md # → the profiles themselves
|
|
196
|
+
|
|
178
197
|
ts-reviewer/
|
|
179
198
|
├── SKILL.md # Main skill file — mode routing, workflow orchestration
|
|
180
199
|
└── references/
|
|
181
|
-
├── type-safety.md # Checklist: any, casts, !, exhaustiveness,
|
|
182
|
-
├── security.md # Checklist: injection, pollution, ReDoS
|
|
183
|
-
├── async-patterns.md # Checklist: floating promises, races, cancellation
|
|
184
|
-
├──
|
|
185
|
-
├──
|
|
186
|
-
├──
|
|
187
|
-
├──
|
|
200
|
+
├── type-safety.md # Checklist: any, unknown, casts, !, exhaustiveness, branded types
|
|
201
|
+
├── security.md # Checklist: trust boundaries, injection, SSRF, pollution, ReDoS
|
|
202
|
+
├── async-patterns.md # Checklist: floating promises, races, timeouts, retries, cancellation
|
|
203
|
+
├── boundary-validation.md # Checklist: runtime validation at edges, DTO/domain separation
|
|
204
|
+
├── error-handling.md # Checklist: silent failures, throw hygiene, failure design
|
|
205
|
+
├── modernization.md # Checklist: patterns below the stack, ??/?. , satisfies, using, toSorted
|
|
206
|
+
├── code-quality.md # Checklist: complexity, dead code, debug artifacts, testability
|
|
207
|
+
├── tsconfig.md # Checklist: strict flags, target/lib, module resolution, deprecated
|
|
208
|
+
├── dependency-hygiene.md # Checklist: lockfiles, versions, npm audit, dependency choice
|
|
209
|
+
├── architecture.md # Checklist: shallow modules, coupling, dependency direction, seams
|
|
188
210
|
└── fix-workflow.md # Complete fix protocol: tests, verification, rollback
|
|
189
211
|
```
|
|
190
212
|
|
|
@@ -192,14 +214,34 @@ ts-reviewer/
|
|
|
192
214
|
|
|
193
215
|
**Reference files** contain the detailed checklists and protocols. Each analysis agent reads only the reference file relevant to its domain, keeping context focused. Architecture analysis is opt-in and loaded only when the domain is active.
|
|
194
216
|
|
|
217
|
+
## Editing the Rules
|
|
218
|
+
|
|
219
|
+
As of 2.0.0, `SKILL.md` and every reference file are written in **CNL-P** — a block-structured format an agent reads as instructions rather than prose. One rule per line, one term per concept, no headings, a hard 250-character line limit.
|
|
220
|
+
|
|
221
|
+
A check line looks like this:
|
|
222
|
+
|
|
223
|
+
```
|
|
224
|
+
- injection — `eval()` and `new Function()` executing a dynamic string: Highest, use a lookup table, a strategy, or a safe parser
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
The format is enforced, not merely recommended:
|
|
228
|
+
|
|
229
|
+
```bash
|
|
230
|
+
npm test # typecheck + 5 conformance tests
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
The test catches a check line that lost its severity, a block the profile does not declare, blocks out of order, a banned vague word, and a line over the limit — each reported with its file and line number.
|
|
234
|
+
|
|
235
|
+
**Before adding or changing a rule, read [`AGENTS.md`](AGENTS.md).** It states which file owns which domain, the shape of a check line, the severity scale, which block takes what, and the line rules. Claude Code picks this up on its own through `CLAUDE.md`; for another agent, point it at `AGENTS.md` explicitly.
|
|
236
|
+
|
|
195
237
|
## How It Works Under the Hood
|
|
196
238
|
|
|
197
239
|
### Scan mode
|
|
198
240
|
|
|
199
241
|
1. **Discovery** — detects domain flags, maps the project, reads tsconfig.json, detects linter and test runner. If architecture is active, also maps module relationships and checks for `docs/adr/`.
|
|
200
242
|
2. **Diagnostics** — runs `tsc --noEmit`, linter, and LSP diagnostics (if available)
|
|
201
|
-
3. **Analysis** — specialized passes for each active domain (sub-agents in Claude Code, sequential in Claude.ai), each with its own checklist
|
|
202
|
-
4. **Report** — deduplicates, applies severity boost (scoped modes), consolidates recurring patterns, writes `code-smells.md`. Architecture findings appear in a separate `## Architecture Opportunities` section at the end.
|
|
243
|
+
3. **Analysis** — specialized passes for each active domain (sub-agents in Claude Code, sequential in Claude.ai), each with its own checklist. Every finding passes an Evidence Protocol: verified against the actual file content, confidence-gated, version-gated against the project's TS/runtime.
|
|
244
|
+
4. **Report** — deduplicates, applies severity boost (scoped modes), consolidates recurring patterns, enforces a noise budget, writes `code-smells.md`. Architecture findings appear in a separate `## Architecture Opportunities` section at the end.
|
|
203
245
|
|
|
204
246
|
### Fix mode
|
|
205
247
|
|
|
@@ -224,9 +266,9 @@ ts-reviewer/
|
|
|
224
266
|
|
|
225
267
|
## Requirements
|
|
226
268
|
|
|
227
|
-
- TypeScript 5.9
|
|
269
|
+
- TypeScript 5.9.x project targeting ES2024 on Node 24
|
|
228
270
|
- Git repository (for scoped modes and safe revert during fix)
|
|
229
|
-
- Node
|
|
271
|
+
- Node 24 with `npx` available (for tsc, linter)
|
|
230
272
|
- Claude Code (recommended) or any Claude interface with skill support
|
|
231
273
|
|
|
232
274
|
## License
|
package/dist/cli.js
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const prompt_1 = require("./prompt");
|
|
6
|
-
const paths_1 = require("./paths");
|
|
2
|
+
import { scaffoldTsReviewerSkill } from "./index.js";
|
|
3
|
+
import { multiSelect } from "./prompt.js";
|
|
4
|
+
import { AI_PROVIDERS, skillTargetDir } from "./paths.js";
|
|
7
5
|
const SKILL_NAME = "ts-reviewer";
|
|
8
|
-
const
|
|
6
|
+
const TARGET_STACK = "TypeScript 5.9.x, ES2024, Node 24";
|
|
9
7
|
function printHelp() {
|
|
10
8
|
process.stdout.write([
|
|
11
9
|
"ts-reviewer: install TypeScript review skill\n",
|
|
@@ -27,20 +25,20 @@ async function main() {
|
|
|
27
25
|
const skillName = SKILL_NAME;
|
|
28
26
|
process.stdout.write([
|
|
29
27
|
"TypeScript Code Reviewer\n",
|
|
30
|
-
`Checks: type safety, async patterns,
|
|
31
|
-
`Target
|
|
28
|
+
`Checks: type safety, security, async patterns, boundary validation, error handling, modernization, code quality, tsconfig, dependency hygiene\n`,
|
|
29
|
+
`Target stack: ${TARGET_STACK}\n`,
|
|
32
30
|
"\n",
|
|
33
31
|
].join(""));
|
|
34
|
-
const selected = await
|
|
32
|
+
const selected = await multiSelect("Install for which AI agents? (Space = toggle, Enter = confirm)", AI_PROVIDERS);
|
|
35
33
|
if (selected.length === 0) {
|
|
36
34
|
process.stdout.write("No agents selected. Exiting.\n");
|
|
37
35
|
return;
|
|
38
36
|
}
|
|
39
37
|
for (const provider of selected) {
|
|
40
|
-
const targetDir =
|
|
41
|
-
const providerLabel =
|
|
38
|
+
const targetDir = skillTargetDir(cwd, provider, skillName);
|
|
39
|
+
const providerLabel = AI_PROVIDERS.find((p) => p.value === provider).label;
|
|
42
40
|
process.stdout.write(`\n[${providerLabel}]\n`);
|
|
43
|
-
const result = await
|
|
41
|
+
const result = await scaffoldTsReviewerSkill({ cwd, skillName, targetDir });
|
|
44
42
|
for (const e of result.entries) {
|
|
45
43
|
const suffix = e.detail ? ` (${e.detail})` : "";
|
|
46
44
|
process.stdout.write(`${e.action}\t${e.relativePath}${suffix}\n`);
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,YAAY,EAAE,cAAc,EAAmB,MAAM,YAAY,CAAC;AAE3E,MAAM,UAAU,GAAG,aAAa,CAAC;AACjC,MAAM,YAAY,GAAG,mCAAmC,CAAC;AAEzD,SAAS,SAAS;IAChB,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB;QACE,gDAAgD;QAChD,IAAI;QACJ,UAAU;QACV,qBAAqB;QACrB,IAAI;QACJ,YAAY;QACZ,+BAA+B;KAChC,CAAC,IAAI,CAAC,EAAE,CAAC,CACX,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,IAAI;IACjB,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACnC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QACnD,SAAS,EAAE,CAAC;QACZ,OAAO;IACT,CAAC;IAED,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAC1B,MAAM,SAAS,GAAG,UAAU,CAAC;IAE7B,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB;QACE,4BAA4B;QAC5B,iJAAiJ;QACjJ,iBAAiB,YAAY,IAAI;QACjC,IAAI;KACL,CAAC,IAAI,CAAC,EAAE,CAAC,CACX,CAAC;IAEF,MAAM,QAAQ,GAAG,MAAM,WAAW,CAChC,gEAAgE,EAChE,YAAY,CACb,CAAC;IAEF,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,gCAAgC,CAAC,CAAC;QACvD,OAAO;IACT,CAAC;IAED,KAAK,MAAM,QAAQ,IAAI,QAAwB,EAAE,CAAC;QAChD,MAAM,SAAS,GAAG,cAAc,CAAC,GAAG,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC;QAC3D,MAAM,aAAa,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,QAAQ,CAAE,CAAC,KAAK,CAAC;QAE5E,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,aAAa,KAAK,CAAC,CAAC;QAE/C,MAAM,MAAM,GAAG,MAAM,uBAAuB,CAAC,EAAE,GAAG,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC,CAAC;QAE5E,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;YAC/B,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;YAChD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,YAAY,GAAG,MAAM,IAAI,CAAC,CAAC;QACpE,CAAC;QAED,IAAI,MAAM,CAAC,YAAY;YAAE,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;IAChD,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACnB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAE,GAAa,EAAE,KAAK,CAAC,CAAC,CAAC,MAAM,CAAE,GAAa,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;IACzF,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC3B,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;AACvB,CAAC,CAAC,CAAC"}
|
package/dist/hash.js
CHANGED
|
@@ -1,11 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
return (
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.sha256Hex = sha256Hex;
|
|
7
|
-
const node_crypto_1 = __importDefault(require("node:crypto"));
|
|
8
|
-
function sha256Hex(input) {
|
|
9
|
-
return node_crypto_1.default.createHash("sha256").update(input, "utf8").digest("hex");
|
|
1
|
+
import crypto from "node:crypto";
|
|
2
|
+
export function sha256Hex(input) {
|
|
3
|
+
return crypto.createHash("sha256").update(input, "utf8").digest("hex");
|
|
10
4
|
}
|
|
11
5
|
//# sourceMappingURL=hash.js.map
|
package/dist/hash.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hash.js","sourceRoot":"","sources":["../src/hash.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"hash.js","sourceRoot":"","sources":["../src/hash.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,aAAa,CAAC;AAEjC,MAAM,UAAU,SAAS,CAAC,KAAa;IACrC,OAAO,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACzE,CAAC"}
|
package/dist/incoming.js
CHANGED
|
@@ -1,14 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.findAvailableIncomingPath = findAvailableIncomingPath;
|
|
7
|
-
const promises_1 = __importDefault(require("node:fs/promises"));
|
|
8
|
-
const node_path_1 = __importDefault(require("node:path"));
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
9
3
|
async function exists(p) {
|
|
10
4
|
try {
|
|
11
|
-
await
|
|
5
|
+
await fs.stat(p);
|
|
12
6
|
return true;
|
|
13
7
|
}
|
|
14
8
|
catch (e) {
|
|
@@ -17,18 +11,18 @@ async function exists(p) {
|
|
|
17
11
|
throw e;
|
|
18
12
|
}
|
|
19
13
|
}
|
|
20
|
-
async function findAvailableIncomingPath(dstPath) {
|
|
21
|
-
const dir =
|
|
22
|
-
const base =
|
|
23
|
-
const first =
|
|
14
|
+
export async function findAvailableIncomingPath(dstPath) {
|
|
15
|
+
const dir = path.dirname(dstPath);
|
|
16
|
+
const base = path.basename(dstPath);
|
|
17
|
+
const first = path.join(dir, `${base}.incoming`);
|
|
24
18
|
if (!(await exists(first)))
|
|
25
19
|
return first;
|
|
26
20
|
for (let i = 2; i < 1000; i++) {
|
|
27
|
-
const p =
|
|
21
|
+
const p = path.join(dir, `${base}.incoming${i}`);
|
|
28
22
|
if (!(await exists(p)))
|
|
29
23
|
return p;
|
|
30
24
|
}
|
|
31
25
|
// should never happen
|
|
32
|
-
return
|
|
26
|
+
return path.join(dir, `${base}.incoming-${Date.now()}`);
|
|
33
27
|
}
|
|
34
28
|
//# sourceMappingURL=incoming.js.map
|
package/dist/incoming.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"incoming.js","sourceRoot":"","sources":["../src/incoming.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"incoming.js","sourceRoot":"","sources":["../src/incoming.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,KAAK,UAAU,MAAM,CAAC,CAAS;IAC7B,IAAI,CAAC;QACH,MAAM,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACjB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,OAAO,CAAM,EAAE,CAAC;QAChB,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,KAAK,QAAQ;YAAE,OAAO,KAAK,CAAC;QAC3C,MAAM,CAAC,CAAC;IACV,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAAC,OAAe;IAC7D,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAClC,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IAEpC,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,WAAW,CAAC,CAAC;IACjD,IAAI,CAAC,CAAC,MAAM,MAAM,CAAC,KAAK,CAAC,CAAC;QAAE,OAAO,KAAK,CAAC;IAEzC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC;QAC9B,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,YAAY,CAAC,EAAE,CAAC,CAAC;QACjD,IAAI,CAAC,CAAC,MAAM,MAAM,CAAC,CAAC,CAAC,CAAC;YAAE,OAAO,CAAC,CAAC;IACnC,CAAC;IAED,sBAAsB;IACtB,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,aAAa,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;AAC1D,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,41 +1,35 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
};
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const meta_1 = require("./meta");
|
|
10
|
-
const hash_1 = require("./hash");
|
|
11
|
-
const io_1 = require("./io");
|
|
12
|
-
const updatePolicy_1 = require("./updatePolicy");
|
|
13
|
-
const incoming_1 = require("./incoming");
|
|
14
|
-
async function scaffoldTsReviewerSkill(opts) {
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { listSkillAssetTemplates } from "./paths.js";
|
|
3
|
+
import { readMeta, writeMeta } from "./meta.js";
|
|
4
|
+
import { sha256Hex } from "./hash.js";
|
|
5
|
+
import { ensureDir, readFileIfExists, atomicWriteFile } from "./io.js";
|
|
6
|
+
import { decideUpdate } from "./updatePolicy.js";
|
|
7
|
+
import { findAvailableIncomingPath } from "./incoming.js";
|
|
8
|
+
export async function scaffoldTsReviewerSkill(opts) {
|
|
15
9
|
const skillName = opts.skillName;
|
|
16
10
|
const targetDir = opts.targetDir;
|
|
17
|
-
await
|
|
18
|
-
const metaPath =
|
|
19
|
-
const meta = (await
|
|
11
|
+
await ensureDir(targetDir);
|
|
12
|
+
const metaPath = path.join(targetDir, ".scaffold-meta.json");
|
|
13
|
+
const meta = (await readMeta(metaPath)) ?? { version: 1, files: {} };
|
|
20
14
|
const entries = [];
|
|
21
15
|
let hadConflicts = false;
|
|
22
|
-
for (const t of
|
|
23
|
-
const relativePath =
|
|
24
|
-
const dstPath =
|
|
16
|
+
for (const t of listSkillAssetTemplates(skillName)) {
|
|
17
|
+
const relativePath = path.relative(opts.cwd, path.join(targetDir, t.fileName)).replace(/\\/g, "/");
|
|
18
|
+
const dstPath = path.join(targetDir, t.fileName);
|
|
25
19
|
const desired = t.content;
|
|
26
|
-
const desiredHash =
|
|
27
|
-
const existing = await
|
|
28
|
-
const existingHash = existing === null ? null :
|
|
20
|
+
const desiredHash = sha256Hex(desired);
|
|
21
|
+
const existing = await readFileIfExists(dstPath);
|
|
22
|
+
const existingHash = existing === null ? null : sha256Hex(existing);
|
|
29
23
|
const lastWrittenHash = meta.files[t.fileName]?.lastWrittenHash ?? null;
|
|
30
|
-
const decision =
|
|
24
|
+
const decision = decideUpdate({ existingHash, lastWrittenHash });
|
|
31
25
|
if (decision.kind === "write") {
|
|
32
|
-
await
|
|
26
|
+
await atomicWriteFile(dstPath, desired);
|
|
33
27
|
meta.files[t.fileName] = { lastWrittenHash: desiredHash };
|
|
34
28
|
entries.push({ action: "WROTE", relativePath });
|
|
35
29
|
continue;
|
|
36
30
|
}
|
|
37
31
|
if (decision.kind === "overwrite") {
|
|
38
|
-
await
|
|
32
|
+
await atomicWriteFile(dstPath, desired);
|
|
39
33
|
meta.files[t.fileName] = { lastWrittenHash: desiredHash };
|
|
40
34
|
entries.push({ action: "UPDATED", relativePath });
|
|
41
35
|
continue;
|
|
@@ -46,15 +40,15 @@ async function scaffoldTsReviewerSkill(opts) {
|
|
|
46
40
|
}
|
|
47
41
|
// conflict
|
|
48
42
|
hadConflicts = true;
|
|
49
|
-
const incomingPath = await
|
|
50
|
-
await
|
|
43
|
+
const incomingPath = await findAvailableIncomingPath(dstPath);
|
|
44
|
+
await atomicWriteFile(incomingPath, desired);
|
|
51
45
|
entries.push({
|
|
52
46
|
action: "CONFLICT",
|
|
53
47
|
relativePath,
|
|
54
|
-
detail:
|
|
48
|
+
detail: path.basename(incomingPath),
|
|
55
49
|
});
|
|
56
50
|
}
|
|
57
|
-
await
|
|
51
|
+
await writeMeta(metaPath, meta);
|
|
58
52
|
return { entries, hadConflicts };
|
|
59
53
|
}
|
|
60
54
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/io.js
CHANGED
|
@@ -1,19 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.ensureDir = ensureDir;
|
|
7
|
-
exports.readFileIfExists = readFileIfExists;
|
|
8
|
-
exports.atomicWriteFile = atomicWriteFile;
|
|
9
|
-
const promises_1 = __importDefault(require("node:fs/promises"));
|
|
10
|
-
const node_path_1 = __importDefault(require("node:path"));
|
|
11
|
-
async function ensureDir(dirPath) {
|
|
12
|
-
await promises_1.default.mkdir(dirPath, { recursive: true });
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
export async function ensureDir(dirPath) {
|
|
4
|
+
await fs.mkdir(dirPath, { recursive: true });
|
|
13
5
|
}
|
|
14
|
-
async function readFileIfExists(filePath) {
|
|
6
|
+
export async function readFileIfExists(filePath) {
|
|
15
7
|
try {
|
|
16
|
-
return await
|
|
8
|
+
return await fs.readFile(filePath, "utf8");
|
|
17
9
|
}
|
|
18
10
|
catch (e) {
|
|
19
11
|
if (e && (e.code === "ENOENT" || e.code === "ENOTDIR"))
|
|
@@ -21,19 +13,19 @@ async function readFileIfExists(filePath) {
|
|
|
21
13
|
throw e;
|
|
22
14
|
}
|
|
23
15
|
}
|
|
24
|
-
async function atomicWriteFile(filePath, content) {
|
|
25
|
-
const dir =
|
|
16
|
+
export async function atomicWriteFile(filePath, content) {
|
|
17
|
+
const dir = path.dirname(filePath);
|
|
26
18
|
await ensureDir(dir);
|
|
27
|
-
const tmp =
|
|
28
|
-
await
|
|
19
|
+
const tmp = path.join(dir, `.${path.basename(filePath)}.tmp-${process.pid}-${Date.now()}`);
|
|
20
|
+
await fs.writeFile(tmp, content, "utf8");
|
|
29
21
|
try {
|
|
30
22
|
// Windows cannot atomically replace existing; remove first.
|
|
31
|
-
await
|
|
23
|
+
await fs.unlink(filePath);
|
|
32
24
|
}
|
|
33
25
|
catch (e) {
|
|
34
26
|
if (!(e && e.code === "ENOENT"))
|
|
35
27
|
throw e;
|
|
36
28
|
}
|
|
37
|
-
await
|
|
29
|
+
await fs.rename(tmp, filePath);
|
|
38
30
|
}
|
|
39
31
|
//# sourceMappingURL=io.js.map
|
package/dist/io.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"io.js","sourceRoot":"","sources":["../src/io.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"io.js","sourceRoot":"","sources":["../src/io.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,OAAe;IAC7C,MAAM,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;AAC/C,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,QAAgB;IACrD,IAAI,CAAC;QACH,OAAO,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IAC7C,CAAC;IAAC,OAAO,CAAM,EAAE,CAAC;QAChB,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,KAAK,QAAQ,IAAI,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC;YAAE,OAAO,IAAI,CAAC;QACpE,MAAM,CAAC,CAAC;IACV,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,QAAgB,EAAE,OAAe;IACrE,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACnC,MAAM,SAAS,CAAC,GAAG,CAAC,CAAC;IAErB,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,QAAQ,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IAC3F,MAAM,EAAE,CAAC,SAAS,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;IAEzC,IAAI,CAAC;QACH,4DAA4D;QAC5D,MAAM,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAC5B,CAAC;IAAC,OAAO,CAAM,EAAE,CAAC;QAChB,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC;YAAE,MAAM,CAAC,CAAC;IAC3C,CAAC;IAED,MAAM,EAAE,CAAC,MAAM,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;AACjC,CAAC"}
|
package/dist/meta.js
CHANGED
|
@@ -1,14 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.readMeta = readMeta;
|
|
7
|
-
exports.writeMeta = writeMeta;
|
|
8
|
-
const promises_1 = __importDefault(require("node:fs/promises"));
|
|
9
|
-
async function readMeta(metaPath) {
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
export async function readMeta(metaPath) {
|
|
10
3
|
try {
|
|
11
|
-
const raw = await
|
|
4
|
+
const raw = await fs.readFile(metaPath, "utf8");
|
|
12
5
|
const parsed = JSON.parse(raw);
|
|
13
6
|
if (!parsed || parsed.version !== 1 || typeof parsed.files !== "object")
|
|
14
7
|
return null;
|
|
@@ -20,8 +13,8 @@ async function readMeta(metaPath) {
|
|
|
20
13
|
throw e;
|
|
21
14
|
}
|
|
22
15
|
}
|
|
23
|
-
async function writeMeta(metaPath, meta) {
|
|
16
|
+
export async function writeMeta(metaPath, meta) {
|
|
24
17
|
const body = JSON.stringify(meta, null, 2) + "\n";
|
|
25
|
-
await
|
|
18
|
+
await fs.writeFile(metaPath, body, "utf8");
|
|
26
19
|
}
|
|
27
20
|
//# sourceMappingURL=meta.js.map
|
package/dist/meta.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"meta.js","sourceRoot":"","sources":["../src/meta.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"meta.js","sourceRoot":"","sources":["../src/meta.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAOlC,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,QAAgB;IAC7C,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QAChD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC/B,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,OAAO,KAAK,CAAC,IAAI,OAAO,MAAM,CAAC,KAAK,KAAK,QAAQ;YAAE,OAAO,IAAI,CAAC;QACrF,OAAO,MAAsB,CAAC;IAChC,CAAC;IAAC,OAAO,CAAM,EAAE,CAAC;QAChB,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,KAAK,QAAQ;YAAE,OAAO,IAAI,CAAC;QAC1C,MAAM,CAAC,CAAC;IACV,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,QAAgB,EAAE,IAAkB;IAClE,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC;IAClD,MAAM,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;AAC7C,CAAC"}
|
package/dist/paths.js
CHANGED
|
@@ -1,54 +1,47 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.AI_PROVIDERS = void 0;
|
|
7
|
-
exports.skillTargetDir = skillTargetDir;
|
|
8
|
-
exports.skillAssetsDir = skillAssetsDir;
|
|
9
|
-
exports.listSkillAssetTemplates = listSkillAssetTemplates;
|
|
10
|
-
const node_fs_1 = __importDefault(require("node:fs"));
|
|
11
|
-
const node_path_1 = __importDefault(require("node:path"));
|
|
12
|
-
exports.AI_PROVIDERS = [
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
export const AI_PROVIDERS = [
|
|
13
4
|
{ label: "Claude Code", value: "claude-code" },
|
|
14
5
|
{ label: "Codex", value: "codex" },
|
|
15
6
|
{ label: "Antigravity", value: "antigravity" },
|
|
16
7
|
];
|
|
17
8
|
const PROVIDER_BASE = {
|
|
18
9
|
"claude-code": ".claude",
|
|
19
|
-
"
|
|
10
|
+
// Project-local Codex skills belong in ".agents"; "~/.codex" is the global user dir.
|
|
11
|
+
// Codex also reads ".codex" implicitly, but ".agents" is the documented location.
|
|
12
|
+
"codex": ".agents",
|
|
20
13
|
"antigravity": ".agent",
|
|
21
14
|
};
|
|
22
|
-
function skillTargetDir(projectRoot, provider, skillName) {
|
|
23
|
-
return
|
|
15
|
+
export function skillTargetDir(projectRoot, provider, skillName) {
|
|
16
|
+
return path.join(projectRoot, PROVIDER_BASE[provider], "skills", skillName);
|
|
24
17
|
}
|
|
25
18
|
function packageRootDir() {
|
|
26
19
|
// dist/* at runtime; src/* in dev. In both cases, package root is one level up.
|
|
27
|
-
return
|
|
20
|
+
return path.resolve(import.meta.dirname, "..");
|
|
28
21
|
}
|
|
29
|
-
function skillAssetsDir(skillName) {
|
|
30
|
-
return
|
|
22
|
+
export function skillAssetsDir(skillName) {
|
|
23
|
+
return path.join(packageRootDir(), skillName);
|
|
31
24
|
}
|
|
32
25
|
function readAsset(skillName, fileName) {
|
|
33
|
-
const p =
|
|
34
|
-
return
|
|
26
|
+
const p = path.join(skillAssetsDir(skillName), fileName);
|
|
27
|
+
return fs.readFileSync(p, "utf8");
|
|
35
28
|
}
|
|
36
29
|
function walkAssetFiles(rootDir, currentDir = rootDir) {
|
|
37
|
-
const entries =
|
|
30
|
+
const entries = fs.readdirSync(currentDir, { withFileTypes: true });
|
|
38
31
|
const files = [];
|
|
39
32
|
for (const entry of entries) {
|
|
40
|
-
const absolutePath =
|
|
33
|
+
const absolutePath = path.join(currentDir, entry.name);
|
|
41
34
|
if (entry.isDirectory()) {
|
|
42
35
|
files.push(...walkAssetFiles(rootDir, absolutePath));
|
|
43
36
|
continue;
|
|
44
37
|
}
|
|
45
38
|
if (entry.isFile()) {
|
|
46
|
-
files.push(
|
|
39
|
+
files.push(path.relative(rootDir, absolutePath).replace(/\\/g, "/"));
|
|
47
40
|
}
|
|
48
41
|
}
|
|
49
42
|
return files.sort();
|
|
50
43
|
}
|
|
51
|
-
function listSkillAssetTemplates(skillName) {
|
|
44
|
+
export function listSkillAssetTemplates(skillName) {
|
|
52
45
|
return walkAssetFiles(skillAssetsDir(skillName)).map((fileName) => ({
|
|
53
46
|
fileName,
|
|
54
47
|
content: readAsset(skillName, fileName),
|
package/dist/paths.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAI7B,MAAM,CAAC,MAAM,YAAY,GAA2C;IAClE,EAAE,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,aAAa,EAAE;IAC9C,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE;IAClC,EAAE,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,aAAa,EAAE;CAC/C,CAAC;AAEF,MAAM,aAAa,GAA+B;IAChD,aAAa,EAAE,SAAS;IACxB,qFAAqF;IACrF,kFAAkF;IAClF,OAAO,EAAE,SAAS;IAClB,aAAa,EAAE,QAAQ;CACxB,CAAC;AAEF,MAAM,UAAU,cAAc,CAAC,WAAmB,EAAE,QAAoB,EAAE,SAAiB;IACzF,OAAO,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,aAAa,CAAC,QAAQ,CAAC,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC;AAC9E,CAAC;AAID,SAAS,cAAc;IACrB,gFAAgF;IAChF,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;AACjD,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,SAAiB;IAC9C,OAAO,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,EAAE,SAAS,CAAC,CAAC;AAChD,CAAC;AAED,SAAS,SAAS,CAAC,SAAiB,EAAE,QAAgB;IACpD,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,SAAS,CAAC,EAAE,QAAQ,CAAC,CAAC;IACzD,OAAO,EAAE,CAAC,YAAY,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;AACpC,CAAC;AAED,SAAS,cAAc,CAAC,OAAe,EAAE,UAAU,GAAG,OAAO;IAC3D,MAAM,OAAO,GAAG,EAAE,CAAC,WAAW,CAAC,UAAU,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IACpE,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QACvD,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;YACxB,KAAK,CAAC,IAAI,CAAC,GAAG,cAAc,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC;YACrD,SAAS;QACX,CAAC;QAED,IAAI,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC;YACnB,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC;QACvE,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,EAAE,CAAC;AACtB,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,SAAiB;IACvD,OAAO,cAAc,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;QAClE,QAAQ;QACR,OAAO,EAAE,SAAS,CAAC,SAAS,EAAE,QAAQ,CAAC;KACxC,CAAC,CAAC,CAAC;AACN,CAAC"}
|