@open-agent-toolkit/cli 0.2.62 → 0.2.64

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.
Files changed (145) hide show
  1. package/assets/bundle-metadata.json +1 -1
  2. package/assets/docs/cli-utilities/config-and-local-state.md +1 -0
  3. package/assets/docs/cli-utilities/configuration.md +10 -8
  4. package/assets/docs/cli-utilities/project-log.md +16 -0
  5. package/assets/docs/cli-utilities/tool-packs.md +83 -0
  6. package/assets/docs/cli-utilities/workflow-gates.md +124 -16
  7. package/assets/docs/contributing/skills.md +42 -7
  8. package/assets/docs/provider-sync/commands.md +3 -0
  9. package/assets/docs/provider-sync/instruction-sync.md +107 -0
  10. package/assets/docs/provider-sync/manifest-and-drift.md +105 -0
  11. package/assets/docs/reference/cli-reference.md +16 -6
  12. package/assets/docs/reference/oat-directory-structure.md +32 -31
  13. package/assets/docs/workflows/projects/lifecycle.md +45 -0
  14. package/assets/docs/workflows/projects/picking-up-projects.md +14 -0
  15. package/assets/docs/workflows/skills/explainer-kit.md +10 -4
  16. package/assets/docs/workflows/skills/repo-improve.md +15 -1
  17. package/assets/public-package-versions.json +4 -4
  18. package/assets/skills/create-agnostic-skill/SKILL.md +9 -7
  19. package/assets/skills/create-agnostic-skill/references/skill-template.md +9 -7
  20. package/assets/skills/oat-explainer-kit/SKILL.md +14 -1
  21. package/assets/skills/oat-explainer-kit/references/config-contract.md +12 -0
  22. package/assets/skills/oat-explainer-kit/references/lifecycle-contract.md +57 -10
  23. package/assets/skills/oat-explainer-kit/scripts/check-terminal-outcome.mjs +28 -5
  24. package/assets/skills/oat-explainer-kit/scripts/probe-recap-seams.mjs +371 -0
  25. package/assets/skills/oat-explainer-kit/scripts/resolve-intent.mjs +123 -1
  26. package/assets/skills/oat-project-autonomous/SKILL.md +10 -1
  27. package/assets/skills/oat-project-autonomous/references/gate-inventory.md +122 -121
  28. package/assets/skills/oat-project-complete/SKILL.md +134 -4
  29. package/assets/skills/oat-project-document/references/docs/autonomy-contract.md +122 -121
  30. package/assets/skills/oat-project-implement/SKILL.md +1 -1
  31. package/assets/skills/oat-project-implement/references/completion-and-closeout.md +38 -6
  32. package/assets/skills/oat-project-implement/references/docs/autonomy-contract.md +122 -121
  33. package/assets/skills/oat-project-lite/references/docs/autonomy-contract.md +122 -121
  34. package/assets/skills/oat-project-next/SKILL.md +62 -19
  35. package/assets/skills/oat-project-plan/SKILL.md +31 -5
  36. package/assets/skills/oat-project-pr-final/SKILL.md +281 -6
  37. package/assets/skills/oat-project-pr-final/references/docs/autonomy-contract.md +122 -121
  38. package/assets/skills/oat-project-progress/SKILL.md +12 -3
  39. package/assets/skills/oat-project-quick-start/SKILL.md +264 -4
  40. package/assets/skills/oat-project-quick-start/references/docs/autonomy-contract.md +122 -121
  41. package/assets/skills/oat-project-summary/SKILL.md +34 -23
  42. package/assets/skills/oat-repo-improve/SKILL.md +40 -5
  43. package/assets/skills/oat-repo-improve/references/plan-template.md +84 -7
  44. package/dist/agents/canonical/resolve.d.ts.map +1 -1
  45. package/dist/agents/canonical/resolve.js +25 -4
  46. package/dist/commands/config/index.d.ts +1 -0
  47. package/dist/commands/config/index.d.ts.map +1 -1
  48. package/dist/commands/config/index.js +401 -18
  49. package/dist/commands/doctor/index.d.ts +7 -0
  50. package/dist/commands/doctor/index.d.ts.map +1 -1
  51. package/dist/commands/doctor/index.js +10 -2
  52. package/dist/commands/gate/index.d.ts +3 -1
  53. package/dist/commands/gate/index.d.ts.map +1 -1
  54. package/dist/commands/gate/index.js +699 -211
  55. package/dist/commands/init/tools/index.d.ts.map +1 -1
  56. package/dist/commands/init/tools/index.js +68 -36
  57. package/dist/commands/init/tools/shared/skill-script-references.d.ts +126 -0
  58. package/dist/commands/init/tools/shared/skill-script-references.d.ts.map +1 -0
  59. package/dist/commands/init/tools/shared/skill-script-references.js +311 -0
  60. package/dist/commands/instructions/instructions.types.d.ts +63 -0
  61. package/dist/commands/instructions/instructions.types.d.ts.map +1 -1
  62. package/dist/commands/instructions/instructions.utils.d.ts +51 -2
  63. package/dist/commands/instructions/instructions.utils.d.ts.map +1 -1
  64. package/dist/commands/instructions/instructions.utils.js +201 -4
  65. package/dist/commands/instructions/sync/sync.d.ts.map +1 -1
  66. package/dist/commands/instructions/sync/sync.js +12 -1
  67. package/dist/commands/instructions/validate/validate.d.ts.map +1 -1
  68. package/dist/commands/instructions/validate/validate.js +12 -1
  69. package/dist/commands/project/log/append.d.ts +195 -0
  70. package/dist/commands/project/log/append.d.ts.map +1 -1
  71. package/dist/commands/project/log/append.js +1034 -11
  72. package/dist/commands/shared/frontmatter.d.ts +51 -0
  73. package/dist/commands/shared/frontmatter.d.ts.map +1 -1
  74. package/dist/commands/shared/frontmatter.js +118 -6
  75. package/dist/commands/status/index.d.ts.map +1 -1
  76. package/dist/commands/status/index.js +5 -3
  77. package/dist/commands/sync/index.d.ts +14 -0
  78. package/dist/commands/sync/index.d.ts.map +1 -1
  79. package/dist/commands/sync/index.js +21 -0
  80. package/dist/commands/tools/info/index.d.ts.map +1 -1
  81. package/dist/commands/tools/info/index.js +14 -1
  82. package/dist/commands/tools/info/info-tool.d.ts +12 -0
  83. package/dist/commands/tools/info/info-tool.d.ts.map +1 -1
  84. package/dist/commands/tools/info/info-tool.js +54 -6
  85. package/dist/commands/tools/info/skill-views.d.ts +86 -0
  86. package/dist/commands/tools/info/skill-views.d.ts.map +1 -0
  87. package/dist/commands/tools/info/skill-views.js +383 -0
  88. package/dist/commands/tools/install/index.d.ts.map +1 -1
  89. package/dist/commands/tools/install/index.js +3 -25
  90. package/dist/commands/tools/list/list-tools.d.ts +2 -0
  91. package/dist/commands/tools/list/list-tools.d.ts.map +1 -1
  92. package/dist/commands/tools/list/list-tools.js +23 -4
  93. package/dist/commands/tools/remove/index.d.ts.map +1 -1
  94. package/dist/commands/tools/remove/index.js +35 -42
  95. package/dist/commands/tools/remove/remove-tools.d.ts +3 -2
  96. package/dist/commands/tools/remove/remove-tools.d.ts.map +1 -1
  97. package/dist/commands/tools/remove/remove-tools.js +14 -4
  98. package/dist/commands/tools/shared/auto-sync.d.ts +12 -1
  99. package/dist/commands/tools/shared/auto-sync.d.ts.map +1 -1
  100. package/dist/commands/tools/shared/auto-sync.js +20 -4
  101. package/dist/commands/tools/shared/format-pack-inventory.d.ts +12 -1
  102. package/dist/commands/tools/shared/format-pack-inventory.d.ts.map +1 -1
  103. package/dist/commands/tools/shared/format-pack-inventory.js +48 -6
  104. package/dist/commands/tools/shared/in-process-sync.d.ts +11 -0
  105. package/dist/commands/tools/shared/in-process-sync.d.ts.map +1 -0
  106. package/dist/commands/tools/shared/in-process-sync.js +79 -0
  107. package/dist/commands/tools/shared/pack-evidence.d.ts +78 -2
  108. package/dist/commands/tools/shared/pack-evidence.d.ts.map +1 -1
  109. package/dist/commands/tools/shared/pack-evidence.js +96 -2
  110. package/dist/commands/tools/shared/pack-lifecycle-outcome.d.ts +11 -0
  111. package/dist/commands/tools/shared/pack-lifecycle-outcome.d.ts.map +1 -1
  112. package/dist/commands/tools/shared/pack-lifecycle-outcome.js +24 -3
  113. package/dist/commands/tools/shared/pack-provider-evidence.d.ts +73 -0
  114. package/dist/commands/tools/shared/pack-provider-evidence.d.ts.map +1 -0
  115. package/dist/commands/tools/shared/pack-provider-evidence.js +161 -0
  116. package/dist/commands/tools/shared/provider-context.d.ts +88 -0
  117. package/dist/commands/tools/shared/provider-context.d.ts.map +1 -0
  118. package/dist/commands/tools/shared/provider-context.js +77 -0
  119. package/dist/commands/tools/shared/provider-reachability.d.ts +93 -0
  120. package/dist/commands/tools/shared/provider-reachability.d.ts.map +1 -0
  121. package/dist/commands/tools/shared/provider-reachability.js +358 -0
  122. package/dist/commands/tools/shared/sync-evidence.d.ts +57 -0
  123. package/dist/commands/tools/shared/sync-evidence.d.ts.map +1 -0
  124. package/dist/commands/tools/shared/sync-evidence.js +147 -0
  125. package/dist/commands/tools/update/index.d.ts +0 -4
  126. package/dist/commands/tools/update/index.d.ts.map +1 -1
  127. package/dist/commands/tools/update/index.js +22 -40
  128. package/dist/commands/tools/update/update-tools.d.ts.map +1 -1
  129. package/dist/commands/tools/update/update-tools.js +23 -8
  130. package/dist/config/json.d.ts +36 -0
  131. package/dist/config/json.d.ts.map +1 -1
  132. package/dist/config/json.js +135 -3
  133. package/dist/config/oat-config.d.ts +41 -0
  134. package/dist/config/oat-config.d.ts.map +1 -1
  135. package/dist/config/oat-config.js +111 -0
  136. package/dist/drift/index.d.ts +2 -0
  137. package/dist/drift/index.d.ts.map +1 -1
  138. package/dist/drift/index.js +1 -0
  139. package/dist/drift/skill-view-diagnostic.d.ts +197 -0
  140. package/dist/drift/skill-view-diagnostic.d.ts.map +1 -0
  141. package/dist/drift/skill-view-diagnostic.js +343 -0
  142. package/dist/validation/skills.d.ts +1 -0
  143. package/dist/validation/skills.d.ts.map +1 -1
  144. package/dist/validation/skills.js +181 -19
  145. package/package.json +2 -2
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: oat-project-progress
3
- version: 1.4.0
3
+ version: 1.4.1
4
4
  description: Use when the user explicitly asks to check OAT project progress — e.g. "check progress", "what's next", "where are we", or confirms a previously offered progress check. Do NOT auto-invoke just because a workflow step completed. Reads project status and offers the next route.
