tend-cli 0.1.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/dist/index.js ADDED
@@ -0,0 +1,87 @@
1
+ import { ClaudeSession, ConfigSchema, EventBus, FindingSchema, FindingStore, ReportBuilder, ReportSchema, Snapshot, addUsage, applyCliOverrides, assertGitRepo, buildProgram, changedFiles, changedVsHead, detectPackageManager, dispatch, filterToChanged, fingerprint, groupRemaining, isAvailable, loadConfig, normalize, orchestrate, planWork, renderSummary, retryCommand, revertFile, route, runScanner, scopeFindings, showCommand, trackForTool, zeroUsage } from "./config-B5rO-fvz.js";
2
+ import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
3
+ import { dirname } from "node:path";
4
+
5
+ //#region src/gate/gate.ts
6
+ /**
7
+ * Run the verification checks in order, stopping at the first rejection and
8
+ * surfacing its revert reason. A fix is kept only if every check passes.
9
+ */
10
+ async function runGate(checks) {
11
+ for (const check of checks) {
12
+ const result = await check.run();
13
+ if (!result.ok) return {
14
+ kept: false,
15
+ reason: result.reason,
16
+ detail: result.detail,
17
+ failedCheck: check.name
18
+ };
19
+ }
20
+ return { kept: true };
21
+ }
22
+
23
+ //#endregion
24
+ //#region src/fixing/change-set.ts
25
+ /**
26
+ * The atomic unit of a fix: edits to one file plus (optionally) its sibling test,
27
+ * applied and reverted together. Captures each file's prior state on apply so a
28
+ * revert — even after a partial apply — restores the working tree exactly.
29
+ */
30
+ var ChangeSet = class {
31
+ /** path → original contents, or null if the file did not exist before. */
32
+ originals = new Map();
33
+ constructor(edits) {
34
+ this.edits = edits;
35
+ }
36
+ apply() {
37
+ for (const edit of this.edits) {
38
+ if (!this.originals.has(edit.path)) this.originals.set(edit.path, existsSync(edit.path) ? readFileSync(edit.path, "utf8") : null);
39
+ mkdirSync(dirname(edit.path), { recursive: true });
40
+ writeFileSync(edit.path, edit.contents);
41
+ }
42
+ }
43
+ revert() {
44
+ for (const [path, original] of this.originals) if (original === null) {
45
+ if (existsSync(path)) rmSync(path, { force: true });
46
+ } else writeFileSync(path, original);
47
+ }
48
+ };
49
+
50
+ //#endregion
51
+ //#region src/commands/run.ts
52
+ /** `tend run` — wire audit → fix loop → report. */
53
+ async function runCommand(deps) {
54
+ const now = deps.now ?? Date.now;
55
+ const start = now();
56
+ const result = await orchestrate(deps);
57
+ const builder = new ReportBuilder();
58
+ builder.recordOutcomes(result.findings);
59
+ builder.recordScannerStatuses(result.scannerStatuses);
60
+ const report = builder.build({
61
+ loops: result.loops,
62
+ durationMs: now() - start,
63
+ exitStatus: result.exitStatus,
64
+ aiUsage: result.usage
65
+ });
66
+ return {
67
+ report,
68
+ exitStatus: result.exitStatus
69
+ };
70
+ }
71
+
72
+ //#endregion
73
+ //#region src/commands/diff.ts
74
+ /** `tend diff` — the files the tool edited (snapshot vs now), the dev's own changes filtered out. */
75
+ async function diffCommand(deps) {
76
+ return deps.snapshot.changedSince(deps.git);
77
+ }
78
+
79
+ //#endregion
80
+ //#region src/commands/undo.ts
81
+ /** `tend undo` — restore the pre-run snapshot exactly. */
82
+ async function undoCommand(deps) {
83
+ await deps.snapshot.restore(deps.git);
84
+ }
85
+
86
+ //#endregion
87
+ export { ChangeSet, ClaudeSession, ConfigSchema, EventBus, FindingSchema, FindingStore, ReportBuilder, ReportSchema, Snapshot, addUsage, applyCliOverrides, assertGitRepo, buildProgram, changedFiles, changedVsHead, detectPackageManager, diffCommand, dispatch, filterToChanged, fingerprint, groupRemaining, isAvailable, loadConfig, normalize, orchestrate, planWork, renderSummary, retryCommand, revertFile, route, runCommand, runGate, runScanner, scopeFindings, showCommand, trackForTool, undoCommand, zeroUsage };
package/package.json ADDED
@@ -0,0 +1,67 @@
1
+ {
2
+ "name": "tend-cli",
3
+ "version": "0.1.0",
4
+ "description": "Audit a JS/TS repo with established scanners, then fix the findings with parallel AI sessions in a safe scan-fix-rescan loop.",
5
+ "keywords": [
6
+ "lint",
7
+ "autofix",
8
+ "code-quality",
9
+ "ai",
10
+ "refactor",
11
+ "static-analysis"
12
+ ],
13
+ "license": "MIT",
14
+ "type": "module",
15
+ "engines": {
16
+ "node": ">=20"
17
+ },
18
+ "bin": {
19
+ "tend": "./dist/bin.js"
20
+ },
21
+ "exports": {
22
+ ".": "./dist/index.js"
23
+ },
24
+ "files": [
25
+ "dist",
26
+ "prompts",
27
+ "configs",
28
+ "README.md",
29
+ "LICENSE"
30
+ ],
31
+ "scripts": {
32
+ "build": "tsdown",
33
+ "prepublishOnly": "tsdown",
34
+ "test": "vitest run",
35
+ "test:watch": "vitest",
36
+ "typecheck": "tsc --noEmit"
37
+ },
38
+ "dependencies": {
39
+ "@eslint/js": "^9.18.0",
40
+ "boxen": "^8.0.1",
41
+ "chalk": "^5.4.1",
42
+ "cli-table3": "^0.6.5",
43
+ "commander": "^13.1.0",
44
+ "cosmiconfig": "^9.0.0",
45
+ "eslint": "^9.18.0",
46
+ "eslint-plugin-sonarjs": "^3.0.1",
47
+ "execa": "^9.5.2",
48
+ "globals": "^15.14.0",
49
+ "gradient-string": "^3.0.0",
50
+ "jscpd": "^4.0.5",
51
+ "knip": "^5.43.6",
52
+ "listr2": "^8.2.5",
53
+ "log-symbols": "^7.0.0",
54
+ "nanoid": "^5.1.6",
55
+ "p-queue": "^8.1.0",
56
+ "simple-git": "^3.27.0",
57
+ "typescript-eslint": "^8.20.0",
58
+ "zod": "^3.24.1"
59
+ },
60
+ "devDependencies": {
61
+ "@types/node": "^22.10.5",
62
+ "@vitest/coverage-v8": "^4.1.5",
63
+ "tsdown": "^0.9.6",
64
+ "typescript": "^5.7.3",
65
+ "vitest": "^4.0.14"
66
+ }
67
+ }
package/prompts/fix.md ADDED
@@ -0,0 +1,29 @@
1
+ # Fix task
2
+
3
+ You are fixing a single file in a codebase. A set of static-analysis findings has been
4
+ located for you precisely — you do **not** need to search for what's wrong.
5
+
6
+ ## The findings
7
+
8
+ {{findings}}
9
+
10
+ ## File
11
+
12
+ `{{file}}` (and its sibling test, if one exists).
13
+
14
+ ## Rules
15
+
16
+ 1. **Fix the underlying issue**, not the symptom. Never silence a finding by adding
17
+ `eslint-disable`, `@ts-ignore`, `@ts-nocheck`, casting to `any`, or deleting the
18
+ offending code. Such edits are rejected automatically.
19
+ 2. **Preserve behavior.** The tests are the behavior oracle. If a fix legitimately
20
+ requires a test change (e.g. an import moved during a refactor), make it — but never
21
+ weaken an assertion to make a failing test pass. A test you edit must still fail
22
+ against the old code.
23
+ 3. **Stay in scope.** Edit only `{{file}}` and its sibling test. Do not touch other files.
24
+ 4. **Type-correct.** The result must pass `tsc --noEmit` (when the project uses TypeScript).
25
+ 5. **Don't introduce new findings.** A fix that trades one issue for another is rejected.
26
+
27
+ ## Output
28
+
29
+ Use the `Write` tool to emit the full, corrected contents of each file you change.