@open-agent-toolkit/cli 0.0.42 → 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.
@@ -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** — five 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`, missing "do not hand-edit" header on generated `index.md`, Node version line that doesn't match the consuming repo's `.nvmrc` / `engines.node`)
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
- "cli": "0.0.42",
3
- "docs-config": "0.0.42",
4
- "docs-theme": "0.0.42",
5
- "docs-transforms": "0.0.42"
2
+ "cli": "0.0.43",
3
+ "docs-config": "0.0.43",
4
+ "docs-theme": "0.0.43",
5
+ "docs-transforms": "0.0.43"
6
6
  }
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: oat-docs-bootstrap
3
- version: 1.0.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
- <!-- generated by oat docs generate-index; do not hand-edit. Source: docs/index.md -->
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 if Scaffold-integrity FP-13/D.2 patched it, the first line is a `<!-- generated -->` banner confirming so.
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.0
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
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.0
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
- - If user chooses option 3: stop and suggest `oat-worktree-bootstrap-auto`.
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.0
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;AAS5C,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;AAwED,wBAAgB,8BAA8B,CAC5C,SAAS,GAAE,OAAO,CAAC,yBAAyB,CAAM,GACjD,OAAO,CAsBT"}
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;AAa3B,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;AAiDD,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,uBAAuB,GAAG,MAAM,CAc7E;AA8GD,wBAAgB,qBAAqB,CACnC,SAAS,GAAE,OAAO,CAAC,oBAAoB,CAAM,GAC5C,OAAO,CAsCT"}
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;CACxB;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,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,CA+EzC;AAED,eAAO,MAAM,oCAAoC,EAAE,yBAOlD,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"}
@@ -109,6 +109,7 @@ export async function resolveDocsInitOptions(input) {
109
109
  siteDescription,
110
110
  lint,
111
111
  format,
112
+ rootPatch: input.providedRootPatch ?? true,
112
113
  };
113
114
  }
114
115
  export const DEFAULT_DOCS_REPO_SHAPE_DEPENDENCIES = {
@@ -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
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open-agent-toolkit/cli",
3
- "version": "0.0.42",
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.42"
36
+ "@open-agent-toolkit/control-plane": "0.0.43"
37
37
  },
38
38
  "devDependencies": {
39
39
  "@types/node": "^22.10.0",