5
5
  disable-model-invocation: false
6
6
  user-invocable: true
@@ -276,12 +276,21 @@ Routing matrix by mode:
276
276
  | --------- | ---------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
277
277
  | discovery | in_progress | Continue `oat-project-discover` |
278
278
  | discovery | complete | `oat-project-plan` |
279
- | plan | in_progress | Continue `oat-project-plan` |
280
- | plan | complete | `oat-project-implement` |
279
+ | plan | in_progress | Continue `oat-project-quick-start` when the plan is not implementation-ready; otherwise `oat-project-implement` |
280
+ | plan | complete | `oat-project-implement` when the plan is implementation-ready; otherwise `oat-project-quick-start` |
281
281
  | implement | in_progress | Continue `oat-project-implement`. If drift detected (see drift detection above), also mention `oat-project-reconcile` as an option. |
282
282
  | implement | complete | Ready for final review / PR |
283
283
  | implement | pr_open | `oat-project-complete` |
284
284
 
285
+ **Quick plan readiness.** "Implementation-ready" in the two `plan` rows above is
286
+ the named **quick plan readiness** predicate, defined once beside Step 3.7 of the
287
+ quick workflow. Load `oat-project-quick-start/SKILL.md` and apply that predicate
288
+ as written to `{PROJECT_PATH}/plan.md`; do not restate or re-derive its
289
+ conditions here, and never read the presence of substantive tasks as readiness on
290
+ its own. A not-ready quick plan is not a dead end and does not need spec-driven
291
+ planning: load `oat-project-quick-start/SKILL.md` and follow its Step 0.5 resume
292
+ branch, which finishes the plan in place without re-scaffolding the project.
293
+
285
294
  **Import mode (`oat_workflow_mode: import`):**
