@esneiderbravo/speclaw 0.3.5 → 0.3.8
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 +44 -15
- package/dist/cli/commands/coverage.js +49 -0
- package/dist/cli/commands/doctor.js +53 -21
- package/dist/cli/commands/telemetry.js +16 -0
- package/dist/cli/commands/update.js +21 -0
- package/dist/cli/index.js +16 -2
- package/dist/cli/lib/untrack.js +1 -0
- package/dist/modules/compass/db.js +20 -1
- package/dist/modules/compass/extract.js +59 -5
- package/dist/modules/compass/indexer.js +30 -1
- package/dist/modules/foundation/context-budget.js +16 -3
- package/dist/modules/foundation/doctor.js +626 -170
- package/dist/modules/foundation/graph.js +7 -4
- package/dist/modules/foundation/hooks.js +12 -0
- package/dist/modules/foundation/laws.js +1 -0
- package/dist/modules/foundation/register-core.js +108 -0
- package/dist/modules/foundation/register.js +18 -106
- package/dist/modules/lawbook/coverage.js +479 -0
- package/dist/modules/lawbook/engine.js +3 -0
- package/dist/modules/lawbook/register.js +13 -0
- package/dist/modules/lawbook/spec-items.js +168 -0
- package/dist/shared/exposure.js +1 -1
- package/dist/shared/install.js +1 -0
- package/dist/shared/redact.js +90 -0
- package/package.json +1 -1
package/dist/shared/install.js
CHANGED
|
@@ -94,6 +94,7 @@ export function copyRendered(srcDir, destDir, vars, report, opts) {
|
|
|
94
94
|
* @param comment - Comment line written above the entry when it is added.
|
|
95
95
|
* @param report - Report mutated in place; the appended entry is recorded under `written`.
|
|
96
96
|
*/
|
|
97
|
+
// Covers: req~ai-specs-gitignore~1
|
|
97
98
|
export function ensureGitignore(projectPath, entry, comment, report) {
|
|
98
99
|
const gitignorePath = path.join(projectPath, ".gitignore");
|
|
99
100
|
let content = "";
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import os from "node:os";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
/**
|
|
4
|
+
* Replace every occurrence of `from` that sits on a path boundary (not as a
|
|
5
|
+
* substring of a longer path). Prevents `/home/runner` from mangling
|
|
6
|
+
* `/opt/home/runner/...` into `/opt~/...` on GitHub Actions.
|
|
7
|
+
*/
|
|
8
|
+
function replacePathToken(text, from, to) {
|
|
9
|
+
if (!from || from.length < 2)
|
|
10
|
+
return text;
|
|
11
|
+
let out = text;
|
|
12
|
+
let idx = 0;
|
|
13
|
+
while ((idx = out.indexOf(from, idx)) !== -1) {
|
|
14
|
+
const before = idx === 0 ? "" : out[idx - 1];
|
|
15
|
+
const afterIdx = idx + from.length;
|
|
16
|
+
const after = afterIdx >= out.length ? "" : out[afterIdx];
|
|
17
|
+
// Preceding char must not continue a path segment (blocks /opt + /home/…).
|
|
18
|
+
const beforeOk = idx === 0 || !/[A-Za-z0-9._-]/.test(before);
|
|
19
|
+
// Following char must end the token or continue as a separator.
|
|
20
|
+
const afterOk = after === "" || after === "/" || after === "\\" || /[\s'",):]/.test(after);
|
|
21
|
+
if (beforeOk && afterOk) {
|
|
22
|
+
out = out.slice(0, idx) + to + out.slice(afterIdx);
|
|
23
|
+
idx += to.length;
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
idx += 1;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return out;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Redact absolute paths and usernames so a doctor report is safe to paste into
|
|
33
|
+
* a public issue. Home becomes `~`, the project root becomes `<project>`, and
|
|
34
|
+
* OS usernames are scrubbed from path segments.
|
|
35
|
+
*
|
|
36
|
+
* @param text - Arbitrary detail / remedy text that may contain paths.
|
|
37
|
+
* @param projectPath - Absolute project root to replace with `<project>`.
|
|
38
|
+
* @returns Redacted text (POSIX and Windows separators handled).
|
|
39
|
+
*/
|
|
40
|
+
export function redactText(text, projectPath) {
|
|
41
|
+
let out = text;
|
|
42
|
+
const home = os.homedir();
|
|
43
|
+
const user = os.userInfo().username;
|
|
44
|
+
const replacements = [];
|
|
45
|
+
const queueReplacement = (from, to) => {
|
|
46
|
+
if (from && from.length > 1)
|
|
47
|
+
replacements.push([from, to]);
|
|
48
|
+
};
|
|
49
|
+
queueReplacement(path.resolve(projectPath), "<project>");
|
|
50
|
+
queueReplacement(projectPath.replace(/\//g, "\\"), "<project>");
|
|
51
|
+
queueReplacement(home, "~");
|
|
52
|
+
queueReplacement(home.replace(/\//g, "\\"), "~");
|
|
53
|
+
queueReplacement(`C:\\Users\\${user}`, "~");
|
|
54
|
+
queueReplacement(`c:\\Users\\${user}`, "~");
|
|
55
|
+
replacements.sort((a, b) => b[0].length - a[0].length);
|
|
56
|
+
for (const [from, to] of replacements) {
|
|
57
|
+
out = replacePathToken(out, from, to);
|
|
58
|
+
if (from.includes("\\"))
|
|
59
|
+
out = replacePathToken(out, from.replace(/\\/g, "/"), to);
|
|
60
|
+
}
|
|
61
|
+
if (user && user.length > 1) {
|
|
62
|
+
const seg = new RegExp(`(^|[/\\\\])${escapeRegExp(user)}(?=[/\\\\]|$)`, "gi");
|
|
63
|
+
out = out.replace(seg, `$1<user>`);
|
|
64
|
+
}
|
|
65
|
+
return out;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Deep-redact every string field in a JSON-compatible value.
|
|
69
|
+
*
|
|
70
|
+
* @param value - Report fragment.
|
|
71
|
+
* @param projectPath - Project root for `<project>` substitution.
|
|
72
|
+
*/
|
|
73
|
+
export function redactValue(value, projectPath) {
|
|
74
|
+
if (typeof value === "string")
|
|
75
|
+
return redactText(value, projectPath);
|
|
76
|
+
if (Array.isArray(value)) {
|
|
77
|
+
return value.map((v) => redactValue(v, projectPath));
|
|
78
|
+
}
|
|
79
|
+
if (value && typeof value === "object") {
|
|
80
|
+
const out = {};
|
|
81
|
+
for (const [k, v] of Object.entries(value)) {
|
|
82
|
+
out[k] = redactValue(v, projectPath);
|
|
83
|
+
}
|
|
84
|
+
return out;
|
|
85
|
+
}
|
|
86
|
+
return value;
|
|
87
|
+
}
|
|
88
|
+
function escapeRegExp(s) {
|
|
89
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
90
|
+
}
|