waymark-docs 0.1.0 → 0.1.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/CHANGELOG.md +7 -0
- package/README.md +20 -10
- package/dist/configuration/index.d.ts +1 -1
- package/dist/configuration/index.js +1 -1
- package/dist/configuration/initialize.js +6 -5
- package/dist/configuration/load.d.ts +4 -2
- package/dist/configuration/load.js +49 -21
- package/dist/documents/scan.js +10 -6
- package/package.json +10 -6
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to Waymark are documented in this file.
|
|
4
4
|
|
|
5
|
+
## [0.1.1](https://github.com/ysfaran/waymark/compare/v0.1.0...v0.1.1) (2026-08-03)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
* **cli:** add Waymark documentation discovery CLI ([ea0e515](https://github.com/ysfaran/waymark/commit/ea0e515479b323448b2a76c84c343ea314786093))
|
|
11
|
+
|
|
5
12
|
## 0.1.0 (2026-07-31)
|
|
6
13
|
|
|
7
14
|
- Initial public release.
|
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Waymark
|
|
1
|
+
# 🪧 Waymark
|
|
2
2
|
|
|
3
3
|
Find the right repository docs for your coding agent.
|
|
4
4
|
|
|
@@ -35,7 +35,7 @@ npm install --save-dev waymark-docs
|
|
|
35
35
|
|
|
36
36
|
## Quick start
|
|
37
37
|
|
|
38
|
-
1. Create
|
|
38
|
+
1. Create a Waymark configuration in the repository root:
|
|
39
39
|
|
|
40
40
|
```sh
|
|
41
41
|
npx waymark init
|
|
@@ -47,6 +47,11 @@ npm install --save-dev waymark-docs
|
|
|
47
47
|
# When true, document metadata must be nested under a `waymark` frontmatter key.
|
|
48
48
|
require-namespace: false
|
|
49
49
|
|
|
50
|
+
# Skip generated or vendored documentation during discovery.
|
|
51
|
+
ignore:
|
|
52
|
+
- docs/generated/**
|
|
53
|
+
- vendor/**
|
|
54
|
+
|
|
50
55
|
kinds:
|
|
51
56
|
adr: Read to understand past architectural decisions and their constraints
|
|
52
57
|
convention: Read before changing code to follow required repository practices
|
|
@@ -56,6 +61,9 @@ npm install --save-dev waymark-docs
|
|
|
56
61
|
typescript: TypeScript-related documentation
|
|
57
62
|
```
|
|
58
63
|
|
|
64
|
+
Ignore patterns are relative to the repository root and support `*`, `?`,
|
|
65
|
+
and `**` wildcards. Waymark also honors `.gitignore` automatically.
|
|
66
|
+
|
|
59
67
|
3. Register a Markdown or MDX file by adding Waymark metadata. For example,
|
|
60
68
|
save this as `docs/conventions/typescript.md`:
|
|
61
69
|
|
|
@@ -93,8 +101,10 @@ npm install --save-dev waymark-docs
|
|
|
93
101
|
docs/conventions/typescript.md — TypeScript conventions for this repository
|
|
94
102
|
```
|
|
95
103
|
|
|
96
|
-
Waymark
|
|
97
|
-
|
|
104
|
+
Waymark uses `waymark.yml` by default and also recognizes `waymark.yaml`. It
|
|
105
|
+
looks for the configuration in the current directory and its ancestors, so
|
|
106
|
+
commands can also run from a nested repository directory. Use only one filename
|
|
107
|
+
per directory.
|
|
98
108
|
|
|
99
109
|
## Commands
|
|
100
110
|
|
|
@@ -108,7 +118,7 @@ commands can also be run from a nested repository directory.
|
|
|
108
118
|
|
|
109
119
|
### `waymark init`
|
|
110
120
|
|
|
111
|
-
Create a starter
|
|
121
|
+
Create a starter configuration in the current directory.
|
|
112
122
|
|
|
113
123
|
```text
|
|
114
124
|
Usage: waymark init [options]
|
|
@@ -138,10 +148,10 @@ configuration beneath another Waymark root.
|
|
|
138
148
|
|
|
139
149
|
### `waymark status`
|
|
140
150
|
|
|
141
|
-
Validate
|
|
142
|
-
repository root and counts for registered documents, unregistered
|
|
143
|
-
kinds, and tags. Invalid repositories produce diagnostics and a
|
|
144
|
-
code, which makes this command suitable for CI.
|
|
151
|
+
Validate the Waymark configuration and all discovered Waymark Documents, then
|
|
152
|
+
print the repository root and counts for registered documents, unregistered
|
|
153
|
+
documents, kinds, and tags. Invalid repositories produce diagnostics and a
|
|
154
|
+
non-zero exit code, which makes this command suitable for CI.
|
|
145
155
|
|
|
146
156
|
```text
|
|
147
157
|
Usage: waymark status [options]
|
|
@@ -280,7 +290,7 @@ Find Markdown and MDX files that are missing Waymark metadata:
|
|
|
280
290
|
npx waymark ls -R --unregistered docs
|
|
281
291
|
```
|
|
282
292
|
|
|
283
|
-
`ls` respects `.gitignore`, Waymark
|
|
293
|
+
`ls` respects `.gitignore`, Waymark ignore patterns, and Git directory boundaries.
|
|
284
294
|
The selected directory must be inside the repository root.
|
|
285
295
|
|
|
286
296
|
### `waymark help`
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export { initializeConfiguration } from "./initialize.js";
|
|
2
|
-
export {
|
|
2
|
+
export { allowedConfigFileNames, defaultConfigFileName, loadConfiguration, } from "./load.js";
|
|
3
3
|
export type { Configuration, ConfigurationDeclaration, ConfigurationDiagnostic, ConfigurationLoadResult, } from "./load.js";
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { initializeConfiguration } from "./initialize.js";
|
|
2
|
-
export {
|
|
2
|
+
export { allowedConfigFileNames, defaultConfigFileName, loadConfiguration, } from "./load.js";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { writeFile } from "node:fs/promises";
|
|
2
2
|
import { dirname, join } from "node:path";
|
|
3
|
-
import { isErrorWithCode
|
|
4
|
-
import {
|
|
3
|
+
import { isErrorWithCode } from "../filesystem.js";
|
|
4
|
+
import { defaultConfigFileName, findConfigurationPath, findConfigurationPathInDirectory, } from "./load.js";
|
|
5
5
|
const starterConfiguration = "# When true, document metadata must be nested under a `waymark` frontmatter key.\n" +
|
|
6
6
|
"require-namespace: false\n" +
|
|
7
7
|
"kinds:\n" +
|
|
@@ -9,9 +9,10 @@ const starterConfiguration = "# When true, document metadata must be nested unde
|
|
|
9
9
|
"tags:\n" +
|
|
10
10
|
" example-tag: Explain the topic represented by this tag\n";
|
|
11
11
|
export async function initializeConfiguration(directoryPath) {
|
|
12
|
-
const configurationPath = join(directoryPath,
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
const configurationPath = join(directoryPath, defaultConfigFileName);
|
|
13
|
+
const existingConfigurationPath = await findConfigurationPathInDirectory(directoryPath);
|
|
14
|
+
if (existingConfigurationPath) {
|
|
15
|
+
throw new Error(`A Waymark configuration already exists at ${existingConfigurationPath}.`);
|
|
15
16
|
}
|
|
16
17
|
const ancestorConfigurationPath = await findConfigurationPath(dirname(directoryPath));
|
|
17
18
|
if (ancestorConfigurationPath) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
export declare const
|
|
1
|
+
export declare const defaultConfigFileName = "waymark.yml";
|
|
2
|
+
export declare const allowedConfigFileNames: readonly ["waymark.yml", "waymark.yaml"];
|
|
2
3
|
export type ConfigurationDeclaration = {
|
|
3
4
|
description: string;
|
|
4
5
|
};
|
|
@@ -11,7 +12,7 @@ export type Configuration = {
|
|
|
11
12
|
requireNamespace: boolean;
|
|
12
13
|
kinds: Map<string, ConfigurationDeclaration>;
|
|
13
14
|
tags: Map<string, ConfigurationDeclaration>;
|
|
14
|
-
|
|
15
|
+
ignorePatterns: string[];
|
|
15
16
|
};
|
|
16
17
|
export type ConfigurationLoadResult = {
|
|
17
18
|
kind: "loaded";
|
|
@@ -25,3 +26,4 @@ export type ConfigurationLoadResult = {
|
|
|
25
26
|
};
|
|
26
27
|
export declare function loadConfiguration(startingDirectoryPath: string): Promise<ConfigurationLoadResult>;
|
|
27
28
|
export declare function findConfigurationPath(startingDirectoryPath: string): Promise<string | undefined>;
|
|
29
|
+
export declare function findConfigurationPathInDirectory(directoryPath: string): Promise<string | undefined>;
|
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
import { readFile } from "node:fs/promises";
|
|
2
|
-
import { dirname, join, resolve } from "node:path";
|
|
2
|
+
import { basename, dirname, join, resolve } from "node:path";
|
|
3
3
|
import { parse } from "yaml";
|
|
4
4
|
import { pathExists } from "../filesystem.js";
|
|
5
|
-
export const
|
|
5
|
+
export const defaultConfigFileName = "waymark.yml";
|
|
6
|
+
export const allowedConfigFileNames = [
|
|
7
|
+
defaultConfigFileName,
|
|
8
|
+
"waymark.yaml",
|
|
9
|
+
];
|
|
6
10
|
export async function loadConfiguration(startingDirectoryPath) {
|
|
7
11
|
const configurationPath = await findConfigurationPath(startingDirectoryPath);
|
|
8
12
|
if (!configurationPath) {
|
|
9
|
-
throw new Error(`Could not find ${
|
|
13
|
+
throw new Error(`Could not find ${allowedConfigFileNames.join(" or ")} from ${resolve(startingDirectoryPath)}.`);
|
|
10
14
|
}
|
|
11
15
|
const rootPath = dirname(configurationPath);
|
|
16
|
+
const loadedConfigurationFileName = basename(configurationPath);
|
|
12
17
|
let parsedConfiguration;
|
|
13
18
|
try {
|
|
14
19
|
parsedConfiguration = parse(await readFile(configurationPath, "utf8"));
|
|
@@ -19,7 +24,7 @@ export async function loadConfiguration(startingDirectoryPath) {
|
|
|
19
24
|
rootPath,
|
|
20
25
|
diagnostics: [
|
|
21
26
|
{
|
|
22
|
-
path:
|
|
27
|
+
path: loadedConfigurationFileName,
|
|
23
28
|
field: "configuration",
|
|
24
29
|
message: "Malformed YAML configuration.",
|
|
25
30
|
},
|
|
@@ -30,7 +35,11 @@ export async function loadConfiguration(startingDirectoryPath) {
|
|
|
30
35
|
return {
|
|
31
36
|
kind: "loaded",
|
|
32
37
|
rootPath,
|
|
33
|
-
configuration: validateConfiguration(
|
|
38
|
+
configuration: validateConfiguration({
|
|
39
|
+
value: parsedConfiguration,
|
|
40
|
+
configurationFileName: loadedConfigurationFileName,
|
|
41
|
+
diagnostics,
|
|
42
|
+
}),
|
|
34
43
|
diagnostics,
|
|
35
44
|
};
|
|
36
45
|
}
|
|
@@ -38,17 +47,30 @@ export async function findConfigurationPath(startingDirectoryPath) {
|
|
|
38
47
|
let directoryPath = resolve(startingDirectoryPath);
|
|
39
48
|
let foundConfigurationPath;
|
|
40
49
|
while (true) {
|
|
41
|
-
const configurationPath =
|
|
42
|
-
if (
|
|
50
|
+
const configurationPath = await findConfigurationPathInDirectory(directoryPath);
|
|
51
|
+
if (configurationPath)
|
|
43
52
|
foundConfigurationPath = configurationPath;
|
|
44
|
-
}
|
|
45
53
|
const parentPath = dirname(directoryPath);
|
|
46
54
|
if (parentPath === directoryPath)
|
|
47
55
|
return foundConfigurationPath;
|
|
48
56
|
directoryPath = parentPath;
|
|
49
57
|
}
|
|
50
58
|
}
|
|
51
|
-
function
|
|
59
|
+
export async function findConfigurationPathInDirectory(directoryPath) {
|
|
60
|
+
const configurationPaths = [];
|
|
61
|
+
for (const fileName of allowedConfigFileNames) {
|
|
62
|
+
const configurationPath = join(directoryPath, fileName);
|
|
63
|
+
if (await pathExists(configurationPath)) {
|
|
64
|
+
configurationPaths.push(configurationPath);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
if (configurationPaths.length > 1) {
|
|
68
|
+
throw new Error(`Multiple Waymark configurations exist in ${resolve(directoryPath)}: ` +
|
|
69
|
+
`${allowedConfigFileNames.join(", ")}.`);
|
|
70
|
+
}
|
|
71
|
+
return configurationPaths[0];
|
|
72
|
+
}
|
|
73
|
+
function validateConfiguration({ value, configurationFileName, diagnostics, }) {
|
|
52
74
|
if (!isRecord(value)) {
|
|
53
75
|
diagnostics.push({
|
|
54
76
|
path: configurationFileName,
|
|
@@ -61,7 +83,7 @@ function validateConfiguration(value, diagnostics) {
|
|
|
61
83
|
"require-namespace",
|
|
62
84
|
"kinds",
|
|
63
85
|
"tags",
|
|
64
|
-
"
|
|
86
|
+
"ignore",
|
|
65
87
|
]);
|
|
66
88
|
for (const field of Object.keys(configuration)) {
|
|
67
89
|
if (!allowedFields.has(field)) {
|
|
@@ -85,17 +107,23 @@ function validateConfiguration(value, diagnostics) {
|
|
|
85
107
|
kinds: validateDeclarations({
|
|
86
108
|
value: configuration.kinds,
|
|
87
109
|
field: "kinds",
|
|
110
|
+
configurationFileName,
|
|
88
111
|
diagnostics,
|
|
89
112
|
}),
|
|
90
113
|
tags: validateDeclarations({
|
|
91
114
|
value: configuration.tags,
|
|
92
115
|
field: "tags",
|
|
116
|
+
configurationFileName,
|
|
117
|
+
diagnostics,
|
|
118
|
+
}),
|
|
119
|
+
ignorePatterns: validateIgnorePatterns({
|
|
120
|
+
value: configuration.ignore,
|
|
121
|
+
configurationFileName,
|
|
93
122
|
diagnostics,
|
|
94
123
|
}),
|
|
95
|
-
exclusions: validateExclusions(configuration.exclude, diagnostics),
|
|
96
124
|
};
|
|
97
125
|
}
|
|
98
|
-
function validateDeclarations({ value, field, diagnostics, }) {
|
|
126
|
+
function validateDeclarations({ value, field, configurationFileName, diagnostics, }) {
|
|
99
127
|
if (!isRecord(value)) {
|
|
100
128
|
diagnostics.push({
|
|
101
129
|
path: configurationFileName,
|
|
@@ -127,25 +155,25 @@ function validateDeclarations({ value, field, diagnostics, }) {
|
|
|
127
155
|
}
|
|
128
156
|
return declarations;
|
|
129
157
|
}
|
|
130
|
-
function
|
|
158
|
+
function validateIgnorePatterns({ value, configurationFileName, diagnostics, }) {
|
|
131
159
|
if (value === undefined)
|
|
132
160
|
return [];
|
|
133
161
|
if (!Array.isArray(value)) {
|
|
134
162
|
diagnostics.push({
|
|
135
163
|
path: configurationFileName,
|
|
136
|
-
field: "
|
|
137
|
-
message: "Expected a sequence of
|
|
164
|
+
field: "ignore",
|
|
165
|
+
message: "Expected a sequence of ignore globs.",
|
|
138
166
|
});
|
|
139
167
|
return [];
|
|
140
168
|
}
|
|
141
|
-
const
|
|
169
|
+
const ignorePatterns = [];
|
|
142
170
|
for (const [index, pattern] of value.entries()) {
|
|
143
|
-
const field = `
|
|
171
|
+
const field = `ignore.${index}`;
|
|
144
172
|
if (typeof pattern !== "string" || pattern.trim() === "") {
|
|
145
173
|
diagnostics.push({
|
|
146
174
|
path: configurationFileName,
|
|
147
175
|
field,
|
|
148
|
-
message: "
|
|
176
|
+
message: "Ignore glob must be a non-empty string.",
|
|
149
177
|
});
|
|
150
178
|
continue;
|
|
151
179
|
}
|
|
@@ -153,7 +181,7 @@ function validateExclusions(value, diagnostics) {
|
|
|
153
181
|
diagnostics.push({
|
|
154
182
|
path: configurationFileName,
|
|
155
183
|
field,
|
|
156
|
-
message: "Negation is not supported in
|
|
184
|
+
message: "Negation is not supported in ignore globs.",
|
|
157
185
|
});
|
|
158
186
|
continue;
|
|
159
187
|
}
|
|
@@ -165,9 +193,9 @@ function validateExclusions(value, diagnostics) {
|
|
|
165
193
|
});
|
|
166
194
|
continue;
|
|
167
195
|
}
|
|
168
|
-
|
|
196
|
+
ignorePatterns.push(pattern);
|
|
169
197
|
}
|
|
170
|
-
return
|
|
198
|
+
return ignorePatterns;
|
|
171
199
|
}
|
|
172
200
|
function isRecord(value) {
|
|
173
201
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
package/dist/documents/scan.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { lstat, readFile, realpath } from "node:fs/promises";
|
|
2
2
|
import { isAbsolute, join, relative, sep } from "node:path";
|
|
3
3
|
import { convertPathToPattern, globby } from "globby";
|
|
4
|
-
import {
|
|
4
|
+
import { allowedConfigFileNames, } from "../configuration/index.js";
|
|
5
5
|
import { isErrorWithCode } from "../filesystem.js";
|
|
6
6
|
import { classifyDocument } from "./classify.js";
|
|
7
7
|
export async function scanDocuments({ rootPath, configuration, scope, }) {
|
|
@@ -9,7 +9,7 @@ export async function scanDocuments({ rootPath, configuration, scope, }) {
|
|
|
9
9
|
const discoveredPaths = await globby(createCandidatePatterns(resolvedScope), {
|
|
10
10
|
cwd: scanRootPath,
|
|
11
11
|
gitignore: true,
|
|
12
|
-
ignore: ["**/.git", "**/.git/**", ...configuration.
|
|
12
|
+
ignore: ["**/.git", "**/.git/**", ...configuration.ignorePatterns],
|
|
13
13
|
dot: true,
|
|
14
14
|
followSymbolicLinks: false,
|
|
15
15
|
braceExpansion: false,
|
|
@@ -21,9 +21,9 @@ export async function scanDocuments({ rootPath, configuration, scope, }) {
|
|
|
21
21
|
const diagnostics = [];
|
|
22
22
|
const unregisteredDocuments = [];
|
|
23
23
|
for (const path of discoveredPaths.sort(compareText)) {
|
|
24
|
-
if (
|
|
24
|
+
if (allowedConfigFileNames.some((fileName) => fileName === path))
|
|
25
25
|
continue;
|
|
26
|
-
if (path.endsWith(`/${
|
|
26
|
+
if (allowedConfigFileNames.some((fileName) => path.endsWith(`/${fileName}`))) {
|
|
27
27
|
diagnostics.push({
|
|
28
28
|
path,
|
|
29
29
|
field: "configuration",
|
|
@@ -102,7 +102,11 @@ async function resolveDocumentScanScope({ rootPath, scope, }) {
|
|
|
102
102
|
}
|
|
103
103
|
function createCandidatePatterns(scope) {
|
|
104
104
|
if (!scope) {
|
|
105
|
-
return [
|
|
105
|
+
return [
|
|
106
|
+
"**/*.md",
|
|
107
|
+
"**/*.mdx",
|
|
108
|
+
...allowedConfigFileNames.map((fileName) => `**/${fileName}`),
|
|
109
|
+
];
|
|
106
110
|
}
|
|
107
111
|
const directoryPattern = convertPathToPattern(scope.relativeDirectoryPath);
|
|
108
112
|
const directoryPrefix = directoryPattern === "" ? "" : `${directoryPattern}/`;
|
|
@@ -112,7 +116,7 @@ function createCandidatePatterns(scope) {
|
|
|
112
116
|
return [
|
|
113
117
|
`${candidatePrefix}*.md`,
|
|
114
118
|
`${candidatePrefix}*.mdx`,
|
|
115
|
-
`${candidatePrefix}${
|
|
119
|
+
...allowedConfigFileNames.map((fileName) => `${candidatePrefix}${fileName}`),
|
|
116
120
|
];
|
|
117
121
|
}
|
|
118
122
|
function createUsageCounts(declarations) {
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "waymark-docs",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "Agent-focused CLI that surfaces repository documentation to improve coding-agent performance.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai-agents",
|
|
7
7
|
"cli",
|
|
8
|
+
"context-engineering",
|
|
8
9
|
"documentation",
|
|
9
|
-
"markdown"
|
|
10
|
-
"repository"
|
|
10
|
+
"markdown"
|
|
11
11
|
],
|
|
12
12
|
"homepage": "https://github.com/ysfaran/waymark#readme",
|
|
13
13
|
"bugs": {
|
|
@@ -37,7 +37,10 @@
|
|
|
37
37
|
"dev": "tsx src/cli.ts",
|
|
38
38
|
"prepack": "cp ../README.md ../CHANGELOG.md ../LICENSE . && pnpm build",
|
|
39
39
|
"postpack": "rm -f README.md CHANGELOG.md LICENSE",
|
|
40
|
-
"
|
|
40
|
+
"test": "pnpm test:unit && pnpm test:integration",
|
|
41
|
+
"test:unit": "vitest run --config vitest.unit.config.ts",
|
|
42
|
+
"test:integration": "vitest run --config vitest.integration.config.ts",
|
|
43
|
+
"typecheck": "tsc --project tsconfig.json --noEmit && tsc --project tsconfig.test.json --noEmit"
|
|
41
44
|
},
|
|
42
45
|
"dependencies": {
|
|
43
46
|
"commander": "14.0.3",
|
|
@@ -47,7 +50,8 @@
|
|
|
47
50
|
"devDependencies": {
|
|
48
51
|
"@types/node": "24.10.10",
|
|
49
52
|
"tsx": "4.20.6",
|
|
50
|
-
"typescript": "7.0.2"
|
|
53
|
+
"typescript": "7.0.2",
|
|
54
|
+
"vitest": "4.0.18"
|
|
51
55
|
},
|
|
52
56
|
"engines": {
|
|
53
57
|
"node": ">=24"
|