286
295
 
287
296
  | oat_phase | oat_phase_status | Next Skill |
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: oat-project-quick-start
3
- version: 2.3.9
3
+ version: 2.3.10
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
  oat_gateable: true
@@ -125,6 +125,26 @@ PROJECTS_ROOT="${OAT_PROJECTS_ROOT:-$(oat config get projects.root 2>/dev/null |
125
125
  PROJECTS_ROOT="${PROJECTS_ROOT%/}"
126
126
  ```
127
127
 
128
+ **Resume in place (existing incomplete quick project).** When `PROJECT_PATH`
129
+ resolves to an existing project whose `state.md` records
130
+ `oat_workflow_mode: quick`, this skill resumes that project and never
131
+ re-scaffolds it: `oat project new` is not re-run, and `discovery.md`,
132
+ `design.md`, and any existing `plan.md` content are preserved as they stand.
133
+ Evaluate **quick plan readiness** — the named predicate defined below, beside
134
+ Step 3.7 — against `"$PROJECT_PATH/plan.md"`:
135
+
136
+ - Not ready → re-enter this skill's own steps from the earliest one whose
137
+ output is missing or still pre-review, and carry on through Step 3.7 so the
138
+ plan reaches a durable review disposition. This is the in-place resume branch
139
+ that the lifecycle routers send a not-ready quick project to; nothing is
140
+ re-scaffolded and no artifact is overwritten from a template. On this path
141
+ Step 3 updates the existing `plan.md` in place: it reads `.oat/templates/plan.md`
142
+ only when `plan.md` is missing, re-asserts the Step 3 pre-review frontmatter
143
+ values, and never replaces phases, tasks, or `## Reviews` rows that the
144
+ earlier run already wrote.
145
+ - Ready → there is nothing left to author here; load
146
+ `oat-project-implement/SKILL.md` and follow it to begin execution.
147
+
128
148
  If no valid active project exists:
