ts-reviewer 1.2.1 → 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 +39 -5
- 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
|
|
|
@@ -44,7 +44,7 @@ The installer prints a short summary before installation:
|
|
|
44
44
|
```text
|
|
45
45
|
TypeScript Code Reviewer
|
|
46
46
|
Checks: type safety, security, async patterns, boundary validation, error handling, modernization, code quality, tsconfig, dependency hygiene
|
|
47
|
-
Target
|
|
47
|
+
Target stack: TypeScript 5.9.x, ES2024, Node 24
|
|
48
48
|
```
|
|
49
49
|
|
|
50
50
|
Then it asks which AI agents to install for. Use Up/Down arrows to move, Space to toggle, and Enter to confirm.
|
|
@@ -92,6 +92,7 @@ By default, only the nine core domains run. Use flags to control which domains a
|
|
|
92
92
|
| *(none)* | Type Safety, Security, Async, Modernization, Code Quality, Config, Boundary Validation, Error Handling, Dependency Hygiene |
|
|
93
93
|
| `--arch` | Architecture only (shallow modules, coupling, dependency direction, seams) |
|
|
94
94
|
| `--full` | All ten domains |
|
|
95
|
+
| `--no-arch` | The nine core domains — overrides `--arch`, `--full`, and any phrase that would enable architecture |
|
|
95
96
|
|
|
96
97
|
Examples:
|
|
97
98
|
|
|
@@ -175,11 +176,24 @@ Architecture findings use the same scale. Each candidate also carries a **Fixabi
|
|
|
175
176
|
## Project Structure
|
|
176
177
|
|
|
177
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
|
+
|
|
178
182
|
src/ # npm/npx installer source
|
|
179
183
|
├── cli.ts # CLI entrypoint and provider prompt
|
|
180
184
|
├── prompt.ts # raw-mode keyboard multi-select
|
|
181
185
|
└── paths.ts # target directories and skill asset loading
|
|
182
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
|
+
|
|
183
197
|
ts-reviewer/
|
|
184
198
|
├── SKILL.md # Main skill file — mode routing, workflow orchestration
|
|
185
199
|
└── references/
|
|
@@ -188,7 +202,7 @@ ts-reviewer/
|
|
|
188
202
|
├── async-patterns.md # Checklist: floating promises, races, timeouts, retries, cancellation
|
|
189
203
|
├── boundary-validation.md # Checklist: runtime validation at edges, DTO/domain separation
|
|
190
204
|
├── error-handling.md # Checklist: silent failures, throw hygiene, failure design
|
|
191
|
-
├── modernization.md # Checklist:
|
|
205
|
+
├── modernization.md # Checklist: patterns below the stack, ??/?. , satisfies, using, toSorted
|
|
192
206
|
├── code-quality.md # Checklist: complexity, dead code, debug artifacts, testability
|
|
193
207
|
├── tsconfig.md # Checklist: strict flags, target/lib, module resolution, deprecated
|
|
194
208
|
├── dependency-hygiene.md # Checklist: lockfiles, versions, npm audit, dependency choice
|
|
@@ -200,6 +214,26 @@ ts-reviewer/
|
|
|
200
214
|
|
|
201
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.
|
|
202
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
|
+
|
|
203
237
|
## How It Works Under the Hood
|
|
204
238
|
|
|
205
239
|
### Scan mode
|
|
@@ -232,9 +266,9 @@ ts-reviewer/
|
|
|
232
266
|
|
|
233
267
|
## Requirements
|
|
234
268
|
|
|
235
|
-
- TypeScript 5.9
|
|
269
|
+
- TypeScript 5.9.x project targeting ES2024 on Node 24
|
|
236
270
|
- Git repository (for scoped modes and safe revert during fix)
|
|
237
|
-
- Node
|
|
271
|
+
- Node 24 with `npx` available (for tsc, linter)
|
|
238
272
|
- Claude Code (recommended) or any Claude interface with skill support
|
|
239
273
|
|
|
240
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"}
|
package/dist/prompt.js
CHANGED
|
@@ -1,30 +1,24 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.multiSelect = multiSelect;
|
|
7
|
-
const node_readline_1 = __importDefault(require("node:readline"));
|
|
8
|
-
const node_process_1 = __importDefault(require("node:process"));
|
|
1
|
+
import readline from "node:readline";
|
|
2
|
+
import process from "node:process";
|
|
9
3
|
function render(message, choices, cursor, selected, isFirst) {
|
|
10
4
|
if (!isFirst) {
|
|
11
|
-
|
|
5
|
+
process.stdout.write(`\x1b[${choices.length + 1}A`);
|
|
12
6
|
}
|
|
13
|
-
|
|
7
|
+
process.stdout.write(`\x1b[2K${message}\n`);
|
|
14
8
|
for (let i = 0; i < choices.length; i++) {
|
|
15
9
|
const mark = selected.has(i) ? "[x]" : "[ ]";
|
|
16
10
|
const arrow = i === cursor ? ">" : " ";
|
|
17
|
-
|
|
11
|
+
process.stdout.write(`\x1b[2K${arrow} ${mark} ${choices[i].label}\n`);
|
|
18
12
|
}
|
|
19
13
|
}
|
|
20
|
-
async function multiSelect(message, choices) {
|
|
21
|
-
if (!
|
|
14
|
+
export async function multiSelect(message, choices) {
|
|
15
|
+
if (!process.stdin.isTTY) {
|
|
22
16
|
return choices.map((c) => c.value);
|
|
23
17
|
}
|
|
24
18
|
const selected = new Set();
|
|
25
19
|
let cursor = 0;
|
|
26
|
-
|
|
27
|
-
|
|
20
|
+
readline.emitKeypressEvents(process.stdin);
|
|
21
|
+
process.stdin.setRawMode(true);
|
|
28
22
|
render(message, choices, cursor, selected, true);
|
|
29
23
|
return new Promise((resolve) => {
|
|
30
24
|
const onKey = (_str, key) => {
|
|
@@ -46,19 +40,19 @@ async function multiSelect(message, choices) {
|
|
|
46
40
|
render(message, choices, cursor, selected, false);
|
|
47
41
|
}
|
|
48
42
|
else if (key.name === "return") {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
43
|
+
process.stdin.removeListener("keypress", onKey);
|
|
44
|
+
process.stdin.setRawMode(false);
|
|
45
|
+
process.stdin.pause();
|
|
52
46
|
resolve(choices.filter((_, i) => selected.has(i)).map((c) => c.value));
|
|
53
47
|
}
|
|
54
48
|
else if (key.ctrl && key.name === "c") {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
49
|
+
process.stdin.removeListener("keypress", onKey);
|
|
50
|
+
process.stdin.setRawMode(false);
|
|
51
|
+
process.stdin.pause();
|
|
52
|
+
process.exit(0);
|
|
59
53
|
}
|
|
60
54
|
};
|
|
61
|
-
|
|
55
|
+
process.stdin.on("keypress", onKey);
|
|
62
56
|
});
|
|
63
57
|
}
|
|
64
58
|
//# sourceMappingURL=prompt.js.map
|
package/dist/prompt.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prompt.js","sourceRoot":"","sources":["../src/prompt.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"prompt.js","sourceRoot":"","sources":["../src/prompt.ts"],"names":[],"mappings":"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"}
|
package/dist/updatePolicy.js
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.decideUpdate = decideUpdate;
|
|
4
1
|
// Inputs are hashes (sha256 hex) or null if missing.
|
|
5
|
-
function decideUpdate(opts) {
|
|
2
|
+
export function decideUpdate(opts) {
|
|
6
3
|
const { existingHash, lastWrittenHash } = opts;
|
|
7
4
|
// missing file
|
|
8
5
|
if (existingHash === null)
|
package/dist/updatePolicy.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"updatePolicy.js","sourceRoot":"","sources":["../src/updatePolicy.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"updatePolicy.js","sourceRoot":"","sources":["../src/updatePolicy.ts"],"names":[],"mappings":"AAMA,qDAAqD;AACrD,MAAM,UAAU,YAAY,CAAC,IAG5B;IACC,MAAM,EAAE,YAAY,EAAE,eAAe,EAAE,GAAG,IAAI,CAAC;IAE/C,eAAe;IACf,IAAI,YAAY,KAAK,IAAI;QAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;IAEpD,8DAA8D;IAC9D,IAAI,eAAe,KAAK,IAAI;QAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC;IAE1D,kEAAkE;IAClE,IAAI,YAAY,KAAK,eAAe;QAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC;IAEnE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC;AAC9B,CAAC"}
|