waypoint-codex 0.7.0 → 0.8.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 +16 -7
- package/dist/src/cli.js +14 -3
- package/dist/src/core.js +71 -6
- package/dist/src/track-index.js +107 -0
- package/dist/src/upgrade.js +100 -0
- package/package.json +1 -1
- package/templates/.agents/skills/code-guide-audit/SKILL.md +2 -0
- package/templates/.agents/skills/planning/SKILL.md +2 -0
- package/templates/.agents/skills/work-tracker/SKILL.md +110 -0
- package/templates/.agents/skills/workspace-compress/SKILL.md +3 -0
- package/templates/.waypoint/agent-operating-manual.md +5 -4
- package/templates/.waypoint/docs/README.md +2 -0
- package/templates/.waypoint/scripts/build-track-index.mjs +169 -0
- package/templates/.waypoint/scripts/prepare-context.mjs +24 -0
- package/templates/.waypoint/track/README.md +38 -0
- package/templates/.waypoint/track/_template.md +44 -0
- package/templates/WORKSPACE.md +5 -1
- package/templates/managed-agents-block.md +2 -0
- package/templates/.agents/skills/error-audit/SKILL.md +0 -69
- package/templates/.agents/skills/error-audit/references/error-patterns.md +0 -37
- package/templates/.agents/skills/observability-audit/SKILL.md +0 -67
- package/templates/.agents/skills/observability-audit/references/observability-patterns.md +0 -35
- package/templates/.agents/skills/ux-states-audit/SKILL.md +0 -63
- package/templates/.agents/skills/ux-states-audit/references/ux-patterns.md +0 -34
package/README.md
CHANGED
|
@@ -22,10 +22,12 @@ Waypoint scaffolds a Codex-friendly repo structure built around a few core piece
|
|
|
22
22
|
|
|
23
23
|
- `AGENTS.md` for the startup contract
|
|
24
24
|
- `.waypoint/WORKSPACE.md` for live operational state
|
|
25
|
+
- `.waypoint/track/` for active long-running execution trackers
|
|
25
26
|
- `.waypoint/docs/` for durable project memory
|
|
26
27
|
- `.waypoint/DOCS_INDEX.md` for docs routing
|
|
28
|
+
- `.waypoint/TRACKS_INDEX.md` for tracker routing
|
|
27
29
|
- `.waypoint/context/` for generated startup context
|
|
28
|
-
- `.agents/skills/` for repo-local workflows like planning, audits, and QA
|
|
30
|
+
- `.agents/skills/` for repo-local workflows like planning, tracking, audits, and QA
|
|
29
31
|
|
|
30
32
|
The philosophy is simple:
|
|
31
33
|
|
|
@@ -40,7 +42,7 @@ Waypoint is most useful when you want:
|
|
|
40
42
|
|
|
41
43
|
- multi-session continuity in a real repo
|
|
42
44
|
- a durable docs and workspace structure for agents
|
|
43
|
-
- stronger planning, review, QA, and closeout defaults
|
|
45
|
+
- stronger planning, tracking, review, QA, and closeout defaults
|
|
44
46
|
- repo-local scaffolding instead of a bunch of global mystery behavior
|
|
45
47
|
|
|
46
48
|
If you only use Codex for tiny one-off edits, Waypoint is probably unnecessary.
|
|
@@ -76,9 +78,11 @@ repo/
|
|
|
76
78
|
├── .agents/
|
|
77
79
|
│ └── skills/
|
|
78
80
|
└── .waypoint/
|
|
79
|
-
├── WORKSPACE.md
|
|
80
81
|
├── DOCS_INDEX.md
|
|
82
|
+
├── TRACKS_INDEX.md
|
|
83
|
+
├── WORKSPACE.md
|
|
81
84
|
├── docs/
|
|
85
|
+
├── track/
|
|
82
86
|
├── context/
|
|
83
87
|
├── scripts/
|
|
84
88
|
└── ...
|
|
@@ -94,6 +98,12 @@ From there, start your Codex session in the repo and follow the generated bootst
|
|
|
94
98
|
waypoint init
|
|
95
99
|
```
|
|
96
100
|
|
|
101
|
+
By default, `waypoint init` updates the global CLI to the latest published `waypoint-codex` first, then scaffolds with that fresh version. If you want to scaffold with the currently installed binary instead, use:
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
waypoint init --skip-cli-update
|
|
105
|
+
```
|
|
106
|
+
|
|
97
107
|
### Full local workflow setup
|
|
98
108
|
|
|
99
109
|
```bash
|
|
@@ -112,10 +122,11 @@ Flags you can combine:
|
|
|
112
122
|
- `--with-roles`
|
|
113
123
|
- `--with-rules`
|
|
114
124
|
- `--with-automations`
|
|
125
|
+
- `--skip-cli-update`
|
|
115
126
|
|
|
116
127
|
## Main commands
|
|
117
128
|
|
|
118
|
-
- `waypoint init` — scaffold or refresh the repo
|
|
129
|
+
- `waypoint init` — update the CLI to latest by default, then scaffold or refresh the repo
|
|
119
130
|
- `waypoint doctor` — validate health and report drift
|
|
120
131
|
- `waypoint sync` — rebuild the docs index and sync optional user-home artifacts
|
|
121
132
|
- `waypoint upgrade` — update the CLI and refresh the current repo using its saved config
|
|
@@ -126,9 +137,7 @@ Flags you can combine:
|
|
|
126
137
|
Waypoint ships a strong default skill pack for real coding work:
|
|
127
138
|
|
|
128
139
|
- `planning`
|
|
129
|
-
- `
|
|
130
|
-
- `observability-audit`
|
|
131
|
-
- `ux-states-audit`
|
|
140
|
+
- `work-tracker`
|
|
132
141
|
- `docs-sync`
|
|
133
142
|
- `code-guide-audit`
|
|
134
143
|
- `break-it-qa`
|
package/dist/src/cli.js
CHANGED
|
@@ -5,7 +5,7 @@ import { fileURLToPath } from "node:url";
|
|
|
5
5
|
import path from "node:path";
|
|
6
6
|
import process from "node:process";
|
|
7
7
|
import { doctorRepository, importLegacyRepo, initRepository, loadWaypointConfig, syncRepository } from "./core.js";
|
|
8
|
-
import { upgradeWaypoint } from "./upgrade.js";
|
|
8
|
+
import { maybeUpgradeWaypointBeforeInit, upgradeWaypoint } from "./upgrade.js";
|
|
9
9
|
const VERSION = JSON.parse(readFileSync(path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../../package.json"), "utf8")).version;
|
|
10
10
|
function resolveRepo(input) {
|
|
11
11
|
return path.resolve(input ?? ".");
|
|
@@ -27,7 +27,7 @@ function printHelp() {
|
|
|
27
27
|
console.log(`usage: waypoint [--version] <command> [options]
|
|
28
28
|
|
|
29
29
|
Commands:
|
|
30
|
-
init Initialize a repository with Waypoint scaffolding
|
|
30
|
+
init Initialize a repository with Waypoint scaffolding (auto-updates CLI unless skipped)
|
|
31
31
|
doctor Validate repository health and report drift
|
|
32
32
|
sync Rebuild docs index and sync optional user-home artifacts
|
|
33
33
|
upgrade Update the global Waypoint CLI and refresh this repo using existing config
|
|
@@ -52,11 +52,22 @@ async function main() {
|
|
|
52
52
|
"app-friendly": { type: "boolean", default: false },
|
|
53
53
|
"with-roles": { type: "boolean", default: false },
|
|
54
54
|
"with-rules": { type: "boolean", default: false },
|
|
55
|
-
"with-automations": { type: "boolean", default: false }
|
|
55
|
+
"with-automations": { type: "boolean", default: false },
|
|
56
|
+
"skip-cli-update": { type: "boolean", default: false }
|
|
56
57
|
},
|
|
57
58
|
allowPositionals: true
|
|
58
59
|
});
|
|
59
60
|
const projectRoot = resolveRepo(positionals[0]);
|
|
61
|
+
if (!values["skip-cli-update"]) {
|
|
62
|
+
const status = maybeUpgradeWaypointBeforeInit({
|
|
63
|
+
currentVersion: VERSION,
|
|
64
|
+
cliEntry: process.argv[1] ? path.resolve(process.argv[1]) : fileURLToPath(import.meta.url),
|
|
65
|
+
initArgs: argv.slice(1),
|
|
66
|
+
});
|
|
67
|
+
if (status !== null) {
|
|
68
|
+
return status;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
60
71
|
const results = initRepository(projectRoot, {
|
|
61
72
|
profile: values["app-friendly"] ? "app-friendly" : "universal",
|
|
62
73
|
withRoles: values["with-roles"],
|
package/dist/src/core.js
CHANGED
|
@@ -4,14 +4,18 @@ import os from "node:os";
|
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import * as TOML from "@iarna/toml";
|
|
6
6
|
import { renderDocsIndex } from "./docs-index.js";
|
|
7
|
+
import { renderTracksIndex } from "./track-index.js";
|
|
7
8
|
import { readTemplate, renderWaypointConfig, MANAGED_BLOCK_END, MANAGED_BLOCK_START, templatePath } from "./templates.js";
|
|
8
9
|
const DEFAULT_CONFIG_PATH = ".waypoint/config.toml";
|
|
9
10
|
const DEFAULT_DOCS_DIR = ".waypoint/docs";
|
|
10
11
|
const DEFAULT_DOCS_INDEX = ".waypoint/DOCS_INDEX.md";
|
|
12
|
+
const DEFAULT_TRACK_DIR = ".waypoint/track";
|
|
13
|
+
const DEFAULT_TRACKS_INDEX = ".waypoint/TRACKS_INDEX.md";
|
|
11
14
|
const DEFAULT_WORKSPACE = ".waypoint/WORKSPACE.md";
|
|
12
15
|
const STATE_DIR = ".waypoint/state";
|
|
13
16
|
const SYNC_RECORDS_FILE = ".waypoint/state/sync-records.json";
|
|
14
17
|
const TIMESTAMPED_WORKSPACE_SECTIONS = new Set([
|
|
18
|
+
"## Active Trackers",
|
|
15
19
|
"## Current State",
|
|
16
20
|
"## In Progress",
|
|
17
21
|
"## Next",
|
|
@@ -101,6 +105,7 @@ function scaffoldWaypointOptionalTemplates(projectRoot) {
|
|
|
101
105
|
copyTemplateTree(templatePath(".waypoint/automations"), path.join(projectRoot, ".waypoint/automations"));
|
|
102
106
|
copyTemplateTree(templatePath(".waypoint/rules"), path.join(projectRoot, ".waypoint/rules"));
|
|
103
107
|
copyTemplateTree(templatePath(".waypoint/scripts"), path.join(projectRoot, ".waypoint/scripts"));
|
|
108
|
+
copyTemplateTree(templatePath(".waypoint/track"), path.join(projectRoot, ".waypoint/track"));
|
|
104
109
|
}
|
|
105
110
|
function scaffoldOptionalCodex(projectRoot) {
|
|
106
111
|
copyTemplateTree(templatePath(".codex"), path.join(projectRoot, ".codex"));
|
|
@@ -112,6 +117,9 @@ export function initRepository(projectRoot, options) {
|
|
|
112
117
|
"docs/README.md",
|
|
113
118
|
"docs/code-guide.md",
|
|
114
119
|
"docs/legacy-import",
|
|
120
|
+
".agents/skills/error-audit",
|
|
121
|
+
".agents/skills/observability-audit",
|
|
122
|
+
".agents/skills/ux-states-audit",
|
|
115
123
|
"WAYPOINT_MIGRATION.md",
|
|
116
124
|
".agents/skills/waypoint-planning",
|
|
117
125
|
".agents/skills/waypoint-docs",
|
|
@@ -145,6 +153,7 @@ export function initRepository(projectRoot, options) {
|
|
|
145
153
|
}));
|
|
146
154
|
writeIfMissing(path.join(projectRoot, DEFAULT_WORKSPACE), readTemplate("WORKSPACE.md"));
|
|
147
155
|
ensureDir(path.join(projectRoot, DEFAULT_DOCS_DIR));
|
|
156
|
+
ensureDir(path.join(projectRoot, DEFAULT_TRACK_DIR));
|
|
148
157
|
writeIfMissing(path.join(projectRoot, ".waypoint/docs/README.md"), readTemplate(".waypoint/docs/README.md"));
|
|
149
158
|
writeIfMissing(path.join(projectRoot, ".waypoint/docs/code-guide.md"), readTemplate(".waypoint/docs/code-guide.md"));
|
|
150
159
|
upsertManagedBlock(path.join(projectRoot, "AGENTS.md"), readTemplate("managed-agents-block.md"));
|
|
@@ -154,13 +163,15 @@ export function initRepository(projectRoot, options) {
|
|
|
154
163
|
}
|
|
155
164
|
appendGitignoreSnippet(projectRoot);
|
|
156
165
|
const docsIndex = renderDocsIndex(projectRoot, path.join(projectRoot, DEFAULT_DOCS_DIR));
|
|
166
|
+
const tracksIndex = renderTracksIndex(projectRoot, path.join(projectRoot, DEFAULT_TRACK_DIR));
|
|
157
167
|
writeText(path.join(projectRoot, DEFAULT_DOCS_INDEX), `${docsIndex.content}\n`);
|
|
168
|
+
writeText(path.join(projectRoot, DEFAULT_TRACKS_INDEX), `${tracksIndex.content}\n`);
|
|
158
169
|
return [
|
|
159
170
|
"Initialized Waypoint scaffold",
|
|
160
171
|
"Installed managed AGENTS block",
|
|
161
|
-
"Created .waypoint/WORKSPACE.md and .waypoint/
|
|
172
|
+
"Created .waypoint/WORKSPACE.md, .waypoint/docs/, and .waypoint/track/ scaffold",
|
|
162
173
|
"Installed repo-local Waypoint skills",
|
|
163
|
-
"Generated .waypoint/DOCS_INDEX.md",
|
|
174
|
+
"Generated .waypoint/DOCS_INDEX.md and .waypoint/TRACKS_INDEX.md",
|
|
164
175
|
];
|
|
165
176
|
}
|
|
166
177
|
export function loadWaypointConfig(projectRoot) {
|
|
@@ -366,6 +377,7 @@ export function doctorRepository(projectRoot) {
|
|
|
366
377
|
const workspaceText = readFileSync(workspacePath, "utf8");
|
|
367
378
|
for (const section of [
|
|
368
379
|
"## Active Goal",
|
|
380
|
+
"## Active Trackers",
|
|
369
381
|
"## Current State",
|
|
370
382
|
"## In Progress",
|
|
371
383
|
"## Next",
|
|
@@ -398,6 +410,7 @@ export function doctorRepository(projectRoot) {
|
|
|
398
410
|
path.join(projectRoot, ".waypoint", "agent-operating-manual.md"),
|
|
399
411
|
path.join(projectRoot, ".waypoint", "scripts", "prepare-context.mjs"),
|
|
400
412
|
path.join(projectRoot, ".waypoint", "scripts", "build-docs-index.mjs"),
|
|
413
|
+
path.join(projectRoot, ".waypoint", "scripts", "build-track-index.mjs"),
|
|
401
414
|
]) {
|
|
402
415
|
if (!existsSync(requiredFile)) {
|
|
403
416
|
findings.push({
|
|
@@ -412,6 +425,9 @@ export function doctorRepository(projectRoot) {
|
|
|
412
425
|
const docsDir = path.join(projectRoot, config.docs_dir ?? DEFAULT_DOCS_DIR);
|
|
413
426
|
const docsIndexPath = path.join(projectRoot, config.docs_index_file ?? DEFAULT_DOCS_INDEX);
|
|
414
427
|
const docsIndex = renderDocsIndex(projectRoot, docsDir);
|
|
428
|
+
const trackDir = path.join(projectRoot, DEFAULT_TRACK_DIR);
|
|
429
|
+
const tracksIndexPath = path.join(projectRoot, DEFAULT_TRACKS_INDEX);
|
|
430
|
+
const tracksIndex = renderTracksIndex(projectRoot, trackDir);
|
|
415
431
|
if (!existsSync(docsDir)) {
|
|
416
432
|
findings.push({
|
|
417
433
|
severity: "error",
|
|
@@ -448,11 +464,56 @@ export function doctorRepository(projectRoot) {
|
|
|
448
464
|
paths: [docsIndexPath],
|
|
449
465
|
});
|
|
450
466
|
}
|
|
467
|
+
if (!existsSync(trackDir)) {
|
|
468
|
+
findings.push({
|
|
469
|
+
severity: "error",
|
|
470
|
+
category: "track",
|
|
471
|
+
message: ".waypoint/track/ directory is missing.",
|
|
472
|
+
remediation: "Run `waypoint init` to scaffold track files.",
|
|
473
|
+
paths: [trackDir],
|
|
474
|
+
});
|
|
475
|
+
}
|
|
476
|
+
for (const relPath of tracksIndex.invalidTracks) {
|
|
477
|
+
findings.push({
|
|
478
|
+
severity: "warn",
|
|
479
|
+
category: "track",
|
|
480
|
+
message: `Tracker is missing valid frontmatter or status: ${relPath}`,
|
|
481
|
+
remediation: "Add `summary`, `last_updated`, `status`, and `read_when` frontmatter using the track template.",
|
|
482
|
+
paths: [path.join(projectRoot, relPath)],
|
|
483
|
+
});
|
|
484
|
+
}
|
|
485
|
+
if (!existsSync(tracksIndexPath)) {
|
|
486
|
+
findings.push({
|
|
487
|
+
severity: "warn",
|
|
488
|
+
category: "track",
|
|
489
|
+
message: ".waypoint/TRACKS_INDEX.md is missing.",
|
|
490
|
+
remediation: "Run `waypoint sync` to generate the tracks index.",
|
|
491
|
+
paths: [tracksIndexPath],
|
|
492
|
+
});
|
|
493
|
+
}
|
|
494
|
+
else if (readFileSync(tracksIndexPath, "utf8").trimEnd() !== tracksIndex.content.trimEnd()) {
|
|
495
|
+
findings.push({
|
|
496
|
+
severity: "warn",
|
|
497
|
+
category: "track",
|
|
498
|
+
message: ".waypoint/TRACKS_INDEX.md is stale.",
|
|
499
|
+
remediation: "Run `waypoint sync` to rebuild the tracks index.",
|
|
500
|
+
paths: [tracksIndexPath],
|
|
501
|
+
});
|
|
502
|
+
}
|
|
503
|
+
if (existsSync(workspacePath) &&
|
|
504
|
+
tracksIndex.activeTrackPaths.length > 0 &&
|
|
505
|
+
!tracksIndex.activeTrackPaths.some((trackPath) => readFileSync(workspacePath, "utf8").includes(trackPath))) {
|
|
506
|
+
findings.push({
|
|
507
|
+
severity: "warn",
|
|
508
|
+
category: "track",
|
|
509
|
+
message: "Workspace does not reference any active tracker file.",
|
|
510
|
+
remediation: "Add the active `.waypoint/track/*.md` file paths under `## Active Trackers` in `.waypoint/WORKSPACE.md`.",
|
|
511
|
+
paths: [workspacePath, ...tracksIndex.activeTrackPaths.map((trackPath) => path.join(projectRoot, trackPath))],
|
|
512
|
+
});
|
|
513
|
+
}
|
|
451
514
|
for (const skillName of [
|
|
452
515
|
"planning",
|
|
453
|
-
"
|
|
454
|
-
"observability-audit",
|
|
455
|
-
"ux-states-audit",
|
|
516
|
+
"work-tracker",
|
|
456
517
|
"docs-sync",
|
|
457
518
|
"code-guide-audit",
|
|
458
519
|
"break-it-qa",
|
|
@@ -528,8 +589,12 @@ export function syncRepository(projectRoot) {
|
|
|
528
589
|
const docsDir = path.join(projectRoot, config.docs_dir ?? DEFAULT_DOCS_DIR);
|
|
529
590
|
const docsIndexPath = path.join(projectRoot, config.docs_index_file ?? DEFAULT_DOCS_INDEX);
|
|
530
591
|
const docsIndex = renderDocsIndex(projectRoot, docsDir);
|
|
592
|
+
const trackDir = path.join(projectRoot, DEFAULT_TRACK_DIR);
|
|
593
|
+
const tracksIndexPath = path.join(projectRoot, DEFAULT_TRACKS_INDEX);
|
|
594
|
+
const tracksIndex = renderTracksIndex(projectRoot, trackDir);
|
|
531
595
|
writeText(docsIndexPath, `${docsIndex.content}\n`);
|
|
532
|
-
|
|
596
|
+
writeText(tracksIndexPath, `${tracksIndex.content}\n`);
|
|
597
|
+
const results = ["Rebuilt .waypoint/DOCS_INDEX.md", "Rebuilt .waypoint/TRACKS_INDEX.md"];
|
|
533
598
|
const featureMap = config.features ?? {};
|
|
534
599
|
if (featureMap.rules) {
|
|
535
600
|
results.push(...syncRules(projectRoot));
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
const VALID_TRACK_STATUSES = new Set(["active", "blocked", "paused", "done", "archived"]);
|
|
4
|
+
const ACTIVE_TRACK_STATUSES = new Set(["active", "blocked", "paused"]);
|
|
5
|
+
const SKIP_NAMES = new Set(["README.md", "CHANGELOG.md", "LICENSE.md"]);
|
|
6
|
+
function shouldSkipTrackFile(entry) {
|
|
7
|
+
return SKIP_NAMES.has(entry) || entry.startsWith("_");
|
|
8
|
+
}
|
|
9
|
+
function parseFrontmatter(filePath) {
|
|
10
|
+
const text = readFileSync(filePath, "utf8");
|
|
11
|
+
if (!text.startsWith("---\n")) {
|
|
12
|
+
return { summary: "", lastUpdated: "", readWhen: [], status: "" };
|
|
13
|
+
}
|
|
14
|
+
const endIndex = text.indexOf("\n---\n", 4);
|
|
15
|
+
if (endIndex === -1) {
|
|
16
|
+
return { summary: "", lastUpdated: "", readWhen: [], status: "" };
|
|
17
|
+
}
|
|
18
|
+
const frontmatter = text.slice(4, endIndex);
|
|
19
|
+
let summary = "";
|
|
20
|
+
let lastUpdated = "";
|
|
21
|
+
let status = "";
|
|
22
|
+
const readWhen = [];
|
|
23
|
+
let collectingReadWhen = false;
|
|
24
|
+
for (const rawLine of frontmatter.split("\n")) {
|
|
25
|
+
const line = rawLine.trim();
|
|
26
|
+
if (line.startsWith("summary:")) {
|
|
27
|
+
summary = line.slice("summary:".length).trim().replace(/^['"]|['"]$/g, "");
|
|
28
|
+
collectingReadWhen = false;
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
if (line.startsWith("last_updated:")) {
|
|
32
|
+
lastUpdated = line.slice("last_updated:".length).trim().replace(/^['"]|['"]$/g, "");
|
|
33
|
+
collectingReadWhen = false;
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
if (line.startsWith("status:")) {
|
|
37
|
+
status = line.slice("status:".length).trim().replace(/^['"]|['"]$/g, "").toLowerCase();
|
|
38
|
+
collectingReadWhen = false;
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
if (line.startsWith("read_when:")) {
|
|
42
|
+
collectingReadWhen = true;
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
if (collectingReadWhen && line.startsWith("- ")) {
|
|
46
|
+
readWhen.push(line.slice(2).trim());
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
if (collectingReadWhen && line.length > 0) {
|
|
50
|
+
collectingReadWhen = false;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return { summary, lastUpdated, readWhen, status };
|
|
54
|
+
}
|
|
55
|
+
function walkTracks(projectRoot, currentDir, output, invalid) {
|
|
56
|
+
for (const entry of readdirSync(currentDir)) {
|
|
57
|
+
const fullPath = path.join(currentDir, entry);
|
|
58
|
+
const stat = statSync(fullPath);
|
|
59
|
+
if (stat.isDirectory()) {
|
|
60
|
+
walkTracks(projectRoot, fullPath, output, invalid);
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
if (!entry.endsWith(".md") || shouldSkipTrackFile(entry)) {
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
const { summary, lastUpdated, readWhen, status } = parseFrontmatter(fullPath);
|
|
67
|
+
const relPath = path.relative(projectRoot, fullPath);
|
|
68
|
+
if (!summary || !lastUpdated || readWhen.length === 0 || !VALID_TRACK_STATUSES.has(status)) {
|
|
69
|
+
invalid.push(relPath);
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
output.push({ path: relPath, summary, readWhen, status });
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
export function renderTracksIndex(projectRoot, trackDir) {
|
|
76
|
+
const entries = [];
|
|
77
|
+
const invalidTracks = [];
|
|
78
|
+
if (existsSync(trackDir)) {
|
|
79
|
+
walkTracks(projectRoot, trackDir, entries, invalidTracks);
|
|
80
|
+
}
|
|
81
|
+
const lines = [
|
|
82
|
+
"# Tracks Index",
|
|
83
|
+
"",
|
|
84
|
+
"Auto-generated by `waypoint sync` / `waypoint doctor`. Read active trackers when resuming long-running work.",
|
|
85
|
+
"",
|
|
86
|
+
"## .waypoint/track/",
|
|
87
|
+
"",
|
|
88
|
+
];
|
|
89
|
+
if (entries.length === 0) {
|
|
90
|
+
lines.push("No tracker files found.");
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
for (const entry of entries.sort((a, b) => a.path.localeCompare(b.path))) {
|
|
94
|
+
lines.push(`- **${entry.path}** — [${entry.status}] ${entry.summary}`);
|
|
95
|
+
lines.push(` Read when: ${entry.readWhen.join("; ")}`);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
lines.push("");
|
|
99
|
+
return {
|
|
100
|
+
content: `${lines.join("\n")}`,
|
|
101
|
+
invalidTracks,
|
|
102
|
+
activeTrackPaths: entries
|
|
103
|
+
.filter((entry) => ACTIVE_TRACK_STATUSES.has(entry.status))
|
|
104
|
+
.map((entry) => entry.path)
|
|
105
|
+
.sort((a, b) => a.localeCompare(b)),
|
|
106
|
+
};
|
|
107
|
+
}
|
package/dist/src/upgrade.js
CHANGED
|
@@ -21,6 +21,83 @@ export function buildInitArgs(projectRoot, config) {
|
|
|
21
21
|
}
|
|
22
22
|
return args;
|
|
23
23
|
}
|
|
24
|
+
function parseVersion(version) {
|
|
25
|
+
const trimmed = version.trim().replace(/^v/, "");
|
|
26
|
+
const match = trimmed.match(/^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?$/);
|
|
27
|
+
if (!match) {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
return {
|
|
31
|
+
core: [Number(match[1]), Number(match[2]), Number(match[3])],
|
|
32
|
+
prerelease: match[4] ? match[4].split(".") : [],
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
function compareIdentifiers(left, right) {
|
|
36
|
+
const leftNumeric = /^\d+$/.test(left);
|
|
37
|
+
const rightNumeric = /^\d+$/.test(right);
|
|
38
|
+
if (leftNumeric && rightNumeric) {
|
|
39
|
+
return Number(left) - Number(right);
|
|
40
|
+
}
|
|
41
|
+
if (leftNumeric) {
|
|
42
|
+
return -1;
|
|
43
|
+
}
|
|
44
|
+
if (rightNumeric) {
|
|
45
|
+
return 1;
|
|
46
|
+
}
|
|
47
|
+
return left.localeCompare(right);
|
|
48
|
+
}
|
|
49
|
+
export function compareVersions(left, right) {
|
|
50
|
+
const leftParsed = parseVersion(left);
|
|
51
|
+
const rightParsed = parseVersion(right);
|
|
52
|
+
if (!leftParsed || !rightParsed) {
|
|
53
|
+
return left.localeCompare(right);
|
|
54
|
+
}
|
|
55
|
+
for (let index = 0; index < leftParsed.core.length; index += 1) {
|
|
56
|
+
const difference = leftParsed.core[index] - rightParsed.core[index];
|
|
57
|
+
if (difference !== 0) {
|
|
58
|
+
return difference;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
const leftPrerelease = leftParsed.prerelease;
|
|
62
|
+
const rightPrerelease = rightParsed.prerelease;
|
|
63
|
+
if (leftPrerelease.length === 0 && rightPrerelease.length === 0) {
|
|
64
|
+
return 0;
|
|
65
|
+
}
|
|
66
|
+
if (leftPrerelease.length === 0) {
|
|
67
|
+
return 1;
|
|
68
|
+
}
|
|
69
|
+
if (rightPrerelease.length === 0) {
|
|
70
|
+
return -1;
|
|
71
|
+
}
|
|
72
|
+
const length = Math.max(leftPrerelease.length, rightPrerelease.length);
|
|
73
|
+
for (let index = 0; index < length; index += 1) {
|
|
74
|
+
const leftIdentifier = leftPrerelease[index];
|
|
75
|
+
const rightIdentifier = rightPrerelease[index];
|
|
76
|
+
if (leftIdentifier === undefined) {
|
|
77
|
+
return -1;
|
|
78
|
+
}
|
|
79
|
+
if (rightIdentifier === undefined) {
|
|
80
|
+
return 1;
|
|
81
|
+
}
|
|
82
|
+
const difference = compareIdentifiers(leftIdentifier, rightIdentifier);
|
|
83
|
+
if (difference !== 0) {
|
|
84
|
+
return difference;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return 0;
|
|
88
|
+
}
|
|
89
|
+
function latestWaypointVersion(options) {
|
|
90
|
+
const npmBinary = options.npmBinary ?? process.env.WAYPOINT_NPM_COMMAND ?? npmBinaryForPlatform();
|
|
91
|
+
const latest = spawnSync(npmBinary, ["view", "waypoint-codex", "version"], {
|
|
92
|
+
stdio: "pipe",
|
|
93
|
+
encoding: "utf8",
|
|
94
|
+
});
|
|
95
|
+
if ((latest.status ?? 1) !== 0) {
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
const version = latest.stdout?.trim();
|
|
99
|
+
return version ? version : null;
|
|
100
|
+
}
|
|
24
101
|
function hasWaypointConfig(projectRoot) {
|
|
25
102
|
return existsSync(path.join(projectRoot, ".waypoint/config.toml"));
|
|
26
103
|
}
|
|
@@ -53,3 +130,26 @@ export function upgradeWaypoint(options) {
|
|
|
53
130
|
});
|
|
54
131
|
return doctor.status ?? 1;
|
|
55
132
|
}
|
|
133
|
+
export function maybeUpgradeWaypointBeforeInit(options) {
|
|
134
|
+
const nodeBinary = options.nodeBinary ?? process.execPath;
|
|
135
|
+
const npmBinary = options.npmBinary ?? process.env.WAYPOINT_NPM_COMMAND ?? npmBinaryForPlatform();
|
|
136
|
+
const stdio = options.stdio ?? "inherit";
|
|
137
|
+
const latestVersion = latestWaypointVersion({ npmBinary });
|
|
138
|
+
if (!latestVersion || compareVersions(latestVersion, options.currentVersion) <= 0) {
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
console.log(`Waypoint CLI ${options.currentVersion} is older than latest ${latestVersion}. Updating before init...`);
|
|
142
|
+
const update = spawnSync(npmBinary, ["install", "-g", "waypoint-codex@latest"], {
|
|
143
|
+
stdio,
|
|
144
|
+
});
|
|
145
|
+
if ((update.status ?? 1) !== 0) {
|
|
146
|
+
return update.status ?? 1;
|
|
147
|
+
}
|
|
148
|
+
const reexecArgs = options.initArgs.includes("--skip-cli-update")
|
|
149
|
+
? options.initArgs
|
|
150
|
+
: [...options.initArgs, "--skip-cli-update"];
|
|
151
|
+
const init = spawnSync(nodeBinary, [options.cliEntry, "init", ...reexecArgs], {
|
|
152
|
+
stdio,
|
|
153
|
+
});
|
|
154
|
+
return init.status ?? 1;
|
|
155
|
+
}
|
package/package.json
CHANGED
|
@@ -47,6 +47,8 @@ Skip rules that genuinely do not apply, but say that you skipped them.
|
|
|
47
47
|
|
|
48
48
|
This skill is narrower than `pre-pr-hygiene`. Use that other skill for broader ship-readiness.
|
|
49
49
|
|
|
50
|
+
If this audit produces a large remediation campaign, create or update a tracker under `.waypoint/track/` before switching into implementation so the fix list does not live only in chat.
|
|
51
|
+
|
|
50
52
|
## Step 4: Verify Evidence
|
|
51
53
|
|
|
52
54
|
Ground each finding in the actual code.
|
|
@@ -36,6 +36,8 @@ The plan belongs in the repo, not only in chat.
|
|
|
36
36
|
- Make sure the doc remains discoverable through the routed docs layer.
|
|
37
37
|
- In chat, return only a concise summary plus the path to the plan doc.
|
|
38
38
|
|
|
39
|
+
If the planned implementation will be large, multi-step, or likely to span multiple sessions, also create or update a tracker under `.waypoint/track/` and link it from `WORKSPACE.md` before implementation begins.
|
|
40
|
+
|
|
39
41
|
## The Core Loop
|
|
40
42
|
|
|
41
43
|
```
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: work-tracker
|
|
3
|
+
description: Create or maintain a durable tracker under `.waypoint/track/` for large multi-step work. Use when implementation will span multiple sessions, when an audit or review produces many fix items, when verification has a long checklist, or whenever `WORKSPACE.md` would become too detailed if it tried to hold the whole execution log.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Work Tracker
|
|
7
|
+
|
|
8
|
+
Use this skill when the work is too large, too long-running, or too itemized to live safely in `WORKSPACE.md`.
|
|
9
|
+
|
|
10
|
+
This skill owns the execution tracker layer:
|
|
11
|
+
|
|
12
|
+
- create or update `.waypoint/track/<slug>.md`
|
|
13
|
+
- keep `WORKSPACE.md` pointing at the active tracker
|
|
14
|
+
- move detailed checklists and progress into the tracker instead of bloating the workspace
|
|
15
|
+
|
|
16
|
+
## Read First
|
|
17
|
+
|
|
18
|
+
Before tracking:
|
|
19
|
+
|
|
20
|
+
1. Read `.waypoint/SOUL.md`
|
|
21
|
+
2. Read `.waypoint/agent-operating-manual.md`
|
|
22
|
+
3. Read `.waypoint/WORKSPACE.md`
|
|
23
|
+
4. Read `.waypoint/context/MANIFEST.md`
|
|
24
|
+
5. Read every file listed in that manifest
|
|
25
|
+
6. Read `.waypoint/track/README.md`
|
|
26
|
+
|
|
27
|
+
## When A Tracker Is Required
|
|
28
|
+
|
|
29
|
+
Create or update a tracker when any of these are true:
|
|
30
|
+
|
|
31
|
+
- the work will likely span multiple sessions
|
|
32
|
+
- there are many actionable items to implement
|
|
33
|
+
- an audit, QA pass, or review produced a remediation campaign
|
|
34
|
+
- verification requires a substantial checklist
|
|
35
|
+
- `WORKSPACE.md` would become noisy if it carried all the detail
|
|
36
|
+
|
|
37
|
+
Small, single-shot work does not need a tracker.
|
|
38
|
+
|
|
39
|
+
## Step 1: Choose The Tracker File
|
|
40
|
+
|
|
41
|
+
- Use `.waypoint/track/<kebab-case-slug>.md`.
|
|
42
|
+
- If a relevant tracker already exists, update it instead of creating a competing one.
|
|
43
|
+
- Keep one tracker per coherent workstream, not one tracker per tiny edit.
|
|
44
|
+
|
|
45
|
+
## Step 2: Set The Frontmatter
|
|
46
|
+
|
|
47
|
+
Trackers need:
|
|
48
|
+
|
|
49
|
+
```yaml
|
|
50
|
+
---
|
|
51
|
+
summary: One-line description
|
|
52
|
+
last_updated: "2026-03-13 11:38 PDT"
|
|
53
|
+
status: active
|
|
54
|
+
read_when:
|
|
55
|
+
- resuming this workstream
|
|
56
|
+
---
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Valid statuses:
|
|
60
|
+
|
|
61
|
+
- `active`
|
|
62
|
+
- `blocked`
|
|
63
|
+
- `paused`
|
|
64
|
+
- `done`
|
|
65
|
+
- `archived`
|
|
66
|
+
|
|
67
|
+
Use `active` unless there is a clear reason not to.
|
|
68
|
+
|
|
69
|
+
## Step 3: Structure The Tracker
|
|
70
|
+
|
|
71
|
+
A good tracker usually includes:
|
|
72
|
+
|
|
73
|
+
- `Goal`
|
|
74
|
+
- `Source`
|
|
75
|
+
- `Current State`
|
|
76
|
+
- `Next`
|
|
77
|
+
- `Workstreams`
|
|
78
|
+
- `Verification`
|
|
79
|
+
- `Decisions`
|
|
80
|
+
- `Notes`
|
|
81
|
+
|
|
82
|
+
Use checklists when there are many concrete items. Use timestamped bullets for materially revised state.
|
|
83
|
+
|
|
84
|
+
## Step 4: Link It From The Workspace
|
|
85
|
+
|
|
86
|
+
Add or update a bullet under `## Active Trackers` in `.waypoint/WORKSPACE.md` that points at the tracker path and states the current phase or next step.
|
|
87
|
+
|
|
88
|
+
`WORKSPACE.md` should answer "what matters right now?"
|
|
89
|
+
The tracker should answer "what exactly is happening across the whole workstream?"
|
|
90
|
+
|
|
91
|
+
## Step 5: Maintain It During Execution
|
|
92
|
+
|
|
93
|
+
- Update `last_updated` whenever you materially change the tracker.
|
|
94
|
+
- Mark completed items done instead of deleting the record.
|
|
95
|
+
- Add blockers, new tasks, and verification status as the work evolves.
|
|
96
|
+
- When the workstream finishes, set `status: done` or `status: archived`.
|
|
97
|
+
|
|
98
|
+
Do not let the tracker become fiction. It must match reality.
|
|
99
|
+
|
|
100
|
+
## Step 6: Distill Durable Knowledge
|
|
101
|
+
|
|
102
|
+
If the tracker reveals durable architecture, rollout, or debugging knowledge, move that durable knowledge into `.waypoint/docs/` and leave the tracker focused on execution state.
|
|
103
|
+
|
|
104
|
+
## Report
|
|
105
|
+
|
|
106
|
+
When you create or update a tracker, report:
|
|
107
|
+
|
|
108
|
+
- the tracker path
|
|
109
|
+
- the current status
|
|
110
|
+
- what `WORKSPACE.md` now points to
|
|
@@ -39,6 +39,7 @@ Ask one question:
|
|
|
39
39
|
|
|
40
40
|
Keep only the answer to that question in the workspace. Usually that means:
|
|
41
41
|
|
|
42
|
+
- active tracker pointers
|
|
42
43
|
- current focus
|
|
43
44
|
- latest verified state
|
|
44
45
|
- open blockers or risks
|
|
@@ -52,6 +53,7 @@ Usually remove or collapse:
|
|
|
52
53
|
- validation transcripts
|
|
53
54
|
- old milestone history
|
|
54
55
|
- duplicated durable documentation
|
|
56
|
+
- per-item implementation checklists that belong in `.waypoint/track/`
|
|
55
57
|
|
|
56
58
|
Compression is documentation quality, not data loss.
|
|
57
59
|
|
|
@@ -66,6 +68,7 @@ When editing the workspace:
|
|
|
66
68
|
5. Do not turn the workspace into an archive, changelog, or debug notebook.
|
|
67
69
|
|
|
68
70
|
If durable context is missing from `.waypoint/docs/`, add or refresh the smallest coherent routed doc before removing it from the workspace.
|
|
71
|
+
If execution detail is still active but too large for the workspace, move it into `.waypoint/track/` instead of deleting it.
|
|
69
72
|
|
|
70
73
|
## Step 4: Protect User-Owned State
|
|
71
74
|
|