129
149
 
130
150
  - Resolve startup input from `$ARGUMENTS` before doing any discovery work:
@@ -132,10 +152,41 @@ If no valid active project exists:
132
152
  - If `$ARGUMENTS` contains only a bare `{project-name}` (for example a slug or short title) without a substantive description, ask the user for a short project description before scanning the repo or drafting discovery.
133
153
  - Do not infer requirements from the project name alone or go exploring the codebase to guess what the project means.
134
154
  - If neither field is available, ask for both the project name and a short project description. One or two sentences is enough for the description.
135
- - Create project via the same scaffolding path used by `oat-project-new`:
155
+ - Create project via the same scaffolding path used by `oat-project-new`, then
156
+ re-resolve `PROJECT_PATH` from the path the scaffold reports:
136
157
 
137
158
  ```bash
138
- oat project new "{project-name}" --mode quick
159
+ SCAFFOLD=$(oat project new "{project-name}" --mode quick --json) || SCAFFOLD=''
160
+ # Report what the scaffolder said, so a `commitStatus` of anything but
161
+ # `committed`, and its `commitError`, stay as visible as they were before this
162
+ # branch started capturing the output.
163
+ printf '%s\n' "$SCAFFOLD"
164
+ # Scaffolding creates the project directory and repoints `activeProject`, so
165
+ # the Step 0.5 value of PROJECT_PATH is stale from here on. Left unresolved it
166
+ # still names whatever project was active before this run -- sending the Step 1
167
+ # and consolidation writes into a project this run is retiring -- or is empty,
168
+ # which makes "$PROJECT_PATH/state.md" the absolute path /state.md. Re-resolve
169
+ # from the report the scaffolder just made.
170
+ SCAFFOLD_STATUS=$(printf '%s\n' "$SCAFFOLD" |
171
+ sed -n 's/.*"status"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' |
172
+ head -1)
173
+ PROJECT_PATH=$(printf '%s\n' "$SCAFFOLD" |
174
+ sed -n 's/.*"projectPath"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' |
175
+ head -1)
176
+ # Only a reported success may fall back to the pointer the scaffolder set. A
177
+ # failed scaffold reports no path and leaves the old pointer untouched, so an
178
+ # unconditional fallback would resolve straight back to the stale project and
179
+ # pass the check below on that project state.md.
180
+ if [ "$SCAFFOLD_STATUS" = "ok" ] && [ -z "$PROJECT_PATH" ]; then
181
+ PROJECT_PATH=$(oat config get activeProject 2>/dev/null || true)
182
+ fi
183
+ # Validate before anything writes. A failed scaffold, an unresolved path, or a
184
+ # path with no state.md stops the run; it never silently writes somewhere else.
185
+ if [ "$SCAFFOLD_STATUS" != "ok" ] || [ -z "$PROJECT_PATH" ] ||
186
+ [ ! -f "$PROJECT_PATH/state.md" ]; then
187
+ printf 'quick-start: scaffolding did not yield a project path with state.md\n' >&2
188
+ exit 1
189
+ fi
139
190
  ```
