@open-agent-toolkit/cli 0.0.41 → 0.0.43
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/assets/docs/contributing/hooks-and-safety.md +9 -2
- package/assets/docs/docs-tooling/add-docs-to-a-repo.md +12 -1
- package/assets/docs/docs-tooling/commands.md +4 -0
- package/assets/public-package-versions.json +4 -4
- package/assets/skills/oat-docs-bootstrap/SKILL.md +11 -3
- package/assets/skills/oat-project-implement/SKILL.md +6 -1
- package/assets/skills/oat-project-quick-start/SKILL.md +2 -1
- package/assets/skills/oat-project-review-provide/SKILL.md +24 -2
- package/assets/skills/oat-project-review-receive/SKILL.md +5 -1
- package/assets/templates/docs-app-fuma/docs/index.md +2 -0
- package/dist/commands/docs/index-generate/index.d.ts +1 -0
- package/dist/commands/docs/index-generate/index.d.ts.map +1 -1
- package/dist/commands/docs/index-generate/index.js +8 -1
- package/dist/commands/docs/init/index.d.ts.map +1 -1
- package/dist/commands/docs/init/index.js +46 -0
- package/dist/commands/docs/init/resolve-options.d.ts +2 -0
- package/dist/commands/docs/init/resolve-options.d.ts.map +1 -1
- package/dist/commands/docs/init/resolve-options.js +1 -0
- package/dist/commands/docs/init/root-package.d.ts +23 -0
- package/dist/commands/docs/init/root-package.d.ts.map +1 -0
- package/dist/commands/docs/init/root-package.js +226 -0
- package/dist/commands/status/index.d.ts.map +1 -1
- package/dist/commands/status/index.js +21 -4
- package/dist/engine/hook.d.ts +6 -3
- package/dist/engine/hook.d.ts.map +1 -1
- package/dist/engine/hook.js +31 -14
- package/dist/engine/index.d.ts +2 -2
- package/dist/engine/index.d.ts.map +1 -1
- package/dist/engine/index.js +1 -1
- package/package.json +2 -2
|
@@ -7,9 +7,16 @@ description: 'Pre-commit hooks and safety contracts for provider sync mutations.
|
|
|
7
7
|
|
|
8
8
|
## Optional pre-commit drift warning hook
|
|
9
9
|
|
|
10
|
-
`oat init` can install a pre-commit hook that
|
|
10
|
+
`oat init` can install a pre-commit hook that checks project provider sync state on every commit by invoking `oat status --scope project --hook`.
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
The hook distinguishes two states so unmanaged files are not reported the same as true drift:
|
|
13
|
+
|
|
14
|
+
- **Warning (managed drift or missing):** a manifest-tracked provider entry has drifted or is missing. Emits `oat: managed provider views are out of sync - run 'oat sync --scope project'` to stderr.
|
|
15
|
+
- **Info (unmanaged strays only):** provider files exist inside a managed directory but are not in the manifest. Emits `oat: unmanaged provider files detected - run 'oat status --scope project' to review` to stderr. Not treated as drift.
|
|
16
|
+
|
|
17
|
+
The hook is non-blocking: it never fails the commit, even when managed drift is detected.
|
|
18
|
+
|
|
19
|
+
OAT installs the hook into Git's currently active hook directory. When a consumer repo keeps hooks in a repo-managed folder such as `.githooks/`, Git must be configured to use that path before install, or OAT must configure it during the hook prompt flow.
|
|
13
20
|
|
|
14
21
|
## Safety contracts
|
|
15
22
|
|
|
@@ -69,12 +69,13 @@ What the skill adds over the raw CLI:
|
|
|
69
69
|
- **Post-scaffold patches for open CLI gaps.** Applied only when capability detection shows the CLI hasn't closed the gap. Each patch is labeled (e.g., `<!-- FP-12 patch -->`) so it can be removed deterministically when the upstream fix lands:
|
|
70
70
|
- **FP-11** — Turbopack `root` for nested-standalone Fumadocs apps (suppresses the multiple-lockfile warning)
|
|
71
71
|
- **FP-12** — `export const metadata = { title, description }` in `app/layout.tsx` (the only thing that populates page `<title>`, meta description, and Open Graph — `DocsLayout.branding.title` only renders nav chrome, and `createDocsConfig()` ignores `title` / `description` entirely)
|
|
72
|
-
- **FP-13** —
|
|
72
|
+
- **FP-13** — four scaffold-content fixes (empty per-page `description:` frontmatter, bare install/build commands missing `--filter` or `cd`-prefix for monorepo/nested shapes, false `docs:lint` claim when `lint=none`, Node version line that doesn't match the consuming repo's `.nvmrc` / `engines.node`)
|
|
73
73
|
- **FP-15** — writes a task-framed `<appRoot>/AGENTS.md` bridge file when the CLI hasn't scaffolded one. The bridge is the docs app's runtime agent reference (separate audience from `docs/contributing.md`)
|
|
74
74
|
- **FP-16** — rewrites `docs/index.md` `## Contents` links to the `.md`-suffixed form that `@open-agent-toolkit/docs-transforms` normalizes at build time (agent-friendlier than extension-less; routes correctly)
|
|
75
75
|
- **FP-17** — trims `docs/contributing.md`'s "Agent guidance" section to a one-line pointer at the docs-app `AGENTS.md`, restoring the three-surfaces separation
|
|
76
76
|
- **Build verification.** Runs install + build, classifies failures against known patterns, stops on unknown errors rather than guessing.
|
|
77
77
|
- **Config inspection.** Reads `.oat/config.json` back, verifies paths exist on disk, handles the nested-standalone dual-config case, and collects the `requireForProjectCompletion` opt-in explicitly.
|
|
78
|
+
- **Root-build explanation.** When the CLI safely patches a compatible Turbo root `build` script, the walkthrough explains why the filter was added, shows the diff shape, and documents how to adjust or revert it. When the CLI skips the patch, the walkthrough relays the recommended manual snippet.
|
|
78
79
|
- **Educational walkthrough.** Seven sections covering the `documentation` config, the two-`index.md` model, the `## Contents` contract (with extension discipline), the three agent-instruction surfaces (root `AGENTS.md` pointer / docs-app `AGENTS.md` / `docs/contributing.md`), Fumadocs internals (or MkDocs Minimum Contract), and the OAT docs ecosystem (`oat-project-document`, `oat-docs-analyze`, `oat-docs-apply`).
|
|
79
80
|
- **Optional content kickoff.** Hands off to `oat-docs-analyze` + `oat-docs-apply` if you want to populate initial repo-specific content immediately.
|
|
80
81
|
|
|
@@ -108,6 +109,12 @@ oat docs init --app-name my-docs --framework mkdocs --yes
|
|
|
108
109
|
|
|
109
110
|
Use 3b when you want a fully headless scaffold (CI, automation) and can accept the raw CLI output without the guided post-patches.
|
|
110
111
|
|
|
112
|
+
For compatible Turbo monorepos, the CLI also patches the repo-root
|
|
113
|
+
`package.json` by default so root `pnpm build` excludes the new docs app and a
|
|
114
|
+
root `build:docs` script is available for docs-only builds. Use
|
|
115
|
+
`--no-root-patch` to opt out, or `--dry-run` to preview the diff without
|
|
116
|
+
writing it.
|
|
117
|
+
|
|
111
118
|
## 3a. Migrating from MkDocs (optional)
|
|
112
119
|
|
|
113
120
|
If you have an existing MkDocs site and want to switch to Fumadocs, use the
|
|
@@ -141,6 +148,10 @@ For **Fumadocs** apps, the docs index is generated automatically via
|
|
|
141
148
|
oat docs generate-index --docs-dir docs
|
|
142
149
|
```
|
|
143
150
|
|
|
151
|
+
The generated app-root `index.md` is machine-owned and now starts with an
|
|
152
|
+
`AUTOGENERATED` warning comment. Edit authored pages under `docs/`, not the
|
|
153
|
+
generated root index.
|
|
154
|
+
|
|
144
155
|
## 5. Analyze the docs surface
|
|
145
156
|
|
|
146
157
|
Use the skill, not the CLI stub, for the real analysis workflow.
|
|
@@ -39,6 +39,8 @@ Key behavior:
|
|
|
39
39
|
- defaults to `apps/<app-name>` for monorepos
|
|
40
40
|
- defaults to `<app-name>/` at repo root for single-package repos
|
|
41
41
|
- sets `documentation.tooling`, `documentation.root`, and `documentation.index` in `.oat/config.json`
|
|
42
|
+
- when the repo root exposes a compatible Turbo `scripts.build`, patches it to exclude the new docs app from the default root build and adds a root-level `build:docs` script
|
|
43
|
+
- prints a unified diff before writing the root `package.json` change and returns a manual snippet when the patch is skipped because the build script is missing, non-Turbo, or ambiguous
|
|
42
44
|
|
|
43
45
|
Fumadocs scaffold:
|
|
44
46
|
|
|
@@ -60,6 +62,7 @@ Supported flags:
|
|
|
60
62
|
- `--description <text>` (site description, optional)
|
|
61
63
|
- `--lint <none|markdownlint-cli2>`
|
|
62
64
|
- `--format <oxfmt|none>`
|
|
65
|
+
- `--no-root-patch`
|
|
63
66
|
- `--yes`
|
|
64
67
|
|
|
65
68
|
Examples:
|
|
@@ -117,6 +120,7 @@ Key behavior:
|
|
|
117
120
|
- includes descriptions from frontmatter when present
|
|
118
121
|
- outputs to app root (`index.md`) by default, not inside the docs directory
|
|
119
122
|
- updates `documentation.index` in `.oat/config.json`
|
|
123
|
+
- prepends an `AUTOGENERATED` warning comment to the output and rewrites the file on every run; do not hand-edit the generated `index.md`
|
|
120
124
|
- sorting: `index.md` first, then directories before files, then lexical
|
|
121
125
|
|
|
122
126
|
Supported flags:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: oat-docs-bootstrap
|
|
3
|
-
version: 1.0.
|
|
3
|
+
version: 1.0.1
|
|
4
4
|
description: Use when bootstrapping a new OAT docs app in a repo. Guides the user through preflight detection, richer input gathering than the raw CLI, `oat docs init` invocation with labeled post-patches for open CLI gaps, build verification, post-scaffold config inspection, and an educational walkthrough. Supports Fumadocs (full path) and MkDocs (lean path with defined minimum contract).
|
|
5
5
|
argument-hint: '<optional-target-dir>'
|
|
6
6
|
disable-model-invocation: true
|
|
@@ -473,6 +473,7 @@ Capture both stdout and stderr. **Do not** stream output directly to the user; t
|
|
|
473
473
|
createdFiles: string[] // paths relative to appRoot
|
|
474
474
|
capabilities: { siteNameFlag: boolean, ... } // from Capability Detection (3b)
|
|
475
475
|
cliLogs: { stdout: string, stderr: string } // retained for Walkthrough
|
|
476
|
+
rootBuildPatch: { status, reason?, diff?, manualSnippet? } | null // parsed from CLI output when available
|
|
476
477
|
patchesApplied: [] // populated by 3c/3d site-identity + scaffold-integrity sub-procedures
|
|
477
478
|
```
|
|
478
479
|
|
|
@@ -655,7 +656,7 @@ Four sub-findings, each with its own gate, target, and idempotency check. All su
|
|
|
655
656
|
- **D.2 — Generated `index.md` header comment.** The header to prepend:
|
|
656
657
|
|
|
657
658
|
```markdown
|
|
658
|
-
<!--
|
|
659
|
+
<!-- AUTOGENERATED by `oat docs generate-index`. Do not hand-edit; changes are clobbered on every `predev` / `prebuild`. -->
|
|
659
660
|
```
|
|
660
661
|
|
|
661
662
|
**Two-pass strategy. Both passes MUST run — do not treat the second as optional.**
|
|
@@ -931,6 +932,13 @@ Narrate each field actually present in their config (skip fields that are absent
|
|
|
931
932
|
- **`documentation.config`** (MkDocs only) — path to `mkdocs.yml`. Present for MkDocs because its chrome/nav is YAML-configured; absent for Fumadocs because chrome is code.
|
|
932
933
|
- **`documentation.requireForProjectCompletion`** — the opt-in collected in Step 5e. If `true`, `oat-project-complete` will block project completion until `oat-docs-analyze` reports no open recommendations. Explain whichever value is set on this project.
|
|
933
934
|
|
|
935
|
+
If `Scaffold Result.rootBuildPatch` is present, narrate it here before moving on:
|
|
936
|
+
|
|
937
|
+
- **When `status` is `applied`, `dry-run`, or `already-configured`:** explain why the root `package.json` changed. The point is not cosmetics; it's to keep repo-root `pnpm build` from pulling the new docs app into the consumer's default Turbo build, where React / Next type collisions can break CI. Show the exact script diff from `rootBuildPatch.diff` when available; if the diff was not retained, at minimum quote the before/after values for `scripts.build` and `scripts["build:docs"]`.
|
|
938
|
+
- Make the behavior concrete: `build` now excludes `{appName}` from the default Turbo build graph, and `build:docs` is the explicit root-level command that builds only the docs app.
|
|
939
|
+
- Document the adjustment/revert path explicitly: "If you want different scope behavior, edit the root `package.json` `scripts.build` and `scripts["build:docs"]` entries together. Removing the extra `--filter='!{appName}'` restores the old all-packages build; changing `build:docs` changes the docs-only target."
|
|
940
|
+
- **When `status` is `skipped`:** surface the skip reason in plain language, then print `rootBuildPatch.manualSnippet` verbatim as the recommended manual Turbo snippet to add. Explain that OAT intentionally left the root scripts alone because it could not prove the existing root build was a Turbo build it was safe to rewrite.
|
|
941
|
+
|
|
934
942
|
End with: "This config is how every OAT docs tool finds your docs. Editing it by hand is supported — but changes to `root` or `config` paths need to match reality on disk."
|
|
935
943
|
|
|
936
944
|
#### Section B (both frameworks) — The two `index.md` files
|
|
@@ -941,7 +949,7 @@ Narrate:
|
|
|
941
949
|
|
|
942
950
|
- **The authored source** at `<appRoot>/docs/index.md`. This is the file the user edits. It has frontmatter (`title`, `description`) and a `## Contents` section listing direct children of the docs root. It is the top of a fractal: every directory has its own `index.md`, each with its own `## Contents`.
|
|
943
951
|
- **The generated map** at `<appRoot>/index.md` (when Fumadocs — the path differs for MkDocs; use the `documentation.index` path resolved by the Inspector if it differs). Regenerated on every `predev` / `prebuild` by the `oat docs generate-index` command. Machine-shaped: rolls up every `## Contents` section in the tree into a single searchable map that tools consume. **Hand-edits are silently clobbered.**
|
|
944
|
-
- **How to tell them apart when opening a file.** If the file sits inside `docs/`, it's authored. If it sits at `<appRoot>/index.md` (outside `docs/`), it's generated — and
|
|
952
|
+
- **How to tell them apart when opening a file.** If the file sits inside `docs/`, it's authored. If it sits at `<appRoot>/index.md` (outside `docs/`), it's generated — and when the CLI or Scaffold-integrity FP-13/D.2 wrote the warning correctly, the first line is `<!-- AUTOGENERATED by \`oat docs generate-index\`... -->`.
|
|
945
953
|
|
|
946
954
|
End with: "Always edit `docs/index.md` and the `## Contents` sections. Never edit the root-level `index.md` — your edits will disappear next build."
|
|
947
955
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: oat-project-implement
|
|
3
|
-
version: 1.3.
|
|
3
|
+
version: 1.3.1
|
|
4
4
|
description: Use when plan.md is ready for execution. Implements plan tasks sequentially with TDD discipline and state tracking.
|
|
5
5
|
disable-model-invocation: true
|
|
6
6
|
user-invocable: true
|
|
@@ -24,6 +24,9 @@ Execute the implementation plan task-by-task with full state tracking.
|
|
|
24
24
|
**CRITICAL — Bookkeeping commits are mandatory, not optional.**
|
|
25
25
|
After every code commit and after every phase/review-fix completion, you MUST commit the OAT tracking files (`implementation.md`, `state.md`, `plan.md`) as a separate bookkeeping commit. Do not defer, batch, or skip these commits under the reasoning that they "aren't related to the implementation." Skipping a bookkeeping commit is the primary cause of cross-session state drift and will cause the next implementation run to fail bookkeeping cross-checks. If bookkeeping commits feel frequent, that is the intended design — they are cheap and they prevent drift.
|
|
26
26
|
|
|
27
|
+
**CRITICAL — Review boundaries require a committed artifact baseline.**
|
|
28
|
+
Do not enter checkpoint review, final review, revise, or PR-final handoff with dirty core project artifacts (`discovery.md`, `spec.md`, `design.md`, `plan.md`, `implementation.md`, `state.md`, plus `.oat/state.md` when refreshed). If one of those boundaries is next and artifact bookkeeping is still uncommitted, stop and create the bookkeeping commit first.
|
|
29
|
+
|
|
27
30
|
## Progress Indicators (User-Facing)
|
|
28
31
|
|
|
29
32
|
When executing this skill, provide lightweight progress feedback so the user can tell what’s happening after they confirm.
|
|
@@ -641,6 +644,8 @@ All must pass before proceeding.
|
|
|
641
644
|
|
|
642
645
|
**At the final plan phase boundary, a code review is required before PR.**
|
|
643
646
|
|
|
647
|
+
Before requesting final review, ensure the latest project-artifact bookkeeping is already committed. Review should evaluate the implementation state as it actually stands on the branch, not a half-tracked working tree.
|
|
648
|
+
|
|
644
649
|
Check if final review already completed (preferred source of truth: plan.md Reviews table):
|
|
645
650
|
|
|
646
651
|
```bash
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: oat-project-quick-start
|
|
3
|
-
version: 1.3.
|
|
3
|
+
version: 1.3.4
|
|
4
4
|
description: Use when a task is small enough for quick mode or rapid iteration is preferred. Scaffolds a lightweight OAT project from discovery directly to a runnable plan, with optional brainstorming and lightweight design.
|
|
5
5
|
argument-hint: '<project-name> ["project description"]'
|
|
6
6
|
disable-model-invocation: true
|
|
@@ -70,6 +70,7 @@ When executing this skill, provide lightweight progress feedback so the user can
|
|
|
70
70
|
- After any write to `discovery.md`, `design.md`, `plan.md`, `implementation.md`, or project `state.md`, ensure the artifact is saved immediately and remains tracked in git.
|
|
71
71
|
- If the skill is about to pause for user input or stop after mutating artifacts, commit the changed artifacts before waiting. Do not leave discovery/design updates only in the working tree.
|
|
72
72
|
- Quick-start handoff is not complete until the changed project artifacts and regenerated `.oat/state.md` dashboard have been committed.
|
|
73
|
+
- This applies to downstream lifecycle boundaries too: implementation, review, revise, and PR skills must inherit a committed artifact baseline, not an untracked project tree.
|
|
73
74
|
|
|
74
75
|
## Process
|
|
75
76
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: oat-project-review-provide
|
|
3
|
-
version: 1.3.
|
|
3
|
+
version: 1.3.1
|
|
4
4
|
description: Use when completed work in an active OAT project needs a quality gate before merge. Performs a lifecycle-scoped review after a task, phase, or full implementation, unlike oat-review-provide.
|
|
5
5
|
disable-model-invocation: true
|
|
6
6
|
user-invocable: true
|
|
@@ -19,6 +19,8 @@ Produce an independent review artifact that verifies requirements/design alignme
|
|
|
19
19
|
|
|
20
20
|
**Required:** Active project with at least one completed task.
|
|
21
21
|
|
|
22
|
+
**Required:** Core project artifacts are already committed before the review begins. Review should not be the first step that notices an untracked project tree or pending bookkeeping-only artifact edits.
|
|
23
|
+
|
|
22
24
|
## Mode Assertion
|
|
23
25
|
|
|
24
26
|
**OAT MODE: Review Request**
|
|
@@ -218,7 +220,27 @@ TARGET_BRANCH="${TARGET_BRANCH:-$CURRENT_BRANCH}" # from user scope, worktree c
|
|
|
218
220
|
|
|
219
221
|
- If user chooses option 1: run `git checkout {TARGET_BRANCH}`, then proceed.
|
|
220
222
|
- If user chooses option 2: set `INLINE_ONLY=true` — skip artifact write (Step 7/8) and output review findings directly in the session. The user can manually save the output.
|
|
221
|
-
|
|
223
|
+
|
|
224
|
+
### Step 1.6: Enforce Committed Artifact Baseline
|
|
225
|
+
|
|
226
|
+
Before gathering review context, inspect the core project artifacts:
|
|
227
|
+
|
|
228
|
+
- `"$PROJECT_PATH/discovery.md"`
|
|
229
|
+
- `"$PROJECT_PATH/spec.md"`
|
|
230
|
+
- `"$PROJECT_PATH/design.md"`
|
|
231
|
+
- `"$PROJECT_PATH/plan.md"`
|
|
232
|
+
- `"$PROJECT_PATH/implementation.md"`
|
|
233
|
+
- `"$PROJECT_PATH/state.md"`
|
|
234
|
+
- `.oat/state.md` (when it exists and was refreshed as part of the project workflow)
|
|
235
|
+
|
|
236
|
+
If any of those files are untracked or modified only because the previous workflow step did not finish its bookkeeping commit:
|
|
237
|
+
|
|
238
|
+
- Stop and tell the user to commit the pending artifact bookkeeping first, or resume the originating workflow skill so it can do that commit.
|
|
239
|
+
- Do not write a review artifact against that half-tracked state.
|
|
240
|
+
|
|
241
|
+
If the review is intentionally inline-only and the user explicitly wants to inspect an uncommitted artifact state, say so clearly in the output and skip writing the review artifact to disk.
|
|
242
|
+
|
|
243
|
+
- If user chooses option 3: stop and suggest `oat-worktree-bootstrap-auto`.
|
|
222
244
|
|
|
223
245
|
### Step 2: Validate Artifacts Exist (Mode-Aware)
|
|
224
246
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: oat-project-review-receive
|
|
3
|
-
version: 1.4.
|
|
3
|
+
version: 1.4.1
|
|
4
4
|
description: Use when review findings from oat-project-review-provide need closure. Converts review artifacts into actionable plan tasks.
|
|
5
5
|
disable-model-invocation: true
|
|
6
6
|
user-invocable: true
|
|
@@ -19,6 +19,8 @@ Turn review output into plan changes and a clear next action. This closes the fe
|
|
|
19
19
|
|
|
20
20
|
**Required:** An active review artifact exists in the top level of `{PROJECT_PATH}/reviews/` (not in `reviews/archived/`).
|
|
21
21
|
|
|
22
|
+
This skill assumes the reviewed project artifacts were already committed before the review ran. If you discover untracked core project artifacts here, treat that as earlier workflow drift and include them in the bookkeeping fix instead of leaving the project partially tracked.
|
|
23
|
+
|
|
22
24
|
## Mode Assertion
|
|
23
25
|
|
|
24
26
|
**OAT MODE: Receive Review**
|
|
@@ -435,6 +437,8 @@ git diff --cached --quiet || git commit -m "chore(oat): record review findings a
|
|
|
435
437
|
|
|
436
438
|
Do not use `git add -A` or glob patterns that reach outside `"$PROJECT_PATH/reviews/"`. Do not include unrelated implementation or code files in this commit. Do not defer this commit without explicit user approval — if deferred, clearly state in the summary that bookkeeping is uncommitted so the original agent knows to commit on return.
|
|
437
439
|
|
|
440
|
+
If the project itself is still untracked because earlier lifecycle steps never committed the initial artifact set, widen this bookkeeping commit to include the untracked core project artifacts (`discovery.md`, `spec.md`, `design.md`, `plan.md`, `implementation.md`, `state.md`, plus `.oat/state.md` when relevant). Do not leave the project tree partially tracked after receive-review finishes.
|
|
441
|
+
|
|
438
442
|
**Note on archived review paths:** When `reviews/archived/` matches a `localPaths` pattern (the default setup), the archived file is gitignored and `git add "$PROJECT_PATH/reviews/"` will only stage the deletion of the original (now-moved) top-level review file. When `reviews/archived/` is tracked, both the deletion and the new archived location are staged. Both cases are safe — the command handles them uniformly.
|
|
439
443
|
|
|
440
444
|
**Worktree handling:** If the project was resolved via a worktree in Step 0, run the git commands scoped to the worktree (`git -C "$WORKTREE_PATH" ...`) so the commit lands on the worktree branch.
|
|
@@ -3,6 +3,8 @@ title: '{{SITE_NAME}}'
|
|
|
3
3
|
description: '{{SITE_DESCRIPTION}}'
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
+
<!-- AUTOGENERATED by `oat docs generate-index`. Do not hand-edit; changes are clobbered on every `predev` / `prebuild`. -->
|
|
7
|
+
|
|
6
8
|
# {{SITE_NAME}}
|
|
7
9
|
|
|
8
10
|
Use this file as the map to the repository's central documentation site. The site is organized to support both human readers and AI agents, with every directory exposing an `index.md` entrypoint.
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type CommandContext, type GlobalOptions } from '../../../app/command-context.js';
|
|
2
2
|
import { Command } from 'commander';
|
|
3
|
+
export declare const GENERATED_INDEX_WARNING = "<!-- AUTOGENERATED by `oat docs generate-index`. Do not hand-edit; changes are clobbered on every `predev` / `prebuild`. -->";
|
|
3
4
|
interface IndexGenerateFileDependencies {
|
|
4
5
|
generateIndex: (docsDir: string) => Promise<import('./generator.js').IndexEntry[]>;
|
|
5
6
|
renderIndex: (entries: import('./generator.js').IndexEntry[]) => string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/commands/docs/index-generate/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,MAAM,sBAAsB,CAAC;AAI9B,OAAO,EAAE,OAAO,EAAU,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/commands/docs/index-generate/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,MAAM,sBAAsB,CAAC;AAI9B,OAAO,EAAE,OAAO,EAAU,MAAM,WAAW,CAAC;AAI5C,eAAO,MAAM,uBAAuB,iIAC4F,CAAC;AAOjI,UAAU,6BAA6B;IACrC,aAAa,EAAE,CACb,OAAO,EAAE,MAAM,KACZ,OAAO,CAAC,OAAO,aAAa,EAAE,UAAU,EAAE,CAAC,CAAC;IACjD,WAAW,EAAE,CAAC,OAAO,EAAE,OAAO,aAAa,EAAE,UAAU,EAAE,KAAK,MAAM,CAAC;IACrE,SAAS,EAAE,CACT,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,cAAc,KACrB,OAAO,CAAC,IAAI,CAAC,CAAC;IACnB,aAAa,EAAE,CACb,QAAQ,EAAE,MAAM,KACb,OAAO,CAAC,OAAO,oBAAoB,EAAE,SAAS,CAAC,CAAC;IACrD,cAAc,EAAE,CACd,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,OAAO,oBAAoB,EAAE,SAAS,KAC3C,OAAO,CAAC,IAAI,CAAC,CAAC;IACnB,eAAe,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;CACnD;AAED,UAAU,yBAAyB;IACjC,mBAAmB,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,cAAc,CAAC;IAChE,QAAQ,EAAE,6BAA6B,CAAC;CACzC;AAgFD,wBAAgB,8BAA8B,CAC5C,SAAS,GAAE,OAAO,CAAC,yBAAyB,CAAM,GACjD,OAAO,CAsBT"}
|
|
@@ -6,6 +6,7 @@ import { readOatConfig, writeOatConfig } from '../../../config/oat-config.js';
|
|
|
6
6
|
import { resolveProjectRoot } from '../../../fs/paths.js';
|
|
7
7
|
import { Command, Option } from 'commander';
|
|
8
8
|
import { generateIndex, renderIndex } from './generator.js';
|
|
9
|
+
export const GENERATED_INDEX_WARNING = '<!-- AUTOGENERATED by `oat docs generate-index`. Do not hand-edit; changes are clobbered on every `predev` / `prebuild`. -->';
|
|
9
10
|
const DEFAULT_FILE_DEPS = {
|
|
10
11
|
generateIndex,
|
|
11
12
|
renderIndex,
|
|
@@ -18,13 +19,19 @@ const DEFAULT_DEPENDENCIES = {
|
|
|
18
19
|
buildCommandContext,
|
|
19
20
|
fileDeps: DEFAULT_FILE_DEPS,
|
|
20
21
|
};
|
|
22
|
+
function buildGeneratedIndexOutput(content) {
|
|
23
|
+
if (!content) {
|
|
24
|
+
return GENERATED_INDEX_WARNING;
|
|
25
|
+
}
|
|
26
|
+
return `${GENERATED_INDEX_WARNING}\n\n${content}`;
|
|
27
|
+
}
|
|
21
28
|
async function runIndexGenerate(context, options, deps) {
|
|
22
29
|
const docsDir = join(context.cwd, options.docsDir);
|
|
23
30
|
const outputPath = options.output
|
|
24
31
|
? join(context.cwd, options.output)
|
|
25
32
|
: join(context.cwd, 'index.md');
|
|
26
33
|
const entries = await deps.generateIndex(docsDir);
|
|
27
|
-
const content = deps.renderIndex(entries);
|
|
34
|
+
const content = buildGeneratedIndexOutput(deps.renderIndex(entries));
|
|
28
35
|
await deps.writeFile(outputPath, content, 'utf8');
|
|
29
36
|
const repoRoot = await deps.resolveRepoRoot(context.cwd);
|
|
30
37
|
const config = await deps.readOatConfig(repoRoot);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/commands/docs/init/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,KAAK,mBAAmB,EAEzB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAGL,KAAK,aAAa,EAClB,KAAK,YAAY,EAElB,MAAM,iCAAiC,CAAC;AAEzC,OAAO,EACL,KAAK,SAAS,EAGf,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAAE,OAAO,EAAU,MAAM,WAAW,CAAC;AAE5C,OAAO,EAIL,KAAK,uBAAuB,EAK7B,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/commands/docs/init/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,KAAK,mBAAmB,EAEzB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAGL,KAAK,aAAa,EAClB,KAAK,YAAY,EAElB,MAAM,iCAAiC,CAAC;AAEzC,OAAO,EACL,KAAK,SAAS,EAGf,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAAE,OAAO,EAAU,MAAM,WAAW,CAAC;AAE5C,OAAO,EAIL,KAAK,uBAAuB,EAK7B,MAAM,mBAAmB,CAAC;AAkB3B,UAAU,oBAAoB;IAC5B,mBAAmB,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,cAAc,CAAC;IAChE,iBAAiB,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IACzC,eAAe,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,UAAU,GAAG,gBAAgB,CAAC,CAAC;IAC9E,gBAAgB,EAAE,CAChB,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,MAAM,EACpB,GAAG,EAAE,aAAa,KACf,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC5B,eAAe,EAAE,CAAC,CAAC,SAAS,MAAM,EAChC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC,EAAE,EAC1B,GAAG,EAAE,aAAa,KACf,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IACvB,WAAW,EAAE,CACX,OAAO,EAAE,cAAc,EACvB,OAAO,EAAE,uBAAuB,EAChC,UAAU,EAAE,MAAM,KACf,OAAO,CAAC,IAAI,CAAC,CAAC;IACnB,qBAAqB,EAAE,CACrB,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,KACT,OAAO,CAAC,mBAAmB,CAAC,CAAC;IAClC,aAAa,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,SAAS,CAAC,CAAC;IACxD,aAAa,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,aAAa,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CAC1E;AAyGD,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,uBAAuB,GAAG,MAAM,CAc7E;AA+GD,wBAAgB,qBAAqB,CACnC,SAAS,GAAE,OAAO,CAAC,oBAAoB,CAAM,GAC5C,OAAO,CAuCT"}
|
|
@@ -6,7 +6,43 @@ import { readOatConfig, writeOatConfig, } from '../../../config/oat-config.js';
|
|
|
6
6
|
import { resolveAssetsRoot } from '../../../fs/assets.js';
|
|
7
7
|
import { Command, Option } from 'commander';
|
|
8
8
|
import { DEFAULT_DOCS_REPO_SHAPE_DEPENDENCIES, detectDocsRepoShape, getDefaultDocsAppName, resolveDocsInitOptions, } from './resolve-options.js';
|
|
9
|
+
import { patchRootPackageJson, } from './root-package.js';
|
|
9
10
|
import { scaffoldDocsApp } from './scaffold.js';
|
|
11
|
+
function logRootPackagePatch(context, result) {
|
|
12
|
+
if (result.status === 'disabled') {
|
|
13
|
+
context.logger.info('Skipped root package.json patch (--no-root-patch).');
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
if (result.diff) {
|
|
17
|
+
context.logger.info('');
|
|
18
|
+
context.logger.info('Root package.json diff:');
|
|
19
|
+
context.logger.info(result.diff);
|
|
20
|
+
}
|
|
21
|
+
if (result.status === 'applied') {
|
|
22
|
+
context.logger.info('Updated the root Turbo build scripts to exclude the docs app from the default build and added `build:docs`.');
|
|
23
|
+
}
|
|
24
|
+
else if (result.status === 'dry-run') {
|
|
25
|
+
context.logger.info('Dry run: the root Turbo build script patch was previewed but not written.');
|
|
26
|
+
context.logger.info('Run without --dry-run to apply these changes.');
|
|
27
|
+
}
|
|
28
|
+
else if (result.status === 'already-configured') {
|
|
29
|
+
context.logger.info('Root package.json already excludes the docs app from the default Turbo build and exposes `build:docs`.');
|
|
30
|
+
}
|
|
31
|
+
else if (result.status === 'skipped') {
|
|
32
|
+
for (const warning of result.warnings) {
|
|
33
|
+
context.logger.warn(warning);
|
|
34
|
+
}
|
|
35
|
+
if (result.manualSnippet) {
|
|
36
|
+
context.logger.info('');
|
|
37
|
+
context.logger.info('Recommended manual Turbo script snippet for the repo root:');
|
|
38
|
+
context.logger.info(result.manualSnippet);
|
|
39
|
+
}
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
for (const warning of result.warnings) {
|
|
43
|
+
context.logger.warn(warning);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
10
46
|
const DEFAULT_DEPENDENCIES = {
|
|
11
47
|
buildCommandContext,
|
|
12
48
|
resolveAssetsRoot,
|
|
@@ -18,6 +54,12 @@ const DEFAULT_DEPENDENCIES = {
|
|
|
18
54
|
assetsRoot,
|
|
19
55
|
...options,
|
|
20
56
|
});
|
|
57
|
+
const rootPackagePatch = await patchRootPackageJson({
|
|
58
|
+
repoRoot: context.cwd,
|
|
59
|
+
appName: options.appName,
|
|
60
|
+
dryRun: context.dryRun,
|
|
61
|
+
enabled: options.rootPatch,
|
|
62
|
+
});
|
|
21
63
|
const config = await readOatConfig(context.cwd);
|
|
22
64
|
config.documentation = {
|
|
23
65
|
...config.documentation,
|
|
@@ -30,6 +72,7 @@ const DEFAULT_DEPENDENCIES = {
|
|
|
30
72
|
...options,
|
|
31
73
|
createdFiles: result.createdFiles,
|
|
32
74
|
appRoot: result.appRoot,
|
|
75
|
+
rootPackagePatch,
|
|
33
76
|
});
|
|
34
77
|
return;
|
|
35
78
|
}
|
|
@@ -39,6 +82,7 @@ const DEFAULT_DEPENDENCIES = {
|
|
|
39
82
|
context.logger.info(` App name: ${options.appName}`);
|
|
40
83
|
context.logger.info(` Lint: ${options.lint}`);
|
|
41
84
|
context.logger.info(` Format: ${options.format}`);
|
|
85
|
+
logRootPackagePatch(context, rootPackagePatch);
|
|
42
86
|
},
|
|
43
87
|
upsertAgentsMdSection,
|
|
44
88
|
readOatConfig,
|
|
@@ -75,6 +119,7 @@ async function runDocsInitCommand(context, options, dependencies) {
|
|
|
75
119
|
providedSiteDescription: options.description,
|
|
76
120
|
providedLint: options.lint,
|
|
77
121
|
providedFormat: options.format,
|
|
122
|
+
providedRootPatch: options.rootPatch,
|
|
78
123
|
inputWithDefault: dependencies.inputWithDefault,
|
|
79
124
|
selectWithAbort: dependencies.selectWithAbort,
|
|
80
125
|
});
|
|
@@ -170,6 +215,7 @@ export function createDocsInitCommand(overrides = {}) {
|
|
|
170
215
|
'oxfmt',
|
|
171
216
|
'none',
|
|
172
217
|
]))
|
|
218
|
+
.option('--no-root-patch', 'Skip patching the consumer root package.json')
|
|
173
219
|
.option('--yes', 'Accept defaults without prompting')
|
|
174
220
|
.action(async (options, command) => {
|
|
175
221
|
const context = dependencies.buildCommandContext(readGlobalOptions(command));
|
|
@@ -12,6 +12,7 @@ export interface DocsInitResolvedOptions {
|
|
|
12
12
|
siteDescription: string;
|
|
13
13
|
lint: DocsLintMode;
|
|
14
14
|
format: DocsFormatMode;
|
|
15
|
+
rootPatch: boolean;
|
|
15
16
|
}
|
|
16
17
|
export interface ResolveDocsInitOptionsInput {
|
|
17
18
|
repoRoot: string;
|
|
@@ -24,6 +25,7 @@ export interface ResolveDocsInitOptionsInput {
|
|
|
24
25
|
providedSiteDescription?: string;
|
|
25
26
|
providedLint?: DocsLintMode;
|
|
26
27
|
providedFormat?: DocsFormatMode;
|
|
28
|
+
providedRootPatch?: boolean;
|
|
27
29
|
inputWithDefault: (message: string, defaultValue: string, ctx: PromptContext) => Promise<string | null>;
|
|
28
30
|
selectWithAbort: <T extends string>(message: string, choices: SelectChoice<T>[], ctx: PromptContext) => Promise<T | null>;
|
|
29
31
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolve-options.d.ts","sourceRoot":"","sources":["../../../../src/commands/docs/init/resolve-options.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,aAAa,EACb,YAAY,EACb,MAAM,iCAAiC,CAAC;AAGzC,MAAM,MAAM,aAAa,GAAG,UAAU,GAAG,gBAAgB,CAAC;AAC1D,MAAM,MAAM,aAAa,GAAG,UAAU,GAAG,QAAQ,CAAC;AAClD,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,mBAAmB,CAAC;AACxD,MAAM,MAAM,cAAc,GAAG,OAAO,GAAG,MAAM,CAAC;AAE9C,MAAM,WAAW,uBAAuB;IACtC,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,aAAa,CAAC;IACzB,SAAS,EAAE,aAAa,CAAC;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;IACxB,IAAI,EAAE,YAAY,CAAC;IACnB,MAAM,EAAE,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"resolve-options.d.ts","sourceRoot":"","sources":["../../../../src/commands/docs/init/resolve-options.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,aAAa,EACb,YAAY,EACb,MAAM,iCAAiC,CAAC;AAGzC,MAAM,MAAM,aAAa,GAAG,UAAU,GAAG,gBAAgB,CAAC;AAC1D,MAAM,MAAM,aAAa,GAAG,UAAU,GAAG,QAAQ,CAAC;AAClD,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,mBAAmB,CAAC;AACxD,MAAM,MAAM,cAAc,GAAG,OAAO,GAAG,MAAM,CAAC;AAE9C,MAAM,WAAW,uBAAuB;IACtC,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,aAAa,CAAC;IACzB,SAAS,EAAE,aAAa,CAAC;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;IACxB,IAAI,EAAE,YAAY,CAAC;IACnB,MAAM,EAAE,cAAc,CAAC;IACvB,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,aAAa,CAAC;IACzB,WAAW,EAAE,OAAO,CAAC;IACrB,cAAc,EAAE,OAAO,CAAC;IACxB,iBAAiB,CAAC,EAAE,aAAa,CAAC;IAClC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,gBAAgB,EAAE,CAChB,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,MAAM,EACpB,GAAG,EAAE,aAAa,KACf,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC5B,eAAe,EAAE,CAAC,CAAC,SAAS,MAAM,EAChC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC,EAAE,EAC1B,GAAG,EAAE,aAAa,KACf,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;CACxB;AAED,MAAM,WAAW,yBAAyB;IACxC,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC/C,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC9C,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,cAAc,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;CACvE;AAiBD,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,aAAa,GACvB,MAAM,CAMR;AAED,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,aAAa,EACxB,OAAO,EAAE,MAAM,GACd,MAAM,CAMR;AAoBD,wBAAsB,mBAAmB,CACvC,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,yBAAyB,GACtC,OAAO,CAAC,aAAa,CAAC,CAqBxB;AAED,wBAAgB,cAAc,CAAC,SAAS,EAAE,aAAa,GAAG,MAAM,CAE/D;AAED,wBAAsB,sBAAsB,CAC1C,KAAK,EAAE,2BAA2B,GACjC,OAAO,CAAC,uBAAuB,GAAG,IAAI,CAAC,CAgFzC;AAED,eAAO,MAAM,oCAAoC,EAAE,yBAOlD,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
type RootPackagePatchReason = 'missing-package-json' | 'no-build-script' | 'non-turbo-build-script' | 'ambiguous-shell-build-script' | 'existing-filter-flags' | 'existing-build-docs-script' | 'disabled';
|
|
2
|
+
type RootPackagePatchStatus = 'applied' | 'dry-run' | 'skipped' | 'disabled' | 'already-configured';
|
|
3
|
+
export interface RootPackagePatchResult {
|
|
4
|
+
status: RootPackagePatchStatus;
|
|
5
|
+
reason?: RootPackagePatchReason;
|
|
6
|
+
packageJsonPath: string;
|
|
7
|
+
diff?: string;
|
|
8
|
+
manualSnippet?: string;
|
|
9
|
+
warnings: string[];
|
|
10
|
+
}
|
|
11
|
+
interface RootPackagePatchDependencies {
|
|
12
|
+
readFile: (path: string, encoding: BufferEncoding) => Promise<string>;
|
|
13
|
+
writeFile: (path: string, content: string, encoding: BufferEncoding) => Promise<void>;
|
|
14
|
+
}
|
|
15
|
+
interface RootPackagePatchOptions {
|
|
16
|
+
repoRoot: string;
|
|
17
|
+
appName: string;
|
|
18
|
+
dryRun: boolean;
|
|
19
|
+
enabled: boolean;
|
|
20
|
+
}
|
|
21
|
+
export declare function patchRootPackageJson(options: RootPackagePatchOptions, dependencies?: RootPackagePatchDependencies): Promise<RootPackagePatchResult>;
|
|
22
|
+
export {};
|
|
23
|
+
//# sourceMappingURL=root-package.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"root-package.d.ts","sourceRoot":"","sources":["../../../../src/commands/docs/init/root-package.ts"],"names":[],"mappings":"AAMA,KAAK,sBAAsB,GACvB,sBAAsB,GACtB,iBAAiB,GACjB,wBAAwB,GACxB,8BAA8B,GAC9B,uBAAuB,GACvB,4BAA4B,GAC5B,UAAU,CAAC;AAEf,KAAK,sBAAsB,GACvB,SAAS,GACT,SAAS,GACT,SAAS,GACT,UAAU,GACV,oBAAoB,CAAC;AAMzB,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,sBAAsB,CAAC;IAC/B,MAAM,CAAC,EAAE,sBAAsB,CAAC;IAChC,eAAe,EAAE,MAAM,CAAC;IACxB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,UAAU,4BAA4B;IACpC,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,cAAc,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACtE,SAAS,EAAE,CACT,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,cAAc,KACrB,OAAO,CAAC,IAAI,CAAC,CAAC;CACpB;AAED,UAAU,uBAAuB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;CAClB;AAsKD,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,uBAAuB,EAChC,YAAY,GAAE,4BAAmD,GAChE,OAAO,CAAC,sBAAsB,CAAC,CA8IjC"}
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import { readFile, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
const DEFAULT_BUILD_SCRIPT = 'turbo run build';
|
|
4
|
+
const ROOT_PACKAGE_PATH = 'package.json';
|
|
5
|
+
const DEFAULT_DEPENDENCIES = {
|
|
6
|
+
readFile,
|
|
7
|
+
writeFile,
|
|
8
|
+
};
|
|
9
|
+
function runsTurboBuild(script) {
|
|
10
|
+
return /^turbo\s+(?:run\s+)?build(?:\s+.*)?$/.test(script.trim());
|
|
11
|
+
}
|
|
12
|
+
function hasShellComposition(script) {
|
|
13
|
+
return /&&|\|\||[;|`]|[$][(]/.test(script);
|
|
14
|
+
}
|
|
15
|
+
function removeFilterFlags(script) {
|
|
16
|
+
return script
|
|
17
|
+
.replace(/\s+--filter(?:=|\s+)(?:"[^"]*"|'[^']*'|\S+)/g, '')
|
|
18
|
+
.trim();
|
|
19
|
+
}
|
|
20
|
+
function getFilterFlags(script) {
|
|
21
|
+
return Array.from(script.matchAll(/\s+(--filter(?:=|\s+)(?:"[^"]*"|'[^']*'|\S+))/g), (match) => match[1]);
|
|
22
|
+
}
|
|
23
|
+
function buildExcludeFilter(appName) {
|
|
24
|
+
return `--filter='!${appName}'`;
|
|
25
|
+
}
|
|
26
|
+
function buildIncludeFilter(appName) {
|
|
27
|
+
return `--filter=${appName}...`;
|
|
28
|
+
}
|
|
29
|
+
function buildManualSnippet(appName, baseBuildScript) {
|
|
30
|
+
const buildScript = baseBuildScript?.trim() || DEFAULT_BUILD_SCRIPT;
|
|
31
|
+
return [
|
|
32
|
+
'"scripts": {',
|
|
33
|
+
` "build": "${buildScript} ${buildExcludeFilter(appName)}",`,
|
|
34
|
+
` "build:docs": "${buildScript} ${buildIncludeFilter(appName)}"`,
|
|
35
|
+
'}',
|
|
36
|
+
].join('\n');
|
|
37
|
+
}
|
|
38
|
+
function inferIndentation(content) {
|
|
39
|
+
const match = /\n([ \t]+)"/.exec(content);
|
|
40
|
+
return match?.[1] ?? ' ';
|
|
41
|
+
}
|
|
42
|
+
function formatJsonWithOriginalStyle(original, value) {
|
|
43
|
+
const indentation = inferIndentation(original);
|
|
44
|
+
const trailingNewline = original.endsWith('\n') ? '\n' : '';
|
|
45
|
+
return `${JSON.stringify(value, null, indentation)}${trailingNewline}`;
|
|
46
|
+
}
|
|
47
|
+
function splitLines(content) {
|
|
48
|
+
const trimmed = content.endsWith('\n') ? content.slice(0, -1) : content;
|
|
49
|
+
return trimmed.length > 0 ? trimmed.split('\n') : [];
|
|
50
|
+
}
|
|
51
|
+
function buildDiffOperations(beforeLines, afterLines) {
|
|
52
|
+
const lengths = Array.from({ length: beforeLines.length + 1 }, () => Array(afterLines.length + 1).fill(0));
|
|
53
|
+
for (let beforeIndex = beforeLines.length - 1; beforeIndex >= 0; beforeIndex -= 1) {
|
|
54
|
+
for (let afterIndex = afterLines.length - 1; afterIndex >= 0; afterIndex -= 1) {
|
|
55
|
+
lengths[beforeIndex][afterIndex] =
|
|
56
|
+
beforeLines[beforeIndex] === afterLines[afterIndex]
|
|
57
|
+
? lengths[beforeIndex + 1][afterIndex + 1] + 1
|
|
58
|
+
: Math.max(lengths[beforeIndex + 1][afterIndex], lengths[beforeIndex][afterIndex + 1]);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
const operations = [];
|
|
62
|
+
let beforeIndex = 0;
|
|
63
|
+
let afterIndex = 0;
|
|
64
|
+
while (beforeIndex < beforeLines.length && afterIndex < afterLines.length) {
|
|
65
|
+
if (beforeLines[beforeIndex] === afterLines[afterIndex]) {
|
|
66
|
+
operations.push({ type: 'context', line: beforeLines[beforeIndex] });
|
|
67
|
+
beforeIndex += 1;
|
|
68
|
+
afterIndex += 1;
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
if (lengths[beforeIndex + 1][afterIndex] >=
|
|
72
|
+
lengths[beforeIndex][afterIndex + 1]) {
|
|
73
|
+
operations.push({ type: 'remove', line: beforeLines[beforeIndex] });
|
|
74
|
+
beforeIndex += 1;
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
operations.push({ type: 'add', line: afterLines[afterIndex] });
|
|
78
|
+
afterIndex += 1;
|
|
79
|
+
}
|
|
80
|
+
while (beforeIndex < beforeLines.length) {
|
|
81
|
+
operations.push({ type: 'remove', line: beforeLines[beforeIndex] });
|
|
82
|
+
beforeIndex += 1;
|
|
83
|
+
}
|
|
84
|
+
while (afterIndex < afterLines.length) {
|
|
85
|
+
operations.push({ type: 'add', line: afterLines[afterIndex] });
|
|
86
|
+
afterIndex += 1;
|
|
87
|
+
}
|
|
88
|
+
return operations;
|
|
89
|
+
}
|
|
90
|
+
function createUnifiedDiff(filePath, before, after) {
|
|
91
|
+
if (before === after) {
|
|
92
|
+
return '';
|
|
93
|
+
}
|
|
94
|
+
const beforeLines = splitLines(before);
|
|
95
|
+
const afterLines = splitLines(after);
|
|
96
|
+
const operations = buildDiffOperations(beforeLines, afterLines);
|
|
97
|
+
return [
|
|
98
|
+
`--- ${filePath}`,
|
|
99
|
+
`+++ ${filePath}`,
|
|
100
|
+
`@@ -1,${beforeLines.length} +1,${afterLines.length} @@`,
|
|
101
|
+
...operations.map((operation) => {
|
|
102
|
+
const prefix = operation.type === 'context'
|
|
103
|
+
? ' '
|
|
104
|
+
: operation.type === 'remove'
|
|
105
|
+
? '-'
|
|
106
|
+
: '+';
|
|
107
|
+
return `${prefix}${operation.line}`;
|
|
108
|
+
}),
|
|
109
|
+
].join('\n');
|
|
110
|
+
}
|
|
111
|
+
export async function patchRootPackageJson(options, dependencies = DEFAULT_DEPENDENCIES) {
|
|
112
|
+
const packageJsonPath = join(options.repoRoot, ROOT_PACKAGE_PATH);
|
|
113
|
+
if (!options.enabled) {
|
|
114
|
+
return {
|
|
115
|
+
status: 'disabled',
|
|
116
|
+
reason: 'disabled',
|
|
117
|
+
packageJsonPath,
|
|
118
|
+
warnings: [],
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
let originalContent;
|
|
122
|
+
try {
|
|
123
|
+
originalContent = await dependencies.readFile(packageJsonPath, 'utf8');
|
|
124
|
+
}
|
|
125
|
+
catch {
|
|
126
|
+
return {
|
|
127
|
+
status: 'skipped',
|
|
128
|
+
reason: 'missing-package-json',
|
|
129
|
+
packageJsonPath,
|
|
130
|
+
manualSnippet: buildManualSnippet(options.appName),
|
|
131
|
+
warnings: [
|
|
132
|
+
'Skipped root package.json patch: root package.json was not found.',
|
|
133
|
+
],
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
const parsed = JSON.parse(originalContent);
|
|
137
|
+
const currentScripts = parsed.scripts ?? {};
|
|
138
|
+
const currentBuildScript = currentScripts.build;
|
|
139
|
+
if (!currentBuildScript) {
|
|
140
|
+
return {
|
|
141
|
+
status: 'skipped',
|
|
142
|
+
reason: 'no-build-script',
|
|
143
|
+
packageJsonPath,
|
|
144
|
+
manualSnippet: buildManualSnippet(options.appName),
|
|
145
|
+
warnings: [
|
|
146
|
+
'Skipped root package.json patch: scripts.build is missing, so there was no Turbo build command to update.',
|
|
147
|
+
],
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
if (!runsTurboBuild(currentBuildScript)) {
|
|
151
|
+
return {
|
|
152
|
+
status: 'skipped',
|
|
153
|
+
reason: 'non-turbo-build-script',
|
|
154
|
+
packageJsonPath,
|
|
155
|
+
manualSnippet: buildManualSnippet(options.appName),
|
|
156
|
+
warnings: [
|
|
157
|
+
'Skipped root package.json patch: scripts.build does not run a Turbo build command, so OAT left it unchanged.',
|
|
158
|
+
],
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
if (hasShellComposition(currentBuildScript)) {
|
|
162
|
+
return {
|
|
163
|
+
status: 'skipped',
|
|
164
|
+
reason: 'ambiguous-shell-build-script',
|
|
165
|
+
packageJsonPath,
|
|
166
|
+
manualSnippet: buildManualSnippet(options.appName),
|
|
167
|
+
warnings: [
|
|
168
|
+
'Skipped root package.json patch: scripts.build wraps the Turbo build in a larger shell expression, so OAT left it unchanged rather than rewriting the full command.',
|
|
169
|
+
],
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
const excludeFilter = buildExcludeFilter(options.appName);
|
|
173
|
+
const filterFlags = getFilterFlags(currentBuildScript);
|
|
174
|
+
const hasUserAuthoredFilters = filterFlags.some((flag) => flag !== excludeFilter);
|
|
175
|
+
if (hasUserAuthoredFilters) {
|
|
176
|
+
return {
|
|
177
|
+
status: 'skipped',
|
|
178
|
+
reason: 'existing-filter-flags',
|
|
179
|
+
packageJsonPath,
|
|
180
|
+
manualSnippet: buildManualSnippet(options.appName, removeFilterFlags(currentBuildScript)),
|
|
181
|
+
warnings: [
|
|
182
|
+
'Skipped root package.json patch: scripts.build already uses `--filter`, so OAT left it unchanged rather than guessing how to merge filter semantics.',
|
|
183
|
+
],
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
const nextScripts = { ...currentScripts };
|
|
187
|
+
const nextBuildScript = currentBuildScript.includes(excludeFilter)
|
|
188
|
+
? currentBuildScript
|
|
189
|
+
: `${currentBuildScript.trim()} ${excludeFilter}`;
|
|
190
|
+
nextScripts.build = nextBuildScript;
|
|
191
|
+
const baseBuildScript = removeFilterFlags(currentBuildScript);
|
|
192
|
+
const desiredBuildDocsScript = `${baseBuildScript} ${buildIncludeFilter(options.appName)}`;
|
|
193
|
+
const warnings = [];
|
|
194
|
+
if (nextScripts['build:docs'] &&
|
|
195
|
+
nextScripts['build:docs'] !== desiredBuildDocsScript) {
|
|
196
|
+
warnings.push('Left scripts["build:docs"] unchanged because the root package already defines a different value.');
|
|
197
|
+
}
|
|
198
|
+
else {
|
|
199
|
+
nextScripts['build:docs'] = desiredBuildDocsScript;
|
|
200
|
+
}
|
|
201
|
+
const nextContent = formatJsonWithOriginalStyle(originalContent, {
|
|
202
|
+
...parsed,
|
|
203
|
+
scripts: nextScripts,
|
|
204
|
+
});
|
|
205
|
+
const diff = createUnifiedDiff(ROOT_PACKAGE_PATH, originalContent, nextContent);
|
|
206
|
+
if (!diff) {
|
|
207
|
+
return {
|
|
208
|
+
status: 'already-configured',
|
|
209
|
+
packageJsonPath,
|
|
210
|
+
warnings,
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
if (!options.dryRun) {
|
|
214
|
+
await dependencies.writeFile(packageJsonPath, nextContent, 'utf8');
|
|
215
|
+
}
|
|
216
|
+
return {
|
|
217
|
+
status: options.dryRun ? 'dry-run' : 'applied',
|
|
218
|
+
reason: warnings.length > 0 ? 'existing-build-docs-script' : undefined,
|
|
219
|
+
packageJsonPath,
|
|
220
|
+
diff,
|
|
221
|
+
manualSnippet: warnings.length > 0
|
|
222
|
+
? buildManualSnippet(options.appName, baseBuildScript)
|
|
223
|
+
: undefined,
|
|
224
|
+
warnings,
|
|
225
|
+
};
|
|
226
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/status/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,MAAM,sBAAsB,CAAC;AAK9B,OAAO,EACL,KAAK,cAAc,EAGpB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAEL,KAAK,iBAAiB,EACtB,KAAK,aAAa,EAEnB,MAAM,iCAAiC,CAAC;AAKzC,OAAO,EACL,KAAK,aAAa,EAClB,KAAK,WAAW,EAGjB,MAAM,cAAc,CAAC;AACtB,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/status/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,MAAM,sBAAsB,CAAC;AAK9B,OAAO,EACL,KAAK,cAAc,EAGpB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAEL,KAAK,iBAAiB,EACtB,KAAK,aAAa,EAEnB,MAAM,iCAAiC,CAAC;AAKzC,OAAO,EACL,KAAK,aAAa,EAClB,KAAK,WAAW,EAGjB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,KAAK,cAAc,EAIpB,MAAM,eAAe,CAAC;AAMvB,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAIhD,OAAO,EAEL,KAAK,kBAAkB,EAExB,MAAM,uCAAuC,CAAC;AAI/C,OAAO,EAGL,KAAK,WAAW,EAChB,KAAK,eAAe,EACrB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,KAAK,aAAa,EAGlB,KAAK,KAAK,EACX,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAmBpC,UAAU,kBAAkB;IAC1B,mBAAmB,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,cAAc,CAAC;IAChE,gBAAgB,EAAE,CAChB,KAAK,EAAE,aAAa,EACpB,OAAO,EAAE,cAAc,KACpB,OAAO,CAAC,MAAM,CAAC,CAAC;IACrB,YAAY,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC1D,YAAY,EAAE,CAAC,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1E,aAAa,EAAE,CACb,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,aAAa,KACjB,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC;IAC/B,WAAW,EAAE,MAAM,eAAe,EAAE,CAAC;IACrC,iBAAiB,EAAE,CACjB,QAAQ,EAAE,eAAe,EAAE,EAC3B,SAAS,EAAE,MAAM,KACd,OAAO,CAAC,eAAe,EAAE,CAAC,CAAC;IAChC,eAAe,EAAE,CAAC,OAAO,EAAE,eAAe,EAAE,KAAK,EAAE,KAAK,KAAK,WAAW,EAAE,CAAC;IAC3E,WAAW,EAAE,CACX,KAAK,EAAE,QAAQ,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,EAClC,SAAS,EAAE,MAAM,EACjB,aAAa,CAAC,EAAE,aAAa,KAC1B,OAAO,CAAC,WAAW,CAAC,CAAC;IAC1B,YAAY,EAAE,CACZ,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,QAAQ,EAClB,gBAAgB,EAAE,cAAc,EAAE,EAClC,OAAO,CAAC,EAAE,IAAI,CAAC,WAAW,EAAE,aAAa,GAAG,mBAAmB,CAAC,KAC7D,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;IAC5B,qBAAqB,EAAE,CACrB,SAAS,EAAE,MAAM,EACjB,gBAAgB,EAAE,cAAc,EAAE,KAC/B,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC;IAC/B,gCAAgC,EAAE,CAChC,SAAS,EAAE,MAAM,EACjB,gBAAgB,EAAE,cAAc,EAAE,KAC/B,OAAO,CAAC,kBAAkB,CAAC,CAAC;IACjC,8BAA8B,EAAE,CAC9B,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,kBAAkB,KACrB,OAAO,CAAC,OAAO,CAAC,CAAC;IACtB,mBAAmB,EAAE,CAAC,CAAC,SAAS,MAAM,EACpC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,iBAAiB,CAAC,CAAC,CAAC,EAAE,EAC/B,GAAG,EAAE,aAAa,KACf,OAAO,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC;IACzB,aAAa,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,aAAa,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACzE,UAAU,EAAE,CACV,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,oBAAoB,EAC3B,QAAQ,EAAE,QAAQ,EAClB,OAAO,CAAC,EAAE;QAAE,gBAAgB,CAAC,EAAE,OAAO,CAAA;KAAE,KACrC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACvB,iBAAiB,EAAE,CAAC,OAAO,EAAE,WAAW,EAAE,KAAK,MAAM,CAAC;CACvD;AAED,UAAU,oBAAoB;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,WAAW,CAAC;IACpB,OAAO,EAAE,WAAW,CAAC;IACrB,QAAQ,CAAC,EAAE;QACT,IAAI,EAAE,YAAY,CAAC;QACnB,QAAQ,EAAE,MAAM,CAAC;QACjB,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC;CACH;AA+eD,wBAAgB,mBAAmB,CACjC,SAAS,GAAE,OAAO,CAAC,kBAAkB,CAAM,GAC1C,OAAO,CAoBT"}
|
|
@@ -5,7 +5,7 @@ import { detectCodexRoleStrays, regenerateCodexAfterAdoption, } from '../shared/
|
|
|
5
5
|
import { confirmAction, selectManyWithAbort, } from '../shared/shared.prompts.js';
|
|
6
6
|
import { readGlobalOptions, resolveConcreteScopes, } from '../shared/shared.utils.js';
|
|
7
7
|
import { detectDrift, detectStrays, } from '../../drift/index.js';
|
|
8
|
-
import { scanCanonical } from '../../engine/index.js';
|
|
8
|
+
import { HOOK_DRIFT_WARNING, HOOK_STRAY_INFO, scanCanonical, } from '../../engine/index.js';
|
|
9
9
|
import { normalizeToPosixPath, resolveProjectRoot, resolveScopeRoot, } from '../../fs/paths.js';
|
|
10
10
|
import { loadManifest, saveManifest } from '../../manifest/manager.js';
|
|
11
11
|
import { claudeAdapter } from '../../providers/claude/index.js';
|
|
@@ -242,7 +242,7 @@ async function collectScopeReports(scope, context, dependencies) {
|
|
|
242
242
|
strayCandidates,
|
|
243
243
|
};
|
|
244
244
|
}
|
|
245
|
-
async function runStatusCommand(context, dependencies) {
|
|
245
|
+
async function runStatusCommand(context, dependencies, options = {}) {
|
|
246
246
|
const reports = [];
|
|
247
247
|
const scopeCollections = [];
|
|
248
248
|
for (const scope of resolveConcreteScopes(context.scope)) {
|
|
@@ -252,6 +252,20 @@ async function runStatusCommand(context, dependencies) {
|
|
|
252
252
|
}
|
|
253
253
|
const summary = summarizeReports(reports);
|
|
254
254
|
const hasIssues = summary.total > 0 && summary.inSync !== summary.total;
|
|
255
|
+
if (options.hook) {
|
|
256
|
+
if (summary.drifted > 0 || summary.missing > 0) {
|
|
257
|
+
context.logger.warn(HOOK_DRIFT_WARNING);
|
|
258
|
+
process.exitCode = 1;
|
|
259
|
+
}
|
|
260
|
+
else if (summary.stray > 0) {
|
|
261
|
+
context.logger.info(HOOK_STRAY_INFO);
|
|
262
|
+
process.exitCode = 0;
|
|
263
|
+
}
|
|
264
|
+
else {
|
|
265
|
+
process.exitCode = 0;
|
|
266
|
+
}
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
255
269
|
if (context.json) {
|
|
256
270
|
const payload = {
|
|
257
271
|
scope: context.scope,
|
|
@@ -338,8 +352,11 @@ export function createStatusCommand(overrides = {}) {
|
|
|
338
352
|
};
|
|
339
353
|
return new Command('status')
|
|
340
354
|
.description('Report provider sync and drift status')
|
|
341
|
-
.
|
|
355
|
+
.option('--hook', 'Emit a minimal pre-commit message: warn on managed drift, info on strays')
|
|
356
|
+
.action(async (options, command) => {
|
|
342
357
|
const context = dependencies.buildCommandContext(readGlobalOptions(command));
|
|
343
|
-
await runStatusCommand(context, dependencies
|
|
358
|
+
await runStatusCommand(context, dependencies, {
|
|
359
|
+
hook: Boolean(options.hook),
|
|
360
|
+
});
|
|
344
361
|
});
|
|
345
362
|
}
|
package/dist/engine/hook.d.ts
CHANGED
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
export declare const HOOK_MARKER_START = "# >>> oat pre-commit hook >>>";
|
|
2
2
|
export declare const HOOK_MARKER_END = "# <<< oat pre-commit hook <<<";
|
|
3
|
-
export declare const HOOK_DRIFT_WARNING = "oat:
|
|
3
|
+
export declare const HOOK_DRIFT_WARNING = "oat: managed provider views are out of sync - run 'oat sync --scope project'";
|
|
4
|
+
export declare const HOOK_STRAY_INFO = "oat: unmanaged provider files detected - run 'oat status --scope project' to review";
|
|
4
5
|
export declare const REPO_GITHOOKS_PATH = ".githooks";
|
|
6
|
+
export type HookStatus = 'in_sync' | 'managed_drift' | 'stray_only';
|
|
5
7
|
export interface HookInstallInfo {
|
|
6
8
|
hookPath: string;
|
|
7
9
|
suggestedHooksPath: string | null;
|
|
8
10
|
suggestedHookPath: string | null;
|
|
9
11
|
}
|
|
10
12
|
interface RunHookCheckOptions {
|
|
11
|
-
runStatusCommand?: (cwd: string) => Promise<
|
|
13
|
+
runStatusCommand?: (cwd: string) => Promise<HookStatus>;
|
|
12
14
|
warn?: (message: string) => void;
|
|
15
|
+
info?: (message: string) => void;
|
|
13
16
|
}
|
|
14
17
|
export declare function getHookInstallInfo(projectRoot: string): Promise<HookInstallInfo>;
|
|
15
18
|
export declare function configureLocalHooksPath(projectRoot: string, hooksPath: string): Promise<void>;
|
|
@@ -17,7 +20,7 @@ export declare function isHookInstalled(projectRoot: string): Promise<boolean>;
|
|
|
17
20
|
export declare function installHook(projectRoot: string): Promise<string>;
|
|
18
21
|
export declare function uninstallHook(projectRoot: string): Promise<void>;
|
|
19
22
|
export declare function runHookCheck(cwd: string, options?: RunHookCheckOptions): Promise<{
|
|
20
|
-
|
|
23
|
+
status: HookStatus;
|
|
21
24
|
}>;
|
|
22
25
|
export {};
|
|
23
26
|
//# sourceMappingURL=hook.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hook.d.ts","sourceRoot":"","sources":["../../src/engine/hook.ts"],"names":[],"mappings":"AAgBA,eAAO,MAAM,iBAAiB,kCAAkC,CAAC;AACjE,eAAO,MAAM,eAAe,kCAAkC,CAAC;AAC/D,eAAO,MAAM,kBAAkB,
|
|
1
|
+
{"version":3,"file":"hook.d.ts","sourceRoot":"","sources":["../../src/engine/hook.ts"],"names":[],"mappings":"AAgBA,eAAO,MAAM,iBAAiB,kCAAkC,CAAC;AACjE,eAAO,MAAM,eAAe,kCAAkC,CAAC;AAC/D,eAAO,MAAM,kBAAkB,iFACiD,CAAC;AACjF,eAAO,MAAM,eAAe,wFAC2D,CAAC;AACxF,eAAO,MAAM,kBAAkB,cAAc,CAAC;AAE9C,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,eAAe,GAAG,YAAY,CAAC;AAEpE,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;CAClC;AAED,UAAU,mBAAmB;IAC3B,gBAAgB,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;IACxD,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CAClC;AAsHD,wBAAsB,kBAAkB,CACtC,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,eAAe,CAAC,CA4B1B;AAED,wBAAsB,uBAAuB,CAC3C,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CAQf;AAED,wBAAsB,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAgB3E;AAED,wBAAsB,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAgCtE;AAuBD,wBAAsB,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAoCtE;AA8BD,wBAAsB,YAAY,CAChC,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,mBAAwB,GAChC,OAAO,CAAC;IAAE,MAAM,EAAE,UAAU,CAAA;CAAE,CAAC,CA2BjC"}
|
package/dist/engine/hook.js
CHANGED
|
@@ -6,7 +6,8 @@ import { ensureDir } from '../fs/io.js';
|
|
|
6
6
|
const execFileAsync = promisify(execFile);
|
|
7
7
|
export const HOOK_MARKER_START = '# >>> oat pre-commit hook >>>';
|
|
8
8
|
export const HOOK_MARKER_END = '# <<< oat pre-commit hook <<<';
|
|
9
|
-
export const HOOK_DRIFT_WARNING = "oat:
|
|
9
|
+
export const HOOK_DRIFT_WARNING = "oat: managed provider views are out of sync - run 'oat sync --scope project'";
|
|
10
|
+
export const HOOK_STRAY_INFO = "oat: unmanaged provider files detected - run 'oat status --scope project' to review";
|
|
10
11
|
export const REPO_GITHOOKS_PATH = '.githooks';
|
|
11
12
|
function escapeRegExp(value) {
|
|
12
13
|
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
@@ -15,9 +16,7 @@ function createHookSnippet(options = {}) {
|
|
|
15
16
|
const lines = [
|
|
16
17
|
HOOK_MARKER_START,
|
|
17
18
|
'if command -v oat >/dev/null 2>&1; then',
|
|
18
|
-
'
|
|
19
|
-
` echo "${HOOK_DRIFT_WARNING}" >&2`,
|
|
20
|
-
' fi',
|
|
19
|
+
' oat status --scope project --hook || true',
|
|
21
20
|
'fi',
|
|
22
21
|
HOOK_MARKER_END,
|
|
23
22
|
];
|
|
@@ -225,11 +224,24 @@ export async function uninstallHook(projectRoot) {
|
|
|
225
224
|
}
|
|
226
225
|
async function runStatusCommandDefault(cwd) {
|
|
227
226
|
try {
|
|
228
|
-
await execFileAsync('oat', ['status', '--scope', 'project'], { cwd });
|
|
229
|
-
|
|
227
|
+
const { stdout } = await execFileAsync('oat', ['status', '--scope', 'project', '--json'], { cwd });
|
|
228
|
+
const payload = JSON.parse(stdout);
|
|
229
|
+
const summary = payload.summary ?? {};
|
|
230
|
+
const drifted = summary.drifted ?? 0;
|
|
231
|
+
const missing = summary.missing ?? 0;
|
|
232
|
+
const stray = summary.stray ?? 0;
|
|
233
|
+
if (drifted + missing > 0) {
|
|
234
|
+
return 'managed_drift';
|
|
235
|
+
}
|
|
236
|
+
if (stray > 0) {
|
|
237
|
+
return 'stray_only';
|
|
238
|
+
}
|
|
239
|
+
return 'in_sync';
|
|
230
240
|
}
|
|
231
241
|
catch {
|
|
232
|
-
|
|
242
|
+
// On any failure (oat missing, JSON parse error, unexpected exit), fall
|
|
243
|
+
// back to treating the state as managed drift so the operator notices.
|
|
244
|
+
return 'managed_drift';
|
|
233
245
|
}
|
|
234
246
|
}
|
|
235
247
|
export async function runHookCheck(cwd, options = {}) {
|
|
@@ -238,17 +250,22 @@ export async function runHookCheck(cwd, options = {}) {
|
|
|
238
250
|
((message) => {
|
|
239
251
|
process.stderr.write(`${message}\n`);
|
|
240
252
|
});
|
|
241
|
-
|
|
253
|
+
const info = options.info ??
|
|
254
|
+
((message) => {
|
|
255
|
+
process.stderr.write(`${message}\n`);
|
|
256
|
+
});
|
|
257
|
+
let status;
|
|
242
258
|
try {
|
|
243
|
-
|
|
244
|
-
// protects custom injected implementations from escaping exceptions.
|
|
245
|
-
inSync = await runStatusCommand(cwd);
|
|
259
|
+
status = await runStatusCommand(cwd);
|
|
246
260
|
}
|
|
247
261
|
catch {
|
|
248
|
-
|
|
262
|
+
status = 'managed_drift';
|
|
249
263
|
}
|
|
250
|
-
if (
|
|
264
|
+
if (status === 'managed_drift') {
|
|
251
265
|
warn(HOOK_DRIFT_WARNING);
|
|
252
266
|
}
|
|
253
|
-
|
|
267
|
+
else if (status === 'stray_only') {
|
|
268
|
+
info(HOOK_STRAY_INFO);
|
|
269
|
+
}
|
|
270
|
+
return { status };
|
|
254
271
|
}
|
package/dist/engine/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
export { computeSyncPlan } from './compute-plan.js';
|
|
2
2
|
export { type EngineScope, type RemovalSyncPlanEntry, SYNC_OPERATION_TYPES, type SyncOperationType, type SyncPlan, type SyncPlanEntry, type SyncResult, } from './engine.types.js';
|
|
3
3
|
export { executeSyncPlan } from './execute-plan.js';
|
|
4
|
-
export { configureLocalHooksPath, getHookInstallInfo, HOOK_DRIFT_WARNING, HOOK_MARKER_END, HOOK_MARKER_START, installHook, isHookInstalled, REPO_GITHOOKS_PATH, runHookCheck, uninstallHook, } from './hook.js';
|
|
5
|
-
export type { HookInstallInfo } from './hook.js';
|
|
4
|
+
export { configureLocalHooksPath, getHookInstallInfo, HOOK_DRIFT_WARNING, HOOK_MARKER_END, HOOK_MARKER_START, HOOK_STRAY_INFO, installHook, isHookInstalled, REPO_GITHOOKS_PATH, runHookCheck, uninstallHook, } from './hook.js';
|
|
5
|
+
export type { HookInstallInfo, HookStatus } from './hook.js';
|
|
6
6
|
export { hasMarker, insertMarker, OAT_DIRECTORY_SENTINEL, OAT_MARKER_PREFIX, writeDirectorySentinel, } from './markers.js';
|
|
7
7
|
export type { CanonicalEntry } from './scanner.js';
|
|
8
8
|
export { scanCanonical } from './scanner.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/engine/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,oBAAoB,EACzB,oBAAoB,EACpB,KAAK,iBAAiB,EACtB,KAAK,QAAQ,EACb,KAAK,aAAa,EAClB,KAAK,UAAU,GAChB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EACL,uBAAuB,EACvB,kBAAkB,EAClB,kBAAkB,EAClB,eAAe,EACf,iBAAiB,EACjB,WAAW,EACX,eAAe,EACf,kBAAkB,EAClB,YAAY,EACZ,aAAa,GACd,MAAM,QAAQ,CAAC;AAChB,YAAY,EAAE,eAAe,EAAE,MAAM,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/engine/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,oBAAoB,EACzB,oBAAoB,EACpB,KAAK,iBAAiB,EACtB,KAAK,QAAQ,EACb,KAAK,aAAa,EAClB,KAAK,UAAU,GAChB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EACL,uBAAuB,EACvB,kBAAkB,EAClB,kBAAkB,EAClB,eAAe,EACf,iBAAiB,EACjB,eAAe,EACf,WAAW,EACX,eAAe,EACf,kBAAkB,EAClB,YAAY,EACZ,aAAa,GACd,MAAM,QAAQ,CAAC;AAChB,YAAY,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAC1D,OAAO,EACL,SAAS,EACT,YAAY,EACZ,sBAAsB,EACtB,iBAAiB,EACjB,sBAAsB,GACvB,MAAM,WAAW,CAAC;AACnB,YAAY,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC"}
|
package/dist/engine/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { computeSyncPlan } from './compute-plan.js';
|
|
2
2
|
export { SYNC_OPERATION_TYPES, } from './engine.types.js';
|
|
3
3
|
export { executeSyncPlan } from './execute-plan.js';
|
|
4
|
-
export { configureLocalHooksPath, getHookInstallInfo, HOOK_DRIFT_WARNING, HOOK_MARKER_END, HOOK_MARKER_START, installHook, isHookInstalled, REPO_GITHOOKS_PATH, runHookCheck, uninstallHook, } from './hook.js';
|
|
4
|
+
export { configureLocalHooksPath, getHookInstallInfo, HOOK_DRIFT_WARNING, HOOK_MARKER_END, HOOK_MARKER_START, HOOK_STRAY_INFO, installHook, isHookInstalled, REPO_GITHOOKS_PATH, runHookCheck, uninstallHook, } from './hook.js';
|
|
5
5
|
export { hasMarker, insertMarker, OAT_DIRECTORY_SENTINEL, OAT_MARKER_PREFIX, writeDirectorySentinel, } from './markers.js';
|
|
6
6
|
export { scanCanonical } from './scanner.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@open-agent-toolkit/cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.43",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Open Agent Toolkit CLI",
|
|
6
6
|
"homepage": "https://github.com/voxmedia/open-agent-toolkit/tree/main/packages/cli",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"ora": "^9.0.0",
|
|
34
34
|
"yaml": "2.8.2",
|
|
35
35
|
"zod": "^3.25.76",
|
|
36
|
-
"@open-agent-toolkit/control-plane": "0.0.
|
|
36
|
+
"@open-agent-toolkit/control-plane": "0.0.43"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
39
|
"@types/node": "^22.10.0",
|