@open-agent-toolkit/cli 0.2.64 → 0.2.65
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/bundle-metadata.json +1 -1
- package/assets/docs/contributing/skills.md +15 -5
- package/assets/public-package-versions.json +4 -4
- package/assets/skills/analyze/SKILL.md +2 -1
- package/assets/skills/authoring-docs/SKILL.md +2 -1
- package/assets/skills/compare/SKILL.md +2 -1
- package/assets/skills/create-agnostic-skill/SKILL.md +2 -1
- package/assets/skills/deep-research/SKILL.md +2 -1
- package/assets/skills/explainer-kit/SKILL.md +2 -1
- package/assets/skills/oat-agent-instructions-analyze/SKILL.md +2 -1
- package/assets/skills/oat-agent-instructions-apply/SKILL.md +2 -1
- package/assets/skills/oat-brainstorm/SKILL.md +2 -1
- package/assets/skills/oat-cursor-cloud-projects/SKILL.md +2 -1
- package/assets/skills/oat-dispatch-subagents/SKILL.md +2 -1
- package/assets/skills/oat-docs/SKILL.md +2 -1
- package/assets/skills/oat-docs-analyze/SKILL.md +2 -1
- package/assets/skills/oat-docs-apply/SKILL.md +2 -1
- package/assets/skills/oat-docs-authoring/SKILL.md +2 -1
- package/assets/skills/oat-docs-bootstrap/SKILL.md +2 -1
- package/assets/skills/oat-doctor/SKILL.md +2 -1
- package/assets/skills/oat-explainer-kit/SKILL.md +2 -1
- package/assets/skills/oat-explainer-kit/scripts/check-core.mjs +322 -2
- package/assets/skills/oat-idea-ideate/SKILL.md +2 -1
- package/assets/skills/oat-idea-new/SKILL.md +2 -1
- package/assets/skills/oat-idea-scratchpad/SKILL.md +2 -1
- package/assets/skills/oat-idea-summarize/SKILL.md +2 -1
- package/assets/skills/oat-pjm-add-backlog-item/SKILL.md +2 -1
- package/assets/skills/oat-pjm-decision/SKILL.md +2 -1
- package/assets/skills/oat-pjm-review-backlog/SKILL.md +2 -1
- package/assets/skills/oat-pjm-update-repo-reference/SKILL.md +2 -1
- package/assets/skills/oat-project-autonomous/SKILL.md +2 -1
- package/assets/skills/oat-project-capture/SKILL.md +2 -1
- package/assets/skills/oat-project-clear-active/SKILL.md +2 -1
- package/assets/skills/oat-project-complete/SKILL.md +2 -1
- package/assets/skills/oat-project-design/SKILL.md +2 -1
- package/assets/skills/oat-project-discover/SKILL.md +2 -1
- package/assets/skills/oat-project-dispatch-subagents/SKILL.md +2 -1
- package/assets/skills/oat-project-document/SKILL.md +2 -1
- package/assets/skills/oat-project-implement/SKILL.md +2 -1
- package/assets/skills/oat-project-import-plan/SKILL.md +2 -1
- package/assets/skills/oat-project-lite/SKILL.md +2 -1
- package/assets/skills/oat-project-new/SKILL.md +2 -1
- package/assets/skills/oat-project-next/SKILL.md +2 -1
- package/assets/skills/oat-project-open/SKILL.md +2 -1
- package/assets/skills/oat-project-plan/SKILL.md +2 -1
- package/assets/skills/oat-project-plan-writing/SKILL.md +2 -1
- package/assets/skills/oat-project-pr-final/SKILL.md +2 -1
- package/assets/skills/oat-project-pr-progress/SKILL.md +2 -1
- package/assets/skills/oat-project-progress/SKILL.md +2 -1
- package/assets/skills/oat-project-promote-spec-driven/SKILL.md +2 -1
- package/assets/skills/oat-project-quick-start/SKILL.md +2 -1
- package/assets/skills/oat-project-reconcile/SKILL.md +2 -1
- package/assets/skills/oat-project-retro/SKILL.md +2 -1
- package/assets/skills/oat-project-retro-file/SKILL.md +2 -1
- package/assets/skills/oat-project-review-provide/SKILL.md +2 -1
- package/assets/skills/oat-project-review-provide-remote/SKILL.md +2 -1
- package/assets/skills/oat-project-review-receive/SKILL.md +2 -1
- package/assets/skills/oat-project-review-receive-remote/SKILL.md +2 -1
- package/assets/skills/oat-project-revise/SKILL.md +2 -1
- package/assets/skills/oat-project-spec/SKILL.md +2 -1
- package/assets/skills/oat-project-split/SKILL.md +2 -1
- package/assets/skills/oat-project-summary/SKILL.md +2 -1
- package/assets/skills/oat-repo-improve/SKILL.md +1 -1
- package/assets/skills/oat-repo-knowledge-index/SKILL.md +2 -1
- package/assets/skills/oat-repo-maintainability-review/SKILL.md +2 -1
- package/assets/skills/oat-review-provide/SKILL.md +2 -1
- package/assets/skills/oat-review-provide-remote/SKILL.md +2 -1
- package/assets/skills/oat-review-receive/SKILL.md +2 -1
- package/assets/skills/oat-review-receive-remote/SKILL.md +2 -1
- package/assets/skills/oat-wave-execute/SKILL.md +2 -1
- package/assets/skills/oat-wave-program/SKILL.md +2 -1
- package/assets/skills/oat-worktree-bootstrap/SKILL.md +2 -1
- package/assets/skills/oat-worktree-bootstrap-auto/SKILL.md +2 -1
- package/assets/skills/oat-wrap-up/SKILL.md +2 -1
- package/assets/skills/recon/SKILL.md +2 -1
- package/assets/skills/skeptic/SKILL.md +2 -1
- package/assets/skills/subagent-orchestration/SKILL.md +2 -1
- package/assets/skills/synthesize/SKILL.md +2 -1
- package/package.json +2 -2
|
@@ -204,9 +204,14 @@ resolution. `resolveSkillVersion` in
|
|
|
204
204
|
runtime helper and the validators cannot disagree.
|
|
205
205
|
|
|
206
206
|
The top-level `version` field remains supported as a deprecated alias. Every
|
|
207
|
-
bundled skill
|
|
208
|
-
|
|
209
|
-
|
|
207
|
+
bundled skill now declares `metadata.version` and carries no top-level
|
|
208
|
+
`version`, so `pnpm oat:validate-skills` reports no alias warnings on the
|
|
209
|
+
bundled tree. The alias is retained for third-party skills installed from
|
|
210
|
+
packs, which may still carry it; it retires on the schedule recorded in
|
|
211
|
+
`DR-260908-bundled-skills-declare` — the warning becomes an error in the first
|
|
212
|
+
release after 0.2.65 that changes the validator, and the resolver's top-level
|
|
213
|
+
read is removed one release after that error has produced no findings on the
|
|
214
|
+
bundled tree.
|
|
210
215
|
|
|
211
216
|
A skill that carries both fields with different values is a conflict. The
|
|
212
217
|
resolver reports the `metadata.version` value together with the conflict, and
|
|
@@ -214,7 +219,12 @@ the callers that must not guess act on it: validation reports an error rather
|
|
|
214
219
|
than silently picking one, and canonical role resolution treats the identity as
|
|
215
220
|
invalid. The runtime version readers still return the `metadata.version` value,
|
|
216
221
|
so an installed-versus-bundled comparison keeps working while the conflict is
|
|
217
|
-
being fixed. Carrying both with the _same_ value
|
|
222
|
+
being fixed. Carrying both with the _same_ value resolves without a conflict and
|
|
223
|
+
without an alias warning, because `metadata.version` wins. A bundled skill must
|
|
224
|
+
still carry `metadata.version` alone: the corpus sweep in
|
|
225
|
+
`packages/cli/src/validation/skills.test.ts` fails on any column-0 `version:`
|
|
226
|
+
line under `.agents/skills`, which is the only check that catches the
|
|
227
|
+
same-value case.
|
|
218
228
|
|
|
219
229
|
### The version is gated
|
|
220
230
|
|
|
@@ -227,7 +237,7 @@ resolved version, so it enforces the bump whether the skill declares
|
|
|
227
237
|
of Done) and in CI; a changed skill whose version matches `origin/main` fails
|
|
228
238
|
the gate. The deprecation warning above is deliberately not part of that gate:
|
|
229
239
|
`check:skill-bumps` fails on any finding it receives, so an alias warning
|
|
230
|
-
routed through it would fail every changed skill
|
|
240
|
+
routed through it would fail every changed skill that still carried one.
|
|
231
241
|
|
|
232
242
|
## Practical Authoring Flow
|
|
233
243
|
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: analyze
|
|
3
|
-
version: 0.2.0
|
|
4
3
|
description: Multi-angle analysis of existing artifacts, codebases, documents, or systems. Examines what you have from six analysis angles and produces structured findings with prioritized recommendations.
|
|
5
4
|
argument-hint: 'target [--context path]'
|
|
6
5
|
user-invocable: true
|
|
7
6
|
allowed-tools: Read, Glob, Grep, Bash, WebSearch, WebFetch, AskUserQuestion, Agent, mcp__*
|
|
7
|
+
metadata:
|
|
8
|
+
version: 0.2.1
|
|
8
9
|
---
|
|
9
10
|
|
|
10
11
|
# /analyze
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: authoring-docs
|
|
3
|
-
version: 1.0.0
|
|
4
3
|
description: Use when creating, restructuring, migrating, auditing, or reviewing technical documentation for software projects. Provides evidence-first, provider-portable Markdown authoring standards.
|
|
5
4
|
argument-hint: '[docs task or target path]'
|
|
6
5
|
disable-model-invocation: false
|
|
7
6
|
allowed-tools: Read, Write, Bash, Glob, Grep, AskUserQuestion
|
|
8
7
|
user-invocable: true
|
|
8
|
+
metadata:
|
|
9
|
+
version: 1.0.1
|
|
9
10
|
---
|
|
10
11
|
|
|
11
12
|
# Authoring Docs
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: compare
|
|
3
|
-
version: 0.1.1
|
|
4
3
|
description: Domain-aware comparative analysis with clear recommendations. Compares options across auto-detected or user-specified dimensions and produces a qualitative assessment with a clear winner.
|
|
5
4
|
argument-hint: 'item1 item2 [item3...] [--save] [--context path] [--dimensions "dim1, dim2, ..."]'
|
|
6
5
|
user-invocable: true
|
|
7
6
|
allowed-tools: Read, Glob, Grep, Bash, WebSearch, WebFetch, AskUserQuestion, Agent, mcp__*
|
|
7
|
+
metadata:
|
|
8
|
+
version: 0.1.2
|
|
8
9
|
---
|
|
9
10
|
|
|
10
11
|
# /compare
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: create-agnostic-skill
|
|
3
|
-
version: 1.4.2
|
|
4
3
|
description: Use when adding a reusable workflow skill for AI coding agents. Scaffolds a new .agents/skills skill using the Agent Skills open standard.
|
|
5
4
|
argument-hint: '[skill-name]'
|
|
6
5
|
disable-model-invocation: true
|
|
7
6
|
allowed-tools: Read, Write, Bash, Glob, Grep, AskUserQuestion
|
|
8
7
|
user-invocable: true
|
|
8
|
+
metadata:
|
|
9
|
+
version: 1.4.3
|
|
9
10
|
---
|
|
10
11
|
|
|
11
12
|
# Create Skill
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: deep-research
|
|
3
|
-
version: 0.2.0
|
|
4
3
|
description: Comprehensive research orchestrator that classifies topics, dispatches parallel research-angle workers, and produces structured artifacts using domain-specific schemas.
|
|
5
4
|
argument-hint: 'topic [--depth surface|standard|exhaustive] [--focus angle] [--context path] [output-path]'
|
|
6
5
|
user-invocable: true
|
|
7
6
|
allowed-tools: Read, Glob, Grep, Bash, WebSearch, WebFetch, AskUserQuestion, Agent, mcp__*
|
|
7
|
+
metadata:
|
|
8
|
+
version: 0.2.1
|
|
8
9
|
---
|
|
9
10
|
|
|
10
11
|
# /deep-research
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: explainer-kit
|
|
3
|
-
version: 2.1.0
|
|
4
3
|
description: Use when building destination-neutral visual explainer artifacts from explicit, versioned inputs.
|
|
5
4
|
user-invocable: true
|
|
6
5
|
allowed-tools: Read, Write, Edit, Bash, Grep, Glob, Agent, mcp__*
|
|
6
|
+
metadata:
|
|
7
|
+
version: 2.1.1
|
|
7
8
|
---
|
|
8
9
|
|
|
9
10
|
# Explainer Kit
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: oat-agent-instructions-analyze
|
|
3
|
-
version: 1.12.0
|
|
4
3
|
description: Run when you need to evaluate agent instruction file coverage, quality, and drift. Produces a severity-rated analysis artifact. Run before oat-agent-instructions-apply to identify what needs improvement.
|
|
5
4
|
disable-model-invocation: true
|
|
6
5
|
user-invocable: true
|
|
7
6
|
allowed-tools: Read, Write, Bash(git:*), Glob, Grep, AskUserQuestion, Task
|
|
7
|
+
metadata:
|
|
8
|
+
version: 1.12.1
|
|
8
9
|
---
|
|
9
10
|
|
|
10
11
|
# Agent Instructions Analysis
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: oat-agent-instructions-apply
|
|
3
|
-
version: 1.7.0
|
|
4
3
|
description: Run when you have an agent instructions analysis artifact and want to generate or update instruction files. Creates a branch, generates files from templates, and optionally opens a PR.
|
|
5
4
|
disable-model-invocation: true
|
|
6
5
|
user-invocable: true
|
|
7
6
|
allowed-tools: Read, Write, Edit, Bash(git:*), Bash(gh:*), Glob, Grep, AskUserQuestion
|
|
7
|
+
metadata:
|
|
8
|
+
version: 1.7.1
|
|
8
9
|
---
|
|
9
10
|
|
|
10
11
|
# Agent Instructions Apply
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: oat-brainstorm
|
|
3
|
-
version: 1.3.6
|
|
4
3
|
description: Use when the user explicitly invokes the `brainstorm` verb, including `/oat-brainstorm`, "let's brainstorm", "brainstorm this", "can we brainstorm X", or "help me brainstorm X". For ambiguous exploratory phrasing ("I've been thinking", "what if", "help me think through"), do NOT auto-enter; respond conversationally and offer mode only after ≥2 sustained exploratory turns. Do NOT use for review, debug, PR, status, implementation, or active-workflow questions.
|
|
5
4
|
disable-model-invocation: false
|
|
6
5
|
user-invocable: true
|
|
7
6
|
allowed-tools: Read, Write, Bash, Glob, Grep, AskUserQuestion
|
|
7
|
+
metadata:
|
|
8
|
+
version: 1.3.7
|
|
8
9
|
---
|
|
9
10
|
|
|
10
11
|
# Brainstorm
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: oat-cursor-cloud-projects
|
|
3
|
-
version: 1.1.1
|
|
4
3
|
description: Use when OAT work is mentioned in a Cursor Cloud environment. Orients agents to cloud detection, repo-rooted project homes, user-first assets, CLI availability, and Cursor dispatch context without owning lifecycle execution.
|
|
5
4
|
disable-model-invocation: false
|
|
6
5
|
user-invocable: true
|
|
7
6
|
allowed-tools: Read, Write, Bash, Glob, Grep
|
|
7
|
+
metadata:
|
|
8
|
+
version: 1.1.2
|
|
8
9
|
---
|
|
9
10
|
|
|
10
11
|
# OAT in Cursor Cloud
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: oat-dispatch-subagents
|
|
3
|
-
version: 1.2.6
|
|
4
3
|
description: Use when an OAT skill or workflow needs provider-neutral selection, launch, recovery, or evidence for bounded subagent work without project lifecycle policy.
|
|
5
4
|
disable-model-invocation: true
|
|
6
5
|
user-invocable: false
|
|
7
6
|
allowed-tools: Read
|
|
7
|
+
metadata:
|
|
8
|
+
version: 1.2.7
|
|
8
9
|
---
|
|
9
10
|
|
|
10
11
|
# Dispatching OAT Subagents
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: oat-docs
|
|
3
|
-
version: 1.0.2
|
|
4
3
|
description: Use when a user asks questions about OAT workflows, CLI commands, skill authoring, configuration, or project lifecycle. Answers questions by reading locally-bundled OAT documentation.
|
|
5
4
|
argument-hint: '[question]'
|
|
6
5
|
disable-model-invocation: false
|
|
7
6
|
user-invocable: true
|
|
8
7
|
allowed-tools: Read, Glob, Grep, AskUserQuestion
|
|
8
|
+
metadata:
|
|
9
|
+
version: 1.0.3
|
|
9
10
|
---
|
|
10
11
|
|
|
11
12
|
# OAT Docs
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: oat-docs-analyze
|
|
3
|
-
version: 1.5.0
|
|
4
3
|
description: Run when you need to evaluate documentation structure, navigation, and coverage against the OAT docs app contract. Produces a severity-rated analysis artifact for oat-docs-apply.
|
|
5
4
|
disable-model-invocation: true
|
|
6
5
|
user-invocable: true
|
|
7
6
|
allowed-tools: Read, Write, Bash(git:*), Glob, Grep, AskUserQuestion, Task
|
|
7
|
+
metadata:
|
|
8
|
+
version: 1.5.1
|
|
8
9
|
---
|
|
9
10
|
|
|
10
11
|
# Docs Analysis
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: oat-docs-apply
|
|
3
|
-
version: 1.3.0
|
|
4
3
|
description: Run when you have a docs analysis artifact and want to generate or update documentation structure and content. Creates a branch, applies approved changes, and optionally opens a PR.
|
|
5
4
|
disable-model-invocation: true
|
|
6
5
|
user-invocable: true
|
|
7
6
|
allowed-tools: Read, Write, Edit, Bash(git:*), Bash(gh:*), Glob, Grep, AskUserQuestion
|
|
7
|
+
metadata:
|
|
8
|
+
version: 1.3.1
|
|
8
9
|
---
|
|
9
10
|
|
|
10
11
|
# Docs Apply
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: oat-docs-authoring
|
|
3
|
-
version: 1.0.0
|
|
4
3
|
description: Use when authoring or restructuring targeted content inside an existing OAT/Fumadocs docs app. Preserves OAT docs navigation, generated indexes, and validation boundaries.
|
|
5
4
|
argument-hint: '[docs task or target path]'
|
|
6
5
|
disable-model-invocation: false
|
|
7
6
|
allowed-tools: Read, Write, Bash, Glob, Grep, AskUserQuestion
|
|
8
7
|
user-invocable: true
|
|
8
|
+
metadata:
|
|
9
|
+
version: 1.0.1
|
|
9
10
|
---
|
|
10
11
|
|
|
11
12
|
# OAT Docs Authoring
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: oat-docs-bootstrap
|
|
3
|
-
version: 1.2.0
|
|
4
3
|
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 gated 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
4
|
argument-hint: '<optional-target-dir>'
|
|
6
5
|
disable-model-invocation: true
|
|
7
6
|
user-invocable: true
|
|
8
7
|
allowed-tools: Read, Write, Edit, Bash, Glob, Grep, AskUserQuestion
|
|
8
|
+
metadata:
|
|
9
|
+
version: 1.2.1
|
|
9
10
|
---
|
|
10
11
|
|
|
11
12
|
# Docs Bootstrap
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: oat-doctor
|
|
3
|
-
version: 1.2.1
|
|
4
3
|
description: Use when you need to diagnose your OAT setup, check for outdated skills, identify misconfigurations, or get a summary of installed tools and config. Runs health checks and recommends corrective actions.
|
|
5
4
|
argument-hint: '[--summary]'
|
|
6
5
|
disable-model-invocation: true
|
|
7
6
|
user-invocable: true
|
|
8
7
|
allowed-tools: Read, Bash, Glob, Grep, AskUserQuestion
|
|
8
|
+
metadata:
|
|
9
|
+
version: 1.2.2
|
|
9
10
|
---
|
|
10
11
|
|
|
11
12
|
# OAT Doctor
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: oat-explainer-kit
|
|
3
|
-
version: 1.0.7
|
|
4
3
|
description: Use when building project explainers or recaps from OAT configuration, state, and lifecycle artifacts.
|
|
5
4
|
disable-model-invocation: false
|
|
6
5
|
user-invocable: true
|
|
7
6
|
allowed-tools: Read, Write, Edit, Bash, Grep, Glob, AskUserQuestion
|
|
7
|
+
metadata:
|
|
8
|
+
version: 1.0.8
|
|
8
9
|
---
|
|
9
10
|
|
|
10
11
|
# OAT Explainer Kit
|
|
@@ -104,11 +104,331 @@ function failure({
|
|
|
104
104
|
};
|
|
105
105
|
}
|
|
106
106
|
|
|
107
|
-
|
|
108
|
-
|
|
107
|
+
/**
|
|
108
|
+
* Read a skill's canonical version from its frontmatter, with
|
|
109
|
+
* `metadata.version` taking precedence over the deprecated top-level `version`
|
|
110
|
+
* alias.
|
|
111
|
+
*
|
|
112
|
+
* ACCEPTED EXCEPTION to the repository rule that only
|
|
113
|
+
* `packages/cli/src/commands/shared/frontmatter.ts` implements this precedence:
|
|
114
|
+
* this script is installed into user projects by pack install, where it can
|
|
115
|
+
* import neither that resolver nor the `yaml` package, so it carries a
|
|
116
|
+
* self-contained reader. The parity contract
|
|
117
|
+
* `tools/smoke/explainer-kit/check-core-version-parity.test.mjs` runs one
|
|
118
|
+
* shared fixture corpus — plus every bundled `SKILL.md` — through this reader
|
|
119
|
+
* and the canonical resolver and requires the same answer; a change to the
|
|
120
|
+
* canonical precedence rule must update those fixtures and this reader
|
|
121
|
+
* together.
|
|
122
|
+
*
|
|
123
|
+
* Anything the canonical resolver cannot resolve cleanly returns `null` so the
|
|
124
|
+
* compatibility check fails closed instead of guessing: a conflict between the
|
|
125
|
+
* two positions, a malformed block, a duplicate key, a tagged, anchored, or
|
|
126
|
+
* aliased scalar, and a plain scalar YAML would read as a number, boolean, or
|
|
127
|
+
* null.
|
|
128
|
+
*
|
|
129
|
+
* Deliberate limits of a parser-free reader, all of which fail closed rather
|
|
130
|
+
* than guess a version: flow collections (`metadata: {version: 1.2.3}`), block
|
|
131
|
+
* scalars, quoted keys, quote escape sequences, multi-line plain scalars, and
|
|
132
|
+
* document markers inside the block all return `null` even where a full YAML
|
|
133
|
+
* parser would resolve them. Nothing in the authoring templates emits those
|
|
134
|
+
* shapes.
|
|
135
|
+
*
|
|
136
|
+
* Every key and value in the block is checked, not just `version`, and the
|
|
137
|
+
* whole block is walked to any depth, so a syntax error anywhere in it fails
|
|
138
|
+
* closed rather than leaving a readable version behind. What remains outside
|
|
139
|
+
* the reader's reach is the content of a shape it refuses outright — the body
|
|
140
|
+
* of a block scalar, or anything inside a flow collection — which it never
|
|
141
|
+
* parses because it never accepts the shape that introduces it.
|
|
142
|
+
*/
|
|
143
|
+
export function readFrontmatterVersion(content) {
|
|
144
|
+
const block = frontmatterBlock(content);
|
|
145
|
+
if (block === null) {
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const root = readBlockMap(block.split('\n').map(classifyLine), -1);
|
|
150
|
+
if (root === null || (root.indent !== null && root.indent !== 0)) {
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
let topLevel;
|
|
155
|
+
let metadata;
|
|
156
|
+
let unusable = false;
|
|
157
|
+
|
|
158
|
+
for (const child of root.children) {
|
|
159
|
+
if (child.name === 'version') {
|
|
160
|
+
const scalar = declaredScalar(child);
|
|
161
|
+
if (scalar === null) {
|
|
162
|
+
unusable = true;
|
|
163
|
+
} else {
|
|
164
|
+
topLevel = scalar;
|
|
165
|
+
}
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
if (child.name === 'metadata') {
|
|
169
|
+
// A `metadata:` key with a scalar or flow value is not the block map the
|
|
170
|
+
// canonical resolver requires, and one with no children is a null scalar.
|
|
171
|
+
if (scalarText(child.value) !== '' || child.map.indent === null) {
|
|
172
|
+
return null;
|
|
173
|
+
}
|
|
174
|
+
const nested = child.map.children.find(
|
|
175
|
+
(entry) => entry.name === 'version',
|
|
176
|
+
);
|
|
177
|
+
if (nested !== undefined) {
|
|
178
|
+
const scalar = declaredScalar(nested);
|
|
179
|
+
if (scalar === null) {
|
|
180
|
+
unusable = true;
|
|
181
|
+
} else {
|
|
182
|
+
metadata = scalar;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (unusable) {
|
|
189
|
+
return null;
|
|
190
|
+
}
|
|
191
|
+
if (metadata !== undefined) {
|
|
192
|
+
return topLevel !== undefined && topLevel !== metadata ? null : metadata;
|
|
193
|
+
}
|
|
194
|
+
return topLevel ?? null;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
function frontmatterBlock(content) {
|
|
198
|
+
const match = content.match(/^---\n([\s\S]*?)\n---/);
|
|
109
199
|
return match?.[1] ?? null;
|
|
110
200
|
}
|
|
111
201
|
|
|
202
|
+
/**
|
|
203
|
+
* Sort one frontmatter line into the few shapes this reader understands.
|
|
204
|
+
*
|
|
205
|
+
* A key must be followed by `:` and then whitespace or the end of the line,
|
|
206
|
+
* which is what YAML requires of a block mapping: `version:1.2.3` is a plain
|
|
207
|
+
* scalar, not a key, and the canonical resolver reads no version from it. A tab
|
|
208
|
+
* in the indentation is never valid YAML indentation, and a quoted key is a
|
|
209
|
+
* shape this reader refuses rather than compares raw against a plain one.
|
|
210
|
+
*/
|
|
211
|
+
function classifyLine(line) {
|
|
212
|
+
if (line.trim() === '') {
|
|
213
|
+
return { kind: 'blank' };
|
|
214
|
+
}
|
|
215
|
+
const indentation = line.match(/^[ \t]*/)[0];
|
|
216
|
+
if (indentation.includes('\t')) {
|
|
217
|
+
return { kind: 'invalid' };
|
|
218
|
+
}
|
|
219
|
+
const indent = indentation.length;
|
|
220
|
+
const rest = line.slice(indent);
|
|
221
|
+
if (rest.startsWith('#')) {
|
|
222
|
+
return { kind: 'comment', indent };
|
|
223
|
+
}
|
|
224
|
+
const key = rest.match(/^([^\s:#]+):(?=[ \t]|$)([ \t].*)?$/);
|
|
225
|
+
// A key is a plain scalar too: a quoted key is a shape this reader refuses
|
|
226
|
+
// rather than compares raw against a plain one, and a key opening with an
|
|
227
|
+
// indicator is not a key at all.
|
|
228
|
+
if (key === null || /^["']/.test(key[1]) || !isPlainScalar(key[1])) {
|
|
229
|
+
return { kind: 'invalid', indent };
|
|
230
|
+
}
|
|
231
|
+
return { kind: 'key', indent, name: key[1], value: key[2] ?? '' };
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Read one block map and everything under it, rejecting every structure this
|
|
236
|
+
* reader cannot validate: an inconsistent indent, a duplicate key at any depth,
|
|
237
|
+
* a value shape it cannot read, or a line it cannot classify. Rejection is
|
|
238
|
+
* always `null`, never a guess.
|
|
239
|
+
*/
|
|
240
|
+
function readBlockMap(lines, parentIndent) {
|
|
241
|
+
let indent = null;
|
|
242
|
+
const names = [];
|
|
243
|
+
const children = [];
|
|
244
|
+
|
|
245
|
+
for (let index = 0; index < lines.length; ) {
|
|
246
|
+
const line = lines[index];
|
|
247
|
+
if (line.kind === 'invalid') {
|
|
248
|
+
return null;
|
|
249
|
+
}
|
|
250
|
+
if (line.kind === 'blank' || line.kind === 'comment') {
|
|
251
|
+
index += 1;
|
|
252
|
+
continue;
|
|
253
|
+
}
|
|
254
|
+
if (line.indent <= parentIndent) {
|
|
255
|
+
return null;
|
|
256
|
+
}
|
|
257
|
+
if (indent === null) {
|
|
258
|
+
indent = line.indent;
|
|
259
|
+
}
|
|
260
|
+
if (line.indent !== indent) {
|
|
261
|
+
return null;
|
|
262
|
+
}
|
|
263
|
+
const identity = keyIdentity(line.name);
|
|
264
|
+
if (names.includes(identity) || !isReadableValue(line.value)) {
|
|
265
|
+
return null;
|
|
266
|
+
}
|
|
267
|
+
names.push(identity);
|
|
268
|
+
|
|
269
|
+
let end = index + 1;
|
|
270
|
+
while (
|
|
271
|
+
end < lines.length &&
|
|
272
|
+
(lines[end].kind === 'blank' ||
|
|
273
|
+
lines[end].kind === 'comment' ||
|
|
274
|
+
lines[end].kind === 'invalid' ||
|
|
275
|
+
lines[end].indent > indent)
|
|
276
|
+
) {
|
|
277
|
+
end += 1;
|
|
278
|
+
}
|
|
279
|
+
const body = lines.slice(index + 1, end);
|
|
280
|
+
const map = body.some((entry) => entry.kind !== 'blank')
|
|
281
|
+
? readBlockMap(body, indent)
|
|
282
|
+
: { indent: null, children: [] };
|
|
283
|
+
// A key cannot own both a scalar and a nested map. This also refuses a
|
|
284
|
+
// multi-line plain scalar, whose continuation lines arrive here as
|
|
285
|
+
// children: folding one is beyond a parser-free reader, so it fails closed.
|
|
286
|
+
if (
|
|
287
|
+
map === null ||
|
|
288
|
+
(map.indent !== null && scalarText(line.value) !== '')
|
|
289
|
+
) {
|
|
290
|
+
return null;
|
|
291
|
+
}
|
|
292
|
+
children.push({ ...line, map });
|
|
293
|
+
index = end;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
return { indent, children };
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* The scalar a key declares, or `null` when it declares something this reader
|
|
301
|
+
* refuses to read as a version — including a multi-line scalar or a nested map,
|
|
302
|
+
* both of which arrive here as children.
|
|
303
|
+
*/
|
|
304
|
+
function declaredScalar(child) {
|
|
305
|
+
return child.map.indent === null ? scalarValue(child.value) : null;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Whether a raw value is a shape this reader can read at all. Every key's value
|
|
310
|
+
* is checked, not just `version`, so no syntax error is silently walked past:
|
|
311
|
+
* the canonical resolver rejects the whole document for any of them.
|
|
312
|
+
*/
|
|
313
|
+
function isReadableValue(raw) {
|
|
314
|
+
const text = raw.trim();
|
|
315
|
+
if (text === '' || text.startsWith('#')) {
|
|
316
|
+
return true;
|
|
317
|
+
}
|
|
318
|
+
if (/^["']/.test(text)) {
|
|
319
|
+
return quotedScalar(text) !== null;
|
|
320
|
+
}
|
|
321
|
+
return isPlainScalar(scalarText(text));
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* Whether a comment-stripped value is a plain scalar YAML reads as a string.
|
|
326
|
+
*
|
|
327
|
+
* Refused: every character YAML forbids at the start of a plain scalar — the
|
|
328
|
+
* flow, block-scalar, anchor, alias, and tag indicators, and the reserved `@`,
|
|
329
|
+
* `` ` ``, and `%` — plus `-`, `?`, and `:` when whitespace or the end of the
|
|
330
|
+
* value follows, which is what makes them indicators rather than the first
|
|
331
|
+
* letter of a word. A `:` anywhere in the value gets the same treatment,
|
|
332
|
+
* because `: ` opens a nested mapping instead of continuing the scalar.
|
|
333
|
+
*
|
|
334
|
+
* Still readable, because none of these is an indicator in block context: a `:`
|
|
335
|
+
* inside a word (`https://example.com`), a `,` after the first character
|
|
336
|
+
* (`allowed-tools: Read, Write`), and a leading `-` or `?` that starts a word
|
|
337
|
+
* (`-word`).
|
|
338
|
+
*/
|
|
339
|
+
function isPlainScalar(plain) {
|
|
340
|
+
return (
|
|
341
|
+
!/^[&*!|>[\]{},@`%]/.test(plain) &&
|
|
342
|
+
!/^[-?](?:[ \t]|$)/.test(plain) &&
|
|
343
|
+
!/:(?:[ \t]|$)/.test(plain)
|
|
344
|
+
);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* The identity YAML gives a mapping key, so two spellings of one key are caught
|
|
349
|
+
* as the duplicate they are: `true` and `True` are the same boolean key, and
|
|
350
|
+
* `1` and `01` the same integer key, even though their text differs.
|
|
351
|
+
*/
|
|
352
|
+
function keyIdentity(name) {
|
|
353
|
+
if (/^(null|Null|NULL|~)$/.test(name)) {
|
|
354
|
+
return 'null';
|
|
355
|
+
}
|
|
356
|
+
if (/^(true|True|TRUE)$/.test(name)) {
|
|
357
|
+
return 'bool:true';
|
|
358
|
+
}
|
|
359
|
+
if (/^(false|False|FALSE)$/.test(name)) {
|
|
360
|
+
return 'bool:false';
|
|
361
|
+
}
|
|
362
|
+
if (
|
|
363
|
+
/^[-+]?[0-9]+$/.test(name) ||
|
|
364
|
+
/^0x[0-9a-fA-F]+$/.test(name) ||
|
|
365
|
+
/^0o[0-7]+$/.test(name) ||
|
|
366
|
+
/^[-+]?(\.[0-9]+|[0-9]+(\.[0-9]*)?)([eE][-+]?[0-9]+)?$/.test(name)
|
|
367
|
+
) {
|
|
368
|
+
return `number:${Number(name)}`;
|
|
369
|
+
}
|
|
370
|
+
return `string:${name}`;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* Strip a trailing comment from a raw value. YAML only starts a comment at a
|
|
375
|
+
* `#` preceded by whitespace, so `1.2.3#note` is the string it looks like.
|
|
376
|
+
*/
|
|
377
|
+
function scalarText(raw) {
|
|
378
|
+
const text = raw.trim();
|
|
379
|
+
if (text.startsWith('#')) {
|
|
380
|
+
return '';
|
|
381
|
+
}
|
|
382
|
+
const comment = text.search(/[ \t]#/);
|
|
383
|
+
return (comment === -1 ? text : text.slice(0, comment)).trim();
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
function quotedScalar(text) {
|
|
387
|
+
const quoted =
|
|
388
|
+
text.match(/^"([^"\\]*)"(?:[ \t]+#.*)?$/) ??
|
|
389
|
+
text.match(/^'([^']*)'(?:[ \t]+#.*)?$/);
|
|
390
|
+
return quoted?.[1] ?? null;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
* Read one plain or quoted string scalar, returning `null` for every value the
|
|
395
|
+
* canonical resolver refuses to treat as a version string.
|
|
396
|
+
*/
|
|
397
|
+
function scalarValue(raw) {
|
|
398
|
+
const text = raw.trim();
|
|
399
|
+
if (text === '' || text.startsWith('#')) {
|
|
400
|
+
return null;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
if (/^["']/.test(text)) {
|
|
404
|
+
const quoted = quotedScalar(text)?.trim();
|
|
405
|
+
return quoted === undefined || quoted === '' ? null : quoted;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
const plain = scalarText(text);
|
|
409
|
+
if (plain === '') {
|
|
410
|
+
return null;
|
|
411
|
+
}
|
|
412
|
+
if (!isPlainScalar(plain)) {
|
|
413
|
+
return null;
|
|
414
|
+
}
|
|
415
|
+
// Core-schema scalars that resolve to a non-string type: `version: 1.10` is
|
|
416
|
+
// the number 1.1, never the string an author meant to write.
|
|
417
|
+
if (
|
|
418
|
+
/^(null|Null|NULL|~)$/.test(plain) ||
|
|
419
|
+
/^(true|True|TRUE|false|False|FALSE)$/.test(plain) ||
|
|
420
|
+
/^[-+]?[0-9]+$/.test(plain) ||
|
|
421
|
+
/^0o[0-7]+$/.test(plain) ||
|
|
422
|
+
/^0x[0-9a-fA-F]+$/.test(plain) ||
|
|
423
|
+
/^[-+]?(\.[0-9]+|[0-9]+(\.[0-9]*)?)([eE][-+]?[0-9]+)?$/.test(plain) ||
|
|
424
|
+
/^[-+]?\.(inf|Inf|INF)$/.test(plain) ||
|
|
425
|
+
/^\.(nan|NaN|NAN)$/.test(plain)
|
|
426
|
+
) {
|
|
427
|
+
return null;
|
|
428
|
+
}
|
|
429
|
+
return plain;
|
|
430
|
+
}
|
|
431
|
+
|
|
112
432
|
function parseVersion(value) {
|
|
113
433
|
if (typeof value !== 'string') {
|
|
114
434
|
return null;
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: oat-idea-ideate
|
|
3
|
-
version: 1.2.2
|
|
4
3
|
description: Use when continuing an existing tracked idea or expanding an explicit scratchpad seed from {IDEAS_ROOT}/scratchpad.md. Do NOT use to start a brand-new, destinationless brainstorm; use oat-brainstorm for that.
|
|
5
4
|
argument-hint: '[--global]'
|
|
6
5
|
disable-model-invocation: true
|
|
7
6
|
user-invocable: true
|
|
8
7
|
allowed-tools: Read, Write, Bash, Glob, AskUserQuestion
|
|
8
|
+
metadata:
|
|
9
|
+
version: 1.2.3
|
|
9
10
|
---
|
|
10
11
|
|
|
11
12
|
# Ideate
|