140
191
 
141
192
  This guarantees:
@@ -143,10 +194,34 @@ This guarantees:
143
194
  - standard artifact scaffolding from `.oat/templates/`
144
195
  - `activeProject` update in `.oat/config.local.json`
145
196
  - repo dashboard refresh (`.oat/state.md`) via existing scaffolder behavior
197
+ - a `PROJECT_PATH` that names the project this run just created, validated
198
+ before Step 1 and before the consolidation write below
199
+
200
+ **Consolidating earlier scaffolds.** When this project absorbs work that earlier
201
+ project scaffolds already started — those directories are being retired into
202
+ this one rather than continued — record what was absorbed in
203
+ `"$PROJECT_PATH/state.md"` frontmatter as part of the same Step 1 frontmatter
204
+ write, so this branch adds fields to that single write rather than performing
205
+ its own. `PROJECT_PATH` here is the re-resolved, validated path above, never the
206
+ pre-scaffold value:
207
+
208
+ - `absorbed_projects: [<slug>]` — the project slug of every retired scaffold,
209
+ which also names the scaffold directory under the projects root that this
210
+ project supersedes.
211
+ - `absorbed_backlog_ids: [<BL-id>]` — every backlog ID those scaffolds carried
212
+ into this project.
213
+
214
+ Record both fields only when a consolidation actually happened; an absent field
215
+ and an empty list are equivalent. These two fields are the only inputs the
216
+ absorbed-project retirement sweep reads at completion, where retiring a scaffold
217
+ is treated as a semantic claim about the planning surfaces rather than the
218
+ physical removal of a directory.
146
219
 
147
220
  ### Step 1: Set Quick Workflow Metadata
148
221
 
149
- Update `"$PROJECT_PATH/state.md"` frontmatter:
222
+ Update `"$PROJECT_PATH/state.md"` frontmatter, using the `PROJECT_PATH` that
223
+ Step 0.5 resolved for a resumed project or that scaffolding re-resolved and
224
+ validated for a new one:
150
225
 
151
226
  - `oat_workflow_mode: quick`
152
227
  - `oat_workflow_origin: native`
