waypoint-codex 0.8.1 → 0.9.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 +14 -28
- package/dist/src/cli.js +2 -34
- package/dist/src/core.js +16 -324
- package/dist/src/templates.js +1 -4
- package/dist/src/upgrade.js +0 -10
- package/package.json +1 -1
- package/templates/.agents/skills/backend-context-interview/SKILL.md +70 -0
- package/templates/.agents/skills/backend-ship-audit/SKILL.md +221 -0
- package/templates/.agents/skills/backend-ship-audit/agents/openai.yaml +3 -0
- package/templates/.agents/skills/backend-ship-audit/references/audit-framework.md +228 -0
- package/templates/.agents/skills/backend-ship-audit/references/report-template.md +92 -0
- package/templates/.agents/skills/frontend-context-interview/SKILL.md +60 -0
- package/templates/.agents/skills/frontend-ship-audit/SKILL.md +87 -0
- package/templates/.agents/skills/frontend-ship-audit/agents/openai.yaml +3 -0
- package/templates/.agents/skills/frontend-ship-audit/references/guidance-file-updates.md +57 -0
- package/templates/.agents/skills/frontend-ship-audit/references/report-template.md +51 -0
- package/templates/.agents/skills/frontend-ship-audit/references/review-framework.md +83 -0
- package/templates/.agents/skills/frontend-ship-audit/scripts/create_frontend_audit.py +81 -0
- package/templates/.codex/agents/code-health-reviewer.toml +75 -2
- package/templates/.codex/agents/code-reviewer.toml +77 -2
- package/templates/.codex/agents/plan-reviewer.toml +65 -4
- package/templates/.waypoint/README.md +2 -5
- package/templates/.waypoint/SOUL.md +1 -1
- package/templates/.waypoint/agent-operating-manual.md +12 -9
- package/templates/.waypoint/config.toml +0 -3
- package/templates/.waypoint/scripts/prepare-context.mjs +7 -52
- package/templates/managed-agents-block.md +38 -2
- package/templates/.waypoint/agents/code-health-reviewer.md +0 -92
- package/templates/.waypoint/agents/code-reviewer.md +0 -105
- package/templates/.waypoint/agents/plan-reviewer.md +0 -86
- package/templates/.waypoint/automations/README.md +0 -18
- package/templates/.waypoint/automations/docs-garden.toml +0 -7
- package/templates/.waypoint/automations/repo-health.toml +0 -8
- package/templates/.waypoint/rules/README.md +0 -6
package/README.md
CHANGED
|
@@ -28,6 +28,7 @@ Waypoint scaffolds a Codex-friendly repo structure built around a few core piece
|
|
|
28
28
|
- `.waypoint/TRACKS_INDEX.md` for tracker routing
|
|
29
29
|
- `.waypoint/context/` for generated startup context
|
|
30
30
|
- `.agents/skills/` for repo-local workflows like planning, tracking, audits, and QA
|
|
31
|
+
- `.codex/` for the default reviewer-agent pack
|
|
31
32
|
|
|
32
33
|
The philosophy is simple:
|
|
33
34
|
|
|
@@ -66,7 +67,7 @@ npx waypoint-codex@latest --help
|
|
|
66
67
|
Inside the repo you want to prepare for Codex:
|
|
67
68
|
|
|
68
69
|
```bash
|
|
69
|
-
waypoint init
|
|
70
|
+
waypoint init
|
|
70
71
|
waypoint doctor
|
|
71
72
|
```
|
|
72
73
|
|
|
@@ -75,6 +76,9 @@ That gives you a repo that looks roughly like this:
|
|
|
75
76
|
```text
|
|
76
77
|
repo/
|
|
77
78
|
├── AGENTS.md
|
|
79
|
+
├── .codex/
|
|
80
|
+
│ ├── agents/
|
|
81
|
+
│ └── config.toml
|
|
78
82
|
├── .agents/
|
|
79
83
|
│ └── skills/
|
|
80
84
|
└── .waypoint/
|
|
@@ -98,39 +102,29 @@ From there, start your Codex session in the repo and follow the generated bootst
|
|
|
98
102
|
waypoint init
|
|
99
103
|
```
|
|
100
104
|
|
|
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:
|
|
105
|
+
By default, `waypoint init` updates the global CLI to the latest published `waypoint-codex` first, then scaffolds with that fresh version. It also installs the reviewer-agent pack by default. If you want to scaffold with the currently installed binary instead, use:
|
|
102
106
|
|
|
103
107
|
```bash
|
|
104
108
|
waypoint init --skip-cli-update
|
|
105
109
|
```
|
|
106
110
|
|
|
107
|
-
### Full local workflow setup
|
|
108
|
-
|
|
109
|
-
```bash
|
|
110
|
-
waypoint init --with-roles --with-rules --with-automations
|
|
111
|
-
```
|
|
112
|
-
|
|
113
111
|
### App-friendly profile
|
|
114
112
|
|
|
115
113
|
```bash
|
|
116
|
-
waypoint init --app-friendly
|
|
114
|
+
waypoint init --app-friendly
|
|
117
115
|
```
|
|
118
116
|
|
|
119
117
|
Flags you can combine:
|
|
120
118
|
|
|
121
119
|
- `--app-friendly`
|
|
122
|
-
- `--with-roles`
|
|
123
|
-
- `--with-rules`
|
|
124
|
-
- `--with-automations`
|
|
125
120
|
- `--skip-cli-update`
|
|
126
121
|
|
|
127
122
|
## Main commands
|
|
128
123
|
|
|
129
124
|
- `waypoint init` — update the CLI to latest by default, then scaffold or refresh the repo
|
|
130
125
|
- `waypoint doctor` — validate health and report drift
|
|
131
|
-
- `waypoint sync` — rebuild the docs
|
|
126
|
+
- `waypoint sync` — rebuild the docs and tracker indexes
|
|
132
127
|
- `waypoint upgrade` — update the CLI and refresh the current repo using its saved config
|
|
133
|
-
- `waypoint import-legacy` — analyze an older repo layout and produce an adoption report
|
|
134
128
|
|
|
135
129
|
## Built-in skills
|
|
136
130
|
|
|
@@ -141,21 +135,24 @@ Waypoint ships a strong default skill pack for real coding work:
|
|
|
141
135
|
- `docs-sync`
|
|
142
136
|
- `code-guide-audit`
|
|
143
137
|
- `break-it-qa`
|
|
138
|
+
- `frontend-ship-audit`
|
|
139
|
+
- `backend-ship-audit`
|
|
144
140
|
- `workspace-compress`
|
|
145
141
|
- `pre-pr-hygiene`
|
|
146
142
|
- `pr-review`
|
|
147
143
|
|
|
148
144
|
These are repo-local, so the workflow travels with the project.
|
|
145
|
+
`break-it-qa`, `frontend-ship-audit`, and `backend-ship-audit` are user-invoked audit skills, not default autonomous agent steps.
|
|
149
146
|
|
|
150
|
-
##
|
|
147
|
+
## Reviewer agents
|
|
151
148
|
|
|
152
|
-
|
|
149
|
+
Waypoint scaffolds these reviewer agents by default:
|
|
153
150
|
|
|
154
151
|
- `code-health-reviewer`
|
|
155
152
|
- `code-reviewer`
|
|
156
153
|
- `plan-reviewer`
|
|
157
154
|
|
|
158
|
-
The intended workflow is
|
|
155
|
+
The intended workflow is closeout-based: run `code-reviewer` before considering any non-trivial implementation slice complete, and run `code-health-reviewer` before considering medium or large changes complete, especially when they add structure, duplicate logic, or introduce new abstractions. If both apply, run them in parallel. A recent self-authored commit is the preferred scope anchor when one cleanly represents the slice, but it is not the only valid trigger.
|
|
159
156
|
|
|
160
157
|
## What makes it different
|
|
161
158
|
|
|
@@ -185,22 +182,11 @@ If you only want to update the CLI:
|
|
|
185
182
|
waypoint upgrade --skip-repo-refresh
|
|
186
183
|
```
|
|
187
184
|
|
|
188
|
-
## Importing an existing repo
|
|
189
|
-
|
|
190
|
-
If you already have an older assistant setup or repo-memory system:
|
|
191
|
-
|
|
192
|
-
```bash
|
|
193
|
-
waypoint import-legacy /path/to/source-repo /path/to/new-repo --init-target
|
|
194
|
-
```
|
|
195
|
-
|
|
196
|
-
This generates an adoption report and helps separate durable docs from old runtime-specific scaffolding.
|
|
197
|
-
|
|
198
185
|
## Learn more
|
|
199
186
|
|
|
200
187
|
- [Overview](docs/overview.md)
|
|
201
188
|
- [Architecture](docs/architecture.md)
|
|
202
189
|
- [Upgrading](docs/upgrading.md)
|
|
203
|
-
- [Importing Existing Repositories](docs/importing-existing-repos.md)
|
|
204
190
|
- [Releasing](docs/releasing.md)
|
|
205
191
|
|
|
206
192
|
## License
|
package/dist/src/cli.js
CHANGED
|
@@ -4,7 +4,7 @@ import { readFileSync } from "node:fs";
|
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
5
|
import path from "node:path";
|
|
6
6
|
import process from "node:process";
|
|
7
|
-
import { doctorRepository,
|
|
7
|
+
import { doctorRepository, initRepository, loadWaypointConfig, syncRepository } from "./core.js";
|
|
8
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) {
|
|
@@ -29,9 +29,8 @@ function printHelp() {
|
|
|
29
29
|
Commands:
|
|
30
30
|
init Initialize a repository with Waypoint scaffolding (auto-updates CLI unless skipped)
|
|
31
31
|
doctor Validate repository health and report drift
|
|
32
|
-
sync Rebuild docs
|
|
32
|
+
sync Rebuild docs and tracker indexes
|
|
33
33
|
upgrade Update the global Waypoint CLI and refresh this repo using existing config
|
|
34
|
-
import-legacy Analyze a legacy repository layout and produce a Waypoint adoption report
|
|
35
34
|
`);
|
|
36
35
|
}
|
|
37
36
|
async function main() {
|
|
@@ -50,9 +49,6 @@ async function main() {
|
|
|
50
49
|
args: argv.slice(1),
|
|
51
50
|
options: {
|
|
52
51
|
"app-friendly": { type: "boolean", default: false },
|
|
53
|
-
"with-roles": { type: "boolean", default: false },
|
|
54
|
-
"with-rules": { type: "boolean", default: false },
|
|
55
|
-
"with-automations": { type: "boolean", default: false },
|
|
56
52
|
"skip-cli-update": { type: "boolean", default: false }
|
|
57
53
|
},
|
|
58
54
|
allowPositionals: true
|
|
@@ -70,9 +66,6 @@ async function main() {
|
|
|
70
66
|
}
|
|
71
67
|
const results = initRepository(projectRoot, {
|
|
72
68
|
profile: values["app-friendly"] ? "app-friendly" : "universal",
|
|
73
|
-
withRoles: values["with-roles"],
|
|
74
|
-
withRules: values["with-rules"],
|
|
75
|
-
withAutomations: values["with-automations"]
|
|
76
69
|
});
|
|
77
70
|
for (const line of results) {
|
|
78
71
|
console.log(`- ${line}`);
|
|
@@ -116,31 +109,6 @@ async function main() {
|
|
|
116
109
|
}
|
|
117
110
|
return 0;
|
|
118
111
|
}
|
|
119
|
-
if (command === "import-legacy") {
|
|
120
|
-
const { values, positionals } = parseArgs({
|
|
121
|
-
args: argv.slice(1),
|
|
122
|
-
options: {
|
|
123
|
-
"init-target": { type: "boolean", default: false }
|
|
124
|
-
},
|
|
125
|
-
allowPositionals: true
|
|
126
|
-
});
|
|
127
|
-
if (positionals.length === 0) {
|
|
128
|
-
console.error("import-legacy requires a source repository path.");
|
|
129
|
-
return 2;
|
|
130
|
-
}
|
|
131
|
-
const sourceRepo = resolveRepo(positionals[0]);
|
|
132
|
-
const targetRepo = positionals[1] ? resolveRepo(positionals[1]) : undefined;
|
|
133
|
-
const result = importLegacyRepo(sourceRepo, targetRepo, {
|
|
134
|
-
initTarget: values["init-target"]
|
|
135
|
-
});
|
|
136
|
-
for (const line of result.actions) {
|
|
137
|
-
console.log(`- ${line}`);
|
|
138
|
-
}
|
|
139
|
-
if (!targetRepo) {
|
|
140
|
-
console.log(result.report);
|
|
141
|
-
}
|
|
142
|
-
return 0;
|
|
143
|
-
}
|
|
144
112
|
if (command === "upgrade") {
|
|
145
113
|
const { values, positionals } = parseArgs({
|
|
146
114
|
args: argv.slice(1),
|
package/dist/src/core.js
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { copyFileSync, existsSync, mkdirSync, readFileSync, readdirSync, rmSync, statSync, writeFileSync, } from "node:fs";
|
|
3
|
-
import os from "node:os";
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, readdirSync, rmSync, statSync, writeFileSync, } from "node:fs";
|
|
4
2
|
import path from "node:path";
|
|
5
3
|
import * as TOML from "@iarna/toml";
|
|
6
4
|
import { renderDocsIndex } from "./docs-index.js";
|
|
@@ -12,8 +10,6 @@ const DEFAULT_DOCS_INDEX = ".waypoint/DOCS_INDEX.md";
|
|
|
12
10
|
const DEFAULT_TRACK_DIR = ".waypoint/track";
|
|
13
11
|
const DEFAULT_TRACKS_INDEX = ".waypoint/TRACKS_INDEX.md";
|
|
14
12
|
const DEFAULT_WORKSPACE = ".waypoint/WORKSPACE.md";
|
|
15
|
-
const STATE_DIR = ".waypoint/state";
|
|
16
|
-
const SYNC_RECORDS_FILE = ".waypoint/state/sync-records.json";
|
|
17
13
|
const TIMESTAMPED_WORKSPACE_SECTIONS = new Set([
|
|
18
14
|
"## Active Trackers",
|
|
19
15
|
"## Current State",
|
|
@@ -101,9 +97,6 @@ function scaffoldSkills(projectRoot) {
|
|
|
101
97
|
copyTemplateTree(templatePath(".agents/skills"), targetRoot);
|
|
102
98
|
}
|
|
103
99
|
function scaffoldWaypointOptionalTemplates(projectRoot) {
|
|
104
|
-
copyTemplateTree(templatePath(".waypoint/agents"), path.join(projectRoot, ".waypoint/agents"));
|
|
105
|
-
copyTemplateTree(templatePath(".waypoint/automations"), path.join(projectRoot, ".waypoint/automations"));
|
|
106
|
-
copyTemplateTree(templatePath(".waypoint/rules"), path.join(projectRoot, ".waypoint/rules"));
|
|
107
100
|
copyTemplateTree(templatePath(".waypoint/scripts"), path.join(projectRoot, ".waypoint/scripts"));
|
|
108
101
|
copyTemplateTree(templatePath(".waypoint/track"), path.join(projectRoot, ".waypoint/track"));
|
|
109
102
|
}
|
|
@@ -135,21 +128,18 @@ export function initRepository(projectRoot, options) {
|
|
|
135
128
|
".codex/agents/reviewer.toml",
|
|
136
129
|
".codex/agents/architect.toml",
|
|
137
130
|
".codex/agents/implementer.toml",
|
|
131
|
+
".waypoint/automations",
|
|
132
|
+
".waypoint/rules",
|
|
133
|
+
".waypoint/state",
|
|
138
134
|
]) {
|
|
139
135
|
removePathIfExists(path.join(projectRoot, deprecatedPath));
|
|
140
136
|
}
|
|
141
|
-
ensureDir(path.join(projectRoot, ".waypoint/automations"));
|
|
142
|
-
ensureDir(path.join(projectRoot, ".waypoint/rules"));
|
|
143
|
-
ensureDir(path.join(projectRoot, STATE_DIR));
|
|
144
137
|
writeText(path.join(projectRoot, ".waypoint/README.md"), readTemplate(".waypoint/README.md"));
|
|
145
138
|
writeText(path.join(projectRoot, ".waypoint/SOUL.md"), readTemplate(".waypoint/SOUL.md"));
|
|
146
139
|
writeText(path.join(projectRoot, ".waypoint/agent-operating-manual.md"), readTemplate(".waypoint/agent-operating-manual.md"));
|
|
147
140
|
scaffoldWaypointOptionalTemplates(projectRoot);
|
|
148
141
|
writeText(path.join(projectRoot, DEFAULT_CONFIG_PATH), renderWaypointConfig({
|
|
149
142
|
profile: options.profile,
|
|
150
|
-
roles: options.withRoles,
|
|
151
|
-
rules: options.withRules,
|
|
152
|
-
automations: options.withAutomations,
|
|
153
143
|
}));
|
|
154
144
|
writeIfMissing(path.join(projectRoot, DEFAULT_WORKSPACE), readTemplate("WORKSPACE.md"));
|
|
155
145
|
ensureDir(path.join(projectRoot, DEFAULT_DOCS_DIR));
|
|
@@ -158,9 +148,7 @@ export function initRepository(projectRoot, options) {
|
|
|
158
148
|
writeIfMissing(path.join(projectRoot, ".waypoint/docs/code-guide.md"), readTemplate(".waypoint/docs/code-guide.md"));
|
|
159
149
|
upsertManagedBlock(path.join(projectRoot, "AGENTS.md"), readTemplate("managed-agents-block.md"));
|
|
160
150
|
scaffoldSkills(projectRoot);
|
|
161
|
-
|
|
162
|
-
scaffoldOptionalCodex(projectRoot);
|
|
163
|
-
}
|
|
151
|
+
scaffoldOptionalCodex(projectRoot);
|
|
164
152
|
appendGitignoreSnippet(projectRoot);
|
|
165
153
|
const docsIndex = renderDocsIndex(projectRoot, path.join(projectRoot, DEFAULT_DOCS_DIR));
|
|
166
154
|
const tracksIndex = renderTracksIndex(projectRoot, path.join(projectRoot, DEFAULT_TRACK_DIR));
|
|
@@ -171,6 +159,7 @@ export function initRepository(projectRoot, options) {
|
|
|
171
159
|
"Installed managed AGENTS block",
|
|
172
160
|
"Created .waypoint/WORKSPACE.md, .waypoint/docs/, and .waypoint/track/ scaffold",
|
|
173
161
|
"Installed repo-local Waypoint skills",
|
|
162
|
+
"Installed reviewer agents and project Codex config",
|
|
174
163
|
"Generated .waypoint/DOCS_INDEX.md and .waypoint/TRACKS_INDEX.md",
|
|
175
164
|
];
|
|
176
165
|
}
|
|
@@ -181,27 +170,6 @@ export function loadWaypointConfig(projectRoot) {
|
|
|
181
170
|
}
|
|
182
171
|
return TOML.parse(readFileSync(configPath, "utf8"));
|
|
183
172
|
}
|
|
184
|
-
function loadSyncRecords(projectRoot) {
|
|
185
|
-
const syncPath = path.join(projectRoot, SYNC_RECORDS_FILE);
|
|
186
|
-
if (!existsSync(syncPath)) {
|
|
187
|
-
return {};
|
|
188
|
-
}
|
|
189
|
-
try {
|
|
190
|
-
return JSON.parse(readFileSync(syncPath, "utf8"));
|
|
191
|
-
}
|
|
192
|
-
catch {
|
|
193
|
-
return {};
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
function saveSyncRecords(projectRoot, records) {
|
|
197
|
-
writeText(path.join(projectRoot, SYNC_RECORDS_FILE), `${JSON.stringify(records, null, 2)}\n`);
|
|
198
|
-
}
|
|
199
|
-
function hashFile(filePath) {
|
|
200
|
-
return createHash("sha256").update(readFileSync(filePath)).digest("hex");
|
|
201
|
-
}
|
|
202
|
-
function codexHome() {
|
|
203
|
-
return process.env.CODEX_HOME ?? path.join(os.homedir(), ".codex");
|
|
204
|
-
}
|
|
205
173
|
function findWorkspaceTimestampViolations(workspaceText) {
|
|
206
174
|
let currentSection = "";
|
|
207
175
|
const violations = new Set();
|
|
@@ -223,111 +191,6 @@ function findWorkspaceTimestampViolations(workspaceText) {
|
|
|
223
191
|
}
|
|
224
192
|
return [...violations];
|
|
225
193
|
}
|
|
226
|
-
function renderCodexAutomation(spec, cwd) {
|
|
227
|
-
const now = Date.now();
|
|
228
|
-
const rrule = spec.rrule?.startsWith("RRULE:") ? spec.rrule : `RRULE:${spec.rrule}`;
|
|
229
|
-
return [
|
|
230
|
-
"version = 1",
|
|
231
|
-
`id = ${JSON.stringify(spec.id)}`,
|
|
232
|
-
`name = ${JSON.stringify(spec.name)}`,
|
|
233
|
-
`prompt = ${JSON.stringify(spec.prompt)}`,
|
|
234
|
-
`status = ${JSON.stringify(spec.status ?? "ACTIVE")}`,
|
|
235
|
-
`rrule = ${JSON.stringify(rrule)}`,
|
|
236
|
-
`execution_environment = ${JSON.stringify(spec.execution_environment ?? "worktree")}`,
|
|
237
|
-
`cwds = ${JSON.stringify(spec.cwds ?? [cwd])}`,
|
|
238
|
-
`created_at = ${now}`,
|
|
239
|
-
`updated_at = ${now}`,
|
|
240
|
-
].join("\n") + "\n";
|
|
241
|
-
}
|
|
242
|
-
function isKebabCase(value) {
|
|
243
|
-
return /^[a-z0-9-]+$/.test(value);
|
|
244
|
-
}
|
|
245
|
-
function validateAutomationSpecFile(filePath) {
|
|
246
|
-
const errors = [];
|
|
247
|
-
let parsed;
|
|
248
|
-
try {
|
|
249
|
-
parsed = TOML.parse(readFileSync(filePath, "utf8"));
|
|
250
|
-
}
|
|
251
|
-
catch (error) {
|
|
252
|
-
return [`invalid TOML: ${error instanceof Error ? error.message : String(error)}`];
|
|
253
|
-
}
|
|
254
|
-
for (const key of ["id", "name", "prompt", "rrule"]) {
|
|
255
|
-
if (!parsed[key]) {
|
|
256
|
-
errors.push(`missing required key \`${key}\``);
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
if (parsed.id && !isKebabCase(parsed.id)) {
|
|
260
|
-
errors.push("automation id must use lowercase kebab-case");
|
|
261
|
-
}
|
|
262
|
-
return errors;
|
|
263
|
-
}
|
|
264
|
-
function syncAutomations(projectRoot) {
|
|
265
|
-
const sourceDir = path.join(projectRoot, ".waypoint/automations");
|
|
266
|
-
if (!existsSync(sourceDir)) {
|
|
267
|
-
return [];
|
|
268
|
-
}
|
|
269
|
-
const targetRoot = path.join(codexHome(), "automations");
|
|
270
|
-
ensureDir(targetRoot);
|
|
271
|
-
const records = loadSyncRecords(projectRoot);
|
|
272
|
-
const results = [];
|
|
273
|
-
for (const entry of readdirSync(sourceDir)) {
|
|
274
|
-
if (!entry.endsWith(".toml")) {
|
|
275
|
-
continue;
|
|
276
|
-
}
|
|
277
|
-
const sourcePath = path.join(sourceDir, entry);
|
|
278
|
-
const errors = validateAutomationSpecFile(sourcePath);
|
|
279
|
-
if (errors.length > 0) {
|
|
280
|
-
results.push(`Skipped ${entry}: ${errors.join("; ")}`);
|
|
281
|
-
continue;
|
|
282
|
-
}
|
|
283
|
-
const spec = TOML.parse(readFileSync(sourcePath, "utf8"));
|
|
284
|
-
if (spec.enabled === false) {
|
|
285
|
-
continue;
|
|
286
|
-
}
|
|
287
|
-
const targetDir = path.join(targetRoot, spec.id);
|
|
288
|
-
const targetPath = path.join(targetDir, "automation.toml");
|
|
289
|
-
ensureDir(targetDir);
|
|
290
|
-
writeText(targetPath, renderCodexAutomation(spec, projectRoot));
|
|
291
|
-
records[sourcePath] = {
|
|
292
|
-
artifact_type: "automation",
|
|
293
|
-
source_path: sourcePath,
|
|
294
|
-
target_path: targetPath,
|
|
295
|
-
source_hash: hashFile(sourcePath),
|
|
296
|
-
target_hash: hashFile(targetPath),
|
|
297
|
-
};
|
|
298
|
-
results.push(`Synced automation \`${spec.id}\``);
|
|
299
|
-
}
|
|
300
|
-
saveSyncRecords(projectRoot, records);
|
|
301
|
-
return results;
|
|
302
|
-
}
|
|
303
|
-
function syncRules(projectRoot) {
|
|
304
|
-
const sourceDir = path.join(projectRoot, ".waypoint/rules");
|
|
305
|
-
if (!existsSync(sourceDir)) {
|
|
306
|
-
return [];
|
|
307
|
-
}
|
|
308
|
-
const targetRoot = path.join(codexHome(), "rules");
|
|
309
|
-
ensureDir(targetRoot);
|
|
310
|
-
const records = loadSyncRecords(projectRoot);
|
|
311
|
-
const results = [];
|
|
312
|
-
for (const entry of readdirSync(sourceDir)) {
|
|
313
|
-
if (!entry.endsWith(".rules")) {
|
|
314
|
-
continue;
|
|
315
|
-
}
|
|
316
|
-
const sourcePath = path.join(sourceDir, entry);
|
|
317
|
-
const targetPath = path.join(targetRoot, `waypoint-${entry}`);
|
|
318
|
-
copyFileSync(sourcePath, targetPath);
|
|
319
|
-
records[sourcePath] = {
|
|
320
|
-
artifact_type: "rules",
|
|
321
|
-
source_path: sourcePath,
|
|
322
|
-
target_path: targetPath,
|
|
323
|
-
source_hash: hashFile(sourcePath),
|
|
324
|
-
target_hash: hashFile(targetPath),
|
|
325
|
-
};
|
|
326
|
-
results.push(`Synced rules \`${entry}\``);
|
|
327
|
-
}
|
|
328
|
-
saveSyncRecords(projectRoot, records);
|
|
329
|
-
return results;
|
|
330
|
-
}
|
|
331
194
|
export function doctorRepository(projectRoot) {
|
|
332
195
|
const findings = [];
|
|
333
196
|
const config = loadWaypointConfig(projectRoot);
|
|
@@ -532,55 +395,15 @@ export function doctorRepository(projectRoot) {
|
|
|
532
395
|
});
|
|
533
396
|
}
|
|
534
397
|
}
|
|
535
|
-
const
|
|
536
|
-
if (
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
const filePath = path.join(automationDir, entry);
|
|
545
|
-
const errors = validateAutomationSpecFile(filePath);
|
|
546
|
-
for (const error of errors) {
|
|
547
|
-
findings.push({
|
|
548
|
-
severity: "error",
|
|
549
|
-
category: "automations",
|
|
550
|
-
message: `${path.relative(projectRoot, filePath)}: ${error}`,
|
|
551
|
-
remediation: "Fix the automation spec and rerun `waypoint sync`.",
|
|
552
|
-
paths: [filePath],
|
|
553
|
-
});
|
|
554
|
-
}
|
|
555
|
-
if (errors.length === 0) {
|
|
556
|
-
const spec = TOML.parse(readFileSync(filePath, "utf8"));
|
|
557
|
-
if (spec.enabled === false) {
|
|
558
|
-
continue;
|
|
559
|
-
}
|
|
560
|
-
}
|
|
561
|
-
if (errors.length === 0 && !records[filePath]) {
|
|
562
|
-
findings.push({
|
|
563
|
-
severity: "info",
|
|
564
|
-
category: "automations",
|
|
565
|
-
message: `Automation \`${path.basename(entry, ".toml")}\` has not been synced.`,
|
|
566
|
-
remediation: "Run `waypoint sync` to install it into Codex home.",
|
|
567
|
-
paths: [filePath],
|
|
568
|
-
});
|
|
569
|
-
}
|
|
570
|
-
}
|
|
571
|
-
}
|
|
572
|
-
}
|
|
573
|
-
if (featureMap.roles) {
|
|
574
|
-
const codexConfigPath = path.join(projectRoot, ".codex/config.toml");
|
|
575
|
-
if (!existsSync(codexConfigPath)) {
|
|
576
|
-
findings.push({
|
|
577
|
-
severity: "warn",
|
|
578
|
-
category: "roles",
|
|
579
|
-
message: "Role support is enabled but .codex/config.toml is missing.",
|
|
580
|
-
remediation: "Run `waypoint init --with-roles` or create the project Codex config files.",
|
|
581
|
-
paths: [codexConfigPath],
|
|
582
|
-
});
|
|
583
|
-
}
|
|
398
|
+
const codexConfigPath = path.join(projectRoot, ".codex/config.toml");
|
|
399
|
+
if (!existsSync(codexConfigPath)) {
|
|
400
|
+
findings.push({
|
|
401
|
+
severity: "warn",
|
|
402
|
+
category: "roles",
|
|
403
|
+
message: "Reviewer agent config is missing from .codex/config.toml.",
|
|
404
|
+
remediation: "Run `waypoint init` or create the project Codex config files.",
|
|
405
|
+
paths: [codexConfigPath],
|
|
406
|
+
});
|
|
584
407
|
}
|
|
585
408
|
return findings;
|
|
586
409
|
}
|
|
@@ -594,136 +417,5 @@ export function syncRepository(projectRoot) {
|
|
|
594
417
|
const tracksIndex = renderTracksIndex(projectRoot, trackDir);
|
|
595
418
|
writeText(docsIndexPath, `${docsIndex.content}\n`);
|
|
596
419
|
writeText(tracksIndexPath, `${tracksIndex.content}\n`);
|
|
597
|
-
|
|
598
|
-
const featureMap = config.features ?? {};
|
|
599
|
-
if (featureMap.rules) {
|
|
600
|
-
results.push(...syncRules(projectRoot));
|
|
601
|
-
}
|
|
602
|
-
if (featureMap.automations) {
|
|
603
|
-
results.push(...syncAutomations(projectRoot));
|
|
604
|
-
}
|
|
605
|
-
return results;
|
|
606
|
-
}
|
|
607
|
-
export function importLegacyRepo(sourceRepo, targetRepo, options = {}) {
|
|
608
|
-
const sourceDocsDir = path.join(sourceRepo, ".meridian/docs");
|
|
609
|
-
const sourceSkillsDir = path.join(sourceRepo, "skills");
|
|
610
|
-
const sourceCommandsDir = path.join(sourceRepo, "commands");
|
|
611
|
-
const sourceAgentsDir = path.join(sourceRepo, "agents");
|
|
612
|
-
const sourceHooksPath = path.join(sourceRepo, "hooks/hooks.json");
|
|
613
|
-
const sourceScriptsDir = path.join(sourceRepo, "scripts");
|
|
614
|
-
const portableDocs = existsSync(sourceDocsDir)
|
|
615
|
-
? readdirSync(sourceDocsDir).filter((entry) => entry.endsWith(".md")).sort()
|
|
616
|
-
: [];
|
|
617
|
-
const portableSkills = existsSync(sourceSkillsDir)
|
|
618
|
-
? readdirSync(sourceSkillsDir)
|
|
619
|
-
.map((entry) => path.join("skills", entry, "SKILL.md"))
|
|
620
|
-
.filter((relPath) => existsSync(path.join(sourceRepo, relPath)))
|
|
621
|
-
.sort()
|
|
622
|
-
: [];
|
|
623
|
-
const portableCommands = existsSync(sourceCommandsDir)
|
|
624
|
-
? readdirSync(sourceCommandsDir)
|
|
625
|
-
.filter((entry) => entry.endsWith(".md"))
|
|
626
|
-
.map((entry) => path.join("commands", entry))
|
|
627
|
-
.sort()
|
|
628
|
-
: [];
|
|
629
|
-
const agentFiles = existsSync(sourceAgentsDir)
|
|
630
|
-
? readdirSync(sourceAgentsDir)
|
|
631
|
-
.filter((entry) => entry.endsWith(".md"))
|
|
632
|
-
.map((entry) => path.join("agents", entry))
|
|
633
|
-
.sort()
|
|
634
|
-
: [];
|
|
635
|
-
const hookFiles = existsSync(sourceHooksPath) ? [path.join("hooks", "hooks.json")] : [];
|
|
636
|
-
const scriptFiles = existsSync(sourceScriptsDir)
|
|
637
|
-
? collectFiles(sourceScriptsDir)
|
|
638
|
-
.filter((filePath) => filePath.endsWith(".py"))
|
|
639
|
-
.map((filePath) => path.relative(sourceRepo, filePath))
|
|
640
|
-
.sort()
|
|
641
|
-
: [];
|
|
642
|
-
const actions = [];
|
|
643
|
-
if (targetRepo && options.initTarget) {
|
|
644
|
-
actions.push(...initRepository(targetRepo, {
|
|
645
|
-
profile: "universal",
|
|
646
|
-
withRoles: false,
|
|
647
|
-
withRules: false,
|
|
648
|
-
withAutomations: false,
|
|
649
|
-
}));
|
|
650
|
-
}
|
|
651
|
-
if (targetRepo) {
|
|
652
|
-
const importDir = path.join(targetRepo, ".waypoint/docs/legacy-import");
|
|
653
|
-
ensureDir(importDir);
|
|
654
|
-
for (const docName of portableDocs) {
|
|
655
|
-
copyFileSync(path.join(sourceDocsDir, docName), path.join(importDir, docName));
|
|
656
|
-
}
|
|
657
|
-
if (portableDocs.length > 0) {
|
|
658
|
-
actions.push(`Copied ${portableDocs.length} legacy docs into ${importDir}`);
|
|
659
|
-
}
|
|
660
|
-
const docsIndex = renderDocsIndex(targetRepo, path.join(targetRepo, DEFAULT_DOCS_DIR));
|
|
661
|
-
writeText(path.join(targetRepo, DEFAULT_DOCS_INDEX), `${docsIndex.content}\n`);
|
|
662
|
-
}
|
|
663
|
-
const report = [
|
|
664
|
-
"# Legacy Repository Adoption Report",
|
|
665
|
-
"",
|
|
666
|
-
`Source: \`${sourceRepo}\``,
|
|
667
|
-
"",
|
|
668
|
-
"## Portable as-is or with light rewriting",
|
|
669
|
-
"",
|
|
670
|
-
`- Docs: ${portableDocs.length}`,
|
|
671
|
-
`- Skills: ${portableSkills.length}`,
|
|
672
|
-
`- Commands/prompts worth reviewing for skill conversion: ${portableCommands.length}`,
|
|
673
|
-
"",
|
|
674
|
-
"### Docs",
|
|
675
|
-
...(portableDocs.length > 0
|
|
676
|
-
? portableDocs.map((entry) => `- \`.meridian/docs/${entry}\``)
|
|
677
|
-
: ["- None"]),
|
|
678
|
-
"",
|
|
679
|
-
"### Skills",
|
|
680
|
-
...(portableSkills.length > 0 ? portableSkills.map((entry) => `- \`${entry}\``) : ["- None"]),
|
|
681
|
-
"",
|
|
682
|
-
"## Replace with explicit Waypoint patterns",
|
|
683
|
-
"",
|
|
684
|
-
"- hook-based session injection -> AGENTS routing, context generation, repo-local skills, doctor/sync",
|
|
685
|
-
"- hidden stop-hook policing -> advisory workflow skills and visible repo state",
|
|
686
|
-
"- transcript learners -> maintenance skills and optional app automations",
|
|
687
|
-
"- opaque reviewer plumbing -> optional Codex roles where actually useful",
|
|
688
|
-
"",
|
|
689
|
-
"## Legacy machinery to drop",
|
|
690
|
-
"",
|
|
691
|
-
`- Hook registration files: ${hookFiles.length}`,
|
|
692
|
-
`- Hook/runtime scripts: ${scriptFiles.length}`,
|
|
693
|
-
"",
|
|
694
|
-
"### Hook/runtime files",
|
|
695
|
-
...((hookFiles.length + scriptFiles.length) > 0
|
|
696
|
-
? [...hookFiles, ...scriptFiles].map((entry) => `- \`${entry}\``)
|
|
697
|
-
: ["- None"]),
|
|
698
|
-
"",
|
|
699
|
-
"## Agent files to reinterpret, not port literally",
|
|
700
|
-
"",
|
|
701
|
-
...(agentFiles.length > 0 ? agentFiles.map((entry) => `- \`${entry}\``) : ["- None"]),
|
|
702
|
-
"",
|
|
703
|
-
"## Notes",
|
|
704
|
-
"",
|
|
705
|
-
"- The strongest reusable assets are methodology, docs patterns, and review/planning discipline.",
|
|
706
|
-
"- The weakest portability surface is hook-dependent session machinery and transcript-coupled automation.",
|
|
707
|
-
"",
|
|
708
|
-
].join("\n");
|
|
709
|
-
if (targetRepo) {
|
|
710
|
-
const reportPath = path.join(targetRepo, ".waypoint/IMPORT_LEGACY.md");
|
|
711
|
-
writeText(reportPath, report);
|
|
712
|
-
actions.push(`Wrote migration report to ${reportPath}`);
|
|
713
|
-
}
|
|
714
|
-
return { report, actions };
|
|
715
|
-
}
|
|
716
|
-
function collectFiles(rootDir) {
|
|
717
|
-
const output = [];
|
|
718
|
-
for (const entry of readdirSync(rootDir)) {
|
|
719
|
-
const fullPath = path.join(rootDir, entry);
|
|
720
|
-
const stat = statSync(fullPath);
|
|
721
|
-
if (stat.isDirectory()) {
|
|
722
|
-
output.push(...collectFiles(fullPath));
|
|
723
|
-
}
|
|
724
|
-
else {
|
|
725
|
-
output.push(fullPath);
|
|
726
|
-
}
|
|
727
|
-
}
|
|
728
|
-
return output;
|
|
420
|
+
return ["Rebuilt .waypoint/DOCS_INDEX.md", "Rebuilt .waypoint/TRACKS_INDEX.md"];
|
|
729
421
|
}
|
package/dist/src/templates.js
CHANGED
|
@@ -27,8 +27,5 @@ export function readTemplate(relativePath) {
|
|
|
27
27
|
}
|
|
28
28
|
export function renderWaypointConfig(options) {
|
|
29
29
|
return readTemplate(".waypoint/config.toml")
|
|
30
|
-
.replace("__PROFILE__", options.profile)
|
|
31
|
-
.replace("__ROLES__", String(options.roles))
|
|
32
|
-
.replace("__RULES__", String(options.rules))
|
|
33
|
-
.replace("__AUTOMATIONS__", String(options.automations));
|
|
30
|
+
.replace("__PROFILE__", options.profile);
|
|
34
31
|
}
|
package/dist/src/upgrade.js
CHANGED
|
@@ -9,16 +9,6 @@ export function buildInitArgs(projectRoot, config) {
|
|
|
9
9
|
if (config.profile === "app-friendly") {
|
|
10
10
|
args.push("--app-friendly");
|
|
11
11
|
}
|
|
12
|
-
const featureMap = config.features ?? {};
|
|
13
|
-
if (featureMap.roles) {
|
|
14
|
-
args.push("--with-roles");
|
|
15
|
-
}
|
|
16
|
-
if (featureMap.rules) {
|
|
17
|
-
args.push("--with-rules");
|
|
18
|
-
}
|
|
19
|
-
if (featureMap.automations) {
|
|
20
|
-
args.push("--with-automations");
|
|
21
|
-
}
|
|
22
12
|
return args;
|
|
23
13
|
}
|
|
24
14
|
function parseVersion(version) {
|
package/package.json
CHANGED