waypoint-codex 0.13.2 → 0.14.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 +18 -0
- package/dist/src/core.js +87 -23
- package/dist/src/docs-index.js +20 -10
- package/dist/src/templates.js +29 -3
- package/package.json +1 -1
- package/templates/.gitignore.snippet +1 -0
- package/templates/.waypoint/config.toml +2 -2
package/README.md
CHANGED
|
@@ -72,6 +72,10 @@ The philosophy is simple:
|
|
|
72
72
|
- investigation before status narration
|
|
73
73
|
- structured workflows that stay in their own tools
|
|
74
74
|
|
|
75
|
+
By default, Waypoint routes docs from `.waypoint/docs/` and plans from `.waypoint/plans/`.
|
|
76
|
+
If your repo keeps routable docs elsewhere, you can add more explicit roots in `.waypoint/config.toml` with `docs_dirs` and `plans_dirs`.
|
|
77
|
+
Waypoint scans each configured root recursively and only includes Markdown files with valid Waypoint frontmatter.
|
|
78
|
+
|
|
75
79
|
## Best fit
|
|
76
80
|
|
|
77
81
|
Waypoint is most useful when you want:
|
|
@@ -117,6 +121,20 @@ repo/
|
|
|
117
121
|
|
|
118
122
|
From there, start your Codex session in the repo and follow the generated bootstrap in `AGENTS.md`.
|
|
119
123
|
|
|
124
|
+
If you want to add more routable roots, extend `.waypoint/config.toml` like this:
|
|
125
|
+
|
|
126
|
+
```toml
|
|
127
|
+
docs_dirs = [
|
|
128
|
+
".waypoint/docs",
|
|
129
|
+
"services/app/docs",
|
|
130
|
+
]
|
|
131
|
+
|
|
132
|
+
plans_dirs = [
|
|
133
|
+
".waypoint/plans",
|
|
134
|
+
"services/app/plans",
|
|
135
|
+
]
|
|
136
|
+
```
|
|
137
|
+
|
|
120
138
|
## Built-in skills
|
|
121
139
|
|
|
122
140
|
Waypoint ships a strong default skill pack for real coding work:
|
package/dist/src/core.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { existsSync, mkdirSync, readFileSync, readdirSync, rmSync, statSync, writeFileSync, } from "node:fs";
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, readdirSync, realpathSync, rmSync, statSync, writeFileSync, } from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import * as TOML from "@iarna/toml";
|
|
4
4
|
import { renderDocsIndex } from "./docs-index.js";
|
|
5
5
|
import { renderTracksIndex } from "./track-index.js";
|
|
6
|
-
import { readTemplate, renderWaypointConfig, MANAGED_BLOCK_END, MANAGED_BLOCK_START, templatePath } from "./templates.js";
|
|
6
|
+
import { defaultWaypointConfig, readTemplate, renderWaypointConfig, MANAGED_BLOCK_END, MANAGED_BLOCK_START, templatePath, } from "./templates.js";
|
|
7
7
|
const DEFAULT_CONFIG_PATH = ".waypoint/config.toml";
|
|
8
8
|
const DEFAULT_DOCS_DIR = ".waypoint/docs";
|
|
9
9
|
const DEFAULT_DOCS_INDEX = ".waypoint/DOCS_INDEX.md";
|
|
@@ -52,6 +52,7 @@ const LEGACY_WAYPOINT_GITIGNORE_RULES = new Set([
|
|
|
52
52
|
".waypoint/context/",
|
|
53
53
|
".waypoint/scripts/",
|
|
54
54
|
".waypoint/track/",
|
|
55
|
+
".waypoint/plans/",
|
|
55
56
|
".waypoint/*",
|
|
56
57
|
"!.waypoint/docs/",
|
|
57
58
|
"!.waypoint/docs/**",
|
|
@@ -83,18 +84,75 @@ const TIMESTAMPED_WORKSPACE_SECTIONS = new Set([
|
|
|
83
84
|
"## Done Recently",
|
|
84
85
|
]);
|
|
85
86
|
const TIMESTAMPED_ENTRY_PATTERN = /^(?:[-*]|\d+\.)\s+\[\d{4}-\d{2}-\d{2} \d{2}:\d{2} [A-Z]{2,5}\]/;
|
|
87
|
+
function configuredRootDirs(projectRoot, roots, legacyRoot, fallbackRoot) {
|
|
88
|
+
const configuredRoots = roots && roots.length > 0
|
|
89
|
+
? roots
|
|
90
|
+
: legacyRoot
|
|
91
|
+
? [legacyRoot]
|
|
92
|
+
: [fallbackRoot];
|
|
93
|
+
const normalizedRoots = [];
|
|
94
|
+
const seen = new Set();
|
|
95
|
+
for (const root of configuredRoots) {
|
|
96
|
+
const trimmedRoot = root.trim();
|
|
97
|
+
if (trimmedRoot.length === 0) {
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
const resolvedRoot = path.resolve(projectRoot, trimmedRoot);
|
|
101
|
+
let dedupeKey = path.normalize(resolvedRoot);
|
|
102
|
+
if (existsSync(resolvedRoot)) {
|
|
103
|
+
try {
|
|
104
|
+
dedupeKey = realpathSync(resolvedRoot);
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
dedupeKey = path.normalize(resolvedRoot);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
if (seen.has(dedupeKey)) {
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
seen.add(dedupeKey);
|
|
114
|
+
normalizedRoots.push(resolvedRoot);
|
|
115
|
+
}
|
|
116
|
+
return normalizedRoots.length > 0 ? normalizedRoots : [path.resolve(projectRoot, fallbackRoot)];
|
|
117
|
+
}
|
|
118
|
+
function docsRootDirs(projectRoot, config) {
|
|
119
|
+
return configuredRootDirs(projectRoot, config?.docs_dirs, config?.docs_dir, DEFAULT_DOCS_DIR);
|
|
120
|
+
}
|
|
121
|
+
function plansRootDirs(projectRoot, config) {
|
|
122
|
+
return configuredRootDirs(projectRoot, config?.plans_dirs, config?.plans_dir, DEFAULT_PLANS_DIR);
|
|
123
|
+
}
|
|
124
|
+
function docsSectionHeading(projectRoot, dir) {
|
|
125
|
+
const relativePath = path.relative(projectRoot, dir).split(path.sep).join("/");
|
|
126
|
+
const normalizedPath = relativePath.length === 0 ? "." : relativePath;
|
|
127
|
+
return normalizedPath.endsWith("/") ? normalizedPath : `${normalizedPath}/`;
|
|
128
|
+
}
|
|
86
129
|
function docsIndexSections(projectRoot, config) {
|
|
87
130
|
return [
|
|
88
|
-
{
|
|
89
|
-
heading:
|
|
90
|
-
dir
|
|
91
|
-
},
|
|
92
|
-
{
|
|
93
|
-
heading:
|
|
94
|
-
dir
|
|
95
|
-
},
|
|
131
|
+
...docsRootDirs(projectRoot, config).map((dir) => ({
|
|
132
|
+
heading: docsSectionHeading(projectRoot, dir),
|
|
133
|
+
dir,
|
|
134
|
+
})),
|
|
135
|
+
...plansRootDirs(projectRoot, config).map((dir) => ({
|
|
136
|
+
heading: docsSectionHeading(projectRoot, dir),
|
|
137
|
+
dir,
|
|
138
|
+
})),
|
|
96
139
|
];
|
|
97
140
|
}
|
|
141
|
+
function buildWaypointConfig(projectRoot, existingConfig, options) {
|
|
142
|
+
const defaults = defaultWaypointConfig({ profile: options.profile });
|
|
143
|
+
return {
|
|
144
|
+
version: existingConfig?.version ?? defaults.version,
|
|
145
|
+
profile: options.profile,
|
|
146
|
+
workspace_file: existingConfig?.workspace_file ?? defaults.workspace_file,
|
|
147
|
+
docs_dirs: configuredRootDirs(projectRoot, existingConfig?.docs_dirs, existingConfig?.docs_dir, DEFAULT_DOCS_DIR).map((dir) => path.relative(projectRoot, dir).split(path.sep).join("/")),
|
|
148
|
+
plans_dirs: configuredRootDirs(projectRoot, existingConfig?.plans_dirs, existingConfig?.plans_dir, DEFAULT_PLANS_DIR).map((dir) => path.relative(projectRoot, dir).split(path.sep).join("/")),
|
|
149
|
+
docs_index_file: existingConfig?.docs_index_file ?? defaults.docs_index_file,
|
|
150
|
+
features: {
|
|
151
|
+
repo_skills: existingConfig?.features?.repo_skills ?? defaults.features?.repo_skills,
|
|
152
|
+
docs_index: existingConfig?.features?.docs_index ?? defaults.features?.docs_index,
|
|
153
|
+
},
|
|
154
|
+
};
|
|
155
|
+
}
|
|
98
156
|
function ensureDir(dirPath) {
|
|
99
157
|
mkdirSync(dirPath, { recursive: true });
|
|
100
158
|
}
|
|
@@ -287,6 +345,7 @@ function scaffoldOptionalCodex(projectRoot) {
|
|
|
287
345
|
export function initRepository(projectRoot, options) {
|
|
288
346
|
ensureDir(projectRoot);
|
|
289
347
|
migrateLegacyRootFiles(projectRoot);
|
|
348
|
+
const config = buildWaypointConfig(projectRoot, loadWaypointConfig(projectRoot), options);
|
|
290
349
|
// Any Waypoint-owned path removed from the scaffold should be added here
|
|
291
350
|
// so `waypoint init` / `waypoint upgrade` can actively prune stale copies.
|
|
292
351
|
for (const deprecatedPath of [
|
|
@@ -324,9 +383,7 @@ export function initRepository(projectRoot, options) {
|
|
|
324
383
|
writeText(path.join(projectRoot, ".waypoint/agent-operating-manual.md"), readTemplate(".waypoint/agent-operating-manual.md"));
|
|
325
384
|
writeIfMissing(path.join(projectRoot, DEFAULT_MEMORY), readTemplate(".waypoint/MEMORY.md"));
|
|
326
385
|
scaffoldWaypointOptionalTemplates(projectRoot);
|
|
327
|
-
writeText(path.join(projectRoot, DEFAULT_CONFIG_PATH), renderWaypointConfig(
|
|
328
|
-
profile: options.profile,
|
|
329
|
-
}));
|
|
386
|
+
writeText(path.join(projectRoot, DEFAULT_CONFIG_PATH), renderWaypointConfig(config));
|
|
330
387
|
writeIfMissing(path.join(projectRoot, DEFAULT_WORKSPACE), readTemplate("WORKSPACE.md"));
|
|
331
388
|
ensureDir(path.join(projectRoot, DEFAULT_DOCS_DIR));
|
|
332
389
|
ensureDir(path.join(projectRoot, DEFAULT_PLANS_DIR));
|
|
@@ -338,9 +395,10 @@ export function initRepository(projectRoot, options) {
|
|
|
338
395
|
scaffoldSkills(projectRoot);
|
|
339
396
|
scaffoldOptionalCodex(projectRoot);
|
|
340
397
|
appendGitignoreSnippet(projectRoot);
|
|
341
|
-
const
|
|
398
|
+
const docsIndexPath = path.join(projectRoot, config.docs_index_file ?? DEFAULT_DOCS_INDEX);
|
|
399
|
+
const docsIndex = renderDocsIndex(projectRoot, docsIndexSections(projectRoot, config));
|
|
342
400
|
const tracksIndex = renderTracksIndex(projectRoot, path.join(projectRoot, DEFAULT_TRACK_DIR));
|
|
343
|
-
writeText(
|
|
401
|
+
writeText(docsIndexPath, `${docsIndex.content}\n`);
|
|
344
402
|
writeText(path.join(projectRoot, DEFAULT_TRACKS_INDEX), `${tracksIndex.content}\n`);
|
|
345
403
|
return [
|
|
346
404
|
"Initialized Waypoint scaffold",
|
|
@@ -475,27 +533,33 @@ export function doctorRepository(projectRoot) {
|
|
|
475
533
|
}
|
|
476
534
|
}
|
|
477
535
|
const docsIndexPath = path.join(projectRoot, config.docs_index_file ?? DEFAULT_DOCS_INDEX);
|
|
478
|
-
const
|
|
479
|
-
const
|
|
536
|
+
const configuredDocsDirs = docsRootDirs(projectRoot, config);
|
|
537
|
+
const configuredPlansDirs = plansRootDirs(projectRoot, config);
|
|
480
538
|
const docsIndex = renderDocsIndex(projectRoot, docsIndexSections(projectRoot, config));
|
|
481
539
|
const trackDir = path.join(projectRoot, DEFAULT_TRACK_DIR);
|
|
482
540
|
const tracksIndexPath = path.join(projectRoot, DEFAULT_TRACKS_INDEX);
|
|
483
541
|
const tracksIndex = renderTracksIndex(projectRoot, trackDir);
|
|
484
|
-
|
|
542
|
+
for (const docsDir of configuredDocsDirs) {
|
|
543
|
+
if (existsSync(docsDir)) {
|
|
544
|
+
continue;
|
|
545
|
+
}
|
|
485
546
|
findings.push({
|
|
486
547
|
severity: "error",
|
|
487
548
|
category: "docs",
|
|
488
|
-
message:
|
|
489
|
-
remediation: "
|
|
549
|
+
message: `${docsSectionHeading(projectRoot, docsDir)} directory is missing.`,
|
|
550
|
+
remediation: "Create the configured docs directory or update `.waypoint/config.toml`.",
|
|
490
551
|
paths: [docsDir],
|
|
491
552
|
});
|
|
492
553
|
}
|
|
493
|
-
|
|
554
|
+
for (const plansDir of configuredPlansDirs) {
|
|
555
|
+
if (existsSync(plansDir)) {
|
|
556
|
+
continue;
|
|
557
|
+
}
|
|
494
558
|
findings.push({
|
|
495
559
|
severity: "error",
|
|
496
560
|
category: "docs",
|
|
497
|
-
message:
|
|
498
|
-
remediation: "
|
|
561
|
+
message: `${docsSectionHeading(projectRoot, plansDir)} directory is missing.`,
|
|
562
|
+
remediation: "Create the configured plans directory or update `.waypoint/config.toml`.",
|
|
499
563
|
paths: [plansDir],
|
|
500
564
|
});
|
|
501
565
|
}
|
package/dist/src/docs-index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { existsSync, readFileSync, readdirSync, realpathSync } from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
const SKIP_DIRS = new Set([
|
|
4
4
|
".git",
|
|
@@ -50,18 +50,25 @@ function parseFrontmatter(filePath) {
|
|
|
50
50
|
}
|
|
51
51
|
return { summary, lastUpdated, readWhen };
|
|
52
52
|
}
|
|
53
|
-
function walkDocs(projectRoot, currentDir, output, invalid) {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
53
|
+
function walkDocs(projectRoot, currentDir, output, invalid, visitedDirs) {
|
|
54
|
+
const resolvedCurrentDir = realpathSync(currentDir);
|
|
55
|
+
if (visitedDirs.has(resolvedCurrentDir)) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
visitedDirs.add(resolvedCurrentDir);
|
|
59
|
+
for (const entry of readdirSync(currentDir, { withFileTypes: true })) {
|
|
60
|
+
if (entry.isSymbolicLink()) {
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
const fullPath = path.join(currentDir, entry.name);
|
|
64
|
+
if (entry.isDirectory()) {
|
|
65
|
+
if (SKIP_DIRS.has(entry.name)) {
|
|
59
66
|
continue;
|
|
60
67
|
}
|
|
61
|
-
walkDocs(projectRoot, fullPath, output, invalid);
|
|
68
|
+
walkDocs(projectRoot, fullPath, output, invalid, visitedDirs);
|
|
62
69
|
continue;
|
|
63
70
|
}
|
|
64
|
-
if (!
|
|
71
|
+
if (!isMarkdownDoc(entry)) {
|
|
65
72
|
continue;
|
|
66
73
|
}
|
|
67
74
|
const { summary, lastUpdated, readWhen } = parseFrontmatter(fullPath);
|
|
@@ -77,10 +84,13 @@ function collectDocEntries(projectRoot, docsDir) {
|
|
|
77
84
|
const entries = [];
|
|
78
85
|
const invalidDocs = [];
|
|
79
86
|
if (existsSync(docsDir)) {
|
|
80
|
-
walkDocs(projectRoot, docsDir, entries, invalidDocs);
|
|
87
|
+
walkDocs(projectRoot, docsDir, entries, invalidDocs, new Set());
|
|
81
88
|
}
|
|
82
89
|
return { entries, invalidDocs };
|
|
83
90
|
}
|
|
91
|
+
function isMarkdownDoc(entry) {
|
|
92
|
+
return entry.isFile() && entry.name.endsWith(".md") && !SKIP_NAMES.has(entry.name);
|
|
93
|
+
}
|
|
84
94
|
export function renderDocsIndex(projectRoot, sections) {
|
|
85
95
|
const lines = [
|
|
86
96
|
"# Docs Index",
|
package/dist/src/templates.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import * as TOML from "@iarna/toml";
|
|
1
2
|
import { readFileSync } from "node:fs";
|
|
2
3
|
import { existsSync } from "node:fs";
|
|
3
4
|
import { fileURLToPath } from "node:url";
|
|
@@ -25,7 +26,32 @@ export function templatePath(relativePath) {
|
|
|
25
26
|
export function readTemplate(relativePath) {
|
|
26
27
|
return readFileSync(templatePath(relativePath), "utf8");
|
|
27
28
|
}
|
|
28
|
-
export function
|
|
29
|
-
return
|
|
30
|
-
|
|
29
|
+
export function defaultWaypointConfig(options) {
|
|
30
|
+
return {
|
|
31
|
+
version: 1,
|
|
32
|
+
profile: options.profile,
|
|
33
|
+
workspace_file: ".waypoint/WORKSPACE.md",
|
|
34
|
+
docs_dirs: [".waypoint/docs"],
|
|
35
|
+
plans_dirs: [".waypoint/plans"],
|
|
36
|
+
docs_index_file: ".waypoint/DOCS_INDEX.md",
|
|
37
|
+
features: {
|
|
38
|
+
repo_skills: true,
|
|
39
|
+
docs_index: true,
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
export function renderWaypointConfig(config) {
|
|
44
|
+
const renderedConfig = {
|
|
45
|
+
version: config.version,
|
|
46
|
+
profile: config.profile,
|
|
47
|
+
workspace_file: config.workspace_file,
|
|
48
|
+
docs_dirs: config.docs_dirs,
|
|
49
|
+
plans_dirs: config.plans_dirs,
|
|
50
|
+
docs_index_file: config.docs_index_file,
|
|
51
|
+
features: config.features ? {
|
|
52
|
+
repo_skills: config.features.repo_skills,
|
|
53
|
+
docs_index: config.features.docs_index,
|
|
54
|
+
} : undefined,
|
|
55
|
+
};
|
|
56
|
+
return TOML.stringify(renderedConfig);
|
|
31
57
|
}
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
version = 1
|
|
2
2
|
profile = "__PROFILE__"
|
|
3
3
|
workspace_file = ".waypoint/WORKSPACE.md"
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
docs_dirs = [".waypoint/docs"]
|
|
5
|
+
plans_dirs = [".waypoint/plans"]
|
|
6
6
|
docs_index_file = ".waypoint/DOCS_INDEX.md"
|
|
7
7
|
|
|
8
8
|
[features]
|