@@ -515,6 +590,13 @@ preserved value is `null` or malformed for the phase-review contract.
515
590
 
516
591
  Create/update `"$PROJECT_PATH/plan.md"` from `.oat/templates/plan.md`.
517
592
 
593
+ `.oat/templates/plan.md` is read only when `"$PROJECT_PATH/plan.md"` is missing.
594
+ On the Step 0.5 resume path the file already exists, so this step updates it in
595
+ place: it re-asserts the frontmatter values below and continues authoring the
596
+ plan body, and it never replaces phases, tasks, or `## Reviews` rows an earlier
597
+ run already wrote. Step 2.9's snapshot restore below is a frontmatter operation
598
+ and does not license a template rewrite of existing content.
599
+
518
600
  Restore the exact snapshot into the resulting `plan.md` frontmatter as part of
519
601
  the first resulting plan write, before any later frontmatter rewrite and before
520
602
  Step 3.55 invokes the shared setup contract. Carry the snapshot losslessly
@@ -842,6 +924,183 @@ cannot be recorded, leave the Step 3 pre-review values unchanged and commit
842
924
  them before stopping. Never expose a partially reviewed quick plan to
843
925
  `oat-project-implement`.
844
926
 
927
+ ### Quick Plan Readiness (Named Predicate)
928
+
929
+ **Quick plan readiness** is defined here, once. `oat-project-plan`,
930
+ `oat-project-progress`, and `oat-project-next` reference it by this name and do
931
+ not restate its conditions.
932
+
933
+ A quick `plan.md` is implementation-ready only when all of the following hold:
934
+
935
+ 1. Frontmatter `oat_status: complete`, quoted or bare.
936
+ 2. Frontmatter `oat_ready_for: oat-project-implement`, quoted or bare.
937
+ 3. Frontmatter `oat_template` is not `true`: `oat_template: false`, an explicit
938
+ null, or an absent key, which is the same absent-or-false convention
939
+ `oat-project-next` applies when it classifies boundary tiers. A duplicated
940
+ `oat_template` key is contradictory, and an unrecognized value is not read as
941
+ ready.
942
+ 4. The `## Reviews` section records the Step 3.7 disposition: a `plan` artifact
943
+ row whose Status is something other than `pending` or `-`, or the explicit
944
+ `Plan artifact review: skipped (workflow.autoArtifactReview.plan=false)`
945
+ recorded on a line of its own, starting at column 0 — never quoted inside
946
+ other prose, never indented into a code block, and never inside a fenced
947
+ example. Fences are read as CommonMark reads them — a fence closes only on a
948
+ bare run of its own marker, at least as long as the one that opened it — so an
949
+ example nested inside another fence stays an example. Indentation is measured
950
+ in columns, with a tab advancing to the next multiple of four, so any line
951
+ indented four or more columns — including a single tab-indented apparent fence
952
+ marker — is example code rather than the record.
953
+ 5. At least one phase carries a substantive task — a `### Task pNN-tNN:`
954
+ heading under a `## Phase` heading, outside any fenced example, whose title
955
+ still reads as text once every `{placeholder}` is removed.
956
+
957
+ Substantive tasks alone never make a plan ready. The plan that Step 3 writes
958
+ already has concrete tasks, yet it carries the Step 3 pre-review frontmatter, so
959
+ it fails conditions 1–3 and is NOT ready. Readiness is the frontmatter plus the
960
+ durably recorded review disposition, never the presence of tasks. A not-ready
961
+ plan resumes through the Step 0.5 resume branch above, in place.
962
+
963
+ Evaluate the predicate mechanically with this guard. It reads `plan.md` only,
964
+ needs no CLI probe, and exits `0` when the plan is ready and `1` when it is not:
965
+
966
+ ```bash
967
+ quick_plan_ready() {
968
+ PLAN_FILE="$1"
969
+ [ -f "$PLAN_FILE" ] || return 1
970
+
971
+ # The frontmatter block must be closed. An unterminated delimiter would
972
+ # otherwise let an ordinary body line satisfy a readiness field.
973
+ FRONTMATTER=$(awk '
974
+ NR == 1 && /^---[[:space:]]*$/ { inside = 1; next }
975
+ inside && /^---[[:space:]]*$/ { closed = 1; exit }
976
+ inside { print }
977
+ END { if (!closed) exit 1 }
978
+ ' "$PLAN_FILE") || return 1
979
+
980
+ # Each field is declared exactly once, with exactly the required value, so a
981
+ # duplicated or contradictory key cannot be read as ready.
982
+ # Quotes must pair: `'complete` and `complete"` are different scalars to YAML
983
+ # and are not the required value here either.
984
+ quick_plan_key() { printf '[\"'\'']?%s[\"'\'']?[[:space:]]*:' "$1"; }
985
+ quick_plan_field() {
986
+ [ "$(printf '%s\n' "$FRONTMATTER" | grep -cE "^$(quick_plan_key "$1")")" = "1" ] || return 1
987
+ printf '%s\n' "$FRONTMATTER" |
988
+ grep -qE "^$(quick_plan_key "$1")[[:space:]]+($2|'$2'|\"$2\")[[:space:]]*(#.*)?$"
989
+ }
990
+ quick_plan_field oat_status complete || return 1
991
+ quick_plan_field oat_ready_for oat-project-implement || return 1
992
+
993
+ # `oat_template` follows the absent-or-false convention `oat-project-next`
994
+ # documents: only an explicit `true` disqualifies a plan. Absent, null, and
995
+ # false all mean "not a template"; a duplicated key is contradictory, and an
996
+ # unrecognized scalar is not read as ready.
997
+ TEMPLATE_KEY=$(quick_plan_key oat_template)
998
+ TEMPLATE_COUNT=$(printf '%s\n' "$FRONTMATTER" | grep -cE "^$TEMPLATE_KEY")
999
+ [ "$TEMPLATE_COUNT" -le 1 ] || return 1
1000
+ if [ "$TEMPLATE_COUNT" = "1" ]; then
1001
+ printf '%s\n' "$FRONTMATTER" |
1002
+ grep -qE "^$TEMPLATE_KEY[[:space:]]*(false|'false'|\"false\"|null|~)?[[:space:]]*(#.*)?$" || return 1
1003
+ fi
1004
+
1005
+ # Fenced examples are not the record: a sample review section inside a code
1006
+ # block must not dispose of a real pending row.
1007
+ REVIEWS=$(awk '
1008
+ # CommonMark measures indentation in columns, not characters: a tab
1009
+ # advances to the next multiple of four, so a single leading tab is
1010
+ # already a four-column code indentation. Counting raw characters would
1011
+ # let a tab-indented apparent closer end the fence used here while the
1012
+ # document still reads it as example content.
1013
+ function indent_columns(text, i, column, character) {
1014
+ column = 0
1015
+ for (i = 1; i <= length(text); i++) {
1016
+ character = substr(text, i, 1)
1017
+ if (character == " ") column++
1018
+ else if (character == "\t") column += 4 - (column % 4)
1019
+ else break
1020
+ }
1021
+ return column
1022
+ }
1023
+ # CommonMark fences: a fence closes only on its own marker character, at
1024
+ # least as long as the one that opened it, and a closing fence carries no
1025
+ # info string. A marker indented four or more columns is indented code.
1026
+ /^[[:space:]]*([`][`][`]|~~~)/ {
1027
+ line = $0
1028
+ if (indent_columns(line) < 4) {
1029
+ sub(/^[[:space:]]*/, "", line)
1030
+ marker = substr(line, 1, 1)
1031
+ len = 0
1032
+ while (substr(line, len + 1, 1) == marker) len++
1033
+ rest = substr(line, len + 1)
1034
+ if (!fence) { fence = 1; fmark = marker; flen = len }
1035
+ else if (marker == fmark && len >= flen && rest ~ /^[[:space:]]*$/) fence = 0
1036
+ }
1037
+ next
1038
+ }
1039
+ fence { next }
1040
+ indent_columns($0) >= 4 { next }
1041
+ /^## Reviews[[:space:]]*$/ { inside = 1; next }
1042
+ inside && /^##[[:space:]]/ { exit }
1043
+ inside { print }
1044
+ ' "$PLAN_FILE")
1045
+ # The skip disposition counts only as its own recorded line, never as a
1046
+ # substring of prose that merely quotes it.
1047
+ if ! printf '%s\n' "$REVIEWS" | grep -qE '^(- )?Plan artifact review: skipped \(workflow\.autoArtifactReview\.plan=false\)[[:space:]]*$'; then
1048
+ PLAN_STATUS=$(printf '%s\n' "$REVIEWS" |
1049
+ grep -E '^\|[[:space:]]*plan[[:space:]]*\|[[:space:]]*artifact[[:space:]]*\|' |
1050
+ tail -1 |
1051
+ awk -F'|' '{ gsub(/^[[:space:]]+|[[:space:]]+$/, "", $4); print $4 }')
1052
+ case "$PLAN_STATUS" in
1053
+ '' | '-' | pending) return 1 ;;
1054
+ esac
1055
+ fi
1056
+
1057
+ # At least one real task heading, inside a phase and outside fenced examples,
1058
+ # whose title still reads as text once every {placeholder} is removed.
1059
+ awk '
1060
+ # CommonMark measures indentation in columns, not characters: a tab
1061
+ # advances to the next multiple of four, so a single leading tab is
1062
+ # already a four-column code indentation. Counting raw characters would
1063
+ # let a tab-indented apparent closer end the fence used here while the
1064
+ # document still reads it as example content.
1065
+ function indent_columns(text, i, column, character) {
1066
+ column = 0
1067
+ for (i = 1; i <= length(text); i++) {
1068
+ character = substr(text, i, 1)
1069
+ if (character == " ") column++
1070
+ else if (character == "\t") column += 4 - (column % 4)
1071
+ else break
1072
+ }
1073
+ return column
1074
+ }
1075
+ # CommonMark fences: a fence closes only on its own marker character, at
1076
+ # least as long as the one that opened it, and a closing fence carries no
1077
+ # info string. A marker indented four or more columns is indented code.
1078
+ /^[[:space:]]*([`][`][`]|~~~)/ {
1079
+ line = $0
1080
+ if (indent_columns(line) < 4) {
1081
+ sub(/^[[:space:]]*/, "", line)
1082
+ marker = substr(line, 1, 1)
1083
+ len = 0
1084
+ while (substr(line, len + 1, 1) == marker) len++
1085
+ rest = substr(line, len + 1)
1086
+ if (!fence) { fence = 1; fmark = marker; flen = len }
1087
+ else if (marker == fmark && len >= flen && rest ~ /^[[:space:]]*$/) fence = 0
1088
+ }
1089
+ next
1090
+ }
1091
+ fence { next }
1092
+ indent_columns($0) >= 4 { next }
1093
+ /^##[[:space:]]/ { inphase = ($0 ~ /^##[[:space:]]+Phase/); next }
1094
+ inphase && /^### Task p[0-9]+-t[0-9]+:[[:space:]]/ {
1095
+ sub(/^### Task p[0-9]+-t[0-9]+:[[:space:]]*/, "")
1096
+ print
1097
+ }
1098
+ ' "$PLAN_FILE" | sed -E 's/\{[^}]*\}//g' | grep -qE '[[:alnum:]]' || return 1
1099
+
1100
+ return 0
1101
+ }
1102
+ ```
1103
+
845
1104
  ### Step 4: Sync Project State
846
1105
 
847
1106
  Update `"$PROJECT_PATH/state.md"`:
@@ -917,3 +1176,4 @@ Report:
917
1176
  - ✅ `implementation.md` is initialized for resumable execution.
918
1177
  - ✅ Changed quick-start artifacts are committed before handoff or pause; `.oat/state.md` is refreshed locally when available.
919
1178
  - ✅ Configured gate has run, and only a corroborated, receive-eligible artifact has been handed off to `oat-project-review-receive` before it is treated as consumed.
1179
+ - ✅ An existing incomplete quick project resumed in place against **quick plan readiness** instead of being re-scaffolded.