@drkmttr/adhere 0.2.2 → 0.3.1
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 +179 -107
- package/package.json +12 -6
- package/skills/adhere/SKILL.md +4 -3
- package/src/cli.ts +61 -85
- package/src/config.ts +19 -0
- package/src/main.ts +13 -11
- package/src/rules.ts +14 -2
- package/src/services/SourceWalker.ts +14 -17
- package/.adhere/config.ts +0 -7
- package/.adhere/rules/refusals-name-the-file.md +0 -17
- package/.github/workflows/ci.yaml +0 -27
- package/.github/workflows/publish.yaml +0 -68
- package/.github/workflows/release.yaml +0 -71
- package/bun.lock +0 -773
- package/scripts/npm-packages.ts +0 -68
- package/test/audit.test.ts +0 -540
- package/test/cli.test.ts +0 -17
- package/tsconfig.json +0 -26
package/src/rules.ts
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
ConfigUnavailable,
|
|
3
|
+
type Rule,
|
|
4
|
+
type RuleId,
|
|
5
|
+
type RuleSource,
|
|
6
|
+
SKIPPED_DIRECTORIES,
|
|
7
|
+
} from "#config.ts";
|
|
2
8
|
import { parseRuleMarkdown } from "#markdown.ts";
|
|
3
9
|
import { Effect, FileSystem, Path, Record } from "effect";
|
|
4
10
|
|
|
@@ -31,7 +37,13 @@ const isMarkdown = (path: string): boolean => path.endsWith(".md");
|
|
|
31
37
|
const isNestedRuleFile = (relative: string): boolean => {
|
|
32
38
|
const segments = segmentsOf(relative);
|
|
33
39
|
const adhere = segments.lastIndexOf(ADHERE_SEGMENT);
|
|
34
|
-
return
|
|
40
|
+
return (
|
|
41
|
+
adhere >= 0 &&
|
|
42
|
+
segments[adhere + 1] !== CACHE_SEGMENT &&
|
|
43
|
+
isMarkdown(relative) &&
|
|
44
|
+
// Only the path to the `.adhere/`: `.adhere/e2e/` is a rule topic, not a skip.
|
|
45
|
+
!segments.slice(0, adhere).some((segment) => SKIPPED_DIRECTORIES.has(segment))
|
|
46
|
+
);
|
|
35
47
|
};
|
|
36
48
|
|
|
37
49
|
const rulePathOf = (segments: ReadonlyArray<string>): ReadonlyArray<string> => {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Context, Effect, FileSystem, Layer, Path } from "effect";
|
|
2
|
+
import { ADHERE_DIRECTORY, SKIPPED_DIRECTORIES } from "#config.ts";
|
|
2
3
|
import type { ScannedFile } from "#models/Audit.ts";
|
|
3
4
|
import { WalkUnavailable } from "#models/Audit.ts";
|
|
4
5
|
|
|
@@ -20,21 +21,15 @@ export class SourceWalker extends Context.Service<
|
|
|
20
21
|
* trees. Otherwise read the working directory itself.
|
|
21
22
|
*/
|
|
22
23
|
const WORKSPACE_DIRS = ["agents", "apps", "packages"] as const;
|
|
23
|
-
/**
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
"/coverage/",
|
|
33
|
-
"/.vite/",
|
|
34
|
-
"/references/",
|
|
35
|
-
"/vendor/",
|
|
36
|
-
"/e2e/",
|
|
37
|
-
] as const;
|
|
24
|
+
/**
|
|
25
|
+
* A path, relative to the root being read, through a skipped directory or
|
|
26
|
+
* through `.adhere/`, whose files are rules and cache rather than source.
|
|
27
|
+
* Relative, so the directories above the working directory never count.
|
|
28
|
+
*/
|
|
29
|
+
export const isInSkippedTree = (relative: string): boolean =>
|
|
30
|
+
relative
|
|
31
|
+
.split(/[\\/]/)
|
|
32
|
+
.some((segment) => segment === ADHERE_DIRECTORY || SKIPPED_DIRECTORIES.has(segment));
|
|
38
33
|
|
|
39
34
|
const isInside = (file: string, root: string): boolean =>
|
|
40
35
|
file === root || file.startsWith(`${root}/`);
|
|
@@ -45,7 +40,6 @@ const isScannable = (file: string, self: string): boolean =>
|
|
|
45
40
|
!file.endsWith(".test.ts") &&
|
|
46
41
|
!file.endsWith("/adhere.config.ts") &&
|
|
47
42
|
!file.endsWith("/.adhere.config.ts") &&
|
|
48
|
-
SKIPS.every((skip) => !file.includes(skip)) &&
|
|
49
43
|
// The audit's own detector patterns are data, not violations of themselves.
|
|
50
44
|
!isInside(file, self);
|
|
51
45
|
|
|
@@ -57,7 +51,10 @@ const rooted = (root: string, paths: ReadonlyArray<string>) => paths.map((rel) =
|
|
|
57
51
|
|
|
58
52
|
/** What the root actually contains: only paths the audit reads. */
|
|
59
53
|
const scannable = (root: string, paths: ReadonlyArray<string>, self: string) =>
|
|
60
|
-
rooted(
|
|
54
|
+
rooted(
|
|
55
|
+
root,
|
|
56
|
+
paths.filter((relative) => !isInSkippedTree(relative)),
|
|
57
|
+
).filter((file) => isScannable(file, self));
|
|
61
58
|
|
|
62
59
|
/** One root's paths, filtered to what the audit reads. */
|
|
63
60
|
const listRoot = Effect.fn("SourceWalker.listRoot")(
|
package/.adhere/config.ts
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: An error raised while reading a config, rule, or cache file names that file in its message, so the user can open it.
|
|
3
|
-
threshold: 0.8
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
Adhere's own rule. A refusal is the only thing the user sees, so it points
|
|
7
|
-
at the file it is about.
|
|
8
|
-
|
|
9
|
-
```ts
|
|
10
|
-
const front =
|
|
11
|
-
yield *
|
|
12
|
-
Schema.decodeUnknownEffect(FrontMatter)(fields).pipe(
|
|
13
|
-
Effect.mapError((problem) =>
|
|
14
|
-
ConfigUnavailable.make({ message: `${file}: ${problem.message}` }),
|
|
15
|
-
),
|
|
16
|
-
);
|
|
17
|
-
```
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
name: CI
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
pull_request:
|
|
5
|
-
push:
|
|
6
|
-
branches: [main]
|
|
7
|
-
|
|
8
|
-
jobs:
|
|
9
|
-
verify:
|
|
10
|
-
runs-on: ubuntu-latest
|
|
11
|
-
steps:
|
|
12
|
-
- uses: actions/checkout@v4
|
|
13
|
-
- uses: oven-sh/setup-bun@v2
|
|
14
|
-
with:
|
|
15
|
-
bun-version: "1.4.2"
|
|
16
|
-
- run: bun install --frozen-lockfile
|
|
17
|
-
- run: bun run typecheck
|
|
18
|
-
- run: bun run test
|
|
19
|
-
- run: bun run build:npm
|
|
20
|
-
- name: Run the launcher against the linux-x64 package
|
|
21
|
-
run: |
|
|
22
|
-
# Outside the checkout, where the launcher has no source to fall back to.
|
|
23
|
-
launcher="$RUNNER_TEMP/launcher"
|
|
24
|
-
mkdir -p "$launcher/node_modules/@drkmttr"
|
|
25
|
-
cp -r bin "$launcher/bin"
|
|
26
|
-
ln -s "$PWD/dist/npm/linux-x64" "$launcher/node_modules/@drkmttr/adhere-linux-x64"
|
|
27
|
-
node "$launcher/bin/adhere.js" --version
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
name: Publish
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
workflow_call:
|
|
5
|
-
inputs:
|
|
6
|
-
tag_name:
|
|
7
|
-
description: "Release tag to publish, for example v0.3.0."
|
|
8
|
-
required: true
|
|
9
|
-
type: string
|
|
10
|
-
workflow_dispatch:
|
|
11
|
-
inputs:
|
|
12
|
-
tag_name:
|
|
13
|
-
description: "Release tag to publish, for example v0.3.0."
|
|
14
|
-
required: true
|
|
15
|
-
type: string
|
|
16
|
-
|
|
17
|
-
permissions:
|
|
18
|
-
id-token: write
|
|
19
|
-
contents: read
|
|
20
|
-
|
|
21
|
-
jobs:
|
|
22
|
-
publish:
|
|
23
|
-
runs-on: ubuntu-latest
|
|
24
|
-
steps:
|
|
25
|
-
- uses: actions/checkout@v4
|
|
26
|
-
with:
|
|
27
|
-
ref: main
|
|
28
|
-
- uses: oven-sh/setup-bun@v2
|
|
29
|
-
with:
|
|
30
|
-
bun-version: "1.4.2"
|
|
31
|
-
- uses: actions/setup-node@v4
|
|
32
|
-
with:
|
|
33
|
-
node-version: "24"
|
|
34
|
-
registry-url: "https://registry.npmjs.org"
|
|
35
|
-
- name: Verify release tag matches package version
|
|
36
|
-
env:
|
|
37
|
-
TAG_NAME: ${{ inputs.tag_name }}
|
|
38
|
-
run: |
|
|
39
|
-
version="${TAG_NAME#v}"
|
|
40
|
-
if [[ "$version" == "$TAG_NAME" || ! "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+([-.+][0-9A-Za-z.-]+)?$ ]]; then
|
|
41
|
-
echo "Release tags must look like vX.Y.Z, optionally with a prerelease/build suffix." >&2
|
|
42
|
-
exit 1
|
|
43
|
-
fi
|
|
44
|
-
package_version="$(node -p "require('./package.json').version")"
|
|
45
|
-
if [ "$version" != "$package_version" ]; then
|
|
46
|
-
echo "Release tag $TAG_NAME does not match package.json version $package_version." >&2
|
|
47
|
-
exit 1
|
|
48
|
-
fi
|
|
49
|
-
- run: bun install --frozen-lockfile
|
|
50
|
-
- run: bun run typecheck
|
|
51
|
-
- run: bun run test
|
|
52
|
-
- run: bun run build:npm
|
|
53
|
-
- name: Publish the platform packages
|
|
54
|
-
run: |
|
|
55
|
-
for directory in dist/npm/*/; do
|
|
56
|
-
name="$(node -p "require('./${directory}package.json').name")"
|
|
57
|
-
version="$(node -p "require('./${directory}package.json').version")"
|
|
58
|
-
# A rerun after a partial publish skips the versions already on npm.
|
|
59
|
-
if npm view "$name@$version" version >/dev/null 2>&1; then
|
|
60
|
-
echo "$name@$version is already published."
|
|
61
|
-
else
|
|
62
|
-
npm publish "$directory" --access public --provenance
|
|
63
|
-
fi
|
|
64
|
-
done
|
|
65
|
-
- name: Publish @drkmttr/adhere with the platform packages as optional dependencies
|
|
66
|
-
run: |
|
|
67
|
-
bun scripts/npm-packages.ts pin
|
|
68
|
-
npm publish --access public --provenance
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
name: Release
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
tags:
|
|
6
|
-
- "v*"
|
|
7
|
-
|
|
8
|
-
permissions:
|
|
9
|
-
contents: write
|
|
10
|
-
|
|
11
|
-
jobs:
|
|
12
|
-
release:
|
|
13
|
-
runs-on: ubuntu-latest
|
|
14
|
-
steps:
|
|
15
|
-
- name: Derive version from tag
|
|
16
|
-
id: release
|
|
17
|
-
shell: bash
|
|
18
|
-
run: |
|
|
19
|
-
version="${GITHUB_REF_NAME#v}"
|
|
20
|
-
if [[ "$version" == "$GITHUB_REF_NAME" || ! "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+([-.+][0-9A-Za-z.-]+)?$ ]]; then
|
|
21
|
-
echo "Release tags must look like vX.Y.Z, optionally with a prerelease/build suffix." >&2
|
|
22
|
-
exit 1
|
|
23
|
-
fi
|
|
24
|
-
echo "version=$version" >> "$GITHUB_OUTPUT"
|
|
25
|
-
|
|
26
|
-
- uses: actions/checkout@v4
|
|
27
|
-
with:
|
|
28
|
-
ref: main
|
|
29
|
-
fetch-depth: 0
|
|
30
|
-
|
|
31
|
-
- name: Ensure tag was cut from current main
|
|
32
|
-
shell: bash
|
|
33
|
-
run: |
|
|
34
|
-
tag_sha="$(git rev-list -n 1 "$GITHUB_REF_NAME")"
|
|
35
|
-
main_sha="$(git rev-parse HEAD)"
|
|
36
|
-
if [[ "$tag_sha" != "$main_sha" ]]; then
|
|
37
|
-
echo "Tag $GITHUB_REF_NAME must point at current main before release-it adds the version bump commit." >&2
|
|
38
|
-
echo "tag=$tag_sha main=$main_sha" >&2
|
|
39
|
-
exit 1
|
|
40
|
-
fi
|
|
41
|
-
|
|
42
|
-
- uses: oven-sh/setup-bun@v2
|
|
43
|
-
with:
|
|
44
|
-
bun-version: "1.4.2"
|
|
45
|
-
|
|
46
|
-
- uses: actions/setup-node@v4
|
|
47
|
-
with:
|
|
48
|
-
node-version: "24"
|
|
49
|
-
|
|
50
|
-
- name: Configure git author
|
|
51
|
-
run: |
|
|
52
|
-
git config user.name "github-actions[bot]"
|
|
53
|
-
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
|
54
|
-
|
|
55
|
-
- run: bun install --frozen-lockfile
|
|
56
|
-
- run: bun run typecheck
|
|
57
|
-
- run: bun run test
|
|
58
|
-
- run: bun run build:npm
|
|
59
|
-
- name: Create GitHub release
|
|
60
|
-
run: bun run release -- --ci "${{ steps.release.outputs.version }}"
|
|
61
|
-
env:
|
|
62
|
-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
63
|
-
|
|
64
|
-
publish:
|
|
65
|
-
needs: release
|
|
66
|
-
uses: ./.github/workflows/publish.yaml
|
|
67
|
-
permissions:
|
|
68
|
-
contents: read
|
|
69
|
-
id-token: write
|
|
70
|
-
with:
|
|
71
|
-
tag_name: ${{ github.ref_name }}
|